summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--INSTALL13
-rw-r--r--LICENSE674
-rw-r--r--Makefile.am50
-rw-r--r--applications/Makefile.am32
-rw-r--r--applications/directql/Makefile89
-rw-r--r--applications/directql/directql.cc993
-rw-r--r--applications/directql/directql_error.cc119
-rw-r--r--applications/directql/directql_error.hh76
-rw-r--r--applications/directql/directql_signal.cc246
-rw-r--r--applications/directql/directql_signal.hh50
-rw-r--r--applications/directql/template_inst.hh149
-rw-r--r--applications/rasql/Makefile.am70
-rw-r--r--applications/rasql/rasql.cc946
-rw-r--r--applications/rasql/rasql_error.cc120
-rw-r--r--applications/rasql/rasql_error.hh79
-rw-r--r--applications/rasql/rasql_signal.cc244
-rw-r--r--applications/rasql/rasql_signal.hh54
-rw-r--r--applications/rasql/test/Makefile66
-rw-r--r--applications/rview/Makefile499
-rw-r--r--applications/rview/cube_render.c3106
-rw-r--r--applications/rview/cube_render.h228
-rw-r--r--applications/rview/cube_render_core.c182
-rw-r--r--applications/rview/cube_render_line.c172
-rw-r--r--applications/rview/cube_render_mesh.c48
-rw-r--r--applications/rview/cube_render_voxline.c482
-rw-r--r--applications/rview/generate_trans.sh1013
-rw-r--r--applications/rview/labelManager.cpp314
-rw-r--r--applications/rview/labelManager.hh69
-rw-r--r--applications/rview/labels.txt451
-rw-r--r--applications/rview/rview.cpp548
-rw-r--r--applications/rview/rview.hh139
-rw-r--r--applications/rview/rview.tex1479
-rw-r--r--applications/rview/rviewApp.cpp828
-rw-r--r--applications/rview/rviewApp.hh112
-rw-r--r--applications/rview/rviewChart.cpp1024
-rw-r--r--applications/rview/rviewColMap.cpp1183
-rw-r--r--applications/rview/rviewColMap.hh254
-rw-r--r--applications/rview/rviewDModes.hh1094
-rw-r--r--applications/rview/rviewDb.cpp970
-rw-r--r--applications/rview/rviewDb.hh110
-rw-r--r--applications/rview/rviewDisplay.cpp1005
-rw-r--r--applications/rview/rviewDisplay.hh224
-rw-r--r--applications/rview/rviewIO.cpp718
-rw-r--r--applications/rview/rviewIO.hh121
-rw-r--r--applications/rview/rviewImage.cpp5230
-rw-r--r--applications/rview/rviewMDD.cpp1006
-rw-r--r--applications/rview/rviewMDD.hh185
-rw-r--r--applications/rview/rviewOSection.cpp1313
-rw-r--r--applications/rview/rviewOSection.hh230
-rw-r--r--applications/rview/rviewPrefs.cpp1571
-rw-r--r--applications/rview/rviewPrefs.hh275
-rw-r--r--applications/rview/rviewQuery.cpp647
-rw-r--r--applications/rview/rviewQuery.hh128
-rw-r--r--applications/rview/rviewSound.cpp1738
-rw-r--r--applications/rview/rviewSound.hh274
-rw-r--r--applications/rview/rviewStrings.cpp216
-rw-r--r--applications/rview/rviewTable.cpp770
-rw-r--r--applications/rview/rviewThumb.cpp1183
-rw-r--r--applications/rview/rviewThumb.hh203
-rw-r--r--applications/rview/rviewTypeMan.cpp564
-rw-r--r--applications/rview/rviewTypeMan.hh106
-rw-r--r--applications/rview/rviewTypes.hh81
-rw-r--r--applications/rview/rviewUtils.cpp3630
-rw-r--r--applications/rview/rviewUtils.hh1045
-rw-r--r--applications/rview/wx_pixmap.cpp1706
-rw-r--r--applications/rview/wx_pixmap.h221
-rw-r--r--bin/Makefile.am47
-rw-r--r--bin/create_db.sh.in116
-rw-r--r--bin/errtxts276
-rw-r--r--bin/errtxts_de258
-rw-r--r--bin/errtxts_en276
-rw-r--r--bin/errtxts_fr267
-rw-r--r--bin/rasdaman114
-rw-r--r--bin/rasmgr.conf.in62
-rw-r--r--bin/start_rasdaman.sh.in123
-rw-r--r--bin/stop_rasdaman.sh.in88
-rw-r--r--catalogmgr/Makefile.am43
-rw-r--r--catalogmgr/algebraops.cc172
-rw-r--r--catalogmgr/algebraops.hh130
-rw-r--r--catalogmgr/autogen_ops.cc316
-rw-r--r--catalogmgr/autogen_ops.hh284
-rw-r--r--catalogmgr/ops.cc3803
-rw-r--r--catalogmgr/ops.hh2042
-rw-r--r--catalogmgr/test/Makefile58
-rw-r--r--catalogmgr/typefactory.cc626
-rw-r--r--catalogmgr/typefactory.hh262
-rw-r--r--clientcomm/Makefile.am64
-rw-r--r--clientcomm/clientcomm.cc124
-rw-r--r--clientcomm/clientcomm.hh269
-rw-r--r--clientcomm/clientcomm.icc43
-rw-r--r--clientcomm/clientcomm_RNPdefault.cc126
-rw-r--r--clientcomm/clientcomm_RPCdefault.cc126
-rw-r--r--clientcomm/clnt_control.c101
-rw-r--r--clientcomm/clnt_control.h46
-rw-r--r--clientcomm/clnt_control/clnt_control.c100
-rw-r--r--clientcomm/clnt_control/clnt_control.h46
-rw-r--r--clientcomm/rpcclientcomm.cc3672
-rw-r--r--clientcomm/rpcclientcomm.hh414
-rw-r--r--clientcomm/rpcif.h.awk59
-rw-r--r--clientcomm/rpcif.h.awk_dec246
-rw-r--r--clientcomm/rpcif.x409
-rw-r--r--clientcomm/rpcif_clnt.c.awk46
-rw-r--r--clientcomm/rpcif_clnt.c.awk_dec62
-rw-r--r--clientcomm/rpcif_clnt.c.awk_dec28
-rw-r--r--clientcomm/rpcif_svc.c.awk59
-rw-r--r--clientcomm/test/Makefile81
-rw-r--r--clientcomm/test/test_clientcomm.cc84
-rw-r--r--commline/Makefile.am31
-rw-r--r--commline/cmlparser.cc915
-rw-r--r--commline/cmlparser.hh242
-rw-r--r--commline/test/Makefile43
-rw-r--r--commline/test/functest.cc59
-rw-r--r--commline/test/test_cml.cc101
-rw-r--r--compression/Makefile.am37
-rw-r--r--compression/compresstime.hh46
-rw-r--r--compression/lincompstream.cc985
-rw-r--r--compression/lincompstream.hh553
-rw-r--r--compression/nocompstream.cc194
-rw-r--r--compression/nocompstream.hh101
-rw-r--r--compression/tilecompnone.cc104
-rw-r--r--compression/tilecompnone.hh68
-rw-r--r--compression/tilecompression.cc342
-rw-r--r--compression/tilecompression.hh201
-rw-r--r--configure.ac336
-rw-r--r--configure.todo86
-rw-r--r--conversion/Makefile.am37
-rw-r--r--conversion/bmp.cc990
-rw-r--r--conversion/bmp.hh91
-rw-r--r--conversion/convertor.cc405
-rw-r--r--conversion/convertor.hh252
-rw-r--r--conversion/convfactory.cc189
-rw-r--r--conversion/convfactory.hh64
-rw-r--r--conversion/csv.cc222
-rw-r--r--conversion/csv.hh93
-rw-r--r--conversion/dem.cc894
-rw-r--r--conversion/dem.hh187
-rw-r--r--conversion/des.cc118
-rw-r--r--conversion/des.h67
-rw-r--r--conversion/ecw.cc339
-rw-r--r--conversion/ecw.hh78
-rw-r--r--conversion/ecwmemfs.cc157
-rw-r--r--conversion/ecwmemfs.hh84
-rw-r--r--conversion/graphic.cc148
-rw-r--r--conversion/graphic.h90
-rw-r--r--conversion/hdf.cc386
-rw-r--r--conversion/hdf.hh104
-rw-r--r--conversion/image.cc1040
-rw-r--r--conversion/image.h226
-rw-r--r--conversion/int16.cc874
-rw-r--r--conversion/int16.hh205
-rw-r--r--conversion/jpeg.cc530
-rw-r--r--conversion/jpeg.hh84
-rw-r--r--conversion/memfs.c421
-rw-r--r--conversion/memfs.cc421
-rw-r--r--conversion/memfs.h85
-rw-r--r--conversion/memfs.hh85
-rw-r--r--conversion/nitf.cc702
-rw-r--r--conversion/nitf.h165
-rw-r--r--conversion/ntf.cc218
-rw-r--r--conversion/ntf.hh80
-rw-r--r--conversion/png.cc597
-rw-r--r--conversion/png.hh79
-rw-r--r--conversion/res.cc110
-rw-r--r--conversion/res.h64
-rw-r--r--conversion/test/Makefile142
-rw-r--r--conversion/test/test_bmp.cc83
-rw-r--r--conversion/test/test_convertor.cc276
-rw-r--r--conversion/test/test_hdf.cc309
-rw-r--r--conversion/test/test_jpeg.cc295
-rw-r--r--conversion/test/test_png.cc237
-rw-r--r--conversion/test/test_vff.cc169
-rw-r--r--conversion/text.cc138
-rw-r--r--conversion/text.h86
-rw-r--r--conversion/tiff.cc653
-rw-r--r--conversion/tiff.hh145
-rw-r--r--conversion/tor.cc230
-rw-r--r--conversion/tor.hh82
-rw-r--r--conversion/utilities.cc109
-rw-r--r--conversion/utilities.h35
-rw-r--r--conversion/vff.cc797
-rw-r--r--conversion/vff.hh138
-rw-r--r--debug/README11
-rw-r--r--debug/debug-clt.hh35
-rw-r--r--debug/debug-srv.hh35
-rw-r--r--debug/debug.hh129
-rw-r--r--depcomp589
-rw-r--r--empty0
-rw-r--r--httpserver/Makefile.am33
-rw-r--r--httpserver/childs.cc246
-rw-r--r--httpserver/config.cc465
-rw-r--r--httpserver/defs.h249
-rw-r--r--httpserver/http-date.cc97
-rw-r--r--httpserver/http-defs.h214
-rw-r--r--httpserver/http-doit.cc536
-rw-r--r--httpserver/http-error.cc446
-rw-r--r--httpserver/http-fields.cc218
-rw-r--r--httpserver/http-methods.cc163
-rw-r--r--httpserver/http-readmsg.cc1014
-rw-r--r--httpserver/http-support.cc503
-rw-r--r--httpserver/http-writemsg.cc314
-rw-r--r--httpserver/http.cc181
-rw-r--r--httpserver/http.h133
-rw-r--r--httpserver/httpserver.conf14
-rw-r--r--httpserver/httpserver.h38
-rw-r--r--httpserver/init.cc319
-rw-r--r--httpserver/logging.cc297
-rw-r--r--httpserver/main.cc191
-rw-r--r--httpserver/protos.h178
-rw-r--r--httpserver/server.h190
-rw-r--r--httpserver/signals.cc287
-rw-r--r--httpserver/support.cc640
-rw-r--r--httpserver/test/Makefile63
-rw-r--r--httpserver/test/httpserver.conf14
-rw-r--r--httpserver/test/post_test.html116
-rw-r--r--httpserver/types.h38
-rw-r--r--include/basictypes.hh207
-rw-r--r--include/basictypes.odl112
-rw-r--r--include/bool.h23
-rw-r--r--include/globals.hh77
-rw-r--r--include/rasdaman.hh70
-rw-r--r--include/stdexcept.h144
-rw-r--r--indexmgr/Makefile.am38
-rw-r--r--indexmgr/hierindexds.cc23
-rw-r--r--indexmgr/hierindexds.hh118
-rw-r--r--indexmgr/indexds.cc24
-rw-r--r--indexmgr/indexds.hh176
-rw-r--r--indexmgr/keyobject.cc135
-rw-r--r--indexmgr/keyobject.hh134
-rw-r--r--indexmgr/mddobjix.cc529
-rw-r--r--indexmgr/mddobjix.hh274
-rw-r--r--indexmgr/persmddobjix.cc2
-rw-r--r--indexmgr/persmddobjix.hh1
-rw-r--r--indexmgr/sdirindexlogic.cc333
-rw-r--r--indexmgr/sdirindexlogic.hh169
-rw-r--r--indexmgr/srcindexlogic.cc288
-rw-r--r--indexmgr/srcindexlogic.hh132
-rw-r--r--indexmgr/srptindexlogic.cc1147
-rw-r--r--indexmgr/srptindexlogic.hh244
-rw-r--r--indexmgr/test/Makefile103
-rw-r--r--indexmgr/test/test_abc.cc373
-rw-r--r--indexmgr/test/test_clusterix.cc338
-rw-r--r--indexmgr/test/test_dirix.cc357
-rw-r--r--indexmgr/test/test_expix.cc488
-rw-r--r--indexmgr/test/test_hierix.cc388
-rw-r--r--indexmgr/test/test_ix.cc517
-rw-r--r--indexmgr/test/test_ix1.cc853
-rw-r--r--indexmgr/transdirix.cc269
-rw-r--r--indexmgr/transdirix.hh141
-rw-r--r--insertutils/Makefile.am50
-rw-r--r--insertutils/insertdemo.sh.in118
-rw-r--r--insertutils/insertppm.cc859
-rw-r--r--insertutils/test/test_insertppm.log70
-rw-r--r--insertutils/test/test_insertppm.log.reference69
-rw-r--r--insertutils/test/test_insertppm.log.save70
-rw-r--r--insertutils/test/test_insertppm.sh152
-rw-r--r--java/Makefile140
-rw-r--r--java/examples/AvgCellRed.java167
-rw-r--r--java/examples/GetData.java148
-rw-r--r--java/examples/TestQuery.java749
-rw-r--r--java/org/odmg/ClassNotPersistenceCapableException.java51
-rw-r--r--java/org/odmg/DArray.classbin0 -> 176 bytes
-rw-r--r--java/org/odmg/DArray.java49
-rw-r--r--java/org/odmg/DBag.classbin0 -> 267 bytes
-rw-r--r--java/org/odmg/DBag.java85
-rw-r--r--java/org/odmg/DCollection.classbin0 -> 463 bytes
-rw-r--r--java/org/odmg/DCollection.java86
-rw-r--r--java/org/odmg/DList.classbin0 -> 204 bytes
-rw-r--r--java/org/odmg/DList.java55
-rw-r--r--java/org/odmg/DMap.classbin0 -> 119 bytes
-rw-r--r--java/org/odmg/DMap.java40
-rw-r--r--java/org/odmg/DSet.classbin0 -> 355 bytes
-rw-r--r--java/org/odmg/DSet.java110
-rw-r--r--java/org/odmg/Database.classbin0 -> 743 bytes
-rw-r--r--java/org/odmg/Database.java150
-rw-r--r--java/org/odmg/DatabaseClosedException.classbin0 -> 466 bytes
-rw-r--r--java/org/odmg/DatabaseClosedException.java51
-rw-r--r--java/org/odmg/DatabaseIsReadOnlyException.classbin0 -> 478 bytes
-rw-r--r--java/org/odmg/DatabaseIsReadOnlyException.java53
-rw-r--r--java/org/odmg/DatabaseNotFoundException.classbin0 -> 465 bytes
-rw-r--r--java/org/odmg/DatabaseNotFoundException.java53
-rw-r--r--java/org/odmg/DatabaseOpenException.classbin0 -> 453 bytes
-rw-r--r--java/org/odmg/DatabaseOpenException.java51
-rw-r--r--java/org/odmg/Implementation.classbin0 -> 614 bytes
-rw-r--r--java/org/odmg/Implementation.java113
-rw-r--r--java/org/odmg/LockNotGrantedException.classbin0 -> 466 bytes
-rw-r--r--java/org/odmg/LockNotGrantedException.java66
-rw-r--r--java/org/odmg/Makefile66
-rw-r--r--java/org/odmg/Makefile.dep0
-rw-r--r--java/org/odmg/NotImplementedException.classbin0 -> 466 bytes
-rw-r--r--java/org/odmg/NotImplementedException.java49
-rw-r--r--java/org/odmg/ODMGException.classbin0 -> 426 bytes
-rw-r--r--java/org/odmg/ODMGException.java49
-rw-r--r--java/org/odmg/ODMGRuntimeException.classbin0 -> 454 bytes
-rw-r--r--java/org/odmg/ODMGRuntimeException.java50
-rw-r--r--java/org/odmg/OQLQuery.classbin0 -> 436 bytes
-rw-r--r--java/org/odmg/OQLQuery.java86
-rw-r--r--java/org/odmg/ObjectDeletedException.classbin0 -> 463 bytes
-rw-r--r--java/org/odmg/ObjectDeletedException.java50
-rw-r--r--java/org/odmg/ObjectNameNotFoundException.classbin0 -> 471 bytes
-rw-r--r--java/org/odmg/ObjectNameNotFoundException.java74
-rw-r--r--java/org/odmg/ObjectNameNotUniqueException.classbin0 -> 474 bytes
-rw-r--r--java/org/odmg/ObjectNameNotUniqueException.java80
-rw-r--r--java/org/odmg/ObjectNotPersistentException.classbin0 -> 481 bytes
-rw-r--r--java/org/odmg/ObjectNotPersistentException.java49
-rw-r--r--java/org/odmg/QueryException.classbin0 -> 432 bytes
-rw-r--r--java/org/odmg/QueryException.java50
-rw-r--r--java/org/odmg/QueryInvalidException.classbin0 -> 454 bytes
-rw-r--r--java/org/odmg/QueryInvalidException.java51
-rw-r--r--java/org/odmg/QueryParameterCountInvalidException.classbin0 -> 496 bytes
-rw-r--r--java/org/odmg/QueryParameterCountInvalidException.java51
-rw-r--r--java/org/odmg/QueryParameterTypeInvalidException.classbin0 -> 493 bytes
-rw-r--r--java/org/odmg/QueryParameterTypeInvalidException.java51
-rw-r--r--java/org/odmg/Transaction.classbin0 -> 494 bytes
-rw-r--r--java/org/odmg/Transaction.java165
-rw-r--r--java/org/odmg/TransactionAbortedException.classbin0 -> 478 bytes
-rw-r--r--java/org/odmg/TransactionAbortedException.java52
-rw-r--r--java/org/odmg/TransactionInProgressException.classbin0 -> 487 bytes
-rw-r--r--java/org/odmg/TransactionInProgressException.java51
-rw-r--r--java/org/odmg/TransactionNotInProgressException.classbin0 -> 496 bytes
-rw-r--r--java/org/odmg/TransactionNotInProgressException.java53
-rw-r--r--java/rasj/Makefile102
-rw-r--r--java/rasj/Makefile.dep0
-rw-r--r--java/rasj/RasBaseType.java109
-rw-r--r--java/rasj/RasClientInternalException.java93
-rw-r--r--java/rasj/RasCollectionType.java96
-rw-r--r--java/rasj/RasConnectionFailedException.java105
-rw-r--r--java/rasj/RasDimensionMismatchException.java107
-rw-r--r--java/rasj/RasException.java104
-rw-r--r--java/rasj/RasFastScale.java361
-rw-r--r--java/rasj/RasGMArray.java532
-rw-r--r--java/rasj/RasIllegalULongValueException.java88
-rw-r--r--java/rasj/RasIllegalUShortValueException.java87
-rw-r--r--java/rasj/RasImplementation.java349
-rw-r--r--java/rasj/RasImplementationInterface.java95
-rw-r--r--java/rasj/RasIndexOutOfBoundsException.java127
-rw-r--r--java/rasj/RasInvalidNameException.java77
-rw-r--r--java/rasj/RasMArrayByte.java110
-rw-r--r--java/rasj/RasMArrayDouble.java195
-rw-r--r--java/rasj/RasMArrayFloat.java195
-rw-r--r--java/rasj/RasMArrayInteger.java196
-rw-r--r--java/rasj/RasMArrayLong.java198
-rw-r--r--java/rasj/RasMArrayShort.java195
-rw-r--r--java/rasj/RasMArrayType.java91
-rw-r--r--java/rasj/RasMInterval.java1332
-rw-r--r--java/rasj/RasMIntervalType.java49
-rw-r--r--java/rasj/RasOIDType.java49
-rw-r--r--java/rasj/RasPoint.java426
-rw-r--r--java/rasj/RasPointType.java49
-rw-r--r--java/rasj/RasPrimitiveType.java169
-rw-r--r--java/rasj/RasQueryExecutionFailedException.java172
-rw-r--r--java/rasj/RasResultIsNoCellException.java69
-rw-r--r--java/rasj/RasResultIsNoIntervalException.java67
-rw-r--r--java/rasj/RasRuntimeException.java104
-rw-r--r--java/rasj/RasSInterval.java1343
-rw-r--r--java/rasj/RasSIntervalType.java49
-rw-r--r--java/rasj/RasStorageLayout.java154
-rw-r--r--java/rasj/RasStreamInputOverflowException.java69
-rw-r--r--java/rasj/RasStructureType.java100
-rw-r--r--java/rasj/RasType.java365
-rw-r--r--java/rasj/RasTypeInvalidException.java93
-rw-r--r--java/rasj/RasTypeNotSupportedException.java82
-rw-r--r--java/rasj/RasTypeUnknownException.java83
-rw-r--r--java/rasj/Rasj.el91
-rw-r--r--java/rasj/clientcommhttp/Makefile62
-rw-r--r--java/rasj/clientcommhttp/Makefile.dep0
-rw-r--r--java/rasj/clientcommhttp/RasCommDefs.classbin0 -> 753 bytes
-rw-r--r--java/rasj/clientcommhttp/RasCommDefs.java54
-rw-r--r--java/rasj/clientcommhttp/RasHttpRequest.classbin0 -> 12597 bytes
-rw-r--r--java/rasj/clientcommhttp/RasHttpRequest.java805
-rw-r--r--java/rasj/clientcommhttp/RasUtils.classbin0 -> 1586 bytes
-rw-r--r--java/rasj/clientcommhttp/RasUtils.java110
-rw-r--r--java/rasj/global/BenchmarkTimer.classbin0 -> 2064 bytes
-rw-r--r--java/rasj/global/BenchmarkTimer.java109
-rw-r--r--java/rasj/global/Debug.classbin0 -> 3400 bytes
-rw-r--r--java/rasj/global/Debug.java229
-rw-r--r--java/rasj/global/Makefile86
-rw-r--r--java/rasj/global/Makefile.dep0
-rw-r--r--java/rasj/global/RasErrorTexts.classbin0 -> 23981 bytes
-rw-r--r--java/rasj/global/RasErrorTexts.java313
-rw-r--r--java/rasj/global/RasErrorTexts.template150
-rw-r--r--java/rasj/global/RasErrorTexts.template272
-rw-r--r--java/rasj/global/RasGlobalDefs.classbin0 -> 4811 bytes
-rw-r--r--java/rasj/global/RasGlobalDefs.java173
-rw-r--r--java/rasj/global/Version.classbin0 -> 403 bytes
-rw-r--r--java/rasj/global/Version.java46
-rw-r--r--java/rasj/global/Version.java.template46
-rw-r--r--java/rasj/odmg/MD5.classbin0 -> 7551 bytes
-rw-r--r--java/rasj/odmg/MD5State.classbin0 -> 1048 bytes
-rw-r--r--java/rasj/odmg/Makefile59
-rw-r--r--java/rasj/odmg/Makefile.dep0
-rw-r--r--java/rasj/odmg/RasBag.classbin0 -> 3170 bytes
-rw-r--r--java/rasj/odmg/RasBag.java178
-rw-r--r--java/rasj/odmg/RasCollection.classbin0 -> 1287 bytes
-rw-r--r--java/rasj/odmg/RasCollection.java105
-rw-r--r--java/rasj/odmg/RasDatabase.classbin0 -> 2477 bytes
-rw-r--r--java/rasj/odmg/RasDatabase.java133
-rw-r--r--java/rasj/odmg/RasList.classbin0 -> 2594 bytes
-rw-r--r--java/rasj/odmg/RasList.java183
-rw-r--r--java/rasj/odmg/RasODMGGlobal.classbin0 -> 663 bytes
-rw-r--r--java/rasj/odmg/RasODMGGlobal.java60
-rw-r--r--java/rasj/odmg/RasODMGImplementation.classbin0 -> 20240 bytes
-rw-r--r--java/rasj/odmg/RasODMGImplementation.java1366
-rw-r--r--java/rasj/odmg/RasODMGImplementation.java.BEFORE_Connection1344
-rw-r--r--java/rasj/odmg/RasODMGImplementation.java.getFreeServer_beginTA1361
-rw-r--r--java/rasj/odmg/RasOID.classbin0 -> 2119 bytes
-rw-r--r--java/rasj/odmg/RasOID.java153
-rw-r--r--java/rasj/odmg/RasOQLQuery.classbin0 -> 5925 bytes
-rw-r--r--java/rasj/odmg/RasOQLQuery.java425
-rw-r--r--java/rasj/odmg/RasObject.classbin0 -> 3229 bytes
-rw-r--r--java/rasj/odmg/RasObject.java244
-rw-r--r--java/rasj/odmg/RasSet.classbin0 -> 2087 bytes
-rw-r--r--java/rasj/odmg/RasSet.java172
-rw-r--r--java/rasj/odmg/RasTransaction.LOCAL_isOpenTA173
-rw-r--r--java/rasj/odmg/RasTransaction.classbin0 -> 2617 bytes
-rw-r--r--java/rasj/odmg/RasTransaction.java173
-rw-r--r--java/rasj/odmg/RasTransaction.java.ORIG146
-rw-r--r--java/rasj/odmg/utils.classbin0 -> 5118 bytes
-rw-r--r--java/rasj/rasj-protocol.html109
-rw-r--r--java/rasj/rnp/MD5.classbin0 -> 7543 bytes
-rw-r--r--java/rasj/rnp/MD5State.classbin0 -> 791 bytes
-rw-r--r--java/rasj/rnp/Makefile61
-rw-r--r--java/rasj/rnp/Makefile.dep0
-rw-r--r--java/rasj/rnp/ParameterDouble64.classbin0 -> 1595 bytes
-rw-r--r--java/rasj/rnp/ParameterFloat32.classbin0 -> 1590 bytes
-rw-r--r--java/rasj/rnp/ParameterInt32.classbin0 -> 1578 bytes
-rw-r--r--java/rasj/rnp/ParameterOpaque.classbin0 -> 1876 bytes
-rw-r--r--java/rasj/rnp/ParameterString.classbin0 -> 1959 bytes
-rw-r--r--java/rasj/rnp/RasRNPImplementation.classbin0 -> 30295 bytes
-rw-r--r--java/rasj/rnp/RasRNPImplementation.java1761
-rw-r--r--java/rasj/rnp/Rnp.classbin0 -> 668 bytes
-rw-r--r--java/rasj/rnp/Rnp.java54
-rw-r--r--java/rasj/rnp/RnpBaseClientComm.classbin0 -> 6519 bytes
-rw-r--r--java/rasj/rnp/RnpBaseClientComm.java207
-rw-r--r--java/rasj/rnp/RnpDecoder.classbin0 -> 3851 bytes
-rw-r--r--java/rasj/rnp/RnpDecoder.java170
-rw-r--r--java/rasj/rnp/RnpEncoder.classbin0 -> 2439 bytes
-rw-r--r--java/rasj/rnp/RnpEncoder.java102
-rw-r--r--java/rasj/rnp/RnpException.classbin0 -> 340 bytes
-rw-r--r--java/rasj/rnp/RnpException.java44
-rw-r--r--java/rasj/rnp/RnpFragment.classbin0 -> 3779 bytes
-rw-r--r--java/rasj/rnp/RnpFragment.java152
-rw-r--r--java/rasj/rnp/RnpFragmentHeader.classbin0 -> 1899 bytes
-rw-r--r--java/rasj/rnp/RnpFragmentHeader.java93
-rw-r--r--java/rasj/rnp/RnpMessage.classbin0 -> 1902 bytes
-rw-r--r--java/rasj/rnp/RnpMessage.java83
-rw-r--r--java/rasj/rnp/RnpMessageHeader.classbin0 -> 2701 bytes
-rw-r--r--java/rasj/rnp/RnpMessageHeader.java150
-rw-r--r--java/rasj/rnp/RnpParameter.classbin0 -> 2965 bytes
-rw-r--r--java/rasj/rnp/RnpParameter.java325
-rw-r--r--java/rasj/rnp/test/Client.java104
-rw-r--r--java/rasj/test/Makefile116
-rw-r--r--java/rasj/test/Makefile.dep0
-rw-r--r--java/rasj/test/MassLoadTest.java324
-rw-r--r--java/rasj/test/Systemtest_rasj.java295
-rw-r--r--java/rasj/test/TestDbTa.java549
-rw-r--r--java/rasj/test/TestException.java361
-rw-r--r--java/rasj/test/TestHttp.java642
-rw-r--r--java/rasj/test/TestMArray.java904
-rw-r--r--java/rasj/test/TestOdmg.java430
-rw-r--r--java/rasj/test/TestQuery.java143
-rw-r--r--java/rasj/test/TestQuery.sh9
-rw-r--r--java/rasj/test/TestRasInterval.java314
-rw-r--r--java/rasj/test/TestRasPoint.java373
-rw-r--r--java/rasj/test/count.sh11
-rw-r--r--java/rasj/test/httptest.java53
-rw-r--r--java/rasj/test/testEva.java229
-rw-r--r--java/rasj/test/testIntervals.java326
-rw-r--r--java/rasj/test/testMArrays.java871
-rw-r--r--m4/ac_prog_ecpg.m430
-rw-r--r--m4/ac_prog_java_cc.m468
-rw-r--r--m4/ac_prog_rpcgen.m430
-rw-r--r--m4/ac_prog_sed.m430
-rw-r--r--m4/ax_lib_postgresql.m4155
-rw-r--r--m4/ax_lib_rasdaman.m4151
-rw-r--r--m4/ct_check_postgres_db.m474
-rw-r--r--manuals_and_examples/Makefile.am28
-rw-r--r--manuals_and_examples/examples/c++/Makefile165
-rw-r--r--manuals_and_examples/examples/c++/avg-cell-red.cc144
-rw-r--r--manuals_and_examples/examples/c++/avg-cell.cc136
-rw-r--r--manuals_and_examples/examples/c++/basictypes.hh206
-rw-r--r--manuals_and_examples/examples/c++/lookup.cc146
-rw-r--r--manuals_and_examples/examples/c++/query.cc172
-rw-r--r--manuals_and_examples/examples/c++/query2.cc181
-rw-r--r--manuals_and_examples/examples/images/anthur.ppm5
-rw-r--r--manuals_and_examples/examples/images/anthur.tifbin0 -> 12664 bytes
-rw-r--r--manuals_and_examples/examples/images/arrow.pgmbin0 -> 9957 bytes
-rw-r--r--manuals_and_examples/examples/images/arrow.tifbin0 -> 456 bytes
-rw-r--r--manuals_and_examples/examples/images/mr_1.pgmbin0 -> 54074 bytes
-rw-r--r--manuals_and_examples/examples/images/mr_1.tifbin0 -> 33760 bytes
-rw-r--r--manuals_and_examples/examples/images/mr_2.pgmbin0 -> 54074 bytes
-rw-r--r--manuals_and_examples/examples/images/mr_2.tifbin0 -> 32844 bytes
-rw-r--r--manuals_and_examples/examples/images/mr_3.pgmbin0 -> 54074 bytes
-rw-r--r--manuals_and_examples/examples/images/mr_3.tifbin0 -> 32658 bytes
-rw-r--r--manuals_and_examples/examples/java/AvgCell.java145
-rw-r--r--manuals_and_examples/examples/java/Lookup.java130
-rw-r--r--manuals_and_examples/examples/java/Makefile45
-rw-r--r--manuals_and_examples/examples/java/Query.java225
-rw-r--r--manuals_and_examples/examples/queries/boolean-masking.ql5
-rw-r--r--manuals_and_examples/examples/queries/sdom.ql3
-rw-r--r--manuals_and_examples/examples/queries/trim-sdom.ql4
-rw-r--r--manuals_and_examples/examples/queries/trim.ql3
-rw-r--r--manuals_and_examples/examples/queries/where.ql4
-rw-r--r--manuals_and_examples/examples/rasdl/basictypes.dl157
-rw-r--r--manuals_and_examples/manuals/banner.html31
-rw-r--r--manuals_and_examples/manuals/body.html54
-rw-r--r--manuals_and_examples/manuals/header.html25
-rw-r--r--manuals_and_examples/manuals/index.html13
-rw-r--r--manuals_and_examples/manuals/logo-rasdaman.gifbin0 -> 7336 bytes
-rw-r--r--manuals_and_examples/manuals/logo.gifbin0 -> 11338 bytes
-rw-r--r--manuals_and_examples/manuals/pdf/dev-guide-c++.docbin0 -> 1605120 bytes
-rw-r--r--manuals_and_examples/manuals/pdf/dev-guide-c++.pdfbin0 -> 395849 bytes
-rw-r--r--manuals_and_examples/manuals/pdf/dev-guide-java.docbin0 -> 1196032 bytes
-rw-r--r--manuals_and_examples/manuals/pdf/dev-guide-java.pdfbin0 -> 165153 bytes
-rw-r--r--manuals_and_examples/manuals/pdf/external-guide-POSTGRESQL.docbin0 -> 115200 bytes
-rw-r--r--manuals_and_examples/manuals/pdf/external-guide-POSTGRESQL.pdfbin0 -> 74020 bytes
-rw-r--r--manuals_and_examples/manuals/pdf/inst-guide.docbin0 -> 2326528 bytes
-rw-r--r--manuals_and_examples/manuals/pdf/inst-guide.pdfbin0 -> 214694 bytes
-rw-r--r--manuals_and_examples/manuals/pdf/ql-guide.docbin0 -> 1863680 bytes
-rw-r--r--manuals_and_examples/manuals/pdf/ql-guide.pdfbin0 -> 531133 bytes
-rw-r--r--manuals_and_examples/manuals/pdf/rview-guide.docbin0 -> 366592 bytes
-rw-r--r--manuals_and_examples/manuals/pdf/rview-guide.pdfbin0 -> 300942 bytes
-rw-r--r--manuals_and_examples/manuals/raslibheader.html26
-rw-r--r--manuals_and_examples/manuals/raslibindex.html13
-rw-r--r--mddmgr/Makefile.am37
-rw-r--r--mddmgr/mddcoll.cc411
-rw-r--r--mddmgr/mddcoll.hh254
-rw-r--r--mddmgr/mddcolliter.cc110
-rw-r--r--mddmgr/mddcolliter.hh97
-rw-r--r--mddmgr/mddcolliter.icc0
-rw-r--r--mddmgr/mddobj.cc392
-rw-r--r--mddmgr/mddobj.hh255
-rw-r--r--mddmgr/test/Makefile109
-rw-r--r--mddmgr/test/test_extbmarkint.cc374
-rw-r--r--mddmgr/test/test_extendobjs.cc324
-rw-r--r--mddmgr/test/test_mddjoin.cc228
-rw-r--r--mddmgr/test/test_mddobj.cc473
-rw-r--r--mddmgr/test/test_mddops.cc335
-rw-r--r--mddmgr/test/test_persmddcoll.cc768
-rw-r--r--mddmgr/test/test_persmddobj.cc1125
-rw-r--r--mddmgr/test/test_transmddcoll.cc180
-rw-r--r--mddmgr/test/test_transmddobj.cc443
-rw-r--r--mymalloc/Makefile.am29
-rw-r--r--mymalloc/mymalloc.h31
-rw-r--r--mymalloc/mymalloc_cln.cc35
-rw-r--r--mymalloc/mymalloc_svc.cc78
-rw-r--r--network/Makefile.am43
-rw-r--r--network/akgnet_commbuffer.cc190
-rw-r--r--network/akgnet_commbuffer.hh169
-rw-r--r--network/akgnet_common.hh100
-rw-r--r--network/akgnet_fdescr.cc113
-rw-r--r--network/akgnet_fdescr.hh107
-rw-r--r--network/akgnet_file.cc51
-rw-r--r--network/akgnet_file.hh73
-rw-r--r--network/akgnet_inetaddr.cc181
-rw-r--r--network/akgnet_inetaddr.hh148
-rw-r--r--network/akgnet_nbcomm.cc579
-rw-r--r--network/akgnet_nbcomm.hh370
-rw-r--r--network/akgnet_selector.cc97
-rw-r--r--network/akgnet_selector.hh95
-rw-r--r--network/akgnet_server.cc173
-rw-r--r--network/akgnet_server.hh157
-rw-r--r--network/akgnet_socket.cc174
-rw-r--r--network/akgnet_socket.hh147
-rw-r--r--network/akgnetwork.hh56
-rw-r--r--qlparser/Makefile.am93
-rw-r--r--qlparser/alloca.c531
-rw-r--r--qlparser/autogen_qtui.cc1151
-rw-r--r--qlparser/autogen_qtui.hh296
-rw-r--r--qlparser/autogen_qtui.icc44
-rw-r--r--qlparser/lex.ll354
-rw-r--r--qlparser/oql.yy2185
-rw-r--r--qlparser/parseinfo.cc102
-rw-r--r--qlparser/parseinfo.hh111
-rw-r--r--qlparser/parseinfo.icc100
-rw-r--r--qlparser/qtatomicdata.cc212
-rw-r--r--qlparser/qtatomicdata.hh134
-rw-r--r--qlparser/qtatomicdata.icc29
-rw-r--r--qlparser/qtbinaryfunc.cc1174
-rw-r--r--qlparser/qtbinaryfunc.hh201
-rw-r--r--qlparser/qtbinaryfunc.icc47
-rw-r--r--qlparser/qtbinaryinduce.cc959
-rw-r--r--qlparser/qtbinaryinduce.hh261
-rw-r--r--qlparser/qtbinaryinduce.icc56
-rw-r--r--qlparser/qtbinaryinduce2.cc919
-rw-r--r--qlparser/qtbinaryinduce2.hh358
-rw-r--r--qlparser/qtbinaryinduce2.icc95
-rw-r--r--qlparser/qtbinaryoperation.cc432
-rw-r--r--qlparser/qtbinaryoperation.hh150
-rw-r--r--qlparser/qtbinaryoperation.icc89
-rw-r--r--qlparser/qtcommand.cc182
-rw-r--r--qlparser/qtcommand.hh97
-rw-r--r--qlparser/qtcommand.icc35
-rw-r--r--qlparser/qtcomplexdata.cc109
-rw-r--r--qlparser/qtcomplexdata.hh92
-rw-r--r--qlparser/qtcomplexdata.icc29
-rw-r--r--qlparser/qtcondense.cc801
-rw-r--r--qlparser/qtcondense.hh352
-rw-r--r--qlparser/qtcondense.icc197
-rw-r--r--qlparser/qtcondenseop.cc440
-rw-r--r--qlparser/qtcondenseop.hh131
-rw-r--r--qlparser/qtcondenseop.icc44
-rw-r--r--qlparser/qtconst.cc265
-rw-r--r--qlparser/qtconst.hh117
-rw-r--r--qlparser/qtconst.icc43
-rw-r--r--qlparser/qtconversion.cc590
-rw-r--r--qlparser/qtconversion.hh113
-rw-r--r--qlparser/qtconversion.icc35
-rw-r--r--qlparser/qtdata.cc127
-rw-r--r--qlparser/qtdata.hh200
-rw-r--r--qlparser/qtdata.icc137
-rw-r--r--qlparser/qtdelete.cc268
-rw-r--r--qlparser/qtdelete.hh100
-rw-r--r--qlparser/qtdelete.icc35
-rw-r--r--qlparser/qtdomainoperation.cc950
-rw-r--r--qlparser/qtdomainoperation.hh124
-rw-r--r--qlparser/qtdomainoperation.icc66
-rw-r--r--qlparser/qtexecute.hh66
-rw-r--r--qlparser/qtinsert.cc361
-rw-r--r--qlparser/qtinsert.hh104
-rw-r--r--qlparser/qtinsert.icc49
-rw-r--r--qlparser/qtintervaldata.cc128
-rw-r--r--qlparser/qtintervaldata.hh102
-rw-r--r--qlparser/qtintervaldata.icc42
-rw-r--r--qlparser/qtintervalop.cc311
-rw-r--r--qlparser/qtintervalop.hh84
-rw-r--r--qlparser/qtintervalop.icc34
-rw-r--r--qlparser/qtiterator.cc260
-rw-r--r--qlparser/qtiterator.hh118
-rw-r--r--qlparser/qtiterator.icc36
-rw-r--r--qlparser/qtjoiniterator.cc338
-rw-r--r--qlparser/qtjoiniterator.hh120
-rw-r--r--qlparser/qtjoiniterator.icc35
-rw-r--r--qlparser/qtmarrayop.cc314
-rw-r--r--qlparser/qtmarrayop.hh90
-rw-r--r--qlparser/qtmarrayop.icc34
-rw-r--r--qlparser/qtmarrayop2.cc369
-rw-r--r--qlparser/qtmarrayop2.hh113
-rw-r--r--qlparser/qtmarrayop2.icc54
-rw-r--r--qlparser/qtmdd.cc329
-rw-r--r--qlparser/qtmdd.hh138
-rw-r--r--qlparser/qtmdd.icc59
-rw-r--r--qlparser/qtmddaccess.cc250
-rw-r--r--qlparser/qtmddaccess.hh114
-rw-r--r--qlparser/qtmddaccess.icc42
-rw-r--r--qlparser/qtmintervaldata.cc188
-rw-r--r--qlparser/qtmintervaldata.hh108
-rw-r--r--qlparser/qtmintervaldata.icc59
-rw-r--r--qlparser/qtmintervalop.cc222
-rw-r--r--qlparser/qtmintervalop.hh81
-rw-r--r--qlparser/qtmintervalop.icc34
-rw-r--r--qlparser/qtnaryoperation.cc414
-rw-r--r--qlparser/qtnaryoperation.hh137
-rw-r--r--qlparser/qtnaryoperation.icc50
-rw-r--r--qlparser/qtnode.cc645
-rw-r--r--qlparser/qtnode.hh503
-rw-r--r--qlparser/qtnode.icc130
-rw-r--r--qlparser/qtoid.cc179
-rw-r--r--qlparser/qtoid.hh78
-rw-r--r--qlparser/qtoid.icc35
-rw-r--r--qlparser/qtoncstream.cc49
-rw-r--r--qlparser/qtoncstream.hh102
-rw-r--r--qlparser/qtoncstream.icc42
-rw-r--r--qlparser/qtoperation.cc126
-rw-r--r--qlparser/qtoperation.hh120
-rw-r--r--qlparser/qtoperation.icc43
-rw-r--r--qlparser/qtoperationiterator.cc303
-rw-r--r--qlparser/qtoperationiterator.hh120
-rw-r--r--qlparser/qtoperationiterator.icc74
-rw-r--r--qlparser/qtpointdata.cc114
-rw-r--r--qlparser/qtpointdata.hh101
-rw-r--r--qlparser/qtpointdata.icc45
-rw-r--r--qlparser/qtpointop.cc214
-rw-r--r--qlparser/qtpointop.hh81
-rw-r--r--qlparser/qtpointop.icc34
-rw-r--r--qlparser/qtscalardata.cc204
-rw-r--r--qlparser/qtscalardata.hh137
-rw-r--r--qlparser/qtscalardata.icc58
-rw-r--r--qlparser/qtselectioniterator.cc281
-rw-r--r--qlparser/qtselectioniterator.hh119
-rw-r--r--qlparser/qtselectioniterator.icc68
-rw-r--r--qlparser/qtstringdata.cc88
-rw-r--r--qlparser/qtstringdata.hh97
-rw-r--r--qlparser/qtstringdata.icc42
-rw-r--r--qlparser/qtunaryfunc.cc414
-rw-r--r--qlparser/qtunaryfunc.hh161
-rw-r--r--qlparser/qtunaryfunc.icc51
-rw-r--r--qlparser/qtunaryinduce.cc1013
-rw-r--r--qlparser/qtunaryinduce.hh267
-rw-r--r--qlparser/qtunaryinduce.icc84
-rw-r--r--qlparser/qtunaryoperation.cc204
-rw-r--r--qlparser/qtunaryoperation.hh111
-rw-r--r--qlparser/qtunaryoperation.icc59
-rw-r--r--qlparser/qtupdate.cc812
-rw-r--r--qlparser/qtupdate.hh119
-rw-r--r--qlparser/qtupdate.icc65
-rw-r--r--qlparser/qtvariable.cc392
-rw-r--r--qlparser/qtvariable.hh136
-rw-r--r--qlparser/qtvariable.icc84
-rw-r--r--qlparser/querytree.cc489
-rw-r--r--qlparser/querytree.hh265
-rw-r--r--qlparser/querytree.icc47
-rw-r--r--qlparser/rasml.awk9
-rw-r--r--qlparser/rasmlgrammar.html27
-rw-r--r--qlparser/symtab.cc159
-rw-r--r--qlparser/symtab.hh110
-rw-r--r--qlparser/test/Makefile89
-rw-r--r--qlparser/test/insertbin.cpp316
-rw-r--r--qlparser/test/template_inst.hh152
-rw-r--r--qlparser/test/test_evaluate.cc338
-rw-r--r--qlparser/test/test_qlparser.cc205
-rw-r--r--rascontrol/Makefile.am53
-rw-r--r--rascontrol/rascontrol.cc341
-rw-r--r--rascontrol/rascontrol.hh164
-rw-r--r--rascontrol/rascontrol_class.cc398
-rw-r--r--rascontrol/rasmgr_tester.cc171
-rw-r--r--rascontrol/rasmgr_tester.hh85
-rw-r--r--rascontrol/rasmgr_utils_comm.cc359
-rw-r--r--rascontrol/rasmgr_utils_comm.hh127
-rw-r--r--rascontrol/rasmgr_utils_conf.cc71
-rw-r--r--rascontrol/rasmgr_utils_conf.hh61
-rw-r--r--rascontrol/raspasswd.cc241
-rw-r--r--rascontrol/raspasswd.hh89
-rw-r--r--rascontrol/test/rasmgrtest.cc178
-rw-r--r--rascontrol/test/rasmgrtester_conf.cc133
-rw-r--r--rascontrol/test/rasmgrtester_conf.hh79
-rw-r--r--rasdl/Makefile.am70
-rw-r--r--rasdl/alloca.cc530
-rw-r--r--rasdl/lex.ll240
-rw-r--r--rasdl/odl.yy631
-rw-r--r--rasdl/parse.cc996
-rw-r--r--rasdl/parse.hh748
-rw-r--r--rasdl/rasdl.awk11
-rw-r--r--rasdl/rasdl.cc724
-rw-r--r--rasdl/rasdl_error.cc124
-rw-r--r--rasdl/rasdl_error.hh77
-rw-r--r--rasdl/rasdlgrammar.html27
-rw-r--r--rasdl/symbtbl.cc305
-rw-r--r--rasdl/symbtbl.hh196
-rw-r--r--rasdl/template_inst.hh83
-rw-r--r--rasdl/test/Makefile78
-rw-r--r--rasdl/test/basictypes.dl157
-rw-r--r--rasdl/test/rasdl_test.sh103
-rw-r--r--rasdl/test/test_rasdl.cc80
-rw-r--r--rasdl/yparse.hh59
-rw-r--r--rasdoc/Doxyfile_external1284
-rw-r--r--rasdoc/Doxyfile_internal1284
-rw-r--r--rasdoc/Doxyfile_relational1284
-rw-r--r--raslib/Makefile.am54
-rw-r--r--raslib/attribute.cc257
-rw-r--r--raslib/attribute.hh134
-rw-r--r--raslib/basetype.cc77
-rw-r--r--raslib/basetype.hh80
-rw-r--r--raslib/collectiontype.cc140
-rw-r--r--raslib/collectiontype.hh108
-rw-r--r--raslib/complex.cc110
-rw-r--r--raslib/complex.hh87
-rw-r--r--raslib/complex.icc1
-rw-r--r--raslib/complextype.cc284
-rw-r--r--raslib/complextype.hh71
-rw-r--r--raslib/complextype.icc1
-rw-r--r--raslib/dlist.cc71
-rw-r--r--raslib/dlist.hh42
-rw-r--r--raslib/endian.cc623
-rw-r--r--raslib/endian.hh118
-rw-r--r--raslib/error.cc888
-rw-r--r--raslib/error.hh583
-rw-r--r--raslib/error.icc74
-rw-r--r--raslib/flatbasetype.cc301
-rw-r--r--raslib/flatbasetype.hh123
-rw-r--r--raslib/itertype.cc97
-rw-r--r--raslib/itertype.hh86
-rw-r--r--raslib/marraytype.cc131
-rw-r--r--raslib/marraytype.hh101
-rw-r--r--raslib/mddtypes.cc416
-rw-r--r--raslib/mddtypes.hh491
-rw-r--r--raslib/memblockvec.cc107
-rw-r--r--raslib/memblockvec.hh84
-rw-r--r--raslib/metaobject.cc81
-rw-r--r--raslib/metaobject.hh77
-rw-r--r--raslib/minterval.cc1055
-rw-r--r--raslib/minterval.hh567
-rw-r--r--raslib/minterval.icc138
-rw-r--r--raslib/mintervaltype.cc80
-rw-r--r--raslib/mintervaltype.hh79
-rw-r--r--raslib/miter.cc33
-rw-r--r--raslib/miter.hh99
-rw-r--r--raslib/miter.icc144
-rw-r--r--raslib/mitera.cc141
-rw-r--r--raslib/mitera.hh92
-rw-r--r--raslib/miterd.cc117
-rw-r--r--raslib/miterd.hh165
-rw-r--r--raslib/miterd.icc166
-rw-r--r--raslib/miterf.hh128
-rw-r--r--raslib/miterf.icc222
-rw-r--r--raslib/odmgtypes.hh204
-rw-r--r--raslib/oid.cc352
-rw-r--r--raslib/oid.hh137
-rw-r--r--raslib/oid.icc62
-rw-r--r--raslib/oidtype.cc80
-rw-r--r--raslib/oidtype.hh79
-rw-r--r--raslib/parseparams.cc283
-rw-r--r--raslib/parseparams.hh116
-rw-r--r--raslib/point.cc372
-rw-r--r--raslib/point.hh165
-rw-r--r--raslib/point.icc54
-rw-r--r--raslib/pointtype.cc81
-rw-r--r--raslib/pointtype.hh81
-rw-r--r--raslib/primitive.cc439
-rw-r--r--raslib/primitive.hh143
-rw-r--r--raslib/primitivetype.cc601
-rw-r--r--raslib/primitivetype.hh147
-rw-r--r--raslib/property.cc99
-rw-r--r--raslib/property.hh77
-rw-r--r--raslib/rm.cc31
-rw-r--r--raslib/rm.hh38
-rw-r--r--raslib/rmdebug.cc430
-rw-r--r--raslib/rmdebug.hh382
-rw-r--r--raslib/rmdebug.icc120
-rw-r--r--raslib/rminit.cc321
-rw-r--r--raslib/rminit.hh181
-rw-r--r--raslib/scalar.cc120
-rw-r--r--raslib/scalar.hh100
-rw-r--r--raslib/shhopt.c485
-rw-r--r--raslib/shhopt.h56
-rw-r--r--raslib/sinterval.cc1018
-rw-r--r--raslib/sinterval.hh451
-rw-r--r--raslib/sinterval.icc76
-rw-r--r--raslib/sintervaltype.cc80
-rw-r--r--raslib/sintervaltype.hh81
-rw-r--r--raslib/storageman.cc133
-rw-r--r--raslib/storageman.hh116
-rw-r--r--raslib/structure.cc282
-rw-r--r--raslib/structure.hh111
-rw-r--r--raslib/structuretype.cc276
-rw-r--r--raslib/structuretype.hh118
-rw-r--r--raslib/template_inst.hh78
-rw-r--r--raslib/test/Makefile192
-rw-r--r--raslib/test/errtxts244
-rw-r--r--raslib/test/test_endian.cc156
-rw-r--r--raslib/test/test_error.cc223
-rw-r--r--raslib/test/test_metaobject.cc332
-rw-r--r--raslib/test/test_minterval.cc118
-rw-r--r--raslib/test/test_miter.cc334
-rw-r--r--raslib/test/test_miterdbin0 -> 241129 bytes
-rw-r--r--raslib/test/test_miterd.cc75
-rw-r--r--raslib/test/test_miterf.cc118
-rw-r--r--raslib/test/test_oid.cc181
-rw-r--r--raslib/test/test_params.cc101
-rw-r--r--raslib/test/test_point.cc90
-rw-r--r--raslib/test/test_rmdebug.cc179
-rw-r--r--raslib/test/test_sinterval.cc164
-rw-r--r--raslib/test/test_timer.cc101
-rw-r--r--raslib/type.cc671
-rw-r--r--raslib/type.hh167
-rw-r--r--rasmgr/Makefile.am60
-rw-r--r--rasmgr/hostcmp.cc66
-rw-r--r--rasmgr/ras_crypto.cc79
-rw-r--r--rasmgr/ras_crypto.hh49
-rw-r--r--rasmgr/rasmgr.hh116
-rw-r--r--rasmgr/rasmgr_comm.cc294
-rw-r--r--rasmgr/rasmgr_comm.hh100
-rw-r--r--rasmgr/rasmgr_comm_nb.cc921
-rw-r--r--rasmgr/rasmgr_comm_nb.hh196
-rw-r--r--rasmgr/rasmgr_config.cc601
-rw-r--r--rasmgr/rasmgr_config.hh134
-rw-r--r--rasmgr/rasmgr_dbm.cc573
-rw-r--r--rasmgr/rasmgr_dbm.hh171
-rw-r--r--rasmgr/rasmgr_error.cc101
-rw-r--r--rasmgr/rasmgr_error.hh91
-rw-r--r--rasmgr/rasmgr_host.cc575
-rw-r--r--rasmgr/rasmgr_host.hh122
-rw-r--r--rasmgr/rasmgr_localsrv.cc368
-rw-r--r--rasmgr/rasmgr_localsrv.hh81
-rw-r--r--rasmgr/rasmgr_main.cc256
-rw-r--r--rasmgr/rasmgr_master.hh136
-rw-r--r--rasmgr/rasmgr_master_nb.cc1007
-rw-r--r--rasmgr/rasmgr_master_nb_hack.cc1007
-rw-r--r--rasmgr/rasmgr_protocol.hh68
-rw-r--r--rasmgr/rasmgr_random.cc176
-rw-r--r--rasmgr/rasmgr_rascontrol.cc2187
-rw-r--r--rasmgr/rasmgr_rascontrol.hh166
-rw-r--r--rasmgr/rasmgr_rascontrol_help.cc521
-rw-r--r--rasmgr/rasmgr_srv.cc858
-rw-r--r--rasmgr/rasmgr_srv.cc.ORIG840
-rw-r--r--rasmgr/rasmgr_srv.hh165
-rw-r--r--rasmgr/rasmgr_users.cc861
-rw-r--r--rasmgr/rasmgr_users.hh257
-rw-r--r--rasmgr/test/Makefile46
-rw-r--r--rasmgr/test/Makefile.dep0
-rw-r--r--rasmgr/test/check_opensockets.sh25
-rw-r--r--rasmgr/test/check_opensockets_idleresult.log92
-rw-r--r--rasmgr/test/test_hostcmpbin0 -> 35013 bytes
-rw-r--r--rasmgr/test/test_hostcmp.cc56
-rw-r--r--rasmgr/test/test_hostcmp.sh36
-rw-r--r--rasmgr/test/test_rasmgr.sh103
-rw-r--r--rasodmg/Makefile.am58
-rw-r--r--rasodmg/alignedtiling.cc635
-rw-r--r--rasodmg/alignedtiling.hh211
-rw-r--r--rasodmg/alignedtiling.icc31
-rw-r--r--rasodmg/collection.cc627
-rw-r--r--rasodmg/collection.hh224
-rw-r--r--rasodmg/collection.icc73
-rw-r--r--rasodmg/database.cc475
-rw-r--r--rasodmg/database.hh270
-rw-r--r--rasodmg/database.icc38
-rw-r--r--rasodmg/dirdecompose.cc147
-rw-r--r--rasodmg/dirdecompose.hh114
-rw-r--r--rasodmg/dirtiling.cc682
-rw-r--r--rasodmg/dirtiling.hh133
-rw-r--r--rasodmg/gmarray.cc484
-rw-r--r--rasodmg/gmarray.hh185
-rw-r--r--rasodmg/gmarray.icc119
-rw-r--r--rasodmg/interesttiling.cc809
-rw-r--r--rasodmg/interesttiling.hh183
-rw-r--r--rasodmg/iterator.cc216
-rw-r--r--rasodmg/iterator.hh137
-rw-r--r--rasodmg/iterator.icc39
-rw-r--r--rasodmg/marray.cc354
-rw-r--r--rasodmg/marray.hh145
-rw-r--r--rasodmg/marray.icc31
-rw-r--r--rasodmg/object.cc603
-rw-r--r--rasodmg/object.hh240
-rw-r--r--rasodmg/object.icc151
-rw-r--r--rasodmg/oqlquery.cc628
-rw-r--r--rasodmg/oqlquery.hh251
-rw-r--r--rasodmg/oqlquery.icc52
-rw-r--r--rasodmg/partinsert.cc199
-rw-r--r--rasodmg/partinsert.hh109
-rw-r--r--rasodmg/polycutout.cc709
-rw-r--r--rasodmg/polycutout.hh162
-rw-r--r--rasodmg/polygon.cc879
-rw-r--r--rasodmg/polygon.hh287
-rw-r--r--rasodmg/ref.cc656
-rw-r--r--rasodmg/ref.hh323
-rw-r--r--rasodmg/ref.icc64
-rw-r--r--rasodmg/set.cc92
-rw-r--r--rasodmg/set.hh79
-rw-r--r--rasodmg/stattiling.cc678
-rw-r--r--rasodmg/stattiling.hh210
-rw-r--r--rasodmg/storagelayout.cc182
-rw-r--r--rasodmg/storagelayout.hh132
-rw-r--r--rasodmg/storagelayout.icc31
-rw-r--r--rasodmg/test/Makefile372
-rw-r--r--rasodmg/test/Makefile.dep0
-rw-r--r--rasodmg/test/cmov_16.ql425
-rw-r--r--rasodmg/test/cmov_32.ql425
-rw-r--r--rasodmg/test/cmov_64.ql425
-rw-r--r--rasodmg/test/croll_16.ql180
-rw-r--r--rasodmg/test/croll_32.ql180
-rw-r--r--rasodmg/test/croll_64.ql180
-rw-r--r--rasodmg/test/croll_sliced.ql180
-rw-r--r--rasodmg/test/csel_16.ql43
-rw-r--r--rasodmg/test/csel_32.ql43
-rw-r--r--rasodmg/test/csel_64.ql43
-rw-r--r--rasodmg/test/csel_sliced.ql43
-rw-r--r--rasodmg/test/defconv.cc598
-rw-r--r--rasodmg/test/defdiff.cc537
-rw-r--r--rasodmg/test/defutil.hh412
-rw-r--r--rasodmg/test/deletecollection.cc720
-rw-r--r--rasodmg/test/earth.ql68
-rw-r--r--rasodmg/test/earth_16.ql41
-rw-r--r--rasodmg/test/earth_32.ql41
-rw-r--r--rasodmg/test/earth_64.ql41
-rw-r--r--rasodmg/test/gen_pattern.cc248
-rw-r--r--rasodmg/test/gen_query.pl116
-rw-r--r--rasodmg/test/gen_rollup.pl209
-rw-r--r--rasodmg/test/gen_s2k.pl65
-rw-r--r--rasodmg/test/init_fast_collection.pl111
-rw-r--r--rasodmg/test/polytest.poly3
-rw-r--r--rasodmg/test/rasql.cc126
-rw-r--r--rasodmg/test/rasql.hh38
-rw-r--r--rasodmg/test/readln.cc64
-rw-r--r--rasodmg/test/readln.hh45
-rw-r--r--rasodmg/test/runbm.sh94
-rw-r--r--rasodmg/test/small_16.ql42
-rw-r--r--rasodmg/test/small_32.ql42
-rw-r--r--rasodmg/test/small_64.ql42
-rw-r--r--rasodmg/test/stat1.dat3
-rw-r--r--rasodmg/test/stat2.dat7
-rw-r--r--rasodmg/test/stat3.dat4
-rw-r--r--rasodmg/test/system_basic.cc1945
-rw-r--r--rasodmg/test/system_basic.hh210
-rw-r--r--rasodmg/test/system_compare.cc273
-rw-r--r--rasodmg/test/system_compare.hh40
-rw-r--r--rasodmg/test/system_insert.cc384
-rw-r--r--rasodmg/test/system_insert.hh43
-rw-r--r--rasodmg/test/system_query.cc400
-rw-r--r--rasodmg/test/system_query.hh37
-rw-r--r--rasodmg/test/system_update.cc399
-rw-r--r--rasodmg/test/system_update.hh40
-rw-r--r--rasodmg/test/test_alignedtiling.cc126
-rw-r--r--rasodmg/test/test_all.sh9
-rw-r--r--rasodmg/test/test_benchmark.cc273
-rw-r--r--rasodmg/test/test_bmark_dir.cc257
-rw-r--r--rasodmg/test/test_bmark_dir1.cc318
-rw-r--r--rasodmg/test/test_bmark_int.cc241
-rw-r--r--rasodmg/test/test_bmark_int1.cc242
-rw-r--r--rasodmg/test/test_bmark_pet.cc235
-rw-r--r--rasodmg/test/test_bmark_stat.cc331
-rw-r--r--rasodmg/test/test_breakdown.cc112
-rw-r--r--rasodmg/test/test_collection.cc116
-rw-r--r--rasodmg/test/test_comp_conv.sh325
-rw-r--r--rasodmg/test/test_db2blob.sqC399
-rw-r--r--rasodmg/test/test_dirtiling.cc93
-rw-r--r--rasodmg/test/test_fastscale.cc293
-rw-r--r--rasodmg/test/test_gmarray.cc229
-rw-r--r--rasodmg/test/test_insert.cc235
-rw-r--r--rasodmg/test/test_insert3.cc843
-rw-r--r--rasodmg/test/test_interesttiling.cc97
-rw-r--r--rasodmg/test/test_iterator.cc135
-rw-r--r--rasodmg/test/test_lookup.cc378
-rw-r--r--rasodmg/test/test_marray.cc110
-rw-r--r--rasodmg/test/test_oqlquery.cc157
-rw-r--r--rasodmg/test/test_polygon.cc951
-rw-r--r--rasodmg/test/test_query.cc693
-rw-r--r--rasodmg/test/test_ref.cc69
-rw-r--r--rasodmg/test/test_set.cc104
-rw-r--r--rasodmg/test/test_stattiling.cc173
-rw-r--r--rasodmg/test/test_storage.cc282
-rw-r--r--rasodmg/test/test_transaction.cc152
-rw-r--r--rasodmg/test/tmov_16.ql425
-rw-r--r--rasodmg/test/tmov_32.ql425
-rw-r--r--rasodmg/test/tmov_64.ql425
-rw-r--r--rasodmg/test/tomo_ops.ql27
-rw-r--r--rasodmg/test/tomo_select.ql72
-rw-r--r--rasodmg/test/troll_16.ql180
-rw-r--r--rasodmg/test/troll_32.ql180
-rw-r--r--rasodmg/test/troll_64.ql180
-rw-r--r--rasodmg/test/troll_sliced.ql180
-rw-r--r--rasodmg/test/tsel_16.ql43
-rw-r--r--rasodmg/test/tsel_32.ql43
-rw-r--r--rasodmg/test/tsel_64.ql43
-rw-r--r--rasodmg/test/tsel_sliced.ql43
-rw-r--r--rasodmg/tiling.cc309
-rw-r--r--rasodmg/tiling.hh228
-rw-r--r--rasodmg/transaction.cc377
-rw-r--r--rasodmg/transaction.hh167
-rw-r--r--rasodmg/transaction.icc46
-rw-r--r--reladminif/Makefile.am68
-rw-r--r--reladminif/adminif.hh174
-rw-r--r--reladminif/adminif.pgc90
-rw-r--r--reladminif/adminifcommon.cc163
-rw-r--r--reladminif/binaryrepresentation.hh31
-rw-r--r--reladminif/databaseif.hh222
-rw-r--r--reladminif/databaseif.pgc1382
-rw-r--r--reladminif/databaseifcommon.cc242
-rw-r--r--reladminif/dbnamedobject.cc179
-rw-r--r--reladminif/dbnamedobject.hh121
-rw-r--r--reladminif/dbobject.cc459
-rw-r--r--reladminif/dbobject.hh291
-rw-r--r--reladminif/dbobjectiditerator.cc103
-rw-r--r--reladminif/dbobjectiditerator.hh108
-rw-r--r--reladminif/dbobjectiterator.cc104
-rw-r--r--reladminif/dbobjectiterator.hh104
-rw-r--r--reladminif/dbref.cc874
-rw-r--r--reladminif/dbref.hh301
-rw-r--r--reladminif/destroyable.hh52
-rw-r--r--reladminif/eoid.cc231
-rw-r--r--reladminif/eoid.hh146
-rw-r--r--reladminif/externs.h81
-rw-r--r--reladminif/lists.h106
-rw-r--r--reladminif/objectbroker.hh506
-rw-r--r--reladminif/objectbroker.pgc1029
-rw-r--r--reladminif/objectbrokercommon.cc1144
-rw-r--r--reladminif/oidif.hh307
-rw-r--r--reladminif/oidif.pgc135
-rw-r--r--reladminif/oidifcommon.cc414
-rw-r--r--reladminif/sqlerror.hh118
-rw-r--r--reladminif/sqlerror.pgc198
-rw-r--r--reladminif/sqlglobals.h50
-rw-r--r--reladminif/test/Makefile90
-rw-r--r--reladminif/test/admintest.C92
-rw-r--r--reladminif/test/check.cc301
-rw-r--r--reladminif/test/dbnamedobjtest.C88
-rw-r--r--reladminif/test/dbreftest.C70
-rw-r--r--reladminif/test/demobld.sql125
-rw-r--r--reladminif/test/demodrop.sql42
-rw-r--r--reladminif/test/eoidtest.C128
-rw-r--r--reladminif/test/indextest.cc227
-rw-r--r--reladminif/test/perstest.C1155
-rw-r--r--reladminif/test/test_databaseif.cc203
-rw-r--r--reladminif/test/testcenter.h47
-rw-r--r--reladminif/test/testconnect.c395
-rw-r--r--reladminif/test/testta.pgc281
-rw-r--r--reladminif/transactionif.hh107
-rw-r--r--reladminif/transactionif.pgc242
-rw-r--r--reladminif/transactionifcommon.cc69
-rw-r--r--relblobif/Makefile.am52
-rw-r--r--relblobif/blobtile.file.pgc402
-rw-r--r--relblobif/blobtile.hh160
-rw-r--r--relblobif/blobtile.pgc765
-rw-r--r--relblobif/blobtilecommon.cc172
-rw-r--r--relblobif/dbtile.cc329
-rw-r--r--relblobif/dbtile.hh222
-rw-r--r--relblobif/filestorageexception.hh42
-rw-r--r--relblobif/ifilestorage.hh56
-rw-r--r--relblobif/inlinetile.cc259
-rw-r--r--relblobif/inlinetile.hh176
-rw-r--r--relblobif/simplefilestorage.cc178
-rw-r--r--relblobif/simplefilestorage.hh66
-rw-r--r--relblobif/test/Makefile65
-rw-r--r--relblobif/test/README.txt5
-rw-r--r--relblobif/test/blobdump.c323
-rw-r--r--relblobif/test/blobdump.pgc315
-rw-r--r--relblobif/test/dblob.C242
-rw-r--r--relblobif/tileid.hh36
-rw-r--r--relcatalogif/Makefile.am69
-rw-r--r--relcatalogif/alltypes.hh38
-rw-r--r--relcatalogif/atomictype.C113
-rw-r--r--relcatalogif/atomictype.hh93
-rw-r--r--relcatalogif/basetype.C130
-rw-r--r--relcatalogif/basetype.hh161
-rw-r--r--relcatalogif/booltype.C157
-rw-r--r--relcatalogif/booltype.hh104
-rw-r--r--relcatalogif/chartype.C158
-rw-r--r--relcatalogif/chartype.hh106
-rw-r--r--relcatalogif/collectiontype.C98
-rw-r--r--relcatalogif/collectiontype.hh129
-rw-r--r--relcatalogif/complextype.hh131
-rw-r--r--relcatalogif/complextype.icc159
-rw-r--r--relcatalogif/compositetype.C104
-rw-r--r--relcatalogif/compositetype.hh99
-rw-r--r--relcatalogif/dbminterval.hh103
-rw-r--r--relcatalogif/dbminterval.lis0
-rw-r--r--relcatalogif/dbminterval.pgc381
-rw-r--r--relcatalogif/doubletype.C154
-rw-r--r--relcatalogif/doubletype.hh103
-rw-r--r--relcatalogif/floattype.C159
-rw-r--r--relcatalogif/floattype.hh95
-rw-r--r--relcatalogif/inlineminterval.cc139
-rw-r--r--relcatalogif/inlineminterval.hh73
-rw-r--r--relcatalogif/integraltype.hh89
-rw-r--r--relcatalogif/integraltype.icc53
-rw-r--r--relcatalogif/longtype.C147
-rw-r--r--relcatalogif/longtype.hh106
-rw-r--r--relcatalogif/mddbasetype.hh142
-rw-r--r--relcatalogif/mddbasetype.lis0
-rw-r--r--relcatalogif/mddbasetype.pgc125
-rw-r--r--relcatalogif/mddbasetypecommon.cc174
-rw-r--r--relcatalogif/mdddimensiontype.hh128
-rw-r--r--relcatalogif/mdddimensiontype.lis0
-rw-r--r--relcatalogif/mdddimensiontype.pgc148
-rw-r--r--relcatalogif/mdddimensiontypecommon.cc166
-rw-r--r--relcatalogif/mdddomaintype.hh137
-rw-r--r--relcatalogif/mdddomaintype.lis0
-rw-r--r--relcatalogif/mdddomaintype.pgc143
-rw-r--r--relcatalogif/mdddomaintypecommon.cc204
-rw-r--r--relcatalogif/mddtype.hh140
-rw-r--r--relcatalogif/mddtype.lis0
-rw-r--r--relcatalogif/mddtype.pgc128
-rw-r--r--relcatalogif/mddtypecommon.cc128
-rw-r--r--relcatalogif/octettype.C158
-rw-r--r--relcatalogif/octettype.hh103
-rw-r--r--relcatalogif/realtype.hh90
-rw-r--r--relcatalogif/realtype.icc52
-rw-r--r--relcatalogif/settype.hh82
-rw-r--r--relcatalogif/settype.lis0
-rw-r--r--relcatalogif/settype.pgc140
-rw-r--r--relcatalogif/settypecommon.cc89
-rw-r--r--relcatalogif/shorttype.C153
-rw-r--r--relcatalogif/shorttype.hh104
-rw-r--r--relcatalogif/structtype.hh173
-rw-r--r--relcatalogif/structtype.icc54
-rw-r--r--relcatalogif/structtype.lis0
-rw-r--r--relcatalogif/structtype.pgc214
-rw-r--r--relcatalogif/structtypecommon.cc511
-rw-r--r--relcatalogif/type.C138
-rw-r--r--relcatalogif/type.hh137
-rw-r--r--relcatalogif/typeiterator.C0
-rw-r--r--relcatalogif/typeiterator.hh30
-rw-r--r--relcatalogif/uintegraltype.hh90
-rw-r--r--relcatalogif/uintegraltype.icc51
-rw-r--r--relcatalogif/ulongtype.C149
-rw-r--r--relcatalogif/ulongtype.hh101
-rw-r--r--relcatalogif/ushorttype.C155
-rw-r--r--relcatalogif/ushorttype.hh100
-rw-r--r--relindexif/Makefile.am49
-rw-r--r--relindexif/dbrcindexds.hh210
-rw-r--r--relindexif/dbrcindexds.pgc495
-rw-r--r--relindexif/dbrcindexdscommon.cc286
-rw-r--r--relindexif/dbtcindex.hh192
-rw-r--r--relindexif/dbtcindex.pgc338
-rw-r--r--relindexif/dbtcindexcommon.cc357
-rw-r--r--relindexif/hierindex.hh219
-rw-r--r--relindexif/hierindex.pgc745
-rw-r--r--relindexif/hierindexcommon.cc1033
-rw-r--r--relindexif/indexid.hh37
-rw-r--r--relindexif/test/Makefile97
-rw-r--r--relindexif/test/computedindex.cc109
-rw-r--r--relindexif/test/exportindex.cc234
-rw-r--r--relindexif/test/miteratest.cc53
-rw-r--r--relindexif/test/testindex.pc262
-rw-r--r--relmddif/Makefile.am49
-rw-r--r--relmddif/dbiterid.hh33
-rw-r--r--relmddif/dbmddobj.hh254
-rw-r--r--relmddif/dbmddobj.pgc546
-rw-r--r--relmddif/dbmddset.hh176
-rw-r--r--relmddif/dbmddset.pgc314
-rw-r--r--relmddif/dbmddsetcommon.cc281
-rw-r--r--relmddif/mddid.hh36
-rw-r--r--relmddif/test/Makefile77
-rw-r--r--relmddif/test/dbiteritest.C67
-rw-r--r--relmddif/test/dbmddcollidt.C111
-rw-r--r--relmddif/test/dbmddcolloidentryt.C101
-rw-r--r--relmddif/test/dbobjtest.C150
-rw-r--r--relmddif/test/intervaltest.C120
-rw-r--r--relmddif/test/mdditest.C312
-rw-r--r--relstorageif/Makefile.am50
-rw-r--r--relstorageif/dbstoragelayout.hh214
-rw-r--r--relstorageif/dbstoragelayout.pgc646
-rw-r--r--relstorageif/empty.cc1
-rw-r--r--relstorageif/storageid.hh32
-rw-r--r--rnprotocol/Makefile.am47
-rw-r--r--rnprotocol/rnpclientcomm.cc1712
-rw-r--r--rnprotocol/rnpclientcomm.hh346
-rw-r--r--rnprotocol/rnpclientcomm2.cc1226
-rw-r--r--rnprotocol/rnpcommunication.cc702
-rw-r--r--rnprotocol/rnpcommunication.hh345
-rw-r--r--rnprotocol/rnpembedded.cc467
-rw-r--r--rnprotocol/rnpembedded.hh256
-rw-r--r--rnprotocol/rnprasserver.cc72
-rw-r--r--rnprotocol/rnprasserver.hh124
-rw-r--r--rnprotocol/rnprotocol.cc819
-rw-r--r--rnprotocol/rnprotocol.hh462
-rw-r--r--rnprotocol/rnpserver.cc134
-rw-r--r--rnprotocol/rnpserver.hh33
-rw-r--r--rnprotocol/rnpservercomm.cc1344
-rw-r--r--rnprotocol/rnpservercomm.hh157
-rw-r--r--rnprotocol/srvrasmgrcomm.cc213
-rw-r--r--rnprotocol/srvrasmgrcomm.hh67
-rw-r--r--server/Makefile.am58
-rw-r--r--server/createinitmdd.cc397
-rw-r--r--server/createinitmdd.hh105
-rw-r--r--server/rasserver_config.cc297
-rw-r--r--server/rasserver_config.hh138
-rw-r--r--server/rasserver_entry.cc528
-rw-r--r--server/rasserver_entry.hh140
-rw-r--r--server/rasserver_main.cc360
-rw-r--r--server/template_inst.hh132
-rw-r--r--server/test/Makefile59
-rw-r--r--server/test/test_mult-db-open.cc165
-rw-r--r--servercomm/Makefile.am50
-rw-r--r--servercomm/callbackmgr.cc172
-rw-r--r--servercomm/callbackmgr.hh136
-rw-r--r--servercomm/httpserver.cc1371
-rw-r--r--servercomm/httpserver.hh173
-rw-r--r--servercomm/httpserver.icc31
-rw-r--r--servercomm/manager.cc1885
-rw-r--r--servercomm/servercomm.cc1399
-rw-r--r--servercomm/servercomm.hh1120
-rw-r--r--servercomm/servercomm.icc31
-rw-r--r--servercomm/servercomm2.cc4051
-rw-r--r--servercomm/test/Makefile117
-rw-r--r--servercomm/test/template_inst.hh138
-rw-r--r--servercomm/test/test_dbcontent.cc161
-rw-r--r--servercomm/test/test_oid.cc229
-rw-r--r--servercomm/test/test_servercomm.cc128
-rw-r--r--storagemgr/Makefile.am35
-rw-r--r--storagemgr/sstoragelayout.cc260
-rw-r--r--storagemgr/sstoragelayout.hh236
-rw-r--r--systemtest/Makefile56
-rw-r--r--systemtest/image1.bmpbin0 -> 450 bytes
-rw-r--r--systemtest/image1.hdfbin0 -> 2968 bytes
-rw-r--r--systemtest/image1.jpgbin0 -> 631 bytes
-rw-r--r--systemtest/image1.pngbin0 -> 145 bytes
-rw-r--r--systemtest/image1.tifbin0 -> 2230 bytes
-rw-r--r--systemtest/image1.vffbin0 -> 276 bytes
-rw-r--r--systemtest/image2.bmpbin0 -> 450 bytes
-rw-r--r--systemtest/image2.hdfbin0 -> 2968 bytes
-rw-r--r--systemtest/image2.jpgbin0 -> 631 bytes
-rw-r--r--systemtest/image2.pngbin0 -> 145 bytes
-rw-r--r--systemtest/image2.tifbin0 -> 2230 bytes
-rw-r--r--systemtest/image2.vff15
-rw-r--r--systemtest/images/ovl1.ppm4
-rw-r--r--systemtest/images/ovl2.ppmbin0 -> 313 bytes
-rw-r--r--systemtest/images/ovl3.ppmbin0 -> 313 bytes
-rw-r--r--systemtest/memleak/overview18
-rw-r--r--systemtest/rasdl/generator_rasdl.sh41
-rw-r--r--systemtest/rasdl/rasdl.sh9
-rw-r--r--systemtest/rasdl/test_rasdl.sh90
-rw-r--r--systemtest/scripts/rasql_1.pngbin0 -> 17042 bytes
-rw-r--r--systemtest/scripts/test_error-par.old2
-rw-r--r--systemtest/scripts/test_error-par.sh130
-rw-r--r--systemtest/scripts/test_error-par/Makefile77
-rw-r--r--systemtest/scripts/test_error-par/test_error-par.cc467
-rw-r--r--systemtest/scripts/test_error-seq.old13
-rw-r--r--systemtest/scripts/test_error-seq.sh99
-rw-r--r--systemtest/scripts/test_error-seq/Makefile70
-rw-r--r--systemtest/scripts/test_error-seq/test_error-seq.cc515
-rw-r--r--systemtest/scripts/test_ql-extend.sh131
-rw-r--r--systemtest/scripts/test_ql-png-options.sh251
-rw-r--r--systemtest/scripts/test_ql-png-options.test/png-color-trns_1.pngbin0 -> 169 bytes
-rw-r--r--systemtest/scripts/test_ql-png-options.test/png-color-trns_10.pngbin0 -> 169 bytes
-rw-r--r--systemtest/scripts/test_ql-png-options.test/png-gray-trns_1.pngbin0 -> 161 bytes
-rw-r--r--systemtest/scripts/test_ql-png-options.test/png-gray-trns_2.pngbin0 -> 161 bytes
-rw-r--r--systemtest/scripts/test_ql-png-options.test/png-gray-trns_3.pngbin0 -> 161 bytes
-rw-r--r--systemtest/scripts/test_ql-png-options.test/png-gray-trns_4.pngbin0 -> 161 bytes
-rw-r--r--systemtest/scripts/test_ql-png-options.test/png-gray-trns_5.pngbin0 -> 161 bytes
-rw-r--r--systemtest/scripts/test_ql-png-options.test/png-gray-trns_6.pngbin0 -> 161 bytes
-rw-r--r--systemtest/scripts/test_ql-png-options.test/png-gray-trns_7.pngbin0 -> 161 bytes
-rw-r--r--systemtest/scripts/test_ql-png-options.test/png-gray-trns_8.pngbin0 -> 161 bytes
-rw-r--r--systemtest/scripts/test_ql-png-options.test/png-gray-trns_9.pngbin0 -> 161 bytes
-rw-r--r--systemtest/scripts/test_ql-png-options.test/png-mono-trns_1.pngbin0 -> 149 bytes
-rw-r--r--systemtest/scripts/test_ql-png-options.test/png-mono-trns_2.pngbin0 -> 149 bytes
-rw-r--r--systemtest/scripts/test_user.sh157
-rw-r--r--systemtest/scripts/testoid.sh114
-rw-r--r--systemtest/testOutputGen.awk19
-rw-r--r--systemtest/testcenter.sh710
-rw-r--r--systemtest/testcenter2.sh444
-rw-r--r--systemtest/testdata/1dset1/cellaccess.ql3
-rw-r--r--systemtest/testdata/1dset1/cellaccess.ql.java.out15
-rw-r--r--systemtest/testdata/1dset1/cellaccess.ql.out14
-rw-r--r--systemtest/testdata/1dset1/trim.ql2
-rw-r--r--systemtest/testdata/1dset1/trim.ql.java.out15
-rw-r--r--systemtest/testdata/1dset1/trim.ql.out14
-rw-r--r--systemtest/testdata/3dset1/proj1.ql2
-rw-r--r--systemtest/testdata/3dset1/proj1.ql.java.out15
-rw-r--r--systemtest/testdata/3dset1/proj1.ql.out14
-rw-r--r--systemtest/testdata/3dset1/proj2.ql2
-rw-r--r--systemtest/testdata/3dset1/proj2.ql.java.out15
-rw-r--r--systemtest/testdata/3dset1/proj2.ql.out14
-rw-r--r--systemtest/testdata/3dset1/proj3.ql2
-rw-r--r--systemtest/testdata/3dset1/proj3.ql.java.out15
-rw-r--r--systemtest/testdata/3dset1/proj3.ql.out14
-rw-r--r--systemtest/testdata/bit/bit_01.ql2
-rw-r--r--systemtest/testdata/bit/bit_01.ql.java.out29
-rw-r--r--systemtest/testdata/bit/bit_01.ql.out44
-rw-r--r--systemtest/testdata/bit/bit_02.ql2
-rw-r--r--systemtest/testdata/bit/bit_02.ql.java.out29
-rw-r--r--systemtest/testdata/bit/bit_02.ql.out44
-rw-r--r--systemtest/testdata/bit/bit_03.ql2
-rw-r--r--systemtest/testdata/bit/bit_03.ql.java.out1
-rw-r--r--systemtest/testdata/bit/bit_03.ql.out6
-rw-r--r--systemtest/testdata/bit/bit_04.ql2
-rw-r--r--systemtest/testdata/bit/bit_04.ql.java.out1
-rw-r--r--systemtest/testdata/bit/bit_04.ql.out6
-rw-r--r--systemtest/testdata/bit/bit_05.ql2
-rw-r--r--systemtest/testdata/bit/bit_05.ql.java.out1
-rw-r--r--systemtest/testdata/bit/bit_05.ql.out6
-rw-r--r--systemtest/testdata/bit/bit_06.ql2
-rw-r--r--systemtest/testdata/bit/bit_06.ql.java.out1
-rw-r--r--systemtest/testdata/bit/bit_06.ql.out6
-rw-r--r--systemtest/testdata/bit/bit_07.ql2
-rw-r--r--systemtest/testdata/bit/bit_07.ql.java.out1
-rw-r--r--systemtest/testdata/bit/bit_07.ql.out6
-rw-r--r--systemtest/testdata/bit/bit_08.ql2
-rw-r--r--systemtest/testdata/bit/bit_08.ql.java.out1
-rw-r--r--systemtest/testdata/bit/bit_08.ql.out6
-rw-r--r--systemtest/testdata/bit/bit_09.ql2
-rw-r--r--systemtest/testdata/bit/bit_09.ql.java.out1
-rw-r--r--systemtest/testdata/bit/bit_09.ql.out6
-rw-r--r--systemtest/testdata/bit/bit_10.ql2
-rw-r--r--systemtest/testdata/bit/bit_10.ql.java.out1
-rw-r--r--systemtest/testdata/bit/bit_10.ql.out6
-rw-r--r--systemtest/testdata/bit/bit_11.ql2
-rw-r--r--systemtest/testdata/bit/bit_11.ql.java.out1
-rw-r--r--systemtest/testdata/bit/bit_11.ql.out6
-rw-r--r--systemtest/testdata/bit/bit_12.ql2
-rw-r--r--systemtest/testdata/bit/bit_12.ql.java.out1
-rw-r--r--systemtest/testdata/bit/bit_12.ql.out6
-rw-r--r--systemtest/testdata/bit/bit_13.ql2
-rw-r--r--systemtest/testdata/bit/bit_13.ql.java.out2
-rw-r--r--systemtest/testdata/bit/bit_13.ql.out1
-rw-r--r--systemtest/testdata/bit/bit_14.ql2
-rw-r--r--systemtest/testdata/bit/bit_14.ql.java.out2
-rw-r--r--systemtest/testdata/bit/bit_14.ql.out1
-rw-r--r--systemtest/testdata/bit/bit_15.ql2
-rw-r--r--systemtest/testdata/bit/bit_15.ql.java.out16
-rw-r--r--systemtest/testdata/bit/bit_15.ql.out6
-rw-r--r--systemtest/testdata/bit/bit_16.ql2
-rw-r--r--systemtest/testdata/bit/bit_16.ql.java.out2
-rw-r--r--systemtest/testdata/bit/bit_16.ql.out1
-rw-r--r--systemtest/testdata/bugfixes/all_collections.ql4
-rw-r--r--systemtest/testdata/bugfixes/all_collections.ql.java.out841
-rw-r--r--systemtest/testdata/bugfixes/all_collections.ql.out164
-rw-r--r--systemtest/testdata/bugfixes/all_collections.ql.tmp164
-rw-r--r--systemtest/testdata/bugfixes/charcast.ql2
-rw-r--r--systemtest/testdata/bugfixes/charcast.ql.java.out29
-rw-r--r--systemtest/testdata/bugfixes/charcast.ql.out44
-rw-r--r--systemtest/testdata/bugfixes/error308.ql1
-rw-r--r--systemtest/testdata/bugfixes/error308.ql.java.out2
-rw-r--r--systemtest/testdata/bugfixes/error308.ql.out1
-rw-r--r--systemtest/testdata/bugfixes/floatcondense.ql4
-rw-r--r--systemtest/testdata/bugfixes/floatcondense.ql.java.out29
-rw-r--r--systemtest/testdata/bugfixes/floatcondense.ql.out24
-rw-r--r--systemtest/testdata/caset1/cond1.ql4
-rw-r--r--systemtest/testdata/caset1/cond1.ql.java.out29
-rw-r--r--systemtest/testdata/caset1/cond1.ql.out44
-rw-r--r--systemtest/testdata/caset1/cond2.ql4
-rw-r--r--systemtest/testdata/caset1/cond2.ql.java.out29
-rw-r--r--systemtest/testdata/caset1/cond2.ql.out44
-rw-r--r--systemtest/testdata/caset1/count1.ql3
-rw-r--r--systemtest/testdata/caset1/count1.ql.java.out29
-rw-r--r--systemtest/testdata/caset1/count1.ql.out24
-rw-r--r--systemtest/testdata/caset1/count2.ql3
-rw-r--r--systemtest/testdata/caset1/count2.ql.java.out15
-rw-r--r--systemtest/testdata/caset1/count2.ql.out14
-rw-r--r--systemtest/testdata/caset1/count3.ql3
-rw-r--r--systemtest/testdata/caset1/count3.ql.java.out15
-rw-r--r--systemtest/testdata/caset1/count3.ql.out14
-rw-r--r--systemtest/testdata/caset1/hist1.ql3
-rw-r--r--systemtest/testdata/caset1/hist1.ql.java.out29
-rw-r--r--systemtest/testdata/caset1/hist1.ql.out24
-rw-r--r--systemtest/testdata/caset1/hist2.ql4
-rw-r--r--systemtest/testdata/caset1/hist2.ql.java.out29
-rw-r--r--systemtest/testdata/caset1/hist2.ql.out24
-rw-r--r--systemtest/testdata/caset1/marray1.ql4
-rw-r--r--systemtest/testdata/caset1/marray1.ql.java.out29
-rw-r--r--systemtest/testdata/caset1/marray1.ql.out44
-rw-r--r--systemtest/testdata/caset1/marray2.ql.out23
-rw-r--r--systemtest/testdata/caset1/marray3.ql.out44
-rw-r--r--systemtest/testdata/caset1/marray4.ql4
-rw-r--r--systemtest/testdata/caset1/marray4.ql.java.out15
-rw-r--r--systemtest/testdata/caset1/marray4.ql.out23
-rw-r--r--systemtest/testdata/caset1/olap1.ql4
-rw-r--r--systemtest/testdata/caset1/olap1.ql.java.out15
-rw-r--r--systemtest/testdata/caset1/olap1.ql.out15
-rw-r--r--systemtest/testdata/caset1/olap2.ql4
-rw-r--r--systemtest/testdata/caset1/olap2.ql.java.out15
-rw-r--r--systemtest/testdata/caset1/olap2.ql.out15
-rw-r--r--systemtest/testdata/cast/cast_01.ql2
-rw-r--r--systemtest/testdata/cast/cast_01.ql.java.out1
-rw-r--r--systemtest/testdata/cast/cast_01.ql.out6
-rw-r--r--systemtest/testdata/cast/cast_02.ql2
-rw-r--r--systemtest/testdata/cast/cast_02.ql.java.out1
-rw-r--r--systemtest/testdata/cast/cast_02.ql.out6
-rw-r--r--systemtest/testdata/cast/cast_03.ql2
-rw-r--r--systemtest/testdata/cast/cast_03.ql.java.out1
-rw-r--r--systemtest/testdata/cast/cast_03.ql.out6
-rw-r--r--systemtest/testdata/cast/cast_04.ql2
-rw-r--r--systemtest/testdata/cast/cast_04.ql.java.out1
-rw-r--r--systemtest/testdata/cast/cast_04.ql.out6
-rw-r--r--systemtest/testdata/cast/cast_05.ql2
-rw-r--r--systemtest/testdata/cast/cast_05.ql.java.out1
-rw-r--r--systemtest/testdata/cast/cast_05.ql.out6
-rw-r--r--systemtest/testdata/cast/cast_06.ql2
-rw-r--r--systemtest/testdata/cast/cast_06.ql.java.out1
-rw-r--r--systemtest/testdata/cast/cast_06.ql.out6
-rw-r--r--systemtest/testdata/cast/cast_07.ql2
-rw-r--r--systemtest/testdata/cast/cast_07.ql.java.out1
-rw-r--r--systemtest/testdata/cast/cast_07.ql.out6
-rw-r--r--systemtest/testdata/cast/cast_08.ql2
-rw-r--r--systemtest/testdata/cast/cast_08.ql.java.out1
-rw-r--r--systemtest/testdata/cast/cast_08.ql.out6
-rw-r--r--systemtest/testdata/cast/cast_09.ql2
-rw-r--r--systemtest/testdata/cast/cast_09.ql.java.out1
-rw-r--r--systemtest/testdata/cast/cast_09.ql.out6
-rw-r--r--systemtest/testdata/cast/cast_10.ql2
-rw-r--r--systemtest/testdata/cast/cast_10.ql.java.out1
-rw-r--r--systemtest/testdata/cast/cast_10.ql.out6
-rw-r--r--systemtest/testdata/cast/cast_11.ql2
-rw-r--r--systemtest/testdata/cast/cast_11.ql.java.out1
-rw-r--r--systemtest/testdata/cast/cast_11.ql.out6
-rw-r--r--systemtest/testdata/cast/cast_12.ql2
-rw-r--r--systemtest/testdata/cast/cast_12.ql.java.out1
-rw-r--r--systemtest/testdata/cast/cast_12.ql.out6
-rw-r--r--systemtest/testdata/cast/cast_13.ql2
-rw-r--r--systemtest/testdata/cast/cast_13.ql.java.out1
-rw-r--r--systemtest/testdata/cast/cast_13.ql.out6
-rw-r--r--systemtest/testdata/cast/cast_14.ql1
-rw-r--r--systemtest/testdata/cast/cast_14.ql.java.out1
-rw-r--r--systemtest/testdata/cast/cast_14.ql.out6
-rw-r--r--systemtest/testdata/cast/cast_15.ql5
-rw-r--r--systemtest/testdata/cast/cast_15.ql.java.out4
-rw-r--r--systemtest/testdata/cast/cast_15.ql.out8
-rw-r--r--systemtest/testdata/cast/cast_16.ql5
-rw-r--r--systemtest/testdata/cast/cast_16.ql.java.out4
-rw-r--r--systemtest/testdata/cast/cast_16.ql.out8
-rw-r--r--systemtest/testdata/cast/cast_17.ql5
-rw-r--r--systemtest/testdata/cast/cast_17.ql.java.out4
-rw-r--r--systemtest/testdata/cast/cast_17.ql.out8
-rw-r--r--systemtest/testdata/cast/cast_18.ql5
-rw-r--r--systemtest/testdata/cast/cast_18.ql.java.out4
-rw-r--r--systemtest/testdata/cast/cast_18.ql.out8
-rw-r--r--systemtest/testdata/complex/complex01.ql1
-rw-r--r--systemtest/testdata/complex/complex01.ql.java.out4
-rw-r--r--systemtest/testdata/complex/complex01.ql.out5
-rw-r--r--systemtest/testdata/complex/complex02.ql1
-rw-r--r--systemtest/testdata/complex/complex02.ql.java.out4
-rw-r--r--systemtest/testdata/complex/complex02.ql.out5
-rw-r--r--systemtest/testdata/complex/complex03.ql1
-rw-r--r--systemtest/testdata/complex/complex03.ql.java.out4
-rw-r--r--systemtest/testdata/complex/complex03.ql.out5
-rw-r--r--systemtest/testdata/complex/complex04.ql1
-rw-r--r--systemtest/testdata/complex/complex04.ql.java.out4
-rw-r--r--systemtest/testdata/complex/complex04.ql.out5
-rw-r--r--systemtest/testdata/complex/complex05.ql1
-rw-r--r--systemtest/testdata/complex/complex05.ql.java.out4
-rw-r--r--systemtest/testdata/complex/complex05.ql.out5
-rw-r--r--systemtest/testdata/complex/complex06.ql1
-rw-r--r--systemtest/testdata/complex/complex06.ql.java.out4
-rw-r--r--systemtest/testdata/complex/complex06.ql.out5
-rw-r--r--systemtest/testdata/complex/complex07.ql1
-rw-r--r--systemtest/testdata/complex/complex07.ql.java.out4
-rw-r--r--systemtest/testdata/complex/complex07.ql.out5
-rw-r--r--systemtest/testdata/complex/complex08.ql1
-rw-r--r--systemtest/testdata/complex/complex08.ql.java.out4
-rw-r--r--systemtest/testdata/complex/complex08.ql.out5
-rw-r--r--systemtest/testdata/complex/complex09.ql1
-rw-r--r--systemtest/testdata/complex/complex09.ql.java.out4
-rw-r--r--systemtest/testdata/complex/complex09.ql.out5
-rw-r--r--systemtest/testdata/complex/complex10.ql1
-rw-r--r--systemtest/testdata/complex/complex10.ql.java.out4
-rw-r--r--systemtest/testdata/complex/complex10.ql.out5
-rw-r--r--systemtest/testdata/complex/complex11.ql1
-rw-r--r--systemtest/testdata/complex/complex11.ql.java.out4
-rw-r--r--systemtest/testdata/complex/complex11.ql.out5
-rw-r--r--systemtest/testdata/complex/complex12.ql1
-rw-r--r--systemtest/testdata/complex/complex12.ql.java.out4
-rw-r--r--systemtest/testdata/complex/complex12.ql.out5
-rw-r--r--systemtest/testdata/complex/complex13.ql1
-rw-r--r--systemtest/testdata/complex/complex13.ql.java.out2
-rw-r--r--systemtest/testdata/complex/complex13.ql.out24
-rw-r--r--systemtest/testdata/complex/complex14.ql1
-rw-r--r--systemtest/testdata/complex/complex14.ql.java.out2
-rw-r--r--systemtest/testdata/complex/complex14.ql.out24
-rw-r--r--systemtest/testdata/conversion/bmp1.ql5
-rw-r--r--systemtest/testdata/conversion/bmp1.ql.java.out29
-rw-r--r--systemtest/testdata/conversion/bmp1.ql.out6
-rw-r--r--systemtest/testdata/conversion/bmp2.ql5
-rw-r--r--systemtest/testdata/conversion/bmp2.ql.java.out29
-rw-r--r--systemtest/testdata/conversion/bmp2.ql.out6
-rw-r--r--systemtest/testdata/conversion/hdf1.ql5
-rw-r--r--systemtest/testdata/conversion/hdf1.ql.java.out29
-rw-r--r--systemtest/testdata/conversion/hdf1.ql.out6
-rw-r--r--systemtest/testdata/conversion/hdf2.ql5
-rw-r--r--systemtest/testdata/conversion/hdf2.ql.java.out2
-rw-r--r--systemtest/testdata/conversion/hdf2.ql.out1
-rw-r--r--systemtest/testdata/conversion/inv_bmp1.ql5
-rw-r--r--systemtest/testdata/conversion/inv_bmp1.ql.java.out29
-rw-r--r--systemtest/testdata/conversion/inv_bmp1.ql.out44
-rw-r--r--systemtest/testdata/conversion/inv_bmp2.ql5
-rw-r--r--systemtest/testdata/conversion/inv_bmp2.ql.java.out15
-rw-r--r--systemtest/testdata/conversion/inv_bmp2.ql.out44
-rw-r--r--systemtest/testdata/conversion/inv_hdf1.ql5
-rw-r--r--systemtest/testdata/conversion/inv_hdf1.ql.java.out29
-rw-r--r--systemtest/testdata/conversion/inv_hdf1.ql.out44
-rw-r--r--systemtest/testdata/conversion/inv_hdf2.ql5
-rw-r--r--systemtest/testdata/conversion/inv_hdf2.ql.java.out2
-rw-r--r--systemtest/testdata/conversion/inv_hdf2.ql.out1
-rw-r--r--systemtest/testdata/conversion/inv_hdf3.ql5
-rw-r--r--systemtest/testdata/conversion/inv_hdf3.ql.java.out2
-rw-r--r--systemtest/testdata/conversion/inv_hdf3.ql.out1
-rw-r--r--systemtest/testdata/conversion/inv_hdf4.ql5
-rw-r--r--systemtest/testdata/conversion/inv_hdf4.ql.java.out2
-rw-r--r--systemtest/testdata/conversion/inv_hdf4.ql.out1
-rw-r--r--systemtest/testdata/conversion/inv_jpeg1.ql5
-rw-r--r--systemtest/testdata/conversion/inv_jpeg1.ql.java.out29
-rw-r--r--systemtest/testdata/conversion/inv_jpeg1.ql.out44
-rw-r--r--systemtest/testdata/conversion/inv_jpeg2.ql5
-rw-r--r--systemtest/testdata/conversion/inv_jpeg2.ql.java.out15
-rw-r--r--systemtest/testdata/conversion/inv_jpeg2.ql.out44
-rw-r--r--systemtest/testdata/conversion/inv_png1.ql5
-rw-r--r--systemtest/testdata/conversion/inv_png1.ql.java.out29
-rw-r--r--systemtest/testdata/conversion/inv_png1.ql.out44
-rw-r--r--systemtest/testdata/conversion/inv_png2.ql5
-rw-r--r--systemtest/testdata/conversion/inv_png2.ql.java.out15
-rw-r--r--systemtest/testdata/conversion/inv_png2.ql.out44
-rw-r--r--systemtest/testdata/conversion/inv_tiff1.ql5
-rw-r--r--systemtest/testdata/conversion/inv_tiff1.ql.java.out29
-rw-r--r--systemtest/testdata/conversion/inv_tiff1.ql.out44
-rw-r--r--systemtest/testdata/conversion/inv_tiff2.ql5
-rw-r--r--systemtest/testdata/conversion/inv_tiff2.ql.java.out15
-rw-r--r--systemtest/testdata/conversion/inv_tiff2.ql.out44
-rw-r--r--systemtest/testdata/conversion/inv_vff1.ql6
-rw-r--r--systemtest/testdata/conversion/inv_vff1.ql.java.out29
-rw-r--r--systemtest/testdata/conversion/inv_vff1.ql.out44
-rw-r--r--systemtest/testdata/conversion/inv_vff2.ql5
-rw-r--r--systemtest/testdata/conversion/inv_vff2.ql.java.out2
-rw-r--r--systemtest/testdata/conversion/inv_vff2.ql.out1
-rw-r--r--systemtest/testdata/conversion/jpeg1.ql5
-rw-r--r--systemtest/testdata/conversion/jpeg1.ql.java.out29
-rw-r--r--systemtest/testdata/conversion/jpeg1.ql.out6
-rw-r--r--systemtest/testdata/conversion/jpeg2.ql5
-rw-r--r--systemtest/testdata/conversion/jpeg2.ql.java.out29
-rw-r--r--systemtest/testdata/conversion/jpeg2.ql.out6
-rw-r--r--systemtest/testdata/conversion/png1.ql5
-rw-r--r--systemtest/testdata/conversion/png1.ql.java.out29
-rw-r--r--systemtest/testdata/conversion/png1.ql.out6
-rw-r--r--systemtest/testdata/conversion/png2.ql5
-rw-r--r--systemtest/testdata/conversion/png2.ql.java.out29
-rw-r--r--systemtest/testdata/conversion/png2.ql.out6
-rw-r--r--systemtest/testdata/conversion/tiff1.ql5
-rw-r--r--systemtest/testdata/conversion/tiff1.ql.java.out29
-rw-r--r--systemtest/testdata/conversion/tiff1.ql.out6
-rw-r--r--systemtest/testdata/conversion/tiff2.ql5
-rw-r--r--systemtest/testdata/conversion/tiff2.ql.java.out29
-rw-r--r--systemtest/testdata/conversion/tiff2.ql.out6
-rw-r--r--systemtest/testdata/conversion/vff1.ql6
-rw-r--r--systemtest/testdata/conversion/vff1.ql.java.out29
-rw-r--r--systemtest/testdata/conversion/vff1.ql.out6
-rw-r--r--systemtest/testdata/conversion/vff2.ql5
-rw-r--r--systemtest/testdata/conversion/vff2.ql.java.out2
-rw-r--r--systemtest/testdata/conversion/vff2.ql.out1
-rw-r--r--systemtest/testdata/empty/empty.ql1
-rw-r--r--systemtest/testdata/empty/empty.ql.java.out2
-rw-r--r--systemtest/testdata/empty/empty.ql.out1
-rw-r--r--systemtest/testdata/empty/empty2.ql1
-rw-r--r--systemtest/testdata/empty/empty2.ql.java.out2
-rw-r--r--systemtest/testdata/empty/empty2.ql.out1
-rw-r--r--systemtest/testdata/empty/empty3.ql3
-rw-r--r--systemtest/testdata/empty/empty3.ql.java.out2
-rw-r--r--systemtest/testdata/empty/empty3.ql.out1
-rw-r--r--systemtest/testdata/empty/empty4.ql3
-rw-r--r--systemtest/testdata/empty/empty4.ql.java.out2
-rw-r--r--systemtest/testdata/empty/empty4.ql.out1
-rw-r--r--systemtest/testdata/empty/empty5.ql2
-rw-r--r--systemtest/testdata/empty/empty5.ql.java.out2
-rw-r--r--systemtest/testdata/empty/empty5.ql.out1
-rw-r--r--systemtest/testdata/empty/empty6.ql2
-rw-r--r--systemtest/testdata/empty/empty6.ql.java.out2
-rw-r--r--systemtest/testdata/empty/empty6.ql.out1
-rw-r--r--systemtest/testdata/empty/opt.ql3
-rw-r--r--systemtest/testdata/empty/opt.ql.java.out2
-rw-r--r--systemtest/testdata/empty/opt.ql.out1
-rw-r--r--systemtest/testdata/empty/opt1.ql3
-rw-r--r--systemtest/testdata/empty/opt1.ql.java.out2
-rw-r--r--systemtest/testdata/empty/opt1.ql.out1
-rw-r--r--systemtest/testdata/empty/opt2.ql3
-rw-r--r--systemtest/testdata/empty/opt2.ql.java.out2
-rw-r--r--systemtest/testdata/empty/opt2.ql.out1
-rw-r--r--systemtest/testdata/empty/opt3.ql3
-rw-r--r--systemtest/testdata/empty/opt3.ql.java.out2
-rw-r--r--systemtest/testdata/empty/opt3.ql.out1
-rw-r--r--systemtest/testdata/empty/opt4.ql3
-rw-r--r--systemtest/testdata/empty/opt4.ql.java.out2
-rw-r--r--systemtest/testdata/empty/opt4.ql.out1
-rw-r--r--systemtest/testdata/empty/opt41.ql3
-rw-r--r--systemtest/testdata/empty/opt41.ql.java.out2
-rw-r--r--systemtest/testdata/empty/opt41.ql.out1
-rw-r--r--systemtest/testdata/empty/opt5.ql2
-rw-r--r--systemtest/testdata/empty/opt5.ql.java.out2
-rw-r--r--systemtest/testdata/empty/opt5.ql.out1
-rw-r--r--systemtest/testdata/empty/opt6.ql2
-rw-r--r--systemtest/testdata/empty/opt6.ql.java.out2
-rw-r--r--systemtest/testdata/empty/opt6.ql.out1
-rw-r--r--systemtest/testdata/empty/opt7.ql2
-rw-r--r--systemtest/testdata/empty/opt7.ql.java.out2
-rw-r--r--systemtest/testdata/empty/opt7.ql.out1
-rw-r--r--systemtest/testdata/empty/opt8.ql2
-rw-r--r--systemtest/testdata/empty/opt8.ql.java.out2
-rw-r--r--systemtest/testdata/empty/opt8.ql.out1
-rw-r--r--systemtest/testdata/empty/opt9.ql2
-rw-r--r--systemtest/testdata/empty/opt9.ql.java.out2
-rw-r--r--systemtest/testdata/empty/opt9.ql.out1
-rw-r--r--systemtest/testdata/errorset1/err300.ql4
-rw-r--r--systemtest/testdata/errorset1/err300.ql.java.out2
-rw-r--r--systemtest/testdata/errorset1/err300.ql.out1
-rw-r--r--systemtest/testdata/errorset1/err301.ql3
-rw-r--r--systemtest/testdata/errorset1/err301.ql.java.out2
-rw-r--r--systemtest/testdata/errorset1/err301.ql.out1
-rw-r--r--systemtest/testdata/errorset1/err302.ql3
-rw-r--r--systemtest/testdata/errorset1/err302.ql.java.out2
-rw-r--r--systemtest/testdata/errorset1/err302.ql.out1
-rw-r--r--systemtest/testdata/errorset1/err349.ql.out6
-rw-r--r--systemtest/testdata/errorset1/err355.ql4
-rw-r--r--systemtest/testdata/errorset1/err355.ql.java.out2
-rw-r--r--systemtest/testdata/errorset1/err355.ql.out1
-rw-r--r--systemtest/testdata/errorset1/err356.ql4
-rw-r--r--systemtest/testdata/errorset1/err356.ql.java.out2
-rw-r--r--systemtest/testdata/errorset1/err356.ql.out1
-rw-r--r--systemtest/testdata/errorset1/err357.ql4
-rw-r--r--systemtest/testdata/errorset1/err357.ql.java.out2
-rw-r--r--systemtest/testdata/errorset1/err357.ql.out1
-rw-r--r--systemtest/testdata/errorset1/err359.ql5
-rw-r--r--systemtest/testdata/errorset1/err359.ql.java.out2
-rw-r--r--systemtest/testdata/errorset1/err359.ql.out1
-rw-r--r--systemtest/testdata/errorset1/err364.ql4
-rw-r--r--systemtest/testdata/errorset1/err364.ql.java.out2
-rw-r--r--systemtest/testdata/errorset1/err364.ql.out1
-rw-r--r--systemtest/testdata/errorset1/err385.ql5
-rw-r--r--systemtest/testdata/errorset1/err385.ql.java.out2
-rw-r--r--systemtest/testdata/errorset1/err385.ql.out1
-rw-r--r--systemtest/testdata/errorset1/err386.ql5
-rw-r--r--systemtest/testdata/errorset1/err386.ql.java.out2
-rw-r--r--systemtest/testdata/errorset1/err386.ql.out1
-rw-r--r--systemtest/testdata/errorset1/err390.ql4
-rw-r--r--systemtest/testdata/errorset1/err390.ql.java.out2
-rw-r--r--systemtest/testdata/errorset1/err390.ql.out1
-rw-r--r--systemtest/testdata/errorset1/err393.ql4
-rw-r--r--systemtest/testdata/errorset1/err393.ql.java.out2
-rw-r--r--systemtest/testdata/errorset1/err393.ql.out1
-rw-r--r--systemtest/testdata/errorset1/err394.ql4
-rw-r--r--systemtest/testdata/errorset1/err394.ql.java.out2
-rw-r--r--systemtest/testdata/errorset1/err394.ql.out1
-rw-r--r--systemtest/testdata/errorset1/err396.ql4
-rw-r--r--systemtest/testdata/errorset1/err396.ql.java.out2
-rw-r--r--systemtest/testdata/errorset1/err396.ql.out1
-rw-r--r--systemtest/testdata/errorset1/err397.ql4
-rw-r--r--systemtest/testdata/errorset1/err397.ql.java.out2
-rw-r--r--systemtest/testdata/errorset1/err397.ql.out1
-rw-r--r--systemtest/testdata/errorset1/err398.ql4
-rw-r--r--systemtest/testdata/errorset1/err398.ql.java.out2
-rw-r--r--systemtest/testdata/errorset1/err398.ql.out1
-rw-r--r--systemtest/testdata/errorset1/err403.ql5
-rw-r--r--systemtest/testdata/errorset1/err403.ql.java.out2
-rw-r--r--systemtest/testdata/errorset1/err403.ql.out1
-rw-r--r--systemtest/testdata/errorset1/err405.ql4
-rw-r--r--systemtest/testdata/errorset1/err405.ql.java.out2
-rw-r--r--systemtest/testdata/errorset1/err405.ql.out1
-rw-r--r--systemtest/testdata/errorset1/err406.ql4
-rw-r--r--systemtest/testdata/errorset1/err406.ql.java.out2
-rw-r--r--systemtest/testdata/errorset1/err406.ql.out1
-rw-r--r--systemtest/testdata/errorset1/err407.ql4
-rw-r--r--systemtest/testdata/errorset1/err407.ql.java.out2
-rw-r--r--systemtest/testdata/errorset1/err407.ql.out1
-rw-r--r--systemtest/testdata/errorset1/err408.ql4
-rw-r--r--systemtest/testdata/errorset1/err408.ql.java.out2
-rw-r--r--systemtest/testdata/errorset1/err408.ql.out1
-rw-r--r--systemtest/testdata/errorset1/err409.ql4
-rw-r--r--systemtest/testdata/errorset1/err409.ql.java.out2
-rw-r--r--systemtest/testdata/errorset1/err409.ql.out1
-rw-r--r--systemtest/testdata/errorset1/err413.ql6
-rw-r--r--systemtest/testdata/errorset1/err413.ql.java.out2
-rw-r--r--systemtest/testdata/errorset1/err413.ql.out1
-rw-r--r--systemtest/testdata/errorset1/err415.ql3
-rw-r--r--systemtest/testdata/errorset1/err415.ql.java.out2
-rw-r--r--systemtest/testdata/errorset1/err415.ql.out1
-rw-r--r--systemtest/testdata/errorset1/err950_300.ql5
-rw-r--r--systemtest/testdata/errorset1/err950_300.ql.java.out2
-rw-r--r--systemtest/testdata/errorset1/err950_300.ql.out1
-rw-r--r--systemtest/testdata/errorset1/err951.ql5
-rw-r--r--systemtest/testdata/errorset1/err951.ql.java.out2
-rw-r--r--systemtest/testdata/errorset1/err951.ql.out1
-rw-r--r--systemtest/testdata/errorset1/err952.ql5
-rw-r--r--systemtest/testdata/errorset1/err952.ql.java.out2
-rw-r--r--systemtest/testdata/errorset1/err952.ql.out1
-rw-r--r--systemtest/testdata/errorset1/err954_300.ql3
-rw-r--r--systemtest/testdata/errorset1/err954_300.ql.java.out2
-rw-r--r--systemtest/testdata/errorset1/err954_300.ql.out1
-rw-r--r--systemtest/testdata/errorset1/err961.ql3
-rw-r--r--systemtest/testdata/errorset1/err961.ql.java.out2
-rw-r--r--systemtest/testdata/errorset1/err961.ql.out1
-rw-r--r--systemtest/testdata/errorset1/err962.ql3
-rw-r--r--systemtest/testdata/errorset1/err962.ql.java.out2
-rw-r--r--systemtest/testdata/errorset1/err962.ql.out1
-rw-r--r--systemtest/testdata/errorset1/err963.ql3
-rw-r--r--systemtest/testdata/errorset1/err963.ql.java.out2
-rw-r--r--systemtest/testdata/errorset1/err963.ql.out1
-rw-r--r--systemtest/testdata/optimization/opt.ql2
-rw-r--r--systemtest/testdata/optimization/opt.ql.java.out29
-rw-r--r--systemtest/testdata/optimization/opt.ql.out44
-rw-r--r--systemtest/testdata/optimization/opt1.ql2
-rw-r--r--systemtest/testdata/optimization/opt1.ql.java.out29
-rw-r--r--systemtest/testdata/optimization/opt1.ql.out44
-rw-r--r--systemtest/testdata/optimization/opt2.ql2
-rw-r--r--systemtest/testdata/optimization/opt2.ql.java.out29
-rw-r--r--systemtest/testdata/optimization/opt2.ql.out44
-rw-r--r--systemtest/testdata/optimization/opt3.ql2
-rw-r--r--systemtest/testdata/optimization/opt3.ql.java.out29
-rw-r--r--systemtest/testdata/optimization/opt3.ql.out44
-rw-r--r--systemtest/testdata/optimization/opt4.ql2
-rw-r--r--systemtest/testdata/optimization/opt4.ql.java.out29
-rw-r--r--systemtest/testdata/optimization/opt4.ql.out44
-rw-r--r--systemtest/testdata/optimization/opt5.ql2
-rw-r--r--systemtest/testdata/optimization/opt5.ql.java.out29
-rw-r--r--systemtest/testdata/optimization/opt5.ql.out44
-rw-r--r--systemtest/testdata/optimization/opt6.ql2
-rw-r--r--systemtest/testdata/optimization/opt6.ql.java.out29
-rw-r--r--systemtest/testdata/optimization/opt6.ql.out44
-rw-r--r--systemtest/testdata/optimization/opt7.ql2
-rw-r--r--systemtest/testdata/optimization/opt7.ql.java.out29
-rw-r--r--systemtest/testdata/optimization/opt7.ql.out44
-rw-r--r--systemtest/testdata/optimization/opt8.ql2
-rw-r--r--systemtest/testdata/optimization/opt8.ql.java.out29
-rw-r--r--systemtest/testdata/optimization/opt8.ql.out44
-rw-r--r--systemtest/testdata/optimization/opt9.ql2
-rw-r--r--systemtest/testdata/optimization/opt9.ql.java.out29
-rw-r--r--systemtest/testdata/optimization/opt9.ql.out44
-rw-r--r--systemtest/testdata/overlay/overlay1.ql2
-rw-r--r--systemtest/testdata/overlay/overlay1.ql.java.out15
-rw-r--r--systemtest/testdata/overlay/overlay1.ql.out23
-rw-r--r--systemtest/testdata/overlay/overlay2.ql2
-rw-r--r--systemtest/testdata/overlay/overlay2.ql.java.out2
-rw-r--r--systemtest/testdata/overlay/overlay2.ql.out1
-rw-r--r--systemtest/testdata/overlay/overlay3.ql2
-rw-r--r--systemtest/testdata/overlay/overlay3.ql.java.out2
-rw-r--r--systemtest/testdata/overlay/overlay3.ql.out1
-rw-r--r--systemtest/testdata/overlay/overlay4.ql2
-rw-r--r--systemtest/testdata/overlay/overlay4.ql.java.out2
-rw-r--r--systemtest/testdata/overlay/overlay4.ql.out1
-rw-r--r--systemtest/testdata/overlay/overlay5.ql2
-rw-r--r--systemtest/testdata/overlay/overlay5.ql.java.out15
-rw-r--r--systemtest/testdata/overlay/overlay5.ql.out23
-rw-r--r--systemtest/testdata/overlay/overlay6.ql12
-rw-r--r--systemtest/testdata/overlay/overlay6.ql.java.out29
-rw-r--r--systemtest/testdata/overlay/overlay6.ql.out120
-rw-r--r--systemtest/testdata/parser/gentest.awk29
-rw-r--r--systemtest/testdata/parser/mm_long.ql3
-rw-r--r--systemtest/testdata/parser/mm_long.ql.java.out1
-rw-r--r--systemtest/testdata/parser/mm_long.ql.out6
-rw-r--r--systemtest/testdata/parser/mp_long.ql2
-rw-r--r--systemtest/testdata/parser/mp_long.ql.java.out1
-rw-r--r--systemtest/testdata/parser/mp_long.ql.out6
-rw-r--r--systemtest/testdata/parser/nm_long.ql2
-rw-r--r--systemtest/testdata/parser/nm_long.ql.java.out1
-rw-r--r--systemtest/testdata/parser/nm_long.ql.out6
-rw-r--r--systemtest/testdata/parser/nn_long.ql2
-rw-r--r--systemtest/testdata/parser/nn_long.ql.java.out1
-rw-r--r--systemtest/testdata/parser/nn_long.ql.out6
-rw-r--r--systemtest/testdata/parser/np_long.ql2
-rw-r--r--systemtest/testdata/parser/np_long.ql.java.out1
-rw-r--r--systemtest/testdata/parser/np_long.ql.out6
-rw-r--r--systemtest/testdata/parser/om_long.ql2
-rw-r--r--systemtest/testdata/parser/om_long.ql.java.out1
-rw-r--r--systemtest/testdata/parser/om_long.ql.out6
-rw-r--r--systemtest/testdata/parser/on_long.ql2
-rw-r--r--systemtest/testdata/parser/on_long.ql.java.out1
-rw-r--r--systemtest/testdata/parser/on_long.ql.out6
-rw-r--r--systemtest/testdata/parser/op_long.ql2
-rw-r--r--systemtest/testdata/parser/op_long.ql.java.out1
-rw-r--r--systemtest/testdata/parser/op_long.ql.out6
-rw-r--r--systemtest/testdata/parser/p1_long.ql2
-rw-r--r--systemtest/testdata/parser/p1_long.ql.java.out1
-rw-r--r--systemtest/testdata/parser/p1_long.ql.out6
-rw-r--r--systemtest/testdata/parser/p2_long.ql2
-rw-r--r--systemtest/testdata/parser/p2_long.ql.java.out1
-rw-r--r--systemtest/testdata/parser/p2_long.ql.out6
-rw-r--r--systemtest/testdata/parser/pm_long.ql2
-rw-r--r--systemtest/testdata/parser/pm_long.ql.java.out1
-rw-r--r--systemtest/testdata/parser/pm_long.ql.out6
-rw-r--r--systemtest/testdata/parser/pp_long.ql2
-rw-r--r--systemtest/testdata/parser/pp_long.ql.java.out1
-rw-r--r--systemtest/testdata/parser/pp_long.ql.out6
-rw-r--r--systemtest/testdata/parser/sqrt_1.ql2
-rw-r--r--systemtest/testdata/parser/sqrt_1.ql.java.out1
-rw-r--r--systemtest/testdata/parser/sqrt_1.ql.out6
-rw-r--r--systemtest/testdata/parser/sqrt_2.ql2
-rw-r--r--systemtest/testdata/parser/sqrt_2.ql.java.out1
-rw-r--r--systemtest/testdata/parser/sqrt_2.ql.out6
-rw-r--r--systemtest/testdata/parser/sqrt_3.ql2
-rw-r--r--systemtest/testdata/parser/sqrt_3.ql.java.out1
-rw-r--r--systemtest/testdata/parser/sqrt_3.ql.out6
-rw-r--r--systemtest/testdata/parser/sqrt_4.ql2
-rw-r--r--systemtest/testdata/parser/sqrt_4.ql.java.out1
-rw-r--r--systemtest/testdata/parser/sqrt_4.ql.out6
-rw-r--r--systemtest/testdata/parser/sqrt_5.ql2
-rw-r--r--systemtest/testdata/parser/sqrt_5.ql.java.out1
-rw-r--r--systemtest/testdata/parser/sqrt_5.ql.out6
-rw-r--r--systemtest/testdata/parser/sqrt_6.ql2
-rw-r--r--systemtest/testdata/parser/sqrt_6.ql.java.out1
-rw-r--r--systemtest/testdata/parser/sqrt_6.ql.out6
-rw-r--r--systemtest/testdata/parser/testcases21
-rw-r--r--systemtest/testdata/partialoverlay/u01_create.ql1
-rw-r--r--systemtest/testdata/partialoverlay/u01_create.ql.out0
-rw-r--r--systemtest/testdata/partialoverlay/u02_create.ql1
-rw-r--r--systemtest/testdata/partialoverlay/u02_create.ql.out0
-rw-r--r--systemtest/testdata/partialoverlay/u03_insert.ql14
-rw-r--r--systemtest/testdata/partialoverlay/u03_insert.ql.out0
-rw-r--r--systemtest/testdata/partialoverlay/u04_insert.ql13
-rw-r--r--systemtest/testdata/partialoverlay/u04_insert.ql.out0
-rw-r--r--systemtest/testdata/partialoverlay/u05_update.ql15
-rw-r--r--systemtest/testdata/partialoverlay/u05_update.ql.out0
-rw-r--r--systemtest/testdata/partialoverlay/u06_update.ql14
-rw-r--r--systemtest/testdata/partialoverlay/u06_update.ql.out0
-rw-r--r--systemtest/testdata/partialoverlay/u07_update.ql15
-rw-r--r--systemtest/testdata/partialoverlay/u07_update.ql.out0
-rw-r--r--systemtest/testdata/partialoverlay/u08_update.ql15
-rw-r--r--systemtest/testdata/partialoverlay/u08_update.ql.out0
-rw-r--r--systemtest/testdata/partialoverlay/u09_lookup.ql3
-rw-r--r--systemtest/testdata/partialoverlay/u09_lookup.ql.out24
-rw-r--r--systemtest/testdata/partialoverlay/u10_lookup.ql3
-rw-r--r--systemtest/testdata/partialoverlay/u10_lookup.ql.out24
-rw-r--r--systemtest/testdata/partialoverlay/u11_overlay.ql.out1
-rw-r--r--systemtest/testdata/partialoverlay/u12_overlay.ql.out84
-rw-r--r--systemtest/testdata/partialoverlay/u13_overlay.ql.out84
-rw-r--r--systemtest/testdata/partialoverlay/u98_drop.ql2
-rw-r--r--systemtest/testdata/partialoverlay/u98_drop.ql.out0
-rw-r--r--systemtest/testdata/partialoverlay/u99_drop.ql1
-rw-r--r--systemtest/testdata/partialoverlay/u99_drop.ql.out0
-rw-r--r--systemtest/testdata/partialupdate/u01_create.ql1
-rw-r--r--systemtest/testdata/partialupdate/u01_create.ql.java.out0
-rw-r--r--systemtest/testdata/partialupdate/u01_create.ql.out0
-rw-r--r--systemtest/testdata/partialupdate/u02_insert.ql13
-rw-r--r--systemtest/testdata/partialupdate/u02_insert.ql.java.out0
-rw-r--r--systemtest/testdata/partialupdate/u02_insert.ql.out0
-rw-r--r--systemtest/testdata/partialupdate/u03_lookup.ql5
-rw-r--r--systemtest/testdata/partialupdate/u03_lookup.ql.java.out15
-rw-r--r--systemtest/testdata/partialupdate/u03_lookup.ql.out24
-rw-r--r--systemtest/testdata/partialupdate/u04_update.ql15
-rw-r--r--systemtest/testdata/partialupdate/u04_update.ql.java.out0
-rw-r--r--systemtest/testdata/partialupdate/u04_update.ql.out0
-rw-r--r--systemtest/testdata/partialupdate/u05_lookup.ql5
-rw-r--r--systemtest/testdata/partialupdate/u05_lookup.ql.java.out15
-rw-r--r--systemtest/testdata/partialupdate/u05_lookup.ql.out34
-rw-r--r--systemtest/testdata/partialupdate/u06_update.ql14
-rw-r--r--systemtest/testdata/partialupdate/u06_update.ql.java.out0
-rw-r--r--systemtest/testdata/partialupdate/u06_update.ql.out0
-rw-r--r--systemtest/testdata/partialupdate/u071_update.ql14
-rw-r--r--systemtest/testdata/partialupdate/u071_update.ql.java.out0
-rw-r--r--systemtest/testdata/partialupdate/u071_update.ql.out0
-rw-r--r--systemtest/testdata/partialupdate/u072_lookup.ql5
-rw-r--r--systemtest/testdata/partialupdate/u072_lookup.ql.java.out15
-rw-r--r--systemtest/testdata/partialupdate/u072_lookup.ql.out54
-rw-r--r--systemtest/testdata/partialupdate/u07_lookup.ql5
-rw-r--r--systemtest/testdata/partialupdate/u07_lookup.ql.java.out15
-rw-r--r--systemtest/testdata/partialupdate/u07_lookup.ql.out54
-rw-r--r--systemtest/testdata/partialupdate/u08_update.ql15
-rw-r--r--systemtest/testdata/partialupdate/u08_update.ql.java.out0
-rw-r--r--systemtest/testdata/partialupdate/u08_update.ql.out0
-rw-r--r--systemtest/testdata/partialupdate/u09_lookup.ql5
-rw-r--r--systemtest/testdata/partialupdate/u09_lookup.ql.java.out15
-rw-r--r--systemtest/testdata/partialupdate/u09_lookup.ql.out64
-rw-r--r--systemtest/testdata/partialupdate/u10_update.ql11
-rw-r--r--systemtest/testdata/partialupdate/u10_update.ql.java.out0
-rw-r--r--systemtest/testdata/partialupdate/u10_update.ql.out0
-rw-r--r--systemtest/testdata/partialupdate/u11_lookup.ql5
-rw-r--r--systemtest/testdata/partialupdate/u11_lookup.ql.java.out15
-rw-r--r--systemtest/testdata/partialupdate/u11_lookup.ql.out64
-rw-r--r--systemtest/testdata/partialupdate/u12_update.ql9
-rw-r--r--systemtest/testdata/partialupdate/u12_update.ql.java.out0
-rw-r--r--systemtest/testdata/partialupdate/u12_update.ql.out0
-rw-r--r--systemtest/testdata/partialupdate/u13_lookup.ql5
-rw-r--r--systemtest/testdata/partialupdate/u13_lookup.ql.java.out15
-rw-r--r--systemtest/testdata/partialupdate/u13_lookup.ql.out64
-rw-r--r--systemtest/testdata/partialupdate/u14_update.ql5
-rw-r--r--systemtest/testdata/partialupdate/u14_update.ql.java.out0
-rw-r--r--systemtest/testdata/partialupdate/u14_update.ql.out0
-rw-r--r--systemtest/testdata/partialupdate/u15_lookup.ql5
-rw-r--r--systemtest/testdata/partialupdate/u15_lookup.ql.java.out15
-rw-r--r--systemtest/testdata/partialupdate/u15_lookup.ql.out64
-rw-r--r--systemtest/testdata/partialupdate/u16_update.ql15
-rw-r--r--systemtest/testdata/partialupdate/u16_update.ql.java.out0
-rw-r--r--systemtest/testdata/partialupdate/u16_update.ql.out0
-rw-r--r--systemtest/testdata/partialupdate/u17_lookup.ql5
-rw-r--r--systemtest/testdata/partialupdate/u17_lookup.ql.java.out15
-rw-r--r--systemtest/testdata/partialupdate/u17_lookup.ql.out64
-rw-r--r--systemtest/testdata/partialupdate/u18_update.ql5
-rw-r--r--systemtest/testdata/partialupdate/u18_update.ql.java.out0
-rw-r--r--systemtest/testdata/partialupdate/u18_update.ql.out0
-rw-r--r--systemtest/testdata/partialupdate/u19_lookup.ql5
-rw-r--r--systemtest/testdata/partialupdate/u19_lookup.ql.java.out15
-rw-r--r--systemtest/testdata/partialupdate/u19_lookup.ql.out64
-rw-r--r--systemtest/testdata/partialupdate/u20_update.ql9
-rw-r--r--systemtest/testdata/partialupdate/u20_update.ql.java.out0
-rw-r--r--systemtest/testdata/partialupdate/u20_update.ql.out0
-rw-r--r--systemtest/testdata/partialupdate/u21_lookup.ql5
-rw-r--r--systemtest/testdata/partialupdate/u21_lookup.ql.java.out15
-rw-r--r--systemtest/testdata/partialupdate/u21_lookup.ql.out64
-rw-r--r--systemtest/testdata/partialupdate/u30_update.ql10
-rw-r--r--systemtest/testdata/partialupdate/u30_update.ql.java.out0
-rw-r--r--systemtest/testdata/partialupdate/u30_update.ql.out0
-rw-r--r--systemtest/testdata/partialupdate/u31_lookup.ql5
-rw-r--r--systemtest/testdata/partialupdate/u31_lookup.ql.java.out15
-rw-r--r--systemtest/testdata/partialupdate/u31_lookup.ql.out64
-rw-r--r--systemtest/testdata/partialupdate/u32_update.ql15
-rw-r--r--systemtest/testdata/partialupdate/u32_update.ql.java.out0
-rw-r--r--systemtest/testdata/partialupdate/u32_update.ql.out0
-rw-r--r--systemtest/testdata/partialupdate/u33_lookup.ql5
-rw-r--r--systemtest/testdata/partialupdate/u33_lookup.ql.java.out15
-rw-r--r--systemtest/testdata/partialupdate/u33_lookup.ql.out64
-rw-r--r--systemtest/testdata/partialupdate/u34_update.ql20
-rw-r--r--systemtest/testdata/partialupdate/u34_update.ql.java.out0
-rw-r--r--systemtest/testdata/partialupdate/u34_update.ql.out0
-rw-r--r--systemtest/testdata/partialupdate/u35_lookup.ql5
-rw-r--r--systemtest/testdata/partialupdate/u35_lookup.ql.java.out15
-rw-r--r--systemtest/testdata/partialupdate/u35_lookup.ql.out64
-rw-r--r--systemtest/testdata/partialupdate/u36_update.ql10
-rw-r--r--systemtest/testdata/partialupdate/u36_update.ql.java.out0
-rw-r--r--systemtest/testdata/partialupdate/u36_update.ql.out0
-rw-r--r--systemtest/testdata/partialupdate/u37_lookup.ql5
-rw-r--r--systemtest/testdata/partialupdate/u37_lookup.ql.java.out15
-rw-r--r--systemtest/testdata/partialupdate/u37_lookup.ql.out64
-rw-r--r--systemtest/testdata/partialupdate/u38_update.ql20
-rw-r--r--systemtest/testdata/partialupdate/u38_update.ql.java.out0
-rw-r--r--systemtest/testdata/partialupdate/u38_update.ql.out0
-rw-r--r--systemtest/testdata/partialupdate/u39_lookup.ql5
-rw-r--r--systemtest/testdata/partialupdate/u39_lookup.ql.java.out15
-rw-r--r--systemtest/testdata/partialupdate/u39_lookup.ql.out64
-rw-r--r--systemtest/testdata/partialupdate/u40_update.ql7
-rw-r--r--systemtest/testdata/partialupdate/u40_update.ql.java.out0
-rw-r--r--systemtest/testdata/partialupdate/u40_update.ql.out0
-rw-r--r--systemtest/testdata/partialupdate/u41_lookup.ql5
-rw-r--r--systemtest/testdata/partialupdate/u41_lookup.ql.java.out15
-rw-r--r--systemtest/testdata/partialupdate/u41_lookup.ql.out64
-rw-r--r--systemtest/testdata/partialupdate/u42_update.ql7
-rw-r--r--systemtest/testdata/partialupdate/u42_update.ql.java.out0
-rw-r--r--systemtest/testdata/partialupdate/u42_update.ql.out0
-rw-r--r--systemtest/testdata/partialupdate/u43_lookup.ql5
-rw-r--r--systemtest/testdata/partialupdate/u43_lookup.ql.java.out15
-rw-r--r--systemtest/testdata/partialupdate/u43_lookup.ql.out64
-rw-r--r--systemtest/testdata/partialupdate/u98_deletemdd.ql2
-rw-r--r--systemtest/testdata/partialupdate/u98_deletemdd.ql.java.out0
-rw-r--r--systemtest/testdata/partialupdate/u98_deletemdd.ql.out0
-rw-r--r--systemtest/testdata/partialupdate/u99_dropcoll.ql1
-rw-r--r--systemtest/testdata/partialupdate/u99_dropcoll.ql.java.out0
-rw-r--r--systemtest/testdata/partialupdate/u99_dropcoll.ql.out0
-rw-r--r--systemtest/testdata/queryresult/boolean.ql2
-rw-r--r--systemtest/testdata/queryresult/boolean.ql.java.out1
-rw-r--r--systemtest/testdata/queryresult/boolean.ql.out6
-rw-r--r--systemtest/testdata/queryresult/char.ql2
-rw-r--r--systemtest/testdata/queryresult/char.ql.java.out1
-rw-r--r--systemtest/testdata/queryresult/char.ql.out6
-rw-r--r--systemtest/testdata/queryresult/double.ql2
-rw-r--r--systemtest/testdata/queryresult/double.ql.java.out1
-rw-r--r--systemtest/testdata/queryresult/double.ql.out6
-rw-r--r--systemtest/testdata/queryresult/float.ql2
-rw-r--r--systemtest/testdata/queryresult/float.ql.java.out1
-rw-r--r--systemtest/testdata/queryresult/float.ql.out6
-rw-r--r--systemtest/testdata/queryresult/long.ql2
-rw-r--r--systemtest/testdata/queryresult/long.ql.java.out1
-rw-r--r--systemtest/testdata/queryresult/long.ql.out6
-rw-r--r--systemtest/testdata/queryresult/minterval.ql2
-rw-r--r--systemtest/testdata/queryresult/minterval.ql.java.out1
-rw-r--r--systemtest/testdata/queryresult/minterval.ql.out6
-rw-r--r--systemtest/testdata/queryresult/octet.ql2
-rw-r--r--systemtest/testdata/queryresult/octet.ql.java.out1
-rw-r--r--systemtest/testdata/queryresult/octet.ql.out6
-rw-r--r--systemtest/testdata/queryresult/point.ql2
-rw-r--r--systemtest/testdata/queryresult/point.ql.java.out1
-rw-r--r--systemtest/testdata/queryresult/point.ql.out6
-rw-r--r--systemtest/testdata/queryresult/short.ql2
-rw-r--r--systemtest/testdata/queryresult/short.ql.java.out1
-rw-r--r--systemtest/testdata/queryresult/short.ql.out6
-rw-r--r--systemtest/testdata/queryresult/sinterval.ql2
-rw-r--r--systemtest/testdata/queryresult/sinterval.ql.java.out1
-rw-r--r--systemtest/testdata/queryresult/sinterval.ql.out6
-rw-r--r--systemtest/testdata/queryresult/struct.ql2
-rw-r--r--systemtest/testdata/queryresult/struct.ql.java.out16
-rw-r--r--systemtest/testdata/queryresult/struct.ql.out6
-rw-r--r--systemtest/testdata/queryresult/ulong.ql2
-rw-r--r--systemtest/testdata/queryresult/ulong.ql.java.out1
-rw-r--r--systemtest/testdata/queryresult/ulong.ql.out6
-rw-r--r--systemtest/testdata/queryresult/ushort.ql2
-rw-r--r--systemtest/testdata/queryresult/ushort.ql.java.out1
-rw-r--r--systemtest/testdata/queryresult/ushort.ql.out6
-rw-r--r--systemtest/testdata/reduce/addcellschar.ql3
-rw-r--r--systemtest/testdata/reduce/addcellschar.ql.java.out29
-rw-r--r--systemtest/testdata/reduce/addcellschar.ql.out24
-rw-r--r--systemtest/testdata/reduce/addcellsdouble.ql3
-rw-r--r--systemtest/testdata/reduce/addcellsdouble.ql.java.out29
-rw-r--r--systemtest/testdata/reduce/addcellsdouble.ql.out24
-rw-r--r--systemtest/testdata/reduce/addcellsfloat.ql3
-rw-r--r--systemtest/testdata/reduce/addcellsfloat.ql.java.out29
-rw-r--r--systemtest/testdata/reduce/addcellsfloat.ql.out24
-rw-r--r--systemtest/testdata/reduce/addcellslong.ql3
-rw-r--r--systemtest/testdata/reduce/addcellslong.ql.java.out29
-rw-r--r--systemtest/testdata/reduce/addcellslong.ql.out24
-rw-r--r--systemtest/testdata/reduce/addcellsoctet.ql3
-rw-r--r--systemtest/testdata/reduce/addcellsoctet.ql.java.out29
-rw-r--r--systemtest/testdata/reduce/addcellsoctet.ql.out24
-rw-r--r--systemtest/testdata/reduce/addcellsshort.ql3
-rw-r--r--systemtest/testdata/reduce/addcellsshort.ql.java.out29
-rw-r--r--systemtest/testdata/reduce/addcellsshort.ql.out24
-rw-r--r--systemtest/testdata/reduce/addcellsstruct.ql3
-rw-r--r--systemtest/testdata/reduce/addcellsstruct.ql.java.out15
-rw-r--r--systemtest/testdata/reduce/addcellsstruct.ql.out24
-rw-r--r--systemtest/testdata/reduce/addcellsulong.ql3
-rw-r--r--systemtest/testdata/reduce/addcellsulong.ql.java.out29
-rw-r--r--systemtest/testdata/reduce/addcellsulong.ql.out24
-rw-r--r--systemtest/testdata/reduce/addcellsushort.ql3
-rw-r--r--systemtest/testdata/reduce/addcellsushort.ql.java.out29
-rw-r--r--systemtest/testdata/reduce/addcellsushort.ql.out24
-rw-r--r--systemtest/testdata/reduce/avgcellschar.ql3
-rw-r--r--systemtest/testdata/reduce/avgcellschar.ql.java.out15
-rw-r--r--systemtest/testdata/reduce/avgcellschar.ql.out14
-rw-r--r--systemtest/testdata/reduce/avgcellsdouble.ql3
-rw-r--r--systemtest/testdata/reduce/avgcellsdouble.ql.java.out15
-rw-r--r--systemtest/testdata/reduce/avgcellsdouble.ql.out14
-rw-r--r--systemtest/testdata/reduce/avgcellsfloat.ql3
-rw-r--r--systemtest/testdata/reduce/avgcellsfloat.ql.java.out15
-rw-r--r--systemtest/testdata/reduce/avgcellsfloat.ql.out14
-rw-r--r--systemtest/testdata/reduce/avgcellslong.ql3
-rw-r--r--systemtest/testdata/reduce/avgcellslong.ql.java.out15
-rw-r--r--systemtest/testdata/reduce/avgcellslong.ql.out14
-rw-r--r--systemtest/testdata/reduce/avgcellsoctet.ql3
-rw-r--r--systemtest/testdata/reduce/avgcellsoctet.ql.java.out15
-rw-r--r--systemtest/testdata/reduce/avgcellsoctet.ql.out14
-rw-r--r--systemtest/testdata/reduce/avgcellsshort.ql3
-rw-r--r--systemtest/testdata/reduce/avgcellsshort.ql.java.out15
-rw-r--r--systemtest/testdata/reduce/avgcellsshort.ql.out14
-rw-r--r--systemtest/testdata/reduce/avgcellsstruct.ql3
-rw-r--r--systemtest/testdata/reduce/avgcellsstruct.ql.java.out15
-rw-r--r--systemtest/testdata/reduce/avgcellsstruct.ql.out14
-rw-r--r--systemtest/testdata/reduce/avgcellsulong.ql3
-rw-r--r--systemtest/testdata/reduce/avgcellsulong.ql.java.out15
-rw-r--r--systemtest/testdata/reduce/avgcellsulong.ql.out14
-rw-r--r--systemtest/testdata/reduce/avgcellsushort.ql3
-rw-r--r--systemtest/testdata/reduce/avgcellsushort.ql.java.out15
-rw-r--r--systemtest/testdata/reduce/avgcellsushort.ql.out14
-rw-r--r--systemtest/testdata/reduce/countcells.ql3
-rw-r--r--systemtest/testdata/reduce/countcells.ql.java.out29
-rw-r--r--systemtest/testdata/reduce/countcells.ql.out24
-rw-r--r--systemtest/testdata/reduce/maxcellschar.ql3
-rw-r--r--systemtest/testdata/reduce/maxcellschar.ql.java.out29
-rw-r--r--systemtest/testdata/reduce/maxcellschar.ql.out24
-rw-r--r--systemtest/testdata/reduce/maxcellsdouble.ql3
-rw-r--r--systemtest/testdata/reduce/maxcellsdouble.ql.java.out29
-rw-r--r--systemtest/testdata/reduce/maxcellsdouble.ql.out24
-rw-r--r--systemtest/testdata/reduce/maxcellsfloat.ql3
-rw-r--r--systemtest/testdata/reduce/maxcellsfloat.ql.java.out29
-rw-r--r--systemtest/testdata/reduce/maxcellsfloat.ql.out24
-rw-r--r--systemtest/testdata/reduce/maxcellslong.ql3
-rw-r--r--systemtest/testdata/reduce/maxcellslong.ql.java.out29
-rw-r--r--systemtest/testdata/reduce/maxcellslong.ql.out24
-rw-r--r--systemtest/testdata/reduce/maxcellsoctet.ql3
-rw-r--r--systemtest/testdata/reduce/maxcellsoctet.ql.java.out29
-rw-r--r--systemtest/testdata/reduce/maxcellsoctet.ql.out24
-rw-r--r--systemtest/testdata/reduce/maxcellsshort.ql3
-rw-r--r--systemtest/testdata/reduce/maxcellsshort.ql.java.out29
-rw-r--r--systemtest/testdata/reduce/maxcellsshort.ql.out24
-rw-r--r--systemtest/testdata/reduce/maxcellsstruct.ql3
-rw-r--r--systemtest/testdata/reduce/maxcellsstruct.ql.java.out15
-rw-r--r--systemtest/testdata/reduce/maxcellsstruct.ql.out24
-rw-r--r--systemtest/testdata/reduce/maxcellsulong.ql3
-rw-r--r--systemtest/testdata/reduce/maxcellsulong.ql.java.out29
-rw-r--r--systemtest/testdata/reduce/maxcellsulong.ql.out24
-rw-r--r--systemtest/testdata/reduce/maxcellsushort.ql3
-rw-r--r--systemtest/testdata/reduce/maxcellsushort.ql.java.out29
-rw-r--r--systemtest/testdata/reduce/maxcellsushort.ql.out24
-rw-r--r--systemtest/testdata/reduce/mincellschar.ql3
-rw-r--r--systemtest/testdata/reduce/mincellschar.ql.java.out29
-rw-r--r--systemtest/testdata/reduce/mincellschar.ql.out24
-rw-r--r--systemtest/testdata/reduce/mincellsdouble.ql3
-rw-r--r--systemtest/testdata/reduce/mincellsdouble.ql.java.out29
-rw-r--r--systemtest/testdata/reduce/mincellsdouble.ql.out24
-rw-r--r--systemtest/testdata/reduce/mincellsfloat.ql3
-rw-r--r--systemtest/testdata/reduce/mincellsfloat.ql.java.out29
-rw-r--r--systemtest/testdata/reduce/mincellsfloat.ql.out24
-rw-r--r--systemtest/testdata/reduce/mincellslong.ql3
-rw-r--r--systemtest/testdata/reduce/mincellslong.ql.java.out29
-rw-r--r--systemtest/testdata/reduce/mincellslong.ql.out24
-rw-r--r--systemtest/testdata/reduce/mincellsoctet.ql.out16
-rw-r--r--systemtest/testdata/reduce/mincellsshort.ql3
-rw-r--r--systemtest/testdata/reduce/mincellsshort.ql.java.out29
-rw-r--r--systemtest/testdata/reduce/mincellsshort.ql.out24
-rw-r--r--systemtest/testdata/reduce/mincellsstruct.ql3
-rw-r--r--systemtest/testdata/reduce/mincellsstruct.ql.java.out15
-rw-r--r--systemtest/testdata/reduce/mincellsstruct.ql.out24
-rw-r--r--systemtest/testdata/reduce/mincellsulong.ql3
-rw-r--r--systemtest/testdata/reduce/mincellsulong.ql.java.out29
-rw-r--r--systemtest/testdata/reduce/mincellsulong.ql.out24
-rw-r--r--systemtest/testdata/reduce/mincellsushort.ql3
-rw-r--r--systemtest/testdata/reduce/mincellsushort.ql.java.out29
-rw-r--r--systemtest/testdata/reduce/mincellsushort.ql.out24
-rw-r--r--systemtest/testdata/rewriteset1/pushdownall.ql7
-rw-r--r--systemtest/testdata/rewriteset1/pushdownall.ql.java.out15
-rw-r--r--systemtest/testdata/rewriteset1/pushdownall.ql.out24
-rw-r--r--systemtest/testdata/rewriteset1/pushdownsome.ql7
-rw-r--r--systemtest/testdata/rewriteset1/pushdownsome.ql.java.out43
-rw-r--r--systemtest/testdata/rewriteset1/pushdownsome.ql.out64
-rw-r--r--systemtest/testdata/testset1/agg1.ql6
-rw-r--r--systemtest/testdata/testset1/agg1.ql.java.out15
-rw-r--r--systemtest/testdata/testset1/agg1.ql.out24
-rw-r--r--systemtest/testdata/testset1/agg2.ql6
-rw-r--r--systemtest/testdata/testset1/agg2.ql.java.out29
-rw-r--r--systemtest/testdata/testset1/agg2.ql.out44
-rw-r--r--systemtest/testdata/testset1/agg3.ql6
-rw-r--r--systemtest/testdata/testset1/agg3.ql.java.out57
-rw-r--r--systemtest/testdata/testset1/agg3.ql.out84
-rw-r--r--systemtest/testdata/testset1/dot1.ql5
-rw-r--r--systemtest/testdata/testset1/dot1.ql.java.out29
-rw-r--r--systemtest/testdata/testset1/dot1.ql.out44
-rw-r--r--systemtest/testdata/testset1/dot2.ql5
-rw-r--r--systemtest/testdata/testset1/dot2.ql.java.out29
-rw-r--r--systemtest/testdata/testset1/dot2.ql.out44
-rw-r--r--systemtest/testdata/testset1/dot3.ql5
-rw-r--r--systemtest/testdata/testset1/dot3.ql.java.out29
-rw-r--r--systemtest/testdata/testset1/dot3.ql.out44
-rw-r--r--systemtest/testdata/testset1/dot4.ql5
-rw-r--r--systemtest/testdata/testset1/dot4.ql.java.out29
-rw-r--r--systemtest/testdata/testset1/dot4.ql.out44
-rw-r--r--systemtest/testdata/testset1/dot5.ql6
-rw-r--r--systemtest/testdata/testset1/dot5.ql.java.out29
-rw-r--r--systemtest/testdata/testset1/dot5.ql.out44
-rw-r--r--systemtest/testdata/testset1/dot6.ql5
-rw-r--r--systemtest/testdata/testset1/dot6.ql.java.out29
-rw-r--r--systemtest/testdata/testset1/dot6.ql.out44
-rw-r--r--systemtest/testdata/testset1/dot7.ql2
-rw-r--r--systemtest/testdata/testset1/dot7.ql.java.out15
-rw-r--r--systemtest/testdata/testset1/dot7.ql.out44
-rw-r--r--systemtest/testdata/testset1/ind1.ql5
-rw-r--r--systemtest/testdata/testset1/ind1.ql.java.out29
-rw-r--r--systemtest/testdata/testset1/ind1.ql.out44
-rw-r--r--systemtest/testdata/testset1/ind2.ql5
-rw-r--r--systemtest/testdata/testset1/ind2.ql.java.out15
-rw-r--r--systemtest/testdata/testset1/ind2.ql.out44
-rw-r--r--systemtest/testdata/testset1/ind3.ql5
-rw-r--r--systemtest/testdata/testset1/ind3.ql.java.out29
-rw-r--r--systemtest/testdata/testset1/ind3.ql.out44
-rw-r--r--systemtest/testdata/testset1/opt1.ql7
-rw-r--r--systemtest/testdata/testset1/opt1.ql.java.out29
-rw-r--r--systemtest/testdata/testset1/opt1.ql.out44
-rw-r--r--systemtest/testdata/testset1/opt2.ql5
-rw-r--r--systemtest/testdata/testset1/opt2.ql.java.out57
-rw-r--r--systemtest/testdata/testset1/opt2.ql.out84
-rw-r--r--systemtest/testdata/testset1/opt4.ql6
-rw-r--r--systemtest/testdata/testset1/opt4.ql.java.out29
-rw-r--r--systemtest/testdata/testset1/opt4.ql.out44
-rw-r--r--systemtest/testdata/testset1/opt5.ql6
-rw-r--r--systemtest/testdata/testset1/opt5.ql.java.out57
-rw-r--r--systemtest/testdata/testset1/opt5.ql.out84
-rw-r--r--systemtest/testdata/testset1/trim1.ql5
-rw-r--r--systemtest/testdata/testset1/trim1.ql.java.out29
-rw-r--r--systemtest/testdata/testset1/trim1.ql.out30
-rw-r--r--systemtest/testdata/testset1/trim2.ql5
-rw-r--r--systemtest/testdata/testset1/trim2.ql.java.out29
-rw-r--r--systemtest/testdata/testset1/trim2.ql.out30
-rw-r--r--systemtest/testdata/testset1/trim3.ql5
-rw-r--r--systemtest/testdata/testset1/trim3.ql.java.out57
-rw-r--r--systemtest/testdata/testset1/trim3.ql.out56
-rw-r--r--systemtest/testdata/testset1/trim4.ql5
-rw-r--r--systemtest/testdata/testset1/trim4.ql.java.out57
-rw-r--r--systemtest/testdata/testset1/trim4.ql.out56
-rw-r--r--systemtest/testdata/testset1/trim5.ql5
-rw-r--r--systemtest/testdata/testset1/trim5.ql.java.out57
-rw-r--r--systemtest/testdata/testset1/trim5.ql.out44
-rw-r--r--systemtest/testdata/testset1/trim6.ql5
-rw-r--r--systemtest/testdata/testset1/trim6.ql.java.out57
-rw-r--r--systemtest/testdata/testset1/trim6.ql.out44
-rw-r--r--systemtest/testdata/testset2/const1.ql5
-rw-r--r--systemtest/testdata/testset2/const1.ql.java.out15
-rw-r--r--systemtest/testdata/testset2/const1.ql.out16
-rw-r--r--systemtest/testdata/testset2/const10.ql5
-rw-r--r--systemtest/testdata/testset2/const10.ql.java.out15
-rw-r--r--systemtest/testdata/testset2/const10.ql.out16
-rw-r--r--systemtest/testdata/testset2/const11.ql5
-rw-r--r--systemtest/testdata/testset2/const11.ql.java.out15
-rw-r--r--systemtest/testdata/testset2/const11.ql.out16
-rw-r--r--systemtest/testdata/testset2/const2.ql5
-rw-r--r--systemtest/testdata/testset2/const2.ql.java.out15
-rw-r--r--systemtest/testdata/testset2/const2.ql.out16
-rw-r--r--systemtest/testdata/testset2/const3.ql5
-rw-r--r--systemtest/testdata/testset2/const3.ql.java.out15
-rw-r--r--systemtest/testdata/testset2/const3.ql.out16
-rw-r--r--systemtest/testdata/testset2/const4.ql5
-rw-r--r--systemtest/testdata/testset2/const4.ql.java.out15
-rw-r--r--systemtest/testdata/testset2/const4.ql.out16
-rw-r--r--systemtest/testdata/testset2/const5.ql5
-rw-r--r--systemtest/testdata/testset2/const5.ql.java.out15
-rw-r--r--systemtest/testdata/testset2/const5.ql.out16
-rw-r--r--systemtest/testdata/testset2/const6.ql5
-rw-r--r--systemtest/testdata/testset2/const6.ql.java.out15
-rw-r--r--systemtest/testdata/testset2/const6.ql.out16
-rw-r--r--systemtest/testdata/testset2/const7.ql5
-rw-r--r--systemtest/testdata/testset2/const7.ql.java.out15
-rw-r--r--systemtest/testdata/testset2/const7.ql.out16
-rw-r--r--systemtest/testdata/testset2/const8.ql5
-rw-r--r--systemtest/testdata/testset2/const8.ql.java.out15
-rw-r--r--systemtest/testdata/testset2/const8.ql.out16
-rw-r--r--systemtest/testdata/testset2/const9.ql5
-rw-r--r--systemtest/testdata/testset2/const9.ql.java.out15
-rw-r--r--systemtest/testdata/testset2/const9.ql.out16
-rw-r--r--systemtest/testdata/testset2/constmdd.ql5
-rw-r--r--systemtest/testdata/testset2/constmdd.ql.java.out15
-rw-r--r--systemtest/testdata/testset2/constmdd.ql.out16
-rw-r--r--systemtest/testdata/testset2/oid5.ql6
-rw-r--r--systemtest/testdata/testset2/oid5.ql.java.out0
-rw-r--r--systemtest/testdata/testset2/oid5.ql.out4
-rw-r--r--systemtest/testdata/testset2/oid6.ql6
-rw-r--r--systemtest/testdata/testset2/oid6.ql.java.out15
-rw-r--r--systemtest/testdata/testset2/oid6.ql.out44
-rw-r--r--systemtest/testdata/testset3/domexp1.ql5
-rw-r--r--systemtest/testdata/testset3/domexp1.ql.java.out29
-rw-r--r--systemtest/testdata/testset3/domexp1.ql.out44
-rw-r--r--systemtest/testdata/testset3/domexp2.ql6
-rw-r--r--systemtest/testdata/testset3/domexp2.ql.java.out29
-rw-r--r--systemtest/testdata/testset3/domexp2.ql.out42
-rw-r--r--systemtest/testdata/testset3/domexp3.ql5
-rw-r--r--systemtest/testdata/testset3/domexp3.ql.java.out29
-rw-r--r--systemtest/testdata/testset3/domexp3.ql.out34
-rw-r--r--systemtest/testdata/testset3/domexp4.ql5
-rw-r--r--systemtest/testdata/testset3/domexp4.ql.java.out29
-rw-r--r--systemtest/testdata/testset3/domexp4.ql.out24
-rw-r--r--systemtest/testdata/testset3/domexp5.ql6
-rw-r--r--systemtest/testdata/testset3/domexp5.ql.java.out29
-rw-r--r--systemtest/testdata/testset3/domexp5.ql.out30
-rw-r--r--systemtest/testdata/testset3/minterval1.ql6
-rw-r--r--systemtest/testdata/testset3/minterval1.ql.java.out29
-rw-r--r--systemtest/testdata/testset3/minterval1.ql.out30
-rw-r--r--systemtest/testdata/testset3/proj1.ql6
-rw-r--r--systemtest/testdata/testset3/proj1.ql.java.out29
-rw-r--r--systemtest/testdata/testset3/proj1.ql.out24
-rw-r--r--systemtest/testdata/testset3/proj2.ql6
-rw-r--r--systemtest/testdata/testset3/proj2.ql.java.out29
-rw-r--r--systemtest/testdata/testset3/proj2.ql.out24
-rw-r--r--systemtest/testdata/testset3/proj3.ql6
-rw-r--r--systemtest/testdata/testset3/proj3.ql.java.out29
-rw-r--r--systemtest/testdata/testset3/proj3.ql.out24
-rw-r--r--systemtest/testdata/testset3/proj4.ql6
-rw-r--r--systemtest/testdata/testset3/proj4.ql.java.out29
-rw-r--r--systemtest/testdata/testset3/proj4.ql.out24
-rw-r--r--systemtest/testdata/testset3/proj5.ql6
-rw-r--r--systemtest/testdata/testset3/proj5.ql.java.out29
-rw-r--r--systemtest/testdata/testset3/proj5.ql.out24
-rw-r--r--systemtest/testdata/testset3/proj6.ql5
-rw-r--r--systemtest/testdata/testset3/proj6.ql.java.out29
-rw-r--r--systemtest/testdata/testset3/proj6.ql.out44
-rw-r--r--systemtest/testdata/testset3/sdom1.ql5
-rw-r--r--systemtest/testdata/testset3/sdom1.ql.java.out29
-rw-r--r--systemtest/testdata/testset3/sdom1.ql.out44
-rw-r--r--systemtest/testdata/testset3/shift1.ql2
-rw-r--r--systemtest/testdata/testset3/shift1.ql.java.out15
-rw-r--r--systemtest/testdata/testset3/shift1.ql.out24
-rw-r--r--systemtest/testdata/testset3/shift2.ql2
-rw-r--r--systemtest/testdata/testset3/shift2.ql.java.out15
-rw-r--r--systemtest/testdata/testset3/shift2.ql.out24
-rw-r--r--systemtest/testdata/testset3/shift3.ql2
-rw-r--r--systemtest/testdata/testset3/shift3.ql.java.out15
-rw-r--r--systemtest/testdata/testset3/shift3.ql.out19
-rw-r--r--systemtest/testdata/testset3/shift4.ql2
-rw-r--r--systemtest/testdata/testset3/shift4.ql.java.out15
-rw-r--r--systemtest/testdata/testset3/shift4.ql.out19
-rw-r--r--systemtest/testdata/testset3/shift41.ql2
-rw-r--r--systemtest/testdata/testset3/shift41.ql.java.out15
-rw-r--r--systemtest/testdata/testset3/shift41.ql.out19
-rw-r--r--systemtest/testdata/testset3/trim1.ql6
-rw-r--r--systemtest/testdata/testset3/trim1.ql.java.out29
-rw-r--r--systemtest/testdata/testset3/trim1.ql.out44
-rw-r--r--systemtest/testdata/testset3/trim2.ql6
-rw-r--r--systemtest/testdata/testset3/trim2.ql.java.out29
-rw-r--r--systemtest/testdata/testset3/trim2.ql.out28
-rw-r--r--systemtest/testdata/testset3/trim3.ql6
-rw-r--r--systemtest/testdata/testset3/trim3.ql.java.out29
-rw-r--r--systemtest/testdata/testset3/trim3.ql.out44
-rw-r--r--systemtest/testdata/testset3/trim4.ql6
-rw-r--r--systemtest/testdata/testset3/trim4.ql.java.out29
-rw-r--r--systemtest/testdata/testset3/trim4.ql.out44
-rw-r--r--systemtest/testdata/testset3/trim5.ql6
-rw-r--r--systemtest/testdata/testset3/trim5.ql.java.out29
-rw-r--r--systemtest/testdata/testset3/trim5.ql.out28
-rw-r--r--systemtest/testdata/unaryfunc/abs_1.ql2
-rw-r--r--systemtest/testdata/unaryfunc/abs_1.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/abs_1.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/abs_2.ql2
-rw-r--r--systemtest/testdata/unaryfunc/abs_2.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/abs_2.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/abs_3.ql2
-rw-r--r--systemtest/testdata/unaryfunc/abs_3.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/abs_3.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/abs_4.ql2
-rw-r--r--systemtest/testdata/unaryfunc/abs_4.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/abs_4.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/abs_5.ql2
-rw-r--r--systemtest/testdata/unaryfunc/abs_5.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/abs_5.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/abs_6.ql2
-rw-r--r--systemtest/testdata/unaryfunc/abs_6.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/abs_6.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/acos_1.ql2
-rw-r--r--systemtest/testdata/unaryfunc/acos_1.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/acos_1.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/acos_2.ql2
-rw-r--r--systemtest/testdata/unaryfunc/acos_2.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/acos_2.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/acos_3.ql2
-rw-r--r--systemtest/testdata/unaryfunc/acos_3.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/acos_3.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/acos_4.ql2
-rw-r--r--systemtest/testdata/unaryfunc/acos_4.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/acos_4.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/acos_5.ql2
-rw-r--r--systemtest/testdata/unaryfunc/acos_5.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/acos_5.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/acos_dom_1.ql2
-rw-r--r--systemtest/testdata/unaryfunc/acos_dom_1.ql.java.out2
-rw-r--r--systemtest/testdata/unaryfunc/acos_dom_1.ql.out1
-rw-r--r--systemtest/testdata/unaryfunc/acos_dom_2.ql2
-rw-r--r--systemtest/testdata/unaryfunc/acos_dom_2.ql.java.out2
-rw-r--r--systemtest/testdata/unaryfunc/acos_dom_2.ql.out1
-rw-r--r--systemtest/testdata/unaryfunc/asin_1.ql2
-rw-r--r--systemtest/testdata/unaryfunc/asin_1.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/asin_1.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/asin_2.ql2
-rw-r--r--systemtest/testdata/unaryfunc/asin_2.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/asin_2.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/asin_3.ql2
-rw-r--r--systemtest/testdata/unaryfunc/asin_3.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/asin_3.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/asin_4.ql2
-rw-r--r--systemtest/testdata/unaryfunc/asin_4.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/asin_4.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/asin_5.ql2
-rw-r--r--systemtest/testdata/unaryfunc/asin_5.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/asin_5.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/asin_dom_1.ql2
-rw-r--r--systemtest/testdata/unaryfunc/asin_dom_1.ql.java.out2
-rw-r--r--systemtest/testdata/unaryfunc/asin_dom_1.ql.out1
-rw-r--r--systemtest/testdata/unaryfunc/asin_dom_2.ql2
-rw-r--r--systemtest/testdata/unaryfunc/asin_dom_2.ql.java.out2
-rw-r--r--systemtest/testdata/unaryfunc/asin_dom_2.ql.out1
-rw-r--r--systemtest/testdata/unaryfunc/atan_1.ql2
-rw-r--r--systemtest/testdata/unaryfunc/atan_1.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/atan_1.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/atan_2.ql2
-rw-r--r--systemtest/testdata/unaryfunc/atan_2.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/atan_2.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/atan_3.ql2
-rw-r--r--systemtest/testdata/unaryfunc/atan_3.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/atan_3.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/atan_4.ql2
-rw-r--r--systemtest/testdata/unaryfunc/atan_4.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/atan_4.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/atan_5.ql2
-rw-r--r--systemtest/testdata/unaryfunc/atan_5.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/atan_5.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/coll_1.ql2
-rw-r--r--systemtest/testdata/unaryfunc/coll_1.ql.java.out29
-rw-r--r--systemtest/testdata/unaryfunc/coll_1.ql.out44
-rw-r--r--systemtest/testdata/unaryfunc/coll_10.ql2
-rw-r--r--systemtest/testdata/unaryfunc/coll_10.ql.java.out29
-rw-r--r--systemtest/testdata/unaryfunc/coll_10.ql.out44
-rw-r--r--systemtest/testdata/unaryfunc/coll_11.ql2
-rw-r--r--systemtest/testdata/unaryfunc/coll_11.ql.java.out29
-rw-r--r--systemtest/testdata/unaryfunc/coll_11.ql.out44
-rw-r--r--systemtest/testdata/unaryfunc/coll_2.ql2
-rw-r--r--systemtest/testdata/unaryfunc/coll_2.ql.java.out29
-rw-r--r--systemtest/testdata/unaryfunc/coll_2.ql.out44
-rw-r--r--systemtest/testdata/unaryfunc/coll_3.ql2
-rw-r--r--systemtest/testdata/unaryfunc/coll_3.ql.java.out29
-rw-r--r--systemtest/testdata/unaryfunc/coll_3.ql.out44
-rw-r--r--systemtest/testdata/unaryfunc/coll_4.ql2
-rw-r--r--systemtest/testdata/unaryfunc/coll_4.ql.java.out2
-rw-r--r--systemtest/testdata/unaryfunc/coll_4.ql.out1
-rw-r--r--systemtest/testdata/unaryfunc/coll_5.ql2
-rw-r--r--systemtest/testdata/unaryfunc/coll_5.ql.java.out2
-rw-r--r--systemtest/testdata/unaryfunc/coll_5.ql.out1
-rw-r--r--systemtest/testdata/unaryfunc/coll_6.ql2
-rw-r--r--systemtest/testdata/unaryfunc/coll_6.ql.java.out29
-rw-r--r--systemtest/testdata/unaryfunc/coll_6.ql.out44
-rw-r--r--systemtest/testdata/unaryfunc/coll_7.ql2
-rw-r--r--systemtest/testdata/unaryfunc/coll_7.ql.java.out29
-rw-r--r--systemtest/testdata/unaryfunc/coll_7.ql.out44
-rw-r--r--systemtest/testdata/unaryfunc/coll_8.ql2
-rw-r--r--systemtest/testdata/unaryfunc/coll_8.ql.java.out29
-rw-r--r--systemtest/testdata/unaryfunc/coll_8.ql.out44
-rw-r--r--systemtest/testdata/unaryfunc/coll_9.ql2
-rw-r--r--systemtest/testdata/unaryfunc/coll_9.ql.java.out29
-rw-r--r--systemtest/testdata/unaryfunc/coll_9.ql.out44
-rw-r--r--systemtest/testdata/unaryfunc/cos_1.ql2
-rw-r--r--systemtest/testdata/unaryfunc/cos_1.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/cos_1.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/cos_2.ql2
-rw-r--r--systemtest/testdata/unaryfunc/cos_2.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/cos_2.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/cos_3.ql2
-rw-r--r--systemtest/testdata/unaryfunc/cos_3.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/cos_3.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/cos_4.ql2
-rw-r--r--systemtest/testdata/unaryfunc/cos_4.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/cos_4.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/cos_5.ql2
-rw-r--r--systemtest/testdata/unaryfunc/cos_5.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/cos_5.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/cos_6.ql2
-rw-r--r--systemtest/testdata/unaryfunc/cos_6.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/cos_6.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/cos_7.ql2
-rw-r--r--systemtest/testdata/unaryfunc/cos_7.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/cos_7.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/exp_1.ql2
-rw-r--r--systemtest/testdata/unaryfunc/exp_1.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/exp_1.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/exp_2.ql2
-rw-r--r--systemtest/testdata/unaryfunc/exp_2.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/exp_2.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/exp_3.ql2
-rw-r--r--systemtest/testdata/unaryfunc/exp_3.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/exp_3.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/exp_erange_1.ql2
-rw-r--r--systemtest/testdata/unaryfunc/exp_erange_1.ql.java.out2
-rw-r--r--systemtest/testdata/unaryfunc/exp_erange_1.ql.out1
-rw-r--r--systemtest/testdata/unaryfunc/exp_erange_2.ql2
-rw-r--r--systemtest/testdata/unaryfunc/exp_erange_2.ql.java.out2
-rw-r--r--systemtest/testdata/unaryfunc/exp_erange_2.ql.out1
-rw-r--r--systemtest/testdata/unaryfunc/ln_1.ql2
-rw-r--r--systemtest/testdata/unaryfunc/ln_1.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/ln_1.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/ln_2.ql2
-rw-r--r--systemtest/testdata/unaryfunc/ln_2.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/ln_2.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/ln_3.ql2
-rw-r--r--systemtest/testdata/unaryfunc/ln_3.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/ln_3.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/ln_edom.ql2
-rw-r--r--systemtest/testdata/unaryfunc/ln_edom.ql.java.out2
-rw-r--r--systemtest/testdata/unaryfunc/ln_edom.ql.out1
-rw-r--r--systemtest/testdata/unaryfunc/ln_erange.ql2
-rw-r--r--systemtest/testdata/unaryfunc/ln_erange.ql.java.out2
-rw-r--r--systemtest/testdata/unaryfunc/ln_erange.ql.out1
-rw-r--r--systemtest/testdata/unaryfunc/log_1.ql2
-rw-r--r--systemtest/testdata/unaryfunc/log_1.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/log_1.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/log_2.ql2
-rw-r--r--systemtest/testdata/unaryfunc/log_2.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/log_2.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/log_3.ql2
-rw-r--r--systemtest/testdata/unaryfunc/log_3.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/log_3.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/log_edom.ql2
-rw-r--r--systemtest/testdata/unaryfunc/log_edom.ql.java.out2
-rw-r--r--systemtest/testdata/unaryfunc/log_edom.ql.out1
-rw-r--r--systemtest/testdata/unaryfunc/log_erange.ql2
-rw-r--r--systemtest/testdata/unaryfunc/log_erange.ql.java.out2
-rw-r--r--systemtest/testdata/unaryfunc/log_erange.ql.out1
-rw-r--r--systemtest/testdata/unaryfunc/mix_1.ql2
-rw-r--r--systemtest/testdata/unaryfunc/mix_1.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/mix_1.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/mix_2.ql2
-rw-r--r--systemtest/testdata/unaryfunc/mix_2.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/mix_2.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/mix_3.ql2
-rw-r--r--systemtest/testdata/unaryfunc/mix_3.ql.java.out2
-rw-r--r--systemtest/testdata/unaryfunc/mix_3.ql.out1
-rw-r--r--systemtest/testdata/unaryfunc/sin_1.ql2
-rw-r--r--systemtest/testdata/unaryfunc/sin_1.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/sin_1.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/sin_2.ql2
-rw-r--r--systemtest/testdata/unaryfunc/sin_2.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/sin_2.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/sin_3.ql2
-rw-r--r--systemtest/testdata/unaryfunc/sin_3.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/sin_3.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/sin_4.ql2
-rw-r--r--systemtest/testdata/unaryfunc/sin_4.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/sin_4.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/sin_5.ql2
-rw-r--r--systemtest/testdata/unaryfunc/sin_5.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/sin_5.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/sin_6.ql2
-rw-r--r--systemtest/testdata/unaryfunc/sin_6.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/sin_6.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/sin_7.ql2
-rw-r--r--systemtest/testdata/unaryfunc/sin_7.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/sin_7.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/sqrt_1.ql2
-rw-r--r--systemtest/testdata/unaryfunc/sqrt_1.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/sqrt_1.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/sqrt_2.ql2
-rw-r--r--systemtest/testdata/unaryfunc/sqrt_2.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/sqrt_2.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/sqrt_3.ql2
-rw-r--r--systemtest/testdata/unaryfunc/sqrt_3.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/sqrt_3.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/sqrt_4.ql2
-rw-r--r--systemtest/testdata/unaryfunc/sqrt_4.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/sqrt_4.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/sqrt_5.ql2
-rw-r--r--systemtest/testdata/unaryfunc/sqrt_5.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/sqrt_5.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/sqrt_6.ql2
-rw-r--r--systemtest/testdata/unaryfunc/sqrt_6.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/sqrt_6.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/sqrt_7.ql2
-rw-r--r--systemtest/testdata/unaryfunc/sqrt_7.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/sqrt_7.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/sqrt_edom.ql2
-rw-r--r--systemtest/testdata/unaryfunc/sqrt_edom.ql.java.out2
-rw-r--r--systemtest/testdata/unaryfunc/sqrt_edom.ql.out1
-rw-r--r--systemtest/testdata/unaryfunc/tan_1.ql2
-rw-r--r--systemtest/testdata/unaryfunc/tan_1.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/tan_1.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/tan_2.ql2
-rw-r--r--systemtest/testdata/unaryfunc/tan_2.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/tan_2.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/tan_3.ql2
-rw-r--r--systemtest/testdata/unaryfunc/tan_3.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/tan_3.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/tan_4.ql2
-rw-r--r--systemtest/testdata/unaryfunc/tan_4.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/tan_4.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/tan_edom_1.ql2
-rw-r--r--systemtest/testdata/unaryfunc/tan_edom_1.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/tan_edom_1.ql.out6
-rw-r--r--systemtest/testdata/unaryfunc/tan_edom_2.ql2
-rw-r--r--systemtest/testdata/unaryfunc/tan_edom_2.ql.java.out1
-rw-r--r--systemtest/testdata/unaryfunc/tan_edom_2.ql.out6
-rw-r--r--systemtest/testdata/updateset1/u1_create.ql1
-rw-r--r--systemtest/testdata/updateset1/u1_create.ql.java.out0
-rw-r--r--systemtest/testdata/updateset1/u1_create.ql.out0
-rw-r--r--systemtest/testdata/updateset1/u2_insert.ql1
-rw-r--r--systemtest/testdata/updateset1/u2_insert.ql.java.out0
-rw-r--r--systemtest/testdata/updateset1/u2_insert.ql.out0
-rw-r--r--systemtest/testdata/updateset1/u3_lookup.ql5
-rw-r--r--systemtest/testdata/updateset1/u3_lookup.ql.java.out15
-rw-r--r--systemtest/testdata/updateset1/u3_lookup.ql.out24
-rw-r--r--systemtest/testdata/updateset1/u4_update.ql3
-rw-r--r--systemtest/testdata/updateset1/u4_update.ql.java.out0
-rw-r--r--systemtest/testdata/updateset1/u4_update.ql.out0
-rw-r--r--systemtest/testdata/updateset1/u51_lookup.ql5
-rw-r--r--systemtest/testdata/updateset1/u51_lookup.ql.java.out15
-rw-r--r--systemtest/testdata/updateset1/u51_lookup.ql.out24
-rw-r--r--systemtest/testdata/updateset1/u5_deletemdd.ql2
-rw-r--r--systemtest/testdata/updateset1/u5_deletemdd.ql.java.out0
-rw-r--r--systemtest/testdata/updateset1/u5_deletemdd.ql.out0
-rw-r--r--systemtest/testdata/updateset1/u7_dropcoll.ql1
-rw-r--r--systemtest/testdata/updateset1/u7_dropcoll.ql.java.out0
-rw-r--r--systemtest/testdata/updateset1/u7_dropcoll.ql.out0
-rw-r--r--systemtest/testdata/updateset2/u1_create.ql1
-rw-r--r--systemtest/testdata/updateset2/u1_create.ql.java.out0
-rw-r--r--systemtest/testdata/updateset2/u1_create.ql.out0
-rw-r--r--systemtest/testdata/updateset2/u2_insert.ql1
-rw-r--r--systemtest/testdata/updateset2/u2_insert.ql.java.out0
-rw-r--r--systemtest/testdata/updateset2/u2_insert.ql.out0
-rw-r--r--systemtest/testdata/updateset2/u4_update.ql3
-rw-r--r--systemtest/testdata/updateset2/u4_update.ql.java.out0
-rw-r--r--systemtest/testdata/updateset2/u4_update.ql.out0
-rw-r--r--systemtest/testdata/updateset2/u5_update.ql3
-rw-r--r--systemtest/testdata/updateset2/u5_update.ql.java.out0
-rw-r--r--systemtest/testdata/updateset2/u5_update.ql.out0
-rw-r--r--systemtest/testdata/updateset2/u97_lookup.ql5
-rw-r--r--systemtest/testdata/updateset2/u97_lookup.ql.java.out15
-rw-r--r--systemtest/testdata/updateset2/u97_lookup.ql.out25
-rw-r--r--systemtest/testdata/updateset2/u98_deletemdd.ql2
-rw-r--r--systemtest/testdata/updateset2/u98_deletemdd.ql.java.out0
-rw-r--r--systemtest/testdata/updateset2/u98_deletemdd.ql.out0
-rw-r--r--systemtest/testdata/updateset2/u99_dropcoll.ql1
-rw-r--r--systemtest/testdata/updateset2/u99_dropcoll.ql.java.out0
-rw-r--r--systemtest/testdata/updateset2/u99_dropcoll.ql.out0
-rw-r--r--systemtest/testdata/updateset3/u01_create.ql1
-rw-r--r--systemtest/testdata/updateset3/u01_create.ql.java.out0
-rw-r--r--systemtest/testdata/updateset3/u01_create.ql.out0
-rw-r--r--systemtest/testdata/updateset3/u02_insert.ql1
-rw-r--r--systemtest/testdata/updateset3/u02_insert.ql.java.out0
-rw-r--r--systemtest/testdata/updateset3/u02_insert.ql.out0
-rw-r--r--systemtest/testdata/updateset3/u03_lookup.ql2
-rw-r--r--systemtest/testdata/updateset3/u03_lookup.ql.java.out15
-rw-r--r--systemtest/testdata/updateset3/u03_lookup.ql.out18
-rw-r--r--systemtest/testdata/updateset3/u04_update.ql3
-rw-r--r--systemtest/testdata/updateset3/u04_update.ql.java.out0
-rw-r--r--systemtest/testdata/updateset3/u04_update.ql.out0
-rw-r--r--systemtest/testdata/updateset3/u05_lookup.ql2
-rw-r--r--systemtest/testdata/updateset3/u05_lookup.ql.java.out15
-rw-r--r--systemtest/testdata/updateset3/u05_lookup.ql.out19
-rw-r--r--systemtest/testdata/updateset3/u06_update.ql3
-rw-r--r--systemtest/testdata/updateset3/u06_update.ql.java.out0
-rw-r--r--systemtest/testdata/updateset3/u06_update.ql.out0
-rw-r--r--systemtest/testdata/updateset3/u07_lookup.ql2
-rw-r--r--systemtest/testdata/updateset3/u07_lookup.ql.java.out15
-rw-r--r--systemtest/testdata/updateset3/u07_lookup.ql.out19
-rw-r--r--systemtest/testdata/updateset3/u08_update.ql3
-rw-r--r--systemtest/testdata/updateset3/u08_update.ql.java.out0
-rw-r--r--systemtest/testdata/updateset3/u08_update.ql.out0
-rw-r--r--systemtest/testdata/updateset3/u09_update.ql3
-rw-r--r--systemtest/testdata/updateset3/u09_update.ql.java.out0
-rw-r--r--systemtest/testdata/updateset3/u09_update.ql.out0
-rw-r--r--systemtest/testdata/updateset3/u10_update.ql3
-rw-r--r--systemtest/testdata/updateset3/u10_update.ql.java.out0
-rw-r--r--systemtest/testdata/updateset3/u10_update.ql.out0
-rw-r--r--systemtest/testdata/updateset3/u97_lookup.ql2
-rw-r--r--systemtest/testdata/updateset3/u97_lookup.ql.java.out15
-rw-r--r--systemtest/testdata/updateset3/u97_lookup.ql.out20
-rw-r--r--systemtest/testdata/updateset3/u98_deletemdd.ql2
-rw-r--r--systemtest/testdata/updateset3/u98_deletemdd.ql.java.out0
-rw-r--r--systemtest/testdata/updateset3/u98_deletemdd.ql.out0
-rw-r--r--systemtest/testdata/updateset3/u99_dropcoll.ql1
-rw-r--r--systemtest/testdata/updateset3/u99_dropcoll.ql.java.out0
-rw-r--r--systemtest/testdata/updateset3/u99_dropcoll.ql.out0
-rw-r--r--systemtest/testdata/updateset4/u01_create.ql1
-rw-r--r--systemtest/testdata/updateset4/u01_create.ql.java.out0
-rw-r--r--systemtest/testdata/updateset4/u01_create.ql.out0
-rw-r--r--systemtest/testdata/updateset4/u02_insert.ql1
-rw-r--r--systemtest/testdata/updateset4/u02_insert.ql.java.out0
-rw-r--r--systemtest/testdata/updateset4/u02_insert.ql.out0
-rw-r--r--systemtest/testdata/updateset4/u97_lookup.ql2
-rw-r--r--systemtest/testdata/updateset4/u97_lookup.ql.java.out15
-rw-r--r--systemtest/testdata/updateset4/u97_lookup.ql.out24
-rw-r--r--systemtest/testdata/updateset4/u98_deletemdd.ql2
-rw-r--r--systemtest/testdata/updateset4/u98_deletemdd.ql.java.out0
-rw-r--r--systemtest/testdata/updateset4/u98_deletemdd.ql.out0
-rw-r--r--systemtest/testdata/updateset4/u99_dropcoll.ql1
-rw-r--r--systemtest/testdata/updateset4/u99_dropcoll.ql.java.out0
-rw-r--r--systemtest/testdata/updateset4/u99_dropcoll.ql.out0
-rw-r--r--systemtest/testjava.sh353
-rw-r--r--tilemgr/Makefile.am33
-rw-r--r--tilemgr/cell.cc1
-rw-r--r--tilemgr/cell.hh2
-rw-r--r--tilemgr/cell.icc2
-rw-r--r--tilemgr/compression.hh1
-rw-r--r--tilemgr/comptile.cc1
-rw-r--r--tilemgr/comptile.hh1
-rw-r--r--tilemgr/gencompression.cc2
-rw-r--r--tilemgr/gencompression.hh2
-rw-r--r--tilemgr/nocompression.cc2
-rw-r--r--tilemgr/nocompression.hh2
-rw-r--r--tilemgr/perstile.cc1
-rw-r--r--tilemgr/perstile.hh0
-rw-r--r--tilemgr/perstile.icc0
-rw-r--r--tilemgr/test/Makefile81
-rw-r--r--tilemgr/test/test_access.cc673
-rw-r--r--tilemgr/test/test_access.data3
-rw-r--r--tilemgr/test/test_splittile.cc142
-rw-r--r--tilemgr/test/test_tile.cc979
-rw-r--r--tilemgr/test/tilertest.cc288
-rw-r--r--tilemgr/tile.cc1187
-rw-r--r--tilemgr/tile.hh391
-rw-r--r--tilemgr/tile.icc1
-rw-r--r--tilemgr/tiler.cc397
-rw-r--r--tilemgr/tiler.hh93
-rw-r--r--tilemgr/transtile.cc1
-rw-r--r--tilemgr/transtile.hh1
-rw-r--r--time/Makefile.am31
-rw-r--r--time/README2
-rw-r--r--time/akg_benchmark.cc123
-rw-r--r--time/akg_localtime.cc60
-rw-r--r--time/akgtime.hh85
-rw-r--r--time/main.cc46
2697 files changed, 328497 insertions, 0 deletions
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..3cb29c7
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,13 @@
+To build and install rasdaman:
+
+ $ ./configure
+ $ make
+ # make install
+
+You may set the installation directory and other parameters by options
+to ./configure. To see them, use:
+
+ $ ./configure --help
+
+Once installed, see the "rasdaman Installation Guide" for the next steps.
+It can be found in manuals_and_examples/manuals/pdf/inst-guide.pdf \ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..9640b39
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,50 @@
+
+#
+# MAKEFILE FOR:
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+# Top Level makefile. This points to the various modules that have to be build
+# and/or deployed
+#
+#
+# COMMENTS:
+#
+##################################################################
+AUTOMAKE_OPTIONS = foreign
+RASMGR_PORT=@RASMGR_PORT@
+RMANBASE=@abs_top_srcdir@
+
+CHECKLIMITS=@CHECKLIMITS@
+
+ACLOCAL_AMFLAGS = -I m4
+
+SUBDIRS = relblobif relindexif relmddif relcatalogif reladminif relstorageif \
+ indexmgr catalogmgr tilemgr storagemgr compression commline network \
+ raslib clientcomm servercomm rnprotocol rasodmg qlparser conversion \
+ mddmgr httpserver mymalloc time server rasmgr rascontrol rasdl \
+ applications bin insertutils manuals_and_examples
+
+dist_log_DATA=empty
+
+# excluded for the moment, contains nothing that is delivered:
+# exportutils
+
diff --git a/applications/Makefile.am b/applications/Makefile.am
new file mode 100644
index 0000000..831ab57
--- /dev/null
+++ b/applications/Makefile.am
@@ -0,0 +1,32 @@
+# -*-Makefile-*-
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+#
+# MAKEFILE FOR:
+# rasdaman applications
+# does nothing but distribute any make call into all subdirs
+#
+# COMMENTS:
+#
+##################################################################
+
+SUBDIRS=rasql
+# should also contain rview and directql
diff --git a/applications/directql/Makefile b/applications/directql/Makefile
new file mode 100644
index 0000000..8852a61
--- /dev/null
+++ b/applications/directql/Makefile
@@ -0,0 +1,89 @@
+# -*-Makefile-*-
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>. # Top Level makefile. This points to the various modules that have to be build
+# and/or deployed
+#
+# MAKEFILE FOR:
+# test programs of module servercomm
+#
+# COMMENTS:
+#
+##################################################################
+#
+# This is just an example Makefile for a test program.
+# The dependency of the test program on the lib of the
+# corresponding module is in the Makefile of the module.
+#
+
+######################### Definitions ############################
+
+# standard include with general options
+include $(RMANBASE)/Makefile.inc
+
+# all test programs
+SRCCXX= directql.cc directql_error.cc directql_signal.cc
+OBJS = ${SRCCXX:%.cc=%.o}
+ALLTESTS = ${SRCCXX:%.cc=%}
+
+# some additional flags for compiling and linking
+
+CXXFLAGS += -I$(RMANBASE)/servercomm -I$(RMANBASE)/commline
+LDFLAGS := -I$(RMANBASE)/servercomm $(LDFLAGS)
+
+# add communication flags
+CXXFLAGS += $(COMMCXXFLAGS)
+LDFLAGS += $(COMMLDFLAGS)
+
+# add compile and link options for STL
+CXXFLAGS += $(STLCXXFLAGS)
+LDFLAGS += $(STLLDFLAGS) -L$(RMANBASE)/lib
+
+########################### Targets ##############################
+
+# test target for servercomm
+.PHONY : directql
+
+directql: $(OBJS) \
+ $(QLPARSER) \
+ $(SERVERCOMM) \
+ $(CLIENTCOMM) \
+ $(CACHETAMGR) \
+ $(MDDIF) \
+ $(CATALOGIF) \
+ $(INDEXIF) \
+ $(INDEXMGR) \
+ $(BLOBIF) \
+ $(ADMINIF) \
+ $(PREPROCESSOR) \
+ $(STORAGEMGR) \
+ $(TILEMGR) \
+ $(RASLIB) \
+ $(RELINDEX) \
+ $(INDEXIF)
+ $(CXX) $(LDFLAGS) -o $@ $^ -lrasodmg $(CLIENTCOMM) -lnetwork $(QLPARSER) $(INDEXMGR) $(CACHETAMGR) $(RELINDEX) $(RELSTORAGEIF) $(RELADMINIF) $(STORAGEMGR) $(CONVERSION) $(INDEXIF) $(RELCATALOGIF) -lcommline -lpq -lecpg -lssl -lcrypto -lcrypt -lpgtypes -lm -ljpeg -ltiff -lpng -lmfhdf -ldf -lz -ldl -rdynamic -Xlinker --export-dynamic
+
+
+# general rules
+include $(RMANBASE)/Makefile.rel
+
+# automatically created dependencies
+include Makefile.dep
diff --git a/applications/directql/directql.cc b/applications/directql/directql.cc
new file mode 100644
index 0000000..98bd3ba
--- /dev/null
+++ b/applications/directql/directql.cc
@@ -0,0 +1,993 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+* rasql
+*
+* PURPOSE:
+* Provides a command line interpretter for rasql queries, with
+* options for displaying results or storing them to file(s)
+*
+* COMMENTS:
+*
+* BUGS:
+* - query filename "" is interpreted as stdin
+*/
+
+
+static const char rasql_rcsid[] = "@(#)rasql,rasql.cc: $Id: rasql.cc,v 1.3 2006/11/06 21:59:01 rasdev Exp $";
+
+#ifndef RMANVERSION
+#error "Please specify RMANVERSION variable!"
+#endif
+
+#ifndef COMPDATE
+#error "Please specify the COMPDATE variable!"
+/*
+COMPDATE=`date +"%d.%m.%Y %H:%M:%S"`
+and -DCOMPDATE="\"$(COMPDATE)\"" when compiling
+*/
+#endif
+
+#define __EXECUTABLE__
+#define EARLY_TEMPLATE
+#define DEBUG_MAIN
+#define DEBUG
+#define RMANDEBUG
+
+#include "debug.hh"
+#include "template_inst.hh"
+#include "raslib/template_inst.hh"
+
+extern char* myExecArgv0 = "";
+extern int tiling = 1;
+extern unsigned long maxTransferBufferSize = 4000000;
+extern int globalOptimizationLevel = 4;
+extern char* dbSchema = 0;
+extern int noTimeOut = 0;
+bool udfEnabled = true;
+
+//RMINITGLOBALS('C');
+
+
+#ifdef __VISUALC__
+#include <strstrea.h>
+#else
+#include <strstream>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <sstream>
+#include <fstream>
+
+using namespace std;
+
+#ifdef __VISUALC__
+ #define __EXECUTABLE__
+#endif
+
+#include "rasodmg/ref.hh"
+#include "raslib/marraytype.hh"
+#include "rasodmg/set.hh"
+#include "rasodmg/marray.hh"
+#include "rasodmg/iterator.hh"
+#include "rasodmg/oqlquery.hh"
+
+#include "raslib/type.hh"
+
+#include "raslib/minterval.hh"
+
+#include "raslib/primitive.hh"
+#include "raslib/complex.hh"
+#include "raslib/structure.hh"
+
+#include "raslib/structuretype.hh"
+#include "raslib/primitivetype.hh"
+
+#include "cmlparser.hh"
+
+#include "directql_error.hh"
+
+#include "servercomm/servercomm.hh"
+
+
+#ifdef __VISUALC__
+ #undef __EXECUTABLE__
+#endif
+
+// debug facility; relies on -DDEBUG at compile time
+// tell debug that here is the place for the variables (to be done in the main() src file)
+#define DEBUG_MAIN
+#include "debug-clt.hh"
+
+const int MAX_STR_LEN = 255;
+const int MAX_QUERY_LEN = 10240;
+
+// possible types of output
+typedef enum
+{ OUT_UNDEF,
+ OUT_FILE,
+ OUT_NONE,
+ OUT_STRING,
+ OUT_HEX,
+ OUT_FORMATTED
+} OUTPUT_TYPE;
+
+// rasdaman MDD type for byte strings (default type used for file format reading)
+#define MDD_STRINGTYPE "GreyString"
+
+/// program exit codes
+#define EXIT_SUCCESS 0
+#define EXIT_USAGE 2
+#define EXIT_FAILURE -1
+
+// parameter names, defaults, and help texts
+
+#define PARAM_HELP_FLAG 'h'
+#define PARAM_HELP "help"
+#define HELP_HELP "show command line switches"
+
+#define PARAM_SERV_FLAG 's'
+#define PARAM_SERV "server"
+#define HELP_SERV "<host-name> rasdaman server"
+#define DEFAULT_SERV "localhost"
+
+#define PARAM_PORT_FLAG 'p'
+#define PARAM_PORT "port"
+#define HELP_PORT "<p> rasmgr port number"
+#define DEFAULT_PORT 5432
+#define DEFAULT_PORT_STR "5432"
+
+#define PARAM_DB_FLAG 'd'
+#define PARAM_DB "database"
+#define HELP_DB "<db-name> name of database"
+#define DEFAULT_DB "RASBASE"
+
+#define PARAM_USER "user"
+#define HELP_USER "<user-name> name of user"
+#define DEFAULT_USER "rasguest"
+
+#define PARAM_PASSWD "passwd"
+#define HELP_PASSWD "<user-passwd> password of user"
+#define DEFAULT_PASSWD "rasguest"
+
+#define PARAM_FILE_FLAG 'f'
+#define PARAM_FILE "file"
+#define HELP_FILE "<f> file name for upload through $i parameters within queries; each $i needs its own file parameter, in proper sequence. Requires --mdddomain and --mddtype"
+
+#define PARAM_DOMAIN "mdddomain"
+#define HELP_DOMAIN "<mdd-domain> domain of marray, format: \'[x0:x1,y0:y1]\' (required only if --file specified and file is in data format r_Array)"
+
+#define PARAM_MDDTYPE "mddtype"
+// this is for display only; internally MDD_STRINGTYPE is used
+#define DEFAULT_MDDTYPE "byte string"
+#define HELP_MDDTYPE "<mdd-type> type of marray (required only if --file specified and file is in data format r_Array)"
+
+#define PARAM_QUERY_FLAG 'q'
+#define PARAM_QUERY "query"
+#define HELP_QUERY "<q> query string to be sent to the rasdaman server for execution"
+
+#define PARAM_OUT "out"
+#define HELP_OUT "<t> use display method t for cell values of result MDDs where t is one of none, file, formatted, string, hex. Implies --content"
+#define DEFAULT_OUT OUT_NONE
+#define PARAM_OUT_FILE "file"
+#define PARAM_OUT_STRING "string"
+#define PARAM_OUT_HEX "hex"
+#define PARAM_OUT_FORMATTED "formatted"
+#define PARAM_OUT_NONE "none"
+#define DEFAULT_OUT_STR PARAM_OUT_NONE
+
+#define PARAM_CONTENT "content"
+#define HELP_CONTENT "display result, if any (see also --out and --type for output formatting)"
+
+#define PARAM_TYPE "type"
+#define HELP_TYPE "display type information for results"
+
+#define PARAM_OUTFILE_FLAG 'o'
+#define PARAM_OUTFILE "outfile"
+#define HELP_OUTFILE "<of> file name template for storing result images (ignored for scalar results). Use '%d' to indicate auto numbering position, like with printf(1). For well-known file types, a proper suffix is appended to the resulting file name. Implies --out file."
+#define DEFAULT_OUTFILE "rasql_%d"
+
+#define PARAM_QUIET "quiet"
+#define HELP_QUIET "print no ornament messages, only results and errors"
+
+#define PARAM_DEBUG "debug"
+#define HELP_DEBUG "generate diagnostic output"
+
+
+char globalConnectId[255] = {0};
+ServerComm *server;
+
+// global variables and default settings
+// -------------------------------------
+
+bool dbIsOpen = false;
+bool taIsOpen = false;
+
+DatabaseIf database;
+TransactionIf ta;
+
+// suppress regular messages in log? (cmd line parameter '--quiet')
+bool quietLog = false;
+// logging mechanism that respects 'quiet' flag:
+#define LOG(a) { if (!quietLog) std::cout << a; }
+
+int optionValueIndex=0;
+
+const char *serverName = DEFAULT_SERV;
+r_ULong serverPort = DEFAULT_PORT;
+const char *baseName = DEFAULT_DB;
+
+const char *user = DEFAULT_USER;
+const char *passwd = DEFAULT_PASSWD;
+
+const char *fileName = NULL;
+const char *queryString=NULL;
+
+bool output = false;
+bool displayType = false;
+
+OUTPUT_TYPE outputType = DEFAULT_OUT;
+
+const char *outFileMask = DEFAULT_OUTFILE;
+
+r_Minterval mddDomain;
+bool mddDomainDef = false;
+
+const char* mddTypeName = NULL;
+bool mddTypeNameDef = false;
+
+// query result set.
+// we define it here because on empty results the set seems to be corrupt which kills the default destructor
+r_Set< r_Ref_Any > result_set;
+
+// end of globals
+
+void
+parseParams(int argc, char** argv) throw (RasqlError, r_Error)
+{
+ CommandLineParser &cmlInter = CommandLineParser::getInstance();
+
+ CommandLineParameter &clp_help = cmlInter.addFlagParameter( PARAM_HELP_FLAG, PARAM_HELP, HELP_HELP );
+
+ CommandLineParameter &clp_query = cmlInter.addStringParameter(PARAM_QUERY_FLAG, PARAM_QUERY, HELP_QUERY );
+ CommandLineParameter &clp_file = cmlInter.addStringParameter(PARAM_FILE_FLAG, PARAM_FILE, HELP_FILE );
+
+ CommandLineParameter &clp_content = cmlInter.addFlagParameter( CommandLineParser::noShortName, PARAM_CONTENT, HELP_CONTENT );
+ CommandLineParameter &clp_out = cmlInter.addStringParameter( CommandLineParser::noShortName, PARAM_OUT, HELP_OUT, DEFAULT_OUT_STR );
+ CommandLineParameter &clp_outfile = cmlInter.addStringParameter( CommandLineParser::noShortName, PARAM_OUTFILE, HELP_OUTFILE, DEFAULT_OUTFILE );
+ CommandLineParameter &clp_mddDomain = cmlInter.addStringParameter( CommandLineParser::noShortName, PARAM_DOMAIN, HELP_DOMAIN );
+ CommandLineParameter &clp_mddType = cmlInter.addStringParameter( CommandLineParser::noShortName, PARAM_MDDTYPE, HELP_MDDTYPE, DEFAULT_MDDTYPE );
+ CommandLineParameter &clp_type = cmlInter.addFlagParameter( CommandLineParser::noShortName, PARAM_TYPE, HELP_TYPE );
+
+ CommandLineParameter &clp_server = cmlInter.addStringParameter( PARAM_SERV_FLAG, PARAM_SERV, HELP_SERV, DEFAULT_SERV );
+ CommandLineParameter &clp_port = cmlInter.addStringParameter( PARAM_PORT_FLAG, PARAM_PORT, HELP_PORT, DEFAULT_PORT_STR);
+ CommandLineParameter &clp_database = cmlInter.addStringParameter( PARAM_DB_FLAG, PARAM_DB, HELP_DB, DEFAULT_DB );
+ CommandLineParameter &clp_user = cmlInter.addStringParameter(CommandLineParser::noShortName, PARAM_USER, HELP_USER, DEFAULT_USER );
+ CommandLineParameter &clp_passwd = cmlInter.addStringParameter(CommandLineParser::noShortName, PARAM_PASSWD, HELP_PASSWD, DEFAULT_PASSWD );
+ CommandLineParameter &clp_quiet = cmlInter.addFlagParameter(CommandLineParser::noShortName, PARAM_QUIET, HELP_QUIET );
+
+#ifdef DEBUG
+ CommandLineParameter &clp_debug = cmlInter.addFlagParameter( CommandLineParser::noShortName, PARAM_DEBUG, HELP_DEBUG );
+#endif
+
+ try
+ {
+ cmlInter.processCommandLine(argc, argv);
+
+ if (cmlInter.isPresent( PARAM_HELP_FLAG ) || argc == 1)
+ {
+ cout << "usage: " << argv[0] << " [--query querystring|-q querystring] [options]" << endl;
+ cout << "options:" << endl;
+ cmlInter.printHelp();
+ exit( EXIT_USAGE ); // FIXME: exit no good style!!
+ }
+
+ // check mandatory parameters ====================================================
+
+ // evaluate mandatory parameter collection --------------------------------------
+ if (cmlInter.isPresent( PARAM_QUERY ))
+ queryString = cmlInter.getValueAsString( PARAM_QUERY );
+ else
+ throw RasqlError( NOQUERY );
+
+ // check optional parameters ====================================================
+
+ // evaluate optional parameter file --------------------------------------
+ if (cmlInter.isPresent( PARAM_FILE ))
+ fileName = cmlInter.getValueAsString( PARAM_FILE );
+
+ // evaluate optional parameter server --------------------------------------
+ if (cmlInter.isPresent( PARAM_SERV ))
+ serverName = cmlInter.getValueAsString( PARAM_SERV );
+
+ // evaluate optional parameter port --------------------------------------
+ if (cmlInter.isPresent( PARAM_PORT ))
+ serverPort = cmlInter.getValueAsLong( PARAM_PORT );
+
+ // evaluate optional parameter database --------------------------------------
+ if (cmlInter.isPresent( PARAM_DB ))
+ baseName = cmlInter.getValueAsString( PARAM_DB );
+
+ // evaluate optional parameter user --------------------------------------
+ if (cmlInter.isPresent( PARAM_USER ))
+ user = cmlInter.getValueAsString( PARAM_USER );
+
+ // evaluate optional parameter passwd --------------------------------------
+ if (cmlInter.isPresent( PARAM_PASSWD ))
+ passwd = cmlInter.getValueAsString( PARAM_PASSWD );
+
+ // evaluate optional parameter content --------------------------------------
+ if (cmlInter.isPresent( PARAM_CONTENT ))
+ output = true;
+
+ // evaluate optional parameter type --------------------------------------
+ if (cmlInter.isPresent( PARAM_TYPE ))
+ displayType = true;
+
+ // evaluate optional parameter hex --------------------------------------
+ if (cmlInter.isPresent( PARAM_OUT ))
+ {
+ output = true;
+ const char* val = cmlInter.getValueAsString( PARAM_OUT );
+ if (val !=0 && strcmp( val, PARAM_OUT_STRING ) == 0)
+ outputType = OUT_STRING;
+ else if (val !=0 && strcmp( val, PARAM_OUT_FILE ) == 0)
+ outputType = OUT_FILE;
+ else if (val !=0 && strcmp( val, PARAM_OUT_FORMATTED ) == 0)
+ outputType = OUT_FORMATTED;
+ else if (val !=0 && strcmp( val, PARAM_OUT_HEX ) == 0)
+ outputType = OUT_HEX;
+ else if (val !=0 && strcmp( val, PARAM_OUT_NONE ) == 0)
+ outputType = OUT_NONE;
+ else
+ throw RasqlError( ILLEGALOUTPUTTYPE );
+ }
+
+ // evaluate optional parameter outfile --------------------------------------
+ if (cmlInter.isPresent( PARAM_OUTFILE ))
+ {
+ outFileMask = cmlInter.getValueAsString( PARAM_OUTFILE );
+ outputType = OUT_FILE;
+ }
+
+ // evaluate optional parameter domain --------------------------------------
+ if ( cmlInter.isPresent( PARAM_DOMAIN ) )
+ {
+ try
+ {
+ mddDomain = r_Minterval(cmlInter.getValueAsString( PARAM_DOMAIN ));
+ mddDomainDef = true;
+ }
+ catch ( r_Error& e ) // Minterval constructor had syntax problems
+ {
+ throw RasqlError( NOVALIDDOMAIN );
+ }
+ }
+
+ // evaluate optional parameter MDD type name --------------------------------------
+ if (cmlInter.isPresent( PARAM_MDDTYPE ))
+ {
+ mddTypeName = cmlInter.getValueAsString( PARAM_MDDTYPE );
+ mddTypeNameDef = true;
+ }
+
+ // evaluate optional parameter 'quiet' --------------------------------------------
+ if (cmlInter.isPresent( PARAM_QUIET ))
+ {
+ quietLog = true;
+ }
+
+#ifdef DEBUG
+ // evaluate optional parameter MDD type name --------------------------------------
+ SET_OUTPUT( cmlInter.isPresent( PARAM_DEBUG ) );
+#endif
+
+ }
+ catch(CmlException& err)
+ {
+ cerr << err.what() << endl;
+ throw RasqlError( ERRORPARSINGCOMMANDLINE );
+ }
+} // parseParams()
+
+
+void
+openDatabase() throw (r_Error)
+{
+ ENTER( "openDatabase" );
+
+ if (! dbIsOpen)
+ {
+ LOG( "opening database " << baseName << " at " << serverName << ":" << serverPort << "..." << flush );
+ //
+ sprintf(globalConnectId, "tcp:postgresql://%s:%d/%s", serverName, serverPort, baseName);
+ //strcpy(globalConnectId, "tcp:postgresql://$serverName:$serverPort/$baseName");
+ printf("conn = %s\n", globalConnectId);
+
+ server = new ServerComm(300, 120, 7013, "rasmgr", 7001, "N1");
+
+
+ AdminIf* myAdmin = AdminIf::instance();
+ database.open( "RASSERVICE");
+
+ //ta.begin( &database );
+
+ ServerComm::ClientTblElt *r = new ServerComm::ClientTblElt("testclient", 2);
+ server->addClientTblEntry (r);
+ accessControl.setServerName("NT1");
+ accessControl.crunchCapability("$I1$ER.$BRASBASE$T1:3:2008:23:39:24$NNT1$D983893f406445a922cba0301bc5a85ec$K");
+ server->openDB(2, "RASBASE", "costea");
+ SET_OUTPUT(TRUE);
+
+ TALK( "ok" );
+ dbIsOpen = true;
+ LOG( "ok" << endl << flush );
+ }
+
+ LEAVE( "openDatabase" );
+} // openDatabase()
+
+void
+closeDatabase() throw (r_Error)
+{
+ ENTER( "closeDatabase" );
+
+ if (dbIsOpen)
+ {
+ TALK( "database was open, closing it" );
+ dbIsOpen = false;
+ }
+
+ LEAVE( "closeDatabase" );
+ return;
+} // closeDatabase()
+
+void
+openTransaction(bool readwrite) throw (r_Error)
+{
+ ENTER( "openTransaction, readwrite=" << (readwrite ? "rw" : "ro" ) );
+
+ if (! taIsOpen)
+ {
+ if (readwrite)
+ {
+ TALK( "transaction was closed, opening rw..." );
+ ta.begin(&database);
+ TALK( "ok" );
+ }
+ else
+ {
+ TALK( "transaction was closed, opening ro..." );
+ ta.begin(&database);
+ TALK( "ok" );
+ }
+
+ taIsOpen = true;
+ }
+
+ LEAVE( "openTransaction" );
+} // openTransaction()
+
+void
+closeTransaction( bool doCommit ) throw (r_Error)
+{
+ ENTER( "closeTransaction, doCommit=" << doCommit );
+
+ if (taIsOpen)
+ {
+ if (doCommit)
+ {
+ TALK( "transaction was open, committing it..." );
+ ta.commit();
+ TALK( "ok" );
+ }
+ else
+ {
+ TALK( "transaction was open, aborting it..." );
+ ta.abort();
+ TALK( "ok" );
+ }
+ taIsOpen = false;
+ }
+
+ LEAVE( "closeTransaction" );
+ return;
+} // closeTransaction()
+
+void printScalar( const r_Scalar& scalar )
+{
+ ENTER( "printScalar" );
+
+ switch( scalar.get_type()->type_id() )
+ {
+ case r_Type::BOOL:
+ LOG( ( ((r_Primitive*)&scalar)->get_boolean() ? "t" : "f" ) << flush );
+ break;
+
+ case r_Type::CHAR:
+ LOG( (int)((r_Primitive*)&scalar)->get_char() << flush );
+ break;
+
+ case r_Type::OCTET:
+ LOG( (int)((r_Primitive*)&scalar)->get_octet() << flush );
+ break;
+
+ case r_Type::SHORT:
+ LOG( ((r_Primitive*)&scalar)->get_short() << flush );
+ break;
+
+ case r_Type::USHORT:
+ LOG( ((r_Primitive*)&scalar)->get_ushort() << flush );
+ break;
+
+ case r_Type::LONG:
+ LOG( ((r_Primitive*)&scalar)->get_long() << flush );
+ break;
+
+ case r_Type::ULONG:
+ LOG( ((r_Primitive*)&scalar)->get_ulong() << flush );
+ break;
+
+ case r_Type::FLOAT:
+ LOG( ((r_Primitive*)&scalar)->get_float() << flush );
+ break;
+
+ case r_Type::DOUBLE:
+ LOG( ((r_Primitive*)&scalar)->get_double() << flush );
+ break;
+
+ case r_Type::COMPLEXTYPE1:
+ case r_Type::COMPLEXTYPE2:
+ LOG( "(" << ((r_Complex*)&scalar)->get_re() << "," << ((r_Complex*)&scalar)->get_im() << ")" << flush );
+ break;
+
+ case r_Type::STRUCTURETYPE:
+ {
+ r_Structure* structValue = (r_Structure*)&scalar;
+ LOG( "{ " << flush );
+ for( int i=0; i<structValue->count_elements(); i++ )
+ {
+ printScalar( (*structValue)[i] );
+ if( i < structValue->count_elements()-1 )
+ LOG( ", " << flush );
+ }
+ LOG( " }" << endl );
+ }
+ break;
+ default:
+ LOG( "scalar type " << scalar.get_type()->type_id() << " not supported!" << endl );
+ break;
+ }
+ LEAVE( "printScalar" );
+} // printScalar()
+
+
+// result_set should be parameter, but is global -- see def for reason
+void printResult( r_Minterval &mddDomain, char* &typeName,
+ char* &typeStructure,
+ r_OId &oid,
+ unsigned short &currentFormat)
+{
+ ENTER( "printResult" );
+
+ if (displayType)
+ {
+ cout << " Oid...................: " << oid << endl;
+ cout << " Type Structure........: "
+ << ( typeStructure ? typeStructure : "<nn>" ) << endl;
+ cout << endl;
+ }
+
+ /* The following can be used if the type is known and the element type is not atomic.
+
+ r_Set< r_Ref< r_Point > >* set2 = (r_Set< r_Ref< r_Point > >*)&result_set;
+ r_Iterator< r_Ref<r_Point> > iter2 = set2->create_iterator();
+ for( iter2.reset(); iter2.not_done(); iter2++ )
+ cout << **iter2 << endl;
+ */
+
+ r_Iterator< r_Ref_Any > iter = result_set.create_iterator();
+ // iter.not_done() seems to behave wrongly on empty set, therefore this additional check -- PB 2003-aug-16
+ for ( int i=1 ; i<=result_set.cardinality() && iter.not_done(); iter++, i++ )
+ {
+ switch( result_set.get_element_type_schema()->type_id() )
+ {
+ case r_Type::MARRAYTYPE:
+ switch ( outputType )
+ {
+ case OUT_NONE:
+ break;
+ case OUT_STRING:
+ {
+ int numCells = r_Ref<r_GMarray>(*iter)->get_array_size();
+ const char* theStuff = r_Ref<r_GMarray>(*iter)->get_array();
+ LOG( " Result object " << i << ": " );
+ for (int cnt = 0; cnt < numCells; cnt++)
+ cout << theStuff[cnt];
+ cout << endl;
+ }
+ break;
+ case OUT_HEX:
+ {
+ int numCells = r_Ref<r_GMarray>(*iter)->get_array_size();
+ const char* theStuff = r_Ref<r_GMarray>(*iter)->get_array();
+ LOG( " Result object " << i << ": " );
+ cout << hex;
+ for (int cnt = 0; cnt < numCells; cnt++)
+ cout << setw(2) << (unsigned short) (0xff & theStuff[cnt]) << " ";
+ cout << dec << endl;
+ }
+ break;
+ case OUT_FORMATTED:
+ LOG( " Result object " << i << ":" << endl );
+ // for (int cnt = 0; cnt < numCells; cnt++)
+ printScalar( *(r_Ref<r_Scalar>(*iter)) );
+ cout << endl;
+ break;
+ case OUT_FILE:
+ {
+ char defFileName[FILENAME_MAX];
+ (void) snprintf( defFileName, sizeof(defFileName)-1, outFileMask, i );
+ TALK( "filename for #" << i << " is " << defFileName );
+
+ // special treatment only for DEFs
+ r_Data_Format mafmt = r_Ref<r_GMarray>(*iter)->get_current_format();
+ switch (mafmt)
+ {
+ case r_TIFF:
+ strcat( defFileName, ".tif" ); break;
+ case r_JPEG:
+ strcat( defFileName, ".jpg" ); break;
+ case r_HDF:
+ strcat( defFileName, ".hdf" ); break;
+ case r_PNG:
+ strcat( defFileName, ".png" ); break;
+ case r_BMP:
+ strcat( defFileName, ".bmp" ); break;
+ case r_VFF:
+ strcat( defFileName, ".vff" ); break;
+ default:
+ strcat( defFileName, ".unknown" ); break;
+ break;
+ }
+
+ LOG( " Result object " << i << ": going into file " << defFileName << "..." << flush );
+ FILE *tfile = fopen( defFileName, "wb" );
+ fwrite((void*)r_Ref<r_GMarray>(*iter)->get_array(), 1, r_Ref<r_GMarray>(*iter)->get_array_size(), tfile );
+ fclose(tfile);
+ LOG( "ok." << endl );
+ }
+ break;
+ default:
+ cerr << "Internal error: unknown output type, ignoring action: " << outputType << endl;
+ break;
+ } // switch(outputType)
+ break;
+
+ case r_Type::POINTTYPE:
+ LOG( " Result element " << i << ": " );
+ cout << *(r_Ref<r_Point>(*iter)) << endl;
+ break;
+
+ case r_Type::SINTERVALTYPE:
+ LOG( " Result element " << i << ": " );
+ cout << *(r_Ref<r_Sinterval>(*iter)) << endl;
+ break;
+
+ case r_Type::MINTERVALTYPE:
+ LOG( " Result element " << i << ": " );
+ cout << *(r_Ref<r_Minterval>(*iter)) << endl;
+ break;
+
+ case r_Type::OIDTYPE:
+ LOG( " Result element " << i << ": " );
+ cout << *(r_Ref<r_OId>(*iter)) << endl;
+ break;
+
+ default:
+ LOG( " Result element " << i << ": " << flush );
+ printScalar( *(r_Ref<r_Scalar>(*iter)) );
+ cout << endl;
+ // or simply
+ // r_Ref<r_Scalar>(*iter)->print_status( cout );
+ } // switch
+ } // for(...)
+
+ LEAVE( "printResult" );
+} // printResult()
+
+
+/*
+ * get database type structure from type name
+ * returns ptr if an MDD type with the given name exists in the database, NULL otherwise
+ * throws r_Error upon general database comm error
+ * needs an open transaction
+ */
+r_Marray_Type * getTypeFromDatabase( const char *mddTypeName ) throw(RasqlError, r_Error)
+{
+ ENTER( "getTypeFromDatabase, mddTypeName=" << mddTypeName );
+ r_Marray_Type *retval = NULL;
+ char* typeStructure = NULL;
+
+ // first, try to get type structure from database using a separate r/o transaction
+ try
+ {
+ server->getTypeStructure(2, mddTypeName, ClientComm::r_MDDType_Type, typeStructure);
+ TALK( "type structure is " << typeStructure );
+ }
+ catch (r_Error& err)
+ {
+ if (err.get_kind() == r_Error::r_Error_DatabaseClassUndefined)
+ {
+ TALK( "Type is not a well known type: " << typeStructure );
+ typeStructure = new char[strlen(mddTypeName) + 1];
+ // earlier code tried this one below, but I feel we better are strict -- PB 2003-jul-06
+ // strcpy(typeStructure, mddTypeName);
+ // TALK( "using instead: " << typeStructure );
+ throw RasqlError( MDDTYPEINVALID );
+ }
+ else // unanticipated error
+ {
+ TALK( "Error during type retrieval from database: " << err.get_errorno() << " " << err.what() );
+ throw;
+ }
+ }
+
+ // next, find out whether it is an MDD type (and not a base or set type, eg)
+ try
+ {
+ r_Type* tempType = r_Type::get_any_type(typeStructure);
+ TALK( "get_any_type() for this type returns: " << tempType );
+ if (tempType->isMarrayType())
+ {
+ retval = (r_Marray_Type*)tempType;
+ tempType = NULL;
+ TALK( "found MDD type: " << retval );
+ }
+ else
+ {
+ TALK( "type is not an marray type: " << typeStructure );
+ delete tempType;
+ tempType = NULL;
+ retval = NULL;
+ throw RasqlError( MDDTYPEINVALID );
+ }
+ }
+ catch (r_Error& err)
+ {
+ TALK( "Error during retrieval of MDD type structure (" << typeStructure << "): " << err.get_errorno() << " " << err.what() );
+ throw;
+ }
+
+ delete [] typeStructure;
+ typeStructure = NULL;
+
+ LEAVE( "getTypeFromDatabase, retval=" << retval );
+ return retval;
+} // getTypeFromDatabase()
+
+void doStuff( int argc, char** argv ) throw (r_Error)
+{
+ char *fileContents = NULL; // contents of file satisfying "$1" parameter in query
+ r_Ref<r_GMarray> fileMDD = NULL; // MDD to satisfy a "$1" parameter
+ r_Marray_Type *mddType = NULL; // this MDD's type
+
+ ENTER( "doStuff" );
+
+ r_OQL_Query query( queryString );
+ TALK( "query is: " << query.get_query() );
+
+ if ( fileName != NULL )
+ {
+ openTransaction( false );
+
+ // if no type name was specified then assume byte string (for encoded files)
+ if ( ! mddTypeNameDef )
+ mddTypeName = MDD_STRINGTYPE;
+
+ LOG( "fetching type information for " << mddTypeName << " from database, using readonly transaction..." << flush );
+ mddType = getTypeFromDatabase( mddTypeName );
+ closeTransaction( true );
+ LOG( "ok" << endl );
+
+ LOG( "reading file " << fileName << "..." << flush );
+ FILE* fileD = fopen( fileName, "r" );
+ if (fileD == NULL)
+ throw RasqlError( FILEINACCESSIBLE );
+
+ fseek( fileD, 0, SEEK_END );
+ int size = ftell( fileD );
+ TALK( "file size is " << size << " bytes" );
+ try
+ {
+ fileContents = new char[size];
+ }
+ catch(std::bad_alloc)
+ {
+ TALK( "Unable to claim memory: " << size << " Bytes" );
+ throw RasqlError( UNABLETOCLAIMRESOURCEFORFILE );
+ }
+
+ fseek( fileD, 0, SEEK_SET );
+ fread( fileContents, 1, size, fileD );
+ fclose( fileD );
+
+ // if no domain specified (this is the case with encoded files), then set to byte stream:
+ if ( ! mddDomainDef )
+ {
+ mddDomain = r_Minterval( 1 ) << r_Sinterval ( 0, size-1 );
+ TALK( "domain set to " << mddDomain );
+ }
+
+ if (size != mddDomain.cell_count() * mddType->base_type().size())
+ throw RasqlError( FILESIZEMISMATCH );
+ LOG( "ok" << endl );
+
+ TALK( "setting up MDD with domain " << mddDomain << " and base type " << mddTypeName );
+ fileMDD = new (mddTypeName) r_GMarray( mddDomain, mddType->base_type().size() );
+ fileMDD->set_type_schema( mddType );
+ fileMDD->set_array_size( mddDomain.cell_count() * mddType->base_type().size() );
+ fileMDD->set_array( fileContents );
+
+ query << *fileMDD;
+
+ TALK( "constants are:" );
+ r_Set<r_GMarray *> * myConstSet = (r_Set<r_GMarray *> *) query.get_constants();
+ r_Iterator< r_GMarray *> iter = myConstSet->create_iterator();
+ int i;
+ for ( i=1, iter.reset(); iter.not_done(); iter++, i++ )
+ {
+ r_Ref< r_GMarray > myConstant = *iter;
+ LOG( " constant " << i << ": " );
+ myConstant->print_status( cout );
+// the following can be used for sporadic debugging of input files, but beware: is very verbose!
+#if 0
+ cout << " Contents: " << hex;
+ const char *a = myConstant->get_array();
+ for (int m=0; m < myConstant->get_array_size(); m++)
+ cout << (unsigned short) (a[m] & 0xFF) << " ";
+ cout << dec << endl;
+#endif
+ }
+ }
+
+ ExecuteQueryRes result;
+
+ if( query.is_update_query() )
+ {
+ openTransaction( true );
+
+ r_Marray<r_ULong>* mddConst = NULL;
+
+ LOG( "Executing update query..." << flush );
+ server->executeQuery(2, queryString, result );
+ LOG( "ok" << endl );
+
+ if( mddConst )
+ delete mddConst;
+
+ closeTransaction( true );
+ }
+ else
+ {
+ openTransaction( false );
+
+ // should be defined here, but is global; see def for reason
+ // r_Set< r_Ref_Any > result_set;
+
+ LOG( "Executing retrieval query..." << flush );
+ int status;
+ status = server->executeQuery(2, queryString, result );
+ switch (status)
+ {
+ case 0: LOG("holds MDD elements" << endl);
+ break;
+ case 1: LOG("holds non-MDD elements" << endl);
+ break;
+ case 2: LOG("holds no elements" << endl);
+ break;
+ };
+
+ r_Minterval mddDomain;
+ char* typeName;
+ char* typeStructure;
+ r_OId oid;
+ unsigned short currentFormat;
+
+ LOG( "Getting result..." << flush );
+ if( output ) {
+ while (true) {
+ LOG( "Getting mdd..." << endl << flush );
+ status = server->getNextMDD(2, mddDomain, typeName, typeStructure, oid, currentFormat);
+ if (status==2) {
+ printf("Empty MDD\n");
+ break;
+ }
+
+ }
+ }
+ //result_set = result;
+ LOG( "ok" << endl );
+
+ closeTransaction( true );
+ }
+
+ if (fileContents != NULL)
+ delete [] fileContents;
+
+ LEAVE( "doStuff" );
+}
+
+/*
+ * returns 0 on success, -1 on error
+ */
+int main(int argc, char** argv)
+{
+ SET_OUTPUT( true ); // inhibit unconditional debug output, await cmd line evaluation
+
+ int retval = EXIT_SUCCESS; // overall result status
+
+ try
+ {
+ parseParams( argc, argv );
+
+ // put LOG after parsing parameters to respect a '--quiet'
+ LOG( argv[0] << ": rasdaman query tool v1.0, rasdaman v" << RMANVERSION/1000 << " -- generated on " << COMPDATE << "." << endl );
+
+ openDatabase();
+ doStuff( argc, argv );
+ closeDatabase();
+ retval = EXIT_SUCCESS;
+ }
+ catch (RasqlError& e)
+ {
+ cerr << argv[0] << ": " << e.what() << endl;
+ retval = EXIT_FAILURE;
+ }
+ catch (const r_Error& e)
+ {
+ cerr << "rasdaman error " << e.get_errorno() << ": " << e.what() << endl;
+ retval = EXIT_FAILURE;
+ }
+ catch (...)
+ {
+ cerr << argv[0] << ": panic: unexpected internal exception." << endl;
+ retval = EXIT_FAILURE;
+ }
+
+ if (retval != EXIT_SUCCESS && (dbIsOpen || taIsOpen) )
+ {
+ LOG( "aborting transaction..." << flush );
+ closeTransaction( false ); // abort transaction and close database, ignore any further exceptions
+ LOG( "ok" << endl );
+ closeDatabase();
+ }
+
+ LOG( argv[0] << " done." << endl );
+ return retval;
+} // main()
+
+// end of rasql.cc
+
diff --git a/applications/directql/directql_error.cc b/applications/directql/directql_error.cc
new file mode 100644
index 0000000..cba8c5e
--- /dev/null
+++ b/applications/directql/directql_error.cc
@@ -0,0 +1,119 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+* SOURCE: rasql_error.cc
+*
+* CLASS: RasqlError
+*
+* COMMENTS:
+* No comments
+*/
+
+
+using namespace std;
+
+static const char rcsid[] = "@(#)raslib, RasqlError: $Id: rasql_error.cc,v 1.1 2003/12/27 19:30:23 rasdev Exp $";
+
+#include <exception>
+#include <string>
+
+// for sprintf():
+#include <stdio.h>
+
+#include "directql_error.hh"
+
+// debug facility; relies on -DDEBUG at compile time
+#include "debug-clt.hh"
+
+/// error object, carrying int error code
+RasqlError::RasqlError( unsigned int e )
+{
+ TALK( "Exception: " << e );
+ errno = e;
+}
+
+/// default destructor
+RasqlError::~RasqlError()
+{
+}
+
+/// print error message (including error code)
+/// NB: not all messages can occur
+const char*
+RasqlError::what()
+{
+ char *errorMsg;
+ switch (errno)
+ {
+ case NOQUERY:
+ errorMsg = "Mandatory parameter '--query' missing.";
+ break;
+ case ERRORPARSINGCOMMANDLINE:
+ errorMsg = "Command line syntax error.";
+ break;
+ case ILLEGALOUTPUTTYPE:
+ errorMsg = "Illegal output type specifier, must be one of none, file, formatted, string, hex.";
+ break;
+ case FILEINACCESSIBLE:
+ errorMsg = "Cannot read input file.";
+ break;
+ case UNABLETOCLAIMRESOURCEFORFILE:
+ errorMsg = "Cannot allocate memory for file read.";
+ break;
+ case NOVALIDDOMAIN:
+ errorMsg = "Syntax error in mdddomain specification, must be [x0:x1,y0:y1] (forgot to quote or escape?)";
+ break;
+ case MDDTYPEINVALID:
+ errorMsg = "MDD type invalid.";
+ break;
+ case FILESIZEMISMATCH:
+ errorMsg = "Input file size does not correspond with MDD domain specified.";
+ break;
+ default :
+ errorMsg = "Unknown error code.";
+ break;
+ case ALLDONE:
+ case 0:
+ errorMsg = "No errors.";
+ }
+
+// size of error text buffer below
+#define ERRTEXT_BUFSIZ 200
+
+ static char errorText[ERRTEXT_BUFSIZ];
+
+// text constants for error msg
+#define MODULE_TAG "IO"
+#define ERROR_TEXT " Error: "
+
+ // check for buffer overflow
+ if (strlen(MODULE_TAG) + 3 + strlen(ERROR_TEXT) + strlen(errorMsg) + 1 > ERRTEXT_BUFSIZ)
+ sprintf( errorText, "%s%03d%s", MODULE_TAG, errno, "(error message too long, cannot display)" );
+ else
+ sprintf( errorText, "%s%03d%s%s", MODULE_TAG, errno, ERROR_TEXT, errorMsg );
+
+ return errorText;
+} // what()
+
+
diff --git a/applications/directql/directql_error.hh b/applications/directql/directql_error.hh
new file mode 100644
index 0000000..99d7c97
--- /dev/null
+++ b/applications/directql/directql_error.hh
@@ -0,0 +1,76 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+ *
+ * COMMENTS:
+ *
+ * No Comments
+*/
+
+#ifndef _RASQL_ERROR_HH_
+#define _RASQL_ERROR_HH_
+
+#ifdef __VISUALC__
+#pragma warning( disable : 4290 )
+#endif
+
+//@ManMemo: Module: {\bf raslib}
+
+/*@Doc:
+
+ This class ...
+*/
+
+
+ /// valid error codes:
+#define ALLDONE -1
+#define OK 0
+#define NOQUERY 1
+#define ERRORPARSINGCOMMANDLINE 2
+#define ILLEGALOUTPUTTYPE 3
+#define FILEINACCESSIBLE 4
+#define UNABLETOCLAIMRESOURCEFORFILE 5
+#define NOVALIDDOMAIN 6
+#define MDDTYPEINVALID 7
+#define FILESIZEMISMATCH 8
+
+class RasqlError // : public std::exception
+{
+ public:
+
+ /// constructor receiving an error number
+ RasqlError( unsigned int e );
+
+ /// destructor
+ virtual ~RasqlError();
+
+ /// get an error description
+ virtual const char * what();
+
+ private:
+ /// error information
+ unsigned int errno;
+};
+
+#endif // _RASQL_ERROR_HH_
diff --git a/applications/directql/directql_signal.cc b/applications/directql/directql_signal.cc
new file mode 100644
index 0000000..3ccdb97
--- /dev/null
+++ b/applications/directql/directql_signal.cc
@@ -0,0 +1,246 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+/* *
+ * SOURCE: rasql_globals.cc
+ *
+ * MODULE: applications/rasql
+ *
+ * PURPOSE:
+ * provide signal handling
+ *
+ * COMMENTS:
+ *
+ * No comments
+*/
+
+static const char rcsid[] = "@(#)rasodmg/test,ImportOrthoUtil: $Id: rasql_signal.cc,v 1.1 2003/12/27 19:30:23 rasdev Exp $";
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#include "raslib/template_inst.hh"
+#endif
+
+#include <iostream>
+#include <string>
+#include <iostream>
+#include <signal.h>
+#ifdef SOLARIS
+#include <strings.h>
+#endif
+
+#include "directql_error.hh"
+#include "directql_signal.hh"
+
+// debug facility; relies on -DDEBUG at compile time
+#include "debug-clt.hh"
+
+//signalCleanup function is called when a signal is received by the program.
+//You should write your function in order to have signal management
+void signalCleanup();
+
+//signalHandler function is called when a signal occurs
+void
+signalHandler(int sig);
+
+//installSignalHandlers function should be called first in main function
+//in order to receive a signal in your program
+void
+signalHandler(int sig)
+{
+ static bool handleSignal = true; // sema to prevent nested signals
+
+ cout << "Caught signal " << sig << ": ";
+ switch (sig)
+ {
+ case SIGHUP:
+ cout << "Hangup (POSIX). ";
+ break;
+ case SIGINT:
+ cout << "Interrupt (ANSI).";
+ break;
+ case SIGQUIT:
+ cout << "Quit (POSIX).";
+ break;
+ case SIGILL:
+ cout << "Illegal instruction (ANSI).";
+ break;
+ case SIGTRAP:
+ cout << "Trace trap (POSIX).";
+ break;
+ case SIGABRT:
+ cout << "Abort (ANSI) or IOT trap (4.2 BSD).";
+ break;
+ case SIGBUS:
+ cout << "BUS error (4.2 BSD).";
+ break;
+ case SIGFPE:
+ cout << "Floating-point exception (ANSI).";
+ break;
+ case SIGKILL:
+ cout << "Kill, unblockable (POSIX).";
+ break;
+ case SIGUSR1:
+ cout << "User-defined signal 1 (POSIX).";
+ break;
+ case SIGSEGV:
+ cout << "Segmentation violation (ANSI).";
+ break;
+ case SIGUSR2:
+ cout << "User-defined signal 2 (POSIX).";
+ break;
+ case SIGPIPE:
+ cout << "Broken pipe (POSIX).";
+ break;
+ case SIGALRM:
+ cout << "Alarm clock (POSIX).";
+ break;
+ case SIGTERM:
+ cout << "Termination (ANSI).";
+ break;
+#ifndef SOLARIS
+#ifndef DECALPHA
+ case SIGSTKFLT:
+ cout << "Stack fault.";
+ break;
+#endif
+#endif
+ case SIGCLD:
+ cout << "SIGCHLD (System V) or child status has changed (POSIX).";
+ break;
+ case SIGCONT:
+ cout << "Continue (POSIX).";
+ break;
+ case SIGSTOP:
+ cout << "Stop, unblockable (POSIX).";
+ break;
+ case SIGTSTP:
+ cout << "Keyboard stop (POSIX). Continuing operation.";
+ break;
+ case SIGTTIN:
+ cout << "Background read from tty (POSIX).";
+ break;
+ case SIGTTOU:
+ cout << "Background write to tty (POSIX). Continuing operation";
+ break;
+ case SIGURG:
+ cout << "Urgent condition on socket (4.2 BSD).";
+ break;
+ case SIGXCPU:
+ cout << "CPU limit exceeded (4.2 BSD).";
+ break;
+ case SIGXFSZ:
+ cout << "File size limit exceeded (4.2 BSD).";
+ break;
+ case SIGVTALRM:
+ cout << "Virtual alarm clock (4.2 BSD).";
+ break;
+ case SIGPROF:
+ cout << "Profiling alarm clock (4.2 BSD).";
+ break;
+ case SIGWINCH:
+ cout << "Window size change (4.3 BSD, Sun). Continuing operation.";
+ break;
+ case SIGPOLL:
+ cout << "Pollable event occurred (System V) or I/O now possible (4.2 BSD).";
+ break;
+ case SIGPWR:
+ cout << "Power failure restart (System V).";
+ break;
+ case SIGSYS:
+ cout << "Bad system call.";
+ break;
+ default:
+ cout << "Unknown signal.";
+ break;
+ }
+ cout << endl << flush;
+
+ // no repeated signals
+ if (handleSignal)
+ handleSignal = false;
+
+ if (sig == SIGCONT || sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU || sig == SIGWINCH)
+ return;
+ else
+ {
+ TALK( "fatal signal, exiting." << flush );
+ exit(sig);
+ }
+}
+
+void
+installSignalHandlers()
+{
+ ENTER( "installSignalHandlers" );
+
+ signal(SIGINT, signalHandler);
+ signal(SIGTERM, signalHandler);
+ signal(SIGHUP, signalHandler);
+ signal(SIGPIPE, signalHandler);
+ signal(SIGHUP, signalHandler);
+ signal(SIGINT, signalHandler);
+ signal(SIGQUIT, signalHandler);
+ signal(SIGILL, signalHandler);
+ signal(SIGTRAP, signalHandler);
+ signal(SIGABRT, signalHandler);
+ signal(SIGIOT, signalHandler);
+ signal(SIGBUS, signalHandler);
+ signal(SIGFPE, signalHandler);
+ signal(SIGKILL, signalHandler);
+ signal(SIGUSR1, signalHandler);
+ signal(SIGSEGV, signalHandler);
+ signal(SIGUSR2, signalHandler);
+ signal(SIGPIPE, signalHandler);
+ signal(SIGALRM, signalHandler);
+ signal(SIGTERM, signalHandler);
+#ifndef SOLARIS
+#ifndef DECALPHA
+ signal(SIGSTKFLT, signalHandler);
+#endif
+#endif
+ signal(SIGCLD, signalHandler);
+ signal(SIGCHLD, signalHandler);
+ signal(SIGCONT, signalHandler);
+ signal(SIGSTOP, signalHandler);
+ signal(SIGTSTP, signalHandler);
+ signal(SIGTTIN, signalHandler);
+ signal(SIGTTOU, signalHandler);
+ signal(SIGURG, signalHandler);
+ signal(SIGXCPU, signalHandler);
+ signal(SIGXFSZ, signalHandler);
+ signal(SIGVTALRM, signalHandler);
+ signal(SIGPROF, signalHandler);
+ signal(SIGWINCH, signalHandler);
+ signal(SIGPOLL, signalHandler);
+ signal(SIGIO, signalHandler);
+ signal(SIGPWR, signalHandler);
+ signal(SIGSYS, signalHandler);
+#if !defined SOLARIS
+#if !defined DECALPHA
+ signal(SIGUNUSED, signalHandler);
+#endif
+#endif
+ LEAVE( "installSignalHandlers" );
+}
+
diff --git a/applications/directql/directql_signal.hh b/applications/directql/directql_signal.hh
new file mode 100644
index 0000000..360804e
--- /dev/null
+++ b/applications/directql/directql_signal.hh
@@ -0,0 +1,50 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+/* *
+ * COMMENTS:
+ *
+ * No comments
+*/
+
+#ifndef _RASQL_SIGNAL_HH_
+#define _RASQL_SIGNAL_HH_
+
+#include <signal.h>
+
+//signalCleanup function is called when a signal is received by the program.
+//You should write your function in order to have signal management
+void signalCleanup();
+
+//signalHandler function is called when a signal occurs
+void
+signalHandler(int sig);
+
+//installSignalHandlers function should be called first in main function
+//in order to receive signal in your program
+
+void
+installSignalHandlers();
+
+#endif _RASQL_SIGNAL_HH_
+
diff --git a/applications/directql/template_inst.hh b/applications/directql/template_inst.hh
new file mode 100644
index 0000000..bed46ab
--- /dev/null
+++ b/applications/directql/template_inst.hh
@@ -0,0 +1,149 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+/* *
+* COMENTS
+*
+* No comments
+*/
+
+//for rb_tree, select1st
+#include <function.h>
+#include <tree.h>
+#include <vector>
+#include <utility>
+#include <memory>
+
+#if(__GNUC__==2 &&__GNUC_MINOR__==95)
+using std::rb_tree;
+using std::select1st;
+#else
+using __gnu_cxx::rb_tree;
+using __gnu_cxx::select1st;
+#endif
+
+using std::vector;
+using std::pair;
+
+// commented by Constantin Jucovschi (gcc 3.4+ no longer supports __default_alloc_template)
+//using std::__default_alloc_template;
+using std::fill_n;
+
+#include "qlparser/symtab.hh"
+
+#include "raslib/attribute.hh"
+#include "raslib/itertype.hh"
+#include "raslib/dlist.hh"
+
+#include "tile.hh"
+
+#include "indexmgr/keyobject.hh"
+
+#include "rasodmg/ref.hh"
+
+#include "reladminif/dbref.hh"
+#include "reladminif/dbobjectiditerator.hh"
+
+#include "relblobif/blobtile.hh"
+#include "relblobif/dbtile.hh"
+#include "relblobif/inlinetile.hh"
+
+#include "relcatalogif/typeiterator.hh"
+#include "relcatalogif/settype.hh"
+#include "relcatalogif/structtype.hh"
+#include "relcatalogif/mddtype.hh"
+#include "relcatalogif/inlineminterval.hh"
+#include "relcatalogif/dbminterval.hh"
+
+#include "relindexif/dbtcindex.hh"
+#include "relindexif/hierindex.hh"
+#include "relindexif/dbrcindexds.hh"
+
+#include "relmddif/dbmddobj.hh"
+#include "relmddif/dbmddset.hh"
+
+#include "relstorageif/dbudfds.hh"
+#include "relstorageif/dbudfpackageds.hh"
+#include "relstorageif/dbstoragelayout.hh"
+
+template class SymbolTable<int>;
+
+//template class r_IterType<r_Attribute>;
+
+template class r_Ref<r_Scalar>;
+template class r_Ref<r_OId>;
+
+template class DBRef<DBHierIndex>;
+template class DBRef<DBRCIndexDS>;
+template class DBRef<DBTCIndex>;
+template class DBRef<BLOBTile>;
+template class DBRef<DBTile>;
+template class DBRef<InlineTile>;
+template class DBRef<DBMDDSet>;
+template class DBRef<DBMinterval>;
+template class DBRef<DBStorageLayout>;
+template class DBRef<DBUDFDS>;
+template class DBRef<DBUDFPackageDS>;
+//template class DBRef<DBMDDObj>;
+// template bool operator< (const DBRef<DBMDDObj>&, const DBRef<DBMDDObj>&);
+
+//template TypeIterator<StructType>;
+//template TypeIterator<SetType>;
+template class TypeIterator<MDDType>;
+template class DBRef<DBMDDObj>;
+template class DBRef<DBObject>;
+
+template class DBObjectIdIterator<DBMDDObj>;
+template class DBObjectIterator<DBMDDObj>;
+template class DBObjectIterator<DBMDDSet>;
+template class DBObjectIterator<StructType>;
+template class DBObjectIterator<SetType>;
+template class DBRef<StructType>;
+template class DBRef<SetType>;
+template class DBRef<MDDType>;
+
+template std::ostream& operator<< (const vector<KeyObject>&, std::ostream&);
+template std::ostream& operator<< (std::ostream &, const vector<KeyObject>&);
+//template std::ostream& operator << (std::ostream& os, const std::vector<double>& list);
+//template std::ostream& operator << (std::ostream& os, const std::vector<r_Minterval>& list);
+
+template class rb_tree<OId, pair<OId const, DBMDDObj *>, select1st<pair<OId const, DBMDDObj *> >, less<OId> >;
+template class rb_tree<OId, pair<OId const, DBMinterval *>, select1st<pair<OId const, DBMinterval *> >, less<OId> >;
+template class rb_tree<OId, pair<OId const, DBRef<DBMDDObj> >, select1st<pair<OId const, DBRef<DBMDDObj> > >, less<OId> >;
+template class rb_tree<OId, pair<OId const, DBMDDSet *>, select1st<pair<OId const, DBMDDSet *> >, less<OId> >;
+template class rb_tree<OId, pair<OId const, MDDType *>, select1st<pair<OId const, MDDType *> >, less<OId> >;
+template class rb_tree<OId, pair<OId const, SetType *>, select1st<pair<OId const, SetType *> >, less<OId> >;
+template class rb_tree<OId, pair<OId const, StructType *>, select1st<pair<OId const, StructType *> >, less<OId> >;
+template class rb_tree<long, pair<long const, BLOBTile *>, select1st<pair<long const, BLOBTile *> >, less<long> >;
+template class rb_tree<long, pair<long const, InlineTile *>, select1st<pair<long const, InlineTile *> >, less<long> >;
+template class vector<BaseType const * >;
+template class vector<OId >;
+template class vector<Tile * >;
+template class vector<Type * >;
+template class vector<char * >;
+template class vector<char >;
+template class vector<r_Data_Format >;
+template class vector<unsigned int >;
+
+template class Tile ** fill_n<Tile **, unsigned int, Tile *>(Tile **, unsigned int, Tile * const &);
+
diff --git a/applications/rasql/Makefile.am b/applications/rasql/Makefile.am
new file mode 100644
index 0000000..819816f
--- /dev/null
+++ b/applications/rasql/Makefile.am
@@ -0,0 +1,70 @@
+# -*-Makefile-*-
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+#
+# MAKEFILE FOR:
+# rasql query utility
+#
+#
+# COMMENTS:
+#
+##################################################################
+
+AM_CXXFLAGS=@CLIENTCXXFLAGS@
+AM_LDFLAGS=@CLIENTLDFLAGS@
+
+bin_PROGRAMS=rasql
+rasql_SOURCES= rasql.cc rasql_error.cc rasql_error.hh \
+ rasql_signal.cc rasql_signal.hh
+rasql_LDADD = ../../rasodmg/librasodmg.a ../../clientcomm/libclientcomm.a \
+ ../../rnprotocol/libclientcomm.a\
+ ../../compression/libcompression.a ../../raslib/libraslib.a \
+ ../../conversion/libconversion.a ../../commline/libcommline.a \
+ ../../network/libnetwork.a
+
+SUBDIRS= ../../rasodmg ../../clientcomm ../../rnprotocol ../../compression \
+ ../../raslib ../../conversion ../../commline ../../network
+
+$(RECURSIVE_CLEAN_TARGETS):
+ @$(MAKE) $(AM_MAKEFLAGS) `echo $@ | sed s/-recursive/-am/`
+
+#rasql: rasql.o rasql_error.o rasql_signal.cc # $(LIBS)
+# $(PURIFY) $(CXX) $(LDFLAGS) -o rasql $^ $(LIBS) $(IMGLIBS) -lm
+
+#LIBS = $(l_SYM)rasodmg $(l_SYM)clientcomm $(l_SYM)compression $(l_SYM)raslib \
+# $(l_SYM)conversion $(l_SYM)commline $(l_SYM)network
+
+#IMGLIBS = $(l_SYM)tiff $(l_SYM)jpeg $(l_SYM)png $(l_SYM)crypto $(l_SYM)z \
+# $(l_SYM)mfhdf $(l_SYM)df $(l_SYM)netpbm
+
+#LDFLAGS += $(L_SYM)$(SUPPORT_BASE)/lib
+
+# COMPDATE must be made more general at the final destination
+# -- now done at central Makefile.inc, after integration into rasdaman
+# COMPDATE = `date +\"%d.%m.%Y %H:%M:%S\"`
+# CXXFLAGS += -DCOMPDATE="\"$(COMPDATE)\""
+
+#SRCCXX= rasql.cc rasql_error.cc rasql_signal.cc
+
+
+
+
+
diff --git a/applications/rasql/rasql.cc b/applications/rasql/rasql.cc
new file mode 100644
index 0000000..197e9fd
--- /dev/null
+++ b/applications/rasql/rasql.cc
@@ -0,0 +1,946 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+* rasql
+*
+* PURPOSE:
+* Provides a command line interpretter for rasql queries, with
+* options for displaying results or storing them to file(s)
+*
+* COMMENTS:
+*
+* BUGS:
+* - query filename "" is interpreted as stdin
+*/
+
+
+static const char rasql_rcsid[] = "@(#)rasql,rasql.cc: $Id: rasql.cc,v 1.3 2006/11/06 21:59:01 rasdev Exp $";
+
+#ifndef RMANVERSION
+#error "Please specify RMANVERSION variable!"
+#endif
+
+#ifndef COMPDATE
+#error "Please specify the COMPDATE variable!"
+/*
+COMPDATE=`date +"%d.%m.%Y %H:%M:%S"`
+and -DCOMPDATE="\"$(COMPDATE)\"" when compiling
+*/
+#endif
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#include "raslib/template_inst.hh"
+#endif
+
+#ifdef __VISUALC__
+#include <strstrea.h>
+#else
+#include <strstream>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <sstream>
+#include <fstream>
+
+using namespace std;
+
+#ifdef __VISUALC__
+ #define __EXECUTABLE__
+#endif
+
+#include "rasodmg/transaction.hh"
+#include "rasodmg/database.hh"
+
+#include "rasodmg/ref.hh"
+#include "raslib/marraytype.hh"
+#include "rasodmg/set.hh"
+#include "rasodmg/marray.hh"
+#include "rasodmg/iterator.hh"
+#include "rasodmg/oqlquery.hh"
+
+#include "raslib/type.hh"
+
+#include "raslib/minterval.hh"
+
+#include "raslib/primitive.hh"
+#include "raslib/complex.hh"
+#include "raslib/structure.hh"
+
+#include "raslib/structuretype.hh"
+#include "raslib/primitivetype.hh"
+
+#include "../../commline/cmlparser.hh"
+
+#include "rasql_error.hh"
+
+#ifdef __VISUALC__
+ #undef __EXECUTABLE__
+#endif
+
+// debug facility; relies on -DDEBUG at compile time
+// tell debug that here is the place for the variables (to be done in the main() src file)
+#define DEBUG_MAIN
+#include "debug-clt.hh"
+
+const int MAX_STR_LEN = 255;
+const int MAX_QUERY_LEN = 10240;
+
+// possible types of output
+typedef enum
+{ OUT_UNDEF,
+ OUT_FILE,
+ OUT_NONE,
+ OUT_STRING,
+ OUT_HEX,
+ OUT_FORMATTED
+} OUTPUT_TYPE;
+
+// rasdaman MDD type for byte strings (default type used for file format reading)
+#define MDD_STRINGTYPE "GreyString"
+
+#ifdef EXIT_FAILURE
+ #undef EXIT_FAILURE
+#endif
+/// program exit codes
+#define EXIT_SUCCESS 0
+#define EXIT_USAGE 2
+#define EXIT_FAILURE -1
+
+
+// parameter names, defaults, and help texts
+
+#define PARAM_HELP_FLAG 'h'
+#define PARAM_HELP "help"
+#define HELP_HELP "show command line switches"
+
+#define PARAM_SERV_FLAG 's'
+#define PARAM_SERV "server"
+#define HELP_SERV "<host-name> rasdaman server"
+#define DEFAULT_SERV "localhost"
+
+#define PARAM_PORT_FLAG 'p'
+#define PARAM_PORT "port"
+#define HELP_PORT "<p> rasmgr port number"
+#define DEFAULT_PORT 7001
+#define DEFAULT_PORT_STR "7001"
+
+#define PARAM_DB_FLAG 'd'
+#define PARAM_DB "database"
+#define HELP_DB "<db-name> name of database"
+#define DEFAULT_DB "RASBASE"
+
+#define PARAM_USER "user"
+#define HELP_USER "<user-name> name of user"
+#define DEFAULT_USER "rasguest"
+
+#define PARAM_PASSWD "passwd"
+#define HELP_PASSWD "<user-passwd> password of user"
+#define DEFAULT_PASSWD "rasguest"
+
+#define PARAM_FILE_FLAG 'f'
+#define PARAM_FILE "file"
+#define HELP_FILE "<f> file name for upload through $i parameters within queries; each $i needs its own file parameter, in proper sequence. Requires --mdddomain and --mddtype"
+
+#define PARAM_DOMAIN "mdddomain"
+#define HELP_DOMAIN "<mdd-domain> domain of marray, format: \'[x0:x1,y0:y1]\' (required only if --file specified and file is in data format r_Array)"
+
+#define PARAM_MDDTYPE "mddtype"
+// this is for display only; internally MDD_STRINGTYPE is used
+#define DEFAULT_MDDTYPE "byte string"
+#define HELP_MDDTYPE "<mdd-type> type of marray (required only if --file specified and file is in data format r_Array)"
+
+#define PARAM_QUERY_FLAG 'q'
+#define PARAM_QUERY "query"
+#define HELP_QUERY "<q> query string to be sent to the rasdaman server for execution"
+
+#define PARAM_OUT "out"
+#define HELP_OUT "<t> use display method t for cell values of result MDDs where t is one of none, file, formatted, string, hex. Implies --content"
+#define DEFAULT_OUT OUT_NONE
+#define PARAM_OUT_FILE "file"
+#define PARAM_OUT_STRING "string"
+#define PARAM_OUT_HEX "hex"
+#define PARAM_OUT_FORMATTED "formatted"
+#define PARAM_OUT_NONE "none"
+#define DEFAULT_OUT_STR PARAM_OUT_NONE
+
+#define PARAM_CONTENT "content"
+#define HELP_CONTENT "display result, if any (see also --out and --type for output formatting)"
+
+#define PARAM_TYPE "type"
+#define HELP_TYPE "display type information for results"
+
+#define PARAM_OUTFILE_FLAG 'o'
+#define PARAM_OUTFILE "outfile"
+#define HELP_OUTFILE "<of> file name template for storing result images (ignored for scalar results). Use '%d' to indicate auto numbering position, like with printf(1). For well-known file types, a proper suffix is appended to the resulting file name. Implies --out file."
+#define DEFAULT_OUTFILE "rasql_%d"
+
+#define PARAM_QUIET "quiet"
+#define HELP_QUIET "print no ornament messages, only results and errors"
+
+#define PARAM_DEBUG "debug"
+#define HELP_DEBUG "generate diagnostic output"
+
+
+// global variables and default settings
+// -------------------------------------
+
+r_Database db;
+r_Transaction ta;
+
+bool dbIsOpen = false;
+bool taIsOpen = false;
+
+// suppress regular messages in log? (cmd line parameter '--quiet')
+bool quietLog = false;
+// logging mechanism that respects 'quiet' flag:
+#define LOG(a) { if (!quietLog) std::cout << a; }
+
+int optionValueIndex=0;
+
+const char *serverName = DEFAULT_SERV;
+r_ULong serverPort = DEFAULT_PORT;
+const char *baseName = DEFAULT_DB;
+
+const char *user = DEFAULT_USER;
+const char *passwd = DEFAULT_PASSWD;
+
+const char *fileName = NULL;
+const char *queryString=NULL;
+
+bool output = false;
+bool displayType = false;
+
+OUTPUT_TYPE outputType = DEFAULT_OUT;
+
+const char *outFileMask = DEFAULT_OUTFILE;
+
+r_Minterval mddDomain;
+bool mddDomainDef = false;
+
+const char* mddTypeName = NULL;
+bool mddTypeNameDef = false;
+
+// query result set.
+// we define it here because on empty results the set seems to be corrupt which kills the default destructor
+r_Set< r_Ref_Any > result_set;
+
+// end of globals
+
+void
+parseParams(int argc, char** argv) throw (RasqlError, r_Error)
+{
+ CommandLineParser &cmlInter = CommandLineParser::getInstance();
+
+ CommandLineParameter &clp_help = cmlInter.addFlagParameter( PARAM_HELP_FLAG, PARAM_HELP, HELP_HELP );
+
+ CommandLineParameter &clp_query = cmlInter.addStringParameter(PARAM_QUERY_FLAG, PARAM_QUERY, HELP_QUERY );
+ CommandLineParameter &clp_file = cmlInter.addStringParameter(PARAM_FILE_FLAG, PARAM_FILE, HELP_FILE );
+
+ CommandLineParameter &clp_content = cmlInter.addFlagParameter( CommandLineParser::noShortName, PARAM_CONTENT, HELP_CONTENT );
+ CommandLineParameter &clp_out = cmlInter.addStringParameter( CommandLineParser::noShortName, PARAM_OUT, HELP_OUT, DEFAULT_OUT_STR );
+ CommandLineParameter &clp_outfile = cmlInter.addStringParameter( CommandLineParser::noShortName, PARAM_OUTFILE, HELP_OUTFILE, DEFAULT_OUTFILE );
+ CommandLineParameter &clp_mddDomain = cmlInter.addStringParameter( CommandLineParser::noShortName, PARAM_DOMAIN, HELP_DOMAIN );
+ CommandLineParameter &clp_mddType = cmlInter.addStringParameter( CommandLineParser::noShortName, PARAM_MDDTYPE, HELP_MDDTYPE, DEFAULT_MDDTYPE );
+ CommandLineParameter &clp_type = cmlInter.addFlagParameter( CommandLineParser::noShortName, PARAM_TYPE, HELP_TYPE );
+
+ CommandLineParameter &clp_server = cmlInter.addStringParameter( PARAM_SERV_FLAG, PARAM_SERV, HELP_SERV, DEFAULT_SERV );
+ CommandLineParameter &clp_port = cmlInter.addStringParameter( PARAM_PORT_FLAG, PARAM_PORT, HELP_PORT, DEFAULT_PORT_STR);
+ CommandLineParameter &clp_database = cmlInter.addStringParameter( PARAM_DB_FLAG, PARAM_DB, HELP_DB, DEFAULT_DB );
+ CommandLineParameter &clp_user = cmlInter.addStringParameter(CommandLineParser::noShortName, PARAM_USER, HELP_USER, DEFAULT_USER );
+ CommandLineParameter &clp_passwd = cmlInter.addStringParameter(CommandLineParser::noShortName, PARAM_PASSWD, HELP_PASSWD, DEFAULT_PASSWD );
+ CommandLineParameter &clp_quiet = cmlInter.addFlagParameter(CommandLineParser::noShortName, PARAM_QUIET, HELP_QUIET );
+
+#ifdef DEBUG
+ CommandLineParameter &clp_debug = cmlInter.addFlagParameter( CommandLineParser::noShortName, PARAM_DEBUG, HELP_DEBUG );
+#endif
+
+ try
+ {
+ cmlInter.processCommandLine(argc, argv);
+
+ if (cmlInter.isPresent( PARAM_HELP_FLAG ) || argc == 1)
+ {
+ cout << "usage: " << argv[0] << " [--query querystring|-q querystring] [options]" << endl;
+ cout << "options:" << endl;
+ cmlInter.printHelp();
+ exit( EXIT_USAGE ); // FIXME: exit no good style!!
+ }
+
+ // check mandatory parameters ====================================================
+
+ // evaluate mandatory parameter collection --------------------------------------
+ if (cmlInter.isPresent( PARAM_QUERY ))
+ queryString = cmlInter.getValueAsString( PARAM_QUERY );
+ else
+ throw RasqlError( NOQUERY );
+
+ // check optional parameters ====================================================
+
+ // evaluate optional parameter file --------------------------------------
+ if (cmlInter.isPresent( PARAM_FILE ))
+ fileName = cmlInter.getValueAsString( PARAM_FILE );
+
+ // evaluate optional parameter server --------------------------------------
+ if (cmlInter.isPresent( PARAM_SERV ))
+ serverName = cmlInter.getValueAsString( PARAM_SERV );
+
+ // evaluate optional parameter port --------------------------------------
+ if (cmlInter.isPresent( PARAM_PORT ))
+ serverPort = cmlInter.getValueAsLong( PARAM_PORT );
+
+ // evaluate optional parameter database --------------------------------------
+ if (cmlInter.isPresent( PARAM_DB ))
+ baseName = cmlInter.getValueAsString( PARAM_DB );
+
+ // evaluate optional parameter user --------------------------------------
+ if (cmlInter.isPresent( PARAM_USER ))
+ user = cmlInter.getValueAsString( PARAM_USER );
+
+ // evaluate optional parameter passwd --------------------------------------
+ if (cmlInter.isPresent( PARAM_PASSWD ))
+ passwd = cmlInter.getValueAsString( PARAM_PASSWD );
+
+ // evaluate optional parameter content --------------------------------------
+ if (cmlInter.isPresent( PARAM_CONTENT ))
+ output = true;
+
+ // evaluate optional parameter type --------------------------------------
+ if (cmlInter.isPresent( PARAM_TYPE ))
+ displayType = true;
+
+ // evaluate optional parameter hex --------------------------------------
+ if (cmlInter.isPresent( PARAM_OUT ))
+ {
+ output = true;
+ const char* val = cmlInter.getValueAsString( PARAM_OUT );
+ if (val !=0 && strcmp( val, PARAM_OUT_STRING ) == 0)
+ outputType = OUT_STRING;
+ else if (val !=0 && strcmp( val, PARAM_OUT_FILE ) == 0)
+ outputType = OUT_FILE;
+ else if (val !=0 && strcmp( val, PARAM_OUT_FORMATTED ) == 0)
+ outputType = OUT_FORMATTED;
+ else if (val !=0 && strcmp( val, PARAM_OUT_HEX ) == 0)
+ outputType = OUT_HEX;
+ else if (val !=0 && strcmp( val, PARAM_OUT_NONE ) == 0)
+ outputType = OUT_NONE;
+ else
+ throw RasqlError( ILLEGALOUTPUTTYPE );
+ }
+
+ // evaluate optional parameter outfile --------------------------------------
+ if (cmlInter.isPresent( PARAM_OUTFILE ))
+ {
+ outFileMask = cmlInter.getValueAsString( PARAM_OUTFILE );
+ outputType = OUT_FILE;
+ }
+
+ // evaluate optional parameter domain --------------------------------------
+ if ( cmlInter.isPresent( PARAM_DOMAIN ) )
+ {
+ try
+ {
+ mddDomain = r_Minterval(cmlInter.getValueAsString( PARAM_DOMAIN ));
+ mddDomainDef = true;
+ }
+ catch ( r_Error& e ) // Minterval constructor had syntax problems
+ {
+ throw RasqlError( NOVALIDDOMAIN );
+ }
+ }
+
+ // evaluate optional parameter MDD type name --------------------------------------
+ if (cmlInter.isPresent( PARAM_MDDTYPE ))
+ {
+ mddTypeName = cmlInter.getValueAsString( PARAM_MDDTYPE );
+ mddTypeNameDef = true;
+ }
+
+ // evaluate optional parameter 'quiet' --------------------------------------------
+ if (cmlInter.isPresent( PARAM_QUIET ))
+ {
+ quietLog = true;
+ }
+
+#ifdef DEBUG
+ // evaluate optional parameter MDD type name --------------------------------------
+ SET_OUTPUT( cmlInter.isPresent( PARAM_DEBUG ) );
+#endif
+
+ }
+ catch(CmlException& err)
+ {
+ cerr << err.what() << endl;
+ throw RasqlError( ERRORPARSINGCOMMANDLINE );
+ }
+} // parseParams()
+
+
+void
+openDatabase() throw (r_Error)
+{
+ ENTER( "openDatabase" );
+
+ if (! dbIsOpen)
+ {
+ LOG( "opening database " << baseName << " at " << serverName << ":" << serverPort << "..." << flush );
+ db.set_servername(serverName, serverPort);
+ db.set_useridentification(user, passwd);
+ TALK( "database was closed, opening database=" << baseName << ", server=" << serverName << ", port=" << serverPort << ", user=" << user << ", passwd=" << passwd << "..." );
+ db.open(baseName);
+ TALK( "ok" );
+ dbIsOpen = true;
+ LOG( "ok" << endl << flush );
+ }
+
+ LEAVE( "openDatabase" );
+} // openDatabase()
+
+void
+closeDatabase() throw (r_Error)
+{
+ ENTER( "closeDatabase" );
+
+ if (dbIsOpen)
+ {
+ TALK( "database was open, closing it" );
+ db.close();
+ dbIsOpen = false;
+ }
+
+ LEAVE( "closeDatabase" );
+ return;
+} // closeDatabase()
+
+void
+openTransaction(bool readwrite) throw (r_Error)
+{
+ ENTER( "openTransaction, readwrite=" << (readwrite ? "rw" : "ro" ) );
+
+ if (! taIsOpen)
+ {
+ if (readwrite)
+ {
+ TALK( "transaction was closed, opening rw..." );
+ ta.begin(r_Transaction::read_write);
+ TALK( "ok" );
+ }
+ else
+ {
+ TALK( "transaction was closed, opening ro..." );
+ ta.begin(r_Transaction::read_only);
+ TALK( "ok" );
+ }
+
+ taIsOpen = true;
+ }
+
+ LEAVE( "openTransaction" );
+} // openTransaction()
+
+void
+closeTransaction( bool doCommit ) throw (r_Error)
+{
+ ENTER( "closeTransaction, doCommit=" << doCommit );
+
+ if (taIsOpen)
+ {
+ if (doCommit)
+ {
+ TALK( "transaction was open, committing it..." );
+ ta.commit();
+ TALK( "ok" );
+ }
+ else
+ {
+ TALK( "transaction was open, aborting it..." );
+ ta.abort();
+ TALK( "ok" );
+ }
+ taIsOpen = false;
+ }
+
+ LEAVE( "closeTransaction" );
+ return;
+} // closeTransaction()
+
+void printScalar( const r_Scalar& scalar )
+{
+ ENTER( "printScalar" );
+
+ switch( scalar.get_type()->type_id() )
+ {
+ case r_Type::BOOL:
+ LOG( ( ((r_Primitive*)&scalar)->get_boolean() ? "t" : "f" ) << flush );
+ break;
+
+ case r_Type::CHAR:
+ LOG( (int)((r_Primitive*)&scalar)->get_char() << flush );
+ break;
+
+ case r_Type::OCTET:
+ LOG( (int)((r_Primitive*)&scalar)->get_octet() << flush );
+ break;
+
+ case r_Type::SHORT:
+ LOG( ((r_Primitive*)&scalar)->get_short() << flush );
+ break;
+
+ case r_Type::USHORT:
+ LOG( ((r_Primitive*)&scalar)->get_ushort() << flush );
+ break;
+
+ case r_Type::LONG:
+ LOG( ((r_Primitive*)&scalar)->get_long() << flush );
+ break;
+
+ case r_Type::ULONG:
+ LOG( ((r_Primitive*)&scalar)->get_ulong() << flush );
+ break;
+
+ case r_Type::FLOAT:
+ LOG( ((r_Primitive*)&scalar)->get_float() << flush );
+ break;
+
+ case r_Type::DOUBLE:
+ LOG( ((r_Primitive*)&scalar)->get_double() << flush );
+ break;
+
+ case r_Type::COMPLEXTYPE1:
+ case r_Type::COMPLEXTYPE2:
+ LOG( "(" << ((r_Complex*)&scalar)->get_re() << "," << ((r_Complex*)&scalar)->get_im() << ")" << flush );
+ break;
+
+ case r_Type::STRUCTURETYPE:
+ {
+ r_Structure* structValue = (r_Structure*)&scalar;
+ LOG( "{ " << flush );
+ for( int i=0; i<structValue->count_elements(); i++ )
+ {
+ printScalar( (*structValue)[i] );
+ if( i < structValue->count_elements()-1 )
+ LOG( ", " << flush );
+ }
+ LOG( " }" << endl );
+ }
+ break;
+ default:
+ LOG( "scalar type " << scalar.get_type()->type_id() << " not supported!" << endl );
+ break;
+ }
+ LEAVE( "printScalar" );
+} // printScalar()
+
+
+// result_set should be parameter, but is global -- see def for reason
+void printResult( /* r_Set< r_Ref_Any > result_set */ )
+{
+ ENTER( "printResult" );
+
+ LOG( "Query result collection has " << result_set.cardinality() << " element(s):" << endl );
+
+ if (displayType)
+ {
+ cout << " Oid...................: " << result_set.get_oid() << endl;
+ cout << " Type Structure........: "
+ << ( result_set.get_type_structure() ? result_set.get_type_structure() : "<nn>" ) << endl;
+ cout << " Type Schema...........: " << flush;
+ if( result_set.get_type_schema() )
+ result_set.get_type_schema()->print_status( cout );
+ else
+ cout << "(no name)" << flush;
+ cout << endl;
+ cout << " Number of entries.....: " << result_set.cardinality() << endl;
+ cout << " Element Type Schema...: " << flush;
+ if( result_set.get_element_type_schema() )
+ result_set.get_element_type_schema()->print_status( cout );
+ else
+ cout << "(no name)" << flush;
+ cout << endl;
+ }
+
+ /* The following can be used if the type is known and the element type is not atomic.
+
+ r_Set< r_Ref< r_Point > >* set2 = (r_Set< r_Ref< r_Point > >*)&result_set;
+ r_Iterator< r_Ref<r_Point> > iter2 = set2->create_iterator();
+ for( iter2.reset(); iter2.not_done(); iter2++ )
+ cout << **iter2 << endl;
+ */
+
+ r_Iterator< r_Ref_Any > iter = result_set.create_iterator();
+ // iter.not_done() seems to behave wrongly on empty set, therefore this additional check -- PB 2003-aug-16
+ for ( int i=1 ; i<=result_set.cardinality() && iter.not_done(); iter++, i++ )
+ {
+ switch( result_set.get_element_type_schema()->type_id() )
+ {
+ case r_Type::MARRAYTYPE:
+ switch ( outputType )
+ {
+ case OUT_NONE:
+ break;
+ case OUT_STRING:
+ {
+ int numCells = r_Ref<r_GMarray>(*iter)->get_array_size();
+ const char* theStuff = r_Ref<r_GMarray>(*iter)->get_array();
+ LOG( " Result object " << i << ": " );
+ for (int cnt = 0; cnt < numCells; cnt++)
+ cout << theStuff[cnt];
+ cout << endl;
+ }
+ break;
+ case OUT_HEX:
+ {
+ int numCells = r_Ref<r_GMarray>(*iter)->get_array_size();
+ const char* theStuff = r_Ref<r_GMarray>(*iter)->get_array();
+ LOG( " Result object " << i << ": " );
+ cout << hex;
+ for (int cnt = 0; cnt < numCells; cnt++)
+ cout << setw(2) << (unsigned short) (0xff & theStuff[cnt]) << " ";
+ cout << dec << endl;
+ }
+ break;
+ case OUT_FORMATTED:
+ LOG( " Result object " << i << ":" << endl );
+ // for (int cnt = 0; cnt < numCells; cnt++)
+ printScalar( *(r_Ref<r_Scalar>(*iter)) );
+ cout << endl;
+ break;
+ case OUT_FILE:
+ {
+ char defFileName[FILENAME_MAX];
+ (void) snprintf( defFileName, sizeof(defFileName)-1, outFileMask, i );
+ TALK( "filename for #" << i << " is " << defFileName );
+
+ // special treatment only for DEFs
+ r_Data_Format mafmt = r_Ref<r_GMarray>(*iter)->get_current_format();
+ switch (mafmt)
+ {
+ case r_TIFF:
+ strcat( defFileName, ".tif" ); break;
+ case r_JPEG:
+ strcat( defFileName, ".jpg" ); break;
+ case r_HDF:
+ strcat( defFileName, ".hdf" ); break;
+ case r_PNG:
+ strcat( defFileName, ".png" ); break;
+ case r_BMP:
+ strcat( defFileName, ".bmp" ); break;
+ case r_VFF:
+ strcat( defFileName, ".vff" ); break;
+ default:
+ strcat( defFileName, ".unknown" ); break;
+ break;
+ }
+
+ LOG( " Result object " << i << ": going into file " << defFileName << "..." << flush );
+ FILE *tfile = fopen( defFileName, "wb" );
+ fwrite((void*)r_Ref<r_GMarray>(*iter)->get_array(), 1, r_Ref<r_GMarray>(*iter)->get_array_size(), tfile );
+ fclose(tfile);
+ LOG( "ok." << endl );
+ }
+ break;
+ default:
+ cerr << "Internal error: unknown output type, ignoring action: " << outputType << endl;
+ break;
+ } // switch(outputType)
+ break;
+
+ case r_Type::POINTTYPE:
+ LOG( " Result element " << i << ": " );
+ cout << *(r_Ref<r_Point>(*iter)) << endl;
+ break;
+
+ case r_Type::SINTERVALTYPE:
+ LOG( " Result element " << i << ": " );
+ cout << *(r_Ref<r_Sinterval>(*iter)) << endl;
+ break;
+
+ case r_Type::MINTERVALTYPE:
+ LOG( " Result element " << i << ": " );
+ cout << *(r_Ref<r_Minterval>(*iter)) << endl;
+ break;
+
+ case r_Type::OIDTYPE:
+ LOG( " Result element " << i << ": " );
+ cout << *(r_Ref<r_OId>(*iter)) << endl;
+ break;
+
+ default:
+ LOG( " Result element " << i << ": " << flush );
+ printScalar( *(r_Ref<r_Scalar>(*iter)) );
+ cout << endl;
+ // or simply
+ // r_Ref<r_Scalar>(*iter)->print_status( cout );
+ } // switch
+ } // for(...)
+
+ LEAVE( "printResult" );
+} // printResult()
+
+
+/*
+ * get database type structure from type name
+ * returns ptr if an MDD type with the given name exists in the database, NULL otherwise
+ * throws r_Error upon general database comm error
+ * needs an open transaction
+ */
+r_Marray_Type * getTypeFromDatabase( const char *mddTypeName ) throw(RasqlError, r_Error)
+{
+ ENTER( "getTypeFromDatabase, mddTypeName=" << mddTypeName );
+ r_Marray_Type *retval = NULL;
+ char* typeStructure = NULL;
+
+ // first, try to get type structure from database using a separate r/o transaction
+ try
+ {
+ typeStructure = db.getComm()->getTypeStructure(mddTypeName, ClientComm::r_MDDType_Type);
+ TALK( "type structure is " << typeStructure );
+ }
+ catch (r_Error& err)
+ {
+ if (err.get_kind() == r_Error::r_Error_DatabaseClassUndefined)
+ {
+ TALK( "Type is not a well known type: " << typeStructure );
+ typeStructure = new char[strlen(mddTypeName) + 1];
+ // earlier code tried this one below, but I feel we better are strict -- PB 2003-jul-06
+ // strcpy(typeStructure, mddTypeName);
+ // TALK( "using instead: " << typeStructure );
+ throw RasqlError( MDDTYPEINVALID );
+ }
+ else // unanticipated error
+ {
+ TALK( "Error during type retrieval from database: " << err.get_errorno() << " " << err.what() );
+ throw;
+ }
+ }
+
+ // next, find out whether it is an MDD type (and not a base or set type, eg)
+ try
+ {
+ r_Type* tempType = r_Type::get_any_type(typeStructure);
+ TALK( "get_any_type() for this type returns: " << tempType );
+ if (tempType->isMarrayType())
+ {
+ retval = (r_Marray_Type*)tempType;
+ tempType = NULL;
+ TALK( "found MDD type: " << retval );
+ }
+ else
+ {
+ TALK( "type is not an marray type: " << typeStructure );
+ delete tempType;
+ tempType = NULL;
+ retval = NULL;
+ throw RasqlError( MDDTYPEINVALID );
+ }
+ }
+ catch (r_Error& err)
+ {
+ TALK( "Error during retrieval of MDD type structure (" << typeStructure << "): " << err.get_errorno() << " " << err.what() );
+ throw;
+ }
+
+ delete [] typeStructure;
+ typeStructure = NULL;
+
+ LEAVE( "getTypeFromDatabase, retval=" << retval );
+ return retval;
+} // getTypeFromDatabase()
+
+void doStuff( int argc, char** argv ) throw (r_Error)
+{
+ char *fileContents = NULL; // contents of file satisfying "$1" parameter in query
+ r_Ref<r_GMarray> fileMDD = NULL; // MDD to satisfy a "$1" parameter
+ r_Marray_Type *mddType = NULL; // this MDD's type
+
+ ENTER( "doStuff" );
+
+ r_OQL_Query query( queryString );
+ TALK( "query is: " << query.get_query() );
+
+ if ( fileName != NULL )
+ {
+ openTransaction( false );
+
+ // if no type name was specified then assume byte string (for encoded files)
+ if ( ! mddTypeNameDef )
+ mddTypeName = MDD_STRINGTYPE;
+
+ LOG( "fetching type information for " << mddTypeName << " from database, using readonly transaction..." << flush );
+ mddType = getTypeFromDatabase( mddTypeName );
+ closeTransaction( true );
+ LOG( "ok" << endl );
+
+ LOG( "reading file " << fileName << "..." << flush );
+ FILE* fileD = fopen( fileName, "r" );
+ if (fileD == NULL)
+ throw RasqlError( FILEINACCESSIBLE );
+
+ fseek( fileD, 0, SEEK_END );
+ int size = ftell( fileD );
+ TALK( "file size is " << size << " bytes" );
+ try
+ {
+ fileContents = new char[size];
+ }
+ catch(std::bad_alloc)
+ {
+ TALK( "Unable to claim memory: " << size << " Bytes" );
+ throw RasqlError( UNABLETOCLAIMRESOURCEFORFILE );
+ }
+
+ fseek( fileD, 0, SEEK_SET );
+ fread( fileContents, 1, size, fileD );
+ fclose( fileD );
+
+ // if no domain specified (this is the case with encoded files), then set to byte stream:
+ if ( ! mddDomainDef )
+ {
+ mddDomain = r_Minterval( 1 ) << r_Sinterval ( 0, size-1 );
+ TALK( "domain set to " << mddDomain );
+ }
+
+ if (size != mddDomain.cell_count() * mddType->base_type().size())
+ throw RasqlError( FILESIZEMISMATCH );
+ LOG( "ok" << endl );
+
+ TALK( "setting up MDD with domain " << mddDomain << " and base type " << mddTypeName );
+ fileMDD = new (mddTypeName) r_GMarray( mddDomain, mddType->base_type().size() );
+ fileMDD->set_type_schema( mddType );
+ fileMDD->set_array_size( mddDomain.cell_count() * mddType->base_type().size() );
+ fileMDD->set_array( fileContents );
+
+ query << *fileMDD;
+
+ TALK( "constants are:" );
+ r_Set<r_GMarray *> * myConstSet = (r_Set<r_GMarray *> *) query.get_constants();
+ r_Iterator< r_GMarray *> iter = myConstSet->create_iterator();
+ int i;
+ for ( i=1, iter.reset(); iter.not_done(); iter++, i++ )
+ {
+ r_Ref< r_GMarray > myConstant = *iter;
+ LOG( " constant " << i << ": " );
+ myConstant->print_status( cout );
+// the following can be used for sporadic debugging of input files, but beware: is very verbose!
+#if 0
+ cout << " Contents: " << hex;
+ const char *a = myConstant->get_array();
+ for (int m=0; m < myConstant->get_array_size(); m++)
+ cout << (unsigned short) (a[m] & 0xFF) << " ";
+ cout << dec << endl;
+#endif
+ }
+ }
+
+ if( query.is_update_query() )
+ {
+ openTransaction( true );
+
+ r_Marray<r_ULong>* mddConst = NULL;
+
+ LOG( "Executing update query..." << flush );
+ r_oql_execute( query );
+ LOG( "ok" << endl );
+
+ if( mddConst )
+ delete mddConst;
+
+ closeTransaction( true );
+ }
+ else
+ {
+ openTransaction( false );
+
+ // should be defined here, but is global; see def for reason
+ // r_Set< r_Ref_Any > result_set;
+
+ LOG( "Executing retrieval query..." << flush );
+ r_oql_execute( query, result_set );
+ LOG( "ok" << endl );
+
+ // generate output only if explicitly requested
+ if( output )
+ printResult( /* result_set */ );
+
+ closeTransaction( true );
+ }
+
+ if (fileContents != NULL)
+ delete [] fileContents;
+
+ LEAVE( "doStuff" );
+}
+
+/*
+ * returns 0 on success, -1 on error
+ */
+int main(int argc, char** argv)
+{
+ SET_OUTPUT( false ); // inhibit unconditional debug output, await cmd line evaluation
+
+ int retval = EXIT_SUCCESS; // overall result status
+
+ try
+ {
+ parseParams( argc, argv );
+
+ // put LOG after parsing parameters to respect a '--quiet'
+ LOG( argv[0] << ": rasdaman query tool v1.0, rasdaman v" << RMANVERSION/1000 << " -- generated on " << COMPDATE << "." << endl );
+
+ openDatabase();
+ doStuff( argc, argv );
+ closeDatabase();
+ retval = EXIT_SUCCESS;
+ }
+ catch (RasqlError& e)
+ {
+ cerr << argv[0] << ": " << e.what() << endl;
+ retval = EXIT_FAILURE;
+ }
+ catch (const r_Error& e)
+ {
+ cerr << "rasdaman error " << e.get_errorno() << ": " << e.what() << endl;
+ retval = EXIT_FAILURE;
+ }
+ catch (...)
+ {
+ cerr << argv[0] << ": panic: unexpected internal exception." << endl;
+ retval = EXIT_FAILURE;
+ }
+
+ if (retval != EXIT_SUCCESS && (dbIsOpen || taIsOpen) )
+ {
+ LOG( "aborting transaction..." << flush );
+ closeTransaction( false ); // abort transaction and close database, ignore any further exceptions
+ LOG( "ok" << endl );
+ closeDatabase();
+ }
+
+ LOG( argv[0] << " done." << endl );
+ return retval;
+} // main()
+
+// end of rasql.cc
+
diff --git a/applications/rasql/rasql_error.cc b/applications/rasql/rasql_error.cc
new file mode 100644
index 0000000..2d5f6e0
--- /dev/null
+++ b/applications/rasql/rasql_error.cc
@@ -0,0 +1,120 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+* rasqlError
+*
+* Provides a error checking for the rasql queries
+* options for storing results to file(s) or displaying them
+*
+* COMMENTS:
+*
+* No comments
+*/
+
+using namespace std;
+
+static const char rcsid[] = "@(#)raslib, RasqlError: $Id: rasql_error.cc,v 1.1 2003/12/27 19:30:23 rasdev Exp $";
+
+#include <exception>
+#include <cstring>
+
+// for sprintf():
+#include <stdio.h>
+
+#include "rasql_error.hh"
+
+// debug facility; relies on -DDEBUG at compile time
+#include "debug-clt.hh"
+
+/// error object, carrying int error code
+RasqlError::RasqlError( unsigned int e )
+{
+ TALK( "Exception: " << e );
+ errno = e;
+}
+
+/// default destructor
+RasqlError::~RasqlError()
+{
+}
+
+/// print error message (including error code)
+/// NB: not all messages can occur
+const char*
+RasqlError::what()
+{
+ const char *errorMsg;
+ switch (errno)
+ {
+ case NOQUERY:
+ errorMsg = "Mandatory parameter '--query' missing.";
+ break;
+ case ERRORPARSINGCOMMANDLINE:
+ errorMsg = "Command line syntax error.";
+ break;
+ case ILLEGALOUTPUTTYPE:
+ errorMsg = "Illegal output type specifier, must be one of none, file, formatted, string, hex.";
+ break;
+ case FILEINACCESSIBLE:
+ errorMsg = "Cannot read input file.";
+ break;
+ case UNABLETOCLAIMRESOURCEFORFILE:
+ errorMsg = "Cannot allocate memory for file read.";
+ break;
+ case NOVALIDDOMAIN:
+ errorMsg = "Syntax error in mdddomain specification, must be [x0:x1,y0:y1] (forgot to quote or escape?)";
+ break;
+ case MDDTYPEINVALID:
+ errorMsg = "MDD type invalid.";
+ break;
+ case FILESIZEMISMATCH:
+ errorMsg = "Input file size does not correspond with MDD domain specified.";
+ break;
+ default :
+ errorMsg = "Unknown error code.";
+ break;
+ case ALLDONE:
+ case 0:
+ errorMsg = "No errors.";
+ }
+
+// size of error text buffer below
+#define ERRTEXT_BUFSIZ 200
+
+ static char errorText[ERRTEXT_BUFSIZ];
+
+// text constants for error msg
+#define MODULE_TAG "IO"
+#define ERROR_TEXT " Error: "
+
+ // check for buffer overflow
+ if (strlen(MODULE_TAG) + 3 + strlen(ERROR_TEXT) + strlen(errorMsg) + 1 > ERRTEXT_BUFSIZ)
+ sprintf( errorText, "%s%03d%s", MODULE_TAG, errno, "(error message too long, cannot display)" );
+ else
+ sprintf( errorText, "%s%03d%s%s", MODULE_TAG, errno, ERROR_TEXT, errorMsg );
+
+ return errorText;
+} // what()
+
+
diff --git a/applications/rasql/rasql_error.hh b/applications/rasql/rasql_error.hh
new file mode 100644
index 0000000..cf372ab
--- /dev/null
+++ b/applications/rasql/rasql_error.hh
@@ -0,0 +1,79 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+* rasqlError
+*
+* Provides a error checking for rasql queries
+*
+* COMMENTS:
+*
+* No Comments
+*/
+
+#ifndef _RASQL_ERROR_HH_
+#define _RASQL_ERROR_HH_
+
+#ifdef __VISUALC__
+#pragma warning( disable : 4290 )
+#endif
+
+//@ManMemo: Module: {\bf raslib}
+
+/*@Doc:
+
+ This class ...
+*/
+
+
+ /// valid error codes:
+#define ALLDONE -1
+#define OK 0
+#define NOQUERY 1
+#define ERRORPARSINGCOMMANDLINE 2
+#define ILLEGALOUTPUTTYPE 3
+#define FILEINACCESSIBLE 4
+#define UNABLETOCLAIMRESOURCEFORFILE 5
+#define NOVALIDDOMAIN 6
+#define MDDTYPEINVALID 7
+#define FILESIZEMISMATCH 8
+
+class RasqlError // : public std::exception
+{
+ public:
+
+ /// constructor receiving an error number
+ RasqlError( unsigned int e );
+
+ /// destructor
+ virtual ~RasqlError();
+
+ /// get an error description
+ virtual const char * what();
+
+ private:
+ /// error information
+ unsigned int errno;
+};
+
+#endif // _RASQL_ERROR_HH_
diff --git a/applications/rasql/rasql_signal.cc b/applications/rasql/rasql_signal.cc
new file mode 100644
index 0000000..49ce7d4
--- /dev/null
+++ b/applications/rasql/rasql_signal.cc
@@ -0,0 +1,244 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+* rasql_signal
+*
+* PURPOSE: Provides signal handling
+*
+* COMMENTS:
+*
+* No comments
+*/
+
+
+static const char rcsid[] = "@(#)rasodmg/test,ImportOrthoUtil: $Id: rasql_signal.cc,v 1.1 2003/12/27 19:30:23 rasdev Exp $";
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#include "raslib/template_inst.hh"
+#endif
+
+#include <iostream>
+#include <string>
+#include <iostream>
+#include <signal.h>
+#ifdef SOLARIS
+#include <strings.h>
+#endif
+
+#include "rasql_error.hh"
+#include "rasql_signal.hh"
+
+// debug facility; relies on -DDEBUG at compile time
+#include "debug-clt.hh"
+
+//signalCleanup function is called when a signal is received by the program.
+//You should write your function in order to have signal management
+void signalCleanup();
+
+//signalHandler function is called when a signal occurs
+void
+signalHandler(int sig);
+
+//installSignalHandlers function should be called first in main function
+//in order to receive a signal in your program
+void
+signalHandler(int sig)
+{
+ static bool handleSignal = true; // sema to prevent nested signals
+
+ cout << "Caught signal " << sig << ": ";
+ switch (sig)
+ {
+ case SIGHUP:
+ cout << "Hangup (POSIX). ";
+ break;
+ case SIGINT:
+ cout << "Interrupt (ANSI).";
+ break;
+ case SIGQUIT:
+ cout << "Quit (POSIX).";
+ break;
+ case SIGILL:
+ cout << "Illegal instruction (ANSI).";
+ break;
+ case SIGTRAP:
+ cout << "Trace trap (POSIX).";
+ break;
+ case SIGABRT:
+ cout << "Abort (ANSI) or IOT trap (4.2 BSD).";
+ break;
+ case SIGBUS:
+ cout << "BUS error (4.2 BSD).";
+ break;
+ case SIGFPE:
+ cout << "Floating-point exception (ANSI).";
+ break;
+ case SIGKILL:
+ cout << "Kill, unblockable (POSIX).";
+ break;
+ case SIGUSR1:
+ cout << "User-defined signal 1 (POSIX).";
+ break;
+ case SIGSEGV:
+ cout << "Segmentation violation (ANSI).";
+ break;
+ case SIGUSR2:
+ cout << "User-defined signal 2 (POSIX).";
+ break;
+ case SIGPIPE:
+ cout << "Broken pipe (POSIX).";
+ break;
+ case SIGALRM:
+ cout << "Alarm clock (POSIX).";
+ break;
+ case SIGTERM:
+ cout << "Termination (ANSI).";
+ break;
+#ifndef SOLARIS
+#ifndef DECALPHA
+ case SIGSTKFLT:
+ cout << "Stack fault.";
+ break;
+#endif
+#endif
+ case SIGCLD:
+ cout << "SIGCHLD (System V) or child status has changed (POSIX).";
+ break;
+ case SIGCONT:
+ cout << "Continue (POSIX).";
+ break;
+ case SIGSTOP:
+ cout << "Stop, unblockable (POSIX).";
+ break;
+ case SIGTSTP:
+ cout << "Keyboard stop (POSIX). Continuing operation.";
+ break;
+ case SIGTTIN:
+ cout << "Background read from tty (POSIX).";
+ break;
+ case SIGTTOU:
+ cout << "Background write to tty (POSIX). Continuing operation";
+ break;
+ case SIGURG:
+ cout << "Urgent condition on socket (4.2 BSD).";
+ break;
+ case SIGXCPU:
+ cout << "CPU limit exceeded (4.2 BSD).";
+ break;
+ case SIGXFSZ:
+ cout << "File size limit exceeded (4.2 BSD).";
+ break;
+ case SIGVTALRM:
+ cout << "Virtual alarm clock (4.2 BSD).";
+ break;
+ case SIGPROF:
+ cout << "Profiling alarm clock (4.2 BSD).";
+ break;
+ case SIGWINCH:
+ cout << "Window size change (4.3 BSD, Sun). Continuing operation.";
+ break;
+ case SIGPOLL:
+ cout << "Pollable event occurred (System V) or I/O now possible (4.2 BSD).";
+ break;
+ case SIGPWR:
+ cout << "Power failure restart (System V).";
+ break;
+ case SIGSYS:
+ cout << "Bad system call.";
+ break;
+ default:
+ cout << "Unknown signal.";
+ break;
+ }
+ cout << endl << flush;
+
+ // no repeated signals
+ if (handleSignal)
+ handleSignal = false;
+
+ if (sig == SIGCONT || sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU || sig == SIGWINCH)
+ return;
+ else
+ {
+ TALK( "fatal signal, exiting." << flush );
+ exit(sig);
+ }
+}
+
+void
+installSignalHandlers()
+{
+ ENTER( "installSignalHandlers" );
+
+ signal(SIGINT, signalHandler);
+ signal(SIGTERM, signalHandler);
+ signal(SIGHUP, signalHandler);
+ signal(SIGPIPE, signalHandler);
+ signal(SIGHUP, signalHandler);
+ signal(SIGINT, signalHandler);
+ signal(SIGQUIT, signalHandler);
+ signal(SIGILL, signalHandler);
+ signal(SIGTRAP, signalHandler);
+ signal(SIGABRT, signalHandler);
+ signal(SIGIOT, signalHandler);
+ signal(SIGBUS, signalHandler);
+ signal(SIGFPE, signalHandler);
+ signal(SIGKILL, signalHandler);
+ signal(SIGUSR1, signalHandler);
+ signal(SIGSEGV, signalHandler);
+ signal(SIGUSR2, signalHandler);
+ signal(SIGPIPE, signalHandler);
+ signal(SIGALRM, signalHandler);
+ signal(SIGTERM, signalHandler);
+#ifndef SOLARIS
+#ifndef DECALPHA
+ signal(SIGSTKFLT, signalHandler);
+#endif
+#endif
+ signal(SIGCLD, signalHandler);
+ signal(SIGCHLD, signalHandler);
+ signal(SIGCONT, signalHandler);
+ signal(SIGSTOP, signalHandler);
+ signal(SIGTSTP, signalHandler);
+ signal(SIGTTIN, signalHandler);
+ signal(SIGTTOU, signalHandler);
+ signal(SIGURG, signalHandler);
+ signal(SIGXCPU, signalHandler);
+ signal(SIGXFSZ, signalHandler);
+ signal(SIGVTALRM, signalHandler);
+ signal(SIGPROF, signalHandler);
+ signal(SIGWINCH, signalHandler);
+ signal(SIGPOLL, signalHandler);
+ signal(SIGIO, signalHandler);
+ signal(SIGPWR, signalHandler);
+ signal(SIGSYS, signalHandler);
+#if !defined SOLARIS
+#if !defined DECALPHA
+ signal(SIGUNUSED, signalHandler);
+#endif
+#endif
+ LEAVE( "installSignalHandlers" );
+}
+
diff --git a/applications/rasql/rasql_signal.hh b/applications/rasql/rasql_signal.hh
new file mode 100644
index 0000000..5ac67a5
--- /dev/null
+++ b/applications/rasql/rasql_signal.hh
@@ -0,0 +1,54 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+* rasql_signal
+*
+* Provides signal handling
+*
+* COMMENTS:
+*
+* No comments
+*/
+
+#ifndef _RASQL_SIGNAL_HH_
+#define _RASQL_SIGNAL_HH_
+
+#include <signal.h>
+
+//signalCleanup function is called when a signal is received by the program.
+//You should write your function in order to have signal management
+void signalCleanup();
+
+//signalHandler function is called when a signal occurs
+void
+signalHandler(int sig);
+
+//installSignalHandlers function should be called first in main function
+//in order to receive signal in your program
+
+void
+installSignalHandlers();
+
+#endif _RASQL_SIGNAL_HH_
+
diff --git a/applications/rasql/test/Makefile b/applications/rasql/test/Makefile
new file mode 100644
index 0000000..023f27c
--- /dev/null
+++ b/applications/rasql/test/Makefile
@@ -0,0 +1,66 @@
+# -*-Makefile-*-
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>. # Top Level makefile. This points to the various modules that have to be build
+# and/or deployed
+#
+
+# MAKEFILE FOR:
+# the test program for a module
+#
+# COMMENTS:
+# List environment dependencies, known bugs, specialities etc.
+#
+##################################################################
+#
+# This is just an example Makefile for a test program.
+# The dependency of the test program on the lib of the
+# corresponding module is in the Makefile of the module.
+#
+
+######################### Definitions ############################
+
+# standard include with general options
+include $(RMANBASE)/Makefile.inc
+
+# object files for test program
+TESTOBJS = test/test.o
+# name of test program
+TESTPRG = testex
+
+########################### Targets ##############################
+
+$(TESTPRG): $(TESTOBJS) $(OBJS)
+ $(CXX) $(LDFLAGS) -o $@ $^
+
+.PHONY : clean
+clean:
+ -rm $(TESTOBJS)
+ -rm $(TESTPRG)
+
+# deletes all non modified, but checked out files
+.PHONY : rcsclean
+rcsclean:
+ -rcsclean
+
+######################## Dependencies ############################
+
+test.o: $(INCDIR)/m1.hh
diff --git a/applications/rview/Makefile b/applications/rview/Makefile
new file mode 100644
index 0000000..27f894c
--- /dev/null
+++ b/applications/rview/Makefile
@@ -0,0 +1,499 @@
+# -*-Makefile-*-
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>. # Top Level makefile. This points to the various modules that have to be build
+# and/or deployed
+#
+# MAKEFILE FOR:
+# RASDAMAN rview client
+#
+# COMMENTS:
+# - does not work currently, use old .SAVE instead
+#
+##################################################################
+
+# standard include with general options
+include $(RMANBASE)/Makefile.inc
+
+# WXDIR = $(SUPPORT_BASEDIR)/wxWindows
+WXDIR = $(RMANBASE)/3rdParty/wxX11-2.4.2
+
+# Get all common compiler flags:
+ifeq ($(OSTYPE),$(OSTYPE_SOLARIS))
+ include $(WXDIR)/src/makeenvs/sol_sun.env
+endif
+
+ifeq ($(OSTYPE),$(OSTYPE_LINUX))
+# include $(WXDIR)/src/makeenvs/linux.env
+endif
+
+PIXMAPLIB = lib/libpixmap$(GUISUFFIX).a
+PIXMAPSHLIB = lib/libpixmap$(GUISUFFIX).$(SHLIBSUFF)
+
+# flags common to all Unix platforms
+#INC = -I$(WXDIR)/include/base -I$(WXDIR)/include/x
+#INC = -I$(WXDIR)/include -I$(WXDIR)/include/wx -D__WXUNIVERSAL__ -D__WXX11__ -D_FILE_OFFSET_BITS=64 -D_LARGE_FILES -DHAVE_BOOL
+INC = `wx-config --cxxflags` -DwxUSE_GLCANVAS=1
+
+RVIEW_VERSION = 2.1
+
+TIFFPATH = /usr/local/
+TIFFINC = -I$(TIFFPATH)/include
+TIFFLIBPATH = -L$(TIFFPATH)/lib
+TIFFLIB = $(TIFFLIBPATH) -ltiff
+
+# define this if you want to use the VFF convertor
+IODEFINES = -DRVIEW_USE_VFF
+
+#stuff for static link
+ifeq ($(OSTYPE),$(OSTYPE_SOLARIS))
+DYNAMICLIBS = -lXm -lXmu -lICE -lSM -lXt -lX11 -lXext -ljpeg -lcrypto
+STATICLIBS = $(SUPPORT_BASE)/lib/libwx_motif.a $(SUPPORT_BASE)/lib/libpixmap_motif.a \
+ $(SUPPORT_BASE)/lib/libtiff.a $(SUPPORT_BASE)/lib/libjpeg.a $(SUPPORT_BASE)/lib/libpng.a\
+ $(SUPPORT_BASE)/lib/libmfhdf.a $(SUPPORT_BASE)/lib/libdf.a $(SUPPORT_BASE)/lib/libz.a \
+ $(SUPPORT_BASE)/lib/libcrypto.a
+endif
+
+ifeq ($(OSTYPE),$(OSTYPE_LINUX))
+DYNAMICLIBS = -lXt -lX11 -lXp -lXext -lICE -lSM
+#STATICLIBS =$(SUPPORT_BASE)/lib/libwx_motif.a $(SUPPORT_BASE)/lib/libpixmap_motif.a -lXpm -lXm -lXmu \
+# $(SUPPORT_BASE)/lib/libtiff.a $(SUPPORT_BASE)/lib/libjpeg.a $(SUPPORT_BASE)/lib/libpng.a\
+# $(SUPPORT_BASE)/lib/libmfhdf.a $(SUPPORT_BASE)/lib/libdf.a $(SUPPORT_BASE)/lib/libz.a \
+# $(SUPPORT_BASE)/lib/libcrypto.a
+endif
+
+ifeq ($(OSTYPE),$(OSTYPE_SOLARIS))
+# Purify gets libraries wrong otherwise!
+TIFFLIB_PURE = -L. -ltiff
+SOUNDPATH = /usr/demo/SOUND
+SOUNDINC = -I$(SOUNDPATH)/include
+SOUNDLIB = -L$(SOUNDPATH)/lib -laudio
+endif
+
+LINK_LIBS = $(LDFLAGS) $(SOUNDLIB) $(LDLIBS) -lwx$(GUISUFFIX)
+#-lwx$(GUISUFFIX)
+STATICLINK_LIBS = $(LDFLAGS) $(SOUNDLIB) $(COMPLIBS) -lXm -lXmu -lXt -lX11 -lm
+#-L./lib -pthread /usr/local/lib/libwx_x11univ-2.4.a -L/usr/X11R6/lib -lX11 -lXpm -lpng -ljpeg -ltiff -ldl -lm
+
+
+# On HP: add +eh +a1 -ptb
+# Replace -DSOLARIS with -DHPUX on HP
+ifeq ($(OSTYPE),$(OSTYPE_SOLARIS))
+RVFLAGS = $(CPPFLAGS) $(CXXFLAGS) -DONCRPC -DSOLARIS $(COMPFLAGS)
+ifdef RMANGCC
+RVFLAGS += -DEARLY_TEMPLATE
+else
+RVFLAGS += -ptr$(RMANBASE)/include/ptrepository
+endif # end ifdef RMANGCC
+endif #end ifeq OSTYPE=solaris
+
+ifeq ($(OSTYPE),$(OSTYPE_LINUX))
+RVFLAGS = $(CPPFLAGS) $(CXXFLAGS) -DONCRPC -DLINUX -DEARLY_TEMPLATE $(COMPFLAGS) $(INC)
+endif
+
+# Replace -DSOLARIS on HP
+ifeq ($(OSTYPE),$(OSTYPE_SOLARIS))
+RVLINK = $(LINK_LIBS) -DONCRPC -DSOLARIS -Llib \
+ $(RASODMG) $(CLIENTCOMM) $(COMPRESSION) $(CONVERSION) $(RASLIB) -lz
+STATICRVLINK = $(STATICLINK_LIBS) -DONCRPC -DSOLARIS -Llib \
+ $(RASODMG) $(CLIENTCOMM) $(CONVERSION) $(COMPRESSION) $(RASLIB)
+endif
+ifeq ($(OSTYPE),$(OSTYPE_LINUX))
+RVLINK = $(LINK_LIBS) -DONCRPC -DLINUX -Llib -L/usr/X11R6/lib \
+ $(RASODMG) $(CLIENTCOMM) $(COMPRESSION) $(CONVERSION) $(RASLIB) -lz
+STATICRVLINK = $(STATICLINK_LIBS) -DONCRPC -DLINUX -DEARLY_TEMPLATE -Llib -L/usr/X11R6/lib \
+ $(RASODMG) $(CLIENTCOMM) $(COMPRESSION) $(CONVERSION) $(RASLIB) -lz
+endif
+
+ifneq (,$(findstring -g,$(COMPFLAGS)))
+ RVLINK += -g
+endif
+
+DEPENDFLAGS = $(RVFLAGS) $(TIFFINC) $(SOUNDINC)
+
+
+TEX_RERUN_CHECK = 'Rerun to get cross-references right'
+
+
+
+
+RVIEW_SOURCES = rview.cpp rviewChart.cpp rviewDb.cpp rviewDisplay.cpp rviewIO.cpp \
+ rviewImage.cpp rviewMDD.cpp rviewPrefs.cpp rviewQuery.cpp \
+ rviewTable.cpp rviewThumb.cpp rviewUtils.cpp rviewSound.cpp \
+ rviewTypeMan.cpp rviewColMap.cpp rviewOSection.cpp rviewApp.cpp \
+ rviewStrings.cpp neuroView.cpp neuroMeta.cpp labelManager.cpp cube_render.c
+
+BASEOBJECTS = rviewUtils.o rviewDb.o \
+ rviewPrefs.o rviewDisplay.o \
+ rviewImage.o rviewChart.o \
+ rviewTable.o rviewMDD.o \
+ rviewQuery.o rviewIO.o \
+ rviewThumb.o rviewSound.o \
+ rviewTypeMan.o rviewColMap.o \
+ rviewOSection.o rviewApp.o \
+ rviewStrings.o labelManager.o \
+ cube_render.o
+
+RVIEWOBJECTS = rview.o $(BASEOBJECTS)
+
+NVIEWOBJECTS = neuroView.o neuroMeta.o $(BASEOBJECTS)
+
+.PHONY : all
+all: # rview_static
+ # FIXME: while rview doesn't compile, use old copy
+ cp rview.SAVE rview
+ echo wx dyn lib is in /usr/local/lib/libwx_x11univ-2.4.so.0.1.1
+
+
+# Main project
+
+# Standard rView binary dynamical linked
+rview: $(RVIEWOBJECTS) $(PIXMAPLIB)
+ $(CC) -o $@ $(RVIEWOBJECTS) $(TEMPLOBJS) $(TIFFLIB) $(RVLINK) -lpixmap$(GUISUFFIX) \
+ $(RASODMG) -lcrypto
+
+test:
+ $(CC) -nodefaultlibs -o rview $(RVIEWOBJECTS) $(TEMPLOBJS) $(DYNAMICLIBS) \
+ -Xlinker -Bstatic $(STATICRVLINK) $(STATICLIBS) $(RASODMG) -lstdc++ \
+ -lwx_motif -lwxstring_motif -Xlinker -Bdynamic -lm -lgcc -lc -lgcc
+
+# Standard rView binary statical linked
+ifeq ($(OSTYPE),$(OSTYPE_LINUX))
+
+rview_static: $(RVIEWOBJECTS) $(PIXMAPLIB)
+ # $(CC) -nodefaultlibs -o rview $(RVIEWOBJECTS) $(TEMPLOBJS) $(DYNAMICLIBS) \
+ # -Xlinker -Bstatic $(STATICRVLINK) $(STATICLIBS) $(RASODMG) -lstdc++ \
+ # -Xlinker -Bdynamic -lm -lgcc -lc -lgcc
+ $(CC) -nodefaultlibs -o rview $(RVIEWOBJECTS) $(TEMPLOBJS) $(DYNAMICLIBS) \
+ -Xlinker -Bstatic $(STATICRVLINK) $(STATICLIBS) $(RASODMG) -lstdc++ \
+ -lwx_motif -lwxstring_motif -Xlinker -Bdynamic -lm -lgcc -lc -lgcc
+
+endif
+ifeq ($(OSTYPE),$(OSTYPE_SOLARIS))
+
+rview_static: $(RVIEWOBJECTS) $(PIXMAPLIB)
+ $(PURIFY) $(CC) -o rview $(RVIEWOBJECTS) $(TEMPLOBJS) $(STATICRVLINK) $(STATICLIBS)
+endif
+
+# Purified rView binary
+rview_pure: $(RVIEWOBJECTS) $(PIXMAPLIB)
+ purify $(CC) -o $@ $(RVIEWOBJECTS) $(TEMPLOBJS) $(TIFFLIB_PURE) $(RVLINK) \
+ -lpixmap$(GUISUFFIX)
+
+# Create rView source file dependencies and store them in the file rviewdepend.
+rview_depend:
+# Create all dependencies and write them to rviewdepend
+ -rm -f _rdp_
+ echo 'for i in $(RVIEW_SOURCES); do \
+ echo $$i; \
+ $(CC) -xM1 $(DEPENDFLAGS) $$i | grep "[a-zA-Z_0-9]* : [a-zA-Z_0-9]" >> _rdp_; \
+ done' | ksh
+ sort -u -o _rdps_ < _rdp_
+ cp _rdps_ Makefile.dep # sed -e 's/\</\$$\(OBJDIR\)\//' _rdps_ > Makefile.dep
+ -rm -f _rdp_ _rdps_
+
+
+# create release
+rview-release: rview_static
+ -rm rview_$(RVIEW_VERSION).tar.gz
+ -strip rview
+ tar fc rview_$(RVIEW_VERSION).tar labels.txt rview
+ gzip -9 rview_$(RVIEW_VERSION).tar
+
+# rView objects -- dependencies in separate Makefile.dep
+rview.o: rview.cpp
+ @# $(CC) -c $(RVFLAGS) -DRVIEW_VERSION=$(RVIEW_VERSION) -o $@ rview.cpp
+ g++ -c -I/home/rasdev/Compile/rasdaman -DCOMPDATE="\"`date +\"%d.%m.%Y %H:%M:%S\"`\"" -DRMANVERSION=6000 -g -DLINUX -DEARLY_TEMPLATE -DLITTLE_ENDIAN $(INC) -DRVIEW_VERSION=2.1 -o objects/rview.o rview.cpp
+
+rviewUtils.o: rviewUtils.cpp
+ $(CC) -c $(RVFLAGS) -o $@ rviewUtils.cpp
+
+rviewDb.o: rviewDb.cpp
+ $(CC) -c $(RVFLAGS) -o $@ rviewDb.cpp
+
+rviewPrefs.o: rviewPrefs.cpp
+ $(CC) -c $(RVFLAGS) -o $@ rviewPrefs.cpp
+
+rviewDisplay.o: rviewDisplay.cpp
+ $(CC) -c $(RVFLAGS) -o $@ rviewDisplay.cpp
+
+rviewImage.o: rviewImage.cpp wx_pixmap.h
+ $(CC) -c $(RVFLAGS) -o $@ rviewImage.cpp
+
+rviewChart.o: rviewChart.cpp
+ $(CC) -c $(RVFLAGS) -o $@ rviewChart.cpp
+
+rviewTable.o: rviewTable.cpp
+ $(CC) -c $(RVFLAGS) -o $@ rviewTable.cpp
+
+rviewMDD.o: rviewMDD.cpp
+ $(CC) -c $(RVFLAGS) -o $@ rviewMDD.cpp
+
+rviewQuery.o: rviewQuery.cpp
+ $(CC) -c $(RVFLAGS) -o $@ rviewQuery.cpp
+
+rviewIO.o: rviewIO.cpp wx_pixmap.h
+ $(CC) -c $(RVFLAGS) $(TIFFINC) $(IODEFINES) -o $@ rviewIO.cpp
+
+rviewThumb.o: rviewThumb.cpp wx_pixmap.h
+ $(CC) -c $(RVFLAGS) -o $@ rviewThumb.cpp
+
+rviewSound.o: rviewSound.cpp
+ $(CC) -c $(RVFLAGS) $(SOUNDINC) -o $@ rviewSound.cpp
+
+rviewTypeMan.o: rviewTypeMan.cpp
+ $(CC) -c $(RVFLAGS) -o $@ rviewTypeMan.cpp
+
+rviewColMap.o: rviewColMap.cpp wx_pixmap_translate.h
+ $(CC) -c $(RVFLAGS) -o $@ rviewColMap.cpp
+
+rviewOSection.o: rviewOSection.cpp
+ $(CC) -c $(RVFLAGS) -o $@ rviewOSection.cpp
+
+rviewApp.o: rviewApp.cpp
+ $(CC) -c $(RVFLAGS) -o $@ rviewApp.cpp
+
+rviewStrings.o: rviewStrings.cpp
+ $(CC) -c $(RVFLAGS) -o $@ rviewStrings.cpp
+
+labelManager.o: labelManager.cpp
+ $(CC) -c $(CPPFLAGS) -o $@ labelManager.cpp
+
+
+# Test program
+test_trans: test_trans.o $(PIXMAPLIB)
+ $(CC) -o $@ test_trans.o $(LINK_LIBS) \
+ -lpixmap$(GUISUFFIX)
+
+test_trans.o: test.cpp wx_pixmap.h
+ $(CC) -c $(CPPFLAGS) -o $@ test.cpp
+
+
+test_dither: test_dither.o $(PIXMAPLIB)
+ $(CC) -o $@ test_dither.o $(LINK_LIBS) \
+ -lpixmap$(GUISUFFIX)
+
+test_dither.o: test.cpp wx_pixmap.h
+ $(CC) -c $(CPPFLAGS) -o $@ test.cpp -DTEST_QUALITY='WX_PIXFLAG_TRANSLATE | WX_PIXFLAG_DITHER'
+
+
+test_render: test_render.o cube_render.o $(PIXMAPLIB)
+ $(CC) -o $@ test_render.o cube_render.o \
+ $(LINK_LIBS) -lpixmap$(GUISUFFIX)
+
+test_render.o: test.cpp cube_render.h wx_pixmap.h
+ $(CC) -c $(CPPFLAGS) -o $@ test.cpp -DTEST_RENDERER
+
+
+test_tomo: test_tomo.o cube_render.o $(PIXMAPLIB)
+ $(CC) -o $@ test_tomo.o cube_render.o \
+ $(LINK_LIBS) -lpixmap$(GUISUFFIX)
+
+test_tomo.o: test.cpp cube_render.h wx_pixmap.h
+ $(CC) -c $(CPPFLAGS) -o $@ test.cpp -DTEST_RENDERER \
+ -DSOURCE_FILE='"/home/hpwibas0/wiss/dehmel/Temp/tomo.raw"'
+
+test_drag: test_drag.o cube_render.o $(PIXMAPLIB)
+ $(CC) -o $@ test_drag.o cube_render.o \
+ $(LINK_LIBS) -lpixmap$(GUISUFFIX)
+
+test_drag.o: test.cpp cube_render.h wx_pixmap.h
+ $(CC) -c $(CPPFLAGS) -o $@ test.cpp -DTEST_RENDERER -DTEST_DRAGGING
+
+test_tdrag: test_tdrag.o cube_render.o $(PIXMAPLIB)
+ $(CC) -o $@ test_tdrag.o cube_render.o \
+ $(LINK_LIBS) -lpixmap$(GUISUFFIX)
+
+test_tdrag.o: test.cpp cube_render.h wx_pixmap.h
+ $(CC) -c $(CPPFLAGS) -o $@ test.cpp -DTEST_RENDERER -DTEST_DRAGGING \
+ -DSOURCE_FILE='"/home/hpwibas0/wiss/dehmel/Temp/tomo.raw"'
+
+
+# Standalone sound player for testing
+splayer: splayer.o
+ $(CC) -o $@ splayer.o $(SOUNDLIB)
+
+splayer.o: rviewSound.cpp rviewSound.hh
+ $(CC) -c $(RVFLAGS) $(SOUNDINC) -D__HAL_ONLY__ -o $@ rviewSound.cpp
+
+
+
+# HP targets -- obsolete
+rview_hp:
+ make rview GUISUFFIX=_hp \
+ LINK_LIBS='-L$(WXDIR)/lib $(HPLDLIBS)'
+
+rview_pure_hp:
+ make rview_pure GUISUFFIX=_hp \
+ LINK_LIBS='-L$(WXDIR)/lib $(HPLDLIBS)'
+
+test_trans_hp:
+ make test_trans GUISUFFIX=_hp \
+ LINK_LIBS='-L$(WXDIR)/lib $(HPLDLIBS)'
+
+test_dither_hp:
+ make test_dither GUISUFFIX=_hp \
+ LINK_LIBS='-L$(WXDIR)/lib $(HPLDLIBS)'
+
+test_render_hp:
+ make test_render GUISUFFIX=_hp \
+ LINK_LIBS='-L$(WXDIR)/lib $(HPLDLIBS)'
+
+test_tomo_hp:
+ make test_tomo GUISUFFIX=_hp \
+ LINK_LIBS='-L$(WXDIR)/lib $(HPLDLIBS)'
+
+test_drag_hp:
+ make test_drag GUISUFFIX=_hp \
+ LINK_LIBS='-L$(WXDIR)/lib $(HPLDLIBS)'
+
+test_tdrag_hp:
+ make test_tdrag GUISUFFIX=_hp \
+ LINK_LIBS='-L$(WXDIR)/lib $(HPLDLIBS)'
+
+
+.PHONY: clean
+clean: clean_docs
+ -rm -f client.* bclient.* core rview *.o lib/* wx_pixmap_*
+ -rm $(BASEOBJECTS) $(RVIEWOBJECTS) $(NVIEWOBJECTS)
+ifeq ($(OSTYPE),$(OSTYPE_LINUX))
+ -rm -f *.rpo
+endif
+
+
+# Main library objects
+lib:
+ -mkdir lib
+
+# Renderer C-Lib.
+cube_render.o: cube_render.c cube_render.h cube_render_core.c \
+ cube_render_line.c cube_render_voxline.c \
+ cube_render_mesh.c
+ $(CC) -c $(CFLAGS) -o $@ cube_render.c
+
+
+# Documentation; use only the targets beginning with docs*
+
+# Dependency from rview.dvi makes sure that rview.dvi is created anew when
+# rview.tex has changed. The shell-script repeats the latex runs until no
+# more label changes occur.
+docs: rview.dvi
+ # grep always throws an error :-(
+ -if [ -f rview.log ]; then \
+ rerun=`grep -c $(TEX_RERUN_CHECK) rview.log`; \
+ else \
+ rerun=1; \
+ fi; \
+ while [ "$$rerun" -ne 0 ]; do \
+ latex rview.tex; \
+ rerun=`grep -c $(TEX_RERUN_CHECK) rview.log`; \
+ done
+
+# Normal PS-output, 1:1
+docs_ps: rview.ps
+
+# 2 up landscape PS output
+docs_ps2: docs_ps rview2.ps
+
+# 2 up landscape and every other page rotated by 180 degrees (suitable for duplex printers)
+docs_ps2m: docs_ps2 rview2m.ps
+
+clean_docs:
+ -rm rview.aux rview.dvi rview.log rview*.ps
+
+
+# Don't use these targets directly
+rview.dvi: rview.tex
+ latex rview.tex
+
+rview.ps: docs
+ dvips -D600 rview.dvi
+
+rview2.ps: docs
+ -dvidvi '2:0(0in,0in),1(8in,0in)' rview.dvi rview.dvi2
+ dvips -D600 -x 667 -t landscape rview.dvi2
+ mv rview.ps rview2.ps
+ rm rview.dvi2
+
+rview2m.ps: docs_ps2
+ pstops "2:0@1.00(0cm,0cm),1U@1.00(21cm,29cm)" rview2.ps rview2m.ps
+
+
+# PIXMAP_LIBRARY for wxWindows
+# The sources consist of the regular source files wx_pixmap.cpp and
+# wx_pixmap.h and several source files automatically generated by the
+# script generate_trans.sh which creates the sources depending on
+# low-level machine specifics. Thus do not edit wx_pixmap_* by hand.
+
+PIXOBJECTS = wx_pixmap.o wx_pixmap_translate.o
+
+# The script auto-creating translation- and dithering sources.
+GENSCRIPT = generate_trans.sh
+
+# Parameters for the generating script are: (0 = lsb, 1 = msb)
+# (bitorder \in [0,1]), (byteorder \in [0,1]), (palette_fill \in [0,3])
+# palette_fill gives the format of RGB in a 32bit word, bit0 describes
+# the fill order, bit1 the colour order: 0:0bgr 1:bgr0 2:0rgb 3:rgb0
+# Use 1 1 0 for Sun Solaris, 0 0 2 for WindowsNT
+ifneq ($(OSTYPE),linux-gnu)
+GENCONFIG = 1 1 0
+else
+GENCONFIG = 0 0 2
+endif
+
+pixmaplib: $(PIXMAPLIB) $(PIXMAPSHLIB)
+
+$(PIXMAPLIB): $(PIXOBJECTS)
+ -mkdir lib
+ ar $(AROPTIONS) $@ $(PIXOBJECTS)
+ $(RANLIB) $@
+
+$(PIXMAPSHLIB): $(PIXOBJECTS)
+ -mkdir lib
+ $(BUILDSHLIB) $@ $(PIXOBJECTS)
+
+wx_pixmap.o: wx_pixmap.cpp wx_pixmap.h wx_pixmap_translate.h \
+ wx_pixmap_dither.cpp wx_pixmap_dither.h
+ $(CC) -c $(CPPFLAGS) $(INC) -o $@ wx_pixmap.cpp
+
+wx_pixmap_translate.o: wx_pixmap_translate.c wx_pixmap_translate.h
+ $(CC) -c $(CFLAGS) -o $@ wx_pixmap_translate.c
+
+wx_pixmap.h: wx_pixmap_translate.h wx_pixmap_dither.h
+
+wx_pixmap_translate.c: $(GENSCRIPT)
+ $(GENSCRIPT) $(GENCONFIG)
+
+wx_pixmap_translate.h: $(GENSCRIPT)
+ $(GENSCRIPT) $(GENCONFIG)
+
+wx_pixmap_dither.cpp: $(GENSCRIPT)
+ $(GENSCRIPT) $(GENCONFIG)
+
+wx_pixmap_dither.h: $(GENSCRIPT)
+ $(GENSCRIPT) $(GENCONFIG)
+
+# this is not appropriate here, Makefile.rel is for relational stuff! -- PB 2003-aug-29
+# general rules
+# include $(RMANBASE)/Makefile.rel
+
+# dependencies
+include Makefile.dep
diff --git a/applications/rview/cube_render.c b/applications/rview/cube_render.c
new file mode 100644
index 0000000..250afce
--- /dev/null
+++ b/applications/rview/cube_render.c
@@ -0,0 +1,3106 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+ * SOURCE: cube_render.c
+ *
+ * MODULE: applications/rview
+ *
+ * PURPOSE:
+ * Renderers for RasDaMan MDD of various base types. Renderers provided
+ * are:
+ * 3D: surface ( RenderCubeSurf() ), voxel ( RenderCubeVoxel() )
+ * 2D: height-fields ( RenderHeightField() ).
+ * Misc primitives: lines ( RenderLineSegment() ), shaded polyings using
+ * a Z-Buffer ( RenderShadedPolygon() ).
+ *
+ * This file includes cube_render_line.c, cube_render_core.c,
+ * cube_render_voxline.c and cube_render_mesh.c to build renderers
+ * for different base types.
+ *
+ * The renderer module is standalone and can be used independently
+ * from rView. In the rView project it's used by rviewImage.
+ *
+ * COMMENTS:
+ * No comments
+ *
+ * BUGS:
+ */
+
+
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <limits.h>
+#include <float.h>
+
+
+#include "cube_render.h"
+
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+/* Internally visible structs and declarations */
+
+/* 0 for LSB, 1 for MSB */
+#ifdef LITTLE_ENDIAN
+#define MACHINE_BYTE_ORDER 0
+#else
+#define MACHINE_BYTE_ORDER 1
+#endif
+
+#define FIXPOINT_PREC 16
+
+
+/* Flags used in faces */
+#define CUBE_RENDER_FACE_HIDDEN 1
+
+
+/* Set debug level */
+#ifndef CUBE_RENDER_DEBUG
+#define CUBE_RENDER_DEBUG 0
+#endif
+
+/* 8 bit values */
+typedef char int8;
+typedef unsigned char uint8;
+
+/* 16 bit values */
+typedef short int16;
+typedef unsigned short uint16;
+
+/* 32bit values */
+typedef long int32;
+typedef unsigned long uint32;
+
+/* RGB data */
+typedef struct rgb_pixel {
+ uint8 r, g, b;
+} rgb_pixel;
+
+
+
+#define MAXIMUM_SEGMENTS 7
+/*
+ * For voxel rendering: holds global and texture coordinates for one segment of a plane.
+ */
+typedef struct project_plane_intersect {
+ vertex_fp left_g;
+ vertex_fp right_g;
+ vertex_fp left_t;
+ vertex_fp right_t;
+ vertex_fp deltaLR_g;
+ vertex_fp deltaLR_t;
+ long left_p;
+ long right_p;
+} project_plane_intersect;
+
+/*
+ * For approximating the normal when voxel rendering
+ */
+typedef struct norm_kernel_desc {
+ int region;
+ real_t *kernel;
+} norm_kernel_desc;
+
+/*
+ * For voxel rendering: holds all global and texture coordinates for all segments of a
+ * plane, the number of planes, the scanline extent and additional rendering parameters.
+ */
+typedef struct project_plane_desc {
+ project_plane_intersect ppi[MAXIMUM_SEGMENTS];
+ long left_p, right_p;
+ int segs;
+ unsigned long pixelThresholdLow; /* Minimum brightness threshold. Default 4. */
+ unsigned long pixelThresholdHigh; /* Same for upper threshold. Default: type's maximum value */
+ unsigned long weightThreshold; /* Terminate depth scan when this weight is reached. Default 64 */
+ double pixelThresholdLowF; /* The same for FP types */
+ double pixelThresholdHighF;
+ double weightThresholdF;
+ int weightQuantisation; /* log2 of weight quantisation steps */
+ real_t zpro;
+ vertex_fp lights;
+ real_t lightsAmbient;
+ real_t lightsCos;
+ real_t lightsScale;
+ real_t lightsScintCos;
+ real_t lightsScintScale;
+ norm_kernel_desc *kDesc;
+ void *voxColour; /* For shading isosurfaces: each voxel gets same colour */
+} project_plane_desc;
+
+
+
+static void RenderCubeDumpFaces(const face *faces, int first, int last);
+static void RenderCubeGetScanline(int ys, int faceNo, render_desc *renderDesc, int scaleTexture);
+
+/* Surface-oriented rendering cores */
+static void RenderCubeCore1(int faceNo, render_desc *renderDesc);
+static void RenderCubeCore2(int faceNo, render_desc *renderDesc);
+static void RenderCubeCore3(int faceNo, render_desc *renderDesc);
+static void RenderCubeCore4(int faceNo, render_desc *renderDesc);
+static void RenderCubeCore8(int faceNo, render_desc *renderDesc);
+
+/* Voxel-oriented rendering cores */
+static void RenderCubeVoxLine1(int line, project_plane_desc *ppd, const render_desc *renderDesc);
+static void RenderCubeVoxLine2(int line, project_plane_desc *ppd, const render_desc *renderDesc);
+static void RenderCubeVoxLine3(int line, project_plane_desc *ppd, const render_desc *renderDesc);
+static void RenderCubeVoxLine3B(int line, project_plane_desc *ppd, const render_desc *renderDesc);
+static void RenderCubeVoxLine4(int line, project_plane_desc *ppd, const render_desc *renderDesc);
+static void RenderCubeVoxLine4F(int line, project_plane_desc *ppd, const render_desc *renderDesc);
+static void RenderCubeVoxLine8F(int line, project_plane_desc *ppd, const render_desc *renderDesc);
+
+
+
+
+#define sqr(x) (x)*(x)
+#define RENDER_SWAP(x,y,h) h=x; x=y; y=h;
+
+
+/* Number of vertices reserved per cube face (including x/z-clipping and appended 1st).
+ Each clipping pass can introduce a new vertex ==> 6, append first ==> 7. */
+#define VERTICES_PER_FACE 7
+/* The same for the clipped face. */
+#define VERTICES_CLIP_FACE 8
+
+#define VERTICES_TOTAL (6*VERTICES_PER_FACE + VERTICES_CLIP_FACE)
+
+
+
+
+#if (MACHINE_BYTE_ORDER == 0)
+#define CUBE_RENDER_BSHIFT 0
+#define CUBE_RENDER_BSTEP 8
+#define CUBE_RENDER_SSHIFT 0
+#define CUBE_RENDER_SSTEP 16
+#else
+#define CUBE_RENDER_BSHIFT 24
+#define CUBE_RENDER_BSTEP -8
+#define CUBE_RENDER_SSHIFT 16
+#define CUBE_RENDER_SSTEP -16
+#endif
+
+
+
+
+
+/* For easier writing down the cube initialisation. First coordinate is the constant.
+ Have to use vectors for initialising! */
+#define INIT_CUBE(x,y,z,u,v,w) \
+ currentv[0].x = u.x; currentv[0].y = u.y; currentv[0].z = u.z; \
+ currentv[1].x = u.x + w.x; currentv[1].y = u.y + w.y; currentv[1].z = u.z + w.z; \
+ currentv[2].x = u.x + v.x + w.x; currentv[2].y = u.y + v.y + w.y; currentv[2].z = u.z + v.z + w.z; \
+ currentv[3].x = u.x + v.x; currentv[3].y = u.y + v.y; currentv[3].z = u.z + v.z; \
+ currentv += 7;
+
+/* Initialise the texture base vectors. They have to be normalised in such a way that
+ when multiplied with the cube's base-vectors the result is the cube texture's
+ base vector (i.e. the texture dimension). Therefore divide by L_2^2 instead of L_2. */
+#define INIT_TEXBASE(i,c) \
+ l = sqr((real_t)(geomData[i].x)) + sqr((real_t)(geomData[i].y)) + sqr((real_t)(geomData[i].z)); \
+ if (l > 0) { \
+ h = ((real_t)(texDesc->c) / l); \
+ t[i-1].x = h*geomData[i].x; t[i-1].y = h*geomData[i].y; t[i-1].z = h*geomData[i].z; \
+ } \
+ else { \
+ return -1; \
+ }
+
+/* Init a bounding box structure */
+#define INIT_BBOX(root) root minx = INT_MAX; root maxx = INT_MIN; \
+ root miny = INT_MAX; root maxy = INT_MIN;
+
+/* Update the bounding box */
+#define UPDATE_BBOX(root,x,y) if (root minx > x) {root minx = x;} \
+ if (root maxx < x) {root maxx = x;} \
+ if (root miny > y) {root miny = y;} \
+ if (root maxy < y) {root maxy = y;}
+
+
+
+
+
+
+
+/* Global vars */
+static norm_kernel_desc NormalizeKernelHomo = {-1, NULL};
+static norm_kernel_desc NormalizeKernelLinear = {-1, NULL};
+static norm_kernel_desc NormalizeKernelGauss = {-1, NULL};
+static norm_kernel_desc NormalizeKernelDummy = {0, NULL};
+
+
+
+/*
+ * For debugging purposes: dumps all faces to stdout.
+ */
+#if (CUBE_RENDER_DEBUG > 0)
+static void RenderCubeDumpFaces(const face *faces, int first, int last)
+{
+ int i, j;
+
+ for (i=first; i<=last; i++)
+ {
+ printf("Face #%d\n", i);
+ for (j=0; j<faces[i].vertices; j++)
+ {
+ printf("\t(%f, %f, %f) : (%d, %d)\n",
+ faces[i].first[j].x, faces[i].first[j].y, faces[i].first[j].z,
+ faces[i].first_p[j].x, faces[i].first_p[j].y);
+ }
+ if (faces[i].vertices > 0)
+ {
+ printf("\t[%f, %f, %f] : [%d, %d]\n",
+ faces[i].first[j].x, faces[i].first[j].y, faces[i].first[j].z,
+ faces[i].first_p[j].x, faces[i].first_p[j].y);
+ }
+ printf("\n");
+ }
+ fflush(stdout);
+}
+#endif
+
+
+
+/*
+ * Calculate the intersection of the current scanplane with the face number faceNo.
+ * If found the translation to texture coordinates is also performed here.
+ */
+
+static void RenderCubeGetScanline(int ys, int faceNo, render_desc *renderDesc, int scaleTexture)
+{
+ int j;
+ face *cface;
+ real_t h;
+ real_t x, y, z, zpro, scanLine;
+ long xp;
+ vertex_fp *vx, *t, *sg, *st;
+ vertex_p *vxp;
+
+ scanLine = (real_t)ys;
+ renderDesc->found = 0; zpro = (real_t)(renderDesc->graphEnv->zpro);
+ cface = renderDesc->faces + faceNo;
+ renderDesc->left_p = INT_MAX; renderDesc->right_p = INT_MIN;
+
+ for (j=0, vx=cface->first, vxp=cface->first_p; j<cface->vertices; j++, vx++, vxp++)
+ {
+ /* Does this line segment intersect with the scanplane? */
+ if (((vxp[1].y <= ys) && (vxp[0].y >= ys)) ||
+ ((vxp[1].y >= ys) && (vxp[0].y <= ys)))
+ {
+ h = (vx[1].y - vx[0].y) * zpro - (vx[1].z - vx[0].z) * scanLine;
+ if (h != 0)
+ {
+ h = - (vx[0].y * zpro - vx[0].z * scanLine) / h;
+ }
+ /* Make sure it's in range (rounding errors could result in problems) */
+ if (h < 0.0) h = 0.0;
+ if (h > 1.0) h = 1.0;
+ x = vx[0].x + h * (vx[1].x - vx[0].x);
+ y = vx[0].y + h * (vx[1].y - vx[0].y);
+ z = vx[0].z + h * (vx[1].z - vx[0].z);
+ xp = (long)((zpro * x) / z + 0.5);
+
+ if (xp < renderDesc->left_p)
+ {
+ renderDesc->left_p = xp;
+ sg = &(renderDesc->left_g); sg->x = x; sg->y = y; sg->z = z;
+ renderDesc->found++;
+ }
+ if (xp > renderDesc->right_p)
+ {
+ renderDesc->right_p = xp;
+ sg = &(renderDesc->right_g); sg->x = x; sg->y = y; sg->z = z;
+ renderDesc->found++;
+ }
+ }
+ }
+ if (renderDesc->found == 0) return;
+
+ /* Calculate the texel positions only when the texture descriptor is defined */
+ if (renderDesc->texDesc != NULL)
+ {
+ vx = &(renderDesc->org); t = renderDesc->texbase;
+ /* Calculate the corresponding texel positions by projecting the global data to the
+ texture base vectors */
+ sg = &(renderDesc->left_g); st = &(renderDesc->left_t);
+ st->x = (sg->x - vx->x)*t[0].x + (sg->y - vx->y)*t[0].y + (sg->z - vx->z)*t[0].z;
+ st->y = (sg->x - vx->x)*t[1].x + (sg->y - vx->y)*t[1].y + (sg->z - vx->z)*t[1].z;
+ st->z = (sg->x - vx->x)*t[2].x + (sg->y - vx->y)*t[2].y + (sg->z - vx->z)*t[2].z;
+ if (scaleTexture != 0)
+ {
+ st->x *= (1<<FIXPOINT_PREC); st->y *= (1<<FIXPOINT_PREC); st->z *= (1<<FIXPOINT_PREC);
+ }
+ if (st->x < 0.0) st->x = 0.0; if (st->x > renderDesc->tmax.x) st->x = renderDesc->tmax.x;
+ if (st->y < 0.0) st->y = 0.0; if (st->y > renderDesc->tmax.y) st->y = renderDesc->tmax.y;
+ if (st->z < 0.0) st->z = 0.0; if (st->z > renderDesc->tmax.z) st->z = renderDesc->tmax.z;
+#if (CUBE_RENDER_DEBUG > 1)
+ printf("Left (%d, %d):\t(%f, %f, %f) : (%f, %f, %f)\n",
+ ys, faceNo, sg->x, sg->y, sg->z, st->x, st->y, st->z);
+#endif
+ sg = &(renderDesc->right_g); st = &(renderDesc->right_t);
+ st->x = (sg->x - vx->x)*t[0].x + (sg->y - vx->y)*t[0].y + (sg->z - vx->z)*t[0].z;
+ st->y = (sg->x - vx->x)*t[1].x + (sg->y - vx->y)*t[1].y + (sg->z - vx->z)*t[1].z;
+ st->z = (sg->x - vx->x)*t[2].x + (sg->y - vx->y)*t[2].y + (sg->z - vx->z)*t[2].z;
+ if (scaleTexture != 0)
+ {
+ st->x *= (1<<FIXPOINT_PREC); st->y *= (1<<FIXPOINT_PREC); st->z *= (1<<FIXPOINT_PREC);
+ }
+ if (st->x < 0.0) st->x = 0.0; if (st->x > renderDesc->tmax.x) st->x = renderDesc->tmax.x;
+ if (st->y < 0.0) st->y = 0.0; if (st->y > renderDesc->tmax.y) st->y = renderDesc->tmax.y;
+ if (st->z < 0.0) st->z = 0.0; if (st->z > renderDesc->tmax.z) st->z = renderDesc->tmax.z;
+#if (CUBE_RENDER_DEBUG > 1)
+ printf("Right (%d, %d):\t(%f, %f, %f) : (%f, %f, %f)\n",
+ ys, faceNo, sg->x, sg->y, sg->z, st->x, st->y, st->z);
+#endif
+ }
+}
+
+
+/*
+ * The core functionality of the rendering engine: each function renders all the
+ * visible lines. The code generated is dependent on the following makros:
+ *
+ * TEXEL_BSIZE The size in bytes of one cell.
+ * TEXEL_POINTER The name of the texture pointer (basetype dependent!).
+ * TEXEL_MULTIPLIER Used when calculating the texel position. If the base type is an atomic
+ * type set it to 1 and TEXEL_POINTER to the atomic type. Otherwise set
+ * TEXEL_POINTER to texture.c (byte) and TEXEL_MULTIPLIER to TEXEL_BSIZE.
+ * TEXEL_ASSIGN Used to write one texel to the next pixel and incrementing the pixel ptr.
+ * TEXEL_ACCU_0..3 Used to read texels into a 32 bit var for cacheing.
+ */
+
+/* Byte-sized base type */
+#undef RENDER_CORE_NAME
+#undef TEXEL_BSIZE
+#undef TEXEL_POINTER
+#undef TEXEL_MULTIPLIER
+#undef TEXEL_ASSIGN
+#undef TEXEL_ACCU_0
+#undef TEXEL_ACCU_1
+#undef TEXEL_ACCU_2
+#undef TEXEL_ACCU_3
+#define RENDER_CORE_NAME RenderCubeCore1
+#define TEXEL_BSIZE 1
+#define TEXEL_POINTER texture.c
+#define TEXEL_MULTIPLIER 1
+#define TEXEL_ASSIGN \
+ *dest.c++ = (TEXEL_FETCH); TEXEL_STEP;
+#define TEXEL_ACCU_0(a) \
+ a = ((TEXEL_FETCH) << CUBE_RENDER_BSHIFT); TEXEL_STEP;
+#define TEXEL_ACCU_1(a) \
+ a |= ((TEXEL_FETCH) << (CUBE_RENDER_BSHIFT + CUBE_RENDER_BSTEP)); TEXEL_STEP;
+#define TEXEL_ACCU_2(a) \
+ a |= ((TEXEL_FETCH) << (CUBE_RENDER_BSHIFT + 2*CUBE_RENDER_BSTEP)); TEXEL_STEP;
+#define TEXEL_ACCU_3(a) \
+ a |= ((TEXEL_FETCH) << (CUBE_RENDER_BSHIFT + 3*CUBE_RENDER_BSTEP)); TEXEL_STEP; *dest.l++ = a;
+#include "cube_render_core.c"
+
+/* Short-sized base type */
+#undef RENDER_CORE_NAME
+#undef TEXEL_BSIZE
+#undef TEXEL_POINTER
+#undef TEXEL_MULTIPLIER
+#undef TEXEL_ASSIGN
+#undef TEXEL_ACCU_0
+#undef TEXEL_ACCU_1
+#undef TEXEL_ACCU_2
+#undef TEXEL_ACCU_3
+#define RENDER_CORE_NAME RenderCubeCore2
+#define TEXEL_BSIZE 2
+#define TEXEL_POINTER texture.s
+#define TEXEL_MULTIPLIER 1
+#define TEXEL_ASSIGN \
+ *dest.s++ = (TEXEL_FETCH); TEXEL_STEP;
+#define TEXEL_ACCU_0(a) \
+ a = ((TEXEL_FETCH) << CUBE_RENDER_SSHIFT); TEXEL_STEP;
+#define TEXEL_ACCU_1(a) \
+ a |= ((TEXEL_FETCH) << (CUBE_RENDER_SSHIFT + CUBE_RENDER_SSTEP)); TEXEL_STEP; *dest.l++ = a;
+#define TEXEL_ACCU_2(a) \
+ a = ((TEXEL_FETCH) << CUBE_RENDER_SSHIFT); TEXEL_STEP;
+#define TEXEL_ACCU_3(a) \
+ a |= ((TEXEL_FETCH) << (CUBE_RENDER_SSHIFT + CUBE_RENDER_SSTEP)); TEXEL_STEP; *dest.l++ = a;
+#include "cube_render_core.c"
+
+/* Shared by RGB, Long and double: */
+#undef TEXEL_ACCU_0
+#undef TEXEL_ACCU_1
+#undef TEXEL_ACCU_2
+#undef TEXEL_ACCU_3
+#define TEXEL_ACCU_0(a) TEXEL_ASSIGN
+#define TEXEL_ACCU_1(a) TEXEL_ASSIGN
+#define TEXEL_ACCU_2(a) TEXEL_ASSIGN
+#define TEXEL_ACCU_3(a) TEXEL_ASSIGN
+
+/* RGB-sized base type */
+#undef RENDER_CORE_NAME
+#undef TEXEL_BSIZE
+#undef TEXEL_POINTER
+#undef TEXEL_MULTIPLIER
+#undef TEXEL_ASSIGN
+#define RENDER_CORE_NAME RenderCubeCore3
+#define TEXEL_BSIZE 3
+#define TEXEL_POINTER texture.c
+#define TEXEL_MULTIPLIER 3
+#define TEXEL_ASSIGN \
+ auxPtr = &TEXEL_FETCH; *dest.c++ = auxPtr[0]; *dest.c++ = auxPtr[1]; *dest.c++ = auxPtr[2]; TEXEL_STEP;
+#include "cube_render_core.c"
+
+/* Long-sized base type */
+#undef RENDER_CORE_NAME
+#undef TEXEL_BSIZE
+#undef TEXEL_POINTER
+#undef TEXEL_MULTIPLIER
+#undef TEXEL_ASSIGN
+#define RENDER_CORE_NAME RenderCubeCore4
+#define TEXEL_BSIZE 4
+#define TEXEL_POINTER texture.l
+#define TEXEL_MULTIPLIER 1
+#define TEXEL_ASSIGN \
+ *dest.l++ = (TEXEL_FETCH); TEXEL_STEP;
+#include "cube_render_core.c"
+
+
+/* Double-sized base type */
+#undef RENDER_CORE_NAME
+#undef TEXEL_BSIZE
+#undef TEXEL_POINTER
+#undef TEXEL_MULTIPLIER
+#undef TEXEL_ASSIGN
+#define RENDER_CORE_NAME RenderCubeCore8
+#define TEXEL_BSIZE 8
+#define TEXEL_POINTER texture.l
+#define TEXEL_MULTIPLIER 2
+#define TEXEL_ASSIGN \
+ auxPtr = &TEXEL_FETCH; *dest.l++ = auxPtr[0]; *dest.l++ = auxPtr[1]; TEXEL_STEP;
+#include "cube_render_core.c"
+
+
+
+
+/*
+ * Function builds a clipped cube into the render_desc structure. Requires faces
+ * and graphEnv to be set up correctly.
+ */
+
+void RenderCubeClipCube(const vertex_fp geomData[4], render_desc *renderDesc, int removeHidden)
+{
+ face *faces, *cface;
+ vertex_fp *currentv, *nextv, *clippedv, *pool;
+ vertex_p *currentv_p, *nextv_p, *clippedv_p, *pool_p;
+ vertex_fp norm;
+ int i, j, k, number;
+ real_t l, h;
+ real_t z0, z1, clip;
+ real_t zpro;
+ long longvar;
+ graph_env *graphEnv;
+
+ faces = renderDesc->faces;
+ pool = renderDesc->faces[0].first; pool_p = renderDesc->faces[0].first_p;
+ graphEnv = renderDesc->graphEnv; zpro = (real_t)(graphEnv->zpro);
+
+ /* Now expand descriptor to full cube description */
+ /* Keep first two vertices of each face free (-> clipping) */
+ currentv = pool + 2;
+ /* Init 3 vertices in pool which aren't needed yet with the coordinates of
+ geomData[0] + geomData[i] */
+ for (i=0; i<3; i++)
+ {
+ pool[VERTICES_PER_FACE*i].x = geomData[0].x + geomData[i+1].x;
+ pool[VERTICES_PER_FACE*i].y = geomData[0].y + geomData[i+1].y;
+ pool[VERTICES_PER_FACE*i].z = geomData[0].z + geomData[i+1].z;
+ }
+ INIT_CUBE(z,x,y,geomData[0],geomData[1],geomData[2]);
+ INIT_CUBE(z,x,y,pool[2*VERTICES_PER_FACE],geomData[2],geomData[1]);
+ INIT_CUBE(x,y,z,geomData[0],geomData[2],geomData[3]);
+ INIT_CUBE(x,y,z,pool[0],geomData[3],geomData[2]);
+ INIT_CUBE(y,x,z,geomData[0],geomData[3],geomData[1]);
+ INIT_CUBE(y,x,z,pool[VERTICES_PER_FACE],geomData[1],geomData[3]);
+
+ for (i=0; i<7; i++) faces[i].flags = 0;
+
+ /* Init seventh (clipz-) face. */
+ faces[6].vertices = 0;
+ faces[6].first = pool + 6*VERTICES_PER_FACE + 1; faces[6].first_p = pool_p + 6*VERTICES_PER_FACE + 1;
+
+ /* First pass: clipz, remove hidden surfaces. */
+ for (i=0; i<6; i++)
+ {
+ cface = faces + i;
+ cface->vertices = 4;
+ cface->first = pool + i*VERTICES_PER_FACE + 2; cface->first_p = pool_p + i*VERTICES_PER_FACE + 1;
+ /* Mustn't remove hidden surfaces before z-clipping! Otherwise z-clipping doesn't
+ work right. */
+
+ /* Init min / max values: get bounding box of projected cube. */
+ INIT_BBOX(cface->bBox.);
+
+ /* Append first vertex */
+ cface->first[4].x = cface->first[0].x;
+ cface->first[4].y = cface->first[0].y;
+ cface->first[4].z = cface->first[0].z;
+
+ /* z-clipping (vertices is still a constant 4 here) */
+ clip = (real_t)(graphEnv->clipz); nextv = cface->first; z0 = nextv->z;
+ currentv = nextv-1; cface->first = currentv; currentv_p = cface->first_p;
+ for (j=0, number=0; j<4; j++)
+ {
+ z1 = nextv[1].z;
+ if ((z0 >= clip) || (z1 >= clip))
+ {
+ clippedv = NULL;
+ if (z0 < clip) /* clip first: just store clipped vertex */
+ {
+ h = (real_t)(z1 - 2*clip + z0) / (z1 - z0);
+ /* Have to trap this case or we might get identical consecutive vertices */
+ currentv->x = (real_t)(0.5*(nextv[1].x + nextv[0].x - h*(nextv[1].x - nextv[0].x)));
+ currentv->y = (real_t)(0.5*(nextv[1].y + nextv[0].y - h*(nextv[1].y - nextv[0].y)));
+ currentv->z = clip;
+ clippedv = currentv; clippedv_p = currentv_p;
+ }
+ else if (z1 < clip) /* clip second: store first vertex (in range) AND clipped vertex */
+ {
+ currentv->x = nextv->x; currentv->y = nextv->y; currentv->z = nextv->z;
+ /* Also do the central for the first vertex projection here */
+ h = (zpro / z0);
+ currentv_p->x = (long)(h*(currentv->x)+0.5); currentv_p->y = (long)(h*(currentv->y)+0.5);
+ UPDATE_BBOX(cface->bBox., currentv_p->x, currentv_p->y);
+ currentv++; currentv_p++;
+ h = (real_t)(z1 - 2*clip + z0) / (z1 - z0);
+ currentv->x = (real_t)(0.5*(nextv[1].x + nextv[0].x - h*(nextv[1].x - nextv[0].x)));
+ currentv->y = (real_t)(0.5*(nextv[1].y + nextv[0].y - h*(nextv[1].y - nextv[0].y)));
+ currentv->z = clip;
+ clippedv = currentv; clippedv_p = currentv_p;
+ number++;
+ }
+ else
+ {
+ currentv->x = nextv->x; currentv->y = nextv->y; currentv->z = nextv->z;
+ }
+
+ /* Do central projection (have to use currentv here rather than z0!) */
+ h = (zpro / currentv->z);
+ currentv_p->x = (long)(h*(currentv->x)+0.5); currentv_p->y = (long)(h*(currentv->y)+0.5);
+ UPDATE_BBOX(cface->bBox., currentv_p->x, currentv_p->y);
+ currentv++; currentv_p++; number++;
+
+ /* Was a vertex clipped? Yes ==> build seventh face */
+ if (clippedv != NULL)
+ {
+#if (CUBE_RENDER_DEBUG > 1)
+ printf("Clipped (face %d): (%f, %f, %f)\n", i, clippedv->x, clippedv->y, clippedv->z);
+#endif
+ /* Compare projected vertex with ones already stored. This is used because projected
+ vertices are integers and thus the test for equality actually means something ;-) */
+ for (k=0; k<faces[6].vertices; k++)
+ {
+ if ((faces[6].first_p[k].x == clippedv_p->x) && (faces[6].first_p[k].y == clippedv_p->y))
+ break;
+ }
+ /* Didn't break loop, i.e. didn't find duplicate, therefore add it */
+ if (k == faces[6].vertices)
+ {
+ faces[6].first[k].x = clippedv->x;
+ faces[6].first[k].y = clippedv->y;
+ faces[6].first[k].z = clippedv->z;
+ faces[6].first_p[k].x = clippedv_p->x;
+ faces[6].first_p[k].y = clippedv_p->y;
+ faces[6].vertices++;
+ }
+ }
+ }
+ z0 = z1; nextv++;
+ }
+ /* In case this face isn't visible after all set its vertex count to 0 */
+ if ((number < 3) || (cface->bBox.minx > graphEnv->clipr) || (cface->bBox.maxx < graphEnv->clipl)
+ || (cface->bBox.miny > graphEnv->clipu) || (cface->bBox.maxy < graphEnv->clipd))
+ {
+ cface->vertices = 0;
+#if (CUBE_RENDER_DEBUG > 0)
+ printf("Clipz (%d): %d, %d, %d, %d : %d\n", i, cface->bBox.minx, cface->bBox.miny, cface->bBox.maxx, cface->bBox.maxy, number);
+#endif
+ }
+ else
+ {
+ cface->vertices = number;
+ /* Remove identical vertices */
+ number = 1;
+ currentv = cface->first; nextv = currentv+1;
+ currentv_p = cface->first_p; nextv_p = currentv_p + 1;
+ for (k=1; k<cface->vertices; k++)
+ {
+ l = sqr(nextv->x - currentv->x)
+ + sqr(nextv->y - currentv->y)
+ + sqr(nextv->z - currentv->z);
+ if (l > 1e-3)
+ {
+ currentv++; currentv_p++; number++;
+ currentv->x = nextv->x; currentv->y = nextv->y; currentv->z = nextv->z;
+ currentv_p->x = nextv_p->x; currentv_p->y = nextv_p->y;
+ }
+ nextv++; nextv_p++;
+ }
+
+ currentv = cface->first + 1; k = 2;
+ /* Calculate face normal. Take into account that consecutive
+ vertices might be identical
+ but sets of 3 may be linearily correlated. So loop until the
+ normal vector isn't of zero length. */
+ do
+ {
+ norm.x = (cface->first[1].y - cface->first[0].y) * (currentv[1].z - currentv[0].z)
+ - (currentv[1].y - currentv[0].y) * (cface->first[1].z - cface->first[0].z);
+ norm.y = (cface->first[1].z - cface->first[0].z) * (currentv[1].x - currentv[0].x)
+ - (currentv[1].z - currentv[0].z) * (cface->first[1].x - cface->first[0].x);
+ norm.z = (cface->first[1].x - cface->first[0].x) * (currentv[1].y - currentv[0].y)
+ - (currentv[1].x - currentv[0].x) * (cface->first[1].y - cface->first[0].y);
+ l = sqr(norm.x) + sqr(norm.y) + sqr(norm.z); k++; currentv++;
+ }
+ while ((l == 0) && (k < number));
+
+ currentv = cface->first;
+
+ /* project normal to a straight line connecting the global origin and a point on
+ the face's surface (use first vertex for convenience). The sign of this scalar
+ product determines whether the face is visible or not. */
+ l = norm.x * currentv->x + norm.y * currentv->y + norm.z * currentv->z;
+
+ if (l >= 0)
+ {
+ cface->flags |= CUBE_RENDER_FACE_HIDDEN;
+ }
+
+ if (removeHidden == 0) l = -1;
+
+ if (l < 0)
+ {
+ cface->vertices = number;
+ /* Append first vertex again */
+ currentv = cface->first + number; currentv_p = cface->first_p + number;
+ currentv->x = cface->first->x; currentv->y = cface->first->y; currentv->z = cface->first->z;
+ currentv_p->x = cface->first_p->x; currentv_p->y = cface->first_p->y;
+ }
+ else
+ {
+ cface->vertices = 0;
+#if (CUBE_RENDER_DEBUG > 0)
+ printf("Face invisible (%d)\n", i);
+#endif
+ }
+ }
+ }
+
+ /* Some code to test the ordering of the clipped face's vertices:
+ cface = faces + 6; cface->first = pool+42; cface->first_p = pool_p+42;
+ cface->vertices = 6;
+ for (i=0; i<6; i++)
+ {
+ cface->first[i].x = 5*i*i; cface->first[i].y = 200*i*(0.5 - (i & 1)); cface->first[i].z = 0;
+ }
+ */
+
+ /* If a new face had to be created due to z-clipping, vertices have to be ordered so
+ there are no crossing lines. The orientation is irrelevant, however, because
+ the clipped face is always visible and the hidden face removal has already been
+ done at this point. Careful, however, because the face might be completely off
+ screen. */
+ if ((number = faces[6].vertices) >= 3)
+ {
+ cface = faces + 6;
+
+ /* Create a bounding box for the clipped face too */
+ INIT_BBOX(cface->bBox.);
+ for (i=0; i<number; i++)
+ {
+ UPDATE_BBOX(cface->bBox., cface->first_p[i].x, cface->first_p[i].y);
+ }
+ /* Is bbox off screen? */
+ if ((cface->bBox.minx > graphEnv->clipr) || (cface->bBox.maxx < graphEnv->clipl)
+ || (cface->bBox.miny > graphEnv->clipu) || (cface->bBox.maxy < graphEnv->clipd))
+ {number = 0; cface->vertices = 0;}
+
+ /* Basically the clipped face can contain up to 6 vertices. If there are
+ only 3 nothing has to be done. */
+ if (number > 3)
+ {
+ real_t tangi[VERTICES_CLIP_FACE]; /* Will contain the tangens of each face */
+
+ /* Calculate the tangens of each vertex relative to the first one. Since tan is
+ strictly monotonous in (-pi/2, pi/2) ordering by tan(x) equals ordering by x.
+ For 2D-coordinates just use the _projected_ coordinates rather than do an
+ expensive transformation into face coordinates. */
+
+ /* First up the anchor point has to be the leftmost or rightmost one (since tan
+ can't tell the difference between y/x and -y/-x). Use left. */
+ longvar = INT_MAX; j = 0;
+ for (i=0; i<number; i++)
+ {
+ if (cface->first_p[i].x < longvar) {longvar = cface->first_p[i].x; j = i;}
+ }
+ if (j != 0)
+ {
+ RENDER_SWAP(cface->first[0].x, cface->first[j].x, z0);
+ RENDER_SWAP(cface->first[0].y, cface->first[j].y, z0);
+ RENDER_SWAP(cface->first[0].z, cface->first[j].z, z0);
+ RENDER_SWAP(cface->first_p[0].x, cface->first_p[j].x, longvar);
+ RENDER_SWAP(cface->first_p[0].y, cface->first_p[j].y, longvar);
+ }
+ /* Now calculate the tangi */
+ currentv_p = cface->first_p; nextv_p = currentv_p + 1;
+ for (i=1; i<number; i++, nextv_p++)
+ {
+ z0 = (real_t)(nextv_p->x - currentv_p->x);
+ z1 = (real_t)(nextv_p->y - currentv_p->y);
+ if (z0 < 0.0) {z0 = -z0; z1 = -z1;}
+ if (z0 < 1e-6) z0 = (real_t)1e-6; /* Trap division by very small values */
+ tangi[i] = (z1/z0);
+ }
+ /* Now sort (Quicksort is not a good idea with <= 6 vertices) */
+ for (i=1; i < number-1; i++)
+ {
+ for (j=i+1; j < number; j++)
+ {
+ if (tangi[i] > tangi[j])
+ {
+ RENDER_SWAP(tangi[i], tangi[j], z0);
+ RENDER_SWAP(cface->first[i].x, cface->first[j].x, z0);
+ RENDER_SWAP(cface->first[i].y, cface->first[j].y, z0);
+ RENDER_SWAP(cface->first[i].z, cface->first[j].z, z0);
+ RENDER_SWAP(cface->first_p[i].x, cface->first_p[j].x, longvar);
+ RENDER_SWAP(cface->first_p[i].y, cface->first_p[j].y, longvar);
+ }
+ }
+ }
+
+ /*printf("Tangi (%d): ", cface->vertices);
+ for (i=1; i<cface->vertices; i++)
+ {
+ printf("%f ", tangi[i]);
+ }
+ printf("\n"); fflush(stdout);*/
+ }
+
+ /* Append first vertex to new face too */
+ currentv = cface->first + number; currentv_p = cface->first_p + number;
+ currentv->x = cface->first->x; currentv->y = cface->first->y; currentv->z = cface->first->z;
+ currentv_p->x = cface->first_p->x; currentv_p->y = cface->first_p->y;
+ }
+ else
+ {
+ faces[6].vertices = 0;
+ }
+
+#if (CUBE_RENDER_DEBUG > 0)
+ printf("Pass1 -- clipz + hidden face removal:\n");
+ RenderCubeDumpFaces(faces, 0, 6);
+#endif
+
+ /* Clip at the left border by calculating intersections with the clipping plane.
+ Since each face's bounding box has been determined above this can't eliminate
+ any more faces, it's purely for efficiency. */
+ for (i=0; i<7; i++)
+ {
+ cface = faces + i;
+ if ((cface->vertices > 0) && (cface->bBox.minx < graphEnv->clipl))
+ {
+ /* Have to build the bbox anew in that case (updated y) */
+ INIT_BBOX(cface->bBox.);
+
+ nextv = cface->first; currentv = nextv-1; cface->first = currentv;
+ nextv_p = cface->first_p; currentv_p = nextv_p-1; cface->first_p = currentv_p;
+ z0 = (real_t)(nextv_p->x);
+ clip = (real_t)(graphEnv->clipl) - 0.5f; /* -0.5 is vital here or you get frayed edges. */
+ for (j=0, number=0; j<cface->vertices; j++)
+ {
+ z1 = (real_t)(nextv_p[1].x);
+ if ((z0 >= clip) || (z1 >= clip))
+ {
+ /* In case both >= clip or the 2nd vertex lies outside the range: copy 1st */
+ if (z0 >= clip)
+ {
+ currentv->x = nextv->x; currentv->y = nextv->y; currentv->z = nextv->z;
+ currentv_p->x = nextv_p->x; currentv_p->y = nextv_p->y;
+ UPDATE_BBOX(cface->bBox., currentv_p->x, currentv_p->y);
+ currentv++; currentv_p++; number++;
+ }
+ /* Next the actual clipping */
+ if ((z0 < clip) || (z1 < clip))
+ {
+ l = ((nextv[1].x - nextv[0].x) * zpro - (nextv[1].z - nextv[0].z) * clip);
+ if (l == 0.0) {h = 0.0;}
+ else
+ {
+ h = (nextv->x * zpro - nextv->z * clip) / l;
+ }
+ currentv->x = nextv[0].x - h*(nextv[1].x - nextv[0].x);
+ currentv->y = nextv[0].y - h*(nextv[1].y - nextv[0].y);
+ currentv->z = nextv[0].z - h*(nextv[1].z - nextv[0].z);
+ currentv_p->x = graphEnv->clipl; currentv_p->y = (long)((zpro * currentv->y) / currentv->z + 0.5);
+ UPDATE_BBOX(cface->bBox., currentv_p->x, currentv_p->y);
+ currentv++; currentv_p++; number++;
+ }
+ }
+ z0 = z1; nextv++; nextv_p++;
+ }
+ cface->vertices = number;
+ /* Append first vertex */
+ currentv->x = cface->first->x; currentv->y = cface->first->y; currentv->z = cface->first->z;
+ currentv_p->x = cface->first_p->x; currentv_p->y = cface->first_p->y;
+ }
+
+ if (cface->vertices > 0)
+ {
+ /* Restrict bBox y values (do that _after_ x-clipping) */
+ if (cface->bBox.miny < graphEnv->clipd) {cface->bBox.miny = graphEnv->clipd;}
+ if (cface->bBox.maxy > graphEnv->clipu) {cface->bBox.maxy = graphEnv->clipu;}
+
+#if (CUBE_RENDER_DEBUG > 0)
+ printf("Bounding Box: %d, %d, %d, %d\n",
+ cface->bBox.minx, cface->bBox.miny, cface->bBox.maxx, cface->bBox.maxy);
+#endif
+ }
+ }
+
+#if (CUBE_RENDER_DEBUG > 0)
+ printf("Pass2 -- clipx\n");
+ RenderCubeDumpFaces(faces, 0, 6);
+#endif
+}
+
+
+
+
+/*
+ * Initialise texture descriptor and transform matrix
+ */
+static int CubeRenderInitTextures(const vertex_fp *geomData, const tex_desc *texDesc, render_desc *renderDesc, int scaleTexture)
+{
+ real_t l, h;
+ vertex_fp *t;
+
+ t = renderDesc->texbase;
+
+ /* Calculate the texture base vectors */
+ INIT_TEXBASE(1,widthx);
+ INIT_TEXBASE(2,widthy);
+ INIT_TEXBASE(3,widthz);
+
+ /* Highest legal value of texture coordinates scaled by fixpoint precision.
+ It's _terribly_ important where you subtract a fraction! You can get
+ _incredible_ distortions by subtracting before shifting.
+ Also the amount to subtract has to be set relative to the texture
+ dimensions because if the subtracted value is too small relative to
+ the number's size you get cases where (x - y) == x (e.g. dim = 300
+ and real_t = float). */
+ if (scaleTexture == 0)
+ {
+ renderDesc->tmax.x = ((real_t)(texDesc->widthx)) - 0.5f;
+ renderDesc->tmax.y = ((real_t)(texDesc->widthy)) - 0.5f;
+ renderDesc->tmax.z = ((real_t)(texDesc->widthz)) - 0.5f;
+ }
+ else
+ {
+ renderDesc->tmax.x = (real_t)((texDesc->widthx << FIXPOINT_PREC) - texDesc->widthx / 64.0);
+ renderDesc->tmax.y = (real_t)((texDesc->widthy << FIXPOINT_PREC) - texDesc->widthy / 64.0);
+ renderDesc->tmax.z = (real_t)((texDesc->widthz << FIXPOINT_PREC) - texDesc->widthz / 64.0);
+ }
+
+ /*printf("%f,%f,%f\n", renderDesc->tmax.x, renderDesc->tmax.y, renderDesc->tmax.z);*/
+
+ renderDesc->texDesc = (tex_desc *)texDesc;
+
+ return 0;
+}
+
+
+
+
+/*
+ * Render the bounding box.
+ */
+static void RenderCubeBBox(const render_desc *renderDesc, int hidden)
+{
+ int i, j;
+ unsigned int flagval;
+ face *faces;
+ graph_env *graphEnv;
+
+ if (hidden == 0) flagval = 0; else flagval = CUBE_RENDER_FACE_HIDDEN;
+ faces = renderDesc->faces;
+ graphEnv = renderDesc->graphEnv;
+
+ for (i=0; i<7; i++)
+ {
+ if ((faces[i].vertices != 0) && ((faces[i].flags & CUBE_RENDER_FACE_HIDDEN) == flagval))
+ {
+ for (j=0; j<faces[i].vertices; j++)
+ {
+ RenderLineSegment(faces[i].first_p + j, faces[i].first_p + (j+1), (render_desc*)renderDesc, graphEnv->bbox_colour);
+ }
+ }
+ }
+}
+
+
+
+/*
+ * Main function to render a cube in 3D.
+ * geomData contains four vertices: the origin (0) and the three base vectors.
+ * graphEnv describes where the plot goes to and what clippling should be applied.
+ * texDesc is the descriptor of the texture data (the cube's contents).
+ */
+
+int RenderCubeSurf(const vertex_fp geomData[4], const graph_env *graphEnv, const tex_desc *texDesc)
+{
+ vertex_fp t[3];
+ face faces[7]; /* For each face */
+ vertex_fp pool[VERTICES_TOTAL];
+ vertex_p pool_p[VERTICES_TOTAL];
+#if (CUBE_RENDER_DEBUG > 0)
+ vertex_fp *currentv, *nextv;
+ vertex_p *currentv_p, *nextv_p;
+ int j;
+ long longvar;
+#endif
+ /*real_t l, h;*/
+ int i;
+ render_desc renderDesc;
+
+ renderDesc.texbase = t;
+
+ CubeRenderInitTextures(geomData, texDesc, &renderDesc, 1);
+
+#if (CUBE_RENDER_DEBUG > 0)
+ /* Projections of the base vectors on the texture base vectors: */
+ for (i=0; i<3; i++)
+ {
+ longvar = (long)(t[i].x * (real_t)(geomData[i+1].x) + t[i].y * (real_t)(geomData[i+1].y) + t[i].z * (real_t)(geomData[i+1].z));
+ printf("texbase %d: (%f, %f, %f), max tex: %ld\n", i, t[i].x, t[i].y, t[i].z, longvar);
+ }
+ /* Scalar products of the texture base vectors (how orthogonal are they?) */
+ for (i=0; i<2; i++)
+ {
+ for (j=i+1; j<3; j++)
+ {
+ printf("t_%d*t_%d: %g ", i, j, t[i].x*t[j].x + t[i].y*t[j].y + t[i].z*t[j].z);
+ }
+ }
+ printf("\n"); fflush(stdout);
+ /* Projection of cube diagonal on texture base vectors (= translation to texture coordinates) */
+ pool->x = geomData[0].x + geomData[1].x + geomData[2].x + geomData[3].x;
+ pool->y = geomData[0].y + geomData[1].y + geomData[2].y + geomData[3].y;
+ pool->z = geomData[0].z + geomData[1].z + geomData[2].z + geomData[3].z;
+ printf("pool: %f, %f, %f\n", pool->x, pool->y, pool->z);
+ for (i=0; i<3; i++)
+ {
+ printf("tex_%d = %f ", i, ((pool->x - geomData[0].x)*t[i].x + (pool->y - geomData[0].y)*t[i].y + (pool->z - geomData[0].z)*t[i].z));
+ }
+ printf("\n"); fflush(stdout);
+#endif
+
+ /* Set up rendering descriptor */
+ renderDesc.faces = faces;
+ renderDesc.faces[0].first = pool; renderDesc.faces[0].first_p = pool_p;
+ renderDesc.graphEnv = (graph_env *)graphEnv;
+
+ /* Set up descriptor structure for scanline analyser */
+ renderDesc.org.x = (real_t)(geomData[0].x);
+ renderDesc.org.y = (real_t)(geomData[0].y);
+ renderDesc.org.z = (real_t)(geomData[0].z);
+
+ RenderCubeClipCube(geomData, &renderDesc, 1);
+
+ /*for (i=0; i<7; i++)
+ {
+ j = faces[i].first + faces[i].vertices - pool;
+ if ((j >= VERTICES_TOTAL) || (j < 0)) {printf("ARGHH1 (%d: %d)!!!", i, j); fflush(stdout); exit(0);}
+ j = faces[i].first_p + faces[i].vertices - pool_p;
+ if ((j >= VERTICES_TOTAL) || (j < 0)) {printf("ARGHH2 (%d: %d)!!!", i, j); fflush(stdout); exit(0);}
+ }*/
+
+ /* Now render all faces */
+ for (i=0; i<7; i++)
+ {
+ if (faces[i].vertices > 0)
+ {
+#if (CUBE_RENDER_DEBUG > 0)
+ currentv = faces[i].first; nextv = currentv + faces[i].vertices;
+ currentv_p = faces[i].first_p; nextv_p = currentv_p + faces[i].vertices;
+ if ((currentv->x != nextv->x) || (currentv->y != nextv->y) || (currentv->z != nextv->z) || (currentv_p->x != nextv_p->x) || (currentv_p->y != nextv_p->y))
+ {
+ printf("First vertex not appended correctly (%f, %f, %f : %d, %d)!\n", nextv->x, nextv->y, nextv->z, nextv_p->x, nextv_p->y); fflush(stdout);
+ }
+#endif
+ switch (texDesc->baseSize)
+ {
+ case 1: RenderCubeCore1(i, &renderDesc); break;
+ case 2: RenderCubeCore2(i, &renderDesc); break;
+ case 3: RenderCubeCore3(i, &renderDesc); break;
+ case 4: RenderCubeCore4(i, &renderDesc); break;
+ case 8: RenderCubeCore8(i, &renderDesc); break;
+ default: fprintf(stderr, "Bad base type size (%d)\n", texDesc->baseSize); exit(-1);
+ }
+ }
+ }
+
+ if ((graphEnv->bbox_colour) != 0xffffffff)
+ {
+ RenderCubeBBox(&renderDesc, 0);
+ }
+
+#if (CUBE_RENDER_DEBUG > 0)
+ printf("CubeRender successful.\n"); fflush(stdout);
+#endif
+
+ return(0);
+}
+
+
+
+
+/*
+ * Render one line in voxel mode for various depths
+ */
+
+#define RENDER_CAST_TYPE uint32
+
+#undef RENDER_CORE_NAME
+#undef TEXEL_BSIZE
+#undef TEXEL_FETCH
+#define RENDER_CORE_NAME RenderCubeVoxLine1
+#define TEXEL_BSIZE 1
+#define TEXEL_FETCH (texture.c[(((tx >> FIXPOINT_PREC) * dimy + (ty >> FIXPOINT_PREC)) * dimz + (tz >> FIXPOINT_PREC))])
+#define RENDER_TABLE_TYPE texture.c
+#include "cube_render_voxline.c"
+
+#undef RENDER_CORE_NAME
+#undef TEXEL_BSIZE
+#undef TEXEL_FETCH
+#undef RENDER_TABLE_TYPE
+#define RENDER_CORE_NAME RenderCubeVoxLine2
+#define TEXEL_BSIZE 2
+#define TEXEL_FETCH (texture.s[(((tx >> FIXPOINT_PREC) * dimy + (ty >> FIXPOINT_PREC)) * dimz + (tz >> FIXPOINT_PREC))])
+#define RENDER_TABLE_TYPE texture.s
+#include "cube_render_voxline.c"
+
+#undef RENDER_CORE_NAME
+#undef TEXEL_BSIZE
+#undef TEXEL_FETCH
+#undef RENDER_TABLE_TYPE
+#define RENDER_CORE_NAME RenderCubeVoxLine3
+#define TEXEL_BSIZE 3
+#define TEXEL_FETCH srcPix=(texture.c + (((tx >> FIXPOINT_PREC) * dimy + (ty >> FIXPOINT_PREC)) * dimz + (tz >> FIXPOINT_PREC)) * 3);
+#define RENDER_TABLE_TYPE texture.c
+#include "cube_render_voxline.c"
+
+#undef RENDER_CORE_NAME
+#define RENDER_CORE_NAME RenderCubeVoxLine3B
+#define TEXEL_RGB_BRIGHTNESS
+#include "cube_render_voxline.c"
+#undef TEXEL_RGB_BRIGHTNESS
+
+#undef RENDER_CORE_NAME
+#undef TEXEL_BSIZE
+#undef TEXEL_FETCH
+#undef RENDER_TABLE_TYPE
+#define RENDER_CORE_NAME RenderCubeVoxLine4
+#define TEXEL_BSIZE 4
+#define TEXEL_FETCH (texture.l[(((tx >> FIXPOINT_PREC) * dimy + (ty >> FIXPOINT_PREC)) * dimz + (tz >> FIXPOINT_PREC))])
+#define RENDER_TABLE_TYPE texture.l
+#include "cube_render_voxline.c"
+
+#undef RENDER_CAST_TYPE
+
+#undef RENDER_CORE_NAME
+#undef TEXEL_BSIZE
+#undef TEXEL_FETCH
+#undef RENDER_TABLE_TYPE
+#define RENDER_CAST_TYPE float
+#define RENDER_FLOAT_TYPE float
+#define RENDER_CORE_NAME RenderCubeVoxLine4F
+#define TEXEL_BSIZE 4
+#define TEXEL_FETCH (texture.f[(((tx >> FIXPOINT_PREC) * dimy + (ty >> FIXPOINT_PREC)) * dimz + (tz >> FIXPOINT_PREC))])
+#define RENDER_TABLE_TYPE texture.f
+#include "cube_render_voxline.c"
+
+#undef RENDER_CAST_TYPE
+#undef RENDER_FLOAT_TYPE
+#undef RENDER_CORE_NAME
+#undef TEXEL_BSIZE
+#undef TEXEL_FETCH
+#undef RENDER_TABLE_TYPE
+#define RENDER_CAST_TYPE double
+#define RENDER_FLOAT_TYPE double
+#define RENDER_CORE_NAME RenderCubeVoxLine8F
+#define TEXEL_BSIZE 8
+#define TEXEL_FETCH (texture.d[(((tx >> FIXPOINT_PREC) * dimy + (ty >> FIXPOINT_PREC)) * dimz + (tz >> FIXPOINT_PREC))])
+#define RENDER_TABLE_TYPE texture.d
+#include "cube_render_voxline.c"
+
+#undef RENDER_FLOAT_TYPE
+
+
+
+
+#define RENDER_SWAP_PLANE_DESC(i,j) \
+ memcpy(&aux, ppd->ppi + i, sizeof(project_plane_intersect)); \
+ memcpy(ppd->ppi + i, ppd->ppi + j, sizeof(project_plane_intersect)); \
+ memcpy(ppd->ppi + j, &aux, sizeof(project_plane_intersect));
+
+/* sort project_plane_desc structure into front/back segments and init some members */
+static void CubeRenderNormalizePlane(project_plane_desc *ppd)
+{
+ int i;
+ long min, max;
+ /*int j;
+ unsigned long isBack;
+ real_t nom, den, pos, h, actual_z, zpro;
+ project_plane_intersect aux;*/
+
+ /* Eliminate segments that are parallel to the scan-beam */
+ i=0;
+ while (i < ppd->segs)
+ {
+ if (ppd->ppi[i].left_p == ppd->ppi[i].right_p)
+ {
+ (ppd->segs)--;
+ if (i < ppd->segs)
+ {
+ memmove(ppd->ppi + i, ppd->ppi + (i+1), (ppd->segs - i) * sizeof(project_plane_intersect));
+ }
+ }
+ else i++;
+ }
+
+#if 0
+ /* Sorting doesn't work well at all... */
+ for (i=0; i<ppd->segs; i++)
+ {
+ /* Use deltaLR for coordinates of middle of segment */
+ ppd->ppi[i].deltaLR_g.x = (ppd->ppi[i].left_g.x + ppd->ppi[i].right_g.x) / 2;
+ ppd->ppi[i].deltaLR_g.y = (ppd->ppi[i].left_g.y + ppd->ppi[i].right_g.y) / 2;
+ ppd->ppi[i].deltaLR_g.z = (ppd->ppi[i].left_g.z + ppd->ppi[i].right_g.z) / 2;
+ }
+
+ /* Leftmost segment (described by middle) to position 0 */
+ for (i=1; i<ppd->segs; i++)
+ {
+ if (ppd->ppi[i].deltaLR_g.x < ppd->ppi[0].deltaLR_g.x)
+ {
+ RENDER_SWAP_PLANE_DESC(i,0);
+ }
+ }
+ /* Determine tan, using deltaLR_t.x */
+ for (i=1; i<ppd->segs; i++)
+ {
+ h = (ppd->ppi[i].deltaLR_g.x - ppd->ppi[0].deltaLR_g.x);
+ if (h == 0.0) h = 1e-4;
+ ppd->ppi[i].deltaLR_t.x = (ppd->ppi[i].deltaLR_g.z - ppd->ppi[0].deltaLR_g.z) / h;
+ }
+ /* Sort by tan in ascending order (i.e. counter-clockwise) */
+ for (i=1; i<ppd->segs-1; i++)
+ {
+ for (j=i+1; j<ppd->segs; j++)
+ {
+ if (ppd->ppi[j].deltaLR_t.x < ppd->ppi[i].deltaLR_t.x)
+ {
+ RENDER_SWAP_PLANE_DESC(i,j);
+ }
+ }
+ }
+ /* Make sure there are no gaps between segments */
+ min = ppd->ppi[0].left_p; max = min;
+ for (i=0; i<ppd->segs; i++)
+ {
+ j = i+1; if (j >= ppd->segs) j = 0;
+ if ((ppd->ppi[i].left_p != ppd->ppi[j].left_p) && (ppd->ppi[i].right_p != ppd->ppi[j].right_p)
+ && (ppd->ppi[i].left_p != ppd->ppi[j].right_p) && (ppd->ppi[i].right_p != ppd->ppi[j].left_p))
+ {
+ int dll, drr, dlr, drl;
+
+ dll = ppd->ppi[i].left_p - ppd->ppi[j].left_p; if (dll < 0) dll = -dll;
+ drr = ppd->ppi[i].right_p - ppd->ppi[j].right_p; if (drr < 0) drr = -drr;
+ dlr = ppd->ppi[i].left_p - ppd->ppi[j].right_p; if (dlr < 0) dlr = -dlr;
+ drl = ppd->ppi[i].right_p - ppd->ppi[j].left_p; if (drl < 0) drl = -drl;
+ if ((dll < drr) && (dll < dlr) && (dll < drl))
+ {
+ ppd->ppi[i].left_p = ppd->ppi[j].left_p;
+ }
+ else if ((drr < dll) && (drr < dlr) && (drr < drl))
+ {
+ ppd->ppi[i].right_p = ppd->ppi[j].right_p;
+ }
+ else if ((dlr < dll) && (dlr < drr) && (dlr < drl))
+ {
+ ppd->ppi[i].left_p = ppd->ppi[j].right_p;
+ }
+ else
+ {
+ ppd->ppi[i].right_p = ppd->ppi[j].left_p;
+ }
+ }
+ if (ppd->ppi[i].left_p < min) min = ppd->ppi[i].left_p;
+ if (ppd->ppi[i].right_p > max) max = ppd->ppi[i].right_p;
+ }
+ ppd->left_p = min; ppd->right_p = max;
+
+ /*
+ * If the first segment is a back segment is a back segment then its left_p is identical
+ * to the next segment's. Since the polygon is convex there can only be two cases of
+ * orderings of the leftmost front / back segments.
+ */
+ if (ppd->ppi[0].left_p == ppd->ppi[1].left_p)
+ {
+ /* First segment is back segment ==> move to end */
+ memcpy(&aux, ppd->ppi + 0, sizeof(project_plane_intersect));
+ memmove(ppd->ppi + 0, ppd->ppi + 1, (ppd->segs - 1) * sizeof(project_plane_intersect));
+ memcpy(ppd->ppi + (ppd->segs - 1), &aux, sizeof(project_plane_intersect));
+ }
+
+ /*for (i=0; i<ppd->segs; i++)
+ {
+ printf("%f,%f,%f\n", ppd->ppi[i].deltaLR_g.x, ppd->ppi[i].deltaLR_g.y, ppd->ppi[i].deltaLR_g.z);
+ }
+ printf("\n");*/
+#endif
+
+ min = ppd->ppi[0].left_p; max = min;
+ for (i=0; i<ppd->segs; i++)
+ {
+ /*printf("[%d: %d,%d] ", i, ppd->ppi[i].left_p, ppd->ppi[i].right_p);*/
+ ppd->ppi[i].deltaLR_g.x = ppd->ppi[i].right_g.x - ppd->ppi[i].left_g.x;
+ ppd->ppi[i].deltaLR_g.y = ppd->ppi[i].right_g.y - ppd->ppi[i].left_g.y;
+ ppd->ppi[i].deltaLR_g.z = ppd->ppi[i].right_g.z - ppd->ppi[i].left_g.z;
+ ppd->ppi[i].deltaLR_t.x = ppd->ppi[i].right_t.x - ppd->ppi[i].left_t.x;
+ ppd->ppi[i].deltaLR_t.y = ppd->ppi[i].right_t.y - ppd->ppi[i].left_t.y;
+ ppd->ppi[i].deltaLR_t.z = ppd->ppi[i].right_t.z - ppd->ppi[i].left_t.z;
+ if (ppd->ppi[i].left_p < min) min = ppd->ppi[i].left_p;
+ if (ppd->ppi[i].right_p > max) max = ppd->ppi[i].right_p;
+ }
+ ppd->left_p = min; ppd->right_p = max;
+ /*printf("\n");*/
+
+ /*for (i=0; i<ppd->segs-1; i++)
+ {
+ for (j=i+1; j<ppd->segs; j++)
+ {
+ if (ppd->ppi[j].left_p < ppd->ppi[i].left_p)
+ {
+ RENDER_SWAP_PLANE_DESC(i,j);
+ }
+ }
+ }*/
+}
+
+
+
+
+int RenderCube(const vertex_fp geomData[4], const graph_env *graphEnv, const tex_desc *texDesc)
+{
+ voxel_desc voxDesc;
+ tex_desc newTexDesc;
+
+ voxDesc.pixelThresholdLow = (double)4;
+ voxDesc.pixelThresholdHigh = (double)0xffffffff;
+ voxDesc.weightThreshold = (double)64;
+ voxDesc.weightQuantisation = 4;
+ voxDesc.useRgbBrightness = 0;
+ /*voxDesc.lights.x = 0.70710678; voxDesc.lights.y = 0.70710678; voxDesc.lights.z = 0;*/
+ voxDesc.light.lights.x = 512; voxDesc.light.lights.y = 512; voxDesc.light.lights.z = (real_t)(graphEnv->zpro);
+ voxDesc.light.ambient = 0.5; voxDesc.light.gain = 1.0;
+ voxDesc.light.cosine = 0.0; voxDesc.light.scintCos = 0.0;
+ voxDesc.kernSize = 2; voxDesc.kernType = RENDER_NORM_KERNEL_GAUSS;
+ voxDesc.voxColour = NULL;
+ memcpy(&newTexDesc, texDesc, sizeof(tex_desc));
+ newTexDesc.floatType = 0;
+ newTexDesc.minVal = 0.0; newTexDesc.maxVal = 1e6;
+ return RenderCubeVoxel(geomData, graphEnv, &newTexDesc, &voxDesc);
+}
+
+
+static norm_kernel_desc *RenderCubeEnsureNormKernel(voxel_desc *voxDesc)
+{
+ if (voxDesc->light.ambient >= 0)
+ {
+ norm_kernel_desc *kDesc;
+ int ksize;
+
+ switch (voxDesc->kernType)
+ {
+ case RENDER_NORM_KERNEL_HOMO: kDesc = &NormalizeKernelHomo; break;
+ case RENDER_NORM_KERNEL_LINEAR: kDesc = &NormalizeKernelLinear; break;
+ case RENDER_NORM_KERNEL_GAUSS: kDesc = &NormalizeKernelGauss; break;
+ default: kDesc = &NormalizeKernelDummy; return kDesc;
+ }
+ if (kDesc->region != voxDesc->kernSize)
+ {
+ int i, j, k;
+ real_t *kernel;
+
+ if (kDesc->kernel != NULL)
+ {
+ free(kDesc->kernel); kDesc->kernel = NULL; kDesc->region = -1;
+ }
+ if ((kDesc->region = voxDesc->kernSize) == 0) return kDesc;
+ ksize = 2 * voxDesc->kernSize + 1;
+ ksize = ksize * ksize * ksize;
+ if ((kDesc->kernel = (real_t*)malloc(ksize * sizeof(real_t))) == NULL)
+ return NULL;
+ kernel = kDesc->kernel;
+ /* This doesn't have to be efficient */
+ for (i=-voxDesc->kernSize; i<=voxDesc->kernSize; i++)
+ {
+ for (j=-voxDesc->kernSize; j<=voxDesc->kernSize; j++)
+ {
+ for (k=-voxDesc->kernSize; k<=voxDesc->kernSize; k++)
+ {
+ switch (voxDesc->kernType)
+ {
+ case RENDER_NORM_KERNEL_HOMO:
+ *kernel = 1.0;
+ break;
+ case RENDER_NORM_KERNEL_LINEAR:
+ *kernel = (real_t)(1.0 - sqrt(sqr(i) + sqr(j) + sqr(k)) / (sqrt(3) * voxDesc->kernSize));
+ break;
+ case RENDER_NORM_KERNEL_GAUSS:
+ *kernel = (real_t)(exp(-(sqr(i) + sqr(j) + sqr(k)) / 2));
+ break;
+ default:
+ break;
+ }
+ kernel++;
+ }
+ }
+ }
+ /*kernel = kDesc->kernel;
+ for (i=-voxDesc->kernSize; i<=voxDesc->kernSize; i++)
+ {
+ for (j=-voxDesc->kernSize; j<=voxDesc->kernSize; j++)
+ {
+ printf("%d,%d: ", i, j);
+ for (k=-voxDesc->kernSize; k<=voxDesc->kernSize; k++)
+ {
+ printf("%f ", *kernel); kernel++;
+ }
+ printf("\n");
+ }
+ }*/
+ }
+ return kDesc;
+ }
+ return NULL;
+}
+
+
+
+/*
+ * Voxel renderer.
+ */
+
+int RenderCubeVoxel(const vertex_fp geomData[4], const graph_env *graphEnv, const tex_desc *texDesc, voxel_desc *voxDesc)
+{
+ vertex_fp t[3];
+ face faces[7];
+ vertex_fp pool[VERTICES_TOTAL];
+ vertex_p pool_p[VERTICES_TOTAL];
+ project_plane_desc ppd;
+ int segsPerLine;
+ render_desc renderDesc;
+ long miny_p, maxy_p;
+ int i, j;
+ double h;
+
+ /* standard renderer preamble (see RenderCube()) */
+ renderDesc.texbase = t;
+
+ CubeRenderInitTextures(geomData, texDesc, &renderDesc, 0);
+
+ renderDesc.faces = faces;
+ renderDesc.faces[0].first = pool; renderDesc.faces[0].first_p = pool_p;
+ renderDesc.graphEnv = (graph_env *)graphEnv;
+
+ renderDesc.org.x = (real_t)(geomData[0].x);
+ renderDesc.org.y = (real_t)(geomData[0].y);
+ renderDesc.org.z = (real_t)(geomData[0].z);
+
+ RenderCubeClipCube(geomData, &renderDesc, 0);
+
+ /* Determine bounding box of entire cube */
+ miny_p = graphEnv->clipu + 1;
+ maxy_p = graphEnv->clipd - 1;
+ for (i=0; i<7; i++)
+ {
+ if (faces[i].vertices != 0)
+ {
+ if (faces[i].bBox.miny < miny_p) miny_p = faces[i].bBox.miny;
+ if (faces[i].bBox.maxy > maxy_p) maxy_p = faces[i].bBox.maxy;
+ }
+ }
+ /* vertical clipping */
+ if ((miny_p > graphEnv->clipu) || (maxy_p < graphEnv->clipd)) return 0;
+ if (miny_p < graphEnv->clipd) miny_p = graphEnv->clipd;
+ if (maxy_p > graphEnv->clipu) maxy_p = graphEnv->clipu;
+
+ /* Set rendering thresholds */
+ if ((texDesc->floatType != 0) || (texDesc->baseSize == 8))
+ {
+ ppd.pixelThresholdLowF = voxDesc->pixelThresholdLow;
+ ppd.pixelThresholdHighF = voxDesc->pixelThresholdHigh;
+ ppd.weightThresholdF = voxDesc->weightThreshold;
+ }
+ else
+ {
+ ppd.pixelThresholdLow = (voxDesc->pixelThresholdLow > (double)ULONG_MAX) ? ULONG_MAX : (unsigned long)(voxDesc->pixelThresholdLow);
+ ppd.pixelThresholdHigh = (voxDesc->pixelThresholdHigh > (double)ULONG_MAX) ? ULONG_MAX : (unsigned long)(voxDesc->pixelThresholdHigh);
+ ppd.weightThreshold = (voxDesc->weightThreshold > (double)ULONG_MAX) ? ULONG_MAX : (unsigned long)(voxDesc->weightThreshold);
+ /*printf("%ul:%f, %ul:%f, %ul:%f\n", ppd.pixelThresholdLow, voxDesc->pixelThresholdLow, ppd.pixelThresholdHigh, voxDesc->pixelThresholdHigh, ppd.weightThreshold, voxDesc->weightThreshold);*/
+ }
+ ppd.weightQuantisation = voxDesc->weightQuantisation;
+ ppd.zpro = (real_t)graphEnv->zpro;
+
+ /*
+ * Transform the lights into texture coordinates. This is done by applying the
+ * same rotations to the lightsource that are necessary to rotate the cube into
+ * a standard orthonormal 3D base.
+ */
+ if ((ppd.lightsAmbient = (real_t)(voxDesc->light.ambient)) >= 0)
+ {
+ vertex_fp lights;
+ real_t gain;
+
+ if ((gain = (real_t)(voxDesc->light.gain)) < 0) gain = 0.0;
+ if ((ppd.lightsCos = (real_t)(voxDesc->light.cosine)) > 0.999) ppd.lightsCos = 0.999f;
+ ppd.lightsScale = (real_t)(1 / (1.0 - ppd.lightsCos));
+ if ((ppd.lightsScintCos = (real_t)(voxDesc->light.scintCos)) > 0.999) ppd.lightsScintCos = 0.999f;
+ ppd.lightsScintScale = (real_t)(gain / (1.0 - ppd.lightsScintCos));
+
+ /* Translate light coordinates into texture coordinates */
+ lights.x = voxDesc->light.lights.x - geomData[0].x;
+ lights.y = voxDesc->light.lights.y - geomData[0].y;
+ lights.z = voxDesc->light.lights.z - geomData[0].z;
+
+#if 0
+ rotation_desc rd[3];
+
+ RenderCubeDetermineRotation(geomData+1, rd);
+
+ /* Rotate light into texture coordinates */
+ h = rd[2].cos * lights.x + rd[2].sin * lights.y;
+ lights.y = -rd[2].sin * lights.x + rd[2].cos * lights.y;
+ lights.x = h;
+ h = rd[1].cos * lights.x + rd[1].sin * lights.z;
+ lights.z = -rd[1].sin * lights.x + rd[1].cos * lights.z;
+ lights.x = h;
+ h = rd[0].cos * lights.y + rd[0].sin * lights.z;
+ lights.z = -rd[0].sin * lights.y + rd[0].cos * lights.z;
+ lights.y = h;
+
+ ppd.lights.x = lights.x;
+ ppd.lights.y = lights.y;
+ ppd.lights.z = lights.z;
+#else
+
+#define PROJECT_LIGHT_SOURCE(n,c) \
+ h = sqr(geomData[n].x) + sqr(geomData[n].y) + sqr(geomData[n].z); \
+ if (h != 0) \
+ { \
+ h = 1/sqrt(h); ppd.lights.c = (real_t)(h * (geomData[n].x * (lights.x-geomData[0].x) + geomData[n].y * (lights.y-geomData[0].y) + geomData[n].z * (lights.z)-geomData[0].z)); \
+ } \
+
+ PROJECT_LIGHT_SOURCE(1,x);
+ PROJECT_LIGHT_SOURCE(2,y);
+ PROJECT_LIGHT_SOURCE(3,z);
+#endif
+
+ ppd.kDesc = RenderCubeEnsureNormKernel(voxDesc);
+ }
+ ppd.voxColour = voxDesc->voxColour;
+
+ /* Render hidden surfaces first */
+ if (graphEnv->bbox_colour != 0xffffffff)
+ {
+ RenderCubeBBox(&renderDesc, 1);
+ }
+
+ /* Now render the voxels */
+ for (i=maxy_p; i>=miny_p; i--)
+ {
+ /*printf("line %d\n", i);*/
+ segsPerLine = 0;
+ for (j=0; j<7; j++)
+ {
+ if (faces[j].vertices != 0)
+ {
+ RenderCubeGetScanline(i, j, &renderDesc, 0);
+ if (renderDesc.found != 0)
+ {
+ ppd.ppi[segsPerLine].left_g = renderDesc.left_g;
+ ppd.ppi[segsPerLine].right_g = renderDesc.right_g;
+ ppd.ppi[segsPerLine].left_t = renderDesc.left_t;
+ ppd.ppi[segsPerLine].right_t = renderDesc.right_t;
+ ppd.ppi[segsPerLine].left_p = renderDesc.left_p;
+ ppd.ppi[segsPerLine].right_p = renderDesc.right_p;
+ ppd.segs = ++segsPerLine;
+ }
+ }
+ }
+ /* need at least two segments for further computation */
+ if (segsPerLine < 2) continue;
+
+ CubeRenderNormalizePlane(&ppd);
+
+ switch (texDesc->baseSize)
+ {
+ case 1: RenderCubeVoxLine1(i, &ppd, &renderDesc); break;
+ case 2: RenderCubeVoxLine2(i, &ppd, &renderDesc); break;
+ case 3:
+ if (voxDesc->useRgbBrightness == 0)
+ RenderCubeVoxLine3(i, &ppd, &renderDesc);
+ else
+ RenderCubeVoxLine3B(i, &ppd, &renderDesc);
+ break;
+ case 4:
+ if (texDesc->floatType == 0)
+ RenderCubeVoxLine4(i, &ppd, &renderDesc);
+ else
+ RenderCubeVoxLine4F(i, &ppd, &renderDesc);
+ break;
+ case 8: RenderCubeVoxLine8F(i, &ppd, &renderDesc); break;
+ default: fprintf(stderr, "Bad base type size (%d)\n", texDesc->baseSize); exit(-1); break;
+ }
+ }
+
+ if (graphEnv->bbox_colour != 0xffffffff)
+ {
+ RenderCubeBBox(&renderDesc, 0);
+ }
+
+#if 0
+ if (voxDesc->lightsAmbient >= 0)
+ {
+ vertex_p from, to;
+
+ printf("Lights at %f, %f, %f\n", ppd.lights.x, ppd.lights.y, ppd.lights.z);
+ from.x = (geomData[0].x * graphEnv->zpro) / geomData[0].z;
+ from.y = (geomData[0].y * graphEnv->zpro) / geomData[0].z;
+ to.x = ((geomData[0].x + ppd.lights.x) * graphEnv->zpro) / (geomData[0].z + ppd.lights.z);
+ to.y = ((geomData[0].y + ppd.lights.y) * graphEnv->zpro) / (geomData[0].z + ppd.lights.z);
+ RenderLineSegment(&from, &to, &renderDesc, graphEnv->bbox_colour);
+ }
+#endif
+
+ return 0;
+}
+
+
+
+/*
+ * Functions for external use of the clipped cube.
+ */
+
+render_desc *RenderCubeBuild(const vertex_fp geomData[4], const graph_env *graphEnv)
+{
+ render_desc *renderDesc;
+
+ if ((renderDesc = (render_desc *)malloc(sizeof(render_desc))) == NULL)
+ return NULL;
+ if ((renderDesc->faces = (face *)malloc(7*sizeof(face))) == NULL)
+ {
+ free(renderDesc); return NULL;
+ }
+ if ((renderDesc->faces[0].first = (vertex_fp *)malloc(VERTICES_TOTAL * sizeof(vertex_fp))) == NULL)
+ {
+ free(renderDesc->faces); free(renderDesc); return NULL;
+ }
+ if ((renderDesc->faces[0].first_p = (vertex_p *)malloc(VERTICES_TOTAL * sizeof(vertex_p))) == NULL)
+ {
+ free(renderDesc->faces[0].first); free(renderDesc->faces); free(renderDesc); return NULL;
+ }
+ renderDesc->graphEnv = (graph_env *)graphEnv;
+ /* Setting the texture descriptor to NULL disables the calculation of left_t, right_t in
+ RenderCubeGetScanline. */
+ renderDesc->texDesc = NULL;
+
+ RenderCubeClipCube(geomData, renderDesc, 1);
+
+ return renderDesc;
+}
+
+
+
+void RenderCubeFreeDesc(render_desc *renderDesc)
+{
+ free(renderDesc->faces[0].first_p);
+ free(renderDesc->faces[0].first);
+ free(renderDesc->faces);
+ free(renderDesc);
+}
+
+
+
+/*
+ * This function rotates a cube into the standard orthonormal 3D-base and
+ * logs the necessary rotations. Rotation is done in z,y,x order, so in
+ * order to rotate a standard base such that its axes coincide with the
+ * input cube's the rotations have to be applied in x,y,z order with
+ * negative sin values.
+ */
+void RenderCubeDetermineRotation(const vertex_fp *base, rotation_desc *rd)
+{
+ vertex_fp e[3];
+ double len;
+ double c, s, h;
+ int i;
+
+ /* Normalize the base */
+ for (i=0; i<3; i++)
+ {
+ len = sqr(base[i].x) + sqr(base[i].y) + sqr(base[i].z);
+ h = 1/sqrt(len);
+ e[i].x = (real_t)(h*base[i].x); e[i].y = (real_t)(h*base[i].y); e[i].z = (real_t)(h*base[i].z);
+ }
+
+ /* First rotate x-vector around z into xz plane */
+ len = sqr(e[0].x) + sqr(e[0].y);
+ if (fabs(len) <= 1e-12)
+ {
+ rd[2].sin = 0.0; rd[2].cos = 1;
+ }
+ else
+ {
+ h = 1/sqrt(len); c = h * e[0].x; s = h * e[0].y;
+ rd[2].sin = s; rd[2].cos = c;
+ for (i=0; i<3; i++)
+ {
+ h = c*e[i].x + s*e[i].y;
+ e[i].y = (real_t)(-s*e[i].x + c*e[i].y);
+ e[i].x = (real_t)h;
+ /*printf("RotZ: %f, %f, %f\n", e[i].x, e[i].y, e[i].z);*/
+ }
+ }
+ /* Then rotate x-vector around y to x axis */
+ len = sqr(e[0].x) + sqr(e[0].z);
+ h = 1/sqrt(len); c = h * e[0].x; s = h * e[0].z;
+ rd[1].sin = s; rd[1].cos = c;
+ for (i=0; i<3; i++)
+ {
+ h = c*e[i].x + s*e[i].z;
+ e[i].z = (real_t)(-s*e[i].x + c*e[i].z);
+ e[i].x = (real_t)h;
+ /*printf("RotY: %f, %f, %f\n", e[i].x, e[i].y, e[i].z);*/
+ }
+ /* Finally rotate y-vector around x to y-axis */
+ len = sqr(e[1].y) + sqr(e[1].z);
+ h = 1/sqrt(len); c = h * e[1].y; s = h * e[1].z;
+ rd[0].sin = s; rd[0].cos = c;
+ for (i=0; i<3; i++)
+ {
+ h = c*e[i].y + s*e[i].z;
+ e[i].z = (real_t)(-s*e[i].y + c*e[i].z);
+ e[i].y = (real_t)h;
+ /*printf("RotX: %f, %f, %f\n", e[i].x, e[i].y, e[i].z);*/
+ }
+}
+
+
+
+/*
+ * This function can be called to get the 3D coordinates of the intersection of a
+ * line from (0,0) through (x_p, y_p) and the cube. It requires renderDesc to be
+ * set up by the function RenderCubeBuild.
+ */
+
+int RenderCubeGetPosition(int x_p, int y_p, vertex_fp *pos, render_desc *renderDesc)
+{
+ int i, status;
+ face *cface;
+ real_t h, zpro, x_r;
+
+ status = 0; zpro = (real_t)(renderDesc->graphEnv->zpro); x_r = (real_t)x_p;
+ for (i=0; (i<7) && (status == 0); i++)
+ {
+ cface = renderDesc->faces + i;
+ if (renderDesc->faces[i].vertices > 0)
+ {
+ if ((y_p >= cface->bBox.miny) && (y_p <= cface->bBox.maxy))
+ {
+ RenderCubeGetScanline(y_p, i, renderDesc, 1);
+ if (renderDesc->found != 0)
+ {
+ if ((x_p >= renderDesc->left_p) && (x_p <= renderDesc->right_p))
+ {
+ pos->x = renderDesc->right_g.x - renderDesc->left_g.x;
+ pos->y = renderDesc->right_g.y - renderDesc->left_g.y;
+ pos->z = renderDesc->right_g.z - renderDesc->left_g.z;
+ h = pos->x * zpro - pos->z * x_r;
+ if (h != 0)
+ {
+ h = - (renderDesc->left_g.x * zpro - renderDesc->left_g.z * x_r) / h;
+ }
+ if (h < 0.0) h = 0.0;
+ if (h > 1.0) h = 1.0;
+ pos->x = renderDesc->left_g.x + h * pos->x;
+ pos->y = renderDesc->left_g.y + h * pos->y;
+ pos->z = renderDesc->left_g.z + h * pos->z;
+ status = 1;
+ }
+ }
+ }
+ }
+ }
+ return status;
+}
+
+
+
+/* Used for plotting the lines in various depths */
+#define RENDER_LINE_CORE_H(d,col) \
+ while (x0 <= x1) \
+ { \
+ *d = col; \
+ if (h < 0) h += delta1; else {h += delta2; destPtr.c += step;} \
+ x0++; d++; \
+ }
+
+#define RENDER_LINE_CORE_V(d,col) \
+ while (y0 != y1) \
+ { \
+ *d = col; \
+ if (h < 0) h += delta1; else {h += delta2; d++;} \
+ y0 += stepy; destPtr.c += step; \
+ } \
+ *d = col;
+
+/*
+ * Render a line (for drawing the object's bounding box). Write a line-plotter explicitly so it
+ * can be easily combined with the rest of the renderer.
+ */
+
+void RenderLineSegment(const vertex_p *from, const vertex_p *to, const render_desc *renderDesc, long colour)
+{
+ int x0, y0, x1, y1, h, step, delta1, delta2, baseSize;
+ graph_env *graphEnv;
+ union {uint8 *c; uint16 *s; rgb_pixel *r; uint32 *l; float *f; double *d;} destPtr;
+ rgb_pixel rgb_colour;
+
+ graphEnv = renderDesc->graphEnv;
+ baseSize = renderDesc->texDesc->baseSize;
+
+ /* Order vertices from left to right */
+ if (from->x < to->x)
+ {
+ x0 = from->x; y0 = from->y; x1 = to->x; y1 = to->y;
+ }
+ else
+ {
+ x0 = to->x; y0 = to->y; x1 = from->x; y1 = from->y;
+ }
+ /* Completely off-screen? */
+ if ((x0 > graphEnv->clipr) || (x1 < graphEnv->clipl)) return;
+ if ((y0 > graphEnv->clipu) && (y1 > graphEnv->clipu)) return;
+ if ((y0 < graphEnv->clipd) && (y1 < graphEnv->clipd)) return;
+
+ /*printf("%4d,%4d,%4d,%4d\n", x0, y0, x1, y1); fflush(stdout);*/
+
+ /* Horizontal clipping */
+ if (x0 < graphEnv->clipl)
+ {
+ y0 = (y0 + y1 - ((y1 - y0) * (x0 - 2*(graphEnv->clipl) + x1)) / (x1 - x0)) >> 1;
+ x0 = graphEnv->clipl;
+ }
+ if (x1 > graphEnv->clipr)
+ {
+ y1 = (y0 + y1 - ((y1 - y0) * (x0 - 2*(graphEnv->clipr) + x1)) / (x1 - x0)) >> 1;
+ x1 = graphEnv->clipr;
+ }
+
+ /* After horizontal clipping both y-values can be outside the clipping rectangle! */
+ if ((y0 > graphEnv->clipu) && (y1 > graphEnv->clipu)) return;
+ if ((y0 < graphEnv->clipd) && (y1 < graphEnv->clipd)) return;
+
+ /* Vertical clipping */
+ if ((y0 > graphEnv->clipu) || (y1 > graphEnv->clipu))
+ {
+ h = (x0 + x1 - ((x1 - x0) * (y0 - 2*(graphEnv->clipu) + y1)) / (y1 - y0)) >> 1;
+ if (y0 > graphEnv->clipu)
+ {
+ y0 = graphEnv->clipu; x0 = h;
+ }
+ else
+ {
+ y1 = graphEnv->clipu; x1 = h;
+ }
+ }
+ if ((y0 < graphEnv->clipd) || (y1 < graphEnv->clipd))
+ {
+ h = (x0 + x1 - ((x1 - x0) * (y0 - 2*(graphEnv->clipd) + y1)) / (y1 - y0)) >> 1;
+ if (y0 < graphEnv->clipd)
+ {
+ y0 = graphEnv->clipd; x0 = h;
+ }
+ else
+ {
+ y1 = graphEnv->clipd; x1 = h;
+ }
+ }
+
+ /*printf("%4d,%4d,%4d,%4d [%4d,%4d,%4d,%4d]\n", x0, y0, x1, y1, graphEnv->clipl, graphEnv->clipr, graphEnv->clipd, graphEnv->clipu); fflush(stdout);*/
+
+ destPtr.c = (uint8*)(graphEnv->dest) + (graphEnv->midy - y0) * (graphEnv->lineadd)
+ + (graphEnv->midx + x0) * baseSize;
+
+ /* vertical stepping in negative logical coordinates steps in positive physical coordinates */
+ step = (y1 < y0) ? graphEnv->lineadd : -graphEnv->lineadd;
+
+ if (baseSize == 3)
+ {
+ rgb_colour.r = colour & 0xff; rgb_colour.g = (colour >> 8) & 0xff; rgb_colour.b = (colour >> 16) & 0xff;
+ }
+
+ /* dx is always positive. dy isn't */
+ h = (y1 - y0); if (h < 0) h = -h;
+ if ((x1 - x0) >= h)
+ {
+ delta1 = 2*(y1 - y0); if (delta1 < 0) delta1 = -delta1;
+ delta2 = delta1 - 2*(x1 - x0);
+ h = delta1 - (x1 - x0);
+
+ switch (baseSize)
+ {
+ case 1:
+ {
+ RENDER_LINE_CORE_H(destPtr.c, (uint8)colour);
+ }
+ break;
+ case 2:
+ {
+ RENDER_LINE_CORE_H(destPtr.s, (uint16)colour);
+ }
+ break;
+ case 3:
+ {
+ RENDER_LINE_CORE_H(destPtr.r, rgb_colour);
+ }
+ break;
+ case 4:
+ if ((renderDesc->texDesc == NULL) || (renderDesc->texDesc->floatType == 0))
+ {
+ RENDER_LINE_CORE_H(destPtr.l, (uint32)colour);
+ }
+ else
+ {
+ float fpcol = (float)(renderDesc->texDesc->maxVal);
+ RENDER_LINE_CORE_H(destPtr.f, fpcol);
+ }
+ break;
+ case 8:
+ {
+ double fpcol = (double)(renderDesc->texDesc->maxVal);
+ RENDER_LINE_CORE_H(destPtr.d, fpcol);
+ }
+ break;
+ default: break;
+ }
+ }
+ else
+ {
+ int stepy;
+
+ stepy = (y1 < y0) ? -1 : 1;
+ delta1 = 2*(x1 - x0);
+ h = (y1 - y0); if (h < 0) h = -h;
+ delta2 = delta1 - 2*h;
+ h = delta1 - h;
+
+ switch (baseSize)
+ {
+ case 1:
+ {
+ RENDER_LINE_CORE_V(destPtr.c, (uint8)colour);
+ }
+ break;
+ case 2:
+ {
+ RENDER_LINE_CORE_V(destPtr.s, (uint16)colour);
+ }
+ break;
+ case 3:
+ {
+ RENDER_LINE_CORE_V(destPtr.r, rgb_colour);
+ }
+ break;
+ case 4:
+ if ((renderDesc->texDesc == NULL) || (renderDesc->texDesc->floatType == 0))
+ {
+ RENDER_LINE_CORE_V(destPtr.l, (uint32)colour);
+ }
+ else
+ {
+ float fpcol = (float)(renderDesc->texDesc->maxVal);
+ RENDER_LINE_CORE_V(destPtr.f, fpcol);
+ }
+ break;
+ case 8:
+ {
+ double fpcol = (double)(renderDesc->texDesc->maxVal);
+ RENDER_LINE_CORE_V(destPtr.d, fpcol);
+ }
+ break;
+ default: break;
+ }
+ }
+}
+
+
+
+void Render3DLine(const vertex_fp *from, const vertex_fp *to, const render_desc *renderDesc, long colour)
+{
+ const graph_env *ge = renderDesc->graphEnv;
+
+ if ((from->z >= ge->clipz) || (to->z >= ge->clipz))
+ {
+ vertex_fp v1, v2;
+ vertex_p p1, p2;
+ double h;
+
+ memcpy(&v1, from, sizeof(vertex_fp));
+ memcpy(&v2, to, sizeof(vertex_fp));
+
+ /* do z-clipping if necessary */
+ if ((from->z < ge->clipz) || (to->z < ge->clipz))
+ {
+ vertex_fp *cv;
+
+ h = (-v1.z + 2*ge->clipz - v2.z) / (v2.z - v1.z);
+ cv = (from->z < ge->clipz) ? &v1 : &v2;
+ cv->x = 0.5*(v1.x + v2.x + h * (v2.x - v1.x));
+ cv->y = 0.5*(v1.y + v2.y + h * (v2.y - v1.y));
+ cv->z = ge->clipz;
+ }
+
+ /* project to 2D coordinates */
+ h = (ge->zpro) / v1.z;
+ p1.x = (long)(h * v1.x);
+ p1.y = (long)(h * v1.y);
+ h = (ge->zpro) / v2.z;
+ p2.x = (long)(h * v2.x);
+ p2.y = (long)(h * v2.y);
+
+ /* and finally render it */
+ RenderLineSegment(&p1, &p2, renderDesc, colour);
+ }
+}
+
+
+
+
+
+/*
+ * Shaded polygons
+ */
+
+#define POLYSHADE_BUILD_GREY_FULL \
+ { \
+ real_t lcos, scos; \
+ uint32 pixel; \
+ lcos = cospos - lcosine; if (lcos < 0.0) lcos = 0.0; else lcos *= lweight; \
+ scos = cospos - scosine; if (scos < 0.0) scos = 0.0; else scos *= sweight; \
+ pixel = (uint32)(colour * (ambient + (1-ambient)*lcos + gain*scos)); \
+ *destPtr = (pixel > 0xff) ? 0xff : (uint8)pixel; \
+ }
+
+#define POLYSHADE_BUILD_GREY_FAST \
+ *destPtr = (uint8)((colour * (cospos + 1)) / 2);
+
+#define POLYSHADE_BUILD_RGB_FULL \
+ { \
+ real_t lcos, scos; \
+ uint32 pixel; \
+ lcos = cospos - lcosine; if (lcos < 0.0) lcos = 0.0; else lcos *= lweight; \
+ scos = cospos - scosine; if (scos < 0.0) scos = 0.0; else scos *= sweight; \
+ lcos = (ambient + (1-ambient)*lcos); scos = gain*scos*colgrey; \
+ pixel = (uint32)( red * lcos + scos); destPtr[0] = (pixel > 0xff) ? 0xff : (uint8)pixel; \
+ pixel = (uint32)(green * lcos + scos); destPtr[1] = (pixel > 0xff) ? 0xff : (uint8)pixel; \
+ pixel = (uint32)( blue * lcos + scos); destPtr[2] = (pixel > 0xff) ? 0xff : (uint8)pixel; \
+ }
+
+#define POLYSHADE_BUILD_RGB_FAST \
+ { \
+ real_t lw = (cospos+1)/2; \
+ uint32 cc; \
+ cc = (uint32)(red * lw); destPtr[0] = (uint8)cc; \
+ cc = (uint32)(green * lw); destPtr[1] = (uint8)cc; \
+ cc = (uint32)(blue * lw); destPtr[2] = (uint8)cc; \
+ }
+
+#ifdef POLYSHADE_RENDER_EXPERIMENTAL
+
+#define INIT_POLYSHADE_SIDE(side) \
+ side##_ctr = proj[side##_idx].y - proj[side##_idx+1].y; \
+ h = (real_t)((side##_ctr == 0) ? 1.0 : (1.0 / side##_ctr)); \
+ side##_dp = h * (proj[side##_idx+1].x - proj[side##_idx].x); \
+ side##_dc = h * (cosine[side##_idx+1] - cosine[side##_idx]); \
+ if (side##_ctr < 0) \
+ { \
+ side##_p = (real_t)(proj[side##_idx+1].x) + 0.5; side##_c = cosine[side##_idx+1]; \
+ side##_ctr = -side##_ctr; \
+ } \
+ else \
+ { \
+ side##_p = (real_t)(proj[side##_idx].x) + 0.5; side##_c = cosine[side##_idx]; \
+ }
+
+#define UPDATE_POLYSHADE_SIDE(side) \
+ if (side##_ctr-- <= 0) \
+ { \
+ side##_idx += side##_step; \
+ if (side##_idx < 0) side##_idx = number-1; \
+ if (side##_idx >= number) side##_idx = 0; \
+ INIT_POLYSHADE_SIDE(side) \
+ } \
+ else \
+ { \
+ side##_p += side##_dp; side##_c += side##_dc; \
+ }
+
+#define POLYSHADE_LINE_LOOP(PIXSIZE, BUILD_PIXEL) \
+ destLine = (uint8*)(graphEnv->dest) + (graphEnv->midy - maxy) * (graphEnv->lineadd) + (graphEnv->midx) * PIXSIZE; \
+ for (i=maxy; i>=miny; i--) \
+ { \
+ int xlp, xrp; \
+ xlp = (int)left_p; \
+ if (xlp <= graphEnv->clipr) \
+ { \
+ xrp = (int)right_p; \
+ if (xrp >= graphEnv->clipl) \
+ { \
+ real_t cospos, cosstep; \
+ if (xlp > xrp) {printf("l %d, x %d %d, i %d %d\n", i, xlp, xrp, left_idx, right_idx); for (n=0; n<number; n++) printf("%d: %f,%f,%f: %d %d\n", n, vert[n].x, vert[n].y, vert[n].z, proj[n].x, proj[n].y); xrp = (int)left_p; xlp = (int)right_p;} \
+ h = (real_t)((xrp == xlp) ? 1 : xrp - xlp); \
+ cospos = left_c; cosstep = (right_c - left_c) / h; \
+ if (xlp < graphEnv->clipl) \
+ { \
+ cospos += cosstep * (graphEnv->clipl - xlp); xlp = graphEnv->clipl; \
+ } \
+ if (xrp > graphEnv->clipr) xrp = graphEnv->clipr; \
+ destPtr = destLine + xlp * PIXSIZE; \
+ for (; xlp <= xrp; xlp++, destPtr += PIXSIZE) \
+ { \
+ BUILD_PIXEL \
+ cospos += cosstep; \
+ } \
+ } \
+ } \
+ destLine += graphEnv->lineadd; \
+ UPDATE_POLYSHADE_SIDE(left) \
+ UPDATE_POLYSHADE_SIDE(right) \
+ }
+
+#else
+
+#define POLYSHADE_LINE_LOOP(PIXSIZE, BUILD_PIXEL) \
+ destLine = (uint8*)(graphEnv->dest) + (graphEnv->midy - maxy) * (graphEnv->lineadd) + (graphEnv->midx) * PIXSIZE; \
+ for (i=(maxy-miny); i>=0; i--, destLine += graphEnv->lineadd, zbLine += zbWidth) \
+ { \
+ int xlp, xrp; \
+ real_t cospos, cosstep; \
+ int zpos, zstep; \
+ xlp = PolyShadeLines[i].left.xp >> FIXPOINT_PREC; xrp = PolyShadeLines[i].right.xp >> FIXPOINT_PREC; \
+ if ((xlp <= graphEnv->clipr) && (xrp >= graphEnv->clipl)) \
+ { \
+ cospos = PolyShadeLines[i].left.c; zpos = PolyShadeLines[i].left.z; \
+ h = (real_t)((xlp == xrp) ? 1.0 : 1.0 / (xrp - xlp)); \
+ cosstep = h * (PolyShadeLines[i].right.c - cospos); \
+ zstep = (int)(h * (PolyShadeLines[i].right.z - zpos)); \
+ if (xlp < graphEnv->clipl) {cospos += (graphEnv->clipl - xlp) * cosstep; zpos += (graphEnv->clipl - xlp) * zstep; xlp = graphEnv->clipl;} \
+ if (xrp > graphEnv->clipr) xrp = graphEnv->clipr; \
+ destPtr = destLine + xlp * PIXSIZE; zbPtr = zbLine + xlp; \
+ for (; xlp <= xrp; xlp++, destPtr += PIXSIZE, zbPtr++, cospos += cosstep, zpos += zstep) \
+ { \
+ if ((zbuffer_t)(zpos >> FIXPOINT_PREC) < *zbPtr) \
+ { \
+ *zbPtr = (zbuffer_t)(zpos >> FIXPOINT_PREC); \
+ BUILD_PIXEL \
+ } \
+ } \
+ } \
+ }
+
+
+typedef struct polyshade_side_t {
+ int xp;
+ int z;
+ real_t c;
+} polyshade_side_t;
+
+typedef struct polyshade_line_t {
+ polyshade_side_t left;
+ polyshade_side_t right;
+} polyshade_line_t;
+
+static int PolyShadeLineSize = 0;
+static polyshade_line_t *PolyShadeLines = NULL;
+
+
+static int RenderInitZBuffer(const graph_env *graphEnv, mesh_desc *meshDesc)
+{
+ int width;
+ unsigned int total;
+
+ width = graphEnv->clipr - graphEnv->clipl + 1;
+ total = width * (graphEnv->clipu - graphEnv->clipd + 1);
+ if (meshDesc->zbuffSize != total)
+ {
+ if (meshDesc->zbuffer != NULL) free(meshDesc->zbuffer);
+ meshDesc->zbuffSize = total;
+ meshDesc->zbuffer = (zbuffer_t*)malloc(total * sizeof(zbuffer_t));
+ }
+ memset(meshDesc->zbuffer, 0xff, total * sizeof(zbuffer_t));
+
+ return width;
+}
+
+#endif
+
+/* Render a (convex!) polygon using shading */
+int RenderShadedPolygon(int numVert, const vertex_fp *vertices, const vertex_fp *normals, unsigned int colour, const graph_env *graphEnv, const light_desc *light, const vertex_fp *real_norm, zbuffer_t *zbuffer)
+{
+ vertex_fp *vert, *vr, *vw;
+ vertex_p *proj, *pr, *pw;
+ real_t *cosine, *cr, *cw;
+ real_t clipz, zpro;
+ real_t h, orient;
+ int miny, maxy, minx, maxx, lastY;
+ int number;
+ int i, n;
+#ifdef POLYSHADE_RENDER_EXPERIMENTAL
+ int left_idx, right_idx, left_step, right_step;
+ real_t left_p, left_dp, right_p, right_dp;
+ real_t left_c, left_dc, right_c, right_dc;
+ int left_ctr, right_ctr;
+ vertex_fp dir1, dir2, snorm;
+ const vertex_fp *snormp;
+#endif
+ uint8 *destLine, *destPtr;
+ uint8 red, green, blue;
+ real_t lcosine, scosine, lweight, sweight, ambient, gain;
+ /* zBuffer */
+ zbuffer_t *zbLine, *zbPtr;
+ int zbWidth;
+
+ clipz = (real_t)(graphEnv->clipz); zpro = (real_t)(graphEnv->zpro);
+
+ /* Early termination of off-screen polygons */
+ minx = INT_MAX; maxx = INT_MIN; miny = INT_MAX; maxy = INT_MIN;
+ for (i=0; i<numVert; i++)
+ {
+ int xp, yp;
+
+ /* The effects of this can't be predicted without explicit z-clipping */
+ if (vertices[i].z <= 0) break;
+ h = zpro / vertices[i].z;
+ xp = (int)(h * vertices[i].x); yp = (int)(h * vertices[i].y);
+ if (xp < minx) minx = xp; if (xp > maxx) maxx = xp;
+ if (yp < miny) miny = yp; if (yp > maxy) maxy = yp;
+ }
+ if (i >= numVert)
+ {
+ if ((maxx < graphEnv->clipl) || (minx > graphEnv->clipr) || (maxy < graphEnv->clipd) || (miny > graphEnv->clipu)) return 0;
+ }
+
+ /* +1 vertex for closing the outline +3 vertices for clipping effects (2 y, 1 z) */
+ vert = (vertex_fp*)malloc((numVert + 4) * sizeof(vertex_fp));
+ proj = (vertex_p*)malloc((numVert + 4) * sizeof(vertex_p));
+ cosine = (real_t*)malloc((numVert + 4) * sizeof(real_t));
+
+ vr = vert+3; memcpy(vr, vertices, numVert*sizeof(vertex_fp));
+ vr[numVert] = vertices[0];
+ cw = cosine+3;
+
+ /* Surface orientation just doesn't work well */
+#if 0
+ if (real_norm == NULL)
+ {
+ /* Determine surface orientation */
+ dir2.x = vertices[2].x - vertices[1].x; dir1.x = vertices[1].x - vertices[0].x;
+ dir2.y = vertices[2].y - vertices[1].y; dir1.y = vertices[1].y - vertices[0].y;
+ dir2.z = vertices[2].z - vertices[1].z; dir1.z = vertices[1].z - vertices[0].z;
+ snorm.x = dir1.y * dir2.z - dir1.z * dir2.y;
+ snorm.y = dir1.z * dir2.x - dir1.x * dir2.z;
+ snorm.z = dir1.x * dir2.y - dir1.y * dir2.x; /* signed surface normal */
+ snormp = &snorm;
+ }
+ else
+ {
+ snormp = real_norm;
+ }
+ /* If the side facing us is the backside, mirror the normal vectors */
+ h = snormp->x * vertices[0].x + snormp->y * vertices[0].y + snormp->z * vertices[0].z;
+ if (h < 0) orient = -1; else orient = 1;
+#else
+ orient = 1;
+#endif
+ /* Calculate the scalar products of the vertices with the light vector */
+ for (i=0; i<numVert; i++)
+ {
+ vertex_fp l;
+
+ l.x = (light->lights.x - vertices[i].x);
+ l.y = (light->lights.y - vertices[i].y);
+ l.z = (light->lights.z - vertices[i].z);
+ h = l.x * l.x + l.y * l.y + l.z * l.z;
+ if (h < 1e-6) h = 1e-6f;
+ h = (real_t)(orient/sqrt(h));
+ cw[i] = h * ((normals[i].x * l.x) + (normals[i].y * l.y) + (normals[i].z * l.z));
+ }
+ cw[i] = cw[0];
+
+ number = 0; cr = cosine+3; vw = vert+2; cw = cosine+2; pw = proj+2;
+
+ /* z clipping */
+ for (i=0; i<numVert; i++)
+ {
+ if ((vr[0].z >= clipz) || (vr[1].z >= clipz))
+ {
+ if (vr[0].z >= clipz)
+ {
+ *vw++ = *vr; *cw++ = *cr;
+ pw->x = (long)((zpro * vr->x) / vr->z); pw->y = (long)((zpro * vr->y) / vr->z); pw++;
+ number++; if (number >= numVert+1) break;
+ }
+ if ((vr[0].z < clipz) || (vr[1].z < clipz))
+ {
+ h = (vr[0].z - 2 * clipz + vr[1].z) / (vr[1].z - vr[0].z);
+ vw->x = (real_t)(0.5*(vr[1].x + vr[0].x - h * (vr[1].x - vr[0].x)));
+ vw->y = (real_t)(0.5*(vr[1].y + vr[0].y - h * (vr[1].y - vr[0].y)));
+ vw->z = clipz;
+ *cw = (real_t)(0.5*(cr[1] + cr[0] - h * (cr[1] - cr[0])));
+ vw++; cw++;
+ pw->x = (long)((zpro * vr->x) / vr->z); pw->y = (long)((zpro * vr->y) / vr->z); pw++;
+ number++; if (number >= numVert+1) break;
+ }
+ }
+ vr++; cr++;
+ }
+ if (number == 0)
+ {
+#if (CUBE_RENDER_DEBUG > 0)
+ printf("PolyShade: void (z)\n");
+#endif
+ free(vert); free(cosine); free(proj);
+ return 0;
+ }
+ vr = vert+2; cr = cosine+2; pr = proj+2; *vw = *vr; *cw = *cr; *pw = *pr;
+
+#if (CUBE_RENDER_DEBUG > 0)
+ for (i=0; i<number; i++) printf("%d: %f %f %f\n", i, vr[i].x, vr[i].y, vr[i].z);
+#endif
+
+ miny = INT_MAX; maxy = INT_MIN; minx = INT_MAX; maxx = INT_MIN;
+ /* y clipping */
+ vw = vert; cw = cosine; pw = proj; n = 0;
+#if 1
+ lastY = (int)((zpro * vr[0].y) / vr[0].z);
+ for (i=0; i<number; i++)
+ {
+ vertex_fp v0, v1, *uv;
+ real_t c0, c1, *uc;
+ int modTwo;
+ int yp;
+
+ yp = (int)((zpro * vr[1].y) / vr[1].z);
+ v0 = vr[0]; v1 = vr[1]; c0 = cr[0]; c1 = cr[1]; modTwo = 0;
+ /* Clip upper bound */
+ if ((lastY <= graphEnv->clipu) || (yp <= graphEnv->clipu))
+ {
+ if ((lastY > graphEnv->clipu) || (yp > graphEnv->clipu))
+ {
+ h = (real_t)(zpro * (v1.y - v0.y) - (graphEnv->clipu + 0.5) * (v1.z - v0.z));
+ if (h != 0.0)
+ {
+ h = (real_t)( - (zpro * v0.y - (graphEnv->clipu + 0.5) * v0.z) / h);
+ if (lastY > graphEnv->clipu)
+ {
+ uv = &v0; uc = &c0;
+ }
+ else
+ {
+ uv = &v1; uc = &c1; modTwo = 1;
+ }
+ uv->x = v0.x + h * (v1.x - v0.x);
+ uv->y = v0.y + h * (v1.y - v0.y);
+ uv->z = v0.z + h * (v1.z - v0.z);
+ *uc = c0 + h * (c1 - c0);
+ }
+ }
+ }
+ if ((lastY >= graphEnv->clipd) || (yp >= graphEnv->clipd))
+ {
+ if ((lastY < graphEnv->clipd) || (yp < graphEnv->clipd))
+ {
+ h = (real_t)(zpro * (v1.y - v0.y) - (graphEnv->clipd - 0.5) * (v1.z - v0.z));
+ if (h != 0.0)
+ {
+ h = (real_t)( - (zpro * v0.y - (graphEnv->clipd - 0.5) * v0.z) / h);
+ if (lastY < graphEnv->clipd)
+ {
+ uv = &v0; uc = &c0;
+ }
+ else
+ {
+ uv = &v1; uc = &c1; modTwo = 1;
+ }
+ uv->x = v0.x + h * (v1.x - v0.x);
+ uv->y = v0.y + h * (v1.y - v0.y);
+ uv->z = v0.z + h * (v1.z - v0.z);
+ *uc = c0 + h * (c1 - c0);
+ }
+ }
+ }
+ if (((lastY <= graphEnv->clipu) || (yp <= graphEnv->clipu)) && ((lastY >= graphEnv->clipd) || (yp >= graphEnv->clipd)))
+ {
+ *vw++ = v0; *cw++ = c0;
+ pw->x = (long)((zpro * v0.x) / v0.z); pw->y = (long)((zpro * v0.y) / v0.z);
+ if (pw->y < miny) miny = pw->y; if (pw->y > maxy) maxy = pw->y;
+ if (pw->x < minx) minx = pw->x; if (pw->x > maxx) maxx = pw->x;
+ pw++; n++; if (n >= numVert+3) break;
+ if (modTwo != 0)
+ {
+ *vw++ = v1; *cw++ = c1;
+ pw->x = (long)((zpro * v1.x) / v1.z); pw->y = (long)((zpro * v1.y) / v1.z);
+ if (pw->y < miny) miny = pw->y; if (pw->y > maxy) maxy = pw->y;
+ if (pw->x < minx) minx = pw->x; if (pw->x > maxx) maxx = pw->x;
+ pw++; n++; if (n >= numVert+3) break;
+ }
+ }
+ vr++; cr++; lastY = yp;
+ }
+#else
+ lastY = pr[0].y;
+ for (i=0; i<number; i++)
+ {
+ vertex_p p0, p1, *up;
+ real_t c0, c1, *uc;
+ int modTwo;
+ int yp;
+
+ yp = pr[1].y;
+ p0 = pr[0]; p1 = pr[1]; c0 = cr[0]; c1 = cr[1]; modTwo = 0;
+ if ((lastY <= graphEnv->clipu) || (yp <= graphEnv->clipu))
+ {
+ if ((lastY > graphEnv->clipu) || (yp > graphEnv->clipu))
+ {
+ h = (yp - 2 * graphEnv->clipu - 1 + lastY) / (yp - lastY);
+ if (lastY > graphEnv->clipu)
+ {
+ up = &p0; uc = &c0;
+ }
+ else
+ {
+ up = &p1; uc = &c1; modTwo = 1;
+ }
+ up->x = (int)(0.5*(p1.x + p0.x - h * (p1.x - p0.x)));
+ up->y = graphEnv->clipu;
+ *uc = 0.5*(c1 + c0 - h * (c1 - c0));
+ }
+ }
+ if ((lastY >= graphEnv->clipd) || (yp >= graphEnv->clipd))
+ {
+ if ((lastY < graphEnv->clipd) || (yp < graphEnv->clipd))
+ {
+ h = (yp - 2 * graphEnv->clipd + 1 + lastY) / (yp - lastY);
+ if (lastY < graphEnv->clipd)
+ {
+ up = &p0; uc = &c0;
+ }
+ else
+ {
+ up = &p1; uc = &c1; modTwo = 1;
+ }
+ up->x = (int)(0.5*(p1.x + p0.x - h * (p1.x - p0.x)));
+ up->y = graphEnv->clipd;
+ *uc = 0.5*(c1 + c0 - h * (c1 - c0));
+ }
+ }
+ if (((lastY <= graphEnv->clipu) || (yp <= graphEnv->clipu)) && ((lastY >= graphEnv->clipd) || (yp >= graphEnv->clipd)))
+ {
+ *pw++ = p0; *cw++ = c0; n++;
+ if (p0.y < miny) miny = p0.y; if (p0.y > maxy) maxy = p0.y;
+ if (p0.x < minx) minx = p0.x; if (p0.x > maxx) maxx = p0.x;
+ if (n >= numVert+3) break;
+ if (modTwo != 0)
+ {
+ *pw++ = p1; *cw++ = c1; n++;
+ if (p1.y < miny) miny = p1.y; if (p1.y > maxy) maxy = p1.y;
+ if (p1/x < minx) minx = p1.x; if (p1.x > maxx) maxx = p1.x;
+ if (n >= numVert+3) break;
+ }
+ }
+ pr++; vr++;
+ }
+#endif
+ if (n == 0)
+ {
+#if (CUBE_RENDER_DEBUG > 0)
+ printf("PolyShade: void (y)\n");
+#endif
+ free(vert); free(cosine); free(proj);
+ return 0;
+ }
+ if ((minx > graphEnv->clipr) || (maxx < graphEnv->clipl))
+ {
+#if (CUBE_RENDER_DEBUG > 0)
+ printf("PolyShade: clipped all x\n");
+#endif
+ free(vert); free(cosine); free(proj);
+ return 0;
+ }
+ *vw = *vert; *cw = *cosine; *pw = *proj;
+ number = n;
+
+#if (CUBE_RENDER_DEBUG > 0)
+ printf("miny %d, maxy %d\n", miny, maxy);
+ for (i=0; i<number; i++) printf("%d: %f %f %f : %d %d\n", i, vert[i].x, vert[i].y, vert[i].z, proj[i].x, proj[i].y);
+#endif
+
+ /* Init lighting parameters */
+ if ((ambient = (real_t)(light->ambient)) >= 0)
+ {
+ lcosine = (real_t)(light->cosine); scosine = (real_t)(light->scintCos);
+ lweight = (lcosine == 1) ? 1 : 1 / (1 - lcosine);
+ sweight = (scosine == 0) ? 1 : 1 / (1 - scosine);
+ gain = (real_t)(light->gain);
+ }
+
+#ifdef POLYSHADE_RENDER_EXPERIMENTAL
+ /* Find the two topmost, non-horizontal bounding lines */
+ left_idx = -1; right_idx = -1;
+ for (n=0; n<number; n++)
+ {
+ if (((proj[n].y == maxy) || (proj[n+1].y == maxy)) && (proj[n].y != proj[n+1].y))
+ {
+ if (left_idx == -1) left_idx = n; else right_idx = n;
+ }
+ }
+ /* is ``polygon'' completely flat? Then just find leftmost / rightmost line */
+ if (right_idx < 0)
+ {
+ left_idx = 0; right_idx = 0;
+ for (i=1; i<number; i++)
+ {
+ if (proj[i].x < proj[left_idx].x) left_idx = i;
+ if (proj[i].x > proj[right_idx].x) right_idx = i;
+ }
+ }
+#if 0 /* Can't happen any more */
+ /* Did something serious go wrong? */
+ if (right_idx < 0)
+ {
+#if (CUBE_RENDER_DEBUG > 0)
+ fprintf(stderr, "Bad polygon:\n");
+ for (i=0; i<number; i++)
+ {
+ fprintf(stderr, "\t%d: v(%f,%f,%f), p(%4d,%4d), c%f\n", i, vert[i].x, vert[i].y, vert[i].z, proj[i].x, proj[i].y, cosine[i]);
+ }
+#endif
+ free(vert); free(cosine); free(proj);
+ return -1;
+ }
+#endif
+ /* Determine surface orientation */
+#if 1
+ h = snorm.x * vert[0].x + snorm.y * vert[0].y + snorm.z * vert[0].z;
+#else
+ dir1.x = vert[1].x / vert[1].z; dir1.y = vert[1].y / vert[1].z;
+ dir2.x = vert[2].x / vert[2].z - dir1.x; dir2.y = vert[2].y / vert[2].z - dir1.y;
+ dir1.x -= vert[0].x / vert[0].z; dir1.y -= vert[0].y / vert[0].z;
+ h = dir1.x * dir2.y - dir1.y * dir2.x;
+#endif
+ if (h <= 0) /* clockwise */
+ {
+ /* left side must have growing yp component */
+ if (proj[left_idx].y > proj[left_idx+1].y)
+ {
+ left_step = left_idx; left_idx = right_idx; right_idx = left_step;
+ }
+ left_step = -1; right_step = 1;
+ }
+ else /* counter-clockwise */
+ {
+ /* left side must have decreasing yp component */
+ if (proj[left_idx].y < proj[left_idx+1].y)
+ {
+ left_step = left_idx; left_idx = right_idx; right_idx = left_step;
+ }
+ left_step = 1; right_step = -1;
+ }
+
+ if (miny < graphEnv->clipd) miny = graphEnv->clipd;
+ if (maxy > graphEnv->clipu) maxy = graphEnv->clipu;
+
+ /*for (i=0; i<number; i++) {int xlp, ylp; xlp = (zpro*vert[i].x)/vert[i].z; ylp = (zpro*vert[i].y)/vert[i].z; if ((xlp != proj[i].x) || (ylp != proj[i].y)) printf("No match %d:%d,%d -- %d,%d\n", i, xlp, ylp, proj[i].x, proj[i].y);}*/
+
+ INIT_POLYSHADE_SIDE(left)
+ INIT_POLYSHADE_SIDE(right)
+
+#if (CUBE_RENDER_DEBUG > 0)
+ printf("left %d, right %d; ls %d, rs %d; lc %d, rc %d\n", left_idx, right_idx, left_step, right_step, left_ctr, right_ctr);
+#endif
+
+ /* Top bits of colour determine rgb / grey mode */
+ if ((colour & 0xff000000) != 0)
+ {
+ red = colour & 0xff; green = (colour >> 8) & 0xff; blue = (colour >> 16) & 0xff;
+ POLYSHADE_LINE_LOOP(3, POLYSHADE_BUILD_RGB_FAST)
+ }
+ else
+ {
+ POLYSHADE_LINE_LOOP(1, POLYSHADE_BUILD_GREY_FAST)
+ }
+
+#else
+
+ if (PolyShadeLineSize < (maxy-miny+1))
+ {
+ PolyShadeLineSize = (maxy-miny+1);
+ if (PolyShadeLines != NULL) free(PolyShadeLines);
+ PolyShadeLines = (polyshade_line_t*)malloc(PolyShadeLineSize * sizeof(polyshade_line_t));
+ }
+
+ for (i=(maxy-miny); i>=0; i--)
+ {
+ PolyShadeLines[i].left.xp = INT_MAX; PolyShadeLines[i].right.xp = INT_MIN;
+ }
+
+ zbWidth = (graphEnv->clipr - graphEnv->clipl + 1);
+ zbLine = zbuffer + ((graphEnv->midy - maxy) * zbWidth + graphEnv->midx);
+
+ /* Plot the outline into this structure */
+ for (n=0; n<number; n++)
+ {
+ polyshade_line_t *pl;
+ int xp, xpstep;
+ real_t c, cstep;
+ int z, zstep;
+ int yp, count, step;
+
+ xp = proj[n].x << FIXPOINT_PREC; yp = proj[n].y; c = cosine[n]; z = (int)((1<<FIXPOINT_PREC)*vert[n].z);
+ if ((count = proj[n+1].y - yp) < 0) {count = -count; step = -1;} else {step = 1;}
+ h = (real_t)((count == 0) ? 1.0 : 1.0 / ((real_t)count));
+ xpstep = (int)(h * ((proj[n+1].x << FIXPOINT_PREC) - xp));
+ cstep = h * (cosine[n+1] - c); zstep = (int)(h * (1<<FIXPOINT_PREC) * (vert[n+1].z - vert[n].z));
+ pl = PolyShadeLines + (yp - miny);
+ if (xp < pl->left.xp)
+ {
+ pl->left.xp = xp; pl->left.c = c; pl->left.z = z;
+ }
+ if (xp > pl->right.xp)
+ {
+ pl->right.xp = xp; pl->right.c = c; pl->right.z = z;
+ }
+ while (count-- > 0)
+ {
+ pl += step; xp += xpstep; c += cstep; z += zstep;
+ if (xp < pl->left.xp)
+ {
+ pl->left.xp = xp; pl->left.c = c; pl->left.z = z;
+ }
+ if (xp > pl->right.xp)
+ {
+ pl->right.xp = xp; pl->right.c = c; pl->right.z = z;
+ }
+ }
+ }
+ /* Top bits of colour determine rgb / grey mode */
+ if ((colour & 0xff000000) != 0)
+ {
+ uint32 colgrey;
+
+ red = colour & 0xff; green = (colour >> 8) & 0xff; blue = (colour >> 16) & 0xff;
+ colgrey = (red + green + blue) / 3;
+ if (ambient < 0)
+ {
+ POLYSHADE_LINE_LOOP(3, POLYSHADE_BUILD_RGB_FAST)
+ }
+ else
+ {
+ POLYSHADE_LINE_LOOP(3, POLYSHADE_BUILD_RGB_FULL)
+ }
+ }
+ else
+ {
+ if (ambient < 0)
+ {
+ POLYSHADE_LINE_LOOP(1, POLYSHADE_BUILD_GREY_FAST)
+ }
+ else
+ {
+ POLYSHADE_LINE_LOOP(1, POLYSHADE_BUILD_GREY_FULL)
+ }
+ }
+#endif
+
+ free(vert); free(proj); free(cosine);
+
+ return 0;
+}
+
+
+
+#define RENDER_MESH_NAME RenderHeightMesh1
+#define RENDER_MESH_TYPE c
+#include "cube_render_mesh.c"
+#undef RENDER_MESH_NAME
+#undef RENDER_MESH_TYPE
+
+#define RENDER_MESH_NAME RenderHeightMesh2
+#define RENDER_MESH_TYPE s
+#include "cube_render_mesh.c"
+#undef RENDER_MESH_NAME
+#undef RENDER_MESH_TYPE
+
+#define RENDER_MESH_NAME RenderHeightMesh4
+#define RENDER_MESH_TYPE l
+#include "cube_render_mesh.c"
+#undef RENDER_MESH_NAME
+#undef RENDER_MESH_TYPE
+
+#define RENDER_MESH_NAME RenderHeightMesh4F
+#define RENDER_MESH_TYPE f
+#include "cube_render_mesh.c"
+#undef RENDER_MESH_NAME
+#undef RENDER_MESH_TYPE
+
+#define RENDER_MESH_NAME RenderHeightMesh8F
+#define RENDER_MESH_TYPE d
+#include "cube_render_mesh.c"
+#undef RENDER_MESH_NAME
+#undef RENDER_MESH_TYPE
+
+int RenderHeightField(mesh_desc *meshDesc, const vertex_fp *rotTrans, const graph_env *graphEnv, const mdd_desc *mddDesc, const light_desc *lightDesc)
+{
+ int i, j, dimx, dimz;
+ vertex_fp *vert, *vp, *vbase;
+ vertex_fp *norm, *np, *nbase;
+ int number;
+ int srcIncX, srcIncZ;
+ uint8 *src;
+ real_t h, hh;
+ real_t x0, x1, x2, x3;
+ real_t z0, z1, z2, z3;
+ int backoff, backstep, sideoff, sidestep, iter0, iter1;
+ zbuffer_t *zbuffer;
+#ifdef POLYSHADE_HEIGHT_EXPERIMENTAL
+ int indices[4][8];
+#endif
+
+ if (RenderHeightGetDomain(mddDesc, &dimx, &dimz, &srcIncX, &srcIncZ) != 0)
+ return -1;
+
+ number = (dimx * dimz);
+ vert = (vertex_fp*)malloc(number * sizeof(vertex_fp));
+ norm = (vertex_fp*)malloc(number * sizeof(vertex_fp));
+
+ /* Only create a new mesh if it has changed */
+ if ((meshDesc->srcData != mddDesc->data) || (meshDesc->width != dimx) || (meshDesc->height != dimz) || (meshDesc->oldGrid != meshDesc->scaleGrid) || (meshDesc->oldHeight != meshDesc->scaleHeight))
+ {
+ if (meshDesc->vert != NULL) free(meshDesc->vert);
+ if (meshDesc->norm != NULL) free(meshDesc->norm);
+
+ meshDesc->vert = (vertex_fp*)malloc(number * sizeof(vertex_fp));
+ meshDesc->norm = (vertex_fp*)malloc(number * sizeof(vertex_fp));
+
+ /* Create a vertex mesh (type-dependent) */
+ src = (uint8*)(mddDesc->data);
+
+ vp = meshDesc->vert;
+ switch (mddDesc->baseSize)
+ {
+ case 1: RenderHeightMesh1(vp, src, srcIncX, srcIncZ, dimx, dimz, meshDesc->scaleGrid, meshDesc->scaleHeight);
+ break;
+ case 2: RenderHeightMesh2(vp, src, srcIncX, srcIncZ, dimx, dimz, meshDesc->scaleGrid, meshDesc->scaleHeight);
+ break;
+ case 4:
+ if (mddDesc->floatType == 0)
+ RenderHeightMesh4(vp, src, srcIncX, srcIncZ, dimx, dimz, meshDesc->scaleGrid, meshDesc->scaleHeight);
+ else
+ RenderHeightMesh4F(vp, src, srcIncX, srcIncZ, dimx, dimz, meshDesc->scaleGrid, meshDesc->scaleHeight);
+ break;
+ case 8: RenderHeightMesh8F(vp, src, srcIncX, srcIncZ, dimx, dimz, meshDesc->scaleGrid, meshDesc->scaleHeight);
+ break;
+ default:
+ fprintf(stderr, "Unable to render a height field for this base type.\n");
+ free(vert); free(norm); return -1;
+ }
+
+ /* Construct normal vector approximations */
+ vp = meshDesc->vert; np = meshDesc->norm; z0 = vp[0].y; z1 = z0;
+ for (i = 0; i < dimx; i++)
+ {
+ for (j = 0; j < dimz; j++)
+ {
+ vertex_fp v;
+ /*real_t vy;*/
+
+ /* Determine min/max */
+ if (vp->y < z0) z0 = vp->y;
+ if (vp->y > z1) z1 = vp->y;
+ /* Calculate normal */
+ if (i == 0) v.x = -(real_t)(vp[dimz].y - vp[0].y);
+ else if (i == dimx-1) v.x = -(real_t)(vp[0].y - vp[-dimz].y);
+ else v.x = (real_t)( - (vp[dimz].y - vp[-dimz].y) * 0.5);
+ v.y = 2 * meshDesc->scaleGrid;
+ if (j == 0) v.z = -(real_t)(vp[1].y - vp[0].y);
+ else if (j == dimz-1) v.z = -(real_t)(vp[0].y - vp[-1].y);
+ else v.z = (real_t)( - (vp[1].y - vp[-1].y) * 0.5);
+ h = (real_t)(1 / sqrt((v.x) * (v.x) + (v.y) * (v.y) + (v.z) * (v.z))); /* v.y != 0 ! */
+ np->x = h * v.x; np->y = h * v.y; np->z = h * v.z;
+ vp++; np++;
+ }
+ }
+ meshDesc->miny = z0; meshDesc->maxy = z1;
+ meshDesc->srcData = mddDesc->data;
+ meshDesc->width = dimx; meshDesc->height = dimz;
+ meshDesc->oldGrid = meshDesc->scaleGrid; meshDesc->oldHeight = meshDesc->scaleHeight;
+ }
+
+ memcpy(vert, meshDesc->vert, number * sizeof(vertex_fp));
+ memcpy(norm, meshDesc->norm, number * sizeof(vertex_fp));
+
+ z0 = (meshDesc->miny + meshDesc->maxy) / 2;
+ z1 = (real_t)(rotTrans[0].y - 0.5*(rotTrans[2].x * dimx * meshDesc->scaleGrid + rotTrans[2].z * dimz * meshDesc->scaleGrid));
+
+ /* Transform vertices and normals */
+ vp = meshDesc->vert; np = meshDesc->norm;
+ for (i=0; i<dimx*dimz; i++, vp++, np++)
+ {
+ z2 = vp->y - z0;
+ vert[i].x = rotTrans[1].x * vp->x + rotTrans[1].y * z2 + rotTrans[1].z * vp->z + rotTrans[0].x;
+ vert[i].y = rotTrans[2].x * vp->x + rotTrans[2].y * z2 + rotTrans[2].z * vp->z + z1;
+ vert[i].z = rotTrans[3].x * vp->x + rotTrans[3].y * z2 + rotTrans[3].z * vp->z + rotTrans[0].z;
+ norm[i].x = rotTrans[1].x * np->x + rotTrans[1].y * np->y + rotTrans[1].z * np->z;
+ norm[i].y = rotTrans[2].x * np->x + rotTrans[2].y * np->y + rotTrans[2].z * np->z;
+ norm[i].z = rotTrans[3].x * np->x + rotTrans[3].y * np->y + rotTrans[3].z * np->z;
+ }
+
+
+ /*
+ * Find order in which to plot: 1) find hindmost side of the grid using min((dz/dx)^2),
+ * 2) test left/right z of this side for running order in inner loop.
+ */
+ x0 = vert[0].x; x1 = vert[dimz * (dimx-1)].x; x2 = vert[dimz * dimx - 1].x; x3 = vert[dimz-1].x;
+ z0 = vert[0].z; z1 = vert[dimz * (dimx-1)].z; z2 = vert[dimz * dimx - 1].z; z3 = vert[dimz-1].z;
+ /* Hindmost corner 0 */
+ if ((z0 >= z1) && (z0 >= z2) && (z0 >= z3))
+ {
+ /* (dz0/dx0)^2 < (dz1/dx1)^2 <==> (dz0dx1)^2 < (dz1dx0)^2 */
+ h = (z1 - z0) * (x3 - x0); hh = (z3 - z0) * (x1 - x0);
+ if (h*h < hh*hh) /* back is 01 */
+ {
+ backoff = 0; backstep = 1; iter0 = dimz;
+ sideoff = 0; sidestep = dimz;
+ }
+ else /* back is 30 */
+ {
+ backoff = 0; backstep = dimz; iter0 = dimx;
+ sideoff = 0; sidestep = 1;
+ }
+ }
+ /* Hindmost corner 1 */
+ else if ((z1 >= z0) && (z1 >= z2) && (z1 >= z3))
+ {
+ h = (z2 - z1) * (x0 - x1); hh = (x2 - x1) * (z0 - z1);
+ if (h*h < hh*hh) /* back is 12 */
+ {
+ backoff = (dimx-2)*dimz; backstep = -dimz; iter0 = dimx;
+ sideoff = 0; sidestep = 1;
+ }
+ else /* back is 01 */
+ {
+ backoff = 0; backstep = 1; iter0 = dimz;
+ sideoff = (dimx-2)*dimz; sidestep = -dimz;
+ }
+ }
+ /* Hindmost corner 2 */
+ else if ((z2 >= z0) && (z2 >= z1) && (z2 >= z3))
+ {
+ h = (z3 - z2) * (x1 - x2); hh = (x3 - x2) * (z1 - z2);
+ if (h*h < hh*hh) /* back is 23 */
+ {
+ backoff = dimz-2; backstep = -1; iter0 = dimz;
+ sideoff = (dimx-2)*dimz; sidestep = -dimz;
+ }
+ else /* back is 12 */
+ {
+ backoff = (dimx-2)*dimz; backstep = -dimz; iter0 = dimx;
+ sideoff = dimz-2; sidestep = -1;
+ }
+ }
+ /* Hindmost corner 3 */
+ else
+ {
+ h = (z0 - z3) * (x2 - x3); hh = (x0 - x3) * (z2 - z3);
+ if (h*h < hh*hh) /* back is 30 */
+ {
+ backoff = 0; backstep = dimz; iter0 = dimx;
+ sideoff = dimz-2; sidestep = -1;
+ }
+ else /* back is 23 */
+ {
+ backoff = dimz-2; backstep = -1; iter0 = dimz;
+ sideoff = 0; sidestep = dimz;
+ }
+ }
+#ifdef POLYSHADE_HEIGHT_EXPERIMENTAL
+ /* Init indices for triangle plotting order */
+ /* 0: 012:023, 1: 023:012, 2: 130:123, 3: 123:130 */
+ indices[0][0] = 0; indices[0][1] = dimz; indices[0][2] = dimz+1;
+ indices[0][3] = 0; indices[0][4] = dimz+1; indices[0][5] = 1;
+ indices[1][0] = 0; indices[1][1] = dimz+1; indices[1][2] = 1;
+ indices[1][3] = 0; indices[1][4] = dimz; indices[1][5] = dimz+1;
+ indices[2][0] = dimz; indices[2][1] = 1; indices[2][2] = 0;
+ indices[2][3] = dimz; indices[2][4] = dimz+1; indices[2][5] = 1;
+ indices[3][0] = dimz; indices[3][1] = dimz+1; indices[3][2] = 1;
+ indices[3][3] = dimz; indices[3][4] = 1; indices[3][5] = 0;
+ /* normals associated with these */
+ indices[0][6] = 0; indices[0][7] = 1; indices[1][6] = 1; indices[1][7] = 0;
+ indices[2][6] = 0; indices[2][7] = 1; indices[3][6] = 1; indices[3][7] = 0;
+
+ vbase = vert + backoff + sideoff; nbase = norm + backoff + sideoff;
+#else
+ /* When using the ZBuffer we try to render front to back for much more efficiency */
+ i = (dimx-2) * dimz + dimz - 2 - backoff - sideoff; vbase = vert + i; nbase = norm + i;
+ backstep = -backstep; sidestep = -sidestep;
+
+ RenderInitZBuffer(graphEnv, meshDesc);
+ zbuffer = meshDesc->zbuffer;
+#endif
+
+ iter1 = dimx + dimz - iter0;
+ for (i=0; i<iter0-1; i++)
+ {
+ vp = vbase; np = nbase;
+ for (j=0; j<iter1-1; j++)
+ {
+#if 0
+ vertex_fp polygon[4], normals[4];
+
+ polygon[0] = vp[0]; polygon[1] = vp[dimz]; polygon[2] = vp[dimz+1]; polygon[3] = vp[1];
+ normals[0] = np[0]; normals[1] = np[dimz]; normals[2] = np[dimz+1]; normals[3] = np[1];
+ /*printf("%d,%d : %f,%f,%f : %f,%f,%f : %f,%f,%f : %f,%f,%f\n", i, j, polygon[0].x, polygon[0].y, polygon[0].z, polygon[1].x, polygon[1].y, polygon[1].z, polygon[2].x, polygon[2].y, polygon[2].z, polygon[3].x, polygon[3].y, polygon[3].z);*/
+ /*colour = (((i+j)&1) == 0) ? 128 : 255;*/
+ RenderShadedPolygon(4, polygon, normals, colour, graphEnv, lightDesc, NULL, zbuffer);
+#else
+ vertex_fp normals[3];
+ vertex_fp diag1, diag2;
+#ifdef POLYSHADE_HEIGHT_EXPERIMENTAL
+ vertex_fp polygon[4], tnorms[2];
+ int *ind;
+#else
+ vertex_fp polygon[3];
+#endif
+
+ /*colour = (((i+j)&1) == 0) ? 128 : 255;*/
+
+ /*
+ * Determine the best splitting line (BCD, BDA vs. ABC, ACD) by minimizing the scalar product
+ * of the normalized diagonals with the normals at their endpoints
+ */
+ diag1.x = vp[1].x - vp[dimz].x; diag1.y = vp[1].y - vp[dimz].y; diag1.z = vp[1].z - vp[dimz].z;
+ h = diag1.x * diag1.x + diag1.y * diag1.y + diag1.z * diag1.z;
+ if (h > 1e-6)
+ {
+ h = (real_t)(1/sqrt(h));
+ diag1.x *= h; diag1.y *= h; diag1.z *= h;
+ }
+ diag2.x = vp[dimz+1].x - vp[0].x; diag2.y = vp[dimz+1].y - vp[0].y; diag2.z = vp[dimz+1].z - vp[0].z;
+ h = diag2.x * diag2.x + diag2.y * diag2.y + diag2.z * diag2.z;
+ if (h > 1e-6)
+ {
+ h = (real_t)(1/sqrt(h));
+ diag2.x *= h; diag2.y *= h; diag2.z *= h;
+ }
+ h = diag1.x * np[dimz].x + diag1.y * np[dimz].y + diag1.z * np[dimz].z;
+ hh = diag1.x * np[1].x + diag1.y * np[1].y + diag1.z * np[1].z;
+ x0 = h*h + hh*hh;
+ h = diag2.x * np[dimz+1].x + diag2.y * np[dimz+1].y + diag2.z * np[dimz+1].z;
+ hh = diag2.x * np[0].x + diag2.y * np[0].y + diag2.z * np[0].z;
+ x1 = h*h + hh*hh;
+#ifdef POLYSHADE_HEIGHT_EXPERIMENTAL
+ polygon[0].x = vp[dimz].x - vp[0].x; polygon[1].x = vp[dimz+1].x - vp[dimz].x;
+ polygon[0].y = vp[dimz].y - vp[0].y; polygon[1].y = vp[dimz+1].y - vp[dimz].y;
+ polygon[0].z = vp[dimz].z - vp[0].z; polygon[1].z = vp[dimz+1].z - vp[dimz].z;
+ polygon[2].x = vp[1].x - vp[dimz+1].x; polygon[3].x = vp[0].x - vp[1].x;
+ polygon[2].y = vp[1].y - vp[dimz+1].y; polygon[3].y = vp[0].y - vp[1].y;
+ polygon[2].z = vp[1].z - vp[dimz+1].z; polygon[3].z = vp[0].z - vp[1].z;
+
+ if (x1 < x0)
+ {
+ /* Diagonal is 02 = diag2 */
+ tnorms[0].x = polygon[0].y * polygon[1].z - polygon[0].z * polygon[1].y;
+ tnorms[0].y = polygon[0].z * polygon[1].x - polygon[0].x * polygon[1].z;
+ tnorms[0].z = polygon[0].x * polygon[1].y - polygon[0].y * polygon[1].x;
+ tnorms[1].x = polygon[2].y * polygon[3].z - polygon[2].z * polygon[3].y;
+ tnorms[1].y = polygon[2].z * polygon[3].x - polygon[2].x * polygon[3].z;
+ tnorms[1].z = polygon[2].x * polygon[3].y - polygon[2].y * polygon[3].x;
+#if 0
+ /* Method #1: scalar product of (real) surface normals with position of normals */
+ h = tnorms[0].x * vp[dimz].x + tnorms[0].y * vp[dimz].y + tnorms[0].z * vp[dimz].z;
+ hh = tnorms[1].x * vp[1].x + tnorms[1].y * vp[1].y + tnorms[1].z * vp[1].z;
+ if (tnorms[0].x * diag1.x + tnorms[0].y * diag1.y + tnorms[0].z * diag1.z > 0)
+ {
+ h = -h; hh = -hh;
+ }
+ if (h < hh) ind = indices[1]; else ind = indices[0];
+#else
+ /* Method #2: Compare z values */
+ h = tnorms[1].x * vp[dimz].x + tnorms[1].y * vp[dimz].y + tnorms[1].z * vp[dimz].z;
+ if (h != 0.0)
+ {
+ h = (tnorms[1].x * vp[1].x + tnorms[1].y * vp[1].y + tnorms[1].z * vp[1].z) / h;
+ }
+ if (h > 1.0) ind = indices[1]; else ind = indices[0];
+#endif
+ }
+ else
+ {
+ /* Diagonal is 13 = diag1 */
+ tnorms[0].x = polygon[3].y * polygon[0].z - polygon[3].z * polygon[0].y;
+ tnorms[0].y = polygon[3].z * polygon[0].x - polygon[3].x * polygon[0].z;
+ tnorms[0].z = polygon[3].x * polygon[0].y - polygon[3].y * polygon[0].x;
+ tnorms[1].x = polygon[1].y * polygon[2].z - polygon[1].z * polygon[2].y;
+ tnorms[1].y = polygon[1].z * polygon[2].x - polygon[1].x * polygon[2].z;
+ tnorms[1].z = polygon[1].x * polygon[2].y - polygon[1].y * polygon[2].x;
+#if 0
+ h = tnorms[0].x * vp[0].x + tnorms[0].y * vp[0].y + tnorms[0].z * vp[0].z;
+ hh = tnorms[1].x * vp[dimz+1].x + tnorms[1].y * vp[dimz+1].y + tnorms[1].z * vp[dimz+1].z;
+ if (tnorms[0].x * diag2.x + tnorms[0].y * diag2.y + tnorms[0].z * diag2.z > 0)
+ {
+ h = -h; hh = -hh;
+ }
+ if (h < hh) ind = indices[3]; else ind = indices[2];
+#else
+ h = tnorms[1].x * vp[0].x + tnorms[1].y * vp[0].y + tnorms[1].z * vp[0].z;
+ if (h != 0.0)
+ {
+ h = (tnorms[1].x * vp[dimz+1].x + tnorms[1].y * vp[dimz+1].y + tnorms[1].z * vp[dimz+1].z) / h;
+ }
+ if (h > 1.0) ind = indices[3]; else ind = indices[2];
+#endif
+ }
+ polygon[0] = vp[ind[0]]; polygon[1] = vp[ind[1]]; polygon[2] = vp[ind[2]];
+ normals[0] = np[ind[0]]; normals[1] = np[ind[1]]; normals[2] = np[ind[2]];
+ RenderShadedPolygon(3, polygon, normals, meshDesc->colour, graphEnv, lightDesc, tnorms + ind[6], zbuffer);
+ polygon[1] = vp[ind[4]]; polygon[2] = vp[ind[5]];
+ normals[1] = np[ind[4]]; normals[2] = np[ind[5]];
+ RenderShadedPolygon(3, polygon, normals, meshDesc->colour, graphEnv, lightDesc, tnorms + ind[7], zbuffer);
+#else
+ if (x1 < x0) /* splitting diagonal is 02 */
+ {
+ polygon[0] = vp[0]; polygon[1] = vp[dimz]; polygon[2] = vp[dimz+1];
+ normals[0] = np[0]; normals[1] = np[dimz]; normals[2] = np[dimz+1];
+ RenderShadedPolygon(3, polygon, normals, meshDesc->colour, graphEnv, lightDesc, NULL, zbuffer);
+ polygon[1] = vp[dimz+1]; polygon[2] = vp[1];
+ normals[1] = np[dimz+1]; normals[2] = np[1];
+ RenderShadedPolygon(3, polygon, normals, meshDesc->colour, graphEnv, lightDesc, NULL, zbuffer);
+ }
+ else
+ {
+ polygon[0] = vp[dimz]; polygon[1] = vp[dimz+1]; polygon[2] = vp[1];
+ normals[0] = np[dimz]; normals[1] = np[dimz+1]; normals[2] = np[1];
+ RenderShadedPolygon(3, polygon, normals, meshDesc->colour, graphEnv, lightDesc, NULL, zbuffer);
+ polygon[1] = vp[1]; polygon[2] = vp[0];
+ normals[1] = np[1]; normals[2] = np[0];
+ RenderShadedPolygon(3, polygon, normals, meshDesc->colour, graphEnv, lightDesc, NULL, zbuffer);
+ }
+#endif /* POLYSHADE_HEIGHT_EXPERIMENTAL */
+
+#endif
+ vp += sidestep; np += sidestep;
+ }
+ vbase += backstep; nbase += backstep;
+ }
+
+ free(vert); free(norm);
+
+ return 0;
+}
+
+
+void RenderHeightFreeMesh(mesh_desc *meshDesc)
+{
+ if (meshDesc->vert != NULL) free(meshDesc->vert);
+ if (meshDesc->norm != NULL) free(meshDesc->norm);
+ if (meshDesc->zbuffer != NULL) free(meshDesc->zbuffer);
+ meshDesc->vert = NULL; meshDesc->norm = NULL;
+ meshDesc->zbuffer = NULL; meshDesc->zbuffSize = 0;
+ meshDesc->srcData = NULL; meshDesc->width = 0; meshDesc->height = 0;
+}
+
+
+int RenderHeightGetDomain(const mdd_desc *mddDesc, int *dimx, int *dimz, int *stepx, int *stepz)
+{
+ int i, idx1=-1, idx2=-1;
+
+ for (i=0; i<mddDesc->numDims; i++)
+ {
+ if (mddDesc->widths[i] != 1)
+ {
+ if (idx1 < 0) idx1 = i;
+ else if (idx2 < 0) idx2 = i;
+ else break;
+ }
+ }
+ if ((idx1 < 0) || (idx2 < 0) || (i < mddDesc->numDims))
+ {
+ fprintf(stderr, "Height field projection must be 2D!\n");
+ return -1;
+ }
+ if (dimx != NULL) *dimx = mddDesc->dims[idx1];
+ if (dimz != NULL) *dimz = mddDesc->dims[idx2];
+ if ((stepx != NULL) || (stepz != NULL))
+ {
+ int s;
+
+ s = mddDesc->baseSize;
+ for (i=mddDesc->numDims-1; i>idx2; i--) s *= mddDesc->dims[i];
+ if (stepz != NULL) *stepz = s;
+ if (stepx != NULL)
+ {
+ for ( ; i>idx1; i--) s *= mddDesc->dims[i];
+ *stepx = s;
+ }
+ }
+ return 0;
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/applications/rview/cube_render.h b/applications/rview/cube_render.h
new file mode 100644
index 0000000..05293c6
--- /dev/null
+++ b/applications/rview/cube_render.h
@@ -0,0 +1,228 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+ * PURPOSE:
+ *
+ * Renderers for RasDaMan MDD of various base types. Renderers provided
+ * are:
+ * 3D: surface ( RenderCubeSurf() ), voxel ( RenderCubeVoxel() )
+ * 2D: height-fields ( RenderHeightField() ).
+ * Misc primitives: lines ( RenderLineSegment() ), shaded polyings using
+ * a Z-Buffer ( RenderShadedPolygon() ).
+ *
+ * The renderer module is standalone and can be used independently
+ * from rView. In the rView project it's used by rviewImage.
+ *
+ * COMMENTS:
+ * No Comments
+ */
+
+
+
+#ifndef _CUBE_RENDER_H
+#define _CUBE_RENDER_H
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Externally visible structs and definitions */
+
+#define CUBE_BSIZE_CHAR 1
+#define CUBE_BSIZE_SHORT 2
+#define CUBE_BSIZE_RGB 3
+#define CUBE_BSIZE_LONG 4
+
+
+/* FP type to use */
+typedef float real_t;
+
+
+typedef struct vertex {
+ long x, y, z;
+} vertex;
+
+typedef struct vertex_fp {
+ real_t x, y, z;
+} vertex_fp;
+
+typedef struct vertex_p {
+ long x, y;
+} vertex_p;
+
+typedef struct rotation_desc {
+ double sin;
+ double cos;
+} rotation_desc;
+
+
+
+typedef struct graph_env {
+ int clipl, clipr, clipd, clipu, clipz;
+ int midx, midy, lineadd, zpro;
+ unsigned long bbox_colour;
+ void *dest;
+} graph_env;
+
+
+typedef struct tex_desc {
+ int dimx, dimy, dimz;
+ int widthx, widthy, widthz;
+ int baseSize;
+ void *data;
+ int floatType;
+ double minVal; /* Only needed for float types */
+ double maxVal;
+} tex_desc;
+
+
+/* generalized tex_desc */
+typedef struct mdd_desc {
+ int numDims;
+ int *widths;
+ int *dims;
+ int baseSize;
+ void *data;
+ int floatType;
+ double minVal;
+ double maxVal;
+} mdd_desc;
+
+
+typedef struct bounding_box {
+ int minx, miny, maxx, maxy;
+} bounding_box;
+
+typedef struct face {
+ int vertices;
+ unsigned int flags;
+ vertex_fp *first;
+ vertex_p *first_p;
+ bounding_box bBox;
+} face;
+
+
+/* Methods for normal vector approximation when summing up neighbouring voxels */
+#define RENDER_NORM_KERNEL_VOID 0
+#define RENDER_NORM_KERNEL_HOMO 1
+#define RENDER_NORM_KERNEL_LINEAR 2
+#define RENDER_NORM_KERNEL_GAUSS 3
+
+typedef unsigned short zbuffer_t;
+
+typedef struct mesh_desc {
+ void *srcData;
+ int width, height;
+ real_t scaleGrid, scaleHeight;
+ real_t oldGrid, oldHeight;
+ unsigned int colour;
+ real_t miny, maxy;
+ vertex_fp *vert;
+ vertex_fp *norm;
+ zbuffer_t *zbuffer;
+ unsigned int zbuffSize;
+} mesh_desc;
+
+typedef struct light_desc {
+ vertex_fp lights;
+ double ambient;
+ double gain;
+ double cosine;
+ double scintCos;
+} light_desc;
+
+typedef struct voxel_desc {
+ double pixelThresholdLow;
+ double pixelThresholdHigh;
+ double weightThreshold;
+ int weightQuantisation;
+ int useRgbBrightness;
+ int kernSize;
+ int kernType;
+ void *voxColour;
+ light_desc light;
+} voxel_desc;
+
+typedef struct render_desc {
+ face *faces;
+ vertex_fp left_g, right_g;
+ vertex_fp left_t, right_t;
+ long left_p, right_p;
+ vertex_fp *texbase;
+ vertex_fp org, tmax;
+ int found, do_lines;
+ tex_desc *texDesc;
+ graph_env *graphEnv;
+} render_desc;
+
+
+
+/*
+ * These calls aren't needed for rendering. They let you build a clipped cube
+ * which can be referenced via the render descriptor (also used internally) and
+ * free the resources after you're finished with them.
+ */
+extern void RenderCubeClipCube(const vertex_fp geomData[4], render_desc *renderDesc, int removeHidden);
+extern render_desc *RenderCubeBuild(const vertex_fp geomData[4], const graph_env *graphEnv);
+extern void RenderCubeFreeDesc(render_desc *renderDesc);
+extern int RenderCubeGetPosition(int x_p, int y_p, vertex_fp *pos, render_desc *renderDesc);
+extern void RenderCubeDetermineRotation(const vertex_fp *base, rotation_desc *rd);
+
+
+
+/*
+ * The actual renderers.
+ * Exit status is 0 for OK, otherwise an error occurred. */
+
+/* For backwards compatibility, equals RenderCubeSurf */
+extern int RenderCube(const vertex_fp geomData[4], const graph_env *graphEnv, const tex_desc *texDesc);
+
+/* Renders the textured surfaces of the cube only */
+extern int RenderCubeSurf(const vertex_fp geomData[4], const graph_env *graphEnv, const tex_desc *texDesc);
+
+/* Renders the cube using a volume-oriented method. */
+extern int RenderCubeVoxel(const vertex_fp geomData[4], const graph_env *graphEnv, const tex_desc *texDesc, voxel_desc *voxDesc);
+
+/* Line API: only texDesc and graphEnv of renderDesc have to be initialized */
+/* Renders a line in unprocessed 3D coordinates */
+extern void Render3DLine(const vertex_fp *from, const vertex_fp *to, const render_desc *renderDesc, long colour);
+/* Renders a line in already projected, z-clipped coordinates */
+extern void RenderLineSegment(const vertex_p *from, const vertex_p *to, const render_desc *renderDesc, long colour);
+
+/* Renders a polygon using shading */
+extern int RenderShadedPolygon(int numVert, const vertex_fp *vertices, const vertex_fp *normals, unsigned int colour, const graph_env *graphEnv, const light_desc *lightDesc, const vertex_fp *real_norm, zbuffer_t *zbuffer);
+
+/* Renders a 2D height field */
+extern int RenderHeightField(mesh_desc *meshDesc, const vertex_fp *rotTrans, const graph_env *graphEnv, const mdd_desc *mddDesc, const light_desc *lightDesc);
+
+extern void RenderHeightFreeMesh(mesh_desc *meshDesc);
+
+extern int RenderHeightGetDomain(const mdd_desc *mddDesc, int *dimx, int *dimz, int *stepx, int *stepz);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/applications/rview/cube_render_core.c b/applications/rview/cube_render_core.c
new file mode 100644
index 0000000..bbf7fd0
--- /dev/null
+++ b/applications/rview/cube_render_core.c
@@ -0,0 +1,182 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+ * cube_render_core.c
+ * Main rendering function. All clipping and hidden face removal has been
+ * performed by the main function, it's also guaranteed that the face is
+ * not ``empty''. All that remains to be done is iterate over the scanlines
+ * and render them.
+ *
+ * COMMENTS:
+ * No comments
+ */
+
+static void RENDER_CORE_NAME (int faceNo, render_desc *renderDesc)
+{
+ graph_env *ge;
+ tex_desc *td;
+ face *cface;
+ real_t zpro;
+ int line, width, i;
+ uint8 *destBase;
+#if (TEXEL_BSIZE == 3)
+ uint8 *auxPtr;
+#endif
+#if (TEXEL_BSIZE == 8)
+ uint32 *auxPtr;
+#endif
+ union {uint8 *c; uint16 *s; uint32 *l;} texture;
+ union {uint8 *c; uint16 *s; uint32 *l;} dest;
+#if (TEXEL_BSIZE < 3)
+ register uint32 accu_t;
+#endif
+ int32 tx, ty, tz, dtx, dty, dtz, ntx, nty, ntz;
+ vertex_fp deltaLR_g, deltaLR_t, *left_g, *left_t;
+ int dimy, dimz, dimyz;
+ real_t nom, den, h, dn, dd;
+#if (CUBE_RENDER_DEBUG > 0)
+ uint8 *high_tide_dest;
+ unsigned int high_tide_src;
+#endif
+
+ ge = (renderDesc->graphEnv); td = (renderDesc->texDesc); zpro = (real_t)(ge->zpro);
+ cface = renderDesc->faces + faceNo;
+
+#if (CUBE_RENDER_DEBUG > 0)
+ high_tide_dest = (uint8*)(ge->dest) + (ge->clipu - ge->clipd + 1) * (ge->lineadd);
+ high_tide_src = (renderDesc->texDesc->dimx)*(renderDesc->texDesc->dimy)*(renderDesc->texDesc->dimz);
+
+ printf("Render face %d (%d, %d, %d, %d)\n",
+ faceNo, cface->bBox.minx, cface->bBox.miny, cface->bBox.maxx, cface->bBox.maxy);
+ if ((cface->bBox.miny < ge->clipd) || (cface->bBox.maxy > ge->clipu))
+ {
+ printf("y out of range (%d,%d)!\n", cface->bBox.miny, cface->bBox.maxy); fflush(stdout);
+ }
+#endif
+ destBase = (uint8*)(ge->dest) + (ge->midy - cface->bBox.maxy)*(ge->lineadd) + (ge->midx * renderDesc->texDesc->baseSize);
+ dimy = renderDesc->texDesc->dimy; dimz = renderDesc->texDesc->dimz; dimyz = dimy * dimz;
+ left_g = &(renderDesc->left_g); left_t = &(renderDesc->left_t);
+
+ /* For each line ... */
+ for (line = cface->bBox.maxy; line >= cface->bBox.miny; line--, destBase += renderDesc->graphEnv->lineadd)
+ {
+ RenderCubeGetScanline(line, faceNo, renderDesc, 1);
+ if (renderDesc->found == 0) continue;
+
+ /* First trap case where everything lies outside (in theory this can happen for some lines) */
+ if ((renderDesc->left_p > ge->clipr) || (renderDesc->right_p < ge->clipl)) continue;
+
+ /* Left clipping; essentially this shouldn't be (and usually isn't) necessary because we
+ already clipped the left border in the main procedure, but rounding errors could still
+ lead to problems. In that case simply updating the plot position without touching the
+ texture coordinates is OK. */
+ if (renderDesc->left_p < ge->clipl) {renderDesc->left_p = ge->clipl;}
+ if (renderDesc->right_p > ge->clipr) {renderDesc->right_p = ge->clipr;}
+
+ dest.c = destBase + (renderDesc->left_p) * TEXEL_BSIZE;
+ width = renderDesc->right_p - renderDesc->left_p + 1;
+ if (width <= 0) continue;
+ /* Compute deltaLR_g and deltaLR_t components */
+ deltaLR_g.x = renderDesc->right_g.x - left_g->x;
+ deltaLR_g.y = renderDesc->right_g.y - left_g->y;
+ deltaLR_g.z = renderDesc->right_g.z - left_g->z;
+ deltaLR_t.x = renderDesc->right_t.x - left_t->x;
+ deltaLR_t.y = renderDesc->right_t.y - left_t->y;
+ deltaLR_t.z = renderDesc->right_t.z - left_t->z;
+ tx = (int32)(left_t->x);
+ ty = (int32)(left_t->y);
+ tz = (int32)(left_t->z);
+
+ /*if (faceNo == 6) printf("(%f,%f,%f:%x,%x,%x)", left_t->x, left_t->y, left_t->z, tx, ty, tz);*/
+ nom = left_g->x * zpro - ((real_t)(renderDesc->left_p)) * left_g->z;
+ den = deltaLR_g.x * zpro - ((real_t)(renderDesc->left_p)) * deltaLR_g.z;
+#if (CUBE_RENDER_DEBUG > 1)
+ printf("Start line %d (%d)\n", line, (dest.c - (uint8*)(ge->dest))); fflush(stdout);
+#endif
+ /*if (faceNo == 0) printf("(%d,%d,%d)",line,renderDesc->left_p, renderDesc->right_p);*/
+
+ /* Avoid jitter */
+ if (fabs(renderDesc->right_t.x - tx) <= FIXPOINT_PREC)
+ {
+#undef TEXEL_FETCH
+#undef TEXEL_STEP
+#define TEXEL_FETCH \
+ TEXEL_POINTER[((ty >> FIXPOINT_PREC) * dimz + (tz >> FIXPOINT_PREC)) * TEXEL_MULTIPLIER]
+#define TEXEL_STEP \
+ ty += dty; tz += dtz;
+#define TEXEL_CONST_X
+
+ texture.c = (uint8*)(renderDesc->texDesc->data) + (tx >> FIXPOINT_PREC) * dimyz * TEXEL_BSIZE;
+#include "cube_render_line.c"
+#undef TEXEL_CONST_X
+ }
+ else if (fabs(renderDesc->right_t.y - ty) <= FIXPOINT_PREC)
+ {
+#undef TEXEL_FETCH
+#undef TEXEL_STEP
+#define TEXEL_FETCH \
+ TEXEL_POINTER[((tx >> FIXPOINT_PREC) * dimyz + (tz >> FIXPOINT_PREC)) * TEXEL_MULTIPLIER]
+#define TEXEL_STEP \
+ tx += dtx; tz += dtz;
+#define TEXEL_CONST_Y
+
+ texture.c = (uint8*)(renderDesc->texDesc->data) + (ty >> FIXPOINT_PREC) * dimz * TEXEL_BSIZE;
+#include "cube_render_line.c"
+#undef TEXEL_CONST_Y
+ }
+ else if (fabs(renderDesc->right_t.z - tz) <= FIXPOINT_PREC)
+ {
+#undef TEXEL_FETCH
+#undef TEXEL_STEP
+#define TEXEL_FETCH \
+ TEXEL_POINTER[(((tx >> FIXPOINT_PREC) * dimy + (ty >> FIXPOINT_PREC)) * dimz) * TEXEL_MULTIPLIER]
+#define TEXEL_STEP \
+ tx += dtx; ty += dty;
+#define TEXEL_CONST_Z
+
+ texture.c = (uint8*)(renderDesc->texDesc->data) + (tz >> FIXPOINT_PREC) * TEXEL_BSIZE;
+#include "cube_render_line.c"
+#undef TEXEL_CONST_Z
+ }
+ else
+ {
+#undef TEXEL_FETCH
+#undef TEXEL_STEP
+#define TEXEL_FETCH \
+ TEXEL_POINTER[(((tx >> FIXPOINT_PREC) * dimy + (ty >> FIXPOINT_PREC)) * dimz + (tz >> FIXPOINT_PREC)) * TEXEL_MULTIPLIER]
+#define TEXEL_STEP \
+ tx += dtx; ty += dty; tz += dtz;
+
+ texture.c = (uint8*)(renderDesc->texDesc->data);
+#include "cube_render_line.c"
+ }
+
+#if (CUBE_RENDER_DEBUG > 1)
+ printf("Line OK\n"); fflush(stdout);
+#endif
+ }
+#if (CUBE_RENDER_DEBUG > 0)
+ printf("Face OK.\n"); fflush(stdout);
+#endif
+}
diff --git a/applications/rview/cube_render_line.c b/applications/rview/cube_render_line.c
new file mode 100644
index 0000000..6c40e6d
--- /dev/null
+++ b/applications/rview/cube_render_line.c
@@ -0,0 +1,172 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+ * COMMENTS:
+ *
+ * This is called from within cube_render.c to render a line. It has been
+ * moved out here to be able to easily optimise the whole system for various
+ * settings and simplify the use of different texture base sizes.
+ */
+
+
+
+ i = (8 - (ge->midx + renderDesc->left_p)) & 7;
+ if ((i > width) || (width < 8)) i = width;
+ while (i > 0)
+ {
+ width -= i;
+ nom -= ((real_t)i) * left_g->z; den -= ((real_t)i) * deltaLR_g.z; h = 0.0;
+ if (den != 0)
+ {
+ h = -nom/den;
+ if (h < 0.0) h = 0.0;
+ if (h > 1.0) h = 1.0;
+ }
+#ifndef TEXEL_CONST_X
+ dtx = ((int32)(left_t->x + h * deltaLR_t.x) - tx) / i;
+#endif
+#ifndef TEXEL_CONST_Y
+ dty = ((int32)(left_t->y + h * deltaLR_t.y) - ty) / i;
+#endif
+#ifndef TEXEL_CONST_Z
+ dtz = ((int32)(left_t->z + h * deltaLR_t.z) - tz) / i;
+#endif
+ while (i > 0)
+ {
+#if (CUBE_RENDER_DEBUG > 2)
+ printf("\t(%d, %d, %d: %d)\n", (tx>>FIXPOINT_PREC), (ty>>FIXPOINT_PREC), (tz>>FIXPOINT_PREC), ((tx>>FIXPOINT_PREC)*dimy + (ty>>FIXPOINT_PREC))*dimz + (tz>>FIXPOINT_PREC)); fflush(stdout);
+#endif
+#if (CUBE_RENDER_DEBUG > 0)
+ if (((tx>>FIXPOINT_PREC)*dimy + (ty>>FIXPOINT_PREC))*dimz + (tz>>FIXPOINT_PREC) > high_tide_src)
+ {
+ printf("Texture buffer overflow (%d, %d, %d) | (%f, %f, %f)!\n", (tx>>FIXPOINT_PREC), (ty>>FIXPOINT_PREC), (tz>>FIXPOINT_PREC), left_t->x + deltaLR_t.x, left_t->y + deltaLR_t.y, left_t->z + deltaLR_t.z); fflush(stdout); break;
+ }
+ if (dest.c > high_tide_dest)
+ {
+ printf("Screen buffer overflow (%d)!\n", (int)(high_tide_dest - (uint8*)(ge->dest)));
+ fflush(stdout); break;
+ }
+#endif
+ TEXEL_ASSIGN;
+ i--;
+ }
+ if (width < 8) i = width;
+ }
+ if (width <= 0) continue;
+ /* The above loop guarantees that at this point width >= 8 */
+ dn = (real_t)(-8.0 * left_g->z); dd = (real_t)(-8.0 * deltaLR_g.z);
+ nom += dn; den += dd; h = 0.0;
+ if (den != 0)
+ {
+ h = -nom/den;
+ if (h < 0.0) h = 0.0;
+ if (h > 1.0) h = 1.0;
+ }
+#ifndef TEXEL_CONST_X
+ dtx = ((int32)(left_t->x + h * deltaLR_t.x) - tx) / 8;
+#endif
+#ifndef TEXEL_CONST_Y
+ dty = ((int32)(left_t->y + h * deltaLR_t.y) - ty) / 8;
+#endif
+#ifndef TEXEL_CONST_Z
+ dtz = ((int32)(left_t->z + h * deltaLR_t.z) - tz) / 8;
+#endif
+
+ /* Help the compiler do efficient Int/FP parallelism. */
+ while (width >= 16)
+ {
+ width -= 8; h = 0.0;
+ nom += dn;
+ TEXEL_ACCU_0(accu_t);
+ den += dd;
+ TEXEL_ACCU_1(accu_t);
+ if (den != 0) h = -nom/den;
+ TEXEL_ACCU_2(accu_t);
+ if (h < 0.0) h = 0.0;
+ TEXEL_ACCU_3(accu_t);
+ if (h > 1.0) h = 1.0;
+ TEXEL_ACCU_0(accu_t);
+#ifndef TEXEL_CONST_X
+ ntx = (int32)(left_t->x + h * deltaLR_t.x);
+#endif
+ TEXEL_ACCU_1(accu_t);
+#ifndef TEXEL_CONST_Y
+ nty = (int32)(left_t->y + h * deltaLR_t.y);
+#endif
+ TEXEL_ACCU_2(accu_t);
+#ifndef TEXEL_CONST_Z
+ ntz = (int32)(left_t->z + h * deltaLR_t.z);
+#endif
+ TEXEL_ACCU_3(accu_t);
+#ifndef TEXEL_CONST_X
+ dtx = (ntx - tx) / 8;
+#endif
+#ifndef TEXEL_CONST_Y
+ dty = (nty - ty) / 8;
+#endif
+#ifndef TEXEL_CONST_Z
+ dtz = (ntz - tz) / 8;
+#endif
+ }
+ /* 8 <= width <= 15 here! */
+ width -= 8; h = 0.0;
+ nom -= ((real_t)width) * left_g->z;
+ TEXEL_ACCU_0(accu_t);
+ den -= ((real_t)width) * deltaLR_g.z;
+ TEXEL_ACCU_1(accu_t);
+ if (den != 0) h = -nom/den;
+ TEXEL_ACCU_2(accu_t);
+ if (h < 0.0) h = 0.0;
+ TEXEL_ACCU_3(accu_t);
+ if (h > 1.0) h = 1.0;
+ TEXEL_ACCU_0(accu_t);
+#ifndef TEXEL_CONST_X
+ ntx = (int32)(left_t->x + h * deltaLR_t.x);
+#endif
+ TEXEL_ACCU_1(accu_t);
+#ifndef TEXEL_CONST_Y
+ nty = (int32)(left_t->y + h * deltaLR_t.y);
+#endif
+ TEXEL_ACCU_2(accu_t);
+#ifndef TEXEL_CONST_Z
+ ntz = (int32)(left_t->z + h * deltaLR_t.z);
+#endif
+ TEXEL_ACCU_3(accu_t);
+ if (width > 0)
+ {
+#ifndef TEXEL_CONST_X
+ dtx = (ntx - tx) / width;
+#endif
+#ifndef TEXEL_CONST_Y
+ dty = (nty - ty) / width;
+#endif
+#ifndef TEXEL_CONST_Z
+ dtz = (ntz - tz) / width;
+#endif
+ while (width > 0)
+ {
+ TEXEL_ASSIGN;
+ width--;
+ }
+ }
diff --git a/applications/rview/cube_render_mesh.c b/applications/rview/cube_render_mesh.c
new file mode 100644
index 0000000..bebaab6
--- /dev/null
+++ b/applications/rview/cube_render_mesh.c
@@ -0,0 +1,48 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+ * COMMENTS:
+ * This is called from within cube_render.c to create a vertex mesh
+ * out of the source data when rendering height fields.
+ */
+
+static void RENDER_MESH_NAME(vertex_fp *vert, const uint8 *src, int srcIncX, int srcIncZ, int dimx, int dimz, real_t scaleGrid, real_t scaleHeight)
+{
+ union {uint8 *c; uint16 *s; uint32 *l; float *f; double *d;} srcLine, srcPtr;
+ real_t gridx, gridz;
+ real_t posx, posz;
+ int i, j;
+ vertex_fp *vp;
+
+ gridx = scaleGrid; gridz = scaleGrid; srcLine.c = (uint8*)src; vp = vert;
+ for (i=0, posx=0.0; i<dimx; i++, posx += gridx, srcLine.c += srcIncX)
+ {
+ srcPtr.c = srcLine.c;
+ for (j=0, posz=0.0; j<dimz; j++, posz += gridz, srcPtr.c += srcIncZ)
+ {
+ vp->x = posx; vp->y = (real_t)(*srcPtr.RENDER_MESH_TYPE)*scaleHeight; vp->z = posz;
+ vp++;
+ }
+ }
+}
diff --git a/applications/rview/cube_render_voxline.c b/applications/rview/cube_render_voxline.c
new file mode 100644
index 0000000..6afa7d6
--- /dev/null
+++ b/applications/rview/cube_render_voxline.c
@@ -0,0 +1,482 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+ * COMMENTS:
+ *
+ * This is called from within cube_render.c to render a line using a voxel
+ * approch. It has been moved here to easily handle different base types
+ * and sizes.
+ */
+
+static void RENDER_CORE_NAME(int line, project_plane_desc *ppd, const render_desc *renderDesc)
+{
+ graph_env *ge;
+ tex_desc *td;
+ union {uint8 *c; uint16 *s; uint32 *l; float *f; double *d;} texture;
+ union {uint8 *c; uint16 *s; uint32 *l; float *f; double *d;} dest;
+ int minx, maxx, posx;
+ project_plane_intersect *front, *back, *lastFront, *lastBack;
+ real_t front_z, back_z, new_z;
+ real_t nom, den, pos, h;
+ real_t zpro;
+ vertex_fp front_t, back_t, deltaFB_t;
+ real_t front_h, back_h;
+ /*int front_num, back_num;*/
+ int i, depth;
+ int32 tx, ty, tz, dtx, dty, dtz;
+ int dimy, dimz, dimyz;
+ int pixelsDone;
+ RENDER_CAST_TYPE value;
+ RENDER_CAST_TYPE ptl, pth, wth; /* thresholds */
+ RENDER_CAST_TYPE wgtAccu, weight;
+ RENDER_CAST_TYPE *voxColour;
+#ifdef RENDER_FLOAT_TYPE
+ real_t weightScale;
+#else
+ int weightQuant;
+#endif
+#if (TEXEL_BSIZE == 3)
+ uint8 *srcPix;
+ uint32 red, green, blue;
+#else
+ RENDER_CAST_TYPE pixel;
+#endif
+
+ ge = renderDesc->graphEnv; td = renderDesc->texDesc; zpro = (real_t)ge->zpro;
+ /* Kill warnings */
+ dtx = 0; dty = 0; dtz = 0;
+ dimy = td->dimy; dimz = td->dimz; dimyz = dimy*dimz;
+ /* Horizontal clipping */
+ minx = (ppd->left_p); if (minx > ge->clipr) return;
+ maxx = (ppd->right_p); if (maxx < ge->clipl) return;
+ if (minx < ge->clipl) minx = ge->clipl;
+ if (maxx > ge->clipr) maxx = ge->clipr;
+#ifdef RENDER_FLOAT_TYPE
+ ptl = (RENDER_CAST_TYPE)(ppd->pixelThresholdLowF);
+ pth = (RENDER_CAST_TYPE)(ppd->pixelThresholdHighF);
+ wth = (RENDER_CAST_TYPE)(ppd->weightThresholdF);
+ weightScale = (real_t)(1.0 / (1 << (ppd->weightQuantisation)));
+#else
+ ptl = (RENDER_CAST_TYPE)(ppd->pixelThresholdLow);
+ pth = (RENDER_CAST_TYPE)(ppd->pixelThresholdHigh);
+ wth = (RENDER_CAST_TYPE)(ppd->weightThreshold);
+ weightQuant = ppd->weightQuantisation;
+#endif
+ voxColour = (RENDER_CAST_TYPE *)(ppd->voxColour);
+ dest.c = (uint8*)(ge->dest) + (ge->midy - line)*(ge->lineadd) + ((ge->midx + minx) * TEXEL_BSIZE);
+ texture.c = (uint8*)(td->data);
+#if 0
+ for (back_num = ppd->segs-1; back_num >= 0; back_num--)
+ {
+ if ((ppd->ppi[back_num].left_p <= minx) && (ppd->ppi[back_num].right_p >= minx)) break;
+ }
+ for (front_num = 0; front_num < ppd->segs; front_num++)
+ {
+ if ((ppd->ppi[front_num].left_p <= minx) && (ppd->ppi[front_num].right_p >= minx)) break;
+ }
+ if (back_num == front_num)
+ {
+ printf("%d,%d | %d\n", front_num, back_num, ppd->segs); fflush(stdout);
+ for (i=0; i<ppd->segs; i++)
+ {
+ printf("\t[%d,%d]\n", ppd->ppi[i].left_p, ppd->ppi[i].right_p);
+ }
+ }
+#endif
+ front = NULL; back = NULL; lastFront = NULL; lastBack = NULL;
+ front_z = 0.0; back_z = 0.0; pixelsDone = 0;
+ /* main pixel loop */
+ for (posx=minx; posx <= maxx; posx++)
+ {
+ pos = (real_t)posx;
+ if (front != NULL)
+ if (front->right_p < posx) front = NULL;
+ if (back != NULL)
+ if (back->right_p < posx) back = NULL;
+
+#if 1
+ /*
+ * Quite tricky: you may only use the two segments found for longer if they
+ * remain the same for a few pixels. For instance two segments which are
+ * linked, one being front and one back: at the leftmost pixel the order
+ * is undefined. Therefore make sure the front / back segments are static
+ * over more than 1 pixel (2 seem to be enough).
+ */
+ if ((front == NULL) || (back == NULL) || (pixelsDone < 2))
+ {
+ /* Determine front and back segment */
+ front = NULL; back = NULL;
+ for (i=0; i<ppd->segs; i++)
+ {
+ if ((ppd->ppi[i].left_p <= posx) && (ppd->ppi[i].right_p >= posx))
+ {
+ den = (ppd->ppi[i].deltaLR_g.x * zpro) - pos * (ppd->ppi[i].deltaLR_g.z);
+ if (den == 0.0) continue;
+ nom = (ppd->ppi[i].left_g.x * zpro) - pos * (ppd->ppi[i].left_g.z);
+ h = - nom / den;
+ if (h < 0.0) h = 0.0; if (h > 1.0) h = 1.0;
+ new_z = ppd->ppi[i].left_g.z + h * (ppd->ppi[i].deltaLR_g.z);
+ if ((front == NULL) || (new_z <= front_z))
+ {
+ front_z = new_z; front = ppd->ppi + i; front_h = h;
+ }
+ if ((back == NULL) || (new_z >= back_z))
+ {
+ back_z = new_z; back = ppd->ppi + i; back_h = h;
+ }
+ }
+ }
+ /* If no front/back segments found: continue loop and try again next time */
+ if ((front == NULL) || (back == NULL)) continue;
+
+ if ((lastFront != front) || (lastBack != back))
+ {
+ lastFront = front; lastBack = back; pixelsDone = 0;
+ }
+ else
+ {
+ pixelsDone++;
+ }
+ }
+ else
+#else
+ if (back == NULL)
+ {
+ /*printf("new back (%d)\n", back_num); fflush(stdout);*/
+ if (back_num < 0) continue;
+ back = ppd->ppi + (back_num--);
+ }
+ if (front == NULL)
+ {
+ /*printf("new front (%d)\n", front_num); fflush(stdout);*/
+ if (front_num >= ppd->segs) continue;
+ front = ppd->ppi + (front_num++);
+ }
+#endif
+ {
+ den = (front->deltaLR_g.x) * zpro - pos * (front->deltaLR_g.z);
+ if (den == 0.0) continue;
+ nom = (front->left_g.x) * zpro - pos * (front->left_g.z);
+ front_h = - nom / den;
+ if (front_h < 0.0) front_h = 0.0; if (front_h > 1.0) front_h = 1.0;
+ den = (back->deltaLR_g.x) * zpro - pos * (back->deltaLR_g.z);
+ if (den == 0.0) continue;
+ nom = (back->left_g.x) * zpro - pos * (back->left_g.z);
+ back_h = - nom / den;
+ if (back_h < 0.0) back_h = 0.0; if (back_h > 1.0) back_h = 1.0;
+ }
+
+ /* front texture coordinates */
+ front_t.x = front->left_t.x + front_h * (front->deltaLR_t.x);
+ front_t.y = front->left_t.y + front_h * (front->deltaLR_t.y);
+ front_t.z = front->left_t.z + front_h * (front->deltaLR_t.z);
+ /* back texture coordinates */
+ back_t.x = back->left_t.x + back_h * (back->deltaLR_t.x);
+ back_t.y = back->left_t.y + back_h * (back->deltaLR_t.y);
+ back_t.z = back->left_t.z + back_h * (back->deltaLR_t.z);
+
+ /* Determine frontmost pixel */
+ deltaFB_t.x = (back_t.x - front_t.x);
+ deltaFB_t.y = (back_t.y - front_t.y);
+ deltaFB_t.z = (back_t.z - front_t.z);
+ /* Step in such a way that you don't move more than one texel in each dimension per step */
+ h = (deltaFB_t.x < 0) ? -deltaFB_t.x : deltaFB_t.x; depth = (int)h;
+ new_z = (deltaFB_t.y < 0) ? -deltaFB_t.y : deltaFB_t.y;
+ if (new_z > h) {depth = (int)new_z; h = new_z;}
+ new_z = (deltaFB_t.z < 0) ? -deltaFB_t.z : deltaFB_t.z;
+ if (new_z > h) depth = (int)new_z;
+
+ if (depth == 0)
+ {
+ depth = 1;
+ }
+ else
+ {
+ h = (1<<FIXPOINT_PREC) / ((real_t)depth);
+ dtx = (int)(deltaFB_t.x * h); dty = (int)(deltaFB_t.y * h); dtz = (int)(deltaFB_t.z * h);
+ }
+ tx = (int)((1<<FIXPOINT_PREC)*front_t.x);
+ ty = (int)((1<<FIXPOINT_PREC)*front_t.y);
+ tz = (int)((1<<FIXPOINT_PREC)*front_t.z);
+
+ /*
+ * Start depth scan to find the frontmost pixel whose brightness exceeds the pixelThreshold
+ * value. The resulting image is almost completely useless if you don't anti-alias by
+ * averaging over some pixels. The approach used here calculates a weighted average over
+ * pixels along the scan beam, favouring bright pixels over dark ones.
+ */
+ wgtAccu = 0;
+#if (TEXEL_BSIZE == 3)
+ red = 0; green = 0; blue = 0;
+#else
+ pixel = 0;
+#endif
+ while (depth > 0)
+ {
+ /*printf("%d : %x,%x,%x : %x,%x,%x\n", depth, tx, ty, tz, dtx, dty, dtz); fflush(stdout);*/
+ /*if ((tx < 0) || (ty < 0) || (tz < 0) || ((tx >> FIXPOINT_PREC) > renderDesc->tmax.x) || ((ty >> FIXPOINT_PREC) > renderDesc->tmax.y) || ((tz >> FIXPOINT_PREC) > renderDesc->tmax.z))
+ {
+ printf("Range!\n");
+ }*/
+#if (TEXEL_BSIZE == 3)
+ TEXEL_FETCH;
+ /* Check each rgb component or the total brightness against threshold values? */
+#ifdef TEXEL_RGB_BRIGHTNESS
+ value = (srcPix[0] + srcPix[1] + srcPix[2]) / 3;
+ if ((value >= ptl) && (value <= pth))
+ {
+#else
+ if (((srcPix[0] >= ptl) && (srcPix[0] <= pth)) ||
+ ((srcPix[1] >= ptl) && (srcPix[1] <= pth)) ||
+ ((srcPix[2] >= ptl) && (srcPix[2] <= pth)))
+ {
+ value = (srcPix[0] + srcPix[1] + srcPix[2]) / 3;
+#endif
+ weight = (value + ((1<<weightQuant)-1)) >> weightQuant;
+ red += srcPix[0] * weight;
+ green += srcPix[1] * weight;
+ blue += srcPix[2] * weight;
+ wgtAccu += weight;
+ if ((RENDER_CAST_TYPE)wgtAccu >= wth) break;
+ }
+#else
+ value = (RENDER_CAST_TYPE)(TEXEL_FETCH);
+ if ((value >= ptl) && (value <= pth))
+ {
+#ifdef RENDER_FLOAT_TYPE
+ weight = weightScale * value;
+#else
+ /* Use weights: bright pixels count more and make the scan terminate much faster than dark ones */
+ weight = (value + ((1<<weightQuant)-1)) >> weightQuant;
+#endif
+#ifdef RENDER_FLOAT_TYPE
+ /* Especially with FP types, value and thus weight may be negative, but weight must be positive! */
+ if (weight < 0) weight = -weight;
+#endif
+ pixel += value * weight;
+ wgtAccu += weight;
+ if ((RENDER_CAST_TYPE)wgtAccu >= wth) break;
+ }
+#endif
+ tx += dtx; ty += dty; tz += dtz;
+ depth--;
+ }
+ /* Pixel transparent? */
+#if (TEXEL_BSIZE == 3)
+ if (wgtAccu != 0)
+ {
+ red /= wgtAccu; green /= wgtAccu; blue /= wgtAccu;
+ }
+# ifdef TEXEL_RGB_BRIGHTNESS
+ if ((red + green + blue < 3*ptl) || (red + green + blue > 3*pth))
+# else
+ if (((red < ptl) && (green < ptl) && (blue < ptl)) || ((red > pth) && (green > pth) && (blue > pth)))
+# endif
+ {
+ dest.c += 3;
+ }
+#else
+ if (wgtAccu != 0) pixel /= wgtAccu;
+ if ((pixel < ptl) || (pixel > pth))
+ {
+# if (TEXEL_BSIZE == 1)
+ dest.c++;
+# elif (TEXEL_BSIZE == 2)
+ dest.s++;
+# elif (TEXEL_BSIZE == 4)
+ dest.l++;
+# else
+ dest.d++;
+# endif
+ }
+#endif
+ else
+ {
+ /* Try grey-level gradient shading */
+ if (ppd->lightsAmbient >= 0)
+ {
+ real_t vx0, vx1, vy0, vy1, vz0, vz1, norm;
+ int offset;
+
+ /* Position of pixel the ray aborted in */
+ tx = (tx - dtx) >> FIXPOINT_PREC;
+ ty = (ty - dty) >> FIXPOINT_PREC;
+ tz = (tz - dtz) >> FIXPOINT_PREC;
+ if (tx < 0) tx = 0; if (tx > td->widthx-1) tx = td->widthx-1;
+ if (ty < 0) ty = 0; if (ty > td->widthy-1) ty = td->widthy-1;
+ if (tz < 0) tz = 0; if (tz > td->widthz-1) tz = td->widthz-1;
+
+ if (ppd->kDesc->region == 0)
+ {
+ real_t center;
+#if 1
+#define RENDER_NORMAL_COORD(t, width, v, delta) \
+ if (t <= 0) v##0 = center; else v##0 = (center + (real_t) RENDER_TABLE_TYPE [offset - delta])/2; \
+ if (t >= (width)-1) v##1 = center; else v##1 = (center + (real_t) RENDER_TABLE_TYPE [offset + delta])/2;
+#else
+#define RENDER_NORMAL_COORD(t, width, v, delta) \
+ if (t <= 0) v##0 = 0.5; else {center = (real_t) RENDER_TABLE_TYPE [offset - delta]; v##0 = (1 + ((center >= ptl) && (center <= pth)) ? 1 : 0) / 2;} \
+ if (t >= (width)-1) v##1 = 0.5; else {center = (real_t) RENDER_TABLE_TYPE [offset + delta]; v##1 = (1 + ((center >= ptl) && (center <= pth)) ? 1 : 0) / 2;}
+#endif
+
+ offset = (((tx * dimy) + ty) * dimz) + tz;
+ /*printf("%d,%d,%d,%d,%p\n", tx, ty, tz, offset, RENDER_TABLE_TYPE); fflush(stdout);*/
+ center = (real_t) RENDER_TABLE_TYPE [offset];
+ RENDER_NORMAL_COORD(tx, td->widthx, vx, dimyz);
+ RENDER_NORMAL_COORD(ty, td->widthy, vy, dimz);
+ RENDER_NORMAL_COORD(tz, td->widthz, vz, 1);
+
+ vx1 -= vx0; vy1 -= vy0; vz1 -= vz0;
+ }
+ else
+ {
+ int xl, xh, yl, yh, zl, zh, ix, iy, iz, region, region2;
+ RENDER_CAST_TYPE val;
+ long offbase, koff, koffbase;
+ real_t *kernel;
+
+ region = ppd->kDesc->region; region2 = 2*region + 1;
+ /* Use mid-point of kernel */
+ kernel = ppd->kDesc->kernel + ((region * region2) + region)*region2 + region;
+ xl = tx - region; if (xl < 0) xl = 0;
+ xh = tx + region; if (xh > td->widthx-1) xh = td->widthx-1;
+ yl = ty - region; if (yl < 0) yl = 0;
+ yh = ty + region; if (yh > td->widthy-1) yh = td->widthy-1;
+ zl = tz - region; if (zl < 0) zl = 0;
+ zh = tz + region; if (zh > td->widthz-1) zh = td->widthz-1;
+ vx1 = 0.0; vy1 = 0.0; vz1 = 0.0;
+ koffbase = ((xl-tx)*region2 + (yl-ty))*region2;
+ region = region2; region2 *= region2;
+ offbase = (((xl * dimy) + yl) * dimz);
+ for (ix = xl; ix <= xh; ix++, offbase += dimyz, koffbase += region2)
+ {
+ offset = offbase; koff = koffbase;
+ for (iy = yl; iy <= yh; iy++, offset += dimz, koff += region)
+ {
+ for (iz = zl; iz <= zh; iz++)
+ {
+#if (TEXEL_BSIZE == 3)
+ srcPix = RENDER_TABLE_TYPE + (offset + iz) * TEXEL_BSIZE;
+ val = (RENDER_CAST_TYPE)((srcPix[0] + srcPix[1] + srcPix[2]) / 3);
+#else
+ val = (RENDER_CAST_TYPE) RENDER_TABLE_TYPE [offset + iz];
+#endif
+#if (!defined(RENDER_RGB_BRIGHTNESS) && (TEXEL_BSIZE == 3))
+ if (((srcPix[0] >= ptl) || (srcPix[1] >= ptl) || (srcPix[2] >= ptl)) && ((srcPix[0] <= pth) || (srcPix[1] <= pth) || (srcPix[2] <= pth)))
+#else
+ if ((val >= ptl) && (val <= pth))
+#endif
+ {
+ real_t wgtval;
+
+ /* Fold the data with a weighing kernel */
+ wgtval = (real_t)(kernel[koff + iz-tz] * val);
+ /*
+ * Whether we use the central values too has no effect on the sums, so
+ * let's no use them for a little extra speed.
+ */
+ if (ix < tx) vx1 -= wgtval; if (ix > tx) vx1 += wgtval;
+ if (iy < ty) vy1 -= wgtval; if (iy > ty) vy1 += wgtval;
+ if (iz < tz) vz1 -= wgtval; if (iz > tz) vz1 += wgtval;
+ }
+ }
+ }
+ }
+ /* Surface normal n, oriented into the volume now in vx1, vy1, vz1*/
+ }
+
+ norm = vx1*vx1 + vy1*vy1 + vz1*vz1;
+ /* calculate vector l from light source to voxel */
+ vx0 = (real_t)tx - ppd->lights.x; vy0 = (real_t)ty - ppd->lights.y; vz0 = (real_t)tz - ppd->lights.z;
+ /* norm = 1 / (|| n ||^2 * || l ||^2) */
+ norm *= (vx0*vx0 + vy0*vy0 + vz0*vz0);
+
+ /*
+ * In case voxColour != NULL it points to a uint32 / float / double value describing the colour
+ * each voxel is assigned. This is good for isosurface rendering, but naturally doesn't make
+ * any sense when shading is disabled.
+ */
+ if (norm != 0)
+ {
+ real_t lweight, gweight;
+#if (TEXEL_BSIZE == 3)
+ RENDER_CAST_TYPE addGrey;
+#endif
+
+ norm = (real_t)(1/sqrt(norm));
+ /* norm = n * l = cos(alpha) */
+ norm = norm * (vx0 * vx1 + vy0 * vy1 + vz0 * vz1);
+ /* Check if the cos is within the angle specified */
+ if ((lweight = norm - ppd->lightsCos) < 0) lweight = 0; else lweight *= ppd->lightsScale;
+ /* lweight = multiplier for pixel intensities */
+ lweight = (real_t)(ppd->lightsAmbient + lweight * (1.0 - ppd->lightsAmbient));
+ if ((gweight = norm - ppd->lightsScintCos) < 0) gweight = 0; else gweight *= ppd->lightsScintScale;
+#if (TEXEL_BSIZE == 3)
+ if (voxColour != NULL)
+ {
+ red = (*voxColour) & 0xff; green = ((*voxColour) >> 8) & 0xff; blue = ((*voxColour) >> 16) & 0xff;
+ }
+ addGrey = (RENDER_CAST_TYPE)(((red + green + blue) / 3) * gweight);
+ red = (uint32)(lweight * red + addGrey);
+ green = (uint32)(lweight * green + addGrey);
+ blue = (uint32)(lweight * blue + addGrey);
+ /* Limit range */
+ if (red > 0xff) red = 0xff;
+ if (green > 0xff) green = 0xff;
+ if (blue > 0xff) blue = 0xff;
+#else
+ if (voxColour != NULL)
+ {
+ pixel = *voxColour;
+ }
+ /* Add a ``white''-component depending on scintillation angle and gain parameter */
+ pixel = (RENDER_CAST_TYPE)(pixel * (lweight + gweight));
+#ifndef RENDER_FLOAT_TYPE
+ /* Limit range for non-floating types */
+ if (pixel > ((1<<(8*TEXEL_BSIZE))-1)) pixel = ((1<<(8*TEXEL_BSIZE))-1);
+#endif
+#endif
+ }
+ }
+#if (TEXEL_BSIZE == 3)
+ dest.c[0] = (uint8)red; dest.c[1] = (uint8)green; dest.c[2] = (uint8)blue;
+ dest.c += 3;
+#else
+# if (TEXEL_BSIZE == 1)
+ *dest.c++ = (uint8)pixel;
+# elif (TEXEL_BSIZE == 2)
+ *dest.s++ = (uint16)pixel;
+# elif (TEXEL_BSIZE == 4)
+# ifdef RENDER_FLOAT_TYPE
+ *dest.f++ = (float)pixel;
+# else
+ *dest.l++ = (uint32)pixel;
+# endif
+# else
+ *dest.d++ = (double)pixel;
+# endif
+#endif
+ }
+ }
+}
diff --git a/applications/rview/generate_trans.sh b/applications/rview/generate_trans.sh
new file mode 100644
index 0000000..11ca279
--- /dev/null
+++ b/applications/rview/generate_trans.sh
@@ -0,0 +1,1013 @@
+#!/usr/bin/ksh
+#
+# Shell-script that creates C-source code for translating the
+# pixmap translation calls used by the wxPixmap-class.
+# (C) 2003 Dr. Peter Baumann
+
+
+
+# If we don't build to a local file things take forever!
+TempSourceFile="/tmp/gtrans_build.x"
+# Filenames to store the source under
+TransSourceFile="wx_pixmap_translate.c"
+TransHeaderFile="wx_pixmap_translate.h"
+DitherSourceFile="wx_pixmap_dither.cpp"
+DitherHeaderFile="wx_pixmap_dither.h"
+
+
+# Modes to build translators to / from for
+ConvertFromModes="0 1 2 3 5 12 15 24"
+ConvertToModes="0 1 2 3 4 5 15 24"
+
+# Print debugging info from each function
+OutputDebugInfo=0
+
+
+# Now machine-dependent setups
+type_u8="unsigned char"
+type_u16="unsigned short"
+type_s16="short"
+type_u32="unsigned long"
+
+
+# Bitorder of source and destination data. 0 = lsb, 1 = msb
+# These should be identical.
+# palette_fill determines the fill order of the palette (also used as screen format):
+# bit 0: fill order, bit 1: colour order. i.e. 0 (0bgr), 1 (bgr0), 2 (0rgb), 3 (rgb0)
+# sixin16bpp determines which of the three colour-components is 6 bits long
+# For typical Unix-systems use 1, 1, 0
+# for NT/LINUX use 0, 0, 2
+src_bitorder=1
+src_byteorder=1
+palette_fill=0
+
+sixin16bpp=1
+
+# These will be variable
+#dest_bitorder=1
+#dest_byteorder=1
+
+
+
+
+# The following lines should be OK for any system.
+
+
+
+# $1, $2, $3 names of colour components. Should always be ordered red, green blue
+InternalComponentsToInt() {
+ InternRGBToIntL="$1 | ($2<<8) | ($3<<16)"
+ InternRGBSToIntS15="($1>>3) | ($2<<2) | ($3<<7)"
+ InternRGBLToIntS15="($1>>3) | (($2&0xf8)<<2) | (($3&0xf8)<<7)"
+}
+
+# $1, $2, $3 names of colour components. Usually (red, green, blue) or (blue, green, red)
+# In case of S this means each colour component is 5 bits (top bits in 8)
+InitComponentsToInt() {
+ # Has the destination mode the same byteorder as the source (native) machine?
+ if [ $src_byteorder -eq $dest_byteorder ]; then
+ if [ $(( $palette_fill & 1 )) -eq 0 ]; then
+ RGBToIntL="$1 | ($2<<8) | ($3<<16)"
+ RGBSToIntS15="($1>>3) | ($2<<2) | ($3<<7)"
+ RGBLToIntS15="($1>>3) | (($2&0xf8)<<2) | (($3&0xf8)<<7)"
+ else
+ RGBToIntL="($1<<8) | ($2<<16) | ($3<<24)"
+ RGBSToIntS15="($1>>2) | ($2<<3) | ($3<<8)"
+ RGBLToIntS15="(($1&0xf8)>>2) | (($2&0xf8)<<3) | ($3<<8)"
+ fi
+
+ # 16bpp asymmetry, only depends on colour order (which is determined outside this function)
+ if [ $sixin16bpp -eq 0 ]; then
+ RGBSToIntS16="($1>>2) | ($2<<3) | ($3<<8)"
+ RGBLToIntS16="($1>>2) | (($2&0xf8)<<3) | (($3&0xf8)<<8)"
+ elif [ $sixin16bpp -eq 1 ]; then
+ RGBSToIntS16="($1>>3) | ($2<<3) | ($3<<8)"
+ RGBLToIntS16="($1>>3) | (($2&0xfc)<<3) | (($3&0xf8)<<8)"
+ else
+ RGBSToIntS16="($1>>3) | ($2<<2) | ($3<<7)"
+ RGBLToIntS16="($1>>3) | (($2&0xf8)<<2) | (($3&0xfc)<<8)"
+ fi
+ else
+ if [ $(( $palette_fill & 1 )) -eq 0 ]; then
+ RGBToIntL="($1<<24) | ($2<<16) | ($3<<8)"
+ RGBSToIntS15="($1<<5) | (($2&0x38)<<10) | ($2>>6) | ($3>>1)"
+ RGBLToIntS15="(($1&0xf8)<<5) | (($2&0x38)<<10) | ($2>>6) | (($3&0xf8)>>1)"
+ else
+ RGBToIntL="($1<<16) | ($2<<8) | $3"
+ RGBSToIntS15="($1<<6) | (($2&0x18)<<11) | ($2>>5) | $3"
+ RGBLToIntS15="((1&0xf8)<<6) | (($2&0x18)<<11) | ($2>>5) | ($3&0xf8)"
+ fi
+
+ if [ $sixin16bpp -eq 0 ]; then
+ RGBSToIntS16="($1<<6) | (($2&0x18)<<11) | ($2>>5) | $3"
+ RGBLToIntS16="(($1&0xfc)<<6) | (($2&0x18)<<11) | ($2>>5) | ($3&0xf8)"
+ elif [ $sixin16bpp -eq 1 ]; then
+ RGBSToIntS16="($1<<5) | (($2&0x1c)<<11) | ($2>>5) | $3"
+ RGBLToIntS16="(($1&0xf8)<<5) | (($2&0x1c)<<11) | ($2>>5) | ($3&0xf8)"
+ else
+ RGBSToIntS16="($1<<5) | (($2&0x38)<<10) | ($2>>6) | $3"
+ RGBLToIntS16="(($1&0xf8)<<5) | (($2&0x38)<<10) | ($2>>6) | ($3&0xfc)"
+ fi
+ fi
+
+}
+
+
+# $1, $2, $3 = component names of the three colours
+InitRGBToInt() {
+ if [ $(( $palette_fill & 2 )) -eq 0 ]; then
+ WriteRGB24="*dest_ptr++ = $1, *dest_ptr++ = $2, *dest_ptr++ = $3"
+ InitComponentsToInt $1 $2 $3
+ else
+ WriteRGB24="*dest_ptr++ = $3, *dest_ptr++ = $2, *dest_ptr++ = $1"
+ InitComponentsToInt $3 $2 $1
+ fi
+}
+
+
+# $1 = cast, $2, $3, $4 component names, $5 aux var
+InitIntToComponents() {
+# Internal representation is constant, RGB starting from bit 0
+IntLToRGBL="$2=$1($5&0xff), $3=$1(($5>>8)&0xff), $4=$1(($5>>16)&0xff)"
+IntLToRGBS="$2=$1($5&0xf8), $3=$1(($5>>8)&0xf8), $4=$1(($5>>16)&0xf8)"
+IntSToRGB="$2=$1(($5<<3)&0xf8), $3=$1(($5>>2)&0xf8), $4=$1(($5>>7)&0xf8)"
+}
+
+
+# $1 = cast. This could contain spaces so make sure to enclose it in quotes!
+# $2, $3, $4 = component names of the three colours, $5 = auxiliary variable
+InitIntToRGB() {
+# Same reason here
+ InitIntToComponents "$1" $2 $3 $4 $5
+}
+
+
+
+# Output functions.
+
+# Initialise the output: $1 = filename
+InitOutput () {
+ rm -f $1
+ CurrentFile=$1
+ CurrentIndent=0
+ TabChar=$(echo \\011)
+ CurrentPrefix=""
+}
+
+# Output data _formatted_. Brace checks are primitive but work OK here.
+output() {
+ if [ "$1" = '}' ] && [ $CurrentIndent -gt 0 ]; then
+ CurrentIndent=$(($CurrentIndent-1))
+ CurrentPrefix=${CurrentPrefix%$TabChar}
+ fi
+ echo "$CurrentPrefix$1" >> $CurrentFile
+ if [ "$1" = '{' ]; then
+ CurrentIndent=$(($CurrentIndent+1))
+ CurrentPrefix="$CurrentPrefix$TabChar"
+ fi
+}
+
+
+# Writes some information in the header
+
+WriteHeaderComment() {
+ output "/*"
+ output " * $CurrentFile"
+ output " * $CurrentDescriptor"
+ output " * Auto-generated $(date)"
+ output " * (C) 2003, Dr. Peter Baumann"
+ output " */"
+ output ""
+}
+
+
+# Get a pixel.
+# $1 = src-ldbpp, $2 = dest-ldbpp, $3 = pixel number
+
+GetPixel() {
+ if [ $1 -lt 3 ]; then
+ if [ $src_bitorder -eq 0 ]; then
+ pixel_value="$(( ($3 * (1<<$1)) & 7))"
+ else
+ pixel_value="$(( ( ($src_ppc-1-$3) * (1<<$1) ) & 7))"
+ fi
+ subidx=$(( $3 >> (3-$1) ))
+ pixel_value="((src_ptr[subidx + $subidx] >> $pixel_value ) & $(( (1<<$sbpp)-1 )) )"
+ else
+ if [ $1 -eq 12 ]; then
+ pixel_value="((*src_ptr++)>>4)"
+ elif [ $1 -eq 24 ]; then
+ pixel_value="red=*src_ptr++, green=*src_ptr++, blue=*src_ptr++"
+ else
+ pixel_value="src_ptr[i + $3]"
+ fi
+ fi
+}
+
+
+# Get a pixel without the optimizations possible in GetPixel
+# ( ((i >> (3-$1)) << (3-$1)) == i ) and translate pixel to RGB
+# values. $1 = src-ldbpp, $2 = dest_ldbpp
+
+GetRGBPixel() {
+ if [ $1 -lt 3 ]; then
+ if [ $src_bitorder -eq 0 ]; then
+ pixel_value="( (i*$sbpp) & 7)"
+ else
+ pixel_value="( ($((8-$sbpp)) - i*$sbpp) & 7)"
+ fi
+ pixel_value="pixPal=pixmapPalette + ((src_ptr[i >> $(( 3-$1 ))] >> $pixel_value ) & $(( (1<<$sbpp)-1 )) ), red=pixPal->red, green=pixPal->green, blue=pixPal->blue"
+ else
+ if [ $1 -eq 24 ]; then
+ pixel_value="red=*src_ptr++, green=*src_ptr++, blue=*src_ptr++"
+ elif [ $1 -eq 12 ]; then
+ pixel_value="red=((*src_ptr++)>>4), green=red, blue=red"
+ else
+ pixel_value="src_ptr[i]"
+ if [ $1 -eq 3 ]; then
+ pixel_value="pixPal=pixmapPalette + $pixel_value, red=pixPal->red, green=pixPal->green, blue=pixPal->blue"
+ # Basically $1 can only be 15
+ elif [ $1 -eq 15 ] || [ $1 -eq 4 ]; then
+ pixel_value="val=$pixel_value, $IntSToRGB"
+ else
+ pixel_value="val=$pixel_value, $IntLToRGBL"
+ fi
+ fi
+ fi
+}
+
+
+# Get a pixel and translate it to the destination mode.
+# Arguments as for GetPixel
+GetPixelTrans() {
+ # First create the command to actually get the pixel
+ GetPixel $1 $2 $3
+
+ # Now Translate the pixel
+
+ # Source mode not true-colour
+ if [ $1 -lt 4 ]; then
+ if [ $2 -gt 3 ]; then
+ if [ $2 -eq 24 ]; then
+ pixel_value="val=ttl[$pixel_value], $IntLToRGBL"
+ else
+ pixel_value="ttl[$pixel_value]"
+ fi
+ else
+ pixel_value="tt[$pixel_value]"
+ fi
+ # Source-mode 15bpp
+ elif [ $1 -eq 15 ]; then
+ # destination mode <= 8bpp
+ if [ $2 -lt 4 ]; then
+ pixel_value="tt[$pixel_value & 0x7fff]"
+ # destination mode 15bpp (==> change bitorder)
+ elif [ $2 -eq 4 ]; then
+ pixel_value="(val=$pixel_value, $IntSToRGB, $RGBSToIntS16)"
+ elif [ $2 -eq 5 ]; then
+ pixel_value="(val=$pixel_value, $IntSToRGB, $RGBToIntL)"
+ elif [ $2 -eq 15 ]; then
+ pixel_value="(val=$pixel_value, $IntSToRGB, $RGBSToIntS15)"
+ elif [ $2 -eq 24 ]; then
+ pixel_value="(val=$pixel_value, $IntSToRGB)"
+ fi
+ # Source-mode 12bpp
+ elif [ $1 -eq 12 ]; then
+ if [ $2 -lt 4 ]; then
+ pixel_value="tt[($pixel_value)&0xff]"
+ elif [ $2 -eq 4 ]; then
+ pixel_value="(red=($pixel_value)&0xf8, green=red, blue=red, $RGBSToIntS16)"
+ elif [ $2 -eq 5 ]; then
+ pixel_value="(red=$pixel_value, green=red, blue=red, $RGBToIntL)"
+ elif [ $2 -eq 15 ]; then
+ pixel_value="(red=($pixel_value)&0xf8, green=red, blue=red, $RGBSToIntS15)"
+ elif [ $2 -eq 24 ]; then
+ pixel_value="(red=$pixel_value, green=red, blue=red)"
+ fi
+ # Source-mode 32bpp
+ elif [ $1 -eq 5 ]; then
+ if [ $2 -eq 24 ]; then
+ pixel_value="(val=$pixel_value, $IntLToRGBL)"
+ else
+ # Destination mode 32bpp (==> change bitorder)
+ if [ $2 -eq 5 ]; then
+ pixel_value="(val=$pixel_value, $IntLToRGBL, $RGBToIntL)"
+ else
+ if [ $2 -eq 4 ]; then
+ pixel_value="(val=$pixel_value, $IntLToRGBS, $RGBSToIntS16)"
+ else
+ if [ $2 -eq 15 ]; then
+ pixel_value="(val=$pixel_value, $IntLToRGBS, $RGBSToIntS15)"
+ else
+ pixel_value="tt[(val=$pixel_value, $IntLToRGBS, $InternRGBSToIntS15)]"
+ fi
+ fi
+ fi
+ fi
+ # Source mode 24bpp
+ elif [ $1 -eq 24 ]; then
+ if [ $2 -eq 5 ]; then
+ pixel_value="($pixel_value, $RGBToIntL)"
+ elif [ $2 -ne 24 ]; then
+ if [ $2 -eq 4 ]; then
+ pixel_value="($pixel_value, $RGBLToIntS16)"
+ else
+ if [ $2 -lt 4 ]; then
+ pixel_value="tt[($pixel_value, $InternRGBLToIntS15)]"
+ else
+ pixel_value="($pixel_value, $RGBLToIntS15)"
+ fi
+ fi
+ fi
+ fi
+
+ # And finally shift the pixel for non-24bpp destination modes
+ if [ $2 -ne 24 ]; then
+ if [ $2 -eq 15 ]; then
+ usedld=4
+ else
+ usedld=$2
+ fi
+ if [ $2 -lt 3 ]; then
+ if [ $dest_bitorder -eq 0 ]; then
+ pixel_value="($pixel_value << $(( ( $3*(1<<$usedld) ) & 7 )) )"
+ else
+ pixel_value="($pixel_value << $(( ( ($dest_ppw-1-$3)*(1<<$usedld) ) & 7 )) )"
+ fi
+ else
+ if [ $src_byteorder -eq 0 ]; then
+ pixel_value="($pixel_value << $(( ( $3*(1<<$usedld) ) & 31 )) )"
+ else
+ pixel_value="($pixel_value << $(( ( ($dest_ppw-1-$3)*(1<<$usedld) ) & 31 )) )"
+ fi
+ fi
+ fi
+}
+
+
+
+# Sets the sbpp and dbpp values according to $1 and $2
+SetModeBpp() {
+ if [ $1 -lt 6 ]; then
+ sbpp=$((1<<$1))
+ else
+ sbpp=$1
+ fi
+ if [ $2 -lt 6 ]; then
+ dbpp=$((1<<$2))
+ else
+ dbpp=$2
+ fi
+}
+
+
+
+# Outputs a function prototype signature if the function signature is not empty
+OutputFuncSig() {
+ if [ "$func_sig" != "" ]; then
+ output "$func_sig;"
+ output
+ fi
+}
+
+
+# Sets the variable func_sig to the signature of the translator function with
+# $1 = src-ldbpp, $2 = dest_ldbpp
+# if either is larger than 5 it's interpreted as bpp rather than ldbpp
+
+TranslatorSignature() {
+
+ SetModeBpp $1 $2
+
+ if [ $sbpp -le 8 ] && [ $dbpp -eq 15 ]; then
+ func_sig=""
+ return
+ fi
+
+ if [ $src_bitorder -eq $dest_bitorder ] && [ $src_byteorder -eq $dest_byteorder ]; then
+ sig_post=""
+ else
+ sig_post="i"
+ fi
+ if [ $dbpp -gt 8 ]; then
+ if [ $(( palette_fill & 2 )) -eq 0 ]; then
+ sig_post=${sig_post}rgb
+ else
+ sig_post=${sig_post}bgr
+ fi
+ fi
+ func_sig="void wx_pixmap_translate_${sbpp}_to_${dbpp}${sig_post} (const $type_u8 *src, $type_u8 *dest, int width, int height, int srcPitch, int destPitch, const $type_u8 *tt)"
+}
+
+
+
+# Arguments: $1 = src-ldbpp, $2 = dest-ldbpp
+
+MakeTranslationFunction() {
+
+ TranslatorSignature $1 $2
+
+ if [ "$func_sig" = "" ]; then
+ return
+ fi
+
+ output "$func_sig"
+ output \{
+
+ # Produce translation code for ALL modes because the order of the colour components
+ # and the endianness might differ.
+ if [ $1 -ne 24 ] || [ $(( $palette_fill & 2 )) -ne 0 ]; then
+ need_translator=1
+ else
+ need_translator=0
+ fi
+
+ if [ $1 -ne $2 ]; then
+ need_translator=1
+ if [ $1 -lt 4 ] && [ $2 -eq 15 ]; then
+ need_translator=0
+ fi
+ fi
+
+ # Is a translator function necessary?
+ if [ $need_translator -ne 0 ]; then
+
+ # Determines what special variables are needed
+ needs_val=0
+ needs_rgb=0
+
+ # setup variable block
+ output "const $type_u8 *src_line = (const $type_u8 *)src;"
+ output "$type_u8 *dest_line = dest;"
+
+ case $sbpp in
+ 1 | 2 | 4 | 8 | 24) type_srcptr=$type_u8 ;;
+ 12 | 15 | 16) type_srcptr=$type_u16 ;;
+ 32) type_srcptr=$type_u32 ;;
+ esac
+ output "register const $type_srcptr *src_ptr;"
+
+ if [ $dbpp -ge 8 ] && [ $dbpp -ne 24 ]; then
+ type_destptr=$type_u32;
+ else
+ type_destptr=$type_u8;
+ fi
+ output "register $type_destptr *dest_ptr;"
+
+ if [ $1 -gt 3 ] && [ ! $1 -eq 12 ] && [ $2 -gt 3 ]; then
+ needs_rgb=1; needs_val=1
+ elif [ $sbpp -eq 24 ] || [ $sbpp -eq 32 ] || [ $dbpp -eq 24 ] || [ $dbpp -eq 15 ]; then
+ needs_rgb=1; needs_val=1
+ fi
+ if [ $1 -eq 24 ] && [ $2 -gt 3 ]; then
+ needs_val=0
+ fi
+ if [ $1 -eq 12 ] && [ $dbpp -ge 15 ]; then
+ needs_rgb=1;
+ fi
+
+ # Cast translation table if ldsrc < 4 and lddest > 3
+ if [ $1 -lt 4 ] && [ $2 -gt 3 ]; then
+ output "const $type_u32 *ttl = (const $type_u32 *)tt;"
+ fi
+
+ output "register int i;"
+ output "int j, i_high;"
+ if [ $1 -lt 3 ]; then
+ output "register int subidx;"
+ fi
+
+ # Evaluate pixels per char in source- and pixels per word in dest mode
+ src_ppc=$((8/$sbpp))
+ if [ $dbpp -eq 15 ] || [ $dbpp -eq 12 ]; then
+ dest_ppw=2
+ elif [ $dbpp -ge 8 ]; then
+ dest_ppw=$((32/$dbpp))
+ else
+ dest_ppw=$((8/$dbpp))
+ fi
+ if [ $src_ppc -gt $dest_ppw ]; then
+ passes=$(($src_ppc/$dest_ppw)); upper_modulo=$(($src_ppc-1));
+ else
+ passes=1; upper_modulo=$(($dest_ppw-1));
+ fi
+
+ if [ $(($passes*$dest_ppw)) -gt 2 ]; then
+ needs_val=1
+ fi
+
+ # Trap some very special cases (not important, just kill ``unused variable'' warnings)
+ if [ $sbpp -eq 12 ]; then
+ if [ $dbpp -eq 15 ] || [ $dbpp -eq 24 ]; then
+ needs_val=0
+ fi
+ fi
+ if [ $sbpp -eq 24 ] && [ $dbpp -eq 4 ]; then
+ needs_val=0
+ fi
+
+ if [ $needs_val -eq 1 ]; then
+ if [ $dbpp -lt 8 ] && [ $sbpp -ne 32 ]; then
+ output "$type_u8 val;"
+ else
+ output "$type_u32 val;"
+ fi
+ fi
+ if [ $needs_rgb -eq 1 ]; then
+ output "$type_u8 red, green, blue;"
+ fi
+
+ output ""
+ if [ $OutputDebugInfo -ne 0 ]; then
+ output 'printf("Plot '"$sbpp - $dbpp:"' width = %d, height = %d, pitch(src) = %d, pitch(dest) = %d\\n", width, height, srcPitch, destPitch); fflush(stdout);'
+ fi
+ output "i_high = (width & ~$upper_modulo );"
+
+ # now for the main loop
+ output "for (j=0; j<height; j++, src_line += srcPitch, dest_line += destPitch)"
+ output \{
+ output "src_ptr = (const $type_srcptr *)src_line; dest_ptr = ($type_destptr *)dest_line;"
+ output "for (i=0; i<i_high; i+=$(($passes*$dest_ppw)) )"
+ output \{
+
+ if [ $1 -lt 3 ]; then
+ output "subidx = (i >> $((3-$1)) );"
+ fi
+
+ pass=$passes
+ while [ $pass -gt 0 ]; do
+ if [ $2 -ne 24 ]; then
+ output "*dest_ptr ="
+ fi
+ loop=0
+ while [ $loop -lt $dest_ppw ]; do
+ GetPixelTrans $1 $2 $(( ($passes - $pass)*$dest_ppw + $loop ))
+ if [ $dbpp -eq 24 ]; then
+ output "$pixel_value, $WriteRGB24;"
+ else
+ output "$pixel_value;"
+ if [ $loop -ne $((dest_ppw - 1)) ]; then
+ output "*dest_ptr |= "
+ fi
+ fi
+ loop=$(($loop+1))
+ done
+ if [ $2 -ne 24 ]; then
+ output "dest_ptr++;"
+ fi
+ pass=$(($pass-1))
+ done;
+
+ output \}
+
+ # Now pad the remaining bytes for modes with less than 32bpp
+ if [ $(($passes*$dest_ppw)) -gt 1 ]; then
+ output "if (i < width)"
+ output \{
+ GetPixelTrans $1 $2 0
+ if [ $1 -lt 3 ]; then
+ output "subidx = (i >> $((3-$1)) );"
+ fi
+ if [ $(($passes*$dest_ppw)) -eq 2 ]; then
+ if [ $2 -ne 24 ]; then
+ output "*dest_ptr++ = $pixel_value;"
+ else
+ output "$pixel_value, $WriteRGB24;"
+ fi
+ else
+ if [ $2 -ne 24 ]; then
+ output "val = $pixel_value;"
+ else
+ output "$pixel_value, $WriteRGB24;"
+ fi
+ loop=1
+ while [ $loop -lt $(($passes*$dest_ppw - 1)) ]; do
+ GetPixelTrans $1 $2 $loop
+ output "if (i+$loop < width)"
+ output \{
+ if [ $2 -ne 24 ]; then
+ if [ $(($loop & ($dest_ppw - 1) )) -eq 0 ]; then
+ output "*dest_ptr++ = val; val = $pixel_value;"
+ else
+ output "val |= $pixel_value;"
+ fi
+ else
+ output "$pixel_value, $WriteRGB24;"
+ fi
+ output \}
+ loop=$(($loop+1))
+ done
+ if [ $2 -ne 24 ]; then
+ output "*dest_ptr++ = ($type_destptr)val;"
+ fi
+ fi
+ output \}
+ fi
+
+ output \}
+
+ if [ $OutputDebugInfo -ne 0 ]; then
+ output 'printf("OK.\\n"); fflush(stdout);'
+ fi
+
+ # from 15->15 / 24->24 / 32->32 trap
+ fi
+
+ output \}
+}
+
+
+
+# Signature of a dithering function
+# This is realised as wxPixmap member-functions
+DithererSignature() {
+
+ SetModeBpp $1 $2
+
+ if [ $src_bitorder -eq $dest_bitorder ] && [ $src_byteorder -eq $dest_byteorder ]; then
+ sig_post=""
+ else
+ sig_post="i"
+ fi
+ func_sig="void wxPixmap::dither_${sbpp}_to_${dbpp}${sig_post} ($type_u8 *dest, int destPad)"
+}
+
+
+
+
+# Ditherer from mode $1 to mode $2
+
+MakeDitheringFunction() {
+ # Only make ditherers for displays with <= 8bpp
+ if [ $2 -lt 4 ]; then
+
+ DithererSignature $1 $2
+ output "$func_sig"
+
+ output \{
+
+ need_idx=0
+
+ output "$type_s16 *errors, *err_ptr;"
+ output "$type_s16 red, green, blue, err_red_r, err_green_r, err_blue_r, err_red_d, err_green_d, err_blue_d;"
+ output "const $type_u8 *src_line = (const $type_u8 *)data;"
+ output "$type_u8 *dest_line = ($type_u8 *)dest;"
+
+ case $1 in
+ 0 | 1 | 2 | 3 | 24) type_srcptr=$type_u8 ;;
+ 4 | 12 | 15) type_srcptr=$type_u16 ;;
+ 5) type_srcptr=$type_u32 ;;
+ esac
+
+ output "register const $type_srcptr *src_ptr;"
+ output "$type_u8 *dest_ptr;"
+ output "$type_u8 r, g, b;"
+ output "int i, j, destPitch;"
+
+ output "register wx_permute_cmap *pixPal;"
+
+ if [ $1 -eq 4 ] || [ $1 -eq 15 ]; then
+ output "$type_u16 val;"
+ elif [ $1 -eq 5 ]; then
+ output "$type_u32 val;"
+ fi
+ if [ $2 -lt 3 ]; then
+ output "$type_u8 pixels;"
+ output "int shift;"
+ fi
+
+ if [ $OutputDebugInfo -ne 0 ]; then
+ output "*errorstr << \"Dither $1 to $2\" << endl;"
+ fi
+
+ output ""
+ output "if ((errors = ($type_s16 *)malloc(3*width*sizeof($type_s16))) == NULL) return;"
+ output "memset((void*)errors, 0, 3*width*sizeof($type_s16));"
+
+ # Pixels per char in src / dest mode
+ src_ppc=$(( 8 >> $1 ))
+ dest_ppc=$(( 8 >> $2 ))
+
+ if [ $dest_bitorder -eq 0 ]; then
+ shift_start=0; shift_step=$dbpp; shift_end=8;
+ else
+ shift_start=$((8-$dbpp)); shift_step=$((-$dbpp)); shift_end=$((0-$dbpp))
+ fi
+
+ output "destPitch = ((width*$dbpp + destPad-1) & ~(destPad-1)) >> 3;"
+
+ output "for (j=0; j<height; j++, src_line += pitch, dest_line += destPitch)"
+ output \{
+ output "src_ptr = (const $type_srcptr *)src_line; dest_ptr = ($type_u8 *)dest_line;"
+ output "err_red_r = 0; err_green_r = 0; err_blue_r = 0;"
+ output "err_red_d = 0; err_green_d = 0; err_blue_d = 0;"
+ if [ $2 -lt 3 ]; then
+ output "pixels = 0; shift = $shift_start;"
+ fi
+ output "for (i=0, err_ptr=errors; i<width; i++, err_ptr += 3)"
+ output \{
+ GetRGBPixel $1 $2
+ output "$pixel_value;"
+ output "red += err_red_r + err_ptr[0]; green += err_green_r + err_ptr[1]; blue += err_blue_r + err_ptr[2];"
+ output "if (red < 0) r=0; else if (red > 255) r=255; else r=red;"
+ output "if (green < 0) g=0; else if (green > 255) g=255; else g=green;"
+ output "if (blue < 0) b=0; else if (blue > 255) b=255; else b=blue;"
+ output "pixPal = parentPalette + (this->*colour_matcher)(r, g, b);"
+ output "red = ($type_s16)r - ($type_s16)(pixPal->red); green = ($type_s16)g - ($type_s16)(pixPal->green); blue = ($type_s16)b - ($type_s16)(pixPal->blue);"
+ output "err_red_r = (3*red)/8; err_green_r = (3*green)/8; err_blue_r = (3*blue)/8;"
+ output "err_ptr[0] = err_red_r + err_red_d; err_ptr[1] = err_green_r + err_green_d; err_ptr[2] = err_blue_r + err_blue_d;"
+ output "err_red_d = red/4; err_green_d = green/4; err_blue_d = blue/4;"
+ output "err_red_r = red - err_red_d - err_red_r; err_green_r = green - err_green_d - err_green_r; err_blue_r = blue - err_blue_d - err_blue_r;"
+
+ if [ $2 -eq 3 ]; then
+ output "*dest_ptr++ = pixPal->number;"
+ else
+ output "pixels |= (pixPal->number << shift);"
+ output "shift += $shift_step;"
+ output "if (shift == $shift_end)"
+ output \{
+ output "*dest_ptr++ = pixels; pixels = 0; shift = $shift_start;"
+ output \}
+ fi
+ output \}
+ if [ $2 -ne 3 ]; then
+ output "if (shift != $shift_start) *dest_ptr++ = pixels;"
+ fi
+ output \}
+ output "free(errors);"
+
+ output \}
+
+ # ($2 < 4)
+ fi
+}
+
+
+
+
+# Customizations
+if [ "$1" = "0" ] || [ "$1" = "1" ]; then
+ src_bitorder=$1
+fi
+if [ "$2" = "0" ] || [ "$2" = "1" ]; then
+ src_byteorder=$2
+fi
+if [ "$3" = "0" ] || [ "$3" = "1" ] || [ "$3" = "2" ] || [ "$3" = "3" ]; then
+ palette_fill=$3
+fi
+
+localdisplay=0
+if [ "$4" = "-local" ]; then
+ localdisplay=1
+fi
+
+echo "Using src_bitorder=$src_bitorder, src_byteorder=$src_byteorder, palette_fill=$palette_fill"
+if [ $localdisplay -eq 0 ]; then
+ echo "Create translators for different endianness"
+else
+ echo "Local displays only, one setting."
+fi
+
+echo "Creating ditherers for modes $ConvertFromModes --> $ConvertToModes:"
+
+CurrentDescriptor="Dithering functions from/to various depths."
+
+echo "Creating source file $DitherSourceFile ..."
+
+InitOutput $TempSourceFile
+
+WriteHeaderComment
+
+output "// This file must be included from wx_pixmap.cpp"
+output ""
+
+# Make translation functions
+
+InternalComponentsToInt red green blue
+
+# We have to init these macros for native and inverted byteorder
+
+dest_bitorder=$src_bitorder; dest_byteorder=$src_byteorder
+InitRGBToInt red green blue
+InitIntToRGB "($type_s16)" red green blue val
+
+for source_mode in $ConvertFromModes; do
+ for dest_mode in $ConvertToModes; do
+ MakeDitheringFunction $source_mode $dest_mode
+ output ""
+ done
+done
+
+# Create additional plotters for network displays?
+if [ $localdisplay -eq 0 ]; then
+
+ dest_bitorder=$(( $src_bitorder ^ 1 )); dest_byteorder=$(( $src_byteorder ^ 1))
+ InitRGBToInt red green blue
+ InitIntToRGB "($type_s16)" red green blue val
+
+ for source_mode in $ConvertFromModes; do
+ for dest_mode in $ConvertToModes; do
+ MakeDitheringFunction $source_mode $dest_mode
+ output ""
+ done
+ done
+
+fi # localdisplay
+
+mv $TempSourceFile $DitherSourceFile
+
+echo "Creating header file $DitherHeaderFile ..."
+
+InitOutput $TempSourceFile
+
+for source_mode in $ConvertFromModes; do
+ for dest_mode in $ConvertToModes; do
+ if [ $dest_mode -lt 4 ]; then
+ dest_bitorder=$src_bitorder; dest_byteorder=$src_byteorder
+ DithererSignature $source_mode $dest_mode
+ output "$func_sig;"
+ if [ $localdisplay -eq 0 ]; then
+ dest_bitorder=$(( $src_bitorder ^ 1 )); dest_byteorder=$(( $src_byteorder ^ 1))
+ DithererSignature $source_mode $dest_mode
+ output "$func_sig;"
+ fi
+ fi
+ done
+done
+
+mv $TempSourceFile $DitherHeaderFile
+
+
+
+
+# Now down to business: create all translation functions as
+# C code.
+
+
+echo "Creating converters for modes $ConvertFromModes --> $ConvertToModes:"
+
+CurrentDescriptor="Translator functions for bitmaps from/to various depths."
+
+echo "Creating source file $TransSourceFile ..."
+
+InitOutput $TempSourceFile
+
+if [ $OutputDebugInfo -ne 0 ]; then
+ output "#include <stdio.h>"
+fi
+output "#include \"$TransHeaderFile\""
+output ""
+
+WriteHeaderComment
+
+dest_bitorder=$src_bitorder; dest_byteorder=$src_byteorder
+InitRGBToInt red green blue
+InitIntToRGB "($type_u8)" red green blue val
+
+for source_mode in $ConvertFromModes; do
+ for dest_mode in $ConvertToModes; do
+ MakeTranslationFunction $source_mode $dest_mode
+ output ""
+ done
+done
+
+palette_fill=$(( $palette_fill ^ 2 ))
+
+InitRGBToInt red green blue
+InitIntToRGB "($type_u8)" red green blue val
+
+for source_mode in $ConvertFromModes; do
+ for dest_mode in $ConvertToModes; do
+ if [ $dest_mode -gt 3 ]; then
+ MakeTranslationFunction $source_mode $dest_mode
+ output ""
+ fi
+ done
+done
+
+palette_fill=$(( $palette_fill ^ 2 ))
+
+if [ $localdisplay -eq 0 ]; then
+ dest_bitorder=$(( $src_bitorder ^ 1 )); dest_byteorder=$(( $src_byteorder ^ 1 ))
+
+ InitRGBToInt red green blue
+ InitIntToRGB "($type_u8)" red green blue val
+
+ for source_mode in $ConvertFromModes; do
+ for dest_mode in $ConvertToModes; do
+ MakeTranslationFunction $source_mode $dest_mode
+ output ""
+ done
+ done
+
+ palette_fill=$(( $palette_fill ^ 2 ))
+
+ InitRGBToInt red green blue
+ InitIntToRGB "($type_u8)" red green blue val
+
+ for source_mode in $ConvertFromModes; do
+ for dest_mode in $ConvertToModes; do
+ if [ $dest_mode -gt 3 ]; then
+ MakeTranslationFunction $source_mode $dest_mode
+ output ""
+ fi
+ done
+ done
+
+ palette_fill=$(( $palette_fill ^ 2 ))
+
+fi # localdisplay
+
+InitRGBToInt red green blue
+InitIntToRGB "($type_u8)" red green blue
+
+
+mv $TempSourceFile $TransSourceFile
+
+
+# Then write the header file
+
+echo "Creating header file $TransHeaderFile ..."
+
+InitOutput $TempSourceFile
+
+output "#ifndef _WX_PIXMAP_TRANSLATE_H_"
+output "#define _WX_PIXMAP_TRANSLATE_H_"
+output ""
+output "#ifdef __cplusplus"
+output 'extern "C" {'
+output "#endif"
+output ""
+
+WriteHeaderComment
+
+output "#define WX_PIXMAP_SRC_BITORDER $src_bitorder"
+output "#define WX_PIXMAP_SRC_BYTEORDER $src_byteorder"
+output "#define WX_PIXMAP_PALETTE_FILL $palette_fill"
+output ""
+
+
+dest_bitorder=$src_bitorder; dest_byteorder=$src_byteorder;
+InitRGBToInt "(red)" "(green)" "(blue)"
+InitIntToRGB "" "(red)" "(green)" "(blue)" "(val)"
+
+output "/* The following macros are for internal use only */"
+output "#define _RGB_TO_PALETTE_LONG(red,green,blue) ($RGBToIntL)"
+output "#define _RGBS_TO_PALETTE_SHORT15(red,green,blue) ($RGBSToIntS15)"
+output "#define _RGBL_TO_PALETTE_SHORT15(red,green,blue) ($RGBLToIntS15)"
+output "#define _RGBS_TO_PALETTE_SHORT16(red,green,blue) ($RGBSToIntS16)"
+output "#define _RGBL_TO_PALETTE_SHORT16(red,green,blue) ($RGBLToIntS16)"
+
+if [ $dest_bitorder -eq 0 ]; then dest_bitorder=1; else dest_bitorder=0; fi
+if [ $dest_byteorder -eq 0 ]; then dest_byteorder=1; else dest_byteorder=0; fi
+InitRGBToInt "(red)" "(green)" "(blue)"
+InitIntToRGB "" "(red)" "(green)" "(blue)" "(val)"
+output "#define _RGB_TO_PALETTE_LONGi(red,green,blue) ($RGBToIntL)"
+output "#define _RGBS_TO_PALETTE_SHORT15i(red,green,blue) ($RGBSToIntS15)"
+output "#define _RGBL_TO_PALETTE_SHORT15i(red,green,blue) ($RGBLToIntS15)"
+output "#define _RGBS_TO_PALETTE_SHORT16i(red,green,blue) ($RGBSToIntS16)"
+output "#define _RGBL_TO_PALETTE_SHORT16i(red,green,blue) ($RGBLToIntS16)"
+output ""
+
+output "/* Use these macros if you use wxPixmap class with translations turned on */"
+output "#define PALETTE_LONG_TO_RGB(val,red,green,blue) ($IntLToRGBL)"
+output "#define PALETTE_SHORT_TO_RGB(val,red,green,blue) ($IntSToRGB)"
+output "#define RGBS_TO_PALETTE_SHORT(red,green,blue) (((red)>>3) | ((green)<<2) | ((blue)<<7))"
+output "#define RGBL_TO_PALETTE_SHORT(red,green,blue) (((red)>>3) | (((green)&0xf8)<<2) | (((blue)&0xf8)<<7))"
+output "#define RGB_TO_PALETTE_LONG(red,green,blue) ((red) | ((green)<<8) | ((blue)<<16))"
+output ""
+
+for source_mode in $ConvertFromModes; do
+ for dest_mode in $ConvertToModes; do
+ dest_bitorder=$src_bitorder; dest_byteorder=$src_byteorder
+ TranslatorSignature $source_mode $dest_mode
+ OutputFuncSig
+ if [ $dest_mode -gt 3 ]; then
+ palette_fill=$(( $palette_fill ^ 2 ))
+ TranslatorSignature $source_mode $dest_mode
+ OutputFuncSig
+ palette_fill=$(( $palette_fill ^ 2 ))
+ fi
+ if [ $localdisplay -eq 0 ]; then
+ dest_bitorder=$(( src_bitorder ^ 1 )); dest_byteorder=$(( src_byteorder ^ 1 ))
+ TranslatorSignature $source_mode $dest_mode
+ OutputFuncSig
+ if [ $dest_mode -gt 3 ]; then
+ palette_fill=$(( $palette_fill ^ 2 ))
+ TranslatorSignature $source_mode $dest_mode
+ OutputFuncSig
+ palette_fill=$(( $palette_fill ^ 2 ))
+ fi
+ fi
+ done
+ output ""
+done
+
+output "#ifdef __cplusplus"
+output "}"
+output "#endif"
+output ""
+
+output "#endif"
+
+mv $TempSourceFile $TransHeaderFile
diff --git a/applications/rview/labelManager.cpp b/applications/rview/labelManager.cpp
new file mode 100644
index 0000000..4134922
--- /dev/null
+++ b/applications/rview/labelManager.cpp
@@ -0,0 +1,314 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+ * PURPOSE:
+ *
+ * The label manager class is used to lookup label:value pairs
+ * stored in a text file. The constructor reads in the file whose
+ * name is passed to it and sorts the non-empty, non-commentary
+ * lines (commentary lines have a '#' as the first non-white
+ * character in a line) in ascending order to make binary searching
+ * possible. The binary search is performed by the lookup member
+ * function.
+ *
+ * COMMENTS: None
+ */
+
+
+
+
+#include <stdio.h>
+#include <string.h>
+#include "iostream.h"
+
+
+
+#include "labelManager.hh"
+
+
+
+
+
+/*
+ * Load the resource file, parse and sort it.
+ */
+
+labelManager::labelManager(const char *resourceFile)
+{
+ FILE *fp;
+ size_t filesize;
+ int i;
+ char c, *b, *upper;
+
+ buffer = NULL; lineTable = NULL; lines = 0;
+ strncpy(badSymbol, "???", 4);
+
+ if ((fp = fopen(resourceFile, "r")) == NULL)
+ {
+ cerr << "Unable to open resource file " << resourceFile << endl;
+ return;
+ }
+
+ // Position to end of file to determine its length.
+ fseek(fp, 0, SEEK_END);
+ filesize = ftell(fp);
+
+ if ((buffer = new char[filesize+1]) == NULL)
+ {
+ cerr << "Not enough memory for buffer!" << endl;
+ }
+
+ fseek(fp, 0, SEEK_SET);
+ // Read in the file and make sure it's terminated by a newline char.
+ fread((void*)buffer, 1, filesize, fp);
+ buffer[filesize] = '\n';
+ fclose(fp);
+
+ upper = buffer + filesize; b = buffer;
+
+ // Pass 1: calculate how much memory is needed for the lineTable.
+ do
+ {
+ // for (i=0; b[i] != '\n'; i++) {cout << b[i];} cout << endl;
+ // Ignore leading whitespace
+ do {c = *b++;} while ((c == ' ') || (c == '\t'));
+ // Commentary line?
+ if (c == '#')
+ {
+ do {c = *b++;} while (c != '\n');
+ }
+ // Line not empty?
+ else if (c != '\n')
+ {
+ lines++; i = 0; i = (b - buffer) - 1;
+ // Make sure it contains a colon!
+ do {c = *b++; if (c == ':') {i = -1;}} while (c != '\n');
+ if (i >= 0)
+ {
+ cerr << "Bad line format (missing colon): ";
+ while (buffer[i] != '\n') {cout << buffer[i]; i++;} cout << endl;
+ delete [] buffer; buffer = NULL; lines = 0; return;
+ }
+ }
+ }
+ while (b < upper);
+
+ if ((lineTable = new char*[lines]) == NULL)
+ {
+ cerr << "Not enough memory for lineTable!" << endl;
+ delete [] buffer; buffer = NULL; lines = 0; return;
+ }
+
+ b = buffer; i = 0;
+
+ // Pass 2: fill in lineTable
+ do
+ {
+ do {c = *b++;} while ((c == ' ') || (c == '\t'));
+ if (c == '#')
+ {
+ do {c = *b++;} while (c != '\n');
+ }
+ else if (c != '\n')
+ {
+ lineTable[i++] = b-1;
+ do {c = *b++;} while (c != '\n');
+ // terminate all non-empty lines with '\0'
+ *(b-1) = '\0';
+ }
+ }
+ while (b < upper);
+
+ if ((unsigned int)i != lines)
+ {
+ cerr << "Fatal error: passes incompatible!" << endl;
+ }
+
+ sortResources(0, lines-1);
+
+ /*cout << lines << " label definitions found." << endl;
+ for (i=0; i<lines; i++)
+ {
+ cout << lineTable[i] << endl;
+ }*/
+}
+
+
+
+/*
+ * Quicksort, using the label identifiers as key.
+ */
+
+void labelManager::sortResources(int from, int to)
+{
+ int i, j;
+ char *swap, *l, *m;
+
+ while (from < to)
+ {
+ i = (from + to) / 2;
+ swap = lineTable[from]; lineTable[from] = lineTable[i]; lineTable[i] = swap;
+ j = from;
+
+ for (i=from+1; i<=to; i++)
+ {
+ l = lineTable[from]; m = lineTable[i];
+ while ((*l == *m) && (*l != ':')) {l++; m++;}
+ // End of first idf reached ==> second string can at best be =, not <
+ if (*l == ':') continue;
+ // If end of second idf was reached the second string is <. Otherwise check chars.
+ if ((*m == ':') || (*m < *l))
+ {
+ j++;
+ swap = lineTable[j]; lineTable[j] = lineTable[i]; lineTable[i] = swap;
+ }
+ }
+ swap = lineTable[from]; lineTable[from] = lineTable[j]; lineTable[j] = swap;
+
+ // Select cheaper recursion branch
+ if ((j - from) < (to - j))
+ {
+ sortResources(from, j-1);
+ from = j+1;
+ }
+ else
+ {
+ sortResources(j+1, to);
+ to = j-1;
+ }
+ }
+}
+
+
+
+
+/*
+ * Destructor: just frees all dynamically allocated memory.
+ */
+
+labelManager::~labelManager(void)
+{
+ if (lineTable != NULL) delete [] lineTable;
+ if (buffer != NULL) delete [] buffer;
+}
+
+
+
+
+/*
+ * Look up a symbol and return a read-only pointer to the symbol value. If
+ * this symbol doesn't exist it returns a pointer to the badSymbol-member.
+ */
+
+char *labelManager::lookup(const char *symbol)
+{
+ int at, step, iter;
+ char *s, *l;
+
+ if (lines == 0) return badSymbol;
+ at = (lines+1)/2; step = (at+1)/2; iter = lines << 1;
+ if (at >= (int)lines) at = lines-1;
+ // Do a binary search over the sorted items
+ while (iter != 0)
+ {
+ // The symbol may be terminated by a colon or any character <= 32
+ s = (char*)symbol; l = lineTable[at];
+ while ((*s == *l) && (*l != ':')) {s++; l++;}
+ // Was the symbol's end reached?
+ if (((unsigned char)(*s) <= 32) || (*s == ':'))
+ {
+ // Both read to the end. Success.
+ if (*l == ':') return (l+1);
+ // Symbol's end reached but not label's ==> label >, i.e. step down
+ at -= step; if (at < 0) at = 0;
+ }
+ else
+ {
+ // label's end reached ==> label <, i.e. step up. Otherwise use chars.
+ if ((*l == ':') || (*l < *s))
+ {
+ at += step; if (at >= (int)lines) at = lines-1;
+ }
+ else
+ {
+ at -= step; if (at < 0) at = 0;
+ }
+ }
+ step = (step+1)/2; iter >>= 1;
+ //cout << at << ", " << step << ", " << iter << ": " << lineTable[at] << endl;
+ }
+ return badSymbol;
+}
+
+
+
+
+/*
+ * Returns the number of label definitions.
+ */
+
+int labelManager::numberOfLabels(void)
+{
+ return lines;
+}
+
+
+
+/*
+ * Returns a read-only pointer to the index-th label in the sorted table.
+ * Normally this shouldn't be used from an outside application, but it
+ * may be handy for debugging.
+ */
+
+char *labelManager::returnLabelNumber(unsigned int index)
+{
+ if (index >= lines)
+ {
+ return NULL;
+ }
+ return lineTable[index];
+}
+
+
+
+
+/* TEST
+int main(int argc, char *argv[])
+{
+ int i;
+ char *b;
+ labelManager lman("labels.txt");
+
+ for (i=0; i<lman.numberOfLabels(); i++)
+ {
+ b = lman.returnLabelNumber(i);
+ while (*b != ':') cout << *b++;
+ cout << ": " << lman.lookup(lman.returnLabelNumber(i)) << endl;
+ }
+
+ cout << lman.lookup("hubba") << endl;
+
+ return 0;
+}
+*/
diff --git a/applications/rview/labelManager.hh b/applications/rview/labelManager.hh
new file mode 100644
index 0000000..a4a81de
--- /dev/null
+++ b/applications/rview/labelManager.hh
@@ -0,0 +1,69 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+ * PURPOSE:
+ *
+ * The label manager class is used to lookup label:value pairs
+ * stored in a text file. The constructor reads in the file whose
+ * name is passed to it and sorts the non-empty, non-commentary
+ * lines (commentary lines have a '#' as the first non-white
+ * character in a line) in ascending order to make binary searching
+ * possible. The binary search is performed by the lookup member
+ * function.
+ *
+ * COMMENTS: None
+ */
+
+
+
+#ifndef _LABEL_MANAGER_H_
+#define _LABEL_MANAGER_H_
+
+
+
+class labelManager
+{
+ public:
+
+ labelManager(const char *resourceFile);
+ ~labelManager(void);
+ char *lookup(const char *symbol);
+ // These two should be handled with care.
+ int numberOfLabels(void);
+ char *returnLabelNumber(unsigned int index);
+
+
+ private:
+
+ void sortResources(int from, int to);
+
+ char *buffer;
+ char **lineTable;
+ unsigned int lines;
+ char badSymbol[4];
+};
+
+
+
+#endif
diff --git a/applications/rview/labels.txt b/applications/rview/labels.txt
new file mode 100644
index 0000000..37037ae
--- /dev/null
+++ b/applications/rview/labels.txt
@@ -0,0 +1,451 @@
+# Text used in rview
+#
+# Commentary lines have a '#' as the first non-white character.
+# Non-empty lines where the first character differs from '#'
+# are interpreted as "identifier:text" combinations. If the colon
+# is missing an error is generated.
+
+# Window titles
+titleRview:rView
+titleCollLook:Lookup a collection
+titleLookScaleColl:Lookup scaled collection
+titleCollDel:Delete a collection
+titleCollCrt:Create a collection
+titleInsertMdd:Insert MDD object
+titleInsertMddPro:Insert projected MDD object
+titleResult:Results
+titlePrefs:Edit preferences
+titleImageFlat:Flat image viewer
+titleImageVolume:Volumetric image viewer
+titleImageHeight:Height field image viewer
+titleImageScaled:Scaled image viewer
+titleImageOrtho:Orthosection viewer
+titleChart:Chart display mode
+titleTable:Tabular display mode
+titleThumb:Thumbnail images
+titleSound:Sound player
+titleQuery:Query Editor
+titleQueryLoad:Load query
+titleQuerySave:Save query
+titleImgSetup:Image settings
+titleColourspace:Colourspace setup
+titleAbout:About rView...
+titleRendererCtrl:Renderer controls
+titleRendererView:Renderer view
+titleStringSet:String result set
+titleTypeMan:Type manager
+titleEnterType:Resolve unknown base type
+titleOrthoLook:Lookup orthosection
+
+# Menu items in the main frame menu
+menMainFile:File
+menMainView:Viewers
+menMainColl:Collections
+menMainHelp:Help
+
+menMainFileQuery:&Query
+menMainFilePrefs:&Prefs
+menMainFileExit:E&xit
+
+menMainViewOpen:&Open
+menMainViewClose:&Close all
+
+menMainCollLook:&Lookup
+menMainCollLkScale:LU &scaled
+menMainCollLkOrtho:LU &ortho
+menMainCollCrt:&Create
+menMainCollDel:&Delete
+
+menMainHelpAbt:&About
+
+# Help text for those menu items
+helpMainFileQuery:Opens a query dialogue box.
+helpMainFilePrefs:Edit the preferences.
+helpMainFileExit:Exit rView.
+
+helpMainViewOpen:Opens a viewer from a file.
+helpMainViewClose:Close all viewers.
+
+helpMainCollLook:Lookup a collection.
+helpMainCollLkScale:Lookup a scaled collection.
+helpMainCollLkOrtho:Lookup an orthosection (3D)
+helpMainCollCrt:Create a collection.
+helpMainCollDel:Delete a collection.
+
+helpMainHelpAbt:Information about this program.
+
+
+# Menu items in the results frame menu
+menRsltItem:Item
+menRsltSlct:Selection
+
+menRsltItemOpAll:Open &All
+menRsltItemThumbAll:&Thumbnail All
+menRsltItemClose:&Close
+
+menRsltSlctSlctAll:Select &All
+menRsltSlctClear:&Clear
+menRsltSlctOpen:&Open
+menRsltSlctThumb:&Thumbnails
+menRsltSlctDel:&Delete
+menRsltSlctEndian:&Endian change
+menRsltSlctTypeMan:Type &Manager
+menRsltSlctInfo:&Info
+
+# Help text for those menu items
+helpRsltItemOpAll:Open all objects.
+helpRsltItemThumbAll:Display all images as thumbnails.
+helpRsltItemClose:Close this window.
+
+helpRsltSlctSlctAll:Select all objects.
+helpRsltSlctClear:Clears the selection.
+helpRsltSlctOpen:Open the selected objects.
+helpRsltSlctThumb:Display thumbnails of the selected object(s).
+helpRsltSlctDel:Delete the selected object(s).
+helpRsltSlctEndian:Change the endianness of the selected object(s).
+helpRsltSlctTypeMan:Call type manager for the selected object(s).
+helpRsltSlctInfo:Display information about the selected object(s).
+
+
+# Menu items in the display window menus
+menDispData:Data
+menDispDataIsrt:&Insert
+menDispDataIsrtPro:Insert &Proj
+menDispDataSave:&Save
+menDispDataSaveTIFF:Save &TIFF
+menDispDataClose:&Close
+menDispView:View
+menDispViewSave:Save
+menDispViewLoad:Load
+menDispViewShow:Show
+
+# Additional menus in chart mode
+menChartMode:Modes
+menChartModeBar:Bar
+menChartModeLine:Line
+menChartModeSpline:Spline
+
+# Additional menus in image mode
+menImgMode:Modes
+menImgModeFlat:Flat
+menImgModeSurf:Surface
+menImgModeVoxel:Voxel
+menImgModeHeight:Height
+menImgSetup:Settings
+menImgSetupRender:Renderer...
+menImgSetupMovie:Movie playback
+menImgMovieOnce:Once
+menImgMovieStart:Same direction
+menImgMovieSwitch:Switch direction
+menImgSetupRctrl:Renderer controls...
+
+# Additional menus in table mode
+menTabMode:Base
+menTabModeDec:Decimal
+menTabModeOct:Octal
+menTabModeHex:Hex
+
+
+# Menu items in query window
+menQueryFile:File
+menQueryEdit:Edit
+menQueryHotlist:List
+menQueryHelp:Help
+menQueryFileOpen:&Open
+menQueryFileSave:&Save
+menQueryFileClose:&Close
+menQueryEditCut:Cu&t
+menQueryEditCopy:&Copy
+menQueryEditPaste:&Paste
+menQueryHelpHelp:&Help
+helpQueryFileOpen:Load a query from disc.
+helpQueryFileSave:Save this query to disc.
+helpQueryFileClose:Close this window.
+helpQueryEditCut:Cut the selected area.
+helpQueryEditCopy:Copy the selected area.
+helpQueryEditPaste:Insert copy buffer at cursor position.
+helpQueryHelpHelp:Information about queries.
+
+
+# Thumbnails menu
+menThumbData:Data
+menThumbDataClose:&Close
+menThumbSetup:Setup
+
+
+# colourspace submenu
+menCspaceTitle:Colourspace
+menCspaceOn:Enable
+menCspaceFull:Full range
+menCspaceProj:Proj range
+menCspaceEdit:Editor...
+
+
+# Text in widgets
+serverName:Server name:
+serverPort:Server port:
+dbName:Database name:
+userName:User:
+userPassword:Password:
+
+# General text in buttons
+textOpen:Open
+textClose:Close
+textOK:OK
+textCancel:Cancel
+textApply:Apply
+textDefaults:Defaults
+textResult:Results
+textProjString:Projection
+textClear:Clear
+textExec:Execute
+textUpdt:Update Data
+textStepx:Step X
+textStepy:Step Y
+textStepC:Step
+textCosys:CO-System
+textCoStep:Y markers
+textDataStep:X markers
+textScale:Scale
+textBaseType:Base type
+textThumb:Thumbnails
+textThumbWidth:ThumbWidth
+textThumbColumns:ThumbCols
+textThumbProjDim:ProjDim
+textThumbProjStep:ProjStep
+textBBox:BBox
+textImages:Images
+textImageMode:Image mode
+textCharts:Charts
+textChartMode:Chart mode
+textTables:Tables
+textTableMode:Table mode
+textMiscPrefs:Misc prefs
+textResample:Resample
+textCspace:RGB space
+textCrange:Full range
+textRotX:Rot X
+textRotY:Rot Y
+textRotZ:Rot Z
+textOff:Off
+textStart:Start
+textStop:Stop
+textTime:Time
+textConvert:Convert
+textOpTime:Time taken for
+textScaleFactor:Scaling factor
+textZoomBox:To box
+textLastZoom:Back
+textZoomIn:Zoom in
+textZoomOut:Zoom out
+textCommunication:Communication
+textTransferFormats:Transfer format
+textTransferParams:Transfer parameters
+textStorageFormats:Storage format
+textStorageParams:Storage parameters
+textSliceX:Slice xy
+textSliceY:Slice yz
+textSliceZ:Slice zx
+textOrthoThickness:Thick
+textOrthoDragRelease:Auto
+textOrthoFireButton:Load
+textZOffset:Z Offset
+
+# Sound window
+soundStart:Start
+soundStop:Stop
+soundOff:Off
+soundPlayTime:Play time
+soundFrequency:Frequency
+soundLatency:Latency
+soundFormat:Format
+soundFmtLin8:8 bit sl
+soundFmtUlin8:8 bit usl
+soundFmtUlaw8:8 bit ulaw
+soundFmtLin16:16 bit sl
+
+# Collection group box in results window
+textCollHeader:Collection:
+textCollName:Name
+textCollType:Type
+
+# Text in lookup scaled window
+lkScaleName:Collection name
+lkScaleScale:Scaling factor
+
+# MDD operations (results window)
+operationUpsamp:Upsample
+operationDownsamp:Downsample
+operationScale:Simple scale
+operationTypeProj:Type project
+operationEndian:Change endian
+
+# Text for display modes
+dispModeLabel:Display mode
+dispModeImage:Flat image
+dispModeVolume:Volumetric
+dispModeOrtho:Orthosection
+dispModeHeight:Height field
+dispModeChart:Chart
+dispModeTable:Table
+dispModeSound:Sound
+dispModeString:String
+
+# Text in preferences window
+prefsFilePath:Pathname of data files
+prefsQueryPath:Pathname of query files
+prefsQueryFont:Font used for queries
+prefsImgDither:Dithering
+prefsDitherBest:Dither best
+prefsMaxDWidth:Maximum width
+prefsMaxDHeight:Maximum height
+prefsVffParams:Convertor parameters
+prefsCspace:RGB space
+prefsCspaceEdit:Edit
+prefsCspaceAct:Cube range
+prefsCspaceFull:Full range
+prefsCspaceProj:Proj range
+prefsMovieMode:Movie mode
+prefsMovieOnce:Once
+prefsMovieStart:Same dir
+prefsMovieSwitch:Switch dir
+prefsSound:Sound defaults
+prefsSndLoop:Loop sound
+prefsLight:Lights
+prefsLightAngle:Light angle
+prefsLightAmbient:Ambient light
+prefsLightGain:Light gain
+prefsKernSize:Kernel size
+prefsKernType:Kernel type
+prefsLightScAngle:Scint angle
+prefsLightDir:Direction
+prefsLightDist:Distance
+prefsUseVCol:Ignore voxel colour
+prefsVoxColour:Voxel colour
+prefsHeightGroup:Height fields
+prefsHgtGrid:Grid size
+prefsHgtScale:Height scale
+prefsOrthoGroup:Orthosections
+prefsOrthoDragRel:On release
+prefsOrthoThick:Thickness
+
+# Text in image settings window
+imgSetRender:Renderer settings
+imgSetVoxel:Voxel settings
+imgSetHeight:Height field
+imgSetRenZpro:Proj plane
+imgSetRenClipz:Clip Z
+imgSetRenUseLight:Use lighting
+imgSetRenLightAn:lAngle
+imgSetRenLightSc:sAngle
+imgSetRenLightAm:Ambient
+imgSetRenLightGn:Gain
+imgSetRenLightDr:Direction
+imgSetRenLightDs:Distance
+imgSetVoxPixThreshLow:Pixel threshold Low
+imgSetVoxPixThreshHigh:Pixel threshold High
+imgSetVoxWgtThresh:Weight threshold
+imgSetVoxWgtQuant:Weight quantisation
+imgSetVoxRgbBright:RGB brightness
+imgSetVoxForType:For type
+imgSetKernSize:K-size
+imgSetKernType:K-type
+imgSetUseVCol:Ignore colours
+imgSetVoxCol:Voxel colour
+imgSetGridSize:Grid
+imgSetHgtScale:Height
+kernelTypeAvg:Average
+kernelTypeLin:Linear
+kernelTypeGauss:Gauss
+
+# text in colourspace mapper window
+cspacePeakRed:E(r)
+cspacePeakGreen:E(g)
+cspacePeakBlue:E(b)
+cspaceSigmaRed:s(r)
+cspaceSigmaGreen:s(g)
+cspaceSigmaBlue:s(b)
+cspaceImmUpdt:Update
+cspaceDrawSum:Draw sum
+cspaceMinVal:Min
+cspaceMaxVal:Max
+cspaceTypeGauss:Gaussian
+cspaceTypeLin:Linear
+cspaceTypeRect:Rectangle
+cspaceTypeAsympt:Asymptotic
+
+loadFile:Load a file
+saveTIFF:Save as TIFF
+saveView:Save current view to file
+loadView:Load a view from file
+
+# Prompting messages
+promptEnterColl:Please enter the collection name.
+promptEnterType:Please enter a base type name for type
+promptEnterOrtho:Please enter the orthosection collection name.
+
+
+# Text appearing in the About window
+rviewAboutLineNum:4
+rviewAboutLine0:*** rView 2.0
+rviewAboutLine1:
+rviewAboutLine2:Visual frontend for the RasDaMan DBMS.
+rviewAboutLine3:(C) 1999-2001 Active Knowledge GmbH.
+
+
+# Text appearing in the StrinSet window
+strSetList:Result set
+
+
+# Errors
+errorFrom:Error from rView:
+
+# RasDaMan errors:
+errorUnknown:Object unknown error.
+errorHostInvalid:Host invalid.
+errorServerInvalid:Server invalid.
+errorClientUnknown:Client unknown.
+errorDatabaseUnknown:Database unknown.
+errorDatabaseOpen:Database is already open.
+errorRpcInterface:RPC Interface is incompatible with server.
+errorDatabaseClosed:Database closed.
+errorCollCreate:Error creating collection.
+errorCollDelete:Error deleting collection.
+errorInsertObj:Error inserting object into collection.
+errorChangeOpen:You can't change the database while it's open.
+errorMemory:Not enough memory left for this operation.
+errorQueryFailed:Error executing query
+errorQueryUnknown:Collection doesn't exist.
+errorQueryParamNum:Number of query parameters is invalid.
+errorTransferFailed:The transfer failed.
+errorProjection:Error in projection string.
+errorProjFree:Projection incompatible with display mode.
+errorTypeSize:Unsupported base type size error.
+errorBaseType:Unsupported base type.
+errorUnknownBase:Unknown base type.
+errorModeDim:Unsupported number of dimensions for this mode.
+errorModeBase:Unsupported base type for this mode.
+errorProjectFree:Bad number of free dimensions in projection string.
+errorUpdtObject:Missing object for update query.
+errorFileOpen:Error opening file
+errorFileWrite:Error writing to file
+errorFileRead:Error reading from file
+errorQueryFile:Unrecognized query file format.
+errorProjThumb:Error building thumbnail.
+errorSoundFormat:Unsupported sound sample format.
+errorSoundDevice:Unable to open sound device.
+errorScaledObjType:Unsupported base type for scaled object.
+errorScaledObjSize:Object scaled to empty spatial domain.
+errorOrthoViewer:Unable to open orthosection viewer on object.
+errorViewType:Wrong viewer type
+
+# Progress reports
+messageFrom:Message from rView
+
+progOpenDb:Opening database...
+progCloseDb:Closing database...
+progLookup:Looking up collection...
+progInsert:Inserting object into collection...
+progDelete:Deleting collection...
+progCreate:Creating collection...
+progQuery:Executing query...
diff --git a/applications/rview/rview.cpp b/applications/rview/rview.cpp
new file mode 100644
index 0000000..5e9c63b
--- /dev/null
+++ b/applications/rview/rview.cpp
@@ -0,0 +1,548 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+ * PURPOSE:
+ *
+ * rView main application (class rView) and main frame (class rviewMainFrame).
+ * The main application includes the database object which has to be accessed
+ * through rView-member functions.
+ *
+ * COMMENTS:
+ * none
+ */
+
+// #ifdef __GNUG__
+// #pragma implementation
+// #endif
+
+// # define __GNUC__
+// # define __GNUC_MINOR__
+
+// changed in wxWindows 2.6.2:
+// #include "wx_prec.h"
+#include <wx/wxprec.h>
+
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+
+#ifndef WX_PRECOMP
+#include <wx/wx.h>
+#endif
+
+// #include "wb_timer.h"
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <sstream>
+
+
+#include "labelManager.hh"
+
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#ifdef __GNUG__
+#include "raslib/template_inst.hh"
+#endif
+#endif
+
+#include "raslib/rmdebug.hh"
+#define DEBUG_MAIN
+#include "debug/debug.hh"
+
+#include "rviewUtils.hh"
+#include "rview.hh"
+#include "rviewQuery.hh"
+
+
+
+
+const int rviewMainFrame::main_width = 300;
+const int rviewMainFrame::main_height = 400 + 2*rview_window_extra_height;
+const int rviewMainFrame::main_border = 8;
+const int rviewMainFrame::main_theight = 50;
+const int rviewMainFrame::main_bwidth = 60;
+const int rviewMainFrame::main_bheight = 30;
+
+
+
+
+/*
+ * Global data
+ */
+
+
+// Start the app.
+static rView rview;
+
+
+
+
+// For some compilers...
+IMPLEMENT_WXWIN_MAIN
+
+
+
+
+#if 0
+#include "rviewTypeMan.hh"
+static void testTypeManager(void)
+{
+ r_Type *newType = r_Type::get_any_type("struct {char red, struct {short s1, long l1}, struct {short s2, long l2}, char green, char blue, struct {float u, float v, float w}}");
+ new rviewTypeMan(NULL, newType);
+ delete newType;
+}
+#endif
+
+
+
+
+
+
+/*
+ * Labels all the widgets and menus in the main frame using the label manager
+ * to lookup the values associated with the symbolic names.
+ */
+
+void rviewMainFrame::label(void)
+{
+ mBar->SetLabel(MENU_MAIN_FILE_QUERY, lman->lookup("menMainFileQuery"));
+ mBar->SetLabel(MENU_MAIN_FILE_PREFS, lman->lookup("menMainFilePrefs"));
+ mBar->SetLabel(MENU_MAIN_FILE_EXIT, lman->lookup("menMainFileExit"));
+ mBar->SetHelpString(MENU_MAIN_FILE_QUERY, lman->lookup("helpMainFileQuery"));
+ mBar->SetHelpString(MENU_MAIN_FILE_PREFS, lman->lookup("helpMainFilePrefs"));
+ mBar->SetHelpString(MENU_MAIN_FILE_EXIT, lman->lookup("helpMainFileExit"));
+
+ mBar->SetLabel(MENU_MAIN_VIEW_OPEN, lman->lookup("menMainViewOpen"));
+ mBar->SetLabel(MENU_MAIN_VIEW_CLOSE, lman->lookup("menMainViewClose"));
+ mBar->SetHelpString(MENU_MAIN_VIEW_OPEN, lman->lookup("helpMainViewOpen"));
+ mBar->SetHelpString(MENU_MAIN_VIEW_CLOSE, lman->lookup("helpMainViewClose"));
+
+ mBar->SetLabel(MENU_MAIN_COLL_LOOK, lman->lookup("menMainCollLook"));
+ mBar->SetLabel(MENU_MAIN_COLL_LKSCL, lman->lookup("menMainCollLkScale"));
+ mBar->SetLabel(MENU_MAIN_COLL_LKORTH, lman->lookup("menMainCollLkOrtho"));
+ //FIXME create collection not implemented yet
+ // mBar->SetLabel(MENU_MAIN_COLL_CREATE, lman->lookup("menMainCollCrt"));
+ mBar->SetLabel(MENU_MAIN_COLL_DELETE, lman->lookup("menMainCollDel"));
+ mBar->SetHelpString(MENU_MAIN_COLL_LOOK, lman->lookup("helpMainCollLook"));
+ mBar->SetHelpString(MENU_MAIN_COLL_LKSCL, lman->lookup("helpMainCollLkScale"));
+ mBar->SetHelpString(MENU_MAIN_COLL_LKORTH, lman->lookup("helpMainCollLkOrtho"));
+ //mBar->SetHelpString(MENU_MAIN_COLL_CREATE, lman->lookup("helpMainCollCrt"));
+ mBar->SetHelpString(MENU_MAIN_COLL_DELETE, lman->lookup("helpMainCollDel"));
+
+ mBar->SetLabel(MENU_MAIN_HELP_ABOUT, lman->lookup("menMainHelpAbt"));
+ mBar->SetHelpString(MENU_MAIN_HELP_ABOUT, lman->lookup("helpMainHelpAbt"));
+
+ mBar->SetLabelTop(0, lman->lookup("menMainFile"));
+ mBar->SetLabelTop(1, lman->lookup("menMainView"));
+ mBar->SetLabelTop(2, lman->lookup("menMainColl"));
+ mBar->SetLabelTop(3, lman->lookup("menMainHelp"));
+
+ server->SetLabel(lman->lookup("serverName"));
+ port->SetLabel(lman->lookup("serverPort"));
+ database->SetLabel(lman->lookup("dbName"));
+ username->SetLabel(lman->lookup("userName"));
+ userpassword->SetLabel(lman->lookup("userPassword"));
+
+ openBut->SetLabel(lman->lookup( (dbOpen) ? "textClose" : "textOpen"));
+ openBut->SetSize(-1, -1, 80, 30);
+}
+
+
+
+
+/*
+ * This is called via the frame manager. Events are broadcast to all the
+ * existing frames. If a frame recognises the object as one of its
+ * children it must return a value != 0.
+ */
+
+int rviewMainFrame::process(wxObject &obj, wxEvent &evt)
+{
+ int type = evt.GetEventType();
+
+ //cout << "rviewMainFrame: Received event" << endl;
+
+ if ((((&obj == (wxObject*)server) || (&obj == (wxObject*)database) ||
+ (&obj == (wxObject*)username)|| (&obj == (wxObject*)userpassword) ||
+ (&obj == (wxObject*)port))
+ && (type == wxEVENT_TYPE_TEXT_ENTER_COMMAND))
+ || ((&obj == (wxObject*)openBut) && (type == wxEVENT_TYPE_BUTTON_COMMAND)))
+ {
+ rView *app = (rView*)rmanClientApp::theApp();
+ app->OpenCloseServer();
+ return 1;
+ }
+ return 0;
+}
+
+
+
+
+
+/*
+ * Initialises the main window's frame, containing the main menus and the
+ * widgets for server and database.
+ */
+
+rviewMainFrame::rviewMainFrame(wxFrame *frame, char *title, int x, int y, int w, int h): rviewFrame(frame, title, x, y, w, h)
+{
+ wxMenu *mbarMenus[4];
+ char buffer[STRINGSIZE];
+
+ aboutWindow = NULL;
+
+ CreateStatusLine(1);
+ dbOpen = FALSE;
+
+ // Create the menus and the menu bar. All labelling is done in the label() member function.
+ mbarMenus[0] = new wxMenu;
+ mbarMenus[0]->Append(MENU_MAIN_FILE_QUERY, "");
+ mbarMenus[0]->Append(MENU_MAIN_FILE_PREFS, "");
+ mbarMenus[0]->Append(MENU_MAIN_FILE_EXIT, "");
+
+ mbarMenus[1] = new wxMenu;
+ mbarMenus[1]->Append(MENU_MAIN_VIEW_OPEN, "");
+ mbarMenus[1]->Append(MENU_MAIN_VIEW_CLOSE, "");
+
+ mbarMenus[2] = new wxMenu;
+ mbarMenus[2]->Append(MENU_MAIN_COLL_LOOK, "");
+ mbarMenus[2]->Append(MENU_MAIN_COLL_LKSCL, "");
+ mbarMenus[2]->Append(MENU_MAIN_COLL_LKORTH, "");
+ //FIXME create collection not implemented yet
+ //mbarMenus[2]->Append(MENU_MAIN_COLL_CREATE, "");
+ mbarMenus[2]->Append(MENU_MAIN_COLL_DELETE, "");
+
+ mbarMenus[3] = new wxMenu;
+ mbarMenus[3]->Append(MENU_MAIN_HELP_ABOUT, "");
+
+ // Note: the titles will be overwritten later on by label() but we need some text
+ // here for keyboard-shortcuts and correct alignment (help flush right).
+ // See wxWindows documentation: the submenus mustn't be used any more after they
+ // were appended to the MenuBar. They are still accessible via the MenuBar through
+ // their id, however.
+ mBar = new wxMenuBar;
+ sprintf(buffer, "&%s", lman->lookup("menMainFile"));
+ mBar->Append(mbarMenus[0], buffer);
+ sprintf(buffer, "&%s", lman->lookup("menMainView"));
+ mBar->Append(mbarMenus[1], buffer);
+ sprintf(buffer, "&%s", lman->lookup("menMainColl"));
+ mBar->Append(mbarMenus[2], buffer);
+ sprintf(buffer, "&%s", lman->lookup("menMainHelp"));
+ mBar->Append(mbarMenus[3], buffer);
+
+ // create panel
+ panel = new wxPanel((wxWindow*)this, main_border, main_border, 256, 100, wxBORDER);
+ panel->SetLabelPosition(wxVERTICAL);
+
+ // Create the text widgets
+ server = new rviewText(panel);
+ panel->NewLine();
+ port = new rviewText(panel);
+ panel->NewLine();
+ database = new rviewText(panel);
+ panel->NewLine();
+ username = new rviewText(panel);
+ panel->NewLine();
+ userpassword = new rviewText(wxTE_PASSWORD, panel);
+ panel->NewLine();
+ // ... and the button
+ openBut = new rviewButton(panel);
+
+ SetMenuBar(mBar);
+
+ newDBState(dbOpen);
+
+ label();
+
+ // Resize everything correctly
+ frameWidth = -1; frameHeight = -1; // force resize
+
+ OnSize(w, h);
+ OnSize(w, h); //twice is done correct
+
+}
+
+
+const char *rviewMainFrame::getFrameName(void) const
+{
+ return "rviewMainFrame";
+}
+
+rviewFrameType rviewMainFrame::getFrameType(void) const
+{
+ return rviewFrameTypeMain;
+}
+
+
+
+void rviewMainFrame::newDBState(bool newState)
+{
+ openBut->SetLabel(lman->lookup( (newState) ? "textClose" : "textOpen"));
+ openBut->SetSize(-1, -1, main_bwidth, main_bheight);
+#ifndef DUMMY_MDD_OBJECT
+ mBar->Enable(MENU_MAIN_COLL_LOOK, newState);
+#endif
+ mBar->Enable(MENU_MAIN_COLL_LKSCL, newState);
+ mBar->Enable(MENU_MAIN_COLL_LKORTH, newState);
+ //FIXME create collection not implemented yet
+ //mBar->Enable(MENU_MAIN_COLL_CREATE, newState);
+ mBar->Enable(MENU_MAIN_COLL_DELETE, newState);
+
+ //set editable mode foe dbOpen
+ server->SetEditable(!newState);
+ port->SetEditable(!newState);
+ database->SetEditable(!newState);
+ username->SetEditable(!newState);
+ userpassword->SetEditable(!newState);
+ //reset to default when database is closed
+ if(!newState)
+ userpassword->SetValue("");
+
+ dbOpen = newState;
+}
+
+
+int rviewMainFrame::userEvent(const user_event &ue)
+{
+ if ((ue.type == usr_db_opened) || (ue.type == usr_db_closed))
+ {
+ newDBState((ue.type == usr_db_opened));
+ return 1;
+ }
+ return 0;
+}
+
+
+
+
+/*
+ * Dummy desctructor.
+ */
+rviewMainFrame::~rviewMainFrame(void)
+{
+}
+
+
+
+/*
+ * Called from wxWindows when a menu item in the main window is selected.
+ */
+
+void rviewMainFrame::OnMenuCommand(int id)
+{
+ switch (id)
+ {
+ case MENU_MAIN_FILE_EXIT:
+ {
+ if (frameManager != NULL)
+ {
+ if (frameManager->broadcastQuit(0) == 0)
+ {
+ cerr << "Some windows refuse to die." << endl;
+ return;
+ }
+ frameManager->broadcastQuit(1);
+ }
+ rmanClientApp::theApp()->SavePreferences();
+ this->Close(TRUE);
+ }
+ break;
+ case MENU_MAIN_FILE_PREFS: prefs->edit(); break;
+ case MENU_MAIN_FILE_QUERY:
+ {
+ rView *app = (rView*)rmanClientApp::theApp();
+ app->OpenQueryWindow();
+ }
+ break;
+ case MENU_MAIN_VIEW_OPEN: rmanClientApp::theApp()->OpenFile(0, NULL, TRUE); break;
+ case MENU_MAIN_VIEW_CLOSE:
+ if (frameManager != NULL)
+ {
+ user_event usr;
+
+ usr.type = usr_close_viewers;
+ frameManager->broadcastUserEvent(usr);
+ }
+ break;
+ case MENU_MAIN_COLL_LOOK: rmanClientApp::theApp()->LookupCollection(); break;
+ case MENU_MAIN_COLL_LKSCL: rmanClientApp::theApp()->LookupScaledCollection(); break;
+ case MENU_MAIN_COLL_LKORTH: rmanClientApp::theApp()->LookupOrthosection(); break;
+ case MENU_MAIN_COLL_CREATE: rmanClientApp::theApp()->CreateCollection(); break;
+ case MENU_MAIN_COLL_DELETE: rmanClientApp::theApp()->DeleteCollection(); break;
+ case MENU_MAIN_HELP_ABOUT:
+ if (aboutWindow == NULL)
+ {
+ aboutWindow = new rviewAbout();
+ }
+ aboutWindow->Show(TRUE);
+ break;
+ default: break;
+ }
+}
+
+/*
+ * Only one exit
+ */
+bool
+rviewMainFrame::OnClose()
+{
+ return FALSE;
+}
+
+
+/*
+ * Called from wxWindows when the main window is resized.
+ */
+
+void rviewMainFrame::OnSize(int w, int h)
+{
+ int x, y, d;
+
+ GetClientSize(&x, &y);
+
+ //need to resize?
+ if (( main_width != x) || ( main_height != y))
+ {
+ frameWidth = main_width;
+ frameHeight = main_height;
+ x = main_width;
+ y = main_height;
+ SetClientSize(x, y);
+ return;
+ }
+
+ x -= 2*main_border; y -= 2*main_border;
+ panel->SetSize(main_border, main_border, x, y);
+
+ x -= 2*main_border; y -= 2*main_border;
+ d = (y - (5*main_theight + main_bheight)) / 6;
+
+ server->SetSize(main_border, main_border + d/2, x, main_theight);
+ port->SetSize(main_border, main_border + main_theight + (3*d)/2, x, main_theight);
+ database->SetSize(main_border, main_border + 2*main_theight + (5*d)/2, x, main_theight);
+ username->SetSize(main_border, main_border + 3*main_theight + (7*d)/2, x, main_theight);
+ userpassword->SetSize(main_border, main_border + 4*main_theight + (9*d)/2, x, main_theight);
+
+ openBut->SetSize((x - main_bwidth)/2, main_border + 5*main_theight + (11*d)/2, main_bwidth, main_bheight);
+}
+
+
+
+void rviewMainFrame::SetDatabaseInfo(const char *srvName, int srvPort, const char *dbName, const char *usrName)
+{
+ server->SetValue(srvName);
+ port->SetValue(srvPort);
+ database->SetValue(dbName);
+ username->SetValue(usrName);
+ userpassword->SetValue(""); // empty password string
+}
+
+
+
+void rviewMainFrame::GetDatabaseInfo(DynamicString &srvName, int& srvPort, DynamicString &dbName,
+ DynamicString &usrName, DynamicString &usrPassword) const
+{
+ server->GetValue(srvName);
+ port->GetValue(srvPort);
+ database->GetValue(dbName);
+ username->GetValue(usrName);
+ userpassword->GetValue(usrPassword);
+}
+
+
+
+
+/*
+ * rView specifics; not too much code, really ;-)
+ */
+
+const char rView::labels_filename[] = "labels.txt";
+const char rView::prefs_filename[] = ".rviewrc";
+const double rView::version = RVIEW_VERSION;
+
+
+rView::rView(void) : rmanClientApp("RVIEWHOME", prefs_filename, labels_filename)
+{
+ mainFrame = NULL;
+}
+
+
+rView::~rView(void)
+{
+}
+
+
+/*
+ * Initialises the GUI of the program. Most of the real stuff is done in
+ * the rviewMainFrame constructor.
+ */
+
+wxFrame *rView::OnInit(void)
+{
+ char buffer[STRINGSIZE];
+
+ sprintf(buffer, "%s %.1f", lman->lookup("titleRview"), version);
+ mainFrame = new rviewMainFrame(NULL, buffer, 0, 0, rviewMainFrame::main_width, rviewMainFrame::main_height);
+
+ mainFrame->SetDatabaseInfo(prefs->serverName, prefs->serverPort, prefs->databaseName, prefs->userName);
+
+ mainFrame->Show(TRUE);
+
+ return (wxFrame*)mainFrame;
+}
+
+
+/*
+ * This function is called from the global callback function mainFrameOpenServer
+ * upon receiving a <RETURN> in one of the text widgets or a click on the
+ * Open button.
+ */
+
+void rView::OpenCloseServer(void)
+{
+ if (database.isOpen())
+ {
+ CloseServer();
+ }
+ else
+ {
+ DynamicString userPassword;
+ mainFrame->GetDatabaseInfo(prefs->serverName, prefs->serverPort, prefs->databaseName,
+ prefs->userName, userPassword);
+ prefs->markModified();
+ if (OpenServer(prefs->serverName, prefs->serverPort, prefs->databaseName, prefs->userName, userPassword))
+ mainFrame->newDBState(FALSE);
+ }
+}
+
+
+void rView::OpenQueryWindow(void)
+{
+ rviewQuery *newQuery = new rviewQuery(&database);
+}
diff --git a/applications/rview/rview.hh b/applications/rview/rview.hh
new file mode 100644
index 0000000..1b26cc8
--- /dev/null
+++ b/applications/rview/rview.hh
@@ -0,0 +1,139 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+ * PURPOSE:
+ *
+ * rView main application (class rView) and main frame (class rviewMainFrame).
+ * The main application includes the database object which has to be accessed
+ * through rView-member functions.
+ *
+ * COMMENTS:
+ * none
+ */
+
+
+
+#ifndef _RVIEW_H_
+#define _RVIEW_H_
+
+
+#ifdef __GNUG__
+#pragma interface
+#endif
+
+
+
+
+
+// RasDaMan includes
+#include "rasodmg/ref.hh"
+#include "rasodmg/marray.hh"
+
+
+#include "rviewApp.hh"
+#include "rviewUtils.hh"
+#include "rviewPrefs.hh"
+
+
+
+/*
+ * rView's main frame
+ */
+class rviewMainFrame: public rviewFrame
+{
+ public:
+
+ rviewMainFrame(wxFrame *frame, char *title, int x, int y, int w, int h);
+ ~rviewMainFrame(void);
+ void OnMenuCommand(int id);
+ void OnSize(int w, int h);
+ void SetDatabaseInfo(const char *srvName, int srvPort,
+ const char *dbName, const char*usrName);
+ void GetDatabaseInfo(DynamicString &srvName, int& srvPort, DynamicString &dbName,
+ DynamicString &usrName, DynamicString &usrPassword) const;
+ void newDBState(bool newState);
+ bool OnClose();
+
+ // Implementations of the rviewFrame virtual functions
+ void label(void);
+ int process(wxObject &obj, wxEvent &evt);
+
+ int userEvent(const user_event &ue);
+
+ virtual const char *getFrameName(void) const;
+ virtual rviewFrameType getFrameType(void) const;
+
+ // constants
+ // Width and height of main window
+ static const int main_width;
+ static const int main_height;
+ // Border around panel in main frame
+ static const int main_border;
+ // Height of server / database text widgets
+ static const int main_theight;
+ // Dimensions of button(s)
+ static const int main_bwidth;
+ static const int main_bheight;
+
+
+ protected:
+
+ rviewText *server;
+ rviewText *port;
+ rviewText *database;
+ rviewText *username;
+ rviewText *userpassword;
+ rviewButton *openBut;
+ wxPanel *panel;
+ wxMenuBar *mBar;
+ bool dbOpen;
+ rviewAbout *aboutWindow;
+};
+
+
+
+/*
+ * rView application specifics
+ */
+class rView: public rmanClientApp
+{
+ public:
+
+ rView(void);
+ virtual ~rView(void);
+ wxFrame *OnInit(void);
+ void OpenCloseServer(void);
+ void OpenQueryWindow(void);
+
+
+ private:
+
+ rviewMainFrame *mainFrame;
+
+ static const char labels_filename[];
+ static const char prefs_filename[];
+ static const double version;
+};
+
+#endif
diff --git a/applications/rview/rview.tex b/applications/rview/rview.tex
new file mode 100644
index 0000000..daab380
--- /dev/null
+++ b/applications/rview/rview.tex
@@ -0,0 +1,1479 @@
+% Documentation for rView
+% (C) 1998-2002 FORWISS, Andreas Dehmel
+
+\def\rview{\textsf{rView}}
+\def\rman{\textsf{RasDaMan}}
+\def\wxwin{\textsf{wxWindows}}
+\def\dollar{\$} % stupid emacs colouring problem with $
+\def\realnumbers{\mbox{I}\!\mbox{R}}
+
+\documentclass[11pt]{article}
+\usepackage{a4wide}
+\usepackage{parskip}
+
+\title{\hrule \vspace{10mm} \Huge rView 2.0\\A visual frontend to the \rman\ DBMS}
+
+\author{Andreas Dehmel}
+
+\date{07 Jan 2002}
+
+\frenchspacing
+\sloppy
+\setcounter{secnumdepth}{5}
+\setcounter{tocdepth}{5}
+
+\begin{document}
+
+\maketitle
+
+\vspace{10mm}
+\hrule
+
+\thispagestyle{empty}
+
+%\newpage
+
+\tableofcontents
+
+\newpage
+
+\section{Introduction}
+
+\rview\ is a frontend to the \rman\ DBMS for visualizing multidimensional raster
+data and generally making it easier to use the database. It is based on the
+freely available, portable \wxwin\ GUI
+(\texttt{http://web.ukonline.co.uk/julian.smart/wxwin/}).\\
+No text displayed in any of its windows is hard-coded into the program, instead
+it uses labels which are read in on startup and dereferenced at run-time. The
+labels are looked up in a file called \texttt{labels.txt} which \rview\ tries to open as
+\texttt{\dollar RVIEWHOME/labels.txt} or, failing that, \texttt{./labels.txt}. If
+no \texttt{labels.txt} file could be found, all text displayed in \rview's windows
+will default to \texttt{???}. The \texttt{labels.txt} file can contain three types of
+lines:
+
+\begin{description}
+\item[Empty lines:] only whitespace (space, tabs)
+\item[Commentary lines:] a \# Symbol preceded by nothing or whitespace and followed
+by any text.
+\item[Label definitions:] These have the form "\texttt{\textsl{label}:\textsl{text associated
+with label}}". There must be no whitespace between the label and the colon; whitespace
+following the colon will not be stripped. Being line-based, label text may not contain
+linefeeds, all other characters are legal.
+\end{description}
+
+Configurations are stored in the file \texttt{.rviewrc} which will be looked for in
+\texttt{\dollar HOME}, the current directory and \texttt{\dollar RVIEWHOME} in that order.
+The current configurations are saved to \texttt{\dollar HOME/.rviewrc} automatically on
+exit. The old \texttt{.rviewrc} file (if existent) will be renamed to \texttt{.rviewrc$\sim$}
+before being overwritten so in case the new preferences file is corrupted for some
+reason the last settings can be easily restored. Serious errors like segmentation violations
+are handled by \rview\ and result in any open databases being closed before the program
+is aborted.
+
+
+\section{The Main Window}
+\label{MainWindow}
+
+The main window allows you to enter information about a database and open or
+close it; furthermore the following menus are available:
+
+\subsection{The \texttt{File} Menu}
+
+The \texttt{File} Menu offers functionality that is available even with the
+database closed:
+
+\begin{description}
+
+\item[Query:] Opens a query shell. See \ref{QueryWindow}.
+
+\item[Prefs:] Opens the preferences editor. See \ref{PreferencesEditor}.
+
+\item[Exit:] Exit \rview. If a database was opened, close it first.
+
+\end{description}
+
+
+\subsection{The \texttt{Viewers} Menu}
+
+The \texttt{Viewers} Menu allows you to open / close viewers directly:
+
+\begin{description}
+
+\item[Open:] Opens a file. Currently this allows you to open TIFF images
+and display them in an image viewer window (\ref{ImageDisplayMode}).
+
+\item[Close all:] Closes all open viewers (\ref{ObjectViewers}) and \texttt{Results}
+windows (\ref{ResultWindow}).
+
+\end{description}
+
+
+\subsection{The \texttt{Collections} Menu}
+
+The \texttt{Collections} Menu combines operations on database collections. Its
+members can therefore only be called once a database has been opened. After
+selecting an item a small dialog-window pops up in which you have to enter
+the collection name.
+
+\begin{description}
+
+\item[Lookup:] Load a collection of objects from the database into client
+memory. On success a \emph{Results}-Window containing all the objects
+in the collection is opened (see \ref{ResultWindow}).
+
+\item[LU scaled:] Load a scaled object from the database. On success a viewer
+window similar to flat image mode is opened (see \ref{ImageModeScaled}).
+
+\item[LU ortho:] Load a 3D object from the database into a partial
+\emph{Orthosection} viewer (see \ref{ImageModeOrtho}). In contrast, a
+full orthosection viewer is available from the \emph{Results} window.
+
+\item[Create:] Create an empty collection.
+
+\item[Delete:] Delete a named collection.
+
+\end{description}
+
+
+\section{The Query Window}
+\label{QueryWindow}
+
+The query window allows you to write and edit database queries as well as load
+and save them. On disk, queries are identified by a \texttt{.ql} extension as well
+as the headline "\texttt{-- rview-Query}" which will not be displayed in the query
+window.\\
+The \texttt{File} menu allows you to \texttt{Open} a query on disk, \texttt{Save} the
+current query to disk or \texttt{Close} the query window. The \texttt{Edit} menu
+operates on selections, allowing you to \texttt{Cut}, \texttt{Copy} or \texttt{Paste} the
+current selection.\\
+The \texttt{List} menu provides a shortcut to all the queries stored in the
+directory described by the \texttt{query path} variable (see \ref{PreferencesEditor}).
+To achieve this the entire directory is scanned for files named
+\texttt{*.ql}. The resulting set of files is then appended to the \texttt{List} menu
+in alphabetical order. The \texttt{List} menu is built every time a query
+window is opened or a query is loaded from / saved to a different directory.
+This behaviour is new in version 1.8, formerly it was only built when a new
+query window was opened.\\
+At the bottom of the query editor are three buttons for query control:
+\texttt{Clear} deletes the current query and provides you with an empty window.
+\texttt{Execute} executes the query (requires an open database). Errors
+during execution are reported to the user; the error position is displayed
+by selecting the erroneous parts of the query. If the query was executed
+without any errors and the resulting collection is not empty, a result window is
+opened (see \ref{ResultWindow} for MDD, \ref{ResultStrings} for scalar return
+types). \texttt{Update Data} opens a TIFF image for use as \texttt{\dollar 1} argument
+in an update query. If a query window has update data associated with it a string
+of the form \texttt{q$n_q$d$n_d$} is appended to its title where \texttt{$n_q$} is a
+decimal number representing the query window and \texttt{$n_d$} is a decimal number
+representing the image viewer. Likewise a string of the form \texttt{d$n_d$q$n_q$} is
+appended to the image viewer's title. If a query window or its update data
+window is closed this information string is removed from the remaining window's
+title bar. If new update data is opened the title bars of the old data viewer and
+the query window are updated accordingly.
+
+
+\section{The Preferences Window}
+\label{PreferencesEditor}
+
+The preferences window can be used to configure many aspects of the program.
+Its upper part is a scrollable window with the actual configuration items
+while the bottom row contains \texttt{OK} and \texttt{Cancel} buttons. Changes
+made to the preferences only become active after clicking on the \texttt{OK}
+button or pressing \texttt{<return>} in one of the text widgets. Clicking on
+\texttt{Cancel} discards all changes made to the preferences since the window
+was opened. Preferences are automatically saved when \rview\ is quit.
+
+\subsection{Misc Prefs}
+
+\begin{description}
+
+\item[Pathname of data files:] the full pathname of the directory \rview\ will
+use by default when loading / saving images and similar data. This field will
+also be updated automatically to the last directory accessed.
+
+\item[Pathname of query files:] the full pathname of the directory
+containing the query files (file extension \texttt{.ql}). This path will also
+be updated automatically to the last directory accessed in a query load
+or save operation.
+
+\item[Font used for queries:] here you can specify the font that should
+be used in the query windows (\ref{QueryWindow}). Fonts are specified like this:\\
+\begin{tabular}{rcl}
+\textsl{font} & = & \lbrack \textsl{keyword} \rbrack * \\
+\textsl{keyword} & = & \textsl{family} $\vert$ \textsl{style} $\vert$ \textsl{weight} $\vert$ \textsl{psize}\\
+\textsl{family} & = & \lbrack decorative $\vert$ default $\vert$ modern $\vert$ roman $\vert$ script $\vert$ swiss $\vert$ teletype \rbrack\\
+\textsl{style} & = & \lbrack italic $\vert$ slant \rbrack\\
+\textsl{weight} & = & \lbrack bold $\vert$ light \rbrack\\
+\textsl{psize} & = & \lbrack 0-9 \rbrack +\\
+\end{tabular}
+\\
+where \texttt{psize} is the point-size of the font. The default font is \texttt{default 12}.
+Changes take effect the next time a query window is opened. See also \ref{Platforms}.
+
+\item[Maximum width, Maximum height:] The maximum dimensions of viewer windows.
+At the moment this is used to limit the size of an image viewer window (\ref{ImageDisplayMode}).
+The size specified here should under no circumstances exceed the screen size.
+
+\item[Convertor parameters:] parameter string for convertors (TIFF, VFF). This allows
+to e.g.\ determine the TIFF compression type (e.g.\ \texttt{comptype=lzw}) or the default
+VFF dimension ordering (e.g.\ \texttt{dorder=xyz}). For a list of parameters see the
+conversion module documentation.
+\end{description}
+
+\subsection{Images}
+
+\begin{description}
+
+\item[Dither images:] This option makes a difference on displays with $\le$ 8bpp only.
+When selected, images are converted to the display using error-diffused dithering
+instead of a simple match to the closest colour. This results in much better quality
+at the expense of speed. Changes take effect the next time an image viewer is opened
+or the size of an existing image changes.
+\item[Dither best:] If this option is disabled, dithering may not have the highest
+possible quality but will be fast enough even for animations. Using \texttt{Dither best}
+involves a substantial amount of computational overhead and is therefore \emph{not}
+recommended for large images.
+\item[RGBSpace:] The default settings for colourspace mapping (see \ref{ColourspaceMapping}).
+You can choose between three range models which will be explained in \ref{ColourspaceMapping},
+or switch it off by default.
+\item[Edit:] This lets you edit the default settings of the colourspace mapping
+(see \ref{ColourspaceMapping}).
+
+\item[Image mode:] The default mode to use in image viewers. See
+\ref{ImageDisplayMode}.
+
+\item[Movie mode:] The default action to take when a movie has ended. The options are
+\texttt{Once} (stop playback), \texttt{Same dir} (restart the movie using the same playback
+direction) and \texttt{Switch dir} (switch playback direction). See \ref{ImageDisplayMode}.
+
+\item[Scaling factor:] The default scaling factor to use when opening a viewer for
+scaled images (see \ref{ImageModeScaled}).
+
+\item[Renderer:] Various settings for the renderers (surface, voxel) in image viewers.
+If the \texttt{For type} box is checked the voxel settings specified here (threshold values,
+weight quantisation and voxel colours) are ignored and base type specific defaults are used
+instead. See \ref{Renderers}.
+
+\item[Height fields:] Default settings for heightfield rendering. See
+\ref{HeightFieldRenderer}.
+
+\item[Orthosections:] Default settings for orthosection viewers. See
+\ref{ImageModeOrtho}.
+
+\item[Thumbnails:] Default settings for the thumbnail viewers. See
+\ref{ThumbnailDisplayMode}.
+
+\end{description}
+
+\subsection{Charts}
+Default settings for the chart viewer. See \ref{ChartDisplayMode}.
+
+\subsection{Tables}
+Default settings for the table viewer. A value of -1 for \texttt{Step X} and \texttt{Step Y}
+means the viewer will make a guess at the grid size depending on the base type of the
+object. See \ref{TableDisplayMode}.
+
+\subsection{Sound}
+Default settings for the sound player. See \ref{SoundDisplayMode}.
+
+\subsection{Communication}
+
+Settings for the data formats to use for data transfer and data storage. The
+transfer data format is always used to send MDD \emph{to} the server. When
+loading data from the server, it's normally a suggested format that's used
+in case the data is uncompressed, but can also be enforced if the transfer
+parameters contain the tuple \texttt{exactformat=1}. The available options are
+the same for transfer and storage. If both data formats differ, the data
+will be converted in the server to the storage format prior to actual
+storage. Usually a light-weight data format should be chosen as transfer
+format (e.g.\ \texttt{RLE} or even raw data \texttt{Array}). It's important to
+note that no lossy compression scheme should be used for transfering MDD
+to the server because the server might have to retile the data, meaning
+it'll be decompressed and recompressed with a potential accumulation of
+loss. Using a lossy format as storage format only avoids this problem
+because the storage format will only be applied to the actual tiles
+stored.\\
+The data formats currently available are the following, but they may be extended
+any time:
+
+\begin{description}
+\item[Lossless:]\ \\
+\vspace{-6mm}
+\begin{description}
+\item[Array:] raw data transfer, no compression
+\item[RLE:] Run Length Encoding
+\item[ZLib:] ZLib compression
+\item[SepRLE:] Run Length Encoding with base type separation
+\item[SepZLib:] ZLib compression with base type separation
+\item[HaarWave:] Haar Wavelet compression
+\end{description}
+\item[Lossy:] (the numbers shown in the list widget are the filter lengths)\\
+\vspace{-6mm}
+\begin{description}
+\item[Daubechies*Wavelet:] the standard Daubechies wavelet series
+\item[LeastAsym*Wavelet:] the least asymmetric Daubechies wavelet series
+\item[Coiflet*Wavelet:] the Coiflet wavelet series
+\end{description}
+\end{description}
+
+In addition, the compression algorithms can be configured considerably by
+writing parameters as a comma-separated list over primitive tuples of the
+form \textsl{keyword=value} into the corresponding parameter window. Newlines
+are allowed and there is no length limit on the parameter list. String
+values can be written without quotes if they don't contain spaces or commas,
+otherwise the string must be embedded in (double) quotes. Currently
+available parameters can be seen in figures
+\mbox{\ref{FigureParamsComm} -- \ref{FigureParamsZerotree}}.
+
+\newcommand{\BeginKeyTable}{%
+ \begin{figure}[hptb]\begin{center}\begin{tabular}{|c|c|c|p{90mm}|}%
+ \hline%
+ \textbf{Keyword} & \textbf{Type} & \textbf{Default} & \textbf{Description}\\%
+ \hline%
+}
+\newcommand{\EndKeyTable}[2]{%
+ \hline%
+ \end{tabular}%
+ \caption{#1} #2%
+ \end{center}\end{figure}%
+}
+
+\BeginKeyTable
+\texttt{exactformat} & int & 0 &
+If \texttt{exactformat} is 0, the transfer format will be used by the server for
+data stored in uncompressed format only; it it's $\ne$ 0, the server will always
+repack the data to the exact format requested by the client\\
+\EndKeyTable{Keywords for client-server communication}{\label{FigureParamsComm}}
+
+\BeginKeyTable
+\texttt{predinter} & string & --- &
+The name of the interchannel predictor which correlates cells across channels
+($\rightarrow$ atomic types within structured types). Possible values:
+\texttt{delta} (normal difference) and \texttt{scaledelta} (rescale to same
+dynamic range, then use difference)\\
+\texttt{predintra} & string & --- &
+The name of the intrachannel predictor which correlates cells to its spatial
+neighbours. Possible values: \texttt{hyperplane} (predict from previous hyperplane,
+e.g.\ previous scanline in a 2D image), \texttt{neighbours} (predict from arithmetic
+average of all neighbouring cells already seen) and \texttt{weighted} (additionally
+weigh the neighbouring cell values according to their offset in each dimension)\\
+\texttt{intermap} & string & --- &
+Comma-separated list of channel mappings of the form
+\texttt{\textit{ch-num}:\textit{pred-num}} where \texttt{\textit{ch-num}} is the
+number of the channel being mapped and \texttt{\textit{pred-num}} is the number
+of the channel it's predicted by. e.g.\ typical for RGB images where green predicts
+red and blue: \texttt{0:1,2:1}\\
+\texttt{intralist} & string & --- &
+Comma-separated list of channel numbers where intrachannel prediction is used.
+If the first character is an exclamation mark, the inverse list is used.\\
+\texttt{hypernorm} & int & 0 &
+For intrachannel \texttt{hyperplane} prediction: the number of the dimension
+orthogonal to the (moving) predictor hyperplane, i.e.\ the direction in which
+prediction takes place\\
+\texttt{predweight} & double & 0.5 &
+For intrachannel \texttt{weighted} prediction: the amount by which a cell weight
+decreases for each offset $\ne$ 0 in a dimension\\
+\EndKeyTable{Keywords for predictors}{\label{FigureParamsPredict}}
+
+\BeginKeyTable
+\texttt{zlevel} & int & 6 &
+The zlib compression level ($0\ldots9$)\\
+\EndKeyTable{Keywords for ZLib compression stream}{\label{FigureParamsZLib}}
+
+\BeginKeyTable
+\texttt{wavestr} & string & \texttt{zlib} &
+The compression stream name to use: \texttt{none}, \texttt{rle}, \texttt{zlib} or
+\texttt{arith}\\
+\texttt{mrlevels} & int & 0 &
+Maximum number of hierarchical levels to do multiresolution analysis on.
+0 means all levels\\
+\texttt{banditer} & string & \texttt{leveldet} &
+The name of the band iterator. Possible values: \texttt{isolevel}, \texttt{leveldet}
+and \texttt{isodetail}\\
+\EndKeyTable{Keywords for wavelets}{\label{FigureParamsWavelet}}
+
+\BeginKeyTable
+\texttt{wqtype} & string & \texttt{zerotree} &
+The quantization type to use. Possible values are \texttt{perband} and \texttt{zerotree}.
+\texttt{zerotree} is much more efficient regarding storage space but involves rather
+much overhead. \texttt{perband} is simpler but compresses worse and is harder to
+configure.\\
+\texttt{enhancelv} & int & 0 &
+Number of hierarchical levels (starting from coarsest one) over which to enhance
+wavelet-coefficients at the boundary (to avoid boundary artifacts at low rates).
+0 disables it.\\
+\texttt{qwavdbg} & int & 0 &
+Level for debug-version: perform additional statistics during encoding;
+higher levels do everything lower levels do. 1: residuum and logarithmic
+histogram; 2: linear histogram for all bands; 3: effect of zeroing each
+band on signal-to-noise ratio\\
+\EndKeyTable{Keywords for lossy wavelets}{\label{FigureParamsQWavelet}}
+
+\BeginKeyTable
+\texttt{qrtype} & string & \texttt{const} &
+The quantizer type (statistics module), setting the bits per band. Values
+are \texttt{const}, \texttt{linear}, \texttt{expnt}, \texttt{gauss} and \texttt{custom}
+where \texttt{custom} can't be selected directly\\
+\texttt{qntype} & string & \texttt{linear} &
+The quantization type, either \texttt{linear} or \texttt{expnt}\\
+\texttt{bitscale} & double & 1.0 &
+Set the scaling factor of the bit allocation curve relative to the size of
+the base type\\
+\texttt{cutoff} & double & 1.0 &
+The band number relative to the total number of wavelet subbands starting
+from which all bands are ignored (quantized to 0)\\
+\texttt{nullzone} & double & 0.0 &
+Coefficients whose absolute value is smaller than \texttt{nullzone} are set to 0\\
+\texttt{relqbits} & string & --- &
+The string is a comma-separated ($\Rightarrow$ the string must be enclosed in
+double quotes) list of floating point values, encoding the number of bits
+relative to the number of bits in the base type each wavelet band should be
+encoded with. Implicitly sets the quantizer type to \texttt{custom}.\\
+\EndKeyTable{Keywords for \emph{perband} lossy wavelet compression}{\label{FigureParamsPerband}}
+
+\BeginKeyTable
+\texttt{zttype} & string & \texttt{band1} &
+The type of the zerotree encoding to use. \texttt{band1} is one-pass with a four symbol
+alphabet whereas \texttt{band2} is two-pass with dominant pass (four symbol alphabet) and
+a subordinate pass (two symbol alphabet).\\
+\texttt{psnr} & double & 100.0 &
+The signal-to-noise ratio to use during encoding. Higher values mean better
+quality\\
+\EndKeyTable{Keywords for \emph{zerotree} lossy wavelet compression}{\label{FigureParamsZerotree}}
+
+The \texttt{exactformat} parameter must be added to the parameters for the
+transfer format, not the one for the storage format. Transfer- and storage
+formats are used like this:
+
+\begin{center}
+\begin{tabular}{|c|p{70mm}|p{50mm}|}
+\hline
+\textbf{Direction} & \textbf{Transfer format} & \textbf{Storage format}\\
+\hline
+Insert & Used for transfer to the server & Used for actually storing the data\\
+\hline
+Retrieval & Depending on the value of \texttt{exactformat}:
+\begin{itemize}
+\item
+= 0: used for data stored in uncompressed format, ignored for all
+other data.
+\item
+$\ne$ 0: used for all data, repacking on the server if necessary
+\end{itemize}
+& ignored\\
+\hline
+\end{tabular}
+\end{center}
+
+\pagebreak[4]
+
+
+\section{The Results Window}
+\label{ResultWindow}
+
+This window is the starting point for visualizing MDD objects downloaded from
+the database as a result of selecting \texttt{Collections->Lookup} from the
+main window (\ref{MainWindow}) or executing a query (\ref{QueryWindow}). All
+MDD objects are owned by this window, so closing viewers does not remove any
+data but the viewers' own from memory. Double-clicking on an entry in the results
+list opens a viewer of the type set by \texttt{Display Mode}. Currently available
+display modes are
+
+\begin{description}
+
+\item[Image modes:]\ \\
+\begin{description}
+\item[Flat image] is a 2D mode and means a simple orthogonal projection that works
+with data of any dimensionality (see \ref{ImageModeFlat}).
+\item[Volumetric] can only be used to visualize volumetric data (i.e.\ 3D) like tomograms.
+It consists of two renderer types, a surface-oriented renderer which only displays the
+textured surfaces of the data\-cube and is therefore very fast and a voxel renderer that
+can also display the inner structure of a data cube at the expense of a substantial amount
+of computational overhead. You may switch between these two modes any time (see
+\ref{ImageModeVolumetric}).
+\item[Orthosection] can only be used to visualize volumetric data which is rendered
+as three orthogonal slices with user-configurable thickness through the volume
+(see \ref{ImageModeOrtho}).
+\item[Height field] is a heightfield renderer that displays arbitrarily dimensioned data as a
+shaded 3D heightfield (see \ref{HeightFieldRenderer}).
+\end{description}
+
+\item[Other modes:]\ \\
+\begin{description}
+\item[Chart] is a 1D mode that can display data as simple chart diagrams (see
+\ref{ChartDisplayMode}).
+\item[Table] is the most generic of all modes in that can display data of any
+dimensionality and base type as a table of numeric values (see \ref{TableDisplayMode}).
+\item[Sound] can be used to play MDD objects as sound samples (see \ref{SoundDisplayMode}).
+\end{description}
+
+\end{description}
+
+There can only be one open viewer for each object for each display mode, so opening an
+object in flat image and height field or chart mode is possible whereas opening two flat
+image viewers on one object is not.\\
+There are two menus available here:\\
+
+\subsection{Item}
+
+This menu offers three items: \texttt{Open all} opens viewers of the type specified by
+\texttt{Display Mode} for all objects in the results list. \texttt{Thumbnail All} opens
+a thumbnail viewer window containing all objects in the results list. \texttt{Close}
+closes the results window and all its viewer windows and frees all memory
+allocated by the objects in the results list.
+
+\subsection{Selection}
+
+The operations in this menu deal with selections of objects. The available menu
+items are
+
+\begin{description}
+\item[Select all:] Mark all objects in the collection as selected.
+\item[Clear:] Clear the current selection.
+\item[Open:] Open the selected objects in the viewer mode specified by \texttt{Display
+Mode}.
+\item[Thumbnails:] Open a thumbnail viewer containing only the selected objects
+rather than the entire collection.
+\item[Delete:] Delete the selected objects and thus free the memory allocated to
+them. Use this if you're short on memory and only need a part of the collection
+for future work. This does not affect persistent objects in the database.
+\item[Change Endian:] Changes the endianness of the selected objects.
+\item[Type Manager:] Allows you to change the base types of the selected objects
+by building new objects consisting only of selected type members. See
+\ref{TypeManager}.
+\item[Info:] Additional information about the selected objects. Not yet implemented.
+\end{description}
+
+
+\subsection{Other options}
+
+You can also scale the selected objects using the \texttt{Scale/Resample} widgets to the
+right of the control field. The writable field contains comma- or space-separated
+scaling factors for each dimension. If there are fewer scaling factors than dimensions,
+the last scaling factor available will be used for all dimensions that don't have
+an explicit scaling factor assigned to them. e.g.\ resampling a 3D object using
+\texttt{"2.0"} scales the entire object by 2 in all dimensions, \texttt{"2.0, 3.0, 4.0"}
+scales the object by 2 in the first dimension, by 3 in the second and by 4 in the
+third while \texttt{"2.0, 1.5"} scales the object by 2 in the first dimension and
+by 1.5 in the second and third dimension.\\
+Different algorithms are used for simple scaling, upsampling and downsampling.
+Simple scaling just uses nearest neighbours and is therefore very fast. The downsides
+are blockiness when scaling up and aliasing when scaling down. Resampling addresses
+these problems at the expense of speed. Downsampling averages over subcubes whereas
+upsampling performs n-linear interpolation. Therefore care should be taken when
+resampling that the scaling factors specified are either all larger or all smaller
+than 1.0. Also note that especially upsampling is very time- and memory-consuming.
+
+\subsection{The Type Manager} \label{TypeManager}
+
+The Type Manager allows you to build new mdd objects out of existing ones by
+copying selected member variables of the source objects only. The Type Manager
+can be opened by selecting a menu entry from the \texttt{Results window}
+(\ref{ResultWindow}). This will open a new window which graphically represents
+the base type of the selected object(s). There is a checkbox for each member
+variable; each checkbox is labeled "\textsl{varname} (\textsl{type})" where \textsl{varname}
+is the name of the member variable (if available) and \textsl{type} is the type of
+this member variable. Structures are recursively grouped together and bounded by
+a rectangular box each. The member variables that should be copied into the
+newly created object have to be selected using the mouse. If the conversion
+is executed and the resulting base type is not known to \rview, the user is
+requested to enter a type name. Unless the resulting object is intended to
+be written into the database again, the name doesn't matter. \rview's visualization
+techniques recognize all atomic types and a structure containing 3 bytes
+(interpreted as RGB).
+
+
+\section{Scalar results} \label{ResultStrings}
+
+If the result of a query is a (collection of) scalar(s) or an interval,
+it will be displayed as a scrollable window where each line shows the
+string-representation of a value. There are no further operations possible
+on results of this type.
+
+
+\section{Object viewers}
+\label{ObjectViewers}
+
+All object viewers share certain basic components which will be explained here before
+the individual modes are examined in more detail.\\
+Most importantly there's the projection string which lets you specify the dimensions
+to visualize as well as pick areas of interest only rather than the entire object.
+The projection string is of the form
+\\
+
+\begin{tabular}{rcl}
+\textsl{projection} & = & $\underbrace{\mbox{\textsl{dim\_desc}}, \ldots , \mbox{\textsl{dim\_desc}}}_{\mbox{\textsl{dimension} times}}$ \\
+\textsl{dim\_desc} & = & \textsl{desc} $\vert$ \textsl{desc:desc} \lbrack\textsl{map\_dim}\rbrack\\
+\textsl{desc} & = & \textsl{coordinate} $\vert$ *\\
+\textsl{coordinate} & = & \lbrack 0-9 \rbrack +\\
+\textsl{map\_dim} & = & \lbrack 0-9 \rbrack +\\
+\end{tabular}
+
+where * and *:* are synonymous, meaning the entire range of this dimension. If
+$\mbox{\textsl{dim\_desc}}_i$ is of the form \textsl{coordinate} a projection to this coordinate in
+dimension $i$ is performed; dimension $i$ is a \emph{fixed dimension}. If
+$\mbox{\textsl{dim\_desc}}_i$ is of the form \textsl{desc:desc} this is interpreted as \textsl{low:high}
+pair of coordinates in dimension $i$ and the entire range between \textsl{low} and \textsl{high}
+is selected; dimension $i$ is a \emph{free dimension}. The optional addition of \textsl{map\_dim}
+in square brackets allows re-ordering dimensions in \emph{some modes} (e.g.\ flat images and
+tables); in this case \textsl{map\_dim} is the number of the dimension that should be associated
+with this interval, starting from 0. This mechanism allows things like transposing. If the
+number of free dimensions is not equal to the dimensionality of the display mode an error
+in the projection string is reported.\\
+\textbf{Examples:} Assuming a 3D-object with the spatial domain
+\lbrack 0:200, 100:400, 200:600 \rbrack\ the following projection strings result in \ldots\\
+
+\begin{description}
+\item[*:*, *:*, *:*] -- Everything (3D).
+\item[0, *:*, *:*] -- A projection to 0 in the first dimension and all data in the other
+two dimensions, i.e.\ an object [100:400, 200:600] (2D).
+\item[0, 200, *:*] -- A projection to 0 in the first and 200 in the second dimension,
+all data in the third dimension (1D).
+\item[100:150, *:300, 300:*] -- The coordinates 100 to 150 in the first dimension,
+100 to 300 in the second dimension and 300 to 600 in the third dimension (3D).
+\item[0, *:*\lbrack 2\rbrack, *:*\lbrack 1\rbrack] -- Like the 2nd example but transposed,
+i.e.\ an object [200:600, 100:400].
+\end{description}
+
+Pressing \texttt{<return>} in the projection string widget or clicking on the \texttt{OK}-button
+next to it updates the display accordingly. If there is at least one fixed dimension, clicking
+on the + and - buttons increases or decreases the value of a fixed dimension, allowing you
+to move through a datacube along a given axis. If there is more than one fixed dimension,
+the writable field between the + and - buttons can be used to specify which one should
+be affected by the + and - buttons. Enter the number of the dimension along which you want
+to move here, starting from 0.\\
+\\
+All but the thumbnail viewers (see \ref{ThumbnailDisplayMode}) also provide the following
+menu entries, listed under \texttt{Data}:
+
+\begin{description}
+\item[Insert:] Insert the entire object into the database. This will pop up a
+dialog box asking you for the name of the collection the object should be stored in.
+
+\item[Insert proj:] Insert the object's current projection only into the
+database.
+
+\item[Save:] Save the raw MDD to disk. The resulting file is just the array data
+without any spatial information, therefore this option should only be used on
+1-dimensional data, e.g.\ TIFF-encoded images.
+
+\item[Close:] Close the viewer.
+
+\end{description}
+
+Additionally, all but the thumbnail viewer have a \texttt{View} menu with at
+least two entries \texttt{Load} and \texttt{Save}. A "view" contains all meta
+information required to visualize the current MDD as it is displayed in the
+viewer's visualization area, e.g.\ renderer configuration, colourspace mapping
+parameters, current rotation etc.; this meta information can be saved to and loaded
+from a file with these two menu entries. A view is specific to one viewer type,
+so a volumetric viewer's view file can not be loaded into a height field renderer.
+Views can be used to easily memorize efficient visualization parameters for later
+use (such as a good viewing angle for voxel rendering), or for visualizing the
+effects of signal processing algorithms on an MDD as a sequence of images of the
+same size/rotation/lighting/$\ldots$.\\
+Note that a view may contain very MDD-specific properties, such as the
+MDD's numeric range used by the colourspace mapper or the spatial extent
+for the projection string. Therefore a view should only be used for either
+the same MDD or MDD with sufficiently similar properties, otherwise unwanted
+side-effects may occur.\\
+Most modes also offer additional menus for specific features, such as saving the
+current visualization to a TIFF image, or displaying the current rotation
+numerically.\\
+Now follows a detailed description of the currently available display modes.
+
+
+\subsection{Image viewers}
+\label{ImageDisplayMode}
+
+The image display modes are the primary modes for graphical representation of MDD
+objects. Next to simple orthogonal projections for displaying 2D images it also
+includes 3D renderers which are described in more detail in \ref{Renderers}.\\
+There are various additional menus in this mode. \texttt{Data} contains the new
+entry \texttt{Save TIFF} which saves the currently visible image to disk as a TIFF file.
+The \texttt{Settings} menu contains configuration options dependent on the image
+mode. The one entry available in all modes is the \textbf{Colourspace} menu, see
+\ref{ColourspaceMapping}. Another possible entry, \textbf{Movie playback}, is
+shared in flat and height field modes (sections \ref{ImageModeFlat},
+\ref{HeightFieldRenderer}) and allows the following choices on what to do
+when the end of the movie has been reached (using \texttt{a = \textsl{start}} and
+\texttt{b = \textsl{end}} of the movie):
+
+\begin{description}
+\item[Once:] Just stop playback.
+\item[Same direction:] Rewind the movie and restart using the same playback direction,
+thus the sequence is \texttt{a $\rightarrow$ b, a $\rightarrow$ b, $\ldots$} or
+\texttt{b $\rightarrow$ a, b $\rightarrow$ a, $\ldots$}, depending on the initial playback
+direction.
+\item[Switch direction:] Switch playback direction so the movie oscillates between
+end-points and the sequence is \texttt{a $\rightarrow$ b, b $\rightarrow$ a, $\ldots$} or
+\texttt{b $\rightarrow$ a, a $\rightarrow$ b, $\ldots$}, depending on the initial playback
+direction.
+\end{description}
+
+Movie mode is possible whenever the dimensionality of the MDD object exceeds the
+dimensionality of the visualization mode (both flat and height field images are 2D,
+therefore movies are possible if the MDD object has dimensionality three or higher).
+The actual movie playback can be controlled with additional buttons created below
+the projection string's +/- buttons. These new buttons,
+which can only be used in \texttt{Flat} and \texttt{Height} mode, behave like auto-repeating
++/- buttons and allow displaying a datacube as a movie. "$<$" corresponds to "-"
+and "$>$" corresponds to "+". In case of more than one free dimension the same
+rules apply that are used for the +/- buttons (see \ref{ObjectViewers}).
+
+In all image modes except for the one for scaled images (see \ref{ImageModeScaled}) you
+can mark a rectangle by dragging its outline while holding down the \texttt{ctrl} key.
+The pixel coordinates of the dragged box relative to the upper left corner of the image
+will be displayed in the upper left corner of the box in the format
+$x_{low}:x_{high}, y_{low}:y_{high}$. Using the left mouse button for the
+drag will always start a new box, using the right mouse button will adjust the size of
+the existing box by moving the nearest corner to the position of the mouse pointer. To
+remove the box simply click inside the image with the \texttt{ctrl} key held down.
+
+
+\subsubsection{Flat Images} \label{ImageModeFlat}
+
+This mode visualizes orthogonal 2D projections of the MDD object. There are no
+restrictions on dimensionality, but only two dimensions can be displayed
+simultaneously. The scale slider can be used to scale the image by any factor
+between 0\% and 500\% using a simple nearest neighbour algorithm which is
+much faster than the resampling procedure available in the Results window
+(\ref{ResultWindow}) but also of considerably worse quality. The size of the image
+and hence the redraw time is determined by the size given by the projection string
+times the scaling factor and is therefore independent of the view window size.
+Flat mode is the recommended viewing mode for actual 2D images or movies
+whereas for 3D data one the the volumetric renderers is the better choice
+(see \ref{ImageModeVolumetric}).
+%In flat mode the orientation of the horizontal axis is from top-to-bottom.
+
+
+\subsubsection{Scaled Images} \label{ImageModeScaled}
+
+This class is very similar to flat images (see \ref{ImageModeFlat}) in that it
+performs orthogonal 2D projections of the MDD object. This mode is intended
+for very large MDD objects that are only transfered in part and/or scaled down
+from the server but never reside in client memory in their entirety. Hence there
+is no scale slider nor movie controls.\\
+In contrast to the other image modes, a box is dragged without holding down the
+\texttt{ctrl} key and the dragged box will always have the same aspect ratio
+as the visible image. The available functionality is represented by four buttons
+below the projection string,
+
+\begin{description}
+\item[To Box:] scale up the image within the dragged box to fill the entire
+area currently visible.
+\item[Back:] return to the previous view.
+\item[Zoom In:] magnify the currently visible image by 2 without changing the
+size of the resulting image, i.e.\ the area of the unscaled image covered by the
+new view is only $\frac{1}{4}$th that of the original view. The upper left corner
+remains the same for both views.
+\item[Zoom Out:] the inverse operation of \texttt{Zoom In}. The visible image
+of the new view can become smaller than in the previous view, however.
+\end{description}
+
+A \emph{view} comprises all meta data that uniquely identifies a visualization
+of an MDD object, i.e.\ a scaling factor, a bounding box (n-D interval) and
+the two free dimensions. Whenever either parameter is changed, the currently
+active view is saved on a stack before the new view is activated. Pressing the
+\texttt{Back} button retrieves just this meta data from the stack in client memory
+whereas the corresponding data is reloaded from the \rman\ server; except for
+the view meta data no data is cached by \rview. There is no limit on the depth
+of the view stack.\\
+Note that the projection string is for the entire, unscaled object, whereas the
+drag box coordinates are relative to the current view. Any changes to the projection
+string will be translated to the current view before they're applied. Also,
+changing the projection string equals the definition of a new view and
+stacking of the previous one.
+
+
+\subsubsection{The Renderers}
+\label{Renderers}
+
+For the various renderers, some new functionality is available in the viewer
+window. The \texttt{BBox} checkbox determines whether the renderer should draw the object's
+bounding box as well. Also there are two new menu entries in the \texttt{Settings}
+menu:
+
+\begin{description}
+\item[Renderer:] Allows changing parameters needed by the 3D renderers. See
+\ref{RendererModel}.
+\item[Renderer controls:] Allows animating rendered images by continuous
+rotation (see \ref{RendererControls}).
+
+\end{description} % settings menu
+
+Renderers also have an additional entry \texttt{Show} in the \texttt{View} menu
+which displays the current rotation matrix, z-offset and scale in a small window.
+The rotation matrix ($3\times 3$) is represented by three rotations around the
+coordinate axes, first $x$, then $y$, then $z$; the angles are in units of $\pi$
+rather than degrees. All entries in this window can also be altered manually.\\
+The renderers always use an image the size of the view window, so it's not a good
+idea to make the view window substantially larger than the area covered by the
+object's bounding box, because although the renderers don't operate outside the
+object's bounding box the image will be larger than necessary and therefore take
+longer to display, in particular when the display is remote over a network.
+
+\paragraph{Renderer Basics} \label{RendererModel} % hardspace to make linefeed possible
+\ \\
+First let's specify the coordinate system: x is the
+horizontal axis, oriented left to right, y is the vertical axis, oriented bottom to
+top and z is the depth axis (parallel to the screen normal), oriented into the screen.
+The observer is at position $(0, 0, 0)$ where the line $(0, 0, x)$ is projected to
+the pixel in the image center. All renderers use perspective projection of
+the data cube to the \emph{projection plane}, a plane parallel to the screen surface
+that intersects the z-axis at position $(0, 0, z_p), \quad z_p > 0$. The value of $z_p$
+determines how much effect perspective projection will have, i.e.\ how quickly an object
+gets smaller as its $z$ component increases. The smaller the value of $z_p$
+the higher the impact of perspective projection. Values between $256$ and $512$
+generally produce good results, with larger values recommended for large objects.
+The value of $z_p$ can be changed in the \texttt{Image settings} window which is
+opened by selecting the \texttt{Settings $\rightarrow$ Renderer} menu available
+in the image viewer.\\
+Parts of the data cube lying too close to (or even behind) the viewer can't be
+rendered, therefore the cube has to be clipped. In order to do this the intersection
+of the cube with the \emph{clipping plane} has to be calculated. The clipping plane
+is a plane parallel to the projection plane, intersecting the z-axis at position
+$(0, 0, c_z), \quad c_z > 0$. In effect the cube is "cut open" so data formerly inside the
+cube will be mapped to the new surface. Generally speaking, the value of $c_z$ should
+be smaller than $z_p$. Values in the area of $\frac{z_p}{2}$ give good results, but
+if you want to slice through the cube without moving it closer to the viewer this
+can be achieved easily by incrementing the value of $c_z$ in the \texttt{Image
+Settings} window.\\
+Using the \texttt{Scale} slider scales the data cube itself, not the rendered
+image which means that you can also get z-clipping effects by scaling the
+cube. It also means that you still get smooth edges in an upscaled renderer
+display and the texels aren't as noticable as their edges are parallel
+to the data cube's edges rather than parallel to the coordinate system.\\
+You can switch on/off lighting in the \texttt{Image settings} window; currently
+this will only have an effect in voxel mode. Let $l$ be the normalized vector
+from the voxel to the light source, $n$ the outward-oriented surface normal and
+$\alpha$ the angle between the two ($\cos\alpha = l \cdot n$). Furthermore let
+$\beta$ be the \emph{light angle} and $\gamma$ the \emph{scintillation angle}
+specified in the \texttt{Image settings} window; both describe the range of angles
+$\alpha$ for which the corresponding parameter should have any effect:
+
+\begin{center}
+\begin{tabular}{rlrl}
+$\lbrack \beta, 180 \rbrack$ & ambient light only & $\lbrack \gamma, 180 \rbrack$ & no scintillation \\
+$\lbrack 0, \beta )$ & ambient light + shading & $\lbrack 0, \gamma )$ & scintillation \\
+\end{tabular}
+\end{center}
+
+One way to express this with normalized weighting factors would be
+
+\begin{displaymath}
+w_l(\alpha,\beta) = \left\lbrace\begin{array}{rl}
+\frac{\cos\alpha - \cos\beta}{1 - \cos\beta} & \mbox{if} \cos\alpha > \cos\beta\\
+0 & \mbox{otherwise}\\
+\end{array} \right. , \qquad
+w_s(\alpha,\gamma) = \left\lbrace\begin{array}{rl}
+\frac{\cos\alpha - \cos\gamma}{1 - \cos\gamma} & \mbox{if} \cos\alpha > \cos\gamma\\
+0 & \mbox{otherwise}\\
+\end{array} \right.
+\end{displaymath}
+
+Note that values greater than 90 (degrees) for $\beta$ or $\gamma$ are unphysical;
+they do help to bring out details in dark areas, however. It is advisable to
+decrease the level of ambient light when increasing the light angle.
+Using these weighting factors a voxel is shaded according to the equation
+\begin{displaymath}
+pixel = voxel \cdot (amb + w_l(\alpha,\beta) \cdot (1 - amb)) + voxel_{grey} \cdot gain \cdot w_s(\alpha,\gamma).
+\end{displaymath}
+The $amb$ parameter determines the level of ambient light and should be in the
+interval \hbox{\lbrack 0, 1\rbrack} where 0 means no ambient light (surfaces not hit
+by the light source are totally black) and 1 means full intensity provided by ambient
+light (which is equivalent to shading off). The first part of the formula thus
+performs a darkening of the actual voxel colour by giving it a base intensity
+determined by $amb$ and additional intensity depending on the surface orientation.
+$voxel_{grey}$ is the greyscale value associated with the voxel colour which,
+when multiplied by $w_s(\alpha,\gamma)$, produces a shaded greyscale version of the voxel,
+so the second part of the formula adds a weighted version of the shaded greyscale
+voxel scaled by $gain$ to the shaded voxel. The $gain$ parameter has to be $\ge 0$ and the
+higher it is the brighter those surfaces where $\alpha < \gamma$ will become. This
+also influences the actual colour of a voxel by forcing a shift towards white the
+more directly the voxel is facing the light source.\\
+The position of the light source is described by the \texttt{Direction} and \texttt{Distance}
+fields in the \texttt{Image settings} window. The possible directions are encoded as a string
+consisting of arbitrary combinations of direction aliases or $\epsilon$ (the empty
+word) for each dimension. Those aliases are \texttt{l, r} (left, right) for the first dimension,
+\texttt{d, u} (down, up) for the second dimension and \texttt{f, b} (front, back) for the
+third dimension. Only one direction alias may be specified for each dimension, so \texttt{l}
+and \texttt{r} are mutually exclusive. Thus the direction string lets you specify the
+26 vertices on the surface of a 3D cube bisected in each dimension through its center
+(plus the 27th vertex
+in the center, but that choice wouldn't be very sensible). Examples would be \texttt{ur}
+(corresponding to $(1,1,0)^T$), \texttt{uf} ($(0,1,-1)^T$) or \texttt{dlb} ($(-1,-1,1)^T$).
+Use the \texttt{Distance} field to determine at which distance from the origin along the
+direction vector the light source should be situated.\\
+For more tuning parameters regarding normal approximation see section \ref{VoxelRenderer}
+about the voxel renderer.
+
+\paragraph{Navigating} \label{RenderNavigation}
+\ \\*
+The data cube can be rotated by moving the mouse while holding down the left
+mouse button. Moving the mouse horizontally rotates around the y-axis (positive
+angles by moving to the right), moving the mouse vertically rotates around the
+x-axis (positive angles by moving to the bottom). This system may be improved
+to something more intuitive in the future.\\
+The cube can be moved along the z-axis by moving the mouse vertically while
+holding down the right mouse button. Moving upwards brings the cube closer
+to the viewer while moving downwards takes to object further away.
+
+\paragraph{The Renderer Controls} \label{RendererControls}
+\ \\*
+This window is opened using the \texttt{Settings $\rightarrow$ Renderer Controls} menu
+in an image viewer and makes it possible
+to animate rendered images. The window consists of three sliders representing the
+three rotation axes with a button labeled "0" to the right of each. Clicking on one of
+the "0" buttons resets the corresponding slider to 0, thus terminating rotation around
+that axis. Rotation starts when you click the lower left button labeled \texttt{Start} which
+will then change to \texttt{Stop}. The slider values can be changed at any time, even
+after animation has been started; dragging the cube directly with the mouse is
+still possible when animation is in progress, too. You can stop the animation by clicking
+on the \texttt{Stop} button in the \texttt{Renderer controls} window or by clicking on the
+button labeled \texttt{\lbrack \rbrack} in the image viewer window which is also used
+for stopping movie playback.
+
+\paragraph{Volumetric renderers} \label{ImageModeVolumetric}
+\ \\
+The volumetric renderers can only handle 3D data with base type sizes of 1 to 4 or
+8 bytes where base types of size 4 may be \texttt{long} or \texttt{float} and a base type
+of size 8 is interpreted as double. Two volumetric renderers are combined in
+one image viewer and the user may freely switch between modes by using the new
+menu \texttt{Modes}. The third is an orthosection viewer (see \ref{ImageModeOrtho})
+which is uses a separate window.
+
+\subparagraph{Surface renderer} \noindent \label{SurfaceRenderer}
+\ \\*
+The surface renderer only visualizes the surfaces of the data cube by texture-mapping
+the data on the cube's surface to the polygons representing it (which may be
+rotated and scaled in any way). While this is very fast it has the drawback that
+data inside the cube can not be visualized at all unless z-clipping is applied
+to the cube (see the basic model). This mode is recommended for rotating or
+positioning the cube before switching to a better but more time-consuming
+mode like the voxel renderer, for instance. It's also the mode of choice for
+data where not all three dimensions are spatial (e.g.\ movies).
+
+\subparagraph{Voxel renderer} \noindent \label{VoxelRenderer}
+\ \\*
+The voxel renderer is recommended for visualizing data where all three dimensions
+are spatial (i.e.\ volume data). Data is visualized by casting rays through
+the volume and calculating the frontmost intersection of each ray with a
+non-empty pixel. In order to get good results over a wide range of input
+data a lot of configuration options are available in the \texttt{Renderer}
+menu.\\
+A few definitions first: an \emph{empty pixel} is one whose value lies outside
+the threshold interval
+$$ti = \lbrack pixel\_threshold\_low, pixel\_threshold\_high \rbrack .$$
+These threshold values are base type dependent; if you specified \texttt{For mode}
+in the preferences window, \rview\ tries to find sensible defaults for these
+parameters, depending on the type, otherwise the values given in the preferences
+are used. A special case is the RGB base type where there are two thresholding
+models: a pixel is interpreted as empty if all its colour components are outside
+the threshold interval (\texttt{RGB brightness} off) or it's considered empty if the
+average of its colour components is outside the threshold interval
+(\texttt{RGB brightness} on).\\
+Since data obtained by computer tomograms and similar techniques usually
+includes a fair amount of noise the naive approach of simply using the
+frontmost non-empty pixel intersected by the ray usually doesn't produce
+any meaningful results. What's needed is some kind of averaging procedure that
+makes the ray penetrate deeper into the data until a weight criterium is met
+and then average over the non-empty pixels that were intersected. Simply
+adding these pixel values produced poor results as well, however. A technique
+that gave very good results was first calculating a weight for each pixel
+using the formula $w = \vert \frac{v + 2^q - 1}{2^q} \vert$ for integers and
+$w = \vert \frac{v}{2^q} \vert$ for floating point types, where $v$ is the
+pixel value (in RGB mode this is the average of the colour components) and $q$
+is the \emph{weight quantisation}. Thus the weight is proportional to the pixel
+value and inversely proportional to $2^q$. The weighted sum of pixels $s$ is updated
+using $s = s + w*p$ where $p$ is the pixel value; note that in RGB mode $s$ and
+$p$ are 3D vectors over the RGB colourspace. Since $w$ was proportional
+to $v$ the update value is proportional to $v^2$, i.e.\ "brighter" pixels have
+a much stronger influence on $s$ than "darker" ones. Additionally the sum of
+weights $n$ is updated using $n = n + w$. If $n$ overflows the \emph{weight
+threshold} $w_{max}$, the ray is terminated and the pixel value used in this
+position is $\frac{s}{n}$, otherwise the search for the next non-empty pixel
+continues. If there are no more non-empty pixels and the pixel value $\frac{s}{n}$
+computed so far is bigger than the lower pixel threshold, this pixel value is
+used, otherwise the pixel is considered transparent.\\
+Summarizing: $q$ determines how much the weight is correlated with the pixel
+value where small values of $q$ mean a strong dependence and large values
+a weak dependence (since
+$\lim_{q \longrightarrow \infty}{\vert \frac{v + 2^q - 1}{2^q} \vert} = 1$ and
+$\lim_{q \longrightarrow \infty}{\vert \frac{v}{2^q} \vert} = 0$, both of which
+are monotonous decreasing in $q$).
+The default value of 4 gives good results with most tomograms. The weight threshold
+$w_{max}$ determines how far the ray will penetrate into the volume. If that
+value is too small, normally invisible noise will prematurely abort the ray and
+thus have a noticable effect on the display (seemingly random, dark blotches instead
+of a smooth surface). Another problem is that typically the pixel colour doesn't
+change rapidly from one pixel to its neighbour but rather slowly over a number
+of pixels, so for instance a white object on a black background is usually surrounded
+by several layers of grey-level pixels. When $w_{max}$ is too small the ray will stop
+in those grey-levels rather than in the white object. Trying to remedy this by just increasing
+the lower pixel threshold doesn't work well and even with large values the results
+still look poor. So if you can't see far enough into the cube you should first try
+increasing $w_{max}$. If $w_{max}$ is too large, on the other hand, you get an x-ray
+effect where the entire object becomes transparent. Also note that the further the
+ray penetrates into the volume the longer the rendering takes.\\
+If you're using lighting there are some more tuning parameters available from the
+\texttt{Image settings} window in the voxel section which deal with normal approximation,
+namely \texttt{Kernel size} and \texttt{Kernel type}. The kernel is a symmetric
+function that will be folded with the sample values, thus producing a smoothed
+normal vector that can compensate for sample noise. The kernel type determines how
+this smoothing is performed. \texttt{Average} gives each sample the same weight, the other
+two are functions over the distance $d$ (L$_2$-norm) of a cell from the kernel center.
+\texttt{Linear} is the function $1 - \frac{d}{s \sqrt{3}}$ and \texttt{Gauss} is the function
+$e^{-\frac{d}{2}}$ where $s$ is the kernel size.\\
+The kernel size parameter is the maximum distance of a point in the kernel from the
+kernel center using the L$_{\infty}$ norm. Therefore a kernel size of $n$ results in a
+kernel cube of size $(2n + 1)^3$. A kernel size of 0 means no smoothing (and hence the
+kernel type is irrelevant), the normal is approximated directly from the sample values,
+therefore this mode produces very bad results with noisy data. For typical samples a
+kernel size of 1 or 2 is much more recommended, although the rendering will take
+substantially longer due to the kernel cube's size (27 cells for a kernel size of 1,
+125 cells for a kernel size of 2). In theory the normal vectors could be cached, however
+this would require 12 bytes of storage for each cell, so a greyscale tomogram of size
+10MB would require 120MB for the normal vector field which seems excessive.\\
+One problem when shading volumetric data is that the entire image tends to darken
+considerably. This is a problem especially when plotting isosurfaces. To overcome
+this limitation there's the option to ignore the voxel colours and assign the same
+intensity to each voxel instead, which should be a bright colour (e.g.\ white); in this case
+the sample values are only used to approximate the object's surface but not for texturing
+it as well. Of course this only makes sense when shading is active since otherwise only
+the object's outline could be seen, therefore this option is ignored with lighting
+deactivated. The colour to assign to each voxel can be specified in the \texttt{Voxel colour}
+field; this is a floating point number in order to be able to handle all base types.
+The default value of this parameter depends upon the setting of
+\texttt{For mode} in the preferences window (i.e.\ when on \rview\ tries to find a sensible
+default for the MDD's base type). A value of 255 for a greyscale image is pure white,
+for instance. A more complicated example is RGB: in that case the colour is encoded as
+a number with the red component in bits 0-7, the green component in bits 8-15
+and the blue component in bits 16-23, so red is 255, green is 65280, blue is
+16711680 and pure white (the default) is 16777215. Alternatively you can specify
+the voxel colour as a hexadecimal value starting with a \texttt{0x} prefix which is
+easier for selecting RGB colours (e.g.\ \texttt{0xff00} for green).\\
+\emph{Tuning}: bad image quality when rendering with lighting is usually the cause of the
+kernel size being too small or the pixel/weight threshold values being wrong. If the
+ray doesn't penetrate deep enough you get the aliasing effects described above. If
+on the other hand the ray penetrates too deep the surface normal will get approximated
+wrongly because the ray terminated a substantial distance away from the actual surface.
+If the image is too dark you should try ignoring the voxel colour and using a very
+bright default colour instead. Only experimentation will result in the best compromise of all
+parameters.\\
+Examples:\\
+For \texttt{tomo\_cubed} use \texttt{pixelThresholdLow = 16}, \texttt{weightThreshold = 16} and
+\texttt{kernelSize = 2}. When ignoring the voxel colours set \texttt{lAngle = 180},
+\texttt{Ambient = 0} and \texttt{Gain = 0.5}. For \texttt{frog\_cubed} set \texttt{pixelThresholdLow = 32},
+\texttt{weightThreshold = 8} and \texttt{kernelSize = 2}. When ignoring the voxel colours set
+\texttt{lAngle = 180}, \texttt{Ambient = 0.0} and \texttt{Gain = 0.0}.
+
+
+\subparagraph{Orthosection renderer} \label{ImageModeOrtho}
+\ \\
+This viewer mode renders volume images as three orthogonal sections through the
+volume, as commonly used in the visualization of medical images. The resulting
+image can be rotated and translated along the z-axis by using the mouse like in
+the other rendered modes.\\
+This viewer comes in two variants, depending on how it's opened:
+
+\begin{description}
+\item[partial:] when opened from the main window's \emph{Collections} menu
+(see \ref{MainWindow}); in this mode only the data for the three sections currently
+visible is held in main memory and new data is loaded from the database
+when required (but not during a drag operation).
+\item[full:] when opened from the results window (see \ref{ResultWindow}); in
+this mode the data for the entire MDD is present in main memory and therefore
+sections can be changed arbitrarily without requiring further database accesses.
+\end{description}
+
+For both modes there are several new widgets in the control area:
+
+\begin{itemize}
+\item
+For each of the three dimensions there's a slider representing the position where each
+hyperplane intersects the axis orthogonal to it. To the right of the slider is a
+text widget where positions can be entered manually. As soon as the mouse pointer
+touches the slider's well (that area within which the bar slides), the section it
+represents is crossed out in the display to facilitate navigation; the cross is
+removed when the mouse pointer leaves the well. The slider is dragged as usual
+by holding down the left (or right) mouse button. Depending on the mode (\emph{partial}
+or \emph{full}), the dragged section is displayed as a solid grey area or the actual
+image data.
+\item
+Towards the bottom right is a text widget labelled \emph{Thick} where the thickness
+of a section in cells can be entered. Note that the handling of thick sections is
+not optimized in any way and in case the viewer is used in partial mode the cells
+intersected by several sections are loaded from the database for each slice, leading
+to an expansion of the data volume transferred by a factor of 3 in the worst case
+(although the amount of overlap is neglectable for thin slices). If you want to
+work with thick sections extensively, use the viewer in \emph{full} mode.
+\item
+Below the thickness widget are two more widgets labelled \emph{Auto} and
+\emph{Load}. These determine how the display is updated in partial mode
+when sections have changed. Dragging a section in partial mode displays
+the section as a filled grey surface to show that the cell values are
+unknown. If \emph{Auto} is checked, the new section is automatically loaded
+from the database after the mouse button used to drag the slider is released,
+otherwise the display is not updated automatically. The \emph{Load} button can
+be used to explicitly request an update at any time; this is necessary in case
+\emph{Auto} isn't checked or the database was closed during the drag and the
+new data couldn't be loaded when the mouse button was released.
+\end{itemize}
+
+\textbf{Current limitations of the Partial mode:}
+\begin{itemize}
+\item
+There is no section cache, so moving the slider will always access the database,
+no matter whether the sections were already loaded at an earlier time in the session.
+\item
+Colourspace mapping in any but \emph{type range} mode is problematic because due to
+the partial character, there is no information about the value range of the entire
+MDD, so some defaults are assumed. This can be easily remedied manually by opening
+the colourspace editor and entering min/max values to use for the translation, but
+it isn't done automatically yet; automatic updates could also lead to unwanted
+side-effects because if a new slice changed the min/max values currently used,
+the colours of the other two sections would be affected as well.
+\end{itemize}
+
+
+
+\paragraph{Height field renderer} \label{HeightFieldRenderer}
+\ \\
+This mode can be used on data of any dimensionality $d$ with an atomic base type. It
+performs a mapping of the form $y_i = f(x_{1,i}, \ldots, x_{d,i})$ where all but two
+of the $x_{j,i}$ are constant, namely $x_{m,i}$ and $x_{n,i}$ (i.e.\ $m$ and $n$ are
+free dimensions as described in \ref{ObjectViewers} and have to be given by the
+projection string). In other words the value of the cell at position
+$(x_{1,i}, \ldots, x_{d,i})$ is interpreted as height information.
+When connecting all the vertices $(x_{m,i},y_i,x_{n,i})$
+thus obtained, a surface in 3D space is created which is rendered using shaded
+polygons, the colour of which can be set via \texttt{VoxelColour} (see the
+\texttt{Image settings} window). Note that this field also accepts hexadecimal
+numbers starting with a \texttt{0x} prefix. If the value of the colour is less then
+256 it will be interpreted as a grey level, otherwise a colour of the form
+\texttt{0xbbggrr}. You can force RGB mode on by setting bit 24 of the colour
+value (required for pure reds). Forcing on RGB mode overrides colourspace mapping,
+if it was turned on.\\
+A primitive light model is always used, namely $pixel = colour \cdot \frac{cos(\alpha)+1}{2}$
+where $\alpha$ is the angle between the surface normal and the light source. When
+switching on lighting the full lighting model described in section \ref{RendererModel} is used.
+Further options for this mode are the grid size $g$ and the height scaling factor $s$
+which are used to create the set of surface vertices
+$S = \lbrace (i \cdot g, j \cdot g, s \cdot m(i,j) \quad \vert \quad l_0 \le i \le h_0, l_1 \le j \le h_1 \rbrace$
+where $m$ is the given 2D projection with the domain $\lbrack l_0:h_0, l_1:h_1 \rbrack$
+of the original nD data $M$ ($m \subseteq M$).\\
+You can also do animations with this mode when the dimensionality of the MDD object
+is higher than 2. Using the movie playback buttons (or +/-) you can slice through the
+data like in \texttt{flat} mode, but with a different rendering technique.\\
+This mode should not be used on large data sets because the number of polygons to render
+is $2 (h_0 - l_0) (h_1 - l_1)$, so even a moderately sized image containing 512*512
+pixels would result in over half a million polygons which take several seconds to
+render. As a general rule of thumb a size of 100*100 should not be exceeded (which
+still requires about 20000 polygons). In case of bigger data it's recommended to scale
+it down prior to using the height field renderer, e.g.\ by using the scaling functionality
+provided in the \texttt{Results Window} (\ref{ResultWindow}).
+
+
+\subsubsection{Colourspace mapping}
+\label{ColourspaceMapping}
+
+Colourspace mapping can be used for visualizing MDD objects of all atomic base types.
+The idea is to map an object's data $d$ of the data type $D$ with a potentially very
+large range to the RGB colour space using a function $f_{cm}: D \rightarrow (r,g,b)$,
+often with the restriction that small changes in the object values result in small
+changes of the resulting colour, i.e.\ for a given $C \in \realnumbers$
+
+$$\| f_{cm}(v_2) - f_{cm}(v_1) \|_2 \le C \vert v_2 - v_1 \vert \qquad \forall v_1, v_2 \in d .$$
+
+This is achieved by using a transfer function $f_{tf}(x, \mu, \sigma)$ for each colour component
+that maps a number $x \in D$ to the interval $\lbrack 0, 1 \rbrack$ where $\mu$ is the
+position of the peak and $\sigma$ is the variation. The colourspace mapping is then
+described by the equation
+
+\begin{displaymath}
+f_{cm}(x) =
+\left( \begin{array}{c}
+r(x) \\ g(x) \\ b(x)
+\end{array} \right)
+=
+\left( \begin{array}{c}
+f_{tf}(x, \mu_r, \sigma_r) \\
+f_{tf}(x, \mu_g, \sigma_g) \\
+f_{tf}(x, \mu_b, \sigma_b) \\
+\end{array} \right) .
+\end{displaymath}
+
+In most cases it is desirable that $f_{tf}$ has a single, global maximum so a colour can
+be easily associated with an intensity range. These thoughts led to modelling the default
+transfer function $f^{gauss}_{tf}$. All in all there are four transfer functions available,
+but not all of them meet all the criteria mentioned above:
+
+\begin{itemize}
+\item
+$f^{gauss}_{tf}(x, \mu, \sigma) = e^\frac{-(x - \mu)^2}{\sigma^2}$\\
+a standard gaussian. In this case
+$C = \sqrt{\frac{6}{e}} \mbox{max}_{i \in \{r,g,b\}} \vert \frac{1}{\sigma_i} \vert$
+(see appendix \ref{CalculateC}). This function is symmetric, smooth and has a distinct
+peak.
+
+\item
+$f^{linear}_{tf}(x, \mu, \sigma) = \left\lbrace \begin{array}{rl}
+1 - \left|\frac{x - \mu}{\sigma} \right| & | x - \mu | < \sigma\\
+0 & \mbox{otherwise}\\
+\end{array} \right.$\\
+a triangular spike that can for instance be used to perform
+a mapping to greyscales directly proportional to the input value. The function
+is symmetric and has a distinct peak but isn't smooth.
+
+\item
+$f^{rect}_{tf}(x, \mu, \sigma) = \left\lbrace \begin{array}{rl}
+1 & | x - \mu | < \sigma\\
+0 & \mbox{otherwise}\\
+\end{array} \right.$\\
+a rectangular pulse in case quantisation effects are
+explicitly wanted. The function is symmetric, has an extended peak but is
+neither smooth nor continuous.
+
+\item
+$f^{asympt}_{tf}(x, \mu, \sigma) = \left\lbrace \begin{array}{rl}
+0 & x < \mu\\
+1 - e^\frac{-(x - \mu)}{\sigma} & \mbox{otherwise}
+\end{array} \right.$\\
+an asymmetric mapping function that starts at position
+$\mu$ and converges to 1 for $x \rightarrow \infty$. The function is smooth and
+continuous but asymmetric and without a peak.
+
+\end{itemize}
+
+You can choose the mapping function you wish by using the widget in the lower right
+of the colourspace mapping editor. It's quite easy to extend \rview\ to support
+many more mapping functions.\\
+The default values for the $\mu$ and $\sigma$ are
+
+$$\mu_r = max, \quad \mu_g = min + \frac{2(max-min)}{3}, \quad \mu_b = min + \frac{max-min}{3}
+\qquad \mbox{and}$$
+$$\sigma_r = \sigma_g = \sigma_b = \frac{max-min}{6 \sqrt{\ln 2}}$$
+
+where $max$ and $min$ can be either the extreme values present in the entire object
+(default), the extreme values the base type can represent (\texttt{Full range} on) or the
+extreme values that occur in the currently selected projection of the object (\texttt{Proj range}
+on). The default values of the $\sigma$-parameters are chosen in such a way that the sum of two
+neighbouring gaussians halfway between their mean values is 1, i.e.\ apart from areas of the
+input range that don't lie between two means the intensity doesn't change drastically.\\
+Colourspace mapping is available in Image and Thumbnail viewers (\ref{ImageDisplayMode},
+\ref{ThumbnailDisplayMode}). The parameters can be changed using the
+\texttt{Settings $\rightarrow$ Colourspace} menu which will become available once colourspace
+mapping has been enabled and results in the \texttt{Colourspace setup} window being opened.
+This window contains a canvas showing the three mapping functions that make up the normalized
+mapping function $f_{cm}^{norm}: \lbrack 0,1 \rbrack \rightarrow (r,g,b)$, each
+plotted in the colour it encodes. If \texttt{Draw sum} is checked the sum of the three
+mapping functions will also be plotted in black, scaled to $\frac{1}{3}$ the height of
+each of the mapping functions with the dotted line representing the value 1. The relation
+between $f_{cm}^{norm}$ and $f_{cm}$ is that $\mu_i = min + (max - min)*\mu_i^{norm}$ and
+$\sigma_i = (max - min)*\sigma_i^{norm}$ for $i \in \{r, g, b\}$.\\
+In the lower half of the
+window are widgets displaying the values of the $\mu_i^{norm}$ (E$(x)$), the
+$\sigma_i^{norm}$ (s$(x)$), $i \in \{r,g,b\}$ and the values of $max$ and $min$ currently
+used. Values can be changed by either entering the new values in the widgets directly
+and pressing \texttt{<return>} or by dragging the curves. For a drag the mouse pointer has
+to be close to the mean value of the curve you want to drag; if the curves are very close
+together, red takes precedence over green, which in turn takes precedence over blue.
+Holding down the left mouse button and moving left/right moves the function's mean value.
+Holding down the right mouse button and moving up/down increases/decreases the function's
+variance. The functions will be immediately redrawn to reflect your latest changes.\\
+If the \texttt{Update} checkbox in the lower half of the window is checked these changes
+will also be propagated to the viewer window owning this colourspace mapper. If this
+viewer's image is very big or the display mode very time-consuming (e.g.\ the Voxel
+renderer) this might take too long so it is advisable to disable the immediate update
+in these situations.\\
+Clicking \texttt{OK} makes the current setup permanent for this viewer and closes the
+\texttt{Colourspace setup} window. \texttt{Cancel} discards the changes, reverts the
+viewer to the state it had before editing and also closes the window.
+
+
+\subsection{Chart viewers}
+\label{ChartDisplayMode}
+
+This is a 1D mode that visualizes the data as a $(x, f(x))$ graph. There are three
+modes available from the \texttt{Modes} menu:
+
+\begin{description}
+\item[Bar:] Bar chart, every value is represented by a filled rectangle.
+\item[Line:] Consecutive values are connected by straight lines.
+\item[Spline:] The values are connected using spline interpolation, thereby
+making it a smooth curve.
+\end{description}
+
+\texttt{Chart} mode is available for all atomic base types. A special case is
+the RGB type where the three components are plotted slightly shifted against
+each other in their corresponding colours.\\
+\texttt{Step} is the width in pixels of two consecutive values on the horizontal
+axis, so larger values will stretch the graph horizontally; in \texttt{Bar} mode this
+is also the width of each bar. A coordinate system is plotted optionally, depending
+on the value of \texttt{CO-System}. In case a coordinate system is requested it can
+be configured in the following ways: \texttt{Y markers} is the step size of the markers
+on the vertical axis. Since the base type may be in a floating point format this is
+a floating point number. \texttt{X markers} does the same for the markers on the horizontal
+axis but is an integer number because all coordinates are integers. You have to press
+\texttt{<return>} in the corresponding widget for changes to have any effect.
+
+
+\subsection{Table viewers}
+\label{TableDisplayMode}
+
+This is a 2D mode that displays the data numerically. In contrast to the other display
+modes this one is totally independent of the base type and can display any MDD object
+for which schema information exists. The first free dimension is mapped to the horizontal,
+the second free dimension to the vertical axis by default. The current grid size in pixels
+is displayed as \texttt{Step X} and \texttt{Step Y}. If the default values given in the
+preferences (\ref{PreferencesEditor}) are -1, \rview\ will
+make a guess at the grid size based on font size and base type. The grid size can
+be changed by explicitly entering new values into the corresponding widgets and
+pressing \texttt{<return>}. If \texttt{CO-System} is checked the coordinate system will
+be displayed.\\
+There are three number bases available from the \texttt{Base} menu: \texttt{Decimal}, \texttt{Octal}
+and \texttt{Hex}. The grid size will be adapted automatically if the default grid size
+was -1. \texttt{Octal} and \texttt{Hex} are also available for floating point types; in
+the case of a \texttt{double} base type the format is two numbers separated by a colon.
+
+
+\subsection{Sound viewers}
+\label{SoundDisplayMode}
+
+This is a 1D mode that can play digital sound samples. 2D data is allowed and will
+be interpreted as multichannel sound where the second free dimension describes the
+channels. There are six buttons for controlling playback. The meaning of each, from left
+to right, is:
+
+\begin{description}
+\item[{\boldmath $\ll$}] Set playback position to start
+\item[{\boldmath $\|$}] Pause/resume playback
+\item[{\boldmath $>$}] Start playback (from beginning)
+\item[{\boldmath $\lbrack\rbrack$}] Stop playback
+\item[{\boldmath $\gg$}] Set playback position to end
+\item[{\boldmath $\longrightarrow$ \mbox{\rm or} $\longleftrightarrow$}] Toggle between normal and looped playback. When in
+loop mode the sample will be repeated indefinitely (until loop mode is switched off
+or playback is stopped manually).
+\end{description}
+
+Below these playback controls are options concerning the sample format and the latency.
+Enter the \texttt{Frequency} in Hz in the writable field to the left. Standard sample frequencies
+are 8000Hz, 11025Hz, 22050Hz, 44100Hz and 48000Hz and the sound hardware may have trouble
+handling anything else. The \texttt{Format} widget can be used to specify the sample format.
+You can only select formats where the size of a sample is the same as the size of the MDD
+base type. Currently four formats are supported:
+
+\begin{description}
+\item[8 bit sl:] 8 bit signed linear, sample midpoint is at \texttt{0x00}
+\item[8 bit usl:] 8 bit unsigned linear, sample midpoint is at \texttt{0x80}
+\item[8 bit ulaw:] 8 bit $\mu$-law (a logarithmic format used e.g.\ in ISDN)
+\item[16 bit sl:] 16 bit signed linear, sample midpoint is at \texttt{0x0000}
+\end{description}
+
+The \texttt{Latency} widget determines how many samples will be created ahead of the
+actual playback. Small values have the advantage that playback reacts to user
+input with no noticeable delays; however they make playback very vulnerable to
+jitter in the buffer fill code which will be most noticeable on a machine
+under load, leading to audible dropouts. Large values have the advantage of
+being very stable regarding dropouts but are slow to react to user input
+(i.e.\ the sound will keep playing a little after a stop or pause). A good compromise
+is usually between 100ms and 300ms, depending on the machine and its load.\\
+The slider at the bottom of the window represents the position of the currently
+audible signal in the sample. You can also drag it to an arbitrary position during
+playback to set the playback position there. Like with stop and pause there will
+be a small delay between the dragging and the playback actually changing due to
+latency.
+
+
+\subsection{Thumbnail viewers}
+\label{ThumbnailDisplayMode}
+
+This mode is unusual in that it can contain images of any number of objects as well
+as a series of images created from one object. By default one thumbnail image of each object
+is displayed, scaled to be \texttt{Thumbnail width} pixels wide while maintaining the
+aspect ratio (i.e.\ an object of size 400*600 and a thumbnail width of 100 will result
+in a thumbnail image of 100*150 pixels). It's also possible to restrict the thumbnails
+to part of the objects using the projection string (e.g.\ \texttt{30:70, 20:80} instead
+of \texttt{*:*, *:*}). \texttt{Thumbnail width} may have any value between 10 and 2000, so
+in most cases it can be used to produce magnified views as well as small thumbnails.
+\texttt{Thumbnail columns} specifies how many thumbnails should be fitted on one
+row.\\
+Objects with more than two dimensions can also be displayed as a series of thumbnails,
+similar to the movie mode in the image viewers (see \ref{ImageDisplayMode}). In order
+to do this the number of free dimensions has to be three, where two are needed for the
+image and one for the dimension to iterate over. By default the first two free
+dimensions are used for the image and the third for the iteration. This behaviour
+can be changed by setting \texttt{ProjDim} to the number of the dimension that should
+be iterated over, starting from 0 (e.g.\ with a projection string of
+\texttt{10:100, *:*, 5, 1:*} the default dimension to iterate over is described by
+\texttt{1:*}, setting \texttt{ProjDim} to 1 would change that to \texttt{*:*}). The iteration
+step can be set using \texttt{ProjStep}; this is the number the coordinate of the
+iteration dimension should be incremented by after each thumbnail image. The larger
+this number the fewer thumbnails will be created for each object.\\
+Beneath each thumbnail is a small descriptive text of the form \texttt{MDD \textsl{mdd}
+\lbrack \textsl{view} \rbrack} where \textsl{mdd} is the number of the MDD object in
+the same order as listed in the results window (\ref{ResultWindow}), starting from 0,
+and \textsl{view} is the number of the view in case the object was displayed as a series
+of thumbnails. Note that \texttt{ProjStep} will also be reflected by \textsl{view}.\\
+Thumbnail viewers also provide colourspace mapping for objects of atomic base types
+(\ref{ColourspaceMapping}); use and configuration is identical to image viewers
+(\ref{ImageDisplayMode}) but due to the nature of the thumbnail mode as a container
+of many objects, \texttt{Proj range} is not available.
+
+
+\section{Platform specifics}
+\label{Platforms}
+
+\subsection{Unix}
+
+\begin{itemize}
+\item
+Changing the font to use for query windows (\ref{QueryWindow}) has no effect. This is
+a bug of the X-version of \wxwin.
+\end{itemize}
+
+\subsection{NT}
+
+\begin{itemize}
+\item
+Exiting \rview\ with an open database crashes the program.
+\end{itemize}
+
+
+\hrule
+
+
+% Appendix
+\newpage
+
+\begin{appendix}
+
+\section{Colourspace mapping smoothness constant C}
+\label{CalculateC}
+
+Let $g_i(x) = e^{-\frac{(x - \mu_i)^2}{\sigma_i^2}}, \quad i \in \{r,g,b\}$. Then
+
+$$\| f_{cm}(v_2) - f_{cm}(v_1) \|_2 = \sqrt{\sum\limits_{i \in \{r,g,b\}} (g_i(v_2) - g_i(v_1))^2}$$
+
+According to the mean value theorem $g_i(v_2) - g_i(v_1) = g'_i(\xi) (v_2 - v_1), \quad
+\xi \in \lbrack v_1, v_2 \rbrack$, so the above can be rewritten to
+$$\sqrt{\sum\limits_{i \in\{r,g,b\}} (g'_i(\xi_i)(v_2 - v_1))^2} \le
+\sqrt{3} \cdot \vert g'_{max} \vert \cdot \vert v_2 - v_1 \vert, \quad
+\mbox{i.e.} \quad C = \sqrt{3} \cdot \vert g'_{max} \vert \quad$$
+$$\mbox{where} \quad \vert g'_{max} \vert = \mbox{max}_{i \in \{r,g,b\}, x \in \realnumbers} \vert g'_i(x) \vert.$$
+
+$g'_i(x) = -2\frac{x - \mu_i}{\sigma_i^2} g_i(x)$ and
+$g''_i(x) = -\frac{2}{\sigma_i^2} g_i(x) + 4\frac{(x - \mu_i)^2}{\sigma_i^4}g_i(x) =
+\frac{2}{\sigma_i^2} g_i(x) (2\frac{(x - \mu_i)^2}{\sigma_i^2} - 1)$. $g'_i(x)$ has
+a local extreme value where $g''_i(x) = 0$,
+i.e.\ $2\frac{(x - \mu_i)^2}{\sigma_i^2} = 1 \Longleftrightarrow x_{0,1} = \mu_i \pm \frac{\sigma_i}{\sqrt{2}}.$
+Due to the symmetry $\vert g'_i(\mu_i + x) \vert = \vert g'_i(\mu_i - x) \vert$ it suffices to
+examine the value of $g'_i(x)$ on one of these points only, e.g.\ $x_0 = \mu_i + \frac{\sigma_i}{\sqrt{2}}$:
+$\vert g'_i(x_0) \vert = \vert \frac{\sqrt{2}}{\sigma_i} e^{-\frac{1}{2}} \vert =
+\sqrt{\frac{2}{e}} \vert \frac{1}{\sigma_i} \vert$. Therefore the solution to the problem is
+$C = \sqrt{\frac{6}{e}} \mbox{max}_{i \in \{r,g,b\}} \vert \frac{1}{\sigma_i} \vert$.
+
+\end{appendix}
+
+\end{document}
diff --git a/applications/rview/rviewApp.cpp b/applications/rview/rviewApp.cpp
new file mode 100644
index 0000000..b0323c3
--- /dev/null
+++ b/applications/rview/rviewApp.cpp
@@ -0,0 +1,828 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+ * PURPOSE:
+ *
+ * rView main application (class rView) and main frame (class rviewMainFrame).
+ * The main application includes the database object which has to be accessed
+ * through rView-member functions.
+ *
+ * COMMENTS:
+ * none
+ */
+
+
+
+#ifdef __GNUG__
+#pragma implementation
+#endif
+
+
+// changed in wxWindows 2.4.2:
+//#include "wx_prec.h"
+#include <wx/wxprec.h>
+
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+
+#ifndef WX_PRECOMP
+#include "wx/wx.h"
+#endif
+
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <iostream.h>
+#include <signal.h>
+#include <ctype.h>
+
+
+#include "labelManager.hh"
+
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#endif
+
+
+#include "raslib/rminit.hh"
+#include "raslib/rmdebug.hh"
+
+#include "rviewApp.hh"
+#include "rviewDb.hh"
+#include "rviewPrefs.hh"
+//#include "rviewQuery.hh"
+#include "rviewIO.hh"
+#include "rviewDModes.hh"
+#include "rviewOSection.hh"
+
+
+
+
+
+/*
+ * Class for the lookup of scaled images, used internally only
+ */
+
+class rviewLookScaleDialog: public rviewFrame
+{
+ public:
+
+ rviewLookScaleDialog(rmanClientApp *parentApp, const char *name, double scale);
+ ~rviewLookScaleDialog(void);
+
+ void label(void);
+ int process(wxObject &obj, wxEvent &evt);
+ void OnSize(int w, int h);
+
+ // constants
+ static const int lkscale_border;
+ static const int lkscale_theight;
+ static const int lkscale_bwidth;
+ static const int lkscale_bheight;
+ static const int lkscale_width;
+ static const int lkscale_height;
+
+
+ protected:
+
+ wxPanel *panel;
+ rviewText *collName;
+ rviewText *scaleString;
+ rviewButton *okBut;
+ rviewButton *cancelBut;
+
+ rmanClientApp *parent;
+};
+
+
+const int rviewLookScaleDialog::lkscale_border = 8;
+const int rviewLookScaleDialog::lkscale_theight = 50;
+const int rviewLookScaleDialog::lkscale_bwidth = 50;
+const int rviewLookScaleDialog::lkscale_bheight = 30;
+const int rviewLookScaleDialog::lkscale_width = 300;
+const int rviewLookScaleDialog::lkscale_height = 2*rviewLookScaleDialog::lkscale_border + 2*rviewLookScaleDialog::lkscale_theight + rview_window_extra_height;
+
+
+rviewLookScaleDialog::rviewLookScaleDialog(rmanClientApp *parentApp, const char *name, double scale) : rviewFrame(NULL, lman->lookup("titleLookScaleColl"), -1, -1, lkscale_width, lkscale_height)
+{
+ panel = new wxPanel(this, 0, 0, lkscale_width, lkscale_height);
+ panel->SetLabelPosition(wxVERTICAL);
+ collName = new rviewText(panel, name);
+ scaleString = new rviewText(panel, scale);
+ okBut = new rviewButton(panel);
+ cancelBut = new rviewButton(panel);
+ parent = parentApp;
+ label();
+
+ frameWidth=-1;
+ frameHeight=-1;
+
+ OnSize(lkscale_width, lkscale_height);
+ OnSize(lkscale_width, lkscale_height);
+
+ Show(TRUE);
+}
+
+rviewLookScaleDialog::~rviewLookScaleDialog(void)
+{
+}
+
+void rviewLookScaleDialog::OnSize(int w, int h)
+{
+ int x, y, aux, boff;
+
+ GetClientSize(&x, &y);
+ panel->SetSize(0, 0, x, y);
+ aux = x - 3*lkscale_border - lkscale_bwidth;
+ collName->SetSize(lkscale_border, lkscale_border, aux, lkscale_theight);
+ scaleString->SetSize(lkscale_border, lkscale_border + lkscale_theight, aux, lkscale_theight);
+ aux += 2*lkscale_border;
+ boff = lkscale_border + lkscale_theight - lkscale_bheight;
+ okBut->SetSize(aux, boff, lkscale_bwidth, lkscale_bheight);
+ cancelBut->SetSize(aux, boff + lkscale_theight, lkscale_bwidth, lkscale_bheight);
+}
+
+void rviewLookScaleDialog::label(void)
+{
+ SetTitle(lman->lookup("titleLookScaleColl"));
+ collName->SetLabel(lman->lookup("lkScaleName"));
+ scaleString->SetLabel(lman->lookup("lkScaleScale"));
+ okBut->SetLabel(lman->lookup("textOK"));
+ cancelBut->SetLabel(lman->lookup("textCancel"));
+}
+
+int rviewLookScaleDialog::process(wxObject &obj, wxEvent &evt)
+{
+ int type = evt.GetEventType();
+ int readAndClose=0;
+
+ if (type == wxEVENT_TYPE_TEXT_ENTER_COMMAND)
+ readAndClose = 1;
+ else if (type == wxEVENT_TYPE_BUTTON_COMMAND)
+ {
+ if (&obj == (wxObject*)okBut)
+ readAndClose = 1;
+ else if (&obj == (wxObject*)cancelBut)
+ {
+ parent->LookupScaledCollection(NULL, 0.0);
+ Close(TRUE);
+ return 1;
+ }
+ }
+ if (readAndClose != 0)
+ {
+ double scale;
+ char *b, *rest;
+
+ b = scaleString->GetValue();
+ scale = strtod(b, &rest);
+ if (b == rest)
+ {
+ cerr << "Bad scaling parameter..." << endl;
+ }
+ else
+ {
+ parent->LookupScaledCollection(collName->GetValue(), scale);
+ Close(TRUE);
+ }
+ return -1;
+ }
+ return 0;
+}
+
+
+
+
+
+//#define DUMMY_MDD_OBJECT r_UShort
+
+//FILE *logfile; // WIN32 debug!!!
+
+
+// Emergency exit signal handler
+void rmanAbort(int code)
+{
+ char *sig;
+
+ // First things first
+ rmanClientApp::theApp()->Shutdown();
+
+ switch (code)
+ {
+ case SIGINT: sig = "SIGINT"; break;
+ case SIGABRT: sig = "SIGABRT"; break;
+ case SIGSEGV: sig = "SIGSEGV"; break;
+ case SIGFPE: sig = "SIGFPE"; break;
+#ifndef __VISUALC__
+ case SIGBUS: sig = "SIGBUS"; break;
+#endif
+ default: sig = "SIG?"; break;
+ }
+
+ cerr << "Aborted " << code << " (" << sig << " )" << endl;
+ //fprintf(logfile, "Aborted (%s)\n", sig);
+
+ exit(-1);
+}
+
+
+/*
+ * A RasDaMan client application using wxWindows. This can be used as base class
+ * to other RasDaMan apps as well.
+ */
+
+rmanClientApp *rmanClientApp::theclientapp = NULL;
+
+const char *rmanClientApp::vffFileName = "vff-file";
+
+rmanClientApp::rmanClientApp(const char *homevar, const char *prefsname, const char *labelname)
+{
+ char *rvh;
+ char *b;
+#ifdef __VISUALC__
+ char *d;
+#endif
+ char labels[STRINGSIZE];
+
+ theclientapp = this;
+
+ //logfile = fopen("rview.log", "w");
+
+ rvh = getenv(homevar);
+
+ // labels.txt is looked for in $RVIEWHOME or failing that .
+ if (rvh == NULL)
+ sprintf(homeDir, ".");
+ else
+ sprintf(homeDir, "%s", rvh);
+
+ sprintf(labels, "%s"DIR_SEPARATOR"%s", homeDir, labelname);
+
+ lman = new labelManager(labels);
+
+ frameManager = new rviewFrameMgr();
+
+ rviewInitCharacterTables();
+
+ strcpy(prefsFileLeafname, prefsname);
+
+ // Preferences are looked for in $HOME, ., $RVIEWHOME
+#ifdef __VISUALC__
+ if (((b = getenv("HOMEDRIVE")) != NULL) && ((d = getenv("HOMEPATH")) != NULL))
+ sprintf(prefsFile, "%s%s", b, d);
+#else
+ if ((b = getenv("HOME")) != NULL)
+ sprintf(prefsFile, "%s", b);
+#endif
+ else
+ strcpy(prefsFile, ".");
+
+ // always save prefs to $HOME/.rviewrc
+ sprintf(prefsSaveFile, "%s"DIR_SEPARATOR"%s", prefsFile, prefsname);
+
+ if (!findPreferencesOnPath(prefsFile))
+ {
+ strcpy(prefsFile, ".");
+ if (!findPreferencesOnPath(prefsFile) && (rvh != NULL))
+ {
+ strcpy(prefsFile, homeDir);
+ findPreferencesOnPath(prefsFile);
+ }
+ }
+
+ if (prefsFile[0] == 0)
+ {
+ cerr << "Couldn't find any preferences files." << endl;
+ cout << "New prefs will be written to " << prefsSaveFile << endl;
+ }
+
+ prefs = new rviewPrefs(prefsFile);
+
+ // Install signal handlers (open databases are ANNOYING!)
+ signal(SIGILL, (void(*)(int))rmanAbort);
+ signal(SIGINT, (void(*)(int))rmanAbort);
+#if !defined(RMANDEBUG)
+ signal(SIGABRT, (void(*)(int))rmanAbort);
+ signal(SIGSEGV, (void(*)(int))rmanAbort);
+#endif
+ signal(SIGFPE, (void(*)(int))rmanAbort);
+#ifndef __VISUALC__
+ signal(SIGBUS, (void(*)(int))rmanAbort);
+#endif
+}
+
+
+rmanClientApp::~rmanClientApp(void)
+{
+ delete lman; lman = NULL;
+ delete frameManager; frameManager = NULL;
+ theclientapp = NULL;
+ rviewIO::terminate();
+ //prefs->save(prefsSaveFile);
+ //fclose(logfile);
+}
+
+
+bool rmanClientApp::findPreferencesOnPath(char *path)
+{
+ sprintf(path + strlen(path), DIR_SEPARATOR"%s", prefsFileLeafname);
+ if (::wxFileExists(path)) return TRUE;
+ path[0] = 0; return FALSE;
+}
+
+
+int rmanClientApp::SavePreferences(void) const
+{
+ return prefs->save(prefsSaveFile);
+}
+
+
+rmanClientApp *rmanClientApp::theApp(void)
+{
+ return theclientapp;
+}
+
+
+bool rmanClientApp::ReadDBState(void)
+{
+ return database.isOpen();
+}
+
+
+
+
+/*
+ * Called when something crashes.
+ */
+void rmanClientApp::Shutdown(void)
+{
+ if (database.isOpen())
+ {
+ database.close();
+ }
+}
+
+
+
+
+int rmanClientApp::OpenServer(const char *srvname, int srvport, const char *dbname,
+ const char *usrname, const char *usrpassword)
+{
+ if (database.isOpen())
+ return -1;
+
+ RMDBGONCE(3, RMDebug::module_applications, "rviewApp", "OpenServer( " << srvname << ", " << dbname << "," << usrname << "," << usrpassword << " )" );
+
+ if (database.open(srvname, srvport, dbname, usrname, usrpassword) != 0)
+ {
+ user_event ue;
+
+ ue.type = usr_db_opened;
+ if (frameManager != NULL)
+ frameManager->broadcastUserEvent(ue);
+
+ return 0;
+ }
+ return -1;
+}
+
+
+int rmanClientApp::CloseServer(void)
+{
+ if (!database.isOpen())
+ return -1;
+
+ user_event ue;
+
+ database.close();
+ ue.type = usr_db_closed;
+
+ if (frameManager != NULL)
+ frameManager->broadcastUserEvent(ue);
+
+ RMDBGONCE(3, RMDebug::module_applications, "rviewApp", "CloseServer() Database closed." );
+
+ return 0;
+}
+
+
+
+rviewFrame *rmanClientApp::OpenFile(unsigned int flags, r_Ref<r_GMarray> *newMddObj, bool resultwin)
+{
+ char *s;
+ char *prefPath = (char*)(prefs->filePath.ptr());
+
+ s = wxFileSelector(lman->lookup("loadFile"), (::wxDirExists(prefPath)) ? prefPath : NULL , NULL, NULL, "*");
+
+ if (s)
+ {
+ int status;
+ r_Ref<r_GMarray> mddPtr;
+
+ RMDBGONCE(3, RMDebug::module_applications, "rviewApp", "OpenFile(...) " << s );
+
+ prefs->filePath = ::wxPathOnly(s);
+ prefs->markModified();
+
+ // load TIFF
+ if (rviewIO::isTIFF(s))
+ {
+ status = rviewIO::loadTIFF(s, mddPtr, prefs->vffParams.ptr());
+ if (status == RVIEW_IO_OK)
+ {
+ rviewDisplay *newImage;
+ mdd_frame mddObj;
+ // receiver makes a copy.
+ mddObj.mdd = mddPtr; mddObj.flags = 0;
+ newImage = new rviewFlatImage(&mddObj, flags | rviewDisplay::display_flag_standalone);
+ if (newMddObj != NULL) *newMddObj = mddPtr;
+ if (newImage->openViewer() != 0)
+ {
+ delete newImage; newImage = NULL;
+ }
+ return newImage;
+ }
+ }
+ // load VFF -- whether this is supported is sorted out in rviewIO.cpp
+ else if (rviewIO::isVFF(s))
+ {
+ status = rviewIO::loadVFF(s, mddPtr, prefs->vffParams.ptr());
+ if (status == RVIEW_IO_OK)
+ {
+ if (resultwin)
+ {
+ // load in results window
+ rviewResult *result;
+ const char *file = ::wxFileNameFromPath(s);
+
+ collection_desc *cdesc = new collection_desc;
+ cdesc->collName = new char[strlen(file)+1];
+ strcpy(cdesc->collName, file);
+ cdesc->collType = new char[strlen(mddPtr->get_type_name())+1];
+ strcpy(cdesc->collType, mddPtr->get_type_name());
+ cdesc->collInfo = new char[strlen(vffFileName)+1];
+ strcpy(cdesc->collInfo, vffFileName);
+ cdesc->number = 1;
+ cdesc->mddObjs = new mdd_frame[1];
+ cdesc->strObjs = NULL;
+ cdesc->mddObjs[0].mdd = mddPtr;
+ cdesc->mddObjs[0].flags = 0;
+
+ result = new rviewResult(cdesc);
+ return result;
+ }
+ else
+ {
+ // load in default viewer
+ rviewDisplay *newImage;
+ mdd_frame mddObj;
+ mddObj.mdd = mddPtr; mddObj.flags = 0;
+ newImage = new rviewVolumeImage(&mddObj, flags | rviewDisplay::display_flag_standalone);
+ if (newMddObj != NULL) *newMddObj = mddPtr;
+ if (newImage->openViewer() != 0)
+ {
+ delete newImage; newImage = NULL;
+ }
+ return newImage;
+ }
+ }
+ }
+ }
+ return (rviewFrame*)NULL;
+}
+
+
+int rmanClientApp::LookupCollection(void)
+{
+ collection_desc *desc;
+ char *name;
+
+ name = ::wxGetTextFromUser(lman->lookup("promptEnterColl"), lman->lookup("titleCollLook"), (char*)(prefs->lastColl.ptr()));
+
+ if (name == NULL) return 0;
+
+ if ((desc = new collection_desc) == NULL)
+ {
+ cerr << lman->lookup("errorMemory") << endl;
+ return 0;
+ }
+ memset(desc, 0, sizeof(collection_desc));
+
+ if ((desc->collName = new char [strlen(name) + 1]) == NULL)
+ {
+ cerr << lman->lookup("errorMemory") << endl;
+ delete desc;
+ return 0;
+ }
+
+ strcpy(desc->collName, name);
+ prefs->lastColl = name;
+ prefs->markModified();
+
+ RMDBGENTER(3, RMDebug::module_applications, "rviewApp", "LookupCollection() " << desc->collName );
+
+#ifdef DUMMY_MDD_OBJECT
+ desc->number = 1;
+ r_Minterval iv(3);
+ iv << r_Sinterval(r_Range(0),r_Range(300)) << r_Sinterval(r_Range(200),r_Range(400)) << r_Sinterval(r_Range(10), r_Range(12));
+ desc->mddObjs = new mdd_frame[1];
+ desc->mddObjs[0].mdd = (r_Ref <r_GMarray>) new r_Marray<DUMMY_MDD_OBJECT>(iv);
+ desc->collType = new char[16]; strcpy(desc->collType, "r_UShort");
+ r_Ref < r_Marray < DUMMY_MDD_OBJECT > > mddPtr = (r_Ref < r_Marray < DUMMY_MDD_OBJECT > >) desc->mddObjs[0].mdd;
+ mddPtr->set_type_by_name("UShortImage");
+ r_Point point(3);
+ cout << mddPtr->spatial_domain() << endl;
+ for (point[0]=0; point[0]<=300; point[0]++)
+ for (point[1]=200; point[1]<=400; point[1]++)
+ for (point[2]=10; point[2]<=12; point[2]++)
+ (*mddPtr)[point] = ((DUMMY_MDD_OBJECT)(point[0] + point[1] + point[2])) << (8*(sizeof(DUMMY_MDD_OBJECT) - 1));
+
+ if (1)
+#else
+ if (database.lookupCollection(desc) != 0)
+#endif
+ {
+
+ RMDBGEXIT(3, RMDebug::module_applications, "rviewApp", "LookupCollection() OK." );
+
+ /*for (int i=0; i<desc->number; i++)
+ {
+ cout << "Object #" << i << ": " << desc->mddArrays[i]->spatial_domain() << endl;
+ }*/
+
+ rviewResult *result = new rviewResult(desc);
+
+ return 1;
+ }
+ else
+ {
+ rviewDeleteCollection(desc);
+ }
+
+ RMDBGEXIT(3, RMDebug::module_applications, "rviewApp", "LookupCollection() FAILED." );
+ return 0;
+}
+
+
+int rmanClientApp::LookupScaledCollection(void)
+{
+ rviewLookScaleDialog *lsd = new rviewLookScaleDialog(this, (char*)(prefs->lastScColl.ptr()), prefs->imgScale);
+
+ return 0;
+}
+
+int rmanClientApp::LookupScaledCollection(const char *name, double scale)
+{
+ if (name != NULL)
+ {
+ collection_desc *desc;
+
+ RMDBGENTER(3, RMDebug::module_applications, "rviewApp", "LookupScaledCollection( " << name << " at scale " << scale << " )");
+
+ prefs->imgScale = scale;
+
+ if ((desc = new collection_desc) == NULL)
+ {
+ cerr << lman->lookup("errorMemory") << endl;
+ return 0;
+ }
+ memset(desc, 0, sizeof(collection_desc));
+
+ if ((desc->collName = new char [strlen(name) + 1]) == NULL)
+ {
+ cerr << lman->lookup("errorMemory") << endl;
+ delete desc;
+ return 0;
+ }
+
+ strcpy(desc->collName, name);
+ prefs->lastScColl = name;
+ prefs->markModified();
+ r_Fast_Base_Scale *scaler;
+
+ if ((scaler = database.lookupScaledObject(desc, scale)) != NULL)
+ {
+ // don't call in standalone mode, viewer sorts it out itself.
+ rviewScaledImage *image = new rviewScaledImage(desc, scaler);
+ if (image->openViewer() != 0)
+ {
+ image->Close(TRUE);
+ RMDBGEXIT(3, RMDebug::module_applications, "rviewApp", "LookupScalledCollection() FAILED" );
+ return 0;
+ }
+ RMDBGEXIT(3, RMDebug::module_applications, "rviewApp", "LookupScalledCollection() OK" );
+ return 1;
+ }
+ else
+ {
+ rviewDeleteCollection(desc);
+ }
+ }
+
+ RMDBGEXIT(3, RMDebug::module_applications, "rviewApp", "LookupScalledCollection() FAILED" );
+ return 0;
+}
+
+
+int rmanClientApp::LookupOrthosection(void)
+{
+ char *name;
+
+ name = ::wxGetTextFromUser(lman->lookup("promptEnterOrtho"), lman->lookup("titleOrthoLook"), (char*)(prefs->lastOrthoColl.ptr()));
+
+ if ((name != NULL) && (strlen(name) != 0))
+ {
+ char buffer[STRINGSIZE];
+ const char *d = name;
+ char *b = buffer;
+ const double *lp = NULL;
+ double loid;
+
+ // search the collection name for a trailing ,<local oid>
+ while ((*d != '\0') && (*d != ','))
+ {
+ *b++ = *d++;
+ }
+ while ((b > buffer) && (isspace((unsigned int)(b[-1])))) b--;
+ *b++ = '\0';
+ if (*d == ',')
+ {
+ loid = atof(d+1);
+ lp = &loid;
+ }
+
+ return LookupOrthosection(buffer, lp);
+ }
+ return -1;
+}
+
+
+int rmanClientApp::LookupOrthosection(const char *collname, const double *loid)
+{
+ rviewOSectionPartImage *newImage = rviewOSectionPartImage::createViewer(collname, loid);
+
+ if (newImage == NULL)
+ {
+ rviewErrorbox::reportError(lman->lookup("errorOrthoViewer"), "rmanClientApp", "LookupOrthosection");
+ return -1;
+ }
+
+ prefs->lastOrthoColl = collname;
+
+ return 0;
+}
+
+
+int rmanClientApp::CreateCollection(void)
+{
+ char *name;
+
+ name = ::wxGetTextFromUser(lman->lookup("promptEnterColl"), lman->lookup("titleCollCrt"), (char*)(prefs->lastOrthoColl.ptr()));
+
+ if (name != NULL)
+ {
+ char buffer[STRINGSIZE];
+
+ strncpy(buffer, name, STRINGSIZE);
+ return database.createCollection(buffer, rbt_none);
+ }
+ return 0;
+}
+
+
+
+int rmanClientApp::DeleteCollection(void)
+{
+ char *name;
+ char buffer[STRINGSIZE];
+
+ name = ::wxGetTextFromUser(lman->lookup("promptEnterColl"), lman->lookup("titleCollDel"), (char*)(prefs->lastColl.ptr()));
+
+ if (name != NULL)
+ {
+ strncpy(buffer, name, STRINGSIZE);
+ return database.deleteCollection(buffer);
+ }
+ return 0;
+}
+
+
+
+int rmanClientApp::insertMDD(r_Ref<r_GMarray> srcMdd, char *collName, r_Minterval *domain)
+{
+ char useName[STRINGSIZE];
+ char *title;
+ int status;
+
+ if (domain == NULL)
+ title = lman->lookup("titleInsertMdd");
+ else
+ title = lman->lookup("titleInsertMddPro");
+
+ if (collName == NULL)
+ {
+ title = ::wxGetTextFromUser(lman->lookup("promptEnterColl"), title, (char*)(prefs->lastColl.ptr()));
+ if (title == NULL) return 0;
+ strncpy(useName, title, STRINGSIZE);
+ }
+ else
+ strncpy(useName, collName, STRINGSIZE);
+
+ if ((status = database.insertObject(useName, srcMdd, domain)) != 0)
+ {
+ prefs->lastColl = useName;
+ prefs->markModified();
+ }
+ return status;
+}
+
+
+
+collection_desc *rmanClientApp::executeQuerySync(char *query, r_Ref<r_GMarray> *updateMdd, bool showProgress)
+{
+ collection_desc *desc;
+
+ if ((desc = new collection_desc) == NULL)
+ {
+ cerr << lman->lookup("errorMemory") << endl;
+ return NULL;
+ }
+
+ desc->number = 0;
+ if (database.executeQuery(desc, query, updateMdd, showProgress) == 0)
+ {
+ delete desc;
+ return NULL;
+ }
+
+ // no result?
+ if (desc->number > 0)
+ {
+ char qcollName[] = "<query>";
+
+ desc->collName = new char[strlen(qcollName)+1];
+ strcpy(desc->collName, qcollName);
+ }
+ else
+ {
+ delete desc;
+ return NULL;
+ }
+
+ return desc;
+}
+
+
+int rmanClientApp::executeQuery(char *query, r_Ref<r_GMarray> *updateMdd)
+{
+ collection_desc *desc;
+
+ if ((desc = executeQuerySync(query, updateMdd)) != NULL)
+ {
+ if (desc->mddObjs != NULL)
+ {
+ rviewResult *qresult = new rviewResult(desc);
+ }
+ else
+ {
+ rviewStringSet *qresult = new rviewStringSet(desc);
+ // rviewStringSet doesn't need the descriptor data after the
+ // constructor, so we can just delete it right away
+ rviewDeleteCollection(desc);
+ }
+ return 1;
+ }
+ return 0;
+}
+
+
+int rmanClientApp::getMinterval(r_Minterval &dom, const char *collname, const double *loid)
+{
+ return database.getMinterval(dom, collname, loid);
+}
diff --git a/applications/rview/rviewApp.hh b/applications/rview/rviewApp.hh
new file mode 100644
index 0000000..c427cfa
--- /dev/null
+++ b/applications/rview/rviewApp.hh
@@ -0,0 +1,112 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+ * PURPOSE:
+ *
+ * RasDaMan + wxWindows application class used as base of rView etc.
+ * The main application includes the database object which has to be accessed
+ * through rmanClientApp-member functions.
+ *
+ * COMMENTS:
+ * none
+ */
+
+
+
+#ifndef _RVIEW_APP_H_
+#define _RVIEW_APP_H_
+
+
+#ifdef __GNUG__
+#pragma interface
+#endif
+
+
+
+
+
+// RasDaMan includes
+#include "rasodmg/ref.hh"
+#include "rasodmg/marray.hh"
+
+
+
+#include "rviewUtils.hh"
+#include "rviewDb.hh"
+#include "rviewDModes.hh"
+
+
+
+
+/*
+ * A generic RasDaMan client app using wxWindows.
+ */
+class rmanClientApp : public wxApp
+{
+ public:
+
+ rmanClientApp(const char *homevar, const char *prefsname, const char *labelname);
+ virtual ~rmanClientApp(void);
+
+ int OpenServer(const char *srvname, int srvport, const char *dbname,
+ const char *usrname, const char *usrpassword);
+ int CloseServer(void);
+ bool ReadDBState(void);
+ int LookupCollection(void);
+ int LookupScaledCollection(void);
+ int LookupScaledCollection(const char *name, double scale);
+ int LookupOrthosection(void);
+ int LookupOrthosection(const char *name, const double *loid);
+ int CreateCollection(void);
+ int DeleteCollection(void);
+ rviewFrame *OpenFile(unsigned int flags=0, r_Ref<r_GMarray> *newMddObj=NULL, bool resultwin=FALSE);
+ virtual void Shutdown(void);
+ int insertMDD(r_Ref<r_GMarray> srcMdd, char *collName=NULL, r_Minterval *domain=NULL);
+ int executeQuery(char *query, r_Ref<r_GMarray> *updateMdd=NULL);
+ collection_desc *executeQuerySync(char *query, r_Ref<r_GMarray> *updateMdd=NULL, bool showProgress=TRUE);
+ int getMinterval(r_Minterval &dom, const char *collname, const double *loid=NULL);
+
+ int SavePreferences(void) const;
+ bool findPreferencesOnPath(char *path);
+
+ // use this call to contact the application instance
+ static rmanClientApp *theApp(void);
+
+
+ protected:
+
+ rviewDatabase database;
+ char prefsFile[STRINGSIZE];
+ char prefsSaveFile[STRINGSIZE];
+ char prefsFileLeafname[STRINGSIZE];
+ char homeDir[STRINGSIZE];
+
+
+ private:
+
+ static rmanClientApp *theclientapp;
+ static const char *vffFileName;
+};
+
+#endif
diff --git a/applications/rview/rviewChart.cpp b/applications/rview/rviewChart.cpp
new file mode 100644
index 0000000..3fddcef
--- /dev/null
+++ b/applications/rview/rviewChart.cpp
@@ -0,0 +1,1024 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+ * SOURCE: rviewChart.cpp
+ *
+ * MODULE: applications/rview
+ *
+ * PURPOSE:
+ * rView chart viewer. Can display MDD objects of any dimension in a time
+ * series fashion. Possible modes are bar charts, line and spline function
+ * plots.
+ *
+ * COMMENTS:
+ * No comments
+ */
+
+
+// Standard wxWindows preamble.
+#ifdef __GNUG__
+#pragma implementation
+#endif
+
+
+// changed in wxWindows 2.4.2:
+//#include "wx_prec.h"
+#include <wx/wxprec.h>
+
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+
+#ifndef WX_PRECOMP
+#include <wx/wx.h>
+#endif
+
+
+
+#include <string.h>
+#include <iostream.h>
+#include <math.h>
+#include <limits.h>
+
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#endif
+
+#include "raslib/rmdebug.hh"
+
+#include "rviewTypes.hh"
+
+#include "labelManager.hh"
+
+#include "rviewUtils.hh"
+#include "rviewDModes.hh"
+#include "rviewPrefs.hh"
+#include "rviewMDD.hh"
+
+
+
+const int chartCanvas::chcanv_cospace = 16;
+const int chartCanvas::chcanv_colength = 6;
+const int chartCanvas::chcanv_exponents = 4;
+
+const int rviewChart::chart_twidth = 64;
+const int rviewChart::chart_theight = 50;
+const int rviewChart::chart_cwidth = 100;
+const int rviewChart::chart_cheight = 50;
+const int rviewChart::chart_minwidth = 100;
+const int rviewChart::chart_minheight = 100;
+const int rviewChart::chart_ctrly = 64;
+const int rviewChart::chart_totaly = rviewDisplay::display_cheight + rviewChart::chart_ctrly;
+
+
+
+chartCanvas::chartCanvas(wxWindow *parent, int x, int y, int w, int h, long style) : wxCanvas(parent, x, y, w, h, style)
+{
+ brush.SetStyle(wxSOLID);
+ brush.SetColour((char)0x80, (char)0x80, (char)0x80);
+ back.SetStyle(wxSOLID);
+ back.SetColour((char)0xe0, (char)0xe0, (char)0xe0);
+ pen.SetStyle(wxSOLID);
+ pen.SetColour(0,0,0);
+ SetBackground(&back);
+ font = new wxFont(12, wxROMAN, wxNORMAL, wxNORMAL);
+ scroll = 0;
+}
+
+
+chartCanvas::~chartCanvas(void)
+{
+ SetBackground(NULL);
+ delete font;
+}
+
+
+
+void chartCanvas::setData(mdd_frame *mf, rviewBaseType bt)
+{
+ mddObj = mf->mdd;
+ dimMDD = (int)(mddObj->spatial_domain().dimension());
+ baseType = bt;
+ if (baseType == rbt_rgb)
+ {
+ brush_r.SetStyle(wxSOLID);
+ brush_r.SetColour((char)0xff, 0, 0);
+ brush_g.SetStyle(wxSOLID);
+ brush_g.SetColour(0, (char)0xff, 0);
+ brush_b.SetStyle(wxSOLID);
+ brush_b.SetColour(0, 0, (char)0xff);
+ pen_r.SetColour((char)0xff, 0, 0);
+ pen_g.SetColour(0, (char)0xff, 0);
+ pen_b.SetColour(0, 0, (char)0xff);
+ }
+}
+
+
+
+int chartCanvas::setProjection(r_Point &p1, r_Point &p2)
+{
+ int i, j;
+ char buffer[STRINGSIZE];
+ float twidth, theight, taux;
+ r_Minterval useInterv;
+
+ pt1 = p1; pt2 = p2; min = 0.0; max = 1.0;
+
+ useInterv= r_Minterval(dimMDD);
+ for (i=0; i<dimMDD; i++)
+ {
+ useInterv << r_Sinterval(pt1[i], pt2[i]);
+ }
+ if (mdd_objectRange(mddObj, useInterv, min, max) == 0)
+ {
+ cerr << lman->lookup("errorBaseType") << endl;
+ return 0;
+ }
+
+ RMDBGONCE(3, RMDebug::module_applications, "chartCanvas", "setProjection(...) min = " << min << ", max = " << max );
+
+ // Determine format to use for numbering the vertical axis
+ taux = fabs(min);
+ if (taux <= pow(10.,(double)-chcanv_exponents)) i = chcanv_exponents;
+ else i = (int)(log(taux)/log(10.));
+ taux = fabs(max);
+ if (taux <= pow(10.,(double)-chcanv_exponents)) j = chcanv_exponents;
+ else j = (int)(log(taux)/log(10.));
+ if (i < j) i = j;
+ if (abs(i) >= chcanv_exponents)
+ {
+ strcpy(format, "%g");
+ }
+ else if (i >= 0)
+ {
+ strcpy(format, "%.0f");
+ }
+ else
+ {
+ sprintf(format, "%%.%df", -i);
+ }
+
+ if (cosys)
+ {
+ SetFont(font);
+ sprintf(buffer, format, min);
+ GetTextExtent(buffer, &twidth, &theight);
+ sprintf(buffer, format, max);
+ GetTextExtent(buffer, &taux, &theight);
+ if (twidth < taux) twidth = taux;
+ coleft = (int)(twidth + chcanv_colength/2);
+ }
+ else
+ coleft = chcanv_cospace;
+
+ return coleft;
+}
+
+
+
+void chartCanvas::setVars(int s, double cs, int ds, bool cy, rviewChartMode cm)
+{
+ step = s;
+ costep = cs;
+ datastep = ds;
+ cosys = cy;
+ cmode = cm;
+}
+
+
+
+// Recurring redraw body
+#define _REDCHARTBAR(wd, pm) \
+ value = (long)(scale * ((*mddPtr)[prun])pm); \
+ if (value < 0) \
+ { \
+ top = orgy; bot = top - (float)value; \
+ } \
+ else \
+ { \
+ top = orgy - (float)value; bot = orgy; \
+ } \
+ if (top < 0) top = 0; if (bot > height) bot = height; \
+ cdc->DrawRect(posx, chcanv_cospace + top, wd, bot - top);
+
+#define _REDCHARTBARLOOP(wd, pm) \
+ for (prun[dim]=pt1[dim]+startOff; prun[dim] <= pt1[dim] + endOff; prun[dim]++, posx+=stepx) \
+ { \
+ _REDCHARTBAR(wd, pm); \
+ }
+
+#define REDCHARTBAR(type) \
+ r_Ref <r_Marray <type> > mddPtr = (r_Ref < r_Marray <type> >)(mddObj); \
+ _REDCHARTBARLOOP(stepx, +0);
+
+void chartCanvas::redrawBar(wxDC *cdc, int height, int dim, int startOff, int endOff, float scale, float posx, float stepx, float orgy)
+{
+ float top, bot;
+ r_Point prun = pt1;
+ long value;
+
+ switch (baseType)
+ {
+ case rbt_bool:
+ {
+ r_Ref <r_Marray <r_Boolean> > mddPtr = (r_Ref < r_Marray <r_Boolean> >)(mddObj);
+ for (prun[dim]=pt1[dim]+startOff; prun[dim] <= pt1[dim]+endOff; prun[dim]++, posx+= stepx)
+ {
+ // This can only be 0 or 1, so don't bother with the sign
+ value = (long)(scale * (*mddPtr)[prun]);
+ cdc->DrawRectangle(posx, chcanv_cospace + orgy - (float)value, stepx, (float)value);
+ }
+ }
+ break;
+ case rbt_char:
+ {
+ REDCHARTBAR(r_Char);
+ }
+ break;
+ case rbt_uchar:
+ {
+ REDCHARTBAR(r_Octet);
+ }
+ break;
+ case rbt_short:
+ {
+ REDCHARTBAR(r_Short);
+ }
+ break;
+ case rbt_ushort:
+ {
+ REDCHARTBAR(r_UShort);
+ }
+ break;
+ case rbt_long:
+ {
+ REDCHARTBAR(r_Long);
+ }
+ break;
+ case rbt_ulong:
+ {
+ REDCHARTBAR(r_ULong);
+ }
+ break;
+ case rbt_rgb:
+ {
+ r_Ref <r_Marray <RGBPixel> > mddPtr = (r_Ref < r_Marray <RGBPixel> >)(mddObj);
+ double oldPosx = posx;
+
+ cdc->SetBrush(&brush_r);
+ _REDCHARTBARLOOP(stepx/3, .red);
+ cdc->SetBrush(&brush_g); posx = oldPosx + stepx/3;
+ _REDCHARTBARLOOP(stepx/3, .green);
+ cdc->SetBrush(&brush_b); posx = oldPosx + 2*stepx/3;
+ _REDCHARTBARLOOP(stepx/3, .blue);
+ cdc->SetBrush(&brush);
+ }
+ break;
+ case rbt_float:
+ {
+ REDCHARTBAR(r_Float);
+ }
+ break;
+ case rbt_double:
+ {
+ REDCHARTBAR(r_Double);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+
+
+#define _REDCHARTLINELOOP(pm) \
+ prun[dim] = pt1[dim] + startOff; \
+ lastVal = chcanv_cospace + orgy - scale * (((*mddPtr)[prun])pm); \
+ for (prun[dim]++ ; prun[dim]<=pt1[dim]+endOff; prun[dim]++, posx += stepx) \
+ { \
+ newVal = chcanv_cospace + orgy - scale * (((*mddPtr)[prun])pm); \
+ cdc->DrawLine(posx, lastVal, posx+stepx, newVal); \
+ lastVal = newVal; \
+ }
+
+#define REDCHARTLINE(type) \
+ r_Ref<r_Marray<type> > mddPtr = (r_Ref<r_Marray<type> >)(mddObj); \
+ _REDCHARTLINELOOP(+0);
+
+void chartCanvas::redrawLine(wxDC *cdc, int dim, int startOff, int endOff, float scale, float posx, float stepx, float orgy)
+{
+ r_Point prun = pt1;
+ float newVal, lastVal;
+
+ if (pt1[dim] + endOff < pt2[dim]) endOff++;
+
+ switch (baseType)
+ {
+ case rbt_bool:
+ {
+ REDCHARTLINE(r_Boolean);
+ }
+ break;
+ case rbt_char:
+ {
+ REDCHARTLINE(r_Char);
+ }
+ break;
+ case rbt_uchar:
+ {
+ REDCHARTLINE(r_Octet);
+ }
+ break;
+ case rbt_short:
+ {
+ REDCHARTLINE(r_Short);
+ }
+ break;
+ case rbt_ushort:
+ {
+ REDCHARTLINE(r_UShort);
+ }
+ break;
+ case rbt_long:
+ {
+ REDCHARTLINE(r_Long);
+ }
+ break;
+ case rbt_ulong:
+ {
+ REDCHARTLINE(r_ULong);
+ }
+ break;
+ case rbt_rgb:
+ {
+ r_Ref<r_Marray<RGBPixel> > mddPtr = (r_Ref<r_Marray<RGBPixel> >)(mddObj);
+ double oldPosx = posx;
+
+ cdc->SetPen(&pen_r);
+ _REDCHARTLINELOOP(.red);
+ cdc->SetPen(&pen_g); posx = oldPosx + stepx/3;
+ _REDCHARTLINELOOP(.green);
+ cdc->SetPen(&pen_b); posx = oldPosx + 2*stepx/3;
+ _REDCHARTLINELOOP(.blue);
+ cdc->SetPen(&pen);
+ }
+ break;
+ case rbt_float:
+ {
+ REDCHARTLINE(r_Float);
+ }
+ break;
+ case rbt_double:
+ {
+ REDCHARTLINE(r_Double);
+ }
+ break;
+ default: break;
+ }
+}
+
+
+
+#define _REDCHARTSPLINELOOP(pm) \
+ for (prun[dim]=pt1[dim]+startOff; prun[dim]<=pt1[dim]+endOff; prun[dim]++, posx+=stepx, i++) \
+ { \
+ vertices[i].x = posx; \
+ vertices[i].y = chcanv_cospace + orgy - scale * (((*mddPtr)[prun])pm); \
+ RMDBGONCE(4, RMDebug::module_applications, "chartCanvas", "_REDCHARTSPLINELOOP(pm) V: " << vertices[i].x << ',' << vertices[i].y ); \
+ vlist.Append(vertices + i); \
+ }
+
+#define REDCHARTSPLINE(type) \
+ r_Ref<r_Marray<type> > mddPtr = (r_Ref<r_Marray<type> >)(mddObj); \
+ _REDCHARTSPLINELOOP(+0);
+
+void chartCanvas::redrawSpline(wxDC *cdc, int dim, int startOff, int endOff, float scale, float posx, float stepx, float orgy)
+{
+ wxPoint *vertices;
+ wxList vlist;
+ wxPoint point;
+ r_Point prun = pt1;
+ float clipx, clipwidth;
+ int i;
+
+ clipx = posx; clipwidth = (endOff - startOff) * stepx;
+
+ // Need additional vertices left (1) and right (2) for splines
+ if (startOff > 0) {startOff--; posx -= stepx;}
+ endOff += 2; if (pt1[dim] + endOff > pt2[dim]) endOff = pt2[dim] - pt1[dim];
+
+ if ((vertices = new wxPoint[endOff - startOff + 1]) == NULL)
+ {
+ cerr << lman->lookup("errorMemory") << endl;
+ return;
+ }
+
+ // Do not delete the contents of the nodes when the list is killed!
+ vlist.DeleteContents(FALSE);
+
+ // It is _vitally_ important to set the clipping region here, because the boundary vertices
+ // are only there to get curvature right. If you don't set the clipping region you get
+ // redraw errors.
+ cdc->SetClippingRegion(clipx, 0, clipwidth, 10000);
+
+ i = 0;
+ switch (baseType)
+ {
+ case rbt_bool:
+ {
+ REDCHARTSPLINE(r_Boolean);
+ }
+ break;
+ case rbt_char:
+ {
+ REDCHARTSPLINE(r_Char);
+ }
+ break;
+ case rbt_uchar:
+ {
+ REDCHARTSPLINE(r_Octet);
+ }
+ break;
+ case rbt_short:
+ {
+ REDCHARTSPLINE(r_Short);
+ }
+ break;
+ case rbt_ushort:
+ {
+ REDCHARTSPLINE(r_UShort);
+ }
+ break;
+ case rbt_long:
+ {
+ REDCHARTSPLINE(r_Long);
+ }
+ break;
+ case rbt_ulong:
+ {
+ REDCHARTSPLINE(r_ULong);
+ }
+ break;
+ case rbt_rgb:
+ {
+ r_Ref<r_Marray<RGBPixel> > mddPtr = (r_Ref<r_Marray<RGBPixel> >) (mddObj);
+ double oldPosx = posx;
+ cdc->SetPen(&pen_r);
+ _REDCHARTSPLINELOOP(.red);
+ cdc->DrawSpline(&vlist); vlist.Clear();
+ cdc->SetPen(&pen_g); posx = oldPosx + stepx/3; i = 0;
+ _REDCHARTSPLINELOOP(.green);
+ cdc->DrawSpline(&vlist); vlist.Clear();
+ cdc->SetPen(&pen_b); posx = oldPosx + 2*stepx/3; i = 0;
+ _REDCHARTSPLINELOOP(.blue);
+ }
+ break;
+ case rbt_float:
+ {
+ REDCHARTSPLINE(r_Float);
+ }
+ break;
+ case rbt_double:
+ {
+ REDCHARTSPLINE(r_Double);
+ }
+ break;
+ default: break;
+ }
+ RMDBGONCE(3, RMDebug::module_applications, "chartCanvas", "redrawSpline() vertices " << (void*)vertices );
+
+ cdc->DrawSpline(&vlist);
+
+ if (baseType == rbt_rgb)
+ cdc->SetPen(&pen);
+
+ cdc->DestroyClippingRegion();
+
+ // ... we delete the data ourselves.
+ delete [] vertices;
+}
+
+
+
+void chartCanvas::OnPaint(void)
+{
+ wxUpdateIterator upd(this);
+ wxRect rect;
+ int w, h, dim, i, x;
+ float scale, orgy, posx, stepx, cm, y;
+ float twidth, theight;
+ wxCanvasDC *cdc;
+ r_Range startOff, endOff;
+ char buffer[STRINGSIZE];
+ bool redrawAll = FALSE;
+
+ //cout << "chartCanvas::OnPaint()" << endl;
+ for (dim=0; dim<dimMDD; dim++) if (pt1[dim] != pt2[dim]) break;
+ if (dim >= dimMDD) return;
+
+ GetClientSize(&w, &h);
+ // Reserve space for co system
+ h -= 2*chcanv_cospace;
+
+ if (fabs(max-min) < 10*DBL_MIN)
+ {
+ scale = (float)h; orgy = h;
+ }
+ else
+ {
+ scale = ((float)h) / (max - min); orgy = max*scale;
+ }
+ if (scale <= 0) return;
+
+ cdc = GetDC();
+ cdc->BeginDrawing();
+ cdc->SetMapMode(MM_TEXT); // 1 unit = 1 pixel
+ cdc->SetBrush(&brush);
+ cdc->SetPen(&pen);
+ cdc->SetFont(font);
+
+ w = GetScrollPos(wxHORIZONTAL);
+ x = rviewDisplay::display_scrstep * w;
+
+ // On the necessity to redraw everything in case of scroll events see rviewTable.cpp
+ if (w != scroll)
+ {
+ redrawAll = TRUE;
+ GetClientSize(&rect.width, &rect.height);
+ rect.x = 0; rect.y = 0;
+ scroll = w;
+ }
+
+ stepx = (float)step;
+
+ // It's important to use for, not while here, due to continue in the loop body
+ for (; upd ; upd++)
+ {
+ if (!redrawAll) upd.GetRect(&rect);
+
+ // Leave space to the left for co-system
+ startOff = (x + rect.x - coleft) / step;
+ if (startOff < 0) startOff = 0;
+ if (pt1[dim] + startOff > pt2[dim])
+ continue;
+ endOff = (x + rect.x - coleft + rect.width + step - 1) / step;
+ if (pt1[dim] + endOff > pt2[dim]) endOff = (r_Range)(pt2[dim] - pt1[dim]);
+ posx = startOff * stepx + coleft;
+
+ switch (cmode)
+ {
+ case rcm_bar: redrawBar(cdc, h, dim, startOff, endOff, scale, posx, stepx, orgy); break;
+ case rcm_line: redrawLine(cdc, dim, startOff, endOff, scale, posx, stepx, orgy); break;
+ case rcm_spline: redrawSpline(cdc, dim, startOff, endOff, scale, posx, stepx, orgy); break;
+ default: break;
+ }
+
+ // Draw coordinate system?
+ if (cosys)
+ {
+ // co-system
+ y = (min*max < 0) ? orgy : h;
+ // Only draw visible portion of horizontal line to avoid overflows
+ cdc->DrawLine(coleft + startOff * stepx, chcanv_cospace + y, coleft + (endOff+1)*stepx, chcanv_cospace + y);
+
+ // vertical axis
+ if (coleft + chcanv_colength/2 >= rect.x)
+ {
+ cdc->DrawLine(coleft, chcanv_cospace, coleft, chcanv_cospace + h);
+ i = (int)(min / costep);
+ for (cm=i*costep; cm <= (float)max; cm += costep)
+ {
+ posx = orgy - cm*scale;
+ if (posx > h) continue;
+ posx += chcanv_cospace;
+ cdc->DrawLine(coleft - chcanv_colength/2, posx, coleft + chcanv_colength/2, posx);
+ sprintf(buffer, format, cm);
+ cdc->GetTextExtent(buffer, &twidth, &theight);
+ cdc->DrawText(buffer, coleft - chcanv_colength/2 - twidth, posx - theight/2);
+ }
+ }
+
+ // horizontal axis
+ i = startOff/datastep; i *= datastep;
+ for (; i <= endOff; i += datastep)
+ {
+ posx = i*stepx + coleft;
+ cdc->DrawLine(posx, chcanv_cospace + y - chcanv_colength, posx, chcanv_cospace + y + chcanv_colength/2);
+ sprintf(buffer, "%ld", i + pt1[dim]);
+ cdc->GetTextExtent(buffer, &twidth, &theight);
+ cdc->DrawText(buffer, posx - twidth/2, y + chcanv_cospace + chcanv_colength/2);
+ }
+ }
+ }
+ cdc->SetBrush(NULL);
+ cdc->SetPen(NULL);
+ cdc->SetFont(NULL);
+ cdc->EndDrawing();
+
+ //cout << "Leaving OnPaint..." << endl;
+}
+
+
+
+
+
+const char *rviewChart::view_StepSize = "stepSize";
+const char *rviewChart::view_Markers = "markers";
+const char *rviewChart::view_ScrollPos = "scrollPos";
+const char *rviewChart::view_CoSys = "coordSys";
+const char *rviewChart::view_ChartMode = "chartMode";
+
+rviewChart::rviewChart(mdd_frame *mf, unsigned int flags) : rviewDisplay(mf, chart_ctrly, flags)
+{
+ int w, h, i;
+ char *b;
+
+ RMDBGONCE(3, RMDebug::module_applications, "rviewChart", "rviewChart()");
+
+ // Chart mode defaults, put into prefs later
+ cmode = prefs->chartMode;
+ if ((cmode != rcm_bar) && (cmode != rcm_line) && (cmode != rcm_spline)) cmode = rcm_bar;
+ step = prefs->chartStep; cosys = prefs->chartCosys;
+ datastep = prefs->chartMarkx; costep = prefs->chartMarky;
+
+ GetClientSize(&w, &h);
+ w -= 2*display_cnvborder; h -= 2*display_cnvborder + chart_totaly;
+ canvas = new chartCanvas((wxWindow*)this, display_cnvborder, display_cnvborder + chart_totaly, w, h);
+
+ stText = new rviewText(ctrlPanel, step);
+ coText = new rviewText(ctrlPanel, costep);
+ dataText = new rviewText(ctrlPanel, datastep);
+ csBox = new rviewCheckBox(ctrlPanel);
+ csBox->SetValue(cosys);
+
+ canvas->setData(mf, baseType);
+
+ canvas->setVars(step, costep, datastep, cosys, cmode);
+
+ b = projString;
+ b += sprintf(b, "*:*");
+ for (i=1; i<dimMDD; i++)
+ {
+ b += sprintf(b, ", %ld", interv[i].low());
+ }
+ project->SetValue(projString);
+
+ scroll = -1;
+ newProjection();
+
+ setModeDimension(1);
+
+ setMinimumViewerSize(chart_minwidth, chart_minheight);
+}
+
+
+int rviewChart::openViewer(void)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewChart", "openViewer()");
+
+ if (baseType == rbt_none)
+ {
+ rviewErrorbox::reportError(lman->lookup("errorModeBase"), rviewChart::getFrameName(), "openViewer");
+ objectInitializedOK = FALSE;
+ return -1;
+ }
+
+ if (rviewDisplay::openViewer() == 0)
+ {
+ int w, h;
+ wxMenu *modes;
+ char buffer[STRINGSIZE];
+
+ modes = new wxMenu;
+ modes->Append(MENU_CHART_MODE_BAR, "", NULL, TRUE);
+ modes->Append(MENU_CHART_MODE_LINE, "", NULL, TRUE);
+ modes->Append(MENU_CHART_MODE_SPLINE, "", NULL, TRUE);
+
+ sprintf(buffer, "&%s", lman->lookup("menChartMode"));
+ mBar->Append(modes, buffer);
+
+ checkModeMenu();
+
+ GetClientSize(&w, &h);
+ label();
+
+ frameWidth=-1;
+ frameHeight=-1;
+
+ OnSize(w, h);
+
+ Show(TRUE);
+
+ return 0;
+ }
+ return -1;
+}
+
+
+const char *rviewChart::getFrameName(void) const
+{
+ return "rviewChart";
+}
+
+rviewFrameType rviewChart::getFrameType(void) const
+{
+ return rviewFrameTypeChart;
+}
+
+int rviewChart::getViewerType(void) const
+{
+ return RVIEW_RESDISP_CHART;
+}
+
+
+
+// We don't own the mdd object. rviewResult does, so don't delete it!!!
+rviewChart::~rviewChart(void)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewChart", "~rviewChart()");
+ closeViewer();
+}
+
+
+
+void rviewChart::checkModeMenu(void)
+{
+ // tick the right mode in the display window.
+ switch (cmode)
+ {
+ case rcm_bar: lastMode = MENU_CHART_MODE_BAR; break;
+ case rcm_line: lastMode = MENU_CHART_MODE_LINE; break;
+ case rcm_spline: lastMode = MENU_CHART_MODE_SPLINE; break;
+ default: lastMode = MENU_CHART_MODE_BAR; break;
+ }
+ mBar->Check(lastMode, TRUE);
+}
+
+
+void rviewChart::label(void)
+{
+ setDisplayTitle(lman->lookup("titleChart"));
+
+ stText->SetLabel(lman->lookup("textStepC"));
+ csBox->SetLabel(lman->lookup("textCosys"));
+ coText->SetLabel(lman->lookup("textCoStep"));
+ dataText->SetLabel(lman->lookup("textDataStep"));
+
+ mBar->SetLabel(MENU_CHART_MODE_BAR, lman->lookup("menChartModeBar"));
+ mBar->SetLabel(MENU_CHART_MODE_LINE, lman->lookup("menChartModeLine"));
+ mBar->SetLabel(MENU_CHART_MODE_SPLINE, lman->lookup("menChartModeSpline"));
+ mBar->SetLabelTop(fixedNumberOfMenus, lman->lookup("menChartMode"));
+
+ rviewDisplay::label();
+}
+
+
+
+void rviewChart::OnSize(int w, int h)
+{
+ int x, y, i, j;
+
+ RMDBGONCE(3, RMDebug::module_applications, "rviewChart", "OnSize(" << w << ", " << h << " )");
+
+ GetClientSize(&x, &y);
+ i = 2*display_border + chart_totaly + 2*chartCanvas::chcanv_cospace;
+ if (y < i)
+ {
+ y = i;
+ SetClientSize(x, i);
+ }
+ x -= 2*display_border;
+ i = x - 3*chart_twidth - chart_cwidth;
+ j = display_border + display_cheight;
+ stText->SetSize(display_border + i/8, j, chart_twidth - display_border, chart_theight);
+ coText->SetSize(display_border + (3*i)/8 + chart_twidth, j, chart_twidth - display_border, chart_theight);
+ dataText->SetSize(display_border + (5*i)/8 + 2*chart_twidth, j, chart_twidth - display_border, chart_theight);
+ csBox->SetSize(display_border + (7*i)/8 + 3*chart_twidth, j, chart_cwidth, chart_cheight);
+
+ y -= 2*display_border + chart_totaly;
+ canvas->SetSize(display_border, display_border + chart_totaly, x, y);
+ rviewDisplay::OnSize(w, h);
+}
+
+
+
+void rviewChart::OnMenuCommand(int id)
+{
+ rviewChartMode cm;
+
+ RMDBGONCE(3, RMDebug::module_applications, "rviewChart", "OnMenuCommand()");
+
+ switch (id)
+ {
+ case MENU_CHART_MODE_BAR: cm = rcm_bar; break;
+ case MENU_CHART_MODE_LINE: cm = rcm_line; break;
+ case MENU_CHART_MODE_SPLINE: cm = rcm_spline; break;
+ default: cm = rcm_none; break;
+ }
+
+ if (cm != rcm_none)
+ {
+ mBar->Check(lastMode, FALSE);
+ mBar->Check(id, TRUE);
+ lastMode = id; cmode = cm;
+ newProjection();
+ }
+ else
+ rviewDisplay::OnMenuCommand(id);
+}
+
+
+
+int rviewChart::process(wxObject &obj, wxEvent &evt)
+{
+ int type = evt.GetEventType();
+ int h;
+ double hd;
+
+ RMDBGONCE(3, RMDebug::module_applications, "rviewChart", "process()");
+
+ if (type == wxEVENT_TYPE_TEXT_ENTER_COMMAND)
+ {
+ if (&obj == (wxObject*)stText)
+ {
+ if ((h = atoi(stText->GetValue())) > 0)
+ {
+ step = h;
+ newProjection();
+ return 1;
+ }
+ }
+ else if (&obj == (wxObject*)coText)
+ {
+ if ((hd = atof(coText->GetValue())) > 0.0)
+ {
+ costep = hd;
+ newProjection();
+ return 1;
+ }
+ }
+ else if (&obj == (wxObject*)dataText)
+ {
+ if ((h = atoi(dataText->GetValue())) > 0)
+ {
+ datastep = h;
+ newProjection();
+ return 1;
+ }
+ }
+ }
+
+ if ((&obj == (wxObject*)csBox) && (type == wxEVENT_TYPE_CHECKBOX_COMMAND))
+ {
+ cosys = csBox->GetValue();
+ // to force a redraw.
+ newProjection();
+ }
+
+ if (rviewDisplay::process(obj, evt) != 0)
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+
+
+int rviewChart::newProjection(void)
+{
+ int dim, i;
+
+ RMDBGONCE(3, RMDebug::module_applications, "rviewChart", "newProjection()");
+
+ if (rviewParseProjection(getVirtualDomain(), pt1, pt2, projString) != dimMDD)
+ {
+ rviewErrorbox::reportError(lman->lookup("errorProjection"), rviewChart::getFrameName(), "newProjection");
+ return -1;
+ }
+
+ dim = -1;
+ for (i=0; i<dimMDD; i++)
+ {
+ if (pt1[i] != pt2[i])
+ {
+ if (dim < 0) dim = i;
+ else dim = dimMDD;
+ }
+ }
+ if ((dim < 0) || (dim >= dimMDD))
+ {
+ rviewErrorbox::reportError(lman->lookup("errorProjectFree"), rviewChart::getFrameName(), "newProjection");
+ return -1;
+ }
+ canvas->setVars(step, costep, datastep, cosys, cmode);
+
+ i = canvas->setProjection(pt1, pt2); // returns coleft
+
+ if (scroll >= 0)
+ scroll = canvas->GetScrollPos(wxHORIZONTAL);
+ else
+ scroll = 0;
+
+ canvas->SetScrollbars(display_scrstep, 0, (int)(((pt2[dim] - pt1[dim] + 1)*step + i + display_scrstep - 1) / display_scrstep), 0, display_pgstep, 0, scroll);
+ //canvas->GetVirtualSize(&dim, &i);
+ //cout << "step = " << step << "virtual size = " << dim << " x " << i << endl;
+
+ return 0;
+}
+
+
+int rviewChart::saveView(FILE *fp)
+{
+ int status = rviewDisplay::saveView(fp);
+
+ writeViewParam(fp, view_StepSize, (long)step);
+ long mvals[2];
+ mvals[0] = (long)costep; mvals[1] = (long)datastep;
+ writeViewParam(fp, view_Markers, 2, mvals);
+ writeViewParam(fp, view_ScrollPos, (long)(canvas->GetScrollPos(wxHORIZONTAL)));
+ writeViewParam(fp, view_CoSys, (long)cosys);
+ writeViewParam(fp, view_ChartMode, (long)cmode);
+
+ return status;
+}
+
+
+int rviewChart::readView(const char *key, const char *value)
+{
+ int status = rviewDisplay::readView(key, value);
+
+ if (status == 0)
+ {
+ if (strcmp(key, view_StepSize) == 0)
+ {
+ step = atoi(value);
+ return 1;
+ }
+ else if (strcmp(key, view_Markers) == 0)
+ {
+ long mvals[2];
+ if (readVector(value, 2, mvals) == 0)
+ {
+ costep = (int)mvals[0]; datastep = (int)mvals[1];
+ }
+ return 1;
+ }
+ else if (strcmp(key, view_ScrollPos) == 0)
+ {
+ scroll = atoi(value);
+ return 1;
+ }
+ else if (strcmp(key, view_CoSys) == 0)
+ {
+ cosys = (bool)atoi(value);
+ return 1;
+ }
+ else if (strcmp(key, view_ChartMode) == 0)
+ {
+ cmode = (rviewChartMode)atoi(value);
+ return 1;
+ }
+ return 0;
+ }
+ return status;
+}
+
+
+void rviewChart::loadViewFinished(void)
+{
+ stText->SetValue(step);
+ coText->SetValue(costep);
+ dataText->SetValue(datastep);
+
+ csBox->SetValue(cosys);
+
+ mBar->Check(lastMode, FALSE);
+ checkModeMenu();
+
+ canvas->SetScrollPos(wxHORIZONTAL, scroll);
+}
diff --git a/applications/rview/rviewColMap.cpp b/applications/rview/rviewColMap.cpp
new file mode 100644
index 0000000..93d3654
--- /dev/null
+++ b/applications/rview/rviewColMap.cpp
@@ -0,0 +1,1183 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+ * PURPOSE:
+ * Colourspace mapper class and support classes.
+ * COMMENTS:
+ * No comments
+ */
+
+
+
+// Standard wxWindows preamble.
+#ifdef __GNUG__
+#pragma implementation
+#endif
+
+
+// changed in wxWindows 2.4.2:
+//#include "wx_prec.h"
+#include <wx/wxprec.h>
+
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+
+#ifndef WX_PRECOMP
+#include <wx/wx.h>
+#endif
+
+
+
+#include <string.h>
+#include <stdlib.h>
+#include <iostream.h>
+#include <math.h>
+#include <limits.h>
+#include <float.h>
+
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#endif
+
+
+#include "raslib/rmdebug.hh"
+
+#include "wx_pixmap_translate.h"
+
+#include "rviewUtils.hh"
+#include "labelManager.hh"
+#include "rviewColMap.hh"
+#include "rviewPrefs.hh"
+#include "rviewMDD.hh"
+
+
+
+
+
+/*
+ * Conversion functions shared by colourspaceCanvas and colourspaceMapper:
+ * convert a value normalized to [0,1] to a value normalized to [0,1]
+ */
+
+static inline double valueToGauss(double value, double peak, double invSig)
+{
+ double h;
+
+ h = (value - peak) * invSig; return exp(-h*h);
+}
+
+static inline double valueToLinear(double value, double peak, double invSig)
+{
+ double h;
+
+ if (value < peak)
+ h = 1.0 - invSig*(peak - value);
+ else
+ h = 1.0 - invSig*(value - peak);
+
+ if (h < 0) h = 0;
+
+ return h;
+}
+
+static inline double valueToRectangle(double value, double peak, double invSig)
+{
+ double h;
+
+ if (value < peak)
+ h = 1.0 - invSig*(peak - value);
+ else
+ h = 1.0 - invSig*(value - peak);
+
+ if (h > 0) h = 1.0; else h = 0.0;
+
+ return h;
+}
+
+static inline double valueToAsymptotic(double value, double peak, double invSig)
+{
+ double h;
+
+ if (value < peak) h = 0;
+ else
+ h = 1.0 - exp((peak - value) * invSig);
+
+ return h;
+}
+
+
+
+/*
+ * Colourspace mapper editor canvas class.
+ */
+
+const int colourspaceCanvas::colcanv_cborder = 8;
+const int colourspaceCanvas::colcanv_mheight = 8;
+
+colourspaceCanvas::colourspaceCanvas(colourspaceFrame *parent, colourspace_params *p, int x, int y, int w, int h, long style) : wxCanvas((wxWindow*)parent, x, y, w, h, style)
+{
+ params = p;
+ canvX = w; canvY = h;
+ parentObj = parent;
+ canvX=100; canvY=100;
+ values = NULL;
+
+ setDrawingFunction();
+
+ brush.SetStyle(wxSOLID); brush.SetColour((char)0xe0, (char)0xe0, (char)0xe0);
+ redPen.SetStyle(wxSOLID); redPen.SetColour((char)0xff, 0, 0);
+ greenPen.SetStyle(wxSOLID); greenPen.SetColour(0, (char)0xff, 0);
+ bluePen.SetStyle(wxSOLID); bluePen.SetColour(0, 0, (char)0xff);
+ blackPen.SetStyle(wxSOLID); blackPen.SetColour(0, 0, 0);
+
+ font = new wxFont(12, wxROMAN, wxNORMAL, wxNORMAL);
+
+ SetBackground(&brush);
+ SetFont(font);
+}
+
+
+colourspaceCanvas::~colourspaceCanvas(void)
+{
+ SetFont(NULL);
+ SetBackground(NULL);
+ delete font;
+ if (values != NULL) delete [] values;
+}
+
+
+void colourspaceCanvas::setDrawingFunction(void)
+{
+ switch (params->type)
+ {
+ case cst_gauss:
+ conversionFunction = valueToGauss; break;
+ case cst_linear:
+ conversionFunction = valueToLinear; break;
+ case cst_rectangle:
+ conversionFunction = valueToRectangle; break;
+ case cst_asympt:
+ conversionFunction = valueToAsymptotic; break;
+ default:
+ cerr << "Unknown drawing function (" << (int)(params->type) << ")" << endl;
+ conversionFunction = NULL;
+ break;
+ }
+ //cout << "cspace type " << (int)(params->type) << endl;
+}
+
+
+void colourspaceCanvas::enableOutlineSum(bool enable)
+{
+ if (enable)
+ {
+ if (values == NULL)
+ {
+ values = new float[canvX]; Redraw();
+ }
+ }
+ else
+ {
+ if (values != NULL)
+ {
+ delete [] values; values = NULL; Redraw();
+ }
+ }
+}
+
+
+void colourspaceCanvas::OnSize(int w, int h)
+{
+ canvX = w; canvY = h;
+ height = (float)(canvY - 2*colcanv_cborder);
+ base = (float)(canvY - colcanv_cborder);
+ step = 1.0 / (canvX - 2*colcanv_cborder);
+ cmin = colcanv_cborder; cmax = canvX - colcanv_cborder;
+ if (values != NULL)
+ {
+ delete [] values; values = new float[canvX];
+ }
+}
+
+
+void colourspaceCanvas::Redraw(void)
+{
+ Refresh(TRUE);
+}
+
+
+void colourspaceCanvas::OnPaint(void)
+{
+ wxRect rect;
+ int y = canvY - colcanv_cborder;
+ float x, xhigh, markstep;
+
+ markstep = (canvX - 2*colcanv_cborder) / 10.0;
+ xhigh = (float)(canvX - colcanv_cborder) + 0.9;
+
+ BeginDrawing();
+
+ wxUpdateIterator upd(this);
+ while (upd)
+ {
+ upd.GetRect(&rect);
+
+ if (values != NULL)
+ memset(values, 0, canvX*sizeof(float));
+
+ if (conversionFunction != NULL)
+ {
+ drawOutline(params->peak_red, params->sigm_red, &redPen, &rect);
+ drawOutline(params->peak_green, params->sigm_green, &greenPen, &rect);
+ drawOutline(params->peak_blue, params->sigm_blue, &bluePen, &rect);
+ }
+ if (values != NULL)
+ drawOutlineSum(&blackPen, &rect);
+
+ SetPen(&blackPen);
+ IntDrawLine(colcanv_cborder, y, canvX - colcanv_cborder, y);
+
+ for (x=(float)colcanv_cborder; x<=xhigh; x += markstep)
+ {
+ IntDrawLine((int)x, y + colcanv_mheight/2, (int)x, y - colcanv_mheight/2);
+ }
+ upd++;
+ }
+ SetPen(NULL);
+
+ EndDrawing();
+}
+
+
+void colourspaceCanvas::OnEvent(wxMouseEvent &mevt)
+{
+ parentObj->processMouseEvent(mevt);
+}
+
+
+int colourspaceCanvas::setupRectangle(int &from, int &to, float &x, wxRect *rect)
+{
+ if (rect == NULL)
+ {
+ from = cmin; from = cmax; x = 0.0;
+ }
+ else
+ {
+ from = rect->x; to = from + rect->width + 1;
+ if (((from < cmin) && (to < cmin)) || ((from > cmax) && (to > cmax)))
+ return -1;
+ if (from < cmin) from = cmin;
+ if (to > cmax) to = cmax;
+ x = (from - cmin) * step;
+ }
+ return 0;
+}
+
+
+void colourspaceCanvas::drawOutline(double peak, double sigma, wxPen *pen, wxRect *rect)
+{
+ float mid = (canvX - 2*colcanv_cborder) * peak + colcanv_cborder;
+ float x, y, lastY;
+ float invSigma;
+ int i, j;
+
+ SetPen(pen);
+
+ DrawLine(mid, base, mid, 0.0);
+
+ invSigma = 1.0 / sigma;
+
+ if (setupRectangle(i, j, x, rect) != 0) return;
+
+ lastY = height * conversionFunction(x, peak, invSigma);
+ if (values != NULL)
+ values[i] += lastY;
+
+ for (i++, x += step; i < j; i++, x+=step)
+ {
+ y = height * conversionFunction(x, peak, invSigma);
+ DrawLine((float)i-1, base - lastY, (float)i, base - y);
+ lastY = y;
+ if (values != NULL)
+ values[i] += y;
+ }
+}
+
+
+void colourspaceCanvas::drawOutlineSum(wxPen *pen, wxRect *rect)
+{
+ int i, j;
+ float x, y, lastY;
+
+ pen->SetStyle(wxSHORT_DASH); SetPen(pen);
+ DrawLine((float)colcanv_cborder, base - height/3, (float)(canvX - colcanv_cborder), base - height/3);
+ pen->SetStyle(wxSOLID); SetPen(pen);
+
+ if (setupRectangle(i, j, x, rect) != 0) return;
+
+ lastY = values[i] / 3;
+ for (i++, x += step; i < j; i++, x+= step)
+ {
+ y = values[i] / 3;
+ DrawLine((float)i-1, base - lastY, (float)i, base - y);
+ lastY = y;
+ }
+}
+
+
+
+
+
+
+/*
+ * Colourspace mapper editor frame class.
+ */
+
+const int colourspaceFrame::colspc_border = 8;
+const int colourspaceFrame::colspc_width = 450;
+const int colourspaceFrame::colspc_height = 400;
+const int colourspaceFrame::colspc_bwidth = 80;
+const int colourspaceFrame::colspc_bheight = 30;
+const int colourspaceFrame::colspc_twidth = 100;
+const int colourspaceFrame::colspc_theight = 30;
+const int colourspaceFrame::colspc_chkheight = 20;
+const int colourspaceFrame::colspc_chwidth = colourspaceFrame::colspc_twidth - rview_choice_sub_width;
+const int colourspaceFrame::colspc_chheight = 20;
+const int colourspaceFrame::colspc_cheight = colourspaceFrame::colspc_bheight + 4*colourspaceFrame::colspc_theight + 5*colourspaceFrame::colspc_border;
+
+
+colourspaceFrame::colourspaceFrame(colourspaceMapper *parent, const colourspace_params *p) : rviewFrame(NULL, lman->lookup("titleColourspace"), 0, 0, colspc_width, colspc_height)
+{
+ // defaults
+ doImmediateUpdate = TRUE; doDrawSum = TRUE;
+
+ parentObj = parent;
+ memcpy(&newParams, p, sizeof(colourspace_params));
+ memcpy(&origParams, p, sizeof(colourspace_params));
+ canvX = 0; canvY = 0;
+ mousebut = 0; didUpdate = 0;
+
+ canvas = new colourspaceCanvas(this, &newParams, 0, 0, 100, 100, wxBORDER);
+ panel = new wxPanel((wxWindow*)this, 0, 100, 100, 100);
+
+ okBut = new rviewButton(panel);
+ cancelBut = new rviewButton(panel);
+ defaultBut = new rviewButton(panel);
+
+ immediateUpdate = new rviewCheckBox(panel);
+ immediateUpdate->SetValue(doImmediateUpdate);
+ drawSum = new rviewCheckBox(panel);
+ drawSum->SetValue(doDrawSum);
+
+ // the text widgets displaying the current setup
+ posR = new rviewText(panel);
+ posG = new rviewText(panel);
+ posB = new rviewText(panel);
+ sigR = new rviewText(panel);
+ sigG = new rviewText(panel);
+ sigB = new rviewText(panel);
+ minVal = new rviewText(panel);
+ maxVal = new rviewText(panel);
+
+ const char *cstypes[4];
+ cstypes[0] = lman->lookup("cspaceTypeGauss");
+ cstypes[1] = lman->lookup("cspaceTypeLin");
+ cstypes[2] = lman->lookup("cspaceTypeRect");
+ cstypes[3] = lman->lookup("cspaceTypeAsympt");
+ csType = new rviewChoice(panel, 4, cstypes);
+ csType->SetLabel("");
+
+ updateDisplay();
+
+ Show(TRUE);
+
+ label();
+
+ frameWidth = -1; frameHeight = -1;
+ OnSize(colspc_width, colspc_height);
+
+ canvas->enableOutlineSum(doDrawSum);
+}
+
+
+colourspaceFrame::~colourspaceFrame(void)
+{
+ if (parentObj != NULL) parentObj->closeEditor(FALSE);
+}
+
+
+const char *colourspaceFrame::getFrameName(void) const
+{
+ return "colourspaceFrame";
+}
+
+rviewFrameType colourspaceFrame::getFrameType(void) const
+{
+ return rviewFrameTypeCspace;
+}
+
+
+void colourspaceFrame::unlinkParent(void)
+{
+ parentObj = NULL;
+}
+
+
+void colourspaceFrame::setRange(double newMinVal, double newMaxVal)
+{
+ char buffer[STRINGSIZE];
+
+ newParams.minVal = newMinVal; newParams.maxVal = newMaxVal;
+ // Just update the text widgets. Rebuilding the pixmap is done automatically.
+ sprintf(buffer, "%f", newMinVal);
+ minVal->SetValue(buffer);
+ sprintf(buffer, "%f", newMaxVal);
+ maxVal->SetValue(buffer);
+}
+
+
+void colourspaceFrame::OnSize(int w, int h)
+{
+ int x, y, px, py;
+
+ GetClientSize(&x, &y);
+ if ((x == frameWidth) && (y == frameHeight))
+ return;
+
+ frameWidth = x;
+ frameHeight = y;
+ y -= colspc_cheight;
+ canvX = x - 2*colspc_border;
+ canvY = y - 2*colspc_border;
+ canvas->SetSize(colspc_border, colspc_border, canvX, canvY);
+ panel->SetSize(0, y, x, colspc_cheight);
+ px = (x - 3*colspc_twidth) / 5;
+ if(px<0) px=0;
+ py = colspc_border;
+ posR->SetSize(px, py, colspc_twidth, colspc_theight);
+ posG->SetSize(2*px + colspc_twidth, py, colspc_twidth, colspc_theight);
+ posB->SetSize(3*px + 2*colspc_twidth, py, colspc_twidth, colspc_theight);
+ py += colspc_border + colspc_theight;
+ sigR->SetSize(px, py, colspc_twidth, colspc_theight);
+ sigG->SetSize(2*px + colspc_twidth, py, colspc_twidth, colspc_theight);
+ sigB->SetSize(3*px+ 2*colspc_twidth, py, colspc_twidth, colspc_theight);
+ py += colspc_border + colspc_theight;
+ px = (x - 3*colspc_twidth)/4;
+ immediateUpdate->SetSize(px, py, colspc_twidth, colspc_chkheight);
+ drawSum->SetSize(px, py + colspc_chkheight, colspc_twidth, colspc_chkheight);
+ minVal->SetSize(2*px + colspc_twidth, py, colspc_twidth, colspc_theight);
+ maxVal->SetSize(2*px + colspc_twidth, py + colspc_theight, colspc_twidth, colspc_theight);
+ csType->SetSize(3*px + 2*colspc_twidth, py, colspc_chwidth, colspc_chheight);
+ py += colspc_border + 2*colspc_theight;
+ px = (x - 3*colspc_bwidth)/3;
+ okBut->SetSize(px/2, py, colspc_bwidth, colspc_bheight);
+ cancelBut->SetSize((3*px)/2 + colspc_bwidth, py, colspc_bwidth, colspc_bheight);
+ defaultBut->SetSize((5*px)/2 + 2*colspc_bwidth, py, colspc_bwidth, colspc_bheight);
+}
+
+
+void colourspaceFrame::label(void)
+{
+ okBut->SetLabel(lman->lookup("textOK"));
+ cancelBut->SetLabel(lman->lookup("textCancel"));
+ defaultBut->SetLabel(lman->lookup("textDefaults"));
+
+ immediateUpdate->SetLabel(lman->lookup("cspaceImmUpdt"));
+ drawSum->SetLabel(lman->lookup("cspaceDrawSum"));
+
+ posR->SetLabel(lman->lookup("cspacePeakRed"));
+ posG->SetLabel(lman->lookup("cspacePeakGreen"));
+ posB->SetLabel(lman->lookup("cspacePeakBlue"));
+ sigR->SetLabel(lman->lookup("cspaceSigmaRed"));
+ sigG->SetLabel(lman->lookup("cspaceSigmaGreen"));
+ sigB->SetLabel(lman->lookup("cspaceSigmaBlue"));
+ minVal->SetLabel(lman->lookup("cspaceMinVal"));
+ maxVal->SetLabel(lman->lookup("cspaceMaxVal"));
+}
+
+
+void colourspaceFrame::makeUpdate(void)
+{
+ canvas->Redraw();
+ if (doImmediateUpdate)
+ {
+ if (parentObj != NULL) parentObj->colourspaceChanged(&newParams);
+ didUpdate++;
+ }
+}
+
+
+int colourspaceFrame::process(wxObject &obj, wxEvent &evt)
+{
+ int type = evt.GetEventType();
+
+ if (type == wxEVENT_TYPE_BUTTON_COMMAND)
+ {
+ if (&obj == (wxObject*)okBut)
+ {
+ updateSettings();
+ if (parentObj != NULL) parentObj->colourspaceChanged(&newParams);
+ Close(TRUE);
+ return 1;
+ }
+ else if (&obj == (wxObject*)cancelBut)
+ {
+ // return to old values, but we did updates?
+ if (didUpdate != 0)
+ {
+ if (parentObj != NULL) parentObj->colourspaceChanged(&origParams);
+ Close(TRUE);
+ return 1;
+ }
+ if (parentObj != NULL) parentObj->closeEditor();
+ return 1;
+ }
+ else if (&obj == (wxObject*)defaultBut)
+ {
+ const colourspace_params *cp = &(prefs->csp);
+ newParams.peak_red = cp->peak_red;
+ newParams.peak_green = cp->peak_green;
+ newParams.peak_blue = cp->peak_blue;
+ newParams.sigm_red = cp->sigm_red;
+ newParams.sigm_green = cp->sigm_green;
+ newParams.sigm_blue = cp->sigm_blue;
+ newParams.type = cp->type;
+ updateDisplay();
+ makeUpdate();
+ return 1;
+ }
+ }
+ if (type == wxEVENT_TYPE_TEXT_ENTER_COMMAND)
+ {
+ if ((&obj == (wxObject*)posR) || (&obj == (wxObject*)posG) || (&obj == (wxObject*)posB) ||
+ (&obj == (wxObject*)sigR) || (&obj == (wxObject*)sigG) || (&obj == (wxObject*)sigB) ||
+ (&obj == (wxObject*)minVal) || (&obj == (wxObject*)maxVal))
+ {
+ updateSettings();
+ makeUpdate();
+ }
+ }
+ if (type == wxEVENT_TYPE_CHECKBOX_COMMAND)
+ {
+ if (&obj == (wxObject*)immediateUpdate)
+ {
+ doImmediateUpdate = immediateUpdate->GetValue();
+ return 1;
+ }
+ if (&obj == (wxObject*)drawSum)
+ {
+ doDrawSum = drawSum->GetValue();
+ canvas->enableOutlineSum(doDrawSum);
+ return 1;
+ }
+ }
+ if (type == wxEVENT_TYPE_CHOICE_COMMAND)
+ {
+ if (&obj == (wxObject*)csType)
+ {
+ updateSettings();
+ canvas->setDrawingFunction();
+ makeUpdate();
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+void colourspaceFrame::updateSettings(void)
+{
+ newParams.peak_red = atof(posR->GetValue());
+ newParams.peak_green = atof(posG->GetValue());
+ newParams.peak_blue = atof(posB->GetValue());
+ newParams.sigm_red = atof(sigR->GetValue());
+ newParams.sigm_green = atof(sigG->GetValue());
+ newParams.sigm_blue = atof(sigB->GetValue());
+ newParams.minVal = atof(minVal->GetValue());
+ newParams.maxVal = atof(maxVal->GetValue());
+ switch (csType->GetSelection())
+ {
+ case 0: newParams.type = cst_gauss; break;
+ case 1: newParams.type = cst_linear; break;
+ case 2: newParams.type = cst_rectangle; break;
+ case 3: newParams.type = cst_asympt; break;
+ default:
+ cerr << "Unknown colourspace type" << endl;
+ break;
+ }
+}
+
+
+void colourspaceFrame::updateDisplay(const colourspace_params *cp)
+{
+ if (cp != NULL)
+ {
+ memcpy(&newParams, cp, sizeof(colourspace_params));
+ memcpy(&origParams, cp, sizeof(colourspace_params));
+ }
+ posR->SetValue(newParams.peak_red);
+ posG->SetValue(newParams.peak_green);
+ posB->SetValue(newParams.peak_blue);
+ sigR->SetValue(newParams.sigm_red);
+ sigG->SetValue(newParams.sigm_green);
+ sigB->SetValue(newParams.sigm_blue);
+ minVal->SetValue(newParams.minVal);
+ maxVal->SetValue(newParams.maxVal);
+
+ switch (newParams.type)
+ {
+ case cst_linear:
+ csType->SetSelection(1); break;
+ case cst_rectangle:
+ csType->SetSelection(2); break;
+ case cst_asympt:
+ csType->SetSelection(3); break;
+ default:
+ csType->SetSelection(0); break;
+ }
+ canvas->setDrawingFunction();
+ canvas->Redraw();
+}
+
+
+void colourspaceFrame::processMouseEvent(wxMouseEvent &mevt)
+{
+ int type = mevt.GetEventType();
+
+ if ((type == wxEVENT_TYPE_LEFT_DOWN) || (type == wxEVENT_TYPE_RIGHT_DOWN))
+ {
+ float delta;
+
+ mevt.Position(&mousex, &mousey); dragColour = -1;
+ delta = mousex - newParams.peak_red * (canvX -2*colourspaceCanvas::colcanv_cborder) - colourspaceCanvas::colcanv_cborder;
+ if ((delta*delta) <= MOUSE_HOTZONE * MOUSE_HOTZONE) dragColour = 0;
+ else
+ {
+ delta = mousex - newParams.peak_green * (canvX - 2*colourspaceCanvas::colcanv_cborder) - colourspaceCanvas::colcanv_cborder;
+ if ((delta*delta) <= MOUSE_HOTZONE * MOUSE_HOTZONE) dragColour = 1;
+ else
+ {
+ delta = mousex - newParams.peak_blue * (canvX - 2*colourspaceCanvas::colcanv_cborder) - colourspaceCanvas::colcanv_cborder;
+ if ((delta*delta) <= MOUSE_HOTZONE * MOUSE_HOTZONE) dragColour = 2;
+ }
+ }
+ if (dragColour >= 0)
+ {
+ if (type == wxEVENT_TYPE_LEFT_DOWN)
+ mousebut = MOUSE_LEFT;
+ else
+ mousebut = MOUSE_RIGHT;
+ }
+ }
+ else if ((type == wxEVENT_TYPE_MOTION) && (mousebut != 0))
+ {
+ float newx, newy;
+ double *newVal=NULL;
+ rviewText *newText;
+
+ mevt.Position(&newx, &newy);
+
+ // left button & left/right movement: move peak position
+ if ((mousebut & MOUSE_LEFT) != 0)
+ {
+ switch (dragColour)
+ {
+ case 0: newVal = &newParams.peak_red; newText = posR; break;
+ case 1: newVal = &newParams.peak_green; newText = posG; break;
+ case 2: newVal = &newParams.peak_blue; newText = posB; break;
+ default: return;
+ }
+ *newVal = (newx - colourspaceCanvas::colcanv_cborder) / (canvX - 2*colourspaceCanvas::colcanv_cborder);
+ if (*newVal < 0.0) *newVal = 0.0;
+ if (*newVal > 1.0) *newVal = 1.0;
+ }
+ // right button & up/down movement: change variance
+ else if ((mousebut & MOUSE_RIGHT) != 0)
+ {
+ switch (dragColour)
+ {
+ case 0: newVal = &newParams.sigm_red; newText = sigR; break;
+ case 1: newVal = &newParams.sigm_green; newText = sigG; break;
+ case 2: newVal = &newParams.sigm_blue; newText = sigB; break;
+ default: return;
+ }
+ *newVal -= 0.5 * (newy - mousey) / (canvX - 2*colourspaceCanvas::colcanv_cborder);
+ // Must not let sigma become too small (floating exceptions)
+ if (*newVal < 1e-6) *newVal = 1e-6;
+ }
+
+ mousex = newx; mousey = newy;
+
+ if (newVal != NULL)
+ {
+ newText->SetValue(*newVal);
+ canvas->Redraw();
+ if (doImmediateUpdate)
+ {
+ if (parentObj != NULL) parentObj->colourspaceChanged(&newParams);
+ didUpdate++;
+ }
+ }
+ }
+ else
+ {
+ mousebut = 0;
+ }
+}
+
+
+
+
+
+
+// Threshold for lookup table size.
+#define COLOURSPACE_TABLE_THRESHOLD 0x10000
+
+/*
+ * Colourspace mapper class. For mapping large range integer values to RGB space
+ * baseType == rbt_none implies just the colourspace object without an associated MDD
+ */
+colourspaceMapper::colourspaceMapper(r_Ref<r_GMarray> &mdd, rviewBaseType bt, const colourspace_params *cp, bool fullrange, const r_Minterval *domain, unsigned long frange)
+{
+ didRange = FALSE;
+ mddObj = mdd; baseType = bt;
+ IntToRGBTab15 = NULL; IntToRGBTab24 = NULL;
+ csFrame = NULL;
+ if (baseType != rbt_none)
+ {
+ objInterv = mddObj->spatial_domain(); dimMDD = objInterv.dimension();
+ lastInterv = objInterv;
+ }
+ // Defaults
+ if (cp == NULL)
+ {
+ memcpy(&par, &(prefs->csp), sizeof(colourspace_params));
+ }
+ else
+ {
+ memcpy(&par, cp, sizeof(colourspace_params));
+ }
+ par.minVal = 0.0; par.maxVal = 0.0; par.floatRange = frange;
+ rangeModeFull = fullrange; useInterv = domain;
+ scalingFactor = 1.0; // needed for FP types only
+ tableKind = getTableForType(baseType);
+
+ tableType = (cspaceType)-1; // initialize to some illegal value
+ setMappingFunctions();
+
+ processRange((rangeModeFull) ? CSPACE_RANGE_FULL : CSPACE_RANGE_ACTUAL);
+
+ //cout << "mustep " << mustep << ", sigma " << sigma << ", min " << par.minVal << ", max " << par.maxVal << endl;
+}
+
+
+int colourspaceMapper::getTableForType(rviewBaseType bt)
+{
+ int tkind;
+
+ switch (bt)
+ {
+ case rbt_long:
+ case rbt_ulong:
+ case rbt_float:
+ case rbt_double: tkind = 1; break;
+ default: tkind = 0; break;
+ }
+ return tkind;
+}
+
+
+int colourspaceMapper::bindMapper(r_Ref<r_GMarray> &mdd, rviewBaseType bt, bool fullrange, const r_Minterval *domain, const colourspace_params *cp)
+{
+ bool cparChanged;
+
+ if (cp == NULL)
+ cparChanged = 0;
+ else
+ cparChanged =
+ ((cp->peak_red != par.peak_red) || (cp->sigm_red != par.sigm_red) ||
+ (cp->peak_green != par.peak_green) || (cp->sigm_green != par.sigm_green) ||
+ (cp->peak_blue != par.peak_blue) || (cp->sigm_blue != par.sigm_blue) ||
+ (cp->type != par.type));
+
+ if ((mddObj.ptr() == mdd.ptr()) && (bt == baseType) && (fullrange == rangeModeFull) && (domain == useInterv) && (cparChanged == 0))
+ return 0; // nothing to do
+
+ if (cparChanged)
+ {
+ colourspace_params cpar;
+ memcpy(&cpar, cp, sizeof(colourspace_params));
+ cpar.minVal = par.minVal; cpar.maxVal = par.maxVal; cpar.floatRange = par.floatRange;
+ colourspaceChanged(&cpar);
+ if (csFrame != NULL)
+ {
+ csFrame->updateDisplay(&cpar);
+ }
+ }
+
+ if ((mddObj.ptr() != mdd.ptr()) || (bt != baseType))
+ {
+ mddObj = mdd; baseType = bt; useInterv = domain; scalingFactor = 1.0;
+ tableKind = getTableForType(baseType);
+ rangeModeFull = fullrange; didRange = FALSE;
+ processRange((rangeModeFull) ? CSPACE_RANGE_FULL : CSPACE_RANGE_ACTUAL);
+ return 1;
+ }
+ if (fullrange != rangeModeFull)
+ {
+ rangeModeFull = fullrange;
+ processRange((rangeModeFull) ? CSPACE_RANGE_FULL : CSPACE_RANGE_ACTUAL);
+ return 1;
+ }
+ if ((domain != useInterv) || ((domain != NULL) && (*domain != *useInterv)) || (cparChanged != 0))
+ {
+ updateProjection(domain);
+ }
+ return 1;
+}
+
+
+colourspaceMapper::~colourspaceMapper(void)
+{
+ if (IntToRGBTab15 != NULL) delete [] IntToRGBTab15;
+ if (IntToRGBTab24 != NULL) delete [] IntToRGBTab24;
+
+ if (csFrame != NULL)
+ {
+ csFrame->unlinkParent();
+ csFrame->Close(TRUE);
+ }
+}
+
+
+void colourspaceMapper::setMappingFunctions(void)
+{
+ switch (par.type)
+ {
+ default:
+ cerr << "Unknown mapping function, default to gauss" << endl;
+ case cst_gauss:
+ convert15 = &colourspaceMapper::ValToGauss15; convert24 = &colourspaceMapper::ValToGauss24;
+ break;
+ case cst_linear:
+ convert15 = &colourspaceMapper::ValToLinear15; convert24 = &colourspaceMapper::ValToLinear24;
+ break;
+ case cst_rectangle:
+ convert15 = &colourspaceMapper::ValToRectangle15; convert24 = &colourspaceMapper::ValToRectangle24;
+ break;
+ case cst_asympt:
+ convert15 = &colourspaceMapper::ValToAsymptotic15; convert24 = &colourspaceMapper::ValToAsymptotic24;
+ break;
+ }
+}
+
+
+// Visual C compiler bug: with optimizations sigma is undefined when !fullrange
+#ifdef __VISUALC__
+#pragma optimize ("", off)
+#endif
+
+void colourspaceMapper::processRange(int rangeMode)
+{
+ double h;
+
+ if (baseType == rbt_none) return;
+
+ if (rangeMode != CSPACE_RANGE_OLD)
+ {
+ int i;
+
+ lastInterv = (useInterv == NULL) ? objInterv : (*useInterv);
+ rangeModeFull = (rangeMode == CSPACE_RANGE_FULL) ? TRUE : FALSE;
+
+ // The number of projected pixels is a measure whether a lookup table pays off.
+ projPixels = lastInterv[0].high() - lastInterv[0].low() + 1;
+ for (i=1; i<dimMDD; i++)
+ {
+ projPixels *= lastInterv[i].high() - lastInterv[i].low() + 1;
+ }
+
+ // Use the full range of the basetype or the actual range of the object?
+ if (rangeModeFull)
+ {
+ switch (baseType)
+ {
+ case rbt_char: par.minVal = 0.0; par.maxVal = (double)UCHAR_MAX; break;
+ case rbt_uchar: par.minVal = (double)SCHAR_MIN; par.maxVal = (double)SCHAR_MAX; break;
+ case rbt_short: par.minVal = (double)SHRT_MIN; par.maxVal = (double)SHRT_MAX; break;
+ case rbt_ushort: par.minVal = 0.0; par.maxVal = (double)USHRT_MAX; break;
+ case rbt_long: par.minVal = (double)LONG_MIN; par.maxVal = (double)LONG_MAX; break;
+ case rbt_ulong: par.minVal = 0.0; par.maxVal = (double)ULONG_MAX; break;
+ // MIN/MAX or DBL and FLT are unsigned, i.e. MIN is the smallest number > 0!
+ case rbt_float: par.minVal = (double)(-FLT_MAX); par.maxVal = (double)FLT_MAX; break;
+ case rbt_double: par.minVal = (double)(-DBL_MAX); par.maxVal = (double)DBL_MAX; break;
+ default: break;
+ }
+ }
+ else
+ {
+ if (!didRange)
+ {
+ int state;
+
+ ::wxBeginBusyCursor();
+ state = mdd_objectRange(mddObj, lastInterv, realMinVal, realMaxVal);
+ ::wxEndBusyCursor();
+ if (state == 0)
+ {
+ realMinVal = 0.0; realMaxVal = 1.0;
+ }
+ //cout << lastInterv << ": " << realMinVal << ", " << realMaxVal << endl;
+ didRange = TRUE;
+ }
+ par.minVal = realMinVal; par.maxVal = realMaxVal;
+ }
+ if (csFrame != NULL)
+ {
+ csFrame->setRange(par.minVal, par.maxVal);
+ }
+ }
+
+ if ((baseType == rbt_float) || (baseType == rbt_double))
+ {
+ // Avoid overflows; min/max could be the lowest/highest values, so the difference is NaN!
+ h = ((par.maxVal) / 256.0) - ((par.minVal) / 256.0);
+ if (h == 0.0) h = 1.0;
+ scalingFactor = ((par.floatRange - 1) / 256.0 ) / h;
+ }
+
+ h = (par.maxVal - par.minVal);
+ peakR = h * par.peak_red; peakG = h * par.peak_green; peakB = h * par.peak_blue;
+ invSigR = 1.0 / (h * par.sigm_red); invSigG = 1.0 / (h * par.sigm_green); invSigB = 1.0 / (h * par.sigm_blue);
+
+ buildCSTab15(TRUE); buildCSTab24(TRUE);
+}
+
+#ifdef __VISUALC__
+#pragma optimize ("", on)
+#endif
+
+
+void colourspaceMapper::updateProjection(const r_Minterval *domain)
+{
+ if (!rangeModeFull)
+ {
+ if ((domain == NULL) && (useInterv == NULL)) return;
+ if (domain != NULL)
+ {
+ int i;
+
+ for (i=0; i<dimMDD; i++)
+ {
+ if ((lastInterv[i].low() != (*domain)[i].low()) ||
+ (lastInterv[i].high() != (*domain)[i].high()))
+ break;
+ }
+ // All equal ==> nothing to do
+ if (i >= dimMDD) return;
+ }
+
+ didRange = FALSE;
+ useInterv = domain;
+ processRange(CSPACE_RANGE_ACTUAL);
+ }
+}
+
+
+
+/*
+ * Shortcuts for defining convertor functions
+ */
+#define CSPACE_CONVERT(returntype, funcname, convname, rgbname) \
+ returntype colourspaceMapper::funcname(double value) \
+ { \
+ unsigned int red, green, blue; \
+ blue = (unsigned int)(255.99*convname(value, peakB, invSigB)); \
+ green = (unsigned int)(255.99*convname(value, peakG, invSigG)); \
+ red = (unsigned int)(255.99*convname(value, peakR, invSigR)); \
+ return rgbname(red, green, blue); \
+ }
+
+#define CSPACE_CONVERT15(funcname, convname) \
+ CSPACE_CONVERT(unsigned short, funcname, convname, RGBL_TO_PALETTE_SHORT)
+#define CSPACE_CONVERT24(funcname, convname) \
+ CSPACE_CONVERT(unsigned long, funcname, convname, RGB_TO_PALETTE_LONG)
+
+CSPACE_CONVERT15(ValToGauss15, valueToGauss)
+CSPACE_CONVERT24(ValToGauss24, valueToGauss)
+CSPACE_CONVERT15(ValToLinear15, valueToLinear)
+CSPACE_CONVERT24(ValToLinear24, valueToLinear)
+CSPACE_CONVERT15(ValToRectangle15, valueToRectangle)
+CSPACE_CONVERT24(ValToRectangle24, valueToRectangle)
+CSPACE_CONVERT15(ValToAsymptotic15, valueToAsymptotic)
+CSPACE_CONVERT24(ValToAsymptotic24, valueToAsymptotic)
+
+
+
+
+unsigned short *colourspaceMapper::buildCSTab15(bool forceRebuild)
+{
+ int i, j;
+ double val;
+
+ // Don't build a 15bpp table if it's not needed
+ if (tableKind != 0) return NULL;
+
+ if (IntToRGBTab15 != NULL)
+ {
+ if ((!forceRebuild) && (tableType == par.type)) return IntToRGBTab15;
+ delete [] IntToRGBTab15; IntToRGBTab15 = NULL;
+ }
+
+ // The code always assumes a table for this depth!
+ //if ((par.maxVal - par.minVal + 1) > (double)COLOURSPACE_TABLE_THRESHOLD) return NULL;
+ j = (int)((par.maxVal - par.minVal) * scalingFactor) + 1;
+
+ IntToRGBTab15 = new unsigned short[j];
+ for (i=0, val=0.0; i<j; i++, val += scalingFactor)
+ {
+ IntToRGBTab15[i] = ValToCS15(val);
+ }
+ tableType = par.type;
+ return IntToRGBTab15;
+}
+
+
+
+unsigned long *colourspaceMapper::buildCSTab24(bool forceRebuild)
+{
+ int i, j;
+ double val;
+ double invScale;
+
+ // Don't build a 32bpp table if it's not needed
+ if (tableKind == 0) return NULL;
+
+ if (IntToRGBTab24 != NULL)
+ {
+ if ((!forceRebuild) && (tableType == par.type)) return IntToRGBTab24;
+ delete [] IntToRGBTab24; IntToRGBTab24 = NULL;
+ }
+
+ j = (int)((par.maxVal - par.minVal) * scalingFactor) + 1;
+ if (j > COLOURSPACE_TABLE_THRESHOLD) return NULL;
+
+ // If we use the range of the current projection and there are fewer visible pixels than
+ // table entries then don't build a table (or we'd sacrifice a lot of speed)
+ if ((!rangeModeFull) && (useInterv != NULL) && (j > projPixels)) return NULL;
+
+ invScale = (scalingFactor == 0.0) ? 1.0 : 1/scalingFactor;
+ IntToRGBTab24 = new unsigned long[j];
+ for (i=0, val=0.0; i<j; i++, val += invScale)
+ {
+ IntToRGBTab24[i] = ValToCS24(val);
+ }
+ tableType = par.type;
+ return IntToRGBTab24;
+}
+
+
+
+double colourspaceMapper::getMinVal(void)
+{
+ return par.minVal;
+}
+
+
+double colourspaceMapper::getMaxVal(void)
+{
+ return par.maxVal;
+}
+
+
+double colourspaceMapper::getScalingFactor(void)
+{
+ return scalingFactor;
+}
+
+
+unsigned short *colourspaceMapper::getCSTab15(void)
+{
+ return IntToRGBTab15;
+}
+
+
+unsigned long *colourspaceMapper::getCSTab24(void)
+{
+ return IntToRGBTab24;
+}
+
+
+void colourspaceMapper::colourspaceChanged(const colourspace_params *newParams, bool autoUpdate)
+{
+ user_event ue;
+
+ memcpy(&par, newParams, sizeof(colourspace_params));
+ setMappingFunctions();
+ processRange(CSPACE_RANGE_OLD);
+
+ if (csFrame != NULL)
+ csFrame->updateDisplay(newParams);
+
+ if (autoUpdate)
+ {
+ // Notify whoever owns this object that its settings have changed (can't have one
+ // specific type of parent because it can be owned by images, thumbnails, prefs, ...)
+ ue.type = usr_cspace_changed;
+ ue.data = (void*)this;
+ //parentFrame->userEvent(ue);
+ if (frameManager != NULL)
+ frameManager->broadcastUserEvent(ue);
+ }
+}
+
+
+void colourspaceMapper::openEditor(void)
+{
+ if (csFrame != NULL) return;
+
+ csFrame = new colourspaceFrame(this, &par);
+}
+
+
+void colourspaceMapper::closeEditor(bool activeClose)
+{
+ if (activeClose) csFrame->Close(TRUE);
+ csFrame = NULL;
+}
+
+
+void colourspaceMapper::getParameters(colourspace_params *dest)
+{
+ if (csFrame != NULL)
+ {
+ csFrame->updateSettings();
+ }
+ memcpy(dest, &par, sizeof(colourspace_params));
+}
diff --git a/applications/rview/rviewColMap.hh b/applications/rview/rviewColMap.hh
new file mode 100644
index 0000000..a217e23
--- /dev/null
+++ b/applications/rview/rviewColMap.hh
@@ -0,0 +1,254 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+ * PURPOSE:
+ * Class definitions for the colourspace mapping.
+ * COMMENTS:
+ * No comments
+ */
+
+
+#ifndef _RVIEW_COLMAP_H_
+#define _RVIEW_COLMAP_H_
+
+
+#include "rviewUtils.hh"
+
+
+
+class colourspaceMapper;
+class colourspaceFrame;
+
+
+enum cspaceType {
+ cst_gauss,
+ cst_linear,
+ cst_rectangle,
+ cst_asympt
+};
+
+typedef struct colourspace_params_s {
+ double peak_red, peak_green, peak_blue;
+ double sigm_red, sigm_green, sigm_blue;
+ double minVal, maxVal;
+ unsigned long floatRange;
+ cspaceType type;
+} colourspace_params;
+
+
+/*
+ * Colourspace configuration canvas
+ */
+class colourspaceCanvas: public wxCanvas
+{
+ public:
+
+ colourspaceCanvas(colourspaceFrame *parent, colourspace_params *p, int x, int y, int w, int h, long style=0);
+ ~colourspaceCanvas(void);
+
+ void enableOutlineSum(bool enable);
+ void setDrawingFunction(void);
+
+ void Redraw(void);
+
+ void OnSize(int w, int h);
+ void OnPaint(void);
+ void OnEvent(wxMouseEvent &mevt);
+
+ // constants
+ // Colourspace canvas border
+ static const int colcanv_cborder;
+ // Height of markers on colourspace canvas
+ static const int colcanv_mheight;
+
+
+ protected:
+
+ int setupRectangle(int &from, int &to, float &x, wxRect *rect);
+ void drawOutline(double peak, double sigma, wxPen *pen, wxRect *rect);
+ void drawOutlineSum(wxPen *pen, wxRect *rect);
+ // Function pointer
+ double (*conversionFunction)(double, double, double);
+
+ colourspaceFrame *parentObj;
+ colourspace_params *params;
+ int canvX, canvY;
+ wxBrush brush;
+ wxPen redPen, greenPen, bluePen, blackPen;
+ wxFont *font;
+ float *values;
+ float height, base, step;
+ int cmin, cmax;
+};
+
+
+/*
+ * Colourspace configuration window
+ */
+class colourspaceFrame: public rviewFrame
+{
+ public:
+
+ colourspaceFrame(colourspaceMapper *parent, const colourspace_params *p);
+ ~colourspaceFrame(void);
+
+ void setRange(double newMinVal, double newMaxVal);
+ void unlinkParent(void);
+
+ void OnSize(int w, int h);
+
+ void label(void);
+ int process(wxObject &obj, wxEvent &evt);
+
+ void updateSettings(void);
+ void updateDisplay(const colourspace_params *cp=NULL);
+ void processMouseEvent(wxMouseEvent &mevt);
+
+ virtual const char *getFrameName(void) const;
+ virtual rviewFrameType getFrameType(void) const;
+
+ // constants
+ // Colourspace editor borders
+ static const int colspc_border;
+ // Colourspace editor window
+ static const int colspc_width;
+ static const int colspc_height;
+ // Colourspace buttons
+ static const int colspc_bwidth;
+ static const int colspc_bheight;
+ // Colourspace text widgets
+ static const int colspc_twidth;
+ static const int colspc_theight;
+ // Colourspace checkbox widgets
+ static const int colspc_chkheight;
+ // Colourspace choice widgets
+ static const int colspc_chwidth;
+ static const int colspc_chheight;
+ // Colourspace control panel height
+ static const int colspc_cheight;
+
+
+ private:
+
+ void makeUpdate(void);
+
+ colourspaceMapper *parentObj;
+ colourspace_params newParams;
+ colourspace_params origParams; // in case of immediate update
+
+ colourspaceCanvas *canvas;
+ wxPanel *panel;
+ rviewText *posR, *posG, *posB;
+ rviewText *sigR, *sigG, *sigB;
+ rviewButton *okBut, *cancelBut, *defaultBut;
+ rviewCheckBox *immediateUpdate;
+ rviewCheckBox *drawSum;
+ rviewText *minVal, *maxVal;
+ rviewChoice *csType;
+ bool doImmediateUpdate;
+ bool doDrawSum;
+ cspaceType cstype;
+ float mousex, mousey;
+ int mousebut;
+ int dragColour;
+ int canvX, canvY;
+ int didUpdate;
+};
+
+
+// modes for calling processRange
+#define CSPACE_RANGE_ACTUAL 0
+#define CSPACE_RANGE_FULL 1
+#define CSPACE_RANGE_OLD 2
+
+/*
+ * Class for mapping large range values to RGB colourspace,
+ * implemented in rviewImage.cpp
+ */
+class colourspaceMapper
+{
+ public:
+
+ colourspaceMapper(r_Ref<r_GMarray> &mdd, rviewBaseType bt, const colourspace_params *cp, bool fullrange=FALSE, const r_Minterval *domain=NULL, unsigned long frange=0x10000);
+ ~colourspaceMapper(void);
+
+ void getObject(r_Ref<r_GMarray> &mdd, rviewBaseType &bt, bool *fullrange=NULL, r_Minterval **domain=NULL) const;
+ int bindMapper(r_Ref<r_GMarray> &mdd, rviewBaseType bt, bool fullrange=FALSE, const r_Minterval *domain=NULL, const colourspace_params *cp=NULL);
+
+ inline unsigned short ValToCS15(double value) {return (this->*convert15)(value);}
+ inline unsigned long ValToCS24(double value) {return (this->*convert24)(value);}
+ unsigned short *buildCSTab15(bool forceRebuild=FALSE);
+ unsigned long *buildCSTab24(bool forceRebuild=FALSE);
+ double getMinVal(void);
+ double getMaxVal(void);
+ double getScalingFactor(void);
+ unsigned short *getCSTab15(void);
+ unsigned long *getCSTab24(void);
+ void processRange(int rangeMode);
+ void updateProjection(const r_Minterval *domain);
+ void colourspaceChanged(const colourspace_params *newParams, bool autoUpdate=TRUE);
+ void openEditor(void);
+ void closeEditor(bool activeClose=TRUE);
+ void getParameters(colourspace_params *dest);
+ void setMappingFunctions(void);
+
+
+ protected:
+
+ static int getTableForType(rviewBaseType bt);
+
+ unsigned short ValToGauss15(double value);
+ unsigned long ValToGauss24(double value);
+ unsigned short ValToLinear15(double value);
+ unsigned long ValToLinear24(double value);
+ unsigned short ValToRectangle15(double value);
+ unsigned long ValToRectangle24(double value);
+ unsigned short ValToAsymptotic15(double value);
+ unsigned long ValToAsymptotic24(double value);
+ // function pointers
+ unsigned short (colourspaceMapper::*convert15)(double value);
+ unsigned long (colourspaceMapper::*convert24)(double value);
+
+ colourspace_params par; // all the important parameters
+ double realMinVal, realMaxVal; // actual range of object
+ bool didRange;
+ bool rangeModeFull;
+ double peakR, peakG, peakB;
+ double invSigR, invSigG, invSigB;
+ double scalingFactor;
+ int dimMDD;
+ int tableKind; // 15 or 24bpp tables?
+ unsigned short *IntToRGBTab15;
+ unsigned long *IntToRGBTab24;
+ cspaceType tableType;
+ colourspaceFrame *csFrame;
+ r_Ref<r_GMarray> mddObj;
+ rviewBaseType baseType;
+ long projPixels;
+ r_Minterval objInterv;
+ r_Minterval lastInterv;
+ const r_Minterval *useInterv;
+};
+
+#endif
diff --git a/applications/rview/rviewDModes.hh b/applications/rview/rviewDModes.hh
new file mode 100644
index 0000000..67c8807
--- /dev/null
+++ b/applications/rview/rviewDModes.hh
@@ -0,0 +1,1094 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+ * PURPOSE:
+ *
+ * Class definitions for the regular object viewers and their support
+ * classes:
+ * - rviewImage hierarchy, including pixmapCanvas, rendererControl
+ * and rviewImageSetup. Source in rviewImage.cpp.
+ * - rviewChart (chartCanvas). Source in rviewChart.cpp.
+ * - rviewTable (tableCanvas). Source in rviewTable.cpp.
+ * COMMENTS:
+ * None
+ */
+
+
+#ifndef _RVIEW_DMODES_H_
+#define _RVIEW_DMODES_H_
+
+
+
+
+#include "rasodmg/ref.hh"
+#include "rasodmg/marray.hh"
+#include "rasodmg/gmarray.hh"
+
+#include "labelManager.hh"
+#include "rviewUtils.hh"
+#include "rviewDisplay.hh"
+#include "rviewColMap.hh"
+
+
+
+#ifdef __VISUALC__
+struct vertex;
+struct vertex_fp;
+struct graph_env;
+struct tex_desc;
+struct voxel_desc;
+struct mesh_desc;
+struct mdd_desc;
+#else
+typedef struct vertex;
+typedef struct vertex_fp;
+typedef struct graph_env;
+typedef struct tex_desc;
+typedef struct voxel_desc;
+typedef struct mesh_desc;
+typedef struct mdd_desc;
+#endif
+
+
+
+
+
+class rviewImage;
+class rviewRenderImage;
+
+
+
+// Possible display formats
+enum rviewImageMode {
+ rim_none,
+ rim_surf,
+ rim_voxel
+};
+
+
+// Flags for light direction
+#define RVIEW_LIGHTDIR_LEFT 1
+#define RVIEW_LIGHTDIR_RIGHT 2
+#define RVIEW_LIGHTDIR_DOWN 4
+#define RVIEW_LIGHTDIR_UP 8
+#define RVIEW_LIGHTDIR_FRONT 16
+#define RVIEW_LIGHTDIR_BACK 32
+
+typedef struct rview_image_setup {
+ unsigned long zpro, clipz;
+ double pixelThresholdLow, pixelThresholdHigh, weightThreshold;
+ int weightQuantisation;
+ bool useRgbBrightness;
+ bool useLights;
+ double lightsAmbient;
+ double lightsGain;
+ double lightsAngle;
+ double lightsScintAngle;
+ int lightsDir;
+ int lightsDist;
+ int kernelSize, kernelType;
+ bool useVoxCol;
+ double voxColour;
+ int gridSize;
+ double scaleHeight;
+} rview_image_setup;
+
+
+/*
+ * Image setup window for customizing the renderer.
+ */
+class rviewImageSetup: public rviewFrame
+{
+ public:
+
+ rviewImageSetup(rview_image_setup *ris, rviewRenderImage *parentWin);
+ ~rviewImageSetup(void);
+
+ void unlinkParent(void);
+
+ void OnSize(int w, int h);
+
+ void label(void);
+ int process(wxObject &obj, wxEvent &evt);
+
+ void updateSettings(const rview_image_setup &ris);
+ void readNewSetup(void);
+
+ virtual const char *getFrameName(void) const;
+ virtual rviewFrameType getFrameType(void) const;
+
+ static int parseLightDirection(const char *dir);
+
+ // constants
+ // Borders used in setup window
+ static const int imgset_border;
+ // Height of text widgets in setup window
+ static const int imgset_theight;
+ // Height of checkboxes in setup window
+ static const int imgset_chkheight;
+ // Height of group boxes in setup window
+ static const int imgset_renheight;
+ static const int imgset_voxheight;
+ static const int imgset_hgtheight;
+ // Dimensions of buttons in setup window
+ static const int imgset_bwidth;
+ static const int imgset_bheight;
+ // Dimensions of checkboxes in setup window
+ static const int imgset_chowidth;
+ static const int imgset_choheight;
+ // Setup window dimensions
+ static const int imgset_width;
+ static const int imgset_height;
+
+
+ protected:
+
+ rviewRenderImage *parent;
+ wxPanel *panel;
+ wxGroupBox *renderGroup, *voxelGroup, *heightGroup;
+ rviewText *zproWidget, *clipzWidget;
+ rviewText *pixThreshLowWidget, *pixThreshHighWidget, *wgtThreshWidget, *wgtQuantWidget;
+ rviewCheckBox *useRgbBrightness;
+ rviewCheckBox *useLights;
+ rviewChoice *kernelSize, *kernelType;
+ rviewText *lightsAmbient, *lightsGain, *lightsAngle, *lightsScintAngle;
+ rviewText *lightsDir, *lightsDist;
+ rviewCheckBox *useVoxCol;
+ rviewText *voxColour;
+ rviewText *gridSize, *scaleHeight;
+ rviewButton *okBut, *cancelBut;
+ rview_image_setup oldSetup, *imgSetup;
+
+ static const char *normalKernelSizes[];
+ static const keyword_to_ident_c normalKernelTypes[];
+};
+
+
+
+/*
+ * Renderer playback control window
+ */
+class rendererControl: public rviewFrame
+{
+ public:
+
+ rendererControl(float drx, float dry, float drz, int mode, rviewRenderImage *parentWin);
+ ~rendererControl(void);
+
+ void unlinkParent(void);
+ void setActiveMode(int mode);
+
+ void OnSize(int w, int h);
+
+ void label(void);
+ int process(wxObject &obj, wxEvent &evt);
+
+ virtual const char *getFrameName(void) const;
+ virtual rviewFrameType getFrameType(void) const;
+
+ // constants
+ // Borders used in renderer control window
+ static const int rctrl_border;
+ // Button dimensions
+ static const int rctrl_bwidth;
+ static const int rctrl_bheight;
+ // Reset button dimensions
+ static const int rctrl_rwidth;
+ static const int rctrl_rheight;
+ // Slider height
+ static const int rctrl_sheight;
+ // Window dimensions
+ static const int rctrl_width;
+ static const int rctrl_height;
+
+
+ protected:
+
+ void updateParameters(void);
+
+ wxPanel *panel;
+ rviewSlider *rotx, *roty, *rotz;
+ rviewButton *resetX, *resetY, *resetZ;
+ rviewButton *actionBut, *closeBut;
+ rviewRenderImage *parent;
+ int active;
+};
+
+
+/*
+ * Renderer current view window (rotation, offset, scale)
+ */
+class rendererCurrentView: public rviewFrame
+{
+ public:
+
+ rendererCurrentView(const vertex_fp &angles, long off, double scale, rviewRenderImage *parentWin);
+ ~rendererCurrentView(void);
+
+ void unlinkParent(void);
+
+ void OnSize(int w, int h);
+
+ void label(void);
+ int process(wxObject &obj, wxEvent &evt);
+
+ virtual const char *getFrameName(void) const;
+ virtual rviewFrameType getFrameType(void) const;
+
+ void updateView(const vertex_fp &angles, long off, double scale);
+
+ // constants
+ // Borders used in renderer view window
+ static const int rcview_border;
+ // Button dimensions
+ static const int rcview_bwidth;
+ static const int rcview_bheight;
+ // Text widget height
+ static const int rcview_theight;
+ // Window dimensions
+ static const int rcview_width;
+ static const int rcview_height;
+
+
+ protected:
+
+ void updateParameters(void);
+
+ wxPanel *panel;
+ rviewButton *applyButton, *closeButton;
+ rviewText *rotx, *roty, *rotz;
+ rviewText *zoff;
+ rviewText *cubeScale;
+ rviewRenderImage *parent;
+};
+
+
+
+class wxPixmap;
+
+/*
+ * Container class for wxPixmap.
+ */
+class pixmapCanvas: public wxCanvas
+{
+ public:
+
+ pixmapCanvas(rviewImage *parent, int x, int y, int w, int h, long style=0);
+ ~pixmapCanvas(void);
+
+ void setPixmap(wxPixmap *pmap);
+ void updateDisplay(bool borders=FALSE);
+
+ void OnPaint(void);
+ void OnEvent(wxMouseEvent &mevt);
+
+ void SetAspectRatio(double ratio); // 0 for none
+ void ToggleDragBox(bool clearMode);
+ void SetDragBox(int x0, int y0, int x1, int y1);
+ bool HasDragBox(void) const;
+ bool GetDragBox(int &x0, int &y0, int &x1, int &y1) const;
+ void UpdateDragBox(int x1, int y1);
+ void AdjustDragBox(int x1, int y1);
+
+
+ protected:
+
+ void paintCore(int x, int y);
+ void adjustBoxToRatio(void);
+
+ wxPixmap *pixmap;
+ wxDC *myDC;
+ wxBrush brush;
+ wxBrush border;
+ wxBrush textBack;
+ wxPen bpen;
+ wxPen fpen;
+ wxFont *font;
+ rviewImage *parentWin;
+ int pixWidth, pixHeight;
+ int offX, offY;
+ int rect_x0, rect_y0, rect_x1, rect_y1;
+ double aspectRatio;
+ wxRect textBBox;
+};
+
+
+// Flags used when settings are updated
+#define RVIEW_IFLAG_VOXEL 1
+#define RVIEW_IFLAG_LIGHT 2
+#define RVIEW_IFLAG_HEIGHT 4
+
+/*
+ * Abstract base class for all windows containing an image + controls
+ */
+class rviewImage: public rviewDisplay
+{
+ public:
+
+ rviewImage(mdd_frame *mf, int es, unsigned int flags=0);
+ virtual ~rviewImage(void);
+
+ virtual int openViewer(void);
+
+ virtual void label(void);
+ virtual int process(wxObject &obj, wxEvent &evt);
+ virtual void processMouseEvent(wxMouseEvent &mevt);
+ virtual int userEvent(const user_event &ue);
+ virtual void prepareToDie(void);
+ virtual int newProjection(void)=0;
+ virtual int requestQuit(int level);
+
+ virtual void OnSize(int w, int h);
+ virtual void OnMenuCommand(int id);
+ virtual bool OnClose(void); // overload from rviewFrame
+
+ virtual const char *getFrameName(void) const;
+ virtual rviewFrameType getFrameType(void) const;
+
+ // Default flags for wxPixmap class (dithering etc)
+ static int getPixmapFlags(void);
+
+ // constants
+ // Slider dimensions
+ static const int image_swidth;
+ static const int image_sheight;
+ // Playback buttons dimensions
+ static const int image_pbwidth;
+ static const int image_pbheight;
+ // Minimum size of image
+ static const int image_minwidth;
+ static const int image_minheight;
+ // Checkbox dimensions
+ static const int image_chkwidth;
+ static const int image_chkheight;
+ // Bounding box checkbox dimensions
+ static const int image_bbwidth;
+ static const int image_bbheight;
+ // Text field dimensions
+ static const int image_twidth;
+ static const int image_theight;
+ // Button dimensions
+ static const int image_bwidth;
+ static const int image_bheight;
+ // Offsets of drag box in canvas
+ static const int image_dragtoff;
+ static const int image_dragtspace;
+ // Distance from the border at which to autoscroll
+ static const int image_draghotzone;
+ // Extra space reserved on control panel
+ static const int image_ctrly;
+ static const int image_totaly;
+
+
+ protected:
+
+ void updatePixmap(char *oldData, char *newData);
+ void configureCspace(bool state);
+ void setCspaceProjMode(bool pmode);
+ void resizeImage(void);
+ void openViewerEpilogue(rviewFrameType ft);
+ int freeDimsFromProjection(int &dim1, int &dim2, r_Point *map);
+ void ensureViewCspace(void);
+ void deleteViewCspace(void);
+ virtual void projectObjectHook(void);
+ virtual void configureMode(void);
+ virtual char *initMode(void)=0;
+ virtual bool cspaceRangeHook(bool suggest);
+ virtual char *movieNewFrame(void);
+ virtual void rotateObject(wxMouseEvent &mevt);
+ virtual int fileMenuInitHook(wxMenu *menu);
+ virtual int configMenuInitHook(wxMenu *menu);
+ // Query viewer capabilities
+ virtual bool modeNeedsCspace(rviewBaseType bt) const;
+ virtual bool canRotateObject(void) const;
+ virtual bool moviePossible(void) const;
+ virtual bool showScaleSlider(void) const;
+ // view management
+ virtual int saveView(FILE *fp);
+ virtual int readView(const char *key, const char *value);
+ virtual void loadViewFinished(void);
+
+ wxPixmap *pixmap;
+ pixmapCanvas *pcanv;
+ rviewSlider *scaleSlider;
+ int pixWidth, pixHeight, pixPitch, pixPad, pixDepth;
+ int virtualPitch;
+ char *imgData;
+ double scaleValue;
+ int scrollx, scrolly;
+ float mousex, mousey;
+ int mousebut;
+ unsigned int freeDims;
+ // For intensity to RGB translations (ushort)
+ colourspaceMapper *csmap;
+ bool doValToCspace;
+ bool doFullRangeCspace;
+ bool doProjRangeCspace;
+ // base type allows cspace mapping?
+ bool cspaceForType;
+ // image fully initialized?
+ bool initPhaseFinished;
+ r_Minterval *csInterv;
+ // shared by flat and height field which don't have a shared derivation path
+ rviewButton *playFwd, *playBack, *playStop;
+ int playDirection;
+ int lastMovieMode;
+ // colourspace parameters for view loading
+ colourspace_params *cspar;
+
+ // view parameters
+ static const char *view_ScrollPos;
+ static const char *view_UseCspace;
+ static const char *view_CspaceFull;
+ static const char *view_CspaceProj;
+ static const char *view_CspaceMeans;
+ static const char *view_CspaceSigmas;
+ static const char *view_CspaceType;
+ static const char *view_CspaceRange;
+ static const char *view_ScaleValue;
+};
+
+
+/*
+ * Base class for flat images, i.e. 2D orthogonal projections
+ */
+class rviewFlatBaseImage: public rviewImage
+{
+ public:
+
+ rviewFlatBaseImage(mdd_frame *mf, int es, unsigned int flags=0);
+ virtual ~rviewFlatBaseImage(void);
+
+ virtual int newProjection(void);
+ virtual int openViewer(void);
+
+ virtual const char *getFrameName(void) const;
+ virtual rviewFrameType getFrameType(void) const;
+
+
+ protected:
+
+ virtual char *initMode(void);
+ char *projectImage(void);
+};
+
+
+/*
+ * Standard flat images
+ */
+class rviewFlatImage: public rviewFlatBaseImage
+{
+ public:
+
+ rviewFlatImage(mdd_frame *mf, unsigned int flags=0);
+ ~rviewFlatImage(void);
+
+ void OnSize(int w, int h);
+
+ virtual int openViewer(void);
+ virtual void label(void);
+ virtual int process(wxObject &obj, wxEvent &evt);
+
+ virtual const char *getFrameName(void) const;
+ virtual rviewFrameType getFrameType(void) const;
+ virtual int getViewerType(void) const;
+
+
+ protected:
+
+ virtual char *initMode(void);
+ virtual bool moviePossible(void) const;
+ virtual char *movieNewFrame(void);
+};
+
+
+/*
+ * Abstract base class for all rendered images (voxel, height field, whatever...)
+ */
+class rviewRenderImage: public rviewImage
+{
+ public:
+
+ rviewRenderImage(mdd_frame *mf, int es, unsigned int flags=0);
+ virtual ~rviewRenderImage(void);
+
+ virtual void label(void);
+ virtual int process(wxObject &obj, wxEvent &evt);
+ virtual int newProjection(void);
+ virtual void prepareToDie(void);
+ virtual int requestQuit(int level);
+ virtual int userEvent(const user_event &ue);
+ virtual void OnSize(int w, int h);
+ virtual void OnMenuCommand(int id);
+ virtual bool OnClose(void);
+
+ virtual const char *getFrameName(void) const;
+ virtual rviewFrameType getFrameType(void) const;
+
+ void closeEditor(bool newSetup);
+ void updateSettings(int setFlags);
+
+ void closeRendererControls(void);
+ void setAutoRotation(float rx, float ry, float rz);
+ void setCurrentView(const vertex_fp &angles, long off, double scale);
+
+
+ protected:
+
+ virtual char *initMode(void);
+ virtual char *setupEnvironment(int w, int h)=0;
+ virtual void rotateObject(wxMouseEvent &mevt);
+ virtual bool doUpdate(int updateFlags)=0;
+ virtual void redrawSettingsChanged(void);
+ virtual void fillBuffer(void)=0;
+ virtual void fillBackgroundCore(rviewBaseType bt, double minVal);
+ virtual int configMenuInitHook(wxMenu *menu);
+ virtual int viewMenuInitHook(wxMenu *menu);
+ virtual bool canRotateObject(void) const;
+ virtual void updateCurrentView(void);
+
+ int setupEnvBase(int w, int h, r_Ref<r_GMarray> &mdd, colourspaceMapper **csm, r_Minterval *csdom);
+ char *setupGraphEnv(void);
+ void fillBufferBackground(bool doCspace, bool &cspaceOK, r_Ref<r_GMarray>& obj, colourspaceMapper **csm, r_Minterval *csdom, rviewBaseType bt, bool fullRange, double *useMinVal=NULL);
+ void translateBufferToCspace(rviewBaseType bt, double *useMinVal=NULL, double *useMaxVal=NULL);
+ static void rotateCube(int axis, float angle, vertex_fp *matrix);
+ void rotateCube(int axis, float angle);
+ void getLightPos(vertex_fp *lpos);
+
+ virtual int saveView(FILE *fp);
+ virtual int readView(const char *key, const char *value);
+ virtual void loadViewFinished(void);
+
+ // convert rotation matrix to angles and back
+ void matrixToAngles(vertex_fp &angles) const;
+ void anglesToMatrix(const vertex_fp &angles);
+
+ int rendererPlayback;
+ vertex_fp *geomData, *geomUse;
+ vertex_fp *rot;
+ graph_env *graphEnv;
+ union {unsigned long l; float f; double d;} voxColour;
+ long zoff;
+ double cubeScale;
+ // Rotation angle increments for renderer playback
+ float drx, dry, drz;
+ // Setup options
+ rview_image_setup setup;
+ rviewImageSetup *setupWindow;
+ rendererControl *rcontrol;
+ rendererCurrentView *rcurview;
+
+ // view keywords
+ static const char *view_ZProject;
+ static const char *view_ZClip;
+ static const char *view_PixThreshLow;
+ static const char *view_PixThreshHigh;
+ static const char *view_WeightThresh;
+ static const char *view_WeightQuant;
+ static const char *view_UseRGBBright;
+ static const char *view_UseLighting;
+ static const char *view_LightAmbient;
+ static const char *view_LightGain;
+ static const char *view_LightAngle;
+ static const char *view_LightScint;
+ static const char *view_LightDir;
+ static const char *view_LightDist;
+ static const char *view_KernelSize;
+ static const char *view_KernelType;
+ static const char *view_UseVoxColour;
+ static const char *view_VoxColour;
+ static const char *view_GridSize;
+ static const char *view_ScaleHeight;
+ static const char *view_Rotation;
+ static const char *view_ZOffset;
+};
+
+
+/*
+ * Class for visualizations of volumetric images (3D texture mapper &
+ * voxel renderer).
+ */
+class rviewVolumeImage: public rviewRenderImage
+{
+ public:
+
+ rviewVolumeImage(mdd_frame *mf, unsigned int flags=0);
+ virtual ~rviewVolumeImage(void);
+
+ virtual void label(void);
+ virtual int process(wxObject &obj, wxEvent &evt);
+ virtual void OnSize(int w, int h);
+ virtual void OnMenuCommand(int id);
+ virtual int openViewer(void);
+
+ virtual const char *getFrameName(void) const;
+ virtual rviewFrameType getFrameType(void) const;
+ virtual int getViewerType(void) const;
+
+
+ protected:
+
+ virtual char *initMode(void);
+ virtual char *setupEnvironment(int w, int h);
+ virtual bool doUpdate(int updateFlags);
+ virtual void fillBuffer(void);
+
+ virtual int saveView(FILE *fp);
+ virtual int readView(const char *key, const char *value);
+ virtual void loadViewFinished(void);
+
+ rviewCheckBox *boundingBox;
+ rviewImageMode imode;
+ int lastMode;
+ tex_desc *texDesc;
+ voxel_desc *voxDesc;
+ bool initVoxParams;
+ bool doBoundingBox;
+
+ static const char *view_VolumeMode;
+ static const char *view_UseBBox;
+};
+
+
+/*
+ * Class for visualizing data as heightfields.
+ */
+class rviewHeightImage: public rviewRenderImage
+{
+ public:
+
+ rviewHeightImage(mdd_frame *mf, unsigned int flags=0);
+ virtual ~rviewHeightImage(void);
+
+ virtual void label(void);
+ virtual int process(wxObject &obj, wxEvent &evt);
+ virtual int newProjection(void);
+ virtual void prepareToDie(void);
+ virtual int requestQuit(int level);
+ virtual int openViewer(void);
+
+ virtual const char *getFrameName(void) const;
+ virtual rviewFrameType getFrameType(void) const;
+ virtual int getViewerType(void) const;
+
+
+ protected:
+
+ int depthForHeightfield(void) const;
+ virtual char *initMode(void);
+ virtual char *setupEnvironment(int w, int h);
+ virtual char *movieNewFrame(void);
+ virtual bool doUpdate(int updateFlags);
+ virtual void redrawSettingsChanged(void);
+ virtual void fillBackgroundCore(rviewBaseType bt, double minVal);
+ virtual void fillBuffer(void);
+ virtual bool cspaceRangeHook(bool suggest);
+ virtual bool moviePossible(void) const;
+ virtual bool modeNeedsCspace(rviewBaseType bt) const;
+
+ mdd_desc *mddDesc;
+ mesh_desc *meshDesc;
+ // for colourspace mapping of heightfields.
+ r_Ref<r_GMarray> dummyMDD;
+};
+
+
+
+/*
+ * An image scaled by the DBMS
+ */
+class r_Fast_Base_Scale;
+
+class rviewScaledImage: public rviewFlatBaseImage
+{
+ public:
+
+ rviewScaledImage(collection_desc *cd, r_Fast_Base_Scale *scaler, unsigned int flags=0);
+ ~rviewScaledImage(void);
+
+ virtual void processMouseEvent(wxMouseEvent &mevt);
+ virtual void label(void);
+ virtual int process(wxObject &obj, wxEvent &evt);
+ virtual int openViewer(void);
+ virtual void OnSize(int w, int h);
+ virtual int newProjection(void);
+
+ virtual const char *getFrameName(void) const;
+ virtual rviewFrameType getFrameType(void) const;
+ virtual int getViewerType(void) const;
+ virtual const r_Minterval &getVirtualDomain(void) const;
+
+
+ protected:
+
+ virtual char *initMode(void);
+ virtual void projectObjectHook(void);
+
+ char *projectImage(void);
+ bool showScaleSlider(void) const;
+ void scaleViewBy(double scale);
+ void newView(bool loadImage=TRUE);
+ void projectionStringForView(void);
+ double getLastScale(void) const;
+
+ // view management
+ virtual int saveView(FILE *fp);
+ virtual int readView(const char *key, const char *value);
+ virtual void loadViewFinished(void);
+ void ensureLoadedView(void);
+
+ rviewButton *zoomInBut;
+ rviewButton *zoomOutBut;
+ rviewButton *lastZoomBut;
+ rviewButton *zoomBoxBut;
+ rviewText *scaleString;
+
+ bool boxState;
+
+ typedef struct {
+ double scale;
+ r_Point low, high;
+ int dim1, dim2;
+ } view_desc_t;
+
+ bool compareViews(const view_desc_t &v1, const view_desc_t &v2);
+
+ // The current view
+ view_desc_t thisView;
+ r_Minterval fullDomain;
+ bool dontLoad;
+ double initialScale;
+ view_desc_t *loadedView;
+
+ DynamicStack<view_desc_t> viewHistory;
+
+ r_Fast_Base_Scale *scaleObject;
+
+ collection_desc *collDesc;
+
+ static const double scaleStep;
+
+ // view parameters
+ static const char *view_CurrentBox;
+ static const char *view_BoxScale;
+};
+
+
+// Structure for static conversion of MDD -> pixmap
+typedef struct rviewFlatProjEnv {
+ // initialized by caller
+ r_GMarray *mddPtr;
+ r_Point pt1, pt2;
+ int dim1, dim2;
+ rviewBaseType bt;
+ double scale;
+ bool doCspace;
+ colourspaceMapper *csmap;
+ int cspaceState;
+ // initialized by prepareFlatProjection()
+ int width, height;
+ int pitch, pad, depth;
+} rviewFlatProjEnv;
+
+// Setup variables for projecting images
+int rviewPrepareFlatProjection(rviewFlatProjEnv &penv);
+// Project an MDD object into an image bitmap
+int rviewPerformFlatProjection(rviewFlatProjEnv &env, char *data);
+
+
+
+
+
+
+enum rviewChartMode {
+ rcm_none,
+ rcm_bar,
+ rcm_line,
+ rcm_spline
+};
+
+/*
+ * Canvas displaying a chart
+ */
+
+class chartCanvas: public wxCanvas
+{
+ public:
+
+ chartCanvas(wxWindow *parent, int x, int y, int w, int h, long style=0);
+ ~chartCanvas(void);
+
+ void setData(mdd_frame *mf, rviewBaseType bt);
+ void setVars(int s, double cs, int ds, bool cy, rviewChartMode cm);
+ int setProjection(r_Point &p1, r_Point &p2);
+ void OnPaint(void);
+
+ // constants
+ // Space reserved on top / bottom of chart
+ static const int chcanv_cospace;
+ // Length of a corrdinate axis marker line
+ static const int chcanv_colength;
+ // Start exponential axis numbering when |exponent| >= x
+ static const int chcanv_exponents;
+
+
+ protected:
+
+ // Core-functionality of chart modes
+ void redrawBar(wxDC *cdc, int height, int dim, int startOff, int endOff, float scale, float posx, float stepx, float orgy);
+ void redrawLine(wxDC *cdc, int dim, int startOff, int endOff, float scale, float posx, float stepx, float orgy);
+ void redrawSpline(wxDC *cdc, int dim, int startOff, int endOff, float scale, float posx, float stepx, float orgy);
+
+ r_Ref<r_GMarray> mddObj;
+ int step, dimMDD;
+ r_Point pt1, pt2;
+ double min, max, costep;
+ rviewBaseType baseType;
+ rviewChartMode cmode;
+ wxBrush brush, back;
+ wxBrush brush_r, brush_g, brush_b;
+ wxPen pen, pen_r, pen_g, pen_b;
+ wxFont *font;
+ bool cosys;
+ char format[10];
+ int coleft, datastep;
+ int scroll;
+};
+
+
+/*
+ * A class for drawing charts
+ */
+
+class rviewChart: public rviewDisplay
+{
+ public:
+
+ rviewChart(mdd_frame *mf, unsigned int flags=0);
+ ~rviewChart(void);
+
+ void label(void);
+ int process(wxObject &obj, wxEvent &evt);
+ int newProjection(void);
+ virtual int openViewer(void);
+
+ void OnSize(int w, int h);
+ void OnMenuCommand(int id);
+
+ virtual const char *getFrameName(void) const;
+ virtual rviewFrameType getFrameType(void) const;
+ virtual int getViewerType(void) const;
+
+ // constants
+ // Text widget dimensions (step)
+ static const int chart_twidth;
+ static const int chart_theight;
+ // checkbox dims
+ static const int chart_cwidth;
+ static const int chart_cheight;
+ // Minimum size of viewer
+ static const int chart_minwidth;
+ static const int chart_minheight;
+ static const int chart_ctrly;
+ static const int chart_totaly;
+
+
+ protected:
+
+ virtual int saveView(FILE *fp);
+ virtual int readView(const char *key, const char *value);
+ virtual void loadViewFinished(void);
+
+ void checkModeMenu(void);
+
+ chartCanvas *canvas;
+ int step, datastep;
+ int lastMode;
+ double costep;
+ int scroll;
+ bool cosys;
+ rviewChartMode cmode;
+ rviewText *stText, *coText, *dataText;
+ rviewCheckBox *csBox;
+
+ static const char *view_StepSize;
+ static const char *view_Markers;
+ static const char *view_ScrollPos;
+ static const char *view_CoSys;
+ static const char *view_ChartMode;
+};
+
+
+
+/*
+ * Canvas for plotting text onto
+ */
+
+class textCanvas: public wxCanvas
+{
+ public:
+
+ textCanvas(wxWindow *parent, int x, int y, int w, int h, long style=0);
+ ~textCanvas(void);
+
+ void setData(mdd_frame *mf, rviewBaseType bt, unsigned int bs);
+ void setStep(int sx, int sy);
+ void setCoSys(bool cs, int &cl, int &ct);
+ void setProjection(r_Point &pt1, r_Point &pt2, unsigned int fd, r_Point *mapIndex=NULL);
+ void setNumberBase(int newBase);
+ void OnPaint(void);
+ void CalcTextExtent(char *b, float &width, float &height);
+ void EstimateCellSize(int &width, int &height);
+
+ // constants
+ // Space around coordinate system
+ static const int txcanv_cospace;
+ // Default space between columns
+ static const int txcanv_colspace;
+ // Border used in text canvas
+ static const int txcanv_border;
+
+
+ protected:
+
+ r_Ref<r_GMarray> mddObj;
+ int stepx, stepy, dimMDD;
+ int scrollX, scrollY;
+ int coleft, cotop;
+ int dim1, dim2;
+ unsigned int freeDims;
+ r_Point pt1, pt2;
+ int numberBase;
+ bool cosys;
+ rviewBaseType baseType;
+ unsigned int baseSize;
+ wxBrush fore, back;
+ wxPen pen;
+ wxFont *font;
+};
+
+
+
+/*
+ * Class for displaying tables
+ */
+
+class rviewTable: public rviewDisplay
+{
+ public:
+
+ rviewTable(mdd_frame *mf, unsigned int flags=0);
+ ~rviewTable(void);
+
+ void label(void);
+ int process(wxObject &obj, wxEvent &evt);
+ int newProjection(void);
+ void newTableSize(void);
+ virtual int openViewer(void);
+
+ virtual const char *getFrameName(void) const;
+ virtual rviewFrameType getFrameType(void) const;
+ virtual int getViewerType(void) const;
+
+ void OnSize(int w, int h);
+ void OnMenuCommand(int id);
+
+ // constants
+ // Dimensions of additional wxText items (configs)
+ static const int table_twidth;
+ static const int table_theight;
+ // Dimensions of check box
+ static const int table_cwidth;
+ static const int table_cheight;
+ // Minimum dimensions of table
+ static const int table_minwidth;
+ static const int table_minheight;
+ static const int table_ctrly;
+ static const int table_totaly;
+
+
+ protected:
+
+ void EstimateCellSize(int &width, int &height);
+
+ virtual int saveView(FILE *fp);
+ virtual int readView(const char *key, const char *value);
+ virtual void loadViewFinished(void);
+
+ void checkModeMenu(void);
+
+ textCanvas *canvas;
+ int stepx, stepy;
+ int scrollx, scrolly;
+ int fieldsx, fieldsy;
+ int lastMode;
+ unsigned int freeDims;
+ bool cosys;
+ rviewText *sxText, *syText;
+ rviewCheckBox *csBox;
+ int numberBase;
+
+ static const char *view_StepSize;
+ static const char *view_ScrollPos;
+ static const char *view_CoSys;
+ static const char *view_NumBase;
+};
+
+
+
+/*
+ * Class for displaying strings
+ */
+
+class rviewStringViewer: public rviewDisplay
+{
+ public:
+
+ rviewStringViewer(mdd_frame *mf, unsigned int flags=0);
+ ~rviewStringViewer(void);
+
+ int newProjection(void);
+ virtual int openViewer(void);
+
+ virtual const char *getFrameName(void) const;
+ virtual rviewFrameType getFrameType(void) const;
+ virtual int getViewerType(void) const;
+
+ void OnSize(int w, int h);
+
+ // constants
+ static const int strview_msgheight;
+ static const int strview_minwidth;
+ static const int strview_minheight;
+ static const int strview_ctrly;
+ static const int strview_totaly;
+
+
+ protected:
+
+ unsigned int freeDims;
+ wxMessage *msgString;
+};
+
+#endif
diff --git a/applications/rview/rviewDb.cpp b/applications/rview/rviewDb.cpp
new file mode 100644
index 0000000..d9c7888
--- /dev/null
+++ b/applications/rview/rviewDb.cpp
@@ -0,0 +1,970 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+ * Purpose:
+ *
+ * Database abstraction layer. All database accesses are performed though
+ * the functions provided here. This includes creating / deleting / looking
+ * up collections, inserting objects into collections and executing RasQL
+ * queries.
+ *
+ * COMMENTS:
+ * None
+ */
+
+
+
+// Standard wxWindows preamble.
+#ifdef __GNUG__
+#pragma implementation
+#endif
+
+
+// changed in wxWindows 2.4.2:
+//#include "wx_prec.h"
+#include <wx/wxprec.h>
+
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+
+#ifndef WX_PRECOMP
+#include <wx/wx.h>
+#endif
+
+
+#include "wb_timer.h"
+
+
+
+#include <string.h>
+
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#endif
+
+#include "raslib/scalar.hh"
+#include "raslib/rmdebug.hh"
+#include "rasodmg/fastscale.hh"
+
+
+#include "rviewTypes.hh"
+
+#include "labelManager.hh"
+
+#include "rviewDb.hh"
+#include "rviewMDD.hh"
+#include "rviewPrefs.hh"
+
+
+
+rviewDatabase::rviewDatabase(void)
+{
+ dbOpen = FALSE;
+ lastTransferFormat = r_Array;
+ lastStorageFormat = r_Array;
+}
+
+
+rviewDatabase::~rviewDatabase(void)
+{
+ if (dbOpen)
+ {
+ close();
+ }
+}
+
+
+bool rviewDatabase::isOpen(void)
+{
+ return dbOpen;
+}
+
+
+
+int rviewDatabase::open(const char *srvname, int srvport, const char *dbname,
+ const char *usrname, const char *usrpassword)
+{
+ int status;
+
+ if (!dbOpen)
+ {
+ server = srvname;
+ port = srvport;
+ database = dbname;
+ username = usrname;
+ userpassword = usrpassword;
+
+ }
+ else
+ {
+ rviewErrorbox::reportError(lman->lookup("errorDatabaseOpen"));
+ return 0;
+ }
+
+ rviewProgress *prog = new rviewProgress(lman->lookup("progOpenDb"));
+
+ try
+ {
+ ::wxStartTimer();
+
+ dbase.set_servername(server,port);
+ dbase.set_useridentification(username, userpassword);
+ dbase.open(database);
+#ifdef RMANDEBUG
+ cout << "Open Database Time: " << ::wxGetElapsedTime(TRUE) << "ms" << endl;
+#endif
+ dbOpen = TRUE;
+ status = 1;
+ }
+ catch ( r_Error &errObj )
+ {
+/*
+ char *errLab;
+ cerr << errObj.what() << endl;
+ switch ( errObj.get_kind() )
+ {
+ case r_Error::r_Error_HostInvalid: errLab = "\\errorHostInvalid"; break;
+ case r_Error::r_Error_ServerInvalid: errLab = "\\errorServerInvalid"; break;
+ case r_Error::r_Error_ClientUnknown: errLab = "\\errorClientUnknown"; break;
+ case r_Error::r_Error_DatabaseUnknown: errLab = "\\errorDatabaseUnknown"; break;
+ case r_Error::r_Error_DatabaseOpen: errLab = "\\errorDatabaseOpen"; break;
+ case r_Error::r_Error_RpcInterfaceIncompatible: errLab = "\\errorRpcInterface"; break;
+ default: errLab = "\\errorUnknown"; break;
+ }
+*/
+
+ rviewErrorbox::reportError((const char*)errObj.what());
+ status = 0;
+ }
+
+ prog->Close(TRUE);
+
+ return status;
+}
+
+
+
+void rviewDatabase::close(void)
+{
+// if (ensureDatabase() == 0) return;
+ dbase.close();
+ dbOpen = FALSE;
+}
+
+
+
+int rviewDatabase::collectionToDesc(r_Set<r_Ref<r_GMarray> > &mddColl, collection_desc *desc)
+{
+ int i, collMembers;
+ rviewBaseType bt = rbt_none;
+ r_Object *mo = NULL;
+
+ desc->number = 0; desc->mddObjs = NULL; desc->strObjs = NULL; desc->collType = NULL;
+
+ collMembers = mddColl.cardinality();
+
+ if (collMembers <= 0)
+ {
+ return 1;
+ }
+
+ if ((desc->mddObjs = new mdd_frame[collMembers]) == NULL)
+ {
+ cerr << lman->lookup("errorMemory") << endl;
+ return 0;
+ }
+
+ r_Iterator < r_Ref <r_GMarray> > iterator = mddColl.create_iterator();
+
+ for (i=0; i<collMembers; i++, iterator++)
+ {
+ RMDBGONCE(3, RMDebug::module_applications, "rviewDb", "collectionToDesc() MDD number " << i << ":\tDomain = " << (*iterator)->spatial_domain() );
+
+ // Copy each MDD object
+ desc->mddObjs[i].mdd = new r_GMarray((const r_GMarray &)(*(*iterator)));
+ // oid isn't copied by copy constructor...
+ desc->mddObjs[i].mdd->initialize_oid((*iterator)->get_oid());
+ if (desc->mddObjs[i].mdd.is_null())
+ {
+ cerr << lman->lookup("errorMemory") << endl;
+ }
+ desc->mddObjs[i].flags = 0;
+ // Set type information?
+ if (mo == NULL)
+ {
+ // we must use the original mdd data to get the type information!
+ mo = (r_Object*)(&(**iterator));
+ bt = rviewGetBasetype(mo);
+ }
+ }
+
+ desc->number = collMembers;
+
+ desc->collType = new char[strlen(rviewBaseTypes[bt]) + 1];
+ strcpy(desc->collType, rviewBaseTypes[bt]);
+
+ return 1;
+}
+
+
+
+int rviewDatabase::lookupCollection(collection_desc *desc)
+{
+ r_Ref < r_Set < r_Ref <r_GMarray > > > mddCollPtr;
+ r_Transaction transaction;
+ int status;
+ char buffer[STRINGSIZE];
+
+ status = 0;
+ rviewProgress *prog = new rviewProgress(lman->lookup("progLookup"));
+
+ try
+ {
+ ::wxStartTimer();
+
+ transaction.begin( r_Transaction::read_only );
+
+ //set storage & transfer params
+ if (!ensureDatabase())
+ {
+ transaction.abort();
+ return 0;
+ }
+
+ mddCollPtr = dbase.lookup_object(desc->collName);
+
+ status = collectionToDesc(*mddCollPtr, desc);
+
+ transaction.commit();
+
+ sprintf(buffer, "%s: %d ms", lman->lookup("textTime"), ::wxGetElapsedTime(TRUE));
+ if ((desc->collInfo = new char[strlen(buffer) + 1]) != NULL)
+ {
+ strcpy(desc->collInfo, buffer);
+ }
+#ifdef RMANDEBUG
+ cout << "Lookup collection " << buffer << endl;
+#endif
+ }
+
+ catch ( r_Error &errObj )
+ {
+ const char *msg;
+
+ cerr << errObj.what() << endl;
+
+ if (errObj.get_errorno() != 0)
+ {
+ msg = errObj.what();
+ }
+ else
+ {
+ switch (errObj.get_kind())
+ {
+ case r_Error::r_Error_ClientUnknown: msg = lman->lookup("errorClientUnknown"); break;
+ case r_Error::r_Error_DatabaseClosed: msg = lman->lookup("errorDatabaseClosed"); break;
+ case r_Error::r_Error_QueryParameterCountInvalid: msg = lman->lookup("errorQueryParamNum"); break;
+ case r_Error::r_Error_TransferFailed: msg = lman->lookup("errorTransferFailed"); break;
+ default: msg = lman->lookup("errorUnknown"); break;
+ }
+ }
+ rviewErrorbox::reportError(msg);
+ }
+
+ prog->Close(TRUE);
+
+ return status;
+}
+
+
+r_Ref<r_GMarray> rviewDatabase::getScaledObject(r_Fast_Base_Scale *scaler, const r_Minterval &trimDomain, double scale)
+{
+ r_Transaction ta;
+ r_Ref<r_GMarray> result;
+
+ try
+ {
+ ta.begin(r_Transaction::read_only);
+
+ //FIXME
+/*
+ //set storage & transfer params
+ if (!ensureDatabase())
+ {
+ ta.abort();
+ return 0;
+ }
+*/
+ // apply trimming before scaling!
+ result = scaler->get_scaled_object(trimDomain, scale, 1);
+ ta.commit();
+ }
+ catch(r_Error &err)
+ {
+ ta.abort();
+ rviewErrorbox::reportError(err.what());
+ }
+ // if the transaction failed, result.is_null() will deliver TRUE.
+ return result;
+}
+
+
+r_Fast_Base_Scale *rviewDatabase::lookupScaledObject(collection_desc *desc, double scale)
+{
+ r_Transaction ta;
+ r_Fast_Base_Scale *result;
+ rviewBaseType baseType;
+ char buffer[STRINGSIZE];
+
+
+
+ desc->strObjs = NULL;
+
+ rviewProgress *prog = new rviewProgress(lman->lookup("progLookup"));
+
+ try
+ {
+ ta.begin(r_Transaction::read_only);
+
+
+ //set storage & transfer params
+ if (!ensureDatabase())
+ {
+ ta.abort();
+ return 0;
+ }
+
+ r_Ref<r_GMarray> minArray = r_Fast_Base_Scale::get_minimal_array(desc->collName);
+ ta.commit();
+ baseType = rviewGetBasetype(minArray.ptr());
+ minArray.destroy();
+ }
+ catch(r_Error &err)
+ {
+ ta.abort();
+ rviewErrorbox::reportError(err.what());
+ prog->Close(TRUE);
+ return NULL;
+ }
+
+ try
+ {
+ ta.begin(r_Transaction::read_only);
+
+
+ //set storage & transfer params
+ if (!ensureDatabase())
+ {
+ ta.abort();
+ return 0;
+ }
+
+ switch (baseType)
+ {
+ case rbt_bool:
+ result = new r_Fast_Scale<r_Boolean>(desc->collName);
+ break;
+ case rbt_char:
+ result = new r_Fast_Scale<r_Char>(desc->collName);
+ break;
+ case rbt_uchar:
+ result = new r_Fast_Scale<r_Octet>(desc->collName);
+ break;
+ case rbt_short:
+ result = new r_Fast_Scale<r_Short>(desc->collName);
+ break;
+ case rbt_ushort:
+ result = new r_Fast_Scale<r_UShort>(desc->collName);
+ break;
+ case rbt_long:
+ result = new r_Fast_Scale<r_Long>(desc->collName);
+ break;
+ case rbt_ulong:
+ result = new r_Fast_Scale<r_ULong>(desc->collName);
+ break;
+ case rbt_float:
+ result = new r_Fast_Scale<r_Float>(desc->collName);
+ break;
+ case rbt_double:
+ result = new r_Fast_Scale<r_Double>(desc->collName);
+ break;
+ case rbt_rgb:
+ result = new r_Fast_Scale<RGBPixel>(desc->collName);
+ break;
+ default:
+ rviewErrorbox::reportError(lman->lookup("errorScaledObjType"));
+ prog->Close(TRUE);
+ return NULL;
+ }
+ ta.commit();
+ }
+ catch(r_Error &err)
+ {
+ ta.abort();
+ rviewErrorbox::reportError(err.what());
+ prog->Close(TRUE);
+ return NULL;
+ }
+
+ r_Ref<r_GMarray> mddObj;
+
+ ::wxStartTimer();
+
+ mddObj = getScaledObject(result, result->get_full_domain(), scale);
+ if (mddObj.is_null())
+ {
+ delete result;
+ prog->Close(TRUE);
+ return NULL;
+ }
+
+ sprintf(buffer, "%s: %d ms", lman->lookup("textTime"), ::wxGetElapsedTime(TRUE));
+ if ((desc->collInfo = new char[strlen(buffer) + 1]) != NULL)
+ {
+ strcpy(desc->collInfo, buffer);
+ }
+ desc->collType = new char[strlen(rviewBaseTypes[baseType]) + 1];
+ strcpy(desc->collType, rviewBaseTypes[baseType]);
+ desc->mddObjs = new mdd_frame[1];
+ desc->number = 1;
+ desc->mddObjs[0].mdd = mddObj; desc->mddObjs[0].flags = 0;
+
+ prog->Close(TRUE);
+
+ return result;
+}
+
+
+int rviewDatabase::createCollection(const char *collName, rviewBaseType bt)
+{
+ r_Ref <r_Set <r_Ref <r_GMarray> > > mddCollPtr;
+ r_Transaction ta;
+
+ try
+ {
+ mddCollPtr = dbase.lookup_object(collName);
+ }
+ catch (...)
+ {
+ RMDBGONCE(3, RMDebug::module_applications, "rviewDb", "createCollection( " << collName << " )");
+
+ ta.begin();
+
+ //set storage & transfer params
+ if (!ensureDatabase())
+ {
+ ta.abort();
+ return 0;
+ }
+
+ try
+ {
+ switch (bt)
+ {
+ case rbt_bool:
+ mddCollPtr = new( &dbase, rviewSetNames[bt][2] ) r_Set< r_Ref< r_Marray< r_Boolean > > >;
+ break;
+ case rbt_char:
+ mddCollPtr = new( &dbase, rviewSetNames[bt][2] ) r_Set< r_Ref< r_Marray< r_Char > > >;
+ break;
+ case rbt_long:
+ mddCollPtr = new( &dbase, rviewSetNames[bt][2] ) r_Set< r_Ref< r_Marray< RGBPixel > > >;
+ break;
+ default: ta.abort(); return 0;
+ }
+
+ dbase.set_object_name(*mddCollPtr, collName);
+
+ ta.commit();
+ }
+ catch (r_Error &obj)
+ {
+ cerr << lman->lookup("errorCollCreate") << ": " << obj.what() << endl;
+ }
+ }
+ return 0;
+}
+
+
+
+int rviewDatabase::deleteCollection(const char *collName)
+{
+ r_Ref <r_Set <r_Ref <r_GMarray> > > mddCollPtr;
+ r_Transaction ta;
+
+ try
+ {
+ ta.begin();
+
+ //set storage & transfer params
+ if (!ensureDatabase())
+ {
+ ta.abort();
+ return 0;
+ }
+
+ mddCollPtr = dbase.lookup_object(collName);
+ mddCollPtr.delete_object();
+ ta.commit();
+ return 1;
+ }
+ catch (...)
+ {
+ cerr << lman->lookup("errorCollDelete") << endl;
+ }
+ return 0;
+}
+
+
+
+int rviewDatabase::insertObject(const char *collName, r_Ref<r_GMarray> mddObj, r_Minterval *domain)
+{
+ r_Ref <r_Set <r_Ref <r_GMarray> > > mddCollPtr;
+ r_Ref <r_GMarray> mddPtr;
+ r_Transaction ta;
+ rviewBaseType bt;
+ r_Object *mo;
+ int dim, status;
+
+ RMDBGENTER(3, RMDebug::module_applications, "rviewDb", "insertObject( " << collName << ", ... )");
+
+ dim = (mddObj->spatial_domain()).dimension();
+ if ((dim < 1) || (dim > MAXIMUM_DIMENSIONS))
+ {
+ rviewErrorbox::reportError(lman->lookup("errorObjectDims"));
+ return 0;
+ }
+
+ // *mddObj ``removes'' r_Ref. Can't leave out the &* combination!
+ mo = (r_Object*)(&(*mddObj));
+ bt = rviewGetBasetype(mo);
+
+ ta.begin();
+
+ //set storage & transfer params
+ if (!ensureDatabase())
+ {
+ ta.abort();
+ return 0;
+ }
+
+ rviewProgress *prog = new rviewProgress(lman->lookup("progInsert"));
+
+ ::wxStartTimer();
+
+ try
+ {
+ mddCollPtr = dbase.lookup_object(collName);
+ RMDBGMIDDLE(3, RMDebug::module_applications, "rviewDb", "insertObject() collection cardinality: " << mddCollPtr->cardinality() );
+ }
+ catch (r_Error &obj)
+ {
+ char *setName;
+
+ setName = (char*)obj.what();
+ setName = rviewSetNames[bt][dim-1];
+
+ switch (bt)
+ {
+ case rbt_bool:
+ mddCollPtr = new (&dbase, setName) r_Set <r_Ref <r_Marray <r_Boolean> > >;
+ break;
+ case rbt_char:
+ mddCollPtr = new (&dbase, setName) r_Set <r_Ref <r_Marray <r_Char> > >;
+ break;
+ case rbt_uchar:
+ mddCollPtr = new (&dbase, setName) r_Set <r_Ref <r_Marray <r_Octet> > >;
+ break;
+ case rbt_short:
+ mddCollPtr = new (&dbase, setName) r_Set <r_Ref <r_Marray <r_Short> > >;
+ break;
+ case rbt_ushort:
+ mddCollPtr = new (&dbase, setName) r_Set <r_Ref <r_Marray <r_UShort> > >;
+ break;
+ case rbt_long:
+ mddCollPtr = new (&dbase, setName) r_Set <r_Ref <r_Marray <r_Long> > >;
+ break;
+ case rbt_ulong:
+ mddCollPtr = new (&dbase, setName) r_Set <r_Ref <r_Marray <r_ULong> > >;
+ break;
+ case rbt_float:
+ mddCollPtr = new (&dbase, setName) r_Set <r_Ref <r_Marray <r_Float> > >;
+ break;
+ case rbt_double:
+ mddCollPtr = new (&dbase, setName) r_Set <r_Ref <r_Marray <r_Double> > >;
+ break;
+ case rbt_rgb:
+ mddCollPtr = new (&dbase, setName) r_Set <r_Ref <r_Marray <RGBPixel> > >;
+ break;
+ default:
+ cerr << "Unknown base type " << bt << endl;
+ ta.abort(); prog->Close(TRUE); return 0;
+ }
+ dbase.set_object_name(*mddCollPtr, collName);
+ }
+
+ status = 0;
+ try
+ {
+ if (mdd_createSubcube(mddObj, mddPtr, domain, &dbase) == 0)
+ {
+ cerr << "Failed to create persistent MDD object" << endl;
+ ta.abort(); prog->Close(TRUE); return 0;
+ }
+ RMDBGMIDDLE(3, RMDebug::module_applications, "rviewDb", "insertObject() Object type name " << rviewTypeNames[bt][dim-1] );
+ mddPtr->set_type_by_name(rviewTypeNames[bt][dim-1]);
+ mddCollPtr->insert_element(mddPtr);
+
+ ta.commit();
+
+#ifdef RMANDEBUG
+ cout << "Insert Object Time: " << ::wxGetElapsedTime(TRUE) << "ms" << endl;
+#endif
+
+ status = 1;
+ }
+ catch (r_Error &obj)
+ {
+ cerr << lman->lookup("errorInsertObj") << ": " << obj.what() << endl;
+ }
+
+ prog->Close(TRUE);
+
+ RMDBGEXIT(3, RMDebug::module_applications, "rviewDb", "insertObject()");
+
+ return status;
+}
+
+
+
+int rviewDatabase::executeQuery(collection_desc *desc, const char *qry, r_Ref<r_GMarray> *updateMdd, bool showProgress)
+{
+ int status;
+ char buffer[STRINGSIZE];
+
+ r_Transaction ta;
+ r_Set<r_Ref_Any> mddColl;
+ int collMembers;
+
+ rviewProgress *prog = NULL;
+
+ if (showProgress)
+ prog = new rviewProgress(lman->lookup("progQuery"));
+
+ status = 0;
+
+ desc->number = 0; desc->mddObjs = NULL; desc->strObjs = NULL; desc->collType = NULL;
+
+ try
+ {
+ int isUpdateQuery;
+ char *mddArg;
+ r_OQL_Query query(qry);
+
+ // Do this check before starting the transaction
+ if (isUpdateQuery = query.is_update_query())
+ {
+ if ((mddArg = (char*)strstr(qry, "$")) != NULL)
+ {
+ if (updateMdd == NULL)
+ {
+ rviewErrorbox::reportError(lman->lookup("errorUpdtObject"));
+ if (prog != NULL)
+ prog->Close(TRUE);
+ return 0;
+ }
+ }
+ }
+
+ ::wxStartTimer();
+
+ if (isUpdateQuery)
+ {
+ ta.begin();
+
+ //set storage & transfer params
+ if (!ensureDatabase())
+ {
+ ta.abort();
+ return 0;
+ }
+
+ }
+ else
+ {
+ ta.begin(r_Transaction::read_only);
+
+
+ //set storage & transfer params
+ if (!ensureDatabase())
+ {
+ ta.abort();
+ return 0;
+ }
+
+ }
+
+#ifdef RMANDEBUG
+ //cout << "Expanded query:" << endl << query.get_query() << endl;
+#endif
+
+ if (isUpdateQuery)
+ {
+#ifdef RMANDEBUG
+ //cout << "Is update query " << endl;
+#endif
+ if (mddArg != NULL)
+ {
+ RMDBGONCE(3, RMDebug::module_applications, "rviewDb", "executeQuery() Update MDD domain " << (*updateMdd)->spatial_domain() );
+ query << *(*updateMdd);
+ }
+ r_oql_execute(query);
+ }
+ else
+ {
+#ifdef RMANDEBUG
+ //cout << "Is normal query" << endl;
+#endif
+ r_oql_execute(query, mddColl);
+ }
+
+ collMembers = mddColl.cardinality();
+
+ if (collMembers != 0)
+ {
+ int collType;
+
+ collType = mddColl.get_element_type_schema()->type_id();
+ if (collType == r_Type::MARRAYTYPE)
+ {
+ r_Set<r_Ref<r_GMarray> > mddArrayColl;
+ r_Iterator<r_Ref_Any> iterator = mddColl.create_iterator();
+ int i;
+
+ RMDBGONCE(3, RMDebug::module_applications, "rviewDb", "executeQuery() array-collection, build new set..." );
+
+ for (i=0; i<collMembers; i++, iterator++)
+ {
+ mddArrayColl.insert_element((r_Ref<r_GMarray>)(*iterator));
+ }
+ status = collectionToDesc(mddArrayColl, desc);
+ }
+ else
+ {
+ r_Iterator<r_Ref_Any > iterator = mddColl.create_iterator();
+ ostrstream memstr(buffer, STRINGSIZE);
+ int i;
+
+ RMDBGONCE(3, RMDebug::module_applications, "rviewDb", "executeQuery() non-marray collection, build table..." );
+
+ desc->mddObjs = NULL;
+ desc->strObjs = new char*[collMembers];
+ desc->number = collMembers;
+
+ for (i=0; i<collMembers; i++, iterator++)
+ {
+ memstr.width(3);
+ memstr << i << ": ";
+ switch (collType)
+ {
+ case r_Type::POINTTYPE:
+ ((r_Ref<r_Point>)*iterator)->print_status(memstr); break;
+ case r_Type::SINTERVALTYPE:
+ ((r_Ref<r_Sinterval>)*iterator)->print_status(memstr); break;
+ case r_Type::MINTERVALTYPE:
+ ((r_Ref<r_Minterval>)*iterator)->print_status(memstr); break;
+ case r_Type::OIDTYPE:
+ ((r_Ref<r_OId>)*iterator)->print_status(memstr); break;
+ default:
+ ((r_Ref<r_Scalar>)*iterator)->print_status(memstr); break;
+ }
+ memstr << '\0';
+ desc->strObjs[i] = new char[strlen(buffer)+1];
+ strcpy(desc->strObjs[i], buffer);
+ //cout << "item " << i << ": " << desc->strObjs[i] << endl;
+ memstr.seekp(0);
+ }
+ (mddColl.get_type_schema())->print_status(memstr);
+ memstr << '\0';
+ desc->collType = new char[strlen(buffer)+1];
+ strcpy(desc->collType, buffer);
+ status = 1;
+ }
+ }
+ ta.commit();
+
+ sprintf(buffer, "%s: %d ms", lman->lookup("textTime"), ::wxGetElapsedTime(TRUE));
+ if ((desc->collInfo = new char[strlen(buffer) + 1]) != NULL)
+ {
+ strcpy(desc->collInfo, buffer);
+ }
+
+#ifdef RMANDEBUG
+ cout << "Execute Query " << buffer << endl;
+#endif
+ // no query error
+ line = -1; col = -1;
+ }
+
+ catch ( r_Equery_execution_failed &errObj )
+ {
+ if (errObj.get_errorno() == 0)
+ {
+ cerr << lman->lookup("errorQueryUnknown") << endl;
+ }
+ else
+ {
+ char msg[1024];
+ const char *what;
+
+ what = errObj.what();
+ if (what != NULL) // might actually happen...
+ {
+ // Memorize the position the error occurred at
+ line = errObj.get_lineno(); col = errObj.get_columnno();
+ sprintf(msg, "%s: %s", lman->lookup("errorQueryFailed"), errObj.what());
+ rviewErrorbox::reportError((const char*)msg);
+ }
+ }
+ }
+
+ catch (r_Error &errObj)
+ {
+ cerr << errObj.what() << endl;
+ }
+
+ if (prog != NULL)
+ prog->Close(TRUE);
+
+ return status;
+}
+
+
+int rviewDatabase::getMinterval(r_Minterval &dom, const char *collname, const double *loid)
+{
+
+ r_Transaction ta;
+ r_Set<r_Ref_Any> collPtr;
+ char buffer[STRINGSIZE];
+ int length, number;
+
+ length = sprintf(buffer, "SELECT SDOM(x) FROM %s AS x", collname);
+ if (loid != NULL)
+ sprintf(buffer + length, " WHERE OID(x) = %f", *loid);
+
+ try
+ {
+ ta.begin(r_Transaction::read_only);
+
+
+ //set storage & transfer params
+ if (!ensureDatabase())
+ {
+ ta.abort();
+ return 0;
+ }
+
+ r_OQL_Query query(buffer);
+ r_oql_execute(query, collPtr);
+ number = collPtr.cardinality();
+ if (number > 1)
+ cout << "rviewDatabase::getMinterval(): more than one object returned!" << endl;
+
+ r_Iterator<r_Ref_Any> iterator = collPtr.create_iterator();
+ dom = *((r_Ref<r_Minterval>)(*iterator));
+
+ ta.commit();
+ }
+ catch (r_Error &err)
+ {
+ ta.abort();
+ cerr << err.what() << endl;
+ return 0;
+ }
+
+ return 1;
+}
+
+
+
+// Returns the position of the error in the last query
+int rviewDatabase::getErrorInfo(int &l, int &c) const
+{
+ if (line < 0) return 0;
+ l = line; c = col;
+ return 1;
+}
+
+
+
+const r_Database *rviewDatabase::getDatabase(void) const
+{
+ return &dbase;
+}
+
+
+
+int rviewDatabase::ensureDatabase(void)
+{
+ if (dbOpen)
+ {
+ r_Data_Format currentFormat;
+
+ currentFormat = prefs->getTransferFormat();
+ if ((lastTransferFormat != currentFormat) || (lastTransferParams != prefs->transferParm))
+ {
+ try
+ {
+ dbase.set_transfer_format(currentFormat, prefs->transferParm);
+ lastTransferFormat = currentFormat;
+ lastTransferParams = prefs->transferParm;
+ }
+ catch (r_Error &err)
+ {
+ cerr << err.what() << endl;
+ }
+ }
+ currentFormat = prefs->getStorageFormat();
+ if ((lastStorageFormat != currentFormat) || (lastStorageParams != prefs->storageParm))
+ {
+ try
+ {
+ dbase.set_storage_format(currentFormat, prefs->storageParm);
+ lastStorageFormat = currentFormat;
+ lastStorageParams = prefs->storageParm;
+ }
+ catch (r_Error &err)
+ {
+ cerr << err.what() << endl;
+ }
+ }
+ return 1;
+ }
+ rviewErrorbox::reportError(lman->lookup("errorDatabaseClosed"));
+ return 0;
+}
diff --git a/applications/rview/rviewDb.hh b/applications/rview/rviewDb.hh
new file mode 100644
index 0000000..33764f4
--- /dev/null
+++ b/applications/rview/rviewDb.hh
@@ -0,0 +1,110 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+ * Purpose:
+ *
+ * Database abstraction layer. All database accesses are performed though
+ * the functions provided here. This includes creating / deleting / looking
+ * up collections, inserting objects into collections and executing RasQL
+ * queries.
+ *
+ * COMMENTS:
+ * none
+ */
+
+
+
+#ifndef _RVIEW_DB_H_
+#define _RVIEW_DB_H_
+
+
+
+#ifdef __GNUG__
+#pragma interface
+#endif
+
+
+
+
+#include "rasodmg/database.hh"
+#include "rasodmg/transaction.hh"
+#include "rasodmg/set.hh"
+#include "rasodmg/ref.hh"
+#include "rasodmg/marray.hh"
+#include "rasodmg/gmarray.hh"
+#include "rasodmg/iterator.hh"
+#include "rasodmg/oqlquery.hh"
+
+
+#include "rviewUtils.hh"
+
+
+
+class r_Fast_Base_Scale;
+
+class rviewDatabase
+{
+ public:
+
+ rviewDatabase(void);
+ ~rviewDatabase(void);
+ int open(const char *srvname, int srvport, const char *dbname,
+ const char *username, const char *userpassword);
+ void close(void);
+ bool isOpen(void);
+ int createCollection(const char *collName, rviewBaseType bt);
+ int deleteCollection(const char *collName);
+ int lookupCollection(collection_desc *desc);
+ static r_Ref<r_GMarray> getScaledObject(r_Fast_Base_Scale *scaler, const r_Minterval &trimDom, double scale);
+ r_Fast_Base_Scale *lookupScaledObject(collection_desc *desc, double scale);
+ int insertObject(const char *collName, r_Ref<r_GMarray> mddObj, r_Minterval *domain=NULL);
+ int executeQuery(collection_desc *desc, const char *query, r_Ref<r_GMarray> *updateMdd=NULL, bool showProgress=TRUE);
+ int getMinterval(r_Minterval &dom, const char *collName, const double *loid=NULL);
+ const r_Database *getDatabase(void) const;
+ int getErrorInfo(int &line, int &col) const;
+
+
+ protected:
+
+ int collectionToDesc(r_Set<r_Ref<r_GMarray> > &mddColl, collection_desc *desc);
+
+ int ensureDatabase(void);
+
+ DynamicString server;
+ int port;
+ DynamicString database;
+ DynamicString username;
+ DynamicString userpassword;
+ DynamicString lastTransferParams;
+ DynamicString lastStorageParams;
+ r_Data_Format lastTransferFormat;
+ r_Data_Format lastStorageFormat;
+
+ bool dbOpen;
+ r_Database dbase;
+ // For errors in queries
+ int line, col;
+};
+
+#endif
diff --git a/applications/rview/rviewDisplay.cpp b/applications/rview/rviewDisplay.cpp
new file mode 100644
index 0000000..bf6d4f4
--- /dev/null
+++ b/applications/rview/rviewDisplay.cpp
@@ -0,0 +1,1005 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+ * PURPOSE:
+ *
+ * Base class for all object viewers (rviewImage, rviewChart, rviewTable
+ * and rviewSound). Provides a frame with standard control widgets and
+ * menus, functions for parsing/advancing the projection string and
+ * initializing protected variables according to the MDD object that will
+ * be displayed.
+ *
+ * COMMENTS:
+ * None
+ */
+
+
+// Standard wxWindows preamble.
+#ifdef __GNUG__
+#pragma implementation
+#endif
+
+
+// changed in wxWindows 2.4.2:
+//#include "wx_prec.h"
+#include <wx/wxprec.h>
+
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+
+#ifndef WX_PRECOMP
+#include <wx/wx.h>
+#endif
+
+
+
+#include <string.h>
+#include <iostream.h>
+#include <ctype.h>
+
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#endif
+
+#include "raslib/rmdebug.hh"
+
+#include "rviewTypes.hh"
+
+#include "labelManager.hh"
+
+#include "rviewUtils.hh"
+#include "rviewDisplay.hh"
+#include "rviewPrefs.hh"
+#include "rviewApp.hh"
+
+
+
+
+/*
+ * Need a slightly more sophisticated panel than the default one
+ */
+class rviewDisplayPanel : public wxPanel
+{
+ public:
+ rviewDisplayPanel(rviewDisplay *parent, int posx, int posy, int width, int height);
+ virtual void OnEvent(wxMouseEvent &mevt);
+ virtual void OnItemEvent(wxItem *item, wxMouseEvent &mevt);
+};
+
+rviewDisplayPanel::rviewDisplayPanel(rviewDisplay *parent, int posx, int posy, int width, int height) :
+ wxPanel((wxWindow*)parent, posx, posy, width, height)
+{
+}
+
+void rviewDisplayPanel::OnEvent(wxMouseEvent &mevt)
+{
+ rviewDisplay *disp = (rviewDisplay*)(GetParent());
+ disp->childMouseEvent(this, mevt);
+ wxPanel::OnEvent(mevt);
+}
+
+void rviewDisplayPanel::OnItemEvent(wxItem *item, wxMouseEvent &mevt)
+{
+ rviewDisplay *disp = (rviewDisplay*)(GetParent());
+ disp->childMouseEvent(item, mevt);
+ wxPanel::OnItemEvent(item, mevt);
+}
+
+
+
+
+/*
+ * Constants
+ */
+
+// window dimensions
+const int rviewDisplay::display_width = 300;
+const int rviewDisplay::display_height = 400;
+const int rviewDisplay::display_cnvborder = 10;
+const int rviewDisplay::display_border = 8;
+const int rviewDisplay::display_scrstep = 8;
+const int rviewDisplay::display_pgstep = 8;
+const int rviewDisplay::display_cheight = 60;
+const int rviewDisplay::display_pjheight = 50;
+const int rviewDisplay::display_pjwidth = 100;
+const int rviewDisplay::display_pbwidth = 40;
+const int rviewDisplay::display_pbheight = 30;
+const int rviewDisplay::display_minwidth = 4*(rviewDisplay::display_pbwidth + rviewDisplay::display_border);
+
+// flags
+const int rviewDisplay::display_flag_standalone = 1;
+const int rviewDisplay::display_flag_update = 2;
+
+// others
+const int rviewDisplay::fixedNumberOfMenus = 2;
+const unsigned int rviewDisplay::viewBuffSize = 1024;
+const char *rviewDisplay::viewFileExtension = "*.rvw";
+
+const char *rviewDisplay::view_HeaderLine = "# rView viewer snapshot";
+const char *rviewDisplay::view_ViewerType = "viewerName";
+const char *rviewDisplay::view_ProjString = "projString";
+const char *rviewDisplay::view_WindowSize = "windowSize";
+
+
+
+/*
+ * rviewDisplay members
+ */
+
+// The global display counter.
+int rviewDisplay::displayCounter=0;
+
+rviewDisplay::rviewDisplay(mdd_frame *mf, int es, unsigned int flags) : rviewFrame(NULL, "", 0, 0, display_width, display_height)
+{
+ int x, y, pw;
+ r_Object *mo;
+ char buffer[STRINGSIZE];
+
+ if ((flags & display_flag_standalone & display_flag_update) != 0)
+ RMDBGENTER(3, RMDebug::module_applications, "rviewDisplay", "rviewDisplay() [UA]")
+ else if ((flags & display_flag_standalone) != 0)
+ RMDBGENTER(3, RMDebug::module_applications, "rviewDisplay", "rviewDisplay() [A]")
+ else if ((flags & display_flag_update) != 0)
+ RMDBGENTER(3, RMDebug::module_applications, "rviewDisplay", "rviewDisplay() [U]")
+
+ // Override by derived classes if an error occurs.
+ // Can't use virtual functions in constructors!
+ objectInitializedOK = TRUE;
+ closeViewerCalled = FALSE;
+
+ displayFlags = flags;
+ mddObj = mf->mdd; extraSpace = es;
+ totalCtrlHeight = display_cheight + extraSpace;
+ rootTitle[0] = '\0';
+ displayOperation = FALSE; // used to avoid reentrancy on resize
+ minViewX = 0; minViewY = 0; dimMode = -1;
+
+ // Copy the current (global) display counter and increment it, thus creating a unique
+ // ID for each display window.
+ displayID = displayCounter++;
+ qwindowID = -1; // no query window
+
+ projString[0] = '\0';
+
+ baseSize = (int)(mddObj->get_type_length());
+ // Determine base type
+ mo = (r_Object*)(&(*mddObj));
+ baseType = rviewGetBasetype(mo);
+
+ interv = mddObj->spatial_domain();
+ dimMDD = interv.dimension();
+
+ mBar = NULL;
+ ctrlPanel = NULL; project = NULL;
+
+ GetClientSize(&x, &y);
+
+ ctrlPanel = new rviewDisplayPanel(this, 0, 0, x, totalCtrlHeight);
+ ctrlPanel->SetLabelPosition(wxVERTICAL);
+
+ x -= 2*display_border; pw = x;
+ if (pw > display_pjwidth) pw = display_pjwidth;
+ project = new rviewText(ctrlPanel);
+ projBut = new rviewButton(ctrlPanel);
+ projMinus = new rviewButton(ctrlPanel, "-");
+ advance = new rviewText(ctrlPanel);
+ projPlus = new rviewButton(ctrlPanel, "+");
+ typeMsg = new wxMessage(ctrlPanel, "");
+
+ // Have to duplicate this code bit.
+ sprintf(buffer, "%s: %s", lman->lookup("textBaseType"), rviewBaseTypes[baseType]);
+ typeMsg->SetLabel(buffer);
+
+ frameWidth=-1;
+ frameWidth=-1;
+
+ RMDBGEXIT(3, RMDebug::module_applications, "rviewDisplay", "rviewDisplay()");
+}
+
+
+rviewDisplay::~rviewDisplay(void)
+{
+ if((displayFlags & display_flag_standalone & display_flag_update) != 0)
+ RMDBGEXIT(3, RMDebug::module_applications, "rviewDisplay", "~rviewDisplay() [UA]")
+ else if ((displayFlags & display_flag_standalone) != 0)
+ RMDBGEXIT(3, RMDebug::module_applications, "rviewDisplay", "~rviewDisplay() [A]")
+ else if ((displayFlags & display_flag_update) != 0)
+ RMDBGEXIT(3, RMDebug::module_applications, "rviewDisplay", "~rviewDisplay() [U]")
+
+ // Update display dying, notify other frames (-> query windows)
+ if ((displayFlags & display_flag_update) != 0)
+ {
+ user_event ue;
+ ue.type = usr_update_closed;
+ ue.data = (void*)(&mddObj);
+ if (frameManager != NULL)
+ frameManager->broadcastUserEvent(ue);
+ }
+ // If standalone free all memory.
+ if ((displayFlags & display_flag_standalone) != 0)
+ {
+ mddObj.destroy();
+ }
+}
+
+
+// notify the parent window that a viewer has been closed;
+// called from viewer destructor.
+void rviewDisplay::closeViewer(void)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewDisplay", "closeViewer()");
+
+ if (!closeViewerCalled)
+ {
+ if (parentFrame != NULL)
+ {
+ mdd_frame mf;
+ user_event ue;
+ mf.flags = getViewerType(); mf.mdd = mddObj;
+ ue.type = usr_viewer_closed; ue.data = (void*)(&mf);
+ parentFrame->userEvent(ue);
+ }
+ closeViewerCalled = TRUE;
+ }
+}
+
+
+const char *rviewDisplay::getFrameName(void) const
+{
+ return "rviewDisplay";
+}
+
+rviewFrameType rviewDisplay::getFrameType(void) const
+{
+ return rviewFrameTypeDisplay;
+}
+
+
+const r_Minterval &rviewDisplay::getVirtualDomain(void) const
+{
+ return interv;
+}
+
+
+// Must concentrate all functionality relying on virtual functions here rather than
+// the constructor
+int rviewDisplay::openViewer(void)
+{
+ int w, h, x, y;
+ char buffer[STRINGSIZE];
+
+ RMDBGONCE(3, RMDebug::module_applications, "rviewDisplay", "openViewer()");
+
+ mBar = new wxMenuBar;
+
+ wxMenu *menu = new wxMenu;
+ menu->Append(MENU_DISP_DATA_INSERT, "");
+ menu->Append(MENU_DISP_DATA_INSERTPRO, "");
+ menu->Append(MENU_DISP_DATA_SAVE, "");
+ fileMenuInitHook(menu);
+ menu->Append(MENU_DISP_DATA_CLOSE, "");
+ sprintf(buffer, "&%s", lman->lookup("menDispData"));
+ mBar->Append(menu, buffer);
+
+ menu = new wxMenu;
+ menu->Append(MENU_DISP_VIEW_SAVE, "");
+ menu->Append(MENU_DISP_VIEW_LOAD, "");
+ viewMenuInitHook(menu);
+ sprintf(buffer, "&%s", lman->lookup("menDispView"));
+ mBar->Append(menu, buffer);
+
+ menuBarInitHook();
+
+ GetSize(&w, &h);
+ //lastWidth = w; lastHeight = h;
+ GetClientSize(&x, &y);
+ mbarHeight = h - y;
+ //cout << "mbar height " << mbarHeight << endl;
+
+ SetMenuBar(mBar);
+
+ newDBState(rmanClientApp::theApp()->ReadDBState());
+
+ return 0;
+}
+
+
+void rviewDisplay::setModeDimension(int dim)
+{
+ bool enable;
+ char adbuff[4];
+
+ dimMode = dim; sprintf(adbuff, "%d", dim);
+ advance->SetValue(adbuff);
+ enable = (dimMDD > dimMode);
+ projPlus->Enable(enable); projMinus->Enable(enable); advance->Enable(enable);
+}
+
+
+void rviewDisplay::label(void)
+{
+ char btbuf[STRINGSIZE];
+
+ mBar->SetLabel(MENU_DISP_DATA_INSERT, lman->lookup("menDispDataIsrt"));
+ mBar->SetLabel(MENU_DISP_DATA_INSERTPRO, lman->lookup("menDispDataIsrtPro"));
+ mBar->SetLabel(MENU_DISP_DATA_SAVE, lman->lookup("menDispDataSave"));
+ mBar->SetLabel(MENU_DISP_DATA_CLOSE, lman->lookup("menDispDataClose"));
+ mBar->SetLabelTop(0, lman->lookup("menDispData"));
+
+ mBar->SetLabel(MENU_DISP_VIEW_SAVE, lman->lookup("menDispViewSave"));
+ mBar->SetLabel(MENU_DISP_VIEW_LOAD, lman->lookup("menDispViewLoad"));
+ mBar->SetLabelTop(1, lman->lookup("menDispView"));
+
+ project->SetLabel(lman->lookup("textProjString"));
+ projBut->SetLabel(lman->lookup("textOK"));
+
+ sprintf(btbuf, "%s: %s", lman->lookup("textBaseType"), rviewBaseTypes[baseType]);
+ typeMsg->SetLabel(btbuf);
+}
+
+
+void rviewDisplay::newDBState(bool dbstate)
+{
+ mBar->Enable(MENU_DISP_DATA_INSERT, dbstate);
+ mBar->Enable(MENU_DISP_DATA_INSERTPRO, dbstate);
+}
+
+
+int rviewDisplay::process(wxObject &obj, wxEvent &evt)
+{
+ int type = evt.GetEventType();
+
+ if (((&obj == (wxObject*)project) && (type == wxEVENT_TYPE_TEXT_ENTER_COMMAND)) || ((&obj == (wxObject*)projBut) && (type == wxEVENT_TYPE_BUTTON_COMMAND)))
+ {
+ strcpy(projString, project->GetValue());
+ newProjection();
+ return 1;
+ }
+ if (((&obj == (wxObject*)projPlus) || (&obj == (wxObject*)projMinus)) && (type == wxEVENT_TYPE_BUTTON_COMMAND))
+ {
+ if (advanceProjection((&obj == (wxObject*)projPlus) ? 1 : -1) != 0)
+ {
+ strcpy(projString, project->GetValue());
+ newProjection();
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+void rviewDisplay::OnSize(int w, int h)
+{
+ int x, y, pw, pos, minw, minh;
+ float tw, th;
+
+ RMDBGONCE(3, RMDebug::module_applications, "rviewDisplay", "OnSize(" << w << ", " << h << " )");
+
+ if (!displayOperation)
+ {
+ project->GetTextExtent((const char*)(lman->lookup("textProjString")), &tw, &th, NULL, NULL, wxSWISS_FONT, FALSE);
+ minw = display_minwidth + ((int)tw);
+ if (minw < minViewX) minw = minViewX;
+ minh = totalCtrlHeight + minViewY + mbarHeight;
+ if ((w < minw) || (h < minh))
+ {
+ // Avoid infinite loops / reentrancy
+ displayOperation = TRUE;
+ if (w < minw) w = minw;
+ if (h < minh) h = minh;
+ //cout << "resize display frame to " << w << ", " << h << " / min " << minViewX << ", " << minViewY << endl;
+ SetSize(-1, -1, w, h);
+ displayOperation = FALSE;
+ }
+ }
+
+ GetClientSize(&x, &y);
+
+ ctrlPanel->SetSize(0, 0, x, totalCtrlHeight);
+ pos = x - 3*display_pbwidth - display_border;
+ pw = pos - 3*display_border - display_pbwidth;
+ x -= 2*display_border;
+ project->SetSize(display_border, display_border, pw, display_pjheight);
+ y = display_border + (display_pjheight - display_pbheight);
+ projBut->SetSize(2*display_border + pw, y, display_pbwidth, display_pbheight);
+ projMinus->SetSize(pos, y, display_pbwidth, display_pbheight);
+ advance->SetSize(pos + display_pbwidth, y - display_border, display_pbwidth, 4*display_pbheight/3);
+ projPlus->SetSize(pos + 2*display_pbwidth, y, display_pbwidth, display_pbheight);
+
+ // Default label font seems to be swiss font. Changing it doesn't appear to
+ // have any effect.
+ typeMsg->GetTextExtent((const char*)(typeMsg->GetLabel()), &tw, &th, NULL, NULL, wxSWISS_FONT, FALSE);
+ typeMsg->SetSize(display_border + x - tw, display_border, tw, th);
+}
+
+
+
+void rviewDisplay::OnMenuCommand(int id)
+{
+ switch (id)
+ {
+ case MENU_DISP_DATA_INSERT:
+ rmanClientApp::theApp()->insertMDD(mddObj);
+ break;
+ case MENU_DISP_DATA_INSERTPRO:
+ {
+ r_Minterval useInterv(dimMDD);
+ int i;
+
+ for (i=0; i<dimMDD; i++)
+ useInterv << r_Sinterval((r_Range)pt1[i], (r_Range)pt2[i]);
+
+ rmanClientApp::theApp()->insertMDD(mddObj, NULL, &useInterv);
+ }
+ break;
+ case MENU_DISP_DATA_SAVE:
+ {
+ char *prefDir = (char*)(prefs->filePath.ptr());
+ char *s = wxFileSelector(lman->lookup("saveData"), (::wxDirExists(prefDir)) ? prefDir : NULL, NULL, NULL, "*", 0, this);
+
+ if (s)
+ {
+ FILE *fp;
+ size_t dataSize = (size_t)baseSize;
+ int i;
+
+ prefs->filePath = ::wxPathOnly(s);
+
+ for (i=0; i<dimMDD; i++)
+ {
+ dataSize *= (interv[i].high() - interv[i].low() + 1);
+ }
+ if ((fp = fopen(s, "wb")) == NULL)
+ {
+ char buffer[STRINGSIZE];
+ sprintf(buffer, "%s %s", lman->lookup("errorFileOpen"), s);
+ rviewErrorbox::reportError(buffer, rviewDisplay::getFrameName(), "OnMenuCommand");
+ }
+ else
+ {
+ if (fwrite(mddObj->get_array(), 1, dataSize, fp) != dataSize)
+ {
+ char buffer[STRINGSIZE];
+ sprintf(buffer, "%s %s", lman->lookup("errorFileWrite"), s);
+ rviewErrorbox::reportError(buffer, rviewDisplay::getFrameName(), "OnMenuCommand");
+ }
+ fclose(fp);
+ }
+ }
+ }
+ break;
+ case MENU_DISP_DATA_CLOSE:
+ prepareToDie(); this->Close(TRUE);
+ break;
+ case MENU_DISP_VIEW_SAVE:
+ doSaveView();
+ break;
+ case MENU_DISP_VIEW_LOAD:
+ doLoadView();
+ break;
+ default: break;
+ }
+}
+
+
+
+
+int rviewDisplay::userEvent(const user_event &ue)
+{
+ if (ue.type == usr_mdd_dying)
+ {
+ if (*((r_Ref<r_GMarray>*)(ue.data)) == mddObj)
+ {
+ prepareToDie();
+ this->Close(TRUE);
+ return 1;
+ }
+ }
+ if ((ue.type == usr_db_opened) || (ue.type == usr_db_closed))
+ {
+ newDBState((ue.type == usr_db_opened));
+ return 1;
+ }
+ if (ue.type == usr_close_viewers)
+ {
+ Close(TRUE);
+ return 1;
+ }
+ return 0;
+}
+
+
+
+// Virtual function, overload by derived classes if you need to.
+void rviewDisplay::prepareToDie(void)
+{
+}
+
+// Virtual function, overload by derived classes
+int rviewDisplay::newProjection(void)
+{
+ return 0;
+}
+
+int rviewDisplay::fileMenuInitHook(wxMenu *menu)
+{
+ return 0;
+}
+
+int rviewDisplay::viewMenuInitHook(wxMenu *menu)
+{
+ return 0;
+}
+
+int rviewDisplay::menuBarInitHook(void)
+{
+ return 0;
+}
+
+
+
+// Support function for advanceProjection
+const char *rviewDisplay::skipIndexMapping(const char *s)
+{
+ const char *b, *d;
+
+ b = s+1;
+ while ((*b == ' ') || (*b == '\t')) b++;
+ d = b;
+ while ((*b >= '0') && (*b <= '9')) b++;
+ if (b == d) return NULL;
+ while ((*b == ' ') || (*b == '\t')) b++;
+ if (*b != ']') return NULL;
+ return b+1;
+}
+
+/*
+ * Change the chosen fixed coordinate according to the advancement mode:
+ * relative: coord += direction
+ * absolute: coord = direction
+ * reset: if (direction <= 0) then to start else to end
+ */
+int rviewDisplay::advanceProjection(int direction, int advmode)
+{
+ const char *b, *d;
+ int cordnt;
+ r_Range value;
+ char tailbuff[STRINGSIZE];
+ unsigned int freeDims=0;
+ const char **dimDescs;
+ const r_Minterval useIv = getVirtualDomain();
+
+ if ((dimDescs = new const char*[dimMDD]) == NULL)
+ return 0;
+
+ // Find free dimensions in projection string
+ strcpy(projString, project->GetValue());
+ b = projString; value = 0;
+ while (*b != '\0')
+ {
+ cordnt = 0; // indicates it's a number
+ while ((*b == ' ') || (*b == '\t')) b++;
+ if (*b == '\0') break;
+ if (value < dimMDD) dimDescs[value] = b;
+ if (*b == '*') // not a number
+ {
+ b++; cordnt=1;
+ }
+ else
+ {
+ if ((*b == '-') || (*b == '+')) b++;
+ d = b;
+ while ((*b >= '0') && (*b <= '9')) b++;
+ if (b == d)
+ {
+ delete [] dimDescs; return 0;
+ }
+ }
+ while (*b == ' ') b++;
+ if (*b == '[')
+ {
+ if ((b = skipIndexMapping(b)) == NULL)
+ {
+ delete [] dimDescs; return 0;
+ }
+ }
+ else if (*b == ':')
+ {
+ b++;
+ while ((*b == ' ') || (*b == '\t')) b++;
+ if (*b == '*') b++;
+ else
+ {
+ if ((*b == '-') || (*b == '+')) b++;
+ d = b;
+ while ((*b >= '0') && (*b <= '9')) b++;
+ if (b == d)
+ {
+ delete [] dimDescs; return 0;
+ }
+ }
+ while ((*b == ' ') || (*b == '\t')) b++;
+ if (*b == '[')
+ {
+ if ((b = skipIndexMapping(b)) == NULL)
+ {
+ delete [] dimDescs; return 0;
+ }
+ }
+ }
+ else if (cordnt == 0)
+ {
+ freeDims |= (1<<value);
+ }
+ while ((*b == ' ') || (*b == '\t')) b++;
+ if (*b == ',') b++;
+ value++;
+ }
+ if ((value != dimMDD) || (freeDims == 0))
+ {
+ delete [] dimDescs; return 0;
+ }
+ cordnt = atoi(advance->GetValue());
+ // Is the specified coordinate a free one?
+ if ((cordnt < 0) || (cordnt >= dimMDD) || ((freeDims & (1<<cordnt)) == 0))
+ {
+ for (cordnt=0; cordnt < (int)(8*sizeof(unsigned int)); cordnt++)
+ {
+ // freeDims is != 0 here.
+ if ((freeDims & (1<<cordnt)) != 0) break;
+ }
+ sprintf(tailbuff, "%d", cordnt);
+ advance->SetValue(tailbuff);
+ }
+ b = dimDescs[cordnt];
+ value = atoi(b);
+
+ // Save tail
+ if (cordnt < dimMDD-1)
+ sprintf(tailbuff, ", %s", dimDescs[cordnt+1]);
+ else
+ tailbuff[0] = '\0';
+
+ // update the coordinate according to the advancement mode
+ if (advmode == display_advmode_relative)
+ value += direction;
+ else if (advmode == display_advmode_absolute)
+ value = direction;
+ else if (advmode == display_advmode_reset)
+ {
+ if (direction <= 0)
+ value = useIv[cordnt].low();
+ else
+ value = useIv[cordnt].high();
+ }
+
+ if ((value >= useIv[cordnt].low()) && (value <= useIv[cordnt].high()))
+ {
+ // this cast here is OK, doesn't compromise the function interface.
+ sprintf((char*)b, "%ld%s", value, tailbuff);
+ project->SetValue(projString);
+ delete [] dimDescs;
+ return 1;
+ }
+ delete [] dimDescs;
+ return 0;
+}
+
+
+
+void rviewDisplay::setDisplayTitle(const char *title)
+{
+ char titleString[STRINGSIZE];
+ char *b;
+
+ if (title != NULL)
+ {
+ strcpy(rootTitle, title);
+ }
+ // Create the title postfix string
+ strcpy(titleString, rootTitle);
+ b = titleString + strlen(titleString);
+ if ((displayFlags & (display_flag_standalone | display_flag_update)) != 0)
+ {
+ *b++ = ' '; *b++ = '[';
+ if ((displayFlags & display_flag_standalone) != 0)
+ b += sprintf(b, "StAln");
+ if ((displayFlags & display_flag_update) != 0)
+ {
+ b += sprintf(b, "U");
+ if (qwindowID != -1)
+ b += sprintf(b, "d%dq%d", displayID, qwindowID);
+ *b++ = ' ';
+ }
+ *b++ = ']';
+ }
+ *b++ = '\0';
+ SetTitle(titleString);
+}
+
+
+
+void rviewDisplay::noLongerUpdate(void)
+{
+ displayFlags &= ~display_flag_update;
+ setDisplayTitle();
+}
+
+
+
+
+int rviewDisplay::getIdentifier(void) const
+{
+ return displayID;
+}
+
+
+int rviewDisplay::getDisplayCounter(void) const
+{
+ return displayCounter;
+}
+
+
+
+void rviewDisplay::setQueryWindow(int qwid)
+{
+ qwindowID = qwid;
+ setDisplayTitle();
+}
+
+
+
+void rviewDisplay::setMinimumViewerSize(int w, int h)
+{
+ minViewX = w; minViewY = h;
+}
+
+
+
+int rviewDisplay::doSaveView(void)
+{
+ char *name = ::wxFileSelector(lman->lookup("saveView"), (char*)(::wxDirExists(prefs->filePath.ptr()) ? prefs->filePath.ptr() : NULL), NULL, NULL, (char*)viewFileExtension);
+
+ if (name != NULL)
+ {
+ FILE *fp = fopen(name, "w");
+ if (fp != NULL)
+ {
+ fprintf(fp, "%s\n\n", view_HeaderLine);
+ int status = saveView(fp);
+ fclose(fp);
+ return status;
+ }
+ return -1;
+ }
+ return 0;
+}
+
+
+int rviewDisplay::doLoadView(void)
+{
+ char *name = ::wxFileSelector(lman->lookup("loadView"), (char*)(::wxDirExists(prefs->filePath.ptr()) ? prefs->filePath.ptr() : NULL), NULL, NULL, (char*)viewFileExtension);
+
+ if (name != NULL)
+ {
+ FILE *fp = fopen(name, "r");
+ if (fp != NULL)
+ {
+ int status = parseViewFile(fp);
+ fclose(fp);
+ loadViewFinished();
+ newProjection();
+ return status;
+ }
+ return -1;
+ }
+ return 0;
+}
+
+
+int rviewDisplay::parseViewFile(FILE *fp)
+{
+ char *buffer = new char[viewBuffSize];
+ unsigned int line = 0;
+ int status = -1;
+
+ if (fgets(buffer, viewBuffSize, fp) != NULL)
+ {
+ int len = strlen(buffer);
+ line++;
+ if (strncmp(view_HeaderLine, buffer, len-1) == 0)
+ {
+ while (!feof(fp))
+ {
+ if (fgets(buffer, viewBuffSize, fp) == NULL)
+ break;
+ line++;
+ char *b = buffer;
+ while (isspace((unsigned int)(*b))) b++;
+ if (*b != '\0')
+ {
+ char *key = b;
+ while (isalnum((unsigned int)(*b))) b++;
+ char *kend = b;
+ while (isspace((unsigned int)(*b))) b++;
+ if (*b != '=')
+ {
+ cerr << "Missing '=' at line " << line << endl;
+ }
+ else
+ {
+ *kend = '\0'; b++;
+ while (isspace((unsigned int)(*b))) b++;
+ len = strlen(b);
+ while ((len > 0) && (isspace((unsigned int)(b[len-1])))) b[--len] = '\0';
+ //cout << "key " << key << ", value " << b << endl;
+ if (readView(key, b) < 0)
+ {
+ delete [] buffer;
+ return -1;
+ }
+ }
+ }
+ }
+ status = 0;
+ }
+ }
+ delete [] buffer;
+ return status;
+}
+
+
+void rviewDisplay::loadViewFinished(void)
+{
+ project->SetValue(projString);
+}
+
+
+void rviewDisplay::writeViewKey(FILE *fp, const char *key)
+{
+ fprintf(fp, "%s\t=\t", key);
+}
+
+
+void rviewDisplay::writeViewParam(FILE *fp, const char *key, const char *value)
+{
+ fprintf(fp, "%s\t=\t%s\n", key, value);
+}
+
+
+void rviewDisplay::writeViewParam(FILE *fp, const char *key, long value)
+{
+ fprintf(fp, "%s\t=\t%ld\n", key, value);
+}
+
+
+void rviewDisplay::writeViewParam(FILE *fp, const char *key, double value)
+{
+ fprintf(fp, "%s\t=\t%.15f\n", key, value);
+}
+
+
+void rviewDisplay::writeViewParam(FILE *fp, const char *key, unsigned int num, const long *values)
+{
+ fprintf(fp, "%s\t=\t%ld", key, values[0]);
+ for (unsigned int i=1; i<num; i++)
+ fprintf(fp, ", %ld", values[i]);
+ fprintf(fp, "\n");
+}
+
+
+void rviewDisplay::writeViewParam(FILE *fp, const char *key, unsigned int num, const double *values)
+{
+ fprintf(fp, "%s\t=\t%.15f", key, values[0]);
+ for (unsigned int i=1; i<num; i++)
+ fprintf(fp, ", %.15f", values[i]);
+ fprintf(fp, "\n");
+}
+
+
+int rviewDisplay::readVector(const char *value, unsigned int num, long *values)
+{
+ unsigned int i = 0;
+ const char *b, *rest;
+
+ b = value;
+ while (i < num)
+ {
+ while (isspace((unsigned int)(*b))) b++;
+ values[i] = strtol(b, (char**)&rest, 10);
+ if (rest == b)
+ return -1;
+ b = rest; i++;
+ while (isspace((unsigned int)(*b))) b++;
+ if (*b == ',') b++;
+ }
+ return 0;
+}
+
+
+int rviewDisplay::readVector(const char *value, unsigned int num, double *values)
+{
+ unsigned int i = 0;
+ const char *b, *rest;
+
+ b = value;
+ while (i < num)
+ {
+ while (isspace((unsigned int)(*b))) b++;
+ values[i] = strtod(b, (char**)&rest);
+ if (rest == b)
+ return -1;
+ b = rest; i++;
+ while (isspace((unsigned int)(*b))) b++;
+ if (*b == ',') b++;
+ }
+ return 0;
+}
+
+
+int rviewDisplay::saveView(FILE *fp)
+{
+ writeViewParam(fp, view_ViewerType, getFrameName());
+ writeViewParam(fp, view_ProjString, projString);
+ GetSize(&frameWidth, &frameHeight);
+ long wsize[2];
+ wsize[0] = (long)frameWidth; wsize[1] = (long)frameHeight;
+ writeViewParam(fp, view_WindowSize, 2, wsize);
+ return 0;
+}
+
+
+int rviewDisplay::readView(const char *key, const char *value)
+{
+ if (strcmp(key, view_ViewerType) == 0)
+ {
+ if (strcmp(value, getFrameName()) != 0)
+ {
+ char buffer[STRINGSIZE];
+ sprintf(buffer, "%s: %s", lman->lookup("errorViewType"), value);
+ rviewErrorbox::reportError(buffer, getFrameName(), "readView");
+ return -1;
+ }
+ return 1;
+ }
+ else if (strcmp(key, view_ProjString) == 0)
+ {
+ strcpy(projString, value);
+ return 1;
+ }
+ else if (strcmp(key, view_WindowSize) == 0)
+ {
+ long wsize[2];
+ if (readVector(value, 2, wsize) == 0)
+ {
+ SetSize(wsize[0], wsize[1]);
+ return 1;
+ }
+ }
+ return 0;
+}
diff --git a/applications/rview/rviewDisplay.hh b/applications/rview/rviewDisplay.hh
new file mode 100644
index 0000000..7587d06
--- /dev/null
+++ b/applications/rview/rviewDisplay.hh
@@ -0,0 +1,224 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+ * Purpose:
+ *
+ * Base class for all object viewers (rviewImage, rviewChart, rviewTable
+ * and rviewSound). Provides a frame with standard control widgets and
+ * menus, functions for parsing/advancing the projection string and
+ * initializing protected variables according to the MDD object that will
+ * be displayed.
+ *
+ * COMMENTS:
+ * None
+ */
+
+
+#ifndef _RVIEW_DISPLAY_H_
+#define _RVIEW_DISPLAY_H_
+
+
+
+
+#include "rasodmg/ref.hh"
+#include "rasodmg/marray.hh"
+#include "rasodmg/gmarray.hh"
+
+#include "labelManager.hh"
+#include "rviewUtils.hh"
+
+
+
+
+/*
+ * A window containing an display mode + controls
+ */
+class rviewDisplay: public rviewFrame
+{
+ public:
+
+ rviewDisplay(mdd_frame *mf, int es, unsigned int flags=0);
+ virtual ~rviewDisplay(void);
+
+ // must use separate call because no virtual functions beyond level i can
+ // be called in a constructor of level i. This became necessary when the
+ // rviewImage class was split up. Returns 0 for OK, -1 for error.
+ virtual int openViewer(void);
+ // Same reason for virtual calls (getViewerType()) in the destructor; this
+ // functions is called from a viewer's destructor to notify its parent of the
+ // close event.
+ void closeViewer(void);
+
+ virtual void label();
+ virtual int process(wxObject &obj, wxEvent &evt);
+
+ virtual void OnSize(int w, int h);
+ virtual void OnMenuCommand(int id);
+
+ virtual const char *getFrameName(void) const;
+ virtual rviewFrameType getFrameType(void) const;
+ virtual int getViewerType(void) const = 0;
+
+ // Needs to process user events
+ virtual int userEvent(const user_event &ue);
+ // Notify derived classes that they should get ready to die. This is needed
+ // for stuff like images with movie-playback running.
+ virtual void prepareToDie(void);
+ // Notify derived classes that the projection has changed
+ virtual int newProjection(void);
+ // get the minterval to use with the projection string
+ virtual const r_Minterval &getVirtualDomain(void) const;
+
+ // Called when an update object has been replaced with a new one
+ void noLongerUpdate(void);
+ // Returns the display ID (used in for update displays)
+ int getIdentifier(void) const;
+ int getDisplayCounter(void) const;
+ // sets the ID of the query window in case it's an update object
+ void setQueryWindow(int qwindowID);
+
+ // viewer-related constants
+ // Default width and height of display window
+ static const int display_width;
+ static const int display_height;
+ // Space reserved around the canvas
+ static const int display_cnvborder;
+ // Borders used in display window
+ static const int display_border;
+ // Scrollbar steps
+ static const int display_scrstep;
+ // Page stepping
+ static const int display_pgstep;
+ // Height of control area
+ static const int display_cheight;
+ // Height of projection widget
+ static const int display_pjheight;
+ // Maximum width of projection widget
+ static const int display_pjwidth;
+ // Projection OK-button dimensions
+ static const int display_pbwidth;
+ static const int display_pbheight;
+ // Minimum display window size (to avoid X errors)
+ static const int display_minwidth;
+
+ // Display flags
+ static const int display_flag_standalone;
+ static const int display_flag_update;
+
+ // modes for advanceProjection()
+ enum display_advmode_e {
+ display_advmode_relative,
+ display_advmode_absolute,
+ display_advmode_reset
+ };
+
+
+ protected:
+
+ // to allow derived functions to add stuff to the file menu before the quit item
+ virtual int fileMenuInitHook(wxMenu *menu);
+ // to allow derived functions to add stuff to the view menu
+ virtual int viewMenuInitHook(wxMenu *menu);
+ // for appending menus to the menu bar
+ virtual int menuBarInitHook(void);
+
+ // Called by the derived classes to (un)grey certain widgets
+ void setModeDimension(int dim);
+ // Called by derived classes to set minimum size of viewer window
+ void setMinimumViewerSize(int w, int h);
+ // Advances projection (+/- buttons)
+ const char *skipIndexMapping(const char *s);
+ int advanceProjection(int direction, int advmode=display_advmode_relative);
+ void newDBState(bool dbstate);
+ void setDisplayTitle(const char *title=NULL);
+ // view management
+ int doSaveView(void);
+ int doLoadView(void);
+ int parseViewFile(FILE *fp);
+ static void writeViewKey(FILE *fp, const char *key);
+ static void writeViewParam(FILE *fp, const char *key, const char *value);
+ static void writeViewParam(FILE *fp, const char *key, long value);
+ static void writeViewParam(FILE *fp, const char *key, double value);
+ static void writeViewParam(FILE *fp, const char *key, unsigned int num, const long *values);
+ static void writeViewParam(FILE *fp, const char *key, unsigned int num, const double *values);
+ static int readVector(const char *value, unsigned int num, long *values);
+ static int readVector(const char *value, unsigned int num, double *values);
+
+ // save the current view to a file descriptor
+ virtual int saveView(FILE *fp);
+ // read a parameter from a view file line; returns 0 if unknown key, 1 otherwise
+ virtual int readView(const char *key, const char *value);
+ // loading a new view is finished, allow updating of displays before the redraw
+ virtual void loadViewFinished(void);
+
+ unsigned int displayFlags;
+ r_Ref<r_GMarray> mddObj;
+ r_Minterval interv;
+ r_Point pt1, pt2, mapIndex;
+ int dimMDD, dimMode, baseSize;
+ rviewBaseType baseType;
+ wxMenuBar *mBar;
+ wxPanel *ctrlPanel;
+ rviewText *project, *advance;
+ wxMessage *typeMsg;
+ rviewButton *projBut, *projPlus, *projMinus;
+ char projString[STRINGSIZE];
+ char rootTitle[STRINGSIZE];
+ int extraSpace;
+ int totalCtrlHeight;
+ int displayID;
+ int qwindowID;
+ int minViewX, minViewY, mbarHeight;
+ bool displayOperation;
+ bool objectInitializedOK;
+ // number of menus that are always on the menu bar
+ static const int fixedNumberOfMenus;
+
+
+ private:
+
+ // This variable avoids closeViewer() being called more than once
+ // in case there are viewer classes derived from a common, non-
+ // abstract base class.
+ bool closeViewerCalled;
+
+ // This global variable is incremented every time a display window is
+ // opened. It is used to init the displayID member to identify display
+ // windows by a number.
+ static int displayCounter;
+
+ // file extension of view file
+ static const char *viewFileExtension;
+
+ // size of buffer for view loading
+ static const unsigned int viewBuffSize;
+
+ // view parameter keywords
+ static const char *view_HeaderLine;
+ static const char *view_ViewerType;
+ static const char *view_ProjString;
+ static const char *view_WindowSize;
+};
+
+#endif
diff --git a/applications/rview/rviewIO.cpp b/applications/rview/rviewIO.cpp
new file mode 100644
index 0000000..538dc9f
--- /dev/null
+++ b/applications/rview/rviewIO.cpp
@@ -0,0 +1,718 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+ * PURPOSE:
+ *
+ * rView data exchange interface for storing MDD to the filing system
+ * or loading from it. Currently supported operations are:
+ * - Load TIFF file.
+ * - Save wxPixmap as TIFF to file.
+ * - Load VFF file (if RVIEW_USE_VFF supported; use conversion module)
+ *
+ * COMMENTS:
+ * None
+ */
+
+
+
+#ifdef __GNUG__
+#pragma implementation
+#endif
+
+
+// changed in wxWindows 2.4.2:
+//#include "wx_prec.h"
+#include <wx/wxprec.h>
+
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+
+#ifndef WX_PRECOMP
+#include <wx/wx.h>
+#endif
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <iostream.h>
+
+
+#include "wx_pixmap.h"
+
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#endif
+
+#include "raslib/rmdebug.hh"
+#include "raslib/basetype.hh"
+#include "raslib/parseparams.hh"
+
+#include "rviewIO.hh"
+#include "rviewTypes.hh"
+
+
+#include "tiffio.h"
+
+
+#ifdef RVIEW_USE_VFF
+/*
+ * The use of the conversion module might cause problems, therefore VFF is
+ * optional; if you have problems with it, build rView without VFF support.
+ */
+#include "conversion/vff.hh"
+#endif
+
+
+
+
+r_Parse_Params *rviewIO::dfltParams = NULL;
+char *rviewIO::tiffCompStr = NULL;
+int rviewIO::tiffCompression = COMPRESSION_DEFLATE;
+
+// Base type structure formats
+const char rviewIO::structure_format_mono[] = "marray <bool, [0:%d,0:%d]>";
+const char rviewIO::structure_format_grey[] = "marray <char, [0:%d,0:%d]>";
+const char rviewIO::structure_format_rgb[] = "marray <struct { char red, char green, char blue }, [0:%d,0:%d]>";
+
+const char rviewIO::structure_format_cube8[] = "marray <char, [%d:%d,%d:%d,%d:%d]>";
+const char rviewIO::structure_format_cube16[] = "marray <ushort, [%d:%d,%d:%d,%d:%d]>";
+const char rviewIO::structure_format_cube32[] = "marray <uint, [%d:%d,%d:%d,%d:%d]>";
+
+// parameters
+const char rviewIO::param_KeyTiffComp[] = "comptype";
+const char rviewIO::param_TiffCompNone[] = "none";
+const char rviewIO::param_TiffCompPack[] = "packbits";
+const char rviewIO::param_TiffCompLZW[] = "lzw";
+const char rviewIO::param_TiffCompZLib[] = "deflate";
+const char rviewIO::param_TiffCompJPEG[] = "jpeg";
+
+
+
+rviewIO::rviewIO(void)
+{
+}
+
+
+rviewIO::~rviewIO(void)
+{
+}
+
+
+void rviewIO::ensureParams(void)
+{
+ if (dfltParams == NULL)
+ {
+ tiffCompStr = NULL;
+ tiffCompression = COMPRESSION_DEFLATE;
+
+ dfltParams = new r_Parse_Params;
+ dfltParams->add(param_KeyTiffComp, &tiffCompStr, r_Parse_Params::param_type_string);
+ }
+}
+
+
+void rviewIO::processParams(const char *params)
+{
+ ensureParams();
+ dfltParams->process(params);
+ tiffCompression = COMPRESSION_DEFLATE;
+ if (tiffCompStr != NULL)
+ {
+ if (strcasecmp(tiffCompStr, param_TiffCompNone) == 0)
+ tiffCompression = COMPRESSION_NONE;
+ else if (strcasecmp(tiffCompStr, param_TiffCompPack) == 0)
+ tiffCompression = COMPRESSION_PACKBITS;
+ else if (strcasecmp(tiffCompStr, param_TiffCompLZW) == 0)
+ tiffCompression = COMPRESSION_LZW;
+ else if (strcasecmp(tiffCompStr, param_TiffCompZLib) == 0)
+ tiffCompression = COMPRESSION_DEFLATE;
+ else if (strcasecmp(tiffCompStr, param_TiffCompJPEG) == 0)
+ tiffCompression = COMPRESSION_JPEG;
+ }
+}
+
+
+void rviewIO::terminate(void)
+{
+ if (dfltParams != NULL)
+ {
+ delete dfltParams;
+ dfltParams = NULL;
+ }
+
+ if (tiffCompStr != NULL)
+ {
+ delete [] tiffCompStr;
+ tiffCompStr = NULL;
+ }
+}
+
+
+const char *rviewIO::getExtension(const char *filename)
+{
+ const char *b, *ext;
+
+ b = filename; ext = NULL;
+ while (*b != '\0')
+ {
+ if (*b == '.')
+ ext = b+1;
+ b++;
+ }
+ return ext;
+}
+
+int rviewIO::isTIFF(const char *filename)
+{
+ const char *ext = getExtension(filename);
+
+ // no extension ==> unrecognized
+ if (ext != NULL)
+ {
+ if ((strcasecmp(ext, "tif") == 0) || (strcasecmp(ext, "tiff") == 0))
+ return 1;
+ }
+ return 0;
+}
+
+
+int rviewIO::loadTIFF(const char *filename, r_Ref<r_GMarray> &mddObj, const char *params)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewIO", "loadTIFF()");
+
+ TIFF* tif;
+ uint32 width, height, x, y;
+ uint16 bps, spp, planarc, photom;
+ int depth, stepx, stepy;
+ r_Minterval interv(2);
+ r_Point prun(2);
+ tdata_t buffer;
+ unsigned char *b;
+ char structure[STRINGSIZE]="";
+
+ if ((tif = TIFFOpen(filename, "r")) == NULL)
+ return RVIEW_IO_NOTFOUND;
+
+ TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);
+ TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);
+ TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bps);
+ TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &spp);
+ TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &planarc);
+ TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photom);
+
+ if ((width < 1) || (height < 1)) return 0;
+
+ RMDBGMIDDLE(3, RMDebug::module_applications, "rviewIO", "loadTIFF() Width " << width << ", height " << height << ", bps " << bps << ", spp " << spp << ", planarconfig " << planarc);
+
+ depth = bps * spp;
+
+ interv << r_Sinterval(r_Range(0), r_Range(width-1)) << r_Sinterval(r_Range(0), r_Range(height-1));
+
+ if ((buffer = _TIFFmalloc(TIFFScanlineSize(tif))) == NULL)
+ {
+ TIFFClose(tif); return RVIEW_IO_MEMORY;
+ }
+
+ switch (depth)
+ {
+ case 1:
+ {
+ r_Ref<r_Marray<r_Boolean> > mddPtr = new r_Marray<r_Boolean>(interv);
+ r_Boolean *imgLine, *imgPtr;
+ r_Boolean min, max;
+ char val=0;
+ int mask;
+
+ // Adjust the photometric interpretation. Later on 0 will be interpreted as black.
+ if (photom == PHOTOMETRIC_MINISWHITE)
+ {
+ min = 1; max = 0;
+ }
+ else
+ {
+ min = 0; max = 1;
+ }
+ stepx = &((*mddPtr)[r_Point(1,0)]) - &((*mddPtr)[r_Point(0,0)]);
+ stepy = &((*mddPtr)[r_Point(0,1)]) - &((*mddPtr)[r_Point(0,0)]);
+ imgLine = (r_Boolean*)(mddPtr->get_array());
+ for (y=0; y<height; y++, imgLine += stepy)
+ {
+ if (planarc == PLANARCONFIG_CONTIG)
+ {
+ TIFFReadScanline(tif, buffer, y);
+ }
+#ifdef FILLORDER_MSB2LSB
+ mask = 0;
+#else
+ mask = 0x100;
+#endif
+ imgPtr = imgLine; b = (unsigned char*)buffer;
+ for (x=0; x<width; x++, imgPtr += stepx)
+ {
+#ifdef FILLORDER_MSB2LSB
+ if (mask == 0) {val = *b++; mask = 0x80;}
+ *imgPtr = ((val & mask) == 0) ? min : max;
+ mask >>= 1;
+#else
+ if (mask == 0x100) {val = *b++; mask = 1;}
+ *imgPtr = ((val & mask) == 0) ? min : max;
+ mask <<= 1;
+#endif
+ }
+ }
+ mddPtr->set_type_by_name(rviewTypeNames[rbt_bool][2-1]);
+ // Init base structure (hack, but better than leaving it undefined)
+ sprintf(structure, structure_format_mono, width-1, height-1);
+ mddObj = (r_Ref<r_GMarray>)mddPtr;
+ }
+ break;
+ case 8:
+ {
+ int paletteIsGrey = 0;
+
+ uint16 *reds, *greens, *blues;
+
+ TIFFGetField(tif, TIFFTAG_COLORMAP, &reds, &greens, &blues);
+ if (photom == PHOTOMETRIC_PALETTE)
+ {
+ for (x=0; x<256; x++)
+ {
+ if ((reds[x] != greens[x]) || (greens[x] != blues[x])) break;
+ }
+ if (x >= 256) paletteIsGrey = 1;
+ }
+ if ((photom == PHOTOMETRIC_PALETTE) && (paletteIsGrey == 0))
+ {
+ r_Ref<r_Marray<RGBPixel> > mddPtr = new r_Marray<RGBPixel>(interv);
+ RGBPixel *imgLine, *imgPtr;
+
+ stepx = &((*mddPtr)[r_Point(1,0)]) - &((*mddPtr)[r_Point(0,0)]);
+ stepy = &((*mddPtr)[r_Point(0,1)]) - &((*mddPtr)[r_Point(0,0)]);
+ imgLine = (RGBPixel*)(mddPtr->get_array());
+ for (y=0; y<height; y++, imgLine += stepy)
+ {
+ if (planarc == PLANARCONFIG_CONTIG)
+ {
+ TIFFReadScanline(tif, buffer, y);
+ }
+ imgPtr = imgLine; b = (unsigned char*)buffer;
+ for (x=0; x<width; x++, imgPtr += stepx, b++)
+ {
+ imgPtr->red = (reds[*b] >> 8);
+ imgPtr->green = (greens[*b] >> 8);
+ imgPtr->blue = (blues[*b] >> 8);
+ }
+ }
+ mddPtr->set_type_by_name(rviewTypeNames[rbt_rgb][2-1]);
+ sprintf(structure, structure_format_rgb, width-1, height-1);
+ mddObj = (r_Ref<r_GMarray>)mddPtr;
+ }
+ else
+ {
+ r_Ref<r_Marray<r_Char> > mddPtr = new r_Marray<r_Char>(interv);
+ r_Char *imgLine, *imgPtr;
+ r_Char transTab[256];
+
+ if (paletteIsGrey != 0)
+ {
+ for (x=0; x<256; x++) transTab[x] = (reds[x] >> 8);
+ }
+ else
+ {
+ // Build a translation table depending on the photometric interpretation
+ if (photom == PHOTOMETRIC_MINISWHITE)
+ {
+ for (x=0; x<256; x++) transTab[x] = 255-x;
+ }
+ else // default to minisblack
+ {
+ for (x=0; x<256; x++) transTab[x] = x;
+ }
+ }
+
+ stepx = &((*mddPtr)[r_Point(1,0)]) - &((*mddPtr)[r_Point(0,0)]);
+ stepy = &((*mddPtr)[r_Point(0,1)]) - &((*mddPtr)[r_Point(0,0)]);
+ imgLine = (r_Char*)(mddPtr->get_array());
+ for (y=0; y<height; y++, imgLine += stepy)
+ {
+ if (planarc == PLANARCONFIG_CONTIG)
+ {
+ TIFFReadScanline(tif, buffer, y);
+ }
+ imgPtr = imgLine; b = (unsigned char*)buffer;
+ for (x=0; x<width; x++, imgPtr += stepx, b++)
+ {
+ *imgPtr = transTab[*b];
+ }
+ }
+ mddPtr->set_type_by_name(rviewTypeNames[rbt_char][2-1]);
+ sprintf(structure, structure_format_grey, width-1, height-1);
+ mddObj = (r_Ref<r_GMarray>)mddPtr;
+ }
+ }
+ break;
+ case 24:
+ {
+ r_Ref<r_Marray<RGBPixel> > mddPtr = new r_Marray<RGBPixel>(interv);
+ RGBPixel *imgLine, *imgPtr;
+
+ stepx = &((*mddPtr)[r_Point(1,0)]) - &((*mddPtr)[r_Point(0,0)]);
+ stepy = &((*mddPtr)[r_Point(0,1)]) - &((*mddPtr)[r_Point(0,0)]);
+ imgLine = (RGBPixel*)(mddPtr->get_array());
+ //cout << "stepx=" << stepx << ", stepy=" << stepy << endl;
+ for (y=0; y<height; y++, imgLine += stepy)
+ {
+ if (planarc == PLANARCONFIG_CONTIG)
+ {
+ TIFFReadScanline(tif, buffer, y);
+ }
+ imgPtr = imgLine; b = (unsigned char*)buffer;
+ for (x=0; x<width; x++, imgPtr += stepx, b+=3)
+ {
+ imgPtr->red = b[0];
+ imgPtr->green = b[1];
+ imgPtr->blue = b[2];
+ }
+ }
+ mddPtr->set_type_by_name(rviewTypeNames[rbt_rgb][2-1]);
+ sprintf(structure, structure_format_rgb, width-1, height-1);
+ mddObj = (r_Ref<r_GMarray>)mddPtr;
+ }
+ break;
+ default: return RVIEW_IO_FORMAT;
+ }
+
+ if (structure[0] != 0)
+ mddObj->set_type_structure(structure);
+
+ _TIFFfree(buffer);
+
+ TIFFClose(tif);
+
+ RMDBGEXIT(3, RMDebug::module_applications, "rviewImage", "~rviewImage() Created MDD object of domain " << mddObj->spatial_domain());
+
+ return RVIEW_IO_OK;
+}
+
+
+int rviewIO::saveTIFF(const char *filename, r_Ref<r_GMarray> &mddPtr, const char *params)
+{
+ cout << "rviewIO::saveTIFF() not implemented" << endl;
+ return RVIEW_IO_UNSUPP;
+}
+
+
+
+/*
+ * Save a wxPixmap as a TIFF image
+ */
+
+int rviewIO::PixmapToTIFF(wxPixmap *pixmap, const char *filename, const char *params)
+{
+ TIFF *tif;
+ int depth, pitch;
+ uint32 width, height;
+ uint8 *srcLine;
+ uint32 i;
+
+ depth = pixmap->getDepth(); pitch = pixmap->getPitch();
+ width = (uint32)(pixmap->getWidth()); height = (uint32)(pixmap->getHeight());
+
+ if ((tif = TIFFOpen(filename, "w")) == NULL)
+ {
+ char buffer[STRINGSIZE];
+
+ sprintf(buffer, "%s %s.\n", lman->lookup("errorFileOpen"), filename);
+ rviewErrorbox eb(buffer); eb.activate();
+ return -1;
+ }
+
+ processParams(params);
+
+ TIFFSetField(tif, TIFFTAG_ARTIST, "rView");
+ TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width);
+ TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height);
+ TIFFSetField(tif, TIFFTAG_COMPRESSION, tiffCompression);
+ TIFFSetField(tif, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB);
+ TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
+ TIFFSetField(tif, TIFFTAG_XRESOLUTION, 90.0);
+ TIFFSetField(tif, TIFFTAG_YRESOLUTION, 90.0);
+
+ srcLine = (uint8*)(pixmap->getData());
+
+ switch (depth)
+ {
+ case 1:
+ {
+ wxColour *pal;
+
+ pal = pixmap->getPalette();
+ if (pal == NULL)
+ {
+ TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
+ }
+ else
+ {
+ if ((int)(pal[0].Red()+pal[0].Green()+pal[0].Blue()) < (int)(pal[1].Red()+pal[1].Green()+pal[1].Blue()))
+ {
+ TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
+ }
+ else
+ {
+ TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE);
+ }
+ }
+ TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 1);
+ TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
+ for (i=0; i<height; i++, srcLine += pitch)
+ {
+ if (TIFFWriteScanline(tif, (tdata_t)srcLine, i, 0) < 0) break;
+ }
+ }
+ break;
+ case 8:
+ {
+ wxColour *pal;
+
+ pal = pixmap->getPalette();
+ TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
+ TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
+ if (pal == NULL)
+ {
+ TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
+ }
+ else
+ {
+ uint16 reds[256], greens[256], blues[256];
+
+ TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE);
+ for (i=0; i<256; i++)
+ {
+ reds[i] = ((pal[i].Red() << 16) - 1) / 255;
+ greens[i] = ((pal[i].Green() << 16) - 1) / 255;
+ blues[i] = ((pal[i].Blue() << 16) -1) / 255;
+ }
+ TIFFSetField(tif, TIFFTAG_COLORMAP, reds, greens, blues);
+ }
+ for (i=0; i<height; i++, srcLine += pitch)
+ {
+ if (TIFFWriteScanline(tif, (tdata_t)srcLine, i, 0) < 0) break;
+ }
+ }
+ break;
+ case 15:
+ {
+ uint32 j;
+ uint8 *destLine, *destPtr;
+ uint16 *srcPtr;
+
+ destLine = new uint8[3*width];
+ TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
+ TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3);
+ TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
+ for (i=0; i<height; i++, srcLine += pitch)
+ {
+ destPtr = destLine; srcPtr = (uint16*)srcLine;
+ for (j=0; j<width; j++, srcPtr++, destPtr+=3)
+ {
+ destPtr[0] = (*srcPtr & 0x1f) << 3;
+ destPtr[1] = (*srcPtr & 0x3e0) >> 2;
+ destPtr[2] = (*srcPtr & 0x7c00) >> 7;
+ }
+ if (TIFFWriteScanline(tif, (tdata_t)destLine, i, 0) < 0) break;
+ }
+ delete [] destLine;
+ }
+ break;
+ case 24:
+ {
+ TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
+ TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3);
+ TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
+ for (i=0; i<height; i++, srcLine += pitch)
+ {
+ if (TIFFWriteScanline(tif, (tdata_t)srcLine, i, 0) < 0) break;
+ }
+ }
+ break;
+ case 32:
+ {
+ uint32 j;
+ uint8 *destLine, *destPtr;
+ uint32 *srcPtr;
+
+ destLine = new uint8[3*width];
+ TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
+ TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3);
+ TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
+ for (i=0; i<height; i++, srcLine += pitch)
+ {
+ destPtr = destLine; srcPtr = (uint32*)srcLine;
+ for (j=0; j<width; j++, srcPtr++, destPtr+=3)
+ {
+ destPtr[0] = (*srcPtr & 0xff);
+ destPtr[1] = (*srcPtr >> 8) & 0xff;
+ destPtr[2] = (*srcPtr >> 16) & 0xff;
+ }
+ if (TIFFWriteScanline(tif, (tdata_t)destLine, i, 0) < 0) break;
+ }
+ delete [] destLine;
+ }
+ break;
+ default:
+ cerr << "rviewIO::PixmapToTIFF(): Unsupported pixmap depth (" << depth << ')' << endl;
+ TIFFClose(tif);
+ break;
+ }
+
+ TIFFClose(tif);
+
+ if (i < height)
+ {
+ char buffer[STRINGSIZE];
+
+ sprintf(buffer, "%s %s.\n", lman->lookup("errorFileWrite"), filename);
+ rviewErrorbox eb(buffer); eb.activate();
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int rviewIO::isVFF(const char *filename)
+{
+ const char *ext = getExtension(filename);
+
+ if (ext != NULL)
+ {
+ if (strcasecmp(ext, "vff") == 0)
+ return 1;
+ }
+ return 0;
+}
+
+
+int rviewIO::loadVFF(const char *filename, r_Ref<r_GMarray> &mddPtr, const char *params)
+{
+#ifdef RVIEW_USE_VFF
+ FILE *fp;
+
+ if ((fp = fopen(filename, "rb")) != NULL)
+ {
+ unsigned long vffSize;
+ char *vffData;
+
+ fseek(fp, 0, SEEK_END);
+ vffSize = ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+ vffData = new char[vffSize];
+ fread(vffData, 1, vffSize, fp);
+ fclose(fp);
+
+ r_Minterval dom(1);
+ dom << r_Sinterval((r_Range)0, (r_Range)vffSize-1);
+
+ r_Conv_VFF vff(vffData, dom, r_Convertor::ctype_char);
+ r_Storage_Man_CPP sman;
+ vff.set_storage_handler(sman);
+ try
+ {
+ r_convDesc desc = vff.convertFrom(params);
+ delete [] vffData;
+ if (desc.destInterv.dimension() == 3)
+ {
+ const char *fmtString = NULL;
+ const char *nameString = NULL;
+
+ // Hmm... we seem to lack a set_type_schema() method...
+ switch (desc.destType->type_id())
+ {
+ case r_Type::BOOL:
+ case r_Type::CHAR:
+ case r_Type::OCTET:
+ fmtString = structure_format_cube8;
+ nameString = rviewTypeNames[rbt_char][2];
+ break;
+ case r_Type::SHORT:
+ case r_Type::USHORT:
+ fmtString = structure_format_cube16;
+ nameString = rviewTypeNames[rbt_ushort][2];
+ break;
+ case r_Type::LONG:
+ case r_Type::ULONG:
+ fmtString = structure_format_cube32;
+ nameString = rviewTypeNames[rbt_ulong][2];
+ break;
+ default:
+ break;
+ }
+ if (fmtString != NULL)
+ {
+ char fmtBuffer[STRINGSIZE];
+
+ sprintf(fmtBuffer, fmtString, desc.destInterv[0].low(), desc.destInterv[0].high(), desc.destInterv[1].low(), desc.destInterv[1].high(), desc.destInterv[2].low(), desc.destInterv[2].high());
+ mddPtr = new r_GMarray;
+ mddPtr->set_spatial_domain(desc.destInterv);
+ mddPtr->set_array(desc.dest);
+ mddPtr->set_type_structure(fmtBuffer);
+ mddPtr->set_type_by_name(nameString);
+ mddPtr->set_type_length(((const r_Base_Type*)desc.destType)->size());
+ mddPtr->set_current_format(r_Array);
+ mddPtr->set_array_size(mddPtr->spatial_domain().cell_count() * mddPtr->get_type_length());
+ //cout << "LOADED VFF " << mddPtr->spatial_domain() << ", " << mddPtr->get_type_structure() << ", " << mddPtr->get_type_name() << endl;
+ delete desc.destType;
+ return RVIEW_IO_OK;
+ }
+ }
+ delete desc.destType;
+ delete [] desc.dest;
+ return RVIEW_IO_FORMAT;
+ }
+ catch (r_Error &err)
+ {
+ cerr << "rviewIO::loadVFF(): " << err.what() << endl;
+ delete [] vffData;
+ return RVIEW_IO_FORMAT;
+ }
+ }
+ return RVIEW_IO_NOTFOUND;
+#else
+ return RVIEW_IO_UNSUPP;
+#endif
+}
+
+
+int rviewIO::saveVFF(const char *filename, r_Ref<r_GMarray> &mddPtr, const char *params)
+{
+ cout << "rviewIO::saveVFF() not implemented" << endl;
+ return RVIEW_IO_UNSUPP;
+}
diff --git a/applications/rview/rviewIO.hh b/applications/rview/rviewIO.hh
new file mode 100644
index 0000000..dfede12
--- /dev/null
+++ b/applications/rview/rviewIO.hh
@@ -0,0 +1,121 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+ * PURPOSE:
+ *
+ * rView data exchange interface for storing MDD to the filing system
+ * or loading from it. Currently supported operations are:
+ * - Load TIFF file.
+ * - Save wxPixmap as TIFF to file.
+ *
+ * COMMENTS:
+ * None
+ */
+
+
+
+#ifndef _RVIEW_IO_H_
+#define _RVIEW_IO_H_
+
+
+#ifdef __GNUG__
+#pragma interface
+#endif
+
+
+
+#include "rasodmg/ref.hh"
+#include "rasodmg/marray.hh"
+#include "rasodmg/gmarray.hh"
+
+#include "rviewUtils.hh"
+
+
+
+// Return status
+enum rviewIoStates {
+ RVIEW_IO_OK,
+ RVIEW_IO_NOTFOUND,
+ RVIEW_IO_MEMORY,
+ RVIEW_IO_UNSUPP,
+ RVIEW_IO_FORMAT
+};
+
+
+// pixmap conversion functions
+class wxPixmap;
+
+// parameter parser
+class r_Parse_Params;
+
+
+class rviewIO
+{
+ public:
+
+ rviewIO(void);
+ ~rviewIO(void);
+
+ static void terminate(void);
+
+ static int isTIFF(const char *filename);
+ static int loadTIFF(const char *filename, r_Ref<r_GMarray> &mddPtr, const char *params=NULL);
+ static int saveTIFF(const char *filename, r_Ref<r_GMarray> &mddPtr, const char *params=NULL);
+ static int PixmapToTIFF(wxPixmap *pixmap, const char *filename, const char *params=NULL);
+ static int isVFF(const char *filename);
+ static int loadVFF(const char *filename, r_Ref<r_GMarray> &mddPtr, const char *params=NULL);
+ static int saveVFF(const char *filename, r_Ref<r_GMarray> &mddPtr, const char *params=NULL);
+
+
+ private:
+
+ static void ensureParams(void);
+ static void processParams(const char *params);
+
+ static r_Parse_Params *dfltParams;
+ static char *tiffCompStr;
+ static int tiffCompression;
+
+ static const char *getExtension(const char *filename);
+
+ // tiff compression keywords
+ static const char param_KeyTiffComp[];
+ static const char param_TiffCompNone[];
+ static const char param_TiffCompPack[];
+ static const char param_TiffCompLZW[];
+ static const char param_TiffCompZLib[];
+ static const char param_TiffCompJPEG[];
+
+ // TIFF formats
+ static const char structure_format_mono[];
+ static const char structure_format_grey[];
+ static const char structure_format_rgb[];
+
+ // VFF formats
+ static const char structure_format_cube8[];
+ static const char structure_format_cube16[];
+ static const char structure_format_cube32[];
+};
+
+#endif
diff --git a/applications/rview/rviewImage.cpp b/applications/rview/rviewImage.cpp
new file mode 100644
index 0000000..bdc6e2f
--- /dev/null
+++ b/applications/rview/rviewImage.cpp
@@ -0,0 +1,5230 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+ * Purpose:
+ *
+ * rView graphical display modes (flat and rendered images). Renderers
+ * provided by the cube_render sources, pixmap interface provided by
+ * the new wxWindows class wxPixmap. Also includes the ColourspaceMapper
+ * object.
+ *
+ * COMMENTS:
+ * None
+ */
+
+
+
+// Standard wxWindows preamble.
+#ifdef __GNUG__
+#pragma implementation
+#endif
+
+
+#include <wx/wx_prec.h>
+
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+
+#ifndef WX_PRECOMP
+#include <wx/wx.h>
+#endif
+
+
+
+#include <string.h>
+#include <stdlib.h>
+#include <iostream.h>
+#include <math.h>
+#include <limits.h>
+#include <float.h>
+
+
+// I hate Windows...
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#endif
+
+
+#include "raslib/rmdebug.hh"
+#include "rasodmg/fastscale.hh"
+
+
+// For information about bit order and so on
+#include "wx_pixmap.h"
+#include "wx_pixmap_translate.h"
+
+#include "cube_render.h"
+
+#include "rviewTypes.hh"
+
+#include "labelManager.hh"
+
+#include "rviewUtils.hh"
+#include "rviewMDD.hh"
+#include "rviewDModes.hh"
+#include "rviewColMap.hh"
+#include "rviewPrefs.hh"
+#include "rviewIO.hh"
+#include "rviewDb.hh"
+
+
+
+
+
+
+
+
+// Table mapping base types to visualisztion types
+int rviewImageTypes[] = {
+ RVIEW_IMGTYPE_NONE, // rbt_none
+ RVIEW_IMGTYPE_MONO, // rbt_bool
+ RVIEW_IMGTYPE_GREY, // rbt_char
+ RVIEW_IMGTYPE_GREY, // rbt_uchar
+ RVIEW_IMGTYPE_GREY12, // rbt_short
+ RVIEW_IMGTYPE_HIGH, // rbt_ushort
+ RVIEW_IMGTYPE_TRUE32, // rbt_long
+ RVIEW_IMGTYPE_TRUE32, // rbt_ulong
+ RVIEW_IMGTYPE_TRUE24, // rbt_rgb
+ RVIEW_IMGTYPE_NONE, // rbt_float
+ RVIEW_IMGTYPE_NONE // rbt_double
+};
+
+
+
+
+
+
+/*
+ * rviewImageSetup members
+ */
+
+const int rviewImageSetup::imgset_border = rviewDisplay::display_border;
+const int rviewImageSetup::imgset_theight = 30;
+const int rviewImageSetup::imgset_chkheight = 24;
+const int rviewImageSetup::imgset_renheight = 206;
+const int rviewImageSetup::imgset_voxheight = 256;
+const int rviewImageSetup::imgset_hgtheight = 60;
+const int rviewImageSetup::imgset_bwidth = 80;
+const int rviewImageSetup::imgset_bheight = 40;
+const int rviewImageSetup::imgset_chowidth = 130;
+const int rviewImageSetup::imgset_choheight = 30;
+const int rviewImageSetup::imgset_width = 400;
+const int rviewImageSetup::imgset_height = rviewImageSetup::imgset_renheight + rviewImageSetup::imgset_voxheight + rviewImageSetup::imgset_hgtheight + rviewImageSetup::imgset_bheight + 5*rviewImageSetup::imgset_border + rview_window_extra_height;
+
+
+const char *rviewImageSetup::normalKernelSizes[] = {
+ "0",
+ "1",
+ "2",
+ "3",
+ NULL
+};
+
+const keyword_to_ident_c rviewImageSetup::normalKernelTypes[] = {
+ {RENDER_NORM_KERNEL_HOMO, "kernelTypeAvg"},
+ {RENDER_NORM_KERNEL_LINEAR, "kernelTypeLin"},
+ {RENDER_NORM_KERNEL_GAUSS, "kernelTypeGauss"},
+ {0, NULL}
+};
+
+rviewImageSetup::rviewImageSetup(rview_image_setup *ris, rviewRenderImage *parentWin) : rviewFrame(NULL, lman->lookup("titleImgSetup"), 0, 0, imgset_width, imgset_height)
+{
+ char buffer[STRINGSIZE];
+ int w, h, x, y, off, posx, posy;
+ char **ktypes;
+ char *b;
+ int i;
+
+ parent = parentWin; imgSetup = ris;
+ memcpy(&oldSetup, ris, sizeof(rview_image_setup));
+
+ GetClientSize(&w, &h);
+ panel = new wxPanel((wxWindow*)this, 0, 0, w, h);
+ w -= 2*imgset_border; posx = imgset_border; posy = imgset_border;
+ renderGroup = new wxGroupBox(panel, "", posx, posy, w, imgset_renheight);
+ posy += imgset_renheight + imgset_border;
+ voxelGroup = new wxGroupBox(panel, "", posx, posy, w, imgset_voxheight);
+ posy += imgset_voxheight + imgset_border;
+ heightGroup = new wxGroupBox(panel, "", posx, posy, w, imgset_hgtheight);
+
+ w -= 2*imgset_border; y = imgset_border;
+ posx += imgset_border;
+ renderGroup->GetClientSize(&x, &h); off = y + imgset_renheight - h;
+ h = (h - 5*imgset_theight) / 5;
+
+ zproWidget = new rviewText(panel);
+ clipzWidget = new rviewText(panel);
+ useLights = new rviewCheckBox(panel);
+ lightsAngle = new rviewText(panel);
+ lightsScintAngle = new rviewText(panel);
+ lightsAmbient = new rviewText(panel);
+ lightsGain = new rviewText(panel);
+ lightsDir = new rviewText(panel);
+ lightsDist = new rviewText(panel);
+ pixThreshLowWidget = new rviewText(panel);
+ pixThreshHighWidget = new rviewText(panel);
+ wgtThreshWidget = new rviewText(panel);
+ wgtQuantWidget = new rviewText(panel);
+ kernelSize = new rviewChoice(panel, 4, (char**)normalKernelSizes, lman->lookup("imgSetKernSize"));
+ ktypes = new char *[3];
+ b = buffer;
+ for (i=0; i<3; i++)
+ {
+ ktypes[i] = b; b += 1 + sprintf(b, "%s", lman->lookup(normalKernelTypes[i].keyword));
+ }
+ kernelType = new rviewChoice(panel, 3, ktypes, lman->lookup("imgSetKernType"));
+ delete [] ktypes;
+ useVoxCol = new rviewCheckBox(panel);
+ useRgbBrightness = new rviewCheckBox(panel);
+ voxColour = new rviewText(panel);
+ gridSize = new rviewText(panel);
+ scaleHeight = new rviewText(panel);
+
+ okBut = new rviewButton(panel);
+ cancelBut = new rviewButton(panel);
+
+ label();
+
+ updateSettings(*ris);
+
+ frameWidth=-1;
+ frameHeight=-1;
+
+ OnSize(imgset_width, imgset_height);
+ OnSize(imgset_width, imgset_height);
+
+ Show(TRUE);
+}
+
+
+
+rviewImageSetup::~rviewImageSetup(void)
+{
+ if (parent != NULL)
+ {
+ user_event ue;
+
+ ue.type = usr_child_closed; ue.data = (void*)this;
+ parent->userEvent(ue);
+ }
+}
+
+
+const char *rviewImageSetup::getFrameName(void) const
+{
+ return "rviewImageSetup";
+}
+
+rviewFrameType rviewImageSetup::getFrameType(void) const
+{
+ return rviewFrameTypeImgSet;
+}
+
+
+void rviewImageSetup::unlinkParent(void)
+{
+ parent = NULL;
+}
+
+
+void rviewImageSetup::updateSettings(const rview_image_setup &ris)
+{
+ char buffer[STRINGSIZE];
+ char *b;
+ int i;
+
+ zproWidget->SetValue((long)(ris.zpro));
+ clipzWidget->SetValue((long)(ris.clipz));
+ useLights->SetValue(ris.useLights);
+ lightsAngle->SetValue(ris.lightsAngle);
+ lightsScintAngle->SetValue(ris.lightsScintAngle);
+ lightsAmbient->SetValue(ris.lightsAmbient);
+ lightsGain->SetValue(ris.lightsGain);
+ lightsDist->SetValue(ris.lightsDist);
+ pixThreshLowWidget->SetValue(ris.pixelThresholdLow, TRUE);
+ pixThreshHighWidget->SetValue(ris.pixelThresholdHigh, TRUE);
+ wgtThreshWidget->SetValue(ris.weightThreshold, TRUE);
+ wgtQuantWidget->SetValue(ris.weightQuantisation);
+ useRgbBrightness->SetValue(ris.useRgbBrightness);
+ useVoxCol->SetValue(ris.useVoxCol);
+ voxColour->SetValue(ris.voxColour);
+ gridSize->SetValue(ris.gridSize);
+ scaleHeight->SetValue(ris.scaleHeight);
+
+ if ((ris.kernelSize >= 0) && (ris.kernelSize < 4))
+ {
+ kernelSize->SetSelection(ris.kernelSize);
+ }
+ for (i=0; normalKernelTypes[i].keyword != NULL; i++)
+ {
+ if (normalKernelTypes[i].ident == ris.kernelType)
+ {
+ kernelType->SetSelection(i); break;
+ }
+ }
+ b = buffer;
+ if ((ris.lightsDir & RVIEW_LIGHTDIR_LEFT) != 0) *b++ = 'l';
+ else if ((ris.lightsDir & RVIEW_LIGHTDIR_RIGHT) != 0) *b++ = 'r';
+ if ((ris.lightsDir & RVIEW_LIGHTDIR_DOWN) != 0) *b++ = 'd';
+ else if ((ris.lightsDir & RVIEW_LIGHTDIR_UP) != 0) *b++ = 'u';
+ if ((ris.lightsDir & RVIEW_LIGHTDIR_FRONT) != 0) *b++ = 'f';
+ else if ((ris.lightsDir & RVIEW_LIGHTDIR_BACK) != 0) *b++ = 'b';
+ *b++ = '\0';
+ lightsDir->SetValue(buffer);
+}
+
+
+
+int rviewImageSetup::parseLightDirection(const char *dir)
+{
+ char *b;
+ int val;
+
+ b = (char*)dir;
+ val = 0;
+ while (*b != '\0')
+ {
+ switch (*b)
+ {
+ case 'l': val |= RVIEW_LIGHTDIR_LEFT; break;
+ case 'r': val |= RVIEW_LIGHTDIR_RIGHT; break;
+ case 'd': val |= RVIEW_LIGHTDIR_DOWN; break;
+ case 'u': val |= RVIEW_LIGHTDIR_UP; break;
+ case 'f': val |= RVIEW_LIGHTDIR_FRONT; break;
+ case 'b': val |= RVIEW_LIGHTDIR_BACK; break;
+ default: break;
+ }
+ b++;
+ }
+ return val;
+}
+
+
+void rviewImageSetup::readNewSetup(void)
+{
+ long val;
+
+ val = asctoi(zproWidget->GetValue());
+ if (val > 0) imgSetup->zpro = (unsigned long)val;
+ val = asctoi(clipzWidget->GetValue());
+ if (val > 0) imgSetup->clipz = (unsigned long)val;
+ imgSetup->useLights = useLights->GetValue();
+ imgSetup->lightsAngle = atof(lightsAngle->GetValue());
+ imgSetup->lightsScintAngle = atof(lightsScintAngle->GetValue());
+ imgSetup->lightsAmbient = atof(lightsAmbient->GetValue());
+ imgSetup->lightsGain = atof(lightsGain->GetValue());
+ imgSetup->lightsDist = asctoi(lightsDist->GetValue());
+ imgSetup->pixelThresholdLow = asctof(pixThreshLowWidget->GetValue());
+ imgSetup->pixelThresholdHigh = asctof(pixThreshHighWidget->GetValue());
+ imgSetup->weightThreshold = asctof(wgtThreshWidget->GetValue());
+ imgSetup->useRgbBrightness = useRgbBrightness->GetValue();
+ val = asctoi(wgtQuantWidget->GetValue());
+ if (val >= 0) imgSetup->weightQuantisation = (int)val;
+ imgSetup->kernelSize = kernelSize->GetSelection();
+ imgSetup->kernelType = normalKernelTypes[kernelType->GetSelection()].ident;
+ imgSetup->useVoxCol = useVoxCol->GetValue();
+ imgSetup->voxColour = asctof(voxColour->GetValue());
+ imgSetup->lightsDir = parseLightDirection(lightsDir->GetValue());
+ imgSetup->gridSize = asctoi(gridSize->GetValue());
+ imgSetup->scaleHeight = atof(scaleHeight->GetValue());
+}
+
+
+void rviewImageSetup::label(void)
+{
+ SetTitle(lman->lookup("titleImgSetup"));
+
+ renderGroup->SetLabel(lman->lookup("imgSetRender"));
+ voxelGroup->SetLabel(lman->lookup("imgSetVoxel"));
+ heightGroup->SetLabel(lman->lookup("imgSetHeight"));
+ zproWidget->SetLabel(lman->lookup("imgSetRenZpro"));
+ clipzWidget->SetLabel(lman->lookup("imgSetRenClipz"));
+ useLights->SetLabel(lman->lookup("imgSetRenUseLight"));
+ lightsAngle->SetLabel(lman->lookup("imgSetRenLightAn"));
+ lightsScintAngle->SetLabel(lman->lookup("imgSetRenLightSc"));
+ lightsAmbient->SetLabel(lman->lookup("imgSetRenLightAm"));
+ lightsGain->SetLabel(lman->lookup("imgSetRenLightGn"));
+ lightsDir->SetLabel(lman->lookup("imgSetRenLightDr"));
+ lightsDist->SetLabel(lman->lookup("imgSetRenLightDs"));
+ pixThreshLowWidget->SetLabel(lman->lookup("imgSetVoxPixThreshLow"));
+ pixThreshHighWidget->SetLabel(lman->lookup("imgSetVoxPixThreshHigh"));
+ wgtThreshWidget->SetLabel(lman->lookup("imgSetVoxWgtThresh"));
+ wgtQuantWidget->SetLabel(lman->lookup("imgSetVoxWgtQuant"));
+ useRgbBrightness->SetLabel(lman->lookup("imgSetVoxRgbBright"));
+ kernelSize->SetLabel(lman->lookup("imgSetKernSize"));
+ kernelType->SetLabel(lman->lookup("imgSetKernType"));
+ useVoxCol->SetLabel(lman->lookup("imgSetUseVCol"));
+ voxColour->SetLabel(lman->lookup("imgSetVoxCol"));
+ gridSize->SetLabel(lman->lookup("imgSetGridSize"));
+ scaleHeight->SetLabel(lman->lookup("imgSetHgtScale"));
+ okBut->SetLabel(lman->lookup("textOK"));
+ cancelBut->SetLabel(lman->lookup("textCancel"));
+}
+
+
+
+void rviewImageSetup::OnSize(int w, int h)
+{
+ int x, y, width, height, off, posx, posy;
+
+ GetClientSize(&width, &height);
+
+ //need to resize?
+ if (( imgset_width != width) || ( imgset_height != height))
+ {
+ frameWidth = imgset_width;
+ frameHeight = imgset_height;
+ width= imgset_width;
+ height = imgset_height;
+ SetClientSize(width, height);
+ return;
+ }
+
+ panel->SetSize(0, 0, width, height);
+ width -= 2*imgset_border; height -= 2*imgset_border;
+ posx = imgset_border; posy = imgset_border;
+ renderGroup->SetSize(posx, posy, width, imgset_renheight);
+ posy += imgset_renheight + imgset_border;
+ voxelGroup->SetSize(posx, posy, width, imgset_voxheight);
+ posy += imgset_voxheight + imgset_border;
+ heightGroup->SetSize(posx, posy, width, imgset_hgtheight);
+
+ width -= 2*imgset_border; y = imgset_border;
+ posx += imgset_border; posy += imgset_border;
+ renderGroup->GetClientSize(&x, &height); off = y + imgset_renheight - height;
+ height = (height - 5*imgset_theight) / 5;
+ posy = off + height/2;
+ zproWidget->SetSize(posx, posy, width/2 - imgset_border, imgset_theight, wxTE_PROCESS_ENTER);
+ clipzWidget->SetSize(posx + width/2, posy, width/2, imgset_theight, wxTE_PROCESS_ENTER);
+ posy += height + imgset_theight;
+ useLights->SetSize(posx, posy, width/2, imgset_theight);
+ posy += height + imgset_theight;
+ lightsAngle->SetSize(posx, posy, width/2 - imgset_border, imgset_theight, wxTE_PROCESS_ENTER);
+ lightsScintAngle->SetSize(posx + width/2, posy, width/2, imgset_theight, wxTE_PROCESS_ENTER);
+ posy += height + imgset_theight;
+ lightsAmbient->SetSize(posx, posy, width/2 - imgset_border, imgset_theight, wxTE_PROCESS_ENTER);
+ lightsGain->SetSize(posx + width/2, posy, width/2, imgset_theight, wxTE_PROCESS_ENTER);
+ posy += height + imgset_theight;
+ lightsDir->SetSize(posx, posy, width/2 - imgset_border, imgset_theight, wxTE_PROCESS_ENTER);
+ lightsDist->SetSize(posx + width/2, posy, width/2, imgset_theight, wxTE_PROCESS_ENTER);
+
+ y += imgset_renheight + imgset_border;
+ voxelGroup->GetClientSize(&x, &height); off = y + imgset_voxheight - height;
+ height = (height - 5*imgset_theight - imgset_chkheight - imgset_choheight) / 6;
+ posy = off + height/2;
+ pixThreshLowWidget->SetSize(posx, posy, width, imgset_theight, wxTE_PROCESS_ENTER);
+ posy += height + imgset_theight;
+ pixThreshHighWidget->SetSize(posx, posy, width, imgset_theight, wxTE_PROCESS_ENTER);
+ posy += height + imgset_theight;
+ wgtThreshWidget->SetSize(posx, posy, width, imgset_theight, wxTE_PROCESS_ENTER);
+ posy += height + imgset_theight;
+ wgtQuantWidget->SetSize(posx, posy, width, imgset_theight, wxTE_PROCESS_ENTER);
+ posy += height + imgset_theight;
+ kernelSize->SetSize(posx, posy, imgset_chowidth, imgset_choheight);
+ kernelType->SetSize(width - imgset_chowidth - 3*imgset_border, posy, imgset_chowidth, imgset_choheight);
+ posy += height + imgset_theight;
+ useVoxCol->SetSize(posx, posy, width/2, imgset_theight);
+ useRgbBrightness->SetSize(posx + width/2, posy, width/2, imgset_theight);
+ posy += height + imgset_chkheight;
+ voxColour->SetSize(posx, posy, width, imgset_theight);
+
+ y += imgset_voxheight + imgset_border;
+ heightGroup->GetClientSize(&x, &height); off = y + imgset_hgtheight - height;
+ height = (height - imgset_theight);
+ posy = off + height/2;
+ gridSize->SetSize(posx, posy, width/2 - imgset_border, imgset_theight, wxTE_PROCESS_ENTER);
+ scaleHeight->SetSize(posx + width/2, posy, width/2, imgset_theight, wxTE_PROCESS_ENTER);
+
+ y += imgset_hgtheight + imgset_border;
+ off = (width - 2*imgset_bwidth) / 2;
+ okBut->SetSize(posx + off/2, y, imgset_bwidth, imgset_bheight);
+ cancelBut->SetSize(posx + (3*off)/2 + imgset_bwidth, y, imgset_bwidth, imgset_bheight);
+}
+
+
+
+int rviewImageSetup::process(wxObject &obj, wxEvent &evt)
+{
+ int type;
+
+ type = evt.GetEventType();
+ if (type == wxEVENT_TYPE_BUTTON_COMMAND)
+ {
+ if (&obj == (wxObject*)okBut)
+ {
+ readNewSetup();
+ if (parent != NULL) parent->closeEditor(TRUE);
+ return 1;
+ }
+ else if (&obj == (wxObject*)cancelBut)
+ {
+ memcpy(imgSetup, &oldSetup, sizeof(rview_image_setup));
+ if (parent != NULL) parent->closeEditor(TRUE);
+ return 1;
+ }
+ }
+ else if ((type == wxEVENT_TYPE_TEXT_ENTER_COMMAND) || (type == wxEVENT_TYPE_CHECKBOX_COMMAND))
+ {
+ int setFlags = -1;
+
+ if ((&obj == (wxObject*)zproWidget) || (&obj == (wxObject*)clipzWidget) ||
+ (&obj == (wxObject*)useLights)) setFlags = 0;
+ // These only require an update of the view-window when voxel mode is on.
+ else if ((&obj == (wxObject*)pixThreshLowWidget) || (&obj == (wxObject*)pixThreshHighWidget) ||
+ (&obj == (wxObject*)wgtThreshWidget) || (&obj == (wxObject*)wgtQuantWidget) ||
+ (&obj == (wxObject*)useRgbBrightness)) setFlags = RVIEW_IFLAG_VOXEL;
+ // These only require an update of the view-window when lights are on.
+ else if ((&obj == (wxObject*)useVoxCol) || (&obj == (wxObject*)lightsAngle) ||
+ (&obj == (wxObject*)lightsScintAngle) || (&obj == (wxObject*)lightsAmbient) ||
+ (&obj == (wxObject*)lightsGain) || (&obj == (wxObject*)lightsDir) ||
+ (&obj == (wxObject*)lightsDist)) setFlags = RVIEW_IFLAG_LIGHT;
+ // These only require an update of the view-window when height mode is on
+ else if ((&obj == (wxObject*)gridSize) || (&obj == (wxObject*)scaleHeight)) setFlags = RVIEW_IFLAG_HEIGHT;
+ // Mixed modes
+ else if (&obj == (wxObject*)voxColour) setFlags = RVIEW_IFLAG_LIGHT | RVIEW_IFLAG_HEIGHT;
+ if (setFlags >= 0)
+ {
+ readNewSetup();
+ if (parent != NULL) parent->updateSettings(setFlags);
+ return 1;
+ }
+ }
+ else if (type == wxEVENT_TYPE_CHOICE_COMMAND)
+ {
+ if ((&obj == (wxObject*)kernelSize) || (&obj == (wxObject*)kernelType))
+ {
+ readNewSetup();
+ if (parent != NULL) parent->updateSettings(TRUE);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+
+
+
+/*
+ * rendererControl class. For advanced control of the renderers + animations
+ */
+
+const int rendererControl::rctrl_border = rviewDisplay::display_border;
+const int rendererControl::rctrl_bwidth = 80;
+const int rendererControl::rctrl_bheight = 30;
+const int rendererControl::rctrl_rwidth = 30;
+const int rendererControl::rctrl_rheight = 30;
+const int rendererControl::rctrl_sheight = 50;
+const int rendererControl::rctrl_width = 300;
+const int rendererControl::rctrl_height = 5*rendererControl::rctrl_border + 3*rendererControl::rctrl_sheight + rendererControl::rctrl_bheight + rview_window_extra_height;
+
+rendererControl::rendererControl(float drx, float dry, float drz, int mode, rviewRenderImage *parentWin) : rviewFrame(NULL, lman->lookup("titleRendererCtrl"), 0, 0, rctrl_width, rctrl_height)
+{
+ int w;
+
+ parent = parentWin; active = mode;
+ panel = new wxPanel((wxWindow*)this, 0, 0, rctrl_width, rctrl_height);
+ w = rctrl_width - 2*rctrl_border;
+ rotx = new rviewSlider(panel, 1000*drx, -1000, 1000, w, lman->lookup("textRotX"));
+ roty = new rviewSlider(panel, 1000*dry, -1000, 1000, w, lman->lookup("textRotY"));
+ rotz = new rviewSlider(panel, 1000*drz, -1000, 1000, w, lman->lookup("textRotZ"));
+
+ resetX = new rviewButton(panel, "0");
+ resetY = new rviewButton(panel, "0");
+ resetZ = new rviewButton(panel, "0");
+
+ actionBut = new rviewButton(panel);
+ closeBut = new rviewButton(panel);
+
+ label();
+
+ OnSize(rctrl_width, rctrl_height);
+
+ Show(TRUE);
+}
+
+
+rendererControl::~rendererControl(void)
+{
+ if (parent != NULL)
+ {
+ user_event ue;
+
+ ue.type = usr_child_closed; ue.data = (void*)this;
+ parent->userEvent(ue);
+ }
+}
+
+
+const char *rendererControl::getFrameName(void) const
+{
+ return "rendererControl";
+}
+
+rviewFrameType rendererControl::getFrameType(void) const
+{
+ return rviewFrameTypeRenCtrl;
+}
+
+
+void rendererControl::unlinkParent(void)
+{
+ parent = NULL;
+}
+
+
+void rendererControl::OnSize(int w, int h)
+{
+ int x, y, dx, dy;
+
+ GetClientSize(&x, &y);
+ panel->SetSize(0, 0, x, y, wxSIZE_ALLOW_MINUS_ONE);
+ dx = (x - 2*rctrl_bwidth) / 2; dy = (rctrl_sheight - rctrl_rheight) / 2;
+ x -= 3*rctrl_border + rctrl_rwidth; y = rctrl_border;
+ rotx->SetSize(rctrl_border, y, x, rctrl_sheight);
+ resetX->SetSize(2*rctrl_border + x, y+dy, rctrl_rwidth, rctrl_rheight);
+ y += rctrl_border + rctrl_sheight;
+ roty->SetSize(rctrl_border, y, x, rctrl_sheight);
+ resetY->SetSize(2*rctrl_border + x, y+dy, rctrl_rwidth, rctrl_rheight);
+ y += rctrl_border + rctrl_sheight;
+ rotz->SetSize(rctrl_border, y, x, rctrl_sheight);
+ resetZ->SetSize(2*rctrl_border + x, y+dy, rctrl_rwidth, rctrl_rheight);
+ y += rctrl_border + rctrl_sheight;
+
+ actionBut->SetSize(dx/2, y, rctrl_bwidth, rctrl_bheight);
+ closeBut->SetSize((3*dx)/2 + rctrl_bwidth, y, rctrl_bwidth, rctrl_bheight);
+}
+
+
+void rendererControl::setActiveMode(int mode)
+{
+ active = mode;
+ actionBut->SetLabel(lman->lookup((active == 0) ? "textStart" : "textStop"));
+ actionBut->SetSize(-1, -1, rctrl_bwidth, rctrl_bheight);
+}
+
+
+void rendererControl::label(void)
+{
+ rotx->SetLabel(lman->lookup("textRotX"));
+ roty->SetLabel(lman->lookup("textRotY"));
+ rotz->SetLabel(lman->lookup("textRotZ"));
+
+ closeBut->SetLabel(lman->lookup("textClose"));
+
+ setActiveMode(active);
+}
+
+
+void rendererControl::updateParameters(void)
+{
+ if (parent != NULL)
+ {
+ if (active == 0)
+ {
+ parent->setAutoRotation(1000.0, 1000.0, 1000.0);
+ }
+ else
+ {
+ parent->setAutoRotation((rotx->GetValue()) / 1000.0, (roty->GetValue()) / 1000.0, (rotz->GetValue()) / 1000.0);
+ }
+ }
+}
+
+
+int rendererControl::process(wxObject &obj, wxEvent &evt)
+{
+ int type = evt.GetEventType();
+
+ if (type == wxEVENT_TYPE_SLIDER_COMMAND)
+ {
+ if ((&obj == (wxObject*)rotx) || (&obj == (wxObject*)roty) || (&obj == (wxObject*)rotz))
+ {
+ updateParameters();
+ return 1;
+ }
+ }
+ else if (type == wxEVENT_TYPE_BUTTON_COMMAND)
+ {
+ if (&obj == (wxObject*)actionBut)
+ {
+ setActiveMode(active ^ 1);
+ updateParameters();
+ return 1;
+ }
+ else if (&obj == (wxObject*)closeBut)
+ {
+ if (parent != NULL) parent->closeRendererControls();
+ return 1;
+ }
+ else if ((&obj == (wxObject*)resetX) || (&obj == (wxObject*)resetY) || (&obj == (wxObject*)resetZ))
+ {
+ if (&obj == (wxObject*)resetX)
+ rotx->SetValue(0);
+ else if (&obj == (wxObject*)resetY)
+ roty->SetValue(0);
+ else if (&obj == (wxObject*)resetZ)
+ rotz->SetValue(0);
+
+ updateParameters();
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+
+
+/*
+ * Renderer view window
+ */
+
+const int rendererCurrentView::rcview_border = rviewDisplay::display_border;
+const int rendererCurrentView::rcview_bwidth = 80;
+const int rendererCurrentView::rcview_bheight = 30;
+const int rendererCurrentView::rcview_theight = 30;
+const int rendererCurrentView::rcview_width = 180;
+const int rendererCurrentView::rcview_height = 220;
+
+rendererCurrentView::rendererCurrentView(const vertex_fp &angles, long off, double scale, rviewRenderImage *parentWin) :
+ rviewFrame(NULL, lman->lookup("titleRendererView"), 0, 0, rcview_width, rcview_height)
+{
+ parent = parentWin;
+
+ panel = new wxPanel((wxWindow*)this, 0, 0, rcview_width, rcview_height);
+
+ rotx = new rviewText(panel);
+ roty = new rviewText(panel);
+ rotz = new rviewText(panel);
+
+ zoff = new rviewText(panel);
+ cubeScale = new rviewText(panel);
+
+ applyButton = new rviewButton(panel);
+ closeButton = new rviewButton(panel);
+
+ label();
+
+ updateView(angles, off, scale);
+
+ OnSize(rcview_width, rcview_height);
+
+ Show(TRUE);
+}
+
+
+rendererCurrentView::~rendererCurrentView(void)
+{
+ if (parent != NULL)
+ {
+ user_event ue;
+
+ ue.type = usr_child_closed; ue.data = (void*)this;
+ parent->userEvent(ue);
+ }
+}
+
+
+const char *rendererCurrentView::getFrameName(void) const
+{
+ return "rendererCurrentView";
+}
+
+
+rviewFrameType rendererCurrentView::getFrameType(void) const
+{
+ return rviewFrameTypeRenView;
+}
+
+
+void rendererCurrentView::unlinkParent(void)
+{
+ parent = NULL;
+}
+
+
+void rendererCurrentView::OnSize(int w, int h)
+{
+ int x, y;
+
+ GetClientSize(&x, &y);
+
+ panel->SetSize(0, 0, w, h, wxSIZE_ALLOW_MINUS_ONE);
+
+ x -= 2*rcview_border;
+ rotx->SetSize(rcview_border, rcview_border, x, rcview_theight);
+ roty->SetSize(rcview_border, rcview_border + rcview_theight, x, rcview_theight);
+ rotz->SetSize(rcview_border, rcview_border + 2*rcview_theight, x, rcview_theight);
+ zoff->SetSize(rcview_border, rcview_border + 3*rcview_theight, x, rcview_theight);
+ cubeScale->SetSize(rcview_border, rcview_border + 4*rcview_theight, x, rcview_theight);
+
+ x -= 2*rcview_bwidth;
+ if (x < 0) x = 0;
+ applyButton->SetSize(rcview_border + x/4, 3*rcview_border + 5*rcview_theight, rcview_bwidth, rcview_bheight);
+ closeButton->SetSize(rcview_border + (3*x)/4 + rcview_bwidth, 3*rcview_border + 5*rcview_theight, rcview_bwidth, rcview_bheight);
+}
+
+
+void rendererCurrentView::label(void)
+{
+ rotx->SetLabel(lman->lookup("textRotX"));
+ roty->SetLabel(lman->lookup("textRotY"));
+ rotz->SetLabel(lman->lookup("textRotZ"));
+ zoff->SetLabel(lman->lookup("textZOffset"));
+ cubeScale->SetLabel(lman->lookup("textScale"));
+ applyButton->SetLabel(lman->lookup("textApply"));
+ closeButton->SetLabel(lman->lookup("textClose"));
+}
+
+
+int rendererCurrentView::process(wxObject &obj, wxEvent &evt)
+{
+ int type = evt.GetEventType();
+
+ if (type == wxEVENT_TYPE_BUTTON_COMMAND)
+ {
+ if (&obj == (wxObject*)applyButton)
+ {
+ updateParameters();
+ return 1;
+ }
+ else if (&obj == (wxObject*)closeButton)
+ {
+ Close(TRUE);
+ return 1;
+ }
+ }
+ else if (type == wxEVENT_TYPE_TEXT_ENTER_COMMAND)
+ {
+ updateParameters();
+ return 1;
+ }
+ return 0;
+}
+
+
+void rendererCurrentView::updateView(const vertex_fp &angles, long off, double scale)
+{
+ rotx->SetValue((double)angles.x);
+ roty->SetValue((double)angles.y);
+ rotz->SetValue((double)angles.z);
+ zoff->SetValue(off);
+ cubeScale->SetValue(scale);
+}
+
+
+void rendererCurrentView::updateParameters(void)
+{
+ if (parent != NULL)
+ {
+ vertex_fp angles;
+ angles.x = atof(rotx->GetValue());
+ angles.y = atof(roty->GetValue());
+ angles.z = atof(rotz->GetValue());
+ parent->setCurrentView(angles, atoi(zoff->GetValue()), atof(cubeScale->GetValue()));
+ }
+}
+
+
+
+
+
+
+
+/*
+ * pixmapCanvas class. For displaying wxPixmaps
+ */
+pixmapCanvas::pixmapCanvas(rviewImage *parent, int x, int y, int w, int h, long style) : wxCanvas((wxWindow*)parent, x, y, w, h, style)
+{
+ pixmap = NULL; font = NULL;
+ parentWin = parent;
+ myDC = (wxDC*)GetDC();
+ brush.SetStyle(wxSOLID); brush.SetColour(0,0,0);
+ border.SetStyle(wxSOLID); border.SetColour(0,0,0);
+ bpen.SetStyle(wxSOLID); bpen.SetColour(0,0,0);
+ // Pen used for frames
+ fpen.SetStyle(wxSOLID); fpen.SetColour((char)0xff, (char)0xff, (char)0xff);
+ fpen.SetCap(wxCAP_BUTT); fpen.SetJoin(wxJOIN_BEVEL);
+ SetBackground(&brush);
+ rect_x0 = -1; rect_y0 = -1; rect_x1 = -1; rect_y1 = -1;
+ aspectRatio = 0;
+}
+
+
+
+// Don't delete the pixmap! This is not our job.
+pixmapCanvas::~pixmapCanvas(void)
+{
+ if (font != NULL)
+ {
+ SetFont(NULL); delete font;
+ }
+ SetBackground(NULL);
+}
+
+
+void pixmapCanvas::setPixmap(wxPixmap *pmap)
+{
+ pixmap = pmap;
+ pixWidth = pmap->getWidth(); pixHeight = pmap->getHeight();
+ if (rect_x0 >= 0)
+ {
+ if (((rect_x0 >= pixWidth) && (rect_x1 >= pixWidth)) ||
+ ((rect_y0 >= pixHeight) && (rect_y1 >= pixHeight)))
+ {
+ rect_x0 = -1; rect_y0 = -1; rect_x1 = -1; rect_y1 = -1;
+ }
+ else
+ {
+ if (rect_x0 >= pixWidth) rect_x0 = pixWidth-1;
+ if (rect_x1 >= pixWidth) rect_x1 = pixWidth-1;
+ if (rect_y0 >= pixHeight) rect_y0 = pixHeight-1;
+ if (rect_y1 >= pixHeight) rect_y1 = pixHeight-1;
+ }
+ }
+}
+
+
+void pixmapCanvas::SetAspectRatio(double ratio)
+{
+ aspectRatio = ratio;
+}
+
+
+void pixmapCanvas::adjustBoxToRatio(void)
+{
+ if ((rect_x0 >= 0) && (aspectRatio > 0))
+ {
+ int width, height;
+
+ width = rect_x1 - rect_x0;
+ if (width < 0) width = -width;
+ height = (int)(width * aspectRatio);
+ if (rect_y1 < rect_y0) height = -height;
+ rect_y1 = rect_y0 + height;
+ if ((rect_y1 < 0) || (rect_y1 >= pixHeight))
+ {
+ if (rect_y1 < 0) rect_y1 = 0; else rect_y1 = pixHeight-1;
+ height = rect_y1 - rect_y0;
+ if (height < 0) height = -height;
+ width = (int)(height / aspectRatio);
+ if (rect_x1 < rect_x0) width = -width;
+ rect_x1 = rect_x0 + width;
+ }
+ }
+}
+
+
+void pixmapCanvas::ToggleDragBox(bool clearMode)
+{
+ int minx, miny, maxx, maxy;
+
+ // Drag box defined?
+ if (rect_x0 < 0) return;
+
+ if (rect_x0 < rect_x1)
+ {
+ minx = rect_x0; maxx = rect_x1;
+ }
+ else
+ {
+ minx = rect_x1; maxx = rect_x0;
+ }
+ if (rect_y0 < rect_y1)
+ {
+ miny = rect_y0; maxy = rect_y1;
+ }
+ else
+ {
+ miny = rect_y1; maxy = rect_y0;
+ }
+
+ // Only redraw the drag box if it's visible...
+ if ((rect_x0 != rect_x1) && (rect_y0 != rect_y1))
+ {
+ int ominx, ominy, omaxx, omaxy;
+
+ SetLogicalFunction(wxINVERT); SetPen(&fpen);
+ //cout << "Draw " << minx << ',' << miny << ',' << maxx << ',' << maxy << endl;
+ ominx = minx + offX; ominy = miny + offY; omaxx = maxx + offX; omaxy = maxy + offY;
+ SetClippingRegion((float)ominx, (float)ominy, omaxx-ominx+1.0, omaxy-ominy+1.0);
+ IntDrawLine(ominx, ominy, omaxx - 1, ominy);
+ IntDrawLine(omaxx, ominy, omaxx, omaxy - 1);
+ IntDrawLine(omaxx, omaxy, ominx + 1, omaxy);
+ IntDrawLine(ominx, omaxy, ominx, ominy + 1);
+ DestroyClippingRegion();
+ }
+
+ if ((rect_x0 == rect_x1) && (rect_y0 == rect_y1) && !clearMode) return;
+
+ // Is the old rectangle to be removed or the new one to be plotted?
+ // This makes a difference with the text!
+ if (clearMode)
+ {
+ Refresh(FALSE, &textBBox);
+ }
+ else
+ {
+ float posx, posy, twidth, theight;
+ char buffer[STRINGSIZE];
+
+ // Create font on demand only
+ if (font == NULL)
+ {
+ // Do not use pure white as background, this isn't handled correctly under X
+ wxColour tfore(0, 0, 0), tback((char)0xf0, (char)0xf0, (char)0xf0);
+
+ font = new wxFont(12, wxROMAN, wxNORMAL, wxNORMAL);
+ SetFont(font); SetTextForeground(&tfore); SetTextBackground(&tback);
+ textBack.SetColour(tback); textBack.SetStyle(wxSOLID);
+ }
+ SetBrush(&textBack); SetPen(&bpen); SetLogicalFunction(wxCOPY);
+ sprintf(buffer, "%d:%d, %d:%d", minx, maxx, miny, maxy);
+ GetTextExtent(buffer, &twidth, &theight);
+ posx = minx + offX + rviewImage::image_dragtoff; posy = miny + offY + rviewImage::image_dragtoff;
+#ifdef wx_msw
+ textBBox.x = (int)posx - rviewDisplay::display_scrstep * GetScrollPos(wxHORIZONTAL);
+ textBBox.y = (int)posy - rviewDisplay::display_scrstep * GetScrollPos(wxVERTICAL);
+#else
+ textBBox.x = (int)posx; textBBox.y = (int)posy;
+#endif
+ twidth += rviewImage::image_dragtspace; theight += rviewImage::image_dragtspace;
+ textBBox.width = (int)twidth; textBBox.height = (int)theight;
+ DrawRectangle(posx, posy, twidth, theight);
+ DrawText(buffer, posx + rviewImage::image_dragtspace/2, posy + rviewImage::image_dragtspace/2);
+ SetBrush(NULL);
+ }
+ SetPen(NULL);
+}
+
+
+void pixmapCanvas::SetDragBox(int x0, int y0, int x1, int y1)
+{
+ int scrollX, scrollY;
+
+ ToggleDragBox(TRUE);
+
+ scrollX = 0;//rviewDisplay::display_scrstep * GetScrollPos(wxHORIZONTAL);
+ scrollY = 0;//rviewDisplay::display_scrstep * GetScrollPos(wxVERTICAL);
+
+ rect_x0 = x0 - offX + scrollX; rect_y0 = y0 - offY + scrollY;
+ rect_x1 = x1 - offX + scrollX; rect_y1 = y1 - offY + scrollY;
+ if (((rect_x0 < 0) && (rect_x1 < 0)) || ((rect_x0 >= pixWidth) && (rect_x1 >= pixWidth)) ||
+ ((rect_y0 < 0) && (rect_y1 < 0)) || ((rect_y0 >= pixHeight) && (rect_y1 >= pixHeight)))
+ {
+ rect_x0 = -1; rect_y0 = -1; rect_x1 = -1; rect_y1 = -1;
+ return;
+ }
+ adjustBoxToRatio();
+ if (rect_x0 < 0) rect_x0 = 0; if (rect_x0 >= pixWidth) rect_x0 = pixWidth-1;
+ if (rect_y0 < 0) rect_y0 = 0; if (rect_y0 >= pixHeight) rect_y0 = pixHeight-1;
+ if (rect_x1 < 0) rect_x1 = 0; if (rect_x1 >= pixWidth) rect_x1 = pixWidth-1;
+ if (rect_y1 < 0) rect_y1 = 0; if (rect_y1 >= pixHeight) rect_y1 = pixHeight-1;
+
+ ToggleDragBox(FALSE);
+}
+
+
+bool pixmapCanvas::HasDragBox(void) const
+{
+ return ((rect_x0 >= 0) && (rect_x0 != rect_x1));
+}
+
+
+bool pixmapCanvas::GetDragBox(int &x0, int &y0, int &x1, int &y1) const
+{
+ if ((rect_x0 < 0) || (rect_x0 == rect_x1)) return FALSE;
+
+ // output sorted: x0 < x1, y0 < y1
+ if (rect_x0 < rect_x1)
+ {
+ x0 = rect_x0; x1 = rect_x1;
+ }
+ else
+ {
+ x0 = rect_x1; x1 = rect_x0;
+ }
+ if (rect_y0 < rect_y1)
+ {
+ y0 = rect_y0; y1 = rect_y1;
+ }
+ else
+ {
+ y0 = rect_y1; y1 = rect_y0;
+ }
+
+ return TRUE;
+}
+
+
+void pixmapCanvas::UpdateDragBox(int x1, int y1)
+{
+ if (rect_x0 < 0) return;
+
+ ToggleDragBox(TRUE);
+
+ rect_x1 = x1 - offX;
+ if (rect_x1 < 0) rect_x1 = 0; if (rect_x1 >= pixWidth) rect_x1 = pixWidth-1;
+ rect_y1 = y1 - offY;
+ if (rect_y1 < 0) rect_y1 = 0; if (rect_y1 >= pixHeight) rect_y1 = pixHeight-1;
+
+ adjustBoxToRatio();
+
+ ToggleDragBox(FALSE);
+
+#if 0
+ int width, height;
+ int scrollX, scrollY;
+ int mapX, mapY;
+
+ scrollX = GetScrollPos(wxHORIZONTAL); scrollY = GetScrollPos(wxVERTICAL);
+ mapX = x1 - scrollX * rviewDisplay::display_scrstep;
+ mapY = y1 - scrollY * rviewDisplay::display_scrstep;
+ // Autoscroll?
+ GetClientSize(&width, &height);
+ if (width >= 2*rviewImage::image_draghotzone)
+ {
+ if (mapX < rviewImage::image_draghotzone)
+ {
+ scrollX -= (rviewImage::image_draghotzone - mapX + rviewDisplay::display_scrstep-1) / rviewDisplay::display_scrstep;
+ if (scrollX >= 0)
+ {
+ SetScrollPos(wxHORIZONTAL, scrollX);
+ x1 = rviewImage::image_draghotzone + (x1-mapX); WarpPointer(x1, y1);
+ }
+ }
+ else if (mapX > (width - rviewImage::image_draghotzone))
+ {
+ scrollX += (mapX - width + rviewImage::image_draghotzone + rviewDisplay::display_scrstep-1) / rviewDisplay::display_scrstep;
+ if (scrollX <= GetScrollRange(wxHORIZONTAL))
+ {
+ SetScrollPos(wxHORIZONTAL, scrollX);
+ x1 = (width - rviewImage::image_draghotzone) + (x1-mapX); WarpPointer(x1, y1);
+ }
+ }
+ }
+ if (height >= 2*rviewImage::image_draghotzone)
+ {
+ if (mapY < rviewImage::image_draghotzone)
+ {
+ scrollY -= (rviewImage::image_draghotzone - mapY + rviewDisplay::display_scrstep-1) / rviewDisplay::display_scrstep;
+ if (scrollY >= 0)
+ {
+ SetScrollPos(wxVERTICAL, scrollY);
+ WarpPointer(x1, rviewImage::image_draghotzone + scrollY * rviewDisplay::display_scrstep);
+ }
+ }
+ else if (mapY > (height - rviewImage::image_draghotzone))
+ {
+ scrollY += (mapY - height + rviewImage::image_draghotzone + rviewDisplay::display_scrstep-1) / rviewDisplay::display_scrstep;
+ if (scrollY <= GetScrollRange(wxVERTICAL))
+ {
+ SetScrollPos(wxVERTICAL, scrollY);
+ WarpPointer(x1, height-rviewImage::image_draghotzone + scrollY * rviewDisplay::display_scrstep);
+ }
+ }
+ }
+#endif
+}
+
+
+void pixmapCanvas::AdjustDragBox(int x1, int y1)
+{
+ if (rect_x0 < 0) SetDragBox(x1, y1, x1, y1);
+ else
+ {
+ ToggleDragBox(TRUE);
+
+ x1 = x1 - offX;// + rviewDisplay::display_scrstep * GetScrollPos(wxHORIZONTAL);
+ if (x1 < 0) x1 = 0; if (x1 >= pixWidth) x1 = pixWidth-1;
+ y1 = y1 - offY;// + rviewDisplay::display_scrstep * GetScrollPos(wxVERTICAL);
+ if (y1 < 0) y1 = 0; if (y1 >= pixHeight) y1 = pixHeight-1;
+
+ if (abs(x1 - rect_x0) < abs(x1 - rect_x1))
+ rect_x0 = rect_x1;
+ if (abs(y1 - rect_y0) < abs(y1 - rect_y1))
+ rect_y0 = rect_y1;
+ rect_x1 = x1; rect_y1 = y1;
+
+ adjustBoxToRatio();
+
+ ToggleDragBox(FALSE);
+ }
+}
+
+
+// Core functionality for plotting picture + border
+void pixmapCanvas::paintCore(int x, int y)
+{
+ int sx, sy;
+
+ GetSize(&sx, &sy);
+
+ if ((offX > 0) || (offY > 0))
+ {
+ float bordx, bordy, height;
+
+ bordx = (float)offX; bordy = (float)offY; height = (float)sy;
+
+ SetLogicalFunction(wxCOPY);
+ SetPen(&bpen); SetBrush(&border);
+
+ if (offX > 0)
+ {
+ DrawRectangle(0.0, 0.0, bordx, height);
+ DrawRectangle(bordx + pixWidth, 0.0, bordx+1, height);
+ }
+ if (offY > 0)
+ {
+ DrawRectangle(bordx, 0.0, (float)pixWidth, bordy);
+ DrawRectangle(bordx, bordy + pixHeight, (float)pixWidth, bordy+1);
+ }
+ SetPen(NULL); SetBrush(NULL);
+ }
+
+ pixmap->plotPixmap(offX - x, offY - y);
+
+ ToggleDragBox(FALSE);
+}
+
+
+void pixmapCanvas::OnPaint(void)
+{
+ wxUpdateIterator upd(this);
+ wxRect rect;
+ int w, h, x, y;
+
+ GetClientSize(&w, &h);
+ x = rviewDisplay::display_scrstep * GetScrollPos(wxHORIZONTAL);
+ y = rviewDisplay::display_scrstep * GetScrollPos(wxVERTICAL);
+
+ offX = (w - pixWidth) / 2; if (offX < 0) offX = 0;
+ offY = (h - pixHeight) / 2; if (offY < 0) offY = 0;
+
+ BeginDrawing();
+
+ while (upd)
+ {
+ //upd.GetRect(&rect);
+ paintCore(x, y);
+ upd++;
+ }
+
+ EndDrawing();
+}
+
+
+void pixmapCanvas::updateDisplay(bool borders)
+{
+ if (parentWin->IsShown())
+ {
+ int cw, ch;
+ int x, y;
+
+ x = rviewDisplay::display_scrstep * GetScrollPos(wxHORIZONTAL);
+ y = rviewDisplay::display_scrstep * GetScrollPos(wxVERTICAL);
+
+ GetClientSize(&cw, &ch);
+ offX = (cw - pixWidth)/2; if (offX < 0) offX = 0;
+ offY = (ch - pixHeight)/2; if (offY < 0) offY = 0;
+ pixmap->invalidatePixmap();
+ if (borders)
+ {
+ int sx, sy;
+
+ GetVirtualSize(&sx, &sy);
+ sx *= rviewDisplay::display_scrstep; sy *= rviewDisplay::display_scrstep;
+ SetClippingRegion(0, 0, sx, sy);
+ paintCore(x, y);
+ }
+ else
+ {
+ SetClippingRegion(offX, offY, pixWidth, pixHeight);
+ paintCore(x, y);
+ }
+ DestroyClippingRegion();
+ }
+}
+
+
+
+void pixmapCanvas::OnEvent(wxMouseEvent &mevt)
+{
+ parentWin->processMouseEvent(mevt);
+}
+
+
+
+
+
+
+/*
+ * rviewImage members
+ */
+
+const int rviewImage::image_swidth = 100;
+const int rviewImage::image_sheight = 40;
+const int rviewImage::image_pbwidth = rviewDisplay::display_pbwidth;
+const int rviewImage::image_pbheight = 30;
+const int rviewImage::image_minwidth = 50;
+const int rviewImage::image_minheight = 50;
+const int rviewImage::image_chkwidth = 80;
+const int rviewImage::image_chkheight = 30;
+const int rviewImage::image_bbwidth = 60;
+const int rviewImage::image_bbheight = 20;
+const int rviewImage::image_twidth = 100;
+const int rviewImage::image_theight = 50;
+const int rviewImage::image_bwidth = 64;
+const int rviewImage::image_bheight = 30;
+const int rviewImage::image_dragtoff = 8;
+const int rviewImage::image_dragtspace = 8;
+const int rviewImage::image_draghotzone = 32;
+const int rviewImage::image_ctrly = 60;
+const int rviewImage::image_totaly = rviewDisplay::display_cheight + rviewImage::image_ctrly;
+
+const char *rviewImage::view_ScrollPos = "scrollPos";
+const char *rviewImage::view_UseCspace = "useCspace";
+const char *rviewImage::view_CspaceFull = "cspaceFull";
+const char *rviewImage::view_CspaceProj = "cspaceProj";
+const char *rviewImage::view_CspaceMeans = "cspaceMeans";
+const char *rviewImage::view_CspaceSigmas = "cspaceSigmas";
+const char *rviewImage::view_CspaceType = "cspaceType";
+const char *rviewImage::view_CspaceRange = "cspaceRange";
+const char *rviewImage::view_ScaleValue = "scaleValue";
+
+rviewImage::rviewImage(mdd_frame *mf, int es, unsigned int flags) : rviewDisplay(mf, es+image_ctrly, flags)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewImage", "rviewImage()");
+
+ // make destructor safe first.
+ csmap = NULL; // signifies no data for value->colourspace mapping initialised yet
+ csInterv = NULL;
+ pixmap = NULL; pcanv = NULL; scaleSlider = NULL;
+ cspar = NULL;
+
+ // This variable is set to true once openViewerEpilogue() is called. Its main use is
+ // 1) on Windows: trap calls to OnSize() happening before the object is fully initialized
+ // 2) for the renderers: avoid actually drawing anything until the window size is fixed.
+ initPhaseFinished = FALSE;
+
+ // Check the base type immediately:
+ if (baseType == rbt_none)
+ {
+ objectInitializedOK = FALSE;
+ return;
+ }
+
+#if 0
+ // Test resampling routines...
+ r_Ref<r_GMarray> mddPtr;
+ r_Minterval newInterv(dimMDD);
+ //for (i=0; i<dimMDD; i++) newInterv << r_Sinterval(4*mddObj->spatial_domain()[i].low(), 4*mddObj->spatial_domain()[i].high());
+ //mdd_objectScaleInter(mddObj, mddPtr, newInterv, baseType);
+ for (i=0; i<dimMDD; i++) newInterv << r_Sinterval((r_Range)(0.5*mddObj->spatial_domain()[i].low()), (r_Range)(0.5*mddObj->spatial_domain()[i].high()));
+ mdd_objectScaleAverage(mddObj, mddPtr, newInterv, baseType);
+ mddObj.destroy();
+ mddObj = mddPtr;
+ interv = mddObj->spatial_domain();
+#endif
+}
+
+
+
+rviewImage::~rviewImage(void)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewImage", "~rviewImage()");
+
+ if (cspar != NULL) delete cspar;
+ if (csmap != NULL) delete csmap;
+ if (csInterv != NULL) delete csInterv;
+ delete pixmap;
+}
+
+
+// concentrate most intelligence in this function rather than the constructor
+// because we can't use virtual functions (correctly) in the constructor.
+int rviewImage::openViewer(void)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewImage", "openViewer()");
+
+ if (!objectInitializedOK)
+ return -1;
+
+ // init lower level stuff like the menu bar
+ rviewDisplay::openViewer();
+
+ wxMenu *config;
+ wxMenu *submenu;
+ char buffer[STRINGSIZE];
+
+ config = new wxMenu;
+ configMenuInitHook(config);
+ submenu = new wxMenu;
+ submenu->Append(MENU_IMAGE_CSPACE_ON, "", NULL, TRUE);
+ submenu->Append(MENU_IMAGE_CSPACE_FULL, "", NULL, TRUE);
+ submenu->Append(MENU_IMAGE_CSPACE_PROJ, "", NULL, TRUE);
+ submenu->Append(MENU_IMAGE_CSPACE_EDIT, "");
+ config->Append(MENU_IMAGE_SETUP_CSPACE, lman->lookup("menCspaceTitle"), submenu, NULL);
+ if (moviePossible())
+ {
+ submenu = new wxMenu;
+ submenu->Append(MENU_IMAGE_MOVIE_ONCE, "", NULL, TRUE);
+ submenu->Append(MENU_IMAGE_MOVIE_START, "", NULL, TRUE);
+ submenu->Append(MENU_IMAGE_MOVIE_SWITCH, "", NULL, TRUE);
+ config->AppendSeparator();
+ config->Append(MENU_IMAGE_SETUP_MOVIE, lman->lookup("menImgSetupMovie"), submenu, NULL);
+ }
+ sprintf(buffer, "&%s", lman->lookup("menImgSetup"));
+ mBar->Append(config, buffer);
+
+ mBar->Enable(MENU_IMAGE_CSPACE_EDIT, FALSE);
+
+ pcanv = NULL; imgData = NULL;
+ scaleValue = 100.0;
+
+ // Colourspace mapper
+ doValToCspace = (prefs->rgbSpace != 0);
+ doFullRangeCspace = (prefs->rgbSpace == 2);
+ // We're not allowed to call setCspaceProjMode before a projection is set
+ // in the init... functions
+ doProjRangeCspace = (prefs->rgbSpace == 3);
+ if (modeNeedsCspace(baseType)) doValToCspace = TRUE;
+
+ mousex = -1.0; mousey = -1.0; mousebut = 0;
+
+ if (showScaleSlider())
+ scaleSlider = new rviewSlider(ctrlPanel, (int)scaleValue, 0, 500, image_swidth, lman->lookup("textScale"));
+
+ if (rviewCheckInitCspace(baseType, NULL, mddObj) != 0)
+ {
+ mBar->Check(MENU_IMAGE_CSPACE_ON, doValToCspace);
+ mBar->Check(MENU_IMAGE_CSPACE_FULL, doFullRangeCspace);
+ mBar->Check(MENU_IMAGE_CSPACE_PROJ, doProjRangeCspace);
+ mBar->Enable(MENU_IMAGE_CSPACE_FULL, doValToCspace);
+ mBar->Enable(MENU_IMAGE_CSPACE_PROJ, doValToCspace);
+ mBar->Enable(MENU_IMAGE_CSPACE_EDIT, doValToCspace);
+ cspaceForType = TRUE;
+ }
+ else
+ {
+ cspaceForType = FALSE;
+ }
+ configureCspace(cspaceForType);
+
+ if (moviePossible())
+ {
+ switch (prefs->movieMode)
+ {
+ case 1: lastMovieMode = MENU_IMAGE_MOVIE_START; break;
+ case 2: lastMovieMode = MENU_IMAGE_MOVIE_SWITCH; break;
+ default: lastMovieMode = MENU_IMAGE_MOVIE_ONCE; break;
+ }
+ playDirection = 0;
+
+ playBack = new rviewButton(ctrlPanel, "<");
+ playStop = new rviewButton(ctrlPanel, "[]");
+ playFwd = new rviewButton(ctrlPanel, ">");
+ mBar->Check(lastMovieMode, TRUE);
+ }
+ else
+ {
+ playBack = NULL; playStop = NULL; playFwd = NULL;
+ }
+
+ configureMode();
+
+ wxColour palette[2];
+ int w, h;
+
+ GetClientSize(&w, &h);
+
+
+ w -= 2*display_cnvborder; h -= 2*display_cnvborder + totalCtrlHeight;
+ pcanv = new pixmapCanvas(this, display_cnvborder, display_cnvborder + totalCtrlHeight, w, h);
+
+ scrollx = -1; scrolly = -1;
+ pixWidth = -1; pixHeight = -1; pixPitch = -1; pixPad = 0; pixDepth = 0; virtualPitch = -1;
+
+ if (initMode() == NULL)
+ {
+ objectInitializedOK = FALSE;
+ return -1;
+ }
+
+ pcanv->Clear();
+
+ if (rviewImageTypes[baseType] == RVIEW_IMGTYPE_MONO)
+ {
+ palette[0] = wxColour(0,0,0); palette[1] = wxColour(255,255,255);
+ }
+ pixmap = new wxPixmap((wxWindow*)pcanv, pixWidth, pixHeight, pixDepth, pixPad, imgData, getPixmapFlags(), ((rviewImageTypes[baseType] == RVIEW_IMGTYPE_MONO) ? palette : NULL));
+ pcanv->setPixmap(pixmap);
+
+ return 0;
+}
+
+
+void rviewImage::openViewerEpilogue(rviewFrameType ft)
+{
+ // Only do something if this was called from the top level image class, i.e. the
+ // one that overloads getFrameType(). Otherwise NOP.
+ if (ft == getFrameType())
+ {
+ int w, h;
+
+ initPhaseFinished = TRUE;
+
+ RMDBGONCE(3, RMDebug::module_applications, "rviewImage", "openViewerEpilogue() from top level " << getFrameName() );
+
+ label();
+
+ setMinimumViewerSize(image_minwidth, image_minheight);
+
+ GetSize(&w, &h);
+
+ OnSize(w, h);
+ OnSize(w, h);
+
+ Show(TRUE);
+ }
+}
+
+
+int rviewImage::freeDimsFromProjection(int &dim1, int &dim2, r_Point *map)
+{
+ // Apply the projection string
+ if (rviewParseProjection(getVirtualDomain(), pt1, pt2, projString, &freeDims, map) != dimMDD)
+ {
+ rviewErrorbox::reportError(lman->lookup("errorProjection"), rviewImage::getFrameName(), "freeDimsFromProjection");
+ return -1;
+ }
+ // Check whether there are more or less than 2 free dimensions.
+ for (dim1=0; dim1<dimMDD; dim1++) if ((freeDims & (1<<dim1)) != 0) break;
+ for (dim2=dim1+1; dim2<dimMDD; dim2++) if ((freeDims & (1<<dim2)) != 0) break;
+ if ((dim1 >= dimMDD) || (dim2 >= dimMDD))
+ {
+ rviewErrorbox::reportError(lman->lookup("errorProjectFree"), rviewImage::getFrameName(), "freeDimsFromProjection");
+ return -1;
+ }
+ if (map != NULL)
+ {
+ dim1 = (*map)[dim1]; dim2 = (*map)[dim2];
+ }
+ return 0;
+}
+
+
+void rviewImage::projectObjectHook(void)
+{
+}
+
+
+const char *rviewImage::getFrameName(void) const
+{
+ return "rviewImage";
+}
+
+rviewFrameType rviewImage::getFrameType(void) const
+{
+ return rviewFrameTypeImage;
+}
+
+
+int rviewImage::fileMenuInitHook(wxMenu *menu)
+{
+ menu->Append(MENU_DISP_DATA_SAVETIFF, "");
+ return 1;
+}
+
+
+bool rviewImage::modeNeedsCspace(rviewBaseType bt) const
+{
+ return ((bt == rbt_float) || (bt == rbt_double));
+}
+
+
+void rviewImage::configureCspace(bool state)
+{
+ mBar->Enable(MENU_IMAGE_SETUP_CSPACE, state);
+ // Bug (feature?) in WinNT version: menu having submenu can't be disabled.
+ mBar->Enable(MENU_IMAGE_CSPACE_ON, state);
+ mBar->Enable(MENU_IMAGE_CSPACE_FULL, state);
+ mBar->Enable(MENU_IMAGE_CSPACE_PROJ, state);
+ mBar->Enable(MENU_IMAGE_CSPACE_EDIT, state);
+}
+
+
+int rviewImage::configMenuInitHook(wxMenu *menu)
+{
+ return 0;
+}
+
+bool rviewImage::cspaceRangeHook(bool suggest)
+{
+ return suggest;
+}
+
+void rviewImage::configureMode(void)
+{
+ bool csranges;
+
+ if (modeNeedsCspace(baseType)) doValToCspace = TRUE;
+
+ csranges = cspaceRangeHook((cspaceForType && doValToCspace));
+
+ if (doValToCspace)
+ {
+ mBar->Enable(MENU_IMAGE_CSPACE_ON, doValToCspace);
+ mBar->Enable(MENU_IMAGE_CSPACE_EDIT, doValToCspace);
+ }
+ mBar->Enable(MENU_IMAGE_CSPACE_FULL, csranges);
+ mBar->Enable(MENU_IMAGE_CSPACE_PROJ, csranges);
+ mBar->Check(MENU_IMAGE_CSPACE_ON, doValToCspace);
+}
+
+
+void rviewImage::setCspaceProjMode(bool pm)
+{
+ if (pm)
+ {
+ int i=0;
+ r_Minterval tempInterv(dimMDD);
+
+ if(!csInterv)
+ csInterv = new r_Minterval(dimMDD);
+
+ for (i=0; i<dimMDD; i++)
+ {
+ tempInterv << r_Sinterval((r_Range)pt1[i], (r_Range)pt2[i]);
+ }
+
+ *csInterv=tempInterv;
+ }
+
+ doProjRangeCspace = pm;
+}
+
+
+void rviewImage::label(void)
+{
+ if (scaleSlider != NULL)
+ scaleSlider->SetLabel(lman->lookup("textScale"));
+
+ mBar->SetLabelTop(fixedNumberOfMenus, lman->lookup("menImgSetup"));
+ mBar->SetLabel(MENU_IMAGE_SETUP_CSPACE, lman->lookup("menCspaceTitle"));
+ mBar->SetLabel(MENU_IMAGE_CSPACE_ON, lman->lookup("menCspaceOn"));
+ mBar->SetLabel(MENU_IMAGE_CSPACE_FULL, lman->lookup("menCspaceFull"));
+ mBar->SetLabel(MENU_IMAGE_CSPACE_PROJ, lman->lookup("menCspaceProj"));
+ mBar->SetLabel(MENU_IMAGE_CSPACE_EDIT, lman->lookup("menCspaceEdit"));
+ if (moviePossible())
+ {
+ mBar->SetLabel(MENU_IMAGE_SETUP_MOVIE, lman->lookup("menImgSetupMovie"));
+ mBar->SetLabel(MENU_IMAGE_MOVIE_ONCE, lman->lookup("menImgMovieOnce"));
+ mBar->SetLabel(MENU_IMAGE_MOVIE_START, lman->lookup("menImgMovieStart"));
+ mBar->SetLabel(MENU_IMAGE_MOVIE_SWITCH, lman->lookup("menImgMovieSwitch"));
+ }
+ mBar->SetLabel(MENU_DISP_DATA_SAVETIFF, lman->lookup("menDispDataSaveTIFF"));
+
+ rviewDisplay::label();
+}
+
+
+
+char *rviewImage::movieNewFrame(void)
+{
+ return NULL;
+}
+
+int rviewImage::process(wxObject &obj, wxEvent &evt)
+{
+ RMDBGENTER(3, RMDebug::module_applications, "rviewImage", "process()");
+
+ int type = evt.GetEventType();
+
+ if (rviewDisplay::process(obj, evt) != 0)
+ {
+ return 1;
+ }
+
+ if (type == wxEVENT_TYPE_BUTTON_COMMAND)
+ {
+ if (moviePossible())
+ {
+ int oldDirection = playDirection;
+
+ if (&obj == (wxObject*)playStop)
+ {
+ RMDBGMIDDLE(3, RMDebug::module_applications, "rviewImage", "process() Playback stop" );
+ playDirection = 0;
+ return 1;
+ }
+ if (&obj == (wxObject*)playBack)
+ playDirection = -1;
+ else if (&obj == (wxObject*)playFwd)
+ playDirection = 1;
+
+ // Only enter the loop if we didn't have playback before to avoid reentrancy.
+ if ((oldDirection == 0) && (playDirection != 0))
+ {
+ char *data, *lastData;
+
+ RMDBGONCE(3, RMDebug::module_applications, "rviewImage", "process() Playback start " << playDirection );
+ do
+ {
+ while (advanceProjection(playDirection) != 0)
+ {
+ lastData = imgData;
+
+ data = movieNewFrame();
+
+ if (data == NULL)
+ {
+ playDirection = 0; return 0;
+ }
+ updatePixmap(lastData, data);
+ ::wxYield();
+ // Order is _vitally _ important here. Check _after_ the call to ::wxYield()!
+ if (playDirection == 0) break;
+ }
+ // Allow for one NULL cycle after playback (ensures no infinite loops if playback
+ // dimension is only 1 element wide.
+ ::wxYield();
+ if (playDirection != 0)
+ {
+ if (mBar->Checked(MENU_IMAGE_MOVIE_ONCE))
+ playDirection = 0;
+ else if (mBar->Checked(MENU_IMAGE_MOVIE_START))
+ {
+ advanceProjection(-playDirection, display_advmode_reset);
+ }
+ else
+ playDirection = -playDirection;
+ }
+ }
+ while (playDirection != 0);
+ }
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+bool rviewImage::moviePossible(void) const
+{
+ return FALSE;
+}
+
+bool rviewImage::canRotateObject(void) const
+{
+ return FALSE;
+}
+
+bool rviewImage::showScaleSlider(void) const
+{
+ return TRUE;
+}
+
+void rviewImage::rotateObject(wxMouseEvent &mevt)
+{
+}
+
+void rviewImage::processMouseEvent(wxMouseEvent &mevt)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewImage", "processMouseEvent()" );
+
+ int newbut=0;
+
+ if (mevt.ControlDown()) newbut = MOUSE_CONTROL;
+ else if (!canRotateObject()) {mousebut = 0; return;}
+
+ if (mevt.leftDown) newbut |= MOUSE_LEFT;
+ if (mevt.middleDown) newbut |= MOUSE_MIDDLE;
+ if (mevt.rightDown) newbut |= MOUSE_RIGHT;
+
+ if (((newbut & MOUSE_CONTROL) == 0) && canRotateObject())
+ {
+ rotateObject(mevt);
+ }
+ else
+ {
+ // Drag a box
+ if ((newbut & MOUSE_LEFT) != 0)
+ {
+ if ((mousebut & MOUSE_LEFT) == 0)
+ {
+ pcanv->SetDragBox(mevt.x, mevt.y, mevt.x, mevt.y);
+ }
+ else
+ {
+ pcanv->UpdateDragBox(mevt.x, mevt.y);
+ }
+ }
+ else if ((newbut & MOUSE_RIGHT) != 0)
+ {
+ if ((mousebut & MOUSE_RIGHT) == 0)
+ {
+ pcanv->AdjustDragBox(mevt.x, mevt.y);
+ }
+ else
+ {
+ pcanv->UpdateDragBox(mevt.x, mevt.y);
+ }
+ }
+ }
+
+ mousebut = newbut;
+ mousex = mevt.x; mousey = mevt.y;
+}
+
+
+void rviewImage::updatePixmap(char *oldData, char *newData)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewImage", "updatePixmap()" );
+
+ if (pixmap == NULL) return;
+
+ if (oldData != newData)
+ {
+ pixmap->newPixmap((wxWindow*)pcanv, pixWidth, pixHeight, pixDepth, pixPad, imgData, getPixmapFlags() | WX_PIXFLAG_SAMEPALETTE);
+ pcanv->setPixmap(pixmap);
+ }
+ pcanv->updateDisplay((oldData != newData));
+}
+
+
+int rviewImage::getPixmapFlags(void)
+{
+ int pixflags = WX_PIXFLAG_TRANSLATE;
+
+ if (prefs->imgDither)
+ {
+ if (prefs->ditherBest)
+ pixflags |= WX_PIXFLAG_DITHER;
+ else
+ pixflags |= WX_PIXFLAG_FASTDITHER;
+ }
+ return pixflags;
+}
+
+
+
+void rviewImage::OnSize(int w, int h)
+{
+ int x, y, pos;
+ bool resize=false;
+
+ RMDBGONCE(3, RMDebug::module_applications, "rviewImage", "OnSize " << w << ", " << h );
+
+ // fully initialized yet?
+ if (initPhaseFinished)
+ {
+ GetClientSize(&x, &y);
+
+ if ((frameWidth == w) && (frameHeight == h))
+ return;
+
+ frameWidth = w;
+ frameHeight = h;
+
+ x -= 2*display_cnvborder; y -= 2*display_cnvborder + totalCtrlHeight;
+ pcanv->SetSize(display_cnvborder, display_cnvborder + totalCtrlHeight, x, y);
+
+ // Ctrl panel items
+ if (scaleSlider != NULL)
+ scaleSlider->SetSize(display_border, image_totaly - image_sheight, x, image_sheight);
+
+ pos = x - 3*image_pbwidth - display_border + 2*display_cnvborder;
+ // Buttons might not be present
+ if (playBack != NULL)
+ playBack->SetSize(pos, display_cheight, image_pbwidth, image_pbheight);
+ if (playStop != NULL)
+ playStop->SetSize(pos + image_pbwidth, display_cheight, image_pbwidth, image_pbheight);
+ if (playFwd != NULL)
+ playFwd->SetSize(pos + 2*image_pbwidth, display_cheight, image_pbwidth, image_pbheight);
+ }
+
+ rviewDisplay::OnSize(w, h);
+}
+
+
+void rviewImage::OnMenuCommand(int id)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewImage", "OnMenuCommand()" );
+
+ switch (id)
+ {
+ case MENU_DISP_DATA_SAVETIFF:
+ {
+ char *file;
+ char *prefDir = (char*)(prefs->filePath.ptr());
+ file = ::wxFileSelector(lman->lookup("saveTIFF"), (::wxDirExists(prefDir)) ? prefDir : NULL, NULL, NULL, "*", 0, this);
+ if (file != NULL)
+ {
+ ::wxBeginBusyCursor();
+ rviewIO::PixmapToTIFF(pixmap, file, prefs->vffParams.ptr());
+ prefs->filePath = ::wxPathOnly(file);
+ ::wxEndBusyCursor();
+ }
+ }
+ break;
+ case MENU_IMAGE_CSPACE_EDIT:
+ if (csmap != NULL)
+ {
+ csmap->openEditor();
+ }
+ break;
+ case MENU_IMAGE_MOVIE_ONCE:
+ case MENU_IMAGE_MOVIE_START:
+ case MENU_IMAGE_MOVIE_SWITCH:
+ if (moviePossible())
+ {
+ mBar->Check(lastMovieMode, FALSE); mBar->Check(id, TRUE); lastMovieMode = id;
+ }
+ break;
+ case MENU_IMAGE_CSPACE_ON:
+ case MENU_IMAGE_CSPACE_FULL:
+ case MENU_IMAGE_CSPACE_PROJ:
+ {
+ if (id == MENU_IMAGE_CSPACE_ON)
+ {
+ // You're not allowed to leave cspace mode for these type/mode combinations
+ if (modeNeedsCspace(baseType))
+ {
+ mBar->Check(MENU_IMAGE_CSPACE_ON, TRUE);
+ }
+ else
+ {
+ doValToCspace = mBar->Checked(MENU_IMAGE_CSPACE_ON);
+ mBar->Enable(MENU_IMAGE_CSPACE_FULL, doValToCspace);
+ mBar->Enable(MENU_IMAGE_CSPACE_PROJ, doValToCspace);
+ mBar->Enable(MENU_IMAGE_CSPACE_EDIT, doValToCspace);
+ }
+ }
+ else if (id == MENU_IMAGE_CSPACE_FULL)
+ {
+ doFullRangeCspace = mBar->Checked(MENU_IMAGE_CSPACE_FULL);
+ if (csmap != NULL)
+ {
+ csmap->processRange((doFullRangeCspace) ? CSPACE_RANGE_FULL : CSPACE_RANGE_ACTUAL);
+ }
+ }
+ else if (id == MENU_IMAGE_CSPACE_PROJ)
+ {
+ setCspaceProjMode(mBar->Checked(MENU_IMAGE_CSPACE_PROJ));
+ if (csmap != NULL)
+ {
+ csmap->updateProjection(csInterv);
+ }
+ }
+ newProjection();
+ }
+ break;
+ default:
+ rviewDisplay::OnMenuCommand(id);
+ break;
+ }
+}
+
+
+// Refuse to be killed if animation is in progress
+bool rviewImage::OnClose(void)
+{
+ if (playDirection != 0) return FALSE;
+ return TRUE;
+}
+
+
+int rviewImage::userEvent(const user_event &ue)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewImage", "userEvent()" );
+
+ if ((ue.type == usr_cspace_changed) && (ue.data == (void*)csmap) && (doValToCspace))
+ {
+ // The csmapper has already updated the tables and internal information
+ newProjection();
+ return 1;
+ }
+ // Don't intercept unknown messages!
+ return rviewDisplay::userEvent(ue);
+}
+
+
+
+void rviewImage::prepareToDie(void)
+{
+ // Stop movie-playback immediately.
+ playDirection = 0;
+ ::wxYield();
+}
+
+
+int rviewImage::requestQuit(int level)
+{
+ playDirection = 0;
+ return rviewFrame::requestQuit(level);
+}
+
+
+void rviewImage::resizeImage(void)
+{
+ int x, y, sx, sy;
+
+ if (scrollx >= 0)
+ scrollx = pcanv->GetScrollPos(wxHORIZONTAL);
+ else
+ scrollx = 0;
+
+ if (scrolly >= 0)
+ scrolly = pcanv->GetScrollPos(wxVERTICAL);
+ else
+ scrolly = 0;
+
+ pcanv->GetVirtualSize(&x, &y);
+ sx = (pixWidth + display_scrstep - 1) / display_scrstep;
+ sy = (pixHeight + display_scrstep - 1) / display_scrstep;
+
+ // Only update the canvas size if this is absolutely necessary to avoid flicker.
+ if ((x != display_scrstep*sx) || (y != display_scrstep*sy))
+ {
+ pcanv->SetScrollbars(display_scrstep, display_scrstep, sx, sy, display_pgstep, display_pgstep, scrollx, scrolly);
+ }
+}
+
+
+void rviewImage::ensureViewCspace(void)
+{
+ if (cspar == NULL)
+ {
+ cspar = new colourspace_params;
+ memset(cspar, 0, sizeof(colourspace_params));
+ }
+}
+
+
+void rviewImage::deleteViewCspace(void)
+{
+ if (cspar != NULL)
+ {
+ delete cspar;
+ cspar = NULL;
+ }
+}
+
+
+int rviewImage::saveView(FILE *fp)
+{
+ int status = rviewDisplay::saveView(fp);
+
+ long spos[2];
+ spos[0] = (long)scrollx; spos[1] = (long)scrolly;
+
+ writeViewParam(fp, view_ScrollPos, 2, spos);
+ writeViewParam(fp, view_UseCspace, (long)doValToCspace);
+ writeViewParam(fp, view_CspaceFull, (long)doFullRangeCspace);
+ writeViewParam(fp, view_CspaceProj, (long)doProjRangeCspace);
+ writeViewParam(fp, view_ScaleValue, scaleValue / 100.0);
+ if (csmap != NULL)
+ {
+ colourspace_params par;
+ double cvals[3];
+ csmap->getParameters(&par);
+ cvals[0] = par.peak_red; cvals[1] = par.peak_green; cvals[2] = par.peak_blue;
+ writeViewParam(fp, view_CspaceMeans, 3, cvals);
+ cvals[0] = par.sigm_red; cvals[1] = par.sigm_green; cvals[2] = par.sigm_blue;
+ writeViewParam(fp, view_CspaceSigmas, 3, cvals);
+ cvals[0] = par.minVal; cvals[1] = par.maxVal;
+ writeViewParam(fp, view_CspaceRange, 2, cvals);
+ writeViewParam(fp, view_CspaceType, (long)par.type);
+ }
+ return status;
+}
+
+
+int rviewImage::readView(const char *key, const char *value)
+{
+ int status = rviewDisplay::readView(key, value);
+
+ if (status == 0)
+ {
+ if (strcmp(key, view_ScrollPos) == 0)
+ {
+ long spos[2];
+ if (readVector(value, 2, spos) == 0)
+ {
+ scrollx = (int)spos[0]; scrolly = (int)spos[1];
+ }
+ return 1;
+ }
+ else if (strcmp(key, view_UseCspace) == 0)
+ {
+ doValToCspace = (bool)atoi(value);
+ return 1;
+ }
+ else if (strcmp(key, view_CspaceFull) == 0)
+ {
+ doFullRangeCspace = (bool)atoi(value);
+ return 1;
+ }
+ else if (strcmp(key, view_CspaceProj) == 0)
+ {
+ doProjRangeCspace = (bool)atoi(value);
+ return 1;
+ }
+ else if (strcmp(key, view_CspaceMeans) == 0)
+ {
+ double mean[3];
+ ensureViewCspace();
+ if (readVector(value, 3, mean) == 0)
+ {
+ cspar->peak_red = mean[0]; cspar->peak_green = mean[1]; cspar->peak_blue = mean[2];
+ }
+ return 1;
+ }
+ else if (strcmp(key, view_CspaceSigmas) == 0)
+ {
+ double sigm[3];
+ ensureViewCspace();
+ if (readVector(value, 3, sigm) == 0)
+ {
+ cspar->sigm_red = sigm[0]; cspar->sigm_green = sigm[1]; cspar->sigm_blue = sigm[2];
+ }
+ return 1;
+ }
+ else if (strcmp(key, view_CspaceRange) == 0)
+ {
+ ensureViewCspace();
+ double crange[2];
+ if (readVector(value, 2, crange) == 0)
+ {
+ cspar->minVal = crange[0]; cspar->maxVal = crange[1];
+ }
+ return 1;
+ }
+ else if (strcmp(key, view_CspaceType) == 0)
+ {
+ ensureViewCspace();
+ cspar->type = (cspaceType)atoi(value);
+ return 1;
+ }
+ else if (strcmp(key, view_ScaleValue) == 0)
+ {
+ scaleValue = 100*atof(value);
+ return 1;
+ }
+ return 0;
+ }
+ return status;
+}
+
+
+void rviewImage::loadViewFinished(void)
+{
+ rviewDisplay::loadViewFinished();
+
+ pcanv->SetScrollPos(wxHORIZONTAL, scrollx);
+ pcanv->SetScrollPos(wxVERTICAL, scrolly);
+
+ if (scaleSlider != NULL)
+ scaleSlider->SetValue((int)scaleValue);
+
+ mBar->Check(MENU_IMAGE_CSPACE_ON, doValToCspace);
+ mBar->Check(MENU_IMAGE_CSPACE_FULL, doFullRangeCspace);
+ mBar->Check(MENU_IMAGE_CSPACE_PROJ, doProjRangeCspace);
+ mBar->Enable(MENU_IMAGE_CSPACE_ON, doValToCspace);
+ mBar->Enable(MENU_IMAGE_CSPACE_FULL, doValToCspace);
+ mBar->Enable(MENU_IMAGE_CSPACE_PROJ, doValToCspace);
+ mBar->Enable(MENU_IMAGE_CSPACE_EDIT, doValToCspace);
+}
+
+
+
+
+
+/*
+ * Flat image base class members
+ */
+rviewFlatBaseImage::rviewFlatBaseImage(mdd_frame *mf, int es, unsigned int flags) : rviewImage(mf, es, flags)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewFlatBaseImage", "rviewFlatImage()" );
+}
+
+
+rviewFlatBaseImage::~rviewFlatBaseImage(void)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewFlatBaseImage", "~rviewFlatBaseImage()" );
+}
+
+
+int rviewFlatBaseImage::openViewer(void)
+{
+ if (dimMDD < 2)
+ {
+ rviewErrorbox::reportError(lman->lookup("errorModeDim"), rviewFlatBaseImage::getFrameName(), "openViewer");
+ objectInitializedOK = FALSE;
+ return -1;
+ }
+ return rviewImage::openViewer();
+}
+
+
+const char *rviewFlatBaseImage::getFrameName(void) const
+{
+ return "rviewFlatBaseImage";
+}
+
+rviewFrameType rviewFlatBaseImage::getFrameType(void) const
+{
+ return rviewFrameTypeFltBsImage;
+}
+
+
+int rviewFlatBaseImage::newProjection(void)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewFlatBaseImage", "newProjection()" );
+
+ char *data, *lastData = imgData;
+
+ if ((data = projectImage()) == NULL) return -1;
+
+ updatePixmap(lastData, data);
+
+ return 0;
+}
+
+
+char *rviewFlatBaseImage::initMode(void)
+{
+ int i=0, j=0, w=0, h=0;
+ char *data=0;
+
+ RMDBGONCE(3, RMDebug::module_applications, "rviewFlatBaseImage", "initMode()" );
+
+ // Initialise the projection string. Use a static default for now, later on use the
+ // last value used.
+ data = projString;
+ data += sprintf(data, "*:*, *:*");
+ for (i=2; i<dimMDD; i++)
+ {
+ data += sprintf(data, ", %ld", interv[i].low());
+ }
+ project->SetValue(projString);
+
+ // This returns a pointer to the projected MDD data, ready for display by wxPixmap.
+ // It will also set the variables pixWidth, pixHeight.
+ data = projectImage();
+
+ // Calculate the size of the whole window to display the entire image by
+ // first examining the difference between the frame's size and the canvas'
+ // client size (i.e. without the scrollbars)
+ GetSize(&i, &j);
+ pcanv->GetClientSize(&w, &h);
+ w = pixWidth + (i-w); h = pixHeight + (j-h);
+
+ // Limit the size of the window to the values specified in prefs.
+ if (w > prefs->maxDWidth) w = prefs->maxDWidth;
+ if (h > prefs->maxDHeight) h = prefs->maxDHeight;
+
+ // ... then set the window size.
+ SetSize(-1, -1, w, h);
+
+ setModeDimension(2);
+
+ return data;
+}
+
+
+char *rviewFlatBaseImage::projectImage(void)
+{
+ int dim1, dim2;
+
+ RMDBGONCE(3, RMDebug::module_applications, "rviewFlatBaseImage", "projectImage()" );
+
+ mapIndex = r_Point(dimMDD);
+ if (freeDimsFromProjection(dim1, dim2, &mapIndex) != 0) return NULL;
+
+ projectObjectHook();
+
+ rviewFlatProjEnv penv;
+
+ penv.mddPtr = mddObj.ptr();
+ penv.pt1 = pt1; penv.pt2 = pt2;
+ penv.dim1 = dim1; penv.dim2 = dim2;
+ penv.bt = baseType;
+ penv.doCspace = doValToCspace;
+ penv.scale = scaleValue / 100;
+ if (penv.scale <= 0) penv.scale = 0.01;
+
+ if (rviewPrepareFlatProjection(penv) != 0) return NULL;
+
+ if (doValToCspace)
+ {
+ // init if necessary
+ setCspaceProjMode(doProjRangeCspace);
+ // No need for the virtual pitch here, as the image buffer won't be filled with data of the base type
+ penv.cspaceState = rviewCheckInitCspace(baseType, &csmap, mddObj, doFullRangeCspace, csInterv, penv.width, &penv.pitch, &penv.depth, &penv.pad, NULL, cspar);
+ if (csmap != NULL)
+ {
+ mBar->Enable(MENU_IMAGE_CSPACE_EDIT, TRUE);
+ if (doProjRangeCspace)
+ {
+ setCspaceProjMode(doProjRangeCspace);
+ csmap->updateProjection(csInterv);
+ }
+ }
+ deleteViewCspace();
+ }
+ else
+ penv.cspaceState = 0;
+
+ penv.csmap = csmap;
+
+ // Only allocate a new array if it's the first time or the size has changed.
+ if ((penv.width != pixWidth) || (penv.height != pixHeight) || (pixPad != penv.pad) || (pixDepth != penv.depth) || (penv.pitch != virtualPitch))
+ {
+ pixWidth = penv.width; pixHeight = penv.height;
+ pixPad = penv.pad; pixPitch = penv.pitch;
+ pixDepth = penv.depth; virtualPitch = penv.pitch;
+ if ((imgData = (char*)malloc(penv.pitch * pixHeight)) == NULL)
+ {
+ rviewErrorbox::reportError(lman->lookup("errorMemory"), rviewFlatBaseImage::getFrameName(), "projectImage");
+ return NULL;
+ }
+ }
+
+ if (rviewPerformFlatProjection(penv, imgData) != 0) return NULL;
+
+ resizeImage();
+
+ return imgData;
+}
+
+
+
+
+/*
+ * Standard flat images
+ */
+
+rviewFlatImage::rviewFlatImage(mdd_frame *mf, unsigned int flags) : rviewFlatBaseImage(mf, 0, flags)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewFlatImage", "rviewFlatImage()" );
+}
+
+rviewFlatImage::~rviewFlatImage(void)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewFlatImage", "~rviewFlatImage()" );
+ closeViewer();
+}
+
+void rviewFlatImage::OnSize(int w, int h)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewFlatImage", "OnSize()");
+
+ if (initPhaseFinished)
+ {
+ int x, y, step, posx, posy;
+
+ GetClientSize(&x, &y);
+
+ if(x < 6*image_bwidth)
+ {
+ x= 6*image_bwidth;
+ frameWidth=x;
+ frameHeight=y;
+ SetClientSize(x, y);
+ return;
+ }
+ }
+ rviewFlatBaseImage::OnSize(w, h);
+}
+int rviewFlatImage::openViewer(void)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewFlatImage", "openViewer()" );
+
+ if (rviewFlatBaseImage::openViewer() == 0)
+ {
+ openViewerEpilogue(rviewFlatImage::getFrameType());
+ return 0;
+ }
+ return -1;
+}
+
+
+const char *rviewFlatImage::getFrameName(void) const
+{
+ return "rviewFlatImage";
+}
+
+rviewFrameType rviewFlatImage::getFrameType(void) const
+{
+ return rviewFrameTypeFlatImage;
+}
+
+int rviewFlatImage::getViewerType(void) const
+{
+ return RVIEW_RESDISP_IMGFLAT;
+}
+
+
+bool rviewFlatImage::moviePossible(void) const
+{
+ return (dimMDD >= 3);
+}
+
+
+char *rviewFlatImage::movieNewFrame(void)
+{
+ return projectImage();
+}
+
+void rviewFlatImage::label(void)
+{
+ setDisplayTitle(lman->lookup("titleImageFlat"));
+ rviewFlatBaseImage::label();
+}
+
+
+int rviewFlatImage::process(wxObject &obj, wxEvent &evt)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewFlatImage", "process()" );
+
+ int type = evt.GetEventType();
+
+ if (type == wxEVENT_TYPE_SLIDER_COMMAND)
+ {
+ scaleValue = (double)(scaleSlider->GetValue());
+ newProjection();
+ return 1;
+ }
+
+ return rviewImage::process(obj, evt);
+}
+
+
+char *rviewFlatImage::initMode(void)
+{
+ if (playBack != NULL)
+ playBack->Enable(TRUE);
+ if (playFwd != NULL)
+ playFwd->Enable(TRUE);
+
+ return rviewFlatBaseImage::initMode();
+}
+
+
+
+
+
+
+
+
+/*
+ * Rendered image class members
+ */
+
+const char *rviewRenderImage::view_ZProject = "zProject";
+const char *rviewRenderImage::view_ZClip = "zClip";
+const char *rviewRenderImage::view_PixThreshLow = "pixThreshLow";
+const char *rviewRenderImage::view_PixThreshHigh = "pixThreshHigh";
+const char *rviewRenderImage::view_WeightThresh = "weightThresh";
+const char *rviewRenderImage::view_WeightQuant = "weightQuant";
+const char *rviewRenderImage::view_UseRGBBright = "useRgbBright";
+const char *rviewRenderImage::view_UseLighting = "useLighting";
+const char *rviewRenderImage::view_LightAmbient = "lightAmbient";
+const char *rviewRenderImage::view_LightGain = "lightGain";
+const char *rviewRenderImage::view_LightAngle = "lightAngle";
+const char *rviewRenderImage::view_LightScint = "lightScintAngle";
+const char *rviewRenderImage::view_LightDir = "lightDirection";
+const char *rviewRenderImage::view_LightDist = "lightDistance";
+const char *rviewRenderImage::view_KernelSize = "kernelSize";
+const char *rviewRenderImage::view_KernelType = "kernelType";
+const char *rviewRenderImage::view_UseVoxColour = "useVoxColour";
+const char *rviewRenderImage::view_VoxColour = "voxColour";
+const char *rviewRenderImage::view_GridSize = "gridSize";
+const char *rviewRenderImage::view_ScaleHeight = "scaleHeight";
+const char *rviewRenderImage::view_Rotation = "rotation";
+const char *rviewRenderImage::view_ZOffset = "zOffset";
+
+rviewRenderImage::rviewRenderImage(mdd_frame *mf, int es, unsigned int flags) : rviewImage(mf, es, flags)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewRenderImage", "rviewRenderImage()" );
+
+ // make destructor-safe first
+ setupWindow = NULL; rcontrol = NULL; rcurview = NULL;
+ geomData = NULL; geomUse = NULL; rot = NULL; graphEnv = NULL;
+
+ // Default renderer parameters
+ setup.zpro = prefs->imgZpro; setup.clipz = prefs->imgClipz;
+ drx = 0.0; dry = 0.0; drz = 0.0;
+
+ // Default voxel parameters. Try to use halfway sensible defaults. Values of -1
+ // saved in the preferences object are substituted by default-values
+ setup.useRgbBrightness = prefs->imgRgbBrightness;
+ setup.weightQuantisation = 4;
+ setup.pixelThresholdLow = prefs->imgPixThreshLow;
+ setup.pixelThresholdHigh = prefs->imgPixThreshHigh;
+ setup.weightThreshold = prefs->imgWgtThresh;
+ // Light defaults
+ setup.useLights = prefs->imgLight;
+ setup.lightsAngle = prefs->imgLightAngle;
+ setup.lightsScintAngle = prefs->imgLightScintAngle;
+ setup.lightsAmbient = prefs->imgLightAmbient;
+ setup.lightsGain = prefs->imgLightGain;
+ setup.lightsDir = rviewImageSetup::parseLightDirection(prefs->imgLightDir);
+ setup.lightsDist = prefs->imgLightDist;
+ setup.kernelSize = prefs->imgKernSize; setup.kernelType = prefs->imgKernType + 1;
+ setup.useVoxCol = prefs->imgUseVCol; setup.voxColour = prefs->imgVoxColour;
+ // Height field defaults
+ setup.gridSize = prefs->imgHeightGrid; setup.scaleHeight = prefs->imgHeightScale;
+
+ rendererPlayback = 0;
+
+ geomData = new vertex_fp[4]; geomUse = new vertex_fp[4];
+ rot = new vertex_fp[3];
+ graphEnv = new graph_env;
+}
+
+
+rviewRenderImage::~rviewRenderImage(void)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewRenderImage", "~rviewRenderImage()" );
+
+ if (setupWindow != NULL)
+ {
+ setupWindow->unlinkParent();
+ setupWindow->Close(TRUE);
+ }
+ if (rcontrol != NULL)
+ {
+ rcontrol->unlinkParent();
+ rcontrol->Close(TRUE);
+ }
+ if (rcurview != NULL)
+ {
+ rcurview->unlinkParent();
+ rcurview->Close(TRUE);
+ }
+ if(geomData)
+ {
+ delete [] geomData;
+ geomData=0;
+ }
+
+ if(geomUse)
+ {
+ delete [] geomUse;
+ geomUse=0;
+ }
+ if(rot)
+ {
+ delete [] rot;
+ rot=0;
+ }
+
+ if(graphEnv)
+ {
+ delete graphEnv;
+ graphEnv=0;
+ }
+}
+
+
+const char *rviewRenderImage::getFrameName(void) const
+{
+ return "rviewRenderImage";
+}
+
+rviewFrameType rviewRenderImage::getFrameType(void) const
+{
+ return rviewFrameTypeRndImage;
+}
+
+
+int rviewRenderImage::configMenuInitHook(wxMenu *menu)
+{
+ menu->Append(MENU_IMAGE_SETUP_RENDER, "");
+ menu->Append(MENU_IMAGE_SETUP_RCONTROL, "");
+ menu->AppendSeparator();
+ return 3;
+}
+
+
+int rviewRenderImage::viewMenuInitHook(wxMenu *menu)
+{
+ menu->Append(MENU_DISP_VIEW_SHOW, "");
+ return 1;
+}
+
+
+void rviewRenderImage::label(void)
+{
+ mBar->SetLabel(MENU_IMAGE_SETUP_RENDER, lman->lookup("menImgSetupRender"));
+ mBar->SetLabel(MENU_IMAGE_SETUP_RCONTROL, lman->lookup("menImgSetupRctrl"));
+ mBar->SetLabel(MENU_DISP_VIEW_SHOW, lman->lookup("menDispViewShow"));
+
+ rviewImage::label();
+}
+
+
+int rviewRenderImage::newProjection(void)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewRenderImage", "newProjection()" );
+
+ char *data, *lastData = imgData;
+
+ if ((data = setupGraphEnv()) == NULL) return -1;
+ fillBuffer();
+
+ updatePixmap(lastData, data);
+
+ return 0;
+}
+
+
+void rviewRenderImage::updateCurrentView(void)
+{
+ if (rcurview != NULL)
+ {
+ vertex_fp angles;
+ matrixToAngles(angles);
+ rcurview->updateView(angles, zoff, cubeScale);
+ }
+}
+
+
+int rviewRenderImage::process(wxObject &obj, wxEvent &evt)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewRenderImage", "process()" );
+
+ int type = evt.GetEventType();
+
+ if (type == wxEVENT_TYPE_SLIDER_COMMAND)
+ {
+ scaleValue = (double)(scaleSlider->GetValue());
+ cubeScale = scaleValue / 100.0;
+ if (cubeScale < 0.01) cubeScale = 0.01;
+ fillBuffer();
+ pcanv->updateDisplay(TRUE);
+ updateCurrentView();
+ return 1;
+ }
+
+ if (type == wxEVENT_TYPE_BUTTON_COMMAND)
+ {
+ if (&obj == (wxObject*)playStop)
+ {
+ rendererPlayback = 0;
+ if (rcontrol != NULL)
+ rcontrol->setActiveMode(0);
+
+ return 1;
+ }
+ }
+
+ return rviewImage::process(obj, evt);
+}
+
+
+bool rviewRenderImage::canRotateObject(void) const
+{
+ return TRUE;
+}
+
+
+void rviewRenderImage::rotateObject(wxMouseEvent &mevt)
+{
+ float pos;
+
+ // Rotate / translate 3D object
+ if (mevt.leftDown)
+ {
+ pos = mevt.x - mousex;
+ rotateCube(1, pos / 100);
+ pos = mevt.y - mousey;
+ rotateCube(0, pos / 100);
+ fillBuffer();
+ pcanv->updateDisplay();
+ updateCurrentView();
+ }
+
+ if (mevt.rightDown)
+ {
+ pos = mevt.y - mousey;
+ zoff += (long)pos;
+ fillBuffer();
+ pcanv->updateDisplay();
+ updateCurrentView();
+ }
+}
+
+
+void rviewRenderImage::OnSize(int w, int h)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewRenderImage", "OnSize()" );
+
+ int oldwidth = frameWidth;
+ int oldheight = frameHeight;
+
+ rviewImage::OnSize(w, h);
+
+ // Fully initialized yet?
+ if ((initPhaseFinished) && ((oldwidth != frameWidth) || (oldheight != frameHeight)))
+ {
+ char *data, *lastData = imgData;
+
+ if ((data = setupGraphEnv()) != NULL)
+ {
+ fillBuffer();
+ updatePixmap(lastData, data);
+ }
+ }
+}
+
+
+void rviewRenderImage::OnMenuCommand(int id)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewRenderImage", "OnMenuCommand()" );
+
+ switch (id)
+ {
+ case MENU_IMAGE_SETUP_RENDER:
+ if (setupWindow == NULL)
+ {
+ setupWindow = new rviewImageSetup(&setup, this);
+ }
+ break;
+ case MENU_IMAGE_SETUP_RCONTROL:
+ if (rcontrol == NULL)
+ {
+ rcontrol = new rendererControl(drx, dry, drz, rendererPlayback, this);
+ }
+ break;
+ case MENU_DISP_VIEW_SHOW:
+ if (rcurview == NULL)
+ {
+ vertex_fp angles;
+ matrixToAngles(angles);
+ rcurview = new rendererCurrentView(angles, zoff, cubeScale, this);
+ }
+ break;
+ default:
+ rviewImage::OnMenuCommand(id);
+ break;
+ }
+}
+
+
+void rviewRenderImage::closeEditor(bool newSetup)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewRenderImage", "closeEditor()" );
+
+ if (newSetup)
+ {
+ updateSettings(FALSE);
+ }
+ setupWindow->Close(TRUE);
+ setupWindow = NULL;
+}
+
+
+void rviewRenderImage::redrawSettingsChanged(void)
+{
+ fillBuffer();
+ pcanv->updateDisplay();
+}
+
+
+void rviewRenderImage::updateSettings(int setFlags)
+{
+ bool doUpt = FALSE;
+
+ if (setFlags == 0)
+ doUpt = TRUE;
+ else
+ doUpt = doUpdate(setFlags);
+
+ if (doUpt)
+ {
+ redrawSettingsChanged();
+ }
+}
+
+
+bool rviewRenderImage::OnClose(void)
+{
+ if (rendererPlayback != 0) return FALSE;
+ return rviewImage::OnClose();
+}
+
+
+int rviewRenderImage::userEvent(const user_event &ue)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewRenderImage", "userEvent()" );
+
+ if (ue.type == usr_child_closed)
+ {
+ if (ue.data == (void*)setupWindow)
+ {
+ setupWindow = NULL;
+ return 1;
+ }
+ else if (ue.data == (void*)rcontrol)
+ {
+ rcontrol = NULL;
+ return 1;
+ }
+ else if (ue.data == (void*)rcurview)
+ {
+ rcurview = NULL;
+ return 1;
+ }
+ }
+ return rviewImage::userEvent(ue);
+}
+
+
+void rviewRenderImage::closeRendererControls(void)
+{
+ if (rcontrol != NULL)
+ {
+ rcontrol->Close(TRUE);
+ rcontrol = NULL;
+ }
+}
+
+
+void rviewRenderImage::prepareToDie(void)
+{
+ rendererPlayback = 0;
+ rviewImage::prepareToDie();
+}
+
+
+int rviewRenderImage::requestQuit(int level)
+{
+ rendererPlayback = 0;
+ return rviewImage::requestQuit(level);
+}
+
+
+void rviewRenderImage::setAutoRotation(float rx, float ry, float rz)
+{
+ //cout << "rotate " << rx << ", " << ry << ", " << rz << endl;
+
+ if (rx >= 100.0)
+ {
+ rendererPlayback = 0; return;
+ }
+ drx = rx; dry = ry; drz = rz;
+
+ // No re-entrancy
+ if (rendererPlayback != 0) return;
+
+ rendererPlayback = 1;
+
+ while (rendererPlayback != 0)
+ {
+ rotateCube(0, M_PI*drx/10); rotateCube(1, M_PI*dry/10); rotateCube(2, M_PI*drz/10);
+ updateCurrentView();
+ newProjection();
+ ::wxYield();
+ }
+}
+
+
+void rviewRenderImage::setCurrentView(const vertex_fp &angles, long off, double scale)
+{
+ anglesToMatrix(angles);
+ zoff = off;
+ cubeScale = scale;
+ scaleSlider->SetValue((int)(100*cubeScale));
+
+ newProjection();
+}
+
+
+char *rviewRenderImage::initMode(void)
+{
+ int i;
+ char *data;
+
+ RMDBGONCE(3, RMDebug::module_applications, "rviewRenderImage", "initMode()" );
+
+ // Scaling factor for the data cube.
+ cubeScale = scaleValue / 100.0;
+ if (cubeScale < 0.01) cubeScale = 0.01;
+
+ // Init rotation matrix
+ for (i=0; i<3; i++)
+ {
+ rot[i].x = 0.0; rot[i].y = 0.0; rot[i].z = 0.0;
+ }
+ rot[0].x = 1.0; rot[1].y = 1.0; rot[2].z = 1.0;
+
+ zoff = 0;
+
+ data = setupGraphEnv();
+
+ if (initPhaseFinished) fillBuffer();
+
+ // Do not update the pixmap here! That's done by the calling procedure, if necessary
+
+ resizeImage();
+
+ return data;
+}
+
+
+char *rviewRenderImage::setupGraphEnv(void)
+{
+ int w, h;
+
+ RMDBGONCE(3, RMDebug::module_applications, "rviewRenderImage", "setupGraphEnv()" );
+
+ if (rviewParseProjection(getVirtualDomain(), pt1, pt2, projString, &freeDims) != dimMDD)
+ {
+ rviewErrorbox::reportError(lman->lookup("errorProjection"), rviewRenderImage::getFrameName(), "setupGraphEnv");
+ return NULL;
+ }
+
+ pcanv->GetClientSize(&w, &h);
+
+ setupEnvironment(w, h);
+
+ graphEnv->zpro = setup.zpro; graphEnv->clipz = setup.clipz;
+ graphEnv->clipl = -pixWidth/2; graphEnv->clipr = graphEnv->clipl + pixWidth - 1;
+ graphEnv->clipd = -pixHeight/2; graphEnv->clipu = graphEnv->clipd + pixHeight - 1;
+ graphEnv->midx = -graphEnv->clipl; graphEnv->midy = graphEnv->clipu;
+ /* lineadd set in one of the modules above */
+ graphEnv->dest = (void*)imgData;
+
+ return imgData;
+}
+
+
+void rviewRenderImage::rotateCube(int axis, float angle, vertex_fp *matrix)
+{
+ real_t c, s;
+ vertex_fp h;
+ int i, j;
+
+ c = cos(angle); s = sin(angle);
+
+ switch (axis)
+ {
+ case 0: i = 1; j = 2; break;
+ case 1: i = 2; j = 0; break;
+ case 2: i = 0; j = 1; break;
+ default:
+ cerr << "Bad rotation axis " << axis;
+ return;
+ }
+ h.x = c * matrix[i].x + s * matrix[j].x;
+ h.y = c * matrix[i].y + s * matrix[j].y;
+ h.z = c * matrix[i].z + s * matrix[j].z;
+ matrix[j].x = c * matrix[j].x - s * matrix[i].x;
+ matrix[j].y = c * matrix[j].y - s * matrix[i].y;
+ matrix[j].z = c * matrix[j].z - s * matrix[i].z;
+ matrix[i].x = h.x;
+ matrix[i].y = h.y;
+ matrix[i].z = h.z;
+
+ /*for (i=0; i<3; i++)
+ {
+ cout << '[' << matrix[i].x << ',' << matrix[i].y << ',' << matrix[i].z << ']';
+ }
+ cout << endl;*/
+
+}
+
+void rviewRenderImage::rotateCube(int axis, float angle)
+{
+ rotateCube(axis, angle, rot);
+}
+
+
+void rviewRenderImage::getLightPos(vertex_fp *lpos)
+{
+ lpos->x = 0; lpos->y = 0; lpos->z = 0;
+ if ((setup.lightsDir & RVIEW_LIGHTDIR_LEFT) != 0) lpos->x = -1.0;
+ else if ((setup.lightsDir & RVIEW_LIGHTDIR_RIGHT) != 0) lpos->x = 1.0;
+ if ((setup.lightsDir & RVIEW_LIGHTDIR_DOWN) != 0) lpos->y = -1.0;
+ else if ((setup.lightsDir & RVIEW_LIGHTDIR_UP) != 0) lpos->y = 1.0;
+ if ((setup.lightsDir & RVIEW_LIGHTDIR_FRONT) != 0) lpos->z = -1.0;
+ else if ((setup.lightsDir & RVIEW_LIGHTDIR_BACK) != 0) lpos->z = 1.0;
+ if (setup.lightsDir != 0)
+ {
+ double h;
+
+ h = ((double) setup.lightsDist) /sqrt((lpos->x * lpos->x) + (lpos->y * lpos->y) + (lpos->z * lpos->z));
+ lpos->x *= h; lpos->y *= h; lpos->z *= h;
+ }
+ lpos->z += graphEnv->zpro;
+}
+
+
+// not correct for x==0, but I don't need that case
+#define SIGN(x) ((x > 0) ? 1 : -1)
+
+#define PRINT_MATRIX(mat) { \
+ for (unsigned int i=0; i<3; i++) \
+ cout << i << ": " << (mat)[i].x << ", " << (mat)[i].y << ", " << (mat)[i].z << endl; \
+ }
+
+void rviewRenderImage::matrixToAngles(vertex_fp &angles) const
+{
+ vertex_fp matrix[3];
+
+ // make copy of rotation matrix for working
+ memcpy(&matrix, rot, 3*sizeof(vertex_fp));
+
+ // Successively rotate it back to identity. Getting this right is a major headache;
+ // one must bear in mind that rot[] are row-vectors and that atan() only returns
+ // values in -pi/2 to pi/2, so the result may have to be shifted by pi.
+ if (matrix[1].x == 0.0)
+ {
+ angles.z = 0.0;
+ }
+ else
+ {
+ angles.z = -((matrix[0].x == 0.0) ? SIGN(matrix[1].x) * M_PI/2 : atan(matrix[1].x / matrix[0].x));
+ }
+ if (matrix[0].x < 0) angles.z += M_PI;
+ if (angles.z != 0.0)
+ {
+ rotateCube(2, -angles.z, matrix);
+ //cout << "ROTz" << endl; PRINT_MATRIX(matrix);
+ }
+
+ if (matrix[2].x == 0.0)
+ {
+ angles.y = 0.0;
+ }
+ else
+ {
+ angles.y = -((matrix[0].x == 0.0) ? -SIGN(matrix[2].x) * M_PI/2 : -atan(matrix[2].x / matrix[0].x));
+ rotateCube(1, -angles.y, matrix);
+ //cout << "ROTy" << endl; PRINT_MATRIX(matrix);
+ }
+
+ if (matrix[2].y == 0.0)
+ {
+ angles.x = 0.0;
+ }
+ else
+ {
+ angles.x = -((matrix[1].y == 0.0) ? SIGN(matrix[2].y) * M_PI/2 : atan(matrix[2].y / matrix[1].y));
+ }
+ if (matrix[1].y < 0) angles.x += M_PI;
+ if (angles.x != 0.0)
+ {
+ rotateCube(0, -angles.x, matrix);
+ //cout << "ROTx" << endl; PRINT_MATRIX(matrix);
+ }
+
+#if 0
+ rotateCube(0, angles.x, matrix);
+ rotateCube(1, angles.y, matrix);
+ rotateCube(2, angles.z, matrix);
+ unsigned int i;
+ double res;
+ for (i=0, res=0.0; i<3; i++)
+ {
+ cout << "REC " << i << ": " << matrix[i].x << ", " << matrix[i].y << ", " << matrix[i].z
+ << " vs. " << rot[i].x << ", " << rot[i].y << ", " << rot[i].z << endl;
+ res += (matrix[i].x - rot[i].x) * (matrix[i].x - rot[i].x) + (matrix[i].y - rot[i].y) * (matrix[i].y - rot[i].y) + (matrix[i].z - rot[i].z) * (matrix[i].z - rot[i].z);
+ }
+ cout << "Residuum " << res << endl;
+#endif
+}
+
+
+void rviewRenderImage::anglesToMatrix(const vertex_fp &angles)
+{
+ unsigned int i;
+
+ for (i=0; i<3; i++)
+ {
+ rot[i].x = 0.0; rot[i].y = 0.0; rot[i].z = 0.0;
+ }
+ rot[0].x = 1.0; rot[1].y = 1.0; rot[2].z = 1.0;
+
+ rotateCube(0, angles.x);
+ rotateCube(1, angles.y);
+ rotateCube(2, angles.z);
+}
+
+
+int rviewRenderImage::saveView(FILE *fp)
+{
+ int status = rviewImage::saveView(fp);
+
+ writeViewParam(fp, view_ZProject, (long)setup.zpro);
+ writeViewParam(fp, view_ZClip, (long)setup.clipz);
+ writeViewParam(fp, view_PixThreshLow, setup.pixelThresholdLow);
+ writeViewParam(fp, view_PixThreshHigh, setup.pixelThresholdHigh);
+ writeViewParam(fp, view_WeightThresh, setup.weightThreshold);
+ writeViewParam(fp, view_WeightQuant, (long)setup.weightQuantisation);
+ writeViewParam(fp, view_UseRGBBright, (long)setup.useRgbBrightness);
+ writeViewParam(fp, view_UseLighting, (long)setup.useLights);
+ writeViewParam(fp, view_LightAmbient, setup.lightsAmbient);
+ writeViewParam(fp, view_LightGain, setup.lightsGain);
+ writeViewParam(fp, view_LightAngle, setup.lightsAngle);
+ writeViewParam(fp, view_LightScint, setup.lightsScintAngle);
+ writeViewParam(fp, view_LightDir, (long)setup.lightsDir);
+ writeViewParam(fp, view_LightDist, (long)setup.lightsDist);
+ writeViewParam(fp, view_KernelSize, (long)setup.kernelSize);
+ writeViewParam(fp, view_KernelType, (long)setup.kernelType);
+ writeViewParam(fp, view_UseVoxColour, (long)setup.useVoxCol);
+ writeViewParam(fp, view_VoxColour, setup.voxColour);
+ writeViewParam(fp, view_GridSize, (long)setup.gridSize);
+ writeViewParam(fp, view_ScaleHeight, setup.scaleHeight);
+
+ vertex_fp angles;
+ double avals[3];
+ matrixToAngles(angles);
+ avals[0] = angles.x; avals[1] = angles.y; avals[2] = angles.z;
+ writeViewParam(fp, view_Rotation, 3, avals);
+ writeViewParam(fp, view_ZOffset, zoff);
+
+ return status;
+}
+
+
+int rviewRenderImage::readView(const char *key, const char *value)
+{
+ int status = rviewImage::readView(key, value);
+
+ if (status == 0)
+ {
+ if (strcmp(key, view_ZProject) == 0)
+ {
+ setup.zpro = (unsigned long)atol(value);
+ return 1;
+ }
+ else if (strcmp(key, view_ZClip) == 0)
+ {
+ setup.clipz = (unsigned long)atol(value);
+ return 1;
+ }
+ else if (strcmp(key, view_PixThreshLow) == 0)
+ {
+ setup.pixelThresholdLow = atof(value);
+ return 1;
+ }
+ else if (strcmp(key, view_PixThreshHigh) == 0)
+ {
+ setup.pixelThresholdHigh = atof(value);
+ return 1;
+ }
+ else if (strcmp(key, view_WeightThresh) == 0)
+ {
+ setup.weightThreshold = atof(value);
+ return 1;
+ }
+ else if (strcmp(key, view_WeightQuant) == 0)
+ {
+ setup.weightQuantisation = atoi(value);
+ return 1;
+ }
+ else if (strcmp(key, view_UseRGBBright) == 0)
+ {
+ setup.useRgbBrightness = (bool)atoi(value);
+ return 1;
+ }
+ else if (strcmp(key, view_UseLighting) == 0)
+ {
+ setup.useLights = (bool)atoi(value);
+ return 1;
+ }
+ else if (strcmp(key, view_LightAmbient) == 0)
+ {
+ setup.lightsAmbient = atof(value);
+ return 1;
+ }
+ else if (strcmp(key, view_LightGain) == 0)
+ {
+ setup.lightsGain = atof(value);
+ return 1;
+ }
+ else if (strcmp(key, view_LightAngle) == 0)
+ {
+ setup.lightsAngle = atof(value);
+ return 1;
+ }
+ else if (strcmp(key, view_LightScint) == 0)
+ {
+ setup.lightsScintAngle = atof(value);
+ return 1;
+ }
+ else if (strcmp(key, view_LightDir) == 0)
+ {
+ setup.lightsDir = atoi(value);
+ return 1;
+ }
+ else if (strcmp(key, view_LightDist) == 0)
+ {
+ setup.lightsDist = atoi(value);
+ return 1;
+ }
+ else if (strcmp(key, view_KernelSize) == 0)
+ {
+ setup.kernelSize = atoi(value);
+ return 1;
+ }
+ else if (strcmp(key, view_KernelType) == 0)
+ {
+ setup.kernelType = atoi(value);
+ return 1;
+ }
+ else if (strcmp(key, view_UseVoxColour) == 0)
+ {
+ setup.useVoxCol = (bool)atoi(value);
+ return 1;
+ }
+ else if (strcmp(key, view_VoxColour) == 0)
+ {
+ setup.voxColour = atof(value);
+ return 1;
+ }
+ else if (strcmp(key, view_GridSize) == 0)
+ {
+ setup.gridSize = atoi(value);
+ return 1;
+ }
+ else if (strcmp(key, view_ScaleHeight) == 0)
+ {
+ setup.scaleHeight = atof(value);
+ return 1;
+ }
+ else if (strcmp(key, view_Rotation) == 0)
+ {
+ double avals[3];
+ if (readVector(value, 3, avals) == 0)
+ {
+ vertex_fp angles;
+ angles.x = avals[0]; angles.y = avals[1]; angles.z = avals[2];
+ anglesToMatrix(angles);
+ }
+ return 1;
+ }
+ else if (strcmp(key, view_ZOffset) == 0)
+ {
+ zoff = atol(value);
+ return 1;
+ }
+ return 0;
+ }
+ return status;
+}
+
+
+void rviewRenderImage::loadViewFinished(void)
+{
+ rviewImage::loadViewFinished();
+
+ if (setupWindow != NULL)
+ setupWindow->updateSettings(setup);
+
+ if (rcurview != NULL)
+ {
+ vertex_fp angles;
+ matrixToAngles(angles);
+ rcurview->updateView(angles, zoff, cubeScale);
+ }
+
+ cubeScale = scaleValue / 100.0;
+}
+
+
+
+/*
+ * Handling the renderer buffer
+ */
+
+#define FILL_BACKGROUND_CORE(type) \
+ type value, *imgSrcPtr; \
+ int fbcx, fbcy; \
+ imgSrcPtr = (type*)(graphEnv->dest); value = (type)minVal; \
+ for (fbcy=0; fbcy < pixHeight; fbcy++) \
+ { \
+ for (fbcx=0; fbcx < pixWidth; fbcx++) \
+ { \
+ imgSrcPtr[fbcx] = value; \
+ } \
+ imgSrcPtr = (type*)(((char*)imgSrcPtr) + virtualPitch); \
+ }
+
+void rviewRenderImage::fillBackgroundCore(rviewBaseType bt, double minVal)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewRenderImage", "fillBackgroundCore()" );
+
+ switch (bt)
+ {
+ case rbt_char:
+ {
+ FILL_BACKGROUND_CORE(r_Char);
+ }
+ break;
+ case rbt_uchar:
+ {
+ FILL_BACKGROUND_CORE(r_Octet);
+ }
+ break;
+ case rbt_short:
+ {
+ FILL_BACKGROUND_CORE(r_Short);
+ }
+ break;
+ case rbt_ushort:
+ {
+ FILL_BACKGROUND_CORE(r_UShort);
+ }
+ break;
+ case rbt_long:
+ {
+ FILL_BACKGROUND_CORE(r_Long);
+ }
+ break;
+ case rbt_ulong:
+ {
+ FILL_BACKGROUND_CORE(r_ULong);
+ }
+ break;
+ case rbt_float:
+ {
+ FILL_BACKGROUND_CORE(r_Float);
+ }
+ break;
+ case rbt_double:
+ {
+ FILL_BACKGROUND_CORE(r_Double);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void rviewRenderImage::fillBufferBackground(bool doCspace, bool &cspaceOK, r_Ref<r_GMarray> &obj, colourspaceMapper **csm, r_Minterval *csdom, rviewBaseType bt, bool fullRange, double *useMinVal)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewRenderImage", "fillBufferBackground()" );
+
+ // In case of colourspace mapping and rendering don't fill the background with 0 but
+ // rather with the currently configured minimum value!
+ if (doCspace)
+ {
+ cspaceOK = FALSE;
+ if (rviewCheckInitCspace(bt, csm, obj, fullRange, csdom) != 0)
+ {
+ double minVal;
+
+ cspaceOK = TRUE;
+ minVal = (useMinVal == NULL) ? (*csm)->getMinVal() : *useMinVal;
+
+ fillBackgroundCore(bt, minVal);
+ }
+ }
+ else
+ {
+ memset(graphEnv->dest, 0, pixPitch * pixHeight);
+ }
+}
+
+
+// Macro for colourspace translation from/to various basetypes
+// Fill in inverse order because source type may be smaller than destination type
+#define TRANSLATE_TO_COLOURSPACE15(type) \
+ type *imgSrcPtr; \
+ long value; \
+ for (j=0; j<pixHeight; j++, imgLine+=pixPitch) \
+ { \
+ imgPtrS = ((unsigned short*)imgLine) + pixWidth-1; imgSrcPtr = ((type*)imgLine) + pixWidth-1; \
+ for (i=0; i<pixWidth; i++, imgPtrS--, imgSrcPtr--) \
+ { \
+ value = (long)(*imgSrcPtr); if (value > maxValL) value = maxValL; \
+ value -= minValL; if (value < 0) value = 0; \
+ *imgPtrS = IntToRGBTab15[value]; \
+ } \
+ }
+
+// Fill in ascending order here because the destination type may be smaller than the source type
+#define TRANSLATE_TO_COLOURSPACE32(type, minval, maxval, scale) \
+ type value, *imgSrcPtr; \
+ char *imgSrcBase = (char*)imgLine; \
+ if (IntToRGBTab24 == NULL) \
+ { \
+ for (j=0; j<pixHeight; j++, imgLine+=pixPitch, imgSrcBase+=virtualPitch) \
+ { \
+ imgPtrL = (unsigned long*)imgLine; imgSrcPtr = (type*)imgSrcBase; \
+ for (i=0; i<pixWidth; i++, imgPtrL++, imgSrcPtr++) \
+ { \
+ *imgPtrL = csmap->ValToCS24((double)(*imgSrcPtr) - minVal); \
+ } \
+ } \
+ } \
+ else \
+ { \
+ for (j=0; j<pixHeight; j++, imgLine+=pixPitch, imgSrcBase+=virtualPitch) \
+ { \
+ imgPtrL = (unsigned long*)imgLine; imgSrcPtr = (type*)imgSrcBase; \
+ for (i=0; i<pixWidth; i++, imgPtrL++, imgSrcPtr++) \
+ { \
+ value = *imgSrcPtr; if (value > maxval) value = maxval; \
+ value -= minval; if (value < 0) value = 0; \
+ *imgPtrL = IntToRGBTab24[(unsigned long)(value * scale)]; \
+ } \
+ } \
+ }
+
+void rviewRenderImage::translateBufferToCspace(rviewBaseType bt, double *useMinVal, double *useMaxVal)
+{
+ double minVal;
+ unsigned char *imgLine;
+ unsigned short *IntToRGBTab15, *imgPtrS;
+ unsigned long *IntToRGBTab24, *imgPtrL;
+ double maxVal, scalingFactor;
+ long minValL, maxValL;
+ int i, j;
+
+ RMDBGONCE(3, RMDebug::module_applications, "rviewRenderImage", "translateBufferToCspace()" );
+
+ // If bounding boxes are drawn there might be pixels out of range here, so trap those!
+ minVal = (useMinVal == NULL) ? csmap->getMinVal() : *useMinVal;
+ maxVal = (useMaxVal == NULL) ? csmap->getMaxVal() : *useMaxVal;
+ minValL = (long)minVal; maxValL = (long)maxVal;
+ scalingFactor = csmap->getScalingFactor();
+
+ imgLine = (unsigned char*)(graphEnv->dest);
+ IntToRGBTab15 = csmap->getCSTab15();
+ IntToRGBTab24 = csmap->getCSTab24();
+
+ switch (bt)
+ {
+ case rbt_char:
+ {
+ TRANSLATE_TO_COLOURSPACE15(r_Char);
+ }
+ break;
+ case rbt_uchar:
+ {
+ TRANSLATE_TO_COLOURSPACE15(r_Octet);
+ }
+ break;
+ case rbt_short:
+ {
+ TRANSLATE_TO_COLOURSPACE15(r_Short);
+ }
+ break;
+ case rbt_ushort:
+ {
+ TRANSLATE_TO_COLOURSPACE15(r_UShort);
+ }
+ break;
+ case rbt_long:
+ {
+ TRANSLATE_TO_COLOURSPACE32(r_Long, minValL, maxValL, 1);
+ }
+ break;
+ case rbt_ulong:
+ {
+ TRANSLATE_TO_COLOURSPACE32(r_ULong, (r_ULong)minValL, (r_ULong)maxValL, 1);
+ }
+ break;
+ case rbt_float:
+ {
+ TRANSLATE_TO_COLOURSPACE32(r_Float, minVal, maxVal, scalingFactor);
+ }
+ break;
+ case rbt_double:
+ {
+ TRANSLATE_TO_COLOURSPACE32(r_Double, minVal, maxVal, scalingFactor);
+ }
+ break;
+ default:
+ {
+ rviewErrorbox::reportError(lman->lookup("errorBaseType"), rviewRenderImage::getFrameName(), "translateBufferToCspace");
+ return;
+ }
+ }
+}
+
+
+int rviewRenderImage::setupEnvBase(int w, int h, r_Ref<r_GMarray> &mdd, colourspaceMapper **csm, r_Minterval *csdom)
+{
+ int needDepth, newPitch, newPad, newVirtPitch;
+
+ needDepth = 8*baseSize;
+ if ((rviewImageTypes[baseType] == RVIEW_IMGTYPE_NONE) && (doValToCspace)) needDepth = 32;
+ if (rviewImageTypes[baseType] == RVIEW_IMGTYPE_HIGH) needDepth = 15;
+ if (rviewImageTypes[baseType] == RVIEW_IMGTYPE_GREY12) needDepth = 12;
+ newPad = 64; newPitch = (w * baseSize + 7) & ~7;
+ newVirtPitch = newPitch;
+
+ if (doValToCspace)
+ {
+ // Init if necessary
+ setCspaceProjMode(doProjRangeCspace);
+ rviewCheckInitCspace(baseType, csm, mdd, doFullRangeCspace, csdom, w, &newPitch, &needDepth, &newPad, &newVirtPitch, cspar);
+ if (*csm != NULL)
+ {
+ mBar->Enable(MENU_IMAGE_CSPACE_EDIT, TRUE);
+ if (doProjRangeCspace)
+ {
+ setCspaceProjMode(doProjRangeCspace);
+ (*csm)->updateProjection(csdom);
+ }
+ }
+ deleteViewCspace();
+ }
+
+ if ((w != pixWidth) || (h != pixHeight) || (pixPad != newPad) || (pixDepth != needDepth) || (newPitch != pixPitch) || (newVirtPitch != virtualPitch))
+ {
+ pixWidth = w; pixHeight = h; pixDepth = needDepth;
+ pixPitch = newPitch; pixPad = newPad; virtualPitch = newVirtPitch;
+ if ((imgData = (char*)malloc(virtualPitch * pixHeight)) == NULL)
+ {
+ rviewErrorbox::reportError(lman->lookup("errorMemory"), getFrameName(), "setupEnvironment");
+ return -1;
+ }
+ }
+
+ graphEnv->lineadd = virtualPitch;
+
+ return 0;
+}
+
+
+
+
+/*
+ * Volume image renderer members
+ */
+
+const char *rviewVolumeImage::view_VolumeMode = "volumeMode";
+const char *rviewVolumeImage::view_UseBBox = "useBBox";
+
+rviewVolumeImage::rviewVolumeImage(mdd_frame *mf, unsigned int flags) : rviewRenderImage(mf, 0, flags)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewVolumeImage", "rviewVolumeImage()" );
+
+ // make destructor safe
+ texDesc = NULL; voxDesc = NULL;
+
+ initVoxParams = FALSE;
+ // Mode defaults
+ imode = prefs->imgMode;
+ if ((imode != rim_surf) && (imode != rim_voxel)) imode = rim_surf;
+
+ if (prefs->imgVoxForType != 0)
+ {
+ initVoxParams = TRUE;
+ switch (baseSize)
+ {
+ case 1:
+ setup.pixelThresholdLow = 4.0; setup.pixelThresholdHigh = 1e6;
+ setup.weightThreshold = 64.0; setup.voxColour = 0xff;
+ break;
+ case 2:
+ setup.pixelThresholdLow = 256.0; setup.pixelThresholdHigh = 65535.0;
+ setup.weightThreshold = 64.0; setup.voxColour = 0xffff;
+ break;
+ case 3:
+ setup.pixelThresholdLow = 4.0; setup.pixelThresholdHigh = 1e6;
+ setup.weightThreshold = 64.0; setup.voxColour = 0xffffff;
+ break;
+ case 4:
+ setup.pixelThresholdLow = 16384.0; setup.pixelThresholdHigh = 1e6;
+ setup.weightThreshold = 64.0; setup.voxColour = 0xffffffff;
+ break;
+ case 8:
+ setup.pixelThresholdLow = 0.0; setup.pixelThresholdHigh = 1e12;
+ setup.weightThreshold = 64.0; setup.voxColour = 1e12;
+ default: break;
+ }
+ }
+
+ // Align bbox with projection's OK-button
+ boundingBox = new rviewCheckBox(ctrlPanel);
+ // Preferences
+ doBoundingBox = prefs->imgBBox;
+ boundingBox->SetValue(doBoundingBox);
+
+ texDesc = new tex_desc;
+ voxDesc = new voxel_desc;
+ texDesc->floatType = ((baseType == rbt_float) || (baseType == rbt_double)) ? 1 : 0;
+
+}
+
+
+int rviewVolumeImage::openViewer(void)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewVolumeImage", "openViewer()" );
+
+ if (dimMDD != 3)
+ {
+ rviewErrorbox::reportError(lman->lookup("errorModeDim"), rviewVolumeImage::getFrameName(), "openViewer");
+ objectInitializedOK = FALSE;
+ return -1;
+ }
+
+ if (rviewRenderImage::openViewer() == 0)
+ {
+ // first add the menus of the parent class
+ int madd = rviewRenderImage::menuBarInitHook();
+
+ // then add my own
+ wxMenu *modes;
+ char buffer[STRINGSIZE];
+ modes = new wxMenu;
+ modes->Append(MENU_IMAGE_MODE_SURF, "", NULL, TRUE);
+ modes->Append(MENU_IMAGE_MODE_VOXEL, "", NULL, TRUE);
+ sprintf(buffer, "&%s", lman->lookup("menImgMode"));
+ mBar->Append(modes, buffer);
+
+ switch (imode)
+ {
+ case rim_surf: lastMode = MENU_IMAGE_MODE_SURF; break;
+ case rim_voxel: lastMode = MENU_IMAGE_MODE_VOXEL; break;
+ default: break;
+ }
+ modes->Check(lastMode, TRUE);
+
+ openViewerEpilogue(rviewVolumeImage::getFrameType());
+
+ return 0;
+ }
+ return -1;
+}
+
+
+rviewVolumeImage::~rviewVolumeImage(void)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewVolumeImage" ,"~rviewVolumeImage()" );
+
+ closeViewer();
+ delete texDesc;
+ delete voxDesc;
+}
+
+
+const char *rviewVolumeImage::getFrameName(void) const
+{
+ return "rviewVolumeImage";
+}
+
+rviewFrameType rviewVolumeImage::getFrameType(void) const
+{
+ return rviewFrameTypeVolImage;
+}
+
+int rviewVolumeImage::getViewerType(void) const
+{
+ return RVIEW_RESDISP_IMGVOLM;
+}
+
+
+void rviewVolumeImage::label(void)
+{
+ setDisplayTitle(lman->lookup("titleImageVolume"));
+
+ boundingBox->SetLabel(lman->lookup("textBBox"));
+
+ mBar->SetLabel(MENU_IMAGE_MODE_SURF, lman->lookup("menImgModeSurf"));
+ mBar->SetLabel(MENU_IMAGE_MODE_VOXEL, lman->lookup("menImgModeVoxel"));
+ mBar->SetLabelTop(fixedNumberOfMenus + 1, lman->lookup("menImgMode"));
+
+ rviewRenderImage::label();
+}
+
+
+int rviewVolumeImage::process(wxObject &obj, wxEvent &evt)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewVolumeImage", "process()" );
+
+ int type = evt.GetEventType();
+
+ if (type == wxEVENT_TYPE_CHECKBOX_COMMAND)
+ {
+ if (&obj == (wxObject*)boundingBox)
+ {
+ doBoundingBox = boundingBox->GetValue();
+ fillBuffer();
+ pcanv->updateDisplay();
+ return 1;
+ }
+ }
+
+ return rviewRenderImage::process(obj, evt);
+}
+
+
+void rviewVolumeImage::OnMenuCommand(int id)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewVolumeImage", "OnMenuCommand()" );
+
+ rviewImageMode newMode = rim_none;
+
+ switch (id)
+ {
+ case MENU_IMAGE_MODE_SURF: newMode = rim_surf; break;
+ case MENU_IMAGE_MODE_VOXEL: newMode = rim_voxel; break;
+ default:
+ rviewRenderImage::OnMenuCommand(id);
+ break;
+ }
+ if (newMode != rim_none)
+ {
+ configureMode();
+
+ // We have to do this in any case or the menus get screwed
+ mBar->Check(lastMode, FALSE);
+ mBar->Check(id, TRUE);
+ lastMode = id;
+
+ if (newMode != imode)
+ {
+ imode = newMode;
+ fillBuffer();
+ updatePixmap(imgData, imgData);
+ }
+ }
+}
+
+
+void rviewVolumeImage::OnSize(int w, int h)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewVolumeImage", "OnSize()" );
+
+ rviewRenderImage::OnSize(w, h);
+
+ if (boundingBox != NULL)
+ boundingBox->SetSize(w + 2*display_cnvborder - 3*display_border - 4*display_pbwidth, display_border, image_bbwidth, image_bbheight);
+}
+
+
+bool rviewVolumeImage::doUpdate(int flags)
+{
+ if (((flags & RVIEW_IFLAG_VOXEL) != 0) && (imode == rim_voxel)) return TRUE;
+ if (((flags & RVIEW_IFLAG_LIGHT) != 0) && setup.useLights) return TRUE;
+ return FALSE;
+}
+
+
+char *rviewVolumeImage::initMode(void)
+{
+ RMDBGENTER(3, RMDebug::module_applications, "rviewVolumeImage", "initMode()" );
+
+ // Initialise the projection string. Use a static default for now, later on use the
+ // last value used.
+ sprintf(projString, "*:*, *:*, *:*");
+
+ project->SetValue(projString);
+ setModeDimension(3);
+
+ if (boundingBox != NULL)
+ boundingBox->Enable(TRUE);
+
+ texDesc->dimx = interv[0].high() - interv[0].low() + 1;
+ texDesc->dimy = interv[1].high() - interv[1].low() + 1;
+ texDesc->dimz = interv[2].high() - interv[2].low() + 1;
+ texDesc->baseSize = baseSize;
+
+ RMDBGEXIT(3, RMDebug::module_applications, "rviewVolumeImage", "initMode() tx=" << texDesc->dimx << ", ty=" << texDesc->dimy << ", tz=" << texDesc->dimz << ", tbase=" << texDesc->baseSize );
+
+ return rviewRenderImage::initMode();
+}
+
+
+char *rviewVolumeImage::setupEnvironment(int w, int h)
+{
+ RMDBGENTER(3, RMDebug::module_applications, "rviewVolumeImage", "setupEnvironment()" );
+
+ int i, offset;
+
+ if (setupEnvBase(w, h, mddObj, &csmap, csInterv) != 0)
+ return NULL;
+
+ // These values change for each projection
+ texDesc->widthx = pt2[0] - pt1[0] + 1;
+ texDesc->widthy = pt2[1] - pt1[1] + 1;
+ texDesc->widthz = pt2[2] - pt1[2] + 1;
+
+ r_Ref<r_Marray<r_Char> > tempMdd = (r_Ref<r_Marray<r_Char> >) mddObj;
+ // Do it like this to avoid having to check all base types
+ r_Point paux = r_Point(dimMDD);
+ for (i=0; i<dimMDD; i++)
+ {
+ paux[i] = interv[i].low();
+ }
+ offset = ((int)(&((*tempMdd)[pt1]) - &((*tempMdd)[paux]))) * baseSize;
+
+ texDesc->data = (void*)((char*)(tempMdd->get_array()) + offset);
+
+ for (i=0; i<4; i++)
+ {
+ geomData[i].x = 0; geomData[i].y = 0; geomData[i].z = 0;
+ }
+ geomData[1].x = (real_t)(pt2[0] - pt1[0] + 1);
+ geomData[2].y = (real_t)(pt2[1] - pt1[1] + 1);
+ geomData[3].z = (real_t)(pt2[2] - pt1[2] + 1);
+
+ RMDBGMIDDLE(3, RMDebug::module_applications, "rviewVolumeImage", "w=" << pixWidth << ", h=" << pixHeight << ", p=" << pixPitch << ", cl=" << graphEnv->clipl << ", cr=" << graphEnv->clipr << ", cd=" << graphEnv->clipd << ", cu=" << graphEnv->clipu << ", mx=" << graphEnv->midx << ", my=" << graphEnv->midy << ", img=" << graphEnv->dest );
+
+ RMDBGMIDDLE(3, RMDebug::module_applications, "rviewVolumeImage", "twx=" << texDesc->widthx << ", twy=" << texDesc->widthy << ", twz=" << texDesc->widthz << ", offset=" << (int)((char*)(texDesc->data) - mddObj->get_array()) << ", base size " << texDesc->baseSize << ", dest=" << (void*)imgData );
+
+ RMDBGEXIT(3, RMDebug::module_applications, "rviewVolumeImage", "setupEnvironment()");
+ return imgData;
+}
+
+
+void rviewVolumeImage::fillBuffer(void)
+{
+ int i;
+ vertex_fp v;
+ bool cspaceOK;
+
+ RMDBGONCE(3, RMDebug::module_applications, "rviewVolumeImage", "fillBuffer()" );
+
+ // Plot bounding box or not?
+ graphEnv->bbox_colour = (doBoundingBox) ? 0xffffff : 0xffffffff;
+ // Update z-rendering parameters
+ graphEnv->zpro = setup.zpro; graphEnv->clipz = setup.clipz;
+
+ for (i=1; i<4; i++)
+ {
+ // Make sure we don't get zero length vectors
+ // (only a problem with strongly deformed ``cubes'', like planes)
+ v.x = cubeScale * (geomData[i].x * rot[0].x + geomData[i].y * rot[0].y + geomData[i].z * rot[0].z);
+ v.y = cubeScale * (geomData[i].x * rot[1].x + geomData[i].y * rot[1].y + geomData[i].z * rot[1].z);
+ v.z = cubeScale * (geomData[i].x * rot[2].x + geomData[i].y * rot[2].y + geomData[i].z * rot[2].z);
+ geomUse[i].x = v.x;
+ geomUse[i].y = v.y;
+ geomUse[i].z = v.z;
+ }
+
+ // Rotate around middle of cube
+ geomUse[0].x = -(geomUse[1].x + geomUse[2].x + geomUse[3].x) / 2;
+ geomUse[0].y = -(geomUse[1].y + geomUse[2].y + geomUse[3].y) / 2;
+ geomUse[0].z = -(geomUse[1].z + geomUse[2].z + geomUse[3].z) / 2 + geomData[3].z / 2 + graphEnv->zpro + zoff;
+
+ /*for (i=0; i<4; i++)
+ {
+ cout << i << ": " << geomUse[i].x << ", " << geomUse[i].y << ", " << geomUse[i].z << endl;
+ }*/
+
+ fillBufferBackground(doValToCspace, cspaceOK, mddObj, &csmap, csInterv, baseType, doFullRangeCspace);
+
+ if ((texDesc->floatType != 0) && (csmap != NULL))
+ {
+ texDesc->minVal = csmap->getMinVal(); texDesc->maxVal = csmap->getMaxVal();
+ }
+
+ if (imode == rim_surf)
+ {
+ RenderCubeSurf(geomUse, graphEnv, texDesc);
+ }
+ else
+ {
+ if (initVoxParams)
+ {
+ if (csmap != NULL)
+ {
+ setup.pixelThresholdLow = csmap->getMinVal(); setup.pixelThresholdHigh = csmap->getMaxVal();
+ setup.weightThreshold = (setup.pixelThresholdHigh - setup.pixelThresholdLow) / 4;
+ setup.voxColour = csmap->getMaxVal();
+ if (setupWindow != NULL) setupWindow->updateSettings(setup);
+ }
+ initVoxParams = FALSE;
+ }
+
+ voxDesc->pixelThresholdLow = setup.pixelThresholdLow;
+ voxDesc->pixelThresholdHigh = setup.pixelThresholdHigh;
+ voxDesc->weightThreshold = setup.weightThreshold;
+ voxDesc->weightQuantisation = setup.weightQuantisation;
+ voxDesc->useRgbBrightness = setup.useRgbBrightness;
+ voxDesc->light.ambient = (setup.useLights) ? setup.lightsAmbient : -1.0;
+ voxDesc->light.gain = setup.lightsGain;
+ voxDesc->light.cosine = cos((M_PI * setup.lightsAngle) / 180);
+ voxDesc->light.scintCos = cos((M_PI * setup.lightsScintAngle) / 180);
+ getLightPos(&(voxDesc->light.lights));
+ voxDesc->kernSize = setup.kernelSize; voxDesc->kernType = setup.kernelType;
+ if (setup.useVoxCol)
+ {
+ switch (baseType)
+ {
+ case rbt_float: voxColour.f = (float)setup.voxColour; break;
+ case rbt_double: voxColour.d = (double)setup.voxColour; break;
+ default: voxColour.l = (unsigned long)setup.voxColour; break;
+ }
+ voxDesc->voxColour = (void*)&voxColour;
+ }
+ else
+ {
+ voxDesc->voxColour = NULL;
+ }
+ ::wxBeginBusyCursor(wxHOURGLASS_CURSOR);
+ RenderCubeVoxel(geomUse, graphEnv, texDesc, voxDesc);
+ ::wxEndBusyCursor();
+ }
+
+ if (doValToCspace && cspaceOK)
+ {
+ translateBufferToCspace(baseType);
+ }
+}
+
+
+int rviewVolumeImage::saveView(FILE *fp)
+{
+ int status = rviewRenderImage::saveView(fp);
+
+ writeViewParam(fp, view_VolumeMode, (long)imode);
+ writeViewParam(fp, view_UseBBox, (long)doBoundingBox);
+
+ return status;
+}
+
+
+int rviewVolumeImage::readView(const char *key, const char *value)
+{
+ int status = rviewRenderImage::readView(key, value);
+
+ if (status == 0)
+ {
+ if (strcmp(key, view_VolumeMode) == 0)
+ {
+ imode = (rviewImageMode)atoi(value);
+ return 1;
+ }
+ else if (strcmp(key, view_UseBBox) == 0)
+ {
+ doBoundingBox = (bool)atoi(value);
+ return 1;
+ }
+ return 0;
+ }
+ return status;
+}
+
+
+void rviewVolumeImage::loadViewFinished(void)
+{
+ rviewRenderImage::loadViewFinished();
+
+ mBar->Check(MENU_IMAGE_MODE_SURF, (imode == rim_surf));
+ mBar->Check(MENU_IMAGE_MODE_VOXEL, (imode == rim_voxel));
+ lastMode = imode;
+
+ boundingBox->SetValue(doBoundingBox);
+
+ // if we're in voxel mode, the parameters loaded are OK, don't overwrite them in fillBuffer()!
+ if (imode == rim_voxel)
+ initVoxParams = FALSE;
+}
+
+
+
+/*
+ * Height field rendered images members
+ */
+rviewHeightImage::rviewHeightImage(mdd_frame *mf, unsigned int flags) : rviewRenderImage(mf, 0, flags)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewHeightImage", "rviewHeightImage()" );
+
+ // make destructor safe
+ mddDesc = NULL; meshDesc = NULL; mddDesc = NULL;
+
+ // create dummy MDD object
+ r_Minterval dummyInterv(2);
+ dummyInterv << r_Sinterval((r_Range)0, (r_Range)1) << r_Sinterval((r_Range)0, (r_Range)1);
+ dummyMDD = (r_Ref<r_GMarray>)(new r_Marray<r_Char>(dummyInterv));
+
+ meshDesc = new mesh_desc; memset(meshDesc, 0, sizeof(mesh_desc));
+ mddDesc = new mdd_desc;
+ mddDesc->numDims = dimMDD;
+ mddDesc->dims = new int[dimMDD];
+ mddDesc->widths = new int[dimMDD];
+ mddDesc->floatType = ((baseType == rbt_float) || (baseType == rbt_double)) ? 1 : 0;
+}
+
+
+rviewHeightImage::~rviewHeightImage(void)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewHeightImage", "~rviewHeightImage()" );
+
+ closeViewer();
+ dummyMDD.destroy();
+ if (meshDesc != NULL)
+ {
+ RenderHeightFreeMesh(meshDesc); delete meshDesc;
+ }
+ if (mddDesc != NULL)
+ {
+ delete [] mddDesc->dims;
+ delete [] mddDesc->widths;
+ delete mddDesc;
+ }
+}
+
+
+int rviewHeightImage::openViewer(void)
+{
+ if (dimMDD < 2)
+ {
+ rviewErrorbox::reportError(lman->lookup("errorModeDim"), rviewHeightImage::getFrameName(), "openViewer");
+ objectInitializedOK = FALSE;
+ return -1;
+ }
+ if (baseType == rbt_rgb)
+ {
+ rviewErrorbox::reportError(lman->lookup("errorModeBase"), rviewHeightImage::getFrameName(), "openViewer");
+ objectInitializedOK = FALSE;
+ return -1;
+ }
+
+ if (rviewRenderImage::openViewer() == 0)
+ {
+ openViewerEpilogue(rviewHeightImage::getFrameType());
+ return 0;
+ }
+ return -1;
+}
+
+
+const char *rviewHeightImage::getFrameName(void) const
+{
+ return "rviewHeightImage";
+}
+
+rviewFrameType rviewHeightImage::getFrameType(void) const
+{
+ return rviewFrameTypeHghtImage;
+}
+
+int rviewHeightImage::getViewerType(void) const
+{
+ return RVIEW_RESDISP_IMGHGHT;
+}
+
+
+bool rviewHeightImage::cspaceRangeHook(bool suggest)
+{
+ return FALSE;
+}
+
+
+bool rviewHeightImage::modeNeedsCspace(rviewBaseType bt) const
+{
+ return FALSE;
+}
+
+
+int rviewHeightImage::newProjection(void)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewHeightImage", "newProjection()" );
+
+ char *data, *lastData = imgData;
+
+ meshDesc->srcData = NULL;
+ if ((data = setupGraphEnv()) == NULL) return -1;
+ fillBuffer();
+
+ updatePixmap(lastData, data);
+
+ return 0;
+}
+
+
+bool rviewHeightImage::moviePossible(void) const
+{
+ return (dimMDD >= 3);
+}
+
+
+char *rviewHeightImage::movieNewFrame(void)
+{
+ char *data;
+
+ if ((data = setupGraphEnv()) != NULL)
+ fillBuffer();
+ return data;
+}
+
+
+bool rviewHeightImage::doUpdate(int flags)
+{
+ if ((flags & RVIEW_IFLAG_LIGHT) != 0) return TRUE;
+ if ((flags & RVIEW_IFLAG_HEIGHT) != 0) return TRUE;
+ return FALSE;
+}
+
+
+void rviewHeightImage::redrawSettingsChanged(void)
+{
+ if (depthForHeightfield() != pixDepth)
+ {
+ char *data = NULL, *lastData = imgData;
+ data = setupGraphEnv();
+ fillBuffer();
+ updatePixmap(lastData, data);
+ }
+ else
+ rviewRenderImage::redrawSettingsChanged();
+}
+
+
+void rviewHeightImage::label(void)
+{
+ setDisplayTitle(lman->lookup("titleImageHeight"));
+ rviewRenderImage::label();
+}
+
+
+int rviewHeightImage::process(wxObject &obj, wxEvent &evt)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewHeightImage", "process()" );
+
+ int type = evt.GetEventType();
+
+ if (type == wxEVENT_TYPE_BUTTON_COMMAND)
+ {
+ if (&obj == (wxObject*)playStop)
+ playDirection = 0;
+ // do not intercept the call (return 1), however, because the renderer
+ // might also rotate the object, which'll be handled on rviewRenderImage
+ // level.
+ }
+
+ return rviewRenderImage::process(obj, evt);
+}
+
+
+void rviewHeightImage::prepareToDie(void)
+{
+ playDirection = 0;
+ rviewRenderImage::prepareToDie();
+}
+
+
+int rviewHeightImage::requestQuit(int level)
+{
+ playDirection = 0;
+ return rviewRenderImage::requestQuit(level);
+}
+
+
+char *rviewHeightImage::initMode(void)
+{
+ int i;
+ char *b;
+
+ RMDBGONCE(3, RMDebug::module_applications, "rviewHeightImage", "initMode()" );
+
+ b = projString;
+ b += sprintf(b, "*:*, *:*");
+ for (i=2; i<dimMDD; i++)
+ {
+ b += sprintf(b, ", %ld", interv[i].low());
+ }
+
+ project->SetValue(projString);
+ setModeDimension(2);
+
+ for (i=0; i<dimMDD; i++)
+ {
+ mddDesc->dims[i] = interv[i].high() - interv[i].low() + 1;
+ mddDesc->widths[i] = mddDesc->dims[i];
+ }
+ mddDesc->baseSize = baseSize;
+
+ return rviewRenderImage::initMode();
+}
+
+
+int rviewHeightImage::depthForHeightfield(void) const
+{
+ return (setup.voxColour >= 256) ? 24 : 8;
+}
+
+
+char *rviewHeightImage::setupEnvironment(int w, int h)
+{
+ int i, needDepth, newPitch, newPad, offset, newVirtPitch;
+
+ RMDBGONCE(3, RMDebug::module_applications, "rviewHeightImage", "setupEnvironment()" );
+
+ needDepth = depthForHeightfield();
+ newPad = 32; newPitch = (w * (needDepth >> 3) + 3) & ~3;
+ newVirtPitch = newPitch;
+
+ if ((doValToCspace) && (needDepth == 8))
+ {
+ setCspaceProjMode(FALSE);
+ rviewCheckInitCspace(rbt_char, &csmap, dummyMDD, TRUE, csInterv, w, &newPitch, &needDepth, &newPad, &newVirtPitch, cspar);
+ if (csmap != NULL)
+ {
+ mBar->Enable(MENU_IMAGE_CSPACE_EDIT, TRUE);
+ }
+ deleteViewCspace();
+ }
+
+ if ((w != pixWidth) || (h != pixHeight) || (pixPad != newPad) || (pixDepth != needDepth) || (newPitch != pixPitch) || (newVirtPitch != virtualPitch))
+ {
+ pixWidth = w; pixHeight = h; pixDepth = needDepth;
+ pixPitch = newPitch; pixPad = newPad; virtualPitch = newVirtPitch;
+ if ((imgData = (char*)malloc(virtualPitch * pixHeight)) == NULL)
+ {
+ rviewErrorbox::reportError(lman->lookup("errorMemory"), rviewHeightImage::getFrameName(), "setupEnvironment");
+ return NULL;
+ }
+ }
+ graphEnv->lineadd = virtualPitch;
+
+ for (i=0; i<dimMDD; i++)
+ {
+ mddDesc->widths[i] = pt2[i] - pt1[i] + 1;
+ }
+
+ r_Ref<r_Marray<r_Char> > tempMdd = (r_Ref<r_Marray<r_Char> >) mddObj;
+ r_Point paux(dimMDD);
+ for (i=0; i<dimMDD; i++)
+ {
+ paux[i] = interv[i].low();
+ }
+
+ offset = ((int)(&((*tempMdd)[pt1]) - &((*tempMdd)[paux]))) * baseSize;
+
+ mddDesc->data = (void*)((char*)(tempMdd->get_array()) + offset);
+
+ return imgData;
+}
+
+
+void rviewHeightImage::fillBackgroundCore(rviewBaseType bt, double minVal)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewHeightImage", "fillBackgroundCore()" );
+
+ memset(graphEnv->dest, 0, pixPitch * pixHeight);
+}
+
+
+void rviewHeightImage::fillBuffer(void)
+{
+ real_t gridScale, scaleHeight;
+ light_desc light;
+ bool useCspace, cspaceOK;
+
+ RMDBGONCE(3, RMDebug::module_applications, "rviewHeightImage", "fillBuffer()" );
+
+ gridScale = cubeScale * setup.gridSize; scaleHeight = cubeScale * setup.scaleHeight;
+ graphEnv->zpro = setup.zpro; graphEnv->clipz = setup.clipz;
+ memcpy(geomUse+1, rot, 3*sizeof(vertex_fp));
+
+ // Calculate the coordinates of the center point of the base diagonal for
+ // centering the rotation
+ int dimx, dimz;
+
+ if (RenderHeightGetDomain(mddDesc, &dimx, &dimz, NULL, NULL) != 0) return;
+
+ geomUse[0].x = -0.5 * gridScale * (dimx * rot[0].x + dimz * rot[0].z);
+ geomUse[0].y = 0.0;
+ geomUse[0].z = -0.5 * gridScale * (dimx * rot[2].x + dimz * rot[2].z) + graphEnv->zpro + zoff;
+
+ useCspace = doValToCspace;
+
+ light.ambient = (setup.useLights) ? setup.lightsAmbient : -1.0;
+ light.gain = setup.lightsGain;
+ light.cosine = cos((M_PI * setup.lightsAngle) / 180);
+ light.scintCos = cos((M_PI * setup.lightsScintAngle) / 180);
+ getLightPos(&(light.lights));
+ meshDesc->scaleGrid = gridScale; meshDesc->scaleHeight = scaleHeight;
+ meshDesc->colour = (unsigned int)(setup.voxColour);
+ if (meshDesc->colour >= 256)
+ {
+ meshDesc->colour |= 0xff000000; // mark as RGB
+ useCspace = FALSE;
+ }
+
+ // Colourspace mapping in the height renderer always means a source type of
+ // 8bpp. Besides there's no correlation between the rendered colours and the
+ // MDD values, therefore the colourspace is always set to [0,255] here.
+ double useMinVal = 0;
+ fillBufferBackground(useCspace, cspaceOK, dummyMDD, &csmap, csInterv, rbt_char, true, &useMinVal);
+
+ ::wxBeginBusyCursor(wxHOURGLASS_CURSOR);
+
+ RenderHeightField(meshDesc, geomUse, graphEnv, mddDesc, &light);
+
+ if (useCspace && cspaceOK)
+ {
+ double useMaxVal=255;
+ translateBufferToCspace(rbt_char, &useMinVal, &useMaxVal);
+ }
+
+ ::wxEndBusyCursor();
+}
+
+
+
+
+/*
+ * Prescaled image class
+ */
+
+const double rviewScaledImage::scaleStep = 2.0;
+
+const char *rviewScaledImage::view_CurrentBox = "currentBox";
+const char *rviewScaledImage::view_BoxScale = "boxScale";
+
+rviewScaledImage::rviewScaledImage(collection_desc *cd, r_Fast_Base_Scale *scaler, unsigned int flags) : rviewFlatBaseImage(cd->mddObjs, 0, flags)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewScaledImage", "rviewScaledImage()" );
+
+ int i;
+
+ scaleObject = scaler;
+ fullDomain = scaleObject->get_full_domain();
+
+ initialScale = scaler->get_last_scale();
+ thisView.scale = initialScale;
+ thisView.dim1 = 0; thisView.dim2 = 1;
+ thisView.low = r_Point(dimMDD);
+ thisView.high = r_Point(dimMDD);
+ for (i=0; i<dimMDD; i++)
+ {
+ thisView.low[i] = fullDomain[i].low();
+ thisView.high[i] = fullDomain[i].high();
+ }
+
+ dontLoad = TRUE;
+ loadedView = NULL;
+
+ collDesc = cd;
+}
+
+
+rviewScaledImage::~rviewScaledImage(void)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewScaledImage", "~rviewScaledImage()" );
+ closeViewer();
+ rviewDeleteCollection(collDesc);
+ // I own the scaler object!
+ delete scaleObject;
+ if (loadedView != NULL)
+ delete loadedView;
+}
+
+
+int rviewScaledImage::openViewer(void)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewScaledImage", "openViewer()" );
+
+ if (rviewFlatBaseImage::openViewer() == 0)
+ {
+ zoomInBut = new rviewButton(ctrlPanel);
+ zoomOutBut = new rviewButton(ctrlPanel);
+ lastZoomBut = new rviewButton(ctrlPanel);
+ zoomBoxBut = new rviewButton(ctrlPanel);
+ scaleString = new rviewText(ctrlPanel, thisView.scale);
+
+ lastZoomBut->Enable((viewHistory.getNumber() != 0));
+ boxState = pcanv->HasDragBox();
+ zoomBoxBut->Enable(boxState);
+
+ mBar->Enable(MENU_DISP_DATA_INSERT, FALSE);
+ mBar->Enable(MENU_DISP_DATA_INSERTPRO, FALSE);
+
+ openViewerEpilogue(rviewScaledImage::getFrameType());
+
+ dontLoad = FALSE;
+
+ return 0;
+ }
+ return -1;
+}
+
+
+void rviewScaledImage::label(void)
+{
+ if (initPhaseFinished)
+ {
+ setDisplayTitle(lman->lookup("titleImageScaled"));
+ scaleString->SetLabel(lman->lookup("textScaleFactor"));
+ zoomBoxBut->SetLabel(lman->lookup("textZoomBox"));
+ lastZoomBut->SetLabel(lman->lookup("textLastZoom"));
+ zoomInBut->SetLabel(lman->lookup("textZoomIn"));
+ zoomOutBut->SetLabel(lman->lookup("textZoomOut"));
+ }
+ rviewFlatBaseImage::label();
+}
+
+
+void rviewScaledImage::OnSize(int w, int h)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewScaledImage", "OnSize()");
+
+ if (initPhaseFinished)
+ {
+ int x, y, step, posx, posy;
+
+ GetClientSize(&x, &y);
+
+ if(x < 6*image_bwidth)
+ {
+ x= 6*image_bwidth;
+ frameWidth=x;
+ frameHeight=y;
+ SetClientSize(x, y);
+ return;
+ }
+
+ x -= 2*display_border;
+ scaleString->SetSize(display_border, image_totaly - image_theight, image_twidth, image_theight);
+ step = (x - image_twidth - 4*image_bwidth) / 4;
+ posx = image_twidth + display_border + step/2;
+ posy = image_totaly - image_bheight;
+ zoomBoxBut->SetSize(posx, posy, image_bwidth, image_bheight);
+ posx += step + image_bwidth;
+ lastZoomBut->SetSize(posx, posy, image_bwidth, image_bheight);
+ posx += step + image_bwidth;
+ zoomInBut->SetSize(posx, posy, image_bwidth, image_bheight);
+ posx += step + image_bwidth;
+ zoomOutBut->SetSize(posx, posy, image_bwidth, image_bheight);
+ }
+
+ rviewFlatBaseImage::OnSize(w, h);
+
+ if (initPhaseFinished)
+ {
+ int w, h, vw, vh;
+
+ pcanv->GetClientSize(&w, &h);
+ pcanv->SetAspectRatio(((double)h) / w);
+ w = (int)(w / thisView.scale); h = (int)(h / thisView.scale);
+ vw = (int)(thisView.high[thisView.dim1] - thisView.low[thisView.dim1]);
+ vh = (int)(thisView.high[thisView.dim2] - thisView.low[thisView.dim2]);
+ if ((vw < w) || (vh < h))
+ {
+ if (vw < w)
+ thisView.high[thisView.dim1] = (r_Range)(thisView.low[thisView.dim1] + w);
+ if (vh < h)
+ thisView.high[thisView.dim2] = (r_Range)(thisView.low[thisView.dim2] + h);
+
+ newView();
+ }
+ }
+}
+
+
+double rviewScaledImage::getLastScale(void) const
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewScaledImage", "getLastScale()");
+ view_desc_t lastView;
+
+ if (viewHistory.peek(lastView) == 0)
+ return lastView.scale;
+ else
+ return initialScale;
+}
+
+
+void rviewScaledImage::scaleViewBy(double scale)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewScaledImage", "scaleViewBy()");
+
+ thisView.high[thisView.dim1] = thisView.low[thisView.dim1]
+ + (r_Range)((thisView.high[thisView.dim1] - thisView.low[thisView.dim1]) / scale);
+ thisView.high[thisView.dim2] = thisView.low[thisView.dim2]
+ + (r_Range)((thisView.high[thisView.dim2] - thisView.low[thisView.dim2]) / scale);
+ thisView.scale *= scale;
+
+ // If we magnify, check whether we can increase the view box
+ if (scale > 1.0)
+ {
+ int w, h;
+
+ pcanv->GetClientSize(&w, &h);
+ w = (int)(w / thisView.scale); h = (int)(h / thisView.scale);
+ // extend the viewbox to the maximum size of the canvas
+ if (thisView.high[thisView.dim1] - thisView.low[thisView.dim1] < w)
+ thisView.high[thisView.dim1] = (r_Range)(thisView.low[thisView.dim1] + w);
+ if (thisView.high[thisView.dim2] - thisView.low[thisView.dim2] < h)
+ thisView.high[thisView.dim2] = (r_Range)(thisView.low[thisView.dim2] + h);
+ // no clipping necessary here, will be done in newView()
+ }
+}
+
+
+int rviewScaledImage::process(wxObject &obj, wxEvent &evt)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewScaledImage", "process()");
+
+ int type = evt.GetEventType();
+
+ if (type == wxEVENT_TYPE_BUTTON_COMMAND)
+ {
+ if (&obj == (wxObject*)lastZoomBut)
+ {
+ if (viewHistory.pop(thisView) == 0)
+ {
+ newView();
+ }
+ if (viewHistory.getNumber() == 0)
+ lastZoomBut->Enable(FALSE);
+
+ return 1;
+ }
+ else if (&obj == (wxObject*)zoomInBut)
+ {
+ viewHistory.push(thisView);
+ lastZoomBut->Enable(TRUE);
+ scaleViewBy(scaleStep);
+ newView();
+ return 1;
+ }
+ else if (&obj == (wxObject*)zoomOutBut)
+ {
+ viewHistory.push(thisView);
+ lastZoomBut->Enable(TRUE);
+ scaleViewBy(1/scaleStep);
+ newView();
+ return 1;
+ }
+ else if (&obj == (wxObject*)zoomBoxBut)
+ {
+ if (pcanv->HasDragBox())
+ {
+ int x0, y0, x1, y1;
+ double relScale;
+
+ viewHistory.push(thisView);
+ lastZoomBut->Enable(TRUE);
+ pcanv->GetDragBox(x0, y0, x1, y1);
+ relScale = (thisView.high[thisView.dim1] - thisView.low[thisView.dim1]) / ((double)(pixmap->getWidth()));
+ thisView.high[thisView.dim1] = thisView.low[thisView.dim1] + (r_Range)(x1*relScale);
+ thisView.low[thisView.dim1] += (r_Range)(x0 * relScale);
+ thisView.high[thisView.dim2] = thisView.low[thisView.dim2] + (r_Range)(y1*relScale);
+ thisView.low[thisView.dim2] += (r_Range)(y0 * relScale);
+ thisView.scale *= ((double)(pixmap->getWidth())) / (x1 - x0);
+ newView();
+ }
+ return 1;
+ }
+ }
+ else if (type == wxEVENT_TYPE_TEXT_ENTER_COMMAND)
+ {
+ if (&obj == (wxObject*)scaleString)
+ {
+ double newScale = atof(scaleString->GetValue());
+ if (newScale != thisView.scale)
+ {
+ viewHistory.push(thisView);
+ lastZoomBut->Enable(TRUE);
+ scaleViewBy(newScale / thisView.scale);
+ newView();
+ }
+ return 1;
+ }
+ }
+
+ return rviewFlatBaseImage::process(obj, evt);
+}
+
+
+// Intercept the mouse event.
+void rviewScaledImage::processMouseEvent(wxMouseEvent &mevt)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewScaledImage", "processMouseEvent()");
+
+ int newbut = 0;
+ bool newBoxState;
+
+ if (mevt.leftDown) newbut |= MOUSE_LEFT;
+ if (mevt.middleDown) newbut |= MOUSE_MIDDLE;
+ if (mevt.rightDown) newbut |= MOUSE_RIGHT;
+
+ // Drag a box
+ if ((newbut & MOUSE_LEFT) != 0)
+ {
+ if ((mousebut & MOUSE_LEFT) == 0)
+ {
+ pcanv->SetDragBox(mevt.x, mevt.y, mevt.x, mevt.y);
+ }
+ else
+ {
+ pcanv->UpdateDragBox(mevt.x, mevt.y);
+ }
+ }
+ else if ((newbut & MOUSE_RIGHT) != 0)
+ {
+ if ((mousebut & MOUSE_RIGHT) == 0)
+ {
+ pcanv->AdjustDragBox(mevt.x, mevt.y);
+ }
+ else
+ {
+ pcanv->UpdateDragBox(mevt.x, mevt.y);
+ }
+ }
+ mousebut = newbut;
+ mousex = mevt.x; mousey = mevt.y;
+
+ newBoxState = pcanv->HasDragBox();
+ if (newBoxState != boxState)
+ {
+ zoomBoxBut->Enable(newBoxState);
+ boxState = newBoxState;
+ }
+}
+
+
+const char *rviewScaledImage::getFrameName(void) const
+{
+ return "rviewPrescaledFrame";
+}
+
+
+rviewFrameType rviewScaledImage::getFrameType(void) const
+{
+ return rviewFrameTypeScaledImage;
+}
+
+
+int rviewScaledImage::getViewerType(void) const
+{
+ return RVIEW_RESDISP_IMGSCLD;
+}
+
+
+bool rviewScaledImage::showScaleSlider(void) const
+{
+ return FALSE;
+}
+
+
+void rviewScaledImage::projectionStringForView(void)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewScaledImage", "projectionStringView()");
+
+ int i;
+ char *b = projString;
+
+ for (i=0; i<thisView.dim1; i++)
+ {
+ b += sprintf(b, "%ld, ", thisView.low[i]);
+ }
+ b += sprintf(b, "%ld:%ld, ", thisView.low[i], thisView.high[i]);
+ i++;
+ for (; i<thisView.dim2; i++)
+ {
+ b += sprintf(b, "%ld, ", thisView.low[i]);
+ }
+ b += sprintf(b, "%ld:%ld, ", thisView.low[i], thisView.high[i]);
+ i++;
+ for (; i<dimMDD; i++)
+ {
+ b += sprintf(b, "%ld, ", thisView.low[i]);
+ }
+ if (b != projString)
+ b[-2] = '\0';
+}
+
+
+char *rviewScaledImage::initMode(void)
+{
+ return rviewFlatBaseImage::initMode();
+}
+
+
+const r_Minterval &rviewScaledImage::getVirtualDomain(void) const
+{
+
+ return fullDomain;
+}
+
+
+void rviewScaledImage::projectObjectHook(void)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewScaledImage", "projectObjectHook()");
+ int i, j;
+
+ for (i=0; i<(int)dimMDD; i++)
+ {
+ thisView.low[i] = pt1[i];
+ thisView.high[i] = pt2[i];
+ }
+ for (i=0, j=0; i<(int)dimMDD; i++)
+ {
+ if ((freeDims & (1<<i)) != 0)
+ {
+ if (j == 0)
+ {
+ thisView.dim1 = i; j++;
+ }
+ else
+ thisView.dim2 = i;
+ }
+ }
+
+ r_Minterval projFull(dimMDD);
+ r_Minterval projScaled;
+
+ for (i=0; i<dimMDD; i++)
+ {
+ // shift point into full domain's origin...
+ projFull << r_Sinterval(fullDomain[i].low(), fullDomain[i].low() + (pt2[i] - pt1[i]));
+ }
+ // now adapt the values to the actual MDD object
+ if (scaleObject->get_scaled_domain(projFull, projScaled, thisView.scale) != 0)
+ {
+ //cout << projFull << ", " << projScaled << ", " << interv << endl;
+ // for now just make sure we're not outside the range...
+ for (i=0; i<dimMDD; i++)
+ {
+ r_Range offset = pt1[i] - fullDomain[i].low();
+ pt1[i] = projScaled[i].low() + offset;
+ if (pt1[i] < interv[i].low()) pt1[i] = interv[i].low();
+ if (pt1[i] > interv[i].high()) pt1[i] = interv[i].high();
+ pt2[i] = projScaled[i].high() + offset;
+ if (pt2[i] < interv[i].low()) pt2[i] = interv[i].low();
+ if (pt2[i] > interv[i].high()) pt2[i] = interv[i].high();
+ }
+ //cout << "Translated " << pt1 << ", " << pt2 << endl;
+ }
+ else
+ {
+ rviewErrorbox::reportError(lman->lookup("errorScaledObjSize"));
+ }
+}
+
+
+char *rviewScaledImage::projectImage(void)
+{
+ return rviewFlatBaseImage::projectImage();
+}
+
+
+bool rviewScaledImage::compareViews(const view_desc_t &v1, const view_desc_t &v2)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewScaledImage", "compareViews()");
+ if ((v1.scale == v2.scale) && (v1.dim1 == v2.dim1) && (v1.dim2 == v2.dim2)
+ && (v1.low == v2.low) && (v1.high == v2.high))
+ return TRUE;
+
+ return FALSE;
+}
+
+
+int rviewScaledImage::newProjection(void)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewScaledImage", "newProjection()");
+ int status;
+ view_desc_t lastView = thisView;
+
+ if ((status = rviewFlatBaseImage::newProjection()) == 0)
+ {
+ if (!compareViews(thisView, lastView))
+ {
+ viewHistory.push(lastView);
+ lastZoomBut->Enable(TRUE);
+ }
+ }
+ return status;
+}
+
+
+void rviewScaledImage::newView(bool loadImage)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewScaledImage", "newView()");
+ int i;
+
+ // Remove drag boxes
+ pcanv->SetDragBox(-1, -1, -1, -1);
+ boxState = FALSE;
+ zoomBoxBut->Enable(boxState);
+
+ // Clip rectangle to actual domain. Ratio already ensured by canvas
+ for (i=0; i<(int)dimMDD; i++)
+ {
+ if (thisView.low[i] < fullDomain[i].low())
+ thisView.low[i] = fullDomain[i].low();
+ if (thisView.high[i] > fullDomain[i].high())
+ thisView.high[i] = fullDomain[i].high();
+ }
+
+ if (!dontLoad) // or loadImage?
+ {
+ r_Minterval orgIv(dimMDD);
+ r_Minterval scaledDom;
+ int i;
+
+ for (i=0; i<(int)dimMDD; i++)
+ {
+ orgIv << r_Sinterval(thisView.low[i], thisView.high[i]);
+ }
+
+ collDesc->mddObjs[0].mdd.destroy();
+
+ ::wxBeginBusyCursor(wxHOURGLASS_CURSOR);
+
+ collDesc->mddObjs[0].mdd = rviewDatabase::getScaledObject(scaleObject, orgIv, thisView.scale);
+
+ ::wxEndBusyCursor();
+
+ if (collDesc->mddObjs[0].mdd.is_null())
+ {
+ Close(TRUE); return;
+ }
+ mddObj = collDesc->mddObjs[0].mdd;
+ interv = mddObj->spatial_domain();
+ }
+
+ projectionStringForView();
+ project->SetValue(projString);
+ scaleString->SetValue(thisView.scale);
+ scaleValue = 100;
+
+ rviewFlatBaseImage::newProjection();
+}
+
+
+int rviewScaledImage::saveView(FILE *fp)
+{
+ int status = rviewFlatBaseImage::saveView(fp);
+
+ long *boxdesc = new long[2*dimMDD + 2];
+
+ boxdesc[0] = (long)(thisView.dim1);
+ boxdesc[1] = (long)(thisView.dim2);
+ for (unsigned int i=0; i<dimMDD; i++)
+ {
+ boxdesc[2+i] = (long)(thisView.low[i]);
+ boxdesc[2+i+dimMDD] = (long)(thisView.high[i]);
+ }
+ writeViewParam(fp, view_CurrentBox, 2*dimMDD + 2, boxdesc);
+ writeViewParam(fp, view_BoxScale, thisView.scale);
+
+ delete [] boxdesc;
+
+ return status;
+}
+
+
+int rviewScaledImage::readView(const char *key, const char *value)
+{
+ int status = rviewFlatBaseImage::readView(key, value);
+
+ if (status == 0)
+ {
+ if (strcmp(key, view_CurrentBox) == 0)
+ {
+ long *boxdesc = new long[2*dimMDD + 2];
+
+ if (readVector(value, 2*dimMDD + 2, boxdesc) == 0)
+ {
+ ensureLoadedView();
+
+ loadedView->dim1 = (int)(boxdesc[0]);
+ loadedView->dim2 = (int)(boxdesc[1]);
+ // why do I always forget these !*&@^$()&^ dim constructors...???
+ loadedView->low = r_Point(dimMDD);
+ loadedView->high = r_Point(dimMDD);
+ for (unsigned int i=0; i<dimMDD; i++)
+ {
+ loadedView->low[i] = (r_Range)(boxdesc[2+i]);
+ loadedView->high[i] = (r_Range)(boxdesc[2+i+dimMDD]);
+ }
+ }
+ delete [] boxdesc;
+ return 1;
+ }
+ else if (strcmp(key, view_BoxScale) == 0)
+ {
+ ensureLoadedView();
+ loadedView->scale = atof(value);
+ return 1;
+ }
+ return 0;
+ }
+ return status;
+}
+
+
+void rviewScaledImage::loadViewFinished(void)
+{
+ rviewFlatBaseImage::loadViewFinished();
+
+ viewHistory.push(thisView);
+ lastZoomBut->Enable(TRUE);
+
+ thisView.scale = loadedView->scale;
+ thisView.low = loadedView->low;
+ thisView.high = loadedView->high;
+ thisView.dim1 = loadedView->dim1;
+ thisView.dim2 = loadedView->dim2;
+
+ delete loadedView;
+ loadedView = NULL;
+
+ newView(TRUE);
+}
+
+
+void rviewScaledImage::ensureLoadedView(void)
+{
+ if (loadedView == NULL)
+ {
+ loadedView = new view_desc_t;
+ memset(loadedView, 0, sizeof(view_desc_t));
+ }
+}
+
+
+
+
+
+
+
+/*
+ * Functions performing the actual translation of MDD into a scaled
+ * image. Code shared between rviewFlatImage and rviewThumb.
+ */
+
+// Number of fractional fixpoint bits
+#define IMAGE_FIXPREC 16
+
+// A macro for recurring code in projectImage
+#define PROJECT_HEADER(type) \
+ if (penv.pt1[penv.dim1] == penv.pt2[penv.dim1]) stepx=0; \
+ else \
+ { \
+ prun[penv.dim1]=penv.pt1[penv.dim1]+1; \
+ prun[penv.dim2]=penv.pt1[penv.dim2]; \
+ stepx = &((*mddPtr)[prun]) - &((*mddPtr)[penv.pt1]); \
+ } \
+ if (penv.pt1[penv.dim2] == penv.pt2[penv.dim2]) stepy=0; \
+ else \
+ { \
+ prun[penv.dim1]=penv.pt1[penv.dim1]; \
+ prun[penv.dim2]=penv.pt1[penv.dim2]+1; \
+ stepy = &((*mddPtr)[prun]) - &((*mddPtr)[penv.pt1]); \
+ } \
+ scalestepx = stepx * (int)(1 / penv.scale); \
+ scalestepy = stepy * (int)(1 / penv.scale); \
+ fracstepx = ((int)((1<<IMAGE_FIXPREC) / penv.scale)) & ((1<<IMAGE_FIXPREC)-1); \
+ fracstepy = ((int)((1<<IMAGE_FIXPREC) / penv.scale)) & ((1<<IMAGE_FIXPREC)-1); \
+ imgLine = (type*)(&((*mddPtr)[penv.pt1]));
+
+#define PROJECT_IMAGE_INCREMENTX \
+ imgPtr += scalestepx; fracx += fracstepx; \
+ if (fracx >= (1<<IMAGE_FIXPREC)) \
+ { \
+ imgPtr += stepx; fracx &= ((1<<IMAGE_FIXPREC)-1); \
+ }
+
+#define PROJECT_IMAGE_INCREMENTY \
+ imgLine += scalestepy; fracy += fracstepy; \
+ if (fracy >= (1<<IMAGE_FIXPREC)) \
+ { \
+ imgLine += stepy; fracy &= ((1<<IMAGE_FIXPREC)-1); \
+ }
+
+// A macro for colourspace translators
+// Do not terminate this macro with a semicolon when using it!
+#define PROJECT_IMAGE_START(type) \
+ r_Marray<type> *mddPtr = (r_Marray<type>*) (penv.mddPtr); \
+ type *imgLine, *imgPtr; \
+ PROJECT_HEADER(type); \
+ for (h=0; h<penv.height; h++, destLine.c+=penv.pitch) \
+ { \
+ for (w=0, imgPtr=imgLine, destPtr.c=destLine.c, fracx=0; w<penv.width; w++)
+
+#define PROJECT_IMAGE_BASE(type) \
+ PROJECT_IMAGE_START(type) \
+ { \
+ PROJECT_IMAGE_TRANSFER_PIXEL(type); \
+ PROJECT_IMAGE_INCREMENTX; \
+ } \
+ PROJECT_IMAGE_INCREMENTY; \
+ }
+
+#define PROJECT_COLOURSPACE32(type, minval, maxval, scale) \
+ if ((IntToRGBTab24 = penv.csmap->getCSTab24()) == NULL) \
+ { \
+ PROJECT_IMAGE_START(type) \
+ { \
+ *destPtr.l++ = penv.csmap->ValToCS24((double)(*imgPtr) - minVal); \
+ PROJECT_IMAGE_INCREMENTX; \
+ } \
+ PROJECT_IMAGE_INCREMENTY; \
+ } \
+ } \
+ else \
+ { \
+ PROJECT_IMAGE_START(type) \
+ { \
+ type value; \
+ value = *imgPtr; \
+ if (value > maxval) value = maxval; value -= minval; if (value < 0) value = 0;\
+ *destPtr.l++ = IntToRGBTab24[(unsigned long)(value * scale)]; \
+ PROJECT_IMAGE_INCREMENTX; \
+ } \
+ PROJECT_IMAGE_INCREMENTY; \
+ } \
+ }
+
+
+int rviewPrepareFlatProjection(rviewFlatProjEnv &penv)
+{
+ int baseSize = penv.mddPtr->get_type_length();
+
+ penv.width = (int)((penv.pt2[penv.dim1] - penv.pt1[penv.dim1] + 1) * penv.scale);
+ penv.height = (int)((penv.pt2[penv.dim2] - penv.pt1[penv.dim2] + 1) * penv.scale);
+
+ switch (rviewImageTypes[penv.bt])
+ {
+ case RVIEW_IMGTYPE_NONE:
+ {
+ if (penv.doCspace)
+ {
+ penv.pitch = penv.width * 4; penv.pad = 32; penv.depth = 32;
+ }
+ else
+ {
+ rviewErrorbox::reportError(lman->lookup("errorUnknownBase"), "rviewPrepareFlatProjection");
+ return -1;
+ }
+ }
+ break;
+ case RVIEW_IMGTYPE_MONO:
+ penv.pitch = (penv.width + 7) >> 3; penv.pad = 8; penv.depth = 1;
+ break;
+ case RVIEW_IMGTYPE_HIGH:
+ penv.pitch = (penv.width * 2 + 3) & ~3; penv.pad = 32; penv.depth = 15;
+ break;
+ case RVIEW_IMGTYPE_GREY12:
+ // unsigned short = 12bpp grey, gets transformed to 8bpp grey
+ penv.pitch = (penv.width + 3) & ~3; penv.pad = 32; penv.depth = 8;
+ break;
+ default:
+ penv.pitch = (penv.width * baseSize + 3) & ~3;
+ penv.pad = 32; penv.depth = 8*baseSize;
+ break;
+ }
+
+#ifdef wx_msw
+ if (penv.bt == rbt_rgb)
+ {
+ penv.pitch = (penv.width * baseSize); penv.pad = 8;
+ }
+#endif
+
+ return 0;
+}
+
+
+int rviewPerformFlatProjection(rviewFlatProjEnv &penv, char *data)
+{
+ int stepx, stepy, scalestepx, scalestepy;
+ int fracstepx, fracstepy, fracx, fracy;
+ union {char *c; short *s; RGBPixel *r; long *l;} destPtr, destLine;
+ r_Point prun;
+ int w, h;
+
+ destLine.c = data;
+ prun = penv.pt1;
+ fracy = 0;
+
+ // Do a colourspace mapping?
+ if (penv.cspaceState != 0)
+ {
+ double minVal, maxVal;
+ long minValL, maxValL;
+ double scalingFactor;
+ unsigned short *IntToRGBTab15;
+ unsigned long *IntToRGBTab24;
+
+ minVal = penv.csmap->getMinVal(); minValL = (long)minVal;
+ maxVal = penv.csmap->getMaxVal(); maxValL = (long)maxVal;
+ scalingFactor = penv.csmap->getScalingFactor();
+
+ IntToRGBTab15 = penv.csmap->getCSTab15();
+
+ switch (penv.bt)
+ {
+#define PROJECT_IMAGE_TRANSFER_PIXEL(type) long value = (long)(*imgPtr); if (value > maxValL) value = maxValL; value -= minValL; if (value < 0) value = 0; *destPtr.s++ = IntToRGBTab15[value]
+ case rbt_char:
+ {
+ PROJECT_IMAGE_BASE(r_Char);
+ }
+ break;
+ case rbt_uchar:
+ {
+ PROJECT_IMAGE_BASE(r_Octet);
+ }
+ break;
+ case rbt_short:
+ {
+ PROJECT_IMAGE_BASE(r_Short);
+ }
+ break;
+ case rbt_ushort:
+ {
+ PROJECT_IMAGE_BASE(r_UShort);
+ }
+ break;
+ case rbt_long:
+ {
+ PROJECT_COLOURSPACE32(r_Long, minValL, maxValL, 1);
+ }
+ break;
+ case rbt_ulong:
+ {
+ PROJECT_COLOURSPACE32(r_ULong, (r_ULong)minValL, (r_ULong)maxValL, 1);
+ }
+ break;
+ case rbt_float:
+ {
+ PROJECT_COLOURSPACE32(r_Float, minVal, maxVal, scalingFactor);
+ }
+ break;
+ case rbt_double:
+ {
+ PROJECT_COLOURSPACE32(r_Double, minVal, maxVal, scalingFactor);
+ }
+ break;
+ default:
+ {
+ rviewErrorbox::reportError(lman->lookup("errorBaseType"), "rviewPerformFlatProjectionCmap");
+ return -1;
+ }
+ break;
+ }
+ }
+ // No, use actual source data with no transformations.
+ else
+ {
+ switch (rviewImageTypes[penv.bt])
+ {
+ case RVIEW_IMGTYPE_MONO:
+ {
+ r_Marray<r_Boolean> *mddPtr = (r_Marray<r_Boolean> *)(penv.mddPtr);
+ r_Boolean *imgLine, *imgPtr;
+ char val;
+ int mask;
+
+ PROJECT_HEADER(r_Boolean);
+ for (h=0; h<penv.height; h++, destLine.c+=penv.pitch)
+ {
+#if (WX_PIXMAP_SRC_BITORDER == 0)
+ mask = 1;
+#else
+ mask = 0x80;
+#endif
+ val = 0;
+ for (w=0, imgPtr=imgLine, destPtr.c=destLine.c, fracx=0; w<penv.width; w++)
+ {
+ if (*imgPtr) val |= mask;
+#if (WX_PIXMAP_SRC_BITORDER == 0)
+ mask <<= 1; if (mask == 0x100) {*destPtr.c++ = val; val = 0; mask = 1;}
+#else
+ mask >>= 1; if (mask == 0) {*destPtr.c++ = val; val = 0; mask = 0x80;}
+#endif
+ PROJECT_IMAGE_INCREMENTX;
+ }
+#if (WX_PIXMAP_SRC_BITORDER == 0)
+ if (mask != 1)
+#else
+ if (mask != 0x80)
+#endif
+ *destPtr.c++ = val;
+ PROJECT_IMAGE_INCREMENTY;
+ }
+ }
+ break;
+
+#undef PROJECT_IMAGE_TRANSFER_PIXEL
+#define PROJECT_IMAGE_TRANSFER_PIXEL(type) *destPtr.c++ = *imgPtr
+ case RVIEW_IMGTYPE_GREY:
+ {
+ PROJECT_IMAGE_BASE(r_Char)
+ }
+ break;
+
+#undef PROJECT_IMAGE_TRANSFER_PIXEL
+#define PROJECT_IMAGE_TRANSFER_PIXEL(type) *destPtr.s++ = *imgPtr
+ case RVIEW_IMGTYPE_HIGH:
+ {
+ PROJECT_IMAGE_BASE(r_Short)
+ }
+ break;
+
+#undef PROJECT_IMAGE_TRANSFER_PIXEL
+#define PROJECT_IMAGE_TRANSFER_PIXEL(type) *destPtr.c++ = (char)((*imgPtr) >> 4)
+ case RVIEW_IMGTYPE_GREY12:
+ {
+ PROJECT_IMAGE_BASE(r_UShort)
+ }
+ break;
+
+#undef PROJECT_IMAGE_TRANSFER_PIXEL
+#define PROJECT_IMAGE_TRANSFER_PIXEL(type) *destPtr.l++ = *imgPtr
+ case RVIEW_IMGTYPE_TRUE32:
+ {
+ PROJECT_IMAGE_BASE(r_Long)
+ }
+ break;
+
+#undef PROJECT_IMAGE_TRANSFER_PIXEL
+#define PROJECT_IMAGE_TRANSFER_PIXEL(type) *destPtr.r++ = *imgPtr
+ case RVIEW_IMGTYPE_TRUE24:
+ {
+ PROJECT_IMAGE_BASE(RGBPixel)
+ }
+ break;
+
+ default:
+ {
+ rviewErrorbox::reportError(lman->lookup("errorBaseType"), "rviewPerformFlatProjection");
+ return -1;
+ }
+ break;
+ }
+ }
+
+ return 0;
+}
diff --git a/applications/rview/rviewMDD.cpp b/applications/rview/rviewMDD.cpp
new file mode 100644
index 0000000..4f175fc
--- /dev/null
+++ b/applications/rview/rviewMDD.cpp
@@ -0,0 +1,1006 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+ * PURPOSE:
+ *
+ * The rviewMDD module encapsulates various generic operations on
+ * MDD objects; it relies heavily on templates for this. All functions
+ * provided here are a) completely independent from the rest of rView
+ * and b) work on any kind of MDD, i.e. no restrictions whatsoever on
+ * dimensionality or base type. Most functions utilize
+ * mdd_objectFunctionType() for this which iterates over the MDD object
+ * basetype first and calls functions provided in the mdd_function_pointers
+ * structure which perform the required operation on each of the primitive
+ * basetypes.
+ *
+ * Functions provided are:
+ *
+ * - mdd_objectRange(): return the minimum and maximum cell values.
+ * - mdd_createSubcube(): creates a new MDD object by copying a subcube
+ * (or all of) a source MDD object; optionally persistent.
+ * - mdd_objectScaleInter(): creates new object by resampling (part of)
+ * the source object using n-linear interpolation. Use for upsampling.
+ * - mdd_objectScaleAverage(): creates new object by resampling (part of)
+ * the source object using averaging. Use for downsampling.
+ * - mdd_objectScaleSimple(): creates new object by scaling (part of)
+ * the source object using simple nearest neighbour. Fast but blocky.
+ * - mdd_objectChangeEndianness(): creates a new object where the
+ * endianness is inverted compared to the source object, or changes
+ * the object itself.
+ *
+ * COMMENTS:
+ * No comments
+ */
+
+
+
+// For early templates
+#ifndef _RVIEW_MDD_CPP_
+#define _RVIEW_MDD_CPP_
+
+
+
+#ifdef __GNUG__
+#pragma implementation
+#endif
+
+
+
+#include <limits.h>
+#include <float.h>
+#include <string.h>
+
+
+
+// Was this file included from rviewMDD.hh?
+#ifdef EARLY_TEMPLATE
+#ifndef __EXECUTABLE__
+#define __EXECUTABLE__
+#define _RVIEW_MDD_EXECUTABLE_
+#endif
+#endif
+
+#include "rasodmg/transaction.hh"
+#include "raslib/primitivetype.hh"
+#include "raslib/structuretype.hh"
+#include "raslib/endian.hh"
+#include "rasodmg/alignedtiling.hh"
+#include "rasodmg/storagelayout.hh"
+#include "rviewMDD.hh"
+#include "rviewTypes.hh"
+
+#ifdef _RVIEW_MDD_EXECUTABLE_
+#undef __EXECUTABLE__
+#endif
+
+
+
+
+#define MDD_FIXPREC 16
+
+
+
+
+
+// auxData interpreted as double[2] containing min, max, initialised externally
+template<class T>
+int objectRange_temp(T *dest, const T *src, const mdd_function_desc *mfd, int dim, int datastep, void *auxData)
+{
+ long *pos;
+ char *srcdata;
+ T **srcptr;
+ int i, j;
+ double min, max, val;
+
+ pos = new long[dim]; srcptr = new T *[dim];
+
+ srcdata = objectCalcStart((const char *)src, mfd, dim);
+
+ for (i=0; i<dim; i++)
+ {
+ pos[i] = mfd[i].useLow; srcptr[i] = (T*)srcdata;
+ }
+
+ min = ((double*)auxData)[0]; max = ((double*)auxData)[1];
+
+ do
+ {
+ val = (double)(*srcptr[dim-1]);
+ if (val < min) min = val;
+ if (val > max) max = val;
+ i = dim-1;
+ while (i >= 0)
+ {
+ pos[i]++; srcptr[i] = (T*)(((char*)(srcptr[i])) + mfd[i].srcoff);
+ if (pos[i] <= mfd[i].useHigh) break;
+ pos[i] = mfd[i].useLow; i--;
+ }
+ if (i >= 0)
+ {
+ for (j=i+1; j<dim; j++) srcptr[j] = srcptr[i];
+ }
+ }
+ while (i >= 0);
+
+ ((double*)auxData)[0] = min; ((double*)auxData)[1] = max;
+
+ delete [] srcptr; delete [] pos;
+
+ return 1;
+}
+
+
+// Additional template code for objectScaleInter template
+inline void objectScaleInterICore(double *srcf, double *destf, double pos, int idx1, int idx2)
+{
+ destf[idx1] = srcf[idx1] + pos * (srcf[idx2] - srcf[idx1]);
+}
+
+template<class T>
+int objectScaleInter_temp(T *dest, const T *src, const mdd_function_desc *mfd, int dim, int datastep, void *auxData)
+{
+ double *pos, *f, *fwork;
+ long *lastpos;
+ long *ipos;
+ long *dp;
+ char **srcptr;
+ char *srcbase;
+ long offset;
+ int i, j, k;
+ int slowOffset;
+ T *srcdata, *destdata;
+ long *cubeoff = (long*)auxData;
+
+ f = new double[(1<<dim)]; fwork = new double[(1<<dim)];
+ pos = new double[dim]; ipos = new long[dim]; lastpos = new long[dim]; srcptr = new char*[dim];
+ dp = new long[dim];
+
+ // Calculate the starting point
+ srcbase = objectCalcStart((const char*)src, mfd, dim);
+
+ for (i=0; i<dim; i++)
+ {
+ pos[i] = (double)(mfd[i].useLow); lastpos[i] = mfd[i].useLow;
+ srcptr[i] = srcbase; dp[i] = mfd[i].newLow;
+ }
+
+ destdata = dest;
+
+ // Main loop: iterate over all dimensions except for the last which is handled separately
+ // in its own loop for efficiency reasons.
+ do
+ {
+ pos[dim-1] = (double)(mfd[dim-1].useLow); dp[dim-1] = mfd[dim-1].newLow;
+
+ // slowOffset determines whether the fast table-lookup offset or the slower dimension looping
+ // offset calculation can be used. Table-lookup is always possible as long as the current
+ // position in the cube is not at the cube's boundary. In the innermost loop slowOffset only
+ // has to be updated, not recalculated, because there is only a (new) overflow possible in the
+ // innermost loop-dimension.
+ slowOffset = 0;
+ for (i=0; i<dim; i++)
+ {
+ ipos[i] = (long)(pos[i]);
+ // Check for high rather than useHigh because we only get problems if its > high.
+ if (ipos[i] >= mfd[i].high) {ipos[i] = mfd[i].useHigh; slowOffset = 1;}
+ }
+
+ srcbase = srcptr[dim-1];
+
+ if (slowOffset != 0)
+ {
+ for (i=0; i<(1<<dim); i++)
+ {
+ offset = 0;
+ for (j=0; j<dim; j++)
+ {
+ // Check against high, not useHigh (see above)
+ if (((i & (1<<j)) != 0) && (ipos[j] < mfd[j].high)) offset += mfd[j].srcoff;
+ }
+ srcdata = (T*)(srcbase + offset);
+ f[i] = (double)(*srcdata);
+ //if (srcdata+offset >= srchigh) cout << "Overflow1" << endl;
+ }
+ }
+ else
+ {
+ for (i=0; i<(1<<dim); i++)
+ {
+ srcdata = (T*)(srcbase + cubeoff[i]);
+ f[i] = (double)(*srcdata);
+ }
+ }
+
+ lastpos[dim-1] = (long)(pos[dim-1]);
+ // Innermost loop
+ for (k = mfd[dim-1].newHigh - mfd[dim-1].newLow + 1; k>0; k--)
+ {
+ // n-linear interpolation
+ for (j=0; j<(1<<dim); j+=2)
+ {
+ objectScaleInterICore(f, fwork, (double)(pos[0] - ipos[0]), j, j+1);
+ }
+ for (i=1; i<dim; i++)
+ {
+ for (j=0; j<(1<<dim); j+=(1<<(i+1)))
+ {
+ objectScaleInterICore(fwork, fwork, (double)(pos[i] - ipos[i]), j, j + (1<<i));
+ }
+ }
+ // We go in sequential order (highest coordinate first)
+ *destdata = (T)(fwork[0]);
+ destdata = (T*)(((char*)destdata) + datastep);
+
+ // end of innermost loop
+ pos[dim-1] += mfd[dim-1].step; offset = (long)(pos[dim-1]);
+ if (offset != lastpos[dim-1])
+ {
+ offset -= lastpos[dim-1]; lastpos[dim-1] = (long)(pos[dim-1]);
+ // Check against high, not useHigh
+ if (lastpos[dim-1] <= mfd[dim-1].high)
+ {
+ srcbase += offset*mfd[dim-1].srcoff; ipos[dim-1] = lastpos[dim-1];
+ }
+ // high, not useHigh
+ if (lastpos[dim-1] >= mfd[dim-1].high) slowOffset = 1;
+ offset = (1<<(dim-1));
+ memcpy(f, f + offset, offset*sizeof(double));
+
+ if (slowOffset != 0)
+ {
+ for (i=(1<<(dim-1)); i<(1<<dim); i++)
+ {
+ offset = 0;
+ for (j=0; j<dim-1; j++)
+ {
+ // high, not useHigh
+ if (((i & (1<<j)) != 0) && (ipos[j] < mfd[j].high)) offset += mfd[j].srcoff;
+ }
+ srcdata = (T*)(srcbase + offset);
+ f[i] = (double)(*srcdata);
+ //if (srcdata+offset >= srchigh) cout << "Overflow2" << endl;
+ }
+ }
+ else
+ {
+ for (i=(1<<(dim-1)); i<(1<<dim); i++)
+ {
+ srcdata = (T*)(srcbase + cubeoff[i - (1<<(dim-1))]);
+ f[i] = (double)(*srcdata);
+ }
+ }
+ }
+ }
+ i = dim-2;
+ while (i >= 0)
+ {
+ dp[i]++;
+ pos[i] += mfd[i].step; offset = (long)(pos[i]);
+ if (offset != lastpos[i])
+ {
+ offset -= lastpos[i]; lastpos[i] = (long)(pos[i]);
+ // high, not useHigh
+ if (lastpos[i] <= mfd[i].high)
+ {
+ srcptr[i] += offset*mfd[i].srcoff; ipos[i] = lastpos[i];
+ }
+ }
+ if (dp[i] <= mfd[i].newHigh) break;
+ dp[i] = mfd[i].newLow; pos[i] = (double)(mfd[i].useLow); lastpos[i] = mfd[i].useLow; i--;
+ }
+ if (i >= 0)
+ {
+ for (j=i+1; j<dim; j++) srcptr[j] = srcptr[i];
+ }
+ }
+ while (i >= 0);
+
+ delete [] pos; delete [] f; delete [] fwork;
+ delete [] ipos; delete [] lastpos; delete [] dp; delete [] srcptr;
+
+ return 1;
+}
+
+
+
+
+template<class T>
+int objectScaleAverage_temp(T *dest, const T *src, const mdd_function_desc *mfd, int dim, int datastep, void *aux)
+{
+ long *pos, *subpos, *dp;
+ T **srcptr, **subptr;
+ long lastpos, number;
+ double avg;
+ int i, j;
+ T *destdata;
+ char *srcdata;
+
+ pos = new long[dim]; subpos = new long[dim]; dp = new long[dim];
+ srcptr = new T*[dim]; subptr = new T*[dim];
+
+ srcdata = objectCalcStart((const char*)src, mfd, dim);
+
+ for (i=0; i<dim; i++)
+ {
+ pos[i] = (mfd[i].useLow << MDD_FIXPREC);
+ dp[i] = mfd[i].newLow; srcptr[i] = (T*)srcdata;
+ }
+
+ destdata = dest;
+ // Iterate over all cells in the destination object
+ do
+ {
+ //for (i=0; i<dim; i++) cout << (pos[i]>>MDD_FIXPREC) << ':' << (void*)(srcptr[i]) << ' '; cout << endl;
+ // start averaging over a subcube
+ avg = 0; number = 0;
+ // init subcube iteration
+ for (i=0; i<dim; i++)
+ {
+ subpos[i] = pos[i]; subptr[i] = srcptr[dim-1]; // no mistake!
+ }
+ do
+ {
+ avg += (double)(*(subptr[dim-1])); number++;
+ i = dim-1;
+ while (i >= 0)
+ {
+ subpos[i] += (1<<MDD_FIXPREC);
+ subptr[i] = (T*)(((char*)(subptr[i])) + mfd[i].srcoff);
+ if ((subpos[i] >> MDD_FIXPREC) < ((pos[i] + mfd[i].lstep) >> MDD_FIXPREC)) break;
+ subpos[i] = pos[i];
+ i--;
+ }
+ if (i >= 0)
+ {
+ for (j=i+1; j<dim; j++) subptr[j] = subptr[i];
+ }
+ }
+ while (i >= 0);
+
+ *destdata = (T)(avg/number);
+ destdata = (T*)(((char*)destdata) + datastep);
+
+ i = dim-1;
+ do
+ {
+ dp[i]++; lastpos = (pos[i] >> MDD_FIXPREC); pos[i] += mfd[i].lstep;
+ srcptr[i] = (T*)(((char*)(srcptr[i])) + ((pos[i] >> MDD_FIXPREC) - lastpos) * mfd[i].srcoff);
+ if (dp[i] <= mfd[i].newHigh) break;
+ dp[i] = mfd[i].newLow; pos[i] = (mfd[i].useLow << MDD_FIXPREC);
+ i--;
+ }
+ while (i >= 0);
+ if (i >= 0)
+ {
+ for (j=i+1; j<dim; j++) srcptr[j] = srcptr[i];
+ }
+ }
+ while (i >= 0);
+
+ delete [] subptr; delete [] srcptr;
+ delete [] dp; delete [] subpos; delete [] pos;
+
+ return 1;
+}
+
+
+
+template<class T>
+int objectScaleSimple_temp(T *dest, const T *src, const mdd_function_desc *mfd, int dim, int datastep, void *aux)
+{
+ long *pos, *dp;
+ long lastpos;
+ T **srcptr;
+ T *destdata;
+ char *srcdata;
+ int i, j;
+
+ pos = new long[dim]; dp = new long[dim]; srcptr = new T*[dim];
+
+ srcdata = objectCalcStart((const char*)src, mfd, dim);
+
+ for (i=0; i<dim; i++)
+ {
+ pos[i] = (mfd[i].useLow << MDD_FIXPREC); dp[i] = mfd[i].newLow;
+ srcptr[i] = (T*)srcdata;
+ }
+ destdata = dest;
+
+ do
+ {
+ *destdata = *(srcptr[dim-1]);
+ destdata = (T*)(((char*)destdata) + datastep);
+ i=dim-1;
+ while (i >= 0)
+ {
+ dp[i]++; lastpos = (pos[i] >> MDD_FIXPREC); pos[i] += mfd[i].lstep;
+ srcptr[i] = (T*)(((char*)srcptr[i]) + ((pos[i] >> MDD_FIXPREC) - lastpos)*mfd[i].srcoff);
+ if (dp[i] <= mfd[i].newHigh) break;
+ dp[i] = mfd[i].newLow; pos[i] = (mfd[i].useLow << MDD_FIXPREC);
+ i--;
+ }
+ if (i >= 0)
+ {
+ for (j=i+1; j<dim; j++) srcptr[j] = srcptr[i];
+ }
+ }
+ while (i >= 0);
+
+ delete [] srcptr; delete [] dp; delete [] pos;
+
+ return 1;
+}
+
+
+
+/* Must not compile non-template code when this file was just included */
+#ifndef __EXECUTABLE__
+
+// in raslib/odmgtypes.hh there are the following typedefs:
+// typedef unsigned char r_Boolean;
+// typedef unsigned char r_Char;
+// so the template instantiation is done twice for the same type. gcc 2.95.2 doesn't
+// like this.
+
+// Sadly, this is necessary with VisualC...
+#define DECLARE_MDD_FUNC(f) \
+// template int f<r_Boolean> MDD_FUNCTION_SIGNATURE(r_Boolean); \
+ template int f<r_Char> MDD_FUNCTION_SIGNATURE(r_Char); \
+ template int f<r_Octet> MDD_FUNCTION_SIGNATURE(r_Octet); \
+ template int f<r_Short> MDD_FUNCTION_SIGNATURE(r_Short); \
+ template int f<r_UShort> MDD_FUNCTION_SIGNATURE(r_UShort); \
+ template int f<r_Long> MDD_FUNCTION_SIGNATURE(r_Long); \
+ template int f<r_ULong> MDD_FUNCTION_SIGNATURE(r_ULong); \
+ template int f<r_Float> MDD_FUNCTION_SIGNATURE(r_Float); \
+ template int f<r_Double> MDD_FUNCTION_SIGNATURE(r_Double);
+
+DECLARE_MDD_FUNC(objectScaleInter_temp);
+DECLARE_MDD_FUNC(objectScaleAverage_temp);
+DECLARE_MDD_FUNC(objectScaleSimple_temp);
+DECLARE_MDD_FUNC(objectRange_temp);
+
+
+
+// Calculate the starting point in the source cube
+char *objectCalcStart(const char *src, const mdd_function_desc *mfd, int dim)
+{
+ int i;
+ char *d;
+
+ d = (char*)src;
+ for (i=0; i<dim; i++)
+ {
+ d += (mfd[i].useLow - mfd[i].low) * mfd[i].srcoff;
+ }
+ return d;
+}
+
+
+/*
+ * Wrapper functions for those templates
+ */
+
+#define CAST_MDDPTR(t, src) \
+ r_Ref<r_Marray<t> > mddPtr = (r_Ref<r_Marray<t> >)(src)
+
+
+int mdd_createSubcube(r_Ref<r_GMarray> srcMdd, r_Ref<r_GMarray> &newMdd, r_Minterval *domain, r_Database *db)
+{
+ r_Dimension dim;
+ char *destdata, *srcdata;
+ r_Ref<r_GMarray> newMddPtr;
+ r_Minterval interv;
+ r_Minterval newInterv;
+ int tpsize;
+ int i, j;
+ long length;
+ mdd_function_desc *mfd;
+ long *pos;
+ char **srcptr;
+
+ interv = srcMdd->spatial_domain(); dim = interv.dimension();
+
+ if (dim < 1) return 0;
+
+ tpsize = srcMdd->get_type_length();
+
+ newInterv = r_Minterval(dim);
+ for (i=0; i<(int)dim; i++)
+ {
+ if (domain == NULL)
+ {
+ newInterv << interv[i];
+ }
+ else
+ {
+ newInterv << (*domain)[i];
+ }
+ }
+
+ if ((destdata = mdd_objectFunctionInitMdd(srcMdd, newMddPtr, newInterv, tpsize, dim, db)) == NULL)
+ {
+ cerr << "Couldn't create new MDD object" << endl;
+ return 0;
+ }
+
+ mfd = mdd_objectFunctionInitData(interv, newInterv, newInterv, tpsize, MDD_OBJECT_INIT_NEWIV);
+
+ srcdata = objectCalcStart(srcMdd->get_array(), mfd, (int)dim);
+
+ pos = new long[dim]; srcptr = new char *[dim];
+
+ for (i=0; i<(int)dim; i++)
+ {
+ pos[i] = mfd[i].useLow; srcptr[i] = srcdata;
+ }
+
+ // Lenght of one strip of data to copy
+ length = (mfd[dim-1].useHigh - mfd[dim-1].useLow + 1) * tpsize;
+ do
+ {
+ memcpy(destdata, srcptr[dim-1], length);
+ destdata += length;
+ i = (int)dim-2;
+ while (i >= 0)
+ {
+ pos[i]++; srcptr[i] += mfd[i].srcoff;
+ if (pos[i] <= mfd[i].useHigh) break;
+ pos[i] = mfd[i].useLow; i--;
+ }
+ if (i >= 0)
+ {
+ for (j=i+1; j<(int)dim; j++) srcptr[j] = srcptr[i];
+ }
+ }
+ while (i >= 0);
+
+ delete [] srcptr; delete [] pos;
+ delete [] mfd;
+
+ newMdd = newMddPtr;
+
+ return 1;
+}
+
+
+
+// Support functions for (recursive) member-by-member resampling of a data cube via interpolation
+int mdd_objectFunctionPrim(const mdd_function_pointers *mfp, r_Primitive_Type *primType, const char *src, char *dest, const mdd_function_desc *mfd, int dim, int tpsize, void *auxData)
+{
+ switch (primType->type_id())
+ {
+ case r_Primitive_Type::BOOL:
+ if (mfp->mddf_bool != NULL)
+ mfp->mddf_bool((r_Boolean*)dest, (const r_Boolean *)src, mfd, dim, tpsize, auxData);
+ break;
+ case r_Primitive_Type::CHAR:
+ if (mfp->mddf_char != NULL)
+ mfp->mddf_char((r_Char*)dest, (const r_Char *)src, mfd, dim, tpsize, auxData);
+ break;
+ case r_Primitive_Type::OCTET:
+ if (mfp->mddf_octet != NULL)
+ mfp->mddf_octet((r_Octet *)dest, (const r_Octet*)src, mfd, dim, tpsize, auxData);
+ break;
+ case r_Primitive_Type::SHORT:
+ if (mfp->mddf_short != NULL)
+ mfp->mddf_short((r_Short *)dest, (const r_Short*)src, mfd, dim, tpsize, auxData);
+ break;
+ case r_Primitive_Type::USHORT:
+ if (mfp->mddf_ushort != NULL)
+ mfp->mddf_ushort((r_UShort *)dest, (const r_UShort*)src, mfd, dim, tpsize, auxData);
+ break;
+ case r_Primitive_Type::LONG:
+ if (mfp->mddf_long != NULL)
+ mfp->mddf_long((r_Long *)dest, (const r_Long*)src, mfd, dim, tpsize, auxData);
+ break;
+ case r_Primitive_Type::ULONG:
+ if (mfp->mddf_ulong != NULL)
+ mfp->mddf_ulong((r_ULong *)dest, (const r_ULong*)src, mfd, dim, tpsize, auxData);
+ break;
+ case r_Primitive_Type::FLOAT:
+ if (mfp->mddf_float != NULL)
+ mfp->mddf_float((r_Float *)dest, (const r_Float*)src, mfd, dim, tpsize, auxData);
+ break;
+ case r_Primitive_Type::DOUBLE:
+ if (mfp->mddf_double != NULL)
+ mfp->mddf_double((r_Double *)dest, (const r_Double*)src, mfd, dim, tpsize, auxData);
+ break;
+ default: return 0;
+ }
+ return 1;
+}
+
+
+// Support functions for (recursive) member-by-member resampling of a data cube via interpolation
+int mdd_objectFunctionStruct(const mdd_function_pointers *mfp, r_Structure_Type *structType, const char *src, char *dest, const mdd_function_desc *mfd, int dim, int tpsize, void *auxData)
+{
+ r_Type *newType;
+ unsigned long offset;
+ char *inc, *outc;
+
+ r_Structure_Type::attribute_iterator iter(structType->defines_attribute_begin());
+ while (iter != structType->defines_attribute_end())
+ {
+ newType = (*iter).type_of().clone();
+ offset = (*iter).offset();
+ inc = (char*)src + offset; outc = (char*)dest + offset;
+
+ if (newType->isStructType())
+ {
+ r_Structure_Type *newStructType = (r_Structure_Type*)newType;
+ mdd_objectFunctionStruct(mfp, newStructType, inc, outc, mfd, dim, tpsize, auxData);
+ }
+ else
+ {
+ r_Primitive_Type *newPrimType = (r_Primitive_Type*)newType;
+ mdd_objectFunctionPrim(mfp, newPrimType, inc, outc, mfd, dim, tpsize, auxData);
+ }
+ delete newType;
+ iter++;
+ }
+ return 1;
+}
+
+
+int mdd_objectFunctionType(const mdd_function_pointers *mfp, const r_Type *baseType, const char *src, char *dest, const mdd_function_desc *mfd, int dim, int tpsize, void *auxData)
+{
+ if (((r_Type*)baseType)->isStructType())
+ {
+ r_Structure_Type *structType = (r_Structure_Type*)baseType;
+ return mdd_objectFunctionStruct(mfp, structType, src, dest, mfd, dim, tpsize, auxData);
+ }
+ else
+ {
+ r_Primitive_Type *primType = (r_Primitive_Type*)baseType;
+ return mdd_objectFunctionPrim(mfp, primType, src, dest, mfd, dim, tpsize, auxData);
+ }
+}
+
+
+char *mdd_objectFunctionInitMdd(r_Ref<r_GMarray> mddPtr, r_Ref<r_GMarray> &newMddPtr, r_Minterval &newInterv, int tpsize, r_Dimension dim, r_Database *db)
+{
+ char *destdata;
+ const char *b;
+ r_Storage_Layout *store;
+
+ if (mddPtr->get_storage_layout() != NULL)
+ {
+ store = new r_Storage_Layout(*(mddPtr->get_storage_layout()));
+ }
+ else
+ {
+ r_Minterval tileInterv(dim);
+ r_Aligned_Tiling *dfltTiling;
+ int dim, i;
+
+ dim = newInterv.dimension();
+ for (i=0; i<dim; i++)
+ {
+ tileInterv << r_Sinterval((r_Range)0, (r_Range)256);
+ }
+ dfltTiling = new r_Aligned_Tiling(tileInterv, tpsize * tileInterv.cell_count());
+ store = new r_Storage_Layout(dfltTiling);
+ }
+
+ if (db == NULL)
+ {
+ newMddPtr = new r_GMarray(newInterv, tpsize, store);
+ }
+ else
+ {
+ newMddPtr = new (db) r_GMarray(newInterv, tpsize, store);
+ }
+
+ destdata = newMddPtr->get_array();
+ newMddPtr->set_current_format(mddPtr->get_current_format());
+ if ((b = mddPtr->get_type_name()) != NULL) newMddPtr->set_type_by_name(b);
+ if ((b = mddPtr->get_type_structure()) != NULL) newMddPtr->set_type_structure(b);
+
+ return destdata;
+}
+
+
+mdd_function_desc *mdd_objectFunctionInitData(r_Minterval &interv, r_Minterval &useInterv, r_Minterval &newInterv, int tpsize, unsigned int flags)
+{
+ int i, offset;
+ r_Dimension dim;
+ mdd_function_desc *mfd;
+
+ dim = interv.dimension();
+ mfd = new mdd_function_desc[dim];
+
+ // Calculate scaling factors
+ for (i=0; i<(int)dim; i++)
+ {
+ mfd[i].low = interv[i].low(); mfd[i].high = interv[i].high();
+ mfd[i].useLow = useInterv[i].low(); mfd[i].useHigh = useInterv[i].high();
+ if ((flags & MDD_OBJECT_INIT_NEWIV) != 0)
+ {
+ mfd[i].newLow = newInterv[i].low(); mfd[i].newHigh = newInterv[i].high();
+ if ((flags & MDD_OBJECT_INIT_FPSTEP) == MDD_OBJECT_INIT_FPSTEP)
+ {
+ // In order to avoid doubling right-boundary pixels we have to use (h-l), not (h-l+1)
+ // as nominator
+ mfd[i].step = ((double)(mfd[i].useHigh - mfd[i].useLow)) / (mfd[i].newHigh - mfd[i].newLow + 1);
+ }
+ else
+ {
+ double h = ((double)(mfd[i].useHigh - mfd[i].useLow + 1)) / (mfd[i].newHigh - mfd[i].newLow + 1);
+ mfd[i].lstep = (long)(h * (1<<MDD_FIXPREC));
+ }
+ }
+ }
+
+ offset = tpsize;
+ for (i=(int)dim-1; i>=0; i--)
+ {
+ mfd[i].srcoff = offset;
+ offset *= (mfd[i].high - mfd[i].low + 1);
+ }
+
+ return mfd;
+}
+
+
+
+int mdd_objectRange(r_Ref<r_GMarray> mddPtr, r_Minterval &useInterv, double &min, double &max)
+{
+ r_Dimension dim;
+ double minmax[2];
+ r_Ref<r_GMarray> newMddPtr; // Dummy...
+ r_Minterval newInterv; // Dummy...
+ r_Minterval interv;
+ const r_Type *baseType;
+ int tpsize;
+ mdd_function_desc *mfd;
+ mdd_function_pointers mfp;
+
+ interv = mddPtr->spatial_domain(); dim = interv.dimension();
+
+ if (dim < 1) return 0;
+
+ if ((baseType = mddPtr->get_base_type_schema()) == NULL)
+ {
+ cerr << "No schema information available!" << endl;
+ return 0;
+ }
+
+ tpsize = mddPtr->get_type_length();
+
+ MDD_INIT_FUNCTIONS(mfp, objectRange_temp);
+
+ mfd = mdd_objectFunctionInitData(interv, useInterv, newInterv, tpsize, 0);
+
+ minmax[0] = DBL_MAX; minmax[1] = -DBL_MAX; // these are unsigned!!!
+
+ mdd_objectFunctionType(&mfp, baseType, mddPtr->get_array(), NULL, mfd, (int)dim, tpsize, (void*)minmax);
+
+ min = minmax[0]; max = minmax[1];
+
+ delete [] mfd;
+
+ return 1;
+}
+
+
+
+// Scale an object using n-linear interpolation (recommended for magnification)
+int mdd_objectScaleInter(r_Ref<r_GMarray> mddPtr, r_Minterval &useInterv, r_Ref<r_GMarray> &newMdd, r_Minterval &newInterv)
+{
+ r_Dimension dim;
+ r_Minterval interv;
+ r_Ref<r_GMarray> newMddPtr;
+ mdd_function_desc *mfd;
+ int i, j;
+ long *cubeoff;
+ char *srcdata, *destdata;
+ int tpsize;
+ long offset;
+ const r_Type *baseType;
+ mdd_function_pointers mfp;
+
+ interv = mddPtr->spatial_domain();
+ dim = interv.dimension();
+ if ((dim < 1) || (dim != newInterv.dimension())) return 0;
+
+ // Type information available?
+ if ((baseType = mddPtr->get_base_type_schema()) == NULL)
+ {
+ cerr << "No schema information available!" << endl;
+ return 0;
+ }
+
+ tpsize = mddPtr->get_type_length();
+
+ if ((destdata = mdd_objectFunctionInitMdd(mddPtr, newMddPtr, newInterv, tpsize, dim)) == NULL)
+ return 0;
+
+ MDD_INIT_FUNCTIONS(mfp, objectScaleInter_temp);
+
+ // create temporary arrays
+ mfd = mdd_objectFunctionInitData(interv, useInterv, newInterv, tpsize, MDD_OBJECT_INIT_FPSTEP);
+ cubeoff = new long[(1<<dim)];
+
+ // Debugging
+ /*T *srchigh;
+ offset=1;
+ for (i=0; i<dim; i++) offset *= (interv[i].high() - interv[i].low() + 1);
+ srchigh = (T*)(mddPtr->get_array()) + offset;*/
+
+ srcdata = (char*)(mddPtr->get_array());
+
+ // Precalculate cube-offsets for more speed in inner loop
+ for (i=0; i<(1<<dim); i++)
+ {
+ offset = 0;
+ for (j=0; j<(int)dim; j++)
+ {
+ if ((i & (1<<j)) != 0) offset += mfd[j].srcoff;
+ }
+ cubeoff[i] = offset;
+ }
+
+ mdd_objectFunctionType(&mfp, baseType, srcdata, destdata, mfd, (int)dim, tpsize, (void*)cubeoff);
+
+ delete [] cubeoff; delete [] mfd;
+
+ newMdd = newMddPtr;
+
+ return 1;
+}
+
+
+// Scale an object by averaging cell values -- recommended for scaling down
+int mdd_objectScaleAverage(r_Ref<r_GMarray> mddPtr, r_Minterval &useInterv, r_Ref<r_GMarray> &newMdd, r_Minterval &newInterv)
+{
+ r_Dimension dim;
+ r_Minterval interv;
+ r_Ref<r_GMarray> newMddPtr;
+ mdd_function_desc *mfd;
+ char *srcdata, *destdata;
+ int tpsize;
+ const r_Type *baseType;
+ mdd_function_pointers mfp;
+
+ interv = mddPtr->spatial_domain();
+ dim = interv.dimension();
+
+ if ((dim < 1) || (dim != newInterv.dimension())) return 0;
+
+ if ((baseType = mddPtr->get_base_type_schema()) == NULL)
+ {
+ cerr << "No schema information available!" << endl;
+ return 0;
+ }
+
+ tpsize = mddPtr->get_type_length();
+
+ if ((destdata = mdd_objectFunctionInitMdd(mddPtr, newMddPtr, newInterv, tpsize, dim)) == NULL)
+ return 0;
+
+ MDD_INIT_FUNCTIONS(mfp, objectScaleAverage_temp);
+
+ mfd = mdd_objectFunctionInitData(interv, useInterv, newInterv, tpsize, MDD_OBJECT_INIT_NEWIV);
+
+ srcdata = mddPtr->get_array();
+
+ mdd_objectFunctionType(&mfp, baseType, srcdata, destdata, mfd, (int)dim, tpsize, NULL);
+
+ delete [] mfd;
+
+ newMdd = (r_Ref<r_GMarray>)newMddPtr;
+
+ return 1;
+}
+
+
+int mdd_objectScaleSimple(r_Ref<r_GMarray> mddPtr, r_Minterval &useInterv, r_Ref<r_GMarray> &newMdd, r_Minterval &newInterv)
+{
+ r_Dimension dim;
+ r_Minterval interv;
+ r_Ref<r_GMarray> newMddPtr;
+ mdd_function_desc *mfd;
+ char *srcdata, *destdata;
+ int tpsize;
+ const r_Type *baseType;
+ mdd_function_pointers mfp;
+
+ interv = mddPtr->spatial_domain();
+ dim = interv.dimension();
+
+ if ((dim < 1) || (dim != newInterv.dimension())) return 0;
+
+ if ((baseType = mddPtr->get_base_type_schema()) == NULL)
+ {
+ cerr << "No schema information available!" << endl;
+ return 0;
+ }
+
+ tpsize = mddPtr->get_type_length();
+
+ if ((destdata = mdd_objectFunctionInitMdd(mddPtr, newMddPtr, newInterv, tpsize, dim)) == NULL)
+ return 0;
+
+ MDD_INIT_FUNCTIONS(mfp, objectScaleSimple_temp);
+
+ mfd = mdd_objectFunctionInitData(interv, useInterv, newInterv, tpsize, MDD_OBJECT_INIT_NEWIV);
+
+ srcdata = mddPtr->get_array();
+
+ mdd_objectFunctionType(&mfp, baseType, srcdata, destdata, mfd, (int)dim, tpsize, NULL);
+
+ newMdd = (r_Ref<r_GMarray>)newMddPtr;
+
+ delete [] mfd;
+
+ return 1;
+}
+
+
+int mdd_objectChangeEndianness(r_Ref<r_GMarray> mddPtr, r_Minterval &useInterv, r_Ref<r_GMarray> *newMdd, r_Minterval *newInterv)
+{
+ char *srcdata;
+ const r_Base_Type *baseType;
+ r_Ref<r_GMarray> newMddPtr; // only used in "new" mode
+ r_Minterval dom, *iterDom;
+ int tpsize;
+
+ if ((baseType = (r_Base_Type*)(mddPtr->get_base_type_schema())) == NULL)
+ {
+ cerr << "No schema information available!" << endl;
+ return 0;
+ }
+
+ tpsize = mddPtr->get_type_length();
+
+ srcdata = mddPtr->get_array();
+
+ dom = mddPtr->spatial_domain();
+
+ if (newMdd == NULL)
+ {
+ r_Endian::swap_array( baseType, dom, dom, srcdata, srcdata );
+ }
+ else
+ {
+ void *destdata;
+ r_Dimension dim = dom.dimension();
+
+ if ((destdata = mdd_objectFunctionInitMdd(mddPtr, newMddPtr, *newInterv, tpsize, dim)) == NULL)
+ return 0;
+
+ r_Endian::swap_array( baseType, dom, *newInterv, *newInterv, *newInterv, srcdata, destdata );
+ }
+
+ if (newMdd != NULL)
+ {
+ *newMdd = newMddPtr;
+ }
+
+ return 1;
+}
+
+#endif
+
+#endif
diff --git a/applications/rview/rviewMDD.hh b/applications/rview/rviewMDD.hh
new file mode 100644
index 0000000..0248b35
--- /dev/null
+++ b/applications/rview/rviewMDD.hh
@@ -0,0 +1,185 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+ * PURPOSE:
+ *
+ * The rviewMDD module encapsulates various generic operations on
+ * MDD objects; it relies heavily on templates for this. All functions
+ * provided here are a) completely independent from the rest of rView
+ * and b) work on any kind of MDD, i.e. no restrictions whatsoever on
+ * dimensionality or base type. Most functions utilize
+ * mdd_objectFunctionType() for this which iterates over the MDD object
+ * basetype first and calls functions provided in the mdd_function_pointers
+ * structure which perform the required operation on each of the primitive
+ * basetypes.
+ *
+ * Functions provided are:
+ *
+ * - mdd_objectRange(): return the minimum and maximum cell values.
+ * - mdd_createSubcube(): creates a new MDD object by copying a subcube
+ * (or all of) a source MDD object; optionally persistent.
+ * - mdd_objectScaleInter(): creates new object by resampling (part of)
+ * the source object using n-linear interpolation. Use for upsampling.
+ * - mdd_objectScaleAverage(): creates new object by resampling (part of)
+ * the source object using averaging. Use for downsampling.
+ * - mdd_objectScaleSimple(): creates new object by scaling (part of)
+ * the source object using simple nearest neighbour. Fast but blocky.
+ * - mdd_objectChangeEndianness(): creates a new object where the
+ * endianness is inverted compared to the source object, or changes
+ * the object itself.
+ *
+ * COMMENTS:
+ * None
+ */
+
+
+
+#ifndef _RVIEW_MDD_H_
+#define _RVIEW_MDD_H_
+
+
+
+#ifdef __GNUG__
+#pragma interface
+#endif
+
+
+#include "rasodmg/ref.hh"
+#include "rasodmg/marray.hh"
+#include "rasodmg/gmarray.hh"
+#include "rasodmg/database.hh"
+#include "raslib/odmgtypes.hh"
+
+#include "raslib/primitivetype.hh"
+#include "raslib/structuretype.hh"
+
+
+
+
+
+/*
+ * Generic functionality on MDD objects -- data types and support functions
+ */
+
+// 1) Data types
+
+// A descriptor of the mdd iteration
+typedef struct mdd_function_desc {
+ double step;
+ long lstep;
+ long srcoff;
+ long low; // Entire domain of source cube
+ long high;
+ long useLow; // Domain that should be used, must be wholly contained in source cube
+ long useHigh;
+ long newLow; // Domain of resulting cube
+ long newHigh;
+} mdd_function_desc;
+
+
+
+// The signature of a basic mdd function
+// Important note: VISUAL C needs the variable pointers first, followed by the
+// constant pointers, or the variable pointers will be interpreted as constant
+// ones too. No joke.
+#define MDD_FUNCTION_SIGNATURE(type) \
+ (type *dest, const type *src, const mdd_function_desc *mfd, int dim, int datastep, void *auxData)
+
+typedef int (*mdd_func_bool)MDD_FUNCTION_SIGNATURE(r_Boolean);
+typedef int (*mdd_func_char)MDD_FUNCTION_SIGNATURE(r_Char);
+typedef int (*mdd_func_octet)MDD_FUNCTION_SIGNATURE(r_Octet);
+typedef int (*mdd_func_short)MDD_FUNCTION_SIGNATURE(r_Short);
+typedef int (*mdd_func_ushort)MDD_FUNCTION_SIGNATURE(r_UShort);
+typedef int (*mdd_func_long)MDD_FUNCTION_SIGNATURE(r_Long);
+typedef int (*mdd_func_ulong)MDD_FUNCTION_SIGNATURE(r_ULong);
+typedef int (*mdd_func_float)MDD_FUNCTION_SIGNATURE(r_Float);
+typedef int (*mdd_func_double)MDD_FUNCTION_SIGNATURE(r_Double);
+
+// A structure of mdd functions for all atomic base types
+typedef struct mdd_function_pointers {
+ mdd_func_bool mddf_bool;
+ mdd_func_char mddf_char;
+ mdd_func_octet mddf_octet;
+ mdd_func_short mddf_short;
+ mdd_func_ushort mddf_ushort;
+ mdd_func_long mddf_long;
+ mdd_func_ulong mddf_ulong;
+ mdd_func_float mddf_float;
+ mdd_func_double mddf_double;
+} mdd_function_pointers;
+
+// Init a mdd_function_pointers structure with a mdd function template (therefore the
+// same function name for all members)
+#define MDD_INIT_FUNCTIONS(mfp, tf) \
+ mfp.mddf_bool = (mdd_func_bool)tf; \
+ mfp.mddf_char = (mdd_func_char)tf; \
+ mfp.mddf_octet = (mdd_func_octet)tf; \
+ mfp.mddf_short = (mdd_func_short)tf; \
+ mfp.mddf_ushort = (mdd_func_ushort)tf; \
+ mfp.mddf_long = (mdd_func_long)tf; \
+ mfp.mddf_ulong = (mdd_func_ulong)tf; \
+ mfp.mddf_float = (mdd_func_float)tf; \
+ mfp.mddf_double = (mdd_func_double)tf;
+
+
+
+// 2) Support functions
+extern char *objectCalcStart(const char *src, const mdd_function_desc *mfd, int dim);
+
+// execute mdd functions over arbitrary objects
+extern int mdd_objectFunctionPrim(const mdd_function_pointers *mfp, r_Primitive_Type *primType, const char *src, char *dest, const mdd_function_desc *mfd, int dim, int tpsize, void *auxData);
+extern int mdd_objectFunctionStruct(const mdd_function_pointers *mfp, r_Structure_Type *structType, const char *src, char *dest, const mdd_function_desc *mfd, int dim, int tpsize, void *auxData);
+extern int mdd_objectFunctionType(const mdd_function_pointers *mfp, const r_Type *baseType, const char *src, char *dest, const mdd_function_desc *mfd, int dim, int tpsize, void *auxData);
+
+// Initialising mdd functions
+#define MDD_OBJECT_INIT_NEWIV 1
+#define MDD_OBJECT_INIT_FPSTEP (2 | MDD_OBJECT_INIT_NEWIV)
+extern char *mdd_objectFunctionInitMdd(r_Ref<r_GMarray> mddPtr, r_Ref<r_GMarray> &newMddPtr, r_Minterval &newInterv, int tpsize, r_Dimension dim, r_Database *db=NULL);
+extern mdd_function_desc *mdd_objectFunctionInitData(r_Minterval &interv, r_Minterval &useInterv, r_Minterval &newInterv, int tpsize, unsigned int flags=0);
+
+
+
+
+
+
+/*
+ * Wrapper functions for mdd function templates
+ */
+int mdd_objectRange(r_Ref<r_GMarray> mddObj, r_Minterval &useInterv, double &min, double &max);
+
+int mdd_createSubcube(r_Ref<r_GMarray> srcMdd, r_Ref<r_GMarray> &newMdd, r_Minterval *domain, r_Database *db);
+
+int mdd_objectScaleInter(r_Ref<r_GMarray> srcMdd, r_Minterval &useInterv, r_Ref<r_GMarray> &newMdd, r_Minterval &newInterv);
+
+int mdd_objectScaleAverage(r_Ref<r_GMarray> srcMdd, r_Minterval &useInterv, r_Ref<r_GMarray> &newMdd, r_Minterval &newInterv);
+
+int mdd_objectScaleSimple(r_Ref<r_GMarray> srcMdd, r_Minterval &useInterv, r_Ref<r_GMarray> &newMdd, r_Minterval &newInterv);
+
+int mdd_objectChangeEndianness(r_Ref<r_GMarray> srcMdd, r_Minterval &useInterv, r_Ref<r_GMarray> *newMdd=NULL, r_Minterval *newInterv=NULL);
+
+#if (defined(EARLY_TEMPLATE) && defined(__EXECUTABLE__))
+#include "rviewMDD.cpp"
+#endif
+
+#endif
diff --git a/applications/rview/rviewOSection.cpp b/applications/rview/rviewOSection.cpp
new file mode 100644
index 0000000..f41346d
--- /dev/null
+++ b/applications/rview/rviewOSection.cpp
@@ -0,0 +1,1313 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+ * PURPOSE:
+ *
+ * A viewer for orthosections in 3D images (bias on medical images)
+ *
+ * COMENTS:
+ * None
+ */
+
+// Standard wxWindows preamble.
+#ifdef __GNUG__
+#pragma implementation
+#endif
+
+
+// changed in wxWindows 2.4.2:
+//#include "wx_prec.h"
+#include <wx/wxprec.h>
+
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+
+#ifndef WX_PRECOMP
+#include <wx/wx.h>
+#endif
+
+
+
+#include <string.h>
+#include <stdlib.h>
+#include <iostream.h>
+#include <math.h>
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#endif
+
+#include "raslib/rmdebug.hh"
+
+#include "rviewApp.hh"
+#include "rviewOSection.hh"
+#include "rviewTypes.hh"
+#include "rviewPrefs.hh"
+
+#include "cube_render.h"
+
+
+
+const int rviewOSectionImage::osection_ctrly = 140;
+const int rviewOSectionImage::osection_rcwidth = 60;
+const int rviewOSectionImage::osection_sheight = 40;
+const int rviewOSectionImage::osection_chkwidth = 60;
+const int rviewOSectionImage::osection_chkheight = 20;
+const int rviewOSectionImage::osection_twidth = 40;
+const int rviewOSectionImage::osection_theight = 50;
+const int rviewOSectionImage::osection_bwidth = 50;
+const int rviewOSectionImage::osection_bheight = 30;
+
+
+
+
+
+
+static void outputGeomData(const vertex_fp *v)
+{
+ unsigned int j;
+ for (j=0; j<4; j++)
+ {
+ cout << '(' << v[j].x << ',' << v[j].y << ',' << v[j].z << ')';
+ }
+ cout << endl;
+}
+
+
+
+
+
+const unsigned int rviewOSectionImage::numSections = 3;
+
+const char *rviewOSectionImage::sliderLabels[rviewOSectionImage::numSections] = {
+ "textSliceX",
+ "textSliceY",
+ "textSliceZ"
+};
+
+const char *rviewOSectionImage::view_Thickness = "thickness";
+const char *rviewOSectionImage::view_MidPoint = "midPoint";
+const char *rviewOSectionImage::view_UseBBox = "useBBox";
+
+/*
+ * The actual viewer class
+ */
+
+// types for internal use defined here (to avoid including cube_render.h from headers)
+
+// the dimensions a section is mapped to (z is the flat one)
+struct rviewOSectionImage::section_map_s {
+ unsigned int x, y, z;
+};
+
+// a partition descriptor (each quadrant is described by one such partition;
+// normally there are 12 in total)
+struct rviewOSectionImage::section_part_s {
+ unsigned int section;
+ unsigned long offset;
+ tex_desc td;
+ vertex_fp gr[4]; // fully rotated and translated
+ vertex_fp grav; // center of gravity
+ real_t distance;
+ int quadrant;
+};
+
+
+rviewOSectionImage::rviewOSectionImage(mdd_frame *mf, unsigned int flags) :
+ rviewRenderImage(mf, osection_ctrly, flags)
+{
+ secmap = NULL;
+ partition = NULL;
+ sliders = NULL;
+ sltexts = NULL;
+ thickness = prefs->imgOrthoThick;
+
+ unsigned int i, j;
+
+ secmap = new section_map_t[numSections];
+ memset(secmap, 0, numSections*sizeof(section_map_t));
+ currentSection = numSections + 1;
+
+ for (i=0; i<numSections; i++)
+ {
+ secmap[i].x = i;
+ secmap[i].y = (i >= 2) ? i-2 : i+1;
+ secmap[i].z = (i >= 1) ? i-1 : i+2;
+ }
+
+ intersection = r_Point(dimMDD);
+ for (i=0; i<dimMDD; i++)
+ {
+ intersection[i] = (interv[i].high() + interv[i].low()) / 2;
+ }
+
+ boundingBox = new rviewCheckBox(ctrlPanel);
+ doBoundingBox = prefs->imgOrthoBBox;
+ boundingBox->SetValue(doBoundingBox);
+
+ //sliders = new rviewSlider*[numSections];
+ sliders = new rviewSpecialSlider*[numSections];
+ sltexts = new rviewText*[numSections];
+
+ for (i=0; i<numSections; i++)
+ {
+ // little precaution against MDD with less than 2D. Proper error in openViewer()
+ j = (secmap[i].z < dimMDD) ? secmap[i].z : dimMDD-1;
+ //sliders[i] = new rviewSlider(ctrlPanel, intersection[j], interv[j].low(), interv[j].high(), 100, lman->lookup(sliderLabels[i]));
+ sliders[i] = new rviewSpecialSlider(this, ctrlPanel, intersection[j], interv[j].low(), interv[j].high(), 100, lman->lookup(sliderLabels[i]));
+ sltexts[i] = new rviewText(ctrlPanel, intersection[j]);
+ }
+
+ thickText = new rviewText(ctrlPanel, thickness);
+ thickText->SetValue(thickness);
+}
+
+
+int rviewOSectionImage::openViewer(void)
+{
+ if (dimMDD != 3)
+ {
+ rviewErrorbox::reportError(lman->lookup("errorModeDim"), rviewOSectionImage::getFrameName(), "openViewer");
+ objectInitializedOK = FALSE;
+ return -1;
+ }
+
+ partition = new section_part_t[numSections * 4];
+ memset(partition, 0, numSections * 4 * sizeof(section_part_t));
+ numPartitions = 0;
+
+ if (rviewRenderImage::openViewer() == 0)
+ {
+ openViewerEpilogue(rviewOSectionImage::getFrameType());
+
+ return 0;
+ }
+ return -1;
+}
+
+
+rviewOSectionImage::~rviewOSectionImage(void)
+{
+ if (secmap != NULL)
+ delete [] secmap;
+
+ if (partition != NULL)
+ delete [] partition;
+
+ if (sliders != NULL)
+ delete [] sliders;
+
+ if (sltexts != NULL)
+ delete [] sltexts;
+}
+
+
+const char *rviewOSectionImage::getFrameName(void) const
+{
+ return "rviewOSectionImage";
+}
+
+rviewFrameType rviewOSectionImage::getFrameType(void) const
+{
+ return rviewFrameTypeOSectionImage;
+}
+
+int rviewOSectionImage::getViewerType(void) const
+{
+ return RVIEW_RESDISP_IMGOSECT;
+}
+
+
+void rviewOSectionImage::label(void)
+{
+ unsigned int i;
+
+ setDisplayTitle(lman->lookup("titleImageOrtho"));
+ boundingBox->SetLabel(lman->lookup("textBBox"));
+ thickText->SetLabel(lman->lookup("textOrthoThickness"));
+ for (i=0; i<numSections; i++)
+ {
+ sliders[i]->SetLabel(lman->lookup(sliderLabels[i]));
+ }
+ rviewRenderImage::label();
+}
+
+
+void rviewOSectionImage::updateSlice(unsigned int num, long value, bool useDummy)
+{
+ unsigned int map = secmap[num].z;
+ //cout << "update slice " << num << endl;
+ // make an update if the value has changed or we need a full update and the current
+ // section is a dummy.
+ if ((intersection[map] != value) || (!useDummy && (getSectionProjection(num) != value)))
+ {
+ if ((interv[map].low() <= value) && (value <= interv[map].high()))
+ {
+ intersection[map] = value;
+ sliders[num]->SetValue(value);
+ sltexts[num]->SetValue(value);
+
+ if (useDummy)
+ createDummySection(num);
+ else
+ ensureSections();
+
+ fillBuffer();
+ updatePixmap(imgData, imgData);
+ }
+ }
+}
+
+
+void rviewOSectionImage::refreshSlices(bool force)
+{
+ if (force)
+ flushSlices();
+
+ ensureSections();
+ fillBuffer();
+ updatePixmap(imgData, imgData);
+}
+
+
+int rviewOSectionImage::process(wxObject &obj, wxEvent &evt)
+{
+ int type = evt.GetEventType();
+
+ if (type == wxEVENT_TYPE_CHECKBOX_COMMAND)
+ {
+ if (&obj == (wxObject*)boundingBox)
+ {
+ doBoundingBox = boundingBox->GetValue();
+ fillBuffer();
+ pcanv->updateDisplay();
+ return 1;
+ }
+ }
+ else if (type == wxEVENT_TYPE_SLIDER_COMMAND)
+ {
+ unsigned int i;
+
+ for (i=0; i<numSections; i++)
+ {
+ if (&obj == (wxObject*)(sliders[i]))
+ {
+ updateSlice(i, sliders[i]->GetValue(), TRUE);
+ return 1;
+ }
+ }
+ }
+ else if (type == wxEVENT_TYPE_TEXT_ENTER_COMMAND)
+ {
+ unsigned int i;
+
+ for (i=0; i<numSections; i++)
+ {
+ if (&obj == (wxObject*)(sltexts[i]))
+ {
+ updateSlice(i, atoi(sltexts[i]->GetValue()), FALSE);
+ return 1;
+ }
+ }
+
+ if (&obj == (wxObject*)thickText)
+ {
+ int newThick = atoi(thickText->GetValue());
+ if ((newThick > 0) && (newThick != thickness))
+ {
+ thickness = newThick;
+ refreshSlices(TRUE);
+ return 1;
+ }
+ }
+ }
+
+ return rviewRenderImage::process(obj, evt);
+}
+
+
+void rviewOSectionImage::childMouseEvent(wxWindow *child, wxMouseEvent &mevt)
+{
+ unsigned int i;
+
+ for (i=0; i<numSections; i++)
+ {
+ if (child == (wxWindow*)(sliders[i]))
+ {
+ float mx, my;
+ unsigned int newSect;
+
+ mevt.Position(&mx, &my);
+ if (sliders[i]->PositionInWell(mx, my))
+ newSect = i;
+ else
+ newSect = numSections + 1;
+
+ if (newSect != currentSection)
+ {
+ currentSection = newSect;
+ fillBuffer();
+ updatePixmap(imgData, imgData);
+ }
+ break;
+ }
+ }
+ // pass on event
+ rviewRenderImage::childMouseEvent(child, mevt);
+}
+
+
+void rviewOSectionImage::OnSize(int w, int h)
+{
+ rviewRenderImage::OnSize(w, h);
+
+ int x, y, width, orgy, posx, posy;
+ unsigned int i;
+
+ ctrlPanel->GetClientSize(&x, &y);
+
+ boundingBox->SetSize(w + 2*display_cnvborder - 3*display_border - 4*display_pbwidth, display_border, osection_chkwidth, osection_chkheight);
+
+ x -= 2*display_border;
+ orgy = totalCtrlHeight - osection_ctrly + display_border;
+ width = x - osection_rcwidth - osection_twidth;
+ if (width < 100)
+ width = 100;
+
+ posx = display_border;
+ posy = orgy;
+ for (i=0; i<numSections; i++)
+ {
+ sliders[i]->SetSize(posx, posy, width - display_border, osection_sheight);
+ sltexts[i]->SetSize(posx + width, posy + display_border, osection_twidth, osection_sheight);
+ posy += osection_sheight;
+ }
+
+ posx = x - osection_rcwidth + 3*display_border/2;
+ posy = orgy;
+ thickText->SetSize(posx, posy, osection_rcwidth, osection_theight);
+}
+
+
+bool rviewOSectionImage::doUpdate(int flags)
+{
+ return FALSE;
+}
+
+
+char *rviewOSectionImage::initMode(void)
+{
+ sprintf(projString, "*:*, *:*, *:*");
+ project->SetValue(projString);
+ setModeDimension(3);
+
+ ensureSections();
+
+ return rviewRenderImage::initMode();
+}
+
+
+char *rviewOSectionImage::setupEnvironment(int w, int h)
+{
+ if (setupEnvBase(w, h, getCsmapArray(), &csmap, csInterv) != 0)
+ return NULL;
+
+ return imgData;
+}
+
+
+void rviewOSectionImage::fillBuffer(void)
+{
+ bool cspaceOK;
+ unsigned int i, j;
+
+ performPartition();
+
+ // bounding boxes?
+ graphEnv->bbox_colour = (doBoundingBox) ? 0xffffff : 0xffffffff;
+ // z params
+ graphEnv->zpro = setup.zpro; graphEnv->clipz = setup.clipz;
+
+ fillBufferBackground(doValToCspace, cspaceOK, getCsmapArray(), &csmap, csInterv, baseType, doFullRangeCspace);
+
+ real_t ztranslate = graphEnv->zpro + zoff;
+ for (i=0; i<numPartitions; i++)
+ {
+ vertex_fp *v = &(partition[i].grav);
+ partition[i].distance = sqrt((v->x * v->x) + (v->y * v->y) + ((v->z + ztranslate) * (v->z + ztranslate)));
+ }
+
+ // finally sort it by the distance to the observer
+ // this is basically at most 12 entries, so there's no point in using complicated sorting techniques
+ for (i=0; i<numPartitions-1; i++)
+ {
+ for (j=i; j<numPartitions; j++)
+ {
+ if (partition[j].distance > partition[i].distance)
+ {
+ section_part_t aux;
+ memcpy(&aux, partition+i, sizeof(section_part_t));
+ memcpy(partition+i, partition+j, sizeof(section_part_t));
+ memcpy(partition+j, &aux, sizeof(section_part_t));
+ }
+ }
+ }
+ //cout << "PARTITIONS " << numPartitions << endl;
+ for (i=0; i<numPartitions; i++)
+ {
+ if (sectionValid(partition[i].section))
+ {
+ tex_desc *td = &(partition[i].td);
+ if ((td->floatType != 0) && (csmap != NULL))
+ {
+ td->minVal = csmap->getMinVal();
+ td->maxVal = csmap->getMaxVal();
+ }
+ td->data = getSectionArray(partition[i].section) + partition[i].offset;
+ memcpy(geomUse, &(partition[i].gr), 4 * sizeof(vertex_fp));
+ geomUse[0].z += ztranslate;
+ //outputGeomData(geomUse);
+ RenderCubeSurf(geomUse, graphEnv, td);
+
+ if (partition[i].section == currentSection)
+ {
+ render_desc renderDesc;
+ vertex_fp from, to;
+ vertex_fp *ax1, *ax2;
+
+ renderDesc.graphEnv = graphEnv;
+ renderDesc.texDesc = td;
+ ax1 = geomUse + (secmap[partition[i].section].x + 1);
+ ax2 = geomUse + (secmap[partition[i].section].y + 1);
+ from.x = geomUse[0].x + ax1->x;
+ from.y = geomUse[0].y + ax1->y;
+ from.z = geomUse[0].z + ax1->z;
+ to.x = geomUse[0].x + ax2->x;
+ to.y = geomUse[0].y + ax2->y;
+ to.z = geomUse[0].z + ax2->z;
+ Render3DLine(&from, &to, &renderDesc, graphEnv->bbox_colour);
+ from.x = geomUse[0].x;
+ from.y = geomUse[0].y;
+ from.z = geomUse[0].z;
+ to.x = geomUse[0].x + ax1->x + ax2->x;
+ to.y = geomUse[0].y + ax1->y + ax2->y;
+ to.z = geomUse[0].z + ax1->z + ax2->z;
+ Render3DLine(&from, &to, &renderDesc, graphEnv->bbox_colour);
+ }
+ }
+ }
+
+ if (doValToCspace && cspaceOK)
+ {
+ translateBufferToCspace(baseType);
+ }
+}
+
+
+int rviewOSectionImage::makeMinterval(unsigned int num, r_Minterval &dom)
+{
+ r_Range low, high;
+ r_Sinterval aux[3];
+ dom = r_Minterval(dimMDD);
+ unsigned int map;
+
+ aux[secmap[num].x] = interv[secmap[num].x];
+ aux[secmap[num].y] = interv[secmap[num].y];
+ // projection dimension
+ map = secmap[num].z;
+ low = intersection[map] - thickness/2;
+ high = low + thickness - 1;
+ if (low < interv[map].low())
+ low = interv[map].low();
+ if (high > interv[map].high())
+ high = interv[map].high();
+ aux[map] = r_Sinterval(low, high);
+
+ dom << aux[0] << aux[1] << aux[2];
+ //cout << "INTERVAL " << dom << endl;
+
+ return 0;
+}
+
+
+int rviewOSectionImage::performPartition(void)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewOSectionImage", "performPartition()");
+ unsigned int i, j;
+ section_part_t *part = partition;
+ r_Point midpoint(dimMDD);
+
+ for (i=0; i<dimMDD; i++)
+ midpoint[i] = (interv[i].high() + interv[i].low() + 1) / 2;
+
+ for (i=0; i<numSections; i++)
+ {
+ if (sectionValid(i))
+ {
+ const r_Minterval secdom = getSectionDomain(i);
+ r_Range low, high;
+ int map;
+
+ // note: all MDD have 3D domains, describing their actual position within
+ // the entire cube, therefore these dimensions can be used directly for the
+ // spatial representation, making things a lot easier than using 2D domains
+ // would.
+ map = secmap[i].z;
+ low = secdom[secmap[i].z].low();
+ high = secdom[secmap[i].z].high();
+ // check whether this section should be displayed at all (-> projection string)
+ if ((pt1[map] <= high) && (pt2[map] >= low))
+ {
+ // yes, now clip it
+ if (low < pt1[map])
+ low = pt1[map];
+ if (high > pt2[map])
+ high = pt2[map];
+
+ r_Sinterval ziv(low, high);
+
+ for (j=0; j<4; j++)
+ {
+ r_Sinterval auxdom[3];
+
+ auxdom[secmap[i].z] = ziv;
+
+ map = secmap[i].x;
+ if ((j & 1) == 0)
+ {
+ low = pt1[map]; high = intersection[map] - thickness/2;
+ }
+ else
+ {
+ low = intersection[map] + thickness/2; high = pt2[map];
+ }
+ // the current projection string might project some of these partitions away
+ if (low <= high)
+ {
+ // this can still happen if the intersection point is outside the current projection
+ // domain for the still visible quadrant.
+ if (low < pt1[map])
+ low = pt1[map];
+ if (high > pt2[map])
+ high = pt2[map];
+
+ auxdom[map] = r_Sinterval(low, high);
+
+ map = secmap[i].y;
+ if ((j & 2) == 0)
+ {
+ low = pt1[map]; high = intersection[map] - thickness/2;
+ }
+ else
+ {
+ low = intersection[map] + thickness/2; high = pt2[map];
+ }
+ // ditto
+ if (low <= high)
+ {
+ // see above
+ if (low < pt1[map])
+ low = pt1[map];
+ if (high > pt2[map])
+ high = pt2[map];
+
+ r_Minterval dom(dimMDD); // domain of quadrant in absolute coordinates
+
+ auxdom[map] = r_Sinterval(low, high);
+ dom << auxdom[0] << auxdom[1] << auxdom[2];
+
+ // now calculate the descriptor for this domain
+ tex_desc *td = &(part->td);
+ part->section = i;
+ const r_Minterval &pardom = getSectionParent(i);
+ td->dimx = pardom[0].high() - pardom[0].low() + 1;
+ td->dimy = pardom[1].high() - pardom[1].low() + 1;
+ td->dimz = pardom[2].high() - pardom[2].low() + 1;
+ td->widthx = dom[0].high() - dom[0].low() + 1;
+ td->widthy = dom[1].high() - dom[1].low() + 1;
+ td->widthz = dom[2].high() - dom[2].low() + 1;
+ part->offset = (((dom[0].low() - pardom[0].low()) * td->dimy + (dom[1].low() - pardom[1].low())) * td->dimz + (dom[2].low() - pardom[2].low())) * baseSize;
+ td->baseSize = baseSize;
+ td->floatType = ((baseType == rbt_float) || (baseType == rbt_double));
+ part->quadrant = j;
+ //cout << "DOM " << dom << ", PARENT " << pardom << ", OFFSET " << part->offset << ", size " << pardom.cell_count() << endl;
+
+ vertex_fp *v, *w;
+
+ // this rotates the subcube's origin. The total origin is 0 for now.
+ // use gr[1] as temporary workspace for the unrotated origin
+ w = &(part->gr[1]);
+ w->x = dom[0].low() - midpoint[0]; // or is it secmap?
+ w->y = dom[1].low() - midpoint[1];
+ w->z = dom[2].low() - midpoint[2];
+
+ v = &(part->gr[0]);
+ v->x = cubeScale * (w->x * rot[0].x + w->y * rot[0].y + w->z * rot[0].z);
+ v->y = cubeScale * (w->x * rot[1].x + w->y * rot[1].y + w->z * rot[1].z);
+ v->z = cubeScale * (w->x * rot[2].x + w->y * rot[2].y + w->z * rot[2].z);
+
+ // then rotate the whole thing and calculate the center of gravity (= origin + 0.5 * diagonal)
+ unsigned int k;
+
+ part->grav.x = part->gr[0].x;
+ part->grav.y = part->gr[0].y;
+ part->grav.z = part->gr[0].z;
+ for (k=1; k<4; k++)
+ {
+ geomUse[k].x = 0; geomUse[k].y = 0; geomUse[k].z = 0;
+ }
+ geomUse[1].x = td->widthx;
+ geomUse[2].y = td->widthy;
+ geomUse[3].z = td->widthz;
+
+ for (k=1; k<4; k++)
+ {
+ v = &(part->gr[k]); w = &(geomUse[k]);
+ // this rotates the cube's axes (edge lengths are width = dom.high() - dom.low() + 1);
+ v->x = cubeScale * (w->x * rot[0].x + w->y * rot[0].y + w->z * rot[0].z);
+ v->y = cubeScale * (w->x * rot[1].x + w->y * rot[1].y + w->z * rot[1].z);
+ v->z = cubeScale * (w->x * rot[2].x + w->y * rot[2].y + w->z * rot[2].z);
+ part->grav.x += 0.5 * (v->x);
+ part->grav.y += 0.5 * (v->y);
+ part->grav.z += 0.5 * (v->z);
+ }
+
+ // advance partition pointer
+ part++;
+ }
+ }
+ }
+ } // entire section clipped away by projection string
+ }
+ }
+ numPartitions = part - partition;
+
+ // sorting isn't done here because it depends on the exact current perspective view.
+ RMDBGIF(4, RMDebug::module_applications, "rviewOSection", \
+ for (i=0; i<numPartitions; i++){\
+ RMInit::dbgFileOut << i << ": " << partition[i].grav.z << ' ';\
+ outputGeomData(&(partition[i].gr[j]));\
+ };\
+ RMInit::dbgFileOut << endl ;
+ );
+ // done; the first entry in partitions is the remotest
+ return 0;
+}
+
+
+int rviewOSectionImage::saveView(FILE *fp)
+{
+ int status = rviewRenderImage::saveView(fp);
+
+ writeViewParam(fp, view_Thickness, (long)thickness);
+ writeViewParam(fp, view_UseBBox, (long)doBoundingBox);
+
+ long middle[numSections];
+ for (unsigned int i=0; i<numSections; i++)
+ middle[i] = (long)(intersection[i]);
+ writeViewParam(fp, view_MidPoint, numSections, middle);
+
+ return status;
+}
+
+
+int rviewOSectionImage::readView(const char *key, const char *value)
+{
+ int status = rviewRenderImage::readView(key, value);
+
+ if (status == 0)
+ {
+ if (strcmp(key, view_Thickness) == 0)
+ {
+ thickness = atoi(value);
+ return 1;
+ }
+ else if (strcmp(key, view_UseBBox) == 0)
+ {
+ doBoundingBox = (bool)atoi(value);
+ return 1;
+ }
+ else if (strcmp(key, view_MidPoint) == 0)
+ {
+ long middle[numSections];
+ if (readVector(value, numSections, middle) == 0)
+ {
+ for (unsigned int i=0; i<numSections; i++)
+ intersection[i] = (r_Range)(middle[i]);
+ }
+ return 1;
+ }
+ return 0;
+ }
+ return status;
+}
+
+
+void rviewOSectionImage::loadViewFinished(void)
+{
+ rviewRenderImage::loadViewFinished();
+
+ thickText->SetValue(thickness);
+ boundingBox->SetValue(doBoundingBox);
+
+ unsigned char modified[numSections];
+ unsigned int i;
+
+ for (i=0; i<numSections; i++)
+ {
+ long value = intersection[secmap[i].z];
+ modified[i] = (value != (r_Range)(sliders[i]->GetValue()));
+ //cout << i << ": IS " << sliders[i]->GetValue() << ", NEW " << value << ", MOD " << (int)(modified[i]) << endl;
+ if (modified[i])
+ {
+ sliders[i]->SetValue((int)value);
+ sltexts[i]->SetValue((int)value);
+ }
+ }
+ for (i=0; i<numSections; i++)
+ {
+ if (modified[i])
+ updateSlice(i, intersection[secmap[i].z], FALSE);
+ }
+}
+
+
+
+
+
+
+/*
+ * Partial orthosection: only the slices are in main memory, new ones are
+ * loaded from the database on demand.
+ */
+
+// a section descriptor (the three slices through the volume are sections)
+struct rviewOSectionPartImage::section_desc_s {
+ r_GMarray *mdd;
+ r_Range proj;
+};
+
+
+/*
+ * The creator for the viewer
+ * This is needed because the interface differs from the other viewers in that
+ * we don't own the object to visualize but have to read descriptors from a
+ * collection first
+ */
+rviewOSectionPartImage *rviewOSectionPartImage::createViewer(const char *collname, const double *loid)
+{
+ char queryBuffer[STRINGSIZE];
+ collection_desc *desc;
+ r_Minterval dom;
+ r_Dimension di;
+
+ if (rmanClientApp::theApp()->getMinterval(dom, collname, loid) == 0)
+ {
+ cerr << "rviewOSectionImage::create(): unable to read spatial domain";
+ return NULL;
+ }
+
+ r_Minterval queryDom(dom.dimension());
+ for (di=0; di<dom.dimension(); di++)
+ queryDom << r_Sinterval(dom[di].low(), dom[di].low());
+
+ ostrstream memstr(queryBuffer, STRINGSIZE);
+ memstr << "SELECT x" << queryDom << " FROM " << collname << " AS x";
+ if (loid != NULL)
+ memstr << " WHERE OID(x) = " << *loid;
+ memstr << '\0';
+
+ //cout << "QUERY: " << queryBuffer << endl;
+
+ if ((desc = rmanClientApp::theApp()->executeQuerySync(queryBuffer, NULL, FALSE)) != NULL)
+ {
+ if (desc->mddObjs != NULL)
+ {
+ unsigned int i;
+ r_GMarray *dummyMDD;
+ const r_GMarray *mdd;
+ mdd_frame dummyFrame;
+
+ mdd = desc->mddObjs[0].mdd.ptr();
+ // create a fake MDD with all the necessary meta data (spatial domain, base type, ...)
+ dummyMDD = new r_GMarray();
+ dummyMDD->set_spatial_domain(dom);
+ dummyMDD->set_type_length(mdd->get_type_length());
+ dummyMDD->set_type_structure(mdd->get_type_structure());
+ dummyMDD->set_type_by_name(mdd->get_type_name());
+ dummyMDD->initialize_oid(mdd->get_oid());
+ //dummyMDD->set_type_schema(mdd->get_type_schema());
+
+ dummyFrame.mdd = r_Ref<r_GMarray>(dummyMDD);
+ dummyFrame.flags = 0;
+ // the collection is useless now
+ rviewDeleteCollection(desc);
+ rviewOSectionPartImage *viewer = new rviewOSectionPartImage(&dummyFrame, collname, dummyFrame.mdd->get_oid(), display_flag_standalone);
+
+ // also open it automatically
+ if (viewer->openViewer() != 0)
+ {
+ delete viewer;
+ return NULL;
+ }
+ return viewer;
+ }
+ rviewDeleteCollection(desc);
+ }
+ return NULL;
+}
+
+
+
+#define INIT_DUMMY_MDD(type, min, max) \
+ csDummy = new r_Marray<type>(dummyDom, dummySL); \
+ ((type*)(csDummy->get_array()))[0] = min; \
+ ((type*)(csDummy->get_array()))[1] = max;
+
+rviewOSectionPartImage::rviewOSectionPartImage(mdd_frame *mf, const char *cname, const r_OId &oid, unsigned int flags) :
+ rviewOSectionImage(mf, flags),
+ objOId(oid),
+ collName(cname)
+{
+ sections = NULL;
+ // create a dummy MDD for use with the colourspace mapper. This contains 2 cells, the first
+ // is min, the second is max. It must be kept up to date as new data is loaded.
+ r_Minterval dummyDom(1);
+ dummyDom << r_Sinterval((r_Range)0, (r_Range)1);
+ r_Storage_Layout *dummySL = NULL;
+ switch(baseType)
+ {
+ case rbt_bool:
+ INIT_DUMMY_MDD(r_Boolean, 0, 1);
+ break;
+ case rbt_char:
+ INIT_DUMMY_MDD(r_Char, 0, 255);
+ break;
+ case rbt_uchar:
+ INIT_DUMMY_MDD(r_Octet, -128, 127);
+ break;
+
+ // from here on the defaults are rather arbitrary...
+ case rbt_short:
+ INIT_DUMMY_MDD(r_Short, -4096, 4095);
+ break;
+ case rbt_ushort:
+ INIT_DUMMY_MDD(r_UShort, 0, 8191);
+ break;
+ case rbt_long:
+ INIT_DUMMY_MDD(r_Long, -65536, 65535);
+ break;
+ break;
+ case rbt_ulong:
+ INIT_DUMMY_MDD(r_ULong, 0, 131071);
+ break;
+ case rbt_float:
+ INIT_DUMMY_MDD(r_Float, -1000.0, 1000.0);
+ break;
+ case rbt_double:
+ INIT_DUMMY_MDD(r_Double, -1000.0, 1000.0);
+ break;
+ case rbt_rgb:
+ {
+ // basically no colourspace mapping is possible here, but I don't want a totally
+ // uninitialized marray around, it's asking for trouble...
+ RGBPixel *ptr;
+ csDummy = new r_Marray<RGBPixel>(dummyDom, dummySL);
+ ptr = (RGBPixel*)(csDummy->get_array());
+ ptr[0].red = 0; ptr[0].green = 0; ptr[0].blue = 0;
+ ptr[1].red = 255; ptr[1].green = 255; ptr[1].blue = 255;
+ }
+ break;
+ default:
+ // this shouldn't happen...
+ break;
+ }
+ csDummy->set_type_by_name(mddObj->get_type_name());
+ csDummy->set_type_structure(mddObj->get_type_structure());
+
+ unsigned int i;
+
+ sections = new section_desc_t[numSections];
+ memset(sections, 0, numSections*sizeof(section_desc_t));
+ for (i=0; i<numSections; i++)
+ {
+ sections[i].mdd = NULL;
+ // init current slice projection to impossible value
+ sections[i].proj = interv[secmap[i].z].low() - 1;
+ }
+
+ fireDragRelease = new rviewCheckBox(ctrlPanel);
+ fireDragRelease->SetValue(prefs->imgOrthoDragRel);
+ fireButton = new rviewButton(ctrlPanel);
+}
+
+
+rviewOSectionPartImage::~rviewOSectionPartImage(void)
+{
+ if (sections != NULL)
+ {
+ unsigned int i;
+
+ for (i=0; i<numSections; i++)
+ {
+ if (sections[i].mdd != NULL)
+ {
+ delete sections[i].mdd;
+ sections[i].mdd = NULL;
+ }
+ }
+ delete [] sections;
+ }
+
+ csDummy.destroy();
+}
+
+
+void rviewOSectionPartImage::label(void)
+{
+ rviewOSectionImage::label();
+ fireDragRelease->SetLabel(lman->lookup("textOrthoDragRelease"));
+ fireButton->SetLabel(lman->lookup("textOrthoFireButton"));
+}
+
+
+int rviewOSectionPartImage::process(wxObject &obj, wxEvent &evt)
+{
+ int type = evt.GetEventType();
+
+ if (type == wxEVENT_TYPE_BUTTON_COMMAND)
+ {
+ if (&obj == (wxObject*)fireButton)
+ {
+ // also read the thickness while we're at it
+ int newThick = atoi(thickText->GetValue());
+ if ((newThick > 0) && (newThick != thickness))
+ {
+ thickness = newThick;
+ refreshSlices(TRUE);
+ }
+ else
+ refreshSlices(FALSE);
+
+ return 1;
+ }
+ }
+ return rviewOSectionImage::process(obj, evt);
+}
+
+
+void rviewOSectionPartImage::childMouseEvent(wxWindow *child, wxMouseEvent &mevt)
+{
+ int type = mevt.GetEventType();
+
+ //cout << "MOUSE EVENT " << type << endl;
+ if (((type == wxEVENT_TYPE_LEFT_UP) || (type == wxEVENT_TYPE_RIGHT_UP)) && fireDragRelease->GetValue())
+ refreshSlices(FALSE);
+ // pass event on to bottom layer
+ rviewOSectionImage::childMouseEvent(child, mevt);
+}
+
+
+void rviewOSectionPartImage::OnSize(int w, int h)
+{
+ rviewOSectionImage::OnSize(w, h);
+
+ int x, y;
+
+ ctrlPanel->GetClientSize(&x, &y);
+
+ x -= osection_rcwidth;
+ y = totalCtrlHeight - osection_ctrly + display_border + osection_theight;
+ fireDragRelease->SetSize(x, y, osection_chkwidth, osection_chkheight);
+ y += osection_chkheight;
+ fireButton->SetSize(x, y, osection_bwidth, osection_bheight);
+}
+
+
+void rviewOSectionPartImage::flushSlices(void)
+{
+ unsigned int i;
+
+ for (i=0; i<numSections; i++)
+ {
+ sections[i].proj = interv[secmap[i].z].low() - 1;
+ }
+}
+
+
+int rviewOSectionPartImage::ensureSections(void)
+{
+ unsigned int i;
+
+ for (i=0; i<numSections; i++)
+ {
+ if (sections[i].proj != intersection[secmap[i].z])
+ {
+ if (sections[i].mdd != NULL)
+ {
+ delete sections[i].mdd;
+ sections[i].mdd = NULL;
+ }
+
+ r_Minterval slicedom;
+ makeMinterval(i, slicedom);
+
+ char buffer[STRINGSIZE];
+ ostrstream memstr(buffer, STRINGSIZE);
+ memstr << "SELECT x" << slicedom << " FROM " << collName.ptr() << " AS x WHERE OID(x) = " << objOId.get_local_oid();
+ memstr << '\0';
+
+ //cout << "QUERY: " << buffer << endl;
+
+ collection_desc *desc;
+
+ if ((desc = rmanClientApp::theApp()->executeQuerySync(buffer, NULL, FALSE)) != NULL)
+ {
+ if (desc->number != 0)
+ {
+ sections[i].mdd = desc->mddObjs[0].mdd.ptr();
+ desc->mddObjs[0].mdd = NULL;
+ rviewDeleteCollection(desc);
+ sections[i].proj = intersection[secmap[i].z];
+ }
+ }
+
+ if (sections[i].mdd == NULL)
+ {
+ createDummySection(i, &slicedom);
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+#define MAKE_DUMMY_SECTION(type, init) \
+ { \
+ sections[num].mdd = new r_Marray<type>(*domp); \
+ type *ptr = (type*)(sections[num].mdd->get_array()); \
+ for (i=0; i<numCells; i++) ptr[i] = (init); \
+ }
+
+int rviewOSectionPartImage::createDummySection(unsigned int num, const r_Minterval *dom)
+{
+ if (sections[num].mdd != NULL)
+ {
+ delete sections[num].mdd;
+ sections[num].mdd = NULL;
+ }
+
+ sections[num].proj = interv[secmap[num].z].low() - 1;
+
+ r_Minterval *usedom = NULL;
+ const r_Minterval *domp;
+ unsigned long numCells, i;
+
+ if (dom == NULL)
+ {
+ usedom = new r_Minterval;
+ makeMinterval(num, *usedom);
+ domp = usedom;
+ }
+ else
+ domp = dom;
+
+ numCells = domp->cell_count();
+
+ switch (baseType)
+ {
+ case rbt_bool:
+ MAKE_DUMMY_SECTION(r_Boolean, 1);
+ break;
+ case rbt_char:
+ MAKE_DUMMY_SECTION(r_Char, 80 + num*32);
+ break;
+ case rbt_uchar:
+ MAKE_DUMMY_SECTION(r_Octet, -48 + num*32);
+ break;
+ case rbt_short:
+ MAKE_DUMMY_SECTION(r_Short, (-48 + num*32)*256);
+ break;
+ case rbt_ushort:
+ MAKE_DUMMY_SECTION(r_UShort, (80 + num*32)*256);
+ break;
+ case rbt_long:
+ MAKE_DUMMY_SECTION(r_Long, (-48 + num*32)*0x1000000);
+ break;
+ case rbt_ulong:
+ MAKE_DUMMY_SECTION(r_ULong, (80 + num*32)*0x1000000);
+ break;
+ case rbt_float:
+ MAKE_DUMMY_SECTION(r_Float, 10.0);
+ break;
+ case rbt_double:
+ MAKE_DUMMY_SECTION(r_Double, 10.0);
+ break;
+ case rbt_rgb:
+ {
+ sections[num].mdd = new r_Marray<RGBPixel>(*domp);
+ RGBPixel *ptr = (RGBPixel*)(sections[num].mdd->get_array());
+ r_Char val = 80 + 32*num;
+ for (i=0; i<numCells; i++)
+ {
+ ptr[i].red = val; ptr[i].green = val; ptr[i].blue = val;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (usedom != NULL)
+ delete usedom;
+
+ return 0;
+}
+
+
+bool rviewOSectionPartImage::sectionValid(unsigned int num)
+{
+ return (sections[num].mdd != NULL);
+}
+
+
+const r_Minterval &rviewOSectionPartImage::getSectionDomain(unsigned int num)
+{
+ return sections[num].mdd->spatial_domain();
+}
+
+
+const r_Minterval &rviewOSectionPartImage::getSectionParent(unsigned int num)
+{
+ return sections[num].mdd->spatial_domain();
+}
+
+
+char *rviewOSectionPartImage::getSectionArray(unsigned int num)
+{
+ return sections[num].mdd->get_array();
+}
+
+
+long rviewOSectionPartImage::getSectionProjection(unsigned int num)
+{
+ return sections[num].proj;
+}
+
+
+r_Ref<r_GMarray> &rviewOSectionPartImage::getCsmapArray(void)
+{
+ return csDummy;
+}
+
+
+
+
+
+
+/*
+ * Full orthosection: the entire object resides in main memory; this integrates
+ * seamlessly with the other viewer types.
+ */
+
+rviewOSectionFullImage::rviewOSectionFullImage(mdd_frame *mf, unsigned int flags) :
+ rviewOSectionImage(mf, flags)
+{
+ sections = new r_Minterval[numSections];
+};
+
+
+rviewOSectionFullImage::~rviewOSectionFullImage(void)
+{
+ closeViewer();
+ delete [] sections;
+ sections=0;
+}
+
+
+int rviewOSectionFullImage::ensureSections(void)
+{
+ unsigned int i;
+
+ for (i=0; i<numSections; i++)
+ makeMinterval(i, sections[i]);
+
+ return 0;
+}
+
+
+int rviewOSectionFullImage::createDummySection(unsigned int num, const r_Minterval *dom)
+{
+ if (dom == NULL)
+ makeMinterval(num, sections[num]);
+ else
+ sections[num] = *dom;
+
+ return 0;
+}
+
+
+void rviewOSectionFullImage::flushSlices(void)
+{
+}
+
+
+bool rviewOSectionFullImage::sectionValid(unsigned int num)
+{
+ return (sections[num].dimension() == dimMDD);
+}
+
+
+const r_Minterval &rviewOSectionFullImage::getSectionDomain(unsigned int num)
+{
+ return sections[num];
+}
+
+
+const r_Minterval &rviewOSectionFullImage::getSectionParent(unsigned int num)
+{
+ return interv;
+}
+
+
+char *rviewOSectionFullImage::getSectionArray(unsigned int num)
+{
+ return mddObj->get_array();
+}
+
+
+long rviewOSectionFullImage::getSectionProjection(unsigned int num)
+{
+ return intersection[secmap[num].z];
+}
+
+
+r_Ref<r_GMarray> &rviewOSectionFullImage::getCsmapArray(void)
+{
+ return mddObj;
+}
diff --git a/applications/rview/rviewOSection.hh b/applications/rview/rviewOSection.hh
new file mode 100644
index 0000000..962c3de
--- /dev/null
+++ b/applications/rview/rviewOSection.hh
@@ -0,0 +1,230 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+ * PURPOSE:
+ *
+ * A viewer for orthosections in 3D images (bias on medical images)
+ *
+ * COMMENTS:
+ * None
+ */
+
+#ifndef _RVIEW_OSECTION_H_
+#define _RVIEW_OSECTION_H_
+
+#include "rviewDModes.hh"
+
+
+/*
+ * Abstract base class for orthosection views of 3D image volumes
+ * Client classes implement the data sources (everything in memory
+ * vs. loading slices on demand)
+ */
+
+class rviewOSectionImage : public rviewRenderImage
+{
+ public:
+
+ rviewOSectionImage(mdd_frame *mf, unsigned int flags=0);
+ virtual ~rviewOSectionImage(void);
+
+ virtual void label(void);
+ virtual int process(wxObject &obj, wxEvent &evt);
+ virtual void OnSize(int w, int h);
+ virtual int openViewer(void);
+
+ virtual const char *getFrameName(void) const;
+ virtual rviewFrameType getFrameType(void) const;
+ virtual int getViewerType(void) const;
+ virtual void childMouseEvent(wxWindow *child, wxMouseEvent &mev);
+
+ // new virtual methods
+ virtual bool sectionValid(unsigned int num) = 0;
+ virtual const r_Minterval &getSectionDomain(unsigned int num) = 0;
+ virtual const r_Minterval &getSectionParent(unsigned int num) = 0;
+ virtual char *getSectionArray(unsigned int num) = 0;
+ virtual long getSectionProjection(unsigned int num) = 0;
+ virtual r_Ref<r_GMarray> &getCsmapArray(void) = 0;
+
+ // internal structures
+ struct section_map_s;
+ struct section_part_s;
+ typedef struct section_map_s section_map_t;
+ typedef struct section_part_s section_part_t;
+
+ // constants
+ // additional height of control panel
+ static const int osection_ctrly;
+ // width of righthand column (next to sliders)
+ static const int osection_rcwidth;
+ // height of slider bar
+ static const int osection_sheight;
+ // Checkbox dimensions
+ static const int osection_chkwidth;
+ static const int osection_chkheight;
+ // Text widget dimensions
+ static const int osection_twidth;
+ static const int osection_theight;
+ // Button dimensions
+ static const int osection_bwidth;
+ static const int osection_bheight;
+
+
+ protected:
+
+ virtual char *initMode(void);
+ virtual char *setupEnvironment(int w, int h);
+ virtual bool doUpdate(int updateFlags);
+ virtual void fillBuffer(void);
+
+ // view management
+ virtual int saveView(FILE *fp);
+ virtual int readView(const char *key, const char *value);
+ virtual void loadViewFinished(void);
+
+ // create the currently relevant spatial domain for a slice
+ int makeMinterval(unsigned int num, r_Minterval &dom);
+ // partition sections into quadrants for rendering
+ int performPartition(void);
+ // update a slice
+ void updateSlice(unsigned int num, long value, bool useDummy=TRUE);
+ // refresh all slices that need to (or all, if force=TRUE)
+ void refreshSlices(bool force=FALSE);
+
+ // load the correct slices from the database if necessary
+ virtual int ensureSections(void) = 0;
+ // create a dummy slice (empty)
+ virtual int createDummySection(unsigned int num, const r_Minterval *dom=NULL) = 0;
+ // flush out all slices
+ virtual void flushSlices(void) = 0;
+
+ void setOId(const r_OId &oid);
+
+ //rviewSlider **sliders;
+ rviewSpecialSlider **sliders;
+ rviewText **sltexts;
+ rviewCheckBox *boundingBox;
+ rviewText *thickText;
+
+ // intersection point of the (3) sections
+ r_Point intersection;
+ // thickness of a section (1)
+ int thickness;
+ // mapping sections to dimensions
+ struct section_map_s *secmap;
+ // mapping partitions (section quadrants) to sections and 3D space
+ struct section_part_s *partition;
+ unsigned int numPartitions;
+ bool doBoundingBox;
+ // currently selected section
+ unsigned int currentSection;
+ // static members
+ static const unsigned int numSections;
+ static const char *sliderLabels[];
+
+ // view parameters
+ static const char *view_Thickness;
+ static const char *view_MidPoint;
+ static const char *view_UseBBox;
+};
+
+
+
+
+/*
+ * Orthosection class where slices are loaded on demand from the database.
+ */
+
+class rviewOSectionPartImage : public rviewOSectionImage
+{
+ public:
+ rviewOSectionPartImage(mdd_frame *mf, const char *cname, const r_OId &oid, unsigned int flags=0);
+ ~rviewOSectionPartImage(void);
+
+ virtual void label(void);
+ virtual int process(wxObject &obj, wxEvent &evt);
+ virtual void OnSize(int w, int h);
+ virtual void childMouseEvent(wxWindow *child, wxMouseEvent &mev);
+
+ virtual bool sectionValid(unsigned int num);
+ virtual const r_Minterval &getSectionDomain(unsigned int num);
+ virtual const r_Minterval &getSectionParent(unsigned int num);
+ virtual char *getSectionArray(unsigned int num);
+ virtual long getSectionProjection(unsigned int num);
+ virtual r_Ref<r_GMarray> &getCsmapArray(void);
+
+ // create a new instance.
+ static rviewOSectionPartImage *createViewer(const char *collname, const double *loid=NULL);
+
+ struct section_desc_s;
+ typedef struct section_desc_s section_desc_t;
+
+
+ protected:
+ virtual int ensureSections(void);
+ virtual int createDummySection(unsigned int num, const r_Minterval *dom=NULL);
+ virtual void flushSlices(void);
+
+ rviewCheckBox *fireDragRelease;
+ rviewButton *fireButton;
+
+ // the sections (slices through the cube; all technically 3D)
+ struct section_desc_s *sections;
+ r_OId objOId;
+ DynamicString collName;
+ // dummy MDD used for colourspace configuration
+ r_Ref<r_GMarray> csDummy;
+};
+
+
+
+
+
+/*
+ * Orthosection class where the entire object is in client memory
+ */
+
+class rviewOSectionFullImage : public rviewOSectionImage
+{
+ public:
+ rviewOSectionFullImage(mdd_frame *mf, unsigned int flags = 0);
+ ~rviewOSectionFullImage(void);
+
+ virtual bool sectionValid(unsigned int num);
+ virtual const r_Minterval &getSectionDomain(unsigned int num);
+ virtual const r_Minterval &getSectionParent(unsigned int num);
+ virtual char *getSectionArray(unsigned int num);
+ virtual long getSectionProjection(unsigned int num);
+ virtual r_Ref<r_GMarray> &getCsmapArray(void);
+
+
+ protected:
+ virtual int ensureSections(void);
+ virtual int createDummySection(unsigned int num, const r_Minterval *dom=NULL);
+ virtual void flushSlices(void);
+
+ r_Minterval *sections;
+};
+
+#endif
diff --git a/applications/rview/rviewPrefs.cpp b/applications/rview/rviewPrefs.cpp
new file mode 100644
index 0000000..895800c
--- /dev/null
+++ b/applications/rview/rviewPrefs.cpp
@@ -0,0 +1,1571 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+ * PURPOSE:
+ *
+ * Management of rView's preferences. This includes an object encapsulating
+ * the preferences and providing IO of these preferences (rviewPrefs) and a
+ * frame class that allows displaying / editing the current preferences
+ * (rviewPrefsWindow).
+ *
+ * COMMENTS:
+ * none
+ */
+
+
+
+// Standard wxWindows preamble.
+#ifdef __GNUG__
+#pragma implementation
+#endif
+
+
+// changed in wxWindows 2.4.2:
+//#include "wx_prec.h"
+#include <wx/wxprec.h>
+
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+
+#ifndef WX_PRECOMP
+#include <wx/wx.h>
+#endif
+
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <iostream.h>
+#include <math.h>
+
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#endif
+
+
+#include "raslib/rmdebug.hh"
+#include "compression/tilecompression.hh"
+
+#include "rviewPrefs.hh"
+#include "labelManager.hh"
+
+
+
+
+rviewPrefs *prefs;
+
+
+enum prefsVarId {
+ PVar_Void,
+ PVar_ServerName,
+ PVar_ServerPort,
+ PVar_DBName,
+ PVar_UserName,
+ PVar_LastColl,
+ PVar_LastScColl,
+ PVar_LastOrColl,
+ PVar_LastDisp,
+ PVar_FilePath,
+ PVar_QueryPath,
+ PVar_QueryFont,
+ PVar_MaxDWidth,
+ PVar_MaxDHeight,
+ PVar_VffParams,
+ PVar_ImgDither,
+ PVar_DitherBest,
+ PVar_RGBSpace,
+ PVar_MovieMode,
+ PVar_ImgMode,
+ PVar_ImgBBox,
+ PVar_ImgZpro,
+ PVar_ImgClipZ,
+ PVar_ImgScale,
+ PVar_ImgPTL,
+ PVar_ImgPTH,
+ PVar_ImgWT,
+ PVar_ImgWQ,
+ PVar_ImgRGBBr,
+ PVar_ImgVoxType,
+ PVar_ImgLight,
+ PVar_ImgLightAn,
+ PVar_ImgLightSc,
+ PVar_ImgLightAm,
+ PVar_ImgLightGn,
+ PVar_ImgKernSz,
+ PVar_ImgKernTp,
+ PVar_ImgUseVCol,
+ PVar_ImgVoxCol,
+ PVar_ImgLightDs,
+ PVar_ImgLightDr,
+ PVar_ImgHgtGrd,
+ PVar_ImgHgtScl,
+ PVar_ImgOrtBBox,
+ PVar_ImgOrtDrag,
+ PVar_ImgOrtThick,
+ PVar_ChartMode,
+ PVar_ChartCosys,
+ PVar_ChartStep,
+ PVar_ChartMarkX,
+ PVar_ChartMarkY,
+ PVar_TableMode,
+ PVar_TableCosys,
+ PVar_TableStepX,
+ PVar_TableStepY,
+ PVar_ThumbPDim,
+ PVar_ThumbPStep,
+ PVar_ThumbWidth,
+ PVar_ThumbCols,
+ PVar_SoundFrq,
+ PVar_SoundLat,
+ PVar_SoundLoop,
+ PVar_CMpeakR,
+ PVar_CMpeakG,
+ PVar_CMpeakB,
+ PVar_CMsigmR,
+ PVar_CMsigmG,
+ PVar_CMsigmB,
+ PVar_CMtype,
+ PVar_ComTrFmt,
+ PVar_ComTrParm,
+ PVar_ComStFmt,
+ PVar_ComStParm,
+ PVar_NUMBER
+};
+
+
+
+const keyword_to_ident_c rviewPrefs::prefsVarDesc[] = {
+ {PVar_ServerName, "serverName"},
+ {PVar_ServerPort, "serverPort"},
+ {PVar_DBName, "databaseName"},
+ {PVar_UserName, "userName"},
+ {PVar_LastColl, "lastCollection"},
+ {PVar_LastScColl, "lastScaledColl"},
+ {PVar_LastOrColl, "lastOrthoColl"},
+ {PVar_LastDisp, "lastDisplay"},
+ {PVar_FilePath, "filePath"},
+ {PVar_QueryPath, "queryPath"},
+ {PVar_QueryFont, "queryFont"},
+ {PVar_MaxDWidth, "maxDWidth"},
+ {PVar_MaxDHeight, "maxDHeight"},
+ {PVar_VffParams, "vffParams"},
+ {PVar_ImgDither, "imgDither"},
+ {PVar_DitherBest, "ditherBest"},
+ {PVar_RGBSpace, "rgbSpace"},
+ {PVar_MovieMode, "movieMode"},
+ {PVar_ImgMode, "imageMode"},
+ {PVar_ImgBBox, "imageBBox"},
+ {PVar_ImgZpro, "imageZpro"},
+ {PVar_ImgClipZ, "imageClipz"},
+ {PVar_ImgScale, "imageScale"},
+ {PVar_ImgPTL, "imagePixThreshLow"},
+ {PVar_ImgPTH, "imagePixThreshHigh"},
+ {PVar_ImgWT, "imageWgtThresh"},
+ {PVar_ImgWQ, "imageWgtQuant"},
+ {PVar_ImgRGBBr, "imageRgbBrightness"},
+ {PVar_ImgVoxType, "voxelSetupForType"},
+ {PVar_ImgLight, "imageLight"},
+ {PVar_ImgLightAn, "imageLightAngle"},
+ {PVar_ImgLightSc, "imageLightScintAng"},
+ {PVar_ImgLightAm, "imageLightAmbient"},
+ {PVar_ImgLightGn, "imageLightGain"},
+ {PVar_ImgKernSz, "imageKernelSize"},
+ {PVar_ImgKernTp, "imageKernelType"},
+ {PVar_ImgUseVCol, "imageUseVCol"},
+ {PVar_ImgVoxCol, "imageVoxColour"},
+ {PVar_ImgLightDr, "imageLightDir"},
+ {PVar_ImgLightDs, "imageLightDist"},
+ {PVar_ImgHgtGrd, "imageHeightGrid"},
+ {PVar_ImgHgtScl, "imageHeightScale"},
+ {PVar_ImgOrtBBox, "imageOrthoBBox"},
+ {PVar_ImgOrtDrag, "imageOrthoFireDragRel"},
+ {PVar_ImgOrtThick, "imageOrthoThickness"},
+ {PVar_ChartMode, "chartMode"},
+ {PVar_ChartCosys, "chartCosys"},
+ {PVar_ChartStep, "chartStep"},
+ {PVar_ChartMarkX, "chartMarkx"},
+ {PVar_ChartMarkY, "chartMarky"},
+ {PVar_TableMode, "tableMode"},
+ {PVar_TableCosys, "tableCosys"},
+ {PVar_TableStepX, "tableStepx"},
+ {PVar_TableStepY, "tableStepy"},
+ {PVar_ThumbPDim, "thumbProjdim"},
+ {PVar_ThumbPStep, "thumbProjstep"},
+ {PVar_ThumbWidth, "thumbWidth"},
+ {PVar_ThumbCols, "thumbCols"},
+ {PVar_SoundFrq, "soundFrequency"},
+ {PVar_SoundLat, "soundLatency"},
+ {PVar_SoundLoop, "soundLoop"},
+ {PVar_CMpeakR, "cspacePeakRed"},
+ {PVar_CMpeakG, "cspacePeakGreen"},
+ {PVar_CMpeakB, "cspacePeakBlue"},
+ {PVar_CMsigmR, "cspaceSigmaRed"},
+ {PVar_CMsigmG, "cspaceSigmaGreen"},
+ {PVar_CMsigmB, "cspaceSigmaBlue"},
+ {PVar_CMtype, "cspaceType"},
+ {PVar_ComTrFmt, "transferFormat"},
+ {PVar_ComTrParm, "transferParameters"},
+ {PVar_ComStFmt, "storageFormat"},
+ {PVar_ComStParm, "storageParameters"},
+ {PVar_Void, NULL}
+};
+
+
+
+
+/*
+ * rviewPrefs members
+ */
+
+const unsigned long rviewPrefs::buffExtendGranularity = 64;
+
+rviewPrefs::rviewPrefs(void)
+{
+ setupVariables();
+}
+
+
+// Load-constructor
+rviewPrefs::rviewPrefs(const char *file)
+{
+ setupVariables();
+ load(file);
+}
+
+
+// Copy-constructor
+rviewPrefs::rviewPrefs(const rviewPrefs &srcPrefs)
+{
+ setupVariables();
+ copyPrefs(srcPrefs, *this);
+}
+
+
+void rviewPrefs::copyPrefs(const rviewPrefs &src, rviewPrefs &dest)
+{
+ dest.serverName = src.serverName;
+ dest.serverPort = src.serverPort;
+ dest.databaseName = src.databaseName;
+ dest.userName = src.userName;
+ dest.lastColl = src.lastColl;
+ dest.lastScColl = src.lastScColl;
+ dest.lastOrthoColl = src.lastOrthoColl;
+ dest.filePath = src.filePath;
+ dest.queryPath = src.queryPath;
+ dest.queryFont = src.queryFont;
+ dest.lastDisplay = src.lastDisplay;
+ dest.maxDWidth = src.maxDWidth;
+ dest.maxDHeight = src.maxDHeight;
+ dest.vffParams = src.vffParams;
+ dest.imgDither = src.imgDither;
+ dest.ditherBest = src.ditherBest;
+ dest.rgbSpace = src.rgbSpace;
+ dest.movieMode = src.movieMode;
+ dest.imgMode = src.imgMode;
+ dest.imgBBox = src.imgBBox;
+ dest.imgZpro = src.imgZpro;
+ dest.imgClipz = src.imgClipz;
+ dest.imgScale = src.imgScale;
+ dest.imgPixThreshLow = src.imgPixThreshLow;
+ dest.imgPixThreshHigh = src.imgPixThreshHigh;
+ dest.imgWgtThresh = src.imgWgtThresh;
+ dest.imgWgtQuant = src.imgWgtQuant;
+ dest.imgRgbBrightness = src.imgRgbBrightness;
+ dest.imgVoxForType = src.imgVoxForType;
+ dest.imgLight = src.imgLight;
+ dest.imgLightAngle = src.imgLightAngle;
+ dest.imgLightScintAngle = src.imgLightScintAngle;
+ dest.imgLightAmbient = src.imgLightAmbient;
+ dest.imgLightGain = src.imgLightGain;
+ dest.imgKernSize = src.imgKernSize;
+ dest.imgKernType = src.imgKernType;
+ dest.imgUseVCol = src.imgUseVCol;
+ dest.imgVoxColour = src.imgVoxColour;
+ dest.imgLightDir = src.imgLightDir;
+ dest.imgLightDist = src.imgLightDist;
+ dest.imgHeightGrid = src.imgHeightGrid;
+ dest.imgHeightScale = src.imgHeightScale;
+ dest.imgOrthoBBox = src.imgOrthoBBox;
+ dest.imgOrthoDragRel = src.imgOrthoDragRel;
+ dest.imgOrthoThick = src.imgOrthoThick;
+ dest.chartMode = src.chartMode;
+ dest.chartCosys = src.chartCosys;
+ dest.chartStep = src.chartStep;
+ dest.chartMarkx = src.chartMarkx;
+ dest.chartMarky = src.chartMarky;
+ dest.tableMode = src.tableMode;
+ dest.tableCosys = src.tableCosys;
+ dest.tableStepx = src.tableStepx;
+ dest.tableStepy = src.tableStepy;
+ dest.thumbProjdim = src.thumbProjdim;
+ dest.thumbProjstep = src.thumbProjstep;
+ dest.thumbWidth = src.thumbWidth;
+ dest.thumbCols = src.thumbCols;
+ dest.soundFreq = src.soundFreq;
+ dest.soundLatency = src.soundLatency;
+ dest.soundLoop = src.soundLoop;
+ dest.transferFmt = src.transferFmt;
+ dest.transferParm = src.transferParm;
+ dest.storageFmt = src.storageFmt;
+ dest.storageParm = src.storageParm;
+ memcpy(&(dest.csp), &(src.csp), sizeof(colourspace_params));
+}
+
+
+rviewPrefs::~rviewPrefs(void)
+{
+ if (pwin != NULL) {pwin->unlinkParent(); pwin->Close(TRUE);}
+ if (inbuff != NULL) delete [] inbuff;
+}
+
+
+
+char *rviewPrefs::getValue(char *b)
+{
+ char *d;
+
+ // This shouldn't happen.
+ while (*b != '=') {if (*b == '\0') return b; b++;}
+ b++;
+ while (isspace((unsigned int)(*b))) b++;
+ d = b;
+ // Allow only printable characters
+ while (isprint((unsigned int)(*d))) d++;
+ // Make sure it's terminated by 0.
+ *d = '\0';
+ return b;
+}
+
+
+// read a line of arbitrary length from a file
+char *rviewPrefs::readLine(FILE *fp)
+{
+ if (inbuff == NULL)
+ {
+ buffSize = buffExtendGranularity;
+ inbuff = new char[buffSize];
+ }
+ inbuff[0] = '\0';
+ inbuff[buffSize-2] = '\0';
+ fgets(inbuff, buffSize, fp);
+ unsigned long currentOff = 0;
+ char last = inbuff[buffSize-2];
+ while ((last != '\0') && (last != '\n') && (last != '\r'))
+ {
+ unsigned long newsize = buffSize + buffExtendGranularity;
+ char *newbuff;
+
+ if ((newbuff = new char[newsize]) == NULL)
+ return NULL;
+ memcpy(newbuff, inbuff, buffSize-1);
+ currentOff = buffSize-1;
+ delete [] inbuff;
+ inbuff = newbuff; buffSize = newsize;
+ inbuff[currentOff] = '\0';
+ fgets(inbuff + currentOff, buffSize - currentOff, fp);
+ last = inbuff[buffSize-2];
+ }
+ return inbuff;
+}
+
+
+int rviewPrefs::load(const char *file)
+{
+ FILE *fp;
+ char *b, *val;
+ int number;
+
+ if ((fp = fopen(file, "r")) == NULL)
+ {
+ prefsModified = TRUE;
+ return 0;
+ }
+
+ while (!feof(fp))
+ {
+ b = readLine(fp);
+ while ((*b == ' ') || (*b == '\t')) b++;
+ if ((*b != '\n') && (*b != '#') && (*b != 0))
+ {
+ number = 0;
+ while (prefsVarDesc[number].keyword != NULL)
+ {
+ int len;
+
+ len = strlen(prefsVarDesc[number].keyword);
+ if ((strncmp(b, prefsVarDesc[number].keyword, len) == 0) && (!isalnum(b[len]))) break;
+ number++;
+ }
+ if (prefsVarDesc[number].keyword == NULL)
+ {
+ cerr << "Bad line in config file: " << b << endl;
+ }
+ else
+ {
+ val = getValue(b);
+ switch (prefsVarDesc[number].ident)
+ {
+ case PVar_ServerName: serverName = val; break;
+ case PVar_ServerPort: serverPort = atoi(val); break;
+ case PVar_DBName: databaseName = val; break;
+ case PVar_UserName: userName = val; break;
+ case PVar_LastColl: lastColl = val; break;
+ case PVar_LastScColl: lastScColl = val; break;
+ case PVar_LastOrColl: lastOrthoColl = val; break;
+ case PVar_LastDisp: lastDisplay = atoi(val); break;
+ case PVar_FilePath: filePath = val; break;
+ case PVar_QueryPath: queryPath = val; break;
+ case PVar_QueryFont: queryFont = val; break;
+ case PVar_MaxDWidth: maxDWidth = atoi(val); break;
+ case PVar_MaxDHeight: maxDHeight = atoi(val); break;
+ case PVar_VffParams: vffParams = val; break;
+ case PVar_ImgDither: imgDither = atoi(val); break;
+ case PVar_DitherBest: ditherBest = atoi(val); break;
+ case PVar_RGBSpace: rgbSpace = atoi(val); break;
+ case PVar_MovieMode: movieMode = atoi(val); break;
+ case PVar_ImgMode: imgMode = (rviewImageMode)atoi(val); break;
+ case PVar_ImgBBox: imgBBox = atoi(val); break;
+ case PVar_ImgZpro: imgZpro = atoi(val); break;
+ case PVar_ImgClipZ: imgClipz = atoi(val); break;
+ case PVar_ImgScale: imgScale = atof(val); break;
+ case PVar_ImgPTL: imgPixThreshLow = atof(val); break;
+ case PVar_ImgPTH: imgPixThreshHigh = atof(val); break;
+ case PVar_ImgWT: imgWgtThresh = atof(val); break;
+ case PVar_ImgWQ: imgWgtQuant = atoi(val); break;
+ case PVar_ImgVoxType: imgVoxForType = atoi(val); break;
+ case PVar_ImgRGBBr: imgRgbBrightness = atoi(val); break;
+ case PVar_ImgLight: imgLight = atoi(val); break;
+ case PVar_ImgLightAn: imgLightAngle = atof(val); break;
+ case PVar_ImgLightSc: imgLightScintAngle = atof(val); break;
+ case PVar_ImgLightAm: imgLightAmbient = atof(val); break;
+ case PVar_ImgLightGn: imgLightGain = atof(val); break;
+ case PVar_ImgKernSz: imgKernSize = atoi(val); break;
+ case PVar_ImgKernTp: imgKernType = atoi(val); break;
+ case PVar_ImgUseVCol: imgUseVCol = atoi(val); break;
+ case PVar_ImgVoxCol: imgVoxColour = atof(val); break;
+ case PVar_ImgLightDr: imgLightDir = val; break;
+ case PVar_ImgLightDs: imgLightDist = atoi(val); break;
+ case PVar_ImgHgtGrd: imgHeightGrid = atoi(val); break;
+ case PVar_ImgHgtScl: imgHeightScale = atof(val); break;
+ case PVar_ImgOrtBBox: imgOrthoBBox = atoi(val); break;
+ case PVar_ImgOrtDrag: imgOrthoDragRel = atoi(val); break;
+ case PVar_ImgOrtThick: imgOrthoThick = atoi(val); break;
+ case PVar_ChartMode: chartMode = (rviewChartMode)atoi(val); break;
+ case PVar_ChartCosys: chartCosys = atoi(val); break;
+ case PVar_ChartStep: chartStep = atoi(val); break;
+ case PVar_ChartMarkX: chartMarkx = atoi(val); break;
+ case PVar_ChartMarkY: chartMarky = atof(val); break;
+ case PVar_TableMode: tableMode = atoi(val); break;
+ case PVar_TableCosys: tableCosys = atoi(val); break;
+ case PVar_TableStepX: tableStepx = atoi(val); break;
+ case PVar_TableStepY: tableStepy = atoi(val); break;
+ case PVar_ThumbPDim: thumbProjdim = atoi(val); break;
+ case PVar_ThumbPStep: thumbProjstep = atoi(val); break;
+ case PVar_ThumbWidth: thumbWidth = atoi(val); break;
+ case PVar_ThumbCols: thumbCols = atoi(val); break;
+ case PVar_SoundFrq: soundFreq = atoi(val); break;
+ case PVar_SoundLat: soundLatency = atoi(val); break;
+ case PVar_SoundLoop: soundLoop = atoi(val); break;
+ case PVar_CMpeakR: csp.peak_red = atof(val); break;
+ case PVar_CMpeakG: csp.peak_green = atof(val); break;
+ case PVar_CMpeakB: csp.peak_blue = atof(val); break;
+ case PVar_CMsigmR: csp.sigm_red = atof(val); break;
+ case PVar_CMsigmG: csp.sigm_green = atof(val); break;
+ case PVar_CMsigmB: csp.sigm_blue = atof(val); break;
+ case PVar_CMtype: csp.type = (cspaceType)atoi(val); break;
+ case PVar_ComTrFmt: transferFmt = atoi(val); break;
+ case PVar_ComTrParm: fromExternal(val, transferParm); break;
+ case PVar_ComStFmt: storageFmt = atoi(val); break;
+ case PVar_ComStParm: fromExternal(val, storageParm); break;
+ default:
+ cout << "Bad prefs ID " << prefsVarDesc[number].ident << endl;
+ break;
+ }
+ }
+ }
+ }
+ fclose(fp);
+
+ return 1;
+}
+
+
+int rviewPrefs::save(const char *file)
+{
+ char backname[STRINGSIZE];
+ FILE *fp;
+ int i;
+
+ if (!prefsModified) return 1;
+
+ // Make a backup copy of the old file
+ sprintf(backname, "%s~", file);
+ remove(backname); rename(file, backname);
+
+ if ((fp = fopen(file, "w")) == NULL)
+ return 0;
+
+ fprintf(fp, "# RasDaView preferences\n\n");
+
+ for (i=0; prefsVarDesc[i].keyword != NULL; i++)
+ {
+ const char *name = prefsVarDesc[i].keyword;
+
+ fprintf(fp, "%s\t=\t", name);
+ switch (prefsVarDesc[i].ident)
+ {
+ case PVar_ServerName: fprintf(fp, "%s", serverName.ptr()); break;
+ case PVar_ServerPort: fprintf(fp, "%d", serverPort); break;
+ case PVar_DBName: fprintf(fp, "%s", databaseName.ptr()); break;
+ case PVar_UserName: fprintf(fp, "%s", userName.ptr()); break;
+ case PVar_LastColl: fprintf(fp, "%s", lastColl.ptr()); break;
+ case PVar_LastScColl: fprintf(fp, "%s", lastScColl.ptr()); break;
+ case PVar_LastOrColl: fprintf(fp, "%s", lastOrthoColl.ptr()); break;
+ case PVar_LastDisp: fprintf(fp, "%d", lastDisplay); break;
+ case PVar_FilePath: fprintf(fp, "%s", filePath.ptr()); break;
+ case PVar_QueryPath: fprintf(fp, "%s", queryPath.ptr()); break;
+ case PVar_QueryFont: fprintf(fp, "%s", queryFont.ptr()); break;
+ case PVar_MaxDWidth: fprintf(fp, "%d", maxDWidth); break;
+ case PVar_MaxDHeight: fprintf(fp, "%d", maxDHeight); break;
+ case PVar_VffParams: fprintf(fp, "%s", vffParams.ptr()); break;
+ case PVar_ImgDither: fprintf(fp, "%d", imgDither); break;
+ case PVar_DitherBest: fprintf(fp, "%d", ditherBest); break;
+ case PVar_RGBSpace: fprintf(fp, "%d", rgbSpace); break;
+ case PVar_MovieMode: fprintf(fp, "%d", movieMode); break;
+ case PVar_ImgMode: fprintf(fp, "%d", imgMode); break;
+ case PVar_ImgBBox: fprintf(fp, "%d", imgBBox); break;
+ case PVar_ImgZpro: fprintf(fp, "%ld", imgZpro); break;
+ case PVar_ImgClipZ: fprintf(fp, "%ld", imgClipz); break;
+ case PVar_ImgScale: fprintf(fp, "%f", imgScale); break;
+ case PVar_ImgPTL: fprintf(fp, "%g", imgPixThreshLow); break;
+ case PVar_ImgPTH: fprintf(fp, "%g", imgPixThreshHigh); break;
+ case PVar_ImgWT: fprintf(fp, "%g", imgWgtThresh); break;
+ case PVar_ImgWQ: fprintf(fp, "%ld", imgWgtQuant); break;
+ case PVar_ImgRGBBr: fprintf(fp, "%d", imgRgbBrightness); break;
+ case PVar_ImgVoxType: fprintf(fp, "%d", imgVoxForType); break;
+ case PVar_ImgLight: fprintf(fp, "%d", imgLight); break;
+ case PVar_ImgLightAn: fprintf(fp, "%f", imgLightAngle); break;
+ case PVar_ImgLightSc: fprintf(fp, "%f", imgLightScintAngle); break;
+ case PVar_ImgLightAm: fprintf(fp, "%f", imgLightAmbient); break;
+ case PVar_ImgLightGn: fprintf(fp, "%f", imgLightGain); break;
+ case PVar_ImgKernSz: fprintf(fp, "%d", imgKernSize); break;
+ case PVar_ImgKernTp: fprintf(fp, "%d", imgKernType); break;
+ case PVar_ImgUseVCol: fprintf(fp, "%d", imgUseVCol); break;
+ case PVar_ImgVoxCol: fprintf(fp, "%f", imgVoxColour); break;
+ case PVar_ImgLightDr: fprintf(fp, "%s", imgLightDir.ptr()); break;
+ case PVar_ImgLightDs: fprintf(fp, "%d", imgLightDist); break;
+ case PVar_ImgHgtGrd: fprintf(fp, "%d", imgHeightGrid); break;
+ case PVar_ImgHgtScl: fprintf(fp, "%f", imgHeightScale); break;
+ case PVar_ImgOrtBBox: fprintf(fp, "%d", imgOrthoBBox); break;
+ case PVar_ImgOrtDrag: fprintf(fp, "%d", imgOrthoDragRel); break;
+ case PVar_ImgOrtThick: fprintf(fp, "%d", imgOrthoThick); break;
+ case PVar_ChartMode: fprintf(fp, "%d", chartMode); break;
+ case PVar_ChartCosys: fprintf(fp, "%d", chartCosys); break;
+ case PVar_ChartStep: fprintf(fp, "%d", chartStep); break;
+ case PVar_ChartMarkX: fprintf(fp, "%d", chartMarkx); break;
+ case PVar_ChartMarkY: fprintf(fp, "%f", chartMarky); break;
+ case PVar_TableMode: fprintf(fp, "%d", tableMode); break;
+ case PVar_TableCosys: fprintf(fp, "%d", tableCosys); break;
+ case PVar_TableStepX: fprintf(fp, "%d", tableStepx); break;
+ case PVar_TableStepY: fprintf(fp, "%d", tableStepy); break;
+ case PVar_ThumbPDim: fprintf(fp, "%d", thumbProjdim); break;
+ case PVar_ThumbPStep: fprintf(fp, "%d", thumbProjstep); break;
+ case PVar_ThumbWidth: fprintf(fp, "%d", thumbWidth); break;
+ case PVar_ThumbCols: fprintf(fp, "%d", thumbCols); break;
+ case PVar_SoundFrq: fprintf(fp, "%d", soundFreq); break;
+ case PVar_SoundLat: fprintf(fp, "%d", soundLatency); break;
+ case PVar_SoundLoop: fprintf(fp, "%d", soundLoop); break;
+ case PVar_CMpeakR: fprintf(fp, "%f", csp.peak_red); break;
+ case PVar_CMpeakG: fprintf(fp, "%f", csp.peak_green); break;
+ case PVar_CMpeakB: fprintf(fp, "%f", csp.peak_blue); break;
+ case PVar_CMsigmR: fprintf(fp, "%f", csp.sigm_red); break;
+ case PVar_CMsigmG: fprintf(fp, "%f", csp.sigm_green); break;
+ case PVar_CMsigmB: fprintf(fp, "%f", csp.sigm_blue); break;
+ case PVar_CMtype: fprintf(fp, "%d", csp.type); break;
+ case PVar_ComTrFmt: fprintf(fp, "%d", transferFmt); break;
+ case PVar_ComTrParm:
+ {
+ char *ext = toExternal(transferParm);
+ fwrite(ext, 1, strlen(ext), fp);
+ delete [] ext;
+ }
+ break;
+ case PVar_ComStFmt: fprintf(fp, "%d", storageFmt); break;
+ case PVar_ComStParm:
+ {
+ char *ext = toExternal(storageParm);
+ fwrite(ext, 1, strlen(ext), fp);
+ delete [] ext;
+ }
+ break;
+ default: break;
+ }
+ fprintf(fp, "\n");
+ }
+ fclose(fp);
+
+ prefsModified = FALSE;
+
+ return 1;
+}
+
+
+void rviewPrefs::setupVariables(void)
+{
+ serverPort = 7001;
+ lastDisplay = 0;
+ maxDWidth = 1024; maxDHeight = 768;
+ imgDither = FALSE; ditherBest = FALSE; rgbSpace = 0; movieMode = 0;
+ imgMode = rim_surf; chartMode = rcm_bar; tableMode = 10;
+ imgBBox = TRUE;
+ imgZpro = 256; imgClipz = 128;
+ imgScale = 1.0;
+ imgPixThreshLow = 4.0; imgPixThreshHigh = 1e6;
+ imgWgtThresh = 64.0; imgWgtQuant = 4;
+ imgRgbBrightness = TRUE; imgVoxForType = TRUE;
+ imgLight = FALSE; imgLightAmbient = 0.5; imgLightGain = 1.0;
+ imgLightAngle = 90.0; imgLightScintAngle = 90.0;
+ imgKernSize = 2; imgKernType = 2;
+ imgUseVCol = FALSE; imgVoxColour = 255.0;
+ imgHeightGrid = 8; imgHeightScale = 1.0;
+ imgLightDir = "ru"; imgLightDist = 512;
+ imgOrthoBBox = TRUE; imgOrthoDragRel = TRUE;
+ imgOrthoThick = 1;
+ chartCosys = TRUE;
+ chartStep = 8; chartMarkx = 20; chartMarky = 20.0;
+ tableCosys = TRUE;
+ tableStepx = -1; tableStepy = -1;
+ thumbProjdim = 2; thumbProjstep = 1; thumbWidth = 100; thumbCols = 4;
+ soundFreq = 11025; soundLatency = 200; soundLoop = 0;
+ csp.peak_red = 1.0; csp.peak_green = 2.0/3; csp.peak_blue = 1.0/3;
+ csp.sigm_red = 1.0 / (6 * sqrt( log(2.0) / log( exp(1.0) ) ) );
+ csp.sigm_green = csp.sigm_red; csp.sigm_blue = csp.sigm_red;
+ csp.type = cst_gauss;
+ transferFmt = 0; storageFmt = 0;
+
+ pwin = NULL;
+ prefsModified = FALSE;
+ inbuff = NULL; buffSize = 0;
+}
+
+
+int rviewPrefs::edit(void)
+{
+ // Only open one preferences editor!
+ if (pwin == NULL)
+ {
+ // The prefs window will work on a copy of these prefs.
+ pwin = new rviewPrefsWindow(this);
+ }
+ return 0;
+}
+
+
+void rviewPrefs::editorClosed(void)
+{
+ pwin = NULL;
+}
+
+void rviewPrefs::updatePrefs(rviewPrefs *newPrefs)
+{
+ copyPrefs(*newPrefs, *this);
+ prefsModified = TRUE;
+}
+
+void rviewPrefs::closeEditor(rviewPrefs *newPrefs)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewPrefs", "closeEditor( " << newPrefs << " )");
+
+ // Did the user specify OK or Cancel? OK ==> set newPrefs
+ if (newPrefs != NULL)
+ {
+ updatePrefs(newPrefs);
+ delete newPrefs;
+ }
+ // Delete the editing window (implicitly closes it).
+ pwin->Close(TRUE);
+ pwin = NULL;
+}
+
+
+void rviewPrefs::markModified(void)
+{
+ prefsModified = TRUE;
+}
+
+
+r_Data_Format rviewPrefs::getTransferFormat(void) const
+{
+ r_Data_Format fmt;
+
+ r_Tile_Compression::get_format_info((unsigned int)transferFmt, fmt);
+ return fmt;
+}
+
+
+r_Data_Format rviewPrefs::getStorageFormat( void ) const
+{
+ r_Data_Format fmt;
+
+ r_Tile_Compression::get_format_info((unsigned int)storageFmt, fmt);
+ return fmt;
+}
+
+
+char *rviewPrefs::toExternal(const DynamicString &str)
+{
+ const char *d = str.ptr();
+ unsigned int numspecial = 0;
+ char *ext, *b;
+
+ while (*d != '\0')
+ {
+ if ((*d == '\n') || (*d == '\t') || (*d == '\\')) numspecial++;
+ d++;
+ }
+ ext = new char[strlen(str.ptr()) + numspecial + 1];
+ d = str.ptr(); b = ext;
+ while (*d != '\0')
+ {
+ switch (*d)
+ {
+ case '\n':
+ *b++ = '\\'; *b++ = 'n'; break;
+ case '\t':
+ *b++ = '\\'; *b++ = 't'; break;
+ case '\\':
+ *b++ = '\\'; *b++ = '\\'; break;
+ default:
+ *b++ = *d;
+ }
+ d++;
+ }
+ *b = '\0';
+
+ return ext;
+}
+
+
+void rviewPrefs::fromExternal(const char *ext, DynamicString &str)
+{
+ const char *d;
+ char *intern, *b;
+
+ intern = new char[strlen(ext)+1];
+ d = ext; b = intern;
+ while (*d != '\0')
+ {
+ if (*d == '\\')
+ {
+ d++;
+ switch(*d)
+ {
+ case 'n':
+ *b++ = '\n'; break;
+ case 't':
+ *b++ = '\t'; break;
+ case '\\':
+ *b++ = '\\'; break;
+ default:
+ cerr << "Warning: parse error in long string " << str << endl;
+ }
+ }
+ else
+ *b++ = *d;
+
+ d++;
+ }
+ *b = '\0';
+ str = intern;
+ delete [] intern;
+}
+
+
+
+
+
+/*
+ * rviewPrefsWindow member functions
+ */
+
+const char *rviewPrefsWindow::soundLatencyChoices[] = {
+ "100ms",
+ "200ms",
+ "300ms",
+ "400ms",
+ "500ms"
+};
+
+const char *rviewPrefsWindow::soundFrequencyChoices[] = {
+ "8000Hz",
+ "11025Hz",
+ "22050Hz",
+ "44100Hz",
+ "48000Hz"
+};
+
+const int rviewPrefsWindow::prefs_width = 450;
+const int rviewPrefsWindow::prefs_height = 300;
+const int rviewPrefsWindow::prefs_border = 8;
+const int rviewPrefsWindow::prefs_bottom = 40;
+const int rviewPrefsWindow::prefs_bwidth = 80;
+const int rviewPrefsWindow::prefs_bheight = 30;
+const int rviewPrefsWindow::prefs_theight = 60;
+const int rviewPrefsWindow::prefs_chkheight = 25;
+const int rviewPrefsWindow::prefs_eheight = 50;
+const int rviewPrefsWindow::prefs_scrwidth = 16;
+const int rviewPrefsWindow::prefs_twheight = 80;
+const int rviewPrefsWindow::prefs_mheight = 30;
+const int rviewPrefsWindow::prefs_grpmsc_height = (11*rviewPrefsWindow::prefs_theight)/2;
+const int rviewPrefsWindow::prefs_grpimg_height = (65*rviewPrefsWindow::prefs_theight)/4;
+const int rviewPrefsWindow::prefs_grpren_height = (15*rviewPrefsWindow::prefs_theight)/2;
+const int rviewPrefsWindow::prefs_grphgt_height = (3*rviewPrefsWindow::prefs_theight)/2;
+const int rviewPrefsWindow::prefs_grport_height = (3*rviewPrefsWindow::prefs_theight)/2;
+const int rviewPrefsWindow::prefs_grpthb_height = (5*rviewPrefsWindow::prefs_theight)/2;
+const int rviewPrefsWindow::prefs_grpcht_height = (5*rviewPrefsWindow::prefs_theight)/2;
+const int rviewPrefsWindow::prefs_grptab_height = (5*rviewPrefsWindow::prefs_theight)/2;
+const int rviewPrefsWindow::prefs_grpsnd_height = (3*rviewPrefsWindow::prefs_theight)/2;
+const int rviewPrefsWindow::prefs_grpcom_height = (7*rviewPrefsWindow::prefs_theight)/2;
+const int rviewPrefsWindow::prefs_pheight = rviewPrefsWindow::prefs_grpmsc_height
+ + rviewPrefsWindow::prefs_grpimg_height
+ + rviewPrefsWindow::prefs_grpcht_height
+ + rviewPrefsWindow::prefs_grptab_height
+ + rviewPrefsWindow::prefs_grpsnd_height
+ + rviewPrefsWindow::prefs_grpcom_height
+ + 6*rviewPrefsWindow::prefs_border;
+
+
+rviewPrefsWindow::rviewPrefsWindow(void): rviewFrame(NULL, "", 0, 0, prefs_width, prefs_height)
+{
+ setupVariables();
+}
+
+
+rviewPrefsWindow::rviewPrefsWindow(rviewPrefs *Prefs): rviewFrame(NULL, "", 0, 0, prefs_width, prefs_height)
+{
+ setupVariables();
+ setPrefs(Prefs);
+}
+
+
+rviewPrefsWindow::~rviewPrefsWindow(void)
+{
+ if (csmap != NULL) delete csmap;
+ if (editPrefs != NULL) delete editPrefs;
+
+ if (myParent != NULL) myParent->editorClosed();
+}
+
+
+const char *rviewPrefsWindow::getFrameName(void) const
+{
+ return "rviewPrefsWindow";
+}
+
+rviewFrameType rviewPrefsWindow::getFrameType(void) const
+{
+ return rviewFrameTypePrefs;
+}
+
+
+void rviewPrefsWindow::unlinkParent(void)
+{
+ myParent = NULL;
+}
+
+
+rviewChoice *rviewPrefsWindow::buildFormatMenu(wxPanel *parent, int fmtNum, const char *label)
+{
+ rviewChoice *menu;
+ r_Data_Format fmt;
+ unsigned int i, numFormats;
+ char **formatNames;
+
+ for (numFormats=0; r_Tile_Compression::get_format_info(numFormats, fmt) != NULL; numFormats++) ;
+ formatNames = new char*[numFormats];
+ for (i=0; i<(int)numFormats; i++)
+ {
+ formatNames[i] = (char*)r_Tile_Compression::get_format_info((unsigned int)i, fmt);
+ }
+ menu = new rviewChoice(parent, numFormats, formatNames, lman->lookup(label));
+ delete [] formatNames;
+ menu->SetSelection(fmtNum);
+
+ return menu;
+}
+
+void rviewPrefsWindow::setPrefs(rviewPrefs *Prefs)
+{
+ int x, y, i;
+ char *choices[4];
+
+ myParent = Prefs;
+
+ editPrefs = new rviewPrefs(*Prefs);
+
+ GetClientSize(&x, &y);
+
+ // Create control panel first; it will be superimposed by the scrolling panel
+ butPanel = new wxPanel((wxWindow*)this, 0, 300, x, prefs_bottom);
+ butOK = new rviewButton(butPanel);
+ butCancel = new rviewButton(butPanel);
+ butApply = new rviewButton(butPanel);
+
+ i = y - prefs_bottom; if (i > prefs_pheight) i = prefs_pheight;
+ scroll = new wxScrollBar(butPanel, (wxFunction)rviewEventHandler, x - prefs_scrwidth, 0, prefs_scrwidth, i, wxVERTICAL);
+ scroll->SetValue(0);
+ // Mis-documentation: you have to set the object length before the view length,
+ // not the other way around.
+ scroll->SetObjectLength(prefs_pheight);
+ scroll->SetViewLength(i);
+ scroll->SetPageLength((3*i)/4);
+ //cout << "view length = " << i << ", object length = " << prefs_pheight << ", page length = " << (3*i)/4 << endl;
+
+ panel = new wxPanel((wxWindow*)this, 0, 0, x, y - prefs_bottom);
+
+ // Put labels above the widgets rather than to the left.
+ panel->SetLabelPosition(wxVERTICAL);
+
+ // Just create everything here. Take care of positioning in OnSize(...)
+ // Misc
+ miscGroup = new wxGroupBox(panel, "", 0, 0, 100, 100);
+ filePath = new rviewText(panel, editPrefs->filePath);
+ queryPath = new rviewText(panel, editPrefs->queryPath);
+ queryFont = new rviewText(panel, editPrefs->queryFont);
+
+ maxDWidth = new rviewText(panel, editPrefs->maxDWidth);
+ maxDHeight = new rviewText(panel, editPrefs->maxDHeight);
+
+ vffParams = new rviewText(panel, editPrefs->vffParams);
+
+ // Image group
+ imgGroup = new wxGroupBox(panel, "", 0, 0, 100, 100);
+ imgDither = new rviewCheckBox(panel);
+ imgDither->SetValue(editPrefs->imgDither);
+ ditherBest = new rviewCheckBox(panel);
+ ditherBest->SetValue(editPrefs->ditherBest);
+ choices[0] = lman->lookup("textOff");
+ choices[1] = lman->lookup("prefsCspaceAct");
+ choices[2] = lman->lookup("prefsCspaceFull");
+ choices[3] = lman->lookup("prefsCspaceProj");
+ rgbSpace = new rviewChoice(panel, 4, choices, lman->lookup("prefsCspace"));
+ rgbSpace->SetSelection(editPrefs->rgbSpace);
+ cstrap = new rviewButton(panel);
+ choices[0] = lman->lookup("prefsMovieOnce");
+ choices[1] = lman->lookup("prefsMovieStart");
+ choices[2] = lman->lookup("prefsMovieSwitch");
+ movieMode = new rviewChoice(panel, 3, choices, lman->lookup("prefsMovieMode"));
+ movieMode->SetSelection(editPrefs->movieMode);
+ renderGroup = new wxGroupBox(panel, "", 0, 0, 100, 100);
+ choices[0] = lman->lookup("menImgModeSurf");
+ choices[1] = lman->lookup("menImgModeVoxel");
+ imgMode = new rviewChoice(panel, 2, choices, lman->lookup("textImageMode"));
+ imgScale = new rviewText(panel, editPrefs->imgScale, FALSE);
+ // Image renderer subgroup
+ imgZpro = new rviewText(panel, (long)(editPrefs->imgZpro));
+ imgClipz = new rviewText(panel, (long)(editPrefs->imgClipz));
+ imgBBox = new rviewCheckBox(panel);
+ imgBBox->SetValue(editPrefs->imgBBox);
+ imgPixThreshLow = new rviewText(panel, editPrefs->imgPixThreshLow, TRUE);
+ imgPixThreshHigh = new rviewText(panel, editPrefs->imgPixThreshHigh, TRUE);
+ imgRgbBrightness = new rviewCheckBox(panel);
+ imgRgbBrightness->SetValue(editPrefs->imgRgbBrightness);
+ imgVoxForType = new rviewCheckBox(panel);
+ imgVoxForType->SetValue(editPrefs->imgVoxForType);
+ imgWgtThresh = new rviewText(panel, editPrefs->imgWgtThresh, TRUE);
+ imgWgtQuant = new rviewText(panel, (long)(editPrefs->imgWgtQuant));
+ imgLight = new rviewCheckBox(panel);
+ imgLight->SetValue(editPrefs->imgLight);
+ choices[0] = "0";
+ choices[1] = "1";
+ choices[2] = "2";
+ choices[3] = "3";
+ imgKernSize = new rviewChoice(panel, 4, choices, lman->lookup("prefsKernSize"));
+ imgKernSize->SetSelection(editPrefs->imgKernSize);
+ choices[0] = lman->lookup("kernelTypeAvg");
+ choices[1] = lman->lookup("kernelTypeLin");
+ choices[2] = lman->lookup("kernelTypeGauss");
+ imgKernType = new rviewChoice(panel, 3, choices, lman->lookup("prefsKernType"));
+ imgKernType->SetSelection(editPrefs->imgKernType);
+ imgLightAngle = new rviewText(panel, editPrefs->imgLightAngle);
+ imgLightAmbient = new rviewText(panel, editPrefs->imgLightAmbient);
+ imgLightGain = new rviewText(panel, editPrefs->imgLightGain);
+ imgLightScintAngle = new rviewText(panel, editPrefs->imgLightScintAngle);
+ imgLightDir = new rviewText(panel, editPrefs->imgLightDir);
+ imgLightDist = new rviewText(panel, editPrefs->imgLightDist);
+ imgUseVCol = new rviewCheckBox(panel);
+ imgUseVCol->SetValue(editPrefs->imgUseVCol);
+ imgVoxColour = new rviewText(panel, editPrefs->imgVoxColour);
+ // Image heightfield subgroup
+ heightGroup = new wxWidowBase(panel, "", 0, 0, 100, 100);
+ imgHeightGrid = new rviewText(panel, editPrefs->imgHeightGrid);
+ imgHeightScale = new rviewText(panel, editPrefs->imgHeightScale);
+ // Image orthosection subgroup
+ orthoGroup = new wxGroupBox(panel, "", 0, 0, 100, 100);
+ imgOrthoBBox = new rviewCheckBox(panel);
+ imgOrthoBBox->SetValue(editPrefs->imgOrthoBBox);
+ imgOrthoDragRel = new rviewCheckBox(panel);
+ imgOrthoDragRel->SetValue(editPrefs->imgOrthoDragRel);
+ imgOrthoThick = new rviewText(panel, editPrefs->imgOrthoThick);
+ // Image thumbnails subgroup
+ thumbGroup = new wxGroupBox(panel, "", 0, 0, 100, 100);
+ thumbProjdim = new rviewText(panel, editPrefs->thumbProjdim);
+ thumbProjstep = new rviewText(panel, editPrefs->thumbProjstep);
+ thumbWidth = new rviewText(panel, editPrefs->thumbWidth);
+ thumbCols = new rviewText(panel, editPrefs->thumbCols);
+
+ // Chart group
+ chartGroup = new wxGroupBox(panel, "", 0, 0, 100, 100);
+ choices[0] = lman->lookup("menChartModeBar");
+ choices[1] = lman->lookup("menChartModeLine");
+ choices[2] = lman->lookup("menChartModeSpline");
+ chartMode = new rviewChoice(panel, 3, choices, lman->lookup("textChartMode"));
+ chartCosys = new rviewCheckBox(panel);
+ chartCosys->SetValue(editPrefs->chartCosys);
+ chartStep = new rviewText(panel, editPrefs->chartStep);
+ chartMarkx = new rviewText(panel, editPrefs->chartMarkx);
+ chartMarky = new rviewText(panel, editPrefs->chartMarky);
+
+ // Table group
+ tableGroup = new wxGroupBox(panel, "", 0, 0, 100, 100);
+ choices[0] = lman->lookup("menTabModeDec");
+ choices[1] = lman->lookup("menTabModeOct");
+ choices[2] = lman->lookup("menTabModeHex");
+ tableMode = new rviewChoice(panel, 3, choices, lman->lookup("textTableMode"));
+ tableCosys = new rviewCheckBox(panel);
+ tableCosys->SetValue(editPrefs->tableCosys);
+ tableStepx = new rviewText(panel, editPrefs->tableStepx);
+ tableStepy = new rviewText(panel, editPrefs->tableStepy);
+
+ // Sound group
+ soundGroup = new wxGroupBox(panel, "", 0, 0, 100, 100);
+ i = sizeof(soundFrequencyChoices) / sizeof(char*);
+ soundFreq = new rviewChoice(panel, i, soundFrequencyChoices, lman->lookup("soundFrequency"));
+ soundFreq->SetSelection(findInChoices(editPrefs->soundFreq, (const char**)soundFrequencyChoices, i));
+ i = sizeof(soundLatencyChoices) / sizeof(char*);
+ soundLatency = new rviewChoice(panel, i, soundLatencyChoices, lman->lookup("soundLatency"));
+ soundLatency->SetSelection(findInChoices(editPrefs->soundLatency, (const char**)soundLatencyChoices, i));
+ soundLoop = new rviewCheckBox(panel);
+ soundLoop->SetValue(editPrefs->soundLoop);
+
+ // Communication group
+ commGroup = new wxGroupBox(panel, "", 0, 0, 100, 100);
+
+ transferFmt = buildFormatMenu(panel, editPrefs->transferFmt, "textTransferFormats");
+ transferMsg = new wxMessage(panel, lman->lookup("textTransferParams"));
+ transferParm = new wxTextWindow(panel, 0, 0, 100, 100);
+ transferParm->WriteText((char*)(editPrefs->transferParm.ptr()));
+ storageFmt = buildFormatMenu(panel, editPrefs->storageFmt, "textStorageFormats");
+ storageMsg = new wxMessage(panel, lman->lookup("textStorageParams"));
+ storageParm = new wxTextWindow(panel, 0, 0, 100, 100);
+ storageParm->WriteText((char*)(editPrefs->storageParm.ptr()));
+
+ switch (editPrefs->imgMode)
+ {
+ case rim_voxel: imgMode->SetSelection(1); break;
+ default: imgMode->SetSelection(0); break;
+ }
+ switch (editPrefs->chartMode)
+ {
+ case rcm_line: chartMode->SetSelection(1); break;
+ case rcm_spline: chartMode->SetSelection(2); break;
+ default: chartMode->SetSelection(0); break;
+ }
+ switch (editPrefs->tableMode)
+ {
+ case 8: tableMode->SetSelection(1); break;
+ case 16: tableMode->SetSelection(2); break;
+ default: tableMode->SetSelection(0); break;
+ }
+
+#ifdef wx_msw
+ // Windows -- you just gotta love it. Obviously there are huge problems when
+ // creating two panels in one window. Thus make sure the button panel is _below_
+ // the configuration panel. That's only possible by directly using Windows calls.
+ SetWindowPos(panel->GetHWND(), HWND_BOTTOM, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE);
+ SetWindowPos(butPanel->GetHWND(), HWND_BOTTOM, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE);
+#endif
+
+ label();
+
+ frameWidth = -1; frameHeight = -1;
+
+ OnSize(x, y);
+ OnSize(x, y);
+
+ Show(TRUE);
+}
+
+
+void rviewPrefsWindow::label(void)
+{
+ SetTitle(lman->lookup("titlePrefs"));
+ miscGroup->SetLabel(lman->lookup("textMiscPrefs"));
+ butOK->SetLabel(lman->lookup("textOK"));
+ butCancel->SetLabel(lman->lookup("textCancel"));
+ butApply->SetLabel(lman->lookup("textApply"));
+ filePath->SetLabel(lman->lookup("prefsFilePath"));
+ queryPath->SetLabel(lman->lookup("prefsQueryPath"));
+ queryFont->SetLabel(lman->lookup("prefsQueryFont"));
+ maxDWidth->SetLabel(lman->lookup("prefsMaxDWidth"));
+ maxDHeight->SetLabel(lman->lookup("prefsMaxDHeight"));
+ vffParams->SetLabel(lman->lookup("prefsVffParams"));
+ imgGroup->SetLabel(lman->lookup("textImages"));
+ imgDither->SetLabel(lman->lookup("prefsImgDither"));
+ ditherBest->SetLabel(lman->lookup("prefsDitherBest"));
+ rgbSpace->SetLabel(lman->lookup("prefsCspace"));
+ cstrap->SetLabel(lman->lookup("prefsCspaceEdit"));
+ movieMode->SetLabel(lman->lookup("prefsMovieMode"));
+ imgMode->SetLabel(lman->lookup("textImageMode"));
+ renderGroup->SetLabel(lman->lookup("menImgSetupRender"));
+ imgBBox->SetLabel(lman->lookup("textBBox"));
+ imgZpro->SetLabel(lman->lookup("imgSetRenZpro"));
+ imgClipz->SetLabel(lman->lookup("imgSetRenClipz"));
+ imgScale->SetLabel(lman->lookup("textScaleFactor"));
+ imgPixThreshLow->SetLabel(lman->lookup("imgSetVoxPixThreshLow"));
+ imgPixThreshHigh->SetLabel(lman->lookup("imgSetVoxPixThreshHigh"));
+ imgWgtThresh->SetLabel(lman->lookup("imgSetVoxWgtThresh"));
+ imgWgtQuant->SetLabel(lman->lookup("imgSetVoxWgtQuant"));
+ imgRgbBrightness->SetLabel(lman->lookup("imgSetVoxRgbBright"));
+ imgVoxForType->SetLabel(lman->lookup("imgSetVoxForType"));
+ imgLight->SetLabel(lman->lookup("prefsLight"));
+ imgLightAngle->SetLabel(lman->lookup("prefsLightAngle"));
+ imgLightAmbient->SetLabel(lman->lookup("prefsLightAmbient"));
+ imgLightGain->SetLabel(lman->lookup("prefsLightGain"));
+ imgKernSize->SetLabel(lman->lookup("prefsKernSize"));
+ imgKernType->SetLabel(lman->lookup("prefsKernType"));
+ imgLightScintAngle->SetLabel(lman->lookup("prefsLightScAngle"));
+ imgLightDir->SetLabel(lman->lookup("prefsLightDir"));
+ imgLightDist->SetLabel(lman->lookup("prefsLightDist"));
+ imgUseVCol->SetLabel(lman->lookup("prefsUseVCol"));
+ imgVoxColour->SetLabel(lman->lookup("prefsVoxColour"));
+ heightGroup->SetLabel(lman->lookup("prefsHeightGroup"));
+ imgHeightGrid->SetLabel(lman->lookup("prefsHgtGrid"));
+ imgHeightScale->SetLabel(lman->lookup("prefsHgtScale"));
+ orthoGroup->SetLabel(lman->lookup("prefsOrthoGroup"));
+ imgOrthoBBox->SetLabel(lman->lookup("textBBox"));
+ imgOrthoDragRel->SetLabel(lman->lookup("prefsOrthoDragRel"));
+ imgOrthoThick->SetLabel(lman->lookup("prefsOrthoThick"));
+ thumbGroup->SetLabel(lman->lookup("textThumb"));
+ thumbProjdim->SetLabel(lman->lookup("textThumbProjDim"));
+ thumbProjstep->SetLabel(lman->lookup("textThumbProjStep"));
+ thumbWidth->SetLabel(lman->lookup("textThumbWidth"));
+ thumbCols->SetLabel(lman->lookup("textThumbColumns"));
+ chartGroup->SetLabel(lman->lookup("textCharts"));
+ chartMode->SetLabel(lman->lookup("textChartMode"));
+ chartCosys->SetLabel(lman->lookup("textCosys"));
+ chartStep->SetLabel(lman->lookup("textStepC"));
+ chartMarkx->SetLabel(lman->lookup("textDataStep"));
+ chartMarky->SetLabel(lman->lookup("textCoStep"));
+ tableGroup->SetLabel(lman->lookup("textTables"));
+ tableMode->SetLabel(lman->lookup("textTableMode"));
+ tableCosys->SetLabel(lman->lookup("textCosys"));
+ tableStepx->SetLabel(lman->lookup("textStepx"));
+ tableStepy->SetLabel(lman->lookup("textStepy"));
+ soundGroup->SetLabel(lman->lookup("prefsSound"));
+ soundFreq->SetLabel(lman->lookup("soundFrequency"));
+ soundLatency->SetLabel(lman->lookup("soundLatency"));
+ soundLoop->SetLabel(lman->lookup("prefsSndLoop"));
+ commGroup->SetLabel(lman->lookup("textCommunication"));
+ transferFmt->SetLabel(lman->lookup("textTransferFormats"));
+ transferMsg->SetLabel(lman->lookup("textTransferParams"));
+ storageFmt->SetLabel(lman->lookup("textStorageFormats"));
+ storageMsg->SetLabel(lman->lookup("textStorageParams"));
+}
+
+
+void rviewPrefsWindow::OnSize(int w, int h)
+{
+ if (panel != NULL)
+ {
+ int x, y, posx, posy, h, gbox, i, width;
+
+ GetClientSize(&x, &y);
+
+ //need to resize?
+ if (( prefs_width != x) || ( prefs_height != y))
+ {
+ frameWidth = prefs_width;
+ frameHeight = prefs_height;
+ x = prefs_width;
+ y = prefs_height;
+ SetClientSize(x, y);
+ return;
+ }
+
+ butPanel->SetSize(0, 0, x, y);
+ i = y - (prefs_bottom + prefs_bheight) / 2 - prefs_border;
+ h = (x - 3*prefs_bwidth)/3;
+ butOK->SetSize(h/2, i, prefs_bwidth, prefs_bheight);
+ butApply->SetSize(prefs_bwidth + (3*h)/2, i, prefs_bwidth, prefs_bheight);
+ butCancel->SetSize(2*prefs_bwidth + (5*h)/2, i, prefs_bwidth, prefs_bheight);
+
+ y -= prefs_bottom + prefs_border;
+
+ if (y > prefs_pheight) y = prefs_pheight;
+
+ posy = scroll->GetValue();
+ // If the window has grown the scrollbar value might be too big
+ if (posy + y > prefs_pheight + prefs_border)
+ {
+ posy = prefs_pheight + prefs_border - y;
+ if (posy < 0) posy = 0;
+ scroll->SetValue(posy);
+ }
+ posx = x - prefs_border - prefs_scrwidth;
+ panel->SetSize(0, -posy, posx, y + posy, wxSIZE_ALLOW_MINUS_ONE);
+
+ // It's very important to make the style wxSIZE_ALLOW_MINUS_ONE to keep wxWindows
+ // from interpreting negative values as defaults. Negative positioning values
+ // can happen due to scrolling.
+
+ h = y - prefs_border;
+ scroll->SetSize(posx, prefs_border, prefs_scrwidth, h);
+ if (h > prefs_pheight) h = prefs_pheight;
+ scroll->SetViewLength(h);
+ // Object length hasn't changed.
+ //scroll->SetObjectLength(prefs_pheight);
+ scroll->SetPageLength((3*h)/4);
+
+ x -= 3*prefs_border + prefs_scrwidth;
+ //y += prefs_bottom - prefs_border;
+
+ // Group boxes
+ posx = prefs_border;
+ gbox = prefs_border;
+ miscGroup->SetSize(posx, gbox, x, prefs_grpmsc_height);
+ gbox += prefs_grpmsc_height + prefs_border;
+ imgGroup->SetSize(posx, gbox, x, prefs_grpimg_height);
+ gbox += prefs_grpimg_height + prefs_border;
+ chartGroup->SetSize(posx, gbox, x, prefs_grpcht_height);
+ gbox += prefs_grpcht_height + prefs_border;
+ tableGroup->SetSize(posx, gbox, x, prefs_grptab_height);
+ gbox += prefs_grptab_height + prefs_border;
+ soundGroup->SetSize(posx, gbox, x, prefs_grpsnd_height);
+ gbox += prefs_grpsnd_height + prefs_border;
+ commGroup->SetSize(posx, gbox, x, prefs_grpcom_height);
+
+ // Misc group
+ posx = 2*prefs_border; x -= 2*prefs_border;
+ gbox = prefs_border;
+ filePath->SetSize(posx, gbox + prefs_theight/2, x, prefs_eheight);
+ queryPath->SetSize(posx, gbox + (3*prefs_theight)/2, x, prefs_eheight);
+ queryFont->SetSize(posx, gbox + (5*prefs_theight)/2, x, prefs_eheight);
+
+ maxDWidth->SetSize(posx, gbox + (7*prefs_theight)/2, x/2, prefs_eheight);
+ maxDHeight->SetSize(posx + x/2, gbox + (7*prefs_theight)/2, x/2, prefs_eheight);
+
+ vffParams->SetSize(posx, gbox + (9*prefs_theight)/2, x, prefs_eheight);
+
+ // Image group
+ gbox += prefs_grpmsc_height + prefs_border;
+ i = gbox + prefs_theight/2;
+ imgDither->SetSize(posx, i, x/3, prefs_chkheight);
+ ditherBest->SetSize(posx, i + prefs_chkheight, x/3, prefs_chkheight);
+ rgbSpace->SetSize(posx + x/3, i, prefs_bwidth, prefs_bheight);
+ cstrap->SetSize(posx + (2*x)/3 + prefs_border, i, prefs_bwidth, prefs_bheight);
+ i += prefs_theight;
+ imgMode->SetSize(posx, i, prefs_bwidth, prefs_bheight);
+ movieMode->SetSize(posx + x/3, i, prefs_bwidth, prefs_bheight);
+ imgScale->SetSize(posx + (2*x)/3 + x/30, i, x/3 -x/30, prefs_eheight);
+ i = gbox + (5*prefs_theight)/2 + prefs_border;
+ renderGroup->SetSize(posx, i, x, prefs_grpren_height);
+ heightGroup->SetSize(posx, i + prefs_grpren_height + prefs_border, x, prefs_grphgt_height);
+ orthoGroup->SetSize(posx, i + prefs_grpren_height + prefs_grphgt_height + 2*prefs_border, x, prefs_grport_height);
+ thumbGroup->SetSize(posx, i + prefs_grpren_height + prefs_grphgt_height + prefs_grport_height + 3*prefs_border, x, prefs_grpthb_height);
+ // Image renderer subgroup
+ posx += prefs_border; x -= 2*prefs_border;
+ i += prefs_theight/2;
+ imgZpro->SetSize(posx, i, x/3, prefs_eheight);
+ imgClipz->SetSize(posx + x/3, i, x/3, prefs_eheight);
+ imgBBox->SetSize(posx + (2*x)/3 + x/40, i, x/3 - x/40, prefs_chkheight);
+ imgRgbBrightness->SetSize(posx + (2*x)/3 + x/40, i + (2*prefs_theight)/3, x/3 - x/40, prefs_chkheight);
+ imgVoxForType->SetSize(posx + (2*x)/3 + x/40, i + (4*prefs_theight)/3, x/3 - x/40, prefs_chkheight);
+ i += prefs_theight;
+ imgPixThreshLow->SetSize(posx, i, x/3, prefs_eheight);
+ imgPixThreshHigh->SetSize(posx + x/3, i, x/3, prefs_eheight);
+ i += prefs_theight;
+ imgWgtThresh->SetSize(posx, i, x/2, prefs_eheight);
+ imgWgtQuant->SetSize(posx + x/2, i, x/2, prefs_eheight);
+ i += prefs_theight;
+ imgLight->SetSize(posx, i, x/4, prefs_bheight); // must reduce width to x/4!
+ imgKernSize->SetSize(posx + x/4, i, x/5, prefs_bheight);
+ imgKernType->SetSize(posx + 2*x/3, i, x/5, prefs_bheight);
+ i += prefs_theight;
+ imgLightAngle->SetSize(posx, i, x/3, prefs_eheight);
+ imgLightAmbient->SetSize(posx + x/3, i, x/3, prefs_eheight);
+ imgLightGain->SetSize(posx + (2*x)/3, i, x/3, prefs_eheight);
+ i += prefs_theight;
+ imgLightScintAngle->SetSize(posx, i, x/3, prefs_eheight);
+ imgLightDir->SetSize(posx + x/3, i, x/3, prefs_eheight);
+ imgLightDist->SetSize(posx + (2*x)/3, i, x/3, prefs_eheight);
+ i += prefs_theight;
+ imgUseVCol->SetSize(posx, i, x/2, prefs_eheight);
+ imgVoxColour->SetSize(posx + x/2, i, x/2, prefs_eheight);
+ // Image heightfield subgroup
+ i = gbox + 3*prefs_theight + prefs_grpren_height + 2*prefs_border;
+ imgHeightGrid->SetSize(posx, i, x/2, prefs_eheight);
+ imgHeightScale->SetSize(posx + x/2, i, x/2, prefs_eheight);
+ // Orthosection subgroup
+ i = gbox + 3*prefs_theight + prefs_grpren_height + prefs_grphgt_height + 2*prefs_border;
+ imgOrthoBBox->SetSize(posx, i, x/3, prefs_eheight);
+ imgOrthoDragRel->SetSize(posx + x/3, i, x/3, prefs_eheight);
+ imgOrthoThick->SetSize(posx + (2*x)/3, i, x/3, prefs_eheight);
+ // Image thumbnail subgroup
+ i = gbox + 3*prefs_theight + prefs_grpren_height + prefs_grphgt_height + prefs_grport_height + 3*prefs_border;
+ thumbProjdim->SetSize(posx, i, x/2, prefs_eheight);
+ thumbProjstep->SetSize(posx + x/2, i, x/2, prefs_eheight);
+ i += prefs_theight;
+ thumbWidth->SetSize(posx, i, x/2, prefs_eheight);
+ thumbCols->SetSize(posx + x/2, i, x/2, prefs_eheight);
+ posx -= prefs_border; x += 2*prefs_border;
+
+ // Chart group
+ gbox += prefs_grpimg_height + prefs_border;
+ i = gbox + prefs_theight/2;
+ chartMode->SetSize(posx, i, prefs_bwidth, prefs_bheight);
+ chartCosys->SetSize(posx + x/2, i, x/2, prefs_eheight);
+ i += prefs_theight;
+ chartStep->SetSize(posx, i, x/3, prefs_eheight);
+ chartMarkx->SetSize(posx + x/3, i, x/3, prefs_eheight);
+ chartMarky->SetSize(posx + (2*x)/3, i, x/3, prefs_eheight);
+
+ // Table group
+ gbox += prefs_grpcht_height + prefs_border;
+ i = gbox + prefs_theight/2;
+ tableMode->SetSize(posx, i, prefs_bwidth, prefs_bheight);
+ tableCosys->SetSize(posx + x/2, i, x/2, prefs_eheight);
+ i += prefs_theight;
+ tableStepx->SetSize(posx, i, x/2, prefs_eheight);
+ tableStepy->SetSize(posx + x/2, i, x/2, prefs_eheight);
+
+ // Sound group
+ gbox += prefs_grptab_height + prefs_border;
+ i = gbox + prefs_theight/2;
+ h = (x - 2*prefs_border) / 3;
+ soundFreq->SetSize(posx, i, prefs_bwidth, prefs_bheight);
+ soundLatency->SetSize(posx + h + prefs_border, i, prefs_bwidth, prefs_bheight);
+ soundLoop->SetSize(posx + 2*(h + prefs_border), i, h, prefs_bheight);
+
+ // Communications box
+ gbox += prefs_grpsnd_height + prefs_border;
+ i = gbox + prefs_theight/2;
+ h = (x - prefs_border) / 2;
+ width = (prefs_bwidth > h) ? h : prefs_bwidth;
+ width -= prefs_border;
+ transferFmt->SetSize(posx, i, width, prefs_bheight);
+ storageFmt->SetSize(posx + h + prefs_border, i, width, prefs_bheight);
+ i += prefs_bheight + 3*prefs_border;
+ transferMsg->SetSize(posx, i, h, prefs_mheight);
+ storageMsg->SetSize(posx + h + prefs_border, i, h, prefs_mheight);
+ i += prefs_mheight;
+ transferParm->SetSize(posx, i, h, prefs_twheight);
+ storageParm->SetSize(posx + h + prefs_border, i, h, prefs_twheight);
+ }
+}
+
+
+void rviewPrefsWindow::textWindowToString(DynamicString &str, wxTextWindow *twin)
+{
+ char *text = twin->GetContents();
+ str = text;
+ delete [] text;
+}
+
+void rviewPrefsWindow::updatePrefs(void)
+{
+ editPrefs->filePath = filePath->GetValue();
+ editPrefs->queryPath = queryPath->GetValue();
+ editPrefs->queryFont = queryFont->GetValue();
+ editPrefs->maxDWidth = asctoi(maxDWidth->GetValue());
+ editPrefs->maxDHeight = asctoi(maxDHeight->GetValue());
+ editPrefs->vffParams = vffParams->GetValue();
+ editPrefs->imgDither = imgDither->GetValue();
+ editPrefs->ditherBest = ditherBest->GetValue();
+ editPrefs->rgbSpace = rgbSpace->GetSelection();
+ editPrefs->movieMode = movieMode->GetSelection();
+ editPrefs->imgBBox = imgBBox->GetValue();
+ editPrefs->imgZpro = asctoi(imgZpro->GetValue());
+ editPrefs->imgClipz = asctoi(imgClipz->GetValue());
+ editPrefs->imgScale = asctof(imgScale->GetValue());
+ editPrefs->imgPixThreshLow = asctof(imgPixThreshLow->GetValue());
+ editPrefs->imgPixThreshHigh = asctof(imgPixThreshHigh->GetValue());
+ editPrefs->imgWgtThresh = asctof(imgWgtThresh->GetValue());
+ editPrefs->imgWgtQuant = asctoi(imgWgtQuant->GetValue());
+ editPrefs->imgRgbBrightness = imgRgbBrightness->GetValue();
+ editPrefs->imgVoxForType = imgVoxForType->GetValue();
+ editPrefs->imgLight = imgLight->GetValue();
+ editPrefs->imgLightAngle = atof(imgLightAngle->GetValue());
+ editPrefs->imgLightAmbient = atof(imgLightAmbient->GetValue());
+ editPrefs->imgLightGain = atof(imgLightGain->GetValue());
+ editPrefs->imgKernSize = imgKernSize->GetSelection();
+ editPrefs->imgKernType = imgKernType->GetSelection();
+ editPrefs->imgLightScintAngle = atof(imgLightScintAngle->GetValue());
+ editPrefs->imgLightDir = imgLightDir->GetValue();
+ editPrefs->imgLightDist = asctoi(imgLightDist->GetValue());
+ editPrefs->imgUseVCol = imgUseVCol->GetValue();
+ editPrefs->imgVoxColour = asctof(imgVoxColour->GetValue());
+ editPrefs->imgHeightGrid = atoi(imgHeightGrid->GetValue());
+ editPrefs->imgHeightScale = atof(imgHeightScale->GetValue());
+ editPrefs->imgOrthoBBox = imgOrthoBBox->GetValue();
+ editPrefs->imgOrthoDragRel = imgOrthoDragRel->GetValue();
+ editPrefs->imgOrthoThick = atoi(imgOrthoThick->GetValue());
+ editPrefs->chartCosys = chartCosys->GetValue();
+ editPrefs->chartStep = atoi(chartStep->GetValue());
+ editPrefs->chartMarkx = atoi(chartMarkx->GetValue());
+ editPrefs->chartMarky = atof(chartMarky->GetValue());
+ editPrefs->tableCosys = tableCosys->GetValue();
+ editPrefs->tableStepx = atoi(tableStepx->GetValue());
+ editPrefs->tableStepy = atoi(tableStepy->GetValue());
+ editPrefs->thumbProjdim = atoi(thumbProjdim->GetValue());
+ editPrefs->thumbProjstep = atoi(thumbProjstep->GetValue());
+ editPrefs->thumbWidth = atoi(thumbWidth->GetValue());
+ editPrefs->thumbCols = atoi(thumbCols->GetValue());
+ editPrefs->soundFreq = atoi(soundFrequencyChoices[soundFreq->GetSelection()]);
+ editPrefs->soundLatency = atoi(soundLatencyChoices[soundLatency->GetSelection()]);
+ editPrefs->soundLoop = soundLoop->GetValue();
+ editPrefs->transferFmt = transferFmt->GetSelection();
+ textWindowToString(editPrefs->transferParm, transferParm);
+ editPrefs->storageFmt = storageFmt->GetSelection();
+ textWindowToString(editPrefs->storageParm, storageParm);
+
+ switch (imgMode->GetSelection())
+ {
+ case 1: editPrefs->imgMode = rim_voxel; break;
+ default: editPrefs->imgMode = rim_surf; break;
+ }
+ switch (chartMode->GetSelection())
+ {
+ case 1: editPrefs->chartMode = rcm_line; break;
+ case 2: editPrefs->chartMode = rcm_spline; break;
+ default: editPrefs->chartMode = rcm_bar; break;
+ }
+ switch (tableMode->GetSelection())
+ {
+ case 1: editPrefs->tableMode = 8; break;
+ case 2: editPrefs->tableMode = 16; break;
+ default: editPrefs->tableMode = 10; break;
+ }
+ if (csmap != NULL)
+ {
+ csmap->getParameters(&(editPrefs->csp));
+ }
+}
+
+
+void rviewPrefsWindow::updateAndDie(void)
+{
+ updatePrefs();
+ if (myParent != NULL) myParent->closeEditor(editPrefs);
+ editPrefs = NULL;
+}
+
+
+int rviewPrefsWindow::process(wxObject &obj, wxEvent &evt)
+{
+ int type = evt.GetEventType();
+
+ if (type == wxEVENT_TYPE_BUTTON_COMMAND)
+ {
+ if (&obj == (wxObject*)butOK)
+ {
+ updateAndDie();
+ return 1;
+ }
+ else if (&obj == (wxObject*)butApply)
+ {
+ updatePrefs();
+ if (myParent != NULL) myParent->updatePrefs(editPrefs);
+ return 1;
+ }
+ else if (&obj == (wxObject*)butCancel)
+ {
+ delete editPrefs; editPrefs = NULL;
+ if (myParent != NULL) myParent->closeEditor(NULL);
+ return 1;
+ }
+ else if (&obj == (wxObject*)cstrap)
+ {
+ if (csmap == NULL)
+ {
+ r_Ref<r_GMarray> dummyMdd;
+
+ csmap = new colourspaceMapper(dummyMdd, rbt_none, &(editPrefs->csp), TRUE, NULL);
+ }
+ csmap->openEditor();
+ }
+ }
+ else if (type == wxEVENT_TYPE_TEXT_ENTER_COMMAND)
+ {
+ updateAndDie();
+ }
+ else if ((type == wxEVENT_TYPE_SCROLLBAR_COMMAND) && (&obj == (wxObject*)scroll))
+ {
+ int x, y, posy;
+
+ GetClientSize(&x, &y);
+ posy = scroll->GetValue();
+ panel->SetSize(0, -posy, x - prefs_border - prefs_scrwidth, y + posy - prefs_bottom - prefs_border, wxSIZE_ALLOW_MINUS_ONE);
+ }
+
+ return 0;
+}
+
+
+void rviewPrefsWindow::setupVariables(void)
+{
+ editPrefs = NULL; myParent = NULL;
+ panel = NULL; csmap = NULL;
+}
+
+
+int rviewPrefsWindow::findInChoices(int value, const char **choices, int number)
+{
+ int i;
+ int lastval, newval;
+
+ lastval = atoi(choices[0]);
+ for (i=1; i<number; i++)
+ {
+ newval = atoi(choices[i]);
+ if ((lastval <= value) && (value < newval)) break;
+ lastval = newval;
+ }
+ return i-1;
+}
+
+
+int rviewPrefsWindow::userEvent(const user_event &ue)
+{
+ if ((ue.type == usr_cspace_changed) && (ue.data == (void*)csmap))
+ {
+ csmap->getParameters(&(editPrefs->csp));
+ return 1;
+ }
+ return 0;
+}
diff --git a/applications/rview/rviewPrefs.hh b/applications/rview/rviewPrefs.hh
new file mode 100644
index 0000000..d1cc181
--- /dev/null
+++ b/applications/rview/rviewPrefs.hh
@@ -0,0 +1,275 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+ * PURPOSE:
+ *
+ * Management of rView's preferences. This includes an object encapsulating
+ * the preferences and providing IO of these preferences (rviewPrefs) and a
+ * frame class that allows displaying / editing the current preferences
+ * (rviewPrefsWindow).
+ *
+ * COMMENTS:
+ * none
+ */
+
+
+
+#ifndef _RVIEW_PREFS_H_
+#define _RVIEW_PREFS_H_
+
+// #include "wx_scrol.h"
+#include "wx/xrc/xh_scrol.h"
+
+#include "raslib/mddtypes.hh"
+
+#include "rviewUtils.hh"
+#include "rviewDModes.hh"
+
+
+
+// Needed by rviewPrefsWindow. Full definition below.
+class rviewPrefs;
+
+
+
+
+/*
+ * The window for editing the preferences
+ */
+class rviewPrefsWindow: public rviewFrame
+{
+ public:
+
+ rviewPrefsWindow(void);
+ rviewPrefsWindow(rviewPrefs *Prefs);
+ ~rviewPrefsWindow(void);
+
+ void setPrefs(rviewPrefs *Prefs);
+
+ void unlinkParent(void);
+
+ void OnSize(int w, int h);
+
+ void label(void);
+ int process(wxObject &obj, wxEvent &evt);
+ int userEvent(const user_event &ue);
+
+ virtual const char *getFrameName(void) const;
+ virtual rviewFrameType getFrameType(void) const;
+
+
+ protected:
+
+ void setupVariables(void);
+ void updatePrefs(void);
+ void updateAndDie(void);
+ int findInChoices(int value, const char **choices, int number);
+
+ static rviewChoice *buildFormatMenu(wxPanel *parent, int fmtNum, const char *label);
+ static void textWindowToString(DynamicString &str, wxTextWindow *twin);
+
+ rviewPrefs *editPrefs;
+ rviewPrefs *myParent;
+
+ wxPanel *panel, *butPanel;
+ rviewButton *butOK, *butCancel, *butApply;
+ // wxGroupBox *miscGroup, *imgGroup, *renderGroup, *thumbGroup, *heightGroup;
+ // wxGroupBox *chartGroup, *tableGroup, *soundGroup, *commGroup, *orthoGroup;
+ wxWindowBase *miscGroup, *imgGroup, *renderGroup, *thumbGroup, *heightGroup;
+ wxWindowBase *chartGroup, *tableGroup, *soundGroup, *commGroup, *orthoGroup;
+ rviewText *filePath, *queryPath, *queryFont;
+ rviewText *vffParams;
+ rviewText *maxDWidth, *maxDHeight;
+ rviewCheckBox *imgDither, *ditherBest;
+ rviewChoice *imgMode, *chartMode, *tableMode, *rgbSpace, *movieMode;
+ rviewCheckBox *imgBBox;
+ rviewText *imgZpro, *imgClipz, *imgPixThreshLow, *imgPixThreshHigh, *imgWgtThresh, *imgWgtQuant;
+ rviewText *imgScale;
+ rviewCheckBox *imgRgbBrightness, *imgVoxForType;
+ rviewCheckBox *imgLight;
+ rviewText *imgLightAmbient, *imgLightGain, *imgLightAngle, *imgLightScintAngle;
+ rviewChoice *imgKernSize, *imgKernType;
+ rviewCheckBox *imgUseVCol;
+ rviewText *imgVoxColour;
+ rviewText *imgLightDir, *imgLightDist;
+ rviewCheckBox *imgOrthoBBox, *imgOrthoDragRel;
+ rviewText *imgOrthoThick;
+ rviewCheckBox *chartCosys;
+ rviewText *chartStep, *chartMarkx, *chartMarky;
+ rviewCheckBox *tableCosys;
+ rviewText *tableStepx, *tableStepy;
+ rviewText *thumbProjdim, *thumbProjstep, *thumbWidth, *thumbCols;
+ rviewChoice *soundFreq, *soundLatency;
+ rviewCheckBox *soundLoop;
+ rviewText *imgHeightGrid, *imgHeightScale;
+ rviewChoice *transferFmt, *storageFmt;
+ wxTextWindow *transferParm, *storageParm;
+ wxMessage *transferMsg, *storageMsg;
+ wxScrollBar *scroll;
+ rviewButton *cstrap;
+ colourspaceMapper *csmap;
+
+ // constants
+ static const char *soundLatencyChoices[];
+ static const char *soundFrequencyChoices[];
+
+ // Width and height of preferences window
+ static const int prefs_width;
+ static const int prefs_height;
+ // Borders used in prefs window
+ static const int prefs_border;
+ // Space at the bottom for button bar
+ static const int prefs_bottom;
+ // Button dimensions
+ static const int prefs_bwidth;
+ static const int prefs_bheight;
+ // Height of a text widget
+ static const int prefs_theight;
+ // Height of a checkbox
+ static const int prefs_chkheight;
+ // Height of a text widget's writable field
+ static const int prefs_eheight;
+ // ScrollBar width
+ static const int prefs_scrwidth;
+ // TextWindow height
+ static const int prefs_twheight;
+ // Message height
+ static const int prefs_mheight;
+ // Group boxes
+ static const int prefs_grpmsc_height;
+ static const int prefs_grpimg_height;
+ static const int prefs_grpren_height;
+ static const int prefs_grphgt_height;
+ static const int prefs_grport_height;
+ static const int prefs_grpthb_height;
+ static const int prefs_grpcht_height;
+ static const int prefs_grptab_height;
+ static const int prefs_grpsnd_height;
+ static const int prefs_grpcom_height;
+ // Height of panel
+ static const int prefs_pheight;
+};
+
+
+/*
+ * Object holding the preferences and the current setup.
+ */
+class rviewPrefs
+{
+ public:
+
+ rviewPrefs(void);
+ rviewPrefs(const char *file);
+ rviewPrefs(const rviewPrefs &srcPrefs);
+ ~rviewPrefs(void);
+
+ int load(const char *file);
+ int save(const char *file);
+ int edit(void);
+ void editorClosed(void);
+ void closeEditor(rviewPrefs *newPrefs);
+ void updatePrefs(rviewPrefs *newPrefs);
+ void markModified(void);
+
+ static void copyPrefs(const rviewPrefs &src, rviewPrefs &dest);
+
+ r_Data_Format getTransferFormat( void ) const;
+ r_Data_Format getStorageFormat( void ) const;
+
+ DynamicString serverName;
+ int serverPort;
+ DynamicString databaseName;
+ DynamicString userName;
+ DynamicString lastColl;
+ DynamicString lastScColl;
+ DynamicString lastOrthoColl;
+ DynamicString filePath;
+ DynamicString queryPath;
+ DynamicString queryFont;
+ DynamicString vffParams;
+ int lastDisplay;
+ int maxDWidth, maxDHeight;
+ bool imgDither, ditherBest;
+ rviewImageMode imgMode;
+ rviewChartMode chartMode;
+ int movieMode, rgbSpace;
+ int tableMode;
+ bool imgBBox;
+ unsigned long imgZpro, imgClipz, imgWgtQuant;
+ double imgPixThreshLow, imgPixThreshHigh, imgWgtThresh;
+ double imgScale;
+ bool imgRgbBrightness, imgVoxForType;
+ bool imgLight;
+ double imgLightAmbient, imgLightGain, imgLightAngle, imgLightScintAngle;
+ int imgKernSize, imgKernType;
+ bool imgUseVCol;
+ double imgVoxColour;
+ DynamicString imgLightDir;
+ int imgLightDist;
+ int imgHeightGrid;
+ double imgHeightScale;
+ bool imgOrthoBBox, imgOrthoDragRel;
+ int imgOrthoThick;
+ bool chartCosys;
+ int chartStep, chartMarkx;
+ double chartMarky;
+ bool tableCosys;
+ int tableStepx, tableStepy;
+ int thumbProjdim, thumbProjstep, thumbWidth, thumbCols;
+ int soundFreq, soundLatency, soundLoop;
+ int transferFmt, storageFmt;
+ DynamicString transferParm, storageParm;
+ colourspace_params csp;
+
+
+ protected:
+
+ void setupVariables(void);
+ // used for getting the value of an argument when reading the prefs file.
+ char *getValue(char *b);
+ // convert long strings (including newlines) from/to external representation
+ static char *toExternal(const DynamicString &str);
+ static void fromExternal(const char *ext, DynamicString &str);
+ // read a line into the internal buffer; return a pointer to the start if successful
+ char *readLine(FILE *fp);
+
+ rviewPrefsWindow *pwin;
+ bool prefsModified;
+
+ char *inbuff;
+ unsigned long buffSize;
+
+ static const unsigned long buffExtendGranularity;
+ static const keyword_to_ident_c prefsVarDesc[];
+};
+
+
+
+/*
+ * Global variables
+ */
+
+extern rviewPrefs *prefs;
+
+#endif
diff --git a/applications/rview/rviewQuery.cpp b/applications/rview/rviewQuery.cpp
new file mode 100644
index 0000000..eddbd7f
--- /dev/null
+++ b/applications/rview/rviewQuery.cpp
@@ -0,0 +1,647 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+ * PURPOSE:
+ *
+ * rView query shell. Handles editing, loading, saving and execution
+ * of RasQL queries. Actual database accesses are performed through
+ * class rView's member functions.
+ *
+ * COMMENTS:
+ * None
+ */
+
+
+
+// Standard wxWindows preamble.
+#ifdef __GNUG__
+#pragma implementation
+#endif
+
+
+#include <wx/wxprec.h>
+
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+
+#ifndef WX_PRECOMP
+#include <wx/wx.h>
+#endif
+
+
+
+#include <string.h>
+#include <iostream.h>
+#include <ctype.h>
+
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#endif
+
+#include "raslib/rmdebug.hh"
+
+#include "rviewApp.hh"
+#include "rviewUtils.hh"
+//#include "rviewDb.hh"
+#include "rviewQuery.hh"
+#include "rviewPrefs.hh"
+
+
+
+
+const int rviewQuery::query_width = 500;
+const int rviewQuery::query_height = 300;
+const int rviewQuery::query_border = 8;
+const int rviewQuery::query_bottom = 50;
+const int rviewQuery::query_bwidth = 80;
+const int rviewQuery::query_bheight = 40;
+
+
+
+
+const char rviewQuery::query_extension[] = ".ql";
+const char rviewQuery::query_firstline[] = "-- rview-Query";
+
+
+
+// The Query window counter
+int rviewQuery::queryCounter = 0;
+
+
+// Lookup tables for fonts. These have to be sorted case-sensitively!
+const keyword_to_ident_c rviewQuery::fontNameTab[] = {
+ {wxDECORATIVE, "decorative"},
+ {wxDEFAULT, "default"},
+ {wxMODERN, "modern"},
+ {wxROMAN, "roman"},
+ {wxSCRIPT, "script"},
+ {wxSWISS, "swiss"},
+ {wxTELETYPE, "teletype"}
+};
+const keyword_to_ident_c rviewQuery::fontStyleTab[] = {
+ {wxITALIC, "italic"},
+ {wxSLANT, "slant"}
+};
+
+const keyword_to_ident_c rviewQuery::fontWeightTab[] = {
+ {wxBOLD, "bold"},
+ {wxLIGHT, "light"}
+};
+
+
+
+
+rviewQuery::rviewQuery(rviewDatabase *db, char *query) : rviewFrame(NULL, NULL, 0, 0, query_width, query_height)
+{
+ int w, h;
+ const char *b;
+ char *d;
+ char buffer[STRINGSIZE];
+ int fontSize, fontName, fontStyle, fontWeight;
+ const int fontNameSize = sizeof(fontNameTab) / sizeof(keyword_to_ident);
+ const int fontStyleSize = sizeof(fontStyleTab) / sizeof(keyword_to_ident);
+ const int fontWeightSize = sizeof(fontWeightTab) / sizeof(keyword_to_ident);
+
+ RMDBGENTER(3, RMDebug::module_applications, "rviewQuery", "rviewQuery()");
+
+ queryDb = db;
+ updateDisplay = NULL;
+
+ CreateStatusLine(1);
+
+ mbar = NULL;
+ for (w=0; w<3; w++) mbarMenus[w] = NULL;
+
+ if (::wxDirExists((char*)(prefs->queryPath.ptr())))
+ hotPath = prefs->queryPath;
+ else
+ hotPath = ".";
+
+ // Read font from prefs
+ b = prefs->queryFont;
+ fontSize = 12; fontName = wxDEFAULT; fontStyle = wxNORMAL; fontWeight = wxNORMAL;
+ while (*b != 0)
+ {
+ while ((*b == ' ') || (*b == ',')) b++;
+ if (*b == 0) break;
+ d = buffer;
+ while ((*b != ' ') && (*b != ',') && (*b != 0)) {*d++ = *b++;}
+ *d++ = 0;
+ w = atoi(buffer);
+ if (w != 0) fontSize = w;
+ else
+ {
+ if ((w = rviewLookupKeyword(buffer, fontNameTab, fontNameSize, FALSE)) >= 0)
+ fontName = w;
+ else if ((w = rviewLookupKeyword(buffer, fontStyleTab, fontStyleSize, FALSE)) >= 0)
+ fontStyle = w;
+ else if ((w = rviewLookupKeyword(buffer, fontWeightTab, fontWeightSize, FALSE)) >= 0)
+ fontWeight = w;
+ else
+ cerr << "Bad identifier in font string: " << buffer << endl;
+ }
+ }
+ //cout << "size " << fontSize << ", name " << fontName << ", style " << fontStyle << ", weight " << fontWeight << endl;
+
+ font = new wxFont(fontSize, fontName, fontStyle, fontWeight);
+ //font = ::wxTheFontList->FindOrCreateFont(fontSize, fontName, fontStyle, fontWeight);
+ //cout << "Font " << font->GetPointSize() << ',' << font->GetFamily() << ',' << font->GetStyle() << endl;
+
+ GetClientSize(&w, &h);
+
+ // Set identifier
+ qwindowID = queryCounter++;
+ updateID = -1; // no update object
+
+ w -= 2*query_border; h -= query_bottom;
+ twin = new wxTextWindow((wxWindow*)this, query_border, query_border, w, h - 2*query_border, wxBORDER | wxNATIVE_IMPL);
+
+ twin->SetFont(font);
+
+ panel = new wxPanel((wxWindow*)this, query_border, h, w, query_bottom);
+ butClear = new rviewButton(panel);
+ butExec = new rviewButton(panel);
+ butUpdt = new rviewButton(panel);
+
+ if (query != NULL)
+ {
+ twin->WriteText(query);
+ }
+
+ buildMenubar();
+
+ newDBState(rmanClientApp::theApp()->ReadDBState());
+
+ label();
+
+ OnSize(w, h);
+
+ Show(TRUE);
+}
+
+
+rviewQuery::~rviewQuery(void)
+{
+ // If an update window is open notify it.
+ if (updateDisplay != NULL)
+ {
+ updateDisplay->noLongerUpdate();
+ }
+}
+
+
+const char *rviewQuery::getFrameName(void) const
+{
+ return "rviewQuery";
+}
+
+rviewFrameType rviewQuery::getFrameType(void) const
+{
+ return rviewFrameTypeQuery;
+}
+
+
+void rviewQuery::OnSize(int w, int h)
+{
+ int x, y;
+
+ GetClientSize(&x, &y);
+ if ((frameWidth == x) && (frameHeight == y)) return;
+ frameWidth = x; frameHeight = y;
+
+ x -= 2*query_border; y -= query_bottom;
+ twin->SetSize(query_border, query_border, x, y - 2*query_border);
+
+ panel->SetSize(query_border, y, x, query_bottom);
+
+ y = (query_bottom - query_bheight) / 2;
+
+ x = (x - 3*query_bwidth) / 3;
+ butClear->SetSize(x/2, y, query_bwidth, query_bheight);
+ butExec->SetSize((3*x)/2 + query_bwidth, y, query_bwidth, query_bheight);
+ butUpdt->SetSize((5*x)/2 + 2*query_bwidth, y, query_bwidth, query_bheight);
+
+ // doesn't work, unfortunately
+ /*if (mbar != NULL)
+ {
+ int hw, hh;
+
+ mbar->GetSize(&x, &y);
+ mbarMenus[3]->GetSize(&hw, &hh);
+ mbarMenus[3]->SetSize(x-hw, (y-hh)/2, hw, hh);
+ }*/
+}
+
+
+void rviewQuery::OnMenuCommand(int id)
+{
+ // Load query from hotlist?
+ if ((id >= MENU_QUERY_HOTLIST) && (id < MENU_QUERY_HOTLIST + hotNumber))
+ {
+ char buffer[STRINGSIZE];
+
+ sprintf(buffer, "%s"DIR_SEPARATOR"%s%s", hotPath.ptr(), mbar->GetLabel(id), query_extension);
+ loadQuery(buffer);
+ return;
+ }
+
+ switch (id)
+ {
+ case MENU_QUERY_FILE_OPEN:
+ case MENU_QUERY_FILE_SAVE:
+ {
+ char *name, *aux;
+ char *prefDir = (char*)(hotPath.ptr());
+ char filter[16];
+
+ sprintf(filter, "*%s", query_extension);
+ if (::wxDirExists(prefDir)) name = prefDir; else name = ".";
+ name = ::wxFileSelector(lman->lookup((id == MENU_QUERY_FILE_OPEN) ? "titleQueryLoad" : "titleQuerySave"), name, NULL, NULL, filter, 0 , this);
+ if (name != NULL)
+ {
+ aux = ::wxFileNameFromPath(name);
+ if (strlen(aux) > 0)
+ {
+ if (id == MENU_QUERY_FILE_OPEN)
+ {
+ RMDBGONCE(3, RMDebug::module_applications, "rviewQuery", "loadQuery()");
+ loadQuery(name);
+ }
+ else
+ {
+ RMDBGONCE(3, RMDebug::module_applications, "rviewQuery", "saveQuery()");
+ saveQuery(name);
+ }
+ hotPath = ::wxPathOnly(name);
+ prefs->queryPath = hotPath;
+ prefs->markModified();
+ buildMenubar();
+ }
+ }
+ }
+ break;
+ case MENU_QUERY_FILE_EXIT: this->Close(TRUE); break;
+ case MENU_QUERY_EDIT_CUT: twin->Cut(); break;
+ case MENU_QUERY_EDIT_COPY: twin->Copy(); break;
+ case MENU_QUERY_EDIT_PASTE: twin->Paste(); break;
+ default: break;
+ }
+}
+
+
+
+void rviewQuery::buildMenubar(void)
+{
+ char pattern[STRINGSIZE], leaf[STRINGSIZE];
+ char *f;
+ char *qhots[MENU_QUERY_HOTRANGE];
+ int i;
+ wxMenu *hotList;
+
+ // Do we actually need to rebuild the menu?
+ if ((mbar != NULL) && (strcmp(hotPath, lastHotPath) == 0)) return;
+
+ // build hotlist menu
+ hotList = new wxMenu;
+ sprintf(pattern, "%s"DIR_SEPARATOR"*%s", hotPath.ptr(), query_extension);
+
+ // Sort the hotlist alphabetically
+ f = ::wxFindFirstFile(pattern); hotNumber = 0;
+ while (f && (hotNumber < MENU_QUERY_HOTRANGE))
+ {
+ strcpy(leaf, ::wxFileNameFromPath(f));
+ f = strstr(leaf, query_extension);
+ if (f != NULL) *f = '\0';
+ if ((qhots[hotNumber] = new char[strlen(leaf) + 1]) == NULL) break;
+ strcpy(qhots[hotNumber], leaf);
+ hotNumber++;
+ f = wxFindNextFile();
+ }
+
+ rviewQuicksortStrings(qhots, 0, hotNumber-1);
+
+ for (i=0; i<hotNumber; i++)
+ {
+ //cout << "Item " << i << ": " << qhots[i] << endl;
+ hotList->Append(MENU_QUERY_HOTLIST + i, qhots[i]);
+ delete [] qhots[i];
+ }
+
+ if (mbar == NULL)
+ {
+ mbarMenus[0] = new wxMenu;
+ mbarMenus[0]->Append(MENU_QUERY_FILE_OPEN, "");
+ mbarMenus[0]->Append(MENU_QUERY_FILE_SAVE, "");
+ mbarMenus[0]->Append(MENU_QUERY_FILE_EXIT, "");
+
+ mbarMenus[1] = new wxMenu;
+ mbarMenus[1]->Append(MENU_QUERY_EDIT_CUT, "");
+ mbarMenus[1]->Append(MENU_QUERY_EDIT_COPY, "");
+ mbarMenus[1]->Append(MENU_QUERY_EDIT_PASTE, "");
+
+ mbarMenus[2] = hotList;
+
+
+ mbar = new wxMenuBar;
+ sprintf(pattern, "&%s", lman->lookup("menQueryFile"));
+ mbar->Append(mbarMenus[0], pattern);
+ sprintf(pattern, "&%s", lman->lookup("menQueryEdit"));
+ mbar->Append(mbarMenus[1], pattern);
+ sprintf(pattern, "&%s", lman->lookup("menQueryHotlist"));
+ mbar->Append(mbarMenus[2], pattern);
+
+ SetMenuBar(mbar);
+ }
+ else
+ {
+ mbar->Delete(mbarMenus[2], 2);
+ sprintf(pattern, "&%s", lman->lookup("menQueryHotlist"));
+ mbar->Append(hotList, pattern);
+ delete mbarMenus[2];
+ mbarMenus[2] = hotList;
+ }
+}
+
+
+
+void rviewQuery::label(void)
+{
+ updateTitle();
+
+ mbar->SetLabel(MENU_QUERY_FILE_OPEN, lman->lookup("menQueryFileOpen"));
+ mbar->SetLabel(MENU_QUERY_FILE_SAVE, lman->lookup("menQueryFileSave"));
+ mbar->SetLabel(MENU_QUERY_FILE_EXIT, lman->lookup("menQueryFileClose"));
+ mbar->SetHelpString(MENU_QUERY_FILE_OPEN, lman->lookup("helpQueryFileOpen"));
+ mbar->SetHelpString(MENU_QUERY_FILE_SAVE, lman->lookup("helpQueryFileSave"));
+ mbar->SetHelpString(MENU_QUERY_FILE_EXIT, lman->lookup("helpQueryFileClose"));
+
+ mbar->SetLabel(MENU_QUERY_EDIT_CUT, lman->lookup("menQueryEditCut"));
+ mbar->SetLabel(MENU_QUERY_EDIT_COPY, lman->lookup("menQueryEditCopy"));
+ mbar->SetLabel(MENU_QUERY_EDIT_PASTE, lman->lookup("menQueryEditPaste"));
+ mbar->SetHelpString(MENU_QUERY_EDIT_CUT, lman->lookup("helpQueryEditCut"));
+ mbar->SetHelpString(MENU_QUERY_EDIT_COPY, lman->lookup("helpQueryEditCopy"));
+ mbar->SetHelpString(MENU_QUERY_EDIT_PASTE, lman->lookup("helpQueryEditPaste"));
+
+ mbar->SetLabelTop(0, lman->lookup("menQueryFile"));
+ mbar->SetLabelTop(1, lman->lookup("menQueryEdit"));
+ mbar->SetLabelTop(2, lman->lookup("menQueryHotlist"));
+
+ butClear->SetLabel(lman->lookup("textClear"));
+ butExec->SetLabel(lman->lookup("textExec"));
+ butUpdt->SetLabel(lman->lookup("textUpdt"));
+}
+
+
+void rviewQuery::updateTitle(void)
+{
+ if (updateID == -1)
+ {
+ SetTitle(lman->lookup("titleQuery"));
+ }
+ else
+ {
+ char buffer[STRINGSIZE];
+ sprintf(buffer, "%s q%dd%d", lman->lookup("titleQuery"), qwindowID, updateID);
+ SetTitle(buffer);
+ }
+}
+
+
+int rviewQuery::process(wxObject &obj, wxEvent &evt)
+{
+ int type = evt.GetEventType();
+
+ if (type == wxEVENT_TYPE_BUTTON_COMMAND)
+ {
+ if (&obj == (wxObject*)butClear)
+ {
+ twin->Clear();
+ return 1;
+ }
+ if (&obj == (wxObject*)butExec)
+ {
+ int numl = twin->GetNumberOfLines();
+ int i, totalLength = 1;
+ char *b, *query;
+
+ query = twin->GetContents();
+
+ // Execute query.
+ i = rmanClientApp::theApp()->executeQuery(query, (updateDisplay == NULL) ? NULL : &updateMddObj);
+ // Did it fail?
+ if (i == 0)
+ {
+ int line, column;
+
+ // Was it a query error?
+ if (queryDb->getErrorInfo(line, column) != 0)
+ {
+ long offset = twin->XYToPosition(column-1, line-1);
+
+ // query was big enough to hold the entore query, so it's definitely
+ // big enough to hold one line
+ twin->GetLineText(line-1, query);
+ b = query + column-1;
+ while ((*b != ' ') && (!iscntrl(*b))) b++;
+ twin->SetSelection(offset, offset + (long)(b - (query + column-1)));
+ }
+ }
+ delete [] query;
+ // Notify that we did something, not whether it was a success
+ return 1;
+ }
+ if (&obj == (wxObject*)butUpdt)
+ {
+ rviewDisplay *newDisplay;
+
+ // Don't set updateDisplay directly. We might have a valid update image and
+ // issued a cancel from the file selection box.
+ if ((newDisplay = (rviewDisplay*)rmanClientApp::theApp()->OpenFile(rviewDisplay::display_flag_update, &updateMddObj, FALSE)) != NULL)
+ {
+ if (updateDisplay != NULL)
+ {
+ updateDisplay->noLongerUpdate();
+ }
+ updateDisplay = newDisplay;
+ updateDisplay->setQueryWindow(qwindowID);
+ updateID = updateDisplay->getIdentifier();
+ updateTitle();
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+
+int rviewQuery::getIdentifier(void) const
+{
+ return qwindowID;
+}
+
+int rviewQuery::getQueryCounter(void) const
+{
+ return queryCounter;
+}
+
+
+
+int rviewQuery::userEvent(const user_event &ue)
+{
+ if ((ue.type == usr_db_opened) || (ue.type == usr_db_closed))
+ {
+ newDBState((ue.type == usr_db_opened));
+ return 1;
+ }
+ if ((updateDisplay != NULL) && (ue.type == usr_update_closed))
+ {
+ r_Ref<r_GMarray> *whichMdd = (r_Ref<r_GMarray>*)(ue.data);
+ if (*whichMdd == updateMddObj)
+ {
+ updateDisplay = NULL; updateID = -1;
+ updateTitle();
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+void rviewQuery::newDBState(bool newState)
+{
+ butExec->Enable(newState);
+}
+
+
+bool rviewQuery::loadQuery(char *file)
+{
+ size_t length;
+ int idlength;
+ char *buffer, *b;
+ FILE *fp;
+
+ if ((fp = fopen(file, "rb")) == NULL)
+ {
+ char msg[STRINGSIZE];
+ sprintf(msg, "%s %s", lman->lookup("errorFileOpen"), file);
+ rviewErrorbox::reportError(msg, rviewQuery::getFrameName(), "loadQuery");
+ return FALSE;
+ }
+
+ fseek(fp, 0, SEEK_END);
+ length = ftell(fp);
+ if ((buffer = new char[length+1]) == NULL)
+ {
+ rviewErrorbox::reportError(lman->lookup("errorMemory"), rviewQuery::getFrameName(), "loadQuery");
+ fclose(fp); return FALSE;
+ }
+ fseek(fp, 0, SEEK_SET);
+
+ b = buffer;
+ for (idlength=0; idlength<(int)length; idlength++)
+ {
+ int c;
+
+ if ((c = fgetc(fp)) == EOF) break;
+#ifdef __VISUALC__
+ if (c != '\r')
+#endif
+ *b++ = c;
+ }
+ *b++ = '\0';
+
+ if (idlength < (int)length)
+ {
+ char msg[STRINGSIZE];
+ sprintf(msg, "%s %s", lman->lookup("errorFileRead"), file);
+ rviewErrorbox::reportError(msg, rviewQuery::getFrameName(), "loadQuery");
+ fclose(fp);
+ return FALSE;
+ }
+
+ fclose(fp);
+
+ idlength = strlen("RasDaView-Query");
+ if (strncmp(buffer, "RasDaView-Query", idlength) != 0)
+ {
+ idlength = strlen(query_firstline);
+ if (strncmp(buffer,query_firstline, idlength) != 0) idlength = -1;
+ }
+ if (idlength < 0)
+ {
+ rviewErrorbox::reportError(lman->lookup("errorQueryFile"), rviewQuery::getFrameName(), "loadQuery");
+ delete [] buffer;
+ return FALSE;
+ }
+ twin->Clear();
+ twin->WriteText(buffer + idlength + 1);
+ delete [] buffer;
+ return TRUE;
+}
+
+
+bool rviewQuery::saveQuery(char *file)
+{
+ FILE *fp;
+ char *buffer, *b, *upper;
+
+ if ((fp = fopen(file, "wb")) == NULL)
+ {
+ char msg[STRINGSIZE];
+ sprintf(msg, "%s %s", lman->lookup("errorFileOpen"), file);
+ rviewErrorbox::reportError(msg, rviewQuery::getFrameName(), "saveQuery");
+ return FALSE;
+ }
+
+ fprintf(fp, query_firstline); fputc('\n', fp);
+ buffer = twin->GetContents();
+ b = buffer; upper = buffer + strlen(buffer);
+
+ while (b < upper)
+ {
+#ifdef __VISUALC__
+ if (*b != '\r')
+#endif
+ if (fputc(*b, fp) != *b) break;
+ b++;
+ }
+ if (b != upper)
+ {
+ char msg[STRINGSIZE];
+ sprintf(msg, "%s %s", lman->lookup("errorFileWrite"), file);
+ rviewErrorbox::reportError(msg, rviewQuery::getFrameName(), "saveQuery");
+ fclose(fp);
+ return FALSE;
+ }
+
+ fclose(fp);
+
+ delete [] buffer;
+
+ return TRUE;
+}
diff --git a/applications/rview/rviewQuery.hh b/applications/rview/rviewQuery.hh
new file mode 100644
index 0000000..2a18fbc
--- /dev/null
+++ b/applications/rview/rviewQuery.hh
@@ -0,0 +1,128 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+ * PURPOSE:
+ *
+ * rView query shell. Handles editing, loading, saving and execution
+ * of RasQL queries. Actual database accesses are performed through
+ * class rView's member functions.
+ *
+ * COMMENTS:
+ * None
+ */
+
+
+
+#ifndef _RVIEW_QUERY_H_
+#define _RVIEW_QUERY_H_
+
+
+#ifdef __GNUG__
+#pragma interface
+#endif
+
+
+
+#include "rviewUtils.hh"
+#include "rviewDb.hh"
+
+
+
+
+
+class rviewQuery: public rviewFrame
+{
+ public:
+
+ rviewQuery(rviewDatabase *db, char *query=NULL);
+ ~rviewQuery(void);
+
+ void OnSize(int w, int h);
+ void OnMenuCommand(int id);
+
+ void label(void);
+ int process(wxObject &obj, wxEvent &evt);
+
+ int userEvent(const user_event &ue);
+
+ virtual const char *getFrameName(void) const;
+ virtual rviewFrameType getFrameType(void) const;
+
+ // Returns the query window ID
+ int getIdentifier(void) const;
+ int getQueryCounter(void) const;
+
+
+ protected:
+
+ void buildMenubar(void);
+ bool loadQuery(char *file);
+ bool saveQuery(char *file);
+ void newDBState(bool newState);
+ void updateTitle(void);
+
+ wxTextWindow *twin;
+ wxMenuBar *mbar;
+ wxMenu *mbarMenus[3];
+ wxPanel *panel;
+ rviewButton *butClear, *butExec, *butUpdt;
+ wxFont *font;
+ int hotNumber;
+ DynamicString hotPath;
+ DynamicString lastHotPath;
+ rviewDatabase *queryDb;
+ // For update queries
+ rviewDisplay *updateDisplay;
+ r_Ref<r_GMarray> updateMddObj;
+ int qwindowID;
+ int updateID;
+
+ static const char query_extension[];
+ static const char query_firstline[];
+
+ static const keyword_to_ident_c fontNameTab[];
+ static const keyword_to_ident_c fontStyleTab[];
+ static const keyword_to_ident_c fontWeightTab[];
+
+ // constants
+ // Width and height of query window
+ static const int query_width;
+ static const int query_height;
+ // Borders in query window
+ static const int query_border;
+ // Height of control area at the bottom of the query
+ static const int query_bottom;
+ // Button dimensions
+ static const int query_bwidth;
+ static const int query_bheight;
+
+
+ private:
+
+ // Query window counter, realises a unique integer ID for each
+ // query window.
+ static int queryCounter;
+};
+
+#endif
diff --git a/applications/rview/rviewSound.cpp b/applications/rview/rviewSound.cpp
new file mode 100644
index 0000000..338e1a5
--- /dev/null
+++ b/applications/rview/rviewSound.cpp
@@ -0,0 +1,1738 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+ * PURPOSE:
+ *
+ * rView sound ``viewer'' for playing back MDD as audio samples.
+ * This file consists of two parts: the highly platform dependent
+ * SoundPlayer class providing the actual low-level sound playback
+ * and the general purpose wxWindows class rviewSoundPlayer that
+ * implements a typical rView display mode window and playback
+ * controls.
+ * The SoundPlayer class currently has implementations for Solaris
+ * and WindowsNT. Supporting other Unix brands only requires
+ * changes to SoundPlayer::configureDevice, supporting other
+ * platforms is considerably more complicated (see Unix vs. NT
+ * implementations).
+ *
+ * COMMENTS:
+ * None
+ */
+
+
+
+// Standard wxWindows preamble.
+#ifdef __GNUG__
+#pragma implementation
+#endif
+
+#ifndef __HAL_ONLY__
+// changed in wxWindows 2.4.2:
+//#include "wx_prec.h"
+#include <wx/wxprec.h>
+
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+
+#ifndef WX_PRECOMP
+#include <wx/wx.h>
+#endif
+
+#endif // HAL
+
+
+/* All platforms */
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <math.h>
+
+#include <iostream.h>
+
+/* Platform class (e.g. Unix) */
+#ifndef __VISUALC__
+
+#include <unistd.h>
+#include <fcntl.h>
+
+/* Platform specific */
+#ifdef __sun
+#include <multimedia/libaudio.h>
+#endif
+
+#endif
+
+
+#ifndef __HAL_ONLY__
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#endif
+
+#include "raslib/rmdebug.hh"
+#include "raslib/primitivetype.hh"
+#include "raslib/minterval.hh"
+//#include "rasodmg/odmgtypes.hh"
+#include "rasodmg/marray.hh"
+#include "rasodmg/ref.hh"
+
+#endif // HAL
+
+#include "rviewSound.hh"
+#ifndef __HAL_ONLY__
+#include "rviewTypes.hh"
+#include "rviewPrefs.hh"
+#include "labelManager.hh"
+#endif // HAL
+
+
+
+
+/* Minimum size of ulaw table */
+const int ULAW_LD_TABLE_MIN=10;
+/* log2 of the length of a linear segment in ulaw coding */
+const int ULAW_LD_LINEAR_SIZE=7;
+
+// general debug messages (should only enable on Unix)
+//#define SOUND_PLAYER_DEBUG
+// Debug output to file?
+//#define SOUND_DEBUG_FILE "Z:\\dehmel\\rview\\slog"
+
+
+
+const int rviewSoundPlayer::sound_bwidth = 50;
+const int rviewSoundPlayer::sound_bheight = 30;
+const int rviewSoundPlayer::sound_sheight = 50;
+const int rviewSoundPlayer::sound_twidth = 120;
+const int rviewSoundPlayer::sound_theight = 50;
+const int rviewSoundPlayer::sound_cwidth = 120;
+const int rviewSoundPlayer::sound_cheight = 30;
+const int rviewSoundPlayer::sound_ctrly = rviewSoundPlayer::sound_bheight + rviewSoundPlayer::sound_theight + rviewSoundPlayer::sound_sheight + 5*rviewDisplay::display_border;
+const int rviewSoundPlayer::sound_width = rviewDisplay::display_width;
+const int rviewSoundPlayer::sound_height = rviewDisplay::display_cheight + rviewSoundPlayer::sound_ctrly + 2*rviewDisplay::display_border;
+const int rviewSoundPlayer::sound_latencies = 11;
+
+
+
+
+/* Global variables and functions */
+static soundPlayer *activePlayer = NULL;
+static int inCallback = 0;
+
+#ifdef SOUND_DEBUG_FILE
+static FILE *debugfd=NULL;
+#endif
+
+
+#ifdef __VISUALC__
+VOID CALLBACK handle_sound_timer(HWND hWnd, UINT uMsg, UINT idEvent, DWORD dwTime)
+{
+#ifdef SOUND_PLAYER_DEBUG
+ cout << "timer called, time " << dwTime << endl;
+#endif
+
+ if ((activePlayer != NULL) && (inCallback == 0))
+ {
+ inCallback = 1;
+ activePlayer->writeSamples(dwTime);
+ inCallback = 0;
+ }
+}
+
+#else
+
+static void handle_sound_timer(int signal)
+{
+#ifdef SOUND_PLAYER_DEBUG
+ cout << "timer called " << signal << ", player " << (void*)activePlayer << ", inCallback " << inCallback << endl;
+#endif
+
+ if ((activePlayer != NULL) && (inCallback == 0))
+ {
+ inCallback = 1;
+ activePlayer->writeSamples();
+ inCallback = 0;
+ }
+}
+#endif
+
+
+
+
+/*
+ * soundPlayer: low-level sound driver, hardware abstraction layer
+ */
+
+soundPlayer::soundPlayer(void)
+{
+ setupVariables();
+}
+
+soundPlayer::soundPlayer(int frq, int ch, FILE *fp, rviewSoundFormat fmt, int lat)
+{
+ setupVariables();
+ newSample(frq, ch, fp, fmt, lat);
+}
+
+soundPlayer::soundPlayer(int frq, int ch, const signed char *data, int len, rviewSoundFormat fmt, int lat)
+{
+ setupVariables();
+ newSample(frq, ch, data, len, fmt, lat);
+}
+
+soundPlayer::soundPlayer(int frq, int ch, const unsigned char *data, int len, rviewSoundFormat fmt, int lat)
+{
+ setupVariables();
+ newSample(frq, ch, data, len, fmt, lat);
+}
+
+soundPlayer::soundPlayer(int frq, int ch, const short *data, int len, rviewSoundFormat fmt, int lat)
+{
+ setupVariables();
+ newSample(frq, ch, data, len, fmt, lat);
+}
+
+soundPlayer::~soundPlayer(void)
+{
+ playbackStop();
+ if (buffer != NULL) delete [] buffer;
+ if (convBuff != NULL) delete [] convBuff;
+ if (LinToUlaw != NULL) delete [] LinToUlaw;
+ if (UlawToLin != NULL) delete [] UlawToLin;
+}
+
+void soundPlayer::setupVariables(void)
+{
+ buffer = NULL; convBuff = NULL; inData = NULL; sampleFile = NULL; suspendedPlayer = NULL;
+ LinToUlaw = NULL; UlawToLin = NULL; timerActive = FALSE; loopMode = 0;
+#ifdef __VISUALC__
+ waveOut = (HWAVEOUT)0; timerID = 0;
+ for (int i=0; i<RVIEW_SND_BUFFERS; i++) waveHdrs[i].lpData = NULL;
+#else
+ audioDevice = -1;
+#endif
+
+#ifdef SOUND_DEBUG_FILE
+ if (debugfd == NULL) debugfd = fopen(SOUND_DEBUG_FILE, "w");
+#endif
+}
+
+void soundPlayer::playbackStop(void)
+{
+#ifdef SOUND_PLAYER_DEBUG
+ cout << "soundPlayer::playbackStop" << endl;
+#endif
+
+ stopTimer();
+
+#ifdef __VISUALC__
+ if (waveOut != (HWAVEOUT)0)
+ {
+ // Reset is CRITICALLY important here! Otherwise playback won't work again
+ // until you quit and restart your app.
+ waveOutReset(waveOut); waveOutClose(waveOut); waveOut = (HWAVEOUT)0;
+ }
+ freeWaveHeaders();
+#else
+ if (audioDevice != -1)
+ {
+ close(audioDevice); audioDevice = -1;
+ }
+#endif
+ inData = NULL; sampleFile = NULL;
+}
+
+int soundPlayer::newSample(int frq, int ch, FILE *fp, rviewSoundFormat fmt, int lat)
+{
+ if (configureDevice(frq, ch, -1, fmt, lat) != 0) return -1;
+ sampleFile = fp;
+ return 0;
+}
+
+int soundPlayer::newSample(int frq, int ch, const signed char *data, int len, rviewSoundFormat fmt, int lat)
+{
+ if (configureDevice(frq, ch, len, fmt, lat) != 0) return -1;
+ inData = (char*)data;
+ return 0;
+}
+
+int soundPlayer::newSample(int frq, int ch, const unsigned char *data, int len, rviewSoundFormat fmt, int lat)
+{
+ if (configureDevice(frq, ch, len, fmt, lat) != 0) return -1;
+ inData = (char*)data;
+ return 0;
+}
+
+int soundPlayer::newSample(int frq, int ch, const short *data, int len, rviewSoundFormat fmt, int lat)
+{
+ if (configureDevice(frq, ch, len, fmt, lat) != 0) return -1;
+ inData = (char*)data;
+ return 0;
+}
+
+int soundPlayer::playbackActive(void)
+{
+ if ((sampleFile != NULL) || (inData != NULL)) return dataOffset;
+
+ return -1;
+}
+
+int soundPlayer::playbackGetOffset(void)
+{
+ if ((sampleFile == NULL) && (inData == NULL)) return -1;
+ return dataOffset;
+}
+
+void soundPlayer::ensureUlawTable(int ulawsize)
+{
+ int i, j, shift, range, sign, base, vsh;
+ unsigned char val;
+ unsigned char *u;
+
+ if (LinToUlaw != NULL)
+ {
+ if (ldUlawSize >= ulawsize) return;
+ delete [] LinToUlaw;
+ }
+ if (ulawsize < ULAW_LD_TABLE_MIN) ldUlawSize = ULAW_LD_TABLE_MIN; else ldUlawSize = ulawsize;
+ LinToUlaw = new unsigned char[(1<<ldUlawSize)];
+
+ range = 255 << (ULAW_LD_LINEAR_SIZE + ldUlawSize - 16);
+ u = LinToUlaw + (1<<(ldUlawSize-1)) - range;
+
+ for (i=-8; i<8; i++)
+ {
+ if (i < 0)
+ {
+ shift = -1-i; sign = -1; base = 127 - 16*shift - 15;
+ }
+ else
+ {
+ shift = i; sign = 1; base = 255 - 16*shift;
+ }
+ vsh = ULAW_LD_LINEAR_SIZE + ldUlawSize + shift - 20;
+ if (vsh < 0)
+ {
+ vsh = -vsh;
+ for (j=0; j<(1<<(ULAW_LD_LINEAR_SIZE + ldUlawSize + shift - 16)); j++)
+ {
+ val = j << vsh;
+ val = base - sign * val;
+ *u++ = val;
+ }
+ }
+ else
+ {
+ for (j=0; j<(1<<(ULAW_LD_LINEAR_SIZE + ldUlawSize + shift - 16)); j++)
+ {
+ val = j >> vsh;
+ val = base - sign * val;
+ *u++ = val;
+ }
+ }
+ }
+ i = (1<<(ldUlawSize-1)) - range;
+ memset(LinToUlaw, LinToUlaw[i], i-1);
+ memset(LinToUlaw + (1<<ldUlawSize) - i, LinToUlaw[(1<<ldUlawSize) - i - 1], i);
+
+ /*for (i=0; i<(1<<(ldUlawSize-4)); i++)
+ {
+ printf("%4x: ", i*16);
+ for (j=0; j<16; j++)
+ {
+ printf("%2x ", LinToUlaw[16*i + j]);
+ }
+ printf("\n");
+ }*/
+}
+
+void soundPlayer::ensureLinearTable(void)
+{
+ int i, j;
+ short *data;
+
+ if (UlawToLin != NULL) return;
+
+ UlawToLin = new short[256];
+ data = UlawToLin;
+
+ for (i=0; i<128; i++)
+ {
+ j = ((127 - i) >> 4);
+ *data++ = -((((1 << j) - 1) << ULAW_LD_LINEAR_SIZE) + ((16-(i&15)) << (j + ULAW_LD_LINEAR_SIZE - 4)));
+ }
+ for (i=128; i<256; i++)
+ {
+ j = ((255 - i) >> 4);
+ *data++ = ((((1 << j) -1) << ULAW_LD_LINEAR_SIZE) + ((15-(i&15)) << (j + ULAW_LD_LINEAR_SIZE - 4)));
+ }
+
+ /*for (i=0; i<32; i++)
+ {
+ printf("%4x: ", i*8);
+ for (j=0; j<8; j++)
+ {
+ printf("%6d ", UlawToLin[8*i + j]);
+ }
+ printf("\n");
+ }*/
+}
+
+char *soundPlayer::ensureConvBuff(int size)
+{
+ if (convBuff == NULL)
+ {
+ convBuff = new char [size]; cbuffSize = size;
+ }
+ else
+ {
+ if (cbuffSize < size)
+ {
+ delete [] convBuff; convBuff = new char [size]; cbuffSize = size;
+ }
+ }
+ return convBuff;
+}
+
+char *soundPlayer::ensureSampleBuff(int size)
+{
+ if (buffer == NULL)
+ {
+ buffer = new char[size]; buffSize = size;
+ }
+ else
+ {
+ if (buffSize < size)
+ {
+ delete [] buffer; buffer = new char[size]; buffSize = size;
+ }
+ }
+ return buffer;
+}
+
+const char *soundPlayer::ensureSamplesForDevice(const char *source, int len)
+{
+ int needSize;
+ int needSamples;
+ int i;
+
+#ifdef SOUND_PLAYER_DEBUG
+ cout << "soundPlayer::ensureSamplesForDevice" << endl;
+#endif
+
+ if (format == devFormat) return source;
+
+ needSamples = len * channels; needSize = len * devSampSize;
+
+ ensureConvBuff(needSize);
+
+ // Device is 8 bit signed linear (mean at 0)
+ if (devFormat == rsf_lin8)
+ {
+ signed char *dest = (signed char*)convBuff;
+
+ if (format == rsf_ulin8)
+ {
+ const unsigned char *src = (const unsigned char*)source;
+
+ for (i=0; i<needSamples; i++) dest[i] = (signed char)(src[i] - 0x80);
+ }
+ else if (format == rsf_ulaw8)
+ {
+ const unsigned char *src = (const unsigned char*)source;
+
+ ensureLinearTable();
+ for (i=0; i<needSamples; i++) dest[i] = (signed char)(UlawToLin[src[i]] >> 8);
+ }
+ else if (format == rsf_lin16)
+ {
+ const short *src = (const short *)source;
+
+ for (i=0; i<needSamples; i++) dest[i] = (signed char)(src[i] >> 8);
+ }
+ }
+ // Device is 8 bit unsigned linear (mean at 0x80)
+ else if (devFormat == rsf_ulin8)
+ {
+ unsigned char *dest = (unsigned char*)convBuff;
+
+ if (format == rsf_lin8)
+ {
+ const signed char *src = (const signed char*)source;
+
+ for (i=0; i<needSamples; i++) dest[i] = (unsigned char)(src[i]) + 0x80;
+ }
+ else if (format == rsf_ulaw8)
+ {
+ const unsigned char *src = (const unsigned char*)source;
+
+ ensureLinearTable();
+ for (i=0; i<needSamples; i++) dest[i] = (unsigned char)((UlawToLin[src[i]] >> 8) + 0x80);
+ }
+ else if (format == rsf_lin16)
+ {
+ const short *src = (const short*)source;
+
+ for (i=0; i<needSamples; i++) dest[i] = (short)((src[i] >> 8) + 0x80);
+ }
+ }
+ // Device is 8 bit ulaw
+ else if (devFormat == rsf_ulaw8)
+ {
+ unsigned char *dest = (unsigned char*)convBuff;
+
+ if (format == rsf_lin8)
+ {
+ const signed char *src = (const signed char*)source;
+ short val;
+
+ ensureUlawTable(8);
+
+ for (i=0; i<needSamples; i++)
+ {
+ val = (src[i] << 8);
+ dest[i] = LinToUlaw[(1<<(ldUlawSize-1)) + (val >> (16 - ldUlawSize))];
+ }
+ }
+ else if (format == rsf_ulin8)
+ {
+ const unsigned char *src = (const unsigned char*)source;
+ short val;
+
+ ensureUlawTable(8);
+
+ for (i=0; i<needSamples; i++)
+ {
+ val = (src[i] << 8) - 0x8000;
+ dest[i] = LinToUlaw[(1<<(ldUlawSize-1)) + (val >> (16 - ldUlawSize))];
+ }
+ }
+ else if (format == rsf_lin16)
+ {
+ const short *src = (const short*)source;
+ short val;
+
+ ensureUlawTable(14);
+
+ for (i=0; i<needSamples; i++)
+ {
+ val = src[i];
+ dest[i] = LinToUlaw[(1<<(ldUlawSize-1)) + (val >> (16 - ldUlawSize))];
+ }
+ }
+ }
+ // Device is 16 bit linear
+ else if (devFormat == rsf_lin16)
+ {
+ short *dest = (short*)convBuff;
+
+ if (format == rsf_lin8)
+ {
+ const signed char *src = (const signed char*)source;
+
+ for (i=0; i<needSamples; i++) dest[i] = (short)(src[i] << 8);
+ }
+ else if (format == rsf_ulin8)
+ {
+ const unsigned char *src = (const unsigned char*)source;
+
+ for (i=0; i<needSamples; i++) dest[i] = (short)((src[i] << 8) - 0x8000);
+ }
+ else if (format == rsf_ulaw8)
+ {
+ const unsigned char *src = (const unsigned char *)source;
+
+ ensureLinearTable();
+ for (i=0; i<needSamples; i++) dest[i] = (short)(UlawToLin[src[i]]);
+ }
+ }
+
+ return convBuff;
+}
+
+const char *soundPlayer::ensureSamples(int &num)
+{
+ const char *result;
+ char *b;
+
+ if (sampleFile != NULL)
+ {
+ ensureSampleBuff(num * sampleSize);
+#ifdef SOUND_PLAYER_DEBUG
+ cout << "read " << num << " samples from " << (void*)sampleFile << endl;
+#endif
+ if (loopMode == 0)
+ {
+ num = fread(buffer, sampleSize, num, sampleFile);
+ dataOffset += num;
+ }
+ else
+ {
+ int total, dsize;
+
+ b = buffer; total = num;
+ while (total > 0)
+ {
+ dsize = fread(b, sampleSize, total, sampleFile);
+ dataOffset += dsize;
+ if (dsize < total)
+ {
+ fseek(sampleFile, 0, SEEK_SET); dataOffset = 0;
+ }
+ b += dsize * sampleSize; total -= dsize;
+ }
+ }
+ if (handleOutOfData(num) != 0)
+ {
+ sampleFile = NULL; return NULL;
+ }
+ result = ensureSamplesForDevice(buffer, num);
+ }
+ else if (inData != NULL)
+ {
+ if (loopMode == 0)
+ {
+ if (num + dataOffset > inLength) num = inLength - dataOffset;
+ result = (char*)inData + dataOffset * sampleSize;
+ dataOffset += num;
+ }
+ else
+ {
+ int total, dsize;
+
+ ensureSampleBuff(num * sampleSize);
+ b = buffer; total = num;
+ while (total > 0)
+ {
+ dsize = inLength - dataOffset;
+ if (dsize > total) dsize = total;
+ memcpy(b, inData + dataOffset * sampleSize, dsize * sampleSize);
+ dataOffset += dsize; if (dataOffset >= inLength) dataOffset = 0;
+ b += dsize * sampleSize; total -= dsize;
+ }
+ result = buffer;
+ }
+ if (handleOutOfData(num) != 0)
+ {
+ inData = NULL; return NULL;
+ }
+ result = ensureSamplesForDevice(result, num);
+ }
+ else
+ {
+ playbackStop(); result = NULL; num = 0;
+ }
+
+ return result;
+}
+
+int soundPlayer::handleOutOfData(int dataSize)
+{
+ // If there is data, do nothing.
+ if (dataSize > 0) return 0;
+
+#ifdef __VISUALC__
+ // On Windows we have to make sure both buffers are played to the end.
+ // Since the new one is all empty that leaves only the current one,
+ // therefore delay by 1 buffer.
+ if (emptyBuffers < 1)
+ {
+ emptyBuffers++; return 0;
+ }
+#endif
+ // On Unix we can stop immediately
+ playbackStop();
+ return 1;
+}
+
+int soundPlayer::playbackSetPosition(int position)
+{
+ int oldPosition = -1;
+
+ oldPosition = dataOffset;
+
+ if (position >= 0)
+ {
+ if (sampleFile != NULL)
+ {
+ fseek(sampleFile, position, SEEK_SET);
+ dataOffset = (int)ftell(sampleFile);
+ }
+ else
+ {
+ dataOffset = (position < inLength) ? position : inLength-1;
+ }
+ }
+ return oldPosition;
+}
+
+int soundPlayer::playbackLoopMode(int lpMode)
+{
+ int oldLoop = loopMode;
+
+ loopMode = lpMode;
+
+ return oldLoop;
+}
+
+
+#ifdef __VISUALC__
+void soundPlayer::freeWaveHeaders(void)
+{
+ int i;
+
+ for (i=0; i<RVIEW_SND_BUFFERS; i++)
+ {
+ if (waveHdrs[i].lpData != NULL)
+ {
+ waveOutUnprepareHeader(waveOut, waveHdrs + i, sizeof(WAVEHDR));
+ delete [] waveHdrs[i].lpData; waveHdrs[i].lpData = NULL;
+ }
+ }
+}
+#endif
+
+int soundPlayer::configureDevice(int frq, int ch, int len, rviewSoundFormat fmt, int lat)
+{
+ // only allow 1 active player at a time.
+ if ((activePlayer != NULL) && (activePlayer != this))
+ {
+ cerr << "Another player is already active" << endl;
+ return -1;
+ }
+
+ playbackStop();
+
+ frequency = frq; latency = lat; channels = ch; format = fmt; inLength = len;
+ samplesWritten = 0; dataOffset = 0;
+ samplesWriteahead = (frequency * latency) / 1000;
+
+#ifdef __VISUALC__
+ devFormat = rsf_lin16;
+#else
+#ifdef __sun
+ if ((audioDevice = open("/dev/audio", O_WRONLY)) != -1)
+ {
+ Audio_hdr head;
+
+ if (fmt == rsf_ulaw8)
+ {
+ head.encoding = AUDIO_ENCODING_ULAW;
+ devFormat = rsf_ulaw8;
+ head.bytes_per_unit = 1;
+ }
+ else
+ {
+ head.encoding = AUDIO_ENCODING_LINEAR;
+ devFormat = rsf_lin16;
+ head.bytes_per_unit = 2;
+ }
+ head.sample_rate = frequency;
+ head.channels = channels;
+ head.samples_per_unit = 1;
+ head.data_size = AUDIO_UNKNOWN_SIZE;
+ head.endian = AUDIO_ENDIAN_BIG;
+ audio_set_play_config(audioDevice, &head);
+ }
+#endif
+ if (audioDevice == -1)
+ {
+ cerr << "Unable to initialize audio device!" << endl;
+ return -1;
+ }
+#endif
+
+ switch (format)
+ {
+ case rsf_lin8:
+ case rsf_ulin8:
+ case rsf_ulaw8: sampleSize = 1; break;
+ case rsf_lin16: sampleSize = 2; break;
+ default: sampleSize = 0; break;
+ }
+ sampleSize *= channels;
+ switch (devFormat)
+ {
+ case rsf_lin8:
+ case rsf_ulin8:
+ case rsf_ulaw8: devSampSize = 1; break;
+ case rsf_lin16: devSampSize = 2; break;
+ default: devSampSize = 0;
+ }
+ devSampSize *= channels;
+
+#ifdef SOUND_PLAYER_DEBUG
+ cout << "sampleSize " << sampleSize << ", devSampSize " << devSampSize << ", writeahead " << samplesWriteahead << endl;
+#endif
+
+#ifdef __VISUALC__
+ waveFmt.wFormatTag = WAVE_FORMAT_PCM;
+ waveFmt.nChannels = channels;
+ waveFmt.nSamplesPerSec = frequency;
+ waveFmt.nAvgBytesPerSec = 2*channels*frequency;
+ waveFmt.nBlockAlign = 2*channels;
+ waveFmt.wBitsPerSample = 16*channels;
+ waveFmt.cbSize = 0;
+
+ int i;
+
+ if ((i = waveOutOpen(&waveOut, WAVE_MAPPER, &waveFmt, 0, 0, WAVE_FORMAT_QUERY)) != MMSYSERR_NOERROR)
+ {
+ cerr << "Unable to initialize audio device! (" << i << ")" << endl;
+ return -1;
+ }
+ waveOutOpen(&waveOut, WAVE_MAPPER, &waveFmt, 0, 0, CALLBACK_NULL | WAVE_FORMAT_DIRECT);
+
+ freeWaveHeaders();
+
+ for (i=0; i<RVIEW_SND_BUFFERS; i++)
+ {
+ waveHdrs[i].lpData = (LPSTR)(new char[samplesWriteahead * devSampSize]);
+ waveHdrs[i].dwBufferLength = (DWORD)(samplesWriteahead * devSampSize);
+ //waveOutPrepareHeader(waveOut, waveHdrs + i, sizeof(WAVEHDR));
+ // Init flags to "done" for writeSamples
+ waveHdrs[i].dwFlags = WHDR_DONE;
+ }
+ currentHeader = 0; emptyBuffers = 0;
+
+#endif
+
+ return startTimer();
+}
+
+
+void soundPlayer::playbackSuspend(void)
+{
+ stopTimer(0);
+#ifdef __VISUALC__
+ // NT!!! If you issue these calls playback gets _seriously_ screwed up later on.
+ //waveOutPause(waveOut);
+#endif
+}
+
+
+void soundPlayer::playbackResume(void)
+{
+ samplesWritten = 0;
+#ifdef __VISUALC__
+ //waveOutRestart(waveOut);
+#endif
+ startTimer(0);
+}
+
+
+#ifdef __VISUALC__
+// VISUALC
+int soundPlayer::setTimerInterval(unsigned int ti)
+{
+ if (ti == 0)
+ {
+ if (timerID != 0)
+ {
+ if (!KillTimer(NULL, timerID)) return 1;
+ timerID = 0;
+ }
+ }
+ else
+ {
+ // ti is in us!
+ if (timerID == 0)
+ {
+ timerID = SetTimer(NULL, 1, (UINT)ti/1000, (TIMERPROC)handle_sound_timer);
+ if (timerID == 0) return 1;
+ }
+ }
+
+ timerActive = (ti != 0);
+
+ return 0;
+}
+
+#else
+// UNIX only
+int soundPlayer::setTimerInterval(unsigned int ti)
+{
+ struct itimerval value;
+ struct sigaction act;
+ int res;
+
+ act.sa_handler = handle_sound_timer;
+ act.sa_flags = SA_RESTART;
+ sigaction(SIGALRM, &act, &oact);
+ value.it_interval.tv_sec = 0;
+ value.it_interval.tv_usec = ti;
+ value.it_value.tv_sec = 0;
+ value.it_value.tv_usec = ti;
+ res = setitimer(ITIMER_REAL, &value, &ovalue);
+
+ timerActive = (ti != 0);
+
+ return res;
+}
+#endif
+
+
+int soundPlayer::startTimer(int ap)
+{
+ unsigned int period;
+
+#ifdef SOUND_PLAYER_DEBUG
+ cout << "soundPlayer::startTimer" << endl;
+#endif
+
+ if (timerActive) return -1;
+
+ if (ap != 0)
+ {
+ if ((activePlayer != this) && (activePlayer != NULL))
+ {
+ activePlayer->playbackSuspend();
+ suspendedPlayer = activePlayer;
+ }
+ }
+ activePlayer = this;
+#ifdef __VISUALC__
+ lastSyncTime = GetTickCount();
+#else
+ struct timezone tzp;
+ gettimeofday(&lastSyncTime, &tzp);
+#endif
+
+ // period in us
+ period = (unsigned int)(1000 * latency * RVIEW_SND_RELPERIOD);
+ if (setTimerInterval(period) != 0)
+ {
+ cerr << "Unable to set up timer!" << endl;
+ return -1;
+ }
+
+#ifdef SOUND_PLAYER_DEBUG
+ cout << "started timer with period " << period << endl;
+#endif
+
+ return 0;
+}
+
+int soundPlayer::stopTimer(int ap)
+{
+ if (!timerActive) return -1;
+
+ setTimerInterval(0);
+ timerActive = FALSE;
+
+ activePlayer = NULL;
+ if (ap != 0)
+ {
+ if (suspendedPlayer != NULL)
+ {
+ activePlayer = suspendedPlayer; suspendedPlayer = NULL;
+ activePlayer->playbackResume();
+ }
+ }
+ return 0;
+}
+
+#ifdef __VISUALC__
+void soundPlayer::writeSamples(DWORD systime)
+#else
+void soundPlayer::writeSamples(void)
+#endif
+{
+ int samplesNeeded;
+#ifdef __VISUALC__
+ samplesNeeded = ((systime - lastSyncTime) * frequency) / 1000;
+#else
+ struct timeval tp;
+ struct timezone tzp;
+ float usecs;
+
+ gettimeofday(&tp, &tzp);
+ usecs = (float)(tp.tv_usec - lastSyncTime.tv_usec);
+ samplesNeeded = (tp.tv_sec - lastSyncTime.tv_sec) * frequency + (int)((usecs * frequency) / 1e6);
+#endif
+
+#ifdef SOUND_PLAYER_DEBUG
+ cout << "soundPlayer::writeSamples" << endl;
+#endif
+
+#ifdef SOUND_DEBUG_FILE
+ fprintf(debugfd, "%d: written: %d, needed: %d, deltawa: %d\n", systime, samplesWritten, samplesNeeded, samplesWritten - samplesNeeded - samplesWriteahead);
+#endif
+
+ if ((samplesWritten - samplesNeeded) >= samplesWriteahead)
+ {
+#ifdef SOUND_PLAYER_DEBUG
+ cout << "soundPlayer: stalled" << endl;
+#endif
+ samplesWritten = (samplesWritten - samplesNeeded);
+#ifdef __VISUALC__
+ lastSyncTime = systime;
+#else
+ lastSyncTime.tv_sec = tp.tv_sec; lastSyncTime.tv_usec = tp.tv_usec;
+#endif
+
+#ifdef SOUND_DEBUG_FILE
+ fprintf(debugfd, "stalled\n");
+#endif
+ }
+ else
+ {
+ int num;
+
+#ifdef SOUND_PLAYER_DEBUG
+ cout << "written " << samplesWritten << ", needed " << samplesNeeded << endl;
+#endif
+
+ // Underflow?
+ if ((samplesWritten - samplesNeeded) < 0)
+ {
+ samplesWritten = samplesNeeded;
+#ifdef SOUND_DEBUG_FILE
+ fprintf(debugfd, "underflow\n");
+#endif
+ }
+ //num = samplesWritten - samplesNeeded;
+ num = samplesWriteahead;
+ if (num != 0)
+ {
+ const char *newSamples;
+
+#ifdef SOUND_PLAYER_DEBUG
+ cout << "samples " << num << ", device " << endl;
+#endif
+ if ((newSamples = ensureSamples(num)) != NULL)
+ {
+#ifdef __VISUALC__
+ int bsize = waveHdrs[currentHeader].dwBufferLength;
+
+#ifdef SOUND_DEBUG_FILE
+ fprintf(debugfd, "need %d, buff %d, flags %x\n", num, bsize, waveHdrs[currentHeader].dwFlags);
+#endif
+ // If the buffer is still being used we do nothing.
+ if ((waveHdrs[currentHeader].dwFlags & (WHDR_INQUEUE | WHDR_DONE)) != WHDR_DONE) return;
+#ifdef SOUND_DEBUG_FILE
+ fprintf(debugfd, "fill Buffer %d\n", currentHeader);
+#endif
+ //waveOutUnprepareHeader(waveOut, waveHdrs + currentHeader, sizeof(WAVEHDR));
+ // must prepare the header here or no playback.
+ //waveHdrs[currentHeader].dwFlags = 0;
+ waveOutPrepareHeader(waveOut, waveHdrs + currentHeader, sizeof(WAVEHDR));
+ memcpy(waveHdrs[currentHeader].lpData, newSamples, num * devSampSize);
+ // Fill rest of buffer with the correct 0 value
+ if (num * devSampSize != bsize)
+ {
+ int fillValue = 0;
+
+ memset(waveHdrs[currentHeader].lpData + num * devSampSize, fillValue, bsize - num * devSampSize);
+ }
+ waveOutWrite(waveOut, waveHdrs + currentHeader, sizeof(WAVEHDR));
+ currentHeader++; if (currentHeader >= RVIEW_SND_BUFFERS) currentHeader = 0;
+ samplesWritten += samplesWriteahead;
+#else
+ write(audioDevice, newSamples, num * devSampSize);
+ samplesWritten += num;
+#endif
+ }
+#ifdef SOUND_PLAYER_DEBUG
+ cout << "soundPlayer: wrote " << num << " samples" << endl;
+#endif
+ }
+ }
+}
+
+
+
+
+
+#ifndef __HAL_ONLY__
+
+// Descriptor for sound formats
+const rviewSoundPlayer::format_desc rviewSoundPlayer::soundFormatDesc[] = {
+ {"soundFmtLin8", rsf_lin8, 1},
+ {"soundFmtUlin8", rsf_ulin8, 1},
+ {"soundFmtUlaw8", rsf_ulaw8, 1},
+ {"soundFmtLin16", rsf_lin16, 2},
+ {NULL, rsf_none, 0}
+};
+
+
+/*
+ * rviewSoundPlayer: sound player widget, platform independent.
+ */
+
+rviewSoundPlayer::rviewSoundPlayer(mdd_frame *mf, unsigned int flags) : rviewDisplay(mf, sound_ctrly, flags)
+{
+ int w, h;
+ char buffer[STRINGSIZE];
+ char **latStr, **fmtStr;
+ int fnumLin8, fnumUlaw8, fnumLin16;
+ char *b;
+ int i;
+
+ RMDBGENTER(3, RMDebug::module_applications, "rviewSoundPlayer", "rviewSoundPlayer()");
+
+#if 0
+ {
+ dimMDD = 1; interv = r_Minterval(1);
+ //interv << r_Sinterval(r_Range(0), r_Range(41744));
+ //#define SAMPLE_NAME "death.sam"
+ //interv << r_Sinterval(r_Range(0), r_Range(79842));
+ //#define SAMPLE_NAME "cyber.sam"
+ interv << r_Sinterval(r_Range(0), r_Range(77071));
+ #define SAMPLE_NAME "willy.sam"
+ r_Ref<r_Marray<r_Octet> > mddPtr = new r_Marray<r_Octet>(interv);
+ mddPtr->set_type_by_name("OctetString");
+ sprintf(buffer, "marray <octet, [0:%d]>", interv[0].high());
+ mddPtr->set_type_structure(buffer);
+ char *data = mddPtr->get_array();
+#ifdef __VISUALC__
+ FILE *fp = fopen("Z:\\dehmel\\rview\\samples\\" SAMPLE_NAME, "rb");
+#else
+ FILE *fp = fopen("samples" DIR_SEPARATOR SAMPLE_NAME, "rb");
+#endif
+ if (fp != NULL)
+ {
+ fread(data, 1, interv[0].high() - interv[0].low() + 1, fp); fclose(fp);
+ }
+ else
+ {
+ memset(data, 0x80, interv[0].high() - interv[0].low() + 1);
+ }
+ mddObj = (r_Ref<r_GMarray>)mddPtr; baseType = rbt_uchar;
+ }
+#endif
+
+ sampleBuffer = NULL; lastOffset = 0; paused = FALSE;
+ typeLength = mddObj->get_type_length(); playbackOn = FALSE;
+
+ // Defaults
+ frequency = prefs->soundFreq; latency = prefs->soundLatency; loopMode = prefs->soundLoop;
+
+ GetClientSize(&w, &h);
+
+ toStart = new rviewButton(ctrlPanel, "<<");
+ toEnd = new rviewButton(ctrlPanel, ">>");
+ pbPause = new rviewButton(ctrlPanel, "||");
+ pbStart = new rviewButton(ctrlPanel, ">");
+ pbStop = new rviewButton(ctrlPanel, "[]");
+ pbLoop = new rviewButton(ctrlPanel);
+
+ slider = new rviewSlider(ctrlPanel, 0, 0, 1000, 10, lman->lookup("soundPlayTime"));
+ frqWidget = new rviewText(ctrlPanel, frequency);
+
+ fnumLin8 = 0; fnumUlaw8 = 0; fnumLin16 = 0;
+ for (i=0; soundFormatDesc[i].labelName != NULL; i++)
+ {
+ switch (soundFormatDesc[i].fmt)
+ {
+ case rsf_lin8: fnumLin8 = i; break;
+ case rsf_ulaw8: fnumUlaw8 = i; break;
+ case rsf_lin16: fnumLin16 = i; break;
+ default: break;
+ }
+ }
+ fmtStr = new char *[i];
+ for (i=0; soundFormatDesc[i].labelName != NULL; i++)
+ fmtStr[i] = lman->lookup(soundFormatDesc[i].labelName);
+ fmtWidget = new rviewChoice(ctrlPanel, i, fmtStr, lman->lookup("soundFormat"));
+ delete [] fmtStr;
+
+ latencies = new int[sound_latencies];
+ for (i=0; i<sound_latencies; i++) latencies[i] = 50 * (i+1);
+ latStr = new char *[sound_latencies];
+ b = buffer;
+ for (i=0; i<sound_latencies; i++)
+ {
+ latStr[i] = b;
+ b += 1 + sprintf(b, "%dms", latencies[i]);
+ }
+ latWidget = new rviewChoice(ctrlPanel, i, latStr, lman->lookup("soundLatency"));
+ delete [] latStr;
+ for (i=0; i<sound_latencies-1; i++)
+ {
+ if ((latencies[i] <= latency) && (latencies[i+1] > latency)) break;
+ }
+ latWidget->SetSelection(i);
+
+ b = projString;
+ b += sprintf(b, "*:*");
+ for (i=1; i<dimMDD; i++)
+ {
+ b += sprintf(b, ", %ld", interv[i].low());
+ }
+ project->SetValue(projString);
+
+ // Interpret 2D data as multiple channels
+ setModeDimension((dimMDD == 1) ? 1 : 2);
+
+ setLoopMode(loopMode);
+
+ // Mustn't create errorbox before all widgets are created.
+ switch (baseType)
+ {
+ case rbt_char: currentFormat = fnumUlaw8; break;
+ case rbt_uchar: currentFormat = fnumLin8; break;
+ case rbt_short: currentFormat = fnumLin16; break;
+ default:
+ {
+ rviewErrorbox::reportError(lman->lookup("errorSoundFormat"), rviewSoundPlayer::getFrameName(), "rviewSoundFormat");
+ currentFormat = -1;
+ objectInitializedOK = FALSE;
+ }
+ break;
+ }
+ if (currentFormat >= 0) fmtWidget->SetSelection(currentFormat);
+
+ RMDBGEXIT(3, RMDebug::module_applications, "rviewSoundPlayer", "rviewSoundPlayer()");
+}
+
+
+int rviewSoundPlayer::openViewer(void)
+{
+
+ RMDBGONCE(3, RMDebug::module_applications, "rviewSoundPlayer", "openViewer()");
+
+ if (currentFormat < 0)
+ {
+ rviewErrorbox::reportError(lman->lookup("errorSoundFormat"), rviewSoundPlayer::getFrameName(), "openViewer");
+ objectInitializedOK = FALSE;
+ return -1;
+ }
+
+ if (rviewDisplay::openViewer() == 0)
+ {
+ int w, h;
+
+ GetClientSize(&w, &h);
+
+ label();
+
+ frameWidth=-1;
+ frameHeight=-1;
+
+ OnSize(w, h);
+ OnSize(w, h);
+
+ Show(TRUE);
+
+ return 0;
+ }
+ return -1;
+}
+
+
+rviewSoundPlayer::~rviewSoundPlayer(void)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewSoundPlayer", "~rviewSoundPlayer()");
+ closeViewer();
+ if (latencies)
+ {
+ delete [] latencies;
+ latencies=0;
+ }
+ if (sampleBuffer)
+ {
+ delete [] sampleBuffer;
+ sampleBuffer=0;
+ }
+}
+
+
+const char *rviewSoundPlayer::getFrameName(void) const
+{
+ return "rviewSoundPlayer";
+}
+
+rviewFrameType rviewSoundPlayer::getFrameType(void) const
+{
+ return rviewFrameTypeSound;
+}
+
+int rviewSoundPlayer::getViewerType(void) const
+{
+ return RVIEW_RESDISP_SOUND;
+}
+
+
+bool rviewSoundPlayer::setLoopMode(bool lm)
+{
+ bool oldMode = loopMode;
+
+ loopMode = lm;
+ if (loopMode)
+ {
+ pbLoop->SetLabel("<-->");
+ }
+ else
+ {
+ pbLoop->SetLabel("--->");
+ }
+ player.playbackLoopMode((loopMode) ? 1 : 0);
+
+ return oldMode;
+}
+
+
+void rviewSoundPlayer::setSlider(int offset)
+{
+ slider->SetValue((offset + frequency - 1) / frequency);
+}
+
+void rviewSoundPlayer::label(void)
+{
+ SetTitle(lman->lookup("titleSound"));
+ slider->SetLabel(lman->lookup("soundPlayTime"));
+ frqWidget->SetLabel(lman->lookup("soundFrequency"));
+ latWidget->SetLabel(lman->lookup("soundLatency"));
+
+ rviewDisplay::label();
+}
+
+int rviewSoundPlayer::process(wxObject &obj, wxEvent &evt)
+{
+ int type = evt.GetEventType();
+
+ RMDBGONCE(3, RMDebug::module_applications, "rviewSoundPlayer", "process(...)");
+
+ if (rviewDisplay::process(obj, evt) != 0)
+ {
+ return 1;
+ }
+
+ if (type == wxEVENT_TYPE_BUTTON_COMMAND)
+ {
+ if (&obj == (wxObject*)pbStart)
+ {
+ startPlayback();
+ return 1;
+ }
+ else if (&obj == (wxObject*)pbStop)
+ {
+ stopPlayback();
+ return 1;
+ }
+ else if (&obj == (wxObject*)toStart)
+ {
+ player.playbackSetPosition(0);
+ setSlider(0);
+ return 1;
+ }
+ else if (&obj == (wxObject*)toEnd)
+ {
+ player.playbackSetPosition(sampleLength);
+ setSlider(sampleLength);
+ return 1;
+ }
+ else if (&obj == (wxObject*)pbPause)
+ {
+ if (paused)
+ {
+ player.playbackResume(); paused = FALSE;
+ }
+ else
+ {
+ player.playbackSuspend(); paused = TRUE;
+ }
+ return 1;
+ }
+ else if (&obj == (wxObject*)pbLoop)
+ {
+ setLoopMode(!loopMode);
+ return 1;
+ }
+ }
+
+ if (type == wxEVENT_TYPE_SLIDER_COMMAND)
+ {
+ if (&obj == (wxObject*)slider)
+ {
+ int soff, poff;
+
+ if ((poff = player.playbackGetOffset()) >= 0)
+ {
+ soff = slider->GetValue();
+ if (soff != poff/frequency)
+ {
+ player.playbackSetPosition(soff * frequency);
+ }
+ }
+ return 1;
+ }
+ }
+
+ if (type == wxEVENT_TYPE_CHOICE_COMMAND)
+ {
+ if (&obj == (wxObject*)fmtWidget)
+ {
+ int newFmt;
+
+ newFmt = fmtWidget->GetSelection();
+ if ((soundFormatDesc[newFmt].sampleSize != baseSize) && (currentFormat >= 0))
+ {
+ fmtWidget->SetSelection(currentFormat);
+ }
+ else
+ {
+ currentFormat = newFmt;
+ }
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+void rviewSoundPlayer::OnSize(int w, int h)
+{
+ int x, y, posx, posy, d;
+
+ RMDBGONCE(3, RMDebug::module_applications, "rviewSoundPlayer", "OnSize( " << w << ", " << h << " )");
+
+ rviewDisplay::OnSize(w, h);
+
+ GetClientSize(&x, &y);
+
+ //need to resize?
+ if (( sound_width != x) || ( sound_height != y))
+ {
+ frameWidth = sound_width;
+ frameHeight = sound_height;
+ x = sound_width;
+ y = sound_height;
+ SetClientSize(x, y);
+ return;
+ }
+
+
+ d = (x - 7*display_border) / 6;
+ posx = display_border; posy = display_border + display_cheight;
+ toStart->SetSize(posx, posy, d, sound_bheight);
+ posx += d + display_border;
+ pbPause->SetSize(posx, posy, d, sound_bheight);
+ posx += d + display_border;
+ pbStart->SetSize(posx, posy, d, sound_bheight);
+ posx += d + display_border;
+ pbStop->SetSize(posx, posy, d, sound_bheight);
+ posx += d + display_border;
+ toEnd->SetSize(posx, posy, d, sound_bheight);
+ posx += d + display_border;
+ pbLoop->SetSize(posx, posy, d, sound_bheight);
+ posx = display_border; posy += sound_bheight + display_border;
+ d = (x - 4*display_border) / 3;
+ frqWidget->SetSize(posx, posy, d, sound_theight);
+ fmtWidget->SetSize(posx + d + display_border, posy, 6*d/9, sound_cheight);
+ latWidget->SetSize(posx + 2*(d + display_border), posy, 5*d/9, sound_cheight);
+ posy += sound_theight + 2*display_border;
+ slider->SetSize(display_border, posy, x - 2*display_border, sound_theight);
+}
+
+
+
+int rviewSoundPlayer::newProjection(void)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewSoundPlayer", "newProjection()");
+
+ if (playbackOn)
+ {
+ player.playbackStop();
+ if (buildSample() != 0) return -1;
+ if (newSample() != 0) return -1; // implicitly does playbackResume()
+ }
+ else
+ {
+ return startPlayback();
+ }
+ return 0;
+}
+
+
+void rviewSoundPlayer::prepareToDie(void)
+{
+ //cout << "rviewSoundPlayer::prepareToDie" << endl;
+ stopPlayback();
+ ::wxYield();
+}
+
+
+int rviewSoundPlayer::newSample(void)
+{
+ int fmt;
+ int status=0;
+
+ RMDBGONCE(3, RMDebug::module_applications, "rviewSoundPlayer", "newSample()");
+
+ frequency = atoi(frqWidget->GetValue());
+ latency = latencies[latWidget->GetSelection()];
+
+ fmt = fmtWidget->GetSelection();
+ switch (fmt)
+ {
+ case 0:
+ status = player.newSample(frequency, channels, (signed char*)sampleBuffer, sampleLength, rsf_lin8, latency);
+ break;
+ case 1:
+ status = player.newSample(frequency, channels, (unsigned char *)sampleBuffer, sampleLength, rsf_ulin8, latency);
+ break;
+ case 2:
+ status = player.newSample(frequency, channels, (unsigned char *)sampleBuffer, sampleLength, rsf_ulin8, latency);
+ break;
+ case 3:
+ status = player.newSample(frequency, channels, (short *)sampleBuffer, sampleLength, rsf_lin16, latency);
+ break;
+ default:
+ {
+ rviewErrorbox::reportError(lman->lookup("errorSoundFormat"), rviewSoundPlayer::getFrameName(), "newSample");
+ }
+ return -1;
+ }
+
+ if (status != 0)
+ {
+ rviewErrorbox::reportError(lman->lookup("errorSoundDevice"), rviewSoundPlayer::getFrameName(), "newSample");
+ return -1;
+ }
+
+ setSlider(0);
+ slider->SetRange(0, (sampleLength + frequency - 1) / frequency);
+
+ return 0;
+}
+
+
+int rviewSoundPlayer::buildSample(void)
+{
+ int stepx, stepy;
+ union {char *c; short *s;} src, dest, srcBase;
+ r_Ref<r_Marray<r_Char> > mddPtr = (r_Ref<r_Marray<r_Char> >)mddObj;
+ char *base;
+ int i;
+
+ RMDBGONCE(3, RMDebug::module_applications, "rviewSoundPlayer", "buildSample()");
+
+ strcpy(projString, project->GetValue());
+ if (rviewParseProjection(getVirtualDomain(), pt1, pt2, projString, &freeDims) != dimMDD)
+ {
+ rviewErrorbox::reportError(lman->lookup("errorProjection"), rviewSoundPlayer::getFrameName(), "buildSample");
+ return -1;
+ }
+
+ dim1 = dimMDD; dim2 = dimMDD;
+ for (dim1=0; dim1<dimMDD; dim1++) if ((freeDims & (1<<dim1)) != 0) break;
+ for (dim2=dim1+1; dim2<dimMDD; dim2++) if ((freeDims & (1<<dim2)) != 0) break;
+
+ sampleLength = pt2[dim1] - pt1[dim1] + 1;
+
+ if (sampleBuffer != NULL)
+ {
+ delete [] sampleBuffer; sampleBuffer = NULL;
+ }
+
+ base = mddObj->get_array();
+ src.c = base + typeLength * ((char*)(&((*mddPtr)[pt1])) - base);
+
+ r_Point paux(pt1);
+ paux[dim1]++;
+ stepx = (int)(&((*mddPtr)[paux]) - &((*mddPtr)[pt1]));
+
+ // One channel or multiple ones?
+ if (dim2 >= dimMDD)
+ {
+ channels = 1;
+ sampleBuffer = (void*)(new char[sampleLength * typeLength]);
+ dest.c = (char*)sampleBuffer;
+ switch (typeLength)
+ {
+ case 1:
+ {
+ for (i=0; i<sampleLength; i++, src.c += stepx)
+ {
+ *dest.c++ = *src.c;
+ }
+ }
+ break;
+ case 2:
+ {
+ for (i=0; i<sampleLength; i++, src.s += stepx)
+ {
+ *dest.s++ = *src.s;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ int j;
+
+ paux[dim1] = pt1[dim1]; paux[dim2]++;
+ stepy = (int)(&((*mddPtr)[paux]) - &((*mddPtr)[pt1]));
+
+ channels = pt2[dim2] - pt1[dim2] + 1;
+ sampleBuffer = (void*)(new char[sampleLength * typeLength * channels]);
+ dest.c = (char*)sampleBuffer;
+ srcBase.c = src.c;
+
+ // Multiple channels ==> create channel-interleaved sample data.
+ switch (typeLength)
+ {
+ case 1:
+ {
+ for (i=0; i<sampleLength; i++, srcBase.c += stepx)
+ {
+ for (j=0, src.c = srcBase.c; j<channels; j++, src.c += stepy)
+ {
+ *dest.c++ = *src.c;
+ }
+ }
+ }
+ break;
+ case 2:
+ {
+ for (i=0; i<sampleLength; i++, srcBase.c += stepx)
+ {
+ for (j=0, src.s = srcBase.s; j<channels; j++, src.s += stepy)
+ {
+ *dest.s++ = *src.s;
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ return 0;
+}
+
+
+int rviewSoundPlayer::startPlayback(void)
+{
+ int offset;
+
+ RMDBGENTER(3, RMDebug::module_applications, "rviewSoundPlayer", "startPlayback()");
+
+ // no reentrancy
+ if (playbackOn) return -1;
+
+ if (sampleBuffer == NULL)
+ {
+ if (buildSample() != 0) return -1;
+ }
+
+ newSample();
+
+ playbackOn = TRUE; paused = FALSE;
+
+ lastOffset = 0;
+ while ((offset = player.playbackActive()) >= 0)
+ {
+ if (abs(offset - lastOffset) >= frequency)
+ {
+ slider->SetValue(offset / frequency);
+ lastOffset = offset;
+ }
+ ::wxYield();
+ if (!playbackOn) break;
+ }
+ if (offset < 0)
+ {
+ setSlider(sampleLength);
+ }
+
+ playbackOn = FALSE;
+
+ return 0;
+}
+
+
+int rviewSoundPlayer::stopPlayback(void)
+{
+ player.playbackStop();
+ playbackOn = FALSE;
+
+ return 0;
+}
+
+
+
+
+
+#else
+
+// Testbed
+int main(int argc, char *argv[])
+{
+ FILE *infile;
+ soundPlayer *sp;
+#ifdef __VISUALC__
+ char *lumpname = "samples\\death.sam";
+#else
+ char *lumpname = "samples/death.sam";
+#endif
+ int offset, lastOffset;
+ int frequency;
+
+ if (argc > 1)
+ {
+ lumpname = argv[1];
+ }
+
+ if ((infile = fopen(lumpname, "rb")) == NULL)
+ {
+ cerr << "Couldn't open file " << lumpname << endl;
+ exit(-1);
+ }
+
+ cout << "create new player" << endl;
+
+ frequency = 11025;
+ sp = new soundPlayer(frequency, 1, infile, rsf_ulin8, 500);
+
+ lastOffset = -frequency;
+ while ((offset = sp->playbackActive()) >= 0)
+ {
+ if (abs(offset - lastOffset) >= frequency)
+ {
+ printf("Time %ds\r", offset / frequency); fflush(stdout);
+ lastOffset = offset;
+ }
+ }
+ printf("\n", offset);
+
+ cout << "delete player" << endl;
+
+ delete sp;
+
+ fclose(infile);
+
+ return 0;
+}
+
+#endif // HAL
diff --git a/applications/rview/rviewSound.hh b/applications/rview/rviewSound.hh
new file mode 100644
index 0000000..e6a156a
--- /dev/null
+++ b/applications/rview/rviewSound.hh
@@ -0,0 +1,274 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+ * PURPOSE:
+ *
+ * rView sound ``viewer'' for playing back MDD as audio samples.
+ * This file consists of two parts: the highly platform dependent
+ * SoundPlayer class providing the actual low-level sound playback
+ * and the general purpose wxWindows class rviewSoundPlayer that
+ * implements a typical rView display mode window and playback
+ * controls.
+ * The SoundPlayer class currently has implementations for Solaris
+ * and WindowsNT. Supporting other Unix brands only requires
+ * changes to SoundPlayer::configureDevice, supporting other
+ * platforms is considerably more complicated (see Unix vs. NT
+ * implementations).
+ *
+ * COMMENTS:
+ * None
+ */
+
+
+
+#ifndef _RVIEW_SOUND_H_
+#define _RVIEW_SOUND_H_
+
+
+#include <stdio.h>
+#include <signal.h>
+
+#ifdef __VISUALC__
+#include <windows.h>
+#endif
+
+
+#ifdef __HAL_ONLY__
+#ifndef __VISUALC__
+#include "bool.h"
+#endif
+typedef bool bool;
+#ifndef TRUE
+#define TRUE true
+#define FALSE false
+#endif
+#else
+#include "rviewUtils.hh"
+#include "rviewDisplay.hh"
+#endif // HAL
+
+
+
+/* Default latency of sound playback */
+#define RVIEW_SND_LATENCY 100
+/* Timer interval relative to sample buffer runtime */
+#define RVIEW_SND_RELPERIOD 0.5
+
+/* Number of sample buffers (NT only) */
+#define RVIEW_SND_BUFFERS 3
+
+
+enum rviewSoundFormat {
+ rsf_none,
+ rsf_lin8,
+ rsf_ulin8,
+ rsf_ulaw8,
+ rsf_lin16
+};
+
+
+
+/*
+ * soundPlayer: hardware abstraction layer
+ */
+
+class soundPlayer
+{
+ public:
+
+ // Base constructor
+ soundPlayer(void);
+ // Constructor for input from file
+ soundPlayer(int frq, int ch, FILE *fp, rviewSoundFormat fmt, int lat=RVIEW_SND_LATENCY);
+ // Constructor for 8bit linear (default)
+ soundPlayer(int frq, int ch, const signed char *data, int len, rviewSoundFormat fmt=rsf_lin8, int lat=RVIEW_SND_LATENCY);
+ // Constructor for 8bit ulaw (default)
+ soundPlayer(int frq, int ch, const unsigned char *data, int len, rviewSoundFormat fmt=rsf_ulaw8, int lat=RVIEW_SND_LATENCY);
+ // Constructor for 16bit linear (default)
+ soundPlayer(int frq, int ch, const short *data, int len, rviewSoundFormat fmt=rsf_lin16, int lat=RVIEW_SND_LATENCY);
+
+ ~soundPlayer(void);
+
+ // For changing during playback
+ int newSample(int frq, int ch, FILE *fp, rviewSoundFormat fmt, int lat=RVIEW_SND_LATENCY);
+ int newSample(int frq, int ch, const signed char *data, int len, rviewSoundFormat=rsf_lin8, int lat=RVIEW_SND_LATENCY);
+ int newSample(int frq, int ch, const unsigned char *data, int len, rviewSoundFormat=rsf_ulaw8, int lat=RVIEW_SND_LATENCY);
+ int newSample(int frq, int ch, const short *data, int len, rviewSoundFormat=rsf_lin16, int lat=RVIEW_SND_LATENCY);
+
+ int playbackGetOffset(void);
+ int playbackActive(void);
+ void playbackSuspend(void);
+ void playbackResume(void);
+ void playbackStop(void);
+ int playbackSetPosition(int position);
+ int playbackLoopMode(int lpMode);
+
+#ifdef __VISUALC__
+ void writeSamples(DWORD systime);
+#else
+ void writeSamples(void);
+#endif
+
+
+ protected:
+
+ void setupVariables(void);
+ const char *ensureSamplesForDevice(const char *source, int len);
+ const char *ensureSamples(int &num);
+ int configureDevice(int frq, int ch, int len, rviewSoundFormat fmt, int lat);
+ void ensureUlawTable(int ulawsize);
+ void ensureLinearTable(void);
+ char *ensureConvBuff(int size);
+ char *ensureSampleBuff(int size);
+
+ int setTimerInterval(unsigned int ti);
+ int startTimer(int ap=1);
+ int stopTimer(int ap=1);
+ int handleOutOfData(int dataSize);
+
+ rviewSoundFormat format;
+ rviewSoundFormat devFormat;
+ int sampleSize, devSampSize;
+ FILE *sampleFile;
+ int dataOffset, inLength;
+ int frequency, channels, latency, samplesWriteahead;
+ int buffSize, cbuffSize;
+ char *buffer, *convBuff;
+ const char *inData;
+ unsigned char *LinToUlaw;
+ short *UlawToLin;
+ int ldUlawSize;
+ int samplesWritten;
+ soundPlayer *suspendedPlayer;
+ int loopMode;
+ bool timerActive;
+
+ // Unix specifics
+#ifdef __VISUALC__
+ void freeWaveHeaders(void);
+
+ HWAVEOUT waveOut;
+ WAVEFORMATEX waveFmt;
+ WAVEHDR waveHdrs[RVIEW_SND_BUFFERS];
+ UINT timerID;
+ DWORD lastSyncTime;
+ int currentHeader;
+ int emptyBuffers;
+#else
+ int audioDevice;
+ struct timeval lastSyncTime;
+ struct sigaction oact;
+ struct itimerval ovalue;
+#endif
+};
+
+
+
+#ifndef __HAL_ONLY__
+
+/*
+ * rviewSoundPlayer: sound player widget
+ */
+
+class rviewSoundPlayer: public rviewDisplay
+{
+ public:
+
+ rviewSoundPlayer(mdd_frame *mf, unsigned int flags=0);
+ ~rviewSoundPlayer(void);
+
+ void label(void);
+ int process(wxObject &obj, wxEvent &evt);
+ virtual int openViewer(void);
+
+ virtual const char *getFrameName(void) const;
+ virtual rviewFrameType getFrameType(void) const;
+ virtual int getViewerType(void) const;
+
+ void OnSize(int w, int h);
+
+ int newProjection(void);
+ void prepareToDie(void);
+
+ typedef struct format_desc {
+ const char *labelName;
+ rviewSoundFormat fmt;
+ int sampleSize;
+ } format_desc;
+
+ // constants
+ // Sound player window button size
+ static const int sound_bwidth;
+ static const int sound_bheight;
+ // Sound player window slider height
+ static const int sound_sheight;
+ // Sound player window text size
+ static const int sound_twidth;
+ static const int sound_theight;
+ // Sount player choice size
+ static const int sound_cwidth;
+ static const int sound_cheight;
+ // Sound player window ctrl area size
+ static const int sound_ctrly;
+ // Sound player frame size
+ static const int sound_width;
+ static const int sound_height;
+ // Number of latency entries
+ static const int sound_latencies;
+
+
+ protected:
+
+ int buildSample(void);
+ int newSample(void);
+ int startPlayback(void);
+ int stopPlayback(void);
+ void setSlider(int offset);
+ bool setLoopMode(bool lm);
+
+ soundPlayer player;
+ rviewButton *toStart, *toEnd;
+ rviewButton *pbPause, *pbStart, *pbStop, *pbLoop;
+ rviewSlider *slider;
+ rviewText *frqWidget;
+ rviewChoice *fmtWidget, *latWidget;
+ int frequency, channels, latency;
+ int lastOffset;
+ int *latencies;
+ void *sampleBuffer;
+ int sampleLength;
+ bool paused;
+ bool playbackOn;
+ bool loopMode;
+ int dim1, dim2;
+ int typeLength;
+ int currentFormat;
+ unsigned int freeDims;
+
+ static const format_desc soundFormatDesc[];
+};
+
+#endif // HAL
+
+#endif
diff --git a/applications/rview/rviewStrings.cpp b/applications/rview/rviewStrings.cpp
new file mode 100644
index 0000000..bd66bd4
--- /dev/null
+++ b/applications/rview/rviewStrings.cpp
@@ -0,0 +1,216 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+ * PURPOSE:
+ *
+ * rView string viewer. Can display 1D MDD objects as strings
+ *
+ * COMMENTS:
+ * None
+ */
+
+
+
+// Standard wxWindows preamble.
+#ifdef __GNUG__
+#pragma implementation
+#endif
+
+
+// changed in wxWindows 2.4.2:
+//#include "wx_prec.h"
+#include <wx/wxprec.h>
+
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+
+#ifndef WX_PRECOMP
+#include <wx/wx.h>
+#endif
+
+
+
+#include <string.h>
+#include <iostream.h>
+#include <ctype.h>
+
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#endif
+
+
+#include "raslib/rmdebug.hh"
+#include "raslib/primitivetype.hh"
+#include "raslib/structuretype.hh"
+
+
+#include "rviewTypes.hh"
+
+#include "labelManager.hh"
+
+#include "rviewUtils.hh"
+#include "rviewDModes.hh"
+#include "rviewPrefs.hh"
+
+
+const int rviewStringViewer::strview_msgheight = 30;
+const int rviewStringViewer::strview_minwidth = 100;
+const int rviewStringViewer::strview_minheight = 64;
+const int rviewStringViewer::strview_ctrly = 32;
+const int rviewStringViewer::strview_totaly = rviewStringViewer::strview_ctrly + rviewDisplay::display_cheight;
+
+
+
+rviewStringViewer::rviewStringViewer(mdd_frame *mf, unsigned int flags) :
+ rviewDisplay(mf, strview_ctrly, flags)
+{
+ RMDBGONCE( 3, RMDebug::module_applications, "rviewStringViewer", "rviewStringViewer()" );
+
+ msgString = new wxMessage(ctrlPanel, "");
+
+ // init projection string -- this viewer works for 1D only!
+ strcpy(projString, "*:*");
+ project->SetValue(projString);
+
+ setModeDimension(1);
+
+ setMinimumViewerSize(strview_minwidth, strview_minheight);
+}
+
+
+int rviewStringViewer::openViewer(void)
+{
+ RMDBGONCE( 3, RMDebug::module_applications, "rviewStringViewer", "openViewer()" );
+
+ if (dimMDD == 1)
+ {
+ if (baseSize == 1)
+ {
+ if (rviewDisplay::openViewer() == 0)
+ {
+ int w, h;
+
+ newProjection();
+
+ label();
+ frameWidth = -1;
+ frameHeight = -1;
+
+ GetClientSize(&w, &h);
+
+ SetSize(w, strview_totaly);
+ OnSize(w, h);
+
+ Show(TRUE);
+
+ return 0;
+ }
+ }
+ else
+ {
+ rviewErrorbox::reportError(lman->lookup("errorBaseType"), getFrameName(), "openViewer()");
+ }
+ }
+ else
+ {
+ rviewErrorbox::reportError(lman->lookup("errorModeDim"), getFrameName(), "openViewer()");
+ }
+ return -1;
+}
+
+
+const char *rviewStringViewer::getFrameName(void) const
+{
+ return "rviewStringViewer";
+}
+
+rviewFrameType rviewStringViewer::getFrameType(void) const
+{
+ return rviewFrameTypeStringViewer;
+}
+
+int rviewStringViewer::getViewerType(void) const
+{
+ return RVIEW_RESDISP_STRVIEW;
+}
+
+
+rviewStringViewer::~rviewStringViewer(void)
+{
+ RMDBGONCE( 3, RMDebug::module_applications, "rviewStringViewer", "~rviewStringViewer()" );
+ closeViewer();
+}
+
+
+void rviewStringViewer::OnSize(int w, int h)
+{
+ int x, y;
+
+ GetClientSize(&x, &y);
+
+ msgString->SetSize(display_border, display_border + display_cheight, x - 2*display_border, strview_msgheight);
+
+ rviewDisplay::OnSize(w, h);
+}
+
+
+int rviewStringViewer::newProjection(void)
+{
+ unsigned int len, i;
+ const char *b;
+ char *newMsg;
+
+ mapIndex = r_Point(dimMDD);
+ if (rviewParseProjection(getVirtualDomain(), pt1, pt2, projString, &freeDims, &mapIndex) != dimMDD)
+ {
+ rviewErrorbox::reportError(lman->lookup("errorProjection"), getFrameName(), "newProjection");
+ return -1;
+ }
+ if ((freeDims & 1) == 0)
+ {
+ rviewErrorbox::reportError(lman->lookup("errorProjectFree"), getFrameName(), "newProjection");
+ return -1;
+ }
+ len = pt2[0] - pt1[0] + 1;
+ newMsg = new char[len + 1];
+ b = mddObj->get_array() + pt1[0];
+ // make sure the message is printable
+ for (i=0; i<len; i++)
+ {
+ if (isprint(b[i]))
+ newMsg[i] = b[i];
+ else
+ newMsg[i] = ' ';
+ }
+ newMsg[i] = '\0';
+ //cout << "MSG: " << newMsg << endl;
+ msgString->SetLabel(newMsg);
+ delete [] newMsg;
+
+ return 0;
+}
diff --git a/applications/rview/rviewTable.cpp b/applications/rview/rviewTable.cpp
new file mode 100644
index 0000000..bd208ce
--- /dev/null
+++ b/applications/rview/rviewTable.cpp
@@ -0,0 +1,770 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+ * PURPOSE:
+ *
+ * rView table viewer. Can display MDD objects of any dimension and base type (!)
+ * as tables. Optional modes are decimal, octal and hex number bases.
+ *
+ * COMMENTS:
+ * None
+ */
+
+
+
+// Standard wxWindows preamble.
+#ifdef __GNUG__
+#pragma implementation
+#endif
+
+
+// changed in wxWindows 2.4.2:
+//#include "wx_prec.h"
+#include <wx/wxprec.h>
+
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+
+#ifndef WX_PRECOMP
+#include <wx/wx.h>
+#endif
+
+
+
+#include <string.h>
+#include <iostream.h>
+
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#endif
+
+
+#include "raslib/rmdebug.hh"
+#include "raslib/primitivetype.hh"
+#include "raslib/structuretype.hh"
+
+
+#include "rviewTypes.hh"
+
+#include "labelManager.hh"
+
+#include "rviewUtils.hh"
+#include "rviewDModes.hh"
+#include "rviewPrefs.hh"
+
+
+const int textCanvas::txcanv_cospace = 8;
+const int textCanvas::txcanv_colspace = 16;
+const int textCanvas::txcanv_border = rviewDisplay::display_border;
+
+const int rviewTable::table_twidth = 64;
+const int rviewTable::table_theight = 50;
+const int rviewTable::table_cwidth = 100;
+const int rviewTable::table_cheight = 50;
+const int rviewTable::table_minwidth = 100;
+const int rviewTable::table_minheight = 100;
+const int rviewTable::table_ctrly = 64;
+const int rviewTable::table_totaly = rviewDisplay::display_cheight + rviewTable::table_ctrly;
+
+
+
+
+textCanvas::textCanvas(wxWindow *parent, int x, int y, int w, int h, long style) : wxCanvas(parent, x, y, w, h, style)
+{
+ wxColour fc(0x10, 0x10, 0x10);
+ wxColour bc(0xf0, 0xf0, 0xf0);
+
+ fore.SetStyle(wxSOLID);
+ fore.SetColour(fc);
+ back.SetStyle(wxSOLID);
+ back.SetColour(bc);
+ // Don't use wxDEFAULT! Doesn't work on Sun! */
+ font = new wxFont(12, wxROMAN, wxNORMAL, wxNORMAL);
+ SetBackground(&back);
+ SetTextBackground(&bc);
+ SetTextForeground(&fc);
+ pen.SetStyle(wxSOLID);
+ pen.SetColour(fc);
+
+ scrollX = 0; scrollY = 0;
+}
+
+
+textCanvas::~textCanvas(void)
+{
+ SetBackground(NULL); SetTextBackground(NULL); SetTextForeground(NULL); pen.SetColour(0, 0, 0);
+ delete font;
+}
+
+
+void textCanvas::setData(mdd_frame *mf, rviewBaseType bt, unsigned int bs)
+{
+ mddObj = mf->mdd;
+ dimMDD = (int)(mddObj->spatial_domain().dimension());
+ baseType = bt;
+ baseSize = bs;
+}
+
+
+void textCanvas::setStep(int sx, int sy)
+{
+ stepx = sx; stepy = sy;
+}
+
+
+void textCanvas::setProjection(r_Point &p1, r_Point &p2, unsigned int fd, r_Point *mapIndex)
+{
+ pt1 = p1; pt2 = p2; freeDims = fd;
+ for (dim1=0; dim1<dimMDD; dim1++) if ((freeDims & (1<<dim1)) != 0) break;
+ for (dim2=dim1+1; dim2<dimMDD; dim2++) if ((freeDims & (1<<dim2)) != 0) break;
+
+ if (dim1 >= dimMDD)
+ dim1 = -1;
+ else if (mapIndex != NULL)
+ dim1 = (*mapIndex)[dim1];
+ if (dim2 >= dimMDD)
+ dim2 = -1;
+ else if (mapIndex != NULL)
+ dim2 = (*mapIndex)[dim2];
+}
+
+
+void textCanvas::setCoSys(bool cs, int &cl, int &ct)
+{
+ cosys = cs;
+
+ if (cosys)
+ {
+ char buffer[STRINGSIZE];
+ float twidth, theight;
+
+ SetFont(font);
+ if (dim2 < 0)
+ {
+ coleft = txcanv_cospace;
+ sprintf(buffer, "%ld", pt1[dim1]);
+ GetTextExtent(buffer, &twidth, &theight);
+ }
+ else
+ {
+ sprintf(buffer, "%ld", (abs(pt1[dim2]) > abs(pt2[dim2])) ? pt1[dim2] :pt2[dim2]);
+ GetTextExtent(buffer, &twidth, &theight);
+ coleft = (int)twidth + txcanv_cospace;
+ }
+ cotop = (int)theight + txcanv_cospace;
+ SetFont(NULL);
+ }
+ else
+ {
+ coleft = 0; cotop = 0;
+ }
+ cl = coleft; ct = cotop;
+}
+
+
+
+void textCanvas::OnPaint(void)
+{
+ wxUpdateIterator upd(this);
+ wxRect rect;
+ int w, h, x, y;
+ r_Point prun = pt1;
+ wxCanvasDC *cdc;
+ r_Range startOffX, endOffX, startOffY, endOffY;
+ float posx, posy;
+ char textbuff[STRINGSIZE];
+ bool redrawAll = FALSE;
+
+ //cout << "textCanvas::OnPaint()" << endl;
+
+ if (dim1 < 0) return;
+
+ GetClientSize(&w, &h);
+
+ cdc = GetDC();
+ cdc->BeginDrawing();
+ cdc->SetMapMode(MM_TEXT);
+ cdc->SetBrush(&fore);
+ cdc->SetFont(font);
+ cdc->SetLogicalFunction(wxCOPY);
+
+ w = GetScrollPos(wxHORIZONTAL); h = GetScrollPos(wxVERTICAL);
+ x = rviewDisplay::display_scrstep * w;
+ y = rviewDisplay::display_scrstep * h;
+
+ // In case of scrolling we have to plot the whole thing. There's a bug in the
+ // current version of wxWindows that means you don't get any rectangles returned
+ // that were covered by other windows and are now visible.
+ if ((w != scrollX) || (h != scrollY))
+ {
+ redrawAll = TRUE;
+ GetClientSize(&rect.width, &rect.height);
+ rect.x = 0; rect.y = 0;
+ scrollX = w; scrollY = h;
+ }
+
+ // Use for, not while, because of continue in loop body
+ for (; upd ; upd++)
+ {
+ if (!redrawAll) upd.GetRect(&rect);
+
+ // cdc->SetClippingRegion(rect.x, rect.y, rect.width, rect.height);
+ // Calculate the range to plot.
+ startOffX = (x + rect.x - txcanv_border - coleft) / stepx;
+ if (startOffX < 0) startOffX = 0;
+ if (pt1[dim1] + startOffX > pt2[dim1]) continue;
+ endOffX = (x + rect.x + rect.width - txcanv_border - coleft + stepx - 1) / stepx;
+ if (endOffX > pt2[dim1] - pt1[dim1]) endOffX = pt2[dim1] - pt1[dim1];
+ if (dim2 < 0)
+ {
+ startOffY = 0; endOffY = 0;
+ }
+ else
+ {
+ startOffY = (y + rect.y - txcanv_border - cotop) / stepy;
+ if (startOffY < 0) startOffY = 0;
+ if (pt1[dim2] + startOffY > pt2[dim2]) continue;
+ endOffY = (y + rect.y + rect.height - txcanv_border - cotop + stepy - 1) / stepy;
+ if (endOffY > pt2[dim2] - pt1[dim2]) endOffY = pt2[dim2] - pt1[dim2];
+ }
+
+ //cout << "table: " << rect.x << ':' << rect.y << ':' << rect.width << ':' << rect.height << " -- " << startOffX << ':' << endOffX << ':' << startOffY << ':' << endOffY << endl;
+
+ posy = (float)(startOffY * stepy + txcanv_border + cotop);
+ r_Ref<r_Marray<r_Char> > mddPtr = (r_Ref<r_Marray<r_Char> >)mddObj;
+ r_Char *srcBase;
+ const r_Type *tp;
+
+ if ((tp = mddPtr->get_base_type_schema()) == NULL)
+ {
+ cerr << "No schema information available" << endl; // FIXME
+ return;
+ }
+
+ srcBase = (r_Char*)(mddPtr->get_array());
+ if (dim2 < 0)
+ {
+ posx = (float)(startOffX * stepx + txcanv_border + coleft);
+ for (prun[dim1]=pt1[dim1]+startOffX; prun[dim1]<=pt1[dim1]+endOffX; prun[dim1]++, posx+=stepx)
+ {
+ long offset;
+
+ offset = ((&((*mddPtr)[prun])) - srcBase) * baseSize;
+ rviewPrintTypedCell(tp, textbuff, (char*)(srcBase + offset), numberBase);
+ cdc->DrawText(textbuff, posx, posy);
+ }
+ }
+ else
+ {
+ for (prun[dim2]=pt1[dim2]+startOffY; prun[dim2]<=pt1[dim2]+endOffY; prun[dim2]++, posy+=stepy)
+ {
+ posx = (float)(startOffX * stepx + txcanv_border + coleft);
+ for (prun[dim1]=pt1[dim1]+startOffX; prun[dim1]<=pt1[dim1]+endOffX; prun[dim1]++, posx+=stepx)
+ {
+ long offset;
+
+ offset = ((&((*mddPtr)[prun])) - srcBase) * baseSize;
+ rviewPrintTypedCell(tp, textbuff, (char*)(srcBase + offset), numberBase);
+ cdc->DrawText(textbuff, posx, posy);
+ }
+ }
+ }
+
+ // Draw coordinate system if necessary
+ if (cosys)
+ {
+ int i;
+
+ // Mustn't plot entire lines in one go; the lengths seem to be broken into 16 bit quantities
+ // internally so you could get overflows. Instead plot just what's visible.
+ if (startOffX == 0)
+ {
+ cdc->DrawLine(txcanv_border, cotop, txcanv_border + coleft, cotop);
+ }
+ if (startOffY == 0)
+ {
+ cdc->DrawLine(txcanv_border + coleft + startOffX * stepx, cotop, txcanv_border + coleft + (endOffX+1)*stepx, cotop);
+ }
+ if (dim2 >= 0)
+ {
+ if (startOffX == 0)
+ {
+ cdc->DrawLine(coleft, txcanv_border + cotop + startOffY * stepy, coleft, txcanv_border + cotop + (endOffY+1) * stepy);
+ }
+ if (startOffY == 0)
+ {
+ cdc->DrawLine(coleft, txcanv_border, coleft, txcanv_border + cotop);
+ }
+ posx = txcanv_cospace/2;
+ posy = startOffY * stepy + txcanv_border + cotop;
+ for (i=startOffY; i<=endOffY; i++, posy+=stepy)
+ {
+ sprintf(textbuff, "%ld", pt1[dim2] + i);
+ cdc->DrawText(textbuff, posx, posy);
+ }
+ }
+
+ posx = startOffX * stepx + txcanv_border + coleft;
+ posy = txcanv_cospace/2;
+ for (i=startOffX; i<=endOffX; i++, posx+=stepx)
+ {
+ sprintf(textbuff, "%ld", pt1[dim1] + i);
+ cdc->DrawText(textbuff, posx, posy);
+ }
+ }
+ }
+ cdc->SetBrush(NULL);
+ cdc->SetFont(NULL);
+ cdc->EndDrawing();
+}
+
+
+void textCanvas::CalcTextExtent(char *b, float &width, float &height)
+{
+ SetFont(font);
+ GetTextExtent(b, &width, &height);
+ SetFont(NULL);
+}
+
+
+void textCanvas::EstimateCellSize(int &width, int &height)
+{
+ char buffer[STRINGSIZE];
+ float twidth, theight;
+
+ sprintf(buffer, " ,");
+ switch (numberBase)
+ {
+ case 8: sprintf(buffer+2, "%o", 255); break;
+ case 16: sprintf(buffer+2, "%x", 255); break;
+ default: sprintf(buffer+2, "%d", 255); break;
+ }
+ CalcTextExtent(buffer, twidth, theight);
+ width = (int)(baseSize * twidth + txcanv_colspace);
+ height = (int)(1.5 * theight);
+}
+
+
+
+void textCanvas::setNumberBase(int newBase)
+{
+ numberBase = newBase;
+}
+
+
+
+
+
+
+
+/*
+ * Class to display tables
+ */
+
+const char *rviewTable::view_StepSize = "stepSize";
+const char *rviewTable::view_ScrollPos = "scrollPos";
+const char *rviewTable::view_CoSys = "coordSys";
+const char *rviewTable::view_NumBase = "numberBase";
+
+rviewTable::rviewTable(mdd_frame *mf, unsigned int flags) : rviewDisplay(mf, table_ctrly, flags)
+{
+ int w, h, i;
+ char *b;
+
+ RMDBGONCE(3, RMDebug::module_applications, "rviewTable", "rviewTable()");
+
+ // Mode defaults, move to prefs later on
+ stepx = prefs->tableStepx; stepy = prefs->tableStepy;
+ cosys = prefs->tableCosys; numberBase = prefs->tableMode;
+
+ GetClientSize(&w, &h);
+ w -= 2*display_cnvborder; h -= 2*display_cnvborder + table_totaly;
+ canvas = new textCanvas((wxWindow*)this, display_cnvborder, display_cnvborder + table_totaly, w, h);
+ canvas->setData(mf, baseType, baseSize);
+
+ // Need to init these before calling EstimateCellSize()
+ sxText = NULL; syText = NULL;
+ // Try to make a good guess about the default table width
+ canvas->setNumberBase(numberBase);
+ EstimateCellSize(stepx, stepy);
+
+ sxText = new rviewText(ctrlPanel, stepx);
+ syText = new rviewText(ctrlPanel, stepy);
+ csBox = new rviewCheckBox(ctrlPanel);
+ csBox->SetValue(cosys);
+
+ // Init projection string
+ b = projString;
+ b += sprintf(b, "*:*");
+ if (dimMDD>1)
+ {
+ b += sprintf(b, ", *:*");
+ }
+ for (i=2; i<dimMDD; i++)
+ {
+ b += sprintf(b, ", %ld", interv[i].low());
+ }
+ project->SetValue(projString);
+
+ scrollx = -1; scrolly = -1;
+ newProjection();
+
+ setModeDimension((dimMDD == 1) ? 1 : 2);
+
+ setMinimumViewerSize(table_minwidth, table_minheight);
+}
+
+
+int rviewTable::openViewer(void)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewTable", "openViewer()");
+
+ if (rviewDisplay::openViewer() == 0)
+ {
+ int w, h;
+ wxMenu *men;
+ char buffer[STRINGSIZE];
+
+ GetClientSize(&w, &h);
+
+ men = new wxMenu;
+ men->Append(MENU_TABLE_MODE_DECIMAL, "", NULL, TRUE);
+ men->Append(MENU_TABLE_MODE_OCTAL, "", NULL, TRUE);
+ men->Append(MENU_TABLE_MODE_HEX, "", NULL, TRUE);
+ sprintf(buffer, "&%s\n", lman->lookup("menTabMode"));
+ mBar->Append(men, buffer);
+
+ checkModeMenu();
+
+ label();
+
+ frameWidth=-1;
+ frameHeight=-1;
+
+ OnSize(w, h);
+ OnSize(w, h);
+
+ Show(TRUE);
+
+ return 0;
+ }
+ return -1;
+}
+
+
+void rviewTable::checkModeMenu(void)
+{
+ switch (numberBase)
+ {
+ case 8: lastMode = MENU_TABLE_MODE_OCTAL; break;
+ case 16: lastMode = MENU_TABLE_MODE_HEX; break;
+ default: lastMode = MENU_TABLE_MODE_DECIMAL; break;
+ }
+ mBar->Check(lastMode, TRUE);
+}
+
+
+const char *rviewTable::getFrameName(void) const
+{
+ return "rviewTable";
+}
+
+rviewFrameType rviewTable::getFrameType(void) const
+{
+ return rviewFrameTypeTable;
+}
+
+int rviewTable::getViewerType(void) const
+{
+ return RVIEW_RESDISP_TABLE;
+}
+
+
+void rviewTable::EstimateCellSize(int &width, int &height)
+{
+ int w, h;
+ char buffer[STRINGSIZE];
+
+ canvas->EstimateCellSize(w, h);
+ // If prefs specify defaults (<= 0), update width/height, otherwise leave old values.
+ if (prefs->tableStepx <= 0)
+ {
+ width = w;
+ if (sxText != NULL) {sprintf(buffer, "%d", w); sxText->SetValue(buffer);}
+ }
+ if (prefs->tableStepy <= 0)
+ {
+ height = h;
+ if (syText != NULL) {sprintf(buffer, "%d", h); syText->SetValue(buffer);}
+ }
+}
+
+
+
+rviewTable::~rviewTable(void)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewTable", "~rviewTable()");
+ closeViewer();
+}
+
+
+
+void rviewTable::label(void)
+{
+ setDisplayTitle(lman->lookup("titleTable"));
+
+ sxText->SetLabel(lman->lookup("textStepx"));
+ syText->SetLabel(lman->lookup("textStepy"));
+ csBox->SetLabel(lman->lookup("textCosys"));
+
+ mBar->SetLabelTop(fixedNumberOfMenus, lman->lookup("menTabMode"));
+ mBar->SetLabel(MENU_TABLE_MODE_DECIMAL, lman->lookup("menTabModeDec"));
+ mBar->SetLabel(MENU_TABLE_MODE_OCTAL, lman->lookup("menTabModeOct"));
+ mBar->SetLabel(MENU_TABLE_MODE_HEX, lman->lookup("menTabModeHex"));
+
+ rviewDisplay::label();
+}
+
+
+
+void rviewTable::OnSize(int w, int h)
+{
+ int x, y, i, j;
+
+ GetClientSize(&x, &y);
+ x -= 2*display_border;
+ i = x - 2*table_twidth - table_cwidth;
+ j = 2*display_border + display_cheight;
+ sxText->SetSize(display_border + i/6, j, table_twidth, table_theight);
+ syText->SetSize(display_border + (3*i)/6 + table_twidth, j, table_twidth, table_theight);
+ csBox->SetSize(display_border + (5*i)/6 + 2*table_twidth, j, table_cwidth, table_cheight);
+ y -= 2*display_border + table_totaly;
+
+ canvas->SetSize(display_border, display_border + table_totaly, x, y);
+
+ rviewDisplay::OnSize(w, h);
+}
+
+
+
+void rviewTable::OnMenuCommand(int id)
+{
+ int newBase;
+
+ switch (id)
+ {
+ case MENU_TABLE_MODE_DECIMAL: newBase = 10; break;
+ case MENU_TABLE_MODE_OCTAL: newBase = 8; break;
+ case MENU_TABLE_MODE_HEX: newBase = 16; break;
+ default: newBase = -1; break;
+ }
+ if (newBase > 0)
+ {
+ mBar->Check(lastMode, FALSE);
+ numberBase = newBase;
+ checkModeMenu();
+ canvas->setNumberBase(numberBase);
+ EstimateCellSize(stepx, stepy);
+ newTableSize();
+ }
+ else
+ {
+ rviewDisplay::OnMenuCommand(id);
+ }
+}
+
+
+
+int rviewTable::process(wxObject &obj, wxEvent &evt)
+{
+ int type = evt.GetEventType();
+ int i, j;
+
+ if (((&obj == (wxObject*)sxText) || (&obj == (wxObject*)syText)) && (type == wxEVENT_TYPE_TEXT_ENTER_COMMAND))
+ {
+ i = atoi(sxText->GetValue());
+ j = atoi(syText->GetValue());
+ if ((i > 0) && (j > 0))
+ {
+ stepx = i; stepy = j;
+ newTableSize();
+ return 1;
+ }
+ }
+
+ if ((&obj == (wxObject*)csBox) && (type == wxEVENT_TYPE_CHECKBOX_COMMAND))
+ {
+ cosys = csBox->GetValue();
+ newProjection();
+ return 1;
+ }
+
+ if (rviewDisplay::process(obj, evt) != 0)
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+
+
+int rviewTable::newProjection(void)
+{
+ int dim1, dim2;
+
+ mapIndex = r_Point(dimMDD);
+ if (rviewParseProjection(getVirtualDomain(), pt1, pt2, projString, &freeDims, &mapIndex) != dimMDD)
+ {
+ rviewErrorbox::reportError(lman->lookup("errorProjection"), rviewTable::getFrameName(), "newProjection");
+ return -1;
+ }
+
+ for (dim1=0; dim1<dimMDD; dim1++) if ((freeDims & (1<<dim1)) != 0) break;
+ for (dim2=dim1+1; dim2<dimMDD; dim2++) if ((freeDims & (1<<dim2)) != 0) break;
+ if (dim1 >= dimMDD)
+ {
+ rviewErrorbox::reportError(lman->lookup("errorProjectFree"), rviewTable::getFrameName(), "newProjection");
+ return -1;
+ }
+ dim1 = mapIndex[dim1];
+ canvas->setProjection(pt1, pt2, freeDims, &mapIndex);
+ fieldsx = pt2[dim1] - pt1[dim1] + 1;
+ if (dim2 >= dimMDD)
+ {
+ fieldsy = 1;
+ }
+ else
+ {
+ dim2 = mapIndex[dim2];
+ fieldsy = pt2[dim2] - pt1[dim2] + 1;
+ }
+
+ //EstimateCellSize(&stepx, &stepy);
+
+ newTableSize();
+
+ return 0;
+}
+
+
+
+void rviewTable::newTableSize(void)
+{
+ int cl, ct;
+ int newstepx, newstepy;
+
+ canvas->setStep(stepx, stepy);
+ canvas->setCoSys(cosys, cl, ct);
+
+ if (scrollx >= 0)
+ scrollx = canvas->GetScrollPos(wxHORIZONTAL);
+ else
+ scrollx = 0;
+
+ if (scrolly >= 0)
+ scrolly = canvas->GetScrollPos(wxVERTICAL);
+ else
+ scrolly = 0;
+
+ newstepx = (int)((fieldsx*stepx + 2*display_border + cl + display_scrstep - 1) / display_scrstep);
+ newstepy = (int)((fieldsy*stepy + 2*display_border + ct + display_scrstep - 1) / display_scrstep);
+
+ canvas->SetScrollbars(display_scrstep, display_scrstep, newstepx, newstepy, display_pgstep, display_pgstep, scrollx, scrolly);
+}
+
+
+int rviewTable::saveView(FILE *fp)
+{
+ int status = rviewDisplay::saveView(fp);
+
+ long lvals[2];
+ lvals[0] = (long)stepx; lvals[1] = (long)stepy;
+ writeViewParam(fp, view_StepSize, 2, lvals);
+ lvals[0] = (long)(canvas->GetScrollPos(wxHORIZONTAL));
+ lvals[1] = (long)(canvas->GetScrollPos(wxVERTICAL));
+ writeViewParam(fp, view_ScrollPos, 2, lvals);
+ writeViewParam(fp, view_CoSys, (long)cosys);
+ writeViewParam(fp, view_NumBase, (long)numberBase);
+
+ return status;
+}
+
+
+int rviewTable::readView(const char *key, const char *value)
+{
+ int status = rviewDisplay::readView(key, value);
+
+ if (status == 0)
+ {
+ if (strcmp(key, view_StepSize) == 0)
+ {
+ long lvals[2];
+ if (readVector(value, 2, lvals) == 0)
+ {
+ stepx = (int)lvals[0]; stepy = (int)lvals[1];
+ }
+ return 1;
+ }
+ else if (strcmp(key, view_ScrollPos) == 0)
+ {
+ long lvals[2];
+ if (readVector(value, 2, lvals) == 0)
+ {
+ scrollx = (int)lvals[0]; scrolly = (int)lvals[1];
+ }
+ return 1;
+ }
+ else if (strcmp(key, view_CoSys) == 0)
+ {
+ cosys = (bool)atoi(value);
+ return 1;
+ }
+ else if (strcmp(key, view_NumBase) == 0)
+ {
+ numberBase = atoi(value);
+ return 1;
+ }
+ return 0;
+ }
+ return status;
+}
+
+
+void rviewTable::loadViewFinished(void)
+{
+ sxText->SetValue(stepx);
+ syText->SetValue(stepy);
+ csBox->SetValue(cosys);
+
+ mBar->Check(lastMode, FALSE);
+ checkModeMenu();
+
+ canvas->SetScrollPos(wxHORIZONTAL, scrollx);
+ canvas->SetScrollPos(wxVERTICAL, scrolly);
+}
diff --git a/applications/rview/rviewThumb.cpp b/applications/rview/rviewThumb.cpp
new file mode 100644
index 0000000..0688ed2
--- /dev/null
+++ b/applications/rview/rviewThumb.cpp
@@ -0,0 +1,1183 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+ * PURPOSE:
+ *
+ * rView thumbnail viewer class. Unlike the regular MDD viewers (e.g.
+ * rviewImage) this is not derived from rviewDisplay because it can
+ * display any number of MDD objects in contrast to regular viewers
+ * which manage exactly one object.
+ *
+ * COMMENTS:
+ * None
+ */
+
+
+
+// Standard wxWindows preamble.
+#ifdef __GNUG__
+#pragma implementation
+#endif
+
+
+// changed in wxWindows 2.4.2:
+//#include "wx_prec.h"
+#include <wx/wxprec.h>
+
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+
+#ifndef WX_PRECOMP
+#include <wx/wx.h>
+#endif
+
+
+
+#include <string.h>
+#include <iostream.h>
+
+
+#include "wx_pixmap.h"
+
+
+#include "labelManager.hh"
+
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#endif
+
+
+
+#include "rviewPrefs.hh"
+#include "rviewTypes.hh"
+#include "rviewUtils.hh"
+#include "rviewThumb.hh"
+
+#include "raslib/rmdebug.hh"
+
+#include "rasodmg/ref.hh"
+#include "rasodmg/marray.hh"
+
+
+
+
+const int rviewThumb::thumb_width = 450;
+const int rviewThumb::thumb_height = 300;
+const int rviewThumb::thumb_imgwidth = 100;
+const int rviewThumb::thumb_perline = 4;
+const int rviewThumb::thumb_space = 32;
+const int rviewThumb::thumb_border = 8;
+const int rviewThumb::thumb_scrstep = 8;
+const int rviewThumb::thumb_pgstep = 8;
+const int rviewThumb::thumb_chkwidth = 100;
+const int rviewThumb::thumb_chkheight = 30;
+const int rviewThumb::thumb_minwidth = 10;
+const int rviewThumb::thumb_maxwidth = 2000;
+const int rviewThumb::thumb_mincols = 1;
+const int rviewThumb::thumb_maxcols = 16;
+const int rviewThumb::thumb_cheight = 64;
+const int rviewThumb::thumb_twidth = 80;
+const int rviewThumb::thumb_theight = 50;
+const int rviewThumb::thumb_prjwidth = 60;
+
+
+
+
+
+
+/*
+ * The thumbnail canvas class
+ */
+thumbCanvas::thumbCanvas(rviewThumb *par, int x, int y, int width, int height) : wxCanvas((wxWindow*)par, x, y, width, height, 0)
+{
+ parent = par;
+ brush.SetStyle(wxSOLID);
+ brush.SetColour((char)0xc0, (char)0xc0, (char)0xc0);
+ SetBackground(&brush);
+ font = new wxFont(12, wxROMAN, wxNORMAL, wxNORMAL);
+}
+
+
+thumbCanvas::~thumbCanvas(void)
+{
+ SetBackground(NULL);
+ delete font;
+}
+
+
+void thumbCanvas::OnPaint(void)
+{
+ int thumbs, thumbsperline;
+ int gridX, gridY;
+ wxPixmap *thumbnail;
+ wxUpdateIterator upd(this);
+ //wxRect rect;
+ int startx, starty, endx, endy, w, h, posx, posy;
+ int scrollx, scrolly;
+ int maxy, runx, runy;
+
+ //cout << "thumbCanvas::OnPaint" << endl;
+
+ parent->getThumbInfo(thumbs, thumbsperline);
+ parent->getGridInfo(gridX, gridY);
+
+ if ((thumbs <= 0) || (thumbsperline <= 0) || (gridX <= 0) || (gridY <= 0)) return;
+
+ GetClientSize(&w, &h);
+
+ scrollx = rviewThumb::thumb_scrstep * GetScrollPos(wxHORIZONTAL);
+ scrolly = rviewThumb::thumb_scrstep * GetScrollPos(wxVERTICAL);
+
+ startx = (scrollx / gridX); endx = ((scrollx + w + gridX - 1) / gridX);
+ starty = (scrolly / gridY); endy = ((scrolly + h + gridY - 1) / gridY);
+ posx = rviewThumb::thumb_space / 2 + gridX * startx;
+ posy = rviewThumb::thumb_space / 2 + gridY * starty;
+
+ maxy = (thumbs + thumbsperline - 1) / thumbsperline;
+
+ if ((startx >= thumbsperline) || (endx < 0)) return;
+ if ((starty >= maxy) || (endy < 0)) return;
+
+ if (startx < 0) startx = 0;
+ if (endx >= thumbsperline) endx = thumbsperline-1;
+
+ if (starty < 0) starty = 0;
+ if (endy >= maxy) endy = maxy - 1;
+
+ BeginDrawing();
+
+ SetFont(font);
+
+ while (upd)
+ {
+ char caption[STRINGSIZE];
+
+ runx = posx;
+ for (w = startx; w <= endx; w++, runx += gridX)
+ {
+ runy = posy;
+ for (h = starty; h <= endy; h++, runy += gridY)
+ {
+ if ((thumbnail = parent->getPixmapNumber(h * thumbsperline + w, caption)) != NULL)
+ {
+ float tw, th;
+
+ /*cout << "Pixmap " << w << ' ' << h << ": " << (void*)thumbnail << ", at " << runx << ' ' << runy
+ << ", width " << thumbnail->getWidth() << ", height " << thumbnail->getHeight()
+ << ", depth " << thumbnail->getDepth() << ", ddepth " << thumbnail->getModeDepth() << endl;*/
+
+ // Pixmaps have the canvas coordinate system, text has the _scrolled_ canvas cosys!
+ thumbnail->plotPixmap(runx - scrollx, runy - scrolly);
+ GetTextExtent(caption, &tw, &th);
+ tw = ((float)(thumbnail->getWidth()) - tw) / 2;
+ th = thumbnail->getHeight();
+ DrawText(caption, runx + tw, runy + th);
+ }
+ }
+ }
+ upd++;
+ }
+
+ SetFont(NULL);
+
+ EndDrawing();
+}
+
+
+void thumbCanvas::updateDisplay(void)
+{
+ if (parent->IsShown())
+ {
+ int cw, ch;
+
+ GetClientSize(&cw, &ch);
+ SetClippingRegion(0, 0, cw, ch);
+ OnPaint();
+ DestroyClippingRegion();
+ }
+}
+
+
+
+/*
+ * The rviewThumb class for displaying thumbnails of images
+ */
+rviewThumb::rviewThumb(void) : rviewFrame(NULL, "", 0, 0, thumb_width, thumb_height)
+{
+ int x, y, tw, py;
+ wxMenu *menu;
+ wxMenu *setup;
+ wxMenu *submenu;
+ char buffer[STRINGSIZE];
+
+ thumbsperline = 4; if (prefs->thumbCols > 0) thumbsperline = prefs->thumbCols;
+ projstep = 1; if (prefs->thumbProjstep > 0) projstep = prefs->thumbProjstep;
+ doValToCspace = (prefs->rgbSpace != 0); doFullRangeCspace = (prefs->rgbSpace == 2);
+ dimproj = prefs->thumbProjdim;
+ imgWidth = 100; if (prefs->thumbWidth > 0) imgWidth = prefs->thumbWidth;
+ if (imgWidth < thumb_minwidth) imgWidth = thumb_minwidth;
+ if (imgWidth > thumb_maxwidth) imgWidth = thumb_maxwidth;
+
+ thumbs = 0; numPixmaps = 0; maxHeight = -1;
+ listHead = NULL; csmap = NULL; canDoCspace = FALSE;
+ gridX = 0; gridY = 0;
+
+ menu = new wxMenu;
+ menu->Append(MENU_THUMB_DATA_CLOSE, "");
+ submenu = new wxMenu;
+ submenu->Append(MENU_THUMB_CSPACE_ON, "", NULL, TRUE);
+ submenu->Append(MENU_THUMB_CSPACE_FULL, "", NULL, TRUE);
+ submenu->Append(MENU_THUMB_CSPACE_EDIT, "");
+ setup = new wxMenu;
+ setup->Append(MENU_THUMB_SETUP_CSPACE, "", submenu, NULL);
+
+ mbar = new wxMenuBar;
+ sprintf(buffer, "&%s", lman->lookup("menThumbData"));
+ mbar->Append(menu, buffer);
+ sprintf(buffer, "&%s", lman->lookup("menThumbSetup"));
+ mbar->Append(setup, buffer);
+ mbar->Check(MENU_THUMB_CSPACE_ON, doValToCspace);
+ mbar->Check(MENU_THUMB_CSPACE_FULL, doFullRangeCspace);
+ configureCspace(FALSE);
+
+ GetClientSize(&x, &y);
+
+ panel = new wxPanel((wxWindow*)this, 0, thumb_border, x, thumb_cheight);
+ panel->SetLabelPosition(wxVERTICAL);
+
+ x -= 2*thumb_border; y -= 2*thumb_border + thumb_cheight;
+ canvas = new thumbCanvas(this, thumb_border, thumb_border + thumb_cheight, x, y);
+
+ tw = (x - 4*thumb_border - 2*thumb_prjwidth) / 3;
+ py = thumb_border;
+ projString[0] = '\0';
+ project = new rviewText(panel);
+ thumbProj = new rviewText(panel, dimproj);
+ thumbStep = new rviewText(panel, projstep);
+ thumbWidth = new rviewText(panel, imgWidth);
+ thumbCols = new rviewText(panel, thumbsperline);
+
+ SetMenuBar(mbar);
+
+ label();
+
+ frameWidth=-1;
+ frameHeight=-1;
+
+ OnSize(x, y);
+ OnSize(x, y);
+
+
+ Show(TRUE);
+}
+
+
+rviewThumb::~rviewThumb(void)
+{
+ if (thumbs != 0)
+ {
+ int i;
+ rviewThumbList *tlst = listHead;
+
+ for (i=0; i<thumbs; i++)
+ {
+ deletePixmapChain(tlst);
+
+ //cout << "delete " << (void*)tlst << endl;
+ listHead = tlst;
+ tlst = tlst->next; delete listHead;
+ }
+ }
+ if (csmap != NULL) delete csmap;
+}
+
+
+void rviewThumb::configureCspace(bool mode)
+{
+ mbar->Enable(MENU_THUMB_SETUP_CSPACE, mode);
+ mbar->Enable(MENU_THUMB_CSPACE_ON, mode);
+ mbar->Enable(MENU_THUMB_CSPACE_FULL, mode);
+ mbar->Enable(MENU_THUMB_CSPACE_EDIT, mode);
+}
+
+
+
+// Deletes all the pixmaps for one MDD object
+void rviewThumb::deletePixmapChain(rviewThumbList *tlst)
+{
+ if (tlst->pixmaps != NULL)
+ {
+ rviewThumbPixList *tplst, *tplast;
+
+ tplst = tlst->pixmaps;
+ while (tplst != NULL)
+ {
+ //cout << " delete " << (void*)tplst << endl;
+ tplast = tplst; tplst = tplst->next;
+ if (tplast->pixmap != NULL) delete tplast->pixmap;
+ delete tplast;
+ numPixmaps--;
+ }
+ tlst->numPix = 0;
+ tlst->pixmaps = NULL;
+ }
+}
+
+
+// Creates a pixmap chain for a given MDD object
+int rviewThumb::pixmapsFromMDD(rviewThumbList *tlst)
+{
+ rviewThumbPixList *newPixmap, *lastPixmap;
+ int i, projval;
+ bool pixLoop;
+
+ //cout << "pixmapsFromMDD" << endl;
+
+ // delete old pixmaps
+ deletePixmapChain(tlst);
+
+ lastPixmap = NULL;
+
+ if (dimproj >= 0)
+ {
+ projval = pt1[dimproj];
+ }
+
+ // Create all thumbnails for this object. This is 1 for 2D objects, any number for 3+D objects
+ do
+ {
+ pixLoop = FALSE;
+ newPixmap = new rviewThumbPixList;
+ newPixmap->next = NULL;
+ newPixmap->dimproj = dimproj; newPixmap->projval = projval;
+
+ if (lastPixmap == NULL)
+ {
+ tlst->pixmaps = newPixmap;
+ }
+ else
+ {
+ lastPixmap->next = newPixmap;
+ }
+ lastPixmap = newPixmap;
+
+ try
+ {
+ if ((newPixmap->pixmap = buildThumbnail(tlst->mdd, tlst->baseType, newPixmap->dimproj, newPixmap->projval)) == NULL)
+ {
+ cerr << lman->lookup("errorProjThumb") << endl;
+ return 0;
+ }
+ }
+ catch (r_Error &errObj)
+ {
+ cerr << errObj.what() << endl;
+ return 0;
+ }
+
+ (tlst->numPix)++; numPixmaps++;
+
+ i = newPixmap->pixmap->getHeight();
+ if (i > maxHeight)
+ {
+ maxHeight = i;
+ }
+
+ if (dimproj >= 0)
+ {
+ projval += projstep;
+ if (projval <= pt2[dimproj]) pixLoop = TRUE;
+ }
+
+ }
+ while (pixLoop);
+
+ return 1;
+}
+
+
+
+int rviewThumb::addMDD(r_Ref<r_GMarray> &newMdd)
+{
+ rviewThumbList *newItem;
+ int i;
+ r_Object *mo;
+ bool oldCstate;
+
+ RMDBGONCE(3, RMDebug::module_applications, "rviewThumb", "addMDD(...)");
+
+ if ((newItem = new rviewThumbList) == NULL) return 0;
+
+ oldCstate = canDoCspace;
+
+ // Init object-dependent internal data?
+ if (projString[0] == '\0')
+ {
+ // No ==> init to a decent default:
+ initForObject(newMdd);
+ }
+ mo = (r_Object*)(&(*newMdd));
+ newItem->mdd = newMdd; newItem->baseType = rviewGetBasetype(mo);
+ newItem->numPix = 0; newItem->next = NULL; newItem->pixmaps = NULL;
+
+ if (pixmapsFromMDD(newItem) == 0)
+ {
+ deletePixmapChain(newItem);
+ delete newItem; return 0;
+ }
+
+ // If it was true before it's true now.
+ if (oldCstate)
+ canDoCspace = TRUE;
+ else
+ {
+ // Otherwise try the transition FALSE -> TRUE
+ if (canDoCspace)
+ {
+ // Enabling the parent automatically enables the children too, so reset them...
+ mbar->Enable(MENU_THUMB_SETUP_CSPACE, TRUE);
+ mbar->Enable(MENU_THUMB_CSPACE_FULL, doValToCspace);
+ mbar->Enable(MENU_THUMB_CSPACE_EDIT, doValToCspace);
+ }
+ }
+
+ if (thumbs == 0)
+ {
+ listHead = newItem;
+ }
+ else
+ {
+ rviewThumbList *tlst = listHead;
+
+ for (i=1; i<thumbs; i++) tlst = tlst->next;
+
+ tlst->next = newItem;
+ }
+
+ thumbs++;
+
+ updateCanvasSize();
+
+ return 1;
+}
+
+
+int rviewThumb::deleteMDD(r_Ref<r_GMarray> &obsMdd)
+{
+ rviewThumbList *last, *tlst;
+ int i;
+
+ RMDBGONCE(3, RMDebug::module_applications, "rviewThumb", "deleteMDD(...)");
+
+ last = NULL; tlst = listHead;
+
+ for (i=0; i<thumbs; i++)
+ {
+ if (tlst->mdd == obsMdd) break;
+ last = tlst; tlst = tlst->next;
+ }
+ if (i < thumbs)
+ {
+ deletePixmapChain(tlst);
+
+ if (last == NULL)
+ {
+ listHead = tlst->next;
+ }
+ else
+ {
+ last->next = tlst->next;
+ }
+ delete tlst;
+ thumbs--;
+
+ // Removing a thumbnail means a new layout and new bounding boxes
+ maxHeight = 0; tlst = listHead;
+ for (i=0; i<thumbs; i++)
+ {
+ int ph;
+ rviewThumbPixList *tplst = tlst->pixmaps;
+
+ while (tplst != NULL)
+ {
+ ph = tplst->pixmap->getHeight();
+ if (ph > maxHeight) maxHeight = ph;
+ tplst = tplst->next;
+ }
+ tlst = tlst->next;
+ }
+ // Close thumbnail viewer when the last thumbnail has been deleted
+ if (thumbs <= 0)
+ {
+ this->Close(TRUE);
+ }
+ else
+ {
+ updateCanvasSize();
+ }
+ return 1;
+ }
+ return 0;
+}
+
+
+void rviewThumb::setLayout(int width, int npl)
+{
+ imgWidth = width; thumbsperline = npl;
+ updateCanvasSize();
+}
+
+
+void rviewThumb::label(void)
+{
+ SetTitle(lman->lookup("titleThumb"));
+ mbar->SetLabelTop(0, lman->lookup("menThumbData"));
+ mbar->SetLabel(MENU_THUMB_DATA_CLOSE, lman->lookup("menThumbDataClose"));
+ mbar->SetLabelTop(1, lman->lookup("menThumbSetup"));
+ mbar->SetLabel(MENU_THUMB_SETUP_CSPACE, lman->lookup("menCspaceTitle"));
+ mbar->SetLabel(MENU_THUMB_CSPACE_ON, lman->lookup("menCspaceOn"));
+ mbar->SetLabel(MENU_THUMB_CSPACE_FULL, lman->lookup("menCspaceFull"));
+ mbar->SetLabel(MENU_THUMB_CSPACE_EDIT, lman->lookup("menCspaceEdit"));
+
+ project->SetLabel(lman->lookup("textProjString"));
+ thumbProj->SetLabel(lman->lookup("textThumbProjDim"));
+ thumbStep->SetLabel(lman->lookup("textThumbProjStep"));
+ thumbWidth->SetLabel(lman->lookup("textThumbWidth"));
+ thumbCols->SetLabel(lman->lookup("textThumbColumns"));
+}
+
+
+int rviewThumb::process(wxObject &obj, wxEvent &evt)
+{
+ int type = evt.GetEventType();
+
+ if (type == wxEVENT_TYPE_TEXT_ENTER_COMMAND)
+ {
+ char buffer[STRINGSIZE];
+ int newVal;
+
+ if (&obj == (wxObject*)thumbWidth)
+ {
+ newVal = atoi(thumbWidth->GetValue());
+ if ((newVal < thumb_minwidth) || (newVal > thumb_maxwidth))
+ {
+ sprintf(buffer, "%d", imgWidth);
+ thumbWidth->SetValue(buffer);
+ }
+ else
+ {
+ newThumbWidth(newVal);
+ }
+ return 1;
+ }
+ if (&obj == (wxObject*)thumbCols)
+ {
+ newVal = atoi(thumbCols->GetValue());
+ if ((newVal < thumb_mincols) || (newVal > thumb_maxcols))
+ {
+ sprintf(buffer, "%d", thumbsperline);
+ thumbCols->SetValue(buffer);
+ }
+ else
+ {
+ thumbsperline = newVal;
+ updateCanvasSize();
+ }
+ return 1;
+ }
+ if (&obj == (wxObject*)project)
+ {
+ if (thumbs > 0)
+ {
+ unsigned int oldProj;
+ int oldFrom, oldTo;
+
+ oldProj = dimproj;
+ if (dimproj >= 0)
+ {
+ oldFrom = pt1[dimproj]; oldTo = pt2[dimproj];
+ }
+ strcpy(projString, project->GetValue());
+ if (parseProjection(listHead->mdd) != 0)
+ {
+ bool fromScratch = TRUE;
+
+ // Determine whether we have to rebuild everything from scratch or not
+ if ((int)oldProj == dimproj)
+ {
+ if (dimproj >= 0)
+ {
+ if ((pt1[dimproj] == oldFrom) && (pt2[dimproj] == oldTo)) fromScratch = TRUE;
+ }
+ }
+ rebuildThumbnails(fromScratch);
+ }
+ }
+ return 1;
+ }
+ if (&obj == (wxObject*)thumbStep)
+ {
+ int oldStep = projstep;
+
+ projstep = atoi(thumbStep->GetValue());
+ if (projstep <= 0)
+ {
+ projstep = 1;
+ thumbProj->SetValue("1");
+ }
+ if ((dimMDD > 2) && (oldStep != projstep)) rebuildThumbnails(TRUE);
+
+ return 1;
+ }
+ if (&obj == (wxObject*)thumbProj)
+ {
+ if ((thumbs > 0) && (dimMDD > 2))
+ {
+ if (parseProjection(listHead->mdd) != 0)
+ {
+ rebuildThumbnails(TRUE);
+ }
+ }
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+const char *rviewThumb::getFrameName(void) const
+{
+ return "rviewThumb";
+}
+
+rviewFrameType rviewThumb::getFrameType(void) const
+{
+ return rviewFrameTypeThumb;
+}
+
+
+void rviewThumb::OnSize(int w, int h)
+{
+ int x, y, tw, py, px;
+
+ GetClientSize(&x, &y);
+ if((x < thumb_width) || (y < thumb_height))
+ {
+ frameWidth = x;
+ frameHeight = y;
+ SetClientSize(thumb_width, thumb_height);
+ return;
+ }
+
+ panel->SetSize(0, thumb_border, x, thumb_cheight);
+ x -= 2*thumb_border; y -= 2*thumb_border + thumb_cheight;
+ canvas->SetSize(thumb_border, thumb_border + thumb_cheight, x, y);
+
+ tw = (x - 2*thumb_prjwidth - 2*thumb_twidth - 6*thumb_border);
+ py = thumb_border;
+ px = thumb_border;
+ project->SetSize(px, py, tw , thumb_theight);
+ px +=thumb_border + tw;
+ thumbProj->SetSize(px, py, thumb_prjwidth, thumb_theight);
+ px +=thumb_prjwidth + thumb_border;
+ thumbStep->SetSize(px, py, thumb_prjwidth, thumb_theight);
+ px +=thumb_prjwidth + thumb_border;
+ thumbWidth->SetSize(px, py, thumb_twidth, thumb_theight);
+ px +=thumb_twidth + thumb_border;
+ thumbCols->SetSize(px, py, thumb_twidth, thumb_theight);
+}
+
+
+void rviewThumb::OnMenuCommand(int id)
+{
+ switch (id)
+ {
+ case MENU_THUMB_DATA_CLOSE:
+ this->Close(TRUE); break;
+ case MENU_THUMB_CSPACE_EDIT:
+ csmap->openEditor(); break;
+ case MENU_THUMB_CSPACE_ON:
+ {
+ rviewThumbList *tlst = listHead;
+ int i;
+
+ // Don't allow switching off cspace mapping if at least one object is float/double.
+ for (i=0; i<thumbs; i++)
+ {
+ if ((tlst->baseType == rbt_float) || (tlst->baseType == rbt_double)) break;
+ tlst = tlst->next;
+ }
+ if (i < thumbs)
+ {
+ mbar->Check(MENU_THUMB_CSPACE_ON, TRUE);
+ }
+ else
+ {
+ doValToCspace = mbar->Checked(MENU_THUMB_CSPACE_ON);
+ mbar->Enable(MENU_THUMB_CSPACE_FULL, doValToCspace);
+ mbar->Enable(MENU_THUMB_CSPACE_EDIT, doValToCspace);
+ rebuildThumbnails(FALSE);
+ }
+ }
+ break;
+ case MENU_THUMB_CSPACE_FULL:
+ doFullRangeCspace = mbar->Checked(MENU_THUMB_CSPACE_FULL);
+ if (csmap != NULL)
+ {
+ csmap->processRange((doFullRangeCspace) ? CSPACE_RANGE_FULL : CSPACE_RANGE_ACTUAL);
+ }
+ rebuildThumbnails(FALSE);
+ break;
+ default: break;
+ }
+}
+
+
+int rviewThumb::userEvent(const user_event &ue)
+{
+ if (ue.type == usr_mdd_dying)
+ {
+ return deleteMDD(*((r_Ref<r_GMarray>*)(ue.data)));
+ }
+ if (ue.type == usr_cspace_changed)
+ {
+ if (ue.data == (void*)csmap)
+ {
+ rebuildThumbnails(FALSE);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+// Return the pixmap with number no and write a textual description into
+// caption which has to be at least STRINGSIZE bytes large.
+wxPixmap *rviewThumb::getPixmapNumber(int no, char *caption)
+{
+ rviewThumbList *tlst = listHead;
+ int major, minor;
+ wxPixmap *retPix = NULL;
+
+ if (no >= numPixmaps) return NULL;
+
+ // major = number of MDD object, minor = number of pixmap for this object
+ major = 0; minor = 0;
+
+ while ((tlst != NULL) && (no > 0))
+ {
+ minor = 0;
+ if (no < tlst->numPix)
+ {
+ rviewThumbPixList *tplst = tlst->pixmaps;
+ while ((tplst != NULL) && (no > 0))
+ {
+ tplst = tplst->next; minor++; no--;
+ }
+ if (tplst == NULL)
+ {
+ retPix = NULL;
+ break;
+ }
+ else
+ {
+ //cout << "found " << (void*)(tplst->pixmap) << endl;
+ retPix = tplst->pixmap;
+ break;
+ }
+ }
+ else
+ {
+ no -= tlst->numPix; tlst = tlst->next; major++;
+ }
+ }
+ if ((retPix == NULL) && (tlst != NULL))
+ {
+ if ((no == 0) && (tlst->numPix > 0))
+ {
+ retPix = tlst->pixmaps->pixmap;
+ }
+ }
+
+ if (retPix != NULL)
+ {
+ sprintf(caption, "MDD %d [%d]", major, minor*projstep);
+ }
+
+ return retPix;
+}
+
+
+void rviewThumb::getThumbInfo(int &num, int &npl)
+{
+ num = numPixmaps; npl = thumbsperline;
+}
+
+
+void rviewThumb::getGridInfo(int &gx, int &gy)
+{
+ gx = gridX; gy = gridY;
+}
+
+
+void rviewThumb::updateCanvasSize(void)
+{
+ int stepx, stepy;
+ int scrollx, scrolly;
+
+ RMDBGONCE(3, RMDebug::module_applications, "rviewThumb", "updateCanvasSize()");
+
+ gridX = imgWidth + thumb_space;
+ gridY = maxHeight + thumb_space;
+
+ scrollx = canvas->GetScrollPos(wxHORIZONTAL); scrolly = canvas->GetScrollPos(wxVERTICAL);
+
+ stepx = (gridX * thumbsperline + thumb_scrstep - 1) / thumb_scrstep;
+ if ((numPixmaps == 0) || (thumbsperline == 0))
+ {
+ stepy = 1;
+ canvas->EnableScrolling(TRUE, FALSE);
+ canvas->SetScrollRange(wxVERTICAL, 0);
+ }
+ else
+ {
+ stepy = (((numPixmaps + thumbsperline - 1) / thumbsperline) * gridY + thumb_scrstep - 1) / thumb_scrstep;
+ canvas->EnableScrolling(TRUE, TRUE);
+ }
+ canvas->SetScrollbars(thumb_scrstep, thumb_scrstep, stepx, stepy, thumb_pgstep, thumb_pgstep, scrollx, scrolly);
+}
+
+
+
+// Init internal variables (e.g. projection-related) according to a sample object
+void rviewThumb::initForObject(r_Ref<r_GMarray> &mddObj)
+{
+ char *data;
+ int i;
+ r_Minterval interv;
+
+ interv = mddObj->spatial_domain();
+ dimMDD = interv.dimension();
+ // freeDims is a bitfield specifying which dimensions are free
+ if (dimMDD <= 2)
+ {
+ freeDims = 3;
+ }
+ else
+ {
+ if ((dimproj == -1) || (dimproj >= dimMDD)) freeDims = 3;
+ else
+ {
+ if (dimproj == 0) freeDims = 6;
+ else if (dimproj == 1) freeDims = 5;
+ else freeDims = 3;
+ }
+ }
+ pt1 = r_Point(dimMDD); pt2 = r_Point(dimMDD);
+ data = projString;
+ for (i=0; i<dimMDD; i++)
+ {
+ pt1[i] = interv[i].low();
+ if ((freeDims & (1<<i)) == 0)
+ {
+ data += sprintf(data, "%d, ", interv[i].low());
+ pt2[i] = interv[i].low();
+ }
+ else
+ {
+ data += sprintf(data, "*:*, ");
+ pt2[i] = interv[i].high();
+ }
+ }
+ data[-2] = 0; // cut the final ", "
+ project->SetValue(projString);
+ parseProjection(mddObj);
+}
+
+
+// Parse the projection string and set up all internal variables that depend on it.
+int rviewThumb::parseProjection(r_Ref<r_GMarray> &mddObj)
+{
+ int x, h;
+
+ mapIndex = r_Point(dimMDD);
+ if (rviewParseProjection(mddObj->spatial_domain(), pt1, pt2, projString, &freeDims, &mapIndex) != dimMDD)
+ {
+ cerr << lman->lookup("errorProjection") << endl;
+ rviewErrorbox eb(lman->lookup("errorProjection")); eb.activate();
+ return 0;
+ }
+
+ dimproj = -1; dim1 = -1; dim2 = -1;
+ for (x=0; x<dimMDD; x++)
+ {
+ if ((freeDims & (1<<x)) != 0)
+ {
+ if (dim1 < 0)
+ dim1 = x;
+ else if (dim2 < 0)
+ dim2 = x;
+ else if (dimproj < 0)
+ dimproj = x;
+ else
+ break;
+ }
+ }
+ if (x < dimMDD)
+ {
+ cerr << lman->lookup("errorProjThumb") << endl;
+ return 0;
+ }
+ //cout << "parseProj: dim1 " << dim1 << ", dim2 " << dim2 << ", dimproj " << dimproj << endl;
+ // are there 3 free dimensions to begin with?
+ if (dimproj >= 0)
+ {
+ // user-specified projection value overrides default (last free one)
+ h = atoi(thumbProj->GetValue());
+ // Now swap around the dimensions as required
+ if (h == dim1)
+ {
+ dim1 = dim2; dim2 = dimproj; dimproj = h;
+ }
+ else if (h == dim2)
+ {
+ dim2 = dimproj; dimproj = h;
+ }
+ // otherwise just keep the default dimproj value
+ }
+ dim1 = mapIndex[dim1]; dim2 = mapIndex[dim2];
+
+ // Also read the other variables that can change the appearance of the thumbnails
+ h = atoi(thumbWidth->GetValue());
+ if ((h >= thumb_minwidth) && (h <= thumb_maxwidth))
+ {
+ imgWidth = h;
+ }
+ h = atoi(thumbStep->GetValue());
+ if (h > 0)
+ {
+ projstep = h;
+ }
+
+ return 1;
+}
+
+
+
+
+wxPixmap *rviewThumb::buildThumbnail(r_Ref<r_GMarray> &mddObj, rviewBaseType baseType, int dimproject, int projval)
+{
+ char *data;
+ wxPixmap *pixmap;
+ wxColour palette[2];
+ int baseSize;
+ int x;
+ r_Minterval thisInterv;
+ int objdim;
+ int srcWidth;
+ r_Point ptlow, pthigh;
+
+ RMDBGENTER(3, RMDebug::module_applications, "rviewThumb", "buildThumbnail(...)");
+
+ //cout << "thumbnail " << dimproject << ", " << projval << endl;
+
+ thisInterv = mddObj->spatial_domain();
+ objdim = thisInterv.dimension();
+
+ // Only data with at least 2 dimensions is allowed
+ if (objdim < 2)
+ return NULL;
+
+ // Check if all the thumbnails have the same number of dimensions
+ if (dimMDD != objdim)
+ {
+ cerr << "Warning: inconsistent number of dimensions in collection!" << endl;
+ }
+
+ // Make sure the points we use are within the spatial domain of this object, in case
+ // the objects in this collection don't have a uniform spatial domain.
+ ptlow = r_Point(dimMDD); pthigh = r_Point(dimMDD);
+ for (x=0; x<dimMDD; x++)
+ {
+ if (pt1[x] >= thisInterv[x].low()) ptlow[x] = pt1[x]; else ptlow[x] = thisInterv[x].low();
+ if (pt2[x] <= thisInterv[x].high()) pthigh[x] = pt2[x]; else pthigh[x] = thisInterv[x].high();
+ }
+ //cout << "Corners " << pt1 << ", " << pt2 << endl;
+ //cout << "low " << ptlow << ", high " << pthigh << endl;
+
+ baseSize = (int)(mddObj->get_type_length());
+
+ if ((baseType == rbt_float) || (baseType == rbt_double))
+ {
+ doValToCspace = TRUE;
+ mbar->Check(MENU_THUMB_CSPACE_ON, TRUE);
+ configureCspace(TRUE);
+ }
+
+ rviewFlatProjEnv penv;
+
+ penv.mddPtr = mddObj.ptr();
+ penv.pt1 = ptlow; penv.pt2 = pthigh;
+ penv.dim1 = dim1; penv.dim2 = dim2;
+ penv.bt = baseType;
+ penv.doCspace = doValToCspace;
+
+ if (dimproject >= 0)
+ {
+ penv.pt1[dimproject] = projval; penv.pt2[dimproject] = projval;
+ }
+ srcWidth = (int)(pthigh[dim1] - ptlow[dim1] + 1);
+ //cout << "srcWidth " << srcWidth << endl;
+ if (srcWidth < 1) srcWidth = 1;
+ penv.scale = ((double)imgWidth) / srcWidth;
+ //cout << "dimproject " << dimproject << ", projval " << projval
+ // << ", scale " << penv.scale << endl;
+ //cout << "penv " << penv.pt1 << ", " << penv.pt2 << endl;
+
+ if (rviewPrepareFlatProjection(penv) != 0) return NULL;
+
+ if (rviewImageTypes[baseType] == RVIEW_IMGTYPE_MONO)
+ {
+ palette[0] = wxColour(0,0,0); palette[1] = wxColour(255,255,255);
+ }
+
+ // Colourspace mapping possible for this object?
+ if (rviewCheckInitCspace(baseType, NULL, mddObj) != 0) canDoCspace = TRUE;
+
+ if (doValToCspace)
+ {
+ penv.cspaceState = rviewCheckInitCspace(baseType, &csmap, mddObj, doFullRangeCspace, NULL, penv.width, &penv.pitch, &penv.depth, &penv.pad);
+ if (csmap != NULL) mbar->Enable(MENU_THUMB_CSPACE_EDIT, TRUE);
+ }
+ else
+ penv.cspaceState = 0;
+
+ penv.csmap = csmap;
+
+ /*if (penv.pitch * penv.height >= 16*1024*1024)
+ return NULL;*/
+
+ if ((data = (char*)malloc(penv.pitch * penv.height)) == NULL)
+ return NULL;
+
+ if (rviewPerformFlatProjection(penv, data) != 0)
+ {
+ free(data); return NULL;
+ }
+
+ pixmap = new wxPixmap((wxWindow*)canvas, penv.width, penv.height, penv.depth, penv.pad, data, rviewImage::getPixmapFlags(), (rviewImageTypes[baseType] == RVIEW_IMGTYPE_MONO) ? palette : NULL);
+
+ RMDBGEXIT(3, RMDebug::module_applications, "rviewThumb", "buildThumbnail(...) Pixmap " << (void*)pixmap );
+
+ return pixmap;
+}
+
+
+
+
+void rviewThumb::newThumbWidth(int newWidth)
+{
+ if (newWidth == imgWidth) return;
+ imgWidth = newWidth;
+
+ rebuildThumbnails(FALSE);
+}
+
+
+
+void rviewThumb::rebuildThumbnails(bool fromScratch)
+{
+ int i, j;
+ rviewThumbList *tlst;
+ rviewThumbPixList *tplst;
+
+ //cout << "rebuildThumbnails " << fromScratch << endl;
+
+ tlst = listHead;
+
+ if (fromScratch)
+ {
+ // Delete all thumbnail pixmaps, including the chain structure
+ for (i=0; i<thumbs; i++, tlst = tlst->next)
+ {
+ deletePixmapChain(tlst);
+ }
+ maxHeight = 0;
+ for (i=0, tlst=listHead; i<thumbs; i++, tlst=tlst->next)
+ {
+ if (pixmapsFromMDD(tlst) == 0)
+ {
+ cerr << lman->lookup("errorProjThumb") << endl;
+ }
+ }
+ }
+ else
+ {
+ // 1) Delete all the thumbnail pixmaps, but leave the chain intact!
+ for (i=0; i<thumbs; i++, tlst = tlst->next)
+ {
+ tplst = tlst->pixmaps;
+ while (tplst != NULL)
+ {
+ if (tplst->pixmap != NULL) delete tplst->pixmap;
+ tplst->pixmap = NULL; tplst = tplst->next;
+ }
+ }
+ // 2) Create new ones. Doing this in two passes is better for the memory allocation
+ for (i=0, tlst=listHead; i<thumbs; i++, tlst = tlst->next)
+ {
+ tplst = tlst->pixmaps;
+ while (tplst != NULL)
+ {
+ if ((tplst->pixmap = buildThumbnail(tlst->mdd, tlst->baseType, tplst->dimproj, tplst->projval)) == NULL)
+ {
+ cerr << lman->lookup("errorProjThumb") << endl;
+ }
+ tplst = tplst->next;
+ }
+ }
+ }
+
+ // Now adapt the maximum height
+ maxHeight = 0; tlst = listHead;
+ for (i=0; i<thumbs; i++, tlst=tlst->next)
+ {
+ tplst = tlst->pixmaps;
+ while (tplst != NULL)
+ {
+ if (tplst->pixmap != NULL)
+ {
+ j = tplst->pixmap->getHeight();
+ if (j > maxHeight) maxHeight = j;
+ }
+ tplst = tplst->next;
+ }
+ }
+
+ updateCanvasSize();
+}
diff --git a/applications/rview/rviewThumb.hh b/applications/rview/rviewThumb.hh
new file mode 100644
index 0000000..dc30c24
--- /dev/null
+++ b/applications/rview/rviewThumb.hh
@@ -0,0 +1,203 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+ * PURPOSE:
+ *
+ * rView thumbnail viewer class. Unlike the regular MDD viewers (e.g.
+ * rviewImage) this is not derived from rviewDisplay because it can
+ * display any number of MDD objects in contrast to regular viewers
+ * which manage exactly one object.
+ *
+ * COMMENTS:
+ * None
+ */
+
+
+
+#ifndef _RVIEW_THUMB_H_
+#define _RVIEW_THUMB_H_
+
+
+
+
+#include "rasodmg/ref.hh"
+#include "rasodmg/marray.hh"
+#include "rasodmg/gmarray.hh"
+
+#include "labelManager.hh"
+#include "rviewUtils.hh"
+#include "rviewDisplay.hh"
+#include "rviewDModes.hh"
+
+
+
+
+class wxPixmap;
+class rviewThumb;
+
+
+// List holding all the pixmap items for one mddObject.
+// This chain is 1 item long for 2D data, but can be any length
+// for higher dimensions
+typedef struct rviewThumbPixList {
+ wxPixmap *pixmap;
+ int dimproj, projval;
+ rviewThumbPixList *next;
+} rviewThumbPixList;
+
+// List holding mdd/pixmap items
+typedef struct rviewThumbList {
+ r_Ref<r_GMarray> mdd;
+ rviewBaseType baseType;
+ int numPix;
+ rviewThumbPixList *pixmaps;
+ rviewThumbList *next;
+} rviewThumbList;
+
+
+
+
+/*
+ * The canvas displaying the thumbnails
+ */
+class thumbCanvas: public wxCanvas
+{
+ public:
+
+ thumbCanvas(rviewThumb *par, int x, int y, int width, int height);
+ ~thumbCanvas(void);
+
+ void OnPaint(void);
+ void updateDisplay(void);
+
+
+ protected:
+
+ wxBrush brush;
+ rviewThumb *parent;
+};
+
+
+
+/*
+ * A window containing small versions of images
+ */
+class rviewThumb: public rviewFrame
+{
+ public:
+
+ rviewThumb(void);
+ ~rviewThumb(void);
+
+ int addMDD(r_Ref<r_GMarray> &newMdd);
+ int deleteMDD(r_Ref<r_GMarray> &obsMdd);
+ void setLayout(int width, int npl);
+ void newThumbWidth(int newWidth);
+
+ void label(void);
+ int process(wxObject &obj, wxEvent &evt);
+ virtual const char *getFrameName(void) const;
+ virtual rviewFrameType getFrameType(void) const;
+
+ void OnSize(int w, int h);
+ void OnMenuCommand(int id);
+
+ int userEvent(const user_event &ue);
+
+ // Used by canvas to get data
+ wxPixmap *getPixmapNumber(int no, char *caption);
+ void getThumbInfo(int &num, int &npl);
+ void getGridInfo(int &gx, int &gy);
+
+ // constants
+ // Initial dimensions of window
+ static const int thumb_width;
+ static const int thumb_height;
+ // Default width of thumbnail images
+ static const int thumb_imgwidth;
+ // Default number of thumbnails per line
+ static const int thumb_perline;
+ // Space between thumbnails
+ static const int thumb_space;
+ // Borders used in thumbnail window
+ static const int thumb_border;
+ // Scrolling values
+ static const int thumb_scrstep;
+ static const int thumb_pgstep;
+ // Dimensions of checkboxs
+ static const int thumb_chkwidth;
+ static const int thumb_chkheight;
+ // Minimum / maximum width of thumbnails
+ static const int thumb_minwidth;
+ static const int thumb_maxwidth;
+ // Minimum / maximum number of thumbnails per line
+ static const int thumb_mincols;
+ static const int thumb_maxcols;
+ // Height of control panel at the top
+ static const int thumb_cheight;
+ // Height of text items
+ static const int thumb_twidth;
+ static const int thumb_theight;
+ // Width of projDim / step widgets
+ static const int thumb_prjwidth;
+
+
+ protected:
+
+ void deletePixmapChain(rviewThumbList *tlst);
+ int pixmapsFromMDD(rviewThumbList *tlst);
+ wxPixmap *buildThumbnail(r_Ref<r_GMarray> &mddObj, rviewBaseType baseType, int dimproject, int projval);
+ void updateCanvasSize(void);
+ void rebuildThumbnails(bool fromScratch);
+ void initForObject(r_Ref<r_GMarray> &mddObj);
+ int parseProjection(r_Ref<r_GMarray> &mddObj);
+ void configureCspace(bool mode);
+
+ char projString[STRINGSIZE];
+ r_Point pt1, pt2, mapIndex;
+ int thumbs, thumbsperline, numPixmaps;
+ int maxHeight;
+ int gridX, gridY;
+ int imgWidth;
+ int dimMDD; // should be constant for all objects!
+ int dim1, dim2; // dimensions to iterate over
+ int dimproj; // projection dim for 3+D objects
+ int projstep; // stepping value in dimproj
+ unsigned int freeDims;
+ rviewThumbList *listHead;
+ thumbCanvas *canvas;
+ wxMenuBar *mbar;
+ wxPanel *panel;
+ rviewText *thumbWidth;
+ rviewText *thumbCols;
+ rviewText *project;
+ rviewText *thumbProj, *thumbStep;
+ wxFont *font;
+ colourspaceMapper *csmap;
+ bool doValToCspace;
+ bool doFullRangeCspace;
+ bool canDoCspace;
+};
+
+#endif
diff --git a/applications/rview/rviewTypeMan.cpp b/applications/rview/rviewTypeMan.cpp
new file mode 100644
index 0000000..9a0af2c
--- /dev/null
+++ b/applications/rview/rviewTypeMan.cpp
@@ -0,0 +1,564 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+ * COMMENTS:
+ * None
+ */
+
+// Standard wxWindows preamble.
+#ifdef __GNUG__
+#pragma implementation
+#endif
+
+
+// changed in wxWindows 2.4.2:
+//#include "wx_prec.h"
+#include <wx/wxprec.h>
+
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+
+#ifndef WX_PRECOMP
+#include <wx/wx.h>
+#endif
+
+
+
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#endif
+
+#include "rviewTypeMan.hh"
+#include "raslib/primitivetype.hh"
+#include "raslib/structuretype.hh"
+
+
+// use extremely large default values, otherwise the window doesn't open
+// correctly on Windows.
+const int rviewTypeMan::tman_width = 1000;
+const int rviewTypeMan::tman_height = 2000;
+const int rviewTypeMan::tman_border = 8;
+const int rviewTypeMan::tman_basewidth = 100;
+const int rviewTypeMan::tman_cheight = 30;
+const int rviewTypeMan::tman_bheight = 30;
+const int rviewTypeMan::tman_bwidth = 50;
+
+// Type keywords
+const char rviewTypeMan::structName[] = "struct";
+const char rviewTypeMan::marrayName[] = "marray";
+
+// String constants for type names
+const char rviewTypeMan::typeBool[] = "bool";
+const char rviewTypeMan::typeChar[] = "char";
+const char rviewTypeMan::typeOctet[] = "octet";
+const char rviewTypeMan::typeShort[] = "short";
+const char rviewTypeMan::typeUShort[] = "ushort";
+const char rviewTypeMan::typeLong[] = "long";
+const char rviewTypeMan::typeULong[] = "ulong";
+const char rviewTypeMan::typeFloat[] = "float";
+const char rviewTypeMan::typeDouble[] = "double";
+
+
+
+void rviewTypeMan::initShare(rviewFrame *parentWindow)
+{
+ numStruct = 0; numMembers = 0; typeDepth = 0;
+ structures = NULL; members = NULL; offsets = NULL; primtypes = NULL;
+ typeNames = NULL;
+ myType = NULL; panel = NULL;
+ parent = parentWindow;
+}
+
+
+rviewTypeMan::rviewTypeMan(rviewFrame *parentWindow) : rviewFrame(NULL, lman->lookup("titleTypeMan"), 0, 0, tman_width, tman_height)
+{
+ initShare(parentWindow);
+}
+
+
+rviewTypeMan::rviewTypeMan(rviewFrame *parentWindow, const r_Type *type) : rviewFrame(NULL, lman->lookup("titleTypeMan"), 0, 0, tman_width, tman_height)
+{
+ initShare(parentWindow);
+ setType(type);
+}
+
+
+rviewTypeMan::~rviewTypeMan(void)
+{
+ user_event usr;
+
+ usr.type = usr_child_closed; usr.data = (void*)this;
+ if (parent != NULL) parent->userEvent(usr);
+
+ clearData();
+}
+
+
+void rviewTypeMan::unlinkParent(void)
+{
+ parent = NULL;
+}
+
+
+void rviewTypeMan::clearData(void)
+{
+ if (structures != NULL) {delete [] structures; structures = NULL;}
+ if (members != NULL) {delete [] members; members = NULL;}
+ if (offsets != NULL) {delete [] offsets; offsets = NULL;}
+ if (primtypes != NULL) {delete [] primtypes; primtypes = NULL;}
+ if (typeNames != NULL) {delete [] typeNames; typeNames = NULL;}
+
+ if (myType != NULL) {delete myType; myType = NULL;}
+
+ if (panel != NULL) {delete panel; panel = NULL;}
+
+ initShare(parent);
+}
+
+
+// The name can't be read from cloned r_Types (not copied). Bug?
+void rviewTypeMan::parsePrimitiveType(const r_Primitive_Type *tp, const char *name, unsigned int &numm, unsigned int offset, wxRect *bbox)
+{
+ if (members != NULL)
+ {
+ char buffer[STRINGSIZE];
+ const char *tname = NULL;
+
+ switch (tp->type_id())
+ {
+ case r_Primitive_Type::BOOL: tname = typeBool; break;
+ case r_Primitive_Type::CHAR: tname = typeChar; break;
+ case r_Primitive_Type::OCTET: tname = typeOctet; break;
+ case r_Primitive_Type::SHORT: tname = typeShort; break;
+ case r_Primitive_Type::USHORT: tname = typeUShort; break;
+ case r_Primitive_Type::LONG: tname = typeLong; break;
+ case r_Primitive_Type::ULONG: tname = typeULong; break;
+ case r_Primitive_Type::FLOAT: tname = typeFloat; break;
+ case r_Primitive_Type::DOUBLE: tname = typeDouble; break;
+ default: break;
+ }
+ typeNames[numm] = tname;
+ sprintf(buffer, "%s (%s)", name, (tname == NULL) ? "" : tname);
+ members[numm]->SetLabel(buffer);
+ members[numm]->SetSize(bbox->x, bbox->y, bbox->width, bbox->height);
+ offsets[numm] = offset;
+ primtypes[numm] = tp->type_id();
+ }
+ numm++;
+}
+
+
+void rviewTypeMan::parseStructType(const r_Structure_Type *tp, unsigned int &nums, unsigned int &numm, unsigned int depth, unsigned int offset, wxRect *bbox)
+{
+ wxRect pos;
+ unsigned int thisStruct = nums++;
+
+ if (bbox != NULL)
+ {
+ pos.x = bbox->x + tman_border;
+ pos.width = bbox->width - 2*tman_border;
+ pos.y = bbox->y + tman_border;
+ pos.height = tman_cheight;
+ }
+
+ if (depth > typeDepth) typeDepth = depth;
+
+ r_Structure_Type::attribute_iterator iter(tp->defines_attribute_begin());
+ while (iter != tp->defines_attribute_end())
+ {
+ r_Type *newType;
+ unsigned int off = offset + (*iter).offset();
+
+ //(*iter).print_status(cout); cout << " --- " << (*iter).name() << endl;
+ newType = (*iter).type_of().clone();
+ if (newType->isStructType())
+ {
+ parseStructType((const r_Structure_Type*)newType, nums, numm, depth+1, off, &pos);
+ }
+ else
+ {
+ parsePrimitiveType((const r_Primitive_Type*)newType, (*iter).name(), numm, off, &pos);
+ pos.y += pos.height;
+ }
+ delete newType;
+ iter++;
+ }
+ if (structures != NULL)
+ {
+ structures[thisStruct]->SetSize(bbox->x, bbox->y, bbox->width, pos.y - bbox->y + tman_border/2);
+ bbox->y = pos.y + tman_border;
+ }
+}
+
+
+void rviewTypeMan::setType(const r_Type *type)
+{
+ unsigned int nums, numm, i;
+ wxRect bbox;
+
+ clearData();
+ panel = new wxPanel(this, -1, -1, -1, -1);
+ myType = type->clone();
+
+ if (myType->isStructType())
+ parseStructType((r_Structure_Type*)type, numStruct, numMembers, 1);
+ else
+ parsePrimitiveType((r_Primitive_Type*)type, "", numMembers);
+
+ if (numStruct != 0)
+ {
+ structures = new wxGroupBox*[numStruct];
+ for (i=0; i<numStruct; i++) structures[i] = new wxGroupBox(panel, "", -1, -1, -1, -1);
+ }
+ members = new rviewCheckBox*[numMembers];
+ for (i=0; i<numMembers; i++)
+ {
+ members[i] = new rviewCheckBox(panel);
+ }
+ offsets = new unsigned int[numMembers];
+ primtypes = new unsigned char[numMembers];
+ typeNames = new const char*[numMembers];
+ baseTypeLength = ((r_Base_Type*)myType)->size();
+
+ nums = 0; numm = 0;
+ bbox.x = tman_border; bbox.y = tman_border;
+ bbox.width = tman_basewidth + 2*tman_border * typeDepth;
+ bbox.height = numMembers * tman_cheight + 2*tman_border * numStruct;
+ if (myType->isStructType())
+ parseStructType((r_Structure_Type*)type, nums, numm, 1, 0, &bbox);
+ else
+ parsePrimitiveType((r_Primitive_Type*)type, "", numm, 0, &bbox);
+
+ closeBut = new rviewButton(panel);
+ convertBut = new rviewButton(panel);
+
+ label();
+
+ bbox.width += 2*tman_border; bbox.height += 2*tman_border;
+ closeBut->SetSize(tman_border, bbox.height, tman_bwidth, tman_bheight);
+ convertBut->SetSize(bbox.width - tman_border - tman_bwidth, bbox.height, tman_bwidth, tman_bheight);
+ bbox.height += tman_bheight + tman_border + rview_window_extra_height;
+
+ SetSize(0, 0, bbox.width, bbox.height);
+ panel->SetSize(0, 0, bbox.width, bbox.height);
+
+ //for (i=0; i<numMembers; i++) cout << (int)(offsets[i]) << ' '; cout << endl;
+
+ Show(TRUE);
+}
+
+
+void rviewTypeMan::label(void)
+{
+ SetTitle(lman->lookup("titleTypeMan"));
+ closeBut->SetLabel(lman->lookup("textClose"));
+ convertBut->SetLabel(lman->lookup("textConvert"));
+}
+
+
+int rviewTypeMan::process(wxObject &obj, wxEvent &evt)
+{
+ int type = evt.GetEventType();
+
+ if (type == wxEVENT_TYPE_BUTTON_COMMAND)
+ {
+ if (&obj == (wxObject*)closeBut)
+ {
+ Close(TRUE);
+ return 1;
+ }
+ else if (&obj == (wxObject*)convertBut)
+ {
+ user_event usr;
+
+ usr.type = usr_typeman_convert; usr.data = (void*)this;
+ if (parent != NULL) parent->userEvent(usr);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+void rviewTypeMan::OnSize(int w, int h)
+{
+ if (panel != NULL)
+ {
+ panel->SetSize(0, 0, w, h);
+ }
+}
+
+
+/*
+ * Warning: this is in fact quit low-level. Assumes alignment -- handle with care!
+ */
+int rviewTypeMan::convert(r_Ref<r_GMarray> &src, r_Ref<r_GMarray> &dest)
+{
+ unsigned int i, newMembers=0;
+
+ //cout << "rviewTypeMan::convert()" << endl;
+
+ for (i=0; i<numMembers; i++)
+ {
+ if (members[i]->GetValue()) newMembers++;
+ }
+ if (newMembers == 0)
+ {
+ cerr << "No types selected; ignored." << endl;
+ return -1;
+ }
+ const r_Type *srcBaseType = src->get_base_type_schema();
+ if (srcBaseType == NULL)
+ {
+ cerr << "No base type information available for object; ignored." << endl;
+ return -1;
+ }
+ if (((r_Base_Type*)srcBaseType)->size() != baseTypeLength)
+ {
+ cerr << "Base type incompatible; ignored." << endl;
+ return -1;
+ }
+
+ unsigned int *newOff = new unsigned int[newMembers];
+ unsigned int *srcIndex = new unsigned int[newMembers];
+ unsigned int j;
+
+ for (i=0, j=0; i<numMembers; i++)
+ {
+ if (members[i]->GetValue()) srcIndex[j++] = i;
+ }
+ //cout << "src index OK" << endl;
+
+ unsigned int off;
+ int needsAlign=1;
+
+ for (i=0, off=0; i<newMembers; i++)
+ {
+ int increment = 1;
+
+ // align certain types
+ switch (primtypes[srcIndex[i]])
+ {
+ case r_Primitive_Type::SHORT:
+ case r_Primitive_Type::USHORT:
+ off = (off+1) & ~1; increment = 2; if (needsAlign < 2) needsAlign = 2;
+ break;
+ case r_Primitive_Type::LONG:
+ case r_Primitive_Type::ULONG:
+ case r_Primitive_Type::FLOAT:
+ off = (off+3) & ~3; increment = 4; if (needsAlign < 4) needsAlign = 4;
+ break;
+ case r_Primitive_Type::DOUBLE:
+ off = (off+3) & ~3; increment = 8; if (needsAlign < 4) needsAlign = 4;
+ break;
+ default: break;
+ }
+ newOff[i] = off; off += increment;
+ }
+ // needsAlign is now the most coarse alignment needed within the type. The start
+ // address of the type itself must also be aligned to this coarseness (e.g.
+ // struct {long, char})
+ unsigned int length = (off + (needsAlign-1)) & ~(needsAlign-1);
+ //cout << "off = " << off << ", length = " << length << endl;
+
+ r_Minterval interv = src->spatial_domain();
+
+#ifdef __VISUALC__
+ // Need this rather roundabout syntax for Visual C
+ dest = (r_Ref<r_GMarray>&)(new r_GMarray);
+#else
+ dest = new r_GMarray;
+#endif
+
+ int dim = interv.dimension();
+ long cells = 1;
+ for (i=0; i<(unsigned int)dim; i++)
+ {
+ cells *= (interv[i].high() - interv[i].low() + 1);
+ }
+ // claim a new array and initialize it, if necessary
+ char *newArray = new char[cells * length];
+ if (needsAlign != 1) memset(newArray, 0, cells*length);
+
+ const char *srcArray = src->get_array();
+ dest->set_array(newArray);
+ dest->set_type_length(length);
+ dest->set_spatial_domain(interv);
+ dest->set_array_size(cells*length);
+
+ unsigned int srcLength = src->get_type_length();
+ long count;
+
+ //cout << "start copying " << newMembers << " members..." << endl;
+ for (i=0; i<newMembers; i++)
+ {
+ //cout << "index " << srcIndex[i] << endl;
+ switch (primtypes[srcIndex[i]])
+ {
+ case r_Primitive_Type::BOOL:
+ case r_Primitive_Type::CHAR:
+ case r_Primitive_Type::OCTET:
+ {
+ const char *s = srcArray + offsets[srcIndex[i]];
+ char *d = newArray + newOff[i];
+
+ for (count=0; count<cells; count++)
+ {
+ *d = *s;
+ s += srcLength; d += length;
+ }
+ }
+ break;
+ case r_Primitive_Type::SHORT:
+ case r_Primitive_Type::USHORT:
+ {
+ const short *s = (const short*)(srcArray + offsets[srcIndex[i]]);
+ short *d = (short*)(newArray + newOff[i]);
+
+ for (count=0; count<cells; count++)
+ {
+ *d = *s;
+ s = (const short*)(((char*)s) + srcLength);
+ d = (short*)(((char*)d) + length);
+ }
+ }
+ break;
+ case r_Primitive_Type::LONG:
+ case r_Primitive_Type::ULONG:
+ case r_Primitive_Type::FLOAT:
+ {
+ const long *s = (const long*)(srcArray + offsets[srcIndex[i]]);
+ long *d = (long*)(newArray + newOff[i]);
+
+ for (count=0; count<cells; count++)
+ {
+ *d = *s;
+ s = (const long*)(((char*)s) + srcLength);
+ d = (long*)(((char*)d) + length);
+ }
+ }
+ break;
+ case r_Primitive_Type::DOUBLE:
+ {
+ const double *s = (const double*)(srcArray + offsets[srcIndex[i]]);
+ double *d = (double*)(newArray + newOff[i]);
+
+ for (count=0; count<cells; count++)
+ {
+ *d = *s;
+ s = (const double*)(((char*)s) + srcLength);
+ d = (double*)(((char*)d) + length);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ delete [] newOff;
+
+ //cout << "build type..." << endl;
+ int strLength = 0;
+ for (i=0; i<newMembers; i++)
+ {
+ strLength += strlen(typeNames[srcIndex[i]]) + 2;
+ }
+ // in case it's a structure type we also need space for "struct { ... }"
+ if (newMembers > 1) strLength += strlen(structName) + 5;
+ // standard wrapper "marray < ... , dim >"
+ strLength += strlen(marrayName) + 5 + 5;
+
+ char *typeString = new char[strLength];
+ char *b = typeString;
+ b += sprintf(b, "%s < ", marrayName);
+ if (newMembers > 1) b += sprintf(b, "%s { ", structName);
+ for (i=0; i<newMembers; i++)
+ {
+ b += sprintf(b, "%s, ", typeNames[srcIndex[i]]);
+ }
+ if (newMembers > 1)
+ strcpy(b-2, " }");
+ else
+ b -= 2;
+ sprintf(b, ", %d >", dim);
+
+ //cout << "TYPE: " << typeString << endl;
+ dest->set_type_structure(typeString);
+
+ //cout << "Checkpoint" << endl;
+
+ // Query for the base type the first time only!
+ if (strlen(baseTypeName) == 0)
+ {
+ // find the base type name...
+ rviewBaseType baseType = rbt_none;
+ if ((newMembers == 3) && (length == 3)) baseType = rbt_rgb;
+ if (newMembers == 1)
+ {
+ switch (primtypes[srcIndex[0]])
+ {
+ case r_Primitive_Type::BOOL: baseType = rbt_bool; break;
+ case r_Primitive_Type::CHAR: baseType = rbt_char; break;
+ case r_Primitive_Type::OCTET: baseType = rbt_uchar; break;
+ case r_Primitive_Type::SHORT: baseType = rbt_short; break;
+ case r_Primitive_Type::USHORT: baseType = rbt_ushort; break;
+ case r_Primitive_Type::LONG: baseType = rbt_long; break;
+ case r_Primitive_Type::ULONG: baseType = rbt_ulong; break;
+ case r_Primitive_Type::FLOAT: baseType = rbt_float; break;
+ case r_Primitive_Type::DOUBLE: baseType = rbt_double; break;
+ default: break;
+ }
+ }
+ if ((baseType != rbt_none) && (dim < MAXIMUM_DIMENSIONS))
+ {
+ baseTypeName = rviewTypeNames[baseType][dim-1];
+ }
+ else
+ {
+ const char *prompt = lman->lookup("promptEnterType");
+ char *msg = new char[strlen(prompt) + strlen(typeString) + 2];
+ sprintf(msg, "%s %s", prompt, typeString);
+ baseTypeName = ::wxGetTextFromUser(msg, lman->lookup("titleEnterType"));
+ delete [] msg;
+ }
+ }
+ dest->set_type_by_name(baseTypeName);
+ //cout << "Base type name = " << baseTypeName << endl;
+
+ /*dest->print_status();
+ const r_Type *btype = dest->get_base_type_schema();
+ if (btype == NULL) cout << "no base type schema" << endl;
+ btype = r_Type::get_any_type(dest->get_type_structure());
+ if (btype == NULL) cout << "string can't be parsed?!?" << endl;*/
+
+ delete [] typeString;
+ delete [] srcIndex;
+
+ return 0;
+}
diff --git a/applications/rview/rviewTypeMan.hh b/applications/rview/rviewTypeMan.hh
new file mode 100644
index 0000000..ef12499
--- /dev/null
+++ b/applications/rview/rviewTypeMan.hh
@@ -0,0 +1,106 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+ * COMMENTS:
+ * None
+ */
+
+#ifndef _RVIEW_TYPE_MAN_H_
+#define _RVIEW_TYPE_MAN_H_
+
+
+#ifdef __GNUG__
+#pragma interface
+#endif
+
+
+#include "rviewUtils.hh"
+#include "rviewDisplay.hh"
+
+
+
+class rviewTypeMan: public rviewFrame
+{
+ public:
+
+ rviewTypeMan(rviewFrame *parentWindow);
+ rviewTypeMan(rviewFrame *parentWindow, const r_Type *type);
+ ~rviewTypeMan(void);
+
+ void unlinkParent(void);
+
+ void setType(const r_Type *type);
+ void label(void);
+ int process(wxObject &obj, wxEvent &evt);
+ void OnSize(int w, int h);
+ int convert(r_Ref<r_GMarray> &src, r_Ref<r_GMarray> &dest);
+
+
+ protected:
+
+ void clearData(void);
+
+ wxPanel *panel;
+ wxGroupBox **structures;
+ rviewCheckBox **members;
+ unsigned int *offsets;
+ unsigned char *primtypes;
+ unsigned int numStruct, numMembers, typeDepth;
+ unsigned int baseTypeLength;
+ r_Type *myType;
+ rviewFrame *parent;
+ rviewButton *closeBut, *convertBut;
+ const char **typeNames;
+ DynamicString baseTypeName;
+
+
+ private:
+
+ void initShare(rviewFrame *parentWindow);
+ void parseStructType(const r_Structure_Type *tp, unsigned int &nums, unsigned int &numm, unsigned int depth, unsigned int offset=0, wxRect *bbox=NULL);
+ void parsePrimitiveType(const r_Primitive_Type *tp, const char *name, unsigned int &numm, unsigned int offset=0, wxRect *bbox=NULL);
+
+ static const char structName[];
+ static const char marrayName[];
+ static const char typeBool[];
+ static const char typeChar[];
+ static const char typeOctet[];
+ static const char typeShort[];
+ static const char typeUShort[];
+ static const char typeLong[];
+ static const char typeULong[];
+ static const char typeFloat[];
+ static const char typeDouble[];
+
+ // constants
+ static const int tman_width;
+ static const int tman_height;
+ static const int tman_border;
+ static const int tman_basewidth;
+ static const int tman_cheight;
+ static const int tman_bheight;
+ static const int tman_bwidth;
+};
+
+#endif
diff --git a/applications/rview/rviewTypes.hh b/applications/rview/rviewTypes.hh
new file mode 100644
index 0000000..20830f7
--- /dev/null
+++ b/applications/rview/rviewTypes.hh
@@ -0,0 +1,81 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+ * COMMENTS:
+ * This file is created automatically by the rasdl command.
+ * DO NOT EDIT
+ */
+
+
+#ifndef _RVTYPES_HH_
+#define _RVTYPES_HH_
+
+//------------------------------------------------------------
+// Includes
+//------------------------------------------------------------
+
+#if (defined(EARLY_TEMPLATE) && !defined(__EXECUTABLE__))
+#define __EXECUTABLE__
+#define __UNDEF_EXEC_TYPES__
+#endif
+
+#include "rasodmg/ref.hh"
+#include "rasodmg/transaction.hh"
+#include "rasodmg/database.hh"
+#include "rasodmg/set.hh"
+#include "rasodmg/iterator.hh"
+#include "rasodmg/marray.hh"
+#include "raslib/odmgtypes.hh"
+
+#if (defined(EARLY_TEMPLATE) && defined(__UNDEF_EXEC_TYPES__))
+#undef __EXECUTABLE__
+#undef __UNDEF_EXEC_TYPES__
+#endif
+
+/*[2,33]*//* TYPEDEF ------------------------- GreyImage */
+typedef r_Marray<r_Char/*[*:*,*:*]*/> GreyImage;
+
+/*[3,24]*//* TYPEDEF ------------------------- GreySet */
+typedef r_Set<r_Ref<GreyImage> > GreySet;
+
+/*[6,36]*//* TYPEDEF ------------------------- BoolImage */
+typedef r_Marray<r_Boolean/*[*:*,*:*]*/> BoolImage;
+
+/*[7,24]*//* TYPEDEF ------------------------- BoolSet */
+typedef r_Set<r_Ref<BoolImage> > BoolSet;
+
+/*[10,1]*//* STRUCT -------------------------- RGBPixel */
+struct RGBPixel {
+ r_Char red;
+ r_Char green;
+ r_Char blue;
+};
+/*[11,37]*//* TYPEDEF ------------------------- RGBImage */
+typedef r_Marray<RGBPixel/*[*:*,*:*]*/> RGBImage;
+
+/*[12,23]*//* TYPEDEF ------------------------- RGBSet */
+typedef r_Set<r_Ref<RGBImage> > RGBSet;
+
+#endif
+
diff --git a/applications/rview/rviewUtils.cpp b/applications/rview/rviewUtils.cpp
new file mode 100644
index 0000000..762ee10
--- /dev/null
+++ b/applications/rview/rviewUtils.cpp
@@ -0,0 +1,3630 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+* PURPOSE:
+*
+* Central definitions of shared objects and constants, global tool functions.
+*
+* - All menu codes used in the program (MENU_...)
+* - Global tool functions for handling collections, base types, projection
+* strings, X events, ... . See ``Global functions''.
+* - rviewFrame class which must be the base class of all frames used in rView.
+* - rviewFrameMgr class for handling all of rView's frames (dispatching events
+* etc)
+* - rviewMultiline class for displaying several lines of non-editable text.
+* - rviewDialog class which is the base class for all rView's dialog windows.
+* - rviewErrorbox class, derived from rviewDialog.
+* - rviewProgress class, derived from rviewDialog.
+* - rviewResults class for displaying database results and dispatching object
+* viewers. Relies on code provided by rviewMDD for scaling/resampling/endian
+* conversions.
+* - rviewAbout class for displaying information about rView itself.
+* - rviewStringSet class for displaying a set of strings in a scrollable
+* list box.
+*
+* COMMENTS:
+* none
+*/
+
+
+// Was file included via header? Then mask out all non-template code
+#if (!defined(EARLY_TEMPLATE) || !defined(__EXECUTABLE__))
+
+// Standard wxWindows preamble.
+#ifdef __GNUG__
+#pragma implementation
+#endif
+
+
+// changed in wxWindows 2.4.2:
+//#include "wx_prec.h"
+#include <wx/wxprec.h>
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+
+#ifndef WX_PRECOMP
+#include <wx/wx.h>
+#endif
+
+// #include "wb_timer.h" -- PB 2006-jan-01
+
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <iostream.h>
+
+
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#endif
+
+
+#include "raslib/rmdebug.hh"
+#include "raslib/primitivetype.hh"
+#include "raslib/structuretype.hh"
+
+#include "rviewUtils.hh"
+#include "rviewMDD.hh"
+#include "rviewPrefs.hh"
+#include "rviewColMap.hh"
+#include "rviewDModes.hh"
+#include "rviewOSection.hh"
+#include "rviewTypes.hh"
+#include "rviewThumb.hh"
+#include "rviewSound.hh"
+#include "rviewTypeMan.hh"
+#include "labelManager.hh"
+
+
+#ifdef __VISUALC__
+const int rview_window_extra_height = 24;
+const int rview_choice_sub_width = 0;
+#else
+const int rview_window_extra_height = 0;
+const int rview_choice_sub_width = 32;
+#endif
+
+
+
+
+
+
+/*
+ * Global data
+ */
+
+// Base type to string translation tables
+
+#if (MAXIMUM_DIMENSIONS != 4)
+#error "Adapt tables for MAXIMUM DIMENSIONS!"
+#endif
+
+// String names of base types
+char *rviewBaseTypes[] = {
+ "none",
+ "Boolean",
+ "Char",
+ "Octet",
+ "Short",
+ "UShort",
+ "Long",
+ "ULong",
+ "RGBPixel",
+ "Float",
+ "Double"
+};
+
+// String names of objects of baseType x and dimension y (-> rviewBaseType)
+char *rviewTypeNames[][MAXIMUM_DIMENSIONS] = {
+ {"?", "?", "?", "?"},
+ {"BoolString", "BoolImage", "BoolCube", "BoolCube4"},
+ {"GreyString", "GreyImage", "GreyCube", "GreyCube4"},
+ {"OctetString", "OctetImage", "OctetCube", "OctetCube4"},
+ {"ShortString", "ShortImage", "ShortCube", "ShortCube4"},
+ {"UShortString", "UShortImage", "UShortCube", "UShortCube4"},
+ {"LongString", "LongImage", "LongCube", "LongCube4"},
+ {"ULongString", "ULongImage", "ULongCube", "ULongCube4"},
+ {"RGBString", "RGBImage", "RGBCube", "RGBCube4"},
+ {"FloatString", "FloatImage", "FloatCube", "FloatCube4"},
+ {"DoubleString", "DoubleImage" "DoubleCube", "DoubleCube4"}
+};
+
+// The same for sets
+char *rviewSetNames[][MAXIMUM_DIMENSIONS] = {
+ {"?", "?", "?", "?"},
+ {"BoolSet1", "BoolSet", "BoolSet3", "BoolSet4"},
+ {"GreySet1", "GreySet", "GreySet3", "GreySet4"},
+ {"OctetSet1", "OctetSet", "OctetSet3", "OctetSet4"},
+ {"ShortSet1", "ShortSet", "ShortSet3", "ShortSet4"},
+ {"UShortSet1", "UShortSet", "UShortSet3", "UShortSet4"},
+ {"LongSet1", "LongSet", "LongSet3", "LongSet4"},
+ {"ULongSet1", "ULongSet", "ULongSet3", "ULongSet4"},
+ {"RGBSet1", "RGBSet", "RGBSet3", "RGBSet4"},
+ {"FloatSet1", "FloatSet", "FloatSet3", "FloatSet4"},
+ {"DoubleSet1", "DoubleSet", "DoubleSet3", "DoubleSet4"}
+};
+
+
+
+unsigned char lowerCaseTable[256];
+
+
+
+// Various support classes
+rviewFrameMgr *frameManager = NULL;
+
+labelManager *lman = NULL;
+
+
+
+
+
+
+/*
+ * GLOBAL functions
+ */
+
+// Frees all memory allocated by a collection descriptor.
+void rviewDeleteCollection(collection_desc *coll)
+{
+ if (coll != NULL)
+ {
+ int i;
+ collection_desc *ptr = coll;
+
+ if (coll->collName != NULL) delete [] coll->collName;
+ if (coll->collType != NULL) delete [] coll->collType;
+ if (coll->collInfo != NULL) delete [] coll->collInfo;
+
+ for (i=0; i<coll->number; i++)
+ {
+ if (coll->mddObjs != NULL)
+ {
+ if (!coll->mddObjs[i].mdd.is_null())
+ {
+ coll->mddObjs[i].mdd.destroy();
+ }
+ }
+ else if (coll->strObjs != NULL)
+ {
+ if (coll->strObjs[i] != NULL)
+ {
+ delete [] coll->strObjs[i];
+ }
+ }
+ }
+ if (coll->mddObjs != NULL) delete [] coll->mddObjs;
+ if (coll->strObjs != NULL) delete [] coll->strObjs;
+
+ delete coll;
+ }
+}
+
+
+
+/*
+ * Support function for rviewParseProjection
+ */
+static const char *rviewParseIndexMapping(const char *s, int idx, int dims, r_Point *mapIndex)
+{
+ const char *b, *d;
+ r_Range value;
+
+ b = s+1;
+ if (mapIndex == NULL)
+ {
+ cerr << "Mode doesn't support reordering of dimensions." << endl;
+ }
+
+ value = (r_Range)strtol(b, (char**)&d, 0);
+ if (b == d) return NULL;
+
+ if ((value < 0) || (value >= (r_Range)dims))
+ {
+ cerr << "Bad dimension index " << value << endl;
+ value = (r_Range)idx;
+ }
+ if (mapIndex != NULL) (*mapIndex)[idx] = value;
+
+ while ((*d == ' ') || (*d == '\t')) d++;
+ if (*d == ']') return d+1;
+ return NULL;
+}
+
+
+/*
+ * Translate a projection string (now RasDaMan style, i.e. things
+ * like *:* are also allowed) into two diagonal r_Points. Returns
+ * number of dimension of projection string for success, 0 for an error.
+ */
+
+int rviewParseProjection(const r_Minterval &interv, r_Point &pt1, r_Point &pt2, const char *projString, unsigned int *freeDims, r_Point *mapIndex)
+{
+ int dims, i;
+ const char *b, *d;
+ r_Range value;
+
+ if (freeDims != NULL) *freeDims = 0;
+ dims = interv.dimension();
+ pt1 = r_Point(dims); pt2 = r_Point(dims);
+
+ b = projString; i = 0;
+ while (*b != '\0')
+ {
+ while ((*b == ' ') || (*b == '\t')) b++;
+ if (*b == ',') b++;
+ while ((*b == ' ') || (*b == '\t')) b++;
+ if (*b == '\0') break;
+ if (i >= dims) return 0;
+ if (*b == '*')
+ {
+ pt1[i] = interv[i].low(); pt2[i] = interv[i].high(); b++;
+ }
+ else
+ {
+ value = (r_Range)strtol(b, (char**)&d, 0);
+ // no valid number found?
+ if (b == d) return 0;
+ b = d;
+ if ((value < interv[i].low()) || (value > interv[i].high())) return 0;
+ pt1[i] = value; pt2[i] = value;
+ }
+ if (mapIndex != NULL) (*mapIndex)[i] = i;
+ while ((*b == ' ') || (*b == '\t')) b++;
+ if (*b == '[') // Explicit index-mapping?
+ {
+ if ((b = rviewParseIndexMapping(b, i, dims, mapIndex)) == NULL) return 0;
+ }
+ else if (*b == ':') // the upper boundaries follow after a colon.
+ {
+ if (freeDims != NULL) *freeDims |= (1<<i);
+ b++;
+ if (*b == '\0') break;
+ if (*b == '*')
+ {
+ value = interv[i].high(); b++;
+ }
+ else
+ {
+ value = (r_Range)strtol(b, (char**)&d, 0);
+ if (b == d) return 0;
+ b = d;
+ if ((value < interv[i].low()) || (value > interv[i].high())) return 0;
+ }
+ pt2[i] = value;
+ while ((*b == ' ') || (*b == '\t')) b++;
+ if (*b == '[')
+ {
+ if ((b = rviewParseIndexMapping(b, i, dims, mapIndex)) == NULL) return 0;
+ }
+ }
+ i++;
+ }
+ return i;
+}
+
+
+
+
+
+/*
+ * Determine the base type of an MDD object, returning a simple identifier.
+ */
+rviewBaseType rviewGetBasetype(r_Object *obj)
+{
+ rviewBaseType baseType;
+ const r_Type *bt;
+
+ baseType = rbt_none;
+
+ // New type schema...
+ bt = obj->get_type_schema();
+ if (bt->type_id() == r_Type::MARRAYTYPE)
+ bt = ((r_GMarray*)obj)->get_base_type_schema();
+ else if (bt->type_id() == r_Type::COLLECTIONTYPE)
+ bt = ((r_Collection<r_Ref_Any>*)obj)->get_element_type_schema();
+
+ if (bt != NULL)
+ {
+ if (((r_Type*)bt)->isStructType())
+ {
+ if (((r_Base_Type*)bt)->size() == 3)
+ baseType = rbt_rgb;
+ else
+ baseType = rbt_none;
+ }
+ else
+ {
+ r_Primitive_Type *pt = (r_Primitive_Type *)bt;
+
+ switch (pt->type_id())
+ {
+ case r_Primitive_Type::BOOL: baseType = rbt_bool; break;
+ case r_Primitive_Type::CHAR: baseType = rbt_char; break;
+ case r_Primitive_Type::OCTET: baseType = rbt_uchar; break;
+ case r_Primitive_Type::SHORT: baseType = rbt_short; break;
+ case r_Primitive_Type::USHORT: baseType = rbt_ushort; break;
+ case r_Primitive_Type::LONG: baseType = rbt_long; break;
+ case r_Primitive_Type::ULONG: baseType = rbt_ulong; break;
+ case r_Primitive_Type::FLOAT: baseType = rbt_float; break;
+ case r_Primitive_Type::DOUBLE: baseType = rbt_double; break;
+ default: baseType = rbt_none; break;
+ }
+ }
+ }
+ else
+ {
+ char *name = (char*)(obj->get_type_name());
+ if (name != NULL)
+ {
+ if (strcmp(name, "GreyImage") == 0) baseType = rbt_char;
+ else if (strcmp(name, "BoolImage") == 0) baseType = rbt_bool;
+ else if (strcmp(name, "RGBImage") == 0) baseType = rbt_rgb;
+ }
+ }
+ return baseType;
+}
+
+
+
+/*
+ * rviewPrintTypedCell() prints the contents of a cell with a given base type into the buffer,
+ * returning the number of characters written.
+ */
+
+// For internal use only
+static void printPrimitiveCell(r_Primitive_Type *primType, char **buff, char *data, int numberBase)
+{
+ char *b = *buff;
+
+ switch (numberBase)
+ {
+ case 8:
+ switch (primType->type_id())
+ {
+ case r_Primitive_Type::BOOL:
+ b += sprintf(b, "%3o", *((r_Boolean*)data)); break;
+ case r_Primitive_Type::CHAR:
+ b += sprintf(b, "%3o", *((r_Char*)data)); break;
+ case r_Primitive_Type::OCTET:
+ b += sprintf(b, "%3o", *((r_Octet*)data)); break;
+ case r_Primitive_Type::SHORT:
+ b += sprintf(b, "%6o", *((r_Short*)data)); break;
+ case r_Primitive_Type::USHORT:
+ b += sprintf(b, "%6o", *((r_UShort*)data)); break;
+ case r_Primitive_Type::LONG:
+ b += sprintf(b, "%11lo", *((r_Long*)data)); break;
+ case r_Primitive_Type::ULONG:
+ b += sprintf(b, "%11lo", *((r_ULong*)data)); break;
+ case r_Primitive_Type::FLOAT:
+ b += sprintf(b, "%011o", *((r_Long*)data)); break;
+ case r_Primitive_Type::DOUBLE:
+ b += sprintf(b, "%011o:%011o", ((r_Long*)data)[0], ((r_Long*)data)[1]); break;
+ default:
+ break;
+ }
+ break;
+ case 16:
+ switch (primType->type_id())
+ {
+ case r_Primitive_Type::BOOL:
+ b += sprintf(b, "%02x", *((r_Boolean*)data)); break;
+ case r_Primitive_Type::CHAR:
+ b += sprintf(b, "%02x", *((r_Char*)data)); break;
+ case r_Primitive_Type::OCTET:
+ b += sprintf(b, "%02x", *((r_Octet*)data)); break;
+ case r_Primitive_Type::SHORT:
+ b += sprintf(b, "%04x", *((r_Short*)data)); break;
+ case r_Primitive_Type::USHORT:
+ b += sprintf(b, "%04x", *((r_UShort*)data)); break;
+ case r_Primitive_Type::LONG:
+ b += sprintf(b, "%08x", *((r_Long*)data)); break;
+ case r_Primitive_Type::ULONG:
+ b += sprintf(b, "%08x", *((r_ULong*)data)); break;
+ case r_Primitive_Type::FLOAT:
+ b += sprintf(b, "%08x", *((r_Long*)data)); break;
+ case r_Primitive_Type::DOUBLE:
+ b += sprintf(b, "%08x:%08x", ((r_Long*)data)[0], ((r_Long*)data)[1]); break;
+ default:
+ break;
+ }
+ break;
+ default:
+ switch (primType->type_id())
+ {
+ case r_Primitive_Type::BOOL:
+ b += sprintf(b, "%3d", *((r_Boolean*)data)); break;
+ case r_Primitive_Type::CHAR:
+ b += sprintf(b, "%3d", *((r_Char*)data)); break;
+ case r_Primitive_Type::OCTET:
+ b += sprintf(b, "%3d", *((r_Octet*)data)); break;
+ case r_Primitive_Type::SHORT:
+ b += sprintf(b, "%5d", *((r_Short*)data)); break;
+ case r_Primitive_Type::USHORT:
+ b += sprintf(b, "%5d", *((r_UShort*)data)); break;
+ case r_Primitive_Type::LONG:
+ b += sprintf(b, "%10ld", *((r_Long*)data)); break;
+ case r_Primitive_Type::ULONG:
+ b += sprintf(b, "%10ld", *((r_ULong*)data)); break;
+ case r_Primitive_Type::FLOAT:
+ b += sprintf(b, "%g", *((r_Float*)data)); break;
+ case r_Primitive_Type::DOUBLE:
+ b += sprintf(b, "%g", *((r_Double*)data)); break;
+ default:
+ break;
+ }
+ break;
+ }
+ *buff = b;
+}
+
+// For internal use only
+void printStructuredCell(r_Structure_Type *structType, char **buff, char *data, int numberBase)
+{
+ r_Type *newType;
+ unsigned long off;
+ char *b;
+
+ b = *buff;
+ *b++ = '{';
+ r_Structure_Type::attribute_iterator iter(structType->defines_attribute_begin());
+ while (iter != structType->defines_attribute_end())
+ {
+ newType = (*iter).type_of().clone();
+ off = (*iter).offset();
+
+ if (newType->isStructType())
+ {
+ r_Structure_Type *newStructType = (r_Structure_Type*)newType;
+ printStructuredCell(newStructType, &b, data + off, numberBase);
+ }
+ else
+ {
+ r_Primitive_Type *newPrimType = (r_Primitive_Type*)newType;
+ printPrimitiveCell(newPrimType, &b, data + off, numberBase);
+ }
+ delete newType;
+ *b++ = ',';
+ iter++;
+ }
+ b[-1] = '}'; *b = '\0';
+ *buff = b;
+}
+
+int rviewPrintTypedCell(const r_Type *baseType, char *buffer, char *data, int numberBase)
+{
+ char *b = buffer;
+
+ if (((r_Type*)baseType)->isStructType())
+ {
+ r_Structure_Type *structType = (r_Structure_Type*)baseType;
+ printStructuredCell(structType, &b, data, numberBase);
+ }
+ else
+ {
+ r_Primitive_Type *primType = (r_Primitive_Type*)baseType;
+ printPrimitiveCell(primType, &b, data, numberBase);
+ }
+ return (int)(b - buffer);
+}
+
+
+
+
+/*
+ * Quicksort a char *[]
+ */
+
+#define QUICKSORT_STRING_SWAP(x,y) h=array[x]; array[x]=array[y]; array[y]=h;
+
+void rviewQuicksortStrings(char *array[], int from, int to)
+{
+ while (from < to)
+ {
+ int i, j;
+ char *h;
+
+ j = (from+to)/2;
+ QUICKSORT_STRING_SWAP(from, j); j=from;
+ for (i=from+1; i<=to; i++)
+ {
+ if (strcmp(array[i], array[from]) < 0)
+ {
+ j++;
+ QUICKSORT_STRING_SWAP(i, j);
+ }
+ }
+ QUICKSORT_STRING_SWAP(from, j);
+
+ if ((j-from) < (to-j))
+ {
+ rviewQuicksortStrings(array, from, j-1);
+ from = j+1;
+ }
+ else
+ {
+ rviewQuicksortStrings(array, j+1, to);
+ to = j-1;
+ }
+ }
+}
+
+
+
+/*
+ * Init character lookup tables (e.g. lower case table)
+ */
+void rviewInitCharacterTables(void)
+{
+ int i;
+
+ for (i=0; i<256; i++) lowerCaseTable[i] = tolower(i);
+}
+
+
+
+#define LOOKUP_KEYWORD_CORE \
+ while (count != 0) \
+ { \
+ b = (const unsigned char*)(kti[pos].keyword); \
+ d = (const unsigned char*)key; \
+ while (TRANSLATE_CHARACTER(b) == TRANSLATE_CHARACTER(d)) \
+ { \
+ if (*b == 0) break; b++; d++; \
+ } \
+ if ((*b == 0) && (*d == 0)) return kti[pos].ident; \
+ if (TRANSLATE_CHARACTER(b) >= TRANSLATE_CHARACTER(d)) \
+ { \
+ pos -= step; if (pos < 0) pos = 0; \
+ } \
+ else \
+ { \
+ pos += step; if (pos >= tabsize) pos = tabsize - 1; \
+ } \
+ step = (step+1) >> 1; count >>= 1; \
+ }
+
+/*
+ * Lookup a keyword in a SORTED keyword_to_ident table. Case sensitivity
+ * is optional but has to match the sorting order of the table, of course.
+ */
+int rviewLookupKeyword(const char *key, const keyword_to_ident_c *kti, int tabsize, bool caseSensitive)
+{
+ int pos, step, count;
+ const unsigned char *b, *d;
+
+ count = tabsize;
+ pos = (tabsize + 1) >> 1; if (pos >= tabsize) pos = tabsize - 1;
+ step = (pos + 1) >> 1;
+ if (caseSensitive)
+ {
+#define TRANSLATE_CHARACTER(x) (*x)
+ LOOKUP_KEYWORD_CORE;
+#undef TRANSLATE_CHARACTER
+ }
+ else
+ {
+#define TRANSLATE_CHARACTER(x) lowerCaseTable[(*x)]
+ LOOKUP_KEYWORD_CORE;
+#undef TRANSLATE_CHARACTER
+ }
+ return -1;
+}
+
+
+
+/* Helper function making sure min/max of the init structure is used by the
+ colourspace mapper */
+
+static void rviewEnsureCspaceRange(colourspaceMapper *csmap, const colourspace_params *cp)
+{
+ // make sure the min/max values are taken from the init structure as well
+ if (cp != NULL)
+ {
+ // assume it's initialized if either values differs from 0
+ if ((cp->minVal != 0.0) || (cp->maxVal != 0.0))
+ {
+ colourspace_params par;
+ csmap->getParameters(&par);
+ par.minVal = cp->minVal;
+ par.maxVal = cp->maxVal;
+ // do not do auto-update, otherwise we're stuck in an infinite loop
+ csmap->colourspaceChanged(&par, FALSE);
+ //cout << "MIN " << par.minVal << ", MAX " << par.maxVal << endl;
+ }
+ }
+}
+
+
+/*
+ * Check whether colourspace mapping is possible for the given
+ * base type and return 1 if so. *csmap must be a pointer to the
+ * colourspaceMapper to use or NULL if there isn't one yet in
+ * which case a new one will have been created on returning 1.
+ * If cmap == NULL the function just returns 0 or 1. If the int*
+ * arguments are not NULL they're set up correctly on exit too.
+ */
+int rviewCheckInitCspace(rviewBaseType baseType, colourspaceMapper **csmap, r_Ref<r_GMarray> &mddObj, bool fullRange, r_Minterval *domain, int w, int *newPitch, int *newDepth, int *newPad, int *virtualPitch, const colourspace_params *cp)
+{
+ colourspace_params par;
+
+ switch (baseType)
+ {
+ case rbt_char:
+ case rbt_uchar:
+ case rbt_short:
+ case rbt_ushort:
+ if (csmap == NULL) return 1;
+ if (*csmap == NULL)
+ {
+ memcpy(&par, (cp == NULL) ? &(prefs->csp) : cp, sizeof(colourspace_params));
+ *csmap = new colourspaceMapper(mddObj, baseType, &par, fullRange, domain);
+ }
+ else
+ (*csmap)->bindMapper(mddObj, baseType, fullRange, domain, cp);
+
+ rviewEnsureCspaceRange(*csmap, cp);
+
+ // always call this and let the mapper sort out whether it has to update
+ (*csmap)->buildCSTab15();
+ if (newPitch == NULL) return 1;
+ if (*newPad < 32) *newPad = 32;
+ *newDepth = 15;
+ switch (*newPad)
+ {
+ case 32: *newPitch = (w*2 + 3) & ~3; break;
+ case 64: *newPitch = (w*2 + 7) & ~7; break;
+ case 128: *newPitch = (w*2 + 15) & ~15; break;
+ case 256: *newPitch = (w*2 + 31) & ~31; break;
+ default:
+ cerr << "Bad pad " << *newPad << endl;
+ return 0;
+ }
+ if (virtualPitch != NULL) *virtualPitch = *newPitch;
+ return 1;
+ break;
+ case rbt_long:
+ case rbt_ulong: // using 24bpp only makes sense for long
+ case rbt_float:
+ case rbt_double: // ... or larger types
+ {
+ int baseWidth;
+
+ baseWidth = 4*w;
+
+ if (csmap == NULL) return 1;
+ if (*csmap == NULL)
+ {
+ memcpy(&par, (cp == NULL) ? &(prefs->csp) : cp, sizeof(colourspace_params));
+ *csmap = new colourspaceMapper(mddObj, baseType, &par, fullRange, domain);
+ }
+ else
+ (*csmap)->bindMapper(mddObj, baseType, fullRange, domain, cp);
+
+ rviewEnsureCspaceRange(*csmap, cp);
+
+ (*csmap)->buildCSTab24();
+ if (newPitch == NULL) return 1;
+ if (*newPad < 32) *newPad = 32;
+ *newDepth = 32;
+ switch (*newPad)
+ {
+ case 32: *newPitch = (baseWidth + 3) & ~3; break;
+ case 64: *newPitch = (baseWidth + 7) & ~7; break;
+ case 128: *newPitch = (baseWidth + 15) & ~15; break;
+ case 256: *newPitch = (baseWidth + 31) & ~31; break;
+ default: cerr << "Bad pad " << *newPad << endl;
+ return 0;
+ }
+ if (virtualPitch != NULL)
+ *virtualPitch = (baseType == rbt_double) ? 2*(*newPitch) : (*newPitch);
+ return 1;
+ }
+ break;
+ default: break;
+ }
+ return 0;
+}
+
+
+
+/*
+ * Smart number conversion functions. They also understand the 0x
+ * prefix and convert the number correctly.
+ */
+
+long asctol(const char *str)
+{
+ return stringtol(str, NULL);
+}
+
+int asctoi(const char *str)
+{
+ return (int)stringtol(str, NULL);
+}
+
+double asctof(const char *str)
+{
+ return stringtof(str, NULL);
+}
+
+long stringtol(const char *str, char **endptr)
+{
+ const char *b = str;
+ long value;
+
+ while (isspace((unsigned int)(*b))) b++;
+ if ((b[0] == '0') && ((b[1] == 'x') || (b[1] == 'X')))
+ {
+ b += 2;
+ value = strtol(b, endptr, 16);
+ }
+ else
+ {
+ value = strtol(b, endptr, 10);
+ }
+ if ((endptr != NULL) && ((const char*)(*endptr) == b)) *endptr = (char*)str;
+ return value;
+}
+
+double stringtof(const char *str, char **endptr)
+{
+ const char *b = str;
+ double value;
+
+ while (isspace((unsigned int)(*b))) b++;
+ if ((b[0] == '0') && ((b[1] == 'x') || (b[1] == 'X')))
+ {
+ b += 2;
+ value = (double)strtol(b, endptr, 16);
+ }
+ else
+ {
+ value = strtod(b, endptr);
+ }
+ if ((endptr != NULL) && ((const char*)(*endptr) == b)) *endptr = (char*)str;
+ return value;
+}
+
+
+
+
+
+/*
+ * Dynamic string class for easy management of dynamically allocated string storage
+ */
+
+const char DynamicString::emptyString[] = "";
+
+
+DynamicString::DynamicString(void)
+{
+ myString = NULL;
+}
+
+DynamicString::DynamicString(const DynamicString &ms)
+{
+ if (ms.myString == NULL)
+ {
+ myString = NULL;
+ }
+ else
+ {
+ myString = new char[strlen(ms.myString) + 1];
+ strcpy(myString, ms.myString);
+ }
+}
+
+
+DynamicString::DynamicString(const char *str)
+{
+ if (str == NULL)
+ {
+ myString = NULL;
+ }
+ else
+ {
+ myString = new char[strlen(str) + 1];
+ strcpy(myString, str);
+ }
+}
+
+
+DynamicString::~DynamicString(void)
+{
+ if (myString != NULL) delete [] myString;
+}
+
+
+DynamicString &DynamicString::first(const char *str, unsigned int num)
+{
+ if (myString != NULL)
+ {
+ delete [] myString; myString = NULL;
+ }
+ if (num != 0)
+ {
+ unsigned int len = strlen(str);
+ if (len > num) len = num;
+ myString = new char[len + 1];
+ strncpy(myString, str, len);
+ myString[len] = '\0';
+ }
+ return *this;
+}
+
+
+DynamicString &DynamicString::operator=(const DynamicString &ms)
+{
+ if (myString != NULL)
+ {
+ delete [] myString; myString = NULL;
+ }
+ if (ms.myString != NULL)
+ {
+ myString = new char[strlen(ms.myString) + 1];
+ strcpy(myString, ms.myString);
+ }
+ return *this;
+}
+
+
+DynamicString &DynamicString::operator=(const char *str)
+{
+ if (myString != NULL)
+ {
+ delete [] myString; myString = NULL;
+ }
+ if (str != NULL)
+ {
+ myString = new char[strlen(str) + 1];
+ strcpy(myString, str);
+ }
+ return *this;
+}
+
+
+const char *DynamicString::ptr(void) const
+{
+ if (myString == NULL) return emptyString;
+ return myString;
+}
+
+DynamicString::operator const char*(void) const
+{
+ return ptr();
+}
+
+
+bool DynamicString::operator==(const DynamicString &str) const
+{
+ return (strcmp(ptr(), str.ptr()) == 0);
+}
+
+
+bool DynamicString::operator==(const char *str) const
+{
+ return (strcmp(ptr(), str) == 0);
+}
+
+
+
+
+
+
+/*
+ * Generic handler function for events like button- and key-presses.
+ * It passes the event to the frameManager which then broadcasts
+ * it to all the frames it knows. If a frame recognizes obj as one
+ * of its children it claims the event, thus aborting the broadcast.
+ */
+
+void rviewEventHandler(wxObject &obj, wxEvent &evt)
+{
+ if (frameManager != NULL)
+ frameManager->broadcastEvent(obj, evt);
+ //cout << endl;
+}
+
+
+
+
+
+
+/*
+ * rviewFrame member functions.
+ * This is an abstract class that is only used for deriving other
+ * (window/frame) classes from it.
+ */
+
+rviewFrame::rviewFrame(wxFrame *parent, char *title, int x, int y, int w, int h) : wxFrame(parent, title, x, y, w, h)
+{
+ RMDBGONCE( 3, RMDebug::module_applications, "rviewFrame", "rviewFrame( " << this << ", ...)" );
+
+ if (frameManager != NULL)
+ frameManager->registerFrame(this);
+
+ parentFrame = NULL;
+ // Init the size with illegal values to make sure the first OnSize gets through
+ frameWidth = -1; frameHeight = -1;
+ // All the frame's children should be destroyed when the frame is destroyed.
+ frames = new rviewFrameMgr(TRUE);
+}
+
+
+rviewFrame::~rviewFrame(void)
+{
+ RMDBGONCE( 3, RMDebug::module_applications, "rviewFrame", "~rviewFrame() " << this );
+
+ delete frames;
+
+ if (frameManager != NULL)
+ frameManager->deregisterFrame(this);
+
+ if (parentFrame != NULL)
+ {
+ parentFrame->deregisterChild(this);
+ }
+}
+
+
+const char *rviewFrame::getFrameName(void) const
+{
+ return "rviewFrame";
+}
+
+rviewFrameType rviewFrame::getFrameType(void) const
+{
+ return rviewFrameTypeGeneric;
+}
+
+
+void rviewFrame::setParent(rviewFrame *parent)
+{
+ parentFrame = parent;
+}
+
+
+void rviewFrame::registerChild(rviewFrame *child)
+{
+ child->setParent(this);
+ frames->registerFrame(child);
+}
+
+
+void rviewFrame::deregisterChild(rviewFrame *child)
+{
+ frames->deregisterFrame(child);
+ child->setParent(NULL);
+}
+
+
+// Called by the global frame manager when the application is about to die.
+int rviewFrame::requestQuit(int level)
+{
+ // Default action on a hard quit: die
+ if (level != 0)
+ {
+ // Do not delete the children, that would upset the frame manager's loop.
+ frames->setDeleteMode(FALSE); setParent(NULL);
+ //delete this;
+ Close(TRUE);
+ }
+ return 0;
+}
+
+
+
+// Called on a user event
+int rviewFrame::userEvent(const user_event &ue)
+{
+ // Default action: nothing. Overload function in derived class if you're
+ // interested in user messages.
+ return 0;
+}
+
+
+// Called by the rviewFrameMgr object to determine which frame receives an event
+int rviewFrame::checkobj(wxObject &obj)
+{
+ return checkobj_rec((wxWindow*)this, obj);
+}
+
+
+// Used internally by rviewFrame::checkobj(); don't access directly. Checks
+// recursively all the children of a given frame against obj.
+int rviewFrame::checkobj_rec(wxWindow *whence, wxObject &obj)
+{
+ if (&obj == (wxObject*)whence) return 1;
+ else
+ {
+ int i, n;
+ wxList *list;
+
+ list = whence->GetChildren();
+ n = list->Number();
+ for (i=0; i<n; i++)
+ {
+ if (checkobj_rec((wxWindow*)(list->Nth(i)->Data()), obj) != 0) return 1;
+ }
+ }
+ return 0;
+}
+
+
+
+// Virtual function. If a derived frame class should refuse to die in some
+// circumstances, it must overload his function.
+bool rviewFrame::OnClose(void)
+{
+ return TRUE;
+}
+
+
+void rviewFrame::childMouseEvent(wxWindow *child, wxMouseEvent &mevt)
+{
+ // by default this is ignored.
+}
+
+
+
+
+
+
+/*
+ * rviewFrameMgr member functions
+ */
+
+rviewFrameMgr::rviewFrameMgr(void)
+{
+ listLength = 0; deleteChildren = FALSE;
+ frameList = NULL; tailList = NULL;
+}
+
+
+rviewFrameMgr::rviewFrameMgr(bool delChild)
+{
+ listLength = 0; deleteChildren = delChild;
+ frameList = NULL; tailList = NULL;
+}
+
+
+rviewFrameMgr::~rviewFrameMgr(void)
+{
+ int i;
+ frame_list *list, *last;
+
+ // Deletes all the frames and their children
+ // Unlink all frames first! Otherwise there'll be trouble because the Frame Manager
+ // will loop over the frames and delete them; but if the frames have a valid parent
+ // they will deregister there which will screw up the Frame Manager's frame list
+ // _during the loop_ and hence crash.
+ list = frameList;
+ for (i=0; i<listLength; i++)
+ {
+ last = list; list = list->next;
+ // If it's the global frame manager it shouldn't delete the children, that's
+ // wxWindows' job. If it's a manager local to a frame it should delete all
+ // that frame's children, however.
+ if (deleteChildren)
+ {
+ last->frame->setParent(NULL);
+ //delete last->frame;
+ last->frame->Close(TRUE);
+ }
+ delete last;
+ }
+}
+
+
+void rviewFrameMgr::registerFrame(rviewFrame *client)
+{
+ frame_list *entry;
+
+ //cout << "frameManager::registerFrame(" << (void*)client << ")" << endl;
+ if ((entry = new frame_list) == NULL)
+ {
+ //cerr << "frameManager: Unable to claim memory!\n" << endl;
+ return;
+ }
+
+ entry->frame = client; entry->next = NULL;
+
+ if (frameList == NULL)
+ {
+ frameList = entry; tailList = entry;
+ }
+ else
+ {
+ tailList->next = entry;
+ tailList = entry;
+ }
+ listLength++;
+ //cout << "Frame manager: Added frame to list. New length = " << listLength << endl;
+ //cout << "(anchor = " << (void*)frameList << ", tail = " << (void*)tailList << ")" << endl;
+}
+
+
+void rviewFrameMgr::deregisterFrame(rviewFrame *client)
+{
+ int i;
+ frame_list *list, *last;
+
+ //cout << "frameManager::deregisterFrame(" << (void*)client << ")" << endl;
+ list = frameList; last = NULL;
+ for (i=0; i<listLength; i++)
+ {
+ if (list->frame == client)
+ {
+ list = list->next;
+ if (last == NULL)
+ {
+ delete frameList; frameList = list; last = list;
+ }
+ else
+ {
+ delete last->next; last->next = list;
+ }
+ listLength--;
+ if (last == NULL) tailList = NULL;
+ else
+ {
+ while (last->next != NULL) last = last->next;
+ tailList = last;
+ }
+ //cout << "Frame manager: Removed frame from list. New length = " << listLength << endl;
+ //cout << "(anchor = " << (void*)frameList << ", tail = " << (void*)tailList << ")" << endl;
+ return;
+ }
+ last = list; list = list->next;
+ }
+}
+
+
+
+int rviewFrameMgr::numberOfFrames(void) const
+{
+ return listLength;
+}
+
+
+
+void rviewFrameMgr::setDeleteMode(bool delChild)
+{
+ deleteChildren = delChild;
+}
+
+
+// Issues re-label requests to all frames.
+void rviewFrameMgr::labelAll(void)
+{
+ int i;
+ frame_list *list;
+
+ //cout << "frameManager::labelAll()" << endl;
+ list = frameList;
+ for (i=0; i<listLength; i++)
+ {
+ list->frame->label();
+ list = list->next;
+ }
+}
+
+
+
+/*
+ * Broadcasts the event to all frames until one claims the event by returning
+ * a value != 0. Warning: this function has to be re-entrant!
+ */
+
+void rviewFrameMgr::broadcastEvent(wxObject &obj, wxEvent &evt)
+{
+ int i;
+ frame_list *list;
+
+ // Note: the broadcast has to go in two steps, first determining which frame
+ // knows the object, then terminating the loop and calling the object as the
+ // last action. The reason is that this function is re-entrant and would
+ // crash badly if the frame list changed during the loop.
+ //cout << "frameManager::broadcastEvent()" << endl;
+ list = frameList;
+ for (i=0; i<listLength; i++)
+ {
+ //cout << "Broadcast to " << (void*)(list->frame) << endl;
+ if (list->frame->checkobj(obj) != 0)
+ {
+ //cout << "Frame manager: object known by frame " << (void*)list->frame << endl;
+ break;
+ }
+ list = list->next;
+ }
+ //cout << "Frame manager: broadcast " << ((list == NULL) ? "failed" : "successful") << endl;
+
+ // Now call the frame.
+ if (list != NULL) {list->frame->process(obj, evt);}
+ // Uncomment this if there's any doubt it's re-entrant
+ //cout << "frameManager::broadcastEvent done" << endl;
+}
+
+
+
+/*
+ * Broadcast a quit-message to all frames but the first one (the main frame). There
+ * are currently two levels, 0 means the frames can yet refuse to die by returning a
+ * value != 0, every other level doesn't give them this option. Returns 0 for failure.
+ * This must only be called for the _global_ frame manager!
+ */
+
+int rviewFrameMgr::broadcastQuit(int level)
+{
+ int i, status;
+ frame_list *list;
+
+ list = frameList->next; status = 1;
+ for (i=1; i<listLength; i++)
+ {
+ //if (level > 0) cout << "delete " << (void*)list << endl;
+ if (list->frame->requestQuit(level) != 0) status = 0;
+ list = list->next;
+ }
+ if (level == 0) return status;
+
+ //cout << "Hard quit OK" << endl;
+ return 1;
+}
+
+
+
+/*
+ * Broadcast a user event to all frames.
+ */
+
+int rviewFrameMgr::broadcastUserEvent(const user_event &ue)
+{
+ int i, status;
+ frame_list *list;
+
+ list = frameList; status = 0;
+ for (i=0; i<listLength; i++)
+ {
+ //cout << "broadcast to " << (void*)(list->frame) << endl;
+ status += list->frame->userEvent(ue);
+ list = list->next;
+ }
+ return status; // number of clients that recognised the event.
+}
+
+
+
+
+
+/*
+ * rviewMultiline member functions
+ */
+
+const int rviewMultiline::multiline_ppc10 = 63;
+
+void rviewMultiline::setupVariables(wxPanel *Panel, int X, int Y, int H, int Lines)
+{
+ int i;
+
+ parent = Panel; lines = Lines;
+ if ((msg = new wxMessage *[lines]) == NULL)
+ {
+ cerr << "rviewMultiline::setupVariables(): " << lman->lookup("errorMemory") << endl;
+ return;
+ }
+ for (i=0; i<lines; i++) msg[i] = NULL;
+
+ x = X; y = Y; lHeight = H;
+}
+
+
+rviewMultiline::rviewMultiline(wxPanel *Panel, int X, int Y, int H, int Lines)
+{
+ setupVariables(Panel, X, Y, H, Lines);
+}
+
+
+rviewMultiline::rviewMultiline(wxPanel *Panel, const char *Message, int X, int Y, int W, int H, int Lines)
+{
+ setupVariables(Panel, X, Y, H, Lines);
+
+ rebuild(Message, W);
+}
+
+
+rviewMultiline::~rviewMultiline(void)
+{
+ // The wxMessage items have been created as children of the panel and will
+ // be deleted by the panel later on. So just delete the array.
+ delete [] msg;
+}
+
+
+void rviewMultiline::rebuild(const char *Message, int W)
+{
+ int length, i, cpl, pos;
+ char *buffer, *b, *base;
+
+ if (msg == NULL) return;
+
+ //cout << "rviewMultiline::rebuild()" << endl;
+
+ cpl = (10*W) / multiline_ppc10;
+
+ if ((buffer = new char[cpl + 1]) == NULL)
+ {
+ cerr << "rviewMultiline::rebuild(): " << lman->lookup("errorMemory") << endl;
+ return;
+ }
+
+ length = strlen(Message); base = (char*)Message;
+
+ for (i=0, pos=y; (length > 0) && (i<lines); i++, pos+=lHeight)
+ {
+ if (length > cpl)
+ {
+ b = base + cpl;
+ while ((*b > 32) && (b > base)) b--;
+ if (b <= base) b = base + cpl; else b++;
+ }
+ else
+ {
+ b = base + length;
+ }
+ memcpy(buffer, base, (int)(b - base)); buffer[(int)(b - base)] = '\0';
+ //cout << buffer << endl;
+ if (msg[i] == NULL)
+ {
+ msg[i] = new wxMessage(parent, buffer, x, pos, W, lHeight, 0, "message");
+ }
+ else
+ {
+ msg[i]->SetSize(x, pos, W, lHeight, 0);
+ msg[i]->SetLabel(buffer);
+ }
+ length -= (int)(b - base); base = b;
+ }
+ while (i<lines)
+ {
+ if (msg[i] != NULL) {delete msg[i]; msg[i] = NULL;}
+ i++;
+ }
+ delete [] buffer;
+}
+
+
+
+int rviewMultiline::getMessageHeight(void) const
+{
+ int i;
+
+ for (i=0; i<lines; i++) if (msg[i] == NULL) break;
+ return(i*lHeight);
+}
+
+
+
+/*
+ * More convenient interface to standard widgets
+ */
+
+rviewText::rviewText(wxPanel *parent, const char *value, char *label, int x, int y, int w, int h) : wxText(parent, (wxFunction)rviewEventHandler, label, (char*)value, x, y, w, h, wxTE_PROCESS_ENTER)
+{
+}
+
+rviewText::rviewText(long style, wxPanel *parent, const char *value, char *label, int x, int y, int w, int h) : wxText(parent, (wxFunction)rviewEventHandler, label, (char*)value, x, y, w, h, style)
+{
+}
+
+rviewText::rviewText(wxPanel *parent, const DynamicString &value, char *label, int x, int y, int w, int h) : wxText(parent, (wxFunction)rviewEventHandler, label, NULL, x, y, w, h, wxTE_PROCESS_ENTER)
+{
+ wxText::SetValue((char*)value.ptr());
+}
+
+rviewText::rviewText(wxPanel *parent, int value, char *label, int x, int y, int w, int h) : wxText(parent, (wxFunction)rviewEventHandler, label, NULL, x, y, w, h, wxTE_PROCESS_ENTER)
+{
+ char buffer[32];
+ sprintf(buffer, "%d", value);
+ wxText::SetValue(buffer);
+}
+
+
+rviewText::rviewText(wxPanel *parent, long value, char *label, int x, int y, int w, int h) : wxText(parent, (wxFunction)rviewEventHandler, label, NULL, x, y, w, h, wxTE_PROCESS_ENTER)
+{
+ char buffer[32];
+ sprintf(buffer, "%ld", value);
+ wxText::SetValue(buffer);
+}
+
+
+rviewText::rviewText(wxPanel *parent, double value, bool sciForm, char *label, int x, int y, int w, int h) : wxText(parent, (wxFunction)rviewEventHandler, label, NULL, x, y, w, h, wxTE_PROCESS_ENTER)
+{
+ char buffer[32];
+ sprintf(buffer, (sciForm) ? "%g" : "%f", value);
+ wxText::SetValue(buffer);
+}
+
+void rviewText::SetValue(char *value)
+{
+ wxText::SetValue(value);
+}
+
+void rviewText::SetValue(const char *value)
+{
+ wxText::SetValue((char*)value);
+}
+
+void rviewText::SetValue(const DynamicString &value)
+{
+ wxText::SetValue((char*)value.ptr());
+}
+
+void rviewText::SetValue(int value)
+{
+ char buffer[32];
+ sprintf(buffer, "%d", value);
+ wxText::SetValue(buffer);
+}
+
+void rviewText::SetValue(unsigned int value)
+{
+ char buffer[32];
+ sprintf(buffer, "%u", value);
+ wxText::SetValue(buffer);
+}
+
+void rviewText::SetValue(long value)
+{
+ char buffer[32];
+ sprintf(buffer, "%ld", value);
+ wxText::SetValue(buffer);
+}
+
+void rviewText::SetValue(double value, bool sciForm)
+{
+ char buffer[32];
+ sprintf(buffer, (sciForm) ? "%g" : "%f", value);
+ wxText::SetValue(buffer);
+}
+
+char *rviewText::GetValue(void)
+{
+ return wxText::GetValue();
+}
+
+void rviewText::GetValue(DynamicString &value)
+{
+ value = wxText::GetValue();
+}
+
+void rviewText::GetValue(int &value)
+{
+ value = asctoi(wxText::GetValue());
+}
+
+void rviewText::GetValue(long &value)
+{
+ value = asctol(wxText::GetValue());
+}
+
+void rviewText::GetValue(float &value)
+{
+ value = asctof(wxText::GetValue());
+}
+
+void rviewText::GetValue(double &value)
+{
+ value = asctof(wxText::GetValue());
+}
+
+
+
+rviewButton::rviewButton(wxPanel *parent, char *label, int x, int y, int w, int h, long style) : wxButton(parent, (wxFunction)rviewEventHandler, label, x, y, w, h, style)
+{
+}
+
+rviewChoice::rviewChoice(wxPanel *parent, int n, char *choices[], char *label, int x, int y, int w, int h, long style) : wxChoice(parent, (wxFunction)rviewEventHandler, label, x, y, w, h, n, choices, style)
+{
+}
+
+// hacked version to make up for wxWindows' lack of const
+rviewChoice::rviewChoice(wxPanel *parent, int n, const char *choices[], char *label, int x, int y, int w, int h, long style) : wxChoice(parent, (wxFunction)rviewEventHandler, label, x, y, w, h, n, (char**)choices, style)
+{
+}
+
+rviewCheckBox::rviewCheckBox(wxPanel *parent, char *label, int x, int y, int w, int h) : wxCheckBox(parent, (wxFunction)rviewEventHandler, label, x, y, w, h)
+{
+}
+
+rviewRadioButton::rviewRadioButton(wxPanel *parent, char *label, bool value, int x, int y, int w, int h) : wxRadioButton(parent, (wxFunction)rviewEventHandler, label, value, x, y, w, h)
+{
+}
+
+rviewScrollBar::rviewScrollBar(wxPanel *parent, int x, int y, int w, int h, long style) : wxScrollBar(parent, (wxFunction)rviewEventHandler, x, y, w, h, style)
+{
+}
+
+rviewSlider::rviewSlider(wxPanel *parent, int value, int min_val, int max_val, int width, char *label, int x, int y, long style) : wxSlider(parent, (wxFunction)rviewEventHandler, label, value, min_val, max_val, x, y, style)
+{
+}
+
+
+
+/*
+ * The special slider class when arbitrary mouse events are required.
+ */
+
+const int rviewSpecialSlider::dflt_barwidth = 30;
+const int rviewSpecialSlider::dflt_barheight = 10;
+const int rviewSpecialSlider::dflt_width = 200;
+const int rviewSpecialSlider::dflt_height = rviewSpecialSlider::dflt_barheight + 2*rviewSpecialSlider::dflt_border;
+const int rviewSpecialSlider::dflt_border = 4;
+
+rviewSpecialSlider::rviewSpecialSlider(rviewFrame *logParent, wxPanel *parent, int val, int min, int max, int width, const char *label) :
+ wxCanvas(parent, -1, -1, (width==-1) ? dflt_width : width, dflt_height, wxRETAINED),
+ background(0x00,0x00,0x00),
+ foreground(0x00,0xff,0x00),
+ wellground(0xff,0xff,0xff),
+ outline(0x00,0x00,0x00),
+ labelColour(*(parent->GetLabelColour())),
+ bback(background, wxTRANSPARENT),
+ bfore(foreground, wxSOLID),
+ bwell(wellground, wxSOLID),
+ outlinePen(outline, 1, wxSOLID),
+ labelFont(12, wxROMAN, wxNORMAL, wxNORMAL),
+ myLabel(label)
+{
+ wxBrush *dcb;
+ logicalParent = logParent;
+ border = dflt_border;
+ barwidth = dflt_barwidth; barheight = dflt_barheight;
+ value = val;
+ vmin = min; vmax = max;
+ if (vmax <= vmin)
+ vmax = vmin+1;
+ dcb = ((wxPanel*)GetParent())->GetDC()->GetBackground();
+ bback = wxBrush(dcb->GetColour(), dcb->GetStyle());
+ SetBackground(&bback);
+ SetFont(&labelFont);
+ GetDC()->GetTextExtent(myLabel.ptr(), &textx, &texty);
+}
+
+rviewSpecialSlider::~rviewSpecialSlider(void)
+{
+}
+
+int rviewSpecialSlider::GetMin(void) const
+{
+ return vmin;
+}
+
+int rviewSpecialSlider::GetMax(void) const
+{
+ return vmax;
+}
+
+int rviewSpecialSlider::GetValue(void) const
+{
+ return value;
+}
+
+void rviewSpecialSlider::SetRange(int min, int max)
+{
+ if (min < max)
+ {
+ vmin = min; vmax = max;
+ if (value < vmin)
+ value = vmin;
+ if (value > vmax)
+ value = vmax;
+ Refresh(TRUE);
+ }
+}
+
+void rviewSpecialSlider::SetValue(int val)
+{
+ if ((vmin <= val) && (val <= vmax))
+ {
+ float barx, bary, bheight, newbx;
+
+ getBarParams(barx, bary, bheight);
+ value = val;
+ getBarParams(newbx, bary, bheight);
+ updateWell(barx, newbx, bary, bheight);
+ }
+}
+
+void rviewSpecialSlider::SetLabel(const char *label)
+{
+ myLabel = label;
+ GetDC()->GetTextExtent(myLabel.ptr(), &textx, &texty);
+ Refresh(TRUE);
+}
+
+bool rviewSpecialSlider::PositionInWell(float posx, float posy)
+{
+ int y0, y1;
+
+ GetClientSize(&cwidth, &cheight);
+ getWellVert(y0, y1);
+ if (((float)y0 <= posy) && (posy <= (float)y1))
+ {
+ if ((posx >= textx + 2*border) && (posx <= (float(cwidth - border))))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+void rviewSpecialSlider::getWellVert(int &y0, int &y1)
+{
+ y0 = cheight - 2*border - barheight;
+ if (y0 < 0)
+ y0 = 0;
+ y0 += border;
+ y1 = cheight - border;
+ if (y1 < y0)
+ y1 = y0;
+}
+
+void rviewSpecialSlider::getBarParams(float &posx, float &posy, float &height)
+{
+ int y0, y1;
+
+ GetClientSize(&cwidth, &cheight);
+
+ posx = (float)((cwidth - 3*border - barwidth - textx) * (value-vmin)) / (vmax - vmin);
+ if (posx < 0)
+ posx = 0;
+ /*cout << "cwidth " << cwidth << ", textx " << textx << ", value " << value << ", border " << border
+ << ", barwidth " << barwidth << ", vmin " << vmin << ", vmax " << vmax << ", posx " << posx << endl;*/
+ posx += (float)(2*border + textx);
+ getWellVert(y0, y1);
+ posy = (float)y0;
+ height = (float)(y1 - y0);
+}
+
+int rviewSpecialSlider::calcNewValue(float posx, float posy, int &val, bool checky)
+{
+ int y0, y1;
+
+ GetClientSize(&cwidth, &cheight);
+
+ getWellVert(y0, y1);
+ if (!checky || ((float)y0 <= posy) && (posy <= (float)y1))
+ {
+ float rem = (float)(cwidth - 3*border - barwidth - textx);
+ if (rem < 1.0)
+ rem = 1.0;
+ val = (int)((((posx - 2*border - textx) * (vmax - vmin)) / rem) + 0.5) + vmin;
+ if (val < vmin)
+ val = vmin;
+ if (val > vmax)
+ val = vmax;
+
+ return 0;
+ }
+ return -1;
+}
+
+
+void rviewSpecialSlider::getUpdateInterval(float oldx, float newx, float &clipx, float &clipw)
+{
+ if (oldx < newx)
+ {
+ clipx = oldx; clipw = newx - oldx + barwidth;
+ }
+ else
+ {
+ clipx = newx; clipw = oldx - newx + barwidth;
+ }
+}
+
+
+void rviewSpecialSlider::updateWell(float oldx, float newx, float posy, float bheight)
+{
+ float clipx, clipw;
+
+ getUpdateInterval(oldx, newx, clipx, clipw);
+ //cout << "CLIP " << clipx << ", " << posy << ", " << clipw << ", " << bheight << endl;
+ // need to enlarge the clipping region somewhat to make sure everything is redrawn
+ BeginDrawing();
+ SetClippingRegion(clipx, 0, clipw+2, cheight);
+ //Clear();
+ redrawCore(newx, posy, bheight);
+ DestroyClippingRegion();
+ EndDrawing();
+}
+
+
+void rviewSpecialSlider::redrawCore(float x, float y, float bheight)
+{
+ float extx, exty, nx, ny;
+ char number[32];
+
+ // first draw the label
+ SetFont(&labelFont);
+ SetTextForeground(&labelColour);
+ DrawText(myLabel.ptr(), 0, y);
+
+ SetPen(&outlinePen);
+ SetBrush(&bwell);
+ DrawRectangle(textx + border, y-border, (float)cwidth - textx - border, bheight + 2*border);
+ SetBrush(&bfore);
+ DrawRectangle(x, y, (float)barwidth, bheight);
+
+ // then draw the current value on top
+ sprintf(number, "%d", value);
+ GetDC()->GetTextExtent(number, &extx, &exty);
+ nx = x + (barwidth - extx)/2; ny = y - exty - border;
+ SetPen(NULL);
+ // must use a non-transparent brush. Finally found the right one!
+ SetBrush(((wxPanel*)GetParent())->GetDC()->GetBackground());
+ DrawRectangle(0, ny, (float)cwidth, exty);
+ DrawText(number, nx, ny);
+}
+
+
+void rviewSpecialSlider::OnPaint(void)
+{
+ wxRect rect;
+ float x, y, bheight;
+
+ getBarParams(x, y, bheight);
+
+ BeginDrawing();
+
+ wxUpdateIterator upd(this);
+ while (upd)
+ {
+ upd.GetRect(&rect);
+ redrawCore(x, y, bheight);
+ upd++;
+ }
+ EndDrawing();
+}
+
+void rviewSpecialSlider::OnEvent(wxMouseEvent &mevt)
+{
+ int type = mevt.GetEventType();
+ float barx, bary, bheight;
+ float mx, my;
+ int newVal = value;
+
+ getBarParams(barx, bary, bheight);
+ mevt.Position(&mx, &my);
+ if ((type == wxEVENT_TYPE_LEFT_DOWN) || (type == wxEVENT_TYPE_RIGHT_DOWN))
+ {
+ if (mx < barx)
+ {
+ if (calcNewValue(barx - barwidth, my, newVal, TRUE) != 0)
+ newVal = value;
+ }
+ else if (mx > barx + barwidth)
+ {
+ if (calcNewValue(barx + barwidth, my, newVal, TRUE) != 0)
+ newVal = value;
+ }
+ }
+ else if (type == wxEVENT_TYPE_MOTION)
+ {
+ if (mevt.LeftIsDown() || mevt.RightIsDown())
+ {
+ if (calcNewValue(mx - barwidth/2, my, newVal, FALSE) != 0)
+ {
+ newVal = value;
+ }
+ }
+ }
+ if (newVal != value)
+ {
+ float newbx, newby, newbh;
+
+ value = newVal;
+ getBarParams(newbx, newby, newbh);
+ updateWell(barx, newbx, bary, bheight);
+
+ // additionally we build a regular command event
+ wxCommandEvent cmd(wxEVENT_TYPE_SLIDER_COMMAND);
+ //OnCommand(*GetParent(), cmd);
+ logicalParent->process(*this, cmd);
+ }
+ // the entire point of this class is to always pass on the actual mouse event to the parent
+ logicalParent->childMouseEvent(this, mevt);
+}
+
+
+
+
+
+
+/*
+ * rviewDialog member functions.
+ */
+
+const int rviewDialog::dialog_width = 300;
+const int rviewDialog::dialog_height = 170;
+const int rviewDialog::dialog_border = 8;
+const int rviewDialog::dialog_buttonsx = 80;
+const int rviewDialog::dialog_buttonsy = 30;
+const int rviewDialog::dialog_bheight = rviewDialog::dialog_buttonsy + 16;
+const int rviewDialog::dialog_lines = 8;
+const int rviewDialog::dialog_lheight = 20;
+
+
+// The strings passed to this function may be labels (first char is a backslash)
+// or explicit text.
+rviewDialog::rviewDialog(const char *title, const char *message, int buttonNo, const char *buttons[]):
+ rviewFrame(NULL, "", 0, 0, dialog_width, dialog_height)
+{
+ int i, x, y;
+ char *string;
+
+ panel = NULL; buttonNumber = 0; buttonPressed = 0;
+
+ buttonText = new char *[buttonNo + 2];
+ but = new rviewButton *[buttonNo];
+
+ if ((buttonText == NULL) || (but == NULL))
+ {
+ cerr << "rviewDialog::rviewDialog(): " << lman->lookup("errorMemory") << endl;
+ if (buttonText != NULL) delete [] buttonText;
+ if (but != NULL) delete [] but;
+ return;
+ }
+
+ buttonNumber = buttonNo;
+
+ buttonText[0] = (char*)title; buttonText[1] = (char*)message;
+ for (i=0; i<buttonNumber; i++)
+ {
+ but[i] = NULL; buttonText[i+2] = (char*)buttons[i];
+ }
+
+ // Only memorize those strings that are a label identifier (first char a backslash)
+ for (i=0; i<2+buttonNumber; i++)
+ {
+ if (buttonText[i] != NULL)
+ {
+ // Don't combine the two ifs with && : there is no defined evaluation order for && !
+ // Always memorize the message text.
+ if ((buttonText[i][0] == '\\') || (i == 1))
+ {
+ // We remove the backslash but need one additional char for the
+ // line terminator ==> strlen -1 + 1.
+ if ((string = new char[strlen(buttonText[i]) + ((i==1) ? 1 : 0)]) == NULL)
+ {
+ cerr << "rviewDialog::rviewDialog(): " << lman->lookup("errorMemory") << endl;
+ while (--i >= 0)
+ {
+ if (buttonText[i] != NULL) delete [] buttonText[i];
+ }
+ delete [] buttonText; buttonText = NULL;
+ delete [] but; but = NULL;
+ buttonNumber = 0;
+ return;
+ }
+ strcpy(string, buttonText[i] + ((i==1) ? 0 : 1)); buttonText[i] = string;
+ //cout << "buttonText[" << i << "] = " << buttonText[i] << endl;
+ }
+ else buttonText[i] = NULL;
+ }
+ }
+
+ GetClientSize(&x, &y);
+
+ panel = new wxPanel((wxWindow*)this, 100, 100, 10, 10);
+
+ msg = new rviewMultiline(panel, dialog_border, dialog_border, dialog_lheight, dialog_lines);
+
+ //cout << x << ", " << y << endl;
+
+ // If the strings are not labels then set them now statically, otherwise they will
+ // be set in the following label() call.
+ if (title[0] != '\\')
+ {
+ SetTitle((char*)title);
+ }
+
+ // Now handle all buttons.
+ for (i=0; i<buttonNumber; i++)
+ {
+ but[i] = new rviewButton(panel);
+ if (buttons[i][0] != '\\')
+ {
+ but[i]->SetLabel((char*)buttons[i]);
+ }
+ else // do this for the button size.
+ {
+ but[i]->SetLabel(lman->lookup(buttons[i]+1));
+ }
+ }
+
+ OnSize(x, y);
+
+ label();
+
+ Show(TRUE);
+}
+
+
+
+rviewDialog::~rviewDialog(void)
+{
+ int i;
+
+ // Widgets that were created as children of other wx items are deleted by those items.
+ // They mustn't be destroyed here!
+
+ if (msg != NULL) delete msg;
+ //if (panel != NULL) delete panel;
+
+ if (but != NULL)
+ {
+ //for (i=0; i<buttonNumber; i++) {if (but[i] != NULL) delete but[i];}
+ delete [] but;
+ }
+
+ if (buttonText != NULL)
+ {
+ for (i=0; i<2+buttonNumber; i++) {if (buttonText[i] != NULL) delete [] buttonText[i];}
+ delete [] buttonText;
+ }
+}
+
+
+const char *rviewDialog::getFrameName(void) const
+{
+ return "rviewDialog";
+}
+
+rviewFrameType rviewDialog::getFrameType(void) const
+{
+ return rviewFrameTypeDialog;
+}
+
+
+void rviewDialog::OnSize(int w, int h)
+{
+ int x, y, empty, pos, i;
+
+ RMDBGONCE( 3, RMDebug::module_applications, "rviewDialog", "OnSize( " << x << ", " << h << " )" );
+
+ GetClientSize(&x, &y);
+ if ((frameWidth == x) && (frameHeight == y)) return;
+ frameWidth = x; frameHeight = y;
+
+ x -= 2*dialog_border; y -= dialog_border;
+ panel->SetSize(0, 0, x, y);
+
+ if (buttonText[1][0] == '\\')
+ msg->rebuild(lman->lookup(buttonText[1]+1), x);
+ else
+ msg->rebuild(buttonText[1], x);
+
+ // Space out the buttons on the available space.
+ if (buttonNumber == 0) return;
+
+ empty = (x - buttonNumber*dialog_buttonsx) / buttonNumber;
+ if(empty <0 )
+ empty=0;
+
+ pos = empty/2;
+
+ for (i=0; i<buttonNumber; i++)
+ {
+ but[i]->SetSize(pos, y - (dialog_bheight + dialog_buttonsy)/2, dialog_buttonsx, dialog_buttonsy);
+ pos += empty + dialog_buttonsx;
+ }
+}
+
+
+
+void rviewDialog::label(void)
+{
+ int i, x, y;
+
+ //cout << "rviewDialog::label()" << endl;
+ // If the widgets are labels then set their new values.
+
+ panel->GetClientSize(&x, &y);
+ if (buttonText[0] != NULL)
+ {
+ SetTitle(lman->lookup(buttonText[0]));
+ }
+
+ // The message is always stored.
+ if (buttonText[1][0] == '\\')
+ msg->rebuild(lman->lookup(buttonText[1]+1), x);
+ else
+ msg->rebuild(buttonText[1], x);
+
+ for (i=0; i<buttonNumber; i++)
+ {
+ if (buttonText[2+i] != NULL)
+ {
+ but[i]->SetLabel(lman->lookup(buttonText[2+i]));
+ }
+ }
+}
+
+
+
+
+/*
+ * Process events which are broadcast by the frame manager.
+ */
+
+int rviewDialog::process(wxObject &obj, wxEvent &evt)
+{
+ int i, type;
+
+ //cout << "rviewDialog::process()" << endl;
+ for (i=0; i<buttonNumber; i++)
+ {
+ if (&obj == (wxObject*)but[i]) break;
+ }
+
+ if (i >= buttonNumber) return 0;
+
+ type = evt.GetEventType();
+
+ if (type == wxEVENT_TYPE_BUTTON_COMMAND)
+ {
+ buttonPressed = i+1;
+ }
+ else
+ {
+ buttonPressed = 0;
+ }
+ //cout << "rviewDialog::process():" << (void*)this << " Button " << buttonPressed << endl;
+
+ return buttonPressed;
+}
+
+
+
+/*
+ * Polling interface to the dialog box. Returns the number of the button that
+ * was pressed, starting from 1 (0 means none). On reading the button number
+ * is reset to 0.
+ */
+
+int rviewDialog::GetButton(void)
+{
+ int val = buttonPressed;
+
+ buttonPressed = 0;
+ return val;
+}
+
+
+
+
+
+/*
+ * Error box
+ * (an intrinsically modal special case of a dialog box)
+ */
+
+char *rviewErrorboxDefaultButton[1] = {"\\textOK"};
+
+rviewErrorbox::rviewErrorbox(const char *message): rviewDialog("\\errorFrom", message, 1, (const char**)rviewErrorboxDefaultButton)
+{
+ //place this in log file
+ cerr << lman->lookup("errorFrom") << ' ' << message << endl;
+}
+
+
+rviewErrorbox::rviewErrorbox(const char *title, const char *message, int buttonNo, const char *buttons[]): rviewDialog(title, message, buttonNo, buttons)
+{
+ //place this in log file
+ cerr << lman->lookup("errorFrom") << ' ' << message << endl;
+}
+
+
+rviewErrorbox::~rviewErrorbox(void) {;}
+
+
+const char *rviewErrorbox::getFrameName(void) const
+{
+ return "rviewErrorbox";
+}
+
+rviewFrameType rviewErrorbox::getFrameType(void) const
+{
+ return rviewFrameTypeErrorbox;
+}
+
+
+int rviewErrorbox::activate(void)
+{
+ int pressed;
+
+ MakeModal(TRUE);
+ while ((pressed = GetButton()) == 0) ::wxYield();
+ MakeModal(FALSE);
+ return pressed;
+}
+
+
+// static member functions
+char *rviewErrorbox::buildErrorMessage(const char *message, const char *classname, const char *funcname)
+{
+ char *buffer, *b;
+ int bsize = strlen(message) + 1;
+
+ if (classname != NULL)
+ {
+ bsize += strlen(classname) + 3; // ": "
+
+ // funcname is ignored unless class name is given
+ if (funcname != NULL)
+ bsize += strlen(funcname) + 3; // "::"
+ }
+
+ buffer = new char[bsize];
+ b = buffer;
+
+ if (classname != NULL)
+ {
+ b += sprintf(b, "%s", classname);
+
+ if (funcname != NULL)
+ b += sprintf(b, "::%s", funcname);
+
+ b += sprintf(b, ": ");
+ }
+ b += sprintf(b, "%s", message);
+
+ return buffer;
+}
+
+
+rviewErrorbox *rviewErrorbox::newErrorbox(const char *message, const char *classname, const char *funcname)
+{
+ char *msg;
+ rviewErrorbox *box;
+
+ msg = buildErrorMessage(message, classname, funcname);
+ box = new rviewErrorbox(msg);
+ delete [] msg;
+
+ return box;
+}
+
+
+rviewErrorbox *rviewErrorbox::newErrorbox(const char *title, const char *message, int buttonNo, const char *buttons[], const char *classname, const char *funcname)
+{
+ char *msg;
+ rviewErrorbox *box;
+
+ msg = buildErrorMessage(message, classname, funcname);
+ box = new rviewErrorbox(msg);
+ delete [] msg;
+
+ return box;
+}
+
+
+int rviewErrorbox::reportError(const char *message, const char *classname, const char *funcname)
+{
+ rviewErrorbox *box;
+ int but;
+
+ box = newErrorbox(message, classname, funcname);
+ but = box->activate();
+ box->Close(TRUE);
+
+ return but;
+}
+
+
+int rviewErrorbox::reportError(const char *title, const char *message, int buttonNo, const char *buttons[], const char *classname, const char *funcname)
+{
+ rviewErrorbox *box;
+ int but;
+
+ box = newErrorbox(title, message, buttonNo, buttons, classname, funcname);
+ but = box->activate();
+ box->Close(TRUE);
+
+ return but;
+}
+
+
+
+
+
+/*
+ * rviewProgress members
+ */
+
+rviewProgress::rviewProgress(const char *message): rviewDialog("\\messageFrom", message, 1, (const char**)rviewErrorboxDefaultButton)
+{
+ int x, y;
+
+ RMDBGONCE( 3, RMDebug::module_applications, "rviewProgress", "rviewProgress( " << lman->lookup("messageFrom") << message << " )" );
+
+ GetSize(&x, &y);
+ y = 2*dialog_border + msg->getMessageHeight() + dialog_bheight;
+ SetSize(-1, -1, x, y);
+
+ // Have to do this to make sure you actually see anything in the window
+ // Crude, but nothing else seems to work...
+ Refresh(TRUE); ::wxYield();
+ // Wait 300ms
+ ::wxStartTimer();
+ while (::wxGetElapsedTime(FALSE) < 300) ::wxYield();
+}
+
+
+
+
+rviewProgress::~rviewProgress(void) {;}
+
+
+int rviewProgress::process(wxObject &obj, wxEvent &evt)
+{
+ if (rviewDialog::process(obj, evt) != 0)
+ {
+ this->Close(TRUE);
+ return 1;
+ }
+ return 0;
+}
+
+
+const char *rviewProgress::getFrameName(void) const
+{
+ return "rviewProgress";
+}
+
+rviewFrameType rviewProgress::getFrameType(void) const
+{
+ return rviewFrameTypeProgress;
+}
+
+
+
+
+/*
+ * rviewResult members
+ */
+
+const int rviewResult::result_x = 0;
+const int rviewResult::result_y = 0;
+const int rviewResult::result_width = 320;
+const int rviewResult::result_height = 296;
+const int rviewResult::result_border = 8;
+const int rviewResult::result_lheight = 20;
+const int rviewResult::result_header = (8 * rviewResult::result_lheight);
+const int rviewResult::result_cwidth = 150;
+const int rviewResult::result_twidth = 90;
+const int rviewResult::result_theight = 30;
+const int rviewResult::result_bwidth = 60;
+const int rviewResult::result_bheight = 30;
+
+rviewResult::rviewResult(void): rviewFrame(NULL, "", result_x, result_y, result_width, result_height)
+{
+ RMDBGONCE( 3, RMDebug::module_applications, "rviewResult", "rviewResult() " << this);
+
+ setupVariables();
+ configureGrey();
+ Show(FALSE);
+}
+
+rviewResult::rviewResult(collection_desc *collection): rviewFrame(NULL, "", result_x, result_y, result_width, result_height)
+{
+ setupVariables();
+ setCollection(collection);
+}
+
+
+rviewResult::~rviewResult(void)
+{
+ RMDBGONCE( 3, RMDebug::module_applications, "rviewResult", "rviewResult() " << this );
+
+ int i;
+ collection_desc *ptr = coll;
+ user_event ue;
+
+ // give all viewers a chance to clean up
+ ue.type = usr_mdd_dying;
+ for (i=0; i<coll->number; i++)
+ {
+ ue.data = (void*)&(coll->mddObjs[i].mdd);
+ frames->broadcastUserEvent(ue);
+ }
+
+ // All the widgets are deleted automatically.
+ if (selectedItems != NULL) delete [] selectedItems;
+ if (typeManager != NULL) {typeManager->unlinkParent(); typeManager->Close(TRUE);}
+
+ rviewDeleteCollection(coll);
+}
+
+
+const char *rviewResult::getFrameName(void) const
+{
+ return "rviewResult";
+}
+
+rviewFrameType rviewResult::getFrameType(void) const
+{
+ return rviewFrameTypeResult;
+}
+
+
+void rviewResult::setCollection(collection_desc *collection)
+{
+ int x, y, i;
+ char res_string[STRINGSIZE];
+
+ // In case this is called when the frame already displays a result (shouldn't
+ // normally happen, though)
+ if (coll != NULL)
+ {
+ rviewDeleteCollection(coll);
+ delete list;
+ }
+ coll = collection;
+
+ // Init flags
+ for (i=0; i<coll->number; i++)
+ {
+ coll->mddObjs[i].flags = 0;
+ }
+
+ GetClientSize(&x, &y);
+
+ list = new wxListBox(panel, (wxFunction)&rviewEventHandler, "", wxMULTIPLE, result_border, result_border + result_header, x, y - result_header, 0, NULL, wxALWAYS_SB | wxLB_MULTIPLE);
+
+ ostrstream memstr(res_string, STRINGSIZE);
+ for (i=0; i<coll->number; i++)
+ {
+ list->Append(mddDescriptorString(memstr, i));
+ }
+
+ if (selectedItems != NULL) delete [] selectedItems;
+ i = (coll->number + 7) >> 3;
+ if ((selectedItems = new char[i]) == NULL)
+ {
+ cerr << "rviewResult::setCollection(): " << lman->lookup("errorMemory") << endl;
+ this->Close(TRUE);
+ return;
+ }
+ memset(selectedItems, 0, i);
+
+ configureGrey();
+
+ label();
+
+ // Force resize
+ frameWidth = -1; frameHeight = -1;
+ OnSize(x, y);
+
+ Show(TRUE);
+}
+
+
+
+char *rviewResult::mddDescriptorString(ostrstream &memstr, int number)
+{
+ r_GMarray *mdd = coll->mddObjs[number].mdd.ptr();
+ r_Data_Format fmt = mdd->get_current_format();
+
+ memstr.width(3);
+ memstr << number << ": ("; memstr.width(0);
+ memstr << mdd->get_type_length() << ") "
+ << mdd->spatial_domain() << ' '
+ << fmt << '\0';
+ memstr.seekp(0);
+
+ return memstr.str();
+}
+
+
+void rviewResult::label(void)
+{
+ char buffer[STRINGSIZE];
+
+ //cout << "labelling " << (void*)mBar << endl;
+
+ SetTitle(lman->lookup("titleResult"));
+
+ if (mBar != NULL)
+ {
+ // Configure all the text in the menu bar
+ mBar->SetLabel(MENU_RSLT_ITEM_OPENALL, lman->lookup("menRsltItemOpAll"));
+ mBar->SetLabel(MENU_RSLT_ITEM_THUMBALL, lman->lookup("menRsltItemThumbAll"));
+ mBar->SetLabel(MENU_RSLT_ITEM_CLOSE, lman->lookup("menRsltItemClose"));
+ mBar->SetHelpString(MENU_RSLT_ITEM_OPENALL, lman->lookup("helpRsltItemOpAll"));
+ mBar->SetHelpString(MENU_RSLT_ITEM_THUMBALL, lman->lookup("helpRsltItemThumbAll"));
+ mBar->SetHelpString(MENU_RSLT_ITEM_CLOSE, lman->lookup("helpRsltItemClose"));
+
+ mBar->SetLabel(MENU_RSLT_SLCT_SLCTALL, lman->lookup("menRsltSlctSlctAll"));
+ mBar->SetLabel(MENU_RSLT_SLCT_CLEAR, lman->lookup("menRsltSlctClear"));
+ mBar->SetLabel(MENU_RSLT_SLCT_OPEN, lman->lookup("menRsltSlctOpen"));
+ mBar->SetLabel(MENU_RSLT_SLCT_THUMB, lman->lookup("menRsltSlctThumb"));
+ mBar->SetLabel(MENU_RSLT_SLCT_DELETE, lman->lookup("menRsltSlctDel"));
+ mBar->SetLabel(MENU_RSLT_SLCT_ENDIAN, lman->lookup("menRsltSlctEndian"));
+ mBar->SetLabel(MENU_RSLT_SLCT_TYPEMAN, lman->lookup("menRsltSlctTypeMan"));
+ mBar->SetLabel(MENU_RSLT_SLCT_INFO, lman->lookup("menRsltSlctInfo"));
+ mBar->SetHelpString(MENU_RSLT_SLCT_SLCTALL, lman->lookup("helpRsltSlctSlctAll"));
+ mBar->SetHelpString(MENU_RSLT_SLCT_CLEAR, lman->lookup("helpRsltSlctClear"));
+ mBar->SetHelpString(MENU_RSLT_SLCT_OPEN, lman->lookup("helpRsltSlctOpen"));
+ mBar->SetHelpString(MENU_RSLT_SLCT_THUMB, lman->lookup("helpRsltSlctThumb"));
+ mBar->SetHelpString(MENU_RSLT_SLCT_DELETE, lman->lookup("helpRsltSlctDel"));
+ mBar->SetHelpString(MENU_RSLT_SLCT_ENDIAN, lman->lookup("helpRsltSlctEndian"));
+ mBar->SetHelpString(MENU_RSLT_SLCT_TYPEMAN, lman->lookup("helpRsltSlctTypeMan"));
+ mBar->SetHelpString(MENU_RSLT_SLCT_INFO, lman->lookup("helpRsltSlctInfo"));
+
+ mBar->SetLabelTop(0, lman->lookup("menRsltItem"));
+ mBar->SetLabelTop(1, lman->lookup("menRsltSlct"));
+ }
+
+ if (list != NULL)
+ {
+ list->SetLabel(lman->lookup("textResult"));
+ }
+
+ if (group != NULL)
+ {
+ group->SetLabel(lman->lookup("textCollHeader"));
+ sprintf(buffer, "%s: %s", lman->lookup("textCollName"), (coll->collName == NULL) ? "" : coll->collName);
+ collName->SetLabel(buffer);
+ sprintf(buffer, "%s: %s", lman->lookup("textCollType"), (coll->collType == NULL) ? "?" : coll->collType);
+ collType->SetLabel(buffer);
+ sprintf(buffer, (coll->collInfo == NULL) ? "" : coll->collInfo);
+ collInfo->SetLabel(buffer);
+
+ if (choice != NULL)
+ {
+ choice->SetLabel(lman->lookup("dispModeLabel"));
+ }
+ }
+ resampBut->SetLabel(lman->lookup("textOK"));
+
+ //cout << "labelled OK" << endl;
+}
+
+
+
+void rviewResult::OnSize(int w, int h)
+{
+ if (panel != NULL)
+ {
+ int x, y;
+
+ RMDBGONCE( 3, RMDebug::module_applications, "rviewResult", "OnSize( " << w << ", " << h << " )");
+
+ GetClientSize(&x, &y);
+ if ((frameWidth == x) && (frameHeight == y)) return;
+ frameWidth = x; frameHeight = y;
+
+ panel->SetClientSize(x, y);
+ x -= 2*result_border; y -= 2*result_border;
+
+ if (list != NULL)
+ list->SetSize(result_border,
+ result_lheight + result_border + result_header,
+ x,
+ y - result_header - result_lheight);
+
+ if (group != NULL)
+ {
+ group->SetSize(result_border,
+ result_border,
+ x,
+ result_header);
+ //group->GetClientSize(&x, &y);
+ x -= 2*result_border; y -=2*result_border;
+ if (collName != NULL)
+ collName->SetSize(2*result_border,
+ result_lheight + result_border,
+ x,
+ result_lheight);
+ if (collType != NULL)
+ collType->SetSize(2*result_border,
+ 2*result_lheight + result_border,
+ x,
+ result_lheight);
+ if (collInfo != NULL)
+ collInfo->SetSize(2*result_border,
+ 3*result_lheight + result_border,
+ x,
+ result_lheight);
+ if (choice != NULL)
+ choice->SetSize(2*result_border,
+ 4*result_lheight + result_border,
+ result_cwidth - cbfactor,
+ result_lheight);
+ }
+ scaleMode->SetSize(3*result_border/2,
+ 6*result_lheight + result_border,
+ result_cwidth - 2*cbfactor,
+ result_lheight);
+ resampText->SetSize(3*result_border/2 + result_cwidth - cbfactor,
+ 6*result_lheight + result_border,
+ result_twidth,
+ result_theight);
+ resampBut->SetSize(3*result_border/2 + result_cwidth - cbfactor/2 + result_twidth,
+ 6*result_lheight + result_border,
+ result_bwidth,
+ result_bheight);
+ }
+}
+
+
+
+void rviewResult::openViewer(int itemNo)
+{
+
+ RMDBGONCE( 3, RMDebug::module_applications, "rviewResult", "openViewer( " << itemNo << " )" );
+
+ if ((itemNo < 0) || (itemNo >= coll->number)) return;
+
+ rviewDisplay *newDisplay=NULL;
+
+ switch (prefs->lastDisplay)
+ {
+ case 0:
+ {
+ if ((coll->mddObjs[itemNo].flags & RVIEW_RESDISP_IMGFLAT) == 0)
+ {
+ newDisplay = new rviewFlatImage(coll->mddObjs + itemNo);
+ }
+ }
+ break;
+ case 1:
+ {
+ if ((coll->mddObjs[itemNo].flags & RVIEW_RESDISP_IMGVOLM) == 0)
+ {
+ newDisplay = new rviewVolumeImage(coll->mddObjs + itemNo);
+ }
+ }
+ break;
+ case 2:
+ {
+ if ((coll->mddObjs[itemNo].flags & RVIEW_RESDISP_IMGOSECT) == 0)
+ {
+ newDisplay = new rviewOSectionFullImage(coll->mddObjs + itemNo);
+ }
+ }
+ break;
+ case 3:
+ {
+ if ((coll->mddObjs[itemNo].flags & RVIEW_RESDISP_IMGHGHT) == 0)
+ {
+ newDisplay = new rviewHeightImage(coll->mddObjs + itemNo);
+ }
+ }
+ break;
+ case 4:
+ {
+ if ((coll->mddObjs[itemNo].flags & RVIEW_RESDISP_CHART) == 0)
+ {
+ newDisplay = new rviewChart(coll->mddObjs + itemNo);
+ }
+ }
+ break;
+ case 5:
+ {
+ if ((coll->mddObjs[itemNo].flags & RVIEW_RESDISP_TABLE) == 0)
+ {
+ newDisplay = new rviewTable(coll->mddObjs + itemNo);
+ }
+ }
+ break;
+ case 6:
+ {
+ if ((coll->mddObjs[itemNo].flags & RVIEW_RESDISP_SOUND) == 0)
+ {
+ newDisplay = new rviewSoundPlayer(coll->mddObjs + itemNo);
+ }
+ }
+ break;
+ case 7:
+ {
+ if ((coll->mddObjs[itemNo].flags & RVIEW_RESDISP_STRVIEW) == 0)
+ {
+ newDisplay = new rviewStringViewer(coll->mddObjs + itemNo);
+ }
+ }
+ break;
+ default:
+ cerr << "Unsupported display mode " << prefs->lastDisplay << endl;
+ return;
+ }
+
+ if (newDisplay != NULL)
+ {
+ if (newDisplay->openViewer() != 0)
+ newDisplay->Close(TRUE);
+ else
+ {
+ coll->mddObjs[itemNo].flags |= newDisplay->getViewerType();
+ registerChild(newDisplay);
+ }
+ }
+}
+
+
+
+/*
+ * This function must be called whenever the selections of the list box
+ * change (click / double click) or items in the listbox are modified or
+ * deleted (this seems to be some wxWindows-internal bug that always
+ * deselects listbox items if an item was changed).
+ */
+int rviewResult::updateSelection(void)
+{
+ int i, changes, sel=-1;
+ char val;
+
+ if (selectedItems == NULL) return -1;
+
+ changes = 0;
+ for (i=0; i<coll->number; i++)
+ {
+ val = selectedItems[i>>3] & (1<<(i&7));
+ if (list->Selected(i))
+ {
+ if (val == 0) {sel=i; changes++;}
+ selectedItems[i>>3] |= (1<<(i&7));
+ }
+ else
+ {
+ if (val != 0) {sel=i; changes++;}
+ selectedItems[i>>3] &= ~(1<<(i&7));
+ }
+ }
+ if (changes > 1)
+ {
+ cerr << "Warning: more than one selection changed!" << endl;
+ }
+
+ configureGrey();
+
+ return sel;
+}
+
+
+
+void rviewResult::operationPrologue(void)
+{
+ ::wxBeginBusyCursor();
+ ::wxStartTimer();
+}
+
+
+void rviewResult::operationEpilogue(const char *opname)
+{
+ int elapsed = ::wxGetElapsedTime();
+
+ ::wxEndBusyCursor();
+
+ if (opname != NULL)
+ {
+ char buffer[STRINGSIZE];
+
+ sprintf(buffer, "%s \"%s\": %dms", lman->lookup("textOpTime"), opname, elapsed);
+ cout << buffer << endl;
+ SetStatusText(buffer);
+ }
+}
+
+
+int rviewResult::parseResampleString(const char *resStr, double *values)
+{
+ int i;
+ const char *b;
+
+ b = resStr; i = 0;
+ while (*b != 0)
+ {
+ while ((*b == ' ') || (*b == '\t')) b++;
+ if (*b == ',') b++;
+ if (*b != 0)
+ {
+ if (values != NULL) values[i] = atof(b);
+ while ((*b != ' ') && (*b != '\t') && (*b != ',') && (*b != 0)) b++;
+ i++;
+ }
+ }
+ return i;
+}
+
+
+int rviewResult::resampleSelection(void)
+{
+ int i, j, res;
+ double *scale;
+ r_Dimension dim;
+ r_Minterval oldInterv, useInterv, newInterv;
+ r_Ref<r_GMarray> newMdd;
+ rviewBaseType baseType;
+ char buffer[STRINGSIZE];
+ user_event usr;
+ char *valStr;
+ int dimString;
+ int smode;
+ const char *operation=NULL;
+
+ ostrstream memstr(buffer, STRINGSIZE);
+
+ valStr = resampText->GetValue();
+ dimString = parseResampleString(valStr, NULL);
+ scale = new double[dimString];
+ parseResampleString(valStr, scale);
+
+ for (i=0; i<dimString; i++)
+ {
+ if (scale[i] <= 0.0) return 0;
+ if (scale[i] != 1.0) break;
+ }
+
+ smode = scaleMode->GetSelection();
+
+ operationPrologue();
+
+ res = 0;
+ for (i=0; i<coll->number; i++)
+ {
+ if (list->Selected(i))
+ {
+ double totalScale = 1.0;
+
+ baseType = rviewGetBasetype((r_Object*)(&(*(coll->mddObjs[i].mdd))));
+ oldInterv = (coll->mddObjs[i].mdd)->spatial_domain();
+ dim = oldInterv.dimension();
+ newInterv = r_Minterval(dim); useInterv = r_Minterval(dim);
+ for (j=0; j<(int)dim; j++)
+ {
+ double h;
+
+ // Use the entire source object for scaling
+ useInterv << oldInterv[j];
+ h = (j < dimString) ? scale[j] : scale[dimString-1]; totalScale *= h;
+ newInterv << r_Sinterval((r_Range)(oldInterv[j].low()), (r_Range)(oldInterv[j].low() + h*(oldInterv[j].high() - oldInterv[j].low() + 1) - 1));
+ }
+ if (smode == 0) // resampling mode
+ {
+ if (totalScale > 1.0)
+ {
+ operation = lman->lookup("operationUpsamp");
+ j = mdd_objectScaleInter(coll->mddObjs[i].mdd, useInterv, newMdd, newInterv);
+ }
+ else
+ {
+ operation = lman->lookup("operationDownsamp");
+ j = mdd_objectScaleAverage(coll->mddObjs[i].mdd, useInterv, newMdd, newInterv);
+ }
+ }
+ else // simple scale mode
+ {
+ operation = lman->lookup("operationScale");
+ j = mdd_objectScaleSimple(coll->mddObjs[i].mdd, useInterv, newMdd, newInterv);
+ }
+ if (j != 0)
+ {
+ usr.type = usr_mdd_dying; usr.data = (void*)(&((coll->mddObjs[i]).mdd));
+ frames->broadcastUserEvent(usr);
+ coll->mddObjs[i].flags = 0;
+ (coll->mddObjs[i].mdd).destroy();
+ coll->mddObjs[i].mdd = newMdd;
+ res++;
+ list->SetString(i, mddDescriptorString(memstr, i));
+ selectedItems[i>>3] &= ~(1<<(i&7));
+ }
+ }
+ }
+
+ operationEpilogue(operation);
+
+ delete [] scale;
+
+ lastSelected = updateSelection();
+
+ return res;
+}
+
+
+int rviewResult::process(wxObject &obj, wxEvent &evt)
+{
+ int type = evt.GetEventType();
+
+ if (&obj == (wxObject*)list)
+ {
+ if (type == wxEVENT_TYPE_LISTBOX_COMMAND)
+ {
+ //cout << "rviewResult::process Listbox command" << endl;
+ lastSelected = updateSelection();
+ return 1;
+ }
+ if (type == wxEVENT_TYPE_LISTBOX_DCLICK_COMMAND)
+ {
+ if ((lastSelected >= 0) && (lastSelected < coll->number))
+ {
+ // This check is necessary
+ if (!list->Selected(lastSelected))
+ {
+ list->SetSelection(lastSelected, TRUE);
+ if (selectedItems != NULL) selectedItems[lastSelected>>3] |= (1<<(lastSelected&7));
+ }
+ openViewer(lastSelected);
+ }
+ return 1;
+ }
+ }
+ if (&obj == (wxObject*)choice)
+ {
+ if (type == wxEVENT_TYPE_CHOICE_COMMAND)
+ {
+ prefs->lastDisplay = choice->GetSelection();
+ prefs->markModified();
+ return 1;
+ }
+ }
+ if (&obj == (wxObject*)resampText)
+ {
+ if (type == wxEVENT_TYPE_TEXT_ENTER_COMMAND)
+ {
+ resampleSelection();
+ return 1;
+ }
+ }
+ if (&obj == (wxObject*)resampBut)
+ {
+ if (type == wxEVENT_TYPE_BUTTON_COMMAND)
+ {
+ resampleSelection();
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+
+int rviewResult::userEvent(const user_event &ue)
+{
+ if (ue.type == usr_viewer_closed)
+ {
+ mdd_frame *mf = (mdd_frame*)(ue.data);
+ int i;
+
+ //{FILE *fp=fopen("xxx", "a+"); fprintf(fp, "Received viewer closed %p --- %p, %d\n", mf->mdd.ptr(), coll->mddObjs[0].mdd.ptr(), mf->flags); fclose(fp);}
+ for (i=0; i<coll->number; i++)
+ {
+ // must compare pointers, comparing r_Refs has strange effects on Win
+ if (mf->mdd.ptr() == coll->mddObjs[i].mdd.ptr()) break;
+ }
+ if (i < coll->number)
+ {
+ coll->mddObjs[i].flags &= ~(mf->flags);
+ return 1;
+ }
+ }
+ else if (ue.type == usr_child_closed)
+ {
+ if (ue.data == (void*)typeManager) typeManager = NULL;
+ return 1;
+ }
+ else if (ue.type == usr_typeman_convert)
+ {
+ convertSelectedItems();
+ typeManager->Close(TRUE); typeManager = NULL;
+ return 1;
+ }
+ else if (ue.type == usr_close_viewers)
+ {
+ Close(TRUE);
+ return 1;
+ }
+
+ return 0;
+}
+
+
+
+void rviewResult::convertSelectedItems(void)
+{
+ int itemNo;
+ user_event usr;
+ char buffer[STRINGSIZE];
+ ostrstream memstr(buffer, STRINGSIZE);
+
+ operationPrologue();
+
+ for (itemNo=0; itemNo < coll->number; itemNo++)
+ {
+ if ((list->Selected(itemNo)) && (!coll->mddObjs[itemNo].mdd.is_null()))
+ {
+ r_Ref<r_GMarray> newMdd;
+
+ if (typeManager->convert(coll->mddObjs[itemNo].mdd, newMdd) == 0)
+ {
+ usr.type = usr_mdd_dying; usr.data = (void*)(&((coll->mddObjs[itemNo]).mdd));
+ frames->broadcastUserEvent(usr);
+ coll->mddObjs[itemNo].mdd.destroy();
+ coll->mddObjs[itemNo].mdd = newMdd;
+ list->SetString(itemNo, mddDescriptorString(memstr, itemNo));
+ }
+ else
+ {
+ newMdd.destroy();
+ }
+ }
+ }
+
+ operationEpilogue(lman->lookup("operationTypeProj"));
+
+ lastSelected = updateSelection();
+}
+
+
+
+// Set up some variables and widgets in the frame.
+void rviewResult::setupVariables(void)
+{
+ int x, y;
+ char *displayModes[RVIEW_RESDISP_NUMBER];
+ char *scaleModes[2];
+ wxMenu *mbarMenus[2];
+ char buffer[STRINGSIZE];
+
+ coll = NULL; panel = NULL; list = NULL; collName = NULL; collType = NULL;
+ group = NULL; mBar = NULL; typeManager = NULL;
+ lastSelected = -1;
+ selectedItems = NULL;
+
+ CreateStatusLine(1);
+
+ mbarMenus[0] = new wxMenu;
+ mbarMenus[0]->Append(MENU_RSLT_ITEM_OPENALL, "");
+ mbarMenus[0]->Append(MENU_RSLT_ITEM_THUMBALL, "");
+ mbarMenus[0]->Append(MENU_RSLT_ITEM_CLOSE, "");
+
+ mbarMenus[1] = new wxMenu;
+ mbarMenus[1]->Append(MENU_RSLT_SLCT_SLCTALL, "");
+ mbarMenus[1]->Append(MENU_RSLT_SLCT_CLEAR, "");
+ mbarMenus[1]->Append(MENU_RSLT_SLCT_OPEN, "");
+ mbarMenus[1]->Append(MENU_RSLT_SLCT_THUMB, "");
+ mbarMenus[1]->Append(MENU_RSLT_SLCT_DELETE, "");
+ mbarMenus[1]->Append(MENU_RSLT_SLCT_ENDIAN, "");
+ mbarMenus[1]->Append(MENU_RSLT_SLCT_TYPEMAN, "");
+ mbarMenus[1]->Append(MENU_RSLT_SLCT_INFO, "");
+
+ mBar = new wxMenuBar;
+ sprintf(buffer, "&%s", lman->lookup("menRsltItem"));
+ mBar->Append(mbarMenus[0], buffer);
+ sprintf(buffer, "&%s", lman->lookup("menRsltSlct"));
+ mBar->Append(mbarMenus[1], buffer);
+
+ GetClientSize(&x, &y);
+ panel = new wxPanel((wxWindow*)this, 0, 0, x, y);
+ x -= 2*result_border; y -= 2*result_border;
+
+ // Create a group box surrounding the collection-items
+ group = new wxGroupBox(panel, "", 0, 0, x, result_header, wxBORDER);
+ x -= 2*result_border; y -= 2*result_border;
+ // Create the message widget showing the collection name
+ collName = new wxMessage(panel, "", 2*result_border, result_lheight + 2*result_border, x, result_lheight, 0, "message");
+ // The same for the collection base type
+ collType = new wxMessage(panel, "", 2*result_border, 2*result_lheight + 2*result_border, x, result_lheight, 0, "message");
+ // The info string
+ collInfo = new wxMessage(panel, "", 2*result_border, 3*result_lheight + 2*result_border, x, result_lheight, 0, "message");
+
+ // And the choice item for the display modes.
+ // In contrast to the menu stuff non-persistent objects are OK here.
+ displayModes[0] = lman->lookup("dispModeImage");
+ displayModes[1] = lman->lookup("dispModeVolume");
+ displayModes[2] = lman->lookup("dispModeOrtho");
+ displayModes[3] = lman->lookup("dispModeHeight");
+ displayModes[4] = lman->lookup("dispModeChart");
+ displayModes[5] = lman->lookup("dispModeTable");
+ displayModes[6] = lman->lookup("dispModeSound");
+ displayModes[7] = lman->lookup("dispModeString");
+ choice = new rviewChoice(panel, RVIEW_RESDISP_NUMBER, displayModes, lman->lookup("dispModeLabel"));
+ choice->SetSelection(prefs->lastDisplay);
+
+ scaleModes[0] = lman->lookup("textResample");
+ scaleModes[1] = lman->lookup("textScale");
+ scaleMode = new rviewChoice(panel, 2, scaleModes);
+ scaleMode->SetSelection(0);
+ scaleMode->SetLabel("");
+
+ sprintf(buffer, "%f", 1.0);
+ resampText = new rviewText(panel, buffer);
+ resampBut = new rviewButton(panel, lman->lookup("textOK"));
+
+ choice->GetSize(&x, &y);
+ cbfactor = x - result_cwidth;
+
+ SetMenuBar(mBar);
+}
+
+
+
+
+void rviewResult::OnMenuCommand(int id)
+{
+ switch (id)
+ {
+ case MENU_RSLT_ITEM_OPENALL:
+ {
+ for (int i=0; i<coll->number; i++)
+ {
+ openViewer(i);
+ }
+ }
+ break;
+ case MENU_RSLT_ITEM_THUMBALL:
+ {
+ int i;
+ rviewThumb *thumb;
+
+ thumb = new rviewThumb;
+ for (i=0; i<coll->number; i++)
+ {
+ thumb->addMDD(coll->mddObjs[i].mdd);
+ }
+ registerChild((rviewFrame*)thumb);
+ }
+ break;
+ case MENU_RSLT_ITEM_CLOSE:
+ {
+ this->Close(TRUE);
+ }
+ break;
+ case MENU_RSLT_SLCT_SLCTALL:
+ {
+ for (int i=0; i<coll->number; i++)
+ {
+ if (!list->Selected(i))
+ {
+ list->SetSelection(i, TRUE);
+ }
+ }
+ if (selectedItems != NULL) memset(selectedItems, 0xff, (coll->number + 7) >> 3);
+ configureGrey();
+ }
+ break;
+ case MENU_RSLT_SLCT_CLEAR:
+ {
+ for (int i=0; i<coll->number; i++)
+ {
+ if (list->Selected(i))
+ {
+ list->SetSelection(i, FALSE);
+ }
+ }
+ if (selectedItems != NULL) memset(selectedItems, 0, (coll->number + 7) >> 3);
+ configureGrey();
+ }
+ break;
+ case MENU_RSLT_SLCT_OPEN:
+ {
+ int i;
+
+ for (i=0; i<coll->number; i++)
+ {
+ if (list->Selected(i))
+ openViewer(i);
+ }
+ }
+ break;
+ case MENU_RSLT_SLCT_THUMB:
+ {
+ int i;
+
+ for (i=0; i<coll->number; i++)
+ {
+ if (list->Selected(i)) break;
+ }
+ if (i < coll->number)
+ {
+ rviewThumb *thumb;
+
+ thumb = new rviewThumb;
+ for (i=0; i<coll->number; i++)
+ {
+ if (list->Selected(i))
+ thumb->addMDD(coll->mddObjs[i].mdd);
+ }
+ registerChild((rviewFrame*)thumb);
+ }
+ }
+ break;
+ case MENU_RSLT_SLCT_DELETE:
+ {
+ int itemNo, j;
+ user_event usr;
+
+ do
+ {
+ for (itemNo=0; itemNo < coll->number; itemNo++)
+ if (list->Selected(itemNo)) break;
+
+ if (itemNo >= coll->number) break;
+ list->Delete(itemNo);
+ // Notify all open display frames that a particular mdd object will die
+ usr.type = usr_mdd_dying; usr.data = (void*)(&((coll->mddObjs[itemNo]).mdd));
+ frames->broadcastUserEvent(usr);
+ if (!coll->mddObjs[itemNo].mdd.is_null())
+ {
+ coll->mddObjs[itemNo].mdd.destroy();
+ }
+ (coll->number)--;
+ for (j=itemNo; j<coll->number; j++)
+ {
+ coll->mddObjs[j] = coll->mddObjs[j+1];
+ // Don't forget to copy the selection too
+ selectedItems[j>>3] &= ~(1<<(j&7));
+ if ((selectedItems[(j+1)>>3] & (1<<((j+1)&7))) != 0) selectedItems[j>>3] |= (1<<(j&7));
+ }
+ }
+ while (1);
+ lastSelected = updateSelection();
+ configureGrey();
+ }
+ break;
+ case MENU_RSLT_SLCT_ENDIAN:
+ {
+ int itemNo;
+ user_event ue;
+
+ operationPrologue();
+
+ ue.type = usr_mdd_dying;
+ for (itemNo = 0; itemNo < coll->number; itemNo++)
+ {
+ if ((list->Selected(itemNo)) && (!coll->mddObjs[itemNo].mdd.is_null()))
+ {
+ r_Minterval useInterv;
+
+ ue.data = (void*)(&((coll->mddObjs[itemNo]).mdd));
+ frames->broadcastUserEvent(ue); // close all open viewers
+ useInterv = coll->mddObjs[itemNo].mdd->spatial_domain();
+ mdd_objectChangeEndianness(coll->mddObjs[itemNo].mdd, useInterv);
+ }
+ }
+ operationEpilogue(lman->lookup("operationEndian"));
+ }
+ break;
+ case MENU_RSLT_SLCT_TYPEMAN:
+ if (typeManager == NULL)
+ {
+ int itemNo;
+ const r_Type *sampleType = NULL;
+
+ for (itemNo = 0; itemNo < coll->number; itemNo++)
+ {
+ if ((list->Selected(itemNo)) && (!coll->mddObjs[itemNo].mdd.is_null()))
+ {
+ sampleType = coll->mddObjs[itemNo].mdd->get_base_type_schema();
+ break;
+ }
+ }
+ /*try {
+ sampleType = r_Type::get_any_type("struct { struct { float u, float v, float w }, float p, float te, float ed, float den, float vis }");
+ } catch (r_Error &err) {
+ cerr << err.what() << endl;
+ }*/
+ if (sampleType != NULL)
+ {
+ if (typeManager == NULL)
+ typeManager = new rviewTypeMan(this, sampleType);
+ }
+ }
+ break;
+ case MENU_RSLT_SLCT_INFO: break;
+ default: break;
+ }
+}
+
+
+
+void rviewResult::configureGrey(void)
+{
+ int i;
+
+ mBar->Enable(MENU_RSLT_ITEM_OPENALL, (coll->number > 0));
+ mBar->Enable(MENU_RSLT_ITEM_THUMBALL, (coll->number> 0));
+
+ for (i=0; i<coll->number; i++)
+ {
+ if (list->Selected(i)) break;
+ }
+ bool enable = (i < coll->number);
+
+ mBar->Enable(MENU_RSLT_SLCT_CLEAR, enable);
+ mBar->Enable(MENU_RSLT_SLCT_OPEN, enable);
+ mBar->Enable(MENU_RSLT_SLCT_THUMB, enable);
+ mBar->Enable(MENU_RSLT_SLCT_DELETE, enable);
+ mBar->Enable(MENU_RSLT_SLCT_ENDIAN, enable);
+ mBar->Enable(MENU_RSLT_SLCT_TYPEMAN, enable);
+ mBar->Enable(MENU_RSLT_SLCT_INFO, enable);
+}
+
+
+
+
+
+/*
+ * rView about window
+ */
+
+const int rviewAbout::about_width = 300;
+const int rviewAbout::about_height = 150;
+const int rviewAbout::about_border = 8;
+const int rviewAbout::about_pheight = 50;
+const int rviewAbout::about_bwidth = 80;
+const int rviewAbout::about_bheight = 30;
+const int rviewAbout::about_mheight = 16;
+
+rviewAbout::rviewAbout(void) : rviewFrame(NULL, "", -1, -1, about_width, about_height)
+{
+ labels = NULL; numlines = 0;
+ panel = new wxPanel((wxWindow*)this, 0, 0, about_width, about_height);
+ okBut = new rviewButton(panel);
+
+ label();
+
+ OnSize(about_width, about_height);
+}
+
+
+rviewAbout::~rviewAbout(void)
+{
+ // the messages themselves will be sorted out by the panel destructor.
+ if (labels != NULL) delete [] labels;
+}
+
+
+const char *rviewAbout::getFrameName(void) const
+{
+ return "rviewAbout";
+}
+
+rviewFrameType rviewAbout::getFrameType(void) const
+{
+ return rviewFrameTypeAbout;
+}
+
+
+void rviewAbout::deleteLabels(void)
+{
+ if (labels != NULL)
+ {
+ int i;
+
+ for (i=0; i<numlines; i++) delete labels[i];
+ delete [] labels; labels = NULL; numlines = 0;
+ }
+}
+
+
+void rviewAbout::label(void)
+{
+ int i, number, x, y;
+
+ SetTitle(lman->lookup("titleAbout"));
+ okBut->SetLabel(lman->lookup("textOK"));
+
+ deleteLabels();
+
+ GetClientSize(&x, &y);
+ y = about_border;
+ number = atoi(lman->lookup("rviewAboutLineNum"));
+ if (number >= 1)
+ {
+ char lineName[64];
+
+ numlines = number;
+ labels = new wxMessage *[numlines]; x -= 2*about_border;
+ for (i=0; i<number; i++)
+ {
+ sprintf(lineName, "rviewAboutLine%d", i);
+ labels[i] = new wxMessage(panel, lman->lookup(lineName), about_border, y, x, about_mheight, 0, "message");
+ y += about_mheight;
+ }
+ }
+ SetSize(-1, -1, x, y + about_pheight + rview_window_extra_height);
+}
+
+
+int rviewAbout::process(wxObject &obj, wxEvent &evt)
+{
+ if ((&obj == (wxObject*)okBut) && (evt.GetEventType() == wxEVENT_TYPE_BUTTON_COMMAND))
+ {
+ Show(FALSE); return 1;
+ }
+ return 0;
+}
+
+
+void rviewAbout::OnSize(int w, int h)
+{
+ int x, y;
+
+ GetClientSize(&x, &y);
+
+ panel->SetSize(0, 0, x, y);
+ x -= 2*about_border; y = about_border;
+ if (panel != NULL)
+ {
+ for (int i=0; i<numlines; i++)
+ {
+ labels[i]->SetSize(about_border, y, x, about_mheight);
+ y += about_mheight;
+ }
+ }
+ x -= about_bwidth; y += (about_pheight - about_bheight)/2;
+ okBut->SetSize(x/2, y, about_bwidth, about_bheight);
+}
+
+
+
+
+
+/*
+ * rviewStringSet window
+ */
+
+const int rviewStringSet::strset_width = 300;
+const int rviewStringSet::strset_height = 250;
+const int rviewStringSet::strset_border = 8;
+const int rviewStringSet::strset_reserve = 50;
+const int rviewStringSet::strset_bwidth = 70;
+const int rviewStringSet::strset_bheight = 40;
+const int rviewStringSet::strset_mheight = 20;
+
+rviewStringSet::rviewStringSet(collection_desc *desc) : rviewFrame(NULL, "", -1, -1, strset_width, strset_height)
+{
+ int w, h;
+ char buffer[STRINGSIZE];
+
+ panel = new wxPanel((wxWindow*)this, 0, 0, strset_width, strset_height);
+ list = new wxListBox(panel, (wxFunction)rviewEventHandler, "", wxSINGLE, 0, 0, strset_width, strset_height, desc->number, desc->strObjs, wxALWAYS_SB);
+ dismiss = new rviewButton(panel);
+
+ sprintf(buffer, "%s: %s", lman->lookup("textCollName"), (desc->collName == NULL) ? "" : desc->collName);
+ collName = new wxMessage(panel, buffer, 0, 0, 10, 10, 0, "message");
+ sprintf(buffer, "%s: %s", lman->lookup("textCollType"), (desc->collType == NULL) ? "" : desc->collType);
+ collType = new wxMessage(panel, buffer, 0, 0, 10, 10, 0, "message");
+ char* tmpChar1 = "message";
+ char* tmpChar2 = "";
+ collInfo = new wxMessage(panel, (desc->collInfo == NULL) ? tmpChar2 : desc->collInfo, 0, 0, 10, 10, 0, tmpChar1);
+
+ GetClientSize(&w, &h);
+
+ label();
+
+ OnSize(w, h);
+
+ Show(TRUE);
+}
+
+
+rviewStringSet::~rviewStringSet(void)
+{
+}
+
+
+const char *rviewStringSet::getFrameName(void) const
+{
+ return "rviewStringSet";
+}
+
+rviewFrameType rviewStringSet::getFrameType(void) const
+{
+ return rviewFrameTypeStrSet;
+}
+
+
+void rviewStringSet::label(void)
+{
+ SetTitle(lman->lookup("titleStringSet"));
+ list->SetLabel(lman->lookup("strSetList"));
+ dismiss->SetLabel(lman->lookup("textClose"));
+}
+
+
+void rviewStringSet::OnSize(int w, int h)
+{
+ int x, y;
+ int head;
+
+ GetClientSize(&x, &y);
+ panel->SetSize(0, 0, x, y);
+ head = 3*(strset_mheight + strset_border);
+ x -= 2*strset_border; y -= 2*strset_border;
+ collName->SetSize(strset_border, strset_border, x, strset_mheight);
+ collType->SetSize(strset_border, strset_mheight + 2*strset_border, x, strset_mheight);
+ collInfo->SetSize(strset_border, 2*strset_mheight + 3*strset_border, x, strset_mheight);
+
+ list->SetSize(strset_border, strset_border + head, x, y - head - strset_reserve);
+ dismiss->SetSize((x - strset_bwidth) / 2, y + 2*strset_border - (strset_reserve + strset_bheight) / 2, strset_bwidth, strset_bheight);
+}
+
+
+int rviewStringSet::process(wxObject &obj, wxEvent &evt)
+{
+ if (&obj == (wxObject*)dismiss)
+ {
+ this->Close(TRUE);
+ return 1;
+ }
+ return 0;
+}
+
+
+int rviewStringSet::getNumItems(void)
+{
+ return list->Number();
+}
+
+
+void rviewStringSet::addItem(const char *string)
+{
+ list->Append((char*)string);
+}
+
+
+char *rviewStringSet::getItem(int number)
+{
+ return list->GetString(number);
+}
+
+
+#ifdef EARLY_TEMPLATE
+#undef __EXECUTABLE__
+#endif
+
+#endif // !defined(EARLY_TEMPLATE) || !defined(__EXECUTABLE__)
+
+
+
+#if (!defined(EARLY_TEMPLATE) || defined(__EXECUTABLE__))
+
+/*
+ * Templates
+ */
+
+// For placement new (DynamicStack template)
+#include <new>
+
+/*
+ * Use malloc/free, placement new and explicit calls to destructors.
+ * Use placement new when initializing on the stack because that's
+ * raw memory, use assignment when initializing parameters
+ */
+template<class T>
+DynamicStack<T>::DynamicStack(unsigned int gran)
+{
+ number = 0; max = 0;
+ if ((stack = (T*)malloc(gran * sizeof(T))) != NULL)
+ {
+ granularity = gran;
+ max = granularity;
+ memset(stack, 0, max * sizeof(T));
+ }
+}
+
+
+template<class T>
+DynamicStack<T>::DynamicStack(const DynamicStack<T> &src)
+{
+ number = 0; max = 0;
+ if ((stack = (T*)malloc(src.max * sizeof(T))) != NULL)
+ {
+ granularity = src.granularity;
+ max = src.max;
+ memset(stack, 0, max*sizeof(T));
+ number = src.number;
+
+ unsigned int i;
+
+ // use loop for class safety
+ for (i=0; i<number; i++)
+ new(stack + i) T(src.stack[i]); // placement new
+ }
+}
+
+
+template<class T>
+DynamicStack<T>::~DynamicStack(void)
+{
+ unsigned int i;
+
+ for (i=0; i<number; i++)
+ stack[i].~T(); // direct destructor call
+
+ if (stack != NULL)
+ free(stack);
+}
+
+
+template<class T>
+int DynamicStack<T>::push(const T &item)
+{
+ if (ensureFree() != 0) return -1;
+ new(stack + number++) T(item); // placement new
+ return 0;
+}
+
+
+template<class T>
+int DynamicStack<T>::pop(T &item)
+{
+ if (number == 0) return -1;
+ item = stack[--number]; // assignment
+ stack[number].~T(); // direct destructor call
+ return 0;
+}
+
+
+template<class T>
+int DynamicStack<T>::peek(T &item) const
+{
+ if (number == 0) return -1;
+ item = stack[number-1]; // assignment
+ return 0;
+}
+
+
+template<class T>
+unsigned int DynamicStack<T>::getNumber(void) const
+{
+ return number;
+}
+
+
+template<class T>
+int DynamicStack<T>::ensureFree(void)
+{
+ if (number >= max)
+ {
+ if ((stack = (T*)realloc(stack, (max + granularity) * sizeof(T))) == NULL)
+ {
+ max = 0; number = 0; return -1;
+ }
+ memset(stack + max, 0, granularity * sizeof(T));
+ max += granularity;
+ }
+ return 0;
+}
+
+#endif
diff --git a/applications/rview/rviewUtils.hh b/applications/rview/rviewUtils.hh
new file mode 100644
index 0000000..32c292c
--- /dev/null
+++ b/applications/rview/rviewUtils.hh
@@ -0,0 +1,1045 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+* PURPOSE:
+*
+* Central definitions of shared objects and constants, global tool functions.
+*
+* - All menu codes used in the program (MENU_...)
+* - Global tool functions for handling collections, base types, projection
+* strings, X events, ... . See ``Global functions''.
+* - rviewFrame class which must be the base class of all frames used in rView.
+* - rviewFrameMgr class for handling all of rView's frames (dispatching events
+* etc)
+* - rviewMultiline class for displaying several lines of non-editable text.
+* - rviewDialog class which is the base class for all rView's dialog windows.
+* - rviewErrorbox class, derived from rviewDialog.
+* - rviewProgress class, derived from rviewDialog.
+* - rviewResults class for displaying database results and dispatching object
+* viewers. Relies on code provided by rviewMDD for scaling/resampling/endian
+* conversions.
+* - rviewAbout class for displaying information about rView itself.
+* - rviewStringSet class for displaying a set of strings in a scrollable
+* list box.
+*
+* COMMENTS:
+* none
+*/
+
+
+
+#ifndef _RVIEW_UTILS_H_
+#define _RVIEW_UTILS_H_
+
+
+#include <sstream>
+
+#include "rasodmg/ref.hh"
+#include "rasodmg/marray.hh"
+#include "rasodmg/gmarray.hh"
+#include "rasodmg/database.hh"
+
+#include "labelManager.hh"
+
+// #include "wx_scrol.h"
+#include "wx/xrc/xh_scrol.h"
+#include "wx/msgout.h"
+
+// #define wxUSE_GLCANVAS 1 // need this? -- PB 2006-jan-01
+#include <wx/glcanvas.h>
+
+
+#ifdef __VISUALC__
+#define DIR_SEPARATOR "\\"
+#define DIR_SEPARATORC '\\'
+#else
+#define DIR_SEPARATOR "/"
+#define DIR_SEPARATORC '/'
+#endif
+
+extern const int rview_window_extra_height;
+extern const int rview_choice_sub_width;
+
+
+
+#define STRINGSIZE 256
+
+
+
+// base type to name translations
+
+// Identifiers for base types
+enum rviewBaseType {
+ rbt_none,
+ rbt_bool,
+ rbt_char,
+ rbt_uchar,
+ rbt_short,
+ rbt_ushort,
+ rbt_long,
+ rbt_ulong,
+ rbt_rgb,
+ rbt_float,
+ rbt_double
+};
+
+// Maximum dimension of data rview can deal with
+#define MAXIMUM_DIMENSIONS 4
+
+// String names for objects / sets over the various basetypes.
+extern char *rviewBaseTypes[];
+extern char *rviewTypeNames[][MAXIMUM_DIMENSIONS];
+extern char *rviewSetNames[][MAXIMUM_DIMENSIONS];
+
+// Base type to image type mapping
+extern int rviewImageTypes[];
+// Possible types:
+enum rview_image_types {
+ RVIEW_IMGTYPE_NONE,
+ RVIEW_IMGTYPE_MONO,
+ RVIEW_IMGTYPE_GREY,
+ RVIEW_IMGTYPE_HIGH,
+ RVIEW_IMGTYPE_GREY12,
+ RVIEW_IMGTYPE_TRUE24,
+ RVIEW_IMGTYPE_TRUE32
+};
+
+
+
+// Mouse buttons
+#define MOUSE_LEFT 1
+#define MOUSE_MIDDLE 2
+#define MOUSE_RIGHT 4
+// Ctrl pressed while mouse event?
+#define MOUSE_CONTROL 8
+// Maximum distance of mouse pointer to an object for manipulating / dragging
+#define MOUSE_HOTZONE 8
+
+
+
+// Menu items
+
+enum rview_menu_ident {
+ MENU_DUMMY_IDENT, // 0 is illegal for a menu id
+
+ // First the ones for the main window
+ MENU_MAIN_FILE_QUERY,
+ MENU_MAIN_FILE_PREFS,
+ MENU_MAIN_FILE_EXIT,
+
+ MENU_MAIN_VIEW_OPEN,
+ MENU_MAIN_VIEW_CLOSE,
+
+ MENU_MAIN_COLL_LOOK,
+ MENU_MAIN_COLL_LKSCL,
+ MENU_MAIN_COLL_LKORTH,
+ MENU_MAIN_COLL_CREATE,
+ MENU_MAIN_COLL_DELETE,
+
+ MENU_MAIN_HELP_ABOUT,
+
+ // Now the menu items for the results window
+ MENU_RSLT_ITEM_OPENALL,
+ MENU_RSLT_ITEM_THUMBALL,
+ MENU_RSLT_ITEM_CLOSE,
+
+ MENU_RSLT_SLCT_SLCTALL,
+ MENU_RSLT_SLCT_CLEAR,
+ MENU_RSLT_SLCT_OPEN,
+ MENU_RSLT_SLCT_THUMB,
+ MENU_RSLT_SLCT_DELETE,
+ MENU_RSLT_SLCT_ENDIAN,
+ MENU_RSLT_SLCT_TYPEMAN,
+ MENU_RSLT_SLCT_INFO,
+
+ // Now the menu items for the display windows
+ MENU_DISP_DATA_INSERT,
+ MENU_DISP_DATA_INSERTPRO,
+ MENU_DISP_DATA_SAVE,
+ MENU_DISP_DATA_CLOSE,
+ MENU_DISP_DATA_SAVETIFF,
+ MENU_DISP_VIEW_SAVE,
+ MENU_DISP_VIEW_LOAD,
+ MENU_DISP_VIEW_SHOW,
+ // Additional menus in charts
+ MENU_CHART_MODE_BAR,
+ MENU_CHART_MODE_LINE,
+ MENU_CHART_MODE_SPLINE,
+ // Additional menus in images
+ MENU_IMAGE_MODE_FLAT,
+ MENU_IMAGE_MODE_SURF,
+ MENU_IMAGE_MODE_VOXEL,
+ MENU_IMAGE_MODE_HEIGHT,
+ MENU_IMAGE_SETUP_RENDER,
+ MENU_IMAGE_SETUP_RCONTROL,
+ MENU_IMAGE_SETUP_CSPACE,
+ MENU_IMAGE_SETUP_MOVIE,
+ MENU_IMAGE_MOVIE_ONCE,
+ MENU_IMAGE_MOVIE_START,
+ MENU_IMAGE_MOVIE_SWITCH,
+ MENU_IMAGE_CSPACE_ON,
+ MENU_IMAGE_CSPACE_FULL,
+ MENU_IMAGE_CSPACE_PROJ,
+ MENU_IMAGE_CSPACE_EDIT,
+ // Additional menus in tables
+ MENU_TABLE_MODE_DECIMAL,
+ MENU_TABLE_MODE_OCTAL,
+ MENU_TABLE_MODE_HEX,
+
+ // Thumbnail window
+ MENU_THUMB_DATA_CLOSE,
+ MENU_THUMB_SETUP_CSPACE,
+ MENU_THUMB_CSPACE_ON,
+ MENU_THUMB_CSPACE_FULL,
+ MENU_THUMB_CSPACE_EDIT,
+
+ // Now the menu items for the query window
+ MENU_QUERY_FILE_OPEN,
+ MENU_QUERY_FILE_SAVE,
+ MENU_QUERY_FILE_EXIT,
+ MENU_QUERY_EDIT_CUT,
+ MENU_QUERY_EDIT_COPY,
+ MENU_QUERY_EDIT_PASTE,
+ MENU_QUERY_HELP_HELP,
+
+ // Total number of menus = first free menu ID for dynamic menus:
+ MENU_TOTAL_NUMBER
+};
+
+// Hotlist menu has no fixed length. Set upper limit with MENU_QUERY_HOTRANGE, however
+#define MENU_QUERY_HOTLIST MENU_TOTAL_NUMBER
+// upper limit for queries in hotlist
+#define MENU_QUERY_HOTRANGE 64
+
+
+
+// Number of display modes
+#define RVIEW_RESDISP_NUMBER 8
+// Flags for each MDD object saying whether it's opened in a display mode
+#define RVIEW_RESDISP_CHART 1
+#define RVIEW_RESDISP_TABLE 2
+#define RVIEW_RESDISP_SOUND 4
+#define RVIEW_RESDISP_IMGFLAT 8
+#define RVIEW_RESDISP_IMGVOLM 16
+#define RVIEW_RESDISP_IMGHGHT 32
+#define RVIEW_RESDISP_IMGOSECT 64
+#define RVIEW_RESDISP_STRVIEW 128
+// this one is special because it can't be used from the results window
+#define RVIEW_RESDISP_IMGSCLD 256
+
+
+
+
+
+// For frame_list type. Full declaration below.
+class rviewFrame;
+class rviewFrameMgr;
+
+
+
+
+/*
+ * Types and structures.
+ */
+
+// User events
+enum rviewUserEvent {
+ usr_none,
+ usr_child_closed, // data = rviewFrame *
+ usr_mdd_dying, // data = r_Ref<r_GMarray>*
+ usr_db_opened,
+ usr_db_closed,
+ usr_update_closed, // data = r_Ref<r_GMarray>*
+ usr_viewer_closed, // data = mdd_frame *
+ usr_cspace_changed, // data = colourspaceMapper*
+ usr_typeman_convert, // data = rviewTypeMan *
+ usr_close_viewers
+};
+
+
+// The frame list item used but the frameManager.
+typedef struct frame_list {
+ rviewFrame *frame;
+ frame_list *next;
+} frame_list;
+
+// An MDD object and some flags
+typedef struct mdd_frame {
+ r_Ref < r_GMarray > mdd;
+ unsigned int flags;
+} mdd_frame;
+
+// Collection descriptor (for lookup / query exection)
+// mddObjs != NULL ==> collection of marrays
+// strObjs != NULL ==> collection of strings
+typedef struct collection_desc {
+ char *collName;
+ char *collType;
+ char *collInfo;
+ int number;
+ mdd_frame *mddObjs;
+ char **strObjs;
+} collection_desc;
+
+// User event used in rviewFrames / frameManager
+typedef struct user_event {
+ rviewUserEvent type;
+ void *data;
+} user_event;
+
+// Keyword to identifier lookup structure
+typedef struct keyword_to_ident {
+ int ident;
+ char *keyword;
+} keyword_to_ident;
+
+// same with a const char *
+typedef struct keyword_to_ident_c {
+ int ident;
+ const char *keyword;
+} keyword_to_ident_c;
+
+
+
+
+/*
+ * Global functions
+ */
+
+// Free all memory allocated by a filled collection descriptor
+void rviewDeleteCollection(collection_desc *coll);
+
+// Generic event handler. Calls the frame manager:
+void rviewEventHandler(wxObject &obj, wxEvent &evt);
+
+// Parse a projection string and return its dimensionality
+extern int rviewParseProjection(const r_Minterval &interv, r_Point &pt1, r_Point &pt2, const char *projString, unsigned int *freeDims=NULL, r_Point *mapIndex=NULL);
+
+// Return an object's base type as integer identifier
+extern rviewBaseType rviewGetBasetype(r_Object *obj);
+
+// Prints the contents of a cell with a given RasDaMan base type into the buffer, returns number
+// of characters written.
+extern int rviewPrintTypedCell(const r_Type *baseType, char *buffer, char *data, int numberBase);
+
+// Quicksorts a char *[]
+extern void rviewQuicksortStrings(char *array[], int from, int to);
+
+// Init character lookup tables
+extern void rviewInitCharacterTables(void);
+
+// Look up a keyword in a sorted (!) keyword_to_ident array
+extern int rviewLookupKeyword(const char *key, const keyword_to_ident_c *kti, int tabsize, bool caseSensitive);
+
+// Checks if colourspace mapping is possible for a given base type
+// and sets up some variables if so.
+class colourspaceMapper;
+struct colourspace_params_s;
+extern int rviewCheckInitCspace(rviewBaseType baseType, colourspaceMapper **csmap, r_Ref<r_GMarray> &mddObj, bool fullRange=FALSE, r_Minterval *domain=NULL, int w=0, int *newPitch=NULL, int *newDepth=NULL, int *newPad=NULL, int *virtualPitch=NULL, const struct colourspace_params_s *cp=NULL);
+
+// Smart number conversions: also understand 0x prefix
+extern long asctol(const char *str);
+extern int asctoi(const char *str);
+extern double asctof(const char *str);
+extern long stringtol(const char *str, char **endptr=NULL);
+extern double stringtof(const char *str, char **endptr=NULL);
+
+
+
+
+// Dynamic string class
+class DynamicString
+{
+ public:
+
+ DynamicString(void);
+ DynamicString(const DynamicString &ds);
+ DynamicString(const char *str);
+ ~DynamicString(void);
+
+ DynamicString &first(const char *str, unsigned int num);
+ DynamicString &operator=(const DynamicString &ds);
+ DynamicString &operator=(const char *str);
+ bool operator==(const DynamicString &ds) const;
+ bool operator==(const char *str) const;
+
+ const char *ptr(void) const;
+ operator const char*(void) const;
+
+
+ private:
+
+ char *myString;
+
+ static const char emptyString[];
+};
+
+
+
+// A stack template class
+template<class T>
+class DynamicStack
+{
+ public:
+
+ DynamicStack(unsigned int gran=8);
+ DynamicStack(const DynamicStack<T> &src);
+ ~DynamicStack(void);
+
+ int push(const T &item);
+ int pop(T &item);
+ int peek(T &item) const;
+ unsigned int getNumber(void) const;
+
+
+ protected:
+
+ int ensureFree(void);
+
+ unsigned int number, max, granularity;
+ T *stack;
+};
+
+
+
+
+
+// Frame types
+enum rviewFrameType {
+ rviewFrameTypeGeneric,
+ rviewFrameTypeMain,
+ rviewFrameTypeQuery,
+ rviewFrameTypePrefs,
+ rviewFrameTypeAbout,
+ rviewFrameTypeDialog,
+ rviewFrameTypeErrorbox,
+ rviewFrameTypeProgress,
+ rviewFrameTypeStrSet,
+ rviewFrameTypeCspace,
+ rviewFrameTypeImgSet,
+ rviewFrameTypeRenCtrl,
+ rviewFrameTypeResult,
+ rviewFrameTypeThumb,
+ rviewFrameTypeDisplay,
+ rviewFrameTypeImage,
+ rviewFrameTypeFltBsImage,
+ rviewFrameTypeFlatImage,
+ rviewFrameTypeRndImage,
+ rviewFrameTypeVolImage,
+ rviewFrameTypeHghtImage,
+ rviewFrameTypeScaledImage,
+ rviewFrameTypeOSectionImage,
+ rviewFrameTypeChart,
+ rviewFrameTypeTable,
+ rviewFrameTypeSound,
+ rviewFrameTypeStringViewer,
+ rviewFrameTypeRenView,
+ rviewFrameTypeNumberOfTypes
+};
+
+
+/*
+ * The base class for all frames. This makes managing open frames
+ * in a uniform way possible. Include after wx.h !
+ */
+
+class rviewFrame: public wxFrame
+{
+ public:
+
+ rviewFrame(wxFrame *parent, char *title, int x, int y, int w, int h);
+ virtual ~rviewFrame(void);
+
+ // When the checkobj(...) method is called the frame checks whether
+ // it knows obj (e.g. it's a button contained in the frame) and claims
+ // the broadcast by returning a value != 0. This is used in frame manager
+ // broadcasts. You should not try to get involved with derived classes
+ // at this point.
+ int checkobj(wxObject &obj);
+
+ // When the label() method is called the derived frame class
+ // has to relabel all its widgets
+ virtual void label(void) = 0;
+
+ // The process() method is called for the object that claimed the
+ // checkobj() function. It has to process the event and return a value
+ // != 0 if it did anything, 0 if the event was ignored. The two
+ // functions are separated because the Frame manager broadcast call
+ // has to be re-entrant and we'll get huge problems if the frame
+ // list changes during the loop.
+ virtual int process(wxObject &obj, wxEvent &evt) = 0;
+
+ // The userEvent method is called to notify frames of events like
+ // the mdd object a frame displays being deleted.
+ virtual int userEvent(const user_event &ue);
+
+ // Called when the frame is to be killed. May be overloaded, but normally
+ // doesn't have to be.
+ virtual int requestQuit(int level);
+
+ // Called for mouse events of some logical child. Normally ignored.
+ virtual void childMouseEvent(wxWindow *child, wxMouseEvent &mevt);
+
+ // The setParent(parent) function makes this frame a (logical) child
+ // of parent. This will remove the frame from the parent's child frame
+ // list when it's deleted.
+ void setParent(rviewFrame *parent);
+ void registerChild(rviewFrame *child);
+ void deregisterChild(rviewFrame *child);
+
+ // Returns the name of this class
+ virtual const char *getFrameName(void) const;
+
+ // Returns the identifier of this frame
+ virtual rviewFrameType getFrameType(void) const;
+
+ // By default each frame is closed by returning TRUE from this wxWindows
+ // function. If you wish to override this behaviour for certain frames,
+ // override the frame's virtual function OnClose().
+ virtual bool OnClose(void);
+
+
+ protected:
+
+ // For keeping track of child frames
+ rviewFrameMgr *frames;
+ rviewFrame *parentFrame;
+ int frameWidth, frameHeight;
+
+
+
+ private:
+
+ // Used internally by the checkobj() member function.
+ int checkobj_rec(wxWindow *whence, wxObject &obj);
+};
+
+
+
+
+/*
+ * The frame manager. Provides central access to frames and
+ * offers functions like automatically re-labeling all existing
+ * frames. Each object of class rviewFrame registers itself here
+ * in the constructor and deregisters itself in the destructor.
+ */
+
+class rviewFrameMgr
+{
+ public:
+
+ rviewFrameMgr(void);
+ rviewFrameMgr(bool delChild);
+ ~rviewFrameMgr(void);
+
+ void registerFrame(rviewFrame *client);
+ void deregisterFrame(rviewFrame *client);
+ int numberOfFrames(void) const;
+ void setDeleteMode(bool delChild);
+
+ // The following functions cause the frame manager to iterate over
+ // all frames and call specific member functions. Some of these
+ // member functions (e.g. process) can stop the iteration by
+ // claiming the call.
+ void labelAll(void);
+ void broadcastEvent(wxObject &obj, wxEvent &evt);
+ int broadcastQuit(int level);
+ int broadcastUserEvent(const user_event &ue);
+
+
+ protected:
+
+ frame_list *frameList;
+ frame_list *tailList;
+ int listLength;
+ bool deleteChildren;
+};
+
+
+
+
+
+/*
+ * A continuous text displayed in multiple lines
+ */
+
+class rviewMultiline
+{
+ public:
+
+ rviewMultiline(wxPanel *Panel, int X, int Y, int H, int Lines);
+ rviewMultiline(wxPanel *Panel, const char *Message, int X, int Y, int W, int H, int Lines);
+ ~rviewMultiline(void);
+
+ // Returns the height used by the messages
+ int getMessageHeight(void) const;
+
+ void rebuild(const char *Message, int W);
+
+ // 10 * number of pixels used per character
+ static const int multiline_ppc10;
+
+
+ protected:
+
+ void setupVariables(wxPanel *Panel, int X, int Y, int H, int Lines);
+
+ wxPanel *parent;
+ wxMessageOutput **msg;
+ int lines;
+ int x, y, lHeight;
+};
+
+
+
+/*
+ * Convenient interface to standard widgets
+ */
+#include <wx/univ/textctrl.h>
+
+class rviewText : public wxTextCtrl
+{
+ public:
+
+ rviewText(wxPanel *parent, const char *value=NULL, char *label="", int x=-1, int y=-1, int w=-1, int h=-1);
+ rviewText(long style, wxPanel *parent, const char *value=NULL, char *label="", int x=-1, int y=-1, int w=-1, int h=-1);
+ rviewText(wxPanel *parent, const DynamicString &value, char *label="", int x=-1, int y=-1, int w=-1, int h=-1);
+ rviewText(wxPanel *parent, int value, char *label="", int x=-1, int y=-1, int w=-1, int h=-1);
+ rviewText(wxPanel *parent, long value, char *label="", int x=-1, int y=-1, int w=-1, int h=-1);
+ rviewText(wxPanel *parent, double value, bool sciForm=FALSE, char *label="", int x=-1, int y=-1, int w=-1, int h=-1);
+
+ void SetValue(char *value);
+ void SetValue(const char *value);
+ void SetValue(const DynamicString &value);
+ void SetValue(int value);
+ void SetValue(unsigned int value);
+ void SetValue(long value);
+ void SetValue(double value, bool sciFrom=FALSE);
+
+ char *GetValue(void);
+ void GetValue(DynamicString &value);
+ void GetValue(int &value);
+ void GetValue(long &value);
+ void GetValue(float &value);
+ void GetValue(double &value);
+};
+
+class rviewButton : public wxButton
+{
+ public:
+
+ rviewButton(wxPanel *parent, char *label="", int x=-1, int y=-1, int w=-1, int h=-1, long style=0);
+};
+
+// BUG IN wxCoice: NEVER CREATE A (wx|rview)Choice ITEM WITH AN EMPTY LABEL!
+class rviewChoice : public wxChoice
+{
+ public:
+
+ rviewChoice(wxPanel *parent, int n, char *choices[], char *label="X", int x=-1, int y=-1, int w=-1, int h=-1, long style=0);
+ // this is kind of a hack to fix wxWindows' lack of const
+ rviewChoice(wxPanel *parent, int n, const char *choices[], char *label="X", int x=-1, int y=-1, int w=-1, int h=-1, long style=0);
+};
+
+class rviewCheckBox : public wxCheckBox
+{
+ public:
+
+ rviewCheckBox(wxPanel *parent, char *label="", int x=-1, int y=-1, int w=-1, int h=-1);
+};
+
+class rviewRadioButton : public wxRadioButton
+{
+ public:
+
+ rviewRadioButton(wxPanel *parent, char *label="", bool value=FALSE, int x=-1, int y=-1, int w=-1, int h=-1);
+};
+
+class rviewScrollBar : public wxScrollBar
+{
+ public:
+
+ rviewScrollBar(wxPanel *parent, int x=-1, int y=-1, int w=-1, int h=-1, long style=wxHORIZONTAL);
+};
+
+class rviewSlider : public wxSlider
+{
+ public:
+
+ rviewSlider(wxPanel *parent, int value, int min_val, int max_val, int width, char *label="", int x=-1, int y=-1, long style=wxHORIZONTAL);
+};
+
+
+/*
+ * The original slider class didn't allow me to pass on arbitrary mouse events
+ * to the (logical) parent which was needed in the orthosection viewer for
+ * automatically loading the data on a button up event. This slider class fixes
+ * this problem and has the same functionality as the original one. Use it
+ * whenever arbitrary mouse events are important.
+ */
+
+class rviewSpecialSlider : public wxGLCanvas
+{
+ public:
+ rviewSpecialSlider(rviewFrame *logParent, wxPanel *parent, int val, int min, int max, int width=-1, const char *label=NULL);
+ ~rviewSpecialSlider(void);
+
+ int GetMax(void) const;
+ int GetMin(void) const;
+ int GetValue(void) const;
+ void SetRange(int min, int max);
+ void SetValue(int val);
+ bool PositionInWell(float posx, float posy);
+
+ virtual void SetLabel(const char *label);
+ virtual void OnPaint(void);
+ virtual void OnEvent(wxMouseEvent &mevt);
+
+
+ protected:
+ void getWellVert(int &y0, int &y1);
+ void getBarParams(float &posx, float &posy, float &height);
+ int calcNewValue(float posx, float posy, int &val, bool checky=FALSE);
+ void redrawCore(float x, float y, float bheight);
+ void getUpdateInterval(float oldx, float newx, float &clipx, float &clipw);
+ void updateWell(float oldx, float newx, float posy, float bheight);
+ wxColour background;
+ wxColour foreground;
+ wxColour wellground;
+ wxColour outline;
+ wxColour labelColour;
+ wxBrush bback;
+ wxBrush bfore;
+ wxBrush bwell;
+ wxPen outlinePen;
+ wxFont labelFont;
+ int border, barwidth, barheight;
+ int value, vmin, vmax;
+ int cwidth, cheight;
+ float textx, texty;
+ DynamicString myLabel;
+ rviewFrame *logicalParent;
+ static const int dflt_width;
+ static const int dflt_height;
+ static const int dflt_border;
+ static const int dflt_barwidth;
+ static const int dflt_barheight;
+};
+
+
+
+
+/*
+ * Dialog box, containing a message and some buttons.
+ */
+class rviewDialog: public rviewFrame
+{
+ public:
+
+ rviewDialog(const char *title, const char *message, int buttonNo, const char *buttons[]);
+ virtual ~rviewDialog(void);
+ void OnSize(int w, int h);
+
+ int GetButton(void);
+
+ // implementations of the rviewFrame virtual functions
+ void label(void);
+ int process(wxObject &obj, wxEvent &evt);
+
+ virtual const char *getFrameName(void) const;
+ virtual rviewFrameType getFrameType(void) const;
+
+ // constants
+ // Width and height of the dialog box
+ static const int dialog_width;
+ static const int dialog_height;
+ // Borders used in the dialog box
+ static const int dialog_border;
+ // Width and height of the buttons
+ static const int dialog_buttonsx;
+ static const int dialog_buttonsy;
+ // Height reserved at the bottom for the buttons
+ static const int dialog_bheight;
+ // Number of text lines
+ static const int dialog_lines;
+ // Height of each of these lines
+ static const int dialog_lheight;
+
+
+ protected:
+
+ wxPanel *panel;
+ char **buttonText;
+ //wxTextWindow *msg;
+ rviewMultiline *msg;
+ rviewButton **but;
+ int buttonNumber;
+ int buttonPressed;
+};
+
+
+
+/*
+ * An error box.
+ */
+
+class rviewErrorbox: public rviewDialog
+{
+ public:
+
+ // Default error-box: a message and an OK button.
+ rviewErrorbox(const char *message);
+ rviewErrorbox(const char *title, const char *message, int buttonNo, const char *buttons[]);
+ ~rviewErrorbox(void);
+ int activate(void);
+
+ virtual const char *getFrameName(void) const;
+ virtual rviewFrameType getFrameType(void) const;
+
+ // creating errorboxes with formatted text
+ static rviewErrorbox *newErrorbox(const char *message, const char *classname=NULL, const char *funcname=NULL);
+ static rviewErrorbox *newErrorbox(const char *title, const char *message, int buttonNo, const char *buttons[], const char *classname=NULL, const char *funcname=NULL);
+ static int reportError(const char *message, const char *classname=NULL, const char *funcname=NULL);
+ static int reportError(const char *title, const char *message, int buttonNo, const char *buttons[], const char *classname=NULL, const char *funcname=NULL);
+
+ private:
+
+ static char *buildErrorMessage(const char *message, const char *classname, const char *funcname);
+};
+
+
+
+/*
+ * Progress reports
+ */
+
+class rviewProgress: public rviewDialog
+{
+ public:
+
+ // Progress reporter (mostly used by database)
+ rviewProgress(const char *message);
+ ~rviewProgress(void);
+
+ int process(wxObject &obj, wxEvent &evt);
+
+ virtual const char *getFrameName(void) const;
+ virtual rviewFrameType getFrameType(void) const;
+};
+
+
+
+/*
+ * Window holding MDD results
+ */
+
+class rviewTypeMan;
+
+class rviewResult: public rviewFrame
+{
+ public:
+
+ rviewResult(void);
+ rviewResult(collection_desc *collection);
+ ~rviewResult(void);
+ void setCollection(collection_desc *collection);
+
+ void label(void);
+ int process(wxObject &obj, wxEvent &evt);
+ int userEvent(const user_event &ue);
+
+ void OnSize(int w, int h);
+ void OnMenuCommand(int id);
+
+ virtual const char *getFrameName(void) const;
+ virtual rviewFrameType getFrameType(void) const;
+
+ // constants
+ // X and Y position of result box
+ static const int result_x;
+ static const int result_y;
+ // Width and height of result box
+ static const int result_width;
+ static const int result_height;
+ // Borders used in results box
+ static const int result_border;
+ // Height of a line (collection info)
+ static const int result_lheight;
+ // Space reserved for header (collection info)
+ static const int result_header;
+ // Width of choice item
+ static const int result_cwidth;
+ // Width and height of resample group
+ static const int result_twidth;
+ static const int result_theight;
+ // Width and height of button
+ static const int result_bwidth;
+ static const int result_bheight;
+
+
+ protected:
+
+ void setupVariables(void);
+ void openViewer(int item);
+ int updateSelection(void);
+ void configureGrey(void);
+ int parseResampleString(const char *resStr, double *values);
+ int resampleSelection(void);
+ char *mddDescriptorString(std::ostream &memstr, int number);
+ void convertSelectedItems(void);
+ // for printing information on time-consuming operations like scaling.
+ void operationPrologue(void);
+ void operationEpilogue(const char *opname);
+
+ collection_desc *coll;
+
+ char *selectedItems; // bitfield
+ int lastSelected;
+ int cbfactor; // number of units a checkbox is bigger than the size set
+
+ wxGroupBox *group;
+ wxMessage *collName, *collType, *collInfo;
+ rviewChoice *choice;
+ wxPanel *panel;
+ wxListBox *list;
+ wxMenuBar *mBar;
+ rviewText *resampText;
+ rviewChoice *scaleMode;
+ rviewButton *resampBut;
+
+ rviewTypeMan *typeManager;
+};
+
+
+
+
+/*
+ * About rView window
+ */
+class rviewAbout: public rviewFrame
+{
+ public:
+
+ rviewAbout(void);
+ ~rviewAbout(void);
+
+ void label(void);
+ int process(wxObject &obj, wxEvent &evt);
+
+ void OnSize(int w, int h);
+
+ virtual const char *getFrameName(void) const;
+ virtual rviewFrameType getFrameType(void) const;
+
+ // constants
+ // Width and height of About window
+ static const int about_width;
+ static const int about_height;
+ // Borders in About window
+ static const int about_border;
+ // Height of panel
+ static const int about_pheight;
+ // Width and height of buttons in About window
+ static const int about_bwidth;
+ static const int about_bheight;
+ // Height of message item
+ static const int about_mheight;
+
+
+ protected:
+
+ void deleteLabels(void);
+
+ wxPanel *panel;
+ rviewButton *okBut;
+ wxMessage **labels;
+ int numlines;
+};
+
+
+
+/*
+ * rviewStringSet window
+ */
+class rviewStringSet: public rviewFrame
+{
+ public:
+
+ rviewStringSet(collection_desc *desc);
+ ~rviewStringSet(void);
+
+ void label(void);
+ int process(wxObject &obj, wxEvent &evt);
+ void OnSize(int w, int h);
+
+ int getNumItems(void);
+ void addItem(const char *string);
+ char *getItem(int number);
+
+ virtual const char *getFrameName(void) const;
+ virtual rviewFrameType getFrameType(void) const;
+
+ // constants
+ // Width and height of the string set window
+ static const int strset_width;
+ static const int strset_height;
+ // Borders in string set window
+ static const int strset_border;
+ // Reserve space at the bottom for the dismiss button
+ static const int strset_reserve;
+ // Width and height of the dismiss button
+ static const int strset_bwidth;
+ static const int strset_bheight;
+ // Height of message fields
+ static const int strset_mheight;
+
+
+ protected:
+
+ wxPanel *panel;
+ wxListBox *list;
+ rviewButton *dismiss;
+ wxMessage *collName, *collType, *collInfo;
+};
+
+
+
+
+
+
+
+/*
+ * Global variables
+ */
+
+extern labelManager *lman;
+extern rviewFrameMgr *frameManager;
+extern unsigned char lowerCaseTable[256];
+
+
+#if (defined(EARLY_TEMPLATE) && defined(__EXECUTABLE__))
+#include "rviewUtils.cpp"
+#endif
+
+#endif
diff --git a/applications/rview/wx_pixmap.cpp b/applications/rview/wx_pixmap.cpp
new file mode 100644
index 0000000..cdb554c
--- /dev/null
+++ b/applications/rview/wx_pixmap.cpp
@@ -0,0 +1,1706 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+ * PURPOSE:
+ * Efficient bitmaps of colour depths 1, 2, 4, 8, 16, 24 and 32bpp
+ *
+ * COMMENTS:
+ * None
+ */
+
+
+#ifdef __GNUG__
+#pragma implementation
+#pragma implementation "wx_pixmap.h"
+#pragma implementation "wx_pixmap_dither.h"
+#endif
+
+
+#include <stdlib.h>
+#include <iostream>
+#include <iomanip>
+
+// changed in wxWindows 2.4.2:
+//#include "wx_prec.h"
+#include <wx/wxprec.h>
+#include <wx/defs.h>
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+#ifndef WX_PRECOM
+#include <wx/wx.h>
+#include <wx/utils.h>
+#include "wx_pixmap.h"
+#include "wx_pixmap_translate.h"
+#endif
+
+#ifdef wx_msw
+#include <malloc.h>
+#endif
+
+#ifdef wx_x
+#include <X11/Xlib.h>
+#endif
+
+
+
+
+
+
+/*
+ * Globals
+ */
+
+unsigned char *TrueTransTab = NULL;
+int TrueTransCount = 0;
+unsigned char *FastDitherTab = NULL;
+int FastDitherCount = 0;
+
+#ifdef wx_x
+typedef struct wxVisualType {
+ int depth, vclass;
+} wxVisualType;
+
+static wxVisualType wxVisualTypes[] = {
+ {32, TrueColor},
+ {24, TrueColor},
+ {16, TrueColor},
+ {15, TrueColor},
+ {8, PseudoColor},
+ {8, GrayScale},
+ {-1, 0}
+ };
+#endif
+
+
+/* Order of RGB components in true-colour modes */
+#define RGB_ORDER_NONE 0
+#define RGB_ORDER_RGB 1
+#define RGB_ORDER_BGR 2
+
+
+
+
+
+/*
+ * Determine the colour component with the biggest weight for sorting and
+ * colour-lookup.
+ */
+
+#if (COLOUR_WEIGHT_RED > COLOUR_WEIGHT_GREEN)
+#error here
+#define AUX1_COMPONENT green
+#define COLOUR_WEIGHT_AUX1 COLOUR_WEIGHT_GREEN
+#if (COLOUR_WEIGHT_RED > COLOUR_WEIGHT_BLUE)
+#define SORT_COMPONENT red
+#define AUX2_COMPONENT blue
+#define COLOUR_WEIGHT_MAX COLOUR_WEIGHT_RED
+#define COLOUR_WEIGHT_AUX1 COLOUR_WEIGHT_BLUE
+#else
+#define SORT_COMPONENT blue
+#define AUX2_COMPONENT red
+#define COLOUR_WEIGHT_MAX COLOUR_WEIGHT_BLUE
+#define COLOUR_WEIGHT_AUX2 COLOUR_WEIGHT_RED
+#endif
+#else
+#define AUX1_COMPONENT red
+#define COLOUR_WEIGHT_AUX1 COLOUR_WEIGHT_RED
+#if (COLOUR_WEIGHT_GREEN > COLOUR_WEIGHT_BLUE)
+#define SORT_COMPONENT green
+#define AUX2_COMPONENT blue
+#define COLOUR_WEIGHT_MAX COLOUR_WEIGHT_GREEN
+#define COLOUR_WEIGHT_AUX2 COLOUR_WEIGHT_BLUE
+#else
+#define SORT_COMPONENT blue
+#define AUX2_COMPONENT green
+#define COLOUR_WEIGHT_MAX COLOUR_WEIGHT_BLUE
+#define COLOUR_WEIGHT_AUX2 COLOUR_WEIGHT_GREEN
+#endif
+#endif
+
+#define SELECT_COMPONENT(x,c) x.c
+
+
+
+// General, platform independent members
+int wxPixmap::getWidth(void) {return(width);}
+
+int wxPixmap::getHeight(void) {return(height);}
+
+int wxPixmap::getDepth(void) {return(depth);}
+
+int wxPixmap::getPitch(void) {return(pitch);}
+
+char *wxPixmap::getData(void) {return(data);}
+
+wxColour *wxPixmap::getPalette(void) {return(palette);}
+
+// Returns the depth of the current mode
+int wxPixmap::getModeDepth(void) {return(displayDepth);}
+
+// Returns the pitch of the current mode
+int wxPixmap::getModePitch(void) {return(displayPitch);}
+
+// Returns a pointer to the mode-translated data or NULL if none.
+char *wxPixmap::getModeData(void) {return(modeData);}
+
+// Returns a pointer to the translation table or NULL if none exists.
+// The format depends on the display depth: <= 8 ==> 8bit, else 32bit
+unsigned char *wxPixmap::getTranslationTable(void)
+{
+ if ((depth > 12) && (displayDepth <= 8)) return TrueTransTab;
+ return TransTab.c;
+}
+
+
+// Error reporting / handling
+void wxPixmap::errorMemory(void)
+{
+#if (DEBUG > 0)
+ *errorstr << "Can't claim memory!" << endl;
+#endif
+}
+
+void wxPixmap::errorGeneric(char *message)
+{
+#if (DEBUG > 0)
+ *errorstr << message << endl;
+#endif
+}
+
+
+// Display can't change on X, but it can on other systems.
+// Returns depth of new mode. Internal variables holding mode information
+// will be overwritten after calling this function, so make sure you copy
+// them first if you need them.
+void wxPixmap::getDisplayAttributes(void)
+{
+#ifdef wx_x
+ int i;
+
+#if 0
+ for (i=0; wxVisualTypes[i].depth >= 0; i++)
+ {
+ if (XMatchVisualInfo(display, screen, wxVisualTypes[i].depth, wxVisualTypes[i].vclass, &visualInfo)) break;
+ }
+#else
+ displayDepth = wxDisplayDepth();
+ for (i=0; wxVisualTypes[i].depth >= 0; i++)
+ {
+ if (wxVisualTypes[i].depth == displayDepth)
+ {
+ if (XMatchVisualInfo(display, screen, wxVisualTypes[i].depth, wxVisualTypes[i].vclass, &visualInfo)) break;
+ }
+ }
+#endif
+ if (wxVisualTypes[i].depth < 0)
+ {
+ errorGeneric("Can't get appropriate X visual");
+ displayDepth = -1;
+ }
+
+ // On X we have to find the bpp manually
+ int j;
+ XPixmapFormatValues *pixvals = XListPixmapFormats(display, &i);
+ for (j=0; j<i; j++)
+ {
+ if (pixvals[j].depth == visualInfo.depth)
+ {
+ // Any match: set displayDepth
+ displayDepth = pixvals[j].bits_per_pixel;
+ // Exact match: stop.
+ if (pixvals[j].bits_per_pixel == pixvals[j].depth) break;
+ }
+ }
+ // Don't forget to free this structure!
+ XFree(pixvals);
+
+ // cout << "Use depth " << displayDepth << endl;
+
+ rgbOrder = RGB_ORDER_RGB;
+ if (displayDepth > 8)
+ {
+ if ((visualInfo.red_mask < visualInfo.green_mask) && (visualInfo.green_mask < visualInfo.blue_mask))
+ rgbOrder = RGB_ORDER_RGB;
+ else if ((visualInfo.red_mask > visualInfo.green_mask) && (visualInfo.green_mask > visualInfo.blue_mask))
+ rgbOrder = RGB_ORDER_BGR;
+#if (DEBUG > 0)
+ else
+ *errorstr << "Unrecognized pixel format, assuming r,g,b" << endl;
+#endif
+ }
+
+ if (BitmapBitOrder(display) == LSBFirst) destBitorder = 0; else destBitorder = 1;
+ if (ImageByteOrder(display) == LSBFirst) destByteorder = 0; else destByteorder = 1;
+ //cout << "destBit " << destBitorder << ", destByte " << destByteorder << endl;
+#endif
+
+#ifdef wx_msw
+ int bpp, planes, pfi;
+ PIXELFORMATDESCRIPTOR pfd;
+
+ desktop = GetDesktopWindow();
+ rootDC = GetDC(desktop);
+ bpp = GetDeviceCaps(rootDC, BITSPIXEL);
+ planes = GetDeviceCaps(rootDC, PLANES);
+ displayDepth = bpp * planes;
+ pfi = 1;//GetPixelFormat(rootDC);
+ if (pfi != 0)
+ {
+ if (DescribePixelFormat(rootDC, pfi, sizeof(PIXELFORMATDESCRIPTOR), &pfd) != 0)
+ {
+ displayDepth = (int)pfd.cRedBits + (int)pfd.cGreenBits + (int)pfd.cBlueBits;
+ rgbOrder = RGB_ORDER_BGR;
+ if (displayDepth > 8)
+ {
+ if ((pfd.cRedShift < pfd.cGreenShift) && (pfd.cGreenShift < pfd.cBlueShift))
+ rgbOrder = RGB_ORDER_RGB;
+ else if ((pfd.cRedShift > pfd.cGreenShift) && (pfd.cGreenShift > pfd.cBlueShift))
+ rgbOrder = RGB_ORDER_BGR;
+#if (DEBUG > 0)
+ else
+ *errorstr << "Unrecognized pixel format, assuming b,g,r" << endl;
+#endif
+ }
+#if (DEBUG > 0)
+ else
+ *errorstr << "Error describing pixel format (" << GetLastError() << ")" << endl;
+#endif
+ }
+ }
+#if (DEBUG > 0)
+ else
+ *errorstr << "Error reading pixel format (" << GetLastError() << ")" << endl;
+#endif
+
+ // On NT use the machine order
+ destBitorder = WX_PIXMAP_SRC_BITORDER; destByteorder = WX_PIXMAP_SRC_BYTEORDER;
+#endif
+
+ // Filter out unsupported display depths
+ switch (displayDepth)
+ {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ case 15:
+ case 16:
+ case 24:
+ case 32: break;
+ default:
+#if (DEBUG > 0)
+ *errorstr << "Unsupported display depth " << displayDepth << endl;
+#endif
+ displayDepth = -1; return;
+ }
+
+#if (DEBUG > 0)
+ *errorstr << "Display depth = " << displayDepth
+ << ", rgb format " << ((rgbOrder == RGB_ORDER_RGB) ? "r,g,b" : "b,g,r") << endl;
+#endif
+}
+
+
+void wxPixmap::initColoursForMode(bool forceUpdate)
+{
+#ifdef wx_pixmap_alloc_cols
+ // Clear colour allocation bitfield
+ memset(ColourAlloc, 0, 32);
+#else
+ processParentPalette(forceUpdate);
+#endif
+ setupTranslators();
+}
+
+
+// Stuff shared by all constructors.
+void wxPixmap::initVariables(void)
+{
+ data = NULL; modeData = NULL; palette = NULL; TransTab.c = NULL; validDisplay = FALSE; busyCursorMode = TRUE;
+ parentWin = NULL; errorstr = NULL;
+#ifndef wx_pixmap_alloc_cols
+ parentPalette = NULL; pixmapPalette = NULL; parentPaletteDepth = 0;
+#endif
+ width=0; height=0; depth=0; pad=0;
+
+#if (DEBUG > 0)
+#ifdef wx_x
+ // For some reason the other variant crashes on Sun
+ errorstr = (ostream*)&cerr;
+#else
+#ifdef wx_msw
+ errorstr = new ofstream("debug.log",ios::out | ios::trunc);
+#else
+ errorstr = new ostream(&streamBuf);
+#endif
+#endif
+#endif
+
+#ifdef wx_x
+ xim = NULL;
+ display = wxGetDisplay();
+ myGC = (GC)0;
+
+ screen = XDefaultScreen(display);
+ rootwin = XRootWindow(display, screen);
+
+ //Screen *myScreen = DefaultScreenOfDisplay(display);
+ //cout << "root depth " << myScreen->root_depth << endl;
+
+#endif
+
+#ifdef wx_msw
+ bitmap = (HBITMAP)0;
+ windowHandle = (HWND)0;
+ rootDC = (HDC)0; srcDC = (HDC)0; winDC = (HDC)0; oldDCObject = (HGDIOBJ)0;
+#endif
+
+ getDisplayAttributes();
+}
+
+
+// New Depth and Flags are passed to this function to allow optimising colour handling.
+void wxPixmap::freeResources(int Depth, unsigned int Flags)
+{
+#ifdef wx_msw
+ if (bitmap != (HBITMAP)0)
+ {
+ DeleteObject(bitmap); bitmap = (HBITMAP)0;
+ }
+ if (modeData != data)
+ {
+ free(modeData); modeData = NULL;
+ }
+ // For symmetry to X
+ if (data != NULL)
+ {
+ free(data); data = NULL;
+ }
+ if (srcDC != (HDC)0)
+ {
+ SelectObject(srcDC, oldDCObject); DeleteObject(srcDC); srcDC = (HDC)0;
+ }
+#endif
+
+#ifdef wx_x
+ if ((modeData != NULL) && (modeData != data))
+ {
+ // In this case the XImage structure was initialised with modeData
+ // rather than data. Therefore on deleting xim modeData will be
+ // deleted automatically. Use malloc/free combination rather than
+ // new/delete.
+ free(data); data = NULL;
+ }
+
+ // Free image if any. This also destroys the data it was initialised with
+ // (see above).
+ if (xim != NULL)
+ {
+ XDestroyImage(xim); xim = NULL;
+ }
+
+ // The graphical context can change every time newPixmap is called, therefore
+ // it must be deleted here and not in the destructor.
+ if (myGC != (GC)0)
+ {
+ XFreeGC(display, myGC); myGC = (GC)0;
+ }
+
+ // If the new palette is the same as the old one we leave the colours as they are.
+ // Note that calling with no colour translation but with samepalette doesn't
+ // free anthing - that's because the Translation table has to be present even
+ // if no _automatic_ translation takes place.
+#ifdef wx_pixmap_alloc_cols
+ if ((Flags & WX_PIXFLAG_SAMEPALETTE) == 0)
+ {
+ // Free colours if any were allocated (i.e. displayDepth <= 8)
+ if ((displayDepth <= 8) && (TransTab.c != NULL))
+ {
+ unsigned long pixels[256];
+ int i, j;
+
+ for (i=0, j=0; i<(1<<displayDepth); i++)
+ {
+ if ((ColourAlloc[i>>3] & (1 << (i & 7))) != 0)
+ {
+ pixels[j++] = i;
+ }
+ }
+ XFreeColors(display, xat.colormap, pixels, j, 0);
+ // *errorstr << j << " colours freed." << endl;
+ }
+ }
+#endif
+#endif // #ifdef wx_x
+
+ // This is for all machines again
+ if ((Flags & WX_PIXFLAG_SAMEPALETTE) == 0)
+ {
+ // In case both depth > 8 (true-colour) and old depth > 8 we don't need to make a new
+ // colourtable, hence we don't have to delete the old one.
+ if ((depth <= 12) && (Depth <= 12) && (TransTab.c != NULL))
+ {
+ delete [] TransTab.c; TransTab.c = NULL;
+ }
+ }
+
+ // Update TrueColour Translation table
+ if ((depth > 12) && (displayDepth <= 8))
+ {
+ if (depth != Depth)
+ {
+ TrueTransCount--;
+#ifdef WX_PIXMAP_GLOBAL_VOLATILE
+ if (TrueTransCount == 0)
+ {
+ delete [] TrueTransTab; TrueTransTab = NULL;
+ }
+#endif
+ }
+ }
+ // Fast dithering table?
+ if ((pixFlags & WX_PIXFLAG_FASTDITHER) != 0)
+ {
+ FastDitherCount--;
+#ifdef WX_PIXMAP_GLOBAL_VOLATILE
+ if (FastDitherCount == 0)
+ {
+ delete [] FastDitherTab; FastDitherTab = NULL;
+ }
+#endif
+ }
+ if (palette != NULL)
+ {
+ delete [] palette; palette = NULL;
+ }
+}
+
+
+#ifndef wx_pixmap_alloc_cols
+
+void wxPixmap::processParentPalette(bool forceUpdate)
+{
+ if (displayDepth > 8)
+ {
+ if (parentPalette != NULL)
+ {
+ delete [] parentPalette; parentPalette=NULL; parentPaletteDepth = 0;
+ }
+ }
+ // For non-truecolour modes read the screen palette and install fast lookup functions
+ // Essentially forceUpdate should only be set to true if only the palette, not the
+ // more depth has changed.
+ else if ((parentPaletteDepth != displayDepth) || forceUpdate)
+ {
+ unsigned int i, ncols;
+ ncols = (1<<displayDepth);
+
+ // just in case...
+ if (parentPalette != NULL) {delete [] parentPalette; parentPalette = NULL; parentPaletteDepth = 0;}
+
+#ifdef wx_x
+ XColor displayColours[256];
+
+ // *errorstr << "Colours = " << ncols << endl;
+ for (i=0; i<ncols; i++) {displayColours[i].pixel = (unsigned long)i;}
+ XQueryColors(display, xat.colormap, displayColours, ncols);
+ if ((parentPalette = new wx_permute_cmap[ncols]) == NULL)
+ {
+ errorMemory(); return;
+ }
+ for (i=0; i<ncols; i++)
+ {
+ register wx_permute_cmap *pc = &(parentPalette[i]);
+ register XColor *xc = &(displayColours[i]);
+
+ pc->red = ((xc->red)>>8); pc->green = ((xc->green)>>8); pc->blue = ((xc->blue)>>8);
+ pc->number = i;
+ }
+#endif
+
+#ifdef wx_msw
+ PALETTEENTRY palEntries[256];
+
+ GetSystemPaletteEntries(rootDC, 0, ncols, palEntries);
+
+ if ((parentPalette = new wx_permute_cmap[ncols]) == NULL)
+ {
+ errorMemory(); return;
+ }
+ for (i=0; i<ncols; i++)
+ {
+ register wx_permute_cmap *pc = &(parentPalette[i]);
+ register PALETTEENTRY *pe = &(palEntries[i]);
+
+ pc->red = pe->peRed; pc->green = pe->peGreen; pc->blue = pe->peBlue;
+ pc->number = i;
+ }
+#endif
+
+ sortParentPalette(0, ncols-1);
+
+ buildInverseTable();
+
+ parentPaletteDepth = displayDepth;
+ }
+}
+
+
+// Returns a pointer to the parent palette. For use with findBestColour.
+wx_permute_cmap *wxPixmap::getParentPalette(void)
+{
+ return parentPalette;
+}
+
+
+
+#define PPAL_SWAP(a,b,h) h=parentPalette[a]; parentPalette[a]=parentPalette[b]; parentPalette[b]=h;
+
+// Quicksorter of parent palette, using the component with the biggest loading value
+void wxPixmap::sortParentPalette(int from, int to)
+{
+ while (from < to)
+ {
+ int mid, i, j;
+ wx_permute_cmap x, y;
+
+ mid = (from + to)/2; j = from;
+ PPAL_SWAP(mid, from, x); // Side-effect: element at first index (before swap) is in x.
+ for (i=from+1; i<=to; i++)
+ {
+ if (SELECT_COMPONENT(parentPalette[i],SORT_COMPONENT) < SELECT_COMPONENT(x,SORT_COMPONENT))
+ {
+ j++;
+ PPAL_SWAP(i,j,y);
+ }
+ }
+ PPAL_SWAP(from,j,y);
+
+ // Decide which branch to recurse into to minimise Stack consumption
+ if ((j - from) < (to - j))
+ {
+ sortParentPalette(from, j-1);
+ from = j+1;
+ }
+ else
+ {
+ sortParentPalette(j+1, to);
+ to = j-1;
+ }
+ }
+}
+
+
+// Builds an inverse lookup-table for the parent palette (after it was sorted).
+// inverseTable[x] specifies the index in parentPalette from where to search for
+// the colour with SORT_COMPONENT = x
+void wxPixmap::buildInverseTable(void)
+{
+ unsigned int i, j, idx, last, value;
+
+ i=0; last=0;
+ while (i < (unsigned int)(1<<displayDepth))
+ {
+ idx = i; value = SELECT_COMPONENT(parentPalette[idx],SORT_COMPONENT);
+ while (++i < (unsigned int)(1<<displayDepth))
+ {
+ if (SELECT_COMPONENT(parentPalette[i],SORT_COMPONENT) != value) break;
+ }
+ // *errorstr << '(' << idx << ',' << i << "):" << last << ',' << value << " ";
+ for (j=last; j<=value; j++)
+ {
+ parentInverse[j] = (i+idx-1)>>1;
+ }
+ last = value+1;
+ }
+ // fill remaining entries
+ while (last < 256) {parentInverse[last] = (1<<displayDepth)-1; last++;}
+
+ /*for (i=0; i<256; i++)
+ {
+ *errorstr << '[' << i << ':' << (int)parentInverse[i] << "] ";
+ }
+ *errorstr << endl;*/
+}
+
+
+#define square_val(x) ((x)*(x))
+
+// Returns the index into parentPalette which addresses the best fit for the RGB colour
+// passed to the function. Don't use for (display) modes with more than 8bpp.
+// This requires parentPalette and parentInverse to be set up correctly. This function
+// may only be used after parentPalette has been sorted and the inverse table has been
+// built.
+int wxPixmap::findBestColour(unsigned char red, unsigned char green, unsigned char blue)
+{
+ COLORREF bestMatch = 0x7fffffff, match;
+ int up, down, bestIdx=-1;
+
+ down = parentInverse[SORT_COMPONENT]; up = down+1;
+ while ((down >= 0) || (up < (1<<displayDepth)))
+ {
+ // Twice basically the same for up and down, but speed is _very_ critical here
+ if (down >= 0)
+ {
+ match = COLOUR_WEIGHT_MAX * square_val((int)SORT_COMPONENT - (int)SELECT_COMPONENT(parentPalette[down], SORT_COMPONENT));
+ if (match > bestMatch) down=-1;
+ else
+ {
+ match += COLOUR_WEIGHT_AUX1 * square_val((int)AUX1_COMPONENT - (int)SELECT_COMPONENT(parentPalette[down], AUX1_COMPONENT)) + COLOUR_WEIGHT_AUX2 * square_val((int)AUX2_COMPONENT - (int)SELECT_COMPONENT(parentPalette[down], AUX2_COMPONENT));
+ if (match < bestMatch) {bestMatch = match; bestIdx = down;}
+ down--;
+ }
+ }
+ if (up < (1<<displayDepth))
+ {
+ match = COLOUR_WEIGHT_MAX * square_val((int)SORT_COMPONENT - (int)SELECT_COMPONENT(parentPalette[up], SORT_COMPONENT));
+ if (match > bestMatch) up=(1<<displayDepth);
+ else
+ {
+ match += COLOUR_WEIGHT_AUX1 * square_val((int)AUX1_COMPONENT - (int)SELECT_COMPONENT(parentPalette[up], AUX1_COMPONENT)) + COLOUR_WEIGHT_AUX2 * square_val((int)AUX2_COMPONENT - (int)SELECT_COMPONENT(parentPalette[up], AUX2_COMPONENT));
+ if (match < bestMatch) {bestMatch = match; bestIdx = up;}
+ up++;
+ }
+ }
+ }
+ // *errorstr << "Best match for " << (int)red << ',' << (int)green << ',' << (int)blue << ": " << bestIdx << " (" << (int)parentPalette[bestIdx].red << ',' << (int)parentPalette[bestIdx].green << ',' << (int)parentPalette[bestIdx].blue << ')' << endl;
+
+ return bestIdx;
+}
+
+
+int wxPixmap::findFastColour(unsigned char red, unsigned char green, unsigned char blue)
+{
+ return (int)(FastDitherTab[(red>>3) | ((green & 0xf8)<<2) | ((blue&0xf8)<<7)]);
+}
+
+
+// Converts the pixmap's palette into a wx_permute_cmap which is needed by the ditherer.
+// Only call if depth <= 8! Other modes are assumed true-colour.
+void wxPixmap::processPixmapPalette(void)
+{
+ int i;
+ int tabsize;
+
+ if (depth <= 8) tabsize = (1<<depth); else tabsize = (1<<12);
+
+ if (pixmapPalette != NULL) {delete [] pixmapPalette; pixmapPalette=NULL;}
+
+ if ((pixmapPalette = new wx_permute_cmap[tabsize]) == NULL)
+ {
+ errorMemory(); return;
+ }
+ // Greyscale?
+ if (palette == NULL)
+ {
+ int step, grey;
+
+ step = 0xff00/(tabsize-1); grey = 0;
+ for (i=0; i<tabsize; i++)
+ {
+ pixmapPalette[i].red = pixmapPalette[i].green = pixmapPalette[i].blue = (grey >> 8);
+ grey += step;
+ }
+ }
+ else
+ {
+ unsigned char red, green, blue;
+
+ for (i=0; i<tabsize; i++)
+ {
+ // palette[i].Get(&red, &green, &blue); -- PB 2006-jan-01
+ red = palette[i].Red();
+ green = palette[i].Green();
+ blue = palette[i].Blue();
+ pixmapPalette[i].red = red; pixmapPalette[i].green = green; pixmapPalette[i].blue = blue;
+ }
+ }
+}
+
+
+#endif // wx_pixmap_alloc_cols
+
+
+
+// Builds the translation table for the current bitmap + palette / display setup.
+void wxPixmap::buildTranslationTable(void)
+{
+#ifndef wx_pixmap_alloc_cols
+ int bestIdx;
+#else
+#ifdef wx_x
+ char cstring[16]; // buffer for holding colour strings
+ XColor xcolour;
+ unsigned long pixel;
+#endif
+#endif
+
+ int i;
+ unsigned char red, green, blue;
+ bool BuildTrueTable = FALSE;
+
+ // *errorstr << "Build translation table" << endl;
+
+ // Essentially this function shouldn't be called with a valid translation table
+ // but to avoid memory leaks let's free an old table anyway.
+ if (TransTab.c != NULL) {delete [] TransTab.c; TransTab.c = NULL;}
+
+ TransTabSize = -1;
+ if (depth <= 8) TransTabSize = (1<<depth);
+ else if (depth == 12) TransTabSize = (1<<8);
+ else if (displayDepth <= 8) TransTabSize = (1<<15);
+
+ if (TransTabSize > 0)
+ {
+ if (TransTabSize > 256) // For a true colour mode?
+ {
+ if (TrueTransTab == NULL)
+ {
+ if ((TrueTransTab = new unsigned char[(1<<15)]) == NULL)
+ {
+ errorMemory(); return;
+ }
+ BuildTrueTable = TRUE;
+ }
+ TrueTransCount++;
+ }
+ if (TransTabSize <= 256);
+ {
+ // Base type of translation table depends on display depth
+ if (displayDepth <= 8) TransTab.c = new unsigned char[TransTabSize];
+ else TransTab.l = new COLORREF[TransTabSize];
+ if (TransTab.c == NULL)
+ {
+ errorMemory(); return;
+ }
+ }
+ // *errorstr << "Allocated Translation table of size " << TransTabSize << endl;
+ }
+
+ if (((pixFlags & WX_PIXFLAG_FASTDITHER) != 0) && (displayDepth <= 8))
+ {
+ if (FastDitherTab == NULL)
+ {
+ if ((FastDitherTab = new unsigned char[(1<<15)]) == NULL)
+ {
+ errorMemory(); return;
+ }
+ if (busyCursorMode) ::wxBeginBusyCursor();
+ for (i=0; i<0x8000; i++)
+ {
+ PALETTE_SHORT_TO_RGB(i, red, green, blue);
+ FastDitherTab[i] = findBestColour(red, green, blue);
+ }
+ if (busyCursorMode) ::wxEndBusyCursor();
+ }
+ FastDitherCount++;
+ }
+
+ // Palette indices --> pixel indices
+ if ((depth <= 12) && (displayDepth <= 8))
+ {
+ int tabsize;
+
+ if (depth <= 8) tabsize = (1<<depth); else tabsize = (1<<8);
+ for (i=0; i<tabsize; i++)
+ {
+ if (palette != NULL)
+ {
+ red = palette[i].Red();
+ green = palette[i].Green();
+ blue = palette[i].Blue();
+ }
+ else
+ {
+ // Assume greyscale
+ red = green = blue = i;
+ }
+#ifdef wx_pixmap_alloc_cols
+#ifdef wx_x
+ sprintf(cstring, "rgb:%x/%x/%x", red, green, blue);
+ XParseColor(display, xat.colormap, cstring, &xcolour);
+ if (XAllocColor(display, xat.colormap, &xcolour))
+ {
+ // ColourAlloc holds the display-, not the source colour numbers.
+ // Allocate each XColour only once! Haven't found an X-call that just
+ // returns the pixel value so I have to allocate and free it in case
+ // it was already allocated.
+ if ((ColourAlloc[(xcolour.pixel)>>3] & (1 << ((xcolour.pixel) & 7))) == 0)
+ {
+ ColourAlloc[(xcolour.pixel)>>3] |= (1 << ((xcolour.pixel) & 7));
+ }
+ else
+ {
+ pixel = xcolour.pixel;
+ XFreeColors(display, xat.colormap, &pixel, 1, 0);
+ }
+ }
+ TransTab.c[i] = (unsigned char)xcolour.pixel;
+ // *errorstr << i << " (" << cstring << "): " << xcolour.pixel << endl;
+#endif
+#ifdef wx_msw
+ TransTab.c[i] = (unsigned char)(GetNearestPaletteIndex(rootDC, red | (green<<8) | (blue<<16)));
+#endif
+#else
+ bestIdx = findBestColour(red, green, blue);
+ TransTab.c[i] = parentPalette[bestIdx].number;
+#endif
+ }
+ }
+ if ((depth > 8) && (displayDepth <= 8))
+ {
+ if (BuildTrueTable)
+ {
+ if (busyCursorMode) ::wxBeginBusyCursor();
+ // This is a bit heavy...
+ for (i=0; i<0x8000; i++)
+ {
+ // The internal format is always the same
+ PALETTE_SHORT_TO_RGB(i,red,green,blue);
+#ifdef wx_pixmap_alloc_cols
+#ifdef wx_x
+ sprintf(cstring, "rgb:%x/%x/%x", red, green, blue);
+ XParseColor(display, xat.colormap, cstring, &xcolour);
+ if (XAllocColor(display, xat.colormap, &xcolour))
+ {
+ if ((ColourAlloc[(xcolour.pixel)>>3] & (1 << ((xcolour.pixel) & 7))) == 0)
+ {
+ ColourAlloc[(xcolour.pixel)>>3] |= (1 << ((xcolour.pixel) & 7));
+ }
+ else
+ {
+ pixel = xcolour.pixel;
+ XFreeColors(display, xat.colormap, &pixel, 1, 0);
+ }
+ }
+ TrueTransTab[i] = (unsigned char)xcolour.pixel;
+#endif
+#ifdef wx_msw
+ TrueTransTab[i] = (unsigned char)(GetNearestPaletteIndex(rootDC, red | (green<<8) | (blue<<16)));
+#endif
+#else
+ bestIdx = (FastDitherTab == NULL) ? findBestColour(red, green, blue) : FastDitherTab[i];
+ TrueTransTab[i] = parentPalette[bestIdx].number;
+#endif
+ }
+ if (busyCursorMode) ::wxEndBusyCursor();
+ }
+ }
+
+ // Special translation tables which are platform independent (true-colour displays):
+ if ((depth <= 12) && (displayDepth > 8))
+ {
+ int tabsize;
+
+ if (depth <= 8) tabsize = (1<<depth); else tabsize = (1<<8);
+
+ // Data with <= 8bpp and no palette interpreted as greyscales.
+ if (palette == NULL)
+ {
+ int step, grey, value = 0;
+
+ step = 0xff00 / (tabsize -1); // stepping value in .8 fixpoint format
+ if (displayDepth == 15) // 15bpp
+ {
+ for (i=0; i<tabsize; i++, value += step)
+ {
+ grey = ((value + 0x400) >> 8); // convert fixpoint to integer, rounding.
+ if (grey > 255) grey = 255;
+
+ if (destByteorder == WX_PIXMAP_SRC_BYTEORDER)
+ TransTab.l[i] = _RGBL_TO_PALETTE_SHORT15(grey, grey, grey);
+ else
+ TransTab.l[i] = _RGBL_TO_PALETTE_SHORT15i(grey, grey, grey);
+ }
+ }
+ else if (displayDepth == 16) // 16bpp
+ {
+ for (i=0; i<tabsize; i++, value += step)
+ {
+ grey = ((value + 0x400) >> 8);
+ if (grey > 255) grey = 255;
+
+ if (destByteorder == WX_PIXMAP_SRC_BYTEORDER)
+ TransTab.l[i] = _RGBL_TO_PALETTE_SHORT16(grey, grey, grey);
+ else
+ TransTab.l[i] = _RGBL_TO_PALETTE_SHORT16i(grey, grey, grey);
+ }
+ }
+ else // 24/32bpp
+ {
+ for (i=0; i<tabsize; i++, value += step)
+ {
+ grey = (value + 0x80) >> 8;
+
+ if (destByteorder == WX_PIXMAP_SRC_BYTEORDER)
+ TransTab.l[i] = _RGB_TO_PALETTE_LONG(grey, grey, grey);
+ else
+ TransTab.l[i] = _RGB_TO_PALETTE_LONGi(grey, grey, grey);
+ }
+ }
+ }
+ else // palette != NULL ==> determine the true-colour values
+ {
+ if (displayDepth == 15)
+ {
+ for (i=0; i<tabsize; i++)
+ {
+ red = palette[i].Red();
+ green = palette[i].Green();
+ blue = palette[i].Blue();
+
+ if (destByteorder == WX_PIXMAP_SRC_BYTEORDER)
+ TransTab.l[i] = _RGBL_TO_PALETTE_SHORT15(red, green, blue);
+ else
+ TransTab.l[i] = _RGBL_TO_PALETTE_SHORT15i(red, green, blue);
+ }
+ }
+ else if (displayDepth == 16)
+ {
+ for (i=0; i<tabsize; i++)
+ {
+ red = palette[i].Red();
+ green = palette[i].Green();
+ blue = palette[i].Blue();
+
+ if (destByteorder == WX_PIXMAP_SRC_BYTEORDER)
+ TransTab.l[i] = _RGBL_TO_PALETTE_SHORT16(red, green, blue);
+ else
+ TransTab.l[i] = _RGBL_TO_PALETTE_SHORT16i(red, green, blue);
+ }
+ }
+ else
+ {
+ for (i=0; i<tabsize; i++)
+ {
+ red = palette[i].Red();
+ green = palette[i].Green();
+ blue = palette[i].Blue();
+
+ if (destByteorder == WX_PIXMAP_SRC_BYTEORDER)
+ TransTab.l[i] = _RGB_TO_PALETTE_LONG(red, green, blue);
+ else
+ TransTab.l[i] = _RGB_TO_PALETTE_LONGi(red, green, blue);
+ }
+ }
+ }
+ }
+
+#if (DEBUG > 0)
+ *errorstr << "Translation table (" << TransTabSize << "), table entry size ";
+ if (displayDepth <= 8) *errorstr << (int)8; else *errorstr << (int)32;
+ *errorstr << " bits." << endl;
+
+ *errorstr << hex;
+ if (displayDepth <= 8)
+ {
+ if (depth > 12)
+ {
+ for (i=0; i<TransTabSize; i++)
+ {
+ *errorstr << '[' << setw(2) << int(TrueTransTab[i]) << "] ";
+ if ((i & 7) == 7) {*errorstr << endl;}
+ }
+ }
+ else
+ {
+ for (i=0; i<TransTabSize; i++)
+ {
+ *errorstr << '[' << setw(2) << int(TransTab.c[i]) << "] ";
+ if ((i & 7) == 7) {*errorstr << endl;}
+ }
+ }
+ }
+ else
+ {
+ for (i=0; i<TransTabSize; i++)
+ {
+ *errorstr << '[' << setw(8) << TransTab.l[i] << "] ";
+ if ((i & 7) == 7) {*errorstr << endl;}
+ }
+ }
+ *errorstr << dec << endl;
+#endif
+}
+
+
+// To avoid repetitions...
+#define _TRANSLATORS_FALSE(target) \
+ pixtrans1 = &wx_pixmap_translate_1_to_##target; pixdither1 = &wxPixmap::dither_1_to_##target; \
+ pixtrans2 = &wx_pixmap_translate_2_to_##target; pixdither2 = &wxPixmap::dither_2_to_##target; \
+ pixtrans4 = &wx_pixmap_translate_4_to_##target; pixdither4 = &wxPixmap::dither_4_to_##target; \
+ pixtrans8 = &wx_pixmap_translate_8_to_##target; pixdither8 = &wxPixmap::dither_8_to_##target; \
+ pixtrans12 = &wx_pixmap_translate_12_to_##target; pixdither12 = &wxPixmap::dither_12_to_##target; \
+ pixtrans15 = &wx_pixmap_translate_15_to_##target; pixdither15 = &wxPixmap::dither_15_to_##target; \
+ pixtrans24 = &wx_pixmap_translate_24_to_##target; pixdither24 = &wxPixmap::dither_24_to_##target; \
+ pixtrans32 = &wx_pixmap_translate_32_to_##target; pixdither32 = &wxPixmap::dither_32_to_##target;
+
+#define _TRANSLATORS_TRUE(target,target2) \
+ pixtrans1 = wx_pixmap_translate_1_to_##target; \
+ pixtrans2 = wx_pixmap_translate_2_to_##target; \
+ pixtrans4 = wx_pixmap_translate_4_to_##target; \
+ pixtrans8 = wx_pixmap_translate_8_to_##target; \
+ pixtrans12 = wx_pixmap_translate_12_to_##target; \
+ pixtrans15 = wx_pixmap_translate_15_to_##target2; \
+ pixtrans24 = wx_pixmap_translate_24_to_##target2; \
+ pixtrans32 = wx_pixmap_translate_32_to_##target2;
+
+void wxPixmap::setupTranslators(void)
+{
+ // Init defaults...
+ pixtrans1 = NULL; pixtrans2 = NULL; pixtrans4 = NULL; pixtrans8 = NULL; pixtrans12 = NULL;
+ pixtrans15 = NULL; pixtrans24 = NULL; pixtrans32 = NULL;
+ pixdither1 = NULL; pixdither2 = NULL; pixdither4 = NULL; pixdither8 = NULL; pixdither12 = NULL;
+ pixdither15 = NULL; pixdither24 = NULL; pixdither32 = NULL;
+
+#ifdef wx_x
+ if ((destBitorder == WX_PIXMAP_SRC_BITORDER) && (destByteorder == WX_PIXMAP_SRC_BYTEORDER))
+#endif
+ {
+ switch (displayDepth)
+ {
+ case 1:
+ _TRANSLATORS_FALSE(1);
+ break;
+ case 2:
+ _TRANSLATORS_FALSE(2);
+ break;
+ case 4:
+ _TRANSLATORS_FALSE(4);
+ break;
+ case 8:
+ _TRANSLATORS_FALSE(8);
+ break;
+ case 15:
+ // For depths 1 to 12 the translators are identical.
+ if (rgbOrder == RGB_ORDER_RGB)
+ {
+ _TRANSLATORS_TRUE(16rgb, 15rgb);
+ }
+ else
+ {
+ _TRANSLATORS_TRUE(16bgr, 15bgr);
+ }
+ break;
+ case 16:
+ if (rgbOrder == RGB_ORDER_RGB)
+ {
+ _TRANSLATORS_TRUE(16rgb, 16rgb);
+ }
+ else
+ {
+ _TRANSLATORS_TRUE(16bgr, 16bgr);
+ }
+ break;
+ case 24:
+ if (rgbOrder == RGB_ORDER_RGB)
+ {
+ _TRANSLATORS_TRUE(24rgb, 24rgb);
+ }
+ else
+ {
+ _TRANSLATORS_TRUE(24bgr, 24bgr);
+ }
+ break;
+ case 32:
+ if (rgbOrder == RGB_ORDER_RGB)
+ {
+ _TRANSLATORS_TRUE(32rgb, 32rgb);
+ }
+ else
+ {
+ _TRANSLATORS_TRUE(32bgr, 32bgr);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+#ifdef wx_x
+ else
+ {
+ switch (displayDepth)
+ {
+ case 1:
+ _TRANSLATORS_FALSE(1i);
+ break;
+ case 2:
+ _TRANSLATORS_FALSE(2i);
+ break;
+ case 4:
+ _TRANSLATORS_FALSE(4i);
+ break;
+ case 8:
+ _TRANSLATORS_FALSE(8i);
+ break;
+ case 15:
+ // For depths 1 to 12 the translators are identical.
+ if (rgbOrder == RGB_ORDER_RGB)
+ {
+ _TRANSLATORS_TRUE(16irgb, 15irgb);
+ }
+ else
+ {
+ _TRANSLATORS_TRUE(16ibgr, 15ibgr);
+ }
+ break;
+ case 16:
+ if (rgbOrder == RGB_ORDER_RGB)
+ {
+ _TRANSLATORS_TRUE(16irgb, 16irgb);
+ }
+ else
+ {
+ _TRANSLATORS_TRUE(16ibgr, 16ibgr);
+ }
+ break;
+ case 24:
+ if (rgbOrder == RGB_ORDER_RGB)
+ {
+ _TRANSLATORS_TRUE(24irgb, 24irgb);
+ }
+ else
+ {
+ _TRANSLATORS_TRUE(24ibgr, 24ibgr);
+ }
+ break;
+ case 32:
+ if (rgbOrder == RGB_ORDER_RGB)
+ {
+ _TRANSLATORS_TRUE(32irgb, 32irgb);
+ }
+ else
+ {
+ _TRANSLATORS_TRUE(32ibgr, 32ibgr);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+#endif
+}
+
+
+
+// Must be called when the current mode changes. If the depth of new and old
+// screen mode is identical Flags determines whether a new Translation table
+// should be built (currently only this one bit used). This obviously never
+// gets called on X.
+void wxPixmap::modeChange(unsigned int modeFlags)
+{
+ int lastDisplayDepth = displayDepth;
+
+ getDisplayAttributes();
+
+ // depth hasn't changed or automatic translation not necessary ==> just build
+ // the tables.
+ if (((displayDepth == lastDisplayDepth) && ((modeFlags & WX_PIXMODE_PALETTE) != 0)) ||
+ ((pixFlags & WX_PIXFLAG_TRANSLATE) == 0))
+ {
+ initColoursForMode(TRUE);
+ buildTranslationTable();
+ }
+ else
+ {
+ // otherwise we need to set up completely new buffers and stuff.
+ if (TrueTransTab != NULL)
+ {
+ delete [] TrueTransTab; TrueTransTab = NULL; TrueTransCount = 0;
+ }
+ if (FastDitherTab != NULL)
+ {
+ delete [] FastDitherTab; FastDitherTab = NULL; FastDitherCount = 0;
+ }
+ newPixmap(parentWin, width, height, depth, pad, data, pixFlags | WX_PIXFLAG_SAMEPALETTE, palette);
+ }
+}
+
+
+wxPixmap::wxPixmap(void)
+{
+ initVariables();
+}
+
+
+wxPixmap::wxPixmap(wxWindow *Win, int Width, int Height, int Depth, int Pad, char *Data, unsigned int Flags, wxColour *Palette)
+{
+ initVariables();
+ newPixmap(Win, Width, Height, Depth, Pad, Data, Flags, Palette);
+}
+
+
+wxPixmap::~wxPixmap(void)
+{
+ if (errorstr != NULL)
+ {
+#ifndef wx_x
+#ifdef wx_msw
+ errorstr->flush();
+#endif
+ delete errorstr;
+#endif
+ }
+
+ // Use illegal value for depth to make sure everything is freed
+ freeResources(0, 0);
+
+#ifndef wx_pixmap_alloc_cols
+ if (parentPalette != NULL) {delete [] parentPalette; parentPalette = NULL;}
+ if (pixmapPalette != NULL) {delete [] pixmapPalette; pixmapPalette = NULL;}
+#endif
+}
+
+
+int wxPixmap::newPixmap(wxWindow *Win, int Width, int Height, int Depth, int Pad, char *Data, unsigned int Flags, wxColour *Palette)
+{
+ int lastDepth = depth;
+#ifdef wx_msw
+ int virtWidth;
+#endif
+
+ // Can we display it at all?
+ if (displayDepth <= 0) return -1;
+
+ // Filter out unsupported depths
+ switch (Depth)
+ {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ case 12:
+ case 15:
+ case 24:
+ case 32: break;
+ default:
+#if (DEBUG > 0)
+ *errorstr << "Unsupported colour depth " << Depth << endl;
+#endif
+ return -1;
+ }
+
+ freeResources(Depth, Flags);
+
+ width = Width; height = Height; depth = Depth; pad = Pad;
+ if ((depth == 12) || (depth == 15) || (depth == 16))
+ pitch = (width * 16 + Pad - 1) >> 3;
+ else
+ pitch = (width * depth + Pad - 1) >> 3;
+
+ switch (Pad)
+ {
+ case 16: pitch &= ~1; break;
+ case 32: pitch &= ~3; break;
+ case 64: pitch &= ~7; break;
+ case 128: pitch &= ~15; break;
+ case 256: pitch &= ~31; break;
+ default: break;
+ }
+ data = Data; validDisplay = FALSE; pixFlags = Flags; parentWin = Win;
+ if ((pixFlags & WX_PIXFLAG_FASTDITHER) != 0)
+ {
+ pixFlags |= WX_PIXFLAG_DITHER; colour_matcher = &wxPixmap::findFastColour;
+ }
+ else
+ {
+ colour_matcher = &wxPixmap::findBestColour;
+ }
+
+ // If the depth changed the translation tables _must_ be updated
+ if (lastDepth != Depth)
+ {
+ pixFlags &= ~WX_PIXFLAG_SAMEPALETTE;
+ }
+
+ if ((pixFlags & WX_PIXFLAG_SAMEPALETTE) == 0)
+ {
+ if ((Palette != NULL) && (Depth <= 8))
+ {
+ palette = new wxColour[1<<Depth];
+ memcpy(palette, Palette, (1<<Depth)*sizeof(wxColour));
+ }
+ }
+
+#ifndef wx_msw
+ // The data has to be translated if its depth differs from the display depth
+ // or the format is different from the internal one. A colour translation
+ // table is needed if translated data is needed AND either mode is <= 8bpp.
+ if (((depth == displayDepth) && (depth == 24) && (rgbOrder == RGB_ORDER_RGB)) ||
+ ((pixFlags & WX_PIXFLAG_TRANSLATE) == 0))
+ {
+ modeData = data; displayPitch = pitch; displayPad = Pad;
+ }
+ else
+#endif
+ {
+ displayPad = 32;
+ int useDepth;
+
+ if (displayDepth == 15)
+ useDepth = 16;
+ else
+ useDepth = displayDepth;
+
+#ifdef wx_x
+ displayPitch = ((width * useDepth + 31) >> 3) & ~3;
+ if ((modeData = (char*)malloc(displayPitch*height*sizeof(char))) == NULL)
+ {
+ errorMemory(); return(-1);
+ }
+#endif
+#ifdef wx_msw
+ virtWidth = width;
+
+ while (((displayPitch = virtWidth * useDepth) & 31) != 0) virtWidth++;
+ displayPitch >>= 3;
+ if ((modeData = (char*)malloc(displayPitch * height * sizeof(char))) == NULL)
+ {
+ errorMemory(); return -1;
+ }
+#endif
+ // *errorstr << "Allocated buffer of size " << width << '*' << height << ", " << displayPitch*height << endl;
+ }
+
+#ifdef wx_msw
+ bmDesc.bmType = 0;
+ bmDesc.bmWidth = virtWidth;
+ bmDesc.bmHeight = height;
+ bmDesc.bmWidthBytes = displayPitch;
+ bmDesc.bmPlanes = 1;
+ bmDesc.bmBitsPixel = displayDepth;
+ bmDesc.bmBits = (LPVOID)modeData;
+ bitmap = CreateBitmapIndirect(&bmDesc);
+ if (bitmap == (HBITMAP)0)
+ {
+ errorMemory(); return(-1);
+ }
+ // *errorstr << "bitmap handle = " << (long)bitmap << endl;
+#endif
+
+#ifdef wx_x
+ // *errorstr << "Get Handle... " << endl;
+ windowHandle = parentWin->GetXWindow();
+ // *errorstr << "windowHandle = " << windowHandle << endl;
+
+ // Use visualInfo.depth rather than displayDepth (24bpp vs 32bpp!)
+ xim = XCreateImage(display, visualInfo.visual, visualInfo.depth, ZPixmap, 0, modeData, width, height, displayPad, displayPitch);
+
+ // Get parent window attributes to get colourmap
+ XGetWindowAttributes(display, windowHandle, &xat);
+ //cout << "window depth " << xat.depth << endl;
+ xgcvals.function = GXcopy;
+ myGC = XCreateGC(display, windowHandle, GCFunction, &xgcvals);
+#endif
+
+#ifdef wx_msw
+ windowHandle = parentWin->GetHWND();
+ winDC = GetDC(windowHandle);
+ srcDC = CreateCompatibleDC(winDC);
+ //srcDC = CreateCompatibleDC(NULL);
+ oldDCObject = SelectObject(srcDC, (HGDIOBJ)bitmap);
+#endif
+
+ initColoursForMode();
+
+ // Now create the translation table if necessary (if depth, lastDepth > 8 we can use the
+ // previous one.
+ if (((depth != displayDepth) && (lastDepth <= 12)) || (depth <= 12))
+ {
+ if ((pixFlags & WX_PIXFLAG_SAMEPALETTE) == 0) {buildTranslationTable();}
+ }
+ // In case the fast dither table has to be built, call function too...
+ else if ((FastDitherTab == NULL) && ((pixFlags & WX_PIXFLAG_FASTDITHER) != 0) && (displayDepth < 15))
+ {
+ buildTranslationTable();
+ }
+
+ // In case the pixmap should be dithered:
+ if (((pixFlags & WX_PIXFLAG_DITHER) != 0) && (depth <= 12) && (displayDepth <= 8))
+ {
+ processPixmapPalette();
+ }
+
+ return(0);
+}
+
+
+
+#ifdef wx_msw
+// Special Win hack
+void wxPixmap::win_translate_24_to_24(unsigned char *dest)
+{
+ int i, j;
+ unsigned char *b, *d, *bline, *dline;
+
+ bline = (unsigned char*)data; dline = dest;
+ for (i=0; i<height; i++, bline+=pitch, dline+=displayPitch)
+ {
+ b = bline; d = dline;
+ if (rgbOrder == RGB_ORDER_RGB)
+ {
+ for (j=0; j<width; j++)
+ {
+ d[0] = b[0];
+ d[1] = b[1];
+ d[2] = b[2];
+ d += 3; b += 3;
+ }
+ }
+ else
+ {
+ for (j=0; j<width; j++)
+ {
+ d[0] = b[2];
+ d[1] = b[1];
+ d[2] = b[0];
+ d += 3; b += 3;
+ }
+ }
+ }
+}
+#endif
+
+
+// It's a biggie: translate the data into the correct format for the current display.
+void wxPixmap::translateToMode(void)
+{
+ const unsigned char *src = (unsigned char *)data;
+ unsigned char *dest = (unsigned char *)modeData;
+ int status = 0;
+
+ if ((data == NULL) || (modeData == NULL) || (displayDepth <= 0)) return;
+
+ // *errorstr << "translate mode " << depth << " to " << displayDepth << endl;
+ if ((data != modeData) && ((pixFlags & WX_PIXFLAG_TRANSLATE) != 0))
+ {
+ switch (depth)
+ {
+ case 1:
+ if (pixtrans1 != NULL) pixtrans1(src, dest, width, height, pitch, displayPitch, TransTab.c);
+ break;
+ case 2:
+ if (pixtrans2 != NULL) pixtrans2(src, dest, width, height, pitch, displayPitch, TransTab.c);
+ break;
+ case 4:
+ if (pixtrans4 != NULL) pixtrans4(src, dest, width, height, pitch, displayPitch, TransTab.c);
+ break;
+ case 8:
+ if (pixtrans8 != NULL) pixtrans8(src, dest, width, height, pitch, displayPitch, TransTab.c);
+ break;
+ case 12:
+ if (pixtrans12 != NULL) pixtrans12(src, dest, width, height, pitch, displayPitch, TransTab.c);
+ break;
+ case 15:
+ if (pixtrans15 != NULL) pixtrans15(src, dest, width, height, pitch, displayPitch, TrueTransTab);
+ break;
+ case 24:
+#ifdef wx_msw
+ if (displayDepth == 24)
+ {
+ win_translate_24_to_24(dest); break;
+ }
+#endif
+ if (pixtrans24 != NULL) pixtrans24(src, dest, width, height, pitch, displayPitch, TrueTransTab);
+ break;
+ case 32:
+ if (pixtrans32 != NULL) pixtrans32(src, dest, width, height, pitch, displayPitch, TrueTransTab);
+ break;
+ default:
+ status = -1;
+ break;
+ }
+
+ // *errorstr << "Translate bitmap status " << status << endl;
+
+ if (status < 0)
+ {
+#if (DEBUG > 0)
+ *errorstr << "Can't translate from " << depth << " to " << displayDepth << endl;
+#endif
+ }
+ }
+ validDisplay = TRUE;
+}
+
+
+// Ditherer to display modes with <= 8bpp. Otherwise use the simple translator.
+void wxPixmap::ditherToMode(void)
+{
+ int status=0;
+ unsigned char *dest = (unsigned char *)modeData;
+
+ if ((data == NULL) || (modeData == NULL) || (displayDepth <= 0)) return;
+
+ /*for (int i=0; i<(1<<depth); i++)
+ {
+ *errorstr << '[' << (int)(pixmapPalette[i].red) << ',' << (int)(pixmapPalette[i].green) << ',' << (int)(pixmapPalette[i].blue) << ']';
+ }
+ *errorstr << endl;*/
+
+ // *errorstr << "Dither mode " << depth << " to " << displayDepth << endl;
+ if (displayDepth <= 8)
+ {
+ if ((busyCursorMode) && ((pixFlags & WX_PIXFLAG_FASTDITHER) == 0))
+ ::wxBeginBusyCursor();
+
+ switch (depth)
+ {
+ case 1:
+ if (pixdither1 != NULL) (this->*pixdither1)(dest, displayPad);
+ break;
+ case 2:
+ if (pixdither2 != NULL) (this->*pixdither2)(dest, displayPad);
+ break;
+ case 4:
+ if (pixdither4 != NULL) (this->*pixdither4)(dest, displayPad);
+ break;
+ case 8:
+ if (pixdither8 != NULL) (this->*pixdither8)(dest, displayPad);
+ break;
+ case 12:
+ if (pixdither12 != NULL) (this->*pixdither12)(dest, displayPad);
+ break;
+ case 15:
+ if (pixdither15 != NULL) (this->*pixdither15)(dest, displayPad);
+ break;
+ case 24:
+ if (pixdither24 != NULL) (this->*pixdither24)(dest, displayPad);
+ break;
+ case 32:
+ if (pixdither32 != NULL) (this->*pixdither32)(dest, displayPad);
+ break;
+ default:
+ status = -1;
+ break;
+ }
+
+ if ((busyCursorMode) && ((pixFlags & WX_PIXFLAG_FASTDITHER) == 0))
+ ::wxEndBusyCursor();
+
+ if (status < 0)
+ {
+#if (DEBUG > 0)
+ *errorstr << "Can't dither from " << depth << " to " << displayDepth << endl;
+#endif
+ }
+ }
+ validDisplay = TRUE;
+}
+
+
+int wxPixmap::plotPixmap(int PosX, int PosY)
+{
+ // *errorstr << "plotPixmap: parentWin=" << (long)parentWin << ", data=" << (long)data << ", modeData=" << (long)modeData << endl;
+ if ((parentWin != NULL) && (data != NULL))
+ {
+ if (parentWin->IsShown())
+ {
+ // Do we have to do a colour translation?
+ if (!validDisplay)
+ {
+ if (data != modeData)
+ {
+ if (((pixFlags & WX_PIXFLAG_DITHER) != 0) && (displayDepth <= 8)) {ditherToMode();}
+ else if ((pixFlags & WX_PIXFLAG_TRANSLATE) != 0) {translateToMode();}
+ }
+#ifdef wx_msw
+ // I'd really like to avoid this but Windoze gets in the way
+ SetBitmapBits(bitmap, displayPitch * height, modeData);
+#endif
+ }
+#ifdef wx_x
+ /*cout << "width = " << xim->width << ", pitch = " << xim->bytes_per_line << ", bpp = " << xim->bits_per_pixel << ", depth = " << xim->depth << ", pad = " << xim->bitmap_pad << endl;
+ cout << "format = " << xim->format << ", byte_order = " << xim->byte_order << ", bitmap_unit = " << xim->bitmap_unit << ", bitmap_bit_order = " << xim->bitmap_bit_order << ", rmask = " << xim->red_mask << ", gmask = " << xim->green_mask << ", bmask = " << xim->blue_mask << endl;*/
+ XPutImage(display, windowHandle, myGC, xim, 0, 0, PosX, PosY, width, height);
+#endif
+
+#ifdef wx_msw
+ if (BitBlt(winDC, PosX, PosY, width, height, srcDC, 0, 0, SRCCOPY) == 0)
+ return -1;
+#endif
+ }
+ return 0;
+ }
+ else
+ {
+ errorGeneric("Window or image definition missing!");
+ }
+ return -1;
+}
+
+
+void wxPixmap::invalidatePixmap(void) {validDisplay = FALSE;}
+
+
+
+/*
+ * re-build the true-colour --> colourmapped table and the fast ditherer table
+ * (in case another application modified a colour and the display goes wrong).
+ */
+void wxPixmap::refreshGlobalTables(void)
+{
+ int newTables=0;
+
+ if ((depth > 12) && (displayDepth <= 8))
+ {
+ newTables |= 1;
+ if (TrueTransTab != NULL)
+ {
+ delete [] TrueTransTab;
+ TrueTransTab = NULL; TrueTransCount--;
+ }
+ }
+ if ((pixFlags & WX_PIXFLAG_FASTDITHER) != 0)
+ {
+ newTables |= 2;
+ if (FastDitherTab != NULL)
+ {
+ delete [] FastDitherTab;
+ FastDitherTab = NULL; FastDitherCount--;
+ }
+ }
+ if (newTables != 0)
+ buildTranslationTable();
+}
+
+
+
+
+/*
+ * Display the busy mouse pointer when an operation takes longer (e.g. dithering)...
+ */
+bool wxPixmap::setBusyCursor(bool newMode)
+{
+ bool oldMode = busyCursorMode;
+ busyCursorMode = newMode;
+ return oldMode;
+}
+
+
+// Finally compile the auto-generated ditherers
+#include "wx_pixmap_dither.cpp"
diff --git a/applications/rview/wx_pixmap.h b/applications/rview/wx_pixmap.h
new file mode 100644
index 0000000..8ce86d2
--- /dev/null
+++ b/applications/rview/wx_pixmap.h
@@ -0,0 +1,221 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+ * PURPOSE:
+ * Efficient bitmaps of colour depths 1, 2, 4, 8, 16, 24 and 32bpp
+ *
+ * COMMENTS:
+ * None
+ */
+
+
+#ifndef wx_pixmap_h
+#define wx_pixmap_h
+
+
+// should be in <wx/defs.h>, but only for OS/2 (?): -- PB 2006-jan-01
+typedef unsigned long COLORREF;
+
+// #include "wx_stat.h"
+#include <wx/generic/statusbr.h>
+
+#ifdef __GNUG__
+#pragma interface
+#endif
+
+#include "wx/object.h"
+
+// changed in new wxWindows
+//#include "wx_prec.h"
+#include "wx/wxprec.h"
+
+
+
+
+/* Weights for colour matching */
+#define COLOUR_WEIGHT_RED 4
+#define COLOUR_WEIGHT_GREEN 9
+#define COLOUR_WEIGHT_BLUE 1
+
+
+/* No changes below this line should be necessary. */
+
+
+/* Flag bits for initialising functions*/
+#define WX_PIXFLAG_TRANSLATE 1 /* class-resident mode translation enabled? */
+#define WX_PIXFLAG_DITHER 2 /* Dither image. Overrides WX_PIXFLAG_TRANSLATE. */
+#define WX_PIXFLAG_SAMEPALETTE 4 /* The palette is the same as the old one */
+#define WX_PIXFLAG_FASTDITHER 8 /* Fast rather than best ditherer */
+#define WX_PIXMODE_PALETTE 1 /* force making new colour tables on a mode change */
+
+
+
+/* Structure for a permuted colour map (for more efficient colour matching) */
+typedef struct wx_permute_cmap {
+ unsigned char red, green, blue, number;
+} wx_permute_cmap;
+
+
+
+
+/*
+ * Translation tables for true-colour-pixmaps to <= 8bpp modes and fast ditherer.
+ * Shared! Define WX_PIXMAP_GLOBAL_VOLATILE to free global translation tables
+ * as soon as no more references to it exist. Default is to keep them.
+ */
+extern unsigned char *TrueTransTab;
+extern unsigned char *FastDitherTab;
+extern int TrueTransCount;
+extern int FastDitherCount;
+
+
+
+class wxPixmap;
+
+/* Type of pixmap translation function */
+typedef void (*wx_pixmap_translate)(const unsigned char *src, unsigned char *dest, int width, int height, int srcPitch, int destPitch, const unsigned char *tt);
+/* Type of pixmap dithering function */
+typedef void (wxPixmap::*wx_pixmap_dither)(unsigned char *dest, int destPad);
+/* Type of colour-matching functions (used in ditherers) */
+typedef int (wxPixmap::*pixmap_colour_match)(unsigned char r, unsigned char g, unsigned char b);
+
+
+/*
+ * Class for efficiently displaying raster images of any depth, initialising
+ * them from binary data.
+ * The macro wx_pixmap_alloc_cols distinguishes between two colour models.
+ * If it's defined the colours are allocated (X), otherwise the current
+ * colourmap is read and processed internally (much faster and usually
+ * much more accurate).
+ */
+
+class WXDLLEXPORT wxPixmap : public wxObject
+{
+ public:
+ /* Public member functions */
+ wxPixmap(void);
+ wxPixmap(wxWindow *Win, int Width, int Height, int Depth, int Pad, char *Data, unsigned int Flags=WX_PIXFLAG_TRANSLATE, wxColour *Palette=NULL);
+ ~wxPixmap(void);
+ int newPixmap(wxWindow *Win, int Width, int Height, int Depth, int Pad, char *Data, unsigned int Flags=WX_PIXFLAG_TRANSLATE, wxColour *Palette=NULL);
+ int plotPixmap(int PosX, int PosY);
+ void invalidatePixmap(void);
+ int getWidth(void);
+ int getHeight(void);
+ int getDepth(void);
+ int getPitch(void);
+ char *getData(void);
+ wxColour *getPalette(void);
+ int getModeDepth(void);
+ int getModePitch(void);
+ char *getModeData(void);
+ unsigned char *getTranslationTable(void);
+ void modeChange(unsigned int Flags);
+ void buildTranslationTable(void);
+ void refreshGlobalTables(void);
+ bool setBusyCursor(bool newMode);
+#ifndef wx_pixmap_alloc_cols
+ void processParentPalette(bool forceUpdate=FALSE);
+ void processPixmapPalette(void);
+ wx_permute_cmap *getParentPalette(void);
+ int findBestColour(unsigned char red, unsigned char green, unsigned char blue);
+ int findFastColour(unsigned char red, unsigned char green, unsigned char blue);
+ /* Include auto-generated ditherer headers; these need the colour maps set up
+ correctly, so it only works with wx_pixmap_alloc_cols not defined. */
+#include "wx_pixmap_dither.h"
+#endif
+
+ protected:
+ /* protected member functions */
+ void errorMemory(void);
+ void errorGeneric(char *message);
+ void initVariables(void);
+ void freeResources(int Depth, unsigned int Flags);
+ void translateToMode(void);
+ void ditherToMode(void);
+ void getDisplayAttributes(void);
+ void initColoursForMode(bool forceUpdate=FALSE);
+ void setupTranslators(void);
+#ifndef wx_pixmap_alloc_cols
+ void sortParentPalette(int from, int to); /* Quicksorter */
+ void buildInverseTable(void);
+#endif
+
+ /* protected variables */
+ int width, height, depth, pad, pitch; /* parameters for image */
+ int displayDepth, displayPitch, displayPad; /* parameters for current display */
+ char *data; /* Raw source data */
+ char *modeData; /* Translated data suitable for plotting */
+ union {unsigned char *c; COLORREF *l;} TransTab; /* Colour translation table. */
+ /* COLORREF is defined in wxWindows */
+ int TransTabSize;
+ wxColour *palette; /* Source data palette */
+ wxWindow *parentWin; /* The parent window date should be plotted to */
+ unsigned int pixFlags;
+#ifdef wx_pixmap_alloc_cols
+ char ColourAlloc[32]; /* bitfield (256 bits). Bit i set ==> X-colour #i allocated OK. */
+ /* only used for displayDepth <= 8. */
+#else
+ int parentPaletteDepth;
+ wx_permute_cmap *parentPalette, *pixmapPalette;
+ unsigned char parentInverse[256];
+#endif
+ bool validDisplay;
+ bool busyCursorMode;
+ // wxDebugStreamBuf streamBuf; -- PB 2006-jan-01
+ wxOutputStream streamBuf;
+ std::ostream *errorstr;
+ int destBitorder, destByteorder, rgbOrder;
+ wx_pixmap_translate pixtrans1, pixtrans2, pixtrans4, pixtrans8, pixtrans12;
+ wx_pixmap_translate pixtrans15, pixtrans24, pixtrans32;
+ wx_pixmap_dither pixdither1, pixdither2, pixdither4, pixdither8, pixdither12;
+ wx_pixmap_dither pixdither15, pixdither24, pixdither32;
+ pixmap_colour_match colour_matcher;
+
+#ifdef wx_x
+ /* System Specifics */
+ Display *display;
+ XVisualInfo visualInfo;
+ XImage *xim;
+ XGCValues xgcvals;
+ XWindowAttributes xat;
+ GC myGC;
+ int screen;
+ Window rootwin, windowHandle;
+#endif
+
+#ifdef wx_msw
+ void win_translate_24_to_24(unsigned char *dest);
+
+ BITMAP bmDesc;
+ HBITMAP bitmap;
+ HWND windowHandle;
+ HWND desktop;
+ HDC rootDC, winDC, srcDC;
+ HGDIOBJ oldDCObject;
+ HPALETTE currentPal;
+#endif
+};
+
+
+#endif
diff --git a/bin/Makefile.am b/bin/Makefile.am
new file mode 100644
index 0000000..a9ad8a0
--- /dev/null
+++ b/bin/Makefile.am
@@ -0,0 +1,47 @@
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+#
+###################################################################
+
+bin_SCRIPTS = start_rasdaman.sh stop_rasdaman.sh create_db.sh rasmgr.conf
+EXTRA_DIST = stop_rasdaman.sh.in start_rasdaman.sh.in create_db.sh.in rasmgr.conf.in
+CLEANFILES = start_rasdaman.sh stop_rasdaman.sh create_db.sh rasmgr.conf
+dist_sysconf_DATA=rasmgr.conf
+dist_pkgdata_DATA=errtxts_en errtxts_de errtxts_fr errtxts
+
+script_edit = $(SED) \
+ -e 's|@logdir[@]|$(logdir)/|g' \
+ -e 's|@bindir[@]|$(bindir)/|g' \
+ -e 's|@pkgdatadir[@]|$(pkgdatadir)/|g'
+
+start_rasdaman.sh stop_rasdaman.sh create_db.sh: Makefile
+ rm -f $@
+ $(script_edit) '$@.in' >$@
+ chmod +x $@
+ chmod a-w $@
+
+start_rasdaman.sh: start_rasdaman.sh.in
+stop_rasdaman.sh: stop_rasdaman.sh.in
+create_db.sh: create_db.sh.in
+rasmgr.conf: rasmgr.conf.in Makefile
+ rm -f $@
+ $(SED) -e "s|@hostname[@]|`hostname`|g" '$@.in' >$@
diff --git a/bin/create_db.sh.in b/bin/create_db.sh.in
new file mode 100644
index 0000000..b7a2f89
--- /dev/null
+++ b/bin/create_db.sh.in
@@ -0,0 +1,116 @@
+#!/bin/bash
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+#
+#
+# PURPOSE:
+# This script creates a CREATE_DB.sql script for
+# generating a rasdaman database with PostgreSQL.
+# This script must be executed by the user which
+# runs the PostgreSQL server.
+#
+#
+# COMMENTS:
+# List environment dependencies, known bugs, specialities etc.
+# -------------------------------------------------------------------
+#
+########################################################################
+
+# --- constants & routines
+
+# script name
+PROG=`basename $0`
+VERSION=5.2
+
+# script return codes
+RC_OK=0
+RC_ERROR=1
+
+# Unix user name under which rasdaman server is expected to run
+RASDAMAN_USER=rasdaman
+
+# default database name
+# (if you change this, then a _lot_ of tools and configs
+# have to get the new database name explicitly, so you may
+# want to seriously consider whether you really want this)
+DATABASE_NAME=RASBASE
+
+# rasdaman base type definition file
+DEFINITION_FILE=@pkgdatadir@examples/rasdl/basictypes.dl
+
+# error termination routine
+error() {
+ echo "$PROG: $1"
+ exit $RC_ERROR
+}
+
+# --- checking preconditions
+echo "$PROG: Creating database, rasdaman v$VERSION on base DBMS PostgreSQL"
+
+# - are we user 'rasdaman'?
+if [ $USER != $RASDAMAN_USER ]
+then
+ echo "Warning: script should be run as user '$RASDAMAN_USER', not '$USER'; will try nevertheless."
+fi
+
+# - Can I find utilities?
+psql --help 2>&1 1>/dev/null || \
+ error "Error: cannot find psql - PostgreSQL not installed or PATH variable does not contain PostgreSQL path?"
+
+@bindir@rasdl --help 2>&1 1>/dev/null
+if [[ $? != 2 ]]
+then
+ error "Error: cannot find rasdl - PATH variable does not contain rasdaman path?"
+fi
+
+if [[ ! -f $DEFINITION_FILE ]]
+then
+ error "Error: cannot find rasdaman basic type definition file '$DEFINITION_FILE'"
+fi
+
+# --- action: create database directory & cluster if needed
+
+echo -n "$PROG: PostgreSQL database generation...\c"
+
+# - PostgreSQL part
+createdb $DATABASE_NAME
+if [[ $? != 0 ]]
+then
+ error "createdb failed."
+fi
+
+# - rasdaman part
+
+echo -n "$PROG: rasdaman dictionnary initialization...\c"
+@bindir@rasdl -c --connect $DATABASE_NAME && @bindir@rasdl -r $DEFINITION_FILE -i --connect $DATABASE_NAME
+if [[ $? != 0 ]]
+then
+ error "rasdl failed."
+fi
+
+# --- action end
+
+echo "$PROG: done."
+exit $RC_OK
+
+# --- end of script
+
diff --git a/bin/errtxts b/bin/errtxts
new file mode 100644
index 0000000..f96f13f
--- /dev/null
+++ b/bin/errtxts
@@ -0,0 +1,276 @@
+208
+# Increment the number above every time you add a new exception
+# (no of error codes - 1)
+#
+# CHANGES:
+# 2003-jul-02 PB corrected some typos in error texts
+# 2003-aug-31 PB corrected some typos in error texts
+# added 830
+# 2003-dec-03 PB added 3000
+# 2005-jun-19 PB added 420, 421, 422
+#
+# This file contains types and textual descriptions of RasDaMan errors.
+# The ascending error numbers are used as index to the descriptions. Each
+# line follows the following syntax:
+#
+# number^type^description.
+#
+# The character '^' is used as delimiter and with '#' a comment line is
+# started. Empty lines are not allowed.
+#
+#
+66^E^Exception: Memory allocation failed.
+100^E^Exception: Internal error: DL parse error.
+200^E^Exception: The result is no point.
+201^E^Exception: The result is no interval.
+202^E^Exception: Index violation ( index range [$low,$high], index $index ).
+203^E^Exception: Dimension mismatch between $dim1 and $dim2.
+204^E^Exception: Stream initialization overflow.
+205^E^Exception: Result is no cell.
+206^E^Serialisable exception r_Ebase_dbms: error in base DBMS.
+207^E^Internal client exception in class $class, method $method: $code.
+208^E^Exception: Access type $aType does not fit base type $bType.
+209^E^Exception: RasType $type is unknown.
+210^E^Exception: Base type $type is not supported yet.
+211^E^Exception: Database is not open.
+212^E^Exception: RPC layer connection to RasDaMan failed.
+213^E^Exception: Wrong URL format (should be http://address:port)
+214^E^Exception: Illegal java long value $val for server base type ULong.
+215^E^Exception: Illegal java integer value $val for server base type UShort.
+216^E^Exception: System collection is not writable.
+217^E^Exception: System collection has no OID.
+218^E^Exception: Conversion format is not supported.
+219^E^Exception: The specified tile size is smaller than the length of the base type of the mdd object.
+220^E^Exception: The tiling strategy in the storage layout is not compatible with the marray.
+221^E^Exception: The domain passed as an argument was not initialised correctly (dimension is 0).
+222^E^Exception: The type name or type structure does not represent a marray type.
+223^E^Exception: The rc index requires a marray type that has a specified domain (with fixed borders in all dimensions).
+224^E^Exception: The tile configuration is incompatible to the marray domain.
+229^E^Exception: The parameterized query has invalid parameter format.
+230^E^Exception: The r_Object was already assigned a type.
+231^E^Exception: The Marray has no base type.
+232^E^Exception: The interval has at least one open bound.
+233^E^Exception: The intervals don't have the same dimension.
+234^E^Exception: The string passed to the tiling object was not correct.
+235^E^Exception: Connection to server already closed.
+236^E^Exception: Error in compression engine
+237^E^Exception: Client communication failure
+238^E^Exception: Base type not supported by conversion/compression module.
+239^E^Exception: Standard overlay using types larger than 16 bytes is not supported.
+240^E^Exception: Insert into a RC index is not allowed.
+241^E^Exception: No tiling defined at that region. Update not possible.
+#
+300^E^Parsing error $errorNo in line $lineNo, column $columnNo: Unexpected name $token.
+301^E^Parsing error $errorNo in line $lineNo, column $columnNo, token $token: All cell values of an MDD must be of the same type.
+302^E^Parsing error $errorNo in line $lineNo, column $columnNo, token $token: Number of cells specified does not match the number of cells of the given spatial domain.
+303^E^Parsing error $errorNo in line $lineNo, column $columnNo, token $token: OId is not valid.
+308^E^Parsing error: Unexpected end of query.
+309^E^Parsing error: Unknown error.
+310^E^Lexical analysing error $errorNo in line $lineNo, column $columnNo: Unexpected characters $token.
+311^E^Parsing error $errorNo in line $lineNo, column $columnNo, token $token: Complex constructor must have both arguments of the same type (i.e. float or double).
+312^E^Parsing error $errorNo in line $lineNo, column $columnNo, token $token: Variable already defined.
+313^E^Parsing error $errorNo in line $lineNo, column $columnNo, token $token: Only constant interval bounds allowed.
+#
+330^E^Preprocessing error $errorNo in line $lineNo, column $columnNo: Unexpected name $token:
+331^E^Preprocessing error $errorNo in line $lineNo, column $columnNo, token $token: attempt to redefine function.
+332^E^Preprocessing error $errorNo in line $lineNo, column $columnNo, token $token: number of actual arguments for the called function differs from the number of formal arguments.
+333^E^Preprocessing error $errorNo in line $lineNo, column $columnNo, token $token: the called function name is ambiguous, try the full qualified name.
+#
+349^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operand out of range.
+350^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: General.
+351^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Spatial domains of the binary induce operands are incompatible.
+352^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operand types are incompatible.
+353^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operand of quantifier must be multidimensional.
+354^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operand of quantifier must be of type r_Marray<d_Boolean>.
+355^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Collection name is unknown.
+356^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Specified domain does not intersect with spatial domain of MDD.
+357^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Variable is unknown.
+358^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Projection operand is not of type r_Marray<T>.
+359^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Result of the where clause must be of type boolean.
+360^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Type of operand is not supported.
+361^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Multiple query targets are not supported.
+362^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Specified domain dimensionality does not equal defined dimensionality of MDD.
+#
+363^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Cell base types of binary induce operation are incompatible.
+364^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Cell base type and scalar type of binary induce operation are incompatible.
+365^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Scalar types of binary operation are incompatible.
+366^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Cell base type of unary induce operation is not supported.
+367^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Scalar type of unary operation is not supported.
+368^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Cell base type for induced dot operation must be complex.
+369^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Scalar type for dot operation must be complex.
+370^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Struct selector is not valid.
+371^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Retrieval query must start with a SELECT statement.
+372^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Update query must start with an INSERT, UPDATE, DELETE, DROP or CREATE statement.
+373^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Unsatisfied MDD constant parameter.
+380^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Data type can not be converted to selected data exchange format.
+381^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Error in convertor of the selected data exchange format.
+382^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Unknown conversion format.
+383^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Parameter of oid function must be a persistent object of type MDD.
+384^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: OId is not valid.
+385^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operation is not supported on strings.
+386^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Base name of oid is not matching the currently opened one.
+387^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: System name of oid is not matching the currently used one.
+388^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Interval bound must be either an integer expression or an asterisk.
+389^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: No interval (in case of fixed bounds, the upper one can not be smaller than the lower one).
+390^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Minterval dimension specifications must be either of type interval or integer.
+391^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Spatial operation must be either of type minterval, point, or integer.
+393^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operand of operation lo/hi must be of type interval.
+394^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operation lo/hi can not be used for an open bound.
+395^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operand of function sdom() must be of type MDD.
+396^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Selection operation is not supported on this data type.
+397^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operand of minterval selection must be of type integer.
+398^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Index for minterval selection is out of range.
+399^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operand of point selection must be of type integer.
+#
+#
+#
+400^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Domain of MDD constructor has to be defined.
+401^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Can not evaluate domain expression to an minterval.
+402^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Projected cell is not defined.
+403^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Binary operation is not supported on these data types.
+404^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Type of cell expression is not supported.
+405^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: First operand of shift function must be of type MDD.
+406^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Second operand of shift function must be of type Point.
+407^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Dimensionality of MDD and point expression are not matching.
+408^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Second operand of shift function must be a constant expression.
+409^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Spatial domain shift of open bounds is not supported.
+#
+#
+#
+410^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operand of point expression must be of type integer.
+411^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Index for point selection is out of range.
+412^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Value expression must be either of type atomic or complex.
+413^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Condition expression must be of type boolean.
+415^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operand of count_cells must be of type r_Marray<d_Boolean>.
+#
+416^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: First operand of scale function must be of type MDD.
+417^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Second operand of scale function must be either of type Point, Integer or Float.
+#
+418^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Second operand of bit function must be of integral type.
+419^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Could not scale the domain.
+420^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Extend operation with open bounds is not supported.
+421^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Target interval of extend operation does not cover MDD to be extended.
+422^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Second operand of extend function must be an minterval.
+#
+499^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Language feature is not supported.
+#
+# 5XX errors for overflow situations
+#
+510^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: The argument is outside the function domain.
+511^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: The function result exceeds the allowed range.
+#
+# 7XX errors for problems with Administration (some Oracle specific)
+#
+700^E^Admin error: General error creating RasDaMan database.
+701^E^Admin error: Error creating table in tablespace RAS_DB_SCHEMA.
+702^E^Admin error: Error inserting into table RAS_COUNTERS.
+703^E^Admin error: Error creating table in tablespace RAS_DB_BLOB.
+704^E^Admin error: Error creating index in tablespace RAS_DB_INDEX.
+705^E^Admin error: Error inserting into table RAS_BASETYPENAMES.
+706^E^Admin error: Error creating table in default tablespace.
+707^E^Admin error: Error on COMMIT creating RasDaMan database.
+708^E^Admin error: Database to be created already exists.
+#
+# 80x errors for RasManager problems
+#
+800^E^RasManager Error: Could not connect to RasServer $url.
+801^E^RasManager Error: System overloaded, please try again later.
+802^E^RasManager Error: Access denied, incorrect user/password.
+803^E^RasManager Error: Access denied, no permission for operation.
+804^E^RasManager Error: Access denied, capability refused.
+805^E^RasManager Error: No suitable servers started, call administrator.
+806^E^RasManager Error: Write transaction in progress, please retry again later.
+807^E^RasManager Error: Requested database unknown.
+808^E^RasManager Error: Request format error.
+#
+# 82x errors for RNP administrative problems
+#
+820^E^RNP Error: First parameter has to be the clientID (clientcomm internal).
+821^E^RNP Error: Client ID invalid, probably a timeout occurred.
+822^E^RNP Error: Unknown command in client request.
+#
+# 83x errors for base DBMS connections
+#
+830^E^base DBMS Error: Cannot connect to base DBMS server (invalid connect string in rasmgr config file?).
+#
+# 9xx errors: Evaluation errors
+#
+900^E^Evaluation error $errorNo in line $lineNo, column $columnNo, near token $token: Type in typedef definition not supported.
+901^E^Evaluation error $errorNo in line $lineNo, column $columnNo, near token $token: Set template type has to be a type reference.
+902^E^Evaluation error $errorNo in line $lineNo, column $columnNo, near token $token: Type reference not found.
+903^E^Evaluation error $errorNo in line $lineNo, column $columnNo, near token $token: MDD base type has to be a type reference or an atomic type.
+904^E^Evaluation error $errorNo in line $lineNo, column $columnNo, near token $token: MDD type must have a domain specification.
+905^E^Evaluation error $errorNo in line $lineNo, column $columnNo, near token $token: Struct type name exists already.
+906^E^Evaluation error $errorNo in line $lineNo, column $columnNo, near token $token: MDD type name exists already.
+907^E^Evaluation error $errorNo in line $lineNo, column $columnNo, near token $token: Set type name exists already.
+#
+950^E^Update error $errorNo in line $lineNo, column $columnNo, near token $token: Update target must be an iterator variable.
+951^E^Update error $errorNo in line $lineNo, column $columnNo, near token $token: Update source must be an expression resulting in an r_Marray<>.
+952^E^Update error $errorNo in line $lineNo, column $columnNo, near token $token: Update base type does not match MDD base type.
+953^E^Update error $errorNo in line $lineNo, column $columnNo, near token $token: Update domain is not within MDD definition domain.
+954^E^Update error $errorNo in line $lineNo, column $columnNo, near token $token: Update target expression must be an assignable value (l-value).
+955^E^Update error $errorNo in line $lineNo, column $columnNo, near token $token: Collection name exists already.
+956^E^Update error $errorNo in line $lineNo, column $columnNo, near token $token: Unknown collection type.
+957^E^Update error $errorNo in line $lineNo, column $columnNo, near token $token: Unknown collection name.
+958^E^Update error $errorNo in line $lineNo, column $columnNo, near token $token: Allocation of new oid failed.
+959^E^Update error $errorNo in line $lineNo, column $columnNo, near token $token: MDD and collection types are incompatible.
+960^E^Update error $errorNo in line $lineNo, column $columnNo, near token $token: Insert expression must be of type MDD.
+961^E^Update error $errorNo in line $lineNo, column $columnNo, near token $token: Update domain must be of type Minterval.
+962^E^Update error $errorNo in line $lineNo, column $columnNo, near token $token: Number of update intervals must match source dimensionaltiy.
+963^E^Update error $errorNo in line $lineNo, column $columnNo, near token $token: Update domain dimensionality must match target MDD dimensionaltiy.
+964^E^Update error $errorNo in line $lineNo, column $columnNo, near token $token: Type is not persistent.
+965^E^Update error $errorNo: MDD type $token unknown.
+966^E^Update error $errorNo: MDD type is missing.
+#
+# 1xxx errors: General errors
+#
+1000^E^General error: RasDaMan tables inconsistent.
+1001^E^General error: RasDaMan server incompatible with database.
+1002^E^General error: Blob with zero length encountered.
+1003^E^General error: Tile container for TC index not found.
+1004^E^General error: Index of MDD Object is not defined.
+1005^E^General error: Storage structure of MDD Object is not defined.
+1006^E^General error: Unknown index type requested.
+1007^E^General error: Illegal index type requested.
+1008^E^General error: No valid collection type passed to MDD collection.
+1009^E^General error: MDD object not valid or not persistent.
+1010^E^General error: No valid MDD type passed to MDD object.
+1011^E^General error: An illegal state has been reached. This is caused by a compiler bug or a library bug.
+1012^E^General error: Invalid collection type passed to MDD collection.
+1013^E^General error: The name of the type is too long.
+1014^E^General error: Invalid name of the object, should contain only [a-zA-Z0-9_]
+#
+# 2xxx errors: Internal errors
+#
+2000^E^Internal error: There seems to be another database open.
+2001^E^Internal error: Invalid OId type encountered.
+2002^E^Internal error: Entry in user defined type not found.
+2003^E^Internal error: Entry in user defined type out of bounds.
+2004^E^Internal error: Transient index used instead of persistent index.
+2005^E^Internal error: Index returned tiles multiple times.
+2006^E^Internal error: Tile was not inserted into index.
+2007^E^Internal error: Transient index access out of bounds.
+2008^E^Internal error: MDD object exists multiple times in cache.
+2009^E^Internal error: Some tile(s) were not inserted into the MDD object.
+2010^E^Internal error: A conversion module returned an incorrect base type.
+2011^E^Internal error: The collection type has no element type.
+2012^E^Internal error: The marray type has no base type.
+2013^E^Internal error: The property has no base type.
+2014^E^Internal error: The scalar was passed a NULL value.
+2015^E^Internal error: The index node that had to be split was not found in its parent.
+2016^E^Internal error: The index found more cells than allowed.
+2017^E^Internal error: The storage layout is incompatible with the index entries.
+2018^E^Internal error: Object does not support swapping.
+2019^E^Internal error: Error encountered during swapping.
+2020^E^Internal error: Binary export for object is not supported.
+2021^E^Internal error: Binary import for object is not supported.
+2022^E^Internal error: Operands and result types don't match.
+#
+# 3xxx errors: Data format conversion errors
+#
+3000^E^Format conversion error: DEM area does not contain any non-null value, empty result generated.
+
+#
+# The last, the unexpected error in server
+#
+10000^E^Unexpected internal server error.
diff --git a/bin/errtxts_de b/bin/errtxts_de
new file mode 100644
index 0000000..7bf983a
--- /dev/null
+++ b/bin/errtxts_de
@@ -0,0 +1,258 @@
+198
+# Increment the number above every time you add a new exception
+#
+# Increment the number above every time you add a new exception
+# (no of error codes - 1)
+#
+# CHANGES:
+# 2005-jun-19 PB added 420, 421, 422
+#
+# This file contains types and textual descriptions of RasDaMan errors.
+# The ascending error numbers are used as index to the descriptions. Each
+# line follows the following syntax:
+#
+# number^type^description.
+#
+# The character '^' is used as delimiter and with '#' a comment line is
+# started. Empty lines are not allowed.
+#
+#
+66^E^Fehler: Speicheranforderung fehlgeschlagen.
+100^E^Fehler: Interner Fehler: DL-Parser-Fehler.
+200^E^Fehler: Das Ergebnis ist kein Punkt.
+201^E^Fehler: Das Ergebnis ist kein Intervall.
+202^E^Fehler: Index-Überschreitung (Indexbereich [$low,$high], Index $index).
+203^E^Fehler: Dimensionen $dim1 und $dim2 entsprechen einander nicht.
+204^E^Fehler: Überlauf bei Stream-Initialisierung.
+205^E^Fehler: Resultat ist keine Zelle.
+206^E^Serialisierungsfehler r_Ebase_dbms: Fehler in Basis-DBMS.
+207^E^Interner Client Fehler in Klasse $class, Methode $method: $code.
+208^E^Fehler: Zugriffstyp $aType passt nicht zu Basistyp $bType.
+209^E^Fehler: Rastertyp $type ist unbekannt.
+210^E^Fehler: Basistyp $type wird noch nicht unterstützt.
+211^E^Fehler: Datenbank wurde nicht geöffnet.
+212^E^Fehler: RPC Verbindung zu RasDaMan fehlgeschlagen.
+213^E^Fehler: Falsches URL-Format (sollte http://adresse:port sein)
+214^E^Fehler: Illegaler Java Long-Wert $val für Server-Basistyp ULong.
+215^E^Fehler: Illegaler Java Integer-Wert $val für Server-Basistyp UShort.
+216^E^Fehler: System-Kollektion ist nicht schreibbar.
+217^E^Fehler: System-Kollektion hat keine OID.
+218^E^Fehler: Konvertierungsformat wird nicht unterstützt.
+219^E^Fehler: Die angegebene Kachelgrösse ist kleiner als die Länge des Basistyps des MDD-Objektes.
+220^E^Fehler: Die Kachelstrategie in der Speichereinteilung ist nicht kompatibel mit dem MArray.
+221^E^Fehler: Die als Argument übergebene Domäne ist nicht korrekt initialisiert worden (Dimension ist 0).
+222^E^Fehler: Der Typname oder die Typstruktur representiert keinen MArray-Typ.
+223^E^Fehler: Der RC-Index benötigt einen MArray-Typ mit einer spezifizierten Domäne (mit festgelegtem Rand in allen Dimensionen).
+224^E^Fehler: Die Kachelkonfiguration ist unkompatibel mit der MArray-Domäne.
+229^E^Fehler: Die parametrisierte Anfrage hat ein ungültiges Parameterformat.
+230^E^Fehler: Dem r_object ist bereits ein Typ zugewiesen worden.
+231^E^Fehler: Das MArray hat keinen Basistyp.
+232^E^Fehler: Das Intervall hat mindestens eine offene Grenze.
+233^E^Fehler: Die Intervalle haben nicht die gleiche Dimension.
+234^E^Fehler: Die Tiling-Beschreibung is nicht korrekt.
+235^E^Fehler: Verbindung zum Server bereits geschlossen.
+236^E^Fehler: Fehler in der Kompression codec.
+237^E^Fehler: Client Verbindung fehlgeschlagen.
+238^E^Fehler: Der Basistyp wird von diesem Konversions-/Kompressionsmodul nicht unterstützt.
+239^E^Fehler: Standard Überlagerung von Zellen mit Typen grösser als 16 Byte wird nicht unterstützt.
+240^E^Fehler: Einfügeoperation in einen RC Index ist nicht erlaubt.
+241^E^Fehler: Layout ist an dieser Stelle nicht definiert. Updateoperation ist nicht moeglich.
+#
+300^E^Parserfehler $errorNo in Zeile $lineNo, Spalte $columnNo: Unerwarteter Name $token.
+301^E^Parserfehler $errorNo in Zeile $lineNo, Spalte $columnNo, Token $token: Alle Zellenwerte eines MDDs müssen vom gleichen Typ sein.
+302^E^Parserfehler $errorNo in Zeile $lineNo, Spalte $columnNo, Token $token: Die Anzahl der angegebenen Zellen entspricht nicht der Anzahl der Zellen der gegebenen Raumdomäne.
+303^E^Parserfehler $errorNo in Zeile $lineNo, Spalte $columnNo, Token $token: OID ist nicht gültig.
+308^E^Parserfehler: Unerwartetes Ende der Anfrage.
+309^E^Parserfehler: Unbekannter Fehler.
+310^E^Fehler des lexikalischen Analysators $errorNo in Zeile $lineNo, Spalte $columnNo: Unerwartete Zeichen $token.
+311^E^Parserfehler $errorNo in Zeile $lineNo, Spalte $columnNo, Token $token: Komplexer Konstruktor muss beide Argumente vom gleichen Typ haben (z.B. Float oder Double).
+312^E^Parserfehler $errorNo in Zeile $lineNo, Spalte $columnNo, Token $token: Variable ist schon definiert worden.
+313^E^Parserfehler $errorNo in Zeile $lineNo, Spalte $columnNo, Token $token: Nur konstante Intervallgrenzen sind zulässig.
+#
+330^E^Präprozessorfehler $errorNo in Zeile $lineNo, Spalte $columnNo: Unerwarteter Name $token:
+331^E^Präprozessorfehler $errorNo in Zeile $lineNo, Spalte $columnNo, Token $token: Versuch eine Funktion erneut zu definieren.
+332^E^Präprozessorfehler $errorNo in Zeile $lineNo, Spalte $columnNo, Token $token: Die Anzahl der wirklichen Argumente für die aufgerufene Funktion unterscheidet sich von der Anzahl der formalen Argumente.
+333^E^Präprozessorfehler $errorNo in Zeile $lineNo, Spalte $columnNo, Token $token: Der aufgerufene Funktionsname ist nicht eindeutig, versuchen Sie den vollen qualifizierten Namen.
+#
+349^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Operand ausserhalb des Wertebereichs.
+350^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Allgemeiner Fehler.
+351^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Die Array-Grenzen sind inkompatibel für die induzierte Operation.
+352^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Die Operandentypen sind inkompatibel.
+353^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Der Operand des Quantifiers muss multidimensional sein.
+354^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Operand des Quantifiers muss vom Typ r_Marray<d_Boolean> sein.
+355^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Kollektionsname ist unbekannt.
+356^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Spezifizierte Domäne schneidet sich nicht mit der Raumdomäne des MDD.
+357^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Variable ist unbekannt.
+358^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Projektionsoperand ist nicht vom Typ r_Marray<T>.
+359^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Ergebnis der where-Klausel muss ein boolischer Typ sein.
+360^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Der Typ des Operanden wird nicht unterstützt.
+361^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Multiple Anfrageziele werden nicht unterstützt.
+362^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Angegebene Domänen-Dimensionalität ist nicht gleich der definierten Dimensionalität des MDD.
+#
+363^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Zellen-Basistyp der binären induzierten Operation sind inkompatibel.
+364^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Zellen-Basistyp und skalarer Typ der binären induzierten Operation sind inkompatibel.
+365^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Die skalaren Typen der binären Operation sind inkompatibel.
+366^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Zellen-Basistyp der unären induzierten Operation wird nicht unterstützt.
+367^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Skalarer Typ der unären Operation wird nicht unterstützt.
+368^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Zellen-Basistyp der induzierten Punktoperation muss komplex sein.
+369^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Skalartyp für Punktoperation muss komplex sein.
+370^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Strukturselektor ist nicht gültig.
+371^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Ergebnisanfrage muss mit einer SELECT-Klausel anfangen.
+372^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Update-Anfragen müssen mit einer INSERT-, UPDATE-, DELETE-, DROP- oder CREATE-Klausel anfangen.
+373^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Unbefriedigter MDD Konstantparameter.
+380^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Datentyp kann nicht konvertiert werden.
+381^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Fehler im ausgewählten konverter.
+382^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Unbekanntes Konvertierungsformat.
+383^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Parameter der OID-Funktion muss ein persistentes Objekt des Typs MDD sein.
+384^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: OID ist nicht gültig.
+385^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Operation wird nicht für Zeichenketten unterstützt.
+386^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Basisname der oid entspricht nicht dem aktuell geöffnetem Basisnamen.
+387^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Systemname der oid entspricht nicht dem aktuell benutztem Systemname.
+388^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Intervallgrenze muss entweder ein Integer-Ausdruck oder ein Asterisk sein.
+389^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Kein Intervall (im Falle einer starren Grenze kann die Obere nicht kleiner sein als die Untere).
+390^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Minterval-Dimensionsspezifikation muss entweder vom Typ Interval oder Integer sein.
+391^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Raumoperation muss entweder vom Typ minterval, Punkt oder Integer sein.
+393^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Operand der Operation lo/hi muss vom Typ interval sein.
+394^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Operation lo/hi can not be used for an open bound.
+395^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Operand der Funktion sdom() muss vom Typ MDD sein.
+396^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Selektionsoperation wird nicht für diesen Datentyp unterstützt.
+397^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Operand der minterval-Selektion muss vom Typ Integer sein.
+398^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Index für minterval-Selektion liegt ausserhalb des Wertebereichs.
+399^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Operand der Punktselektion muss vom Typ Integer sein.
+#
+#
+#
+400^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Domäne des MDD-Konstruktors muss definiert sein.
+401^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Can not evaluate domain expression to an minterval.
+402^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Projezierte Zelle ist nicht definiert.
+403^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Binäre Operation wird bei diesen Datentypen nicht unterstützt.
+404^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Typ des Zellenausdrucks wird nicht unterstützt.
+405^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Der erste Operand der Verschiebefunktion muss vom Typ MDD sein.
+406^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Der zweite Operand der Verschiebefunktion muss vom Typ Punkt sein.
+407^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Dimensionalität des MDD- und Punktausdrucks entsprechen nicht einander.
+408^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Der zweite Operand der Verschiebefunktion muss ein konstanter Ausdruck sein.
+409^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Shift-Operation auf offenen Feldgrenzen nicht erlaubt.
+#
+#
+#
+410^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Operand des Punktausdrucks muss vom Typ Integer sein.
+411^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Index der Punktselektion liegt ausserhalb des Wertebereichs.
+412^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Werteausdruck muss entweder vom Typ atomar oder komplex sein.
+413^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Bedingungsausdruck muss vom Typ boolisch sein.
+415^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Operand der count_cells muss vom Typ r_Marray<d_Boolean> sein.
+#
+416^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Der erste Operand der Skalierungsfunktion muss vom Typ MDD.
+417^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Der zweite Operand der Skalierungsfunktion muss entweder vom Typ Punkt, Integer oder Float sein.
+#
+418^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Der zweite Operand der Bit-Funktion muss ein integraler Typ sein.
+419^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Konnte die Domäne nicht skalieren.
+420^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Extend-Operation mit offenen Intervallgrenzen wird nicht unterstützt.
+421^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Ziel-Intervall der extend-Operation überdeckt zu erweiterndes MDD nicht vollständig.
+422^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Der zweite Operand der extend-Funktion muss vom Typ Mintervall sein.
+#
+499^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Sprachmerkmal wird nicht unterstützt.
+#
+# 5XX errors for overflow situations
+510^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Das Argument liegt ausserhalb der Funktionsdomäne.
+511^E^Ausführungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Das Ergebnis der Funktion überschreitet den erlaubten Wertebereich.
+#
+# 7XX errors for problems with Administration (some Oracle specific)
+#
+700^E^Administrationsfehler: Allgemeiner Fehler beim erzeugen der RasDaMan-Datenbank.
+701^E^Administrationsfehler: Fehler beim Erzeugen einer Tabelle im Tablespace RAS_DB_SCHEMA.
+702^E^Administrationsfehler: Fehler beim Einfügen in die Tabelle RAS_COUNTERS.
+703^E^Administrationsfehler: Fehler beim erzeugen einer Tabelle im Tablespace RAS_DB_BLOB.
+704^E^Administrationsfehler: Fehler beim erzeugen des Index im Tablespace RAS_DB_INDEX.
+705^E^Administrationsfehler: Fehler beim Einfügen in die Tabelle RAS_BASETYPENAMES.
+706^E^Administrationsfehler: Fehler beim Erzeugen einer Tabelle im Standard-Tablespace.
+707^E^Administrationsfehler: Fehler beim COMMIT während der Erzeugung der RasDaMan-Datenbank.
+708^E^Administrationsfehler: Die zu erzeugende Datenbank existiert bereits.
+#
+# 8xx errors for RasManager problems
+#
+800^E^RasManager Fehler: Konnte keine Verbindung zum RasServer $url herstellen.
+801^E^RasManager Fehler: Systemüberlastung - bitte versuchen Sie es später noch einmal.
+802^E^RasManager Fehler: Zugriff verweigert - ungültiger Benutzer/Passwort.
+803^E^RasManager Fehler: Zugriff verweigert - keine Erlaubnis für diese Operation.
+804^E^RasManager Fehler: Zugriff verweigert - Fähigkeit abgewiesen.
+805^E^RasManager Fehler: Keine geeigneten Server gestartet - informieren Sie den rasadmin.
+806^E^RasManager Fehler: Schreibtransaktion am laufen - bitte Versuchen Sie es später noch einmal.
+807^E^RasManager Fehler: Angeforderte Datenbank unbekannt.
+808^E^RasManager Fehler: Anfrageformat-Fehler.
+830^E^RasManager Fehler: Rasserver kann keine Verbindung zum Basis-DBMS aufbauen (ungültiger connect-Parameter in rasmgr-Konfigurationsdatei?).
+#
+# 9xx errors: Evaluation errors
+#
+900^E^Auswertungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Typ in typedef-Definition wird nicht unterstützt.
+901^E^Auswertungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Set-Template muss eine Typreferenz sein.
+902^E^Auswertungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Typreferenz wurde nicht gefunden.
+903^E^Auswertungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: MDD-Basistyp muss eine Typreferenz oder ein atomarer Typ sein.
+904^E^Auswertungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: MDD-Typ muss eine Domänenspezifikation haben.
+905^E^Auswertungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Strukturen-Typname existiert bereits.
+906^E^Auswertungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: MDD-Typname existiert bereits.
+907^E^Auswertungsfehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Set-Typname existiert bereits.
+#
+950^E^Update-Fehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Update-Ziel muss eine Iteratorvariable sein.
+951^E^Update-Fehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Update-Quelle muss ein Ausdruck mit dem Ergebnis eines r_Marray<> sein.
+952^E^Update-Fehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Update-Basistyp entspricht nicht dem MDD-Basistypen.
+953^E^Update-Fehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Update-Domäne liegt nicht innerhalb der MDD-Definitionsdomäne.
+954^E^Update-Fehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Update-Zielausdruck muss ein zuweisungsfähiger Wert sein (l-value).
+955^E^Update-Fehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Kollektionsname existiert bereits.
+956^E^Update-Fehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Unbekannter Kollektionstyp.
+957^E^Update-Fehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Unbekannter Kollektionsname.
+958^E^Update-Fehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Zuweisung der neuen OID fehlgeschlagen.
+959^E^Update-Fehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: MDD- und Kollektionstyp sind inkompatibel.
+960^E^Update-Fehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Insert-Ausdruck muss vom Typ MDD sein.
+961^E^Update-Fehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Update-Domäne muss vom Typ Minterval sein.
+962^E^Update-Fehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Anzahl der Update-Intervalle müssen der Quellendimensionalität entsprechen.
+963^E^Update-Fehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Update-Domänendimensionalität muss der Ziel-MDD-Dimensionalität entsprechen.
+964^E^Update-Fehler $errorNo in Zeile $lineNo, Spalte $columnNo, nahe Token $token: Typ ist nicht persistent.
+965^E^Update-Fehler $errorNo: MDD-Typ $token unbekannt.
+966^E^Update-Fehler $errorNo: MDD-Typ fehlt.
+#
+# 1xxx errors: Allgemeiner Fehlers
+#
+1000^E^Allgemeiner Fehler: RasDaMan-Tabelle inkonsistent.
+1001^E^Allgemeiner Fehler: RasDaMan-Server ist inkompatibel mit der Datenbank.
+1002^E^Allgemeiner Fehler: Blob mit Null-Länge gefunden.
+1003^E^Allgemeiner Fehler: Kachelcontainer für TC-Index nicht gefunden.
+1004^E^Allgemeiner Fehler: Index des MDD-Objektes ist nicht definiert.
+1005^E^Allgemeiner Fehler: Die Speicherstruktur des MDD-Objektes ist nicht definiert.
+1006^E^Allgemeiner Fehler: Unbekannter Indextyp angefordert.
+1007^E^Allgemeiner Fehler: Illegaler Indextyp ausgewählt.
+1008^E^Allgemeiner Fehler: Kein gültiger Kollektionstyp an MDD-Kollektion geleitet.
+1009^E^Allgemeiner Fehler: MDD-Objekt nicht gültig oder nicht persistent.
+1010^E^Allgemeiner Fehler: Kein gültiger MDD-Typ an MDD-Objekt geleitet.
+1011^E^Allgemeiner Fehler: Ein illegaler Zustand wurde erreicht. Dies wurde durch einen Compiler- oder Bibliotheksfehler verursacht.
+1012^E^Allgemeiner Fehler: Ungültiger Kollektionstyp an MDD-Kollektion geleitet.
+1013^E^Allgemeiner Fehler: Der Name des Typs ist zu lang.
+1014^E^Allgemeiner Fehler: Ungültiges Zeichen in Objektname. Es sollten nur [a-zA-Z0-9_] enthalten sein.
+#
+# 2xxx errors: Interner Fehlers
+#
+2000^E^Interner Fehler: Eine andere Datenbank scheint offen zu sein.
+2001^E^Interner Fehler: Ungültiger OID-Typ wurde gefunden.
+2002^E^Interner Fehler: Eintrag im benutzerdefinierten Typ wurde nicht gefunden.
+2003^E^Interner Fehler: Eintrag in benutzerdefiniertem Typ ist ausserhalb seines Wertebereichs.
+2004^E^Interner Fehler: Transienter Index wurde anstatt des persistenten Indexes benutzt.
+2005^E^Interner Fehler: Index lieferte Kacheln mehrmalig zurück.
+2006^E^Interner Fehler: Kachel wurde nicht in den Index eingefügt.
+2007^E^Interner Fehler: Zugriff auf transientem Index ausserhalb seines Wertesbereiches.
+2008^E^Interner Fehler: MDD-Objekt existiert mehrmalig im Cache.
+2009^E^Interner Fehler: Einige Kacheln wurden nicht in das MDD-Objekt eingefügt.
+2010^E^Interner Fehler: Ein Konvertierungsmodul hat einen inkorrekten Basistyp zurück geliefert.
+2011^E^Interner Fehler: Der Kollektionstyp hat keinen Elementtyp.
+2012^E^Interner Fehler: Der MArray-Typ hat keinen Basistyp.
+2013^E^Interner Fehler: Die Property hat keinen Basistyp.
+2014^E^Interner Fehler: Der Skalar hat einen NULL-Wert übergeben.
+2015^E^Interner Fehler: Der Index-Knotenpunkt, welcher geteilt werden sollte, wurde bei seinem Elterneintrag nicht gefunden.
+2016^E^Interner Fehler: Der Index fand mehr Zellen als erlaubt sind.
+2017^E^Interner Fehler: Die Speicherdarstellung ist inkompatibel mit den Indexeinträgen.
+2018^E^Interner Fehler: Objekt unterstuetzt Speicherauslagerung nicht.
+2019^E^Interner Fehler: Die Speicherauslagerung ist fehlgeschlagen.
+2020^E^Interner Fehler: Binärer Export für Objekt ist nicht unterstützt.
+2021^E^Interner Fehler: Binärer Import für Objekt ist nicht unterstützt.
+#
+# The last, the unexpected error in server
+#
+10000^E^Unerwarteter interner Serverfehler.
diff --git a/bin/errtxts_en b/bin/errtxts_en
new file mode 100644
index 0000000..f96f13f
--- /dev/null
+++ b/bin/errtxts_en
@@ -0,0 +1,276 @@
+208
+# Increment the number above every time you add a new exception
+# (no of error codes - 1)
+#
+# CHANGES:
+# 2003-jul-02 PB corrected some typos in error texts
+# 2003-aug-31 PB corrected some typos in error texts
+# added 830
+# 2003-dec-03 PB added 3000
+# 2005-jun-19 PB added 420, 421, 422
+#
+# This file contains types and textual descriptions of RasDaMan errors.
+# The ascending error numbers are used as index to the descriptions. Each
+# line follows the following syntax:
+#
+# number^type^description.
+#
+# The character '^' is used as delimiter and with '#' a comment line is
+# started. Empty lines are not allowed.
+#
+#
+66^E^Exception: Memory allocation failed.
+100^E^Exception: Internal error: DL parse error.
+200^E^Exception: The result is no point.
+201^E^Exception: The result is no interval.
+202^E^Exception: Index violation ( index range [$low,$high], index $index ).
+203^E^Exception: Dimension mismatch between $dim1 and $dim2.
+204^E^Exception: Stream initialization overflow.
+205^E^Exception: Result is no cell.
+206^E^Serialisable exception r_Ebase_dbms: error in base DBMS.
+207^E^Internal client exception in class $class, method $method: $code.
+208^E^Exception: Access type $aType does not fit base type $bType.
+209^E^Exception: RasType $type is unknown.
+210^E^Exception: Base type $type is not supported yet.
+211^E^Exception: Database is not open.
+212^E^Exception: RPC layer connection to RasDaMan failed.
+213^E^Exception: Wrong URL format (should be http://address:port)
+214^E^Exception: Illegal java long value $val for server base type ULong.
+215^E^Exception: Illegal java integer value $val for server base type UShort.
+216^E^Exception: System collection is not writable.
+217^E^Exception: System collection has no OID.
+218^E^Exception: Conversion format is not supported.
+219^E^Exception: The specified tile size is smaller than the length of the base type of the mdd object.
+220^E^Exception: The tiling strategy in the storage layout is not compatible with the marray.
+221^E^Exception: The domain passed as an argument was not initialised correctly (dimension is 0).
+222^E^Exception: The type name or type structure does not represent a marray type.
+223^E^Exception: The rc index requires a marray type that has a specified domain (with fixed borders in all dimensions).
+224^E^Exception: The tile configuration is incompatible to the marray domain.
+229^E^Exception: The parameterized query has invalid parameter format.
+230^E^Exception: The r_Object was already assigned a type.
+231^E^Exception: The Marray has no base type.
+232^E^Exception: The interval has at least one open bound.
+233^E^Exception: The intervals don't have the same dimension.
+234^E^Exception: The string passed to the tiling object was not correct.
+235^E^Exception: Connection to server already closed.
+236^E^Exception: Error in compression engine
+237^E^Exception: Client communication failure
+238^E^Exception: Base type not supported by conversion/compression module.
+239^E^Exception: Standard overlay using types larger than 16 bytes is not supported.
+240^E^Exception: Insert into a RC index is not allowed.
+241^E^Exception: No tiling defined at that region. Update not possible.
+#
+300^E^Parsing error $errorNo in line $lineNo, column $columnNo: Unexpected name $token.
+301^E^Parsing error $errorNo in line $lineNo, column $columnNo, token $token: All cell values of an MDD must be of the same type.
+302^E^Parsing error $errorNo in line $lineNo, column $columnNo, token $token: Number of cells specified does not match the number of cells of the given spatial domain.
+303^E^Parsing error $errorNo in line $lineNo, column $columnNo, token $token: OId is not valid.
+308^E^Parsing error: Unexpected end of query.
+309^E^Parsing error: Unknown error.
+310^E^Lexical analysing error $errorNo in line $lineNo, column $columnNo: Unexpected characters $token.
+311^E^Parsing error $errorNo in line $lineNo, column $columnNo, token $token: Complex constructor must have both arguments of the same type (i.e. float or double).
+312^E^Parsing error $errorNo in line $lineNo, column $columnNo, token $token: Variable already defined.
+313^E^Parsing error $errorNo in line $lineNo, column $columnNo, token $token: Only constant interval bounds allowed.
+#
+330^E^Preprocessing error $errorNo in line $lineNo, column $columnNo: Unexpected name $token:
+331^E^Preprocessing error $errorNo in line $lineNo, column $columnNo, token $token: attempt to redefine function.
+332^E^Preprocessing error $errorNo in line $lineNo, column $columnNo, token $token: number of actual arguments for the called function differs from the number of formal arguments.
+333^E^Preprocessing error $errorNo in line $lineNo, column $columnNo, token $token: the called function name is ambiguous, try the full qualified name.
+#
+349^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operand out of range.
+350^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: General.
+351^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Spatial domains of the binary induce operands are incompatible.
+352^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operand types are incompatible.
+353^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operand of quantifier must be multidimensional.
+354^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operand of quantifier must be of type r_Marray<d_Boolean>.
+355^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Collection name is unknown.
+356^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Specified domain does not intersect with spatial domain of MDD.
+357^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Variable is unknown.
+358^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Projection operand is not of type r_Marray<T>.
+359^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Result of the where clause must be of type boolean.
+360^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Type of operand is not supported.
+361^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Multiple query targets are not supported.
+362^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Specified domain dimensionality does not equal defined dimensionality of MDD.
+#
+363^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Cell base types of binary induce operation are incompatible.
+364^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Cell base type and scalar type of binary induce operation are incompatible.
+365^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Scalar types of binary operation are incompatible.
+366^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Cell base type of unary induce operation is not supported.
+367^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Scalar type of unary operation is not supported.
+368^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Cell base type for induced dot operation must be complex.
+369^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Scalar type for dot operation must be complex.
+370^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Struct selector is not valid.
+371^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Retrieval query must start with a SELECT statement.
+372^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Update query must start with an INSERT, UPDATE, DELETE, DROP or CREATE statement.
+373^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Unsatisfied MDD constant parameter.
+380^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Data type can not be converted to selected data exchange format.
+381^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Error in convertor of the selected data exchange format.
+382^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Unknown conversion format.
+383^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Parameter of oid function must be a persistent object of type MDD.
+384^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: OId is not valid.
+385^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operation is not supported on strings.
+386^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Base name of oid is not matching the currently opened one.
+387^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: System name of oid is not matching the currently used one.
+388^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Interval bound must be either an integer expression or an asterisk.
+389^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: No interval (in case of fixed bounds, the upper one can not be smaller than the lower one).
+390^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Minterval dimension specifications must be either of type interval or integer.
+391^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Spatial operation must be either of type minterval, point, or integer.
+393^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operand of operation lo/hi must be of type interval.
+394^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operation lo/hi can not be used for an open bound.
+395^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operand of function sdom() must be of type MDD.
+396^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Selection operation is not supported on this data type.
+397^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operand of minterval selection must be of type integer.
+398^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Index for minterval selection is out of range.
+399^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operand of point selection must be of type integer.
+#
+#
+#
+400^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Domain of MDD constructor has to be defined.
+401^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Can not evaluate domain expression to an minterval.
+402^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Projected cell is not defined.
+403^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Binary operation is not supported on these data types.
+404^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Type of cell expression is not supported.
+405^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: First operand of shift function must be of type MDD.
+406^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Second operand of shift function must be of type Point.
+407^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Dimensionality of MDD and point expression are not matching.
+408^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Second operand of shift function must be a constant expression.
+409^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Spatial domain shift of open bounds is not supported.
+#
+#
+#
+410^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operand of point expression must be of type integer.
+411^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Index for point selection is out of range.
+412^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Value expression must be either of type atomic or complex.
+413^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Condition expression must be of type boolean.
+415^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operand of count_cells must be of type r_Marray<d_Boolean>.
+#
+416^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: First operand of scale function must be of type MDD.
+417^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Second operand of scale function must be either of type Point, Integer or Float.
+#
+418^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Second operand of bit function must be of integral type.
+419^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Could not scale the domain.
+420^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Extend operation with open bounds is not supported.
+421^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Target interval of extend operation does not cover MDD to be extended.
+422^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Second operand of extend function must be an minterval.
+#
+499^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Language feature is not supported.
+#
+# 5XX errors for overflow situations
+#
+510^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: The argument is outside the function domain.
+511^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: The function result exceeds the allowed range.
+#
+# 7XX errors for problems with Administration (some Oracle specific)
+#
+700^E^Admin error: General error creating RasDaMan database.
+701^E^Admin error: Error creating table in tablespace RAS_DB_SCHEMA.
+702^E^Admin error: Error inserting into table RAS_COUNTERS.
+703^E^Admin error: Error creating table in tablespace RAS_DB_BLOB.
+704^E^Admin error: Error creating index in tablespace RAS_DB_INDEX.
+705^E^Admin error: Error inserting into table RAS_BASETYPENAMES.
+706^E^Admin error: Error creating table in default tablespace.
+707^E^Admin error: Error on COMMIT creating RasDaMan database.
+708^E^Admin error: Database to be created already exists.
+#
+# 80x errors for RasManager problems
+#
+800^E^RasManager Error: Could not connect to RasServer $url.
+801^E^RasManager Error: System overloaded, please try again later.
+802^E^RasManager Error: Access denied, incorrect user/password.
+803^E^RasManager Error: Access denied, no permission for operation.
+804^E^RasManager Error: Access denied, capability refused.
+805^E^RasManager Error: No suitable servers started, call administrator.
+806^E^RasManager Error: Write transaction in progress, please retry again later.
+807^E^RasManager Error: Requested database unknown.
+808^E^RasManager Error: Request format error.
+#
+# 82x errors for RNP administrative problems
+#
+820^E^RNP Error: First parameter has to be the clientID (clientcomm internal).
+821^E^RNP Error: Client ID invalid, probably a timeout occurred.
+822^E^RNP Error: Unknown command in client request.
+#
+# 83x errors for base DBMS connections
+#
+830^E^base DBMS Error: Cannot connect to base DBMS server (invalid connect string in rasmgr config file?).
+#
+# 9xx errors: Evaluation errors
+#
+900^E^Evaluation error $errorNo in line $lineNo, column $columnNo, near token $token: Type in typedef definition not supported.
+901^E^Evaluation error $errorNo in line $lineNo, column $columnNo, near token $token: Set template type has to be a type reference.
+902^E^Evaluation error $errorNo in line $lineNo, column $columnNo, near token $token: Type reference not found.
+903^E^Evaluation error $errorNo in line $lineNo, column $columnNo, near token $token: MDD base type has to be a type reference or an atomic type.
+904^E^Evaluation error $errorNo in line $lineNo, column $columnNo, near token $token: MDD type must have a domain specification.
+905^E^Evaluation error $errorNo in line $lineNo, column $columnNo, near token $token: Struct type name exists already.
+906^E^Evaluation error $errorNo in line $lineNo, column $columnNo, near token $token: MDD type name exists already.
+907^E^Evaluation error $errorNo in line $lineNo, column $columnNo, near token $token: Set type name exists already.
+#
+950^E^Update error $errorNo in line $lineNo, column $columnNo, near token $token: Update target must be an iterator variable.
+951^E^Update error $errorNo in line $lineNo, column $columnNo, near token $token: Update source must be an expression resulting in an r_Marray<>.
+952^E^Update error $errorNo in line $lineNo, column $columnNo, near token $token: Update base type does not match MDD base type.
+953^E^Update error $errorNo in line $lineNo, column $columnNo, near token $token: Update domain is not within MDD definition domain.
+954^E^Update error $errorNo in line $lineNo, column $columnNo, near token $token: Update target expression must be an assignable value (l-value).
+955^E^Update error $errorNo in line $lineNo, column $columnNo, near token $token: Collection name exists already.
+956^E^Update error $errorNo in line $lineNo, column $columnNo, near token $token: Unknown collection type.
+957^E^Update error $errorNo in line $lineNo, column $columnNo, near token $token: Unknown collection name.
+958^E^Update error $errorNo in line $lineNo, column $columnNo, near token $token: Allocation of new oid failed.
+959^E^Update error $errorNo in line $lineNo, column $columnNo, near token $token: MDD and collection types are incompatible.
+960^E^Update error $errorNo in line $lineNo, column $columnNo, near token $token: Insert expression must be of type MDD.
+961^E^Update error $errorNo in line $lineNo, column $columnNo, near token $token: Update domain must be of type Minterval.
+962^E^Update error $errorNo in line $lineNo, column $columnNo, near token $token: Number of update intervals must match source dimensionaltiy.
+963^E^Update error $errorNo in line $lineNo, column $columnNo, near token $token: Update domain dimensionality must match target MDD dimensionaltiy.
+964^E^Update error $errorNo in line $lineNo, column $columnNo, near token $token: Type is not persistent.
+965^E^Update error $errorNo: MDD type $token unknown.
+966^E^Update error $errorNo: MDD type is missing.
+#
+# 1xxx errors: General errors
+#
+1000^E^General error: RasDaMan tables inconsistent.
+1001^E^General error: RasDaMan server incompatible with database.
+1002^E^General error: Blob with zero length encountered.
+1003^E^General error: Tile container for TC index not found.
+1004^E^General error: Index of MDD Object is not defined.
+1005^E^General error: Storage structure of MDD Object is not defined.
+1006^E^General error: Unknown index type requested.
+1007^E^General error: Illegal index type requested.
+1008^E^General error: No valid collection type passed to MDD collection.
+1009^E^General error: MDD object not valid or not persistent.
+1010^E^General error: No valid MDD type passed to MDD object.
+1011^E^General error: An illegal state has been reached. This is caused by a compiler bug or a library bug.
+1012^E^General error: Invalid collection type passed to MDD collection.
+1013^E^General error: The name of the type is too long.
+1014^E^General error: Invalid name of the object, should contain only [a-zA-Z0-9_]
+#
+# 2xxx errors: Internal errors
+#
+2000^E^Internal error: There seems to be another database open.
+2001^E^Internal error: Invalid OId type encountered.
+2002^E^Internal error: Entry in user defined type not found.
+2003^E^Internal error: Entry in user defined type out of bounds.
+2004^E^Internal error: Transient index used instead of persistent index.
+2005^E^Internal error: Index returned tiles multiple times.
+2006^E^Internal error: Tile was not inserted into index.
+2007^E^Internal error: Transient index access out of bounds.
+2008^E^Internal error: MDD object exists multiple times in cache.
+2009^E^Internal error: Some tile(s) were not inserted into the MDD object.
+2010^E^Internal error: A conversion module returned an incorrect base type.
+2011^E^Internal error: The collection type has no element type.
+2012^E^Internal error: The marray type has no base type.
+2013^E^Internal error: The property has no base type.
+2014^E^Internal error: The scalar was passed a NULL value.
+2015^E^Internal error: The index node that had to be split was not found in its parent.
+2016^E^Internal error: The index found more cells than allowed.
+2017^E^Internal error: The storage layout is incompatible with the index entries.
+2018^E^Internal error: Object does not support swapping.
+2019^E^Internal error: Error encountered during swapping.
+2020^E^Internal error: Binary export for object is not supported.
+2021^E^Internal error: Binary import for object is not supported.
+2022^E^Internal error: Operands and result types don't match.
+#
+# 3xxx errors: Data format conversion errors
+#
+3000^E^Format conversion error: DEM area does not contain any non-null value, empty result generated.
+
+#
+# The last, the unexpected error in server
+#
+10000^E^Unexpected internal server error.
diff --git a/bin/errtxts_fr b/bin/errtxts_fr
new file mode 100644
index 0000000..f26d4b3
--- /dev/null
+++ b/bin/errtxts_fr
@@ -0,0 +1,267 @@
+205
+# Increment the number above every time you add a new exception
+# (no of error codes - 1)
+#
+# CHANGES:
+# 2003-jun-28 PB created from Didier Richard's translation (thanks!)
+# added 420, 421, 422
+#
+# This file contains types and textual descriptions of RasDaMan errors.
+# The ascending error numbers are used as index to the descriptions. Each
+# line follows the following syntax:
+#
+# number^type^description.
+#
+# The character '^' is used as delimiter and with '#' a comment line is
+# started. Empty lines are not allowed.
+#
+#
+66^E^Exception: echec de l'allocation memoire.
+100^E^Exception: erreur interne: erreur d'analyse DL.
+200^E^Exception: le resultat n'est pas un point.
+201^E^Exception: le resultat n'est pas un intervalle.
+202^E^Exception: violation d'index ( intervalle d'index [$low,$high], index $index ).
+203^E^Exception: incoherence des Dimension entre $dim1 et $dim2.
+204^E^Exception: Bourage du flux d'ecriture.
+205^E^Exception: le resultat n'est pas une cellule.
+206^E^Exception d'ecriture r_Ebase_dbms: erreur dans la base DBMS.
+207^E^Exception du client interne pour la classe $class, methode $method: $code.
+208^E^Exception: type d'acces $aType ne correspond au type de la base $bType.
+209^E^Exception: RasType $type est inconnu.
+210^E^Exception: Type de base $type n'est pas encore supporte.
+211^E^Exception: base de donnees non accessible.
+212^E^Exception: Connexion a la couche RPC de RasDaMan echouee.
+213^E^Exception: Fromat d'URL incorrect (devrait etre http://address:port)
+214^E^Exception: Valeur illegale du type java long $val pour le type de la base ULong.
+215^E^Exception: Valeur illegale du type java integer $val pour le type de la base UShort.
+216^E^Exception: La collection systeme n'est pas inscriptible.
+217^E^Exception: La collection systeme n'a pas d'identificateur.
+218^E^Exception: Conversion de format non supportee.
+219^E^Exception: La taille specifiee pour la dalle est plus petite que la longueur du type de la base mdd.
+220^E^Exception: La strategie de dallage pour le stockage de la couche n'est pas compatible avec marray.
+221^E^Exception: Le domaine fourni comme argument n'a pas ete initialise correctement (dimension vaut 0).
+222^E^Exception: Le type name ou structure ne represente pas un type marray.
+223^E^Exception: L'index rc necessite un type marray qui a un domaine specifie (avec the bordure fixees dans toutes les dimensions).
+224^E^Exception: La configuration du dallage est incompatible avec le domaine marray.
+229^E^Exception: Le parametre format de la requete est invalide.
+230^E^Exception: Le r_Object a deja ete affecte a un type.
+231^E^Exception: Le Marray n'a pas de type de base.
+232^E^Exception: L'intervalle est semi-ouvert.
+233^E^Exception: Les intervalles n'ont pas la meme dimension.
+234^E^Exception: La chaine fournie pour la dalle n'est pas correcte.
+235^E^Exception: La connexion au serveur a deja ete fermee.
+236^E^Exception: Erreur dans le moteur de compression
+237^E^Exception: Echec dans la communication avec le client
+238^E^Exception: Type de base non supporte par le module de conversion/compression.
+239^E^Exception: Superposition standard utilisant des types plus grand que 16 octets non supportee.
+240^E^Exception: Insertion dans l'index RC n'est pas autorisee.
+241^E^Exception: Aucun dallage fourni pour cette zone. Mise a jour impossible.
+#
+300^E^Erreur d'analyse $errorNo a la ligne $lineNo, colonne $columnNo: mot inattendu $token.
+301^E^Erreur d'analyse $errorNo a la ligne $lineNo, colonne $columnNo, mot $token: toutes les valeurs de cellule d'un MDD doivent etre du meme type.
+302^E^Erreur d'analyse $errorNo a la ligne $lineNo, colonne $columnNo, mot $token: le nombre de cellule specifie ne correspond as au nombre de cellules du domaine spatial fourni.
+303^E^Erreur d'analyse $errorNo a la ligne $lineNo, colonne $columnNo, mot $token: l'identificateur n'est pas valide.
+308^E^Erreur d'analyse: fin de requere inattendu
+309^E^Erreur d'analyse: erreur inconnue.
+310^E^Erreur d'analyse lexicale $errorNo a la ligne $lineNo, colonne $columnNo: caracteres inattendus $token.
+311^E^Erreur d'analyse $errorNo a la ligne $lineNo, colonne $columnNo, token $token: le constructeur complexe doivent avoir ses deux arguments du meme type (i.e. float ou double).
+312^E^Erreur d'analyse $errorNo a la ligne $lineNo, colonne $columnNo, token $token: Variable deja definie.
+313^E^Erreur d'analyse $errorNo a la ligne $lineNo, colonne $columnNo, token $token: seules des valeurs contantes d'intervalle sont acceptees.
+#
+330^E^Erreur de pre-traitement $errorNo a la ligne $lineNo, colonne $columnNo: mot inattendu $token:
+331^E^Erreur de pre-traitement $errorNo a la ligne $lineNo, colonne $columnNo, mot $token: atentative de redefinition d'une fonction.
+332^E^Erreur de pre-traitement $errorNo a la ligne $lineNo, colonne $columnNo, mot $token: nombre de parametres actuels pour la fonction appelee distincts du nombre parametres formels.
+333^E^Erreur de pre-traitement $errorNo a la ligne $lineNo, colonne $columnNo, mot $token: la fonction appeles est ambigue, essaie avec le nom pleienement qualifie.
+#
+349^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: depassement de capacite de l'operande.
+350^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: General.
+351^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: domaines spatiaux du binaire induits par les operandes sont incompatibles.
+352^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: type d'operandes incompatibles.
+353^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: l'operande du quantifieur doit etre multidimensionnel.
+354^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: l'operande du quantifieur doit etre du type r_Marray<d_Boolean>.
+355^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: nom de la collection inconnu.
+356^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: le domaine specifie n'intersecte pas le domaine spatial du MDD.
+357^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: Variable inconnue.
+358^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: l'operande de la projection n'est pas du type r_Marray<T>.
+359^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: resultat du clause where doit etre du type boolean.
+360^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: type d'operande non supporte.
+361^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: resultats de requete multiple non supportes.
+362^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: la dimension du domaine specifie n'est pas egale a celle du MDD.
+#
+363^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: les types des cellules induisent que l'operation binaire est incompatible.
+364^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: le type de cellule et le type scalaire induisent que l'operation binaire est incompatible.
+365^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: les types scalaire de l'operation binaire sont incompatible.
+366^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: le type de cellule d'une operation binaire unaire n'est pas supporte.
+367^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: le type scalaire d'une operation binaire unaire n'est pas supporte.
+368^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: le type de cellule pour l'operation doit etre complexe.
+369^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: le type scalaire pour l'operation doit etre complexe.
+370^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: selecteur de structure invalide.
+371^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: une recherche doit debuter par le mot clef SELECT.
+372^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: une mise a jour doit debuter avec l'un des mots clefs suivants INSERT, UPDATE, DELETE, DROP ou CREATE.
+373^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: parametre constant MDD non satisfait.
+380^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: Les donnees ne peuvent pas etre converties dans le format selectionne.
+381^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: Erreur dans la conversion dans le format selectionne.
+382^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: Format de conversion inconnu.
+383^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: Le parametre de la fonction oid dans etre un parametre de type MDD persistant.
+384^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: L'identificateur n'est pas valide.
+385^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: L'operation n'est pas supportee sur des chaines de caracteres.
+386^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: L'espace de nommage des identificateurs ne correspond pas a celui couramment ouvert.
+387^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: Le systeme de nommage des identificateurs ne correspond pas a celui en cours.
+388^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: La borne doit etre soit une expression entiere soit *.
+389^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: Aucun intervalle (dans le cas de bornes fixes, la borne superieure doit etre plus grande que la borne inferieure).
+390^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: Les specifications de la dimension Minterval doivent etre de type interval ou integer.
+391^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: iL'operation spatiale doit etre de l'un des types suivants : minterval, point, ou integer.
+393^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: L'operande de l'operation lo/hidoit etre de type interval.
+394^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: L'operation lo/hi ne peut pas etre utilisee sur un intervalle ouvert.
+395^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: l'operande de la fonction sdom() doit etre de type MDD.
+396^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: L'operation de selection n'est pas supportee sur ce type de donnees.
+397^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: L'operande de la selection minterval doit etre de type integer.
+398^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: L'index de la secltion minterval est hors des bornes.
+399^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: L'operand de la selection point doit etre de type integer.
+#
+#
+#
+400^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: Le domaine du constructor de MDD doit etre defini.
+401^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: Impossible d'evaluer l'expression domain en minterval.
+402^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: La cellule projetee n'est pas definie.
+403^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: L'operation binaire n'est pas supportee sur ces types de donnees.
+404^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: Le type d'expression cell n'est pas supporte.
+405^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: Le premier operande de la fonction shift doit etre de type MDD.
+406^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: Le second operande de la fonction shift doit etre de type Point.
+407^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: Les dimensions du MDD et du point ne correspondent pas.
+408^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: Le second operande de la fonction shift doit etre une exporession constante.
+409^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: Le deplacement d'un domaine spatial sur un intervalle ouvert n'est pas supporte.
+#
+#
+#
+410^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: L'operande d'une expression point doit etre de type integer.
+411^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: L'index d'une selection de point selection est hors intervalle.
+412^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: La valeur de l'expression doit etre soit de type atomic, soit complex.
+413^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: l'expression conditionnelle doit etre de type boolean.
+415^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: L'operande de count_cells doit etre de type r_Marray<d_Boolean>.
+#
+416^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: Le premier operande de la fonction scale function doit etre de type MDD.
+417^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: Le second operande de la fonction scale doit etre de l'un des types suivants : Point, Integer ou Float.
+#
+418^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: Le second operande d'une fonction bit a bit doit etre de type entier.
+419^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: Impossible de mettre le domaine a l'echelle.
+#
+499^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: Le concept Language n'est pas supporte.
+#
+510^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: L'argument est hors du domaine de la fonction.
+511^E^Erreur d'execution $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: Le resultat de la fonction depasse l'intervalle autorise.
+#
+# 7XX errors for problems with Administration (some Oracle specific)
+#
+700^E^Erreur d'administration: General error creating RasDaMan database.
+701^E^Erreur d'administration: Error creating table in tablespace RAS_DB_SCHEMA.
+702^E^Erreur d'administration: Error inserting into table RAS_COUNTERS.
+703^E^Erreur d'administration: Error creating table in tablespace RAS_DB_BLOB.
+704^E^Erreur d'administration: Error creating index in tablespace RAS_DB_INDEX.
+705^E^Erreur d'administration: Error inserting into table RAS_BASETYPENAMES.
+706^E^Erreur d'administration: Error creating table in default tablespace.
+707^E^Erreur d'administration: Error on COMMIT creating RasDaMan database.
+708^E^Erreur d'administration: Database to be created already exists.
+#
+# 80x errors for RasManager problems
+#
+800^E^Erreur de RasManager: Impossible de se connecter a RasServer $url.
+801^E^Erreur de RasManager: Systeme surcharge, re-essayer plus tard.
+802^E^Erreur de RasManager: Acces refuse, utilisateur/mot de passe incorrect.
+803^E^Erreur de RasManager: Acces refuse, aucune permission pour l'operation.
+804^E^Erreur de RasManager: Acces refuse a la description des metadonnees.
+805^E^Erreur de RasManager: Aucun serveur trouve, contacter l'administrateur.
+806^E^Erreur de RasManager: Transaction d'ecriture en cours, re-essayer plus tard.
+807^E^Erreur de RasManager: Base de donnees inconnue.
+808^E^Erreur de RasManager: Demande de format en erreur.
+#
+# 82x errors for RNP administrative problems
+#
+820^E^Erreur RNP: Le premier parametre doit etre le client ID (clientcomm interne).
+821^E^Erreur RNP: Client ID invalide, un depassement s'est probablement passe.
+822^E^Erreur RNP: Commande inconnue pour la requete au client.
+#
+# 83x errors for base DBMS connections
+#
+830^E^Erreur DBMS: Impossible de se connecter a serveur RDBMS (chaine de connexion incorrecte dans le configuration?).
+#
+# 9xx errors: Evaluation errors
+#
+900^E^Erreur d'evaluation $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: Type de la definition typedef non supporte.
+901^E^Erreur d'evaluation $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: Le type de l'ensemble generique doit etre un type reference.
+902^E^Erreur d'evaluation $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: Type reference non trouve.
+903^E^Erreur d'evaluation $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: Le type de base MDD doit etre un type reference ou un type atomique.
+904^E^Erreur d'evaluation $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: Le type MDD doit avoir un domaine de specification.
+905^E^Erreur d'evaluation $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: Structure deja existante.
+906^E^Erreur d'evaluation $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: Type MDD deja existant.
+907^E^Erreur d'evaluation $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: Type d'ensemble deja existant.
+#
+950^E^Erreur de mise a jour $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: La cible de mise a jour doit etre une variable iterator.
+951^E^Erreur de mise a jour $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: La source de mise a jour doit etre un expression r_Marray<>.
+952^E^Erreur de mise a jour $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: Le type de mise a jour ne correspond pas au type MDD.
+953^E^Erreur de mise a jour $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: Le domaine de mise a jour n'est pas dans le domaine de definition du MDD.
+954^E^Erreur de mise a jour $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: L'expression de mise a jour doit etre une l-value (affectable).
+955^E^Erreur de mise a jour $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: Le nom de la collection existe deja.
+956^E^Erreur de mise a jour $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: Type de la collection inconnu.
+957^E^Erreur de mise a jour $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: Nom de la collection inconnu.
+958^E^Erreur de mise a jour $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: Allocation d'un nouvel identificateur echouee.
+959^E^Erreur de mise a jour $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: Les types MDD et collection sont incompatibles.
+960^E^Erreur de mise a jour $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: L'expression d'insertion doit etre de type MDD.
+961^E^Erreur de mise a jour $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: Le domaine de mise a juor doit etre de type Minterval.
+962^E^Erreur de mise a jour $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: Le nombre d'intervalles de mise a jour doit correspondre aux dimensions de la source.
+963^E^Erreur de mise a jour $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: La dimension du domaine de mise a jour doit correspondre aux dimensions du MDD cible.
+964^E^Erreur de mise a jour $errorNo a la ligne $lineNo, colonne $columnNo, proche du mot $token: Type non persistant.
+965^E^Erreur de mise a jour: MDD type $token unknown.
+966^E^Erreur de mise a jour: MDD type is missing.
+#
+# 1xxx errors: General errors
+#
+1000^E^Erreur generale: Tables RasDaMan inconsistantes.
+1001^E^Erreur generale: Serveur RasDaMan incompatible avec le serveur RDBMS.
+1002^E^Erreur generale: Blob vide retourne.
+1003^E^Erreur generale: Tuile d'index TC non trouvee.
+1004^E^Erreur generale: Index de l'objet MDD non defini.
+1005^E^Erreur generale: Structure de stockage de l'objet MDD non definie.
+1006^E^Erreur generale: Type d'index demande inconnu.
+1007^E^Erreur generale: Type d'index demande invalide.
+1008^E^Erreur generale: Aucun collection valide fournie a la collection MDD.
+1009^E^Erreur generale: Objet MDD non valide ou non persistant.
+1010^E^Erreur generale: Aucun type MDD valide fourni a l'objet MDD.
+1011^E^Erreur generale: Etat de calcul illegal (Boggue du compilateur ou de la bibliotheque).
+1012^E^Erreur generale: Type de collection fourni a la collection MDD invalide.
+1013^E^Erreur generale: Le nom du type est trop long.
+1014^E^Erreur generale: Le nom de l'objet est invalide, il ne peut contenir que [a-zA-Z0-9_]
+#
+# 2xxx errors: Internal errors
+#
+2000^E^Erreur interne Il semble qu'un autre RDBMS soit ouvert.
+2001^E^Erreur interne Type d'identificateur invalide.
+2002^E^Erreur interne Type utilisateur non trouve.
+2003^E^Erreur interne Type utilisateur hors de l'intervalle.
+2004^E^Erreur interne Index volatile utilise au lieu d'un index persistant.
+2005^E^Erreur interne L'index renvoie des tuiles a plusieurs reprises.
+2006^E^Erreur interne Tuile non inseree dans l'index.
+2007^E^Erreur interne Acces hors de l'intervalle d'un index volatile.
+2008^E^Erreur interne L'objet MDD existe plusieurs fois dans le cache.
+2009^E^Erreur interne Ceraine(s) tuile(s) n'ont pas ete inserees dans l'objet MDD.
+2010^E^Erreur interne Un module de conversion a retourne un type de base incorrect.
+2011^E^Erreur interne Le type collection n'a aucun element.
+2012^E^Erreur interne Le type marray type n'a pas de type de base.
+2013^E^Erreur interne L'attribut n'a pas de type de base.
+2014^E^Erreur interne La valeur scalaire est NULL.
+2015^E^Erreur interne Le noeud de l'index qui a fragmente n'a ete retrouve dans son noeud pere.
+2016^E^Erreur interne L'index a retourn plus de cellules qu'autorise.
+2017^E^Erreur interne La couche de stockage est incompatible avec les entrees de l'index.
+2018^E^Erreur interne L'objet ne supporte pas le swapping.
+2019^E^Erreur interne Erreur lors d'un swapping.
+2020^E^Erreur interne L'export binaire de l'objet n'est pas supporte.
+2021^E^Erreur interne L'import binaire de l'objet n'est pas supporte.
+#
+# 3xxx errors: Data format conversion errors
+#
+3000^E^Erreur de conversionde format: la zone MNE contient des valeurs nulles, une resultat vide a ete genere.
+
+#
+# The last, the unexpected error in server
+#
+10000^E^Erreur interne du serveur inattendue.
diff --git a/bin/rasdaman b/bin/rasdaman
new file mode 100644
index 0000000..4c39306
--- /dev/null
+++ b/bin/rasdaman
@@ -0,0 +1,114 @@
+#! /bin/sh
+#
+# rasdaman - boot time start/stop script
+#
+# SYNOPSIS
+# rasdaman [start|stop|restart]
+#
+# DESCRIPTION
+# Boot script to launch/terminate rasdaman, to go into
+# the init directory.
+# Install as /etc/init.d/rasdaman and a symlink to it
+# as /sbin/rcrasdaman. Link to it from the appropriate
+# runlevel directories (usually rc3.d and rc5.d).
+# Make sure that the base DBMS is launched well before
+# rasdaman during boot time, and stopped well before
+# at shutdown time.
+#
+# RETURN VALUES:
+# 0 rasdaman server found, is up & running
+# 1 rasdaman server not found
+# 2 error
+#
+# COMMENTS:
+# - uses start_rasdaman.sh and stop_rasdaman.sh in ~rasdaman/bin/
+#
+# Copyright (c) 2003 rasdaman GmbH
+#
+#
+### BEGIN INIT INFO
+# Provides: rasdaman
+# Required-Start: $remote_fs $syslog
+# Required-Stop: $remote_fs $syslog
+# Default-Start: 3 5
+# Default-Stop: 0 1 2 6
+# Description: Start rasdaman and oracle.
+### END INIT INFO
+
+# Source SuSE config
+. /etc/rc.config
+
+# Determine the base and follow a runlevel link name.
+base=${0##*/}
+link=${base#*[SK][0-9][0-9]}
+
+# Force execution if not called by a runlevel directory.
+test $link = $base && START_RASDAMAN=yes
+test "$START_RASDAMAN" = yes || exit 0
+
+# Shell functions sourced from /etc/rc.status:
+# rc_check check and set local and overall rc status
+# rc_status check and set local and overall rc status
+# rc_status -v ditto but be verbose in local rc status
+# rc_status -v -r ditto and clear the local rc status
+# rc_failed set local and overall rc status to failed
+# rc_failed <num> set local and overall rc status to <num><num>
+# rc_reset clear local rc status (overall remains)
+# rc_exit exit appropriate to overall rc status
+. /etc/rc.status
+
+# First reset status of this service
+rc_reset
+
+# Return values acc. to LSB for all commands but status:
+# 0 - success
+# 1 - generic or unspecified error
+# 2 - invalid or excess argument(s)
+# 3 - unimplemented feature (e.g. "reload")
+# 4 - insufficient privilege
+# 5 - program is not installed
+# 6 - program is not configured
+# 7 - program is not running
+#
+# Note that starting an already running service, stopping
+# or restarting a not-running service as well as the restart
+# with force-reload (in case signalling is not supported) are
+# considered a success.
+
+case "$1" in
+ start)
+ echo -n "Starting rasdaman"
+ ## Start daemon with startproc(8). If this fails
+ ## the echo return value is set appropriate.
+
+ # NOTE: startproc return 0, even if service is
+ # already running to match LSB spec.
+ su - rasdaman -c '$HOME/bin/start_rasdaman.sh'
+ # Remember status and be verbose
+ rc_status -v
+ ;;
+ stop)
+ echo -n "Shutting down rasdaman"
+ ## Stop daemon with killproc(8) and if this fails
+ ## set echo the echo return value.
+ su - rasdaman -c '$HOME/bin/stop_rasdaman.sh'
+
+ # Remember status and be verbose
+ rc_status -v
+ ;;
+ restart)
+ echo -n "Restarting rasdaman"
+ ## Like force-reload, but if daemon does not support
+ ## signalling, do nothing (!)
+
+ # If it supports signalling:
+ echo -n "Reload service rasdaman"
+ $0 stop && (sleep 5; $0 start)
+ rc_status -v
+ ;;
+ *)
+ echo "Usage: $0 {start|stop|restart}"
+ exit 1
+ ;;
+esac
+rc_exit
diff --git a/bin/rasmgr.conf.in b/bin/rasmgr.conf.in
new file mode 100644
index 0000000..6df0571
--- /dev/null
+++ b/bin/rasmgr.conf.in
@@ -0,0 +1,62 @@
+# ----------------------------------------------------------------------------
+#
+# rasmgr.conf.template: rasmgr configuration file sample
+#
+# PURPOSE:
+# define server processes for rasdaman;
+# this configuration file is read by rasmgr upon system start;
+# settings can be changed during runtime via rascontrol.
+# Adapt it and rename it to rasmgr.conf in directory $RMANHOME
+# (which usually will be ~rasdaman).
+#
+# COMMENTS:
+# - this is a sample file and will NOT WORK
+# in your environment without adaptation!
+# - do not edit while rasmgr is running, may be overwritten!
+# - see Installation Guide for a complete list of options
+#
+# Copyright (c) 2005 rasdaman GmbH
+# ----------------------------------------------------------------------------
+
+# define symbolic name for database host
+# the MYHOST name is just a symbolic one, does not have to correspond with
+# any ame outside rasdaman; however MUST NOT BE EQUAL to any other name used
+# in this file!
+# parameters:
+# -connect c server connect information (RDBMS login, database
+# name, or similar - depends on the base DBMS used;
+# eg, can be "/" for Oracle, "RASBASE" for PostgreSQL)
+define dbh rasdaman_host -connect RASBASE
+# define database
+# parameters:
+# -dbh d this database's server runs on host d
+define db RASBASE -dbh rasdaman_host
+
+# define a rasdaman database server process with name N1
+# parameters:
+# -host h name of the host machine the server runs on
+# (cf: man 1 hostname)
+# -type t communication protocol type is t
+# (one of: 'r' for RPC, 'h' for HTTP, 'n' for RNP);
+# recommended: use 'n', all others are deprecated
+# -port p port number for contacting this server is p
+# (rasmgr by default uses 7001, so you may simply count up)
+# -dbh d use database host d (see "define dbh" for allowed names)
+define srv N1 -host @hostname@ -type n -port 7002 -dbh rasdaman_host
+# change settings for this server
+# parameters:
+# -countdown n server will automatically restart after n requests
+# (beware of long-running transactions!)
+# -autorestart r r is on or off; if on, automatically restart server
+# upon any termination (recommended: on)
+# -xp p "extra parameters" passed to the rasserver binary as is
+# (see rasserver -h); all up to end of line, including
+# all whitespace, will be packed into p.
+# In particular (like in the example here) you can
+# provide a specific timeout in seconds determining
+# after how many seconds of inactivity the server will
+# detach from the client, aborting any open transaction
+change srv N1 -countdown 1000 -autorestart on -xp --timeout 300
+
+# end of rasmgr.conf.template
+
diff --git a/bin/start_rasdaman.sh.in b/bin/start_rasdaman.sh.in
new file mode 100644
index 0000000..de564dd
--- /dev/null
+++ b/bin/start_rasdaman.sh.in
@@ -0,0 +1,123 @@
+#!/bin/bash
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+#
+
+#
+# start_rasdaman.sh - start rasdaman server complex
+#
+# SYNTAX
+# start_rasdaman.sh [servers...]
+#
+# DESCRIPTION
+# This script starts rasdaman.
+# Which rasdaman servers are started depends on the 'server' name(s) provided:
+# * If no server name is provided then the environment variable $RASSERVERS is
+# inspected to obtain a list of servers to be started. If $RASSERVERS is not
+# set, then all rasdaman servers defined will be attempted to start.
+# * If at least one parameter is provided then all parameters
+# will be treated as a server name which is tried to be started.
+#
+# One possible reason while not all servers may come up is that more servers
+# might be defined than your licence model allows to run in parallel.
+#
+# To log in to the server, the external variable $RASLOGIN is expected to hold
+# an ID string (see rasdaman manual). If not found, a desperate last attempt is
+# made to login as rasadmin/rasadmin. If this fails, no servers are started at all.
+#
+# PRECONDITIONS
+# - need to have a rasdaman admin login either from $RASLOGIN or as rasadmin/rasadmin
+# - need to have an id that allows to write into $RMANHOME/log
+# - need to have a valid rasdaman installation + key
+#
+# RETURN CODES
+ RC_OK=0 # everything went fine
+ RC_ERROR=1 # something went wrong
+
+# --- CONSTANTS -----------------------------------------------------
+
+# sleep time to let rasmgr establish before spawning servers
+WAIT_FOR_CHILDREN=5
+
+# get script name
+MYNAME=`basename $0`
+
+# error messages:
+ERROR_PARAM="ERS001 Error: illegal parameter: $1"
+
+# --- END CONSTANTS -------------------------------------------------
+
+# --- ACTION --------------------------------------------------------
+
+echo $MYNAME: starting rasdaman server complex...
+
+# --- start rasmgr: -------------------------------------------------
+
+# here we want to put all log files
+cd @logdir@
+
+# clear previous log file
+rm -f nohup.out
+
+# start rasdaman server manager as demon; log will go into nohup.out
+nohup @bindir@rasmgr & 2>&1
+
+# --- start servers: -------------------------------------------------
+
+# allow process to establish
+sleep $WAIT_FOR_CHILDREN
+
+# these servers will be started:
+if [ $1 ]
+then
+ # parameters provided, take them as server names
+ SERVERS=$*
+else
+ if [ "$RASSERVERS" ]; then
+ SERVERS=$RASSERVERS
+ else
+ SERVERS=""
+ fi
+fi
+
+# determine rascontrol login
+if [ -z "$RASLOGIN" ]; then
+ export RASLOGIN=rasadmin:d293a15562d3e70b6fdc5ee452eaed40
+fi
+
+# ...then spawn server workers
+if [ "$SERVERS" ]; then
+ for SRV in $SERVERS
+ do
+ echo -n $MYNAME: starting server $SRV...
+ @bindir@rascontrol -e -q -x up srv $SRV || exit $!
+ done
+else
+ echo $MYNAME: starting all rasdaman servers...
+ @bindir@rascontrol -e -q -x up srv -all || exit $!
+fi
+
+echo $MYNAME: done.
+exit $RC_OK
+
+# --- END ACTION ----------------------------------------------------
+
diff --git a/bin/stop_rasdaman.sh.in b/bin/stop_rasdaman.sh.in
new file mode 100644
index 0000000..90c99a9
--- /dev/null
+++ b/bin/stop_rasdaman.sh.in
@@ -0,0 +1,88 @@
+#!/bin/bash
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+#
+#
+# stop_rasdaman.sh - shut down rasdaman server complex
+#
+# SYNTAX
+# stop_rasdaman.sh
+#
+# DESCRIPTION
+# This script terminates rasdaman.
+# First, all server processes are terminated. Then, the server
+# manager (rasmgr) is shut down.
+# To log in to the server, the external variable $RASLOGIN is expected to hold
+# an ID string (see rasdaman manual). If not found, a desperate last attempt is
+# made to login as rasadmin/rasadmin. If this fails, no servers are stopped at all.
+#
+# BE CAREFUL
+# By terminating rasdaman, all open transactions are aborted,
+# and their contents will be irretrievably lost!
+#
+# PRECONDITIONS
+# - need to have a rasdaman admin login either from $RASLOGIN or as rasadmin/rasadmin
+# - no open transactions or databases, they will be killed and transactions aborted
+#
+
+# --- CONSTANTS -----------------------------------------------------
+
+MYNAME=`basename $0`
+
+# --- END CONSTANTS -------------------------------------------------
+
+# --- ACTION --------------------------------------------------------
+
+echo $MYNAME: terminating all rasdaman servers
+
+# --- stop rasdaman servers: ---------------------------------------
+
+if [ -z "$RASLOGIN" ]; then
+ export RASLOGIN=rasadmin:d293a15562d3e70b6fdc5ee452eaed40
+fi
+
+# determine a list of all currently running servers
+ALLSERVERS=`@bindir@rascontrol -e -q -x list srv | awk '{ if (\$6 == "UP") print \$2;}'`
+
+# ...and shut down all of them, forcefully (!); any open transaction will be lost
+for SRV in $ALLSERVERS
+do
+ echo -n $MYNAME: terminating server $SRV...
+ @bindir@rascontrol -e -q -x down srv $SRV -kill
+ echo "done."
+done
+
+# --- stop rasmgr: -------------------------------------------------
+
+# give rasserver processes time to disappear
+sleep 2
+
+# finally shut down thes server manager
+echo -n "terminating rasdaman server manager(s)..."
+@bindir@rascontrol -e -q -x down host -all
+echo "done."
+
+# --- END ACTION ----------------------------------------------------
+
+echo $MYNAME: done.
+exit $RC_OK
+
diff --git a/catalogmgr/Makefile.am b/catalogmgr/Makefile.am
new file mode 100644
index 0000000..b7b8c08
--- /dev/null
+++ b/catalogmgr/Makefile.am
@@ -0,0 +1,43 @@
+# -*-Makefile-*- (for Emacs)
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+#
+# MAKEFILE FOR:
+# catalogmgr
+#
+# COMMENTS:
+#
+##################################################################
+
+
+RMANBASE=@abs_top_srcdir@
+BASEDBCXXFLAGS=@BASEDBCXXFLAGS@
+BASEDBLDFLAGS=@BASEDBLDFLAGS@
+
+AM_CXXFLAGS= $(BASEDBCXXFLAGS)
+AM_LDFLAGS= $(BASEDBLDFLAGS)
+
+# object files to put in library
+noinst_LIBRARIES=libcatalogmgr.a
+libcatalogmgr_a_SOURCES=ops.cc typefactory.cc algebraops.cc ops.hh \
+ typefactory.hh algebraops.hh autogen_ops.hh
+EXTRA_libcatalogmgr_a_SOURCES = autogen_ops.cc
+
diff --git a/catalogmgr/algebraops.cc b/catalogmgr/algebraops.cc
new file mode 100644
index 0000000..559a797
--- /dev/null
+++ b/catalogmgr/algebraops.cc
@@ -0,0 +1,172 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/*************************************************************
+ *
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)qlparser, QLMarrayOp, QLCondenseOp: $Header: /home/rasdev/CVS-repository/rasdaman/catalogmgr/algebraops.cc,v 1.5 2003/12/20 23:41:27 rasdev Exp $";
+
+#include "raslib/rmdebug.hh"
+
+#include "algebraops.hh"
+
+#include "qlparser/qtoperation.hh"
+#include "qlparser/qtdata.hh"
+#include "qlparser/qtpointdata.hh"
+#include "qlparser/qtscalardata.hh"
+#include "qlparser/qtatomicdata.hh"
+
+#include "relcatalogif/basetype.hh"
+
+QLMarrayOp::QLMarrayOp( QtOperation* newCellExpression,
+ std::vector<QtData*>* newDataList,
+ std::string &newIteratorName,
+ BaseType* newResType,
+ unsigned int newResOff ) :
+ MarrayOp( newResType, newResOff ),
+ cellExpression( newCellExpression ),
+ dataList( newDataList ),
+ iteratorName( newIteratorName )
+{
+}
+
+
+
+QLMarrayOp::~QLMarrayOp()
+{
+}
+
+
+
+void
+QLMarrayOp::operator() ( char *result, const r_Point &p )
+{
+ // update point data of input list
+ if ( dataList )
+ ((QtPointData *)dataList->back())->setPointData( p );
+
+ if ( cellExpression ) {
+ QtData* resultData = cellExpression->evaluate( dataList );
+
+ if( resultData ) {
+ if( resultData->isScalarData() ) {
+ QtScalarData* scalarResultData = (QtScalarData*)resultData;
+ memcpy( (void*)result,
+ (void*)scalarResultData->getValueBuffer(),
+ scalarResultData->getValueType()->getSize() );
+ }
+ else
+ RMInit::logOut << "Internal Error: QLMarrayOp::operator() - cell type invalid." << endl;
+ resultData->deleteRef();
+ }
+ }
+}
+
+
+
+
+QLCondenseOp::QLCondenseOp( QtOperation* newCellExpression,
+ QtOperation* newCondExpression,
+ std::vector<QtData*>* newDataList,
+ std::string &newIteratorName,
+ BaseType* newResType,
+ unsigned int newResOff,
+ BinaryOp* newAccuOp,
+ char* newInitVal )
+
+ : GenCondenseOp( newResType, newResOff, newAccuOp, newInitVal ),
+ cellExpression( newCellExpression ),
+ condExpression( newCondExpression ),
+ dataList( newDataList ),
+ iteratorName( newIteratorName )
+{
+ //
+ // add point with its iterator name to the data list
+ //
+
+ // create QtPointData object
+ QtPointData* pointData = new QtPointData( r_Point() );
+
+ // set its iterator name
+ pointData->setIteratorName( iteratorName );
+
+ // add it to the list
+ dataList->push_back( pointData );
+}
+
+
+
+QLCondenseOp::~QLCondenseOp()
+{
+ // remove point data object from inputList again
+ dataList->back()->deleteRef();
+ dataList->pop_back();
+}
+
+
+
+void
+QLCondenseOp::operator() ( const r_Point& p )
+{
+ unsigned int currentCellValid = 1;
+
+ // update point data of input list
+ if ( dataList )
+ ((QtPointData*)dataList->back())->setPointData( p );
+
+ if ( condExpression ) {
+ QtData* condData = condExpression->evaluate( dataList );
+#ifdef QT_RUNTIME_TYPE_CHECK
+ if( condData->getDataType() != QT_BOOL ) {
+ RMInit::logOut << "Internal error in QLCondenseOp::operator() - "
+ << "runtime type checking failed (BOOL)." << endl;
+ }
+ else
+#endif
+ currentCellValid = ((QtAtomicData*)condData)->getUnsignedValue();
+ condData->deleteRef();
+ }
+
+ if ( currentCellValid ) {
+ QtData* resultData = cellExpression->evaluate( dataList );
+ if ( resultData ) {
+#ifdef QT_RUNTIME_TYPE_CHECK
+ if ( !(resultData->isScalarData()) ) {
+ RMInit::logOut << "Internal Error: QLCondenseOp::operator() - cell type invalid." << endl;
+ }
+ else
+#endif
+ {
+ QtScalarData* scalarResultData = (QtScalarData*)resultData;
+ (*accuOp)( initVal, initVal, scalarResultData->getValueBuffer() );
+ }
+
+ resultData->deleteRef();
+ }
+ }
+}
diff --git a/catalogmgr/algebraops.hh b/catalogmgr/algebraops.hh
new file mode 100644
index 0000000..d026db1
--- /dev/null
+++ b/catalogmgr/algebraops.hh
@@ -0,0 +1,130 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/*************************************************************
+ *
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#ifndef _ALGEBRAOPS_HH_
+#define _ALGEBRAOPS_HH__
+
+#include "ops.hh"
+
+#include <vector>
+#include <string>
+
+// forward declarations
+class QtOperation;
+class QtData;
+
+//@ManMemo: Module: {\bf catalogif}
+
+/*@Doc:
+
+ Operation object for marray contstructor of the query language.
+
+*/
+
+class QLMarrayOp: public MarrayOp
+{
+ public:
+ /// constructor
+ QLMarrayOp( QtOperation* newCellExpression, std::vector<QtData*>* newDataList,
+ std::string &newIteratorName,
+ BaseType* newResType, unsigned int newResOff = 0 );
+ /**
+ Constructor gets cell expression pointer, data vector for bounded variables,
+ cell type, and type offset
+ */
+
+ /// virtual destructor
+ virtual ~QLMarrayOp();
+
+ /// operator that carries out the cell expression on point {\tt p}.
+ virtual void operator() ( char* result, const r_Point& p );
+
+ private:
+ /// pointer to the cell expression
+ QtOperation* cellExpression;
+
+ /// pointer to data vector
+ std::vector<QtData*>* dataList;
+
+ /// name of the iterator
+ std::string iteratorName;
+};
+
+
+
+
+//@ManMemo: Module: {\bf catalogif}
+
+/*@Doc:
+
+ Operation object for condenser operation of the query language.
+
+*/
+
+class QLCondenseOp: public GenCondenseOp
+{
+ public:
+ /// constructor
+ QLCondenseOp( QtOperation* newCellExpression,
+ QtOperation* newCondExpression,
+ std::vector<QtData*>* newDataList,
+ std::string &newIteratorName,
+ BaseType* newResType,
+ unsigned int newResOff,
+ BinaryOp* newAccuOp,
+ char* newInitVal = 0 );
+ /**
+ Constructor gets cell expression pointer, cell condition expression pointer,
+ data vector for bounded variables, cell type, and type offset
+ */
+
+ /// virtual destructor
+ virtual ~QLCondenseOp();
+
+ /// operator that carries out the cell expression on point {\tt p}.
+ virtual void operator() ( const r_Point& p );
+
+ private:
+ /// pointer to the cell expression
+ QtOperation* cellExpression;
+
+ /// pointer to the condition expression
+ QtOperation* condExpression;
+
+ /// pointer to data vector
+ std::vector<QtData*>* dataList;
+
+ /// name of the iterator
+ std::string iteratorName;
+};
+
+#endif
+
diff --git a/catalogmgr/autogen_ops.cc b/catalogmgr/autogen_ops.cc
new file mode 100644
index 0000000..6e17cc8
--- /dev/null
+++ b/catalogmgr/autogen_ops.cc
@@ -0,0 +1,316 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/*************************************************************
+ *
+ *
+ *
+ *
+ * COMMENTS: Automaticaly generated
+ *
+ ************************************************************/
+
+
+#include <cmath>
+#include <cerrno>
+
+
+OpABSCDouble::OpABSCDouble(
+ const BaseType* newResType,
+ const BaseType* newOpType,
+ unsigned int newResOff,
+ unsigned int newOpOff)
+ : UnaryOp(newResType, newOpType, newResOff, newOpOff) {}
+
+
+void OpABSCDouble::operator()(char* res, const char* op) {
+ double convOp;
+ double convRes;
+ errno = 0;
+ convRes = fabs(*(opType->convertToCDouble(op + opOff, &convOp)));
+ if(errno) {
+ if(errno == EDOM) throw 510;
+ if(errno == ERANGE) throw 511;
+ }
+ resType->makeFromCDouble(res + resOff, &convRes);
+}
+
+OpSQRTCDouble::OpSQRTCDouble(
+ const BaseType* newResType,
+ const BaseType* newOpType,
+ unsigned int newResOff,
+ unsigned int newOpOff)
+ : UnaryOp(newResType, newOpType, newResOff, newOpOff) {}
+
+
+void OpSQRTCDouble::operator()(char* res, const char* op) {
+ double convOp;
+ double convRes;
+ errno = 0;
+ convRes = sqrt(*(opType->convertToCDouble(op + opOff, &convOp)));
+ if(errno) {
+ if(errno == EDOM) throw 510;
+ if(errno == ERANGE) throw 511;
+ }
+ resType->makeFromCDouble(res + resOff, &convRes);
+}
+
+OpEXPCDouble::OpEXPCDouble(
+ const BaseType* newResType,
+ const BaseType* newOpType,
+ unsigned int newResOff,
+ unsigned int newOpOff)
+ : UnaryOp(newResType, newOpType, newResOff, newOpOff) {}
+
+
+void OpEXPCDouble::operator()(char* res, const char* op) {
+ double convOp;
+ double convRes;
+ errno = 0;
+ convRes = exp(*(opType->convertToCDouble(op + opOff, &convOp)));
+ if(errno) {
+ if(errno == EDOM) throw 510;
+ if(errno == ERANGE) throw 511;
+ }
+ resType->makeFromCDouble(res + resOff, &convRes);
+}
+
+OpLOGCDouble::OpLOGCDouble(
+ const BaseType* newResType,
+ const BaseType* newOpType,
+ unsigned int newResOff,
+ unsigned int newOpOff)
+ : UnaryOp(newResType, newOpType, newResOff, newOpOff) {}
+
+
+void OpLOGCDouble::operator()(char* res, const char* op) {
+ double convOp;
+ double convRes;
+ errno = 0;
+ convRes = log10(*(opType->convertToCDouble(op + opOff, &convOp)));
+ if(errno) {
+ if(errno == EDOM) throw 510;
+ if(errno == ERANGE) throw 511;
+ }
+ resType->makeFromCDouble(res + resOff, &convRes);
+}
+
+OpLNCDouble::OpLNCDouble(
+ const BaseType* newResType,
+ const BaseType* newOpType,
+ unsigned int newResOff,
+ unsigned int newOpOff)
+ : UnaryOp(newResType, newOpType, newResOff, newOpOff) {}
+
+
+void OpLNCDouble::operator()(char* res, const char* op) {
+ double convOp;
+ double convRes;
+ errno = 0;
+ convRes = log(*(opType->convertToCDouble(op + opOff, &convOp)));
+ if(errno) {
+ if(errno == EDOM) throw 510;
+ if(errno == ERANGE) throw 511;
+ }
+ resType->makeFromCDouble(res + resOff, &convRes);
+}
+
+OpSINCDouble::OpSINCDouble(
+ const BaseType* newResType,
+ const BaseType* newOpType,
+ unsigned int newResOff,
+ unsigned int newOpOff)
+ : UnaryOp(newResType, newOpType, newResOff, newOpOff) {}
+
+
+void OpSINCDouble::operator()(char* res, const char* op) {
+ double convOp;
+ double convRes;
+ errno = 0;
+ convRes = sin(*(opType->convertToCDouble(op + opOff, &convOp)));
+ if(errno) {
+ if(errno == EDOM) throw 510;
+ if(errno == ERANGE) throw 511;
+ }
+ resType->makeFromCDouble(res + resOff, &convRes);
+}
+
+OpCOSCDouble::OpCOSCDouble(
+ const BaseType* newResType,
+ const BaseType* newOpType,
+ unsigned int newResOff,
+ unsigned int newOpOff)
+ : UnaryOp(newResType, newOpType, newResOff, newOpOff) {}
+
+
+void OpCOSCDouble::operator()(char* res, const char* op) {
+ double convOp;
+ double convRes;
+ errno = 0;
+ convRes = cos(*(opType->convertToCDouble(op + opOff, &convOp)));
+ if(errno) {
+ if(errno == EDOM) throw 510;
+ if(errno == ERANGE) throw 511;
+ }
+ resType->makeFromCDouble(res + resOff, &convRes);
+}
+
+OpTANCDouble::OpTANCDouble(
+ const BaseType* newResType,
+ const BaseType* newOpType,
+ unsigned int newResOff,
+ unsigned int newOpOff)
+ : UnaryOp(newResType, newOpType, newResOff, newOpOff) {}
+
+
+void OpTANCDouble::operator()(char* res, const char* op) {
+ double convOp;
+ double convRes;
+ errno = 0;
+ convRes = tan(*(opType->convertToCDouble(op + opOff, &convOp)));
+ if(errno) {
+ if(errno == EDOM) throw 510;
+ if(errno == ERANGE) throw 511;
+ }
+ resType->makeFromCDouble(res + resOff, &convRes);
+}
+
+OpSINHCDouble::OpSINHCDouble(
+ const BaseType* newResType,
+ const BaseType* newOpType,
+ unsigned int newResOff,
+ unsigned int newOpOff)
+ : UnaryOp(newResType, newOpType, newResOff, newOpOff) {}
+
+
+void OpSINHCDouble::operator()(char* res, const char* op) {
+ double convOp;
+ double convRes;
+ errno = 0;
+ convRes = sin(*(opType->convertToCDouble(op + opOff, &convOp)));
+ if(errno) {
+ if(errno == EDOM) throw 510;
+ if(errno == ERANGE) throw 511;
+ }
+ resType->makeFromCDouble(res + resOff, &convRes);
+}
+
+OpCOSHCDouble::OpCOSHCDouble(
+ const BaseType* newResType,
+ const BaseType* newOpType,
+ unsigned int newResOff,
+ unsigned int newOpOff)
+ : UnaryOp(newResType, newOpType, newResOff, newOpOff) {}
+
+
+void OpCOSHCDouble::operator()(char* res, const char* op) {
+ double convOp;
+ double convRes;
+ errno = 0;
+ convRes = cos(*(opType->convertToCDouble(op + opOff, &convOp)));
+ if(errno) {
+ if(errno == EDOM) throw 510;
+ if(errno == ERANGE) throw 511;
+ }
+ resType->makeFromCDouble(res + resOff, &convRes);
+}
+
+OpTANHCDouble::OpTANHCDouble(
+ const BaseType* newResType,
+ const BaseType* newOpType,
+ unsigned int newResOff,
+ unsigned int newOpOff)
+ : UnaryOp(newResType, newOpType, newResOff, newOpOff) {}
+
+
+void OpTANHCDouble::operator()(char* res, const char* op) {
+ double convOp;
+ double convRes;
+ errno = 0;
+ convRes = tan(*(opType->convertToCDouble(op + opOff, &convOp)));
+ if(errno) {
+ if(errno == EDOM) throw 510;
+ if(errno == ERANGE) throw 511;
+ }
+ resType->makeFromCDouble(res + resOff, &convRes);
+}
+
+OpARCSINCDouble::OpARCSINCDouble(
+ const BaseType* newResType,
+ const BaseType* newOpType,
+ unsigned int newResOff,
+ unsigned int newOpOff)
+ : UnaryOp(newResType, newOpType, newResOff, newOpOff) {}
+
+
+void OpARCSINCDouble::operator()(char* res, const char* op) {
+ double convOp;
+ double convRes;
+ errno = 0;
+ convRes = asin(*(opType->convertToCDouble(op + opOff, &convOp)));
+ if(errno) {
+ if(errno == EDOM) throw 510;
+ if(errno == ERANGE) throw 511;
+ }
+ resType->makeFromCDouble(res + resOff, &convRes);
+}
+
+OpARCCOSCDouble::OpARCCOSCDouble(
+ const BaseType* newResType,
+ const BaseType* newOpType,
+ unsigned int newResOff,
+ unsigned int newOpOff)
+ : UnaryOp(newResType, newOpType, newResOff, newOpOff) {}
+
+
+void OpARCCOSCDouble::operator()(char* res, const char* op) {
+ double convOp;
+ double convRes;
+ errno = 0;
+ convRes = acos(*(opType->convertToCDouble(op + opOff, &convOp)));
+ if(errno) {
+ if(errno == EDOM) throw 510;
+ if(errno == ERANGE) throw 511;
+ }
+ resType->makeFromCDouble(res + resOff, &convRes);
+}
+
+OpARCTANCDouble::OpARCTANCDouble(
+ const BaseType* newResType,
+ const BaseType* newOpType,
+ unsigned int newResOff,
+ unsigned int newOpOff)
+ : UnaryOp(newResType, newOpType, newResOff, newOpOff) {}
+
+
+void OpARCTANCDouble::operator()(char* res, const char* op) {
+ double convOp;
+ double convRes;
+ errno = 0;
+ convRes = atan(*(opType->convertToCDouble(op + opOff, &convOp)));
+ if(errno) {
+ if(errno == EDOM) throw 510;
+ if(errno == ERANGE) throw 511;
+ }
+ resType->makeFromCDouble(res + resOff, &convRes);
+}
+
diff --git a/catalogmgr/autogen_ops.hh b/catalogmgr/autogen_ops.hh
new file mode 100644
index 0000000..28969be
--- /dev/null
+++ b/catalogmgr/autogen_ops.hh
@@ -0,0 +1,284 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/*************************************************************
+ *
+ *
+ *
+ *
+ * COMMENTS: Automaticaly generated
+ *
+ ************************************************************/
+
+
+//@ManMemo: Module: {\bf catalogmgr}
+
+/*@Doc:
+
+*/
+
+// class declaration
+class OpABSCDouble : public UnaryOp {
+public:
+ OpABSCDouble(
+ const BaseType* newResType,
+ const BaseType* newOpType,
+ unsigned int newResOff = 0,
+ unsigned int newOpOff = 0
+ );
+ virtual void operator() (char* result, const char* op);
+};
+
+//@ManMemo: Module: {\bf catalogmgr}
+
+/*@Doc:
+
+*/
+
+// class declaration
+class OpSQRTCDouble : public UnaryOp {
+public:
+ OpSQRTCDouble(
+ const BaseType* newResType,
+ const BaseType* newOpType,
+ unsigned int newResOff = 0,
+ unsigned int newOpOff = 0
+ );
+ virtual void operator() (char* result, const char* op);
+};
+
+//@ManMemo: Module: {\bf catalogmgr}
+
+/*@Doc:
+
+*/
+
+// class declaration
+class OpEXPCDouble : public UnaryOp {
+public:
+ OpEXPCDouble(
+ const BaseType* newResType,
+ const BaseType* newOpType,
+ unsigned int newResOff = 0,
+ unsigned int newOpOff = 0
+ );
+ virtual void operator() (char* result, const char* op);
+};
+
+//@ManMemo: Module: {\bf catalogmgr}
+
+/*@Doc:
+
+*/
+
+// class declaration
+class OpLOGCDouble : public UnaryOp {
+public:
+ OpLOGCDouble(
+ const BaseType* newResType,
+ const BaseType* newOpType,
+ unsigned int newResOff = 0,
+ unsigned int newOpOff = 0
+ );
+ virtual void operator() (char* result, const char* op);
+};
+
+//@ManMemo: Module: {\bf catalogmgr}
+
+/*@Doc:
+
+*/
+
+// class declaration
+class OpLNCDouble : public UnaryOp {
+public:
+ OpLNCDouble(
+ const BaseType* newResType,
+ const BaseType* newOpType,
+ unsigned int newResOff = 0,
+ unsigned int newOpOff = 0
+ );
+ virtual void operator() (char* result, const char* op);
+};
+
+//@ManMemo: Module: {\bf catalogmgr}
+
+/*@Doc:
+
+*/
+
+// class declaration
+class OpSINCDouble : public UnaryOp {
+public:
+ OpSINCDouble(
+ const BaseType* newResType,
+ const BaseType* newOpType,
+ unsigned int newResOff = 0,
+ unsigned int newOpOff = 0
+ );
+ virtual void operator() (char* result, const char* op);
+};
+
+//@ManMemo: Module: {\bf catalogmgr}
+
+/*@Doc:
+
+*/
+
+// class declaration
+class OpCOSCDouble : public UnaryOp {
+public:
+ OpCOSCDouble(
+ const BaseType* newResType,
+ const BaseType* newOpType,
+ unsigned int newResOff = 0,
+ unsigned int newOpOff = 0
+ );
+ virtual void operator() (char* result, const char* op);
+};
+
+//@ManMemo: Module: {\bf catalogmgr}
+
+/*@Doc:
+
+*/
+
+// class declaration
+class OpTANCDouble : public UnaryOp {
+public:
+ OpTANCDouble(
+ const BaseType* newResType,
+ const BaseType* newOpType,
+ unsigned int newResOff = 0,
+ unsigned int newOpOff = 0
+ );
+ virtual void operator() (char* result, const char* op);
+};
+
+//@ManMemo: Module: {\bf catalogmgr}
+
+/*@Doc:
+
+*/
+
+// class declaration
+class OpSINHCDouble : public UnaryOp {
+public:
+ OpSINHCDouble(
+ const BaseType* newResType,
+ const BaseType* newOpType,
+ unsigned int newResOff = 0,
+ unsigned int newOpOff = 0
+ );
+ virtual void operator() (char* result, const char* op);
+};
+
+//@ManMemo: Module: {\bf catalogmgr}
+
+/*@Doc:
+
+*/
+
+// class declaration
+class OpCOSHCDouble : public UnaryOp {
+public:
+ OpCOSHCDouble(
+ const BaseType* newResType,
+ const BaseType* newOpType,
+ unsigned int newResOff = 0,
+ unsigned int newOpOff = 0
+ );
+ virtual void operator() (char* result, const char* op);
+};
+
+//@ManMemo: Module: {\bf catalogmgr}
+
+/*@Doc:
+
+*/
+
+// class declaration
+class OpTANHCDouble : public UnaryOp {
+public:
+ OpTANHCDouble(
+ const BaseType* newResType,
+ const BaseType* newOpType,
+ unsigned int newResOff = 0,
+ unsigned int newOpOff = 0
+ );
+ virtual void operator() (char* result, const char* op);
+};
+
+//@ManMemo: Module: {\bf catalogmgr}
+
+/*@Doc:
+
+*/
+
+// class declaration
+class OpARCSINCDouble : public UnaryOp {
+public:
+ OpARCSINCDouble(
+ const BaseType* newResType,
+ const BaseType* newOpType,
+ unsigned int newResOff = 0,
+ unsigned int newOpOff = 0
+ );
+ virtual void operator() (char* result, const char* op);
+};
+
+//@ManMemo: Module: {\bf catalogmgr}
+
+/*@Doc:
+
+*/
+
+// class declaration
+class OpARCCOSCDouble : public UnaryOp {
+public:
+ OpARCCOSCDouble(
+ const BaseType* newResType,
+ const BaseType* newOpType,
+ unsigned int newResOff = 0,
+ unsigned int newOpOff = 0
+ );
+ virtual void operator() (char* result, const char* op);
+};
+
+//@ManMemo: Module: {\bf catalogmgr}
+
+/*@Doc:
+
+*/
+
+// class declaration
+class OpARCTANCDouble : public UnaryOp {
+public:
+ OpARCTANCDouble(
+ const BaseType* newResType,
+ const BaseType* newOpType,
+ unsigned int newResOff = 0,
+ unsigned int newOpOff = 0
+ );
+ virtual void operator() (char* result, const char* op);
+};
+
diff --git a/catalogmgr/ops.cc b/catalogmgr/ops.cc
new file mode 100644
index 0000000..ee6ad24
--- /dev/null
+++ b/catalogmgr/ops.cc
@@ -0,0 +1,3803 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+static const char rcsid[] = "@(#)catalogif,ops.cc: $Header: /home/rasdev/CVS-repository/rasdaman/catalogmgr/ops.cc,v 1.67 2003/12/20 23:41:27 rasdev Exp $";
+
+#include <limits.h>
+#include <values.h>
+#include <string.h> // memcpy()
+#include <malloc.h> // malloc()
+#include "ops.hh"
+#include "relcatalogif/alltypes.hh"
+#include "typefactory.hh"
+#include "raslib/point.hh"
+
+//-----------------------------------------------
+// getUnaryOp
+//-----------------------------------------------
+UnaryOp* Ops::getUnaryOp(Ops::OpType op, const BaseType* resType, const BaseType* opType, unsigned int resOff, unsigned int opOff) {
+
+#ifndef NO_OPT_OPS
+/////////////////////////////////////////////
+ if(resType->getType() == opType->getType() && resType->getSize() == 1 && resType->getType() != STRUCT) {
+ switch(op) {
+ case Ops::OP_IDENTITY:
+ return new OpIDENTITYChar(resType, opType, resOff, opOff );
+ }
+ }
+ if(resType->getType() == opType->getType() && resType->getSize() == 2 && resType->getType() != STRUCT) {
+ switch(op) {
+ case Ops::OP_IDENTITY:
+ return new OpIDENTITYShort(resType, opType, resOff, opOff );
+ }
+ }
+ if(resType->getType() == opType->getType() && resType->getSize() == 4 && resType->getType() != STRUCT ) {
+ switch(op) {
+ case Ops::OP_IDENTITY:
+ return new OpIDENTITYLong(resType, opType, resOff, opOff );
+ }
+ }
+/////////////////////////////////////////////
+#endif
+
+ // cast operations
+ if(op > Ops::OP_CAST_BEGIN && op < Ops::OP_CAST_END) {
+ if(opType->getType() < STRUCT)
+ return new OpCAST(resType, opType, resOff, opOff );
+
+ else if(opType->getType() == STRUCT)
+ return new OpUnaryStruct(resType, opType, op, resOff, opOff);
+
+ else
+ return 0;
+ }
+
+ // all Char
+ if( resType->getType() == BOOLTYPE && opType->getType() == BOOLTYPE ) {
+ switch(op) {
+ case Ops::OP_NOT:
+ return new OpNOTBool(resType, opType, resOff, opOff );
+ }
+ }
+ if((resType->getType() >= ULONG && resType->getType() <= BOOLTYPE) && (opType->getType() >= ULONG &&
+ opType->getType() <= OCTET)) {
+
+ switch(op) {
+ case Ops::OP_NOT:
+ return new OpNOTCULong(resType, opType, resOff, opOff );
+ case Ops::OP_IDENTITY:
+ return new OpIDENTITYCULong(resType, opType, resOff, opOff );
+ default:
+ return 0;
+ }
+ }
+ // result is LONG, SHORT or OCTET and the only operand between ULONG and OCTET
+ if((resType->getType() == LONG || resType->getType() == SHORT || resType->getType() == OCTET) &&
+ (opType->getType() >= ULONG && opType->getType() <= OCTET) ) {
+
+ switch(op) {
+ case Ops::OP_NOT:
+ return new OpNOTCLong(resType, opType, resOff, opOff );
+ case Ops::OP_IDENTITY:
+ return new OpIDENTITYCLong(resType, opType, resOff, opOff );
+ default:
+ return 0;
+ }
+ }
+
+ // result is COMPELEXTYPE1 or COMPLEXTYPE2
+ if(resType->getType() == COMPLEXTYPE1 && opType->getType() == COMPLEXTYPE1 || // remember && has precedence over ||
+ resType->getType() == COMPLEXTYPE2 && opType->getType() == COMPLEXTYPE2 )
+ return new OpIDENTITYComplex(resType, opType, resOff, opOff );
+
+
+
+ // result is FLOAT or DOUBLE and the only operand between ULONG and FLOAT
+ if(resType->getType() == FLOAT || resType->getType() == DOUBLE && opType->getType() >= ULONG && opType->getType() <= FLOAT) {
+
+ switch(op) {
+ case Ops::OP_IDENTITY:
+ return new OpIDENTITYCDouble(resType, opType, resOff, opOff );
+
+ case Ops::OP_SQRT:
+ return new OpSQRTCDouble(resType, opType, resOff, opOff);
+ case Ops::OP_ABS:
+ return new OpABSCDouble(resType, opType, resOff, opOff);
+ case Ops::OP_EXP:
+ return new OpEXPCDouble(resType, opType, resOff, opOff);
+ case Ops::OP_LOG:
+ return new OpLOGCDouble(resType, opType, resOff, opOff);
+ case Ops::OP_LN:
+ return new OpLNCDouble(resType, opType, resOff, opOff);
+ case Ops::OP_SIN:
+ return new OpSINCDouble(resType, opType, resOff, opOff);
+ case Ops::OP_COS:
+ return new OpCOSCDouble(resType, opType, resOff, opOff);
+ case Ops::OP_TAN:
+ return new OpTANCDouble(resType, opType, resOff, opOff);
+ case Ops::OP_SINH:
+ return new OpSINHCDouble(resType, opType, resOff, opOff);
+ case Ops::OP_COSH:
+ return new OpCOSHCDouble(resType, opType, resOff, opOff);
+ case Ops::OP_TANH:
+ return new OpTANHCDouble(resType, opType, resOff, opOff);
+ case Ops::OP_ARCSIN:
+ return new OpARCSINCDouble(resType, opType, resOff, opOff);
+ case Ops::OP_ARCCOS:
+ return new OpARCCOSCDouble(resType, opType, resOff, opOff);
+ case Ops::OP_ARCTAN:
+ return new OpARCTANCDouble(resType, opType, resOff, opOff);
+
+ case Ops::OP_REALPART:
+ return new OpRealPart(resType, opType, resOff, opOff);
+ case Ops::OP_IMAGINARPART:
+ return new OpImaginarPart(resType, opType, resOff, opOff);
+
+ default:
+ return 0;
+ }
+ }
+
+ // retriving real or imaginar parts of a complex argument
+ if(resType->getType() == DOUBLE && (opType->getType() == COMPLEXTYPE1 || opType->getType() == COMPLEXTYPE2)) {
+ switch(op) {
+ case Ops::OP_REALPART:
+ return new OpRealPart(resType, opType, resOff, opOff);
+
+ case Ops::OP_IMAGINARPART:
+ return new OpImaginarPart(resType, opType, resOff, opOff);
+
+ default:
+ return 0;
+ }
+ }
+
+ if(resType->getType() == COMPLEXTYPE1 && opType->getType() == COMPLEXTYPE1 || // remember && has precedence over ||
+ resType->getType() == COMPLEXTYPE2 && opType->getType() == COMPLEXTYPE2 )
+ return new OpIDENTITYComplex(resType, opType, resOff, opOff );
+
+ if( resType->getType() == STRUCT && resType->compatibleWith(opType) ) {
+
+#ifndef NO_OPT_IDENTITY_STRUCT
+/////////////////////////////
+ switch(op) {
+ case Ops::OP_IDENTITY:
+ return new OpIDENTITYStruct(resType, opType, resOff, opOff );
+ default:
+/////////////////////////////
+#endif
+ return new OpUnaryStruct( resType, opType, op, resOff, opOff );
+
+#ifndef NO_OPT_IDENTITY_STRUCT
+/////////////////////////////
+ }
+/////////////////////////////
+#endif
+
+ }
+ return 0;
+}
+
+BinaryOp*
+Ops::getBinaryOp( Ops::OpType op, const BaseType* resType, const BaseType* op1Type,
+ const BaseType* op2Type, unsigned int resOff,
+ unsigned int op1Off, unsigned int op2Off )
+{
+// if this flag is set, optimized operation execution for Char
+// is turned off.
+#ifndef NO_OPT_OPS
+ // all Char
+ if( resType->getType() == CHAR && op1Type->getType() == CHAR &&
+ op2Type->getType() == CHAR ) {
+ switch(op) {
+ case Ops::OP_PLUS:
+ return new OpPLUSChar(resType, op1Type, op2Type, resOff, op1Off, op2Off);
+ case Ops::OP_MINUS:
+ return new OpMINUSChar(resType, op1Type, op2Type, resOff, op1Off, op2Off);
+ case Ops::OP_DIV:
+ return new OpDIVChar(resType, op1Type, op2Type, resOff, op1Off, op2Off);
+ case Ops::OP_MULT:
+ return new OpMULTChar(resType, op1Type, op2Type, resOff, op1Off, op2Off);
+ }
+ }
+#endif
+ if ((resType->getType() == op1Type->getType()) && (resType->getType() == op2Type->getType()) && (op == Ops::OP_OVERLAY))
+ {
+ return new OpOVERLAY(resType, op1Type, op2Type, resType->getSize(), OpOVERLAY::nullPattern, resOff, op1Off, op2Off);
+ }
+
+ // all Bool
+ if( resType->getType() == BOOLTYPE && op1Type->getType() == BOOLTYPE &&
+ op2Type->getType() == BOOLTYPE ) {
+ switch(op) {
+ case Ops::OP_AND:
+ return new OpANDBool(resType, op1Type, op2Type, resOff, op1Off,
+ op2Off);
+ case Ops::OP_OR:
+ return new OpORBool(resType, op1Type, op2Type, resOff, op1Off,
+ op2Off);
+ case Ops::OP_XOR:
+ return new OpXORBool(resType, op1Type, op2Type, resOff, op1Off,
+ op2Off);
+ }
+ }
+ // result is unsigned integer
+ if( (resType->getType() >= ULONG && resType->getType() <= BOOLTYPE) &&
+ (op1Type->getType() >= ULONG && op1Type->getType() <= OCTET) &&
+ (op2Type->getType() >= ULONG && op2Type->getType() <= OCTET) ) {
+ switch(op) {
+ case Ops::OP_PLUS:
+ return new OpPLUSCULong(resType, op1Type, op2Type, resOff, op1Off, op2Off);
+ case Ops::OP_MINUS:
+ return new OpMINUSCULong(resType, op1Type, op2Type, resOff, op1Off, op2Off);
+ case Ops::OP_DIV:
+ return new OpDIVCULong(resType, op1Type, op2Type, resOff, op1Off, op2Off);
+ case Ops::OP_MULT:
+ return new OpMULTCULong(resType, op1Type, op2Type, resOff, op1Off, op2Off);
+ case Ops::OP_AND:
+ return new OpANDCULong(resType, op1Type, op2Type, resOff, op1Off, op2Off);
+ case Ops::OP_OR:
+ return new OpORCULong(resType, op1Type, op2Type, resOff, op1Off, op2Off);
+ case Ops::OP_XOR:
+ return new OpXORCULong(resType, op1Type, op2Type, resOff, op1Off, op2Off);
+ }
+ }
+ // result is signed integer
+ if( (resType->getType() == LONG || resType->getType() == SHORT ||
+ resType->getType() == OCTET) &&
+ (op1Type->getType() >= ULONG && op1Type->getType() <= OCTET) &&
+ (op2Type->getType() >= ULONG && op2Type->getType() <= OCTET) ) {
+ switch(op) {
+ case Ops::OP_PLUS:
+ return new OpPLUSCLong(resType, op1Type, op2Type, resOff, op1Off,
+ op2Off);
+ case Ops::OP_MINUS:
+ return new OpMINUSCLong(resType, op1Type, op2Type, resOff, op1Off,
+ op2Off);
+ case Ops::OP_DIV:
+ return new OpDIVCLong(resType, op1Type, op2Type, resOff, op1Off,
+ op2Off);
+ case Ops::OP_MULT:
+ return new OpMULTCLong(resType, op1Type, op2Type, resOff, op1Off,
+ op2Off);
+ case Ops::OP_AND:
+ return new OpANDCLong(resType, op1Type, op2Type, resOff, op1Off,
+ op2Off);
+ case Ops::OP_OR:
+ return new OpANDCLong(resType, op1Type, op2Type, resOff, op1Off,
+ op2Off);
+ case Ops::OP_XOR:
+ return new OpANDCLong(resType, op1Type, op2Type, resOff, op1Off,
+ op2Off);
+ }
+ }
+ // result is float or double
+ if( (resType->getType() == FLOAT || resType->getType() == DOUBLE) &&
+ (op1Type->getType() >= ULONG && op1Type->getType() <= FLOAT) &&
+ (op2Type->getType() >= ULONG && op2Type->getType() <= FLOAT) ) {
+ switch(op) {
+ case Ops::OP_PLUS:
+ return new OpPLUSCDouble(resType, op1Type, op2Type, resOff, op1Off,
+ op2Off);
+ case Ops::OP_MINUS:
+ return new OpMINUSCDouble(resType, op1Type, op2Type, resOff, op1Off,
+ op2Off);
+ case Ops::OP_DIV:
+ return new OpDIVCDouble(resType, op1Type, op2Type, resOff, op1Off,
+ op2Off);
+ case Ops::OP_MULT:
+ return new OpMULTCDouble(resType, op1Type, op2Type, resOff, op1Off,
+ op2Off);
+ }
+ }
+
+
+//*************************************************************************************
+// *** COMPLEXTYPE ***
+//************************************************************************************
+
+ // result is complex
+ if(resType->getType() == COMPLEXTYPE1 || resType->getType() == COMPLEXTYPE2) {
+ switch(op) {
+
+ case Ops::OP_PLUS:
+ if(op1Type->getType() < COMPLEXTYPE1)
+ return new OpPLUSComplex(resType, op1Type, op2Type, resOff, op1Off, op2Off, OpPLUSComplex::FIRST);
+ else if(op2Type->getType() < COMPLEXTYPE1)
+ return new OpPLUSComplex(resType, op1Type, op2Type, resOff, op1Off, op2Off, OpPLUSComplex::SECOND);
+ else
+ return new OpPLUSComplex(resType, op1Type, op2Type, resOff, op1Off, op2Off);
+
+ case Ops::OP_MINUS:
+ if(op1Type->getType() < COMPLEXTYPE1)
+ return new OpMINUSComplex(resType, op1Type, op2Type, resOff, op1Off, op2Off, OpMINUSComplex::FIRST);
+ else if(op2Type->getType() < COMPLEXTYPE1)
+ return new OpMINUSComplex(resType, op1Type, op2Type, resOff, op1Off, op2Off, OpMINUSComplex::SECOND);
+ else
+ return new OpMINUSComplex(resType, op1Type, op2Type, resOff, op1Off, op2Off);
+
+ case Ops::OP_DIV:
+ if(op1Type->getType() < COMPLEXTYPE1)
+ return new OpDIVComplex(resType, op1Type, op2Type, resOff, op1Off, op2Off, OpDIVComplex::FIRST);
+ else if(op2Type->getType() < COMPLEXTYPE1)
+ return new OpDIVComplex(resType, op1Type, op2Type, resOff, op1Off, op2Off, OpDIVComplex::SECOND);
+ else
+ return new OpDIVComplex(resType, op1Type, op2Type, resOff, op1Off, op2Off);
+
+ case Ops::OP_MULT:
+ if(op1Type->getType() < COMPLEXTYPE1)
+ return new OpMULTComplex(resType, op1Type, op2Type, resOff, op1Off, op2Off, OpMULTComplex::FIRST);
+ else if(op2Type->getType() < COMPLEXTYPE1)
+ return new OpMULTComplex(resType, op1Type, op2Type, resOff, op1Off, op2Off, OpMULTComplex::SECOND);
+ else
+ return new OpMULTComplex(resType, op1Type, op2Type, resOff, op1Off, op2Off);
+ }
+ }
+
+//*************************************************************************************
+
+
+#ifndef NO_OPT_OPS
+ // result is bool, operands are Chars
+ if( (resType->getType() == BOOLTYPE) && (op1Type->getType() == CHAR) &&
+ (op2Type->getType() == CHAR) ) {
+ switch(op) {
+ case Ops::OP_EQUAL:
+ return new OpEQUALChar(resType, op1Type, op2Type, resOff, op1Off,
+ op2Off);
+ case Ops::OP_LESS:
+ return new OpLESSChar(resType, op1Type, op2Type, resOff, op1Off,
+ op2Off);
+ case Ops::OP_LESSEQUAL:
+ return new OpLESSEQUALChar(resType, op1Type, op2Type, resOff,
+ op1Off, op2Off);
+ case Ops::OP_NOTEQUAL:
+ return new OpNOTEQUALChar(resType, op1Type, op2Type, resOff,
+ op1Off, op2Off);
+ case Ops::OP_GREATER:
+ return new OpGREATERChar(resType, op1Type, op2Type, resOff,
+ op1Off, op2Off);
+ case Ops::OP_GREATEREQUAL:
+ return new OpGREATEREQUALChar(resType, op1Type, op2Type, resOff,
+ op1Off, op2Off);
+ }
+ }
+#endif
+ // result is bool
+ if( (resType->getType() == BOOLTYPE) &&
+ (op1Type->getType() >= ULONG && op1Type->getType() <= BOOLTYPE) &&
+ (op2Type->getType() >= ULONG && op2Type->getType() <= BOOLTYPE) ) {
+ switch(op) {
+ case Ops::OP_EQUAL:
+ return new OpEQUALCCharCULong(resType, op1Type, op2Type, resOff, op1Off,
+ op2Off);
+ case Ops::OP_LESS:
+ return new OpLESSCCharCULong(resType, op1Type, op2Type, resOff, op1Off,
+ op2Off);
+ case Ops::OP_LESSEQUAL:
+ return new OpLESSEQUALCCharCULong(resType, op1Type, op2Type, resOff,
+ op1Off, op2Off);
+ case Ops::OP_NOTEQUAL:
+ return new OpNOTEQUALCCharCULong(resType, op1Type, op2Type, resOff,
+ op1Off, op2Off);
+ case Ops::OP_GREATER:
+ return new OpGREATERCCharCULong(resType, op1Type, op2Type, resOff,
+ op1Off, op2Off);
+ case Ops::OP_GREATEREQUAL:
+ return new OpGREATEREQUALCCharCULong(resType, op1Type, op2Type, resOff,
+ op1Off, op2Off);
+ }
+ }
+ if( (resType->getType() == BOOLTYPE) &&
+ (op1Type->getType() >= ULONG && op1Type->getType() <= OCTET ) &&
+ (op2Type->getType() >= ULONG && op2Type->getType() <= OCTET ) ) {
+ switch(op) {
+ case Ops::OP_EQUAL:
+ return new OpEQUALCCharCLong(resType, op1Type, op2Type, resOff, op1Off,
+ op2Off);
+ case Ops::OP_LESS:
+ return new OpLESSCCharCLong(resType, op1Type, op2Type, resOff, op1Off,
+ op2Off);
+ case Ops::OP_LESSEQUAL:
+ return new OpLESSEQUALCCharCLong(resType, op1Type, op2Type, resOff,
+ op1Off, op2Off);
+ case Ops::OP_NOTEQUAL:
+ return new OpNOTEQUALCCharCLong(resType, op1Type, op2Type, resOff,
+ op1Off, op2Off);
+ case Ops::OP_GREATER:
+ return new OpGREATERCCharCLong(resType, op1Type, op2Type, resOff,
+ op1Off, op2Off);
+ case Ops::OP_GREATEREQUAL:
+ return new OpGREATEREQUALCCharCLong(resType, op1Type, op2Type, resOff,
+ op1Off, op2Off);
+ case Ops::OP_BIT:
+ return new OpBIT(resType, op1Type, op2Type, resOff, op1Off, op2Off);
+
+ }
+ }
+ if( (resType->getType() == BOOLTYPE) &&
+ (op1Type->getType() >= ULONG && op1Type->getType() <= FLOAT ) &&
+ (op2Type->getType() >= ULONG && op2Type->getType() <= FLOAT ) ) {
+ switch(op) {
+ case Ops::OP_EQUAL:
+ return new OpEQUALCCharCDouble(resType, op1Type, op2Type, resOff, op1Off,
+ op2Off);
+ case Ops::OP_LESS:
+ return new OpLESSCCharCDouble(resType, op1Type, op2Type, resOff, op1Off,
+ op2Off);
+ case Ops::OP_LESSEQUAL:
+ return new OpLESSEQUALCCharCDouble(resType, op1Type, op2Type, resOff,
+ op1Off, op2Off);
+ case Ops::OP_NOTEQUAL:
+ return new OpNOTEQUALCCharCDouble(resType, op1Type, op2Type, resOff,
+ op1Off, op2Off);
+ case Ops::OP_GREATER:
+ return new OpGREATERCCharCDouble(resType, op1Type, op2Type, resOff,
+ op1Off, op2Off);
+ case Ops::OP_GREATEREQUAL:
+ return new OpGREATEREQUALCCharCDouble(resType, op1Type, op2Type, resOff,
+ op1Off, op2Off);
+ }
+ }
+ // comparison of structs
+ if( (resType->getType() == BOOLTYPE) &&
+ (op1Type->getType() >= STRUCT && op1Type->getType() <= CLASSTYPE ) &&
+ (op1Type->compatibleWith(op2Type)) ) {
+ switch(op) {
+ case Ops::OP_EQUAL:
+ return new OpEQUALStruct(resType, op1Type, op2Type, resOff, op1Off,
+ op2Off);
+ case Ops::OP_NOTEQUAL:
+ return new OpNOTEQUALStruct(resType, op1Type, op2Type, resOff, op1Off,
+ op2Off);
+ }
+ }
+ // result is Struct, two operands are structs
+ if( resType->getType() == STRUCT && op1Type->getType() == STRUCT &&
+ op2Type->getType() == STRUCT ) {
+
+
+ if(op >= OP_MINUS && op <= OP_XOR && isApplicableOnStruct(op, op1Type) &&
+ resType->compatibleWith(op1Type) && resType->compatibleWith(op2Type)) {
+ return new OpBinaryStruct( resType, op, resOff, op1Off, op2Off);
+ }
+ else
+ return 0;
+ }
+ // result is Struct, first operand is struct
+ if( resType->getType() == STRUCT && op1Type->getType() == STRUCT ) {
+ if(op >= OP_MINUS && op <= OP_XOR &&
+ isApplicableOnStructConst(op, op1Type, op2Type)) {
+ return new OpBinaryStructConst(
+ resType, op1Type, op2Type,
+ op,
+ resOff, op1Off, op2Off
+ );
+ }
+ else
+ return 0;
+ }
+ // result is Struct, second operand is struct
+ if( resType->getType() == STRUCT && op2Type->getType() == STRUCT ) {
+ if(op >= OP_MINUS && op <= OP_XOR &&
+ isApplicableOnStructConst(op, op2Type, op1Type))
+ return new OpBinaryConstStruct(
+ resType, op1Type, op2Type,
+ op,
+ resOff, op1Off, op2Off
+ );
+ else
+ return 0;
+ }
+ return 0;
+}
+
+
+//-----------------------------------------------------------------
+// getCondenseOp
+//-----------------------------------------------------------------
+
+CondenseOp*
+Ops::getCondenseOp(Ops::OpType op, const BaseType* resType, const BaseType* opType, unsigned int resOff, unsigned int opOff) {
+ if(resType->getType() == BOOLTYPE) {
+ switch(op) {
+ case Ops::OP_SOME:
+ return new OpSOMECChar(resType, opType, resOff, opOff);
+ case Ops::OP_ALL:
+ return new OpALLCChar(resType, opType, resOff, opOff);
+ }
+ }
+
+ else if( resType->getType() == ULONG && opType->getType() == BOOLTYPE ) {
+ switch(op) {
+ case Ops::OP_COUNT:
+ return new OpCOUNTCChar(resType, opType, resOff, opOff);
+ case Ops::OP_SUM:
+ return new OpSUMCULong(resType, opType, resOff, opOff);
+ }
+ }
+
+ else if((resType->getType() >= ULONG && resType->getType() <= BOOLTYPE) &&
+ (opType->getType() >= ULONG && opType->getType() <= BOOLTYPE)) {
+ switch(op) {
+ case Ops::OP_MAX:
+ return new OpMAXCULong(resType, opType, resOff, opOff);
+ case Ops::OP_MIN:
+ return new OpMINCULong(resType, opType, resOff, opOff);
+ case Ops::OP_SUM:
+ return new OpSUMCULong(resType, opType, resOff, opOff);
+ }
+ }
+
+ else if((resType->getType() == LONG || resType->getType() == SHORT ||
+ resType->getType() == OCTET) && (opType->getType() >= ULONG && opType->getType() <= OCTET) ) {
+ switch(op) {
+ case Ops::OP_MAX:
+ return new OpMAXCLong(resType, opType, resOff, opOff);
+ case Ops::OP_MIN:
+ return new OpMINCLong(resType, opType, resOff, opOff);
+ case Ops::OP_SUM:
+ return new OpSUMCLong(resType, opType, resOff, opOff);
+ }
+ }
+ else if((resType->getType() == FLOAT || resType->getType() == DOUBLE ) &&
+ (opType->getType() >= ULONG && opType->getType() <= FLOAT) ) {
+ switch(op) {
+ case Ops::OP_MAX:
+ return new OpMAXCDouble(resType, opType, resOff, opOff);
+ case Ops::OP_MIN:
+ return new OpMINCDouble(resType, opType, resOff, opOff);
+ case Ops::OP_SUM:
+ return new OpSUMCDouble(resType, opType, resOff, opOff);
+ }
+ }
+ else if( resType->getType() == STRUCT)
+ // res and op are structs with same structure.
+ return new OpCondenseStruct( resType, opType, op, resOff, opOff );
+
+ return 0;
+}
+
+
+CondenseOp*
+Ops::getCondenseOp( Ops::OpType op, const BaseType* resType, char* newAccu,
+ const BaseType* opType, unsigned int resOff, unsigned int opOff )
+{
+ if(resType->getType() == BOOLTYPE) {
+ switch(op) {
+ case Ops::OP_SOME:
+ return new OpSOMECChar(resType, newAccu, opType, resOff, opOff);
+ case Ops::OP_ALL:
+ return new OpALLCChar(resType, newAccu, opType, resOff, opOff);
+ }
+ }
+ else if( resType->getType() == ULONG && opType->getType() == BOOLTYPE ) {
+ switch(op) {
+ case Ops::OP_COUNT:
+ return new OpCOUNTCChar(resType, newAccu, opType, resOff, opOff);
+ }
+ }
+ else if( (resType->getType() >= ULONG && resType->getType() <= BOOLTYPE) &&
+ (opType->getType() >= ULONG && opType->getType() <= BOOLTYPE) ) {
+ switch(op) {
+ case Ops::OP_MAX:
+ return new OpMAXCULong(resType, newAccu, opType, resOff, opOff);
+ case Ops::OP_MIN:
+ return new OpMINCULong(resType, newAccu, opType, resOff, opOff);
+ case Ops::OP_SUM:
+ return new OpSUMCULong(resType, newAccu, opType, resOff, opOff);
+ }
+ }
+ else if( (resType->getType() == LONG || resType->getType() == SHORT ||
+ resType->getType() == OCTET) &&
+ (opType->getType() >= ULONG && opType->getType() <= OCTET) ) {
+ switch(op) {
+ case Ops::OP_MAX:
+ return new OpMAXCLong(resType, newAccu, opType, resOff, opOff);
+ case Ops::OP_MIN:
+ return new OpMINCLong(resType, newAccu, opType, resOff, opOff);
+ case Ops::OP_SUM:
+ return new OpSUMCLong(resType, newAccu, opType, resOff, opOff);
+ }
+ }
+ else if( (resType->getType() == FLOAT || resType->getType() == DOUBLE ) &&
+ (opType->getType() >= ULONG && opType->getType() <= FLOAT) ) {
+ switch(op) {
+ case Ops::OP_MAX:
+ return new OpMAXCDouble(resType, newAccu, opType, resOff, opOff);
+ case Ops::OP_MIN:
+ return new OpMINCDouble(resType, newAccu, opType, resOff, opOff);
+ case Ops::OP_SUM:
+ return new OpSUMCDouble(resType, newAccu, opType, resOff, opOff);
+ }
+ }
+ else if( resType->getType() == STRUCT ) {
+ // res and op are structs with same structure.
+ return new OpCondenseStruct( resType, newAccu, opType, op, resOff, opOff );
+ }
+ return 0;
+}
+
+//-----------------------------------------------
+// isApplicable
+//-----------------------------------------------
+int Ops::isApplicable(Ops::OpType op, const BaseType* op1Type, const BaseType* op2Type) {
+ UnaryOp* myUnaryOp;
+ BinaryOp* myBinaryOp;
+ CondenseOp* myCondenseOp;
+
+ const BaseType* resType;
+
+ // could be getResType( op, op1Type, op2Type ), but this
+ // introduces circular dependency between the two functions.
+ // So it is broken here.
+
+ if( op == OP_SOME || op == OP_ALL || (op >= OP_EQUAL && op <= OP_GREATEREQUAL) ) {
+ // result must be Bool
+ resType = TypeFactory::mapType("Bool");
+ }
+ else if(op == OP_COUNT)
+ resType = TypeFactory::mapType("ULong");
+
+ else if(op > OP_UFUNC_BEGIN && op < OP_UFUNC_END )
+ resType = TypeFactory::mapType("Double");
+
+ else if(op > Ops::OP_CAST_BEGIN && op < Ops::OP_CAST_END && op1Type->getType() <= FLOAT) {
+ const char *typeName[] = {
+ "Bool", "Char", "Octet", "Short", "UShort",
+ "Long", "ULong", "Float", "Double"
+ };
+ resType = TypeFactory::mapType(typeName[op - OP_CAST_BEGIN - 1]);
+ }
+
+ else if(op == OP_BIT)
+ resType = TypeFactory::mapType("Bool");
+ else if(op == OP_SUM && op1Type->getType() <= CHAR)
+ resType = TypeFactory::mapType("ULong");
+ else if(op == OP_SUM && op1Type->getType() <= OCTET)
+ resType = TypeFactory::mapType("Long");
+ else if(op == OP_SUM && op1Type->getType() <= FLOAT)
+ resType = TypeFactory::mapType("Double");
+ else if(op == OP_SUM && op1Type->getType() == COMPLEXTYPE1)
+ resType = TypeFactory::mapType("Complex1");
+ else if(op == OP_SUM && op1Type->getType() == COMPLEXTYPE2)
+ resType = TypeFactory::mapType("Complex2");
+
+ // unary operations on complex: re, im
+ else if(op == OP_REALPART || op == OP_IMAGINARPART) {
+ if(op1Type->getType() == COMPLEXTYPE1)
+ resType = TypeFactory::mapType("Float");
+ if(op1Type->getType() == COMPLEXTYPE2)
+ resType = TypeFactory::mapType("Double");
+ }
+
+ else if(op2Type == 0)
+ resType = (BaseType*)op1Type;
+
+ else if( op1Type->getType() >= STRUCT && op1Type->getType() <= CLASSTYPE )
+ // composite types must be compatible, so just take one of them as
+ // result
+ resType = (BaseType*)op1Type;
+ else if( op2Type->getType() >= STRUCT && op2Type->getType() <= CLASSTYPE )
+ // composite types must be compatible, so just take one of them as
+ // result
+ resType = (BaseType*)op2Type;
+
+
+ else if(op1Type->getType() == COMPLEXTYPE2 || op2Type->getType() == COMPLEXTYPE2)
+ // if one of the opernds is complex type and the other any atomic type
+ // the result should be complex
+ resType = TypeFactory::mapType("Complex2");
+
+ else if(op1Type->getType() == COMPLEXTYPE1 || op2Type->getType() == COMPLEXTYPE1)
+ // idem
+ resType = TypeFactory::mapType("Complex1");
+
+ else if( op >= OP_IS && op <= OP_XOR )
+ // result must be long in this case
+ resType = TypeFactory::mapType("Long");
+ else
+ // Double is the strongest type anyway
+ resType = TypeFactory::mapType("Double");
+
+ if(op == OP_OVERLAY)
+ resType = (BaseType*)op1Type;
+
+
+ // unary or condense operations
+ if(op2Type == 0) {
+ myUnaryOp = getUnaryOp(op, resType, (BaseType*)op1Type);
+ if(myUnaryOp != 0) {
+ delete myUnaryOp;
+ return 1; // found an unary op
+ }
+ myCondenseOp = getCondenseOp(op, (BaseType*)resType, (BaseType*)op1Type);
+ if(myCondenseOp != 0) {
+ delete myCondenseOp;
+ return 1; // found a condense op
+ }
+ else
+ return 0; // found neither
+ }
+ else {
+ myBinaryOp = getBinaryOp(op, resType, (BaseType*)op1Type, (BaseType*)op2Type);
+ if(myBinaryOp != 0) {
+ delete myBinaryOp;
+ return 1;
+
+ }
+ else
+ return 0;
+ }
+}
+
+
+//-----------------------------------------------
+// getResultType
+//-----------------------------------------------
+const BaseType* Ops::getResultType(Ops::OpType op, const BaseType* op1, const BaseType* op2) {
+
+ // operations between composite types defined only on compatible types
+ if(op == OP_OVERLAY)
+ {
+ if ((op1->getType() == STRUCT) || (op2->getType() == STRUCT))
+ {
+ if (op1->compatibleWith(op2))
+ {
+ return op1;
+ }
+ else {
+ return NULL;
+ }
+ }
+ if (op1->getType() == op2->getType())
+ {
+ return op1;
+ }
+ return NULL;
+ }
+
+ // operation BIT returns bool or struct {bool, ...}
+ if(op == OP_BIT) {
+ if(op1->getType() == STRUCT) {
+ StructType* resStructType = new StructType;
+ TypeFactory::addTempType(resStructType);
+
+ StructType* opStructType = (StructType* )op1;
+
+ for(int i = 0; i < opStructType->getNumElems(); ++i) {
+ const BaseType* resType = getResultType(op, opStructType->getElemType(i), op2);
+
+ if(!resType)
+ return 0;
+
+ resStructType->addElement(opStructType->getElemName(i), resType);
+ }
+
+ return (BaseType *) resStructType;
+ }
+
+ // integral types
+ else if(op1->getType() <= OCTET)
+ return TypeFactory::mapType("Bool");
+
+ else
+ return 0;
+ }
+
+ // operation not even applicable, so no result type
+ if(!isApplicable(op, op1, op2)) {
+ return 0;
+ }
+
+ // the condense operation COUNT always returns an unsigned long
+ if( op == Ops::OP_COUNT )
+ return TypeFactory::mapType("ULong");
+ // SQRT returns DOUBLE
+
+
+ if( op > Ops::OP_UFUNC_BEGIN && op < Ops::OP_UFUNC_END )
+ return TypeFactory::mapType("Double");
+
+ if(op > Ops::OP_CAST_BEGIN && op < Ops::OP_CAST_END) {
+ if(op1->getType() < STRUCT) {
+ const char *typeName[] = {
+ "Bool", "Char", "Octet", "Short", "UShort",
+ "Long", "ULong", "Float", "Double"
+ };
+ return TypeFactory::mapType(typeName[op - OP_CAST_BEGIN - 1]);
+ }
+
+ else if(op1->getType() == STRUCT) {
+ StructType* resStructType = new StructType;
+ TypeFactory::addTempType(resStructType);
+ StructType* opStructType = (StructType* )op1;
+
+ for(int i = 0; i < opStructType->getNumElems(); ++i) {
+ const BaseType* resType = getResultType(op, opStructType->getElemType(i));
+ if(!resType)
+ return 0;
+
+ resStructType->addElement(opStructType->getElemName(i), resType);
+ }
+
+ return (BaseType *)resStructType;
+ }
+
+ else
+ return 0;
+
+ }
+
+ // the condense operation ADD_CELLS returns maximal type
+ // (i.e. long/ulong or double)
+ if(!op2 && op == Ops::OP_SUM) {
+ if(op1->getType() <= BOOLTYPE)
+ return TypeFactory::mapType("ULong");
+
+ if(op1->getType() <= OCTET)
+ return TypeFactory::mapType("Long");
+
+ else if(op1->getType() <= FLOAT)
+ return TypeFactory::mapType("Double");
+
+ else if(op1->getType() == COMPLEXTYPE1)
+ return TypeFactory::mapType("Complex1");
+
+ else if(op1->getType() == COMPLEXTYPE2)
+ return TypeFactory::mapType("Complex2");
+
+ else if(op1->getType() == STRUCT) {
+ StructType* resStructType = new StructType;
+ TypeFactory::addTempType(resStructType);
+ StructType* opStructType = (StructType* )op1;
+
+ for(int i = 0; i < opStructType->getNumElems(); ++i) {
+ const BaseType* resType = getResultType(op, opStructType->getElemType(i));
+ if(!resType)
+ return 0;
+
+ resStructType->addElement(opStructType->getElemName(i), resType);
+ }
+
+ return (BaseType *)resStructType;
+ }
+ else
+ return 0;
+ }
+
+ // some :-) unary and condense operations return the same type
+ if(op == OP_REALPART || op == OP_IMAGINARPART) {
+ if(op1->getType() == COMPLEXTYPE1)
+ return TypeFactory::mapType("Float");
+ else if(op1->getType() == COMPLEXTYPE2)
+ return TypeFactory::mapType("Double");
+ }
+ if( op2 == 0 )
+ return (BaseType*)op1;
+ // operations between composite types defined only on compatible types
+ if( op1->getType() >= STRUCT && op1->getType() <= CLASSTYPE ) {
+ if( op == OP_EQUAL || op == OP_NOTEQUAL )
+ return TypeFactory::mapType("Bool");
+ else {
+ if(op1->getType() == STRUCT && op2->getType() <= FLOAT) {
+
+ StructType* resStructType = new StructType;
+ TypeFactory::addTempType(resStructType);
+ StructType* opStructType = (StructType* )op1;
+
+ for(int i = 0; i < opStructType->getNumElems(); ++i) {
+ const BaseType* resType = getResultType(op, opStructType->getElemType(i), op2);
+ if(!resType)
+ return 0;
+
+ resStructType->addElement(opStructType->getElemName(i), resType);
+ }
+
+ return (BaseType *)resStructType;
+ }
+ else
+ return (BaseType*)op1;
+ }
+ }
+ if( op2->getType() >= STRUCT && op2->getType() <= CLASSTYPE ) {
+
+ if(op1->getType() <= FLOAT && op2->getType() == STRUCT) {
+
+ StructType* resStructType = new StructType;
+ TypeFactory::addTempType(resStructType);
+ StructType* opStructType = (StructType* )op2;
+
+ for(int i = 0; i < opStructType->getNumElems(); ++i) {
+ const BaseType* resType = getResultType(op, op1, opStructType->getElemType(i));
+ if(!resType)
+ return 0;
+ resStructType->addElement(opStructType->getElemName(i), resType);
+ }
+
+
+ return (BaseType *)resStructType;
+ }
+ else
+ return (BaseType*)op2;
+ }
+
+ // comparison operators always return bool
+ if(op >= OP_EQUAL && op <= OP_GREATEREQUAL)
+ return TypeFactory::mapType("Bool");
+ // all the other binary functions return "strongest" type
+ // if only one of operand is signed, result also has to be signed.
+ if( isSignedType(op1) && !isSignedType(op2) ) {
+ // swap it, action is in next if clause
+ const BaseType* dummy;
+ dummy = op2;
+ op2 = op1;
+ op1 = dummy;
+ }
+ if( !isSignedType(op1) && isSignedType(op2) ) {
+ // got to get the thing with the highest precision and make sure
+ // it is signed.
+ if( op2->getType() == COMPLEXTYPE1 || op2->getType() == COMPLEXTYPE2 ||
+ op2->getType() == FLOAT || op2->getType() == DOUBLE || op2->getType() == LONG )
+ return (BaseType*)op2;
+ if( op1->getType() == USHORT )
+ return TypeFactory::mapType("Short");
+ if( op2->getType() == SHORT )
+ return (BaseType*)op2;
+ return TypeFactory::mapType("Octet");
+ }
+ // return the stronger type
+ if(op1->getType() == COMPLEXTYPE2 || op2->getType() == COMPLEXTYPE2)
+ return TypeFactory::mapType("Complex2");
+ if(op1->getType() == COMPLEXTYPE1 || op2->getType() == COMPLEXTYPE1)
+ return TypeFactory::mapType("Complex1");
+ if(op1->getType() == DOUBLE || op2->getType() == DOUBLE)
+ return TypeFactory::mapType("Double");
+ if(op1->getType() == FLOAT || op2->getType() == FLOAT)
+ return TypeFactory::mapType("Float");
+ if(op1->getType() <= op2->getType())
+ return (BaseType*)op1;
+ else
+ return (BaseType*)op2;
+}
+
+int
+Ops::isApplicableOnStruct( Ops::OpType op, const BaseType* opType )
+{
+ int i = 0;
+ StructType* myStructType = (StructType*)opType;
+ int numElems = myStructType->getNumElems();
+
+ for(i = 0; i < numElems; i++) {
+ if( !isApplicable(op, myStructType->getElemType(i),
+ myStructType->getElemType(i)) )
+ return 0;
+ }
+ return 1;
+}
+
+int
+Ops::isApplicableOnStructConst( Ops::OpType op, const BaseType* op1Type,
+ const BaseType* op2Type )
+{
+ int i = 0;
+ StructType* myStructType = (StructType*)op1Type;
+ int numElems = myStructType->getNumElems();
+
+ for(i = 0; i < numElems; i++) {
+ if( !isApplicable(op, myStructType->getElemType(i), op2Type) )
+ return 0;
+ }
+ return 1;
+}
+
+int
+Ops::isSignedType( const BaseType* type )
+{
+ return ( type->getType() >= LONG && type->getType() <= COMPLEXTYPE2 );
+}
+
+int
+Ops::isCondenseOp( Ops::OpType op )
+{
+ return ( op >= OP_SOME && op <= OP_ALL );
+}
+
+int
+Ops::isUnaryOp( Ops::OpType op )
+{
+ return ( op >= OP_NOT && op <= OP_IDENTITY );
+}
+
+int
+Ops::isBinaryOp( Ops::OpType op )
+{
+ return ( op >= OP_MINUS && op <= OP_GREATEREQUAL );
+}
+
+void
+Ops::execUnaryConstOp( Ops::OpType op, const BaseType* resType,
+ const BaseType* opType, char* res,
+ const char* op1, unsigned int resOff,
+ unsigned int opOff )
+{
+ UnaryOp* myOp = Ops::getUnaryOp( op, resType, opType, resOff, opOff );
+ try
+ {
+ (*myOp)(res, op1);
+ }
+ catch(...)
+ {
+ delete myOp; // cleanup
+ throw;
+ }
+
+ delete myOp;
+}
+
+void
+Ops::execBinaryConstOp( Ops::OpType op, const BaseType* resType,
+ const BaseType* op1Type,
+ const BaseType* op2Type, char* res,
+ const char* op1, const char* op2,
+ unsigned int resOff, unsigned int op1Off,
+ unsigned int op2Off )
+{
+ BinaryOp* myOp = Ops::getBinaryOp( op, resType, op1Type, op2Type,
+ resOff, op1Off, op2Off );
+ (*myOp)(res, op1, op2);
+ delete myOp;
+}
+
+UnaryOp::UnaryOp( const BaseType* newResType, const BaseType* newOpType,
+ unsigned int newResOff, unsigned int newOpOff )
+ : resType(newResType), opType(newOpType), resOff(newResOff), opOff(newOpOff)
+{
+}
+
+OpIDENTITYStruct::OpIDENTITYStruct( const BaseType* newResType, const BaseType* newOpType,
+ unsigned int newResOff,
+ unsigned int newOpOff )
+ : UnaryOp(newResType, newOpType, newResOff, newOpOff)
+{
+}
+
+void
+OpIDENTITYStruct::operator()( char* res, const char* op )
+{
+ memcpy( (void*)(res + resOff), (void*)(op + opOff), resType->getSize() );
+}
+
+OpNOTCULong::OpNOTCULong( const BaseType* newResType, const BaseType* newOpType,
+ unsigned int newResOff, unsigned int newOpOff )
+ : UnaryOp(newResType, newOpType, newResOff, newOpOff)
+{
+}
+
+void
+OpNOTCULong::operator()( char* res, const char* op )
+{
+ r_ULong longOp;
+ r_ULong longRes;
+
+ longRes = *(opType->convertToCULong(op + opOff, &longOp)) ^ 0xFFFFFFFF;
+ resType->makeFromCULong( res + resOff, &longRes);
+}
+
+OpIDENTITYCULong::OpIDENTITYCULong( const BaseType* newResType, const BaseType* newOpType,
+ unsigned int newResOff,
+ unsigned int newOpOff )
+ : UnaryOp(newResType, newOpType, newResOff, newOpOff)
+{
+}
+
+void
+OpIDENTITYCULong::operator()( char* res, const char* op )
+{
+ r_ULong longOp;
+
+ // !!!! HP specific, assumes 4 Byte long and MSB..LSB
+ // byte order
+ resType->makeFromCULong( res + resOff,
+ opType->convertToCULong(op + opOff, &longOp) );
+}
+
+OpNOTCLong::OpNOTCLong( const BaseType* newResType, const BaseType* newOpType,
+ unsigned int newResOff, unsigned int newOpOff )
+ : UnaryOp(newResType, newOpType, newResOff, newOpOff)
+{
+}
+
+void
+OpNOTCLong::operator()( char* res, const char* op )
+{
+ r_Long longOp;
+ r_Long longRes;
+
+ longRes = *(opType->convertToCLong(op + opOff, &longOp)) ^ 0xFFFFFFFF;
+ resType->makeFromCLong( res + resOff, &longRes);
+}
+
+OpIDENTITYCLong::OpIDENTITYCLong( const BaseType* newResType, const BaseType* newOpType,
+ unsigned int newResOff,
+ unsigned int newOpOff )
+ : UnaryOp(newResType, newOpType, newResOff, newOpOff)
+{
+}
+
+void
+OpIDENTITYCLong::operator()( char* res, const char* op )
+{
+ r_Long longOp;
+
+ resType->makeFromCLong( res + resOff,
+ opType->convertToCLong(op + opOff, &longOp) );
+}
+
+OpIDENTITYCDouble::OpIDENTITYCDouble( const BaseType* newResType, const BaseType* newOpType,
+ unsigned int newResOff,
+ unsigned int newOpOff )
+ : UnaryOp(newResType, newOpType, newResOff, newOpOff)
+{
+}
+
+void
+OpIDENTITYCDouble::operator()( char* res, const char* op )
+{
+ double doubleOp;
+
+ // !!!! HP specific, assumes 4 Byte double and MSB..LSB
+ // byte order
+ resType->makeFromCDouble( res + resOff,
+ opType->convertToCDouble(op + opOff, &doubleOp) );
+}
+
+OpNOTBool::OpNOTBool( const BaseType* newResType, const BaseType* newOpType,
+ unsigned int newResOff, unsigned int newOpOff )
+ : UnaryOp(newResType, newOpType, newResOff, newOpOff)
+{
+}
+
+void
+OpNOTBool::operator()( char* res, const char* op )
+{
+ // special case for bools, because bitwise not is not
+ // equivalent to logical not
+ *(res + resOff) = !(*(op + opOff));
+}
+
+BinaryOp::BinaryOp( const BaseType* newResType, const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff,
+ unsigned int newOp1Off, unsigned int newOp2Off )
+ : resType(newResType), op1Type(newOp1Type), op2Type(newOp2Type),
+ resOff(newResOff), op1Off(newOp1Off), op2Off(newOp2Off)
+{
+}
+
+void
+BinaryOp::getCondenseInit(char* init)
+{
+ init = 0;
+ // perhaps should also raise exception as operation cannot be used
+ // as condenser.
+}
+
+OpPLUSCULong::OpPLUSCULong( const BaseType* newResType, const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff,
+ unsigned int newOp1Off, unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpPLUSCULong::operator()( char* res, const char* op1, const char* op2 )
+{
+ r_ULong longOp1 = 0;
+ r_ULong longOp2 = 0;
+ r_ULong longRes = 0;
+
+ longRes = *(op1Type->convertToCULong(op1 + op1Off, &longOp1)) +
+ *(op2Type->convertToCULong(op2 + op2Off, &longOp2));
+ resType->makeFromCULong( res + resOff, &longRes);
+}
+
+void
+OpPLUSCULong::getCondenseInit(char* init)
+{
+ r_ULong dummy = 0;
+
+ resType->makeFromCULong(init, &dummy);
+}
+
+OpPLUSULong::OpPLUSULong( const BaseType* newResType, const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff,
+ unsigned int newOp1Off, unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpPLUSULong::operator()( char* res, const char* op1, const char* op2 )
+{
+ cout << "Hier krachts?" << endl;
+ *(r_ULong*)(res + resOff) =
+ *(r_ULong*)(op1 + op1Off) + *(r_ULong*)(op2 + op2Off);
+}
+
+void
+OpPLUSULong::getCondenseInit(char* init)
+{
+ r_ULong dummy = 0;
+
+ resType->makeFromCULong(init, &dummy);
+}
+
+OpMINUSCULong::OpMINUSCULong( const BaseType* newResType, const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff,
+ unsigned int newOp1Off, unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpMINUSCULong::operator()( char* res, const char* op1, const char* op2 )
+{
+ r_ULong longOp1 = 0;
+ r_ULong longOp2 = 0;
+ r_ULong longRes = 0;
+
+ longRes = *(op1Type->convertToCULong(op1 + op1Off, &longOp1)) -
+ *(op2Type->convertToCULong(op2 + op2Off, &longOp2));
+ resType->makeFromCULong( res + resOff, &longRes);
+}
+
+OpDIVCULong::OpDIVCULong( const BaseType* newResType, const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff,
+ unsigned int newOp1Off, unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpDIVCULong::operator()( char* res, const char* op1, const char* op2 )
+{
+ r_ULong longOp1 = 0;
+ r_ULong longOp2 = 0;
+ r_ULong longRes = 0;
+
+ op2Type->convertToCULong(op2 + op2Off, &longOp2);
+
+ if(longOp2 == 0)
+ // catch division by zero, perhaps should throw exception
+ longRes = 0;
+ else {
+ longRes = *(op1Type->convertToCULong(op1 + op1Off, &longOp1)) / longOp2;
+ }
+
+ resType->makeFromCULong( res + resOff, &longRes);
+}
+
+OpMULTCULong::OpMULTCULong( const BaseType* newResType, const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff,
+ unsigned int newOp1Off, unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpMULTCULong::operator()( char* res, const char* op1, const char* op2 )
+{
+ r_ULong longOp1 = 0;
+ r_ULong longOp2 = 0;
+ r_ULong longRes = 0;
+
+ longRes = *(op1Type->convertToCULong(op1 + op1Off, &longOp1)) *
+ *(op2Type->convertToCULong(op2 + op2Off, &longOp2));
+ resType->makeFromCULong( res + resOff, &longRes);
+}
+
+void
+OpMULTCULong::getCondenseInit(char* init)
+{
+ r_ULong dummy = 1;
+
+ resType->makeFromCULong(init, &dummy);
+}
+
+OpANDCULong::OpANDCULong( const BaseType* newResType, const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff,
+ unsigned int newOp1Off, unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpANDCULong::operator()( char* res, const char* op1, const char* op2 )
+{
+ r_ULong longOp1 = 0;
+ r_ULong longOp2 = 0;
+ r_ULong longRes = 0;
+
+ longRes = *(op1Type->convertToCULong(op1 + op1Off, &longOp1)) &
+ *(op2Type->convertToCULong(op2 + op2Off, &longOp2));
+ resType->makeFromCULong( res + resOff, &longRes);
+}
+
+void
+OpANDCULong::getCondenseInit(char* init)
+{
+ char dummy[8] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+
+ memcpy( init, dummy, resType->getSize() );
+}
+
+OpANDBool::OpANDBool( const BaseType* newResType, const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff,
+ unsigned int newOp1Off, unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpANDBool::operator()( char* res, const char* op1, const char* op2 )
+{
+ *(res + resOff) = (*(op1 + op1Off) && *(op2 + op2Off));
+}
+
+void
+OpANDBool::getCondenseInit(char* init)
+{
+ *init = 1;
+}
+
+OpORCULong::OpORCULong( const BaseType* newResType, const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff,
+ unsigned int newOp1Off, unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpORCULong::operator()( char* res, const char* op1, const char* op2 )
+{
+ r_ULong longOp1 = 0;
+ r_ULong longOp2 = 0;
+ r_ULong longRes = 0;
+
+ longRes = *(op1Type->convertToCULong(op1 + op1Off, &longOp1)) |
+ *(op2Type->convertToCULong(op2 + op2Off, &longOp2));
+ resType->makeFromCULong( res + resOff, &longRes);
+}
+
+void
+OpORCULong::getCondenseInit(char* init)
+{
+ char dummy[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ memcpy( init, dummy, resType->getSize() );
+}
+
+OpORBool::OpORBool( const BaseType* newResType, const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff,
+ unsigned int newOp1Off, unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpORBool::operator()( char* res, const char* op1, const char* op2 )
+{
+ *(res + resOff) = (*(op1 + op1Off) || *(op2 + op2Off));
+}
+
+void
+OpORBool::getCondenseInit(char* init)
+{
+ *init = 0;
+}
+
+OpXORCULong::OpXORCULong( const BaseType* newResType, const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff,
+ unsigned int newOp1Off, unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpXORCULong::operator()( char* res, const char* op1, const char* op2 )
+{
+ r_ULong longOp1 = 0;
+ r_ULong longOp2 = 0;
+ r_ULong longRes = 0;
+
+ longRes = *(op1Type->convertToCULong(op1 + op1Off, &longOp1)) ^
+ *(op2Type->convertToCULong(op2 + op2Off, &longOp2));
+ resType->makeFromCULong( res + resOff, &longRes);
+}
+
+OpXORBool::OpXORBool( const BaseType* newResType, const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff,
+ unsigned int newOp1Off, unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpXORBool::operator()( char* res, const char* op1, const char* op2 )
+{
+ *(res + resOff) = !(*(op1 + op1Off) == *(op2 + op2Off));
+}
+
+OpPLUSCLong::OpPLUSCLong( const BaseType* newResType, const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff,
+ unsigned int newOp1Off, unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpPLUSCLong::operator()( char* res, const char* op1, const char* op2 )
+{
+ r_Long longOp1 = 0;
+ r_Long longOp2 = 0;
+ r_Long longRes = 0;
+
+ longRes = *(op1Type->convertToCLong(op1 + op1Off, &longOp1)) +
+ *(op2Type->convertToCLong(op2 + op2Off, &longOp2));
+ resType->makeFromCLong( res + resOff, &longRes);
+}
+
+void
+OpPLUSCLong::getCondenseInit(char* init)
+{
+ r_Long dummy = 0;
+
+ resType->makeFromCLong(init, &dummy);
+}
+
+OpMINUSCLong::OpMINUSCLong( const BaseType* newResType, const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff,
+ unsigned int newOp1Off, unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpMINUSCLong::operator()( char* res, const char* op1, const char* op2 )
+{
+ r_Long longOp1 = 0;
+ r_Long longOp2 = 0;
+ r_Long longRes = 0;
+
+ longRes = *(op1Type->convertToCLong(op1 + op1Off, &longOp1)) -
+ *(op2Type->convertToCLong(op2 + op2Off, &longOp2));
+ resType->makeFromCLong( res + resOff, &longRes);
+}
+
+OpDIVCLong::OpDIVCLong( const BaseType* newResType, const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff,
+ unsigned int newOp1Off, unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpDIVCLong::operator()( char* res, const char* op1, const char* op2 )
+{
+ r_Long longOp1 = 0;
+ r_Long longOp2 = 0;
+ r_Long longRes = 0;
+
+ op2Type->convertToCLong(op2, &longOp2);
+
+ if(longOp2 == 0)
+ // catch division by zero, perhaps should throw exception
+ longRes = 0;
+ else {
+ longRes = *(op1Type->convertToCLong(op1 + op1Off, &longOp1)) / longOp2;
+ }
+
+ resType->makeFromCLong( res + resOff, &longRes);
+}
+
+OpMULTCLong::OpMULTCLong( const BaseType* newResType, const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff,
+ unsigned int newOp1Off, unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpMULTCLong::operator()( char* res, const char* op1, const char* op2 )
+{
+ r_Long longOp1 = 0;
+ r_Long longOp2 = 0;
+ r_Long longRes = 0;
+
+ longRes = *(op1Type->convertToCLong(op1 + op1Off, &longOp1)) *
+ *(op2Type->convertToCLong(op2 + op2Off, &longOp2));
+ resType->makeFromCLong( res + resOff, &longRes);
+}
+
+void
+OpMULTCLong::getCondenseInit(char* init)
+{
+ r_Long dummy = 1;
+
+ resType->makeFromCLong(init, &dummy);
+}
+
+OpANDCLong::OpANDCLong( const BaseType* newResType, const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff,
+ unsigned int newOp1Off, unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpANDCLong::operator()( char* res, const char* op1, const char* op2 )
+{
+ r_Long longOp1 = 0;
+ r_Long longOp2 = 0;
+ r_Long longRes = 0;
+
+ longRes = *(op1Type->convertToCLong(op1 + op1Off, &longOp1)) &
+ *(op2Type->convertToCLong(op2 + op2Off, &longOp2));
+ resType->makeFromCLong( res + resOff, &longRes);
+}
+
+void
+OpANDCLong::getCondenseInit(char* init)
+{
+ char dummy[8] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+
+ memcpy( init, dummy, resType->getSize() );
+}
+
+OpORCLong::OpORCLong( const BaseType* newResType, const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff,
+ unsigned int newOp1Off, unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpORCLong::operator()( char* res, const char* op1, const char* op2 )
+{
+ r_Long longOp1 = 0;
+ r_Long longOp2 = 0;
+ r_Long longRes = 0;
+
+ longRes = *(op1Type->convertToCLong(op1 + op1Off, &longOp1)) |
+ *(op2Type->convertToCLong(op2 + op2Off, &longOp2));
+ resType->makeFromCLong( res + resOff, &longRes);
+}
+
+void
+OpORCLong::getCondenseInit(char* init)
+{
+ char dummy[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ memcpy( init, dummy, resType->getSize() );
+}
+
+OpXORCLong::OpXORCLong( const BaseType* newResType, const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff,
+ unsigned int newOp1Off, unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpXORCLong::operator()( char* res, const char* op1, const char* op2 )
+{
+ r_Long longOp1 = 0;
+ r_Long longOp2 = 0;
+ r_Long longRes = 0;
+
+ longRes = *(op1Type->convertToCLong(op1 + op1Off, &longOp1)) ^
+ *(op2Type->convertToCLong(op2 + op2Off, &longOp2));
+ resType->makeFromCLong( res + resOff, &longRes);
+}
+
+OpPLUSCDouble::OpPLUSCDouble( const BaseType* newResType, const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff,
+ unsigned int newOp1Off, unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpPLUSCDouble::operator()( char* res, const char* op1, const char* op2 )
+{
+ double doubleOp1 = 0;
+ double doubleOp2 = 0;
+ double doubleRes = 0;
+
+ doubleRes = *(op1Type->convertToCDouble(op1 + op1Off, &doubleOp1)) +
+ *(op2Type->convertToCDouble(op2 + op2Off, &doubleOp2));
+ resType->makeFromCDouble( res + resOff, &doubleRes);
+}
+
+void
+OpPLUSCDouble::getCondenseInit(char* init)
+{
+ double dummy = 0.0;
+
+ resType->makeFromCDouble(init, &dummy);
+}
+
+OpMINUSCDouble::OpMINUSCDouble( const BaseType* newResType, const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff,
+ unsigned int newOp1Off, unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpMINUSCDouble::operator()( char* res, const char* op1, const char* op2 )
+{
+ double doubleOp1 = 0;
+ double doubleOp2 = 0;
+ double doubleRes = 0;
+
+ doubleRes = *(op1Type->convertToCDouble(op1 + op1Off, &doubleOp1)) -
+ *(op2Type->convertToCDouble(op2 + op2Off, &doubleOp2));
+ resType->makeFromCDouble( res + resOff, &doubleRes);
+}
+
+OpDIVCDouble::OpDIVCDouble( const BaseType* newResType, const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff,
+ unsigned int newOp1Off, unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpDIVCDouble::operator()( char* res, const char* op1, const char* op2 )
+{
+ double doubleOp1 = 0;
+ double doubleOp2 = 0;
+ double doubleRes = 0;
+
+ op2Type->convertToCDouble(op2, &doubleOp2);
+
+ if(doubleOp2 == 0)
+ // catch division by zero, perhaps should throw exception
+ doubleRes = 0;
+ else {
+ doubleRes = *(op1Type->convertToCDouble(op1 + op1Off, &doubleOp1)) / doubleOp2;
+ }
+
+ resType->makeFromCDouble( res + resOff, &doubleRes);
+}
+
+OpMULTCDouble::OpMULTCDouble( const BaseType* newResType, const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff,
+ unsigned int newOp1Off, unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpMULTCDouble::operator()( char* res, const char* op1, const char* op2 )
+{
+ double doubleOp1 = 0;
+ double doubleOp2 = 0;
+ double doubleRes = 0;
+
+ doubleRes = *(op1Type->convertToCDouble(op1 + op1Off, &doubleOp1)) *
+ *(op2Type->convertToCDouble(op2 + op2Off, &doubleOp2));
+ resType->makeFromCDouble( res + resOff, &doubleRes);
+}
+
+void
+OpMULTCDouble::getCondenseInit(char* init)
+{
+ double dummy = 1.0;
+
+ resType->makeFromCDouble(init, &dummy);
+}
+
+OpEQUALCCharCULong::OpEQUALCCharCULong( const BaseType* newResType,
+ const BaseType* newOp1Type,
+ const BaseType* newOp2Type,
+ unsigned int newResOff,
+ unsigned int newOp1Off,
+ unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpEQUALCCharCULong::operator()( char* res, const char* op1,
+ const char* op2 )
+{
+ r_ULong longOp1;
+ r_ULong longOp2;
+
+ *(res + resOff) = *(op1Type->convertToCULong(op1 + op1Off, &longOp1)) ==
+ *(op2Type->convertToCULong(op2 + op2Off, &longOp2));
+}
+
+OpLESSCCharCULong::OpLESSCCharCULong( const BaseType* newResType,
+ const BaseType* newOp1Type,
+ const BaseType* newOp2Type,
+ unsigned int newResOff,
+ unsigned int newOp1Off,
+ unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpLESSCCharCULong::operator()( char* res, const char* op1,
+ const char* op2 )
+{
+ r_ULong longOp1;
+ r_ULong longOp2;
+
+ *(res + resOff) = *(op1Type->convertToCULong(op1 + op1Off, &longOp1)) <
+ *(op2Type->convertToCULong(op2 + op2Off, &longOp2));
+}
+
+OpLESSEQUALCCharCULong::OpLESSEQUALCCharCULong( const BaseType* newResType,
+ const BaseType* newOp1Type,
+ const BaseType* newOp2Type,
+ unsigned int newResOff,
+ unsigned int newOp1Off,
+ unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpLESSEQUALCCharCULong::operator()( char* res, const char* op1,
+ const char* op2 )
+{
+ r_ULong longOp1;
+ r_ULong longOp2;
+
+ *(res + resOff) = *(op1Type->convertToCULong(op1 + op1Off, &longOp1)) <=
+ *(op2Type->convertToCULong(op2 + op2Off, &longOp2));
+}
+
+OpNOTEQUALCCharCULong::OpNOTEQUALCCharCULong( const BaseType* newResType,
+ const BaseType* newOp1Type,
+ const BaseType* newOp2Type,
+ unsigned int newResOff,
+ unsigned int newOp1Off,
+ unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpNOTEQUALCCharCULong::operator()( char* res, const char* op1,
+ const char* op2 )
+{
+ r_ULong longOp1;
+ r_ULong longOp2;
+
+ *(res + resOff) = *(op1Type->convertToCULong(op1 + op1Off, &longOp1)) !=
+ *(op2Type->convertToCULong(op2 + op2Off, &longOp2));
+}
+
+OpGREATERCCharCULong::OpGREATERCCharCULong( const BaseType* newResType,
+ const BaseType* newOp1Type,
+ const BaseType* newOp2Type,
+ unsigned int newResOff,
+ unsigned int newOp1Off,
+ unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpGREATERCCharCULong::operator()( char* res, const char* op1,
+ const char* op2 )
+{
+ r_ULong longOp1;
+ r_ULong longOp2;
+
+ *(res + resOff) = *(op1Type->convertToCULong(op1 + op1Off, &longOp1)) >
+ *(op2Type->convertToCULong(op2 + op2Off, &longOp2));
+}
+
+OpGREATEREQUALCCharCULong::OpGREATEREQUALCCharCULong( const BaseType* newResType,
+ const BaseType* newOp1Type,
+ const BaseType* newOp2Type,
+ unsigned int newResOff,
+ unsigned int newOp1Off,
+ unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpGREATEREQUALCCharCULong::operator()( char* res, const char* op1,
+ const char* op2 )
+{
+ r_ULong longOp1;
+ r_ULong longOp2;
+
+ *(res + resOff) = *(op1Type->convertToCULong(op1 + op1Off, &longOp1)) >=
+ *(op2Type->convertToCULong(op2 + op2Off, &longOp2));
+}
+
+OpEQUALCCharCLong::OpEQUALCCharCLong( const BaseType* newResType,
+ const BaseType* newOp1Type,
+ const BaseType* newOp2Type,
+ unsigned int newResOff,
+ unsigned int newOp1Off,
+ unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpEQUALCCharCLong::operator()( char* res, const char* op1,
+ const char* op2 )
+{
+ r_Long longOp1;
+ r_Long longOp2;
+
+ *(res + resOff) = *(op1Type->convertToCLong(op1 + op1Off, &longOp1)) ==
+ *(op2Type->convertToCLong(op2 + op2Off, &longOp2));
+}
+
+OpLESSCCharCLong::OpLESSCCharCLong( const BaseType* newResType,
+ const BaseType* newOp1Type,
+ const BaseType* newOp2Type,
+ unsigned int newResOff,
+ unsigned int newOp1Off,
+ unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpLESSCCharCLong::operator()( char* res, const char* op1,
+ const char* op2 )
+{
+ r_Long longOp1;
+ r_Long longOp2;
+
+ *(res + resOff) = *(op1Type->convertToCLong(op1 + op1Off, &longOp1)) <
+ *(op2Type->convertToCLong(op2 + op2Off, &longOp2));
+}
+
+OpLESSEQUALCCharCLong::OpLESSEQUALCCharCLong( const BaseType* newResType,
+ const BaseType* newOp1Type,
+ const BaseType* newOp2Type,
+ unsigned int newResOff,
+ unsigned int newOp1Off,
+ unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpLESSEQUALCCharCLong::operator()( char* res, const char* op1,
+ const char* op2 )
+{
+ r_Long longOp1;
+ r_Long longOp2;
+
+ *(res + resOff) = *(op1Type->convertToCLong(op1 + op1Off, &longOp1)) <=
+ *(op2Type->convertToCLong(op2 + op2Off, &longOp2));
+}
+
+OpNOTEQUALCCharCLong::OpNOTEQUALCCharCLong( const BaseType* newResType,
+ const BaseType* newOp1Type,
+ const BaseType* newOp2Type,
+ unsigned int newResOff,
+ unsigned int newOp1Off,
+ unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpNOTEQUALCCharCLong::operator()( char* res, const char* op1,
+ const char* op2 )
+{
+ r_Long longOp1;
+ r_Long longOp2;
+
+ *(res + resOff) = *(op1Type->convertToCLong(op1 + op1Off, &longOp1)) !=
+ *(op2Type->convertToCLong(op2 + op2Off, &longOp2));
+}
+
+OpGREATERCCharCLong::OpGREATERCCharCLong( const BaseType* newResType,
+ const BaseType* newOp1Type,
+ const BaseType* newOp2Type,
+ unsigned int newResOff,
+ unsigned int newOp1Off,
+ unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpGREATERCCharCLong::operator()( char* res, const char* op1,
+ const char* op2 )
+{
+ r_Long longOp1;
+ r_Long longOp2;
+
+ *(res + resOff) = *(op1Type->convertToCLong(op1 + op1Off, &longOp1)) >
+ *(op2Type->convertToCLong(op2 + op2Off, &longOp2));
+}
+
+OpGREATEREQUALCCharCLong::OpGREATEREQUALCCharCLong( const BaseType* newResType,
+ const BaseType* newOp1Type,
+ const BaseType* newOp2Type,
+ unsigned int newResOff,
+ unsigned int newOp1Off,
+ unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpGREATEREQUALCCharCLong::operator()( char* res, const char* op1,
+ const char* op2 )
+{
+ r_Long longOp1;
+ r_Long longOp2;
+
+ *(res + resOff) = *(op1Type->convertToCLong(op1 + op1Off, &longOp1)) >=
+ *(op2Type->convertToCLong(op2 + op2Off, &longOp2));
+}
+
+OpEQUALCCharCDouble::OpEQUALCCharCDouble( const BaseType* newResType,
+ const BaseType* newOp1Type,
+ const BaseType* newOp2Type,
+ unsigned int newResOff,
+ unsigned int newOp1Off,
+ unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpEQUALCCharCDouble::operator()( char* res, const char* op1,
+ const char* op2 )
+{
+ double doubleOp1;
+ double doubleOp2;
+
+ *(res + resOff) = *(op1Type->convertToCDouble(op1 + op1Off, &doubleOp1)) ==
+ *(op2Type->convertToCDouble(op2 + op2Off, &doubleOp2));
+}
+
+OpLESSCCharCDouble::OpLESSCCharCDouble( const BaseType* newResType,
+ const BaseType* newOp1Type,
+ const BaseType* newOp2Type,
+ unsigned int newResOff,
+ unsigned int newOp1Off,
+ unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpLESSCCharCDouble::operator()( char* res, const char* op1,
+ const char* op2 )
+{
+ double doubleOp1;
+ double doubleOp2;
+
+ *(res + resOff) = *(op1Type->convertToCDouble(op1 + op1Off, &doubleOp1)) <
+ *(op2Type->convertToCDouble(op2 + op2Off, &doubleOp2));
+}
+
+OpLESSEQUALCCharCDouble::OpLESSEQUALCCharCDouble( const BaseType* newResType,
+ const BaseType* newOp1Type,
+ const BaseType* newOp2Type,
+ unsigned int newResOff,
+ unsigned int newOp1Off,
+ unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpLESSEQUALCCharCDouble::operator()( char* res, const char* op1,
+ const char* op2 )
+{
+ double doubleOp1;
+ double doubleOp2;
+
+ *(res + resOff) = *(op1Type->convertToCDouble(op1 + op1Off, &doubleOp1)) <=
+ *(op2Type->convertToCDouble(op2 + op2Off, &doubleOp2));
+}
+
+OpNOTEQUALCCharCDouble::OpNOTEQUALCCharCDouble( const BaseType* newResType,
+ const BaseType* newOp1Type,
+ const BaseType* newOp2Type,
+ unsigned int newResOff,
+ unsigned int newOp1Off,
+ unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpNOTEQUALCCharCDouble::operator()( char* res, const char* op1,
+ const char* op2 )
+{
+ double doubleOp1;
+ double doubleOp2;
+
+ *(res + resOff) = *(op1Type->convertToCDouble(op1 + op1Off, &doubleOp1)) !=
+ *(op2Type->convertToCDouble(op2 + op2Off, &doubleOp2));
+}
+
+OpGREATERCCharCDouble::OpGREATERCCharCDouble( const BaseType* newResType,
+ const BaseType* newOp1Type,
+ const BaseType* newOp2Type,
+ unsigned int newResOff,
+ unsigned int newOp1Off,
+ unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpGREATERCCharCDouble::operator()( char* res, const char* op1,
+ const char* op2 )
+{
+ double doubleOp1;
+ double doubleOp2;
+
+ *(res + resOff) = *(op1Type->convertToCDouble(op1 + op1Off, &doubleOp1)) >
+ *(op2Type->convertToCDouble(op2 + op2Off, &doubleOp2));
+}
+
+OpGREATEREQUALCCharCDouble::OpGREATEREQUALCCharCDouble( const BaseType* newResType,
+ const BaseType* newOp1Type,
+ const BaseType* newOp2Type,
+ unsigned int newResOff,
+ unsigned int newOp1Off,
+ unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpGREATEREQUALCCharCDouble::operator()( char* res, const char* op1,
+ const char* op2 )
+{
+ double doubleOp1;
+ double doubleOp2;
+
+ *(res + resOff) = *(op1Type->convertToCDouble(op1 + op1Off, &doubleOp1)) >=
+ *(op2Type->convertToCDouble(op2 + op2Off, &doubleOp2));
+}
+
+CondenseOp::CondenseOp( const BaseType* newResType, const BaseType* newOpType,
+ unsigned int newResOff, unsigned int newOpOff )
+ : resType(newResType), opType(newOpType), resOff(newResOff), opOff(newOpOff),
+ accu(0)
+{
+}
+
+CondenseOp::CondenseOp( const BaseType* newResType, char* newAccu,
+ const BaseType* newOpType, unsigned int newResOff,
+ unsigned int newOpOff )
+ : resType(newResType), opType(newOpType), resOff(newResOff), opOff(newOpOff)
+{
+ accu = new char[resType->getSize()];
+ memcpy(accu, newAccu, resType->getSize());
+}
+
+char*
+CondenseOp::getAccuVal()
+{
+ return accu;
+}
+
+CondenseOp::~CondenseOp()
+{
+ delete [] accu;
+}
+
+
+OpSOMECChar::OpSOMECChar( const BaseType* newResType, const BaseType* newOpType,
+ unsigned int newResOff, unsigned int newOpOff )
+ : CondenseOp(newResType, newOpType, newResOff, newOpOff)
+{
+ // initialising with neutral value
+ accu = new char[1];
+ // result is always char
+ *accu = 0;
+}
+
+OpSOMECChar::OpSOMECChar( const BaseType* newResType, char* newAccu,
+ const BaseType* newOpType, unsigned int newResOff,
+ unsigned int newOpOff )
+ : CondenseOp(newResType, newAccu, newOpType, newResOff, newOpOff)
+{
+}
+
+char*
+OpSOMECChar::operator()( const char* op, char* init )
+{
+ *(unsigned char*)(init + resOff) = *(unsigned char*)(init + resOff) || *(unsigned char*)(op + opOff);
+ return init;
+}
+
+char*
+OpSOMECChar::operator()( const char* op )
+{
+ *(unsigned char*)(accu + resOff) = *(unsigned char*)(accu + resOff) || *(unsigned char*)(op + opOff);
+ return accu;
+}
+
+OpALLCChar::OpALLCChar( const BaseType* newResType, const BaseType* newOpType,
+ unsigned int newResOff, unsigned int newOpOff )
+ : CondenseOp(newResType, newOpType, newResOff, newOpOff)
+{
+ // initialising with neutral value
+ accu = new char[1];
+ // result is always char
+ *accu = 1;
+}
+
+OpALLCChar::OpALLCChar( const BaseType* newResType, char* newAccu,
+ const BaseType* newOpType, unsigned int newResOff,
+ unsigned int newOpOff )
+ : CondenseOp(newResType, newAccu, newOpType, newResOff, newOpOff)
+{
+}
+
+char*
+OpALLCChar::operator()( const char* op, char* init )
+{
+ *(unsigned char*)(init + resOff) = *(unsigned char*)(init + resOff) &&
+ *(unsigned char*)(op + opOff);
+ return init;
+}
+
+char*
+OpALLCChar::operator()( const char* op )
+{
+ *(unsigned char*)(accu + resOff) = *(unsigned char*)(accu + resOff) &&
+ *(unsigned char*)(op + opOff);
+ return accu;
+}
+
+OpCOUNTCChar::OpCOUNTCChar( const BaseType* newResType, const BaseType* newOpType,
+ unsigned int newResOff, unsigned int newOpOff )
+ : CondenseOp(newResType, newOpType, newResOff, newOpOff)
+{
+ // initialising with neutral value
+ accu = new char[4];
+ // result is always r_ULong
+ *(r_ULong*)accu = 0;
+
+}
+
+OpCOUNTCChar::OpCOUNTCChar( const BaseType* newResType, char* newAccu,
+ const BaseType* newOpType, unsigned int newResOff,
+ unsigned int newOpOff )
+ : CondenseOp(newResType, newAccu, newOpType, newResOff, newOpOff)
+{
+}
+
+char*
+OpCOUNTCChar::operator()( const char* op, char* init )
+{
+ *(r_ULong*)(init + resOff) = *(r_ULong*)(init + resOff) +
+ *(unsigned char*)(op + opOff);
+ return init;
+}
+
+char*
+OpCOUNTCChar::operator()( const char* op )
+{
+ *(r_ULong*)(accu + resOff) = *(r_ULong*)(accu + resOff) +
+ *(unsigned char*)(op + opOff);
+ return accu;
+}
+
+OpMAXCULong::OpMAXCULong( const BaseType* newResType, const BaseType* newOpType,
+ unsigned int newResOff, unsigned int newOpOff )
+ : CondenseOp(newResType, newOpType, newResOff, newOpOff)
+{
+ r_ULong myVal = 0;
+ // initialising with neutral value
+ accu = new char[resType->getSize()];
+ resType->makeFromCULong(accu, &myVal);
+}
+
+OpMAXCULong::OpMAXCULong( const BaseType* newResType, char* newAccu,
+ const BaseType* newOpType, unsigned int newResOff,
+ unsigned int newOpOff )
+ : CondenseOp(newResType, newAccu, newOpType, newResOff, newOpOff)
+{
+}
+
+char*
+OpMAXCULong::operator()( const char* op, char* init )
+{
+ r_ULong longOp = 0;
+ r_ULong longRes = 0;
+
+ longOp = *(opType->convertToCULong(op + opOff, &longOp));
+ longRes = *(resType->convertToCULong(init + resOff, &longRes));
+
+ if(longOp > longRes) {
+ resType->makeFromCULong(init + resOff, &longOp);
+ }
+
+ return init;
+}
+
+char*
+OpMAXCULong::operator()( const char* op )
+{
+ return OpMAXCULong::operator()(op, accu);
+}
+
+OpMAXCLong::OpMAXCLong( const BaseType* newResType, const BaseType* newOpType,
+ unsigned int newResOff, unsigned int newOpOff )
+ : CondenseOp(newResType, newOpType, newResOff, newOpOff)
+{
+ r_Long myVal = INT_MIN;
+ // initialising with neutral value
+ accu = new char[resType->getSize()];
+ resType->makeFromCLong(accu, &myVal);
+}
+
+OpMAXCLong::OpMAXCLong( const BaseType* newResType, char* newAccu,
+ const BaseType* newOpType, unsigned int newResOff,
+ unsigned int newOpOff )
+ : CondenseOp(newResType, newAccu, newOpType, newResOff, newOpOff)
+{
+}
+
+char*
+OpMAXCLong::operator()( const char* op, char* init )
+{
+ r_Long longOp = 0;
+ r_Long longRes = 0;
+
+ longOp = *(opType->convertToCLong(op + opOff, &longOp));
+ longRes = *(resType->convertToCLong(init + resOff, &longRes));
+
+ if(longOp > longRes) {
+ resType->makeFromCLong(init + resOff, &longOp);
+ }
+
+ return init;
+}
+
+char*
+OpMAXCLong::operator()( const char* op )
+{
+ return OpMAXCLong::operator()(op, accu);
+}
+
+OpMAXCDouble::OpMAXCDouble( const BaseType* newResType, const BaseType* newOpType,
+ unsigned int newResOff, unsigned int newOpOff )
+ : CondenseOp(newResType, newOpType, newResOff, newOpOff)
+{
+ double myVal = (-1.0)*DBL_MAX;
+ // initialising with neutral value
+ accu = new char[resType->getSize()];
+ // make sure accu contains a legal float
+ memset(accu, 0, resType->getSize());
+ resType->makeFromCDouble(accu, &myVal);
+}
+
+OpMAXCDouble::OpMAXCDouble( const BaseType* newResType, char* newAccu,
+ const BaseType* newOpType, unsigned int newResOff,
+ unsigned int newOpOff )
+ : CondenseOp(newResType, newAccu, newOpType, newResOff, newOpOff)
+{
+}
+
+char*
+OpMAXCDouble::operator()( const char* op, char* init )
+{
+ double longOp = 0;
+ double longRes = 0;
+
+ longOp = *(opType->convertToCDouble(op + opOff, &longOp));
+ longRes = *(resType->convertToCDouble(init + resOff, &longRes));
+
+ if(longOp > longRes) {
+ resType->makeFromCDouble(init + resOff, &longOp);
+ }
+
+ return init;
+}
+
+char*
+OpMAXCDouble::operator()( const char* op )
+{
+ return OpMAXCDouble::operator()(op, accu);
+}
+
+OpMINCULong::OpMINCULong( const BaseType* newResType, const BaseType* newOpType,
+ unsigned int newResOff, unsigned int newOpOff )
+ : CondenseOp(newResType, newOpType, newResOff, newOpOff)
+{
+ r_ULong myVal = UINT_MAX;
+ // initialising with neutral value
+ accu = new char[resType->getSize()];
+ resType->makeFromCULong(accu, &myVal);
+}
+
+OpMINCULong::OpMINCULong( const BaseType* newResType, char* newAccu,
+ const BaseType* newOpType, unsigned int newResOff,
+ unsigned int newOpOff )
+ : CondenseOp(newResType, newAccu, newOpType, newResOff, newOpOff)
+{
+}
+
+char*
+OpMINCULong::operator()( const char* op, char* init )
+{
+ r_ULong longOp = 0;
+ r_ULong longRes = 0;
+
+ longOp = *(opType->convertToCULong(op + opOff, &longOp));
+ longRes = *(resType->convertToCULong(init + resOff, &longRes));
+
+ if(longOp < longRes) {
+ resType->makeFromCULong(init + resOff, &longOp);
+ }
+
+ return init;
+}
+
+char*
+OpMINCULong::operator()( const char* op )
+{
+ return OpMINCULong::operator()(op, accu);
+}
+
+OpMINCLong::OpMINCLong( const BaseType* newResType, const BaseType* newOpType,
+ unsigned int newResOff, unsigned int newOpOff )
+ : CondenseOp(newResType, newOpType, newResOff, newOpOff)
+{
+ r_Long myVal = INT_MAX;
+ // initialising with neutral value
+ accu = new char[resType->getSize()];
+ resType->makeFromCLong(accu, &myVal);
+}
+
+OpMINCLong::OpMINCLong( const BaseType* newResType, char* newAccu,
+ const BaseType* newOpType, unsigned int newResOff,
+ unsigned int newOpOff )
+ : CondenseOp(newResType, newAccu, newOpType, newResOff, newOpOff)
+{
+}
+
+char*
+OpMINCLong::operator()( const char* op, char* init )
+{
+ r_Long longOp = 0;
+ r_Long longRes = 0;
+
+ longOp = *(opType->convertToCLong(op + opOff, &longOp));
+ longRes = *(resType->convertToCLong(init + resOff, &longRes));
+
+ if(longOp < longRes) {
+ resType->makeFromCLong(init + resOff, &longOp);
+ }
+
+ return init;
+}
+
+char*
+OpMINCLong::operator()( const char* op )
+{
+ return OpMINCLong::operator()(op, accu);
+}
+
+OpMINCDouble::OpMINCDouble( const BaseType* newResType, const BaseType* newOpType,
+ unsigned int newResOff, unsigned int newOpOff )
+ : CondenseOp(newResType, newOpType, newResOff, newOpOff)
+{
+ double myVal = DBL_MAX;
+ // initialising with neutral value
+ accu = new char[resType->getSize()];
+ // make sure accu contains a legal float
+ memset(accu, 0, resType->getSize());
+ resType->makeFromCDouble(accu, &myVal);
+}
+
+
+OpMINCDouble::OpMINCDouble( const BaseType* newResType, char* newAccu,
+ const BaseType* newOpType, unsigned int newResOff,
+ unsigned int newOpOff )
+ : CondenseOp(newResType, newAccu, newOpType, newResOff, newOpOff)
+{
+}
+
+char*
+OpMINCDouble::operator()( const char* op, char* init )
+{
+ double longOp = 0;
+ double longRes = 0;
+
+ longOp = *(opType->convertToCDouble(op + opOff, &longOp));
+ longRes = *(resType->convertToCDouble(init + resOff, &longRes));
+
+ if(longOp < longRes) {
+ resType->makeFromCDouble(init + resOff, &longOp);
+ }
+
+ return init;
+}
+
+char*
+OpMINCDouble::operator()( const char* op )
+{
+ return OpMINCDouble::operator()(op, accu);
+}
+
+OpSUMCULong::OpSUMCULong( const BaseType* newResType, const BaseType* newOpType,
+ unsigned int newResOff, unsigned int newOpOff )
+ : CondenseOp(newResType, newOpType, newResOff, newOpOff)
+{
+ r_ULong myVal = 0;
+ // initialising with neutral value
+ accu = new char[resType->getSize()];
+ resType->makeFromCULong(accu, &myVal);
+}
+
+OpSUMCULong::OpSUMCULong( const BaseType* newResType, char* newAccu,
+ const BaseType* newOpType, unsigned int newResOff,
+ unsigned int newOpOff )
+ : CondenseOp(newResType, newAccu, newOpType, newResOff, newOpOff)
+{
+}
+
+char*
+OpSUMCULong::operator()( const char* op, char* init )
+{
+ r_ULong longOp = 0;
+ r_ULong longRes = 0;
+
+ opType->convertToCULong(op + opOff, &longOp);
+ resType->convertToCULong(init + resOff, &longRes);
+
+ longRes += longOp;
+ resType->makeFromCULong( init + resOff, &longRes);
+
+ return init;
+}
+
+char*
+OpSUMCULong::operator()( const char* op )
+{
+ return OpSUMCULong::operator()(op, accu);
+}
+
+OpSUMCLong::OpSUMCLong( const BaseType* newResType, const BaseType* newOpType,
+ unsigned int newResOff, unsigned int newOpOff )
+ : CondenseOp(newResType, newOpType, newResOff, newOpOff)
+{
+ r_Long myVal = 0;
+ // initialising with neutral value
+ accu = new char[resType->getSize()];
+ resType->makeFromCLong(accu, &myVal);
+}
+
+OpSUMCLong::OpSUMCLong( const BaseType* newResType, char* newAccu,
+ const BaseType* newOpType, unsigned int newResOff,
+ unsigned int newOpOff )
+ : CondenseOp(newResType, newAccu, newOpType, newResOff, newOpOff)
+{
+}
+
+char*
+OpSUMCLong::operator()( const char* op, char* init )
+{
+ r_Long longOp = 0;
+ r_Long longRes = 0;
+
+ longOp = *(opType->convertToCLong(op + opOff, &longOp));
+ longRes = *(resType->convertToCLong(init + resOff, &longRes));
+
+ longRes = longOp + longRes;
+ resType->makeFromCLong( init + resOff, &longRes);
+
+ return init;
+}
+
+char*
+OpSUMCLong::operator()( const char* op )
+{
+ return OpSUMCLong::operator()(op, accu);
+}
+
+OpSUMCDouble::OpSUMCDouble( const BaseType* newResType, const BaseType* newOpType,
+ unsigned int newResOff, unsigned int newOpOff )
+ : CondenseOp(newResType, newOpType, newResOff, newOpOff)
+{
+ double myVal = 0.0;
+ // initialising with neutral value
+ accu = new char[resType->getSize()];
+ resType->makeFromCDouble(accu, &myVal);
+}
+
+OpSUMCDouble::OpSUMCDouble( const BaseType* newResType, char* newAccu,
+ const BaseType* newOpType, unsigned int newResOff,
+ unsigned int newOpOff )
+ : CondenseOp(newResType, newAccu, newOpType, newResOff, newOpOff)
+{
+}
+
+char*
+OpSUMCDouble::operator()( const char* op, char* init )
+{
+ double longOp = 0;
+ double longRes = 0;
+
+ longOp = *(opType->convertToCDouble(op + opOff, &longOp));
+ longRes = *(resType->convertToCDouble(init + resOff, &longRes));
+
+ longRes = longOp + longRes;
+ resType->makeFromCDouble( init + resOff, &longRes);
+
+ return init;
+}
+
+char*
+OpSUMCDouble::operator()( const char* op )
+{
+ return OpSUMCDouble::operator()(op, accu);
+}
+
+OpCondenseStruct::OpCondenseStruct(
+ const BaseType* newResType,
+ const BaseType* newOpType,
+ Ops::OpType op,
+ unsigned int newResOff,
+ unsigned int newOpOff )
+ : CondenseOp(newResType, newOpType, newResOff, newOpOff)
+{
+ int i = 0;
+
+ myResType = (StructType*)newResType;
+ myOpType = (StructType*)newOpType;
+ numElems = myOpType->getNumElems();
+ elemOps = new CondenseOp*[numElems];
+ for(i = 0; i < numElems; i++) {
+ elemOps[i] = Ops::getCondenseOp(
+ op,
+ myResType->getElemType(i),
+ myOpType->getElemType(i),
+ newResOff + myResType->getOffset(i),
+ newOpOff + myOpType->getOffset(i)
+ );
+ }
+
+ accu = new char[resType->getSize()];
+ for(i = 0; i < numElems; i++) {
+ memcpy(accu + myResType->getOffset(i), elemOps[i]->getAccuVal(),
+ myResType->getElemType(i)->getSize());
+ }
+
+}
+
+//--------------------------------------------
+// OpCondenseStruct
+//--------------------------------------------
+
+OpCondenseStruct::OpCondenseStruct(
+ const BaseType* newResType,
+ char* newAccu,
+ const BaseType* newOpType,
+ Ops::OpType op,
+ unsigned int newResOff,
+ unsigned int newOpOff )
+ : CondenseOp(newResType, newOpType, newResOff, newOpOff)
+{
+ int i = 0;
+
+ myResType = (StructType*)newResType;
+ myOpType = (StructType*)newOpType;
+ numElems = myOpType->getNumElems();
+ elemOps = new CondenseOp*[numElems];
+ for(i = 0; i < numElems; i++) {
+ elemOps[i] = Ops::getCondenseOp(
+ op,
+ myResType->getElemType(i),
+ myOpType->getElemType(i),
+ newResOff + myResType->getOffset(i),
+ newOpOff + myOpType->getOffset(i)
+ );
+ }
+
+ accu = new char[resType->getSize()];
+ memcpy(accu, newAccu, resType->getSize());
+}
+
+OpCondenseStruct::~OpCondenseStruct()
+{
+ int i;
+
+ for(i = 0; i < numElems; i++) {
+ delete elemOps[i];
+ }
+ delete[] elemOps;
+}
+
+char*
+OpCondenseStruct::operator()( const char* op, char* init )
+{
+ int i;
+
+ for(i = 0; i < numElems; i++) {
+ (*elemOps[i])(op, init);
+ }
+ return init;
+}
+
+char*
+OpCondenseStruct::operator()( const char* op )
+{
+ int i;
+
+ for(i = 0; i < numElems; i++) {
+ (*elemOps[i])(op, accu);
+ }
+ return accu;
+}
+
+
+
+//--------------------------------------------
+// OpBinaryStruct
+//--------------------------------------------
+
+static Ops::OpType _operation;
+
+OpBinaryStruct::OpBinaryStruct( const BaseType* newStructType, Ops::OpType op,
+ unsigned int newResOff, unsigned int newOp1Off,
+ unsigned int newOp2Off )
+ : BinaryOp(newStructType, newStructType, newStructType, newResOff,
+ newOp1Off, newOp2Off)
+{
+ int i = 0;
+
+ _operation = op;
+
+ myStructType = (StructType*)newStructType;
+ numElems = myStructType->getNumElems();
+ elemOps = new BinaryOp*[numElems];
+ for(i = 0; i < numElems; i++) {
+ elemOps[i] = Ops::getBinaryOp( op, myStructType->getElemType(i),
+ myStructType->getElemType(i),
+ myStructType->getElemType(i),
+ newResOff + myStructType->getOffset(i),
+ newOp1Off + myStructType->getOffset(i),
+ newOp2Off + myStructType->getOffset(i) );
+ }
+}
+
+OpBinaryStruct::~OpBinaryStruct()
+{
+ int i;
+
+ for(i = 0; i < numElems; i++) {
+ delete elemOps[i];
+ }
+ delete[] elemOps;
+}
+
+void
+OpBinaryStruct::operator()( char* res, const char* op1,
+ const char* op2 )
+{
+ int i;
+
+ if( _operation == Ops::OP_OVERLAY )
+ {
+ RMInit::logOut << "OpBinaryStruct operation" << endl;
+ for(i = 0; i < numElems; ++i)
+ if(*(op2 + op2Off)) {
+ for(int j = 0; j < numElems; ++j)
+ *(res + resOff) = *(op2 + op2Off);
+ return;
+ }
+ }
+
+
+ for(i = 0; i < numElems; i++) {
+ (*elemOps[i])(res, op1, op2);
+ }
+
+}
+
+//--------------------------------------------
+// OpBinaryStructConst
+//--------------------------------------------
+
+OpBinaryStructConst::OpBinaryStructConst(
+ const BaseType* res,
+ const BaseType* op1,
+ const BaseType* op2,
+ Ops::OpType op,
+ unsigned int newResOff,
+ unsigned int newOp1Off,
+ unsigned int newOp2Off )
+ : BinaryOp(res, op1, op2, newResOff,
+ newOp1Off, newOp2Off)
+{
+ int i = 0;
+
+ resStructType = (StructType*)resType;
+ opStructType = (StructType*)op1Type;
+ numElems = opStructType->getNumElems();
+ elemOps = new BinaryOp*[numElems];
+ for(i = 0; i < numElems; i++) {
+ elemOps[i] = Ops::getBinaryOp( op,
+ resStructType->getElemType(i),
+ opStructType->getElemType(i),
+ op2Type,
+ newResOff + resStructType->getOffset(i),
+ newOp1Off + opStructType->getOffset(i),
+ newOp2Off );
+ }
+}
+
+OpBinaryStructConst::~OpBinaryStructConst()
+{
+ int i;
+
+ for(i = 0; i < numElems; i++) {
+ delete elemOps[i];
+ }
+ delete[] elemOps;
+}
+
+void
+OpBinaryStructConst::operator()( char* res, const char* op1,
+ const char* op2 )
+{
+ int i;
+
+ for(i = 0; i < numElems; i++) {
+ (*elemOps[i])(res, op1, op2);
+ }
+}
+
+//--------------------------------------------
+// OpBinaryConstStruct
+//--------------------------------------------
+
+OpBinaryConstStruct::OpBinaryConstStruct(
+ const BaseType* res,
+ const BaseType* op1,
+ const BaseType* op2,
+ Ops::OpType op,
+ unsigned int newResOff,
+ unsigned int newOp1Off,
+ unsigned int newOp2Off )
+ : BinaryOp(res, op1, op2, newResOff,
+ newOp1Off, newOp2Off)
+{
+ int i = 0;
+
+ resStructType = (StructType*)resType;
+ opStructType = (StructType*)op2Type;
+ numElems = opStructType->getNumElems();
+ elemOps = new BinaryOp*[numElems];
+ for(i = 0; i < numElems; i++) {
+ elemOps[i] = Ops::getBinaryOp( op,
+ resStructType->getElemType(i),
+ op1Type,
+ opStructType->getElemType(i),
+ newResOff + resStructType->getOffset(i),
+ newOp1Off,
+ newOp2Off + opStructType->getOffset(i) );
+ }
+}
+
+OpBinaryConstStruct::~OpBinaryConstStruct()
+{
+ int i;
+
+ for(i = 0; i < numElems; i++) {
+ delete elemOps[i];
+ }
+ delete[] elemOps;
+}
+
+void
+OpBinaryConstStruct::operator()( char* res, const char* op1,
+ const char* op2 )
+{
+ int i;
+
+ for(i = 0; i < numElems; i++) {
+ (*elemOps[i])(res, op1, op2);
+ }
+}
+
+//--------------------------------------------
+// OpEQUALStruct
+//--------------------------------------------
+
+OpEQUALStruct::OpEQUALStruct( const BaseType* newResType,
+ const BaseType* newOp1Type,
+ const BaseType* newOp2Type,
+ unsigned int newResOff,
+ unsigned int newOp1Off,
+ unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+ int i = 0;
+
+ numElems = ((StructType*)op1Type)->getNumElems();
+ elemOps = new BinaryOp*[numElems];
+ for(i = 0; i < numElems; i++) {
+ elemOps[i] =
+ Ops::getBinaryOp( Ops::OP_EQUAL, resType,
+ ((StructType*)op1Type)->getElemType(i),
+ ((StructType*)op2Type)->getElemType(i),
+ newResOff,
+ newOp1Off + ((StructType*)op1Type)->getOffset(i),
+ newOp2Off + ((StructType*)op2Type)->getOffset(i) );
+ }
+}
+
+OpEQUALStruct::~OpEQUALStruct()
+{
+ int i;
+
+ for(i = 0; i < numElems; i++) {
+ delete elemOps[i];
+ }
+ delete[] elemOps;
+}
+
+void
+OpEQUALStruct::operator()( char* res, const char* op1,
+ const char* op2 )
+{
+ int i;
+ char dummy = 1;
+
+ for(i = 0; i < numElems; i++) {
+ (*elemOps[i])(res, op1, op2);
+ dummy = *res && dummy;
+ }
+ *res = dummy;
+}
+
+//--------------------------------------------
+// OpNOTEQUALStruct
+//--------------------------------------------
+
+OpNOTEQUALStruct::OpNOTEQUALStruct( const BaseType* newResType,
+ const BaseType* newOp1Type,
+ const BaseType* newOp2Type,
+ unsigned int newResOff,
+ unsigned int newOp1Off,
+ unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+ int i = 0;
+
+ numElems = ((StructType*)op1Type)->getNumElems();
+ elemOps = new BinaryOp*[numElems];
+ for(i = 0; i < numElems; i++) {
+ elemOps[i] =
+ Ops::getBinaryOp( Ops::OP_NOTEQUAL, resType,
+ ((StructType*)op1Type)->getElemType(i),
+ ((StructType*)op2Type)->getElemType(i),
+ newResOff,
+ newOp1Off + ((StructType*)op1Type)->getOffset(i),
+ newOp2Off + ((StructType*)op2Type)->getOffset(i) );
+ }
+}
+
+OpNOTEQUALStruct::~OpNOTEQUALStruct()
+{
+ int i;
+
+ for(i = 0; i < numElems; i++) {
+ delete elemOps[i];
+ }
+ delete[] elemOps;
+}
+
+void
+OpNOTEQUALStruct::operator()( char* res, const char* op1,
+ const char* op2 )
+{
+ int i;
+ char dummy = 0;
+
+ for(i = 0; i < numElems; i++) {
+ (*elemOps[i])(res, op1, op2);
+ dummy = *res || dummy;
+ }
+ *res = dummy;
+}
+
+//--------------------------------------------
+// OpUnaryStruct
+//--------------------------------------------
+
+OpUnaryStruct::OpUnaryStruct(
+ const BaseType* newResType,
+ const BaseType* newOpType,
+ Ops::OpType op,
+ unsigned int newResOff,
+ unsigned int newOpOff)
+ : UnaryOp(newResType, newOpType, newResOff, newOpOff)
+{
+ int i = 0;
+
+ myResType = (StructType*)newResType;
+ myOpType = (StructType*)newOpType;
+ numElems = myOpType->getNumElems();
+ elemOps = new UnaryOp*[numElems];
+ for(i = 0; i < numElems; i++) {
+ elemOps[i] = Ops::getUnaryOp(
+ op,
+ myResType->getElemType(i),
+ myOpType->getElemType(i),
+ newResOff + myResType->getOffset(i),
+ newOpOff + myOpType->getOffset(i)
+ );
+ }
+}
+
+OpUnaryStruct::~OpUnaryStruct()
+{
+ int i;
+
+ for(i = 0; i < numElems; i++) {
+ delete elemOps[i];
+ }
+ delete[] elemOps;
+}
+
+void
+OpUnaryStruct::operator()( char* result, const char* op )
+{
+ int i;
+
+ for(i = 0; i < numElems; i++) {
+ try {
+ (*elemOps[i])(result, op);
+ }
+ catch(...) {
+ // cleanup
+ for(i = 0; i < numElems; i++) {
+ delete elemOps[i];
+ }
+ delete[] elemOps;
+ throw;
+ }
+ }
+}
+
+//--------------------------------------------
+// OpPLUSChar
+//--------------------------------------------
+
+OpPLUSChar::OpPLUSChar( const BaseType* newResType, const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff,
+ unsigned int newOp1Off, unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpPLUSChar::operator()( char* res, const char* op1, const char* op2 )
+{
+ *(unsigned char*)(res + resOff) =
+ *(unsigned char*)(op1 + op1Off) + *(unsigned char*)(op2 + op2Off);
+}
+
+void
+OpPLUSChar::getCondenseInit(char* init)
+{
+ *init = 0;
+}
+
+//--------------------------------------------
+// OpMINUSChar
+//--------------------------------------------
+
+OpMINUSChar::OpMINUSChar( const BaseType* newResType, const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff,
+ unsigned int newOp1Off, unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpMINUSChar::operator()( char* res, const char* op1, const char* op2 )
+{
+ *(unsigned char*)(res + resOff) =
+ *(unsigned char*)(op1 + op1Off) - *(unsigned char*)(op2 + op2Off);
+}
+
+//--------------------------------------------
+// OpDIVChar
+//--------------------------------------------
+
+OpDIVChar::OpDIVChar( const BaseType* newResType, const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff,
+ unsigned int newOp1Off, unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpDIVChar::operator()( char* res, const char* op1, const char* op2 )
+{
+ if(*(unsigned char*)(op2 + op2Off) == 0)
+ // catch division by zero, perhaps should throw exception
+ *(unsigned char*)(res + resOff) = 0;
+ else {
+ *(unsigned char*)(res + resOff) = *(unsigned char*)(op1 + op1Off) /
+ *(unsigned char*)(op2 + op2Off);
+ }
+}
+
+//--------------------------------------------
+// OpMULTChar
+//--------------------------------------------
+
+OpMULTChar::OpMULTChar( const BaseType* newResType, const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff,
+ unsigned int newOp1Off, unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpMULTChar::operator()( char* res, const char* op1, const char* op2 )
+{
+ *(unsigned char*)(res + resOff) =
+ *(unsigned char*)(op1 + op1Off) * *(unsigned char*)(op2 + op2Off);
+}
+
+void
+OpMULTChar::getCondenseInit(char* init)
+{
+ *init = 1;
+}
+
+//--------------------------------------------
+// OpEQUALChar
+//--------------------------------------------
+
+OpEQUALChar::OpEQUALChar( const BaseType* newResType,
+ const BaseType* newOp1Type,
+ const BaseType* newOp2Type,
+ unsigned int newResOff,
+ unsigned int newOp1Off,
+ unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpEQUALChar::operator()( char* res, const char* op1,
+ const char* op2 )
+{
+ *(unsigned char*)(res + resOff) = *(unsigned char*)(op1 + op1Off) ==
+ *(unsigned char*)(op2 + op2Off);
+}
+
+//--------------------------------------------
+// OpLESSChar
+//--------------------------------------------
+
+OpLESSChar::OpLESSChar( const BaseType* newResType,
+ const BaseType* newOp1Type,
+ const BaseType* newOp2Type,
+ unsigned int newResOff,
+ unsigned int newOp1Off,
+ unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpLESSChar::operator()( char* res, const char* op1,
+ const char* op2 )
+{
+ *(unsigned char*)(res + resOff) = *(unsigned char*)(op1 + op1Off) <
+ *(unsigned char*)(op2 + op2Off);
+}
+
+//--------------------------------------------
+// OpLESSEQUALChar
+//--------------------------------------------
+
+OpLESSEQUALChar::OpLESSEQUALChar( const BaseType* newResType,
+ const BaseType* newOp1Type,
+ const BaseType* newOp2Type,
+ unsigned int newResOff,
+ unsigned int newOp1Off,
+ unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpLESSEQUALChar::operator()( char* res, const char* op1,
+ const char* op2 )
+{
+ *(unsigned char*)(res + resOff) = *(unsigned char*)(op1 + op1Off) <=
+ *(unsigned char*)(op2 + op2Off);
+}
+
+//--------------------------------------------
+// OpNOTEQUALChar
+//--------------------------------------------
+
+OpNOTEQUALChar::OpNOTEQUALChar( const BaseType* newResType,
+ const BaseType* newOp1Type,
+ const BaseType* newOp2Type,
+ unsigned int newResOff,
+ unsigned int newOp1Off,
+ unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpNOTEQUALChar::operator()( char* res, const char* op1,
+ const char* op2 )
+{
+ *(unsigned char*)(res + resOff) = *(unsigned char*)(op1 + op1Off) !=
+ *(unsigned char*)(op2 + op2Off);
+}
+
+
+//--------------------------------------------
+// OpGREATERChar
+//--------------------------------------------
+
+OpGREATERChar::OpGREATERChar( const BaseType* newResType,
+ const BaseType* newOp1Type,
+ const BaseType* newOp2Type,
+ unsigned int newResOff,
+ unsigned int newOp1Off,
+ unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpGREATERChar::operator()( char* res, const char* op1,
+ const char* op2 )
+{
+ *(unsigned char*)(res + resOff) = *(unsigned char*)(op1 + op1Off) >
+ *(unsigned char*)(op2 + op2Off);
+}
+
+
+
+//--------------------------------------------
+// OpGREATEREQUALChar
+//--------------------------------------------
+
+OpGREATEREQUALChar::OpGREATEREQUALChar( const BaseType* newResType,
+ const BaseType* newOp1Type,
+ const BaseType* newOp2Type,
+ unsigned int newResOff,
+ unsigned int newOp1Off,
+ unsigned int newOp2Off )
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff,
+ newOp1Off, newOp2Off)
+{
+}
+
+void
+OpGREATEREQUALChar::operator()( char* res, const char* op1,
+ const char* op2 )
+{
+ *(unsigned char*)(res + resOff) = *(unsigned char*)(op1 + op1Off) >=
+ *(unsigned char*)(op2 + op2Off);
+}
+
+//--------------------------------------------
+// OpIDENTITYChar
+//--------------------------------------------
+
+OpIDENTITYChar::OpIDENTITYChar( const BaseType* newResType, const BaseType* newOpType,
+ unsigned int newResOff,
+ unsigned int newOpOff )
+ : UnaryOp(newResType, newOpType, newResOff, newOpOff)
+{
+}
+
+void
+OpIDENTITYChar::operator()( char* res, const char* op )
+{
+ *(unsigned char*)(res + resOff) = *(unsigned char*)(op + opOff);
+}
+
+//--------------------------------------------
+//
+//--------------------------------------------
+
+OpIDENTITYShort::OpIDENTITYShort( const BaseType* newResType, const BaseType* newOpType,
+ unsigned int newResOff,
+ unsigned int newOpOff )
+ : UnaryOp(newResType, newOpType, newResOff, newOpOff)
+{
+}
+
+void
+OpIDENTITYShort::operator()( char* res, const char* op )
+{
+ *(unsigned short*)(res + resOff) = *(unsigned short*)(op + opOff);
+}
+
+//--------------------------------------------
+// OpIDENTITYLong
+//--------------------------------------------
+
+OpIDENTITYLong::OpIDENTITYLong( const BaseType* newResType, const BaseType* newOpType,
+ unsigned int newResOff,
+ unsigned int newOpOff )
+ : UnaryOp(newResType, newOpType, newResOff, newOpOff)
+{
+}
+
+void
+OpIDENTITYLong::operator()( char* res, const char* op )
+{
+ *(r_ULong*)(res + resOff) = *(r_ULong*)(op + opOff);
+}
+
+//--------------------------------------------
+// MarrayOp
+//--------------------------------------------
+
+MarrayOp::MarrayOp( const BaseType* newResType, unsigned int newResOff )
+ : resType(newResType), resOff(newResOff)
+{
+}
+
+void
+MarrayOp::operator()( char* result, const r_Point& p )
+{
+ r_ULong sum = 0;
+
+ for(int i = 0; i < p.dimension(); i++)
+ sum += p[i];
+
+ resType->makeFromCULong(result, &sum);
+}
+
+//--------------------------------------------
+// GenCondenseOp
+//--------------------------------------------
+
+GenCondenseOp::GenCondenseOp( const BaseType* newResType, unsigned int newResOff,
+ BinaryOp* newAccuOp, char* newInitVal )
+ : resType(newResType), resOff(newResOff), accuOp(newAccuOp), myInitVal(0)
+{
+ if(newInitVal == 0) {
+ initVal = new char[resType->getSize()];
+ myInitVal = 1;
+ accuOp->getCondenseInit(initVal);
+ }
+ else
+ initVal = newInitVal;
+}
+
+GenCondenseOp::~GenCondenseOp()
+{
+ if(myInitVal)
+ delete [] initVal;
+}
+
+
+void
+GenCondenseOp::operator()( const r_Point& p )
+{
+ r_ULong sum = 0;
+ char buf[8];
+
+ for(int i = 0; i < p.dimension(); i++)
+ sum += p[i];
+
+ resType->makeFromCULong(buf, &sum);
+
+ (*accuOp)(initVal, initVal, buf);
+}
+
+BinaryOp*
+GenCondenseOp::getAccuOp()
+{
+ return accuOp;
+}
+
+const BaseType*
+GenCondenseOp::getResultType()
+{
+ return resType;
+}
+
+unsigned int
+GenCondenseOp::getResultOff()
+{
+ return resOff;
+}
+
+char*
+GenCondenseOp::getAccuVal()
+{
+ return initVal;
+}
+
+
+//--------------------------------------------
+// Complex
+//--------------------------------------------
+
+// *** PLUS ***
+
+OpPLUSComplex::OpPLUSComplex(
+ const BaseType* newResType,
+ const BaseType* newOp1Type,
+ const BaseType* newOp2Type,
+ unsigned int newResOff,
+ unsigned int newOp1Off,
+ unsigned int newOp2Off,
+ ScalarFlag flag)
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff, newOp1Off, newOp2Off), scalarFlag(flag)
+{
+ op1ReOff = scalarFlag == OpPLUSComplex::FIRST ? 0: ((GenericComplexType *)newOp1Type)->getReOffset();
+ op1ImOff = scalarFlag == OpPLUSComplex::FIRST ? 0: ((GenericComplexType *)newOp1Type)->getImOffset();
+ op2ReOff = scalarFlag == OpPLUSComplex::SECOND ? 0: ((GenericComplexType *)newOp2Type)->getReOffset();
+ op2ImOff = scalarFlag == OpPLUSComplex::SECOND ? 0: ((GenericComplexType *)newOp2Type)->getImOffset();
+
+ resReOff = ((GenericComplexType *)newResType)->getReOffset();
+ resImOff = ((GenericComplexType *)newResType)->getImOffset();
+}
+
+void OpPLUSComplex::operator()(char* res, const char* op1, const char* op2) {
+ double op1Re = 0;
+ double op2Re = 0;
+ double op1Im = 0;
+ double op2Im = 0;
+ double resRe, resIm;
+
+ if(scalarFlag == FIRST) {
+ resRe = *(op1Type->convertToCDouble(op1 + op1Off + op1ReOff, &op1Re)) +
+ *(op2Type->convertToCDouble(op2 + op2Off + op2ReOff, &op2Re));
+
+ resIm = *(op2Type->convertToCDouble(op2 + op2Off + op2ImOff, &op2Im));
+ }
+ else if(scalarFlag == SECOND) {
+ resRe = *(op1Type->convertToCDouble(op1 + op1Off + op1ReOff, &op1Re)) +
+ *(op2Type->convertToCDouble(op2 + op2Off + op2ReOff, &op2Re));
+
+ resIm = *(op1Type->convertToCDouble(op1 + op1Off + op1ImOff, &op1Im));
+ }
+ else {
+ resRe = *(op1Type->convertToCDouble(op1 + op1Off + op1ReOff, &op1Re)) +
+ *(op2Type->convertToCDouble(op2 + op2Off + op2ReOff, &op2Re));
+
+ resIm = *(op1Type->convertToCDouble(op1 + op1Off + op1ImOff, &op1Im)) +
+ *(op2Type->convertToCDouble(op2 + op2Off + op2ImOff, &op2Im));
+ }
+
+ resType->makeFromCDouble(res + resOff + resReOff, &resRe);
+ resType->makeFromCDouble(res + resOff + resImOff, &resIm);
+}
+
+void OpPLUSComplex::getCondenseInit(char* init) {
+ double dummyRe = 0.0;
+ double dummyIm = 0.0;
+ resType->makeFromCDouble(init + resReOff, &dummyRe);
+ resType->makeFromCDouble(init + resImOff, &dummyIm);
+}
+
+// *** MINUS ***
+
+
+OpMINUSComplex::OpMINUSComplex(
+ const BaseType* newResType,
+ const BaseType* newOp1Type,
+ const BaseType* newOp2Type,
+ unsigned int newResOff,
+ unsigned int newOp1Off,
+ unsigned int newOp2Off,
+ ScalarFlag flag)
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff, newOp1Off, newOp2Off), scalarFlag(flag)
+{
+ op1ReOff = scalarFlag == OpPLUSComplex::FIRST ? 0: ((GenericComplexType *)newOp1Type)->getReOffset();
+ op1ImOff = scalarFlag == OpPLUSComplex::FIRST ? 0: ((GenericComplexType *)newOp1Type)->getImOffset();
+ op2ReOff = scalarFlag == OpPLUSComplex::SECOND ? 0: ((GenericComplexType *)newOp2Type)->getReOffset();
+ op2ImOff = scalarFlag == OpPLUSComplex::SECOND ? 0: ((GenericComplexType *)newOp2Type)->getImOffset();
+
+ resReOff = ((GenericComplexType *)newResType)->getReOffset();
+ resImOff = ((GenericComplexType *)newResType)->getImOffset();
+}
+
+void OpMINUSComplex::operator()(char* res, const char* op1, const char* op2) {
+ double op1Re = 0;
+ double op2Re = 0;
+ double op1Im = 0;
+ double op2Im = 0;
+ double resRe, resIm;
+
+ if(scalarFlag == FIRST) {
+ resRe = *(op1Type->convertToCDouble(op1 + op1Off + op1ReOff, &op1Re)) -
+ *(op2Type->convertToCDouble(op2 + op2Off + op2ReOff, &op2Re));
+
+ resIm = *(op2Type->convertToCDouble(op2 + op2Off + op2ImOff, &op2Im));
+ }
+ else if(scalarFlag == SECOND) {
+ resRe = *(op1Type->convertToCDouble(op1 + op1Off + op1ReOff, &op1Re)) -
+ *(op2Type->convertToCDouble(op2 + op2Off + op2ReOff, &op2Re));
+
+ resIm = *(op1Type->convertToCDouble(op1 + op1Off + op1ImOff, &op1Im));
+ }
+ else {
+ resRe = *(op1Type->convertToCDouble(op1 + op1Off + op1ReOff, &op1Re)) -
+ *(op2Type->convertToCDouble(op2 + op2Off + op2ReOff, &op2Re));
+
+ resIm = *(op1Type->convertToCDouble(op1 + op1Off + op1ImOff, &op1Im)) -
+ *(op2Type->convertToCDouble(op2 + op2Off + op2ImOff, &op2Im));
+ }
+
+ resType->makeFromCDouble(res + resOff + resReOff, &resRe);
+ resType->makeFromCDouble(res + resOff + resImOff, &resIm);
+}
+
+// *** DIV ***
+
+OpDIVComplex::OpDIVComplex(
+ const BaseType* newResType,
+ const BaseType* newOp1Type,
+ const BaseType* newOp2Type,
+ unsigned int newResOff,
+ unsigned int newOp1Off,
+ unsigned int newOp2Off,
+ ScalarFlag flag)
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff, newOp1Off, newOp2Off), scalarFlag(flag)
+{
+ op1ReOff = scalarFlag == OpPLUSComplex::FIRST ? 0: ((GenericComplexType *)newOp1Type)->getReOffset();
+ op1ImOff = scalarFlag == OpPLUSComplex::FIRST ? 0: ((GenericComplexType *)newOp1Type)->getImOffset();
+ op2ReOff = scalarFlag == OpPLUSComplex::SECOND ? 0: ((GenericComplexType *)newOp2Type)->getReOffset();
+ op2ImOff = scalarFlag == OpPLUSComplex::SECOND ? 0: ((GenericComplexType *)newOp2Type)->getImOffset();
+
+ resReOff = ((GenericComplexType *)newResType)->getReOffset();
+ resImOff = ((GenericComplexType *)newResType)->getImOffset();
+}
+
+void OpDIVComplex::operator()(char* res, const char* op1, const char* op2) {
+ double op1Re = 0;
+ double op2Re = 0;
+ double op1Im = 0;
+ double op2Im = 0;
+ double resRe, resIm;
+
+ if(scalarFlag == FIRST) {
+ double a = *(op1Type->convertToCDouble(op1 + op1Off + op1ReOff, &op1Re));
+ double x = *(op2Type->convertToCDouble(op2 + op2Off + op2ReOff, &op2Re));
+ double y = *(op2Type->convertToCDouble(op2 + op2Off + op2ImOff, &op2Im));
+
+ resRe = a * x / (x * x + y * y);
+ resIm = - a * y / (x * x + y * y);
+ }
+ else if(scalarFlag == SECOND) {
+
+ resRe = *(op1Type->convertToCDouble(op1 + op1Off + op1ReOff, &op1Re)) /
+ *(op2Type->convertToCDouble(op2 + op2Off + op2ReOff, &op2Re));
+
+ resIm = *(op1Type->convertToCDouble(op1 + op1Off + op1ImOff, &op1Im)) /
+ *(op2Type->convertToCDouble(op2 + op2Off + op2ImOff, &op2Im));
+ }
+ else { // NONE
+ double x1 = *(op1Type->convertToCDouble(op1 + op1Off + op1ReOff, &op1Re));
+ double y1 = *(op1Type->convertToCDouble(op1 + op1Off + op1ImOff, &op1Im));
+ double x2 = *(op2Type->convertToCDouble(op2 + op2Off + op2ReOff, &op2Re));
+ double y2 = *(op2Type->convertToCDouble(op2 + op2Off + op2ImOff, &op2Im));
+
+ resRe = (x1 * x2 + y1 * y2) / (x2 * x2 + y2 * y2);
+ resIm = (y1 * x2 - x1 * y2) / (x2 * x2 + y2 * y2);
+ }
+
+ resType->makeFromCDouble(res + resOff + resReOff, &resRe);
+ resType->makeFromCDouble(res + resOff + resImOff, &resIm);
+}
+
+// *** MULT ***
+
+OpMULTComplex::OpMULTComplex(
+ const BaseType* newResType,
+ const BaseType* newOp1Type,
+ const BaseType* newOp2Type,
+ unsigned int newResOff,
+ unsigned int newOp1Off,
+ unsigned int newOp2Off,
+ ScalarFlag flag)
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff, newOp1Off, newOp2Off), scalarFlag(flag)
+{
+ op1ReOff = scalarFlag == OpPLUSComplex::FIRST ? 0: ((GenericComplexType *)newOp1Type)->getReOffset();
+ op1ImOff = scalarFlag == OpPLUSComplex::FIRST ? 0: ((GenericComplexType *)newOp1Type)->getImOffset();
+ op2ReOff = scalarFlag == OpPLUSComplex::SECOND ? 0: ((GenericComplexType *)newOp2Type)->getReOffset();
+ op2ImOff = scalarFlag == OpPLUSComplex::SECOND ? 0: ((GenericComplexType *)newOp2Type)->getImOffset();
+
+ resReOff = ((GenericComplexType *)newResType)->getReOffset();
+ resImOff = ((GenericComplexType *)newResType)->getImOffset();
+}
+
+void OpMULTComplex::operator()(char* res, const char* op1, const char* op2) {
+ double op1Re = 0;
+ double op2Re = 0;
+ double op1Im = 0;
+ double op2Im = 0;
+ double resRe, resIm;
+
+
+ if(scalarFlag == FIRST) {
+ resRe = *(op1Type->convertToCDouble(op1 + op1Off + op1ReOff, &op1Re)) *
+ *(op2Type->convertToCDouble(op2 + op2Off + op2ReOff, &op2Re));
+
+ resIm = *(op1Type->convertToCDouble(op1 + op1Off + op1ReOff, &op1Re)) *
+ *(op2Type->convertToCDouble(op2 + op2Off + op2ImOff, &op2Im));
+ }
+ else if(scalarFlag == SECOND) {
+ resRe = *(op1Type->convertToCDouble(op1 + op1Off + op1ReOff, &op1Re)) *
+ *(op2Type->convertToCDouble(op2 + op2Off + op2ReOff, &op2Re));
+
+ resIm = *(op1Type->convertToCDouble(op1 + op1Off + op1ImOff, &op1Im)) *
+ *(op2Type->convertToCDouble(op2 + op2Off + op2ReOff, &op2Re));
+ }
+ else {
+ // Re = x1 * x2 - y1 * y2
+
+ resRe = *(op1Type->convertToCDouble(op1 + op1Off + op1ReOff, &op1Re)) * // x1
+ *(op2Type->convertToCDouble(op2 + op2Off + op2ReOff, &op2Re)) - // x2
+ *(op1Type->convertToCDouble(op1 + op1Off + op1ImOff, &op1Im)) * // y1
+ *(op2Type->convertToCDouble(op2 + op2Off + op2ImOff, &op2Im)); // y2
+
+ // Im = x1 * y2 + x2 * y1
+
+ resIm = *(op1Type->convertToCDouble(op1 + op1Off + op1ReOff, &op1Re)) * // x1
+ *(op2Type->convertToCDouble(op2 + op2Off + op2ImOff, &op2Im)) + // y2
+ *(op2Type->convertToCDouble(op2 + op2Off + op2ReOff, &op2Re)) * // x2
+ *(op1Type->convertToCDouble(op1 + op1Off + op1ImOff, &op1Im)); // y1
+ }
+
+ resType->makeFromCDouble(res + resOff + resReOff, &resRe);
+ resType->makeFromCDouble(res + resOff + resImOff, &resIm);
+}
+
+void OpMULTComplex::getCondenseInit(char* init) {
+ double dummyRe = 0.0;
+ double dummyIm = 0.0;
+ resType->makeFromCDouble(init + resReOff, &dummyRe);
+ resType->makeFromCDouble(init + resImOff, &dummyIm);
+}
+
+// *** IDENTITY ***
+
+OpIDENTITYComplex::OpIDENTITYComplex(
+ const BaseType* newResType,
+ const BaseType* newOpType,
+ unsigned int newResOff,
+ unsigned int newOpOff )
+ : UnaryOp(newResType, newOpType, newResOff, newOpOff)
+{}
+
+void OpIDENTITYComplex::operator()(char* res, const char* op) {
+ memcpy((void *)(res + resOff), (void *)(op + opOff), resType->getSize());
+}
+
+// *** REAL PART ***
+
+OpRealPart::OpRealPart(
+ const BaseType* newResType,
+ const BaseType* newOpType,
+ unsigned int newResOff,
+ unsigned int newOpOff)
+ : UnaryOp(newResType, newOpType, newResOff, newOpOff)
+{
+ opReOff = ((GenericComplexType *)newOpType)->getReOffset();
+}
+
+
+void OpRealPart::operator()(char* res, const char* op) {
+ double result;
+
+ opType->convertToCDouble(op + opOff + opReOff, &result);
+ resType->makeFromCDouble(res + resOff, &result);
+}
+
+// *** IMAGINAR PART ***
+
+OpImaginarPart::OpImaginarPart(
+ const BaseType* newResType,
+ const BaseType* newOpType,
+ unsigned int newResOff,
+ unsigned int newOpOff)
+ : UnaryOp(newResType, newOpType, newResOff, newOpOff)
+{
+ opImOff = ((GenericComplexType *)newOpType)->getImOffset();
+}
+
+
+void OpImaginarPart::operator()(char* res, const char* op) {
+ double result;
+
+ opType->convertToCDouble(op + opOff + opImOff, &result);
+ resType->makeFromCDouble(res + resOff, &result);
+}
+
+
+//--------------------------------------------
+// OpCAST
+//--------------------------------------------
+
+OpCAST::OpCAST(
+ const BaseType* newResType,
+ const BaseType* newOpType,
+ unsigned int newResOff,
+ unsigned int newOpOff)
+ : UnaryOp(newResType, newOpType, newResOff, newOpOff) {}
+
+void OpCAST::operator()(char* res, const char* op) {
+
+ if(resType->getType() == FLOAT || resType->getType() == DOUBLE) {
+ // floating point types
+ double dblOp;
+ double dblRes = *(opType->convertToCDouble(op + opOff, &dblOp));
+ resType->makeFromCDouble(res + resOff, &dblRes);
+ }
+ else {
+ // all integral types
+ r_Long lngOp;
+ r_Long lngRes = *(opType->convertToCLong(op + opOff, &lngOp));
+ resType->makeFromCLong(res + resOff, &lngRes);
+ }
+}
+
+
+//--------------------------------------------
+// OpOVERLAY
+//--------------------------------------------
+
+OpOVERLAY::OpOVERLAY( const BaseType* newResType, const BaseType* newOp1Type, const BaseType* newOp2Type, size_t typeSize, const char* transparentPattern, unsigned int newResOff, unsigned int newOp1Off, unsigned int newOp2Off)
+ : BinaryOp(newResType, newOp1Type, newOp2Type, newResOff, newOp1Off, newOp2Off), length(typeSize), pattern(transparentPattern)
+{
+ if ((pattern == nullPattern) && (length > 16))
+ {
+ RMInit::logOut << "OpOVERLAY overlay with types larger than 16 bytes not supported yet" << endl;
+ throw r_Error(OVERLAYPATTERNTOOSMALL);
+ }
+}
+
+void OpOVERLAY::operator()( char *res, const char *op1, const char *op2 )
+{
+ if (memcmp(pattern, op1 + op1Off, length) == 0)
+ {//match
+ memcpy(res + resOff, op2 + op2Off, length);
+ }
+ else {//no match
+ memcpy(res + resOff, op1 + op1Off, length);
+ }
+}
+
+const char*
+OpOVERLAY::nullPattern = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
+
+//--------------------------------------------
+// OpBIT
+//--------------------------------------------
+
+OpBIT::OpBIT(
+ const BaseType* newResType,
+ const BaseType* newOp1Type,
+ const BaseType* newOp2Type,
+ unsigned int newResOff,
+ unsigned int newOp1Off,
+ unsigned int newOp2Off)
+
+ : BinaryOp(newResType,
+ newOp1Type, newOp2Type,
+ newResOff, newOp1Off,
+ newOp2Off)
+ {}
+
+
+void OpBIT::operator() (char *res, const char *op1, const char *op2) {
+ r_ULong lngOp1, lngOp2, lngRes;
+
+ op1Type->convertToCULong(op1 + op1Off, &lngOp1);
+ op2Type->convertToCULong(op2 + op2Off, &lngOp2);
+ lngRes = lngOp1 >> lngOp2 & 0x1L;
+ resType->makeFromCULong(res + resOff, &lngRes);
+}
+
+
+
+
+#include "autogen_ops.cc"
diff --git a/catalogmgr/ops.hh b/catalogmgr/ops.hh
new file mode 100644
index 0000000..61ffc40
--- /dev/null
+++ b/catalogmgr/ops.hh
@@ -0,0 +1,2042 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * Ops contains an enum for identifying all possible
+ * operations.
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#ifndef _OPS_HH_
+#define _OPS_HH_
+
+#include <limits.h>
+
+class CondenseOp;
+class UnaryOp;
+class BinaryOp;
+class BaseType;
+class StructType;
+class Tile;
+class r_Point;
+
+//@Man: TypeEnum
+//@Type: typedef
+//@Memo: Module: {\bf catalogif}.
+
+enum TypeEnum
+{
+ ULONG, USHORT, CHAR, BOOLTYPE, LONG, SHORT, OCTET, DOUBLE, FLOAT,
+ COMPLEXTYPE1, // COMPLEX already defined as token !!!
+ COMPLEXTYPE2,
+ STRUCT,
+ CLASSTYPE, SETTYPE, MDDTYPE
+};
+
+/*@Doc: This is an enum used for handling types instead of using the
+ string representation of the name. For some strange reason
+ I did not manage to define it in Ops scope. I had to use BOOLTYPE
+ instead of BOOL because of name conflicts.
+
+ Attention: DO NOT change the sequence because some code relies on it.
+This is the ops code and the persistence code: from the typenum the oids are generated. changing the order of the enums makes old databases incompatible. there is already a migration tool which shows how to adapt the database schema.
+ */
+
+//@ManMemo: Module: {\bf catalogif}.
+
+/*@Doc:
+ The class Ops is contains an enumeration type giving symbolic names
+ to all implemented operations. These names are given as parameters
+ to functions concerning operations in \Ref{Tile} and
+ \Ref{BaseType}. The selection of operations is actually done in
+ functions of this class, called by the classes mentioned above. The
+ operations are implemented in subclasses of \Ref{CondenseOp},
+ \Ref{UnaryOp} and \Ref{BinaryOp}.
+
+ The operations in the following table are defined at the moment.
+ They can be used in expressions like {\tt Ops::OP_EQUAL}.
+
+ \begin{tabular}{cl}
+
+ symbolic name && operation \\
+
+ && {\bf condense operations} \\
+ OP_SOME && condense boolean tile with OR \\
+ OP_ALL && condense boolean tile with AND \\
+
+ && {\bf unary operations} \\
+ OP_NOT && negation (bitwise for ints, logical for bools) \\
+ OP_SQRT && square root (for doubles) \\
+ OP_IDENTITY && used for copying cells \\
+
+ && {\bf binary operations} \\
+ OP_MINUS && subtraction \\
+ OP_PLUS && addition \\
+ OP_MULT && multiplication \\
+ OP_DIV && division \\
+ OP_IS && not implemented yet \\
+ OP_AND && bitwise resp. logical AND \\
+ OP_OR && bitwise resp. logical OR \\
+ OP_XOR && bitwise resp. logical XOR \\
+ OP_EQUAL && equality (result Bool) \\
+ OP_LESS && less than (result Bool) \\
+ OP_LESSEQUAL && less than or equal (result Bool) \\
+ OP_NOTEQUAL && inequality (result Bool) \\
+ OP_GREATER && greater than (result Bool) \\
+ OP_GREATEREQUAL && greater than or equal (result Bool) \\
+
+ \end{tabular}
+*/
+
+class Ops
+{
+public:
+ enum OpType
+ {
+ // condense operations.
+ OP_COUNT, OP_MAX, OP_MIN, OP_SUM, OP_SOME,
+ /* insert new condense ops before this line */ OP_ALL,
+ // unary operations.
+ OP_NOT,
+
+ //*******************
+ OP_UFUNC_BEGIN,
+ OP_ABS, OP_SQRT,
+ OP_EXP, OP_LOG, OP_LN,
+ OP_SIN, OP_COS, OP_TAN,
+ OP_SINH, OP_COSH, OP_TANH,
+ OP_ARCSIN, OP_ARCCOS, OP_ARCTAN,
+ OP_UFUNC_END,
+
+ OP_REALPART,
+ OP_IMAGINARPART,
+
+ OP_CAST_BEGIN,
+ OP_CAST_BOOL,
+ OP_CAST_CHAR,
+ OP_CAST_OCTET,
+ OP_CAST_SHORT,
+ OP_CAST_USHORT,
+ OP_CAST_LONG,
+ OP_CAST_ULONG,
+ OP_CAST_FLOAT,
+ OP_CAST_DOUBLE,
+ OP_CAST_END,
+ //*******************
+
+ /* insert new unary ops before this line */ OP_IDENTITY,
+ // binary operations.
+ OP_MINUS, OP_PLUS, OP_DIV, OP_MULT,
+ OP_IS, OP_AND, OP_OR, OP_OVERLAY, OP_BIT, OP_XOR,
+ /* insert new binary ops before this line */
+ OP_EQUAL, OP_LESS, OP_LESSEQUAL,
+ OP_NOTEQUAL, OP_GREATER, OP_GREATEREQUAL
+
+ };
+
+
+//@Man: methods for getting functions
+//@{
+ /// get function object for unary operation.
+ static UnaryOp* getUnaryOp( Ops::OpType op, const BaseType* restype,
+ const BaseType* optype, unsigned int resOff = 0,
+ unsigned int opOff = 0 );
+ /*@Doc:
+ An \Ref{UnaryOp} carrying out #op# on the given types is
+ returned. If #op# is not applicable to the given types,
+ 0 is returned.
+ */
+ /// get function object for binary operation.
+ static BinaryOp* getBinaryOp( Ops::OpType op, const BaseType* resType,
+ const BaseType* op1Type, const BaseType* op2Type,
+ unsigned int resOff = 0,
+ unsigned int op1Off = 0,
+ unsigned int op2Off = 0 );
+ /*@Doc:
+ An \Ref{BinaryOp} carrying out #op# on the given types is
+ returned. If #op# is not applicable to the given types,
+ 0 is returned.
+ */
+ static CondenseOp* getCondenseOp( Ops::OpType op, const BaseType* resType,
+ const BaseType* opType = 0,
+ unsigned int resOff = 0,
+ unsigned int opOff = 0);
+ /// get function object for condense operation.
+ static CondenseOp* getCondenseOp( Ops::OpType op, const BaseType* resType,
+ char* newAccu, const BaseType* opType = 0,
+ unsigned int resOff = 0,
+ unsigned int opOff = 0 );
+ /*@Doc:
+ An \Ref{CondenseOp} carrying out #op# on the given types is
+ returned. If #op# is not applicable to the given types,
+ 0 is returned.
+ */
+//@}
+
+//@Man: methods for checking applicability of functions.
+//@{
+ /// checks, if #op# is applicable on the given types.
+ static int isApplicable( Ops::OpType op, const BaseType* op1Type,
+ const BaseType* op2Type = 0 );
+ /*@Doc:
+ For unary or condense operations, just leave out #op2Type# (or
+ set it to 0).
+ */
+ /// gives back suggested return type for #op# carried out on the given types.
+ static const BaseType* getResultType( Ops::OpType op, const BaseType* op1,
+ const BaseType* op2 = 0 );
+ /*@Doc:
+ This usually gives back the "stronger" type of #op1Type# or #op2Type#
+ (e.g. for a function like OP_PLUS). Usually the operation can also
+ be applied to another type, loosing information if the type is
+ "weaker". At the moment, only comparison operations (e.g. OP_EQUAL)
+ have a well defined return type, which is Bool. No other return type
+ can be used for these operations. If the operation is not applicable
+ to the given type, 0 is returned.
+ */
+ /// executes operation on a constant.
+ static void execUnaryConstOp( Ops::OpType op, const BaseType* resType,
+ const BaseType* opType, char* res,
+ const char* op1, unsigned int resOff = 0,
+ unsigned int opOff = 0 );
+ /// executes operation on two constants.
+ static void execBinaryConstOp( Ops::OpType op, const BaseType* resType,
+ const BaseType* op1Type,
+ const BaseType* op2Type, char* res,
+ const char* op1, const char* op2,
+ unsigned int resOff = 0,
+ unsigned int op1Off = 0,
+ unsigned int op2Off = 0 );
+//@}
+
+private:
+ /// checks, if #op# is applicable on two struct of type opType.
+ static int isApplicableOnStruct( Ops::OpType op, const BaseType* opType );
+ /*@ManMemo: checks, if #op# is applicable on struct of type op1Type
+ and value of type op2Type.*/
+ static int isApplicableOnStructConst( Ops::OpType op,
+ const BaseType* op1Type,
+ const BaseType* op2Type );
+ /// returns 1 for signed types, 0 for unsigned.
+ static int isSignedType( const BaseType* type );
+ // these functions aren't even used for the time being, but may
+ // be important for better implementations of isApplicable and
+ // getResultType.
+ static int isCondenseOp( Ops::OpType op );
+ static int isUnaryOp( Ops::OpType op );
+ static int isBinaryOp( Ops::OpType op );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+
+/*@Doc:
+ CondenseOp is the superclass for all condense operations. The
+ operator() carries out a condense operation on one cell {\tt op},
+ which is accumulated into {\tt accu}. {\tt accu} is returned as a
+ result. Remember to always initialize {\tt accu} correctly according
+ to the condense operation used (e.g. 0 for \Ref{OpSOMEBool} or 1 for
+ \Ref{OpALLBool}).
+*/
+
+class CondenseOp
+{
+public:
+ /*@ManMemo: constructor gets RasDaMan base type of result and operand
+ and offsets to result and operand (for structs). */
+ CondenseOp( const BaseType* newResType, const BaseType* newOpType,
+ unsigned int newResOff = 0, unsigned int newOpOff = 0 );
+ /*@ManMemo: constructor gets RasDaMan base type of result and operand,
+ initial value, and offsets to result and operand (for structs) . */
+ CondenseOp( const BaseType* newResType, char* newAccu, const BaseType* newOpType,
+ unsigned int newResOff = 0, unsigned int newOpOff = 0 );
+ /// operator to carry out operation on {\tt op}.
+ virtual char* operator()( const char* op, char* myAccu ) = 0;
+ /// operator to carry out operation on {\tt op} using internal accu.
+ virtual char* operator()( const char* op ) = 0;
+ /// operator to access value of internal accumulator.
+ virtual char* getAccuVal();
+ /*@ManMemo: virtual destructor because subclasse OpCondenseStruct has
+ non-trivial destructor. */
+ virtual ~CondenseOp();
+
+protected:
+ char* accu;
+ const BaseType* opType;
+ const BaseType* resType;
+ unsigned int resOff;
+ unsigned int opOff;
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_SOME on C type #char#.
+
+class OpSOMECChar : public CondenseOp
+{
+public:
+ /*@ManMemo: constructor gets RasDaMan base type of result and operand
+ and offsets to result and operand (for structs). */
+ OpSOMECChar( const BaseType* newResType, const BaseType* newOpType,
+ unsigned int newResOff = 0, unsigned int newOpOff = 0 );
+ /// constructor initializing internal accu.
+ OpSOMECChar( const BaseType* newResType, char* newAccu,
+ const BaseType* newOpType, unsigned int newResOff,
+ unsigned int newOpOff );
+ /// operator to carry out operation on {\tt op}.
+ virtual char* operator()( const char* op, char* myAccu );
+ /// operator to carry out operation on {\tt op} using internal accu.
+ virtual char* operator()( const char* op );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_ALL on C type #char#.
+
+class OpALLCChar : public CondenseOp
+{
+public:
+ /*@ManMemo: constructor gets RasDaMan base type of result and operand
+ and offsets to result and operand (for structs). */
+ OpALLCChar( const BaseType* newResType, const BaseType* newOpType,
+ unsigned int newResOff = 0, unsigned int newOpOff = 0 );
+ /// constructor initializing internal accu.
+ OpALLCChar( const BaseType* newResType, char* newAccu,
+ const BaseType* newOpType, unsigned int newResOff,
+ unsigned int newOpOff );
+ /// operator to carry out operation on {\tt op}.
+ virtual char* operator()( const char* op, char* myAccu );
+ /// operator to carry out operation on {\tt op} using internal accu.
+ virtual char* operator()( const char* op );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_COUNT on C type #char#.
+
+class OpCOUNTCChar : public CondenseOp
+{
+public:
+ /*@ManMemo: constructor gets RasDaMan base type of result and operand
+ and offsets to result and operand (for structs). */
+ OpCOUNTCChar( const BaseType* newResType, const BaseType* newOpType,
+ unsigned int newResOff = 0, unsigned int newOpOff = 0 );
+ /// constructor initializing internal accu.
+ OpCOUNTCChar( const BaseType* newResType, char* newAccu,
+ const BaseType* newOpType, unsigned int newResOff,
+ unsigned int newOpOff );
+ /// operator to carry out operation on {\tt op}.
+ virtual char* operator()( const char* op, char* myAccu );
+ /// operator to carry out operation on {\tt op} using internal accu.
+ virtual char* operator()( const char* op );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_MAX on C type #char#.
+
+class OpMAXCULong : public CondenseOp
+{
+public:
+ /*@ManMemo: constructor gets RasDaMan base type of result and operand
+ and offsets to result and operand (for structs). */
+ OpMAXCULong( const BaseType* newResType, const BaseType* newOpType,
+ unsigned int newResOff = 0, unsigned int newOpOff = 0 );
+ /// constructor initializing internal accu.
+ OpMAXCULong( const BaseType* newResType, char* newAccu,
+ const BaseType* newOpType, unsigned int newResOff,
+ unsigned int newOpOff );
+ /// operator to carry out operation on {\tt op}.
+ virtual char* operator()( const char* op, char* myAccu );
+ /// operator to carry out operation on {\tt op} using internal accu.
+ virtual char* operator()( const char* op );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_MAX on C type #char#.
+
+class OpMAXCLong : public CondenseOp
+{
+public:
+ /*@ManMemo: constructor gets RasDaMan base type of result and operand
+ and offsets to result and operand (for structs). */
+ OpMAXCLong( const BaseType* newResType, const BaseType* newOpType,
+ unsigned int newResOff = 0, unsigned int newOpOff = 0 );
+ /// constructor initializing internal accu.
+ OpMAXCLong( const BaseType* newResType, char* newAccu,
+ const BaseType* newOpType, unsigned int newResOff,
+ unsigned int newOpOff );
+ /// operator to carry out operation on {\tt op}.
+ virtual char* operator()( const char* op, char* myAccu );
+ /// operator to carry out operation on {\tt op} using internal accu.
+ virtual char* operator()( const char* op );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_MAX on C type #char#.
+
+class OpMAXCDouble : public CondenseOp
+{
+public:
+ /*@ManMemo: constructor gets RasDaMan base type of result and operand
+ and offsets to result and operand (for structs). */
+ OpMAXCDouble( const BaseType* newResType, const BaseType* newOpType,
+ unsigned int newResOff = 0, unsigned int newOpOff = 0 );
+ /// constructor initializing internal accu.
+ OpMAXCDouble( const BaseType* newResType, char* newAccu,
+ const BaseType* newOpType, unsigned int newResOff,
+ unsigned int newOpOff );
+ /// operator to carry out operation on {\tt op}.
+ virtual char* operator()( const char* op, char* myAccu );
+ /// operator to carry out operation on {\tt op} using internal accu.
+ virtual char* operator()( const char* op );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_MIN on C type #char#.
+
+class OpMINCULong : public CondenseOp
+{
+public:
+ /*@ManMemo: constructor gets RasDaMan base type of result and operand
+ and offsets to result and operand (for structs). */
+ OpMINCULong( const BaseType* newResType, const BaseType* newOpType,
+ unsigned int newResOff = 0, unsigned int newOpOff = 0 );
+ /// constructor initializing internal accu.
+ OpMINCULong( const BaseType* newResType, char* newAccu,
+ const BaseType* newOpType, unsigned int newResOff,
+ unsigned int newOpOff );
+ /// operator to carry out operation on {\tt op}.
+ virtual char* operator()( const char* op, char* myAccu );
+ /// operator to carry out operation on {\tt op} using internal accu.
+ virtual char* operator()( const char* op );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_MIN on C type #char#.
+
+class OpMINCLong : public CondenseOp
+{
+public:
+ /*@ManMemo: constructor gets RasDaMan base type of result and operand
+ and offsets to result and operand (for structs). */
+ OpMINCLong( const BaseType* newResType, const BaseType* newOpType,
+ unsigned int newResOff = 0, unsigned int newOpOff = 0 );
+ /// constructor initializing internal accu.
+ OpMINCLong( const BaseType* newResType, char* newAccu,
+ const BaseType* newOpType, unsigned int newResOff,
+ unsigned int newOpOff );
+ /// operator to carry out operation on {\tt op}.
+ virtual char* operator()( const char* op, char* myAccu );
+ /// operator to carry out operation on {\tt op} using internal accu.
+ virtual char* operator()( const char* op );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_MIN on C type #char#.
+
+class OpMINCDouble : public CondenseOp
+{
+public:
+ /*@ManMemo: constructor gets RasDaMan base type of result and operand
+ and offsets to result and operand (for structs). */
+ OpMINCDouble( const BaseType* newResType, const BaseType* newOpType,
+ unsigned int newResOff = 0, unsigned int newOpOff = 0 );
+ /// constructor initializing internal accu.
+ OpMINCDouble( const BaseType* newResType, char* newAccu,
+ const BaseType* newOpType, unsigned int newResOff,
+ unsigned int newOpOff );
+ /// operator to carry out operation on {\tt op}.
+ virtual char* operator()( const char* op, char* myAccu );
+ /// operator to carry out operation on {\tt op} using internal accu.
+ virtual char* operator()( const char* op );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_SUM on C type #char#.
+
+class OpSUMCULong : public CondenseOp
+{
+public:
+ /*@ManMemo: constructor gets RasDaMan base type of result and operand
+ and offsets to result and operand (for structs). */
+ OpSUMCULong(const BaseType* newResType,const BaseType* newOpType,
+ unsigned int newResOff = 0, unsigned int newOpOff = 0 );
+ /// constructor initializing internal accu.
+ OpSUMCULong(const BaseType* newResType, char* newAccu,
+ const BaseType* newOpType, unsigned int newResOff,
+ unsigned int newOpOff );
+ /// operator to carry out operation on {\tt op}.
+ virtual char* operator()( const char* op, char* myAccu );
+ /// operator to carry out operation on {\tt op} using internal accu.
+ virtual char* operator()( const char* op );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_SUM on C type #char#.
+
+class OpSUMCLong : public CondenseOp
+{
+public:
+ /*@ManMemo: constructor gets RasDaMan base type of result and operand
+ and offsets to result and operand (for structs). */
+ OpSUMCLong(const BaseType* newResType,const BaseType* newOpType,
+ unsigned int newResOff = 0, unsigned int newOpOff = 0 );
+ /// constructor initializing internal accu.
+ OpSUMCLong(const BaseType* newResType, char* newAccu,
+ const BaseType* newOpType, unsigned int newResOff,
+ unsigned int newOpOff );
+ /// operator to carry out operation on {\tt op}.
+ virtual char* operator()( const char* op, char* myAccu );
+ /// operator to carry out operation on {\tt op} using internal accu.
+ virtual char* operator()( const char* op );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_SUM on C type #char#.
+
+class OpSUMCDouble : public CondenseOp
+{
+public:
+ /*@ManMemo: constructor gets RasDaMan base type of result and operand
+ and offsets to result and operand (for structs). */
+ OpSUMCDouble(const BaseType* newResType,const BaseType* newOpType,
+ unsigned int newResOff = 0, unsigned int newOpOff = 0 );
+ /// constructor initializing internal accu.
+ OpSUMCDouble(const BaseType* newResType, char* newAccu,
+ const BaseType* newOpType, unsigned int newResOff,
+ unsigned int newOpOff );
+ /// operator to carry out operation on {\tt op}.
+ virtual char* operator()( const char* op, char* myAccu );
+ /// operator to carry out operation on {\tt op} using internal accu.
+ virtual char* operator()( const char* op );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: Class for carrying out condense operations on structs.
+
+// Inherits some useless members from CondenseOp, don't want to
+// change this now.
+class OpCondenseStruct : public CondenseOp
+{
+public:
+ /// constructor gets struct type.
+ OpCondenseStruct(
+ const BaseType* newResType,
+ const BaseType* newOpType,
+ Ops::OpType op,
+ unsigned int newResOff = 0, unsigned int newOpOff = 0
+ );
+ /// constructor gets struct type and initial value for internal accu.
+ OpCondenseStruct(
+ const BaseType* newResType,
+ char* newAccu,
+ const BaseType* newOpType,
+ Ops::OpType op,
+ unsigned int newResOff,
+ unsigned int newOpOff
+ );
+ /// destructor.
+ virtual ~OpCondenseStruct();
+ /// operator to carry out operation on struct {\tt op}.
+ virtual char* operator()( const char* op, char* myAccu );
+ /// operator to carry out operation on struct {\tt op} using internal accu.
+ virtual char* operator()( const char* op );
+protected:
+ StructType* myResType;
+ StructType* myOpType;
+ unsigned int numElems;
+ // array of operations on the elements.
+ CondenseOp** elemOps;
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+
+/*@Doc:
+ UnaryOp is the superclass for all unary operations. The
+ operator() carries out a unary operation on one cell {\tt op} and
+ stores the result in the cell {\tt result}.
+*/
+
+class UnaryOp
+{
+public:
+ /*@ManMemo: constructor gets RasDaMan base type of result and operand
+ and offsets to result and operand (for structs). */
+ UnaryOp(const BaseType* newResType,const BaseType* newOpType,
+ unsigned int newResOff = 0, unsigned int newOpOff = 0 );
+ /// operator to carry out operation on {\tt op}.
+ virtual void operator()( char* result, const char* op ) = 0;
+ /*@ManMemo: virtual destructor because subclasse OpUnaryStruct has
+ non-trivial destructor. */
+ virtual ~UnaryOp() { };
+
+protected:
+ const BaseType* opType;
+ const BaseType* resType;
+ unsigned int resOff;
+ unsigned int opOff;
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: Class for carrying out binary operations on structs.
+
+// Inherits some useless members from UnaryOp, don't want to
+// change this now.
+class OpUnaryStruct : public UnaryOp
+{
+public:
+ /// constructor gets struct type.
+ OpUnaryStruct(
+ const BaseType* newResType,
+ const BaseType* newOpType,
+ Ops::OpType op,
+ unsigned int newResOff = 0,
+ unsigned int newOpOff = 0
+ );
+ /// destructor.
+ virtual ~OpUnaryStruct();
+ /// operator to carry out operation on struct {\tt op}.
+ virtual void operator()( char* result, const char* op );
+
+protected:
+ StructType* myResType;
+ StructType* myOpType;
+ unsigned int numElems;
+ // array of operations on the elements.
+ UnaryOp** elemOps;
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_IDENTITY on structs. Works, if struct types are identical.
+
+class OpIDENTITYStruct : public UnaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operand.
+ OpIDENTITYStruct(const BaseType* newResType,const BaseType* newOpType,
+ unsigned int newResOff = 0, unsigned int newOpOff = 0 );
+ /// operator to carry out operation on {\tt op} with result {\tt result}.
+ virtual void operator()( char* result, const char* op );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_NOT on C type #unsigned long#, result #unsigned long#.
+
+class OpNOTCULong : public UnaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operand.
+ OpNOTCULong(const BaseType* newResType,const BaseType* newOpType,
+ unsigned int newResOff = 0, unsigned int newOpOff = 0 );
+ /// operator to carry out operation on {\tt op} with result {\tt result}.
+ virtual void operator()( char* result, const char* op );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_IDENTITY on C type #unsigned long#, result #unsigned long#.
+
+class OpIDENTITYCULong : public UnaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operand.
+ OpIDENTITYCULong(const BaseType* newResType,const BaseType* newOpType,
+ unsigned int newResOff = 0, unsigned int newOpOff = 0 );
+ /// operator to carry out operation on {\tt op} with result {\tt result}.
+ virtual void operator()( char* result, const char* op );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_NOT on C type #unsigned long#, result #unsigned long#.
+
+class OpNOTCLong : public UnaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operand.
+ OpNOTCLong(const BaseType* newResType,const BaseType* newOpType,
+ unsigned int newResOff = 0, unsigned int newOpOff = 0 );
+ /// operator to carry out operation on {\tt op} with result {\tt result}.
+ virtual void operator()( char* result, const char* op );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_NOT on Bools (logical NOT as opposed to bitwise NOT).
+
+class OpNOTBool : public UnaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operand.
+ OpNOTBool(const BaseType* newResType,const BaseType* newOpType,
+ unsigned int newResOff = 0, unsigned int newOpOff = 0 );
+ /// operator to carry out operation on {\tt op} with result {\tt result}.
+ virtual void operator()( char* result, const char* op );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_IDENTITY on C type #unsigned long#, result #unsigned long#.
+
+class OpIDENTITYCLong : public UnaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operand.
+ OpIDENTITYCLong(const BaseType* newResType,const BaseType* newOpType,
+ unsigned int newResOff = 0, unsigned int newOpOff = 0 );
+ /// operator to carry out operation on {\tt op} with result {\tt result}.
+ virtual void operator()( char* result, const char* op );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_IDENTITY on C type #unsigned long#, result #unsigned long#.
+
+class OpIDENTITYCDouble : public UnaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operand.
+ OpIDENTITYCDouble(const BaseType* newResType,const BaseType* newOpType,
+ unsigned int newResOff = 0, unsigned int newOpOff = 0 );
+ /// operator to carry out operation on {\tt op} with result {\tt result}.
+ virtual void operator()( char* result, const char* op );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+/*@Doc:
+ BinaryOp is the superclass for all binary operations. The operator()
+ carries out a binary operation on cells {\tt op1} and {\tt op2}. The
+ result is stored in the cell {\tt res}.
+*/
+
+class BinaryOp
+{
+public:
+ /*@ManMemo: constructor gets RasDaMan base type of result and operands
+ and offsets to result and operands (for structs). */
+ BinaryOp(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0, unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 ) = 0;
+ /// returns initialization value for {\ref GenCondenseOp}.
+ virtual void getCondenseInit(char* init);
+ /*@ManMemo: virtual destructor because subclasse OpBinaryStruct has
+ non-trivial destructor. */
+ virtual ~BinaryOp() { };
+
+protected:
+ const BaseType* op1Type;
+ const BaseType* op2Type;
+ const BaseType* resType;
+ unsigned int resOff;
+ unsigned int op1Off;
+ unsigned int op2Off;
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: Class for carrying out binary operations on structs.
+
+// Inherits some useless members from BinaryOp, don't want to
+// change this now.
+class OpBinaryStruct : public BinaryOp
+{
+public:
+ /// constructor gets struct type.
+ OpBinaryStruct(const BaseType* newStructType, Ops::OpType op,
+ unsigned int newResOff = 0, unsigned int newOp1Off = 0,
+ unsigned int newOp2Off = 0 );
+ /// destructor.
+ virtual ~OpBinaryStruct();
+ /// operator to carry out operation on struct {\tt op}.
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+protected:
+ StructType* myStructType;
+ unsigned int numElems;
+ // array of operations on the elements.
+ BinaryOp** elemOps;
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+/*@Doc: Class for carrying out binary operations on structs where the
+ second operand is a value. */
+
+class OpBinaryStructConst : public BinaryOp
+{
+public:
+ /// constructor gets struct type.
+ OpBinaryStructConst(
+ const BaseType* resType,
+ const BaseType* op1Type,
+ const BaseType* op2Type,
+ Ops::OpType op, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0,
+ unsigned int newOp2Off = 0 );
+ /// destructor.
+ virtual ~OpBinaryStructConst();
+ /// operator to carry out operation on struct {\tt op}.
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+protected:
+ StructType* resStructType;
+ StructType* opStructType;
+ unsigned int numElems;
+ // array of operations on the elements.
+ BinaryOp** elemOps;
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+/*@Doc: Class for carrying out binary operations on structs where the
+ first operand is a value. */
+
+class OpBinaryConstStruct : public BinaryOp
+{
+public:
+ /// constructor gets struct type.
+ OpBinaryConstStruct(
+ const BaseType* resType,
+ const BaseType* op1Type,
+ const BaseType* op2Type,
+ Ops::OpType op, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0,
+ unsigned int newOp2Off = 0 );
+ /// destructor.
+ virtual ~OpBinaryConstStruct();
+ /// operator to carry out operation on struct {\tt op}.
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+protected:
+ StructType* resStructType;
+ StructType* opStructType;
+ unsigned int numElems;
+ // array of operations on the elements.
+ BinaryOp** elemOps;
+};
+
+class OpEQUALStruct : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpEQUALStruct(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0, unsigned int newOp2Off = 0 );
+ /// destructor.
+ virtual ~OpEQUALStruct();
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+protected:
+ unsigned int numElems;
+ // array of operations on the elements.
+ BinaryOp** elemOps;
+};
+
+class OpNOTEQUALStruct : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpNOTEQUALStruct(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0,
+ unsigned int newOp2Off = 0 );
+ /// destructor.
+ virtual ~OpNOTEQUALStruct();
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+protected:
+ unsigned int numElems;
+ // array of operations on the elements.
+ BinaryOp** elemOps;
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_PLUS on C type #unsigned long# and #unsigned long#, result #unsigned long#.
+
+class OpPLUSCULong : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpPLUSCULong(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0, unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+ virtual void getCondenseInit(char* init);
+};
+
+class OpPLUSULong : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpPLUSULong(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0, unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+ virtual void getCondenseInit(char* init);
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_MINUS on C type #unsigned long# and #unsigned long#, result #unsigned long#.
+
+class OpMINUSCULong : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpMINUSCULong(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0, unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_DIV on C type #unsigned long# and #unsigned long#, result #unsigned long#.
+
+class OpDIVCULong : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpDIVCULong(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0, unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_MULT on C type #unsigned long# and #unsigned long#, result #unsigned long#.
+
+class OpMULTCULong : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpMULTCULong(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0, unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+ virtual void getCondenseInit(char* init);
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_AND on C type #unsigned long# and #unsigned long#, result #unsigned long#.
+
+class OpANDCULong : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpANDCULong(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0, unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+ virtual void getCondenseInit(char* init);
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_AND on Bools (logical as opposed to bitwise)
+
+class OpANDBool : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpANDBool(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0, unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+ virtual void getCondenseInit(char* init);
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_OR on C type #unsigned long# and #unsigned long#, result #unsigned long#.
+
+class OpORCULong : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpORCULong(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0, unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+ virtual void getCondenseInit(char* init);
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_OR on Bools (logical as opposed to bitwise)
+
+class OpORBool : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpORBool(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0, unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+ virtual void getCondenseInit(char* init);
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_XOR on C type #unsigned long# and #unsigned long#, result #unsigned long#.
+
+class OpXORCULong : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpXORCULong(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0, unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_XOR on Bools (logical as opposed to bitwise)
+
+class OpXORBool : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpXORBool(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0, unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_PLUS on C type #long# and #long#, result #long#.
+
+class OpPLUSCLong : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpPLUSCLong(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0, unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+ virtual void getCondenseInit(char* init);
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_MINUS on C type #long# and #long#, result #long#.
+
+class OpMINUSCLong : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpMINUSCLong(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0, unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_DIV on C type #long# and #long#, result #long#.
+
+class OpDIVCLong : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpDIVCLong(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0, unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_MULT on C type #long# and #long#, result #long#.
+
+class OpMULTCLong : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpMULTCLong(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0, unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+ virtual void getCondenseInit(char* init);
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_AND on C type #long# and #long#, result #long#.
+
+class OpANDCLong : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpANDCLong(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0, unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+ virtual void getCondenseInit(char* init);
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_OR on C type #long# and #long#, result #long#.
+
+class OpORCLong : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpORCLong(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0, unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+ virtual void getCondenseInit(char* init);
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_XOR on C type #long# and #long#, result #long#.
+
+class OpXORCLong : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpXORCLong(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0, unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_PLUS on C type #double# and #double#, result #double#.
+
+class OpPLUSCDouble : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpPLUSCDouble(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0, unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+ virtual void getCondenseInit(char* init);
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_MINUS on C type #double# and #double#, result #double#.
+
+class OpMINUSCDouble : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpMINUSCDouble(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0, unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_DIV on C type #double# and #double#, result #double#.
+
+class OpDIVCDouble : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpDIVCDouble(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0, unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_MULT on C type #double# and #double#, result #double#.
+
+class OpMULTCDouble : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpMULTCDouble(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0, unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+ virtual void getCondenseInit(char* init);
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_EQUAL on C type #unsigned long# and #unsigned long#, result #char#.
+
+class OpEQUALCCharCULong : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpEQUALCCharCULong(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0, unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_LESS on C type #unsigned long# and #unsigned long#, result #char#.
+
+class OpLESSCCharCULong : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpLESSCCharCULong(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0, unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_LESSEQUAL on C type #unsigned long# and #unsigned long#, result #char#.
+
+class OpLESSEQUALCCharCULong : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpLESSEQUALCCharCULong(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0,
+ unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_NOTEQUAL on C type #unsigned long# and #unsigned long#, result #char#.
+
+class OpNOTEQUALCCharCULong : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpNOTEQUALCCharCULong(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0,
+ unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_GREATER on C type #unsigned long# and #unsigned long#, result #char#.
+
+class OpGREATERCCharCULong : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpGREATERCCharCULong(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0,
+ unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_GREATEREQUAL on \Ref{ULong} and \Ref{ULong}, result \Ref{Bool}.
+
+class OpGREATEREQUALCCharCULong : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpGREATEREQUALCCharCULong(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0,
+ unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_EQUAL on C type #unsigned long# and #unsigned long#, result #char#.
+
+class OpEQUALCCharCLong : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpEQUALCCharCLong(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0, unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_LESS on C type #long# and #long#, result #char#.
+
+class OpLESSCCharCLong : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpLESSCCharCLong(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0, unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_LESSEQUAL on C type #long# and #long#, result #char#.
+
+class OpLESSEQUALCCharCLong : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpLESSEQUALCCharCLong(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0,
+ unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_NOTEQUAL on C type #long# and #long#, result #char#.
+
+class OpNOTEQUALCCharCLong : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpNOTEQUALCCharCLong(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0,
+ unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_GREATER on C type #long# and #long#, result #char#.
+
+class OpGREATERCCharCLong : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpGREATERCCharCLong(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0,
+ unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_GREATEREQUAL on C type #long# and #long#, result #char#.
+
+class OpGREATEREQUALCCharCLong : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpGREATEREQUALCCharCLong(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0,
+ unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_EQUAL on C type #double# and #double#, result #char#.
+
+class OpEQUALCCharCDouble : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpEQUALCCharCDouble(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0, unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_LESS on C type #double# and #double#, result #char#.
+
+class OpLESSCCharCDouble : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpLESSCCharCDouble(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0, unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_LESSEQUAL on C type #double# and #double#, result #char#.
+
+class OpLESSEQUALCCharCDouble : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpLESSEQUALCCharCDouble(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0,
+ unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_NOTEQUAL on C type #double# and #double#, result #char#.
+
+class OpNOTEQUALCCharCDouble : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpNOTEQUALCCharCDouble(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0,
+ unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_GREATER on C type #double# and #double#, result #char#.
+
+class OpGREATERCCharCDouble : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpGREATERCCharCDouble(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0,
+ unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_GREATEREQUAL on C type #double# and #double#, result #char#.
+
+class OpGREATEREQUALCCharCDouble : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpGREATEREQUALCCharCDouble(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0,
+ unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_PLUS specialized for RasDaMan type Char.
+
+class OpPLUSChar : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpPLUSChar(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0, unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+ virtual void getCondenseInit(char* init);
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_MINUS specialized for RasDaMan type Char.
+
+class OpMINUSChar : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpMINUSChar(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0, unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_MULT specialized for RasDaMan type Char.
+
+class OpMULTChar : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpMULTChar(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0, unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+ virtual void getCondenseInit(char* init);
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_DIV specialized for RasDaMan type Char.
+
+class OpDIVChar : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpDIVChar(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0, unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_EQUAL specialized for RasDaMan type Char.
+
+class OpEQUALChar : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpEQUALChar(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0, unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_LESS specialized for RasDaMan type Char.
+
+class OpLESSChar : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpLESSChar(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0, unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_LESSEQUAL specialized for RasDaMan type Char.
+
+class OpLESSEQUALChar : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpLESSEQUALChar(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0,
+ unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_NOTEQUAL specialized for RasDaMan type Char.
+
+class OpNOTEQUALChar : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpNOTEQUALChar(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0,
+ unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_GREATER specialized for RasDaMan type Char.
+
+class OpGREATERChar : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpGREATERChar(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0,
+ unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_GREATEREQUAL specialized for RasDaMan type Char.
+
+class OpGREATEREQUALChar : public BinaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operands.
+ OpGREATEREQUALChar(const BaseType* newResType,const BaseType* newOp1Type,
+ const BaseType* newOp2Type, unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0,
+ unsigned int newOp2Off = 0 );
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1,
+ const char* op2 );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_IDENTITY specialized for RasDaMan type Char.
+
+class OpIDENTITYChar : public UnaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operand.
+ OpIDENTITYChar(const BaseType* newResType,const BaseType* newOpType,
+ unsigned int newResOff = 0, unsigned int newOpOff = 0 );
+ /// operator to carry out operation on {\tt op} with result {\tt result}.
+ virtual void operator()( char* result, const char* op );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_IDENTITY specialized for RasDaMan type Short.
+
+class OpIDENTITYShort : public UnaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operand.
+ OpIDENTITYShort(const BaseType* newResType,const BaseType* newOpType,
+ unsigned int newResOff = 0, unsigned int newOpOff = 0 );
+ /// operator to carry out operation on {\tt op} with result {\tt result}.
+ virtual void operator()( char* result, const char* op );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_IDENTITY specialized for RasDaMan type Long.
+
+class OpIDENTITYLong : public UnaryOp
+{
+public:
+ /// constructor gets RasDaMan base type of result and operand.
+ OpIDENTITYLong(const BaseType* newResType,const BaseType* newOpType,
+ unsigned int newResOff = 0, unsigned int newOpOff = 0 );
+ /// operator to carry out operation on {\tt op} with result {\tt result}.
+ virtual void operator()( char* result, const char* op );
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+
+/*@Doc:
+ MarrayOp is the superclass for all marray constructors. The class
+ defined here is just a dummy and will be specialized in another
+ module. operator() gets an r_Point as a parameter. For a useful
+ marray constructor operation() will also need to calculate an
+ expression.
+*/
+
+class MarrayOp
+{
+public:
+ /*@ManMemo: constructor gets RasDaMan base type of result and its
+ offset (for structs). Subclasses will have additional parameters. */
+ MarrayOp(const BaseType* newResType, unsigned int newResOff = 0 );
+ /// operator to carry out operation on {\tt p}. Has a dummy implementation.
+ virtual void operator() ( char* result, const r_Point& p );
+ /*@ManMemo: virtual destructor because subclasses may have
+ non-trivial destructor. */
+ virtual ~MarrayOp() { };
+
+protected:
+ const BaseType* resType;
+ unsigned int resOff;
+};
+
+//@ManMemo: Module: {\bf catalogif}.
+
+/*@Doc:
+ GenCondenseOp is the superclass for all general condense operations.
+ The class defined here is just a dummy and will be specialized in
+ another module. operator() gets an r_Point as a parameter. For a useful
+ marray constructor operation() will also need to calculate an
+ expression. Every GenCondenseOp has a binary operation which is
+ used to accumulate the values. If an initVal (of type resType)
+ is given, it is used as a basis for accumulation. Otherwist a
+ default initVal is retrieved from {\tt accuOp}.
+*/
+
+class GenCondenseOp
+{
+public:
+ /*@ManMemo: constructor gets RasDaMan base type of result and its
+ offset (for structs, 0 if no struct). A binary operation for
+ accumulation is given and an optional init value. Subclasses
+ will have additional parameters. Note that newInitVal has to be
+ deleted by the caller! */
+ GenCondenseOp(const BaseType* newResType, unsigned int newResOff,
+ BinaryOp* newAccuOp, char* newInitVal = 0 );
+ /// operator to carry out operation on {\tt p}. Has a dummy implementation.
+ virtual void operator()( const r_Point& p );
+ /// returns binary accumulation op (needed in class {\ref Tile}.
+ BinaryOp* getAccuOp();
+ /// returns result type (needed in class {\ref Tile}.
+ const BaseType* getResultType();
+ /// returns result offset (needed in class {\ref Tile}.
+ unsigned int getResultOff();
+ /// returns accumulated result.
+ char* getAccuVal();
+ /*@ManMemo: virtual destructor because subclasses may have
+ non-trivial destructor. */
+ virtual ~GenCondenseOp();
+
+protected:
+ const BaseType* resType;
+ unsigned int resOff;
+ BinaryOp* accuOp;
+ // initVal is always of RasDaMan-Type restype!
+ char* initVal;
+ // used to flag if destructor should delete initVal
+ int myInitVal;
+};
+
+
+//--------------------------------------------
+// Complex operations
+//--------------------------------------------
+
+class OpPLUSComplex : public BinaryOp {
+public:
+ // Question: which operand is scalar?
+ // Answere: NONE, FIRST, SECOND
+ enum ScalarFlag { NONE, FIRST, SECOND};
+
+ OpPLUSComplex(
+ const BaseType* newResType,
+ const BaseType* newOp1Type,
+ const BaseType* newOp2Type,
+ unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0,
+ unsigned int newOp2Off = 0,
+ ScalarFlag flag = NONE
+ );
+ virtual void operator()(char* res, const char* op1, const char* op2);
+ virtual void getCondenseInit(char* init);
+
+protected:
+ unsigned int op1ReOff;
+ unsigned int op1ImOff;
+ unsigned int op2ReOff;
+ unsigned int op2ImOff;
+ unsigned int resReOff;
+ unsigned int resImOff;
+ ScalarFlag scalarFlag;
+};
+
+class OpMINUSComplex : public BinaryOp {
+public:
+ // Question: which operand is scalar?
+ // Answere: NONE, FIRST, SECOND
+ enum ScalarFlag { NONE, FIRST, SECOND};
+
+ OpMINUSComplex(
+ const BaseType* newResType,
+ const BaseType* newOp1Type,
+ const BaseType* newOp2Type,
+ unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0,
+ unsigned int newOp2Off = 0,
+ ScalarFlag flag = NONE
+ );
+ virtual void operator()(char* res, const char* op1, const char* op2);
+
+protected:
+ unsigned int op1ReOff;
+ unsigned int op1ImOff;
+ unsigned int op2ReOff;
+ unsigned int op2ImOff;
+ unsigned int resReOff;
+ unsigned int resImOff;
+ ScalarFlag scalarFlag;
+};
+
+class OpDIVComplex : public BinaryOp {
+public:
+ // Question: which operand is scalar?
+ // Answere: NONE, FIRST, SECOND
+ enum ScalarFlag { NONE, FIRST, SECOND};
+
+ OpDIVComplex(
+ const BaseType* newResType,
+ const BaseType* newOp1Type,
+ const BaseType* newOp2Type,
+ unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0,
+ unsigned int newOp2Off = 0,
+ ScalarFlag flag = NONE
+ );
+ virtual void operator()( char* res, const char* op1, const char* op2 );
+
+protected:
+ unsigned int op1ReOff;
+ unsigned int op1ImOff;
+ unsigned int op2ReOff;
+ unsigned int op2ImOff;
+ unsigned int resReOff;
+ unsigned int resImOff;
+ ScalarFlag scalarFlag;
+};
+
+class OpMULTComplex : public BinaryOp {
+public:
+ // Question: which operand is scalar?
+ // Answere: NONE, FIRST, SECOND
+ enum ScalarFlag { NONE, FIRST, SECOND};
+
+ OpMULTComplex(
+ const BaseType* newResType,
+ const BaseType* newOp1Type,
+ const BaseType* newOp2Type,
+ unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0,
+ unsigned int newOp2Off = 0,
+ ScalarFlag flag = NONE
+ );
+ virtual void operator()( char* res, const char* op1, const char* op2 );
+ virtual void getCondenseInit(char* init);
+
+protected:
+ unsigned int op1ReOff;
+ unsigned int op1ImOff;
+ unsigned int op2ReOff;
+ unsigned int op2ImOff;
+ unsigned int resReOff;
+ unsigned int resImOff;
+ ScalarFlag scalarFlag;
+};
+
+class OpIDENTITYComplex : public UnaryOp {
+public:
+ OpIDENTITYComplex(const BaseType* , const BaseType* , unsigned int = 0, unsigned int = 0);
+ virtual void operator()(char* result, const char* op);
+};
+
+class OpRealPart : public UnaryOp {
+public:
+ OpRealPart(
+ const BaseType* newResType,
+ const BaseType* newOpType,
+ unsigned int newResOff = 0,
+ unsigned int newOpOff = 0
+ );
+ virtual void operator() (char* result, const char* op);
+
+private:
+ unsigned int opReOff;
+};
+
+
+class OpImaginarPart : public UnaryOp {
+public:
+ OpImaginarPart(
+ const BaseType* newResType,
+ const BaseType* newOpType,
+ unsigned int newResOff = 0,
+ unsigned int newOpOff = 0
+ );
+ virtual void operator() (char* result, const char* op);
+
+private:
+ unsigned int opImOff;
+};
+
+//--------------------------------------------
+// OpCAST
+//--------------------------------------------
+/*@Doc:
+OpCAST provide cast operation.
+*/
+
+class OpCAST : public UnaryOp {
+public:
+ OpCAST(
+ const BaseType* newResType,
+ const BaseType* newOpType,
+ unsigned int newResOff = 0,
+ unsigned int newOpOff = 0
+ );
+ /// operator to carry out cast operation.
+ virtual void operator() (char* result, const char* op);
+};
+
+//--------------------------------------------
+// OpOVERLAY
+//--------------------------------------------
+//@ManMemo: Module: {\bf catalogif}.
+//@Doc: OP_OVERLAY
+
+class OpOVERLAY : public BinaryOp
+{
+public:
+ /// this pattern is only 16 bytes long and empty, if your struct is longer you need to supply your own pattern
+ static const char* nullPattern;
+ /// constructor gets RasDaMan base type of result and operands.
+ OpOVERLAY(const BaseType* newResType,
+ const BaseType* newOp1Type,
+ const BaseType* newOp2Type,
+ size_t typeSize,
+ const char* transparentPattern = OpOVERLAY::nullPattern,
+ unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0,
+ unsigned int newOp2Off = 0);
+
+ /*@ManMemo: operator to carry out operation on {\tt op1} and
+ {\tt op2} with result {\tt res}. */
+ virtual void operator()( char* res, const char* op1, const char* op2 );
+private:
+ size_t length;
+
+ const char* pattern;
+};
+
+
+//--------------------------------------------
+// OpBIT
+//--------------------------------------------
+/*@Doc:
+*/
+
+class OpBIT : public BinaryOp {
+public:
+ OpBIT(
+ const BaseType* newResType,
+ const BaseType* newOp1Type,
+ const BaseType* newOp2Type,
+ unsigned int newResOff = 0,
+ unsigned int newOp1Off = 0,
+ unsigned int newOp2Off = 0
+ );
+
+ /// operator to carry out bit operation
+ virtual void operator()(char* res, const char* op1, const char* op2);
+};
+
+
+
+#include "autogen_ops.hh"
+
+
+#endif
+// LocalWords: op
diff --git a/catalogmgr/test/Makefile b/catalogmgr/test/Makefile
new file mode 100644
index 0000000..7671ac5
--- /dev/null
+++ b/catalogmgr/test/Makefile
@@ -0,0 +1,58 @@
+# -*-Makefile-*-
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>. # Top Level makefile. This points to the various modules that have to be build
+# and/or deployed
+#
+
+# MAKEFILE FOR:
+# the test program for a module
+#
+# COMMENTS:
+# List environment dependencies, known bugs, specialities etc.
+#
+##################################################################
+
+#
+# This is just an example Makefile for a test program.
+# The dependency of the test program on the lib of the
+# corresponding module is in the Makefile of the module.
+#
+
+######################### Definitions ############################
+
+# standard include with general options
+include $(RMANBASE)/Makefile.inc
+
+# object files for test program
+OBJS =
+# name of test program
+ALLTESTS =
+
+MISCCLEAN := core
+
+########################### Targets ##############################
+
+# general rules
+include $(RMANBASE)/Makefile.rel
+
+# automatically created dependencies
+include Makefile.dep
diff --git a/catalogmgr/typefactory.cc b/catalogmgr/typefactory.cc
new file mode 100644
index 0000000..80fee7a
--- /dev/null
+++ b/catalogmgr/typefactory.cc
@@ -0,0 +1,626 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+// This is -*- C++ -*-
+/*************************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ * uses embedded SQL
+ *
+ ***********************************************************************/
+
+static const char rcsid[] = "@(#)catalogif,TypeFactory: $Header: /home/rasdev/CVS-repository/rasdaman/catalogmgr/typefactory.cc,v 1.19 2003/12/20 23:41:27 rasdev Exp $";
+
+#include <vector>
+#include <algorithm>
+#include <map>
+#include <utility>
+#include <set>
+
+#include "raslib/rminit.hh"
+#include "raslib/rmdebug.hh"
+#include "relcatalogif/alltypes.hh"
+#include "typefactory.hh"
+#include "reladminif/objectbroker.hh"
+#include "reladminif/adminif.hh"
+#include "reladminif/databaseif.hh"
+#include "reladminif/sqlerror.hh"
+#include "reladminif/externs.h"
+#include "reladminif/dbref.hh"
+#include "relcatalogif/dbminterval.hh"
+#include "relmddif/mddid.hh"
+#include "relmddif/dbmddobj.hh"
+#include "relmddif/dbmddset.hh"
+
+TypeFactory* TypeFactory::myInstance = 0;
+
+const short TypeFactory::MaxBuiltInId = 11;
+
+const char* OctetType::Name = "Octet";
+const char* UShortType::Name = "UShort";
+const char* ShortType::Name = "Short";
+const char* ULongType::Name = "ULong";
+const char* LongType::Name = "Long";
+const char* BoolType::Name = "Bool";
+const char* CharType::Name = "Char";
+const char* FloatType::Name = "Float";
+const char* DoubleType::Name = "Double";
+const char* ComplexType1::Name = "Complex1";
+const char* ComplexType2::Name = "Complex2";
+
+using namespace std;
+
+// all atomic types given back by mapType()
+// for managing the memory of temporary types
+std::vector<Type*> *TypeFactory::theTempTypes = 0;
+
+TypeFactory*
+TypeFactory::instance()
+ {
+ if(myInstance == 0)
+ {
+ myInstance = new TypeFactory;
+ }
+ return myInstance;
+ }
+
+const BaseType*
+TypeFactory::mapType(const char* typeName)
+ {
+ RMDBGENTER(4, RMDebug::module_catalogmgr, "TypeFactory", "mapType(" << typeName << ")");
+ BaseType* resultType = 0;
+ resultType = (BaseType*)ObjectBroker::getObjectByName(OId::ATOMICTYPEOID, typeName);
+ if (resultType == 0)
+ {
+ try {
+ resultType = (BaseType*)ObjectBroker::getObjectByName(OId::STRUCTTYPEOID, typeName);
+ }
+ catch (r_Error)
+ {
+ resultType = 0;
+ }
+ }
+ RMDBGEXIT(4, RMDebug::module_catalogmgr, "TypeFactory", "mapType(" << typeName << ") END " << resultType);
+ return resultType;
+ }
+
+const StructType*
+TypeFactory::addStructType(const StructType* type)
+ {
+ RMDBGENTER(4, RMDebug::module_catalogmgr, "TypeFactory", "addStructType(" << type->getTypeName() << ")");
+ StructType* persistentType = 0;
+ const StructType* retval = 0;
+ if (type->isPersistent())
+ {
+ RMDBGMIDDLE(5, RMDebug::module_catalogmgr, "TypeFactory", "type is persistent " << type->getName() << " " << type->getOId());
+ retval = type;
+ }
+ else {
+ persistentType = new StructType((char*)type->getTypeName(), type->getNumElems());
+ BaseType* t = 0;
+ for (int i = 0; i < type->getNumElems(); i++)
+ {
+ switch (type->getElemType(i)->getType())
+ {
+ case STRUCT:
+ RMDBGMIDDLE(6, RMDebug::module_catalogmgr, "TypeFactory", "element is struct type " << (char*)type->getElemName(i) << " of type " << type->getElemType(i)->getName());
+ persistentType->addElement(type->getElemName(i), addStructType((const StructType*)type->getElemType(i)));
+ break;
+ case ULONG:
+ case USHORT:
+ case CHAR:
+ case BOOLTYPE:
+ case LONG:
+ case SHORT:
+ case OCTET:
+ case DOUBLE:
+ case FLOAT:
+ case COMPLEXTYPE1:
+ case COMPLEXTYPE2:
+ RMDBGMIDDLE(6, RMDebug::module_catalogmgr, "TypeFactory", "element is atomic type " << (char*)type->getElemName(i) << " of type " << type->getElemType(i)->getName());
+ persistentType->addElement(type->getElemName(i), (BaseType*)ObjectBroker::getObjectByOId(type->getElemType(i)->getOId()));
+ break;
+ default:
+ persistentType = 0;
+ RMDBGMIDDLE(0, RMDebug::module_catalogmgr, "TypeFactory", "addStructType(" << type->getTypeName() << ") unknown type " << type->getOId() << type->getOId().getType());
+ break;
+ }
+ }
+ RMDBGMIDDLE(5, RMDebug::module_catalogmgr, "TypeFactory", "type is now persistent " << persistentType->getName() << " " << persistentType->getOId());
+ persistentType->setCached(true);
+ persistentType->setPersistent(true);
+ ObjectBroker::registerDBObject(persistentType);
+ retval = persistentType;
+ }
+ RMDBGEXIT(4, RMDebug::module_catalogmgr, "TypeFactory", "addStructType(" << retval->getTypeName() << ") END");
+ return retval;
+ }
+
+const SetType*
+TypeFactory::mapSetType(const char* typeName)
+ {
+ RMDBGENTER(4, RMDebug::module_catalogmgr, "TypeFactory", "mapSetType(" << typeName << ")");
+ // it is a user defined type
+ SetType* resultType = 0;
+ try {
+ resultType = (SetType*)ObjectBroker::getObjectByName(OId::SETTYPEOID, typeName);
+ }
+ catch (r_Error)
+ {
+ resultType = 0;
+ }
+ RMDBGEXIT(4, RMDebug::module_catalogmgr, "TypeFactory", "mapSetType(" << typeName << ") END " << resultType);
+ return resultType;
+ }
+
+const SetType*
+TypeFactory::addSetType(const SetType* type)
+ {
+ RMDBGENTER(4, RMDebug::module_catalogmgr, "TypeFactory", "addSetType(" << type->getTypeName() << ")");
+ SetType* persistentType = 0;
+ const SetType* retval = 0;
+ if (type->isPersistent())
+ {
+ RMDBGMIDDLE(5, RMDebug::module_catalogmgr, "TypeFactory", "type is persistent " << type->getName() << " " << type->getOId());
+ retval = type;
+ }
+ else {
+ persistentType = new SetType((char*)type->getTypeName(), addMDDType(type->getMDDType()));
+ persistentType->setPersistent(true);
+ RMDBGMIDDLE(5, RMDebug::module_catalogmgr, "TypeFactory", "type is now persistent " << type->getName() << " " << persistentType->getOId());
+ ObjectBroker::registerDBObject(persistentType);
+ persistentType->setCached(true);
+ retval = persistentType;
+ }
+ RMDBGEXIT(4, RMDebug::module_catalogmgr, "TypeFactory", "addSetType(" << retval->getTypeName() << ") END");
+ return retval;
+ }
+
+const MDDType*
+TypeFactory::mapMDDType(const char* typeName)
+ {
+ RMDBGENTER(4, RMDebug::module_catalogmgr, "TypeFactory", "mapMDDType(" << typeName << ")");
+ MDDType* resultType = 0;
+ try {
+ resultType = ObjectBroker::getMDDTypeByName(typeName);
+ }
+ catch (...)
+ {
+ resultType = 0;
+ }
+ RMDBGEXIT(4, RMDebug::module_catalogmgr, "TypeFactory", "mapMDDType(" << typeName << ") END " << resultType);
+ return resultType;
+ }
+
+const MDDType*
+TypeFactory::addMDDType(const MDDType* type)
+ {
+ RMDBGENTER(4, RMDebug::module_catalogmgr, "TypeFactory", "addMDDType(" << type->getTypeName() << ")");
+ MDDType* persistentType = 0;
+ const MDDType* retval = 0;
+ BaseType* t = 0;
+
+ if (type->isPersistent())
+ {
+ RMDBGMIDDLE(5, RMDebug::module_catalogmgr, "TypeFactory", "type is persistent " << type->getOId());
+ retval = type;
+ }
+ else {
+ RMDBGMIDDLE(5, RMDebug::module_catalogmgr, "TypeFactory", "type is not persistent " << type->getOId());
+ switch (type->getSubtype())
+ {
+ case MDDType::MDDONLYTYPE:
+ RMDBGMIDDLE(7, RMDebug::module_catalogmgr, "TypeFactory", "is MDDONLYTYPE");
+ persistentType = new MDDType(type->getTypeName());
+ break;
+ case MDDType::MDDBASETYPE:
+ RMDBGMIDDLE(7, RMDebug::module_catalogmgr, "TypeFactory", "is MDDBASETYPE");
+ persistentType = new MDDBaseType(type->getTypeName(), addStructType((StructType*)((MDDBaseType*)type)->getBaseType()));
+ break;
+ case MDDType::MDDDOMAINTYPE:
+ RMDBGMIDDLE(7, RMDebug::module_catalogmgr, "TypeFactory", "is MDDDOMAINTYPE");
+ persistentType = new MDDDomainType(type->getTypeName(), addStructType((StructType*)((MDDBaseType*)type)->getBaseType()), *((MDDDomainType*)type)->getDomain());
+ break;
+ case MDDType::MDDDIMENSIONTYPE:
+ RMDBGMIDDLE(7, RMDebug::module_catalogmgr, "TypeFactory", "is MDDDIMENSIONTYPE");
+ persistentType = new MDDDimensionType(type->getTypeName(), addStructType((StructType*)((MDDBaseType*)type)->getBaseType()), ((MDDDimensionType*)type)->getDimension());
+ break;
+ default:
+ RMDBGMIDDLE(0, RMDebug::module_catalogmgr, "TypeFactory", "addMDDType(" << type->getName() << ") mddsubtype unknown");
+ break;
+ }
+ if (persistentType != 0)
+ {
+ persistentType->setPersistent(true);
+ RMDBGMIDDLE(6, RMDebug::module_catalogmgr, "TypeFactory", "adding " << persistentType->getName() << " " << persistentType->getOId());
+ persistentType->setCached(true);
+ ObjectBroker::registerDBObject(persistentType);
+ retval = persistentType;
+ }
+ else {
+ //error message was already given in switch default
+ }
+ }
+ RMDBGEXIT(4, RMDebug::module_catalogmgr, "TypeFactory", "addMDDType(" << type->getTypeName() << ") END");
+ return retval;
+ }
+
+Type*
+TypeFactory::addTempType(Type* type)
+ {
+ // put in front to avoid deletion of MDDTypes still referenced
+ // by an MDDBaseType.
+ theTempTypes->insert(theTempTypes->begin(), type);
+ return type;
+ }
+
+void
+TypeFactory::initialize()
+ {
+ // to initailize the typefactory
+ RMDBGENTER(4, RMDebug::module_catalogmgr, "TypeFactory", "initialize()");
+ if (!theTempTypes)
+ theTempTypes = new std::vector<Type*>;
+
+ RMDBGEXIT(4, RMDebug::module_catalogmgr, "TypeFactory", "initialize() END");
+ }
+
+void
+TypeFactory::freeTempTypes()
+ {
+ RMDBGENTER(4, RMDebug::module_catalogmgr, "TypeFactory", "freeTempTypes()");
+
+ // delete all temporary types
+ if (theTempTypes)
+ {
+ for(std::vector<Type*>::iterator iter = theTempTypes->begin(); iter != theTempTypes->end(); iter++)
+ {
+ delete *iter;
+ *iter = 0;
+ }
+ delete theTempTypes;
+ theTempTypes = 0;
+ }
+ RMDBGEXIT(4, RMDebug::module_catalogmgr, "TypeFactory", "freeTempTypes()");
+ }
+
+TypeFactory::TypeFactory()
+ {
+ }
+
+void
+TypeFactory::deleteStructType(const char* typeName)
+ {
+ RMDBGENTER(4, RMDebug::module_catalogmgr, "TypeFactory", "deleteStructType(" << typeName << ")");
+ const DBObject* resultType = mapType(typeName);
+ if (resultType)
+ {
+ if (resultType->getOId().getCounter() > MaxBuiltInId)
+ {//only neccessary to check if the type is in a mdd base/dim/dom type
+ bool canDelete = true;
+ for (TypeIterator<MDDType> miter = createMDDIter(); miter.not_done(); miter.advance())
+ {
+ if (miter.get_element()->getSubtype() != MDDType::MDDONLYTYPE)
+ {
+ if (((MDDBaseType*)(miter.get_element().ptr()))->getBaseType() == resultType)
+ {
+ RMDBGMIDDLE(5, RMDebug::module_catalogmgr, "TypeFactory", "mdd type " << miter.get_element()->getName() << " contains " << typeName);
+ canDelete = false;
+ break;
+ }
+ }
+ }
+ if (canDelete)
+ {
+ DBObjectId toKill(resultType->getOId());
+ toKill->setPersistent(false);
+ toKill->setCached(false);
+ RMDBGMIDDLE(5, RMDebug::module_catalogmgr, "TypeFactory", "will be deleted from db");
+ }
+ else {
+ RMDBGMIDDLE(5, RMDebug::module_catalogmgr, "TypeFactory", "will not be deleted from db");
+ }
+ }
+ else {
+ RMDBGMIDDLE(0, RMDebug::module_catalogmgr, "TypeFactory", "builtin type will not be deleted");
+ }
+ }
+ else {
+ RMDBGMIDDLE(5, RMDebug::module_catalogmgr, "TypeFactory", "is not in map");
+ }
+ RMDBGEXIT(4, RMDebug::module_catalogmgr, "TypeFactory", "deleteStructType(" << typeName << ")");
+ }
+
+void
+TypeFactory::deleteMDDType(const char* typeName)
+ {
+ RMDBGENTER(4, RMDebug::module_catalogmgr, "TypeFactory", "deleteMDDType(" << typeName << ")");
+ const MDDType* resultType = mapMDDType(typeName); //is ok because only short for find
+ if (resultType)
+ {
+ bool canDelete = true;
+ for (TypeIterator<SetType> miter = createSetIter(); miter.not_done(); miter.advance())
+ {
+ if (miter.get_element()->getMDDType() == resultType)
+ {
+ RMDBGMIDDLE(5, RMDebug::module_catalogmgr, "TypeFactory", "set type " << miter.get_element()->getName() << " contains " << typeName);
+ canDelete = false;
+ break;
+ }
+ }
+ if (canDelete)
+ {
+ if (resultType->getSubtype() != MDDType::MDDONLYTYPE)
+ {
+ //mdd only types can not be in mdd objects
+ OIdSet* theList = ObjectBroker::getAllObjects(OId::MDDOID);
+ for (OIdSet::iterator miter = theList->begin(); miter != theList->end(); miter++)
+ {
+ if (DBMDDObjId(*miter)->getMDDBaseType() == resultType)
+ {
+ RMDBGMIDDLE(5, RMDebug::module_catalogmgr, "TypeFactory", "mdd object " << *miter << " contains " << typeName);
+ canDelete = false;
+ break;
+ }
+ }
+ delete theList;
+ theList = 0;
+ }
+ if (canDelete)
+ {
+ DBObjectId toKill(resultType->getOId());
+ toKill->setPersistent(false);
+ toKill->setCached(false);
+ RMDBGMIDDLE(5, RMDebug::module_catalogmgr, "TypeFactory", "will be deleted from db");
+ }
+ else {
+ RMDBGMIDDLE(5, RMDebug::module_catalogmgr, "TypeFactory", "will not be deleted from db");
+ }
+ }
+ else {
+ RMDBGMIDDLE(5, RMDebug::module_catalogmgr, "TypeFactory", "will not be deleted from db");
+ }
+ }
+ else {
+ RMDBGMIDDLE(5, RMDebug::module_catalogmgr, "TypeFactory", "is not in map");
+ }
+ RMDBGEXIT(4, RMDebug::module_catalogmgr, "TypeFactory", "deleteMDDType(" << typeName << ") END");
+ }
+
+void
+TypeFactory::deleteSetType(const char* typeName)
+ {
+ RMDBGENTER(4, RMDebug::module_catalogmgr, "TypeFactory", "deleteSetType(" << typeName << ")");
+ const DBObject* resultType = (SetType*)mapSetType(typeName);//is ok because only short for find
+ if (resultType)
+ {
+ bool canDelete = true;
+ OIdSet* theList = ObjectBroker::getAllObjects(OId::MDDCOLLOID);
+ for (OIdSet::iterator miter = theList->begin(); miter != theList->end(); miter++)
+ {
+ if (DBMDDSetId(*miter)->getCollType() == resultType)
+ {
+ RMDBGMIDDLE(5, RMDebug::module_catalogmgr, "TypeFactory", "set object " << *miter << " contains " << typeName);
+ canDelete = false;
+ break;
+ }
+ }
+ delete theList;
+ theList = 0;
+ if (canDelete)
+ {
+ DBObjectId toKill(resultType->getOId());
+ toKill->setPersistent(false);
+ toKill->setCached(false);
+ RMDBGMIDDLE(5, RMDebug::module_catalogmgr, "TypeFactory", "will be deleted from db");
+ }
+ else {
+ RMDBGMIDDLE(5, RMDebug::module_catalogmgr, "TypeFactory", "will not be deleted from db");
+ }
+ }
+ else {
+ RMDBGMIDDLE(5, RMDebug::module_catalogmgr, "TypeFactory", "is not in map");
+ }
+ RMDBGEXIT(4, RMDebug::module_catalogmgr, "TypeFactory", "deleteSetType(" << typeName << ") END");
+ }
+
+const Type*
+TypeFactory::ensurePersistence(Type* type)
+ {
+ std::vector<Type*>::iterator iter;
+ const Type* retval = 0;
+ Type* ttype = 0;
+
+ // deleting type if it is in the list of tempTypes
+ if(theTempTypes)
+ {
+ for(iter = theTempTypes->begin(); iter < theTempTypes->end(); iter++)
+ {
+ if(*iter == type)
+ {
+ theTempTypes->erase(iter);
+ }
+ }
+ }
+ // check if the struct type is alread in the DBMS
+ switch (type->getType())
+ {
+ case STRUCT:
+ {
+ TypeIterator<StructType> ist = createStructIter();
+ while (ist.not_done())
+ {
+ ttype = ist.get_element();
+ if (ttype->compatibleWith(type))
+ {
+ retval = ttype;
+ break;
+ }
+ ist.advance();
+ }
+ if (!retval)
+ retval = addStructType((const StructType*)type);
+ }
+ break;
+ case MDDTYPE:
+ {
+ TypeIterator<MDDType> imd = createMDDIter();
+ while (imd.not_done())
+ {
+ ttype = imd.get_element();
+ if (ttype->compatibleWith(type))
+ {
+ retval = ttype;
+ break;
+ }
+ imd.advance();
+ }
+ if (!retval)
+ retval = addMDDType((const MDDType*)type);
+ }
+ break;
+ case SETTYPE:
+ {
+ TypeIterator<SetType> ise = createSetIter();
+ while (ise.not_done())
+ {
+ ttype = ise.get_element();
+ if (ttype->compatibleWith(type))
+ {
+ retval = ttype;
+ break;
+ }
+ ise.advance();
+ }
+ if (!retval)
+ retval = addSetType((const SetType*)type);
+ }
+ break;
+ case ULONG:
+ retval = (Type*)ObjectBroker::getObjectByOId(OId(ULONG, OId::ATOMICTYPEOID));
+ break;
+ case USHORT:
+ retval = (Type*)ObjectBroker::getObjectByOId(OId(USHORT, OId::ATOMICTYPEOID));
+ break;
+ case CHAR:
+ retval = (Type*)ObjectBroker::getObjectByOId(OId(CHAR, OId::ATOMICTYPEOID));
+ break;
+ case BOOLTYPE:
+ retval = (Type*)ObjectBroker::getObjectByOId(OId(BOOLTYPE, OId::ATOMICTYPEOID));
+ break;
+ case LONG:
+ retval = (Type*)ObjectBroker::getObjectByOId(OId(LONG, OId::ATOMICTYPEOID));
+ break;
+ case SHORT:
+ retval = (Type*)ObjectBroker::getObjectByOId(OId(SHORT, OId::ATOMICTYPEOID));
+ break;
+ case OCTET:
+ retval = (Type*)ObjectBroker::getObjectByOId(OId(OCTET, OId::ATOMICTYPEOID));
+ break;
+ case DOUBLE:
+ retval = (Type*)ObjectBroker::getObjectByOId(OId(DOUBLE, OId::ATOMICTYPEOID));
+ break;
+ case FLOAT:
+ retval = (Type*)ObjectBroker::getObjectByOId(OId(FLOAT, OId::ATOMICTYPEOID));
+ break;
+ case COMPLEXTYPE1:
+ retval = (Type*)ObjectBroker::getObjectByOId(OId(COMPLEXTYPE1, OId::ATOMICTYPEOID));
+ break;
+ case COMPLEXTYPE2:
+ retval = (Type*)ObjectBroker::getObjectByOId(OId(COMPLEXTYPE2, OId::ATOMICTYPEOID));
+ break;
+ default:
+ RMDBGONCE(0, RMDebug::module_catalogmgr, "TypeFactory", "ensurePersitence() is not a STRUCT/MDDTYPE/SETTYPE/ATOMIC " << type->getName());
+ break;
+ }
+ if (!type->isPersistent())
+ delete type;
+ return retval;
+ }
+
+TypeIterator<SetType>
+TypeFactory::createSetIter()
+ {
+ RMDBGONCE(1, RMDebug::module_catalogmgr, "TypeFactory", "createSetIter()");
+ OIdSet* t = ObjectBroker::getAllObjects(OId::SETTYPEOID);
+ TypeIterator<SetType> ti(*t);
+ delete t;
+ t = 0;
+ return ti;
+ }
+
+TypeIterator<StructType>
+TypeFactory::createStructIter()
+ {
+ RMDBGONCE(1, RMDebug::module_catalogmgr, "TypeFactory", "createStructIter()");
+ OIdSet* t = ObjectBroker::getAllObjects(OId::STRUCTTYPEOID);
+ TypeIterator<StructType> ti(*t);
+ delete t;
+ t = 0;
+ return ti;
+ }
+
+TypeIterator<MDDType>
+TypeFactory::createMDDIter()
+ {
+ RMDBGENTER(1, RMDebug::module_catalogmgr, "TypeFactory", "createMDDIter()");
+ OIdSet theMDDTypes;
+ OIdSet* tempList = 0;
+ OIdSet::iterator i;
+
+ tempList = ObjectBroker::getAllObjects(OId::MDDTYPEOID);
+ theMDDTypes = *tempList;
+ delete tempList;
+
+ tempList = ObjectBroker::getAllObjects(OId::MDDBASETYPEOID);
+ while (!tempList->empty())
+ {
+ theMDDTypes.insert(*(tempList->begin()));
+ tempList->erase(*(tempList->begin()));
+ }
+ delete tempList;
+
+ tempList = ObjectBroker::getAllObjects(OId::MDDDIMTYPEOID);
+ while (!tempList->empty())
+ {
+ theMDDTypes.insert(*(tempList->begin()));
+ tempList->erase(*(tempList->begin()));
+ }
+ delete tempList;
+
+ tempList = ObjectBroker::getAllObjects(OId::MDDDOMTYPEOID);
+ while (!tempList->empty())
+ {
+ theMDDTypes.insert(*(tempList->begin()));
+ tempList->erase(*(tempList->begin()));
+ }
+ delete tempList;
+
+ RMDBGEXIT(1, RMDebug::module_catalogmgr, "TypeFactory", "createMDDIter()");
+ return TypeIterator<MDDType>(theMDDTypes);
+ }
+
+
diff --git a/catalogmgr/typefactory.hh b/catalogmgr/typefactory.hh
new file mode 100644
index 0000000..816bb2d
--- /dev/null
+++ b/catalogmgr/typefactory.hh
@@ -0,0 +1,262 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#ifndef _TYPEFACTORY_HH_
+#define _TYPEFACTORY_HH_
+
+class TypeFactory;
+
+#include <vector>
+#include <map>
+
+#include "reladminif/oidif.hh"
+#include "relcatalogif/typeiterator.hh"
+
+class ULongType;
+class LongType;
+class CharType;
+class BoolType;
+class UShortType;
+class ShortType;
+class OctetType;
+class DoubleType;
+class FloatType;
+class ComplexType1;
+class ComplexType2;
+class StructType;
+class BaseType;
+class SetType;
+class MDDType;
+class Type;
+class DBMinterval;
+
+//@ManMemo: Module: {\bf relcatalogif}.
+
+/*@Doc:
+
+The user specifies types as strings. This is passed down to the
+TypeFactory where according to the string the object representing
+the type is read from the database. The base DBMS manages
+persistent objects for all base types. Pointers to these
+persistent objects are returned if #mapType# is called. In the
+current implementation, these pointers get invalid after a
+transaction is committed. So the user has to call #mapType# again
+after a commit(most programs do this anyway).
+
+The name of the type used for accessing it is the class name without
+the Type suffix. e.g. "Bool" for \Ref{BoolType} or "ULong" for
+\Ref{ULongType}.
+
+Only one instance of TypeFactory exists at any time. Also only one
+instance of the types exits in memory. The pointers returned
+should not be freed, the memory is freed, when the TypeFactory is
+destroyed. The static member function can also be called directly
+with the scope operator. The class follows the singleton design
+pattern(Gamma et. al. S. 127ff.) and the builder design pattern
+(Gamma et. al. S. 97ff.).
+
+{\bf Functionality}
+
+Returns a pointer to \Ref{BaseType} to the type which is identified by
+a string.
+
+{\bf Interdependencies}
+
+Will be used from \Ref{MDDObject} and subclasses when created.
+Because all types are stored persistently, it is necessary to open
+a session using AdminIf::instance()(see \Ref{AdminIf}), a
+database using DatabaseIf::open()(see \Ref{DatabaseIf) and a
+transaction using TransactionIf::begin(see \Ref{TransactionIf)
+before creating instances of types with mapType().
+*/
+
+class TypeFactory
+ {
+ public:
+ static TypeFactory* instance();
+ /*@Doc:
+ used to access instance of TileFactory.
+ */
+
+ static const BaseType* mapType(const char* typeName);
+ /*@Doc:
+ maps a string to a base type
+ e.g. #aTypeFactory->mapType("ULong")# returns a pointer to an
+ instance of ULongType. This also works for user defined type
+ like #aTypeFactory->mapType("myStruct")# returning a pointer
+ to a user defined StructType.
+ */
+
+ //static BaseType* mapType(char* typeName);
+ /*@Doc:
+ maps a string to a base type
+ use the const char* version!!
+ */
+
+ static const SetType* mapSetType(const char* typeName);
+ /*@Doc:
+ maps a string to a set type
+ */
+
+ //static const SetType* mapSetType(char* typeName);
+ /*@Doc:
+ maps a string to a set type
+ use the const char* version!!
+ */
+
+ static const MDDType* mapMDDType(const char* typeName);
+ /*@Doc:
+ maps a string to a mdd type
+ */
+
+ //static const MDDType* mapMDDType(char* typeName);
+ /*@Doc:
+ maps a string to a mdd type.
+ use the const char* version!!
+ */
+
+ static const StructType* addStructType(const StructType* type);
+ /*@Doc:
+ add a new struct type to the current DBMS.
+ After calling this function, a user defined type can be
+ retrieved with function #mapType()#. The type only becomes
+ persistent after commit.
+ */
+
+ static const SetType* addSetType(const SetType* type);
+ /*@Doc:
+ add a new set type to the current DBMS.
+ After calling this function, a user defined set type can be
+ retrieved with function #mapSetType()#. The type only becomes
+ persistent after commit.
+ */
+
+ static const MDDType* addMDDType(const MDDType* type);
+ /*@Doc:
+ add a new set type to the current DBMS.
+ After calling this function, a user defined mdd type can be
+ retrieved with function #mapMDDType()#. The type only becomes
+ persistent after commit.
+ */
+
+ static void deleteStructType(const char* typeName);
+ /*@Doc:
+ delete a struct type in the current DBMS.
+ */
+
+ static void deleteSetType(const char* typeName);
+ /*@Doc:
+ delete a set type in the current DBMS.
+ */
+
+ static void deleteMDDType(const char* typeName);
+ /*@Doc:
+ delete a mdd type in the current DBMS.
+ */
+
+ static TypeIterator<StructType> createStructIter();
+ /*@Doc:
+ Note that get_element returns a pointer to a StructType!
+ returns an iterator for StructTypes.
+ */
+
+ static TypeIterator<SetType> createSetIter();
+ /*@Doc:
+ Note that get_element returns a pointer to a SetType!
+ returns an iterator for SetTypes.
+ */
+
+ static TypeIterator<MDDType> createMDDIter();
+ /*@Doc:
+ Note that get_element returns a pointer to a MDDType!
+ returns an iterator for MDDTypes.
+ */
+
+
+ static Type* addTempType(Type* type);
+ /*@Doc:
+ Memory is freed at commit time of transaction in
+ TransactionIf::commit(), TransactionIf::validate() and
+ TransactionIf::abort().
+
+ {\em Note:} You have to use addTempType() on a composite type
+ (e.g. \Ref{SetType}) first before calling addTempType() on a
+ component(e.g. \Ref{MDDType}). Otherwise the component may be
+ freed first sometimes leading to a crash.
+ registers a temporary type with the type factory.
+ */
+
+ static void initialize();
+ /*@Doc:
+ Should only be called by \Ref{TransactionIf}).
+ initializes after a begin transaction. theTempTypes are created.
+ */
+
+ static void freeTempTypes();
+ /*@Doc:
+ Should only be called by \Ref{TransactionIf}).
+ frees temporary types.
+ */
+
+ static const Type* ensurePersistence(Type* type);
+ /*@Doc:
+ This function has to be called on all types registered as
+ temporary types but getting persistent during query execution. The
+ type is deleted from the tempTypes list, i.e. not freed on end of
+ transaction. If a structurally equivalent type is found in the
+ database it will be used and a pointer to it returned. Note that
+ this currently works only for StructTypes!
+ has to be called on temporary types getting persistent.
+ */
+
+ static const short MaxBuiltInId;
+
+ protected:
+ TypeFactory();
+ /*@Doc:
+ constructor, can not be used from outside.
+ */
+
+ private:
+ static TypeFactory* myInstance;
+ /*@Doc:
+ pointer to instance for Singleton pattern.
+ */
+
+ static std::vector<Type*> *theTempTypes;
+ /*@Doc:
+ a vector containing pointers to temporary allocated types.
+ */
+
+ };
+
+#endif
diff --git a/clientcomm/Makefile.am b/clientcomm/Makefile.am
new file mode 100644
index 0000000..62f6b7c
--- /dev/null
+++ b/clientcomm/Makefile.am
@@ -0,0 +1,64 @@
+# -*-Makefile-*- (for Emacs)
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+#
+# MAKEFILE FOR:
+# module clientcomm
+#
+# COMMENTS:
+# - build of akgnet should be revisited wrt. 3rdParty!
+#
+##################################################################
+
+AM_CXXFLAGS = @CLIENTCXXFLAGS@
+AM_LDFLAGS = @CLIENTLDFLAGS@
+
+noinst_LIBRARIES=libclientcomm.a
+libclientcomm_a_SOURCES = rpcif_clnt.cc rpcif_xdr.c rpcif.h \
+ clientcomm.cc clientcomm.hh rpcclientcomm.cc \
+ rpcclientcomm.hh clientcomm.icc \
+ ../mymalloc/mymalloc_cln.cc ../mymalloc/mymalloc.h
+EXTRA_libclientcomm_a_SOURCES = rpcif.x
+BUILT_SOURCES= rpcif_clnt.cc rpcif_xdr.c rpcif.h rpcif_svc.cc
+CLEANFILES=rpcif_clnt.cc rpcif_xdr.c rpcif.h rpcif.h.tmp rpcif_clnt.c.tmp \
+ rpcif_svc.cc.tmp rpcif_svc.cc
+
+
+rpcif.h: rpcif.x
+ $(RPCGEN) -h -o rpcif.h.tmp rpcif.x
+ $(AWK) -f rpcif.h.awk rpcif.h.tmp > rpcif.h
+ rm rpcif.h.tmp
+
+rpcif_clnt.cc: rpcif.x
+ $(RPCGEN) -l -o rpcif_clnt.cc.tmp rpcif.x
+ $(AWK) -f rpcif_clnt.c.awk rpcif_clnt.cc.tmp > rpcif_clnt.cc
+ rm rpcif_clnt.cc.tmp
+
+rpcif_xdr.c: rpcif.x
+ -rm rpcif_xdr.c
+ $(RPCGEN) -c -o rpcif_xdr.c rpcif.x
+
+rpcif_svc.cc: rpcif.x
+ $(RPCGEN) -m -o rpcif_svc.cc.tmp rpcif.x
+ $(AWK) -f rpcif_svc.c.awk rpcif_svc.cc.tmp > rpcif_svc.cc
+ rm rpcif_svc.cc.tmp
+
diff --git a/clientcomm/clientcomm.cc b/clientcomm/clientcomm.cc
new file mode 100644
index 0000000..d1dffb8
--- /dev/null
+++ b/clientcomm/clientcomm.cc
@@ -0,0 +1,124 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: clientcomm.cc
+ *
+ * MODULE: clientcomm
+ * CLASS: ClientComm
+ *
+ * COMMENTS:
+ * None
+*/
+
+static const char rcsid[] = "@(#)clientcomm, ClientComm: $Id: clientcomm.cc,v 1.145 2006/01/03 21:39:21 rasdev Exp $";
+
+using namespace std;
+
+#include "clientcomm/clientcomm.hh"
+#include "clientcomm/rpcclientcomm.hh"
+#include "rnprotocol/rnpclientcomm.hh"
+
+
+#include "raslib/endian.hh"
+int
+ClientComm::changeEndianness( r_GMarray* mdd, const r_Base_Type *bt )
+{
+ const r_Base_Type *baseType;
+ const r_Minterval &interv = mdd->spatial_domain();
+
+ baseType = (bt == NULL) ? mdd->get_base_type_schema() : bt;
+
+ if (baseType == NULL )
+ {
+ cerr << "ClientComm::changeEndianness: No base type information!" << endl;
+ return 0;
+ }
+
+ r_Endian::swap_array(baseType, interv, interv, mdd->get_array(), mdd->get_array());
+
+ return 1;
+}
+
+
+int
+ClientComm::changeEndianness( const r_GMarray* mdd, void *newMdd, const r_Base_Type* bt )
+{
+ const r_Base_Type *baseType;
+ const r_Minterval &interv = mdd->spatial_domain();
+
+ // Get the base type...
+ baseType = (bt == NULL) ? ((r_GMarray*)mdd)->get_base_type_schema() : bt;
+
+ if ( baseType == NULL )
+ {
+ cerr << "ClientComm::changeEndianness: No base type information!" << endl;
+ memcpy( newMdd, mdd->get_array(), mdd->get_array_size());
+ return 0;
+ }
+
+ r_Endian::swap_array(baseType, interv, interv, mdd->get_array(), newMdd);
+
+ return 1;
+}
+
+ClientComm::ClientComm( ) throw( r_Error )
+ {
+
+ }
+
+ClientComm* ClientComm::createObject(const char* rasmgrName, int rasmgrPort)
+ {
+ char *env = getenv("RMANPROTOCOL");
+
+ bool createRNP = currentProtocolIsRNP;
+
+ if(env != 0)
+ {
+ if(strcmp(env,"RNP") == 0 || strcmp(env,"HTTP") == 0) createRNP = true;
+ if(strcmp(env,"RPC") == 0 || strcmp(env,"COMPAT") == 0) createRNP = false;
+ // rest is ignored
+ }
+
+ if(createRNP)
+ return new RnpClientComm( rasmgrName, rasmgrPort);
+
+ return new RpcClientComm(rasmgrName, rasmgrPort);
+ }
+
+ClientComm::~ClientComm() throw()
+{
+ }
+
+// default comm protocol to be used:
+// true use RNP
+// false use RPC
+bool ClientComm::currentProtocolIsRNP=true; // up to (excl) 6.0 'false' for MOSS to maintain compat with old apps
+
+void ClientComm::useRNP() throw() { currentProtocolIsRNP = true; }
+
+void ClientComm::useRPC() throw() { currentProtocolIsRNP = false; }
+
+bool ClientComm::internalSettingIsRNP() throw() { return currentProtocolIsRNP;}
+
+
+
diff --git a/clientcomm/clientcomm.hh b/clientcomm/clientcomm.hh
new file mode 100644
index 0000000..4d255d5
--- /dev/null
+++ b/clientcomm/clientcomm.hh
@@ -0,0 +1,269 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: clientcomm.hh
+ *
+ * MODULE: clientcomm
+ * CLASS: ClientComm
+ *
+ * COMMENTS:
+ * ClientComm is now an abstract class, with two subclasses: RpcClintComm and RnpClientComm
+ * This will change again when RPC will be dropped forever
+ *
+*/
+
+#ifndef _CLIENTCOMM_
+#define _CLIENTCOMM_
+
+#include "raslib/rminit.hh"
+#include "raslib/error.hh"
+#include "rasodmg/oqlquery.hh"
+#include "rasodmg/marray.hh"
+
+#include "raslib/primitivetype.hh"
+
+
+template <class T> class r_Set;
+class r_Ref_Any;
+class r_Base_Type;
+class r_Parse_Params;
+
+
+//@ManMemo: Module: {\bf clientcomm}
+
+/*@Doc:
+
+The class ClientComm represents {\bf one} connection between
+{\bf one} client entity (e.g. an object of class \Ref{r_Database}) and
+the server. Therefore, the host name has to be provided at
+the constructor.
+*/
+
+class ClientComm
+{
+ public:
+
+ /// destructor (closes the connection and releases resources)
+ virtual ~ClientComm() throw();
+
+ // the class is not necessary singleton, but the type of the actual object depends on the environment
+ static ClientComm* createObject(const char* rasmgrName, int rasmgrPort);
+
+ /** Methods for setting the protocol. Default will be RNP, but until release 5.2 it is RPC,
+ unless you compile with -DDEFAULTRNP
+ Also, if the environment variable RMANPROTOCOL is set, it's value is used to set the protocol
+ and the 'in-code' setting is ignored
+ RMANPROTOCOL can be:
+ - RNP -> RNP is used
+ - COMPAT -> raslib uses RPC, rasj uses HTTP
+ - RPC -> raslib uses RPC, rasj uses RNP
+ - HTTP -> raslib uses RNP, rasj uses HTTP
+ every other value is ignored and the 'in-code' setting is used
+
+ NOTE: This methods will be removed in the next version
+ */
+
+ static void useRNP() throw();
+ static void useRPC() throw();
+ static bool internalSettingIsRNP() throw();
+
+ virtual bool effectivTypeIsRNP() throw() = 0;
+
+ //@Man: Database methods
+ //@{
+ ///
+ //RNP: all made pure
+
+ /// open database
+ virtual int openDB( const char* database ) = 0;
+ /// close current database
+ virtual int closeDB() = 0;
+ /// create a database
+ virtual int createDB( const char* name ) throw(r_Error) = 0;
+ /// destroy a database
+ virtual int destroyDB( const char* name ) throw(r_Error) = 0;
+
+ ///
+ //@}
+
+ //@Man: Transaction methods
+ //@{
+ ///
+
+ /// begin transaction
+ virtual int openTA( unsigned short readOnly = 0 ) throw(r_Error) =0;
+ /// commit current transaction
+ virtual int commitTA() throw(r_Error) =0;
+ /// abort current transaction
+ virtual int abortTA() =0;
+
+ ///
+ //@}
+
+ //@Man: MDD methods
+ //@{
+ ///
+
+ /// inserts a MDD object in an existing MDD collection on the server
+ virtual void insertMDD( const char* collName, r_GMarray* mar ) throw( r_Error ) =0;
+ /// gets MDD object by oid
+ virtual r_Ref_Any getMDDByOId( const r_OId& oid ) throw( r_Error ) =0;
+
+ ///
+ //@}
+
+ //@Man: Collection methods
+ //@{
+ ///
+
+ /// creates an empty MDD collection on the server
+ virtual void insertColl( const char* collName, const char* typeName, const r_OId& oid ) throw( r_Error ) =0;
+ /// deletes an MDD collection by name
+ virtual void deleteCollByName( const char* collName ) throw( r_Error ) =0;
+ /// deletes an object by oid (right now, objects are collection only)
+ virtual void deleteObjByOId( const r_OId& oid ) throw( r_Error ) =0;
+ /// removes an object from a collection
+ virtual void removeObjFromColl( const char* name, const r_OId& oid ) throw ( r_Error ) =0;
+ /// gets collection by name
+ virtual r_Ref_Any getCollByName( const char* name ) throw( r_Error ) =0;
+ /// gets collection by oid
+ virtual r_Ref_Any getCollByOId ( const r_OId& oid ) throw( r_Error ) =0;
+ /// gets collection references by name
+ virtual r_Ref_Any getCollOIdsByName( const char* name ) throw( r_Error ) =0;
+ /// gets collection references by oid
+ virtual r_Ref_Any getCollOIdsByOId ( const r_OId& oid ) throw( r_Error ) =0;
+
+ ///
+ //@}
+
+ //@Man: Query methods
+ //@{
+ ///
+
+ /// query execution
+ virtual void executeQuery( const r_OQL_Query& query, r_Set< r_Ref_Any >& result ) throw( r_Error ) =0;
+ /*@Doc:
+ Executes a retrieval query of type \Ref{r_OQL_Query} and returns the result. Every
+ MDD object of the MDD collection is fetched from the server and inserted
+ in the resulting \Ref{r_Set}.
+ */
+
+ /// update execution
+ virtual void executeQuery( const r_OQL_Query& query ) throw( r_Error ) =0;
+ /*@Doc:
+ Executes an update query of type \Ref{r_OQL_Query}.
+ */
+
+ ///
+ //@}
+
+
+ //@Man: System methods
+ //@{
+ ///
+
+ /// get new oid
+ virtual r_OId getNewOId( unsigned short objType ) throw(r_Error) = 0;
+
+ /// get oid type
+ virtual unsigned short getObjectType( const r_OId& oid ) throw(r_Error) = 0;
+
+ enum r_Type_Type
+ {
+ r_SetType_Type = 1,
+ r_MDDType_Type = 2
+ };
+
+ /// get type structure
+ /// deallocate using delete []
+ virtual char* getTypeStructure( const char* typeName, r_Type_Type typeType ) throw(r_Error) =0;
+
+ ///
+ //@}
+
+ /// changes endianness of MDD data
+ static int changeEndianness( r_GMarray* mdd, const r_Base_Type* bt=NULL );
+ /// changes the endianness of MDD data and keeps the original untouched
+ static int changeEndianness( const r_GMarray* mdd, void *newData, const r_Base_Type* bt=NULL );
+
+ /// provides read access to my clientID
+ virtual unsigned long getClientID() const = 0;
+
+
+ //@Man: Methods for asynchronious alive signal concept
+ //@{
+
+ /// triggers an alive signal
+ virtual void triggerAliveSignal() = 0;
+ /**
+ First, it sets the switch {\tt aliveSignalRemaining} saying that an alive signal
+ should be send to the server. Then it calls {\tt sendAliveSignal()} to send it
+ immediately if possible.
+ */
+
+ /// send an alive signal if necessary and possible
+ virtual void sendAliveSignal() = 0;
+ /**
+ Sends an alive signal to the server if the switch {\tt aliveSignalRemaining} is
+ set and no other RPC is active. If a signal can be sent, {\tt aliveSignalRemaining}
+ is set to 0 again.
+ */
+
+ /// set the preferred transfer format
+ virtual int setTransferFormat( r_Data_Format format, const char* formatParams=NULL ) =0;
+
+ /// set the preferred storage format
+ virtual int setStorageFormat( r_Data_Format format, const char *formatParams=NULL ) =0;
+
+ /// get extended error information
+ virtual const char *getExtendedErrorInfo() throw(r_Error) =0;
+
+ /// get real server name (the dinamic one, assigned by the RasMGR)
+ const char* getServerName();
+
+ /// user identification for RasMGR
+ virtual void setUserIdentification(const char *userName, const char *plainTextPassword) =0;
+
+ /// set maximum retry to get a server
+ virtual void setMaxRetry(unsigned int newMaxRetry) = 0;
+
+ /// get maximum retry to get a server
+ virtual unsigned int getMaxRetry() = 0;
+
+ /// set and get communication timeout interval. Only RNP really uses it
+ virtual void setTimeoutInterval(int seconds) = 0;
+ virtual int getTimeoutInterval() = 0;
+
+ ///
+ //@}
+
+ protected:
+ /// constructor getting nothing
+ ClientComm() throw( r_Error );
+
+ private:
+
+ static bool currentProtocolIsRNP;
+ };
+
+#endif
diff --git a/clientcomm/clientcomm.icc b/clientcomm/clientcomm.icc
new file mode 100644
index 0000000..4a77e46
--- /dev/null
+++ b/clientcomm/clientcomm.icc
@@ -0,0 +1,43 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INLINE SOURCE: clientcomm.icc
+ *
+ * MODULE: clientcomm
+ * CLASS: ClientComm
+ *
+ * COMMENTS:
+ * None
+*/
+
+inline unsigned long
+ClientComm::getClientID() const
+{
+ return clientID;
+}
+
+inline CLIENT*
+ClientComm::getBindingHandle() const
+{
+ return binding_h;
+}
diff --git a/clientcomm/clientcomm_RNPdefault.cc b/clientcomm/clientcomm_RNPdefault.cc
new file mode 100644
index 0000000..87ceda4
--- /dev/null
+++ b/clientcomm/clientcomm_RNPdefault.cc
@@ -0,0 +1,126 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: clientcomm.cc
+ *
+ * MODULE: clientcomm
+ * CLASS: ClientComm
+ *
+ * PURPOSE:
+ *
+ * COMMENTS:
+ * No Comments
+*/
+
+static const char rcsid[] = "@(#)clientcomm, ClientComm: $Id: clientcomm.cc,v 1.143 2005/09/09 16:16:29 rasdev Exp $";
+
+using namespace std;
+
+#include "clientcomm/clientcomm.hh"
+#include "clientcomm/rpcclientcomm.hh"
+#include "rnprotocol/rnpclientcomm.hh"
+
+
+#include "raslib/endian.hh"
+int
+ClientComm::changeEndianness( r_GMarray* mdd, const r_Base_Type *bt )
+{
+ const r_Base_Type *baseType;
+ const r_Minterval &interv = mdd->spatial_domain();
+
+ baseType = (bt == NULL) ? mdd->get_base_type_schema() : bt;
+
+ if (baseType == NULL )
+ {
+ cerr << "ClientComm::changeEndianness: No base type information!" << endl;
+ return 0;
+ }
+
+ r_Endian::swap_array(baseType, interv, interv, mdd->get_array(), mdd->get_array());
+
+ return 1;
+}
+
+
+int
+ClientComm::changeEndianness( const r_GMarray* mdd, void *newMdd, const r_Base_Type* bt )
+{
+ const r_Base_Type *baseType;
+ const r_Minterval &interv = mdd->spatial_domain();
+
+ // Get the base type...
+ baseType = (bt == NULL) ? ((r_GMarray*)mdd)->get_base_type_schema() : bt;
+
+ if ( baseType == NULL )
+ {
+ cerr << "ClientComm::changeEndianness: No base type information!" << endl;
+ memcpy( newMdd, mdd->get_array(), mdd->get_array_size());
+ return 0;
+ }
+
+ r_Endian::swap_array(baseType, interv, interv, mdd->get_array(), newMdd);
+
+ return 1;
+}
+
+ClientComm::ClientComm( ) throw( r_Error )
+ {
+
+ }
+
+ClientComm* ClientComm::createObject(const char* rasmgrName, int rasmgrPort)
+ {
+ char *env = getenv("RMANPROTOCOL");
+
+ bool createRNP = currentProtocolIsRNP;
+
+ if(env != 0)
+ {
+ if(strcmp(env,"RNP") == 0 || strcmp(env,"HTTP") == 0) createRNP = true;
+ if(strcmp(env,"RPC") == 0 || strcmp(env,"COMPAT") == 0) createRNP = false;
+ // rest is ignored
+ }
+
+ if(createRNP)
+ return new RnpClientComm( rasmgrName, rasmgrPort);
+
+ return new RpcClientComm(rasmgrName, rasmgrPort);
+ }
+
+ClientComm::~ClientComm() throw()
+{
+ }
+
+// default comm protocol to be used:
+// true use RNP
+// false use RPC
+bool ClientComm::currentProtocolIsRNP=true;
+
+void ClientComm::useRNP() throw() { currentProtocolIsRNP = true; }
+
+void ClientComm::useRPC() throw() { currentProtocolIsRNP = false; }
+
+bool ClientComm::internalSettingIsRNP() throw() { return currentProtocolIsRNP;}
+
+
+
diff --git a/clientcomm/clientcomm_RPCdefault.cc b/clientcomm/clientcomm_RPCdefault.cc
new file mode 100644
index 0000000..2c69e00
--- /dev/null
+++ b/clientcomm/clientcomm_RPCdefault.cc
@@ -0,0 +1,126 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: clientcomm.cc
+ *
+ * MODULE: clientcomm
+ * CLASS: ClientComm
+ *
+ * PURPOSE:
+ *
+ * COMMENTS:
+ * No Comments
+*/
+
+static const char rcsid[] = "@(#)clientcomm, ClientComm: $Id: clientcomm.cc,v 1.143 2005/09/09 16:16:29 rasdev Exp $";
+
+using namespace std;
+
+#include "clientcomm/clientcomm.hh"
+#include "clientcomm/rpcclientcomm.hh"
+#include "rnprotocol/rnpclientcomm.hh"
+
+
+#include "raslib/endian.hh"
+int
+ClientComm::changeEndianness( r_GMarray* mdd, const r_Base_Type *bt )
+{
+ const r_Base_Type *baseType;
+ const r_Minterval &interv = mdd->spatial_domain();
+
+ baseType = (bt == NULL) ? mdd->get_base_type_schema() : bt;
+
+ if (baseType == NULL )
+ {
+ cerr << "ClientComm::changeEndianness: No base type information!" << endl;
+ return 0;
+ }
+
+ r_Endian::swap_array(baseType, interv, interv, mdd->get_array(), mdd->get_array());
+
+ return 1;
+}
+
+
+int
+ClientComm::changeEndianness( const r_GMarray* mdd, void *newMdd, const r_Base_Type* bt )
+{
+ const r_Base_Type *baseType;
+ const r_Minterval &interv = mdd->spatial_domain();
+
+ // Get the base type...
+ baseType = (bt == NULL) ? ((r_GMarray*)mdd)->get_base_type_schema() : bt;
+
+ if ( baseType == NULL )
+ {
+ cerr << "ClientComm::changeEndianness: No base type information!" << endl;
+ memcpy( newMdd, mdd->get_array(), mdd->get_array_size());
+ return 0;
+ }
+
+ r_Endian::swap_array(baseType, interv, interv, mdd->get_array(), newMdd);
+
+ return 1;
+}
+
+ClientComm::ClientComm( ) throw( r_Error )
+ {
+
+ }
+
+ClientComm* ClientComm::createObject(const char* rasmgrName, int rasmgrPort)
+ {
+ char *env = getenv("RMANPROTOCOL");
+
+ bool createRNP = currentProtocolIsRNP;
+
+ if(env != 0)
+ {
+ if(strcmp(env,"RNP") == 0 || strcmp(env,"HTTP") == 0) createRNP = true;
+ if(strcmp(env,"RPC") == 0 || strcmp(env,"COMPAT") == 0) createRNP = false;
+ // rest is ignored
+ }
+
+ if(createRNP)
+ return new RnpClientComm( rasmgrName, rasmgrPort);
+
+ return new RpcClientComm(rasmgrName, rasmgrPort);
+ }
+
+ClientComm::~ClientComm() throw()
+{
+ }
+
+// default comm protocol to be used:
+// true use RNP
+// false use RPC
+bool ClientComm::currentProtocolIsRNP=true; // up to (excl) 6.0 'false' for MOSS to maintain compat with old apps
+
+void ClientComm::useRNP() throw() { currentProtocolIsRNP = true; }
+
+void ClientComm::useRPC() throw() { currentProtocolIsRNP = false; }
+
+bool ClientComm::internalSettingIsRNP() throw() { return currentProtocolIsRNP;}
+
+
+
diff --git a/clientcomm/clnt_control.c b/clientcomm/clnt_control.c
new file mode 100644
index 0000000..7cb683d
--- /dev/null
+++ b/clientcomm/clnt_control.c
@@ -0,0 +1,101 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+
+#include "clientcomm/clnt_control/clnt_control.h"
+#include "clientcomm/rpcif.h"
+
+#include <stdio.h>
+
+void client_control(CLIENT *cl, unsigned int rq, char *in)
+{
+ clnt_control(cl, rq, in);
+}
+
+void client_destroy(CLIENT *cl)
+{
+ clnt_destroy(cl);
+}
+
+CLIENT* client_create(char *host, u_long prog, u_long vers, char *prot)
+{
+ return clnt_create(host, prog, vers, prot);
+}
+
+extern void xdr_free(xdrproc_t proc, char *objp );
+
+void xdrfree( ntxdr_Type xdrType, char *objp )
+{
+ switch( xdrType )
+ {
+ case ntxdr_ExecuteQueryRes:
+ xdr_free( xdr_ExecuteQueryRes, objp );
+ break;
+ case ntxdr_ExecuteUpdateRes:
+ xdr_free( xdr_ExecuteUpdateRes, objp );
+ break;
+ case ntxdr_GetMDDRes:
+ xdr_free( xdr_GetMDDRes, objp );
+ break;
+ case ntxdr_GetTileRes:
+ xdr_free( xdr_GetTileRes, objp );
+ break;
+ case ntxdr_GetCollRes:
+ xdr_free( xdr_GetCollRes, objp );
+ break;
+ case ntxdr_GetCollOIdsRes:
+ xdr_free( xdr_GetCollOIdsRes, objp );
+ break;
+ case ntxdr_OIdRes:
+ xdr_free( xdr_OIdRes, objp );
+ break;
+ case ntxdr_ObjectTypeRes:
+ xdr_free( xdr_ObjectTypeRes, objp );
+ break;
+ case ntxdr_GetTypeStructureRes:
+ xdr_free( xdr_GetTypeStructureRes, objp );
+ break;
+ case ntxdr_GetElementRes:
+ xdr_free( xdr_GetElementRes, objp );
+ break;
+ case ntxdr_ServerStatRes:
+ xdr_free( xdr_ServerStatRes, objp );
+ break;
+ default:
+ printf( "Error: xdr_free of a unknown type." );
+ }
+}
+
+
+
+// Looks like ntohl and htonl are missing in all libs on our NT versions...
+u_long PASCAL FAR ntohl(u_long x)
+{
+ return (u_long)((x & 0xff) << 24) | ((x & 0xff00) << 8) | ((x >> 8) & 0xff00) | ((x >> 24) & 0xff);
+}
+
+u_long PASCAL FAR htonl(u_long x)
+{
+ // swapping the endianness works either way...
+ return ntohl(x);
+}
diff --git a/clientcomm/clnt_control.h b/clientcomm/clnt_control.h
new file mode 100644
index 0000000..cff1c07
--- /dev/null
+++ b/clientcomm/clnt_control.h
@@ -0,0 +1,46 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#include <rpc/rpc.h>
+
+
+void client_control(CLIENT *cl, unsigned int rq, char *in);
+
+void client_destroy(CLIENT *cl);
+
+CLIENT* client_create(char *host, u_long prog, u_long vers, char *prot);
+
+typedef enum { ntxdr_ExecuteQueryRes,
+ ntxdr_ExecuteUpdateRes,
+ ntxdr_GetMDDRes,
+ ntxdr_GetTileRes,
+ ntxdr_GetCollRes,
+ ntxdr_GetCollOIdsRes,
+ ntxdr_OIdRes,
+ ntxdr_ObjectTypeRes,
+ ntxdr_GetTypeStructureRes,
+ ntxdr_GetElementRes,
+ ntxdr_ServerStatRes
+ } ntxdr_Type;
+
+void xdrfree( ntxdr_Type xdrType, char *objp );
diff --git a/clientcomm/clnt_control/clnt_control.c b/clientcomm/clnt_control/clnt_control.c
new file mode 100644
index 0000000..299b687
--- /dev/null
+++ b/clientcomm/clnt_control/clnt_control.c
@@ -0,0 +1,100 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#include "clientcomm/clnt_control/clnt_control.h"
+#include "clientcomm/rpcif.h"
+
+#include <stdio.h>
+
+void client_control(CLIENT *cl, unsigned int rq, char *in)
+{
+ clnt_control(cl, rq, in);
+}
+
+void client_destroy(CLIENT *cl)
+{
+ clnt_destroy(cl);
+}
+
+CLIENT* client_create(char *host, u_long prog, u_long vers, char *prot)
+{
+ return clnt_create(host, prog, vers, prot);
+}
+
+extern void xdr_free(xdrproc_t proc, char *objp );
+
+void xdrfree( ntxdr_Type xdrType, char *objp )
+{
+ switch( xdrType )
+ {
+ case ntxdr_ExecuteQueryRes:
+ xdr_free( xdr_ExecuteQueryRes, objp );
+ break;
+ case ntxdr_ExecuteUpdateRes:
+ xdr_free( xdr_ExecuteUpdateRes, objp );
+ break;
+ case ntxdr_GetMDDRes:
+ xdr_free( xdr_GetMDDRes, objp );
+ break;
+ case ntxdr_GetTileRes:
+ xdr_free( xdr_GetTileRes, objp );
+ break;
+ case ntxdr_GetCollRes:
+ xdr_free( xdr_GetCollRes, objp );
+ break;
+ case ntxdr_GetCollOIdsRes:
+ xdr_free( xdr_GetCollOIdsRes, objp );
+ break;
+ case ntxdr_OIdRes:
+ xdr_free( xdr_OIdRes, objp );
+ break;
+ case ntxdr_ObjectTypeRes:
+ xdr_free( xdr_ObjectTypeRes, objp );
+ break;
+ case ntxdr_GetTypeStructureRes:
+ xdr_free( xdr_GetTypeStructureRes, objp );
+ break;
+ case ntxdr_GetElementRes:
+ xdr_free( xdr_GetElementRes, objp );
+ break;
+ case ntxdr_ServerStatRes:
+ xdr_free( xdr_ServerStatRes, objp );
+ break;
+ default:
+ printf( "Error: xdr_free of a unknown type." );
+ }
+}
+
+
+
+// Looks like ntohl and htonl are missing in all libs on our NT versions...
+u_long PASCAL FAR ntohl(u_long x)
+{
+ return (u_long)((x & 0xff) << 24) | ((x & 0xff00) << 8) | ((x >> 8) & 0xff00) | ((x >> 24) & 0xff);
+}
+
+u_long PASCAL FAR htonl(u_long x)
+{
+ // swapping the endianness works either way...
+ return ntohl(x);
+}
diff --git a/clientcomm/clnt_control/clnt_control.h b/clientcomm/clnt_control/clnt_control.h
new file mode 100644
index 0000000..cff1c07
--- /dev/null
+++ b/clientcomm/clnt_control/clnt_control.h
@@ -0,0 +1,46 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#include <rpc/rpc.h>
+
+
+void client_control(CLIENT *cl, unsigned int rq, char *in);
+
+void client_destroy(CLIENT *cl);
+
+CLIENT* client_create(char *host, u_long prog, u_long vers, char *prot);
+
+typedef enum { ntxdr_ExecuteQueryRes,
+ ntxdr_ExecuteUpdateRes,
+ ntxdr_GetMDDRes,
+ ntxdr_GetTileRes,
+ ntxdr_GetCollRes,
+ ntxdr_GetCollOIdsRes,
+ ntxdr_OIdRes,
+ ntxdr_ObjectTypeRes,
+ ntxdr_GetTypeStructureRes,
+ ntxdr_GetElementRes,
+ ntxdr_ServerStatRes
+ } ntxdr_Type;
+
+void xdrfree( ntxdr_Type xdrType, char *objp );
diff --git a/clientcomm/rpcclientcomm.cc b/clientcomm/rpcclientcomm.cc
new file mode 100644
index 0000000..206e7ce
--- /dev/null
+++ b/clientcomm/rpcclientcomm.cc
@@ -0,0 +1,3672 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: rpcclientcomm.cc
+ *
+ * MODULE: clientcomm
+ * CLASS: RpcClientComm
+ *
+ * PURPOSE:
+ *
+ * COMMENTS:
+ * None
+*/
+
+#include "mymalloc/mymalloc.h"
+
+static const char rcsid[] = "@(#)clientcomm, RpcClientComm: $Id: rpcclientcomm.cc,v 1.11 2005/09/09 16:16:29 rasdev Exp $";
+
+#include <openssl/evp.h>
+
+#include <stdio.h>
+#include <math.h> // for ceil(), log(), exp()
+
+#include <vector>
+#include <iostream>
+#include <fstream>
+#include <string>
+using namespace std;
+
+#ifdef __VISUALC__
+ #include <windows.h> // for the required defines and stuff
+ #include <mmsystem.h> // for setEventTimer and killEventTimer
+ #include <winbase.h>
+#else
+
+ #if defined(DECALPHA) || defined(LINUX)
+
+ #if !defined(_XOPEN_SOURCE_EXTENDED)
+ #define _XOPEN_SOURCE_EXTENDED // for gethostid
+ #endif
+
+ #endif
+
+ #include <unistd.h> // for sleep(), alarm()
+ #include <signal.h> // for signal()
+#endif
+#ifdef __VISUALC__ // do this ONLY for VisualC! Not for EARLY_TEMPLATE
+ #define __EXECUTABLE__
+#endif
+
+#if (defined(__VISUALC__) || defined(CYGWIN))
+ extern "C"
+ {
+ #include "clientcomm/clnt_control/clnt_control.h"
+ }
+# define XDRFREE(proc, res) xdrfree( ntxdr_##proc, (char*)res )
+#else
+# define XDRFREE(proc, res) xdr_free( (xdrproc_t)xdr_##proc, (char*)res )
+#endif
+
+#include "rasodmg/transaction.hh"
+#include "rasodmg/database.hh"
+#include "rasodmg/iterator.hh"
+#include "rasodmg/set.hh"
+#include "rasodmg/ref.hh"
+#include "rasodmg/storagelayout.hh"
+#include "rasodmg/tiling.hh"
+
+#include "raslib/minterval.hh"
+#include "raslib/rmdebug.hh"
+#include "raslib/rminit.hh"
+#include "raslib/primitivetype.hh"
+#include "raslib/complextype.hh"
+#include "raslib/structuretype.hh"
+#include "raslib/primitive.hh"
+#include "raslib/complex.hh"
+#include "raslib/structure.hh"
+#include "raslib/endian.hh"
+#include "raslib/parseparams.hh"
+// for transfer compression
+#include "compression/tilecompression.hh"
+
+#include "clientcomm/rpcclientcomm.hh"
+
+
+#ifdef __VISUALC__ // do this ONLY for VisualC! Not for EARLY_TEMPLATE
+ #undef __EXECUTABLE__
+#endif
+
+RMINITGLOBALS('C')
+
+#include<stdio.h>
+#include<errno.h>
+#include<stdlib.h>
+#include<unistd.h>
+#include<sys/types.h>
+#include<sys/socket.h>
+#include<netinet/in.h>
+#include<netdb.h>
+#include<iostream>
+#include<string.h>
+
+#define ALIVEINTERVAL 60
+#define TAWRITEWAITINTERVAL 10
+
+#ifdef SOLARIS
+extern "C" void aliveSignal( int );
+#endif
+#ifdef __VISUALC__
+void CALLBACK TimerProc(UINT wTimerID, UINT wMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
+#else
+void aliveSignal( int )
+#endif
+{
+ if(!RMInit::noTimeOut) {
+ // get the current clientcomm object
+ ClientComm* myComm = r_Database::actual_database->getComm();
+ if( myComm == 0 )
+ {
+ RMInit::logOut << "RpcClientComm: Error: RpcClientComm object only usable within r_Database object." << endl;
+ return;
+ }
+
+ myComm->triggerAliveSignal();
+ }
+}
+
+
+RpcClientComm::RpcClientComm( const char* _rasmgrHost, int _rasmgrPort ) throw( r_Error )
+: binding_h(NULL),
+ clientID(0),
+#ifdef __VISUALC__
+ UINT timerid(0),
+#endif
+ status(0),
+ serverUp(0),
+ rpcActive(0),
+ aliveSignalRemaining(0),
+ endianServer(0),
+ endianClient(0),
+ serverRPCversion(0),
+ transferFormat(r_Array),
+ storageFormat(r_Array),
+ transferFormatParams(NULL),
+ storageFormatParams(NULL),
+ clientParams(NULL),
+ serverCompresses(0),
+ exactFormat(0),
+ RPCIF_PARA(0)
+{
+ clientParams = new r_Parse_Params();
+ clientParams->add("compserver", &serverCompresses, r_Parse_Params::param_type_int);
+ clientParams->add("exactformat", &exactFormat, r_Parse_Params::param_type_int);
+
+ endianClient = (int)r_Endian::get_endianness();
+
+ this->rasmgrHost=(char*)_rasmgrHost;
+ this->rasmgrPort=_rasmgrPort;
+ serverHost[0]=0;
+ capability[0]=0;
+ strcpy(identificationString,"rasguest:8e70a429be359b6dace8b5b2500dedb0"); // this is MD5("rasguest");
+}
+
+static int rpcRetryCounter = 0;
+
+RpcClientComm::~RpcClientComm() throw()
+{
+ disconnectFromServer();
+ delete clientParams;
+ clientParams = NULL;
+}
+
+bool RpcClientComm::effectivTypeIsRNP() throw()
+ {
+ return false;
+ }
+
+void
+RpcClientComm::executeQuery( const r_OQL_Query& query, r_Set< r_Ref_Any >& result )
+ throw( r_Error )
+{
+ if(binding_h == NULL) {
+ RMInit::logOut << endl << "RpcClientComm::executeQuery(query, result) ERROR: CONNECTION TO SERVER ALREADY CLOSED" << endl << endl;
+ throw r_Error(CONNECTIONCLOSED);
+ }
+
+ char* queryString;
+
+ // Get the query string by using a backdoor function of r_OQL_Query
+ queryString = (char*)query.get_query();
+
+ // Finally, this is the remote procedure which sends the query and receives a
+ // client Id under which the client can access the r_Marrays he is to receive
+ ExecuteQueryParams* params = new ExecuteQueryParams;
+ ExecuteQueryRes* res;
+ params->clientID = clientID;
+ params->query = queryString;
+
+ setRPCActive();
+ rpcRetryCounter = 0;
+ do
+ {
+ res = rpcexecutequery_1( params, binding_h );
+
+ if( !res )
+ {
+ RMInit::logOut << endl << "WARNING: RPC NULL POINTER (rpcexecutequery_1)" << endl << endl;
+ sleep(RMInit::clientcommSleep);
+ }
+ if (rpcRetryCounter > RMInit::clientcommMaxRetry)
+ {
+ RMInit::logOut << "RPC call 'rpcexecutequery' failed" << endl;
+ throw r_Error(CLIENTCOMMUICATIONFAILURE);
+ }
+ rpcRetryCounter++;
+ }while( res == 0 );
+ setRPCInactive();
+
+ delete params;
+
+ if( res->status == 0 )
+ {
+ result.set_type_by_name( res->typeName );
+ result.set_type_structure( res->typeStructure );
+
+ XDRFREE(ExecuteQueryRes, res);
+
+ getMDDCollection( result, 1 );
+ }
+ else if( res->status == 1 )
+ {
+ result.set_type_by_name( res->typeName );
+ result.set_type_structure( res->typeStructure );
+
+ XDRFREE(ExecuteQueryRes, res);
+
+ getElementCollection( result );
+ }
+ else if (res->status == 2)
+ {
+ // Result collection is empty and nothing has to be got.
+ XDRFREE(ExecuteQueryRes, res);
+ }
+ else if( res->status == 4 || res->status == 5 )
+ {
+ r_Equery_execution_failed err( res->errorNo, res->lineNo, res->columnNo, res->token );
+ XDRFREE(ExecuteQueryRes, res);
+ throw err;
+ }
+ else
+ {
+ r_Error err;
+
+ if( res->status == 3 )
+ err = r_Error( r_Error::r_Error_ClientUnknown );
+ else
+ err = r_Error( r_Error::r_Error_TransferFailed );
+
+ XDRFREE(ExecuteQueryRes, res);
+
+ throw err;
+ }
+}
+
+
+
+void
+RpcClientComm::executeQuery( const r_OQL_Query& query )
+ throw( r_Error )
+{
+ RMDBGENTER(2, RMDebug::module_clientcomm, "RpcClientComm", "executeQuery(query)")
+
+ if(binding_h == NULL) {
+ RMInit::logOut << endl << "RpcClientComm::executeQuery(query) ERROR: CONNECTION TO SERVER ALREADY CLOSED" << endl << endl;
+ throw r_Error(CONNECTIONCLOSED);
+ }
+
+ // update -> check for read_only transaction
+ if( r_Transaction::actual_transaction == 0 ||
+ r_Transaction::actual_transaction->get_mode() == r_Transaction::read_only )
+ {
+ r_Error err = r_Error( r_Error::r_Error_TransactionReadOnly );
+ throw err;
+ }
+
+ unsigned short rpcStatus;
+ unsigned short* rpcStatusPtr = 0;
+
+ //
+ // Send MDD constants to the server.
+ //
+ if( query.get_constants() )
+ {
+ r_Set< r_GMarray* >* mddConstants = (r_Set< r_GMarray* >*)query.get_constants();
+
+ setRPCActive();
+ rpcRetryCounter = 0;
+ do
+ {
+ rpcStatusPtr = rpcinitexecuteupdate_1( &clientID, binding_h );
+
+ if( !rpcStatusPtr )
+ {
+ RMInit::logOut << endl << "WARNING: RPC NULL POINTER (rpcinitexecuteupdate_1)" << endl << endl;
+ sleep(RMInit::clientcommSleep);
+ }
+ if (rpcRetryCounter > RMInit::clientcommMaxRetry)
+ {
+ RMInit::logOut << "RPC call 'rpcexecuteupdate' failed" << endl;
+ throw r_Error(CLIENTCOMMUICATIONFAILURE);
+ }
+ rpcRetryCounter++;
+ }while( rpcStatusPtr == 0 );
+ rpcStatus = *rpcStatusPtr;
+ setRPCInactive();
+
+ r_Iterator<r_GMarray*> iter = mddConstants->create_iterator();
+
+ for( iter.reset(); iter.not_done(); iter++ )
+ {
+ r_GMarray* mdd = *iter;
+ const r_Base_Type* baseType = mdd->get_base_type_schema();
+
+ if( mdd )
+ {
+ // initiate composition of MDD at server side
+ InsertTransMDDParams* params = new InsertTransMDDParams;
+ params->clientID = clientID;
+ params->collName = strdup(""); // not used
+ params->domain = mdd->spatial_domain().get_string_representation();
+ params->typeLength = mdd->get_type_length();
+ params->typeName = (char*)mdd->get_type_name();
+
+ if(binding_h == NULL) {
+ RMInit::logOut << endl << "RpcClientComm::executeQuery(query) ERROR: CONNECTION TO SERVER ALREADY CLOSED" << endl << endl;
+ throw r_Error(CONNECTIONCLOSED);
+ }
+
+ setRPCActive();
+ rpcRetryCounter = 0;
+ do
+ {
+ rpcStatusPtr = rpcstartinserttransmdd_1( params, binding_h );
+
+ if( !rpcStatusPtr )
+ {
+ RMInit::logOut << endl << "WARNING: RPC NULL POINTER (rpcinserttransmdd_1)" << endl << endl;
+ sleep(RMInit::clientcommSleep);
+ }
+ if (rpcRetryCounter > RMInit::clientcommMaxRetry)
+ {
+ RMInit::logOut << "RPC call 'rpcexecutequery' failed" << endl;
+ throw r_Error(CLIENTCOMMUICATIONFAILURE);
+ }
+ rpcRetryCounter++;
+ }while( rpcStatusPtr == 0 );
+ rpcStatus = *rpcStatusPtr;
+ setRPCInactive();
+
+ free( params->domain );
+ free( params->collName );
+ delete params;
+
+ if( rpcStatus > 0 )
+ {
+ r_Error err;
+
+ switch( rpcStatus )
+ {
+ case 2:
+ err = r_Error( r_Error::r_Error_DatabaseClassUndefined );
+ break;
+ case 3:
+ err = r_Error( r_Error::r_Error_TypeInvalid );
+ break;
+ default:
+ err = r_Error( r_Error::r_Error_TransferFailed );
+ }
+ RMInit::logOut << "Error: rpcinitmdd() - " << err.what() << endl;
+ RMDBGEXIT(2, RMDebug::module_clientcomm, "RpcClientComm", "executeQuery(query) error occured")
+ throw err;
+ }
+
+ r_Set< r_GMarray* >* bagOfTiles;
+
+
+ bagOfTiles = mdd->get_storage_layout()->decomposeMDD( mdd );
+
+ RMDBGMIDDLE(2, RMDebug::module_clientcomm, "RpcClientComm", "decomposing into " << bagOfTiles->cardinality() << " tiles");
+
+ r_Iterator< r_GMarray* > iter2 = bagOfTiles->create_iterator();
+ r_GMarray *origTile;
+ iter2.reset();
+
+ while( iter2.not_done() )
+ {
+ RPCMarray* rpcMarray;
+
+ origTile = *iter2;
+
+ // advance iter here to determine if this is the last call (not_done())
+ iter2.advance();
+
+ RMDBGMIDDLE(2, RMDebug::module_clientcomm, "RpcClientComm", "inserting Tile with domain " << origTile->spatial_domain() << ", " << origTile->spatial_domain().cell_count() * origTile->get_type_length() << " bytes")
+
+ getMarRpcRepresentation( origTile, rpcMarray, mdd->get_storage_layout()->get_storage_format(), baseType );
+
+ InsertTileParams* params2 = new InsertTileParams;
+ params2->clientID = clientID;
+ params2->isPersistent = 0;
+ params2->marray = rpcMarray;
+
+ if(binding_h == NULL) {
+ RMInit::logOut << endl << "RpcClientComm::executeQuery(query) ERROR: CONNECTION TO SERVER ALREADY CLOSED" << endl << endl;
+ throw r_Error(CONNECTIONCLOSED);
+ }
+
+ setRPCActive();
+ rpcRetryCounter = 0;
+ do
+ {
+ rpcStatusPtr = rpcinserttile_1( params2, binding_h );
+
+ if( !rpcStatusPtr )
+ {
+ RMInit::logOut << endl << "WARNING: RPC NULL POINTER (rpcinserttile_1)" << endl << endl;
+ sleep(RMInit::clientcommSleep);
+ }
+ if (rpcRetryCounter > RMInit::clientcommMaxRetry)
+ {
+ RMInit::logOut << "RPC call 'rpcinserttile' failed" << endl;
+ throw r_Error(CLIENTCOMMUICATIONFAILURE);
+ }
+ rpcRetryCounter++;
+ }while( rpcStatusPtr == 0 );
+ rpcStatus = *rpcStatusPtr;
+RMDBGIF(20, RMDebug::module_clientcomm, "WAITAFTERSENDTILE", \
+ RMInit::dbgOut << "Waiting 10 sec after send tile\n" << std::endl; \
+ sleep(10); \
+ RMInit::dbgOut << "Continue now\n" << std::endl; );
+ setRPCInactive();
+
+ // free rpcMarray structure (rpcMarray->data.confarray_val is freed somewhere else)
+ freeMarRpcRepresentation( origTile, rpcMarray );
+ delete params2;
+
+ // delete current tile (including data block)
+ delete origTile;
+
+ if( rpcStatus > 0 )
+ {
+ RMInit::logOut << "Error: rpctransfertile() - general" << endl;
+ RMDBGEXIT(2, RMDebug::module_clientcomm, "RpcClientComm", "executeQuery() error occured")
+ throw r_Error( r_Error::r_Error_TransferFailed );
+ }
+
+ RMDBGMIDDLE(2, RMDebug::module_clientcomm, "RpcClientComm", "OK")
+ }
+
+ EndInsertMDDParams* params3 = new EndInsertMDDParams;
+ params3->clientID = clientID;
+ params3->isPersistent = 0;
+
+ if(binding_h == NULL) {
+ RMInit::logOut << endl << "RpcClientComm::executeQuery(query) ERROR: CONNECTION TO SERVER ALREADY CLOSED" << endl << endl;
+ throw r_Error(CONNECTIONCLOSED);
+ }
+
+ setRPCActive();
+ rpcRetryCounter = 0;
+ do
+ {
+ rpcStatusPtr = rpcendinsertmdd_1( params3, binding_h );
+
+ if( !rpcStatusPtr )
+ {
+ RMInit::logOut << endl << "WARNING: RPC NULL POINTER (rpcendinsertmdd_1)" << endl << endl;
+ sleep(RMInit::clientcommSleep);
+ }
+ if (rpcRetryCounter > RMInit::clientcommMaxRetry)
+ {
+ RMInit::logOut << "RPC call 'rpcinsertmdd' failed" << endl;
+ throw r_Error(CLIENTCOMMUICATIONFAILURE);
+ }
+ rpcRetryCounter++;
+ }while( rpcStatusPtr == 0 );
+ rpcStatus = *rpcStatusPtr;
+ setRPCInactive();
+
+ delete params3;
+
+ // delete transient data
+ bagOfTiles->remove_all();
+ delete bagOfTiles;
+ }
+ }
+ }
+
+ //
+ // Send the update query.
+ //
+ ExecuteQueryParams* params = new ExecuteQueryParams;
+ ExecuteUpdateRes* res;
+ params->clientID = clientID;
+ params->query = (char*)query.get_query();
+
+ if(binding_h == NULL) {
+ RMInit::logOut << endl << "RpcClientComm::executeQuery(query) ERROR: CONNECTION TO SERVER ALREADY CLOSED" << endl << endl;
+ throw r_Error(CONNECTIONCLOSED);
+ }
+
+ setRPCActive();
+ rpcRetryCounter = 0;
+ do
+ {
+ res = rpcexecuteupdate_1( params, binding_h );
+
+ if( !res )
+ {
+ RMInit::logOut << endl << "WARNING: RPC NULL POINTER (rpcexecuteupdate_1)" << endl << endl;
+ sleep(RMInit::clientcommSleep);
+ }
+ if (rpcRetryCounter > RMInit::clientcommMaxRetry)
+ {
+ RMInit::logOut << "RPC call 'rpcexecuteupdate' failed" << endl;
+ throw r_Error(CLIENTCOMMUICATIONFAILURE);
+ }
+ rpcRetryCounter++;
+ }while( res == 0 );
+ setRPCInactive();
+
+ delete params;
+
+ rpcStatus = res->status;
+
+ if( rpcStatus == 2 || rpcStatus == 3 )
+ {
+ r_Equery_execution_failed err( res->errorNo, res->lineNo, res->columnNo, res->token );
+
+ XDRFREE(ExecuteUpdateRes, res);
+
+ RMDBGEXIT(2, RMDebug::module_clientcomm, "RpcClientComm", "executeQuery() error occured")
+ throw err;
+ }
+
+ XDRFREE(ExecuteUpdateRes, res);
+
+ if( rpcStatus == 1 || rpcStatus > 3 )
+ {
+ r_Error err;
+
+ if( rpcStatus == 1 )
+ err = r_Error( r_Error::r_Error_ClientUnknown );
+ else
+ err = r_Error( r_Error::r_Error_TransferFailed );
+
+ RMDBGEXIT(2, RMDebug::module_clientcomm, "RpcClientComm", "executeQuery() error occured")
+ throw err;
+ }
+ RMDBGEXIT(2, RMDebug::module_clientcomm, "RpcClientComm", "executeQuery()")
+}
+
+
+
+void
+RpcClientComm::insertColl( const char* collName, const char* typeName, const r_OId& oid )
+ throw( r_Error )
+{
+ if(binding_h == NULL) {
+ RMInit::logOut << endl << "RpcClientComm::insertColl(collName, typeName, oid ) ERROR: CONNECTION TO SERVER ALREADY CLOSED" << endl << endl;
+ throw r_Error(CONNECTIONCLOSED);
+ }
+
+ // update -> check for read_only transaction
+ if( r_Transaction::actual_transaction == 0 ||
+ r_Transaction::actual_transaction->get_mode() == r_Transaction::read_only )
+ {
+ r_Error err = r_Error( r_Error::r_Error_TransactionReadOnly );
+ throw err;
+ }
+
+ unsigned short rpcStatus;
+ unsigned short* rpcStatusPtr = 0;
+
+ InsertCollParams* params = new InsertCollParams;
+ params->clientID = clientID;
+ params->collName = (char*)collName;
+ params->typeName = (char*)typeName;
+ params->oid = (char*)oid.get_string_representation();
+
+ setRPCActive();
+ rpcRetryCounter = 0;
+ do
+ {
+ rpcStatusPtr = rpcinsertcoll_1( params, binding_h );
+
+ if( !rpcStatusPtr )
+ {
+ RMInit::logOut << endl << "WARNING: RPC NULL POINTER (rpcinsertcoll_1)" << endl << endl;
+ sleep(RMInit::clientcommSleep);
+ }
+ if (rpcRetryCounter > RMInit::clientcommMaxRetry)
+ {
+ RMInit::logOut << "RPC call 'rpcinsertcoll' failed" << endl;
+ throw r_Error(CLIENTCOMMUICATIONFAILURE);
+ }
+ rpcRetryCounter++;
+ }while( rpcStatusPtr == 0 );
+ rpcStatus = *rpcStatusPtr;
+ setRPCInactive();
+
+ delete params;
+
+ if( rpcStatus > 0 )
+ {
+ r_Error err;
+
+ switch( rpcStatus )
+ {
+ case 1:
+ err = r_Error( r_Error::r_Error_ClientUnknown );
+ break;
+ case 2:
+ err = r_Error( r_Error::r_Error_DatabaseClassUndefined );
+ break;
+ case 3:
+ err = r_Error( r_Error::r_Error_NameNotUnique );
+ break;
+ default:
+ err = r_Error( r_Error::r_Error_General );
+ }
+ RMInit::logOut << "Error: rpcCreateMDDCollection() - " << err.what() << endl;
+ throw err;
+ }
+}
+
+
+
+void
+RpcClientComm::deleteCollByName( const char* collName )
+ throw( r_Error )
+{
+ if(binding_h == NULL) {
+ RMInit::logOut << endl << "RpcClientComm::deleteCollByName(collName) ERROR: CONNECTION TO SERVER ALREADY CLOSED" << endl << endl;
+ throw r_Error(CONNECTIONCLOSED);
+ }
+
+ // update -> check for read_only transaction
+ if( r_Transaction::actual_transaction == 0 ||
+ r_Transaction::actual_transaction->get_mode() == r_Transaction::read_only )
+ {
+ r_Error err = r_Error( r_Error::r_Error_TransactionReadOnly );
+ throw err;
+ }
+
+ unsigned short rpcStatus;
+ unsigned short* rpcStatusPtr=0;
+
+ NameSpecParams* params = new NameSpecParams;
+ params->clientID = clientID;
+ params->name = (char*)collName;
+
+ setRPCActive();
+ rpcRetryCounter = 0;
+ do
+ {
+ rpcStatusPtr = rpcdeletecollbyname_1( params, binding_h );
+
+ if( !rpcStatusPtr )
+ {
+ RMInit::logOut << endl << "WARNING: RPC NULL POINTER (rpcdeletecollbyname_1)" << endl << endl;
+ sleep(RMInit::clientcommSleep);
+ }
+ if (rpcRetryCounter > RMInit::clientcommMaxRetry)
+ {
+ RMInit::logOut << "RPC call 'rpcdeletecollbyname' failed" << endl;
+ throw r_Error(CLIENTCOMMUICATIONFAILURE);
+ }
+ rpcRetryCounter++;
+ }while( rpcStatusPtr == 0 );
+ rpcStatus = *rpcStatusPtr;
+ setRPCInactive();
+
+ delete params;
+
+ if( rpcStatus > 0 )
+ {
+ r_Error err;
+
+ switch( rpcStatus )
+ {
+ case 1:
+ err = r_Error( r_Error::r_Error_ClientUnknown );
+ break;
+ case 2:
+ err = r_Error( r_Error::r_Error_ObjectUnknown );
+ break;
+ default:
+ err = r_Error( r_Error::r_Error_General );
+ }
+ RMInit::logOut << "Error: rpcInsertMDD() - " << err.what() << endl;
+ throw err;
+ }
+}
+
+
+
+void
+RpcClientComm::deleteObjByOId( const r_OId& oid )
+ throw( r_Error )
+{
+ if(binding_h == NULL) {
+ RMInit::logOut << endl << "RpcClientComm::deleteObjectByOId(oid) ERROR: CONNECTION TO SERVER ALREADY CLOSED" << endl << endl;
+ throw r_Error(CONNECTIONCLOSED);
+ }
+
+ // update -> check for read_only transaction
+ if( r_Transaction::actual_transaction == 0 ||
+ r_Transaction::actual_transaction->get_mode() == r_Transaction::read_only )
+ {
+ r_Error err = r_Error( r_Error::r_Error_TransactionReadOnly );
+ throw err;
+ }
+
+ unsigned short rpcStatus;
+ unsigned short* rpcStatusPtr;
+
+ OIdSpecParams* params = new OIdSpecParams;
+ params->clientID = clientID;
+ params->oid = (char*) oid.get_string_representation();
+
+ setRPCActive();
+ rpcRetryCounter = 0;
+ do
+ {
+ rpcStatusPtr = rpcdeleteobjbyoid_1( params, binding_h );
+
+ if( !rpcStatusPtr )
+ {
+ RMInit::logOut << endl << "WARNING: RPC NULL POINTER (rpcdeleteobjbyoid_1)" << endl << endl;
+ sleep(RMInit::clientcommSleep);
+ }
+ if (rpcRetryCounter > RMInit::clientcommMaxRetry)
+ {
+ RMInit::logOut << "RPC call 'rpcdeleteobjbyoid' failed" << endl;
+ throw r_Error(CLIENTCOMMUICATIONFAILURE);
+ }
+ rpcRetryCounter++;
+ }while( rpcStatusPtr == 0 );
+ rpcStatus = *rpcStatusPtr;
+ setRPCInactive();
+ delete params;
+
+ if( rpcStatus > 0 )
+ {
+ r_Error err;
+
+ switch( rpcStatus )
+ {
+ case 1:
+ err = r_Error( r_Error::r_Error_ClientUnknown );
+ break;
+ case 2:
+ err = r_Error( r_Error::r_Error_ObjectUnknown );
+ break;
+ default:
+ err = r_Error( r_Error::r_Error_General );
+ }
+ RMInit::logOut << "Error: rpcInsertMDD() - " << err.what() << endl;
+ throw err;
+ }
+}
+
+
+
+void
+RpcClientComm::removeObjFromColl( const char* collName, const r_OId& oid )
+ throw( r_Error )
+{
+ if(binding_h == NULL) {
+ RMInit::logOut << endl << "RpcClientComm::removeObjFromColl(collName, oid) ERROR: CONNECTION TO SERVER ALREADY CLOSED" << endl << endl;
+ throw r_Error(CONNECTIONCLOSED);
+ }
+
+ // update -> check for read_only transaction
+ if( r_Transaction::actual_transaction == 0 ||
+ r_Transaction::actual_transaction->get_mode() == r_Transaction::read_only )
+ {
+ r_Error err = r_Error( r_Error::r_Error_TransactionReadOnly );
+ throw err;
+ }
+
+ unsigned short rpcStatus;
+ unsigned short* rpcStatusPtr;
+
+ RemoveObjFromCollParams* params = new RemoveObjFromCollParams;
+ params->clientID = clientID;
+ params->collName = (char*) collName;
+ params->oid = (char*) oid.get_string_representation();
+
+ setRPCActive();
+ rpcRetryCounter = 0;
+ do
+ {
+ rpcStatusPtr = rpcremoveobjfromcoll_1( params, binding_h );
+
+ if( !rpcStatusPtr )
+ {
+ RMInit::logOut << endl << "WARNING: RPC NULL POINTER (rpcremoveobjfromcoll_1)" << endl << endl;
+ sleep(RMInit::clientcommSleep);
+ }
+ if (rpcRetryCounter > RMInit::clientcommMaxRetry)
+ {
+ RMInit::logOut << "RPC call 'rpcremoveobjfromcoll' failed" << endl;
+ throw r_Error(CLIENTCOMMUICATIONFAILURE);
+ }
+ rpcRetryCounter++;
+ }while( rpcStatusPtr == 0 );
+ rpcStatus = *rpcStatusPtr;
+ setRPCInactive();
+
+ delete params;
+
+ if( rpcStatus > 0 )
+ {
+ r_Error err;
+
+ switch( rpcStatus )
+ {
+ case 1:
+ err = r_Error( r_Error::r_Error_ClientUnknown );
+ break;
+ case 2:
+ case 3:
+ err = r_Error( r_Error::r_Error_ObjectUnknown );
+ break;
+ default:
+ err = r_Error( r_Error::r_Error_General );
+ }
+ RMInit::logOut << "Error: rpcInsertMDD() - " << err.what() << endl;
+ throw err;
+ }
+}
+
+
+
+void
+RpcClientComm::insertMDD( const char* collName, r_GMarray* mar )
+ throw( r_Error )
+{
+ RMDBGENTER(2, RMDebug::module_clientcomm, "RpcClientComm", "insertMDD(" << collName << ", marray)")
+
+ if(binding_h == NULL) {
+ RMInit::logOut << endl << "RpcClientComm::insertMDD(collName, mar) ERROR: CONNECTION TO SERVER ALREADY CLOSED" << endl << endl;
+ throw r_Error(CONNECTIONCLOSED);
+ }
+
+ // update -> check for read_only transaction
+ if( r_Transaction::actual_transaction == 0 ||
+ r_Transaction::actual_transaction->get_mode() == r_Transaction::read_only )
+ {
+ r_Error err = r_Error( r_Error::r_Error_TransactionReadOnly );
+ RMDBGEXIT(2, RMDebug::module_clientcomm, "RpcClientComm", "insertMDD(" << collName << ", marray) error")
+ throw err;
+ }
+
+ unsigned short rpcStatus;
+ unsigned short* rpcStatusPtr=0;
+ r_Minterval spatdom;
+ r_Bytes marBytes;
+ RPCMarray* rpcMarray;
+ r_Bytes tileSize = 0;
+
+ // get the spatial domain of the r_GMarray
+ spatdom = mar->spatial_domain();
+
+ // determine the amount of data to be transferred
+ marBytes = mar->get_array_size();
+
+ RMDBGMIDDLE(2, RMDebug::module_clientcomm, "RpcClientComm", "inserting MDD with domain " << spatdom << ", cell length " << mar->get_type_length() << ", " << marBytes << " bytes" )
+
+ const r_Base_Type* baseType = mar->get_base_type_schema();
+
+ // if the MDD is too large for being transfered as one block, it has to be
+ // divided in tiles
+ const r_Tiling* til = mar->get_storage_layout()->get_tiling();
+ r_Tiling_Scheme scheme = til->get_tiling_scheme();
+ if (scheme == r_NoTiling)
+ tileSize = RMInit::RMInit::clientTileSize;
+ else
+ //allowed because the only subclass of tiling without size is no tiling
+ tileSize = ((const r_Size_Tiling*)til)->get_tile_size();
+
+ if( RMInit::tiling && marBytes > tileSize )
+ {
+ // initiate composition of MDD at server side
+ InsertPersMDDParams* params = new InsertPersMDDParams;
+ params->clientID = clientID;
+ params->collName = (char*)collName;
+ params->domain = spatdom.get_string_representation();
+ params->typeLength = mar->get_type_length();
+ params->typeName = (char*)mar->get_type_name();
+ params->oid = (char*)mar->get_oid().get_string_representation();
+
+ setRPCActive();
+ rpcRetryCounter = 0;
+ do
+ {
+ rpcStatusPtr = rpcstartinsertpersmdd_1( params, binding_h );
+
+ if( !rpcStatusPtr )
+ {
+ RMInit::logOut << endl << "WARNING: RPC NULL POINTER (rpcstartinsertpersmdd_1)" << endl << endl;
+ sleep(RMInit::clientcommSleep);
+ }
+ if (rpcRetryCounter > RMInit::clientcommMaxRetry)
+ {
+ RMInit::logOut << "RPC call 'rpcstartinsertpersmdd' failed" << endl;
+ throw r_Error(CLIENTCOMMUICATIONFAILURE);
+ }
+ rpcRetryCounter++;
+ }while( rpcStatusPtr == 0 );
+ rpcStatus = *rpcStatusPtr;
+ setRPCInactive();
+
+ free( params->domain );
+ delete params;
+
+ if( rpcStatus > 0 )
+ {
+ r_Error err;
+
+ switch( rpcStatus )
+ {
+ case 2:
+ err = r_Error( r_Error::r_Error_DatabaseClassUndefined );
+ break;
+ case 3:
+ err = r_Error( r_Error::r_Error_CollectionElementTypeMismatch );
+ break;
+ case 4:
+ err = r_Error( r_Error::r_Error_TypeInvalid );
+ break;
+ default:
+ err = r_Error( r_Error::r_Error_TransferFailed );
+ }
+ RMInit::logOut << "Error: rpcInsertMDDObj() - " << err.what() << endl;
+ RMDBGEXIT(2, RMDebug::module_clientcomm, "RpcClientComm", "insertMDD(" << collName << ", marray) error")
+ throw err;
+ }
+
+ r_Set< r_GMarray* >* bagOfTiles;
+
+
+ bagOfTiles = mar->get_storage_layout()->decomposeMDD( mar );
+
+ RMDBGMIDDLE(2, RMDebug::module_clientcomm, "RpcClientComm", "decomposing into " << bagOfTiles->cardinality() << " tiles")
+
+ r_Iterator< r_GMarray* > iter = bagOfTiles->create_iterator();
+ r_GMarray *origTile;
+ iter.reset();
+
+ while( iter.not_done() )
+ {
+ origTile = *iter;
+
+ // advance iter here to determine if this is the last call (not_done())
+ iter.advance();
+
+ RMDBGMIDDLE(2, RMDebug::module_clientcomm, "RpcClientComm", "inserting Tile with domain " << origTile->spatial_domain() << ", " << origTile->spatial_domain().cell_count() * origTile->get_type_length() << " bytes")
+
+ getMarRpcRepresentation( origTile, rpcMarray, mar->get_storage_layout()->get_storage_format(), baseType );
+
+ InsertTileParams* params2 = new InsertTileParams;
+ params2->clientID = clientID;
+ params2->isPersistent = 1;
+ params2->marray = rpcMarray;
+
+ if(binding_h == NULL) {
+ RMInit::logOut << endl << "RpcClientComm::insertMDD(collName, mar) ERROR: CONNECTION TO SERVER ALREADY CLOSED" << endl << endl;
+ throw r_Error(CONNECTIONCLOSED);
+ }
+
+ setRPCActive();
+ rpcRetryCounter = 0;
+ do
+ {
+ rpcStatusPtr = rpcinserttile_1( params2, binding_h );
+
+ if( !rpcStatusPtr )
+ {
+ RMInit::logOut << endl << "WARNING: RPC NULL POINTER (rpcinserttile_1)" << endl << endl;
+ sleep(RMInit::clientcommSleep);
+ }
+ if (rpcRetryCounter > RMInit::clientcommMaxRetry)
+ {
+ RMInit::logOut << "RPC call 'rpcinserttile' failed" << endl;
+ throw r_Error(CLIENTCOMMUICATIONFAILURE);
+ }
+ rpcRetryCounter++;
+ }while( rpcStatusPtr == 0 );
+ rpcStatus = *rpcStatusPtr;
+ setRPCInactive();
+
+ // free rpcMarray structure (rpcMarray->data.confarray_val is freed somewhere else)
+ freeMarRpcRepresentation( origTile, rpcMarray );
+ delete params2;
+
+ // delete current tile (including data block)
+ delete origTile;
+
+ if( rpcStatus > 0 )
+ {
+ RMInit::logOut << "Error: rpcInsertMDD() - general" << endl;
+ RMDBGEXIT(2, RMDebug::module_clientcomm, "RpcClientComm", "insertMDD(" << collName << ", marray) error")
+ throw r_Error( r_Error::r_Error_TransferFailed );
+ }
+
+ RMDBGMIDDLE(2, RMDebug::module_clientcomm, "RpcClientComm", "OK")
+ }
+
+ EndInsertMDDParams* params3 = new EndInsertMDDParams;
+ params3->clientID = clientID;
+ params3->isPersistent = 1;
+
+ if(binding_h == NULL) {
+ RMInit::logOut << endl << "RpcClientComm::insertMDD(collName, mar) ERROR: CONNECTION TO SERVER ALREADY CLOSED" << endl << endl;
+ throw r_Error(CONNECTIONCLOSED);
+ }
+
+ setRPCActive();
+ rpcRetryCounter = 0;
+ do
+ {
+ rpcStatusPtr = rpcendinsertmdd_1( params3, binding_h );
+
+ if( !rpcStatusPtr )
+ {
+ RMInit::logOut << endl << "WARNING: RPC NULL POINTER (rpcendinsertmdd_1)" << endl << endl;
+ sleep(RMInit::clientcommSleep);
+ }
+ if (rpcRetryCounter > RMInit::clientcommMaxRetry)
+ {
+ RMInit::logOut << "RPC call 'rpcendinsertmdd' failed" << endl;
+ throw r_Error(CLIENTCOMMUICATIONFAILURE);
+ }
+ rpcRetryCounter++;
+ }while( rpcStatusPtr == 0 );
+ rpcStatus = *rpcStatusPtr;
+ setRPCInactive();
+
+ delete params3;
+
+ // delete transient data
+ bagOfTiles->remove_all();
+ delete bagOfTiles;
+ }
+ else // begin: MDD is transferred in one piece
+ {
+ RMDBGMIDDLE(2, RMDebug::module_clientcomm, "RpcClientComm", ", one tile" )
+
+ getMarRpcRepresentation( mar, rpcMarray, mar->get_storage_layout()->get_storage_format(), baseType );
+
+ InsertMDDParams* params = new InsertMDDParams;
+ params->clientID = clientID;
+ params->collName = (char*)collName;
+ params->marray = rpcMarray;
+ params->typeName = (char*)mar->get_type_name();
+ params->oid = (char*)mar->get_oid().get_string_representation();
+
+ if(binding_h == NULL) {
+ RMInit::logOut << endl << "RpcClientComm::insertMDD(collName, mar) ERROR: CONNECTION TO SERVER ALREADY CLOSED" << endl << endl;
+ throw r_Error(CONNECTIONCLOSED);
+ }
+
+ setRPCActive();
+ rpcRetryCounter = 0;
+ do
+ {
+ rpcStatusPtr = rpcinsertmdd_1( params, binding_h );
+
+ if( !rpcStatusPtr )
+ {
+ RMInit::logOut << endl << "WARNING: RPC NULL POINTER (rpcinsertmdd_1)" << endl << endl;
+ sleep(RMInit::clientcommSleep);
+ }
+ if (rpcRetryCounter > RMInit::clientcommMaxRetry)
+ {
+ RMInit::logOut << "RPC call 'rpcinsertmdd' failed" << endl;
+ throw r_Error(CLIENTCOMMUICATIONFAILURE);
+ }
+ rpcRetryCounter++;
+ }while( rpcStatusPtr == 0 );
+ rpcStatus = *rpcStatusPtr;
+ setRPCInactive();
+
+ freeMarRpcRepresentation( mar, rpcMarray );
+ delete params;
+
+ RMDBGMIDDLE(2, RMDebug::module_clientcomm, "RpcClientComm", "ok" )
+
+ if( rpcStatus > 0 )
+ {
+ r_Error err;
+
+ switch( rpcStatus )
+ {
+ case 2:
+ err = r_Error( r_Error::r_Error_DatabaseClassUndefined );
+ break;
+ case 3:
+ err = r_Error( r_Error::r_Error_CollectionElementTypeMismatch );
+ break;
+ case 4:
+ err = r_Error( r_Error::r_Error_TypeInvalid );
+ break;
+ default:
+ err = r_Error( r_Error::r_Error_TransferFailed );
+ }
+ RMInit::logOut << "Error: rpcInsertMDD() - " << err.what() << endl;
+ throw err;
+ }
+
+ } // end: MDD i transferred in one piece
+}
+
+
+
+r_Data_Format
+RpcClientComm::doTransferDecompression( r_GMarray* tile, const r_Base_Type *type,
+ r_Data_Format fmt, unsigned long size )
+{
+
+ RMDBGENTER( 2, RMDebug::module_clientcomm, "RpcClientComm", "doTransferDecompression(...) tile dom:"
+ << tile->spatial_domain() << " array size:" << tile->get_array_size()
+ << " type size:" << tile->get_type_length());
+ if (fmt != r_Array)
+ {
+ r_Tile_Compression *engine = NULL;
+ char *newTileData = NULL;
+ r_Data_Format newFormat;
+
+ RMDBGMIDDLE( 2, RMDebug::module_clientcomm, "RpcClientComm", "doTransferDecompression(...) decompressing from "
+ << fmt << ", " << size << "bytes");
+
+ try
+ {
+ r_Storage_Man_CPP sman;
+ engine = r_Tile_Compression::create( fmt, tile->spatial_domain(), type );
+ engine->set_storage_handler(sman);
+ newTileData = (char*)(engine->decompress(tile->get_array(), size));
+ RMDBGMIDDLE( 2, RMDebug::module_clientcomm, "RpcClientComm",
+ "doTransferDecompression(...) decompression to " << engine->get_decomp_format() << " OK");
+ }
+ catch (r_Error &err)
+ {
+ RMDBGMIDDLE( 2, RMDebug::module_clientcomm, "RpcClientComm",
+ "doTransferDecompression(...) decompression to " << engine->get_decomp_format() << " FAILED");
+ RMInit::logOut << "RpcClientComm::doTransferDecompression() Error decompressing data, assuming raw" << endl;
+ }
+
+ newFormat = engine->get_decomp_format();
+
+ if (newTileData != NULL)
+ {
+ delete [] tile->get_array();
+ tile->set_array(newTileData);
+ tile->set_array_size(tile->spatial_domain().cell_count()*tile->get_type_length());
+ }
+ else
+ newFormat = fmt;
+
+ RMDBGMIDDLE( 2, RMDebug::module_clientcomm, "RpcClientComm", "doTransferDecompression(...) tile newFmt:"
+ << newFormat << " dom:" << tile->spatial_domain()
+ << " array size:" << tile->get_array_size()
+ << " type size:" << tile->get_type_length());
+
+ // ... also make sure the decoded format is really raw array data (r_Array)
+ if ((endianClient != endianServer) && (newFormat == r_Array))
+ {
+ // if compression engine already handles endianness we mustn't change again
+ if (!engine->converts_endianness()) {
+ RMDBGMIDDLE( 2, RMDebug::module_clientcomm, "RpcClientComm", "doTransferDecompression(...) for "
+ << fmt << " endianness changed from "
+ << (r_Endian::r_Endianness)endianServer << " to " << (r_Endian::r_Endianness) endianClient);
+ changeEndianness(tile, type);
+ }
+ }
+
+ if (engine != NULL)
+ delete engine;
+
+ RMDBGEXIT( 2, RMDebug::module_clientcomm, "RpcClientComm", "doTransferDecompression(...) tile fmt:" << newFormat);
+
+ return newFormat;
+ }
+
+ if (endianClient != endianServer) {
+ RMDBGMIDDLE( 2, RMDebug::module_clientcomm, "RpcClientComm", "doTransferDecompression(...) for "
+ << fmt << " endianness changed from "
+ << (r_Endian::r_Endianness)endianServer << " to " << (r_Endian::r_Endianness) endianClient);
+ changeEndianness(tile, type);
+ }
+
+ RMDBGEXIT( 2, RMDebug::module_clientcomm, "RpcClientComm", "doTransferDecompression(...) tile fmt:" << r_Array);
+ return r_Array;
+}
+
+r_Ref_Any
+RpcClientComm::getMDDByOId( const r_OId& oid )
+ throw( r_Error )
+{
+
+ if(binding_h == NULL) {
+ RMInit::logOut << endl << "RpcClientComm::getMDDByOId(oid) ERROR: CONNECTION TO SERVER ALREADY CLOSED" << endl << endl;
+ throw r_Error(CONNECTIONCLOSED);
+ }
+
+ RMDBGENTER(2, RMDebug::module_clientcomm, "RpcClientComm", "getMDDByOId(" << oid << ")")
+
+ r_Ref_Any mddResult;
+
+ r_GMarray* marray = 0;
+ unsigned short tileStatus = 0;
+ unsigned short rpcStatus = 0;
+ unsigned short* rpcStatusPtr = 0;
+
+ OIdSpecParams params;
+ GetMDDRes* thisResult = 0;
+ params.clientID = clientID;
+ params.oid = (char*)oid.get_string_representation();
+
+ setRPCActive();
+ rpcRetryCounter = 0;
+ do
+ {
+ thisResult = rpcgetmddbyoid_1( &params, binding_h );
+
+ if( !thisResult )
+ {
+ RMInit::logOut << endl << "WARNING: RPC NULL POINTER (rpcgetmddbyoid_1)" << endl << endl;
+ sleep(RMInit::clientcommSleep);
+ }
+ if (rpcRetryCounter > RMInit::clientcommMaxRetry)
+ {
+ RMInit::logOut << "RPC call 'rpcgetmddbyoid' failed" << endl;
+ throw r_Error(CLIENTCOMMUICATIONFAILURE);
+ }
+ rpcRetryCounter++;
+ }while( thisResult == 0 );
+ setRPCInactive();
+
+ rpcStatus = thisResult->status;
+
+ if( rpcStatus != 0 )
+ {
+ r_Error err;
+
+ switch( rpcStatus )
+ {
+ case 1:
+ err = r_Error( r_Error::r_Error_ClientUnknown );
+ break;
+ case 2:
+ case 3:
+ err = r_Error( r_Error::r_Error_ObjectUnknown );
+ break;
+ default:
+ err = r_Error( r_Error::r_Error_TransferFailed );
+ }
+
+ XDRFREE(GetMDDRes, thisResult);
+
+ RMDBGEXIT(2, RMDebug::module_clientcomm, "RpcClientComm", "failed")
+ throw err;
+ }
+
+ r_Ref< r_GMarray > mdd;
+ getMDDCore(mdd, thisResult, 0);
+ mddResult = mdd;
+
+ setRPCActive();
+RMDBGIF(20, RMDebug::module_clientcomm, "WAITENDTRANSFERSTART", \
+ RMInit::dbgOut << "Waiting 100 sec before end transfer\n" << std::endl; \
+ sleep(100); \
+ RMInit::dbgOut << "Continue now\n" << std::endl; );
+
+ if(binding_h == NULL) {
+ RMInit::logOut << endl << "RpcClientComm::getMDDByOId(oid) ERROR: CONNECTION TO SERVER ALREADY CLOSED" << endl << endl;
+ throw r_Error(CONNECTIONCLOSED);
+ }
+
+ rpcRetryCounter = 0;
+ do
+ {
+ rpcStatusPtr = rpcendtransfer_1( &clientID, binding_h );
+ if (rpcRetryCounter > RMInit::clientcommMaxRetry)
+ {
+ RMInit::logOut << "RPC call 'rpcendtransfer' failed" << endl;
+ throw r_Error(CLIENTCOMMUICATIONFAILURE);
+ }
+ rpcRetryCounter++;
+
+ if( !rpcStatusPtr )
+ {
+ RMInit::logOut << endl << "WARNING: RPC NULL POINTER (rpcendtransfer_1)" << endl << endl;
+ sleep(RMInit::clientcommSleep);
+ }
+ }while( rpcStatusPtr == 0 );
+ rpcStatus = *rpcStatusPtr;
+RMDBGIF(20, RMDebug::module_clientcomm, "WAITENDTRANSFEREND", \
+ RMInit::dbgOut << "Waiting 100 sec after end transfer\n" << std::endl; \
+ sleep(100); \
+ RMInit::dbgOut << "Continue now\n" << std::endl; );
+ setRPCInactive();
+
+ RMDBGEXIT(2, RMDebug::module_clientcomm, "RpcClientComm", "ok")
+
+ return mddResult;
+}
+
+
+
+r_Ref_Any
+RpcClientComm::getCollByName( const char* collName )
+ throw( r_Error )
+{
+ if(binding_h == NULL) {
+ RMInit::logOut << endl << "RpcClientComm::getCollByName(collName) ERROR: CONNECTION TO SERVER ALREADY CLOSED" << endl << endl;
+ throw r_Error(CONNECTIONCLOSED);
+ }
+
+ RMDBGENTER(2, RMDebug::module_clientcomm, "RpcClientComm", "getCollByName(" << collName << ")")
+ r_Set< r_Ref_Any >* set = 0;
+ unsigned short rpcStatus = 0;
+
+ NameSpecParams* params = new NameSpecParams;
+ GetCollRes* thisResult = 0;
+ params->clientID = clientID;
+ params->name = (char*)collName;
+
+ setRPCActive();
+ rpcRetryCounter = 0;
+ do
+ {
+ thisResult = rpcgetcollbyname_1( params, binding_h );
+
+ if( !thisResult )
+ {
+ RMInit::logOut << endl << "WARNING: RPC NULL POINTER (rpcgetcollbyname_1)" << endl << endl;
+ sleep(RMInit::clientcommSleep);
+ }
+ if (rpcRetryCounter > RMInit::clientcommMaxRetry)
+ {
+ RMInit::logOut << "RPC call 'rpcgetcollbyname' failed" << endl;
+ throw r_Error(CLIENTCOMMUICATIONFAILURE);
+ }
+ rpcRetryCounter++;
+ }while( thisResult == 0 );
+ setRPCInactive();
+
+ delete params;
+
+ rpcStatus = thisResult->status;
+
+ if( rpcStatus != 0 && rpcStatus != 1 )
+ {
+ r_Error err;
+
+ switch( rpcStatus )
+ {
+ case 2:
+ err = r_Error( r_Error::r_Error_ObjectUnknown );
+ break;
+ case 3:
+ err = r_Error( r_Error::r_Error_ClientUnknown );
+ break;
+ default:
+ err = r_Error( r_Error::r_Error_TransferFailed );
+ }
+
+ XDRFREE(GetCollRes, thisResult);
+
+ RMDBGEXIT(2, RMDebug::module_clientcomm, "RpcClientComm", "failed")
+ throw err;
+ }
+
+ RMDBGMIDDLE(2, RMDebug::module_clientcomm, "RpcClientComm", "ok")
+
+ // create the set
+ r_OId rOId( thisResult->oid );
+ set = new ( r_Database::actual_database, r_Object::read, rOId ) r_Set< r_Ref_Any >;
+
+ // initialize data elements
+ set->set_type_by_name ( thisResult->typeName );
+ set->set_type_structure( thisResult->typeStructure );
+ set->set_object_name ( thisResult->collName );
+
+ // now the transfer structure of rpcgetcollbyname can be freed
+ XDRFREE(GetCollRes, thisResult);
+
+ // get collection elements
+ if( rpcStatus == 0 )
+ getMDDCollection( *set, 0 );
+ // else rpcStatus == 1 -> Result collection is empty and nothing has to be got.
+
+ RMDBGEXIT(2, RMDebug::module_clientcomm, "RpcClientComm", "getCollByName(" << collName << ")")
+ return r_Ref_Any( set->get_oid(), set );
+}
+
+
+
+r_Ref_Any
+RpcClientComm::getCollByOId( const r_OId& oid )
+ throw( r_Error )
+{
+ if(binding_h == NULL) {
+ RMInit::logOut << endl << "RpcClientComm::getCollByOId(oid) ERROR: CONNECTION TO SERVER ALREADY CLOSED" << endl << endl;
+ throw r_Error(CONNECTIONCLOSED);
+ }
+
+ RMDBGENTER(2, RMDebug::module_clientcomm, "RpcClientComm", "getCollByOId(" << oid << ")")
+ r_Set< r_Ref_Any >* set = 0;
+ unsigned short rpcStatus = 0;
+
+ OIdSpecParams* params = new OIdSpecParams;
+ GetCollRes* thisResult = 0;
+ params->clientID = clientID;
+ params->oid = (char*)oid.get_string_representation();
+
+ setRPCActive();
+ rpcRetryCounter = 0;
+ do
+ {
+ thisResult = rpcgetcollbyoid_1( params, binding_h );
+
+ if( !thisResult )
+ {
+ RMInit::logOut << endl << "WARNING: RPC NULL POINTER (rpcgetcollbyoid_1)" << endl << endl;
+ sleep(RMInit::clientcommSleep);
+ }
+ if (rpcRetryCounter > RMInit::clientcommMaxRetry)
+ {
+ RMInit::logOut << "RPC call 'rpcgetcollbyoid' failed" << endl;
+ throw r_Error(CLIENTCOMMUICATIONFAILURE);
+ }
+ rpcRetryCounter++;
+ }while( thisResult == 0 );
+ setRPCInactive();
+
+ delete params;
+
+ rpcStatus = thisResult->status;
+
+ if( rpcStatus != 0 && rpcStatus != 1 )
+ {
+ r_Error err;
+
+ switch( rpcStatus )
+ {
+ case 2:
+ err = r_Error( r_Error::r_Error_ObjectUnknown );
+ break;
+ case 3:
+ err = r_Error( r_Error::r_Error_ClientUnknown );
+ break;
+ default:
+ err = r_Error( r_Error::r_Error_TransferFailed );
+ }
+
+ XDRFREE(GetCollRes, thisResult);
+
+ RMDBGEXIT(2, RMDebug::module_clientcomm, "RpcClientComm", "failed")
+ throw err;
+ }
+
+ RMDBGMIDDLE(2, RMDebug::module_clientcomm, "RpcClientComm", "ok")
+
+ // create the set
+ r_OId rOId( thisResult->oid );
+ set = new ( r_Database::actual_database, r_Object::read, rOId ) r_Set< r_Ref_Any >;
+
+ // initialize data elements
+ set->set_type_by_name ( thisResult->typeName );
+ set->set_type_structure( thisResult->typeStructure );
+ set->set_object_name ( thisResult->collName );
+
+ // now the transfer structure can be freed
+ XDRFREE(GetCollRes, thisResult);
+
+ // get collection elements
+ if( rpcStatus == 0 )
+ getMDDCollection( *set, 0 );
+ // else rpcStatus == 1 -> Result collection is empty and nothing has to be got.
+
+ RMDBGEXIT(2, RMDebug::module_clientcomm, "RpcClientComm", "failed")
+ return r_Ref_Any( set->get_oid(), set );
+}
+
+
+
+r_Ref_Any
+RpcClientComm::getCollOIdsByName( const char* collName )
+ throw( r_Error )
+{
+ if(binding_h == NULL) {
+ RMInit::logOut << endl << "RpcClientComm::getCollOIdsByName(collName) ERROR: CONNECTION TO SERVER ALREADY CLOSED" << endl << endl;
+ throw r_Error(CONNECTIONCLOSED);
+ }
+ RMDBGENTER(2, RMDebug::module_clientcomm, "RpcClientComm", "getCollOIdsByName(" << collName << ")")
+ r_Set< r_Ref<r_GMarray> >* set = 0;
+ unsigned short rpcStatus = 0;
+
+ NameSpecParams* params = new NameSpecParams;
+ GetCollOIdsRes* thisResult = 0;
+ params->clientID = clientID;
+ params->name = (char*)collName;
+
+ setRPCActive();
+ rpcRetryCounter = 0;
+ do
+ {
+ thisResult = rpcgetcolloidsbyname_1( params, binding_h );
+
+ if( !thisResult )
+ {
+ RMInit::logOut << endl << "WARNING: RPC NULL POINTER (rpcgetcolloidsbyname_1)" << endl << endl;
+ sleep(RMInit::clientcommSleep);
+ }
+ if (rpcRetryCounter > RMInit::clientcommMaxRetry)
+ {
+ RMInit::logOut << "RPC call 'rpcgetcolloidsbyname' failed" << endl;
+ throw r_Error(CLIENTCOMMUICATIONFAILURE);
+ }
+ rpcRetryCounter++;
+ }while( thisResult == 0 );
+ setRPCInactive();
+
+ delete params;
+
+ rpcStatus = thisResult->status;
+
+ if( rpcStatus != 0 && rpcStatus != 1 )
+ {
+ r_Error err;
+
+ switch( rpcStatus )
+ {
+ case 2:
+ err = r_Error( r_Error::r_Error_ObjectUnknown );
+ break;
+ case 3:
+ err = r_Error( r_Error::r_Error_ClientUnknown );
+ break;
+ default:
+ err = r_Error( r_Error::r_Error_TransferFailed );
+ }
+
+ XDRFREE(GetCollOIdsRes, thisResult);
+
+ RMDBGEXIT(2, RMDebug::module_clientcomm, "RpcClientComm", "failed")
+ throw err;
+ }
+
+ RMDBGMIDDLE(2, RMDebug::module_clientcomm, "RpcClientComm", "ok")
+
+ // create the set
+ r_OId rOId( thisResult->oid );
+ set = new ( r_Database::actual_database, r_Object::read, rOId ) r_Set< r_Ref< r_GMarray > >;
+
+ set->set_type_by_name ( thisResult->typeName );
+ set->set_type_structure( thisResult->typeStructure );
+ set->set_object_name ( thisResult->collName );
+
+ // fill set with oids
+ if( rpcStatus == 0 )
+ {
+ for( unsigned int i=0; i<thisResult->oidTable.oidTable_len; i++ )
+ {
+ set->insert_element( r_Ref<r_GMarray>( r_OId( thisResult->oidTable.oidTable_val[i].oid ) ), 1 );
+
+ RMDBGMIDDLE(2, RMDebug::module_clientcomm, "RpcClientComm", "oid " << i << ": " << thisResult->oidTable.oidTable_val[i].oid)
+ }
+ }
+
+ // now the transfer structure can be freed
+ XDRFREE(GetCollOIdsRes, thisResult);
+
+ RMDBGEXIT(2, RMDebug::module_clientcomm, "RpcClientComm", "getCollOIdsByName")
+ return r_Ref_Any( set->get_oid(), set );
+}
+
+
+
+r_Ref_Any
+RpcClientComm::getCollOIdsByOId( const r_OId& oid )
+ throw( r_Error )
+{
+ if(binding_h == NULL) {
+ RMInit::logOut << endl << "RpcClientComm::getCollOIdsByOId(oid) ERROR: CONNECTION TO SERVER ALREADY CLOSED" << endl << endl;
+ throw r_Error(CONNECTIONCLOSED);
+ }
+ RMDBGENTER(2, RMDebug::module_clientcomm, "RpcClientComm", "getCollOIdsByOId(" << oid << ")")
+ r_Set< r_Ref<r_GMarray> >* set = 0;
+ unsigned short rpcStatus = 0;
+
+ OIdSpecParams* params = new OIdSpecParams;
+ GetCollOIdsRes* thisResult = 0;
+ params->clientID = clientID;
+ params->oid = (char*)oid.get_string_representation();
+
+ setRPCActive();
+ rpcRetryCounter = 0;
+ do
+ {
+ thisResult = rpcgetcolloidsbyoid_1( params, binding_h );
+
+ if( !thisResult )
+ {
+ RMInit::logOut << endl << "WARNING: RPC NULL POINTER (rpcgetcolloidsbyoid_1)" << endl << endl;
+ sleep(RMInit::clientcommSleep);
+ }
+ if (rpcRetryCounter > RMInit::clientcommMaxRetry)
+ {
+ RMInit::logOut << "RPC call 'rpcgetcolloidsbyoid' failed" << endl;
+ throw r_Error(CLIENTCOMMUICATIONFAILURE);
+ }
+ rpcRetryCounter++;
+ }while( thisResult== 0 );
+ setRPCInactive();
+
+ delete params;
+
+ rpcStatus = thisResult->status;
+
+ if( rpcStatus != 0 && rpcStatus != 1 )
+ {
+ r_Error err;
+
+ switch( rpcStatus )
+ {
+ case 2:
+ err = r_Error( r_Error::r_Error_ObjectUnknown );
+ break;
+ case 3:
+ err = r_Error( r_Error::r_Error_ClientUnknown );
+ break;
+ default:
+ err = r_Error( r_Error::r_Error_TransferFailed );
+ }
+
+ XDRFREE(GetCollOIdsRes, thisResult);
+
+ RMDBGEXIT(2, RMDebug::module_clientcomm, "RpcClientComm", "failed")
+ throw err;
+ }
+
+ RMDBGMIDDLE(2, RMDebug::module_clientcomm, "RpcClientComm", "ok")
+
+ // create the set
+ r_OId rOId( thisResult->oid );
+ set = new ( r_Database::actual_database, r_Object::read, rOId ) r_Set< r_Ref< r_GMarray > >;
+
+ set->set_type_by_name ( thisResult->typeName );
+ set->set_type_structure( thisResult->typeStructure );
+ set->set_object_name ( thisResult->collName );
+
+ // fill set with oids
+ if( rpcStatus == 0 )
+ {
+ for( unsigned int i=0; i<thisResult->oidTable.oidTable_len; i++ )
+ {
+ set->insert_element( r_Ref<r_GMarray>( r_OId( thisResult->oidTable.oidTable_val[i].oid ) ), 1 );
+ RMDBGMIDDLE(2, RMDebug::module_clientcomm, "RpcClientComm", "contains oid #" << i << ":" << thisResult->oidTable.oidTable_val[i].oid)
+ }
+ }
+
+ // now the transfer structure can be freed
+ XDRFREE(GetCollOIdsRes, thisResult);
+
+ RMDBGEXIT(2, RMDebug::module_clientcomm, "RpcClientComm", "getCollOIdsByOId")
+ return r_Ref_Any( set->get_oid(), set );
+}
+
+int
+RpcClientComm::createDB( const char* name )
+ throw(r_Error)
+{
+ if(binding_h == NULL) {
+ RMInit::logOut << endl << "RpcClientComm::createDB(name) ERROR: CONNECTION TO SERVER ALREADY CLOSED" << endl << endl;
+ throw r_Error(CONNECTIONCLOSED);
+ }
+
+ unsigned short rpcStatus=0;
+ unsigned short* rpcStatusPtr=0;
+
+ setRPCActive();
+ rpcRetryCounter = 0;
+ do
+ {
+ rpcStatusPtr = rpccreatedb_1( (char**)&name, binding_h );
+
+ if( !rpcStatusPtr )
+ {
+ RMInit::logOut << endl << "WARNING: RPC NULL POINTER (rpccreatedb_1)" << endl << endl;
+ sleep(RMInit::clientcommSleep);
+ }
+ if (rpcRetryCounter > RMInit::clientcommMaxRetry)
+ {
+ RMInit::logOut << "RPC call 'rpccreatedb' failed" << endl;
+ throw r_Error(CLIENTCOMMUICATIONFAILURE);
+ }
+ rpcRetryCounter++;
+ }while( rpcStatusPtr == 0 );
+ rpcStatus = *rpcStatusPtr;
+ setRPCInactive();
+
+ return rpcStatus;
+}
+
+
+int
+RpcClientComm::destroyDB( const char* name )
+ throw(r_Error)
+{
+ if(binding_h == NULL) {
+ RMInit::logOut << endl << "RpcClientComm::destroyDB(name) ERROR: CONNECTION TO SERVER ALREADY CLOSED" << endl << endl;
+ throw r_Error(CONNECTIONCLOSED);
+ }
+
+ unsigned short rpcStatus=0;
+ unsigned short* rpcStatusPtr=0;
+
+ setRPCActive();
+ rpcRetryCounter = 0;
+ do
+ {
+ rpcStatusPtr = rpcdestroydb_1( (char**)&name, binding_h );
+
+ if( !rpcStatusPtr )
+ {
+ RMInit::logOut << endl << "WARNING: RPC NULL POINTER (rpcdestroydb_1)" << endl << endl;
+ sleep(RMInit::clientcommSleep);
+ }
+ if (rpcRetryCounter > RMInit::clientcommMaxRetry)
+ {
+ RMInit::logOut << "RPC call 'rpcdestroydb' failed" << endl;
+ throw r_Error(CLIENTCOMMUICATIONFAILURE);
+ }
+ rpcRetryCounter++;
+ }while( rpcStatusPtr == 0 );
+ rpcStatus = *rpcStatusPtr;
+ setRPCInactive();
+
+ return rpcStatus;
+}
+
+
+int
+RpcClientComm::openDB( const char* database )
+{
+ strcpy(dataBase,database);
+
+ connectToServer(1); // this means read-only
+
+ int answer=executeOpenDB(database);
+
+ if(answer==0) answer=executeCloseDB();
+ // else the DB is not open and makes ugly log output on the server
+
+ disconnectFromServer();
+ return answer;
+}
+
+int
+RpcClientComm::executeOpenDB( const char* database )
+{
+
+ if(binding_h == NULL) {
+ RMInit::logOut << endl << "RpcClientComm::executeOpenDB(database) ERROR: CONNECTION TO SERVER ALREADY CLOSED" << endl << endl;
+ return CONNECTIONCLOSED;
+ }
+
+ RMDBGENTER(2, RMDebug::module_clientcomm, "RpcClientComm", "executeOpenDB(" << database << ")")
+ // Send first "I'm alive" signal in ALIVEINTERVAL seconds
+#ifdef WIN32
+ timerid = timeSetEvent(ALIVEINTERVAL * 1000, 0, TimerProc, 0, TIME_PERIODIC);
+#else
+ alarm( ALIVEINTERVAL );
+#endif
+ OpenDBParams* params = new OpenDBParams;
+ OpenDBRes* thisResult = 0;
+ params->dbName = (char*)database;
+ params->userName = (char*)RMInit::userName;
+ params->capability = capability;
+ int* dummyParam = new int(0);// dummy
+ int* endianResult = NULL;
+ ServerVersionRes* versionResult = NULL;
+
+ setRPCActive();
+ versionResult = rpcgetserverversion_1( dummyParam, binding_h );
+ RMDBGMIDDLE(2, RMDebug::module_clientcomm, "RpcClientComm", "server version " << versionResult->serverVersionNo << ", rpc version " << versionResult->rpcInterfaceVersionNo)
+ // don't forget to add 0.5, otherwise rounding errors!
+ serverRPCversion = (int)(1000.0 * versionResult->rpcInterfaceVersionNo + 0.5);
+ if (serverRPCversion != RPCVERSION)
+ {
+ RMDBGMIDDLE(2, RMDebug::module_clientcomm, "RpcClientComm", "RPC interface version mismatch: client (" << RPCVERSION/1000.0 << "), server (" << versionResult->rpcInterfaceVersionNo << ")")
+ RMInit::logOut << "Client Server Communication incompatible" << endl;
+ setRPCInactive();
+ RMDBGEXIT(2, RMDebug::module_clientcomm, "RpcClientComm", "executeOpenDB(" << database << ") " << 4)
+ return 4; // servercomm::openDB creates codes 1-3.
+ }
+
+ if(binding_h == NULL) {
+ RMInit::logOut << endl << "RpcClientComm::executeOpenDB(database) ERROR: CONNECTION TO SERVER ALREADY CLOSED" << endl << endl;
+ return CONNECTIONCLOSED;
+ }
+
+ rpcRetryCounter = 0;
+ do
+ {
+ thisResult = rpcopendb_1( params, binding_h );
+
+ if( !thisResult )
+ {
+ RMInit::logOut << endl << "WARNING: RPC NULL POINTER (rpcopendb_1)" << endl << endl;
+ sleep(RMInit::clientcommSleep);
+ }
+ if (rpcRetryCounter > RMInit::clientcommMaxRetry)
+ {
+ RMInit::logOut << "RPC call 'rpcopendb' failed" << endl;
+ throw r_Error(CLIENTCOMMUICATIONFAILURE);
+ }
+ rpcRetryCounter++;
+ }while( thisResult == 0 );
+
+ if(binding_h == NULL) {
+ RMInit::logOut << endl << "RpcClientComm::executeOpenDB(database) ERROR: CONNECTION TO SERVER ALREADY CLOSED" << endl << endl;
+ return CONNECTIONCLOSED;
+ }
+
+ endianResult = rpcgetserverendian_1( dummyParam, binding_h );
+
+ setRPCInactive();
+
+ delete params;
+ delete dummyParam;
+
+ clientID = thisResult->clientID;
+ endianServer = *endianResult;
+ //cout << "server endianness: " << endianServer << ", client: " << endianClient << endl;
+
+ RMDBGEXIT(2, RMDebug::module_clientcomm, "RpcClientComm", "executeOpenDB(" << database << ") " << thisResult->status)
+ return thisResult->status;
+}
+
+
+int
+RpcClientComm::closeDB()
+{
+ // We decided that it is not necessary to do anything for closeDB, the database is already closed by others
+ RMInit::logOut << "Fake closeDB" << endl;
+
+ return 0;// answer;
+}
+
+int
+RpcClientComm::executeCloseDB()
+{
+ if(binding_h == NULL) {
+ RMInit::logOut << endl << "RpcClientComm::executeCloseDB(database) ERROR: CONNECTION TO SERVER ALREADY CLOSED" << endl << endl;
+ return CONNECTIONCLOSED;
+ }
+
+ unsigned short rpcStatus=0;
+ unsigned short* rpcStatusPtr=0;
+
+ // Suspend "I'm alive" signal
+#ifdef __VISUALC__
+ timeKillEvent(timerid);
+#else
+ alarm( 0 );
+#endif
+
+ setRPCActive();
+ rpcRetryCounter = 0;
+ do
+ {
+ rpcStatusPtr = rpcclosedb_1( &clientID, binding_h );
+
+ if( !rpcStatusPtr )
+ {
+ RMInit::logOut << endl << "WARNING: RPC NULL POINTER (rpcclosedb_1)" << endl << endl;
+ sleep(RMInit::clientcommSleep);
+ }
+ if (rpcRetryCounter > RMInit::clientcommMaxRetry)
+ {
+ RMInit::logOut << "RPC call 'rpcclosedb' failed" << endl;
+ throw r_Error(CLIENTCOMMUICATIONFAILURE);
+ }
+ rpcRetryCounter++;
+ }while( rpcStatusPtr == 0 );
+ rpcStatus = *rpcStatusPtr;
+ setRPCInactive();
+
+ return rpcStatus;
+}
+
+int
+RpcClientComm::openTA( unsigned short readOnly )
+ throw(r_Error)
+ {
+ int answer=0;
+ connectToServer(readOnly);
+
+ answer=executeOpenDB(dataBase);
+
+ if(answer==0) executeOpenTA(readOnly);
+
+ //If there is an error CONNECTIONCLOSED, we report this, it is important to know
+ if(answer == CONNECTIONCLOSED) {
+ throw r_Error(CONNECTIONCLOSED);
+ }
+
+ return answer;
+ }
+
+int
+RpcClientComm::executeOpenTA( unsigned short readOnly )
+{
+ if(binding_h == NULL) {
+ RMInit::logOut << endl << "RpcClientComm::executeOpenTA(database) ERROR: CONNECTION TO SERVER ALREADY CLOSED" << endl << endl;
+ return CONNECTIONCLOSED;
+ }
+
+ unsigned short rpcStatus=0;
+ unsigned short* rpcStatusPtr=0;
+ int secsWaited = 0;
+
+ BeginTAParams params;
+ params.clientID = clientID;
+ params.readOnly = readOnly;
+ params.capability = capability;
+
+ setRPCActive();
+ rpcRetryCounter = 0;
+ do
+ {
+ rpcStatusPtr = rpcbeginta_1( &params, binding_h );
+
+ if( !rpcStatusPtr )
+ {
+ RMInit::logOut << endl << "WARNING: RPC NULL POINTER (rpcbeginta_1)" << endl << endl;
+ sleep(RMInit::clientcommSleep);
+ }
+ if (rpcRetryCounter > RMInit::clientcommMaxRetry)
+ {
+ RMInit::logOut << "RPC call 'rpcbeginta' failed" << endl;
+ throw r_Error(CLIENTCOMMUICATIONFAILURE);
+ }
+ rpcRetryCounter++;
+ }while( rpcStatusPtr == 0 );
+
+ rpcStatus = *rpcStatusPtr;
+
+RMDBGIF(20, RMDebug::module_tools, "WAITRECEIVEDTILE", \
+ RMInit::dbgOut << "Waiting 100 sec after receive tile\n" << std::endl; \
+ sleep(100); \
+ RMInit::dbgOut << "Continue now\n" << std::endl; );
+ setRPCInactive();
+
+/* not necessary with V5
+ int sleepCntr = 1;
+ while( rpcStatus == 2 )
+ {
+ if( sleepCntr == 64 ) sleepCntr /= 2;
+ RMInit::logOut << "Another transaction is already active, sleeping " << sleepCntr*2 << " secs..." << endl;
+ sleepCntr *= 2;
+ secsWaited += sleepCntr;
+#ifndef __VISUALC__
+ sleep( sleepCntr );
+#else
+ Sleep( sleepCntr*1000 );
+#endif
+ setRPCActive();
+ do
+ {
+ rpcStatusPtr = rpcbeginta_1( &params, binding_h );
+
+ if( !rpcStatusPtr )
+ {
+ RMInit::logOut << endl << "WARNING: RPC NULL POINTER (rpcbeginta_1)" << endl << endl;
+ sleep(RMInit::clientcommSleep);
+ }
+ }while( rpcStatusPtr == 0 );
+ rpcStatus = *rpcStatusPtr;
+ setRPCInactive();
+ }
+*/
+ return rpcStatus;
+}
+
+int
+RpcClientComm::commitTA()
+ throw(r_Error)
+{
+ int answer=executeCommitTA();
+
+ if(answer==0) answer=executeCloseDB();
+
+ //If there is an error CONNECTIONCLOSED, we report this, it is important to know
+ if(answer == CONNECTIONCLOSED) {
+ throw r_Error(CONNECTIONCLOSED);
+ }
+
+ disconnectFromServer();
+
+ return answer;
+}
+
+int
+RpcClientComm::executeCommitTA()
+{
+ if(binding_h == NULL) {
+ RMInit::logOut << endl << "RpcClientComm::executeCommitTA(database) ERROR: CONNECTION TO SERVER ALREADY CLOSED" << endl << endl;
+ return CONNECTIONCLOSED;
+ }
+
+ unsigned short rpcStatus=0;
+ unsigned short* rpcStatusPtr=0;
+
+ setRPCActive();
+ rpcRetryCounter = 0;
+ do
+ {
+ rpcStatusPtr = rpccommitta_1( &clientID, binding_h );
+
+ if( !rpcStatusPtr ) {
+ {
+ RMInit::logOut << endl << "WARNING: RPC NULL POINTER (rpccommitta_1)" << endl << endl;
+ sleep(RMInit::clientcommSleep);
+ }
+ }
+ if (rpcRetryCounter > RMInit::clientcommMaxRetry)
+ {
+ RMInit::logOut << "RPC call 'rpccommitta' failed" << endl;
+ throw r_Error(CLIENTCOMMUICATIONFAILURE);
+ }
+ rpcRetryCounter++;
+ }while( rpcStatusPtr == 0 );
+ rpcStatus = *rpcStatusPtr;
+ setRPCInactive();
+
+ return rpcStatus;
+}
+
+int
+RpcClientComm::abortTA()
+{
+ int answer=0;
+ try {
+ answer = executeAbortTA();
+
+ if(answer==0) answer=executeCloseDB();
+
+ disconnectFromServer();
+ }
+ catch (r_Error& e)
+ {
+ RMInit::logOut << "RpcClientComm::abortTA() caught error: " << e.get_errorno() << " " << e.what() << std::endl;
+ answer = 1;
+ }
+
+ //If there is an error CONNECTIONCLOSED, we ignore this, it is in abort
+
+ return answer;
+}
+
+int
+RpcClientComm::executeAbortTA()
+{
+ if(binding_h == NULL) {
+ RMInit::logOut << endl << "RpcClientComm::executeAbortTA(database) ERROR: CONNECTION TO SERVER ALREADY CLOSED" << endl << endl;
+ return CONNECTIONCLOSED;
+ }
+
+ unsigned short rpcStatus=0;
+ unsigned short* rpcStatusPtr=0;
+
+ setRPCActive();
+ rpcRetryCounter = 0;
+ do
+ {
+ rpcStatusPtr = rpcabortta_1( &clientID, binding_h );
+
+ if( !rpcStatusPtr ) {
+ {
+ RMInit::logOut << endl << "WARNING: RPC NULL POINTER (rpcabortta_1)" << endl << endl;
+ sleep(RMInit::clientcommSleep);
+ }
+ }
+ if (rpcRetryCounter > RMInit::clientcommMaxRetry)
+ {
+ RMInit::logOut << "RPC call 'rpcabortta' failed" << endl;
+ throw r_Error(CLIENTCOMMUICATIONFAILURE);
+ }
+ rpcRetryCounter++;
+ }while( rpcStatusPtr == 0 );
+ rpcStatus = *rpcStatusPtr;
+ setRPCInactive();
+
+ return rpcStatus;
+}
+
+
+r_OId
+RpcClientComm::getNewOId( unsigned short objType )
+ throw(r_Error)
+{
+ if(binding_h == NULL) {
+ RMInit::logOut << endl << "RpcClientComm::getNewOId(objType) ERROR: CONNECTION TO SERVER ALREADY CLOSED" << endl << endl;
+ throw r_Error(CONNECTIONCLOSED);
+ }
+
+ // update -> check for read_only transaction
+ if( r_Transaction::actual_transaction == 0 ||
+ r_Transaction::actual_transaction->get_mode() == r_Transaction::read_only )
+ {
+ r_Error err = r_Error( r_Error::r_Error_TransactionReadOnly );
+ throw err;
+ }
+
+ unsigned short rpcStatus = 0;
+
+ NewOIdParams* params = new NewOIdParams;
+ OIdRes* thisResult = 0;
+ params->clientID = clientID;
+ params->objType = objType;
+
+ setRPCActive();
+ rpcRetryCounter = 0;
+ do
+ {
+ thisResult = rpcgetnewoid_1( params, binding_h );
+
+ if( !thisResult )
+ {
+ RMInit::logOut << endl << "WARNING: RPC NULL POINTER (rpcgetnewoid_1)" << endl << endl;
+ sleep(RMInit::clientcommSleep);
+ }
+ if (rpcRetryCounter > RMInit::clientcommMaxRetry)
+ {
+ RMInit::logOut << "RPC call 'rpcgetnewoid' failed" << endl;
+ throw r_Error(CLIENTCOMMUICATIONFAILURE);
+ }
+ rpcRetryCounter++;
+ }while( thisResult == 0 );
+ setRPCInactive();
+
+ delete params;
+
+ rpcStatus = thisResult->status;
+
+ r_OId oid( thisResult->oid );
+
+ // now the transfer structure of rpcgetcollbyname can be freed
+ XDRFREE(OIdRes, thisResult);
+
+ if( rpcStatus != 0 )
+ {
+ r_Error err;
+
+ switch( rpcStatus )
+ {
+ case 1:
+ err = r_Error( r_Error::r_Error_ClientUnknown );
+ break;
+ case 2:
+ err = r_Error( r_Error::r_Error_CreatingOIdFailed );
+ break;
+ default:
+ err = r_Error( r_Error::r_Error_TransferFailed );
+ }
+ throw err;
+ }
+
+ return oid;
+}
+
+
+unsigned short
+RpcClientComm::getObjectType( const r_OId& oid )
+ throw(r_Error)
+{
+ if(binding_h == NULL) {
+ RMInit::logOut << endl << "RpcClientComm::getObjectType(oid) ERROR: CONNECTION TO SERVER ALREADY CLOSED" << endl << endl;
+ throw r_Error(CONNECTIONCLOSED);
+ }
+
+ OIdSpecParams* params = new OIdSpecParams;
+ ObjectTypeRes* thisResult = 0;
+ params->clientID = clientID;
+ params->oid = (char*)oid.get_string_representation();
+
+ setRPCActive();
+ rpcRetryCounter = 0;
+ do
+ {
+ thisResult = rpcgetobjecttype_1( params, binding_h );
+
+ if( !thisResult )
+ {
+ RMInit::logOut << endl << "WARNING: RPC NULL POINTER (rpcgetobjecttype_1)" << endl << endl;
+ sleep(RMInit::clientcommSleep);
+ }
+ if (rpcRetryCounter > RMInit::clientcommMaxRetry)
+ {
+ RMInit::logOut << "RPC call 'rpcgetobjexttype' failed" << endl;
+ throw r_Error(CLIENTCOMMUICATIONFAILURE);
+ }
+ rpcRetryCounter++;
+ }while( thisResult == 0 );
+ setRPCInactive();
+
+ delete params;
+
+ unsigned short rpcStatus = thisResult->status;
+ unsigned short objType = thisResult->objType;
+
+ // now the transfer structure can be freed
+ XDRFREE(ObjectTypeRes, thisResult);
+
+ if( rpcStatus != 0 )
+ {
+ r_Error err;
+
+ switch( rpcStatus )
+ {
+ case 1:
+ err = r_Error( r_Error::r_Error_ClientUnknown );
+ break;
+ case 2:
+ err = r_Error( r_Error::r_Error_ObjectUnknown );
+ break;
+ default:
+ err = r_Error( r_Error::r_Error_TransferFailed );
+ }
+ throw err;
+ }
+
+ return objType;
+}
+
+
+char*
+RpcClientComm::getTypeStructure( const char* typeName, r_Type_Type typeType )
+ throw(r_Error)
+{
+ if(binding_h == NULL) {
+ RMInit::logOut << endl << "RpcClientComm::getTypeStructure(typeName, typeType) ERROR: CONNECTION TO SERVER ALREADY CLOSED" << endl << endl;
+ throw r_Error(CONNECTIONCLOSED);
+ }
+
+ GetTypeStructureParams* params = new GetTypeStructureParams;
+ GetTypeStructureRes* thisResult = 0;
+ params->clientID = clientID;
+ params->typeName = (char*)typeName;
+ params->typeType = typeType;
+
+ setRPCActive();
+ rpcRetryCounter = 0;
+ do
+ {
+ thisResult = rpcgettypestructure_1( params, binding_h );
+
+ if( !thisResult )
+ {
+ RMInit::logOut << endl << "WARNING: RPC NULL POINTER (rpcgettypestructure_1)" << endl << endl;
+ sleep(RMInit::clientcommSleep);
+ }
+ if (rpcRetryCounter > RMInit::clientcommMaxRetry)
+ {
+ RMInit::logOut << "RPC call 'rpcgettypestructure' failed" << endl;
+ throw r_Error(CLIENTCOMMUICATIONFAILURE);
+ }
+ rpcRetryCounter++;
+ }while( thisResult == 0 );
+ setRPCInactive();
+
+ delete params;
+
+ char* typeStructure = 0;
+ unsigned short rpcStatus = thisResult->status;
+
+ if( rpcStatus == 0 )
+ {
+ typeStructure = new char[strlen(thisResult->typeStructure) + 1];
+ strcpy(typeStructure, thisResult->typeStructure);
+ // this has to be freed by rpc:thisResult->typeStructure = 0;
+ }
+
+ // now the transfer structure can be freed
+ XDRFREE(GetTypeStructureRes, thisResult);
+
+ if( rpcStatus != 0 )
+ {
+ r_Error err;
+
+ switch( rpcStatus )
+ {
+ case 2:
+ err = r_Error( r_Error::r_Error_DatabaseClassUndefined );
+ break;
+ default:
+ err = r_Error( r_Error::r_Error_TransferFailed );
+ }
+ throw err;
+ }
+
+ return typeStructure;
+}
+
+
+void
+RpcClientComm::getMarRpcRepresentation( const r_GMarray* mar, RPCMarray*& rpcMarray,
+ r_Data_Format initStorageFormat,
+ const r_Base_Type *baseType)
+{
+ RMDBGENTER(2, RMDebug::module_clientcomm, "RpcClientComm", "getMarRpcRepresentation(...)");
+
+ // allocate memory for the RPCMarray data structure and assign its fields
+ rpcMarray = (RPCMarray*)mymalloc( sizeof(RPCMarray) );
+ rpcMarray->domain = mar->spatial_domain().get_string_representation();
+ rpcMarray->cellTypeLength = mar->get_type_length();
+
+ void* arrayData = NULL;
+ r_ULong arraySize=0;
+
+ if (initStorageFormat == r_Array)
+ {
+ if (transferFormat != r_Array)
+ {
+ r_Tile_Compression *engine = NULL;
+
+ try
+ {
+ r_Storage_Man_CPP sman;
+ engine = r_Tile_Compression::create(transferFormat, mar->spatial_domain(), baseType);
+ engine->set_storage_handler(sman);
+ RMDBGMIDDLE(2, RMDebug::module_clientcomm, "RpcClientComm", "getMarRpcRepresentation(...) compress with " << engine->get_name())
+ if ((endianClient != endianServer) && (!engine->converts_endianness()))
+ {
+ RMDBGMIDDLE( 2, RMDebug::module_clientcomm, "RpcClientComm", "getMarRpcRepresentation(...) for "
+ << transferFormat << " endianness changed before compression from " << (r_Endian::r_Endianness)endianClient
+ << " to " << (r_Endian::r_Endianness) endianServer);
+ char *endianData = new char[mar->get_array_size()];
+ changeEndianness(mar, endianData, baseType);
+ arrayData = engine->compress(endianData, arraySize, transferFormatParams);
+ delete [] endianData;
+ endianData=NULL;
+ }
+ else
+ {
+ arrayData = engine->compress(mar->get_array(), arraySize, transferFormatParams);
+ }
+ RMDBGMIDDLE(2, RMDebug::module_clientcomm, "RpcClientComm", "compression returned " << arrayData << " (" << arraySize << " bytes)")
+ /*void *testData = engine->decompress(arrayData, arraySize);
+ cout << "Decompression worked " << ((memcmp(mar->get_array(), testData, (mar->get_type_length()) * (mar->spatial_domain().cell_count())) == 0) ? "OK" : "!NOT!") << endl;
+ delete [] testData;*/
+
+ // ForWiss: revert to uncompressed data if the compressed data is larger
+ // coman: and introduced a bug of endianess ...
+ if (arraySize > mar->get_array_size())
+ {
+ RMInit::logOut << "RpcClientComm::getMarRpcRepresentation(...) Warning: overriding compression setting("
+ << transferFormat << ") to " << r_Array
+ << " because compressed size( " << arraySize
+ << " bytes) > uncompressed size( " << mar->get_array_size() << " bytes)" << endl;
+ delete [] arrayData;
+ arrayData = NULL;
+ }
+ }
+ catch (r_Error &err)
+ {
+ RMInit::logOut << "RpcClientComm::getMarRpcRepresentation(...) Error: Unsupported data format " << transferFormat << endl;
+ }
+ if (engine != NULL)
+ delete engine;
+ }
+ else
+ {
+ if (endianClient != endianServer)
+ {
+ RMDBGMIDDLE( 2, RMDebug::module_clientcomm, "RpcClientComm", "getMarRpcRepresentation(...) for "
+ << transferFormat << " endianness changed from "
+ << (r_Endian::r_Endianness)endianClient << " to " << (r_Endian::r_Endianness) endianServer);
+ arraySize = mar->get_array_size();
+ arrayData = new char[arraySize];
+ changeEndianness(mar, arrayData, baseType);
+ }
+ }
+ }
+
+ if (arrayData == NULL)
+ {
+ //error in compression or compression inefficient
+ rpcMarray->currentFormat = initStorageFormat;
+ rpcMarray->data.confarray_len = mar->get_array_size();
+ if (endianClient != endianServer)
+ {
+ RMDBGMIDDLE( 2, RMDebug::module_clientcomm, "RpcClientComm", "getMarRpcRepresentation(...) for "
+ << transferFormat << "endianness changed from "
+ << (r_Endian::r_Endianness)endianClient << " to " << (r_Endian::r_Endianness) endianServer
+ << " because compression " << transferFormat << " failed" );
+ arrayData = new char[arraySize];
+ changeEndianness(mar, arrayData, baseType);
+ rpcMarray->data.confarray_val = (char*)(arrayData);
+ }
+ else
+ {
+ rpcMarray->data.confarray_val = (char*)(mar->get_array());
+ }
+ }
+ else
+ {
+ if (arraySize != mar->get_array_size())
+ {
+ RMDBGMIDDLE(2, RMDebug::module_clientcomm, "RpcClientComm", "compressed to " << (100.0*arraySize) / mar->get_array_size() << "%")
+ }
+ rpcMarray->currentFormat = transferFormat;
+ rpcMarray->data.confarray_len = arraySize;
+ rpcMarray->data.confarray_val = (char*)arrayData;
+ }
+ rpcMarray->storageFormat = storageFormat;
+
+ RMDBGEXIT(2, RMDebug::module_clientcomm, "RpcClientComm", "getMarRpcRepresentation(...)");
+}
+
+
+void
+RpcClientComm::freeMarRpcRepresentation( const r_GMarray* mar, RPCMarray* rpcMarray )
+{
+ if (rpcMarray->data.confarray_val != ((r_GMarray*)mar)->get_array())
+ {
+ delete [] rpcMarray->data.confarray_val;
+ }
+ free( rpcMarray->domain );
+ free( rpcMarray );
+}
+
+void
+RpcClientComm::getMDDCollection( r_Set< r_Ref_Any >& mddColl, unsigned int isQuery )
+ throw(r_Error)
+{
+ if(binding_h == NULL) {
+ RMInit::logOut << endl << "RpcClientComm::getMDDCollection(mddColl, isQuery) ERROR: CONNECTION TO SERVER ALREADY CLOSED" << endl << endl;
+ throw r_Error(CONNECTIONCLOSED);
+ }
+ RMDBGENTER(2, RMDebug::module_clientcomm, "RpcClientComm", "getMDDCollection(...)")
+ unsigned short tileStatus=0;
+ unsigned short mddStatus = 0;
+// r_Minterval mddDomain;
+
+ RMInit::logOut << endl;
+
+ while( mddStatus == 0 ) // repeat until all MDDs are transferred
+ {
+ r_Ref<r_GMarray> mddResult;
+
+ GetMDDRes* thisResult = 0;
+
+ // Get spatial domain of next MDD
+ setRPCActive();
+ rpcRetryCounter = 0;
+ do
+ {
+ thisResult = rpcgetnextmdd_1( &clientID, binding_h );
+
+ if( !thisResult )
+ {
+ RMInit::logOut << endl << "WARNING: RPC NULL POINTER (rpcgetnextmdd_1)" << endl << endl;
+ sleep(RMInit::clientcommSleep);
+ }
+ if (rpcRetryCounter > RMInit::clientcommMaxRetry)
+ {
+ RMInit::logOut << "RPC call 'rpcgetnextmdd' failed" << endl;
+ throw r_Error(CLIENTCOMMUICATIONFAILURE);
+ }
+ rpcRetryCounter++;
+ }while( thisResult == 0 );
+ setRPCInactive();
+
+ mddStatus = thisResult->status;
+
+ RMDBGMIDDLE(2, RMDebug::module_clientcomm, "RpcClientComm", "read MDD")
+
+ if( mddStatus == 2 )
+ {
+ RMInit::logOut << "Error: getMDDCollection(...) - no transfer collection or empty transfer collection" << endl;
+ throw r_Error( r_Error::r_Error_TransferFailed );
+ }
+ else
+ tileStatus = 0 ? 10 : 0;
+
+ // create r_Minterval
+ // mddDomain = r_Minterval( thisResult->domain );
+
+ tileStatus = getMDDCore(mddResult, thisResult, isQuery);
+
+ // finally, insert the r_Marray into the set
+
+ mddColl.insert_element( mddResult, 1 );
+
+ if( tileStatus == 0 ) // if this is true, we're done with this collection
+ break;
+
+ RMDBGMIDDLE(2, RMDebug::module_clientcomm, "RpcClientComm", "ok");
+
+ } // end while( mddStatus == 0 )
+
+ if(binding_h == NULL) {
+ RMInit::logOut << endl << "RpcClientComm::getMDDCollection(mddColl, isQuery) ERROR: CONNECTION TO SERVER ALREADY CLOSED" << endl << endl;
+ throw r_Error(CONNECTIONCLOSED);
+ }
+
+ unsigned short* rpcStatusPtr = 0;
+
+ setRPCActive();
+ rpcRetryCounter = 0;
+ do
+ {
+ rpcStatusPtr = rpcendtransfer_1( &clientID, binding_h );
+
+ if( !rpcStatusPtr )
+ {
+ RMInit::logOut << endl << "WARNING: RPC NULL POINTER (rpcendtransfer_1)" << endl << endl;
+ sleep(RMInit::clientcommSleep);
+ }
+ if (rpcRetryCounter > RMInit::clientcommMaxRetry)
+ {
+ RMInit::logOut << "RPC call 'rpcendtransfer' failed" << endl;
+ throw r_Error(CLIENTCOMMUICATIONFAILURE);
+ }
+ rpcRetryCounter++;
+ }while( rpcStatusPtr == 0 );
+ setRPCInactive();
+}
+
+
+
+void
+RpcClientComm::getElementCollection( r_Set< r_Ref_Any >& resultColl )
+ throw(r_Error)
+{
+ if(binding_h == NULL) {
+ RMInit::logOut << endl << "RpcClientComm::getElementCollection(resultColl) ERROR: CONNECTION TO SERVER ALREADY CLOSED" << endl << endl;
+ throw r_Error(CONNECTIONCLOSED);
+ }
+ unsigned short rpcStatus = 0;
+
+ RMInit::logOut << endl << " got set of type " << resultColl.get_type_structure() << endl;
+
+ while( rpcStatus == 0 ) // repeat until all elements are transferred
+ {
+ GetElementRes* thisResult = 0;
+
+ if(binding_h == NULL) {
+ RMInit::logOut << endl << "RpcClientComm::getElementCollection(resultColl) ERROR: CONNECTION TO SERVER ALREADY CLOSED" << endl << endl;
+ throw r_Error(CONNECTIONCLOSED);
+ }
+
+ setRPCActive();
+ rpcRetryCounter = 0;
+ do
+ {
+ thisResult = rpcgetnextelement_1( &clientID, binding_h );
+
+ if( !thisResult )
+ {
+ RMInit::logOut << endl << "WARNING: RPC NULL POINTER (rpcgetnextelement_1)" << endl << endl;
+ sleep(RMInit::clientcommSleep);
+ }
+ if (rpcRetryCounter > RMInit::clientcommMaxRetry)
+ {
+ RMInit::logOut << "RPC call 'rpcgetnextelement' failed" << endl;
+ throw r_Error(CLIENTCOMMUICATIONFAILURE);
+ }
+ rpcRetryCounter++;
+ }while( thisResult == 0 );
+ setRPCInactive();
+
+ rpcStatus = thisResult->status;
+
+ if( rpcStatus == 2 )
+ {
+ RMInit::logOut << "Error: getElementCollection(...) - no transfer collection or empty transfer collection" << endl;
+ throw r_Error( r_Error::r_Error_TransferFailed );
+ }
+
+ // create new collection element, use type of collection resultColl
+ r_Ref_Any element;
+ const r_Type* elementType = resultColl.get_element_type_schema();
+
+ // convert the endianness before creating the new element!
+ if (endianClient != endianServer)
+ {
+ if (endianClient == 0)
+ elementType->convertToBigEndian(thisResult->data.confarray_val, 1);
+ else
+ elementType->convertToLittleEndian(thisResult->data.confarray_val, 1);
+ }
+
+ switch( elementType->type_id() )
+ {
+ case r_Type::BOOL:
+ case r_Type::CHAR:
+ case r_Type::OCTET:
+ case r_Type::SHORT:
+ case r_Type::USHORT:
+ case r_Type::LONG:
+ case r_Type::ULONG:
+ case r_Type::FLOAT:
+ case r_Type::DOUBLE:
+ {
+ element = new r_Primitive( thisResult->data.confarray_val, (r_Primitive_Type*) elementType );
+ r_Transaction::actual_transaction->add_object_list( r_Transaction::SCALAR, (void*) element );
+ }
+ break;
+
+ case r_Type::COMPLEXTYPE1:
+ case r_Type::COMPLEXTYPE2:
+ element = new r_Complex(thisResult->data.confarray_val, (r_Complex_Type *)elementType);
+ r_Transaction::actual_transaction->add_object_list(r_Transaction::SCALAR, (void *)element);
+ break;
+
+ case r_Type::STRUCTURETYPE:
+ {
+ element = new r_Structure( thisResult->data.confarray_val, (r_Structure_Type*) elementType );
+ r_Transaction::actual_transaction->add_object_list( r_Transaction::SCALAR, (void*) element );
+ }
+ break;
+
+ case r_Type::POINTTYPE:
+ {
+ char* stringRep = new char[thisResult->data.confarray_len+1];
+ strncpy( stringRep, thisResult->data.confarray_val, thisResult->data.confarray_len );
+ stringRep[thisResult->data.confarray_len] = '\0';
+
+ r_Point* typedElement = new r_Point( stringRep );
+ element = typedElement;
+ r_Transaction::actual_transaction->add_object_list( r_Transaction::POINT, (void*) typedElement );
+ delete [] stringRep;
+ }
+ break;
+
+ case r_Type::SINTERVALTYPE:
+ {
+ char* stringRep = new char[thisResult->data.confarray_len+1];
+ strncpy( stringRep, thisResult->data.confarray_val, thisResult->data.confarray_len );
+ stringRep[thisResult->data.confarray_len] = '\0';
+ r_Sinterval* typedElement = new r_Sinterval( stringRep );
+ element = typedElement;
+ r_Transaction::actual_transaction->add_object_list( r_Transaction::SINTERVAL, (void*) typedElement );
+ delete [] stringRep;
+ }
+ break;
+
+ case r_Type::MINTERVALTYPE:
+ {
+ char* stringRep = new char[thisResult->data.confarray_len+1];
+ strncpy( stringRep, thisResult->data.confarray_val, thisResult->data.confarray_len );
+ stringRep[thisResult->data.confarray_len] = '\0';
+
+ r_Minterval* typedElement = new r_Minterval( stringRep );
+ element = typedElement;
+ r_Transaction::actual_transaction->add_object_list( r_Transaction::MINTERVAL, (void*) typedElement );
+ delete [] stringRep;
+ }
+ break;
+
+ case r_Type::OIDTYPE:
+ {
+ char* stringRep = new char[thisResult->data.confarray_len+1];
+ strncpy( stringRep, thisResult->data.confarray_val, thisResult->data.confarray_len );
+ stringRep[thisResult->data.confarray_len] = '\0';
+
+ r_OId* typedElement = new r_OId( stringRep );
+ element = typedElement;
+ r_Transaction::actual_transaction->add_object_list( r_Transaction::OID, (void*) typedElement );
+ delete [] stringRep;
+ }
+ break;
+ default:
+ RMDBGENTER(2, RMDebug::module_clientcomm, "RpcClientComm", "getElementCollection(...) bad element typeId" << elementType->type_id())
+ break;
+ }
+
+
+ RMInit::logOut << " got element" << endl;
+
+ // now the transfer structure of rpcgetnextmdd can be freed
+ XDRFREE(GetElementRes, thisResult);
+
+ // insert element into result set
+ resultColl.insert_element( element, 1 );
+ }
+
+
+ if(binding_h == NULL) {
+ RMInit::logOut << endl << "RpcClientComm::getElementCollection(resultColl) ERROR: CONNECTION TO SERVER ALREADY CLOSED" << endl << endl;
+ throw r_Error(CONNECTIONCLOSED);
+ }
+
+ unsigned short* rpcStatusPtr = 0;
+
+ setRPCActive();
+ rpcRetryCounter = 0;
+ do
+ {
+ rpcStatusPtr = rpcendtransfer_1( &clientID, binding_h );
+
+ if( !rpcStatusPtr )
+ {
+ RMInit::logOut << endl << "WARNING: RPC NULL POINTER (rpcendtransfer_1)" << endl << endl;
+ sleep(RMInit::clientcommSleep);
+ }
+ if (rpcRetryCounter > RMInit::clientcommMaxRetry)
+ {
+ RMInit::logOut << "RPC call 'rpcendtransfer' failed" << endl;
+ throw r_Error(CLIENTCOMMUICATIONFAILURE);
+ }
+ rpcRetryCounter++;
+ }while( rpcStatusPtr == 0 );
+ setRPCInactive();
+}
+
+unsigned short
+RpcClientComm::getMDDCore( r_Ref< r_GMarray > &mdd, GetMDDRes *thisResult, unsigned int isQuery )
+ throw( r_Error )
+{
+ // create r_Minterval and oid
+ r_Minterval mddDomain( thisResult->domain );
+ r_OId rOId ( thisResult->oid );
+ r_GMarray *marray;
+
+ //cout << "getMDDCore..." << endl;
+ if( isQuery )
+ marray = new( r_Database::actual_database, r_Object::transient, rOId ) r_GMarray();
+ else
+ marray = new( r_Database::actual_database, r_Object::read , rOId ) r_GMarray();
+
+ marray->set_spatial_domain( mddDomain );
+ marray->set_type_by_name ( thisResult->typeName );
+ marray->set_type_structure( thisResult->typeStructure );
+
+ r_Data_Format currentFormat = (r_Data_Format)(thisResult->currentFormat);
+ if (r_Tile_Compression::check_data_format(currentFormat) == 1)
+ currentFormat = r_Array;
+ marray->set_current_format( currentFormat );
+
+ r_Data_Format decompFormat;
+
+ const r_Base_Type *baseType = marray->get_base_type_schema();
+
+ // now the transfer structure of rpcgetnextmdd can be freed
+ XDRFREE(GetMDDRes, thisResult);
+
+ //RMDBGOUTFLUSH( 2, "domain " << mddDomain << " ... " )
+
+ // Variables needed for tile transfer
+ GetTileRes* tileRes=0;
+ unsigned short mddDim = mddDomain.dimension(); // we assume that each tile has the same dimensionality as the MDD
+ r_Minterval tileDomain;
+ r_GMarray* tile; // for temporary tile
+ char* memCopy;
+ unsigned long memCopyLen;
+ int tileCntr = 0;
+ unsigned short tileStatus = 0;
+
+ tileStatus = 2; // call rpcgetnexttile_1 at least once
+
+ while( tileStatus == 2 || tileStatus == 3 ) // while( for all tiles of the current MDD )
+ {
+
+ if(binding_h == NULL) {
+ RMInit::logOut << endl << "RpcClientComm::getMDDCore(mdd, thisResult, isQuery) ERROR: CONNECTION TO SERVER ALREADY CLOSED" << endl << endl;
+ throw r_Error(CONNECTIONCLOSED);
+ }
+
+ setRPCActive();
+ rpcRetryCounter = 0;
+ do
+ {
+ tileRes = rpcgetnexttile_1( &clientID, binding_h );
+
+ if( !tileRes )
+ {
+ RMInit::logOut << endl << "WARNING: RPC NULL POINTER (rpcgetnexttile_1)" << endl << endl;
+ sleep(RMInit::clientcommSleep);
+ }
+ if (rpcRetryCounter > RMInit::clientcommMaxRetry)
+ {
+ RMInit::logOut << "RPC call 'rpcgetnexttile' failed" << endl;
+ throw r_Error(CLIENTCOMMUICATIONFAILURE);
+ }
+ rpcRetryCounter++;
+ } while( tileRes == 0 );
+RMDBGIF(20, RMDebug::module_tools, "WAITRECEIVEDTILE", \
+ RMInit::dbgOut << "Waiting 100 sec after receive tile\n" << std::endl; \
+ sleep(100); \
+ RMInit::dbgOut << "Continue now\n" << std::endl; );
+ setRPCInactive();
+
+
+ tileStatus = tileRes->status;
+
+ if( tileStatus == 4 )
+ {
+ XDRFREE(GetTileRes, tileRes);
+
+ RMInit::logOut << "Error: rpcGetNextTile(...) - no tile to transfer or empty transfer collection" << endl;
+ throw r_Error( r_Error::r_Error_TransferFailed );
+ }
+
+ // take cellTypeLength for current MDD of the first tile
+ if( tileCntr == 0 )
+ marray->set_type_length( tileRes->marray->cellTypeLength );
+
+ tileDomain = r_Minterval( tileRes->marray->domain );
+ memCopyLen = tileDomain.cell_count() * marray->get_type_length(); // cell type length of the tile must be the same
+ if (memCopyLen < tileRes->marray->data.confarray_len)
+ memCopyLen = tileRes->marray->data.confarray_len; // may happen when compression expands
+ memCopy = new char[ memCopyLen ];
+
+ // create temporary tile
+ tile = new r_GMarray();
+ tile->set_spatial_domain( tileDomain );
+ tile->set_array( memCopy );
+ tile->set_array_size( memCopyLen );
+ tile->set_type_length( tileRes->marray->cellTypeLength );
+ tileCntr++;
+
+ // Variables needed for block transfer of a tile
+ unsigned long blockOffset = 0;
+ unsigned short subStatus = 3;
+ currentFormat = (r_Data_Format)(tileRes->marray->currentFormat);
+
+ switch( tileStatus )
+ {
+ case 3: // at least one block of the tile is left
+
+ // Tile arrives in several blocks -> put them together
+ concatArrayData(tileRes->marray->data.confarray_val, tileRes->marray->data.confarray_len, memCopy, memCopyLen, blockOffset);
+ XDRFREE(GetTileRes, tileRes);
+
+ while( subStatus == 3 )
+ {
+
+ if(binding_h == NULL) {
+ RMInit::logOut << endl << "RpcClientComm::getMDDCore(mdd, thisResult, isQuery) ERROR: CONNECTION TO SERVER ALREADY CLOSED" << endl << endl;
+ throw r_Error(CONNECTIONCLOSED);
+ }
+
+ setRPCActive();
+ rpcRetryCounter = 0;
+ do
+ {
+ tileRes = rpcgetnexttile_1( &clientID, binding_h );
+
+ if( !tileRes )
+ {
+ RMInit::logOut << endl << "WARNING: RPC NULL POINTER (rpcgetnexttile_1)" << endl << endl;
+ sleep(RMInit::clientcommSleep);
+ }
+ if (rpcRetryCounter > RMInit::clientcommMaxRetry)
+ {
+ RMInit::logOut << "RPC call 'rpcgetnexttile' failed" << endl;
+ throw r_Error(CLIENTCOMMUICATIONFAILURE);
+ }
+ rpcRetryCounter++;
+ } while( tileRes == 0 );
+ setRPCInactive();
+
+ subStatus = tileRes->status;
+
+ if( subStatus == 4 )
+ {
+ XDRFREE(GetTileRes, tileRes);
+
+ RMInit::logOut << "Error: rpcGetNextTile(...) - no tile to transfer or empty transfer collection" << endl;
+ throw r_Error( r_Error::r_Error_TransferFailed );
+ }
+
+ // RMInit::logOut << "Status: " << subStatus << endl;
+ // RMInit::logOut << "BlockOffset: " << blockOffset << " Size: " << tileRes->marray->data.confarray_len << endl;
+ concatArrayData(tileRes->marray->data.confarray_val, tileRes->marray->data.confarray_len, memCopy, memCopyLen, blockOffset);
+ XDRFREE(GetTileRes, tileRes);
+ }
+
+ tileStatus = subStatus;
+ break;
+
+ default: // tileStatus = 0,3 last block of the current tile
+
+ // Tile arrives as one block.
+ concatArrayData(tileRes->marray->data.confarray_val, tileRes->marray->data.confarray_len, memCopy, memCopyLen, blockOffset);
+ // RMInit::logOut << "Internal size: " << tileRes->marray->data.confarray_len << endl;
+
+ XDRFREE(GetTileRes, tileRes);
+ break;
+ }
+
+ // uncompress the tile if necessary
+ decompFormat = doTransferDecompression( tile, baseType, currentFormat, blockOffset );
+
+ char* marrayData = NULL;
+ // Now the tile is transferred completely, insert it into current MDD
+ if( tileStatus < 2 && tileCntr == 1 && (tile->spatial_domain() == marray->spatial_domain()))
+ {
+ // MDD consists of just one tile that is the same size of the mdd
+
+ // simply take the data memory of the tile
+ marray->set_array( tile->get_array() );
+ marray->set_array_size( tile->get_array_size() );
+ tile->set_array( 0 );
+ }
+ else
+ {
+ // MDD consists of more than one tile or the tile does not cover the whole domain
+
+ r_Bytes size = mddDomain.cell_count() * marray->get_type_length();
+
+ if( tileCntr == 1 )
+ {
+ // allocate memory for the MDD
+ marrayData = new char[ size ];
+ memset(marrayData, 0, size);
+
+ marray->set_array( marrayData );
+ }
+ else
+ marrayData = marray->get_array();
+
+
+ // copy tile data into MDD data space (optimized, relying on the internal representation of an MDD )
+ char* mddBlockPtr;
+ char* tileBlockPtr = tile->get_array();
+ unsigned long blockCells = tileDomain[tileDomain.dimension()-1].high()-tileDomain[tileDomain.dimension()-1].low()+1;
+ unsigned long blockSize = blockCells * marray->get_type_length();
+ unsigned long blockNo = tileDomain.cell_count() / blockCells;
+
+ for( unsigned long blockCtr = 0; blockCtr < blockNo; blockCtr++ )
+ {
+ mddBlockPtr = marrayData + marray->get_type_length()*mddDomain.cell_offset( tileDomain.cell_point( blockCtr * blockCells ) );
+ memcpy( (void*)mddBlockPtr, (void*)tileBlockPtr, (size_t)blockSize );
+ tileBlockPtr += blockSize;
+ }
+
+ // former non-optimized version
+ // for( i=0; i<tileDomain->cell_count(); i++ )
+ // (*marray)[tileDomain->cell_point( i )] = (*tile)[tileDomain->cell_point( i )];
+
+ marray->set_array_size( size );
+ }
+
+ // delete temporary tile
+ delete tile;
+
+ } // end while( MDD is not transferred completely )
+
+
+ mdd = r_Ref<r_GMarray>( marray->get_oid(), marray );
+
+ return tileStatus;
+}
+
+int RpcClientComm::concatArrayData( const char *source, unsigned long srcSize, char *&dest, unsigned long &destSize, unsigned long &destLevel )
+{
+ if (destLevel + srcSize > destSize)
+ {
+ // need to extend dest
+ unsigned long newSize = destLevel + srcSize;
+ char *newArray;
+
+ // allocate a little extra if we have to extend
+ newSize = newSize + newSize / 16;
+
+// RMDBGOUT( 1, "RpcClientComm::concatArrayData(): need to extend from " << destSize << " to " << newSize );
+
+ if ((newArray = new char[newSize]) == NULL)
+ return -1;
+
+ memcpy(newArray, dest, destLevel);
+ delete [] dest;
+ dest = newArray;
+ destSize = newSize;
+ }
+
+ memcpy(dest + destLevel, source, srcSize);
+ destLevel += srcSize;
+
+ return 0;
+}
+
+
+void RpcClientComm::triggerAliveSignal()
+{
+ aliveSignalRemaining = 1;
+
+ sendAliveSignal();
+}
+
+
+void RpcClientComm::sendAliveSignal()
+{
+ if( aliveSignalRemaining && !checkRPCActive() )
+ {
+ aliveSignalRemaining = 0;
+
+ unsigned long myID = getClientID();
+
+ // tell the server I'm alive
+
+ // determine my binding handle
+ CLIENT* myHandle = getBindingHandle();
+
+ unsigned short* rpcStatusPtr = 0;
+
+ setRPCActive();
+ rpcRetryCounter = 0;
+ do
+ {
+ rpcStatusPtr = rpcalive_1( &myID, myHandle );
+
+ if( !rpcStatusPtr )
+ {
+ RMInit::logOut << endl << "WARNING: RPC NULL POINTER (rpcalive_1)" << endl << endl;
+ sleep(RMInit::clientcommSleep);
+ }
+ if (rpcRetryCounter > RMInit::clientcommMaxRetry)
+ {
+ RMInit::logOut << "RPC call 'rpcalive' failed" << endl;
+ throw r_Error(CLIENTCOMMUICATIONFAILURE);
+ }
+ rpcRetryCounter++;
+ }while( rpcStatusPtr == 0 );
+ setRPCInactive();
+ RMDBGONCE(3, RMDebug::module_clientcomm, "RpcClientComm", "sent alive signal")
+
+#ifdef __VISUALC__
+ timeKillEvent(timerid);
+ timerid = timeSetEvent(ALIVEINTERVAL * 1000, 0, TimerProc, NULL, TIME_PERIODIC);
+#else
+ // Re-initialize the signal handler to point to this function
+ signal( SIGALRM, aliveSignal );
+
+ // Reset the alarm
+ alarm( ALIVEINTERVAL );
+#endif
+ }
+}
+
+
+int RpcClientComm::setTransferFormat( r_Data_Format format, const char* formatParams )
+{
+ transferFormat = format;
+
+ if (transferFormatParams != NULL)
+ {
+ free(transferFormatParams);
+ transferFormatParams = NULL;
+ }
+ if (formatParams != NULL)
+ {
+ transferFormatParams = (char*)mymalloc(strlen(formatParams)+1);
+ strcpy(transferFormatParams, formatParams);
+
+ // extract ``exactformat'' if present
+ clientParams->process(transferFormatParams);
+ }
+
+ SetServerTransferParams* params = new SetServerTransferParams;
+
+ params->clientID = getClientID();
+ params->format = (unsigned short)format;
+ if (transferFormatParams == NULL)
+ params->formatParams = "";
+ else
+ params->formatParams = transferFormatParams;
+
+ CLIENT* myHandle = getBindingHandle();
+
+ unsigned short* rpcStatusPtr = 0;
+
+ setRPCActive();
+ rpcRetryCounter = 0;
+ do
+ {
+ rpcStatusPtr = rpcsetservertransfer_1( params, myHandle );
+
+ if (!rpcStatusPtr)
+ {
+ RMInit::logOut << endl << "WARNING: RPC NULL POINTER (rpcsetservertransfer_1)" << endl << endl;
+ sleep(RMInit::clientcommSleep);
+ }
+ if (rpcRetryCounter > RMInit::clientcommMaxRetry)
+ {
+ RMInit::logOut << "RPC call 'rpcsetservertransfer' failed" << endl;
+ throw r_Error(CLIENTCOMMUICATIONFAILURE);
+ }
+ rpcRetryCounter++;
+ }
+ while ( rpcStatusPtr == 0 );
+ setRPCInactive();
+
+ delete params;
+
+ return (int)(*rpcStatusPtr);
+}
+
+
+int RpcClientComm::setStorageFormat( r_Data_Format format, const char *formatParams )
+{
+ storageFormat = format;
+
+ if (storageFormatParams != NULL)
+ {
+ free(storageFormatParams);
+ storageFormatParams = NULL;
+ }
+ if (formatParams != NULL)
+ {
+ storageFormatParams = (char*)mymalloc(strlen(formatParams) + 1);
+ strcpy(storageFormatParams, formatParams);
+ // extract ``compserver'' if present
+ clientParams->process(storageFormatParams);
+ }
+
+ SetServerTransferParams *params = new SetServerTransferParams;
+
+ params->clientID = getClientID();
+ params->format = (unsigned short)format;
+ if (storageFormatParams == NULL)
+ params->formatParams = "";
+ else
+ params->formatParams = storageFormatParams;
+
+ CLIENT *myHandle = getBindingHandle();
+
+ unsigned short *rpcStatusPtr = 0;
+
+ setRPCActive();
+ rpcRetryCounter = 0;
+ do
+ {
+ rpcStatusPtr = rpcsetserverstorage_1( params, myHandle );
+ if( !rpcStatusPtr )
+ {
+ RMInit::logOut << endl << "WARNING: RPC NULL POINTER (rpcsetserverstorage_1)" << endl << endl;
+ sleep(RMInit::clientcommSleep);
+ }
+ if (rpcRetryCounter > RMInit::clientcommMaxRetry)
+ {
+ RMInit::logOut << "RPC call 'rpcsetserverstorage' failed" << endl;
+ throw r_Error(CLIENTCOMMUICATIONFAILURE);
+ }
+ rpcRetryCounter++;
+ }
+ while ( rpcStatusPtr == NULL );
+ setRPCInactive();
+
+ delete params;
+
+ return (int)(*rpcStatusPtr);
+}
+
+
+void
+RpcClientComm::setRPCActive()
+{
+ rpcActive = 1;
+}
+
+
+
+void
+RpcClientComm::setRPCInactive()
+{
+ rpcActive = 0;
+ sendAliveSignal();
+}
+
+
+int
+RpcClientComm::checkRPCActive()
+{
+ return rpcActive;
+}
+
+const char *
+RpcClientComm::getExtendedErrorInfo()
+ throw(r_Error)
+{
+ if(binding_h == NULL) {
+ RMInit::logOut << endl << "RpcClientComm::getMDDCollection(mddColl, isQuery) ERROR: CONNECTION TO SERVER ALREADY CLOSED" << endl << endl;
+ throw r_Error(CONNECTIONCLOSED);
+ }
+
+ static char *errorInfo = NULL;
+
+ GetExtendedErrorInfo *result=NULL;
+
+ int dummy;
+
+ if(errorInfo) delete[] errorInfo;
+
+ setRPCActive();
+
+ rpcRetryCounter = 0;
+ do{
+
+ result = rpcgeterrorinfo_1(&dummy, binding_h);
+ if( !result )
+ {
+ RMInit::logOut << endl << "WARNING: RPC NULL POINTER (rpcalive_1)" << endl << endl;
+ sleep(RMInit::clientcommSleep);
+ }
+ if (rpcRetryCounter > RMInit::clientcommMaxRetry)
+ {
+ RMInit::logOut << "RPC call 'rpcgeterrorinfo' failed" << endl;
+ throw r_Error(CLIENTCOMMUICATIONFAILURE);
+ }
+ rpcRetryCounter++;
+
+ }while(!result);
+
+ setRPCInactive();
+
+ errorInfo = new char[strlen(result->errorText)+1];
+ strcpy(errorInfo,result->errorText);
+
+ return errorInfo;
+}
+
+
+#define MAXMSG 512
+
+int RpcClientComm::readWholeMessage(int socket,char *destBuffer,int buffSize)
+ {
+ // we read what is comming in until we encounter a '\0'
+ // this is our end-sign.
+ int totalLength=0;
+ int redNow;
+ while(1)
+ {
+ redNow = read(socket,destBuffer+totalLength,buffSize-totalLength);
+ if(redNow == -1)
+ { if(errno == EINTR) continue; // read was interrupted by signal
+
+ return -1; // another error
+ }
+ totalLength+=redNow;
+
+ if(destBuffer[totalLength-1]==0) break; // THE END
+ }
+ return totalLength;
+ }
+
+int RpcClientComm::writeWholeMessage(int socket,char *destBuffer,int buffSize)
+ {
+ // we write the whole message, including the ending '\0', which is already in
+ // the buffSize provided by the caller
+ int totalLength=0;
+ int writeNow;
+ while(1)
+ {
+ writeNow = write(socket,destBuffer+totalLength,buffSize-totalLength);
+ if(writeNow == -1)
+ { if(errno == EINTR) continue; // read was interrupted by signal
+
+ return -1; // another error
+ }
+ totalLength+=writeNow;
+
+ if( totalLength==buffSize ) break; // THE END
+ }
+ return totalLength;
+ }
+
+void
+RpcClientComm::setMaxRetry(unsigned int newMaxRetry)
+ {
+ RMInit::clientcommMaxRetry = newMaxRetry;
+ }
+
+unsigned int
+RpcClientComm::getMaxRetry()
+ {
+ return RMInit::clientcommMaxRetry;
+ }
+
+
+static void pause(int retryCount)
+ {
+ unsigned int milisec = 50 + retryCount * 50;
+ if(milisec > 1000) milisec = 1000;
+
+ timeval tv;
+ tv.tv_sec = milisec / 1000;
+ tv.tv_usec = milisec * 1000;
+
+ select(0,NULL,NULL,NULL,&tv);
+ }
+
+int
+RpcClientComm::getFreeServer(unsigned short readOnly)
+ {
+ //RMInit::logOut << "getFreeServer in"<<endl;
+ for(int retryCount=0;;retryCount++)
+ {
+ try
+ {
+ executeGetFreeServer(readOnly);
+
+ // if no error, we have the server, so break
+ break;
+ }
+ catch(r_Error &e)
+ {
+ int errorno = e.get_errorno();
+ //cerr<<"errorno="<<errorno;
+ if(( errorno==801 || errorno==805 || errorno==806) && retryCount < RMInit::clientcommMaxRetry)
+ { //cerr<<" retry="<<retryCount<<endl;
+ RMInit::logOut << "Connection to RasDaMan failed with " << errorno << ": retry " << retryCount << endl;
+ pause(retryCount);
+ }
+ else throw;
+ }
+ }
+ //RMInit::logOut << "getFreeServer out"<<endl;
+ return 1;
+ }
+int
+RpcClientComm::executeGetFreeServer(unsigned short readOnly)
+ {
+ static char myRasmgrID[100]="";
+ if(myRasmgrID[0]==0)
+ { unsigned int hostid = gethostid();
+ unsigned int pid = getpid();
+ sprintf(myRasmgrID,"%u:%u",hostid,pid);
+ }
+
+ char message[MAXMSG];
+ char header[MAXMSG];
+ char body[MAXMSG];
+ sprintf(header,"POST getfreeserver HTTP/1.1\r\nAccept: text/plain\r\nUserAgent: RasClient/1.0\r\nAuthorization: ras %s\r\nContent-length:",identificationString);
+ sprintf(body,"%s RPC %s %s",dataBase,(readOnly ? "ro":"rw"), myRasmgrID);
+ sprintf(message,"%s %d\r\n\r\n%s",header,strlen(body)+1,body);
+
+ struct protoent* getprotoptr = getprotobyname("tcp");
+
+ struct hostent *hostinfo = gethostbyname(rasmgrHost);
+ if(hostinfo==NULL)
+ { RMInit::logOut << "Error locating RasMGR" << rasmgrHost <<" ("<<strerror(errno)<<')'<<endl;
+ throw r_Error( r_Error::r_Error_ServerInvalid );
+ }
+
+ sockaddr_in internetSocketAddress;
+
+ internetSocketAddress.sin_family=AF_INET;
+ internetSocketAddress.sin_port=htons(rasmgrPort);
+ internetSocketAddress.sin_addr=*(struct in_addr*)hostinfo->h_addr;
+
+
+ int sock;
+ bool ok = false;
+ int retry;
+ for(retry=0;retry<RMInit::clientcommMaxRetry * 40 ;retry++) // this has to be 5000 or so, now that counter is 120 default (later we'll make this better)
+ {
+ sock=socket(PF_INET,SOCK_STREAM,getprotoptr->p_proto);
+ //cout<<"Socket="<<sock<<" protocol(tcp)="<<getprotoptr->p_proto<<endl;
+ if(sock<0) { //cerr<<"getFreeServer: cannot open socket to RasMGR, ("<<strerror(errno)<<')'<<endl;
+ if(retry==0) RMInit::logOut << "getFreeServer: cannot open socket to RasMGR, ("<<strerror(errno)<<')'<<endl;
+ sleep(RMInit::clientcommSleep);
+ continue;
+ }
+
+ if(connect(sock,(struct sockaddr*)&internetSocketAddress,sizeof(internetSocketAddress)) < 0)
+ { if(retry==0) RMInit::logOut <<"getFreeServer: Connection to RasMGR failed! ("<<strerror(errno)<<')'<<endl;
+ close(sock);
+ sleep(RMInit::clientcommSleep);
+ continue;
+ }
+
+ ok = true;
+ break;
+ }
+ if(retry) RMInit::logOut << "getFreeServer: tried " << retry+1 << " times " <<endl;
+
+ if( !ok ){ RMInit::logOut << "getFreeServer: I give up, sorry" <<endl;
+ close(sock);
+ throw r_Error( r_Error::r_Error_ServerInvalid );
+ }
+
+ //write_to_server
+ int nbytes=writeWholeMessage(sock,message,strlen(message)+1);
+
+ if(nbytes<0)
+ { RMInit::logOut << "Error writing message to RasMGR" << rasmgrHost << " ("<<strerror(errno)<<')' << endl;
+ close(sock);
+ throw r_Error( r_Error::r_Error_ServerInvalid );
+ }
+
+ //wait and read answer
+ nbytes=readWholeMessage(sock,message,MAXMSG);
+ close(sock);
+
+ if(nbytes<0)
+ { RMInit::logOut << "Error reading answer from RasMGR" << rasmgrHost <<" ("<<strerror(errno)<<')'<<endl;
+ throw r_Error( r_Error::r_Error_ServerInvalid );
+ }
+
+ // and now, analize answer
+ // first line is: HTTP/1.1 code answertext(CRLF)
+ char *p=strstr(message," "); //looks for the first white space to locate status-code
+
+ int statusCode=strtoul( p, (char **)NULL, 10);
+
+ char *pEOL=strstr(p,"\r\n"); // locate CRLF
+ if(!pEOL)
+ { RMInit::logOut << "Invalid answer from RasMGR" << endl;
+ throw r_Error( r_Error::r_Error_ServerInvalid );
+ }
+
+ if(statusCode==200)
+ { // It's OK
+ char *addr = strstr(message,"\r\n\r\n")+4; //looks for the address of server
+
+ addr = strtok(addr," \r\n\t"); //isolates the RasMGR host name
+
+ char *portString = strtok(NULL," \r\n\t"); //looks for the rpc_prognum, sended as string
+
+ char *capab = strtok(NULL," \r\n\t");
+
+ if(portString && addr && capab)
+ {
+ strcpy(serverHost,addr);
+ RPCIF_PARA= strtoul( portString, (char **)NULL, 0); // requires 0x if base16
+ strcpy(capability,capab);
+ //cout<<"Got server="<<serverHost<<" servnr=0x"<<hex<<RPCIF_PARA<<dec<<endl;
+ }
+ else
+ { RMInit::logOut << "Invalid answer from RasMGR" << endl;
+ throw r_Error( r_Error::r_Error_ServerInvalid );
+ }
+
+ }
+ else
+ {
+ char *errText = strstr(message,"\r\n\r\n")+4;
+ //cerr<<"cucu Error "<<errText<<endl;
+ //RMInit::logOut << "Error "<<errText<< endl;
+
+ int errorCode = strtoul(errText, (char**)NULL, 0);
+ //cerr <<" throw "<< errorCode <<endl;
+
+ switch(errorCode)
+ { case 802:
+ case 803:
+ case 804: throw r_Error( r_Error::r_Error_AccesDenied,errorCode);
+ break;
+ case 801:
+ case 805:
+ case 806: throw r_Error( r_Error::r_Error_SystemOverloaded,errorCode);
+ break;
+ case 807: throw r_Error( r_Error::r_Error_DatabaseUnknown,errorCode);
+ break;
+ default :
+ throw r_Error( r_Error::r_Error_General,808 );
+ break;
+ }
+ }
+ return 1;
+ }
+
+
+const char*
+RpcClientComm::getServerName()
+ { return serverHost;
+ }
+
+
+int
+RpcClientComm::connectToServer(unsigned short readOnly)
+ {
+ disconnectFromServer(); // just to be sure
+ getFreeServer(readOnly);
+
+#if (defined(__VISUALC__) || defined(CYGWIN))
+ RMInit::logOut << "Initializing the NT-RPC ..." << flush;
+ rpc_nt_init();
+ RMInit::logOut << "OK" << endl;
+#endif
+ RMInit::logOut << "Creating the binding..." << flush;
+#if (defined(__VISUALC__) || defined(CYGWIN))
+ binding_h = client_create( (char *) serverHost, RPCIF_PARA, RPCIFVERS, "tcp" );
+#else
+ binding_h = clnt_create( (char *) serverHost, RPCIF_PARA, RPCIFVERS, "tcp" );
+ if( !binding_h )
+ {
+ cout << endl;
+ clnt_pcreateerror("");
+ }
+#endif
+ if( !binding_h )
+ {
+ RMInit::logOut << "FAILED" << endl;
+ throw r_Error( r_Error::r_Error_ServerInvalid );
+ }
+ else
+ {
+ RMInit::logOut << "OK" << endl;
+ serverUp = 1;
+ }
+
+ /* Default timeout can be changed using clnt_control() */
+ // moved constant into raslib/riminit.hh, changed 25->3 -- PB 2005-sep-09
+ static struct timeval timeout = { RPC_TIMEOUT, 0 };
+
+#if (defined(__VISUALC__) || defined(CYGWIN))
+ client_control( binding_h, CLGET_TIMEOUT, (char *)&timeout );
+#else
+ clnt_control( binding_h, CLGET_TIMEOUT, (char *)&timeout );
+#endif
+ RMInit::logOut << "Timeout: " << timeout.tv_sec << " sec " << timeout.tv_usec << " microsec" << endl;
+
+ timeout.tv_sec = RMInit::timeOut;
+ timeout.tv_usec = 0;
+#if (defined(__VISUALC__) || defined(CYGWIN))
+ client_control( binding_h, CLSET_TIMEOUT, (char *)&timeout );
+#else
+ clnt_control( binding_h, CLSET_TIMEOUT, (char*)&timeout );
+#endif
+
+ RMInit::logOut << "Timeout set to " << timeout.tv_sec / 60. << " min." << endl;
+
+#ifndef __VISUALC__
+ // Install a signal handler for the alive signal
+ signal( SIGALRM, aliveSignal );
+#endif
+ return 1;
+}
+
+int RpcClientComm::disconnectFromServer() throw()
+ {
+ if(!binding_h)
+ {
+ RMInit::logOut << "Disconnect from server: no binding" << endl;
+ return -1;
+ }
+ else
+ {
+ RMInit::logOut << "Disconnect from server: binding ok" << endl;
+ }
+
+#ifdef __VISUALC__
+ RMInit::logOut << "Deleting the binding...";
+ client_destroy(binding_h);
+ RMInit::logOut << "OK" << endl;
+ timeKillEvent(timerid);
+ RMInit::logOut << "Deactivating the NT-RPC feature...";
+ rpc_nt_exit();
+ RMInit::logOut << "OK" << endl;
+#else
+ RMInit::logOut << "Deleting the binding...";
+#ifdef CYGWIN
+ client_destroy(binding_h);
+ rpc_nt_exit();
+#else
+ clnt_destroy(binding_h);
+#endif
+ RMInit::logOut << "OK" << endl;
+
+ if (storageFormatParams != NULL)
+ free(storageFormatParams);
+ storageFormatParams = NULL;
+
+ if (transferFormatParams != NULL)
+ free(transferFormatParams);
+ transferFormatParams = NULL;
+
+ binding_h = NULL;
+
+ // suspend alarm timer for the periodical alive signal
+ alarm( 0 );
+#endif
+
+ return 0;
+ }
+
+// we will make this nicer after the D-day (this means when we change to para-proc
+int messageDigest(const char *input,char *output,const char *mdName);
+
+void
+RpcClientComm::setUserIdentification(const char *userName, const char *plainTextPassword)
+ {
+ char digest[33]="";
+ messageDigest(plainTextPassword,digest,"MD5");
+ sprintf(identificationString,"%s:%s",userName,digest);
+ }
+
+int messageDigest(const char *input,char *output,const char *mdName)
+ {
+
+ EVP_MD_CTX mdctx;
+ const EVP_MD *md;
+ unsigned int md_len, i;
+ unsigned char md_value[100];
+
+ OpenSSL_add_all_digests();
+
+ md = EVP_get_digestbyname(mdName);
+
+ if(!md) return 0;
+
+ EVP_DigestInit(&mdctx, md);
+ EVP_DigestUpdate(&mdctx,input, strlen(input));
+ EVP_DigestFinal(&mdctx, md_value, &md_len);
+
+ for(i = 0; i < md_len; i++) sprintf(output+i+i,"%02x", md_value[i]);
+
+ return strlen(output);
+ }
+
+unsigned long
+RpcClientComm::getClientID() const
+{
+ return clientID;
+}
+
+
+CLIENT*
+RpcClientComm::getBindingHandle() const
+{
+ return binding_h;
+}
+
+
+void RpcClientComm::setTimeoutInterval(int seconds){ };
+
+int RpcClientComm::getTimeoutInterval() { return 0;};
+
diff --git a/clientcomm/rpcclientcomm.hh b/clientcomm/rpcclientcomm.hh
new file mode 100644
index 0000000..d07fa68
--- /dev/null
+++ b/clientcomm/rpcclientcomm.hh
@@ -0,0 +1,414 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: rpcclientcomm.hh
+ *
+ * MODULE: clientcomm
+ * CLASS: RpcClientComm
+ *
+ * COMMENTS:
+ * None
+*/
+
+// Everything commented out with /* RNP RNP*/ is done because of the switch to RNP
+
+#ifndef RPCCLIENTCOMM_HH
+#define RPCCLIENTCOMM_HH
+
+#include "clientcomm.hh"
+
+/* RNP
+#include "raslib/rminit.hh"
+#include "raslib/error.hh"
+#include "rasodmg/oqlquery.hh"
+#include "rasodmg/marray.hh"
+
+#include "raslib/primitivetype.hh"
+RNP */
+
+#ifdef __VISUALC__
+extern "C"
+{
+#include <rpc/rpc.h>
+}
+#else
+#include <rpc/rpc.h>
+#endif
+
+#ifndef _RPCIF_
+ #define _RPCIF_
+ #include "clientcomm/rpcif.h"
+#endif
+
+
+/* RNP
+template <class T> class r_Set;
+class r_Ref_Any;
+class r_Base_Type;
+class r_Parse_Params;
+RNP */
+
+
+//@ManMemo: Module: {\bf clientcomm}
+
+/*@Doc:
+
+The class ClientComm represents {\bf one} RPC connection between
+{\bf one} client entity (e.g. an object of class \Ref{r_Database}) and
+the server. Therefore, the host name has to be provided at
+the constructor.
+Basically, all methods of a Clientcomm object map directly
+to the corresponding RPC calls. All public clientcomm methods
+may throw exceptions of type {\tt r_Error_TransferFailed} if the
+communication breaks down during RPC execution.
+
+*/
+
+class RpcClientComm : public ClientComm
+{
+ public:
+ /// constructor getting the host name of the rasmgr host and it's listening port (default 7001).
+ RpcClientComm( const char* rasmgrHost, int rasmgrPort = RASMGRPORT ) throw( r_Error );
+
+ /*@Doc:
+ May throw an exception of type {\tt r_Error_HostInvalid} if the hostname
+ cannot be successfully resolved and an exception of type {\tt r_Error_ServerInvalid}
+ if there is no RasDaMan RPC server running on the designated host.
+ */
+
+ /// destructor (closes the connection and releases resources)
+ ~RpcClientComm() throw();
+
+ bool effectivTypeIsRNP() throw();
+
+ //@Man: Database methods
+ //@{
+ ///
+
+ /// open database
+ int openDB( const char* database );
+ /// close current database
+ int closeDB();
+ /// create a database
+ int createDB( const char* name ) throw(r_Error);
+ /// destroy a database
+ int destroyDB( const char* name ) throw(r_Error);
+
+ ///
+ //@}
+
+ //@Man: Transaction methods
+ //@{
+ ///
+
+ /// begin transaction
+ int openTA( unsigned short readOnly = 0 ) throw(r_Error);
+ /// commit current transaction
+ int commitTA() throw(r_Error);
+ /// abort current transaction
+ int abortTA();
+
+ ///
+ //@}
+
+ //@Man: MDD methods
+ //@{
+ ///
+
+ /// inserts a MDD object in an existing MDD collection on the server
+ void insertMDD( const char* collName, r_GMarray* mar ) throw( r_Error );
+ /// gets MDD object by oid
+ r_Ref_Any getMDDByOId( const r_OId& oid ) throw( r_Error );
+
+ ///
+ //@}
+
+ //@Man: Collection methods
+ //@{
+ ///
+
+ /// creates an empty MDD collection on the server
+ void insertColl( const char* collName, const char* typeName, const r_OId& oid ) throw( r_Error );
+ /// deletes an MDD collection by name
+ void deleteCollByName( const char* collName ) throw( r_Error );
+ /// deletes an object by oid (right now, objects are collection only)
+ void deleteObjByOId( const r_OId& oid ) throw( r_Error );
+ /// removes an object from a collection
+ void removeObjFromColl( const char* name, const r_OId& oid ) throw ( r_Error );
+ /// gets collection by name
+ r_Ref_Any getCollByName( const char* name ) throw( r_Error );
+ /// gets collection by oid
+ r_Ref_Any getCollByOId ( const r_OId& oid ) throw( r_Error );
+ /// gets collection references by name
+ r_Ref_Any getCollOIdsByName( const char* name ) throw( r_Error );
+ /// gets collection references by oid
+ r_Ref_Any getCollOIdsByOId ( const r_OId& oid ) throw( r_Error );
+
+ ///
+ //@}
+
+ //@Man: Query methods
+ //@{
+ ///
+
+ /// query execution
+ void executeQuery( const r_OQL_Query& query, r_Set< r_Ref_Any >& result ) throw( r_Error );
+ /*@Doc:
+ Executes a retrieval query of type \Ref{r_OQL_Query} and returns the result. Every
+ MDD object of the MDD collection is fetched from the server and inserted
+ in the resulting \Ref{r_Set}.
+ */
+
+ /// update execution
+ void executeQuery( const r_OQL_Query& query ) throw( r_Error );
+ /*@Doc:
+ Executes an update query of type \Ref{r_OQL_Query}.
+ */
+
+ ///
+ //@}
+
+
+ //@Man: System methods
+ //@{
+ ///
+
+ /// get new oid
+ r_OId getNewOId( unsigned short objType ) throw(r_Error);
+
+ /// get oid type
+ unsigned short getObjectType( const r_OId& oid ) throw(r_Error);
+
+ /// get type structure
+ /// dallocate using delete []
+ char* getTypeStructure( const char* typeName, r_Type_Type typeType ) throw(r_Error);
+
+ ///
+ //@}
+
+ /// provides read access to my clientID
+ inline unsigned long getClientID() const;
+
+ /// provides read access to my binding handle
+ inline CLIENT* getBindingHandle() const;
+
+ //@Man: Methods for asynchronious alive signal concept
+ //@{
+
+ /// triggers an alive signal
+ void triggerAliveSignal();
+ /**
+ First, it sets the switch {\tt aliveSignalRemaining} saying that an alive signal
+ should be send to the server. Then it calls {\tt sendAliveSignal()} to send it
+ immediately if possible.
+ */
+
+ /// send an alive signal if necessary and possible
+ void sendAliveSignal();
+ /**
+ Sends an alive signal to the server if the switch {\tt aliveSignalRemaining} is
+ set and no other RPC is active. If a signal can be sent, {\tt aliveSignalRemaining}
+ is set to 0 again.
+ */
+
+ /// set the preferred transfer format
+ int setTransferFormat( r_Data_Format format, const char* formatParams=NULL );
+
+ int writeWholeMessage(int socket,char *destBuffer,int buffSize);
+ int readWholeMessage(int socket,char *destBuffer,int buffSize);
+
+ /// set the preferred storage format
+ int setStorageFormat( r_Data_Format format, const char *formatParams=NULL );
+
+ /// sets a mutex for RPC
+ void setRPCActive();
+
+ /// frees the mutex for RPC and calls sendAliveSignal() for sending remaining signals
+ void setRPCInactive();
+
+ /// checks if an RPC is active
+ int checkRPCActive();
+
+ /// get extended error information
+ const char *getExtendedErrorInfo() throw(r_Error);
+
+ /// get real server name (the dinamic one, assigned by the RasMGR)
+ const char* getServerName();
+
+ /// user identification for RasMGR
+ void setUserIdentification(const char *userName, const char *plainTextPassword);
+
+ /// set maximum retry to get a server
+ void setMaxRetry(unsigned int newMaxRetry);
+
+ /// get maximum retry to get a server
+ unsigned int getMaxRetry();
+
+ ///
+ //@}
+
+ void setTimeoutInterval(int seconds);
+
+ int getTimeoutInterval();
+
+ private:
+ // binding handle
+ CLIENT* binding_h;
+
+ /// client ID assigned to me by the server (used to index the client table)
+ unsigned long clientID;
+
+#ifdef __VISUALC__
+ // save the timerid for later killing it
+ UINT timerid;
+#endif
+
+ // status variable of the last RPC library function call
+ unsigned long status;
+
+ /// status: server is running
+ int serverUp;
+
+ /// determines if an RPC is active
+ int rpcActive;
+
+ /// switch determining if a alive signal should be send to the server
+ int aliveSignalRemaining;
+
+ /// do transfer decompression
+ r_Data_Format doTransferDecompression( r_GMarray *tile, const r_Base_Type *type,
+ r_Data_Format fmt, unsigned long size );
+ /**
+ internal function for transparent transfer decompression. returns
+ data format of decompressed tile.
+ */
+
+ /// internal function for reading an MDD from the database
+ unsigned short getMDDCore( r_Ref<r_GMarray> &mdd, GetMDDRes *thisResult, unsigned int isQuery ) throw( r_Error );
+
+ /// concatenate data to an array, making sure there are no overflows (used by getMDDCore())
+ int concatArrayData( const char *source, unsigned long srcSize, char *&dest,
+ unsigned long &destSize, unsigned long &destLevel );
+
+ /// internal function for converting a \Ref{r_GMarray} into its RPC representation
+ void getMarRpcRepresentation( const r_GMarray* mar, RPCMarray*& rpcMarray,
+ r_Data_Format initStorageFormat = r_Array,
+ const r_Base_Type *bt = NULL);
+
+ /// internal function for freeing data allocated by getMarRpcRepresentation()
+ void freeMarRpcRepresentation( const r_GMarray* mar, RPCMarray* rpcMarray );
+
+ /// internal function for client/server protocol handling of MDD collection transfer
+ void getMDDCollection( r_Set< r_Ref_Any >& result, unsigned int isQuery ) throw(r_Error);
+
+ /// internal function for client/server protocol handling of non-MDD collection transfer
+ void getElementCollection( r_Set< r_Ref_Any >& result ) throw(r_Error);
+
+ /// endianness of client and server (0 means big endian)
+ int endianServer;
+ int endianClient;
+
+ /// version of server's RPC interface
+ int serverRPCversion;
+
+ /// data format for transfer compression
+ r_Data_Format transferFormat;
+ /// storage format for inserting new tiles
+ r_Data_Format storageFormat;
+ /// transfer format parameters
+ char* transferFormatParams;
+ /// storage format parameters
+ char *storageFormatParams;
+ /// parameter object for configuration
+ r_Parse_Params *clientParams;
+ /**
+ Possible parameters:
+
+ \begin{tabular}{lcl}
+ compserver && int && on insert the server compresses the data, rather than the client\\
+ exactformat && int && the server must provide data in the exact transfer data format\\
+ \end{tabular}
+
+ compserver has to be provided in storageFormatParams during insert
+ exactformat has to be provided in transferFormatParams during download
+ */
+ /// policy is compress-on-server
+ int serverCompresses;
+ /// policy is exact
+ int exactFormat;
+
+ /// dinamically connects to RPC-Server, requesting a readOnly/read-write connection
+ int connectToServer(unsigned short readOnly);
+
+ /// disconnects from RPC-Server after completed request
+ int disconnectFromServer() throw();
+
+ /// requests a free server from the rasmgr, retrying maxRetry times
+ int getFreeServer(unsigned short readOnly);
+
+ /// requests a free server from the rasmgr
+ int executeGetFreeServer(unsigned short readOnly);
+
+ /// open database
+ int executeOpenDB( const char* database );
+
+ /// issues "close current database" - request
+ int executeCloseDB();
+
+ /// issues "begin transaction" - request
+ int executeOpenTA( unsigned short readOnly = 0 );
+
+ /// issues "commit current transaction" - request
+ int executeCommitTA();
+
+ /// issues "abort current transaction" - request
+ int executeAbortTA();
+
+ /// the name of the rasmgr host
+ char *rasmgrHost;
+
+ /// the listening port of the rasmgr
+ int rasmgrPort;
+
+ /// the name of the server host
+ char serverHost[100]; //can't be just a pointer, it's never stored elsewhere
+
+ /// RPC prognum of the server
+ unsigned long RPCIF_PARA;
+
+ /// the name of the opened database, needed because it will be opened again and again, in a hidden operation
+ /// all 3 will be dinamic allocated strings when we change to parallel-proc
+ char dataBase[100];
+
+ // the capability
+ char capability[100];
+
+ /// user identification string
+ char identificationString[100];
+
+};
+
+//RNP #include "clientcomm.icc"
+
+
+#endif
diff --git a/clientcomm/rpcif.h.awk b/clientcomm/rpcif.h.awk
new file mode 100644
index 0000000..881b6d9
--- /dev/null
+++ b/clientcomm/rpcif.h.awk
@@ -0,0 +1,59 @@
+/bool_t xdr_OpenDBParams()/ { print "#ifdef __cplusplus\n extern \"C\" {bool_t xdr_OpenDBParams(); }\n#else\n bool_t xdr_OpenDBParams();\n#endif";
+ next; }
+/bool_t xdr_OpenDBRes()/ { print "#ifdef __cplusplus\n extern \"C\" {bool_t xdr_OpenDBRes(); }\n#else\n bool_t xdr_OpenDBRes();\n#endif";
+ next; }
+/bool_t xdr_BeginTAParams()/ { print "#ifdef __cplusplus\n extern \"C\" {bool_t xdr_BeginTAParams(); }\n#else\n bool_t xdr_BeginTAParams();\n#endif";
+ next; }
+/bool_t xdr_ExecuteQueryParams()/ { print "#ifdef __cplusplus\n extern \"C\" {bool_t xdr_ExecuteQueryParams(); }\n#else\n bool_t xdr_ExecuteQueryParams();\n#endif";
+ next; }
+/bool_t xdr_OIdSpecParams()/ { print "#ifdef __cplusplus\n extern \"C\" {bool_t xdr_OIdSpecParams(); }\n#else\n bool_t xdr_OIdSpecParams();\n#endif";
+ next; }
+/bool_t xdr_InsertTransMDDParams()/ { print "#ifdef __cplusplus\n extern \"C\" {bool_t xdr_InsertTransMDDParams(); }\n#else\n bool_t xdr_InsertTransMDDParams();\n#endif";
+ next; }
+/bool_t xdr_InsertPersMDDParams()/ { print "#ifdef __cplusplus\n extern \"C\" {bool_t xdr_InsertPersMDDParams(); }\n#else\n bool_t xdr_InsertPersMDDParams();\n#endif";
+ next; }
+/bool_t xdr_InsertTileParams()/ { print "#ifdef __cplusplus\n extern \"C\" {bool_t xdr_InsertTileParams(); }\n#else\n bool_t xdr_InsertTileParams();\n#endif";
+ next; }
+/bool_t xdr_EndInsertMDDParams()/ { print "#ifdef __cplusplus\n extern \"C\" {bool_t xdr_EndInsertMDDParams(); }\n#else\n bool_t xdr_EndInsertMDDParams();\n#endif";
+ next; }
+/bool_t xdr_InsertMDDParams()/ { print "#ifdef __cplusplus\n extern \"C\" {bool_t xdr_InsertMDDParams(); }\n#else\n bool_t xdr_InsertMDDParams();\n#endif";
+ next; }
+/bool_t xdr_NameSpecParams()/ { print "#ifdef __cplusplus\n extern \"C\" {bool_t xdr_NameSpecParams(); }\n#else\n bool_t xdr_NameSpecParams();\n#endif";
+ next; }
+/bool_t xdr_InsertCollParams()/ { print "#ifdef __cplusplus\n extern \"C\" {bool_t xdr_InsertCollParams(); }\n#else\n bool_t xdr_InsertCollParams();\n#endif";
+ next; }
+/bool_t xdr_RemoveObjFromCollParams()/ { print "#ifdef __cplusplus\n extern \"C\" {bool_t xdr_RemoveObjFromCollParams(); }\n#else\n bool_t xdr_RemoveObjFromCollParams();\n#endif";
+ next; }
+/bool_t xdr_NewOIdParams()/ { print "#ifdef __cplusplus\n extern \"C\" {bool_t xdr_NewOIdParams(); }\n#else\n bool_t xdr_NewOIdParams();\n#endif";
+ next; }
+/bool_t xdr_GetTypeStructureParams()/ { print "#ifdef __cplusplus\n extern \"C\" {bool_t xdr_GetTypeStructureParams(); }\n#else\n bool_t xdr_GetTypeStructureParams();\n#endif";
+ next; }
+/bool_t xdr_SetServerTransferParams()/ { print "#ifdef __cplusplus\n extern \"C\" {bool_t xdr_SetServerTransferParams(); }\n#else\n bool_t xdr_SetServerTransferParams();\n#endif";
+ next; }
+/bool_t xdr_GetExtendedErrorInfo()/ { print "#ifdef __cplusplus\n extern \"C\" {bool_t xdr_GetExtendedErrorInfo(); }\n#else\n bool_t xdr_GetExtendedErrorInfo();\n#endif";
+ next; }
+/bool_t xdr_GetMDDRes()/ { print "#ifdef __cplusplus\n extern \"C\" {bool_t xdr_GetMDDRes(); }\n#else\n bool_t xdr_GetMDDRes();\n#endif";
+ next; }
+/bool_t xdr_GetCollRes()/ { print "#ifdef __cplusplus\n extern \"C\" {bool_t xdr_GetCollRes(); }\n#else\n bool_t xdr_GetCollRes();\n#endif";
+ next; }
+/bool_t xdr_GetTileRes()/ { print "#ifdef __cplusplus\n extern \"C\" {bool_t xdr_GetTileRes(); }\n#else\n bool_t xdr_GetTileRes();\n#endif";
+ next; }
+/bool_t xdr_ExecuteQueryRes()/ { print "#ifdef __cplusplus\n extern \"C\" {bool_t xdr_ExecuteQueryRes(); }\n#else\n bool_t xdr_ExecuteQueryRes();\n#endif";
+ next; }
+/bool_t xdr_ExecuteUpdateRes()/ { print "#ifdef __cplusplus\n extern \"C\" {bool_t xdr_ExecuteUpdateRes(); }\n#else\n bool_t xdr_ExecuteUpdateRes();\n#endif";
+ next; }
+/bool_t xdr_OIdRes()/ { print "#ifdef __cplusplus\n extern \"C\" {bool_t xdr_OIdRes(); }\n#else\n bool_t xdr_OIdRes();\n#endif";
+ next; }
+/bool_t xdr_ServerStatRes()/ { print "#ifdef __cplusplus\n extern \"C\" {bool_t xdr_ServerStatRes(); }\n#else\n bool_t xdr_ServerStatRes();\n#endif";
+ next; }
+/bool_t xdr_ServerVersionRes()/ { print "#ifdef __cplusplus\n extern \"C\" {bool_t xdr_ServerVersionRes(); }\n#else\n bool_t xdr_ServerVersionRes();\n#endif";
+ next; }
+/bool_t xdr_ObjectTypeRes()/ { print "#ifdef __cplusplus\n extern \"C\" {bool_t xdr_ObjectTypeRes(); }\n#else\n bool_t xdr_ObjectTypeRes();\n#endif";
+ next; }
+/bool_t xdr_GetCollOIdsRes()/ { print "#ifdef __cplusplus\n extern \"C\" {bool_t xdr_GetCollOIdsRes(); }\n#else\n bool_t xdr_GetCollOIdsRes();\n#endif";
+ next; }
+/bool_t xdr_GetTypeStructureRes()/ { print "#ifdef __cplusplus\n extern \"C\" {bool_t xdr_GetTypeStructureRes(); }\n#else\n bool_t xdr_GetTypeStructureRes();\n#endif";
+ next; }
+/bool_t xdr_GetElementRes()/ { print "#ifdef __cplusplus\n extern \"C\" {bool_t xdr_GetElementRes(); }\n#else\n bool_t xdr_GetElementRes();\n#endif";
+ next; }
+ { print $0; }
diff --git a/clientcomm/rpcif.h.awk_dec2 b/clientcomm/rpcif.h.awk_dec2
new file mode 100644
index 0000000..d71df53
--- /dev/null
+++ b/clientcomm/rpcif.h.awk_dec2
@@ -0,0 +1,46 @@
+BEGIN {
+ print "#ifndef _RPCIF_H_RPCGEN";
+ print "#define _RPCIF_H_RPCGEN";
+ print "#include <rpc/rpc.h>";
+ }
+/\*rpc[^(]*/ {
+ if (FILENAME == "rpcif.h.tmp")
+ {
+ headerLine = $0;
+ startMethodName = index(headerLine, "*") + 1;
+ methodNameLength = length(headerLine) - 2 - startMethodName;
+ methodName = substr(headerLine, startMethodName, methodNameLength);
+ #print "method name " methodName;
+ startOfLine = substr(headerLine, 1, startMethodName - 1);
+ #print "start of line " startOfLine;
+ #print "method name to replace " methodNameToReplace;
+ startInMethod = index(theMethods, methodName);
+ methodIsFirst = substr(theMethods, startInMethod);
+ #print "methodIsFirst " methodIsFirst;
+ endInMethod = index(methodIsFirst, ":");
+ endInMethod--;
+ methodIsOnly = substr(methodIsFirst, 1, endInMethod);
+ #print "methodIsOnly " methodIsOnly;
+ correctLine = startOfLine methodIsOnly ";";
+ print correctLine;
+ next;
+ }
+ }
+/^rpc[^(]*/ {
+ if (FILENAME != "rpcif.h.tmp")
+ {
+ theMethods = $0 ":" theMethods;
+ #print "theMethods " theMethods;
+ }
+ next;
+ }
+ {
+ if (FILENAME == "rpcif.h.tmp")
+ {
+ print $0;
+ }
+ }
+
+END {
+ print "#endif"
+ } \ No newline at end of file
diff --git a/clientcomm/rpcif.x b/clientcomm/rpcif.x
new file mode 100644
index 0000000..1bf9efb
--- /dev/null
+++ b/clientcomm/rpcif.x
@@ -0,0 +1,409 @@
+/*Every return structure has to have unsigned short (the status variable) as its first elment!*/
+/*This is due to the patching of the rpc server communication code*/
+
+typedef opaque confarray<>;
+
+struct RPCMarray
+{
+ string domain<>;
+ unsigned long cellTypeLength;
+ unsigned short currentFormat;
+ unsigned short storageFormat;
+ confarray data;
+};
+
+struct RPCClientEntry
+{
+ unsigned long clientId;
+ string clientIdText<>;
+ string userName<>;
+ string baseName<>;
+ unsigned long creationTime;
+ unsigned long lastActionTime;
+ unsigned long transferColl;
+ unsigned long transferIter;
+ unsigned long assembleMDD;
+ unsigned long transferMDD;
+ unsigned long transTiles;
+ unsigned long tileIter;
+ unsigned long bytesToTransfer;
+};
+
+struct RPCOIdEntry
+{
+ string oid<>;
+};
+
+/* special definitions for rpcOpenDB */
+struct OpenDBParams
+{
+ string dbName<>;
+ string userName<>;
+ string capability<>;
+};
+
+/*Every return structure has to have unsigned short (the status variable) as its first elment!*/
+/*This is due to the patching of the rpc server communication code*/
+struct OpenDBRes
+{
+ unsigned short status;
+ unsigned long clientID;
+};
+
+/* special definitions for rpcBeginTA */
+struct BeginTAParams
+{
+ unsigned long clientID;
+ unsigned short readOnly;
+ string capability<>;
+};
+
+/* special definitions for rpcExecuteQuery */
+struct ExecuteQueryParams
+{
+ unsigned long clientID;
+ string query<>;
+};
+
+/*Every return structure has to have unsigned short (the status variable) as its first elment!*/
+/*This is due to the patching of the rpc server communication code*/
+struct ExecuteQueryRes
+{
+ unsigned short status;
+ unsigned long errorNo;
+ unsigned long lineNo;
+ unsigned long columnNo;
+ string token<>;
+ string typeName<>;
+ string typeStructure<>;
+};
+
+/*Every return structure has to have unsigned short (the status variable) as its first elment!*/
+/*This is due to the patching of the rpc server communication code*/
+struct ExecuteUpdateRes
+{
+ unsigned short status;
+ unsigned long errorNo;
+ unsigned long lineNo;
+ unsigned long columnNo;
+ string token<>;
+};
+
+/* special definitions for rpcInsertColl */
+struct InsertCollParams
+{
+ unsigned long clientID;
+ string collName<>;
+ string typeName<>;
+ string oid<>;
+};
+
+/* special definitions for rpcGetCollByName, rpcDeleteCollByName */
+struct NameSpecParams
+{
+ unsigned long clientID;
+ string name<>;
+};
+
+/* special definitions for rpcGetCollByOId, rpcDeleteCollByOId */
+struct OIdSpecParams
+{
+ unsigned long clientID;
+ string oid<>;
+};
+
+/* special definitions for rpcRemoveObjFromColl */
+struct RemoveObjFromCollParams
+{
+ unsigned long clientID;
+ string collName<>;
+ string oid<>;
+};
+
+/*Every return structure has to have unsigned short (the status variable) as its first elment!*/
+/*This is due to the patching of the rpc server communication code*/
+/* special definitions for rpcGetCollByName, rpcGetCollByOId */
+struct GetCollRes
+{
+ unsigned short status;
+ string typeName<>;
+ string typeStructure<>;
+ string oid<>;
+ string collName<>;
+};
+
+/*Every return structure has to have unsigned short (the status variable) as its first elment!*/
+/*This is due to the patching of the rpc server communication code*/
+/* special definitions for rpcGetCollOIdsByName, rpcGetCollOIdsByOId */
+struct GetCollOIdsRes
+{
+ unsigned short status;
+ string typeName<>;
+ string typeStructure<>;
+ string oid<>;
+ string collName<>;
+
+ RPCOIdEntry oidTable<>;
+};
+
+/*Every return structure has to have unsigned short (the status variable) as its first elment!*/
+/*This is due to the patching of the rpc server communication code*/
+/* special definitions for rpcGetNextMDD */
+struct GetMDDRes
+{
+ unsigned short status;
+ string domain<>;
+ string typeName<>;
+ string typeStructure<>;
+ string oid<>;
+ unsigned short currentFormat;
+};
+
+/*Every return structure has to have unsigned short (the status variable) as its first elment!*/
+/*This is due to the patching of the rpc server communication code*/
+/* special definitions for rpcGetNextTile */
+struct GetTileRes
+{
+ unsigned short status;
+ RPCMarray* marray;
+};
+
+/*Every return structure has to have unsigned short (the status variable) as its first elment!*/
+/*This is due to the patching of the rpc server communication code*/
+/* special definitions for rpcGetNewOid */
+struct OIdRes
+{
+ unsigned short status;
+ string oid<>;
+};
+
+/*Every return structure has to have unsigned short (the status variable) as its first elment!*/
+/*This is due to the patching of the rpc server communication code*/
+/* special definitions for rpcGetObjectType */
+struct ObjectTypeRes
+{
+ unsigned short status;
+ unsigned short objType;
+};
+
+/* special definitions for rpcInsertMDD */
+struct InsertMDDParams
+{
+ unsigned long clientID;
+ string collName<>;
+ string typeName<>;
+ string oid<>;
+ RPCMarray* marray;
+};
+
+/* special definitions for rpcInsertTile */
+struct InsertTileParams
+{
+ unsigned long clientID;
+ int isPersistent;
+ RPCMarray* marray;
+};
+
+/* special definitions for rpcEndInsertMDD */
+struct EndInsertMDDParams
+{
+ unsigned long clientID;
+ int isPersistent;
+};
+
+/* special definitions for rpcStartInsertTransMDD */
+struct InsertTransMDDParams
+{
+ unsigned long clientID;
+ string collName<>;
+ string domain<>;
+ unsigned long typeLength;
+ string typeName<>;
+};
+
+
+/* special definitions for rpcStartInsertPersMDD */
+struct InsertPersMDDParams
+{
+ unsigned long clientID;
+ string collName<>;
+ string domain<>;
+ unsigned long typeLength;
+ string typeName<>;
+ string oid<>;
+};
+
+
+/* special definitions for rpcGetNewOid */
+struct NewOIdParams
+{
+ unsigned long clientID;
+ unsigned short objType;
+};
+
+
+/*Every return structure has to have unsigned short (the status variable) as its first elment!*/
+/*This is due to the patching of the rpc server communication code*/
+/* special definitions for rpcServerStat*/
+struct ServerStatRes
+{
+ unsigned short status;
+ unsigned long inactivityTimeout;
+ unsigned long managementInterval;
+ unsigned long transactionActive;
+ unsigned long maxTransferBufferSize;
+ unsigned long nextClientId;
+ unsigned long clientNumber;
+
+ unsigned long memArena;
+ unsigned long memSmblks;
+ unsigned long memOrdblks;
+ unsigned long memFordblks;
+ unsigned long memUordblks;
+
+ RPCClientEntry clientTable<>;
+};
+
+
+/*Every return structure has to have unsigned short (the status variable) as its first elment!*/
+/*This is due to the patching of the rpc server communication code*/
+/* special definitions for rpcGetServerVersion */
+struct ServerVersionRes
+{
+ unsigned short status;
+ double serverVersionNo;
+ double rpcInterfaceVersionNo;
+};
+
+
+/* special definitions for rpcGetTypeStructure */
+struct GetTypeStructureParams
+{
+ unsigned long clientID;
+ string typeName<>;
+ unsigned short typeType;
+};
+
+/*Every return structure has to have unsigned short (the status variable) as its first elment!*/
+/*This is due to the patching of the rpc server communication code*/
+struct GetTypeStructureRes
+{
+ unsigned short status;
+ string typeStructure<>;
+};
+
+/*Every return structure has to have unsigned short (the status variable) as its first elment!*/
+/*This is due to the patching of the rpc server communication code*/
+/* special definitions for rpcGetNextElement */
+struct GetElementRes
+{
+ unsigned short status;
+ confarray data;
+};
+
+/* for setting the transfer data format in the server */
+struct SetServerTransferParams
+{
+ unsigned long clientID;
+ unsigned short format;
+ string formatParams<>;
+};
+
+/*Every return structure has to have unsigned short (the status variable) as its first elment!*/
+/*This is due to the patching of the rpc server communication code*/
+/* for the getExtendedErrorInfo function*/
+struct GetExtendedErrorInfo
+{
+ unsigned short status;
+ string errorText<>;
+};
+
+program RPCIF
+{
+ version RPCIFVERS
+ {
+ /* server system calls */
+ ServerVersionRes RPCGETSERVERVERSION ( int ) = 1;
+ u_short RPCSHUTDOWN ( int ) = 2;
+ ServerStatRes RPCSERVERSTAT ( int ) = 3;
+ u_short RPCKILLTABLEENTRY ( unsigned long ) = 4;
+ unsigned short RPCALIVE ( unsigned long ) = 5;
+
+ /* Db calls */
+ OpenDBRes RPCOPENDB ( OpenDBParams ) = 6;
+ unsigned short RPCCLOSEDB ( unsigned long ) = 7;
+ unsigned short RPCCREATEDB ( string ) = 8;
+ unsigned short RPCDESTROYDB ( string ) = 9;
+
+ /* TA calls */
+ unsigned short RPCBEGINTA ( BeginTAParams ) = 10;
+ unsigned short RPCCOMMITTA ( unsigned long ) = 11;
+ unsigned short RPCABORTTA ( unsigned long ) = 12;
+
+ /* Query */
+ ExecuteQueryRes RPCEXECUTEQUERY ( ExecuteQueryParams ) = 13;
+
+ /* Get MDDs of a query by OId */
+ GetMDDRes RPCGETNEXTMDD ( unsigned long ) = 14;
+ GetMDDRes RPCGETMDDBYOID ( OIdSpecParams ) = 15;
+ GetTileRes RPCGETNEXTTILE ( unsigned long ) = 16;
+ unsigned short RPCENDTRANSFER ( unsigned long ) = 17;
+
+ /* Update */
+ unsigned short RPCINITEXECUTEUPDATE ( unsigned long ) = 18;
+ ExecuteUpdateRes RPCEXECUTEUPDATE ( ExecuteQueryParams ) = 19;
+
+ /* insert a transient/persistent MDD tile by tile */
+ unsigned short RPCSTARTINSERTTRANSMDD ( InsertTransMDDParams ) = 20;
+ unsigned short RPCSTARTINSERTPERSMDD ( InsertPersMDDParams ) = 21;
+ unsigned short RPCINSERTTILE ( InsertTileParams ) = 22;
+ unsigned short RPCENDINSERTMDD ( EndInsertMDDParams ) = 23;
+
+ /* insert a persistent MDD at once */
+ unsigned short RPCINSERTMDD ( InsertMDDParams ) = 24;
+
+ /* get whole collection (updated) */
+ GetCollRes RPCGETCOLLBYNAME ( NameSpecParams ) = 25;
+ GetCollRes RPCGETCOLLBYOID ( OIdSpecParams ) = 26;
+
+ /* get collection references */
+ GetCollOIdsRes RPCGETCOLLOIDSBYNAME ( NameSpecParams ) = 27;
+ GetCollOIdsRes RPCGETCOLLOIDSBYOID ( OIdSpecParams ) = 28;
+
+ /* insert collection */
+ unsigned short RPCINSERTCOLL ( InsertCollParams ) = 29;
+
+ /* delete */
+ unsigned short RPCDELETECOLLBYNAME ( NameSpecParams ) = 30;
+ unsigned short RPCDELETEOBJBYOID ( OIdSpecParams ) = 31;
+
+ /* delete MDD from collection */
+ unsigned short RPCREMOVEOBJFROMCOLL ( RemoveObjFromCollParams ) = 32;
+
+ /* get new OId */
+ OIdRes RPCGETNEWOID ( NewOIdParams ) = 33;
+
+ /* get object type */
+ ObjectTypeRes RPCGETOBJECTTYPE ( OIdSpecParams ) = 34;
+
+ /* Type */
+ GetTypeStructureRes RPCGETTYPESTRUCTURE ( GetTypeStructureParams ) = 35;
+
+ /* Get non-MDD data */
+ GetElementRes RPCGETNEXTELEMENT ( unsigned long ) = 36;
+
+ /* Get the server's endianness */
+ int RPCGETSERVERENDIAN ( int ) = 37;
+
+ /* Make the server transfer MDD in the r_Data_Format passed as param */
+ unsigned short RPCSETSERVERTRANSFER ( SetServerTransferParams ) = 38;
+
+ /* Get extended error information */
+ GetExtendedErrorInfo RPCGETERRORINFO ( void ) = 39;
+
+ /* Make the server store MDD in the r_Data_Format passed as param */
+ unsigned short RPCSETSERVERSTORAGE ( SetServerTransferParams ) = 40;
+
+ } = 1;
+
+} = 0x29999999; /* program number ranges established by ONC */
diff --git a/clientcomm/rpcif_clnt.c.awk b/clientcomm/rpcif_clnt.c.awk
new file mode 100644
index 0000000..8681578
--- /dev/null
+++ b/clientcomm/rpcif_clnt.c.awk
@@ -0,0 +1,46 @@
+BEGIN { nodebug = 0;
+ print"#include <stdio.h>";
+ print"#include \"raslib/error.hh\"";
+ print"#include \"raslib/rminit.hh\"";
+ }
+/rpcshutdown/ { nodebug = 1; print $0; next; }
+/^}/ { nodebug = 0; print $0; next; }
+nodebug==1 { print $0; next; }
+/static.*clnt_res;/ { print $0; print "\tenum clnt_stat stat;\n"; next; }
+/if.*clnt_call/ { x=$0;
+ sub(/if *\( *clnt_call/, "if ( (stat = clnt_call", x);
+ sub(/\) *!= *RPC_SUCCESS *)/, ") ) != RPC_SUCCESS )", x);
+ print x;
+ next;
+ }
+/\) *!= *RPC_SUCCESS/ { x=$0;
+ sub(/\) *!= *RPC_SUCCESS *)/, ") ) != RPC_SUCCESS )", x);
+ print x;
+ next;
+ }
+/return *\(NULL\)/ {
+ print "\t\tclnt_perrno( stat );";
+ print $0;
+ print "\t\t}";
+
+ print "\tif (*((u_short*)&clnt_res) == 42)";
+ print "\t\t{";
+ print "\t\tGetExtendedErrorInfo* result = NULL;";
+ print "\t\tint dummy;";
+ print "\t\tint counter = 0;";
+ print "\t\twhile (!(result = rpcgeterrorinfo_1(&dummy, clnt)) && (counter < RMInit::rpcMaxRetry))";
+ print "\t\t\t{";
+ print "\t\t\tcounter++;";
+ print "\t\t\t}";
+ print "\t\tr_Error* t = NULL, e;";
+ print "\t\tif (counter == RMInit::rpcMaxRetry)";
+ print "\t\t\tt = new r_Error(RPCCOMMUNICATIONFAILURE);";
+ print "\t\telse";
+ print "\t\t\tt = r_Error::getAnyError(result->errorText);";
+ print "\t\te=*t;";
+ print "\t\tdelete t;";
+ print "\t\tthrow e;";
+ next;
+ }
+
+ { print $0; }
diff --git a/clientcomm/rpcif_clnt.c.awk_dec b/clientcomm/rpcif_clnt.c.awk_dec
new file mode 100644
index 0000000..46a4bdf
--- /dev/null
+++ b/clientcomm/rpcif_clnt.c.awk_dec
@@ -0,0 +1,62 @@
+BEGIN { nodebug = 0;
+ print"#include <stdio.h>";
+ print"#ifdef AIX";
+ print"#include <strings.h>";
+ print"#endif";
+ print"#include \"raslib/error.hh\"";
+ print"#include \"raslib/rminit.hh\"";
+ }
+/^rpc[^(]*([^)]*)/ {
+ sig = substr($0, 1, index($0,"(") - 1);
+ getline;
+ par1 = substr($0, 1, length - 1);
+ getline;
+ par2 = substr($0, 1, length - 1);
+ print sig "(" par1 "," par2 ")";
+ if ( sig == "rpcshutdown" )
+ nodebug = 1;
+ next;
+ }
+
+#/rpcshutdown/ { nodebug = 1; print $0; next; }
+/^}/ { nodebug = 0; print $0; next; }
+nodebug==1 { print $0; next; }
+/static.*res;/ { print $0; print "\tenum clnt_stat stat;\n"; next; }
+/if.*clnt_call/ { x=$0;
+ sub(/if *\( *clnt_call/, "if ( (stat = clnt_call", x);
+ sub(/\) *!= *RPC_SUCCESS *\)/, ") ) != RPC_SUCCESS )", x);
+ print x;
+ next;
+ }
+/\) *!= *RPC_SUCCESS/ { x=$0;
+ sub(/\) *!= *RPC_SUCCESS *\)/, ") ) != RPC_SUCCESS )", x);
+ print x;
+ next;
+ }
+/return *\(NULL\)/ {
+ print "\t\tclnt_perrno( stat );";
+ print $0;
+ print "\t\t}";
+
+ print "\tif (*((u_short*)&res) == 42)";
+ print "\t\t{";
+ print "\t\tGetExtendedErrorInfo* result = NULL;";
+ print "\t\tint dummy;";
+ print "\t\tint counter = 0;";
+ print "\t\twhile (!(result = rpcgeterrorinfo_1(&dummy, clnt)) && (counter < RMInit::rpcMaxRetry))";
+ print "\t\t\t{";
+ print "\t\t\tcounter++;";
+ print "\t\t\t}";
+ print "\t\tr_Error* t = NULL, e;";
+ print "\t\tif (counter == RMInit::rpcMaxRetry)";
+ print "\t\t\tt = new r_Error(RPCCOMMUNICATIONFAILURE);";
+ print "\t\telse";
+ print "\t\t\tt = r_Error::getAnyError(result->errorText);";
+ print "\t\te=*t;";
+ print "\t\tdelete t;";
+ print "\t\tthrow e;";
+ next;
+ }
+
+
+ { print $0; }
diff --git a/clientcomm/rpcif_clnt.c.awk_dec2 b/clientcomm/rpcif_clnt.c.awk_dec2
new file mode 100644
index 0000000..33de2e0
--- /dev/null
+++ b/clientcomm/rpcif_clnt.c.awk_dec2
@@ -0,0 +1,8 @@
+/if.*clnt.*SUCCESS.*/ {
+ split($0, parts, ",");
+ print parts[1] ", " parts[2] ", (xdrproc_t)" parts[3] ", (caddr_t)" parts[4] ", (xdrproc_t)" parts[5] ", (caddr_t)" parts[6] ", " parts[7]
+ next;
+ }
+ {
+ print $0;
+ }
diff --git a/clientcomm/rpcif_svc.c.awk b/clientcomm/rpcif_svc.c.awk
new file mode 100644
index 0000000..3baef21
--- /dev/null
+++ b/clientcomm/rpcif_svc.c.awk
@@ -0,0 +1,59 @@
+BEGIN {
+ print "//patched by awk 1";
+ print "#include \"raslib/error.hh\""
+ print "#include \"servercomm/servercomm.hh\""
+ print "#include <new>"
+ print "char *secureResultBufferForRPC;"
+ print "bool bMemFailed = false;"
+ print "//end patched by awk 1";
+ }
+/result\ =\ .*local/ {
+ print "//patched by awk 2";
+ print "\ttry\t{";
+ print "//end patched by awk 2";
+ print $0;
+ print "//patched by awk 2.1";
+ print "\t\t}";
+ print "\tcatch (r_Error& e)";
+ print "\t\t{";
+ print "\t\tretvalTxt = e.serialiseError();";
+ print "\t\tu_short temp = 42;";
+ print "\t\tresult = secureResultBufferForRPC;";
+ print "\t\tmemcpy(result, (char*)&temp, sizeof(u_short));"
+ print "\t\t}";
+ print "\tcatch (std::bad_alloc)";
+ print "\t\t{";
+ print "\t\tbMemFailed = true;"
+ print "\t\tServerComm* sc = ServerComm::actual_servercomm;"
+ print "\t\tr_Ememory_allocation e;"
+ print "\t\tretvalTxt = e.serialiseError();"
+ print "\t\tu_short temp = 42;";
+ print "\t\tresult = secureResultBufferForRPC;"
+ print "\t\tmemcpy(result, (char*)&temp, sizeof(u_short));"
+ print "\t\t"
+ print "\t\t}";
+ print "//end patched by awk 2.1";
+ next;
+ }
+/^void$/ {
+ print "//patched by awk 3";
+ print "char\*";
+ print "//end patched by awk 3";
+ next;
+ }
+/^{$/ {
+ print $0;
+ print "//patched by awk 4";
+ print "char\* retvalTxt = 0;";
+ print "//end patched by awk 4";
+ next;
+ }
+/return;/ {
+ print "//patched by awk 5";
+ print "return retvalTxt;";
+ print "//end patched by awk 5";
+ next;
+ }
+ {
+ print $0;
+ }
diff --git a/clientcomm/test/Makefile b/clientcomm/test/Makefile
new file mode 100644
index 0000000..490ea9f
--- /dev/null
+++ b/clientcomm/test/Makefile
@@ -0,0 +1,81 @@
+# -*-Makefile-*-
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>. # Top Level makefile. This points to the various modules that have to be build
+# and/or deployed
+
+#
+# MAKEFILE FOR:
+# test programs of module clientcomm
+#
+# COMMENTS:
+#
+##################################################################
+#
+# This is just an example Makefile for a test program.
+# The dependency of the test program on the lib of the
+# corresponding module is in the Makefile of the module.
+#
+
+######################### Definitions ############################
+
+# standard include with general options
+include $(RMANBASE)/Makefile.inc
+
+# all test programs
+SRCCXX = test_clientcomm.cc
+OBJS = ${SRCCXX:%.cc=%.o}
+ALLTESTS = ${SRCCXX:%.cc=%}
+
+# use client specific flags
+CXXFLAGS := $(CLIENTCXXFLAGS)
+LDFLAGS := $(CLIENTLDFLAGS)
+
+# some additional flags for compiling and linking
+CXXFLAGS += -I$(RMANBASE)/clientcomm
+LDFLAGS += -I$(RMANBASE)/clientcomm
+
+# add communication flags
+CXXFLAGS += $(COMMCXXFLAGS)
+LDFLAGS += $(COMMLDFLAGS)
+
+# use template repository of module rasodmg
+CXXFLAGS := -ptr$(RMANBASE)/rasodmg/ptrepository $(CXXFLAGS)
+LDFLAGS := -ptr$(RMANBASE)/rasodmg/ptrepository $(LDFLAGS)
+
+########################### Targets ##############################
+
+# test target for clientcomm
+.PHONY : clientcomm
+clientcomm: test_module test_clientcomm
+
+.PHONY : test_module
+test_module:
+ cd $(RMANBASE)/clientcomm; $(MAKE)
+
+test_clientcomm: test_clientcomm.o $(CLIENTCOMM) $(RASODMG) $(RASLIB)
+ $(CXX) $(LDFLAGS) -o $@ $^ -lm
+
+# general rules
+include $(RMANBASE)/Makefile.rel
+
+# automatically created dependencies
+include Makefile.dep
diff --git a/clientcomm/test/test_clientcomm.cc b/clientcomm/test/test_clientcomm.cc
new file mode 100644
index 0000000..d59047a
--- /dev/null
+++ b/clientcomm/test/test_clientcomm.cc
@@ -0,0 +1,84 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_clientcomm.cc
+ *
+ * MODULE: clientcomm
+ *
+ * PURPOSE:
+ *
+ * COMMENTS:
+ * None
+*/
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#ifdef __GNUG__
+#include "template_inst.hh"
+#endif
+#endif
+
+#include <iostream>
+
+#include "rasodmg/ref.hh"
+#include "clientcomm/clientcomm.hh"
+
+
+int main()
+{
+ try
+ {
+ ClientComm a( "sunwibas15" );
+
+ cout << "Opening db ..." << flush;
+ a.openDB( "RolandBase" );
+ cout << "OK" << endl;
+
+ cout << "Starting ta ..." << flush;
+ a.openTA();
+ cout << "OK" << endl;
+
+ cout << "Getting type structure RGBImage ..." << flush;
+ char* ts = a.getTypeStructure( "RGBImage", ClientComm::r_MDDType_Type );
+ cout << "OK" << endl;
+
+ cout << "Type Structure " << ts << endl;
+
+ free( ts );
+
+ cout << "Comitting ta ..." << flush;
+ a.commitTA();
+ cout << "OK" << endl;
+
+ cout << "Closing db ..." << flush;
+ a.closeDB();
+ cout << "OK" << endl;
+ }
+ catch ( ... )
+ {
+ cout << "Exception occured: Server or connection problems." << endl;
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/commline/Makefile.am b/commline/Makefile.am
new file mode 100644
index 0000000..6ff5043
--- /dev/null
+++ b/commline/Makefile.am
@@ -0,0 +1,31 @@
+# -*-Makefile-*-
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+#
+# MODULE: commline
+#
+# COMMENTS:
+#
+##################################################################
+
+noinst_LIBRARIES=libcommline.a
+libcommline_a_SOURCES=cmlparser.cc cmlparser.hh
diff --git a/commline/cmlparser.cc b/commline/cmlparser.cc
new file mode 100644
index 0000000..7c3d50d
--- /dev/null
+++ b/commline/cmlparser.cc
@@ -0,0 +1,915 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: cmlparser.cc
+ *
+ * MODULE: akinside/commline
+ *
+ * PURPOSE:
+ *
+ * COMMENTS:
+ * None
+*/
+
+
+#include <cmlparser.hh>
+
+#include <stdio.h>
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <cstring>
+
+#include <ctype.h>
+#include <vector>
+#include <iomanip>
+#include <cstdlib>
+
+using namespace std;
+
+static const char rcsid[] = "@(#)commline,cmlparser: $Id: cmlparser.cc,v 1.5 2006/01/17 07:50:07 rasdev Exp $";
+
+const char* CommandLineParserVersion = "1.0 (c) 2003 Dr. Peter Baumann";
+
+//#############################################################
+
+char*
+dupString(const char* cc)
+{
+ if(cc)
+ {
+ // strdup uses malloc, we would like to avoid it
+ char *dup = new char[strlen(cc)+1];
+ // new throws? we hope
+ strcpy(dup,cc);
+ return dup;
+ }
+
+ return NULL;
+}
+
+CmlException::CmlException(const string& whatString)
+:problem(whatString)
+{
+}
+
+CmlException::~CmlException() throw()
+{
+}
+
+const char* CmlException::what() const throw()
+{
+ return problem.c_str();
+}
+
+
+//############################################################
+
+const char* CommandLineParameter::defaultTitle = "default: ";
+const char* CommandLineParameter::descSep = " ";
+const char* CommandLineParameter::descTab = "\t";
+const char* CommandLineParameter::descIndent = " ";
+const char* CommandLineParameter::descLineSep = "\n";
+const char CommandLineParameter::descOpen = '<';
+const char CommandLineParameter::descClose = '>';
+const char* CommandLineParameter::descLeftDefault = "(";
+const char* CommandLineParameter::descRightDefault = ")";
+
+
+
+CommandLineParameter::CommandLineParameter(char newShortName, const char* newLongName, const char* newDefaultValue) throw(CmlException)
+ : longName(NULL), defaultValue(NULL), descriptionText(NULL), paramDescription(NULL)
+{
+
+ if((!isalnum(newShortName) || (newShortName == CommandLineParser::noShortName))
+ && (!newLongName || !strcmp(newLongName, CommandLineParser::noLongName)))
+ throw CmlException(string("") + "Invalid option: shortName='" + newShortName + "' longName='" + (newLongName? newLongName: "NULL") + "'");
+
+ shortName = newShortName;
+ longName = dupString(newLongName);
+ present = false;
+ wasLongName = false;
+ defaultValue = dupString(newDefaultValue);
+
+ shNameString[0] = newShortName;
+ shNameString[1] = 0;
+
+ paramDescription = NULL;
+ descriptionText = NULL;
+}
+
+CommandLineParameter::CommandLineParameter(char newShortName, const char* newLongName, long newDefaultValue) throw(CmlException)
+ : longName(NULL), defaultValue(NULL), descriptionText(NULL), paramDescription(NULL)
+{
+
+ if((!isalnum(newShortName) || (newShortName == CommandLineParser::noShortName))
+ && (!newLongName || !strcmp(newLongName, CommandLineParser::noLongName)))
+ throw CmlException(string("") + "Invalid option: shortName='" + newShortName + "' longName='" + (newLongName? newLongName: "NULL") + "'");
+
+ shortName = newShortName;
+ longName = dupString(newLongName);
+ present = false;
+ wasLongName = false;
+
+ // convert default to ASCII, for uniform handling
+ stringstream s;
+ s << newDefaultValue;
+ defaultValue = dupString( s.str().c_str() );
+
+ shNameString[0] = newShortName;
+ shNameString[1] = 0;
+
+ paramDescription = NULL;
+ descriptionText = NULL;
+}
+
+const char* CommandLineParameter::calledName()
+{
+ const char* retval=NULL;
+
+ if(shortName == CommandLineParser::noShortName)
+ retval = longName;
+ else
+ if(!strcmp(longName, CommandLineParser::noLongName))
+ retval = shNameString;
+ else
+ retval = (wasLongName && longName) ? longName : shNameString;
+ return retval;
+}
+
+void CommandLineParameter::reset()
+{
+ present=false;
+ wasLongName=false;
+}
+
+
+CommandLineParameter::~CommandLineParameter()
+{
+ if(longName)
+ delete[] longName;
+
+ if(defaultValue)
+ delete[] defaultValue;
+
+ // paramDescription and descriptionText point both to the same string
+ // but depends on the context which has to be deleted
+ if(paramDescription)
+ {
+ delete[] paramDescription;
+ paramDescription = NULL;
+ descriptionText = NULL;
+ }
+ if(descriptionText)
+ delete[] descriptionText;
+}
+
+void CommandLineParameter::setDescription(const char *desc)
+{
+ // cleaning the previous paramDescription
+ // paramDescription and descriptionText point both to the same string
+ // but depends on the context which has to be deleted
+ if(paramDescription)
+ {
+ delete[] paramDescription;
+ paramDescription = NULL;
+ descriptionText = NULL;
+ }
+ if(descriptionText) delete[] descriptionText;
+
+ if(desc==NULL)
+ {
+ paramDescription=NULL;
+ descriptionText =NULL;
+ }
+ else
+ {
+ paramDescription = dupString(desc);
+
+ // if the string is "<text> line1...", for options with parameters
+ if(paramDescription[0]==descOpen)
+ {
+ int len = strlen(paramDescription);
+ int i=0;
+ for(i=0;i<len;i++)
+ {
+ if((paramDescription[i]==descClose) && (i<len-1))
+ {
+ paramDescription[i+1]=0;
+ descriptionText = paramDescription+i+2;
+ break;
+ }
+ }
+
+ if(i>=len-1) // I didn't find descClose
+ {
+ descriptionText=paramDescription;
+ paramDescription=NULL;
+ }
+ }
+ else
+ {
+ // the string is just "line1..." for options without parameters
+ descriptionText = paramDescription;
+ paramDescription = NULL;
+ }
+ }
+
+#ifdef DEBUG
+ cout<<"desc="<<desc<<endl;
+ if(paramDescription==NULL)
+ cout<<"paramDescription=NULL"<<endl;
+ else
+ cout<<"paramDescription="<<paramDescription<<endl;
+
+ if(descriptionText==NULL)
+ cout<<"descriptionText=NULL"<<endl;
+ else
+ cout<<"descriptionText="<<descriptionText<<endl;
+#endif
+}
+
+bool CommandLineParameter::doesMatch(char c)
+{
+ if(shortName==CommandLineParser::noShortName)
+ return false;
+ return shortName==c ? true:false;
+}
+
+bool CommandLineParameter::doesMatch(const char* s)
+{
+ if(longName==NULL)
+ return false;
+ if(s == NULL)
+ return false;
+ if(!strcmp(longName, CommandLineParser::noLongName))
+ return false;
+ return strcmp(longName,s)==0 ? true:false;
+}
+
+char CommandLineParameter::getShortName() const
+{
+ return shortName;
+}
+
+const char* CommandLineParameter::getLongName() const
+{
+ return longName;
+}
+
+/// print help text, composed from the option descriptions passwd to cml
+ostream& CommandLineParameter::printHelp(ostream &os)
+{
+ if(descriptionText == NULL)
+ return os;
+
+ static const unsigned int longNameLen=30;
+ static const unsigned int longParamLen=30;
+
+ os << CommandLineParameter::descIndent;
+
+ if(isalnum(shortName) && (shortName != CommandLineParser::noShortName))
+ os<< CommandLineParser::ShortSign <<shortName;
+ // we want a flush left display, don't adjust short/long params each -- PB 2003-jul-05
+ // else
+ // os << " ";
+
+ if((isalnum(shortName) && (shortName != CommandLineParser::noShortName)) &&
+ (longName && strcmp(longName, CommandLineParser::noLongName)))
+ os << ", ";
+ // we want a flush left display, don't adjust short/long params each -- PB 2003-jul-05
+ // else
+ // os << " ";
+
+ // we want the parameter to appear right after the option, no adjustment -- PB 2003-jul-
+ // os.setf(ios::left);
+ // os << setw(longNameLen);
+
+ if(longName && strcmp(longName, CommandLineParser::noLongName))
+ {
+ string s;
+ s += CommandLineParser::LongSign;
+ s += longName;
+ os << s.c_str();
+ }
+ else
+ os << "";
+
+ // separator between param name and value
+ os << CommandLineParameter::descSep;
+
+ // no adjustment, again
+ // os.setf(ios::left);
+ // os << setw(longParamLen);
+
+ // param value, such as "<database>"
+ if(paramDescription)
+ os << paramDescription;
+
+ // separator between param value and default
+ if(defaultValue)
+ os << CommandLineParameter::descTab;
+
+ // print default, if any: "(default: 42)"
+ if(defaultValue)
+ os << CommandLineParameter::descLeftDefault << defaultTitle << defaultValue << CommandLineParameter::descRightDefault;
+
+ // in a second line, print description text (2*indent)
+ if(descriptionText)
+ os << CommandLineParameter::descLineSep << CommandLineParameter::descIndent << CommandLineParameter::descIndent << descriptionText;
+
+ os<<flush;
+
+ return os;
+}
+
+//#####################################################################
+
+FlagParameter::FlagParameter(char nShortName, const char* nLongName) throw(CmlException)
+:CommandLineParameter(nShortName,nLongName,(const char*)NULL)
+{
+}
+
+bool FlagParameter::needsValue()
+{
+ return false;
+}
+
+bool FlagParameter::takeValue(const char*)
+{
+ return false;
+}
+
+void FlagParameter::popValue()
+{
+}
+
+bool FlagParameter::isPresent()
+{
+ return present;
+}
+
+bool FlagParameter::setPresent(char c) throw(CmlException)
+{
+ if(c && c==shortName)
+ {
+ if(present==true)
+ {
+ if(wasLongName==true)
+ throw CmlException(string("") + "Parameter '" + longName + "' clashes with parameter '" + shortName + "'");
+ else
+ throw CmlException(string("") + "Parameter '" + shortName + "' was already present");
+ }
+ present=true;
+ return true;
+ }
+ return false;
+}
+
+bool FlagParameter::setPresent(const char* s) throw(CmlException)
+{
+ if(longName != NULL && !strcmp(longName,s))
+ {
+ if(present==true)
+ {
+ if(wasLongName==true)
+ throw CmlException(string("") + "Parameter '" + longName + "' was already present");
+ else
+ throw CmlException(string("") + "Parameter '" + longName + "' clashes with parameter '" + shortName + "'");
+ }
+ wasLongName=true;
+ present=true;
+ return true;
+ }
+ return false;
+}
+
+const char* FlagParameter::getValueAsString() throw(CmlException)
+{
+ throw CmlException("Flag parameter can't return a string value");
+}
+
+long FlagParameter::getValueAsLong() throw(CmlException)
+{
+ throw CmlException("Flag parameter can't return a 'long' value");
+}
+
+double FlagParameter::getValueAsDouble() throw(CmlException)
+{
+ throw CmlException("Flag parameter can't return a 'double' value");
+}
+
+ostream& FlagParameter::printStatus(ostream &os)
+{
+ if(present)
+ os<<"option '"<<calledName()<<"' present";
+ else
+ os<<"option '"<<calledName()<<"' missing";
+
+ return os;
+}
+//#####################################################################
+StringParameter::StringParameter(char nShortName, const char* nLongName, const char* newDefaultValue) throw(CmlException)
+:CommandLineParameter(nShortName,nLongName,newDefaultValue)
+{
+ value.clear();
+}
+
+StringParameter::StringParameter(char nShortName, const char* nLongName, long newDefaultValue) throw(CmlException)
+:CommandLineParameter(nShortName,nLongName,newDefaultValue)
+{
+ value.clear();
+}
+
+StringParameter::~StringParameter()
+{
+ reset();
+}
+
+bool StringParameter::setPresent(char c) throw(CmlException)
+{
+ if(c && c==shortName)
+ {
+ present=true;
+ return true;
+ }
+ return false;
+}
+
+bool StringParameter::setPresent(const char* s) throw(CmlException)
+{
+ if(longName != NULL && !strcmp(longName,s))
+ {
+ wasLongName=true;
+ present=true;
+ return true;
+ }
+ return false;
+}
+
+bool StringParameter::isPresent()
+{
+ return ( ! value.empty() );
+}
+
+void StringParameter::reset()
+{
+ list<char*>::iterator iter = value.begin();
+/* FIXME: free mem to avoid mem leaks
+ while ( iter != value.end() )
+ {
+ if (*iter != NULL)
+ delete[] *iter;
+ }
+*/
+ value.clear();
+
+ CommandLineParameter::reset();
+}
+
+
+bool StringParameter::needsValue()
+{
+ return true;
+}
+
+bool StringParameter::takeValue(const char* s)
+{
+ char *aux = dupString(s);
+ value.push_back( aux );
+ return true;
+}
+
+void StringParameter::popValue()
+{
+ if ( ! value.empty() )
+ value.pop_front();
+}
+
+const char* StringParameter::getValueAsString() throw(CmlException)
+{
+ return ( !value.empty() ? value.front() : defaultValue );
+}
+
+long StringParameter::getValueAsLong() throw(CmlException)
+{
+ const char *r = ( !value.empty() ? value.front() : defaultValue );
+
+ if(r == NULL)
+ throw CmlException(string("") + "No value for parameter '" + calledName() + "'");
+
+ char *endptr;
+
+ long result = strtol( r, &endptr, 0);
+
+ if( *endptr != 0 )
+ throw CmlException(string("") + "Invalid integer value for parameter '" + calledName() + "'");
+
+ return result;
+}
+
+double StringParameter::getValueAsDouble() throw(CmlException)
+{
+ const char *r = ( !value.empty() ? value.front() : defaultValue );
+
+ if(r == NULL)
+ throw CmlException(string("") + "No value for parameter '" + calledName() + "'");
+
+ char *endptr;
+
+ double result = strtod( r, &endptr);
+
+ if( *endptr != 0 )
+ throw CmlException(string("") + "Invalid double value for parameter '" + calledName() + "'");
+
+ return result;
+}
+
+ostream& StringParameter::printStatus(ostream &os)
+{
+ if(value.empty())
+ os<<"option '"<<calledName()<<"' empty.";
+ else
+ {
+ os<<"option '"<<calledName()<<"' present: ";
+ list<char*>::iterator iter = value.begin();
+ while ( iter != value.end() )
+ {
+ os<< "'" << (*iter ? *iter : "(null)") << "' ";
+ iter++;
+ }
+ }
+ return os;
+}
+
+//##########################################################
+const char CommandLineParser::noShortName = '-';
+const char* CommandLineParser::noLongName = "--";
+const char* CommandLineParser::ShortSign = "-";
+const char* CommandLineParser::LongSign = "--";
+
+CommandLineParser* CommandLineParser::myself = NULL;
+
+CommandLineParser& CommandLineParser::getInstance()
+{
+ if(myself == NULL)
+ myself = new CommandLineParser;
+ return *myself;
+}
+
+CommandLineParser::CommandLineParser()
+{
+ lastParameter = NULL;
+ nextTokenIsValue = false;
+}
+
+CommandLineParser::~CommandLineParser()
+{
+ delete myself;
+ myself=NULL;
+
+ lastParameter=NULL;
+
+ list<CommandLineParameter*>::iterator iter = cmlParameter.begin();
+ for(unsigned int i=0;i<cmlParameter.size();i++,iter++)
+ delete *iter;
+}
+
+
+CommandLineParameter& CommandLineParser::addFlagParameter(char shortName, const char *longName, const char *description) throw(CmlException)
+{
+ CommandLineParameter *cp = new FlagParameter(shortName,longName);
+ cp->setDescription(description);
+ cmlParameter.push_back(cp);
+ return *cp;
+}
+
+CommandLineParameter& CommandLineParser::addStringParameter(char shortName, const char* longName, const char *description, const char* newDefaultValue) throw(CmlException)
+{
+ CommandLineParameter *cp = new StringParameter(shortName,longName,newDefaultValue);
+ cp->setDescription(description);
+ cmlParameter.push_back(cp);
+ return *cp;
+}
+
+CommandLineParameter& CommandLineParser::addLongParameter(char shortName, const char* longName, const char *description, long newDefaultValue) throw(CmlException)
+{
+ CommandLineParameter *cp = new StringParameter(shortName,longName,newDefaultValue);
+ cp->setDescription(description);
+ cmlParameter.push_back(cp);
+ return *cp;
+}
+
+bool CommandLineParser::isPresent(char shortName) throw(CmlException)
+{
+ StringParameter *sp;
+ FlagParameter *fp;
+ bool result;
+
+ CommandLineParameter &cml = getParameter(shortName);
+ if ((sp = dynamic_cast<StringParameter*>(&cml)))
+ result = sp->isPresent();
+ else if ((fp = dynamic_cast<FlagParameter*>(&cml)))
+ result = fp->isPresent();
+ return result;
+}
+
+bool CommandLineParser::isPresent(const char* longName) throw(CmlException)
+{
+ StringParameter *sp;
+ FlagParameter *fp;
+ bool result;
+
+ CommandLineParameter &cml = getParameter(longName);
+ if ((sp = dynamic_cast<StringParameter*>(&cml)))
+ result = sp->isPresent();
+ else if ((fp = dynamic_cast<FlagParameter*>(&cml)))
+ result = fp->isPresent();
+ return result;
+}
+
+const char* CommandLineParser::getValueAsString(char shortName) throw(CmlException)
+{
+ CommandLineParameter &cml = getParameter(shortName);
+ return cml.getValueAsString();
+}
+
+long CommandLineParser::getValueAsLong(char shortName) throw(CmlException)
+{
+ CommandLineParameter &cml = getParameter(shortName);
+ return cml.getValueAsLong();
+}
+
+double CommandLineParser::getValueAsDouble(char shortName) throw(CmlException)
+{
+ CommandLineParameter &cml = getParameter(shortName);
+ return cml.getValueAsDouble();
+}
+
+const char* CommandLineParser::getValueAsString(const char* longName) throw(CmlException)
+{
+ CommandLineParameter &cml = getParameter(longName);
+ return cml.getValueAsString();
+}
+
+long CommandLineParser::getValueAsLong(const char* longName) throw(CmlException)
+{
+ CommandLineParameter &cml = getParameter(longName);
+ return cml.getValueAsLong();
+}
+
+double CommandLineParser::getValueAsDouble(const char* longName) throw(CmlException)
+{
+ CommandLineParameter &cml = getParameter(longName);
+ return cml.getValueAsDouble();
+}
+
+
+void CommandLineParser::processCommandLine(int argc, char** argv) throw(CmlException)
+{
+ for(int i=1;i<argc;i++)
+ {
+ char *nextToken=argv[i];
+
+// bool sw1 = (nextToken[0]=='-') ? true:false; // token starts with "-"
+// bool sw2 = (sw1 && nextToken[1]=='-') ? true:false; // token starts with "--"
+
+ bool sw1 = (!strncmp(nextToken, ShortSign, strlen(ShortSign))) ? true:false; // token starts with ShortSign
+ bool sw2 = (!strncmp(nextToken, LongSign, strlen(LongSign))) ? true:false; // token starts with LongSign
+
+ //check only for ShortSign/LongSign
+ if(sw1 && !strcmp(nextToken, ShortSign))
+ throw CmlException(string("") + "Syntax error: '" + ShortSign + "' with no parameter in command line");
+ if(sw2 && !strcmp(nextToken, LongSign))
+ throw CmlException(string("") + "Syntax error: '" + LongSign + "' with no parameter in command line");
+
+ if(nextTokenIsValue)
+ setValue(nextToken);
+ else if(sw2)
+ longNameParameter(nextToken);
+ else if(sw1)
+ shortNameParameter(nextToken);
+ else
+ {
+ throw CmlException(string("") + "Syntax error: unexpected token '" + nextToken + "' in command line");
+ }
+ }
+ if(nextTokenIsValue)
+ throw CmlException(string("") + "Syntax error: missing value for parameter '" + lastParameter->calledName() + "' in command line");
+}
+
+
+CommandLineParameter& CommandLineParser::getParameter(char shortName) throw(CmlException)
+{
+ list<CommandLineParameter*>::iterator iter = cmlParameter.begin();
+
+ for(unsigned int i=0;i<cmlParameter.size();i++,iter++)
+ {
+ if( (*iter)->doesMatch(shortName) )
+ {
+ return *(*iter);
+ }
+ }
+ throw CmlException(string("") + "Syntax error: unknown parameter '" + shortName + "' in command line");
+}
+
+CommandLineParameter& CommandLineParser::getParameter(const char* longName) throw(CmlException)
+{
+ list<CommandLineParameter*>::iterator iter = cmlParameter.begin();
+
+ for(unsigned int i=0;i<cmlParameter.size();i++,iter++)
+ {
+ if( (*iter)->doesMatch(longName) )
+ {
+ return *(*iter);
+ }
+ }
+ throw CmlException(string("") + "Syntax error: unknown parameter '" + longName + "' in command line");
+}
+
+
+void CommandLineParser::setValue(const char* value) throw(CmlException)
+{
+ if(lastParameter == NULL)
+ {
+ throw CmlException("internal error: setValue - lastParameter==null");
+ }
+ lastParameter->takeValue(value);
+ nextTokenIsValue=false;
+}
+
+void CommandLineParser::longNameParameter(const char *nextToken) throw(CmlException)
+{
+ const char* longName = nextToken + strlen(LongSign); // sari peste LongSign (former "--")
+
+ CommandLineParameter &cml = getParameter(longName);
+ cml.setPresent(longName);
+ if(cml.needsValue())
+ {
+ lastParameter = &cml;
+ nextTokenIsValue=true;
+ }
+}
+
+void CommandLineParser::shortNameParameter(const char *nextToken) throw(CmlException)
+{
+ int tokenLength = strlen(nextToken);
+
+ for(int i=strlen(ShortSign);i<tokenLength;i++) //former i=1 for '-'
+ {
+ char shortName = nextToken[i];
+ CommandLineParameter &cml = getParameter(shortName);
+ cml.setPresent(shortName);
+
+ if(cml.needsValue())
+ {
+ if(i==tokenLength-1)
+ {
+ lastParameter = &cml;
+ nextTokenIsValue=true;
+ }
+ else
+ {
+ const char *value = nextToken + i+1;
+ cml.takeValue(value);
+ }
+ break;
+ }
+ }
+
+}
+
+void CommandLineParser::printHelp()
+{
+ std::list<CommandLineParameter*>::const_iterator iter=cmlParameter.begin();
+ std::list<CommandLineParameter*>::const_iterator iterEnd=cmlParameter.end();
+ for(; iter!=iterEnd; ++iter)
+ {
+ CommandLineParameter* ptr=*iter;
+ ptr->printHelp( std::cout );
+ std::cout << std::endl;
+ }
+ return;
+}
+
+void CommandLineParser::printStatus()
+{
+ std::list<CommandLineParameter*>::const_iterator iter=cmlParameter.begin();
+ std::list<CommandLineParameter*>::const_iterator iterEnd=cmlParameter.end();
+
+ for(; iter!=iterEnd; ++iter)
+ {
+ CommandLineParameter* ptr=*iter;
+ ptr->printStatus( std::cout ) << std::endl;
+ }
+
+ std::cout <<std::endl;
+
+}
+
+bool CommandLineParser::testProcessCommandLine(const char *testCml)
+{
+ std::list<CommandLineParameter*>::const_iterator iter=cmlParameter.begin();
+ std::list<CommandLineParameter*>::const_iterator iterEnd=cmlParameter.end();
+ string test;
+ string::size_type posStart, posEnd;
+ const char* spaceSep = " \t\v\f\n\r";
+ const char* prgName = "program";
+ std::vector<std::string> argList;
+ char **argv=NULL;
+ unsigned int argc=0, i=0, n=0;
+ static unsigned int counter=1;
+
+ if(!testCml)
+ {
+ std::cout << "Error: test_cml is null" << endl;
+ printStatus();
+ return false;
+ }
+
+ std::cout << "Test " << counter << " commandline='" << testCml << "'" << std::endl;
+
+ //converting to argc, argv
+ test=testCml;
+ posEnd=0;
+ while(true)
+ {
+ posStart=test.find_first_not_of(spaceSep, posEnd);
+ if(posStart != string::npos)
+ {
+ posEnd=test.find_first_of(spaceSep, posStart);
+ if(posEnd != string::npos)
+ {
+ std::cout << "arg " << argList.size() + 1 << "='" << test.substr(posStart, posEnd-posStart) << "'" << std::endl;
+ argList.push_back(test.substr(posStart, posEnd-posStart));
+ }
+ else //last element
+ {
+ std::cout << "arg " << argList.size() + 1 << "='" << test.substr(posStart, test.size()-posStart) << "'" << std::endl;
+ argList.push_back(test.substr(posStart, test.size()-posStart));
+ break;
+ }
+ }
+ else
+ break;
+ }
+
+ //build argv in C style
+ n=argList.size();
+ argc = n + 1;
+ argv=new char*[ argc ];
+ argv[0] = dupString(prgName);
+ for(i=0; i < n; i++)
+ argv[i + 1] = dupString(argList[i].c_str());
+
+ std::cout << "Test " << counter++ << " output:" << std::endl;
+
+ try
+ {
+ //reset all options
+ for(; iter!=iterEnd; ++iter)
+ {
+ (*iter)->reset();
+ }
+ //process commandline
+ processCommandLine(argc, argv);
+ }
+ catch(CmlException &e)
+ {
+ std::cout<<"Error: "<<e.what()<<std::endl;
+ for(i=0; i < argc; i++)
+ delete [] argv[i];
+ delete[] argv;
+
+ printStatus();
+ return false;
+ }
+
+ for(i=0; i < argc; i++)
+ delete [] argv[i];
+ delete[] argv;
+
+ printStatus();
+ return true;
+}
+
diff --git a/commline/cmlparser.hh b/commline/cmlparser.hh
new file mode 100644
index 0000000..1a29ded
--- /dev/null
+++ b/commline/cmlparser.hh
@@ -0,0 +1,242 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: cmlparser.hh
+ *
+ * MODULE: command line interpreter
+ *
+ * PURPOSE:
+ * Tool for interpreting command line arguments
+ *
+ * COMMENTS:
+ * None
+*/
+
+
+#ifndef AK_CMLPARSER_HH
+#define AK_CMLPARSER_HH
+
+
+
+#include <list>
+#include <string>
+#include <exception>
+#include <iostream>
+
+using std::string;
+using std::list;
+using std::ostream;
+using std::cout;
+
+// Command Line Parser version
+extern const char* CommandLineParserVersion;
+
+// specific errors thrown by the parser
+class CmlException : public std::exception
+ {
+ public:
+ explicit CmlException(const string& whatString);
+ virtual ~CmlException() throw();
+ virtual const char* what() const throw();
+
+ protected:
+ string problem;
+ };
+
+
+class CommandLineParameter
+ {
+ public:
+
+ static const char* defaultTitle;
+ static const char* descSep;
+ static const char* descTab;
+ static const char* descIndent;
+ static const char* descLineSep;
+ static const char descOpen;
+ static const char descClose;
+ static const char* descLeftDefault;
+ static const char* descRightDefault;
+
+ virtual ~CommandLineParameter();
+
+ //interface for Parser
+ void setDescription(const char*);
+
+ bool doesMatch(char c);
+ bool doesMatch(const char* s);
+
+ char getShortName() const;
+ const char* getLongName() const;
+
+ virtual bool setPresent(char c) throw(CmlException) = 0;
+ virtual bool setPresent(const char* s) throw(CmlException) = 0;
+
+ virtual bool needsValue() = 0;
+ virtual bool takeValue(const char* s) = 0;
+ virtual void popValue() = 0;
+
+ void virtual reset();
+ const char *calledName();
+
+ // has a (at least one) value been assigned?
+ virtual bool isPresent() = 0;
+
+ virtual const char* getValueAsString() throw(CmlException) = 0;
+ virtual long getValueAsLong() throw(CmlException) = 0;
+ virtual double getValueAsDouble() throw(CmlException) = 0;
+
+ virtual ostream& printStatus(ostream& = cout) = 0;
+ ostream& printHelp(ostream& = cout);
+
+ protected:
+ CommandLineParameter(char newShortName, const char* newLongName, const char* newDefaultValue) throw(CmlException);
+ CommandLineParameter(char newShortName, const char* newLongName, long newDefaultValue) throw(CmlException);
+
+ protected:
+
+ char shortName;
+ char* longName;
+ bool present;
+ bool wasLongName;
+
+ char* defaultValue;
+ char shNameString[2];
+
+ char *descriptionText;
+ char *paramDescription;
+ };
+
+
+class FlagParameter: public CommandLineParameter
+ {
+ public:
+ FlagParameter(char nShortName, const char*nLongName) throw(CmlException);
+
+ bool setPresent(char c) throw(CmlException);
+ bool setPresent(const char* s) throw(CmlException);
+ bool isPresent();
+
+ bool needsValue();
+ bool takeValue(const char* s);
+ void popValue();
+
+ const char* getValueAsString() throw(CmlException);
+ long getValueAsLong() throw(CmlException);
+ double getValueAsDouble() throw(CmlException);
+
+ ostream& printStatus(ostream& = cout);
+ };
+
+class StringParameter: public CommandLineParameter
+ {
+ private:
+ list<char*> value;
+
+ public:
+ StringParameter(char nShortName, const char* nLongName, const char *newDefaultValue = NULL) throw(CmlException);
+ StringParameter(char nShortName, const char* nLongName, long newDefaultValue = 0L) throw(CmlException);
+ ~StringParameter();
+
+ bool setPresent(char c) throw(CmlException);
+ bool setPresent(const char* s) throw(CmlException);
+ bool isPresent();
+
+ bool needsValue();
+ bool takeValue(const char* s);
+ void popValue();
+
+ const char* getValueAsString() throw(CmlException);
+ long getValueAsLong() throw(CmlException);
+ double getValueAsDouble() throw(CmlException);
+
+ void reset();
+
+ ostream& printStatus(ostream& = cout);
+
+ };
+
+
+class CommandLineParser
+ {
+ public:
+ static const char noShortName;
+ static const char* noLongName;
+ static const char* ShortSign;
+ static const char* LongSign;
+
+
+ static CommandLineParser& getInstance();
+
+ ~CommandLineParser();
+
+ /*
+ These functions take a parameter called description. This is a string used in printHelp
+ The format of this string has to be:
+ <name of parameter> line1\n\t\tline2...\n\t\tlineN
+ brackets<> and space after are mandatory if there is a parameter!
+ Otherwise no <>!
+ */
+ CommandLineParameter& addFlagParameter(char shortName, const char* longName, const char* description) throw(CmlException);
+ CommandLineParameter& addStringParameter(char shortName, const char* longName, const char* description, const char *newDefaultValue = NULL) throw(CmlException);
+ CommandLineParameter& addLongParameter(char shortName, const char* longName, const char* description, long newDefaultValue = 0L ) throw(CmlException);
+
+ bool isPresent(char shortName) throw(CmlException);
+ bool isPresent(const char* longName) throw(CmlException);
+
+ const char* getValueAsString(char shortName) throw(CmlException);
+ long getValueAsLong(char shortName) throw(CmlException);
+ double getValueAsDouble(char shortName) throw(CmlException);
+
+ const char* getValueAsString(const char* longName) throw(CmlException);
+ long getValueAsLong(const char* longName) throw(CmlException);
+ double getValueAsDouble(const char* longName) throw(CmlException);
+
+ void processCommandLine(int argc, char** argv) throw(CmlException);
+
+ bool testProcessCommandLine(const char* test_cml);
+
+ void printHelp();
+ void printStatus();
+
+ private:
+ static CommandLineParser* myself;
+
+ list<CommandLineParameter*> cmlParameter;
+
+ CommandLineParameter *lastParameter;
+ bool nextTokenIsValue;
+
+ CommandLineParser();
+
+ CommandLineParameter& getParameter(char shortName) throw(CmlException);
+ CommandLineParameter& getParameter(const char* longName) throw(CmlException);
+
+ void setValue(const char* value) throw(CmlException);
+
+ void longNameParameter(const char* nextToken) throw(CmlException);
+
+ void shortNameParameter(const char* nextToken) throw(CmlException);
+ };
+
+#endif
diff --git a/commline/test/Makefile b/commline/test/Makefile
new file mode 100644
index 0000000..7297c80
--- /dev/null
+++ b/commline/test/Makefile
@@ -0,0 +1,43 @@
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>. # Top Level makefile. This points to the various modules that have to be build
+# and/or deployed
+
+include $(RMANBASE)/Makefile.inc
+
+OBJS = test_cml.o
+BINS = test_cml functest
+LIBS =
+MISCS = core
+
+CXXFLAGS += ${COMPFLAGS}
+
+all: $(BINS)
+
+test_cml: test_cml.cc ../cmlparser.o
+ $(CXX) $(CXXFLAGS) -I. -I.. -o test_cml test_cml.cc ../cmlparser.o
+
+functest: functest.cc ../cmlparser.o
+ $(CXX) $(CXXFLAGS) -I. -I.. -o functest functest.cc ../cmlparser.o
+
+clean:
+ -rm $(OBJS) $(MISC)
+
diff --git a/commline/test/functest.cc b/commline/test/functest.cc
new file mode 100644
index 0000000..96bd87d
--- /dev/null
+++ b/commline/test/functest.cc
@@ -0,0 +1,59 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+static const char rcsid[] = "@(#)commline,functest: $Id: functest.cc,v 1.1 2005/09/15 12:55:37 rasdev Exp $";
+
+#include<cmlparser.hh>
+
+using std::cout;
+using std::endl;
+
+
+int main()
+ {
+ CommandLineParser &cmlp = CommandLineParser::getInstance();
+
+ try
+ {
+ cmlp.addFlagParameter('f', "fragmented", "fragment file until there is no file any more");
+ cmlp.addFlagParameter(0 , "delete", "delete root directory");
+ cmlp.addFlagParameter('s', NULL, "use server for crushing system");
+
+ cmlp.addStringParameter('u', "user", "<name> user name\n\t\tcucubau", "rasguest");
+ cmlp.addStringParameter( CommandLineParser::noShortName, "passwd", "<password> user password", "rasguest");
+ cmlp.addStringParameter('d', CommandLineParser::noLongName, "<databasename> database name");
+ }
+ catch(CmlException e)
+ {
+ cout << "Error defining options:" << endl;
+ cout << e.what() << endl;
+ return EXIT_FAILURE;
+ }
+
+ cmlp.printHelp();
+
+ return EXIT_SUCCESS;
+ }
+
+
+
+
diff --git a/commline/test/test_cml.cc b/commline/test/test_cml.cc
new file mode 100644
index 0000000..df9a072
--- /dev/null
+++ b/commline/test/test_cml.cc
@@ -0,0 +1,101 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+static const char rcsid[] = "@(#)commline,test_cml.cc: $Id: test_cml.cc,v 1.3 2005/12/21 23:02:06 rasdev Exp $";
+
+#include "cmlparser.hh"
+
+using std::cout;
+using std::endl;
+
+//set to 1 for testing invalid options
+const int TESTOPT=0;
+
+int
+main(int argc, char** argv)
+ {
+ CommandLineParser& cmlInter = CommandLineParser::getInstance();
+
+ if(TESTOPT)
+ cout<<"------ Defining Test options -----"<<endl;
+
+ //defines options
+ try
+ {
+ CommandLineParameter& a = cmlInter.addFlagParameter('r',"resistent", "r desc");
+ CommandLineParameter& b = cmlInter.addFlagParameter('g',"ab", "ab desc");
+ CommandLineParameter& c = cmlInter.addStringParameter('f',"file", "<filename f desc");
+ CommandLineParameter& d = cmlInter.addStringParameter('s',"server", "server> s desc");
+ CommandLineParameter& e = cmlInter.addStringParameter(CommandLineParser::noShortName,"ts", "<ts> test -");
+ CommandLineParameter& f = cmlInter.addStringParameter('t', CommandLineParser::noLongName, "<tl> test --", "test --");
+
+ if(TESTOPT)
+ CommandLineParameter& g = cmlInter.addStringParameter(CommandLineParser::noShortName, CommandLineParser::noLongName, "<tl> - --");
+
+ }
+ catch(CmlException& e)
+ {
+ cout << "Erorr:" << e.what() << endl;
+ return 1;
+ }
+
+ cout<<"------ Test options -----"<<endl;
+ cmlInter.printHelp();
+
+ cout<<"------ Correct Start -----"<<endl;
+ cmlInter.testProcessCommandLine("-r --ab --file testFile -s serverName");
+ cmlInter.testProcessCommandLine("-r --ab --file testFile ");
+ cmlInter.testProcessCommandLine("-r --ab -s serverName");
+ cmlInter.testProcessCommandLine("-rf testFile -s serverName");
+ cmlInter.testProcessCommandLine("-rgf testFile -s serverName");
+ cmlInter.testProcessCommandLine(" --ab --file testFile -s serverName");
+ cmlInter.testProcessCommandLine("--resistent");
+ cmlInter.testProcessCommandLine("--file testFile --server serverName");
+ cmlInter.testProcessCommandLine("-r --ab --file testFile -s -1");
+ cmlInter.testProcessCommandLine("-r --ab --file test -s \"serverName\"");
+ cmlInter.testProcessCommandLine("");
+ cmlInter.testProcessCommandLine(" ");
+ cmlInter.testProcessCommandLine(" ");
+
+ cout<<"------ Multiple Options Start -----"<<endl;
+ cmlInter.testProcessCommandLine("-f F1 -f F2 --file F3 --file F4");
+
+ cout<<"------ Errors Start -----"<<endl;
+ cmlInter.testProcessCommandLine("-r -r --resistent --resistent"); // multiple flags not allowed
+ cmlInter.testProcessCommandLine("-r --ab --file testFile -s");
+ cmlInter.testProcessCommandLine("-r --ab -file testFile");
+ cmlInter.testProcessCommandLine("-r --ab --file -s serverName");
+ cmlInter.testProcessCommandLine("r --ab --file testFile -s serverName");
+ cmlInter.testProcessCommandLine("-r -ab --file testFile -s serverName");
+ cmlInter.testProcessCommandLine("-r ab --file testFile -s serverName");
+ cmlInter.testProcessCommandLine("-rfs testFile serverName");
+ cmlInter.testProcessCommandLine("- r");
+ cmlInter.testProcessCommandLine("-");
+ cmlInter.testProcessCommandLine("--");
+ cmlInter.testProcessCommandLine("-r --");
+ cmlInter.testProcessCommandLine("-r -- ab --file testFile -s serverName");
+
+ cout<<"------ Test End -----"<<endl;
+
+ return 0;
+ }
diff --git a/compression/Makefile.am b/compression/Makefile.am
new file mode 100644
index 0000000..73e3c68
--- /dev/null
+++ b/compression/Makefile.am
@@ -0,0 +1,37 @@
+# -*-Makefile-*- (for Emacs)
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+#
+# MAKEFILE FOR:
+# module compression
+#
+# COMMENTS:
+#
+##################################################################
+
+AM_CXXFLAGS=@CLIENTCXXFLAGS@
+AM_LDFLAGS=@CLIENTLDFLAGS@
+
+noinst_LIBRARIES = libcompression.a
+libcompression_a_SOURCES=nocompstream.cc nocompstream.hh tilecompression.cc \
+ tilecompression.hh tilecompnone.cc tilecompnone.hh \
+ compresstime.hh lincompstream.hh
diff --git a/compression/compresstime.hh b/compression/compresstime.hh
new file mode 100644
index 0000000..c83ad3b
--- /dev/null
+++ b/compression/compresstime.hh
@@ -0,0 +1,46 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: compresstime.hh
+ *
+ * MODULE: compression
+ * CLASS:
+ *
+ * PURPOSE: benchmark compression modules
+ *
+ * COMMENTS:
+ *
+*/
+
+#ifndef _R_COMPRESS_TIME_HH_
+#define _R_COMPRESS_TIME_HH_
+
+#ifdef COMPBENCHMARK
+// for RMTimer
+#include "raslib/rmdebug.hh"
+#define CBENCH_STATEMENT(s) s
+#else
+#define CBENCH_STATEMENT(s)
+#endif
+
+#endif
diff --git a/compression/lincompstream.cc b/compression/lincompstream.cc
new file mode 100644
index 0000000..f5c8474
--- /dev/null
+++ b/compression/lincompstream.cc
@@ -0,0 +1,985 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: lincompstream.cc
+ *
+ * MODULE: compression
+ * CLASS: r_LinCompStream, r_LinDecompStream
+ *
+ * COMMENTS:
+ *
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "raslib/rminit.hh"
+#include "raslib/rmdebug.hh"
+#include "raslib/parseparams.hh"
+#include "raslib/memblockvec.hh"
+#include "compression/lincompstream.hh"
+// for creation of linear (de)compression streams from identifiers
+#include "compression/nocompstream.hh"
+#include "compression/rlestream.hh"
+#include "compression/zlibstream.hh"
+#include "compression/arithstream.hh"
+#include "compression/filestream.hh"
+#include "compression/compresstime.hh"
+
+
+
+const char r_Linear_Stream::bankNameSep = ':';
+
+
+r_Linear_Stream::r_Linear_Stream( void )
+{
+ params = NULL;
+ myTimer = NULL;
+}
+
+r_Linear_Stream::~r_Linear_Stream( void )
+{
+ if (params != NULL)
+ delete params;
+ CBENCH_STATEMENT(if (myTimer != NULL) delete myTimer);
+}
+
+
+r_Linear_Stream::r_Lin_Stream_Format r_Linear_Stream::get_id( const char *name )
+{
+ if (strcasecmp(name, "none") == 0)
+ return r_Lin_Stream_None;
+ else if (strcasecmp(name, "rle") == 0)
+ return r_Lin_Stream_RLE;
+ else if (strcasecmp(name, "zlib") == 0)
+ return r_Lin_Stream_ZLib;
+ else if (strcasecmp(name, "arith") == 0)
+ return r_Lin_Stream_Arith;
+ else if (strcasecmp(name, "file") == 0)
+ return r_Lin_Stream_File;
+ return r_Lin_Stream_NUMBER;
+}
+
+const char *r_Linear_Stream::get_format_string( r_Lin_Stream_Format fmt )
+{
+ switch (fmt)
+ {
+ case r_Lin_Stream_None:
+ return "None";
+ case r_Lin_Stream_RLE:
+ return "RLE";
+ case r_Lin_Stream_ZLib:
+ return "ZLib";
+ case r_Lin_Stream_Arith:
+ return "Arithmetic";
+ case r_Lin_Stream_File:
+ return "File";
+ default:
+ break;
+ }
+ return "???";
+}
+
+r_Linear_Stream::r_Lin_Stream_Format *r_Linear_Stream::get_bank_ids( const char *names )
+{
+ r_Lin_Stream_Format *fmts;
+ unsigned int number, i;
+ const char *d;
+ char buffer[32];
+ char *b;
+
+ d = names; number = 1;
+ while (*d != '\0')
+ {
+ if (*d == bankNameSep) number++;
+ d++;
+ }
+ fmts = new r_Lin_Stream_Format[number+1];
+ d = names; i = 0;
+ while (*d != '\0')
+ {
+ while (isspace((unsigned int)(*d))) d++;
+ b = buffer;
+ while ((!isspace((unsigned int)(*d))) && (*d != bankNameSep) && (*d != '\0')) *b++ = *d++;
+ *b = '\0';
+ if ((fmts[i++] = get_id(buffer)) == r_Lin_Stream_NUMBER)
+ {
+ RMInit::logOut << "r_Linear_Stream::get_bank_ids(): unknown format \""
+ << buffer << '\"' << endl;
+ delete [] fmts;
+ return NULL;
+ }
+ while (isspace((unsigned int)(*d))) d++;
+ if (*d == bankNameSep) d++;
+ }
+ fmts[i] = r_Lin_Stream_NUMBER;
+ if (i != number)
+ {
+ RMInit::logOut << "r_Linear_Stream::get_bank_ids(): warning, inconsistent stream number "
+ << i << ", should be " << number;
+ }
+ return fmts;
+}
+
+char *r_Linear_Stream::get_bank_string( const r_Lin_Stream_Format *ids )
+{
+ unsigned int i, len;
+ char *result, *b;
+
+ len = 0;
+ for (i=0; ids[i] != r_Lin_Stream_NUMBER; i++)
+ {
+ len += strlen(get_format_string(ids[i])) + 1;
+ }
+ result = new char[len+1];
+ b = result;
+ for (i=0; ids[i] != r_Lin_Stream_NUMBER; i++)
+ {
+ const char *str = get_format_string(ids[i]);
+ strcpy(b, str);
+ b += strlen(str);
+ *b++ = bankNameSep;
+ }
+ // remove trailing name separator
+ if (b != result) b--;
+ *b = '\0';
+
+ return result;
+}
+
+int r_Linear_Stream::set_num_symbols( unsigned int syms )
+{
+ // by default this is ignored by most streams (except for arithmetic coding)
+ return 0;
+}
+
+
+// this method should basically only be called when COMPBENCHMARK is defined
+void r_Linear_Stream::instantiate_timer( const char *func, int level )
+{
+#ifdef COMPBENCHMARK
+ if (myTimer != NULL)
+ delete myTimer;
+
+ myTimer = new RMTimer(get_name(), func, level);
+
+ myTimer->start();
+#endif
+}
+
+
+std::ostream &operator<<( std::ostream &s, r_Linear_Stream::r_Lin_Stream_Format fmt )
+{
+ s << r_Linear_Stream::get_format_string(fmt);
+ return s;
+}
+
+
+/*
+ * Linear compression storage
+ */
+
+r_Lin_Comp_Store::r_Lin_Comp_Store( r_ULong bsize )
+{
+ mblocks = NULL;
+ streamer = NULL;
+ cacheSize = bsize;
+ cacheOff = 0;
+ cache = NULL;
+}
+
+r_Lin_Comp_Store::r_Lin_Comp_Store( r_Lin_Comp_Stream *str, r_ULong csize )
+{
+ mblocks = NULL;
+ streamer = str;
+ cacheSize = csize;
+ cacheOff = 0;
+ cache = NULL;
+}
+
+r_Lin_Comp_Store::~r_Lin_Comp_Store( void )
+{
+ // although cache is used in both modes, it's merely a pointer to a block within
+ // mblocks in static mode and mustn't be freed directly in that case.
+ if (mblocks != NULL)
+ {
+ delete mblocks;
+ }
+ else if (cache != NULL)
+ {
+ delete [] ((char*)cache);
+ }
+}
+
+int r_Lin_Comp_Store::start( r_Bytes typeSize )
+{
+ if (streamer != NULL)
+ {
+ RMDBGONCE( 3, RMDebug::module_compression, "r_Lin_Comp_Store", "start() stream " << streamer->get_name() );
+ streamer->begin(typeSize);
+ cache = new char[cacheSize];
+ }
+ else
+ {
+ RMDBGONCE( 3, RMDebug::module_compression, "r_Lin_Comp_Store", "start() static, bsize " << cacheSize );
+ mblocks = new r_Memory_Block_Vector(cacheSize);
+ cache = mblocks->add();
+ }
+
+ if (cache == NULL)
+ return -1;
+
+ return 0;
+}
+
+void *r_Lin_Comp_Store::frag_ptr( void )
+{
+ return (void*)(((char*)cache) + cacheOff);
+}
+
+r_ULong r_Lin_Comp_Store::frag_size( void ) const
+{
+ return cacheSize - cacheOff;
+}
+
+int r_Lin_Comp_Store::frag_stored( r_ULong size )
+{
+ if (size != 0)
+ {
+ cacheOff += size;
+ if (cacheOff >= cacheSize)
+ {
+ if (streamer == NULL)
+ {
+ cache = mblocks->add();
+ }
+ else
+ {
+ if (streamer->put(cache, cacheOff) < 0)
+ return -1;
+ }
+ cacheOff = 0;
+ }
+ }
+ return 0;
+}
+
+int r_Lin_Comp_Store::put( const void *data, r_ULong size )
+{
+ const char *dptr = (const char*)data;
+ r_ULong left = size;
+
+ // note: cache in static mode!
+ while (left != 0)
+ {
+ r_ULong rest;
+
+ rest = cacheSize - cacheOff;
+#ifdef RMANDEBUG
+ if (rest == 0)
+ {
+ RMInit::logOut << "r_Lin_Comp_Store::put(): fatal error!" << endl;
+ throw r_Error (COMPRESSIONFAILED);
+ }
+#endif
+ if (rest > left)
+ rest = left;
+
+ if (rest != 0)
+ {
+ memcpy(((char*)cache) + cacheOff, dptr, rest);
+
+ if (frag_stored(rest) < 0)
+ return -1;
+
+ left -= rest;
+ dptr += rest;
+ }
+ }
+ return 0;
+}
+
+int r_Lin_Comp_Store::put( unsigned char val )
+{
+ ((unsigned char*)cache)[cacheOff] = val;
+ return frag_stored(1);
+}
+
+int r_Lin_Comp_Store::flush( void )
+{
+ if (streamer != NULL)
+ {
+ if (cacheOff != 0)
+ {
+ if (streamer->put(cache, cacheOff) < 0)
+ return -1;
+
+ cacheOff = 0;
+ }
+ }
+ return 0;
+}
+
+r_ULong r_Lin_Comp_Store::stop( void )
+{
+ RMDBGONCE( 3, RMDebug::module_compression, "r_Lin_Comp_Store", "stop()" );
+ if (streamer == NULL)
+ {
+ return mblocks->get_size(cacheOff);
+ }
+ else
+ {
+ if (flush() < 0)
+ return 0;
+
+ return streamer->end();
+ }
+}
+
+void r_Lin_Comp_Store::copy_data( void *dest )
+{
+ if (streamer == NULL)
+ {
+ mblocks->copy_data(dest, cacheOff);
+ }
+ else
+ {
+ streamer->copy_data(dest);
+ }
+}
+
+void r_Lin_Comp_Store::print_status( std::ostream &str ) const
+{
+ if (streamer == NULL)
+ {
+ str << "[static; " << mblocks->get_number() << " blocks, " << mblocks->get_size(cacheOff) << " bytes]";
+ }
+ else
+ {
+ str << "[stream: " << streamer->get_name() << ']';
+ }
+}
+
+
+std::ostream &operator<<( std::ostream &str, const r_Lin_Comp_Store &store )
+{
+ store.print_status(str);
+ return str;
+}
+
+
+
+
+/*
+ * Linear compression encoders...
+ */
+r_Lin_Comp_Stream::r_Lin_Comp_Stream( const r_Lin_Comp_Stream &src ) : r_Linear_Stream()
+{
+ target = NULL; // anything else would have bad side-effects...
+ streamer = src.streamer;
+ blockSize = src.blockSize;
+ autoDeleteStreams = 0;
+}
+
+r_Lin_Comp_Stream::r_Lin_Comp_Stream( void ) : r_Linear_Stream()
+{
+ target = NULL;
+ streamer = NULL;
+ blockSize = 4096;
+ autoDeleteStreams = 0;
+}
+
+r_Lin_Comp_Stream::~r_Lin_Comp_Stream( void )
+{
+ if (target != NULL)
+ delete target;
+
+ if (autoDeleteStreams != 0)
+ free_streams();
+}
+
+void r_Lin_Comp_Stream::set_block_size( r_ULong bsize )
+{
+ blockSize = bsize;
+}
+
+void r_Lin_Comp_Stream::set_stream( r_Lin_Comp_Stream *str )
+{
+ streamer = str;
+}
+
+r_Lin_Comp_Stream *r_Lin_Comp_Stream::get_stream( void )
+{
+ return streamer;
+}
+
+const r_Lin_Comp_Stream *r_Lin_Comp_Stream::get_stream( void ) const
+{
+ return streamer;
+}
+
+void r_Lin_Comp_Stream::print_bank_name( std::ostream &str ) const
+{
+ const r_Lin_Comp_Stream *s = streamer;
+
+ str << get_name();
+ while (s != NULL)
+ {
+ str << " : " << s->get_name();
+ s = s->get_stream();
+ }
+}
+
+void r_Lin_Comp_Stream::free_streams( void )
+{
+ r_Lin_Comp_Stream *s = streamer;
+
+ while (s != NULL)
+ {
+ r_Lin_Comp_Stream *next = s->get_stream();
+ delete s;
+ s = next;
+ }
+}
+
+const char *r_Lin_Comp_Stream::get_stream_file( void ) const
+{
+ const r_Lin_Comp_Stream *s = this;
+
+ while (s != NULL)
+ {
+ if (s->get_format() == r_Lin_Stream_File)
+ return ((r_File_Comp_Stream*)s)->get_file_name();
+ s = s->streamer;
+ }
+ return NULL;
+}
+
+int r_Lin_Comp_Stream::set_stream_file( const char *name )
+{
+ r_Lin_Comp_Stream *s = this;
+
+ while (s != NULL)
+ {
+ if (s->get_format() == r_Lin_Stream_File)
+ {
+ ((r_File_Comp_Stream*)s)->set_file_name(name);
+ return 1;
+ }
+ s = s->streamer;
+ }
+ return 0;
+}
+
+void r_Lin_Comp_Stream::set_storage_handler( const r_Storage_Man &newStore )
+{
+ mystore = newStore;
+}
+
+void r_Lin_Comp_Stream::set_params( const char *str )
+{
+ if (params != NULL)
+ params->process(str);
+}
+
+void r_Lin_Comp_Stream::init_target( void )
+{
+ if (target != NULL)
+ delete target;
+
+ if (streamer == NULL)
+ target = new r_Lin_Comp_Store(blockSize);
+ else
+ target = new r_Lin_Comp_Store(streamer);
+}
+
+void r_Lin_Comp_Stream::exit_target( void )
+{
+ if (target != NULL)
+ {
+ delete target;
+ target = NULL;
+ }
+}
+
+
+// static member function for creation
+r_Lin_Comp_Stream* r_Lin_Comp_Stream::create( r_Lin_Stream_Format fmt, const char *pstr ) throw(r_Error)
+{
+ switch (fmt)
+ {
+ case r_Lin_Stream_None:
+ return new r_No_Comp_Stream();
+ case r_Lin_Stream_RLE:
+ return new r_RLE_Comp_Stream();
+ case r_Lin_Stream_ZLib:
+ return new r_ZLib_Comp_Stream( pstr );
+ case r_Lin_Stream_Arith:
+ return new r_Arith_Comp_Stream();
+ case r_Lin_Stream_File:
+ return new r_File_Comp_Stream( pstr);
+ default:
+ RMInit::logOut << "Unknown linear compression format " << fmt << endl;
+ r_Error err(r_Error::r_Error_General);
+ throw(err);
+ }
+ return NULL;
+}
+
+// allocate a stream bank
+r_Lin_Comp_Stream* r_Lin_Comp_Stream::create( r_Lin_Stream_Format *ids, const char *pstr ) throw(r_Error)
+{
+ r_Lin_Comp_Stream *result = NULL;
+ unsigned int i;
+
+ for (i=0; ids[i] != r_Lin_Stream_NUMBER; i++) ;
+ try
+ {
+ for (; i!=0; i--)
+ {
+ r_Lin_Comp_Stream *str = create(ids[i-1], pstr);
+ str->set_stream(result);
+ result = str;
+ }
+ }
+ catch( r_Error &err )
+ {
+ if (result != NULL)
+ {
+ result->free_streams();
+ delete result;
+ }
+ throw(err);
+ }
+ // mark the root stream as a stream bank owning all child streams
+ if (result != NULL)
+ result->autoDeleteStreams = 1;
+
+ return result;
+}
+
+
+std::ostream &operator<<( std::ostream &str, const r_Lin_Comp_Stream &comp )
+{
+ comp.print_bank_name(str);
+ return str;
+}
+
+
+
+/*
+ * Linear decompression storage
+ */
+
+r_Lin_Decomp_Store::r_Lin_Decomp_Store( void )
+{
+ RMDBGONCE( 3, RMDebug::module_compression, "r_Lin_Decomp_Store", "r_Lin_Decomp_Store()" );
+ streamer = NULL;
+ cache = NULL;
+}
+
+r_Lin_Decomp_Store::r_Lin_Decomp_Store( r_Lin_Decomp_Stream *str, r_ULong csize )
+{
+ RMDBGONCE( 3, RMDebug::module_compression, "r_Lin_Decomp_Store", "r_Lin_Decomp_Store(" << str->get_name() << ')' );
+ streamer = str;
+ cacheSize = csize;
+ cache = new char[cacheSize];
+}
+
+r_Lin_Decomp_Store::~r_Lin_Decomp_Store( void )
+{
+ if (cache != NULL)
+ delete [] (char*)cache;
+}
+
+int r_Lin_Decomp_Store::start( r_Bytes typeSize, const void *data, r_ULong size )
+{
+ if (streamer == NULL)
+ {
+ RMDBGONCE( 4, RMDebug::module_compression, "r_Lin_Decomp_Store", "start() static" );
+ dataBase = data;
+ dataSize = size;
+ dataOffset = 0;
+ }
+ else
+ {
+ RMDBGONCE( 4, RMDebug::module_compression, "r_Lin_Decomp_Store", "start() stream " << streamer->get_name() );
+ cacheLevel = 0;
+ cacheOff = 0;
+ return streamer->begin(typeSize, data, size);
+ }
+ return 0;
+}
+
+int r_Lin_Decomp_Store::ensure_data( void )
+{
+ // in static mode, we don't have to do anything.
+ if ((streamer != NULL) && (cacheOff >= cacheLevel))
+ {
+ // returns 0 for OK or the _negative_ number of unread bytes
+ int status = streamer->get(cache, cacheSize);
+ if (status < 0)
+ {
+ cacheLevel = (r_ULong)((r_Long)cacheSize + (r_Long)status);
+ if (cacheLevel == 0)
+ return -1;
+ }
+ else
+ {
+ // total refill of cache possible
+ cacheLevel = cacheSize;
+ }
+ cacheOff = 0;
+ //cout << "CACHE LEVEL " << cacheLevel << endl;
+ return 1;
+ }
+ return 0;
+}
+
+int r_Lin_Decomp_Store::get( void *data, r_ULong size )
+{
+ r_ULong rest;
+
+ if (streamer == NULL)
+ {
+ rest = dataSize - dataOffset;
+ if (rest > size)
+ rest = size;
+ memcpy(data, ((const char*)dataBase) + dataOffset, rest);
+ dataOffset += rest;
+ if (rest < size)
+ return -((int)(size - rest));
+ }
+ else
+ {
+ r_ULong left = size;
+ char *dptr = (char*)data;
+
+ while (left != 0)
+ {
+ if (ensure_data() < 0)
+ return -((int)left);
+
+ rest = cacheLevel - cacheOff;
+ if (rest > left)
+ rest = left;
+
+ memcpy(dptr, ((char*)cache) + cacheOff, rest);
+ dptr += rest;
+ cacheOff += rest;
+ left -= rest;
+ }
+ }
+ return 0;
+}
+
+int r_Lin_Decomp_Store::get( unsigned char &val )
+{
+ if (streamer == NULL)
+ {
+ if (dataOffset >= dataSize)
+ return -1;
+
+ val = ((unsigned char*)dataBase)[dataOffset++];
+ }
+ else
+ {
+ if (ensure_data() < 0)
+ return -1;
+
+ val = ((unsigned char*)cache)[cacheOff++];
+ }
+ return 0;
+}
+
+int r_Lin_Decomp_Store::stop( void )
+{
+ RMDBGONCE( 4, RMDebug::module_compression, "r_Lin_Decomp_Store", "stop()" );
+ if (streamer != NULL)
+ {
+ return streamer->end();
+ }
+ return 0;
+}
+
+const void *r_Lin_Decomp_Store::frag_ptr( void ) const
+{
+ if (streamer == NULL)
+ return (const void*)(((char*)dataBase)+dataOffset);
+
+ return (const void*)(((char*)cache)+cacheOff);
+}
+
+r_ULong r_Lin_Decomp_Store::frag_size( void ) const
+{
+ if (streamer == NULL)
+ return dataSize - dataOffset;
+
+ return cacheLevel - cacheOff;
+}
+
+int r_Lin_Decomp_Store::frag_read( r_ULong size )
+{
+ if (streamer == NULL)
+ dataOffset += size;
+ else
+ cacheOff += size;
+
+ return 0;
+}
+
+void r_Lin_Decomp_Store::print_status( std::ostream &str ) const
+{
+ if (streamer == NULL)
+ {
+ str << "[static: current " << dataOffset << ", total " << dataSize << ']';
+ }
+ else
+ {
+ str << "[stream: " << streamer->get_name() << ']';
+ }
+}
+
+
+std::ostream &operator<<( std::ostream &str, const r_Lin_Decomp_Store &store )
+{
+ store.print_status(str);
+ return str;
+}
+
+
+
+/*
+ * linear compression decoders
+ */
+r_Lin_Decomp_Stream::r_Lin_Decomp_Stream( void )
+{
+ params = NULL;
+ source = NULL;
+ streamer = NULL;
+ autoDeleteStreams = 0;
+}
+
+r_Lin_Decomp_Stream::~r_Lin_Decomp_Stream( void )
+{
+ if (source != NULL)
+ delete source;
+
+ if (autoDeleteStreams != 0)
+ free_streams();
+}
+
+void r_Lin_Decomp_Stream::set_params( const char *str )
+{
+ if (params != NULL)
+ params->process(str);
+}
+
+void r_Lin_Decomp_Stream::set_stream( r_Lin_Decomp_Stream *str )
+{
+ streamer = str;
+}
+
+r_Lin_Decomp_Stream *r_Lin_Decomp_Stream::get_stream( void )
+{
+ return streamer;
+}
+
+const r_Lin_Decomp_Stream *r_Lin_Decomp_Stream::get_stream( void ) const
+{
+ return streamer;
+}
+
+void r_Lin_Decomp_Stream::print_bank_name( std::ostream &str ) const
+{
+ const r_Lin_Decomp_Stream *s = streamer;
+
+ str << get_name();
+ while (s != NULL)
+ {
+ str << " : " << s->get_name();
+ s = s->get_stream();
+ }
+}
+
+void r_Lin_Decomp_Stream::free_streams( void )
+{
+ r_Lin_Decomp_Stream *s = streamer;
+
+ while (s != NULL)
+ {
+ r_Lin_Decomp_Stream *next = s->get_stream();
+ delete s;
+ s = next;
+ }
+}
+
+const char *r_Lin_Decomp_Stream::get_stream_file( void ) const
+{
+ const r_Lin_Decomp_Stream *s = this;
+
+ while (s != NULL)
+ {
+ if (s->get_format() == r_Lin_Stream_File)
+ return ((r_File_Decomp_Stream*)s)->get_file_name();
+ s = s->streamer;
+ }
+ return NULL;
+}
+
+int r_Lin_Decomp_Stream::set_stream_file( const char *name )
+{
+ r_Lin_Decomp_Stream *s = this;
+
+ while (s != NULL)
+ {
+ if (s->get_format() == r_Lin_Stream_File)
+ {
+ ((r_File_Decomp_Stream*)s)->set_file_name(name);
+ return 1;
+ }
+ s = s->streamer;
+ }
+ return 0;
+}
+
+void r_Lin_Decomp_Stream::init_source( void )
+{
+ if (source != NULL)
+ delete source;
+
+ if (streamer == NULL)
+ source = new r_Lin_Decomp_Store();
+ else
+ source = new r_Lin_Decomp_Store(streamer);
+}
+
+void r_Lin_Decomp_Stream::exit_source( void )
+{
+ delete source;
+ source = NULL;
+}
+
+// static member function for creation
+r_Lin_Decomp_Stream* r_Lin_Decomp_Stream::create( r_Lin_Stream_Format fmt, const char *pstr ) throw(r_Error)
+{
+ switch (fmt)
+ {
+ case r_Lin_Stream_None:
+ return new r_No_Decomp_Stream();
+ case r_Lin_Stream_RLE:
+ return new r_RLE_Decomp_Stream();
+ case r_Lin_Stream_ZLib:
+ return new r_ZLib_Decomp_Stream();
+ case r_Lin_Stream_Arith:
+ return new r_Arith_Decomp_Stream();
+ case r_Lin_Stream_File:
+ return new r_File_Decomp_Stream( pstr );
+ default:
+ RMInit::logOut << "Unknown linear compression format " << fmt << endl;
+ r_Error err(r_Error::r_Error_General);
+ throw(err);
+ }
+ return NULL;
+}
+
+// allocate a stream bank
+r_Lin_Decomp_Stream* r_Lin_Decomp_Stream::create( r_Lin_Stream_Format *ids, const char *pstr ) throw(r_Error)
+{
+ r_Lin_Decomp_Stream *result = NULL;
+ unsigned int i;
+
+ for (i=0; ids[i] != r_Lin_Stream_NUMBER; i++) ;
+ try
+ {
+ for (; i!=0; i--)
+ {
+ r_Lin_Decomp_Stream *str = create(ids[i-1], pstr);
+ str->set_stream(result);
+ result = str;
+ }
+ }
+ catch( r_Error &err )
+ {
+ if (result != NULL)
+ {
+ result->free_streams();
+ delete result;
+ }
+ throw(err);
+ }
+ // mark the root stream as a stream bank owning all the child streams
+ if (result != NULL)
+ result->autoDeleteStreams = 1;
+
+ return result;
+}
+
+
+std::ostream &operator<<( std::ostream &str, const r_Lin_Decomp_Stream &decomp )
+{
+ decomp.print_bank_name(str);
+ return str;
+}
+
+
+
+/*
+ * The container object for matching compression / decompression streams
+ */
+
+r_Lin_Codec_Stream::r_Lin_Codec_Stream( void ) : comp(NULL), decomp(NULL)
+{
+}
+
+
+r_Lin_Codec_Stream::r_Lin_Codec_Stream( r_Linear_Stream::r_Lin_Stream_Format fmt, const char *pstr )
+{
+ comp = r_Lin_Comp_Stream::create(fmt, pstr);
+ decomp = r_Lin_Decomp_Stream::create(fmt, pstr);
+}
+
+
+r_Lin_Codec_Stream::r_Lin_Codec_Stream( r_Linear_Stream::r_Lin_Stream_Format *ids, const char *pstr )
+{
+ comp = r_Lin_Comp_Stream::create(ids, pstr);
+ decomp = r_Lin_Decomp_Stream::create(ids, pstr);
+}
+
+
+r_Lin_Codec_Stream::r_Lin_Codec_Stream( const r_Lin_Codec_Stream &lc )
+{
+ comp = lc.comp->clone();
+ decomp = lc.decomp->clone();
+}
+
+
+r_Lin_Codec_Stream::~r_Lin_Codec_Stream( void )
+{
+ if (comp != NULL)
+ delete comp;
+ if (decomp != NULL)
+ delete decomp;
+}
diff --git a/compression/lincompstream.hh b/compression/lincompstream.hh
new file mode 100644
index 0000000..2e6793e
--- /dev/null
+++ b/compression/lincompstream.hh
@@ -0,0 +1,553 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: lincompstream.hh
+ *
+ * MODULE: compression
+ * CLASS: r_Lin_Comp_Stream, r_Lin_Decomp_Stream
+ *
+ * PURPOSE:
+ * Abstract base class for linear compression streams
+ *
+ * COMMENTS:
+ *
+*/
+
+#ifndef _LINCOMPSTREAM_H_
+#define _LINCOMPSTREAM_H_
+
+
+#include <stdio.h>
+#include <iostream>
+
+#include "raslib/error.hh"
+#include "raslib/storageman.hh"
+#include "raslib/odmgtypes.hh"
+
+
+
+
+class r_Parse_Params;
+class RMTimer;
+
+
+//@ManMemo: Module {\bf compression}
+
+/*@Doc:
+ r_Linear_Stream:
+ Abstract base class for linear compression and decompression strings.
+ Implements enumerator and common interface calls.
+ Linear streams are used to compress or uncompress data in a given format.
+ The can operate in static mode (the compressed data is stored to / read
+ from memory directly) or in streaming mode (the compressed data is stored
+ to / read from another linear stream, without having to buffer intermediate
+ data explicitly or in its entirety). Streaming mode results in nesting
+ linear streams, which can be done to arbitrary depth.
+*/
+
+class r_Linear_Stream
+{
+ public:
+ // stream identifiers
+ enum r_Lin_Stream_Format {
+ r_Lin_Stream_None,
+ r_Lin_Stream_RLE,
+ r_Lin_Stream_ZLib,
+ r_Lin_Stream_Arith,
+ r_Lin_Stream_File,
+ r_Lin_Stream_NUMBER // used as error code
+ };
+ /// default constructor
+ r_Linear_Stream( void );
+ /// destructor
+ virtual ~r_Linear_Stream( void );
+ /// identification
+ virtual r_Lin_Stream_Format get_format( void ) const = 0;
+ /// get the name of the stream, returns r_Lin_Stream_Void if unknown
+ virtual const char* get_name(void) const = 0;
+ /// set compression parameters from a string
+ virtual void set_params( const char *str ) = 0;
+ /// set number of symbols in the stream (used by e.g. arithmetic coders)
+ virtual int set_num_symbols( unsigned int syms );
+ /// get stream identifier from name
+ static r_Lin_Stream_Format get_id( const char *name );
+ /**
+ the name (case independent) may be one of the following
+
+ \begin{tabular}{ll}
+ none && r_No_(De)Comp_Stream\\
+ rle && r_RLE_(De)Comp_Stream\\
+ zlib && r_ZLib_(De)Comp_Stream\\
+ arith && r_Arith_(De)Comp_Stream\\
+ file && r_File_(De)Comp_Stream\\
+ end{tabular}
+ */
+ /// return the string representation of the given format
+ static const char *get_format_string( r_Lin_Stream_Format fmt );
+ /// return a linear stream bank (concatenated streams), terminated by r_Lin_Stream_NUMBER
+ static r_Lin_Stream_Format *get_bank_ids( const char *names );
+ /// return a string representation of the stream bank (caller frees with delete[])
+ static char *get_bank_string( const r_Lin_Stream_Format *ids );
+
+
+ protected:
+ /// instantiate the timer for benchmarking with a certain level
+ void instantiate_timer( const char *func, int level=0 );
+ /// parameters
+ r_Parse_Params *params;
+ /// timer for benchmarking; always defined to keep object size constant
+ RMTimer *myTimer;
+ /// the character used to separate stream names in stream banks
+ static const char bankNameSep;
+};
+
+
+//@ManMemo: Module {\bf compression}
+
+/// string output
+extern std::ostream &operator<<( std::ostream &s, r_Linear_Stream::r_Lin_Stream_Format fmt );
+
+
+
+//@ManMemo: Module {\bf compression}
+
+/*@Doc:
+ r_Lin_Comp_Store:
+ Class abstracting between storing compressed data statically in an object of
+ type r_Memory_Block_Vector or another r_Lin_Comp_Stream to unify normal and
+ (nested) streaming interface. There is a high-level and a low-level interface.
+ The high-level interface allows writing a specified number of bytes to the
+ object (which will redirect it to memory or stream automatically) and is the
+ preferred way. The low-level interface allows block-oriented, external
+ compression libraries like ZLib to operate by giving it a block to store
+ data to. In this case, use frag_ptr() to get the address of a block of
+ memory (``fragment'') which can be written to, the maximum size of which can
+ be obtained with frag_size() and write to it. After your data has been
+ written, you MUST call frag_stored() with the number of bytes you wrote to
+ frag_ptr(), otherwise subsequent calls of frag_ptr() will all return the
+ same data. See zlibstream for an implementation using the low-level
+ interface and the other streams on how the high-level interface is used.
+*/
+
+class r_Lin_Comp_Stream;
+class r_Memory_Block_Vector;
+
+class r_Lin_Comp_Store
+{
+ public:
+ /// constructor for static mode, receiving block size for r_Memory_Block_Vector.
+ r_Lin_Comp_Store( r_ULong bsize );
+ /// constructor for streaming mode, receiving stream compression object and cache size
+ r_Lin_Comp_Store( r_Lin_Comp_Stream *str, r_ULong csize=4096 );
+ /// destructor
+ ~r_Lin_Comp_Store( void );
+
+ /// start output
+ int start( r_Bytes typeSize );
+ /// write data; return 0 for OK, -1 for error
+ int put( const void *data, r_ULong size );
+ /// write single byte
+ int put( unsigned char val );
+ /// stop outputting data and return size
+ r_ULong stop( void );
+ /// copy the data
+ void copy_data( void *dest );
+ /// flush data
+ int flush( void );
+ /// get pointer to current fragment (low-level interface)
+ void *frag_ptr( void );
+ /// get the remaining space in the current fragmend (low-level interface)
+ r_ULong frag_size( void ) const;
+ /// notify that size bytes have been store to current fragmemt (low-level interface)
+ int frag_stored( r_ULong size );
+ /// print status
+ void print_status( std::ostream &str ) const;
+
+
+ protected:
+ /// memory block vector for static mode
+ r_Memory_Block_Vector *mblocks;
+ /// compression stream for streaming mode
+ r_Lin_Comp_Stream *streamer;
+ /// cache in streaming mode
+ void *cache;
+ /// size and current offset in both modes
+ r_ULong cacheSize;
+ r_ULong cacheOff;
+};
+
+extern std::ostream &operator<<( std::ostream &str, const r_Lin_Comp_Store &store );
+
+
+
+//@ManMemo: Module {\bf compression}
+
+/*@Doc:
+ Abstract base class for linear compression streams. Memory allocation is all
+ done transparently in the background. This class provides a common interface
+ to compression methods like zlib or RLE. It can operate in static or streaming
+ mode. In static mode, compressed data is stored explicitly in memory as a whole,
+ whereas in streaming mode, data merely streams through the object and is piped
+ into another object of type r_Lin_Comp_Stream; only a small amount of compressed
+ data is buffered internally for more efficiency. Use set_stream(str) with str != NULL
+ to activate streaming mode, using str as the receiving class.
+*/
+
+class r_Lin_Comp_Stream : public r_Linear_Stream
+{
+ public:
+ /// default constructor
+ r_Lin_Comp_Stream( void );
+ /// copy constructor
+ r_Lin_Comp_Stream( const r_Lin_Comp_Stream &src );
+ /// destructor
+ virtual ~r_Lin_Comp_Stream( void );
+
+ /// change memory handlers (don't change between begin() ... end()!)
+ virtual void set_storage_handler( const r_Storage_Man &newStore );
+
+ /// creation
+ static r_Lin_Comp_Stream* create( r_Lin_Stream_Format fmt, const char *pstr=NULL ) throw(r_Error);
+ /**
+ fmt may be one of the following:
+
+ \begin{tabular}{ll}
+ r_Lin_Stream_None && r_No_(De)Comp_Stream\\
+ r_Lin_Stream_RLE && r_RLE_(De)Comp_Stream\\
+ r_Lin_Stream_ZLib && r_ZLib_(De)Comp_Stream\\
+ r_Lin_Stream_Arith && r_Arith_(De)Comp_Stream\\
+ r_Lin_Stream_File && r_File_(De)Comp_Stream\\
+ \end{tabular}
+
+ In addition, theres r_Lin_Stream_NUMBER used as error code.
+ */
+
+ /// create a stream bank (format as returned by r_Linear_Stream::get_bank_ids() )
+ static r_Lin_Comp_Stream* create( r_Lin_Stream_Format *ids, const char *pstr=NULL ) throw(r_Error);
+
+ /// cloning
+ virtual r_Lin_Comp_Stream* clone( void ) const = 0;
+
+ /// set block size
+ void set_block_size( r_ULong bsize );
+ /// select streaming interface
+ void set_stream( r_Lin_Comp_Stream *str );
+ /*
+ Streamed compression doesn't buffer the data but writes it to the specified
+ lincompstream instead. This allows easy and efficient concatenation of
+ compression streams.
+ */
+ /// get read/write streamer object
+ r_Lin_Comp_Stream *get_stream( void );
+ /// get read-only streamer object
+ const r_Lin_Comp_Stream *get_stream( void ) const;
+ /// print the name of the entire stream bank (recursively)
+ void print_bank_name( std::ostream &str ) const;
+ /// free all child streams (recursively set by set_stream() )
+ void free_streams( void );
+ /// get the name of the output file, or NULL if stream bank doesn't contain file stream
+ const char *get_stream_file( void ) const;
+ /// set the name of the output file if stream bank contains file stream, otherwise return 0
+ int set_stream_file( const char *name );
+
+
+ //@Man: Interface
+ //@{
+ /**
+ typeSize is the size of the base type to encode which is important
+ for some derived classes (e.g. RLE). Make sure that all size arguments
+ must be multiples of typeSize later on. The value 1 should always
+ work, but will usually not be optimal.
+ the inputSize parameter of begin() is the size of the input data or
+ 0 for using defaults). This parameter directly influences the size
+ of the input buffer for some streams and should therefore be used
+ with care.
+ */
+ /// begin compression
+ virtual int begin( r_Bytes typeSize, r_ULong inputSize=0 ) = 0;
+ /// write data to stream
+ virtual int put( const void* data, r_ULong size ) = 0;
+ /// end compression
+ virtual void* end( r_ULong &size ) = 0;
+ /**
+ standard end call, allocates new (linear) memory, copies the data
+ there and frees all internal data
+ */
+ /// alternative end call, just finalizes the stream and returns the size
+ virtual r_ULong end( void ) = 0;
+ /// copy output data into linear memory
+ virtual void copy_data( void* dest ) = 0;
+ //@}
+ virtual void set_params( const char *str );
+
+
+ protected:
+ /// init the target object according to the mode
+ void init_target( void );
+ /// completely finished the target object
+ void exit_target( void );
+ /// memory management object, defaults to C-style
+ r_Storage_Man mystore;
+ /// storage abstraction object
+ r_Lin_Comp_Store *target;
+ /// compression stream for streaming mode
+ r_Lin_Comp_Stream *streamer;
+ /// block size for static mode
+ r_ULong blockSize;
+ /// automatically delete all child streams in destructor if bank constructor was used
+ int autoDeleteStreams;
+};
+
+
+//@ManMemo: Moduke {\bf compression}
+
+//@Doc: print the stream (bank) name of the compression stream to a C++ stream
+
+extern std::ostream &operator<<( std::ostream &str, const r_Lin_Comp_Stream &comp );
+
+
+
+//@ManMemo: Module {\bf compression}
+
+/*@Doc:
+ r_Lin_Decomp_Store:
+ Class abstracting between loading data from raw memory or from another r_Lin_Decomp_Stream
+ to unify normal and (nested) streaming interface. As in r_Lin_Comp_Store, there's a
+ high-level and a low-level interface. The high-level interface can be used to request
+ a specified number of bytes from the storage source (memory or another stream). The
+ low-level interface can be used for external, block-oriented compression libraries
+ like ZLib. Use frag_ptr() to get the start address of the input data and frag_size()
+ for the maximum number of bytes you can read from there. After you read a block, you
+ must call frag_read() with the size of the block as argument, otherwise frag_ptr()
+ will always return the same data. In addition, you should always call ensure_data()
+ before you call frag_ptr(). For an implementation of the low-level interface see
+ zlibstream and the other streams on how the high-level interface should be used.
+ */
+
+class r_Lin_Decomp_Stream;
+
+class r_Lin_Decomp_Store
+{
+ public:
+ /// constructor for static mode
+ r_Lin_Decomp_Store( void );
+ /// constructor for streaming mode, receiving stream decompression object and cache size
+ r_Lin_Decomp_Store( r_Lin_Decomp_Stream *str, r_ULong csize=4096 );
+ /// destructor
+ ~r_Lin_Decomp_Store( void );
+
+ /// start reading data
+ int start( r_Bytes typeSize, const void *data, r_ULong size );
+ /// read data, returns 0 for OK, negative number of unread bytes otherwise
+ int get( void *data, r_ULong size );
+ /// read single byte; returns 0 for OK, -1 for error
+ int get( unsigned char &val );
+ /// stop reading data
+ int stop( void );
+ /// makes sure there's some data in the cache in streaming mode, returns -1 if EOF
+ int ensure_data( void );
+ /// get pointer to current fragment (low-level interface)
+ const void *frag_ptr( void ) const;
+ /// get the valid bytes in the current fragment (low-level interface)
+ r_ULong frag_size( void ) const;
+ /// notify that size bytes have been read from the current fragment
+ int frag_read( r_ULong size );
+ /// print status
+ void print_status( std::ostream &str ) const;
+
+
+ protected:
+ /// start of compressed data in static mode
+ const void *dataBase;
+ /// size of compressed data in static mode
+ r_ULong dataSize;
+ /// current offset in compressed data in static mode
+ r_ULong dataOffset;
+ /// decompression stream in streaming mode
+ r_Lin_Decomp_Stream *streamer;
+ /// cache in streaming mode
+ void *cache;
+ /// cache size, current fill level and current offset in streaming mode
+ r_ULong cacheSize;
+ r_ULong cacheLevel;
+ r_ULong cacheOff;
+};
+
+extern std::ostream &operator<<( std::ostream &str, const r_Lin_Decomp_Store &store );
+
+
+
+//@ManMemo: Module {\bf compression}
+
+/*@Doc:
+ r_Lin_Decomp_Stream:
+ Abstract base class for linear decompression streams. Linear decompression streams
+ can operate in static mode (compressed data is read directly from memory) and
+ streaming mode (compressed data is read from another linear decompression stream).
+ In streaming mode, only a small amount of compressed data is ever buffered
+ internally for more efficiency. Use set_stream(str) with str != NULL to activate
+ streaming mode, using str as the stream providing the input data for this stream.
+ The data and size passed to the begin() method actually belong to str and are
+ passed to it automatically.
+ */
+
+class r_Lin_Decomp_Stream : public r_Linear_Stream
+{
+ public:
+ /// default constructor
+ r_Lin_Decomp_Stream( void );
+ /// destructor
+ virtual ~r_Lin_Decomp_Stream( void );
+
+ /// creation
+ static r_Lin_Decomp_Stream* create( r_Lin_Stream_Format fmt, const char *pstr=NULL ) throw(r_Error);
+ /**
+ for the values of fmt see r_Lin_Comp_Stream::create()
+ */
+ /// create a stream bank
+ static r_Lin_Decomp_Stream* create( r_Lin_Stream_Format *ids, const char *pstr=NULL ) throw(r_Error);
+
+ /// cloning
+ virtual r_Lin_Decomp_Stream* clone( void ) const = 0;
+
+ /// select streaming interface
+ void set_stream( r_Lin_Decomp_Stream *str );
+ /*
+ Streamed decompression doesn't read the data from linear memory but from another
+ object of type r_Lin_Decomp_Stream instead to allow easy and efficient concatenation
+ of decompression streams.
+ */
+ /// get read/write streamer object
+ r_Lin_Decomp_Stream *get_stream( void );
+ /// get read-only streamer object
+ const r_Lin_Decomp_Stream *get_stream( void ) const;
+ /// print the name of the entire stream bank (recursively)
+ void print_bank_name( std::ostream &str ) const;
+ /// free all child streams
+ void free_streams( void );
+ /// get the name of the output file, or NULL if stream bank doesn't contain file stream
+ const char *get_stream_file( void ) const;
+ /// set the name of the output file if stream bank contains file stream, otherwise return 0
+ int set_stream_file( const char *name );
+
+ //@Man: Interface
+ //@{
+ /**
+ You can use three approaches:
+ \begin{enumerate}
+ \item
+ supply dest to begin() and use the get(size) call which will
+ store data to dest and increment dest afterwards, or
+ \item
+ use get(buffer, size) (in that case dest is irrelevant), or
+ \item
+ supply dest to begin() to store the pointer internally, retrieve
+ the pointer later using getDestPtr() and use it in some other
+ way in get(buffer, size) calls.
+ \end{enumerate}
+ */
+ /// get the pointer to destination stored within the object
+ inline void* get_dest_ptr(void) {return destPtr;}
+ /// start decompression.
+ virtual int begin( r_Bytes typeSize, const void* data, r_ULong size,
+ void* dest=NULL ) = 0;
+ /// get() returns 0 for OK, otherwise the negative number of non-read bytes
+ virtual int get( void* buffer, r_ULong size ) = 0;
+ /// get data and store it in the internal destptr (which is incremented)
+ virtual int get( r_ULong size ) = 0;
+ /// end decompression
+ virtual int end( void ) = 0;
+ //@}
+ /// set compression parameters from string
+ virtual void set_params( const char *str );
+
+
+ protected:
+ /// prepare the storage abstraction object
+ void init_source( void );
+ /// finished with the storage abstraction object
+ void exit_source( void );
+ /// default destination
+ void* destPtr;
+ /// storage abstraction object
+ r_Lin_Decomp_Store *source;
+ /// stream object in streaming mode
+ r_Lin_Decomp_Stream *streamer;
+ /// automatically delete all child streams in destructor if bank constructor was used
+ int autoDeleteStreams;
+};
+
+
+//@ManMemo: Module {\bf compression}
+
+//@Doc: print the stream (bank) name of the decompression stream to a C++ stream
+
+extern std::ostream &operator<<( std::ostream &str, const r_Lin_Decomp_Stream &decomp );
+
+
+
+
+//@ManMemo: Module {\bf compression}
+
+/*@Doc:
+ Container class for matching compression and decompression streams
+*/
+
+class r_Lin_Codec_Stream
+{
+ public:
+ /// default constructor, should not be used
+ r_Lin_Codec_Stream( void );
+ /// constructor that creates the codecs
+ r_Lin_Codec_Stream( r_Linear_Stream::r_Lin_Stream_Format fmt, const char *pstr=NULL );
+ /**
+ for the values of fmt see r_Lin_Comp_Stream::create()
+ */
+ /// constructor for a codec bank
+ r_Lin_Codec_Stream( r_Linear_Stream::r_Lin_Stream_Format *ids, const char *pstr=NULL );
+
+ /// copy constructor
+ r_Lin_Codec_Stream( const r_Lin_Codec_Stream &lc );
+ /// destructor
+ ~r_Lin_Codec_Stream( void );
+
+ /// get the stream format
+ inline r_Linear_Stream::r_Lin_Stream_Format get_format( void ) {
+ return comp->get_format();
+ }
+ /// get the compression stream
+ inline r_Lin_Comp_Stream *get_comp_stream( void ) {
+ return comp;
+ }
+ /// get the decompression stream
+ inline r_Lin_Decomp_Stream *get_decomp_stream( void ) {
+ return decomp;
+ }
+
+
+ protected:
+ r_Lin_Comp_Stream *comp;
+ r_Lin_Decomp_Stream *decomp;
+};
+
+#endif
diff --git a/compression/nocompstream.cc b/compression/nocompstream.cc
new file mode 100644
index 0000000..a5758f7
--- /dev/null
+++ b/compression/nocompstream.cc
@@ -0,0 +1,194 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: nocompstream.cc
+ *
+ * MODULE: compression
+ * CLASS: r_No_Comp_Stream, r_No_Decomp_Stream
+ *
+ * COMMENTS:
+ *
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+
+#include "compression/nocompstream.hh"
+#include "compression/compresstime.hh"
+#include "raslib/rminit.hh"
+#include "raslib/rmdebug.hh"
+
+
+
+
+r_No_Comp_Stream::r_No_Comp_Stream( void ) : r_Lin_Comp_Stream()
+{
+ blockSize = 4096;
+}
+
+r_No_Comp_Stream::r_No_Comp_Stream( const r_No_Comp_Stream& src ) : r_Lin_Comp_Stream(src)
+{
+ blockSize = src.blockSize;
+}
+
+r_No_Comp_Stream::~r_No_Comp_Stream( void )
+{
+}
+
+int r_No_Comp_Stream::begin( r_Bytes typeSize, r_ULong inputSize )
+{
+ CBENCH_STATEMENT(instantiate_timer("compress", 0));
+ init_target();
+ int status = target->start(typeSize);
+ CBENCH_STATEMENT(myTimer->pause());
+ return status;
+}
+
+int r_No_Comp_Stream::put( const void* data, r_ULong size )
+{
+ CBENCH_STATEMENT(myTimer->resume());
+ int status = target->put(data, size);
+ CBENCH_STATEMENT(myTimer->pause());
+ return status;
+}
+
+void* r_No_Comp_Stream::end( r_ULong &size )
+{
+ CBENCH_STATEMENT(myTimer->resume());
+
+ size = target->stop();
+ void* result;
+
+ if (size == 0)
+ {
+ CBENCH_STATEMENT(myTimer->stop());
+ return NULL;
+ }
+
+ result = mystore.storage_alloc(size);
+
+ target->copy_data(result);
+
+ exit_target();
+
+ CBENCH_STATEMENT(myTimer->stop());
+
+ return result;
+}
+
+r_ULong r_No_Comp_Stream::end( void )
+{
+ CBENCH_STATEMENT(myTimer->resume());
+ r_ULong size = target->stop();
+ CBENCH_STATEMENT(myTimer->stop());
+ return size;
+}
+
+void r_No_Comp_Stream::copy_data( void* dest )
+{
+ target->copy_data(dest);
+
+ exit_target();
+}
+
+const char* r_No_Comp_Stream::get_name( void ) const
+{
+ return "r_No_Comp_Stream";
+}
+
+r_Linear_Stream::r_Lin_Stream_Format r_No_Comp_Stream::get_format( void ) const
+{
+ return r_Lin_Stream_None;
+}
+
+r_Lin_Comp_Stream* r_No_Comp_Stream::clone( void ) const
+{
+ return new r_No_Comp_Stream(*this);
+}
+
+
+
+
+r_No_Decomp_Stream::r_No_Decomp_Stream( void ) : r_Lin_Decomp_Stream()
+{
+}
+
+r_No_Decomp_Stream::r_No_Decomp_Stream( const r_No_Decomp_Stream& src ) : r_Lin_Decomp_Stream()
+{
+}
+
+r_No_Decomp_Stream::~r_No_Decomp_Stream( void )
+{
+}
+
+int r_No_Decomp_Stream::begin( r_Bytes typeSize, const void* data, r_ULong size, void* dest )
+{
+ CBENCH_STATEMENT(instantiate_timer("decompress", 0));
+ init_source();
+ int status = source->start(typeSize, data, size);
+ CBENCH_STATEMENT(myTimer->pause());
+ return status;
+}
+
+int r_No_Decomp_Stream::get( void* buffer, r_ULong size )
+{
+ CBENCH_STATEMENT(myTimer->resume());
+ int status = source->get(buffer, size);
+ CBENCH_STATEMENT(myTimer->pause());
+ return status;
+}
+
+int r_No_Decomp_Stream::get( r_ULong size )
+{
+ CBENCH_STATEMENT(myTimer->resume());
+ int status = get(destPtr, size);
+ destPtr = (void*)(((char*)destPtr) + size);
+ CBENCH_STATEMENT(myTimer->pause());
+ return status;
+}
+
+int r_No_Decomp_Stream::end( void )
+{
+ CBENCH_STATEMENT(myTimer->resume());
+ int status = source->stop();
+ exit_source();
+ CBENCH_STATEMENT(myTimer->stop());
+ return status;
+}
+
+const char* r_No_Decomp_Stream::get_name( void ) const
+{
+ return "r_No_Decomp_Stream";
+}
+
+r_Linear_Stream::r_Lin_Stream_Format r_No_Decomp_Stream::get_format( void ) const
+{
+ return r_Lin_Stream_None;
+}
+
+r_Lin_Decomp_Stream* r_No_Decomp_Stream::clone( void ) const
+{
+ return new r_No_Decomp_Stream(*this);
+}
diff --git a/compression/nocompstream.hh b/compression/nocompstream.hh
new file mode 100644
index 0000000..8f8aa0d
--- /dev/null
+++ b/compression/nocompstream.hh
@@ -0,0 +1,101 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: nocompstream.hh
+ *
+ * MODULE: compression
+ * CLASS: r_No_Comp_Stream, r_No_Decomp_Stream
+ *
+ * COMMENTS:
+ *
+*/
+
+#ifndef _NOCOMPSTREAM_H_
+#define _NOCOMPSTREAM_H_
+
+
+#include "compression/lincompstream.hh"
+
+
+
+//@ManMemo: Module {\bf compression}
+
+//@Man: compression
+
+/*@Doc:
+ Linear compression class implementing simple storage without
+ compression.
+*/
+
+class r_No_Comp_Stream : public r_Lin_Comp_Stream
+{
+public:
+ /// default constructor
+ r_No_Comp_Stream( void );
+ /// copy constructor
+ r_No_Comp_Stream( const r_No_Comp_Stream& src );
+ /// destructor
+ ~r_No_Comp_Stream( void );
+ /// identification
+ r_Lin_Stream_Format get_format( void ) const;
+ const char* get_name( void ) const;
+ /// cloning
+ r_Lin_Comp_Stream* clone( void ) const;
+ /// control compression
+ int begin( r_Bytes typeSize, r_ULong inputSize=0 );
+ int put( const void* data, r_ULong size );
+ void* end( r_ULong &size );
+ r_ULong end( void );
+ void copy_data( void* dest );
+};
+
+
+//@Man: Decompression
+
+/*@Doc:
+ Linear decompression class implementing simple storage without
+ decompression.
+*/
+class r_No_Decomp_Stream : public r_Lin_Decomp_Stream
+{
+public:
+ /// default constructor
+ r_No_Decomp_Stream( void );
+ /// copy constructor
+ r_No_Decomp_Stream( const r_No_Decomp_Stream& src );
+ /// destructor
+ ~r_No_Decomp_Stream( void );
+ /// identification
+ r_Lin_Stream_Format get_format( void ) const;
+ const char* get_name( void ) const;
+ /// cloning
+ r_Lin_Decomp_Stream* clone( void ) const;
+ /// control decompression
+ int begin( r_Bytes typeSize, const void* data, r_ULong size,
+ void* dest=NULL );
+ int get( void* buffer, r_ULong size );
+ int get( r_ULong size );
+ int end( void );
+};
+
+#endif
diff --git a/compression/tilecompnone.cc b/compression/tilecompnone.cc
new file mode 100644
index 0000000..12d4908
--- /dev/null
+++ b/compression/tilecompnone.cc
@@ -0,0 +1,104 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: tilecompnone.cc
+ *
+ * MODULE: compression
+ * CLASS: r_Tile_Comp_None
+ *
+ * COMMENTS:
+ *
+*/
+
+#include <string.h>
+
+#include "raslib/rminit.hh"
+#include "raslib/rmdebug.hh"
+#include "compression/tilecompnone.hh"
+
+
+r_Tile_Comp_None::r_Tile_Comp_None( const r_Minterval &dom, const r_Base_Type *type ) : r_Tile_Compression(dom, type)
+{
+ RMDBGONCE( 2, RMDebug::module_compression, "r_Tile_Comp_None", "r_Tile_Comp_None(dom,type)" );
+}
+
+
+r_Tile_Comp_None::r_Tile_Comp_None( const r_Tile_Comp_None &src) : r_Tile_Compression(src)
+{
+ RMDBGONCE( 2, RMDebug::module_compression, "r_Tile_Comp_None", "r_Tile_Comp_None(src)" );
+}
+
+
+r_Tile_Comp_None::~r_Tile_Comp_None( void )
+{
+ RMDBGONCE( 2, RMDebug::module_compression, "r_Tile_Comp_None", "~r_Tile_Comp_None()" );
+}
+
+
+void *r_Tile_Comp_None::compress( const void *src, r_ULong &size, const char *options )
+{
+ void *result;
+
+ RMDBGONCE( 2, RMDebug::module_compression, "r_Tile_Comp_None", "compress()" );
+
+ size = get_tile_size();
+ if ((result = mystore.storage_alloc(size)) != NULL)
+ memcpy(result, src, get_tile_size());
+ else
+ RMInit::logOut << "r_Tile_Comp_None::compress(): unable to allocate memory" << endl;
+
+ return result;
+}
+
+
+void *r_Tile_Comp_None::decompress( const void *src, r_ULong size, const char *options )
+{
+ void *result;
+
+ RMDBGONCE( 2, RMDebug::module_compression, "r_Tile_Comp_None", "decompress()" );
+
+ if ((result = mystore.storage_alloc(get_tile_size())) != NULL)
+ memcpy(result, src, get_tile_size());
+ else
+ RMInit::logOut << "r_Tile_Comp_None::decompress(): unable to allocate memory" << endl;
+
+ return result;
+}
+
+
+const char *r_Tile_Comp_None::get_name( void ) const
+{
+ return format_name_array;
+}
+
+
+r_Data_Format r_Tile_Comp_None::get_data_format( void ) const
+{
+ return r_Array;
+}
+
+
+r_Tile_Compression *r_Tile_Comp_None::clone( void ) const
+{
+ return new r_Tile_Comp_None(*this);
+}
diff --git a/compression/tilecompnone.hh b/compression/tilecompnone.hh
new file mode 100644
index 0000000..1c0ae3a
--- /dev/null
+++ b/compression/tilecompnone.hh
@@ -0,0 +1,68 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: tilecompnone.hh
+ *
+ * MODULE: compression
+ * CLASS: r_Tile_Comp_None
+ *
+ * COMMENTS:
+ *
+*/
+
+
+#ifndef _R_TILE_COMP_NONE_HH_
+#define _R_TILE_COMP_NONE_HH_
+
+#include "compression/tilecompression.hh"
+
+
+//@ManMemo: Module {\bf compression}
+
+/*@Doc:
+ Tile compression for no compression. This should normally not be used,
+ but in some cases it's required for cleaner modelling (e.g. an unsupported
+ data format is requested which is interpreted as uncompressed data).
+*/
+
+class r_Tile_Comp_None : public r_Tile_Compression
+{
+ public:
+ /// constructor
+ r_Tile_Comp_None( const r_Minterval &dom, const r_Base_Type *type );
+ /// copy constructor
+ r_Tile_Comp_None( const r_Tile_Comp_None &src );
+ /// destructor
+ ~r_Tile_Comp_None( void );
+ /// compress function
+ virtual void *compress( const void *data, r_ULong &size, const char *options=NULL );
+ /// decompress function
+ virtual void *decompress( const void *data, r_ULong size, const char *options=NULL );
+ /// identification
+ const char *get_name( void ) const;
+ r_Data_Format get_data_format( void ) const;
+ /// create a copy
+ r_Tile_Compression *clone( void ) const;
+};
+
+#endif
diff --git a/compression/tilecompression.cc b/compression/tilecompression.cc
new file mode 100644
index 0000000..f99a815
--- /dev/null
+++ b/compression/tilecompression.cc
@@ -0,0 +1,342 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: tilecompression.cc
+ *
+ * MODULE: compression
+ * CLASS: r_Tile_Compression
+ *
+ * COMMENTS:
+ *
+*/
+
+
+#include <stdlib.h>
+#include <string.h>
+
+
+#include "raslib/rmdebug.hh"
+#include "raslib/minterval.hh"
+#include "raslib/type.hh"
+#include "raslib/type.hh"
+#include "raslib/basetype.hh"
+#include "raslib/parseparams.hh"
+#include "raslib/primitivetype.hh"
+#include "raslib/structuretype.hh"
+
+#include "compression/tilecompression.hh"
+// for creating tile compression objects
+#include "compression/tilecompnone.hh"
+#include "compression/compresstime.hh"
+
+
+
+/*
+ * r_Tile_Compression class
+ */
+
+const r_Tile_Compression::tile_comp_format_t r_Tile_Compression::all_formats[] = {
+ { r_Array, format_name_array },
+ { r_RLE, format_name_rle },
+ { r_ZLib, format_name_zlib },
+ { r_Sep_RLE, format_name_sep_rle },
+ { r_Sep_ZLib, format_name_sep_zlib },
+ { r_Wavelet_Haar, format_name_wavelet_haar },
+ { r_Wavelet_Daubechies, format_name_wavelet_daubechies },
+ { r_Wavelet_QHaar, format_name_wavelet_qhaar },
+ // here we go the wavelets defined in r_Ortho_Wavelet_Factory
+ { r_Wavelet_Daub6, format_name_wavelet_daub6 },
+ { r_Wavelet_Daub8, format_name_wavelet_daub8 },
+ { r_Wavelet_Daub10, format_name_wavelet_daub10 },
+ { r_Wavelet_Daub12, format_name_wavelet_daub12 },
+ { r_Wavelet_Daub14, format_name_wavelet_daub14 },
+ { r_Wavelet_Daub16, format_name_wavelet_daub16 },
+ { r_Wavelet_Daub18, format_name_wavelet_daub18 },
+ { r_Wavelet_Daub20, format_name_wavelet_daub20 },
+ { r_Wavelet_Least8, format_name_wavelet_least8 },
+ { r_Wavelet_Least10, format_name_wavelet_least10 },
+ { r_Wavelet_Least12, format_name_wavelet_least12 },
+ { r_Wavelet_Least14, format_name_wavelet_least14 },
+ { r_Wavelet_Least16, format_name_wavelet_least16 },
+ { r_Wavelet_Least18, format_name_wavelet_least18 },
+ { r_Wavelet_Least20, format_name_wavelet_least20 },
+ { r_Wavelet_Coiflet6, format_name_wavelet_coiflet6 },
+ { r_Wavelet_Coiflet12, format_name_wavelet_coiflet12 },
+ { r_Wavelet_Coiflet18, format_name_wavelet_coiflet18 },
+ { r_Wavelet_Coiflet24, format_name_wavelet_coiflet24 },
+ { r_Wavelet_Coiflet30, format_name_wavelet_coiflet30 },
+ { r_TMC, format_name_tmc }
+};
+
+
+r_Tile_Compression::r_Tile_Compression( const r_Minterval &dom, const r_Base_Type *type ) : mydomain(dom)
+{
+ mytype = (r_Base_Type*)(type->clone());
+ compParams = NULL;
+ decompParams = NULL;
+ myTimer = NULL;
+}
+
+
+r_Tile_Compression::r_Tile_Compression( const r_Tile_Compression &src ) : mydomain(src.mydomain)
+{
+ mytype = (r_Base_Type*)(src.mytype->clone());
+ compParams = NULL;
+ decompParams = NULL;
+ myTimer = NULL;
+ mystore = src.mystore;
+}
+
+
+r_Tile_Compression::~r_Tile_Compression( void )
+{
+ delete mytype;
+
+ if (compParams != NULL)
+ delete compParams;
+ if (decompParams != NULL)
+ delete decompParams;
+ CBENCH_STATEMENT(if (myTimer != NULL) delete myTimer);
+}
+
+
+bool r_Tile_Compression::converts_endianness( void ) const
+{
+ return false;
+}
+
+
+r_Bytes r_Tile_Compression::get_type_size( void ) const
+{
+ return mytype->size();
+}
+
+
+r_ULong r_Tile_Compression::get_tile_size( void ) const
+{
+ unsigned int size;
+
+ if ((size = get_type_size()) == 0) return 0;
+
+ return size * mydomain.cell_count();
+}
+
+
+const r_Minterval &r_Tile_Compression::get_domain( void ) const
+{
+ return mydomain;
+}
+
+
+const r_Base_Type *r_Tile_Compression::get_base_type( void ) const
+{
+ return mytype;
+}
+
+
+void r_Tile_Compression::set_storage_handler( const r_Storage_Man &newStore )
+{
+ mystore = newStore;
+}
+
+
+// should only be called if COMPBENCHMARK is defined
+void r_Tile_Compression::instantiate_timer( const char *func, int level )
+{
+#ifdef COMPBENCHMARK
+ if (myTimer != NULL)
+ delete myTimer;
+
+ myTimer = new RMTimer(get_name(), func, level);
+ myTimer->start();
+#endif
+}
+
+
+void r_Tile_Compression::resume_timer( void )
+{
+ CBENCH_STATEMENT(myTimer->resume());
+}
+
+void r_Tile_Compression::pause_timer( void )
+{
+ CBENCH_STATEMENT(myTimer->pause());
+}
+
+
+
+void r_Tile_Compression::write_short( void *dest, r_Short val )
+{
+ unsigned char *dptr = (unsigned char*)dest;
+
+ dptr[0] = (val & 0xff);
+ dptr[1] = ((val >> 8) & 0xff);
+}
+
+
+void r_Tile_Compression::write_long( void *dest, r_Long val )
+{
+ unsigned char *dptr = (unsigned char*)dest;
+
+ dptr[0] = (val & 0xff);
+ dptr[1] = ((val >> 8) & 0xff);
+ dptr[2] = ((val >> 16) & 0xff);
+ dptr[3] = ((val >> 24) & 0xff);
+}
+
+
+void r_Tile_Compression::read_short( const void *src, r_Short &val )
+{
+ const unsigned char *sptr = (const unsigned char *)src;
+
+ val = (r_Short)(sptr[0] | (sptr[1] << 8));
+}
+
+
+void r_Tile_Compression::read_long( const void *src, r_Long &val )
+{
+ const unsigned char *sptr = (const unsigned char *)src;
+
+ val = (r_Long)(sptr[0] | (sptr[1] << 8) | (sptr[2] << 16) | (sptr[3] << 24));
+}
+
+
+r_Data_Format r_Tile_Compression::get_decomp_format( void ) const
+{
+ return r_Array;
+}
+
+
+unsigned int r_Tile_Compression::get_atom_info( const r_Base_Type* baseType, unsigned int* sizes, unsigned int* idxptr )
+{
+ unsigned int sum;
+ unsigned int idx;
+
+ RMDBGONCE( 3, RMDebug::module_compression, "r_Tile_Compression", "get_atom_info()" );
+
+ if (idxptr == NULL)
+ idx = 0;
+ else
+ idx = *idxptr;
+
+ if (baseType->isStructType())
+ {
+ r_Structure_Type* structType = (r_Structure_Type*)baseType;
+ r_Structure_Type::attribute_iterator iter(structType->defines_attribute_begin());
+
+ sum = 0;
+ while (iter != structType->defines_attribute_end())
+ {
+ r_Base_Type *newType = (r_Base_Type*)((*iter).type_of().clone());
+ if (newType->isStructType())
+ sum += get_atom_info(newType, sizes);
+ else
+ {
+ sum++;
+ if (sizes != NULL)
+ sizes[idx++] = newType->size();
+ }
+ delete newType;
+ iter++;
+ }
+ }
+ else
+ {
+ sum = 1;
+ if (sizes != NULL)
+ sizes[idx++] = baseType->size();
+ }
+
+ if (idxptr != NULL)
+ *idxptr = idx;
+
+ return sum;
+}
+
+
+const char *r_Tile_Compression::get_format_info( unsigned int number, r_Data_Format &fmt )
+{
+ unsigned int numFormats = sizeof(all_formats) / sizeof(tile_comp_format_t);
+
+ if (number >= numFormats)
+ return NULL;
+
+ fmt = all_formats[number].format;
+ return all_formats[number].name;
+}
+
+
+r_Tile_Compression::Support_Format r_Tile_Compression::check_data_format( r_Data_Format fmt )
+{
+ return r_Tile_Compression::COMPRESSION;
+}
+
+
+// create tile compression object from data format
+r_Tile_Compression *r_Tile_Compression::create( r_Data_Format fmt, const r_Minterval &dom, const r_Base_Type *type ) throw(r_Error)
+{
+ r_Tile_Compression *result;
+
+ switch (fmt)
+ {
+ // raw array data
+ case r_Array:
+ result = new r_Tile_Comp_None(dom, type);
+ break;
+ default:
+ RMInit::logOut << "r_Tile_Compression::create(): Unknown or unsupported tile compression " << fmt << endl;
+ r_Error err(r_Error::r_Error_General);
+ throw(err);
+ break;
+ }
+ return result;
+}
+
+
+// create tile compression object from algorithm name
+r_Tile_Compression *r_Tile_Compression::create( const char *name, const r_Minterval &dom, const r_Base_Type *type) throw(r_Error)
+{
+ return create(get_format_from_name(name), dom, type);
+}
+
+
+// get the data format for a compression name
+r_Data_Format r_Tile_Compression::get_format_from_name( const char *name ) throw(r_Error)
+{
+ unsigned int numFormats = sizeof(all_formats) / sizeof(tile_comp_format_t);
+ unsigned int i;
+
+ for (i=0; i<numFormats; i++)
+ {
+ if (strcasecmp(name, all_formats[i].name) == 0)
+ break;
+ }
+ if (i >= numFormats)
+ {
+ RMInit::logOut << "r_Tile_Compression::create(): Unknown compression algorithm " << name << endl;
+ r_Error err(r_Error::r_Error_General);
+ throw(err);
+ }
+ return all_formats[i].format;
+}
+
diff --git a/compression/tilecompression.hh b/compression/tilecompression.hh
new file mode 100644
index 0000000..6e954ce
--- /dev/null
+++ b/compression/tilecompression.hh
@@ -0,0 +1,201 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: tilecompression.hh
+ *
+ * MODULE: compression
+ * CLASS: r_Tile_Compression
+ *
+ * COMMENTS:
+ *
+*/
+
+
+#ifndef _R_TILE_COMPRESSION_HH_
+#define _R_TILE_COMPRESSION_HH_
+
+
+#include <stdio.h>
+
+#include "raslib/error.hh"
+#include "raslib/minterval.hh"
+#include "raslib/mddtypes.hh"
+#include "raslib/odmgtypes.hh"
+#include "raslib/storageman.hh"
+
+
+class r_Base_Type;
+class r_Parse_Params;
+class RMTimer;
+
+
+//@ManMemo: Module: {\bf compression}
+
+/*@Doc:
+ Abstract base class for compression / decompression functionality
+ of tiles, to be executed on client or server. r_Tile_Compression is
+ used by both compressing and uncompressing classes.
+ */
+
+class r_Tile_Compression
+{
+ public:
+ /// enum used as return for check_data_format
+ enum Support_Format
+ { INVALID=0, COMPRESSION, CONVERSION };
+
+ /// default constructor, fixes size and layout of tile
+ r_Tile_Compression( const r_Minterval &dom, const r_Base_Type *type );
+ /// copy constructor
+ r_Tile_Compression( const r_Tile_Compression &src );
+ /// destructor
+ virtual ~r_Tile_Compression( void );
+
+ /// check support for fmt
+ static Support_Format check_data_format( r_Data_Format fmt );
+ /**
+ check whether there is support for the given data format; returns COMPRESSION
+ for a real compression format, CONVERSION for a data exchange format, INVALID othe */
+
+ /// create a compression class from the data format
+ static r_Tile_Compression *create( r_Data_Format fmt, const r_Minterval &dom, const r_Base_Type *type ) throw(r_Error);
+
+ /// create a compression class from the name of the compression algorithm
+ static r_Tile_Compression *create( const char *name, const r_Minterval &dom, const r_Base_Type *type ) throw(r_Error);
+
+ /// get a data format for a compression name
+ static r_Data_Format get_format_from_name( const char *name ) throw(r_Error);
+
+ /// read name and data format of available tile compression formats
+ static const char *get_format_info( unsigned int number, r_Data_Format &fmt );
+
+ /// compress
+ virtual void *compress( const void *data, r_ULong &size, const char *options = NULL ) = 0;
+ /**
+ compresses data, passes options to the underlying compression scheme
+ and returns a pointer to the compressed data and its size. Deallocate
+ the pointer with tilecomp_free() !
+ */
+
+ /// decompress
+ virtual void *decompress( const void *data, r_ULong size, const char *options = NULL ) = 0;
+ /**
+ decompresses the compressed data of size bytes, passing options to the
+ underlying decompression scheme and returns a pointer to the
+ decompressed data. Deallocate the pointer with tilecomp_free() !
+ */
+
+ /// data format after decompression
+ virtual r_Data_Format get_decomp_format( void ) const;
+ /**
+ data format after decompression. This allows easier integration of
+ data exchange formats with the compression mechanism: real compression
+ engines return r_Array, DEF containers return their DEF's data format.
+ This function need only be overloaded if the decompressed format differs
+ from r_Array.
+ */
+
+ /// check whether compression and decompression automatically do the
+ /// required endianness conversions (this is usually only true for
+ /// complex approaches like wavelets)
+ virtual bool converts_endianness( void ) const;
+
+ /// returns name of compression scheme
+ virtual const char *get_name( void ) const = 0;
+ /// returns compression scheme identifier
+ virtual r_Data_Format get_data_format( void ) const = 0;
+ /// make a copy of this compression scheme
+ virtual r_Tile_Compression *clone( void ) const = 0;
+
+ /// returns the size of one cell
+ r_Bytes get_type_size( void ) const;
+ /// returns the size of the uncompressed data
+ r_ULong get_tile_size( void ) const;
+ /// returns tile domain
+ const r_Minterval &get_domain( void ) const;
+ /// returns tile type
+ const r_Base_Type *get_base_type( void ) const;
+ /// resume timer (COMPBENCHMARK only)
+ void resume_timer( void );
+ /// pause timer (COMPBENCHMARK only)
+ void pause_timer( void );
+
+ /// set the storage handler
+ virtual void set_storage_handler( const r_Storage_Man &newStore );
+ /**
+ set the storage handler to use for memory (de)allocation of the
+ pointers returned from (de)compress. By default malloc/free are
+ used.
+ */
+
+ //@Man: internal<--> external data representations
+ /**
+ Since the tile compression class must run on client and server, the
+ data format must be well-specified on both. The following functions
+ take care of endianness and alignment.
+ */
+ /// write a short to dest
+ static void write_short( void *dest, r_Short val );
+ /// write a long to dest
+ static void write_long( void *dest, r_Long val );
+ /// read a short from dest
+ static void read_short( const void *src, r_Short &val );
+ /// write a short to dest
+ static void read_long( const void *src, r_Long &val );
+
+ /// structure for storing information about all data formats
+ typedef struct tile_comp_format_s {
+ r_Data_Format format;
+ const char *name;
+ } tile_comp_format_t;
+
+
+
+ protected:
+
+ /// get information about a base type's atomic types
+ static unsigned int get_atom_info( const r_Base_Type* baseType, unsigned int* sizes=NULL,
+ unsigned int *idxptr=NULL );
+ /**
+ return number of atomic types in base type, optionally return the
+ individual sizes in sizes. idxptr must be NULL (or missing) when calling.
+ */
+
+ /// instantiate timer for benchmarking with a given level
+ void instantiate_timer( const char *func, int level=0 );
+
+ r_Storage_Man mystore;
+
+ r_Minterval mydomain;
+ r_Base_Type *mytype;
+
+ r_Parse_Params *compParams;
+ r_Parse_Params *decompParams;
+
+ RMTimer *myTimer;
+
+ static const tile_comp_format_t all_formats[];
+};
+
+
+#endif
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..a7c6902
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,336 @@
+# -*- Autoconf -*-
+# Process this file with autoconf to produce a configure script.
+
+AC_PREREQ(2.61)
+AC_INIT(Rasdaman, 8.0.0, p.baumann@jacobs-university.de)
+RMANVERSION=8000
+AM_INIT_AUTOMAKE()
+# Define CXXFLAGS before AC_PROG_CXX or it will automatically add -g -O2 on some systems
+CXXFLAGS=
+GCJFLAGS=
+# Checks for programs.
+AC_PROG_CXX
+AC_PROG_AWK
+#AC_PROG_YACC
+AC_PROG_CC
+AC_PROG_CPP
+AC_PROG_LEX
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_PROG_MAKE_SET
+AC_PROG_RANLIB
+AC_PROG_RPCGEN
+AC_PROG_SED
+dnl we preffer java
+AC_PROG_JAVA_CC
+dnl we need bison not yacc
+AC_CHECK_PROGS(YACC, bison, [${am_missing_run} bison])
+
+# Checks for libraries.
+# FIXME: Replace `main' with a function in `-lcrypt':
+AC_CHECK_LIB([crypt], [main], , [AC_MSG_FAILURE([Library not found! Please install...])])
+AC_CHECK_LIB([crypto], [EVP_DigestFinal], , [AC_MSG_FAILURE([Library not found! Please install...])])
+# FIXME: Replace `main' with a function in `-lcurses':
+AC_CHECK_LIB([curses], [main], , [AC_MSG_FAILURE([Library not found! Please install...])])
+# FIXME: Replace `main' with a function in `-ldf':
+AC_CHECK_LIB([df], [main], , [AC_MSG_FAILURE([Library not found! Please install...])])
+# FIXME: Replace `main' with a function in `-ldl':
+AC_CHECK_LIB([dl], [main], , [AC_MSG_FAILURE([Library not found! Please install...])])
+# FIXME: Replace `main' with a function in `-lfl':
+AC_CHECK_LIB([fl], [main], , [AC_MSG_FAILURE([Library not found! Please install...])])
+# FIXME: Replace `main' with a function in `-ljpeg':
+AC_CHECK_LIB([jpeg], [main], , [AC_MSG_FAILURE([Library not found! Please install...])])
+# FIXME: Replace `main' with a function in `-lm':
+AC_CHECK_LIB([m], [main], , [AC_MSG_FAILURE([Library not found! Please install...])])
+# FIXME: Replace `main' with a function in `-lmfhdf':
+AC_CHECK_LIB([mfhdf], [main], , [AC_MSG_FAILURE([Library not found! Please install...])])
+# FIXME: Replace `main' with a function in `-lncurses':
+AC_CHECK_LIB([ncurses], [main], , [AC_MSG_FAILURE([Library not found! Please install...])])
+AC_CHECK_LIB([png], [png_write_row], , [AC_MSG_FAILURE([Library not found! Please install...])])
+AC_CHECK_LIB([netpbm], [ppm_readppm], , [AC_MSG_FAILURE([Library not found! Please install...])])
+# FIXME: Replace `main' with a function in `-lreadline':
+AC_CHECK_LIB([readline], [main], , [AC_MSG_FAILURE([Library not found! Please install...])])
+# FIXME: Replace `main' with a function in `-lsocket':
+AC_CHECK_LIB([socket], [main])
+# FIXME: Replace `main' with a function in `-lssl':
+AC_CHECK_LIB([storagemgr], [main])
+AC_CHECK_LIB([tiff], [TIFFGetField], , [AC_MSG_FAILURE([Library not found! Please install...])])
+# FIXME: Replace `main' with a function in `-lz':
+AC_CHECK_LIB([z], [main], , [AC_MSG_FAILURE([Library not found! Please install...])])
+
+
+# Checks for header files.
+AC_PATH_X
+AC_HEADER_DIRENT
+AC_HEADER_STDC
+AC_HEADER_SYS_WAIT
+AC_CHECK_HEADERS([arpa/inet.h fcntl.h float.h limits.h malloc.h memory.h netdb.h netinet/in.h stdlib.h string.h strings.h sys/socket.h sys/time.h unistd.h values.h hdf.h mfhdf hdf/hdf.h hdf/mfhdf.h])
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_HEADER_STDBOOL
+AC_C_CONST
+AC_C_INLINE
+AC_TYPE_INT32_T
+AC_TYPE_PID_T
+AC_C_RESTRICT
+AC_TYPE_SIZE_T
+AC_HEADER_TIME
+AC_STRUCT_TM
+AC_TYPE_UINT32_T
+AC_C_VOLATILE
+
+# Checks for library functions.
+AC_FUNC_ALLOCA
+AC_FUNC_CLOSEDIR_VOID
+AC_FUNC_ERROR_AT_LINE
+AC_REPLACE_FNMATCH
+AC_FUNC_FORK
+AC_FUNC_MALLOC
+AC_FUNC_MEMCMP
+AC_FUNC_MKTIME
+AC_FUNC_REALLOC
+AC_FUNC_SELECT_ARGTYPES
+AC_TYPE_SIGNAL
+AC_FUNC_STAT
+AC_FUNC_STRFTIME
+AC_FUNC_STRTOD
+AC_FUNC_VPRINTF
+AC_CHECK_FUNCS([alarm bzero clock_gettime dup2 floor getcwd gethostbyaddr gethostbyname gethostname getpass gettimeofday inet_ntoa localtime_r memmove memset mkdir pathconf pow rint select socket sqrt strcasecmp strchr strdup strerror strncasecmp strrchr strstr strtol strtoul])
+
+AC_CONFIG_FILES([Makefile
+ catalogmgr/Makefile
+ relblobif/Makefile
+ relindexif/Makefile
+ relmddif/Makefile
+ relcatalogif/Makefile
+ reladminif/Makefile
+ relstorageif/Makefile
+ indexmgr/Makefile
+ tilemgr/Makefile
+ storagemgr/Makefile
+ compression/Makefile
+ commline/Makefile
+ network/Makefile
+ raslib/Makefile
+ clientcomm/Makefile
+ servercomm/Makefile
+ rnprotocol/Makefile
+ rasodmg/Makefile
+ qlparser/Makefile
+ conversion/Makefile
+ mddmgr/Makefile
+ httpserver/Makefile
+ mymalloc/Makefile
+ time/Makefile
+ server/Makefile
+ rasmgr/Makefile
+ rascontrol/Makefile
+ rasdl/Makefile
+ applications/Makefile
+ applications/rasql/Makefile
+ bin/Makefile
+ manuals_and_examples/Makefile
+ insertutils/Makefile
+ ])
+
+# --------------- Header Template Definitions ----------------------
+####################################################################
+AH_TEMPLATE([DEBUG], [Enables debug functionality])
+AH_TEMPLATE([RMANDEBUG], [Enables debug functionality])
+AH_TEMPLATE([RMANVERSION], [The version of Rasdaman currently compiled])
+AH_TEMPLATE([BASEDB_PGSQL], [If defined we are compiling over PostgreSQL])
+AH_TEMPLATE([__NO_MATH_INLINES], [Used by some performance implementaion of math libraries.])
+AH_TEMPLATE([EARLY_TEMPLATE], [When set allows templates to be instantiated earlier.])
+AH_TEMPLATE([BIG_ENDIAN], [The host system uses big endian encoding.])
+AH_TEMPLATE([LITTLE_ENDIAN], [The host system uses little endian encoding.])
+AH_TEMPLATE([CPPSTDLIB], [Use the std.])
+AH_TEMPLATE([RASARCHITECTURE], [The name of the architecture for which the system is compiling.])
+AH_TEMPLATE([X86], [Compile for a X86 based system.])
+AH_TEMPLATE([NO_in_addr_t], [Don't use addr_t.])
+AH_TEMPLATE([COMPDATE], [Date of the build (of the configure not the actual build)])
+AH_TEMPLATE([BASEDBSTRING], [Name of the database that supports the compiled version of rasdaman.])
+AH_TEMPLATE([RASSCHEMAVERSION], [The version of the schema the database uses.])
+AH_TEMPLATE([NO_OFFICIAL_RELEASE], [activate this if you generate a "non-official" release, i.e.: without license check])
+AH_TEMPLATE([CONFDIR], [The directory where the installed programs will find their configuration])
+# --------------- Parameter Definition -----------------------------
+####################################################################
+AC_PRESERVE_HELP_ORDER
+AC_ARG_WITH([default-rasmgr-port],
+ [AS_HELP_STRING([--with-default-rasmgr-port],
+ [change the default RasMgr port (7001)])],
+ [RASMGR_PORT=$withval],
+ [RASMGR_PORT=7001])
+
+AC_ARG_WITH([static-libs],
+ [AS_HELP_STRING([--with-static-libs],
+ [try to compile using statically linked DBMS libraries])],
+ [],
+ [with_static_libs=no])
+# postgres is automatically defined in m4/ct_check_postgres_db.m4
+AC_ARG_WITH([default-basedb],
+ [AS_HELP_STRING([--with-basedb],
+ [change the default Base DBMS])],
+ [],
+ [with_default_basedb=check])
+AC_ARG_ENABLE([debug],
+ [AS_HELP_STRING([--enable-debug],
+ [this feature enables generation of binaries that contain extra code for debug output. The output is usually very verbose. It's not recommended for production use.])],
+ [RMANDEBUG=on],
+ [RMANDEBUG=])
+
+AC_ARG_WITH([test-server],
+ [AS_HELP_STRING([--with-test-server=ADDRESS],
+ [server used for testing])],
+ [SERVER="$withval"],
+ [SERVER=localhost])
+AC_ARG_WITH([test-database],
+ [AS_HELP_STRING([--with-test-database=NAME],
+ [database name used for testing])],
+ [DATABASE="$withval"],
+ [DATABASE=PEBAU])
+AC_ARG_WITH([test-port],
+ [AS_HELP_STRING([--with-test-port=PORT],
+ [port on which the test server is listening])],
+ [PORT="$withval"],
+ [PORT="$RASMGRPORT"])
+AC_ARG_WITH([test-user],
+ [AS_HELP_STRING([--with-test-user=USERNAME],
+ [username used for connecting to the test server])],
+ [USER="$withval"],
+ [USER=rasadmin])
+AC_ARG_WITH([test-passwd],
+ [AS_HELP_STRING([--with-test-passwd=PASSWORD],
+ [password used for connecting to the test server])],
+ [USER="$withval"],
+ [USER=rasadmin])
+AC_ARG_WITH([logdir],
+ [AS_HELP_STRING([--with-logdir=PATH],
+ [the path where the servers will store their logs])],
+ [logdir="$withval"],
+ [AS_IF([test "x$prefix" = "x/usr/local"],
+ [logdir="/var/log/rasdaman"],
+ [logdir="${prefix}/log"])])
+
+# --------------- Database Specific Configuration ------------------
+####################################################################
+
+AS_IF([test "x$with_default_basedb" == xcheck],
+ [with_default_basedb=postgresql])
+
+AC_MSG_NOTICE([Using database $with_default_basedb.])
+
+AS_IF([test "$with_default_basedb" == postgresql],
+ # PostgreSQL definitions
+ [VERSIONDB=7.4.6
+ AX_LIB_POSTGRESQL([7.4.6])
+ AC_MSG_NOTICE([using PotgreSQL version $POSTGRESQL_VERSION])
+ AC_DEFINE([BASEDB_PGSQL])
+
+ EMBEDDEDSQLEXT="pgc"
+ EMBEDDEDSQLOUT="cc"
+
+ BASEDBCXXFLAGS=" $POSTGRESQL_CFLAGS"
+ BASEDBLDFLAGS="$POSTGRESQL_LDFLAGS -lz -lecpg"
+ STATICBASEDBFLAGS="$BASEDBLDFLAGS"
+ LDFLAGS="$LDFLAGS $POSTGRESQL_LDFLAGS"
+
+ AC_PROG_ECPG
+ #AC_CHECK_LIB([ecpg], [main])
+ #AC_CHECK_HEADERS([ecpgerrno.h])
+ # TODO: change main to something sensible
+ AC_CHECK_LIB([pq], [main], , [AC_MSG_FAILURE([Library not found! Please install...])])
+ AC_CHECK_LIB([pgtypes], [main], , [AC_MSG_FAILURE([Library not found! Please install...])])
+ EMBEDDEDSQLPRECOMPILER="$ECPG -o"
+ BASEDBSTRING=pgsql
+ ],
+ [AC_MSG_ERROR([unsupported base DBMS: $with_default_basedb])])
+
+# --------------- General Configuration ----------------------------
+####################################################################
+
+abs_top_srcdir=`pwd`
+RMANBASE=$abs_top_srcdir
+
+# Optional packages
+
+# If rasgeo is present then delegate configure to it.
+if test -d "$srcdir/rasgeo"; then
+ echo rasgeo
+# AC_CONFIGURE_SUBDIRS([rasgeo])
+fi
+
+# General definitions.
+AS_IF([test "x$RMANDEBUG" != x],
+ [AC_DEFINE([RMANDEBUG])
+ AC_DEFINE([DEBUG])
+ CXXFLAGS+=" -g"
+ ],
+ [
+ AC_DEFINE([__NO_MATH_INLINES])
+ CXXFLAGS+=" -O2"
+ ])
+# CXXFLAGS+= -fPIC ???NEEDED???
+AC_DEFINE_UNQUOTED([RMANVERSION], [$RMANVERSION])
+AC_DEFINE_UNQUOTED([BASEDBSTRING], ["$BASEDBSTRING"])
+AC_DEFINE([EARLY_TEMPLATE])
+AC_C_BIGENDIAN([AC_DEFINE([BIG_ENDIAN])], [AC_DEFINE([LITTLE_ENDIAN])])
+AC_DEFINE([CPPSTDLIB])
+AC_DEFINE([X86]) # Currently, but the code supports multiple platforms
+AC_DEFINE([RASARCHITECTURE], ["X86"])
+AC_DEFINE([RASSCHEMAVERSION], [5])
+AC_DEFINE([NO_OFFICIAL_RELEASE])
+AC_DEFINE([NOPRE])
+# if not on DEC Alpha
+BASEDBLDFLAGS+=" -lnsl"
+STATICBASEDBLDFLAGS+=" -lnsl"
+# endif
+AC_DEFINE([NO_in_addr_t])
+BASEDBCXXFLAGS+=" $DBIF_INC"
+
+CLIENTCXXFLAGS=$CXXFLAGS
+CLIENTLDFLAGS=$CXXLDFLAGS
+
+COMPDATE=`date +"%d.%m.%Y %H:%M:%S"`
+AC_DEFINE_UNQUOTED([COMPDATE], ["$COMPDATE"])
+
+CXXFLAGS+=" -I$abs_top_srcdir -I$abs_top_srcdir/debug -I$abs_top_srcdir/include"
+
+# --------------- System Test Settings -----------------------------
+####################################################################
+
+
+
+# --------------- Makefile Substitutions --------------------------
+####################################################################
+
+AC_SUBST(EMBEDDEDSQLPRECOMPILER)
+AC_SUBST(EMBEDDEDSQLEXT)
+AC_SUBST(EMBEDDEDSQLOUT)
+AC_SUBST(BASEDBCXXFLAGS)
+AC_SUBST(BASEDBLDFLAGS)
+AC_SUBST(CLIENTCXXFLAGS)
+AC_SUBST(CLIENTLDFLAGS)
+AC_SUBST(DB2_INC)
+AC_SUBST(DB2_INSTANCEPATH)
+AC_SUBST(DB2_CPPLIBS)
+AC_SUBST(DBIF_INC)
+AC_SUBST(INFORMIX_INC)
+AC_SUBST(ORA_INC)
+AC_SUBST(ORA_PROC)
+AC_SUBST(ORA_PROCPPFLAGS)
+AC_SUBST(ORALDFLAGS)
+AC_SUBST(RASMGR_PORT)
+AC_SUBST(REL_STATIC_LIBS)
+AC_SUBST(RMANBASE)
+AC_SUBST(STATICBASEDBFLAGS)
+AC_SUBST(logdir)
+
+#Directories used in the source-code
+CXXFLAGS="$CXXFLAGS -DSHARE_DATA_DIR=\\\"\$(pkgdatadir)/\\\""
+CXXFLAGS="$CXXFLAGS -DCONFDIR=\\\"\$(sysconfdir)/\\\""
+CXXFLAGS="$CXXFLAGS -DBINDIR=\\\"\$(bindir)/\\\""
+CXXFLAGS="$CXXFLAGS -DABSOLUTE_LOG_DIR=\\\"\$(logdir)/\\\""
+
+AC_OUTPUT
+
+AC_MSG_NOTICE([Rasdaman succesfully configured.])
diff --git a/configure.todo b/configure.todo
new file mode 100644
index 0000000..7086975
--- /dev/null
+++ b/configure.todo
@@ -0,0 +1,86 @@
+ applications/Makefile
+ applications/directql/Makefile
+ applications/rasql/Makefile
+ applications/rasql/test/Makefile
+
+ catalogmgr/test/Makefile
+ clientcomm/Makefile
+ clientcomm/test/Makefile
+ commline/Makefile
+ commline/test/Makefile
+ compression/Makefile
+ compression/test/Makefile
+ conversion/Makefile
+ conversion/test/Makefile
+ exportutils/Makefile
+ httpserver/Makefile
+ httpserver/test/Makefile
+ indexmgr/Makefile
+ indexmgr/test/Makefile
+ insertutils/Makefile
+ java/Makefile
+ java/examples/Makefile
+ java/org/odmg/Makefile
+ java/rasdaview/Makefile
+ java/rasj/Makefile
+ java/rasj/clientcommhttp/Makefile
+ java/rasj/global/Makefile
+ java/rasj/odmg/Makefile
+ java/rasj/rnp/Makefile
+ java/rasj/test/Makefile
+ mddmgr/Makefile
+ mddmgr/test/Makefile
+ migration/Makefile
+ mymalloc/Makefile
+ network/Makefile
+ pre/Makefile
+ qlparser/Makefile
+ qlparser/test/Makefile
+ rascontrol/Makefile
+ rasdl/Makefile
+ rasdl/test/Makefile
+ rasdoc/Makefile
+ rasgeo/Makefile
+ rasgeo/commander/source/Makefile
+ rasgeo/coordconv/Makefile
+ rasgeo/coordconv/test/Makefile
+ rasgeo/coordtrans/Makefile
+ rasgeo/coordtrans/test/Makefile
+ rasgeo/exporttools/Makefile
+ rasgeo/exporttools/test/Makefile
+ rasgeo/importtools/Makefile
+ rasgeo/importtools/test/Makefile
+ rasgeo/inittools/Makefile
+ rasgeo/inittools/test/Makefile
+ rasgeo/navigator/Makefile
+ rasgeo/navigator/test/Makefile
+ rasgeo/navigator/test/messages/Makefile
+ rasgeo/rasimport/Makefile
+ raslib/Makefile
+ raslib/test/Makefile
+ rasmgr/Makefile
+ rasmgr/test/Makefile
+ rasodmg/Makefile
+ rasodmg/test/Makefile
+ reladminif/Makefile
+ reladminif/test/Makefile
+ relblobif/Makefile
+ relblobif/test/Makefile
+ relcatalogif/Makefile
+ relcatalogif/test/Makefile
+ relindexif/Makefile
+ relindexif/test/Makefile
+ relmddif/Makefile
+ relmddif/test/Makefile
+ relstorageif/Makefile
+ rnprotocol/Makefile
+ server/Makefile
+ server/test/Makefile
+ servercomm/Makefile
+ servercomm/test/Makefile
+ storagemgr/Makefile
+ systemtest/Makefile
+ tilemgr/Makefile
+ tilemgr/test/Makefile
+ time/Makefile
+ utilities/Makefile])
diff --git a/conversion/Makefile.am b/conversion/Makefile.am
new file mode 100644
index 0000000..8da362d
--- /dev/null
+++ b/conversion/Makefile.am
@@ -0,0 +1,37 @@
+# -*-Makefile-*- (for Emacs)
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+#
+# MAKEFILE FOR:
+# module conversion
+#
+#
+# COMMENTS:
+#
+##################################################################
+
+noinst_LIBRARIES=libconversion.a
+libconversion_a_SOURCES= convertor.cc convfactory.cc tiff.cc hdf.cc png.cc jpeg.cc \
+ csv.cc bmp.cc vff.cc tor.cc dem.cc ecw.cc memfs.cc \
+ convertor.hh convfactory.hh tiff.hh hdf.hh png.hh jpeg.hh \
+ csv.hh bmp.hh vff.hh tor.hh dem.hh ecw.hh memfs.hh \
+ ntf.hh
diff --git a/conversion/bmp.cc b/conversion/bmp.cc
new file mode 100644
index 0000000..9995943
--- /dev/null
+++ b/conversion/bmp.cc
@@ -0,0 +1,990 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: bmp.cc
+ *
+ * MODULE: conversion
+ *
+ * CLASSES: r_Conv_BMP
+ *
+ * COMMENTS:
+ * Provides functions to convert data to BMP and back.
+ *
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <iostream>
+#include <string.h>
+#include <new>
+
+#include "raslib/rminit.hh"
+#include "raslib/rmdebug.hh"
+#include "raslib/parseparams.hh"
+#include "conversion/bmp.hh"
+#include "conversion/memfs.hh"
+
+
+// Some Windows-structs, redefined for platform-independent use.
+typedef struct {
+ unsigned short type;
+ r_ULong size;
+ unsigned short res0;
+ unsigned short res1;
+ r_ULong offset;
+} bitmap_file_header_t;
+
+typedef struct {
+ r_ULong size;
+ r_Long width;
+ r_Long height;
+ unsigned short planes;
+ unsigned short bitCount;
+ r_ULong compression;
+ r_ULong sizeImage;
+ r_Long xpels;
+ r_Long ypels;
+ r_ULong clrUsed;
+ r_ULong clrImportant;
+} bitmap_info_header_t;
+
+typedef struct {
+ unsigned char blue;
+ unsigned char green;
+ unsigned char red;
+ unsigned char null;
+} rgb_quad_t;
+
+// Identifier of BMP data (first two bytes)
+const unsigned short BMP_IDENTIFIER=0x4d42;
+// Compression types (correspond to BI_RGB, BI_RLE8, BI_RLE4)
+const int COMPRESS_NONE=0;
+const int COMPRESS_RLE8=1;
+const int COMPRESS_RLE4=2;
+// Size of BITMAPFILEHEADER (the Windows struct)
+const int BMPFILEHEADERSIZE=sizeof(bitmap_file_header_t) - sizeof(BMP_IDENTIFIER);
+// Size of BITMAPINFOHEADER (the Windows struct)
+const int BMPINFOHEADERSIZE=sizeof(bitmap_info_header_t);
+// Total header size
+const int BMPHEADERSIZE=(BMPFILEHEADERSIZE + BMPINFOHEADERSIZE);
+
+// Shortcuts for reading and writing short and long types from/to little endian bytestreams
+#define READ_LE_SHORT(p,s) \
+ s = p[0] | (p[1] << 8); p += 2;
+#define READ_LE_LONG(p,l) \
+ l = p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); p += 4;
+#define WRITE_LE_SHORT(p,s) \
+ p[0] = s & 0xff; p[1] = (s >> 8) & 0xff; p += 2;
+#define WRITE_LE_LONG(p,l) \
+ p[0] = l & 0xff; p[1] = (l >> 8) & 0xff; p[2] = (l >> 16) & 0xff; p[3] = (l >> 24) & 0xff; p += 4;
+
+
+
+void r_Conv_BMP::initBMP( void )
+{
+ memFS = NULL;
+
+ compress = 1;
+
+ if (params == NULL)
+ params = new r_Parse_Params;
+
+ params->add("compress", &compress, r_Parse_Params::param_type_int);
+}
+
+
+r_Conv_BMP::r_Conv_BMP(const char *src, const r_Minterval &interv, int tp) throw(r_Error)
+: r_Convertor(src, interv, tp)
+{
+ initBMP();
+}
+
+
+r_Conv_BMP::r_Conv_BMP(const char *src, const r_Minterval &interv, const r_Type *tp) throw(r_Error)
+: r_Convertor(src, interv, tp)
+{
+ initBMP();
+}
+
+
+r_Conv_BMP::~r_Conv_BMP(void)
+{
+ if (memFS != NULL)
+ {
+ memfs_killfs((void*)memFS);
+ delete memFS;
+ memFS=NULL;
+ }
+}
+
+
+unsigned char *r_Conv_BMP::flushLiterals(int numLit, int pixelAdd, unsigned char *dest, const unsigned char *lastLit, const unsigned char *mapColours)
+{
+ unsigned char *destPtr = dest;
+
+ while (numLit != 0)
+ {
+ // Must code literal runs of less than 3 bytes as runs
+ if (numLit < 3)
+ {
+ while (numLit > 0)
+ {
+ *destPtr++ = 1; *destPtr++ = mapColours[*lastLit];
+ lastLit += pixelAdd; numLit--;
+ }
+ }
+ else
+ {
+ int litLength=0;
+ r_Ptr align=0;
+
+ litLength = numLit; if (litLength > 255) litLength = 255;
+ *destPtr++ = 0x00; *destPtr++ = (unsigned char)litLength;
+ numLit -= litLength;
+ while (litLength > 0)
+ {
+ *destPtr++ = mapColours[*lastLit]; lastLit += pixelAdd; litLength--;
+ }
+ align = (r_Ptr)destPtr; if ((align & 1) != 0) *destPtr++ = 0;
+ }
+ }
+ return destPtr;
+}
+
+
+r_convDesc &r_Conv_BMP::convertTo( const char *options) throw(r_Error)
+{
+ void *handle=NULL;
+ bitmap_info_header_t ihead;
+ rgb_quad_t *palette = NULL;
+ int i=0, j=0;
+ int paletteSize=0, pixelSize=0;
+ int destPitch=0, pixelAdd=0, lineAdd=0;
+ int width=0, height=0;
+ r_ULong offset=0;
+ r_ULong fileSize=0;
+ unsigned char *dest=NULL, *destPtr=NULL;
+ const unsigned char *srcLine=NULL, *srcPtr=NULL;
+ unsigned char bmpHeaders[BMPHEADERSIZE];
+ unsigned char mapColours[256];
+
+ memFS = new memFSContext; handle = (void*)memFS;
+ if ((memFS == NULL) || (memfs_initfs(handle) < 0))
+ {
+ RMInit::logOut << "r_Conv_BMP::convertTo(): couldn't initialize memfs!" << endl;
+ throw r_Error(MEMMORYALLOCATIONERROR);
+ }
+ memfs_newfile(handle);
+
+ width = (int)(desc.srcInterv[0].high() - desc.srcInterv[0].low() + 1);
+ height = (int)(desc.srcInterv[1].high() - desc.srcInterv[1].low() + 1);
+
+ params->process(options);
+
+ ihead.size = BMPINFOHEADERSIZE;
+ ihead.width = (r_Long)width;
+ ihead.height = (r_Long)height;
+ ihead.planes = 1;
+ ihead.compression = COMPRESS_NONE;
+ ihead.xpels = 0; ihead.ypels = 0;
+
+ switch (desc.baseType)
+ {
+ case ctype_bool:
+ ihead.bitCount = 1; destPitch = ((width + 31) & ~31) >> 3; paletteSize = 2; pixelSize = 1;
+ ihead.clrUsed = 2; ihead.clrImportant = 2;
+ palette = new rgb_quad_t[2];
+ palette[0].red = 0x00; palette[0].green = 0x00; palette[0].blue = 0x00; palette[0].null = 0x00;
+ palette[1].red = 0xff; palette[1].green = 0xff; palette[1].blue = 0xff; palette[1].null = 0x00;
+ break;
+ case ctype_char:
+ {
+ ihead.bitCount = 8; destPitch = ((width + 3) & ~3); pixelSize = 1;
+ if (compress != 0) ihead.compression = COMPRESS_RLE8;
+ // Determine which colours actually appear in the image
+ memset(mapColours, 0, 256);
+ srcLine = (const unsigned char*)desc.src;
+ for (i=0; i<width*height; i++) mapColours[*srcLine++] = 1;
+ // Count distinct colours
+ paletteSize = 0;
+ for (i=0; i<256; i++) if (mapColours[i] != 0) paletteSize++;
+ // Create palette
+ RMDBGONCE(3, RMDebug::module_conversion, "r_Conv_BMP", "convertTo(): number of distinct colours: " << paletteSize )
+ palette = new rgb_quad_t[paletteSize];
+ paletteSize = 0;
+ for (i=0; i<256; i++)
+ {
+ if (mapColours[i] != 0)
+ {
+ palette[paletteSize].red = (unsigned char)i;
+ palette[paletteSize].green = (unsigned char)i;
+ palette[paletteSize].blue = (unsigned char)i;
+ palette[paletteSize].null = 0;
+ paletteSize++;
+ }
+ }
+ // ``compress'' colourmap
+ paletteSize = 0;
+ for (i=0; i<256; i++)
+ {
+ if (mapColours[i] != 0) mapColours[i] = paletteSize++;
+ }
+ ihead.clrUsed = paletteSize; ihead.clrImportant = 0; // for simplicity's sake
+ break;
+ }
+ case ctype_rgb:
+ ihead.bitCount = 24; destPitch = ((width * 3 + 3) & ~3); paletteSize = 0; pixelSize = 3;
+ ihead.clrUsed = 0; ihead.clrImportant = 0;
+ break;
+ default:
+ RMInit::logOut << "r_Conv_BMP::convertTo(): Unknown base type!" << endl;
+ throw r_Error(r_Error::r_Error_General);
+ }
+ lineAdd = pixelSize; pixelAdd = height * pixelSize;
+
+ // Write dummy header, to be replaced later
+ memset(bmpHeaders, 0, BMPHEADERSIZE);
+ memfs_write(handle, bmpHeaders, BMPHEADERSIZE);
+ if (paletteSize != 0)
+ {
+ memfs_write(handle, palette, paletteSize * sizeof(rgb_quad_t));
+ delete [] palette; palette = NULL;
+ }
+
+ srcLine = (const unsigned char*)(desc.src + (height-1) * pixelSize);
+
+ if (ihead.compression == COMPRESS_NONE)
+ {
+ if ((dest = new unsigned char[destPitch]) == NULL)
+ {
+ RMInit::logOut << "r_Conv_BMP::convertTo(): out of memory!" << endl;
+ throw r_Error(MEMMORYALLOCATIONERROR);
+ }
+ for (j=0; j<height; j++, srcLine -= lineAdd)
+ {
+ srcPtr = srcLine; destPtr = dest;
+ switch (desc.baseType)
+ {
+ case ctype_bool:
+ {
+ int mask=0;
+ unsigned char val=0;
+
+ mask = 0x80; val = 0;
+ for (i=0; i<width; i++, srcPtr += pixelAdd)
+ {
+ if (*srcPtr != 0) val |= mask;
+ mask >>= 1;
+ if (mask == 0)
+ {
+ *destPtr++ = val; mask = 0x80; val = 0;
+ }
+ }
+ if (mask != 0x80) *destPtr++ = val;
+ }
+ break;
+ case ctype_char:
+ for (i=0; i<width; i++, srcPtr += pixelAdd)
+ {
+ *destPtr++ = mapColours[*srcPtr];
+ }
+ break;
+ case ctype_rgb:
+ for (i=0; i<width; i++, srcPtr += pixelAdd)
+ {
+ *destPtr++ = srcPtr[2]; *destPtr++ = srcPtr[1]; *destPtr++ = srcPtr[0];
+ }
+ break;
+ }
+ // Align to 32bit-boundary
+ for (i = (4 - (r_Ptr)destPtr) & 3; i>0; i--) *destPtr++ = 0;
+ memfs_write(handle, dest, destPitch);
+ }
+ delete [] dest; dest = NULL;
+ }
+ else // implies RLE 8
+ {
+ if ((dest = new unsigned char[2*destPitch]) == NULL)
+ {
+ RMInit::logOut << "r_Conv_BMP::convertTo(): out of memory!" << endl;
+ throw r_Error(MEMMORYALLOCATIONERROR);
+ }
+
+ for (j=0; j<height; j++, srcLine -= lineAdd)
+ {
+ const unsigned char *lastLit=NULL, *tryRun=NULL;
+ int k=0, numLit=0;
+
+ srcPtr = srcLine; destPtr = dest;
+ lastLit = srcPtr; i = 0; numLit = 0;
+ while (i < width)
+ {
+ k = i;
+ tryRun = srcPtr;
+ while (k < width-1)
+ {
+ if (*tryRun != *(tryRun + pixelAdd)) break;
+ tryRun += pixelAdd; k++;
+ }
+ // If k < width-1 tryRun points to the first symbol not int the run,
+ // otherwise it points to the last one in the run
+ if (k == width-1) k = width - i; else k -= i;
+ // Run found ==> encode literals + run
+ // If a literal sequence has to be broken for the run we require a longer run.
+ // For the sequence <lit><run><lit> a run shorter than 5 bytes is best merged into lit.
+ // For the sequence <lit><run1><run2> the first run should be merged with lit if it's
+ // less than 3 bytes long. Therefore on average 4 bytes minimum runs are best.
+ if (((numLit == 0) && (k > 1)) || (k > 3))
+ {
+ // First output the pending literals, if any
+ destPtr = flushLiterals(numLit, pixelAdd, destPtr, lastLit, mapColours);
+ numLit = 0;
+ i += k;
+ // Now output the run
+ while (k > 0)
+ {
+ int runLength=0;
+
+ runLength = k; if (runLength > 255) runLength = 255;
+ *destPtr++ = runLength; *destPtr++ = mapColours[*srcPtr];
+ k -= runLength;
+ }
+ srcPtr = tryRun; lastLit = srcPtr;
+ }
+ else
+ {
+ numLit++; srcPtr += pixelAdd; i++;
+ }
+ }
+ // Flush remaining literals
+ destPtr = flushLiterals(numLit, pixelAdd, destPtr, lastLit, mapColours);
+ // EOL
+ *destPtr++ = 0; *destPtr++ = 0;
+ memfs_write(handle, dest, (destPtr - dest));
+ }
+ // EOB
+ dest[0] = 0; dest[1] = 1;
+ memfs_write(handle, dest, 2);
+
+ delete [] dest; dest = NULL;
+ }
+
+ fileSize = memfs_size(handle);
+ RMDBGONCE( 3, RMDebug::module_conversion, "r_Conv_BMP", "convertTo(): size: " << fileSize );
+ offset = BMPHEADERSIZE + paletteSize * sizeof(rgb_quad_t);
+ dest = bmpHeaders;
+ ihead.sizeImage = fileSize - offset;
+
+ WRITE_LE_SHORT(dest, BMP_IDENTIFIER);
+ WRITE_LE_LONG(dest, fileSize);
+ WRITE_LE_SHORT(dest, 0);
+ WRITE_LE_SHORT(dest, 0);
+ WRITE_LE_LONG(dest, offset);
+
+ WRITE_LE_LONG(dest, ihead.size);
+ WRITE_LE_LONG(dest, ihead.width);
+ WRITE_LE_LONG(dest, ihead.height);
+ WRITE_LE_SHORT(dest, ihead.planes);
+ WRITE_LE_SHORT(dest, ihead.bitCount);
+ WRITE_LE_LONG(dest, ihead.compression);
+ WRITE_LE_LONG(dest, ihead.sizeImage);
+ WRITE_LE_LONG(dest, ihead.xpels);
+ WRITE_LE_LONG(dest, ihead.ypels);
+ WRITE_LE_LONG(dest, ihead.clrUsed);
+ WRITE_LE_LONG(dest, ihead.clrImportant);
+
+ memfs_seek(handle, 0, SEEK_SET);
+ memfs_write(handle, bmpHeaders, BMPHEADERSIZE);
+
+ if ((desc.dest = (char*)mystore.storage_alloc(fileSize)) == NULL)
+ {
+ RMInit::logOut << "r_Conv_BMP::convertTo(): out of memory!" << endl;
+ throw r_Error(MEMMORYALLOCATIONERROR);
+ }
+ memfs_seek(handle, 0, SEEK_SET);
+ memfs_read(handle, desc.dest, fileSize);
+
+ memfs_killfs(handle);
+ delete memFS; memFS = NULL;
+
+ desc.destInterv = r_Minterval(1);
+ desc.destInterv << r_Sinterval((r_Range)0, (r_Range)fileSize-1);
+
+ desc.destType = r_Type::get_any_type("char");
+
+ return desc;
+}
+
+
+// Auxiliary makro for RLE coders
+#define BMP_RLE_LINEFEED \
+ destLine -= lineAdd; destPtr = destLine; j++; i = 0;
+
+r_convDesc &r_Conv_BMP::convertFrom(const char *options) throw(r_Error)
+{
+ bitmap_file_header_t fhead;
+ bitmap_info_header_t ihead;
+ const rgb_quad_t *palette=NULL;
+ const unsigned char *bmp=NULL;
+ int i=0, j=0;
+ int srcPitch=0;
+ int pixelSize=0, destType=0;
+ int paletteIsGrey=0, paletteSize=0;
+ int width=0, height=0;
+ unsigned char emit0=0, emit1=0; // in case of bitmap -> bool: values to emit for 0 and 1
+ int lineAdd=0, pixelAdd=0;
+
+ bmp = (const unsigned char*)desc.src;
+
+ // Read file header
+ READ_LE_SHORT(bmp, fhead.type);
+ READ_LE_LONG(bmp, fhead.size);
+ READ_LE_SHORT(bmp, fhead.res0);
+ READ_LE_SHORT(bmp, fhead.res1);
+ READ_LE_LONG(bmp, fhead.offset);
+
+ if (fhead.type != BMP_IDENTIFIER)
+ {
+ RMInit::logOut << "r_Conv_BMP::convertFrom(): not a BMP file" << endl;
+ throw r_Error(r_Error::r_Error_General);
+ }
+
+ // Read info header
+ READ_LE_LONG(bmp, ihead.size);
+ READ_LE_LONG(bmp, ihead.width);
+ READ_LE_LONG(bmp, ihead.height);
+ READ_LE_SHORT(bmp, ihead.planes);
+ READ_LE_SHORT(bmp, ihead.bitCount);
+ READ_LE_LONG(bmp, ihead.compression);
+ READ_LE_LONG(bmp, ihead.sizeImage);
+ READ_LE_LONG(bmp, ihead.xpels);
+ READ_LE_LONG(bmp, ihead.ypels);
+ READ_LE_LONG(bmp, ihead.clrUsed);
+ READ_LE_LONG(bmp, ihead.clrImportant);
+
+ width = (int)ihead.width; height = (int)ihead.height;
+
+ RMDBGIF(4, RMDebug::module_conversion, "r_Conv_BMP", \
+ RMInit::dbgOut << "File: type " << std::hex << fhead.type << ", size " << std::dec << fhead.size; \
+ RMInit::dbgOut << ", rsv0 " << fhead.res0 << ", rsv1 " << fhead.res1 << ", offs " << fhead.offset << endl; \
+ RMInit::dbgOut << "Info: size " << ihead.size << ", width " << ihead.width << ", height " << ihead.height; \
+ RMInit::dbgOut << ", planes " << ihead.planes << ", bits " << ihead.bitCount << ", comp " << ihead.compression; \
+ RMInit::dbgOut << ", sizeImg " << ihead.sizeImage << ", xpels " << ihead.xpels << ", ypels " << ihead.ypels; \
+ RMInit::dbgOut << ", clrUsed " << ihead.clrUsed << ", clrImp " << ihead.clrImportant << endl; )
+
+ palette = (const rgb_quad_t*)(desc.src + BMPFILEHEADERSIZE + ihead.size);
+ paletteIsGrey = 0;
+ paletteSize = ihead.clrUsed;
+ if ((paletteSize == 0) && (ihead.bitCount != 24)) paletteSize = (1 << ihead.bitCount);
+
+ switch (ihead.bitCount)
+ {
+ case 1:
+ srcPitch = ((width + 31) & ~31) >> 3;
+ // Grey?
+ if ((palette[0].red == palette[0].green) && (palette[0].green == palette[0].blue) &&
+ (palette[1].red == palette[1].green) && (palette[1].green == palette[1].blue))
+ {
+ paletteIsGrey = 1; pixelSize = 1;
+ // Yes; also black + white?
+ if (((palette[0].red == 0x00) && (palette[1].red == 0xff)) ||
+ ((palette[0].red == 0xff) && (palette[1].red == 0x00)))
+ {
+ // Yes
+ destType = ctype_bool;
+ if (palette[0].red == 0)
+ {
+ emit0 = 0; emit1 = 1;
+ }
+ else
+ {
+ emit0 = 1; emit1 = 0;
+ }
+ }
+ else
+ {
+ // No
+ destType = ctype_char;
+ }
+ }
+ else
+ {
+ // Convert to RGB
+ destType = ctype_rgb; pixelSize = 3;
+ }
+ break;
+ case 4:
+ case 8:
+ {
+ if (ihead.bitCount == 4)
+ {
+ srcPitch = ((width + 7) & ~7) >> 1;
+ }
+ else
+ {
+ srcPitch = ((width + 3) & ~3); }
+ // Check whether the palette is greyscale
+ for (i=0; i<paletteSize; i++)
+ {
+ if ((palette[i].red != palette[i].green) || (palette[i].green != palette[i].blue)) break;
+ }
+ if (i < paletteSize)
+ {
+ destType = ctype_rgb; pixelSize = 3;
+ }
+ else
+ {
+ destType = ctype_char; paletteIsGrey = 1; pixelSize = 1;
+ }
+ }
+ break;
+ case 24:
+ destType = ctype_rgb; srcPitch = (width * 3 + 3) & ~3;
+ pixelSize = 3;
+ break;
+ default:
+ {
+ RMInit::logOut << "r_Conv_BMP::convertFrom(): Bad bitmap depth" << endl;
+ throw r_Error(r_Error::r_Error_General);
+ }
+ }
+
+ RMDBGONCE( 4, RMDebug::module_conversion, "r_Conv_BMP", "convertFrom(): type " << destType << ", srcPitch " << srcPitch << ", pixelSize " << pixelSize << ", palsize " << paletteSize );
+
+ unsigned char *dest=NULL, *destPtr=NULL, *destLine=NULL;
+ const unsigned char *imgPtr=NULL, *imgLine=NULL;
+
+ pixelAdd = pixelSize * height; lineAdd = pixelSize;
+
+ imgLine = (const unsigned char *)(palette + paletteSize);
+
+ if ((dest = (unsigned char*)mystore.storage_alloc(width * height * pixelSize)) == NULL)
+ {
+ RMInit::logOut << "r_Conv_BMP::convertFrom(): out of memory" << endl;
+ throw r_Error(MEMMORYALLOCATIONERROR);
+ }
+
+ if (ihead.compression != COMPRESS_NONE)
+ {
+ // This is only defined for 8bpp and 4bpp data. The result can only be 8bpp or 24bpp.
+ // Init the entire picture to colour #0. Is this correct? Undocumented.
+ destPtr = dest; i = width * height;
+ if (paletteIsGrey == 0)
+ {
+ while (i > 0)
+ {
+ destPtr[0] = palette[0].red; destPtr[1] = palette[0].green; destPtr[2] = palette[0].blue;
+ destPtr += pixelSize; i--;
+ }
+ }
+ else
+ {
+ while (i > 0)
+ {
+ destPtr[0] = palette[0].red;
+ destPtr += pixelSize; i--;
+ }
+ }
+ }
+
+ destLine = dest + ((height - 1) * pixelSize);
+
+ switch (ihead.compression)
+ {
+ case COMPRESS_NONE:
+ for (j=0; j<height; j++, destLine -= lineAdd, imgLine += srcPitch)
+ {
+ destPtr = destLine; imgPtr = imgLine;
+ switch (ihead.bitCount)
+ {
+ case 1:
+ {
+ int mask=0;
+ unsigned char val=0;
+
+ mask = 0x00;
+ switch (destType)
+ {
+ case ctype_bool:
+ for (i=0; i<width; i++, destPtr += pixelAdd)
+ {
+ if (mask == 0x00)
+ {
+ mask = 0x80; val = *imgPtr++;
+ }
+ *destPtr = ((val & mask) == 0) ? emit0 : emit1;
+ mask >>= 1;
+ }
+ break;
+ case ctype_char:
+ for (i=0; i<width; i++, destPtr += pixelAdd)
+ {
+ if (mask == 0x00)
+ {
+ mask = 0x80; val = *imgPtr++;
+ }
+ *destPtr = palette[(((val & mask) == 0) ? 0 : 1)].red;
+ mask >>= 1;
+ }
+ break;
+ case ctype_rgb:
+ for (i=0; i<width; i++, destPtr += pixelAdd)
+ {
+ int idx=0;
+
+ if (mask == 0x00)
+ {
+ mask = 0x80; val = *imgPtr++;
+ }
+ idx = ((val & mask) == 0) ? 0 : 1;
+ destPtr[0] = palette[idx].red;
+ destPtr[1] = palette[idx].green;
+ destPtr[2] = palette[idx].blue;
+ mask >>= 1;
+ }
+ break;
+ }
+ }
+ break;
+ case 4:
+ {
+ switch (destType)
+ {
+ case ctype_char:
+ for (i=0; i<width; i+=2)
+ {
+ *destPtr = palette[(*imgPtr) >> 4].red;
+ destPtr += pixelAdd;
+ *destPtr = palette[(*imgPtr & 0x0f)].red;
+ destPtr += pixelAdd; imgPtr++;
+ }
+ if (i < width)
+ {
+ *destPtr = palette[(*imgPtr) >> 4].red;
+ }
+ break;
+ case ctype_rgb:
+ for (i=0; i<width; i+=2)
+ {
+ int idx;
+
+ idx = (*imgPtr) >> 4;
+ destPtr[0] = palette[idx].red;
+ destPtr[1] = palette[idx].green;
+ destPtr[2] = palette[idx].blue;
+ destPtr += pixelAdd;
+ idx = (*imgPtr) & 0x0f;
+ destPtr[0] = palette[idx].red;
+ destPtr[1] = palette[idx].green;
+ destPtr[2] = palette[idx].blue;
+ destPtr += pixelAdd; imgPtr++;
+ }
+ if (i < width)
+ {
+ int idx;
+
+ idx = (*imgPtr) >> 4;
+ destPtr[0] = palette[idx].red;
+ destPtr[1] = palette[idx].green;
+ destPtr[2] = palette[idx].blue;
+ }
+ break;
+ }
+ }
+ break;
+ case 8:
+ switch (destType)
+ {
+ case ctype_char:
+ for (i=0; i<width; i++, destPtr += pixelAdd)
+ {
+ *destPtr = palette[*imgPtr++].red;
+ }
+ break;
+ case ctype_rgb:
+ for (i=0; i<width; i++, destPtr += pixelAdd)
+ {
+ destPtr[0] = palette[*imgPtr].red;
+ destPtr[1] = palette[*imgPtr].green;
+ destPtr[2] = palette[*imgPtr].blue;
+ imgPtr++;
+ }
+ break;
+ }
+ break;
+ case 24:
+ for (i=0; i<width; i++, destPtr += pixelAdd)
+ {
+ destPtr[0] = imgPtr[2]; destPtr[1] = imgPtr[1]; destPtr[2] = imgPtr[0];
+ imgPtr += 3;
+ }
+ break;
+ }
+ }
+ break;
+ case COMPRESS_RLE8:
+ {
+ i = 0; j = 0; destPtr = destLine; imgPtr = imgLine;
+ while (j >= 0)
+ {
+ unsigned char val=0, cmd=0;
+
+ //cout << "(" << i << "," << j << ")" << endl;
+ cmd = *imgPtr++;
+ if (cmd == 0) // escape
+ {
+ cmd = *imgPtr++;
+ switch (cmd)
+ {
+ case 0: // end of line
+ //cout << "EOL" << endl;
+ BMP_RLE_LINEFEED;
+ break;
+ case 1: // end of bitmap
+ //cout << "EOB" << endl;
+ j = -1;
+ break;
+ case 2: // delta
+ //cout << "DELTA" << endl;
+ val = *imgPtr++; i += val; destPtr += val * pixelAdd;
+ val = *imgPtr++; j += val; destPtr -= val * lineAdd; destLine -= val * lineAdd;
+ break;
+ default: // absolute mode
+ //cout << "ABS" << endl;
+ while (cmd > 0)
+ {
+ val = *imgPtr++;
+ if (j < height)
+ {
+ if (i >= width)
+ {
+ BMP_RLE_LINEFEED;
+ }
+ destPtr[0] = palette[val].red;
+ if (paletteIsGrey == 0)
+ {
+ destPtr[1] = palette[val].green;
+ destPtr[2] = palette[val].blue;
+ }
+ destPtr += pixelAdd; i++;
+ }
+ cmd--;
+ }
+ // Align srcPtr to a Windows-Word position (==> aligned to short)
+ if ((((r_Ptr)imgPtr) & 1) != 0) imgPtr++;
+ break;
+ }
+ }
+ else // repeat sequence
+ {
+ //cout << "RUN" << endl;
+ val = *imgPtr++;
+ while (cmd > 0)
+ {
+ if (j < height)
+ {
+ if (i >= width)
+ {
+ BMP_RLE_LINEFEED;
+ }
+ destPtr[0] = palette[val].red;
+ if (paletteIsGrey == 0)
+ {
+ destPtr[1] = palette[val].green;
+ destPtr[2] = palette[val].blue;
+ }
+ destPtr += pixelAdd; i++;
+ }
+ cmd--;
+ }
+ }
+ }
+ }
+ break;
+ case COMPRESS_RLE4:
+ {
+ i = 0; j = 0; destPtr = destLine; imgPtr = imgLine;
+ while (j >= 0)
+ {
+ unsigned char val=0, cmd=0;
+
+ cmd = *imgPtr++;
+ if (cmd == 0) // escape
+ {
+ cmd = *imgPtr++;
+ switch (cmd)
+ {
+ case 0: // end of line
+ BMP_RLE_LINEFEED;
+ break;
+ case 1: // end of bitmap
+ j = -1;
+ break;
+ case 2: // delta
+ val = *imgPtr++; i += val; destPtr += val * pixelAdd;
+ val = *imgPtr++; j += val; destPtr -= val * lineAdd; destLine -= val * lineAdd;
+ break;
+ default: // absolute mode
+ while (cmd > 1)
+ {
+ val = *imgPtr++;
+ if (j < height)
+ {
+ if (i >= width)
+ {
+ BMP_RLE_LINEFEED;
+ }
+ destPtr[0] = palette[val >> 4].red;
+ if (paletteIsGrey == 0)
+ {
+ destPtr[1] = palette[val >> 4].green;
+ destPtr[2] = palette[val >> 4].blue;
+ }
+ destPtr += pixelAdd; i++;
+ if (i >= width)
+ {
+ BMP_RLE_LINEFEED;
+ }
+ destPtr[0] = palette[val & 0x0f].red;
+ if (paletteIsGrey == 0)
+ {
+ destPtr[1] = palette[val & 0x0f].green;
+ destPtr[2] = palette[val & 0x0f].blue;
+ }
+ destPtr += pixelAdd; i++;
+ }
+ cmd-=2;
+ }
+ if (cmd != 0)
+ {
+ val = *imgPtr++;
+ if (j < height)
+ {
+ if (i >= width)
+ {
+ BMP_RLE_LINEFEED;
+ }
+ destPtr[0] = palette[val >> 4].red;
+ if (paletteIsGrey == 0)
+ {
+ destPtr[1] = palette[val >> 4].green;
+ destPtr[2] = palette[val >> 4].blue;
+ }
+ destPtr += pixelAdd; i++;
+ }
+ }
+ // Align srcPtr to a Windows-Word position (==> aligned to short)
+ if ((((r_Ptr)imgPtr) & 1) != 0) imgPtr++;
+ break;
+ }
+ }
+ else // repeat sequence
+ {
+ val = *imgPtr++;
+ while (cmd > 1)
+ {
+ if (j < height)
+ {
+ if (i >= width)
+ {
+ BMP_RLE_LINEFEED;
+ }
+ destPtr[0] = palette[val >> 4].red;
+ if (paletteIsGrey == 0)
+ {
+ destPtr[1] = palette[val >> 4].green;
+ destPtr[2] = palette[val >> 4].blue;
+ }
+ destPtr += pixelAdd; i++;
+ if (i >= width)
+ {
+ BMP_RLE_LINEFEED;
+ }
+ destPtr[0] = palette[val & 0x0f].red;
+ if (paletteIsGrey == 0)
+ {
+ destPtr[1] = palette[val & 0x0f].green;
+ destPtr[2] = palette[val & 0x0f].blue;
+ }
+ destPtr += pixelAdd; i++;
+ }
+ cmd -= 2;
+ }
+ if (cmd != 0)
+ {
+ if (j < height)
+ {
+ if (i >= width)
+ {
+ BMP_RLE_LINEFEED;
+ }
+ destPtr[0] = palette[val >> 4].red;
+ if (paletteIsGrey == 0)
+ {
+ destPtr[1] = palette[val >> 4].green;
+ destPtr[2] = palette[val >> 4].blue;
+ }
+ destPtr += pixelAdd; i++;
+ }
+ }
+ }
+ }
+ }
+ break;
+ default:
+ {
+ RMInit::logOut << "r_Conv_BMP::convertFrom(): bad compression type" << endl;
+ mystore.storage_free(dest);
+ throw r_Error(r_Error::r_Error_General);
+ }
+ }
+
+ desc.dest = (char*)dest; desc.baseType = destType;
+
+ desc.destInterv = r_Minterval(2);
+ desc.destInterv << r_Sinterval((r_Range)0, (r_Range)width-1)
+ << r_Sinterval((r_Range)0, (r_Range)height-1);
+
+ desc.destType = get_external_type(desc.baseType);
+
+ return desc;
+}
+
+
+
+const char *r_Conv_BMP::get_name( void ) const
+{
+ return format_name_bmp;
+}
+
+
+r_Data_Format r_Conv_BMP::get_data_format( void ) const
+{
+ return r_BMP;
+}
+
+
+r_Convertor *r_Conv_BMP::clone( void ) const
+{
+ return new r_Conv_BMP(desc.src, desc.srcInterv, desc.baseType);
+}
diff --git a/conversion/bmp.hh b/conversion/bmp.hh
new file mode 100644
index 0000000..de49ddc
--- /dev/null
+++ b/conversion/bmp.hh
@@ -0,0 +1,91 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: bmp.hh
+ *
+ * MODULE: conversion
+ *
+ * CLASSES: r_Conv_BMP
+ *
+ * COMMENTS:
+ *
+ * Provides interface to convert data to other formats.
+ *
+*/
+
+#ifndef _R_CONV_BMP_HH_
+#define _R_CONV_BMP_HH_
+
+#include "conversion/convertor.hh"
+
+
+
+//@ManMemo: Module {\bf conversion}
+
+/*@Doc:
+ BMP convertor class.
+ Completely native implementation, doesn't use external libs.
+ memfs is used differently here, therefore the class is derived
+ directly from r_Convertor rather than r_Convert_Memory.
+
+ Supported parameters are
+
+ \begin{tabular}{lcl}
+ compress && int && Use compression (8bpp only)
+ \end{tabular}
+*/
+
+class r_Conv_BMP : public r_Convertor
+{
+ public:
+ /// constructor using an r_Type object
+ r_Conv_BMP( const char *src, const r_Minterval &interv, const r_Type *tp ) throw(r_Error);
+ /// constructor using convert_type_e shortcut
+ r_Conv_BMP( const char *src, const r_Minterval &interv, int tp ) throw(r_Error);
+ /// destructor
+ ~r_Conv_BMP( void );
+
+ /// convert to BMP
+ virtual r_convDesc &convertTo( const char *options=NULL ) throw(r_Error);
+ /// convert from BMP
+ virtual r_convDesc &convertFrom( const char *options=NULL ) throw(r_Error);
+ /// cloning
+ virtual r_Convertor *clone( void ) const;
+ /// identification
+ virtual const char *get_name( void ) const;
+ virtual r_Data_Format get_data_format( void ) const;
+
+
+ private:
+ /// initalize BMP class
+ void initBMP( void );
+ /// Needed by the encoder in RLE mode
+ unsigned char *flushLiterals(int numLit, int pixelAdd, unsigned char *dest, const unsigned char *lastLit, const unsigned char *mapColours);
+
+ memFSContext *memFS;
+
+ /// parameters
+ int compress;
+};
+
+#endif
diff --git a/conversion/convertor.cc b/conversion/convertor.cc
new file mode 100644
index 0000000..9c6f353
--- /dev/null
+++ b/conversion/convertor.cc
@@ -0,0 +1,405 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: convertor.cc
+ *
+ * MODULE: conversion
+ *
+ * CLASSES: r_Convertor, r_Convert_Memory
+ *
+ * PURPOPSE:
+ * Provides interface to convert data to other formats.
+ *
+ * COMMENTS:
+ * - FIXME: r_Convertor::get_internal_type(): every structType is recognised as RGB!
+ *
+*/
+
+#include "conversion/convertor.hh"
+#include "conversion/memfs.hh"
+#include "raslib/error.hh"
+#include "raslib/parseparams.hh"
+#include "raslib/rminit.hh"
+#include "raslib/primitivetype.hh"
+
+
+/*
+ * r_Convertor class
+ */
+
+void r_Convertor::initShare( const char *src, const r_Minterval &interv )
+{
+ desc.src = src;
+ desc.srcInterv = interv;
+ desc.srcType = NULL;
+ desc.destType = NULL;
+ desc.dest = NULL;
+ params = NULL;
+ destroySrc = false;
+}
+
+
+r_Convertor::r_Convertor( void )
+{
+ desc.srcType = NULL;
+ desc.destType = NULL;
+ desc.dest = NULL;
+ desc.src = NULL;
+ desc.baseType = ctype_void;
+ params = NULL;
+}
+
+
+r_Convertor::r_Convertor( const char *src, const r_Minterval &interv, const r_Type *tp, bool fullTypes ) throw(r_Error)
+{
+ initShare(src, interv);
+
+ desc.srcType = tp;
+
+ if (tp == NULL)
+ {
+ RMInit::logOut << "Error: in conversion: type is null." << endl;
+ throw r_Error();
+ }
+
+ // Initialise desc.baseType from desc.srcType
+ desc.baseType=get_internal_type(tp, fullTypes);
+
+ if (!fullTypes) {
+ switch (tp->type_id()) {
+ case r_Type::FLOAT:
+ this->applyColorScheme<float>();
+ break;
+ case r_Type::DOUBLE:
+ applyColorScheme<double>();
+ break;
+ case r_Type::USHORT:
+ applyColorScheme<unsigned short>();
+ break;
+ case r_Type::SHORT:
+ applyColorScheme<short>();
+ break;
+ }
+ }
+}
+
+
+r_Convertor::r_Convertor(const char *src, const r_Minterval &interv, int type) throw(r_Error)
+{
+ initShare(src, interv);
+
+ desc.baseType = type;
+}
+
+
+r_Convertor::~r_Convertor(void)
+{
+ // Don't delete the resulting object pointer (desc->dest) !
+ // This is the job of the external application.
+ if (params!=NULL)
+ {
+ delete params;
+ params=NULL;
+ }
+ if (destroySrc)
+ {
+ delete desc.src;
+ destroySrc=false;
+ }
+}
+
+
+void r_Convertor::set_storage_handler( const r_Storage_Man &newStore )
+{
+ mystore = newStore;
+}
+
+
+const r_Storage_Man&
+r_Convertor::get_storage_handler( ) const
+{
+ return mystore;
+}
+
+
+
+r_Type *r_Convertor::get_external_type( int ctype ) throw(r_Error)
+{
+ r_Type* retval=NULL;
+ switch (ctype)
+ {
+ case ctype_bool:
+ retval=r_Type::get_any_type("boolean");
+ break;
+ case ctype_char:
+ case ctype_uint8:
+ retval=r_Type::get_any_type("char");
+ break;
+ case ctype_int8:
+ retval=r_Type::get_any_type("octet");
+ break;
+ case ctype_int16:
+ retval=r_Type::get_any_type("short");
+ break;
+ case ctype_uint16:
+ retval=r_Type::get_any_type("ushort");
+ break;
+ case ctype_int32:
+ retval=r_Type::get_any_type("long");
+ break;
+ case ctype_uint32:
+ retval=r_Type::get_any_type("ulong");
+ break;
+ case ctype_int64:
+ retval=r_Type::get_any_type("double"); // currently unsupported
+ break;
+ case ctype_uint64:
+ retval=r_Type::get_any_type("double"); // currently unsupported
+ break;
+ case ctype_float32:
+ retval=r_Type::get_any_type("float");
+ break;
+ case ctype_float64:
+ retval=r_Type::get_any_type("double");
+ break;
+ case ctype_rgb:
+ retval=r_Type::get_any_type("struct {char, char, char}");
+ break;
+ default:
+ RMInit::logOut << "Error: in conversion: unsupported type " << ctype << endl;
+ r_Error err(r_Error::r_Error_General);
+ throw(err);
+ }
+ return retval;
+}
+
+
+template <class baseType>
+void r_Convertor::applyColorScheme() {
+ baseType *data = (baseType*)desc.src;
+ baseType min=data[0], max=data[0];
+ int i, size = desc.srcInterv.cell_count();
+ unsigned char *t, *img = new unsigned char[size*3];
+ for (i=1; i<size; ++i) {
+ if (min > data[i])
+ min=data[i];
+ if (max < data[i])
+ max=data[i];
+ }
+ for (i=0, t=img; i<size; ++i) {
+ float n = (data[i]-min)/(max-min);
+ if (n<0.5) {
+ *t=(unsigned char)((0.5-n)*500); t++;
+ *t=(unsigned char)(n*500); t++;
+ *t=0; t++;
+ } else
+ {
+ *t=0;t++;
+ *t=(unsigned char)((1-n)*500); t++;
+ *t=(unsigned char)((n-0.5)*500); t++;
+ }
+ }
+ destroySrc = true;
+ desc.src = (char*)img;
+}
+
+r_Convertor::convert_type_e
+r_Convertor::get_internal_type(const r_Type* tp, bool fullTypes) throw(r_Error) {
+ r_Convertor::convert_type_e retval=ctype_void;
+
+ if (tp == NULL)
+ return retval;
+
+ //check if tp is structure type
+ if (tp->isStructType())
+ {
+ // make life easy and always interpret as RGB
+ retval = ctype_rgb;
+ }
+ else
+ {
+ //is primitive type
+ if (fullTypes == false)
+ {
+ // restricted types for ``classic'' image formats
+ switch (tp->type_id())
+ {
+ case r_Type::BOOL:
+ retval = ctype_bool; break;
+ case r_Type::CHAR:
+ case r_Type::OCTET:
+ retval = ctype_char; break;
+ // added (U)LONG -- PB 2005-apr-27
+ case r_Type::LONG:
+ retval = ctype_int32; break;
+ case r_Type::ULONG:
+ retval = ctype_uint32; break;
+ // set to defined value (FIXME: still not good) -- PB 2005-apr-27
+ default:
+ RMInit::logOut << "Error: in conversion: unknown type " << tp->type_id() << ", setting to void." << endl;
+ retval = ctype_rgb;
+ //retval = ctype_char;
+
+ break;
+ }
+ }
+ else
+ {
+ // full types for more generic convertors
+ switch (tp->type_id())
+ {
+ case r_Type::BOOL:
+ //FIXME that was in hdf.cc retval = ctype_uint8; break;
+ retval = ctype_bool; break;
+ case r_Type::CHAR:
+ retval = ctype_uint8; break;
+ case r_Type::OCTET:
+ retval = ctype_int8; break;
+ case r_Type::SHORT:
+ retval = ctype_int16; break;
+ case r_Type::USHORT:
+ retval = ctype_uint16; break;
+ case r_Type::LONG:
+ retval = ctype_int32; break;
+ case r_Type::ULONG:
+ retval = ctype_uint32; break;
+ case r_Type::FLOAT:
+ retval = ctype_float32; break;
+ case r_Type::DOUBLE:
+ retval = ctype_float64; break;
+ default:
+ break;
+ }
+ }//endif fullTypes
+ if (retval == ctype_void)
+ {
+ RMInit::logOut << "Warning: in conversion: this type overrides base type: " << tp->type_id() << "; using char." << endl;
+ retval = ctype_char;
+ }
+ }//endif structuretype
+
+ return retval;
+}
+
+std::ostream& operator<<(std::ostream& os, r_Convertor::convert_type_e& cte)
+{
+ switch(cte)
+ {
+ case r_Convertor::ctype_bool:
+ os << "bool";
+ break;
+ case r_Convertor::ctype_char:
+ os << "char";
+ break;
+ case r_Convertor::ctype_uint8:
+ os << "uint8";
+ break;
+ case r_Convertor::ctype_int8:
+ os << "int8";
+ break;
+ case r_Convertor::ctype_int16:
+ os << "int16";
+ break;
+ case r_Convertor::ctype_uint16:
+ os << "uint16";
+ break;
+ case r_Convertor::ctype_int32:
+ os << "int32";
+ break;
+ case r_Convertor::ctype_uint32:
+ os << "uint32";
+ break;
+ case r_Convertor::ctype_int64:
+ os << "int64"; // currently unsupported
+ break;
+ case r_Convertor::ctype_uint64:
+ os << "uint64"; // currently unsupported
+ break;
+ case r_Convertor::ctype_float32:
+ os << "float32";
+ break;
+ case r_Convertor::ctype_float64:
+ os << "float64";
+ break;
+ case r_Convertor::ctype_rgb:
+ os << "rgb";
+ break;
+ default:
+ os << "r_Convertor::convert_type_e unknown type: " << cte << endl;
+ break;
+ }
+
+ return os;
+}
+
+/*
+ * r_Convert_Memory class
+ */
+
+void r_Convert_Memory::initMemory( void ) throw(r_Error)
+{
+ int status = -1;
+
+ memFS=NULL;
+ handle=NULL;
+
+ memFS = new memFSContext;
+ if ( memFS != NULL)
+ {
+ handle = (void*)memFS;
+ if (memfs_initfs(handle) >= 0)
+ status = 0;
+ }
+ if (status < 0)
+ {
+ RMInit::logOut << "Error: cannot allocate memory for conversion." << endl;
+ r_Error err(MEMMORYALLOCATIONERROR);
+ throw(err);
+ }
+}
+
+
+r_Convert_Memory::r_Convert_Memory( const char *src, const r_Minterval &interv, const r_Type *tp, int fullTypes ) throw(r_Error)
+: r_Convertor(src, interv, tp, fullTypes)
+{
+ initMemory();
+}
+
+
+r_Convert_Memory::r_Convert_Memory( const char *src, const r_Minterval &interv, int type ) throw(r_Error)
+: r_Convertor(src, interv, type)
+{
+ initMemory();
+}
+
+
+r_Convert_Memory::~r_Convert_Memory( void )
+{
+ memfs_killfs(handle);
+ if(memFS!=NULL)
+ {
+ delete memFS;
+ memFS=NULL;
+ }
+ handle=NULL;
+}
diff --git a/conversion/convertor.hh b/conversion/convertor.hh
new file mode 100644
index 0000000..01931f4
--- /dev/null
+++ b/conversion/convertor.hh
@@ -0,0 +1,252 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: convertor.hh
+ *
+ * MODULE: conversion
+ *
+ * CLASSES: r_Convertor, r_Convert_Memory
+ *
+ * COMMENTS:
+ *
+ * Provides interface to convert data to other formats.
+ *
+*/
+
+#ifndef _R_CONVERTOR_
+#define _R_CONVERTOR_
+
+#include <stdlib.h>
+
+#include "raslib/error.hh"
+#include "raslib/minterval.hh"
+#include "raslib/type.hh"
+#include "raslib/mddtypes.hh"
+#include "raslib/storageman.hh"
+//#include "conversion/memfs.h"
+
+
+
+// Declare to avoid including memfs.h (and with that tiffio.h)
+struct memFSContext;
+
+class r_Parse_Params;
+
+
+typedef struct r_convDesc {
+ const char *src; // pointer to source data
+ char *dest; // pointer to destination data
+ r_Minterval srcInterv; // dimensions of source data
+ r_Minterval destInterv; // dimensions of destination data
+ int baseType; // shortcut to src basetype
+ const r_Type *srcType; // basetypes of src data
+ r_Type *destType; // basetypes of dest data
+} r_convDesc;
+
+
+
+//@ManMemo: Module {\bf conversion}
+
+
+/*@Doc:
+ Conversion classes from and to data exchange formats. Can also be used for
+ tile compression of special MDD types (= images)
+
+ \begin{itemize}
+ \item
+ the member function convertTo() performs the conversion MDD -> DEF
+ \item
+ the member function convertFrom() performs the conversion DEF -> MDD
+ \item
+ the r_convDesc reference returned from this call is only valid while
+ the convertor object is.
+ \item
+ after successful execution the returned r_convDesc structure contains
+ the following information:
+ \begin{itemize}
+ \item
+ dest: pointer to converted data, allocated by the configured heap
+ storage object which will use malloc() by default (see
+ set_storage_handler()); must be deallocated by the caller.
+ \item
+ destInterv: r_Minterval describing the converted object's domain.
+ \item
+ destType: pointer to an r_Type object describing the converted
+ object's type; must be deallocated by the caller.
+ \end{itemize}
+ \item
+ on failure an exception is thrown.
+ \end{itemize}
+
+ The member function convertTo() receives a parameter string as argument
+ which is NULL for default parameters. The format of the string is such
+ that it can be parsed by r_Parse_Params. The params member variable is
+ initialized to NULL in this class. Derived classes that wish to add
+ parameters must first check whether params is NULL and create a new
+ object if so, then add their parameters. This makes it possible to
+ accumulate parameters over all class hierarchies.
+*/
+
+class r_Convertor
+{
+ public:
+ /// default constructor (should not be used)
+ r_Convertor( void );
+ /// constructor using an r_Type object
+ r_Convertor( const char *src, const r_Minterval &interv, const r_Type *tp,
+ bool fullTypes=false) throw(r_Error);
+ /// constructor using convert_type_e shortcut
+ r_Convertor( const char *src, const r_Minterval &interv, int type ) throw(r_Error);
+ /**
+ convert_type_e is an enumerator that acts as a shortcut to base types
+ relevant for DEFs. The values and what they correspond to are listed
+ below (the types below the line are for HDF):
+
+ \begin{tabular}{ll}
+ ctype_void && No type, used for errors\\
+ ctype_bool && bool\\
+ ctype_char && char\\
+ ctype_rgb && struct {char, char, char}\\
+ \hline
+ ctype_int8 && signed char\\
+ ctype_uint8 && unsigned char\\
+ ctype_int16 && short\\
+ ctype_uint16 && unsigned short\\
+ ctype_int32 && int\\
+ ctype_uint32 && unsigned int\\
+ ctype_int64 && (unsupported)\\
+ ctype_uint64 && (unsupported)\\
+ ctype_float32 && float\\
+ ctype_float64 && double\\
+ \end{tabular}
+ */
+
+ /// destructor
+ virtual ~r_Convertor( void );
+
+ //@Man: Interface
+ /// convert array to DEF
+ virtual r_convDesc &convertTo( const char *options=NULL ) throw(r_Error) = 0;
+
+ /// convert DEF to array
+ virtual r_convDesc &convertFrom( const char *options=NULL ) throw(r_Error) = 0;
+
+ /// cloning
+ virtual r_Convertor *clone( void ) const = 0;
+
+ /// identification
+ virtual const char *get_name( void ) const = 0;
+ virtual r_Data_Format get_data_format( void ) const = 0;
+
+ /// set storage handler, default is malloc/free
+ void set_storage_handler( const r_Storage_Man &newStore );
+
+ /// get storage handler, default is malloc/free
+ const r_Storage_Man& get_storage_handler( ) const;
+
+
+ /// base type shortcuts
+ enum convert_type_e {
+ // undefined type
+ ctype_void,
+ // Shortcut for the three important base types r_Boolean, r_Char and RGBPixel
+ ctype_bool,
+ ctype_char,
+ ctype_rgb,
+ // More generic types for HDF
+ ctype_int8,
+ ctype_uint8,
+ ctype_int16,
+ ctype_uint16,
+ ctype_int32,
+ ctype_uint32,
+ ctype_int64,
+ ctype_uint64,
+ ctype_float32,
+ ctype_float64
+ };
+
+ //@{ helper structure for encoding string-to-int parameters
+ typedef struct convert_string_s {
+ const char *key;
+ int id;
+ } convert_string_t;
+ //@}
+
+ /// get a r_Type from an internal type
+ static r_Type *get_external_type( int ctype ) throw(r_Error);
+
+ /// get a internal type from a r_Type
+ static convert_type_e get_internal_type( const r_Type* type, bool fullTypes=false ) throw(r_Error);
+
+ protected:
+ /// initialize internal structures
+ void initShare( const char *src, const r_Minterval &interv );
+
+ /// true if we should free the src area (in case the input was converted to rgb)
+ bool destroySrc;
+
+ /// convert unsupported type to rgb by applying the default color scheme
+ template <class baseType>
+ void applyColorScheme();
+
+ /// conversion context
+ r_convDesc desc;
+
+ /// parameter parser
+ r_Parse_Params *params;
+
+ /// storage manager
+ r_Storage_Man mystore;
+};
+
+///ostream operator for convert_type_e
+std::ostream& operator<<(std::ostream& os, r_Convertor::convert_type_e& cte);
+
+/*@Doc:
+ Abstract base class for all memory-to-memory conversion classes,
+ uses memfs for of data with unknown size at the time of creation.
+*/
+
+class r_Convert_Memory : public r_Convertor
+{
+ public:
+ /// constructor using an r_Type object
+ r_Convert_Memory( const char *src, const r_Minterval &interv, const r_Type *tp,
+ int fullTypes=0) throw(r_Error);
+ /// constructur using convert_type_e shortcut
+ r_Convert_Memory( const char *src, const r_Minterval &interv, int type ) throw(r_Error);
+ /// destructor
+ virtual ~r_Convert_Memory( void );
+
+
+ protected:
+ /// init memfs
+ void initMemory( void ) throw(r_Error);
+
+ /// variables
+ memFSContext *memFS;
+ void *handle;
+};
+
+#endif
diff --git a/conversion/convfactory.cc b/conversion/convfactory.cc
new file mode 100644
index 0000000..31f27ae
--- /dev/null
+++ b/conversion/convfactory.cc
@@ -0,0 +1,189 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: convertor.cc
+ *
+ * MODULE: conversion
+ *
+ * CLASSES: r_Convertor_Factory
+ * Create convertors out of data formats
+ *
+ * COMMENTS:
+ * - temporary, for debugging
+*/
+
+#include "raslib/rminit.hh"
+#include "debug.hh"
+
+#include "conversion/convfactory.hh"
+
+// all the conversion types, for easy creation
+#include "tiff.hh"
+#include "hdf.hh"
+#include "png.hh"
+#include "jpeg.hh"
+#include "bmp.hh"
+#include "vff.hh"
+#include "tor.hh"
+#include "dem.hh"
+#include "ecw.hh"
+#include "ntf.hh"
+#include "csv.hh"
+
+
+
+bool r_Convertor_Factory::is_supported( r_Data_Format fmt )
+{
+ ENTER( "r_Convertor_Factory::is_supported( " << fmt << " )" );
+
+ bool retval=false;
+ switch (fmt)
+ {
+ case r_TIFF:
+ case r_PNG:
+ case r_JPEG:
+ case r_BMP:
+ case r_VFF:
+ case r_TOR:
+ case r_DEM:
+ case r_ECW:
+#ifndef DISABLE_HDF
+ case r_HDF:
+#endif
+ // case r_NTF:
+ retval=true;
+ break;
+ default:
+ retval=false;
+ break;
+ }
+
+ LEAVE( "r_Convertor_Factory::is_supported() -> " << retval );
+ return retval;
+}
+
+r_Convertor *r_Convertor_Factory::create( r_Data_Format fmt, const char *src, const r_Minterval &interv, const r_Type *tp) throw(r_Error)
+{
+ ENTER( "r_Convertor_Factory::create( fmt=" << fmt << ", &src=" << ((r_Ptr) src) << ", interval=" << interv << ", &type=" << ((r_Ptr) tp) << " )" );
+ r_Convertor *result = NULL;
+
+ switch (fmt)
+ {
+ case r_TIFF:
+ result = new r_Conv_TIFF(src, interv, tp);
+ break;
+ case r_PNG:
+ result = new r_Conv_PNG(src, interv, tp);
+ break;
+ case r_CSV:
+ result = new r_Conv_CSV(src, interv, tp);
+ break;
+ case r_JPEG:
+ result = new r_Conv_JPEG(src, interv, tp);
+ break;
+ case r_BMP:
+ result = new r_Conv_BMP(src, interv, tp);
+ break;
+ case r_VFF:
+ result = new r_Conv_VFF(src, interv, tp);
+ break;
+ case r_TOR:
+ result = new r_Conv_TOR(src, interv, tp);
+ break;
+ case r_DEM:
+ result = new r_Conv_DEM(src, interv, tp);
+ break;
+ case r_ECW:
+ result = new r_Conv_ECW(src, interv, tp);
+ break;
+#ifndef DISABLE_HDF
+ case r_HDF:
+ result = new r_Conv_HDF(src, interv, tp);
+ break;
+#endif
+ // case r_NTF:
+ // TALK( "creating NTF converter..." );
+ // result = new r_Conv_NTF(src, interv, tp);
+ // break;
+ default:
+ RMInit::logOut << "Error: in conversion factory during create: unsupported format: " << fmt << endl;
+ r_Error err(CONVERSIONFORMATNOTSUPPORTED);
+ throw(err);
+ }
+
+ LEAVE( "r_Convertor_Factory::create() -> " << result );
+ return result;
+}
+
+
+r_Convertor *r_Convertor_Factory::create( r_Data_Format fmt, const char *src, const r_Minterval &interv, int type ) throw(r_Error)
+{
+ ENTER( "r_Convertor_Factory::create( fmt=" << fmt << ", &src=" << ((r_Ptr) src) << ", interval=" << interv << ", type=" << type << " )" );
+
+ r_Convertor *result = NULL;
+
+ switch (fmt)
+ {
+ case r_TIFF:
+ result = new r_Conv_TIFF(src, interv, type);
+ break;
+ case r_PNG:
+ result = new r_Conv_PNG(src, interv, type);
+ break;
+ case r_JPEG:
+ result = new r_Conv_JPEG(src, interv, type);
+ break;
+ case r_BMP:
+ result = new r_Conv_BMP(src, interv, type);
+ break;
+ case r_VFF:
+ result = new r_Conv_VFF(src, interv, type);
+ break;
+ case r_TOR:
+ result = new r_Conv_TOR(src, interv, type);
+ break;
+ case r_DEM:
+ result = new r_Conv_DEM(src, interv, type);
+ break;
+ case r_ECW:
+ result = new r_Conv_ECW(src, interv, type);
+ break;
+#ifndef DISABLE_HDF
+ case r_HDF:
+ result = new r_Conv_HDF(src, interv, type);
+ break;
+#endif
+ // case r_NTF:
+ // TALK( "creating NTF converter..." );
+ // result = new r_Conv_NTF(src, interv, type);
+ // break;
+ default:
+ RMInit::logOut << "Error: in conversion factory during create: unsupported format: " << fmt << endl;
+ r_Error err(CONVERSIONFORMATNOTSUPPORTED);
+ throw(err);
+ }
+
+ LEAVE( "r_Convertor_Factory::create() -> " << result );
+ return result;
+}
+
diff --git a/conversion/convfactory.hh b/conversion/convfactory.hh
new file mode 100644
index 0000000..e299dca
--- /dev/null
+++ b/conversion/convfactory.hh
@@ -0,0 +1,64 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: convertor.cc
+ *
+ * MODULE: conversion
+ *
+ * CLASSES: r_Convertor_Factory
+ *
+ * COMMENTS:
+ * Create convertors out of data formats
+*/
+
+#include "raslib/mddtypes.hh"
+#include "raslib/error.hh"
+
+
+class r_Convertor;
+class r_Minterval;
+class r_Type;
+
+
+//@ManMemo: Module {\bf conversion}
+
+/*@Doc:
+ r_Convertor_Factory is a class encapsulating static functions to
+ create convertors out of data formats. The alternative of making
+ this functionality static members of r_Converstor would have meant
+ that all code using just one convertor would have to link the libs
+ of all convertors, rendering it unusable.
+*/
+
+class r_Convertor_Factory
+{
+ public:
+ /// check for support
+ static bool is_supported( r_Data_Format fmt );
+ /// creating from r_Type
+ static r_Convertor *create( r_Data_Format fmt, const char *src, const r_Minterval &interv,
+ const r_Type *tp ) throw(r_Error);
+ /// creating from internal type
+ static r_Convertor *create( r_Data_Format fmt, const char *src, const r_Minterval &interv,
+ int type ) throw(r_Error);
+};
diff --git a/conversion/csv.cc b/conversion/csv.cc
new file mode 100644
index 0000000..7babcbe
--- /dev/null
+++ b/conversion/csv.cc
@@ -0,0 +1,222 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: csv.cc
+ *
+ * MODULE: conversion
+ *
+ * CLASSES: r_Conv_CSV
+ *
+ * COMMENTS:
+ *
+ * Provides functions to convert data to CSV SD and back.
+ *
+*/
+
+/* Added by Sorin Stancu-Mara. Definition clashed for type int8, define in both
+* /usr/include/csv.h and in /usr/include/tiff.h
+* This will supress the tiff.h definition.
+* Both definitions are similar
+*/
+#define HAVE_INT8
+
+#include "conversion/csv.hh"
+#include "raslib/error.hh"
+#include "raslib/rminit.hh"
+#include "raslib/parseparams.hh"
+#include "raslib/primitivetype.hh"
+#include <iostream>
+#include <fstream>
+#include <cstring>
+
+#include "csv.hh"
+
+#include <stdio.h>
+#include <iostream>
+
+
+r_Conv_CSV::r_Conv_CSV(const char *src, const r_Minterval &interv, const r_Type *tp) throw(r_Error)
+: r_Convertor(src, interv, tp, true)
+{
+ if (tp->isStructType())
+ {
+ RMInit::logOut << "r_Conv_CSV::r_Conv_CSV(): structured types not supported." << endl;
+ throw r_Error(r_Error::r_Error_General);
+ }
+}
+
+
+
+r_Conv_CSV::r_Conv_CSV(const char *src, const r_Minterval &interv, int tp) throw(r_Error)
+: r_Convertor(src, interv, tp)
+{
+}
+
+
+/*
+int r_Conv_HDF::getTypeSize(int intType, char *format)
+{
+
+ switch (intType)
+ {
+ case ctype_int8: strcpy(format, "%c"); return 1; break;
+ case ctype_uint8:
+ case ctype_char:
+ case ctype_bool: return 1; break;
+ case ctype_int16: return 2; break;
+ case ctype_uint16: return 2; break;
+ case ctype_int32: return 4; break;
+ case ctype_uint32: return 4; break;
+ case ctype_int64: return 8; break;
+ case ctype_uint64: return 8; break;
+ case ctype_float32: return 4; break;
+ case ctype_float64: return 8; break;
+ default: return 1; break;
+ }
+ return 1;
+}
+*/
+
+r_Conv_CSV::~r_Conv_CSV(void)
+{
+}
+
+template <class baseType, class castType>
+void r_Conv_CSV::print(std::ofstream &f, baseType* val, int *dims, int dim) {
+ if (dim==1) {
+ for (int i=0; i<dims[0]-1; ++i, val++)
+ f << (castType)val[0] << ",";
+ f << (castType) val[dims[0]-1]; val++;
+ } else {
+ for (int i=0; i<dims[0]-1; ++i, val++) {
+ f << "{";
+ print<baseType, castType>(f, val, dims+1, dim-1);
+ f << "},";
+ }
+ f << "{";
+ print<baseType, castType>(f, val, dims+1, dim-1);
+ f << "}";
+ }
+}
+
+
+r_convDesc &r_Conv_CSV::convertTo( const char *options ) throw(r_Error)
+{
+ char name[256];
+ strncpy(name, tmpnam(NULL), 256);
+ std::ofstream ftemp(name);
+ //int size = getTypeSize(desc.baseType);
+ int rank, i;
+ int *dimsizes;
+ rank = desc.srcInterv.dimension();
+ const char *src = desc.src;
+
+ char *t;
+
+ dimsizes = new int[rank];
+
+ for (i=0; i<rank; i++)
+ {
+ dimsizes[i] = desc.srcInterv[i].high() - desc.srcInterv[i].low() + 1;
+ }
+
+ switch (desc.baseType)
+ {
+ case ctype_int8: print<const r_Octet, int>(ftemp, (const r_Octet* &)src, dimsizes, rank); break;
+ case ctype_uint8:
+ case ctype_char:
+ case ctype_bool: print<r_Char, int>(ftemp, (r_Char* &)src, dimsizes, rank); break;
+ case ctype_int16: print<r_Short, int>(ftemp, (r_Short* &)src, dimsizes, rank); break;
+ case ctype_uint16: print<r_UShort, int>(ftemp, (r_UShort* &) src, dimsizes, rank); break;
+ case ctype_int32: print<r_Long, int>(ftemp, (r_Long* &) src, dimsizes, rank); break;
+ case ctype_uint32: print<r_ULong, int>(ftemp, (r_ULong* &) src, dimsizes, rank); break;
+ case ctype_int64: print<long long, long long>(ftemp, (long long* &) src, dimsizes, rank); break;
+ case ctype_uint64: print<unsigned long long, unsigned long long>(ftemp, (unsigned long long* &) src, dimsizes, rank); break;
+ case ctype_float32: print<r_Float, float>(ftemp, (r_Float* &) src, dimsizes, rank); break;
+ case ctype_float64: print<r_Double, float>(ftemp, (r_Double* &) src, dimsizes, rank); break;
+ default: print<r_Char, int>(ftemp, (r_Char* &)src, dimsizes, rank);
+ }
+
+ delete [] dimsizes; dimsizes=NULL;
+ ftemp.close();
+
+ FILE *fp;
+ int filesize;
+
+ if ((fp = fopen(name, "rb")) == NULL)
+ {
+ RMInit::logOut << "r_Conv_CSV::convertTo(): unable to read back file." << endl;
+ throw r_Error(r_Error::r_Error_General);
+ }
+ fseek(fp, 0, SEEK_END);
+ filesize = ftell(fp);
+
+ desc.destInterv = r_Minterval(1);
+ desc.destInterv << r_Sinterval((r_Range)0, (r_Range)filesize - 1);
+
+ if ((desc.dest = (char*)mystore.storage_alloc(filesize)) == NULL)
+ {
+ RMInit::logOut << "r_Conv_CSV::convertTo(): out of memory error" << endl;
+ fclose(fp);
+ throw r_Error(MEMMORYALLOCATIONERROR);
+ }
+ fseek(fp, 0, SEEK_SET);
+ fread(desc.dest, 1, filesize, fp);
+
+ fclose(fp);
+
+ remove(name);
+
+ // Result is just a bytestream
+ desc.destType = r_Type::get_any_type("char");
+
+ return desc;
+}
+
+
+
+r_convDesc &r_Conv_CSV::convertFrom(const char *options) throw(r_Error)
+{
+ RMInit::logOut << "importing CSV data not yet implemented" << endl;
+ throw new r_Error(CONVERSIONFORMATNOTSUPPORTED);
+ return desc;
+}
+
+
+
+const char *r_Conv_CSV::get_name( void ) const
+{
+ return "csv";
+}
+
+
+r_Data_Format r_Conv_CSV::get_data_format( void ) const
+{
+ return r_CSV;
+}
+
+
+r_Convertor *r_Conv_CSV::clone( void ) const
+{
+ return new r_Conv_CSV(desc.src, desc.srcInterv, desc.baseType);
+}
diff --git a/conversion/csv.hh b/conversion/csv.hh
new file mode 100644
index 0000000..c4eed18
--- /dev/null
+++ b/conversion/csv.hh
@@ -0,0 +1,93 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: csv.hh
+ *
+ * MODULE: conversion
+ *
+ * CLASSES: r_Conv_CSV
+ *
+ * COMMENTS:
+ *
+ * Provides interface to convert data to other formats.
+ *
+*/
+
+#ifndef _R_CONV_CSV_HH_
+#define _R_CONV_CSV_HH_
+
+#include "conversion/convertor.hh"
+#include <ostream>
+
+//@ManMemo: Module {\bf conversion}
+
+/*@Doc:
+ CSV convertor class.
+
+ Supported parameters are
+
+ \begin{tabular}{lcl}
+ comptype && string && the compression type to use (see below)\\
+ quality && int && quality parameter for JPEG compression\\
+ skiphuff && int && skipping parameter for Huffman coding\\
+ \end{tabular}
+
+ The compression type defaults to deflate but may be one of the
+ following
+
+ \begin{tabular}{ll}
+ none && no compression\\
+ rle && Run Length Coding\\
+ huffman && Huffman coding\\
+ deflate && ZIP deflate\\
+ \end{tabular}
+
+*/
+class r_Conv_CSV : public r_Convertor
+{
+ public:
+ /// constructor using an r_Type object. Exception if the type isn't atomic.
+ r_Conv_CSV( const char *src, const r_Minterval &interv, const r_Type *tp) throw(r_Error);
+ /// constructor using convert_type_e shortcut
+ r_Conv_CSV( const char *src, const r_Minterval &interv, int tp ) throw(r_Error);
+ /// destructor
+ ~r_Conv_CSV( void );
+
+ /// convert to CSV
+ virtual r_convDesc &convertTo( const char *options=NULL ) throw(r_Error);
+ /// convert from CSV
+ virtual r_convDesc &convertFrom( const char *options=NULL ) throw(r_Error);
+ /// cloning
+ virtual r_Convertor *clone( void ) const;
+ /// identification
+ virtual const char *get_name( void ) const;
+ virtual r_Data_Format get_data_format( void ) const;
+
+
+ private:
+ template <class baseType, class castType>
+ void print(std::ofstream &f, baseType* val, int *dims, int dim);
+
+};
+
+#endif
diff --git a/conversion/dem.cc b/conversion/dem.cc
new file mode 100644
index 0000000..09e801e
--- /dev/null
+++ b/conversion/dem.cc
@@ -0,0 +1,894 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: dem.hh
+ *
+ * MODULE: conversion
+ *
+ * CLASSES: r_Conv_DEM
+ *
+ * PURPOSE:
+ * Provides interface to convert data from/to Array format to/from DEM format.
+ *
+ * COMMENTS:
+ * For further support send a mail to comanl@yahoo.com
+ * - convertTo() writes a temp file; this should be omitted for performance reasons
+*/
+
+static const char rcsid[] = "@(#)conversion,r_Conv_DEM: $Id: dem.cc,v 1.10 2005/09/08 12:59:26 rasdev Exp $";
+
+#include "conversion/dem.hh"
+
+#include <float.h>
+#include <string>
+#include <cstring>
+#include <strstream>
+#include <sstream>
+#include <algorithm>
+
+using std::istringstream;
+using std::istrstream;
+using std::string;
+using namespace std;
+
+#include "raslib/rminit.hh"
+#include "raslib/parseparams.hh"
+#include "raslib/primitivetype.hh"
+
+
+const r_Dimension r_Conv_DEM::srcIntervDim=1;
+const r_Dimension r_Conv_DEM::destIntervDim=2;
+const r_ULong r_Conv_DEM::paramMin=6;
+const char* r_Conv_DEM::paramSep=",";
+const char* r_Conv_DEM::paramEq="=";
+const char* r_Conv_DEM::paramFlipX="flipx";
+const char* r_Conv_DEM::paramFlipY="flipy";
+const char* r_Conv_DEM::paramStartX="startx";
+const char* r_Conv_DEM::paramEndX="endx";
+const char* r_Conv_DEM::paramResX="resx";
+const char* r_Conv_DEM::paramStartY="starty";
+const char* r_Conv_DEM::paramEndY="endy";
+const char* r_Conv_DEM::paramResY="resy";
+
+const r_Double r_Conv_DEM::NULL_DB = 0.;
+const r_Double r_Conv_DEM::ZERO_DB = FLT_MIN;
+const r_Double r_Conv_DEM::ZERO_DEM = 0.;
+
+r_Conv_DEM::~r_Conv_DEM( void )
+{
+ //nothing to care for
+}
+
+void r_Conv_DEM::initGeoBBox( r_GeoBBox& cBBox )
+{
+ //flipy is selected by default
+ cBBox.flipy = 1;
+
+ //flipx is not selected by default
+ cBBox.flipx = 0;
+
+ //geo information are initialized by default to DBL_MAX
+ // FIXME: better defaults res=1, min=-MAX?
+ cBBox.startx = DBL_MAX;
+ cBBox.endx = DBL_MAX;
+ cBBox.resx = DBL_MAX;
+ cBBox.starty = DBL_MAX;
+ cBBox.endy = DBL_MAX;
+ cBBox.resy = DBL_MAX;
+}
+
+r_Conv_DEM::r_Conv_DEM(const char* source, const r_Minterval& lengthordomain, const r_Type* tp) throw(r_Error)
+ : r_Convertor(source, lengthordomain, tp, true)
+{
+ initGeoBBox(collBBox);
+}
+
+r_Conv_DEM::r_Conv_DEM(const char* source, const r_Minterval& lengthordomain, int tp) throw(r_Error)
+ : r_Convertor(source, lengthordomain, tp)
+{
+ initGeoBBox(collBBox);
+}
+
+bool
+r_Conv_DEM::decodeOptions(const char* options,
+ r_GeoBBox& cBBox) throw()
+{
+ RMInit::logOut << "r_Conv_DEM::decodeOptions(" << (options?options:"NULL") << ")" << endl;
+
+ r_Parse_Params parseParams;
+
+ initGeoBBox(cBBox);
+
+ parseParams.add(paramFlipX, &cBBox.flipx, r_Parse_Params::param_type_int);
+ parseParams.add(paramFlipY, &cBBox.flipy, r_Parse_Params::param_type_int);
+ parseParams.add(paramStartX, &cBBox.startx, r_Parse_Params::param_type_double);
+ parseParams.add(paramEndX, &cBBox.endx, r_Parse_Params::param_type_double);
+ parseParams.add(paramResX, &cBBox.resx, r_Parse_Params::param_type_double);
+ parseParams.add(paramStartY, &cBBox.starty, r_Parse_Params::param_type_double);
+ parseParams.add(paramEndY, &cBBox.endy, r_Parse_Params::param_type_double);
+ parseParams.add(paramResY, &cBBox.resy, r_Parse_Params::param_type_double);
+
+ //process options
+ r_Long processRet=parseParams.process(options);
+ if(processRet < paramMin)
+ {
+ RMInit::logOut << "r_Conv_DEM::decodeOptions(...) Error: Some required options are missing!" << endl;
+ return false;
+ }
+
+ //check if start,res,end are present
+ if(cBBox.startx == DBL_MAX)
+ {
+ RMInit::logOut << "r_Conv_DEM::decodeOptions(...) Error: startx is not present!" << endl;
+ return false;
+ }
+
+ if(cBBox.starty == DBL_MAX)
+ {
+ RMInit::logOut << "r_Conv_DEM::decodeOptions(...) Error: starty is not present!" << endl;
+ return false;
+ }
+
+ if(cBBox.endx == DBL_MAX)
+ {
+ RMInit::logOut << "r_Conv_DEM::decodeOptions(...) Error: endx is not present!" << endl;
+ return false;
+ }
+
+ if(cBBox.endy == DBL_MAX)
+ {
+ RMInit::logOut << "r_Conv_DEM::decodeOptions(...) Error: endy is not present!" << endl;
+ return false;
+ }
+
+ if(cBBox.resx == DBL_MAX)
+ {
+ RMInit::logOut << "r_Conv_DEM::decodeOptions(...) Error: resx is not present!" << endl;
+ return false;
+ }
+
+ if(cBBox.resy == DBL_MAX)
+ {
+ RMInit::logOut << "r_Conv_DEM::decodeOptions(...) Error: resy is not present!" << endl;
+ return false;
+ }
+
+
+ //check res
+ if(!cBBox.resx)
+ {
+ RMInit::logOut << "r_Conv_DEM::decodeOptions(...) Error: resx is zero!" << endl;
+ return false;
+ }
+
+ if(!cBBox.resy)
+ {
+ RMInit::logOut << "r_Conv_DEM::decodeOptions(...) Error: resy is zero!" << endl;
+ return false;
+ }
+
+ //check start >= end
+ if(cBBox.startx >= cBBox.endx )
+ {
+ RMInit::logOut << "r_Conv_DEM::decodeOptions(...) Error: startx >= endx!" << endl;
+ return false;
+ }
+
+ if(cBBox.starty >= cBBox.endy)
+ {
+ RMInit::logOut << "r_Conv_DEM::decodeOptions(...) Erorr: starty >= endy!" << endl;
+ return false;
+ }
+
+ //show parsed options
+ RMInit::logOut.setf(std::ios::fixed);
+ RMInit::logOut << "r_Conv_DEM::decodeOptions(...) parsed options:" << endl
+ << " " << paramFlipX << paramEq << cBBox.flipx
+ << " " << paramFlipY << paramEq << cBBox.flipy << endl
+ << " " << paramStartX << paramEq << cBBox.startx
+ << " " << paramEndX << paramEq << cBBox.endx
+ << " " << paramResX << paramEq << cBBox.resx << endl
+ << " " << paramStartY << paramEq << cBBox.starty
+ << " " << paramEndY << paramEq << cBBox.endy
+ << " " << paramResY << paramEq << cBBox.resy << endl;
+ return true;
+}
+
+string
+r_Conv_DEM::encodeOptions(const r_GeoBBox& cBBox) throw()
+{
+ std::ostringstream os;
+
+ os.str("");
+ os.setf(std::ios::fixed);
+ os << paramFlipX << paramEq << cBBox.flipx
+ << paramSep << paramFlipY << paramEq << cBBox.flipy
+ << paramSep << paramStartX << paramEq << cBBox.startx
+ << paramSep << paramEndX << paramEq << cBBox.endx
+ << paramSep << paramResX << paramEq << cBBox.resx
+ << paramSep << paramStartY << paramEq << cBBox.starty
+ << paramSep << paramEndY << paramEq << cBBox.endy
+ << paramSep << paramResY << paramEq << cBBox.resy;
+
+ RMInit::logOut << "r_Conv_DEM::encodeOptions(" << os.str() << ")" << endl;
+
+ return os.str();
+}
+
+void
+r_Conv_DEM::checkLimits() throw(r_Error)
+{
+ //show processed data
+ RMInit::logOut << "r_Conv_DEM::checkLimits() processed data:" << endl
+ << " minx=" << min.x << " miny=" << min.y << " minh=" << min.h << endl
+ << " maxx=" << max.x << " maxy=" << max.y << " maxh=" << max.h << endl;
+ // printf( "r_Conv_DEM::checkLimits() processed data: minx=%8G, miny=%8G, minh=%8G, maxx=%8G, maxy=%8G, maxh=%8G\n", min.x, min.y, min.h, max.x, max.y, max.h );
+
+ if(collBBox.startx > min.x)
+ {
+ RMInit::logOut << "r_Conv_DEM::checkLimits() startx( " << collBBox.startx << ") > min.x (" << min.x << " )!" << endl;
+ throw r_Error();
+ }
+ if(collBBox.endx < max.x)
+ {
+ RMInit::logOut << "r_Conv_DEM::checkLimits() endx( " << collBBox.endx << ") < max.x (" << max.x << " )!" << endl;
+ throw r_Error();
+ }
+
+ if(collBBox.starty > min.y)
+ {
+ RMInit::logOut << "r_Conv_DEM::checkLimits() starty( " << collBBox.starty << ") > min.y (" << min.y << " )!" << endl;
+ throw r_Error();
+ }
+
+ if(collBBox.endy < max.y)
+ {
+ RMInit::logOut << "r_Conv_DEM::checkLimits() endy( " << collBBox.endy << ") < max.y (" << max.y << " )!" << endl;
+ throw r_Error();
+ }
+}
+
+void
+r_Conv_DEM::readFromSrcStream() throw(r_Error)
+{
+ istrstream iFile(desc.src, desc.srcInterv[0].get_extent());
+ string currStrRow;
+ r_Long rowNo=0;
+ r_Double noResx, noResy;
+ DEMRow currRow, prevRow;
+
+ min.x=min.y=min.h=DBL_MAX;
+ max.x=max.y=max.h=-DBL_MAX;
+ demRows.clear();
+
+ //process the lines
+ while(!iFile.eof())
+ {
+ getline(iFile, currStrRow);
+ rowNo++;
+ if(currStrRow.empty())
+ {
+ // TALK( "r_Conv_DEM::readFromSrcStream() skipping empty line " << rowNo );
+ continue;
+ }
+ else
+ {
+ // have an input stream for analysing the current line
+ // (declaring this variable here allows to have a fresh one;
+ // had a reentrance problem with followup lines -- PB 2005-sep-08)
+ istringstream icurrRow;
+ icurrRow.str(currStrRow);
+
+ //decode x
+ icurrRow >> currRow.x;
+ if(!icurrRow)
+ {
+ RMInit::logOut << "Error in r_Conv_DEM::readFromSrcStream():: unable to decode x in line " << rowNo << ", skipping line: " << currStrRow << endl;
+ continue;
+ }
+
+ //decode y
+ icurrRow >> currRow.y;
+ if(!icurrRow)
+ {
+ RMInit::logOut << "Error in r_Conv_DEM::readFromSrcStream():: unable to decode y in line " << rowNo << ", skipping line: " << currStrRow << endl;
+ continue;
+ }
+
+ //decode h
+ icurrRow >> currRow.h;
+ if(!icurrRow)
+ {
+ RMInit::logOut << "Error in r_Conv_DEM::readFromSrcStream():: unable to decode h in line " << rowNo << ", skipping line: " << currStrRow << endl;
+ continue;
+ }
+
+ //update to support NULL value: 0. (real value) goes in FLT_MIN(db value)
+ //because 0.(db value) represent NULL(real value). When we do export we skip NULL values.
+ if(currRow.h == ZERO_DEM)
+ currRow.h=ZERO_DB;
+
+ //FIXME we ignore this check, because it may happen to have a incomplet dem
+ /*
+ //check if we have resx, resy
+ noResx=currRow.x/collBBox.resx;
+ if((currRow.x - noResx*collBBox.resx) > 0.)
+ {
+ RMInit::logOut << "r_Conv_DEM::readFromSrcStream() resolution for x on line " <<
+ rowNo << " is not " << collBBox.resx << " !" << endl;
+ throw r_Error();
+ }
+ noResy=currRow.y/collBBox.resy;
+ if((currRow.y - noResy*collBBox.resy) > 0.)
+ {
+ RMInit::logOut << "r_Conv_DEM::readFromSrcStream() resolution for y on line " <<
+ rowNo << " is not " << collBBox.resy << " !" << endl;
+ throw r_Error();
+ }
+ */
+
+ //compute min, max for x,y,z
+ min.x=std::min<r_Double>(min.x, currRow.x);
+ min.y=std::min<r_Double>(min.y, currRow.y);
+ min.h=std::min<r_Double>(min.h, currRow.h);
+ max.x=std::max<r_Double>(max.x, currRow.x);
+ max.y=std::max<r_Double>(max.y, currRow.y);
+ max.h=std::max<r_Double>(max.h, currRow.h);
+
+ //store currRow
+ demRows.push_back(currRow);
+ }//end if(currStrRow.empty())
+
+ }//end reading src stream
+
+ if(demRows.empty())
+ {
+ // TALK( "r_Conv_DEM::readFromSrcStream() desc.src stream empty." );
+ throw r_Error();
+ }
+
+ // std::cout << "r_Conv_DEM::readFromSrcStream(): x=" << min.x << ":" << max.x << ", y=" << min.y << ":" << max.y << endl;
+
+ //check limits
+ checkLimits();
+}
+
+
+void
+r_Conv_DEM::readToSrcStream() throw(r_Error)
+{
+ r_Long x=0, y=0;
+ r_Long xlow=0, ylow=0;
+ r_Long xhigh=0, yhigh=0;
+ DEMRow currRow;
+ r_Bytes typeSize=0;
+ r_Long offset=0;
+ char* buffer=NULL;
+
+ //initialize
+ xlow=desc.srcInterv[0].low();
+ ylow=desc.srcInterv[1].low();
+
+ xhigh=desc.srcInterv[0].high();
+ yhigh=desc.srcInterv[1].high();
+
+ //compute min & max
+ if (collBBox.flipx)
+ {
+ min.x=collBBox.endx - xhigh*collBBox.resx;
+ max.x=collBBox.endx - xlow*collBBox.resx;
+ }
+ else
+ {
+ min.x=collBBox.startx + xlow*collBBox.resx;
+ max.x=collBBox.startx + xhigh*collBBox.resx;
+ }
+
+ if(collBBox.flipy)
+ {
+ min.y=collBBox.endy - yhigh*collBBox.resy;
+ max.y=collBBox.endy - ylow*collBBox.resy;
+ }
+ else
+ {
+ min.y=collBBox.starty + ylow*collBBox.resy;
+ max.y=collBBox.starty + yhigh*collBBox.resy;
+ }
+
+ min.h=DBL_MAX;
+ max.h=-DBL_MAX;
+
+ //check limits
+ checkLimits();
+
+ //prepare container
+ demRows.clear();
+ typeSize=((r_Primitive_Type*)desc.srcType)->size();
+ buffer=new char[typeSize];
+ if(!buffer)
+ {
+ RMInit::logOut << "r_Conv_DEM::readToSrcStream() unable to claim memory !" << endl;
+ throw r_Ememory_allocation();
+ }
+ for(y=ylow; y<=yhigh; y++)
+ {
+ if(collBBox.flipy)
+ currRow.y=collBBox.endy - y*collBBox.resy;
+ else
+ currRow.y=collBBox.starty + y*collBBox.resy;
+
+ for(x=xlow; x<=xhigh; x++)
+ {
+ if(collBBox.flipx)
+ currRow.x=collBBox.endx - x*collBBox.resx;
+ else
+ currRow.x=collBBox.startx + x*collBBox.resx;
+ offset=desc.srcInterv.cell_offset(r_Point(x,y))*typeSize;
+ memcpy(buffer, &desc.src[offset], typeSize);
+
+ switch(desc.srcType->type_id())
+ {
+ case r_Type::BOOL:
+ currRow.h=((r_Primitive_Type*)desc.srcType)->get_boolean(buffer);
+ break;
+ case r_Type::CHAR:
+ currRow.h=((r_Primitive_Type*)desc.srcType)->get_char(buffer);
+ break;
+ case r_Type::OCTET:
+ currRow.h=((r_Primitive_Type*)desc.srcType)->get_octet(buffer);
+ break;
+ case r_Type::SHORT:
+ currRow.h=((r_Primitive_Type*)desc.srcType)->get_short(buffer);
+ break;
+ case r_Type::USHORT:
+ currRow.h=((r_Primitive_Type*)desc.srcType)->get_ushort(buffer);
+ break;
+ case r_Type::LONG:
+ currRow.h=((r_Primitive_Type*)desc.srcType)->get_long(buffer);
+ break;
+ case r_Type::ULONG:
+ currRow.h=((r_Primitive_Type*)desc.srcType)->get_ulong(buffer);
+ break;
+ case r_Type::FLOAT:
+ currRow.h=((r_Primitive_Type*)desc.srcType)->get_float(buffer);
+ break;
+ case r_Type::DOUBLE:
+ currRow.h=((r_Primitive_Type*)desc.srcType)->get_double(buffer);
+ break;
+ default:
+ //write message to log
+ RMInit::logOut << "r_Conv_DEM::readToSrcStream() srcType (" << desc.srcType->type_id() << ") unsupported !" << endl;
+ //clean up
+ if(buffer)
+ {
+ delete[] buffer;
+ buffer=NULL;
+ }
+ //report error
+ throw r_Error();
+ break;
+ }
+ min.h=std::min<r_Double>(min.h, currRow.h);
+ max.h=std::max<r_Double>(max.h, currRow.h);
+ demRows.push_back(currRow);
+ }
+ }
+
+ //clean up
+ if(buffer)
+ {
+ delete[] buffer;
+ buffer=NULL;
+ }
+
+ if(demRows.empty())
+ {
+ RMInit::logOut << "r_Conv_DEM::readToSrcStream() src stream is empty !" << endl;
+ throw r_Error();
+ }
+
+ RMInit::logOut << "r_Conv_DEM::readToSrcStream() processed interval [" << xlow << ":" << xhigh << "," << ylow << ":" << yhigh << "]" << endl;
+}
+
+
+void
+r_Conv_DEM::writeFromDestStream() throw(r_Error)
+{
+ DEMRowVec::const_iterator iter, iterEnd;
+ r_Long xdim, ydim, offset;
+ r_Point currPt(destIntervDim);
+ r_Bytes typeSize=0;
+
+
+ //FIXME here we should modify for other type support
+ if(desc.destType->type_id() != r_Type::DOUBLE)
+ {
+ RMInit::logOut << "r_Conv_DEM::writeFromDestStream() destType (" << desc.destType->type_id()
+ << ") is not " << r_Type::DOUBLE << " !" << endl;
+ throw r_Error();
+ }
+
+ xdim=desc.destInterv[0].get_extent();
+ ydim=desc.destInterv[1].get_extent();
+ iter=demRows.begin();
+ iterEnd=demRows.end();
+ typeSize=((r_Primitive_Type*)desc.destType)->size();
+
+ //FIXME correction for strange effect of r_Long cast with 1e-6
+ while(iter != iterEnd)
+ {
+ if(collBBox.flipx)
+ currPt[0]=(collBBox.endx - iter->x)/collBBox.resx + 1e-6;
+ else
+ currPt[0]=(iter->x - collBBox.startx)/collBBox.resx + 1e-6;
+ if(collBBox.flipy)
+ currPt[1]=(collBBox.endy - iter->y)/collBBox.resy + 1e-6;
+ else
+ currPt[1]=(iter->y - collBBox.starty)/collBBox.resy + 1e-6;
+ ((r_Primitive_Type*)desc.destType)->set_double(&desc.dest[desc.destInterv.cell_offset(currPt)*typeSize], iter->h);
+ ++iter;
+ }
+
+ RMInit::logOut << "r_Conv_DEM::writeFromDestStream() processed " << xdim << " x " << ydim << " elements." << endl;
+}
+
+void
+r_Conv_DEM::writeToDestStream(ofstream& oFile) throw(r_Error)
+{
+ DEMRowVec::const_iterator iter, iterEnd;
+ r_Double currH;
+
+ if(!oFile.is_open())
+ {
+ RMInit::logOut << "r_Conv_DEM::writeToDestStream() oFile is not opened !" << endl;
+ throw r_Error();
+ }
+ oFile.setf(std::ios::fixed);
+
+ iter=demRows.begin();
+ iterEnd=demRows.end();
+ while(iter != iterEnd)
+ {
+ //update to support NULL value: 0. (real value) goes in FLT_MIN(db value)
+ //because 0.(db value) represent NULL(real value). When we do export we skip NULL values.
+ currH = iter->h;
+ if(currH != NULL_DB)
+ {
+ //FIXME we have to implement different here when we change server scale algorithm
+ if(currH == ZERO_DB)
+ currH = ZERO_DEM;
+ oFile << iter->x << "\t" << iter->y << "\t" << currH << endl;
+ }
+ ++iter;
+ }
+}
+
+r_convDesc&
+r_Conv_DEM::convertFrom(const char* options) throw (r_Error)
+{
+ bool hasSrcType=true;
+
+ RMInit::logOut << "r_Conv_DEM::convertFrom(" << (options?options:"NULL") << ")" << endl;
+
+ if(!desc.srcType)
+ {
+ desc.srcType=get_external_type(desc.baseType);
+ hasSrcType=false;
+ }
+
+ try
+ {
+ RMInit::logOut << "r_Conv_DEM::convertFrom(...) src interval=" << desc.srcInterv << endl;
+ RMInit::logOut << "r_Conv_DEM::convertFrom(...) src type=" << desc.srcType->type_id() << endl;
+
+ //check options
+ if(!decodeOptions(options, collBBox))
+ {
+ RMInit::logOut << "Error in r_Conv_DEM::convertFrom(): illegal option string: " << (options?options:"(null)") << endl;
+ throw r_Error();
+ }
+
+ //check desc.srcInterv.dimension
+ if(desc.srcInterv.dimension() != srcIntervDim)
+ {
+ RMInit::logOut << "r_Conv_DEM::convertFrom(" << (options?options:"NULL")
+ << ") desc.srcInterv dimension (" << desc.srcInterv.dimension()
+ << " != " << srcIntervDim << " !" << endl;
+ throw r_Error();
+ }
+
+ //check srcType
+ if(!desc.srcType->isPrimitiveType())
+ {
+ RMInit::logOut << "r_Conv_DEM::convertFrom(" << (options?options:"NULL")
+ << ") desc.srcType (" << desc.srcType->type_id()
+ << ") not supported, only primitive types !" << endl;
+ throw r_Error();
+ }
+
+ if(desc.srcType->isComplexType())
+ {
+ RMInit::logOut << "r_Conv_DEM::convertFrom(" << (options?options:"NULL")
+ << ") desc.srcType (" << desc.srcType->type_id()
+ << ") not supported !" << endl;
+ throw r_Error();
+ }
+
+ //read src stream
+ readFromSrcStream();
+
+ //convert from DEM to marray
+ //--computing the marray domain
+ desc.destInterv = r_Minterval(destIntervDim);
+
+ //FIXME correction for strange efect of r_Long cast with 1e-6
+ if(collBBox.flipx)
+ desc.destInterv << r_Sinterval((r_Long)((collBBox.endx - max.x)/collBBox.resx + 1e-6),
+ (r_Long)((collBBox.endx - min.x)/collBBox.resx + 1e-6));
+ else
+ desc.destInterv << r_Sinterval((r_Long)((min.x - collBBox.startx)/collBBox.resx + 1e-6),
+ (r_Long)((max.x - collBBox.startx)/collBBox.resx + 1e-6));
+ if(collBBox.flipy)
+ desc.destInterv << r_Sinterval((r_Long)((collBBox.endy - max.y)/collBBox.resy + 1e-6),
+ (r_Long)((collBBox.endy - min.y)/collBBox.resy + 1e-6));
+ else
+ desc.destInterv << r_Sinterval((r_Long)((min.y - collBBox.starty)/collBBox.resy + 1e-6),
+ (r_Long)((max.y - collBBox.starty)/collBBox.resy + 1e-6));
+
+ RMInit::logOut << "r_Conv_DEM::convertFrom(...) dest interval=" << desc.destInterv << endl;
+
+ //--creating the resulting type
+ desc.destType = new r_Primitive_Type("Double", r_Type::DOUBLE);
+ RMInit::logOut << "r_Conv_DEM::convertFrom(...) dest type=" << desc.destType->type_id() << endl;
+
+ //--claim memory for result
+ desc.dest = (char*)mystore.storage_alloc(desc.destInterv.cell_count() * ((r_Primitive_Type*)desc.destType)->size());
+ if(desc.dest==NULL)
+ {
+ RMInit::logOut << "r_Conv_DEM::convertFrom(" << (options?options:"NULL")
+ << ") unable to claim memory !" << endl;
+ throw r_Ememory_allocation();
+ }
+ memset(desc.dest, 0, desc.destInterv.cell_count() * ((r_Primitive_Type*)desc.destType)->size());
+
+ //--write parsed data in desc.dest
+ writeFromDestStream();
+ }
+ catch(r_Error& err)
+ {
+ //cleanup
+ if(!hasSrcType)
+ {
+ delete desc.srcType;
+ desc.srcType=NULL;
+ }
+
+ //desc.destType
+ if(desc.destType)
+ {
+ delete desc.destType;
+ desc.destType=NULL;
+ }
+
+ //desc.dest
+ if(desc.dest)
+ {
+ mystore.storage_free(desc.dest);
+ desc.dest=NULL;
+ }
+
+ //report error
+ throw;
+ }
+
+ //cleanup
+ if(!hasSrcType)
+ {
+ delete desc.srcType;
+ desc.srcType=NULL;
+ }
+
+ //return result
+ return desc;
+}
+
+
+r_convDesc&
+r_Conv_DEM::convertTo(const char* options) throw (r_Error)
+{
+ bool hasSrcType=true;
+
+ char* pTempFileName=NULL; // name of temp file
+ string tempFileName; // duplicate of temp file name -- heaven knows why
+ ofstream oFile; // for writing out file
+ FILE* pFile=NULL; // for reading back file
+ size_t lenFile=0; // size of file as read
+
+ RMInit::logOut << "r_Conv_DEM::convertTo(" << (options?options:"NULL") << ")" << endl;
+
+ try
+ {
+ if(!desc.srcType)
+ {
+ desc.srcType=get_external_type(desc.baseType);
+ hasSrcType=false;
+ }
+
+ RMInit::logOut << "r_Conv_DEM::convertTo(...) src interval=" << desc.srcInterv << endl;
+ RMInit::logOut << "r_Conv_DEM::convertTo(...) src type=" << desc.srcType->type_id() << endl;
+
+ //check options
+ if(!decodeOptions(options, collBBox))
+ throw r_Error();
+
+ if(!desc.srcType->isPrimitiveType())
+ {
+ RMInit::logOut << "r_Conv_DEM::convertTo(" << (options?options:"NULL")
+ << ") desc.srcType (" << desc.srcType->type_id()
+ << ") not supported, only primitive types !" << endl;
+ throw r_Error();
+ }
+ if(desc.srcType->isComplexType())
+ {
+ RMInit::logOut << "r_Conv_DEM::convertTo(" << (options?options:"NULL")
+ << ") desc.srcType (" << desc.srcType->type_id()
+ << ") not supported !" << endl;
+ throw r_Error();
+ }
+
+ //read src data
+ readToSrcStream();
+
+ //convert from marray to DEM;
+ //--create the temp file
+ //FIXME for multithread application
+ pTempFileName=tmpnam(NULL);
+ if(pTempFileName==NULL)
+ {
+ RMInit::logOut << "r_Conv_DEM::convertTo(" << (options?options:"NULL")
+ << ") desc.srcType (" << desc.srcType->type_id()
+ << ") unable to generate a tempory file !" << endl;
+ throw r_Error();
+ }
+
+ tempFileName=pTempFileName;
+ oFile.open(tempFileName.c_str());
+ if(!oFile.is_open())
+ {
+ RMInit::logOut << "r_Conv_DEM::convertTo(" << (options?options:"NULL")
+ << ") desc.srcType (" << desc.srcType->type_id()
+ << ") unable to open the tempory file !" << endl;
+ throw r_Error();
+ }
+
+ RMInit::logOut << "r_Conv_DEM::convertTo(...) temp file=" << tempFileName << endl;
+
+ //--get DEM format
+ writeToDestStream(oFile);
+ oFile.close();
+
+ //--accessing the temp file
+ if ((pFile = fopen(tempFileName.c_str(), "rb")) == NULL)
+ {
+ RMInit::logOut << "r_Conv_DEM::convertTo(): unable to read back file." << endl;
+ throw r_Error(r_Error::r_Error_General);
+ }
+ fseek(pFile, 0, SEEK_END);
+ lenFile = ftell(pFile);
+ RMInit::logOut << "r_Conv_DEM::convertTo(...) dest len=" << lenFile << endl;
+
+ if (!lenFile)
+ {
+ RMInit::logOut << "r_Conv_DEM::convertTo(): source contains only NULL values." << endl;
+ throw r_Error( E_DEM_EMPTY );
+ }
+
+ //--creating the resulting type
+ desc.destType = new r_Primitive_Type("Char", r_Type::CHAR);
+
+ //--computing the marray domain
+ desc.destInterv = r_Minterval(srcIntervDim);
+ desc.destInterv << r_Sinterval((r_Long)0, (r_Long)lenFile - 1);
+
+ RMInit::logOut << "r_Conv_DEM::convertTo(...) dest interval=" << desc.destInterv << endl;
+ RMInit::logOut << "r_Conv_DEM::convertTo(...) dest type=" << desc.destType->type_id() << endl;
+
+ //--claim memory for desc.dest
+ desc.dest = (char*)mystore.storage_alloc(lenFile);
+ if(desc.dest==NULL)
+ {
+ RMInit::logOut << "r_Conv_DEM::convertTo(" << (options?options:"NULL")
+ << ") unable to claim memory !" << endl;
+ throw r_Ememory_allocation();
+ }
+ memset(desc.dest, 0, lenFile);
+
+ //--store data in desc.dest
+ fseek(pFile, 0, SEEK_SET);
+ fread(desc.dest, 1, lenFile, pFile);
+
+ //clean up
+ fclose(pFile);
+ pFile=NULL;
+ remove(pTempFileName);
+ }
+ catch(r_Error& err)
+ {
+ //cleanup
+ if(!hasSrcType)
+ {
+ delete desc.srcType;
+ desc.srcType=NULL;
+ }
+
+ //desc.destType
+ if(desc.destType)
+ {
+ delete desc.destType;
+ desc.destType=NULL;
+ }
+
+ //desc.dest
+ if(desc.dest)
+ {
+ mystore.storage_free(desc.dest);
+ desc.dest=NULL;
+ }
+
+ // close & remove file, if not done previously
+ fclose(pFile);
+ pFile=NULL;
+ remove(pTempFileName);
+
+ //rethrow error
+ throw;
+ }
+
+ //clean up
+ if(!hasSrcType)
+ {
+ delete desc.srcType;
+ desc.srcType=NULL;
+ }
+
+ //return result
+ return desc;
+}
+
+const char*
+r_Conv_DEM::get_name() const throw()
+{
+ return get_name_from_data_format(r_DEM);
+}
+
+r_Data_Format
+r_Conv_DEM::get_data_format() const throw()
+{
+ return r_DEM;
+}
+
+r_Convertor*
+r_Conv_DEM::clone() const throw(r_Error)
+{
+ return new r_Conv_DEM(desc.src, desc.srcInterv, desc.srcType);
+}
diff --git a/conversion/dem.hh b/conversion/dem.hh
new file mode 100644
index 0000000..ccfdbef
--- /dev/null
+++ b/conversion/dem.hh
@@ -0,0 +1,187 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: dem.hh
+ *
+ * MODULE: conversion
+ *
+ * CLASSES: r_Conv_DEM
+ *
+ * PURPOSE:
+ * Provides interface to convert data to other formats.
+ *
+ * COMMENTS:
+ * None
+*/
+
+#ifndef _R_CONV_DEM_HH_
+#define _R_CONV_DEM_HH_
+
+#include <sstream>
+#include <vector>
+#include <string>
+#include <cstdio>
+using std::vector;
+using std::ofstream;
+using std::string;
+
+#include "conversion/convertor.hh"
+#include "raslib/odmgtypes.hh"
+
+//@ManMemo: Module {\bf conversion}
+
+/*@Doc:
+ DEM convertor class.
+
+ Supported parameters are
+
+ \begin{tabular}{lcl}
+ {\tt flipx} && int && flip image flag on x axis, default 0\\
+ {\tt flipy} && int && flip image flag on y axis, default 1\\
+ {\tt startx} && double && start value on x axis \\
+ {\tt endx} && double && end value on x axis \\
+ {\tt resx} && double && resolution on x axis \\
+ {\tt starty} && double && start value on y axis \\
+ {\tt endy} && double && end value on y axis \\
+ {\tt resy} && double && resolution on y axis \\
+ \end{tabular}
+
+ The "flipx" parameter is a flag for mirroring the image on x axis.
+ The "flipy" parameter is a flag for mirroring the image on y axis.
+ [startx:endx, starty:endy] represents the geographical bounding box
+ of the whole image. The corresponding pixel bounding box is calculated
+ as follows:
+ if flipy is disabled:
+ [(minx-startx)/resx:(maxx-startx)/resx, (miny-starty)/resy:(maxy-starty)/resy]
+ else
+ [(minx-startx)/resx:(maxx-startx)/resx, (endy-maxy)/resy:(endy-miny)/resy]
+
+ if flipx is disabled:
+ [(minx-startx)/resx:(maxx-startx)/resx, (miny-starty)/resy:(maxy-starty)/resy]
+ else
+ [(endx-maxx)/resx:(endx-minx)/resx, (miny-starty)/resy:(maxy-starty)/resy]
+
+ The pairs (startx, endx, resx), (starty, endy, resy) are for the whole image(e.g image bounding)
+ and the pairs (minx,maxx, resx), (miny, maxy, resy) are for the current part of image.
+ They are used to compute the position of current image in RasDaMan coordinates.
+*/
+
+// r_Error code for "empty DEM result generated"; this def should go into a central list
+// -- PB 2003-dec-03
+#define E_DEM_EMPTY 3000
+
+class r_Conv_DEM : public r_Convertor
+{
+ public:
+ // constants to handle NULL
+ static const r_Double NULL_DB;
+ static const r_Double ZERO_DB;
+ static const r_Double ZERO_DEM;
+
+ //inner class for convertor parameters
+ class r_GeoBBox
+ {
+ public:
+ r_Double startx, endx, resx;
+ r_Double starty, endy, resy;
+ r_ULong flipy, flipx;
+ };
+
+ r_Conv_DEM(const char* source, const r_Minterval& lengthordomain, const r_Type* tp) throw(r_Error);
+
+ r_Conv_DEM(const char* source, const r_Minterval& lengthordomain, int tp) throw(r_Error);
+
+ r_convDesc& convertFrom(const char* options = NULL) throw (r_Error);
+
+ r_convDesc& convertTo(const char* options = NULL) throw (r_Error);
+
+ const char* get_name() const throw();
+
+ r_Data_Format get_data_format() const throw();
+
+ r_Convertor* clone() const throw(r_Error);
+
+ /// dimension of src domain accepted as input in convertFrom
+ static const r_Dimension srcIntervDim;
+
+ /// dimension of dest domain accepted as input in convertTo
+ static const r_Dimension destIntervDim;
+
+ /// decode convertor options
+ static bool decodeOptions( const char* options,
+ r_GeoBBox& collBBox) throw();
+
+ /// encode convertor options
+ static string encodeOptions(const r_GeoBBox& collBBox) throw();
+
+ /// destructor
+ virtual ~r_Conv_DEM( void );
+
+ /// init convertor parameters to default value
+ static void initGeoBBox( r_GeoBBox& cBBox );
+
+ private:
+
+
+ /// check limits before converting
+ void checkLimits() throw(r_Error);
+
+ ///i/o src/dest stream
+ void readFromSrcStream() throw(r_Error);
+ void readToSrcStream() throw(r_Error);
+ void writeFromDestStream() throw(r_Error);
+ void writeToDestStream(ofstream& oFile) throw(r_Error);
+
+ /// parameters
+ r_GeoBBox collBBox;
+
+ /// class constants
+ static const r_ULong paramMin;
+ static const char* paramSep;
+ static const char* paramEq;
+ static const char* paramFlipX;
+ static const char* paramFlipY;
+ static const char* paramStartX;
+ static const char* paramEndX;
+ static const char* paramResX;
+ static const char* paramStartY;
+ static const char* paramEndY;
+ static const char* paramResY;
+
+
+ /// internal data
+ class DEMRow
+ {
+ public:
+ r_Double x,y,h;
+ };
+
+ typedef vector<DEMRow> DEMRowVec;
+
+ DEMRow min, max;
+ DEMRowVec demRows;
+
+ };
+
+#endif
+
diff --git a/conversion/des.cc b/conversion/des.cc
new file mode 100644
index 0000000..a6d9843
--- /dev/null
+++ b/conversion/des.cc
@@ -0,0 +1,118 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#include <iostream>
+#include <fstream>
+
+#include "des.h"
+#include "nitf.h"
+#include "utilities.h"
+
+using namespace std;
+using namespace RasNITF;
+
+des::des(){
+
+ m_desshf = NULL;
+ m_desdata = NULL;
+ data_length = 0;
+ header_length = 0;
+}
+
+des::~des(){
+
+ if(m_desshf != NULL){
+ delete m_desshf;
+ m_desshf = NULL;
+ }
+
+ if(m_desdata != NULL){
+ delete m_desdata;
+ m_desdata = NULL;
+ }
+
+}
+
+int des::read_file(istream &hNITF, long desh_length, long des_length){
+
+ int charsread = 0;
+
+ header_length=desh_length;
+
+ charsread += read_verify2(hNITF, m_de, 2 + 25 + 2 + 167);
+
+ //if TRE_OF read teh next two
+ if(strncmp(m_destag,"TRE_OVERFLOW",12)==0) {
+ charsread += read_verify2(hNITF, m_desoflw, 6+3);
+ }
+
+ charsread += read_verify2(hNITF, m_desshl, 4);
+ n_desshl = charptrtolong(m_desshl,4);
+
+ if (n_desshl > 0) {
+ m_desshf = new char[n_desshl];
+ if(m_desshf == NULL) cerr<<"ERROR: could not allocate memory";
+ charsread += read_verify2(hNITF, m_desshf, n_desshl);
+ }
+
+ m_desdata = new char[des_length];
+ charsread += read_verify2(hNITF, m_desdata, des_length);
+ data_length = des_length;
+
+ return charsread;
+}
+
+int des::write_file(ofstream &fNITF){
+
+ fNITF.write(m_de, 2);
+ fNITF.write(m_destag, 25);
+ fNITF.write(m_desver, 2);
+ fNITF.write(m_dessg, 167);
+
+ if(strncmp(m_destag,"TRE_OVERFLOW",12)==0) {
+ fNITF.write(m_desoflw, 6);
+ fNITF.write(m_desitem, 3);
+ }
+
+ fNITF.write( m_desshl, 4);
+
+ if (n_desshl > 0) {
+ fNITF.write(m_desshf, n_desshl);
+ }
+
+ if( m_desdata != NULL) {
+ fNITF.write( m_desdata, data_length);
+ }
+
+ //TODO
+ return 0;
+
+}
+
+string des::get_ld() const {
+ return des_dl;
+}
+
+string des::get_ldsh() const {
+ return des_hl;
+}
diff --git a/conversion/des.h b/conversion/des.h
new file mode 100644
index 0000000..358ad5e
--- /dev/null
+++ b/conversion/des.h
@@ -0,0 +1,67 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+
+#ifndef __RASNITF_DES_H
+#define __RASNITF_DES_H
+
+#include <vector>
+#include <iostream>
+#include <fstream>
+
+namespace RasNITF
+{
+
+class des {
+
+ char m_de[2];
+ char m_destag[25];
+ char m_desver[2];
+ char m_dessg[167];
+ char m_desoflw[6];
+ char m_desitem[3];
+ char m_desshl[4];
+ char *m_desshf;
+ char *m_desdata;
+
+ int header_length;
+ long n_desshl;
+ int data_length;
+ int des_header_length;
+
+ std::string des_hl ;
+ std::string des_dl ;
+
+ public:
+
+ des();
+ ~des();
+ int read_file(std::istream &,long,long);
+ int write_file(std::ofstream &);
+ std::string get_ld() const;
+ std::string get_ldsh() const;
+
+};
+
+}
+#endif
diff --git a/conversion/ecw.cc b/conversion/ecw.cc
new file mode 100644
index 0000000..3035e28
--- /dev/null
+++ b/conversion/ecw.cc
@@ -0,0 +1,339 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#include "raslib/rminit.hh"
+#include "raslib/rmdebug.hh"
+#include "raslib/parseparams.hh"
+#include "raslib/mitera.hh"
+#include "raslib/minterval.hh"
+#include "raslib/primitivetype.hh"
+#include "ecw.hh"
+#include "convertor.hh"
+#include "convfactory.hh"
+
+#ifdef ECW
+#include "ecwmemfs.hh"
+#include "NCSECWClient.h"
+#include "NCSErrors.h"
+
+NCSError memOpen(char *szFileName, void **ppClientData)
+ {
+ RMDBGENTER(5, RMDebug::module_conversion, "ECWMem", "memOpen(" << szFileName << ", fd)");
+ MemoryFileSystem* myMem = new MemoryFileSystem();
+ *ppClientData = (void*)myMem;
+ MemoryFileSystem::m_Error err = MemoryFileSystem::No_Error;
+ err = myMem->open(szFileName);
+ RMDBGEXIT(5, RMDebug::module_conversion, "ECWMem", "memOpen(" << szFileName << ", fd) " << err);
+ if (err == MemoryFileSystem::No_Error)
+ return NCS_SUCCESS;
+ else
+ return NCS_FILE_OPEN_FAILED;
+ }
+
+NCSError memClose(void *pClientData)
+ {
+ RMDBGENTER(5, RMDebug::module_conversion, "ECWMem", "memClose(fd)");
+ MemoryFileSystem::m_Error err = MemoryFileSystem::No_Error;
+ err = ((MemoryFileSystem*)pClientData)->close();
+ if (err == MemoryFileSystem::No_Error)
+ {
+ delete pClientData;
+ RMDBGEXIT(5, RMDebug::module_conversion, "ECWMem", "memClose(fd) OK");
+ return NCS_SUCCESS;
+ }
+ else {
+ RMDBGEXIT(5, RMDebug::module_conversion, "ECWMem", "memClose(fd) Already closed");
+ return NCS_FILE_CLOSE_ERROR;
+ }
+ }
+
+NCSError memRead(void *pClientData, void *pBuffer, UINT32 nLength)
+ {
+ RMDBGENTER(5, RMDebug::module_conversion, "ECWMem", "memRead(fd, buffer, " << nLength << ")");
+ MemoryFileSystem::m_Error err = ((MemoryFileSystem*)pClientData)->read(pBuffer, nLength);
+ if (err == MemoryFileSystem::No_Error)
+ {
+ RMDBGEXIT(5, RMDebug::module_conversion, "ECWMem", "memRead(fd, buffer, " << nLength << ") OK");
+ return NCS_SUCCESS;
+ }
+ else {
+ RMDBGEXIT(5, RMDebug::module_conversion, "ECWMem", "memRead(fd, buffer, " << nLength << ") ERROR");
+ return NCS_FILE_SEEK_ERROR;
+ }
+ }
+
+NCSError memSeek(void *pClientData, UINT64 nOffset)
+ {
+ RMDBGENTER(5, RMDebug::module_conversion, "ECWMem", "memSeek(fd, " << nOffset << ")");
+ MemoryFileSystem::m_Error err = ((MemoryFileSystem*)pClientData)->seek(nOffset);
+ if (err == MemoryFileSystem::No_Error)
+ {
+ RMDBGEXIT(5, RMDebug::module_conversion, "ECWMem", "memSeek(fd, " << nOffset << ") OK");
+ return NCS_SUCCESS;
+ }
+ else {
+ RMDBGEXIT(5, RMDebug::module_conversion, "ECWMem", "memSeek(fd, " << nOffset << ") ERROR");
+ return NCS_FILE_SEEK_ERROR;
+ }
+ }
+
+NCSError memTell(void *pClientData, UINT64 *pOffset)
+ {
+ RMDBGENTER(5, RMDebug::module_conversion, "ECWMem", "memTell(fd, " << *pOffset << ")");
+ *pOffset = ((MemoryFileSystem*)pClientData)->tell();
+ RMDBGEXIT(5, RMDebug::module_conversion, "ECWMem", "memTell(fd, " << *pOffset << ")");
+ return NCS_SUCCESS;
+ }
+#endif
+
+void
+r_Conv_ECW::initECW()
+ {
+ RMDBGONCE(5, RMDebug::module_conversion, "r_Conv_ECW", "initECW()");
+ if(params ==NULL)
+ {
+ params = new r_Parse_Params(2);
+ }
+ }
+
+r_Conv_ECW::r_Conv_ECW(const char* source, const r_Minterval& lengthordomain, const r_Type* tp) throw(r_Error)
+ : r_Convertor(source, lengthordomain, tp, true)
+ {
+ RMDBGONCE(5, RMDebug::module_conversion, "r_Conv_ECW", "r_Conv_ECW(source, " << lengthordomain << ", " << tp->name() << ")");
+ initECW();
+ }
+
+r_Conv_ECW::r_Conv_ECW(const char* source, const r_Minterval& lengthordomain, int tp) throw(r_Error)
+ : r_Convertor(source, lengthordomain, tp)
+ {
+ RMDBGONCE(5, RMDebug::module_conversion, "r_Conv_ECW", "r_Conv_ECW(source, " << lengthordomain << ", " << tp << ")");
+ initECW();
+ }
+
+r_convDesc&
+r_Conv_ECW::convertFrom(const char* options) throw (r_Error)
+ {
+#ifdef ECW
+ RMDBGENTER(5, RMDebug::module_conversion, "r_Conv_ECW", "convertFrom(" << ((options)? options : "NULL") << ")");
+ int windowx = 1000;
+ int windowy = 1000;
+ params->add("windowx", &windowx, r_Parse_Params::param_type_int);
+ params->add("windowy", &windowy, r_Parse_Params::param_type_int);
+ params->process(options);
+ RMDBGMIDDLE(5, RMDebug::module_conversion, "r_Conv_ECW", "window x " << windowx);
+ RMDBGMIDDLE(5, RMDebug::module_conversion, "r_Conv_ECW", "window y " << windowy);
+ switch (desc.baseType)
+ {
+ case ctype_bool:
+ case ctype_char:
+ case ctype_uint8:
+ break;
+ case ctype_rgb:
+ break;
+ default:
+ RMInit::logOut << "r_Conv_ECW unknown base type!" << std::endl;
+ throw r_Error(COMPRESSIONFAILED);
+ }
+ NCSFileView *pNCSFileView = NULL;
+ NCSFileViewFileInfo *pNCSFileInfo = NULL;
+
+ NCSError eError = NCS_SUCCESS;
+ eError = NCSecwSetIOCallbacks(memOpen, memClose, memRead, memSeek, memTell);
+ if (eError != NCS_SUCCESS)
+ {
+ RMInit::logOut << "Error = " << NCSGetErrorText(eError) << std::endl;
+ throw r_Error(COMPRESSIONFAILED);
+ }
+ UINT8 **p_p_output_line = NULL;
+ UINT8 *p_output_buffer = NULL;
+ UINT32 x_size = 0;
+ UINT32 y_size = 0;
+ UINT32 number_x = 0;
+ UINT32 number_y = 0;
+ UINT32 start_x = 0;
+ UINT32 start_y = 0;
+ UINT32 end_x = 0;
+ UINT32 end_y = 0;
+ UINT32 band = 0;
+ UINT32 nBands = 0;
+ MemoryFileSystem::memorySrc = desc.src;
+ MemoryFileSystem::memorySrcLength = desc.srcInterv[0].high() - desc.srcInterv[0].low() + 1;
+ eError = NCScbmOpenFileView((char*)MemoryFileSystem::memorySrcName, &pNCSFileView, NULL);
+
+ if (eError != NCS_SUCCESS)
+ {
+ RMInit::logOut << "Error = " << NCSGetErrorText(eError) << std::endl;
+ throw r_Error(COMPRESSIONFAILED);
+ }
+
+ NCScbmGetViewFileInfo(pNCSFileView, &pNCSFileInfo);
+ x_size = pNCSFileInfo->nSizeX;
+ y_size = pNCSFileInfo->nSizeY;
+ nBands = pNCSFileInfo->nBands;
+ RMDBGMIDDLE(5, RMDebug::module_conversion, "r_Conv_ECW", "image : " << x_size << " x " << y_size << ", " << nBands << " bands");
+
+ /* Have to set up the band list. Compatible with ER Mapper's method.*/
+ /* In this example we always request all bands.*/
+ UINT32* band_list = new UINT32[nBands];
+ for( band = 0; band < nBands; band++ )
+ band_list[band] = band;
+ size_t typeLength = nBands;
+ switch (desc.baseType)
+ {
+ case ctype_bool:
+ case ctype_char:
+ case ctype_uint8:
+ if (nBands != 1)
+ {
+ RMInit::logOut << "r_Conv_ECW conversion of base types bot supported" << std::endl;
+ throw r_Error(COMPRESSIONFAILED);
+ }
+ break;
+ case ctype_rgb:
+ if (nBands != 3)
+ {
+ RMInit::logOut << "r_Conv_ECW conversion of base types bot supported" << std::endl;
+ throw r_Error(COMPRESSIONFAILED);
+ }
+ break;
+ default:
+ RMInit::logOut << "r_Conv_ECW there is a really bad error in your compiler" << std::endl;
+ throw r_Error(10000);
+ break;
+ }
+ start_x = 0;
+ start_y = 0;
+ end_x = x_size - 1;
+ end_y = y_size - 1;
+ number_x = x_size;
+ number_y = y_size;
+
+ windowx = number_x;
+ windowy = number_y;
+
+ r_Minterval imageDomain(2);
+ imageDomain << r_Sinterval((r_Range)0, (r_Range)number_x - 1);
+ imageDomain << r_Sinterval((r_Range)0, (r_Range)number_y - 1);
+ RMDBGMIDDLE(5, RMDebug::module_conversion, "r_Conv_ECW", "image domain " << imageDomain << ", type length " << typeLength << " bands");
+ char* image = (char*)mystore.storage_alloc(number_x * number_y * typeLength);
+ //char* image = new char[number_x * number_y * typeLength];
+ memset(image, 0, number_x * number_y * typeLength);
+ r_Minterval maxDom(2);
+ maxDom << r_Sinterval((r_Range)0, (r_Range)1000 - 1);
+ maxDom << r_Sinterval((r_Range)0, (r_Range)1000 - 1);
+ r_MiterArea dom_iter(&maxDom, &imageDomain);
+ r_Minterval iterArea(2);
+ while (!dom_iter.isDone())
+ {
+ iterArea = dom_iter.nextArea();
+ start_x = iterArea[0].low();
+ start_y = iterArea[1].low();
+ end_x = iterArea[0].high();
+ end_y = iterArea[1].high();
+ number_x = iterArea[0].get_extent();
+ number_y = iterArea[1].get_extent();
+ RMDBGMIDDLE(5, RMDebug::module_conversion, "r_Conv_ECW", "current " << start_x << ":" << end_x << "," << start_y << ":" << end_y << " window " << number_x << " x " << number_y);
+ eError = NCScbmSetFileView(pNCSFileView, nBands, band_list, start_x, start_y, end_x, end_y, number_x, number_y);
+ if( eError != NCS_SUCCESS)
+ {
+ RMInit::logOut << "Error while setting file view to " << nBands << " bands, [" << start_x << ":" << end_x << "," << start_y << ":" << end_y << "], window size " << number_x << " x " << number_y << " pixel" << std::endl;
+ RMInit::logOut << "Error = " << NCSGetErrorText(eError) << std::endl;
+ NCScbmCloseFileViewEx(pNCSFileView, TRUE);
+ delete [] band_list;
+ mystore.storage_free(image);
+ throw r_Error(COMPRESSIONFAILED);
+ }
+
+ p_output_buffer = new UINT8[number_x * nBands];
+ p_p_output_line = new UINT8*[nBands];
+
+ for(band = 0; band < nBands; band++ )
+ p_p_output_line[band] = p_output_buffer + (band * number_x);
+
+ /*
+ ** Read each line of the compressed file
+ */
+ for( UINT32 line = 0; line < number_y; line++ )
+ {
+ NCSEcwReadStatus eReadStatus = NCScbmReadViewLineBIL( pNCSFileView, p_p_output_line);
+ if (eReadStatus != NCSECW_READ_OK)
+ {
+ RMInit::logOut << "Read line error at line " << line << std::endl;
+ RMInit::logOut << "Status code " << eReadStatus << std::endl;
+ NCScbmCloseFileViewEx(pNCSFileView, TRUE);
+ delete [] band_list;
+ delete [] p_p_output_line;
+ delete [] p_output_buffer;
+ mystore.storage_free(image);
+ throw r_Error(COMPRESSIONFAILED);
+ }
+ for (int b = 0; b < nBands; b++)
+ {
+ for (int l = 0; l < number_x; l++)
+ {
+ image[(l + iterArea[0].low()) * windowy * typeLength + (line + iterArea[1].low()) * typeLength + b] = p_p_output_line[b][l];
+ }
+ }
+ }
+ delete [] p_p_output_line;
+ delete [] p_output_buffer;
+ RMDBGMIDDLE(5, RMDebug::module_conversion, "r_Conv_ECW", "read done");
+ }
+ NCScbmCloseFileViewEx(pNCSFileView, TRUE);
+ delete [] band_list;
+ desc.dest = (char*)image;
+ desc.destInterv = imageDomain;
+ desc.destType = get_external_type(desc.baseType);
+ return desc;
+#else
+ RMDBGENTER(5, RMDebug::module_conversion, "r_Conv_ECW", "convertFrom(" << options << ") NOT COMPILED");
+ RMInit::logOut << "r_Conv_ECW::convertFrom(" << options << ") ecw support not compiled in" << std::endl;
+ throw r_Error(COMPRESSIONFAILED);
+#endif
+ }
+
+r_convDesc&
+r_Conv_ECW::convertTo(const char* options) throw (r_Error)
+ {
+ RMInit::logOut << "r_Conv_ECW::convertTo(" << options << ") compression not supported" << std::endl;
+ throw r_Error(COMPRESSIONFAILED);
+ }
+
+const char*
+r_Conv_ECW::get_name() const
+ {
+ return get_name_from_data_format(r_ECW);
+ }
+
+r_Data_Format
+r_Conv_ECW::get_data_format() const
+ {
+ return r_ECW;
+ }
+
+r_Convertor*
+r_Conv_ECW::clone() const
+ {
+ return new r_Conv_ECW(desc.src, desc.srcInterv, desc.srcType);
+ }
+
diff --git a/conversion/ecw.hh b/conversion/ecw.hh
new file mode 100644
index 0000000..d418809
--- /dev/null
+++ b/conversion/ecw.hh
@@ -0,0 +1,78 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: ecw.hh
+ *
+ * MODULE: conversion
+ *
+ * CLASSES: r_Conv_ECW
+ *
+ * COMMENTS:
+ * Provides interface to convert data from ECW to r_Array
+ *
+*/
+
+#ifndef _R_CONV_ECW_HH_
+#define _R_CONV_ECW_HH_
+#include "conversion/convertor.hh"
+
+//@ManMemo: Module {\bf conversion}
+
+/*@Doc:
+ ECW convertor class.
+
+ Supported parameters are
+
+ \begin{tabular}{lcl}
+ {\tt windowx} && uint && maximum number of colums to convert in one ecw call, default 1000\\
+ {\tt windowy} && uint && maximum number of lines to convert in one ecw call, default 1000\\
+ \end{tabular}
+*/
+
+
+class r_Conv_ECW : public r_Convertor
+ {
+ public:
+ r_Conv_ECW(const char* source, const r_Minterval& lengthordomain, const r_Type* tp) throw(r_Error);
+
+ r_Conv_ECW(const char* source, const r_Minterval& lengthordomain, int tp) throw(r_Error);
+
+ r_convDesc& convertFrom(const char* options = NULL) throw (r_Error);
+
+ r_convDesc& convertTo(const char* options = NULL) throw (r_Error);
+
+ const char* get_name() const;
+
+ r_Data_Format get_data_format() const;
+
+ r_Convertor* clone() const;
+
+
+ private:
+ void initECW();
+
+ };
+
+#endif
+
+
diff --git a/conversion/ecwmemfs.cc b/conversion/ecwmemfs.cc
new file mode 100644
index 0000000..07357d6
--- /dev/null
+++ b/conversion/ecwmemfs.cc
@@ -0,0 +1,157 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#include "ecwmemfs.hh"
+#include <fstream>
+#include <algorithm>
+#include "raslib/rminit.hh"
+#include "raslib/rmdebug.hh"
+
+const char*
+MemoryFileSystem::memorySrc = NULL;
+
+r_Bytes
+MemoryFileSystem::memorySrcLength = 0;
+
+const char*
+MemoryFileSystem::memorySrcName = "memory.src";
+
+MemoryFileSystem::MemoryFileSystem()
+ : current(NULL),
+ source(NULL),
+ length(0),
+ closed(false),
+ owner(true)
+ {
+ RMDBGONCE(5, RMDebug::module_conversion, "MemoryFileSystem", "MemoryFileSystem()");
+ }
+
+MemoryFileSystem::m_Error
+MemoryFileSystem::open(const char* memorySource, r_Bytes mSize)
+ {
+ RMDBGONCE(5, RMDebug::module_conversion, "MemoryFileSystem", "open(source, " << mSize << ")");
+ owner = false;
+ length = mSize;
+ source = (char*)memorySource;
+ current = source;
+ return No_Error;
+ }
+
+MemoryFileSystem::m_Error
+MemoryFileSystem::open(const char* fileName)
+ {
+ owner = true;
+ RMDBGENTER(5, RMDebug::module_conversion, "MemoryFileSystem", "open(" << fileName << ")");
+ if (fileName == memorySrcName)
+ {
+ MemoryFileSystem::m_Error err = open(memorySrc, memorySrcLength);
+ RMDBGEXIT(5, RMDebug::module_conversion, "MemoryFileSystem", "open(" << fileName << ") " << err);
+ return err;
+ }
+ else {
+ std::ifstream f;
+ f.open(fileName);
+ if (!f.is_open())
+ {
+ RMInit::logOut << "MemoryFileSystem::open(" << fileName << ") could not open file" << std::endl;
+ RMDBGEXIT(5, RMDebug::module_conversion, "MemoryFileSystem", "open(" << fileName << ") " << Error);
+ return Error;
+ }
+ f.seekg(0, std::ios::end);
+ std::ios::pos_type end = f.tellg();
+ RMDBGMIDDLE(5, RMDebug::module_conversion, "MemoryFileSystem", "size " << end);
+ length = end;
+ source = new char[end];
+ current = source;
+ memset(source, 0, end);
+ f.seekg(0, std::ios::beg);
+ f.read(source, end);
+ f.close();
+ RMDBGEXIT(5, RMDebug::module_conversion, "MemoryFileSystem", "open(" << fileName << ") " << No_Error);
+ return No_Error;
+ }
+ }
+
+MemoryFileSystem::m_Error
+MemoryFileSystem::close()
+ {
+ RMDBGENTER(5, RMDebug::module_conversion, "MemoryFileSystem", "close()");
+ if (!closed)
+ {
+ if (owner)
+ {
+ delete [] source;
+ }
+ source = NULL;
+ current = NULL;
+ length = 0;
+ RMDBGEXIT(5, RMDebug::module_conversion, "MemoryFileSystem", "close() " << No_Error);
+ return No_Error;
+ }
+ else {
+ RMDBGEXIT(5, RMDebug::module_conversion, "MemoryFileSystem", "close() " << Error);
+ return Error;
+ }
+ }
+
+MemoryFileSystem::~MemoryFileSystem()
+ {
+ RMDBGONCE(5, RMDebug::module_conversion, "MemoryFileSystem", "~MemoryFileSystem()");
+ close();
+ }
+
+MemoryFileSystem::m_Error
+MemoryFileSystem::read(void* buffer, r_Bytes bSize)
+ {
+ RMDBGENTER(5, RMDebug::module_conversion, "MemoryFileSystem", "read(buffer, " << bSize << ")");
+ bSize = std::min(bSize, length - (current - source));
+ RMDBGMIDDLE(5, RMDebug::module_conversion, "MemoryFileSystem", "reading " << bSize);
+ memcpy(buffer, current, bSize);
+ current += bSize;
+ RMDBGEXIT(5, RMDebug::module_conversion, "MemoryFileSystem", "read(buffer, " << bSize << ") " << No_Error);
+ return No_Error;
+ }
+
+unsigned long long
+MemoryFileSystem::tell()
+ {
+ RMDBGONCE(5, RMDebug::module_conversion, "MemoryFileSystem", "tell() " << (current - source));
+ return current - source;
+ }
+
+MemoryFileSystem::m_Error
+MemoryFileSystem::seek(unsigned long long offset)
+ {
+ RMDBGENTER(5, RMDebug::module_conversion, "MemoryFileSystem", "seek(" << offset << ")");
+ if (offset > length)
+ {
+ RMDBGEXIT(5, RMDebug::module_conversion, "MemoryFileSystem", "seek(" << offset << ") (length " << length << ") " << Error);
+ return Error;
+ }
+ else {
+ current = offset + source;
+ RMDBGEXIT(5, RMDebug::module_conversion, "MemoryFileSystem", "seek(" << offset << ") " << No_Error);
+ return No_Error;
+ }
+ }
+
diff --git a/conversion/ecwmemfs.hh b/conversion/ecwmemfs.hh
new file mode 100644
index 0000000..f61ed10
--- /dev/null
+++ b/conversion/ecwmemfs.hh
@@ -0,0 +1,84 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#ifndef _ECWMEMFS_HH_
+#define _ECWMEMFS_HH_
+
+#include "raslib/mddtypes.hh"
+
+class MemoryFileSystem
+ {
+ public:
+ enum m_Error
+ {
+ No_Error = 0,
+ Error = 1
+ };
+
+ MemoryFileSystem();
+
+ ///open file an read into memory - completely
+ m_Error open(const char* fileName);
+
+ ///use this memory chunk with mSize bytes length
+ m_Error open(const char* memorySource, r_Bytes mSize);
+
+ ///close and deinitialise (delete only my own data)
+ m_Error close();
+
+ ///call close
+ ~MemoryFileSystem();
+
+ ///read bSize bytes into buffer, only if bSize bytes are available
+ m_Error read(void* buffer, r_Bytes bSize);
+
+ ///get current position
+ unsigned long long tell();
+
+ ///go to offset bytes from begining of memory
+ m_Error seek(unsigned long long offset);
+
+ ///if you use open(const* char) and the pointer is memorySrcName then no file will be read but this pointer
+ static const char* memorySrc;
+
+ ///file names which point to this will not read from file system but from memorySrc
+ static const char* memorySrcName;
+
+ ///the length of the memorySrc chunk must be specified in memoryLength
+ static r_Bytes memorySrcLength;
+
+ private:
+
+ ///my memory block
+ char* source;
+ ///my current position
+ char* current;
+ ///am i closed
+ bool closed;
+ ///do i own my memory data
+ bool owner;
+ ///how long is my memory data
+ r_Bytes length;
+ };
+
+#endif
diff --git a/conversion/graphic.cc b/conversion/graphic.cc
new file mode 100644
index 0000000..1ba5bda
--- /dev/null
+++ b/conversion/graphic.cc
@@ -0,0 +1,148 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#include <iostream>
+#include <fstream>
+#include <cstring>
+
+#include "graphic.h"
+#include "nitf.h"
+#include "utilities.h"
+
+using namespace std;
+using namespace RasNITF;
+
+graphic::graphic()
+{
+ m_graphic_data = NULL;
+ m_sxshd = NULL;
+}
+
+graphic::~graphic()
+{
+ if(m_graphic_data != NULL)
+ delete m_graphic_data;
+ m_graphic_data = NULL;
+
+ if(m_sxshd != NULL)
+ delete m_sxshd;
+ m_sxshd = NULL;
+
+}
+
+int graphic::read_file(istream &hNITF, long gh_length, long graph_length)
+{
+ int charsread = 0;
+ long start_position = 0;
+
+ header_length = gh_length;
+
+ // here find where are we relative to the begining
+ start_position = hNITF.tellg();
+
+ // here read the header data
+ charsread += read_verify2(hNITF,m_sy, 2+10+20+1+2+11+2+20+2+8+4+1+8+43+1+40+1+8+15+1+1+13+3+3+10+10+1+10+2);
+
+ charsread += read_verify2(hNITF, m_sxshdl, 5);
+
+ n_sxshdl = charptrtolong(m_sxshdl, 5);
+
+ if (n_sxshdl > 0) {
+ n_sxshdl -= 3;
+ read_verify2(hNITF, m_sxsofl, 3);
+ m_sxshd = new char[n_sxshdl - 3];
+ if(m_sxshd == NULL) cerr<<"ERROR: could not allocate memory";
+ read_verify2(hNITF, m_sxshd, n_sxshdl);
+ n_sxshdl += 3;
+
+ }
+
+ // check if we are where we should be
+
+ if( ((long)hNITF.tellg()) != (start_position + gh_length)) {
+ cerr << "Error in graph.cpp";
+ exit(2);
+ }
+
+ // store the text data
+
+ m_graphic_data = new char[graph_length];
+ if(m_graphic_data == NULL) cerr<<"ERROR: could not allocate memory";
+ data_length = read_verify2(hNITF, m_graphic_data, graph_length);
+ return charsread;
+}
+
+int graphic::write_file(ofstream &fNITF){
+
+ fNITF.write( m_sy, 2);
+ fNITF.write( m_sid, 10);
+ fNITF.write( m_sname, 20);
+ fNITF.write( m_ssclas, 1);
+ fNITF.write( m_ssclsy, 2);
+ fNITF.write( m_sscode, 11);
+ fNITF.write( m_ssctlh, 2);
+ fNITF.write( m_ssrel, 20);
+ fNITF.write( m_ssdctp, 2);
+ fNITF.write( m_ssdcdt, 8);
+ fNITF.write( m_ssdcxm, 4);
+ fNITF.write( m_ssdg, 1);
+ fNITF.write( m_ssdgdt, 8);
+ fNITF.write( m_sscltx, 43);
+ fNITF.write( m_sscatp, 1);
+ fNITF.write( m_sscaut, 40);
+ fNITF.write( m_sscrsn, 1);
+ fNITF.write( m_sssrdt, 8);
+ fNITF.write( m_ssctln, 15);
+ fNITF.write( m_encryp, 1);
+ fNITF.write( m_stype, 1);
+ fNITF.write( m_sres1, 13);
+ fNITF.write( m_sdlvl, 3);
+ fNITF.write( m_salvl, 3);
+ fNITF.write( m_sloc, 10);
+ fNITF.write( m_sbnd1, 10);
+ fNITF.write( m_scolor, 1);
+ fNITF.write( m_sbnd2, 10);
+ fNITF.write( m_sres2, 2);
+ fNITF.write(m_sxshdl, 5);
+
+ if (n_sxshdl > 0) {
+ fNITF.write(m_sxsofl, 3);
+ fNITF.write(m_sxshd, n_sxshdl - 3);
+ }
+
+ if( m_graphic_data != NULL) {
+ fNITF.write( m_graphic_data, data_length);
+ }
+
+ //TODO change to charswritten
+ return 0;
+
+}
+
+string graphic::get_ls() {
+ return graphic_dl;
+}
+
+string graphic::get_lssh() {
+ return graphic_hl;
+}
diff --git a/conversion/graphic.h b/conversion/graphic.h
new file mode 100644
index 0000000..e1662e2
--- /dev/null
+++ b/conversion/graphic.h
@@ -0,0 +1,90 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+
+#ifndef __GRAPHIC_H_INCLUDED
+#define __GRAPHIC_H_INCLUDED
+
+#include<vector>
+#include<iostream>
+#include<fstream>
+
+namespace RasNITF
+{
+
+class graphic{
+ private:
+ char m_sy[2];
+ char m_sid[10];
+ char m_sname[20];
+ char m_ssclas[1];
+ char m_ssclsy[2];
+ char m_sscode[11];
+ char m_ssctlh[2];
+ char m_ssrel[20];
+ char m_ssdctp[2];
+ char m_ssdcdt[8];
+ char m_ssdcxm[4];
+ char m_ssdg[1];
+ char m_ssdgdt[8];
+ char m_sscltx[43];
+ char m_sscatp[1];
+ char m_sscaut[40];
+ char m_sscrsn[1];
+ char m_sssrdt[8];
+ char m_ssctln[15];
+ char m_encryp[1];
+ char m_stype[1];
+ char m_sres1[13];
+ char m_sdlvl[3];
+ char m_salvl[3];
+ char m_sloc[10];
+ char m_sbnd1[10];
+ char m_scolor[1];
+ char m_sbnd2[10];
+ char m_sres2[2];
+ char m_sxshdl[5];
+ char m_sxsofl[3];
+ char* m_sxshd;
+ char *m_graphic_data;
+
+ int header_length;
+ int data_length;
+ int n_sxshdl;
+ int n_sxsofl;
+
+ std::string graphic_hl ;
+ std::string graphic_dl ;
+
+ public:
+ graphic();
+ ~graphic();
+ int read_file(std::istream&, long, long);
+ int write_file(std::ofstream &);
+ std::string get_ls();
+ std::string get_lssh();
+};
+
+}
+
+#endif
diff --git a/conversion/hdf.cc b/conversion/hdf.cc
new file mode 100644
index 0000000..5effb10
--- /dev/null
+++ b/conversion/hdf.cc
@@ -0,0 +1,386 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: hdf.cc
+ *
+ * MODULE: conversion
+ *
+ * CLASSES: r_Conv_HDF
+ *
+ * COMMENTS:
+ *
+ * Provides functions to convert data to HDF SD and back.
+ *
+*/
+
+/* Added by Sorin Stancu-Mara. Definition clashed for type int8, define in both
+* /usr/include/hdf.h and in /usr/include/tiff.h
+* This will supress the tiff.h definition.
+* Both definitions are similar
+*/
+#define HAVE_INT8
+
+#include "conversion/hdf.hh"
+#include "raslib/error.hh"
+#include "raslib/rminit.hh"
+#include "raslib/parseparams.hh"
+#include "raslib/primitivetype.hh"
+
+
+#ifdef HAVE_HDF_H
+ #include "hdf.h"
+#elif HAVE_HDF_HDF_H
+ #include "hdf/hdf.h"
+#else
+ #error "No hdf.h header available."
+#endif
+
+#ifdef HAVE_MFHDF_H
+ #include "mfhdf.h"
+#elif HAVE_HDF_MFHDF_H
+ #include "hdf/mfhdf.h"
+#else
+ #error "No mfhdf.h header available."
+#endif
+
+#include <stdio.h>
+#include <iostream>
+
+
+
+const r_Convertor::convert_string_t r_Conv_HDF::compNames[] = {
+ {"none", COMP_CODE_NONE},
+ {"rle", COMP_CODE_RLE},
+ {"huffman", COMP_CODE_SKPHUFF},
+ {"deflate", COMP_CODE_DEFLATE},
+ {NULL, COMP_CODE_NONE}
+};
+
+// Buffer used for switching the majorness (column <--> row) of the array data
+const int r_Conv_HDF::MaxSwapBufferSize = 0x10000;
+
+
+
+
+void r_Conv_HDF::initHDF( void )
+{
+ compType = NULL;
+ quality = 80;
+ skiphuff = 0;
+
+ if (params == NULL)
+ params = new r_Parse_Params;
+
+ params->add("comptype", &compType, r_Parse_Params::param_type_string);
+ params->add("quality", &quality, r_Parse_Params::param_type_int);
+ params->add("skiphuff", &skiphuff, r_Parse_Params::param_type_int);
+}
+
+
+int r_Conv_HDF::getHDFtype(int intType, int &size)
+{
+ int result=0;
+
+ switch (intType)
+ {
+ case ctype_int8: result = DFNT_CHAR8; size = 1; break;
+ case ctype_uint8:
+ case ctype_char:
+ case ctype_bool: result = DFNT_UCHAR8; size = 1; break;
+ case ctype_int16: result = DFNT_INT16; size = 2; break;
+ case ctype_uint16: result = DFNT_UINT16; size = 2; break;
+ case ctype_int32: result = DFNT_INT32; size = 4; break;
+ case ctype_uint32: result = DFNT_UINT32; size = 4; break;
+ case ctype_int64: result = DFNT_INT64; size = 8; break;
+ case ctype_uint64: result = DFNT_UINT64; size = 8; break;
+ case ctype_float32: result = DFNT_FLOAT32; size = 4; break;
+ case ctype_float64: result = DFNT_FLOAT64; size = 8; break;
+ default: result = 0; size = 1; break;
+ }
+ return result;
+}
+
+
+int r_Conv_HDF::getIntType( int hdfType, int &size )
+{
+ int result=0;
+
+ switch (hdfType)
+ {
+ case DFNT_CHAR8: result = ctype_int8; size = 1; break;
+ case DFNT_UCHAR8: result = ctype_uint8; size = 1; break;
+ case DFNT_INT16: result = ctype_int16; size = 2; break;
+ case DFNT_UINT16: result = ctype_uint16; size = 2; break;
+ case DFNT_INT32: result = ctype_int32; size = 4; break;
+ case DFNT_UINT32: result = ctype_uint32; size = 4; break;
+ case DFNT_INT64: result = ctype_int64; size = 8; break;
+ case DFNT_UINT64: result = ctype_uint64; size = 8; break;
+ case DFNT_FLOAT32: result = ctype_float32; size = 4; break;
+ case DFNT_FLOAT64: result = ctype_float64; size = 8; break;
+ default: result = ctype_void; size = 1; break;
+ }
+ return result;
+}
+
+
+
+r_Conv_HDF::r_Conv_HDF(const char *src, const r_Minterval &interv, const r_Type *tp) throw(r_Error)
+: r_Convertor(src, interv, tp, true)
+{
+ initHDF();
+
+ if (tp->isStructType())
+ {
+ RMInit::logOut << "r_Conv_HDF::r_Conv_HDF(): structured types not supported." << endl;
+ throw r_Error(r_Error::r_Error_General);
+ }
+}
+
+
+
+r_Conv_HDF::r_Conv_HDF(const char *src, const r_Minterval &interv, int tp) throw(r_Error)
+: r_Convertor(src, interv, tp)
+{
+ initHDF();
+}
+
+
+
+r_Conv_HDF::~r_Conv_HDF(void)
+{
+ if (compType != NULL)
+ {
+ delete [] compType;
+ compType = NULL;
+ }
+}
+
+
+
+r_convDesc &r_Conv_HDF::convertTo( const char *options ) throw(r_Error)
+{
+ char name[256];
+ int32 handle=0, sds_id=0, rank=0;
+ comp_coder_t comp_type=COMP_CODE_NONE;
+ int32 *dimsizes=NULL, *start=NULL;
+ size_t filesize=0;
+ int i=0, j=0;
+ FILE *fp=NULL;
+ comp_info c_info;
+
+ strncpy(name, tmpnam(NULL), 256);
+ //name = "testfile.hdf";
+
+ if ((handle = SDstart(name, DFACC_CREATE)) == FAIL)
+ {
+ RMInit::logOut << "r_Conv_HDF::convertTo(): unable to open output file." << endl;
+ throw r_Error(r_Error::r_Error_General);
+ }
+ rank = desc.srcInterv.dimension();
+
+ dimsizes = new int32[rank]; start = new int32[rank];
+ datatype = getHDFtype(desc.baseType, datasize);
+
+ for (i=0; i<rank; i++)
+ {
+ dimsizes[i] = desc.srcInterv[i].high() - desc.srcInterv[i].low() + 1;
+ start[i] = 0;
+ }
+
+ if ((sds_id = SDcreate(handle, "RasDaMan object", datatype, rank, dimsizes)) == FAIL)
+ {
+ RMInit::logOut << "r_Conv_HDF::convertTo(): unable to create object." << endl;
+ SDend(handle); remove(name);
+ throw r_Error(r_Error::r_Error_General);
+ }
+ SDsetfillmode(sds_id, SD_NOFILL);
+
+ params->process(options);
+
+ comp_type = COMP_CODE_DEFLATE;
+ if (compType != NULL)
+ {
+ for (i=0; compNames[i].key != NULL; i++)
+ {
+ if (strcasecmp(compNames[i].key, compType) == 0)
+ {
+ comp_type = (comp_coder_t)compNames[i].id;
+ break;
+ }
+ }
+ if (compNames[i].key == NULL)
+ {
+ RMInit::logOut << "r_Conv_HDF::convertTo(): unsupported compression type " << compType << endl;
+ }
+ }
+ c_info.skphuff.skp_size = skiphuff;
+ c_info.deflate.level = quality;
+
+ SDsetcompress(sds_id, comp_type, &c_info);
+
+ SDwritedata(sds_id, start, NULL, dimsizes, (VOIDP)(desc.src));
+
+ delete [] dimsizes; dimsizes=NULL;
+ delete [] start; start=NULL;
+
+ SDendaccess(sds_id);
+
+ SDend(handle);
+
+ if ((fp = fopen(name, "rb")) == NULL)
+ {
+ RMInit::logOut << "r_Conv_HDF::convertTo(): unable to read back file." << endl;
+ throw r_Error(r_Error::r_Error_General);
+ }
+ fseek(fp, 0, SEEK_END);
+ filesize = ftell(fp);
+
+ desc.destInterv = r_Minterval(1);
+ desc.destInterv << r_Sinterval((r_Range)0, (r_Range)filesize - 1);
+
+ if ((desc.dest = (char*)mystore.storage_alloc(filesize)) == NULL)
+ {
+ RMInit::logOut << "r_Conv_HDF::convertTo(): out of memory error" << endl;
+ fclose(fp);
+ throw r_Error(MEMMORYALLOCATIONERROR);
+ }
+ fseek(fp, 0, SEEK_SET);
+ fread(desc.dest, 1, filesize, fp);
+
+ fclose(fp);
+
+ remove(name);
+
+ // Result is just a bytestream
+ desc.destType = r_Type::get_any_type("char");
+
+ return desc;
+}
+
+
+
+r_convDesc &r_Conv_HDF::convertFrom(const char *options) throw(r_Error)
+{
+ char name[256];
+ int32 handle=0, sds_id=0, rank=0, dtype=0, numattr=0, array_size=0;
+ int32 dimsizes[MAX_VAR_DIMS];
+ int32 *start=NULL;
+ int dsize=0;
+ size_t filesize=0;
+ FILE *fp=NULL;
+ int i=0;
+
+ if (desc.srcInterv.dimension() != 1)
+ {
+ RMInit::logOut << "r_Conv_HDF::convertFrom(): source data must be a bytestream!" << endl;
+ throw r_Error(r_Error::r_Error_General);
+ }
+
+ strncpy(name, tmpnam(NULL), 256);
+ if ((fp = fopen(name, "wb")) == NULL)
+ {
+ RMInit::logOut << "r_Conv_HDF::convertFrom(): unable to write temporary file!" << endl;
+ throw r_Error(r_Error::r_Error_General);
+ }
+ filesize = desc.srcInterv[0].high() - desc.srcInterv[0].low() + 1;
+ if ((i = fwrite(desc.src, 1, filesize, fp)) != filesize)
+ {
+ RMInit::logOut << "r_Conv_HDF::convertFrom(): error writing to temporary file ("
+ << i << " / " << filesize << ')' << endl;
+ throw r_Error(r_Error::r_Error_General);
+ }
+ fclose(fp);
+
+ if ((handle = SDstart(name, DFACC_READ)) == FAIL)
+ {
+ RMInit::logOut << "r_Conv_HDF::convertFrom(): can't read temporary file!" << endl;
+ throw r_Error(r_Error::r_Error_General);
+ }
+ // Only read the first object in the file
+ if ((sds_id = SDselect(handle, 0)) == FAIL)
+ {
+ RMInit::logOut << "r_Conv_HDF::convertFrom(): unable to open first object" << endl;
+ SDend(handle); remove(name);
+ throw r_Error(r_Error::r_Error_General);
+ }
+
+ SDgetinfo(sds_id, NULL, &rank, dimsizes, &dtype, &numattr);
+
+ // Ignore native datatype flag
+ dtype &= ~DFNT_NATIVE;
+
+ desc.destType = get_external_type(getIntType(dtype, dsize));
+
+ start = new int32[rank];
+ desc.destInterv = r_Minterval(rank);
+ array_size = (int32)dsize;
+ for (i=0; i<rank; i++)
+ {
+ desc.destInterv << r_Sinterval(r_Range(0), r_Range(dimsizes[i]-1));
+ array_size *= dimsizes[i];
+ start[i] = 0;
+ }
+
+ if ((desc.dest = (char*)mystore.storage_alloc(array_size)) == NULL)
+ {
+ RMInit::logOut << "r_Conv_HDF::convertFrom(): out of memory error!" << endl;
+ SDend(handle); remove(name);
+ throw r_Error(MEMMORYALLOCATIONERROR);
+ }
+
+ if (SDreaddata(sds_id, start, NULL, dimsizes, (VOIDP)desc.dest) == FAIL)
+ {
+ RMInit::logOut << "r_Conv_HDF::convertFrom(): error reading data" << endl;
+ SDend(handle); remove(name);
+ throw r_Error(r_Error::r_Error_General);
+ }
+
+ delete [] start; start=NULL;
+
+ SDendaccess(sds_id);
+
+ SDend(handle);
+
+ remove(name);
+
+ return desc;
+}
+
+
+
+const char *r_Conv_HDF::get_name( void ) const
+{
+ return format_name_hdf;
+}
+
+
+r_Data_Format r_Conv_HDF::get_data_format( void ) const
+{
+ return r_HDF;
+}
+
+
+r_Convertor *r_Conv_HDF::clone( void ) const
+{
+ return new r_Conv_HDF(desc.src, desc.srcInterv, desc.baseType);
+}
diff --git a/conversion/hdf.hh b/conversion/hdf.hh
new file mode 100644
index 0000000..0546811
--- /dev/null
+++ b/conversion/hdf.hh
@@ -0,0 +1,104 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: hdf.hh
+ *
+ * MODULE: conversion
+ *
+ * CLASSES: r_Conv_HDF
+ *
+ * COMMENTS:
+ *
+ * Provides interface to convert data to other formats.
+ *
+*/
+
+#ifndef _R_CONV_HDF_HH_
+#define _R_CONV_HDF_HH_
+
+#include "conversion/convertor.hh"
+
+
+//@ManMemo: Module {\bf conversion}
+
+/*@Doc:
+ HDF convertor class.
+
+ Supported parameters are
+
+ \begin{tabular}{lcl}
+ comptype && string && the compression type to use (see below)\\
+ quality && int && quality parameter for JPEG compression\\
+ skiphuff && int && skipping parameter for Huffman coding\\
+ \end{tabular}
+
+ The compression type defaults to deflate but may be one of the
+ following
+
+ \begin{tabular}{ll}
+ none && no compression\\
+ rle && Run Length Coding\\
+ huffman && Huffman coding\\
+ deflate && ZIP deflate\\
+ \end{tabular}
+
+*/
+class r_Conv_HDF : public r_Convertor
+{
+ public:
+ /// constructor using an r_Type object. Exception if the type isn't atomic.
+ r_Conv_HDF( const char *src, const r_Minterval &interv, const r_Type *tp) throw(r_Error);
+ /// constructor using convert_type_e shortcut
+ r_Conv_HDF( const char *src, const r_Minterval &interv, int tp ) throw(r_Error);
+ /// destructor
+ ~r_Conv_HDF( void );
+
+ /// convert to HDF
+ virtual r_convDesc &convertTo( const char *options=NULL ) throw(r_Error);
+ /// convert from HDF
+ virtual r_convDesc &convertFrom( const char *options=NULL ) throw(r_Error);
+ /// cloning
+ virtual r_Convertor *clone( void ) const;
+ /// identification
+ virtual const char *get_name( void ) const;
+ virtual r_Data_Format get_data_format( void ) const;
+
+
+ private:
+ /// init HDF module
+ void initHDF( void );
+ /// translate an internal type into an HDF type and return the size.
+ static int getHDFtype(int intType, int &size);
+ /// translate an HDF type into an internal type and return the size
+ static int getIntType(int hdfType, int &size);
+ /// variables
+ int datatype, datasize;
+ /// parameters
+ int skiphuff;
+ int quality;
+ char *compType;
+ static const convert_string_t compNames[];
+ static const int MaxSwapBufferSize;
+};
+
+#endif
diff --git a/conversion/image.cc b/conversion/image.cc
new file mode 100644
index 0000000..95018d6
--- /dev/null
+++ b/conversion/image.cc
@@ -0,0 +1,1040 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#ifdef __GNUG__
+#include "raslib/template_inst.hh"
+#endif
+#endif
+
+#include <iostream>
+#include <fstream>
+#include <iomanip>
+/*
+#include <strstream>
+
+#include "raslib/rminit.hh"
+#include "rasodmg/marray.hh"
+#include "rasodmg/ref.hh"
+#include "rasodmg/set.hh"
+#include "rasodmg/database.hh"
+#include "rasodmg/partinsert.hh"
+#include "raslib/type.hh"
+#include "raslib/odmgtypes.hh"
+*/
+#include <cstring>
+#include <cstdlib>
+#include <sys/types.h>
+#include <unistd.h>
+#include <cstdio>
+#include <iostream>
+#include <fstream>
+
+#include "image.h"
+#include "utilities.h"
+
+using namespace std;
+using namespace RasNITF;
+
+
+typedef struct {
+ unsigned char red, green, blue;
+} RGBPixel;
+
+image_band::image_band(){
+ lutdnnm = NULL;
+}
+
+image_band::~image_band(){
+
+ if (lutdnnm != NULL){
+ delete lutdnnm;
+ lutdnnm = NULL;
+ }
+}
+
+image::image(){
+
+ m_icom = NULL;
+ m_bands = NULL;
+ m_udid = NULL;
+ m_ixshd = NULL;
+ m_data = NULL;
+
+}
+
+image::~image(){
+
+ if (m_icom != NULL) {
+ delete m_icom;
+ m_icom = NULL;
+ }
+
+ if (m_bands != NULL){
+ delete[] m_bands;
+ m_bands = NULL;
+ }
+
+ if (m_udid != NULL) {
+ delete m_udid;
+ m_udid = NULL;
+ }
+
+ if (m_ixshd != NULL) {
+ delete m_ixshd;
+ m_ixshd = NULL;
+ }
+
+ if (m_data != NULL) {
+ delete m_data;
+ m_data = NULL;
+ }
+}
+
+
+/**********************************************************************
+ * NAME: image::read_file
+ * PURPOSE: read an image from an ntf file into an image object
+ *********************************************************************/
+
+int image::read_file(istream &hNITF, long lish, long li, bool read_image_data){
+
+ int charsread=0;
+
+ // read IM through ICORDS
+
+ charsread += read_verify2(hNITF, m_im, (2+10+14+17+80+1+2+11+2+20+2+8+4+1+8+43+1+40+1+8+15+1+42+8+8+3+8+8+2+1+1));
+
+ // read IGEOLO field if used
+
+ if (m_icords[0] != ' ') {
+ charsread += read_verify2(hNITF, m_igeolo, 60);
+ } else {
+ memset(m_igeolo, ' ', 60);
+ charsread += 60;
+ }
+
+ // read NICOM and ICOM
+
+ charsread += read_verify2(hNITF, m_nicom, 1);
+ n_nicom = charptrtoint(m_nicom, 1);
+
+ if (n_nicom > 0) {
+ m_icom = new char[n_nicom * 80];
+ charsread += read_verify2(hNITF, m_icom, n_nicom * 80);
+ } else {
+ m_icom = NULL;
+ }
+
+ // read IC
+
+ charsread += read_verify2(hNITF, m_ic, 2);
+
+ // read COMRAT if necessary
+
+ if ((strncmp(m_ic, "NC", 2) != 0) && (strncmp(m_ic, "NM", 2) != 0)) {
+ charsread += read_verify2(hNITF, m_comrat, 4);
+ }
+
+ charsread += read_verify2(hNITF, m_nbands, 1);
+ n_nbands = charptrtoint(m_nbands, 1);
+
+ if (n_nbands == 0) {
+ charsread += read_verify2(hNITF, m_xbands, 5);
+ n_xbands = charptrtoint(m_xbands, 5);
+ numbands = n_xbands;
+ } else {
+ n_xbands = 0;
+ numbands = n_nbands;
+ }
+
+ if (numbands > 0){
+
+ m_bands = new image_band[numbands];
+
+ for (int i = 0; i < numbands; i++) {
+
+ // read IREPBANDnn..NLUTSnn
+ charsread += read_verify2(hNITF, m_bands[i].irepbandnn, (2+6+1+3+1));
+
+ // get # of LUTS for this band
+ m_bands[i].numluts = charptrtoint( m_bands[i].nlutsnn, 1);
+
+ // read LUTs entries per LUT
+ if (m_bands[i].numluts > 0) {
+
+ // read # of LUT entries
+ charsread += read_verify2(hNITF, m_bands[i].nelutnn, 5);
+ m_bands[i].numlutentries = charptrtoint(m_bands[i].nelutnn, 5);
+
+ // allocate space for the LUT entries
+ m_bands[i].lutdnnm = new char[m_bands[i].numluts * m_bands[i].numlutentries];
+
+ // read LUT entries
+ charsread += read_verify2(hNITF, m_bands[i].lutdnnm, m_bands[i].numluts * m_bands[i].numlutentries);
+
+ } else {
+
+ m_bands[i].lutdnnm = NULL;
+ }
+
+ } /* end for (band_num = 0... */
+
+ } else {
+
+ m_bands = NULL;
+
+ }
+
+ // read m_isync..udidl
+
+ charsread += read_verify2(hNITF, m_isync, (1+1+4+4+4+4+2+3+3+10+4+5));
+ n_udidl = charptrtolong(m_udidl, 5);
+
+ if (n_udidl > 0) {
+ charsread += read_verify2(hNITF, m_udofl, 3);
+ m_udid = new char[n_udidl];
+ charsread += read_verify2(hNITF, m_udid, n_udidl - 3);
+ }
+
+ // read ixshdl
+
+ charsread += read_verify2(hNITF, m_ixshdl, 5);
+ n_ixshdl = charptrtolong(m_ixshdl, 5);
+
+ if (n_ixshdl > 0) {
+ charsread += read_verify2(hNITF, m_ixsofl, 3);
+ m_ixshd = new char[n_ixshdl];
+ charsread += read_verify2(hNITF, m_ixshd, n_ixshdl - 3);
+ }
+
+ /***********************************************************************
+ * MASKED IMAGES ARE IGNORED FOR NOW !!!
+ ***********************************************************************
+
+ strncpy(temp_buffer, m_ic, 2);
+ temp_buffer[2] = '\0';
+
+ if (strcmp(temp_buffer, "NM") == 0 || strcmp(temp_buffer, "M1") == 0
+ || strcmp(temp_buffer, "M3") == 0
+ || strcmp(temp_buffer, "M4") == 0
+ || strcmp(temp_buffer, "M5") == 0) {
+
+ // ERROR not implemented yet masked images
+ }
+
+ ************************************************************************/
+
+ // copy image data
+
+ header_length = lish;
+ data_length = li;
+
+ if(read_image_data == true) {
+ m_data = new char[li];
+ charsread += read_verify2(hNITF, m_data, li);
+ } else {
+ charsread += li;
+ }
+ n_nbpr = 0; // number of blocks per row
+ n_nbpc = 0; // number of blocks per column
+ n_nppbh = 0; // number of of pixels per block horizontally
+ n_nppbv = 0; // number of of pixels per block vertically
+
+ n_nppbh = charptrtoint( m_nppbh, 4);
+ n_nppbv = charptrtoint( m_nppbv, 4);
+ n_nbpr = charptrtoint( m_nbpr, 4);
+ n_nbpc = charptrtoint( m_nbpc, 4);
+
+ cout<<"IC: ";
+ cout.write(m_ic, 2);
+
+ cout<<"\nNBANDS: ";
+ cout.write(m_nbands, 1);
+
+ cout<<"\nnumber of blocks per row: ";
+ cout.write(m_nbpr, 4);
+
+ cout<<"\nNumber of blocks per column: ";
+ cout.write(m_nbpc, 4);
+
+ cout<<"\nImode: ";
+ cout.write(m_imode, 1);
+
+ return charsread;
+
+}
+
+/**********************************************************************
+ * NAME: image::write_file
+ * PURPOSE: write an image object into an ntf file on hard drive
+ *********************************************************************/
+
+int image::write_file(ofstream &fs){
+
+ int charswritten=0;
+
+ fs.write(m_im, 2);
+ fs.write(m_iid1, 10);
+ fs.write(m_idatim, 14);
+ fs.write(m_tgtid, 17);
+ fs.write(m_iid2, 80);
+ fs.write(m_isclas, 1);
+ fs.write(m_isclsy, 2);
+ fs.write(m_iscode, 11);
+ fs.write(m_isctlh, 2);
+ fs.write(m_isrel, 20);
+ fs.write(m_isdctp, 2);
+ fs.write(m_isdcdt, 8);
+ fs.write(m_isdcxm, 4);
+ fs.write(m_isdg, 1);
+ fs.write(m_isdgdt, 8);
+ fs.write(m_iscltx, 43);
+ fs.write(m_iscatp, 1);
+ fs.write(m_iscaut, 40);
+ fs.write(m_iscrsn, 1);
+ fs.write(m_issrdt, 8);
+ fs.write(m_isctln, 15);
+ fs.write(m_encryp, 1);
+ fs.write(m_isorce, 42);
+ fs.write(m_nrows, 8);
+ fs.write(m_ncols, 8);
+ fs.write(m_pvtype, 3);
+ fs.write(m_irep, 8);
+ fs.write(m_icat, 8);
+ fs.write(m_abpp, 2);
+ fs.write(m_pjust, 1);
+ fs.write(m_icords, 1);
+
+ if (m_icords[0] != ' '){
+ fs.write(m_igeolo, 60);
+ charswritten += 60;
+ }
+ fs.write(m_nicom, 1);
+
+ charswritten += 2 + 10 + 14 + 17 + 80 + 1 + 2 + 11 + 2 + 20 + 2 + 8 + 4 +1 + 8 + 43 + 1 + 40 + 1 + 8 + 15 + 1 + 42 + 8 + 8 + 3 + 8 + 8 + 2 + 1 + 1 + 1;
+
+ if (m_icom!=NULL) {
+ fs.write(m_icom, n_nicom * 80);
+ charswritten += n_nicom * 80;
+ }
+
+ fs.write(m_ic, 2);
+ charswritten += 2;
+
+ if ((strncmp(m_ic, "NC", 2) != 0) && (strncmp(m_ic, "NM", 2) != 0)) {
+ fs.write(m_comrat, 4);
+ charswritten += 4;
+ }
+ fs.write(m_nbands, 1);
+ charswritten += 1;
+
+ if (n_nbands == 0) {
+ fs.write(m_xbands, 5);
+ charswritten += 5;
+ }
+
+ if (m_bands != NULL){
+ for (int i=0; i<numbands; i++){
+ fs.write(m_bands[i].irepbandnn, 2);
+ fs.write(m_bands[i].isubcatnn, 6);
+ fs.write(m_bands[i].ifcnn, 1);
+ fs.write(m_bands[i].imfltnn, 3);
+ fs.write(m_bands[i].nlutsnn, 1);
+
+ charswritten += 2 + 6 + 1 + 3 + 1;
+
+ if (m_bands[i].numluts > 0){
+ fs.write(m_bands[i].nelutnn, 5);
+ fs.write(m_bands[i].lutdnnm, m_bands[i].numluts * m_bands[i].numlutentries);
+
+ charswritten += 5 + m_bands[i].numluts * m_bands[i].numlutentries;
+ }
+ }
+ }
+
+ fs.write(m_isync, 1);
+ fs.write(m_imode, 1);
+ fs.write(m_nbpr, 4);
+ fs.write(m_nbpc, 4);
+ fs.write(m_nppbh, 4);
+ fs.write(m_nppbv, 4);
+ fs.write(m_nbpp, 2);
+ fs.write(m_idlvl, 3);
+ fs.write(m_ialvl, 3);
+ fs.write(m_iloc, 10);
+ fs.write(m_imag, 4);
+ fs.write(m_udidl, 5);
+
+ charswritten += 1 + 1 + 4 + 4 + 4 +4 + 2 + 3 + 3 + 10 + 4 + 5;
+
+ if (n_udidl > 0) {
+ fs.write(m_udofl, 3);
+ fs.write(m_udid, n_udidl - 3);
+ charswritten += n_udidl;
+ }
+
+ fs.write(m_ixshdl, 5);
+ charswritten += 5;
+
+ if (n_ixshdl > 0) {
+ fs.write(m_ixsofl, 3);
+ fs.write(m_ixshd, n_ixshdl - 3);
+ charswritten += n_ixshdl;
+ }
+
+
+cout<<" wrote image header length: " << charswritten <<endl;
+if(m_data){
+fs.write(m_data, data_length);
+cout<< "image data length is : "<<data_length<<endl ;
+charswritten += data_length;
+}
+cout<<"IMAGE WRITE_FILE wrote "<< charswritten<<endl;
+
+ return charswritten;
+}
+
+
+/**********************************************************************
+ * NAME:image::get_li
+ * -------------------------------------------------------------------
+ * PURPOSE: image size
+ *********************************************************************/
+
+string image::get_li() const {
+ string temp(textdl);
+ return temp;
+}
+
+/**********************************************************************
+ * NAME:image::get_lish
+ * -------------------------------------------------------------------
+ * PURPOSE: returns the image header size
+ *********************************************************************/
+
+string image::get_lish() const {
+ string temp(texthl);
+ return temp;
+}
+
+
+/**********************************************************************
+ * NAME: image::compute_data_reordering_variables
+ *---------------------------------------------------------------------
+ * PURPOSE: computes some variable necessary for converting data from
+ * the ntf internal data storage to pixel sequential storage and vice
+ * versa
+ *********************************************************************/
+
+void image::compute_data_reordering_variables(){
+
+ int px_comp_size_bits = charptrtoint(m_nbpp, 2);
+
+ if ((px_comp_size_bits % 8) == 0) {
+ px_comp_size = px_comp_size_bits / 8;
+ } else {
+ cout << "unsupported pixel component size "<<endl;
+ exit(101);
+ }
+
+ px_size = px_comp_size * numbands;
+ numblocks = n_nbpc * n_nbpr;
+ block_size_bytes = data_length / numblocks;
+ block_size_pixels = n_nppbv * n_nppbh;
+ block_row_size = block_size_bytes / n_nppbv;
+ block_band_size = block_size_bytes /numbands;
+ block_band_size_px = block_size_pixels / numbands;
+ image_band_size = data_length / numbands;
+
+ n_nrows = charptrtolong(m_nrows, 8);
+ n_ncols = charptrtolong(m_ncols, 8);
+
+}
+
+/**********************************************************************
+ * NAME: image::blpxseq2pxseq
+ * -------------------------------------------------------------------
+ * PURPOSE: coverts memory data from block pixel sequential to pixel
+ * sequential storage
+ *********************************************************************/
+
+int image::blpxseq2pxseq(char* src, char* dest){
+
+ char *rowblockstart = NULL;
+ char *writefrom = NULL;
+
+
+ cout<< "n_nbpc: "<<n_nbpc <<endl;
+ cout<< "n_nbpr: " <<n_nbpr<<endl;
+ cout<< "block_size_bytes: " << block_size_bytes <<endl;
+ cout<< "block_row_size: " << block_row_size <<endl;
+
+ for (int vbindex=0; vbindex < n_nbpc; vbindex++){
+
+ rowblockstart = (char*)(src + vbindex * n_nbpr * block_size_bytes);
+
+ for (int hbindex = 0; hbindex < n_nbpr; hbindex++){
+
+ for(int i = 0; i < n_nppbv; i++){
+
+ writefrom = (char*) (rowblockstart + i * n_nbpr * block_row_size + hbindex * block_row_size );
+ strncpy(dest, writefrom , block_row_size);
+ dest += block_row_size;
+
+ cout<< "writing row: "<< i <<" of BLOCK: " << hbindex << "IN BLOCK ROW "<< vbindex<<endl;
+
+ cout << "writefrom "<< int(writefrom) <<"dest" << int(dest) <<" block row size " << block_row_size <<endl;
+ }
+ }
+ }
+
+ return 0;
+
+}
+
+/**********************************************************************
+ * NAME: image::pxseq2blpxseq
+ * -------------------------------------------------------------------
+ * PURPOSE: coverts memory data from pixel sequential to block pixel
+ * sequential storage
+ *********************************************************************/
+
+int image::pxseq2blpxseq(char* src, char* dest){
+
+ char *rowblockstart = NULL;
+ char *copyfrom = NULL;
+
+ for (int vbindex=0; vbindex < n_nbpc; vbindex++){
+
+ rowblockstart = (char*)(src + vbindex * n_nbpr * block_size_bytes);
+
+ for (int hbindex = 0; hbindex < n_nbpr; hbindex++){
+ for(int i = 0; i < n_nppbv; i++){
+ copyfrom = (char*) (rowblockstart + i * n_nbpr * block_row_size + hbindex * block_row_size );
+ strncpy(dest, copyfrom, block_row_size);
+ dest += block_row_size;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/**********************************************************************
+ * NAME: image::to_pixel_sequential
+ * --------------------------------------------------------------------
+ * PURPOSE: determines internal ntf image storage and chooses which
+ * convertion function to call in oreder to make the data pixel
+ * sequential
+ *********************************************************************/
+
+int image::to_pixel_sequential(){
+
+ string ic(m_ic,2);
+
+ if(ic=="NC"){
+
+ compute_data_reordering_variables();
+
+ if (numbands == 1) {
+
+ imode_1band2ps();
+
+ } else if (numbands == 3) {
+
+ switch(*m_imode) {
+ case 'B':
+ return imode_b2ps();
+ case 'P':
+ return imode_p2ps();
+ case 'S':
+ return imode_s2ps();
+ case 'R':
+ return imode_r2ps();
+ default:
+ exit(102);
+ }
+ }
+
+ return 0;
+
+ } else {
+ exit(103);
+ }
+
+}
+
+/**********************************************************************
+ * NAME: image::to_block_pixel_sequential
+ * --------------------------------------------------------------------
+ * PURPOSE: determines internal ntf image storage and chooses which
+ * convertion function to call in oreder to make the data block pixel
+ * sequential
+ *********************************************************************/
+
+int image::to_block_pixel_sequential(char* src){
+
+ string ic(m_ic,2);
+
+ if(ic=="NC"){
+
+ compute_data_reordering_variables();
+
+ if (numbands == 1) {
+
+ imode_ps21band(src);
+
+ } else if (numbands == 3) {
+
+ switch(*m_imode) {
+ case 'B':
+ return imode_ps2b(src);
+ case 'P':
+ return imode_ps2p(src);
+ case 'S':
+ return imode_ps2s(src);
+ case 'R':
+ return imode_ps2r(src);
+ default:
+ exit(104);
+ }
+ }
+
+ return 0;
+
+ } else {
+ exit(105);
+ }
+
+}
+
+/**********************************************************************
+ * NAME: image::imode_1band2ps
+ * --------------------------------------------------------------------
+ * PURPOSE: data convertion fucntion for the data of an image with 1
+ * band only (for details see NITF spec imode field)
+ *********************************************************************/
+
+int image::imode_1band2ps() {
+
+ char* temp_data = new char [data_length];
+ strncpy(temp_data, m_data, data_length);
+ blpxseq2pxseq(temp_data, m_data);
+ delete temp_data;
+
+ return 0;
+}
+
+/**********************************************************************
+ * NAME: image::imode_ps21band
+ * --------------------------------------------------------------------
+ * PURPOSE: data convertion fucntion for the data of an image with 1
+ * band only (for details see NITF spec imode field)
+ *********************************************************************/
+
+int image::imode_ps21band(char* src) {
+
+ pxseq2blpxseq(src, m_data);
+
+ return 0;
+}
+
+
+/**********************************************************************
+ * NAME: image::imode_b2ps
+ * -------------------------------------------------------------------
+ * PURPOSE: data convertion fucntion for the data of an image stored
+ * in band interleaved by block internal storage (for details see NITF
+ * spec imode field)
+ *********************************************************************/
+
+int image::imode_b2ps() {
+/*
+ char* kurets = new char[24];
+ strncpy(kurets, "ADMPBENQCFORGJSVHKTXILUY", 24);
+ char* temp_data = new char[24];
+ char* beginning = temp_data;
+ char* read_sofar = kurets;
+ char* RED_offset = NULL;
+ char* GREEN_offset = NULL;
+ char* BLUE_offset = NULL;
+
+ for(int block_index = 0; block_index < 2; block_index++) {
+
+ RED_offset = read_sofar;
+ GREEN_offset = (char*)(read_sofar + 4);
+ BLUE_offset = (char*)(read_sofar + 8);
+
+ for (int i=0; i < 4; i++) {
+ for (int j = 0; j < 1; j++){
+ cout<<RED_offset[0]<<endl;
+ *temp_data++ = *RED_offset++;
+ read_sofar++;
+ }
+ for (int j = 0; j < 1; j++){
+ cout<<GREEN_offset[0]<<endl;
+ *temp_data++ = *GREEN_offset++;
+ read_sofar++;
+ }
+ for (int j = 0; j < 1; j++){
+ cout<<BLUE_offset[0]<<endl;
+ *temp_data++ = *BLUE_offset++;
+ read_sofar++;
+ }
+ }
+ }
+ temp_data=beginning;
+ cout.write(temp_data, 24);
+ cout<<endl;
+ blpxseq2pxseq(temp_data, kurets);
+ cout.write(kurets, 24);
+ exit(1234);
+ delete temp_data;
+ return 0;
+*/
+
+ char* temp_data = new char[data_length];
+ char* read_sofar = m_data;
+ char* RED_offset = NULL;
+ char* GREEN_offset = NULL;
+ char* BLUE_offset = NULL;
+
+ for(int block_index = 0; block_index < numblocks; block_index++) {
+
+ RED_offset = read_sofar;
+ GREEN_offset = (char*)(read_sofar + block_band_size);
+ BLUE_offset = (char*)(read_sofar + 2 * block_band_size);
+
+ for (int i=0; i < block_band_size_px; i++) {
+ for (int j = 0; j < px_comp_size; j++){
+ *temp_data++ = *RED_offset++;
+ read_sofar++;
+ }
+ for (int j = 0; j < px_comp_size; j++){
+ *temp_data++ = *GREEN_offset++;
+ read_sofar++;
+ }
+ for (int j = 0; j < px_comp_size; j++){
+ *temp_data++ = *BLUE_offset++;
+ read_sofar++;
+ }
+ }
+ }
+
+ blpxseq2pxseq(temp_data, m_data);
+
+ delete temp_data;
+ return 0;
+
+}
+
+/**********************************************************************
+ * NAME: image::imode_ps2b
+ * -------------------------------------------------------------------
+ * PURPOSE: data convertion fucntion for the data of an image stored
+ * in band interleaved by block internal storage (for details see NITF
+ * spec imode field)
+ *********************************************************************/
+
+int image::imode_ps2b(char* src) {
+
+ char* temp_data = new char[data_length];
+ pxseq2blpxseq(src, temp_data);
+
+ char* written_sofar = m_data;
+ char* RED_offset = NULL;
+ char* GREEN_offset = NULL;
+ char* BLUE_offset = NULL;
+
+ for(int block_index = 0; block_index < numblocks; block_index++) {
+
+ RED_offset = m_data;
+ GREEN_offset = (char*)(written_sofar + block_band_size);
+ BLUE_offset = (char*)(written_sofar + 2 * block_band_size);
+
+ for (int i=0; i < block_band_size_px; i++) {
+ for (int j = 0; j < px_comp_size; j++){
+ *RED_offset++ = *temp_data++;
+ written_sofar++;
+ }
+ for (int j = 0; j < px_comp_size; j++){
+ *GREEN_offset++ = *temp_data++;
+ written_sofar++;
+ }
+ for (int j = 0; j < px_comp_size; j++){
+ *BLUE_offset++ = *temp_data++;
+ written_sofar++;
+ }
+ }
+ }
+
+ delete temp_data;
+
+ return 0;
+}
+
+/**********************************************************************
+ * NAME:image::imode_p2ps
+ * --------------------------------------------------------------------
+ * PURPOSE: data convertion fucntion for the data of an image stored
+ * in band interleaved by pixel by block internal storage (for details
+ * see NITF spec imode field)
+ *********************************************************************/
+
+int image::imode_p2ps() {
+
+ char* temp_data = new char [data_length];
+ strncpy(temp_data, m_data, data_length);
+ blpxseq2pxseq(temp_data, m_data);
+ delete temp_data;
+
+ return 0;
+}
+
+/**********************************************************************
+ * NAME:image::imode_ps2p
+ * --------------------------------------------------------------------
+ * PURPOSE: data convertion fucntion for the data of an image stored
+ * in band interleaved by pixel by block internal storage (for details
+ * see NITF spec imode field)
+ *********************************************************************/
+
+int image::imode_ps2p(char* src){
+
+ pxseq2blpxseq(src, m_data);
+ return 0;
+}
+
+
+/**********************************************************************
+ * NAME:image::imode_r2ps
+ * --------------------------------------------------------------------
+ * PURPOSE: data convertion fucntion for the data of an image stored
+ * in band interleaved by row by block internal storage ( for details
+ * see NITF spec imode field)
+ *********************************************************************/
+
+int image::imode_r2ps() {
+
+ char* temp_data = new char [data_length];
+
+ char* read_sofar = m_data;
+ char* RED_offset = NULL;
+ char* GREEN_offset = NULL;
+ char* BLUE_offset = NULL;
+
+ int block_row_band_size = block_row_size/numbands;
+
+ for(int block_index = 0; block_index < numblocks ; block_index++) {
+ for (int rowinblock = 0; rowinblock < n_nppbv; rowinblock++){
+
+ RED_offset = read_sofar;
+ GREEN_offset =(char*) (read_sofar + block_row_band_size);
+ BLUE_offset = (char*) (read_sofar+ 2 * block_row_band_size);
+
+ for (int i = 0; i < n_nppbh; i++){
+
+ for (int j = 0; j < px_comp_size; j++){
+ *temp_data++ = *RED_offset++;
+ read_sofar++;
+ }
+
+ for (int j = 0; j < px_comp_size; j++){
+ *temp_data++ = *GREEN_offset++;
+ read_sofar++;
+ }
+
+ for (int j = 0; j < px_comp_size; j++){
+
+ *temp_data++ = *BLUE_offset++;
+ read_sofar++;
+ }
+ }
+ }
+ }
+
+ blpxseq2pxseq(temp_data, m_data);
+ delete temp_data;
+ return 0;
+}
+
+/**********************************************************************
+ * NAME:image::imode_ps2r
+ * --------------------------------------------------------------------
+ * PURPOSE: data convertion fucntion for the data of an image stored
+ * in band interleaved by row by block internal storage ( for details
+ * see NITF spec imode field)
+ *********************************************************************/
+
+int image::imode_ps2r(char* src) {
+
+ char* temp_data = new char [data_length];
+ pxseq2blpxseq(src, temp_data);
+
+ char* written_sofar = m_data;
+ char* RED_offset = NULL;
+ char* GREEN_offset = NULL;
+ char* BLUE_offset = NULL;
+
+ int block_row_band_size = block_row_size/numbands;
+
+ for(int block_index = 0; block_index < numblocks ; block_index++) {
+ for (int rowinblock = 0; rowinblock < n_nppbv; rowinblock++){
+
+ RED_offset = written_sofar;
+ GREEN_offset =(char*) (written_sofar + block_row_band_size);
+ BLUE_offset = (char*) (written_sofar+ 2 * block_row_band_size);
+
+ for (int i = 0; i < n_nppbh; i++){
+
+ for (int j = 0; j < px_comp_size; j++){
+ *RED_offset++ = *temp_data++;
+ written_sofar++;
+ }
+
+ for (int j = 0; j < px_comp_size; j++){
+ *GREEN_offset++ = *temp_data++;
+ written_sofar++;
+ }
+
+ for (int j = 0; j < px_comp_size; j++){
+ *BLUE_offset++ = *temp_data++;
+ written_sofar++;
+ }
+ }
+ }
+ }
+
+ delete temp_data;
+ return 0;
+}
+
+
+/**********************************************************************
+ * NAME:image::imode_s2ps
+ * -------------------------------------------------------------------
+ * PURPOSE: data convertion fucntion for the data of an image stored
+ * in band sequential internal storage (for details see NITF spec
+ * imode field)
+ *********************************************************************/
+
+int image::imode_s2ps() {
+
+ int numpix = n_nrows * n_ncols;
+
+ char* temp_data = new char [data_length];
+
+ char* RED_offset = m_data;
+ char* GREEN_offset = (char*)(m_data + image_band_size);
+ char* BLUE_offset = (char*)(m_data + 2 * image_band_size);
+
+ for (int i=0; i < numpix; i++) {
+
+ for (int j = 0; j < px_comp_size; j++){
+ *temp_data++ = *RED_offset++;
+ }
+
+ for (int j = 0; j < px_comp_size; j++){
+ *temp_data++ = *GREEN_offset++;
+ }
+
+ for (int j = 0; j < px_comp_size; j++){
+
+ *temp_data++ = *BLUE_offset++;
+ }
+ }
+
+ blpxseq2pxseq(temp_data, m_data);
+ delete temp_data;
+
+ return 0;
+}
+
+/**********************************************************************
+ * NAME:image::imode_ps2s
+ * -------------------------------------------------------------------
+ * PURPOSE: data convertion fucntion for the data of an image stored
+ * in band sequential internal storage (for details see NITF spec
+ * imode field)
+ *********************************************************************/
+
+int image::imode_ps2s(char* src) {
+
+ char* temp_data = new char[data_length];
+ pxseq2blpxseq(src, temp_data);
+
+ int numpix = n_nrows * n_ncols;
+
+ char* RED_offset = m_data;
+ char* GREEN_offset = (char*)(m_data + image_band_size);
+ char* BLUE_offset = (char*)(m_data + 2 * image_band_size);
+
+ for (int i=0; i < numpix; i++) {
+
+ for (int j = 0; j < px_comp_size; j++){
+ *RED_offset++ = *temp_data++;
+ }
+
+ for (int j = 0; j < px_comp_size; j++){
+ *GREEN_offset++ = *temp_data++;
+ }
+
+ for (int j = 0; j < px_comp_size; j++){
+ *BLUE_offset++ = *temp_data++;
+ }
+ }
+
+ delete temp_data;
+
+ return 0;
+}
+
+long image::get_size() const
+{
+ return data_length;
+}
+
+int image::get_width() const
+{
+ return n_nrows;
+}
+
+int image::get_height() const
+{
+ return n_ncols;
+}
+
+string image::get_irep() const {
+ return string(m_irep, 8);
+}
+
+string image::get_pvtype() const {
+ return string(m_pvtype, 3);
+}
+
+int image::get_nbpp_bytes() const {
+
+ return charptrtoint(m_nbpp, 2);
+}
diff --git a/conversion/image.h b/conversion/image.h
new file mode 100644
index 0000000..91213ed
--- /dev/null
+++ b/conversion/image.h
@@ -0,0 +1,226 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#ifndef __RASNITF_IMAGE_H
+#define __RASNITF_IMAGE_H
+
+#include <fstream>
+#include <iostream>
+
+namespace RasNITF{
+
+class image_band{
+
+ public:
+
+ char irepbandnn[2];
+ char isubcatnn[6];
+ char ifcnn[1];
+ char imfltnn[3];
+ char nlutsnn[1];
+ char nelutnn[5];
+ int numluts;
+ int numlutentries;
+ char* lutdnnm;
+
+ image_band();
+ ~image_band();
+
+};
+
+class image {
+
+ /*********************************
+ * image header fields
+ ********************************/
+
+ char m_im[2];
+ char m_iid1[10];
+ char m_idatim[14];
+ char m_tgtid[17];
+ char m_iid2[80];
+ char m_isclas[1];
+ char m_isclsy[2];
+ char m_iscode[11];
+ char m_isctlh[2];
+ char m_isrel[20];
+ char m_isdctp[2];
+ char m_isdcdt[8];
+ char m_isdcxm[4];
+ char m_isdg[1];
+ char m_isdgdt[8];
+ char m_iscltx[43];
+ char m_iscatp[1];
+ char m_iscaut[40];
+ char m_iscrsn[1];
+ char m_issrdt[8];
+ char m_isctln[15];
+ char m_encryp[1];
+ char m_isorce[42];
+ char m_nrows[8];
+ char m_ncols[8];
+ char m_pvtype[3];
+ char m_irep[8];
+ char m_icat[8];
+ char m_abpp[2];
+ char m_pjust[1];
+ char m_icords[1];
+ char m_igeolo[60];
+ char m_nicom[1];
+ char* m_icom;
+ char m_ic[2];
+ char m_comrat[4];
+ char m_nbands[1];
+ char m_xbands[5];
+ image_band* m_bands;
+ char m_isync[1];
+ char m_imode[1];
+ char m_nbpr[4];
+ char m_nbpc[4];
+ char m_nppbh[4];
+ char m_nppbv[4];
+ char m_nbpp[2];
+ char m_idlvl[3];
+ char m_ialvl[3];
+ char m_iloc[10];
+ char m_imag[4];
+ char m_udidl[5];
+ char m_udofl[3];
+ char* m_udid;
+ char m_ixshdl[5];
+ char m_ixsofl[3];
+ char* m_ixshd;
+
+ /*****************************
+ * image data mask table
+ ****************************/
+
+ /*
+ long imdataoff;
+ unsigned short bmrlnth;
+ unsigned short tmrlnth;
+ unsigned short tpxcdlnth;
+ long tpxcd;
+ char* BMRnBNDm;
+ char* TMRnBNDm;
+ */
+
+ /*****************************
+ * raw image data
+ *****************************/
+
+ char* m_data;
+
+ /*****************************
+ * additional variables
+ *****************************/
+
+// bool compressed;
+ int n_nicom;
+ int n_nbands;
+ int n_xbands;
+ int numbands;
+ int n_udidl;
+ int n_ixshdl;
+ long header_length;
+ long data_length;
+ char texthl[6];
+ char textdl[10];
+ int n_nbpr;
+ int n_nbpc;
+ int n_nppbh;
+ int n_nppbv;
+
+ /*****************************
+ * variables for data reordering
+ * populated by compute_data_reordering_variables()
+ *****************************/
+
+ int n_nrows;
+ int n_ncols;
+ int px_comp_size;
+ int px_size;
+ int numblocks;
+
+ long block_size_bytes;
+ long block_size_pixels;
+ long block_row_size; //bytes
+ long block_band_size; //bytes
+ long block_band_size_px;
+ long image_band_size;
+
+
+ int copy_block_data(char* writeto, int hor_block_index, int ver_block_index );
+
+ // functions for data reordering
+
+ void compute_data_reordering_variables();
+
+ int blpxseq2pxseq(char* src, char* dest);
+ int pxseq2blpxseq(char*, char*);
+
+ int imode_1band2ps();
+ int imode_b2ps();
+ int imode_r2ps();
+ int imode_p2ps();
+ int imode_s2ps();
+
+ int imode_ps21band(char*);
+ int imode_ps2b(char*);
+ int imode_ps2r(char*);
+ int imode_ps2p(char*);
+ int imode_ps2s(char*);
+
+
+ public:
+
+ image();
+ ~image();
+
+ int read_file(std::istream&, long, long, bool read_image_data);
+ int write_file(std::ofstream& fs);
+
+ std::string get_li() const;
+ std::string get_lish() const;
+ long get_size() const;
+ int get_width() const;
+ int get_height() const;
+
+ int to_pixel_sequential();
+ int to_block_pixel_sequential(char* src);
+
+ std::string get_irep() const;
+ std::string get_pvtype() const;
+
+ int get_nbpp_bytes() const;
+
+// char* get_data_ptr();
+
+
+};
+
+}
+
+#endif
+
+
diff --git a/conversion/int16.cc b/conversion/int16.cc
new file mode 100644
index 0000000..abd8a2f
--- /dev/null
+++ b/conversion/int16.cc
@@ -0,0 +1,874 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: int16.hh
+ *
+ * MODULE: conversion
+ *
+ * CLASSES: r_Conv_int16
+ *
+ * COMMENTS:
+ * Provides interface to convert data from/to Array format to/from int16 format.
+ *
+*/
+
+static const char rcsid[] = "@(#)conversion,r_Conv_int16: $Id: int16.cc,v 1.8 2002/10/01 09:16:38 coman Exp $";
+
+#include "conversion/int16.hh"
+
+#include <float.h>
+#include <string>
+#include <cstring>
+#include <strstream>
+#include <sstream>
+#include <algorithm>
+
+using std::istringstream;
+using std::istrstream;
+using std::string;
+
+#include "raslib/rminit.hh"
+#include "raslib/parseparams.hh"
+#include "raslib/primitivetype.hh"
+
+
+const r_Dimension r_Conv_int16::srcIntervDim=1;
+const r_Dimension r_Conv_int16::destIntervDim=2;
+const r_ULong r_Conv_int16::paramMin=6;
+const char* r_Conv_int16::paramSep=",";
+const char* r_Conv_int16::paramEq="=";
+const char* r_Conv_int16::paramFlipX="flipx";
+const char* r_Conv_int16::paramFlipY="flipy";
+const char* r_Conv_int16::paramStartX="startx";
+const char* r_Conv_int16::paramEndX="endx";
+const char* r_Conv_int16::paramResX="resx";
+const char* r_Conv_int16::paramStartY="starty";
+const char* r_Conv_int16::paramEndY="endy";
+const char* r_Conv_int16::paramResY="resy";
+
+const r_Double r_Conv_int16::NULL_DB = 0.;
+const r_Double r_Conv_int16::ZERO_DB = FLT_MIN;
+const r_Double r_Conv_int16::ZERO_int16 = 0.;
+
+r_Conv_int16::~r_Conv_int16( void )
+{
+ //nothing to care for
+}
+
+void r_Conv_int16::initGeoBBox( r_GeoBBox& cBBox )
+{
+ //flipy is selected by default
+ cBBox.flipy = 1;
+
+ //flipx is not selected by default
+ cBBox.flipx = 0;
+
+ //geo information are initialized by default to DBL_MAX
+ // FIXME: better defaults res=1, min=-MAX?
+ cBBox.startx = DBL_MAX;
+ cBBox.endx = DBL_MAX;
+ cBBox.resx = DBL_MAX;
+ cBBox.starty = DBL_MAX;
+ cBBox.endy = DBL_MAX;
+ cBBox.resy = DBL_MAX;
+}
+
+r_Conv_int16::r_Conv_int16(const char* source, const r_Minterval& lengthordomain, const r_Type* tp) throw(r_Error)
+ : r_Convertor(source, lengthordomain, tp, true)
+{
+ initGeoBBox(collBBox);
+}
+
+r_Conv_int16::r_Conv_int16(const char* source, const r_Minterval& lengthordomain, int tp) throw(r_Error)
+ : r_Convertor(source, lengthordomain, tp)
+{
+ initGeoBBox(collBBox);
+}
+
+bool
+r_Conv_int16::decodeOptions(const char* options,
+ r_GeoBBox& cBBox) throw()
+{
+ RMInit::logOut << "r_Conv_int16::decodeOptions(" << (options?options:"NULL") << ")" << endl;
+
+ r_Parse_Params parseParams;
+
+ initGeoBBox(cBBox);
+
+ parseParams.add(paramFlipX, &cBBox.flipx, r_Parse_Params::param_type_int);
+ parseParams.add(paramFlipY, &cBBox.flipy, r_Parse_Params::param_type_int);
+ parseParams.add(paramStartX, &cBBox.startx, r_Parse_Params::param_type_double);
+ parseParams.add(paramEndX, &cBBox.endx, r_Parse_Params::param_type_double);
+ parseParams.add(paramResX, &cBBox.resx, r_Parse_Params::param_type_double);
+ parseParams.add(paramStartY, &cBBox.starty, r_Parse_Params::param_type_double);
+ parseParams.add(paramEndY, &cBBox.endy, r_Parse_Params::param_type_double);
+ parseParams.add(paramResY, &cBBox.resy, r_Parse_Params::param_type_double);
+
+ //process options
+ r_Long processRet=parseParams.process(options);
+ if(processRet < paramMin)
+ {
+ RMInit::logOut << "r_Conv_int16::decodeOptions(...) Error: Some required options are missing!" << endl;
+ return false;
+ }
+
+ //check if start,res,end are present
+ if(cBBox.startx == DBL_MAX)
+ {
+ RMInit::logOut << "r_Conv_int16::decodeOptions(...) Error: startx is not present!" << endl;
+ return false;
+ }
+
+ if(cBBox.starty == DBL_MAX)
+ {
+ RMInit::logOut << "r_Conv_int16::decodeOptions(...) Error: starty is not present!" << endl;
+ return false;
+ }
+
+ if(cBBox.endx == DBL_MAX)
+ {
+ RMInit::logOut << "r_Conv_int16::decodeOptions(...) Error: endx is not present!" << endl;
+ return false;
+ }
+
+ if(cBBox.endy == DBL_MAX)
+ {
+ RMInit::logOut << "r_Conv_int16::decodeOptions(...) Error: endy is not present!" << endl;
+ return false;
+ }
+
+ if(cBBox.resx == DBL_MAX)
+ {
+ RMInit::logOut << "r_Conv_int16::decodeOptions(...) Error: resx is not present!" << endl;
+ return false;
+ }
+
+ if(cBBox.resy == DBL_MAX)
+ {
+ RMInit::logOut << "r_Conv_int16::decodeOptions(...) Error: resy is not present!" << endl;
+ return false;
+ }
+
+
+ //check res
+ if(!cBBox.resx)
+ {
+ RMInit::logOut << "r_Conv_int16::decodeOptions(...) Error: resx is zero!" << endl;
+ return false;
+ }
+
+ if(!cBBox.resy)
+ {
+ RMInit::logOut << "r_Conv_int16::decodeOptions(...) Error: resy is zero!" << endl;
+ return false;
+ }
+
+ //check start >= end
+ if(cBBox.startx >= cBBox.endx )
+ {
+ RMInit::logOut << "r_Conv_int16::decodeOptions(...) Error: startx >= endx!" << endl;
+ return false;
+ }
+
+ if(cBBox.starty >= cBBox.endy)
+ {
+ RMInit::logOut << "r_Conv_int16::decodeOptions(...) Erorr: starty >= endy!" << endl;
+ return false;
+ }
+
+ //show parsed options
+ RMInit::logOut.setf(std::ios::fixed);
+ RMInit::logOut << "r_Conv_int16::decodeOptions(...) parsed options:" << endl
+ << " " << paramFlipX << paramEq << cBBox.flipx
+ << " " << paramFlipY << paramEq << cBBox.flipy << endl
+ << " " << paramStartX << paramEq << cBBox.startx
+ << " " << paramEndX << paramEq << cBBox.endx
+ << " " << paramResX << paramEq << cBBox.resx << endl
+ << " " << paramStartY << paramEq << cBBox.starty
+ << " " << paramEndY << paramEq << cBBox.endy
+ << " " << paramResY << paramEq << cBBox.resy << endl;
+ return true;
+}
+
+string
+r_Conv_int16::encodeOptions(const r_GeoBBox& cBBox) throw()
+{
+ std::ostringstream os;
+
+ os.str("");
+ os.setf(std::ios::fixed);
+ os << paramFlipX << paramEq << cBBox.flipx
+ << paramSep << paramFlipY << paramEq << cBBox.flipy
+ << paramSep << paramStartX << paramEq << cBBox.startx
+ << paramSep << paramEndX << paramEq << cBBox.endx
+ << paramSep << paramResX << paramEq << cBBox.resx
+ << paramSep << paramStartY << paramEq << cBBox.starty
+ << paramSep << paramEndY << paramEq << cBBox.endy
+ << paramSep << paramResY << paramEq << cBBox.resy;
+
+ RMInit::logOut << "r_Conv_int16::encodeOptions(" << os.str() << ")" << endl;
+
+ return os.str();
+}
+
+void
+r_Conv_int16::checkLimits() throw(r_Error)
+{
+ //show processed data
+ RMInit::logOut << "r_Conv_int16::checkLimits() processed data:" << endl
+ << " minx=" << min.x << " miny=" << min.y << " minh=" << min.h << endl
+ << " maxx=" << max.x << " maxy=" << max.y << " maxh=" << max.h << endl;
+ // printf( "r_Conv_int16::checkLimits() processed data: minx=%8G, miny=%8G, minh=%8G, maxx=%8G, maxy=%8G, maxh=%8G\n", min.x, min.y, min.h, max.x, max.y, max.h );
+
+ if(collBBox.startx > min.x)
+ {
+ RMInit::logOut << "r_Conv_int16::checkLimits() startx( " << collBBox.startx << ") > min.x (" << min.x << " )!" << endl;
+ throw r_Error();
+ }
+ if(collBBox.endx < max.x)
+ {
+ RMInit::logOut << "r_Conv_int16::checkLimits() endx( " << collBBox.endx << ") < max.x (" << max.x << " )!" << endl;
+ throw r_Error();
+ }
+
+ if(collBBox.starty > min.y)
+ {
+ RMInit::logOut << "r_Conv_int16::checkLimits() starty( " << collBBox.starty << ") > min.y (" << min.y << " )!" << endl;
+ throw r_Error();
+ }
+
+ if(collBBox.endy < max.y)
+ {
+ RMInit::logOut << "r_Conv_int16::checkLimits() endy( " << collBBox.endy << ") < max.y (" << max.y << " )!" << endl;
+ throw r_Error();
+ }
+}
+
+void
+r_Conv_int16::readFromSrcStream() throw(r_Error)
+{
+ istrstream iFile(desc.src, desc.srcInterv[0].get_extent());
+ string currStrRow;
+ istringstream icurrRow;
+ r_Long rowNo=0;
+ r_Double noResx, noResy;
+ int16Row currRow, prevRow;
+
+ min.x=min.y=min.h=DBL_MAX;
+ max.x=max.y=max.h=-DBL_MAX;
+ demRows.clear();
+
+ //process the lines
+ while(!iFile.eof())
+ {
+ getline(iFile, currStrRow);
+ rowNo++;
+ if(currStrRow.empty())
+ {
+ RMInit::logOut << "r_Conv_int16::readFromSrcStream() skipping empty line " << rowNo << endl;
+ continue;
+ }
+ else
+ {
+ icurrRow.str(currStrRow);
+
+ //decode x
+ icurrRow >> currRow.x;
+ if(!icurrRow)
+ {
+ RMInit::logOut << "r_Conv_int16::readFromSrcStream() skiping line " << rowNo
+ << "(unable to decode x) !" << endl;
+ continue;
+ }
+
+ //decode y
+ icurrRow >> currRow.y;
+ if(!icurrRow)
+ {
+ RMInit::logOut << "r_Conv_int16::readFromSrcStream() skiping line " << rowNo
+ << "(unable to decode y) !" << endl;
+ continue;
+ }
+
+ //decode h
+ icurrRow >> currRow.h;
+ if(!icurrRow)
+ {
+ RMInit::logOut << "r_Conv_int16::readFromSrcStream() skiping line " << rowNo
+ << "(unable to decode h) !" << endl;
+ continue;
+ }
+
+ //update to support NULL value: 0. (real value) goes in FLT_MIN(db value)
+ //because 0.(db value) represent NULL(real value). When we do export we skip NULL values.
+ if(currRow.h == ZERO_int16) currRow.h=ZERO_DB;
+
+ //FIXME we ignore this check, because it may happen to have a incomplet dem
+ /*
+ //check if we have resx, resy
+ noResx=currRow.x/collBBox.resx;
+ if((currRow.x - noResx*collBBox.resx) > 0.)
+ {
+ RMInit::logOut << "r_Conv_int16::readFromSrcStream() resolution for x on line " <<
+ rowNo << " is not " << collBBox.resx << " !" << endl;
+ throw r_Error();
+ }
+ noResy=currRow.y/collBBox.resy;
+ if((currRow.y - noResy*collBBox.resy) > 0.)
+ {
+ RMInit::logOut << "r_Conv_int16::readFromSrcStream() resolution for y on line " <<
+ rowNo << " is not " << collBBox.resy << " !" << endl;
+ throw r_Error();
+ }
+ */
+
+ //compute min, max for x,y,z
+ min.x=std::min<r_Double>(min.x, currRow.x);
+ min.y=std::min<r_Double>(min.y, currRow.y);
+ min.h=std::min<r_Double>(min.h, currRow.h);
+ max.x=std::max<r_Double>(max.x, currRow.x);
+ max.y=std::max<r_Double>(max.y, currRow.y);
+ max.h=std::max<r_Double>(max.h, currRow.h);
+
+ //store currRow
+ demRows.push_back(currRow);
+ }//end if(currStrRow.empty())
+ }//end reading src stream
+
+ if(demRows.empty())
+ {
+ RMInit::logOut << "r_Conv_int16::readFromSrcStream() desc.src stream is empty !" << endl;
+ throw r_Error();
+ }
+
+ //check limits
+ checkLimits();
+}
+
+
+void
+r_Conv_int16::readToSrcStream() throw(r_Error)
+{
+ r_Long x=0, y=0;
+ r_Long xlow=0, ylow=0;
+ r_Long xhigh=0, yhigh=0;
+ int16Row currRow;
+ r_Bytes typeSize=0;
+ r_Long offset=0;
+ char* buffer=NULL;
+
+ //initialize
+ xlow=desc.srcInterv[0].low();
+ ylow=desc.srcInterv[1].low();
+
+ xhigh=desc.srcInterv[0].high();
+ yhigh=desc.srcInterv[1].high();
+
+ //compute min & max
+ if (collBBox.flipx)
+ {
+ min.x=collBBox.endx - xhigh*collBBox.resx;
+ max.x=collBBox.endx - xlow*collBBox.resx;
+ }
+ else
+ {
+ min.x=collBBox.startx + xlow*collBBox.resx;
+ max.x=collBBox.startx + xhigh*collBBox.resx;
+ }
+
+ if(collBBox.flipy)
+ {
+ min.y=collBBox.endy - yhigh*collBBox.resy;
+ max.y=collBBox.endy - ylow*collBBox.resy;
+ }
+ else
+ {
+ min.y=collBBox.starty + ylow*collBBox.resy;
+ max.y=collBBox.starty + yhigh*collBBox.resy;
+ }
+
+ min.h=DBL_MAX;
+ max.h=-DBL_MAX;
+
+ //check limits
+ checkLimits();
+
+ //prepare container
+ demRows.clear();
+ typeSize=((r_Primitive_Type*)desc.srcType)->size();
+ buffer=new char[typeSize];
+ if(!buffer)
+ {
+ RMInit::logOut << "r_Conv_int16::readToSrcStream() unable to claim memory !" << endl;
+ throw r_Ememory_allocation();
+ }
+
+ for(y=ylow; y<=yhigh; y++)
+ {
+ if(collBBox.flipy)
+ currRow.y=collBBox.endy - y*collBBox.resy;
+ else
+ currRow.y=collBBox.starty + y*collBBox.resy;
+
+ for(x=xlow; x<=xhigh; x++)
+ {
+ if(collBBox.flipx)
+ currRow.x=collBBox.endx - x*collBBox.resx;
+ else
+ currRow.x=collBBox.startx + x*collBBox.resx;
+ offset=desc.srcInterv.cell_offset(r_Point(x,y))*typeSize;
+ memcpy(buffer, &desc.src[offset], typeSize);
+ switch(desc.srcType->type_id())
+ {
+ case r_Type::BOOL:
+ currRow.h=((r_Primitive_Type*)desc.srcType)->get_boolean(buffer);
+ break;
+ case r_Type::CHAR:
+ currRow.h=((r_Primitive_Type*)desc.srcType)->get_char(buffer);
+ break;
+ case r_Type::OCTET:
+ currRow.h=((r_Primitive_Type*)desc.srcType)->get_octet(buffer);
+ break;
+ case r_Type::SHORT:
+ currRow.h=((r_Primitive_Type*)desc.srcType)->get_short(buffer);
+ break;
+ case r_Type::USHORT:
+ currRow.h=((r_Primitive_Type*)desc.srcType)->get_ushort(buffer);
+ break;
+ case r_Type::LONG:
+ currRow.h=((r_Primitive_Type*)desc.srcType)->get_long(buffer);
+ break;
+ case r_Type::ULONG:
+ currRow.h=((r_Primitive_Type*)desc.srcType)->get_ulong(buffer);
+ break;
+ case r_Type::FLOAT:
+ currRow.h=((r_Primitive_Type*)desc.srcType)->get_float(buffer);
+ break;
+ case r_Type::DOUBLE:
+ currRow.h=((r_Primitive_Type*)desc.srcType)->get_double(buffer);
+ break;
+ default:
+ //write message to log
+ RMInit::logOut << "r_Conv_int16::readToSrcStream() srcType (" << desc.srcType->type_id() << ") unsupported !" << endl;
+ //clean up
+ if(buffer)
+ {
+ delete[] buffer;
+ buffer=NULL;
+ }
+ //report error
+ throw r_Error();
+ break;
+ }
+ min.h=std::min<r_Double>(min.h, currRow.h);
+ max.h=std::max<r_Double>(max.h, currRow.h);
+ demRows.push_back(currRow);
+ }
+ }
+
+ //clean up
+ if(buffer)
+ {
+ delete[] buffer;
+ buffer=NULL;
+ }
+
+ if(demRows.empty())
+ {
+ RMInit::logOut << "r_Conv_int16::readToSrcStream() src stream is empty !" << endl;
+ throw r_Error();
+ }
+}
+
+
+void
+r_Conv_int16::writeFromDestStream() throw(r_Error)
+{
+ int16RowVec::const_iterator iter, iterEnd;
+ r_Long xdim, ydim, offset;
+ r_Point currPt(destIntervDim);
+ r_Bytes typeSize=0;
+
+
+ //FIXME here we should modify for other type support
+ if(desc.destType->type_id() != r_Type::DOUBLE)
+ {
+ RMInit::logOut << "r_Conv_int16::writeFromDestStream() destType (" << desc.destType->type_id()
+ << ") is not " << r_Type::DOUBLE << " !" << endl;
+ throw r_Error();
+ }
+
+ xdim=desc.destInterv[0].get_extent();
+ ydim=desc.destInterv[1].get_extent();
+ iter=demRows.begin();
+ iterEnd=demRows.end();
+ typeSize=((r_Primitive_Type*)desc.destType)->size();
+
+ //FIXME correction for strange efect of r_Long cast with 1e-6
+ while(iter != iterEnd)
+ {
+ if(collBBox.flipx)
+ currPt[0]=(collBBox.endx - iter->x)/collBBox.resx + 1e-6;
+ else
+ currPt[0]=(iter->x - collBBox.startx)/collBBox.resx + 1e-6;
+ if(collBBox.flipy)
+ currPt[1]=(collBBox.endy - iter->y)/collBBox.resy + 1e-6;
+ else
+ currPt[1]=(iter->y - collBBox.starty)/collBBox.resy + 1e-6;
+ ((r_Primitive_Type*)desc.destType)->set_double(&desc.dest[desc.destInterv.cell_offset(currPt)*typeSize], iter->h);
+ ++iter;
+ }
+}
+
+void
+r_Conv_int16::writeToDestStream(ofstream& oFile) throw(r_Error)
+{
+ int16RowVec::const_iterator iter, iterEnd;
+ r_Double currH;
+
+ if(!oFile.is_open())
+ {
+ RMInit::logOut << "r_Conv_int16::writeToDestStream() oFile is not opened !" << endl;
+ throw r_Error();
+ }
+ oFile.setf(std::ios::fixed);
+
+ iter=demRows.begin();
+ iterEnd=demRows.end();
+ while(iter != iterEnd)
+ {
+ //update to support NULL value: 0. (real value) goes in FLT_MIN(db value)
+ //because 0.(db value) represent NULL(real value). When we do export we skip NULL values.
+ currH = iter->h;
+ if(currH != NULL_DB)
+ {
+ //FIXME we have to implement different here when we change server scale algorithm
+ if(currH == ZERO_DB)
+ currH = ZERO_int16;
+ oFile << iter->x << "\t" << iter->y << "\t" << currH << endl;
+ }
+ ++iter;
+ }
+}
+
+r_convDesc&
+r_Conv_int16::convertFrom(const char* options) throw (r_Error)
+{
+ bool hasSrcType=true;
+
+ RMInit::logOut << "r_Conv_int16::convertFrom(" << (options?options:"NULL") << ")" << endl;
+
+ if(!desc.srcType)
+ {
+ desc.srcType=get_external_type(desc.baseType);
+ hasSrcType=false;
+ }
+
+ try
+ {
+ RMInit::logOut << "r_Conv_int16::convertFrom(...) src interval=" << desc.srcInterv << endl;
+ RMInit::logOut << "r_Conv_int16::convertFrom(...) src type=" << desc.srcType->type_id() << endl;
+
+ //check options
+ if(!decodeOptions(options, collBBox))
+ throw r_Error();
+
+ //check desc.srcInterv.dimension
+ if(desc.srcInterv.dimension() != srcIntervDim)
+ {
+ RMInit::logOut << "r_Conv_int16::convertFrom(" << (options?options:"NULL")
+ << ") desc.srcInterv dimension (" << desc.srcInterv.dimension()
+ << " != " << srcIntervDim << " !" << endl;
+ throw r_Error();
+ }
+
+ //check srcType
+ if(!desc.srcType->isPrimitiveType())
+ {
+ RMInit::logOut << "r_Conv_int16::convertFrom(" << (options?options:"NULL")
+ << ") desc.srcType (" << desc.srcType->type_id()
+ << ") not supported, only primitive types !" << endl;
+ throw r_Error();
+ }
+
+ if(desc.srcType->isComplexType())
+ {
+ RMInit::logOut << "r_Conv_int16::convertFrom(" << (options?options:"NULL")
+ << ") desc.srcType (" << desc.srcType->type_id()
+ << ") not supported !" << endl;
+ throw r_Error();
+ }
+
+ //read src stream
+ readFromSrcStream();
+
+ //convert from int16 to marray
+ //--computing the marray domain
+ desc.destInterv = r_Minterval(destIntervDim);
+
+ //FIXME correction for strange efect of r_Long cast with 1e-6
+ if(collBBox.flipx)
+ desc.destInterv << r_Sinterval((r_Long)((collBBox.endx - max.x)/collBBox.resx + 1e-6),
+ (r_Long)((collBBox.endx - min.x)/collBBox.resx + 1e-6));
+ else
+ desc.destInterv << r_Sinterval((r_Long)((min.x - collBBox.startx)/collBBox.resx + 1e-6),
+ (r_Long)((max.x - collBBox.startx)/collBBox.resx + 1e-6));
+ if(collBBox.flipy)
+ desc.destInterv << r_Sinterval((r_Long)((collBBox.endy - max.y)/collBBox.resy + 1e-6),
+ (r_Long)((collBBox.endy - min.y)/collBBox.resy + 1e-6));
+ else
+ desc.destInterv << r_Sinterval((r_Long)((min.y - collBBox.starty)/collBBox.resy + 1e-6),
+ (r_Long)((max.y - collBBox.starty)/collBBox.resy + 1e-6));
+
+ RMInit::logOut << "r_Conv_int16::convertFrom(...) dest interval=" << desc.destInterv << endl;
+
+ //--creating the resulting type
+ desc.destType = new r_Primitive_Type("Double", r_Type::DOUBLE);
+ RMInit::logOut << "r_Conv_int16::convertFrom(...) dest type=" << desc.destType->type_id() << endl;
+
+ //--claim memory for result
+ desc.dest = (char*)mystore.storage_alloc(desc.destInterv.cell_count() * ((r_Primitive_Type*)desc.destType)->size());
+ if(desc.dest==NULL)
+ {
+ RMInit::logOut << "r_Conv_int16::convertFrom(" << (options?options:"NULL")
+ << ") unable to claim memory !" << endl;
+ throw r_Ememory_allocation();
+ }
+ memset(desc.dest, 0, desc.destInterv.cell_count() * ((r_Primitive_Type*)desc.destType)->size());
+
+ //--write parsed data in desc.dest
+ writeFromDestStream();
+ }
+ catch(r_Error& err)
+ {
+ //cleanup
+ if(!hasSrcType)
+ {
+ delete desc.srcType;
+ desc.srcType=NULL;
+ }
+
+ //desc.destType
+ if(desc.destType)
+ {
+ delete desc.destType;
+ desc.destType=NULL;
+ }
+
+ //desc.dest
+ if(desc.dest)
+ {
+ mystore.storage_free(desc.dest);
+ desc.dest=NULL;
+ }
+
+ //report error
+ throw;
+ }
+
+ //cleanup
+ if(!hasSrcType)
+ {
+ delete desc.srcType;
+ desc.srcType=NULL;
+ }
+
+ //return result
+ return desc;
+}
+
+
+r_convDesc&
+r_Conv_int16::convertTo(const char* options) throw (r_Error)
+{
+ bool hasSrcType=true;
+
+ RMInit::logOut << "r_Conv_int16::convertTo(" << (options?options:"NULL") << ")" << endl;
+
+ try
+ {
+ if(!desc.srcType)
+ {
+ desc.srcType=get_external_type(desc.baseType);
+ hasSrcType=false;
+ }
+
+ RMInit::logOut << "r_Conv_int16::convertTo(...) src interval=" << desc.srcInterv << endl;
+ RMInit::logOut << "r_Conv_int16::convertTo(...) src type=" << desc.srcType->type_id() << endl;
+
+ //check options
+ if(!decodeOptions(options, collBBox))
+ throw r_Error();
+
+ if(!desc.srcType->isPrimitiveType())
+ {
+ RMInit::logOut << "r_Conv_int16::convertTo(" << (options?options:"NULL")
+ << ") desc.srcType (" << desc.srcType->type_id()
+ << ") not supported, only primitive types !" << endl;
+ throw r_Error();
+ }
+ if(desc.srcType->isComplexType())
+ {
+ RMInit::logOut << "r_Conv_int16::convertTo(" << (options?options:"NULL")
+ << ") desc.srcType (" << desc.srcType->type_id()
+ << ") not supported !" << endl;
+ throw r_Error();
+ }
+
+ //read src data
+ readToSrcStream();
+
+ //convert from marray to int16;
+ char* pTempFileName=NULL;
+ string tempFileName;
+ ofstream oFile;
+ FILE* pFile=NULL;
+ size_t lenFile=0;
+
+ //--create the temp file
+ //FIXME for multithread application
+ pTempFileName=tmpnam(NULL);
+ if(pTempFileName==NULL)
+ {
+ RMInit::logOut << "r_Conv_int16::convertTo(" << (options?options:"NULL")
+ << ") desc.srcType (" << desc.srcType->type_id()
+ << ") unable to generate a tempory file !" << endl;
+ throw r_Error();
+ }
+
+ tempFileName=pTempFileName;
+ oFile.open(tempFileName.c_str());
+ if(!oFile.is_open())
+ {
+ RMInit::logOut << "r_Conv_int16::convertTo(" << (options?options:"NULL")
+ << ") desc.srcType (" << desc.srcType->type_id()
+ << ") unable to open the tempory file !" << endl;
+ throw r_Error();
+ }
+
+ RMInit::logOut << "r_Conv_int16::convertTo(...) temp file=" << tempFileName << endl;
+
+ //--get int16 format
+ writeToDestStream(oFile);
+ oFile.close();
+
+ //--accessing the temp file
+ if ((pFile = fopen(tempFileName.c_str(), "rb")) == NULL)
+ {
+ RMInit::logOut << "r_Conv_int16::convertTo(): unable to read back file." << endl;
+ throw r_Error(r_Error::r_Error_General);
+ }
+ fseek(pFile, 0, SEEK_END);
+ lenFile = ftell(pFile);
+ RMInit::logOut << "r_Conv_int16::convertTo(...) dest len=" << lenFile << endl;
+
+ if (!lenFile)
+ {
+ RMInit::logOut << "r_Conv_int16::convertTo(): source contains only NULL values." << endl;
+ throw r_Error();
+ }
+
+ //--creating the resulting type
+ desc.destType = new r_Primitive_Type("Char", r_Type::CHAR);
+
+ //--computing the marray domain
+ desc.destInterv = r_Minterval(srcIntervDim);
+ desc.destInterv << r_Sinterval((r_Long)0, (r_Long)lenFile - 1);
+
+ RMInit::logOut << "r_Conv_int16::convertTo(...) dest interval=" << desc.destInterv << endl;
+ RMInit::logOut << "r_Conv_int16::convertTo(...) dest type=" << desc.destType->type_id() << endl;
+
+ //--claim memory for desc.dest
+ desc.dest = (char*)mystore.storage_alloc(lenFile);
+ if(desc.dest==NULL)
+ {
+ RMInit::logOut << "r_Conv_int16::convertTo(" << (options?options:"NULL")
+ << ") unable to claim memory !" << endl;
+ throw r_Ememory_allocation();
+ }
+ memset(desc.dest, 0, lenFile);
+
+ //--story the data in desc.dest
+ fseek(pFile, 0, SEEK_SET);
+ fread(desc.dest, 1, lenFile, pFile);
+
+ //clean up
+ fclose(pFile);
+ pFile=NULL;
+ remove(pTempFileName);
+ }
+ catch(r_Error& err)
+ {
+ //cleanup
+ if(!hasSrcType)
+ {
+ delete desc.srcType;
+ desc.srcType=NULL;
+ }
+
+ //desc.destType
+ if(desc.destType)
+ {
+ delete desc.destType;
+ desc.destType=NULL;
+ }
+
+ //desc.dest
+ if(desc.dest)
+ {
+ mystore.storage_free(desc.dest);
+ desc.dest=NULL;
+ }
+
+ //rethrow error
+ throw;
+ }
+
+ //clean up
+ if(!hasSrcType)
+ {
+ delete desc.srcType;
+ desc.srcType=NULL;
+ }
+
+ //return result
+ return desc;
+}
+
+const char*
+r_Conv_int16::get_name() const throw()
+{
+ return get_name_from_data_format(r_int16);
+}
+
+r_Data_Format
+r_Conv_int16::get_data_format() const throw()
+{
+ return r_int16;
+}
+
+r_Convertor*
+r_Conv_int16::clone() const throw(r_Error)
+{
+ return new r_Conv_int16(desc.src, desc.srcInterv, desc.srcType);
+}
diff --git a/conversion/int16.hh b/conversion/int16.hh
new file mode 100644
index 0000000..c8d9f98
--- /dev/null
+++ b/conversion/int16.hh
@@ -0,0 +1,205 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: int16.hh
+ *
+ * MODULE: conversion
+ *
+ * CLASSES: r_Conv_int16
+ *
+ * COMMENTS:
+ * Provides interface to convert data to other formats.
+*/
+
+#ifndef _R_CONV_int16_HH_
+#define _R_CONV_int16_HH_
+
+#include <sstream>
+#include <vector>
+#include <string>
+#include <cstdio>
+using std::vector;
+using std::ofstream;
+using std::string;
+
+#include "conversion/convertor.hh"
+#include "raslib/odmgtypes.hh"
+
+//@ManMemo: Module {\bf conversion}
+
+/*@Doc:
+ int16 convertor class.
+
+ Supported parameters are
+
+ \begin{tabular}{lcl}
+ {\tt flipx} && int && flip image flag on x axis, default 0\\
+ {\tt flipy} && int && flip image flag on y axis, default 1\\
+ {\tt startx} && double && start value on x axis \\
+ {\tt endx} && double && end value on x axis \\
+ {\tt sizex} && int && number of pixels in horizontal direction (int >0)
+ {\tt sizey} && int && number of pixels in vertical direction (int >0)
+ {\tt resx} && double && resolution on x axis \\
+ {\tt starty} && double && start value on y axis \\
+ {\tt endy} && double && end value on y axis \\
+ {\tt resy} && double && resolution on y axis \\
+ {\tt hstep} && double && resolution on h axis \\
+ \end{tabular}
+
+ The "flipx" parameter is a flag for mirroring the image on x axis.
+ The "flipy" parameter is a flag for mirroring the image on y axis.
+ [startx:endx, starty:endy] represents the geographical bounding box
+ of the whole image. The corresponding pixel bounding box is calculated
+ as follows:
+ if flipy is disabled:
+ [(minx-startx)/resx:(maxx-startx)/resx, (miny-starty)/resy:(maxy-starty)/resy]
+ else
+ [(minx-startx)/resx:(maxx-startx)/resx, (endy-maxy)/resy:(endy-miny)/resy]
+
+ if flipx is disabled:
+ [(minx-startx)/resx:(maxx-startx)/resx, (miny-starty)/resy:(maxy-starty)/resy]
+ else
+ [(endx-maxx)/resx:(endx-minx)/resx, (miny-starty)/resy:(maxy-starty)/resy]
+
+ The pairs (startx, endx, resx), (starty, endy, resy) apply to the whole MDD object in the database
+ whereas the pairs (minx,maxx, resx), (miny, maxy, resy) describe the part of image under consideration.
+ They are used to compute the update part's position in RasDaMan coordinates.
+ Value hstep is vertical resolution (multiplied into the value read during conversion into internal format).
+*/
+
+
+Format specification: int16
+
+input parameters:
+ geox geo reference x of upper left point (float >0)
+ geoy geo reference y of upper left point (float >0)
+ resx horizontal resolution (pixel distance) in meters (float >0)
+ resy vertical resolution (pixel distance) in meters (float >0)
+ hstep factor by which pixel values have to be multiplied to obtain real height in meters (float >0)
+
+
+An int16 file contains a sequence of sizex*sizey height values, advancing from west to east and from north to south. Each pixel consists of a 16 bit integer where the lower byte comes first in sequence (i.e., pixel value is byte[i]+byte[i+1]*256).
+There is no file header, pixels start immediately at the beginning.
+
+Points are defined as follows for pixel position (i,j) in file (starting with (0/0):
+ geo position x = geox + i*resx
+ geo position y = geoy + j*resy
+ height = ( byte[ 2*i + 2*j*sizex] + byte[ 2*i + 2*j*sizex + 1] * 256 ) * hstep
+
+where / denotes integer division
+
+class r_Conv_int16 : public r_Convertor
+{
+ public:
+ // constants to handle NULL
+ static const r_Double NULL_DB;
+ static const r_Double ZERO_DB;
+ static const r_Double ZERO_int16;
+
+ //inner class for convertor parameters
+ class r_GeoBBox
+ {
+ public:
+ r_Double startx, endx, resx;
+ r_Double starty, endy, resy;
+ r_ULong flipy, flipx;
+ };
+
+ r_Conv_int16(const char* source, const r_Minterval& lengthordomain, const r_Type* tp) throw(r_Error);
+
+ r_Conv_int16(const char* source, const r_Minterval& lengthordomain, int tp) throw(r_Error);
+
+ r_convDesc& convertFrom(const char* options = NULL) throw (r_Error);
+
+ r_convDesc& convertTo(const char* options = NULL) throw (r_Error);
+
+ const char* get_name() const throw();
+
+ r_Data_Format get_data_format() const throw();
+
+ r_Convertor* clone() const throw(r_Error);
+
+ /// dimension of src domain accepted as input in convertFrom
+ static const r_Dimension srcIntervDim;
+
+ /// dimension of dest domain accepted as input in convertTo
+ static const r_Dimension destIntervDim;
+
+ /// decode convertor options
+ static bool decodeOptions( const char* options,
+ r_GeoBBox& collBBox) throw();
+
+ /// encode convertor options
+ static string encodeOptions(const r_GeoBBox& collBBox) throw();
+
+ /// destructor
+ virtual ~r_Conv_int16( void );
+
+ /// init convertor parameters to default value
+ static void initGeoBBox( r_GeoBBox& cBBox );
+
+ private:
+
+
+ /// check limits before converting
+ void checkLimits() throw(r_Error);
+
+ ///i/o src/dest stream
+ void readFromSrcStream() throw(r_Error);
+ void readToSrcStream() throw(r_Error);
+ void writeFromDestStream() throw(r_Error);
+ void writeToDestStream(ofstream& oFile) throw(r_Error);
+
+ /// parameters
+ r_GeoBBox collBBox;
+
+ /// class constants
+ static const r_ULong paramMin;
+ static const char* paramSep;
+ static const char* paramEq;
+ static const char* paramFlipX;
+ static const char* paramFlipY;
+ static const char* paramStartX;
+ static const char* paramEndX;
+ static const char* paramResX;
+ static const char* paramStartY;
+ static const char* paramEndY;
+ static const char* paramResY;
+
+
+ /// internal data
+ class int16Row
+ {
+ public:
+ r_Double x,y,h;
+ };
+
+ typedef vector<int16Row> int16RowVec;
+
+ int16Row min, max;
+ int16RowVec demRows;
+
+ };
+
+#endif
+
diff --git a/conversion/jpeg.cc b/conversion/jpeg.cc
new file mode 100644
index 0000000..7638d82
--- /dev/null
+++ b/conversion/jpeg.cc
@@ -0,0 +1,530 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: jpeg.cc
+ *
+ * MODULE: conversion
+ *
+ * CLASSES: r_Conv_JPEG
+ *
+ * COMMENTS:
+ *
+ * Provides functions to convert data to JPEG and back
+ *
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <iostream>
+#include <string.h>
+#include <setjmp.h>
+
+extern "C" {
+#include "jpeglib.h"
+}
+
+#include "raslib/rminit.hh"
+#include "raslib/parseparams.hh"
+#include "conversion/jpeg.hh"
+#include "conversion/memfs.hh"
+
+
+
+#define JPEG_IO_BUFFER_SIZE 4096
+
+
+// JPEG-interface in C-namespace (like JPEG lib)
+extern "C" {
+
+
+typedef struct my_compress_struct {
+ jpeg_compress_struct pub;
+ thandle_t handle;
+ JOCTET *buffer;
+ int bufferSize;
+} my_compress_struct;
+
+typedef struct my_decompress_struct {
+ jpeg_decompress_struct pub;
+ thandle_t handle;
+ JOCTET *buffer;
+ int bufferSize;
+} my_decompress_struct;
+
+typedef struct my_error_mgr {
+ jpeg_error_mgr pub;
+ jmp_buf setjmp_buffer;
+} my_error_mgr;
+
+
+// See jpeg library example
+static void my_error_exit(jpeg_common_struct *cptr)
+{
+ my_error_mgr *myerr = (my_error_mgr*)(cptr->err);
+ (*cptr->err->output_message)(cptr);
+ longjmp(myerr->setjmp_buffer, 1);
+}
+
+
+
+/*
+ * Memory IO wrapper functions, rely on memFS.
+ */
+
+// Destination manager methods
+// cptr is actually a pointer to my_compress_struct
+static void dm_init_destination(jpeg_compress_struct *cptr)
+{
+ my_compress_struct *mptr = (my_compress_struct*)cptr;
+
+ if ((mptr->buffer = new JOCTET[JPEG_IO_BUFFER_SIZE]) == NULL)
+ {
+ RMInit::logOut << "r_Conv_JPEG@dm_init_destination(): out of memory" << endl;
+ throw r_Error(MEMMORYALLOCATIONERROR);
+ }
+ mptr->bufferSize = JPEG_IO_BUFFER_SIZE;
+ cptr->dest->next_output_byte = mptr->buffer; cptr->dest->free_in_buffer = mptr->bufferSize;
+}
+
+
+static boolean dm_empty_output_buffer(jpeg_compress_struct *cptr)
+{
+ my_compress_struct *mptr = (my_compress_struct*)cptr;
+ boolean retval=FALSE;
+
+ if (memfs_write(mptr->handle, mptr->buffer, mptr->bufferSize) == mptr->bufferSize)
+ {
+ cptr->dest->next_output_byte = mptr->buffer; cptr->dest->free_in_buffer = mptr->bufferSize;
+ retval=TRUE;
+ }
+ return retval;
+}
+
+
+static void dm_term_destination(jpeg_compress_struct *cptr)
+{
+ my_compress_struct *mptr = (my_compress_struct*)cptr;
+
+ if (cptr->dest->next_output_byte != mptr->buffer)
+ {
+ memfs_write(mptr->handle, mptr->buffer, (cptr->dest->next_output_byte - mptr->buffer));
+ }
+ delete [] mptr->buffer; mptr->buffer = NULL;
+}
+
+
+// Source manager methods
+// dptr is actually a pointer to my_decompress_struct
+static void sm_init_source(jpeg_decompress_struct *dptr)
+{
+ my_decompress_struct *mptr = (my_decompress_struct*)dptr;
+
+ if ((mptr->buffer = new JOCTET[JPEG_IO_BUFFER_SIZE]) == NULL)
+ {
+ RMInit::logOut << "r_Conv_JPEG@sm_init_source(): out of memory" << endl;
+ throw r_Error(MEMMORYALLOCATIONERROR);
+ }
+ mptr->bufferSize = JPEG_IO_BUFFER_SIZE;
+ dptr->src->next_input_byte = mptr->buffer; dptr->src->bytes_in_buffer = 0;
+}
+
+
+// See jdatasrc.c
+static boolean sm_fill_input_buffer(jpeg_decompress_struct *dptr)
+{
+ my_decompress_struct *mptr = (my_decompress_struct*)dptr;
+ int read_bytes=0;
+
+ if ((read_bytes = memfs_chunk_read(mptr->handle, mptr->buffer, mptr->bufferSize)) != 0)
+ {
+ dptr->src->bytes_in_buffer = read_bytes;
+ }
+ else
+ {
+ mptr->buffer[0] = (JOCTET)0xff;
+ mptr->buffer[1] = (JOCTET)JPEG_EOI;
+ dptr->src->bytes_in_buffer = 2;
+ }
+ dptr->src->next_input_byte = mptr->buffer;
+
+ return TRUE;
+}
+
+
+// See jdatasrc.c
+static void sm_skip_input_data(jpeg_decompress_struct *dptr, long num_bytes)
+{
+ my_decompress_struct *mptr = (my_decompress_struct*)dptr;
+
+ if (num_bytes < dptr->src->bytes_in_buffer)
+ {
+ dptr->src->next_input_byte += num_bytes; dptr->src->bytes_in_buffer -= num_bytes;
+ }
+ else
+ {
+ int read_bytes=0;
+
+ num_bytes -= dptr->src->bytes_in_buffer;
+ dptr->src->next_input_byte = mptr->buffer;
+ while (num_bytes >= mptr->bufferSize)
+ {
+ memfs_chunk_seek(mptr->handle, mptr->bufferSize, SEEK_CUR);
+ num_bytes -= mptr->bufferSize;
+ }
+ read_bytes = memfs_chunk_read(mptr->handle, mptr->buffer, mptr->bufferSize);
+ if (read_bytes <= num_bytes)
+ {
+ mptr->buffer[0] = (JOCTET)0xff;
+ mptr->buffer[1] = (JOCTET)JPEG_EOI;
+ dptr->src->bytes_in_buffer = 2;
+ }
+ else
+ {
+ dptr->src->next_input_byte = mptr->buffer + num_bytes;
+ dptr->src->bytes_in_buffer = read_bytes - num_bytes;
+ }
+ }
+}
+
+
+/*static boolean sm_resync_to_restart(jpeg_decompress_struct *dptr, int desired)
+{
+ return FALSE;
+}*/
+
+
+static void sm_term_source(jpeg_decompress_struct *dptr)
+{
+ my_decompress_struct *mptr = (my_decompress_struct*)dptr;
+
+ delete [] mptr->buffer; mptr->buffer = NULL;
+}
+
+
+} // end of C namespace
+
+
+
+
+/*
+ * r_Conv_JPEG class for converting MDD to JPEG and back
+ */
+
+void r_Conv_JPEG::initJPEG( void )
+{
+ quality = 80;
+
+ if (params == NULL)
+ params = new r_Parse_Params;
+
+ params->add("quality", &quality, r_Parse_Params::param_type_int);
+}
+
+
+r_Conv_JPEG::r_Conv_JPEG(const char *src, const r_Minterval &interv, int tp) throw(r_Error)
+: r_Convert_Memory(src, interv, tp)
+{
+ initJPEG();
+}
+
+
+r_Conv_JPEG::r_Conv_JPEG(const char *src, const r_Minterval &interv, const r_Type *tp) throw(r_Error)
+: r_Convert_Memory(src, interv, tp)
+{
+ initJPEG();
+}
+
+
+r_Conv_JPEG::~r_Conv_JPEG(void)
+{
+}
+
+
+r_convDesc &r_Conv_JPEG::convertTo( const char *options) throw(r_Error)
+{
+ struct jpeg_destination_mgr destMgr;
+ struct jpeg_compress_struct *cptr=NULL;
+ struct jpeg_error_mgr *jptr=NULL;
+ my_error_mgr jerr;
+ my_compress_struct cinfo;
+ int width=0, height=0, lineAdd=0, pixelAdd=0;
+ int i=0, j=0, spp=0;
+ J_COLOR_SPACE jcs;
+ JSAMPROW row_pointers[1];
+ JSAMPLE *row=NULL, *rowPtr=NULL;
+ r_Long jpegSize=0;
+
+ row = NULL;
+ memset(&cinfo, 0, sizeof(my_compress_struct));
+ cinfo.handle = (thandle_t)handle;
+ cptr = (struct jpeg_compress_struct*)&cinfo.pub;
+ jptr = (struct jpeg_error_mgr*)&jerr.pub;
+
+ cptr->err = jpeg_std_error(jptr);
+ jptr->error_exit = my_error_exit;
+
+ params->process(options);
+
+ if (setjmp(jerr.setjmp_buffer))
+ {
+ if (row != NULL) {delete [] row; row = NULL;}
+ jpeg_abort_compress(cptr);
+ jpeg_destroy_compress(cptr);
+ // destination manager destructor might not be called on an abort
+ if (cinfo.buffer != NULL){delete [] cinfo.buffer; cinfo.buffer=NULL;}
+ RMInit::logOut << "r_Conv_JPEG::convertTo(" << options << "): unable to save the stack" << endl;
+ throw r_Error(r_Error::r_Error_General);
+ }
+
+ jpeg_create_compress(cptr);
+ jpeg_set_quality(cptr, quality, 0);
+
+ memfs_newfile(handle);
+
+ destMgr.init_destination = dm_init_destination;
+ destMgr.empty_output_buffer = dm_empty_output_buffer;
+ destMgr.term_destination = dm_term_destination;
+
+ cptr->dest = &destMgr;
+
+ width = (int)(desc.srcInterv[0].high() - desc.srcInterv[0].low() + 1);
+ height = (int)(desc.srcInterv[1].high() - desc.srcInterv[1].low() + 1);
+
+ cptr->image_width = (JDIMENSION)width; cptr->image_height = (JDIMENSION)height;
+
+ switch (desc.baseType)
+ {
+ case ctype_bool:
+ case ctype_char:
+ jcs = JCS_GRAYSCALE; spp = 1; lineAdd = 1; pixelAdd = height; break;
+ case ctype_rgb:
+ jcs = JCS_RGB; spp = 3; lineAdd = 3; pixelAdd = 3*height; break;
+ default:
+ RMInit::logOut << "r_Conv_JPEG::convertTo(" << options << "): unsupported base type" << endl;
+ throw r_Error(r_Error::r_Error_General);
+ }
+
+ cptr->input_components = spp; cptr->in_color_space = jcs;
+
+ jpeg_set_defaults(cptr);
+
+ jpeg_set_quality(cptr, quality, TRUE);
+
+ jpeg_start_compress(cptr, TRUE);
+
+ if ((row = new JSAMPLE[width * spp]) == NULL)
+ {
+ RMInit::logOut << "r_Conv_JPEG::convertTo(" << options << "): out of memory" << endl;
+ throw r_Error(MEMMORYALLOCATIONERROR);
+ }
+
+ row_pointers[0] = row;
+
+ const unsigned char *src=NULL, *srcPtr=NULL;
+
+ src = (const unsigned char*)desc.src;
+
+ for (j=0; j<height; j++, src += lineAdd)
+ {
+ srcPtr = src; rowPtr = row;
+
+ switch (desc.baseType)
+ {
+ case ctype_bool:
+ for (i=0; i<width; i++, srcPtr += pixelAdd)
+ {
+ *rowPtr++ = (*srcPtr == 0) ? 0 : 0xff;
+ }
+ break;
+ case ctype_char:
+ for (i=0; i<width; i++, srcPtr += pixelAdd)
+ {
+ *rowPtr++ = *srcPtr;
+ }
+ break;
+ case ctype_rgb:
+ for (i=0; i<width; i++, srcPtr += pixelAdd)
+ {
+ *rowPtr++ = srcPtr[0]; *rowPtr++ = srcPtr[1]; *rowPtr++ = srcPtr[2];
+ }
+ break;
+ }
+ jpeg_write_scanlines(cptr, row_pointers, 1);
+ }
+
+ delete [] row; row = NULL;
+
+ jpeg_finish_compress(cptr);
+
+ jpeg_destroy_compress(cptr);
+
+ jpegSize = memfs_size(handle);
+
+ if ((desc.dest = (char*)mystore.storage_alloc(jpegSize)) == NULL)
+ {
+ RMInit::logOut << "r_Conv_JPEG::convertTo(" << options << "): out of memory" << endl;
+ throw r_Error(MEMMORYALLOCATIONERROR);
+ }
+ memfs_seek(handle, 0, SEEK_SET);
+ memfs_read(handle, desc.dest, jpegSize);
+
+ desc.destInterv = r_Minterval(1);
+ desc.destInterv << r_Sinterval((r_Range)0, (r_Range)jpegSize - 1);
+
+ desc.destType = r_Type::get_any_type("char");
+
+ return desc;
+}
+
+
+r_convDesc &r_Conv_JPEG::convertFrom(const char *options) throw(r_Error)
+{
+ struct jpeg_source_mgr srcMgr;
+ struct jpeg_decompress_struct *dptr=NULL;
+ struct jpeg_error_mgr *jptr=NULL;
+ my_error_mgr jerr;
+ my_decompress_struct cinfo;
+ int width=0, height=0, lineAdd=0, pixelAdd=0;
+ int i=0, j=0, spp=0;
+ J_COLOR_SPACE jcs;
+ JSAMPROW row_pointers[1];
+ JSAMPLE *row=NULL, *rowPtr=NULL;
+ char *dest=NULL, *destPtr=NULL;
+
+ row = NULL; desc.dest = NULL;
+ memset(&cinfo, 0, sizeof(my_decompress_struct));
+ cinfo.handle = (thandle_t)handle;
+ dptr = (struct jpeg_decompress_struct*)&cinfo.pub;
+ jptr = (struct jpeg_error_mgr*)&jerr.pub;
+
+ dptr->err = jpeg_std_error(jptr);
+ jptr->error_exit = my_error_exit;
+
+ if (setjmp(jerr.setjmp_buffer))
+ {
+ if (row != NULL) {delete [] row; row = NULL;}
+ if (desc.dest != NULL) {mystore.storage_free(desc.dest); desc.dest = NULL;}
+ jpeg_abort_decompress(dptr);
+ jpeg_destroy_decompress(dptr);
+ // Source manager destructor might not be called on an abort
+ if (cinfo.buffer != NULL) {delete [] cinfo.buffer; cinfo.buffer=NULL;}
+ RMInit::logOut << "r_Conv_JPEG::convertFrom(" << options << "): unable to save the stack" << endl;
+ throw r_Error(r_Error::r_Error_General);
+ }
+
+ jpeg_create_decompress(dptr);
+
+ memfs_chunk_initfs(handle, (char*)desc.src, (r_Long)(desc.srcInterv[0].high() - desc.srcInterv[0].low() + 1));
+
+ srcMgr.init_source = sm_init_source;
+ srcMgr.fill_input_buffer = sm_fill_input_buffer;
+ srcMgr.skip_input_data = sm_skip_input_data;
+ srcMgr.resync_to_restart = NULL; //sm_resync_to_restart;
+ srcMgr.term_source = sm_term_source;
+
+ dptr->src = &srcMgr;
+
+ jpeg_read_header(dptr, TRUE);
+ width = (int)(dptr->image_width); height = (int)(dptr->image_height);
+
+ if (dptr->num_components == 1)
+ {
+ desc.baseType = ctype_char;
+ lineAdd = 1; pixelAdd = height;
+ }
+ else
+ {
+ desc.baseType = ctype_rgb;
+ lineAdd = 3; pixelAdd = 3*height;
+ dptr->out_color_space = JCS_RGB;
+ }
+
+ jpeg_start_decompress(dptr);
+
+ spp = (int)(dptr->output_components);
+
+ row = new JSAMPLE[width * spp];
+ desc.dest = (char*)mystore.storage_alloc(width * height * spp);
+
+ if ((row == NULL) || (desc.dest == NULL))
+ {
+ if (row != NULL) {delete [] row; row = NULL;}
+ RMInit::logOut << "r_Conv_JPEG::convertFrom(): out of memory" << endl;
+ throw r_Error(MEMMORYALLOCATIONERROR);
+ }
+
+ row_pointers[0] = row; dest = desc.dest;
+ for (j=0; j<height; j++, dest += lineAdd)
+ {
+ jpeg_read_scanlines(dptr, row_pointers, 1);
+ destPtr = dest; rowPtr = row;
+ switch (spp)
+ {
+ case 1:
+ for (i=0; i<width; i++, destPtr += pixelAdd)
+ {
+ *destPtr = *rowPtr++;
+ }
+ break;
+ case 3:
+ for (i=0; i<width; i++, destPtr += pixelAdd)
+ {
+ destPtr[0] = *rowPtr++; destPtr[1] = *rowPtr++; destPtr[2] = *rowPtr++;
+ }
+ break;
+ }
+ }
+
+ delete [] row; row = NULL;
+
+ jpeg_finish_decompress(dptr);
+
+ jpeg_destroy_decompress(dptr);
+
+ desc.destInterv = r_Minterval(2);
+ desc.destInterv << r_Sinterval((r_Range)0, (r_Range)width-1)
+ << r_Sinterval((r_Range)0, (r_Range)height-1);
+
+ desc.destType = get_external_type(desc.baseType);
+
+ return desc;
+}
+
+
+
+const char *r_Conv_JPEG::get_name( void ) const
+{
+ return format_name_jpeg;
+}
+
+
+r_Data_Format r_Conv_JPEG::get_data_format( void ) const
+{
+ return r_JPEG;
+}
+
+
+r_Convertor *r_Conv_JPEG::clone( void ) const
+{
+ return new r_Conv_JPEG(desc.src, desc.srcInterv, desc.baseType);
+}
diff --git a/conversion/jpeg.hh b/conversion/jpeg.hh
new file mode 100644
index 0000000..2c2bb6b
--- /dev/null
+++ b/conversion/jpeg.hh
@@ -0,0 +1,84 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: jpeg.hh
+ *
+ * MODULE: conversion
+ *
+ * CLASSES: r_Conv_JPEG
+ *
+ * COMMENTS:
+ *
+ * Provides interface to convert data to JPEG and back.
+ *
+*/
+
+#ifndef _R_CONV_JPEG_HH_
+#define _R_CONV_JPEG_HH_
+
+#include "conversion/convertor.hh"
+
+
+//@ManMemo: Module {\bf conversion}
+
+/*@Doc:
+ JPEG convertor class.
+
+ Supported parameters are
+
+ \begin{tabular}{lcl}
+ quality && int && quality ratio between 0 and 100
+ \end{tabular}
+
+ */
+
+class r_Conv_JPEG : public r_Convert_Memory
+{
+ public:
+ /// constructor using an r_Type object
+ r_Conv_JPEG( const char *src, const r_Minterval &interv, const r_Type *tp ) throw(r_Error);
+ /// constructor using convert_type_e shortcut
+ r_Conv_JPEG( const char *src, const r_Minterval &interv, int tp ) throw(r_Error);
+ /// destructor
+ ~r_Conv_JPEG( void );
+
+ /// convert to JPEG
+ virtual r_convDesc &convertTo( const char *options=NULL ) throw(r_Error);
+ /// convert from JPEG
+ virtual r_convDesc &convertFrom( const char *options=NULL ) throw(r_Error);
+ /// cloning
+ virtual r_Convertor *clone( void ) const;
+ /// identification
+ virtual const char *get_name( void ) const;
+ virtual r_Data_Format get_data_format( void ) const;
+
+
+ private:
+ /// init JPEG class
+ void initJPEG( void );
+
+ /// parameters
+ int quality;
+};
+
+#endif
diff --git a/conversion/memfs.c b/conversion/memfs.c
new file mode 100644
index 0000000..c346880
--- /dev/null
+++ b/conversion/memfs.c
@@ -0,0 +1,421 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: memfs.c
+ *
+ * MODULE: conversion
+ *
+ * PURPOSE:
+ * Memory Filing System used by some of the convertor modules
+ *
+ * COMMENTS
+ * None
+*/
+
+#include "mymalloc/mymalloc.h"
+
+#include <stdio.h>
+#include <malloc.h>
+#include <string.h>
+#include "conversion/memfs.hh"
+
+
+/* can't use RMDBGOUT because this is C, not C++ */
+const int MEMFSDBGLEVEL = 4;
+
+extern int RManDebug;
+
+
+
+/* This function for internal use only */
+int memfs_ensure(thandle_t handle, toff_t off)
+{
+ memFSContext *memFS = (memFSContext *)handle;
+ char **mam2=NULL;
+ int mamSize2=0, i=0;
+
+#ifdef RMANDEBUG
+ if (RManDebug >= MEMFSDBGLEVEL)
+ {
+ printf("memfs_ensure: %d\n", off); fflush(stdout);
+ }
+#endif
+ /* Do we have to allocate a bigger mam? */
+ mamSize2 = (off >> MEMFS_LD_BLOCKSIZE);
+ if (mamSize2 >= memFS->mamSize)
+ {
+ /* Always allocate mam in powers of 2. That ensures that if we run out
+ of space the new mam will be twice as big as the old one. */
+ i = 0; while (mamSize2 != 0) {mamSize2 >>= 1; i++;}
+ mamSize2 = (1 << i);
+#ifdef RMANDEBUG
+ if (RManDebug >= MEMFSDBGLEVEL)
+ {
+ printf("memfs_ensure: growing mam from %d to %d\n", memFS->mamSize, mamSize2);
+ fflush(stdout);
+ }
+#endif
+ if ((mam2 = (char **)mymalloc(mamSize2 * sizeof(char*))) == NULL)
+ return -1;
+ /* Copy existing mam entries */
+ memcpy ((void*)mam2, (void*) memFS->mam, memFS->mamSize * sizeof(char*));
+ /* Init new mam entries */
+ for (i=memFS->mamSize; i < mamSize2; i++)
+ {
+ mam2[i] = NULL;
+ }
+ /* free old mam */
+ free(memFS->mam);
+ memFS->mam = mam2; memFS->mamSize = mamSize2;
+ }
+ /* Calculate again because its value might have been changed by the
+ above block */
+ mamSize2 = (off >> MEMFS_LD_BLOCKSIZE);
+ if ((memFS->mam)[mamSize2] == NULL)
+ {
+ /* We don't just have to allocate this one new block but all the
+ ones with lower addresses that aren't defined yet as well */
+ for (i=memFS->mamHighest+1; i <= mamSize2; i++)
+ {
+ if (((memFS->mam)[i] = (char*)mymalloc((1 << MEMFS_LD_BLOCKSIZE) * sizeof(char))) == NULL)
+ return -1;
+ }
+ memFS->mamHighest = mamSize2;
+ }
+ /* All done, the memFS can now hold an object of size off */
+ return 0;
+}
+
+
+/* Initialise the memory filing system */
+int memfs_initfs(thandle_t handle)
+{
+ memFSContext *memFS = (memFSContext *)handle;
+ int i=0;
+
+#ifdef RMANDEBUG
+ if (RManDebug >= MEMFSDBGLEVEL)
+ {
+ printf("memfs_initfs\n"); fflush(stdout);
+ }
+#endif
+ memFS->pos = 0; memFS->high = 0;
+ memFS->mamSize = MEMFS_MAM_ENTRIES;
+ if ((memFS->mam = (char **)mymalloc(MEMFS_MAM_ENTRIES * sizeof(char *))) == NULL)
+ return -1;
+ if (((memFS->mam)[0] = (char*)mymalloc((1 << MEMFS_LD_BLOCKSIZE) * sizeof(char))) == NULL)
+ return -1;
+ memFS->mamHighest = 0;
+ for (i=1; i<MEMFS_MAM_ENTRIES; i++)
+ {
+ (memFS->mam)[i] = NULL;
+ }
+ return 0;
+}
+
+
+/* Kill the memory filing system, freeing all its resources */
+void memfs_killfs(thandle_t handle)
+{
+ memFSContext *memFS = (memFSContext *)handle;
+ int i=0;
+
+#ifdef RMANDEBUG
+ if (RManDebug >= MEMFSDBGLEVEL)
+ {
+ printf("memfs_killfs\n"); fflush(stdout);
+ }
+#endif
+ for (i=0; i < memFS->mamSize; i++)
+ {
+ if ((memFS->mam)[i] == NULL) break;
+ free((memFS->mam)[i]);
+ }
+ free(memFS->mam);
+}
+
+
+/* Reset file pointers, leave memory setup */
+void memfs_newfile(thandle_t handle)
+{
+ memFSContext *memFS = (memFSContext *)handle;
+
+#ifdef RMANDEBUG
+ if (RManDebug >= MEMFSDBGLEVEL)
+ {
+ printf("memfs_newfile\n"); fflush(stdout);
+ }
+#endif
+ memFS->pos = 0; memFS->high = 0;
+}
+
+
+tsize_t memfs_read(thandle_t handle, tdata_t mem, tsize_t size)
+{
+ tsize_t todo=0, transfered = 0;
+ int block=0, offset=0, x=0;
+ memFSContext *memFS = (memFSContext *)handle;
+
+ /* Don't read over the end of the "file" */
+ todo = memFS->high - memFS->pos;
+#ifdef RMANDEBUG
+ if (RManDebug >= MEMFSDBGLEVEL)
+ {
+ printf("memfs_read: (%d, left: %d)\n", todo, memFS->high); fflush(stdout);
+ }
+#endif
+ if (todo > size) todo = size;
+ while (todo > 0)
+ {
+ block = (memFS->pos >> MEMFS_LD_BLOCKSIZE);
+ offset = memFS->pos - (block << MEMFS_LD_BLOCKSIZE);
+ /* Space left in this buffer */
+ x = (1 << MEMFS_LD_BLOCKSIZE) - offset;
+ if (x > todo) x = todo;
+ memcpy((void*)mem, (void*)(((memFS->mam)[block]) + offset), x);
+ /* tdata_t is some kind of void *, so we have to do this cast */
+ mem = (tdata_t)(((char*)mem) + x);
+ memFS->pos += x; transfered += x; todo -= x;
+ }
+ return transfered;
+}
+
+
+tsize_t memfs_write(thandle_t handle, tdata_t mem, tsize_t size)
+{
+ tsize_t transfered = 0;
+ memFSContext *memFS = (memFSContext *)handle;
+ int block=0, offset=0, x=0;
+
+ /* Make sure there's enough room for this write */
+ if (memfs_ensure(handle, memFS->pos + size) < 0) return 0;
+#ifdef RMANDEBUG
+ if (RManDebug >= MEMFSDBGLEVEL)
+ {
+ printf("memfs_write (%d)\n",size); fflush(stdout);
+ }
+#endif
+ while (size > 0)
+ {
+ /* See memfs_read */
+ block = (memFS->pos >> MEMFS_LD_BLOCKSIZE);
+ offset = memFS->pos - (block << MEMFS_LD_BLOCKSIZE);
+ x = (1 << MEMFS_LD_BLOCKSIZE) - offset;
+ if (x > size) x = size;
+ memcpy((void*)(((memFS->mam)[block]) + offset), (void*)mem, x);
+ mem = (tdata_t)(((char *)mem) + x);
+ memFS->pos += x; transfered += x; size -= x;
+ }
+ if (memFS->pos > memFS->high) {memFS->high = memFS->pos;}
+ return transfered;
+}
+
+
+toff_t memfs_seek(thandle_t handle, toff_t offset, int mode)
+{
+ memFSContext *memFS = (memFSContext *)handle;
+
+ switch (mode)
+ {
+ case SEEK_SET: memFS->pos = offset; break;
+ case SEEK_CUR: memFS->pos += offset; break;
+ case SEEK_END: memFS->pos = memFS->high + offset; break;
+ default: break;
+ }
+ if (memFS->pos < 0) memFS->pos = 0;
+ /* Don't limit to end of file (this actually caused problems!) */
+ memfs_ensure(handle, memFS->pos);
+ if (memFS->pos > memFS->high) memFS->high = memFS->pos;
+#ifdef RMANDEBUG
+ if (RManDebug >= MEMFSDBGLEVEL)
+ {
+ printf("memfs_seek: Set pos to %d\n", memFS->pos); fflush(stdout);
+ }
+#endif
+ return memFS->pos;
+}
+
+
+int memfs_close(thandle_t handle)
+{
+#ifdef RMANDEBUG
+ if (RManDebug >= MEMFSDBGLEVEL)
+ {
+ printf("memfs_close:\n"); fflush(stdout);
+ }
+#endif
+ return 1; /* = success? */
+}
+
+
+toff_t memfs_size(thandle_t handle)
+{
+#ifdef RMANDEBUG
+ if (RManDebug >= MEMFSDBGLEVEL)
+ {
+ printf("memfs_size:\n"); fflush(stdout);
+ }
+#endif
+ return (((memFSContext *)handle)->high);
+}
+
+
+int memfs_map(thandle_t handle, tdata_t *memp, toff_t *top)
+{
+#ifdef RMANDEBUG
+ if (RManDebug >= MEMFSDBGLEVEL)
+ {
+ printf("memfs_map: %p, %d\n", *memp, *top); fflush(stdout);
+ }
+#endif
+ return 0;
+}
+
+
+void memfs_unmap(thandle_t handle, tdata_t mem, toff_t to)
+{
+#ifdef RMANDEBUG
+ if (RManDebug >= MEMFSDBGLEVEL)
+ {
+ printf("memfs_unmap: %p, %d\n", mem, to); fflush(stdout);
+ }
+#endif
+}
+
+
+
+
+
+
+/* Read-only from memory (simple chunky model, not block-oriented) */
+void memfs_chunk_initfs(thandle_t handle, char *src, r_Long size)
+{
+ memFSContext *memFS = (memFSContext *)handle;
+
+#ifdef RMANDEBUG
+ if (RManDebug >= MEMFSDBGLEVEL)
+ {
+ printf("memfs_chunk_initfs: %p, %d\n", src, size); fflush(stdout);
+ }
+#endif
+ memFS->pos = 0;
+ memFS->chunk = src;
+ memFS->high = size;
+}
+
+
+tsize_t memfs_chunk_read(thandle_t handle, tdata_t mem, tsize_t size)
+{
+ tsize_t todo=0;
+ memFSContext *memFS = (memFSContext *)handle;
+
+ todo = memFS->high - memFS->pos;
+#ifdef RMANDEBUG
+ if (RManDebug >= MEMFSDBGLEVEL)
+ {
+ printf("memfs_chunk_read: %d (left %d)\n", size, todo); fflush(stdout);
+ }
+#endif
+ if (todo > size) todo = size;
+ if (todo > 0)
+ {
+ memcpy((void*)mem, (void*)(memFS->chunk + memFS->pos), todo);
+ memFS->pos += todo;
+ }
+ return todo;
+}
+
+
+toff_t memfs_chunk_seek(thandle_t handle, toff_t offset, int mode)
+{
+ memFSContext *memFS = (memFSContext *)handle;
+
+ switch (mode)
+ {
+ case SEEK_SET: memFS->pos = offset; break;
+ case SEEK_CUR: memFS->pos += offset; break;
+ case SEEK_END: memFS->pos = memFS->high + offset; break;
+ default: break;
+ }
+ if (memFS->pos < 0) memFS = 0;
+ /* Since file can't be extended this is OK here */
+ if (memFS->pos > memFS->high) memFS->pos = memFS->high;
+#ifdef RMANDEBUG
+ if (RManDebug >= MEMFSDBGLEVEL)
+ {
+ printf("memfs_chunk_seek: Position to %d\n", memFS->pos); fflush(stdout);
+ }
+#endif
+ return memFS->pos;
+}
+
+
+int memfs_chunk_close(thandle_t handle)
+{
+#ifdef RMANDEBUG
+ if (RManDebug >= MEMFSDBGLEVEL)
+ {
+ printf("memfs_chunk_close:\n"); fflush(stdout);
+ }
+#endif
+ return 1;
+}
+
+
+toff_t memfs_chunk_size(thandle_t handle)
+{
+#ifdef RMANDEBUG
+ if (RManDebug >= MEMFSDBGLEVEL)
+ {
+ printf("memfs_chunk_size:\n"); fflush(stdout);
+ }
+#endif
+ return (((memFSContext *)handle)->high);
+}
+
+
+/* Map file to memory -- since we already have it in memory in the
+ first place this is very simple. */
+int memfs_chunk_map(thandle_t handle, tdata_t *memp, toff_t *top)
+{
+ memFSContext *memFS = (memFSContext *)handle;
+
+#ifdef RMANDEBUG
+ if (RManDebug >= MEMFSDBGLEVEL)
+ {
+ printf("memfs_chunk_map:\n"); fflush(stdout);
+ }
+#endif
+ *memp = (tdata_t)(memFS->chunk); *top = (toff_t)(memFS->high);
+ return 1; /* Success? */
+}
+
+void memfs_chunk_unmap(thandle_t handle, tdata_t mem, toff_t to)
+{
+#ifdef RMANDEBUG
+ if (RManDebug >= MEMFSDBGLEVEL)
+ {
+ printf("memfs_chunk_unmap: %p, %d\n", mem, to); fflush(stdout);
+ }
+#endif
+}
diff --git a/conversion/memfs.cc b/conversion/memfs.cc
new file mode 100644
index 0000000..8dca196
--- /dev/null
+++ b/conversion/memfs.cc
@@ -0,0 +1,421 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: memfs.c
+ *
+ * MODULE: conversion
+ *
+ * PURPOSE:
+ * Memory Filing System used by some of the convertor modules
+ *
+ * COMMENTS:
+ * None
+*/
+
+#include "mymalloc/mymalloc.h"
+
+#include <stdio.h>
+#include <malloc.h>
+#include <string.h>
+#include "conversion/memfs.hh"
+
+
+/* can't use RMDBGOUT because this is C, not C++ */
+const int MEMFSDBGLEVEL = 4;
+
+extern int RManDebug;
+
+
+
+/* This function for internal use only */
+int memfs_ensure(thandle_t handle, toff_t off)
+{
+ memFSContext *memFS = (memFSContext *)handle;
+ char **mam2=NULL;
+ int mamSize2=0, i=0;
+
+#ifdef RMANDEBUG
+ if (RManDebug >= MEMFSDBGLEVEL)
+ {
+ printf("memfs_ensure: %d\n", off); fflush(stdout);
+ }
+#endif
+ /* Do we have to allocate a bigger mam? */
+ mamSize2 = (off >> MEMFS_LD_BLOCKSIZE);
+ if (mamSize2 >= memFS->mamSize)
+ {
+ /* Always allocate mam in powers of 2. That ensures that if we run out
+ of space the new mam will be twice as big as the old one. */
+ i = 0; while (mamSize2 != 0) {mamSize2 >>= 1; i++;}
+ mamSize2 = (1 << i);
+#ifdef RMANDEBUG
+ if (RManDebug >= MEMFSDBGLEVEL)
+ {
+ printf("memfs_ensure: growing mam from %d to %d\n", memFS->mamSize, mamSize2);
+ fflush(stdout);
+ }
+#endif
+ if ((mam2 = (char **)mymalloc(mamSize2 * sizeof(char*))) == NULL)
+ return -1;
+ /* Copy existing mam entries */
+ memcpy ((void*)mam2, (void*) memFS->mam, memFS->mamSize * sizeof(char*));
+ /* Init new mam entries */
+ for (i=memFS->mamSize; i < mamSize2; i++)
+ {
+ mam2[i] = NULL;
+ }
+ /* free old mam */
+ free(memFS->mam);
+ memFS->mam = mam2; memFS->mamSize = mamSize2;
+ }
+ /* Calculate again because its value might have been changed by the
+ above block */
+ mamSize2 = (off >> MEMFS_LD_BLOCKSIZE);
+ if ((memFS->mam)[mamSize2] == NULL)
+ {
+ /* We don't just have to allocate this one new block but all the
+ ones with lower addresses that aren't defined yet as well */
+ for (i=memFS->mamHighest+1; i <= mamSize2; i++)
+ {
+ if (((memFS->mam)[i] = (char*)mymalloc((1 << MEMFS_LD_BLOCKSIZE) * sizeof(char))) == NULL)
+ return -1;
+ }
+ memFS->mamHighest = mamSize2;
+ }
+ /* All done, the memFS can now hold an object of size off */
+ return 0;
+}
+
+
+/* Initialise the memory filing system */
+int memfs_initfs(thandle_t handle)
+{
+ memFSContext *memFS = (memFSContext *)handle;
+ int i=0;
+
+#ifdef RMANDEBUG
+ if (RManDebug >= MEMFSDBGLEVEL)
+ {
+ printf("memfs_initfs\n"); fflush(stdout);
+ }
+#endif
+ memFS->pos = 0; memFS->high = 0;
+ memFS->mamSize = MEMFS_MAM_ENTRIES;
+ if ((memFS->mam = (char **)mymalloc(MEMFS_MAM_ENTRIES * sizeof(char *))) == NULL)
+ return -1;
+ if (((memFS->mam)[0] = (char*)mymalloc((1 << MEMFS_LD_BLOCKSIZE) * sizeof(char))) == NULL)
+ return -1;
+ memFS->mamHighest = 0;
+ for (i=1; i<MEMFS_MAM_ENTRIES; i++)
+ {
+ (memFS->mam)[i] = NULL;
+ }
+ return 0;
+}
+
+
+/* Kill the memory filing system, freeing all its resources */
+void memfs_killfs(thandle_t handle)
+{
+ memFSContext *memFS = (memFSContext *)handle;
+ int i=0;
+
+#ifdef RMANDEBUG
+ if (RManDebug >= MEMFSDBGLEVEL)
+ {
+ printf("memfs_killfs\n"); fflush(stdout);
+ }
+#endif
+ for (i=0; i < memFS->mamSize; i++)
+ {
+ if ((memFS->mam)[i] == NULL) break;
+ free((memFS->mam)[i]);
+ }
+ free(memFS->mam);
+}
+
+
+/* Reset file pointers, leave memory setup */
+void memfs_newfile(thandle_t handle)
+{
+ memFSContext *memFS = (memFSContext *)handle;
+
+#ifdef RMANDEBUG
+ if (RManDebug >= MEMFSDBGLEVEL)
+ {
+ printf("memfs_newfile\n"); fflush(stdout);
+ }
+#endif
+ memFS->pos = 0; memFS->high = 0;
+}
+
+
+tsize_t memfs_read(thandle_t handle, tdata_t mem, tsize_t size)
+{
+ tsize_t todo=0, transfered = 0;
+ int block=0, offset=0, x=0;
+ memFSContext *memFS = (memFSContext *)handle;
+
+ /* Don't read over the end of the "file" */
+ todo = memFS->high - memFS->pos;
+#ifdef RMANDEBUG
+ if (RManDebug >= MEMFSDBGLEVEL)
+ {
+ printf("memfs_read: (%d, left: %d)\n", todo, memFS->high); fflush(stdout);
+ }
+#endif
+ if (todo > size) todo = size;
+ while (todo > 0)
+ {
+ block = (memFS->pos >> MEMFS_LD_BLOCKSIZE);
+ offset = memFS->pos - (block << MEMFS_LD_BLOCKSIZE);
+ /* Space left in this buffer */
+ x = (1 << MEMFS_LD_BLOCKSIZE) - offset;
+ if (x > todo) x = todo;
+ memcpy((void*)mem, (void*)(((memFS->mam)[block]) + offset), x);
+ /* tdata_t is some kind of void *, so we have to do this cast */
+ mem = (tdata_t)(((char*)mem) + x);
+ memFS->pos += x; transfered += x; todo -= x;
+ }
+ return transfered;
+}
+
+
+tsize_t memfs_write(thandle_t handle, tdata_t mem, tsize_t size)
+{
+ tsize_t transfered = 0;
+ memFSContext *memFS = (memFSContext *)handle;
+ int block=0, offset=0, x=0;
+
+ /* Make sure there's enough room for this write */
+ if (memfs_ensure(handle, memFS->pos + size) < 0) return 0;
+#ifdef RMANDEBUG
+ if (RManDebug >= MEMFSDBGLEVEL)
+ {
+ printf("memfs_write (%d)\n",size); fflush(stdout);
+ }
+#endif
+ while (size > 0)
+ {
+ /* See memfs_read */
+ block = (memFS->pos >> MEMFS_LD_BLOCKSIZE);
+ offset = memFS->pos - (block << MEMFS_LD_BLOCKSIZE);
+ x = (1 << MEMFS_LD_BLOCKSIZE) - offset;
+ if (x > size) x = size;
+ memcpy((void*)(((memFS->mam)[block]) + offset), (void*)mem, x);
+ mem = (tdata_t)(((char *)mem) + x);
+ memFS->pos += x; transfered += x; size -= x;
+ }
+ if (memFS->pos > memFS->high) {memFS->high = memFS->pos;}
+ return transfered;
+}
+
+
+toff_t memfs_seek(thandle_t handle, toff_t offset, int mode)
+{
+ memFSContext *memFS = (memFSContext *)handle;
+
+ switch (mode)
+ {
+ case SEEK_SET: memFS->pos = offset; break;
+ case SEEK_CUR: memFS->pos += offset; break;
+ case SEEK_END: memFS->pos = memFS->high + offset; break;
+ default: break;
+ }
+ if (memFS->pos < 0) memFS->pos = 0;
+ /* Don't limit to end of file (this actually caused problems!) */
+ memfs_ensure(handle, memFS->pos);
+ if (memFS->pos > memFS->high) memFS->high = memFS->pos;
+#ifdef RMANDEBUG
+ if (RManDebug >= MEMFSDBGLEVEL)
+ {
+ printf("memfs_seek: Set pos to %d\n", memFS->pos); fflush(stdout);
+ }
+#endif
+ return memFS->pos;
+}
+
+
+int memfs_close(thandle_t handle)
+{
+#ifdef RMANDEBUG
+ if (RManDebug >= MEMFSDBGLEVEL)
+ {
+ printf("memfs_close:\n"); fflush(stdout);
+ }
+#endif
+ return 1; /* = success? */
+}
+
+
+toff_t memfs_size(thandle_t handle)
+{
+#ifdef RMANDEBUG
+ if (RManDebug >= MEMFSDBGLEVEL)
+ {
+ printf("memfs_size:\n"); fflush(stdout);
+ }
+#endif
+ return (((memFSContext *)handle)->high);
+}
+
+
+int memfs_map(thandle_t handle, tdata_t *memp, toff_t *top)
+{
+#ifdef RMANDEBUG
+ if (RManDebug >= MEMFSDBGLEVEL)
+ {
+ printf("memfs_map: %p, %d\n", *memp, *top); fflush(stdout);
+ }
+#endif
+ return 0;
+}
+
+
+void memfs_unmap(thandle_t handle, tdata_t mem, toff_t to)
+{
+#ifdef RMANDEBUG
+ if (RManDebug >= MEMFSDBGLEVEL)
+ {
+ printf("memfs_unmap: %p, %d\n", mem, to); fflush(stdout);
+ }
+#endif
+}
+
+
+
+
+
+
+/* Read-only from memory (simple chunky model, not block-oriented) */
+void memfs_chunk_initfs(thandle_t handle, char *src, r_Long size)
+{
+ memFSContext *memFS = (memFSContext *)handle;
+
+#ifdef RMANDEBUG
+ if (RManDebug >= MEMFSDBGLEVEL)
+ {
+ printf("memfs_chunk_initfs: %p, %d\n", src, size); fflush(stdout);
+ }
+#endif
+ memFS->pos = 0;
+ memFS->chunk = src;
+ memFS->high = size;
+}
+
+
+tsize_t memfs_chunk_read(thandle_t handle, tdata_t mem, tsize_t size)
+{
+ tsize_t todo=0;
+ memFSContext *memFS = (memFSContext *)handle;
+
+ todo = memFS->high - memFS->pos;
+#ifdef RMANDEBUG
+ if (RManDebug >= MEMFSDBGLEVEL)
+ {
+ printf("memfs_chunk_read: %d (left %d)\n", size, todo); fflush(stdout);
+ }
+#endif
+ if (todo > size) todo = size;
+ if (todo > 0)
+ {
+ memcpy((void*)mem, (void*)(memFS->chunk + memFS->pos), todo);
+ memFS->pos += todo;
+ }
+ return todo;
+}
+
+
+toff_t memfs_chunk_seek(thandle_t handle, toff_t offset, int mode)
+{
+ memFSContext *memFS = (memFSContext *)handle;
+
+ switch (mode)
+ {
+ case SEEK_SET: memFS->pos = offset; break;
+ case SEEK_CUR: memFS->pos += offset; break;
+ case SEEK_END: memFS->pos = memFS->high + offset; break;
+ default: break;
+ }
+ if (memFS->pos < 0) memFS = 0;
+ /* Since file can't be extended this is OK here */
+ if (memFS->pos > memFS->high) memFS->pos = memFS->high;
+#ifdef RMANDEBUG
+ if (RManDebug >= MEMFSDBGLEVEL)
+ {
+ printf("memfs_chunk_seek: Position to %d\n", memFS->pos); fflush(stdout);
+ }
+#endif
+ return memFS->pos;
+}
+
+
+int memfs_chunk_close(thandle_t handle)
+{
+#ifdef RMANDEBUG
+ if (RManDebug >= MEMFSDBGLEVEL)
+ {
+ printf("memfs_chunk_close:\n"); fflush(stdout);
+ }
+#endif
+ return 1;
+}
+
+
+toff_t memfs_chunk_size(thandle_t handle)
+{
+#ifdef RMANDEBUG
+ if (RManDebug >= MEMFSDBGLEVEL)
+ {
+ printf("memfs_chunk_size:\n"); fflush(stdout);
+ }
+#endif
+ return (((memFSContext *)handle)->high);
+}
+
+
+/* Map file to memory -- since we already have it in memory in the
+ first place this is very simple. */
+int memfs_chunk_map(thandle_t handle, tdata_t *memp, toff_t *top)
+{
+ memFSContext *memFS = (memFSContext *)handle;
+
+#ifdef RMANDEBUG
+ if (RManDebug >= MEMFSDBGLEVEL)
+ {
+ printf("memfs_chunk_map:\n"); fflush(stdout);
+ }
+#endif
+ *memp = (tdata_t)(memFS->chunk); *top = (toff_t)(memFS->high);
+ return 1; /* Success? */
+}
+
+void memfs_chunk_unmap(thandle_t handle, tdata_t mem, toff_t to)
+{
+#ifdef RMANDEBUG
+ if (RManDebug >= MEMFSDBGLEVEL)
+ {
+ printf("memfs_chunk_unmap: %p, %d\n", mem, to); fflush(stdout);
+ }
+#endif
+}
diff --git a/conversion/memfs.h b/conversion/memfs.h
new file mode 100644
index 0000000..42958ad
--- /dev/null
+++ b/conversion/memfs.h
@@ -0,0 +1,85 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: memfs.hh
+ *
+ * MODULE: conversion
+ *
+ * PURPOSE:
+ * Memory Filing System used by some of the convertor modules.
+ *
+ * COMMENTS:
+ * None
+*/
+
+#ifndef _MEMFS_HH_
+#define _MEMFS_HH_
+
+/* For data types used by the memfs */
+#include "tiffio.h"
+#include "raslib/odmgtypes.hh"
+
+
+/* Claim blocks in 4k chunks */
+const int MEMFS_LD_BLOCKSIZE = 12;
+/* Initially preserve enough room for 16 blocks */
+const int MEMFS_MAM_ENTRIES = 16;
+
+typedef struct memFSContext {
+ r_Long pos, high;
+ int mamSize, mamHighest;
+ char **mam;
+ char *chunk;
+} memFSContext;
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Flexible, read-write memFS */
+int memfs_initfs(thandle_t handle);
+void memfs_killfs(thandle_t handle);
+void memfs_newfile(thandle_t handle);
+tsize_t memfs_read(thandle_t handle, tdata_t mem, tsize_t size);
+tsize_t memfs_write(thandle_t handle, tdata_t mem, tsize_t size);
+toff_t memfs_seek(thandle_t handle, toff_t offset, int mode);
+int memfs_close(thandle_t handle);
+toff_t memfs_size(thandle_t handle);
+int memfs_map(thandle_t handle, tdata_t *memp, toff_t *top);
+void memfs_unmap(thandle_t handle, tdata_t mem, toff_t top);
+
+/* Simple, read-only memFS */
+void memfs_chunk_initfs(thandle_t handle, char *src, r_Long size);
+tsize_t memfs_chunk_read(thandle_t handle, tdata_t mem, tsize_t size);
+toff_t memfs_chunk_seek(thandle_t handle, toff_t offset, int mode);
+int memfs_chunk_close(thandle_t handle);
+toff_t memfs_chunk_size(thandle_t handle);
+int memfs_chunk_map(thandle_t handle, tdata_t *memp, toff_t *top);
+void memfs_chunk_unmap(thandle_t handle, tdata_t mem, toff_t to);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/conversion/memfs.hh b/conversion/memfs.hh
new file mode 100644
index 0000000..1b88b37
--- /dev/null
+++ b/conversion/memfs.hh
@@ -0,0 +1,85 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: memfs.hh
+ *
+ * MODULE: conversion
+ *
+ * PURPOSE:
+ * Memory Filing System used by some of the convertor modules.
+ *
+ * COMMENTS:
+ * None
+*/
+
+#ifndef _MEMFS_HH_
+#define _MEMFS_HH_
+
+/* For data types used by the memfs */
+#include "tiffio.h"
+#include "raslib/odmgtypes.hh"
+
+
+/* Claim blocks in 4k chunks */
+const int MEMFS_LD_BLOCKSIZE = 12;
+/* Initially preserve enough room for 16 blocks */
+const int MEMFS_MAM_ENTRIES = 16;
+
+typedef struct memFSContext {
+ r_Long pos, high;
+ int mamSize, mamHighest;
+ char **mam;
+ char *chunk;
+} memFSContext;
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Flexible, read-write memFS */
+int memfs_initfs(thandle_t handle);
+void memfs_killfs(thandle_t handle);
+void memfs_newfile(thandle_t handle);
+tsize_t memfs_read(thandle_t handle, tdata_t mem, tsize_t size);
+tsize_t memfs_write(thandle_t handle, tdata_t mem, tsize_t size);
+toff_t memfs_seek(thandle_t handle, toff_t offset, int mode);
+int memfs_close(thandle_t handle);
+toff_t memfs_size(thandle_t handle);
+int memfs_map(thandle_t handle, tdata_t *memp, toff_t *top);
+void memfs_unmap(thandle_t handle, tdata_t mem, toff_t top);
+
+/* Simple, read-only memFS */
+void memfs_chunk_initfs(thandle_t handle, char *src, r_Long size);
+tsize_t memfs_chunk_read(thandle_t handle, tdata_t mem, tsize_t size);
+toff_t memfs_chunk_seek(thandle_t handle, toff_t offset, int mode);
+int memfs_chunk_close(thandle_t handle);
+toff_t memfs_chunk_size(thandle_t handle);
+int memfs_chunk_map(thandle_t handle, tdata_t *memp, toff_t *top);
+void memfs_chunk_unmap(thandle_t handle, tdata_t mem, toff_t to);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/conversion/nitf.cc b/conversion/nitf.cc
new file mode 100644
index 0000000..dbdfee0
--- /dev/null
+++ b/conversion/nitf.cc
@@ -0,0 +1,702 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#include <string>
+#include <stdio.h>
+#include <cstdlib>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <iostream>
+#include <fstream>
+#include <strstream>
+#include <exception>
+
+
+#include "nitf.h"
+#include "image.h"
+#include "graphic.h"
+#include "text.h"
+#include "des.h"
+#include "res.h"
+#include "utilities.h"
+
+using namespace std;
+using namespace RasNITF;
+
+nitf::nitf(){
+
+ isEmpty = true;
+
+ m_li = NULL;
+ m_ls = NULL;
+ m_lt = NULL;
+ m_ld = NULL;
+ m_lr = NULL;
+ m_udhd = NULL;
+ m_xhd = NULL;
+
+ m_images = NULL;
+ m_graphics = NULL;
+ m_texts = NULL;
+ m_des = NULL;
+ m_res = NULL;
+
+ n_numi=0;
+}
+/*
+nitf::nitf(char* data){
+
+}
+*/
+nitf::~nitf(){
+
+ if (m_li != NULL) {
+ delete m_li;
+ m_li = NULL;
+ }
+
+ if (m_ls != NULL) {
+ delete m_ls;
+ m_ls = NULL;
+ }
+
+ if (m_lt != NULL) {
+ delete m_lt;
+ m_lt = NULL;
+ }
+
+ if (m_ld != NULL) {
+ delete m_ld;
+ m_ld = NULL;
+ }
+
+ if (m_lr != NULL) {
+ delete m_lr;
+ m_lr = NULL;
+ }
+
+ if (m_udhd != NULL) {
+ delete m_udhd;
+ m_udhd = NULL;
+ }
+
+ if (m_xhd != NULL) {
+ delete m_xhd;
+ m_xhd = NULL;
+ }
+
+ if (m_images != NULL) {
+ delete[] m_images;
+ m_images = NULL;
+ }
+
+ if (m_graphics != NULL) {
+ delete[] m_graphics;
+ m_graphics = NULL;
+ }
+
+ if (m_texts != NULL) {
+ delete[] m_texts;
+ m_texts = NULL;
+ }
+
+ if (m_des != NULL) {
+ delete[] m_des;
+ m_des = NULL;
+ }
+
+ if (m_res != NULL) {
+ delete[] m_res;
+ m_res = NULL;
+ }
+
+}
+
+bool nitf::checkempty(){
+ return isEmpty;
+}
+
+void nitf::empty(){
+
+ if (!this->isEmpty){
+
+ if (m_li != NULL) {
+ delete m_li;
+ m_li = NULL;
+ }
+
+ if (m_ls != NULL) {
+ delete m_ls;
+ m_ls = NULL;
+ }
+
+ if (m_lt != NULL) {
+ delete m_lt;
+ m_lt = NULL;
+ }
+
+ if (m_ld != NULL) {
+ delete m_ld;
+ m_ld = NULL;
+ }
+
+ if (m_lr != NULL) {
+ delete m_lr;
+ m_lr = NULL;
+ }
+
+ if (m_udhd != NULL) {
+ delete m_udhd;
+ m_udhd = NULL;
+ }
+
+ if (m_xhd != NULL) {
+ delete m_xhd;
+ m_xhd = NULL;
+ }
+
+ if (m_images != NULL) {
+ delete[] m_images;
+ m_images = NULL;
+ }
+
+ if (m_graphics != NULL) {
+ delete[] m_graphics;
+ m_graphics = NULL;
+ }
+
+ if (m_texts != NULL) {
+ delete[] m_texts;
+ m_texts = NULL;
+ }
+
+ if (m_des != NULL) {
+ delete[] m_des;
+ m_des = NULL;
+ }
+
+ if (m_res != NULL) {
+ delete[] m_res;
+ m_res = NULL;
+ }
+ }
+
+ this->isEmpty = true;
+}
+
+void nitf::stats() const {
+ int adress=n_hl;
+ cout<<"Printing statistics for the NITF file in memmory\n";
+ cout<<"================================================\n";
+ cout<<"Filename:\t\t"<<endl;
+ cout<<"File title:\n";
+ cout.write(m_ftitle,80);
+ cout<<"\nFile Length\t\t"<<n_fl;
+ cout<<"\nFile Header Length\t"<<n_hl;
+ cout<<"\nNumber of Images:\t"<<n_numi;
+ cout<<"\n====================IMAGES======================\n";
+ for(int i=0; i<n_numi; i++) {
+ cout<<"Length of Image Header "<<i<<"\t"<<n_lish[i]<<" Starting at "<<adress<<endl;
+ adress+=n_lish[i];
+ cout<<"Length of Image "<<i<<"\t"<<n_li[i]<<" Starting at "<<adress<<endl;
+ adress+=n_li[i];
+ }
+ cout<<"\nNumber of Graphics:\t"<<n_nums;
+ cout<<"\n===================GRAPHICS======================\n";
+ for(int i=0; i<n_nums; i++) {
+ cout<<"Length of Graphic Header "<<i<<"\t"<<n_lssh[i]<<" Starting at "<<adress<<endl;
+ adress+=n_lssh[i];
+ cout<<"Length of Graphic "<<i<<"\t"<<n_ls[i]<<" Starting at "<<adress<<endl;
+ adress+=n_ls[i];
+
+ }
+ cout<<"\nNumber of Texts:\t"<<n_numt;
+ cout<<"\n====================TEXTS========================\n";
+ for(int i=0; i<n_numt; i++) {
+
+ cout<<"Length of Text Header "<<i<<"\t"<<n_ltsh[i]<<" Starting at "<<adress<<endl;
+ adress+=n_ltsh[i];
+ cout<<"Length of Text "<<i<<"\t"<<n_lt[i]<<" Starting at "<<adress<<endl;
+ adress+=n_lt[i];
+ }
+ cout<<"\nNumber of Deses:\t"<<n_numdes;
+ cout<<"\n====================DESES======================\n";
+ for(int i=0; i<n_numdes; i++) {
+ cout<<"Length of Des Header "<<i<<"\t"<<n_ldsh[i]<<" Starting at "<<adress<<endl;
+ adress+=n_ldsh[i];
+ cout<<"Length of Des "<<i<<"\t"<<n_ld[i]<<" Starting at "<<adress<<endl;
+ adress+=n_ld[i];
+
+ }
+ cout<<"\nNumber of Reses:\t"<<n_numres;
+ cout<<"\n====================RESES======================\n";
+ for(int i=0; i<n_numres; i++) {
+
+ cout<<"Length of Res Header "<<i<<"\t"<<n_lrsh[i]<<" Starting at "<<adress<<endl;
+ adress+=n_lrsh[i];
+ cout<<"Length of Res "<<i<<"\t"<<n_lr[i]<<" Starting at "<<adress<<endl;
+ adress+=n_lr[i];
+ }
+ cout<<"\n\nThank you for using statistics, have a nice day\n";
+ cout<<"---8<---8<---8<---8<---8<---8<---8<---8<---8<---8<---\n";
+}
+
+
+int nitf::read_file(string filename){
+
+ ifstream hNITF;
+ hNITF.open(filename.c_str(), ios::in);
+ if (!hNITF.good()) exit(-1);
+ bool read_image_data = true;
+
+ return read(hNITF, read_image_data);
+
+}
+
+int nitf::read_headers_from(char* file_data, long file_length){
+
+ istrstream hNITF(file_data, file_length);
+ if (!hNITF.good()) exit(-1);
+ bool read_image_data = false;
+
+ return read(hNITF, read_image_data);;
+
+}
+
+
+int nitf::read(istream &hNITF, bool read_image_data){
+
+ char temp_buffer[100];
+ int charsread = 0;
+
+ // CHECK IF EMPTY EXCEPTION
+ if (!hNITF.good()) exit(-1);
+
+ // read file name and version and check for consistency
+
+ charsread += read_verify2(hNITF, m_fhdr, 9);
+
+ if (strncmp(m_fhdr, "NITF02.10", 9) != 0)
+ exit(2);
+
+ // copy all security fields as character data
+ charsread += read_verify2(hNITF, m_clevel, (2 + 4 + 10 + 14 + 80 + 1 + 2 + 11 + 2 + 20 + 2 + 8 + 4 + 1 + 8 + 43 +
+ 1 + 40 + 1 + 8 + 15 + 5 + 5 + 1 + 3 + 24 + 18));
+
+ // read file length
+ charsread += read_verify2(hNITF, m_fl, 12);
+ n_fl = charptrtolong(m_fl, 12);
+
+ // read header length
+ charsread += read_verify2(hNITF, m_hl, 6);
+ n_hl = charptrtolong(m_hl, 6);
+
+ // read number of images
+ charsread += read_verify2(hNITF, m_numi, 3);
+ n_numi = charptrtoint(m_numi, 3);
+ m_li = new char[n_numi*(6+10)];
+
+ for (int i = 0; i < n_numi; i++ ){
+
+ charsread += read_verify2(hNITF, temp_buffer, 6);
+ n_lish.push_back(charptrtolong(temp_buffer, 6));
+ strncpy((char*)(m_li + i*16), temp_buffer, 6);
+
+ charsread += read_verify2(hNITF, temp_buffer, 10);
+ n_li.push_back(charptrtolong(temp_buffer, 10));
+ strncpy((char*)(m_li + i*16 + 6), temp_buffer, 10);
+ }
+
+ // read number of graphics
+
+ charsread += read_verify2(hNITF, m_nums, 3);
+ n_nums = charptrtoint(m_nums, 3);
+ m_ls = new char[n_nums*(4 + 6)];
+
+ for (int i = 0; i < n_nums; i++ ){
+
+ charsread += read_verify2(hNITF, temp_buffer, 4);
+ n_lssh.push_back(charptrtolong(temp_buffer, 4));
+ strncpy((char*)(m_ls + i*10), temp_buffer, 4);
+
+ charsread += read_verify2(hNITF, temp_buffer, 6);
+ n_ls.push_back(charptrtolong(temp_buffer, 6));
+ strncpy((char*)(m_ls + i*10 + 4), temp_buffer, 6);
+ }
+
+ // read NUMX field
+
+ charsread += read_verify2(hNITF, m_numx, 3);
+
+ // read number of texts
+
+ charsread += read_verify2(hNITF, m_numt, 3);
+ n_numt = charptrtoint(m_numt, 3);
+ m_lt = new char[n_numt*(4+5)];
+
+ for (int i = 0; i < n_numt; i++ ){
+
+ charsread += read_verify2(hNITF, temp_buffer, 4);
+ n_ltsh.push_back(charptrtolong(temp_buffer, 4));
+ strncpy((char*)(m_lt+i*9), temp_buffer, 4);
+
+ charsread += read_verify2(hNITF, temp_buffer, 5);
+ n_lt.push_back(charptrtolong(temp_buffer, 5));
+ strncpy((char*)(m_lt + i*9 + 4), temp_buffer, 5);
+ }
+
+ // read DES sizes data
+
+ charsread += read_verify2(hNITF, m_numdes, 3);
+ n_numdes = charptrtoint(m_numdes, 3);
+ m_ld = new char[n_numdes * (4 + 9)];
+
+ for (int i = 0; i < n_numdes; i++ ){
+
+ charsread += read_verify2(hNITF, temp_buffer, 4);
+ n_ldsh.push_back(charptrtolong(temp_buffer, 4));
+ strncpy((char*)(m_ld+i*13), temp_buffer, 4);
+
+ charsread += read_verify2(hNITF, temp_buffer, 9);
+ n_ld.push_back(charptrtolong(temp_buffer, 9));
+ strncpy((char*)(m_ld + i*13 + 4), temp_buffer, 9);
+ }
+
+ // read RES sizes data
+
+ charsread += read_verify2(hNITF, m_numres, 3);
+ n_numres = charptrtoint(m_numres, 3);
+ m_lr = new char[n_numres * (4 + 7)];
+
+ for (int i = 0; i < n_numres; i++){
+
+ charsread += read_verify2(hNITF, temp_buffer, 4);
+ n_lrsh.push_back(charptrtolong(temp_buffer, 4));
+ strncpy((char*)(m_lr + i*11), temp_buffer, 4);
+
+ charsread += read_verify2(hNITF, temp_buffer, 7);
+ n_lr.push_back(charptrtolong(temp_buffer, 7));
+ strncpy((char*)(m_lr + i*11 + 4), temp_buffer, 7);
+ }
+
+ // read UDHDL
+
+ charsread += read_verify2(hNITF, m_udhdl, 5);
+ n_udhdl = charptrtoint(m_udhdl, 5);
+
+ // read UDHOFL and UDHD if necessary
+
+ if (n_udhdl > 0) {
+
+ charsread += read_verify2(hNITF, m_udhofl, 3);
+ m_udhd = new char[n_udhdl-3];
+ charsread += read_verify2(hNITF, m_udhd, n_udhdl-3);
+ }
+
+ // read XHDL
+
+ charsread += read_verify2(hNITF, m_xhdl, 5);
+ n_xhdl = charptrtoint(m_xhdl, 5);
+
+ // read XHOFL and XHD if necessary
+
+ if (n_xhdl > 0) {
+ charsread += read_verify2(hNITF, m_xhdlofl, 3);
+ m_xhd = new char[n_xhdl-3];
+ charsread += read_verify2(hNITF, m_xhd, n_xhdl-3);
+ }
+
+ if (((long)(hNITF.tellg()))!= n_hl){
+ cout<< "header length read not as specified" << endl;
+ cout<<endl<<"read: tellg: "<< hNITF.tellg() << " nhl " << n_hl<<endl;
+ cout<< "chars read: " << charsread << endl;
+ exit(3);
+ }
+
+ // read images
+
+ if (n_numi > 0) {
+ m_images = new image[n_numi];
+ for(int i=0; i<n_numi; i++) {
+ m_images[i].read_file(hNITF, n_lish[i], n_li[i], read_image_data);
+ }
+ } else {
+ m_images = NULL;
+ }
+
+ // read graphics
+
+ if (n_nums > 0) {
+ m_graphics = new graphic[n_nums];
+ for(int i=0; i<n_nums; i++) {
+ m_graphics[i].read_file(hNITF, n_lssh[i], n_ls[i]);
+ }
+ } else {
+ m_graphics = NULL;
+ }
+
+ // read texts
+
+ if (n_numt > 0) {
+ m_texts = new text[n_numt];
+ for(int i=0; i<n_numt; i++) {
+ m_texts[i].read_file(hNITF, n_ltsh[i], n_lt[i]);
+ }
+ } else {
+ m_texts = NULL;
+ }
+
+
+ if (n_numdes > 0) {
+ m_des = new des[n_numdes];
+ for(int i=0; i<n_numdes; i++) {
+ m_des[i].read_file(hNITF, n_ldsh[i], n_ld[i]);
+ }
+ } else {
+ m_des = NULL;
+ }
+
+ if (n_numres > 0) {
+ m_res = new res[n_numres];
+ for(int i=0; i<n_numres; i++) {
+ m_res[i].read_file(hNITF, n_lrsh[i], n_lr[i]);
+ }
+ } else {
+ m_res = NULL;
+ }
+
+
+ this->isEmpty = false;
+
+ return charsread;
+
+}
+
+
+
+
+int nitf::write_file(std::string filename){
+
+ int charswritten = 0;
+ ofstream fNITF(filename.c_str());
+
+ fNITF.write(m_fhdr, 9);
+ fNITF.write(m_clevel, 2);
+ fNITF.write(m_stype, 4);
+ fNITF.write(m_ostaid, 10);
+ fNITF.write(m_fdt, 14);
+ fNITF.write(m_ftitle, 80);
+ fNITF.write(m_fsclas, 1);
+ fNITF.write(m_fsclsy, 2);
+ fNITF.write(m_fscode, 11);
+ fNITF.write(m_fsctlh, 2);
+ fNITF.write(m_fsrel, 20);
+ fNITF.write(m_fsdctp, 2);
+ fNITF.write(m_fsdcdt, 8);
+ fNITF.write(m_fsdcxm, 4);
+ fNITF.write(m_fsdg, 1);
+ fNITF.write(m_fsdgdt, 8);
+ fNITF.write(m_fscltx, 43);
+ fNITF.write(m_fscatp, 1);
+ fNITF.write(m_fscaut, 40);
+ fNITF.write(m_fscrsn, 1);
+ fNITF.write(m_fssrdt, 8);
+ fNITF.write(m_fsctln, 15);
+ fNITF.write(m_fscop, 5);
+ fNITF.write(m_fscpys, 5);
+ fNITF.write(m_encryp, 1);
+ fNITF.write(m_fbkgc, 3);
+ fNITF.write(m_oname, 24);
+ fNITF.write(m_ophone, 18);
+ fNITF.write(m_fl, 12);
+ fNITF.write(m_hl, 6);
+
+ charswritten += 9 + 2 + 4 + 10 + 14 + 80 + 1+ 2 + 11 + 2 + 20 + 2 + 8 + 4 + 1 + 8 + 43 + 1 + 40 + 1 +8 + 15 + 5 + 5 + 1 + 3 + 24 + 18 + 12 + 6;
+
+ fNITF.write(m_numi, 3);
+ charswritten += 3;
+ if(n_numi > 0){
+ fNITF.write(m_li, n_numi * (6 + 10));
+ charswritten += n_numi * (6 + 10);
+ }
+
+ fNITF.write(m_nums, 3);
+ charswritten += 3;
+ if(n_nums > 0){
+ fNITF.write(m_ls, n_nums * (4 + 6));
+ charswritten += n_nums * (4 + 6);
+ }
+
+ fNITF.write(m_numx, 3);
+
+ fNITF.write(m_numt, 3);
+ charswritten += 6;
+ if(n_numt > 0) {
+ fNITF.write(m_lt, n_numt * (4 + 5));
+ charswritten += n_numt * (4 + 5);
+ }
+
+ fNITF.write(m_numdes, 3);
+ charswritten += 3;
+ if(n_numdes > 0) {
+ fNITF.write(m_ld, n_numdes * (4 + 9));
+ charswritten += n_numdes * (4 + 9);
+ }
+
+ fNITF.write(m_numres, 3);
+ charswritten += 3;
+ if(n_numres > 0) {
+ fNITF.write(m_lr, n_numdes * (4 + 7));
+ charswritten += n_numdes* (4 + 7);
+ }
+
+ fNITF.write(m_udhdl, 5);
+ if (n_udhdl > 0){
+ fNITF.write(m_udhofl, 3);
+ fNITF.write(m_udhd, n_udhdl - 3);
+ charswritten += n_udhdl;
+ }
+
+
+ fNITF.write(m_xhdl, 5);
+ if (n_xhdl > 0){
+ fNITF.write(m_xhdlofl, 3);
+ fNITF.write(m_xhd, n_xhdl - 3);
+ charswritten += n_xhdl;
+ }
+
+ for(int i=0; i< n_numi; i++){
+ m_images[i].write_file(fNITF);
+ }
+
+ for(int i=0; i< n_nums; i++){
+ m_graphics[i].write_file(fNITF);
+ }
+
+ for(int i=0; i< n_numt; i++){
+ m_texts[i].write_file(fNITF);
+ }
+
+ for(int i=0; i< n_numdes; i++){
+ m_des[i].write_file(fNITF);
+ }
+
+ for(int i=0; i< n_numres; i++){
+ m_res[i].write_file(fNITF);
+ }
+
+ return charswritten;
+}
+
+void nitf::image_to_pixel_sequential(int index) {
+
+ if( !isEmpty ) {
+ if( (index < 0) || (index > n_numi)) {
+ throw(74);
+ exit(3);
+ } else {
+ m_images[index].to_pixel_sequential();
+ }
+ }
+}
+
+long nitf::get_image_size(int image_index) const
+{
+ return m_images[image_index].get_size();
+}
+
+int nitf::get_image_width(int image_index) const
+{
+ return m_images[image_index].get_width();
+}
+
+int nitf::get_image_height(int image_index) const
+{
+ return m_images[image_index].get_height();
+}
+
+long nitf::get_image_offset(int image_index) const
+{
+ long offset = 0;
+
+ offset += n_hl;
+
+ for(int ctr = 0; ctr < image_index; ctr++ ) {
+ offset+= n_li[ctr] + n_lish[ctr];
+ }
+
+ offset += n_lish[image_index];
+
+ return offset;
+}
+
+bool nitf::isRGB(int image_index){
+
+ bool RGB = false;
+
+ if (m_images[image_index].get_irep() == " RGB") {
+ if (m_images[image_index].get_nbpp_bytes() == 1 ){
+ RGB = true;
+ } else {
+ // throw(74);
+ exit(1704);
+ }
+ }
+
+ return RGB;
+
+}
+
+bool nitf::isGRAY(int image_index){
+
+ bool GRAY = false;
+
+ if ((m_images[image_index].get_irep() == " MONO") && (m_images[image_index].get_pvtype() == "INT")) {
+ if (m_images[image_index].get_nbpp_bytes() == 1 ){
+ GRAY = true;
+ } else {
+ // throw(74);
+ exit(1704);
+ }
+ }
+
+ return GRAY;
+}
+
+bool nitf::isBOOL(int image_index){
+
+ bool isBOOL = false;
+
+ if ((m_images[image_index].get_irep() == " MONO") && (m_images[image_index].get_pvtype() == " B")) {
+ if (m_images[image_index].get_nbpp_bytes() == 1 ){
+ isBOOL = true;
+ } else {
+ // throw(74);
+ exit(1704);
+ }
+ }
+
+ return isBOOL;
+}
diff --git a/conversion/nitf.h b/conversion/nitf.h
new file mode 100644
index 0000000..892eb14
--- /dev/null
+++ b/conversion/nitf.h
@@ -0,0 +1,165 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+/**
+ * This is the definition of the NITF class, an agregation of the Classes Header,
+ * Image, Graphic and Text
+ */
+
+#ifndef __RASNITF_NITF_H
+#define __RASNITF_NITF_H
+
+#include<string>
+#include<vector>
+#include<iostream>
+#include<fstream>
+
+
+namespace RasNITF{
+
+class image;
+class graphic;
+class text;
+class des;
+class res;
+
+class nitf {
+
+ char m_fhdr[9];
+ char m_clevel[2];
+ char m_stype[4];
+ char m_ostaid[10];
+ char m_fdt[14];
+ char m_ftitle[80];
+ char m_fsclas[1];
+ char m_fsclsy[2];
+ char m_fscode[11];
+ char m_fsctlh[2];
+ char m_fsrel[20];
+ char m_fsdctp[2];
+ char m_fsdcdt[8];
+ char m_fsdcxm[4];
+ char m_fsdg[1];
+ char m_fsdgdt[8];
+ char m_fscltx[43];
+ char m_fscatp[1];
+ char m_fscaut[40];
+ char m_fscrsn[1];
+ char m_fssrdt[8];
+ char m_fsctln[15];
+ char m_fscop[5];
+ char m_fscpys[5];
+ char m_encryp[1];
+ char m_fbkgc[3];
+ char m_oname[24];
+ char m_ophone[18];
+
+ char m_fl[12];
+ char m_hl[6];
+ char m_numi[3];
+ char* m_li; // image sizes data
+ char m_nums[3];
+ char* m_ls; // graphic sizes data
+ char m_numx[3];
+ char m_numt[3];
+ char* m_lt; // text sizes data
+ char m_numdes[3];
+ char* m_ld; // des sizes data
+ char m_numres[3];
+ char* m_lr; // res sizes data
+ char m_udhdl[5];
+ char m_udhofl[3];
+ char* m_udhd;
+ char m_xhdl[5];
+ char m_xhdlofl[3];
+ char* m_xhd;
+
+ // DATA
+
+ //std::ifstream hNITF;
+
+ long n_fl;
+ long n_hl;
+
+ int n_numi;
+ std::vector<long> n_lish;
+ std::vector<long> n_li;
+ image *m_images;
+
+ int n_nums;
+ std::vector<long> n_lssh;
+ std::vector<long> n_ls;
+ graphic *m_graphics;
+
+ int n_numt;
+ std::vector<long> n_ltsh;
+ std::vector<long> n_lt;
+ text *m_texts;
+
+ int n_numdes;
+ std::vector<long> n_ldsh;
+ std::vector<long> n_ld;
+ des *m_des;
+
+ int n_numres;
+ std::vector<long> n_lrsh;
+ std::vector<long> n_lr;
+ res *m_res;
+
+ int n_udhdl;
+ int n_xhdl;
+
+ bool isEmpty;
+
+public:
+
+ nitf();
+ ~nitf();
+
+ int read_file(std::string filename);
+ int read_headers_from(char* file_data, long file_length);
+ int read(std::istream &hNITF, bool read_image_data);
+
+ int write_file(std::string filename);
+
+ void image_to_pixel_sequential(int index);
+
+ void stats() const;
+ void empty();
+ bool checkempty();
+
+ long get_image_size(int index = 0) const;
+ int get_image_width(int index = 0) const;
+ int get_image_height(int index = 0) const;
+ int get_image_pixel_type(int index = 0) const;
+ long get_image_offset(int index = 0) const;
+
+ bool isRGB(int image_index);
+ bool isGRAY(int image_index);
+ bool isBOOL(int image_index);
+
+};
+
+}
+
+#endif
diff --git a/conversion/ntf.cc b/conversion/ntf.cc
new file mode 100644
index 0000000..7db1bc7
--- /dev/null
+++ b/conversion/ntf.cc
@@ -0,0 +1,218 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: ntf.cc
+ *
+ * MODULE: conversion
+ *
+ * CLASSES: r_Conv_NTF
+ *
+ * COMMENTS:
+ *
+ * Provides functions to convert data to NTF and back.
+ *
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <iostream>
+#include <string.h>
+#include <new>
+
+#include "raslib/rminit.hh"
+#include "raslib/rmdebug.hh"
+#include "raslib/parseparams.hh"
+#include "conversion/ntf.hh"
+#include "conversion/memfs.hh"
+
+// nitf reader library
+
+#include "nitf.h"
+#include "image.h"
+
+r_Conv_NTF::r_Conv_NTF( const char *src, const r_Minterval &interv, const r_Type *tp )
+ throw(r_Error):r_Convert_Memory(src, interv, tp)
+{
+}
+
+r_Conv_NTF::r_Conv_NTF( const char *src, const r_Minterval &interv, int tp )
+ throw(r_Error):r_Convert_Memory(src, interv, tp)
+{
+}
+
+r_Conv_NTF::~r_Conv_NTF( void ){
+}
+
+/***********************************************************
+ * NAME: r_Conv_NTF::convertFrom
+ * ---------------------------------------------------------
+ * PURPOSE: convert from NITF image file data to the
+ * corresponding rasdaman type pixel sequential data
+ ***********************************************************/
+
+r_convDesc& r_Conv_NTF::convertFrom( const char *options ) throw(r_Error){
+
+ char *nitf_file_data = NULL;
+ char *nitf_img = NULL;
+ long fileSize = 0;
+ RasNITF::nitf nitf_file;
+
+ nitf_file_data = (char*) desc.src;
+
+ //READ NITF HEADERS
+
+ nitf_file.read_headers_from(nitf_file_data, int(desc.srcInterv[0].high() - desc.srcInterv[0].low() + 1));
+
+ // MOVE POINTER TO THE IMAGE DATA
+
+ nitf_img = (char*)(desc.src + nitf_file.get_image_offset());
+ fileSize = nitf_file.get_image_size();
+
+ // CONVERT ALL DATA TO PIXEL SEQUENTIAL
+
+ nitf_file.image_to_pixel_sequential(0); // the address of the image is also known internaly so no need to pass the pointer
+
+ // ALLOCATE STORAGE FOR DESC.DEST WITH? THE SIZE OF THE IMAGE
+
+ if ((desc.dest = (char*)mystore.storage_alloc(fileSize)) == NULL)
+ {
+ RMInit::logOut << "r_Conv_NTF::convertTo(): out of memory!" << endl;
+ throw r_Error(MEMMORYALLOCATIONERROR);
+ }
+
+ // COPY THE PIXEL SEQUENTIAL DATA TO THE DESC.DEST
+
+ memcpy(desc.dest, nitf_img, fileSize);
+
+ // SET THE INTERVALS
+
+ desc.destInterv = r_Minterval(2);
+ desc.destInterv << r_Sinterval(( r_Range)0, (r_Range) ( nitf_file.get_image_width() - 1))
+ << r_Sinterval(( r_Range)0, (r_Range) ( nitf_file.get_image_height() -1));
+
+ // SETR BASE TYPE
+
+ int image_index = 0;
+
+ if(nitf_file.isRGB(image_index)) {
+ desc.baseType = ctype_rgb;
+ } else if(nitf_file.isGRAY(image_index)) {
+ desc.baseType = ctype_char;
+ } else if(nitf_file.isBOOL(image_index)) {
+ desc.baseType = ctype_bool;
+ }
+ else {
+ RMInit::logOut << "r_Conv_NTF::convertFrom:" << "unsupported NITF file pixel type" << endl;
+ throw r_Error(r_Error::r_Error_General);
+ }
+
+
+
+/* switch (nitf_file.get_image_pixel_type()){
+ case NITF_BI:
+ desc.baseType = ctype_bool;
+ break;
+ case NITF_GRAY:
+ desc.baseType = ctype_char;
+ break;
+ case NITF_RGB:
+ desc.baseType = ctype_rgb;
+ break;
+ default:
+ RMInit::logOut << "r_Conv_NTF::convertFrom:" << "unsupported NITF file pixel type" << endl;
+ }
+*/
+ desc.destType = get_external_type(desc.baseType);
+
+ return desc;
+
+}
+
+/***********************************************************
+ * NAME: r_Conv_NTF::convertTo
+ * ---------------------------------------------------------
+ * PURPOSE: convert from rasdaman data to the
+ * corresponding nitf storage type
+ ***********************************************************/
+
+r_convDesc& r_Conv_NTF::convertTo( const char *options ) throw(r_Error){
+
+ int width=0, height=0;
+ int fileSize = 0;
+
+ // DETERMINE WIDTH AND HEIGHT
+
+ width = (int)(desc.srcInterv[0].high() - desc.srcInterv[0].low() + 1);
+ height = (int)(desc.srcInterv[1].high() - desc.srcInterv[1].low() + 1);
+
+ // CALCULATE THE SIZE OF THE IMAGE FILE
+
+ switch (desc.baseType)
+ {
+ case ctype_bool:
+ fileSize = width * height * 1;
+ break;
+ case ctype_char:
+ fileSize = width * height * 1;
+ break;
+ case ctype_rgb:
+ fileSize = width * height * 3;
+ default:
+ RMInit::logOut << "r_Conv_BMP::convertTo(): Unknown base type!" << endl;
+ throw r_Error(r_Error::r_Error_General);
+ }
+
+ // ALLOCATE STORAGE FOR THE IMAGE DATA
+
+ if ((desc.dest = (char*)mystore.storage_alloc(fileSize)) == NULL)
+ {
+ RMInit::logOut << "r_Conv_NTF::convertTo(): out of memory!" << endl;
+ throw r_Error(MEMMORYALLOCATIONERROR);
+ }
+
+ memcpy(desc.dest, desc.src, fileSize);
+
+ // SET THE SIZE OF THE DATA
+
+ desc.destInterv = r_Minterval(1);
+ desc.destInterv << r_Sinterval((r_Range)0, (r_Range)fileSize-1);
+
+ // SET THE TYPE OF TEH DATA
+
+ desc.destType = r_Type::get_any_type("char");
+
+ return desc;
+}
+
+
+r_Convertor* r_Conv_NTF::clone( void ) const{
+ return new r_Conv_NTF(desc.src, desc.srcInterv, desc.baseType);
+}
+
+const char * r_Conv_NTF::get_name( void ) const{
+ return format_name_ntf;
+}
+
+r_Data_Format r_Conv_NTF::get_data_format( void ) const{
+ return r_NTF;
+}
diff --git a/conversion/ntf.hh b/conversion/ntf.hh
new file mode 100644
index 0000000..e4800ae
--- /dev/null
+++ b/conversion/ntf.hh
@@ -0,0 +1,80 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: ntf.hh
+ *
+ * MODULE: conversion
+ *
+ * CLASSES: r_Conv_NTF
+ *
+ * COMMENTS:
+ *
+ * Provides interface to convert data to other formats.
+ *
+*/
+
+#ifndef _R_CONV_NTF_HH_
+#define _R_CONV_NTF_HH_
+
+#include "conversion/convertor.hh"
+
+//@ManMemo: Module {\bf conversion}
+
+/*@Doc:
+ NTF convertor class.
+ Completely native implementation, doesn't use external libs.
+*/
+
+class r_Conv_NTF : public r_Convert_Memory
+{
+ public:
+
+ /// constructor using an r_Type object
+ r_Conv_NTF( const char *src, const r_Minterval &interv, const r_Type *tp ) throw(r_Error);
+
+ /// constructor using convert_type_e shortcut
+ r_Conv_NTF( const char *src, const r_Minterval &interv, int tp ) throw(r_Error);
+
+ /// destructor
+ ~r_Conv_NTF( void );
+
+ /// convert to NTF
+ virtual r_convDesc &convertTo( const char *options=NULL ) throw(r_Error);
+
+ /// convert from NTF
+ virtual r_convDesc &convertFrom( const char *options=NULL ) throw(r_Error);
+
+ /// cloning
+ virtual r_Convertor *clone( void ) const;
+
+ /// identification
+ virtual const char *get_name( void ) const;
+ virtual r_Data_Format get_data_format( void ) const;
+ private:
+
+ ///keeps the block index
+ char *bl_num, *bl_size, *d_offset;
+
+};
+
+#endif
diff --git a/conversion/png.cc b/conversion/png.cc
new file mode 100644
index 0000000..b869a82
--- /dev/null
+++ b/conversion/png.cc
@@ -0,0 +1,597 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: png.cc
+ *
+ * MODULE: conversion
+ * Provides functions to convert data to PNG and back.
+ *
+ * CLASSES: r_Conv_PNG
+ *
+ * COMMENTS:
+ * - option parsing known bugs:
+ * * no overflow check on options string buffer
+ * * missing ")" is silently ignored
+ * * on hex input, non-hex chars are silently discarded (!)
+ * * too large numbers are mapped to unsigned short's max int
+ * * negative numbers are mapped to unsigned short's max int
+ * - do not use "," within an option because this is the parse_param separator
+ * - FIXME: define some 3xxx error codes instead of general exception
+ *
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <iostream>
+#include <string.h>
+
+#include "png.h"
+
+#include "raslib/rminit.hh"
+#include "raslib/rmdebug.hh"
+#include "debug.hh"
+
+#include "conversion/png.hh"
+#include "conversion/memfs.hh"
+
+#include "raslib/parseparams.hh"
+
+
+// transparency keyword in option string (cf. PNG standard):
+#define TRANSP_KEY "tRNS"
+
+
+/* memfs interface functions in C namespace */
+
+extern "C" {
+
+static void png_mem_read_data(png_struct *png_ptr, png_byte *data, png_size_t length)
+{
+ void *handle=NULL;
+
+ handle = (void*)png_get_io_ptr(png_ptr);
+ memfs_chunk_read(handle, (tdata_t)data, (tsize_t)length);
+}
+
+
+static void png_mem_write_data(png_struct *png_ptr, png_byte *data, png_size_t length)
+{
+ void *handle=NULL;
+
+ handle = (void*)png_get_io_ptr(png_ptr);
+ memfs_write(handle, (tdata_t)data, (tsize_t)length);
+}
+
+
+static void png_mem_flush_data(png_struct *png_ptr)
+{
+ void *handle=NULL;
+
+ handle = (void*)png_get_io_ptr(png_ptr);
+}
+
+
+/* Customized error handling */
+static void *png_user_error_ptr = NULL;
+
+static void png_user_warning_fn(png_struct *png_ptr, const char *warning_msg)
+{
+ fprintf(stdout, "r_Conv_PNG warning: %s\n", warning_msg); fflush(stdout);
+}
+
+static void png_user_error_fn(png_struct *png_ptr, const char *error_msg)
+{
+ fprintf(stderr, "r_Conv_PNG error: %s\n", error_msg);
+ // return from this routine, exception will be thrown in setjmp code
+}
+
+} // end of C namespace
+
+
+
+
+/*
+ * r_Conv_PNG class for converting MDD to PNG and back
+ */
+
+const char *r_Conv_PNG::name_InfoKey = "Description";
+const char *r_Conv_PNG::name_InfoText = "rasdaman MDD encoded as PNG";
+const char *r_Conv_PNG::method_convertTo = "r_Conv_PNG::convertTo()";
+const char *r_Conv_PNG::method_convertFrom = "r_Conv_PNG::convertFrom()";
+
+r_Conv_PNG::r_Conv_PNG(const char *src, const r_Minterval &interv, int tp) throw(r_Error)
+: r_Convert_Memory(src, interv, tp)
+{
+}
+
+
+r_Conv_PNG::r_Conv_PNG(const char *src, const r_Minterval &interv, const r_Type *tp) throw(r_Error)
+: r_Convert_Memory(src, interv, tp)
+{
+}
+
+
+r_Conv_PNG::~r_Conv_PNG(void)
+{
+}
+
+
+r_convDesc &r_Conv_PNG::convertTo( const char *options ) throw(r_Error)
+{
+ ENTER( "r_Conv_PNG::convertTo( " << (options==NULL?"(null)":options) << " )" );
+
+ png_struct *write_ptr=NULL;
+ png_info *info_ptr = NULL;
+ int i=0, j=0;
+ png_uint_32 width=0, height=0;
+ int colourType=0, compType=0;
+ int spp=0, bps=0, lineAdd=0, pixelAdd=0;
+ png_color_8 sig_bit;
+ png_text infotext[1];
+ char *trans_string = NULL; // transparency string buffer
+ int itemsScanned = 0; // # of items scanned in options string
+ bool transpFound = false; // keyword for transparency found in options?
+
+ i = 0; // error state: 0 is ok, !=0 is error
+
+ // option analysis: create parse object -- PB 2005-jul-12
+ if (params == NULL)
+ params = new r_Parse_Params();
+ params->add(TRANSP_KEY, &trans_string, r_Parse_Params::param_type_string);
+ transpFound = params->process(options);
+
+ // check for good options, if any
+ if (options != NULL && ! transpFound)
+ {
+ RMInit::logOut << "Error: illegal PNG option string: " << options << endl;
+ throw r_Error(r_Error::r_Error_General);
+ }
+
+ write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, png_user_error_ptr, png_user_error_fn, png_user_warning_fn);
+
+ if (write_ptr == NULL)
+ i=1;
+ else
+ {
+ info_ptr = png_create_info_struct(write_ptr);
+ if (info_ptr == NULL)
+ {
+ RMInit::logOut << "Error: unable to allocate PNG header." << endl;
+ i=1;
+ }
+ else if (setjmp(write_ptr->jmpbuf))
+ {
+ png_destroy_write_struct(&write_ptr, &info_ptr);
+ RMInit::logOut << "Error: unable to save PNG stack" << endl;
+ throw r_Error(r_Error::r_Error_General);
+ }
+ }
+
+ if (i != 0)
+ {
+ png_destroy_write_struct(&write_ptr, &info_ptr);
+ throw r_Error(r_Error::r_Error_General);
+ }
+
+ memfs_newfile(handle);
+
+ png_set_write_fn(write_ptr, (void*)handle, png_mem_write_data, png_mem_flush_data);
+
+ // Compression
+ compType = PNG_COMPRESSION_TYPE_BASE;
+
+ // Size
+ width = desc.srcInterv[0].high() - desc.srcInterv[0].low() + 1;
+ height = desc.srcInterv[1].high() - desc.srcInterv[1].low() + 1;
+
+ // Depth and sample format and transparency
+ // added transparency -- PB 2005-jul-12
+ switch (desc.baseType)
+ {
+ case ctype_bool:
+ spp = 1; bps = 1; pixelAdd = height; lineAdd = 1;
+ colourType = PNG_COLOR_TYPE_GRAY; sig_bit.gray = 1;
+ if (transpFound)
+ {
+ itemsScanned = sscanf( trans_string, " %hi ", &(info_ptr->trans_values.gray) );
+ if (itemsScanned == 1) // all required items found?
+ {
+ info_ptr->valid |= PNG_INFO_tRNS; // activate tRNS chunk
+ }
+ else
+ {
+ RMInit::logOut << "Error: illegal syntax in transparency color specification - should be \"%i\", but is: " << trans_string << endl;
+ throw r_Error(r_Error::r_Error_General);
+ }
+ }
+ break;
+
+ case ctype_char:
+ spp = 1; bps = 8; pixelAdd = height; lineAdd = 1;
+ colourType = PNG_COLOR_TYPE_GRAY; sig_bit.gray = 8;
+ if (transpFound)
+ {
+ itemsScanned = sscanf( trans_string, " %hi ", &(info_ptr->trans_values.gray) );
+ if (itemsScanned == 1) // all required items found?
+ {
+ info_ptr->valid |= PNG_INFO_tRNS; // activate tRNS chunk
+ }
+ else
+ {
+ RMInit::logOut << "Error: illegal syntax in transparency color specification - should be \"%i\", but is: " << trans_string << endl;
+ throw r_Error(r_Error::r_Error_General);
+ }
+ }
+ break;
+
+ case ctype_rgb:
+ spp = 3; bps = 8; pixelAdd = 3*height; lineAdd = 3;
+ colourType = PNG_COLOR_TYPE_RGB;
+ sig_bit.red = 8; sig_bit.green = 8; sig_bit.blue = 8;
+ if (transpFound)
+ {
+ itemsScanned = sscanf( trans_string, " ( %hi ; %hi ; %hi ) ", &(info_ptr->trans_values.red), &(info_ptr->trans_values.green), &(info_ptr->trans_values.blue) );
+ if (itemsScanned == 3) // all required items found?
+ {
+ info_ptr->valid |= PNG_INFO_tRNS; // activate tRNS chunk
+ }
+ else
+ {
+ RMInit::logOut << "Error: illegal syntax in item #" << itemsScanned << " of transparency color specification - should be \"(%i;%i;%i)\", but is: " << trans_string << endl;
+ throw r_Error(r_Error::r_Error_General);
+ }
+ }
+ break;
+
+ default:
+ RMInit::logOut << "Error: " << method_convertTo << ": Unknown base type." << endl;
+ throw r_Error(r_Error::r_Error_General);
+ } // switch
+
+ // adjust transparency color value to pixel depth (unconditionally, even if transparency is unused)
+ if (bps == 8)
+ {
+ info_ptr->trans_values.red &= 0xff;
+ info_ptr->trans_values.green &= 0xff;
+ info_ptr->trans_values.blue &= 0xff;
+ info_ptr->trans_values.gray &= 0xff;
+ }
+
+ if (trans_string != NULL)
+ {
+ delete [] trans_string;
+ trans_string = NULL;
+ }
+
+
+ png_set_IHDR(write_ptr, info_ptr, width, height, bps, colourType, PNG_INTERLACE_NONE, compType, PNG_FILTER_TYPE_BASE);
+ png_set_sBIT(write_ptr, info_ptr, &sig_bit);
+
+ // Info text
+ infotext[0].key = new char[strlen(name_InfoKey)+1];
+ strcpy(infotext[0].key, name_InfoKey);
+ infotext[0].text = new char[strlen(name_InfoText)+1];
+ strcpy(infotext[0].text, name_InfoText);
+ infotext[0].compression = PNG_TEXT_COMPRESSION_NONE;
+ infotext[0].text_length = strlen(infotext[0].text);
+ png_set_text(write_ptr, info_ptr, infotext, 1);
+
+ // Write header
+ png_write_info(write_ptr, info_ptr);
+
+ png_byte *row=NULL, *rowPtr=NULL;
+ const unsigned char *src=NULL, *srcPtr=NULL;
+
+ row = new png_byte[((bps * spp * width + 7) >> 3)];
+ src = (const unsigned char*)(desc.src);
+
+ for (j=0; j<height; j++)
+ {
+ rowPtr = row; srcPtr = src;
+
+ switch (desc.baseType)
+ {
+ case ctype_bool:
+ {
+ int mask=0;
+ png_byte val=0;
+
+ val = 0; mask = 0x80; // png docs: leftmost pixel in high-order bits
+ for (i=0; i<width; i++, srcPtr += pixelAdd)
+ {
+ if (*srcPtr != 0) val |= mask;
+ mask >>= 1;
+ if (mask == 0)
+ {
+ *rowPtr++ = val; val = 0; mask = 0x80;
+ }
+ }
+ if (mask != 0x80) *rowPtr++ = val;
+ }
+ break;
+ case ctype_char:
+ {
+ for (i=0; i<width; i++, srcPtr += pixelAdd)
+ {
+ *rowPtr++ = *srcPtr;
+ }
+ }
+ break;
+ case ctype_rgb:
+ {
+ for (i=0; i<width; i++, srcPtr += pixelAdd)
+ {
+ *rowPtr++ = srcPtr[0];
+ *rowPtr++ = srcPtr[1];
+ *rowPtr++ = srcPtr[2];
+ }
+ }
+ break;
+ }
+
+ png_write_row(write_ptr, row);
+
+ src += lineAdd;
+ }
+
+ delete [] row; row=NULL;
+
+ png_write_end(write_ptr, info_ptr);
+
+#ifdef RMANDEBUG
+ // if (RManDebug >= 4)
+ {
+ RMInit::dbgOut << "wrote PNG image: width=" << width << ", height=" << height << ", bps=" << bps << ", colour=";
+ switch (desc.baseType)
+ {
+ case ctype_bool:
+ RMInit::dbgOut << "bw";
+ if (transpFound)
+ RMInit::dbgOut << ", transparent=" << info_ptr->trans_values.gray;
+ break;
+ case ctype_char:
+ RMInit::dbgOut << "grey";
+ if (transpFound)
+ RMInit::dbgOut << ", transparent=" << info_ptr->trans_values.gray;
+ break;
+ case ctype_rgb:
+ RMInit::dbgOut << "rgb";
+ if (transpFound)
+ RMInit::dbgOut << ", transparent=(" << info_ptr->trans_values.red << info_ptr->trans_values.green << info_ptr->trans_values.blue << ")";
+ break;
+ default:
+ RMInit::dbgOut << "(illegal)";
+ break;
+ }
+ RMInit::dbgOut << endl;
+ }
+#endif
+
+ // --- Cleanup -------------------------------------------------------
+ png_destroy_write_struct(&write_ptr, &info_ptr);
+
+ delete [] infotext[0].key; infotext[0].key=NULL;
+ delete [] infotext[0].text; infotext[0].text=NULL;
+
+ r_Long pngSize = memfs_size(handle);
+
+ if ((desc.dest = (char*)mystore.storage_alloc(pngSize)) == NULL)
+ {
+ RMInit::logOut << "Error: " << method_convertTo << ": out of memory." << endl;
+ throw r_Error(MEMMORYALLOCATIONERROR);
+ }
+ memfs_seek(handle, 0, SEEK_SET);
+ memfs_read(handle, desc.dest, pngSize);
+
+ desc.destInterv = r_Minterval(1);
+ desc.destInterv << r_Sinterval((r_Range)0, (r_Range)pngSize - 1);
+
+ // set result type to char string
+ desc.destType = r_Type::get_any_type("char");
+
+ LEAVE( "r_Conv_PNG::convertTo()" );
+ return desc;
+}
+
+
+r_convDesc &r_Conv_PNG::convertFrom(const char *options) throw(r_Error)
+{
+ png_struct *read_ptr=NULL;
+ png_info *info_ptr = NULL;
+ int i=0, j=0, pass=0, numPasses=0;
+ png_uint_32 width=0, height=0, pitch=0;
+ int colourType=0, interlaceType=0, compType=0, filterType=0;
+ int spp=0, bps=0, lineAdd=0, pixelAdd=0;
+
+ i = 0;
+ read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, png_user_error_ptr, png_user_error_fn, png_user_warning_fn);
+ if (read_ptr == NULL) i=1;
+ else
+ {
+ info_ptr = png_create_info_struct(read_ptr);
+ if (info_ptr == NULL) i=1;
+ else if (setjmp(read_ptr->jmpbuf))
+ {
+ png_destroy_read_struct(&read_ptr, &info_ptr, NULL);
+ RMInit::logOut << "r_Conv_PNG::convertFrom(" << options << "): unable to save the stack" << endl;
+ throw r_Error(r_Error::r_Error_General);
+ }
+ }
+ if (i != 0)
+ {
+ png_destroy_read_struct(&read_ptr, &info_ptr, NULL);
+ throw r_Error(r_Error::r_Error_General);
+ }
+
+ memfs_chunk_initfs(handle, (char*)desc.src, (r_Long)(desc.srcInterv[0].high() - desc.srcInterv[0].low() + 1));
+
+ desc.dest = NULL;
+
+ png_set_read_fn(read_ptr, (void*)handle, png_mem_read_data);
+
+ png_read_info(read_ptr, info_ptr);
+
+ png_get_IHDR(read_ptr, info_ptr, &width, &height, &bps, &colourType, &interlaceType, &compType, &filterType);
+
+ if (bps > 8)
+ {
+ RMInit::logOut << method_convertFrom << " warning: 16 bit samples quantized to 8 bit" << endl;
+ png_set_strip_16(read_ptr);
+ }
+
+ if ((colourType & PNG_COLOR_MASK_ALPHA) != 0)
+ {
+ RMInit::logOut << method_convertFrom << " warning: image contains alpha channel which will be lost" << endl;
+ png_set_strip_alpha(read_ptr);
+ }
+
+ if (bps < 8)
+ {
+ png_set_packing(read_ptr); // extract depths 1-4 as 1 byte per pixel
+ }
+
+ switch (colourType)
+ {
+ case PNG_COLOR_TYPE_GRAY:
+ case PNG_COLOR_TYPE_GRAY_ALPHA:
+ pitch = width; lineAdd = 1; pixelAdd = height;
+ if (bps == 1) desc.baseType = ctype_bool; else desc.baseType = ctype_char;
+ break;
+ case PNG_COLOR_TYPE_PALETTE:
+ png_set_expand(read_ptr);
+ case PNG_COLOR_TYPE_RGB:
+ case PNG_COLOR_TYPE_RGB_ALPHA:
+ pitch = 3*width; lineAdd = 3; pixelAdd = 3*height;
+ desc.baseType = ctype_rgb;
+ break;
+ default:
+ RMInit::logOut << method_convertFrom << ": don't understand image format" << endl;
+ throw r_Error(r_Error::r_Error_General);
+ }
+
+ numPasses = png_set_interlace_handling(read_ptr);
+
+#ifdef RMANDEBUG
+ if (RManDebug >= 4)
+ {
+ RMInit::dbgOut << "PNG image: width " << width << ", height " << height << ", bps " << bps;
+ RMInit::dbgOut << ", colour ";
+ switch (desc.baseType)
+ {
+ case ctype_bool: RMInit::dbgOut << "bw"; break;
+ case ctype_char: RMInit::dbgOut << "grey"; break;
+ case ctype_rgb: RMInit::dbgOut << "rgb"; break;
+ }
+ RMInit::dbgOut << ", interlace level " << numPasses << endl;
+ }
+#endif
+
+ png_byte *row = new png_byte[pitch];
+
+ desc.dest = (char*)mystore.storage_alloc(pitch * height);
+
+ for (pass=0; pass < numPasses; pass++)
+ {
+ unsigned char *dest, *destPtr;
+
+ dest = (unsigned char*)(desc.dest);
+ for (j=0; j<height; j++, dest += lineAdd)
+ {
+ png_byte *rowPtr=NULL;
+
+ destPtr = dest; rowPtr = row;
+ switch (desc.baseType)
+ {
+ case ctype_bool:
+ case ctype_char:
+ {
+ // In case of multiple passes set up the buffer according to the last pass
+ if (pass != 0)
+ {
+ for (i=0; i<width; i++, destPtr += pixelAdd)
+ {
+ *rowPtr++ = *destPtr;
+ }
+ destPtr = dest; rowPtr = row;
+ }
+ png_read_row(read_ptr, row, NULL);
+ for (i=0; i<width; i++, destPtr += pixelAdd)
+ {
+ *destPtr = *rowPtr++;
+ }
+ }
+ break;
+ case ctype_rgb:
+ {
+ if (pass != 0)
+ {
+ for (i=0; i<width; i++, destPtr += pixelAdd)
+ {
+ *rowPtr++ = destPtr[0]; *rowPtr++ = destPtr[1]; *rowPtr++ = destPtr[2];
+ }
+ destPtr = dest; rowPtr = row;
+ }
+ png_read_row(read_ptr, row, NULL);
+ for (i=0; i<width; i++, destPtr += pixelAdd)
+ {
+ destPtr[0] = *rowPtr++; destPtr[1] = *rowPtr++; destPtr[2] = *rowPtr++;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ png_read_end(read_ptr, info_ptr);
+
+ delete [] row; row=NULL;
+
+ png_destroy_read_struct(&read_ptr, &info_ptr, NULL);
+
+ desc.destInterv = r_Minterval(2);
+ desc.destInterv << r_Sinterval((r_Range)0, (r_Range)width-1)
+ << r_Sinterval((r_Range)0, (r_Range)height-1);
+
+ desc.destType = get_external_type(desc.baseType);
+
+ return desc;
+}
+
+
+
+const char *r_Conv_PNG::get_name( void ) const
+{
+ return format_name_png;
+}
+
+
+r_Data_Format r_Conv_PNG::get_data_format( void ) const
+{
+ return r_PNG;
+}
+
+
+r_Convertor *r_Conv_PNG::clone( void ) const
+{
+ return new r_Conv_PNG(desc.src, desc.srcInterv, desc.baseType);
+}
diff --git a/conversion/png.hh b/conversion/png.hh
new file mode 100644
index 0000000..6b56300
--- /dev/null
+++ b/conversion/png.hh
@@ -0,0 +1,79 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: png.hh
+ *
+ * MODULE: conversion
+ *
+ * CLASSES: r_Conv_PNG
+ *
+ * COMMENTS:
+ *
+ * Provides interface to convert data to other formats.
+ *
+*/
+
+#ifndef _R_CONV_PNG_HH_
+#define _R_CONV_PNG_HH_
+
+#include "conversion/convertor.hh"
+
+
+
+//@ManMemo: Module {\bf conversion}
+
+/*@Doc:
+ PNG convertor class.
+
+ This class doesn't have parameters.
+*/
+
+class r_Conv_PNG : public r_Convert_Memory
+{
+ public:
+ /// constructor using an r_Type object
+ r_Conv_PNG( const char *src, const r_Minterval &interv, const r_Type *tp ) throw(r_Error);
+ /// constructor using convert_type_e shortcut
+ r_Conv_PNG( const char *src, const r_Minterval &interv, int tp ) throw(r_Error);
+ /// destructor
+ ~r_Conv_PNG( void );
+
+ /// convert to PNG
+ virtual r_convDesc &convertTo( const char *options=NULL ) throw(r_Error);
+ /// convert from PNG
+ virtual r_convDesc &convertFrom( const char *options=NULL ) throw(r_Error);
+ /// cloning
+ virtual r_Convertor *clone( void ) const;
+ /// identification
+ virtual const char *get_name( void ) const;
+ virtual r_Data_Format get_data_format( void ) const;
+
+ private:
+ /// names
+ static const char *name_InfoKey;
+ static const char *name_InfoText;
+ static const char *method_convertTo;
+ static const char *method_convertFrom;
+};
+
+#endif
diff --git a/conversion/res.cc b/conversion/res.cc
new file mode 100644
index 0000000..ffca7f9
--- /dev/null
+++ b/conversion/res.cc
@@ -0,0 +1,110 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#include <iostream>
+#include <fstream>
+
+#include "res.h"
+#include "nitf.h"
+#include "utilities.h"
+
+using namespace std;
+using namespace RasNITF;
+
+res::res(){
+
+ m_resshf = NULL;
+ m_resdata = NULL;
+}
+
+res::~res(){
+
+ if(m_resshf != NULL){
+ delete m_resshf;
+ m_resshf = NULL;
+ }
+
+ if(m_resdata != NULL){
+ delete m_resdata;
+ m_resdata = NULL;
+ }
+}
+
+int res::read_file(istream &hNITF, long lrsh, long lr){
+
+ int charsread = 0;
+
+ header_length = lrsh;
+ data_length = lr;
+
+ charsread += read_verify2(hNITF, m_re, 2 + 25 + 2 + 167 + 4);
+ n_resshl = charptrtolong(m_resshl,4);
+
+ if (n_resshl > 0) {
+ m_resshf = new char[n_resshl];
+ charsread += read_verify2(hNITF, m_resshf, n_resshl);
+ }
+
+ m_resdata = new char[data_length];
+ charsread += read_verify2(hNITF, m_resdata, data_length);
+
+ return charsread;
+}
+
+int res::write_file(ofstream &fNITF)
+
+{
+
+ int charswritten = 0;
+
+ fNITF.write(m_re, 2);
+ fNITF.write(m_restag, 25);
+ fNITF.write(m_resver, 2);
+ fNITF.write(m_ressg, 167);
+ fNITF.write(m_resshl, 4);
+
+ if (fNITF.good()) charswritten += 2 + 25 + 2 + 167 + 4;
+
+ if (n_resshl > 0) {
+ fNITF.write(m_resshf, n_resshl);
+ }
+
+ if (fNITF.good()) charswritten += n_resshl;
+
+ if( m_resdata != NULL) {
+ fNITF.write( m_resdata, data_length);
+ }
+
+ if (fNITF.good()) charswritten += data_length;
+
+ return charswritten;
+
+}
+
+string res::get_lr() const {
+ return res_dl;
+}
+
+string res::get_lrsh() const {
+ return res_hl;
+}
diff --git a/conversion/res.h b/conversion/res.h
new file mode 100644
index 0000000..a655938
--- /dev/null
+++ b/conversion/res.h
@@ -0,0 +1,64 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#ifndef __RASNITF_RES_H
+#define __RASNITF_RES_H
+
+#include <vector>
+#include <iostream>
+#include <fstream>
+
+namespace RasNITF
+{
+
+class res {
+
+ char m_re[2];
+ char m_restag[25];
+ char m_resver[2];
+ char m_ressg[167];
+ char m_resshl[4];
+ char* m_resshf;
+ char* m_resdata;
+
+ long n_resshl;
+ long data_length;
+ long header_length;
+
+ std::string res_hl;
+ std::string res_dl;
+ public:
+
+ res();
+ ~res();
+
+ int read_file(std::istream &,long,long);
+ int write_file(std::ofstream &);
+ std::string get_lr() const;
+ std::string get_lrsh() const;
+
+};
+
+}
+
+#endif
diff --git a/conversion/test/Makefile b/conversion/test/Makefile
new file mode 100644
index 0000000..410e1c4
--- /dev/null
+++ b/conversion/test/Makefile
@@ -0,0 +1,142 @@
+# -*-Makefile-*-
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>. # Top Level makefile. This points to the various modules that have to be build
+# and/or deployed
+#
+# MAKEFILE FOR:
+# test programs of module conversion
+#
+# COMMENTS:
+#
+##################################################################
+#
+# This is just an example Makefile for a test program.
+# The dependency of the test program on the lib of the
+# corresponding module is in the Makefile of the module.
+#
+
+######################### Definitions ############################
+
+# standard include with general options
+include $(RMANBASE)/Makefile.inc
+
+# all test programs
+ifeq ($(OSTYPE),linux-gnu)
+ALLTESTS = test_convertor test_png test_jpeg test_bmp test_vff
+else
+ALLTESTS = test_convertor test_hdf test_png test_jpeg test_bmp test_vff
+endif
+
+# For the time being: HDF includes / libs
+HDFBASE = $(SUPPORT_BASE)
+HDFINC = -I$(HDFBASE)/include
+HDFLIB = -L$(HDFBASE)/lib -ldf -ljpeg -lz -lmfhdf -lnsl
+
+ifeq ($(OSTYPE),linux-gnu)
+ LINKLIBS=$(CONVERSION) $(CLIENTCOMM) $(COMPRESSION) $(RASLIB) $(RASODMG)
+ CLIENTLDFLAGS += -lz
+else
+ ifdef RMANGCC
+ LINKLIBS=$(CONVERSION) $(CLIENTCOMM) $(COMPRESSION) $(RASLIB) $(RASODMG)
+ CLIENTLDFLAGS += -lsocket -lnsl -lz
+ else
+ LINKLIBS=$(CONVERSION) $(RASLIB)
+ endif
+endif
+
+########################### Targets ##############################
+
+# test target for convertors like r_TIFF
+.PHONY : convertor
+convertor: test_module $(ALLTESTS)
+
+.PHONY : test_module
+test_module:
+ cd $(RMANBASE)/conversion; $(MAKE)
+
+.PHONY : tiff
+tiff: test_module test_convertor
+
+.PHONY : hdf
+hdf: test_module test_hdf
+
+.PHONY : png
+png: test_module test_png
+
+.PHONY : jpeg
+jpeg: test_module test_jpeg
+
+.PHONY : bmp
+bmp: test_module test_bmp
+
+.PHONY : vff
+vff: test_module test_vff
+
+
+test_convertor: test_convertor.o $(LINKLIBS)
+ $(PURIFY) $(CXX) $(CLIENTLDFLAGS) -o $@ $^ -L$(SUPPORT_BASE)/lib -ltiff -ljpeg -lz -lcrypto
+
+test_hdf: test_hdf.o $(LINKLIBS)
+ $(PURIFY) $(CXX) $(CLIENTLDFLAGS) -o $@ $^ -L$(SUPPORT_BASE)/lib -lcrypto -lz $(HDFLIB)
+
+test_png: test_png.o $(LINKLIBS)
+ $(PURIFY) $(CXX) $(CLIENTLDFLAGS) -o $@ $^ -L$(SUPPORT_BASE)/lib -lpng -lz -lcrypto
+
+test_jpeg: test_jpeg.o $(LINKLIBS)
+ $(PURIFY) $(CXX) $(CLIENTLDFLAGS) -o $@ $^ -L$(SUPPORT_BASE)/lib -ljpeg -lz -lcrypto
+
+test_bmp: test_bmp.o $(LINKLIBS)
+ $(PURIFY) $(CXX) $(CLIENTLDFLAGS) -o $@ $^ -L$(SUPPORT_BASE)/lib -lcrypto -lz
+
+test_vff: test_vff.o $(LINKLIBS)
+ $(PURIFY) $(CXX) $(CLIENTLDFLAGS) -o $@ $^ -L$(SUPPORT_BASE)/lib -lcrypto -lz
+
+
+.PHONY : clean
+clean:
+ -rm $(ALLTESTS)
+ -rm *.o
+
+# deletes all non modified, but checked out files
+.PHONY : rcsclean
+rcsclean:
+ -rcsclean
+
+######################## Dependencies ############################
+
+test_convertor.o: test_convertor.cc
+ $(CXX) test_convertor.cc -c -o $@ $(CLIENTCXXFLAGS)
+
+test_hdf.o: test_hdf.cc
+ $(CXX) test_hdf.cc -c -o $@ $(HDFINC) $(CLIENTCXXFLAGS)
+
+test_png.o: test_png.cc
+ $(CXX) test_png.cc -c -o $@ $(CLIENTCXXFLAGS)
+
+test_jpeg.o: test_jpeg.cc
+ $(CXX) test_jpeg.cc -c -o $@ $(CLIENTCXXFLAGS)
+
+test_bmp.o: test_bmp.cc
+ $(CXX) test_bmp.cc -c -o $@ $(CLIENTCXXFLAGS)
+
+test_vff.o: test_vff.cc
+ $(CXX) test_vff.cc -c -o $@ $(CLIENTCXXFLAGS)
diff --git a/conversion/test/test_bmp.cc b/conversion/test/test_bmp.cc
new file mode 100644
index 0000000..c98712e
--- /dev/null
+++ b/conversion/test/test_bmp.cc
@@ -0,0 +1,83 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <iostream>
+#include <string.h>
+
+
+#include "conversion/convertor.hh"
+#include "conversion/bmp.hh"
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#include "raslib/template_inst.hh"
+#endif
+
+int main(int argc, char *argv[])
+{
+ char filename[256] = "Somewhere.bmp";
+ long fsize=0;
+ FILE *fp=NULL;
+ char *data=NULL;
+ r_Minterval interv(1);
+ r_Minterval imgInterv;
+ r_Conv_BMP *bmp=NULL;
+ r_convDesc desc;
+ r_Type *baseType=NULL;
+ char *imgData=NULL;
+
+ if (argc > 1)
+ strcpy(filename, argv[1]);
+
+ fp = fopen(filename, "rb");
+ if (fp == NULL)
+ {
+ cerr << "Unable to open file " << filename << endl;
+ exit(-1);
+ }
+
+ fseek(fp, 0, SEEK_END);
+ fsize = ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+
+ data = new char[fsize];
+ fread(data, 1, fsize, fp);
+ fclose(fp);
+
+ interv << r_Sinterval((r_Range)0, (r_Range)fsize-1);
+
+ cout << "Convert from BMP..." << endl;
+ bmp = new r_Conv_BMP(data, interv, r_Convertor::ctype_char);
+ desc = bmp->convertFrom();
+ baseType = desc.destType;
+ imgData = desc.dest;
+ imgInterv = desc.destInterv;
+ delete [] data;
+ data=NULL;
+ delete bmp;
+ bmp=NULL;
+
+ cout << "Convert to BMP..." << endl;
+ bmp = new r_Conv_BMP(imgData, imgInterv, baseType);
+ desc = bmp->convertTo("compress=1");
+ fsize = desc.destInterv[0].high() - desc.destInterv[0].low() + 1;
+
+ fp = fopen("result.bmp", "wb");
+ fwrite(desc.dest, 1, fsize, fp);
+ fclose(fp);
+
+ free(desc.dest);
+ desc.dest=NULL;
+ delete desc.destType;
+ desc.destType=NULL;
+ delete bmp;
+ bmp=NULL;
+
+ cout << "Clean up..." << endl;
+
+ delete baseType;
+ baseType=NULL;
+ free(imgData);
+ imgData=NULL;
+
+ return 0;
+}
diff --git a/conversion/test/test_convertor.cc b/conversion/test/test_convertor.cc
new file mode 100644
index 0000000..9305278
--- /dev/null
+++ b/conversion/test/test_convertor.cc
@@ -0,0 +1,276 @@
+#include <iostream>
+#include <stdio.h>
+#include <string.h>
+#include "conversion/convertor.hh"
+#include "conversion/tiff.hh"
+#include "raslib/rminit.hh"
+#include "rasodmg/gmarray.hh"
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#include "raslib/template_inst.hh"
+#endif
+
+// define if you want to use r_Type variables to set the
+// array type.
+//#define TEST_CONV_USE_RTYPES
+
+
+void ConvertToTIFFCore(r_Conv_TIFF *tiff, const char *save, const char *params)
+{
+ r_convDesc desc;
+ FILE *tfile;
+ long size;
+
+ try
+ {
+ // desc will become invalid when the TIFF object is deleted.
+ // The same applies to all data allocated by the TIFF object,
+ // e.g. the buffer holding the resulting TIFF.
+ desc = tiff->convertTo(params);
+
+ size = (long)(desc.destInterv[0].high() - desc.destInterv[0].low() + 1);
+ if ((tfile = fopen(save, "wb")) == NULL)
+ {
+ cerr << "Error opening file " << save << endl;
+ }
+ else
+ {
+ fwrite((void*)(desc.dest), (size_t)1, (size_t)size, tfile);
+ fclose(tfile);
+ }
+ cout << "test_convertor: r_Conv_TIFF::convertTo successful. "
+ << "size = " << size << ", type = ";
+ desc.destType->print_status(cout); cout << endl;
+ // This is the job of the client!
+ free(desc.dest);
+ delete desc.destType;
+ }
+ catch (r_Error &err)
+ {
+ cout << "An error occurred: " << err.what() << endl;
+ }
+}
+
+
+void ConvertToTIFF(char *data, r_Minterval &iv, r_Type *type, const char *save, const char *params)
+{
+ r_Conv_TIFF *tiff;
+
+ cout << "test_convertor (r_Type): ";
+ if (type)
+ {
+ cout << "Base Type is "; type->print_status(cout); cout << endl;
+ }
+ else
+ {
+ cout << "Base type not defined!" << endl;
+ }
+
+ tiff = new r_Conv_TIFF(data, iv, type);
+ ConvertToTIFFCore(tiff, save, params);
+ delete tiff;
+}
+
+
+void ConvertToTIFF(char *data, r_Minterval &iv, int type, const char *save, const char *params)
+{
+ r_Conv_TIFF *tiff;
+
+ cout << "test_convertor (int):" << endl;
+
+ tiff = new r_Conv_TIFF(data, iv, type);
+ ConvertToTIFFCore(tiff, save, params);
+ delete tiff;
+}
+
+
+void ConvertFromTIFF(char *name, const char *params, const char *save_as = NULL)
+{
+ FILE *fp;
+ long size;
+ r_convDesc desc;
+ r_Conv_TIFF *tiff;
+ char *data;
+ r_Minterval iv;
+
+ fp = fopen(name, "r");
+ fseek(fp, 0, SEEK_END);
+ size = ftell(fp);
+ data = new char[size];
+ fseek(fp, 0, SEEK_SET);
+ fread((void*)data, (size_t)1, (size_t)size, fp);
+ fclose(fp);
+
+ // Set interval
+ iv = r_Minterval(1); iv << r_Sinterval(r_Range(0), r_Range(size - 1));
+
+ // Base type is coded in TIFF
+ tiff = new r_Conv_TIFF(data, iv, (int)0);
+
+ desc = tiff->convertFrom();
+
+ cout << "test_convertor: r_Conv_TIFF::convertFrom successful."
+ << " domain = " << desc.destInterv << ", type = ";
+ desc.destType->print_status(cout); cout << endl;
+
+ delete [] data;
+
+ // save file again as TIFF to check convertFrom validity?
+ if (save_as != NULL)
+ {
+ cout << "test_convertor: Saving data again as <" << save_as << ">..." << endl;
+ ConvertToTIFF(desc.dest, desc.destInterv, desc.baseType, save_as, params);
+ }
+
+ // The order in which objects are deleted is important!
+ free(desc.dest);
+ delete desc.destType;
+
+ // Delete this last. From then on desc is invalid.
+ delete tiff;
+}
+
+
+
+// Flag bits for main()
+#define CONVERTOR_WRITE_BACK 1
+
+
+// Calling convention: test_convertor [-x # -y # -c <compression> -v -h]
+// Where -x: width, -y: height, -c: compression, -v: write again as TIFF after reading
+// -h: Help on usage
+// width, height default to 200, 100
+int main (int argc, char *argv[])
+{
+ r_GMarray dummyArray; // need this for linking on Linux, don't know why
+ char *data, *lineBase, *line;
+ int width = 200, height = 100;
+ unsigned int flags = 0;
+ int i, j;
+ char params[256];
+ const char *paramptr = NULL;
+#ifdef TEST_CONV_USE_RTYPES
+ r_Type *type;
+#endif
+ struct nametable {char *write, *verify;} tiffnames[] = {
+ {"grey.tif", "grey2.tif"},
+ {"bool.tif", "bool2.tif"},
+ {"rgb.tif", "rgb2.tif"}
+ };
+
+ i = 1;
+ while (i < argc)
+ {
+ if (argv[i][0] == '-')
+ {
+ switch (argv[i][1])
+ {
+ case 'x': width = atoi(argv[++i]); break;
+ case 'y': height = atoi(argv[++i]); break;
+ case 'c':
+ sprintf(params, "comptype=%s", argv[++i]);
+ paramptr = params;
+ break;
+ case 'v': flags |= CONVERTOR_WRITE_BACK; break;
+ case 'h':
+ cout << "Usage: " << argv[0] << "[-w # -h # -c <string> -v -h]" << endl;
+ cout << "\t-x #: width" << endl;
+ cout << "\t-y #: height" << endl;
+ cout << "\t-c <string>: compression (see r_Conv_TIFF::compNames)" << endl;
+ cout << "\t-v: write the TIFF files just read back as TIFF files for verifying" << endl;
+ cout << "\t-h: this help" << endl;
+ exit(0);
+ default: cout << "Bad switch -" << argv[i][1] << endl; break;
+ }
+ }
+ i++;
+ }
+
+ cout << "test_convertor: use images of size " << width << " * " << height
+ << ", compression: ";
+
+ // Allocate enough room for _all_ types of data.
+ if ((data = new char[3*width*height]) == NULL)
+ {
+ cout << "Out of memory error!" << endl; exit(0);
+ }
+
+ r_Minterval iv(2);
+ iv << r_Sinterval(r_Range(0), r_Range(width - 1))
+ << r_Sinterval(r_Range(0), r_Range(height - 1));
+
+ // Take into account that MDD arrays are transposed compared to
+ // images!
+ cout << "Greyscale:" << endl;
+ lineBase = data;
+ for (j=0; j<height; j++, lineBase++)
+ {
+ line = lineBase;
+ for (i=0; i<width; i++, line += height)
+ {
+ *line = (char)((i+j) & 0xff);
+ }
+ }
+
+#ifdef TEST_CONV_USE_RTYPES
+ type = r_Type::get_base_type("char");
+ ConvertToTIFF(data, iv, type, tiffnames[0].write, paramptr);
+ delete type;
+#else
+ ConvertToTIFF(data, iv, (int)(r_Convertor::ctype_char), tiffnames[0].write, paramptr);
+#endif
+
+ cout << "Bitmap:" << endl;
+ lineBase = data;
+ for (j=0; j<height; j++, lineBase++)
+ {
+ line = lineBase;
+ for (i=0; i<width; i++, line += height)
+ {
+ *line = (char)((i + j) & 1);
+ }
+ }
+
+#ifdef TEST_CONV_USE_RTYPES
+ type = r_Type::get_base_type("boolean");
+ ConvertToTIFF(data, iv, type, tiffnames[1].write, paramptr);
+ delete type;
+#else
+ ConvertToTIFF(data, iv, (int)(r_Convertor::ctype_bool), tiffnames[1].write, paramptr);
+#endif
+
+ cout << "RGB:" << endl;
+ lineBase = data;
+ for (j=0; j<height; j++, lineBase += 3)
+ {
+ line = lineBase;
+ for (i=0; i<width; i++, line += 3*height)
+ {
+ line[0] = ((i+j) & 0xff); line [1] = ((0xff - (i+j)) & 0xff);
+ line[2] = (((i+j) >> 1) & 0xff);
+ }
+ }
+
+#ifdef TEST_CONV_USE_RTYPES
+ type = r_Type::get_base_type("struct{ char red, char green, char blue }");
+ ConvertToTIFF(data, iv, type, tiffnames[2].write, paramptr);
+ delete type;
+#else
+ ConvertToTIFF(data, iv, (int)(r_Convertor::ctype_rgb), tiffnames[2].write, paramptr);
+#endif
+
+ delete [] data;
+
+ // Try the other way around: convert from TIFF
+ ConvertFromTIFF("rgb.tif", paramptr,
+ ((flags & CONVERTOR_WRITE_BACK) != 0) ? tiffnames[2].verify : NULL);
+
+ ConvertFromTIFF("bool.tif", paramptr,
+ ((flags & CONVERTOR_WRITE_BACK) != 0) ? tiffnames[1].verify : NULL);
+
+ ConvertFromTIFF("grey.tif", paramptr,
+ ((flags & CONVERTOR_WRITE_BACK) != 0) ? tiffnames[0].verify : NULL);
+
+ return 0;
+}
diff --git a/conversion/test/test_hdf.cc b/conversion/test/test_hdf.cc
new file mode 100644
index 0000000..a11b98a
--- /dev/null
+++ b/conversion/test/test_hdf.cc
@@ -0,0 +1,309 @@
+#include "conversion/convertor.hh"
+#include "conversion/hdf.hh"
+#include "raslib/minterval.hh"
+#include "raslib/primitivetype.hh"
+
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#include "raslib/template_inst.hh"
+#endif
+
+char *TypeIDToName(int tpid)
+{
+ switch (tpid)
+ {
+ case r_Primitive_Type::BOOL: return "bool"; break;
+ case r_Primitive_Type::CHAR: return "char"; break;
+ case r_Primitive_Type::OCTET: return "octet"; break;
+ case r_Primitive_Type::SHORT: return "short"; break;
+ case r_Primitive_Type::USHORT: return "ushort"; break;
+ case r_Primitive_Type::LONG: return "long"; break;
+ case r_Primitive_Type::ULONG: return "ulong"; break;
+ case r_Primitive_Type::FLOAT: return "float"; break;
+ case r_Primitive_Type::DOUBLE: return "double"; break;
+ default: return"?"; break;
+ }
+}
+
+
+int TestHDF(r_Minterval &domain, r_Type *tp, const char *params=NULL)
+{
+ r_Primitive_Type *prim;
+ char *src, *dest;
+ r_Minterval destInterv;
+ r_Conv_HDF *hdf;
+ r_Type *destType;
+ r_convDesc desc;
+ int i, j, k;
+ int rank, array_size, datasize;
+ int *dimsizes, *dimsteps, *dimidx;
+ char **srcPtrs;
+ int ptid, retid;
+
+ if (tp->isStructType())
+ {
+ cerr << "No structured types allowed!" << endl;
+ return -1;
+ }
+ prim = (r_Primitive_Type*)tp;
+ ptid = prim->type_id();
+ cout << "Source domain = " << domain << ", type = " << TypeIDToName(ptid) << endl;
+
+ switch (ptid)
+ {
+ case r_Primitive_Type::BOOL:
+ case r_Primitive_Type::CHAR:
+ case r_Primitive_Type::OCTET:
+ datasize = 1; break;
+ case r_Primitive_Type::SHORT:
+ case r_Primitive_Type::USHORT:
+ datasize = 2; break;
+ case r_Primitive_Type::LONG:
+ case r_Primitive_Type::ULONG:
+ case r_Primitive_Type::FLOAT:
+ datasize = 4; break;
+ case r_Primitive_Type::DOUBLE:
+ datasize = 8; break;
+ default:
+ cerr << "Unrecognized base type" << endl;
+ return -1;
+ }
+
+ rank = domain.dimension();
+ dimsizes = new int[rank]; dimsteps = new int[rank]; dimidx = new int[rank];
+ srcPtrs = new char*[rank];
+ for (i=0; i<rank; i++)
+ {
+ dimsizes[i] = domain[i].high() - domain[i].low() + 1;
+ dimidx[i] = 0;
+ }
+ array_size = datasize;
+ for (i=rank-1; i>=0; i--)
+ {
+ dimsteps[i] = array_size; array_size *= dimsizes[i];
+ }
+ src = new char[array_size];
+
+ for (i=0; i<rank; i++) srcPtrs[i] = src;
+
+ k = 0;
+ do
+ {
+ //cout << (int)(srcPtrs[0] - src) << endl;
+
+ // A bit inefficient, but customized code for the entire loop for each type
+ // would result in way too much code for testing purposes only.
+ switch (ptid)
+ {
+ case r_Primitive_Type::BOOL:
+ case r_Primitive_Type::CHAR:
+ case r_Primitive_Type::OCTET:
+ *((char*)srcPtrs[0]) = (char)k;
+ break;
+ case r_Primitive_Type::SHORT:
+ case r_Primitive_Type::USHORT:
+ *((short*)srcPtrs[0]) = (short)k;
+ break;
+ case r_Primitive_Type::LONG:
+ case r_Primitive_Type::ULONG:
+ *((long*)srcPtrs[0]) = (long)k;
+ break;
+ case r_Primitive_Type::FLOAT:
+ *((float*)srcPtrs[0]) = (float)k;
+ break;
+ case r_Primitive_Type::DOUBLE:
+ *((double*)srcPtrs[0]) = (double)k;
+ break;
+ default: break;
+ }
+ k++; i = 0;
+ do
+ {
+ dimidx[i]++;
+ if (dimidx[i] < dimsizes[i]) break;
+ dimidx[i] = 0; i++;
+ }
+ while (i < rank);
+ if (i < rank)
+ {
+ srcPtrs[i] += dimsteps[i];
+ if (i > 0)
+ {
+ // Init the array with the value x_0 + x_1 + ... + x_(n-1)
+ k = dimidx[0];
+ for (j=1; j<rank; j++) k += dimidx[j];
+ for (j=i; j>0; j--) {srcPtrs[j-1] = srcPtrs[j];;}
+ }
+ }
+ }
+ while (i < rank);
+
+ hdf = new r_Conv_HDF(src, domain, tp);
+
+ dest = NULL;
+
+ try
+ {
+ desc = hdf->convertTo(params);
+ dest = desc.dest;
+ destInterv = desc.destInterv;
+ destType = desc.destType;
+ }
+ catch(r_Error &err)
+ {
+ cerr << "Exception! " << err.what() << endl;
+ }
+
+ cout << "Encoded interval " << desc.destInterv << endl;
+
+ delete hdf;
+
+ if (dest != NULL)
+ {
+ try
+ {
+ hdf = new r_Conv_HDF(dest, destInterv, destType);
+
+ desc = hdf->convertFrom();
+
+ cout << "retrieved type = "; desc.destType->print_status();
+ retid = ((r_Primitive_Type*)(desc.destType))->type_id();
+ cout << ", (" << ((retid == ptid) ? "OK" : "Differs") << ')' << endl;
+ cout << "retrieved domain " << desc.destInterv << ' ';
+ i = 0;
+ if (desc.destInterv.dimension() == rank)
+ {
+ for (i=0; i<rank; i++)
+ {
+ if (desc.destInterv[i].high() - desc.destInterv[i].low() != domain[i].high() - domain[i].low())
+ break;
+ }
+ }
+ if (i < rank)
+ {
+ cout << "Incompatible!" << endl;
+ return -1;
+ }
+ cout << "(OK)" << endl;
+
+ for (i=0; i<array_size; i++)
+ {
+ if (src[i] != desc.dest[i]) break;
+ }
+ if (i == array_size)
+ {
+ cout << "Data identical" << endl;
+ }
+ else
+ {
+ cout << "Data differs at " << i << endl;
+ }
+
+ cout << endl;
+
+ delete destType;
+ delete desc.destType;
+
+ free(desc.dest); // HDF^-1 ( HDF (X) )
+ }
+ catch(r_Error &err)
+ {
+ cerr << "Exception! " << err.what() << endl;
+ }
+ }
+
+ delete hdf;
+
+ if (dest != NULL)
+ free(dest); // HDF (X)
+
+ delete [] src; // X
+
+ delete [] dimsizes; delete [] dimsteps; delete [] dimidx; delete [] srcPtrs;
+
+ // Delete the base type passed from the caller too
+ delete tp;
+
+ return 0;
+}
+
+
+
+
+
+int main(int argc, char *argv[])
+{
+ r_Minterval interv;
+ r_Type *tp;
+
+ // 3D data set over char
+ interv = r_Minterval(3);
+ interv << r_Sinterval(r_Range(0), r_Range(19))
+ << r_Sinterval(r_Range(0), r_Range(29))
+ << r_Sinterval(r_Range(0), r_Range(39));
+ tp = r_Type::get_any_type("char");
+ TestHDF(interv, tp);
+
+ // 2D data set over short
+ interv = r_Minterval(2);
+ interv << r_Sinterval(r_Range(0), r_Range(100))
+ << r_Sinterval(r_Range(0), r_Range(200));
+ tp = r_Type::get_any_type("short");
+ TestHDF(interv, tp);
+
+ // 1D data set over long
+ interv = r_Minterval(1);
+ interv << r_Sinterval(r_Range(0), r_Range(400));
+ tp = r_Type::get_any_type("long");
+ TestHDF(interv, tp);
+
+ // 2D data set over float
+ interv = r_Minterval(2);
+ interv << r_Sinterval(r_Range(0), r_Range(200))
+ << r_Sinterval(r_Range(0), r_Range(300));
+ tp = r_Type::get_any_type("float");
+ TestHDF(interv, tp);
+
+ // 2D data set over double
+ interv = r_Minterval(2);
+ interv << r_Sinterval(r_Range(100), r_Range(300))
+ << r_Sinterval(r_Range(100), r_Range(400));
+ tp = r_Type::get_any_type("double");
+ TestHDF(interv, tp);
+
+ // 1D data set over octet
+ interv = r_Minterval(1);
+ interv << r_Sinterval(r_Range(0), r_Range(200));
+ tp = r_Type::get_any_type("octet");
+ TestHDF(interv, tp);
+
+ // 1D data set over bool
+ interv = r_Minterval(1);
+ interv << r_Sinterval(r_Range(0), r_Range(200));
+ tp = r_Type::get_any_type("boolean");
+ TestHDF(interv, tp);
+
+ // 1D data set over unsigned short
+ interv = r_Minterval(1);
+ interv << r_Sinterval(r_Range(0), r_Range(200));
+ tp = r_Type::get_any_type("ushort");
+ TestHDF(interv, tp);
+
+ // 1D data set over unsigned long
+ interv = r_Minterval(1);
+ interv << r_Sinterval(r_Range(0), r_Range(200));
+ tp = r_Type::get_any_type("ulong");
+ TestHDF(interv, tp);
+
+ // 4D data set over char
+ interv = r_Minterval(4);
+ interv << r_Sinterval(r_Range(100), r_Range(149))
+ << r_Sinterval(r_Range(110), r_Range(184))
+ << r_Sinterval(r_Range(120), r_Range(219))
+ << r_Sinterval(r_Range(130), r_Range(204));
+ tp = r_Type::get_any_type("char");
+ TestHDF(interv, tp);
+
+ return 0;
+}
diff --git a/conversion/test/test_jpeg.cc b/conversion/test/test_jpeg.cc
new file mode 100644
index 0000000..e56a3d4
--- /dev/null
+++ b/conversion/test/test_jpeg.cc
@@ -0,0 +1,295 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <iostream>
+#include <string.h>
+#include <math.h>
+
+
+#include "conversion/convertor.hh"
+#include "conversion/jpeg.hh"
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#include "raslib/template_inst.hh"
+#endif
+
+static int init_identity(int offset)
+{
+ return offset;
+}
+
+static int init_square(int offset)
+{
+ return offset * offset;
+}
+
+static int SinTabOK = 0;
+static int SinusTable[512];
+
+static int init_sine(int offset)
+{
+ if (SinTabOK == 0)
+ {
+ int i;
+
+ for (i=0; i<512; i++)
+ {
+ SinusTable[i] = (int)(255*sin(M_PI * offset / 512.0));
+ }
+ SinTabOK = 1;
+ }
+ return SinusTable[offset & 511];
+}
+
+static int JpegErrorFileNumber;
+
+int test_picture(int width, int height, int bpp, const char *params, int (*init)(int))
+{
+ char *data;
+ r_Minterval interv(2);
+ int datasize;
+ int baseType;
+ int bytespp;
+ int i;
+
+ switch (bpp)
+ {
+ case 1: baseType = r_Convertor::ctype_bool; bytespp = 1; break;
+ case 8: baseType = r_Convertor::ctype_char; bytespp = 1; break;
+ case 24: baseType = r_Convertor::ctype_rgb; bytespp = 3; break;
+ default:
+ cerr << "Unknown bpp value " << bpp << endl;
+ return -1;
+ }
+
+ interv << r_Sinterval((r_Range)0, (r_Range)width-1)
+ << r_Sinterval((r_Range)0, (r_Range)height-1);
+
+ datasize = (width * bytespp * height);
+ data = new char[datasize];
+
+ cout << "Test: bpp = " << bpp << ", domain = " << interv << ", params = " << ((params == NULL) ? "" : params) << ", size = " << datasize << endl;
+
+ if (bpp > 1)
+ {
+ for (i=0; i<datasize; i++) data[i] = (char)init(i);
+ }
+ else
+ {
+ int j, count;
+
+ for (i=0; i<datasize; i+=8)
+ {
+ count = datasize - i; if (count > 8) count = 8;
+ for (j=0; j<count; j++) data[i+j] = ((init(i>>3) & (1<<j)) == 0) ? 0 : 1;
+ }
+ }
+
+ r_Conv_JPEG *jpeg = NULL;
+ char *dest = NULL;
+
+ try
+ {
+ r_convDesc desc;
+ int destsize;
+ int status = 0;
+
+ jpeg = new r_Conv_JPEG(data, interv, baseType);
+ desc = jpeg->convertTo(params);
+ destsize = desc.destInterv[0].high() - desc.destInterv[0].low() + 1;
+ cout << "\tConverted to JPEG, domain " << desc.destInterv << endl;
+ dest = desc.dest;
+ r_Minterval destInterv(desc.destInterv);
+ delete desc.destType;
+ delete jpeg;
+ jpeg = new r_Conv_JPEG(dest, destInterv, r_Convertor::ctype_char);
+ desc = jpeg->convertFrom();
+ cout << "\tConverted from JPEG, domain " << desc.destInterv << endl;
+
+ if (interv == desc.destInterv)
+ {
+ unsigned char *b, *d;
+ double totalError;
+ unsigned char maxError;
+ int i;
+
+ // Bitmaps get expanded to greyscale...
+ if (baseType == r_Convertor::ctype_bool)
+ {
+ for (i=0; i<datasize; i++)
+ {
+ if (data[i] != 0) data[i] = 0xff;
+ }
+ }
+
+ b = (unsigned char*)data; d = (unsigned char*)desc.dest;
+ totalError = 0.0; maxError = abs(*b - *d);
+ for (i=0; i<datasize; i++)
+ {
+ b[i] = abs(b[i] - d[i]);
+ if (b[i] > maxError) maxError = b[i];
+ totalError += (double)(b[i]);
+ }
+
+ r_Conv_JPEG *errpeg;
+ r_convDesc cdsc;
+ char errfile[256];
+ FILE *fp;
+ int errType;
+
+ errType = (baseType == r_Convertor::ctype_bool) ? r_Convertor::ctype_char : baseType;
+ sprintf(errfile, "jerror%d.jpg", JpegErrorFileNumber++);
+ cout << "\tCreating error file <" << errfile << "> ..." << endl;
+ cout << "\t(max error = " << (int)maxError << ", avg error = "
+ << totalError / (double)datasize << ")" << endl;
+
+ errpeg = new r_Conv_JPEG(data, interv, errType);
+ cdsc = errpeg->convertTo("quality=90");
+ i = (int)(cdsc.destInterv[0].high() - cdsc.destInterv[0].low() + 1);
+ if ((fp = fopen(errfile, "wb")) == NULL)
+ {
+ cerr << "\tUnable to open output file!" << endl;
+ }
+ else
+ {
+ fwrite(cdsc.dest, 1, i, fp);
+ fclose(fp);
+ }
+ delete cdsc.destType;
+ free(cdsc.dest);
+ delete errpeg;
+ }
+ else
+ {
+ cout << "\t Domain differs!!!" << endl;
+ status = -1;
+ }
+
+ delete jpeg;
+ delete [] data;
+ free(dest);
+ free(desc.dest);
+ delete desc.destType;
+
+ return status;
+ }
+ catch (r_Error &err)
+ {
+ cerr << "Error: " << err.what() << endl;
+
+ delete [] data;
+ if (dest != NULL) delete [] dest;
+ if (jpeg != NULL) delete jpeg;
+
+ return -1;
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ int i;
+ char jpegfile[256] = "";
+ char params[256];
+ const char *paramptr = NULL;
+
+ i = 1;
+ while (i < argc)
+ {
+ if (strcmp(argv[i], "-file") == 0)
+ {
+ strcpy(jpegfile, argv[++i]);
+ }
+ else if (strcmp(argv[i], "-quality") == 0)
+ {
+ sprintf(params, "quality=%s", argv[++i]);
+ paramptr = params;
+ }
+ i++;
+ }
+
+ if (jpegfile[0] == '\0')
+ {
+ JpegErrorFileNumber = 0;
+ test_picture(400, 300, 1, paramptr, init_identity);
+ test_picture(400, 300, 8, paramptr, init_identity);
+ test_picture(400, 300, 24, paramptr, init_identity);
+ test_picture(701, 333, 1, paramptr, init_square);
+ test_picture(701, 333, 8, paramptr, init_square);
+ test_picture(701, 333, 24, paramptr, init_square);
+ test_picture(3007, 3999, 1, paramptr, init_sine);
+ test_picture(3007, 3999, 8, paramptr, init_sine);
+ test_picture(3007, 3999, 24, paramptr, init_sine);
+ }
+ else
+ {
+ FILE *fp;
+ long fileSize;
+ char *data = NULL;
+ char *cdata = NULL;
+ r_convDesc desc;
+ r_Type *baseType;
+ r_Conv_JPEG *jpeg;
+
+ if ((fp = fopen(jpegfile, "rb")) == NULL)
+ {
+ cerr << "Unable to open input file" << endl;
+ return -1;
+ }
+ fseek(fp, 0, SEEK_END); fileSize = ftell(fp); fseek(fp, 0, SEEK_SET);
+ data = new char[fileSize];
+ fread(data, 1, fileSize, fp);
+ fclose(fp);
+
+ jpeg = NULL; baseType = NULL;
+ try
+ {
+ r_Minterval interv(1);
+ interv << r_Sinterval((r_Range)0, (r_Range)fileSize-1);
+
+ jpeg = new r_Conv_JPEG(data, interv, 0);
+ cout << "Converting file <" << jpegfile << "> to MDD..." << endl;
+ desc = jpeg->convertFrom();
+
+ r_Minterval imgInterv(desc.destInterv);
+ delete [] data; data = NULL;
+ cdata = desc.dest;
+ baseType = desc.destType;
+ delete jpeg;
+
+ cout << "Resulting domain " << imgInterv << ", ";
+ baseType->print_status();
+ cout << endl;
+
+ jpeg = new r_Conv_JPEG(cdata, imgInterv, baseType);
+ cout << "Converting MDD back to JPEG..." << endl;
+ desc = jpeg->convertTo(paramptr);
+ free(cdata);
+ cdata = desc.dest;
+
+ cout << "Resulting domain " << desc.destInterv << ", ";
+ desc.destType->print_status();
+ cout << endl;
+
+ fp = fopen("result.jpg", "wb");
+ fileSize = desc.destInterv[0].high() - desc.destInterv[0].low() + 1;
+ fwrite(cdata, 1, fileSize, fp);
+ fclose(fp);
+
+ delete baseType;
+ free(cdata);
+
+ delete desc.destType;
+ delete jpeg;
+ }
+ catch (r_Error &err)
+ {
+ cerr << "Conversion failed: " << err.what() << endl;
+ if (baseType != NULL) delete baseType;
+ if (cdata != NULL) delete [] cdata;
+ if (jpeg != NULL) delete jpeg;
+ }
+ if (data != NULL)
+ delete [] data;
+ }
+ return 0;
+}
diff --git a/conversion/test/test_png.cc b/conversion/test/test_png.cc
new file mode 100644
index 0000000..bc481fc
--- /dev/null
+++ b/conversion/test/test_png.cc
@@ -0,0 +1,237 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <iostream>
+#include <string.h>
+#include <math.h>
+
+
+#include "conversion/convertor.hh"
+#include "conversion/png.hh"
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#include "raslib/template_inst.hh"
+#endif
+
+static int init_identity(int offset)
+{
+ return offset;
+}
+
+static int init_square(int offset)
+{
+ return offset * offset;
+}
+
+static int SinTabOK = 0;
+static int SinusTable[512];
+
+static int init_sine(int offset)
+{
+ if (SinTabOK == 0)
+ {
+ int i;
+
+ for (i=0; i<512; i++)
+ {
+ SinusTable[i] = (int)(255*sin(M_PI * offset / 512.0));
+ }
+ SinTabOK = 1;
+ }
+ return SinusTable[offset & 511];
+}
+
+int test_picture(int width, int height, int bpp, int (*init)(int))
+{
+ char *data;
+ r_Minterval interv(2);
+ int datasize;
+ int baseType;
+ int bytespp;
+ int i;
+
+ switch (bpp)
+ {
+ case 1: baseType = r_Convertor::ctype_bool; bytespp = 1; break;
+ case 8: baseType = r_Convertor::ctype_char; bytespp = 1; break;
+ case 24: baseType = r_Convertor::ctype_rgb; bytespp = 3; break;
+ default:
+ cerr << "Unknown bpp value " << bpp << endl;
+ return -1;
+ }
+
+ interv << r_Sinterval((r_Range)0, (r_Range)width-1)
+ << r_Sinterval((r_Range)0, (r_Range)height-1);
+
+ datasize = (width * bytespp * height);
+ data = new char[datasize];
+
+ cout << "Test: bpp = " << bpp << ", domain = " << interv << ", size = " << datasize << endl;
+
+ if (bpp > 1)
+ {
+ for (i=0; i<datasize; i++) data[i] = (char)init(i);
+ }
+ else
+ {
+ int j, count;
+
+ for (i=0; i<datasize; i+=8)
+ {
+ count = datasize - i; if (count > 8) count = 8;
+ for (j=0; j<count; j++) data[i+j] = ((init(i>>3) & (1<<j)) == 0) ? 0 : 1;
+ //for (j=0; j<count; j++) cout << (char)(data[i+j] + '0'); cout << endl;
+ }
+ }
+
+ r_Conv_PNG *png = NULL;
+ char *dest = NULL;
+
+ try
+ {
+ r_convDesc desc;
+ int destsize;
+ int status = -1;
+
+ png = new r_Conv_PNG(data, interv, baseType);
+ desc = png->convertTo();
+ destsize = desc.destInterv[0].high() - desc.destInterv[0].low() + 1;
+ cout << "\tConverted to PNG, domain " << desc.destInterv << endl;
+ dest = desc.dest;
+ r_Minterval destInterv(desc.destInterv);
+ delete desc.destType;
+ delete png;
+ png = new r_Conv_PNG(dest, destInterv, r_Convertor::ctype_char);
+ desc = png->convertFrom();
+ cout << "\tConverted from PNG, domain " << desc.destInterv << endl;
+
+ if (interv == desc.destInterv)
+ status = memcmp(data, desc.dest, datasize);
+
+ delete png;
+ delete [] data;
+ free(dest);
+ free(desc.dest);
+ delete desc.destType;
+
+ if (status != 0)
+ {
+ cout << "\t!!! Data not identical !!!" << endl;
+ }
+
+ return 0;
+ }
+ catch (r_Error &err)
+ {
+ cerr << "Error: " << err.what() << endl;
+
+ delete [] data;
+ if (dest != NULL) free(dest);
+ if (png != NULL) delete png;
+
+ return -1;
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ int i;
+ char pngfile[256] = "";
+
+ i = 1;
+ while (i < argc)
+ {
+ if (strcmp(argv[i], "-file") == 0)
+ {
+ strcpy(pngfile, argv[++i]);
+ }
+ i++;
+ }
+
+ if (pngfile[0] == '\0')
+ {
+ // No PNG-file given, standard test-suite
+ test_picture(400, 300, 1, init_identity);
+ test_picture(400, 300, 8, init_identity);
+ test_picture(400, 300, 24, init_identity);
+ test_picture(701, 333, 1, init_square);
+ test_picture(701, 333, 8, init_square);
+ test_picture(701, 333, 24, init_square);
+ test_picture(3007, 3999, 1, init_sine);
+ test_picture(3007, 3999, 8, init_sine);
+ test_picture(3007, 3999, 24, init_sine);
+ }
+ else
+ {
+ // Work on this file
+ FILE *fp;
+ size_t fsize;
+ char *data;
+ r_convDesc desc;
+ r_Conv_PNG *png;
+ r_Type *baseType;
+
+ if ((fp = fopen(pngfile, "rb")) == NULL)
+ {
+ cerr << "Unable to open input file" << endl;
+ return -1;
+ }
+ fseek(fp, 0, SEEK_END); fsize = ftell(fp); fseek(fp, 0, SEEK_SET);
+
+ data = new char[fsize];
+ fread(data, 1, fsize, fp);
+ fclose(fp);
+
+ png = NULL; baseType = NULL;
+ try
+ {
+ r_Minterval interv(1);
+ interv << r_Sinterval((r_Range)0, (r_Range)fsize-1);
+
+ png = new r_Conv_PNG(data, interv, r_Convertor::ctype_char);
+ cout << "Converting file <" << pngfile << "> to MDD..." << endl;
+ desc = png->convertFrom();
+
+ cout << "Resulting domain " << desc.destInterv << ", ";
+ desc.destType->print_status();
+ cout << endl;
+
+ interv = r_Minterval(desc.destInterv);
+
+ delete [] data;
+ data = desc.dest;
+ baseType = desc.destType;
+ delete png;
+
+ fsize = (interv[0].high() - interv[0].low() + 1) * (interv[1].high() - interv[1].low() + 1);
+
+ png = new r_Conv_PNG(data, interv, baseType);
+ cout << "Converting MDD back to PNG..." << endl;
+ desc = png->convertTo();
+
+ cout << "Resulting domain " << desc.destInterv << ", ";
+ desc.destType->print_status();
+ cout << endl;
+
+ fp = fopen("result.png", "wb");
+ fwrite(desc.dest, 1, (desc.destInterv[0].high() - desc.destInterv[0].low() + 1), fp);
+ fclose(fp);
+
+ delete baseType;
+
+ free(data);
+ free(desc.dest);
+ delete desc.destType;
+ delete png;
+ }
+ catch (r_Error &err)
+ {
+ cerr << "Conversion failed: " << err.what() << endl;
+ if (baseType != NULL) delete baseType;
+ if (data != NULL) delete [] data;
+ if (png != NULL) delete png;
+ }
+ }
+
+ return 0;
+}
diff --git a/conversion/test/test_vff.cc b/conversion/test/test_vff.cc
new file mode 100644
index 0000000..e3d6016
--- /dev/null
+++ b/conversion/test/test_vff.cc
@@ -0,0 +1,169 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <iostream>
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#endif
+
+#include "conversion/vff.hh"
+#include "raslib/rminit.hh"
+#include "raslib/basetype.hh"
+
+#ifdef __GNUG__
+#include "rasodmg/transaction.hh"
+#include "raslib/template_inst.hh"
+#else
+RMINITGLOBALS('C')
+#endif
+
+
+
+static void PrintUsage(const char *name)
+{
+ cout << "Usage: " << name << " [-o <vffoutfile> -p <params> -h] <vffinfile>" << endl;
+}
+
+
+int main(int argc, char *argv[])
+{
+ const char *infile=NULL;
+ const char *outfile=NULL;
+ const char *params=NULL;
+ int i;
+
+ i=1;
+ while (i<argc)
+ {
+ if (argv[i][0] == '-')
+ {
+ switch (argv[i][1])
+ {
+ case 'o':
+ outfile = argv[++i]; break;
+ case 'p':
+ params = argv[++i]; break;
+ case 'h':
+ PrintUsage(argv[0]); exit(0);
+ default:
+ cerr << "Unknown switch " << argv[i] << endl;
+ break;
+ }
+ }
+ else
+ {
+ if (infile != NULL)
+ cerr << "More than one input file, ignored" << endl;
+ else
+ infile = argv[i];
+ }
+ i++;
+ }
+
+ if (infile == NULL)
+ {
+ PrintUsage(argv[0]);
+ exit(-1);
+ }
+
+ FILE *fp;
+ if ((fp = fopen(infile, "rb")) == NULL)
+ {
+ cerr << "Unable to open input file " << infile << endl;
+ return -1;
+ }
+
+ size_t fsize;
+ char *data;
+
+ fseek(fp, 0, SEEK_END);
+ fsize = ftell(fp);
+
+ if ((data = new char[fsize]) == NULL)
+ {
+ cerr << "Unable to claim memory for file" << endl;
+ fclose(fp);
+ return -1;
+ }
+ fseek(fp, 0, SEEK_SET);
+ fread(data, 1, fsize, fp);
+ fclose(fp);
+
+ r_Minterval interv(1);
+ interv << r_Sinterval((r_Range)0, (r_Range)fsize-1);
+ r_Conv_VFF conv(data, interv, r_Convertor::ctype_char);
+ r_convDesc desc;
+
+ cout << "Convert from VFF... " << flush;
+ try
+ {
+ desc = conv.convertFrom(params);
+ cout << "OK" << endl;
+
+ r_Conv_VFF convb(desc.dest, desc.destInterv, desc.destType);
+ r_convDesc descb;
+
+ cout << "Convert back to VFF... " << flush;
+ try
+ {
+ descb = convb.convertTo(params);
+ cout << "OK" << endl;
+
+ if (outfile != NULL)
+ {
+ if ((fp = fopen(outfile, "wb")) == NULL)
+ {
+ cerr << "Unable to write to file " << outfile << endl;
+ }
+ else
+ {
+ fsize = (size_t)(descb.destInterv[0].high() - descb.destInterv[0].low() + 1);
+ fwrite(descb.dest, 1, fsize, fp);
+ fclose(fp);
+ }
+ }
+
+ // endianness-safe comparison of binary data:
+ // convert the just created VFF data back to an MDD and compare the
+ // result with the first MDD thus converted.
+ r_Conv_VFF convc(descb.dest, descb.destInterv, descb.destType);
+ r_convDesc descc;
+
+ cout << "Compare binary data... " << flush;
+ try
+ {
+ descc = convc.convertFrom(params);
+ if (memcmp(descc.dest, desc.dest, desc.destInterv.cell_count() * ((r_Base_Type*)desc.destType)->size()) == 0)
+ cout << "identical" << endl;
+ else
+ cout << "differs!!!" << endl;
+
+ delete descc.destType;
+ free(descc.dest);
+ }
+ catch (r_Error &err)
+ {
+ cerr << "failed: " << err.what() << endl;
+ }
+
+ delete descb.destType;
+ free(descb.dest);
+ }
+ catch (r_Error &err)
+ {
+ cerr << "failed: " << err.what() << endl;
+ }
+ delete desc.destType;
+ free(desc.dest);
+ }
+ catch (r_Error &err)
+ {
+ cerr << "failed: " << err.what() << endl;
+ }
+
+ delete [] data;
+
+ return 0;
+}
diff --git a/conversion/text.cc b/conversion/text.cc
new file mode 100644
index 0000000..82ec81b
--- /dev/null
+++ b/conversion/text.cc
@@ -0,0 +1,138 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#include <iostream>
+#include <fstream>
+
+#include "text.h"
+#include "nitf.h"
+#include "utilities.h"
+
+using namespace std;
+using namespace RasNITF;
+
+RasNITF::text::text()
+{
+ m_text_data = NULL;
+ m_txshd = NULL;
+}
+
+RasNITF::text::~text()
+{
+ if(m_text_data != NULL)
+ delete m_text_data;
+ m_text_data = NULL;
+
+ if(m_txshd != NULL)
+ delete m_txshd;
+ m_txshd = NULL;
+
+}
+
+int RasNITF::text::read_file(istream &hNITF, long th_length, long text_length)
+{
+ int charsread = 0;
+ long starting_position = 0;
+
+ header_length=th_length;
+ starting_position = hNITF.tellg();
+ charsread += read_verify2(hNITF, m_te, 2 + 7 + 3 + 14 + 80 + 1 + 2 + 11 + 2 + 20 + 2 + 8+ 4+ 1+ 8+ 43 + 1 + 40 + 1 + 8+ 15+ 1+ 3);
+
+ // read txshdl
+
+ charsread += read_verify2(hNITF, m_txshdl, 5);
+ n_txshdl = charptrtolong(m_txshdl, 5);
+
+ if (n_txshdl > 0) {
+ n_txshdl -= 3;
+ charsread += read_verify2(hNITF, m_txsofl, 3);
+ m_txshd = new char[n_txshdl];
+ if(m_txshd == NULL) cerr<<"ERROR: could not allocate memory";
+ charsread += read_verify2(hNITF, m_txshd, n_txshdl);
+ n_txshdl += 3;
+
+ }
+
+ // check if we are where we should be
+ if((long)(hNITF.tellg()) != starting_position + th_length) exit(2);
+
+ // store the text data
+
+ m_text_data = new char[text_length];
+ if(m_text_data == NULL) cerr<<"ERROR: could not allocate memory";
+ charsread += read_verify2(hNITF, m_text_data, text_length);
+ data_length = text_length;
+
+ return charsread;
+}
+
+int RasNITF::text::write_file(ofstream &fNITF)
+{
+
+ fNITF.write(m_te, 2);
+ fNITF.write(m_textid, 7);
+ fNITF.write(m_txtalvl, 3);
+ fNITF.write(m_txtdt, 14);
+ fNITF.write(m_txtitl, 80);
+ fNITF.write(m_tsclas, 1);
+ fNITF.write(m_tsclsy, 2);
+ fNITF.write(m_tscode, 11);
+ fNITF.write(m_tsctlh, 2);
+ fNITF.write(m_tsrel, 20);
+ fNITF.write(m_tsdctp, 2);
+ fNITF.write(m_tsdcdt, 8);
+ fNITF.write(m_tsdcxm, 4);
+ fNITF.write(m_tsdg, 1);
+ fNITF.write(m_tsdgdt, 8);
+ fNITF.write(m_tscltx, 43);
+ fNITF.write(m_tscatp, 1);
+ fNITF.write(m_tscaut, 40);
+ fNITF.write(m_tscrsn, 1);
+ fNITF.write(m_tssrdt, 8);
+ fNITF.write(m_tsctln, 15);
+ fNITF.write(m_encryp, 1);
+ fNITF.write(m_txtfmt, 3);
+
+ fNITF.write(m_txshdl, 5);
+
+ if (n_txshdl > 0) {
+ fNITF.write(m_txsofl, 3);
+ fNITF.write(m_txshd, n_txshdl - 3);
+ }
+
+ if( m_text_data != NULL) {
+ fNITF.write( m_text_data, data_length);
+ }
+
+ //TODO:
+ return 0;
+
+}
+
+string RasNITF::text::get_lt() const {
+ return text_dl;
+}
+
+string RasNITF::text::get_ltsh() const {
+ return text_hl;
+}
diff --git a/conversion/text.h b/conversion/text.h
new file mode 100644
index 0000000..3746286
--- /dev/null
+++ b/conversion/text.h
@@ -0,0 +1,86 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+
+#ifndef __TEXT_H_INCLUDED
+#define __TEXT_H_INCLUDED
+
+#include<vector>
+#include <iostream>
+#include <fstream>
+
+namespace RasNITF
+{
+/* forward declarations follow : */
+
+class nitf;
+
+class text
+{
+ private:
+ char m_te[2];
+ char m_textid[7];
+ char m_txtalvl[3];
+ char m_txtdt[14];
+ char m_txtitl[80];
+ char m_tsclas[1];
+ char m_tsclsy[2];
+ char m_tscode[11];
+ char m_tsctlh[2];
+ char m_tsrel[20];
+ char m_tsdctp[2];
+ char m_tsdcdt[8];
+ char m_tsdcxm[4];
+ char m_tsdg[1];
+ char m_tsdgdt[8];
+ char m_tscltx[43];
+ char m_tscatp[1];
+ char m_tscaut[40];
+ char m_tscrsn[1];
+ char m_tssrdt[8];
+ char m_tsctln[15];
+ char m_encryp[1];
+ char m_txtfmt[3];
+ char m_txshdl[5];
+ char m_txsofl[3];
+ char* m_txshd;
+ char *m_text_data;
+
+ int header_length;
+ int data_length;
+ int n_txshdl;
+ int n_txsofl;
+
+ std::string text_hl ;
+ std::string text_dl ;
+
+ public:
+ text();
+ ~text(); //destructor freeing memory
+ int read_file(std::istream &,long,long);
+ int write_file(std::ofstream &); //writes the information to the data file
+ std::string get_lt() const;
+ std::string get_ltsh() const;
+};
+}
+#endif
diff --git a/conversion/tiff.cc b/conversion/tiff.cc
new file mode 100644
index 0000000..463f858
--- /dev/null
+++ b/conversion/tiff.cc
@@ -0,0 +1,653 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: tiff.cc
+ *
+ * MODULE: conversion
+ *
+ * CLASSES: r_Conv_TIFF
+ *
+ * COMMENTS:
+ *
+ * Provides functions to convert data to TIFF and back.
+ *
+*/
+
+#include <iostream>
+#include <string.h>
+
+#ifdef AIX
+#include <strings.h>
+#endif
+
+#include "conversion/tiff.hh"
+#include "conversion/memfs.hh"
+#include "raslib/error.hh"
+#include "raslib/rminit.hh"
+#include "raslib/parseparams.hh"
+
+const int r_Conv_TIFF::defaultRPS = 32;
+
+const char r_Conv_TIFF::dummyFileFmt[] = "/tmp/%p.tif";
+
+const struct r_Convertor::convert_string_s r_Conv_TIFF::compNames[] = {
+ {"none", COMPRESSION_NONE},
+ {"ccittrle", COMPRESSION_CCITTRLE},
+ {"ccittfax3", COMPRESSION_CCITTFAX3},
+ {"ccittfax4", COMPRESSION_CCITTFAX4},
+ {"lzw", COMPRESSION_LZW},
+ {"ojpeg", COMPRESSION_OJPEG},
+ {"jpeg", COMPRESSION_JPEG},
+ {"next", COMPRESSION_NEXT},
+ {"ccittrlew", COMPRESSION_CCITTRLEW},
+ {"packbits", COMPRESSION_PACKBITS},
+ {"thunderscan", COMPRESSION_THUNDERSCAN},
+ {"pixarfilm", COMPRESSION_PIXARFILM},
+ {"pixarlog", COMPRESSION_PIXARLOG},
+ {"deflate", COMPRESSION_DEFLATE},
+ {"dcs", COMPRESSION_DCS},
+ {"jbig", COMPRESSION_JBIG},
+#ifndef LINUX
+ {"sgilog", COMPRESSION_SGILOG},
+ {"sgilog24", COMPRESSION_SGILOG24},
+ {"it8ctpad", COMPRESSION_IT8CTPAD},
+ {"it8lw", COMPRESSION_IT8LW},
+ {"it8mp", COMPRESSION_IT8MP},
+ {"it8bl", COMPRESSION_IT8BL},
+#endif
+ {NULL, COMPRESSION_NONE}
+};
+
+const struct r_Convertor::convert_string_s r_Conv_TIFF::resunitNames[] = {
+ {"none", RESUNIT_NONE},
+ {"inch", RESUNIT_INCH},
+ {"centimeter", RESUNIT_CENTIMETER},
+ {NULL, RESUNIT_NONE}
+};
+
+// Change these according to the platform!
+// Fill order of bits in bitmap mode. Define 0 for LSB, otherwise MSB
+#define _R_TIFF_BITFILLORDER 1
+
+
+// Setup internal macros according to the fill-order
+#if (_R_TIFF_BITFILLORDER == 0)
+#define _R_TIFF_MASK_VALUE 1
+#define _R_TIFF_MASK_SHIFT(x) (x) <<= 1;
+#else
+#define _R_TIFF_MASK_VALUE (1<<7)
+#define _R_TIFF_MASK_SHIFT(x) (x) >>= 1;
+#endif
+
+
+// TIFF class functions
+
+// Translate string compression type to libtiff compression type
+int r_Conv_TIFF::get_compression_from_name(const char* strComp)
+{
+ unsigned short i=0;
+ int tiffComp=COMPRESSION_NONE;
+
+ if(strComp != NULL)
+ {
+ for (i=0; compNames[i].key != NULL; i++)
+ {
+ if (strcasecmp(compNames[i].key, strComp) == 0)
+ {
+ tiffComp = compNames[i].id;
+ break;
+ }
+ }
+
+ if (compNames[i].key == NULL)
+ RMInit::logOut << "r_Conv_TIFF::get_compression_from_name(): unsupported compression type " << strComp << endl;
+ }
+
+ return tiffComp;
+}
+
+// Translate string resolution unit type to libtiff resolution unit type
+int r_Conv_TIFF::get_resunit_from_name(const char* strResUnit)
+{
+ unsigned short i=0;
+ int tiffResUnit=RESUNIT_NONE;
+
+ if(strResUnit != NULL)
+ {
+ for (i=0; resunitNames[i].key != NULL; i++)
+ {
+ if (strcasecmp(resunitNames[i].key, strResUnit) == 0)
+ {
+ tiffResUnit = resunitNames[i].id;
+ break;
+ }
+ }
+
+ if (resunitNames[i].key == NULL)
+ RMInit::logOut << "r_Conv_TIFF::get_resunit_from_name(): unsupported resolution unit type " << strResUnit << endl;
+ }
+
+ return tiffResUnit;
+}
+
+void r_Conv_TIFF::initTIFF( void )
+{
+ compType = NULL;
+ quality = 80;
+ override_bpp = 0;
+ override_bps = 0;
+ override_depth = 0;
+
+ if (params == NULL)
+ params = new r_Parse_Params();
+
+ params->add("comptype", &compType, r_Parse_Params::param_type_string);
+ params->add("quality", &quality, r_Parse_Params::param_type_int);
+ params->add("bpp", &override_bpp, r_Parse_Params::param_type_int);
+ params->add("bps", &override_bps, r_Parse_Params::param_type_int);
+ params->add("depth", &override_depth, r_Parse_Params::param_type_int);
+}
+
+
+r_Conv_TIFF::r_Conv_TIFF(const char *src, const r_Minterval &interv, const r_Type *tp) throw(r_Error)
+: r_Convert_Memory(src, interv, tp)
+{
+ initTIFF();
+}
+
+
+r_Conv_TIFF::r_Conv_TIFF(const char *src, const r_Minterval &interv, int type) throw(r_Error)
+: r_Convert_Memory(src, interv, type)
+{
+ initTIFF();
+}
+
+
+r_Conv_TIFF::~r_Conv_TIFF(void)
+{
+ if (compType != NULL)
+ {
+ delete [] compType;
+ compType = NULL;
+ }
+}
+
+
+// Compression modes recommended:
+//
+// Bitmap, Greyscales: COMPRESSION_LZW, COMPRESSION_DEFLATE
+// RGB: COMPRESSION_JPEG, COMPRESSION_SGILOG24
+r_convDesc &r_Conv_TIFF::convertTo( const char *options ) throw(r_Error)
+{
+ if (options != NULL)
+ printf("tiff convert option = %s\n", options);
+ else
+ printf("tiff options are null = %s\n");
+ TIFF *tif=NULL;
+ char dummyFile[256];
+ uint16 cmap[256]; // Colour map (for greyscale images)
+ uint32 pixelAdd=0, lineAdd=0; // number of _bytes_ to add to a pointer
+ // to the source data to get the address
+ // of the pixel to the right / downwards.
+ uint16 bps=0, bpp=0;
+ uint32 width=0, height=0, i=0;
+ int tiffcomp = COMPRESSION_NONE;
+
+ params->process(options);
+
+ // translate string compression type to libtiff compression type
+ if (compType != NULL)
+ tiffcomp=get_compression_from_name(compType);
+
+ // Set dimensions
+ width = (uint32)(desc.srcInterv[0].high() - desc.srcInterv[0].low() + 1);
+ height = (uint32)(desc.srcInterv[1].high() - desc.srcInterv[1].low() + 1);
+
+ switch (desc.baseType)
+ {
+ // MDD arrays are transposed compared to the format needed for images.
+ // Therefore the pixelAdd and lineAdd values change places.
+ case ctype_bool:
+ bps = 1; bpp = 1; pixelAdd = height; lineAdd = 1;
+ break;
+ case ctype_char:
+ bps = 8; bpp = 8; pixelAdd = height; lineAdd = 1;
+ break;
+ case ctype_rgb:
+ bps = 8; bpp = 24; pixelAdd = 3*height; lineAdd = 3;
+ break;
+ default: RMInit::logOut << "r_Conv_TIFF::convertTo(): unknown base type!" << endl;
+ throw r_Error(BASETYPENOTSUPPORTEDBYOPERATION);
+ }
+
+ // Just to make sure nothing serious goes wrong if this conversion
+ // function is called more than once.
+ memfs_newfile(handle);
+
+ // Open a dummy output file (all operations will be redirected to
+ // Memory). Make dummy file unique for each object by using the
+ // address of its memFSContext (kind of a hack, I know...). That
+ // should ensure re-entrancy.
+ sprintf(dummyFile, dummyFileFmt, (void*)handle);
+ tif = TIFFClientOpen(dummyFile, "w", handle,
+ memfs_read, memfs_write, memfs_seek, memfs_close, memfs_size,
+ memfs_map, memfs_unmap);
+
+ if (tif == NULL)
+ {
+ RMInit::logOut << "r_Conv_TIFF::convertTo(): couldn't open file " << dummyFile << endl;
+ throw r_Error(r_Error::r_Error_General);
+ }
+
+ TIFFSetField(tif, TIFFTAG_ARTIST, "RasDaMan");
+ TIFFSetField(tif, TIFFTAG_DOCUMENTNAME, "Image");
+ TIFFSetField(tif, TIFFTAG_SOFTWARE, "RasDaMan");
+ //TIFFSetField(tif, TIFFTAG_SUBFILETYPE, (uint32)0);
+ TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width);
+ TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height);
+ TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bps);
+ // UNIX doesn't mind which fill-order. NT only understands this one.
+ TIFFSetField(tif, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB);
+ TIFFSetField(tif, TIFFTAG_COMPRESSION, (uint16)tiffcomp);
+ TIFFSetField(tif, TIFFTAG_ORIENTATION, (uint16)ORIENTATION_TOPLEFT);
+ // Format-dependent tags
+ if (desc.baseType == ctype_rgb)
+ {
+ TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, (uint16)PHOTOMETRIC_RGB);
+ TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, (uint16)3);
+ }
+ else
+ {
+ if (desc.baseType == ctype_char)
+ {
+ TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, (uint16)PHOTOMETRIC_PALETTE);
+ }
+ else
+ {
+ TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, (uint16)PHOTOMETRIC_MINISBLACK);
+ }
+ TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, (uint16)1);
+ }
+ TIFFSetField(tif, TIFFTAG_PLANARCONFIG, (uint16)PLANARCONFIG_CONTIG);
+ TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tif, (uint32)-1));
+ //TIFFSetField(tif, TIFFTAG_MINSAMPLEVALUE, (uint16)0);
+ //TIFFSetField(tif, TIFFTAG_MAXSAMPLEVALUE, (uint16)255);
+ TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, (uint16)RESUNIT_INCH);
+ TIFFSetField(tif, TIFFTAG_XRESOLUTION, (float)90.0);
+ TIFFSetField(tif, TIFFTAG_YRESOLUTION, (float)90.0);
+ TIFFSetField(tif, TIFFTAG_XPOSITION, (float)0.0);
+ TIFFSetField(tif, TIFFTAG_YPOSITION, (float)0.0);
+ if ((tiffcomp == COMPRESSION_JPEG) || (tiffcomp == COMPRESSION_OJPEG))
+ {
+ if (quality == 100)
+ {
+ TIFFSetField(tif, TIFFTAG_JPEGPROC, JPEGPROC_LOSSLESS);
+ }
+ else
+ {
+ TIFFSetField(tif, TIFFTAG_JPEGQUALITY, quality);
+ }
+ }
+
+ // build the colour-map (greyscale, i.e. all 3 components identical)
+ // TIFF needs 16 bit values for this (--> tools/tiffdither.c)
+ for (i=0; i<256; i++) cmap[i] = (uint16)(i*((1L << 16) - 1)/255);
+ TIFFSetField(tif, TIFFTAG_COLORMAP, cmap, cmap, cmap);
+
+ // Be VERY, VERY careful about the order and the items you write
+ // out. TIFFWriteDirectory, e.g., has very ugly side-effects.
+ uint32 *tbuff=NULL;
+ const char *l=NULL, *line = desc.src;
+ uint8 *normal=NULL; // normalised source data
+ uint32 row=0;
+
+ // cout << "r_Conv_TIFF: Main Loop:" << endl;
+ if ((tbuff = new uint32[((width * bpp + 31) >> 5)]) != NULL)
+ {
+ // now go line by line
+ for (row = 0; row < height; row++, line += lineAdd)
+ {
+ normal = (uint8 *)tbuff; l = line;
+
+ // copy data in the correct format to the buffer
+ switch (desc.baseType)
+ {
+ case ctype_bool:
+ {
+ uint8 val = 0, mask = _R_TIFF_MASK_VALUE;
+
+ // convert 8bpp bitmap to 1bpp bitmap
+ for (i=0; i < width; i++, l += pixelAdd)
+ {
+ // fill bits in lsb order
+ if (*l != 0) val |= mask;
+ _R_TIFF_MASK_SHIFT(mask);
+ if (mask == 0) {*normal++ = val; val = 0; mask = _R_TIFF_MASK_VALUE;}
+ }
+ if (mask != _R_TIFF_MASK_VALUE) *normal++ = val;
+ }
+ break;
+ case ctype_char:
+ {
+ // copy data (and transpose)
+ for (i=0; i < width; i++, l += pixelAdd)
+ {
+ *normal++ = *l;
+ }
+ }
+ break;
+ case ctype_rgb:
+ {
+ // copy data (and transpose)
+ for (i=0; i < width; i++, l += pixelAdd)
+ {
+ *normal++ = l[0]; *normal++ = l[1]; *normal++ = l[2];
+ }
+ }
+ break;
+ }
+ if (TIFFWriteScanline(tif, (tdata_t)tbuff, row, 0) < 0) break;
+ }
+
+ delete [] tbuff; tbuff = NULL;
+ }
+
+ if (row < height) // error
+ {
+ RMInit::logOut << "r_Conv_TIFF::convertTo(): error writing data!" << endl;
+ TIFFClose(tif); remove(dummyFile);
+ throw r_Error(r_Error::r_Error_General);
+ }
+
+ TIFFClose(tif);
+ // Now delete the dummy file
+ remove(dummyFile);
+
+ r_Long tifSize = memfs_size(handle);
+
+ // Allocate an array of just the right size and "load" object there
+ if ((desc.dest = (char*)mystore.storage_alloc(sizeof(char) * tifSize)) == NULL)
+ {
+ RMInit::logOut << "r_Conv_TIFF::convertTo(): out of memory" << endl;
+ throw r_Error(MEMMORYALLOCATIONERROR);
+ }
+ memfs_seek(handle, 0, SEEK_SET);
+ memfs_read(handle, desc.dest, tifSize);
+
+ // Set up destination interval
+ desc.destInterv = r_Minterval(1);
+ desc.destInterv << r_Sinterval(r_Range(0), r_Range(tifSize - 1));
+
+ // define the base type as char for now
+ desc.destType = r_Type::get_any_type("char");
+
+ return desc;
+}
+
+
+
+r_convDesc &r_Conv_TIFF::convertFrom(const char *options) throw(r_Error)
+{
+ if (options != NULL)
+ printf("tiff convert option = %s\n", options);
+ else
+ printf("tiff options are null = %s\n");
+ params->process(options);
+ TIFF *tif=NULL;
+ char dummyFile[256];
+ int isOK=0, typeSize=0;
+ uint16 bps=0, bpp=0, spp=0, planar=0, photometric=0;
+ uint32 width=0, height=0, pixelAdd=0, lineAdd=0, i=0;
+ uint16 *reds=NULL, *greens=NULL, *blues=NULL;
+
+ // Init simple (chunky) memFS
+ memfs_chunk_initfs(handle, (char*)desc.src, (r_Long)(desc.srcInterv[0].high()-desc.srcInterv[0].low()+1));
+
+ desc.dest = NULL;
+
+ // Create dummy file for use in the TIFF open function
+ sprintf(dummyFile, dummyFileFmt, (void*)handle);
+ fclose(fopen(dummyFile, "wb"));
+ //cout << "r_Conv_TIFF: Dummy created OK" << endl;
+
+ // Open and force memory mapping mode
+ tif = TIFFClientOpen(dummyFile, "rM", handle,
+ memfs_chunk_read, memfs_chunk_read, memfs_chunk_seek, memfs_chunk_close,
+ memfs_chunk_size, memfs_chunk_map, memfs_chunk_unmap);
+
+ if (tif == NULL)
+ {
+ RMInit::logOut << "r_Conv_TIFF::convertFrom(): unable to open file!" << endl;
+ throw r_Error(r_Error::r_Error_General);
+ }
+ //cout << "r_Conv_TIFF: Opened OK" << endl;
+
+ //TIFFPrintDirectory(tif, stdout, 0);
+
+ TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bps);
+ TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &spp);
+ bpp = spp * bps;
+ TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &planar);
+ TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);
+ TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);
+ TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometric);
+
+ // Filter out the kind of image we understand.
+ isOK = 1;
+ if ((bps != 1) && (bps != 8))
+ {
+ RMInit::logOut << "r_Conv_TIFF::convertFrom(): bad number of bits per sample: " << bps << " (must be 1 or 8)" << endl;
+ if (override_bps)
+ bps = override_bps;
+ else
+ isOK = 0;
+ }
+ if ((bpp != 1) && (bpp != 8) && (bpp != 24))
+ {
+ RMInit::logOut << "r_Conv_TIFF::convertFrom(): bad number of bits per pixel: " << bpp << " (must be 1, 8 or 24)" << endl;
+ if (override_bpp)
+ bpp = override_bpp;
+ else
+ isOK = 0;
+ }
+ if (planar != PLANARCONFIG_CONTIG)
+ {
+ RMInit::logOut << "r_Conv_TIFF::convertFrom(): can't handle bitplanes!" << endl;
+ isOK = 0;
+ }
+
+ if (isOK)
+ {
+ //cout << "r_Conv_TIFF: Image OK: bps = " << bps << ", spp = " << spp << ", width = " << width << ", height = " << height << endl;
+
+ if (bpp == 24)
+ {
+ pixelAdd = 3*height; lineAdd = 3; typeSize = 3;
+ desc.baseType = ctype_rgb;
+ }
+ else
+ {
+ if ((photometric == PHOTOMETRIC_PALETTE) && (override_depth != 1))
+ {
+ TIFFGetField(tif, TIFFTAG_COLORMAP, &reds, &greens, &blues);
+ for (i=0; i<256; i++)
+ {
+ if ((reds[i] != greens[i]) || (greens[i] != blues[i])) break;
+ }
+ if (i < 256)
+ {
+ pixelAdd = 3*height; lineAdd = 3; typeSize = 3;
+ desc.baseType = ctype_rgb;
+ }
+ else
+ {
+ pixelAdd = height; lineAdd = 1; typeSize = 1;
+ desc.baseType = ctype_char;
+ }
+ if (override_depth)
+ {
+ switch (override_depth)
+ {
+ case 1:
+ pixelAdd = height; lineAdd = 1; typeSize = 1;
+ desc.baseType = ctype_bool;
+ break;
+ case 8:
+ pixelAdd = height; lineAdd = 1; typeSize = 1;
+ desc.baseType = ctype_char;
+ break;
+ case 24:
+ pixelAdd = 3*height; lineAdd = 3; typeSize = 3;
+ desc.baseType = ctype_rgb;
+ break;
+ }
+ }
+ }
+ else
+ {
+ pixelAdd = height; lineAdd = 1; typeSize = 1;
+ desc.baseType = (bpp == 1) ? ctype_bool : ctype_char;
+ }
+ }
+
+ if ((desc.dest = (char*)mystore.storage_alloc(width*height*typeSize*sizeof(char))) == NULL)
+ {
+ RMInit::logOut << "r_Conv_TIFF::convertFrom(): out of memory error!" << endl;
+ }
+ else
+ {
+ //cout << "r_Conv_TIFF: baseType = " << desc.baseType << ", size = " << typeSize << ", pixelAdd = " << pixelAdd << ", lineAdd = " << lineAdd << endl;
+
+ uint32 *tbuff=NULL;
+ char *l=NULL, *line = desc.dest;
+ uint8 *normal=NULL;
+ uint32 row = 0;
+
+ if ((tbuff = new uint32[(width * bpp + 31) >> 5]) != NULL)
+ {
+ for (row = 0; row < height; row++, line += lineAdd)
+ {
+ if (TIFFReadScanline(tif, (tdata_t)tbuff, row, 0) < 0) break;
+
+ normal = (uint8 *)tbuff; l = line;
+
+ switch (desc.baseType)
+ {
+ case ctype_bool:
+ {
+ uint8 mask = _R_TIFF_MASK_VALUE;
+
+ for (i=0; i < width; i++, l += pixelAdd)
+ {
+ *l = (((*normal) & mask) == 0) ? 0 : 1;
+ _R_TIFF_MASK_SHIFT(mask);
+ if (mask == 0) {normal++; mask = _R_TIFF_MASK_VALUE;}
+ }
+ }
+ break;
+ case ctype_char:
+ {
+ if (reds != NULL)
+ {
+ for (i=0; i < width; i++, l += pixelAdd)
+ {
+ *l = (reds[*normal++]) >> 8;
+ }
+ }
+ else
+ {
+ for (i=0; i < width; i++, l += pixelAdd)
+ {
+ *l = *normal++;
+ }
+ }
+ }
+ break;
+ case ctype_rgb:
+ {
+ if (reds != NULL)
+ {
+ for (i=0; i < width; i++, l += pixelAdd)
+ {
+ uint8 val = *normal++;
+
+ l[0] = (reds[val]) >> 8;
+ l[1] = (greens[val]) >> 8;
+ l[2] = (blues[val]) >> 8;
+ }
+ }
+ else
+ {
+ for (i=0; i < width; i++, l += pixelAdd)
+ {
+ l[0] = *normal++; l[1] = *normal++; l[2] = *normal++;
+ }
+ }
+ }
+ break;
+ }
+ }
+ delete [] tbuff; tbuff = NULL;
+ }
+
+ if (row < height)
+ {
+ RMInit::logOut << "r_Conv_TIFF::convertFrom(): error reading data!" << endl;
+ TIFFClose(tif); remove(dummyFile);
+ throw r_Error(r_Error::r_Error_General);
+ }
+ }
+ }
+
+ TIFFClose(tif);
+
+ remove(dummyFile);
+
+ // Build destination interval
+ desc.destInterv = r_Minterval(2);
+ desc.destInterv << r_Sinterval(r_Range(0), r_Range(width - 1))
+ << r_Sinterval( r_Range(0), r_Range(height - 1));
+
+ desc.destType = get_external_type(desc.baseType);
+
+ return desc;
+}
+
+
+
+const char *r_Conv_TIFF::get_name( void ) const
+{
+ return format_name_tiff;
+}
+
+
+r_Data_Format r_Conv_TIFF::get_data_format( void ) const
+{
+ return r_TIFF;
+}
+
+
+r_Convertor *r_Conv_TIFF::clone( void ) const
+{
+ return new r_Conv_TIFF(desc.src, desc.srcInterv, desc.baseType);
+}
diff --git a/conversion/tiff.hh b/conversion/tiff.hh
new file mode 100644
index 0000000..008f1c5
--- /dev/null
+++ b/conversion/tiff.hh
@@ -0,0 +1,145 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: tiff.hh
+ *
+ * MODULE: conversion
+ *
+ * PURPOSE:
+ * Provides interface to convert data between TIFF and internal format.
+ * The convertFrom() and convertTo() methods accept a null-terminated
+ * option string of the following syntax:
+ * optionString ::= ( option )*
+ * option ::= "comptype=" string
+ * "quality=" int
+ * "bpp=" int
+ * "bps=" int
+ * "depth=" int
+ *
+ * CLASSES: r_Conv_TIFF
+ *
+ * COMMENTS:
+ *
+*/
+
+#ifndef _R_CONV_TIFF_HH_
+#define _R_CONV_TIFF_HH_
+
+#include "conversion/convertor.hh"
+
+
+
+//@ManMemo: Module {\bf conversion}
+
+/*@Doc:
+ TIFF convertor class.
+
+ Supported parameters are
+
+ \begin{tabular}{lcl}
+ {\tt comptype} && string && compression type (see below)\\
+ {\tt quality} && int && quality parameter (JPEG)\\
+ {\tt bpp} && int && override number of bits per p (if not set in the tiff)\\
+ {\tt bps} && int && override number of bits per s (if not set in the tiff)\\
+ {\tt depth} && int && override number of colors in the mdd\\
+ \end{tabular}
+
+ The compression type defaults to lzw, but it may be one of the
+ following (but not all types may be supported by the version of
+ the TIFF library; note also that some compression types are only
+ valid for specific colour depths):
+
+ \begin{tabular}{ll}
+ {\tt none}\\
+ {\tt ccittrle}\\
+ {\tt ccittfax3}\\
+ {\tt ccittfax4}\\
+ {\tt lzw}\\
+ {\tt ojpeg}\\
+ {\tt jpeg}\\
+ {\tt next}\\
+ {\tt ccittrlew}\\
+ {\tt packbits}\\
+ {\tt thunderscan}\\
+ {\tt pixarfilm}\\
+ {\tt pixarlog}\\
+ {\tt deflate}\\
+ {\tt dcs}\\
+ {\tt jbig}\\
+ {\tt sgilog} && Not Linux\\
+ {\tt sgilog24} && Not Linux\\
+ {\tt it8ctpad} && Not Linux\\
+ {\tt it8lw} && Not Linux\\
+ {\tt it8mp} && Not Linux\\
+ {\tt it8bl} && Not Linux\\
+ \end{tabular}
+
+ For more information refer to the TIFFlib manual pages.
+ */
+
+class r_Conv_TIFF : public r_Convert_Memory
+{
+ public:
+ /// constructor using an r_Type object
+ r_Conv_TIFF( const char *src, const r_Minterval &interv, const r_Type *tp ) throw(r_Error);
+ /// constructor using convert_type_e shortcut
+ r_Conv_TIFF( const char *src, const r_Minterval &interv, int type ) throw(r_Error);
+ /// destructor
+ ~r_Conv_TIFF( void );
+
+ /// convert to TIFF
+ virtual r_convDesc &convertTo( const char *options=NULL) throw(r_Error);
+ /// convert from TIFF
+ virtual r_convDesc &convertFrom( const char *options=NULL ) throw(r_Error);
+ /// cloning
+ virtual r_Convertor *clone( void ) const;
+ /// identification
+ virtual const char *get_name( void ) const;
+ virtual r_Data_Format get_data_format( void ) const;
+
+ /// translate string compression type to libtiff compression type
+ static int get_compression_from_name(const char* strComp);
+
+ /// translate string resolution unit type to libtiff resolution unit type
+ static int get_resunit_from_name(const char* strComp);
+
+ private:
+ /// init TIFF class
+ void initTIFF( void );
+ /// parameters
+ char *compType;
+ int quality;
+ int override_bpp;
+ int override_bps;
+ int override_depth;
+ /// connection between string compression type and libtiff compression type
+ static const convert_string_t compNames[];
+ /// connection between string resolution unit type and libtiff resolution unit type
+ static const convert_string_t resunitNames[];
+ /// default rows per strip (32)
+ static const int defaultRPS;
+ /// temporary dummy file
+ static const char dummyFileFmt[];
+};
+
+#endif
diff --git a/conversion/tor.cc b/conversion/tor.cc
new file mode 100644
index 0000000..0663fd4
--- /dev/null
+++ b/conversion/tor.cc
@@ -0,0 +1,230 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#include "conversion/tor.hh"
+#include "raslib/endian.hh"
+#include "raslib/rminit.hh"
+#include "raslib/parseparams.hh"
+#include "raslib/primitivetype.hh"
+
+void r_Conv_TOR::initTOR()
+{
+ if(params ==NULL)
+ {
+ params = new r_Parse_Params(3);
+ }
+}
+
+r_Conv_TOR::r_Conv_TOR(const char* source, const r_Minterval& lengthordomain, const r_Type* tp) throw(r_Error)
+ : r_Convertor(source, lengthordomain, tp, true)
+ {
+ initTOR();
+ }
+
+r_Conv_TOR::r_Conv_TOR(const char* source, const r_Minterval& lengthordomain, int tp) throw(r_Error)
+ : r_Convertor(source, lengthordomain, tp)
+ {
+ initTOR();
+ }
+
+r_convDesc&
+r_Conv_TOR::convertFrom(const char* options) throw (r_Error)
+ {
+ int swap = 0;
+ int rescale = 0;
+ char* domain = NULL;
+ params->add("swapendianness", &swap, r_Parse_Params::param_type_int);
+ params->add("rescale", &rescale, r_Parse_Params::param_type_int);
+ params->add("domain", &domain, r_Parse_Params::param_type_string);
+ params->process(options);
+ r_Minterval t;
+ RMInit::logOut << "r_Conv_TOR::convert swap " << swap << " rescale " << rescale << " domain " << (domain?domain:"NULL") << std::endl;
+ if (domain == NULL)
+ {
+ RMInit::logOut << "r_Conv_TOR::convertFrom no domain specified in options string" << std::endl;
+ throw r_Error();
+ }
+ try {
+ t = r_Minterval(domain);
+ }
+ catch (r_Eno_interval& e)
+ {
+ RMInit::logOut << "r_Conv_TOR::convertFrom no correct domain specified in options string" << std::endl;
+ throw r_Error();
+ }
+ if (t.dimension() != 2)
+ {
+ RMInit::logOut << "r_Conv_TOR::convertFrom domain in options string must have 2 dimensions" << std::endl;
+ throw r_Error();
+ }
+ r_Range x = t[0].high() - t[0].low() + 1;
+ r_Range y = t[1].high() - t[1].low() + 1;
+ r_UShort* array = (r_UShort*)mystore.storage_alloc(x * y * sizeof(r_UShort));
+ double max = 0;
+ double min = 0;
+ r_Char tc;
+ double maxu = 0;
+ double minu = 0;
+ r_UShort tu;
+ switch (desc.baseType)
+ {
+ case ctype_bool:
+ case ctype_char:
+ case ctype_uint8:
+ if (desc.srcInterv[0].high() - desc.srcInterv[0].low() + 1 != t.cell_count() * sizeof(r_Char))
+ {
+ RMInit::logOut << "r_Conv_TOR::convertFrom the supplied data is " << desc.srcInterv[0].high() - desc.srcInterv[0].low() + 1 << " bytes, but " << t.cell_count() << " bytes were expected" << std::endl;
+ throw r_Error();
+ }
+ get_limits(&tc, min, max);
+ get_limits(&tu, minu, maxu);
+ for(int i=0; i < x; i++)
+ {
+ for(int j=0; j < y; j++)
+ {
+ if (rescale)
+ array[i * x + j] = ((r_Octet*)desc.src)[j * x + i] / max * maxu;
+ else
+ array[i * x + j] = ((r_Octet*)desc.src)[j * x + i];
+ }
+ }
+ break;
+ case ctype_uint16:
+ if (desc.srcInterv[0].high() - desc.srcInterv[0].low() + 1 != t.cell_count() * sizeof(r_UShort))
+ {
+ RMInit::logOut << "r_Conv_TOR::convertFrom the supplied data is " << desc.srcInterv[0].high() - desc.srcInterv[0].low() + 1 << " bytes, but " << t.cell_count() << " bytes were expected" << std::endl;
+ throw r_Error();
+ }
+ for(int i=0; i < x; i++)
+ {
+ for(int j=0; j < y; j++)
+ {
+ array[i * x + j] = ((r_UShort*)desc.src)[j * x + i];
+ }
+ }
+ break;
+ default:
+ RMInit::logOut << "r_Conv_TOR unknown base type!" << std::endl;
+ throw r_Error();
+ }
+ if (swap)
+ {
+ r_UShort* temp = (r_UShort*)mystore.storage_alloc(x * y * sizeof(r_UShort));
+ r_Endian::swap_array(x * y * sizeof(r_UShort), array, temp);
+ mystore.storage_free(array);
+ array = temp;
+ }
+
+ desc.dest = (char*)array;
+ desc.destInterv = t;
+ desc.destType = new r_Primitive_Type("UShort", r_Type::USHORT);
+ return desc;
+ }
+
+r_convDesc&
+r_Conv_TOR::convertTo(const char* options) throw (r_Error)
+ {
+ int swap = 0;
+ int rescale = 0;
+ params->add("swapendianness", &swap, r_Parse_Params::param_type_int);
+ params->add("rescale", &rescale, r_Parse_Params::param_type_int);
+ params->process(options);
+ if (desc.srcInterv.dimension() != 2)
+ {
+ RMInit::logOut << "r_Conv_TOR::convertFrom domain in options string must have 2 dimensions" << std::endl;
+ throw r_Error();
+ }
+ r_Range x = desc.srcInterv[0].high() - desc.srcInterv[0].low() + 1;
+ r_Range y = desc.srcInterv[1].high() - desc.srcInterv[1].low() + 1;
+ r_UShort* array = (r_UShort*)mystore.storage_alloc(x * y * sizeof(r_UShort));
+ double max = 0;
+ double min = 0;
+ r_Char tc;
+ double maxu = 0;
+ double minu = 0;
+ r_UShort tu;
+ switch (desc.baseType)
+ {
+ case ctype_bool:
+ case ctype_char:
+ case ctype_uint8:
+ get_limits(&tc, min, max);
+ get_limits(&tu, minu, maxu);
+ for(int i=0; i < x; i++)
+ {
+ for(int j=0; j < y; j++)
+ {
+ if (rescale)
+ array[i * x + j] = ((r_Octet*)desc.src)[j * x + i] / max * maxu;
+ else
+ array[i * x + j] = ((r_Octet*)desc.src)[j * x + i];
+ }
+ }
+ break;
+ case ctype_uint16:
+ for(int i=0; i < x; i++)
+ {
+ for(int j=0; j < y; j++)
+ {
+ array[i * x + j] = ((r_UShort*)desc.src)[j * x + i];
+ }
+ }
+ break;
+ default:
+ RMInit::logOut << "r_Conv_TOR unknown base type!" << std::endl;
+ throw r_Error();
+ }
+ if (swap)
+ {
+ r_UShort* temp =(r_UShort*)mystore.storage_alloc(x * y * sizeof(r_UShort));
+ r_Endian::swap_array(x * y * sizeof(r_UShort), array, temp);
+ mystore.storage_free(array);
+ array = temp;
+ }
+
+ desc.dest = (char*)array;
+ r_Minterval td(1);
+ td << r_Sinterval((r_Range)0, (r_Range)(desc.srcInterv.cell_count() * sizeof(r_UShort) - 1));
+ desc.destInterv = td;
+ desc.destType = new r_Primitive_Type("Char", r_Type::CHAR);
+ return desc;
+ }
+
+const char*
+r_Conv_TOR::get_name() const
+ {
+ return get_name_from_data_format(r_TOR);
+ }
+
+r_Data_Format
+r_Conv_TOR::get_data_format() const
+ {
+ return r_TOR;
+ }
+
+r_Convertor*
+r_Conv_TOR::clone() const
+ {
+ return new r_Conv_TOR(desc.src, desc.srcInterv, desc.srcType);
+ }
+
diff --git a/conversion/tor.hh b/conversion/tor.hh
new file mode 100644
index 0000000..d7bd189
--- /dev/null
+++ b/conversion/tor.hh
@@ -0,0 +1,82 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: tor.hh
+ *
+ * MODULE: conversion
+ *
+ * CLASSES: r_Conv_TOR
+ *
+ * COMMENTS:
+ *
+ * Provides interface to convert data from/to TOR to/from r_Array
+ *
+*/
+
+#ifndef _R_CONV_TOR_HH_
+#define _R_CONV_TOR_HH_
+#include "conversion/convertor.hh"
+
+//@ManMemo: Module {\bf conversion}
+
+/*@Doc:
+ TOR convertor class.
+
+ Supported parameters are
+
+ \begin{tabular}{lcl}
+ {\tt swapendianness} && int && flag for swapendianness, default 0\\
+ {\tt rescale} && int && flag for rescale, default 0\\
+ {\tt domain} && string && domain string of TOR file\\
+ \end{tabular}
+
+ The "swapendianness" parameter is a flag for endianness change operation.
+ The "rescale" parameter is a flag for rescale operation.
+*/
+
+
+class r_Conv_TOR : public r_Convertor
+ {
+ public:
+ r_Conv_TOR(const char* source, const r_Minterval& lengthordomain, const r_Type* tp) throw(r_Error);
+
+ r_Conv_TOR(const char* source, const r_Minterval& lengthordomain, int tp) throw(r_Error);
+
+ r_convDesc& convertFrom(const char* options = NULL) throw (r_Error);
+
+ r_convDesc& convertTo(const char* options = NULL) throw (r_Error);
+
+ const char* get_name() const;
+
+ r_Data_Format get_data_format() const;
+
+ r_Convertor* clone() const;
+
+
+ private:
+ void initTOR();
+
+ };
+
+#endif
+
diff --git a/conversion/utilities.cc b/conversion/utilities.cc
new file mode 100644
index 0000000..7b8df84
--- /dev/null
+++ b/conversion/utilities.cc
@@ -0,0 +1,109 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#include <cstdio>
+#include <cstring>
+#include <cstdlib>
+#include <sys/types.h>
+#include <unistd.h>
+#include <iostream>
+#include <fstream>
+#include <string>
+
+#include "utilities.h"
+
+using namespace std;
+using namespace RasNITF;
+
+long RasNITF::read_verify(std::istream &fNITF, char *destination, long length, char *sErrorMessage, bool nullify)
+
+{
+ long rc;
+
+ fNITF.read(destination, length);
+ rc = fNITF.gcount();
+
+ if (!fNITF.good()){
+ cout<<sErrorMessage<<endl;
+ exit(1);
+ }
+
+ if (rc != length) {
+ cout<<sErrorMessage<<endl;
+ exit(1);
+ }
+
+ if (nullify)
+ destination[length] = '\0';
+
+ return rc;
+}
+
+long RasNITF::read_verify2(std::istream &fNITF, char *destination, long length)
+
+{
+ long rc;
+
+ fNITF.read(destination, length);
+ rc = fNITF.gcount();
+
+ if (!fNITF.good()){
+ exit(3);
+ }
+
+ if (rc != length) {
+ exit(4);
+ }
+
+ return rc;
+}
+
+
+int RasNITF::charptrtoint(const char *str, int length){
+
+ int num;
+ string temp;
+
+ if (length > 5) {
+
+ cout << "WARNING LOSING DATA from long to int conversion" << endl;
+
+ }
+
+
+ temp.assign(str, length);
+ num = atoi(temp.c_str());
+
+ return num;
+}
+
+long RasNITF::charptrtolong(const char *str, int length){
+
+ long num;
+ string temp;
+
+ temp.assign(str, length);
+ num = atol(temp.c_str());
+
+ return num;
+}
diff --git a/conversion/utilities.h b/conversion/utilities.h
new file mode 100644
index 0000000..3b74a38
--- /dev/null
+++ b/conversion/utilities.h
@@ -0,0 +1,35 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#ifndef __UTILITIES_H_INCLUDED
+#define __UTILITIES_H_INCLUDED
+
+namespace RasNITF {
+
+ long read_verify(std::istream &fNITF, char *destination, long length, char *sErrorMessage, bool nullify);
+ long read_verify2(std::istream &fNITF, char *destination, long length);
+ int charptrtoint(const char *str, int length);
+ long charptrtolong(const char *str, int length);
+
+}
+#endif
diff --git a/conversion/vff.cc b/conversion/vff.cc
new file mode 100644
index 0000000..25b58f7
--- /dev/null
+++ b/conversion/vff.cc
@@ -0,0 +1,797 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * FILE: vff.cc
+ *
+ * MODULE: conversion
+ *
+ * CLASSES: r_Conv_VFF
+ *
+ * COMMENTS:
+ *
+ * Provides interface to convert data to VFF and back.
+ *
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <iostream>
+#include <strstream>
+
+#include "raslib/rminit.hh"
+#include "raslib/endian.hh"
+#include "raslib/miterd.hh"
+#include "raslib/odmgtypes.hh"
+#include "raslib/parseparams.hh"
+#include "conversion/vff.hh"
+
+
+// file magic
+const char *r_Conv_VFF::fileMagic = "ncaa";
+
+// keyword enumerators, must be kept in sync with keywords
+enum vff_keyword_e {
+ vffkey_rank = 0,
+ vffkey_type,
+ vffkey_format,
+ vffkey_size,
+ vffkey_origin,
+ vffkey_extent,
+ vffkey_aspect,
+ vffkey_bands,
+ vffkey_bits,
+ vffkey_value,
+ vffkey_endian,
+ vffkey_dorder,
+ vffkey_NUMBER
+};
+
+// Keywords
+const char *r_Conv_VFF::keywords[] = {
+ // mandatory
+ "rank",
+ "type",
+ "format",
+ "size",
+ "origin",
+ "extent",
+ "aspect",
+ "bands",
+ "bits",
+ // optional
+ "value",
+ "endianness",
+ "data_order"
+};
+
+// values
+const char *r_Conv_VFF::kval_Raster = "raster";
+const char *r_Conv_VFF::kval_Slice = "slice";
+const char *r_Conv_VFF::kval_LEndian = "little_endian";
+const char *r_Conv_VFF::kval_BEndian = "big_endian";
+
+// default data order
+const char *r_Conv_VFF::dfltDataOrder2 = "xy";
+const char *r_Conv_VFF::dfltDataOrder3 = "yzx";
+
+// default dimension order
+const char *r_Conv_VFF::dfltDimOrder2 = "xy";
+const char *r_Conv_VFF::dfltDimOrder3 = "yzx";
+
+// end of header
+const char r_Conv_VFF::endOfHeader = 0x0c;
+
+// method names
+const char *r_Conv_VFF::method_convTo = "r_Conv_VFF::convertTo()";
+const char *r_Conv_VFF::method_convFrom = "r_Conv_VFF::convertFrom()";
+
+
+r_Conv_VFF::r_Conv_VFF( const char *src, const r_Minterval &interv, int tp ) throw(r_Error)
+: r_Convertor(src, interv, tp)
+{
+ initVFF();
+}
+
+
+r_Conv_VFF::r_Conv_VFF( const char *src, const r_Minterval &interv, const r_Type *tp ) throw(r_Error)
+: r_Convertor(src, interv, tp, true)
+{
+ initVFF();
+}
+
+
+r_Conv_VFF::~r_Conv_VFF( void )
+{
+ if (dorderParam != NULL)
+ delete [] dorderParam;
+ if (dimOrderParam != NULL)
+ delete [] dimOrderParam;
+}
+
+
+void r_Conv_VFF::initVFF( void )
+{
+ dorderParam = NULL;
+ dimOrderParam = NULL;
+ dfltEndianness = 0; // big endian
+
+ if (params == NULL)
+ params = new r_Parse_Params;
+
+ params->add("dorder", &dorderParam, r_Parse_Params::param_type_string);
+ params->add("dimorder", &dimOrderParam, r_Parse_Params::param_type_string);
+ params->add("vffendian", &dfltEndianness, r_Parse_Params::param_type_int);
+}
+
+
+void r_Conv_VFF::skip_white( const char *&str )
+{
+ while ((*str != endOfHeader) && (isspace((unsigned int)(*str)))) str++;
+}
+
+void r_Conv_VFF::write_interval( const char *keyname, std::ostream &str, const r_Minterval &iv, const unsigned int *order, r_Range inc )
+{
+ r_Dimension i;
+ str << keyname << '=' << (iv[order[0]].high() - iv[order[0]].low() + inc);
+ for (i=1; i<iv.dimension(); i++)
+ str << ' ' << (iv[order[i]].high() - iv[order[i]].low() + inc);
+ str << ";\n";
+}
+
+void r_Conv_VFF::write_origin( const char *keyname, std::ostream &str, const r_Minterval &iv, const unsigned int *order )
+{
+ r_Dimension i;
+ str << keyname << '=' << iv[order[0]].low();
+ for (i=1; i<iv.dimension(); i++)
+ str << ' ' << iv[order[i]].low();
+ str << ";\n";
+}
+
+const char *r_Conv_VFF::read_vector( r_Dimension dim, const char *str, double *&vec )
+{
+ if (dim == 0)
+ return NULL;
+
+ vec = new double[dim];
+ r_Dimension i;
+
+ for (i=0; i<dim; i++)
+ {
+ const char *rest;
+ vec[i] = strtod(str, (char**)&rest);
+ if (str == rest)
+ break;
+ str = rest;
+ }
+ if (i < dim)
+ {
+ delete [] vec;
+ vec = NULL;
+ return NULL;
+ }
+ return str;
+}
+
+const char *r_Conv_VFF::read_string( const char *str, char *dest, bool allowSpace )
+{
+ const char *d = str;
+ char *b = dest;
+
+ while (*d != ';')
+ {
+ if ((allowSpace == 1) && (isspace((unsigned int)(*d))))
+ break;
+ *b++ = *d++;
+ }
+ *b++ = '\0';
+ return d;
+}
+
+const char *r_Conv_VFF::get_endian_id( void )
+{
+ return ((r_Endian::get_endianness() == r_Endian::r_Endian_Big) ? kval_BEndian : kval_LEndian);
+}
+
+
+const char *r_Conv_VFF::get_default_order( r_Dimension dim )
+{
+ return (dim == 2) ? dfltDataOrder2 : dfltDataOrder3;
+}
+
+
+const char *r_Conv_VFF::get_default_dim_order( r_Dimension dim )
+{
+ return (dim == 2) ? dfltDimOrder2 : dfltDimOrder3;
+}
+
+
+int r_Conv_VFF::parse_data_order( r_Dimension dim, const char *dstr, unsigned int *order )
+{
+ unsigned char *mapped = new unsigned char[dim];
+ unsigned int i;
+
+ memset(mapped, 0, dim);
+ for (i=0; i<dim; i++)
+ {
+ unsigned int map;
+
+ switch (dstr[i])
+ {
+ case 'x':
+ map = 1; break;
+ case 'y':
+ map = 2; break;
+ case 'z':
+ map = 3; break;
+ default:
+ map = 0; break;
+ }
+
+ if ((map == 0) || (mapped[map-1] != 0))
+ break;
+
+ order[i] = map-1;
+ mapped[map-1] = 1;
+ //cout << order[i] << endl;
+ }
+
+ delete [] mapped;
+
+ if (i < dim)
+ {
+ RMInit::logOut << "r_Conv_VFF::parse_data_order(): descriptor " << dstr
+ << " inconsistent, revert to defaults" << endl;
+
+ return parse_data_order(dim, get_default_order(dim), order);
+ }
+
+ return 0;
+}
+
+
+unsigned int *r_Conv_VFF::get_dimension_order( r_Dimension dim ) const
+{
+ unsigned int *order = new unsigned int[dim];
+ char dimOrder[8];
+
+ // Anders Ledberg: Karolinska reader _always_ uses yzx as dimension order
+ if (dimOrderParam == NULL)
+ strncpy(dimOrder, get_default_dim_order(dim), 8);
+ else
+ strncpy(dimOrder, dimOrderParam, 8);
+
+ dimOrder[7] = '\0';
+ parse_data_order(dim, dimOrder, order);
+
+ return order;
+}
+
+
+const char *r_Conv_VFF::get_default_endianness( void ) const
+{
+ return (dfltEndianness == 0) ? kval_BEndian : kval_LEndian;
+}
+
+
+r_convDesc &r_Conv_VFF::convertTo( const char *options ) throw(r_Error)
+{
+ r_Dimension dim;
+ int bits, typeSize;
+ char header[1024]; // and ``640k should be enough for everyone''...
+ char dataOrder[8];
+
+ dim = desc.srcInterv.dimension();
+ if ((dim < 2) || (dim > 3))
+ {
+ r_Error err(r_Error::r_Error_General);
+ throw(err);
+ }
+
+ switch (desc.baseType)
+ {
+ case ctype_bool:
+ case ctype_char:
+ case ctype_int8:
+ case ctype_uint8:
+ bits = 8; typeSize = 1; break;
+ case ctype_int16:
+ case ctype_uint16:
+ bits = 16; typeSize = 2; break;
+ case ctype_int32:
+ case ctype_uint32:
+ bits = 32; typeSize = 4; break;
+ default:
+ r_Error err(r_Error::r_Error_General);
+ throw(err);
+ break;
+ }
+ //cout << "TYPE " << desc.baseType << ", SIZE " << typeSize << endl;
+
+ if (options != NULL)
+ params->process(options);
+
+ if (dorderParam != NULL)
+ strcpy(dataOrder, dorderParam);
+ else
+ strcpy(dataOrder, get_default_order(dim));
+
+ std::ostrstream memstr(header, 1024);
+
+ // order of dimensions in vectors
+ unsigned int *dimOrder = get_dimension_order(dim);
+
+ // write header
+ memstr << fileMagic << '\n';
+ memstr << keywords[vffkey_rank] << '=' << dim << ";\n";
+ memstr << keywords[vffkey_type] << '=' << kval_Raster << ";\n";
+ memstr << keywords[vffkey_format] << '=' << kval_Slice << ";\n";
+ // the dimensions are still ordered like in the VFF file, only the internal
+ // linearization differs!
+ write_interval(keywords[vffkey_size], memstr, desc.srcInterv, dimOrder, 1);
+ write_origin(keywords[vffkey_origin], memstr, desc.srcInterv, dimOrder);
+ write_interval(keywords[vffkey_extent], memstr, desc.srcInterv, dimOrder);
+ if (dim == 2)
+ {
+ // FIXME, aspect should be modelled too
+ memstr << keywords[vffkey_aspect] << "=1.0 1.0;\n";
+ }
+ else
+ {
+ // FIXME, ditto
+ memstr << keywords[vffkey_aspect] << "=1.0 1.0 1.0;\n";
+ }
+
+ // only suypport one band ATM
+ memstr << keywords[vffkey_bands] << "=1;\n";
+ memstr << keywords[vffkey_bits] << '=' << bits << ";\n";
+ memstr << keywords[vffkey_endian] << '=' << get_endian_id() << ";\n";
+ memstr << keywords[vffkey_dorder] << '=' << dataOrder << ";\n";
+ memstr << '\n' << endOfHeader << '\n' << '\0';
+
+ unsigned long headerSize, dataSize, totalSize;
+
+ headerSize = strlen(header);
+ dataSize = desc.srcInterv.cell_count() * typeSize;
+ totalSize = headerSize + dataSize;
+
+ if ((desc.dest = (char*)mystore.storage_alloc(headerSize + dataSize)) == NULL)
+ {
+ r_Error err(r_Error::r_Error_General);
+ throw(err);
+ }
+ memcpy(desc.dest, header, headerSize);
+
+ // treat all dimensions alike thanks to generic iterators
+
+ // source iterator, iterate in user order
+ r_MiterDirect iter((void*)desc.src, desc.srcInterv, desc.srcInterv, typeSize, 1);
+ unsigned int *order, *steps;
+
+ order = new unsigned int[dim];
+ steps = new unsigned int[dim];
+
+ for (unsigned int i=0; i<dim; i++)
+ steps[i] = 1;
+
+ parse_data_order(dim, dataOrder, order);
+
+ // note: dest may not be aligned to a position conforming to its base type,
+ // so copy byte-wise.
+ unsigned char *dptr = (unsigned char*)(desc.dest + headerSize);
+ switch (typeSize)
+ {
+ case 1:
+ {
+ while (iter.isDone() == 0)
+ {
+ *dptr = *((const unsigned char*)iter.getData(order));
+ iter.iterateUserOrder(order, steps);
+ dptr++;
+ }
+ }
+ break;
+ case 2:
+ {
+ while (iter.isDone() == 0)
+ {
+ const unsigned char *sptr = (const unsigned char*)iter.getData(order);
+ dptr[0] = sptr[0];
+ dptr[1] = sptr[1];
+ //cout << iter << ':' << (long)((const char*)sptr-desc.src) << ':' << (unsigned short)((sptr[0] << 8) | (sptr[1])) << ' ';
+ iter.iterateUserOrder(order, steps);
+ dptr+=2;
+ }
+ }
+ break;
+ case 4:
+ {
+ while (iter.isDone() == 0)
+ {
+ const unsigned char *sptr = (const unsigned char*)iter.getData(order);
+ dptr[0] = sptr[0];
+ dptr[1] = sptr[1];
+ dptr[2] = sptr[2];
+ dptr[3] = sptr[3];
+ iter.iterateUserOrder(order, steps);
+ dptr+=4;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ delete [] steps;
+ delete [] order;
+ delete [] dimOrder;
+
+ desc.destInterv = r_Minterval(1);
+ desc.destInterv << r_Sinterval((r_Range)0, (r_Range)totalSize-1);
+ desc.destType = r_Type::get_any_type("char");
+
+ return desc;
+}
+
+
+r_convDesc &r_Conv_VFF::convertFrom( const char *options ) throw(r_Error)
+{
+ const char *header = desc.src;
+ unsigned char *keysRead;
+ unsigned int i;
+ r_Dimension dim=0;
+ int bits, bands;
+ double *vecSize, *vecOrigin, *vecValue;
+ char endian[32];
+ char dataOrder[8];
+
+ if (strncmp(header, fileMagic, strlen(fileMagic)) != 0)
+ {
+ r_Error err(r_Error::r_Error_General);
+ throw(err);
+ }
+
+ keysRead = new unsigned char[vffkey_NUMBER];
+ memset(keysRead, 0, vffkey_NUMBER);
+
+ header += strlen(fileMagic);
+ skip_white(header);
+
+ vecSize = NULL;
+ vecOrigin = NULL;
+ vecValue = NULL;
+
+ strcpy(endian, get_default_endianness());
+
+ if (options != NULL)
+ params->process(options);
+
+ // no order -- check later if one was defined and init it _after_ we know the rank
+ dataOrder[0] = '\0';
+
+ do
+ {
+ if (*header != endOfHeader);
+ {
+ const char *rest;
+ double *vecTemp;
+
+ for (i=0; i<(unsigned int)vffkey_NUMBER; i++)
+ {
+ if (strncmp(header, keywords[i], strlen(keywords[i])) == 0)
+ break;
+ }
+
+ if (i == vffkey_NUMBER)
+ {
+ // skip unknown keywords
+ while ((*header != ';') && (*header != endOfHeader))
+ header++;
+ if (*header == ';')
+ header++;
+ }
+ else
+ {
+ //cout << "KEY " << keywords[i] << endl;
+
+ keysRead[i] = 1;
+
+ header += strlen(keywords[i]);
+ skip_white(header);
+
+ if (*header != '=')
+ break;
+
+ header++;
+ skip_white(header);
+
+ rest = header;
+ switch ((vff_keyword_e)i)
+ {
+ case vffkey_rank:
+ dim = strtol(header, (char**)&rest, 10);
+ if ((rest == header) || (dim < 2) || (dim > 3))
+ {
+ RMInit::logOut << method_convFrom << ": bad rank " << dim << endl;
+ rest = NULL;
+ }
+ break;
+ case vffkey_type:
+ if (strncmp(header, kval_Raster, strlen(kval_Raster)) == 0)
+ rest = header + strlen(kval_Raster);
+ else
+ {
+ RMInit::logOut << method_convFrom << ": bad type" << endl;
+ rest = NULL;
+ }
+ break;
+ case vffkey_format:
+ if (strncmp(header, kval_Slice, strlen(kval_Slice)) == 0)
+ rest = header + strlen(kval_Slice);
+ else
+ {
+ RMInit::logOut << method_convFrom << ": bad format" << endl;
+ rest = NULL;
+ }
+ break;
+ case vffkey_size:
+ rest = read_vector(dim, header, vecSize);
+ break;
+ case vffkey_origin:
+ rest = read_vector(dim, header, vecOrigin);
+ break;
+ case vffkey_extent:
+ // extent just parsed, otherwise ignored
+ rest = read_vector(dim, header, vecTemp);
+ delete [] vecTemp;
+ break;
+ case vffkey_aspect:
+ // FIXME: aspect ignored
+ rest = read_vector(dim, header, vecTemp);
+ delete [] vecTemp;
+ break;
+ case vffkey_bands:
+ bands = strtol(header, (char**)&rest, 10);
+ if ((rest == header) || (bands != 1))
+ {
+ RMInit::logOut << method_convFrom << ": bad number of bands " << bands << endl;
+ rest = NULL;
+ }
+ break;
+ case vffkey_bits:
+ bits = strtol(header, (char**)&rest, 10);
+ if ((rest == header) || ((bits != 8) && (bits != 16) && (bits != 32)))
+ {
+ RMInit::logOut << method_convFrom << ": bad number of bits " << bits << endl;
+ rest = NULL;
+ }
+ break;
+ case vffkey_value:
+ // FIXME: values ignored
+ rest = read_vector(2, header, vecValue);
+ break;
+ case vffkey_endian:
+ rest = read_string(header, endian);
+ break;
+ case vffkey_dorder:
+ rest = read_string(header, dataOrder);
+ break;
+ default:
+ break;
+ }
+ if (rest == NULL)
+ break;
+
+ header = rest;
+ skip_white(header);
+ if (*header == ';')
+ header++;
+ }
+ }
+ skip_white(header);
+ }
+ while (*header != endOfHeader);
+
+ // was there a data order? no ==> init either used-defined or default
+ if (dataOrder[0] == '\0')
+ {
+ if (dorderParam != NULL)
+ strcpy(dataOrder, dorderParam);
+ else
+ strcpy(dataOrder, get_default_order(dim));
+ }
+
+ //cout << "RANK " << dim << ", BANDS " << bands << ", BITS " << bits << endl;
+
+ // check whether all mandatory keywords are present
+ for (i=0; i<(unsigned int)vffkey_value; i++)
+ {
+ if (keysRead[i] == 0)
+ {
+ header = NULL;
+ break;
+ }
+ }
+
+ if ((header == NULL) || (*header != endOfHeader))
+ {
+ // parse error
+ RMInit::logOut << method_convFrom << ": PARSE ERROR" << endl;
+
+ delete [] keysRead;
+
+ if (vecSize != NULL)
+ delete [] vecSize;
+ if (vecOrigin != NULL)
+ delete [] vecOrigin;
+ if (vecValue != NULL)
+ delete [] vecValue;
+
+ r_Error err(r_Error::r_Error_General);
+ throw(err);
+ }
+
+ // after this instruction, header points to the linefeed
+ header++;
+ // after this instruction, header points to the data
+ header++;
+
+ desc.destInterv = r_Minterval(dim);
+
+ // order of dimensions in vectors
+ unsigned int *dimOrder = get_dimension_order(dim);
+
+ // the order of the dimensions is the same, only the linearization differs
+ for (i=0; i<dim; i++)
+ {
+ // the old method didn't work for high<0 (wrong rounding direction)
+ r_Range low, width;
+ low = (r_Range)(vecOrigin[i]);
+ width = (r_Range)(vecSize[i]);
+ //cout << "SIZE " << dimOrder[i] << ": " << width << ", ORG " << low << endl;
+ desc.destInterv[dimOrder[i]] = r_Sinterval(low, low+width-1);
+ }
+ //cout << desc.destInterv << endl;
+
+ delete [] vecOrigin;
+ delete [] vecSize;
+
+ int typeSize = (bits>>3);
+ unsigned long dataSize = desc.destInterv.cell_count() * typeSize;
+ //cout << "Type size " << typeSize << ", dim " << dim << endl;
+
+ if ((desc.dest = (char*)mystore.storage_alloc(dataSize)) == NULL)
+ {
+ delete [] keysRead;
+
+ if (vecValue != NULL)
+ delete [] vecValue;
+
+ r_Error err(r_Error::r_Error_General);
+ throw(err);
+ }
+
+ // treat all dimensions alike
+
+ // must copy byte-by-byte because the source data may not be aligned!
+ r_MiterDirect iter(desc.dest, desc.destInterv, desc.destInterv, typeSize, 1);
+ unsigned int *order, *steps;
+ const unsigned char *sptr = (const unsigned char *)header;
+
+ order = new unsigned int[dim];
+ steps = new unsigned int[dim];
+
+ for (i=0; i<dim; i++)
+ steps[i] = 1;
+
+ parse_data_order(dim, dataOrder, order);
+
+ switch (typeSize)
+ {
+ case 1:
+ while (iter.isDone() == 0)
+ {
+ *((r_Char*)iter.getData(order)) = *sptr;
+ iter.iterateUserOrder(order, steps);
+ sptr++;
+ }
+ break;
+ case 2:
+ while (iter.isDone() == 0)
+ {
+ unsigned char *dptr = (unsigned char*)iter.getData(order);
+ dptr[0] = sptr[0];
+ dptr[1] = sptr[1];
+ //cout << iter << ':' << (long)((char*)dptr - desc.dest) << ':' << (long)((char*)sptr - header) << ':' << (unsigned short)((sptr[0] << 8) | sptr[1]) << ' ';
+ iter.iterateUserOrder(order, steps);
+ sptr+=2;
+ }
+ break;
+ case 4:
+ while (iter.isDone() == 0)
+ {
+ unsigned char *dptr = (unsigned char*)iter.getData(order);
+ dptr[0] = sptr[0];
+ dptr[1] = sptr[1];
+ dptr[2] = sptr[2];
+ dptr[3] = sptr[3];
+ iter.iterateUserOrder(order, steps);
+ sptr+=4;
+ }
+ break;
+ default:
+ break;
+ }
+
+ delete [] order;
+ delete [] steps;
+ delete [] dimOrder;
+
+ switch (typeSize)
+ {
+ case 1:
+ desc.destType = get_external_type(ctype_char);
+ break;
+ case 2:
+ desc.destType = get_external_type(ctype_uint16);
+ if (strcmp(endian, get_endian_id()) != 0)
+ r_Endian::swap_array(dataSize, (const r_UShort*)desc.dest, (r_UShort*)desc.dest);
+ break;
+ case 4:
+ desc.destType = get_external_type(ctype_uint32);
+ if (strcmp(endian, get_endian_id()) != 0)
+ r_Endian::swap_array(dataSize, (const r_ULong*)desc.dest, (r_ULong*)desc.dest);
+ break;
+ default:
+ break;
+ }
+
+ //desc.destType->print_status();
+
+ if (vecValue != NULL)
+ delete [] vecValue;
+
+ delete [] keysRead;
+
+ return desc;
+}
+
+
+const char *r_Conv_VFF::get_name( void ) const
+{
+ return format_name_vff;
+}
+
+
+r_Data_Format r_Conv_VFF::get_data_format( void ) const
+{
+ return r_VFF;
+}
+
+
+r_Convertor *r_Conv_VFF::clone( void ) const
+{
+ return new r_Conv_VFF(desc.src, desc.srcInterv, desc.baseType);
+}
diff --git a/conversion/vff.hh b/conversion/vff.hh
new file mode 100644
index 0000000..f1829b5
--- /dev/null
+++ b/conversion/vff.hh
@@ -0,0 +1,138 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * FILE: vff.hh
+ *
+ * MODULE: conversion
+ *
+ * CLASSES: r_Conv_VFF
+ *
+ * COMMENTS:
+ *
+ * Provides interface to convert data to VFF and back.
+ *
+*/
+
+#ifndef _R_CONV_VFF_HH_
+#define _R_CONV_VFF_HH_
+
+#include "conversion/convertor.hh"
+
+
+
+//@ManMemo: Module {\bf conversion}
+
+/*@Doc:
+ VFF convertor class.
+
+ Supported parameters are
+
+ \begin{tabular}{rcl}
+ dorder && string && data order to read/write in 3D mode; permutations of "xyz"\\
+ dimorder && string && dimension order for vectors (size, origin, ...)\\
+ vffendian && int && default endianness, 0 for big endian, 1 for little\\
+ \end{tabular}
+
+*/
+
+class r_Conv_VFF : public r_Convertor
+{
+ public:
+ /// constructor using an r_Type object
+ r_Conv_VFF( const char *src, const r_Minterval &interv, const r_Type *tp ) throw(r_Error);
+ /// constructor using a convert_type_e shortcut
+ r_Conv_VFF( const char *src, const r_Minterval &interv, int tp ) throw(r_Error);
+ /// destructor
+ ~r_Conv_VFF( void );
+
+ /// convert to VFF
+ virtual r_convDesc &convertTo( const char *options=NULL ) throw(r_Error);
+ /// convert from VFF
+ virtual r_convDesc &convertFrom( const char *options=NULL ) throw(r_Error);
+ /// cloning
+ virtual r_Convertor *clone( void ) const;
+ /// identification
+ virtual const char *get_name( void ) const;
+ virtual r_Data_Format get_data_format( void ) const;
+
+
+ private:
+ /// shared init code
+ void initVFF( void );
+ /// skip whitespace when parsing the header
+ static void skip_white( const char *&str );
+ /// read a floating point vector from the header and return pointer to rest
+ static const char *read_vector( r_Dimension dim, const char *str, double *&vec );
+ /// read a string from the header and return pointer to rest
+ static const char *read_string( const char *str, char *dest, bool allowSpace=0 );
+ /// write an interval to a stream
+ static void write_interval( const char *keyname, std::ostream &str, const r_Minterval &iv,
+ const unsigned int *order, r_Range inc=0 );
+ /// write an origin to a stream
+ static void write_origin( const char *keyname, std::ostream &str, const r_Minterval &iv,
+ const unsigned int *order );
+ /// get the VFF-endian id for the host machine's
+ static const char *get_endian_id( void );
+ /// parse data order string, revert to default if failed
+ static int parse_data_order( r_Dimension dim, const char *dstr, unsigned int *order );
+ /// get default data order for a dimensionality
+ static const char *get_default_order( r_Dimension dim );
+ /// get default dimension order for a dimensionality
+ static const char *get_default_dim_order( r_Dimension dim );
+
+ /// get dimension order in newly allocated array
+ unsigned int *get_dimension_order( r_Dimension dim ) const;
+ /// get the default endianness
+ const char *get_default_endianness( void ) const;
+
+ /// data order parameter
+ char *dorderParam;
+ /// dimension order parameter
+ char *dimOrderParam;
+ /// default endianness parameter
+ int dfltEndianness;
+
+ /// identifier (ncaa) in header
+ static const char *fileMagic;
+ /// keyword names
+ static const char *keywords[];
+ /// special key values
+ static const char *kval_Raster;
+ static const char *kval_Slice;
+ static const char *kval_LEndian;
+ static const char *kval_BEndian;
+ /// default data order for 2D/3D
+ static const char *dfltDataOrder2;
+ static const char *dfltDataOrder3;
+ /// default dimension order fo 2D/3D
+ static const char *dfltDimOrder2;
+ static const char *dfltDimOrder3;
+ /// end-of-header marker
+ static const char endOfHeader;
+ /// name of convertTo() method
+ static const char *method_convTo;
+ /// name of convertFrom() method
+ static const char *method_convFrom;
+};
+
+#endif
diff --git a/debug/README b/debug/README
new file mode 100644
index 0000000..7a776d1
--- /dev/null
+++ b/debug/README
@@ -0,0 +1,11 @@
+This directory contains an include file which helps to generate formatted trace output.
+See this file for usage directions.
+No executable is generated here.
+Has been taken from rasmgr; Makefiles still have to be reworked before removing it there.
+Tests to be done.
+ -- PB 2003-aug-19
+
+have 2 versions now, one for server and one for client side.
+functionality identical except that srv version uses RMInit::logOut to have the same output location (i.e., file).
+ -- PB 2003-nov-24
+
diff --git a/debug/debug-clt.hh b/debug/debug-clt.hh
new file mode 100644
index 0000000..4a37565
--- /dev/null
+++ b/debug/debug-clt.hh
@@ -0,0 +1,35 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: debug-clt.hh
+ *
+ * MODULE: rasmgr/test (prelim)
+ *
+ * COMMENTS:
+ * - uses cout for output; except for that. identical to debug-srv.hh
+ *
+*/
+
+#define OSTREAM cout
+#include "debug.hh"
+
diff --git a/debug/debug-srv.hh b/debug/debug-srv.hh
new file mode 100644
index 0000000..2660355
--- /dev/null
+++ b/debug/debug-srv.hh
@@ -0,0 +1,35 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: debug-srv.hh
+ *
+ * MODULE: rasmgr/test (prelim)
+ *
+ * COMMENTS:
+ * - uses RMInit::logOut, otherwise identical to debug-clt.hh
+ *
+*/
+
+#define OSTREAM RMInit::logOut
+#include "debug.hh"
+
diff --git a/debug/debug.hh b/debug/debug.hh
new file mode 100644
index 0000000..d9fb8b2
--- /dev/null
+++ b/debug/debug.hh
@@ -0,0 +1,129 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: debug.hh
+ *
+ * MODULE: rasmgr/test (prelim)
+ *
+ * COMMENTS:
+ * - needs RMInit
+*/
+
+#ifndef DEBUG_HH
+#define DEBUG_HH
+
+/* activated through
+#define DEBUG
+in the target code; needs one main! */
+
+#include <iostream>
+
+#ifdef DEBUG
+// enable trace macros
+
+// allow output stream 'cout' to be overridden
+#ifndef OSTREAM
+ #define OSTREAM std::cout
+#endif // OSTREAM
+
+#define INDENT ". "
+
+// no output by default
+#define DEBUG_OUTPUT_DEFAULT false
+
+/// for C++, we declare refs as "C" to exclude them from name mangling;
+/// for C it's like always
+/// --- well nice, but doesn't work for now, so we set it back
+#ifdef __cplusplus
+# define EXTERN extern // "C"
+#else
+# define EXTERN extern
+#endif
+
+/// variables are allocated in the main module (i.e., the source where main() resides),
+/// and referened from all other places
+#ifdef DEBUG_MAIN
+ int indentLevel = 0;
+ bool debugOutput = DEBUG_OUTPUT_DEFAULT;
+#else
+ EXTERN int indentLevel;
+ EXTERN bool debugOutput;
+#endif // DEBUG_MAIN
+
+/// enable/disable debug output from program
+/// b == true: switch on output
+/// b == false: switch off output
+#define SET_OUTPUT(b) { debugOutput = b; }
+
+/// ENTER(a): write trace line for entering a function (increases indentation)
+#define ENTER(a) \
+ { \
+ if (debugOutput) \
+ { \
+ for (int i = 0; i < indentLevel; i++) \
+ OSTREAM << INDENT; \
+ OSTREAM << "ENTER " << a << std::endl << std::flush; \
+ indentLevel++; \
+ } \
+ }
+
+/// LEAVE(a): write trace line for leaving a function (decreases indentation)
+#define LEAVE(a) \
+ { \
+ if (debugOutput) \
+ { \
+ if (indentLevel > 0 ) \
+ indentLevel--; \
+ for (int i = 0; i < indentLevel; i++) \
+ OSTREAM << INDENT; \
+ OSTREAM << "LEAVE " << a << std::endl << std::flush; \
+ } \
+ }
+
+
+/// TALK(a): write trace line from within a function (leaves indentation unchanged)
+#define TALK(a) \
+ { \
+ if (debugOutput) \
+ { \
+ for (int i = 0; i < indentLevel; i++) \
+ OSTREAM << INDENT; \
+ OSTREAM << a << std::endl << std::flush; \
+ } \
+ }
+
+#else
+// disable all trace macros
+#undef SET_OUTPUT
+#undef ENTER
+#undef LEAVE
+#undef TALK
+
+#define SET_OUTPUT(b) { /* SET_OUTPUT(b) */ }
+#define ENTER(a) { /* ENTER(a) */ }
+#define LEAVE(a) { /* LEAVE(a) */ }
+#define TALK(a) { /* TALK(a) */ }
+
+#endif // DEBUG
+
+#endif // DEBUG_HH
diff --git a/depcomp b/depcomp
new file mode 100644
index 0000000..e5f9736
--- /dev/null
+++ b/depcomp
@@ -0,0 +1,589 @@
+#! /bin/sh
+# depcomp - compile a program generating dependencies as side-effects
+
+scriptversion=2007-03-29.01
+
+# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007 Free Software
+# Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
+
+case $1 in
+ '')
+ echo "$0: No command. Try \`$0 --help' for more information." 1>&2
+ exit 1;
+ ;;
+ -h | --h*)
+ cat <<\EOF
+Usage: depcomp [--help] [--version] PROGRAM [ARGS]
+
+Run PROGRAMS ARGS to compile a file, generating dependencies
+as side-effects.
+
+Environment variables:
+ depmode Dependency tracking mode.
+ source Source file read by `PROGRAMS ARGS'.
+ object Object file output by `PROGRAMS ARGS'.
+ DEPDIR directory where to store dependencies.
+ depfile Dependency file to output.
+ tmpdepfile Temporary file to use when outputing dependencies.
+ libtool Whether libtool is used (yes/no).
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+ exit $?
+ ;;
+ -v | --v*)
+ echo "depcomp $scriptversion"
+ exit $?
+ ;;
+esac
+
+if test -z "$depmode" || test -z "$source" || test -z "$object"; then
+ echo "depcomp: Variables source, object and depmode must be set" 1>&2
+ exit 1
+fi
+
+# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
+depfile=${depfile-`echo "$object" |
+ sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
+tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
+
+rm -f "$tmpdepfile"
+
+# Some modes work just like other modes, but use different flags. We
+# parameterize here, but still list the modes in the big case below,
+# to make depend.m4 easier to write. Note that we *cannot* use a case
+# here, because this file can only contain one case statement.
+if test "$depmode" = hp; then
+ # HP compiler uses -M and no extra arg.
+ gccflag=-M
+ depmode=gcc
+fi
+
+if test "$depmode" = dashXmstdout; then
+ # This is just like dashmstdout with a different argument.
+ dashmflag=-xM
+ depmode=dashmstdout
+fi
+
+case "$depmode" in
+gcc3)
+## gcc 3 implements dependency tracking that does exactly what
+## we want. Yay! Note: for some reason libtool 1.4 doesn't like
+## it if -MD -MP comes after the -MF stuff. Hmm.
+## Unfortunately, FreeBSD c89 acceptance of flags depends upon
+## the command line argument order; so add the flags where they
+## appear in depend2.am. Note that the slowdown incurred here
+## affects only configure: in makefiles, %FASTDEP% shortcuts this.
+ for arg
+ do
+ case $arg in
+ -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
+ *) set fnord "$@" "$arg" ;;
+ esac
+ shift # fnord
+ shift # $arg
+ done
+ "$@"
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ mv "$tmpdepfile" "$depfile"
+ ;;
+
+gcc)
+## There are various ways to get dependency output from gcc. Here's
+## why we pick this rather obscure method:
+## - Don't want to use -MD because we'd like the dependencies to end
+## up in a subdir. Having to rename by hand is ugly.
+## (We might end up doing this anyway to support other compilers.)
+## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
+## -MM, not -M (despite what the docs say).
+## - Using -M directly means running the compiler twice (even worse
+## than renaming).
+ if test -z "$gccflag"; then
+ gccflag=-MD,
+ fi
+ "$@" -Wp,"$gccflag$tmpdepfile"
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
+## The second -e expression handles DOS-style file names with drive letters.
+ sed -e 's/^[^:]*: / /' \
+ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
+## This next piece of magic avoids the `deleted header file' problem.
+## The problem is that when a header file which appears in a .P file
+## is deleted, the dependency causes make to die (because there is
+## typically no way to rebuild the header). We avoid this by adding
+## dummy dependencies for each header file. Too bad gcc doesn't do
+## this for us directly.
+ tr ' ' '
+' < "$tmpdepfile" |
+## Some versions of gcc put a space before the `:'. On the theory
+## that the space means something, we add a space to the output as
+## well.
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+hp)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+sgi)
+ if test "$libtool" = yes; then
+ "$@" "-Wp,-MDupdate,$tmpdepfile"
+ else
+ "$@" -MDupdate "$tmpdepfile"
+ fi
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+
+ if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
+ echo "$object : \\" > "$depfile"
+
+ # Clip off the initial element (the dependent). Don't try to be
+ # clever and replace this with sed code, as IRIX sed won't handle
+ # lines with more than a fixed number of characters (4096 in
+ # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
+ # the IRIX cc adds comments like `#:fec' to the end of the
+ # dependency line.
+ tr ' ' '
+' < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
+ tr '
+' ' ' >> $depfile
+ echo >> $depfile
+
+ # The second pass generates a dummy entry for each header file.
+ tr ' ' '
+' < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
+ >> $depfile
+ else
+ # The sourcefile does not contain any dependencies, so just
+ # store a dummy comment line, to avoid errors with the Makefile
+ # "include basename.Plo" scheme.
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+aix)
+ # The C for AIX Compiler uses -M and outputs the dependencies
+ # in a .u file. In older versions, this file always lives in the
+ # current directory. Also, the AIX compiler puts `$object:' at the
+ # start of each line; $object doesn't have directory information.
+ # Version 6 uses the directory in both cases.
+ dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+ test "x$dir" = "x$object" && dir=
+ base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
+ if test "$libtool" = yes; then
+ tmpdepfile1=$dir$base.u
+ tmpdepfile2=$base.u
+ tmpdepfile3=$dir.libs/$base.u
+ "$@" -Wc,-M
+ else
+ tmpdepfile1=$dir$base.u
+ tmpdepfile2=$dir$base.u
+ tmpdepfile3=$dir$base.u
+ "$@" -M
+ fi
+ stat=$?
+
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+ exit $stat
+ fi
+
+ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+ do
+ test -f "$tmpdepfile" && break
+ done
+ if test -f "$tmpdepfile"; then
+ # Each line is of the form `foo.o: dependent.h'.
+ # Do two passes, one to just change these to
+ # `$object: dependent.h' and one to simply `dependent.h:'.
+ sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
+ # That's a tab and a space in the [].
+ sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
+ else
+ # The sourcefile does not contain any dependencies, so just
+ # store a dummy comment line, to avoid errors with the Makefile
+ # "include basename.Plo" scheme.
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+icc)
+ # Intel's C compiler understands `-MD -MF file'. However on
+ # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c
+ # ICC 7.0 will fill foo.d with something like
+ # foo.o: sub/foo.c
+ # foo.o: sub/foo.h
+ # which is wrong. We want:
+ # sub/foo.o: sub/foo.c
+ # sub/foo.o: sub/foo.h
+ # sub/foo.c:
+ # sub/foo.h:
+ # ICC 7.1 will output
+ # foo.o: sub/foo.c sub/foo.h
+ # and will wrap long lines using \ :
+ # foo.o: sub/foo.c ... \
+ # sub/foo.h ... \
+ # ...
+
+ "$@" -MD -MF "$tmpdepfile"
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ # Each line is of the form `foo.o: dependent.h',
+ # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
+ # Do two passes, one to just change these to
+ # `$object: dependent.h' and one to simply `dependent.h:'.
+ sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
+ # Some versions of the HPUX 10.20 sed can't process this invocation
+ # correctly. Breaking it into two sed invocations is a workaround.
+ sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" |
+ sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+hp2)
+ # The "hp" stanza above does not work with aCC (C++) and HP's ia64
+ # compilers, which have integrated preprocessors. The correct option
+ # to use with these is +Maked; it writes dependencies to a file named
+ # 'foo.d', which lands next to the object file, wherever that
+ # happens to be.
+ # Much of this is similar to the tru64 case; see comments there.
+ dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+ test "x$dir" = "x$object" && dir=
+ base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
+ if test "$libtool" = yes; then
+ tmpdepfile1=$dir$base.d
+ tmpdepfile2=$dir.libs/$base.d
+ "$@" -Wc,+Maked
+ else
+ tmpdepfile1=$dir$base.d
+ tmpdepfile2=$dir$base.d
+ "$@" +Maked
+ fi
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile1" "$tmpdepfile2"
+ exit $stat
+ fi
+
+ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
+ do
+ test -f "$tmpdepfile" && break
+ done
+ if test -f "$tmpdepfile"; then
+ sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile"
+ # Add `dependent.h:' lines.
+ sed -ne '2,${; s/^ *//; s/ \\*$//; s/$/:/; p;}' "$tmpdepfile" >> "$depfile"
+ else
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile" "$tmpdepfile2"
+ ;;
+
+tru64)
+ # The Tru64 compiler uses -MD to generate dependencies as a side
+ # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'.
+ # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
+ # dependencies in `foo.d' instead, so we check for that too.
+ # Subdirectories are respected.
+ dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+ test "x$dir" = "x$object" && dir=
+ base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
+
+ if test "$libtool" = yes; then
+ # With Tru64 cc, shared objects can also be used to make a
+ # static library. This mechanism is used in libtool 1.4 series to
+ # handle both shared and static libraries in a single compilation.
+ # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d.
+ #
+ # With libtool 1.5 this exception was removed, and libtool now
+ # generates 2 separate objects for the 2 libraries. These two
+ # compilations output dependencies in $dir.libs/$base.o.d and
+ # in $dir$base.o.d. We have to check for both files, because
+ # one of the two compilations can be disabled. We should prefer
+ # $dir$base.o.d over $dir.libs/$base.o.d because the latter is
+ # automatically cleaned when .libs/ is deleted, while ignoring
+ # the former would cause a distcleancheck panic.
+ tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4
+ tmpdepfile2=$dir$base.o.d # libtool 1.5
+ tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5
+ tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504
+ "$@" -Wc,-MD
+ else
+ tmpdepfile1=$dir$base.o.d
+ tmpdepfile2=$dir$base.d
+ tmpdepfile3=$dir$base.d
+ tmpdepfile4=$dir$base.d
+ "$@" -MD
+ fi
+
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
+ exit $stat
+ fi
+
+ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
+ do
+ test -f "$tmpdepfile" && break
+ done
+ if test -f "$tmpdepfile"; then
+ sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
+ # That's a tab and a space in the [].
+ sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
+ else
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+#nosideeffect)
+ # This comment above is used by automake to tell side-effect
+ # dependency tracking mechanisms from slower ones.
+
+dashmstdout)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout, regardless of -o.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test $1 != '--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ # Remove `-o $object'.
+ IFS=" "
+ for arg
+ do
+ case $arg in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift # fnord
+ shift # $arg
+ ;;
+ esac
+ done
+
+ test -z "$dashmflag" && dashmflag=-M
+ # Require at least two characters before searching for `:'
+ # in the target name. This is to cope with DOS-style filenames:
+ # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise.
+ "$@" $dashmflag |
+ sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile"
+ rm -f "$depfile"
+ cat < "$tmpdepfile" > "$depfile"
+ tr ' ' '
+' < "$tmpdepfile" | \
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+dashXmstdout)
+ # This case only exists to satisfy depend.m4. It is never actually
+ # run, as this mode is specially recognized in the preamble.
+ exit 1
+ ;;
+
+makedepend)
+ "$@" || exit $?
+ # Remove any Libtool call
+ if test "$libtool" = yes; then
+ while test $1 != '--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+ # X makedepend
+ shift
+ cleared=no
+ for arg in "$@"; do
+ case $cleared in
+ no)
+ set ""; shift
+ cleared=yes ;;
+ esac
+ case "$arg" in
+ -D*|-I*)
+ set fnord "$@" "$arg"; shift ;;
+ # Strip any option that makedepend may not understand. Remove
+ # the object too, otherwise makedepend will parse it as a source file.
+ -*|$object)
+ ;;
+ *)
+ set fnord "$@" "$arg"; shift ;;
+ esac
+ done
+ obj_suffix="`echo $object | sed 's/^.*\././'`"
+ touch "$tmpdepfile"
+ ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
+ rm -f "$depfile"
+ cat < "$tmpdepfile" > "$depfile"
+ sed '1,2d' "$tmpdepfile" | tr ' ' '
+' | \
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile" "$tmpdepfile".bak
+ ;;
+
+cpp)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test $1 != '--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ # Remove `-o $object'.
+ IFS=" "
+ for arg
+ do
+ case $arg in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift # fnord
+ shift # $arg
+ ;;
+ esac
+ done
+
+ "$@" -E |
+ sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
+ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' |
+ sed '$ s: \\$::' > "$tmpdepfile"
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ cat < "$tmpdepfile" >> "$depfile"
+ sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+msvisualcpp)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout, regardless of -o,
+ # because we must use -o when running libtool.
+ "$@" || exit $?
+ IFS=" "
+ for arg
+ do
+ case "$arg" in
+ "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
+ set fnord "$@"
+ shift
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift
+ shift
+ ;;
+ esac
+ done
+ "$@" -E |
+ sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile"
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile"
+ echo " " >> "$depfile"
+ . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+none)
+ exec "$@"
+ ;;
+
+*)
+ echo "Unknown depmode $depmode" 1>&2
+ exit 1
+ ;;
+esac
+
+exit 0
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
diff --git a/empty b/empty
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/empty
diff --git a/httpserver/Makefile.am b/httpserver/Makefile.am
new file mode 100644
index 0000000..94d883b
--- /dev/null
+++ b/httpserver/Makefile.am
@@ -0,0 +1,33 @@
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+#
+# MAKEFILE FOR:
+# Rasdaman http server
+#
+##################################################################
+
+noinst_LIBRARIES=libhttpserver.a
+AM_CFLAGS=$(CXXFLAGS)
+libhttpserver_a_SOURCES= types.h http.h server.h defs.h http-defs.h protos.h \
+ logging.cc signals.cc config.cc support.cc childs.cc init.cc \
+ http-support.cc http-methods.cc http-fields.cc http-date.cc \
+ http-error.cc http-readmsg.cc http-writemsg.cc \
+ http-doit.cc http.cc httpserver.h main.cc
diff --git a/httpserver/childs.cc b/httpserver/childs.cc
new file mode 100644
index 0000000..66729f1
--- /dev/null
+++ b/httpserver/childs.cc
@@ -0,0 +1,246 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#include "mymalloc/mymalloc.h"
+/*------------------------------------------------------------------------*/
+/* childs.c - child process handling. */
+/* */
+/*------------------------------------------------------------------------*/
+/* Comments: */
+/* - intended purpose: */
+/* Keep all functions related to child processes in one place. */
+/* - Status: */
+/* - Functions to Create and Initialize a child is thrown in. */
+/* - Should think over the actual design - looks somewhat */
+/* messy now. It should be something more clean and of */
+/* generic use, so it can be reused in future projects. */
+/* - Nevertheless -- it works, and there should be no creeping */
+/* surprises in the code... [FLW Alert... ;-)] */
+/*------------------------------------------------------------------------*/
+/*
+ * RCS:
+ * $RCSfile: childs.c,v $ $Revision: 1.6 $ $State: Exp $
+ * $Locker: $
+ */
+
+
+#include "defs.h"
+#include "protos.h"
+#include "types.h"
+#include "server.h"
+#include "http-defs.h"
+#include "http.h"
+
+extern struct ServerBase Server;
+
+
+/****** childs/InitChild *****************************************************
+*
+* NAME
+* InitChild -- data initializition after forking the child process.
+*
+* SYNOPSIS
+* int InitChild( struct ClientBase *Client );
+*
+* FUNCTION
+*
+* RESULT
+*
+* NOTES
+*
+* BUGS
+*
+* SEE ALSO
+*
+******************************************************************************
+*
+*/
+
+rc_t InitChild( struct ClientBase *Client )
+{
+ char *UnknownIP = "0.0.0.0";
+
+ /* Init ClientBase */
+ strcpy( Client->Host.IPAddrString, inet_ntoa( Client->Socket.sin_addr ) );
+ if( Client->Host.IPAddrString == NULL )
+ strcpy( Client->Host.IPAddrString, UnknownIP );
+ Client->Host.IPAddress = inet_addr( Client->Host.IPAddrString );
+
+ Client->Comm.ConnStatus = CONN_UNDEFINED;
+ InitHTTPMsg( &Client->Response );
+ InitReqInfo( &Client->Request );
+
+ return( OK );
+}
+
+
+
+/****** childs/NewChild ******************************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+* ### Temporary fork() wrapper.
+* Will be later expanded into something more usefull...
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+pid_t NewChild( struct ChildBase *List, struct FDsets *PDSets, struct ClientBase *Client )
+{
+ struct ChildBase *Child;
+
+ Child = (struct ChildBase*)mymalloc( sizeof( struct ChildBase ) );
+ if( Child == NULL ) // Failure? => QUIT.
+ ErrorMsg( E_SYS, FAIL, "FAIL: NewChild(): malloc() failed!" );
+
+ // Open pipe
+ if( pipe( Child->PD ) < 0 )
+ {
+ ErrorMsg( E_SYS, ERROR, "ERROR: NewChild(): pipe() failed." );
+ Child->PipeStatus = PIPE_CLOSED;
+ }
+ else
+ {
+ Child->PipeStatus = PIPE_OPEN;
+ }
+
+ Child->PId = fork();
+
+ if( Child->PId < 0 ) // fork() Error? => QUIT.
+ ErrorMsg( E_SYS, FAIL, "FAIL: NewChild(): fork() failed!" );
+
+ if( Child->PId > 0 ) // parent process?
+ {
+ // Add Pipe-Descriptors to PipeSets
+ if( Child->PipeStatus == PIPE_OPEN )
+ {
+ FD_SET( Child->PD[0], &PDSets->Read );
+ if( Child->PD[0] > PDSets->MaxFD )
+ PDSets->MaxFD = Child->PD[0];
+ close( Child->PD[1] );
+ }
+ // Add Child to List
+ AddChild( List, Child );
+ }
+ else // child process
+ {
+ InitChild( Client );
+ // Remember PD to parent
+ Client->Pipe = Child->PD[1];
+ close( Child->PD[0] );
+ free( Child );
+ }
+
+ return( Child->PId );
+}
+
+
+void CleanupChild( struct ChildBase *List, struct FDsets *PDSets, pid_t PId )
+{
+ struct ChildBase *Ptr;
+ struct ChildBase *Tmp;
+
+ LogMsg( LG_SERVER, DEBUG, "DEBUG: Begin CleanupChild ..." );
+
+ if(PDSets == NULL)
+ LogMsg( LG_SERVER, DEBUG, "DEBUG: ########### PDSets is NULL!" );
+ if(PId == (pid_t)0)
+ LogMsg( LG_SERVER, DEBUG, "DEBUG: ########### ChildPid is NULL!" );
+ if(List == NULL)
+ LogMsg( LG_SERVER, DEBUG, "DEBUG: ########### ChildBase is NULL!" );
+
+ if( List->PId > 0 )
+ {
+ for( Ptr = List; Ptr->next != List; Ptr = Ptr->next )
+ {
+ if( Ptr->next->PId == PId )
+ {
+ Tmp = Ptr->next;
+ break;
+ }
+ }
+ // Close pipe
+ close( Tmp->PD[0] );
+ // Remove Pipe-Descriptors from PipeSets
+ FD_CLR( Tmp->PD[0], &PDSets->Read );
+ RemChild( List, Tmp );
+ }
+}
+
+
+void AddChild( struct ChildBase *List, struct ChildBase *Child )
+{
+ Child->next = List->next;
+ Child->prev = List;
+ List->next->prev = Child;
+ List->next = Child;
+ List->PId++;
+}
+
+
+void RemChild( struct ChildBase *List, struct ChildBase *Child )
+{
+ Child->prev->next = Child->next;
+ Child->next->prev = Child->prev;
+ List->PId--;
+ free( Child );
+}
+
+
+struct ChildBase *GetChild( struct ChildBase *List, pid_t PId )
+{
+ struct ChildBase *Ptr;
+
+ if( List->PId > 0 )
+ {
+ for( Ptr = List; Ptr->next != List; Ptr = Ptr->next )
+ {
+ if( Ptr->next->PId == PId )
+ return( Ptr->next );
+ }
+ return( NULL );
+ }
+ else
+ return( NULL );
+}
diff --git a/httpserver/config.cc b/httpserver/config.cc
new file mode 100644
index 0000000..d4c235b
--- /dev/null
+++ b/httpserver/config.cc
@@ -0,0 +1,465 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include "mymalloc/mymalloc.h"
+/*------------------------------------------------------------------------*/
+/* config.c - configuration and setup stuff. */
+/*------------------------------------------------------------------------*/
+/* Comments: */
+/* - intended purpose: */
+/* Contains all code related to setup the configuration. */
+/* - Status: */
+/* - There were more features planned than are now available. */
+/* - Especially some arguments are disabled or non-functional, */
+/* so: onle use "-c <config-filepath>", and don't care about */
+/* the rest! */
+/* - The Flag Handling of Verbose/Debug-Mode is somewhat broken */
+/* - ReadConfig() uses static buffers. But they are protected */
+/* against overwriting. */
+/* - ReadConfig() contains some printf()'s. */
+/* - Handling of Sub-Server configuration still disabled. */
+/* - The rest should be okay. */
+/*------------------------------------------------------------------------*/
+
+#include <iostream>
+using namespace std;
+
+#include "defs.h"
+#include "protos.h"
+#include "server.h"
+#include <unistd.h> // for gethostname()
+
+#ifdef SOLARIS
+ // function prototype with C linkage
+ extern "C" int gethostname(char *name, int namelen);
+#endif
+
+extern int globalHTTPPort;
+
+/****** config/ReadArgs ******************************************************
+*
+* NAME
+* ReadArgs --
+*
+* SYNOPSIS
+* int ReadArgs( int argc, char *argv[] );
+*
+* FUNCTION
+*
+* RESULT
+*
+* NOTES
+*
+* BUGS
+*
+* SEE ALSO
+*
+******************************************************************************
+*
+*/
+
+rc_t ReadArgs( struct ServerBase *Server, int argc, char *argv[] )
+{
+ int i;
+ int LogMode = LM_VERBOSE;
+ char *Filename = NULL;
+
+ for( i = 1; i < argc; ++i)
+ {
+ if( argv[i][0] != '-' )
+ {
+ break;
+ }
+ switch( argv[i][1] )
+ {
+ case 'D': /* Debug-Flag setzen */
+ LogMode |= LF_STDERR;
+ break;
+ case 'V': /* Verbose-Flag setzen */
+ LogMode |= LF_VERB;
+ break;
+ case 'c': /* Config-File im naechsten Argument */
+ if( ++i >= argc ) /* Keine weiteren Argumente? */
+ {
+ printf( "Oops: Missing config filename after '-c' switch.\n" );
+ printf( "Please try again.\n" );
+ Exit( FAIL );
+ }
+ else
+ {
+ Filename = argv[i];
+ }
+ break;
+ case 'h':
+ printf( "Usage: %s [-c <ConfigFile>] [-V] [-D]\n", argv[0] );
+ Exit( WARN );
+ break;
+ case '?':
+ printf( "Usage: %s [-c <ConfigFile>] [-V] [-D]\n", argv[0] );
+ Exit( WARN );
+ break;
+ default: /* Kein bekanntes Argument */
+ printf( "Unknown option '%s'.\n", argv[i] );
+ Exit( FAIL );
+ break;
+ }
+ }
+
+ return( CheckAndSet( Server, Filename, LogMode ) );
+}
+
+
+/****** config/CheckAndSet ***************************************************
+*
+* NAME
+* CheckAndSet --
+*
+* SYNOPSIS
+* int CheckAndSet( char *Directory, char *Filename, int LogMode );
+*
+* FUNCTION
+*
+* RESULT
+*
+* NOTES
+*
+* BUGS
+*
+* SEE ALSO
+*
+******************************************************************************
+*
+*/
+
+rc_t CheckAndSet( struct ServerBase *Server, char *Filename, int LogMode )
+{
+ rc_t RC = 0;
+
+ /* we skipped the config file
+ char *Def_ConfFile = "httpserver.conf";
+
+ if( Filename == NULL )
+ {
+ LogMsg( LG_SERVER, WARN, "WARN: No config file given - using default %s.",
+ Def_ConfFile );
+ Filename = Def_ConfFile;
+ }
+
+ SetFilename( Server, FT_CONFFILE, Filename );
+ */
+ Server->Log.Mode = LogMode;
+
+ return( RC );
+}
+
+
+/****** config/SetServDir ****************************************************
+*
+* NAME
+* SetServDir --
+*
+* SYNOPSIS
+* int SetServDir( char *Dirname );
+*
+* FUNCTION
+*
+* RESULT
+*
+* NOTES
+*
+* BUGS
+*
+* SEE ALSO
+*
+******************************************************************************
+*
+*/
+
+rc_t SetServDir( struct ServerBase *Server, char *Dirname )
+{
+ char *Buffer;
+ size_t BuffSize;
+ size_t MaxPath;
+
+ if ( ( Buffer = PathAlloc( &BuffSize ) ) == NULL )
+ ErrorMsg( E_SYS, FAIL, "FAIL: Buffer allocation for pathname of server directory." );
+ Buffer[0] = '\0';
+
+ /* Platz lassen, um auch noch Filenamen + '\0' im Buffer */
+ /* unterbringen zu können. */
+
+ MaxPath = BuffSize - strlen( "httpserver.conf" );
+ if( strlen( Dirname ) >= MaxPath )
+ ErrorMsg( E_SYS, FAIL, "FAIL: Pathname of server directory too long." );
+ Buffer = strncpy( Buffer, Dirname, MaxPath );
+
+ if( Buffer[ strlen( Buffer ) - 1 ] != '/' )
+ Buffer = strcat( Buffer, "/" );
+
+ if(Server->Directory) free(Server->Directory);
+ Server->Directory = Buffer;
+ return( OK );
+}
+
+
+/****** config/SetFilename ***************************************************
+*
+* NAME
+* SetConfFile --
+*
+* SYNOPSIS
+* int SetConfFile( char *Filename );
+*
+* FUNCTION
+*
+* RESULT
+*
+* NOTES
+*
+* BUGS
+*
+* SEE ALSO
+*
+******************************************************************************
+*
+*/
+
+
+rc_t SetFilename( struct ServerBase *Server, int Type, char *Filename )
+{
+ char *Buffer = NULL;
+ size_t BuffSize = 0;
+ size_t PathLength, FileLength;
+
+ if( Filename != NULL )
+ {
+ if ( ( Buffer = PathAlloc( &BuffSize ) ) == NULL )
+ ErrorMsg( E_SYS, FAIL, "FAIL: Buffer allocation for filename \"%s\".", Filename );
+ Buffer[0] = '\0';
+
+ if( Server->Directory != NULL )
+ PathLength = strlen( Server->Directory );
+ FileLength = strlen( Filename );
+
+ if( FileLength >= BuffSize )
+ ErrorMsg( E_SYS, FAIL, "FAIL: Pathname of file \"%s\" too long.", Filename );
+
+ if( Filename[0] != '/' )
+ {
+ if( ( PathLength + FileLength ) >= BuffSize )
+ ErrorMsg( E_SYS, FAIL, "FAIL: Path/filename of file \"%s\" too long.", Filename );
+
+ Buffer = strncpy( Buffer, Server->Directory, BuffSize );
+ }
+ Buffer = strncat( Buffer, Filename, FileLength );
+ }
+
+ switch( Type )
+ {
+ case FT_CONFFILE:
+ Server->ConfigFile = Buffer;
+ break;
+ case FT_ACCESSLOG:
+ Server->Log.Access.Filename = Buffer;
+ break;
+ case FT_SERVERLOG:
+ Server->Log.Server.Filename = Buffer;
+ break;
+ case FT_COMMLOG:
+ Server->Log.Comm.Filename = Buffer;
+ break;
+ case FT_PIDFILE:
+ Server->PidFile = Buffer;
+ break;
+ default:
+ ErrorMsg( E_SYS, ERROR, "ERROR: Unknown filetype: %d.", Type );
+ return( ERROR );
+ break;
+ }
+ return( OK );
+}
+
+
+rc_t SetString( struct ServerBase *Server, int Type, char *String )
+{
+ char *Buffer = NULL;
+ size_t BuffSize = 0;
+
+ if( String != NULL )
+ {
+ BuffSize = strlen( String );
+ if ( ( Buffer = (char*)mymalloc( BuffSize+1 ) ) == NULL )
+ ErrorMsg( E_SYS, FAIL, "FAIL: Buffer allocation for string \"%s\".", String );
+ strcpy( Buffer, String );
+
+ switch( Type )
+ {
+ case ST_HOSTNAME:
+ Server->Host.Name = Buffer;
+ break;
+ case ST_MAILADDRESS:
+ Server->AdminMailAddress = Buffer;
+ break;
+ default:
+ ErrorMsg( E_SYS, ERROR, "ERROR: Unknown stringtype: %d.", Type );
+ return( ERROR );
+ break;
+ }
+ return( OK );
+ }
+ else
+ return( ERROR );
+}
+
+
+/****** config/ConfigureServer ***********************************************
+*
+* NAME
+* ConfigureServer --
+*
+* SYNOPSIS
+* int ConfigureServer( char *Keyword, char *Value1, char *Value2,
+* char *Value3 );
+*
+* FUNCTION
+*
+* RESULT
+*
+* NOTES
+*
+* BUGS
+*
+* SEE ALSO
+*
+******************************************************************************
+*
+*/
+
+rc_t ConfigureServer( struct ServerBase *Server )
+{
+ char* myName;
+ char* rmanhome = CONFDIR;
+ int MaxURLLength = 120;
+ int BuffSize;
+ char* Buffer;
+
+ BuffSize = strlen( rmanhome );
+
+ if ( ( Buffer = (char*)mymalloc( BuffSize+200 ) ) == NULL )
+ ErrorMsg( E_SYS, FAIL, "FAIL: Buffer allocation for Server Configuration" );
+ if( gethostname( Buffer, 200 ) )
+ ErrorMsg( E_SYS, FAIL, "FAIL: Could not determine my Hostname" );
+
+ myName=strdup(Buffer);
+
+ strcpy(Buffer,rmanhome);
+ SetFilename( Server, FT_COMMLOG, strcat(Buffer,"/httpcomm.log") );
+
+ Server->Port = globalHTTPPort;
+
+ SetString( Server, ST_MAILADDRESS, "admin@localhost" );
+
+ SetString( Server, ST_HOSTNAME, myName );
+
+ SetServDir( Server, rmanhome );
+
+ strcpy(Buffer,rmanhome);
+ SetFilename( Server, FT_ACCESSLOG, strcat(Buffer,"/httpaccess.log") );
+
+ Server->MaxURLLength = MaxURLLength;
+
+ strcpy(Buffer,rmanhome);
+ SetFilename( Server, FT_PIDFILE, strcat(Buffer,"/httpserver.pid") );
+
+ strcpy(Buffer,rmanhome);
+ SetFilename( Server, FT_SERVERLOG, strcat(Buffer,"/httpserver.log") );
+
+ free(Buffer);
+ free(myName);
+
+ return( OK );
+}
+
+
+/****** config/GetConfigKey **************************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+* With Help from K&R, Chapter 6, binsearch().
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+int GetConfigKey( char *Keyword )
+{
+ struct KeywordKey KeyTable[] =
+ {
+ { "AccessLog", KEY_ACCESSLOG },
+ { "CommLog", KEY_COMMLOG },
+ { "IndexFile", KEY_INDEXFILE },
+ { "MaxURLLength", KEY_MAXURLLENGTH },
+ { "PidFile", KEY_PIDFILE },
+ { "Port", KEY_PORT },
+ { "ServerAdmin", KEY_SERVERADMIN },
+ { "ServerLog", KEY_SERVERLOG },
+ { "ServerName", KEY_SERVERNAME },
+ { "ServerRoot", KEY_SERVERROOT },
+ };
+
+ int cond;
+ int low;
+ int high;
+
+ low = 0;
+ high = NUM_KEYS - 1;
+
+ while( low < high )
+ {
+ if( ( cond = strcmp( Keyword, KeyTable[ low ].Keyword ) ) == 0 )
+ return( KeyTable[ low ].Key );
+ low++;
+ }
+
+ return -1;
+}
+
diff --git a/httpserver/defs.h b/httpserver/defs.h
new file mode 100644
index 0000000..26d3b36
--- /dev/null
+++ b/httpserver/defs.h
@@ -0,0 +1,249 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*------------------------------------------------------------------------*/
+/* defs.h - Global defines and typedefs. */
+/*------------------------------------------------------------------------*/
+
+
+#ifndef _DEFS_H
+#define _DEFS_H
+
+
+/* Name of this daemon
+ */
+
+#define PROGRAM_NAME "httpserver"
+#define PROGRAM_VERSION "1.0"
+#define DAEMONNAME PROGRAM_NAME "/" PROGRAM_VERSION
+#define SERVERFIELD "Server: " DAEMONNAME "\r\n"
+
+
+/* These constants *may* be changed
+ */
+
+#define BUFFSIZE 8192
+#define MAXLINELEN 4096
+#define PIPE_BUFFSIZE 4096
+#define DATE_BUFFSIZE 40
+#define IO_BUFFSIZE 65536
+#define DEFAULT_MAXURLLENGTH 1000000
+// #define IO_BUFFSIZE 1024
+
+/* TimeOut values are given in seconds
+ */
+
+ /* Timeout when talking with subservers and client */
+#define DIALOG_TIMEOUT 30
+ /* Timeout when trying to get an unspecified mesage body, for example */
+ /* dynamically generated output (typically CGI output). */
+ /* You may have to *really* wait for it, so don't make it too small! */
+#define MSGBODY_TIMEOUT 30
+
+
+/* Misc. defines
+ */
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifdef SOCKLENNOTDEFINED
+typedef int socklen_t;
+#endif
+
+#define max(a,b) (a > b ? a : b)
+#define min(a,b) (a < b ? a : b)
+
+#define FOREGROUND 0
+#define BACKGROUND 1
+
+/* Std.-Zugriffsberechtigung für neue Dateien */
+#define FILE_MODE ( S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH )
+
+/* Filetypes: */
+#define FT_NOFILE 0
+#define FT_CONFFILE 1
+#define FT_ACCESSLOG 2
+#define FT_SERVERLOG 3
+#define FT_COMMLOG 4
+#define FT_PIDFILE 5
+#define FT_CACHEFILE 6
+
+/* Stringtypes: */
+#define ST_NOSTRING 0
+#define ST_HOSTNAME 1
+#define ST_MAILADDRESS 2
+
+
+/* Pipe Status:
+ */
+
+#define PIPE_OPEN 1
+#define PIPE_CLOSED 0
+
+/* LogFile Status:
+ */
+
+#define FILE_OPEN 1
+#define FILE_CLOSED 0
+
+/* Logging Modes:
+ * FILE (0) ServerLog und AccessLog einrichten und oeffnen
+ * STDIO (1) ServerLog -> stderr; AccessLog -> stdout
+ * DEBUG (2) Detaillierte Meldungen
+ */
+
+#define LF_VERB 0x0001
+#define LF_STDERR 0x0002
+
+#define LM_NORMAL 0 /* Not Verbose, write into log files */
+#define LM_VERBOSE 1 /* Verbose, write into log files */
+#define LM_STDERR 2 /* Not Verbose, use STDOUT/STDERR */
+#define LM_VERBOSE_STDERR 3 /* Verbose, use STDOUT/STDERR */
+
+
+/* LogLevels / ReturnCodes:
+ * DEBUG (1) Detaillierte Aktionsmeldungen
+ * INFO (2) Statusmeldungen
+ * NOTE (3) Hinweise auf besondere Situationen
+ * WARN (5) Behebbare Fehlersituationen
+ * ERROR (10) Fehler die zu Aktionsabbruch fuehren
+ * FAIL (20) Fehler die zum Programmabbruch fuehren
+ */
+
+#define OK 0
+#define DEBUG 1
+#define INFO 2
+#define NOTE 3
+#define WARN 5
+#define ERROR 10
+#define FAIL 20
+#define DUMP 50
+
+#define SYS_ERROR -1
+
+/* Logging sub-systems:
+ * LG_SERVER generic server logfile
+ * LG_ACCESS HTTP request logfile
+ */
+
+#define LG_SERVER 1
+#define LG_ACCESS 2
+#define LG_COMM 3
+
+/* Error-Type flags:
+ * SYS TRUE System Error: strerror(errno)
+ * PRIV FALSE Application Error
+ */
+
+#define E_SYS TRUE
+#define E_PRIV FALSE
+
+/* Configuration Keyword Keys:
+ */
+
+#define KEY_ACCESSLOG 1
+#define KEY_COMMLOG 2
+#define KEY_INDEXFILE 3
+#define KEY_MAXURLLENGTH 4
+#define KEY_PIDFILE 5
+#define KEY_PORT 6
+#define KEY_SERVERADMIN 7
+#define KEY_SERVERLOG 8
+#define KEY_SERVERNAME 9
+#define KEY_SERVERROOT 10
+#define NUM_KEYS 11
+
+/* SubServer Communication Status Codes:
+ */
+
+#define COMM_UNSUPPORTED -3 /* don't know how to handle comm state */
+#define COMM_UNEXPECTED -2 /* unexpected data received */
+#define COMM_FAILED -1 /* trouble while communicating, protocol failure */
+#define COMM_IDLE 0 /* not connected and ready */
+#define COMM_CONNECTING 1 /* trying to connect or "Keep-Alive" connection */
+#define COMM_GET_RESPHEAD 2 /* reading and processing response header */
+#define COMM_GET_RESPBODY 3 /* reading response body */
+#define COMM_MAY_GET_BODY 4 /* have to check for response body */
+#define COMM_HERE_IS_MORE 5 /* select() indicated that there IS more data */
+#define COMM_DONE 9 /* communication done, protocol OK */
+/* Currently not in use: */
+#define COMM_RECONNECTING 10 /* trying to reconnect for authorization */
+#define COMM_VERIFYING 11 /* analysing response: add. processing required */
+#define COMM_SENDINGAUTH 12 /* (re-)sending request with authorization */
+
+/* Connection Mode Codes:
+ */
+
+#define CONN_FAILURE -3 /* Failure when setting up connection */
+#define CONN_BROKEN -2 /* Connection broken while communicating */
+#define CONN_UNDEFINED -1 /* Connection not initiated */
+#define CONN_CLOSE 0 /* Connection will be closed ASAP */
+#define CONN_OPEN 1 /* Connection is ready for communication */
+#define CONN_ERROR 2 /* Error condition in communication */
+
+/* ToDo Action Codes:
+ */
+
+#define DO_NOTHING 0
+#define DO_SINGLE_SERVER 1
+#define DO_REWRITE 2
+#define DO_SEND_RESPONSE 3
+#define DO_SEND_ERROR 4
+#define DO_SHUTDOWN 5
+
+/* Client Types */
+#define BROWSER 1
+#define RASCLIENT 2
+
+/* ToDo Argument Codes:
+ */
+
+/* - DO_REWRITE: */
+#define MODE_HTTP_1_0 1
+#define MODE_HTTP_1_1 2
+
+/* - INTERPRETE_POST_REQUEST: - */
+#define REQU_OK 1
+#define REQU_UNKNOWN_PARAMETER 2
+#define REQU_UNKNOWN_CLIENT 3
+
+/* - Result Types: Error, MDD, Skalar - */
+#define RESULT_ERROR 1
+#define RESULT_MDD 2
+#define RESULT_SKALAR 3
+
+/* - DO_SEND_ERROR: */
+/* -> use HTTP Status Codes (see http-defs.h) */
+
+/* - DO_SHUTDOWN: */
+#define CLOSE_ALL 1
+#define CLOSE_CLIENT_ONLY 2 /* Currently not used */
+
+/* - DO_NOTHING: */
+#define REALLY_NOTHING 0
+
+#endif /* _DEFS_H not defined */
diff --git a/httpserver/http-date.cc b/httpserver/http-date.cc
new file mode 100644
index 0000000..82324dd
--- /dev/null
+++ b/httpserver/http-date.cc
@@ -0,0 +1,97 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*------------------------------------------------------------------------*/
+/* http-support.c - get and set HTTP date strings. */
+/* */
+/*------------------------------------------------------------------------*/
+/*
+ * RCS:
+ * $RCSfile: http-date.c,v $ $Revision: 1.1 $ $State: Exp $
+ * $Locker: $
+ */
+
+
+#include "defs.h"
+#include "types.h"
+#include "protos.h"
+#include "server.h"
+#include "http-defs.h"
+#include "http.h"
+
+
+/****** http-date/HTTP_Date **************************************************
+*
+* NAME
+* HTTP_Date -- create a HTTP date string.
+*
+* SYNOPSIS
+* rc_t HTTP_Date( char *Buffer, size_t BuffSize );
+*
+* FUNCTION
+* Creates a date (and time) string as defined in the HTTP
+* specifications. It uses the `gmtime()' system function to get the
+* current time in Greenwich Mean Time and creates a date string with
+* the help of `strftime()'.
+*
+* INPUTS
+* Buffer - a pointer to a buffer for the new string.
+* BuffSize - size of the Buffer for the date string.
+*
+* RESULT
+* Returns the "OK" status code if it succesfully created the date
+* string, "ERROR" otherwise. The only reason for this function should
+* fail, is when the Buffer is not large enough.
+* As a side effect, if the function succeeds, Buffer will contain the
+* current time and date in a format conforming to the HTTP
+* specifications.
+*
+* BUGS
+* Does not check if Buffer is NULL-pointer.
+*
+* SEE ALSO
+* RFC 2068: Hypertext Transfer Protocol -- HTTP/1.1
+*
+******************************************************************************
+*
+*/
+
+rc_t HTTP_Date( char *Buffer, size_t BuffSize )
+{
+ time_t systime;
+ time_t *time_ptr;
+ struct tm *tm_ptr;
+ size_t strsize;
+
+ time_ptr = &systime;
+ time( time_ptr );
+
+ /* HTTP Date: "wdy, dd mmm yyyy hh:mm:ss GMT" */
+
+ tm_ptr = gmtime( time_ptr );
+ strsize = strftime( Buffer, BuffSize, "%a, %d %b %Y %H:%M:%S GMT", tm_ptr );
+ if( strsize == BuffSize )
+ return( ERROR );
+ else
+ return( OK );
+}
+
diff --git a/httpserver/http-defs.h b/httpserver/http-defs.h
new file mode 100644
index 0000000..12df7bc
--- /dev/null
+++ b/httpserver/http-defs.h
@@ -0,0 +1,214 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*------------------------------------------------------------------------*/
+/* http-defs.h - defines for HTTP. */
+/*------------------------------------------------------------------------*/
+
+
+#ifndef _HTTP_DEFS_H
+#define _HTTP_DEFS_H
+
+#define AUTH_MAX_RETRIES 1
+
+/*
+ */
+
+#define HTTP_REQUEST 1
+#define HTTP_RESPONSE 2
+
+
+/* ReqInfo/RespInfo structure states when reading/parsing requests/responses
+ */
+
+#define RI_EMPTY 0
+#define RI_READ_OK 1
+#define RI_READ_ERROR 2
+#define RI_PARSE_OK 3
+#define RI_PARSE_WARN 4 /* trouble when parsing MsgHeaders */
+#define RI_PARSE_ERROR 5 /* Request Line/Status Line not found */
+
+/* Known Protocols:
+ */
+
+#define HTTP_0_9 0
+#define HTTP_0_9_STRING ""
+#define HTTP_1_0 1
+#define HTTP_1_0_STRING "HTTP/1.0"
+#define HTTP_1_1 2
+#define HTTP_1_1_STRING "HTTP/1.1"
+
+
+/* HTTP Method Keys:
+ */
+
+#define MKEY_NONE 0
+#define MKEY_GET 1
+#define MKEY_HEAD 2
+#define MKEY_PUT 3
+#define MKEY_POST 4
+#define MKEY_DELETE 5
+#define MKEY_OPTIONS 6
+#define MKEY_TRACE 7
+#define MKEY_UNKNOWN 999
+
+#define NUM_MKEYS 7
+
+
+/* HTTP Status Codes:
+ */
+
+#define STATUS_UNKNOWN 0
+#define STATUS_UNDEFINED 0
+#define STATUS_Continue 100
+#define STATUS_Switching_Protocols 101
+#define STATUS_OK 200
+#define STATUS_Created 201
+#define STATUS_Accepted 202
+#define STATUS_Non_Authoritative_Information 203
+#define STATUS_No_Content 204
+#define STATUS_Reset_Content 205
+#define STATUS_Partial_Content 206
+#define STATUS_Multiple_Choices 300
+#define STATUS_Moved_Permanently 301
+#define STATUS_Moved_Temporarily 302
+#define STATUS_See_Other 303
+#define STATUS_Not_Modified 304
+#define STATUS_Use_Proxy 305
+#define STATUS_Switch_Proxy 306
+#define STATUS_Bad_Request 400
+#define STATUS_Unauthorized 401
+#define STATUS_Payment_Required 402
+#define STATUS_Forbidden 403
+#define STATUS_Not_Found 404
+#define STATUS_Method_Not_Allowed 405
+#define STATUS_Not_Acceptable 406
+#define STATUS_Proxy_Authentication_Required 407
+#define STATUS_Request_Timeout 408
+#define STATUS_Conflict 409
+#define STATUS_Gone 410
+#define STATUS_Length_Required 411
+#define STATUS_Precondition_Failed 412
+#define STATUS_Request_Entity_Too_Large 413
+#define STATUS_Request_URI_Too_Long 414
+#define STATUS_Unsupported_Media_Type 415
+#define STATUS_Requested_Range_Not_Valid 416
+#define STATUS_Expectation_Failed 419
+#define STATUS_Internal_Server_Error 500
+#define STATUS_Not_Implemented 501
+#define STATUS_Bad_Gateway 502
+#define STATUS_Service_Unavailable 503
+#define STATUS_Gateway_Timeout 504
+#define STATUS_HTTP_Version_Not_Supported 505
+#define STATUS_Redirection_Failed 506
+
+
+/* HTTP Header Keys:
+ */
+
+#define HKEY_CONTINUE 0
+#define HKEY_Accept 1
+#define HKEY_Accept_Charset 2
+#define HKEY_Accept_Encoding 3
+#define HKEY_Accept_Language 4
+#define HKEY_Accept_Ranges 5
+#define HKEY_Age 6
+#define HKEY_Allow 7
+#define HKEY_Authorization 8
+#define HKEY_Cache_Control 9
+#define HKEY_Compliance 10
+#define HKEY_Connection 11
+#define HKEY_Content_Base 12
+#define HKEY_Content_Encoding 13
+#define HKEY_Content_Language 14
+#define HKEY_Content_Length 15
+#define HKEY_Content_Location 16
+#define HKEY_Content_MD5 17
+#define HKEY_Content_Range 18
+#define HKEY_Content_Type 19
+#define HKEY_Date 20
+#define HKEY_ETag 21
+#define HKEY_Expect 22
+#define HKEY_Expires 23
+#define HKEY_From 24
+#define HKEY_Host 25
+#define HKEY_If_Modified_Since 26
+#define HKEY_If_Match 27
+#define HKEY_If_None_Match 28
+#define HKEY_If_Range 29
+#define HKEY_If_Unmodified_Since 30
+#define HKEY_Keep_Alive 31
+#define HKEY_Last_Modified 32
+#define HKEY_Location 33
+#define HKEY_Max_Forwards 34
+#define HKEY_Non_Compliance 35
+#define HKEY_Pragma 36
+#define HKEY_Proxy_Authenticate 37
+#define HKEY_Proxy_Authorization 38
+#define HKEY_Public 39
+#define HKEY_Range 40
+#define HKEY_Referer 41
+#define HKEY_Retry_After 42
+#define HKEY_Server 43
+#define HKEY_Set_Proxy 44
+#define HKEY_Transfer_Encoding 45
+#define HKEY_Upgrade 46
+#define HKEY_User_Agent 47
+#define HKEY_Vary 48
+#define HKEY_Warning 49
+#define HKEY_WWW_Authenticate 50
+#define HKEY_UNKNOWN 999
+
+#define NUM_HKEYS 50
+
+
+/* Language Keys:
+ */
+
+ /* These numbers are intentionally choosen: */
+ /* Space left for upgrades. */
+ /* See also: ISP 639 / Version 1 */
+
+#define LANG_UNKNOWN 0
+#define LANG_DE 22
+#define LANG_EN 25
+#define LANG_EO 26
+#define LANG_ES 27
+#define LANG_FR 34
+#define LANG_IT 53
+
+
+/* Security Realm Keys:
+ */
+
+#define REALM_ERROR -1
+#define REALM_UNKNOWN 0
+#define REALM_UNDEFINED 0
+#define REALM_IPCLASS_A 1
+#define REALM_IPCLASS_B 2
+#define REALM_IPCLASS_C 3
+#define REALM_IPADDRESS 4
+#define REALM_HOSTNAME 10
+#define REALM_DOMAIN 11
+
+
+#endif /* _HTTP_DEFS_H not defined */
diff --git a/httpserver/http-doit.cc b/httpserver/http-doit.cc
new file mode 100644
index 0000000..1136fb6
--- /dev/null
+++ b/httpserver/http-doit.cc
@@ -0,0 +1,536 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#include "mymalloc/mymalloc.h"
+/*------------------------------------------------------------------------*/
+/* http-doit.c - functions for handling the communication in its */
+/* various states. */
+/*------------------------------------------------------------------------*/
+
+#include "servercomm/httpserver.hh"
+
+#include "defs.h"
+#include "protos.h"
+#include "server.h"
+#include "http-defs.h"
+#include "http.h"
+
+extern struct ServerBase Server;
+
+/****** http/Accept **********************************************************
+*
+* NAME
+* Accept -- wrapper function to `accept()' system call.
+*
+* SYNOPSIS
+* rc_t Accept( int SockFD, struct ClientBase *Client );
+*
+* FUNCTION
+* This function is used as a wrapper for the `accept()' system call so
+* the appropriate variables and structures as defined for this program
+* will be used. In addition, if `accept()' fails it will lead the
+* program into immediate abortion.
+*
+* INPUTS
+* SockFD - the file descriptor of the socket, which will be used to
+* accept connections.
+* Client - a pointer to a ClientBase structure, where all necessary
+* informations of the client who made the connection is stored.
+*
+* RESULT
+* Returns the "OK" status code on success, never returns if it fails.
+* As a side effect, when `accept()' returns, the socket structure that
+* is part of the ClientBase structure is setup by `accpet()'.
+*
+* NOTES
+* "Client" must be a pointer to a valid ClientBase structure.
+* Calls `ErrorMsg()' in case of an failure with option fail, which will
+* cause an immediate abortion of the program.
+*
+* BUGS
+* 1) Does not check if "Client" is a NULL pointer.
+* 2) On some systems the accept call has to be made twice to succeed,
+* because the first attempt fails with an "interrupted system call"
+* error message.
+*
+******************************************************************************
+*
+*/
+
+rc_t Accept( int SockFD, struct ClientBase *Client )
+{
+ short cc = 0;
+ int test = -1;
+
+ if( Client == NULL )
+ ErrorMsg( E_SYS, FAIL, "FAIL: accept(): Client is NULL." );
+ Client->SockSize = sizeof( Client->Socket );
+
+ while (( cc < 10 ) && ( test < 0 ))
+ {
+#ifdef DECALPHA
+ test = accept( SockFD, (struct sockaddr *)&Client->Socket,
+ (int*)&Client->SockSize );
+#else
+ test = accept( SockFD, (struct sockaddr *)&Client->Socket,
+ (socklen_t*)&Client->SockSize );
+#endif
+ cc++;
+ LogMsg( LG_SERVER, DEBUG, "DEBUG: accept call # %d",cc );
+ }
+ Client->SockFD = test;
+ if( Client->SockFD < 0 )
+ ErrorMsg( E_SYS, FAIL, "FAIL: accept()." );
+ return( OK );
+}
+
+
+
+
+void GetRequest( struct ClientBase *Client )
+{
+ int flags;
+
+ /*-- Try to make SockFD non-blocking; */
+ /* if it fails, try to continue nevertheless --*/
+ flags = fcntl( Client->SockFD, F_GETFL, 0 );
+ if( flags < 0 )
+ ErrorMsg( E_SYS, WARN,
+ "WARN: GetRequest(): Client Socket: fcntl() (get flags) failed." );
+ else if( fcntl( Client->SockFD, F_SETFL, flags | O_NONBLOCK ) < 0 )
+ ErrorMsg( E_SYS, WARN,
+ "WARN: GetRequest(): Client Socket: fcntl() (set to non-blocking) failed." );
+
+ /*-- Read Header of Request */
+ Client->Request.State = ReadHeader( Client->SockFD,
+ &Client->Request.HeadBuff,
+ &Client->Request.HeadSize );
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: Header is:\n %s",Client->Request.HeadBuff );
+}
+
+
+
+
+void InterpreteRequest( struct ClientBase *Client, struct ToDoArgs *ToDo )
+{
+ struct CacheData *Data = NULL;
+
+ switch( Client->Request.State )
+ {
+ case RI_PARSE_ERROR:
+ // The request couldn't be parsed (comm. error or something similar)
+ // --> Shutdown the connection.
+ Client->Comm.Protocol = HTTP_1_0;
+ Client->Comm.ConnStatus = CONN_ERROR;
+ ToDo->What = DO_SHUTDOWN;
+ ToDo->Which.Code = CLOSE_CLIENT_ONLY;
+ break;
+ case RI_PARSE_OK:
+ // Check for Protocol Version of Client
+ // May be a HTTP/0.9 request?
+ if( Client->Request.Line.Version.Major <= 0 )
+ {
+ // Yes -- we don't support it, would be too much trouble ahead...
+ ToDo->What = DO_SEND_ERROR;
+ ToDo->Which.Code = STATUS_HTTP_Version_Not_Supported;
+ return;
+ }
+ else if( Client->Request.Line.Version.Major == 1 )
+ {
+ Client->Comm.Protocol = HTTP_1_0;
+ }
+ else
+ {
+ ToDo->What = DO_SEND_ERROR;
+ ToDo->Which.Code = STATUS_HTTP_Version_Not_Supported;
+ return;
+ }
+
+ // Check for Content-Length and if available, then ReadBody()
+ Client->Request.BodySize = GetContentLength( Client->Request.First );
+ if( Client->Request.BodySize > 0 )
+ {
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: InterpreteRequest() -> ReadBody()." );
+ Client->Request.BodyBuff = ReadBody( Client->SockFD, Client->Request.BodySize );
+ }
+ // Get Connection Status //### currently not really...
+ if( TRUE )
+ Client->Comm.ConnStatus = CONN_CLOSE;
+
+ // Check for supported Methods
+ if( Client->Request.Line.Method != MKEY_POST )
+ {
+ // No supported Method found...
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: No post request!" );
+ ToDo->What = DO_SEND_ERROR;
+ ToDo->Which.Code = STATUS_Method_Not_Allowed;
+ }
+ // Send response
+ else
+ {
+ ToDo->What = DO_SEND_RESPONSE;
+ ToDo->Which.Code = REQU_OK;
+ }
+ break;
+ default:
+ // Strange State...
+ ErrorMsg( E_PRIV, ERROR,
+ "ERROR: InterpreteRequest(): Request can't be handled!" );
+ Client->Comm.ConnStatus = CONN_ERROR;
+ ToDo->What = DO_SHUTDOWN;
+ ToDo->Which.Code = CLOSE_CLIENT_ONLY;
+ break;
+ }
+}
+
+
+
+char *ComposeErrorResponse( int Errno, int ClientType )
+{
+ char *Msg;
+ char *Buff;
+ size_t BuffSize = BUFFSIZE;
+
+ if( ( Msg = (char*)mymalloc( BuffSize ) ) == NULL )
+ {
+ ErrorMsg( E_SYS, ERROR,
+ "ERROR: ComposeErrorMsg() - malloc() error for Msg Buffer buffer." );
+ }
+ BuffSize -= 1;
+ Buff = Msg;
+
+ switch( ClientType )
+ {
+ case BROWSER:
+ /* Fehlermeldungen fuer HTML-Browser */
+ SNPrintf( Buff, &BuffSize, "<BR><H1>Error %d: ", Errno );
+ Buff = Msg + strlen( Msg );
+ switch( Errno )
+ {
+ case REQU_UNKNOWN_PARAMETER:
+ SNPrintf( Buff, &BuffSize, "Unknown protocol parameter." );
+ break;
+ default:
+ SNPrintf( Buff, &BuffSize, "Undefined protocol error." );
+ break;
+ }
+ break;
+
+ case RASCLIENT:
+ default:
+ /* Fehlermeldungen fuer RasClients */
+ SNPrintf( Buff, &BuffSize, "%d+%d+%d", RESULT_ERROR, Errno, 0 );
+ break;
+ }
+
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: ComposeErrorMsg() returns %s", Msg );
+ return Msg;
+}
+
+
+
+void SendResponse( struct ClientBase *Client )
+{
+
+ /*
+ LogMsg( LG_SERVER, DEBUG, "DEBUG: SendResponse() : %s",
+ Client->Response.Body );
+ */
+
+ SendHTTPMsg( Client->SockFD, &Client->Response );
+}
+
+
+/*********************************************************************
+ *
+ * This function interpretes the body of an incoming request
+ * and fills the RequestInfo struct accordingly.
+ *
+ *********************************************************************/
+rc_t GetHTTPRequest( char *Source, int SourceLen, struct HTTPRequest *RequestInfo)
+{
+ char *Buffer = NULL;
+ char *Input;
+
+ Input = (char*)mymalloc( SourceLen + 1 );
+ memcpy( Input, Source, SourceLen );
+ Input[SourceLen] = '\0';
+ // Read the message body and check for the post parameters
+ Buffer = strtok( Input, "=" );
+ while( Buffer != NULL )
+ {
+ if( strcmp(Buffer,"Database") == 0 )
+ {
+ RequestInfo->Database = strdup(strtok( NULL, "&" ));
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: Parameter Database is %s", RequestInfo->Database );
+ Buffer = strtok( NULL, "=" );
+ }
+ else if( strcmp(Buffer,"QueryString") == 0 )
+ {
+ RequestInfo->QueryString = strdup(strtok( NULL, "&" ));
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: Parameter QueryString is %s", RequestInfo->QueryString );
+ Buffer = strtok( NULL, "=" );
+ }
+ else if( strcmp(Buffer,"Capability") == 0 )
+ {
+ RequestInfo->Capability = strdup(strtok( NULL, "&\0" ));
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: Parameter Capability is %s", RequestInfo->Capability );
+ Buffer = strtok( NULL, "=" );
+ }
+ else if( strcmp(Buffer,"ClientID") == 0 )
+ {
+ RequestInfo->ClientID = strdup(strtok( NULL, "&" ));
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: Parameter ClientID is %s", RequestInfo->ClientID );
+ Buffer = strtok( NULL, "=" );
+ }
+ else if( strcmp(Buffer,"Command") == 0 )
+ {
+ RequestInfo->Command = atoi( strtok( NULL, "&" ) );
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: Parameter Command is %i", RequestInfo->Command );
+ Buffer = strtok( NULL, "=" );
+ }
+ else if( strcmp(Buffer,"Endianess") == 0 )
+ {
+ RequestInfo->Endianess = atoi( strtok( NULL, "&" ) );
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: Parameter Endianess is %i", RequestInfo->Endianess );
+ Buffer = strtok( NULL, "=" );
+ }
+ else if( strcmp(Buffer,"NumberOfQueryParameters") == 0 )
+ {
+ RequestInfo->NumberOfQueryParams = atoi( strtok( NULL, "&" ) );
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: Parameter NumberOfQueryParams is %i", RequestInfo->NumberOfQueryParams );
+ Buffer = strtok( NULL, "=" );
+ }
+ else if( strcmp(Buffer,"BinDataSize") == 0 )
+ {
+ RequestInfo->BinDataSize = atoi( strtok( NULL, "&" ) );
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: Parameter BinDataSize is %i", RequestInfo->BinDataSize );
+ Buffer = strtok( NULL, "=" );
+ }
+ else if( strcmp(Buffer,"BinData") == 0 )
+ {
+ // This parameter has to be the last one!
+ RequestInfo->BinData = (char*)mymalloc( RequestInfo->BinDataSize );
+ memcpy(RequestInfo->BinData, Source + (SourceLen-RequestInfo->BinDataSize), RequestInfo->BinDataSize );
+ //set Buffer to NULL => exit this while block
+ Buffer = NULL;
+ }
+ else if( strcmp(Buffer,"ClientType") == 0 )
+ {
+ Buffer = strtok( NULL, "&" );
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: Parameter Type is %s", Buffer );
+ /* BROWSER? */
+ if( strcmp(Buffer,"BROWSER") == 0 )
+ RequestInfo->ClientType = 1;
+ /* Rasclient? */
+ else if( strcmp(Buffer,"RASCLIENT") == 0 )
+ RequestInfo->ClientType = 2;
+ /* Sonstiges */
+ else
+ {
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: Unknown Parameter %s", Buffer );
+ return REQU_UNKNOWN_CLIENT;
+ }
+ Buffer = strtok( NULL, "=" );
+ }
+ else
+ return REQU_UNKNOWN_PARAMETER;
+ }
+
+ free(Input);
+ return REQU_OK;
+}
+
+
+/********************************************************
+ *
+ * Analyses the client request (using the "GetHTTPRequest" function)
+ * and executes the query (function "processQuery").
+ * The result is written into the client response structure.
+ *
+ **********************************************************/
+void InterpretePOSTRequest ( struct ClientBase *Client )
+{
+ int result = 0;
+ struct HTTPRequest RequestInfo;
+ char *tmp;
+
+ /* Initialize RequestInfo */
+ RequestInfo.Database = NULL;
+ RequestInfo.QueryString = NULL;
+ RequestInfo.ClientType = 0;
+ RequestInfo.ClientID = NULL;
+ RequestInfo.Command = 0;
+ RequestInfo.Endianess = 0;
+ RequestInfo.NumberOfQueryParams = 0;
+ RequestInfo.BinDataSize = 0;
+ RequestInfo.BinData = NULL;
+ RequestInfo.Capability = NULL;
+
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: InterpretePostRequest() ..." );
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: Request.BodySize is %d",Client->Request.BodySize );
+
+ /* get the necessary parameters */
+ result = GetHTTPRequest( Client->Request.BodyBuff, Client->Request.BodySize, &RequestInfo );
+
+ if( result == REQU_OK )
+ {
+ // here the query is actually executed
+ char* queryResult;
+ long resultLen;
+ ServerComm* scObject = ServerComm::actual_servercomm;
+
+ // the cast should be save, function only called on HTTP requests
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: Vor processRequest ..." );
+ resultLen = ((HttpServer*)scObject)->processRequest(1, RequestInfo.Database, RequestInfo.Command,
+ RequestInfo.QueryString, RequestInfo.BinDataSize,
+ RequestInfo.BinData, RequestInfo.Endianess,
+ queryResult,RequestInfo.Capability);
+
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: ... nach processRequest." );
+
+ // Note that this has to be freed!!!!!
+ Client->Response.Body = queryResult;
+ Client->Response.BodySize = resultLen;
+
+
+ Client->ClientType = RequestInfo.ClientType;
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: ResponseBody is %s", Client->Response.Body );
+ }
+ else
+ {
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: InterpretePostRequest(): send error response. " );
+ Client->Response.Body = ComposeErrorResponse( result, RequestInfo.ClientType );
+ Client->Response.BodySize = strlen( Client->Response.Body );
+ Client->ClientType = RequestInfo.ClientType;
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: ResponseBody is %s", Client->Response.Body );
+ }
+
+ // free RequestInfo
+ free(RequestInfo.Database);
+ free(RequestInfo.QueryString);
+ free(RequestInfo.Capability);
+ free(RequestInfo.BinData);
+ free(RequestInfo.ClientID);
+
+}
+
+
+
+void CreateRasResponse( struct HTTPMode *Mode, struct ClientBase *Client )
+{
+ char *Head;
+ char *Buff;
+ size_t BuffSize = BUFFSIZE;
+ char MDate[30];
+
+
+
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: Response Header begin, malloc BUFFSIZE is %d", BUFFSIZE );
+
+ HTTP_Date( MDate, 30 );
+
+ if( ( Head = (char*)mymalloc( BuffSize ) ) == NULL )
+ {
+ ErrorMsg( E_SYS, ERROR,
+ "ERROR: CreateRasResponse() - malloc() error for head buffer." );
+ }
+
+ BuffSize -= 1;
+ Buff = Head;
+ bzero( Head, BuffSize );
+ CreateStatusLine( Buff, &BuffSize, STATUS_OK, Mode->Protocol );
+
+ /* General Message Header */
+ Buff = Head + strlen( Head );
+ SNPrintf( Buff, &BuffSize, "Date: %s\r\n", MDate );
+ Buff = Head + strlen( Head );
+ SNPrintf( Buff, &BuffSize, "Connection: close\r\n" );
+
+ /* Response Message Header */
+ Buff = Head + strlen( Head );
+ SNPrintf( Buff, &BuffSize, SERVERFIELD );
+
+ /* Entity Message Header */
+ Buff = Head + strlen( Head );
+ switch( Client->ClientType )
+ {
+ case BROWSER:
+ SNPrintf( Buff, &BuffSize, "Content-Type: text/html\r\n" );
+ break;
+ case RASCLIENT:
+ SNPrintf( Buff, &BuffSize, "Content-Type: application/octet-stream\r\n" );
+ break;
+ default:
+ SNPrintf( Buff, &BuffSize, "Content-Type: application/octet-stream\r\n" );
+ break;
+ }
+ Buff = Head + strlen( Head );
+
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: ClientResponse BodySize is %d", Client->Response.BodySize );
+
+ SNPrintf( Buff, &BuffSize, "Content-Length: %d\r\n", Client->Response.BodySize );
+ Buff = Head + strlen( Head );
+ SNPrintf( Buff, &BuffSize, "Last-Modified: %s\r\n", MDate );
+ Buff = Head + strlen( Head );
+ SNPrintf( Buff, &BuffSize, "\r\n" );
+
+ Client->Response.Head = Head;
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: Response Header is %s", Client->Response.Head );
+
+}
+
+
+
+void WriteAccessLog( struct ClientBase *Client )
+{
+ char TimeString[ DATE_BUFFSIZE ];
+ struct hostent *Host;
+ char *Hostname = NULL;
+
+ bzero( TimeString, DATE_BUFFSIZE );
+
+ if( (int)Client->Host.IPAddress != -1 )
+ {
+ Host = gethostbyaddr( (const char *)&Client->Host.IPAddress,
+ sizeof( Client->Host.IPAddress ), AF_INET );
+ if( Host != NULL )
+ Hostname = Host->h_name;
+ else
+ Hostname = Client->Host.IPAddrString;
+ }
+ else
+ Hostname = Client->Host.IPAddrString;
+
+ LogDate( TimeString, DATE_BUFFSIZE );
+ LogMsg( LG_ACCESS, INFO, "%s - - %s \"%s\" %d %d\n",
+ Hostname,
+ TimeString,
+ Client->Request.Line.Vanilla,
+ Client->RespStatus,
+ Client->Response.BodySize );
+}
+
+
+
+
diff --git a/httpserver/http-error.cc b/httpserver/http-error.cc
new file mode 100644
index 0000000..92fd451
--- /dev/null
+++ b/httpserver/http-error.cc
@@ -0,0 +1,446 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#include "mymalloc/mymalloc.h"
+/*------------------------------------------------------------------------*/
+/* http-error.c - HTTP Error message handling. */
+/*------------------------------------------------------------------------*/
+/* Comments: */
+/* - Status: */
+/* - The internal response strings should be completed and */
+/* the overly long lines should be broken up. */
+/* - A somewhat more dynamic approach to the handling of the */
+/* error string table should be used. */
+/*------------------------------------------------------------------------*/
+
+#include "defs.h"
+#include "protos.h"
+#include "server.h"
+#include "http-defs.h"
+#include "http.h"
+
+struct HTTPError HTTPErrorTable[] =
+{
+ {
+ STATUS_Continue,
+ "Continue",
+ "",
+ ""
+ },
+ {
+ STATUS_Switching_Protocols,
+ "Switching Protocols",
+ "",
+ ""
+ },
+ {
+ STATUS_OK,
+ "OK",
+ "",
+ ""
+ },
+ {
+ STATUS_Created,
+ "Created",
+ "",
+ ""
+ },
+ {
+ STATUS_Accepted,
+ "Accepted",
+ "",
+ ""
+ },
+ {
+ STATUS_Non_Authoritative_Information,
+ "Non-Authoritative Information",
+ "",
+ ""
+ },
+ {
+ STATUS_No_Content,
+ "No Content",
+ "",
+ ""
+ },
+ {
+ STATUS_Reset_Content,
+ "Reset Content",
+ "",
+ ""
+ },
+ {
+ STATUS_Partial_Content,
+ "Partial Content",
+ "",
+ ""
+ },
+ {
+ STATUS_Multiple_Choices,
+ "Multiple Choices",
+ "",
+ ""
+ },
+ {
+ STATUS_Moved_Permanently,
+ "Moved Permanently",
+ "",
+ ""
+ },
+ {
+ STATUS_Moved_Temporarily,
+ "Moved Temporarily",
+ "",
+ ""
+ },
+ {
+ STATUS_See_Other,
+ "See Other",
+ "",
+ ""
+ },
+ {
+ STATUS_Not_Modified,
+ "Not Modified",
+ "",
+ ""
+ },
+ {
+ STATUS_Use_Proxy,
+ "Use Proxy",
+ "",
+ ""
+ },
+ {
+ STATUS_Bad_Request,
+ "Bad Request",
+ "<HTML><HEAD>\n<TITLE>400 Bad Request</TITLE>\n</HEAD>"\
+ "<BODY>\n<H1>Bad Request</H1>\n"\
+ "Your browser sent a request that this server could not understand.\n"\
+ "</BODY></HTML>\n",
+ "<HTML><HEAD>\n<TITLE>400 Bad Request</TITLE>\n</HEAD>"\
+ "<BODY>\n<H1>Problem mit Request</H1>\n"\
+ "Ihr Browser hat einen Request geschickt, der von diesem Server "\
+ "nicht verstanden wurde.\n"\
+ "</BODY></HTML>\n"
+ },
+ {
+ STATUS_Unauthorized,
+ "Unauthorized",
+ "<HTML><HEAD>\n<TITLE>401 Unauthorized</TITLE>\n</HEAD>"\
+ "<BODY>\n<H1>Unauthorized</H1>\n"\
+ "You have not the necessary rights to get the requested document.\n"\
+ "</BODY></HTML>\n",
+ "<HTML><HEAD>\n<TITLE>401 Unauthorized</TITLE>\n</HEAD>"\
+ "<BODY>\n<H1>Nicht Authorisiert</H1>\n"\
+ "Sie haben nicht die notwendigen Rechte um auf das angeforderte "\
+ "Dokument zuzugreifen.\n"\
+ "</BODY></HTML>\n"
+ },
+ {
+ STATUS_Payment_Required,
+ "Payment Required",
+ "<HTML><HEAD>\n<TITLE>402 Payment Required</TITLE>\n</HEAD><BODY>\n<H1>Payment Required</H1>\n</BODY></HTML>\n",
+ "<HTML><HEAD>\n<TITLE>402 Payment Required</TITLE>\n</HEAD><BODY>\n<H1>Payment Required</H1>\n</BODY></HTML>\n"
+ },
+ {
+ STATUS_Forbidden,
+ "Forbidden",
+ "<HTML><HEAD>\n<TITLE>403 Forbidden</TITLE>\n</HEAD><BODY>\n<H1>Forbidden</H1>\n</BODY></HTML>\n",
+ "<HTML><HEAD>\n<TITLE>403 Forbidden</TITLE>\n</HEAD><BODY>\n<H1>Forbidden</H1>\n</BODY></HTML>\n"
+ },
+ {
+ STATUS_Not_Found,
+ "Not Found",
+ "<HTML><HEAD>\n<TITLE>404 Not Found</TITLE>\n</HEAD>"\
+ "<BODY>\n<H1>Not Found</H1>\n"\
+ "<EM>Tried hard, really...</EM>\n"\
+ "</BODY></HTML>\n",
+ "<HTML><HEAD>\n<TITLE>404 Not Found</TITLE>\n</HEAD>"\
+ "<BODY>\n<H1>Nicht Gefunden</H1>\n"\
+ "Das angeforderte Dokument wurde nicht gefunden.\n"\
+ "</BODY></HTML>\n"
+ },
+ {
+ STATUS_Method_Not_Allowed,
+ "Method Not Allowed",
+ "<HTML><HEAD>\n<TITLE>405 Method Not Allowed</TITLE>\n</HEAD><BODY>\n<H1>Method Not Allowed</H1>\n</BODY></HTML>\n",
+ "<HTML><HEAD>\n<TITLE>405 Method Not Allowed</TITLE>\n</HEAD><BODY>\n<H1>Method Not Allowed</H1>\n</BODY></HTML>\n"
+ },
+ {
+ STATUS_Not_Acceptable,
+ "Not Acceptable",
+ "<HTML><HEAD>\n<TITLE>406 Not Acceptable</TITLE>\n</HEAD><BODY>\n<H1>Not Acceptable</H1>\n</BODY></HTML>\n",
+ "<HTML><HEAD>\n<TITLE>406 Not Acceptable</TITLE>\n</HEAD><BODY>\n<H1>Not Acceptable</H1>\n</BODY></HTML>\n"
+ },
+ {
+ STATUS_Proxy_Authentication_Required,
+ "Proxy Authentication Required",
+ "<HTML><HEAD>\n<TITLE>407 Proxy Authentication Required</TITLE>\n</HEAD><BODY>\n<H1>Proxy Authentication Required</H1>\n</BODY></HTML>\n",
+ "<HTML><HEAD>\n<TITLE>407 Proxy Authentication Required</TITLE>\n</HEAD><BODY>\n<H1>Proxy Authentication Required</H1>\n</BODY></HTML>\n"
+ },
+ {
+ STATUS_Request_Timeout,
+ "Request Timeout",
+ "<HTML><HEAD>\n<TITLE>408 Request Timeout</TITLE>\n</HEAD><BODY>\n<H1>Request Timeout</H1>\n</BODY></HTML>\n",
+ "<HTML><HEAD>\n<TITLE>408 Request Timeout</TITLE>\n</HEAD><BODY>\n<H1>Request Timeout</H1>\n</BODY></HTML>\n"
+ },
+ {
+ STATUS_Conflict,
+ "Conflict",
+ "<HTML><HEAD>\n<TITLE>409 Conflict</TITLE>\n</HEAD><BODY>\n<H1>Conflict</H1>\n</BODY></HTML>\n",
+ "<HTML><HEAD>\n<TITLE>409 Conflict</TITLE>\n</HEAD><BODY>\n<H1>Conflict</H1>\n</BODY></HTML>\n"
+ },
+ {
+ STATUS_Gone,
+ "Gone",
+ "<HTML><HEAD>\n<TITLE>410 Gone</TITLE>\n</HEAD><BODY>\n<H1>Gone</H1>\n</BODY></HTML>\n",
+ "<HTML><HEAD>\n<TITLE>410 Gone</TITLE>\n</HEAD><BODY>\n<H1>Gone</H1>\n</BODY></HTML>\n"
+ },
+ {
+ STATUS_Length_Required,
+ "Length Required",
+ "<HTML><HEAD>\n<TITLE>411 Length Required</TITLE>\n</HEAD><BODY>\n<H1>Length Required</H1>\n</BODY></HTML>\n",
+ "<HTML><HEAD>\n<TITLE>411 Length Required</TITLE>\n</HEAD><BODY>\n<H1>Length Required</H1>\n</BODY></HTML>\n"
+ },
+ {
+ STATUS_Precondition_Failed,
+ "Precondition Failed",
+ "<HTML><HEAD>\n<TITLE>412 Precondition Failed</TITLE>\n</HEAD><BODY>\n<H1>Precondition Failed</H1>\n</BODY></HTML>\n",
+ "<HTML><HEAD>\n<TITLE>412 Precondition Failed</TITLE>\n</HEAD><BODY>\n<H1>Precondition Failed</H1>\n</BODY></HTML>\n"
+ },
+ {
+ STATUS_Request_Entity_Too_Large,
+ "Request Entity Too Large",
+ "<HTML><HEAD>\n<TITLE>413 Request Entity Too Large</TITLE>\n</HEAD><BODY><H1>Request Entity Too Large\n</H1>\n</BODY></HTML>\n",
+ "<HTML><HEAD>\n<TITLE>413 Request Entity Too Large</TITLE>\n</HEAD><BODY><H1>Request Entity Too Large\n</H1>\n</BODY></HTML>\n"
+ },
+ {
+ STATUS_Request_URI_Too_Long,
+ "Request-URI Too Long",
+ "<HTML><HEAD>\n<TITLE>414 Request-URI Too Long</TITLE>\n</HEAD><BODY><H1>Request-URI Too Long\n</H1>\n</BODY></HTML>\n",
+ "<HTML><HEAD>\n<TITLE>414 Request-URI Too Long</TITLE>\n</HEAD><BODY><H1>Request-URI Too Long\n</H1>\n</BODY></HTML>\n"
+ },
+ {
+ STATUS_Unsupported_Media_Type,
+ "Unsupported Media Type",
+ "<HTML><HEAD>\n<TITLE>415 Unsupported Media Type</TITLE>\n</HEAD><BODY>\n<H1>Unsupported Media Type</H1>\n</BODY></HTML>\n",
+ "<HTML><HEAD>\n<TITLE>415 Unsupported Media Type</TITLE>\n</HEAD><BODY>\n<H1>Unsupported Media Type</H1>\n</BODY></HTML>\n"
+ },
+ {
+ STATUS_Requested_Range_Not_Valid,
+ "Requested Range Not Valid",
+ "<HTML><HEAD>\n<TITLE>416 Requested Range Not Valid</TITLE>\n</HEAD><BODY>\n<H1>Requested Range Not Valid</H1>\n</BODY></HTML>\n",
+ "<HTML><HEAD>\n<TITLE>416 Requested Range Not Valid</TITLE>\n</HEAD><BODY>\n<H1>Requested Range Not Valid</H1>\n</BODY></HTML>\n"
+ },
+ {
+ STATUS_Internal_Server_Error,
+ "Internal Server Error",
+ "<HTML><HEAD>\n<TITLE>500 Internal Server Error</TITLE>\n</HEAD><BODY>\n<H1>Internal Server Error</H1>\n</BODY></HTML>\n",
+ "<HTML><HEAD>\n<TITLE>500 Internal Server Error</TITLE>\n</HEAD><BODY>\n<H1>Internal Server Error</H1>\n</BODY></HTML>\n"
+ },
+ {
+ STATUS_Not_Implemented,
+ "Not Implemented",
+ "<HTML><HEAD>\n<TITLE>501 Not Implemented</TITLE>\n</HEAD><BODY>\n<H1>Not Implemented</H1>\n</BODY></HTML>\n",
+ "<HTML><HEAD>\n<TITLE>501 Not Implemented</TITLE>\n</HEAD><BODY>\n<H1>Not Implemented</H1>\n</BODY></HTML>\n"
+ },
+ {
+ STATUS_Bad_Gateway,
+ "Bad Gateway",
+ "<HTML><HEAD>\n<TITLE>502 Bad Gateway</TITLE>\n</HEAD><BODY>\n<H1>Bad Gateway</H1>\n</BODY></HTML>\n",
+ "<HTML><HEAD>\n<TITLE>502 Bad Gateway</TITLE>\n</HEAD><BODY>\n<H1>Bad Gateway</H1>\n</BODY></HTML>\n"
+ },
+ {
+ STATUS_Service_Unavailable,
+ "Service Unavailable",
+ "<HTML><HEAD>\n<TITLE>503 Service Unavailable</TITLE>\n</HEAD><BODY>\n<H1>Service Unavailable</H1>\n</BODY></HTML>\n",
+ "<HTML><HEAD>\n<TITLE>503 Service Unavailable</TITLE>\n</HEAD><BODY>\n<H1>Service Unavailable</H1>\n</BODY></HTML>\n"
+ },
+ {
+ STATUS_Gateway_Timeout,
+ "Gateway Timeout",
+ "<HTML><HEAD>\n<TITLE>504 Gateway Timeout</TITLE>\n</HEAD><BODY>\n<H1>Gateway Timeout</H1>\n</BODY></HTML>\n",
+ "<HTML><HEAD>\n<TITLE>504 Gateway Timeout</TITLE>\n</HEAD><BODY>\n<H1>Gateway Timeout</H1>\n</BODY></HTML>\n"
+ },
+ {
+ STATUS_HTTP_Version_Not_Supported,
+ "HTTP Version Not Supported",
+ "<HTML><HEAD>\n<TITLE>505 HTTP Version Not Supported</TITLE>\n</HEAD><BODY>\n<H1>HTTP Version Not Supported</H1>\n</BODY></HTML>\n",
+ "<HTML><HEAD>\n<TITLE>505 HTTP Version Not Supported</TITLE>\n</HEAD><BODY>\n<H1>HTTP Version Not Supported</H1>\n</BODY></HTML>\n"
+ },
+};
+
+#define NUM_STATUSCODES 37
+
+
+/****** http-error/GetHTTPErrorTableEntry ************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+int GetHTTPErrorTableEntry( int Code )
+{
+ int low;
+ int high;
+ int mid;
+ int check[ NUM_STATUSCODES ];
+ int i;
+
+ low = 0;
+ high = NUM_STATUSCODES - 1;
+ for( i = 0; i < NUM_STATUSCODES; i++ )
+ check[ i ] = 0;
+
+ while( low <= high )
+ {
+ mid = ( low + high ) / 2;
+ if( Code < HTTPErrorTable[mid].Code )
+ {
+ if( check[mid] == 0 )
+ {
+ check[mid] = 1;
+ high = mid - 1;
+ }
+ else
+ return( 0 );
+ }
+ else if( Code > HTTPErrorTable[mid].Code )
+ {
+ if( check[mid] == 0 )
+ {
+ check[mid] = 1;
+ low = mid + 1;
+ }
+ else
+ return( 0 );
+ }
+ else
+ {
+ return( mid );
+ }
+ }
+}
+
+
+/****** http-error/CreateHTTPError *******************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+rc_t CreateHTTPError( int Code, struct HTTPMode *Mode, struct HTTPMsg *Msg )
+{
+ char *Head;
+ char *Buff;
+ size_t BuffSize = BUFFSIZE;
+ char *Body;
+ size_t BodySize;
+ size_t Used;
+
+ int Entry;
+ char Date[DATE_BUFFSIZE];
+
+ bzero( Date, DATE_BUFFSIZE );
+ if( ( Head = (char*)mymalloc( BuffSize ) ) == NULL )
+ {
+ ErrorMsg( E_SYS, ERROR,
+ "ERROR: CreateHTTPError() - malloc() error for head buffer." );
+ return( ERROR );
+ }
+ Buff = Head;
+ BuffSize -= 1;
+
+ HTTP_Date( Date, DATE_BUFFSIZE );
+ Entry = GetHTTPErrorTableEntry( Code );
+ Body = HTTPErrorTable[Entry].Message_en;
+ BodySize = strlen( HTTPErrorTable[Entry].Message_en );
+
+ CreateStatusLine( Buff, &BuffSize, Code, Mode->Protocol );
+ Used = strlen( Head );
+ Buff = Head + Used;
+ BuffSize -= Used;
+ SNPrintf( Buff, &BuffSize,
+ "Date: %s\r\n"
+ "Connection: close\r\n"
+ "%s"
+ "Content-Type: text/html\r\n"
+ "Content-Language: %s\r\n"
+ "Content-Length: %d\r\n\r\n",
+ Date, SERVERFIELD, "en", BodySize );
+
+ Msg->Head = Head;
+ Msg->Body = strdup(Body);
+ Msg->BodySize = BodySize;
+
+ return( OK );
+}
diff --git a/httpserver/http-fields.cc b/httpserver/http-fields.cc
new file mode 100644
index 0000000..76f00f7
--- /dev/null
+++ b/httpserver/http-fields.cc
@@ -0,0 +1,218 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*------------------------------------------------------------------------*/
+/* http-fields.c - get and set HTTP Header fieldnames. */
+/*------------------------------------------------------------------------*/
+
+
+#include "defs.h"
+#include "protos.h"
+#include "server.h"
+#include "http-defs.h"
+#include "http.h"
+
+
+struct KeywordKey FieldnameKeyTable[] =
+{
+ { "Accept" , HKEY_Accept },
+ { "Accept-Charset" , HKEY_Accept_Charset },
+ { "Accept-Encoding" , HKEY_Accept_Encoding },
+ { "Accept-Language" , HKEY_Accept_Language },
+ { "Accept-Ranges" , HKEY_Accept_Ranges },
+ { "Accept-charset" , HKEY_Accept_Charset },
+ { "Accept-encoding" , HKEY_Accept_Encoding },
+ { "Accept-language" , HKEY_Accept_Language },
+ { "Accept-ranges" , HKEY_Accept_Ranges },
+ { "Age" , HKEY_Age },
+ { "Allow" , HKEY_Allow },
+ { "Authorization" , HKEY_Authorization },
+ { "Cache-Control" , HKEY_Cache_Control },
+ { "Cache-control" , HKEY_Cache_Control },
+ { "Compliance" , HKEY_Compliance },
+ { "Connection" , HKEY_Connection },
+ { "Content-Base" , HKEY_Content_Base },
+ { "Content-Encoding" , HKEY_Content_Encoding },
+ { "Content-Language" , HKEY_Content_Language },
+ { "Content-Length" , HKEY_Content_Length },
+ { "Content-Location" , HKEY_Content_Location },
+ { "Content-MD5" , HKEY_Content_MD5 },
+ { "Content-Range" , HKEY_Content_Range },
+ { "Content-Type" , HKEY_Content_Type },
+ { "Content-base" , HKEY_Content_Base },
+ { "Content-encoding" , HKEY_Content_Encoding },
+ { "Content-language" , HKEY_Content_Language },
+ { "Content-length" , HKEY_Content_Length },
+ { "Content-location" , HKEY_Content_Location },
+ { "Content-range" , HKEY_Content_Range },
+ { "Content-type" , HKEY_Content_Type },
+ { "Date" , HKEY_Date },
+ { "ETag" , HKEY_ETag },
+ { "Expect" , HKEY_Expect },
+ { "Expires" , HKEY_Expires },
+ { "From" , HKEY_From },
+ { "Host" , HKEY_Host },
+ { "If-Modified-Since" , HKEY_If_Modified_Since },
+ { "If-Match" , HKEY_If_Match },
+ { "If-None-Match" , HKEY_If_None_Match },
+ { "If-Range" , HKEY_If_Range },
+ { "If-Unmodified-Since" , HKEY_If_Unmodified_Since },
+ { "Keep-Alive" , HKEY_Keep_Alive },
+ { "Last-Modified" , HKEY_Last_Modified },
+ { "Location" , HKEY_Location },
+ { "Max-Forwards" , HKEY_Max_Forwards },
+ { "Non-Compliance" , HKEY_Non_Compliance },
+ { "Pragma" , HKEY_Pragma },
+ { "Proxy-Authenticate" , HKEY_Proxy_Authenticate },
+ { "Proxy-Authorization" , HKEY_Proxy_Authorization },
+ { "Public" , HKEY_Public },
+ { "Range" , HKEY_Range },
+ { "Referer" , HKEY_Referer },
+ { "Retry-After" , HKEY_Retry_After },
+ { "Server" , HKEY_Server },
+ { "Set-Proxy" , HKEY_Set_Proxy },
+ { "Transfer-Encoding" , HKEY_Transfer_Encoding },
+ { "Upgrade" , HKEY_Upgrade },
+ { "User-Agent" , HKEY_User_Agent },
+ { "Vary" , HKEY_Vary },
+ { "WWW-Authenticate" , HKEY_WWW_Authenticate },
+ { "Warning" , HKEY_Warning },
+};
+
+#define NUM_FIELDS 62
+
+
+/****** http-fields/HTTP_GetHKey *********************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+int HTTP_GetHKey( char *Keyword )
+{
+ int cond;
+ int low;
+ int high;
+ int mid;
+ int check[ NUM_FIELDS ];
+ int i;
+
+ low = 0;
+ high = NUM_FIELDS - 1;
+ for( i = 0; i < NUM_FIELDS; i++ )
+ check[ i ] = 0;
+
+ while( low <= high )
+ {
+ mid = ( low + high ) / 2;
+ if( ( cond = strcmp( Keyword, FieldnameKeyTable[mid].Keyword ) ) < 0 )
+ {
+ if( check[mid] == 0 )
+ {
+ check[mid] = 1;
+ high = mid - 1;
+ }
+ else
+ return( HKEY_UNKNOWN );
+ }
+ else if( cond > 0 )
+ {
+ if( check[mid] == 0 )
+ {
+ check[mid] = 1;
+ low = mid + 1;
+ }
+ else
+ return( HKEY_UNKNOWN );
+ }
+ else
+ return( FieldnameKeyTable[mid].Key );
+ }
+ return( HKEY_UNKNOWN );
+}
+
+
+/****** http-fields/HTTP_GetFieldName ****************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+char *HTTP_GetFieldName( int Key )
+{
+ int i;
+
+ for( i = 0; i < NUM_FIELDS; i++ )
+ {
+ if( FieldnameKeyTable[i].Key == Key )
+ return( FieldnameKeyTable[i].Keyword );
+ }
+ return( NULL );
+}
diff --git a/httpserver/http-methods.cc b/httpserver/http-methods.cc
new file mode 100644
index 0000000..4a99f71
--- /dev/null
+++ b/httpserver/http-methods.cc
@@ -0,0 +1,163 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*------------------------------------------------------------------------*/
+/* http-methods.c - get and set HTTP Method names. */
+/*------------------------------------------------------------------------*/
+
+
+#include "defs.h"
+#include "protos.h"
+#include "server.h"
+#include "http-defs.h"
+#include "http.h"
+
+#include <ctype.h>
+
+struct KeywordKey MethodKeyTable[] =
+{
+ { "GET", MKEY_GET },
+ { "HEAD", MKEY_HEAD },
+ { "PUT", MKEY_PUT },
+ { "POST", MKEY_POST },
+ { "DELETE", MKEY_DELETE },
+ { "OPTIONS", MKEY_OPTIONS },
+ { "TRACE", MKEY_TRACE },
+};
+
+
+/****** http-methods/HTTP_GetMKey ********************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+int HTTP_GetMKey( char *Keyword )
+{
+ int cond;
+ int low;
+ int high;
+ int mid;
+ int check[ NUM_MKEYS ];
+ int i;
+
+ low = 0;
+ high = NUM_MKEYS - 1;
+ for( i = 0; i < NUM_MKEYS; i++ )
+ check[ i ] = 0;
+ if( !isalpha( *Keyword ) )
+ return( MKEY_NONE );
+ while( low <= high )
+ {
+ mid = ( low + high ) / 2;
+ if( ( cond = strcmp( Keyword, MethodKeyTable[mid].Keyword ) ) < 0 )
+ {
+ if( check[mid] == 0 )
+ {
+ check[mid] = 1;
+ high = mid - 1;
+ }
+ else
+ return( MKEY_UNKNOWN );
+ }
+ else if( cond > 0 )
+ {
+ if( check[mid] == 0 )
+ {
+ check[mid] = 1;
+ low = mid + 1;
+ }
+ else
+ return( MKEY_UNKNOWN );
+ }
+ else
+ return( MethodKeyTable[mid].Key );
+ }
+ return( MKEY_UNKNOWN );
+}
+
+
+/****** http-methods/HTTP_GetMethodName **************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+char *HTTP_GetMethodName( int Key )
+{
+ int i;
+
+ for( i = 0; i < NUM_MKEYS; i++ )
+ {
+ if( MethodKeyTable[i].Key == Key )
+ return( MethodKeyTable[i].Keyword );
+ }
+ return( NULL );
+}
diff --git a/httpserver/http-readmsg.cc b/httpserver/http-readmsg.cc
new file mode 100644
index 0000000..da88274
--- /dev/null
+++ b/httpserver/http-readmsg.cc
@@ -0,0 +1,1014 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#include "mymalloc/mymalloc.h"
+/*------------------------------------------------------------------------*/
+/* http-readmsg.c - generic HTTP-Message functions: */
+/* Reading and parsing of HTTP-Messages. */
+/*------------------------------------------------------------------------*/
+/* Comments: */
+/* - Status: */
+/* - Missing symbolic constant BUFFBLOCK_SIZE. */
+/* - To check: All Buffers free()ed? Also in error cases? */
+/* - ParseReqLine()/ParseRespLine() use static buffers, but */
+/* they are protected against overwriting. */
+/*------------------------------------------------------------------------*/
+
+
+#include "defs.h"
+#include "protos.h"
+#include "server.h"
+#include "http-defs.h"
+#include "http.h"
+
+
+/****** http-readmsg/ReadHeader **********************************************
+*
+* NAME
+* ReadHeader -- Read a HTTP message header from a socket.
+*
+* SYNOPSIS
+* char *ReadHeader( int SockFD, size_t *size );
+*
+* FUNCTION
+* This function reads from the socket descriptor "SockFD" until it
+* detects an empty line (two <CR><LF> sequences in a row). Every read
+* character is stored in a buffer, which is dynamically allocated.
+* If the empty line is detected, it returns a pointer to the buffer
+* and the variable "*size" contains the buffersize.
+*
+* INPUTS
+* SockFD - The socket descriptor to read from.
+* size - A pointer to a variable which may hold the size of the buffer
+* which contains the message header.
+*
+* RESULT
+* A pointer a buffer with the HTTP message header.
+*
+* NOTES
+* The function checks for errors returned by the "read()" system call.
+* Other problems ("out-of-band" data, socket errors) are not checked.
+*
+******************************************************************************
+*
+*/
+
+int ReadHeader( int SockFD, char **Buffer, size_t *BuffSize )
+{
+ size_t BuffBlock = 1024;
+ size_t minbuff = 2;
+ size_t nread = 0;
+ size_t sumread = 0;
+ char *Ptr;
+ int check_eol = 0;
+ int error = FALSE;
+ int elapsed = 0;
+
+ for(;;)
+ {
+ if( *BuffSize - sumread < minbuff )
+ {
+ *BuffSize += BuffBlock;
+ *Buffer = (char*)realloc( *Buffer, *BuffSize );
+ if( *Buffer == NULL )
+ {
+ ErrorMsg( E_SYS, ERROR, "ERROR: ReadHeader(): malloc() failed." );
+ error = TRUE;
+ break;
+ }
+ bzero( *Buffer, *BuffSize );
+ }
+
+ Ptr = *Buffer + sumread;
+ nread = read( SockFD, Ptr, 1 );
+ if( nread == 1 )
+ {
+ elapsed = 0; /* Clear timeout counter */
+ sumread++;
+ if( *Ptr == '\n' ) /* Check for two consecutive "\r\n" */
+ {
+ if( check_eol == 1 )
+ break; /* if found => End-Of-Header */
+ else
+ check_eol = 1;
+ }
+ else if( *Ptr != '\r' )
+ check_eol = 0;
+ }
+ else if( nread == 0 )
+ {
+ if( elapsed >= 30 )
+ {
+ ErrorMsg( E_PRIV, ERROR, "ERROR: ReadHeader() timed out." );
+ error = TRUE;
+ break;
+ }
+ sleep(1);
+ elapsed++;
+ }
+ else
+ {
+ if( errno != EAGAIN )
+ {
+ ErrorMsg( E_SYS, ERROR, "ERROR: ReadHeader(): read() failed." );
+ error = TRUE;
+ break;
+ }
+ else
+ {
+ sleep( elapsed );
+ if( elapsed >= 30 )
+ {
+ ErrorMsg( E_PRIV, ERROR, "ERROR: ReadHeader() timed out." );
+ error = TRUE;
+ break;
+ }
+ sleep(1);
+ elapsed++;
+ }
+ }
+ }
+ if( error == TRUE )
+ {
+ if( *Buffer != NULL )
+ free( *Buffer );
+ *Buffer = NULL;
+ *BuffSize = 0;
+ return( RI_READ_ERROR );
+ }
+ else
+ return( RI_READ_OK );
+}
+
+
+/****** http-readmsg/ReadBody ************************************************
+*
+* NAME
+* ReadBody -- Read a HTTP message body from a socket.
+*
+* SYNOPSIS
+* char *ReadBody( int SockFD, size_t BuffSize );
+*
+* FUNCTION
+* This functions reads the HTTP message body with the size "BuffSize"
+* from the socket "SockFD". A buffer for the message body is allocated
+* within this function and a pointer to this buffer is returned.
+*
+* INPUTS
+* SockFD - The socket descriptor to read from.
+* BuffSize - The size of the message body.
+*
+* RESULT
+* A pointer to the buffer which contains the message body.
+*
+* NOTES
+* The function checks for errors returned by the "read()" system call.
+* Other problems ("out-of-band" data, socket errors) are not checked.
+*
+******************************************************************************
+*
+*/
+
+char *ReadBody( int SockFD, size_t BuffSize )
+{
+ int nread = 0;
+ char *Buffer = NULL;
+
+ if( ( Buffer = (char*)mymalloc( BuffSize + 1 ) ) == NULL )
+ {
+ ErrorMsg( E_SYS, ERROR, "ERROR: malloc error for HTTP-Body buffer." );
+ return( Buffer );
+ }
+ bzero( Buffer, BuffSize + 1);
+ nread = ReadN( SockFD, Buffer, BuffSize );
+ if( nread < 0 )
+ {
+ ErrorMsg( E_SYS, ERROR, "ERROR: ReadBody(): read() failed." );
+ free( Buffer );
+ Buffer = NULL;
+ return( Buffer );
+ }
+ else if( nread < BuffSize )
+ {
+ ErrorMsg( E_PRIV, WARN, "WARN: MessageBody not of expected size." );
+ }
+ return( Buffer );
+}
+
+
+/****** http-readmsg/ParseReqHeader ******************************************
+*
+* NAME
+* ParseReqHeader - Parse the HTTP request header.
+*
+* SYNOPSIS
+* rc_t ParseReqHeader( struct ReqInfo *Request );
+*
+* FUNCTION
+* This is the main function for parsing the HTTP request headers.
+* It first calls "ParseReqLine()" to actually parse the "Request
+* Line" (the first line of an HTTP request) and then calls
+* subsequently "ParseMsgLine()" for every non-empty line following
+* the request-line.
+*
+* The results of this parsing process are stored in a data structure
+* of the type "ReqInfo", which is later used for searching in and
+* reconstructing of the header informations.
+*
+* INPUTS
+* Request - A pointer to a data structure of the type ReqInfo.
+*
+* RESULT
+* Returns "OK" if everything went well.
+*
+* BUGS
+* It doesn't check if "Request" is a NULL pointer.
+*
+* SEE ALSO
+* ParseRespHeader(), ParseReqLine(), ParseMsgLine().
+*
+******************************************************************************
+*
+*/
+
+rc_t ParseReqHeader( struct ReqInfo *Request )
+{
+ char *Buffer;
+ char *Param;
+ int Key;
+ struct MsgHeader *Header;
+
+ Header = NULL;
+ Buffer = Request->HeadBuff;
+ if( Request->State == RI_READ_OK )
+ {
+ Buffer = ParseReqLine( Buffer, Request );
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: *** Parsed Req %s", Buffer );
+ if( Request->State == RI_PARSE_ERROR )
+ return( WARN );
+ }
+ else
+ {
+ Request->State = RI_PARSE_ERROR;
+ return( WARN );
+ }
+
+ while( Buffer != NULL && *Buffer != '\0' )
+ {
+ Key = -1;
+ Param = NULL;
+ Buffer = ParseMsgLine( Buffer, &Key, &Param );
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: *** Parsed Msg %s", Buffer );
+ if( Buffer != NULL )
+ {
+ Header = AppendMsgHeader( Request->Last, Key, Param );
+ Request->Last = Header;
+ }
+ if( Request->First == NULL )
+ Request->First = Header;
+ }
+ if( Request->First == NULL )
+ {
+ Request->State = RI_PARSE_WARN;
+ return( WARN );
+ }
+ else
+ {
+ Request->State = RI_PARSE_OK;
+ return( OK );
+ }
+}
+
+
+/****** http-readmsg/ParseRespHeader *****************************************
+*
+* NAME
+* ParseRespHeader - Parse the HTTP response header.
+*
+* SYNOPSIS
+* rc_t ParseRespHeader( struct RespInfo *Response );
+*
+* FUNCTION
+* This is the main function for parsing the HTTP response headers.
+* It first calls "ParseRespLine()" to actually parse the "Response
+* Line" (the first line of an HTTP response) and then calls
+* subsequently "ParseMsgLine()" for every non-empty line following
+* the request-line.
+*
+* The results of this parsing process are stored in a data structure
+* of the type "RespInfo", which is later used for searching in and
+* reconstructing of the header informations.
+*
+* INPUTS
+* Response - A pointer to a data structure of the type RespInfo.
+*
+* RESULT
+* Returns "OK" if everything went well.
+*
+* BUGS
+* Actually, it always returns an "OK" status code.
+* It doesn't check if "Response" is a NULL pointer.
+*
+* SEE ALSO
+* ParseReqHeader(), ParseRespLine(), ParseMsgLine().
+*
+******************************************************************************
+*
+*/
+
+rc_t ParseRespHeader( struct RespInfo *Response )
+{
+ char *Buffer;
+ char *Keyword;
+ char *Param;
+ size_t i;
+ int Key;
+ struct MsgHeader *Header;
+
+ Header = NULL;
+ Buffer = Response->HeadBuff;
+ Buffer = ParseRespLine( Buffer, Response );
+
+ while( Buffer != NULL )
+ {
+ Key = -1;
+ Param = NULL;
+ Buffer = ParseMsgLine( Buffer, &Key, &Param );
+ if( Buffer != NULL )
+ {
+ Header = AppendMsgHeader( Response->Last, Key, Param );
+ Response->Last = Header;
+ }
+ if( Response->First == NULL )
+ Response->First = Header;
+ }
+ return( OK );
+}
+
+
+/****** http-readmsg/ParseReqLine ********************************************
+*
+* NAME
+* ParseReqLine - Parse the HTTP request line.
+*
+* SYNOPSIS
+* char *ParseReqLine( char *Buffer, struct ReqInfo *Request );
+*
+* FUNCTION
+* This function parses the beginning of the buffer "Buffer" for the
+* contents of a HTTP request line. Since the parsing process (as
+* implemented here) is destructive to the original string, the buffer
+* is first scanned for a <CR><LF> sequence (end-of-line mark of a
+* HTTP message) while copying any other character encountered to a
+* secondary buffer. This "Backup" of the request line is later used
+* for logging purposes, so it can be referred to in case of a problem.
+*
+* Then the request line is parsed and broken up in its components, as
+* they are: Request method, URL, protocol-id and version. These are
+* stored in the appropriate places in a "ReqInfo" data structure.
+*
+* INPUTS
+* Buffer - A pointer to the raw data of a HTTP request.
+* Request - A pointer to a data structure of the type ReqInfo.
+*
+* RESULT
+* A pointer into the buffer, pointing to the rest of the data to be
+* processed.
+*
+* BUGS
+* "Buffer" and "Request" are not checked for NULL pointers.
+* The "Backup" of the request line has a maximum length of
+* "MAXLINELEN".
+*
+* SEE ALSO
+* ParseRespLine().
+*
+******************************************************************************
+*
+*/
+
+char *ParseReqLine( char *Buffer, struct ReqInfo *Request )
+{
+ char Tmp[ MAXLINELEN ];
+ char *NewBuffer;
+ char *Ptr;
+ char *Keyword;
+ char *URL = NULL;
+ char *PVersion = NULL;
+ int Key = 0;
+ int PVmaj = -1;
+ int PVmin = -1;
+ int i;
+ int eol_found = FALSE;
+
+ Keyword = Buffer;
+
+ for( Ptr = Buffer, i = 0; i < MAXLINELEN; Ptr++, i++ )
+ {
+ if( *Ptr == '\r')
+ Tmp[i] = '\0';
+ else if( *Ptr == '\n' )
+ {
+ Tmp[i] = '\0';
+ eol_found = TRUE;
+ break;
+ }
+ else
+ Tmp[i] = *Ptr;
+ }
+ Tmp[i+1] = '\0';
+ if( eol_found != TRUE )
+ {
+ Request->State = RI_PARSE_ERROR;
+ return( NULL );
+ }
+
+ for( Ptr = Buffer; *Ptr != '\n'; Ptr++ )
+ {
+ if( *Ptr == ' ' )
+ {
+ if( URL == NULL )
+ {
+ *Ptr = '\0';
+ URL = ++Ptr;
+ }
+ else
+ {
+ *Ptr = '\0';
+ ++Ptr;
+ if( strcmp( "HTTP/", Ptr ) )
+ {
+ Ptr += 5;
+ PVersion = Ptr;
+ }
+ }
+ }
+ else if( *Ptr == '\r' )
+ {
+ *Ptr = '\0';
+ }
+ }
+ *Ptr = '\0';
+ NewBuffer = ++Ptr;
+
+ if( PVersion != NULL )
+ {
+ for( Ptr = PVersion; *Ptr != '\0'; Ptr++ )
+ {
+ if( *Ptr == '.' )
+ {
+ *Ptr = '\0';
+ ++Ptr;
+ break;
+ }
+ }
+ PVmaj = strtol( PVersion, NULL, 10 );
+ PVmin = strtol( Ptr, NULL, 10 );
+ }
+
+ if( URL != NULL )
+ {
+ Request->Line.Vanilla = (char*)mymalloc( strlen( Tmp ) + 1 );
+ Request->Line.Method = HTTP_GetMKey( Keyword );
+ // SplitURL( URL, &Request->Line.URL );
+ Request->Line.URL.Path = URL;
+ Request->Line.Version.Major = PVmaj;
+ Request->Line.Version.Minor = PVmin;
+ strcpy( Request->Line.Vanilla, Tmp );
+ Request->State = RI_PARSE_OK;
+ return( NewBuffer );
+ }
+ else
+ {
+ Request->State = RI_PARSE_ERROR;
+ return( NULL );
+ }
+}
+
+
+/****** http-readmsg/ParseRespLine *******************************************
+*
+* NAME
+* ParseRespLine - Parse the HTTP response line.
+*
+* SYNOPSIS
+* char *ParseRespLine( char *Buffer, struct RespInfo *Response );
+*
+* FUNCTION
+* This function parses the beginning of the buffer "Buffer" for the
+* contents of a HTTP response line. Since the parsing process (as
+* implemented here) is destructive to the original string, the buffer
+* is first scanned for a <CR><LF> sequence (end-of-line mark of a
+* HTTP message) while copying any other character encountered to a
+* secondary buffer. This "Backup" of the response line is later used
+* for logging purposes, so it can be referred to in case of a problem.
+*
+* Then the response line is parsed and broken up in its components, as
+* they are: Protocol-id and version, (numeric) status code and
+* "reason phrase". These are stored in the appropriate places in a
+* "RespInfo" data structure.
+*
+* INPUTS
+* Buffer - A pointer to the raw data of a HTTP request.
+* Response - A pointer to a data structure of the type RespInfo.
+*
+* RESULT
+* A pointer into the buffer, pointing to the rest of the data to be
+* processed.
+*
+* BUGS
+* "Buffer" and "Response" are not checked for NULL pointers.
+* The "Backup" of the response line has a maximum length of
+* "MAXLINELEN".
+*
+* SEE ALSO
+* ParseReqLine().
+*
+******************************************************************************
+*
+*/
+
+char *ParseRespLine( char *Buffer, struct RespInfo *Response )
+{
+ char Tmp[ MAXLINELEN ];
+ char *Ptr;
+ char *Reason = NULL;
+ char *PVersion = NULL;
+ char *Status = NULL;
+ char *PVmaj = NULL;
+ char *PVmin = NULL;
+ int i;
+
+ for( Ptr = Buffer, i = 0; i <= MAXLINELEN - 1; Ptr++, i++ )
+ {
+ if( *Ptr == '\r')
+ Tmp[i] = '\0';
+ else if( *Ptr == '\n' )
+ {
+ Tmp[i] = '\0';
+ break;
+ }
+ else
+ Tmp[i] = *Ptr;
+ }
+ Tmp[i+1] = '\0';
+
+ Response->Line.Vanilla = (char*)mymalloc( strlen( Tmp ) + 1 );
+ strcpy( Response->Line.Vanilla, Tmp );
+
+ if( strcmp( "HTTP/", Buffer ) )
+ {
+ PVmaj = Buffer + 5;
+ for( Ptr = PVmaj; *Ptr != ' '; Ptr++ )
+ {
+ if( *Ptr == '.' )
+ {
+ *Ptr = '\0';
+ PVmin = ++Ptr;
+ }
+ }
+ *Ptr = '\0';
+ Response->Line.Version.Major = strtol( PVmaj, NULL, 10 );
+ Response->Line.Version.Minor = strtol( PVmin, NULL, 10 );
+ }
+ else
+ return( NULL );
+
+ Status = ++Ptr;
+ while( *Ptr != ' ' )
+ Ptr++;
+ *Ptr = '\0';
+ Response->Line.Status = strtol( Status, NULL, 10 );
+
+ Ptr++;
+ Response->Line.Reason = Ptr;
+
+ while( *Ptr != '\n' )
+ {
+ if( *Ptr == '\r' )
+ *Ptr = '\0';
+ Ptr++;
+ }
+ *Ptr = '\0';
+
+ return( ++Ptr );
+}
+
+
+/****** http-readmsg/ParseMsgLine ********************************************
+*
+* NAME
+* ParseMsgLine - Parse a HTTP message header line.
+*
+* SYNOPSIS
+* char *ParseMsgLine( char *Buffer, int *Key, char **Param );
+*
+* FUNCTION
+* This function parses a HTTP message header field into the
+* components field name and field content ("value" of this field).
+* The appropriate token for the field name is stored in the variable
+* where "Key" points to and "Param" points to the field content
+* string.
+*
+* INPUTS
+* Buffer - A pointer to the raw data of a HTTP request.
+* Key - A pointer to a variable which will store the field name token.
+* Param - A pointer to a character pointer, which will refer to
+* the field content string.
+*
+* RESULT
+* A pointer into the buffer, pointing to the rest of the data to be
+* processed.
+*
+* NOTES
+* In case of unknown field names, the field content string will
+* contain not only the value of the field, instead it will contain the
+* complete header line.
+*
+* BUGS
+* "Buffer", "Key" and "Param" are not checked against NULL pointers.
+*
+******************************************************************************
+*
+*/
+
+char *ParseMsgLine( char *Buffer, int *Key, char **Param )
+{
+ char *Keyword;
+ char *Ptr;
+ int HaveKey = FALSE;
+
+ if( ( *Buffer == ' ' ) || ( *Buffer == '\t' ) )
+ {
+ *Key = HKEY_CONTINUE;
+ *Param = Buffer;
+
+ for( Ptr = Buffer; *Ptr != '\n'; Ptr++ )
+ {
+ if( *Ptr == '\r' )
+ *Ptr = '\0';
+ else if( *Ptr == '\0' )
+ break;
+ }
+ *Ptr = '\0';
+ return( ++Ptr );
+ }
+
+ Keyword = Buffer;
+ for( Ptr = Buffer; *Ptr != '\n'; Ptr++ )
+ {
+ if( *Ptr == ':' )
+ {
+ if( HaveKey == FALSE )
+ {
+ HaveKey = TRUE;
+ *Ptr = '\0';
+ *Key = HTTP_GetHKey( Keyword );
+ if( *Key != HKEY_UNKNOWN )
+ {
+ Ptr++;
+ while( ( *Ptr == ' ' ) || ( *Ptr == '\t' ) )
+ ++Ptr;
+ *Param = Ptr;
+ }
+ else
+ {
+ *Ptr = ':';
+ *Param = Buffer;
+ }
+ }
+ }
+ else if( *Ptr == '\r' )
+ *Ptr = '\0';
+ else if( *Ptr == '\0' )
+ break;
+ }
+ *Ptr = '\0';
+
+ if( *Key == -1 || HaveKey == FALSE )
+ return( NULL );
+ else
+ return( ++Ptr );
+}
+
+
+/****** http-readmsg/splitURL ************************************************
+*
+* NAME
+* splitURL - break up an URL string into its components.
+*
+* SYNOPSIS
+* void splitURL( char *Buffer, struct URLComps *URL );
+*
+* FUNCTION
+* This function searches in a linked list of "MsgHeader" elements
+* for one with a "Content_Length" token, and returns the integer
+* value of it.
+*
+* INPUTS
+* Buffer - the URL string.
+* URL - a pointer to structure, which holds the pointers to the
+* the strings of the components.
+*
+* RESULT
+* If the creation of a buffer for the components fails, all components
+* of URL will have NULL pointers. If no protocol is found in Buffer,
+* URL->Path will contain the complete contents of Buffer (it is
+* assumed that Buffer conatins a relative URL). In this case
+* URL->Extra whill always be NULL.
+* URL->Servername may be NULL, if there was no Servername separator
+* ("//") found - this may be the case for URLs pointing to "this"
+* Server ("localhost").
+*
+******************************************************************************
+*
+*/
+
+void SplitURL( char *Buffer, struct URLComps *URL )
+{
+ char *NewBuffer;
+ size_t BuffSize;
+ char *Ptr1;
+ char *Ptr2;
+ char *Tmp;
+ int HaveProto = FALSE;
+ int CheckSep = FALSE;
+ int HaveServer = FALSE;
+ int HavePath = FALSE;
+ int HaveExtra = FALSE;
+
+ BuffSize = strlen( Buffer ) + 4;
+ NewBuffer = (char*)mymalloc( BuffSize );
+ if( NewBuffer != NULL )
+ {
+ bzero( NewBuffer, BuffSize );
+ Tmp = NewBuffer;
+ for( Ptr1 = Buffer, Ptr2 = NewBuffer; Ptr1 <= Buffer + BuffSize; Ptr1++, Ptr2++ )
+ {
+ if( HaveProto == FALSE )
+ {
+ if( *Ptr1 == ':' )
+ {
+ HaveProto = TRUE;
+ URL->Protocol = Tmp;
+ Tmp = Ptr2 + 1;
+ }
+ else
+ {
+ *Ptr2 = *Ptr1;
+ }
+ }
+ else if( CheckSep == FALSE )
+ {
+ CheckSep = TRUE;
+ if( *Ptr1 == '/' && *(Ptr1+1) == '/' )
+ {
+ Ptr1++;
+ }
+ else
+ {
+ HaveServer = TRUE;
+ URL->Servername = NULL;
+ Ptr1--;
+ }
+ }
+ else if( HaveServer == FALSE )
+ {
+ if( *Ptr1 == '/' )
+ {
+ HaveServer = TRUE;
+ URL->Servername = Tmp;
+ Tmp = Ptr2 + 1;
+ Ptr1--;
+ }
+ else
+ {
+ *Ptr2 = *Ptr1;
+ }
+ }
+ else if( HavePath == FALSE )
+ {
+ if( *Ptr1 == '#' || *Ptr1 == '?' )
+ {
+ HavePath = TRUE;
+ URL->Path = Tmp;
+ Tmp = Ptr2 + 1;
+ Ptr1--;
+ }
+ else
+ {
+ *Ptr2 = *Ptr1;
+ }
+ }
+ else
+ {
+ if( HaveExtra == FALSE )
+ {
+ HaveExtra = TRUE;
+ URL->Extra = Tmp;
+ }
+ *Ptr2 = *Ptr1;
+ }
+ }
+ if( HaveProto == FALSE )
+ {
+ URL->Path = Tmp;
+ }
+ }
+ else
+ {
+ URL->Protocol = NULL;
+ URL->Servername = NULL;
+ URL->Path = NULL;
+ URL->Extra = NULL;
+ }
+
+ return;
+}
+
+
+/****** http-readmsg/GetContentLength ****************************************
+*
+* NAME
+* GetContentLength - search for the "Content-Length" header in a HTTP
+* message and return the value if found.
+*
+* SYNOPSIS
+* size_t GetContentLength( struct MsgHeader *Ptr );
+*
+* FUNCTION
+* This function searches in a linked list of "MsgHeader" elements
+* for one with a "Content_Length" token, and returns the integer
+* value of it.
+*
+* INPUTS
+* Ptr - A pointer to a "MsgHeader" node.
+*
+* RESULT
+* 0 if no "Content-Length" header is found, otherwise the value of
+* this message header converted into an integer (more precisely: the
+* return value of "strtol()").
+*
+* BUGS
+* The return value of "strtol()" should maybe checked for proper
+* results.
+*
+* SEE ALSO
+* GetFieldContent().
+*
+******************************************************************************
+*
+*/
+
+size_t GetContentLength( struct MsgHeader *Ptr )
+{
+ while( Ptr != NULL )
+ {
+ if( Ptr->Field == HKEY_Content_Length )
+ return( strtol( Ptr->Content, NULL, 10 ) );
+ Ptr = Ptr->Next;
+ }
+ return( 0 );
+}
+
+
+/****** http-readmsg/GetFieldContent *****************************************
+*
+* NAME
+* GetFieldContent - Return the content of a specific message header.
+*
+* SYNOPSIS
+* char *GetFieldContent( struct MsgHeader *Ptr, int Field,
+* struct MsgHeader **Next );
+*
+* FUNCTION
+* This function searches in a linked list of "MsgHeader" elements
+* for one with the token in the argument "Field", and returns the
+* value of it.
+*
+* INPUTS
+* Ptr - A pointer to a "MsgHeader" node.
+* Field - The token of the field to search for.
+* Next - A pointer to the next "MsgHeader" in the list.
+*
+* RESULT
+* NULL if the header is not found, otherwise a pointer to the content
+* string.
+*
+* SEE ALSO
+* GetContentLength().
+*
+******************************************************************************
+*
+*/
+
+char *GetFieldContent( struct MsgHeader *Ptr, int Field, struct MsgHeader **Next )
+{
+ while( Ptr != NULL )
+ {
+ if( Ptr->Field == Field )
+ {
+ if( Next != NULL )
+ *Next = Ptr->Next;
+ return( Ptr->Content );
+ }
+ Ptr = Ptr->Next;
+ }
+ return( NULL );
+}
+
+
+/****** http-readmsg/GetRealm ************************************************
+*
+* NAME
+* GetRealm - Search for specific Authentication realms.
+*
+* SYNOPSIS
+* int GetRealm( char *String );
+*
+* FUNCTION
+* This function searches in the "WWW-Authenticate" header for specific
+* authentication realm strings. If one of them is found, the
+* appropriate code for this realm is returned.
+*
+* INPUTS
+* String - A pointer to the contents of the "WWW-Authenticate" header
+* field.
+*
+* RESULT
+* A realm type code.
+*
+* BUGS
+* "String" is not checked against a NULL pointer.
+*
+******************************************************************************
+*
+*/
+
+int GetRealm( char *String )
+{
+ struct KeywordKey RealmKeyTable[] =
+ {
+ { "httpserver-IPClass-A", REALM_IPCLASS_A },
+ { "httpserver-IPClass-B", REALM_IPCLASS_B },
+ { "httpserver-IPClass-C", REALM_IPCLASS_C },
+ { "httpserver-IPAddress", REALM_IPADDRESS },
+ { "httpserver-Hostname", REALM_HOSTNAME },
+ { "httpserver-Domain", REALM_DOMAIN },
+ };
+#define NUM_REALMS 6
+
+ char *Buff;
+ char *Ptr;
+ char *Tmp;
+ int i;
+
+ Ptr = String;
+ if( ( strncasecmp( "realm=", Ptr, 6 ) == 0 ) )
+ {
+ Ptr = Ptr + 6;
+ if( ( Buff = (char*)mymalloc( strlen( Ptr ) + 1 ) ) == NULL )
+ return( REALM_ERROR );
+ strcpy( Buff, Ptr );
+
+ /* Kill Quotes... */
+ if( *Ptr == '"' )
+ {
+ Ptr++;
+ Tmp = strrchr( Ptr, '"' );
+ if( Tmp != NULL )
+ *Tmp = '\0';
+ }
+ for( i = 0; i < NUM_REALMS; i++ )
+ {
+ if( strcmp( RealmKeyTable[i].Keyword, Ptr ) == 0 )
+ {
+ free( Buff );
+ return( RealmKeyTable[i].Key );
+ }
+ }
+ return( REALM_UNKNOWN );
+ }
+ else
+ return( REALM_ERROR );
+}
diff --git a/httpserver/http-support.cc b/httpserver/http-support.cc
new file mode 100644
index 0000000..c4a03b4
--- /dev/null
+++ b/httpserver/http-support.cc
@@ -0,0 +1,503 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include "mymalloc/mymalloc.h"
+/*------------------------------------------------------------------------*/
+/* http-support.c - Support functions for HTTP-Message data. */
+/*------------------------------------------------------------------------*/
+/* Comments: */
+/* - Status: */
+/* - To check: All Buffers free()ed? Also in error cases? */
+/*------------------------------------------------------------------------*/
+/*
+ * RCS:
+ * $RCSfile: http-support.c,v $ $Revision: 1.5 $ $State: Exp $
+ * $Locker: $
+ */
+
+
+#include "defs.h"
+#include "protos.h"
+#include "server.h"
+#include "http-defs.h"
+#include "http.h"
+
+
+
+/****** http-support/InitClientBase ******************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+rc_t InitClientBase( struct ClientBase *Client )
+{
+ return( ERROR );
+}
+
+
+/****** http-support/InitReqInfo *********************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+rc_t InitReqInfo( struct ReqInfo *Request )
+{
+ Request->HeadBuff = NULL;
+ Request->HeadSize = 0;
+ Request->BodyBuff = NULL;
+ Request->BodySize = 0;
+ Request->Line.Method = 0;
+ Request->Line.URL.Protocol = NULL;
+ Request->Line.URL.Servername = NULL;
+ Request->Line.URL.Path = NULL;
+ Request->Line.URL.Extra = NULL;
+ Request->Line.Version.Major = 0;
+ Request->Line.Version.Minor = 0;
+ Request->First = NULL;
+ Request->Last = NULL;
+ Request->Body = NULL;
+ return( OK );
+}
+
+
+/****** http-support/InitRespInfo ********************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+rc_t InitRespInfo( struct RespInfo *Response )
+{
+ Response->HeadBuff = NULL;
+ Response->HeadSize = 0;
+ Response->BodyBuff = NULL;
+ Response->BodySize = 0;
+ Response->Line.Version.Major = 0;
+ Response->Line.Version.Minor = 0;
+ Response->Line.Status = 0;
+ Response->Line.Reason = NULL;
+ Response->First = NULL;
+ Response->Last = NULL;
+ Response->Body = NULL;
+ return( OK );
+}
+
+
+/****** http-support/InitHTTPMsg *********************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+void InitHTTPMsg( struct HTTPMsg *Msg )
+{
+ Msg->Head = NULL;
+ Msg->Body = NULL;
+ Msg->BodySize = 0;
+}
+
+
+/****** http-support/NewMsgHeader ********************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+struct MsgHeader *NewMsgHeader( int Key, char *String )
+{
+ struct MsgHeader *NewHeader;
+
+ NewHeader = (struct MsgHeader*)mymalloc( sizeof( struct MsgHeader ) );
+ if( NewHeader == NULL )
+ return( NULL );
+ NewHeader->Next = NULL;
+ NewHeader->Field = Key;
+ NewHeader->Content = String;
+ return( NewHeader );
+}
+
+
+/****** http-support/AppendMsgHeader *****************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+struct MsgHeader *AppendMsgHeader( struct MsgHeader *Last, int Key, char *String )
+{
+ struct MsgHeader *NewHeader;
+
+ NewHeader = NewMsgHeader( Key, String );
+ if( NewHeader == NULL )
+ {
+ ErrorMsg( E_SYS, ERROR, "ERROR: malloc error for MsgHeader structure." );
+ return( NULL );
+ }
+ if( Last != NULL )
+ {
+ Last->Next = NewHeader;
+ }
+ return( NewHeader );
+}
+
+
+/****** http-support/DeleteMsgHeader *****************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+void DeleteMsgHeader( struct MsgHeader *First )
+{
+ struct MsgHeader *Tmp;
+
+ if( First != NULL )
+ {
+ Tmp = First->Next;
+ free( First );
+ First = Tmp;
+ }
+ return;
+}
+
+
+/****** http-support/PrintReqInfo ********************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+void PrintReqInfo( struct ReqInfo *Request )
+{
+ struct MsgHeader *Ptr;
+
+ printf( ">> %s %s HTTP/%d.%d\n",
+ HTTP_GetMethodName( Request->Line.Method ),
+ Request->Line.URL.Protocol ? Request->Line.URL.Protocol : "",
+ Request->Line.URL.Servername ? Request->Line.URL.Servername : "",
+ Request->Line.URL.Path ? Request->Line.URL.Path : "",
+ Request->Line.URL.Extra ? Request->Line.URL.Extra : "",
+ Request->Line.Version.Major, Request->Line.Version.Minor );
+
+ Ptr = Request->First;
+ while( Ptr != NULL )
+ {
+ printf( ">> %s: %s\n", HTTP_GetFieldName( Ptr->Field ), Ptr->Content );
+ Ptr = Ptr->Next;
+ }
+ return;
+}
+
+
+/****** http-support/PrintRespInfo *******************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+void PrintRespInfo( struct RespInfo *Response )
+{
+ struct MsgHeader *Ptr;
+
+ printf( ">> HTTP/%d.%d %d %s\n",
+ Response->Line.Version.Major, Response->Line.Version.Minor ,
+ Response->Line.Status,
+ Response->Line.Reason );
+
+ Ptr = Response->First;
+ while( Ptr != NULL )
+ {
+ printf( ">> %s: %s\n", HTTP_GetFieldName( Ptr->Field ), Ptr->Content );
+ Ptr = Ptr->Next;
+ }
+ return;
+}
+
+
+/****** http-support/CheckSockError ******************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+rc_t CheckSockError( int SockFD, int Level, int OptName )
+{
+ int error;
+ size_t len = sizeof( error );
+
+#ifdef DECALPHA
+ if( getsockopt( SockFD, Level, OptName, (char *)&error, (int*)&len ) < 0 )
+#else
+ if( getsockopt( SockFD, Level, OptName, (char *)&error, (socklen_t*)&len ) < 0 )
+#endif
+ return( FAIL );
+ if( error )
+ {
+ errno = error;
+ return( ERROR );
+ }
+ return( OK );
+}
+
+
diff --git a/httpserver/http-writemsg.cc b/httpserver/http-writemsg.cc
new file mode 100644
index 0000000..20d430f
--- /dev/null
+++ b/httpserver/http-writemsg.cc
@@ -0,0 +1,314 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include "mymalloc/mymalloc.h"
+/*------------------------------------------------------------------------*/
+/* http-writemsg.c - generic HTTP-Message functions: */
+/* Creating and sending of HTTP-Messages. */
+/*------------------------------------------------------------------------*/
+/* Comments: */
+/* - Status: */
+/* - To check: All Buffers free()ed? Also in error cases? */
+/*------------------------------------------------------------------------*/
+/*
+ * RCS:
+ * $RCSfile: http-writemsg.c,v $ $Revision: 1.3 $ $State: Exp $
+ * $Locker: $
+ */
+
+
+#include "defs.h"
+#include "protos.h"
+#include "types.h"
+#include "server.h"
+#include "http-defs.h"
+#include "http.h"
+
+extern struct HTTPError HTTPErrorTable[];
+
+
+/****** http-writemsg/AddField ***********************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+rc_t AddField( struct MsgHeader *Ptr, int Field, char *Content )
+{
+ struct MsgHeader *NewHeader;
+
+ if( Ptr != NULL )
+ while( Ptr->Next != NULL )
+ Ptr = Ptr->Next;
+
+ NewHeader = AppendMsgHeader( Ptr, Field, Content );
+ if( NewHeader != NULL )
+ return( OK );
+ else
+ return( WARN );
+}
+
+
+/****** http-writemsg/CreateStatusLine ***************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+rc_t CreateStatusLine( char *Buffer, size_t *BuffSize, int Code, int Protocol )
+{
+ int Entry;
+
+ Entry = GetHTTPErrorTableEntry( Code );
+ switch( Protocol )
+ {
+ case HTTP_1_0:
+ {
+ if( Entry != 0 )
+ SNPrintf( Buffer, BuffSize, "HTTP/1.0 %d %s\r\n", Code, HTTPErrorTable[Entry].Reason );
+ else
+ SNPrintf( Buffer, BuffSize, "HTTP/1.0 %d Statuscode %d\r\n", Code, Code );
+ return( OK );
+ }
+ break;
+ case HTTP_1_1:
+ {
+ if( Entry != 0 )
+ SNPrintf( Buffer, BuffSize, "HTTP/1.1 %d %s\r\n", Code, HTTPErrorTable[Entry].Reason );
+ else
+ SNPrintf( Buffer, BuffSize, "HTTP/1.1 %d Statuscode %d\r\n", Code, Code );
+ return( OK );
+ }
+ break;
+ default:
+ {
+ return( ERROR );
+ }
+ }
+}
+
+
+/****** http-writemsg/CreateHTTPMsg ******************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+struct HTTPMsg *CreateHTTPMsg( char *Header, char *Body, size_t BodySize )
+{
+ struct HTTPMsg *Msg;
+
+ /* printf( "### CreateHTTPMsg(+)\n" ); */
+ Msg = (struct HTTPMsg*)mymalloc( sizeof( struct HTTPMsg ) );
+ if( Msg != NULL )
+ {
+ /* printf( "### Header[%d]:\n%s", strlen( Header ), Header ); */
+ /* printf( "### Body[%d]:\n", BodySize ); */
+
+ Msg->Body = Body;
+ Msg->BodySize = BodySize;
+
+ if( ( Msg->Head = (char*)mymalloc( strlen( Header ) + 1 ) ) != NULL )
+ strcpy( Msg->Head, Header );
+ else
+ {
+ free( Msg );
+ return( NULL );
+ }
+ /* printf( "### Done!\n" ); */
+ }
+ /* printf( "### CreateHTTPMsg(-)\n" ); */
+ return( Msg );
+}
+
+
+/****** http-writemsg/SendHTTPMsg ********************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+rc_t SendHTTPMsg( int SockFD, struct HTTPMsg *Msg )
+{
+ size_t Check;
+
+ if( ( Msg != NULL ) && ( Msg->Head != NULL ) )
+ {
+ Check = WriteN( SockFD, Msg->Head, strlen(Msg->Head) );
+ if( Check < 0 )
+ ErrorMsg( E_SYS, ERROR, "ERROR: WriteN(): write() failed." );
+ else if( Check != strlen(Msg->Head) )
+ LogMsg( LG_SERVER, WARN,
+ "WARN: SendHTTPMsg(): %d of %d Bytes of Header written!",
+ Check, strlen(Msg->Head) );
+
+ if( ( Msg->Body != NULL ) && ( Msg->BodySize > 0 ) )
+ {
+ Check = WriteN( SockFD, Msg->Body, Msg->BodySize );
+ if( Check < 0 )
+ ErrorMsg( E_SYS, ERROR, "ERROR: WriteN(): write() failed." );
+ else if( Check != Msg->BodySize )
+ LogMsg( LG_SERVER, WARN,
+ "WARN: SendHTTPMsg(): %d of %d Bytes of Body written!",
+ Check, Msg->BodySize );
+ }
+ return( OK );
+ }
+ else
+ {
+ return( ERROR );
+ }
+}
+
+
+/****** http-writemsg/FreeHTTPMsg ********************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+rc_t FreeHTTPMsg( struct HTTPMsg *Ptr )
+{
+ free( Ptr->Head );
+ free( Ptr );
+ return( OK );
+}
diff --git a/httpserver/http.cc b/httpserver/http.cc
new file mode 100644
index 0000000..898be85
--- /dev/null
+++ b/httpserver/http.cc
@@ -0,0 +1,181 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*------------------------------------------------------------------------*/
+/* http.c - reworked HTTP communication main loop. */
+/*------------------------------------------------------------------------*/
+
+
+#include "defs.h"
+#include "protos.h"
+#include "server.h"
+#include "http-defs.h"
+#include "http.h"
+
+/*
+ * Release ClientBase
+ */
+void releaseClientBase(struct ClientBase *cb)
+{
+ // free Host
+ free(cb->Host.Name);
+
+ // free Socket
+ // struct sockaddr_in Socket;
+
+ // free TimeOut
+ // struct timeval TimeOut;
+
+ // free Request
+ free(cb->Request.HeadBuff);
+ free(cb->Request.BodyBuff);
+ struct MsgHeader *dummy = NULL;
+ while(cb->Request.First != NULL)
+ {
+ dummy = cb->Request.First->Next;
+ //free(cb->Request.First->Content);
+ free(cb->Request.First);
+ cb->Request.First = dummy;
+ }
+ free(cb->Request.Body);
+ free(cb->Request.Line.Vanilla);
+
+ // free Response
+ free(cb->Response.Head);
+ free(cb->Response.Body);
+
+}
+
+
+/****** http/HandleRequest ***************************************************
+*
+* NAME
+* HandleRequest -- main function for communication processing.
+*
+* SYNOPSIS
+* void HandleRequest( struct ClientBase *Client,
+* SubServerPtr SubServerList );
+*
+* FUNCTION
+* This is the main function which handles the HTTP communication.
+* It calls successivley the functions for handling the request from
+* the client, opening the sockets to the sub-servers and sending
+* the rewritten requests to them, handling the responses and finally
+* sending a response to the client.
+*
+* INPUTS
+* Client - Data structure which holds various informations about
+* the client.
+* SubServerList - The head to a list of all sub-server data structures.
+*
+* NOTES
+* "Client" and "SubServerList" must be valid - they will not be
+* checked. Since "Client" have to be valid in the previous call to
+* "Accept()" this shouldn't be much of a problem...
+*
+* This is "rewritten from scratch" version of "HandleRequest()"
+* since the old version seemed not suitable enough for expansion
+* to handle more error conditions in the communication, and for
+* integration of more features.
+*
+* BUGS
+* Various left. Especially the authorization mechanism doesn't work
+* (yet). Also, some aspects of the HTTP aren't handled gracefully
+* (HTTP/0.9 messages, handling of other methods than GET, HEAD and
+* POST, etc.).
+*
+******************************************************************************
+*
+*/
+void HandleRequest( struct ClientBase *Client )
+{
+ struct ToDoArgs ToDo;
+ int RespState;
+
+ ToDo.What = DO_NOTHING;
+ ToDo.Which.Code = REALLY_NOTHING;
+ Client->Comm.ConnStatus = CONN_OPEN;
+
+ while( Client->Comm.ConnStatus == CONN_OPEN )
+ {
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: HandleRequest(): Reading Request.");
+ GetRequest( Client );
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: HandleRequest(): Parsing Request.");
+ ParseReqHeader( &Client->Request );
+
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: HandleRequest(): Interpreting Request.");
+ InterpreteRequest( Client, &ToDo );
+ switch( ToDo.What )
+ {
+ case DO_SEND_RESPONSE:
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: HandleRequest(): doing InterpreteRequest.");
+ InterpretePOSTRequest( Client );
+
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: HandleRequest(): doing CreateRasResponse.");
+ CreateRasResponse( &Client->Comm, Client );
+ /*
+ LogMsg( LG_SERVER, DEBUG, "DEBUG: SendResponse() for Request: \"%s\".",
+ Client->Request.Line.Vanilla );
+ */
+
+ SendHTTPMsg( Client->SockFD, &Client->Response );
+ WriteAccessLog( Client );
+ LogMsg( LG_SERVER, DEBUG, "DEBUG: HandleRequest(): SEND_RESPONSE done.");
+ break;
+
+ case DO_SEND_ERROR:
+ LogMsg( LG_SERVER, DEBUG, "DEBUG: HandleRequest(): doing SEND_ERROR." );
+ Client->RespStatus = ToDo.Which.Code;
+ LogMsg( LG_SERVER, DEBUG, "DEBUG: CreateHTTPError( %d, -, %p )...",
+ Client->RespStatus, &Client->Response );
+ CreateHTTPError( Client->RespStatus, &Client->Comm, &Client->Response );
+ LogMsg( LG_SERVER, DEBUG, "DEBUG: CreateHTTPError() done." );
+ LogMsg( LG_SERVER, DEBUG, "DEBUG: SendResponse()..." );
+ SendResponse( Client );
+ LogMsg( LG_SERVER, DEBUG, "DEBUG: SendResponse() done." );
+ LogMsg( LG_SERVER, DEBUG, "DEBUG: Write*Log()..." );
+ WriteAccessLog( Client );
+ LogMsg( LG_SERVER, DEBUG, "DEBUG: WriteLog() done." );
+ LogMsg( LG_SERVER, DEBUG, "DEBUG: HandleRequest(): SEND_ERROR done.");
+ break;
+
+ case DO_SHUTDOWN:
+ LogMsg( LG_SERVER, DEBUG, "DEBUG: HandleRequest(): doing SHUTDOWN.");
+ close( Client->SockFD );
+ LogMsg( LG_SERVER, DEBUG, "DEBUG: HandleRequest(): SHUTDOWN done.");
+ break;
+
+ default:
+ LogMsg( LG_SERVER, DEBUG, "DEBUG: HandleRequest(): doing UNDEFINED ACTION.");
+ ErrorMsg( E_PRIV, ERROR, "ERROR: HandleRequest(): Undefined action!" );
+ Client->RespStatus = STATUS_Internal_Server_Error;
+ CreateHTTPError( Client->RespStatus, &Client->Comm, &Client->Response );
+ SendResponse( Client );
+ WriteAccessLog( Client );
+ LogMsg( LG_SERVER, DEBUG, "DEBUG: HandleRequest(): UNDEFINED ACTION done.");
+ break;
+ }
+ releaseClientBase(Client);
+
+ }
+}
+
diff --git a/httpserver/http.h b/httpserver/http.h
new file mode 100644
index 0000000..f22ee49
--- /dev/null
+++ b/httpserver/http.h
@@ -0,0 +1,133 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*------------------------------------------------------------------------*/
+/* http.h - typedefs and structures for HTTP. */
+/*------------------------------------------------------------------------*/
+/*
+ * RCS:
+ * $RCSfile: http.h,v $ $Revision: 1.3 $ $State: Exp $
+ * $Locker: $
+ */
+
+#ifndef _HTTP_H
+#define _HTTP_H
+
+
+struct KeywordKey
+{
+ char *Keyword;
+ int Key;
+};
+
+struct HTTPError
+{
+ int Code;
+ char *Reason;
+ char *Message_en;
+ char *Message_de;
+};
+
+/* HTTP Message structure
+ */
+
+struct HTTPMsg
+{
+ char *Head;
+ char *Body;
+ int BodySize;
+};
+
+
+struct URLComps
+{
+ char *Protocol;
+ char *Servername;
+ char *Path;
+ char *Extra;
+};
+
+
+struct Version
+{
+ int Major;
+ int Minor;
+};
+
+
+struct RequestLine
+{
+ char *Vanilla;
+ int Method;
+ struct URLComps URL;
+ struct Version Version;
+};
+
+struct StatusLine
+{
+ char *Vanilla;
+ struct Version Version;
+ int Status;
+ char *Reason;
+};
+
+struct MsgHeader
+{
+ struct MsgHeader *Next;
+ int Field;
+ char *Content;
+};
+
+
+/* Data Structure for HTTP Request
+ */
+
+struct ReqInfo
+{
+ int State;
+ char *HeadBuff;
+ size_t HeadSize;
+ char *BodyBuff;
+ size_t BodySize;
+ struct RequestLine Line;
+ struct MsgHeader *First;
+ struct MsgHeader *Last;
+ char *Body;
+};
+
+/* Data Structure for HTTP Response
+ */
+
+struct RespInfo
+{
+ int State;
+ char *HeadBuff;
+ size_t HeadSize;
+ char *BodyBuff;
+ size_t BodySize;
+ struct StatusLine Line;
+ struct MsgHeader *First;
+ struct MsgHeader *Last;
+ char *Body;
+};
+
+#endif /* _HTTP_H not defined */
diff --git a/httpserver/httpserver.conf b/httpserver/httpserver.conf
new file mode 100644
index 0000000..a56c060
--- /dev/null
+++ b/httpserver/httpserver.conf
@@ -0,0 +1,14 @@
+#
+# httpserver Configuration file
+#
+ServerName: sunwibas15.forwiss.tu-muenchen.de
+Port: 8080
+
+ServerAdmin: widmann@forwiss.tu-muenchen.de
+
+ServerRoot: /home/gast/beinhofe/rman/
+AccessLog: /home/gast/beinhofe/rman/httpserver/httpaccess.log
+ServerLog: /home/gast/beinhofe/rman/httpserver/httpserver.log
+PidFile: /home/gast/beinhofe/rman/httpserver/httpserver.pid
+MaxURLLength: 120
+
diff --git a/httpserver/httpserver.h b/httpserver/httpserver.h
new file mode 100644
index 0000000..9c95c5b
--- /dev/null
+++ b/httpserver/httpserver.h
@@ -0,0 +1,38 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/***
+ * INCLUDE: httpserver.h
+ *
+ * MODULE: httpserver
+ * CLASS: none, C header
+ *
+ * COMMENTS:
+ *
+*/
+
+#ifndef _HTTPSERVERC_
+#define _HTTPSERVERC_
+
+extern int init_httpserver( int argc, char *argv[] );
+
+#endif
diff --git a/httpserver/init.cc b/httpserver/init.cc
new file mode 100644
index 0000000..b58ce35
--- /dev/null
+++ b/httpserver/init.cc
@@ -0,0 +1,319 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#include "mymalloc/mymalloc.h"
+/*------------------------------------------------------------------------*/
+/* init.c - Functions to setup the server. */
+/*------------------------------------------------------------------------*/
+
+#include <iostream>
+
+#include "defs.h"
+#include "protos.h"
+#include "server.h"
+#include "http-defs.h"
+#include "http.h"
+
+extern struct ServerBase Server;
+
+
+/****** init/Initialize ******************************************************
+*
+* NAME
+* Initialize -- central function for initializing the servers data
+* structures and environment.
+*
+* SYNOPSIS
+* int Initialize( int argc, char *argv[], struct ServerBase *Server );
+*
+* FUNCTION
+*
+* RESULT
+*
+* NOTES
+*
+* BUGS
+*
+* SEE ALSO
+*
+******************************************************************************
+*
+*/
+
+rc_t Initialize( int argc, char *argv[], struct ServerBase *Server )
+{
+
+ /* Make sure that the Server structure is empty. -------------------- */
+ bzero( (char *)Server, sizeof( *Server ) );
+
+ /* Create Head of ChildList */
+ Server->ChildList = (struct ChildBase*)mymalloc( sizeof( struct ChildBase ) );
+ if( Server->ChildList == NULL )
+ ErrorMsg( E_SYS, FAIL, "FAIL: Initialize(): malloc() failed!" );
+ else
+ {
+ //LogMsg( LG_SERVER, DEBUG, "DEBUG: Creating Head of ChildList" );
+ Server->ChildList->next = Server->ChildList;
+ Server->ChildList->prev = Server->ChildList;
+ Server->ChildList->PId = 0;
+ }
+
+ /* Read the environment variables */
+ char* dummy = CONFDIR;
+ if( dummy == NULL)
+ ErrorMsg( E_SYS, FAIL, "FAIL: Environment variable RMANHOME is not set!" );
+ Server->Directory = (char*)mymalloc(strlen(dummy) + 2);
+ strcpy(Server->Directory, dummy);
+ if( Server->Directory[strlen(Server->Directory)] != '/' )
+ strcat( Server->Directory, "/" );
+
+ /* Read Arguments and Server configuration file - and setup --------- */
+ /* the corresponding data structures. --------------------------- */
+
+ ReadArgs( Server, argc, argv );
+ //ReadConfig( Server );
+
+ ConfigureServer( Server );
+ // CheckConfig( Server ); // Check for reasonable configuration
+
+ /* Set timeout for communication with subservers and client --------- */
+ Server->Client.TimeOut.tv_sec = DIALOG_TIMEOUT;
+ Server->Client.TimeOut.tv_usec = 0;
+
+ /* Get the process into "daemon"-mode. ------------------------------ */
+ InitDaemon( Server->Log.Mode );
+ Server->PId = getpid();
+
+ //SavePId( Server->PidFile );
+ /* Initialize the Server Socket. ------------------------------------ */
+ InitSocket( &Server->SockFD, &Server->Socket, Server->Port );
+
+ /* Setup and Open the logfiles. ------------------------------------- */
+ OpenLog( &Server->Log, Server->Log.Access.Filename,
+ Server->Log.Server.Filename,
+ Server->Log.Comm.Filename );
+
+
+ LogMsg( LG_SERVER, INFO, "INFO: ========= %s started. ===============", DAEMONNAME );
+
+ // We don't do that so that the one process running can be exited with simple ^C
+ /* Initialize the signal handlers. ---------------------------------- */
+ // InitSigHandler();
+
+ /* Everything is just great... -------------------------------------- */
+ return( OK );
+}
+
+
+/****** init/InitDaemon ******************************************************
+*
+* NAME
+* InitDaemon -- going into "daemon"-mode: process forks to run in the
+* background and closes all open file-descriptors.
+*
+* SYNOPSIS
+* int InitDaemon( int Mode );
+*
+* FUNCTION
+*
+* RESULT
+*
+* NOTES
+*
+* BUGS
+*
+* SEE ALSO
+*
+******************************************************************************
+*
+*/
+
+rc_t InitDaemon( int Mode )
+{
+ int i;
+ pid_t pid;
+ int openmax;
+
+ // RasDaMan does not go into background!
+ chdir( Server.Directory ); /* Arbeitsverzeichnis wechseln */
+ umask( 0 ); /* Dateischutzbitmaske loeschen */
+ return( OK );
+}
+
+
+/****** init/InitSocket ******************************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+* ### Minimum Socket Setup. Stay tuned.
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+rc_t InitSocket( int *SockFD, struct sockaddr_in *Socket, int Port )
+{
+ int val = 0;
+ size_t len;
+
+ Socket->sin_family = AF_INET;
+ Socket->sin_addr.s_addr = htonl( INADDR_ANY );
+ Socket->sin_port = htons( Port );
+ if( ( *SockFD = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 )
+ ErrorMsg( E_SYS, FAIL, "FAIL: Open socket for server." );
+
+#ifdef SO_REUSEADDR
+ val = 1;
+ len = sizeof( val );
+ if( setsockopt( *SockFD, SOL_SOCKET, SO_REUSEADDR, (char*)&val, len ) < 0 )
+ ErrorMsg( E_SYS, WARN, "WARN: InitSocket(): can't set sockopt REUSEADDR." );
+#else
+ LogMsg( LG_SERVER, INFO, "INFO: InitSocket(): sockopt REUSEADDR not available." );
+#endif
+
+ if( bind( *SockFD, (struct sockaddr *)Socket, sizeof( *Socket ) ) < 0 )
+ ErrorMsg( E_SYS, FAIL, "FAIL: Bind socket for server." );
+ return( OK );
+}
+
+
+/****** init/InitClientSocket ************************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+rc_t InitClientSocket( int *SockFD,
+ struct sockaddr_in *Socket,
+ char *Hostname,
+ int Port )
+{
+ struct hostent *Host;
+
+ bzero( (char *)Socket, sizeof( *Socket ) );
+
+ Socket->sin_family = AF_INET;
+ Host = gethostbyname( Hostname );
+ if( Host == NULL )
+ {
+ return( ERROR );
+ }
+ memcpy( (char *)&Socket->sin_addr, (char *)Host->h_addr, Host->h_length );
+
+ Socket->sin_port = htons( Port );
+ if( ( *SockFD = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 )
+ return( ERROR );
+ return( OK );
+}
+
+
+/****** init/SavePId *********************************************************
+*
+* NAME
+* SavePId -- store process id in file.
+*
+* SYNOPSIS
+* void SavePId( char *PIdFilename );
+*
+* FUNCTION
+* THis function saves the parent process id in a file, so this file
+* can be used by for example shell scripts to identify the correct
+* process to signal it.
+*
+* INPUTS
+* PIdFilename -- Full pathname of the file which stortes the pid.
+*
+* RESULT
+* Does not return anything.
+*
+* NOTES
+* This function is called by Initialize(), right after the logs are
+* opened. So the content of the pidfile is also only valid afterwards.
+* To ensure, that there is no stale pidfile, it is deleted on normal
+* termination.
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+
+void SavePId( char *PIdFilename )
+{
+ FILE *PIdFile;
+
+ if( ( PIdFile = fopen( PIdFilename, "w" ) ) != NULL )
+ {
+ fprintf( PIdFile, "%d", getpid() );
+ fclose( PIdFile );
+ }
+}
diff --git a/httpserver/logging.cc b/httpserver/logging.cc
new file mode 100644
index 0000000..e486c66
--- /dev/null
+++ b/httpserver/logging.cc
@@ -0,0 +1,297 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*------------------------------------------------------------------------*/
+/* logging.c - logging and error message handling. */
+/*------------------------------------------------------------------------*/
+
+#include "defs.h"
+#include "protos.h"
+#include "server.h"
+
+
+extern struct Logging *LogBase;
+
+
+rc_t OpenLog( struct Logging *Log, char *AccessLog, char *ServerLog, char *CommLog )
+{
+ /* removed this, we don't need this logs
+ if( (Log->Mode & LF_STDERR) == LF_STDERR ) // Log to STDOUT/STDERR ?
+ {
+ Log->Access.Filename = NULL;
+ Log->Access.FD = STDOUT_FILENO;
+ Log->Access.State = FILE_OPEN;
+ Log->Server.Filename = NULL;
+ Log->Server.FD = STDERR_FILENO;
+ Log->Server.State = FILE_OPEN;
+ Log->Comm.Filename = NULL;
+ Log->Comm.FD = STDOUT_FILENO;
+ Log->Comm.State = FILE_OPEN;
+ }
+ else
+ {
+ Log->Access.Filename = AccessLog;
+ if( AccessLog != NULL )
+ {
+ Log->Access.FD = open( Log->Access.Filename,
+ O_WRONLY | O_CREAT | O_APPEND, FILE_MODE );
+ if( Log->Server.FD < 0 )
+ ErrorMsg( E_SYS, FAIL, "FAIL: Open AccessLog failed." );
+ Log->Access.State = FILE_OPEN;
+ }
+ else
+ {
+ Log->Access.State = FILE_CLOSED;
+ }
+
+ Log->Server.Filename = ServerLog;
+ if( ServerLog != NULL )
+ {
+ Log->Server.FD = open( Log->Server.Filename,
+ O_WRONLY | O_CREAT | O_APPEND, FILE_MODE );
+ if( Log->Server.FD < 0 )
+ ErrorMsg( E_SYS, FAIL, "FAIL: Open ServerLog failed." );
+ Log->Server.State = FILE_OPEN;
+ }
+ else
+ {
+ Log->Server.State = FILE_CLOSED;
+ }
+ }
+ */
+
+ Log->Server.State = FILE_CLOSED;
+ Log->Access.State = FILE_CLOSED;
+ Log->Comm.State = FILE_CLOSED;
+ return( OK );
+}
+
+
+void CloseLog( struct Logging *Log )
+{
+ //close( Log->Server.FD );
+ Log->Server.State = FILE_CLOSED;
+ //close( Log->Access.FD );
+ Log->Access.State = FILE_CLOSED;
+}
+
+
+
+void ErrorMsg( int errnoFlag, int ErrLevel, const char *ErrMsg, ... )
+{
+ int errno_save;
+ char ErrMsgBuffer[ MAXLINELEN ];
+ size_t StringSize, BuffSize;
+ va_list ArgPtr;
+
+ errno_save = errno;
+
+ va_start( ArgPtr, ErrMsg );
+ if( VSNPrintf( ErrMsgBuffer, MAXLINELEN, ErrMsg, ArgPtr ) < 0)
+ ErrorMsg( E_PRIV, WARN, "WARN: Log message exceeded buffer size!" );
+ va_end( ArgPtr );
+
+ StringSize = strlen( ErrMsgBuffer );
+ BuffSize = MAXLINELEN - StringSize;
+
+ if( errnoFlag )
+ {
+ if( SNPrintf( ErrMsgBuffer + StringSize, &BuffSize,
+ " Reason: %s", StrError( errno_save ) ) < 0)
+ {
+ ErrorMsg( E_PRIV, WARN, "WARN: Log message exceeded buffer size!" );
+ }
+ }
+ LogMsg( LG_SERVER, ErrLevel, ErrMsgBuffer );
+
+ switch( ErrLevel )
+ {
+ case DUMP:
+ {
+ abort(); /* core dump erzeugen und beenden */
+ exit( DUMP ); /* sollte nicht soweit kommen... */
+ }
+ break;
+ case FAIL:
+ {
+ exit( FAIL ); /* Ausstieg mit Status "FAIL". */
+ }
+ break;
+ default:
+ return;
+ }
+}
+
+
+void LogMsg( int SubSys, int Level, const char *Msg, ... )
+{
+ return;
+ /*
+ char MsgBuffer[ MAXLINELEN ];
+ char *BufferPtr;
+ size_t BuffSize = MAXLINELEN;
+ size_t TimeBuffSize = DATE_BUFFSIZE;
+ va_list ArgPtr;
+
+ if( (Level == DEBUG) && ((LogBase->Mode & LF_VERB) == 0) ) // DEBUG Msgs wanted?
+ return;
+
+ bzero( MsgBuffer, MAXLINELEN );
+ BufferPtr = &MsgBuffer[0];
+
+ // ### HACK! access.log datestamp is already in msg string!
+ if( SubSys != LG_ACCESS )
+ {
+ LogDate( BufferPtr, TimeBuffSize );
+ strcat( BufferPtr, " " );
+ }
+ if( SubSys == LG_SERVER )
+ {
+ BufferPtr = &MsgBuffer[0] + strlen( MsgBuffer );
+ sprintf( BufferPtr, "<%d> ", getpid() );
+ }
+
+ BufferPtr = &MsgBuffer[0] + strlen( MsgBuffer );
+ BuffSize = MAXLINELEN - strlen( MsgBuffer ) - 2;
+
+ va_start( ArgPtr, Msg );
+ if( VSNPrintf( BufferPtr, BuffSize , Msg, ArgPtr ) < 0)
+ ErrorMsg( E_PRIV, WARN, "WARN: Log message exceeded buffer size!" );
+ va_end( ArgPtr );
+
+ // Log-Meldungen sollten immer ein <EOL> am Ende haben.
+ // Also kontrollieren und nötigenfalls ergänzen.
+ // Da MsgBuffer mit maximal MAXLINELEN - 2 Zeichen gefüllt sein
+ // sollte, kann gefahrlos <EOL> angehängt werden.
+
+ if( MsgBuffer[ strlen( MsgBuffer ) - 1 ] != '\n' )
+ strcat( MsgBuffer, "\n" );
+
+ // Moeglichkeiten:
+ // stdio offen, Server.Log nicht initialisiert
+ // stdio offen, Server.Log initialisiert (Log auf stdio)
+ // stdio geschlossen, Server.Log initialisiert (Log in File)
+
+ switch( SubSys )
+ {
+ case LG_SERVER:
+ if( LogBase->Server.State == FILE_OPEN )
+ write( LogBase->Server.FD, MsgBuffer, strlen( MsgBuffer ) );
+ else
+ write( STDERR_FILENO, MsgBuffer, strlen( MsgBuffer ) );
+ break;
+ case LG_ACCESS:
+ if( LogBase->Access.State == FILE_OPEN )
+ write( LogBase->Access.FD, MsgBuffer, strlen( MsgBuffer ) );
+ else
+ write( STDOUT_FILENO, Msg, strlen( MsgBuffer ) );
+ break;
+ case LG_COMM:
+ if( LogBase->Comm.State == FILE_OPEN )
+ write( LogBase->Comm.FD, MsgBuffer, strlen( MsgBuffer ) );
+ else
+ write( STDOUT_FILENO, Msg, strlen( MsgBuffer ) );
+ break;
+ default:
+ ErrorMsg( E_PRIV, WARN, "WARN: Unknown Logging sub-system!" );
+ }
+ */
+ return;
+}
+
+rc_t LogDate( char *Buffer, int BuffSize )
+{
+ struct tm *ltime;
+ int TZoffset;
+ char sign;
+
+ size_t strsize;
+ size_t RestSize;
+
+ ltime = Get_GMToffset( &TZoffset );
+
+ /* LOG Date Format: "[dd/mmm/yyyy:HH:MM:SS {-|+}XXXX]" */
+ /* XXXX = Timezone offset format: HHMM */
+ sign = ( TZoffset < 0 ? '-' : '+' );
+ if( TZoffset < 0 )
+ TZoffset = -TZoffset;
+
+ strsize = strftime( Buffer, BuffSize, "[%d/%b/%Y:%H:%M:%S ", ltime );
+ if( strsize >= BuffSize-6 || strsize == 0 )
+ return( ERROR );
+ else
+ {
+ RestSize = BuffSize-strsize;
+ SNPrintf( Buffer+strsize, &RestSize, "%c%.2d%.2d]",
+ sign, TZoffset/60, TZoffset%60 );
+ return( OK );
+ }
+}
+
+
+/****** logging/Get_GMToffset ************************************************
+*
+* NAME
+* Get_GMToffset -- Get numerical offset of localtime to gmtime.
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+* Source code taken from Apache 1.3.1 distribution.
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+struct tm *Get_GMToffset( int *tz )
+{
+ time_t tt = time(NULL);
+ struct tm gmt;
+ struct tm *t;
+ int days, hours, minutes;
+
+ /* Assume we are never more than 24 hours away. */
+ gmt = *gmtime(&tt); /* remember gmtime/localtime return ptr to static */
+ t = localtime(&tt); /* buffer... so be careful */
+ days = t->tm_yday - gmt.tm_yday;
+ hours = ((days < -1 ? 24 : 1 < days ? -24 : days * 24)
+ + t->tm_hour - gmt.tm_hour);
+ minutes = hours * 60 + t->tm_min - gmt.tm_min;
+ *tz = minutes;
+ return( t );
+}
diff --git a/httpserver/main.cc b/httpserver/main.cc
new file mode 100644
index 0000000..5082fe9
--- /dev/null
+++ b/httpserver/main.cc
@@ -0,0 +1,191 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#include "raslib/error.hh"
+#include "raslib/rminit.hh"
+
+#include "httpserver.h"
+
+#include "defs.h"
+#include "protos.h"
+#include "types.h"
+#include "server.h"
+
+#ifdef PURIFY
+#include <purify.h>
+#endif
+
+/*--- Global Data Section: ------------------------------------------------*/
+/* All we need to remember or may want to know is in this structure */
+
+struct ServerBase Server;
+
+struct Logging *LogBase = &Server.Log;
+
+/****** main/main ************************************************************
+*
+* NAME
+* main -- the main function of this program.
+*
+* SYNOPSIS
+* void main( int argc, char *argv[] );
+*
+* FUNCTION
+* "main" calls "Initialize()" for setting up the program, activates
+* the main socket with the "listen()" system call, and then waits
+* forever for a client to connect. If a client connection request is
+* received, a child process will be spawned and the child will handle
+* the request while the parent process will wait again for new
+* connection requests.
+*
+* INPUTS
+* argc - The number of arguments given on the command line.
+* argv[] - An array of strings, containing the arguments given on the
+* command line.
+*
+* NOTES
+* The program can only be stopped by sending it the corresponding
+* signals ("SIGQUIT", "SIGTERM").
+*
+* BUGS
+* None known. Not here.
+*
+* SEE ALSO
+* Initialize(), Accept(), AddChild(), InitChild(), HandleRequest().
+*
+******************************************************************************
+*
+*/
+
+extern int init_httpserver( int argc, char *argv[] )
+{
+ pid_t ChildPId; /* -> Server.ChildInfo */
+
+ RMInit::logOut << "Initialising parameters for HTTP server... " << endl;
+ RMInit::logOut.flush();
+ Initialize( argc, argv, &Server );
+
+ RMInit::logOut << "Initialising server socket for HTTP server... " << endl;
+ RMInit::logOut.flush();
+ listen( Server.SockFD, 5 );
+ RMInit::logOut << "Waiting for client calls... " << endl;
+ RMInit::logOut.flush();
+
+#ifdef PURIFY
+ purify_printf( "Server Startup Finnished." );
+ purify_new_leaks();
+#endif
+
+/* // this is a quick hack for testing */
+/* return 0; */
+ for(;;)
+ {
+ Accept( Server.SockFD, &Server.Client );
+
+ strcpy( Server.Client.Host.IPAddrString, inet_ntoa( Server.Client.Socket.sin_addr ) );
+
+ if( Server.Client.Host.IPAddrString == NULL )
+ strcpy( Server.Client.Host.IPAddrString, "0.0.0.0" );
+
+ Server.Client.Host.IPAddress = inet_addr( Server.Client.Host.IPAddrString );
+ Server.Client.Comm.ConnStatus = CONN_UNDEFINED;
+ InitHTTPMsg( &Server.Client.Response );
+ InitReqInfo( &Server.Client.Request );
+
+ LogMsg( LG_SERVER, INFO, "INFO: ====== Connection from %s accepted...",
+ Server.Client.Host.IPAddrString );
+ HandleRequest( &Server.Client );
+ LogMsg( LG_SERVER, INFO, "INFO: ====== EOT. Disconnecting." );
+
+ close( Server.Client.SockFD );
+
+ }
+ // otherwise Exit(OK) should have been called
+ return -1;
+}
+
+
+
+/****** main/Exit ************************************************************
+*
+* NAME
+* Exit -- Cleanup when exiting.
+*
+* SYNOPSIS
+* void Exit( int RC );
+*
+* FUNCTION
+* This function closes all open socket descriptors and the logging
+* subsystem. If the calling process is the parent process, it also
+* deletes the file where the process Id is stored.
+* After that, it calls the "exit()" function with the return code
+* "RC".
+*
+* INPUTS
+* RC - return or exit code, indicating the error condition of the
+* program.
+*
+* NOTES
+* This function is called by the signal handlers for "SIGQUIT",
+* "SIGTERM", "SIGINT" and "SIGHUP" and the main() function.
+* In future versions, "SIGHUP" should be changed to reread the
+* configuration file instead of calling Exit().
+*
+* BUGS
+* The global variable "SubServer[]" should not be used.
+*
+* SEE ALSO
+* Exit().
+*
+******************************************************************************
+*
+*/
+
+int Exit( int RC )
+{
+ int i;
+
+ // for( i = 0; i < NUM_SUBSERVER; i++ )
+ // close( SubServer[i].SockFD );
+ close( Server.SockFD );
+
+ if( getpid() == Server.PId ) /* Is this the parent process? */
+ {
+ unlink( Server.PidFile );
+ LogMsg( LG_SERVER, DEBUG, "DEBUG: Main process exiting (RC=%d)...", RC );
+ LogMsg( LG_SERVER, INFO,
+ "INFO: ========= %s terminated. ============", DAEMONNAME );
+ }
+ else
+ {
+ LogMsg( LG_SERVER, DEBUG, "DEBUG: Exiting (RC=%d)...", RC );
+ }
+
+ CloseLog( &Server.Log );
+
+ free(Server.Directory);
+
+ if(RC != OK) throw r_Error( r_Error::r_Error_General );
+ return RC;
+}
+
diff --git a/httpserver/protos.h b/httpserver/protos.h
new file mode 100644
index 0000000..60a0ac9
--- /dev/null
+++ b/httpserver/protos.h
@@ -0,0 +1,178 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*------------------------------------------------------------------------*/
+/* protos.h - Prototypes of all functions */
+/*------------------------------------------------------------------------*/
+/*
+ * RCS:
+ * $RCSfile: protos.h,v $ $Revision: 1.10 $ $State: Exp $
+ * $Locker: $
+ */
+
+#ifndef _PROTOS_H
+#define _PROTOS_H
+
+#include "server.h"
+
+/*------------------------------------------------------------------------*/
+/* Protoypes from main.c */
+/*------------------------------------------------------------------------*/
+
+int Exit( int );
+
+/* init.c */
+rc_t Initialize( int, char **, struct ServerBase * );
+rc_t InitDaemon( int );
+rc_t InitSocket( int *, struct sockaddr_in *, int );
+rc_t InitClientSocket( int *, struct sockaddr_in *, char *, int );
+void SavePId( char * );
+
+/* childs.c */
+rc_t InitChild( struct ClientBase * );
+pid_t NewChild( struct ChildBase *List, struct FDsets *PDSets, struct ClientBase *Client );
+void CleanupChild( struct ChildBase *List, struct FDsets *PDSets, pid_t PId );
+void AddChild( struct ChildBase *List, struct ChildBase *Child );
+void RemChild( struct ChildBase *List, struct ChildBase *Child );
+struct ChildBase *GetChild( struct ChildBase *List, pid_t PId );
+
+/*------------------------------------------------------------------------*/
+/* Protoypes from config.c */
+/*------------------------------------------------------------------------*/
+
+rc_t ReadArgs( struct ServerBase *, int, char ** );
+rc_t ReadConfig( struct ServerBase * );
+rc_t CheckAndSet( struct ServerBase *, char *, int );
+rc_t SetServDir( struct ServerBase *, char * );
+rc_t SetFilename( struct ServerBase *, int, char * );
+rc_t SetString( struct ServerBase *, int, char * );
+rc_t ConfigureServer( struct ServerBase * );
+int GetConfigKey( char * );
+
+/*------------------------------------------------------------------------*/
+/* Protoypes from signals.c */
+/*------------------------------------------------------------------------*/
+
+typedef void(*sighandler)(int);
+
+sighandler Signal( int, sighandler );
+void SigHandler( int );
+rc_t InitSigHandler( void );
+
+/*------------------------------------------------------------------------*/
+/* Protoypes from logging.c */
+/*------------------------------------------------------------------------*/
+
+rc_t OpenLog( struct Logging *, char *, char *, char * );
+void CloseLog( struct Logging *Log );
+void LogMsg( int, int, const char *, ... );
+void ErrorMsg( int, int, const char *, ... );
+rc_t LogDate( char *, int );
+struct tm *Get_GMToffset( int * );
+
+/*------------------------------------------------------------------------*/
+/* Protoypes for communication handling. */
+/*------------------------------------------------------------------------*/
+
+/* http.c */
+void HandleRequest( struct ClientBase *Client );
+
+/* http-doit.c */
+rc_t Accept( int, struct ClientBase * );
+void GetRequest( struct ClientBase *Client );
+void InterpreteRequest( struct ClientBase *Client, struct ToDoArgs *ToDo );
+int SendRequest( int SockFD, struct HTTPMsg *Request, struct FDsets *RW_Sets );
+int ReadResponseHead( int SockFD, struct RespInfo *Response, struct FDsets *RW_Sets );
+int ReadResponseBody( int SockFD, struct RespInfo *Response, struct FDsets *RW_Sets );
+void SendResponse( struct ClientBase *Client );
+void CreateRasResponse( struct HTTPMode *Mode, struct ClientBase *Client );
+void DoMessageBody( struct ClientBase *Client );
+void InterpretePOSTRequest ( struct ClientBase *Client );
+void WriteAccessLog( struct ClientBase *Client );
+
+
+/* http-readmsg.c */
+int ReadHeader( int SockFD, char **Buffer, size_t *BuffSize );
+char *ReadBody( int SockFD, size_t BuffSize );
+rc_t ParseReqHeader( struct ReqInfo *Request );
+rc_t ParseRespHeader( struct RespInfo *Response );
+char *ParseReqLine( char *Buffer, struct ReqInfo *Request );
+char *ParseRespLine( char *Buffer, struct RespInfo *Response );
+char *ParseMsgLine( char *Buffer, int *Key, char **Param );
+void SplitURL( char *Buffer, struct URLComps *URL );
+size_t GetContentLength( struct MsgHeader *Ptr );
+char *GetFieldContent( struct MsgHeader *Ptr, int Field, struct MsgHeader **Next );
+int GetRealm( char *String );
+
+/* http-writemsg.g */
+rc_t AddField( struct MsgHeader *Ptr, int Field, char *Content );
+rc_t CreateStatusLine( char *Buffer, size_t *BuffSize, int Code, int Protocol );
+struct HTTPMsg *CreateHTTPMsg( char *, char *, size_t ); // ???
+rc_t SendHTTPMsg( int SockFD, struct HTTPMsg *Msg );
+rc_t FreeHTTPMsg( struct HTTPMsg *Ptr );
+
+/* http-error.c */
+int GetHTTPErrorTableEntry( int Code );
+rc_t CreateHTTPError( int Code, struct HTTPMode *Mode, struct HTTPMsg *Msg );
+
+/* http-methods.c */
+int HTTP_GetMKey( char * );
+char *HTTP_GetMethodName( int );
+
+/* http-fields.c */
+int HTTP_GetHKey( char * );
+char *HTTP_GetFieldName( int );
+
+/* http-date.c */
+rc_t HTTP_Date( char *, size_t );
+
+/* http-support.c */
+rc_t InitClientBase( struct ClientBase * );
+rc_t InitReqInfo( struct ReqInfo * );
+rc_t InitRespInfo( struct RespInfo * );
+void InitHTTPMsg( struct HTTPMsg *Msg );
+struct MsgHeader *NewMsgHeader( int, char * );
+struct MsgHeader *AppendMsgHeader( struct MsgHeader *, int, char * );
+void DeleteMsgHeader( struct MsgHeader * );
+void PrintReqInfo( struct ReqInfo * );
+void PrintRespInfo( struct RespInfo * );
+rc_t CheckSockError( int, int, int );
+char *CharToBits( char c );
+
+
+
+/*------------------------------------------------------------------------*/
+/* Protoypes from support.c */
+/*------------------------------------------------------------------------*/
+
+int Get_OpenMax( void );
+char *PathAlloc( size_t * );
+int ReadN( register int, register char *, register int );
+int WriteN( register int, register char *, register int );
+int ReadLine( register int, register char *, register int );
+rc_t ParseString( char *, char *, ... );
+int SNPrintf( char *, size_t *, const char *, ... );
+int VSNPrintf( char *, size_t, const char *, va_list );
+char *StrError( int );
+char *StrToLower( char * );
+
+#endif /* _PROTOS_H not defined */
diff --git a/httpserver/server.h b/httpserver/server.h
new file mode 100644
index 0000000..e3b3f54
--- /dev/null
+++ b/httpserver/server.h
@@ -0,0 +1,190 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*------------------------------------------------------------------------*/
+/* server.h - server structures. */
+/*------------------------------------------------------------------------*/
+
+
+#ifndef _SERVER_H
+#define _SERVER_H
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <limits.h>
+#include <errno.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#ifndef AIX
+ #include <sys/fcntl.h>
+#endif
+
+#include <fcntl.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include "types.h"
+#include "http.h"
+
+struct HTTPRequest
+{
+ char *Database;
+ int Command;
+ char *QueryString;
+ int ClientType;
+ char *ClientID;
+ int Endianess;
+ int NumberOfQueryParams;
+ char *BinData;
+ int BinDataSize;
+ char *Capability;
+};
+
+union WhichArg
+{
+ int Code;
+};
+
+struct ToDoArgs
+{
+ int What;
+ union WhichArg Which;
+};
+
+struct FDsets
+{
+ int MaxFD;
+ fd_set Read;
+ fd_set Write;
+};
+
+struct LogFile
+{
+ char *Filename;
+ int FD;
+ int State;
+};
+
+
+struct Logging
+{
+ int Mode;
+ struct LogFile Server;
+ struct LogFile Access;
+ struct LogFile Comm;
+};
+
+struct ChildBase
+{
+ struct ChildBase *next;
+ struct ChildBase *prev;
+ pid_t PId;
+ int PD[2];
+ int PipeStatus;
+};
+
+
+struct Host
+{
+ char *Name;
+ char IPAddrString[ 16 ];
+#ifdef NO_in_addr_t
+ unsigned long IPAddress;
+#else
+ in_addr_t IPAddress;
+#endif
+};
+
+
+struct HTTPMode
+{
+ int Protocol;
+ int ConnStatus;
+};
+
+
+struct ClientBase
+{
+ /* Client Host Infos */
+ struct Host Host;
+ int ClientType;
+ /* Socket */
+ int SockFD;
+ struct sockaddr_in Socket;
+ int SockSize;
+ /* select() timeout */
+ struct timeval TimeOut;
+
+ struct HTTPMode Comm;
+ /* Request */
+ struct ReqInfo Request;
+ /* Response */
+ struct HTTPMsg Response;
+ int RespStatus;
+ /* Pipe to Parent process */
+ int Pipe;
+ char PipeBuffer[PIPE_BUFFSIZE];
+};
+
+
+struct ServerBase
+{
+ pid_t PId;
+ /* -- Config.Information */
+ struct Host Host;
+ int Port;
+ char *AdminMailAddress;
+ char *Directory;
+ char *ConfigFile;
+ char *PidFile;
+ //char *CacheFile;
+ size_t MaxURLLength;
+ /* -- Status Information */
+ int Status;
+ struct ChildBase *ChildList;
+ struct FDsets PipeSets;
+ /* -- Global Data */
+ struct Logging Log;
+ struct CacheNode *Cache;
+ /* -- Server Socket */
+ int SockFD;
+ struct sockaddr_in Socket;
+ /* -- Client Information */
+ struct ClientBase Client;
+};
+
+
+#endif /* _SERVER_H not defined */
diff --git a/httpserver/signals.cc b/httpserver/signals.cc
new file mode 100644
index 0000000..4bda368
--- /dev/null
+++ b/httpserver/signals.cc
@@ -0,0 +1,287 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*------------------------------------------------------------------------*/
+/* signals.c - signal handling stuff. */
+/*------------------------------------------------------------------------*/
+/*
+ * RCS:
+ * $RCSfile: signals.c,v $ $Revision: 1.8 $ $State: Exp $
+ * $Locker: $
+*/
+
+
+#include "defs.h"
+#include "protos.h"
+#include "server.h"
+
+extern struct ServerBase Server;
+
+
+/****** signals/Signal *******************************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+* Own Signal() function, based on sigaction().
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+sighandler Signal( int signo, sighandler x)
+{
+ struct sigaction SigAction;
+ struct sigaction OldAction;
+
+ SigAction.sa_handler = (void(*)(int))SigHandler;
+ sigemptyset( & SigAction.sa_mask );
+ SigAction.sa_flags = 0;
+
+ if( signo == SIGALRM )
+ {
+#ifdef SA_INTERRUPT
+ SigAction.sa_flags |= SA_INTERRUPT; /* SunOS */
+#endif
+ }
+ else
+ {
+#ifdef SA_RESTART
+ SigAction.sa_flags |= SA_RESTART; /* SVR4, 4.3+ BSD */
+#endif
+ }
+
+ if( sigaction( signo, &SigAction, &OldAction ) < 0 )
+ return( SIG_ERR );
+ return( OldAction.sa_handler );
+}
+
+
+/****** signals/SigHandler ***************************************************
+*
+* NAME
+* SigHandler -- Little Signal Handler.
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+void SigHandler( int Signal )
+{
+ //not used(see line 169) char Buffer[PIPE_BUFFSIZE];
+ int errno_bak;
+ int ChildStatus;
+ pid_t ChildPId;
+ struct ChildBase *Child = NULL;
+
+ errno_bak = errno;
+ switch( Signal )
+ {
+ case SIGHUP:
+ LogMsg( LG_SERVER, INFO, "INFO: Received 'SIGHUP'." );
+ errno = errno_bak;
+ Exit( OK );
+ break;
+
+ case SIGINT:
+ LogMsg( LG_SERVER, INFO, "INFO: Received 'SIGINT'." );
+ errno = errno_bak;
+ Exit( OK );
+ break;
+
+ case SIGQUIT:
+ LogMsg( LG_SERVER, INFO, "INFO: Received 'SIGQUIT'." );
+ errno = errno_bak;
+ Exit( OK );
+ break;
+
+ case SIGUSR1:
+ LogMsg( LG_SERVER, INFO, "INFO: Received 'SIGUSR1'." );
+ // SaveCache( Server.Cache, Server.CacheFile );
+ break;
+
+ case SIGUSR2:
+ LogMsg( LG_SERVER, INFO, "INFO: Received 'SIGUSR2'." );
+ break;
+
+ case SIGPIPE:
+ LogMsg( LG_SERVER, INFO, "INFO: Received 'SIGPIPE'." );
+ break;
+
+ case SIGTERM:
+ LogMsg( LG_SERVER, INFO, "INFO: Received 'SIGTERM'." );
+ errno = errno_bak;
+ Exit( OK );
+ break;
+
+ case SIGCHLD:
+ LogMsg( LG_SERVER, INFO, "INFO: Received 'SIGCHLD'." );
+ ChildPId = waitpid( -1, &ChildStatus, WNOHANG );
+ while( ChildPId > 0 )
+ {
+ if( WIFEXITED( ChildStatus ) )
+ {
+ /*-- Has Child send a Message? --*/
+ if( WEXITSTATUS( ChildStatus ) == NOTE )
+ {
+ Child = GetChild( Server.ChildList, ChildPId );
+ if( Child != NULL )
+ {
+ /*
+ bzero( Buffer, PIPE_BUFFSIZE );
+ read( Child->PD[0], Buffer, PIPE_BUFFSIZE );
+ HandlePipeMsg( Buffer, Server.SubServerList, Server.Cache );
+ */
+ }
+ }
+ LogMsg( LG_SERVER, DEBUG,
+ "DEBUG: Child <%d> exited normally with status %d.",
+ ChildPId, WEXITSTATUS( ChildStatus ) );
+ }
+ else if( WIFSIGNALED( ChildStatus ) )
+ {
+ LogMsg( LG_SERVER, DEBUG,
+ "DEBUG: Child <%d> exited abnormally, signal number = %d.",
+ ChildPId, WTERMSIG( ChildStatus ) );
+ }
+ else if( WIFSTOPPED( ChildStatus ) )
+ {
+ LogMsg( LG_SERVER, DEBUG,
+ "DEBUG: Child <%d> is stopped, signal number = %d.",
+ ChildPId, WSTOPSIG( ChildStatus ) );
+ }
+ else
+ {
+ LogMsg( LG_SERVER, WARN,
+ "WARN: Something strange with Child <%d> (Status: %d).",
+ ChildPId, ChildStatus );
+ }
+
+ CleanupChild( Server.ChildList, &Server.PipeSets, ChildPId );
+ ChildPId = waitpid( -1, &ChildStatus, WNOHANG );
+
+ }
+ if( ChildPId == -1 && errno != ECHILD )
+ ErrorMsg( E_SYS, WARN, "WARN: waitpid() returned an Error.", errno );
+ LogMsg( LG_SERVER, DEBUG, "DEBUG: Exiting Signal Handler ..." );
+ break;
+ default:
+ ErrorMsg( E_PRIV, ERROR, "ERROR: Signal %d couldn't be handled!", Signal );
+ break;
+ }
+ errno = errno_bak;
+ return;
+}
+
+
+/****** signals/InitSigHandler ***********************************************
+*
+* NAME
+* InitSigHandler -- Minimum Signal Handler setup.
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+
+rc_t InitSigHandler( void )
+{
+ if( Signal( SIGHUP, SigHandler ) == SIG_ERR )
+ ErrorMsg( E_SYS, ERROR, "ERROR: Installing Signal Handler (HUP)." );
+ if( Signal( SIGINT, SigHandler ) == SIG_ERR )
+ ErrorMsg( E_SYS, ERROR, "ERROR: Installing Signal Handler (INT)." );
+ if( Signal( SIGQUIT, SigHandler ) == SIG_ERR )
+ ErrorMsg( E_SYS, ERROR, "ERROR: Installing Signal Handler (QUIT)." );
+ if( Signal( SIGTERM, SigHandler ) == SIG_ERR )
+ ErrorMsg( E_SYS, ERROR, "ERROR: Installing Signal Handler (TERM)." );
+ if( Signal( SIGCHLD, SigHandler ) == SIG_ERR )
+ ErrorMsg( E_SYS, ERROR, "ERROR: Installing Signal Handler (CHLD)." );
+ if( Signal( SIGUSR1, SigHandler ) == SIG_ERR )
+ ErrorMsg( E_SYS, ERROR, "ERROR: Installing Signal Handler (USR1)." );
+ if( Signal( SIGUSR2, SigHandler ) == SIG_ERR )
+ ErrorMsg( E_SYS, ERROR, "ERROR: Installing Signal Handler (USR2)." );
+
+ if( Signal( SIGPIPE, SigHandler ) == SIG_ERR )
+ ErrorMsg( E_SYS, ERROR, "ERROR: Installing Signal Handler (PIPE)." );
+ return( OK );
+}
+
diff --git a/httpserver/support.cc b/httpserver/support.cc
new file mode 100644
index 0000000..6a011fd
--- /dev/null
+++ b/httpserver/support.cc
@@ -0,0 +1,640 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include "mymalloc/mymalloc.h"
+/*------------------------------------------------------------------------*/
+/* support.c - support functions for the gateway httpd. */
+/*------------------------------------------------------------------------*/
+/*
+ * RCS:
+ * $RCSfile: support.c,v $ $Revision: 1.6 $ $State: Exp $
+ * $Locker: $
+ */
+
+#include <ctype.h>
+
+#include "defs.h"
+#include "types.h"
+#include "protos.h"
+#include "server.h"
+
+
+/****** support/Get_OpenMax **************************************************
+*
+* NAME
+* Get_OpenMax -- get the maximum of file descriptors per process.
+*
+* SYNOPSIS
+* int Get_OpenMax( void );
+*
+* FUNCTION
+* Get the systems maximum number of file descriptors per process. Uses
+* OPEN_MAX -- if defined -- else asks the system per sysconf() call.
+* If this still doesn't succeed, returns some kind of "reasonable
+* default".
+*
+* INPUTS
+* openmax - A global variable that holds the value of OPEN_MAX,
+* if defined, else '0'.
+*
+* RESULT
+* Returns the number of file descriptors, may be zero or a positive
+* int value.
+* openmax will be set to an appropriate value if it was set to '0'
+* when Get_OpenMax() was called.
+*
+* NOTES
+* Uses ErrMsg() to report problems with sysconf(). Hmmm...
+*
+* BUGS
+* Does also return the guessed value if sysconf() reported an error.
+* This seems to be okay for my needs...
+*
+* SEE ALSO
+* Richard W. Stevens: "Advanced Programming in the UNIX Environment",
+* 1992 Addison-Wesley Publishing Company, Inc.
+*
+******************************************************************************
+*
+*/
+
+#ifdef OPEN_MAX
+static size_t openmax = OPEN_MAX; /* Wenn vorhanden, dann ist das alles */
+#else /* was gebraucht wird. */
+static size_t openmax = 0;
+#endif
+
+#ifdef NOFILE
+#define OPEN_MAX_GUESS NOFILE
+#else
+#define OPEN_MAX_GUESS 256 /* Falls OPEN_MAX undefiniert (dynamisch) */
+#endif /* ist, ist dies u.U. nicht adaequat! */
+
+int Get_OpenMax( void )
+{
+ if( openmax == 0 )
+ {
+ errno = 0;
+ if( ( openmax = sysconf( _SC_OPEN_MAX ) ) < 0 )
+ {
+ if( errno == 0 )
+ {
+ openmax = OPEN_MAX_GUESS;
+ }
+ else
+ {
+ /* sysconf() returned an error... strange, but... */
+ /* Does it justify to break the program? */
+ /* Naah, I don't think so... So we just print a note */
+ /* and give back our "reasonable default"... */
+ ErrorMsg( E_SYS, WARN, "WARN: sysconf error for _SC_OPEN_MAX." );
+ openmax = OPEN_MAX_GUESS;
+ }
+ }
+ }
+
+ return( openmax );
+}
+
+
+/****** support/PathAlloc ****************************************************
+*
+* NAME
+* PathAlloc -- allocate memory as buffer for pathnames.
+*
+* SYNOPSIS
+* char *PathAlloc( size_t *size );
+*
+* FUNCTION
+* Get the systems maximum of characters in absolute pathnames. Uses
+* PATH_MAX -- if defined -- else asks the system per pathconf() call.
+* If this still doesn't succeed, uses some kind of "reasonable
+* default".
+* Then it calls malloc() to allocate the buffer.
+*
+* INPUTS
+* size - A pointer to a variable, which will set to the size of
+* the buffer. If it is NULL, you won't get any size
+* information.
+* pathmax - A global variable that holds the value of PATH_MAX,
+* if defined, else '0'
+*
+* RESULT
+* Returns a "char" pointer to the allocated buffer.
+* NULL, if the allocation failed. Then it will also print a log
+* message.
+* pathmax will be set to an appropriate value if it was set to '0'
+* when PathAlloc() was called.
+*
+* NOTES
+* Uses ErrMsg() to report problems with pathconf() and malloc().
+*
+* BUGS
+* Does also use the guessed value if pathconf() reported an error.
+* This seems to be okay for my needs...
+*
+* SEE ALSO
+* Richard W. Stevens: "Advanced Programming in the UNIX Environment",
+* 1992 Addison-Wesley Publishing Company, Inc.
+*
+******************************************************************************
+*
+*/
+
+#ifdef PATH_MAX
+static size_t pathmax = PATH_MAX; /* Wenn vorhanden, dann ist das alles */
+#else /* was gebraucht wird. */
+static size_t pathmax = 0;
+#endif
+
+#ifdef MAXPATHLEN
+#define PATH_MAX_GUESS MAXPATHLEN
+#else
+#define PATH_MAX_GUESS 1024 /* Falls PATH_MAX undefiniert (dynamisch) */
+#endif /* ist, ist dies u.U. nicht adäquat! */
+
+char *PathAlloc( size_t *size )
+{
+ char *Ptr;
+
+ if( pathmax == 0 )
+ {
+ errno = 0;
+ if( ( pathmax = pathconf( "/", _PC_PATH_MAX ) ) < 0 )
+ {
+ if( errno == 0 )
+ {
+ pathmax = PATH_MAX_GUESS;
+ }
+ else
+ {
+ /* pathconf() returned an error... strange, but... */
+ /* See also Get_OpenMax(). */
+ /* We give back our "reasonable default"... */
+ ErrorMsg( E_SYS, WARN, "WARN: pathconf error for _PC_PATH_MAX." );
+ pathmax = PATH_MAX_GUESS;
+ }
+ }
+ }
+ else
+ {
+ // it appears that every call makes the path 1 byte longer. Anyway, the config file
+ // is not read too often and I am not willing to debug it now
+ pathmax++; /* Don't forget the "/" character... */
+ }
+
+ if( ( Ptr = (char*)mymalloc( pathmax + 1 ) ) == NULL )
+ {
+ if( size != NULL )
+ *size = 0;
+ ErrorMsg( E_SYS, ERROR, "ERROR: malloc error for pathname buffer." );
+ }
+ else
+ {
+ if( size != NULL )
+ *size = pathmax + 1;
+ }
+ return( Ptr );
+}
+
+
+/****** support/ReadN ********************************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+/**************************************************************************
+ * Read "n" bytes from a descriptor.
+ * Use in place of read() when fd is a stream socket.
+ * Checks for error 'EAGAIN', in case of nonblocking IO.
+ */
+
+int ReadN( register int fd, register char *ptr, register int nbytes )
+{
+ int nleft;
+ int nread;
+
+ nleft = nbytes;
+ while( nleft > 0 )
+ {
+ nread = read( fd, ptr, nleft );
+ if( nread < 0 )
+ if( errno != EAGAIN )
+ return( nread ); /* error, return < 0 */
+ else
+ continue;
+ else if( nread == 0 )
+ break; /* EOF */
+ nleft -= nread;
+ ptr += nread;
+ }
+ return( nbytes - nleft ); /* return >= 0 */
+}
+
+
+/****** support/WriteN *******************************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+/**************************************************************************
+ * Write "n" bytes to a descriptor.
+ * Use in place of write() when fd is a stream socket.
+ * Checks for error 'EAGAIN', in case of nonblocking IO.
+ */
+
+int WriteN( register int fd, register char *ptr, register int nbytes )
+{
+ long nleft;
+ long nwritten = 0;
+
+ nleft = nbytes;
+ while( nleft > 0 )
+ {
+ nwritten = write( fd, ptr, nleft );
+ if( nwritten < 0 )
+ {
+ if( errno != EAGAIN )
+ return( nwritten ); /* error */
+ else
+ continue;
+ }
+ nleft -= nwritten;
+ ptr += nwritten;
+ }
+ return( nbytes - nleft );
+}
+
+
+/****** support/ReadLine *****************************************************
+*
+* NAME
+*
+*
+* SYNOPSIS
+*
+*
+* FUNCTION
+*
+*
+* INPUTS
+*
+*
+* RESULT
+*
+*
+* NOTES
+*
+*
+* BUGS
+*
+*
+* SEE ALSO
+*
+*
+******************************************************************************
+*
+*/
+/**************************************************************************
+ * Read a line from a descriptor.
+ * Checks for error 'EAGAIN', in case of nonblocking IO.
+ */
+
+int ReadLine( register int fd, register char *ptr, register int maxlen )
+{
+ int n;
+ int rc;
+ char c;
+
+ for( n = 1; n < maxlen; n++ )
+ {
+ if( ( rc = read( fd, &c, 1 ) ) == 1 )
+ {
+ *ptr++ = c;
+ if( c == '\n' )
+ break;
+ }
+ else if( rc == 0 )
+ if( n == 1 )
+ return( 0 ); /* EOF, no data read */
+ else
+ break; /* EOF, some data was read */
+ else
+ if( errno != EAGAIN )
+ return( -1 ); /* error */
+ }
+ *ptr = 0;
+ return( n );
+}
+
+
+/****** support/ParseString **************************************************
+*
+* NAME
+* ParseString -- Break string into words.
+*
+* SYNOPSIS
+* int ParseString( char *String, char *Token, ... );
+*
+* FUNCTION
+*
+* RESULT
+*
+* NOTES
+*
+* BUGS
+*
+* SEE ALSO
+*
+******************************************************************************
+*
+*/
+
+rc_t ParseString( char *String, char *Token, ... )
+{
+ /* ###TODO: Das letzte Argument sollte den kompletten Reststring erhalten */
+ /* Buffer loeschen vor Austritt */
+ va_list ArgPtr;
+ char *Keyword;
+ char *Value;
+ char *NextToken;
+ char *NNextToken;
+ char *Delim = " \t\n\r"; /* Begrenzungszeichen */
+
+ if( ( String[0] == '#' ) || /* Kommentar, */
+ ( String[0] == '\n' ) || /* oder Leerzeile? */
+ ( String[0] == '\r' ) )
+ return( ERROR ); /* => Zurück. */
+
+ Keyword = strtok( String, Delim ); /* 1. Token suchen */
+ if( Keyword != NULL ) /* Etwas gefunden? */
+ {
+ if( Keyword[0] == '#' ) /* Auch Kommentarzeile: */
+ return( ERROR ); /* => Zurück. */
+ strcpy( Token, Keyword ); /* Keyword in Buffer kopieren */
+
+ /* Var.Arg. Liste abarbeiten bis Arg == NULL. */
+ /* Letztes Arg. muss NULL sein, da va_arg() nicht selbst in der Lage */
+ /* ist das letzte Argument zu erkennen. */
+
+ va_start( ArgPtr, Token ); /* VarArg initialisieren */
+ NextToken = va_arg( ArgPtr, char * ); /* 1. zus. Argument holen. */
+ if( NextToken != NULL)
+ {
+ NNextToken = va_arg( ArgPtr, char * ); /* 2. zus. Arg. holen */
+ while( NNextToken != NULL ) /* Argument vorhanden? */
+ {
+ Value = strtok( NULL, Delim ); /* Weiteres Token suchen */
+ if( Value != NULL ) /* Wort gefunden? */
+ strcpy( NextToken, Value ); /* Token in Buffer kopieren */
+ else /* Ansonsten: */
+ strcpy( NextToken, "\0" ); /* Leerstring uebergeben */
+ NextToken = NNextToken;
+ NNextToken = va_arg( ArgPtr, char * ); /* Zeiger auf nächstes Arg. */
+ }
+ Value = strtok( NULL, "\n\r" ); /* Zeiger auf Reststring holen */
+ if( Value != NULL ) /* Wenn vorhanden, */
+ strcpy( NextToken, Value ); /* in letztes Arg. übergeben */
+ else /* wenn nicht, */
+ strcpy( NextToken, "\0" ); /* Leerstring übergeben */
+ }
+ va_end( ArgPtr ); /* VarArg aufräumen */
+ return( OK ); /* OK: Es wurde etwas gefunden */
+ }
+ return( ERROR ); /* ERROR: String war leer. */
+}
+
+
+/****** support/SNPrintf *****************************************************
+*
+* NAME
+* SNPrintf -- print into buffer with size-check.
+*
+* SYNOPSIS
+* int SNPrintf( char *String, size_t *Size, const char *Format, ... );
+*
+* FUNCTION
+*
+* RESULT
+*
+* NOTES
+*
+* BUGS
+*
+* SEE ALSO
+*
+******************************************************************************
+*
+*/
+
+int SNPrintf( char *String, size_t *Size, const char *Format, ... )
+{
+ va_list ArgPtr;
+ int n = 0;
+
+ if( *Size > 0 )
+ {
+ va_start( ArgPtr, Format );
+ n = VSNPrintf( String, *Size, Format, ArgPtr );
+ va_end( ArgPtr );
+
+ if( n >= 0 )
+ *Size = *Size - n;
+ else
+ *Size = 0;
+ }
+ return( n );
+}
+
+
+/****** support/VSNPrintf ****************************************************
+*
+* NAME
+* VSNPrintf -- print variable argument list into buffer with size-check.
+*
+* SYNOPSIS
+* int VSNPrintf( char *String, size_t Size,
+* const char *Format, va_list ArgPtr );
+*
+* FUNCTION
+*
+* RESULT
+*
+* NOTES
+*
+* BUGS
+*
+* SEE ALSO
+*
+******************************************************************************
+*
+*/
+
+int VSNPrintf( char *String, size_t Size, const char *Format, va_list ArgPtr )
+{
+ int n = 0;
+ char *Buffer = NULL;
+
+#ifdef NO_vsnprintf
+ if( Size == 0 )
+ n = 0;
+ else if( Size > 0 )
+ {
+ if( ( Buffer = (char*)mymalloc( BUFFSIZE ) ) != NULL )
+ {
+ n = vsprintf( Buffer, Format, ArgPtr );
+ if( n < Size )
+ strncpy( String, Buffer, Size );
+ else
+ {
+ strncpy( String, Buffer, Size-1 );
+ *( String + Size ) = '\0';
+ n = -1;
+ }
+ free( Buffer );
+ }
+ else
+ n = -1;
+ }
+ else
+ n = -1;
+#else
+ n = vsnprintf( String, Size, Format, ArgPtr );
+#endif
+ return( n );
+}
+
+
+/****** support/StrError *****************************************************
+*
+* NAME
+* StrError - return error string for given error code.
+*
+* SYNOPSIS
+* char *StrError( int ErrNum );
+*
+* FUNCTION
+*
+* RESULT
+*
+* NOTES
+*
+* BUGS
+*
+* SEE ALSO
+*
+******************************************************************************
+*
+*/
+
+char *StrError( int ErrNum )
+{
+#ifdef NO_strerror
+ char Buffer[20];
+
+ bzero( Buffer, 20 );
+ sprintf( Buffer, "Error %d", ErrNum );
+ return( Buffer );
+#else
+ return( strerror( ErrNum ) );
+#endif
+}
+
+/****** support/StrToLower ***************************************************
+*
+* NAME
+* StrToLower - make all characters of a string lower case.
+*
+* SYNOPSIS
+* char *StrToLower( char *String );
+*
+* FUNCTION
+*
+* RESULT
+*
+* NOTES
+*
+* BUGS
+*
+* SEE ALSO
+*
+******************************************************************************
+*
+*/
+
+char *StrToLower( char *String )
+{
+ while( *String != '\0' )
+ {
+ *String = tolower( *String );
+ String++;
+ }
+ return( String );
+}
diff --git a/httpserver/test/Makefile b/httpserver/test/Makefile
new file mode 100644
index 0000000..2fef649
--- /dev/null
+++ b/httpserver/test/Makefile
@@ -0,0 +1,63 @@
+# -*-Makefile-*- (for Emacs)
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>. # Top Level makefile. This points to the various modules that have to be build
+# and/or deployed
+#
+# MAKEFILE FOR:
+# a RasDaMan module
+#
+# COMMENTS:
+# This Makefile was created during the relational port when
+# splitting up catalogif into O2 dependent und not O2 dependent.
+#
+# IMPORTANT:
+# As opposed to all other Makefiles catalogmgr does not have
+# its own library. catalogif is used instead, otherwise the
+# linking of all executables would have had to be changed.
+#
+##################################################################
+
+#
+# IMPORTANT:
+# This is an example Makefile, it has to be adapted for
+# every module. This is usually done by editing the
+# following:
+# * variables OBJS, TESTOBJS and TESTPRG
+# * the dependencies at the end
+# * every occurence of EXLIB
+# * the toplevel Makefile and Makefile.inc
+#
+
+######################### Definitions ############################
+
+# standard include with general options
+include $(RMANBASE)/Makefile.inc
+
+MISCCLEAN := core
+
+########################### Targets ##############################
+
+# general rules
+include $(RMANBASE)/Makefile.rel
+
+# automatically created dependencies
+include Makefile.dep
diff --git a/httpserver/test/httpserver.conf b/httpserver/test/httpserver.conf
new file mode 100644
index 0000000..63ae3fd
--- /dev/null
+++ b/httpserver/test/httpserver.conf
@@ -0,0 +1,14 @@
+#
+# httpserver Configuration file
+#
+ServerName: sunwibas13.forwiss.tu-muenchen.de
+Port: 8080
+
+ServerAdmin: zoller@forwiss.tu-muenchen.de
+
+ServerRoot: /home/sunwibas13/wiss/zoller/RASDAMAN/httpserver/test
+AccessLog: /home/sunwibas13/wiss/zoller/RASDAMAN/httpserver/test/access.log
+ServerLog: /home/sunwibas13/wiss/zoller/RASDAMAN/httpserver/test/server.log
+PidFile: /home/sunwibas13/wiss/zoller/RASDAMAN/httpserver/test/httpserver.pid
+MaxURLLength: 120
+
diff --git a/httpserver/test/post_test.html b/httpserver/test/post_test.html
new file mode 100644
index 0000000..46aab47
--- /dev/null
+++ b/httpserver/test/post_test.html
@@ -0,0 +1,116 @@
+<HEAD>
+<TITLE>Error</TITLE>
+</HEAD>
+
+<BODY>
+<H1>IMPORTANT NOTE</H1>
+
+<P>Unfortunately requests to the RasDaMan HTTP server are cached by
+ default. Be sure to disable the proxy in your webserver and also
+ disable the internal cache by telling the browser to verify the
+ document every time.</P>
+
+
+<CENTER>
+<P>
+<BR>
+<H1>Test for Post-Request: Client is Browser</H1>
+
+<FORM ACTION="http://sunwibas0.forwiss.tu-muenchen.de:8080" METHOD=POST>
+<INPUT TYPE=HIDDEN NAME="Database" VALUE="NorbertBase">
+<INPUT TYPE=HIDDEN NAME="QueryString" VALUE="SELECT img FROM test_image AS img">
+<INPUT TYPE=HIDDEN NAME="ClientType" VALUE="BROWSER">
+
+<INPUT TYPE=SUBMIT VALUE="Test: Everything correct!">
+</FORM>
+<P>
+
+<FORM ACTION="http://sunwibas0.forwiss.tu-muenchen.de:8080" METHOD=POST>
+<INPUT TYPE=HIDDEN NAME="Database" VALUE="NorbertBase">
+<INPUT TYPE=HIDDEN NAME="QueryString" VALUE="SELECT img FROM test_image AS img">
+<INPUT TYPE=HIDDEN NAME="ClientType" VALUE="xyz">
+
+<INPUT TYPE=SUBMIT VALUE="Test: Wrong Client Type">
+</FORM>
+<P>
+
+<FORM ACTION="http://sunwibas0.forwiss.tu-muenchen.de:8080" METHOD=POST>
+<INPUT TYPE=HIDDEN NAME="Database" VALUE="NorbertBase">
+<INPUT TYPE=HIDDEN NAME="ClientType" VALUE="BROWSER">
+<INPUT TYPE=HIDDEN NAME="TestParam" VALUE="wfwef">
+
+<INPUT TYPE=SUBMIT VALUE="Test: Unknown Post Parameters">
+</FORM>
+<P>
+
+<P>
+<A HREF="http://sunwibas0.forwiss.tu-muenchen.de:8080/">Get-request</A>
+
+
+<H1>Testing different return types</H1>
+
+<FORM ACTION="http://sunwibas0.forwiss.tu-muenchen.de:8080" METHOD=POST>
+<INPUT TYPE=HIDDEN NAME="Database" VALUE="NorbertBase">
+<INPUT TYPE=HIDDEN NAME="QueryString" VALUE="SELECT count_cells(img > 9l) FROM test_image AS img">
+<INPUT TYPE=HIDDEN NAME="ClientType" VALUE="RASCLIENT">
+
+<INPUT TYPE=SUBMIT VALUE="Returns scalar">
+</FORM>
+<P>
+
+<FORM ACTION="http://sunwibas0.forwiss.tu-muenchen.de:8080" METHOD=POST>
+<INPUT TYPE=HIDDEN NAME="Database" VALUE="NorbertBase">
+<INPUT TYPE=HIDDEN NAME="QueryString" VALUE="SELECT sdom(img) FROM test_image AS img">
+<INPUT TYPE=HIDDEN NAME="ClientType" VALUE="RASCLIENT">
+
+<INPUT TYPE=SUBMIT VALUE="Returns spatial domain">
+</FORM>
+<P>
+
+<FORM ACTION="http://sunwibas0.forwiss.tu-muenchen.de:8080" METHOD=POST>
+<INPUT TYPE=HIDDEN NAME="Database" VALUE="NorbertBase">
+<INPUT TYPE=HIDDEN NAME="QueryString" VALUE="SELECT grmblfx(img) FROM test_image AS img">
+<INPUT TYPE=HIDDEN NAME="ClientType" VALUE="RASCLIENT">
+
+<INPUT TYPE=SUBMIT VALUE="Returns error">
+</FORM>
+<P>
+
+<FORM ACTION="http://sunwibas0.forwiss.tu-muenchen.de:8080" METHOD=POST>
+<INPUT TYPE=HIDDEN NAME="Database" VALUE="NorbertBase">
+<INPUT TYPE=HIDDEN NAME="QueryString" VALUE="SELECT img FROM rockies AS img">
+<INPUT TYPE=HIDDEN NAME="ClientType" VALUE="RASCLIENT">
+
+<INPUT TYPE=SUBMIT VALUE="Retrieve whole rockies">
+</FORM>
+<P>
+
+<P>
+
+
+<H1>Test for Post-Request: Client is RasClient</H1>
+
+<FORM ACTION="http://sunwibas0.forwiss.tu-muenchen.de:8080" METHOD=POST>
+<INPUT TYPE=HIDDEN NAME="Database" VALUE="NorbertBase">
+<INPUT TYPE=HIDDEN NAME="QueryString" VALUE="SELECT img FROM test_image AS img">
+<INPUT TYPE=HIDDEN NAME="ClientType" VALUE="RASCLIENT">
+
+<INPUT TYPE=SUBMIT VALUE="Test: Everything correct!">
+</FORM>
+<P>
+
+<FORM ACTION="http://sunwibas0.forwiss.tu-muenchen.de:8080" METHOD=POST>
+<INPUT TYPE=HIDDEN NAME="Database" VALUE="NorbertBase">
+<INPUT TYPE=HIDDEN NAME="ClientType" VALUE="RASCLIENT">
+<INPUT TYPE=HIDDEN NAME="TestParam" VALUE="wfwef">
+
+<INPUT TYPE=SUBMIT VALUE="Test: Unknown Post Parameters">
+</FORM>
+<P>
+
+
+
+</CENTER>
+
+</BODY>
+
diff --git a/httpserver/types.h b/httpserver/types.h
new file mode 100644
index 0000000..dab5bb0
--- /dev/null
+++ b/httpserver/types.h
@@ -0,0 +1,38 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*------------------------------------------------------------------------*/
+/* types.h - data types. */
+/*------------------------------------------------------------------------*/
+/*
+ * RCS:
+ * $RCSfile: types.h,v $ $Revision: 1.1 $ $State: Exp $
+ * $Locker: $
+ */
+
+#ifndef _TYPES_H
+#define _TYPES_H
+
+typedef struct SubServerBase *SubServerPtr;
+typedef int rc_t;
+
+#endif /* _TYPES_H not defined */
diff --git a/include/basictypes.hh b/include/basictypes.hh
new file mode 100644
index 0000000..8148208
--- /dev/null
+++ b/include/basictypes.hh
@@ -0,0 +1,207 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+//------------------------------------------------------------
+// This file is created automatically by the rasdl processor.
+//
+// DO NOT EDIT
+//------------------------------------------------------------
+
+#ifndef __BASICTYPES_HH_
+#define __BASICTYPES_HH_
+
+//------------------------------------------------------------
+// Includes
+//------------------------------------------------------------
+
+#include "rasdaman.hh"
+
+/*[2,25]*//* TYPEDEF ------------------------- GreyImage */
+typedef r_Marray<r_Char> GreyImage;
+
+/*[3,24]*//* TYPEDEF ------------------------- GreySet */
+typedef r_Set<r_Ref<GreyImage> > GreySet;
+
+/*[6,28]*//* TYPEDEF ------------------------- BoolImage */
+typedef r_Marray<r_Boolean> BoolImage;
+
+/*[7,24]*//* TYPEDEF ------------------------- BoolSet */
+typedef r_Set<r_Ref<BoolImage> > BoolSet;
+
+/*[10,1]*//* STRUCT -------------------------- RGBPixel */
+struct RGBPixel {
+ r_Char red;
+ r_Char green;
+ r_Char blue;
+};
+/*[11,29]*//* TYPEDEF ------------------------- RGBImage */
+typedef r_Marray<RGBPixel> RGBImage;
+
+/*[12,23]*//* TYPEDEF ------------------------- RGBSet */
+typedef r_Set<r_Ref<RGBImage> > RGBSet;
+
+/*[15,35]*//* TYPEDEF ------------------------- ULongImage */
+typedef r_Marray<r_ULong > ULongImage;
+
+/*[16,25]*//* TYPEDEF ------------------------- ULongSet */
+typedef r_Set<r_Ref<ULongImage> > ULongSet;
+
+/*[19,26]*//* TYPEDEF ------------------------- GreyCube */
+typedef r_Marray<r_Char> GreyCube;
+
+/*[20,23]*//* TYPEDEF ------------------------- GreySet3 */
+typedef r_Set<r_Ref<GreyCube> > GreySet3;
+
+/*[24,29]*//* TYPEDEF ------------------------- BoolString */
+typedef r_Marray<r_Boolean> BoolString;
+
+/*[25,25]*//* TYPEDEF ------------------------- BoolSet1 */
+typedef r_Set<r_Ref<BoolString> > BoolSet1;
+
+/*[27,29]*//* TYPEDEF ------------------------- BoolCube */
+typedef r_Marray<r_Boolean> BoolCube;
+
+/*[28,23]*//* TYPEDEF ------------------------- BoolSet3 */
+typedef r_Set<r_Ref<BoolCube> > BoolSet3;
+
+/*[30,26]*//* TYPEDEF ------------------------- GreyString */
+typedef r_Marray<r_Char> GreyString;
+
+/*[31,25]*//* TYPEDEF ------------------------- GreySet1 */
+typedef r_Set<r_Ref<GreyString> > GreySet1;
+
+/*[33,27]*//* TYPEDEF ------------------------- ShortString */
+typedef r_Marray<r_Short > ShortString;
+
+/*[34,26]*//* TYPEDEF ------------------------- ShortSet1 */
+typedef r_Set<r_Ref<ShortString> > ShortSet1;
+
+/*[36,27]*//* TYPEDEF ------------------------- ShortImage */
+typedef r_Marray<r_Short > ShortImage;
+
+/*[37,25]*//* TYPEDEF ------------------------- ShortSet */
+typedef r_Set<r_Ref<ShortImage> > ShortSet;
+
+/*[39,27]*//* TYPEDEF ------------------------- ShortCube */
+typedef r_Marray<r_Short > ShortCube;
+
+/*[40,24]*//* TYPEDEF ------------------------- ShortSet3 */
+typedef r_Set<r_Ref<ShortCube> > ShortSet3;
+
+/*[42,36]*//* TYPEDEF ------------------------- UShortString */
+typedef r_Marray<r_UShort > UShortString;
+
+/*[43,27]*//* TYPEDEF ------------------------- UShortSet1 */
+typedef r_Set<r_Ref<UShortString> > UShortSet1;
+
+/*[45,36]*//* TYPEDEF ------------------------- UShortImage */
+typedef r_Marray<r_UShort > UShortImage;
+
+/*[46,26]*//* TYPEDEF ------------------------- UShortSet */
+typedef r_Set<r_Ref<UShortImage> > UShortSet;
+
+/*[48,36]*//* TYPEDEF ------------------------- UShortCube */
+typedef r_Marray<r_UShort > UShortCube;
+
+/*[49,25]*//* TYPEDEF ------------------------- UShortSet3 */
+typedef r_Set<r_Ref<UShortCube> > UShortSet3;
+
+/*[51,26]*//* TYPEDEF ------------------------- LongString */
+typedef r_Marray<r_Long > LongString;
+
+/*[52,25]*//* TYPEDEF ------------------------- LongSet1 */
+typedef r_Set<r_Ref<LongString> > LongSet1;
+
+/*[54,26]*//* TYPEDEF ------------------------- LongImage */
+typedef r_Marray<r_Long > LongImage;
+
+/*[55,24]*//* TYPEDEF ------------------------- LongSet */
+typedef r_Set<r_Ref<LongImage> > LongSet;
+
+/*[57,26]*//* TYPEDEF ------------------------- LongCube */
+typedef r_Marray<r_Long > LongCube;
+
+/*[58,23]*//* TYPEDEF ------------------------- LongSet3 */
+typedef r_Set<r_Ref<LongCube> > LongSet3;
+
+/*[60,35]*//* TYPEDEF ------------------------- ULongString */
+typedef r_Marray<r_ULong > ULongString;
+
+/*[61,26]*//* TYPEDEF ------------------------- ULongSet1 */
+typedef r_Set<r_Ref<ULongString> > ULongSet1;
+
+/*[63,35]*//* TYPEDEF ------------------------- ULongCube */
+typedef r_Marray<r_ULong > ULongCube;
+
+/*[64,24]*//* TYPEDEF ------------------------- ULongSet3 */
+typedef r_Set<r_Ref<ULongCube> > ULongSet3;
+
+/*[66,30]*//* TYPEDEF ------------------------- RGBString */
+typedef r_Marray<RGBPixel> RGBString;
+
+/*[67,24]*//* TYPEDEF ------------------------- RGBSet1 */
+typedef r_Set<r_Ref<RGBString> > RGBSet1;
+
+/*[69,30]*//* TYPEDEF ------------------------- RGBCube */
+typedef r_Marray<RGBPixel> RGBCube;
+
+/*[70,22]*//* TYPEDEF ------------------------- RGBSet3 */
+typedef r_Set<r_Ref<RGBCube> > RGBSet3;
+
+/*[72,27]*//* TYPEDEF ------------------------- FloatString */
+typedef r_Marray<r_Float> FloatString;
+
+/*[73,26]*//* TYPEDEF ------------------------- FloatSet1 */
+typedef r_Set<r_Ref<FloatString> > FloatSet1;
+
+/*[75,27]*//* TYPEDEF ------------------------- FloatImage */
+typedef r_Marray<r_Float> FloatImage;
+
+/*[76,25]*//* TYPEDEF ------------------------- FloatSet */
+typedef r_Set<r_Ref<FloatImage> > FloatSet;
+
+/*[78,27]*//* TYPEDEF ------------------------- FloatCube */
+typedef r_Marray<r_Float> FloatCube;
+
+/*[79,24]*//* TYPEDEF ------------------------- FloatSet3 */
+typedef r_Set<r_Ref<FloatCube> > FloatSet3;
+
+/*[81,28]*//* TYPEDEF ------------------------- DoubleString */
+typedef r_Marray<r_Double> DoubleString;
+
+/*[82,27]*//* TYPEDEF ------------------------- DoubleSet1 */
+typedef r_Set<r_Ref<DoubleString> > DoubleSet1;
+
+/*[84,28]*//* TYPEDEF ------------------------- DoubleImage */
+typedef r_Marray<r_Double> DoubleImage;
+
+/*[85,26]*//* TYPEDEF ------------------------- DoubleSet */
+typedef r_Set<r_Ref<DoubleImage> > DoubleSet;
+
+/*[87,28]*//* TYPEDEF ------------------------- DoubleCube */
+typedef r_Marray<r_Double> DoubleCube;
+
+/*[88,25]*//* TYPEDEF ------------------------- DoubleSet3 */
+typedef r_Set<r_Ref<DoubleCube> > DoubleSet3;
+
+#endif
diff --git a/include/basictypes.odl b/include/basictypes.odl
new file mode 100644
index 0000000..ec1884c
--- /dev/null
+++ b/include/basictypes.odl
@@ -0,0 +1,112 @@
+// example 1
+typedef marray <char,2> GreyImage;
+typedef set<GreyImage> GreySet;
+
+// example 2
+typedef marray <boolean,2> BoolImage;
+typedef set<BoolImage> BoolSet;
+
+// example 3
+struct RGBPixel { char red, green, blue; };
+typedef marray <RGBPixel,2> RGBImage;
+typedef set<RGBImage> RGBSet;
+
+// example 4
+typedef marray <unsigned long, 2> ULongImage;
+typedef set<ULongImage> ULongSet;
+
+// example 5
+typedef marray <char, 3> GreyCube;
+typedef set<GreyCube> GreySet3;
+
+
+// heavily expanded types (Andreas)
+typedef marray <boolean, 1> BoolString;
+typedef set<BoolString> BoolSet1;
+
+typedef marray <boolean, 3> BoolCube;
+typedef set<BoolCube> BoolSet3;
+
+typedef marray <char, 1> GreyString;
+typedef set<GreyString> GreySet1;
+
+typedef marray <octet, 1> OctetString;
+typedef set<OctetString> OctetSet1;
+
+typedef marray <octet, 2> OctetImage;
+typedef set<OctetImage> OctetSet;
+
+typedef marray <octet, 3> OctetCube;
+typedef set<OctetCube> OctetSet3;
+
+typedef marray <short, 1> ShortString;
+typedef set<ShortString> ShortSet1;
+
+typedef marray <short, 2> ShortImage;
+typedef set<ShortImage> ShortSet;
+
+typedef marray <short, 3> ShortCube;
+typedef set<ShortCube> ShortSet3;
+
+typedef marray <unsigned short, 1> UShortString;
+typedef set<UShortString> UShortSet1;
+
+typedef marray <unsigned short, 2> UShortImage;
+typedef set<UShortImage> UShortSet;
+
+typedef marray <unsigned short, 3> UShortCube;
+typedef set<UShortCube> UShortSet3;
+
+typedef marray <long, 1> LongString;
+typedef set<LongString> LongSet1;
+
+typedef marray <long, 2> LongImage;
+typedef set<LongImage> LongSet;
+
+typedef marray <long, 3> LongCube;
+typedef set<LongCube> LongSet3;
+
+typedef marray <unsigned long, 1> ULongString;
+typedef set<ULongString> ULongSet1;
+
+typedef marray <unsigned long, 3> ULongCube;
+typedef set<ULongCube> ULongSet3;
+
+typedef marray <RGBPixel, 1> RGBString;
+typedef set<RGBString> RGBSet1;
+
+typedef marray <RGBPixel, 3> RGBCube;
+typedef set<RGBCube> RGBSet3;
+
+typedef marray <float, 1> FloatString;
+typedef set<FloatString> FloatSet1;
+
+typedef marray <float, 2> FloatImage;
+typedef set<FloatImage> FloatSet;
+
+typedef marray <float, 3> FloatCube;
+typedef set<FloatCube> FloatSet3;
+
+typedef marray <float, 4> FloatCube4;
+typedef set<FloatCube4> FloatSet4;
+
+typedef marray <double, 1> DoubleString;
+typedef set<DoubleString> DoubleSet1;
+
+typedef marray <double, 2> DoubleImage;
+typedef set<DoubleImage> DoubleSet;
+
+typedef marray <double, 3> DoubleCube;
+typedef set<DoubleCube> DoubleSet3;
+
+typedef marray <complex, 1> Gauss1;
+typedef set<Gauss1> GaussSet1;
+
+typedef marray<complexd, 1> Gauss2;
+typedef set<Gauss2> GaussSet2;
+
+typedef marray <complex, 2> Gauss1Image;
+typedef set<Gauss1Image> Gauss1Set;
+
+typedef marray<complexd, 2> Gauss2Image;
+typedef set<Gauss2Image> Gauss2Set;
diff --git a/include/bool.h b/include/bool.h
new file mode 100644
index 0000000..c8cf406
--- /dev/null
+++ b/include/bool.h
@@ -0,0 +1,23 @@
+/*
+ *
+ * Copyright (c) 1994
+ * Hewlett-Packard Company
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Hewlett-Packard Company makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
+
+// most systems should have bool defined now (Sun CC 5.0, g++), it is in the
+// ANSI standard.
+
+#ifdef OS_HPUX_10
+#define bool int
+#endif
+#define true 1
+#define false 0
diff --git a/include/globals.hh b/include/globals.hh
new file mode 100644
index 0000000..e64392b
--- /dev/null
+++ b/include/globals.hh
@@ -0,0 +1,77 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: globals.hh
+ *
+ * MODULE: rasdaman
+ * CLASS: Globals
+ *
+ * PURPOSE:
+ * This class provides basic constants used across rasdaman.
+ * Any value that is of external importance (default names, timeouts, ...)
+ * but are NOT TO BE DELIVERED should be defined here.
+ *
+ * COMMENTS:
+ * - make this a real class
+ * - successively collect all important values here
+ *
+*/
+
+#ifndef GLOBALS_HH
+#define GLOBALS_HH
+
+/// default rasmgr listen port
+#define DEFAULT_PORT 7001
+
+/// name of env var pointing to rasdaman home dir (ex: "/opt/rasdaman")
+#define RMANHOME_VAR "RMANHOME"
+
+/// default name of server machine, if gethostname() fails
+#define DEFAULT_HOSTNAME "localhost"
+
+/// default database name
+#define DEFAULT_DBNAME "RASBASE"
+
+/// name of rasmgr configuration file
+#define RASMGR_CONF_FILE "rasmgr.conf"
+
+/// default r/o login name for client tools
+#define DEFAULT_USER "rasguest"
+/// default password for this user
+#define DEFAULT_PASSWD "rasguest"
+
+/// server log directory
+#define LOGDIR "/log"
+/// server alternative log directory, if RMANHOME not specified, defined via autoconf/automake
+#define ALT_LOGDIR ABSOLUTE_LOG_DIR
+/// log file suffix
+#define LOG_SUFFIX "log"
+
+/// max transfer buffer size (import clients)
+#define MAX_BUFFER_SIZE 4194304L
+
+/// client timeout [secs]
+#define CLIENT_TIMEOUT 300
+
+#endif // GLOBALS_HH
+
diff --git a/include/rasdaman.hh b/include/rasdaman.hh
new file mode 100644
index 0000000..8c983c9
--- /dev/null
+++ b/include/rasdaman.hh
@@ -0,0 +1,70 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+//------------------------------------------------------------
+// RasDaMan Standard Include
+//
+// DO NOT EDIT
+//------------------------------------------------------------
+
+#ifndef __RASDAMAN_HH_
+#define __RASDAMAN_HH_
+
+//------------------------------------------------------------
+// Includes
+//------------------------------------------------------------
+
+#include "rasodmg/ref.hh"
+#include "rasodmg/transaction.hh"
+#include "rasodmg/database.hh"
+#include "rasodmg/set.hh"
+#include "rasodmg/iterator.hh"
+#include "rasodmg/marray.hh"
+#include "rasodmg/oqlquery.hh"
+#include "rasodmg/storagelayout.hh"
+#include "rasodmg/alignedtiling.hh"
+#include "rasodmg/interesttiling.hh"
+#include "rasodmg/dirtiling.hh"
+#include "rasodmg/stattiling.hh"
+
+#include "raslib/endian.hh"
+#include "raslib/odmgtypes.hh"
+#include "raslib/mddtypes.hh"
+#include "raslib/oid.hh"
+#include "raslib/type.hh"
+#include "raslib/minterval.hh"
+#include "raslib/primitive.hh"
+#include "raslib/complex.hh"
+#include "raslib/structure.hh"
+#include "raslib/primitivetype.hh"
+#include "raslib/complextype.hh"
+#include "raslib/structuretype.hh"
+#include "raslib/rmdebug.hh"
+#include "raslib/parseparams.hh"
+
+#include "conversion/convertor.hh"
+#include "conversion/convfactory.hh"
+
+#include "compression/tilecompression.hh"
+
+#endif
diff --git a/include/stdexcept.h b/include/stdexcept.h
new file mode 100644
index 0000000..0c0a3af
--- /dev/null
+++ b/include/stdexcept.h
@@ -0,0 +1,144 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: stdexcept.h
+ *
+ * CLASSES: exception
+ * logic_error
+ * domain_error
+ * invalid_argument
+ * length_error
+ * out_of_range
+ * runtime_error
+ * range_error
+ * overflow_error
+ *
+ * PURPOSE:
+ * This file implements the exception class hierarchy of
+ * Standard C++. It is thought to be substituted by a
+ * compiler package implementation in future.
+ *
+ * COMMENTS:
+ *
+*/
+
+#ifndef _D_EXCEPTION_
+#define _D_EXCEPTION_
+
+class exception
+{
+ public:
+ exception() throw() : errorString(0) {};
+
+ exception( const char* s ) throw()
+ {
+ errorString = new char[strlen(s)+1];
+ strcpy( errorString, s );
+ };
+
+ exception( const exception& ex ) throw()
+ {
+ errorString = new char[strlen(ex.what())+1];
+ strcpy( errorString, ex.what() );
+ };
+
+ ~exception() throw()
+ {
+ if( errorString ) delete[] errorString;
+ };
+
+ exception& operator=( const exception& ex ) throw()
+ {
+ if( this != &ex )
+ {
+ if( errorString ) delete[] errorString;
+
+ errorString = new char[strlen(ex.what())+1];
+ strcpy( errorString, ex.what() );
+ }
+ return *this;
+ };
+
+ inline virtual const char* what() const throw() { return errorString; };
+
+ private:
+ char* errorString;
+};
+
+
+class logic_error : public exception
+{
+ public:
+ logic_error( const char* what_arg ) throw() : exception( what_arg ) {};
+};
+
+
+class domain_error : public logic_error
+{
+ public:
+ domain_error( const char* what_arg ) throw() : logic_error( what_arg ) {};
+};
+
+
+class invalid_argument : public logic_error
+{
+ public:
+ invalid_argument( const char* what_arg ) throw() : logic_error( what_arg ) {};
+};
+
+
+class length_error : public logic_error
+{
+ public:
+ length_error( const char* what_arg ) throw() : logic_error( what_arg ) {};
+};
+
+
+class out_of_range : public logic_error
+{
+ public:
+ out_of_range( const char* what_arg ) throw() : logic_error( what_arg ) {};
+};
+
+
+class runtime_error : public exception
+{
+ public:
+ runtime_error( const char* what_arg ) throw() : exception( what_arg ) {};
+};
+
+
+class range_error : public runtime_error
+{
+ public:
+ range_error( const char* what_arg ) throw() : runtime_error( what_arg ) {};
+};
+
+
+class overflow_error : public runtime_error
+{
+ public:
+ overflow_error( const char* what_arg ) throw() : runtime_error( what_arg ) {};
+};
+
+#endif
diff --git a/indexmgr/Makefile.am b/indexmgr/Makefile.am
new file mode 100644
index 0000000..01eac08
--- /dev/null
+++ b/indexmgr/Makefile.am
@@ -0,0 +1,38 @@
+# -*-Makefile-*- (for Emacs)
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+#
+# MAKEFILE FOR:
+# indexmgr
+#
+#
+# COMMENTS:
+#
+##################################################################
+
+noinst_LIBRARIES=libindexmgr.a
+libindexmgr_a_SOURCES= mddobjix.cc transdirix.cc keyobject.cc srptindexlogic.cc \
+ sdirindexlogic.cc indexds.cc hierindexds.cc srcindexlogic.cc \
+ mddobjix.hh transdirix.hh keyobject.hh srptindexlogic.hh \
+ sdirindexlogic.hh indexds.hh hierindexds.hh srcindexlogic.hh
+
+CLEANFILES=core
diff --git a/indexmgr/hierindexds.cc b/indexmgr/hierindexds.cc
new file mode 100644
index 0000000..9ccc2ce
--- /dev/null
+++ b/indexmgr/hierindexds.cc
@@ -0,0 +1,23 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include "relindexif/hierindex.hh"
diff --git a/indexmgr/hierindexds.hh b/indexmgr/hierindexds.hh
new file mode 100644
index 0000000..c4aedb6
--- /dev/null
+++ b/indexmgr/hierindexds.hh
@@ -0,0 +1,118 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: hierindexds.hh
+ *
+ * MODULE: indexmgr
+ * CLASS: HierIndexDS
+ *
+ * COMMENTS:
+ *
+*/
+
+#ifndef _HIERINDEXDS_HH_
+#define _HIERINDEXDS_HH_
+
+#include "indexmgr/indexds.hh"
+
+//@ManMemo: Module: {\bf indexmgr}
+/*@Doc:
+ Interface class for Data Structure classes of Hierarchical Indexes.
+ Classes which wish to use the RPTreeIndexLogic must implement this
+ class.
+*/
+
+class HierIndexDS : public IndexDS
+ {
+ public:
+ HierIndexDS():IndexDS() {}
+
+ HierIndexDS(const OId& id):IndexDS(id) {}
+
+ virtual double getOccupancy() const = 0;
+ /*@Doc:
+ Return the relative occupancy of this index.
+ For flat indexes return 0.
+ Not implemented.
+ */
+
+ virtual HierIndexDS* getParent() const = 0;
+ /*@Doc:
+ Returns a newly constructed HierIndexDS pointer to this
+ object`s parent.
+ */
+
+ virtual void setParent(const HierIndexDS* newPa) = 0;
+ /*@Doc:
+ Sets the parent node of this object to newPa.
+ */
+
+ virtual void setIsNode(bool beNode) = 0;
+ /*@Doc:
+ When set to false, this index will behave as a leaf.
+ When set to true, this index will behave as a node.
+ */
+
+ virtual bool isLeaf() const = 0;
+ /*@Doc:
+ If true this index contains objects which are stored in the index.
+ If false this index contains index nodes.
+ */
+
+ virtual bool isRoot() const = 0;
+ /*@Doc:
+ If true this object is the root node.
+ */
+
+ virtual unsigned int getHeight() const = 0;
+ /*@Doc:
+ Returns the height of this subtree.
+ Returns the complete height when called by the root node.
+ */
+
+ virtual unsigned int getTotalEntryCount() const = 0;
+ /*@Doc:
+ Get number of entries in leafs of the subtree.
+ Returns the number of all entries in the tree
+ when called by the root node.
+ */
+
+ virtual unsigned int getTotalNodeCount() const = 0;
+ /*@Doc:
+ Get number of nodes in the tree.
+ Returns the number of all nodes in the tree
+ when called by the root node.
+ I do not count myself.
+ */
+
+ virtual unsigned int getTotalLeafCount() const = 0;
+ /*@Doc:
+ Get number of leafs in this subtree.
+ Returns the number of all leafes in the tree
+ when called by the root node.
+ I do count myself -> I am a leaf, I return 1.
+ */
+
+ };
+
+#endif
diff --git a/indexmgr/indexds.cc b/indexmgr/indexds.cc
new file mode 100644
index 0000000..04c3dd2
--- /dev/null
+++ b/indexmgr/indexds.cc
@@ -0,0 +1,24 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include "indexds.hh"
+
diff --git a/indexmgr/indexds.hh b/indexmgr/indexds.hh
new file mode 100644
index 0000000..ede1583
--- /dev/null
+++ b/indexmgr/indexds.hh
@@ -0,0 +1,176 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: indexds.hh
+ *
+ * MODULE: indexmgr
+ * CLASS: IndexDS
+ *
+ * COMMENTS:
+ *
+*/
+
+#ifndef _INDEXDS_HH_
+#define _INDEXDS_HH_
+
+#include "reladminif/dbobject.hh"
+#include "reladminif/lists.h"
+#include "reladminif/oidif.hh"
+
+//@ManMemo: Module: {\bf indexmgr}
+/*@Doc:
+
+This is an interface class. It is abstract. It supplies the signature that
+is required to allow SDirIndexLogic to manage this object.
+
+*/
+
+class IndexDS : public DBObject
+ {
+ public:
+ IndexDS():DBObject() {}
+
+ IndexDS(const OId& id):DBObject(id) {}
+
+ virtual r_Minterval getCoveredDomain() const = 0;
+ /*@Doc:
+ returns the domain which is covered by the entries of this index.
+ when some one has time:
+ this should not be persistent
+ this is not the same as assigned domain
+ this should be updated automatically when removing and adding entries, and is
+ */
+
+ virtual r_Minterval getAssignedDomain() const = 0;
+ /*@Doc:
+ returns the domain this index is responsible for (assigned domain).
+ when some one has time:
+ this is persistent and should be
+ this should not be the same as covered domain, but is
+ this should not be updated when removing entries, but is because of above
+ */
+
+ virtual r_Minterval getObjectDomain(unsigned int pos) const = 0;
+ /*@Doc:
+ Returns the (assigned) domain for the object in position {\ttpos}.
+ The object domain is always a assigned domain, because we do not read the domain from the entries (blobtiles do not store one).
+ At some point this of course makes storing the assigned domain obsolete (because it is stored at the parent, in case of the root it is the covered domain which can be computed from the entries)
+ */
+
+ virtual r_Dimension getDimension() const = 0;
+ /*@Doc:
+ Returns the dimensionality of this index.
+ */
+
+ virtual unsigned int getSize() const = 0;
+ /*@Doc:
+ Only the number of elements in this index node is returned.
+ */
+
+ virtual bool isValid() const = 0;
+ /*@Doc:
+ true when domains of entries of nodes are completely covered
+ by the assigned domains of the nodes and assigned domains of
+ leafs intersect with each of their entries domains. The assigned domains may not intersect.
+ false otherwise.
+ */
+
+ virtual bool isUnderFull() const = 0;
+ /*@Doc:
+ Returns true when the index does not have the minimal number of entries (it is a candidate for merging).
+ Otherwise false.
+ */
+
+ virtual bool isOverFull() const = 0;
+ /*@Doc:
+ Same as above but vice versa.
+ */
+
+ virtual bool isSameAs(const IndexDS* pix) const = 0;
+ /*@Doc:
+ Compares two index data structures:
+ When both are persistent, their oids are compared.
+ When both are transient there memory address is compared.
+ Else they are not equal.
+ */
+
+ virtual bool removeObject(unsigned int pos) = 0;
+ /*@Doc:
+ Removes an object from this index. It returns true if the object was successfully removed.
+ */
+
+ virtual bool removeObject(const KeyObject& theKey) = 0;
+ /*@Doc:
+ Removes an object from this index. It returns true if the object was successfully removed.
+ */
+
+ virtual void insertObject(const KeyObject& theKey, unsigned int pos) = 0;
+ /*@Doc:
+ Inserts the object in theKey at the sppecified position.
+ Position 0 means at the front.
+ */
+
+ virtual void setAssignedDomain(const r_Minterval& domain) = 0;
+ /*@Doc:
+ Sets the assigned domain.
+ */
+
+ virtual void setObject(const KeyObject& theKey, unsigned int pos) = 0;
+ /*@Doc:
+ Sets the entry and domain at position pos.
+ */
+
+ virtual void setObjectDomain(const r_Minterval& dom, unsigned int pos) = 0;
+ /*@Doc:
+ Sets the assigned domain of the object at position pos to dom.
+ */
+
+ virtual const KeyObject& getObject(unsigned int pos) const = 0;
+ /*@Doc:
+ The requested object will be placed in result.
+ */
+
+ virtual void getObjects(KeyObjectVector& objs) const = 0;
+ /*@Doc:
+ Push all entries into the vector
+ */
+
+ virtual unsigned int getOptimalSize() const = 0;
+ /*@Doc:
+ Computes the optimal number of entries for this index.
+ Should be moved to a place where StorageLayout is accessible.
+ */
+
+ virtual void freeDS() = 0;
+ /*@Doc:
+ Marks the persistent database index data structure for
+ deletion all entries contained in it will be deleted
+ from the database along with it.
+ */
+
+ virtual OId::OIdPrimitive getIdentifier() const = 0;
+
+ virtual IndexDS* getNewInstance() const = 0;
+ };
+
+#endif
diff --git a/indexmgr/keyobject.cc b/indexmgr/keyobject.cc
new file mode 100644
index 0000000..e1d46ab
--- /dev/null
+++ b/indexmgr/keyobject.cc
@@ -0,0 +1,135 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#include "keyobject.hh"
+#include "tilemgr/tile.hh"
+
+ostream& operator<<(ostream& in, const KeyObject& d)
+ {
+ if (d.isPersCarrier())
+ {
+ in << "Carrier{" << d.getDomain() << ", " << d.getObject().getOId() << "}";
+ }
+ else {
+ in << "Carrier{" << d.getDomain() << ", TransTile}";
+ }
+ return in;
+ }
+
+KeyObject::KeyObject()
+ : transobject(NULL)
+ {
+ }
+
+KeyObject::KeyObject(const KeyObject& old)
+ : persobject(old.persobject),
+ domain(old.domain),
+ transobject(old.transobject)
+ {
+ }
+
+KeyObject::KeyObject(const Tile* tile)
+ : persobject(),
+ domain(tile->getDomain()),
+ transobject(NULL)
+ {
+ if (tile->isPersistent())
+ {
+ persobject = (const DBObjectId&)((Tile*)tile)->getDBTile();
+ }
+ else {
+ transobject = (Tile*)tile;
+ }
+ }
+
+KeyObject::KeyObject(const DBObjectId& obj, const r_Minterval& dom)
+ : persobject(obj),
+ domain(dom),
+ transobject(NULL)
+ {
+ }
+
+KeyObject::~KeyObject()
+ {
+ transobject = NULL;
+ }
+
+void
+KeyObject::setDomain(const r_Minterval& dom)
+ {
+ domain = dom;
+ }
+
+void
+KeyObject::setTransObject(const Tile* tile)
+ {
+ domain = tile->getDomain();
+ transobject = (Tile*)tile;
+ }
+
+void
+KeyObject::setObject(const DBObjectId& obj)
+ {
+ persobject = obj;
+ }
+
+bool
+KeyObject::isInitialised() const
+ {
+ if (transobject)
+ return true;
+ if (persobject.isInitialised())
+ return true;
+ return false;
+ }
+
+bool
+KeyObject::isPersCarrier() const
+ {
+ return (transobject == NULL);
+ }
+
+Tile*
+KeyObject::getTransObject() const
+ {
+ return transobject;
+ }
+
+const DBObjectId&
+KeyObject::getObject() const
+ {
+ return persobject;
+ }
+
+r_Minterval
+KeyObject::getDomain() const
+ {
+ return domain;
+ }
+/*
+const r_Minterval&
+KeyObject::getDomain() const
+ {
+ return domain;
+A }
+*/
diff --git a/indexmgr/keyobject.hh b/indexmgr/keyobject.hh
new file mode 100644
index 0000000..51bf89c
--- /dev/null
+++ b/indexmgr/keyobject.hh
@@ -0,0 +1,134 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#ifndef _KEYOBJECT_HH_
+#define _KEYOBJECT_HH_
+
+class Tile;
+class KeyObject;
+
+#include "reladminif/dbobject.hh"
+#include "raslib/minterval.hh"
+#include "reladminif/dbref.hh"
+
+//@ManMemo: Module: {\bf indexmgr}
+/*@Doc:
+This class is a carrier structure which carries objects and their domains
+through the different levels of the index.
+*/
+class KeyObject
+ {
+ public:
+ KeyObject();
+
+ KeyObject(const KeyObject& old);
+ /*@Doc:
+ Copy constructor. Copies the tile pointer.
+ */
+
+ KeyObject(const Tile* p);
+ /*@Doc:
+ Construccts a new KeyObject. The type (persistent/transinet)
+ is deremined based on the Tile. The domain also.
+ This constructor is sometimes misused by the compiler in statements like KeyObject p = 0.
+ This will cause a crash because the domain is read from the tile which is NULL : )
+ */
+
+ KeyObject(const DBObjectId& obj, const r_Minterval& dom);
+ /*@Doc:
+ Constructs a new KeyObject for a persistent object.
+ */
+
+ const DBObjectId& getObject() const;
+ /*@Doc:
+ Returns a smartpointer to the persistent object attribute.
+ If this is a transient object carrier the returned smart-
+ pointer is invalid.
+ */
+
+ Tile* getTransObject() const;
+ /*@Doc:
+ Returns the transient object. If this KeyObject carries
+ a persistent object a NULL is returned.
+ */
+
+ r_Minterval getDomain() const;
+ /*@Doc:
+ Returns the domain which is associated with the objects that
+ is carried.
+ */
+
+ ~KeyObject();
+ /*@Doc:
+ Does not delete the TransTile!!
+ */
+
+ bool isInitialised() const;
+ /*@Doc:
+ Returns true if trans object is initialised or the dbref is initialised.
+ */
+
+ bool isPersCarrier() const;
+ /*@Doc:
+ Returns true if the transobject attribute is NULL.
+ */
+
+ void setDomain(const r_Minterval& dom);
+ /*@Doc:
+ Alters the domain the KeyObject carries.
+ */
+
+ void setTransObject(const Tile* tile);
+ /*@Doc:
+ makes the KeyObject a transient carrier and copies the pointer.
+ */
+
+ void setObject(const DBObjectId& obj);
+ /*@Doc:
+ makes the KeyObject a persistent carrier and copies object.
+ */
+
+ protected:
+ DBObjectId persobject;
+ /*@Doc:
+ A smartpointer to the carried object if it is persistent.
+ */
+
+ r_Minterval domain;
+ /*@Doc:
+ The domain which the carried object belongs to.
+ */
+
+ Tile* transobject;
+ /*@Doc:
+ Attribute for storing a transtile. is NULL if a persistent
+ object is carried.
+ */
+ };
+
+/*@Doc:
+ Prints the status of KeyObject object.
+*/
+extern std::ostream& operator<<(std::ostream& in, const KeyObject& d);
+
+#endif
diff --git a/indexmgr/mddobjix.cc b/indexmgr/mddobjix.cc
new file mode 100644
index 0000000..6e85d97
--- /dev/null
+++ b/indexmgr/mddobjix.cc
@@ -0,0 +1,529 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: mddobjix.cc
+ *
+ * MODULE: indexmgr
+ * CLASS: MDDObjIx
+ *
+ * COMMENTS:
+ * none
+ *
+*/
+static const char rcsid[] = "@(#)mddobjix, MDDObjIx: $Id: mddobjix.cc,v 1.30 2002/07/24 14:33:51 hoefner Exp $";
+
+#include <iostream>
+#include <math.h>
+
+#include "indexmgr/mddobjix.hh"
+#include "raslib/rmdebug.hh"
+#include "tilemgr/tile.hh"
+#include "indexmgr/srptindexlogic.hh"
+#include "indexmgr/sdirindexlogic.hh"
+#include "indexmgr/srcindexlogic.hh"
+#include "indexmgr/transdirix.hh"
+#include "relindexif/hierindex.hh"
+#include "relindexif/dbtcindex.hh"
+#include "relindexif/dbrcindexds.hh"
+#include "keyobject.hh"
+#include "reladminif/lists.h"
+#include "relblobif/tileid.hh"
+
+void
+MDDObjIx::setNewLastAccess(const r_Minterval& newLastAccess, const std::vector<Tile*>* newLastTiles)
+ {
+ lastAccess = newLastAccess;
+ releasePersTiles();
+ lastAccessTiles = *newLastTiles;
+ }
+
+void
+MDDObjIx::setNewLastAccess(const Tile* newLastTile, bool clear)
+ {
+ if (clear)
+ {
+ releasePersTiles();
+ lastAccessTiles.erase(lastAccessTiles.begin(), lastAccessTiles.end());
+ }
+ if (newLastTile)
+ {
+ r_Minterval region = newLastTile->getDomain();
+ lastAccess = region;
+ lastAccessTiles.push_back((Tile*)newLastTile);
+ }
+ }
+
+bool
+MDDObjIx::removeTileFromLastAccesses(const Tile* tileToRemove)
+ {
+ bool found = false;
+ std::vector<Tile*>::iterator iter;
+ for (iter = lastAccessTiles.begin(); iter != lastAccessTiles.end() ; iter++)
+ {
+ if (*iter == tileToRemove)
+ {
+ found = true;
+ lastAccessTiles.erase(iter);
+ break;
+ }
+ }
+ if (found)
+ {
+ r_Minterval emptyInterval;
+ lastAccess = emptyInterval;
+ }
+ return found;
+ }
+
+std::vector< Tile* >*
+MDDObjIx::lastAccessIntersect(const r_Minterval& searchInter) const
+ {
+ std::vector< Tile* >* interResult = 0;
+ if ((lastAccess.dimension() != 0) && (lastAccess.covers(searchInter)))
+ {
+ RMDBGONCE(6, RMDebug::module_indexmgr, "MDDObjIx", "lastAccessIntersect Search in the cache ")
+ interResult = new std::vector< Tile* >();
+ interResult->reserve(10);
+ for (int i = 0; i < lastAccessTiles.size(); i++)
+ {
+ if (lastAccessTiles[i]->getDomain().intersects_with(searchInter))
+ interResult->push_back(lastAccessTiles[i]);
+ }
+ if (interResult->size() == 0)
+ {
+ delete interResult;
+ interResult = NULL;
+ }
+ }
+ return interResult;
+ }
+
+Tile*
+MDDObjIx::lastAccessPointQuery(const r_Point& searchPoint) const
+ {
+ Tile* result = 0;
+
+ if ((lastAccess.dimension() != 0) && (lastAccess.covers(searchPoint)))
+ {
+ for (int i = 0; !result && i < lastAccessTiles.size(); i++)
+ {
+ if (lastAccessTiles[i]->getDomain().covers(searchPoint))
+ {
+ result = lastAccessTiles[i];
+ }
+ }
+ }
+ return (result);
+ }
+
+void
+MDDObjIx::releasePersTiles()
+ {
+ RMDBGENTER(6, RMDebug::module_indexmgr, "MDDObjIx", "releasePersTiles()")
+ if (isPersistent())
+ {
+ Tile* t = NULL;
+ for(int i = 0; i < lastAccessTiles.size(); i++)
+ {
+ t = lastAccessTiles[i];
+ delete t;
+ lastAccessTiles[i] = NULL;
+ }
+ lastAccessTiles.clear();
+ }
+ RMDBGEXIT(6, RMDebug::module_indexmgr, "MDDObjIx", "releasePersTiles()")
+ }
+
+void
+MDDObjIx::printStatus(unsigned int level, std::ostream& stream) const
+ {
+ stream << "MDDObjIx [ last access interval = " << lastAccess << " tile cache size = " << lastAccessTiles.size() << " index structure = ";
+ actualIx->printStatus(level, stream);
+ }
+
+DBObjectId
+MDDObjIx::getDBMDDObjIxId() const
+ {
+ return actualIx;
+ }
+
+r_Minterval
+MDDObjIx::getCurrentDomain() const
+ {
+ return actualIx->getCoveredDomain();
+ }
+
+r_Dimension
+MDDObjIx::getDimension() const
+ {
+ return actualIx->getDimension();
+ }
+
+#ifdef RMANBENCHMARK
+void
+MDDObjIx::initializeTimerPointers()
+ {
+ pointQueryTimer= new RMTimer("DirIx", "pointQuery time ");
+ intersectTimer = new RMTimer("DirIx", "intersect time ");
+ getTilesTimer = new RMTimer("DirIx", "getTiles time ");
+ }
+#endif
+
+MDDObjIx::MDDObjIx(const StorageLayout& sl, const r_Minterval& dim, const BaseType* bt)
+ : cellBaseType(bt),
+ myStorageLayout(sl),
+ actualIx(0),
+ _isPersistent(true)
+ {
+ RMDBGENTER(10, RMDebug::module_indexmgr, "MDDObjIx", "MDDObjIx(storage, " << dim << ", type)")
+ lastAccessTiles.reserve(10);
+ if (bt == NULL)
+ {
+ RMDBGMIDDLE(10, RMDebug::module_indexmgr, "MDDObjIx", "TransIndex")
+ _isPersistent = false;
+ }
+ initializeLogicStructure();
+ if (isPersistent())
+ {
+ r_Range temp;
+ switch(myStorageLayout.getIndexType())
+ {
+ case r_RPlus_Tree_Index:
+ actualIx = (HierIndexDS*)new DBHierIndex(dim.dimension(), false, true);
+ break;
+ case r_Reg_Computed_Index:
+ actualIx = new DBRCIndexDS(dim, SRCIndexLogic::computeNumberOfTiles(myStorageLayout, dim));
+ break;
+ case r_Tile_Container_Index:
+ actualIx = (HierIndexDS*)new DBTCIndex(dim.dimension(), false);
+ break;
+ case r_Directory_Index:
+ actualIx = (HierIndexDS*)new DBHierIndex(dim.dimension(), false, true);
+ break;
+ case r_Auto_Index:
+ default:
+ // should never get here. If Auto_Index, a specific index was
+ RMDBGONCE(0, RMDebug::module_indexmgr, "MDDObjIx", "initializeLogicStructure() Auto_Index or unknown index chosen");
+ throw r_Error(UNKNOWN_INDEX_TYPE);
+ break;
+ }
+ }
+ else {
+ //only dirindex supports transient indexes
+ actualIx = new TransDirIx(dim.dimension());
+ }
+#ifdef RMANBENCHMARK
+ initializeTimerPointers();
+#endif
+ RMDBGEXIT(10, RMDebug::module_indexmgr, "MDDObjIx", "MDDObjIx(storage, " << dim << ", type)")
+ }
+
+MDDObjIx::MDDObjIx(DBObjectId newDBIx, const StorageLayout& sl, const BaseType* bt)
+ : cellBaseType(bt),
+ myStorageLayout(sl),
+ actualIx(newDBIx),
+ _isPersistent(true)
+ {
+ initializeLogicStructure();
+ lastAccessTiles.reserve(10);
+#ifdef RMANBENCHMARK
+ initializeTimerPointers();
+#endif
+ }
+
+void
+MDDObjIx::initializeLogicStructure()
+ {
+ switch(myStorageLayout.getIndexType())
+ {
+ case r_RPlus_Tree_Index:
+ case r_Tile_Container_Index:
+ do_getObjs = SRPTIndexLogic::getObjects;
+ do_insertObj = SRPTIndexLogic::insertObject2;
+ do_pointQuery = SRPTIndexLogic::containPointQuery2;
+ do_removeObj = SRPTIndexLogic::removeObject;
+ do_intersect = SRPTIndexLogic::intersect2;
+ break;
+ case r_Reg_Computed_Index:
+ do_getObjs = SRCIndexLogic::getObjects;
+ do_insertObj = SRCIndexLogic::insertObject;
+ do_pointQuery = SRCIndexLogic::containPointQuery;
+ do_removeObj = SRCIndexLogic::removeObject;
+ do_intersect = SRCIndexLogic::intersect;
+ break;
+ case r_Directory_Index:
+ // chosen before this
+ do_getObjs = SDirIndexLogic::getObjects;
+ do_pointQuery = SDirIndexLogic::containPointQuery;
+ do_removeObj = SDirIndexLogic::removeObject;
+ do_intersect = SDirIndexLogic::intersect;
+ do_insertObj = SDirIndexLogic::insertObject;
+ break;
+ default:
+ case r_Auto_Index:
+ // should never get here. If Auto_Index, a specific index was
+ RMInit::logOut << "MDDObjIx::initializeLogicStructure() illegal index (" << myStorageLayout.getIndexType() << ") chosen!" << endl;
+ throw r_Error(ILLEGAL_INDEX_TYPE);
+ break;
+ }
+ }
+
+
+void
+MDDObjIx::insertTile(const Tile* newTile)
+ {
+ if (isPersistent())
+ {
+ ((Tile*)newTile)->setPersistent();
+ }
+ KeyObject t(newTile);
+ do_insertObj(actualIx, t, myStorageLayout);
+ setNewLastAccess(newTile, false);
+ }
+
+bool
+MDDObjIx::removeTile(const Tile* tileToRemove)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "MDDObjIx", "removeTile(Tile)")
+ bool found = false;
+ // removes from cache, if it's there
+ removeTileFromLastAccesses(tileToRemove);
+
+ // removes from the index itself
+ KeyObject t(tileToRemove);
+ found = do_removeObj(actualIx, t, myStorageLayout);
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "MDDObjIx", "removeTile(Tile)")
+ return found;
+ }
+
+vector< Tile* >*
+MDDObjIx::intersect(const r_Minterval& searchInter) const
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "MDDObjIx", "intersect(" << searchInter << ")")
+#ifdef RMANBENCHMARK
+ if(RManBenchmark >= 3) intersectTimer->start();
+#endif
+
+ vector< Tile* >* result = lastAccessIntersect(searchInter);
+ if (!result)
+ {
+ KeyObjectVector resultKeys;
+ do_intersect(actualIx, searchInter, resultKeys, myStorageLayout);
+ result = new vector< Tile* >();
+ if (!resultKeys.empty())
+ {
+ unsigned int resSize = resultKeys.size();
+ result->reserve(resSize);
+ Tile* t = NULL;
+ unsigned int i = 0;
+ if (isPersistent())
+ {
+//this checks if there are double tiles in the result
+ RMDBGIF(1, RMDebug::module_indexmgr, "MDDObjIx", \
+ DomainMap t; \
+ DomainMap::iterator it; \
+ for (i = 0; i < resSize; i++) \
+ { \
+ DomainPair p(resultKeys[i].getObject().getOId(), \
+ resultKeys[i].getDomain()); \
+ if ((it = t.find(p.first)) != t.end()) \
+ { \
+ RMDBGMIDDLE(0, RMDebug::module_indexmgr, "MDDObjIx", \
+ "intersect(" << searchInter << \
+ ") received double tile: " << \
+ resultKeys[i]) \
+ for (int i = 0; i < resultKeys.size(); i++) \
+ { \
+ RMInit::dbgOut << resultKeys[i] << endl; \
+ } \
+ throw r_Error(TILE_MULTIPLE_TIMES_RETRIEVED); \
+ } \
+ t.insert(p); \
+ } \
+ );
+ for (i = 0; i < resSize; i++)
+ {
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "MDDObjIx", "received entry " << resultKeys[i])
+ result->push_back(new Tile(resultKeys[i].getDomain(), cellBaseType, DBTileId(resultKeys[i].getObject())));
+ }
+ }
+ else {
+ for (i = 0; i < resSize; i++)
+ {
+ result->push_back(resultKeys[i].getTransObject());
+ }
+ }
+ ((MDDObjIx*) this)->setNewLastAccess(searchInter, result);
+ }
+ }
+#ifdef RMANBENCHMARK
+ if(RManBenchmark >= 3) intersectTimer->stop();
+#endif
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "MDDObjIx", "intersect(" << searchInter << ") " << (void*)result)
+ return result;
+ }
+
+char*
+MDDObjIx::pointQuery(const r_Point& searchPoint)
+ {
+ char* result = 0;
+
+ Tile* resultTile = containPointQuery(searchPoint);
+
+ if(resultTile)
+ {
+ result = resultTile->getCell(searchPoint);
+ }
+ return result;
+ }
+
+const char*
+MDDObjIx::pointQuery(const r_Point& searchPoint) const
+ {
+ const char* result = 0;
+
+ Tile* resultTile = containPointQuery(searchPoint);
+
+ if(resultTile)
+ {
+ result = resultTile->getCell(searchPoint);
+ }
+ return result;
+ }
+
+Tile*
+MDDObjIx::containPointQuery(const r_Point& searchPoint) const
+ {
+
+ Tile* resultTile = 0;
+
+#ifdef RMANBENCHMARK
+ if(RManBenchmark >= 4) pointQueryTimer->start();
+#endif
+ resultTile = lastAccessPointQuery(searchPoint);
+ if (!resultTile)
+ {
+ KeyObject resultKey;
+ do_pointQuery(actualIx, searchPoint, resultKey, myStorageLayout);
+ if (resultKey.isInitialised())
+ {
+ if (isPersistent())
+ {
+ resultTile = new Tile(resultKey.getDomain(), cellBaseType, DBTileId(resultKey.getObject()));
+ // for rcindex
+ ((DBObject*)resultKey.getObject().ptr())->setCached(false);
+ }
+ else {
+ resultTile = resultKey.getTransObject();
+ }
+ ((MDDObjIx*) this)->setNewLastAccess(resultTile);
+ }
+ }
+
+#ifdef RMANBENCHMARK
+ if (RManBenchmark >= 4) pointQueryTimer->stop();
+#endif
+ return resultTile;
+ }
+
+vector< Tile* >*
+MDDObjIx::getTiles() const
+ {
+#ifdef RMANBENCHMARK
+ if(RManBenchmark >= 3) getTilesTimer->start();
+#endif
+ vector< Tile* >* result = NULL;
+ KeyObjectVector resultKeys;
+ do_getObjs(actualIx, resultKeys, myStorageLayout);
+ if (!resultKeys.empty())
+ {
+ result = new vector< Tile* >();
+ unsigned int resSize = resultKeys.size();
+ result->reserve(resSize);
+ Tile* t = 0;
+ if (isPersistent())
+ {
+//this checks if there are double tiles in the result
+ RMDBGIF(1, RMDebug::module_indexmgr, "MDDObjIx", \
+ DomainMap tmap; \
+ DomainMap::iterator it; \
+ for (int cnt = 0; cnt < resSize; cnt++) \
+ { \
+ DomainPair p(resultKeys[cnt].getObject().getOId(), \
+ resultKeys[cnt].getDomain()); \
+ if ((it = tmap.find(p.first)) != tmap.end()) \
+ { \
+ RMDBGMIDDLE(0, RMDebug::module_indexmgr, "MDDObjIx", \
+ "getTiles() received double tile: " << \
+ resultKeys[cnt]) \
+ for (int cnt = 0; cnt < resultKeys.size(); cnt++) \
+ { \
+ RMInit::dbgOut << resultKeys[cnt] << endl; \
+ } \
+ throw r_Error(TILE_MULTIPLE_TIMES_RETRIEVED ); \
+ } \
+ tmap.insert(p); \
+ } \
+ );
+ for (int i = 0; i < resSize; i++)
+ {
+ result->push_back(new Tile(resultKeys[i].getDomain(), cellBaseType, DBTileId(resultKeys[i].getObject())));
+ }
+ }
+ else {
+ for (int i = 0; i < resultKeys.size(); i++)
+ {
+ result->push_back(resultKeys[i].getTransObject());
+ }
+ }
+ r_Minterval emptyInterval;
+ ((MDDObjIx*) this)->setNewLastAccess(emptyInterval, result);
+ }
+#ifdef RMANBENCHMARK
+ if(RManBenchmark >= 3) getTilesTimer->stop();
+#endif
+ return result;
+ }
+
+
+bool
+MDDObjIx::isPersistent() const
+ {
+ return _isPersistent;
+ }
+
+MDDObjIx::~MDDObjIx()
+ {
+ releasePersTiles();
+ actualIx->destroy();
+ actualIx = 0;
+
+#ifdef RMANBENCHMARK
+ pointQueryTimer->setOutput(0);
+ if (pointQueryTimer) delete pointQueryTimer;
+ intersectTimer->setOutput(0);
+ if (intersectTimer) delete intersectTimer;
+ getTilesTimer->setOutput(0);
+ if (getTilesTimer) delete getTilesTimer;
+#endif
+ }
diff --git a/indexmgr/mddobjix.hh b/indexmgr/mddobjix.hh
new file mode 100644
index 0000000..0e7dd09
--- /dev/null
+++ b/indexmgr/mddobjix.hh
@@ -0,0 +1,274 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#ifndef _MDDOBJIX_HH_
+#define _MDDOBJIX_HH_
+
+class PersTile;
+class BaseType;
+class Tile;
+class r_Point;
+#include "raslib/minterval.hh"
+#include "raslib/rmdebug.hh"
+#include "indexmgr/indexds.hh"
+#include "storagemgr/sstoragelayout.hh"
+#include "reladminif/lists.h"
+#include "relindexif/indexid.hh"
+#include <vector>
+
+
+/****************************************************************************
+ *
+ *
+ * INCLUDE: mddobjix.hh
+ *
+ * MODULE: indexmgr
+ * CLASS: MDDObjIx
+ *
+ *
+ * COMMENTS:
+ * none
+ *
+ ****************************************************************************/
+
+
+//@ManMemo: Module: {\bf indexmgr}
+/*@Doc:
+
+Each MDD Object is composed of a set of tiles which are accessed through an index.
+The task of the index is to determine the tiles affected by a spatial operation and to allow fast access to them. It will also take care of memory management of the tiles.
+
+{\bfMDD Objects indexes: }
+
+MDD Objects indexes are multidimensional since they provide access to multidimensional rectangular tiles existing in multidimensional intervals. An MDDObjIx has to be able to deal with different dimensionalities.
+
+The index of an MDD object keeps the information about the current domain of the MDD object. During the lifetime of the object, it is possible that the definition (or current) domain of an object is not completely covered by the tiles already inserted.
+At each moment, the current domain of an object is the closure of the domains of all tiles. All tiles should be completely contained
+in the definition domain of an object.
+The definition domain may have open boundaries, but the current domain is always a closed interval.
+
+The lower classes in the indexmgr support storage of any kind of persistent object.
+This class has to be changed to reflect this aability.
+
+ In the future, functions have to be implemented which allow the user
+ to give indication about priorities for freeing tiles from main memory.
+
+*/
+
+//function pointer to the static function which inserts objects
+typedef bool (*IxLogic_insertObject) (IndexDS* theIx, const KeyObject& theObj, const StorageLayout& sl);
+
+//function pointer to the static function which removes objects
+typedef bool (*IxLogic_removeObject) (IndexDS* theIx, const KeyObject& theObj, const StorageLayout& sl);
+
+//function pointer to the static function which gets objects from the index
+typedef void (*IxLogic_intersect) (const IndexDS* theIx, const r_Minterval& searchInterval, KeyObjectVector& objs, const StorageLayout& sl);
+
+//function pointer to the static function which gets object at point
+typedef void (*IxLogic_containPointQuery) (const IndexDS* theIx, const r_Point& searchPoint, KeyObject& result, const StorageLayout& sl);
+
+//function pointer to the static function which inserts objects
+typedef void (*IxLogic_getObjects) (const IndexDS* theIx, KeyObjectVector& objs, const StorageLayout& sl);
+
+class MDDObjIx
+ {
+ public:
+
+ MDDObjIx(const StorageLayout& sl, const r_Minterval& dom, const BaseType* bt = 0);
+ /*@Doc:
+ When bt is NULL this index will behave as if it were a transient index.
+ */
+
+ MDDObjIx(DBObjectId newDBIx, const StorageLayout& sl, const BaseType* bt);
+ /*@Doc:
+ When bt is NULL this index will behave as if it were a transient index.
+ */
+
+ void printStatus(unsigned int level = 0, std::ostream& stream = std::cout) const;
+
+ ~MDDObjIx();
+
+ DBObjectId getDBMDDObjIxId() const;
+
+ r_Minterval getCurrentDomain() const;
+
+ r_Dimension getDimension() const;
+
+ void insertTile(const Tile* newTile);
+
+ bool removeTile(const Tile *);
+
+ std::vector<Tile *> * intersect(const r_Minterval &) const;
+
+ char* pointQuery(const r_Point& searchPoint);
+
+ const char* pointQuery(const r_Point& searchPoint) const;
+
+ Tile* containPointQuery(const r_Point& searchPoint) const;
+
+ std::vector< Tile* >* getTiles() const;
+
+ bool isPersistent() const;
+
+ void releasePersTiles();
+ /*@Doc:
+ This function has to be called by the destructors of persistent subclasses which use the cache, to make sure that the memory for the tiles in the cache is freed.
+ This will only have effect on persistent indexes.
+ Transient indexes keep their tiles in TransDirIx which deletes its tiles in the destructor.
+ */
+
+ protected:
+
+ void setNewLastAccess(const r_Minterval& newLastAccess, const std::vector<Tile*>* newLastTiles);
+
+ void setNewLastAccess(const Tile* newLastTile, bool te = true);
+ /*@Doc:
+ Add a new tile to the cache and reset the access domain
+ If clear:
+ clear the cache
+ release all tiles
+ */
+
+ std::vector< Tile* >* lastAccessIntersect(const r_Minterval& searchInter) const;
+
+ Tile* lastAccessPointQuery(const r_Point& searchPoint) const;
+
+ bool removeTileFromLastAccesses(const Tile* tileToRemove);
+ /*@Doc:
+ Does NOT free tileToRemove allocated memory. Only removes this pointer from lastAccesses list if it finds it there.
+ Returns true if found.
+ Subclasses which use the cache must call this function before removing a tile from the index, or else the tile may remain in main memory.
+ */
+
+ r_Minterval lastAccess;
+ /*@Doc:
+ Either empty interval, if not to search in the cache, or an interval
+ corresponding to the search done the last time. The algorithms which
+ search this cache for an intersection take this into account.
+ It works simultaneously as a flag and as the specification for the last
+ access, if valid.
+ Last searched region.
+ */
+
+ std::vector< Tile* > lastAccessTiles;
+ /*@Doc:
+ Internal cache of {\tt Tile}s accessed the last time.
+ Contents change everytime there is an insert, an intersect, a getTiles
+ or a poin query, in the following way:
+ - insert: cache invalid, last Access is put to empty interval,
+ lastAccessTiles contains the inserted tiles. This is needed
+ if we want the index to automatically manage the memory
+ allocated for persistent tiles or else the just inserted
+ tiles are immediately invalid for the user after insertion
+ in the object. The lastAccess can not be put to the area
+ because it's impossible to determine the area corresponding
+ to inserted tiles (there may be empty areas and so on, it
+ would be rather complex to calculate these things).
+ - intersect/pointquery: cache and lastAccessTiles get the new result.
+ The old access and tiles are thrown away.
+ - getTiles: it would be very inefficient to search here for smaller
+ regions, so lastAccess is made empty and lastAccessTiles
+ contains the tiles accessed (because of PersTiles and
+ automatic management of their memory, they have to be
+ kept by the MDDObjIx).
+ For this reason, tiles passed by PersMDDObj are only valid until the
+ next intersect/pointQuery/insert/getTiles operation.
+ Alternative implementation for getTiles - always put in the cache
+ correctly.
+ Make a check about the search interval and what is in the cache (for
+ example, if cell_count < 90% cache cell count , access index).
+ Such a check should also be done in lastAccessPointQuery(): if the
+ cache has more than 10 elements, it is not worth searching in it for
+ a point.
+ */
+
+ const BaseType* cellBaseType;
+ /*@Doc:
+ This is needed because the PersTile constructor expects a BaseType.
+ It Should be considered to move the creation of PersTiles into the
+ MDDObj class.
+ */
+
+
+ IndexDS* actualIx;
+ /*@Doc:
+ The real index structure
+ */
+
+ IxLogic_insertObject do_insertObj;
+ /*@Doc:
+ Function pointer to insert tile logic
+ */
+
+ IxLogic_removeObject do_removeObj;
+ /*@Doc:
+ Function pointer to remove tile logic
+ */
+
+ IxLogic_intersect do_intersect;
+ /*@Doc:
+ Function pointer to find tiles logic
+ */
+
+ IxLogic_containPointQuery do_pointQuery;
+ /*@Doc:
+ Function pointer to find tile logic
+ */
+
+ IxLogic_getObjects do_getObjs;
+ /*@Doc:
+ Function pointer to get all tiles logic
+ */
+
+ #ifdef RMANBENCHMARK
+
+ void initializeTimerPointers();
+ /*@Doc:
+ This code was commented out because it crashed
+ */
+
+ RMTimer *pointQueryTimer;
+ RMTimer *intersectTimer;
+ RMTimer *getTilesTimer;
+ #endif
+ void initializeLogicStructure();
+ /**
+ {\tt actualDBIx} and {\tt cellBaseType} must be already correctly set.
+ The function pointers are set according to the index type.
+ */
+
+ bool _isPersistent;
+ /*@Doc:
+ This class is used for both persistent and tranisent objects
+ To be able to distinguish whether it is persistent or transient
+ this attribute is used.
+ */
+
+ const StorageLayout& myStorageLayout;
+ /*@Doc:
+ Nifty object which holds information on how to store data in the database.
+ It tells you which index to use, hos large a index might become and so on.
+ */
+ };
+
+#endif
diff --git a/indexmgr/persmddobjix.cc b/indexmgr/persmddobjix.cc
new file mode 100644
index 0000000..02a8c2d
--- /dev/null
+++ b/indexmgr/persmddobjix.cc
@@ -0,0 +1,2 @@
+//moved to mddobjix
+
diff --git a/indexmgr/persmddobjix.hh b/indexmgr/persmddobjix.hh
new file mode 100644
index 0000000..b4e4c9b
--- /dev/null
+++ b/indexmgr/persmddobjix.hh
@@ -0,0 +1 @@
+//moved to mddobjix
diff --git a/indexmgr/sdirindexlogic.cc b/indexmgr/sdirindexlogic.cc
new file mode 100644
index 0000000..e63ba22
--- /dev/null
+++ b/indexmgr/sdirindexlogic.cc
@@ -0,0 +1,333 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: dirix.cc
+ *
+ * MODULE: indexmgr
+ * CLASS: SDirIndexLogic
+ *
+ * COMMENTS:
+ *
+*/
+static const char rcsiddirix[] = "@(#)dirix, SDirIndexLogic: $Id: sdirindexlogic.cc,v 1.10 2002/06/15 18:27:49 coman Exp $";
+
+#include <iostream>
+#include "raslib/rmdebug.hh"
+#include "indexmgr/sdirindexlogic.hh"
+#include "keyobject.hh"
+#include "indexds.hh"
+
+
+bool
+SDirIndexLogic::insertObject(IndexDS* ixDS, const KeyObject& newKeyObject, const StorageLayout& sl)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SDirIndexLogic", "insertObject(" << newKeyObject << ")");
+ r_Minterval newKeyObjectDomain = newKeyObject.getDomain();
+
+ int pos = binarySearch(ixDS, newKeyObjectDomain, Lowest, 0, (int)ixDS->getSize()-1);
+ ixDS->insertObject(newKeyObject, pos + 1);
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SDirIndexLogic", "insertObject(" << newKeyObject << ")");
+ //should check if insertion was succesfull
+ return true;
+ }
+
+int
+SDirIndexLogic::binarySearch( const IndexDS* ixDS,
+ const r_Minterval& newDomain,
+ OrderPoint o,
+ int first,
+ int last)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SDirIndexLogic", "binarySearch(" << newDomain << ", " << (int)o << ", " << first <<", " << last << ")");
+ int retval = 0;
+ int middle = 0;
+ int compResult = 0;
+
+ if (first > last)
+ retval = last;
+ else {
+ middle = (last + first) /2;
+ compResult = compare(newDomain, ixDS->getObjectDomain(middle), o , o);
+ if (compResult < 0)
+ retval = binarySearch(ixDS, newDomain, o, first, middle - 1);
+ else
+ if (compResult > 0)
+ retval = binarySearch(ixDS, newDomain, o, middle + 1, last);
+ else
+ retval = middle;
+ }
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SDirIndexLogic", "binarySearch(" << newDomain << ", " << (int)o << ", " << first <<", " << last << ") " << retval);
+ return retval;
+ }
+
+
+int
+SDirIndexLogic::binaryPointSearch( const IndexDS* ixDS,
+ const r_Point& pnt,
+ SDirIndexLogic::OrderPoint o,
+ int first,
+ int last)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SDirIndexLogic", "binaryPointSearch(" << pnt << ", " << (int)o << ", " << first << ", " << last << ")");
+ int retval = 0;
+ int middle = 0;
+ int compResult = 0;
+ r_Minterval KeyObjectDomain;
+ r_Point pnt2;
+
+ if (first > last)
+ retval = -1;
+ else
+ {
+ middle = (last + first) /2;
+ KeyObjectDomain = ixDS->getObjectDomain(middle);
+ if (KeyObjectDomain.covers(pnt) == 1)
+ retval = middle;
+ else
+ {
+ switch(o)
+ {
+ case Highest:
+ pnt2 = KeyObjectDomain.get_high();
+ break;
+ case Lowest:
+ pnt2 = KeyObjectDomain.get_origin();
+ break;
+ case None:
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SDirIndexLogic", "binaryPointSearch(...) o is None");
+ break;
+ }
+
+ compResult = pnt.compare_with(pnt2);
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SDirIndexLogic", "binaryPointSearch compResult " << compResult);
+
+ if (compResult > 0 && o == Highest)
+ retval = binaryPointSearch(ixDS, pnt, o, middle+1, last);
+ else
+ if (compResult < 0 && o == Lowest)
+ retval = binaryPointSearch(ixDS, pnt, o, first, middle -1);
+ else
+ {
+ compResult = binaryPointSearch(ixDS, pnt, o, middle +1, last);
+ if (compResult < 0)
+ retval = binaryPointSearch(ixDS, pnt, o, first, middle -1);
+ else
+ retval = compResult;
+ }
+ }
+ }
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SDirIndexLogic", "binaryPointSearch(" << pnt << ", " << (int)o << ", " << first << ", " << last << ") " << retval);
+ return retval;
+ }
+
+
+int
+SDirIndexLogic::binaryRegionSearch( const IndexDS* ixDS,
+ const r_Minterval& mint,
+ r_Area& area,
+ KeyObjectVector& intersectedObjects,
+ int first,
+ int last)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SDirIndexLogic", "binaryRegionSearch(" << mint << ", " << area << ", vector, " << first << ", " << last << ")");
+ int retval = 0;
+ int middle = 0;
+ r_Minterval t;
+ int inc = 0;
+ int ix = 0;
+ r_Minterval objDomain;
+ int compResult = 0;
+ KeyObject newObj;
+ r_Minterval intersectedRegion;
+ // assumes order according to the lowest corner of the objects
+ if (first > last)
+ retval = -1;
+ else {
+ middle = (last + first) / 2;
+ t = ixDS->getObjectDomain(middle);
+ if (mint.get_high().compare_with(t.get_origin()) < 0)
+ {// R.hi < tile.lo no tiles after this one
+ retval = binaryRegionSearch(ixDS, mint, area, intersectedObjects, first, middle - 1);
+ }
+ else {
+ if (t.get_high().compare_with(mint.get_origin()) < 0)
+ {
+ retval = binaryRegionSearch(ixDS, mint, area, intersectedObjects, middle + 1, last);
+ if (area > 0)
+ retval = binaryRegionSearch(ixDS, mint, area, intersectedObjects, first, middle - 1);
+ }
+ else {
+ inc = 1;
+ ix = middle;
+ //starting to search forward, starting in the middle
+ while (true)
+ {
+ objDomain = ixDS->getObjectDomain(ix);
+ compResult = mint.get_high().compare_with(objDomain.get_origin());
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SDirIndexLogic", "position " << ix << " last " << last << " incrementor " << inc << " object domain " << objDomain << " compare " << compResult);
+ // object intersects region
+ if (objDomain.intersects_with(mint))
+ {
+ intersectedRegion = objDomain;
+ intersectedRegion.intersection_with(mint);
+ area = area - intersectedRegion.cell_count();
+ newObj = ixDS->getObject(ix);
+ intersectedObjects.push_back(newObj);
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SDirIndexLogic", "added one entry, intersected region " << intersectedRegion << " area left " << area);
+ }
+ if (inc != -1 && (ix == last || compResult < 0))
+ {
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SDirIndexLogic", "starting again at middle, but going backwards");
+ ix = middle;
+ inc = -1;
+ }
+ if (ix == first && inc == -1)//not needed:||first == last
+ {
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SDirIndexLogic", "breaking loop, arrived at start");
+ retval = ix;
+ break;
+ }
+ if (area <= 0)// || first == last || ix == first)
+ {
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SDirIndexLogic", "breaking loop, area is found");
+ retval = ix;
+ break;
+ }
+ ix += inc;
+ }
+ }
+ }
+ }
+
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SDirIndexLogic", "binaryRegionSearch(" << mint << ", " << area << ", vector, " << first << ", " << last << ") " << retval);
+ return retval;
+ }
+
+
+int
+SDirIndexLogic::compare(const r_Minterval& mint1,
+ const r_Minterval& mint2,
+ OrderPoint o1,
+ OrderPoint o2)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SDirIndexLogic", "compare(" << mint1 << ", " << mint2 << ", " << (int)o1 << ", " << (int)o2 << ")");
+ r_Point point1,point2;
+ switch(o1)
+ {
+ case Highest:
+ point1 = mint1.get_high();
+ break;
+ case Lowest:
+ point1 = mint1.get_origin();
+ break;
+ case None:
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SDirIndexLogic", "compare(...) o1 is None");
+ break;
+ }
+ switch(o2)
+ {
+ case Highest:
+ point2 = mint2.get_high();
+ break;
+ case Lowest:
+ point2 = mint2.get_origin();
+ break;
+ case None:
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SDirIndexLogic", "compare(...) o2 is None");
+ break;
+ }
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SDirIndexLogic", "compare(" << mint1 << ", " << mint2 << ", " << (int)o1 << ", " << (int)o2 << ") " << point1.compare_with(point2));
+ return point1.compare_with(point2);
+ }
+
+void
+SDirIndexLogic::intersect(const IndexDS* ixDS, const r_Minterval& searchInter, KeyObjectVector& intersectedObjs, const StorageLayout& sl)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SDirIndexLogic", "intersect(" << searchInter << ")");
+ r_Area area = 0;
+ int result = 0;
+ r_Minterval intersectArea(searchInter.dimension());
+ r_Minterval currDom(ixDS->getCoveredDomain());
+ // avoid exceptions from r_Minterval
+ if (!searchInter.intersects_with(currDom))
+ {
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SDirIndexLogic", "intersect(" << searchInter << ") search interval does not intersect wit current domain " << currDom);
+ }
+ else {
+ // Optimization: no need to search the whole area.
+ // only the area which is intersected by the current domain.
+ intersectArea.intersection_of(searchInter, currDom);
+ area = intersectArea.cell_count();
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SDirIndexLogic", "Area = " << area);
+ result = binaryRegionSearch(ixDS, intersectArea, area, intersectedObjs, 0, (int) ixDS->getSize() - 1);
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SDirIndexLogic", "intersect(" << searchInter << ") vectorsize: " << intersectedObjs.size());
+ }
+ }
+
+void
+SDirIndexLogic::intersectUnOpt(const IndexDS* ixDS, const r_Minterval& searchInter, KeyObjectVector& intersectedObjs)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SDirIndexLogic", "intersectUnOpt(" << searchInter << ")");
+ for(int i=0; i< ixDS->getSize(); i++)
+ {
+ r_Minterval objInterval = ixDS->getObjectDomain(i);
+ if (searchInter.intersects_with(objInterval))
+ {
+ KeyObject obj = ixDS->getObject(i);
+ intersectedObjs.push_back(obj);
+ }
+ }
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SDirIndexLogic", "intersectUnOpt(" << searchInter << ") vectorsize: " << intersectedObjs.size());
+ }
+
+void
+SDirIndexLogic::containPointQuery(const IndexDS* ixDS, const r_Point& searchPoint, KeyObject& result, const StorageLayout& sl)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SDirIndexLogic", "containPointQuery(" << searchPoint << ")");
+ int ix = binaryPointSearch(ixDS, searchPoint, Lowest, 0, (int) ixDS->getSize() - 1);
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SDirIndexLogic", "result from binaryPointSearch ix " << ix);
+
+ if (ix >= 0)
+ {
+ result = ixDS->getObject(ix);
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SDirIndexLogic", "containPointQuery(" << searchPoint << ") " << result);
+ }
+ else {
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SDirIndexLogic", "containPointQuery(" << searchPoint << ") nothing found ");
+ }
+ }
+
+void
+SDirIndexLogic::getObjects(const IndexDS* ixDS, KeyObjectVector& objs, const StorageLayout& sl)
+ {
+ RMDBGONCE(4, RMDebug::module_indexmgr, "SDirIndexLogic", "getObjects()");
+ ixDS->getObjects(objs);
+ }
+
+bool
+SDirIndexLogic::removeObject(IndexDS* ixDS, const KeyObject& objToRemove, const StorageLayout& sl)
+ {
+ RMDBGONCE(4, RMDebug::module_indexmgr, "SDirIndexLogic", "removeObject(" << objToRemove << ")");
+ return ixDS->removeObject(objToRemove);
+ }
+
diff --git a/indexmgr/sdirindexlogic.hh b/indexmgr/sdirindexlogic.hh
new file mode 100644
index 0000000..f94084c
--- /dev/null
+++ b/indexmgr/sdirindexlogic.hh
@@ -0,0 +1,169 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#ifndef _DIRIX_HH_
+#define _DIRIX_HH_
+
+#include "reladminif/lists.h"
+class r_Point;
+class StorageLayout;
+
+/***********************
+ *
+ * INCLUDE: dirix.hh
+ *
+ * MODULE: indexmgr
+ * CLASS: SDirIndexLogic
+ *
+ *
+ * COMMENTS:
+ *
+ ***********/
+
+//@ManMemo: Module: {\bf indexmgr}
+/*@Doc:
+
+ The SDirIndexLogic class implements a Directory of Interval Objects Index.
+
+ Objects inserted in the index must be disjunctive, since optimizations
+ are made which assume nonoverlapping interval objects.
+
+ It can be used as index on tiles of MDD objects.
+ A directory index consists solely of the current domain and
+ a list of entries, one for each interval object (for instance, a tile).
+ Interval objects must not overlap, since {\tt SDirIndexLogic} optimizes access
+ based on the assumption that entries don't overlap. Entries are
+ sorted by the lower vertice.
+ Each entry contains the interval domain and a reference to the object
+ itself.
+
+ SDirIndexLogic implements the higher level index functionality and uses the
+ functionality of {\tt IndexDS} to do the operations.
+
+ This way, {\tt SDirIndexLogic} can be used for both persistent or
+ main memory indexes, tiles index or intermediate nodes of a multidimensional
+ index, etc, by defining appropriate {\tt IndexDS} classes. Examples are
+ {\tt TransDirIx} and {\tt DBHierIndex}, for transient and persistent
+ indexes, respectively.A
+
+ The logic classes are stack based for performance and memory reasons -> everything is static.
+*/
+
+class SDirIndexLogic
+ {
+ public:
+
+ static bool insertObject(IndexDS* theIx, const KeyObject& newObject, const StorageLayout& sl);
+ /*@Doc:
+ Inserts a new object in the index.
+ */
+
+ static bool removeObject(IndexDS* theIx, const KeyObject& tileToRemove, const StorageLayout& sl);
+ /*@Doc:
+ Removes the tile from the object.
+ */
+
+ static void intersect(const IndexDS* theIx, const r_Minterval& searchInter, KeyObjectVector& objs, const StorageLayout& sl);
+ /*@Doc:
+ Search the index for a search region.
+ Determines all the tiles in the index which intersect a given
+ search interval (given by {\tt searchInter}).
+ The memory space allocated by this function for the contents
+ of the keyobjects in the returned vector (only) must be released
+ afterwards by the caller.
+ */
+
+ static void intersectUnOpt(const IndexDS* theIx, const r_Minterval& searchInter, KeyObjectVector& objs);
+ /*@Doc:
+ Search the index for a search region.
+ Old unoptimized version of intersect(). Just scans all the entries,
+ tests each one for intersection, returning all that intersect.
+ This method is actually used for removing of tiles (a tile can be stored in multiple nodes).
+ */
+
+ static void containPointQuery(const IndexDS* theIx, const r_Point& searchPoint, KeyObject& result, const StorageLayout& sl);
+ /*@Doc:
+ Passes a pointer to the searched item.
+ Memory is for the KeyObject is not to be released by the caller.
+ */
+
+ static void getObjects(const IndexDS* ixDS, KeyObjectVector& objs, const StorageLayout& sl);
+ /*@Doc:
+ Returns all the tiles belonging to the object.
+ */
+
+ enum OrderPoint
+ {
+ Highest = 1,
+ Lowest = 2,
+ None = 0
+ };
+ /*@Doc:
+ */
+
+ static int compare( const r_Minterval& mint1,
+ const r_Minterval& mint2,
+ OrderPoint o1 = Lowest,
+ OrderPoint o2 = Lowest);
+ /*@Doc:
+ Compares two intervals based on two points from each one.
+ Returns : -1 if mint1.point(o1) < mint2.point(o2);
+ 0 iff mint1.point(o1) == mint2.point(o2) and
+ 1 iff mint1.point(o1) > mint2.point(o2); where
+ mint.point(o) is the lowest corner point of mint if o == Lowest,
+ mint.point(o) is the highest corner point of mint if o == Highest.
+ */
+
+ static int binarySearch( const IndexDS* theIx,
+ const r_Minterval& newDomain,
+ OrderPoint o,
+ int first,
+ int last);
+ /*@Doc:
+ Returns position of searched item or position before the one where
+ it should be inserted to keep the order of the list (-1 means it should be
+ inserted at the beginning of the list).
+ */
+
+ static int binaryPointSearch( const IndexDS* theIx,
+ const r_Point& pnt,
+ OrderPoint o,
+ int first,
+ int last);
+ /*@Doc:
+ Returns position of tile having the point, -1 if point not there.
+ */
+
+ static int binaryRegionSearch( const IndexDS* theIx,
+ const r_Minterval& mint,
+ r_Area& area,
+ KeyObjectVector& intersectedObjects,
+ int first,
+ int last);
+ /*@Doc:
+ Assumes ordering according to the lowest corner of the tiles!!!
+ */
+
+ };
+
+#endif
diff --git a/indexmgr/srcindexlogic.cc b/indexmgr/srcindexlogic.cc
new file mode 100644
index 0000000..b2e6d4b
--- /dev/null
+++ b/indexmgr/srcindexlogic.cc
@@ -0,0 +1,288 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * MODULE: indexmgr
+ * CLASS: SRCIndexLogic
+ *
+ * COMMENTS:
+ *
+*/
+
+static const char rcsiddirix[] = "@(#)dirix, SRCIndexLogic: $Id: srcindexlogic.cc,v 1.8 2002/09/19 11:38:25 hoefner Exp $";
+
+#include <iostream>
+#include <math.h>
+#include "raslib/rmdebug.hh"
+#include "raslib/odmgtypes.hh"
+#include "indexmgr/srcindexlogic.hh"
+#include "keyobject.hh"
+#include "indexds.hh"
+#include "relindexif/dbrcindexds.hh"
+#include "storagemgr/sstoragelayout.hh"
+#include "relblobif/tileid.hh"
+#include "relblobif/blobtile.hh"
+#include "raslib/mitera.hh"
+
+unsigned int
+SRCIndexLogic::computeNumberOfTiles(const StorageLayout& sl, const r_Minterval& mddDomain)
+ {
+/*
+ cout << "mddDomain " << mddDomain << endl;
+ cout << "mddDomain extent " << mddDomain.get_extent() << endl;
+ cout << "tileConfig " << sl.getTileConfiguration() << endl;
+ cout << "tileConfig extent " << sl.getTileConfiguration().get_extent() << endl;
+ cout << "normalized " << temp << endl;
+ cout << "cell count " << temp.cell_count() << endl;
+*/
+ return computeNormalizedDomain(mddDomain.get_extent(), sl.getTileConfiguration().get_extent()).cell_count();
+ }
+
+r_Minterval
+SRCIndexLogic::computeNormalizedDomain(const r_Point& mddDomainExtent, const r_Point& tileConfigExtent)
+ {
+ r_Dimension theDim = mddDomainExtent.dimension();
+ r_Minterval normalizedDomain(theDim);
+ r_Range normalized = 0;
+
+ for (r_Dimension dim = 0; dim < theDim; dim++)
+ {
+ normalized = (r_Range)(mddDomainExtent[dim]/tileConfigExtent[dim]) - 1;
+ //cout << "mdd domain extent [" << dim << "] " << mddDomainExtent[dim] << endl;
+ //cout << "tile config extent [" << dim << "] " << tileConfigExtent[dim] << endl;
+ //cout << "division " << mddDomainExtent[dim]/tileConfigExtent[dim] << endl;
+ //cout << "normalized " << normalized << endl;
+ //remove this if we support rc index with border tiles
+ if ((normalized + 1)* tileConfigExtent[dim] != mddDomainExtent[dim])
+ {
+ //cout << "got you" << endl;
+ RMInit::logOut << "SRCIndexLogic::computeNormalizedDomain() the mdd domain does not fit the tile configuration" << endl;
+ throw r_Error(TILECONFIGMARRAYINCOMPATIBLE);
+ }
+ normalizedDomain[dim] = r_Sinterval(0, normalized);
+ }
+ RMDBGONCE(4, RMDebug::module_indexmgr, "SRCIndexLogic", "computeNormalizedDomain(" << mddDomainExtent << ", " << tileConfigExtent << ") " << normalizedDomain);
+ return normalizedDomain;
+ }
+
+r_Point
+SRCIndexLogic::computeNormalizedPoint(const r_Point& toNormalize, const r_Point& tileConfigExtent, const r_Point& mddDomainOrigin)
+ {
+ r_Dimension theDim = mddDomainOrigin.dimension();
+ r_Point normalizedPoint(theDim);
+
+ for (r_Dimension dim = 0; dim < theDim; dim++)
+ {
+ normalizedPoint[dim] = (r_Range)((toNormalize[dim] - mddDomainOrigin[dim])/tileConfigExtent[dim]);
+ }
+ RMDBGONCE(4, RMDebug::module_indexmgr, "SRCIndexLogic", "computeNormalizedPoint(" << toNormalize << ", " << tileConfigExtent << ", " << mddDomainOrigin << ") " << normalizedPoint);
+ return normalizedPoint;
+ }
+
+r_Minterval
+SRCIndexLogic::computeDomain(const r_Point& toConvert, const r_Point& tileConfigExtent, const r_Point& mddDomainOrigin)
+ {
+ r_Dimension theDim = mddDomainOrigin.dimension();
+ r_Minterval result(theDim);
+ r_Range high = 0;
+ r_Range low = 0;
+ r_Range offset = 0;
+ r_Range toConvTemp = 0;
+
+ for (r_Dimension dim = 0; dim < theDim; dim++)
+ {
+ toConvTemp = toConvert[dim];
+ offset = fmod((r_Double)(toConvTemp - mddDomainOrigin[dim]), tileConfigExtent[dim]);
+ low = toConvTemp - offset;
+ //there has to be a check if we support border tiles.
+ high = toConvTemp - offset + tileConfigExtent[dim];
+ result[dim] = r_Sinterval(low, high);
+ }
+ RMDBGONCE(4, RMDebug::module_indexmgr, "SRCIndexLogic", "computeDomain(" << toConvert << ", " << tileConfigExtent << ", " << mddDomainOrigin << ") " << result);
+ return result;
+ }
+
+OId
+SRCIndexLogic::computeOId(const r_Minterval& mddDomain, const r_Point& tileConfigExtent, OId::OIdCounter baseCounter, OId::OIdType type, const r_Point& tileOrigin)
+ {
+ OId::OIdCounter counter;
+ counter = computeNormalizedDomain(mddDomain.get_extent(), tileConfigExtent).cell_offset(computeNormalizedPoint(tileOrigin, tileConfigExtent, mddDomain.get_origin())) + baseCounter;
+ RMDBGONCE(4, RMDebug::module_indexmgr, "SRCIndexLogic", "computeOId(" << mddDomain << ", " << tileConfigExtent << ", " << baseCounter << ", " << tileOrigin << ") " << OId(counter, type));
+ return OId(counter, type);
+ }
+
+bool
+SRCIndexLogic::insertObject(IndexDS* ixDS, const KeyObject& newKeyObject, const StorageLayout& sl)
+ {
+ //this method should check if the tile is actually in the tiling
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SRCIndexLogic", "insertObject(" << newKeyObject << ")");
+
+ RMInit::logOut << "SRCIndexLogic::insertObject(" << ixDS->getIdentifier() << ", " << newKeyObject << ", sl) insert operation not allowed" << endl;
+ throw r_Error(INSERTINTORCINDEX);
+ //if src is able to extend:
+ r_Minterval newKeyObjectDomain = newKeyObject.getDomain();
+ r_Minterval tileConfig = sl.getTileConfiguration();
+ r_Minterval mddDomain = ixDS->getCoveredDomain();
+ OId newBlobOId(computeOId(mddDomain, tileConfig.get_extent(), ((DBRCIndexDS*)ixDS)->getBaseCounter(), ((DBRCIndexDS*)ixDS)->getBaseOIdType(), newKeyObjectDomain.get_origin()));
+ DBTileId tile = newKeyObject.getObject();
+ BLOBTile* t = new BLOBTile(tile->getSize(), tile->getCells(), tile->getDataFormat(), newBlobOId);
+ // is done in the constructor
+ //t->setPersistent(true);
+ tile->setPersistent(false);
+
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SRCIndexLogic", "insertObject(" << newKeyObject << ")");
+ //should check if insertion was succesfull
+ return true;
+ }
+
+/*
+r_Minterval
+SRCIndexLogic::computeDomain(const r_Point& toConvert, const r_Point& tileConfigExtent, const r_Point& mddDomainOrigin)
+ {
+ r_Dimension theDim = mddDomainOrigin.dimension();
+ r_Minterval result(theDim);
+ r_Range high = 0;
+ r_Range low = 0;
+ r_Range offset = 0;
+ r_Range toConvTemp = 0;
+
+ for (r_Dimension dim = 0; dim < theDim; dim++)
+ {
+ toConvTemp = toConvert[dim];
+ offset = fmod((toConvTemp - mddDomainOrigin[dim]), tileConfigExtent[dim]);
+ low = toConvTemp - offset;
+ high = toConvTemp - offset + tileConfigExtent[dim];
+ result[dim] = r_Sinterval(low, high);
+ }
+ return result;
+ }
+*/
+
+r_Minterval
+SRCIndexLogic::computeTiledDomain(const r_Minterval& completeDomain, const r_Point& tileConfigExtent, const r_Minterval& widenMe)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SRCIndexLogic", "computeTiledDomain(" << completeDomain << ", " << tileConfigExtent << ", " << widenMe << ")");
+ r_Minterval searchDomain(completeDomain.create_intersection(widenMe));
+ r_Dimension theDim = searchDomain.dimension();
+ r_Minterval retval(theDim);
+ r_Range high = 0;
+ r_Range low = 0;
+ r_Range offsetlow = 0;
+ r_Range offsethigh = 0;
+ r_Range mddOrigin = 0;
+ r_Range tileExtent = 0;
+ r_Sinterval currSi;
+ r_Point mddDomainOrigin = completeDomain.get_origin();
+ RMDBGMIDDLE(5, RMDebug::module_indexmgr, "SRCIndexLogic", "search domain " << searchDomain << " mdd origin " << mddDomainOrigin)
+
+ for (r_Dimension dim = 0; dim < theDim; dim++)
+ {// make retval fit the tiling layout
+ currSi = searchDomain[dim];
+ low = currSi.low();
+ high = currSi.high();
+ mddOrigin = mddDomainOrigin[dim];
+ tileExtent = tileConfigExtent[dim];
+ offsetlow = (low - mddOrigin)%tileExtent;
+ offsethigh = (high - mddOrigin)%tileExtent;
+ //this has to be revised if we support border tiles
+ retval[dim] = r_Sinterval(low - offsetlow, high - offsethigh + tileExtent - 1);
+ RMDBGMIDDLE(6, RMDebug::module_indexmgr, "SRCIndexLogic", "mdd interval " << currSi << " offset low " << offsetlow << " offset high " << offsethigh << " tile extent " << tileExtent)
+ }
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SRCIndexLogic", "computeTiledDomain(" << completeDomain << ", " << tileConfigExtent << ", " << widenMe << ") " << retval);
+ return retval;
+ }
+
+void
+SRCIndexLogic::intersect(const IndexDS* ixDS, const r_Minterval& searchInter, KeyObjectVector& intersectedObjs, const StorageLayout& sl)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SRCIndexLogic", "intersect(" << searchInter << ")");
+ r_Minterval mddDomain = ixDS->getCoveredDomain();
+ if (searchInter.intersects_with(mddDomain))
+ {
+ r_Minterval tileConfig = sl.getTileConfiguration();
+ r_Point tileConfigExtent = tileConfig.get_extent();
+ OId::OIdCounter baseCounter = ((DBRCIndexDS*)ixDS)->getBaseCounter();
+ OId::OIdType type = ((DBRCIndexDS*)ixDS)->getBaseOIdType();
+ r_Dimension dim = mddDomain.dimension();
+ r_Point searchPoint(dim);
+ r_Minterval searchDomain = computeTiledDomain(mddDomain, tileConfigExtent, searchInter);
+ r_MiterArea iter(&tileConfig, &searchDomain);
+ r_Minterval iterArea(dim);
+
+ while (!iter.isDone())
+ {//iterate through the partitions in the search domain
+ iterArea = iter.nextArea();
+ r_Point orig = iterArea.get_origin();
+ OId t = computeOId(mddDomain, tileConfigExtent, baseCounter, type, orig);
+ DBObjectId theObject(t);
+ //the domain of the object has to be adapted to the border tiles
+ if (!theObject.is_null())
+ {
+ theObject->setCached(true);
+ }
+ else {
+ theObject = new BLOBTile(t, sl.getTileSize(), sl.getDataFormat(orig));
+ theObject->setCached(true);
+ }
+ intersectedObjs.push_back(KeyObject(theObject, iterArea));
+ }
+ }
+ }
+
+void
+SRCIndexLogic::containPointQuery(const IndexDS* ixDS, const r_Point& searchPoint, KeyObject& result, const StorageLayout& sl)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SRCIndexLogic", "containPointQuery(" << searchPoint << ")");
+ r_Minterval mddDomain = ixDS->getCoveredDomain();
+ if (mddDomain.covers(searchPoint))
+ {
+ r_Minterval tileConfig = sl.getTileConfiguration();
+ r_Point tileConfigExtent = tileConfig.get_extent();
+ OId t = computeOId(mddDomain, tileConfigExtent, ((DBRCIndexDS*)ixDS)->getBaseCounter(), ((DBRCIndexDS*)ixDS)->getBaseOIdType(), searchPoint);
+ DBObjectId theObject(t);
+ if (!theObject.is_null())
+ {
+ theObject->setCached(true);
+ }
+ else {
+ theObject = new BLOBTile(t, sl.getTileSize(), sl.getDataFormat(searchPoint));
+ }
+ result.setDomain(computeDomain(searchPoint, tileConfigExtent, mddDomain.get_origin()));
+ result.setObject(theObject.getOId());
+ }
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SRCIndexLogic", "containPointQuery(" << searchPoint << ") " << result);
+ }
+
+void
+SRCIndexLogic::getObjects(const IndexDS* ixDS, KeyObjectVector& objs, const StorageLayout& sl)
+ {
+ RMDBGONCE(4, RMDebug::module_indexmgr, "SRCIndexLogic", "getObjects()");
+ intersect(ixDS, ixDS->getCoveredDomain(), objs, sl);
+ }
+
+bool
+SRCIndexLogic::removeObject(IndexDS* ixDS, const KeyObject& objToRemove, const StorageLayout& sl)
+ {
+ RMDBGONCE(4, RMDebug::module_indexmgr, "SRCIndexLogic", "removeObject(" << objToRemove << ")");
+ return true;
+ }
+
diff --git a/indexmgr/srcindexlogic.hh b/indexmgr/srcindexlogic.hh
new file mode 100644
index 0000000..92b0869
--- /dev/null
+++ b/indexmgr/srcindexlogic.hh
@@ -0,0 +1,132 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * MODULE: indexmgr
+ * CLASS: SRCIndexLogic
+ *
+ * COMMENTS:
+ *
+*/
+
+#ifndef _SRCINDEXLOGIC_HH_
+#define _SRCINDEXLOGIC_HH_
+
+#include "reladminif/lists.h"
+#include "raslib/minterval.hh"
+#include "reladminif/oidif.hh"
+
+class r_Point;
+class StorageLayout;
+class SRCIndexLogic;
+
+//@ManMemo: Module: {\bf indexmgr}
+/*@Doc:
+
+The regular computed index uses DBRCIndexDS and StorageLayout to store its persistent data.
+The point is:
+ The tiles all have the same layout.
+ The domain of the mdd is fixed.
+With those preliminaries it is possible to speed up the index considerably.
+DBRCIndexDS stores the domain of the mdd object, the first OIdCounter and the OIdType of the entries.
+The storage layout stores the tile configuration.
+
+An algorithm computes the oid of a tile using the complete domain and the tile configuration.
+
+The number of allocated oids has to be stored in the DBRCIndexDS because the DBRCIndexDS has to delete
+all tiles belonging to it without information on the tile configuration (an hence cannot compute its
+size).
+
+*/
+
+class SRCIndexLogic
+ {
+ public:
+
+ static unsigned int computeNumberOfTiles(const StorageLayout& sl, const r_Minterval& mddDomain);
+ /*@Doc:
+ Compute the number of tiles that will have to be allocated by the index. This is based on the tile config from storagelayout and the domain covered by the mdd.
+ */
+
+ static bool insertObject(IndexDS* theIx, const KeyObject& newObject, const StorageLayout& sl);
+ /*@Doc:
+ Inserts a new object in the index. Creates a new tile which has the oid that belongs to that domain. The original tile is deleted from database.
+ */
+
+ static bool removeObject(IndexDS* theIx, const KeyObject& tileToRemove, const StorageLayout& sl);
+ /*@Doc:
+ Removes the tile from the object.
+ */
+
+ static void intersect(const IndexDS* theIx, const r_Minterval& searchInter, KeyObjectVector& objs, const StorageLayout& sl);
+ /*@Doc:
+ Search the index for a search region.
+ Determines all the tiles in the index which intersect a given
+ search interval (given by {\tt searchInter}).
+ The memory space allocated by this function for the contents
+ of the keyobjects in the returned vector (only) must be released
+ afterwards by the caller.
+ */
+
+ static void containPointQuery(const IndexDS* theIx, const r_Point& searchPoint, KeyObject& result, const StorageLayout& sl);
+ /*@Doc:
+ Passes a pointer to the searched item.
+ Memory is for the KeyObject is not to be released by the caller.
+ */
+
+ static void getObjects(const IndexDS* ixDS, KeyObjectVector& objs, const StorageLayout& sl);
+ /*@Doc:
+ Returns all the tiles belonging to the object.
+ */
+
+ protected:
+
+ static r_Minterval computeNormalizedDomain(const r_Point& mddDomainExtent, const r_Point& tileConfigExtent);
+ /*@Doc:
+ compute the normalized matrix from the extent of the domain and the extent of the tile config.
+ */
+
+ static r_Point computeNormalizedPoint(const r_Point& toNormalize, const r_Point& tileConfigExtent, const r_Point& mddDomainOrigin);
+ /*@Doc:
+ compute the normalized point from the point, the extent of the tile config and the origin of the mdd domain.
+ this point is then used to calculate the number of the tile in the normailzed matrix.
+ */
+
+ static r_Minterval computeDomain(const r_Point& toConvert, const r_Point& tileConfigExtent, const r_Point& mddDomainOrigin);
+ /*@Doc:
+ compute the tile domain based on the point inside that domain, the tile config extent and the origin of the mdd.
+ */
+
+ static OId computeOId(const r_Minterval& mddDomain, const r_Point& tileConfigExtent, OId::OIdCounter baseCounter, OId::OIdType type, const r_Point& tileOrigin);
+ /*@Doc:
+ compute the oid of an entry based on the domain of the mdd, the extent of the tile config, the starting oid adress, the type of oid and the origin of the tile domain.
+ */
+
+ static r_Minterval computeTiledDomain(const r_Minterval& completeDomain, const r_Point& tileConfigExtent, const r_Minterval& widenMe);
+ /*@Doc:
+ compute the completely tiled domain, which is the intersection of the complete domain and the domain to be tiled (widenMe), based on the tile config.
+ Example: user requests tiles in domain [3:5]. the tile config is [1], the complete domain is [2:7]. the result will be [2:5] because [3:3] belongs to the tile [2:3].
+ */
+
+ };
+
+#endif
diff --git a/indexmgr/srptindexlogic.cc b/indexmgr/srptindexlogic.cc
new file mode 100644
index 0000000..8ddc26b
--- /dev/null
+++ b/indexmgr/srptindexlogic.cc
@@ -0,0 +1,1147 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#include "indexmgr/srptindexlogic.hh"
+#include "raslib/rmdebug.hh"
+#include "tilemgr/tile.hh"
+#include "raslib/point.hh"
+#include "indexmgr/sdirindexlogic.hh"
+#include <math.h>
+#include "indexmgr/keyobject.hh"
+#include "relindexif/hierindex.hh"
+#include "reladminif/dbref.hh"
+#include "relindexif/indexid.hh"
+
+const float ff = 0.5;
+
+//removes all entries from a index and inserts them into a vector
+void
+clear(KeyObjectVector& keyvec, HierIndexDS* node)
+ {
+ RMDBGENTER(7, RMDebug::module_indexmgr, "SRPTIndexLogic", "clear(keyvec, " << OId(node->getIdentifier()) << ")");
+ unsigned int i = 0;
+ unsigned int nodeSize = node->getSize();
+
+ keyvec.reserve(nodeSize);
+ while (!keyvec.empty())
+ {
+ keyvec.erase(keyvec.begin());
+ }
+ for(i = 0; i < nodeSize; i++)
+ {
+ keyvec.push_back(node->getObject(0));
+ node->removeObject((unsigned int)0);
+ }
+ RMDBGEXIT(7, RMDebug::module_indexmgr, "SRPTIndexLogic", "clear(keyvec, " << OId(node->getIdentifier()) << ")");
+ }
+
+/*this may be usefull when getting rid of the extendFaces method
+unsigned int
+findNearestNode(IndexDS* whereToLook, const r_Minterval& theEntryDomain)
+ {
+ r_Minterval sum(theEntryDomain.dimension());
+//this code is not used -> no pror
+ r_Area smallestArea = (r_Area)0xFFFFFFFF;
+ unsigned int smallestAreaAt = 0;
+ unsigned long currentArea = 0;
+ unsigned int i = 0;
+ unsigned int numElems = whereToLook->getSize();
+
+ for (i = 0; i < numElems; i++)
+ {
+ currentArea = sum.closure_of(whereToLook->getObjectDomain(i), theEntryDomain).cell_count();
+ if (currentArea <= smallestArea)
+ {
+ smallestArea = currentArea;
+ smallestAreaAt = i;
+ }
+ }
+ return smallestAreaAt;
+ }
+*/
+
+bool
+SRPTIndexLogic::insertObject2(IndexDS* ixDS, const KeyObject& newKeyObject, const StorageLayout& sl)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "insertObject2(" << OId(ixDS->getIdentifier()) << ", " << newKeyObject << ")")
+ IndexPVector leafNodes2Split;
+ r_Minterval newKeyObjectDom;
+ r_Minterval cd;
+ bool extend = false;
+ bool* facesToExtendLo = NULL;
+ bool* facesToExtendHi = NULL;
+ r_Dimension i = 0;
+ r_Dimension dim = 0;
+ unsigned int overflowed = 0;
+
+ if (ixDS->getSize() == 0)
+ {
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "Index is empty. only set domain");
+ ixDS->setAssignedDomain(newKeyObject.getDomain());
+ }
+ else {
+ // initialize facesToExtend
+ newKeyObjectDom = newKeyObject.getDomain();
+ cd = ixDS->getCoveredDomain();
+ dim = cd.dimension();
+ extend = false;
+ facesToExtendLo = new bool[dim];
+ facesToExtendHi = new bool[dim];
+ for(i = 0; i < dim; i++)
+ {
+ if (newKeyObjectDom[i].low() < cd[i].low())
+ {
+ facesToExtendLo[i] = true;
+ extend = true;
+ }
+ else
+ facesToExtendLo[i] = false;
+
+ if (newKeyObjectDom[i].high() > cd[i].high())
+ {
+ facesToExtendHi[i] = true;
+ extend = true;
+ }
+ else
+ facesToExtendHi[i] = false;
+ }
+
+ // Implementation note:
+ // the extension of faces could be integrated with the insertObject()
+ // function and result in a more efficient but more complex implementation
+ // (a nonrecursive extendFaces() woul be needed and insertObject()
+ // changed to have additional parameters oldCurrDom, facesToExtendLo,
+ // facesToExtendHi).
+ // The simple solution was chosen, where the whole tree is first updated
+ // for the new borders and then the insertion is made.
+ // Another solution would be the implementation of the external borders as
+ // infinite. Each node would have to have both a current domain and a domain.
+
+ if (extend)
+ {
+ SRPTIndexLogic::extendFaces((HierIndexDS*)ixDS, newKeyObjectDom, cd, facesToExtendLo, facesToExtendHi);
+ }
+ else {
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "no need to extend faces");
+ }
+ delete[] facesToExtendLo;
+ facesToExtendLo = NULL;
+ delete[] facesToExtendHi;
+ facesToExtendHi = NULL;
+ }
+
+ // call recursive insertObject()
+ overflowed = SRPTIndexLogic::insertObject(newKeyObject, (HierIndexDS*)ixDS, leafNodes2Split, sl);
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "number of leaf overflows " << leafNodes2Split.size())
+
+ if (!leafNodes2Split.empty())
+ SRPTIndexLogic::splitNodes((HierIndexDS*)ixDS, leafNodes2Split, sl);
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "insertObject2(" << OId(ixDS->getIdentifier()) << ", " << newKeyObject << ")")
+ //there should be a check here : )
+ return true;
+ }
+
+void
+SRPTIndexLogic::intersect2(const IndexDS* ixDS, const r_Minterval& searchInter, KeyObjectVector& intersectedObjs, const StorageLayout& sl)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "intersect2(" << OId(ixDS->getIdentifier()) << ", " << searchInter << ")")
+ r_Minterval dom = ixDS->getCoveredDomain();
+ r_Area area = 0;
+
+ // avoid exceptions from r_Minterval
+ if (searchInter.intersects_with(dom))
+ {
+ //this is neccessary because intersectNoDuplicats would think there were other index nodes that cover this area.
+ r_Minterval searchDom = searchInter.create_intersection(dom);
+ //needed this parent domain, or else indexes with one level only don't work
+ area = searchDom.cell_count();
+ SRPTIndexLogic::intersect(searchDom, dom, intersectedObjs, (const HierIndexDS*)ixDS, area);
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "intersect2(" << OId(ixDS->getIdentifier()) << "*, " << searchInter << ") found #" << intersectedObjs.size() << " matches");
+ }
+ else {
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "intersect2(" << OId(ixDS->getIdentifier()) << "* dom " << dom << ", " << searchInter << ") don't intersect");
+ }
+ }
+
+void
+SRPTIndexLogic::containPointQuery2(const IndexDS* ixDS, const r_Point& searchPoint, KeyObject& result, const StorageLayout& sl)
+ {
+ SRPTIndexLogic::containPointQuery(searchPoint, (const HierIndexDS*)ixDS, result, sl);
+ }
+
+void
+SRPTIndexLogic::getObjects(const IndexDS* ixDS, KeyObjectVector& objs, const StorageLayout& sl)
+ {
+ // can be optimized !!!
+ intersect2((const HierIndexDS*)ixDS, ixDS->getCoveredDomain(), objs, sl);
+ }
+
+int
+SRPTIndexLogic::insertObject( const KeyObject& newKeyObject,
+ HierIndexDS* ix,
+ IndexPVector& leafNodes2Split,
+ const StorageLayout& sl)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "insertObject(" << newKeyObject << ", " << OId(ix->getIdentifier()) << ", leafNodes2Split.size " << leafNodes2Split.size() << ")")
+ int overflowed = 0;
+
+ if (ix->isLeaf())
+ {
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "ix is Leaf")
+ //this is new
+ r_Minterval oldDom = ix->getCoveredDomain();
+ SDirIndexLogic::insertObject(ix, newKeyObject, sl);
+ ix->setAssignedDomain(oldDom);
+ // no node overflow, simply insert newEntry
+ if (ix->isOverFull())
+ {// node overflow: add node to list of nodes to split
+ overflowed = 1;
+ leafNodes2Split.push_back(ix);
+ }
+ else {
+ if (!ix->isRoot())
+ {
+ ix->destroy();
+ }
+ }
+ }
+ else {
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "ix is Node")
+ KeyObjectVector intersectedNodes;
+ KeyObjectVector::iterator nodeIt;
+ SDirIndexLogic::intersect(ix, newKeyObject.getDomain(), intersectedNodes, sl);
+ while (!intersectedNodes.empty())
+ {
+ overflowed = overflowed + insertObject(newKeyObject, DBHierIndexId((*(intersectedNodes.begin())).getObject()).ptr(), leafNodes2Split, sl);
+ intersectedNodes.erase(intersectedNodes.begin());
+ }
+ }
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "insertObject(" << newKeyObject << ", ix, leafNodes2Split.size " << leafNodes2Split.size() << ") " << overflowed)
+ return overflowed;
+ }
+
+
+void
+SRPTIndexLogic::extendFaces( HierIndexDS* ix,
+ const r_Minterval& newKeyObjectDom,
+ const r_Minterval& oldCurrDom,
+ const bool* facesToExtendLo,
+ const bool* facesToExtendHi)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "extendFaces(" << OId(ix->getIdentifier()) << ", " << newKeyObjectDom << ", " << oldCurrDom << ", facesToExtendLo, facesToExtendHi)");
+ bool extendEntries = false;
+ unsigned int numberElems = 0;
+ r_Dimension dim = 0;
+ r_Dimension i = 0;
+ r_Dimension d = 0;
+ r_Minterval entryDom;
+ bool follow = false;
+ r_Minterval ixDom = oldCurrDom;//ix->getCoveredDomain();
+
+ if (ix->isLeaf())
+ {
+ if (!(ix->isRoot())) // nothing to do!!!
+ {//this entry's domain was set in the previous call of extendFaces
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", OId(ix->getIdentifier()) << " is Leaf and not Root - already updated");
+ ix->destroy();
+ ix = 0;
+ }
+ else {// ix is both leaf and root, one node only!! must update domain
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", OId(ix->getIdentifier()) << " is Leaf and Root - update domain");
+ ixDom.closure_with(newKeyObjectDom);
+ ix->setAssignedDomain(ixDom);
+ }
+ }
+ else {
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", OId(ix->getIdentifier()) << " is Node");
+ dim = newKeyObjectDom.dimension();
+ for (i = 0; i < dim; i++)
+ {
+ if (facesToExtendLo[i] && (ixDom[i].low() == oldCurrDom[i].low()))
+ {
+ ixDom[i].set_low(newKeyObjectDom[i].low());
+ extendEntries = true;
+ }
+ if (facesToExtendHi[i] && (ixDom[i].high() == oldCurrDom[i].high()))
+ {
+ ixDom[i].set_high(newKeyObjectDom[i].high());
+ extendEntries = true;
+ }
+ }
+ if (extendEntries)
+ {
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "must extend entries");
+ numberElems = ix->getSize();
+ for (i = 0; i < numberElems; i++)
+ {
+ follow = false;
+ entryDom = ix->getObjectDomain(i);
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "Entry #" << i << " has domain " << entryDom);
+ for(d = 0; d < dim; d++)
+ {
+ if (facesToExtendLo[d] && (entryDom[d].low() == oldCurrDom[d].low()))
+ {
+ entryDom[d].set_low(newKeyObjectDom[d].low());
+ follow = true;
+ }
+ if (facesToExtendHi[d] && (entryDom[d].high() == oldCurrDom[d].high()))
+ {
+ entryDom[d].set_high(newKeyObjectDom[d].high());
+ follow = true;
+ }
+ }
+ if (follow)
+ {
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "Entry #" << i << " must be extended to " << entryDom);
+ HierIndexDS* child = convert(ix->getObject(i));
+ extendFaces(child, newKeyObjectDom, oldCurrDom, facesToExtendLo, facesToExtendHi);
+ ix->setObjectDomain(entryDom, i);
+ }
+ }
+ }
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "new Domain of " << OId(ix->getIdentifier()) << " is " << ix->getCoveredDomain());
+ if (!ix->isRoot())
+ {
+ ix->destroy();
+ ix =0;
+ }
+ }
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "extendFaces(ixMayBeNull, " << newKeyObjectDom << ", " << oldCurrDom << ", facesToExtendLo, facesToExtendHi)");
+ }
+
+
+
+void
+SRPTIndexLogic::splitNodes(HierIndexDS* ixDS, IndexPVector& leafNodes2Split, const StorageLayout& sl)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "splitNodes(" << OId(ixDS->getIdentifier()) << ", leafNodes2Split)")
+ HierIndexDS* parentIxDS = NULL;
+ HierIndexDS* leafNodeIxDS = NULL;
+ HierIndexDS* n1 = NULL;
+ HierIndexDS* n2 = NULL;
+ HierIndexDS* nln1 = NULL; // non leaf nodes
+ HierIndexDS* nln2 = NULL; // non leaf nodes
+ HierIndexDS* tempPar = NULL;
+ r_Dimension axis = 0;
+ r_Range value = 0;
+ int parentOverflowed = 0;
+ KeyObjectVector keyvec;
+ KeyObject nodekey1;
+ KeyObject nodekey2;
+ r_Minterval domain;
+ bool wasroot = false;
+ bool found = false;
+ r_Dimension dim = ixDS->getDimension();
+ unsigned int numElem = 0;
+ unsigned int cur = 0;
+
+ while (!leafNodes2Split.empty())
+ {
+ leafNodeIxDS = (HierIndexDS*)leafNodes2Split[0];
+ leafNodes2Split.erase(leafNodes2Split.begin());
+
+ wasroot = leafNodeIxDS->isRoot();
+ if (wasroot)
+ domain = leafNodeIxDS->getCoveredDomain();
+ else {
+ tempPar = leafNodeIxDS->getParent();
+ KeyObject tkey;
+ numElem = tempPar->getSize();
+ for (cur = 0; cur < numElem; cur++)
+ {
+ tkey = tempPar->getObject(cur);
+ if (((OId::OIdPrimitive)tkey.getObject().getOId()) == leafNodeIxDS->getIdentifier())
+ {
+ domain = tkey.getDomain();
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ {
+ RMInit::logOut << "SRPTIndexLogic::splitNodes() the leaf node to split was not found in its parent" << endl;
+ throw r_Error(INDEXNOTFOUNDINPARENT);
+ }
+ tempPar->destroy();
+ tempPar = NULL;
+ }
+
+ calculatePartition(axis, value, leafNodeIxDS);
+ clear(keyvec, leafNodeIxDS);
+ n1 = (HierIndexDS*)leafNodeIxDS->getNewInstance();
+ if (wasroot)
+ {
+ parentIxDS = leafNodeIxDS;
+ n2 = (HierIndexDS*)leafNodeIxDS->getNewInstance();
+ leafNodeIxDS->setIsNode(true);
+ leafNodeIxDS = NULL;
+ }
+ else {
+ parentIxDS = leafNodeIxDS->getParent();
+ n2 = leafNodeIxDS;
+ leafNodeIxDS = NULL;
+ }
+ splitLeaf(n1, n2, keyvec, axis, value, domain, sl);
+ nodekey1 = convert(n1);
+ nodekey2 = convert(n2);
+ if (!wasroot)
+ parentIxDS->removeObject(nodekey2);
+ SDirIndexLogic::insertObject(parentIxDS, nodekey1, sl);
+ SDirIndexLogic::insertObject(parentIxDS, nodekey2, sl);
+ parentOverflowed = parentIxDS->isOverFull();
+
+ n1->destroy();
+ n1 = NULL;
+ n2->destroy();
+ n2 = NULL;
+
+ while (parentOverflowed) // split up
+ {
+ wasroot = parentIxDS->isRoot();
+ domain = parentIxDS->getAssignedDomain();
+ calculatePartition(axis, value, parentIxDS);
+ clear(keyvec, parentIxDS);
+ nln1 = (HierIndexDS*)parentIxDS->getNewInstance();
+
+ if (wasroot)
+ {
+ nln2 = (HierIndexDS*)parentIxDS->getNewInstance();
+ }
+ else {
+ nln2 = parentIxDS;
+ parentIxDS = parentIxDS->getParent();
+ }
+ splitNonLeaf(nln1, nln2, keyvec, leafNodes2Split, axis, value, domain, sl);
+ nodekey1 = convert(nln1);
+ nodekey2 = convert(nln2);
+ if (!wasroot)
+ parentIxDS->removeObject(nodekey2);
+ SDirIndexLogic::insertObject(parentIxDS, nodekey1, sl);
+ SDirIndexLogic::insertObject(parentIxDS, nodekey2, sl);
+ parentOverflowed = parentIxDS->isOverFull();
+
+ nln1->destroy();
+ nln1 = NULL;
+ nln2->destroy();
+ nln2 = NULL;
+ }
+ if (parentIxDS && (parentIxDS != ixDS))
+ {
+ parentIxDS->destroy();
+ parentIxDS = NULL;
+ }
+ }
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "splitNodes(" << OId(ixDS->getIdentifier()) << ", leafNodes2Split)")
+ }
+
+void
+SRPTIndexLogic::splitLeaf( HierIndexDS* pd1,
+ HierIndexDS* pd2,
+ KeyObjectVector& keyvec,
+ r_Dimension axis,
+ r_Range value,
+ r_Minterval& domain,
+ const StorageLayout& sl)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "splitLeaf(" << OId(pd1->getIdentifier()) << ", " << OId(pd2->getIdentifier()) << ", keyvec, " << axis << ", " << value << ", " << domain << ")")
+ unsigned int i = 0;
+ unsigned int leafSize = keyvec.size();
+
+ r_Minterval cd(domain);
+ r_Minterval nd1 = cd;
+ r_Minterval nd2 = cd;
+
+ KeyObject obj;
+
+ nd1[axis].set_high(value - 1);
+ nd2[axis].set_low(value);
+ RMDBGMIDDLE(6, RMDebug::module_indexmgr, "SRPTIndexLogic", "old leaf domain " << cd << " partition 1 " << nd1 << " partition 2 " << nd2);
+ //populate two nodes
+ for(i = 0; i < leafSize; i++)
+ {
+ cd = keyvec[i].getDomain();
+ RMDBGMIDDLE(5, RMDebug::module_indexmgr, "SRPTIndexLogic", "ObjectDomain of Object #" << i << " is " << cd);
+ obj = keyvec[i];
+ if (nd1.intersects_with(cd))
+ {
+ SDirIndexLogic::insertObject(pd1, obj, sl);
+ }
+ if (nd2.intersects_with(cd))
+ {
+ SDirIndexLogic::insertObject(pd2, obj, sl);
+ }
+//sanity check
+RMDBGIF(0, RMDebug::module_indexmgr, "SRPTIndexLogic", \
+ if (!nd1.intersects_with(cd) && !nd2.intersects_with(cd)) \
+ { \
+ RMInit::logOut << "SRPTIndexLogic::splitLeaf() the entry does not intersect with any node: node 1 " << nd1 << " node 2 " << nd2 << " entry " << cd << endl; \
+ throw r_Error(TILE_NOT_INSERTED_INTO_INDEX); \
+ } )
+ }
+ pd1->setAssignedDomain(nd1);
+ pd2->setAssignedDomain(nd2);
+
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "splitLeaf(" << OId(pd1->getIdentifier()) << ", " << OId(pd2->getIdentifier()) << ", keyvec, " << axis << ", " << value << ", " << domain << ")")
+ }
+
+void
+SRPTIndexLogic::splitNonLeaf( HierIndexDS* pd1,
+ HierIndexDS* pd2,
+ KeyObjectVector& keyvec,
+ IndexPVector& leafNodes2Split,
+ r_Dimension axis,
+ r_Range value,
+ const r_Minterval& domain,
+ const StorageLayout& sl)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "splitNonLeaf(" << OId(pd1->getIdentifier()) << ", " << OId(pd2->getIdentifier()) << ", keyvec, leafNodes2Split, " << axis << ", " << value << ", " << domain << ")");
+ r_Dimension dim = domain.dimension();
+ r_Minterval cd(domain);
+ r_Minterval nd1(cd);
+ r_Minterval nd2(cd);
+ r_Minterval leafDomain(dim);
+ r_Minterval nodeDomain(dim);
+ KeyObjectVector listMinKO1;
+ KeyObjectVector listMinKO2;
+ KeyObjectVector keyvec2;
+ IndexPVector newLeafsToSplit;
+ HierIndexDS* entry = NULL;
+ HierIndexDS* n11 = NULL;
+ HierIndexDS* parentIxDS = NULL;
+ KeyObject tempKey;
+ KeyObject k11;
+ KeyObject k22;
+ unsigned int i = 0;
+ unsigned int a = 0;
+ unsigned int nodeSize = keyvec.size();
+ unsigned int leafSize = 0;
+
+ nd1[axis].set_high(value - 1);
+ nd2[axis].set_low(value);
+
+ //repopulate node and pd1
+ for(i = 0; i < nodeSize; i++)
+ {
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "repopulating node (entry " << i << " of " << nodeSize << ")");
+ tempKey = keyvec[i];
+ entry = convert(tempKey);
+ // entry's domain
+ cd = keyvec[i].getDomain();
+ if (nd1.covers(cd))
+ {
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "entry #" << i << " " << cd << " covers node 1 " << nd1);
+ // updates parent automatically
+ SDirIndexLogic::insertObject(pd1, tempKey, sl);
+ entry->destroy();
+ entry = 0;
+ }
+ else {
+ if (nd2.covers(cd))
+ {
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "entry #" << i << " " << cd << " covers node 2 " << nd2);
+ // updates parent automatically
+ SDirIndexLogic::insertObject(pd2, tempKey, sl);
+ entry->destroy();
+ entry = NULL;
+ }
+ else {// intersects both -> split down
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "entry #" << i << " " << cd << " intersects both " << nd1 << " " << nd2);
+ n11 = NULL;
+ //k11 is not a pointer! it is an object
+ // k11 = 0;
+ if (entry->isLeaf())
+ {
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "entry is leaf ")
+ n11 = (HierIndexDS*)entry->getNewInstance();
+ n11->setIsNode(false);
+ leafDomain = cd;
+ clear(keyvec2, entry);
+ splitLeaf(n11, entry, keyvec2, axis, value, leafDomain, sl);
+ //if this was one of the leaf nodes to split, remove it from the list
+ leafSize = leafNodes2Split.size();
+ newLeafsToSplit = vector< IndexDS* >();
+ for (a = 0; a < leafSize; a++)
+ {
+ if (leafNodes2Split[a]->isSameAs(entry))
+ {
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "will not add entry " << a << " to leafNodes2Split.size " << leafSize)
+ }
+ else {
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "will add entry " << a << " to leafNodes2Split.size " << leafSize)
+ newLeafsToSplit.push_back(leafNodes2Split[a]);
+ }
+ }
+ leafNodes2Split = newLeafsToSplit;
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "new LeafsToSplit size:" << leafNodes2Split.size())
+ }
+ else {// nonleaf node to be split
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "entry is nonleaf ")
+ n11 = (HierIndexDS*)entry->getNewInstance();
+ n11->setIsNode(true);
+ nodeDomain = cd;
+ parentIxDS = entry->getParent();
+ clear(keyvec2, entry);
+ splitNonLeaf(n11, entry, keyvec2, leafNodes2Split, axis, value, nodeDomain, sl);
+ k22 = convert(entry);
+ parentIxDS->removeObject(k22);
+ parentIxDS->destroy();
+ parentIxDS = NULL;
+ }
+ //n11 and entry are allocated
+ //n11 and entry are not inserted in a parent!
+ k11 = convert(n11);
+ if (n11->isUnderFull() || n11->isLeaf())
+ {//leaf or node with more than minfill entries
+ SDirIndexLogic::insertObject(pd1, k11, sl);
+ if (n11->isLeaf() && n11->isOverFull())
+ {//very improbable that this happens
+ //leaf with more than maxfill entries
+ leafNodes2Split.push_back(n11);
+ }
+ else {//node or leaf with ok entries
+ n11->destroy();
+ n11 = NULL;
+ }
+ }
+ else {//node with less than minfill entries
+ listMinKO1.push_back(k11);
+ //k11 is deleted in redistribute
+ n11->destroy();
+ n11 = NULL;
+ }
+ k22 = convert(entry);
+ if (entry->isUnderFull() || entry->isLeaf())
+ {
+ SDirIndexLogic::insertObject(pd2, k22, sl);
+ if (entry->isLeaf() && entry->isOverFull())
+ {// very improbable that this happens
+ leafNodes2Split.push_back(entry);
+ }
+ else {
+ entry->destroy();
+ entry = 0;
+ }
+ }
+ else {
+ listMinKO2.push_back(k22);
+ entry->destroy();
+ entry = 0;
+ //k22 is deleted in redistribute
+ //where is entry deleted
+ }
+ }
+ }
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "ended repopulating node (entry " << i << " of " << nodeSize << ")");
+ }
+ redistributeEntries(pd1, listMinKO1, sl);
+ redistributeEntries(pd2, listMinKO2, sl);
+ pd1->setAssignedDomain(nd1);
+ pd2->setAssignedDomain(nd2);
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "splitNonLeaf(" << OId(pd1->getIdentifier()) << ", " << OId(pd2->getIdentifier()) << ", keyvec, leafNodes2Split, " << axis << ", " << value << ", " << domain << ")");
+ }
+
+void
+SRPTIndexLogic::redistributeEntries(IndexDS* node, KeyObjectVector& listMinKO, const StorageLayout& sl)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "redistributeEntries(" << OId(node->getIdentifier()) << ", redistList.size " << listMinKO.size() << ")")
+ // not implemented. It could redistribute objects in case of too low fill factor
+ unsigned int size = listMinKO.size();
+ for(int i = 0; i < size; i++)
+ {
+ SDirIndexLogic::insertObject(node, listMinKO[i], sl);
+ }
+
+ listMinKO.clear();
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "redistributeEntries(" << OId(node->getIdentifier()) << ", redistList.size " << listMinKO.size() << ")")
+ }
+
+bool
+SRPTIndexLogic::removeObject(IndexDS* ixDS, const KeyObject& objToRemove, const StorageLayout& sl)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "removeObject(" << OId(ixDS->getIdentifier()) << ", " << objToRemove << ")")
+ bool found = false;
+ if (ixDS->getAssignedDomain().intersects_with(objToRemove.getDomain()))
+ {
+ if (((HierIndexDS*)ixDS)->isLeaf())
+ if (ixDS->removeObject(objToRemove))
+ {
+ found = true;
+ }
+ else {
+ RMDBGMIDDLE(0, RMDebug::module_indexmgr, "SRPTIndexLogic", "removeObject(" << ixDS->getAssignedDomain() << ", " << objToRemove.getDomain() << ") object was not found")
+ }
+ else {
+ KeyObjectVector candidates;
+ SDirIndexLogic::intersectUnOpt(ixDS, objToRemove.getDomain(), candidates);
+ for (KeyObjectVector::iterator it = candidates.begin(); it != candidates.end(); it++)
+ {
+ if (SRPTIndexLogic::removeObject((HierIndexDS*)DBHierIndexId((*it).getObject()), objToRemove, sl))
+ found = true;
+ else {
+ RMDBGMIDDLE(0, RMDebug::module_indexmgr, "SRPTIndexLogic", "removeObject(" << ixDS->getAssignedDomain() << ", " << objToRemove.getDomain() << ") did not remove an entry in a node")
+ }
+ }
+ }
+ }
+ else {
+ RMDBGMIDDLE(0, RMDebug::module_indexmgr, "SRPTIndexLogic", "removeObject(" << ixDS->getAssignedDomain() << ", " << objToRemove.getDomain() << ") did not intersect")
+ }
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "removeObject(" << OId(ixDS->getIdentifier()) << ", const KeyObject*)")
+ return found;
+ }
+
+void
+SRPTIndexLogic::calculatePartition(r_Dimension& axis, r_Range& value, const HierIndexDS* node)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "calculatePartition(" << axis << ", " << value << ", " << OId(node->getIdentifier()) << ")");
+ float bestDist1 = 1;
+ float bestDist2 = 1;
+ double bestDistBal = 1;
+ r_Dimension dim = node->getDimension();
+ r_Dimension first = 0;//rand()%dim;
+ r_Dimension a = first;
+ unsigned int elemCount = node->getSize();
+ r_Range v = -1;
+ float dist1 = 0;
+ float dist2 = 0;
+ double distBal = 0;
+
+ while (true)
+ {
+ for (int i = 0; i < elemCount; i++)
+ {
+ v = node->getObjectDomain(i)[a].low();
+ calculateDistribution(a, v, dist1, dist2, node);
+
+ // balanced property of this split distribution: how close it
+ // is to 50%, 50% distribution. Worst case: 1.
+ distBal = fabs(dist1 - 0.5) + fabs(dist2 - 0.5);
+
+ if (distBal < bestDistBal)// less overlapping in number of entries;add other conditions !!!
+ {
+ bestDist1 = dist1;
+ bestDist2 = dist2;
+ bestDistBal = fabs(bestDist1 - 0.5) + fabs(bestDist2 - 0.5);
+ axis = a;
+ value = v;
+ }
+ }
+ a = (a+1) % dim;
+ if (a == first)
+ break;
+ }
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "calculatePartition(" << axis << ", " << value <<", " << OId(node->getIdentifier()) << ")")
+ }
+
+
+void
+SRPTIndexLogic::calculateDistribution( r_Dimension axis,
+ r_Range value,
+ float& dist1,
+ float& dist2,
+ const HierIndexDS* node)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "calculateDistribution(" << axis <<", " << value << ", Dist1, Dist2, " << OId(node->getIdentifier()) << ")")
+ dist1 = 0;
+ dist2 = 0;
+ unsigned int n = node->getSize();
+ r_Minterval dom;
+ for (unsigned int i = 0; i < n ; i++)
+ {
+ dom = node->getObjectDomain(i);
+ if (dom[axis].high() < value)
+ {// entry will fall in first part only
+ dist1 +=1;
+ RMDBGMIDDLE(7, RMDebug::module_indexmgr, "SRPTIndexLogic", "Entry goes into the first");
+ }
+ else {// entry will fall in first part only
+ if (dom[axis].low() >= value)
+ {
+ dist2 +=1;
+ RMDBGMIDDLE(7, RMDebug::module_indexmgr, "SRPTIndexLogic", "Entry goes into the second");
+ }
+ else {// entry will fall in both parts
+ dist1 +=1;
+ dist2 +=1;
+ RMDBGMIDDLE(7, RMDebug::module_indexmgr, "SRPTIndexLogic", "Entry goes into the first and second");
+ }
+ }
+ }
+ dist1 = dist1/n;
+ dist2 = dist2/n;
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "calculateDistribution(" << axis <<", " << value << ", " << dist1 << ", " << dist2 << ", " << OId(node->getIdentifier()) << ")")
+ }
+
+
+void
+SRPTIndexLogic::intersect( const r_Minterval& searchInter,
+ const r_Minterval& parentEntryDomain,
+ KeyObjectVector& intersectedObjs,
+ const HierIndexDS* ix,
+ r_Area& area)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "intersect(SearchDom:" << searchInter << ", ParentDom:" << parentEntryDomain << ", intersectedObjects.size " << intersectedObjs.size() << ", " << OId(ix->getIdentifier()) << ", Area " << area << ") ")
+
+ r_Minterval intersectArea;
+ r_Minterval dom = ix->getCoveredDomain();
+ KeyObjectVector intersectedNodes;
+ HierIndexDS* tempIx = NULL;
+ r_Area nodeArea = 0;
+ r_Area oldArea = area;
+ unsigned int i = 0;
+ unsigned int nodeSize = ix->getSize();
+
+ if (ix->isLeaf())
+ {
+ //are there cells which belong into the result?
+ if (searchInter.intersects_with(dom))
+ {
+ intersectArea = searchInter.create_intersection(dom);
+ //may this leaf put cells into the result?
+ if (intersectArea.intersects_with(parentEntryDomain))
+ {
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "searchDom " << searchInter << " indexDom " << dom << " intersection " << intersectArea << " area " << area);
+ binaryRegionSearch(ix, searchInter, area, intersectedObjs, 0, nodeSize - 1, dom);//parentEntryDomain);
+ }
+ }
+ }
+ else {// node is not a Leaf
+ if (searchInter.intersects_with(dom))
+ {
+ nodeArea = area;
+ binaryRegionSearch(ix, searchInter, nodeArea, intersectedNodes, 0, nodeSize - 1, dom);
+ for (i = 0; i < intersectedNodes.size(); i++)
+ {
+ if (area == 0)
+ {
+ RMDBGMIDDLE(0, RMDebug::module_indexmgr, "SRPTIndexLogic", "intersect AREA IS ALREADY FOUND")
+ }
+ if (nodeArea > oldArea)
+ {
+ RMInit::logOut << "SRPTIndexLogic::intersect() the index found more cells than allowed" << endl;
+ throw r_Error(INDEXEXHAUSTEDAREA);
+ }
+ r_Minterval objDom(intersectedNodes[i].getDomain());
+ tempIx = convert(intersectedNodes[i]);
+ intersect(searchInter, objDom, intersectedObjs, tempIx, area);
+ tempIx->destroy();
+ }
+ }
+ }
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "intersect(SearchDom:" << searchInter << ", ParentDom:" << parentEntryDomain << ", intersectedObjects.size " << intersectedObjs.size() << ", " << OId(ix->getIdentifier()) << ", Area " << area << ")")
+ }
+
+bool
+SRPTIndexLogic::intersectNoDuplicates( const r_Minterval& searchInter,
+ const r_Minterval& entryDomain,
+ const r_Minterval& parentEntryDomain)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "intersectNoDuplicates(SearchDom:" << searchInter << ", EntryDom:" << entryDomain << ", ParentDom:" << parentEntryDomain << ")");
+
+ bool retval = true;
+ int testcase = 0;
+ r_Dimension i = 0;
+ r_Dimension dim = entryDomain.dimension();
+
+ // This condition allows an early detection of duplicates in the
+ // index structure for intersection operations.
+ // An entry of a leaf node is only added to the list of entries
+ // intersected by that node having it internally with respect to the
+ // parent (since no other node may have it then) or if it crosses
+ // the upper bounds of the parent node (it will be also crossed by
+ // another parent at the upper bounds and it is added to the list then).
+
+ // don't add the entry if it doesn't intersect the search area
+ // or if it intersects a lower bound of the parent's
+ // domain and that lower bound of the parent is higher than
+ // that of the search region
+ r_Range searchLo = 0;
+ r_Range entryLo = 0;
+
+
+ for (i = 0 ; i < dim; i++)
+ {
+ searchLo = searchInter[i].low();
+ entryLo = entryDomain[i].low();
+ // entry doesn't intersect search region
+ if (entryLo > searchInter[i].high())
+ {
+ retval = false;
+ break;
+ }
+ // entry doesn't intersect search region
+ if (entryDomain[i].high() < searchLo)
+ {
+ retval = false;
+ break;
+ }
+ // entry is also in another node where it intersects the higher bounds,
+ // it should be included then, not here
+ if (entryLo < parentEntryDomain[i].low() && searchLo < parentEntryDomain[i].low())
+ {
+ retval = false;
+ break;
+ }
+ }
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "intersectNoDuplicates(SearchDom:" << searchInter << ", EntryDom:" << entryDomain << ", ParentDom:" << parentEntryDomain << ")" << retval << " testcase " << testcase << " at dim " << i);
+ return retval;
+ }
+
+int
+SRPTIndexLogic::regionSearch( const HierIndexDS* ixNode,
+ const r_Minterval& mint,
+ r_Area& area,
+ KeyObjectVector& intersectedObjects,
+ const r_Minterval& parentEntryDomain)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "regionSearch(" << OId(ixNode->getIdentifier()) << ", SearchDom " << mint << ", Area " << area << ", intersectedObjects.size " << intersectedObjects.size() << ", ParentDom " << parentEntryDomain << ")");
+
+ r_Minterval intersectedRegion;
+ unsigned int endAt = ixNode->getSize();
+ int retval = endAt;
+ KeyObject newObj;
+ r_Minterval objDomain;
+ unsigned int i = 0;
+ r_Area oldArea = area;
+
+/*there must be something like or the map version
+ DomainMap t;
+ DomainMap::iterator it;
+ for (i = 0; i < intersectedObjects->size(); i++)
+ {
+ DomainPair p((*intersectedObjects)[i]->getObject().getOId(), (*intersectedObjects)[i]->getDomain());
+ t.insert(p);
+ }
+*/
+
+ for (i = 0; i < endAt ; i++)
+ {
+ objDomain = ixNode->getObjectDomain(i);
+ // object intersects region
+ // problem with calculation of complete area when the entry is not added.
+
+/*there must be something like or the map version
+ if (objDomain.intersects_with(mint))
+ {
+ objDomain.intersection_with(mint);
+ area = area - objDomain.cell_count();
+ if (area <= 0)
+ {
+ retval = i;
+ break;
+ }
+ //insert intersectNoDuplicates here
+ }
+*/
+
+ if (intersectNoDuplicates(mint, objDomain, parentEntryDomain))
+ {
+
+/*there must be something like or the map version
+ if ((it = t.find(ixNode->getObject(i)->getObject().getOId())) == t.end())
+ {
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "adding " << ixNode->getObject(i)->getObject().getOId() << " intersected region " << intersectedRegion << " area " << area);
+ }
+ else {
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "not adding " << ixNode->getObject(i)->getObject().getOId() << " area " << area);
+ RMInit::logOut << "should never happen" << endl;
+ RMInit::logOut << "want to add " << ixNode->getObject(i)->getObject().getOId() << " at " << objDomain << endl;
+ for (it = t.begin(); it != t.end(); it++)
+ RMInit::logOut << OId((*it).first) << " at " << (*it).second << endl;
+ throw r_Error(TESTERROR);
+ }
+*/
+
+ objDomain.intersection_with(mint);
+ area = area - objDomain.cell_count();
+ newObj = ixNode->getObject(i);
+ intersectedObjects.push_back(newObj);
+ if (oldArea < area)
+ {
+ retval = i;
+ RMInit::logOut << "SRPTIndexLogic::regionSearch() the area was completely exhausted" << endl;
+ throw r_Error(INDEXEXHAUSTEDAREA);
+ break;
+ }
+ if (area == 0)
+ {
+ retval = i;
+ break;
+ }
+ }
+ else {
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "not adding " << ixNode->getObject(i).getObject().getOId() << " dom " << objDomain << " does not intersect")
+ }
+ }
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "regionSearch(" << OId(ixNode->getIdentifier()) << ", SearchDom " << mint << ", Area " << area << ", intersectedObjects.size " << intersectedObjects.size() << ", ParentDom " << parentEntryDomain << ")" << retval);
+ return retval;
+ }
+
+
+int
+SRPTIndexLogic::binaryRegionSearch( const HierIndexDS* ixNode,
+ const r_Minterval& mint,
+ r_Area& area,
+ KeyObjectVector& intersectedObjects,
+ int first,
+ int last,
+ const r_Minterval& parentEntryDomain)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "binaryRegionSearch(" << OId(ixNode->getIdentifier()) << ", SearchDom " << mint << ", Area " << area << ", intersectedObjs.size " << intersectedObjects.size() << ", From " << first << ", To " << last << ", ParentDom " << parentEntryDomain << ")");
+ // code copied from DirIx::binaryRegionSearch (11.11.98)
+ // and further adapted
+ // assumes order according to the lowest corner of the objects
+
+ int retval = 0;
+ int middle = 0;
+ int inc = 0;
+ int ix = 0;
+ int compResult = 0;
+ r_Minterval t;
+ r_Minterval objDomain;
+ r_Minterval intersectedRegion;
+ KeyObject newObj;
+ r_Area oldArea = area;
+
+ if (area == 0)
+ retval = -1;
+ else
+ if (first > last)
+ retval = -1;
+ else {
+ middle = (last + first)/2;
+
+ t = ixNode->getObjectDomain(middle);
+ if(mint.get_high().compare_with(t.get_origin()) < 0)
+ { // R.hi < tile.lo no tiles after this one
+ retval = binaryRegionSearch(ixNode, mint, area, intersectedObjects, first, middle - 1, parentEntryDomain);
+ }
+ else {
+ if(t.get_high().compare_with(mint.get_origin()) < 0)
+ {
+ retval = binaryRegionSearch(ixNode, mint, area, intersectedObjects, middle + 1, last, parentEntryDomain);
+ if (area > 0)
+ {
+ retval = binaryRegionSearch(ixNode, mint, area, intersectedObjects, first, middle - 1, parentEntryDomain);
+ }
+ }
+ else {
+ inc = 1;
+ for (ix = middle; ; ix += inc)
+ {
+ objDomain = ixNode->getObjectDomain(ix);
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "cycle " << ix << " " << objDomain);
+ compResult = mint.get_high().compare_with(objDomain.get_origin());
+ // object intersects region
+ if (intersectNoDuplicates(mint, objDomain, parentEntryDomain))
+ {
+ intersectedRegion = objDomain;
+ intersectedRegion.intersection_with(mint).intersection_with(parentEntryDomain);
+ oldArea = area;
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "interesected region " << intersectedRegion << " intersection area " << intersectedRegion.cell_count() << " area before " << area)
+ area = area - intersectedRegion.cell_count();
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "area after " << area)
+ if (area > oldArea)
+ {
+ RMInit::logOut << "SRPTIndexLogic::binaryRegionSearch() index found more cells than allowed" << endl;
+ throw r_Error(INDEXEXHAUSTEDAREA);
+ }
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "intersectedRegion " << intersectedRegion << " area " << area)
+ newObj = ixNode->getObject(ix);
+ intersectedObjects.push_back(newObj);
+ if (area == 0)
+ {
+ retval = ix;
+ break;
+ }
+ }
+ if (inc != -1 && (ix == last || compResult < 0))
+ {
+ ix = middle;
+ inc = -1;
+ }
+ if (ix == first && inc == -1)
+ {
+ retval = ix;
+ break;
+ }
+ }
+ }
+ }
+ }
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "binaryRegionSearch(" << OId(ixNode->getIdentifier()) << ", SearchDom " << mint << ", Area " << area << ", intersectedObjs.size " << intersectedObjects.size() << ", From " << first << ", To " << last << ", ParentDom " << parentEntryDomain << ")" << retval);
+ return retval;
+ }
+
+void
+SRPTIndexLogic::containPointQuery( const r_Point& searchPoint,
+ const HierIndexDS* ix,
+ KeyObject& result,
+ const StorageLayout& sl)
+ {
+ RMDBGENTER(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "containPointQuery(" << searchPoint << ", Node " << ix << ", result)");
+ HierIndexDS* intersectedNode = NULL;
+ if (!ix)
+ {
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "containPointQuery(" << searchPoint << ", Node, result) node is NULL");
+ }
+ else {
+ if (ix->isLeaf())
+ {
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "index " << OId(ix->getIdentifier()) << " is leaf");
+ SDirIndexLogic::containPointQuery(ix, searchPoint, result, sl);
+ }
+ else {
+ RMDBGMIDDLE(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "index " << OId(ix->getIdentifier()) << " is node");
+ KeyObject lowerNode;
+ SDirIndexLogic::containPointQuery(ix, searchPoint, lowerNode, sl);
+ containPointQuery(searchPoint, convert(lowerNode), result, sl);
+ }
+ if (result.isInitialised())
+ {
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "containPointQuery(" << searchPoint << ", " << OId(ix->getIdentifier()) << ")" << result);
+ }
+ else {
+ RMDBGEXIT(4, RMDebug::module_indexmgr, "SRPTIndexLogic", "containPointQuery(" << searchPoint << ", " << OId(ix->getIdentifier()) << ") nothing found");
+ }
+ }
+ }
+
+HierIndexDS*
+SRPTIndexLogic::convert(const KeyObject& toConvert)
+ {
+ HierIndexDS* retval = NULL;
+ if (toConvert.isInitialised())
+ retval = (HierIndexDS*)DBHierIndexId(toConvert.getObject());
+ return retval;
+ }
+
+KeyObject
+SRPTIndexLogic::convert(HierIndexDS* toConvert)
+ {
+ if (toConvert)
+ return KeyObject(DBObjectId(toConvert->getIdentifier()), toConvert->getAssignedDomain());
+ KeyObject retval;
+ return retval;
+ }
+
diff --git a/indexmgr/srptindexlogic.hh b/indexmgr/srptindexlogic.hh
new file mode 100644
index 0000000..7ad0dc5
--- /dev/null
+++ b/indexmgr/srptindexlogic.hh
@@ -0,0 +1,244 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#ifndef _SRPTINDEXLOGIC_HH_
+#define _SRPTINDEXLOGIC_HH_
+
+#include "indexmgr/hierindexds.hh"
+#include "reladminif/lists.h"
+class r_Point;
+class StorageLayout;
+
+
+//@ManMemo: Module: {\bf indexmgr}
+/*@Doc:
+This class contains the logic for access, insertion and removal of objects
+into an index data structure. The logic is based on the R-Plus Tree. Objects
+inserted in this index don`t have to be regular. The leaf object`s domain
+must not overlap.
+
+The leaf objects are sorted into nodes which are split when needed. Nodes
+are split when the number of objects in them is equal to the maximum size
+specified by the underlying index data structure. This check should be done
+using the IndexDS::isOverFull() method.
+
+This class uses functionality supplied by SDirIndexLogic.
+
+This class was converted to pure static methods because it is fast to use stack.
+*/
+
+class SRPTIndexLogic
+ {
+ public:
+ static bool insertObject2(IndexDS* ixDS, const KeyObject& newObject, const StorageLayout& sl);
+ /*@Doc:
+ Inserts a new object in the index.
+ Must have a name different from the other insertObject because of the stupid compiler.
+ */
+
+ static bool removeObject(IndexDS* ixDS, const KeyObject& tileToRemove, const StorageLayout& sl);
+ /*@Doc:
+ Removes the object from the indexx.
+ */
+
+ static void intersect2(const IndexDS* ixDS, const r_Minterval& searchInter, KeyObjectVector& objs, const StorageLayout& sl);
+ /*@Doc:
+ Search the index for a search region.
+ Determines all the tiles in the index which intersect a given
+ search interval (given by {\tt searchInter}).
+ Must have a name different from other intersect because of compiler.
+ */
+
+ static void containPointQuery2(const IndexDS* ixDS, const r_Point& searchPoint, KeyObject& result, const StorageLayout& sl);
+ /*@Doc:
+ Passes a pointer to the searched item.
+ Must have different name from other containPointQuery because of compiler.
+ */
+
+ static void getObjects(const IndexDS* ixDS, KeyObjectVector& objs, const StorageLayout& sl);
+ /*@Doc:
+ Returns all the tiles belonging to the object.
+ */
+
+ static int insertObject( const KeyObject& newObject,
+ HierIndexDS* ix,
+ IndexPVector& leafNodes2Split,
+ const StorageLayout& sl);
+ /*@Doc:
+ Inserts a new object in the index.
+ Recursive function which does the real job.
+ The return value is 1 if the current node was split, 0 otherwise. This is
+ used internally by the algorithm (?really - better not touch it?).
+ In {\tt leafNodes2Split}, the set of overflowed leaf nodes is returned.
+ It should be passed to {\tt splitNodes()}.
+ */
+
+
+ static void extendFaces(HierIndexDS* ix,
+ const r_Minterval& newKeyObjectDom,
+ const r_Minterval& oldCurrDom,
+ const bool* facesToExtendLo,
+ const bool* facesToExtendHi);
+ /*@Doc:
+ This method extends the domains of all index nodes which
+ intersect with the object that will be inserted.
+ This is neccessary because subsequently all nodes which
+ intersect with the object to be inserted are retrieved by
+ DirIndexLogic.
+ */
+
+ static void splitNodes( HierIndexDS* ixDS,
+ IndexPVector& leafNodes2Split,
+ const StorageLayout& sl);
+ /*@Doc:
+ Splits all nodes after insert
+ Full nodes are split all at once, to avoid repetition of splits.
+ Uses splitLeaf and splitNonLeaf to carry out the task.
+ */
+
+ static void splitLeaf( HierIndexDS* n1,
+ HierIndexDS* n2,
+ KeyObjectVector& keyvec,
+ r_Dimension axis,
+ r_Range value,
+ r_Minterval& domain,
+ const StorageLayout& sl);
+ /*@Doc:
+ Splits a leaf node
+ {\tt n1} has the entries which intersect (leafNodeDomain and x(axis) <= value),
+ {\tt n2 } the ones intersecting (leafNodeDomain and x(axis) > value).
+ The keyvec holds the tiles which will be inserted into the 2 new leafs.
+ The domain is the complete assigned domain of both leafs. It will be divided into 2 parts
+ based on axis and value. Then the tiles are assigned to the leaf that covers them - or both.
+ */
+
+ static void splitNonLeaf( HierIndexDS* n1,
+ HierIndexDS* n2,
+ KeyObjectVector& keyvec,
+ IndexPVector& leafNodes2Split,
+ r_Dimension axis,
+ r_Range value,
+ const r_Minterval& domain,
+ const StorageLayout& sl);
+ /*@Doc:
+ Splits a nonleaf node
+ Does semantically the same as splitLeaf. Syntactically it is quite different because it has to check
+ for over full nodes and treat them.
+ */
+
+ static void redistributeEntries(IndexDS* node,
+ KeyObjectVector& listMinKO,
+ const StorageLayout& sl);
+ /*@Doc:
+ stores the Keyobjects in the node. could do some more
+ fancy stuff in the future (like checking for under full and then redistribute those nodes).
+ */
+
+ static void calculatePartition( r_Dimension& axis,
+ r_Range& value,
+ const HierIndexDS* node);
+ /*@Doc:
+ Calculates the optimal partition for this node Partition is returned in {\tt axis}, {\tt value}.
+ This is the most problematic stuff because it depends on the order of insertion.
+ The index nodes are not optimally filled. But you know: we are the fastest anyway ; )
+ */
+
+ static void calculateDistribution( r_Dimension axis,
+ r_Range value,
+ float& dist1,
+ float& dist2,
+ const HierIndexDS* node);
+ /*@Doc:
+ Caluculates the distribution of entries for a given partition
+ Used by calculate partition.
+ Calculates resulting distribution of children of a node {\ttnode} if
+ it is split at axis = value. Distributions are returned in {\ttdist1}
+ (percentage of nodes intersecting x(axis) <= value) and {\ttdist2}
+ (percentage of nodes intersecting x(axis) > value).
+ */
+
+ static void intersect( const r_Minterval& searchInter,
+ const r_Minterval& parentDomain,
+ KeyObjectVector& intersectedObjs,
+ const HierIndexDS* ix,
+ r_Area& area);
+ /*@Doc:
+ This method helps you get the data out of the index again : )
+ searchInter will tell you for what to look.
+ parentDomain is used to determin if you should include a matching object or not.
+ you might not want to include a matching object because of duplicate entries in the index.
+ this choice is made by intersectNoDuplicates.
+ intersectedObjs holds the found entries.
+ the area is used to determine if we got everything.
+ */
+
+ static bool intersectNoDuplicates( const r_Minterval& searchInter,
+ const r_Minterval& entryDomain,
+ const r_Minterval& parentDomain);
+ /*@Doc:
+ Decides if the entry at hand should be included from this index or if it is in another
+ one and will be included from there.
+ */
+
+
+ static int binaryRegionSearch( const HierIndexDS* ixNode,
+ const r_Minterval& mint,
+ r_Area& area,
+ KeyObjectVector& intersectedObjects,
+ int first,
+ int last,
+ const r_Minterval& parentEntryDom);
+ /*@Doc:
+ This will use a binary search algorithm to quickly find the nodes we want.
+ */
+
+ static int regionSearch(const HierIndexDS* ixNode,
+ const r_Minterval& mint,
+ r_Area& area,
+ KeyObjectVector& intersectedObjects,
+ const r_Minterval& parentDomain);
+ /*@Doc:
+ This is a not binary search algorithm for doing the same as binaryRegionSearch.
+ */
+
+ static void containPointQuery(const r_Point& searchPoint, const HierIndexDS* ix, KeyObject& result, const StorageLayout& sl);
+ /*@Doc:
+ */
+
+ static HierIndexDS* convert(const KeyObject& toConvert);
+ /*@Doc:
+ Helper method for converting a keyobject to a hierindex object.
+ the parameter must be deleted by the caller.
+ the returned object must be deleted by the caller.
+ */
+
+ static KeyObject convert(HierIndexDS* toConvert);
+ /*@Doc:
+ Helper method for converting a hierindex to a keyobject.
+ the parameter must be deleted by the caller.
+ the returned object must be deleted by the caller.
+ */
+
+ };
+
+#endif
diff --git a/indexmgr/test/Makefile b/indexmgr/test/Makefile
new file mode 100644
index 0000000..5ae92c2
--- /dev/null
+++ b/indexmgr/test/Makefile
@@ -0,0 +1,103 @@
+# -*-Makefile-*-
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>. # Top Level makefile. This points to the various modules that have to be build
+# and/or deployed
+#
+# MAKEFILE FOR:
+# test programs of module indexmgr
+#
+# COMMENTS:
+# List environment dependencies, known bugs, specialities etc.
+#
+##################################################################
+#
+# This is just an example Makefile for a test program.
+# The dependency of the test program on the lib of the
+# corresponding module is in the Makefile of the module.
+#
+
+######################### Definitions ############################
+
+# standard include with general options
+include $(RMANBASE)/Makefile.inc
+
+# all test programs
+SRCCXX= test_clusterix.cc test_expix.cc test_ix.cc \
+ test_abc.cc test_dirix.cc test_hierix.cc test_ix1.cc
+OBJS = ${SRCCXX:%.cc=%.o}
+ALLTESTS = ${SRCCXX:%.cc=%}
+MISCCLEAN = core
+
+# some additional flags for compiling and linking
+CXXFLAGS := $(STLCXXFLAGS) $(CXXFLAGS)
+
+# includes in module directory
+LDFLAGS += -I$(RMANBASE)/indexif
+LDFLAGS := $(STLLDFLAGS) $(LDFLAGS) -L$(SUPPORT_BASE)/lib -lz
+
+
+########################### Targets ##############################
+
+# make all tests
+.PHONY: test
+test: $(ALLTESTS)
+
+# test target for class Index (always make module!)
+.PHONY: test_index_target
+test_index_target: build_module test_dirix test_clusterix test_expix
+
+######################## Dependencies ############################
+
+# make module
+.PHONY: build_module
+build_module:
+ cd $(RMANBASE)/indexmgr; $(MAKE)
+
+# can not be used as a target (module library is not remade!)
+
+test_abc: test_abc.o
+ $(PURIFY) $(CXX) -o $@ $^ -lm
+
+test_dirix: test_dirix.o $(INDEXMGR) $(INDEXIF) $(RASLIB) $(CACHETAMGR) $(CATALOGIF) $(BLOBIF) $(ADMINIF) $(MDDIF)
+ $(PURIFY) $(CXX) $(BASEDBLDFLAGS) $(LDFLAGS) -o $@ $^ -lm $(QLPARSER)
+
+test_ix1: test_ix1.o $(INDEXMGR) $(INDEXIF) $(RASLIB) $(CACHETAMGR) $(CATALOGIF) \
+ $(BLOBIF) $(ADMINIF) $(MDDIF) $(TOOLS) $(QLPARSER)
+ $(PURIFY) $(CXX) $(BASEDBLDFLAGS) $(LDFLAGS) -o $@ $^ -lm $(QLPARSER)
+
+test_ix: test_ix.o $(RASLIB)
+ $(PURIFY) $(CXX) $(BASEDBLDFLAGS) $(LDFLAGS) -o $@ $^ -lm
+
+test_hierix: test_hierix.o $(INDEXMGR) $(INDEXIF) $(RASLIB) $(CACHETAMGR) $(CATALOGIF) $(BLOBIF) $(ADMINIF) $(MDDIF)
+ $(PURIFY) $(CXX) $(BASEDBLDFLAGS) $(LDFLAGS) -o $@ $^ -lm $(QLPARSER)
+
+test_expix: test_expix.o $(INDEXMGR) $(INDEXIF) $(RASLIB) $(CACHETAMGR) $(CATALOGIF) $(BLOBIF) $(ADMINIF) $(MDDIF) $(TOOLS) $(QLPARSER)
+ $(PURIFY) $(CXX) $(BASEDBLDFLAGS) $(LDFLAGS) -o $@ $^ -lm $(INDEXMGR)
+
+test_clusterix: test_clusterix.o $(INDEXMGR) $(INDEXIF) $(RASLIB) $(CACHETAMGR) $(CATALOGIF) $(BLOBIF) $(ADMINIF) $(MDDIF)
+ $(PURIFY) $(CXX) $(BASEDBLDFLAGS) $(LDFLAGS) -o $@ $^ -lm $(INDEXIF) $(INDEXMGR)
+
+# general rules
+include $(RMANBASE)/Makefile.rel
+
+# automatically created dependencies
+include Makefile.dep
diff --git a/indexmgr/test/test_abc.cc b/indexmgr/test/test_abc.cc
new file mode 100644
index 0000000..7c8160b
--- /dev/null
+++ b/indexmgr/test/test_abc.cc
@@ -0,0 +1,373 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: testabc.cc
+ *
+ * MODULE: test for A,B,C
+ *
+ * PURPOSE:
+ * Tests a hierarchy of classes where each one, after insertElement( )
+ * transforms itself into the superclass. Preparation for Hierarchy
+ * of indexes DirIx, RegDirIx, etc.
+ *
+ * COMMENTS:
+ * none
+ *
+*/
+
+#include <stdlib.h>
+#include <iostream.h>
+// #include <vector.h>
+
+
+// extern char* myExecArgv0 = "";
+
+// #include "raslib/rminit.hh"
+//RMINITGLOBALS('C')
+
+class A
+{
+public:
+ A( );
+ A( A* a );
+ virtual void insertElement( A*& a );
+ virtual A* insertElementTransform( );
+ static void insertElementTransformStat( A*& );
+ virtual void printStatus( );
+ virtual ~A( );
+ int* DynAtt_A;
+ int StatAtt_A;
+protected:
+ void testProtectedA( );
+};
+
+A::A( )
+ :StatAtt_A(1)
+{
+ DynAtt_A = new int;
+ *DynAtt_A = 2;
+ cout <<"A Constructor"<< endl;
+}
+
+A::A( A* a)
+ :StatAtt_A( a->StatAtt_A ), DynAtt_A( a->DynAtt_A )
+{
+ a->DynAtt_A = 0;
+}
+
+void A::insertElement( A*& a )
+{
+ cout <<"A::insertElement( ) ";
+ printStatus( );
+ cout << endl;
+}
+
+A* A::insertElementTransform( )
+{
+ cout <<"A::insertElementTransform( ) ";
+ printStatus( );
+ cout << endl;
+ return this;
+}
+
+void A::insertElementTransformStat( A*& ix )
+{
+ cout <<"A::insertElementTransformStat( ) ";
+ ix->printStatus( );
+ cout << endl;
+}
+
+void A::printStatus( )
+{
+ cout <<"A: Dyn " << *DynAtt_A <<" Stat "<< StatAtt_A << endl;
+}
+
+A::~A()
+{
+ cout <<"A Destructor"<< endl;
+ if (DynAtt_A) delete DynAtt_A;
+}
+
+void A::testProtectedA( )
+{
+ cout <<"A::testProtectedA( )"<<endl;
+}
+
+class B: public A
+{
+public:
+ B( );
+ B( A* b );
+ virtual void insertElement( A*& a );
+ virtual A* insertElementTransform( );
+ static void insertElementTransformStat( A*& ix );
+ virtual void printStatus( );
+ virtual ~B( );
+ int* DynAtt_B;
+ int StatAtt_B;
+ void testProtectedB( );
+};
+
+B::B( )
+ :A( ),StatAtt_B(3)
+{
+ DynAtt_B = new int;
+ *DynAtt_B = 4;
+ cout <<"B Constructor"<< endl;
+}
+
+B::B( A* b )
+ :A(b),StatAtt_B(((B*)b)->StatAtt_B),DynAtt_B(((B*)b)->DynAtt_B)
+{
+ // use dynamic attributes of b, so that has to delete them
+ // from origin
+ ((B*)b)->DynAtt_B = 0;
+}
+
+void B::insertElement( A*& a )
+{
+ cout <<"B::insertElement( ) ";
+ printStatus( );
+ cout << endl;
+ A* c = new A( a );
+ delete a;
+ a = c;
+}
+
+A* B::insertElementTransform( )
+{
+ A* thisA = this;
+ cout <<"B::insertElementTransform( ) ";
+ printStatus( );
+
+ A* a = new A(thisA);
+ delete thisA;
+ return a;
+}
+
+void B::insertElementTransformStat( A*& ix )
+{
+ A* thisA = ix;
+ cout <<"B::insertElementTransformStat( ) ";
+ ix->printStatus( );
+
+ A* a = new A(thisA);
+ delete thisA;
+ ix = thisA;
+}
+
+void B::printStatus( )
+{
+ cout <<"B: Dyn " << *DynAtt_B <<" Stat "<< StatAtt_B << endl;
+}
+B::~B()
+{
+ cout <<"B Destructor"<< endl;
+ if (DynAtt_B) delete DynAtt_B;
+}
+
+void B::testProtectedB( )
+{
+ cout << "B::testProtectedB( ) calling A::testProtectedA( ) on itself: "<< endl;
+ A::testProtectedA( );
+ B objB;
+ cout << "B::testProtectedB( ) calling A::testProtectedA( ) on another obj B: "<< endl;
+ objB.testProtectedA( );
+ // A objA;
+ // cout << "B::testProtectedB( ) calling A::testProtectedA( ) on another obj A: "<< endl;
+ // objA.testProtectedA();
+}
+
+class C: public B
+{
+public:
+ C( int );
+ virtual void insertElement( A*& a );
+ virtual A* insertElementTransform( );
+ static void insertElementTransformStat( A*& ix );
+ virtual void printStatus( );
+ virtual ~C( );
+ int* DynAtt_C;
+ int StatAtt_C;
+};
+
+C::C(int)
+ :B(), StatAtt_C(5)
+{
+ DynAtt_C = new int;
+ *DynAtt_C = 6;
+ cout <<"C Constructor "<< endl;
+}
+void C::insertElement( A*& a )
+{
+ if( a != this )
+ cout << "Unexpected Usage of C::insertElement( ) "<< endl;
+ cout <<"C::insertElement( ) ";
+ printStatus( );
+
+ B* c = new B(a);
+ delete a;
+ a = c;
+}
+
+A* C::insertElementTransform( )
+{
+ A* thisA = this;
+ cout <<"C::insertElementTransform( ) ";
+ printStatus( );
+
+ B* b = new B(thisA);
+ delete thisA;
+ return b;
+
+}
+
+void C::insertElementTransformStat( A*& ix )
+{
+ A* thisA = ix;
+ cout <<"C::insertElementTransformStat( ) ";
+ ix->printStatus( );
+
+
+ B* b = new B(thisA);
+ ix = b;
+ delete thisA;
+
+}
+
+void C::printStatus( )
+{
+ cout <<"C: Dyn " << *DynAtt_C <<" Stat "<< StatAtt_C << endl;
+}
+
+C::~C( )
+{
+ cout <<"C Destructor"<< endl;
+ if (DynAtt_C) delete DynAtt_C;
+}
+
+/*************************************************************
+ * Function name.: int main( )
+ *
+ * Return value..: exit status
+ ************************************************************/
+int
+main( )
+{
+
+ cout << endl << " ---------------------------------------------- " << endl;
+ cout << endl << " Testing insertElementTransformStat( ) -------- " <<endl;
+
+ int i1t = 3;
+ cout << "Creating new C" << endl;
+ A *at = new C( i1t );
+ cout << endl << "Inserting 1. element in C and getting B"<< endl;
+ at->insertElementTransformStat( at );
+ cout << endl << "Inserting 2. element in B and getting A"<< endl;
+ at->insertElementTransformStat( at );
+ cout << endl << "Inserting 3. element in A and getting A"<< endl;
+ at->insertElementTransformStat( at );
+ cout << endl << "Inserting 4. element in A and getting A"<< endl;
+ at->insertElementTransformStat( at );
+ cout << endl << "Destroying object"<< endl;
+ delete at;
+
+ cout << endl << " ---------------------------------------------- "<< endl;
+ at = new C( i1t );
+ cout << endl << "Inserting 1. element in C and getting B"<< endl;
+ at->insertElementTransformStat( at );
+ cout << endl << "Destroying object"<< endl;
+ delete at;
+
+ cout << endl << " ---------------------------------------------- " << endl;
+
+ exit( 0);
+/*
+ cout << endl << " ---------------------------------------------- " << endl;
+ cout << endl << " Testing insertElementTransform( ) ------------ " <<endl;
+
+ int i1t = 3;
+ cout << "Creating new C" << endl;
+ A *at = new C( i1t );
+ cout << endl << "Inserting 1. element in C and getting B"<< endl;
+ at = at->insertElementTransform( );
+ cout << endl << "Inserting 2. element in B and getting A"<< endl;
+ at = at->insertElementTransform( );
+ cout << endl << "Inserting 3. element in A and getting A"<< endl;
+ at = at->insertElementTransform( );
+ cout << endl << "Inserting 4. element in A and getting A"<< endl;
+ at = at->insertElementTransform( );
+ cout << endl << "Destroying object"<< endl;
+ delete at;
+
+ cout << endl << " ---------------------------------------------- "<< endl;
+ at = new C( i1t );
+ cout << endl << "Inserting 1. element in C and getting B"<< endl;
+ at = at->insertElementTransform( );
+ cout << endl << "Destroying object"<< endl;
+ delete at;
+
+ cout << endl << " ---------------------------------------------- " << endl;
+*/
+
+
+
+/*
+ B objB;
+ objB.testProtectedB( );
+ exit( 0 );
+
+ int i1 = 3;
+ cout << "Creating new C" << endl;
+ A *a = new C( i1 );
+ cout << endl << "Inserting 1. element in C and getting B"<< endl;
+ a->insertElement( a );
+ cout << endl << "Inserting 2. element in B and getting A"<< endl;
+ a->insertElement( a );
+ cout << endl << "Inserting 3. element in A and getting A"<< endl;
+ a->insertElement( a );
+ cout << endl << "Inserting 4. element in A and getting A"<< endl;
+ a->insertElement( a );
+ cout << endl << "Destroying object"<< endl;
+ delete a;
+
+ cout << endl << " ---------------------------------------------- "<< endl;
+ a = new C( i1 );
+ cout << endl << "Inserting 1. element in C and getting B"<< endl;
+ a->insertElement( a );
+ cout << endl << "Destroying object"<< endl;
+ delete a;
+
+ cout << endl << " ---------------------------------------------- "<< endl;
+ C a1( i1 );
+ a = new C( i1 );
+ cout << endl << "Inserting 1. element in C and getting B"<< endl;
+ a1.insertElement( a );
+ cout << endl << "Inserting 2. element in C and getting B"<< endl;
+ a->insertElement( a );
+ cout << endl << "Destroying object"<< endl;
+ delete a;
+
+ exit( 0 );
+*/
+}
diff --git a/indexmgr/test/test_clusterix.cc b/indexmgr/test/test_clusterix.cc
new file mode 100644
index 0000000..92f4cf9
--- /dev/null
+++ b/indexmgr/test/test_clusterix.cc
@@ -0,0 +1,338 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_clusterix.cc
+ *
+ * MODULE: test for ClusterIx
+ *
+ * COMMENTS:
+ * none
+ *
+*/
+
+#include <stdlib.h>
+#include <iostream.h>
+#include <vector.h>
+
+#include "o2lib_CC.hxx" // declaration of O2-collection-classes
+
+#include "indexmgr/clusterix.hh"
+#include "dbclusterix.hh"
+#include "dbmddobjix.hh"
+#include "blobtile.hh"
+#include "basetype.hh"
+#include "ulongtype.hh"
+#include "raslib/minterval.hh"
+#include "raslib/sinterval.hh"
+#include "cachetamgr/perstile.hh"
+#include "cachetamgr/tile.hh"
+
+static char O2BenchDBName[] = "ClusterIxBase";
+// This test program must use a different base because it
+// doesn't use catalogif and adminif. It is not a complete RasDaBase.
+static char O2BenchSchemaName[] = "TestSMSchema";
+
+#include "raslib/rminit.hh"
+RMINITGLOBALS('C')
+
+static void ClearDB( d_Database &DB );
+static void testAccessing();
+static void testConstructors();
+static void testSearch();
+
+
+/*************************************************************
+ * Function name.: int main( int argc, char** argv)
+ *
+ * Arguments.....:
+ * argc: number of arguments given to program
+ * argv: array of char* with arguments
+ * Return value..: exit status
+ * Description...: none
+ ************************************************************/
+
+int
+main( int argc, char** argv)
+{
+ // variables representing O2 database, ta and session
+ d_Session session;
+ d_Database database;
+ d_Transaction ta;
+
+ // initialize the O2 session
+ cout << "Initializing O2 session..." << endl;
+ session.set_default_env();
+ if (session.begin(argc, argv)){
+ cerr << "Something wrong to start o2" << endl;
+ exit(1);
+ }
+
+ // clear the DB (in case the base already exists)
+ cout << "Deleting contents of database..." << endl;
+ ClearDB(database);
+
+ // connect to the database
+ cout << "Connecting to database " << O2BenchDBName
+ << "..." << endl;
+ // database.open( O2BenchDBName ); // doesn't work with O2 V.5
+
+ // create root collection
+ cout << "Creating root collection..." << endl;
+ ta.begin();
+ database.create_persistent_root( "IndexContainer",
+ "d_List<d_Ref<DBClusterIx>>",
+ OL_CONSTANT);
+ ta.commit();
+
+ // create indexes and put them in IndexContainer
+ cout << "Create indices and put in IndexContainer..." << endl;
+ ta.begin();
+ testConstructors();
+ ta.commit();
+
+ // read index and print contents
+ cout << "Read indices and print contents..." << endl;
+ ta.begin();
+ testAccessing();
+ ta.commit();
+
+ // test search operation and print contents
+ cout << "Search a rectangular region and print contents..." << endl;
+ ta.begin();
+ testSearch();
+ ta.commit();
+
+ cout << "Ending O2 session..." << endl;
+ database.close();
+ session.end();
+}
+
+/*************************************************************
+ * Function......: testConstructors()
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: constructs Indices and inserts them
+ * in root collection.
+ ************************************************************/
+
+static void testConstructors()
+{
+ ClusterIx* indexObj2;
+ ULongType anyType;
+ char anyCell[4];
+
+ cout << "....testConstructors"<< endl;
+
+ // read root object
+ d_List<DBMDDObjIxId> indexList("IndexContainer");
+
+ // create Index Object
+ cout << " indexObj1" << endl;
+
+ cout << " tile 1 = nil, 10-12, 20-24 "<< endl;
+ r_Sinterval limits1Obj1(10l,12l);
+ r_Sinterval limits2Obj1(20l,24l);
+ r_Minterval dom(2);
+ dom << limits1Obj1 << limits2Obj1;
+ PersTile* tile1Obj1 = new PersTile( dom, &anyType, (const char*) anyCell);
+
+ cout << " tile 2 = nil, 0-400, 22-24 "<< endl;
+ dom[0].set_interval(0l,400l);
+ dom[1].set_interval(22l,24l);
+ PersTile* tile2Obj1 = new PersTile( dom, &anyType, (const char*) anyCell);
+
+ cout << " tile 3 = nil, 0-600, 10-1000 "<< endl;
+ dom[0].set_interval(0l,600l);
+ dom[1].set_interval(10l,1000l);
+ PersTile* tile3Obj1 = new PersTile( dom, &anyType, (const char*) anyCell);
+
+ vector<PersTile*> newTiles;
+ newTiles.push_back(tile1Obj1);
+ newTiles.push_back(tile2Obj1);
+ newTiles.push_back(tile3Obj1);
+
+ ClusterIx* indexObj1 = new ClusterIx(newTiles);
+ indexList.insert_element_last(indexObj1->getDBMDDObjIxId());
+
+ // create DBclusterix Object
+
+ cout << " indexObj2 "<< endl;
+ cout << " tile 1 = nil, 0-19, 20-59, 30-59 "<< endl;
+ r_Sinterval limits1Obj2(0l,19l);
+ r_Sinterval limits2Obj2(20l,59l);
+ r_Sinterval limits3Obj2(30l,59l);
+ r_Minterval dom2(3);
+ dom2 << limits1Obj2 << limits2Obj2 << limits3Obj2;
+ PersTile* tile1Obj2 = new PersTile( dom2, &anyType, (const char*) anyCell);
+ indexObj2 = new ClusterIx(tile1Obj2);
+
+ cout << " tile 2 = nil, 20-39, 60-79, 60-89 "<< endl;
+ dom2[0].set_interval(20l,39l);
+ dom2[1].set_interval(60l,79l);
+ dom2[2].set_interval(60l,89l);
+ PersTile* tile2Obj2 = new PersTile( dom2, &anyType, (const char*) anyCell);
+ indexObj2->insertTile(tile2Obj2);
+ indexList.insert_element_last(indexObj2->getDBMDDObjIxId());
+
+ delete indexObj1;
+ delete indexObj2;
+}
+
+/*************************************************************
+ * Function......: testAccessing()
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: reads DBClusterIx's and shows contents
+ ************************************************************/
+
+static void testAccessing()
+{
+ DBMDDObjIxId accessedIndex;
+
+ cout << "....testAccessing"<<endl;
+
+ // read root object
+ d_List< DBMDDObjIxId > indexList("IndexContainer");
+ // used for iterating
+ d_Iterator< DBMDDObjIxId > indexIt = indexList.create_iterator();
+
+ for( int i = 1 ; indexIt.not_done(); i++, indexIt.advance())
+ {
+ accessedIndex = indexIt.get_element();
+ cout << " --"<<i<<". index object in list:" << endl;
+ accessedIndex->printStatus();
+ cout<<endl;
+ }
+
+}
+
+/*************************************************************
+ * Function......: testSearch()
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: reads Index's and shows contents
+ ************************************************************/
+
+static void testSearch()
+{
+
+ DBMDDObjIxId accessedIndex;
+ ULongType anyType;
+
+ cout << "....testSearch"<<endl;
+
+ // read root object
+ d_List< DBMDDObjIxId > indexList("IndexContainer");
+ // used for iterating
+ d_Iterator< DBMDDObjIxId > indexIt = indexList.create_iterator();
+
+ for( int i = 0 ; indexIt.not_done(); i++, indexIt.advance())
+ {
+ vector< Tile* >* entriesList;
+
+ accessedIndex = indexIt.get_element();
+
+ if (i == 0 || i == 1)
+ {
+ r_Minterval searchInt1(2);
+ r_Minterval searchInt2(3);
+
+ cout << " -- " << i+1 << ". index object in list. Search for:";
+ switch (i) {
+ case 0: searchInt1[0].set_interval(10l,20l);
+ searchInt1[1].set_interval(10l,30l);
+ cout << " 10-20, 10-30" << endl;
+ entriesList = accessedIndex->intersect(searchInt1, &anyType);
+ break;
+ case 1: searchInt2[0].set_interval(10l,20l);
+ searchInt2[1].set_interval(10l,30l);
+ searchInt2[2].set_interval(40l,50l);
+ cout << " 10-20, 10-30, 40-50" <<endl;
+ entriesList = accessedIndex->intersect(searchInt2, &anyType);
+ break;
+ default: break;
+ }
+ cout << " -- Search result: " << endl;
+ vector<Tile*>::iterator entryIt = entriesList->begin();
+
+ // O2 d_List d_Iterator< d_Ref<TilesIxEntry> > entryIt = entriesList->create_iterator();
+ // O2 d_List for ( ; entryIt.not_done() ; entryIt.advance() )
+ // O2 d_List entryIt.get_element()->printStatus();
+
+ while (entryIt != entriesList->end())
+ {
+ // (*entryIt)->printStatus();
+ r_Minterval tileInterval = (*entryIt)->getDomain();
+ int dimensionality = tileInterval.dimension();
+
+ cout << " PersTile printStatus";
+ cout << " domain == " << dimensionality << ": ";
+ for (int i = 0; i <dimensionality; i++)
+ cout << tileInterval[i].low() << "-" << tileInterval[i].high() <<", ";
+ cout << endl;
+
+ entryIt++;
+ }
+ }
+
+ // release(entriesList->begin(), entriesList->end());
+ for( vector<Tile*>::iterator entIt = entriesList->begin();
+ entIt != entriesList->end();
+ entIt++ )
+ delete *entIt;
+
+ delete entriesList;
+
+ }
+
+}
+/*************************************************************
+ * Function......: clearDB( d_Database &DB )
+ *
+ * Arguments.....: none
+ * DB: reference to a d_Database-object to use
+ * Return value..: none
+ * Description...: delete the O2-base (in case it already
+ * existed) and recreates an empty base
+ ************************************************************/
+
+static void ClearDB( d_Database &DB )
+{
+ d_Transaction trans;
+ trans.begin();
+
+ cout << "Destroying " << O2BenchDBName << endl;
+
+ // destroy the database in case it already exists
+ DB.destroy( O2BenchDBName );
+
+ // and create a new one
+ cout << "Creating " << O2BenchDBName <<" on schema "
+ << O2BenchSchemaName << endl;
+ DB.create( O2BenchDBName, O2BenchSchemaName );
+
+ trans.commit();
+}
diff --git a/indexmgr/test/test_dirix.cc b/indexmgr/test/test_dirix.cc
new file mode 100644
index 0000000..801d974
--- /dev/null
+++ b/indexmgr/test/test_dirix.cc
@@ -0,0 +1,357 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_dirix.cc
+ *
+ * MODULE: test for DirIx
+ *
+ * PURPOSE:
+ * instantiates DBDirIx objects and reads them
+ *
+ * COMMENTS:
+ * none
+ *
+*/
+
+#include <stdlib.h>
+#include <iostream.h>
+#include <vector.h>
+
+#define TEST_PROTECTED
+
+#include "o2lib_CC.hxx" // declaration of O2-collection-classes
+
+#include "indexmgr/dirix.hh"
+#include "dbdirix.hh"
+#include "dbmddobjix.hh"
+#include "blobtile.hh"
+#include "basetype.hh"
+#include "ulongtype.hh"
+#include "raslib/minterval.hh"
+#include "raslib/sinterval.hh"
+#include "cachetamgr/perstile.hh"
+#include "cachetamgr/tile.hh"
+#include "indexmgr/persdirix.hh"
+#include "indexmgr/regdirix.hh"
+
+static char O2BenchDBName[] = "DirIxBase";
+// This test program must use a different base because it
+// doesn't use catalogif and adminif. It is not a complete RasDaBase.
+static char O2BenchSchemaName[] = "TestSMSchema";
+
+extern char* myExecArgv0 = "";
+
+#include "raslib/rminit.hh"
+RMINITGLOBALS('C')
+
+static void ClearDB( d_Database &DB );
+static void testAccessing();
+static void testConstructors();
+static void testSearch();
+
+/*************************************************************
+ * Function name.: int main( int argc, char** argv)
+ *
+ * Arguments.....:
+ * argc: number of arguments given to program
+ * argv: array of char* with arguments
+ * Return value..: exit status
+ * Description...: none
+ ************************************************************/
+
+int
+main( int argc, char** argv)
+{
+
+ // variables representing O2 database, ta and session
+ d_Session session;
+ d_Database database;
+ d_Transaction ta;
+
+ // initialize the O2 session
+ cout << "Initializing O2 session..." << endl;
+ session.set_default_env();
+ if (session.begin(argc, argv)){
+ cerr << "Something wrong to start o2" << endl;
+ exit(1);
+ }
+
+ // clear the DB (in case the base already exists)
+ cout << "Deleting contents of database..." << endl;
+ ClearDB(database);
+
+ // connect to the database
+ cout << "Connecting to database " << O2BenchDBName
+ << "..." << endl;
+ // database.open( O2BenchDBName ); // doesn't work with O2 V.5
+
+ // create root collection
+ cout << "Creating root collection..." << endl;
+ ta.begin();
+ /*
+ database.create_persistent_root( "IndexContainer",
+ "d_List<d_Ref<DBDirIx>>",
+ OL_CONSTANT);
+ */
+ ta.commit();
+
+
+ // create indexes and put them in IndexContainer
+ cout << "Create indices and put in IndexContainer..." << endl;
+ ta.begin();
+ testConstructors();
+ ta.commit();
+
+ // read index and print contents
+ cout << "Read indices and print contents..." << endl;
+ ta.begin();
+ testAccessing();
+ ta.commit();
+
+ // test search operation and print contents
+ cout << "Search a rectangular region and print contents..." << endl;
+ ta.begin();
+ testSearch();
+ ta.commit();
+
+ cout << "Ending O2 session..." << endl;
+ database.close();
+ session.end();
+}
+
+/*************************************************************
+ * Function......: testConstructors()
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: constructs Indices and inserts them
+ * in root collection.
+ ************************************************************/
+
+static void testConstructors()
+{
+ ULongType anyType;
+ char anyCell[4];
+
+ cout << "....testConstructors"<< endl;
+
+ // read root object
+ d_List<DBMDDObjIxId> indexList("IndexContainer");
+
+ // create Index Object
+ cout << " indexObj1" << endl;
+
+ r_Minterval dom( "[10:12,20:24]");
+ cout << " tile 1 = nil, "<< dom << endl;
+ PersTile* tile1Obj1 =
+ new PersTile( dom, ( const BaseType* ) &anyType, (const char*) anyCell);
+
+ dom = r_Minterval( "[0:400,22:24]");
+ cout << " tile 2 = nil, "<< dom << endl;
+ PersTile* tile2Obj1 =
+ new PersTile( dom, ( const BaseType* ) &anyType, (const char*) anyCell);
+
+ dom = r_Minterval( "[0:600,10:1000]");
+ cout << " tile 3 = nil, "<< dom << endl;
+ PersTile* tile3Obj1 =
+ new PersTile( dom, ( const BaseType* ) &anyType, (const char*) anyCell);
+
+ vector<Tile*> newTiles;
+ newTiles.push_back(tile1Obj1);
+ newTiles.push_back(tile2Obj1);
+ newTiles.push_back(tile3Obj1);
+
+ PersDirIx* pd1 =
+ new PersDirIx( tile1Obj1->getDimension( ), ( const BaseType* ) &anyType );
+ RegDirIx<PersDirIx, Tile >* indexObj1 = new RegDirIx<PersDirIx, Tile >( pd1 );
+ MultiDimIx<Tile>::insertObjectsTransform( newTiles, indexObj1 );
+ // indexObj1->insertObjectsTransform( newTiles, indexObj1 );
+ indexList.insert_element_last(pd1->getDBMDDObjIxId());
+
+ // create DBDirIx Object
+
+ cout << " indexObj2 "<< endl;
+ r_Minterval dom2( "[0:19,20:59,30:59]");
+ cout << " tile 1 = nil, "<< dom2 << endl;
+ PersTile* tile1Obj2 =
+ new PersTile( dom2, ( const BaseType* ) &anyType, (const char*) anyCell);
+ PersDirIx* pd2 =
+ new PersDirIx( tile1Obj2->getDimension( ), ( const BaseType* ) &anyType );
+ RegDirIx<PersDirIx, Tile>* indexObj2 = new RegDirIx<PersDirIx, Tile>( pd2 );
+ indexObj2->insertObject( tile1Obj2 );
+
+ dom2 = r_Minterval( "[20:39,60:79,60:89]");
+ cout << " tile 2 = nil, "<< dom2 << endl;
+ PersTile* tile2Obj2 =
+ new PersTile( dom2, ( const BaseType* ) &anyType, (const char*) anyCell);
+ indexObj2->insertObject(tile2Obj2);
+ indexList.insert_element_last(pd2->getDBMDDObjIxId());
+
+ // PerDirIx doesn't free tiles
+ delete tile1Obj1;
+ delete tile2Obj1;
+ delete tile3Obj1;
+
+ delete tile1Obj2;
+ delete tile2Obj2;
+ delete indexObj1;
+ delete indexObj2;
+}
+
+/*************************************************************
+ * Function......: testAccessing()
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: reads DBDirIx's and shows contents
+ ************************************************************/
+
+static void testAccessing()
+{
+ DBMDDObjIxId accessedIndex;
+
+ cout << "....testAccessing"<<endl;
+
+ // read root object
+ d_List< DBMDDObjIxId > indexList("IndexContainer");
+ // used for iterating
+ d_Iterator< DBMDDObjIxId > indexIt = indexList.create_iterator();
+
+ for( int i = 1 ; indexIt.not_done(); i++, indexIt.advance())
+ {
+ accessedIndex = indexIt.get_element();
+ cout << " --"<<i<<". index object in list:" << endl;
+ accessedIndex->printStatus();
+ cout<<endl;
+ }
+
+}
+
+/*************************************************************
+ * Function......: testSearch()
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: reads Index's and shows contents
+ ************************************************************/
+
+static void testSearch()
+{
+
+ DBMDDObjIxId accessedIndex;
+ ULongType anyType;
+
+ cout << "....testSearch"<<endl;
+
+ // read root object
+ d_List< DBMDDObjIxId > indexList("IndexContainer");
+ // used for iterating
+ d_Iterator< DBMDDObjIxId > indexIt = indexList.create_iterator();
+
+ for( int i = 0 ; indexIt.not_done(); i++, indexIt.advance())
+ {
+ vector< Tile* >* entriesList;
+
+ accessedIndex = indexIt.get_element();
+
+ if (i == 0 || i == 1)
+ {
+ r_Minterval searchInt1(2);
+ r_Minterval searchInt2(3);
+
+ cout << " -- " << i+1 << ". index object in list. Search for:";
+ switch (i) {
+ case 0: searchInt1[0].set_interval(10l,20l);
+ searchInt1[1].set_interval(10l,30l);
+ cout << " 10-20, 10-30" << endl;
+ entriesList = ((d_Ref< DBDirIx>) accessedIndex)->intersect(searchInt1, &anyType);
+ break;
+ case 1: searchInt2[0].set_interval(10l,20l);
+ searchInt2[1].set_interval(10l,30l);
+ searchInt2[2].set_interval(40l,50l);
+ cout << " 10-20, 10-30, 40-50" <<endl;
+ entriesList = ((d_Ref<DBDirIx>)accessedIndex)->intersect(searchInt2, &anyType);
+ break;
+ default: break;
+ }
+ cout << " -- Search result: " << endl;
+ vector<Tile*>::iterator entryIt = entriesList->begin();
+
+ // O2 d_List d_Iterator< d_Ref<TilesIxEntry> > entryIt = entriesList->create_iterator();
+ // O2 d_List for ( ; entryIt.not_done() ; entryIt.advance() )
+ // O2 d_List entryIt.get_element()->printStatus();
+
+ while (entryIt != entriesList->end())
+ {
+ // (*entryIt)->printStatus();
+ r_Minterval tileInterval = (*entryIt)->getDomain();
+ int dimensionality = tileInterval.dimension();
+
+ cout << " PersTile printStatus";
+ cout << " domain == " << dimensionality << ": ";
+ for (int i = 0; i <dimensionality; i++)
+ cout << tileInterval[i].low() << "-" << tileInterval[i].high() <<", ";
+ cout << endl;
+
+ entryIt++;
+ }
+ }
+
+ // release(entriesList->begin(), entriesList->end());
+ for( vector<Tile*>::iterator entIt = entriesList->begin();
+ entIt != entriesList->end();
+ entIt++ )
+ delete *entIt;
+
+ delete entriesList;
+
+ }
+
+}
+/*************************************************************
+ * Function......: clearDB( d_Database &DB )
+ *
+ * Arguments.....: none
+ * DB: reference to a d_Database-object to use
+ * Return value..: none
+ * Description...: delete the O2-base (in case it already
+ * existed) and recreates an empty base
+ ************************************************************/
+
+static void ClearDB( d_Database &DB )
+{
+ d_Transaction trans;
+ trans.begin();
+
+ cout << "Destroying " << O2BenchDBName << endl;
+
+ // destroy the database in case it already exists
+ DB.destroy( O2BenchDBName );
+
+ // and create a new one
+ cout << "Creating " << O2BenchDBName <<" on schema "
+ << O2BenchSchemaName << endl;
+ DB.create( O2BenchDBName, O2BenchSchemaName );
+
+ trans.commit();
+}
diff --git a/indexmgr/test/test_expix.cc b/indexmgr/test/test_expix.cc
new file mode 100644
index 0000000..fc178a0
--- /dev/null
+++ b/indexmgr/test/test_expix.cc
@@ -0,0 +1,488 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_expix.cc
+ *
+ * MODULE: test for DirIx<T>
+ *
+ * PURPOSE:
+ * instantiates DirIx objects, inputs tiles and reads them, comparing
+ * performance for different indexes (for instance, DirIx<PersDirIx> vs.
+ * DirIx<TransDirIx>. Uses O2 directly.
+ *
+ * COMMENTS:
+ * none
+ *
+*/
+
+#include <stdlib.h>
+#include <iostream.h>
+#include <vector.h>
+
+#include "o2lib_CC.hxx" // declaration of O2-collection-classes
+
+#include "indexmgr/transmddobjix.hh"
+#include "indexmgr/persmddobjix.hh"
+#include "indexmgr/dirix.hh"
+#include "indexmgr/transdirix.hh"
+#include "dbdirix.hh"
+#include "dbmddobjix.hh"
+#include "blobtile.hh"
+#include "basetype.hh"
+#include "ulongtype.hh"
+#include "raslib/minterval.hh"
+#include "raslib/sinterval.hh"
+#include "cachetamgr/perstile.hh"
+#include "cachetamgr/tile.hh"
+#include "tools/timer.hh"
+#include "indexmgr/persdirix.hh"
+
+static char O2BenchDBName[] = "DirIxBase";
+// This test program must use a different base because it
+// doesn't use catalogif and adminif. It is not a complete RasDaBase.
+static char O2BenchSchemaName[] = "TestSMSchema";
+
+extern char* myExecArgv0 = "";
+
+#include "raslib/rminit.hh"
+RMINITGLOBALS('C')
+
+static void ClearDB( d_Database &DB );
+static void testAccessing();
+
+static void testTransDirIx();
+static void testDirIx();
+
+
+/*************************************************************
+ * Function name.: int main( int argc, char** argv)
+ *
+ * Arguments.....:
+ * argc: number of arguments given to program
+ * argv: array of char* with arguments
+ * Return value..: exit status
+ * Description...: none
+ ************************************************************/
+
+int
+main( int argc, char** argv)
+{
+
+ // variables representing O2 database, ta and session
+ d_Session session;
+ d_Database database;
+ d_Transaction ta;
+
+ // initialize the O2 session
+ cout << "Initializing O2 session..." << endl;
+ session.set_default_env();
+ if (session.begin(argc, argv)){
+ cerr << "Something wrong to start o2" << endl;
+ exit(1);
+ }
+
+ // clear the DB (in case the base already exists)
+ cout << "Deleting contents of database..." << endl;
+ ClearDB(database);
+
+ // connect to the database
+ cout << "Connecting to database " << O2BenchDBName
+ << "..." << endl;
+ // database.open( O2BenchDBName ); // doesn't work with O2 V.5
+
+ // create root collection
+ cout << "Creating root collection..." << endl;
+ ta.begin();
+ // database.create_persistent_root( "IndexContainer",
+ // "d_List<d_Ref<DBDirIx>>",
+ // OL_CONSTANT);
+ ta.commit();
+
+ /*
+ cout << "Testing TransDirIx..." << endl;
+ ta.begin();
+ testTransDirIx( );
+ ta.commit();
+ */
+
+ cout << "Testing DirIx..." << endl;
+ ta.begin();
+ testDirIx( );
+ ta.commit();
+
+ cout << endl;
+ cout << "Ending O2 session..." << endl;
+ database.close();
+ session.end();
+
+ return 0;
+}
+
+
+void
+testTransDirIx( )
+{
+
+ cout << "....testTransDirIx"<< endl;
+
+ TransDirIx* ti = new TransDirIx( 2 );
+ cout << "TransDirIx just created: "<< endl;
+ ti->printStatus( );
+
+ ULongType anyType;
+ char anyCell[4];
+
+ TransTile* ttArray[12];
+
+ for( long j = 0; j < 12 ; j++)
+ {
+ r_Minterval dom(2);
+ dom << r_Sinterval( j, j+ 5 ) << r_Sinterval( j , j+5 );
+ TransTile* tt = new TransTile( dom, (BaseType* ) &anyType, anyCell );
+ ttArray[j] = tt;
+ }
+
+ for( j = 0; j < 10 ; j++)
+ {
+ cout << "Insert Tile Last " << ttArray[j]->getDomain( ) << endl;
+ ti->insertObjectLast( ttArray[j] );
+ ti->printStatus( );
+ }
+
+ cout << "Insert Tile pos 5 " << ttArray[10]->getDomain( ) << endl;
+ ti->insertObject( ttArray[10], 5 );
+ ti->printStatus( );
+
+ cout << "Insert Tile First " << ttArray[11]->getDomain( ) << endl;
+ ti->insertObjectFirst( ttArray[11] );
+ ti->printStatus( );
+
+ delete ti;
+}
+
+void
+testDirIx( )
+{
+ cout << "....testDirIx"<< endl;
+
+ ULongType anyType;
+ char anyCell[4];
+
+ // TransDirIx* t = new TransDirIx( 2 );
+ // PersDirIx* t = new PersDirIx( 2, &anyType );
+
+ // char index[] = "MDDObjIx* DirIx<TransDIrIx>";
+ // char index[] = "MDDObjIx* DirIx<PersDirIx>";
+ // char index[] = "MDDObjIx* PersMDDObjIx ";
+ // char index[] = "TransMDDObjIx* DirIx<TransDirIx> ";
+ char index[] = "PersMDDObjIx* DirIx< > ";
+ // MDDObjIx* /* DirIx< TransDirIx >* */ di = new DirIx< TransDirIx >( t );
+ // DirIx< PersDirIx >* di = new DirIx< PersDirIx >( t );
+ MDDStorage ms1;
+ ms1.setIndexType( MDDStorage::DirTilesIx );
+ PersMDDObjIx* di = new PersMDDObjIx( 2, &anyType, &ms1 );
+ // TransMDDObjIx* di = new TransMDDObjIx( 2, 0 );
+
+ // char index1[] = "TransMDDObjIx* RegDirIx<TransDirIx>";
+ char index1[] = "PersMDDObjIx* RegDirIx< >";
+ // char index1[] = "TransMDDObjIx* ";
+ // TransMDDObjIx* di1 = new TransMDDObjIx( 2, 1 );
+ // DirIx< TransDirIx >* di1 = new DirIx< TransDirIx >( t );
+ MDDStorage ms;
+ ms.setIndexType( MDDStorage::RegDirIx );
+ PersMDDObjIx* di1 = new PersMDDObjIx( 2, &anyType, &ms );
+
+ cout << "Comparison of Index " << index << endl;
+ cout << "with Index1 " << index1 << endl;
+
+ // NumTiles should be a square from something:
+ unsigned const sqrtnumTiles = 32;
+ unsigned const NumTiles = sqrtnumTiles * sqrtnumTiles ;
+ unsigned const NumIntersections = 30;
+
+ // cout << "Index " << index << " just created: "<< endl;
+ // di->printStatus( );
+
+
+ cout <<"Random insertion of tiles into the indexe(s) ..." << endl;
+ Tile* ttArray[NumTiles]; Tile* tt1Array[NumTiles];
+ unsigned alreadyUsed[NumTiles];
+
+ long j = 0;
+
+ for( long k = 0; k < sqrtnumTiles ; k++ )
+ {
+ for( long l = 0; l < sqrtnumTiles ; l++)
+ {
+ r_Minterval dom(2);
+ // dom << r_Sinterval( k*5 , k*5+5-1 ) << r_Sinterval( l*5 , l*5+5-1 );
+ dom << r_Sinterval( k , k ) << r_Sinterval( l , l );
+
+ // Tile* tt = new TransTile( dom, (BaseType* ) &anyType, anyCell );
+ Tile* tt = new PersTile( dom, (const BaseType* ) &anyType, anyCell );
+ // Tile* tt1 = new TransTile( dom, (BaseType* ) &anyType, anyCell );
+ Tile* tt1 = new PersTile( dom, (const BaseType* ) &anyType, anyCell );
+
+ ttArray[j] = tt; tt1Array[j] = tt1;
+ alreadyUsed[j]=0;
+ j++;
+ }
+ }
+
+ cout <<" j "<< j << endl;
+
+ for( j = 0; j < NumTiles ; j++)
+ {
+ int ixToUse = rand( ) % NumTiles;
+ if ( alreadyUsed[ ixToUse ] )
+ {
+ // calculate another index;
+ ixToUse = 0;
+ for( int i = 0; !ixToUse && i < NumTiles; i++ )
+ {
+ if ( !alreadyUsed[i] ) ixToUse = i;
+ }
+ }
+ alreadyUsed[ ixToUse ] = 1;
+ cout << "Insert Tile ttArray[ " << ixToUse << " ] : ";
+ cout << ttArray[ixToUse]->getDomain( ) << endl;
+
+ // Index
+ di->insertTile( ttArray[ ixToUse ] );
+ // Index 1
+ di1->insertTile( tt1Array[ ixToUse ] );
+ // di->printStatus( );
+ }
+
+ cout << index << " contents: "<< endl;
+ di->printStatus( );
+
+ cout << index1 << " contents: "<< endl;
+ di1->printStatus( );
+ cout << endl;
+
+ r_Minterval cd = di->getCurrentDomain( );
+
+ r_Minterval badQuery1("[33:43,139:149]");
+ // not bad r_Minterval badQuery1("[65:75,32:42]");
+
+ r_Minterval badQuery2("[139:149,144:154]");
+
+ r_Minterval badQuery3("[43:53,81:91]");
+ // not bad r_Minterval badQuery3("[107:117,53:63]");
+
+ r_Minterval badQuery4("[37:47,151:161]");
+ // not bad r_Minterval badQuery4("[89:99,11:21]");
+
+ r_Minterval badQuery5("[71:81,113:123]"); // not bad
+
+ // test extreme cases: no intersection at all with the current domain
+ r_Minterval badQuery6("[161:162,113:113]");
+
+ // test extreme cases: no intersection at all with the current domain
+ r_Minterval badQuery7("[170:172,140:140]");
+
+ for( int i = 0; i < NumIntersections; i++ )
+ {
+ Timer time; Timer time1;
+ RMTimer* rtime = new RMTimer( "DirIx", "intersect" );
+ RMTimer* rtime1 = new RMTimer( "RegDirIx", "intersect" );
+ r_Minterval intRegion( 2 );
+ long l1 = cd.get_origin( )[0];
+ long l2 = cd.get_origin( )[1];
+ long h1 = cd.get_high( )[0];
+ long h2 = cd.get_high( )[1];
+ long length1 = h1 - l1 +1;
+ long length2 = h2 - l2 +1;
+ l1 = l1 + rand( ) % length1;
+ l2 = l2 + rand( ) % length2;
+ h1 = l1 + (rand( ) % (h1-l1+1) );
+ h2 = l2 + (rand( ) % (h2-l2+1) );
+ intRegion << r_Sinterval( l1,h1) << r_Sinterval( l2,h2);
+
+/*
+ if ( i == NumIntersections - 1 )
+ intRegion = badQuery1;
+ if ( i == NumIntersections - 2 )
+ intRegion = badQuery2;
+ if ( i == NumIntersections - 3 )
+ intRegion = badQuery3;
+ if ( i == NumIntersections - 4 )
+ intRegion = badQuery4;
+ if ( i == NumIntersections - 5 )
+ intRegion = badQuery5;
+*/
+ if ( i == NumIntersections - 6 )
+ intRegion = badQuery6;
+ if ( i == NumIntersections - 7 )
+ intRegion = badQuery7;
+
+
+ cout << "Intersect with "<< intRegion << endl;
+
+ // Index
+ time.start( ); rtime->start( );
+ vector< Tile* >* rqResult = di->intersect( intRegion );
+ rtime->stop( ); time.stop( );
+ if ( rqResult )
+ {
+ cout << index << endl << " No. of tiles, time , time/noTiles = "
+ << rqResult->size( ) << " , "<< time << " , ";
+ if ( rqResult->size( ) ) cout << time.ellapsed_sec( )/rqResult->size( ) << endl;
+ }
+ else
+ cout << "No tiles intersected "<< endl;
+ delete rtime;
+
+ // Index 1
+ time1.start( ); rtime1->start( );
+ vector< Tile* >* rqResult1 = di1->intersect( intRegion );
+ rtime1->stop( ); time1.stop( );
+ if ( rqResult1 )
+ {
+ cout << index1 << endl << " No. of tiles, time1, time1/noTiles = "
+ << rqResult1->size( ) << " , "<< time1 << " , ";
+ if ( rqResult1->size( ) ) cout << time1.ellapsed_sec( )/rqResult1->size( ) << endl;
+ }
+ else
+ cout << "No tiles intersected "<< endl;
+ delete rtime1;
+
+
+ // Index
+ cout << "Result " << index << endl;
+ if ( rqResult )
+ {
+ for( int j = 0; j < rqResult->size( ); j++)
+ cout << ( *rqResult )[j]->getDomain( ) << endl;
+ delete rqResult;
+ }
+
+ // Index1
+ cout << "Result " << index1 << endl;
+ if ( rqResult1 )
+ {
+ for( j = 0; j < rqResult1->size( ); j++)
+ cout << ( *rqResult1 )[j]->getDomain( ) << endl;
+ delete rqResult1;
+ }
+ cout << endl;
+ }
+
+ for( i = 0; i < NumIntersections; i++ )
+ {
+ Timer time; Timer time1;
+ r_Point pnt(2);
+ RMTimer* rtime = new RMTimer( "DirIx", "Point query" );
+ RMTimer* rtime1 = new RMTimer( "RegDirIx", "Point query" );
+ long l1 = cd.get_origin( )[0];
+ long l2 = cd.get_origin( )[1];
+ long length1 = cd.get_high( )[0] - l1;
+ long length2 = cd.get_high( )[1] - l2;
+ l1 = l1 + rand( ) % length1;
+ l2 = l2 + rand( ) % length2;
+ pnt << l1 << l2;
+
+ cout << "Point query with "<< pnt << endl;
+
+
+ // Index
+ time.start( ); rtime->start( );
+ Tile* rqResult = di->containPointQuery( pnt );
+ rtime->stop( ); time.stop( );
+ cout << index << " tile, time = "
+ << rqResult->getDomain( ) << " , "<< time << endl;
+ delete rtime;
+
+ // Index 1
+ time1.start( ); rtime1->start( );
+ Tile* rqResult1 = di1->containPointQuery( pnt );
+ rtime1->stop( ); time1.stop( );
+ cout << index1 << " tile, time1 = "
+ << rqResult1->getDomain( ) << " , "<< time1 << endl;
+ delete rtime1;
+
+ cout << endl;
+ }
+
+ delete di;
+ delete di1;
+}
+
+/*************************************************************
+ * Function......: testAccessing()
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: reads DBDirIx's and shows contents
+ ************************************************************/
+
+static void testAccessing()
+{
+ DBMDDObjIxId accessedIndex;
+
+ cout << "....testAccessing"<<endl;
+
+ // read root object
+ d_List< DBMDDObjIxId > indexList("IndexContainer");
+ // used for iterating
+ d_Iterator< DBMDDObjIxId > indexIt = indexList.create_iterator();
+
+ for( int i = 1 ; indexIt.not_done(); i++, indexIt.advance())
+ {
+ accessedIndex = indexIt.get_element();
+ cout << " --"<<i<<". index object in list:" << endl;
+ accessedIndex->printStatus();
+ cout<<endl;
+ }
+
+}
+
+
+/*************************************************************
+ * Function......: clearDB( d_Database &DB )
+ *
+ * Arguments.....: none
+ * DB: reference to a d_Database-object to use
+ * Return value..: none
+ * Description...: delete the O2-base (in case it already
+ * existed) and recreates an empty base
+ ************************************************************/
+
+static void ClearDB( d_Database &DB )
+{
+ d_Transaction trans;
+ trans.begin();
+
+ cout << "Destroying " << O2BenchDBName << endl;
+
+ // destroy the database in case it already exists
+ DB.destroy( O2BenchDBName );
+
+ // and create a new one
+ cout << "Creating " << O2BenchDBName <<" on schema "
+ << O2BenchSchemaName << endl;
+ DB.create( O2BenchDBName, O2BenchSchemaName );
+
+ trans.commit();
+}
diff --git a/indexmgr/test/test_hierix.cc b/indexmgr/test/test_hierix.cc
new file mode 100644
index 0000000..306d1bc
--- /dev/null
+++ b/indexmgr/test/test_hierix.cc
@@ -0,0 +1,388 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_hierix.cc
+ *
+ * MODULE: test for PersHierIx
+ *
+ * PURPOSE:
+ * instantiates DBDirIx objects and reads them
+ *
+ * COMMENTS:
+ * none
+ *
+*/
+
+#include <stdlib.h>
+#include <iostream.h>
+#include <vector.h>
+
+#define TEST_PROTECTED
+
+#include "o2lib_CC.hxx" // declaration of O2-collection-classes
+
+
+#include "dbhierix.hh"
+#include "dbdirix.hh"
+#include "dbmddobjix.hh"
+
+#include "blobtile.hh"
+#include "basetype.hh"
+#include "ulongtype.hh"
+#include "raslib/minterval.hh"
+#include "raslib/sinterval.hh"
+#include "cachetamgr/perstile.hh"
+#include "cachetamgr/tile.hh"
+#include "indexmgr/persdirix.hh"
+#include "indexmgr/regdirix.hh"
+#include "indexmgr/pershierix.hh"
+#include "indexmgr/dirix.hh"
+#include "indexmgr/rptreeix.hh"
+
+static char O2BenchDBName[] = "HierIxBase";
+// This test program must use a different base because it
+// doesn't use catalogif and adminif. It is not a complete RasDaBase.
+static char O2BenchSchemaName[] = "TestSMSchema";
+
+extern char* myExecArgv0 = "";
+
+#include "raslib/rminit.hh"
+RMINITGLOBALS('C')
+
+static void ClearDB( d_Database &DB );
+static void testAccessing();
+static void testConstructors();
+static void testSearch();
+
+/*************************************************************
+ * Function name.: int main( int argc, char** argv)
+ *
+ * Arguments.....:
+ * argc: number of arguments given to program
+ * argv: array of char* with arguments
+ * Return value..: exit status
+ * Description...: none
+ ************************************************************/
+
+int
+main( int argc, char** argv)
+{
+
+ // variables representing O2 database, ta and session
+ d_Session session;
+ d_Database database;
+ d_Transaction ta;
+
+ // initialize the O2 session
+ cout << "Initializing O2 session..." << endl;
+ session.set_default_env();
+ if (session.begin(argc, argv)){
+ cerr << "Something wrong to start o2" << endl;
+ exit(1);
+ }
+
+ // clear the DB (in case the base already exists)
+ cout << "Deleting contents of database..." << endl;
+ ClearDB(database);
+
+ // connect to the database
+ cout << "Connecting to database " << O2BenchDBName
+ << "..." << endl;
+ // database.open( O2BenchDBName ); // doesn't work with O2 V.5
+
+ // create root collection
+ cout << "Creating root collection..." << endl;
+ ta.begin();
+ database.create_persistent_root( "HierIndexContainer",
+ "d_List<d_Ref<DBDirIx>>",
+ OL_CONSTANT);
+ ta.commit();
+
+
+ // create indexes and put them in HierIndexContainer
+ cout << "Create indices and put in HierIndexContainer..." << endl;
+ ta.begin();
+ testConstructors();
+ ta.commit();
+
+ // read index and print contents
+ cout << "Read indices and print contents..." << endl;
+ ta.begin();
+ testAccessing();
+ ta.commit();
+
+ // test search operation and print contents
+ // cout << "Search a rectangular region and print contents..." << endl;
+ // ta.begin();
+ // testSearch();
+ //ta.commit();
+
+ cout << "Ending O2 session..." << endl;
+ database.close();
+ session.end();
+}
+
+/*************************************************************
+ * Function......: testConstructors()
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: constructs Indices and inserts them
+ * in root collection.
+ ************************************************************/
+
+static void testConstructors()
+{
+ ULongType anyType;
+ char anyCell[4];
+ RPlusTreeIx< Tile >* rtix;
+
+ cout << "....testConstructors"<< endl;
+
+ // read root object
+ d_List<DBMDDObjIxId> indexList("HierIndexContainer");
+
+
+ // create Index Object
+ cout << " indexObj1" << endl;
+
+ r_Minterval dom( "[10:12,20:24]");
+ cout << " tile 1 = nil, "<< dom << endl;
+ PersTile* tile1Obj1 =
+ new PersTile( dom, ( const BaseType* ) &anyType, (const char*) anyCell);
+
+ dom = r_Minterval( "[0:400,22:24]");
+ cout << " tile 2 = nil, "<< dom << endl;
+ PersTile* tile2Obj1 =
+ new PersTile( dom, ( const BaseType* ) &anyType, (const char*) anyCell);
+
+ dom = r_Minterval( "[0:600,10:1000]");
+ cout << " tile 3 = nil, "<< dom << endl;
+ PersTile* tile3Obj1 =
+ new PersTile( dom, ( const BaseType* ) &anyType, (const char*) anyCell);
+
+ vector<Tile*> newTiles;
+ newTiles.push_back(tile1Obj1);
+ newTiles.push_back(tile2Obj1);
+ newTiles.push_back(tile3Obj1);
+
+ PersDirIx* pd1 =
+ new PersDirIx( tile1Obj1->getDimension( ), ( const BaseType* ) &anyType );
+ pd1->insertObject( tile1Obj1, 0 );
+ pd1->insertObject( tile2Obj1, 1 );
+ pd1->insertObject( tile3Obj1, 2 );
+
+ // pd1->insertObjects( newTiles );
+
+ indexList.insert_element_last(pd1->getDBMDDObjIxId());
+
+ // create DBDirIx Object
+
+ cout << " indexObj2 "<< endl;
+ // cout << " tile 1 = nil, 0-19, 20-59, 30-59 "<< endl;
+ r_Minterval dom2( "[0:19,20:59,30:59]");
+ cout << " tile 1 = nil, "<< dom2 << endl;
+
+ PersTile* tile1Obj2 =
+ new PersTile( dom2, ( const BaseType* ) &anyType, (const char*) anyCell);
+ PersDirIx* pd2 =
+ new PersDirIx( tile1Obj2->getDimension( ), ( const BaseType* ) &anyType );
+ pd2->insertObject( tile1Obj2, 0 );
+ // RegDirIx<PersDirIx, Tile>* indexObj2 = new RegDirIx<PersDirIx, Tile>( pd2 );
+ // indexObj2->insertObject( tile1Obj2 );
+
+ // cout << " tile 2 = nil, 20-39, 60-79, 60-89 "<< endl;
+ dom2 = r_Minterval( "[20:39,60:79,60:89]");
+ cout << " tile 2 = nil, "<< dom2 << endl;
+
+ PersTile* tile2Obj2 =
+ new PersTile( dom2, ( const BaseType* ) &anyType, (const char*) anyCell);
+ pd2->insertObject( tile2Obj2, 1 );
+ // indexObj2->insertObject(tile2Obj2);
+ indexList.insert_element_last(pd2->getDBMDDObjIxId());
+
+
+ PersHierIx* hierIxObj =
+ new PersHierIx( pd1->getDimension( ),( const BaseType* ) &anyType );
+ rtix = new RPlusTreeIx< Tile >( hierIxObj );
+
+ DirIx< PersHierIx, PersIx >* hix = new DirIx< PersHierIx, PersIx >( hierIxObj );
+
+ // hierIxObj->insertObject( pd1, 0 );
+ // hierIxObj->insertObject( pd2, 1 );
+ r_Minterval domain( pd1->getDomain( ) );
+ // domain.closure_with( pd2->getDomain(
+ hix->insertObject( pd1 );
+ hix->insertObject( pd2 );
+ indexList.insert_element_last(hierIxObj->getDBMDDObjIxId());
+
+ // PerDirIx doesn't free tiles
+ delete tile1Obj1;
+ delete tile2Obj1;
+ delete tile3Obj1;
+
+ delete tile1Obj2;
+ delete tile2Obj2;
+ // delete pd1;
+ // delete pd2;
+ // delete hierIxObj;
+ delete hix;
+}
+
+/*************************************************************
+ * Function......: testAccessing()
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: reads DBDirIx's and shows contents
+ ************************************************************/
+
+static void testAccessing()
+{
+ DBMDDObjIxId accessedIndex;
+
+ cout << "....testAccessing"<<endl;
+
+ // read root object
+ d_List< DBMDDObjIxId > indexList("HierIndexContainer");
+ // used for iterating
+ d_Iterator< DBMDDObjIxId > indexIt = indexList.create_iterator();
+
+ for( int i = 1 ; indexIt.not_done(); i++, indexIt.advance())
+ {
+ accessedIndex = indexIt.get_element();
+ cout << " --"<<i<<". index object in list:" << endl;
+ accessedIndex->printStatus();
+ cout<<endl;
+ }
+
+}
+
+/*************************************************************
+ * Function......: testSearch()
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: reads Index's and shows contents
+ ************************************************************/
+
+static void testSearch()
+{
+
+ DBMDDObjIxId accessedIndex;
+ ULongType anyType;
+
+ cout << "....testSearch"<<endl;
+
+ // read root object
+ d_List< DBMDDObjIxId > indexList("HierIndexContainer");
+ // used for iterating
+ d_Iterator< DBMDDObjIxId > indexIt = indexList.create_iterator();
+
+ for( int i = 0 ; indexIt.not_done(); i++, indexIt.advance())
+ {
+ vector< Tile* >* entriesList;
+
+ accessedIndex = indexIt.get_element();
+
+ if (i == 0 || i == 1)
+ {
+ r_Minterval searchInt1(2);
+ r_Minterval searchInt2(3);
+
+ cout << " -- " << i+1 << ". index object in list. Search for:";
+ switch (i) {
+ case 0: searchInt1[0].set_interval(10l,20l);
+ searchInt1[1].set_interval(10l,30l);
+ cout << " 10-20, 10-30" << endl;
+ entriesList = ((d_Ref< DBDirIx>) accessedIndex)->intersect(searchInt1, &anyType);
+ break;
+ case 1: searchInt2[0].set_interval(10l,20l);
+ searchInt2[1].set_interval(10l,30l);
+ searchInt2[2].set_interval(40l,50l);
+ cout << " 10-20, 10-30, 40-50" <<endl;
+ entriesList = ((d_Ref<DBDirIx>)accessedIndex)->intersect(searchInt2, &anyType);
+ break;
+ default: break;
+ }
+ cout << " -- Search result: " << endl;
+ vector<Tile*>::iterator entryIt = entriesList->begin();
+
+ // O2 d_List d_Iterator< d_Ref<TilesIxEntry> > entryIt = entriesList->create_iterator();
+ // O2 d_List for ( ; entryIt.not_done() ; entryIt.advance() )
+ // O2 d_List entryIt.get_element()->printStatus();
+
+ while (entryIt != entriesList->end())
+ {
+ // (*entryIt)->printStatus();
+ r_Minterval tileInterval = (*entryIt)->getDomain();
+ int dimensionality = tileInterval.dimension();
+
+ cout << " PersTile printStatus";
+ cout << " domain == " << dimensionality << ": ";
+ for (int i = 0; i <dimensionality; i++)
+ cout << tileInterval[i].low() << "-" << tileInterval[i].high() <<", ";
+ cout << endl;
+
+ entryIt++;
+ }
+ }
+
+ // release(entriesList->begin(), entriesList->end());
+ for( vector<Tile*>::iterator entIt = entriesList->begin();
+ entIt != entriesList->end();
+ entIt++ )
+ delete *entIt;
+
+ delete entriesList;
+
+ }
+
+}
+/*************************************************************
+ * Function......: clearDB( d_Database &DB )
+ *
+ * Arguments.....: none
+ * DB: reference to a d_Database-object to use
+ * Return value..: none
+ * Description...: delete the O2-base (in case it already
+ * existed) and recreates an empty base
+ ************************************************************/
+
+static void ClearDB( d_Database &DB )
+{
+ d_Transaction trans;
+ trans.begin();
+
+ cout << "Destroying " << O2BenchDBName << endl;
+
+ // destroy the database in case it already exists
+ DB.destroy( O2BenchDBName );
+
+ // and create a new one
+ cout << "Creating " << O2BenchDBName <<" on schema "
+ << O2BenchSchemaName << endl;
+ DB.create( O2BenchDBName, O2BenchSchemaName );
+
+ trans.commit();
+}
diff --git a/indexmgr/test/test_ix.cc b/indexmgr/test/test_ix.cc
new file mode 100644
index 0000000..424140c
--- /dev/null
+++ b/indexmgr/test/test_ix.cc
@@ -0,0 +1,517 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_ix.cc
+ *
+ * MODULE: test for RasDaMan tiles indexes
+ *
+ * PURPOSE:
+ * Compares RPTreeIx's to DirIx's
+ *
+ * COMMENTS:
+ * none
+ *
+*/
+
+#include <stdlib.h>
+#include <iostream.h>
+#include <vector.h>
+
+#include "raslib/minterval.hh"
+#include "raslib/sinterval.hh"
+#include "raslib/rmdebug.hh"
+
+
+#include <math.h>
+
+extern char* myExecArgv0 = "";
+
+unsigned maximumFill = 10;
+
+#include "raslib/rminit.hh"
+RMINITGLOBALS('C')
+
+
+void calculateGrid( const r_Minterval& baseTile,
+ const r_Minterval& gridDesc,
+ long& numberParts,
+ vector<r_Minterval>*& grid ); //r_Minterval*& grid );
+
+
+float calculateAlignFactor( const vector<r_Minterval>& partition);
+
+int isDisjunctive( const vector<r_Minterval>& parts );
+
+void createTilesDomains( ofstream& outRndPopFile,
+ ofstream& outRndBMFile,
+ ofstream& outPopFile,
+ ofstream& outBMFile,
+ float alignFactor,
+ vector< r_Minterval >*& tgIntsVec,
+ int numberTiles,
+ unsigned dim );
+int randomInsertion = 1;
+int seqInsertion = 1;
+
+/*************************************************************
+ * Function name.: int main( int argc, char** argv)
+ *
+ * Arguments.....:
+ * argc: number of arguments given to program
+ * argv: array of char* with arguments
+ * Return value..: exit status
+ * Description...: none
+ ************************************************************/
+int
+main( int argc, char** argv)
+{
+
+ // variables representing O2 database, ta and session
+
+ if( argc < 4 ) {
+ cout << "Usage: test_ix <dim> <numberTiles> <alignFactor> [-r|-s]" << endl;
+ cout << " -s only sequential insertion " << endl;
+ cout << " -r only random insertion " << endl;
+ cout << " default - both sequential and random " << endl;
+ return -1;
+ }
+
+ unsigned dim;
+ unsigned numberTiles;
+ float af;
+ dim = atoi( argv[1]);
+ numberTiles = atoi( argv[2]);
+ af = atof( argv[3] );
+ if ( dim < 2 || dim > 8 )
+ {
+ cout << " Error : dimensionality outside supported limits !" << endl;
+ return -1;
+ }
+ if ( numberTiles > 100000 || numberTiles < 50 )
+ {
+ cout << " Error : number of tiles outside supported limits !" << endl;
+ return -1;
+ }
+ if ( af < 0.05 || af > 1 )
+ {
+ cout << " Error : alignment fator outside supported limits !" << endl;
+ return -1;
+ }
+
+ if ( argc == 5 && strcmp(argv[4], "-r") == 0 )
+ {
+ seqInsertion = 0;
+ }
+ else if ( argc == 5 && strcmp(argv[4], "-s") == 0 )
+ {
+ randomInsertion = 0;
+ }
+
+
+ cout << "Dimensionality " << dim << endl;
+ cout << "Number of Tiles " << numberTiles << endl;
+ cout << "Alignment factor " << af << endl;
+ cout << "RandomInsertion ";
+
+ if ( randomInsertion )
+ cout << "RandomInsertion " << endl;
+ if ( seqInsertion )
+ cout << "SequentialInsertion " << endl;
+
+ vector< r_Minterval >* tgIntsVec;
+
+
+ char namePopFile[100];
+ char nameRndPopFile[100];
+ char nameBMFile[100];
+ char nameRndBMFile[100];
+ int afint = af*100;
+
+ sprintf( nameRndPopFile, "ix%dd%dn%dafrndpop.txt", dim, numberTiles, afint);
+ sprintf( nameRndBMFile, "ix%dd%dn%dafrnd.bm", dim, numberTiles, afint);
+ sprintf( namePopFile, "ix%dd%dn%dafpop.txt", dim, numberTiles, afint);
+ sprintf( nameBMFile, "ix%dd%dn%daf.bm", dim, numberTiles, afint);
+
+ ofstream ixStreamPopResults( namePopFile );
+ ofstream ixStreamRndPopResults( nameRndPopFile );
+ ofstream ixStreamBMResults( nameBMFile );
+ ofstream ixStreamRndBMResults( nameRndBMFile );
+ if ( randomInsertion )
+ {
+ cout << "nameRndPopFile " << nameRndPopFile << endl;
+ cout << "nameRndBMFile " << nameRndBMFile << endl;
+ // system("/usr/bin/date
+ if ( !ixStreamRndPopResults || !ixStreamRndBMResults )
+ {
+ cout <<"Error: one file could not be openened" << endl;
+ return -1;
+ }
+ }
+ if ( seqInsertion )
+ {
+ cout << "namePopFile " << namePopFile << endl;
+ cout << "nameBMFile " << nameBMFile << endl;
+ // system("/usr/bin/date
+ if ( !ixStreamPopResults || !ixStreamBMResults )
+ {
+ cout <<"Error: one file could not be openened" << endl;
+ return -1;
+ }
+ }
+
+
+ cout << "Dim " << dim << endl;
+ cout << "NTiles wanted " << numberTiles << endl;
+ cout << "AlignFactor wanted " << af << endl;
+
+
+ createTilesDomains( ixStreamRndPopResults, ixStreamRndBMResults,
+ ixStreamPopResults, ixStreamBMResults, af, tgIntsVec,
+ numberTiles, dim );
+ numberTiles = tgIntsVec->size( ); // integer arithmetic error
+
+
+ ixStreamPopResults.close( );
+ ixStreamBMResults.close( );
+ ixStreamRndPopResults.close( );
+ ixStreamRndBMResults.close( );
+
+ return 0;
+}
+
+
+/*************************************************************************
+ *
+ *
+ ************************************************************************/
+void
+calculateGrid( const r_Minterval& baseTile,
+ const r_Minterval& gridDesc,
+ long& numberParts,
+ vector< r_Minterval>*& grid ) // grid r_Minterval*& grid)
+{
+ cout << "calculateGrid( " << baseTile << ", "<< gridDesc << ") "<< endl;
+ numberParts = gridDesc.cell_count( );
+ grid = new vector<r_Minterval>(numberParts); //new r_Minterval[numberParts];
+ r_Point ix( baseTile.dimension( ));
+ r_Point ext = baseTile.get_extent( );
+ for ( int i= 0; i < numberParts ; i++ )
+ {
+ ix = gridDesc.cell_point( i )* ext;
+ (*grid)[i] = baseTile.create_translation( ix );
+ // grid[i] = r_Minterval( baseTile.create_translation( ix ) );
+ }
+
+}
+
+/*************************************************************************
+ *
+ *
+ ************************************************************************/
+void
+createTilesDomains( ofstream& outRndPopFile, // file for test_populate
+ ofstream& outRndBMFile, // file for benchmark
+ ofstream& outPopFile, // file for test_populate
+ ofstream& outBMFile, // file for benchmark
+ float alignFactor,
+ vector< r_Minterval >*& tgIntsVec,
+ int numberTiles,
+ unsigned dim )
+{
+
+ if( alignFactor > 1 || alignFactor == 0 )
+ {
+ cout <<"Error: invalid alignment factor." << endl;
+ exit(0);
+ }
+
+ cout << "Alignment factor wanted " << alignFactor << endl;
+ cout << "Number of tiles, dim " << numberTiles << ", "<< dim << endl;
+
+ // number of partitions of the total grid
+ double ntgdouble = numberTiles/alignFactor;
+ // cout <<"Number of tiles in total grid (double)== " << ntgdouble << endl;
+ long ntg = ntgdouble;
+ cout <<"Number of tiles in total grid (long)== " << ntg << endl;
+
+ // r_Minterval* tgInts;
+
+ float f = float (1/ float(dim) );
+ long n = pow( ntg, f);
+ cout <<"Number of tiles in d-1 first directions (n) == " << n << endl;
+ r_Minterval tile(dim);
+ const unsigned tileLength = 3;
+ r_Minterval totalGrid( dim );
+ for (int i = 0; i < dim -1; i++ )
+ {
+ tile[i].set_interval( r_Range( 0 ), tileLength-1 );
+ totalGrid[i].set_interval( r_Range( 0 ), n-1 );
+ }
+ long n1 = pow(n,dim-1);
+ n1 = ntg/n1;
+ cout << "Number of tiles in direction d (n1) == " << n1 << endl;
+ tile[dim-1].set_interval( r_Range( 0 ), tileLength-1 );
+ totalGrid[dim-1].set_interval( r_Range( 0 ), n1-1 );
+
+ long ntg1;
+ calculateGrid( tile, totalGrid, ntg1, tgIntsVec );
+
+ if ( ntg1 < numberTiles )
+ {
+ cout <<"Error: number of partitions in total grid less than numberTiles";
+ cout <<"Exiting the program (integer arithmetic)"<< endl;
+ // exit(0);
+ }
+
+ if ( ntg1 != ntg )
+ {
+ cout << "Warning: number of partitions in total grid is not as expected " << endl;
+ cout << "Alignment factor won't be as expected (integer arithmetic)"<< endl;
+ }
+
+ cout << endl;
+
+ //tgIntsVec = new vector< r_Minterval >( tgInts, tgInts+ntg1 );
+
+ // delete tgInts; // ????
+
+ cout << "Number of tiles in total grid " << ntg1 << endl;
+ /*
+ for( i =0; i < tgIntsVec->size( ); i++ )
+ cout << "Interval "<< i << (*tgIntsVec)[i] <<endl;
+ */
+ int numberMerges = ntg1-numberTiles;
+ int cont = 1;
+ for ( i = 0; i < numberMerges && cont ; )
+ {
+ int found = 0;
+ int r = rand( ) % (tgIntsVec->size( ) );
+ // merge randomly
+ int notFinished = 1;
+
+ int contr = 1;
+ for( int ri = 0; contr && cont ; ri++)
+ {
+ notFinished = 1;
+ int init = rand( ) % tgIntsVec->size( );
+ for( int j = init; notFinished ; )
+ {
+ // cout <<"i,j"<< i <<","<< j<<endl;
+ if( (*tgIntsVec)[j].is_mergeable( (*tgIntsVec)[r]) )
+ {
+
+ if ( i % 100 == 0 )
+ cout << numberMerges-i << ". Merging j,r "<< j <<","<< r << " "
+ << (*tgIntsVec)[j] << ", " << (*tgIntsVec)[r] << " resulting ";
+ /*
+ cout << numberMerges-i << ". Merging j,r "<< j <<","<< r << " "
+ << (*tgIntsVec)[j] << ", " << (*tgIntsVec)[r] << " resulting ";
+ */
+
+ (*tgIntsVec)[j] = (*tgIntsVec)[j].closure_with( (*tgIntsVec)[r] );
+ tgIntsVec->erase( tgIntsVec->begin( ) + r );
+
+ if ( i % 100 == 0 )
+ {
+ if ( r < j )
+ cout << (*tgIntsVec)[j-1] <<endl;
+ else
+ cout << (*tgIntsVec)[j] <<endl;
+ }
+
+ i++;
+ notFinished = 0;
+ found = 1;
+ }
+ j = (j+1) % tgIntsVec->size( );
+ if ( j == init )
+ notFinished = 0;
+ }
+ // cout << " r == " << r << ", j == " << j << " , notFinished == " << notFinished << endl;
+ // cout << " ri == " << ri << " , tgIntsVec->size( ) " << tgIntsVec->size( ) << endl;
+ r = (r+1) % tgIntsVec->size( );
+ if ( found )
+ contr = 0; // already found
+ else
+ {
+ if ( ri >= tgIntsVec->size( ) )
+ cont = 0; // no more merges possible
+ else
+ r = (r+1) % tgIntsVec->size( );
+ }
+ }
+ }
+
+ cout << "======================================================="<< endl;
+ cout << "Results : "<< endl;
+ cout << " Alignement Factor wanted :" << alignFactor << endl;
+ cout << " Number of Resulting Tiles " << tgIntsVec->size( ) << endl;
+
+ cout << " Resulting Tiles " << endl;
+
+ unsigned ntilesObta = tgIntsVec->size( );
+ cout << "NTiles obtained " << ntilesObta << endl;
+
+ float faObta = float ( tgIntsVec->size( ))/ntg1;
+ cout <<" Alignment factor obtained "<< faObta << endl;
+
+ /*
+ * Benchmark file format:
+ * Dim \t ntiles \t af \t random \t h \t occ
+ */
+ if ( seqInsertion )
+ {
+ outBMFile << dim << "\t";
+ outBMFile << ntilesObta << "\t";
+ outBMFile << faObta << "\t";
+ outBMFile << "0\t";
+ }
+ if ( randomInsertion )
+ {
+ outRndBMFile << dim << "\t";
+ outRndBMFile << ntilesObta << "\t";
+ outRndBMFile << faObta << "\t";
+ outRndBMFile <<"1\t";
+ }
+
+ // Visual_Tiling_2D visTil( dom, "TilesImage");
+
+ /*
+ * Pop file format:
+ * Database: BmarkIxBase
+ *
+ * MDDColl: Ix2D_1000N_5AF_Set; Char2DSet
+ *
+ * MDDObj: [ 0:*, 0:*] ; Char2D
+ *
+ * HowToStore:
+ * IndexType: R+TreeIx
+ */
+ char collRndName[100];
+ char collName[100];
+ char collTypeName[100];
+ char mddTypeName[100];
+ int faInt = faObta*100;
+ if ( randomInsertion )
+ sprintf( collRndName, "Ix%dD_%dN_%dAF_RND_Set", dim, ntilesObta, faInt);
+ if ( seqInsertion )
+ sprintf( collName, "Ix%dD_%dN_%dAF_Set", dim, ntilesObta, faInt);
+ r_Minterval dom( dim );
+ for ( int d = 0; d < dim; d++ )
+ dom[d].set_interval((r_Range)0,'*');
+
+ sprintf( collTypeName, "Char%dDSet", dim);
+ sprintf( mddTypeName, "Char%dD", dim );
+
+ if ( seqInsertion )
+ {
+ outPopFile << "Database: BmarkIxBase " << endl << endl;
+ outPopFile << "MDDColl: " << collName << "; " << collTypeName << endl<< endl;
+ outPopFile << "MDDObj: " << dom << " ; " << mddTypeName << endl;
+ outPopFile << "HowToStore:" << endl;
+ outPopFile << "IndexType: R+TreeIx " << endl << endl;
+ }
+ if ( randomInsertion )
+ {
+ outRndPopFile << "Database: BmarkIxBase " << endl << endl;
+ outRndPopFile << "MDDColl: " << collRndName << "; " << collTypeName << endl<< endl;
+ outRndPopFile << "MDDObj: " << dom << " ; " << mddTypeName << endl;
+ outRndPopFile << "HowToStore:" << endl;
+ outRndPopFile << "IndexType: R+TreeIx " << endl << endl;
+ }
+ if ( seqInsertion )
+ {
+ for( i = 0; i < tgIntsVec->size( ); i++ )
+ {
+ outPopFile <<"Tile : "<< " "<< (*tgIntsVec)[i] << "; 0x0000" << endl;
+ }
+ }
+ if ( randomInsertion )
+ {
+ unsigned vecSz = tgIntsVec->size( );
+ vector< r_Minterval >* tgIntsVec2;
+ tgIntsVec2 = new vector<r_Minterval>(vecSz);
+ unsigned tix = i;
+ for( i = 0; i < vecSz; i++ )
+ {
+ tix = rand( ) % tgIntsVec->size( );
+ outRndPopFile <<"Tile : "<< " "<< (*tgIntsVec)[tix] << "; 0x0000" << endl;
+ (*tgIntsVec2)[i] = (*tgIntsVec)[tix];
+ tgIntsVec->erase( tgIntsVec->begin( ) + tix );
+ }
+ vector< r_Minterval >* tmpIntsVec;
+ tmpIntsVec = tgIntsVec;
+ tgIntsVec = tgIntsVec2;
+ delete tmpIntsVec;
+ }
+
+ /* For debugging purposes:
+ if( !isDisjunctive( *tgIntsVec ))
+ {
+ cout <<"Error: Nondisjunctive partition, exiting program "<< endl;
+ exit( 0);
+ }
+ else cout <<" Disjunctive partition OK " << endl;
+ */
+
+ if( tgIntsVec->size( ) != numberTiles )
+ {
+ cout <<"Error: tgIntsVec->size( ) != numberTiles "<< endl;
+ // exit( 0);
+ }
+ // calculateAlignFactor( tgIntsVec );
+
+}
+
+
+/*************************************************************************
+ *
+ *
+ ************************************************************************/
+float
+calculateAlignFactor( const vector<r_Minterval>& part )
+{
+ float fa;
+ // for ( int i = 0; i < part.size( ); i++ ) ;
+
+ return fa;
+}
+
+/*************************************************************************
+ *
+ *
+ ************************************************************************/
+int isDisjunctive( const vector<r_Minterval>& parts )
+{
+ for( int i = 0; i < parts.size( ); i++ )
+ {
+ r_Minterval inter = parts[i];
+ for( int j = i+1; j < parts.size( ); j++ )
+ {
+ if( inter.intersects_with( parts[j] ))
+ return 0;
+ }
+ }
+ return 1;
+}
+
diff --git a/indexmgr/test/test_ix1.cc b/indexmgr/test/test_ix1.cc
new file mode 100644
index 0000000..73c5323
--- /dev/null
+++ b/indexmgr/test/test_ix1.cc
@@ -0,0 +1,853 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_ix.cc
+ *
+ * MODULE: test for RasDaMan tiles indexes
+ *
+ * PURPOSE:
+ * Compares RPTreeIx's to DirIx's
+ *
+ * COMMENTS:
+ * none
+ *
+*/
+
+#include "mymalloc/mymalloc.h"
+
+#include <stdlib.h>
+#include <iostream.h>
+#include <vector.h>
+
+
+#include "o2lib_CC.hxx" // declaration of O2-collection-classes
+#include <o2.h> // O2 Engine
+#include <o2_error.h> // O2 error from O2 Engine
+
+#include "dbmddobjix.hh"
+#include "basetype.hh"
+#include "chartype.hh"
+#include "raslib/minterval.hh"
+#include "raslib/sinterval.hh"
+#include "cachetamgr/perstile.hh"
+#include "tools/timer.hh"
+#include "indexmgr/persdirix.hh"
+#include "indexmgr/pershierix.hh"
+#include "indexmgr/rptreeix.hh"
+#include "indexmgr/dirix.hh"
+#include "raslib/rmdebug.hh"
+
+
+#include <math.h>
+
+// This test program must use a different base because it
+// doesn't use catalogif and adminif. It is not a complete RasDaBase.
+static char O2BenchDBName[] = "TestIxBase";
+static char O2BenchSchemaName[] = "TestSMSchema";
+
+extern char* myExecArgv0 = "";
+
+unsigned maximumFill = 10;
+
+#include "raslib/rminit.hh"
+RMINITGLOBALS('C')
+
+static void ClearDB( d_Database &DB );
+
+// indexType 1 : R+ tree, 2: DirIx
+static void testPopulateIx( int indexType,
+ const vector< r_Minterval >& tilesDoms );
+
+// static void createTilesArr( Tile** tiles, float alignFactor, int numberTiles );
+
+
+void testCompareIxs( );
+
+void calculateGrid( const r_Minterval& baseTile,
+ const r_Minterval& gridDesc,
+ long& numberParts,
+ vector<r_Minterval>*& grid ); //r_Minterval*& grid );
+
+static void testCompareIxs( char* index, char* index1,
+ MultiDimIx<Tile>* ix, MultiDimIx<Tile>* ix1,
+ r_Minterval* searchInts, int numInts);
+
+float calculateAlignFactor( const vector<r_Minterval>& partition);
+
+int isDisjunctive( const vector<r_Minterval>& parts );
+
+void createTilesDomains( ofstream& outPopFile,
+ ofstream& outBMFile,
+ float alignFactor,
+ vector< r_Minterval >*& tgIntsVec,
+ int numberTiles,
+ unsigned dim );
+int randomInsertion;
+
+/*************************************************************
+ * Function name.: int main( int argc, char** argv)
+ *
+ * Arguments.....:
+ * argc: number of arguments given to program
+ * argv: array of char* with arguments
+ * Return value..: exit status
+ * Description...: none
+ ************************************************************/
+int
+main( int argc, char** argv)
+{
+
+ // variables representing O2 database, ta and session
+ d_Session session;
+ d_Database database;
+ d_Transaction ta;
+
+ if( argc < 4 ) {
+ cout << "Usage: test_ix <dim> <numberTiles> <alignFactor> [-r]" << endl;
+ return -1;
+ }
+
+ unsigned dim;
+ unsigned numberTiles;
+ float af;
+ dim = atoi( argv[1]);
+ numberTiles = atoi( argv[2]);
+ af = atof( argv[3] );
+ if ( dim < 2 || dim > 8 )
+ {
+ cout << " Error : dimensionality outside supported limits !" << endl;
+ return -1;
+ }
+ if ( numberTiles > 100000 || numberTiles < 50 )
+ {
+ cout << " Error : number of tiles outside supported limits !" << endl;
+ return -1;
+ }
+ if ( af < 0.05 || af > 1 )
+ {
+ cout << " Error : alignment fator outside supported limits !" << endl;
+ return -1;
+ }
+
+ if ( argc == 5 && strcmp(argv[4], "-r") == 0 )
+ randomInsertion = 1;
+ else
+ randomInsertion = 0;
+
+
+ cout << "Dimensionality " << dim << endl;
+ cout << "Number of Tiles " << numberTiles << endl;
+ cout << "Alignment factor " << af << endl;
+ cout << "RandomInsertion ";
+ if ( randomInsertion )
+ cout << " yes " << endl;
+ else
+ cout << " no " << endl;
+
+ /*
+ // initialize the O2 session
+ cout << "Initializing O2 session..." << endl;
+ session.set_default_env();
+ if (session.begin(argc, argv)){
+ cerr << "Something wrong to start o2" << endl;
+ exit(1);
+ }
+
+ // connect to the database
+ cout << "Connecting to database " << O2BenchDBName
+ << "..." << endl;
+ try{
+ database.open( O2BenchDBName ); // doesn't work with O2 V.5
+ }
+ catch( ...)
+ {
+ cout << "Could not open database. Exiting "<< endl;
+ session.end();
+ return -1;
+ }
+
+
+ // create root collection
+ cout << "Checking root collection..." << endl;
+ ta.begin();
+ Handle collHandle = 0;
+ collHandle = o2_get_root((char*)"HierIndexContainer");
+
+ if (!collHandle)
+ {
+ cout << "Collection doesn't exist yet, creating collection ... "<< endl;
+ // if root name isn't used yet, create new root name for MDD collection
+ // I don't know if this is needed. It works without it.
+ o2_unref_handle( collHandle );
+ database.create_persistent_root( "HierIndexContainer",
+ "d_List<d_Ref<DBMDDObjIx>>",
+ OL_CONSTANT);
+ }
+ else
+ {
+ cout << "Collection exists already, does nothing. "<< endl;
+ // if it exists already, doesn't do anything
+ // I don't know if this is needed. It works without it.
+ o2_unref_handle(collHandle);
+ }
+ */
+ /*
+ int exists = 1;
+ try{
+ d_List< DBMDDObjIxId > indexList("HierIndexContainer");
+ }
+ catch( ...)
+ {
+ cout << "Persistent root does't exist" << endl;
+ exists =0;
+ }
+ if ( !exists )
+ database.create_persistent_root( "HierIndexContainer",
+ "d_List<d_Ref<DBMDDObjIx>>",
+ OL_CONSTANT);
+ */
+ // ta.commit();
+
+
+ vector< r_Minterval >* tgIntsVec;
+
+
+ char namePopFile[100];
+ char nameBMFile[100];
+ int afint = af*100;
+ if ( randomInsertion )
+ {
+ sprintf( namePopFile, "ix%dd%dn%dafrndpop.txt", dim, numberTiles, afint);
+ sprintf( nameBMFile, "ix%dd%dn%dafrnd.bm", dim, numberTiles, afint);
+ }
+ else
+ {
+ sprintf( namePopFile, "ix%dd%dn%dafpop.txt", dim, numberTiles, afint);
+ sprintf( nameBMFile, "ix%dd%dn%daf.bm", dim, numberTiles, afint);
+ }
+ cout << "namePopFile " << namePopFile << endl;
+ cout << "nameBMFile " << nameBMFile << endl;
+
+ ofstream ixStreamPopResults(namePopFile);
+ ofstream ixStreamBMResults(nameBMFile);
+
+ // system("/usr/bin/date
+ if ( !ixStreamPopResults || !ixStreamBMResults )
+ {
+ cout <<"Error: one file could not be openened" << endl;
+ return -1;
+ }
+
+ cout << "Dim " << dim << endl;
+ cout << "NTiles wanted " << numberTiles << endl;
+ cout << "AlignFactor wanted " << af << endl;
+
+
+ // numberTiles = 80 * i;
+ createTilesDomains( ixStreamPopResults, ixStreamBMResults, af, tgIntsVec, numberTiles, dim );
+ numberTiles = tgIntsVec->size( ); // integer arithmetic error
+
+ /*
+ cout << "Populating Index 1..." << endl;
+ ta.begin( );
+ testPopulateIx( 1, *tgIntsVec );
+ ta.commit( );
+
+ cout << "Populating Index 2..." << endl;
+ ta.begin( );
+ testPopulateIx( 2, *tgIntsVec );
+ ta.commit( );
+
+ delete tgIntsVec;
+
+ cout <<"Testing two indexes ..."<< endl;
+ ta.begin( );
+ testCompareIxs( );
+ ta.commit( );
+
+ cout << endl;
+ cout << "Ending O2 session..." << endl;
+ database.close();
+ session.end();
+ */
+
+ ixStreamPopResults.close( );
+ ixStreamBMResults.close( );
+
+ return 0;
+}
+
+/*************************************************************************
+ *
+ *
+ ************************************************************************/
+void
+testPopulateIx( int indexType, const vector< r_Minterval >& tilesDomains )
+{
+ CharType anyType;
+ char* anyCells;
+ const int numberTiles = tilesDomains.size( );
+ const int dim = tilesDomains[1].dimension( );
+
+
+ cout << "....testPopulateIx"<< endl;
+ d_List< DBMDDObjIxId > indexList("HierIndexContainer");
+
+ PersDirIx* ix = new PersDirIx( dim, &anyType );
+
+ MultiDimIx< Tile >* rix;
+
+ cout << "Ix of type ";
+ switch( indexType )
+ {
+ case 1:
+ cout << "RPlusTree ";
+ rix = new RPlusTreeIx<Tile>( ix, maximumFill );
+ break;
+ case 2:
+ cout << "DirIx ";
+ rix = new DirIx< PersDirIx, Tile >( ix );
+ break;
+ // to be extended
+ default:
+ cout <<"Error "<<endl;
+ exit( 2 );
+ }
+
+ cout << "just created: "<< endl;
+ rix->printStatus( );
+
+ Tile* tiles[100000];
+
+ for( int i = 0; i < tilesDomains.size( ); i++ )
+ {
+ anyCells = (char*)mymalloc(tilesDomains[i].cell_count() * anyType.getSize());
+ tiles[i] =
+ new PersTile( tilesDomains[i], (const BaseType*) &anyType, anyCells);
+ }
+
+
+ cout << endl;
+ for( i = 0; i < numberTiles ; i++ )
+ {
+ cout << endl << "Insert new tile " << i << " " << tiles[i]->getDomain( )<< endl;
+
+ rix->insertObject( tiles[i] );
+
+ // rix->printStatus( );
+ // cout << endl;
+ }
+ cout << endl << "Finished, index contents: " << endl;
+ rix->printStatus( );
+ cout << endl;
+ indexList.insert_element_last( ( (PersIx*) (rix->getIxDS( )) )->getDBMDDObjIxId( ) );
+ for( i = 0; i < numberTiles ; i++ )
+ delete tiles[i];
+ delete rix;
+}
+
+/*************************************************************************
+ *
+ *
+ ************************************************************************/
+void
+calculateGrid( const r_Minterval& baseTile,
+ const r_Minterval& gridDesc,
+ long& numberParts,
+ vector< r_Minterval>*& grid ) // grid r_Minterval*& grid)
+{
+ cout << "calculateGrid( " << baseTile << ", "<< gridDesc << ") "<< endl;
+ numberParts = gridDesc.cell_count( );
+ grid = new vector<r_Minterval>(numberParts); //new r_Minterval[numberParts];
+ r_Point ix( baseTile.dimension( ));
+ r_Point ext = baseTile.get_extent( );
+ for ( int i= 0; i < numberParts ; i++ )
+ {
+ ix = gridDesc.cell_point( i )* ext;
+ (*grid)[i] = baseTile.create_translation( ix );
+ // grid[i] = r_Minterval( baseTile.create_translation( ix ) );
+ }
+
+}
+
+/*************************************************************************
+ *
+ *
+ ************************************************************************/
+void
+createTilesDomains( ofstream& outPopFile, // file for test_populate
+ ofstream& outBMFile, // file for benchmark
+ float alignFactor,
+ vector< r_Minterval >*& tgIntsVec,
+ int numberTiles,
+ unsigned dim )
+{
+
+ if( alignFactor > 1 || alignFactor == 0 )
+ {
+ cout <<"Error: invalid alignment factor." << endl;
+ exit(0);
+ }
+
+ cout << "Alignment factor wanted " << alignFactor << endl;
+ cout << "Number of tiles, dim " << numberTiles << ", "<< dim << endl;
+
+ // number of partitions of the total grid
+ double ntgdouble = numberTiles/alignFactor;
+ // cout <<"Number of tiles in total grid (double)== " << ntgdouble << endl;
+ long ntg = ntgdouble;
+ cout <<"Number of tiles in total grid (long)== " << ntg << endl;
+
+ // r_Minterval* tgInts;
+
+ float f = float (1/ float(dim) );
+ long n = pow( ntg, f);
+ cout <<"Number of tiles in d-1 first directions (n) == " << n << endl;
+ r_Minterval tile(dim);
+ const unsigned tileLength = 5;
+ r_Minterval totalGrid( dim );
+ for (int i = 0; i < dim -1; i++ )
+ {
+ tile[i].set_interval( r_Range( 0 ), tileLength-1 );
+ totalGrid[i].set_interval( r_Range( 0 ), n-1 );
+ }
+ long n1 = pow(n,dim-1);
+ n1 = ntg/n1;
+ cout << "Number of tiles in direction d (n1) == " << n1 << endl;
+ tile[dim-1].set_interval( r_Range( 0 ), tileLength-1 );
+ totalGrid[dim-1].set_interval( r_Range( 0 ), n1-1 );
+
+ long ntg1;
+ calculateGrid( tile, totalGrid, ntg1, tgIntsVec );
+
+ if ( ntg1 < numberTiles )
+ {
+ cout <<"Error: number of partitions in total grid less than numberTiles";
+ cout <<"Exiting the program (integer arithmetic)"<< endl;
+ // exit(0);
+ }
+
+ if ( ntg1 != ntg )
+ {
+ cout << "Warning: number of partitions in total grid is not as expected " << endl;
+ cout << "Alignment factor won't be as expected (integer arithmetic)"<< endl;
+ }
+
+ cout << endl;
+
+ //tgIntsVec = new vector< r_Minterval >( tgInts, tgInts+ntg1 );
+
+ // delete tgInts; // ????
+
+ cout << "Number of tiles in total grid " << ntg1 << endl;
+ /*
+ for( i =0; i < tgIntsVec->size( ); i++ )
+ cout << "Interval "<< i << (*tgIntsVec)[i] <<endl;
+ */
+ int numberMerges = ntg1-numberTiles;
+ int cont = 1;
+ for ( i = 0; i < numberMerges && cont ; )
+ {
+ int found = 0;
+ int r = rand( ) % (tgIntsVec->size( ) );
+ // merge randomly
+ int notFinished = 1;
+
+ int contr = 1;
+ for( int ri = 0; contr && cont ; ri++)
+ {
+ notFinished = 1;
+ int init = rand( ) % tgIntsVec->size( );
+ for( int j = init; notFinished ; )
+ {
+ // cout <<"i,j"<< i <<","<< j<<endl;
+ if( (*tgIntsVec)[j].is_mergeable( (*tgIntsVec)[r]) )
+ {
+
+ if ( i % 100 == 0 )
+ cout << numberMerges-i << ". Merging j,r "<< j <<","<< r << " "
+ << (*tgIntsVec)[j] << ", " << (*tgIntsVec)[r] << " resulting ";
+ /*
+ cout << numberMerges-i << ". Merging j,r "<< j <<","<< r << " "
+ << (*tgIntsVec)[j] << ", " << (*tgIntsVec)[r] << " resulting ";
+ */
+
+ (*tgIntsVec)[j] = (*tgIntsVec)[j].closure_with( (*tgIntsVec)[r] );
+ tgIntsVec->erase( tgIntsVec->begin( ) + r );
+
+ if ( i % 100 == 0 )
+ {
+ if ( r < j )
+ cout << (*tgIntsVec)[j-1] <<endl;
+ else
+ cout << (*tgIntsVec)[j] <<endl;
+ }
+
+ i++;
+ notFinished = 0;
+ found = 1;
+ }
+ j = (j+1) % tgIntsVec->size( );
+ if ( j == init )
+ notFinished = 0;
+ }
+ // cout << " r == " << r << ", j == " << j << " , notFinished == " << notFinished << endl;
+ // cout << " ri == " << ri << " , tgIntsVec->size( ) " << tgIntsVec->size( ) << endl;
+ r = (r+1) % tgIntsVec->size( );
+ if ( found )
+ contr = 0; // already found
+ else
+ {
+ if ( ri >= tgIntsVec->size( ) )
+ cont = 0; // no more merges possible
+ else
+ r = (r+1) % tgIntsVec->size( );
+ }
+ }
+ }
+
+ cout << "======================================================="<< endl;
+ cout << "Results : "<< endl;
+ cout << " Alignement Factor wanted :" << alignFactor << endl;
+ cout << " Number of Resulting Tiles " << tgIntsVec->size( ) << endl;
+
+ cout << " Resulting Tiles " << endl;
+
+ unsigned ntilesObta = tgIntsVec->size( );
+ cout << "NTiles obtained " << ntilesObta << endl;
+
+ float faObta = float ( tgIntsVec->size( ))/ntg1;
+ cout <<" Alignment factor obtained "<< faObta << endl;
+
+ /*
+ * Benchmark file format:
+ * Dim \t ntiles \t af \t random \t h \t occ
+ */
+ outBMFile << dim << "\t";
+ outBMFile << ntilesObta << "\t";
+ outBMFile << faObta << "\t";
+ if ( randomInsertion )
+ outBMFile <<"1\t";
+ else
+ outBMFile << "0\t";
+
+ // Visual_Tiling_2D visTil( dom, "TilesImage");
+
+ /*
+ * Pop file format:
+ * Database: BmarkIxBase
+ *
+ * MDDColl: Ix2D_1000N_5AF_Set; Char2DSet
+ *
+ * MDDObj: [ 0:*, 0:*] ; Char2D
+ *
+ * HowToStore:
+ * IndexType: R+TreeIx
+ */
+ char collName[100];
+ char collTypeName[100];
+ char mddTypeName[100];
+ int faInt = faObta*100;
+ if ( randomInsertion )
+ sprintf( collName, "Ix%dD_%dN_%dAF_RND_Set", dim, ntilesObta, faInt);
+ else
+ sprintf( collName, "Ix%dD_%dN_%dAF_Set", dim, ntilesObta, faInt);
+ r_Minterval dom( dim );
+ for ( int d = 0; d < dim; d++ )
+ dom[d].set_interval((r_Range)0,'*');
+
+ sprintf( collTypeName, "Char%dDSet", dim);
+ sprintf( mddTypeName, "Char%dD", dim );
+ outPopFile << "Database: BmarkIxBase " << endl << endl;
+ outPopFile << "MDDColl: " << collName << "; " << collTypeName << endl<< endl;
+ outPopFile << "MDDObj: " << dom << " ; " << mddTypeName << endl;
+ outPopFile << "HowToStore:" << endl;
+ outPopFile << "IndexType: R+TreeIx " << endl << endl;
+ if ( randomInsertion )
+ {
+ unsigned vecSz = tgIntsVec->size( );
+ vector< r_Minterval >* tgIntsVec2;
+ tgIntsVec2 = new vector<r_Minterval>(vecSz);
+ unsigned tix = i;
+ for( i = 0; i < vecSz; i++ )
+ {
+ tix = rand( ) % tgIntsVec->size( );
+ outPopFile <<"Tile : "<< " "<< (*tgIntsVec)[tix] << "; 0x0000" << endl;
+ (*tgIntsVec2)[i] = (*tgIntsVec)[tix];
+ tgIntsVec->erase( tgIntsVec->begin( ) + tix );
+ }
+ vector< r_Minterval >* tmpIntsVec;
+ tmpIntsVec = tgIntsVec;
+ tgIntsVec = tgIntsVec2;
+ delete tmpIntsVec;
+ }
+ else
+ {
+ for( i = 0; i < tgIntsVec->size( ); i++ )
+ {
+ outPopFile <<"Tile : "<< " "<< (*tgIntsVec)[i] << "; 0x0000" << endl;
+ }
+ }
+
+ /* For debugging purposes:
+ if( !isDisjunctive( *tgIntsVec ))
+ {
+ cout <<"Error: Nondisjunctive partition, exiting program "<< endl;
+ exit( 0);
+ }
+ else cout <<" Disjunctive partition OK " << endl;
+ */
+
+ if( tgIntsVec->size( ) != numberTiles )
+ {
+ cout <<"Error: tgIntsVec->size( ) != numberTiles "<< endl;
+ // exit( 0);
+ }
+ // calculateAlignFactor( tgIntsVec );
+
+}
+
+/*************************************************************************
+ *
+ *
+ ************************************************************************/
+/*
+void
+createTilesArr( Tile** tiles,
+ float alignFactor,
+ vector< r_Minterval >* tgIntsVec )
+{
+
+ ULongType anyType;
+ char* anyCells;
+
+ for( i = 0; i < tgIntsVec->size( ); i++ )
+ {
+ anyCells = (char*)malloc(tilesDomains[i].cell_count() * anyType.getSize());
+ tiles[i] =
+ new PersTile( (*tgIntsVec)[i], (const BaseType*) &anyType, anyCells);
+ }
+
+}
+*/
+
+/*************************************************************************
+ *
+ *
+ ************************************************************************/
+float
+calculateAlignFactor( const vector<r_Minterval>& part )
+{
+ float fa;
+ // for ( int i = 0; i < part.size( ); i++ ) ;
+
+ return fa;
+}
+
+/*************************************************************************
+ *
+ *
+ ************************************************************************/
+int isDisjunctive( const vector<r_Minterval>& parts )
+{
+ for( int i = 0; i < parts.size( ); i++ )
+ {
+ r_Minterval inter = parts[i];
+ for( int j = i+1; j < parts.size( ); j++ )
+ {
+ if( inter.intersects_with( parts[j] ))
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/*************************************************************
+ * Function name.:
+ * void
+ * testCompareIxs( char* index, char* index1, )
+ *
+ * Arguments.....:
+ * index : name of first index
+ * index1: name of second index
+ *
+ ************************************************************/
+void
+testCompareIxs( )
+{
+ DBMDDObjIxId accessedIndex;
+ CharType anyType;
+ // char anyCell[4];
+ cout << "....testCompareIxs"<<endl;
+
+ // read root object
+ d_List< DBMDDObjIxId > indexList("HierIndexContainer");
+ // used for iterating
+ d_Iterator< DBMDDObjIxId > indexIt = indexList.create_iterator();
+
+ MultiDimIx< Tile >* ix = 0;
+ MultiDimIx< Tile >* ix1 = 0;
+ PersIx* dix;
+ PersIx* dix1;
+
+ for( int i = 1 ; indexIt.not_done(); i++, indexIt.advance())
+ {
+ accessedIndex = indexIt.get_element();
+ cout << " --"<<i<<". index object in list:" << endl;
+ accessedIndex->printStatus();
+ if (accessedIndex->isRoot( ) && accessedIndex->isLeaf( ) )
+ {
+ // to avoid mem leaks in repeated executions of this test program
+ if ( ix1 ) delete ix1;
+ cout << endl << "Creating DirIx ... ";
+ dix1 = new PersDirIx( accessedIndex, (const BaseType*) &anyType );
+ ix1 = new DirIx< PersDirIx, Tile >( (PersDirIx*)dix1 );
+ }
+ else
+ {
+ // to avoid mem leaks in repeated executions of this test program
+ if ( ix ) delete ix;
+ cout << endl << "Creating R+-tree ... ";
+ dix = new PersHierIx( accessedIndex, (const BaseType*) &anyType );
+ ix = new RPlusTreeIx<Tile>( dix,maximumFill );
+ }
+ cout << endl;
+ }
+ cout <<"OK"<<endl;
+
+ const int numInts = 30;
+ r_Minterval searchInts[numInts];
+
+ for( i = 0; i < numInts ; i++ )
+ {
+ r_Range l1= rand( ) % 25; r_Range l2 = rand( ) % 30;
+ searchInts[i] = r_Minterval( 2 );
+ searchInts[i] << r_Sinterval( l1, l1+rand() % 50 );
+ searchInts[i] << r_Sinterval( l2, l2 +rand( ) % 50 );
+
+ /*
+ searchInts[0] = r_Minterval( "[0:100,0:100]");
+ searchInts[1] = r_Minterval( "[150:200,100:250]");
+ searchInts[2] = r_Minterval( "[100:300,250:400]");
+ searchInts[1] = r_Minterval( "[50:100,100:250]");
+ searchInts[1] = r_Minterval( "[50:73,90:94]");
+ */
+ }
+
+ testCompareIxs( "R+-tree ", "DirIx ", ix, ix1, searchInts, numInts);
+
+ delete ix; delete ix1;
+}
+
+/*************************************************************************
+ *
+ *
+ ************************************************************************/
+void
+testCompareIxs( char* index, char* index1,
+ MultiDimIx<Tile>* ix, MultiDimIx<Tile>* ix1,
+ r_Minterval* searchInts, int numInts)
+{
+ cout << "....testCompareIxs"<< endl;
+
+ //ULongType anyType;
+ // char anyCell[4];
+
+
+ cout << "Comparison of Index " << index << endl;
+ cout << "with Index1 " << index1 << endl;
+
+ for( int i = 0; i < numInts; i++ )
+ {
+ Timer time; Timer time1;
+ RMTimer* rtime = new RMTimer( index, "intersect" );
+ RMTimer* rtime1 = new RMTimer( index1, "intersect" );
+
+ cout << "Intersect with "<< searchInts[i] << endl;
+
+ // Index
+ time.start( ); rtime->start( );
+ vector< Tile* >* rqResult = ix->intersect( searchInts[i] );
+ int num, num1;
+ rtime->stop( ); time.stop( );
+ if ( rqResult )
+ {
+ num = rqResult->size( );
+ cout << index << endl << " No. of tiles, time , time/noTiles = "
+ << rqResult->size( ) << " , "<< time << " , ";
+ if ( rqResult->size( ) ) cout << time.ellapsed_sec( )/rqResult->size( ) << endl;
+ }
+ else
+ {
+ cout << "No tiles intersected "<< endl;
+ num = 0;
+ }
+ delete rtime;
+
+ // Index 1
+ time1.start( ); rtime1->start( );
+ vector< Tile* >* rqResult1 = ix1->intersect( searchInts[i] );
+ rtime1->stop( ); time1.stop( );
+ if ( rqResult1 )
+ {
+ num1 = rqResult1->size( );
+ cout << index1 << endl << " No. of tiles, time1, time1/noTiles = "
+ << rqResult1->size( ) << " , "<< time1 << " , ";
+ if ( rqResult1->size( ) ) cout << time1.ellapsed_sec( )/rqResult1->size( ) << endl;
+ }
+ else
+ {
+ cout << "No tiles intersected "<< endl;
+ num1 = 0;
+ }
+ delete rtime1;
+ if ( num != num1 )
+ cout << "Error !!!!" << endl;
+
+ // Index
+ cout << "Result " << index << endl;
+ if ( rqResult )
+ {
+ for( int j = 0; j < rqResult->size( ); j++)
+ {
+ cout << ( *rqResult )[j]->getDomain( ) << endl;
+ delete (*rqResult)[j];
+ }
+ delete rqResult;
+ }
+
+ // Index1
+ cout << "Result " << index1 << endl;
+ if ( rqResult1 )
+ {
+ for( int j = 0; j < rqResult1->size( ); j++)
+ {
+ cout << ( *rqResult1 )[j]->getDomain( ) << endl;
+ delete (*rqResult1)[j];
+ }
+ delete rqResult1;
+ }
+ cout << endl;
+ }
+
+}
diff --git a/indexmgr/transdirix.cc b/indexmgr/transdirix.cc
new file mode 100644
index 0000000..60129c3
--- /dev/null
+++ b/indexmgr/transdirix.cc
@@ -0,0 +1,269 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: transdirix.cc
+ *
+ * MODULE: indexmgr
+ * CLASS: TransDirIx
+ *
+ *
+ * COMMENTS:
+ * none
+ *
+*/
+static const char rcsid[] = "@(#)transdirix, TransDirIx: $Id: transdirix.cc,v 1.17 2002/05/16 16:26:10 coman Exp $";
+
+#include <iostream>
+#include "indexmgr/keyobject.hh"
+#include "indexmgr/transdirix.hh"
+#include "raslib/rmdebug.hh"
+#include "reladminif/oidif.hh"
+#include "tilemgr/tile.hh"
+
+IndexDS*
+TransDirIx::getNewInstance() const
+ {
+ return new TransDirIx(getDimension());
+ }
+
+void
+TransDirIx::freeDS()
+ {
+ }
+
+unsigned int
+TransDirIx::getOptimalSize() const
+ {
+ return 1000;
+ }
+
+unsigned int
+TransDirIx::getDimension() const
+ {
+ return currDomain.dimension();
+ }
+
+bool
+TransDirIx::isPersistent() const
+ {
+ return false;
+ }
+
+TransDirIx::TransDirIx(r_Dimension dim)
+ : currDomain(dim),
+ tiles()
+ {
+ RMDBGONCE(2, RMDebug::module_indexif, "TransDirIx", "TransDirIx() " << (r_Ptr)this);
+ }
+
+void
+TransDirIx::printStatus(unsigned int level, std::ostream& stream) const
+ {
+ stream << "TransDirIx " << currDomain << endl;
+ KeyObjectVector::const_iterator entryIt = tiles.begin();
+
+ int i = 0;
+ while (entryIt != tiles.end())
+ {
+ stream << i << ". " << (*entryIt).getDomain() << endl;
+ entryIt++;
+ i++;
+ }
+ }
+
+void
+TransDirIx::insertObject(const KeyObject& newKeyObject, unsigned int pos)
+ {
+ if (pos < 0 || pos > getSize())
+ {
+ RMInit::logOut << "TransDirIx::insertObject(" << newKeyObject << ", " << pos << ") pos out of range" << endl;
+ throw r_Error(TRANSIENT_INDEX_OUT_OF_BOUNDS);
+ }
+ else {
+ if (tiles.size() == 0)
+ currDomain = newKeyObject.getDomain();
+ else
+ currDomain.closure_with(newKeyObject.getDomain());
+ tiles.insert(tiles.begin() + pos, newKeyObject);
+ }
+ }
+
+bool
+TransDirIx::removeObject(const KeyObject& tileToRemove)
+ {
+ bool found = false;
+ for (KeyObjectVector::iterator iter = tiles.begin(); iter != tiles.end(); iter++)
+ {
+ if ((*iter).getTransObject() == tileToRemove.getTransObject())
+ {
+ found = true;
+ tiles.erase(iter);
+ break;
+ }
+ }
+ return found;
+ }
+
+OId::OIdPrimitive
+TransDirIx::getIdentifier() const
+ {
+ return (OId::OIdPrimitive)(r_Ptr)this;
+ }
+
+void
+TransDirIx::setAssignedDomain(const r_Minterval& newDomain)
+ {
+ currDomain = newDomain;
+ }
+
+
+const KeyObject&
+TransDirIx::getObject(unsigned int pos) const
+ {
+ return tiles[pos];
+ }
+
+r_Minterval
+TransDirIx::getObjectDomain(unsigned int pos) const
+ {
+ return tiles[pos].getDomain();
+ }
+
+void
+TransDirIx::getObjects(KeyObjectVector& objs) const
+ {
+ objs = tiles;
+ }
+
+r_Minterval
+TransDirIx::getCoveredDomain() const
+ {
+ return currDomain;
+ }
+
+unsigned int
+TransDirIx::getSize() const
+ {
+ return tiles.size();
+ }
+
+r_Bytes
+TransDirIx::getTotalStorageSize() const
+ {
+ // size of currDomain field:
+ r_Bytes sz = currDomain.get_storage_size();
+
+ // size of tiles vector
+ // even though the size of each entry summed here corresponds to the
+ // KeyObject, it should be added here since it
+ // is "additional data" stored due to the storage structure adopted.
+ // For each entry (tile), there is a domain specification, a pointer and
+ // an r_Bytes size field:
+ sz += tiles.size() * (currDomain.get_storage_size() + sizeof(KeyObject) + sizeof (r_Bytes));
+
+ return sz;
+ }
+
+TransDirIx::~TransDirIx()
+ {
+ RMDBGENTER(2, RMDebug::module_indexif, "TransDirIx", "~TransDirIx() " << (r_Ptr)this);
+ for (unsigned int i = 0; i < tiles.size(); i++)
+ {
+ delete tiles[i].getTransObject();
+ }
+ RMDBGEXIT(2, RMDebug::module_indexif, "TransDirIx", "~TransDirIx() " << (r_Ptr)this);
+ }
+
+std::vector< r_Minterval* >*
+TransDirIx::getObjectDomains(void) const
+ {
+ std::vector< r_Minterval* >* te = new std::vector< r_Minterval* >();
+ te->reserve(tiles.size());
+ int end = tiles.size();
+ for (int i = 0; i < end; i++)
+ {
+ (*te)[i] = new r_Minterval(tiles[i].getDomain());
+ }
+ return te;
+ }
+
+bool
+TransDirIx::isValid() const
+ {
+ return true;
+ }
+
+bool
+TransDirIx::isUnderFull() const
+ {
+ return false;
+ }
+
+bool
+TransDirIx::isOverFull() const
+ {
+ return false;
+ }
+
+bool
+TransDirIx::isSameAs(const IndexDS* ix) const
+ {
+ if (ix->isPersistent())
+ return false;
+ else
+ if (ix == this)
+ return true;
+ else
+ return false;
+ }
+
+void
+TransDirIx::setObject(const KeyObject& theKey, unsigned int i)
+ {
+ tiles[i] = theKey;
+ }
+
+void
+TransDirIx::setObjectDomain(const r_Minterval& dom, unsigned int i)
+ {
+ tiles[i].setDomain(dom);
+ }
+
+r_Minterval
+TransDirIx::getAssignedDomain(void) const
+ {
+ return currDomain;
+ }
+
+bool
+TransDirIx::removeObject(unsigned int pos)
+ {
+ bool found = false;
+ if (pos < tiles.size())
+ {
+ found = true;
+ tiles.erase(tiles.begin() + pos);
+ }
+ return found;
+ }
+
diff --git a/indexmgr/transdirix.hh b/indexmgr/transdirix.hh
new file mode 100644
index 0000000..f5e829d
--- /dev/null
+++ b/indexmgr/transdirix.hh
@@ -0,0 +1,141 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: transdirix.hh
+ *
+ * MODULE: indexmgr
+ * CLASS: TransDirIx
+ *
+ * COMMENTS:
+ *
+*/
+
+#ifndef _TRANSDIRIX_HH_
+#define _TRANSDIRIX_HH_
+
+#include "indexmgr/indexds.hh"
+#include "reladminif/lists.h"
+
+//@ManMemo: Module: {\bf indexmgr}
+/*@Doc:
+
+A TransDirIx object is the data structure for an index of a transient MDD
+object. It is to be used with DirIndexLogic.
+A transient directory index keeps track of the current domain of the object.
+It is a very simple structure, consisting of the current domain of the object
+and a set of entries, one for each object belonging to the mdd object.
+
+For documentation on methods see IndexDS.
+*/
+
+class TransDirIx : public IndexDS
+ {
+
+ public:
+
+ TransDirIx(r_Dimension dim);
+ /*@Doc:
+ Creates a new transient index for an object with dimensionality
+ {\tt dim}.
+ */
+
+ void printStatus(unsigned int level = 0, std::ostream& stream = std::cout) const;
+
+ void insertObject(const KeyObject& newKeyObject, unsigned int pos);
+ /*@Doc:
+ Inserts a new tile in the index at position {\tt pos}, which must be
+ between 0 and {\tt getNumberElems()} (that is, {\tt pos } is
+ interpreted as an index in the new list. If {\tt pos} is getNumberElems(),
+ the element is put at the end of the list. All elements at following
+ positions are shifted to the right. The new tile to insert ({\tt newKeyObject})
+ must be transient (of type TransKeyObject). The current domain is updated.
+ */
+
+ virtual void setObject(const KeyObject& theKey, unsigned int pos);
+
+ virtual void setObjectDomain(const r_Minterval& dom, unsigned int pos);
+
+ bool removeObject(unsigned int pos);
+
+ bool removeObject(const KeyObject& theKey);
+
+ virtual bool isValid() const;
+
+ virtual bool isUnderFull() const;
+
+ virtual bool isOverFull() const;
+
+ virtual bool isSameAs(const IndexDS* pix) const;
+
+ const KeyObject& getObject(unsigned int pos) const;
+
+ r_Minterval getObjectDomain(unsigned int pos) const;
+
+ DomainPVector* getObjectDomains() const;
+
+ void getObjects(KeyObjectVector&) const;
+
+ r_Minterval getCoveredDomain() const;
+
+ r_Minterval getAssignedDomain() const;
+
+ r_Dimension getDimension() const;
+
+ void setAssignedDomain(const r_Minterval& domain);
+
+ unsigned int getSize() const;
+
+ r_Bytes getTotalStorageSize() const;
+
+ bool isPersistent() const;
+
+ virtual ~TransDirIx();
+ /*@Doc:
+ Destructor - deletes tiles from main memory.
+ */
+
+ virtual unsigned int getOptimalSize() const;
+
+ virtual void freeDS();
+ /*@Doc:
+ does not do anything - there is no persistent data structure
+ */
+
+ virtual OId::OIdPrimitive getIdentifier() const;
+
+ virtual IndexDS* getNewInstance() const;
+ private:
+
+ r_Minterval currDomain;
+ /**
+ Always set automatically to the MBR of the tiles in {\tt tiles}.
+ If the number of tiles is zero, the currDomain is invalid (may have any
+ values). All methods dealing with the currDomain must then check whether
+ the object has tiles in order to operate on the currDomain.
+ */
+
+ KeyObjectVector tiles;
+ };
+
+
+#endif
diff --git a/insertutils/Makefile.am b/insertutils/Makefile.am
new file mode 100644
index 0000000..473f7bf
--- /dev/null
+++ b/insertutils/Makefile.am
@@ -0,0 +1,50 @@
+# -*-Makefile-*-
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+#
+# MAKEFILE FOR:
+# utility programs
+#
+# COMMENTS:
+# - Various insertion-tools for special client data
+#
+##################################################################
+
+AM_CXXFLAGS = $(COMMCXXFLAGS)
+AM_LDFLAGS = $(COMMLDFLAGS)
+bin_PROGRAMS = insertppm
+bin_SCRIPTS = insertdemo.sh
+insertppm_SOURCES=insertppm.cc ../mymalloc/mymalloc_cln.cc
+insertppm_LDADD=../rasodmg/librasodmg.a ../clientcomm/libclientcomm.a \
+ ../compression/libcompression.a ../conversion/libconversion.a \
+ ../raslib/libraslib.a ../rnprotocol/libclientcomm.a \
+ ../network/libnetwork.a
+CLEANFILES = insertdemo.sh
+EXTRA_DIST = insertdemo.sh.in
+
+insertdemo.sh: insertdemo.sh.in Makefile
+ rm -f insertdemo.sh
+ sed -e 's|@bindir[@]|$(bindir)/|g' \
+ -e 's|@pkgdatadir[@]|$(pkgdatadir)/|g'\
+ <insertdemo.sh.in >insertdemo.sh
+ chmod +x insertdemo.sh
+ chmod a-w insertdemo.sh
diff --git a/insertutils/insertdemo.sh.in b/insertutils/insertdemo.sh.in
new file mode 100644
index 0000000..8328b3a
--- /dev/null
+++ b/insertutils/insertdemo.sh.in
@@ -0,0 +1,118 @@
+#!/bin/bash
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+#
+##########################################################################
+#
+# SOURCE: insertdemo.sh
+#
+# PURPOSE:
+# create the demo collections used in the rasdaman manuals.
+# Currently these are: mr, mr2, rgb.
+# Data are taken from the images directory; they are small enough not to
+# eat away remarkable disk space.
+# The script returns a nonzero exit code upon error.
+#
+# COMMENTS:
+# - insertppm needs the ppm library installed.
+#
+#######################################################################
+
+
+# --- parameter evaluation --------------------------------------------
+
+if [ $# != 5 ]
+then
+ echo "Usage: $0 host port imagedir user passwd"
+ echo " host host name of rasdaman server"
+ echo " port port where rasdaman server listens (usually: 7001)"
+ echo " imagedir source image directory"
+ echo " user rasdaman database login name (needs write access)"
+ echo " passwd rasdaman password"
+ echo "Example: $0 localhost 7001 @pkgdatadir@examples/images rasadmin rasadmin"
+ exit 0
+fi
+
+ HOST=$1
+ PORT=$2
+IMAGEDIR=$3
+ USER=$4
+ PASSWD=$5
+
+
+# --- global defines --------------------------------------------------
+
+# script name
+PROG=`basename $0`
+
+# database to be used
+DB=RASBASE
+
+# shorthand: insertppm parameters
+INSERTPPM_ARGS="--server $HOST --port $PORT --database $DB --user $USER --passwd $PASSWD"
+
+# --- check prerequisites ---------------------------------------------
+
+echo "$PROG: rasdaman demo data insert script v2.0"
+echo "$PROG: using host $HOST, image directory $IMAGEDIR, and user/passwd $USER/$PASSWD"
+
+# --- evaluate cmd line parameters ------------------------------------
+
+# is insertppm compiled already?
+if [ -f @bindir@insertppm ]
+then
+ INSERTPPM="@bindir@insertppm"
+else
+ echo "$PROG: insertppm not found. Trying to compile it...\c"
+ make --directory=@pkgdatadir@examples/c++ insertppm
+ if [ -f @pkgdatadir@examples/c++/insertppm ]
+ then
+ echo "ok"
+ INSERTPPM="@pkgdatadir@examples/c++/insertppm"
+ else
+ echo "$PROG: Error: Failed to compile insertppm."
+ exit 1
+ fi
+fi
+
+# does $IMAGEDIR point to a good directory?
+if [ ! -d $IMAGEDIR ]
+then
+ echo "$PROG: Illegal package path $IMAGEDIR."
+ exit 1
+fi
+
+# insert packages
+echo -n "mr..."
+for i in $IMAGEDIR/mr_?.pgm;
+do
+ $INSERTPPM $INSERTPPM_ARGS --type grey --collection mr $i || exit 1
+done
+echo -n "mr2..."
+$INSERTPPM $INSERTPPM_ARGS --type grey --collection mr2 $IMAGEDIR/mr_1.pgm || exit 1
+echo -n "rgb..."
+$INSERTPPM $INSERTPPM_ARGS --type color --collection rgb $IMAGEDIR/anthur.ppm || exit 1
+
+echo "$PROG: done."
+
+# end of insertdemo.sh
+
diff --git a/insertutils/insertppm.cc b/insertutils/insertppm.cc
new file mode 100644
index 0000000..37e6e6f
--- /dev/null
+++ b/insertutils/insertppm.cc
@@ -0,0 +1,859 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: insertppm.cc
+ *
+ * MODULE: insertutils
+ *
+ * PURPOSE:
+ * read one or more ppm image file(s) and create a rasdaman
+ * object out of its contents.
+ * If one file is provided, then a 2-D object will be generated.
+ * If several files are provided then a 3-D object will be
+ * generated; to this end, all files have to agree on pixel
+ * type and x/y extent.
+ * If the collection doesn't exist previously, it is created.
+ * If it does exist, new objects will be created in it
+ * (obviously requiring thet the collection type is appropriate).
+ *
+ * COMMENTS:
+ * - Has to be compiled with the following options:
+ *
+ * -D__STDC__ -DSYSV -I/usr/local/dist/include
+ * -L/usr/local/dist/lib -lppm -lpgm -lpbm
+ *
+ * The defines are necessary so that HP CC can understand the
+ * ppm.h include correctly.
+ * - needs PPM package installed.
+ *
+*/
+
+static const char rcsid[] = "@(#)cachetamgr,readppm: $Header: /home/rasdev/CVS-repository/rasdaman/insertutils/insertppm.cc,v 1.67 2006/01/17 07:36:25 rasdev Exp $";
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#ifdef __GNUG__
+#include "raslib/template_inst.hh"
+#endif
+#endif
+
+using namespace std;
+
+#include <iostream>
+#include <fstream>
+#include <iomanip>
+#include <sstream>
+#include <stdlib.h>
+#include <getopt.h>
+#include <list>
+
+#include "raslib/rminit.hh"
+#include "rasodmg/marray.hh"
+#include "rasodmg/ref.hh"
+#include "rasodmg/set.hh"
+#include "rasodmg/database.hh"
+#include "rasodmg/partinsert.hh"
+#include "raslib/type.hh"
+#include "raslib/odmgtypes.hh"
+#include "raslib/error.hh"
+
+// this is for inhouse debug macros; not needed for standalone compilation
+#ifdef RMANDEBUG || DEBUG
+ #define DEBUG_MAIN
+ #include "debug.hh"
+#endif
+
+extern "C" {
+ #include <ppm.h>
+}
+
+// program exit codes:
+#define EXIT_OK 0
+#define EXIT_ERROR -1
+#define EXIT_USAGE -2
+
+// pixel type names
+#define PIXEL_TYPE_BOOL "bin"
+#define PIXEL_TYPE_GREY "grey"
+#define PIXEL_TYPE_COLOR "color"
+
+// pixel sizes in byte:
+#define PIXSIZE_BW sizeof(char)
+#define PIXSIZE_GREY sizeof(char)
+#define PIXSIZE_COL sizeof(RGBPixel)
+
+// internal pixel type indicator
+typedef enum
+{
+ PIXEL_BOOL,
+ PIXEL_GREY,
+ PIXEL_COLOR
+} PixelType;
+
+// the color image type:
+typedef struct {
+ unsigned char red, green, blue;
+} RGBPixel;
+
+// --- default values --------------------------------------------
+#define DEFAULT_TYPE "color"
+#define DEFAULT_PORT "7001"
+#define DEFAULT_HOST "localhost"
+#define DEFAULT_USER "rasguest"
+#define DEFAULT_PASSWD "rasguest"
+#define DEFAULT_VERBOSE false
+#define DEFAULT_DB "RASBASE"
+#define DEFAULT_TR_FMT "Array"
+#define DEFAULT_ST_FMT "Array"
+#define DEFAULT_TILE_LO 0
+#define DEFAULT_TILE_HI 31
+#define DEFAULT_PIXSIZE PIXSIZE_COL
+#define DEFAULT_PIXEL_TYPE PIXEL_COLOR
+
+// --- options --------------------------------------------
+// long option names
+#define OPTION_HELP "help"
+#define OPTION_COLLECTION "collection"
+#define OPTION_TYPE "type"
+#define OPTION_RESCALE "rescale"
+#define OPTION_TILE "tiled"
+#define OPTION_SERVER "server"
+#define OPTION_PORT "port"
+#define OPTION_DATABASE "database"
+#define OPTION_USER "user"
+#define OPTION_PASSWD "passwd"
+#define OPTION_TRANSFERFORMAT "transferformat"
+#define OPTION_TRANSFERFORMATPARAMS "transferformatparams"
+#define OPTION_STORAGEFORMAT "storageformat"
+#define OPTION_STORAGEFORMATPARAMS "storageformatparams"
+#define OPTION_VERBOSE "verbose"
+
+// long option descriptor
+static struct option long_options[] =
+{
+ { OPTION_HELP, 0, 0, 0 },
+ { OPTION_COLLECTION, 1, 0, 0 },
+ { OPTION_TYPE, 1, 0, 0 },
+ { OPTION_RESCALE, 0, 0, 0 },
+ { OPTION_TILE, 1, 0, 0 },
+ { OPTION_SERVER, 1, 0, 0 },
+ { OPTION_PORT, 1, 0, 0 },
+ { OPTION_DATABASE, 1, 0, 0 },
+ { OPTION_USER, 1, 0, 0 },
+ { OPTION_PASSWD, 1, 0, 0 },
+ { OPTION_TRANSFERFORMAT, 1, 0, 0 },
+ { OPTION_TRANSFERFORMATPARAMS, 1, 0, 0 },
+ { OPTION_STORAGEFORMAT, 1, 0, 0 },
+ { OPTION_STORAGEFORMATPARAMS, 1, 0, 0 },
+ { OPTION_VERBOSE, 0, 0, 0 },
+ { 0, 0, 0, 0 }
+};
+
+// short option descriptor
+const char *short_options = "hc:t:rs:d:u:p:v";
+
+// --- verbose output --------------------------------------------
+// verbosity flag
+static bool verbose = DEFAULT_VERBOSE;
+
+// conditional log output
+#define LOG if (verbose) cerr
+
+// --- globals --------------------------------------------
+// global variables to make readRow work (not nice, I know)
+static FILE* readppm_fp=NULL;
+static int readppm_colsP=0; // number of columns
+static int readppm_rowsP=0; // number of rows
+static pixval readppm_maxvalP=0; // maximum pixel value (-> pixel depth)
+static int readppm_formatP=0;
+
+// --- functions --------------------------------------------
+
+/*
+ * calculate size of image
+ * for a 3D image, numSlices is used to determine the z axis extent
+ * preconditions:
+ * - fname!=NULL, \0 terminated
+ * - imgSize contains valid 2D or 3D minterval, depending on mdd3d
+ */
+r_Minterval readHeader( const char *fName, bool mdd3d, unsigned int numSlices )
+{
+ FILE* fp=NULL;
+ int colsP=0; // number of columns
+ int rowsP=0; // number of row
+ pixval maxvalP=0; // maximum pixel value (-> pixel depth)
+ int formatP=0;
+ r_Minterval result;
+
+ // check if the file exists (pm_openr() just dumps on error, leaving db open)
+ std::fstream inFile( fName, std::ios::in );
+ if(!inFile)
+ {
+ cerr << "Error: cannot find input file " << fName << endl;
+ throw r_Error( r_Error::r_Error_General );
+ }
+
+ fp = pm_openr( fName );
+ if(!fp)
+ {
+ cerr << "Error: cannot find input file " << fName << endl;
+ throw r_Error( r_Error::r_Error_General );
+ }
+
+ // initialize colsP and rowsP to create MDD
+ ppm_readppminit( fp, &colsP, &rowsP, &maxvalP, &formatP );
+ pm_close(fp);
+
+ if(mdd3d)
+ {
+ // domain of MDD
+ result = r_Minterval(3)
+ << r_Sinterval((r_Range)0, (r_Range)(numSlices - 1))
+ << r_Sinterval((r_Range)0, (r_Range)(colsP - 1))
+ << r_Sinterval((r_Range)0, (r_Range)(rowsP - 1));
+ }
+ else
+ {
+ // domain of MDD
+ result = r_Minterval(2)
+ << r_Sinterval((r_Range)0, (r_Range)colsP - 1)
+ << r_Sinterval((r_Range)0, (r_Range)rowsP - 1);
+ }
+
+ LOG << "header says: " << result << endl;
+ return result;
+}
+
+/*
+ * read one image file
+ * preconditions:
+ * - fname!=NULL, \0 terminated
+ */
+void readImage(char* contents, const char *fName, bool mdd3d, PixelType pixType, bool rescale, r_Range slicenum = 0, r_Range slicepos = 0 ) throw (r_Error)
+{
+ FILE* fp=NULL; // input image file
+ int colsP=0; // number of columns
+ int rowsP=0; // number of rows
+ pixval maxvalP; // maximum pixel value (-> pixel depth)
+ pixel** pixelsP=NULL; // all pixels in the image
+ pixel aPixel; // one pixel
+ pixel scaledPixel; // pixel scaled to 0 to 255
+
+ // open PPM file
+ fp = pm_openr(fName);
+ if(!fp)
+ {
+ cerr << "iError: cannot find input file " << fName << endl;
+ throw r_Error( r_Error::r_Error_General );
+ }
+
+ // read it (also initializes information about picture)
+ pixelsP = ppm_readppm( fp, &colsP, &rowsP, &maxvalP );
+
+ // iterate through all pixels
+ int i=0, j=0;
+ for(i = 0; i < rowsP; i++)
+ {
+ for(j = 0; j < colsP; j++)
+ {
+ // read pixel
+ aPixel = pixelsP[i][j];
+
+ // scale pixel to 0-255
+ if(rescale)
+ PPM_DEPTH( scaledPixel, aPixel, maxvalP, 255 );
+ else
+ scaledPixel = aPixel;
+
+ switch (pixType)
+ {
+ case PIXEL_BOOL:
+ contents[(slicepos*colsP*rowsP + j*rowsP + i)*PIXSIZE_BW] = PPM_GETB( scaledPixel ) == 0 ? 0 : 1;
+ break;
+ case PIXEL_GREY: // create Char out of pixel (just take blue)
+ contents[(slicepos*colsP*rowsP + j*rowsP + i)*PIXSIZE_GREY] = PPM_GETB( scaledPixel );
+ break;
+ case PIXEL_COLOR: // create ULong out of pixel colors
+ contents[(slicepos*colsP*rowsP + j*rowsP + i)*PIXSIZE_COL + 0] = PPM_GETR( scaledPixel );
+ contents[(slicepos*colsP*rowsP + j*rowsP + i)*PIXSIZE_COL + 1] = PPM_GETG( scaledPixel );
+ contents[(slicepos*colsP*rowsP + j*rowsP + i)*PIXSIZE_COL + 2] = PPM_GETB( scaledPixel );
+ break;
+ default:
+ cerr << "Error: unknown pixel type code: " << pixType << endl;
+ break;
+ }
+ }
+ }
+
+ // close PPM and free memory
+ pm_close(fp);
+ ppm_freearray( pixelsP, rowsP );
+}
+
+/*
+ * open the image file; no reading is done
+ * preconditions:
+ * - fname!=NULL, \0 terminated
+ */
+void openImage( const char *fName, bool mdd3d )
+{
+ // open PPM file
+ readppm_fp = pm_openr( fName );
+ if(!readppm_fp)
+ {
+ cerr << "Error: cannot find input file " << fName << endl;
+ throw r_Error( r_Error::r_Error_General );
+ }
+
+ ppm_readppminit( readppm_fp, &readppm_colsP, &readppm_rowsP, &readppm_maxvalP, &readppm_formatP );
+}
+
+/*
+ * read numRows rows in an image file
+ */
+void readRows(char* contents, r_Range startRow, r_Range numRows, PixelType pixType, bool rescale)
+{
+ pixel aPixel; // one pixel
+ pixel scaledPixel; // pixel scaled to range 0..255
+ pixel* row=NULL; // all pixels in one row
+ unsigned int currRow=0; // current row #
+
+ row = new pixel[readppm_colsP];
+
+ for(currRow = 0; currRow < numRows; currRow++)
+ {
+ // read a row
+ ppm_readppmrow(readppm_fp, row, readppm_colsP, readppm_maxvalP, readppm_formatP);
+
+ // iterate through all pixels in this row
+ for( int i = 0; i < readppm_colsP; i++ )
+ {
+ // read pixel
+ aPixel = row[i];
+
+ // scale pixel to 0-255
+ if(rescale)
+ PPM_DEPTH( scaledPixel, aPixel, readppm_maxvalP, 255 );
+ else
+ scaledPixel = aPixel;
+
+ switch (pixType)
+ {
+ case PIXEL_BOOL:
+ contents[(i*numRows + currRow)*PIXSIZE_BW] = (PPM_GETB(scaledPixel)==0) ? 0 : 1;
+ break;
+ case PIXEL_GREY: // create Bool out of pixel (just take blue)
+ contents[(i*numRows + currRow)*PIXSIZE_GREY] = PPM_GETB( scaledPixel );
+ break;
+ case PIXEL_COLOR: // create ULong out of pixel colors
+ contents[(i*numRows + currRow)*PIXSIZE_COL + 0] = PPM_GETR( scaledPixel );
+ contents[(i*numRows + currRow)*PIXSIZE_COL + 1] = PPM_GETG( scaledPixel );
+ contents[(i*numRows + currRow)*PIXSIZE_COL + 2] = PPM_GETB( scaledPixel );
+ break;
+ default:
+ cerr << "Error: unknown pixel type code: " << pixType << endl;
+ break;
+ }
+ }
+ }
+
+ delete [] row;
+ row=NULL;
+}
+
+/*
+ * create a transient mdd with domain dom
+ */
+void createMarray(const r_Minterval &dom, r_Ref<r_GMarray> &mddPtr, PixelType pixType)
+{
+ switch (pixType)
+ {
+ case PIXEL_BOOL:
+ LOG << "creating MDD of type bool and extent " << dom << endl;
+ mddPtr = (r_GMarray*)(new r_Marray<r_Boolean>(dom));
+ break;
+ case PIXEL_GREY: // create Bool out of pixel (just take blue)
+ LOG << "creating MDD of type grey and extent " << dom << endl;
+ mddPtr = (r_GMarray*)(new r_Marray<r_Char>(dom));
+ break;
+ case PIXEL_COLOR: // create ULong out of pixel colors
+ LOG << "creating MDD of type color and extent " << dom << endl;
+ mddPtr = (r_GMarray*)(new r_Marray<RGBPixel>(dom));
+ break;
+ default:
+ cerr << "Error: unknown pixel type code: " << pixType << endl;
+ break;
+ }
+}
+
+
+/*
+ * print usage text, using program name 'name'
+ * preconditions:
+ * - name != NULL, name \0 terminated
+ */
+void
+printUsage(const char* name)
+{
+ cout << "Usage: " << name << " [-h|--help|-c <name>|--collection <name>] [options] files..." << endl;
+ cout << "Options:"<< endl;
+ cout << " -h, --help this help" << endl;
+ cout << " -c, --collection <name> collection to store image; will be created if nonexistent (required)" << endl;
+ cout << " -t, --type <t> store as pixel type t where t is one of: bin, grey, color (default: " << DEFAULT_TYPE << ")" << endl;
+ cout << " -r, --rescale rescale pixel values to 8 bit = 0:255 (default: no rescale)" << endl;
+ cout << " --tiled <t> store object in tiles of size t where t = [min0:max0,min1:max1,...,minn:maxn] (default: 1 tile)" << endl;
+ cout << " -s, --server <name> server host (default: " << DEFAULT_HOST << ")" << endl;
+ cout << " --port <p> server port (default: " << DEFAULT_PORT << ")" << endl;
+ cout << " -d, --database <name> database name (default: " << DEFAULT_DB << ")" << endl;
+ cout << " -u, --user <name> user name (default: " << DEFAULT_USER << ")" << endl;
+ cout << " -p, --passwd <passwd> password (default: " << DEFAULT_PASSWD << ")" << endl << endl;
+ cout << " --transferformat <fmt> transfer format. default: " << DEFAULT_TR_FMT << ")" << endl;
+ cout << " --transferformatparams <params> transfer format parameters.(default: '')" << endl;
+ cout << " --storageformat <fmt> storage format (default: " << DEFAULT_ST_FMT << ")" << endl;
+ cout << " --storageformatparams <params> storage format parameters.(default: '')" << endl;
+ cout << " -v, --verbose be verbose (default: be brief)" << endl;
+ cout << "Note: If one file is passed, then a 2D object will be generated. " << endl
+ << " If several files are passed, then a 3D object will be generated (in the sequence passed)," << endl
+ << " In this case all files must have same pixel type and x/y extent." << endl;
+}
+
+int
+main( int argc, char** argv )
+{
+ const char *prog = argv[0]; // our name
+ int retval = EXIT_OK; // program exit code
+
+ PixelType pixType = DEFAULT_PIXEL_TYPE; // image pixel type
+ const char *typeString = DEFAULT_TYPE; // image pixel type
+ r_Bytes typeSize=DEFAULT_PIXSIZE; // pixel size [bytes]
+ const char *tileString = NULL; // transfer format string
+ const char *transferFormatString = DEFAULT_TR_FMT; // transfer format string
+ r_Data_Format transferFormat=r_Array; // transfer format used
+ const char *transferFormatParams = ""; // transfer format parameters
+ const char *storageFormatString = DEFAULT_ST_FMT; // storage format string
+ r_Data_Format storageFormat=r_Array; // storage format used
+ char *storageFormatParams = ""; // storage format parameters
+
+ const char *collName=NULL; // name of collection
+
+ r_Minterval imgSize; // size of image
+ r_Minterval tileSize; // size of tiles
+
+ const char *dbName=DEFAULT_DB; // name of database
+ const char *serverName=DEFAULT_HOST; // name of RasDaMan server host
+ const char *serverPortString = DEFAULT_PORT; // string parameter for port
+ unsigned int serverPort=0; // port of RasDaMan server
+ const char *userName=DEFAULT_USER; // name of RasDaMan user
+ const char *passwd=DEFAULT_PASSWD; // password of RasDaMan user
+
+ list<string> fileNameList; // input file name list
+
+ bool mdd3d = false; // flag for 3D MDD
+ bool tiled = false; // flag for tiling
+ bool rescale = false; // flag for rescaling pixel values to 0:255
+
+ r_Database database; // rasdaman database object, for connection
+
+ // --- collect cmd line parameters --------------------------------------------------
+
+ int c;
+ int digit_optind = 0;
+
+ if (argc==1) // no params at all?
+ {
+ printUsage( prog );
+ return EXIT_USAGE;
+ }
+
+ while (1)
+ {
+ int this_option_optind = optind ? optind : 1;
+ int option_index = 0;
+
+ c = getopt_long (argc, argv, short_options, long_options, &option_index);
+ if (c == -1)
+ break;
+
+ switch (c)
+ {
+ case 0: // long option
+ if (strcmp(long_options[option_index].name,OPTION_HELP)==0)
+ {
+ printUsage( prog );
+ return EXIT_USAGE;
+ }
+ else if (strcmp(long_options[option_index].name,OPTION_COLLECTION)==0)
+ collName = optarg;
+ else if (strcmp(long_options[option_index].name,OPTION_TYPE)==0)
+ typeString = optarg;
+ else if (strcmp(long_options[option_index].name,OPTION_RESCALE)==0)
+ rescale = true;
+ else if (strcmp(long_options[option_index].name,OPTION_TILE)==0)
+ tileString = optarg;
+ else if (strcmp(long_options[option_index].name,OPTION_SERVER)==0)
+ serverName = optarg;
+ else if (strcmp(long_options[option_index].name,OPTION_PORT)==0)
+ serverPortString = optarg;
+ else if (strcmp(long_options[option_index].name,OPTION_DATABASE)==0)
+ dbName = optarg;
+ else if (strcmp(long_options[option_index].name,OPTION_USER)==0)
+ userName = optarg;
+ else if (strcmp(long_options[option_index].name,OPTION_PASSWD)==0)
+ passwd = optarg;
+ else if (strcmp(long_options[option_index].name,OPTION_TRANSFERFORMAT)==0)
+ transferFormatString = optarg;
+ else if (strcmp(long_options[option_index].name,OPTION_TRANSFERFORMATPARAMS)==0)
+ transferFormatParams = optarg;
+ else if (strcmp(long_options[option_index].name,OPTION_STORAGEFORMAT)==0)
+ storageFormatString = optarg;
+ else if (strcmp(long_options[option_index].name,OPTION_STORAGEFORMATPARAMS)==0)
+ storageFormatParams = optarg;
+ else if (strcmp(long_options[option_index].name,OPTION_VERBOSE)==0)
+ verbose = true;
+ else
+ {
+ cerr << "Error: invalid option: " << long_options[option_index].name << endl;
+ return EXIT_ERROR;
+ }
+ break;
+
+ case 'h':
+ printUsage( prog );
+ return EXIT_USAGE;
+ break;
+ case 'c':
+ if (!optarg)
+ {
+ cerr << "Error: missing collection name." << endl;
+ return EXIT_ERROR;
+ }
+ collName = optarg;
+ break;
+ case 't':
+ if (!optarg)
+ {
+ cerr << "Error: missing type." << endl;
+ return EXIT_ERROR;
+ }
+ typeString = optarg;
+ break;
+ case 'r':
+ rescale = true;
+ break;
+ case 's':
+ if (!optarg)
+ {
+ cerr << "Error: missing server name." << endl;
+ return EXIT_ERROR;
+ }
+ serverName = optarg;
+ break;
+ case 'd':
+ if (!optarg)
+ {
+ cerr << "Error: missing database name." << endl;
+ return EXIT_ERROR;
+ }
+ dbName = optarg;
+ break;
+ case 'u':
+ if (!optarg)
+ {
+ cerr << "Error: missing user name." << endl;
+ return EXIT_ERROR;
+ }
+ userName = optarg;
+ break;
+ case 'p':
+ if (!optarg)
+ {
+ cerr << "Error: missing password." << endl;
+ return EXIT_ERROR;
+ }
+ passwd = optarg;
+ break;
+ case 'v':
+ verbose = true;
+ break;
+ default:
+ printf ("Error: illegal option letter %c\n", c);
+ break;
+ }
+ } // while
+
+ // get non-option arguments (ie, file names)
+ if (optind < argc)
+ {
+ while (optind < argc)
+ fileNameList.push_back(string(argv[optind++]));
+ mdd3d = (fileNameList.size() > 1);
+ }
+ else
+ {
+ cerr << "Error: no input file name provided." << endl;
+ return EXIT_ERROR;
+ }
+
+ // check mandatory parameters
+ if (collName==NULL)
+ {
+ cerr << "Error: missing collection name; use option '--" << OPTION_COLLECTION << "'." << endl;
+ return EXIT_ERROR;
+ }
+
+ // transform parameters where necessary
+ serverPort = strtol(serverPortString, (char **)NULL, 10);
+ if (errno==ERANGE || errno==EINVAL)
+ {
+ cerr << "Error: port not an integer number: " << serverPortString << endl;
+ return EXIT_ERROR;
+ }
+ if( tileString )
+ {
+ try
+ {
+ tileSize = r_Minterval(tileString);
+ tiled = true;
+ }
+ catch (r_Error e)
+ {
+ cerr << "Error " << e.get_errorno() << ": " << e.what() << endl;
+ return EXIT_ERROR;
+ }
+ }
+ else
+ {
+ // use default tile sizes
+ if(mdd3d)
+ tileSize = r_Minterval(3)
+ << r_Sinterval((r_Range)DEFAULT_TILE_LO, (r_Range)DEFAULT_TILE_HI)
+ << r_Sinterval((r_Range)DEFAULT_TILE_LO, (r_Range)DEFAULT_TILE_HI)
+ << r_Sinterval((r_Range)DEFAULT_TILE_LO, (r_Range)DEFAULT_TILE_HI);
+ else
+ tileSize = r_Minterval(2)
+ << r_Sinterval((r_Range)DEFAULT_TILE_LO, (r_Range)DEFAULT_TILE_HI)
+ << r_Sinterval((r_Range)DEFAULT_TILE_LO, (r_Range)DEFAULT_TILE_HI);
+ LOG << "tileSize = " << tileSize << endl;
+ }
+ transferFormat = get_data_format_from_name( transferFormatString );
+ if(transferFormat == r_Data_Format_NUMBER)
+ {
+ cerr << "Error: Invalid transfer format '" << transferFormatString << "'" << endl;
+ return EXIT_ERROR;
+ }
+ storageFormat = get_data_format_from_name( storageFormatString );
+ if(storageFormat == r_Data_Format_NUMBER)
+ {
+ cerr << "Error: Invalid storage format '" << storageFormatString << "'" << endl;
+ return EXIT_ERROR;
+ }
+ if (typeString!=NULL)
+ {
+ if (strcmp(typeString,PIXEL_TYPE_BOOL)==0)
+ pixType = PIXEL_BOOL;
+ else if (strcmp(typeString,PIXEL_TYPE_GREY)==0)
+ pixType = PIXEL_GREY;
+ else if (strcmp(typeString,PIXEL_TYPE_COLOR)==0)
+ pixType = PIXEL_COLOR;
+ else
+ {
+ cerr << "Error: illegal pixel type: " << typeString << endl;
+ return EXIT_ERROR;
+ }
+ }
+
+ LOG << prog << " v2.0 rasdaman PPM image insert utility" << endl;
+
+ LOG << OPTION_COLLECTION << " = " << collName << ", ";
+ LOG << OPTION_TYPE << " = " << typeString << ", ";
+ LOG << "3d = " << mdd3d << ", ";
+ LOG << OPTION_RESCALE << " = " << rescale << ", ";
+ LOG << OPTION_TILE << " = " << tileSize << endl;
+ LOG << OPTION_SERVER << " = " << serverName << ", ";
+ LOG << OPTION_PORT << " = " << serverPort << ", ";
+ LOG << OPTION_DATABASE << " = " << dbName << ", ";
+ LOG << OPTION_USER << " = " << userName << ", ";
+ LOG << OPTION_PASSWD << " = " << passwd << endl;
+ LOG << OPTION_TRANSFERFORMAT << " = " << transferFormatString << ", ";
+ LOG << OPTION_TRANSFERFORMATPARAMS << " = " << transferFormatParams << ", ";
+ LOG << OPTION_STORAGEFORMAT << " = " << storageFormatString << ", ";
+ LOG << OPTION_STORAGEFORMATPARAMS << " = " << storageFormatParams << endl;
+ LOG << OPTION_VERBOSE << " = " << verbose << endl;
+ LOG << "file list = " ;
+ for ( list<string>::iterator from = fileNameList.begin(); from != fileNameList.end(); ++from )
+ LOG << *from << " ";
+ LOG << endl;
+
+ // --- action --------------------------------------------------
+ try
+ {
+ LOG << "connecting to " << serverName << ":" << serverPort << "..." << flush;
+ database.set_servername(serverName, serverPort);
+ database.set_useridentification(userName, passwd);
+ database.open( dbName );
+ // note: partial insert implicitly opens/closes TA
+
+ // determine MDD object's parameters
+ const char *mddTypeName=NULL;
+ const char *collTypeName=NULL;
+ switch (pixType)
+ {
+ case PIXEL_BOOL:
+ collTypeName = mdd3d ? "BoolSet3" : "BoolSet";
+ mddTypeName = mdd3d ? "BoolCube" : "BoolImage";
+ typeSize = PIXSIZE_BW;
+ break;
+ case PIXEL_GREY:
+ collTypeName = mdd3d ? "GreySet3" : "GreySet";
+ mddTypeName = mdd3d ? "GreyCube" : "GreyImage";
+ typeSize = PIXSIZE_GREY;
+ break;
+ case PIXEL_COLOR:
+ collTypeName = mdd3d ? "RGBSet3" : "RGBSet";
+ mddTypeName = mdd3d ? "RGBCube" : "RGBImage";
+ typeSize = PIXSIZE_COL;
+ break;
+ default:
+ cerr << "Error: unknown pixel type code: " << pixType << endl;
+ throw r_Error( r_Error::r_Error_General );
+ }
+ LOG << "mdd type = " << mddTypeName << ", set type = " << collTypeName << endl;
+
+ // read header information for imgSize
+ imgSize = readHeader(fileNameList.front().c_str(),mdd3d, fileNameList.size()); // we know we have at least 1 elem in list
+ if(!tiled)
+ tileSize = imgSize; // if not tiled then tile size = image size
+
+ // Create a partial insert object with regular tiling
+ r_Partial_Insert pins(database, collName, mddTypeName, collTypeName, tileSize, typeSize);
+
+ r_Ref<r_GMarray> mddPtr;
+ r_Minterval cacheDom;
+
+ // iterate through all the pictures
+ if(mdd3d)
+ {
+ cout << "creating 3D object of extent " << imgSize << " from: " << flush;
+
+ r_Range numImgs = imgSize[0].high()+1; // X
+ r_Range imgRows = imgSize[2].high()+1; // Y
+ r_Range imgCols = imgSize[1].high()+1; // Z
+ r_Range tileX = tileSize[0].high()+1;
+
+ // create domain of first cache
+ cacheDom = r_Minterval(3) << r_Sinterval((r_Range)0, tileX - 1)
+ << r_Sinterval((r_Range)0, imgCols - 1)
+ << r_Sinterval((r_Range)0, imgRows - 1);
+
+ createMarray(cacheDom, mddPtr, pixType);
+ char *contents = mddPtr->get_array();
+
+ unsigned int k = 0;
+ list<string>::iterator currentFileName = fileNameList.begin();
+ while ( k < fileNameList.size() )
+ {
+ cout << (*currentFileName).c_str() << "..." << flush;
+ LOG << "#" << k << " " << cacheDom << "..." << flush;
+
+ readImage(contents, (*currentFileName).c_str(), true, pixType, rescale, k, k%tileX);
+
+ if (k % tileX == tileX-1 || k == fileNameList.size()-1)
+ {
+ if (pins.update(mddPtr.ptr(), transferFormat, transferFormatParams, storageFormat, storageFormatParams) != 0)
+ throw r_Error( r_Error::r_Error_General );
+
+ mddPtr.destroy();
+
+ // we are done:
+ if(k == fileNameList.size()-1)
+ break;
+
+ // create domain of next tile
+ cacheDom = r_Minterval(3)
+ << r_Sinterval( (r_Range) (k + 1),
+ (r_Range) (k+tileX > fileNameList.size()-1 ? fileNameList.size()-1 : k+tileX) )
+ << r_Sinterval((r_Range)0, imgCols - 1)
+ << r_Sinterval((r_Range)0, imgRows - 1);
+
+ createMarray(cacheDom, mddPtr, pixType);
+ const char *contents = mddPtr->get_array();
+ }
+
+ ++currentFileName, ++k;
+ }
+ }
+ else
+ {
+ r_Range imgCols = imgSize[0].high()+1;
+ r_Range imgRows = imgSize[1].high()+1;
+ r_Range tileRows = tileSize[0].high()+1;
+ const char *fName = fileNameList.front().c_str(); // we know we have 1 element in list
+
+ cout << "creating 3D object of extent " << imgSize << " from " << fName << "..." << flush;
+
+ openImage(fName,false); // open image for reading
+
+ for( int k = 0; k < imgRows; k += tileRows )
+ {
+ // create domain of next tile
+ cacheDom = r_Minterval(2)
+ << r_Sinterval((r_Range)0, imgCols - 1)
+ << r_Sinterval(k, k + min(tileRows-1, imgRows-k-1));
+
+ LOG << "#" << k << " " << cacheDom << "..." << flush;
+
+ createMarray(cacheDom, mddPtr, pixType);
+ char *contents = mddPtr->get_array();
+
+ readRows(contents, k, min(tileRows, imgRows - k), pixType, rescale);
+
+ if (pins.update(mddPtr.ptr(), transferFormat, transferFormatParams, storageFormat, storageFormatParams) != 0)
+ throw r_Error( r_Error::r_Error_General );
+
+ mddPtr.destroy();
+ }
+ }
+ database.close();
+
+ cout << "ok" << endl;
+ }
+ catch(r_Error &err)
+ {
+ cerr << err.what() << endl;
+ // emergency abort/close, ignoring any eventual further exception
+ try
+ {
+ database.close();
+ }
+ catch(...)
+ { }
+ retval = EXIT_ERROR;
+ }
+ catch (...)
+ {
+ cout << "Panic: unexpected exception." << endl;
+ }
+
+ LOG << argv[0] << " done." << endl;
+ return retval;
+}
diff --git a/insertutils/test/test_insertppm.log b/insertutils/test/test_insertppm.log
new file mode 100644
index 0000000..e9f7c29
--- /dev/null
+++ b/insertutils/test/test_insertppm.log
@@ -0,0 +1,70 @@
+./test_insertppm.sh: testing insertppm start
+Usage: ../insertppm [-h|--help|-c <name>|--collection <name>] [options] files...
+Options:
+ -h, --help this help
+ -c, --collection <name> collection to store image; will be created if nonexistent (required)
+ -t, --type <t> store as pixel type t where t is one of: bin, grey, color (default: color)
+ -r, --rescale rescale pixel values to 8 bit = 0:255 (default: no rescale)
+ --tiled <t> store object in tiles of size t where t = [min0:max0,min1:max1,...,minn:maxn] (default: 1 tile)
+ -s, --server <name> server host (default: localhost)
+ --port <p> server port (default: 7001)
+ -d, --database <name> database name (default: RASBASE)
+ -u, --user <name> user name (default: rasguest)
+ -p, --passwd <passwd> password (default: rasguest)
+
+ --transferformat <fmt> transfer format. default: Array)
+ --transferformatparams <params> transfer format parameters.(default: '')
+ --storageformat <fmt> storage format (default: Array)
+ --storageformatparams <params> storage format parameters.(default: '')
+ -v, --verbose be verbose (default: be brief)
+Note: If one file is passed, then a 2D object will be generated.
+ If several files are passed, then a 3D object will be generated (in the sequence passed),
+ In this case all files must have same pixel type and x/y extent.
+exit code 254
+Usage: ../insertppm [-h|--help|-c <name>|--collection <name>] [options] files...
+Options:
+ -h, --help this help
+ -c, --collection <name> collection to store image; will be created if nonexistent (required)
+ -t, --type <t> store as pixel type t where t is one of: bin, grey, color (default: color)
+ -r, --rescale rescale pixel values to 8 bit = 0:255 (default: no rescale)
+ --tiled <t> store object in tiles of size t where t = [min0:max0,min1:max1,...,minn:maxn] (default: 1 tile)
+ -s, --server <name> server host (default: localhost)
+ --port <p> server port (default: 7001)
+ -d, --database <name> database name (default: RASBASE)
+ -u, --user <name> user name (default: rasguest)
+ -p, --passwd <passwd> password (default: rasguest)
+
+ --transferformat <fmt> transfer format. default: Array)
+ --transferformatparams <params> transfer format parameters.(default: '')
+ --storageformat <fmt> storage format (default: Array)
+ --storageformatparams <params> storage format parameters.(default: '')
+ -v, --verbose be verbose (default: be brief)
+Note: If one file is passed, then a 2D object will be generated.
+ If several files are passed, then a 3D object will be generated (in the sequence passed),
+ In this case all files must have same pixel type and x/y extent.
+exit code 254
+Usage: ../insertppm [-h|--help|-c <name>|--collection <name>] [options] files...
+Options:
+ -h, --help this help
+ -c, --collection <name> collection to store image; will be created if nonexistent (required)
+ -t, --type <t> store as pixel type t where t is one of: bin, grey, color (default: color)
+ -r, --rescale rescale pixel values to 8 bit = 0:255 (default: no rescale)
+ --tiled <t> store object in tiles of size t where t = [min0:max0,min1:max1,...,minn:maxn] (default: 1 tile)
+ -s, --server <name> server host (default: localhost)
+ --port <p> server port (default: 7001)
+ -d, --database <name> database name (default: RASBASE)
+ -u, --user <name> user name (default: rasguest)
+ -p, --passwd <passwd> password (default: rasguest)
+
+ --transferformat <fmt> transfer format. default: Array)
+ --transferformatparams <params> transfer format parameters.(default: '')
+ --storageformat <fmt> storage format (default: Array)
+ --storageformatparams <params> storage format parameters.(default: '')
+ -v, --verbose be verbose (default: be brief)
+Note: If one file is passed, then a 2D object will be generated.
+ If several files are passed, then a 3D object will be generated (in the sequence passed),
+ In this case all files must have same pixel type and x/y extent.
+exit code 254
+exit code 255
+exit code 255
+./test_insertppm.sh: testing insertppm done
diff --git a/insertutils/test/test_insertppm.log.reference b/insertutils/test/test_insertppm.log.reference
new file mode 100644
index 0000000..31355a5
--- /dev/null
+++ b/insertutils/test/test_insertppm.log.reference
@@ -0,0 +1,69 @@
+./test_insertppm.sh: testing insertppm start
+Usage: ../insertppm [-h|--help|-c <name>|--collection <name>] [options] files...
+Options:
+ -h, --help this help
+ -c, --collection <name> collection to store image; will be created if nonexistent (required)
+ -t, --type <t> store as pixel type t where t is one of: bin, grey, color (default: color)
+ -r, --rescale rescale pixel values to 8 bit = 0:255 (default: no rescale)
+ --tiled <t> store object in tiles of size t where t = [min0:max0,min1:max1,...,minn:maxn] (default: 1 tile)
+ -s, --server <name> server host (default: localhost)
+ --port <p> server port (default: 7001)
+ -d, --database <name> database name (default: RASBASE)
+ -u, --user <name> user name (default: rasguest)
+ -p, --passwd <passwd> password (default: rasguest)
+
+ --transferformat <fmt> transfer format. default: Array)
+ --transferformatparams <params> transfer format parameters.(default: '')
+ --storageformat <fmt> storage format (default: Array)
+ --storageformatparams <params> storage format parameters.(default: '')
+ -v, --verbose be verbose (default: be brief)
+Note: If one file is passed, then a 2D object will be generated.
+ If several files are passed, then a 3D object will be generated (in the sequence passed),
+ In this case all files must have same pixel type and x/y extent.
+exit code 254
+Usage: ../insertppm [-h|--help|-c <name>|--collection <name>] [options] files...
+Options:
+ -h, --help this help
+ -c, --collection <name> collection to store image; will be created if nonexistent (required)
+ -t, --type <t> store as pixel type t where t is one of: bin, grey, color (default: color)
+ -r, --rescale rescale pixel values to 8 bit = 0:255 (default: no rescale)
+ --tiled <t> store object in tiles of size t where t = [min0:max0,min1:max1,...,minn:maxn] (default: 1 tile)
+ -s, --server <name> server host (default: localhost)
+ --port <p> server port (default: 7001)
+ -d, --database <name> database name (default: RASBASE)
+ -u, --user <name> user name (default: rasguest)
+ -p, --passwd <passwd> password (default: rasguest)
+
+ --transferformat <fmt> transfer format. default: Array)
+ --transferformatparams <params> transfer format parameters.(default: '')
+ --storageformat <fmt> storage format (default: Array)
+ --storageformatparams <params> storage format parameters.(default: '')
+ -v, --verbose be verbose (default: be brief)
+Note: If one file is passed, then a 2D object will be generated.
+ If several files are passed, then a 3D object will be generated (in the sequence passed),
+ In this case all files must have same pixel type and x/y extent.
+exit code 254
+Usage: ../insertppm [-h|--help|-c <name>|--collection <name>] [options] files...
+Options:
+ -h, --help this help
+ -c, --collection <name> collection to store image; will be created if nonexistent (required)
+ -t, --type <t> store as pixel type t where t is one of: bin, grey, color (default: color)
+ -r, --rescale rescale pixel values to 8 bit = 0:255 (default: no rescale)
+ --tiled <t> store object in tiles of size t where t = [min0:max0,min1:max1,...,minn:maxn] (default: 1 tile)
+ -s, --server <name> server host (default: localhost)
+ --port <p> server port (default: 7001)
+ -d, --database <name> database name (default: RASBASE)
+ -u, --user <name> user name (default: rasguest)
+ -p, --passwd <passwd> password (default: rasguest)
+
+ --transferformat <fmt> transfer format. default: Array)
+ --transferformatparams <params> transfer format parameters.(default: '')
+ --storageformat <fmt> storage format (default: Array)
+ --storageformatparams <params> storage format parameters.(default: '')
+ -v, --verbose be verbose (default: be brief)
+Note: If one file is passed, then a 2D object will be generated.
+ If several files are passed, then a 3D object will be generated (in the sequence passed),
+ In this case all files must have same pixel type and x/y extent.
+exit code 254
+exit code 255
+exit code 255
diff --git a/insertutils/test/test_insertppm.log.save b/insertutils/test/test_insertppm.log.save
new file mode 100644
index 0000000..e9f7c29
--- /dev/null
+++ b/insertutils/test/test_insertppm.log.save
@@ -0,0 +1,70 @@
+./test_insertppm.sh: testing insertppm start
+Usage: ../insertppm [-h|--help|-c <name>|--collection <name>] [options] files...
+Options:
+ -h, --help this help
+ -c, --collection <name> collection to store image; will be created if nonexistent (required)
+ -t, --type <t> store as pixel type t where t is one of: bin, grey, color (default: color)
+ -r, --rescale rescale pixel values to 8 bit = 0:255 (default: no rescale)
+ --tiled <t> store object in tiles of size t where t = [min0:max0,min1:max1,...,minn:maxn] (default: 1 tile)
+ -s, --server <name> server host (default: localhost)
+ --port <p> server port (default: 7001)
+ -d, --database <name> database name (default: RASBASE)
+ -u, --user <name> user name (default: rasguest)
+ -p, --passwd <passwd> password (default: rasguest)
+
+ --transferformat <fmt> transfer format. default: Array)
+ --transferformatparams <params> transfer format parameters.(default: '')
+ --storageformat <fmt> storage format (default: Array)
+ --storageformatparams <params> storage format parameters.(default: '')
+ -v, --verbose be verbose (default: be brief)
+Note: If one file is passed, then a 2D object will be generated.
+ If several files are passed, then a 3D object will be generated (in the sequence passed),
+ In this case all files must have same pixel type and x/y extent.
+exit code 254
+Usage: ../insertppm [-h|--help|-c <name>|--collection <name>] [options] files...
+Options:
+ -h, --help this help
+ -c, --collection <name> collection to store image; will be created if nonexistent (required)
+ -t, --type <t> store as pixel type t where t is one of: bin, grey, color (default: color)
+ -r, --rescale rescale pixel values to 8 bit = 0:255 (default: no rescale)
+ --tiled <t> store object in tiles of size t where t = [min0:max0,min1:max1,...,minn:maxn] (default: 1 tile)
+ -s, --server <name> server host (default: localhost)
+ --port <p> server port (default: 7001)
+ -d, --database <name> database name (default: RASBASE)
+ -u, --user <name> user name (default: rasguest)
+ -p, --passwd <passwd> password (default: rasguest)
+
+ --transferformat <fmt> transfer format. default: Array)
+ --transferformatparams <params> transfer format parameters.(default: '')
+ --storageformat <fmt> storage format (default: Array)
+ --storageformatparams <params> storage format parameters.(default: '')
+ -v, --verbose be verbose (default: be brief)
+Note: If one file is passed, then a 2D object will be generated.
+ If several files are passed, then a 3D object will be generated (in the sequence passed),
+ In this case all files must have same pixel type and x/y extent.
+exit code 254
+Usage: ../insertppm [-h|--help|-c <name>|--collection <name>] [options] files...
+Options:
+ -h, --help this help
+ -c, --collection <name> collection to store image; will be created if nonexistent (required)
+ -t, --type <t> store as pixel type t where t is one of: bin, grey, color (default: color)
+ -r, --rescale rescale pixel values to 8 bit = 0:255 (default: no rescale)
+ --tiled <t> store object in tiles of size t where t = [min0:max0,min1:max1,...,minn:maxn] (default: 1 tile)
+ -s, --server <name> server host (default: localhost)
+ --port <p> server port (default: 7001)
+ -d, --database <name> database name (default: RASBASE)
+ -u, --user <name> user name (default: rasguest)
+ -p, --passwd <passwd> password (default: rasguest)
+
+ --transferformat <fmt> transfer format. default: Array)
+ --transferformatparams <params> transfer format parameters.(default: '')
+ --storageformat <fmt> storage format (default: Array)
+ --storageformatparams <params> storage format parameters.(default: '')
+ -v, --verbose be verbose (default: be brief)
+Note: If one file is passed, then a 2D object will be generated.
+ If several files are passed, then a 3D object will be generated (in the sequence passed),
+ In this case all files must have same pixel type and x/y extent.
+exit code 254
+exit code 255
+exit code 255
+./test_insertppm.sh: testing insertppm done
diff --git a/insertutils/test/test_insertppm.sh b/insertutils/test/test_insertppm.sh
new file mode 100644
index 0000000..5250a48
--- /dev/null
+++ b/insertutils/test/test_insertppm.sh
@@ -0,0 +1,152 @@
+#!/bin/bash
+####################### Makefile header ##########################
+#
+# test_insertppm: test insertppm, rasgeo ppm import utility
+#
+# TEST CANDIDATE:
+# insertppm
+#
+# TEST MODE:
+# automatic
+#
+# PREREQUISITES:
+# - rasdaman server (RNP, RPC) running, any base DBMS
+# - ~rasdaman/images accessible with standard imagery
+#
+# CHANGE HISTORY (append further entries):
+# when: who: what:
+# ----------------------------------------------------------------
+# 2005-dec-02 PB created
+#
+# COMMENTS:
+# - exit -1 if "ERROR" found in log file or in diff to canonical log file
+# - test program must be in cwd
+# - old log is saved to <logfile>.save
+# - todo:
+# test storage and transfer parameters
+#
+# Copyright (C) 2005 Dr. Peter Baumann
+#
+##################################################################
+
+# --- declarations -----------------------------------------------
+
+# shorthands and orga stuff
+IPPM=../insertppm
+
+PROG=`basename $0`
+INDENT="+++ "
+
+# ERROR keyword, should be standardised across all rasdaman tests
+ERROR=ERROR
+
+# log file output
+LOG=`basename $0 .sh`.log
+
+# reference log file
+REFLOG=$LOG.reference
+
+# save old log here if it exists
+SAVELOG=$LOG.save
+
+# test defaults:
+COLL_RGB=rgb
+COLL_GREY=mr
+COLL_3D=mr3d
+FILEPATH=~rasdaman/images
+FILE_RGB=$FILEPATH/anthur.ppm
+FILE_GREY=$FILEPATH/mr_1.pgm
+FILE_LIST=$FILEPATH/mr_?.pgm
+TYPE_GREY=grey
+TYPE_RGB=color
+TILED_3D=[1:2,3:4,5:6]
+
+SERVER=`hostname`
+PORT=7001
+DATABASE=RASBASE
+USER=rasadmin
+PASSWD=rasadmin
+
+TRANSFERFORMAT=TIFF
+TRANSFERFORMATPARAMS=TIFF_PARAMS
+STORAGEFORMAT=RLE
+STORAGEFORMATPARAMS=RLE_PARAMS
+
+# --- action -----------------------------------------------
+
+# save old log if present
+if [ -f $LOG ]
+then
+ echo found old log file, shifting it to $SAVELOG
+ mv $LOG $SAVELOG
+fi
+echo "$0: testing insertppm start" | tee $LOG
+
+echo $INDENT $INDENT starting softly
+echo $INDENT no params
+( $IPPM || (export RC=$?; echo exit code $RC) ) | tee -a $LOG
+
+echo $INDENT call help
+( $IPPM -h || (export RC=$?; echo exit code $RC) ) | tee -a $LOG
+
+echo $INDENT call help
+( $IPPM --help || (export RC=$?; echo exit code $RC) ) | tee -a $LOG
+
+echo $INDENT all correct
+echo $INDENT $INDENT all mandatory syntactically correct
+# ( $IPPM -c $COLL_RGB $FILE_RGB || (export RC=$?; echo Fatal $ERROR, exit code $RC) ) | tee -a $LOG
+
+echo $INDENT $INDENT all syntactically correct, long version,
+# ( $IPPM --collection $COLL_3D --type $TYPE_GREY --rescale --tiled $TILED_3D --verbose \
+# --server $SERVER --port $PORT --database $DATABASE --user $USER --passwd $PASSWD \
+# `ls $FILE_LIST` || (export RC=$?; echo Fatal $ERROR, exit code $RC) ) | tee -a $LOG
+
+echo collection param missing:
+( $IPPM $FILE_RGB \
+ || (export RC=$?; echo exit code $RC) ) | tee -a $LOG
+echo file param missing:
+( $IPPM --collection $COLL_RGB \
+ || (export RC=$?; echo exit code $RC) ) | tee -a $LOG
+
+echo $INDENT $INDENT starting softly done
+echo $INDENT $INDENT illegal cmd line options start
+
+echo $INDENT $INDENT mdd domain parameter syntax mismatch
+
+echo tbd.
+
+echo $INDENT $INDENT illegal cmd line options done
+echo
+echo $INDENT $INDENT image type bool
+echo $INDENT $INDENT $INDENT nontiled
+echo tbd.
+echo $INDENT $INDENT $INDENT tiled
+echo tbd.
+echo $INDENT $INDENT image type grey
+echo $INDENT $INDENT $INDENT nontiled
+echo tbd.
+echo $INDENT $INDENT $INDENT tiled
+echo tbd.
+echo $INDENT $INDENT image type rgb
+echo $INDENT $INDENT $INDENT nontiled
+echo tbd.
+echo $INDENT $INDENT $INDENT tiled
+echo tbd.
+
+echo $INDENT $INDENT transfer and storage parameters
+echo tbd.
+
+# --- now compare result with canonical log:
+
+if [ `diff $LOG $REFLOG | wc -l` -ne "0" ]
+then
+ echo $0: $ERROR: log file differes from reference log file, please examine!
+ exit -1
+else
+ echo $0: no difference found between log and reference log
+fi
+
+echo "$0: testing insertppm done" >>$LOG
+echo "$0: done."
+
+
diff --git a/java/Makefile b/java/Makefile
new file mode 100644
index 0000000..a6fb3dc
--- /dev/null
+++ b/java/Makefile
@@ -0,0 +1,140 @@
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>. # Top Level makefile. This points to the various modules that have to be build
+# and/or deployed
+#
+# MAKEFILE FOR:
+# RasDaMan Java Client
+#
+#
+# COMMENTS:
+#
+##################################################################
+######################### Definitions ############################
+
+# standard include with general options
+include $(RMANBASE)/Makefile.inc
+
+########################### Targets ##############################
+
+.PHONY: all rasj rnp rasj_jar rasdaview odmg clean docu rasj_docu rasdaview_docu odmg_docu empty java_release_docu examples test
+
+# all
+all: rasj_jar examples rasdaview
+
+# rasj jar file
+rasj_jar: rasj odmg rnp
+ $(JAR) -cf rasj.jar rasj/*.class rasj/clientcommhttp/*.class rasj/odmg/*.class org/odmg/*.class rasj/global/*.class rasj/rnp/*.class
+
+# batch test suite
+.PHONY: systemtest
+systemtest:
+ cd rasj; $(MAKE) systemtest
+
+# rasj
+rasj:
+ cd rasj; $(MAKE)
+
+# odmg
+odmg:
+ cd org/odmg; $(MAKE)
+
+# examples
+examples:
+ cd examples; $(MAKE)
+
+# rasdaview
+rasdaview:
+ cd rasdaview; $(MAKE)
+
+# delete classes .PHONY : clean
+clean:
+ cd rasj; $(MAKE) clean
+ cd rasdaview; $(MAKE) clean
+ cd org/odmg; $(MAKE) clean
+ cd examples; $(MAKE) clean
+ -rm -rf rasj.jar
+
+# --- documentation -----------------------------------------------------------
+
+# complete docu
+# removed package insert (nonexisting), added test -- PB 2003-jun-28
+docu:
+ cd rasj; $(MAKE) docu
+
+# rasj distribution docu
+rasj_docu:
+ mkdir -p $(RELEASEDOCDIR)/java
+ $(JAVADOC) -breakiterator -author -d $(DOCDIR)/java -sourcepath $(RASBASE)/java rasj rasj.clientcommhttp \
+ rasj.odmg rasj.global
+
+# rasdaview docu
+rasdaview_docu:
+ mkdir -p $(DOCDIR)/rasdaview
+ $(JAVADOC) -breakiterator -author -d $(DOCDIR)/rasdaview -sourcepath $(RASBASE)/java rasdaview
+
+# ODMG docu
+odmg_docu:
+ mkdir -p $(DOCDIR)/org
+ $(JAVADOC) -breakiterator -author -d $(DOCDIR)/org -sourcepath $(RASBASE)/java org.odmg
+ chmod -R g+w $(DOCDIR)/org
+
+# Java realeses docu
+java_release_docu:
+ -rm -rf $(RELEASEDOCBASE)/html/rasj
+ mkdir -p $(RELEASEDOCBASE)/html/rasj
+ echo "<img src='logo-rasdaman.gif' height='100' border='none'><br>Java API v$(RMANVERSIONNAME)" \
+ >javadocheader.html
+ $(JAVADOC) -breakiterator -author -public -splitindex -header "`cat javadocheader.html`" \
+ -footer "`cat javadocfooter.html`" -windowtitle "rasdaman Java Doc" \
+ -bottom "`cat javadocbottom.html`" -doctitle "`cat javadoctitle.html`" \
+ -use -d $(RELEASEDOCBASE)/html/rasj -sourcepath $(RMANBASE)/java org.odmg rasj \
+ -stylesheetfile stylesheet.css
+ chmod -R g+w $(RELEASEDOCBASE)/html/rasj
+
+# following obsolete? -- PB 2006-jan-03
+
+# examples docu
+examples_docu:
+ mkdir -p $(DOCDIR)/examples
+ $(JAVADOC) -breakiterator -author -d $(DOCDIR)/examples -sourcepath $(RASBASE)/java examples
+ chmod -R g+w $(DOCDIR)/examples
+
+# insert docu
+insert_docu:
+ mkdir -p $(DOCDIR)/insert
+ $(JAVADOC) -breakiterator -author -d $(DOCDIR)/insert -sourcepath $(RASBASE)/java insert
+
+# --- rasview -----------------------------------------------------------------
+
+# make rasview jar file
+rasview_jar: rasj odmg rasdaview
+ $(JAR) -cf rasview.jar rasj/*.class rasj/clientcommhttp/*.class rasj/odmg/*.class org/odmg/*.class rasj/global/*.class rasdaview/*.class
+
+# delete all files
+empty:
+ cd rasj; $(MAKE) empty
+ cd rasdaview; $(MAKE) empty
+ cd org/odmg; $(MAKE) empty
+
+depend:
+ echo "No dependecy is used for java"
+
diff --git a/java/examples/AvgCellRed.java b/java/examples/AvgCellRed.java
new file mode 100644
index 0000000..a6a903f
--- /dev/null
+++ b/java/examples/AvgCellRed.java
@@ -0,0 +1,167 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE: Example Java program for computing the avg cell red value
+ * for a RGB image in a given collection.
+ *
+ *
+ ************************************************************/
+
+package examples;
+
+import rasj.*;
+import rasj.odmg.*;
+import org.odmg.*;
+import java.util.*;
+
+/** Example Java program for computing the avg cell red value
+ * for a RGB image in a given collection.
+ *
+ * set the server name with -server, the database name with -database, the collection name with -collection,
+ * the port number with -port, the user login with -user, the password with -passwd
+ */
+public class AvgCellRed
+{
+ public static void main(String[] args)
+ {
+ String server = "localhost";
+ String base = "RASBASE";
+ String coll = "rgb";
+ String port = "7001";
+ String user = "rasguest";
+ String passwd = "rasguest";
+
+ long sum;
+ long pixelcount;
+
+ for (int i=args.length-1; i>=0; i--)
+ {
+ //System.out.println(args[i]);
+ if (args[i].equals("-server"))
+ server = args[i+1];
+ if (args[i].equals("-database"))
+ base = args[i+1];
+ if (args[i].equals("-collection"))
+ coll = args[i+1];
+ if (args[i].equals("-port"))
+ port = args[i+1];
+ if (args[i].equals("-user"))
+ user = args[i+1];
+ if (args[i].equals("-passwd"))
+ passwd = args[i+1];
+ }
+ //System.out.println(server+base+coll+port+user+passwd);
+
+ DBag resultBag = null;
+ RasGMArray result = null;
+ Transaction myTa = null;
+ Database myDb = null;
+ OQLQuery myQu = null;
+
+ try
+ {
+ Implementation myApp = new RasImplementation("http://"+server+":"+port);
+ ((RasImplementation)myApp).setUserIdentification(user, passwd);
+ myDb = myApp.newDatabase();
+
+ System.out.println("Opening database ...");
+ myDb.open(base, Database.OPEN_READ_ONLY);
+
+ System.out.println("Starting transaction ...");
+ myTa = myApp.newTransaction();
+ myTa.begin();
+
+ System.out.println("Retrieving MDDs ...");
+ myQu = myApp.newOQLQuery();
+ myQu.create("select img from "+ coll+" as img");
+ resultBag = (DBag)myQu.execute();
+ //System.out.println(resultBag);
+ if (resultBag != null)
+ {
+ Iterator iter = resultBag.iterator();
+ while (iter.hasNext())
+ {
+ result = (RasGMArray)iter.next();
+ System.out.println(result);
+ if(result.getTypeLength() != 3)
+ System.out.println("skipping image because of non-RGB cell type");
+ else
+ {
+ sum = 0;
+ pixelcount = 0;
+
+ for(long i = result.spatialDomain().item(0).low();
+ i <= result.spatialDomain().item(0).high(); i++)
+ {
+ for(long j = result.spatialDomain().item(1).low();
+ j <= result.spatialDomain().item(1).high(); j++)
+ {
+ RasPoint p = new RasPoint(i,j);
+ //System.out.println(p);
+ sum += result.getCell(p)[0];
+
+ }
+ }
+ pixelcount = (result.spatialDomain().item(0).high() -
+ result.spatialDomain().item(0).low() + 1) *
+ (result.spatialDomain().item(1).high() -
+ result.spatialDomain().item(1).low() + 1);
+ System.out.println("Average over "+pixelcount+" red pixels is "+
+ (sum/pixelcount));
+ }
+ }
+ System.out.println("All results");
+ }
+
+ System.out.println( "Committing transaction ..." );
+ myTa.commit();
+
+ System.out.println( "Closing database ..." );
+ myDb.close();
+
+ }
+ catch (RasException rase)
+ {
+ System.out.println("An exception has occurred: " + rase.getMessage());
+ }
+ catch (org.odmg.ODMGException e)
+ {
+ System.out.println("An exception has occurred: " + e.getMessage());
+ System.out.println("Try to abort the transaction ...");
+ if(myTa != null) myTa.abort();
+
+ try
+ {
+ System.out.println("Try to close the database ...");
+ if(myDb != null) myDb.close();
+ }
+ catch ( org.odmg.ODMGException exp )
+ {
+ System.err.println("Could not close the database: " + exp.getMessage());
+ }
+ }
+ System.out.println( "Done." );
+ }
+}
diff --git a/java/examples/GetData.java b/java/examples/GetData.java
new file mode 100644
index 0000000..e952f47
--- /dev/null
+++ b/java/examples/GetData.java
@@ -0,0 +1,148 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE: Example Java program for computing the avg cell red value
+ * for a RGB image in a given collection.
+ *
+ *
+ ************************************************************/
+
+package examples;
+
+import rasj.*;
+import rasj.odmg.*;
+import org.odmg.*;
+import java.util.*;
+
+/** Example Java program for computing the avg cell red value
+ * for a RGB image in a given collection.
+ *
+ * set the server name with -server, the database name with -database, the collection name with -collection,
+ * the port number with -port, the user login with -user, the password with -passwd
+ */
+public class GetData
+{
+ public static void main(String[] args)
+ {
+ String server = "localhost";
+ String base = "RASBASE";
+ String coll = "NN3_1";
+ String port = "7101";
+ String user = "rasguest";
+ String passwd = "rasguest";
+
+ long sum;
+ long pixelcount;
+
+ for (int i=args.length-1; i>=0; i--)
+ {
+ //System.out.println(args[i]);
+ if (args[i].equals("-server"))
+ server = args[i+1];
+ if (args[i].equals("-database"))
+ base = args[i+1];
+ if (args[i].equals("-collection"))
+ coll = args[i+1];
+ if (args[i].equals("-port"))
+ port = args[i+1];
+ if (args[i].equals("-user"))
+ user = args[i+1];
+ if (args[i].equals("-passwd"))
+ passwd = args[i+1];
+ }
+ //System.out.println(server+base+coll+port+user+passwd);
+
+ DBag resultBag = null;
+ RasGMArray result = null;
+ Transaction myTa = null;
+ Database myDb = null;
+ OQLQuery myQu = null;
+
+ try
+ {
+ Implementation myApp = new RasImplementation("http://"+server+":"+port);
+ ((RasImplementation)myApp).setUserIdentification(user, passwd);
+ ((RasImplementation)myApp).setTraceThreshold(4);
+ myDb = myApp.newDatabase();
+
+ System.out.println("Opening database ...");
+ myDb.open(base, Database.OPEN_READ_ONLY);
+
+ System.out.println("Starting transaction ...");
+ myTa = myApp.newTransaction();
+ myTa.begin();
+
+ System.out.println("Retrieving MDDs ...");
+ myQu = myApp.newOQLQuery();
+ myQu.create("select img from "+ coll+" as img");
+ resultBag = (DBag)myQu.execute();
+ //System.out.println(resultBag);
+ if (resultBag != null)
+ {
+ Iterator iter = resultBag.iterator();
+ while (iter.hasNext())
+ {
+ result = (RasGMArray)iter.next();
+ System.out.println(result);
+ RasMArrayFloat tmp = (RasMArrayFloat) result;
+ float [] info = tmp.getFloatArray();
+ System.out.println(info.length);
+ for (int i=0; i<info.length; i++)
+ System.out.println(info[i]);
+ }
+ System.out.println("All results");
+ }
+
+ System.out.println( "Committing transaction ..." );
+ myTa.commit();
+
+ System.out.println( "Closing database ..." );
+ myDb.close();
+
+ }
+/*
+ catch (RasException rase)
+ {
+ System.out.println("An exception has occurred: " + rase.getMessage());
+ }*/
+ catch (org.odmg.ODMGException e)
+ {
+ System.out.println("An exception has occurred: " + e.getMessage());
+ System.out.println("Try to abort the transaction ...");
+ if(myTa != null) myTa.abort();
+
+ try
+ {
+ System.out.println("Try to close the database ...");
+ if(myDb != null) myDb.close();
+ }
+ catch ( org.odmg.ODMGException exp )
+ {
+ System.err.println("Could not close the database: " + exp.getMessage());
+ }
+ }
+ System.out.println( "Done." );
+ }
+}
diff --git a/java/examples/TestQuery.java b/java/examples/TestQuery.java
new file mode 100644
index 0000000..ac0bb30
--- /dev/null
+++ b/java/examples/TestQuery.java
@@ -0,0 +1,749 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE: used in RMANHOME/systemtest/testjava.sh
+ *
+ *
+ ************************************************************/
+package examples;
+
+import rasj.*;
+import rasj.odmg.*;
+import org.odmg.*;
+import java.util.*;
+import java.io.*;
+
+/**
+ * used in RMANHOME/systemtest/testjava.sh
+ *
+ * set the server name with -server, the database name with -database, the collection name with -collection,
+ * set port number with -port, the user login with -user, the password with -passwd,
+ * and path to query file with -queryfile, path to log file with -logfile, path to query test directory wtih -testdirectory
+ */
+
+class Record
+ {
+
+ static StringBuffer locQuery = new StringBuffer(20000);
+ static StringBuffer locExpected = new StringBuffer(20000);
+
+ boolean commitBefore = false;
+ String queryFileShortName = null;
+ String queryFileFullName = null;
+ String query = null;
+ String expectedFile = null;
+ String expected = null;
+ volatile String answer = null;
+ volatile DBag result = null;
+
+ boolean loadQuery()
+ {
+ FileReader fr = null;
+ BufferedReader in = null;
+ boolean answer = true;
+ String ret = null;
+
+ try
+ {
+ if(queryFileFullName == null) return false;
+ //System.out.println(file);
+ fr = new FileReader(queryFileFullName);
+ in = new BufferedReader(fr);
+ String s;
+
+ locQuery.delete(0, locQuery.length());
+ locQuery.append( "-- " + queryFileFullName + "\n");
+ while((s = in.readLine()) != null)
+ {
+ locQuery.append("\n" + s);
+ }
+
+ query = locQuery.toString();
+ }
+ catch(FileNotFoundException e)
+ {
+ ret = "Query-file not found!\n"+e.getMessage();
+ System.err.println(ret);
+ answer = false;
+ }
+ catch(IOException e)
+ {
+ ret = "Could not read Query-file!\n"+e.getMessage();
+ System.err.println(ret);
+ answer = false;
+ }
+ finally
+ {
+ try{
+ if(in != null) in.close();
+ if(fr != null) fr.close();
+ }
+ catch(Exception e){}
+ }
+ return answer;
+ }
+
+ boolean loadExpected()
+ {
+ FileReader fr = null;
+ BufferedReader in = null;
+ boolean answer = true;
+ String ret = null;
+ String s = null;
+
+ try
+ {
+ if(expectedFile == null) return false;
+ //System.out.println(file);
+ fr = new FileReader(expectedFile);
+ in = new BufferedReader(fr);
+ locExpected.delete(0, locExpected.length());
+
+ if((s=in.readLine()) != null)
+ locExpected.append(s);
+ while((s = in.readLine()) != null)
+ {
+ locExpected.append("\n" + s);
+ }
+
+ expected = locExpected.toString();
+ }
+ catch(FileNotFoundException e)
+ {
+ ret = "Expected-file not found!\n"+e.getMessage();
+ System.err.println(ret);
+ answer = false;
+ }
+ catch(IOException e)
+ {
+ ret = "Could not read expected-file!\n"+e.getMessage();
+ System.err.println(ret);
+ answer = false;
+ }
+ finally
+ {
+ try{
+ if(in != null) in.close();
+ if(fr != null) fr.close();
+ }
+ catch(Exception e){}
+ }
+ return answer;
+ }
+ }
+
+class FilesToProcess
+ {
+ Vector records;
+
+
+ FilesToProcess(String path) throws Exception
+ {
+ records = new Vector();
+
+ File filePath = new File(path);
+ processPath(filePath);
+ loadAllQueries();
+ }
+
+ Record getRecord(int i)
+ {
+ return (Record)records.get(i);
+ }
+
+ int countRecords()
+ {
+ return records.size();
+ }
+
+ void print()
+ {
+ System.out.println("List of all files to process");
+ for(int i = 0; i<records.size(); i++)
+ {
+ Record record = (Record)records.get(i);
+
+ System.out.println(i + " " + record.queryFileShortName);// + " " + record.queryFileFullName + " " + record.expectedFile);
+
+ //System.out.println(" query=" + record.query);
+ }
+ }
+
+ private void processPath(File path) throws Exception
+ {
+ File [] fl = null;
+ try {
+ fl = path.listFiles();
+ }
+ catch(Exception e) {
+ System.err.println("Error FileToProcess::processPath(" + path + ")" + e.getMessage());
+ throw e;
+ }
+
+ if(fl == null) {
+ System.err.println("Error FileToProcess::processPath(" + path + ") path does not denote a directory, or an I/O error occured." );
+ throw new Exception("Error FileToProcess::processPath(" + path + ") path does not denote a directory, or an I/O error occured." );
+ }
+
+ boolean first = true;
+ for(int i=0; i<fl.length; i++)
+ {
+ if(fl[i].isDirectory()) { processPath(fl[i]); continue;}
+
+ if(fl[i].isFile() && accept(fl[i]) )
+ {
+ Record record = new Record();
+
+ record.commitBefore = first;
+ record.queryFileShortName = fl[i].getName();
+ record.queryFileFullName = fl[i].getAbsolutePath();
+ record.expectedFile = record.queryFileFullName + ".java.out";
+
+ records.add(record);
+ first = false;
+ }
+ }
+ }
+
+ private boolean accept(File f)
+ {
+ String extension = getExtension(f);
+ if (extension != null) return extension.equals("ql");
+ return false;
+ }
+
+ private String getExtension(File f)
+ {
+ String ext = null;
+ String s = f.getName();
+ int i = s.lastIndexOf('.');
+
+ if (i > 0 && i < s.length() - 1)
+ {
+ ext = s.substring(i+1).toLowerCase();
+ }
+ return ext;
+ }
+
+ private void loadAllQueries()
+ {
+ for(int i = 0; i<records.size(); i++)
+ {
+ Record record = (Record)records.get(i);
+
+ record.loadQuery();
+ }
+ }
+
+ }
+
+class ExpectedLoader extends Thread
+ {
+ FilesToProcess fp = null;
+
+ ExpectedLoader(FilesToProcess x)
+ {
+ fp = x;
+ }
+
+ public void run()
+ {
+ for(int i=0;i < fp.countRecords(); i++)
+ {
+ Record record = fp.getRecord(i);
+ record.loadExpected();
+ }
+ }
+ }
+
+class AnswerConvertor extends Thread
+ {
+ FilesToProcess fp = null;
+
+ AnswerConvertor(FilesToProcess x)
+ {
+ fp = x;
+ }
+
+ public void run()
+ {
+ for(int i=0;i < fp.countRecords(); i++)
+ {
+ Record record = fp.getRecord(i);
+
+ while(record.result == null) { try { Thread.sleep(1000); } catch(Exception e){} }
+
+ Object res;
+
+ Iterator iter = record.result.iterator();
+ String ret = "";
+ while (iter.hasNext())
+ {
+ res = iter.next();
+ if(res instanceof RasGMArray)
+ ret = ret + ((RasGMArray)res).toTestString();
+ else
+ ret = ret + res.toString();
+ }
+
+ record.answer = ret;
+ }
+ }
+ }
+
+class AnswerLoader extends Thread
+ {
+ FilesToProcess fp = null;
+
+ Transaction myTa = null;
+ Database myDb = null;
+ int accessMode;
+ Implementation myApp = null;
+
+ final long noOfRetries=10000;
+ long countRetry=0;
+ int count = 0;
+
+ OQLQuery myQu;
+ String server = null;
+ String port = null;
+ String database = null;
+ String user = null;
+ String passwd = null;
+
+ AnswerLoader(String s, String p, String d, String u, String pwd, FilesToProcess x)
+ {
+ fp = x;
+ server = s;
+ port = p;
+ database = d;
+ user = u;
+ passwd = pwd;
+ }
+
+ public void run()
+ {
+ for(int i=0;i < fp.countRecords(); i++)
+ {
+ Record record = fp.getRecord(i);
+
+ String answer = getAnswer(record);
+
+ if(answer != null)
+ { // an error or empty string
+ DBag result = new RasBag();
+ result.add(answer);
+ record.result = result;
+ // here we put the error or empty result in a DBag, so the conversion string puts it in "answer"
+ // It is cleaner for threads
+ }
+ }
+ clearConnection(true);
+ }
+
+ String getAnswer(Record record)
+ {
+ if(record.query == null || record.query.equals("")) return "-no query-";
+
+ String ret = "";
+
+ try
+ {
+ if(record.commitBefore) clearConnection(false);
+ connectToRasDaMan();
+
+ createQueryObject(record.query);
+
+// System.out.println( "Executing query..." );
+ DBag result = (DBag) myQu.execute();
+
+ Object res;
+ if (result != null)
+ {
+ // we have an answer, the conversion is done on another thread
+ record.result = result;
+ ret = null;
+ }
+ // empty result -> ""; good result -> null;
+ // bad result -> error text built from the following catch's
+ return ret;
+ }
+ catch(RasRuntimeException e)
+ {
+ ret = "\n RasRuntimeException: " + e.getMessage();
+ }
+ catch(RasException e)
+ {
+ ret = "\n RasException: "+e.getMessage();
+ }
+ catch (org.odmg.ODMGException e)
+ {
+ ret = "\n ODMGException: "+ e.getMessage();
+ }
+ return ret;
+ }
+
+ void connectToRasDaMan() throws ODMGException, RasRuntimeException, ODMGRuntimeException
+ {
+ if(myTa != null) return;
+
+ myApp = new RasImplementation("http://"+server+":"+port);
+ ((RasImplementation)myApp).setUserIdentification(user, passwd);
+ myDb = myApp.newDatabase();
+ myTa = myApp.newTransaction();
+
+ tryOpenDatabase();
+ }
+
+ void clearConnection(boolean error)
+ {
+ try{
+ if(myTa != null)
+ if(error) myTa.abort();
+ else myTa.commit();
+ if(myDb != null) myDb.close();
+ myTa = null;
+ myDb = null;
+ myApp = null;
+ }
+ catch ( org.odmg.ODMGException exp )
+ {
+ // can't heapen, our DB.close doesn't throw anything
+ }
+ }
+
+ void createQueryObject(String query) throws org.odmg.ODMGException, RasRuntimeException, RasException
+ {
+ myQu = myApp.newOQLQuery();
+
+ myQu.create(query);
+
+ StringTokenizer strTok = new StringTokenizer(query, "$");
+ RasMInterval domain;
+ RasGMArray mddConst;
+ if(strTok.hasMoreTokens()) strTok.nextToken();
+
+ while(strTok.hasMoreTokens())
+ {
+ strTok.nextToken();
+ domain = new RasMInterval("[0:10,0:10]");
+ RasStorageLayout stl = new RasStorageLayout();
+ stl.setTileSize(8);
+ mddConst = new RasGMArray(domain, 4, stl);
+ byte[] data = new byte[mddConst.getArray().length];
+ for(int j = 0; j < data.length; j++)
+ { data[j] = (byte)j;
+ }
+ mddConst.setArray(data);
+ mddConst.setObjectTypeName("ULongImage");
+ //System.out.println(mddConst);
+ myQu.bind(mddConst);
+ }
+ accessMode=Database.OPEN_READ_WRITE;
+ // we cache transactions, so let it like this
+ /*
+ if(isUpdateQuery(query))
+ accessMode=Database.OPEN_READ_WRITE;
+ else
+ accessMode=Database.OPEN_READ_ONLY;
+ */
+ }
+
+ void tryOpenDatabase() throws ODMGException, RasRuntimeException, ODMGRuntimeException
+ {
+ countRetry=0;
+ while(true)
+ {
+ try
+ {
+ //System.out.println( "Opening database ..." );
+ myDb.open( database, accessMode);
+
+ //System.out.println( "Starting transaction ..." );
+ myTa.begin();
+
+ break;
+ }
+ catch(RasRuntimeException e)
+ {
+ if(eatException() == false)
+ { clearConnection(true);
+ throw e;
+ }
+ }
+ catch (ODMGException e)
+ {
+ if(eatException() == false)
+ { clearConnection(true);
+ throw e;
+ }
+ }
+ catch (ODMGRuntimeException e)
+ {
+ if(eatException() == false)
+ { clearConnection(true);
+ throw e;
+ }
+ }
+ }
+ }
+
+ boolean eatException()
+ {
+ boolean retval=false;
+
+ countRetry++;
+ if((countRetry % 1000) == 0)
+ System.out.println( "Server busy, retry ... " + countRetry + " / " + noOfRetries );
+
+ if(countRetry<noOfRetries)
+ {
+ try { Thread.sleep(1000); } catch(InterruptedException e){ }
+ retval=true;
+ }
+ return retval;
+ }
+
+ boolean isUpdateQuery(String query)
+ {
+ boolean retval = false;
+ // detect query type
+ if((query.indexOf("select") == -1) &&
+ (query.indexOf("SELECT") == -1))
+ retval = true;
+
+ return retval;
+ }
+
+
+ }
+
+
+
+public class TestQuery
+{
+ final long noOfRetries=10000;
+ long countRetry=0;
+ int count = 0;
+
+ String logfile = "";
+ String ret = "";
+ String query = "";
+
+ Random noRandom;
+
+ Transaction myTa;
+ Database myDb;
+ int accessMode;
+ Implementation myApp;
+ OQLQuery myQu;
+
+
+ static boolean dontDeleteResultFile = false;
+
+ static String server = "localhost";
+ static String port = "7001";
+ static String database = "RASBASE";
+ static String user = "rasguest";
+ static String passwd = "rasguest";
+ static String testdir = "";
+ static String logFile = "";
+ static Date start = null;
+ static Date end = null;
+
+ static void parseParams( String[] args) {
+ //arguments parsing
+ for (int i=0; i < args.length; i++)
+ {
+ //System.out.print(args[i] + " ");
+ // server name
+ if (args[i].equals("-server"))
+ server = args[i+1];
+ // port number
+ if (args[i].equals("-port"))
+ port = args[i+1];
+ // database name
+ if (args[i].equals("-database"))
+ database = args[i+1];
+ // path to logfile
+ if (args[i].equals("-logfile"))
+ logFile = args[i+1];
+ // user login
+ if (args[i].equals("-user"))
+ user = args[i+1];
+ // password
+ if (args[i].equals("-passwd"))
+ passwd = args[i+1];
+ // path to test directory
+ if (args[i].equals("-testdirectory"))
+ testdir = args[i+1];
+ if (args[i].equals("-preserveresult"))
+ dontDeleteResultFile = true;
+ }
+
+ //print header
+ System.out.println("TestQuery version 1.0 for RasJ API ");
+ System.out.println("Server : " + server);
+ System.out.println("Port : " + port);
+ System.out.println("Database : " + database);
+ System.out.println("User : " + user);
+ System.out.println("Password : " + passwd);
+ System.out.println("Test Directory : " + testdir);
+ System.out.println("Preserve Result : " + dontDeleteResultFile);
+
+ //put time stamp
+ start = new Date();
+ System.out.println("Test started at: " + start.toString());
+ }
+
+ public static void main( String[] args )
+ {
+
+ parseParams(args);
+
+
+ PrintWriter logWriter = openLogWriter(logFile);
+ if(logWriter == null) {
+ //could not open the file
+ start = null;
+ System.exit(-1);
+ }
+
+ logWriter.println("TestQuery version 1.0 for RasJ API ");
+ logWriter.println("Server : " + server);
+ logWriter.println("Port : " + port);
+ logWriter.println("Database : " + database);
+ logWriter.println("User : " + user);
+ logWriter.println("Password : " + passwd);
+ logWriter.println("Test Directory : " + testdir);
+ logWriter.println("Preserve Result : " + dontDeleteResultFile);
+ logWriter.println("TEST JAVA STARTED AT: " + start.toString());
+
+ FilesToProcess fp = null;
+
+ // this prepares the list of files and loads the queries
+ try {
+ fp = new FilesToProcess(testdir);
+ // fp.print();
+ }
+ catch(Exception e) {
+ //could not directory of query files
+ start = null;
+ System.exit(-1);
+ }
+
+
+ // this goes to rasserver and gets the answers, which are put in DBag Record.result
+ AnswerLoader answerLoader = new AnswerLoader(server, port, database, user, passwd, fp);
+ answerLoader.start();
+
+ // this takes the results and converts them to string: Record.result->Record.answer
+ AnswerConvertor answerConvertor = new AnswerConvertor(fp);
+ answerConvertor.start();
+
+ // this brings the expected results from disk - starts the least because it's very fast
+ ExpectedLoader exp = new ExpectedLoader(fp);
+ exp.start();
+
+ //used to write the output if is requested
+ FileWriter outputFW = null;
+
+ for(int i=0;i < fp.countRecords(); i++)
+ {
+ Record record = fp.getRecord(i);
+
+ while(record.answer == null) { try { Thread.sleep(1000); } catch(Exception e){} }
+
+ System.out.print("" + (i+1) + ": " + record.queryFileShortName);
+ if(record.answer.equals(record.expected))
+ {
+ System.out.println(" OK");
+ logWriter.write(i + ": OK (" + record.queryFileFullName + ")\n");
+ }
+ else
+ {
+ System.out.println(" FAILED!");
+ logWriter.write(i + ": FAILED (" + record.queryFileFullName + ")\n");
+ if(dontDeleteResultFile == true)
+ {
+ try
+ {
+ outputFW=new FileWriter(record.queryFileFullName + ".java.tmp");
+ outputFW.write(record.answer);
+ outputFW.close();
+ outputFW=null;
+ }
+ catch(Exception a)
+ {
+ if(outputFW != null)
+ {
+ try
+ {
+ outputFW.close();
+ }
+ catch(Exception b)
+ {
+ }
+ }
+ }
+ }
+ logWriter.write(" expected=" + record.expected + "\n but got=" + record.answer + "\n");
+ }
+ }
+
+ //put time stamp
+ end = new Date();
+ System.out.println("Test ended at: " + end.toString());
+ logWriter.println("TEST JAVA ENDED AT: " + end.toString());
+
+ logWriter.close();
+ logWriter = null;
+ start=null;
+ end=null;
+ }
+
+ static PrintWriter openLogWriter(String logFileName) {
+ if(logFileName == null || logFileName.equals("")) {
+ System.out.println("No logfile name provided!");
+ return null;
+ }
+
+ try {
+ FileOutputStream fos = new FileOutputStream(logFileName, true);
+ return new PrintWriter(fos);
+ }
+ catch(FileNotFoundException e) {
+ System.out.println("Log-file not found!\n"+e.getMessage());
+ }
+ catch(IOException e) {
+ System.out.println("Could not write Log-file!\n"+e.getMessage());
+ }
+
+ return null;
+ }
+
+ }
+
+
diff --git a/java/org/odmg/ClassNotPersistenceCapableException.java b/java/org/odmg/ClassNotPersistenceCapableException.java
new file mode 100644
index 0000000..4fe7110
--- /dev/null
+++ b/java/org/odmg/ClassNotPersistenceCapableException.java
@@ -0,0 +1,51 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+package org.odmg;
+
+/**
+* This exception is thrown when the implementation cannot make an object persistent because of the type of the object.
+* @author David Jordan (as Java Editor of the Object Data Management Group)
+* @version ODMG 3.0
+*/
+
+public class ClassNotPersistenceCapableException extends ODMGRuntimeException
+{
+
+/**
+* Construct an instance of the exception.
+*/
+ public ClassNotPersistenceCapableException()
+ {
+ super();
+ }
+
+/**
+* Construct an instance of the exception.
+* @param msg A string providing a description of the exception.
+*/
+ public ClassNotPersistenceCapableException(String msg)
+ {
+ super(msg);
+ }
+}
diff --git a/java/org/odmg/DArray.class b/java/org/odmg/DArray.class
new file mode 100644
index 0000000..ea7e037
--- /dev/null
+++ b/java/org/odmg/DArray.class
Binary files differ
diff --git a/java/org/odmg/DArray.java b/java/org/odmg/DArray.java
new file mode 100644
index 0000000..de03894
--- /dev/null
+++ b/java/org/odmg/DArray.java
@@ -0,0 +1,49 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+package org.odmg;
+import java.util.List;
+
+/**
+* The interface that defines the operations of an ODMG array,
+* <BR><I> not yet available in RasDaMan. </BR></I>
+* Nearly all of its operations are defined by the JavaSoft <code>List</code> interface.
+* All of the operations defined by the JavaSoft <code>List</code>
+* interface are supported by an ODMG implementation of <code>DArray</code>,
+* the exception <code>UnsupportedOperationException</code> is not thrown when a
+* call is made to any of the <code>List</code> methods.
+* An instance of a class implementing this interface can be obtained
+* by calling the method <code>Implementation.newDArray</code>.
+* @author David Jordan (as Java Editor of the Object Data Management Group)
+* @version ODMG 3.0
+*/
+// @see java.lang.UnsupportedOperationException
+
+public interface DArray extends org.odmg.DCollection, java.util.List
+{
+/**
+* Resize the array to have <code>newSize</code> elements.
+* @param newSize The new size of the array.
+*/
+ public void resize(int newSize);
+}
+
diff --git a/java/org/odmg/DBag.class b/java/org/odmg/DBag.class
new file mode 100644
index 0000000..53ec907
--- /dev/null
+++ b/java/org/odmg/DBag.class
Binary files differ
diff --git a/java/org/odmg/DBag.java b/java/org/odmg/DBag.java
new file mode 100644
index 0000000..5812c32
--- /dev/null
+++ b/java/org/odmg/DBag.java
@@ -0,0 +1,85 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+package org.odmg;
+
+/**
+* This interface defines the operations associated with an ODMG bag collection.
+* All of the operations defined by the JavaSoft <code>Collection</code>
+* interface are supported by an ODMG implementation of <code>DBag</code>,
+* the exception <code>UnsupportedOperationException</code> is not thrown when a
+* call is made to any of the <code>Collection</code> methods.
+* @author David Jordan (as Java Editor of the Object Data Management Group)
+* @version ODMG 3.0
+*/
+// * @see java.lang.UnsupportedOperationException
+
+public interface DBag extends DCollection
+{
+/**
+* A new <code>DBag</code> instance is created that is the union of this object
+* and <code>otherBag</code>.
+* This method is similar to the <code>addAll</code> method in <code>Collection</code>,
+* except that this method creates a new collection and <code>addAll</code>
+* modifies the object to contain the result.
+* @param otherBag The other bag to use in the union operation.
+* @return A <code>DBag</code> instance that contains the union of this object
+* and <code>otherBag</code>.
+*/
+// * @see com.sun.java.util.collections.Collection#addAll
+ public DBag union(DBag otherBag);
+
+/**
+* A new <code>DBag</code> instance is created that contains the intersection of
+* this object and the <code>DBag</code> referenced by <code>otherBag</code>.
+* This method is similar to the <code>retainAll</code> method in <code>Collection</code>,
+* except that this method creates a new collection and <code>retainAll</code>
+* modifies the object to contain the result.
+* @param otherBag The other bag to use in creating the intersection.
+* @return A <code>DBag</code> instance that contains the intersection of this
+* object and <code>otherBag</code>.
+*/
+// @see com.sun.java.util.collections.Collection#retainAll
+ public DBag intersection(DBag otherBag);
+
+/**
+* A new <code>DBag</code> instance is created that contains the difference of
+* this object and the <code>DBag</code> instance referenced by <code>otherBag</code>.
+* This method is similar to the <code>removeAll</code> method in <code>Collection</code>,
+* except that this method creates a new collection and <code>removeAll</code>
+* modifies the object to contain the result.
+* @param otherBag The other bag to use in creating the difference.
+* @return A <code>DBag</code> instance that contains the elements of this object
+* minus the elements in <code>otherBag</code>.
+*/
+// * @see com.sun.java.util.collections.Collection#removeAll
+ public DBag difference(DBag otherBag);
+
+/**
+* This method returns the number of occurrences of the object <code>obj</code>
+* in the <code>DBag</code> collection.
+* @param obj The value that may have elements in the collection.
+* @return The number of occurrences of <code>obj</code> in this collection.
+*/
+ public int occurrences(Object obj);
+}
+
diff --git a/java/org/odmg/DCollection.class b/java/org/odmg/DCollection.class
new file mode 100644
index 0000000..304df43
--- /dev/null
+++ b/java/org/odmg/DCollection.class
Binary files differ
diff --git a/java/org/odmg/DCollection.java b/java/org/odmg/DCollection.java
new file mode 100644
index 0000000..37cb173
--- /dev/null
+++ b/java/org/odmg/DCollection.java
@@ -0,0 +1,86 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+package org.odmg;
+
+/**
+* The base interface for all ODMG collections.
+* The ODMG collections are based on JavaSoft’s collection interfaces.
+* All of the operations defined by the JavaSoft <code>Collection</code>
+* interface are supported by an ODMG implementation of <code>DCollection</code>;
+* the exception <code>UnsupportedOperationException</code> is not thrown when a
+* call is made to any of the <code>Collection</code> methods.
+* <p>
+* <code>DCollection</code> contains methods used to perform queries on the collection.
+* The OQL query predicate is given as a string with the syntax of the
+* <code>where</code> clause of OQL. The predefined OQL variable <code>this</code>
+* is used inside the predicate to denote the current element of the collection.
+* @author David Jordan (as Java Editor of the Object Data Management Group)
+* @version ODMG 3.0
+*/
+// * @see com.sun.java.util.collections.UnsupportedOperationException
+
+public interface DCollection extends java.util.Collection
+{
+/**
+* Selects the single element of the collection for which the provided OQL query
+* predicate is true,
+* <BR><I> not yet available in RasDaMan. </BR></I>
+* @param predicate An OQL boolean query predicate.
+* @return The element that evaluates to true for the predicate. If no element
+* evaluates to true, null is returned.
+* @exception QueryInvalidException The query predicate is invalid.
+*/
+ public Object selectElement(String predicate) throws QueryInvalidException;
+
+/**
+* Access all of the elements of the collection that evaluate to true for the
+* provided query predicate,
+* <BR><I> not yet available in RasDaMan. </BR></I>
+* @param predicate An OQL boolean query predicate.
+* @return An iterator used to iterate over the elements that evaluated true for the predicate.
+* @exception QueryInvalidException The query predicate is invalid.
+*/
+ public java.util.Iterator select(String predicate) throws QueryInvalidException;
+
+/**
+* Evaluate the boolean query predicate for each element of the collection and
+* return a new collection that contains each element that evaluated to true,
+* <BR><I> not yet available in RasDaMan. </BR></I>
+* @param predicate An OQL boolean query predicate.
+* @return A new collection containing the elements that evaluated true for the predicate.
+* @exception QueryInvalidException The query predicate is invalid.
+*/
+ public DCollection query(String predicate) throws QueryInvalidException;
+
+/**
+* Determines whether there is an element of the collection that evaluates to true
+* for the predicate,
+* <BR><I> not yet available in RasDaMan. </BR></I>
+* @param predicate An OQL boolean query predicate.
+* @return True if there is an element of the collection that evaluates to true
+* for the predicate, otherwise false.
+* @exception QueryInvalidException The query predicate is invalid.
+*/
+ public boolean existsElement(String predicate) throws QueryInvalidException;
+}
+
diff --git a/java/org/odmg/DList.class b/java/org/odmg/DList.class
new file mode 100644
index 0000000..b66b41b
--- /dev/null
+++ b/java/org/odmg/DList.class
Binary files differ
diff --git a/java/org/odmg/DList.java b/java/org/odmg/DList.java
new file mode 100644
index 0000000..fbbc8b9
--- /dev/null
+++ b/java/org/odmg/DList.java
@@ -0,0 +1,55 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+package org.odmg;
+
+/**
+* The ODMG List collection.
+* A <code>DList</code> collection is an ordered collection that provides
+* efficient insertion and removal of elements at arbitrary positions in the
+* list, but it also supports indexed access. The beginning index value is 0.
+* When an element is added at a given position in the list, the index of all
+* subsequent elements is increased by 1. Similarly, when an element is removed
+* from the list, the index of all subsequent elements is decreased by 1.
+* <p>
+* All of the operations defined by the JavaSoft <code>List</code>
+* interface are supported by an ODMG implementation of <code>DList</code>,
+* the exception <code>UnsupportedOperationException</code> is not thrown when a
+* call is made to any of the <code>List</code> methods.
+* @author David Jordan (as Java Editor of the Object Data Management Group)
+* @version ODMG 3.0
+*/
+// * @see com.sun.java.util.collections.UnsupportedOperationException
+
+public interface DList extends DCollection, java.util.List {
+/**
+* Creates a new <code>DList</code> object that contains the contents of this
+* <code>DList</code> object concatenated
+* with the contents of the <code>otherList</code> object.
+* @param otherList The list whose elements are placed at the end of the list
+* returned by this method.
+* @return A new <code>DList</code> that is the concatenation of this list and
+* the list referenced by <code>otherList</code>.
+*/
+ public DList concat(DList otherList);
+}
+
diff --git a/java/org/odmg/DMap.class b/java/org/odmg/DMap.class
new file mode 100644
index 0000000..a61fe58
--- /dev/null
+++ b/java/org/odmg/DMap.class
Binary files differ
diff --git a/java/org/odmg/DMap.java b/java/org/odmg/DMap.java
new file mode 100644
index 0000000..0e99017
--- /dev/null
+++ b/java/org/odmg/DMap.java
@@ -0,0 +1,40 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+package org.odmg;
+
+/**
+* The ODMG Map collection interface,
+* <BR><I> not yet available in RasDaMan. </BR></I>
+* All of the operations defined by the JavaSoft <code>Map</code>
+* interface are supported by an ODMG implementation of <code>DMap</code>,
+* the exception <code>UnsupportedOperationException</code> is not thrown when a
+* call is made to any of the <code>Map</code> methods.
+* @author David Jordan (as Java Editor of the Object Data Management Group)
+* @version ODMG 3.0
+*/
+// * @see com.sun.java.util.collections.UnsupportedOperationException
+
+public interface DMap extends java.util.Map {
+
+}
+
diff --git a/java/org/odmg/DSet.class b/java/org/odmg/DSet.class
new file mode 100644
index 0000000..8381da6
--- /dev/null
+++ b/java/org/odmg/DSet.class
Binary files differ
diff --git a/java/org/odmg/DSet.java b/java/org/odmg/DSet.java
new file mode 100644
index 0000000..bcad44c
--- /dev/null
+++ b/java/org/odmg/DSet.java
@@ -0,0 +1,110 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+package org.odmg;
+
+/**
+* The ODMG Set collection interface.
+* A <code>DSet</code> object is an unordered collection that does not support
+* multiple elements with the same value. An implementation typically is very
+* efficient at determining whether the collection contains a particular value.
+* <p>
+* All of the operations defined by the JavaSoft <code>Set</code>
+* interface are supported by an ODMG implementation of <code>DSet</code>,
+* the exception <code>UnsupportedOperationException</code> is not thrown when a
+* call is made to any of the <code>Set</code> methods.
+* @author David Jordan (as Java Editor of the Object Data Management Group)
+* @version ODMG 3.0
+*/
+// * @see java.lang.UnsupportedOperationException
+
+public interface DSet extends DCollection, java.util.Set
+{
+
+/**
+* Create a new <code>DSet</code> object that is the set union of this
+* <code>DSet</code> object and the set referenced by <code>otherSet</code>,
+* <BR><I> not yet available in RasDaMan. </BR></I>
+* @param otherSet The other set to be used in the union operation.
+* @return A newly created <code>DSet</code> instance that contains the union of the two sets.
+*/
+ public DSet union(DSet otherSet);
+
+/**
+* Create a new <code>DSet</code> object that is the set intersection of this
+* <code>DSet</code> object and the set referenced by <code>otherSet</code>,
+* <BR><I> not yet available in RasDaMan. </BR></I>
+* @param otherSet The other set to be used in the intersection operation.
+* @return A newly created <code>DSet</code> instance that contains the
+* intersection of the two sets.
+*/
+ public DSet intersection(DSet otherSet);
+
+/**
+* Create a new <code>DSet</code> object that contains the elements of this
+* collection minus the elements in <code>otherSet</code>,
+* <BR><I> not yet available in RasDaMan. </BR></I>
+* @param otherSet A set containing elements that should not be in the result set.
+* @return A newly created <code>DSet</code> instance that contains the elements
+* of this set minus those elements in <code>otherSet</code>.
+*/
+ public DSet difference(DSet otherSet);
+
+/**
+* Determine whether this set is a subset of the set referenced by <code>otherSet</code>,
+* <BR><I> not yet available in RasDaMan. </BR></I>
+* @param otherSet Another set.
+* @return True if this set is a subset of the set referenced by <code>otherSet</code>,
+* otherwise false.
+*/
+ public boolean subsetOf(DSet otherSet);
+
+/**
+* Determine whether this set is a proper subset of the set referenced by
+* <code>otherSet</code>,
+* <BR><I> not yet available in RasDaMan. </BR></I>
+* @param otherSet Another set.
+* @return True if this set is a proper subset of the set referenced by
+* <code>otherSet</code>, otherwise false.
+*/
+ public boolean properSubsetOf(DSet otherSet);
+
+/**
+* Determine whether this set is a superset of the set referenced by <code>otherSet</code>,
+* <BR><I> not yet available in RasDaMan. </BR></I>
+* @param otherSet Another set.
+* @return True if this set is a superset of the set referenced by <code>otherSet</code>,
+* otherwise false.
+*/
+ public boolean supersetOf(DSet otherSet);
+
+/**
+* Determine whether this set is a proper superset of the set referenced by
+* <code>otherSet</code>,
+* <BR><I> not yet available in RasDaMan. </BR></I>
+* @param otherSet Another set.
+* @return True if this set is a proper superset of the set referenced by
+* <code>otherSet</code>, otherwise false.
+*/
+ public boolean properSupersetOf(DSet otherSet);
+}
+
diff --git a/java/org/odmg/Database.class b/java/org/odmg/Database.class
new file mode 100644
index 0000000..e365844
--- /dev/null
+++ b/java/org/odmg/Database.class
Binary files differ
diff --git a/java/org/odmg/Database.java b/java/org/odmg/Database.java
new file mode 100644
index 0000000..6edd15c
--- /dev/null
+++ b/java/org/odmg/Database.java
@@ -0,0 +1,150 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+package org.odmg;
+
+/**
+* The interface for interacting with an ODMG database.
+* Databases must be opened before starting any transactions that use the database
+* and closed after ending these transactions.
+* <P>
+* A database application generally begins processing by accessing one or more
+* critical objects and proceeding from there. These objects are root objects,
+* because they lead to interconnected webs of other objects.
+* The ability to name an object (using method <code>bind</code>) and
+* retrieve it later by that name (using method <code>lookup</code> facilitates
+* this start-up capability. A name is not explicitly defined as an attribute of
+* an object. Naming an object also makes it persistent.
+* <P>
+* There is a single flat name scope per database; thus all names in a particular
+* database are unique.
+* @author David Jordan (as Java Editor of the Object Data Management Group)
+* @version ODMG 3.0
+*/
+
+public interface Database {
+/**
+* The database is not open.
+*/
+ public static final int NOT_OPEN = 0;
+
+/**
+* The database is opened for read-only access.
+*/
+ public static final int OPEN_READ_ONLY = 1;
+
+/**
+* The database is opened for reading and writing.
+*/
+ public static final int OPEN_READ_WRITE = 2;
+
+/**
+* The database is open for exclusive access.
+*/
+ public static final int OPEN_EXCLUSIVE = 3;
+
+/**
+* Open the named database with the specified access mode.
+* Attempts to open a database when it has already been opened will result in
+* the throwing of the exception <code>DatabaseOpenException</code>.
+* A <code>DatabaseNotFoundException</code> is thrown if the database does not exist.
+* Some implementations may throw additional exceptions that are also derived from
+* <code>ODMGException</code>.
+* @param name The name of the database.
+* @param accessMode The access mode, which should be one of the static fields:
+* <code>OPEN_READ_ONLY</code>, <code>OPEN_READ_WRITE</code>,
+* or <code>OPEN_EXCLUSIVE</code>.
+* @exception ODMGException The database could not be opened.
+*/
+ public void open(String name, int accessMode) throws ODMGException;
+
+/**
+* Close the database.
+* After you have closed a database, further attempts to access objects in the
+* database will cause the exception <code>DatabaseClosedException</code> to be thrown.
+* Some implementations may throw additional exceptions that are also derived
+* from <code>ODMGException</code>.
+* @exception ODMGException Unable to close the database.
+*/
+ public void close() throws ODMGException;
+
+/**
+* Associate a name with an object and make it persistent,
+* <BR><I> not yet available in RasDaMan. </BR></I>
+* An object instance may be bound to more than one name.
+* Binding a previously transient object to a name makes that object persistent.
+* @param object The object to be named.
+* @param name The name to be given to the object.
+* @exception org.odmg.ObjectNameNotUniqueException
+* If an attempt is made to bind a name to an object and that name is already bound
+* to an object.
+*/
+ public void bind(Object object, String name) throws ObjectNameNotUniqueException;
+
+/**
+* Lookup an object via its name,
+* <BR><I> not yet available in RasDaMan. </BR></I>
+* @param name The name of an object.
+* @return The object with that name.
+* @exception ObjectNameNotFoundException There is no object with the specified name.
+* @see ObjectNameNotFoundException
+*/
+ public Object lookup(String name) throws ObjectNameNotFoundException;
+
+/**
+* Disassociate a name with an object,
+* <BR><I> not yet available in RasDaMan. </BR></I>
+* @param name The name of an object.
+* @exception ObjectNameNotFoundException No object exists in the database with that name.
+*/
+ public void unbind(String name) throws ObjectNameNotFoundException;
+
+/**
+* Make a transient object durable in the database,
+* <BR><I> not yet available in RasDaMan. </BR></I>
+* It must be executed in the context of an open transaction.
+* If the transaction in which this method is executed commits,
+* then the object is made durable.
+* If the transaction aborts,
+* then the makePersistent operation is considered not to have been executed,
+* and the target object is again transient.
+* ClassNotPersistenceCapableException is thrown if the implementation cannot make
+* the object persistent because of the type of the object.
+* @param object The object to make persistent.
+*/
+ public void makePersistent(Object object);
+
+/**
+* Deletes an object from the database,
+* <BR><I> not yet available in RasDaMan. </BR></I>
+* It must be executed in the context of an open transaction.
+* If the object is not persistent, then ObjectNotPersistent is thrown.
+* If the transaction in which this method is executed commits,
+* then the object is removed from the database.
+* If the transaction aborts,
+* then the deletePersistent operation is considered not to have been executed,
+* and the target object is again in the database.
+* @param object The object to delete.
+*/
+ public void deletePersistent(Object object);
+}
+
diff --git a/java/org/odmg/DatabaseClosedException.class b/java/org/odmg/DatabaseClosedException.class
new file mode 100644
index 0000000..11a3969
--- /dev/null
+++ b/java/org/odmg/DatabaseClosedException.class
Binary files differ
diff --git a/java/org/odmg/DatabaseClosedException.java b/java/org/odmg/DatabaseClosedException.java
new file mode 100644
index 0000000..134e53c
--- /dev/null
+++ b/java/org/odmg/DatabaseClosedException.java
@@ -0,0 +1,51 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+package org.odmg;
+
+/**
+* This exception is thrown when an attempt is made to call a method
+* on a Database that has been closed or has not been opened.
+* @author David Jordan (as Java Editor of the Object Data Management Group)
+* @version ODMG 3.0
+* @see org.odmg.Database
+*/
+
+public class DatabaseClosedException extends ODMGRuntimeException
+{
+/**
+* Construct an instance of the exception without a message.
+*/
+ public DatabaseClosedException()
+ {
+ super();
+ }
+/**
+* Construct an instance of the exception with the provided message.
+* @param msg A message indicating why the exception occurred.
+*/
+ public DatabaseClosedException(String msg)
+ {
+ super(msg);
+ }
+}
+
diff --git a/java/org/odmg/DatabaseIsReadOnlyException.class b/java/org/odmg/DatabaseIsReadOnlyException.class
new file mode 100644
index 0000000..e56d554
--- /dev/null
+++ b/java/org/odmg/DatabaseIsReadOnlyException.class
Binary files differ
diff --git a/java/org/odmg/DatabaseIsReadOnlyException.java b/java/org/odmg/DatabaseIsReadOnlyException.java
new file mode 100644
index 0000000..4640372
--- /dev/null
+++ b/java/org/odmg/DatabaseIsReadOnlyException.java
@@ -0,0 +1,53 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+package org.odmg;
+
+/**
+* This exception is thrown when a call has been made that modifies
+* a database that is open in read-only mode.
+* @author David Jordan (as Java Editor of the Object Data Management Group)
+* @version ODMG 3.0
+* @see org.odmg.Database
+* @see org.odmg.ODMGRuntimeException
+*/
+
+public class DatabaseIsReadOnlyException extends ODMGRuntimeException
+{
+/**
+* Construct an instance of the exception without a message.
+*/
+ public DatabaseIsReadOnlyException()
+ {
+ super();
+ }
+
+/**
+* Construct an instance of the exception with a descriptive message.
+* @param msg A message indicating why the exception occurred.
+*/
+ public DatabaseIsReadOnlyException(String msg)
+ {
+ super(msg);
+ }
+}
+
diff --git a/java/org/odmg/DatabaseNotFoundException.class b/java/org/odmg/DatabaseNotFoundException.class
new file mode 100644
index 0000000..87a8eb1
--- /dev/null
+++ b/java/org/odmg/DatabaseNotFoundException.class
Binary files differ
diff --git a/java/org/odmg/DatabaseNotFoundException.java b/java/org/odmg/DatabaseNotFoundException.java
new file mode 100644
index 0000000..0151685
--- /dev/null
+++ b/java/org/odmg/DatabaseNotFoundException.java
@@ -0,0 +1,53 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+package org.odmg;
+
+/**
+* This exception is thrown when attempting to open a database that does not exist.
+* This could be caused by the name provided to <code>Database.open</code> being incorrect.
+* @author David Jordan (as Java Editor of the Object Data Management Group)
+* @version ODMG 3.0
+* @see org.odmg.Database#open
+*/
+
+public class DatabaseNotFoundException extends ODMGException
+{
+/**
+* Construct an instance of the exception.
+*/
+ public DatabaseNotFoundException()
+ {
+ super();
+ }
+
+
+/**
+* Construct an instance of the exception with a descriptive message.
+* @param msg A message indicating why the exception occurred.
+*/
+ public DatabaseNotFoundException(String msg)
+ {
+ super(msg);
+ }
+}
+
diff --git a/java/org/odmg/DatabaseOpenException.class b/java/org/odmg/DatabaseOpenException.class
new file mode 100644
index 0000000..d05e8b4
--- /dev/null
+++ b/java/org/odmg/DatabaseOpenException.class
Binary files differ
diff --git a/java/org/odmg/DatabaseOpenException.java b/java/org/odmg/DatabaseOpenException.java
new file mode 100644
index 0000000..f34238a
--- /dev/null
+++ b/java/org/odmg/DatabaseOpenException.java
@@ -0,0 +1,51 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+package org.odmg;
+
+/**
+* This exception is thrown when attempting to open a database that is already open.
+* @author David Jordan (as Java Editor of the Object Data Management Group)
+* @version ODMG 3.0
+* @see org.odmg.Database#open
+*/
+
+public class DatabaseOpenException extends ODMGException
+{
+/**
+* Construct an instance of the exception.
+*/
+ public DatabaseOpenException()
+ {
+ super();
+ }
+
+/**
+* Construct an instance of the exception with a descriptive message.
+* @param msg A message indicating why the exception occurred.
+*/
+ public DatabaseOpenException(String msg)
+ {
+ super(msg);
+ }
+}
+
diff --git a/java/org/odmg/Implementation.class b/java/org/odmg/Implementation.class
new file mode 100644
index 0000000..07165c9
--- /dev/null
+++ b/java/org/odmg/Implementation.class
Binary files differ
diff --git a/java/org/odmg/Implementation.java b/java/org/odmg/Implementation.java
new file mode 100644
index 0000000..f2d2e6f
--- /dev/null
+++ b/java/org/odmg/Implementation.java
@@ -0,0 +1,113 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+package org.odmg;
+
+/**
+* The factory interface for a particular ODMG implementation.
+* Each ODMG implementation will have a class that implements this interface.
+* @author David Jordan (as Java Editor of the Object Data Management Group)
+* @version ODMG 3.0
+*/
+
+public interface Implementation {
+/**
+* Create a <code>Transaction</code> object and associate it with the current thread.
+* @return The newly created <code>Transaction</code> instance.
+* @see org.odmg.Transaction
+*/
+ public Transaction newTransaction();
+
+/**
+* Get the current <code>Transaction</code> for the thread.
+* @return The current <code>Transaction</code> object or null if there is none.
+* @see org.odmg.Transaction
+*/
+ public Transaction currentTransaction();
+
+/**
+* Create a new <code>Database</code> object.
+* @return The new <code>Database</code> object.
+* @see org.odmg.Database
+*/
+ public Database newDatabase();
+
+/**
+* Create a new <code>OQLQuery</code> object.
+* @return The new <code>OQLQuery</code> object.
+* @see org.odmg.OQLQuery
+*/
+ public OQLQuery newOQLQuery();
+
+/**
+* Create a new <code>DList</code> object.
+* @return The new <code>DList</code> object.
+* @see org.odmg.DList
+*/
+ public DList newDList();
+
+/**
+* Create a new <code>DBag</code> object.
+* @return The new <code>DBag</code> object.
+* @see org.odmg.DBag
+*/
+ public DBag newDBag();
+
+/**
+* Create a new <code>DSet</code> object.
+* @return The new <code>DSet</code> object.
+* @see org.odmg.DSet
+*/
+ public DSet newDSet();
+
+/**
+* Create a new <code>DArray</code> object,
+* <BR><I> not yet available in RasDaMan. </BR></I>
+* @return The new <code>DArray</code> object.
+* @see org.odmg.DArray
+*/
+ public DArray newDArray();
+
+/**
+* Create a new <code>DMap</code> object,
+* <BR><I> not yet available in RasDaMan. </BR></I>
+* @return The new <code>DMap</code> object.
+* @see org.odmg.DMap
+*/
+ public DMap newDMap();
+
+/**
+* Get a <code>String</code> representation of the object's identifier.
+* @param obj The object whose identifier is being accessed.
+* @return The object's identifier in the form of a String
+*/
+ public String getObjectId(Object obj);
+
+/**
+* Get the <code>Database</code> that contains the object <code>obj</code>,
+* <BR><I> not yet available in RasDaMan. </BR></I>
+* @param obj The object.
+* @return The <code>Database</code> that contains the object.
+*/
+ public Database getDatabase(Object obj);
+}
+
diff --git a/java/org/odmg/LockNotGrantedException.class b/java/org/odmg/LockNotGrantedException.class
new file mode 100644
index 0000000..b5e7928
--- /dev/null
+++ b/java/org/odmg/LockNotGrantedException.class
Binary files differ
diff --git a/java/org/odmg/LockNotGrantedException.java b/java/org/odmg/LockNotGrantedException.java
new file mode 100644
index 0000000..4287d2c
--- /dev/null
+++ b/java/org/odmg/LockNotGrantedException.java
@@ -0,0 +1,66 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+package org.odmg;
+
+/**
+* This exception is thrown if a lock could not be granted on an object.
+* @author David Jordan (as Java Editor of the Object Data Management Group)
+* @version ODMG 3.0
+*/
+
+public class LockNotGrantedException extends ODMGRuntimeException
+{
+/**
+* Construct an instance of the exception.
+*/
+ public LockNotGrantedException()
+ {
+ super();
+ }
+
+/**
+* Construct an instance of the exception with a descriptive message.
+* @param msg A description of the exception.
+*/
+ public LockNotGrantedException(String msg)
+ {
+ super(msg);
+ }
+/*
+ private Object o;
+ private int m;
+*
+* Construct an instance of the exception.
+* @param obj The object that the application was trying to acquire a lock on.
+* @param mode The lock mode that the application was attempting to acquire.
+* @see org.odmg.Transaction#lock
+*
+ public LockNotGrantedException(Object obj, int mode)
+ {
+ super();
+ o = obj;
+ m = mode;
+ }
+*/
+}
+
diff --git a/java/org/odmg/Makefile b/java/org/odmg/Makefile
new file mode 100644
index 0000000..a50c9b4
--- /dev/null
+++ b/java/org/odmg/Makefile
@@ -0,0 +1,66 @@
+# -*-Makefile-*- (for Emacs)
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>. # Top Level makefile. This points to the various modules that have to be build
+# and/or deployed
+#
+# MAKEFILE FOR:
+# package RasJ
+#
+# COMMENTS:
+#
+##################################################################
+######################### Definitions ############################
+
+# standard include with general options
+include $(RMANBASE)/Makefile.inc
+
+# directory where HTML documentation is created
+DOCDIR := $(DOCBASE)/java/org
+
+########################### Targets ##############################
+
+SRCS = DArray.java DatabaseOpenException.java ObjectNotPersistentException.java \
+ DBag.java Implementation.java QueryException.java DCollection.java \
+ LockNotGrantedException.java QueryInvalidException.java \
+ DList.java NotImplementedException.java QueryParameterCountInvalidException.java \
+ DMap.java ODMGException.java QueryParameterTypeInvalidException.java \
+ DSet.java ODMGRuntimeException.java Transaction.java Database.java \
+ OQLQuery.java TransactionAbortedException.java DatabaseClosedException.java \
+ ObjectDeletedException.java TransactionInProgressException.java \
+ DatabaseIsReadOnlyException.java DatabaseNotFoundException.java ObjectNameNotFoundException.java \
+ TransactionNotInProgressException.java
+OBJS = ${SRCS:%.java=%.class}
+MISCCLEAN = *.class
+
+########################### Targets ##############################
+
+# compile everything
+.PHONY : all
+all: $(OBJS)
+
+
+# delete all files
+empty:
+ -rm -f $(SRCS) $(MISCCLEAN)
+
+# general rules
+include $(RMANBASE)/Makefile.rel
diff --git a/java/org/odmg/Makefile.dep b/java/org/odmg/Makefile.dep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/java/org/odmg/Makefile.dep
diff --git a/java/org/odmg/NotImplementedException.class b/java/org/odmg/NotImplementedException.class
new file mode 100644
index 0000000..31eef9e
--- /dev/null
+++ b/java/org/odmg/NotImplementedException.class
Binary files differ
diff --git a/java/org/odmg/NotImplementedException.java b/java/org/odmg/NotImplementedException.java
new file mode 100644
index 0000000..db90b14
--- /dev/null
+++ b/java/org/odmg/NotImplementedException.java
@@ -0,0 +1,49 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+package org.odmg;
+/**
+* This exception is thrown when an implementation does not support an operation.
+* @author David Jordan (as Java Editor of the Object Data Management Group)
+* @version ODMG 3.0
+*/
+
+public class NotImplementedException extends ODMGRuntimeException
+{
+/**
+* Construct an instance of the exception.
+*/
+ public NotImplementedException()
+ {
+ super();
+ }
+
+/**
+* Construct an instance of the exception.
+* @param msg A string providing a description of the exception.
+*/
+ public NotImplementedException(String msg)
+ {
+ super(msg);
+ }
+}
diff --git a/java/org/odmg/ODMGException.class b/java/org/odmg/ODMGException.class
new file mode 100644
index 0000000..1333641
--- /dev/null
+++ b/java/org/odmg/ODMGException.class
Binary files differ
diff --git a/java/org/odmg/ODMGException.java b/java/org/odmg/ODMGException.java
new file mode 100644
index 0000000..866bec5
--- /dev/null
+++ b/java/org/odmg/ODMGException.java
@@ -0,0 +1,49 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+package org.odmg;
+
+/**
+* This is the base class for all exceptions thrown by an ODMG implementation.
+* @author David Jordan (as Java Editor of the Object Data Management Group)
+* @version ODMG 3.0
+*/
+
+public class ODMGException extends Exception {
+/**
+* Construct an <code>ODMGException</code> object without an error message.
+*/
+ public ODMGException()
+ {
+ super();
+ }
+/**
+* Construct an <code>ODMGException</code> object with an error message.
+* @param msg The error message associated with this exception.
+*/
+
+ public ODMGException(String msg)
+ {
+ super(msg);
+ }
+}
+
diff --git a/java/org/odmg/ODMGRuntimeException.class b/java/org/odmg/ODMGRuntimeException.class
new file mode 100644
index 0000000..d5182c6
--- /dev/null
+++ b/java/org/odmg/ODMGRuntimeException.class
Binary files differ
diff --git a/java/org/odmg/ODMGRuntimeException.java b/java/org/odmg/ODMGRuntimeException.java
new file mode 100644
index 0000000..c124d00
--- /dev/null
+++ b/java/org/odmg/ODMGRuntimeException.java
@@ -0,0 +1,50 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+package org.odmg;
+
+/**
+* This is the base class for all RuntimeExceptions thrown by an ODMG implementation.
+* @author David Jordan (as Java Editor of the Object Data Management Group)
+* @version ODMG 3.0
+*/
+
+public class ODMGRuntimeException extends RuntimeException {
+
+/**
+* Construct an instance of the exception.
+*/
+ public ODMGRuntimeException()
+ {
+ super();
+ }
+
+/**
+* Construct an instance of the exception with the specified message.
+* @param msg The message associated with the exception.
+*/
+ public ODMGRuntimeException(String msg)
+ {
+ super(msg);
+ }
+}
+
diff --git a/java/org/odmg/OQLQuery.class b/java/org/odmg/OQLQuery.class
new file mode 100644
index 0000000..5910baa
--- /dev/null
+++ b/java/org/odmg/OQLQuery.class
Binary files differ
diff --git a/java/org/odmg/OQLQuery.java b/java/org/odmg/OQLQuery.java
new file mode 100644
index 0000000..9d09c4f
--- /dev/null
+++ b/java/org/odmg/OQLQuery.java
@@ -0,0 +1,86 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+package org.odmg;
+
+/**
+* The interface to an OQL query object.
+* @author David Jordan (as Java Editor of the Object Data Management Group)
+* @version ODMG 3.0
+*/
+
+public interface OQLQuery {
+
+/**
+* Create an OQL query from the string parameter.
+* In order to execute a query, an <code>OQLQuery</code> object must be created
+* by calling <code>Implementation.newOQLQuery</code>, then calling the
+* <code>create</code> method with the query string.
+* The <code>create</code> method might throw <code>QueryInvalidException</code>
+* if the query could not be compiled properly. Some implementations may not want
+* to compile the query before <code>execute</code> is called. In this case
+* <code>QueryInvalidException</code> is thrown when <code>execute</code> is called.
+* @param query An OQL query.
+* @exception QueryInvalidException The query syntax is invalid.
+*/
+ public void create(String query) throws QueryInvalidException;
+
+/**
+* Bind a parameter to the query.
+* A parameter is denoted in the query string passed to <code>create</code> by <i>$i</i>,
+* where <i>i</i> is the rank of the parameter, beginning with 1.
+* The parameters are set consecutively by calling this method <code>bind</code>.
+* The <i>ith</i> variable is set by the <i>ith</i> call to the <code>bind</code> method.
+* If any of the <i>$i</i> are not set by a call to <code>bind</code> at the point
+* <code>execute</code> is called, <code>QueryParameterCountInvalidException</code> is thrown.
+* The parameters must be objects, and the result is an <code>Object</code>.
+* Objects must be used instead of primitive types (<code>Integer</code> instead
+* of <code>int</code>) for passing the parameters.
+* <P>
+* If the parameter is of the wrong type,
+* <code>QueryParameterTypeInvalidException</code> is thrown.
+* After executing a query, the parameter list is reset.
+* @param parameter A value to be substituted for a query parameter.
+* @exception QueryParameterCountInvalidException The number of calls to
+* <code>bind</code> has exceeded the number of parameters in the query.
+* @exception QueryParameterTypeInvalidException The type of the parameter does
+* not correspond with the type of the parameter in the query.
+*/
+ public void bind(Object parameter) throws QueryParameterCountInvalidException,
+ QueryParameterTypeInvalidException;
+
+/**
+* Execute the query.
+* After executing a query, the parameter list is reset.
+* Some implementations may throw additional exceptions that are also derived
+* from <code>ODMGException</code>.
+* @return The object that represents the result of the query.
+* The returned data, whatever its OQL type, is encapsulated into an object.
+* For instance, when OQL returns an integer, the result is put into an
+* <code>Integer</code> object. When OQL returns a collection (literal or object),
+* the result is always a Java collection object of the same kind
+* (for instance, a <code>DList</code>).
+* @exception QueryException An exception has occurred while executing the query.
+*/
+ public Object execute() throws QueryException;
+}
+
diff --git a/java/org/odmg/ObjectDeletedException.class b/java/org/odmg/ObjectDeletedException.class
new file mode 100644
index 0000000..962c25d
--- /dev/null
+++ b/java/org/odmg/ObjectDeletedException.class
Binary files differ
diff --git a/java/org/odmg/ObjectDeletedException.java b/java/org/odmg/ObjectDeletedException.java
new file mode 100644
index 0000000..dfdcc6c
--- /dev/null
+++ b/java/org/odmg/ObjectDeletedException.java
@@ -0,0 +1,50 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+package org.odmg;
+
+/**
+* This exception is thrown when accessing an object that was deleted.
+* @author David Jordan (as Java Editor of the Object Data Management Group)
+* @version ODMG 3.0
+*/
+
+public class ObjectDeletedException extends ODMGRuntimeException
+{
+
+/**
+* Construct an instance of the exception.
+*/
+ public ObjectDeletedException()
+ {
+ super();
+ }
+
+/**
+* Construct an instance of the exception.
+* @param msg A string providing a description of the exception.
+*/
+ public ObjectDeletedException(String msg)
+ {
+ super(msg);
+ }
+}
diff --git a/java/org/odmg/ObjectNameNotFoundException.class b/java/org/odmg/ObjectNameNotFoundException.class
new file mode 100644
index 0000000..fcc0b2b
--- /dev/null
+++ b/java/org/odmg/ObjectNameNotFoundException.class
Binary files differ
diff --git a/java/org/odmg/ObjectNameNotFoundException.java b/java/org/odmg/ObjectNameNotFoundException.java
new file mode 100644
index 0000000..a0f4e01
--- /dev/null
+++ b/java/org/odmg/ObjectNameNotFoundException.java
@@ -0,0 +1,74 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+package org.odmg;
+
+/**
+* An attempt to get a object via its name using <code>Database.lookup</code>
+* and the name is not associated with an object in the database.
+* @author David Jordan (as Java Editor of the Object Data Management Group)
+* @version ODMG 3.0
+* @see org.odmg.Database#lookup
+*/
+
+public class ObjectNameNotFoundException extends ODMGException
+{
+/**
+* Construct an instance of the exception.
+*/
+ public ObjectNameNotFoundException()
+ {
+ super();
+ }
+
+/**
+* Construct an instance of the exception with a descriptive message.
+* @param msg A message describing the exception.
+*/
+ public ObjectNameNotFoundException(String msg)
+ {
+ super(msg);
+ }
+/*
+ private String n;
+
+* Construct an instance of the exception.
+* @param name The name passed to Database.lookup that is not associated with
+* any object in the database.
+
+ public ObjectNameNotFoundException(String name)
+ {
+ super();
+ n = name;
+ }
+
+
+* Access the name that is not bound to any object in the database.
+* @return The name that was passed to Database.lookup.
+
+ public String getName()
+ {
+ return n;
+ }
+*/
+}
+
diff --git a/java/org/odmg/ObjectNameNotUniqueException.class b/java/org/odmg/ObjectNameNotUniqueException.class
new file mode 100644
index 0000000..99573a6
--- /dev/null
+++ b/java/org/odmg/ObjectNameNotUniqueException.class
Binary files differ
diff --git a/java/org/odmg/ObjectNameNotUniqueException.java b/java/org/odmg/ObjectNameNotUniqueException.java
new file mode 100644
index 0000000..8d18ae7
--- /dev/null
+++ b/java/org/odmg/ObjectNameNotUniqueException.java
@@ -0,0 +1,80 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+package org.odmg;
+
+/**
+* This exception is thrown when attempting to bind a name to an object
+* when the name is already bound to another object.
+* @author David Jordan (as Java Editor of the Object Data Management Group)
+* @version ODMG 3.0
+* @see org.odmg.Database#bind
+*/
+
+public class ObjectNameNotUniqueException extends ODMGException
+{
+/**
+* Construct an instance of the exception.
+*/
+ public ObjectNameNotUniqueException()
+ {
+ super();
+ }
+
+/**
+* Construct an instance of the exception with a descriptive message.
+* @param msg A message containing a description of the exception.
+*/
+ public ObjectNameNotUniqueException(String msg)
+ {
+ super(msg);
+ }
+/*
+ private Object o;
+ private String n;
+ public ObjectNameNotUniqueException(Object obj, String name)
+ {
+ super();
+ o = obj;
+ n = name;
+ }
+
+
+* Get the object that was passed to Database.bind.
+* @return The object that was being bound to a name.
+
+ public Object getObject()
+ {
+ return o;
+ }
+
+
+* Get the name that is not unique.
+* @return The name that is already associated with another object.
+
+ public String getName()
+ {
+ return n;
+ }
+*/
+}
+
diff --git a/java/org/odmg/ObjectNotPersistentException.class b/java/org/odmg/ObjectNotPersistentException.class
new file mode 100644
index 0000000..c3f015d
--- /dev/null
+++ b/java/org/odmg/ObjectNotPersistentException.class
Binary files differ
diff --git a/java/org/odmg/ObjectNotPersistentException.java b/java/org/odmg/ObjectNotPersistentException.java
new file mode 100644
index 0000000..15dbfdf
--- /dev/null
+++ b/java/org/odmg/ObjectNotPersistentException.java
@@ -0,0 +1,49 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+package org.odmg;
+
+/**
+* This exception is thrown when deleting an object that is not persistent.
+* @author David Jordan (as Java Editor of the Object Data Management Group)
+* @version ODMG 3.0
+*/
+
+public class ObjectNotPersistentException extends ODMGRuntimeException {
+
+/**
+* Construct an instance of the exception.
+*/
+ public ObjectNotPersistentException()
+ {
+ super();
+ }
+
+/**
+* Construct an instance of the exception.
+* @param msg A string providing a description of the exception.
+*/
+ public ObjectNotPersistentException(String msg)
+ {
+ super(msg);
+ }
+}
diff --git a/java/org/odmg/QueryException.class b/java/org/odmg/QueryException.class
new file mode 100644
index 0000000..dda9522
--- /dev/null
+++ b/java/org/odmg/QueryException.class
Binary files differ
diff --git a/java/org/odmg/QueryException.java b/java/org/odmg/QueryException.java
new file mode 100644
index 0000000..ab7a855
--- /dev/null
+++ b/java/org/odmg/QueryException.java
@@ -0,0 +1,50 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+package org.odmg;
+
+/**
+* This is the base class for all exceptions associated with queries.
+* @author David Jordan (as Java Editor of the Object Data Management Group)
+* @version ODMG 3.0
+*/
+
+public class QueryException extends ODMGException {
+/**
+* Constructs an instance of the exception.
+*/
+ public QueryException()
+ {
+ super();
+ }
+
+/**
+* Constructs an instance of the exception with a message indicating the reason
+* for the exception.
+* @param msg A message indicating the reason for the exception.
+*/
+ public QueryException(String msg)
+ {
+ super(msg);
+ }
+}
+
diff --git a/java/org/odmg/QueryInvalidException.class b/java/org/odmg/QueryInvalidException.class
new file mode 100644
index 0000000..59b997d
--- /dev/null
+++ b/java/org/odmg/QueryInvalidException.class
Binary files differ
diff --git a/java/org/odmg/QueryInvalidException.java b/java/org/odmg/QueryInvalidException.java
new file mode 100644
index 0000000..25ea648
--- /dev/null
+++ b/java/org/odmg/QueryInvalidException.java
@@ -0,0 +1,51 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+package org.odmg;
+
+/**
+* This exception is thrown if the query is not a valid OQL query.
+* @author David Jordan (as Java Editor of the Object Data Management Group)
+* @version ODMG 3.0
+*/
+
+public class QueryInvalidException extends QueryException
+{
+/**
+* Construct an instance of the exception.
+*/
+ public QueryInvalidException()
+ {
+ super();
+ }
+
+/**
+* Construct an instance of the exception.
+* @param msg A string indicating why the <code>OQLQuery</code> instance does not
+* represent a valid OQL query.
+*/
+ public QueryInvalidException(String msg)
+ {
+ super(msg);
+ }
+}
+
diff --git a/java/org/odmg/QueryParameterCountInvalidException.class b/java/org/odmg/QueryParameterCountInvalidException.class
new file mode 100644
index 0000000..906976d
--- /dev/null
+++ b/java/org/odmg/QueryParameterCountInvalidException.class
Binary files differ
diff --git a/java/org/odmg/QueryParameterCountInvalidException.java b/java/org/odmg/QueryParameterCountInvalidException.java
new file mode 100644
index 0000000..c14fc47
--- /dev/null
+++ b/java/org/odmg/QueryParameterCountInvalidException.java
@@ -0,0 +1,51 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+package org.odmg;
+
+/**
+* This exception is thrown when the number of bound parameters for a query
+* does not match the number of placeholders.
+* @author David Jordan (as Java Editor of the Object Data Management Group)
+* @version ODMG 3.0
+*/
+
+public class QueryParameterCountInvalidException extends QueryException
+{
+/**
+* Construct an instance of the exception.
+*/
+ public QueryParameterCountInvalidException()
+ {
+ super();
+ }
+
+/**
+* Construct an instance of the exception with a message.
+* @param msg A message indicating why the exception has been thrown.
+*/
+ public QueryParameterCountInvalidException(String msg)
+ {
+ super(msg);
+ }
+}
+
diff --git a/java/org/odmg/QueryParameterTypeInvalidException.class b/java/org/odmg/QueryParameterTypeInvalidException.class
new file mode 100644
index 0000000..0c0aabb
--- /dev/null
+++ b/java/org/odmg/QueryParameterTypeInvalidException.class
Binary files differ
diff --git a/java/org/odmg/QueryParameterTypeInvalidException.java b/java/org/odmg/QueryParameterTypeInvalidException.java
new file mode 100644
index 0000000..7ce81ea
--- /dev/null
+++ b/java/org/odmg/QueryParameterTypeInvalidException.java
@@ -0,0 +1,51 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+package org.odmg;
+
+/**
+* This exception is thrown when the type of a query parameter
+* is not compatible with the expected type.
+* @author David Jordan (as Java Editor of the Object Data Management Group)
+* @version ODMG 3.0
+*/
+
+public class QueryParameterTypeInvalidException extends QueryException
+{
+/**
+* Construct an instance of the exception.
+*/
+ public QueryParameterTypeInvalidException()
+ {
+ super();
+ }
+
+/**
+* Construct an instance of the exception with a message.
+* @param msg The message explaining details of the exception.
+*/
+ public QueryParameterTypeInvalidException(String msg)
+ {
+ super(msg);
+ }
+}
+
diff --git a/java/org/odmg/Transaction.class b/java/org/odmg/Transaction.class
new file mode 100644
index 0000000..0f5095b
--- /dev/null
+++ b/java/org/odmg/Transaction.class
Binary files differ
diff --git a/java/org/odmg/Transaction.java b/java/org/odmg/Transaction.java
new file mode 100644
index 0000000..9cfb2b8
--- /dev/null
+++ b/java/org/odmg/Transaction.java
@@ -0,0 +1,165 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+package org.odmg;
+
+/**
+* This interfaces provides the operations necessary to perform database transactions.
+* All access, creation, and modification of persistent objects and their fields
+* must be done within a transaction. Before performing any database operations,
+* a thread must explicitly create a transaction object or associate itself with
+* an existing transaction object (by calling <code>join</code>),
+* and that transaction must be open (through a call to <code>begin</code>).
+* All subsequent operations by the thread, including reads, writes, and lock
+* acquisitions, are done under the thread’s current transaction.
+* <P>
+* A thread may only operate on its current transaction. For example,
+* a <code>TransactionNotInProgressException</code> is thrown if a thread attempts
+* to begin, commit, checkpoint, or abort a transaction prior to joining itself
+* to that transaction.
+* <P>
+* A transaction is either <i>open</i> or <i>closed</i>. A transaction is open if a call
+* has been made to <code>begin</code>, but no call has been made to <code>commit</code> or
+* <code>abort</code>. Once <code>commit</code> or <code>abort</code> is called,
+* the transaction is closed. The method <code>isOpen</code> can be called to
+* determine the state of the transaction.
+* <P>
+* Read locks are implicitly obtained on objects as they are accessed.
+* Write locks are implicitly obtained as objects are modified.
+* <code>Transaction</code> objects are transient, they cannot be stored in the database.
+* @author David Jordan (as Java Editor of the Object Data Management Group)
+* @version ODMG 3.0
+* @see TransactionNotInProgressException
+*/
+
+public interface Transaction {
+/**
+* Attach the caller's thread to this <code>Transaction</code> and detach the thread
+* from any former <code>Transaction</code> the thread may have been associated with,
+* <BR><I> not yet available in rasdaman. </BR></I>
+*/
+ public void join();
+
+/**
+* Detach the caller's thread from this <code>Transaction</code>, but do not attach
+* the thread to another <code>Transaction</code>,
+* <BR><I> not yet available in rasdaman. </BR></I>
+*/
+ public void leave();
+
+/**
+* Start a transaction.
+* Calling <code>begin</code> multiple times on the same transaction object,
+* without an intervening call to <code>commit</code> or <code>abort</code>,
+* causes the exception <code>TransactionInProgressException</code> to be thrown
+* on the second and subsequent calls. Operations executed before a transaction
+* has been opened, or before reopening after a transaction is aborted or committed,
+* have undefined results;
+* these may throw a <code>TransactionNotInProgressException</code> exception.
+*/
+ public void begin();
+
+/**
+* Determine whether the transaction is open or not.
+* A transaction is open if a call has been made to <code>begin</code>,
+* but a subsequent call to either <code>commit</code> or <code>abort</code>
+* has not been made.
+* @return True if the transaction is open, otherwise false.
+*/
+ public boolean isOpen();
+
+/**
+* Commit and close the transaction.
+* Calling <code>commit</code> commits to the database all persistent object
+* modifications within the transaction and releases any locks held by the transaction.
+* A persistent object modification is an update of any field of an existing
+* persistent object, or an update or creation of a new named object in the database.
+* If a persistent object modification results in a reference from an existing
+* persistent object to a transient object, the transient object is moved to the
+* database, and all references to it updated accordingly. Note that the act of
+* moving a transient object to the database may create still more persistent
+* references to transient objects, so its referents must be examined and moved as well.
+* This process continues until the database contains no references to transient objects,
+* a condition that is guaranteed as part of transaction commit.
+* Committing a transaction does not remove from memory transient objects created
+* during the transaction
+*/
+ public void commit();
+
+/**
+* Abort and close the transaction.
+* Calling abort abandons all persistent object modifications and releases the
+* associated locks.
+* Aborting a transaction does not restore the state of modified transient objects
+*/
+ public void abort();
+
+/**
+* Commit the transaction, but reopen the transaction, retaining all locks.
+* Calling <code>checkpoint</code> commits persistent object modifications made
+* within the transaction since the last checkpoint to the database.
+* The transaction retains all locks it held on those objects at the time the
+* checkpoint was invoked.
+*/
+ public void checkpoint();
+
+/**
+* Read lock mode.
+*/
+ public static final int READ = 1;
+
+/**
+* Upgrade lock mode.
+*/
+ public static final int UPGRADE = 2;
+
+/**
+* Write lock mode.
+*/
+ public static final int WRITE = 4;
+
+/**
+* Upgrade the lock on the given object to the given lock mode,
+* <BR><I> not yet available in rasdaman. </BR></I>
+* The call has no effect if the object's current lock is already at or above
+* that level of lock mode.
+* @param obj The object to acquire a lock on.
+* @param lockMode The lock mode to acquire. The lock modes are <code>READ</code>,
+* <code>UPGRADE</code>, and <code>WRITE</code>.
+* @exception LockNotGrantedException Is thrown if the given lock mode could not be acquired.
+*/
+ public void lock(Object obj, int lockMode)
+ throws LockNotGrantedException;
+/**
+* Upgrade the lock on the given object to the given lock mode,
+* <BR><I> not yet available in rasdaman. </BR></I>
+* Method <code>tryLock</code> is the same as <code>lock</code> except it returns
+* a boolean indicating whether the lock was granted instead of generating an exception.
+* @param obj The object to acquire a lock on.
+* @param lockMode The lock mode to acquire. The lock modes are <code>READ</code>,
+* <code>UPGRADE</code>, and <code>WRITE</code>.
+* @return True if the lock has been acquired, otherwise false.
+*/
+ public boolean tryLock(Object obj, int lockMode);
+
+}
+
diff --git a/java/org/odmg/TransactionAbortedException.class b/java/org/odmg/TransactionAbortedException.class
new file mode 100644
index 0000000..d696a8a
--- /dev/null
+++ b/java/org/odmg/TransactionAbortedException.class
Binary files differ
diff --git a/java/org/odmg/TransactionAbortedException.java b/java/org/odmg/TransactionAbortedException.java
new file mode 100644
index 0000000..0a1d0d3
--- /dev/null
+++ b/java/org/odmg/TransactionAbortedException.java
@@ -0,0 +1,52 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+package org.odmg;
+
+/**
+* This exception is thrown when the database asynchronously and explicitly
+* aborts the user's transaction due to some failure, the user's data is reset
+* just as if the user had directly called <code>Transaction.abort</code>.
+* @author David Jordan (as Java Editor of the Object Data Management Group)
+* @version ODMG 3.0
+*/
+
+public class TransactionAbortedException extends ODMGRuntimeException
+{
+/**
+* Constructs an instance of the exception.
+*/
+ public TransactionAbortedException()
+ {
+ super();
+ }
+
+/**
+* Constructs an instance of the exception with the provided message.
+* @param msg The message that describes the exception.
+*/
+ public TransactionAbortedException(String msg)
+ {
+ super(msg);
+ }
+}
+
diff --git a/java/org/odmg/TransactionInProgressException.class b/java/org/odmg/TransactionInProgressException.class
new file mode 100644
index 0000000..253a599
--- /dev/null
+++ b/java/org/odmg/TransactionInProgressException.class
Binary files differ
diff --git a/java/org/odmg/TransactionInProgressException.java b/java/org/odmg/TransactionInProgressException.java
new file mode 100644
index 0000000..1d1f908
--- /dev/null
+++ b/java/org/odmg/TransactionInProgressException.java
@@ -0,0 +1,51 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+package org.odmg;
+
+/**
+* This exception is thrown when a call has been made to a method that
+* should not be called when a transaction is in progress.
+* @author David Jordan (as Java Editor of the Object Data Management Group)
+* @version ODMG 3.0
+*/
+
+public class TransactionInProgressException extends ODMGRuntimeException
+{
+/**
+* Constructs an instance of the exception.
+*/
+ public TransactionInProgressException()
+ {
+ super();
+ }
+
+/**
+* Constructs an instance of the exception with the provided message.
+* @param msg The message explaining the exception.
+*/
+ public TransactionInProgressException(String msg)
+ {
+ super(msg);
+ }
+}
+
diff --git a/java/org/odmg/TransactionNotInProgressException.class b/java/org/odmg/TransactionNotInProgressException.class
new file mode 100644
index 0000000..2fa74e5
--- /dev/null
+++ b/java/org/odmg/TransactionNotInProgressException.class
Binary files differ
diff --git a/java/org/odmg/TransactionNotInProgressException.java b/java/org/odmg/TransactionNotInProgressException.java
new file mode 100644
index 0000000..9770671
--- /dev/null
+++ b/java/org/odmg/TransactionNotInProgressException.java
@@ -0,0 +1,53 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+package org.odmg;
+
+/**
+* This exception is thrown when attempting to perform an operation that
+* must be performed when there is a transaction is in progress, but no
+* such transaction is in progress.
+* @author David Jordan (as Java Editor of the Object Data Management Group)
+* @version ODMG 3.0
+* @see ODMGRuntimeException
+*/
+
+public class TransactionNotInProgressException extends ODMGRuntimeException
+{
+/**
+* Constructs an instance of the exception.
+*/
+ public TransactionNotInProgressException()
+ {
+ super();
+ }
+
+/**
+* Constructs an instance of the exception with the provided message.
+* @param msg A message that describes the exception.
+*/
+ public TransactionNotInProgressException(String msg)
+ {
+ super(msg);
+ }
+}
+
diff --git a/java/rasj/Makefile b/java/rasj/Makefile
new file mode 100644
index 0000000..b0e86e8
--- /dev/null
+++ b/java/rasj/Makefile
@@ -0,0 +1,102 @@
+# -*-Makefile-*- (for Emacs)
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>. # Top Level makefile. This points to the various modules that have to be build
+# and/or deployed
+#
+# MAKEFILE FOR:
+# package RasJ
+#
+# COMMENTS:
+# - FIXME: needs Makefile.rel for java.class rule, but Makefile.rel
+# should be reserved for RDBMS modules
+##################################################################
+######################### Definitions ############################
+
+# standard include with general options
+include $(RMANBASE)/Makefile.inc
+
+
+SRCS = RasBaseType.java RasClientInternalException.java RasCollectionType.java \
+ RasConnectionFailedException.java RasDimensionMismatchException.java \
+ RasException.java RasFastScale.java RasGMArray.java RasIllegalULongValueException.java \
+ RasIllegalUShortValueException.java RasImplementation.java RasImplementationInterface.java \
+ RasIndexOutOfBoundsException.java RasInvalidNameException.java RasMArrayByte.java \
+ RasMArrayDouble.java RasMArrayFloat.java RasMArrayInteger.java RasMArrayLong.java \
+ RasMArrayShort.java RasMArrayType.java RasMInterval.java RasMIntervalType.java \
+ RasOIDType.java RasPoint.java RasPointType.java RasPrimitiveType.java \
+ RasQueryExecutionFailedException.java RasResultIsNoCellException.java \
+ RasResultIsNoIntervalException.java RasRuntimeException.java RasSInterval.java \
+ RasSIntervalType.java RasStorageLayout.java RasStreamInputOverflowException.java \
+ RasStructureType.java RasType.java RasTypeInvalidException.java \
+ RasTypeNotSupportedException.java RasTypeUnknownException.java
+OBJS = ${SRCS:%.java=%.class}
+MISCCLEAN = *.class
+
+# directory where HTML documentation is created
+DOCDIR_JAVA := $(DOCBASE)/rasj/
+
+########################### Targets ##############################
+
+# compile everything
+.PHONY : all
+all: $(OBJS)
+ cd clientcommhttp; $(MAKE)
+ cd odmg; $(MAKE)
+ cd global; $(MAKE)
+ cd rnp; $(MAKE)
+
+# run test suite
+.PHONY: systemtest
+systemtest:
+ cd test; $(MAKE) systemtest
+
+# generate HTML doc
+.PHONY: docu
+docu:
+ mkdir -p $(DOCDIR_RASJ)
+ $(JAVADOC) -breakiterator -private -author -d $(DOCDIR_RASJ) -sourcepath $(RMANBASE)/java \
+ rasj rasj.clientcommhttp rasj.odmg rasj.global rasdaview org.odmg examples
+ chmod -R g+w $(DOCDIR_RASJ)
+ cd test; $(MAKE) docu
+
+# delete classes
+.PHONY : clean
+clean:
+ -rm -f $(MISCCLEAN)
+ cd clientcommhttp; $(MAKE) clean
+ cd odmg; $(MAKE) clean
+ cd global; $(MAKE) clean
+ cd test; $(MAKE) clean
+ cd rnp; $(MAKE) clean
+
+# report environment used:
+check:
+ echo CLASSPATH=$(CLASSPATH)
+ echo PATH=$(PATH)
+ echo JAVA_HOME=$(JAVA_HOME)
+ echo JSDK_HOME=$(JSDK_HOME)
+ java -version
+
+############################ Dependencies #######################
+
+# FIXME: remove this dependency, establish .java.class rule in a general place
+include $(RMANBASE)/Makefile.rel
diff --git a/java/rasj/Makefile.dep b/java/rasj/Makefile.dep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/java/rasj/Makefile.dep
diff --git a/java/rasj/RasBaseType.java b/java/rasj/RasBaseType.java
new file mode 100644
index 0000000..53add89
--- /dev/null
+++ b/java/rasj/RasBaseType.java
@@ -0,0 +1,109 @@
+package rasj;
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * This class represents the Base types and is the superclass of
+ * the types RasStructureType and RasPrimitiveType in the
+ * representation of the RasDaMan type system.
+ * <P>
+ * <B>Note:</B> if a new base type is created using this class, it is only known on client-side but not
+ * stored within the database. If you want to introduce a new type for the RasDaMan system, you
+ * should use the "rasdl" utility.
+ * </P>
+ * @version $Revision: 1.6 $
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+public class RasBaseType extends RasType
+{
+ static final String rcsid = "@(#)Package rasj, class RasBaseType: $Header: /home/rasdev/CVS-repository/rasdaman/java/rasj/RasBaseType.java,v 1.6 2003/12/10 21:04:23 rasdev Exp $";
+
+ /**
+ * Stores the size of type in bytes
+ **/
+ protected long typeSize;
+
+ /**
+ * Default constructor.
+ **/
+ public RasBaseType()
+ {
+ super();
+ typeSize = 0;
+ }
+
+ /**
+ * Constructor getting name of basetype.
+ * @param newTypeName name of the new base type
+ * @param newSize size of the new base type
+ **/
+ public RasBaseType(String newTypeName, long newSize)
+ {
+ super(newTypeName);
+ typeSize = newSize;
+ }
+
+ /**
+ * Retrieves the id of the type.
+ * @return the id of the type
+ **/
+ public int getTypeID()
+ {
+ return 0;
+ }
+
+ /**
+ * Checks if the current type is a base type (primitive type or structure type).
+ * @return true if it is a base type, false otherwise.
+ **/
+ public boolean isBaseType()
+ {
+ return true;
+ }
+
+ /**
+ * Retrieves the size of the type.
+ * @return the size of the base type.
+ **/
+ public long getSize()
+ {
+ return typeSize;
+ }
+
+ /**
+ * Returns a string representation of this object.
+ * @return a string description of this object.
+ **/
+ public String toString()
+ {
+ return super.toString() + "typeSize: " + typeSize + "\n";
+ }
+}
diff --git a/java/rasj/RasClientInternalException.java b/java/rasj/RasClientInternalException.java
new file mode 100644
index 0000000..84726ff
--- /dev/null
+++ b/java/rasj/RasClientInternalException.java
@@ -0,0 +1,93 @@
+package rasj;
+
+import rasj.global.*;
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * This runtime exception indicates an internal error on client-side , which cannot
+ * be solved by the user. In case of such an event, please send a bug message to
+ * info@active-knowledge.de containing the complete error message and a precise
+ * description of the actions that lead to this exception.
+ * @version $Revision: 1.4 $
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+public class RasClientInternalException extends RasRuntimeException
+{
+ static final String rcsid = "@(#)Package rasj, class RasException: $Header: /home/rasdev/CVS-repository/rasdaman/java/rasj/RasClientInternalException.java,v 1.4 2003/12/19 16:22:27 rasdev Exp $";
+
+ private int errNo = 0;
+ private String errText = null;
+ private String cName = null;
+ private String mName = null;
+
+ /**
+ * standard constructor.
+ **/
+ public RasClientInternalException(String className, String methodName, String msg)
+ {
+ errNo = RasGlobalDefs.INTERNAL_CLIENT_ERROR;
+ errText = ( (msg==null) ? "(none)" : msg );
+ cName = ( (className==null) ? "(none)" : className );
+ mName = ( (methodName==null) ? "(none)" : methodName );
+ }
+
+ /**
+ * Returns the error message.
+ * @return the error message.
+ **/
+ public String getMessage()
+ {
+ int index;
+
+ String msg = RasErrorTexts.getErrorMessage(errNo);
+
+ StringBuffer buf = new StringBuffer(msg);
+ index = msg.indexOf( RasGlobalDefs.KEYWORD_CLASS );
+ if(index != -1)
+ buf.replace(index, index+RasGlobalDefs.KEYWORD_CLASS.length(), cName);
+ msg = buf.toString();
+
+ buf = new StringBuffer(msg);
+ index = msg.indexOf( RasGlobalDefs.KEYWORD_METHOD );
+ if(index != -1)
+ buf.replace(index, index+RasGlobalDefs.KEYWORD_METHOD.length(), mName);
+ msg = buf.toString();
+
+ buf = new StringBuffer(msg);
+ index = msg.indexOf( RasGlobalDefs.KEYWORD_CODE );
+ if(index != -1)
+ buf.replace(index, index+RasGlobalDefs.KEYWORD_CODE.length(), errText);
+ msg = buf.toString();
+ return msg;
+ }
+
+}
diff --git a/java/rasj/RasCollectionType.java b/java/rasj/RasCollectionType.java
new file mode 100644
index 0000000..6a9e3a3
--- /dev/null
+++ b/java/rasj/RasCollectionType.java
@@ -0,0 +1,96 @@
+package rasj;
+
+import rasj.*;
+import rasj.global.*;
+import java.util.*;
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * This class represents the Collection type in the ODMG conformant
+ * representation of the RasDaMan type system.
+ * @version $Revision: 1.6 $
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+
+public class RasCollectionType extends RasType
+{
+ static final String rcsid = "@(#)Package rasj, class RasCollectionType: $Header: /home/rasdev/CVS-repository/rasdaman/java/rasj/RasCollectionType.java,v 1.6 2003/12/10 21:04:23 rasdev Exp $";
+
+ private RasType elementType;
+
+ /**
+ * Simple constructor.
+ **/
+ public RasCollectionType()
+ {
+ super();
+ elementType = null;
+ }
+
+ /**
+ * Constructor getting the element type of the new collection type.
+ * @param type the element type of the new collection type
+ **/
+ public RasCollectionType(RasType type)
+ {
+ super("RAS_COLLECTION");
+ typeID = RasGlobalDefs.RAS_COLLECTION;
+ elementType = type;
+ }
+
+ /**
+ * Retrieves the collection type's element type.
+ * @return the element type of this collection type
+ **/
+ public RasType getElementType()
+ {
+ return elementType;
+ }
+
+ /**
+ * Returns the type of this object (which is RAS_SET in this case).
+ * @return the type of this object (RAS_SET)
+ **/
+ public String getKind()
+ {
+ return "RAS_SET";
+ }
+
+ /**
+ * Creates a string representation of this object.
+ * @return the string representation of this object
+ **/
+ public String toString()
+ {
+ return super.toString() + "ElementType of Set: \n" + elementType + "\n ";
+ }
+}
diff --git a/java/rasj/RasConnectionFailedException.java b/java/rasj/RasConnectionFailedException.java
new file mode 100644
index 0000000..54cfa07
--- /dev/null
+++ b/java/rasj/RasConnectionFailedException.java
@@ -0,0 +1,105 @@
+package rasj;
+
+import rasj.global.*;
+import org.odmg.*;
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * This exception is raised when the connection to the RasDaMan server fails. This typically happens
+ * when the RasDaMan server is either not running or unable to connect to the base DBMS. Also
+ * communication failures between RasManager and RasServer may produce this kind of exception.
+ * @version $Revision: 1.8 $
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+
+public class RasConnectionFailedException extends ODMGRuntimeException
+{
+ static final String rcsid = "@(#)Package rasj.clientcommhttp, class RasConnectionFailedException: $Header: /home/rasdev/CVS-repository/rasdaman/java/rasj/RasConnectionFailedException.java,v 1.8 2003/12/19 16:22:27 rasdev Exp $";
+
+ /**
+ * The RasDaMan erro number
+ **/
+ private int errorNo = 0;
+
+ /**
+ * Optional parameter
+ **/
+ private String param = null;
+
+ /**
+ * Default constructor taking the rasdaman error number and an optional parameter.
+ * @param errNo the rasdaman error number
+ * @param parameter optional parameter that can be inserted into the error message
+ **/
+ public RasConnectionFailedException(int errNo, String parameter)
+ {
+ super();
+ errorNo = errNo;
+ param = ( (parameter==null) ? "(null)" : parameter );
+ }
+
+ /**
+ * Returns the RasDaMan error number
+ */
+ public int getErrorNo()
+ {
+ return errorNo;
+ }
+
+ /**
+ * Returns the error message.
+ **/
+ public String getMessage()
+ {
+ String msg = super.getMessage();
+ if(msg == null)
+ {
+ msg = RasErrorTexts.getErrorMessage(errorNo);
+ int index = 0;
+
+ // replace parameters
+ switch(errorNo)
+ {
+ case RasGlobalDefs.MANAGER_CONN_FAILED:
+ StringBuffer buf = new StringBuffer(msg);
+ index = msg.indexOf( RasGlobalDefs.KEYWORD_URL );
+ if(index != -1)
+ buf.replace(index, index+RasGlobalDefs.KEYWORD_URL.length(), param);
+ msg = buf.toString();
+ break;
+ }
+ }
+ return msg;
+ }
+
+
+}
diff --git a/java/rasj/RasDimensionMismatchException.java b/java/rasj/RasDimensionMismatchException.java
new file mode 100644
index 0000000..9f1cf1b
--- /dev/null
+++ b/java/rasj/RasDimensionMismatchException.java
@@ -0,0 +1,107 @@
+package rasj;
+
+import rasj.global.*;
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * This exception is thrown if the dimensions of two objects do not match.
+ * @version $Revision: 1.6 $
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+
+public class RasDimensionMismatchException extends RasException
+{
+ static final String rcsid = "@(#)Package rasj, class RasDimensionMismatchException: $Header: /home/rasdev/CVS-repository/rasdaman/java/rasj/RasDimensionMismatchException.java,v 1.6 2003/12/19 16:22:27 rasdev Exp $";
+
+ // first dimensionality
+ private long dim1;
+ // second dimensionality
+ private long dim2;
+
+ /**
+ * Standard constructor getting two dimensionalities.
+ * @param pdim1 the dimension of the first object
+ * @param pdim2 the dimension of the second object
+ **/
+ protected RasDimensionMismatchException( long pdim1, long pdim2)
+ {
+ super(RasGlobalDefs.DIMENSION_MISMATCH);
+ dim1 = pdim1;
+ dim2 = pdim2;
+ }
+
+ /**
+ * Returns the error message.
+ * @return the error message.
+ **/
+ public String getMessage()
+ {
+ int index;
+
+ if(super.getMessage() == null)
+ {
+ String msg = RasErrorTexts.getErrorMessage(errNo);
+
+ StringBuffer buf = new StringBuffer(msg);
+ index = msg.indexOf( RasGlobalDefs.KEYWORD_DIM1 );
+ if(index != -1)
+ buf.replace(index, index+RasGlobalDefs.KEYWORD_DIM1.length(), String.valueOf(dim1));
+ msg = buf.toString();
+ index = msg.indexOf( RasGlobalDefs.KEYWORD_DIM1 );
+ if(index != -1)
+ buf.replace(index, index+RasGlobalDefs.KEYWORD_DIM1.length(), String.valueOf(dim2));
+ msg = buf.toString();
+ return msg;
+ }
+ else
+ return super.getMessage();
+ }
+
+ /**
+ * Returns the dimension of the first object.
+ * @return the dimension of the first object
+ **/
+ public long getDim1()
+ {
+ return dim1;
+ }
+
+ /**
+ * Returns the dimension of the second object.
+ * @return the dimension of the second object
+ **/
+ public long getDim2()
+ {
+ return dim2;
+ }
+}
diff --git a/java/rasj/RasException.java b/java/rasj/RasException.java
new file mode 100644
index 0000000..4e02e08
--- /dev/null
+++ b/java/rasj/RasException.java
@@ -0,0 +1,104 @@
+package rasj;
+
+import rasj.global.*;
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * This is the superclass of all exceptions in the rasj package, except for
+ * {@link rasj.RasQueryExecutionFailedException RasQueryExecutionFailedException}.
+ * @see rasj.RasRuntimeException
+ * @version $Revision: 1.6 $
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+
+public class RasException extends Exception
+{
+ static final String rcsid = "@(#)Package rasj, class RasException: $Header: /home/rasdev/CVS-repository/rasdaman/java/rasj/RasException.java,v 1.6 2003/12/19 16:22:27 rasdev Exp $";
+
+ protected int errNo = 0;
+ protected String errText = null;
+
+ /**
+ * Standard constructor.
+ **/
+ protected RasException()
+ {
+ }
+
+ /**
+ * Constructor getting the error number.
+ * @param num the RasDaMan error number
+ **/
+ protected RasException( int num )
+ {
+ errNo = num;
+ }
+
+ /**
+ * Constructor getting the error message.
+ * @param msg the error message
+ **/
+ protected RasException( String msg )
+ {
+ errText = ( (msg==null) ? "(null)" : msg );
+ }
+
+ /**
+ * Constructor getting error number and error message.
+ * @param num the RasDaMan error number
+ * @param msg the error message
+ **/
+ protected RasException( int num, String msg )
+ {
+ errNo = num;
+ errText = ( (msg==null) ? "(null)" : msg );
+ }
+
+ /**
+ * Method for retrieving the error number.
+ * @return the error number
+ **/
+ public int getErrNo()
+ {
+ return errNo;
+ }
+
+ /**
+ * Method retrieving the error message.
+ * @return the error message
+ **/
+ public String getMessage()
+ {
+ return errText;
+ }
+
+}
diff --git a/java/rasj/RasFastScale.java b/java/rasj/RasFastScale.java
new file mode 100644
index 0000000..bbc21f4
--- /dev/null
+++ b/java/rasj/RasFastScale.java
@@ -0,0 +1,361 @@
+package rasj;
+
+import rasj.clientcommhttp.*;
+import rasj.odmg.*;
+import rasj.global.*;
+import org.odmg.*;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import java.sql.*;
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * Abstract base class for fast scaling
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+
+abstract class RasFastBaseScale implements RasGlobalDefs
+{
+
+ OQLQuery query = null;
+ String collectionName = null;
+ RasMInterval fullDomain = null;
+ double lastScaleUsed;
+
+ /**
+ * Default constructor.
+ *
+ * This constructor gets the name of the image collection and and an OQLQuery object as parameters.
+ * <P><B>Important:</B>This class does not open its own connection to the database nor start or
+ * commit any transactions. This has to be done by the application using FastScale.</P>
+ * @param collection the name of the collection containing the image(s)
+ * @param queryObject the OQLQuery object for connecting to the database
+ **/
+ public RasFastBaseScale( final String collection, final OQLQuery queryObject )
+ {
+ collectionName = collection;
+ query = queryObject;
+ fullDomain = readFullDomain(collectionName);
+ }
+
+ /**
+ * Returns the full (unscaled) Domain of the image.
+ * @return the original domain of the image
+ **/
+ public final RasMInterval getFullDomain()
+ {
+ return fullDomain;
+ }
+
+ /**
+ * Returns the scaled domain of the image.
+ **/
+ public RasMInterval scaleGetDomain( final RasMInterval areaOp, final RasPoint origin, double scale)
+ throws RasClientInternalException
+ {
+ try
+ {
+ int i;
+ int dim = areaOp.dimension();
+ RasMInterval areaScale = new RasMInterval(dim);
+
+ for( i=0 ; i<dim ; i++ )
+ {
+ int low, high;
+
+ // simple trafo of low coordinate
+ low = (int)(origin.item(i) + (areaOp.item(i).low() - origin.item(i)) * scale);
+
+ // for the high coordinate use the low coordinate of the _next_ tile
+ // ( = areaOp.item(i).high() + 1 ) and subtract 1 ==> seamless tiling.
+ high = (int)(origin.item(i) +
+ (areaOp.item(i).high() + 1 - origin.item(i)) * scale - 1);
+
+/* FIXME At some point we need to have a clean design
+ // now make sure these values transformed back into the original domain are legal
+ // values. Due to floor rounding low <= true_low, i.e. underflow is possible.
+ if ((int)((low - origin.item(i)) / scale) < areaOp.item(i).low() - origin.item(i))
+ {
+ low++;
+ }
+
+ // Because of floor rounding, high is always legal. However, if the low
+ // coordinate of the next tile underflows, the high value of this one would
+ // no longer match seamlessly. Therefore we have to check whether the cell
+ // at high+1 transformed back into the original domain is a legal value too
+ // and use that as the real high boundary if so.
+ if ((int)((high+1 - origin.item(i)) / scale) <=
+ areaOp.item(i).high() - origin.item(i))
+ {
+ high++;
+ }
+*/
+
+ if (high < low)
+ return null;
+
+ areaScale.stream(new RasSInterval(low, high));
+
+ }
+ return areaScale;
+ }
+ catch(RasIndexOutOfBoundsException e1)
+ {
+ throw new RasClientInternalException("RasFastBaseScale","scaleGetDomain",e1.getMessage());
+ }
+ catch(RasStreamInputOverflowException e2)
+ {
+ throw new RasClientInternalException("RasFastBaseScale","scaleGetDomain",e2.getMessage());
+ }
+ catch(RasResultIsNoIntervalException e3)
+ {
+ throw new RasClientInternalException("RasFastBaseScale","scaleGetDomain",e3.getMessage());
+ }
+ }
+
+ /**
+ * Reads the full domain of the given image. This method is called in the RasFastScale constructor.
+ * @param name name of the collection containing the image
+ * @return the full domain of the image
+ **/
+ protected RasMInterval readFullDomain(String collection) throws RasClientInternalException
+ {
+ try {
+ query.create("SELECT sdom(img) FROM " + collection + " AS img");
+ DBag resultBag = (DBag)query.execute();
+ if (resultBag != null)
+ {
+ Iterator iter = resultBag.iterator();
+ if(iter.hasNext())
+ return (RasMInterval)iter.next();
+ else
+ throw new RasClientInternalException("RasFastScale","readFullDomain","query produced no result.");
+ }
+ else
+ throw new RasClientInternalException("RasFastScale","readFullDomain","query produced no result.");
+
+ }
+ catch(Exception e1) {
+ throw new RasClientInternalException("RasFastScale","readFullDomain",e1.getMessage());
+ }
+ }
+
+ /**
+ * gets the minimal array
+ **/
+ protected RasGMArray getMinimalArray(final String collection) throws RasClientInternalException
+ {
+ try {
+ RasMInterval iv;
+ iv = readFullDomain(collection);
+ RasMInterval getDomain = new RasMInterval(iv.dimension());
+ int i;
+ for(i=0 ; i<iv.dimension() ; i++)
+ {
+ // we actually only get one point.
+ getDomain.stream(new RasSInterval(iv.item(i).low(), iv.item(i).low()));
+ }
+ query.create("SELECT img" + getDomain.toString() + " FROM " + collection + " AS img");
+ DBag resultBag = (DBag)query.execute();
+ if (resultBag != null)
+ {
+ Iterator iter = resultBag.iterator();
+ if(iter.hasNext())
+ return (RasGMArray)iter.next();
+ else
+ throw new RasClientInternalException("RasFastScale","getMinimalArray","query produced no result.");
+ }
+ else
+ throw new RasClientInternalException("RasFastScale","getMinimalArray","query produced no result.");
+ }
+ catch(Exception e1) {
+ throw new RasClientInternalException("RasFastScale","getMinimalArray",e1.getMessage());
+ }
+ }
+
+ /**
+ * gets the scaling domain
+ **/
+ public RasMInterval getScaledDomain( final RasMInterval area, double scale)
+ throws RasClientInternalException
+ {
+ RasMInterval retval = null;
+ int nearest = -1, i = 0;
+ double nearScale = 0.0;
+
+ // find the nearest scaling factor larger than the requested scale
+ for ( i = 0; i < (int)NUM_FAST_PRE_SCALE; i++ )
+ {
+ if(FAST_PRE_SCALE_FACTORS[i] < scale) break;
+ nearest = i;
+ }
+ if ( nearest != -1 )
+ {
+ retval=scaleGetDomain(area, fullDomain.getOrigin(), FAST_PRE_SCALE_FACTORS[nearest]);
+ if ( (scale != FAST_PRE_SCALE_FACTORS[nearest]) && (retval != null) )
+ {
+ nearScale=scale/ FAST_PRE_SCALE_FACTORS[nearest];
+ retval=scaleGetDomain(retval, fullDomain.getOrigin(), nearScale);
+ }
+ }
+ else
+ {
+ retval = scaleGetDomain(area, fullDomain.getOrigin(), scale);
+ }
+
+ return retval;
+ }
+
+ /**
+ * gets the last used scale
+ **/
+ public double getLastScale()
+ {
+ return lastScaleUsed;
+ }
+
+}
+
+/**
+ * class for fast scaling
+ * @version $Revision: 1.17 $
+ **/
+public class RasFastScale extends RasFastBaseScale implements RasGlobalDefs
+{
+ static final String rcsid = "@(#)Package rasj, class RasFastScale, RasFastBaseScale: $Header: /home/rasdev/CVS-repository/rasdaman/java/rasj/RasFastScale.java,v 1.17 2003/12/10 21:04:23 rasdev Exp $";
+
+ /**
+ * Default constructor.
+ *
+ * This constructor gets the name of the image collection and and an OQLQuery object as parameters.
+ * <P><B>Important:</B>This class does not open its own connection to the database nor start or
+ * commit any transactions. This has to be done by the application using FastScale.</P>
+ * @param collection the name of the collection containing the image(s)
+ * @param queryObject the OQLQuery object for connecting to the database
+ **/
+ public RasFastScale( final String collection, final OQLQuery queryObject )
+ {
+ super(collection,queryObject);
+
+ }
+
+ /**
+ * Returns the scaled image.
+ *
+ * @param trimDomain the domain of the desired image sector
+ * @param scalingFactor the scaling factor ( values greater than 1 mean magnification, lesser than
+ * 1 lead to a reduction )
+ * @param domType determines wether the scaling or the trimmimg have to be executed first. Currently
+ * only domType=1 is supported by the server.
+ *
+ */
+ public Object getScaledImage (final RasMInterval trimDomain, double scalingFactor, int domType)
+ throws QueryException
+ {
+ // That one should be the simpler part. Just choose the appropriate
+ // scaling factor from the list and the corresponding collection,
+ // adapt the factor given here and execute the query.
+
+ int i;
+ int nearest = -1;
+ String suffix = null;
+ RasGMArray res = null;
+ Object result = null;
+
+ // find the nearest scaling factor larger than the requested scale
+ for ( i = 0; i < (int)NUM_FAST_PRE_SCALE; i++ )
+ {
+ if(FAST_PRE_SCALE_FACTORS[i] < scalingFactor) break;
+ nearest = i;
+ }
+
+ while(true)
+ {
+ try {
+
+ double nearScale;
+
+ // Try all collections, therefore decide on this here.
+ if (nearest == -1 || nearest == 0)
+ {
+ nearScale = 1.0;
+ suffix = "";
+ }
+ else
+ {
+ nearScale = FAST_PRE_SCALE_FACTORS[nearest];
+ suffix = FAST_PRE_SCALE_SUFFIXES[nearest];
+ }
+
+ // depending on the value of domType apply the trim domain to the scaled object
+ // (domType == 0) or to the unscaled object (domType != 0).
+ if (domType == 0)
+ query.create("SELECT scale(img," + scalingFactor / nearScale + ')' + trimDomain +
+ " FROM " + collectionName + suffix + " AS img");
+ else
+ {
+ RasMInterval scaledTrimDomain = null;
+
+ scaledTrimDomain = getScaledDomain(trimDomain, nearScale);
+ if ( scaledTrimDomain == null )
+ {
+ nearest--; // we can't get an error here for the highest scale!
+ continue; // try the next higher scaling factor instead.
+ }
+
+ query.create("SELECT scale(img" + scaledTrimDomain + ',' + scalingFactor / nearScale +
+ ") FROM " + collectionName + suffix + " AS img");
+ //System.err.println("Query : " + query );
+
+ }
+
+ DBag resultBag = (DBag)query.execute();
+ if (resultBag != null)
+ {
+ result = (DBag)resultBag;
+ break;
+ }
+ else
+ throw new RasClientInternalException("RasFastScale","getScaledImage","query returned no result.");
+ }
+ catch(Exception e1) {
+ throw new RasClientInternalException("RasFastScale","getScaledImage",e1.getMessage());
+ }
+
+ }
+ return result;
+ }
+
+}
diff --git a/java/rasj/RasGMArray.java b/java/rasj/RasGMArray.java
new file mode 100644
index 0000000..da0843c
--- /dev/null
+++ b/java/rasj/RasGMArray.java
@@ -0,0 +1,532 @@
+package rasj;
+
+import rasj.*;
+import rasj.odmg.*;
+import rasj.global.*;
+
+import java.io.*;
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * This class represents a generic MDD in the sense that it
+ * is independent of the cell base type. The only information
+ * available is the length in bytes of the base type.
+ * <P>More specific MDDs including base type information for more
+ * type safety are represented by a set of typed subclasses.
+ * @version $Revision: 1.26 $
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+public class RasGMArray extends RasObject implements RasGlobalDefs
+{
+ static final String rcsid = "@(#)Package rasj, class RasGMArray: $Header: /home/rasdev/CVS-repository/rasdaman/java/rasj/RasGMArray.java,v 1.26 2003/12/10 21:04:23 rasdev Exp $";
+
+ /** spatial domain */
+ protected RasMInterval domain;
+
+ /** internal array representation in bytes*/
+ protected byte[] data;
+
+ /** internal array representation as Object for use in special marrays*/
+ protected Object objectData;
+
+ /** internal object for accessing one cell of the array */
+ protected byte[] currentCell;
+
+ /** size of internal array representation in bytes */
+ protected long dataSize;
+
+ /** length of the cell base type in bytes */
+ protected long typeLength;
+
+ /** store current data format */
+ protected int currentFormat; //RasDataFormat -> RasGlobalDefs
+
+ /** storage layout object */
+ protected RasStorageLayout storageLayout;
+
+ /**
+ * Default constructor.
+ **/
+ public RasGMArray()
+ {
+ super(RAS_MARRAY);
+ data = null;
+ objectData = null;
+ currentCell = null;
+ dataSize = 0;
+ domain = null;
+ typeLength = 0;
+ currentFormat = RAS_ARRAY;
+ storageLayout = new RasStorageLayout();
+ }
+
+ /**
+ * Constructor for uninitialized MDD objects
+ * @param initDomain The initial Domain of the GMArray
+ * @param cellTypeLength The length of the cell type used
+ */
+ public RasGMArray(final RasMInterval initDomain, long cellTypeLength)
+ {
+ super(RAS_MARRAY);
+ data = null;
+ objectData = null;
+ dataSize = 0;
+ domain = initDomain;
+ typeLength = cellTypeLength;
+ currentFormat = RAS_ARRAY;
+ storageLayout = new RasStorageLayout();
+
+ // If dimensionality is zero, just one scalar value is stored.
+ dataSize = ((domain.dimension() != 0) ? domain.cellCount() : 1) * typeLength;
+ data = new byte[(int)dataSize];
+ currentCell = new byte[(int)cellTypeLength];
+ }
+
+ /**
+ * Constructor for uninitialized MDD objects with Storage Layout
+ * @param initDomain The initial Domain of the GMArray
+ * @param cellTypeLength The length of the cell type used
+ * @param RasStorageLayout The storage layout to be used
+ */
+ public RasGMArray(final RasMInterval initDomain, long cellTypeLength, RasStorageLayout stl)
+ {
+ super(RAS_MARRAY);
+ data = null;
+ objectData = null;
+ dataSize = 0;
+ domain = initDomain;
+ typeLength = cellTypeLength;
+ currentFormat = RAS_ARRAY;
+ storageLayout = stl;
+
+ // If dimensionality is zero, just one scalar value is stored.
+ dataSize = ((domain.dimension() != 0) ? domain.cellCount() : 1) * typeLength;
+ data = new byte[(int)dataSize];
+ currentCell = new byte[(int)cellTypeLength];
+ }
+
+
+ /**
+ * Copy constructor.
+ * @param obj a copy of this object will be created
+ **/
+ public RasGMArray(final RasGMArray obj)
+ {
+ super(obj, RAS_MARRAY);
+ if(data!=null)
+ {
+ System.arraycopy(obj.getArray(), 0, data, 0, (int)obj.dataSize);
+ objectData = null;
+ }
+ dataSize = obj.getArraySize();
+ domain = obj.spatialDomain();
+ typeLength = obj.typeLength;
+ currentFormat = obj.currentFormat;
+ storageLayout = new RasStorageLayout(obj.storageLayout);
+ if(obj.typeLength != 0)
+ currentCell = new byte[(int)obj.typeLength];
+ }
+
+ /**
+ * This method copies the values of mArray to itself.
+ * @param mArray the values of this MArray will be copied
+ * @return itself (after having copied the values from mArray)
+ **/
+ public RasGMArray setTo(final RasGMArray mArray)
+ {
+ if(this != mArray)
+ {
+ if(data != null)
+ {
+ data = null;
+ }
+
+ if (mArray.data != null)
+ {
+ dataSize = mArray.dataSize;
+ data = mArray.data;
+ }
+ if (mArray.objectData != null)
+ {
+ dataSize = mArray.dataSize;
+ objectData = mArray.objectData;
+ }
+
+ if(storageLayout != null)
+ {
+ storageLayout = null;
+ }
+
+
+ // this has to be changed to a clone() function in future
+ if(mArray.storageLayout != null)
+ storageLayout = new RasStorageLayout(mArray.storageLayout);
+
+ domain = mArray.domain;
+ typeLength = mArray.typeLength;
+ currentFormat = mArray.currentFormat;
+ }
+ return this;
+ }
+
+ /**
+ * Reads a cell of the MDD. The cell's value is returned
+ * as a byte array, the length of which depends on the size of the base type.
+ * If you want to get the cell value as a primitive type (like integer or byte),
+ * you either have to do a cast or use the type-specific MArrays
+ * that are derived from this class.
+ * @param point the coordinates of the requested cell
+ * @return a byte array representing the value of the requested cell.
+ **/
+ public byte[] getCell(RasPoint point) throws RasDimensionMismatchException, RasIndexOutOfBoundsException
+ {
+ // first test dimensionality
+ if(point.dimension() != domain.dimension())
+ throw new RasDimensionMismatchException(point.dimension(), domain.dimension());
+ if(typeLength == 0)
+ return null;
+
+ System.arraycopy(data, (int)(domain.cellOffset(point)*typeLength), currentCell, 0, (int)typeLength);
+ return currentCell;
+
+ }
+
+ /**
+ * Returns the storage layout object of this MDD.
+ * @return the storage layout object
+ **/
+ public final RasStorageLayout getStorageLayout()
+ {
+ return storageLayout;
+ }
+
+ /**
+ * Sets the storage layout object and checks compatibility with the domain.
+ * @param stl the new storage layout
+ */
+ public void setStorageLayout(RasStorageLayout stl) throws RasDimensionMismatchException
+ {
+ if (!stl.isCompatible(domain))
+ throw new RasDimensionMismatchException(domain.dimension(),stl.getSpatialDomain().dimension());
+ else
+ storageLayout = stl;
+ }
+
+ /**
+ * Returns a RasGMArray that is the intersection of the current domain
+ * with the specified interval.
+ * @param where the interval that is used for the intersection
+ * @return the result of the intersection of this GMArray with the parameter interval
+ */
+ public RasGMArray intersectionWith(RasMInterval where)
+ {
+ RasGMArray tile = new RasGMArray();
+
+ try {
+ RasMInterval objDomain = spatialDomain();
+ int numDims = objDomain.dimension();
+ long tlength = getTypeLength();
+
+ byte[] objData = new byte[(int)(where.cellCount() * tlength)];
+ tile.setSpatialDomain(where);
+ tile.setTypeLength(tlength);
+ tile.setArray(objData);
+ tile.setArraySize(where.cellCount() * tlength);
+
+ long blockLength =
+ where.item(numDims-1).high() - where.item(numDims-1).low() + 1;
+ long total = where.cellCount()/blockLength;
+
+ byte[] dest = objData;
+ byte[] source = getArray();
+ int blength = (int)(blockLength * tlength);
+
+ for (long cell=0; cell<total; cell++)
+ {
+ RasPoint p = where.cellPoint(cell*blockLength);
+
+ System.arraycopy(source, (int)(objDomain.cellOffset(p) * tlength), dest,
+ (int)(where.cellOffset(p) * tlength), blength);
+ }
+
+ return tile;
+ }
+
+ catch(RasIndexOutOfBoundsException e1) {
+ // this canno toccur (theoretically)
+ throw new RasClientInternalException("RasGMArray","intersectionWith()",e1.getMessage());
+ }
+ catch(RasResultIsNoCellException e2) {
+ // this canno toccur (theoretically)
+ throw new RasClientInternalException("RasGMArray","intersectionWith()",e2.getMessage());
+ }
+
+ }
+
+
+ // Read methods
+ /**
+ * Gets the spatial domain.
+ * @return the spatial domain of this GMArray
+ **/
+ public final RasMInterval spatialDomain()
+ {
+ return domain;
+ }
+
+ /**
+ * Gets the internal representation of this GMAarray (the byte array).
+ * @return the byte array representing this GMArray
+ **/
+ public byte[] getArray()
+ {
+ return data;
+ }
+
+ /**
+ * Gets the size of the internal representation of this GMArray (in bytes).
+ * @return the size of this GMArray
+ **/
+ public final long getArraySize()
+ {
+ return dataSize;
+ }
+
+ /**
+ * Gets the length of cell type (in bytes).
+ * @return the cell type length
+ **/
+ public final long getTypeLength()
+ {
+ return typeLength;
+ }
+
+ /**
+ * Gets the current data format (RAS_ARRAY).
+ * @return the current data format
+ **/
+ public final int getCurrentFormat()
+ {
+ return currentFormat;
+ }
+
+
+ // Write methods
+ /**
+ * Sets the spatial domain.
+ * @param dom the new spatial domain of this GMArray
+ **/
+ public void setSpatialDomain(final RasMInterval dom)
+ {
+ domain = dom;
+ }
+
+ /**
+ * Sets the internal representation of the GMArray.
+ * @param newData the new byte array representing the contents of this GMArray
+ **/
+ public void setArray(byte[] newData)
+ {
+ data = newData;
+ dataSize = newData.length;
+ objectData = null;
+ }
+
+ /**
+ * Sets the size of the internal representation (in bytes).
+ * @param newValue the size of the internal representation (the byte array)
+ **/
+ public void setArraySize(long newValue)
+ {
+ dataSize = newValue;
+ }
+
+ /**
+ * Sets the length of the cell type (in bytes).
+ * @param newValue the cell type length
+ **/
+ public void setTypeLength(long newValue)
+ {
+ typeLength = newValue;
+ /* Now create the byte array object used for returning cell values */
+ currentCell = new byte[(int)newValue];
+ }
+
+ /**
+ * Sets the current data format.
+ * @param newFormat the new data format
+ **/
+ public void setCurrentFormat(int newFormat)
+ {
+ currentFormat = newFormat;
+ }
+
+ // Methods for database communication (internal use only)
+
+ /* inserts an object into the database
+ public void insertObjIntoDB()
+ {
+ // Nothing is done in that case. RasMArray objects can just be inserted as elements
+ // of a collection which invokes RasGMArray.insertObjIntoDB(String collName)
+ // of the RasMArray objects.
+
+ //RasDatabase.currentDatabase.communication.insertSingleMDDObj(this);
+ System.out.println(" do nothing ");
+ }
+ */
+
+ /* inserts myself into a specific collection in the database
+ public void insertObjIntoDB(String collName) throws RasException
+ {
+ // Insert myself in database only if I have a type name, otherwise
+ // an exception is thrown.
+ if(!typeName)
+ {
+ throw new RasErrorDatabaseClassUndefined();
+ }
+ //RasDatabase.currentDatabase.communication.insertMDD(collName, this);
+ }
+ */
+
+ /** gets the String representation */
+ public String toString()
+ {
+ String tileDomain = "";
+
+ RasType typeSchema = (RasType)(((RasGMArray)this).getTypeSchema());
+ RasBaseType baseTypeSchema = (RasBaseType)(((RasGMArray)this).getBaseTypeSchema());
+
+ if(storageLayout.getSpatialDomain() == null)
+ tileDomain = getTilingDomain(domain,typeLength);
+ else
+ tileDomain = storageLayout.getSpatialDomain().toString();
+
+ String s = "\n" + getClass().getName();
+ s = s + "\n"
+ + " Oid...................: " + getOID() + "\n"
+ + " Object Name...........: " + getObjectName() + "\n"
+ + " Object Type...........: " + getObjectType() + "\n"
+ + " Object Type Name......: " + getObjectTypeName() + "\n"
+ + " Type Structure........: " + ((getTypeStructure() != null) ? getTypeStructure() : "<nn>") + "\n"
+ + " Type Schema...........: " + ((typeSchema != null) ? typeSchema.toString() : "<nn>") + "\n"
+ + " Domain................: " + domain + "\n"
+ + " TilingDomain..........: " + tileDomain + "\n"
+ + " TileSize..............: " + storageLayout.getTileSize() + " bytes\n"
+ + " Base Type Schema......: " + ((baseTypeSchema != null) ? baseTypeSchema.toString() : "<nn>") + "\n"
+ + " Base Type Length......: " + typeLength + "\n"
+ + " Data format...........: " + currentFormat + "\n"
+ + " Data size (bytes).....: " + dataSize + "\n";
+
+ return s;
+ }
+
+ /** gets the String for testing */
+ public String toTestString()
+ {
+ String tileDomain = "";
+
+ RasType typeSchema = (RasType)(((RasGMArray)this).getTypeSchema());
+ RasBaseType baseTypeSchema = (RasBaseType)(((RasGMArray)this).getBaseTypeSchema());
+
+ if(storageLayout.getSpatialDomain() == null)
+ tileDomain = getTilingDomain(domain,typeLength);
+ else
+ tileDomain = storageLayout.getSpatialDomain().toString();
+
+ StringBuffer buffer = new StringBuffer(getArray().length * 4); // for most elements 3 characters and a space
+ buffer.append("\n" + getClass().getName());
+ buffer.append("\n"
+ //+ " Oid...................: " + getOID() + "\n"
+ + " Object Name...........: " + getObjectName() + "\n"
+ + " Object Type...........: " + getObjectType() + "\n"
+ + " Object Type Name......: " + getObjectTypeName() + "\n"
+ + " Type Structure........: " + ((getTypeStructure() != null) ? getTypeStructure() : "<nn>") + "\n"
+ + " Type Schema...........: " + ((typeSchema != null) ? typeSchema.toString() : "<nn>") + "\n"
+ + " Domain................: " + domain + "\n"
+ + " TilingDomain..........: " + tileDomain + "\n"
+ + " TileSize..............: " + storageLayout.getTileSize() + " bytes\n"
+ + " Base Type Schema......: " + ((baseTypeSchema != null) ? baseTypeSchema.toString() : "<nn>") + "\n"
+ + " Base Type Length......: " + typeLength + "\n"
+ + " Data format...........: " + currentFormat + "\n"
+ + " Data size (bytes).....: " + dataSize + "\n"
+ );
+
+ //print bytes, just for testing!!!
+ for(int j=0; j < getArray().length; j++)
+ {
+ buffer.append(" " + getArray()[j]);
+ }
+
+ return buffer.toString();
+ }
+
+ /**
+ * Returns the base type schema of this GMArray.
+ * @return the base type schema
+ **/
+ public RasBaseType getBaseTypeSchema()
+ {
+ RasType type = getTypeSchema();
+ RasBaseType baseType = null;
+
+ if (type != null)
+ {
+ if (type.getTypeID() == RasGlobalDefs.RAS_MARRAY)
+ {
+ RasMArrayType mArrayType = (RasMArrayType)type;
+ baseType = (mArrayType.getBaseType());
+ }
+ }
+
+ return baseType;
+ }
+
+
+ //######### for internal use
+
+ // calculates the tiling domain based on the original MDD, the type length and the tileSize
+ // of the MDD's storageLayout.
+ private String getTilingDomain(final RasMInterval originalDomain, final long typeLength)
+ {
+ long tileSize = storageLayout.getTileSize();
+ int dim = originalDomain.dimension();
+ double tmp = 1.0/dim;
+ int size=(int)(Math.pow((double)(tileSize / typeLength),tmp))-1;
+ String retVal = "0:"+String.valueOf(size);
+ for(int x=1; x<dim; x++)
+ retVal = retVal + ",0:" + size;
+ return "["+retVal+"]";
+ }
+
+}
+
+
diff --git a/java/rasj/RasIllegalULongValueException.java b/java/rasj/RasIllegalULongValueException.java
new file mode 100644
index 0000000..34f7fbb
--- /dev/null
+++ b/java/rasj/RasIllegalULongValueException.java
@@ -0,0 +1,88 @@
+package rasj;
+
+import rasj.global.*;
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * This exception is thrown if a {@link rasj.RasMArrayLong RasMArrayLong} is trying to be sent to the
+ * server where one or more cell values exceed 2^32 or are negative. Such cell values are illegal
+ * because the ODMG standard restricts unsigned long values in C++ (i.e. in the RasDaMan server)
+ * to 4 bytes, whereas java long values have 8 bytes.
+ * <p>
+ * Although in this case the server would store only the least 4 bytes of the cell value without throwing an
+ * exception, the java client interface does not allow sending such illegal long values in order
+ * to enforce application integrity.
+ * @see rasj.RasMArrayLong
+ * @version $Revision: 1.3 $
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+public class RasIllegalULongValueException extends RasRuntimeException
+{
+ static final String rcsid = "@(#)Package rasj, class RasIllegalULongValueException: $Header: /home/rasdev/CVS-repository/rasdaman/java/rasj/RasIllegalULongValueException.java,v 1.3 2003/12/19 16:22:27 rasdev Exp $";
+
+ // the base type
+ long illegalValue = 0;
+
+ /**
+ * Standard constructor getting the illegal long value
+ * @param illegalLongValue the cell value that caused the error
+ **/
+ public RasIllegalULongValueException(long illegalLongValue)
+ {
+ super(RasGlobalDefs.ILLEGAL_ULONG_VALUE);
+ illegalValue = illegalLongValue;
+ }
+
+ /**
+ * Returns the error message.
+ * @return the error message.
+ **/
+ public String getMessage()
+ {
+ int i;
+
+ if(super.getMessage() == null)
+ {
+ String msg = RasErrorTexts.getErrorMessage(errNo);
+
+ StringBuffer buf = new StringBuffer(msg);
+ i = msg.indexOf( RasGlobalDefs.KEYWORD_VAL );
+ if(i != -1)
+ buf.replace(i, i+RasGlobalDefs.KEYWORD_VAL.length(), String.valueOf(illegalValue));
+ msg = buf.toString();
+ return msg;
+ }
+ else
+ return super.getMessage();
+ }
+
+}
diff --git a/java/rasj/RasIllegalUShortValueException.java b/java/rasj/RasIllegalUShortValueException.java
new file mode 100644
index 0000000..6c8ae17
--- /dev/null
+++ b/java/rasj/RasIllegalUShortValueException.java
@@ -0,0 +1,87 @@
+package rasj;
+
+import rasj.global.*;
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * This exception is thrown if a {@link rasj.RasMArrayShort RasMArrayShort} is trying to be sent to the
+ * server for ODMG type UShort where one or more cell values exceed 2^16 or are negative. Such cell values are illegal
+ * because the ODMG standard restricts unsigned short values (i.e. in the RasDaMan server)
+ * to 2 bytes, whereas java integer values have 4 bytes.
+ * Although in this case the server would store only the least 2 bytes of the cell value without throwing an
+ * exception, the java client interface does not allow sending such illegal short values in order
+ * to enforce application integrity.
+ * @see rasj.RasMArrayShort
+ * @version $Revision: 1.4 $
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+public class RasIllegalUShortValueException extends RasRuntimeException
+{
+ static final String rcsid = "@(#)Package rasj, class RasIllegalUShortValueException: $Header: /home/rasdev/CVS-repository/rasdaman/java/rasj/RasIllegalUShortValueException.java,v 1.4 2003/12/19 16:22:27 rasdev Exp $";
+
+ // the base type
+ int illegalValue = 0;
+
+ /**
+ * Standard constructor getting the illegal short value
+ * @param illegalShortValue the cell value that caused the error
+ **/
+ public RasIllegalUShortValueException(int illegalUShortValue)
+ {
+ super(RasGlobalDefs.ILLEGAL_USHORT_VALUE);
+ illegalValue = illegalUShortValue;
+ }
+
+ /**
+ * Returns the error message.
+ * @return the error message.
+ **/
+ public String getMessage()
+ {
+ int i;
+
+ if(super.getMessage() == null)
+ {
+ String msg = RasErrorTexts.getErrorMessage(errNo);
+
+ StringBuffer buf = new StringBuffer(msg);
+ i = msg.indexOf( RasGlobalDefs.KEYWORD_VAL );
+ if(i != -1)
+ buf.replace(i, i+RasGlobalDefs.KEYWORD_VAL.length(), String.valueOf(illegalValue));
+ msg = buf.toString();
+ return msg;
+ }
+ else
+ return super.getMessage();
+ }
+
+}
diff --git a/java/rasj/RasImplementation.java b/java/rasj/RasImplementation.java
new file mode 100644
index 0000000..d30a7f3
--- /dev/null
+++ b/java/rasj/RasImplementation.java
@@ -0,0 +1,349 @@
+package rasj;
+
+import rasj.odmg.*;
+import rasj.global.*; // RASJ_VERSION
+import rasj.rnp.*;
+import org.odmg.*;
+import rasj.clientcommhttp.*;
+
+import java.io.*;
+import java.net.*;
+import java.lang.*;
+import java.util.*;
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * ODMG Implementation Bootstrap Object
+ * This class implements an ODMG Bootstrap Object. This is the only vendor-dependent
+ * object a user needs for performing database operations.
+ * @version $Revision: 1.16 $
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+
+public class RasImplementation implements Implementation
+ {
+ /**
+ * This is the "real" Implementation object that is used. Because it contains a lot of
+ * internal methods that have to be used by the rasj.odmg package, it has been put
+ * into that package in order to avoid making this internal methods publicly visible and
+ * available.
+ **/
+ private RasImplementationInterface imp = null;
+
+ private static boolean isRNP = true; // use RNP by default
+
+ /**
+ * C/s protocol indicators.
+ */
+ public static final String PROTOCOL_RNP = "RNP" ; // RNP protocol indicator
+ public static final String PROTOCOL_RPC = "RPC" ; // RPC protocol indicator
+ public static final String PROTOCOL_HTTP = "HTTP" ; // HTTP protocol indicator
+ public static final String PROTOCOL_COMP = "COMPAT" ; // "compatiblity", means: using RNP (legacy)
+
+ /**
+ * Standard constructor.
+ * @param server - Complete URL of the RasDaMan httpserver (including port number)
+ */
+ public RasImplementation(String server)
+ {
+ Debug.talkCritical( RasGlobalDefs.RASJ_VERSION );
+ Debug.talkCritical( " Using server " + server );
+
+ String envVar = System.getProperty("RMANPROTOCOL"); // uses "-D" option
+
+ boolean useRNP = isRNP;
+
+ if(envVar != null)
+ {
+ Debug.talkWarning( "environment variable RMANPROTOCOL enforces protocol " + envVar );
+ if ( envVar.equalsIgnoreCase( PROTOCOL_RNP ) )
+ useRNP = true;
+ else if ( envVar.equalsIgnoreCase( PROTOCOL_RPC ) )
+ {
+ Debug.talkCritical( "Error: protocol " + PROTOCOL_RPC + " not supported by rasj: using " + PROTOCOL_RNP + " instead." );
+ useRNP = true;
+ }
+ else if ( envVar.equalsIgnoreCase( PROTOCOL_HTTP ) )
+ useRNP = false;
+ else if ( envVar.equalsIgnoreCase( PROTOCOL_COMP ) )
+ {
+ Debug.talkCritical( "Compatibility mode specified, using " + PROTOCOL_RNP + "." );
+ useRNP = true;
+ }
+ else
+ {
+ Debug.talkCritical( "Error: unknown protocol: " + envVar + "; using protocol " + PROTOCOL_RNP + "." );
+ useRNP = true;
+ }
+ }
+
+ if(useRNP)
+ {
+ Debug.talkVerbose( "RasImplementation.constructor: using protocol " + PROTOCOL_RNP + "." );
+ imp = new RasRNPImplementation(server);
+ }
+ else
+ {
+ Debug.talkVerbose( "RasImplementation.constructor: using protocol " + PROTOCOL_HTTP + "." );
+ imp = new RasODMGImplementation(server);
+ }
+ } // RasImplementation()
+
+ /**
+ * Extended constructor, allowing to set protocol (does not query env var).
+ * If the protocol is illegal, RNP is assumed as default.
+ * @param server - Complete URL of the RasDaMan httpserver (including port number)
+ * @param protocol - c/s communication protocol selector, one of: "RNP", "HTTP"
+ */
+ public RasImplementation(String server, String protocol)
+ {
+ Debug.talkCritical( RasGlobalDefs.RASJ_VERSION );
+ Debug.talkCritical( " Using server " + server );
+
+ if( protocol.equalsIgnoreCase( PROTOCOL_RNP ) )
+ {
+ Debug.talkVerbose( "Using protocol " + PROTOCOL_RNP + "." );
+ imp = new RasRNPImplementation(server);
+ }
+ else if( protocol.equalsIgnoreCase( PROTOCOL_HTTP ) )
+ {
+ Debug.talkVerbose( "Using protocol " + PROTOCOL_HTTP + "." );
+ imp = new RasODMGImplementation(server);
+ }
+ else
+ {
+ Debug.talkCritical( "Error: unknown protocol: " + protocol + "; using " + PROTOCOL_RNP + " instead." );
+ imp = new RasRNPImplementation(server);
+ }
+
+ } // RasImplementation()
+
+ public static void setRNP()
+ {
+ isRNP = true;
+ }
+
+ public static void setHTTP()
+ {
+ isRNP = false;
+ }
+
+ public boolean isDefaultRNP()
+ {
+ Debug.talkVerbose( "RasImplementation.isDefaultRNP: RNP=" + isRNP + "." );
+ return isRNP;
+ }
+
+ /**
+ * returns 1 if an openDB command is executed (closeDB sets it back to 0).
+ */
+ public int dbIsOpen()
+ {
+ return imp.dbIsOpen();
+ }
+
+ /*
+ * Create a new transaction object and associate it with the current thread.
+ */
+ public Transaction newTransaction()
+ {
+ return imp.newTransaction();
+ }
+
+ /**
+ * Get current transaction for thread, or NULL if none.
+ */
+ public Transaction currentTransaction()
+ {
+ return imp.currentTransaction();
+ }
+
+ /**
+ * Create a new database object.
+ */
+ public Database newDatabase()
+ {
+ return imp.newDatabase();
+ }
+
+ /**
+ * Create a new query object.
+ */
+ public OQLQuery newOQLQuery()
+ {
+ return imp.newOQLQuery();
+ }
+
+ /**
+ * Create a new DList object.
+ */
+ public DList newDList()
+ {
+ return imp.newDList();
+ }
+
+ /**
+ * Create a new DBag object.
+ */
+ public DBag newDBag()
+ {
+ return imp.newDBag();
+ }
+
+ /**
+ * Create a new DSet object.
+ */
+ public DSet newDSet()
+ {
+ return imp.newDSet();
+ }
+
+ /**
+ * Not implemented yet.
+ */
+ public DArray newDArray()
+ {
+ throw new NotImplementedException();
+ }
+
+ /**
+ * Not implemented yet.
+ */
+ public DMap newDMap()
+ {
+ throw new NotImplementedException();
+ }
+
+ /**
+ * Get a String representation of the object's identifier.
+ */
+ public String getObjectId(Object obj)
+ {
+ return imp.getObjectId(obj);
+ }
+
+ /**
+ * Not implemented yet.
+ */
+ public Database getDatabase(Object obj)
+ {
+ throw new NotImplementedException();
+ }
+
+ /**
+ * Open database
+ */
+ public void openDB(String name, int accessMode) throws ODMGException
+ {
+ imp.openDB(name,accessMode);
+ }
+
+ /**
+ * Closes an open database. At the moment, only one database can be open at
+ * a given time and thus no parameter "database" is necessary here.
+ */
+ public void closeDB() throws ODMGException
+ {
+ imp.closeDB();
+ }
+
+ /**
+ * Begin a transaction.
+ */
+ public void beginTA()throws ODMGException
+ {
+ imp.beginTA();
+ }
+
+ /**
+ * Returns TRUE if a transaction is currently open.
+ */
+ public boolean isOpenTA()throws ODMGException
+ {
+ Debug.talkCritical( "RasImplementation::isOpenTA: calling imp.isOpenTA()" );
+ return imp.isOpenTA();
+ }
+
+ /**
+ * Commit a transaction.
+ */
+ public void commitTA()throws ODMGException
+ {
+ imp.commitTA();
+ }
+
+ /**
+ * Abort a transaction.
+ */
+ public void abortTA()throws ODMGException
+ {
+ imp.abortTA();
+ }
+
+ /**
+ * Set the maximum retry parameter
+ */
+ public void setMaxRetry(int newRetry)
+ {
+ imp.setMaxRetry(newRetry);
+ }
+
+ /**
+ * Get the maximum retry parameter
+ */
+ public int getMaxRetry()
+ {
+ return imp.getMaxRetry();
+ }
+
+ /**
+ * Set user identification : name/plain password
+ * (default is rasguest/rasguest)
+ */
+ public void setUserIdentification(String userName, String plainPass)
+ {
+ imp.setUserIdentification(userName,plainPass);
+ }
+
+ /**
+ * Set trace output threshold
+ * (0 = minimal, 4 = verbose; 1 = default)
+ */
+ public void setTraceThreshold( int level )
+ {
+ Debug.talkCritical( "setting trace level to " + level );
+ rasj.global.Debug.setDebugThreshold( level );
+ }
+
+}
+
+
diff --git a/java/rasj/RasImplementationInterface.java b/java/rasj/RasImplementationInterface.java
new file mode 100644
index 0000000..f59d506
--- /dev/null
+++ b/java/rasj/RasImplementationInterface.java
@@ -0,0 +1,95 @@
+package rasj;
+
+import org.odmg.*;
+import java.io.*;
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * This interface contains the methods implemented by RasOdmgImplementation and RasRnpImplementation
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+ public interface RasImplementationInterface extends Implementation
+ {
+ String getRasServer();
+
+ int dbIsOpen();
+
+ int getClientID();
+
+ int getAccessMode();
+
+ String getErrorStatus();
+
+ Transaction newTransaction();
+
+ Transaction currentTransaction();
+
+ Database newDatabase();
+
+ OQLQuery newOQLQuery();
+
+ DList newDList();
+
+ DBag newDBag();
+
+ DSet newDSet();
+
+ DArray newDArray();
+
+ DMap newDMap();
+
+ String getObjectId(Object obj);
+
+ Database getDatabase(Object obj);
+
+ void openDB(String name, int accessMode)throws ODMGException;
+
+ void closeDB() throws ODMGException;
+
+ void beginTA();
+
+ boolean isOpenTA();
+
+ void commitTA();
+
+ void abortTA();
+
+ void setMaxRetry(int newRetry);
+
+ int getMaxRetry();
+
+ void setUserIdentification(String userName, String plainPass);
+
+ Object queryRequest(String parameters) throws RasQueryExecutionFailedException;
+ }
+
diff --git a/java/rasj/RasIndexOutOfBoundsException.java b/java/rasj/RasIndexOutOfBoundsException.java
new file mode 100644
index 0000000..315c6d7
--- /dev/null
+++ b/java/rasj/RasIndexOutOfBoundsException.java
@@ -0,0 +1,127 @@
+package rasj;
+
+import rasj.global.*;
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * This exception is thrown when a cell index for an MDD exceeds
+ * the objects's bounds.
+ * @version $Revision: 1.6 $
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+
+public class RasIndexOutOfBoundsException extends RasException
+{
+ static final String rcsid = "@(#)Package rasj, class RasIndexOutOfBoundsException: $Header: /home/rasdev/CVS-repository/rasdaman/java/rasj/RasIndexOutOfBoundsException.java,v 1.6 2003/12/19 16:22:27 rasdev Exp $";
+
+ // lower bound
+ private long low;
+ // upper bound
+ private long high;
+ // index which caused the error
+ private long index;
+
+ /**
+ * stamdard constructor getting lower bound, upper bound and the index.
+ * @param dlow lower bound of the object
+ * @param dhigh upper bound of the object
+ * @param dindex the index that caused this exception
+ **/
+ protected RasIndexOutOfBoundsException(long dlow, long dhigh, long dindex )
+ {
+ super(RasGlobalDefs.INDEX_OUT_OF_BOUNDS);
+ low = dlow;
+ high = dhigh;
+ index = dindex;
+ }
+
+ /**
+ * Returns the error message.
+ * @return the error message.
+ **/
+ public String getMessage()
+ {
+ int i;
+
+ if(super.getMessage() == null)
+ {
+ String msg = RasErrorTexts.getErrorMessage(errNo);
+
+ StringBuffer buf = new StringBuffer(msg);
+ i = msg.indexOf( RasGlobalDefs.KEYWORD_LOW );
+ if(i != -1)
+ buf.replace(i, i+RasGlobalDefs.KEYWORD_LOW.length(), String.valueOf(low));
+ msg = buf.toString();
+ i = msg.indexOf( RasGlobalDefs.KEYWORD_HIGH );
+ if(i != -1)
+ buf.replace(i, i+RasGlobalDefs.KEYWORD_HIGH.length(), String.valueOf(high));
+ msg = buf.toString();
+ i = msg.indexOf( RasGlobalDefs.KEYWORD_INDEX );
+ if(i != -1)
+ buf.replace(i, i+RasGlobalDefs.KEYWORD_INDEX.length(), String.valueOf(index));
+ msg = buf.toString();
+ return msg;
+ }
+ else
+ return super.getMessage();
+ }
+
+ /**
+ * Returns the lower bound of the accessed object.
+ * @return the lower bound of the object
+ **/
+ public long getLow()
+ {
+ return low;
+ }
+
+ /**
+ * Returns the higher bound of the accessed object.
+ * @return the higher bound of the object
+ **/
+ public long getHigh()
+ {
+ return high;
+ }
+
+ /**
+ * Returns the index responsible for throwing this exception.
+ * @return the index that caused the exception
+ **/
+ public long getIndex()
+ {
+ return index;
+ }
+
+}
+
diff --git a/java/rasj/RasInvalidNameException.java b/java/rasj/RasInvalidNameException.java
new file mode 100644
index 0000000..72f3c88
--- /dev/null
+++ b/java/rasj/RasInvalidNameException.java
@@ -0,0 +1,77 @@
+package rasj;
+
+import rasj.global.*;
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * This exception is thrown if a object name contains unaccepted characters
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+
+public class RasInvalidNameException extends RasRuntimeException
+{
+ static final String rcsid = "@(#)Package rasj, class RasInvalidNameException: $Header: /home/rasdev/CVS-repository/rasdaman/java/rasj/RasInvalidNameException.java,v 1.3 2003/12/19 16:22:27 rasdev Exp $";
+
+ String wrongName = null;
+
+ public RasInvalidNameException(String name)
+ {
+ super(RasGlobalDefs.INVALID_OBJECT_NAME_ERROR);
+
+ wrongName = ( (name==null) ? "(null)" : name );
+ }
+
+ /**
+ * Returns the error message.
+ * @return the error message.
+ **/
+ public String getMessage()
+ {
+ int i;
+
+ if(super.getMessage() == null)
+ {
+ String msg = RasErrorTexts.getErrorMessage(errNo);
+
+ StringBuffer buf = new StringBuffer(msg);
+ i = msg.indexOf( RasGlobalDefs.KEYWORD_INVNAME );
+ if(i != -1)
+ buf.replace(i, i+RasGlobalDefs.KEYWORD_INVNAME.length(), wrongName);
+ msg = buf.toString();
+ return msg;
+ }
+ else
+ return super.getMessage();
+ }
+
+}
+
diff --git a/java/rasj/RasMArrayByte.java b/java/rasj/RasMArrayByte.java
new file mode 100644
index 0000000..71556a2
--- /dev/null
+++ b/java/rasj/RasMArrayByte.java
@@ -0,0 +1,110 @@
+package rasj;
+
+import rasj.*;
+import rasj.odmg.*;
+import rasj.global.*;
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * This class represents a MArray with base type Byte.
+ * @version $Revision: 1.7 $
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+public class RasMArrayByte extends RasGMArray
+{
+
+ /** default constructor */
+ public RasMArrayByte()
+ {
+ super();
+ typeLength = SIZE_OF_BYTE;
+ }
+
+ /**
+ * constructor for uninitialized MDD objects
+ * * @param initDomain The initial Domain of the MArray
+ */
+ public RasMArrayByte(final RasMInterval initDomain)
+ {
+ super(initDomain, SIZE_OF_BYTE);
+ }
+
+ /**
+ * Constructor for uninitialized MDD objects with Storage Layout
+ * @param initDomain The initial Domain of the MArray
+ * @param RasStorageLayout The storage layout to be used
+ */
+ public RasMArrayByte(final RasMInterval initDomain, RasStorageLayout stl)
+ {
+ super(initDomain, SIZE_OF_BYTE, stl);
+ }
+
+ /**
+ * copy constructor
+ * @param obj a copy of this object will be created
+ */
+ public RasMArrayByte(final RasMArrayByte obj)
+ {
+ super(obj);
+ }
+
+ /**
+ * subscript operator for read access of a cell. The cell value is returned
+ * as a byte[1] array.
+ */
+ public byte[] getCell(RasPoint point)
+ throws RasDimensionMismatchException, RasIndexOutOfBoundsException
+ {
+ //first test dimensionality
+ if(point.dimension() != domain.dimension())
+ throw new RasDimensionMismatchException(point.dimension(), domain.dimension());
+ byte[] retValue = new byte[1];
+ retValue[0] = data[(int)domain.cellOffset(point)];
+ return retValue;
+ }
+
+ /** subscript operator for read access of a cell. The cell value is returned as
+ * a Byte.
+ */
+ public byte getByte(final RasPoint point)
+ throws RasDimensionMismatchException, RasIndexOutOfBoundsException
+ {
+ // first test dimensionality
+ if(point.dimension() != domain.dimension())
+ throw new RasDimensionMismatchException(point.dimension(), domain.dimension());
+
+ return data[(int)domain.cellOffset(point)];
+ }
+
+
+}
+
diff --git a/java/rasj/RasMArrayDouble.java b/java/rasj/RasMArrayDouble.java
new file mode 100644
index 0000000..955ef6a
--- /dev/null
+++ b/java/rasj/RasMArrayDouble.java
@@ -0,0 +1,195 @@
+package rasj;
+
+import rasj.*;
+import rasj.odmg.*;
+import rasj.global.*;
+
+import java.io.*;
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * This class represents a MArray with base type double.
+ * @version $Revision: 1.5 $
+ * method intersectionWith(RasMInterval) uses byte array and is not optimized for special data arrays
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+
+public class RasMArrayDouble extends RasGMArray
+{
+
+ /** default constructor */
+ public RasMArrayDouble()
+ {
+ super();
+ typeLength = SIZE_OF_DOUBLE;
+ }
+
+ /**
+ * constructor for uninitialized MDD objects
+ * @param initDomain The initial Domain of the MArray
+ */
+ public RasMArrayDouble(final RasMInterval initDomain)
+ {
+ super(initDomain, SIZE_OF_DOUBLE);
+ objectData = new double[(int)(dataSize/SIZE_OF_DOUBLE)];
+ data = null;
+ }
+
+ /**
+ * Constructor for uninitialized MDD objects with Storage Layout
+ * @param initDomain The initial Domain of the MArray
+ * @param RasStorageLayout The storage layout to be used
+ */
+ public RasMArrayDouble(final RasMInterval initDomain, RasStorageLayout stl)
+ {
+ super(initDomain, SIZE_OF_DOUBLE, stl);
+ objectData = new double[(int)(dataSize/SIZE_OF_DOUBLE)];
+ data = null;
+ }
+
+ /**
+ * copy constructor
+ * @param obj a copy of this object will be created
+ */
+ public RasMArrayDouble(final RasMArrayDouble obj)
+ {
+ super(obj);
+ if(obj.objectData!=null)
+ {
+ objectData = new double[(int)(obj.dataSize/SIZE_OF_DOUBLE)];
+ System.arraycopy(obj.getDoubleArray(), 0, objectData, 0, (int)(obj.dataSize/SIZE_OF_DOUBLE));
+ data = null;
+ }
+ }
+
+ /**
+ * subscript operator for read access of a cell. The cell value is returned
+ * as a byte[4] array. This kind of access to a cell is significantly slower
+ * than getDouble(), because each cell value has to be converted from double to a
+ * byte[SIZE_OF_DOUBLE] array.
+ * The user has to take care that each Cell value is stored, before getting the next Cell.
+ */
+ public byte[] getCell(RasPoint point)
+ throws RasDimensionMismatchException, RasIndexOutOfBoundsException
+ {
+ double cellValue;
+ long tmp;
+
+ //first test dimensionality
+ if(point.dimension() != domain.dimension())
+ throw new RasDimensionMismatchException(point.dimension(), domain.dimension());
+
+ cellValue = ((double[])objectData)[(int)domain.cellOffset(point)];
+ for(int i=0; i<SIZE_OF_DOUBLE; i++)
+ {
+ tmp = Double.doubleToRawLongBits(cellValue);
+ tmp >>>= (((SIZE_OF_DOUBLE -1)-i)*8);
+ currentCell[i] = (byte)tmp;
+ }
+
+ return currentCell;
+ }
+
+ /** subscript operator for read access of a cell. The cell value is returned as
+ * an double. This access method is faster then getCell(), because no conversion
+ * from double to Byte[SIZE_OF_DOUBLE] has to be done.
+ */
+ public double getDouble(final RasPoint point)
+ throws RasDimensionMismatchException, RasIndexOutOfBoundsException
+ {
+ // first test dimensionality
+ if(point.dimension() != domain.dimension())
+ throw new RasDimensionMismatchException(point.dimension(), domain.dimension());
+
+ return ((double[])objectData)[(int)domain.cellOffset(point)];
+ }
+
+ /**
+ * get the internal representation of the array
+ */
+ public double[] getDoubleArray()
+ {
+ if(objectData==null)
+ {
+ ByteArrayInputStream bis = new ByteArrayInputStream(data);
+ DataInputStream dis = new DataInputStream(bis);
+ objectData = new double[data.length/SIZE_OF_DOUBLE];
+ try
+ {
+ for(int j=0; j<data.length/SIZE_OF_DOUBLE; j++)
+ {
+ ((double[])objectData)[j] = dis.readDouble();
+ }
+ }
+ catch(IOException e)
+ {
+ throw new RasClientInternalException("RasMArrayDouble", "getDoubleArray()",
+ "IOException while converting data to objectData array " + e.getMessage());
+ }
+ }
+ return (double[])objectData;
+ }
+
+ /** get the internal representation of the array in bytes,
+ * please use getDoubleArray()
+ */
+ public byte[] getArray()
+ {
+ if(data==null)
+ {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ DataOutputStream dos = new DataOutputStream(bos);
+ try
+ {
+ for(int j=0; j<((double[])objectData).length; j++)
+ dos.writeDouble(((double[])objectData)[j]);
+ }
+ catch(IOException e)
+ {
+ throw new RasClientInternalException("RasMArrayDouble", "getArray()",
+ "IOException while converting objectData to data array " + e.getMessage());
+ }
+ data = bos.toByteArray();
+ }
+ return data;
+ }
+
+ /** set the internal representation of the array */
+ public void setArray(double[] newData)
+ {
+ objectData = newData;
+ data = null;
+ dataSize = newData.length * SIZE_OF_DOUBLE;
+ }
+
+}
+
diff --git a/java/rasj/RasMArrayFloat.java b/java/rasj/RasMArrayFloat.java
new file mode 100644
index 0000000..d303823
--- /dev/null
+++ b/java/rasj/RasMArrayFloat.java
@@ -0,0 +1,195 @@
+package rasj;
+
+import rasj.*;
+import rasj.odmg.*;
+import rasj.global.*;
+import java.io.*;
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * This class represents a MArray with base type float.
+ * @version $Revision: 1.5 $
+ * method intersectionWith(RasMInterval) uses byte array and is not optimized for special data arrays
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+public class RasMArrayFloat extends RasGMArray
+{
+
+ /** default constructor */
+ public RasMArrayFloat()
+ {
+ super();
+ typeLength = SIZE_OF_FLOAT;
+ }
+
+ /**
+ * constructor for uninitialized MDD objects
+ * @param initDomain The initial Domain of the MArray
+ * */
+ public RasMArrayFloat(final RasMInterval initDomain)
+ {
+ super(initDomain, SIZE_OF_FLOAT);
+ objectData = new float[(int)(dataSize/SIZE_OF_FLOAT)];
+ data = null;
+ }
+
+ /**
+ * Constructor for uninitialized MDD objects with Storage Layout
+ * @param initDomain The initial Domain of the MArray
+ * @param RasStorageLayout The storage layout to be used
+ */
+ public RasMArrayFloat(final RasMInterval initDomain, RasStorageLayout stl)
+ {
+ super(initDomain, SIZE_OF_FLOAT, stl);
+ objectData = new float[(int)(dataSize/SIZE_OF_FLOAT)];
+ data = null;
+ }
+
+ /**
+ * copy constructor
+ * @param obj a copy of this object will be created
+ * */
+ public RasMArrayFloat(final RasMArrayFloat obj)
+ {
+ super(obj);
+ if(obj.objectData!=null)
+ {
+ objectData = new float[(int)(obj.dataSize/SIZE_OF_FLOAT)];
+ System.arraycopy(obj.getFloatArray(), 0, objectData, 0, (int)(obj.dataSize/SIZE_OF_FLOAT));
+ data = null;
+ }
+ }
+
+ /**
+ * subscript operator for read access of a cell. The cell value is returned
+ * as a byte[SIZE_OF_FLOAT] array. This kind of access to a cell is significantly slower
+ * than getFloat(), because each cell value has to be converted from float to a
+ * byte[SIZE_OF_FLOAT] array.
+ * The user has to take care that each Cell value is stored, before getting the next Cell.
+ */
+ public byte[] getCell(RasPoint point)
+ throws RasDimensionMismatchException, RasIndexOutOfBoundsException
+ {
+ float cellValue;
+ int tmp;
+
+ //first test dimensionality
+ if(point.dimension() != domain.dimension())
+ throw new RasDimensionMismatchException(point.dimension(), domain.dimension());
+
+ cellValue = ((float[])objectData)[(int)domain.cellOffset(point)];
+ for(int i=0; i<SIZE_OF_FLOAT; i++)
+ {
+ tmp = Float.floatToRawIntBits(cellValue);
+ tmp >>>= (((SIZE_OF_FLOAT -1)-i)*8);
+ currentCell[i] = (byte)tmp;
+ }
+
+ return currentCell;
+
+ }
+
+ /** subscript operator for read access of a cell. The cell value is returned as
+ * an float. This access method is faster then getCell(), because no conversion
+ * from float to Byte[SIZE_OF_FLOAT] has to be done.
+ */
+ public float getFloat( final RasPoint point)
+ throws RasDimensionMismatchException, RasIndexOutOfBoundsException
+ {
+ // first test dimensionality
+ if(point.dimension() != domain.dimension())
+ throw new RasDimensionMismatchException(point.dimension(), domain.dimension());
+
+ return ((float[])objectData)[(int)domain.cellOffset(point)];
+ }
+
+ /**
+ * get the internal representation of the array
+ */
+ public float[] getFloatArray()
+ {
+ if(objectData==null)
+ {
+ ByteArrayInputStream bis = new ByteArrayInputStream(data);
+ DataInputStream dis = new DataInputStream(bis);
+ objectData = new float[data.length/SIZE_OF_FLOAT];
+ try
+ {
+ for(int j=0; j<data.length/SIZE_OF_FLOAT; j++)
+ {
+ ((float[])objectData)[j] = dis.readFloat();
+ }
+ }
+ catch(IOException e)
+ {
+ throw new RasClientInternalException("RasMArrayFloat", "getFloatArray()",
+ "IOException while converting data to objectData array " + e.getMessage());
+ }
+ }
+ return (float[])objectData;
+ }
+
+ /** get the internal representation of the array in bytes,
+ * please use getFloatArray()
+ */
+ public byte[] getArray()
+ {
+ if(data==null)
+ {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ DataOutputStream dos = new DataOutputStream(bos);
+ try
+ {
+ for(int j=0; j<((float[])objectData).length; j++)
+ dos.writeFloat(((float[])objectData)[j]);
+ }
+ catch(IOException e)
+ {
+ throw new RasClientInternalException("RasMArrayFloat", "getArray()",
+ "IOException while converting objectData to data array " + e.getMessage());
+ }
+ data = bos.toByteArray();
+ }
+ return data;
+ }
+
+ /** set the internal representation of the array */
+ public void setArray(float[] newData)
+ {
+ objectData = newData;
+ data = null;
+ dataSize = newData.length * SIZE_OF_FLOAT;
+ }
+
+}
+
diff --git a/java/rasj/RasMArrayInteger.java b/java/rasj/RasMArrayInteger.java
new file mode 100644
index 0000000..bd07401
--- /dev/null
+++ b/java/rasj/RasMArrayInteger.java
@@ -0,0 +1,196 @@
+package rasj;
+
+import rasj.*;
+import rasj.odmg.*;
+import rasj.global.*;
+import java.io.*;
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * This class represents a MArray with base type Integer.
+ * @version $Revision: 1.11 $
+ * for ODMG type UShort(2 bytes, due to ODMG standard) you can use RasMArrayInteger,
+ * but only values up to 2^16 (performance loss because of convertion 4 bytes-> 2 bytes!);
+ * method intersectionWith(RasMInterval) uses byte array and is not optimized for special data arrays
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+public class RasMArrayInteger extends RasGMArray
+{
+
+ /** default constructor */
+ public RasMArrayInteger()
+ {
+ super();
+ typeLength = SIZE_OF_INTEGER;
+ }
+
+ /**
+ * constructor for uninitialized MDD objects
+ * @param initDomain The initial Domain of the MArray
+ * */
+ public RasMArrayInteger(final RasMInterval initDomain)
+ {
+ super(initDomain, SIZE_OF_INTEGER);
+ objectData = new int[(int)(dataSize/SIZE_OF_INTEGER)];
+ data = null;
+ }
+
+ /**
+ * Constructor for uninitialized MDD objects with Storage Layout
+ * @param initDomain The initial Domain of the MArray
+ * @param RasStorageLayout The storage layout to be used
+ */
+ public RasMArrayInteger(final RasMInterval initDomain, RasStorageLayout stl)
+ {
+ super(initDomain, SIZE_OF_INTEGER, stl);
+ objectData = new int[(int)(dataSize/SIZE_OF_INTEGER)];
+ data = null;
+ }
+
+
+ /**
+ * copy constructor
+ * @param obj a copy of this object will be created
+ */
+ public RasMArrayInteger(final RasMArrayInteger obj)
+ {
+ super(obj);
+ if(obj.objectData!=null)
+ {
+ objectData = new int[(int)(obj.dataSize/SIZE_OF_INTEGER)];
+ System.arraycopy(obj.getIntArray(), 0, objectData, 0, (int)(obj.dataSize/SIZE_OF_INTEGER));
+ data = null;
+ }
+ }
+
+ /**
+ * subscript operator for read access of a cell. The cell value is returned
+ * as a byte[SIZE_OF_INTEGER] array. This kind of access to a cell is significantly slower
+ * than getInt(), because each cell value has to be converted from int to a
+ * byte[SIZE_OF_INTEGER] array.
+ * The user has to take care that each Cell value is stored, before getting the next Cell.
+ */
+ public byte[] getCell(RasPoint point)
+ throws RasDimensionMismatchException, RasIndexOutOfBoundsException
+ {
+ int cellValue;
+ int tmp;
+
+ //first test dimensionality
+ if(point.dimension() != domain.dimension())
+ throw new RasDimensionMismatchException(point.dimension(), domain.dimension());
+
+ cellValue = ((int[])objectData)[(int)domain.cellOffset(point)];
+ for(int i=0; i<SIZE_OF_INTEGER; i++)
+ {
+ tmp = cellValue;
+ tmp >>>= (((SIZE_OF_INTEGER -1)-i)*8);
+ currentCell[i] = (byte)tmp;
+ }
+
+ return currentCell;
+
+ }
+
+ /** subscript operator for read access of a cell. The cell value is returned as
+ * an Integer. This access method is faster then getCell(), because no conversion
+ * from int to Byte[SIZE_OF_INTEGER] has to be done.
+ */
+ public int getInt( final RasPoint point)
+ throws RasDimensionMismatchException, RasIndexOutOfBoundsException
+ {
+ // first test dimensionality
+ if(point.dimension() != domain.dimension())
+ throw new RasDimensionMismatchException(point.dimension(), domain.dimension());
+
+ return ((int[])objectData)[(int)domain.cellOffset(point)];
+ }
+
+ /**
+ * get the internal representation of the array
+ */
+ public int[] getIntArray()
+ {
+ if(objectData==null)
+ {
+ ByteArrayInputStream bis = new ByteArrayInputStream(data);
+ DataInputStream dis = new DataInputStream(bis);
+ objectData = new int[data.length/SIZE_OF_INTEGER];
+ try
+ {
+ for(int j=0; j<data.length/SIZE_OF_INTEGER; j++)
+ {
+ ((int[])objectData)[j] = dis.readInt();
+ }
+ }
+ catch(IOException e)
+ {
+ throw new RasClientInternalException("RasMArrayInteger", "getIntArray()",
+ "IOException while converting data to objectData array " + e.getMessage());
+ }
+ }
+ return (int[])objectData;
+ }
+
+ /** get the internal representation of the array in bytes,
+ * please use getIntArray()
+ */
+ public byte[] getArray()
+ {
+ if(data==null)
+ {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ DataOutputStream dos = new DataOutputStream(bos);
+ try
+ {
+ for(int j=0; j<((int[])objectData).length; j++)
+ dos.writeInt(((int[])objectData)[j]);
+ }
+ catch(IOException e)
+ {
+ throw new RasClientInternalException("RasMArrayInteger", "getArray()",
+ "IOException while converting objectData to data array " + e.getMessage());
+ }
+ data = bos.toByteArray();
+ }
+ return data;
+ }
+
+ /** set the internal representation of the array */
+ public void setArray(int[] newData)
+ {
+ objectData = newData;
+ data = null;
+ dataSize = newData.length * SIZE_OF_INTEGER;
+ }
+}
+
diff --git a/java/rasj/RasMArrayLong.java b/java/rasj/RasMArrayLong.java
new file mode 100644
index 0000000..936f460
--- /dev/null
+++ b/java/rasj/RasMArrayLong.java
@@ -0,0 +1,198 @@
+package rasj;
+
+import rasj.*;
+import rasj.odmg.*;
+import rasj.global.*;
+import java.io.*;
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * This class represents a MArray with base type long.
+ * @version $Revision: 1.7 $
+ * for ODMG type Long(4 bytes, due to ODMG standard) please use RasMArrayInteger,
+ * for ODMG type ULong(4 bytes, due to ODMG standard) you can use RasMArrayLong,
+ * but only values up to 2^32 (performance loss because of convertion 8 bytes-> 4 bytes!);
+ * method intersectionWith(RasMInterval) uses byte array and is not optimized for special data arrays
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+public class RasMArrayLong extends RasGMArray
+{
+
+ /** default constructor */
+ public RasMArrayLong()
+ {
+ super();
+ typeLength = SIZE_OF_LONG;
+ }
+
+ /**
+ * constructor for uninitialized MDD objects
+ * @param initDomain The initial Domain of the MArray
+ */
+ public RasMArrayLong(final RasMInterval initDomain)
+ {
+ super(initDomain, SIZE_OF_LONG);
+ objectData = new long[(int)(dataSize/SIZE_OF_LONG)];
+ data = null;
+ }
+
+ /**
+ * Constructor for uninitialized MDD objects with Storage Layout
+ * @param initDomain The initial Domain of the MArray
+ * @param RasStorageLayout The storage layout to be used
+ */
+ public RasMArrayLong(final RasMInterval initDomain, RasStorageLayout stl)
+ {
+ super(initDomain, SIZE_OF_LONG, stl);
+ objectData = new long[(int)(dataSize/SIZE_OF_LONG)];
+ data = null;
+ }
+
+
+ /**
+ * copy constructor
+ * @param obj a copy of this object will be created
+ */
+ public RasMArrayLong(final RasMArrayLong obj)
+ {
+ super(obj);
+ if(obj.objectData!=null)
+ {
+ objectData = new long[(int)(obj.dataSize/SIZE_OF_LONG)];
+ System.arraycopy(obj.getLongArray(), 0, objectData, 0, (int)(obj.dataSize/SIZE_OF_LONG));
+ data = null;
+ }
+ }
+
+ /**
+ * subscript operator for read access of a cell. The cell value is returned
+ * as a byte[SIZE_OF_LONG] array. This kind of access to a cell is significantly slower
+ * than getLong(), because each cell value has to be converted from long to a
+ * byte[SIZE_OF_LONG] array.
+ * The user has to take care that each Cell value is stored, before getting the next Cell.
+ */
+ public byte[] getCell(RasPoint point)
+ throws RasDimensionMismatchException, RasIndexOutOfBoundsException
+ {
+ long cellValue;
+ long tmp;
+
+ //first test dimensionality
+ if(point.dimension() != domain.dimension())
+ throw new RasDimensionMismatchException(point.dimension(), domain.dimension());
+
+ cellValue = ((long[])objectData)[(int)domain.cellOffset(point)];
+ for(int i=0; i<SIZE_OF_LONG; i++)
+ {
+ tmp = cellValue;
+ tmp >>>= (((SIZE_OF_LONG -1)-i)*SIZE_OF_LONG);
+ currentCell[i] = (byte)tmp;
+ }
+
+ return currentCell;
+
+ }
+
+ /** subscript operator for read access of a cell. The cell value is returned as
+ * an long. This access method is faster then getCell(), because no conversion
+ * from long to Byte[SIZE_OF_LONG] has to be done.
+ */
+ public long getLong( final RasPoint point)
+ throws RasDimensionMismatchException, RasIndexOutOfBoundsException
+ {
+ // first test dimensionality
+ if(point.dimension() != domain.dimension())
+ throw new RasDimensionMismatchException(point.dimension(), domain.dimension());
+
+ return ((long[])objectData)[(int)domain.cellOffset(point)];
+ }
+
+ /**
+ * get the internal representation of the array
+ */
+ public long[] getLongArray()
+ {
+ if(objectData==null)
+ {
+ ByteArrayInputStream bis = new ByteArrayInputStream(data);
+ DataInputStream dis = new DataInputStream(bis);
+ objectData = new long[data.length/SIZE_OF_LONG];
+ try
+ {
+ for(int j=0; j<data.length/SIZE_OF_LONG; j++)
+ {
+ ((long[])objectData)[j] = dis.readLong();
+ }
+ }
+ catch(IOException e)
+ {
+ throw new RasClientInternalException("RasMArrayLong", "getLongArray()",
+ "IOException while converting data to objectData array " + e.getMessage());
+ }
+ }
+ return (long[])objectData;
+ }
+
+ /** get the internal representation of the array in bytes,
+ * please use getLongArray()
+ */
+ public byte[] getArray()
+ {
+ if(data==null)
+ {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ DataOutputStream dos = new DataOutputStream(bos);
+ try
+ {
+ for(int j=0; j<((long[])objectData).length; j++)
+ dos.writeLong(((long[])objectData)[j]);
+ }
+ catch(IOException e)
+ {
+ throw new RasClientInternalException("RasMArrayLong", "getArray()",
+ "IOException while converting objectData to data array " + e.getMessage());
+ }
+ data = bos.toByteArray();
+ }
+ return data;
+ }
+
+ /** set the internal representation of the array */
+ public void setArray(long[] newData)
+ {
+ objectData = newData;
+ data = null;
+ dataSize = newData.length * SIZE_OF_LONG;
+ }
+}
+
diff --git a/java/rasj/RasMArrayShort.java b/java/rasj/RasMArrayShort.java
new file mode 100644
index 0000000..98c4657
--- /dev/null
+++ b/java/rasj/RasMArrayShort.java
@@ -0,0 +1,195 @@
+package rasj;
+
+import rasj.*;
+import rasj.odmg.*;
+import rasj.global.*;
+import java.io.*;
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * This class represents a MArray with base type short.
+ * @version $Revision: 1.6 $
+ * method intersectionWith(RasMInterval) uses byte array and is not optimized for special data arrays
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+public class RasMArrayShort extends RasGMArray
+{
+
+ /** default constructor */
+ public RasMArrayShort()
+ {
+ super();
+ typeLength = SIZE_OF_SHORT;
+ }
+
+ /**
+ * constructor for uninitialized MDD objects
+ * @param initDomain The initial Domain of the MArray
+ */
+ public RasMArrayShort(final RasMInterval initDomain)
+ {
+ super(initDomain, SIZE_OF_SHORT);
+ objectData = new short[(int)(dataSize/SIZE_OF_SHORT)];
+ data = null;
+ }
+
+ /**
+ * Constructor for uninitialized MDD objects with Storage Layout
+ * @param initDomain The initial Domain of the MArray
+ * @param RasStorageLayout The storage layout to be used
+ */
+ public RasMArrayShort(final RasMInterval initDomain, RasStorageLayout stl)
+ {
+ super(initDomain, SIZE_OF_SHORT, stl);
+ objectData = new short[(int)(dataSize/SIZE_OF_SHORT)];
+ data = null;
+ }
+
+ /**
+ * copy constructor
+ * @param obj a copy of this object will be created
+ */
+ public RasMArrayShort(final RasMArrayShort obj)
+ {
+ super(obj);
+ if(obj.objectData!=null)
+ {
+ objectData = new short[(int)(obj.dataSize/SIZE_OF_SHORT)];
+ System.arraycopy(obj.getShortArray(), 0, objectData, 0, (int)(obj.dataSize/SIZE_OF_SHORT));
+ data = null;
+ }
+ }
+
+ /**
+ * subscript operator for read access of a cell. The cell value is returned
+ * as a byte[SIZE_OF_SHORT] array. This kind of access to a cell is significantly slower
+ * than getShort(), because each cell value has to be converted from short to a
+ * byte[SIZE_OF_SHORT] array.
+ * The user has to take care that each Cell value is stored, before getting the next Cell.
+ */
+ public byte[] getCell(RasPoint point)
+ throws RasDimensionMismatchException, RasIndexOutOfBoundsException
+ {
+ short cellValue;
+ short tmp;
+
+ //first test dimensionality
+ if(point.dimension() != domain.dimension())
+ throw new RasDimensionMismatchException(point.dimension(), domain.dimension());
+
+ cellValue = ((short[])objectData)[(int)domain.cellOffset(point)];
+ for(int i=0; i<SIZE_OF_SHORT; i++)
+ {
+ tmp = cellValue;
+ tmp >>>= (((SIZE_OF_SHORT -1)-i)*8);
+ currentCell[i] = (byte)tmp;
+ }
+
+ return currentCell;
+
+ }
+
+ /** subscript operator for read access of a cell. The cell value is returned as
+ * an short. This access method is faster then getCell(), because no conversion
+ * from short to byte[SIZE_OF_SHORT] has to be done.
+ */
+ public int getShort(final RasPoint point)
+ throws RasDimensionMismatchException, RasIndexOutOfBoundsException
+ {
+ // first test dimensionality
+ if(point.dimension() != domain.dimension())
+ throw new RasDimensionMismatchException(point.dimension(), domain.dimension());
+
+ return ((short[])objectData)[(int)domain.cellOffset(point)];
+ }
+
+ /**
+ * get the internal representation of the array
+ */
+ public short[] getShortArray()
+ {
+ if(objectData==null)
+ {
+ ByteArrayInputStream bis = new ByteArrayInputStream(data);
+ DataInputStream dis = new DataInputStream(bis);
+ objectData = new short[data.length/SIZE_OF_SHORT];
+ try
+ {
+ for(int j=0; j<data.length/SIZE_OF_SHORT; j++)
+ {
+ ((short[])objectData)[j] = dis.readShort();
+ }
+ }
+ catch(IOException e)
+ {
+ throw new RasClientInternalException("RasMArrayShort", "getShortArray()",
+ "IOException while converting data to objectData array " + e.getMessage());
+ }
+ }
+ return (short[])objectData;
+ }
+
+ /** get the internal representation of the array in bytes,
+ * please use getShortArray()
+ */
+ public byte[] getArray()
+ {
+ if(data==null)
+ {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ DataOutputStream dos = new DataOutputStream(bos);
+ try
+ {
+ for(int j=0; j<((short[])objectData).length; j++)
+ dos.writeShort(((short[])objectData)[j]);
+ }
+ catch(IOException e)
+ {
+ throw new RasClientInternalException("RasMArrayShort", "getArray()",
+ "IOException while converting objectData to data array " + e.getMessage());
+ }
+ data = bos.toByteArray();
+ }
+ return data;
+ }
+
+ /** set the internal representation of the array */
+ public void setArray(short[] newData)
+ {
+ objectData = newData;
+ data = null;
+ dataSize = newData.length * SIZE_OF_SHORT;
+ }
+
+}
+
diff --git a/java/rasj/RasMArrayType.java b/java/rasj/RasMArrayType.java
new file mode 100644
index 0000000..baef491
--- /dev/null
+++ b/java/rasj/RasMArrayType.java
@@ -0,0 +1,91 @@
+package rasj;
+
+import rasj.*;
+import rasj.global.*;
+
+import java.util.*;
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * This class represents the MArray type in the ODMG conformant
+ * representation of the RasDaMan type system.
+ * @version $Revision: 1.8 $
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+public class RasMArrayType extends RasType
+{
+ static final String rcsid = "@(#)Package rasj, class RasMArrayType: $Header: /home/rasdev/CVS-repository/rasdaman/java/rasj/RasMArrayType.java,v 1.8 2003/12/19 16:22:27 rasdev Exp $";
+
+ private RasBaseType baseType;
+
+ /**
+ * Default constructor.
+ **/
+ public RasMArrayType()
+ {
+ super();
+ baseType = null;
+ }
+
+ /**
+ * Constructor getting the type of th new MArray.
+ * @param newBaseType the type of the new MArray
+ **/
+ public RasMArrayType(RasBaseType newBaseType)
+ {
+ super("RAS_MARRAY");
+ typeID = RasGlobalDefs.RAS_MARRAY;
+ baseType = newBaseType;
+ }
+
+ /**
+ * Retrieves the base type of this MArray.
+ * @return the base type of this MArray
+ **/
+ public RasBaseType getBaseType()
+ {
+ return baseType;
+ }
+
+ /**
+ * Returns a string representing this object.
+ * @return the string representation of this object
+ **/
+ public String toString()
+ {
+ return super.toString() + "BaseType of MArray: \n" + baseType + "\n ";
+ }
+
+
+
+}
diff --git a/java/rasj/RasMInterval.java b/java/rasj/RasMInterval.java
new file mode 100644
index 0000000..dec1e3c
--- /dev/null
+++ b/java/rasj/RasMInterval.java
@@ -0,0 +1,1332 @@
+package rasj;
+
+import java.lang.*;
+import java.util.*;
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * The spatial domain of an MDD is represented by an object
+ * of class RasMInterval. It specifies lower and upper bound
+ * of the point set for each dimension of an MDD. Internally,
+ * the class is realized through an array of intervals of type
+ * RasSInterval.
+ *
+ * For the operations union, difference, and intersection the
+ * dimensionalties of the operands must be equal, otherwise an
+ * exception is raised. The semantics of the operations are
+ * defined as follows for each dimension:
+ *
+ * | ... fixed bound
+ * -* ... open bound
+ *
+ *
+ * class orientation union difference intersection
+ * -----------------------------------------------------------
+ * 1 |-a-| |-b-| error a error
+ *
+ * 2 |-a-| [a1,b2] [a1,b1] [b1,a2]
+ * 2 |-b-|
+ *
+ * 3 |--a--| a error b
+ * 3 |-b-|
+ *
+ * 4 |-b-| [b1,a2] [b2,a2] [a1,b2]
+ * 4 |-a-|
+ *
+ * 5 |--b--| b error a
+ * 5 |-a-|
+ *
+ * 6 |-b-| |-a-| error a error
+ *
+ * 7 |-a-|-b-| [a1,b2] a [a2,a2]
+ *
+ * 8 |-b-|-a-| [b1,a2] a [b2,b2]
+ *
+ * 9 |--a--| a [a1,b1] b
+ * 9 |-b-|
+ *
+ * 10 |--a--| a [b2,a2] b
+ * 10 |-b-|
+ *
+ * 11 |-a-| a error a
+ * 11 |-b-|
+ *
+ * 12 |--b--| b error a
+ * 12 |-a-|
+ *
+ * 13 |--b--| b error a
+ * 13 |-a-|
+ *
+ * -----------------------------------------------------
+ *
+ * 14 |--a--* a error b
+ * 14 |-b-|
+ *
+ * 15 |--a--* a [b2,a2] b
+ * 15 |-b-|
+ *
+ * 16 |-b-| |-a-* error a error
+ *
+ * 17 |-b-|-a-* [b1,a2] a [b2,b2]
+ *
+ * 18 |--a--* [b1,a2] [b2,a2] [a1,b2]
+ * 18 |-b-|
+ *
+ * -----------------------------------------------------
+ *
+ * 19 *--a--| a error b
+ * 19 |-b-|
+ *
+ * 20 *--a--| a [a1,b1] b
+ * 20 |-b-|
+ *
+ * 21 *-a-| |-b-| error a error
+ *
+ * 22 *-a-|-b-| [a1,b2] a [a2,a2]
+ *
+ * 23 *--a--| [a1,b2] [a1,b1] [b1,a2]
+ * 23 |-b-|
+ *
+ * -----------------------------------------------------
+ *
+ * 24 |--b--* b error a
+ * 24 |-a-|
+ *
+ * 25 |--b--* b error a
+ * 25 |-a-|
+ *
+ * 26 |-a-| |-b-* error a error
+ *
+ * 27 |-a-|-b-* [a1,b2] a [a2,a2]
+ *
+ * 28 |--b--* [a1,b2] [a1,b1] [b1,a2]
+ * 28 |-a-|
+ *
+ * -----------------------------------------------------
+ *
+ * 29 *--b--| b error a
+ * 29 |-a-|
+ *
+ * 30 *--b--| b error a
+ * 30 |-a-|
+ *
+ * 31 *-b-| |-a-| error a error
+ *
+ * 32 *-b-|-a-| [b1,a2] a [b2,b2]
+ *
+ * 33 *--b--| [b1,a2] [b2,a2] [a1,b2]
+ * 33 |-a-|
+ *
+ * -----------------------------------------------------
+ *
+ * 34 *-a-| |-b-* error a error
+ *
+ * 35 *-a-|-b-* [a1,b2] a [a2,a2]
+ *
+ * 36 *-a-| [a1,b2] [a1,b1] [b1,a2]
+ * 36 |-b-*
+ *
+ * -----------------------------------------------------
+ *
+ * 37 *-b-| |-a-* error a error
+ *
+ * 38 *-b-|-a-* [b1,a2] a [b2,b2]
+ *
+ * 39 *-b-| [b1,a2] [a1,b1] [a1,b2]
+ * 39 |-a-*
+ *
+ * -----------------------------------------------------
+ *
+ * 40 *-a-| b error a
+ * 40 *-b-|
+ *
+ * 41 *-a-| a error a
+ * 41 *-b-|
+ *
+ * 42 *-b-| a [b2,a2] b
+ * 42 *-a-|
+ *
+ * -----------------------------------------------------
+ *
+ * 43 |-a-* a [a1,b1] b
+ * 43 |-b-*
+ *
+ * 44 |-a-* a error a
+ * 44 |-b-*
+ *
+ * 45 |-b-* b error a
+ * 45 |-a-*
+ *
+ * -----------------------------------------------------
+ * 46 *-a-* |-b-| a error b
+ *
+ * 47 *-b-* |-a-| b error b
+ *
+ * 48 *-a-* a [b2,a2] b
+ * 48 *-b-|
+ *
+ * 49 *-a-* a [a1,b1] b
+ * 49 |-b-*
+ *
+ * 50 *-b-* b error a
+ * 50 *-a-|
+ *
+ * 51 *-b-* b error a
+ * 51 |-a-*
+ *
+ * 52 *-a-* a error a
+ * 52 *-b-*
+ *
+ * Attention: The difference operation has to be reconsidered in future
+ * concerning a discrete interpretation of the intervals.
+ *
+ * The closure operation defines an interval which is the smallest
+ * interval containing the two operands.
+ * The method intersectsWith() returns false in the error cases of the
+ * intersection operation and true otherwise.
+ *
+ * * @version $Revision: 1.15 $
+ *
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+
+public class RasMInterval
+{
+ static final String rcsid = "@(#)Package rasj, class RasMInterval: $Header: /home/rasdev/CVS-repository/rasdaman/java/rasj/RasMInterval.java,v 1.15 2003/12/10 21:04:23 rasdev Exp $";
+
+ /** array for storing the intervals */
+ protected RasSInterval[] intervals;
+
+ /** dimensionality of the domain */
+ protected int dimensionality;
+
+ /** number of components initialized already */
+ protected int streamInitCnt;
+
+ /**
+ * Constructor getting dimensionality for stream initializing.
+ * @param dim the dimensionality of this MInterval
+ **/
+ public RasMInterval(int dim)
+ {
+ dimensionality = dim;
+ streamInitCnt = 0;
+ intervals = new RasSInterval[dimensionality];
+
+ for(int i=0; i<dim; i++)
+ intervals[i] = new RasSInterval();
+ }
+
+ /**
+ * Constructor taking a string representation (for example "[1:255, 1:200]").
+ * @param mIntStr a string specifying the MInterval
+ **/
+ public RasMInterval(String mIntStr) throws RasResultIsNoIntervalException
+ {
+ dimensionality = 1;
+ streamInitCnt = 0;
+
+ if(mIntStr.trim().charAt(0) != '[')
+ {
+ // error
+ dimensionality = 0;
+ return;
+ }
+
+ /** for parsing the string */
+
+ StringTokenizer strTok = new StringTokenizer(mIntStr.trim(), "[:,]");
+ String strCurTok = null;
+
+ /** calculate dimensionality */
+ dimensionality = strTok.countTokens()/2;
+
+ intervals = new RasSInterval[ dimensionality ];
+
+
+ for(int i=0; i<dimensionality; i++)
+ {
+ RasSInterval sint = new RasSInterval();
+
+ strCurTok = strTok.nextToken();
+
+ if(strCurTok.equals("*"))
+ {
+ sint.setLow('*');
+ }
+ else
+ {
+ sint.setLow(Long.parseLong(strCurTok.trim()));
+ }
+
+
+ strCurTok = strTok.nextToken();
+
+ if(strCurTok.equals("*"))
+ {
+ sint.setHigh('*');
+ }
+ else
+ {
+ sint.setHigh(Long.parseLong(strCurTok.trim()));
+ }
+
+ intervals[i] = sint;
+ }
+ }
+
+ /**
+ * Method for stream initialization with intervals.
+ * @param newInterval the interval that has to be streamed
+ **/
+ public void stream(final RasSInterval newInterval) throws RasStreamInputOverflowException
+ {
+ if(streamInitCnt >= dimensionality)
+ throw new RasStreamInputOverflowException();
+
+ intervals[streamInitCnt++] = newInterval;
+
+ }
+
+ /**
+ * Method for stream initialization with point intervals.
+ * @param p the point interval that has to be streamed
+ **/
+ public void stream(long p) throws RasStreamInputOverflowException, RasResultIsNoIntervalException
+ {
+ if(streamInitCnt >= dimensionality)
+ throw new RasStreamInputOverflowException();
+
+ intervals[streamInitCnt++] = new RasSInterval(p, p);
+
+ }
+
+ /**
+ * Default constructor.
+ **/
+ public RasMInterval()
+ {
+ dimensionality = 0;
+ streamInitCnt = 0;
+
+ intervals = null;
+ }
+
+ /**
+ * Copy constructor.
+ * @param mInterval the MInterval that is to be copied
+ **/
+ public RasMInterval(final RasMInterval mInterval)
+ throws RasStreamInputOverflowException, RasIndexOutOfBoundsException
+ {
+ dimensionality = mInterval.dimension();
+ streamInitCnt = mInterval.streamInitCnt;
+ intervals = new RasSInterval[ dimensionality ];
+
+ for(int i=0; i<dimensionality; i++)
+ intervals[i] = new RasSInterval(mInterval.item(i));
+ }
+
+ /**
+ * Determines if the self mInterval intersects with the delivered one.
+ * @param mInterval the MInterval to be intersected
+ **/
+ public boolean intersectsWith(final RasMInterval mInterval)
+ throws RasDimensionMismatchException, RasIndexOutOfBoundsException
+ {
+ boolean result = true;
+
+ if(dimensionality != mInterval.dimension())
+ throw new RasDimensionMismatchException( dimensionality, mInterval.dimension());
+
+ /** none of the interval pairs are allowed to be disjoint */
+ for(int i=0; i<dimensionality; i++)
+ {
+ if(0 == intervals[i].intersectsWith(mInterval.item(i)) || -1 == intervals[i].intersectsWith(mInterval.item(i)))
+ {
+ result = false;
+ break;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Read access the i-th interval.
+ * @param i the dimension to be read
+ **/
+ public RasSInterval item(int i) throws RasIndexOutOfBoundsException
+ {
+ if(i < 0 || i >= dimensionality)
+ throw new RasIndexOutOfBoundsException(0, dimensionality-1, i);
+
+ return intervals[i];
+ }
+
+ /**
+ * Write access to the i-th interval.
+ * @param i the dimension that is to be accessed
+ * @param value the interval that is to be assigned to the specified dimension
+ **/
+ public void setItem(int i, RasSInterval value) throws RasIndexOutOfBoundsException
+ {
+ if(i < 0 || i >= dimensionality)
+ throw new RasIndexOutOfBoundsException(0, dimensionality-1, i);
+ intervals[i] = value;
+ }
+
+ /*
+ * set MInterval
+ public final RasMInterval setTo(final RasMInterval mInterval)
+ throws RasStreamInputOverflowException, RasIndexOutOfBoundsException
+ {
+ if(this != mInterval)
+ {
+ if((intervals != null) && dimensionality != mInterval.dimension())
+ {
+ intervals = null;
+ }
+
+ dimensionality = mInterval.dimension();
+ streamInitCnt = mInterval.streamInitCnt;
+
+ if(intervals == null)
+ intervals = new RasSInterval[ dimensionality ];
+
+ for(int i=0; i<dimensionality; i++)
+ intervals[i] = new RasSInterval(mInterval.item(i));
+ }
+
+ return this;
+ }
+ */
+
+ /**
+ * Method for testing equality of two MIntervals. Two domains are equal
+ * if they have the same number of dimensions and each dimension has the
+ * same lower and upper bounds.
+ * @param mint the MInterval that is compared to this MInterval
+ * @return true if the two MIntervals are equal
+ **/
+ public boolean equals(final RasMInterval mint)
+ {
+ boolean returnValue = false;
+
+ try {
+ if(dimensionality == mint.dimensionality)
+ {
+ returnValue = true;
+
+ for(int i=0; i<dimensionality && returnValue ; i++)
+ returnValue &= (intervals[i] == mint.item(i));
+ }
+
+ return returnValue;
+ }
+
+ catch(RasIndexOutOfBoundsException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Method for testing inequality. This is the negation of the equals method.
+ * @param mint the MInterval that is compared to this MInterval
+ * @return true if the two MIntervals are not equal
+ **/
+ public boolean notEquals(final RasMInterval mint)
+ {
+ return !equals(mint);
+ }
+
+ /**
+ * Method for testing if this interval covers the given point.
+ * @param pnt the point to be tested
+ * @return
+ * <TABLE BORDER=0 CELLPADDING=3>
+ * <TR><TD ALIGN=RIGHT><B>-1</B></TD><TD> if the point has not the same dimensionality</TD></TR>
+ * <TR><TD ALIGN=RIGHT><B>1</B></TD><TD> if the point is covered by this MInterval</TD></TR>
+ * <TR><TD ALIGN=RIGHT><B>0</B></TD><TD> if the point is not covered</TD></TR>
+ * </TABLE>
+ **/
+ public final int covers(RasPoint pnt)
+ {
+ if (dimensionality != pnt.dimension())
+ return -1;
+ try {
+ for (int i = 0; i < pnt.dimension(); i++)
+ {
+ if ((intervals[i].isLowFixed() && pnt.item(i) < intervals[i].low()) ||
+ (intervals[i].isHighFixed() && pnt.item(i) > intervals[i].high()))
+ return 0;
+ }
+ return 1;
+ }
+ catch(RasIndexOutOfBoundsException e) {
+ // This cannot occur (theoretically)
+ throw new RasClientInternalException("RasMInterval","covers(RasPoint pnt)",e.getMessage());
+ }
+ }
+
+ /**
+ * Method for testing if this interval covers the given interval.
+ * @param inter2 the MInterval to be tested
+ * @return
+ * <TABLE BORDER=0i CELLPADDING=3>
+ * <TR><TD ALIGN=RIGHT><B>-1</B></TD><TD> if the point has not the same dimensionality</TD></TR>
+ * <TR><TD ALIGN=RIGHT><B>1</B></TD><TD> if the point is covered by this MInterval</TD></TR>
+ * <TR><TD ALIGN=RIGHT><B>0</B></TD><TD> if the point is not covered</TD></TR>
+ **/
+ public int covers(RasMInterval inter2)
+ {
+ if(dimensionality != inter2.dimension())
+ return -1;
+
+ try {
+ for (int i = 0; i < dimensionality ; i++)
+ {
+ if (
+ ( intervals[i].isLowFixed() &&
+ (!(inter2.item(i).isLowFixed()) ||
+ intervals[i].low() > inter2.item(i).low() // both lows fixed here
+ )
+ ) || // end of lows check
+ ( intervals[i].isHighFixed() &&
+ (!(inter2.item(i).isHighFixed()) ||
+ intervals[i].high() < inter2.item(i).high() // both highs fixed here
+ )
+ )
+ )
+ return 0;
+ }
+ return 1;
+ }
+ catch( RasIndexOutOfBoundsException e) {
+ // this can not occur (theoretically)
+ throw new RasClientInternalException("RasMInterval","covers(RasMInterval inter2)",e.getMessage());
+ }
+ }
+
+ /**
+ * Gets the dimensionality of this MInterval.
+ * @return the dimensionality of this MInterval
+ **/
+ public int dimension()
+ {
+ return dimensionality;
+ }
+
+ /**
+ * Gets the point with the lowest coordinates in every dimension.
+ * @return the origin of this MInterval (the point with the lowest coordinates)
+ **/
+ public RasPoint getOrigin()
+ {
+ try {
+ int i;
+ RasPoint pt = new RasPoint(dimensionality);
+
+ for(i=0; i<dimensionality; i++)
+ pt.stream(intervals[i].low());
+
+ return pt;
+ }
+ catch(RasStreamInputOverflowException e) {
+ // This cannot occur (theoretically)
+ throw new RasClientInternalException("RasMInterval","getOrigin()",e.getMessage());
+ }
+ }
+
+ /**
+ * Gets the point with the highest coordinates in every dimension.
+ * @return the point with the highest coordinates in this MInterval
+ **/
+ public RasPoint getHigh()
+ {
+ try {
+ int i;
+ RasPoint pt = new RasPoint(dimensionality);
+
+ for(i=0; i<dimensionality; i++)
+ pt.stream(intervals[i].high());
+
+ return pt;
+ }
+ catch(RasStreamInputOverflowException e) {
+ // This cannot occur (theoretically)
+ throw new RasClientInternalException("RasMInterval","getHigh()",e.getMessage());
+ }
+ }
+
+ /**
+ * Gets the size of this MInterval as a point, that means the point specifies the extent
+ * of this MInterval ( i.e. high() - low() ) in each dimension.
+ * @return the size of this MInterval
+ **/
+ public RasPoint getExtent()
+ {
+ try {
+ int i;
+ RasPoint pt = new RasPoint(dimensionality);
+
+ for(i=0; i<dimensionality; i++)
+ pt.stream(intervals[i].high() - intervals[i].low() + 1);
+
+ return pt;
+ }
+ catch(RasStreamInputOverflowException e) {
+ // This cannot occur (theoretically)
+ System.err.println("Error in method RasMInterval.getExtent()");
+ return null;
+ }
+ }
+
+ /**
+ * This method checks if this MInterval is mergeable with another MInterval.
+ * Two RasMIntervals are "mergeable" if they have the same low() and high()
+ * values in all dimensions except in one where they differ by one point,
+ * this is, a.low()==b.high()+1 or b.low()==a.high()+1. For instance, the
+ * following two blocks are mergeable:
+ *
+ * <pre>
+ * +-------------+---------------------------------------+
+ * | A | B |
+ * +-------------|---------------------------------------|
+ *
+ * and the following two are not:
+ *
+ * +-------------+-------------------------+
+ * | | B |
+ * | A +-------------------------+
+ * +-------------+
+ *
+ * </pre>
+ * @param b the MInterval to be checked
+ * @return true if the two intervalls are mergeable
+ **/
+ public boolean isMergeable(final RasMInterval b)
+ {
+ final RasMInterval a = this; // An alias to this object
+
+ // The blocks must have the same dimensionality to be mergeable
+ if (a.dimensionality != b.dimensionality)
+ return false;
+
+ // Count the number of adjacent frontiers
+ int onesDifferences = 0;
+
+ // Is Mergeable variable
+ boolean isMerg = true;
+
+ // For all dimensions
+ try {
+ for (int i=0; i<dimensionality; i++)
+ {
+ if (a.item(i).low() != b.item(i).low()) // Diferente origins
+ {
+ if ((a.item(i).low() == b.item(i).high()+1) || // If borders are adjacent
+ (b.item(i).low() == a.item(i).high()+1))
+ {
+ ++onesDifferences; // Update counter
+ }
+ else
+ {
+ isMerg = false; // Else non-mergeable blocks
+ break;
+ }
+ }
+ else // Same origins
+ {
+ if (a.item(i).high() != b.item(i).high()) // Check ending
+ {
+ isMerg = false; // Not the same, can't be
+ break; // mergeable
+ }
+ }
+ }
+
+ if (isMerg && (onesDifferences!=1)) // Only one adjacent borded
+ isMerg = false; // allowed
+
+ return isMerg; // Return result
+ }
+
+ catch(RasIndexOutOfBoundsException e) {
+ // This cannot occur (theoretically)
+ throw new RasClientInternalException("RasMInterval","isMergeable()",e.getMessage());
+ }
+
+ }
+
+ /**
+ * This methods translates the current MInterval by a point.
+ * It adds the coordinates of the given point to the lower bounds of the
+ * current MInterval. This operation is only legal if all lower bounds are
+ * fixed and the point has the same dimension as the MInterval!<P>
+ * Note that this method modifies the current MInterval. If you want to
+ * get a new MInterval, use the {@link #createTranslation(RasPoint) createTranslation} method
+ * instead.<P>
+ * @param t the point to be added
+ * @return the current MInterval
+ **/
+ public RasMInterval translate(RasPoint t)
+ throws RasDimensionMismatchException, RasResultIsNoIntervalException
+ {
+ int i;
+
+ if(dimensionality != t.dimension())
+ throw new RasDimensionMismatchException(dimensionality, t.dimension());
+
+ try {
+
+ for(i=0; i<dimensionality; i++)
+ {
+ intervals[i].setInterval(intervals[i].low() + t.item(i),
+ intervals[i].high() + t.item(i));
+ }
+ }
+ catch(RasIndexOutOfBoundsException e) {
+ // this cannor occur (theoretically)
+ throw new RasClientInternalException("RasMInterval","translate()",e.getMessage());
+ }
+
+ return this;
+ }
+
+
+ /**
+ * This method returns a new MInterval resulting from a translation of the current
+ * MInterval by the given point.
+ * It creates a copy of the current MInterval and adds the coordinates of the given
+ * point to its lower bounds.<P>
+ * This operation is only legal if all lower bounds are
+ * fixed and the point has the same dimension as the MInterval!<P>
+ * @param t the point to be added
+ * @return the new MInterval
+ **/
+ public RasMInterval createTranslation(RasPoint t)
+ throws RasDimensionMismatchException, RasResultIsNoIntervalException
+ {
+ if(dimensionality != t.dimension())
+ throw new RasDimensionMismatchException(dimensionality, t.dimension());
+
+ RasMInterval result = new RasMInterval(dimensionality);
+
+ try {
+ for(int i=0; i<dimensionality; i++)
+ result.intervals[i].setInterval(intervals[i].low() + t.item(i),
+ intervals[i].high() + t.item(i));
+ }
+ catch(RasIndexOutOfBoundsException e) {
+ // this cannot occur (theoretically)
+ throw new RasClientInternalException("RasMInterval","createTranslation()",e.getMessage());
+ }
+
+ return result;
+ }
+
+ /**
+ * Calculates the union of two MIntervals. This is only possible for two MIntervals
+ * having the same dimensionality.
+ * <P>Note that this operation modifies the current object. If you want to get a new MInterval,
+ * use {@link #createUnion(RasMInterval) createUnion} instead.</P>
+ * @param mint1 the first MInterval
+ * @param mint2 the second MInterval
+ * @return the current MInterval (representing the union of mint1 and mint2)
+ **/
+ public RasMInterval unionOf(final RasMInterval mint1, final RasMInterval mint2)
+ throws RasDimensionMismatchException, RasResultIsNoIntervalException
+ {
+ if(mint1.dimension() != mint2.dimension())
+ throw new RasDimensionMismatchException( mint1.dimension(), mint2.dimension());
+
+ // cleanup + initializing of this
+
+ dimensionality = mint1.dimension();
+ streamInitCnt = dimensionality;
+ intervals = new RasSInterval[ dimensionality ];
+
+ try {
+
+ for(int i=0; i<dimensionality; i++)
+ {
+ intervals[i] = new RasSInterval();
+ intervals[i].unionOf(mint1.item(i), mint2.item(i));
+ }
+ return this;
+ }
+ catch(RasIndexOutOfBoundsException e) {
+ // this cannot occur (theoretically)
+ throw new RasClientInternalException("RasMInterval","unionOf()",e.getMessage());
+ }
+
+ }
+
+ /**
+ * Calculates the union of the current MIntervall with another one.
+ * <P>Note that this operation modifies the current object. If you want to get a new MInterval,
+ * use {@link #createUnion(RasMInterval) createUnion} instead.</P>
+ * @param mint the MInterval to be used for the union
+ * @return the current MInterval (after the union with mint)
+ **/
+ public RasMInterval unionWith(final RasMInterval mint)
+ throws RasDimensionMismatchException, RasResultIsNoIntervalException
+ {
+ if(dimensionality != mint.dimension())
+ throw new RasDimensionMismatchException( dimensionality, mint.dimension());
+
+ try {
+
+ for(int i=0; i<dimensionality; i++)
+ intervals[i].unionWith(mint.item(i));
+ return this;
+ }
+ catch(RasIndexOutOfBoundsException e) {
+ // this cannot occur (theoretically)
+ throw new RasClientInternalException("RasMInterval","unionWith()",e.getMessage());
+ }
+
+ }
+
+ /**
+ * @deprecated This methdod provides just another name for the
+ * unionWith method and might not be supported in future versions. Please
+ * use {@link #unionWith(RasMInterval) unionWith} instead.
+ * @param mint the MInterval to be added
+ * @return the current MInterval after adding mint
+ **/
+ public RasMInterval addToSelf(final RasMInterval mint)
+ throws RasDimensionMismatchException, RasResultIsNoIntervalException
+ {
+ return unionWith(mint);
+ }
+
+
+ /**
+ * Returns a new MInterval calculated from a union of the current MInterval
+ * and the given one.
+ * @param mint the MInterval to be unioned with this MInterval
+ * @return the union of this MInterval and mint
+ **/
+ public RasMInterval createUnion(final RasMInterval mint)
+ throws RasDimensionMismatchException, RasResultIsNoIntervalException
+ {
+ if(dimensionality != mint.dimension())
+ throw new RasDimensionMismatchException( dimensionality, mint.dimension());
+
+ RasMInterval result = new RasMInterval(dimensionality);
+ try {
+ for(int i=0; i<dimensionality; i++)
+ result.stream(intervals[i].createUnion(mint.item(i)));
+ return result;
+ }
+ catch(RasIndexOutOfBoundsException e) {
+ // this cannot occur (theoretically)
+ throw new RasClientInternalException("RasMInterval","createUnion()",e.getMessage());
+ }
+ catch(RasStreamInputOverflowException e) {
+ // this cannot occur (theoretically)
+ throw new RasClientInternalException("RasMInterval","createUnion()",e.getMessage());
+ }
+
+ }
+
+
+ /**
+ * @deprecated This methdod provides just another name for the
+ * createUnion method and might not be supported in future versions. Please
+ * use {@link #createUnion(RasMInterval) createUnion} instead.
+ * @param mint the MInterval to be added
+ * @return the current MInterval after adding mint
+ **/
+ public RasMInterval add(final RasMInterval mint)
+ throws RasDimensionMismatchException, RasResultIsNoIntervalException
+ {
+ return createUnion(mint);
+ }
+
+
+ /**
+ * Calculates the difference of two MIntervals.
+ * <P>Note that this operation modifies the current object. If you want to get a new MInterval,
+ * use {@link #createDifference(RasMInterval) createDifference} instead.</P>
+ * @param mint1 the first MInterval
+ * @param mint2 the second MInterval
+ * @return the current MInterval (representing the difference of mint1 and mint2)
+ **/
+ public RasMInterval differenceOf(final RasMInterval mint1, final RasMInterval mint2)
+ throws RasDimensionMismatchException, RasResultIsNoIntervalException
+ {
+ if(mint1.dimension() != mint2.dimension())
+ throw new RasDimensionMismatchException( mint1.dimension(), mint2.dimension());
+
+ // cleanup + initializing of this
+
+ dimensionality = mint1.dimension();
+ streamInitCnt = dimensionality;
+ intervals = new RasSInterval[ dimensionality ];
+
+ try {
+
+ for(int i=0; i<dimensionality; i++)
+ {
+ intervals[i] = new RasSInterval();
+ intervals[i].differenceOf(mint1.item(i), mint2.item(i));
+ }
+ return this;
+ }
+ catch(RasIndexOutOfBoundsException e) {
+ // this cannot occur (theoretically)
+ throw new RasClientInternalException("RasMInterval","differenceOf()",e.getMessage());
+ }
+ }
+
+ /**
+ * Calculates the difference of the current MInterval and the given one.
+ * <P>Note that this operation modifies the current object. If you want to get a new MInterval,
+ * use {@link #createDifference(RasMInterval) createDifference} instead.</P>
+ * @param mint the MInterval used for building the difference
+ * @return the current MInterval (representing the difference of this MInterval and mint)
+ **/
+ public RasMInterval differenceWith(final RasMInterval mint)
+ throws RasDimensionMismatchException, RasResultIsNoIntervalException
+ {
+ if(dimensionality != mint.dimension())
+ throw new RasDimensionMismatchException(dimensionality, mint.dimension());
+
+ try {
+ for(int i=0; i<dimensionality; i++)
+ {
+ intervals[i].differenceWith(mint.item(i));
+ }
+ return this;
+ }
+ catch(RasIndexOutOfBoundsException e) {
+ // this cannot occur (theoretically)
+ throw new RasClientInternalException("RasMInterval","differenceWith()",e.getMessage());
+ }
+ }
+
+ /**
+ * @deprecated This methdod provides just another name for the
+ * differenceWith method and might not be supported in future versions. Please
+ * use {@link #differenceWith(RasMInterval) differenceWith} instead.
+ * @param mint1 the MInterval used for building the difference
+ * @return the difference of this MInterval and mint2
+ **/
+ public RasMInterval diffFromSelf(RasMInterval mint)
+ throws RasDimensionMismatchException, RasResultIsNoIntervalException
+ {
+ return differenceWith(mint);
+ }
+
+ /**
+ * Returns a new MInterval calculated from a difference of the current MInterval
+ * and the given one.
+ * @param mint the MInterval used for calculating the difference with the current MInterval
+ * @return the difference of this MInterval and mint
+ **/
+ public RasMInterval createDifference(RasMInterval mint)
+ throws RasDimensionMismatchException, RasResultIsNoIntervalException
+ {
+ if(dimensionality != mint.dimension())
+ throw new RasDimensionMismatchException(dimensionality, mint.dimension());
+
+ RasMInterval result = new RasMInterval(dimensionality);
+
+ try {
+ for(int i=0; i<dimensionality; i++)
+ result.stream(intervals[i].createDifference(mint.item(i)));
+ return result;
+ }
+ catch(RasIndexOutOfBoundsException e) {
+ // this cannot occur (theoretically)
+ throw new RasClientInternalException("RasMInterval","createDifference()",e.getMessage());
+ }
+ catch(RasStreamInputOverflowException e) {
+ // this cannot occur (theoretically)
+ throw new RasClientInternalException("RasMInterval","createDifference()",e.getMessage());
+ }
+
+ }
+
+ /**
+ * @deprecated This methdod provides just another name for the
+ * createDifference method and might not be supported in future versions. Please
+ * use {@link #createDifference(RasMInterval) createDifference} instead.
+ * @param mint the MInterval used for calculating the difference with the current MInterval
+ * @return the difference of this MInterval and mint
+ **/
+ public RasMInterval diff(RasMInterval mint)
+ throws RasDimensionMismatchException, RasResultIsNoIntervalException
+ {
+ return createDifference(mint);
+ }
+
+
+ // Methods/Operators for the intersection operation:
+ /**
+ * This method calculates the intersection of two MIntervals. This is only possible if the
+ * two MIntervals have the same dimensionality.
+ * <P>Note that this operation modifies the current object. If you want to get a new MInterval,
+ * use {@link #createIntersection(RasMInterval) createIntersection} instead.</P>
+ * @param mint1 the first MInterval
+ * @param mint2 the second MInterval
+ * @return the current MInterval (representing the intersection of mint1 and mint2)
+ **/
+ public RasMInterval intersectionOf(RasMInterval mint1, RasMInterval mint2)
+ throws RasDimensionMismatchException, RasResultIsNoIntervalException
+ {
+ if(mint1.dimension() != mint2.dimension())
+ throw new RasDimensionMismatchException( mint1.dimension(), mint2.dimension());
+
+ // cleanup + initializing of this
+
+ dimensionality = mint1.dimension();
+ streamInitCnt = dimensionality;
+ intervals = new RasSInterval[ dimensionality ];
+
+ try {
+ for(int i=0; i<dimensionality; i++)
+ {
+ intervals[i] = new RasSInterval();
+ intervals[i].intersectionOf(mint1.item(i), mint2.item(i));
+ }
+ return this;
+ }
+ catch(RasIndexOutOfBoundsException e) {
+ // this cannot occur (theoretically)
+ throw new RasClientInternalException("RasMInterval","intersectionOf()",e.getMessage());
+ }
+
+ }
+
+ /**
+ * Calculates the intersection of the current MInterval and the given one.
+ * <P>Note that this operation modifies the current object. If you want to get a new MInterval,
+ * use {@link #createIntersection(RasMInterval) createIntersection} instead.</P>
+ * @param mint the MInterval used for building the intersection
+ * @return the current MInterval (representing the intersection of this MInterval and mint)
+ **/
+ public RasMInterval intersectionWith(RasMInterval mint)
+ throws RasDimensionMismatchException, RasResultIsNoIntervalException
+ {
+ if(dimensionality != mint.dimension())
+ throw new RasDimensionMismatchException(dimensionality, mint.dimension());
+
+ try {
+ for(int i=0; i<dimensionality; i++)
+ intervals[i].intersectionWith(mint.item(i));
+ return this;
+ }
+ catch(RasIndexOutOfBoundsException e) {
+ // this cannot occur (theoretically)
+ throw new RasClientInternalException("RasMInterval","intersectionWith()",e.getMessage());
+ }
+ }
+
+ /**
+ * @deprecated This methdod provides just another name for the
+ * intersectionWith method and might not be supported in future versions. Please
+ * use {@link #intersectionWith(RasMInterval) intersectionWith} instead.
+ * @param mint the MInterval used for building the intersection
+ * @return the intersection of this MInterval and mint
+ **/
+ public RasMInterval multWithSelf(RasMInterval mint)
+ throws RasDimensionMismatchException, RasResultIsNoIntervalException
+ {
+ return intersectionWith(mint);
+ }
+
+
+ /**
+ * Returns a new MInterval calculated from the intersection of the current MInterval
+ * and the given one.
+ * @param mint the MInterval used for calculating the intersection with the current MInterval
+ * @return the intersection of this MInterval and mint
+ **/
+ public RasMInterval createIntersection (RasMInterval mint)
+ throws RasDimensionMismatchException, RasResultIsNoIntervalException
+ {
+ if(dimensionality != mint.dimension())
+ throw new RasDimensionMismatchException( dimensionality, mint.dimension());
+
+ RasMInterval result = new RasMInterval(dimensionality);
+ try {
+ for(int i=0; i<dimensionality; i++)
+ result.stream(intervals[i].createIntersection(mint.item(i)));
+ return result;
+ }
+ catch(RasIndexOutOfBoundsException e) {
+ // this cannot occur (theoretically)
+ throw new RasClientInternalException("RasMInterval","createIntersection()",e.getMessage());
+ }
+ catch(RasStreamInputOverflowException e) {
+ // this cannot occur (theoretically)
+ throw new RasClientInternalException("RasMInterval","createIntersection()",e.getMessage());
+ }
+ }
+
+ /**
+ * @deprecated This methdod provides just another name for the
+ * createIntersection method and might not be supported in future versions. Please
+ * use {@link #createIntersection(RasMInterval) createIntersection} instead.
+ * @param mint the MInterval used for calculating the intersection with the current MInterval
+ * @return the intersection of this MInterval and mint
+ **/
+ public RasMInterval mult(final RasMInterval mint)
+ throws RasDimensionMismatchException, RasResultIsNoIntervalException
+ {
+ return createIntersection(mint);
+ }
+
+
+ // Methods/Operators for the closure operation:
+ /**
+ * Calculates the closure of two MIntervals.
+ * <P>Note that this operation modifies the current object. If you want to get a new MInterval,
+ * use {@link #createClosure(RasMInterval) createClosure} instead.</P>
+ * @param mint1 the first MInterval
+ * @param mint2 the second MInterval
+ * @return the current MInterval (representing the closure of mint1 and mint2)
+ **/
+ public RasMInterval closureOf(RasMInterval mint1, RasMInterval mint2)
+ throws RasDimensionMismatchException, RasResultIsNoIntervalException
+ {
+
+ if(mint1.dimension() != mint2.dimension())
+ throw new RasDimensionMismatchException( mint1.dimension(), mint2.dimension());
+
+ // cleanup + initializing of this
+
+ dimensionality = mint1.dimension();
+ streamInitCnt = dimensionality;
+ intervals = new RasSInterval[ dimensionality ];
+
+ try
+ {
+ for(int i=0; i<dimensionality; i++)
+ {
+ intervals[i] = new RasSInterval();
+ intervals[i].closureOf(mint1.item(i), mint2.item(i));
+ }
+ return this;
+ }
+ catch(RasIndexOutOfBoundsException e) {
+ // this cannot occur (theoretically)
+ throw new RasClientInternalException("RasMInterval","closureOf()",e.getMessage());
+ }
+ }
+
+ /**
+ * Calculates the closure of the current MInterval and the given one.
+ * <P>Note that this operation modifies the current object. If you want to get a new MInterval,
+ * use {@link #createClosure(RasMInterval) createClosure} instead.</P>
+ * @param mint the MInterval used for building the closure
+ * @return the current MInterval (representing the closure of this MInterval and mint)
+ **/
+ public RasMInterval closureWith(final RasMInterval mint)
+ throws RasDimensionMismatchException, RasResultIsNoIntervalException
+ {
+ if(dimensionality != mint.dimension())
+ throw new RasDimensionMismatchException( dimensionality, mint.dimension());
+
+ try
+ {
+ for(int i=0; i<dimensionality; i++)
+ intervals[i].closureWith(mint.item(i));
+ return this;
+ }
+ catch(RasIndexOutOfBoundsException e) {
+ // this cannot occur (theoretically)
+ throw new RasClientInternalException("RasMInterval","closureWith()",e.getMessage());
+ }
+ }
+
+ /**
+ * Returns a new MInterval calculated from the closure of the current MInterval
+ * and the given one.
+ * @param mint the MInterval used for calculating the closure with the current MInterval
+ * @return the closure of this MInterval and mint
+ **/
+ public RasMInterval createClosure(RasMInterval mint)
+ throws RasDimensionMismatchException, RasResultIsNoIntervalException
+ {
+ if(dimensionality != mint.dimension())
+ throw new RasDimensionMismatchException( dimensionality, mint.dimension());
+
+ RasMInterval result = new RasMInterval(dimensionality);
+
+ try
+ {
+ for(int i=0; i<dimensionality; i++)
+ result.stream(intervals[i].createClosure(mint.item(i)));
+ return result;
+ }
+ catch(RasIndexOutOfBoundsException e) {
+ // this cannot occur (theoretically)
+ throw new RasClientInternalException("RasMInterval","createClosure()",e.getMessage());
+ }
+ catch(RasStreamInputOverflowException e) {
+ // this cannot occur (theoretically)
+ throw new RasClientInternalException("RasMInterval","createClosure()",e.getMessage());
+ }
+
+ }
+
+ // Methods for internal use only:
+
+ /**
+ * Calculates the number of cells.
+ **/
+ long cellCount()
+ {
+ long cellCount=1;
+
+ for(int i=0; i<dimensionality; i++)
+ cellCount *= intervals[i].high() - intervals[i].low() + 1;
+
+ return cellCount;
+ }
+
+ /**
+ * Calculates the offset in cells for one dimensional (linear) access to
+ * the given point (dimension ordering is high first).
+ **/
+ long cellOffset( final RasPoint point)
+ throws RasIndexOutOfBoundsException
+ {
+ int i = 0;
+ long offset = 0;
+
+ // calculate offset
+ for(i = 0; i < dimensionality - 1; i++)
+ {
+ if(point.item(i) < intervals[i].low() || point.item(i) > intervals[i].high())
+ throw new RasIndexOutOfBoundsException(intervals[i].low(), intervals[i].high(), point.item(i) );
+
+ offset = (offset + point.item(i) - intervals[i].low()) * (intervals[i+1].high() - intervals[i+1].low() + 1);
+ }
+
+ // now i = dimensionality - 1
+ if(point.item(i) < intervals[i].low() || point.item(i) > intervals[i].high())
+ throw new RasIndexOutOfBoundsException(intervals[i].low(), intervals[i].high(), point.item(i) );
+
+ offset += point.item(i) - intervals[i].low();
+
+ return offset;
+ }
+
+ /**
+ * This method calculates the spatial domain
+ * coordinates as a point from the offset
+ * specified. Lower dimensions are higher
+ * valued which means that the highest dimension
+ * is stored in a sequence.
+ **/
+ RasPoint cellPoint(long offset) throws RasResultIsNoCellException
+ {
+ int i;
+ long factor=1;
+ RasPoint pt = new RasPoint(dimensionality);
+
+ try {
+
+ if(offset >= cellCount())
+ throw new RasResultIsNoCellException();
+
+ for(i=0; i<dimensionality; i++)
+ factor *= intervals[i].high() - intervals[i].low() + 1;
+
+ for(i=0; i<dimensionality; i++)
+ {
+ factor /= intervals[i].high() - intervals[i].low() + 1;
+ pt.stream(intervals[i].low() + (offset - (offset%factor))/factor);
+ offset %= factor;
+ }
+
+ return pt;
+ }
+ catch( RasStreamInputOverflowException e ) {
+ // this cannot occur (theoretically)
+ System.err.println("Error in method RasMInterval.cellPoint().");
+ return null;
+ }
+ }
+
+ // delete the specified dimension
+ void deleteDimension(int dim) throws RasException
+ {
+ if(dim < 0 || dim >= dimensionality)
+ throw new RasIndexOutOfBoundsException(0, dimensionality-1, dim);
+
+ dimensionality -= 1;
+ streamInitCnt = dimensionality;
+ RasSInterval[] newIntervals = new RasSInterval[ dimensionality ];
+
+ for(int i=0, j=0; i<dimensionality; i++, j++)
+ {
+ if(i==dim) j++;
+ newIntervals[i] = intervals[j];
+ }
+
+ intervals = newIntervals;
+ }
+
+ // calculate the size of the storage space occupied
+ long getStorageSize()
+ {
+ long sz = 26; //18 + 2 * 4
+
+ if (dimensionality > 0)
+ sz += dimensionality * 18;
+
+ return sz;
+ }
+
+ /** gives back the string representation */
+ public String toString()
+ {
+ String retString = "";
+ if(dimensionality > 0)
+ {
+ for(int i=0; i<dimensionality-1; i++)
+ {
+ retString = retString + intervals[i].toString() + ",";
+ }
+ retString = retString + intervals[dimensionality-1].toString();
+ }
+
+ return "[" + retString + "]";
+ }
+}
diff --git a/java/rasj/RasMIntervalType.java b/java/rasj/RasMIntervalType.java
new file mode 100644
index 0000000..ec31e17
--- /dev/null
+++ b/java/rasj/RasMIntervalType.java
@@ -0,0 +1,49 @@
+package rasj;
+
+import rasj.*;
+import java.util.*;
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * This class represents the MInterval type in the ODMG conformant
+ * representation of the RasDaMan type system.
+ * @version $Revision: 1.4 $
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+
+public class RasMIntervalType extends RasType
+{
+ static final String rcsid = "@(#)Package rasj, class RasMIntervalType: $Header: /home/rasdev/CVS-repository/rasdaman/java/rasj/RasMIntervalType.java,v 1.4 2003/12/10 21:04:23 rasdev Exp $";
+
+
+}
diff --git a/java/rasj/RasOIDType.java b/java/rasj/RasOIDType.java
new file mode 100644
index 0000000..feb4d92
--- /dev/null
+++ b/java/rasj/RasOIDType.java
@@ -0,0 +1,49 @@
+package rasj;
+
+import rasj.*;
+import java.util.*;
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * This class represents the OID type in the ODMG conformant
+ * representation of the RasDaMan type system.
+ * @version $Revision: 1.4 $
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+
+public class RasOIDType extends RasType
+{
+ static final String rcsid = "@(#)Package rasj, class RasOIDType: $Header: /home/rasdev/CVS-repository/rasdaman/java/rasj/RasOIDType.java,v 1.4 2003/12/10 21:04:23 rasdev Exp $";
+
+
+}
diff --git a/java/rasj/RasPoint.java b/java/rasj/RasPoint.java
new file mode 100644
index 0000000..b0f3793
--- /dev/null
+++ b/java/rasj/RasPoint.java
@@ -0,0 +1,426 @@
+package rasj;
+
+import java.lang.*;
+import java.util.*;
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * This class represents an n-dimensional point vector.
+ * @version $Revision: 1.9 $
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+
+public class RasPoint
+{
+ static final String rcsid = "@(#)Package rasj, class RasPoint: $Header: /home/rasdev/CVS-repository/rasdaman/java/rasj/RasPoint.java,v 1.9 2003/12/10 21:04:23 rasdev Exp $";
+
+ // array holding the point coordinates
+ private long[] points;
+ // dimensionality of the point
+ private int dimensionality;
+ // number of components initialized already
+ private int streamInitCnt;
+
+ /**
+ * Constructor getting the dimensionality for stream initialization.
+ * @param dim the dimensionality of this point
+ **/
+ public RasPoint(int dim)
+ {
+ dimensionality = dim;
+ streamInitCnt = 0;
+
+ points = new long[dimensionality];
+
+ for(int i=0; i< dimensionality; i++)
+ points[i] = 0;
+ }
+
+ /**
+ * Method for stream initialization of this point.
+ * @param newElement a new dimension that is added to this point
+ **/
+ public RasPoint stream(long newElement) throws RasStreamInputOverflowException
+ {
+ if(streamInitCnt >= dimensionality)
+ throw new RasStreamInputOverflowException();
+
+ points[streamInitCnt++] = newElement;
+ return this;
+ }
+
+ /**
+ * constructor taking a string representation for this point (for example "[1, 2, 3]").
+ * @param stringRep the string representation for this point
+ **/
+ public RasPoint(String stringRep)
+ {
+ dimensionality = 1;
+ streamInitCnt = 0;
+
+ if(stringRep.trim().charAt(0) != '[')
+ {
+ // error
+ dimensionality = 0;
+ return;
+ }
+
+ // for parsing the string
+ StringTokenizer strTok = new StringTokenizer(stringRep.trim(), "[,]");
+ String strCurTok = null;
+
+ // calculate dimensionality
+ dimensionality = strTok.countTokens();
+
+ points = new long[dimensionality];
+
+ for(int i=0; i<dimensionality; i++)
+ {
+ strCurTok = strTok.nextToken();
+ points[i] = Long.parseLong(strCurTok.trim());
+ }
+ }
+
+ /**
+ * Easy-to-use constructor for two dimensional points.
+ * @param p1 the value of the first dimension
+ * @param p2 the value of the second dimension
+ **/
+ public RasPoint(long p1, long p2)
+ {
+ dimensionality = 2;
+ streamInitCnt = 2;
+
+ points = new long[dimensionality];
+ points[0] = p1;
+ points[1] = p2;
+ }
+
+ /**
+ * Easy-to-use constructor for three dimensional points.
+ * @param p1 the value of the first dimension
+ * @param p2 the value of the second dimension
+ * @param p3 the value of the third dimension
+ **/
+ public RasPoint(long p1, long p2, long p3)
+ {
+ dimensionality =3;
+ streamInitCnt = 3;
+
+ points = new long[dimensionality];
+ points[0] = p1;
+ points[1] = p2;
+ points[2] = p3;
+ }
+
+ /**
+ * Easy-to-use constructor for four dimensional points.
+ * @param p1 the value of the first dimension
+ * @param p2 the value of the second dimension
+ * @param p3 the value of the third dimension
+ * @param p4 the value of the fourth dimension
+ **/
+ public RasPoint(long p1, long p2, long p3, long p4)
+ {
+ dimensionality = 4;
+ streamInitCnt = 4;
+
+ points = new long[dimensionality];
+ points[0] = p1;
+ points[1] = p2;
+ points[2] = p3;
+ points[3] = p4;
+ }
+
+ /**
+ * Easy-to-use constructor for five dimensional points.
+ * @param p1 the value of the first dimension
+ * @param p2 the value of the second dimension
+ * @param p3 the value of the third dimension
+ * @param p4 the value of the fourth dimension
+ * @param p5 the value of the fifth dimension
+ **/
+ public RasPoint(long p1, long p2, long p3, long p4, long p5)
+ {
+ dimensionality = 5;
+ streamInitCnt = 5;
+
+ points = new long[dimensionality];
+ points[0] = p1;
+ points[1] = p2;
+ points[2] = p3;
+ points[3] = p4;
+ points[4] = p5;
+ }
+
+ /**
+ * Default constructor.
+ **/
+ public RasPoint()
+ {
+ dimensionality = 0;
+ streamInitCnt = 0;
+
+ points = null;
+ }
+
+ /**
+ * Copy constructor that initializes this point with the values of the given one.
+ * @param pt the point used to copy the values from
+ **/
+ public RasPoint(final RasPoint pt)
+ {
+ dimensionality = pt.dimension();
+ streamInitCnt = dimensionality;
+ points = new long[ dimensionality ];
+
+ try {
+ for(int i=0; i<dimensionality; i++)
+ points[i] = pt.item(i);
+ }
+ catch(RasIndexOutOfBoundsException e) {
+ // this cannot occur (theoretically)
+ System.out.println("Error in RasPoint copy constructor.");
+ }
+ }
+
+ /**
+ * Read access to the i-th coordinate.
+ * @param i the dimension that is to be read
+ * @return the value of the i-th coordinate
+ **/
+ public long item(int i) throws RasIndexOutOfBoundsException
+ {
+ if(i < 0 || i >= dimensionality)
+ throw new RasIndexOutOfBoundsException(0, dimensionality-1, i);
+
+ return points[i];
+ }
+
+ /**
+ * write access to the i-th coordinate
+ * @param i the coordinate that is to be accessed
+ * @param value the value that is to be assigned to the specified coordinate
+ **/
+ public void setItem(int i, long value) throws RasIndexOutOfBoundsException
+ {
+ if(i < 0 || i >= dimensionality)
+ throw new RasIndexOutOfBoundsException(0, dimensionality-1, i);
+ points[i] = value;
+ }
+
+ /**
+ * This method copies the values of the given point to the current point. All
+ * previously defined values of the current point will be deleted.
+ * @param pt the point to be copied
+ * @return the current point with its new values
+ **/
+ public final RasPoint setTo(final RasPoint pt) throws RasIndexOutOfBoundsException
+ {
+ if(this != pt)
+ {
+ if((points != null) && dimensionality != pt.dimension())
+ {
+ points = null;
+ }
+
+ dimensionality = pt.dimension();
+ streamInitCnt = dimensionality;
+
+ if(points == null)
+ points = new long[ dimensionality ];
+
+ for(int i=0; i<dimensionality; i++)
+ points[i] = pt.item(i);
+
+ }
+
+ return this;
+ }
+
+ /**
+ * Compares this point to another point.
+ * @param p the point to be compared
+ * @return
+ * <TABLE BORDER=0 CELLPADDING=3>
+ * <TR><TD ALIGN=RIGHT VALIGN=TOP><B>-2</B></TD><TD> if the points have not the same dimensionality</TD></TR>
+ * <TR><TD ALIGN=RIGHT VALIGN=TOP><B>-1</B></TD><TD> if the current point is "lesser" than point p.
+ * <BR>In this context, "lesser" refers to the comparison of the coordinates in decreasing order
+ * of magnitude For example, the point (2,2,9) is "lesser" than the point (2,3,1).</TD></TR>
+ * <TR><TD ALIGN=RIGHT VALIGN=TOP><B>0</B></TD><TD> if the two points have an equal value</TD></TR>
+ * <TR><TD ALIGN=RIGHT VALIGN=TOP><B>1</B></TD><TD> if the current point is "greater" than point p
+ * ("greater" is the opposite of "lesser").</TD></TR>
+ * </TABLE>
+ **/
+ public final int comparedWith(final RasPoint p)
+ {
+ if(dimensionality != p.dimensionality)
+ return -2;
+
+ try {
+ for (int i = 0; i < dimensionality; i++)
+ {
+ if (points[i] > p.item(i))
+ return 1;
+ if (points[i] < p.item(i))
+ return -1 ;
+ }
+ return 0;
+ }
+ catch(RasIndexOutOfBoundsException e) {
+ // this cannot occur (theoretically)
+ System.out.println("Error in method RasPoint.comparedWith().");
+ return -2;
+ }
+ }
+
+ /**
+ * Method for testing equality of two points.<BR>Two points are equal
+ * if they have the same dimensionality and identic values in each dimension.
+ * @param pt the point that is compared to the current point
+ * @return true if the two points are equal
+ **/
+ public boolean equals(final RasPoint pt) throws RasDimensionMismatchException
+ {
+ boolean returnValue = false;
+
+ if(dimensionality != pt.dimensionality)
+ {
+ throw new RasDimensionMismatchException(dimensionality, pt.dimensionality);
+ }
+ try {
+ returnValue = true;
+ for(int i=0; i<dimensionality && returnValue ; i++)
+ returnValue &= (points[i] == pt.item(i));
+ return returnValue;
+ }
+ catch(RasIndexOutOfBoundsException e) {
+ // this cannot occur (theoretically)
+ return false;
+ }
+ }
+
+ /**
+ * Method for testing inequality. This is the negation of the equals method.
+ * @param pt the point that is compared to the current point
+ * @return true if the two points are not equal
+ **/
+ public boolean notEquals(final RasPoint pt) throws RasDimensionMismatchException
+ {
+ return !equals(pt);
+ }
+
+ /**
+ * Method for vector addition. The current point will be modified to contain
+ * the result of the addition.
+ * @param pt the point ot be added to the current point
+ * @return the current point after the addition
+ **/
+ public RasPoint add(final RasPoint pt) throws RasDimensionMismatchException
+ {
+ if(dimensionality != pt.dimension())
+ throw new RasDimensionMismatchException(dimensionality, pt.dimension());
+
+ try {
+ RasPoint result = new RasPoint(dimensionality);
+ for(int i=0; i<dimensionality; i++)
+ {
+ result.stream(points[i] + pt.item(i));
+ }
+ return result;
+ }
+ catch(RasException e) {
+ // this cannot occur (theoretically)
+ System.err.println("Error in method RasPoint.add().");
+ return null;
+ }
+ }
+
+
+ /**
+ * Method for vector multiplication. The current point will be modified to contain
+ * the result of the multiplication.
+ * @param pt the point ot be multiplied to the current point
+ * @return the current point after the multiplication
+ **/
+ public RasPoint mult(final RasPoint pt) throws RasDimensionMismatchException
+ {
+ if(dimensionality != pt.dimension())
+ throw new RasDimensionMismatchException(dimensionality, pt.dimension());
+
+ try {
+ RasPoint result= new RasPoint(dimensionality);
+ for(int i=0; i<dimensionality; i++)
+ {
+ result.stream(points[i] * pt.item(i));
+ }
+ return result;
+ }
+ catch(RasException e) {
+ // this cannot occur (theoretically)
+ System.err.println("Error in method RasPoint.mult().");
+ return null;
+ }
+ }
+
+
+ /**
+ * Gets the dimensionality of this point.
+ * @return the dimensionality of this point
+ **/
+ public int dimension()
+ {
+ return dimensionality;
+ }
+
+
+ /**
+ * Gives back the string representation of this point.
+ * @return the string representation of this point
+ **/
+ public String toString()
+ {
+ String retString = "";
+ if(dimensionality > 0)
+ {
+ for(int i=0; i<dimensionality-1; i++)
+ {
+ retString = retString + Long.toString(points[i]) + ",";
+ }
+ retString = retString + Long.toString(points[dimensionality-1]);
+ }
+
+ return "[" + retString + "]";
+ }
+
+}
diff --git a/java/rasj/RasPointType.java b/java/rasj/RasPointType.java
new file mode 100644
index 0000000..3f0f4b1
--- /dev/null
+++ b/java/rasj/RasPointType.java
@@ -0,0 +1,49 @@
+package rasj;
+
+import rasj.*;
+import java.util.*;
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * This class represents the Point type in the ODMG conformant
+ * representation of the RasDaMan type system.
+ * @version $Revision: 1.4 $
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+
+public class RasPointType extends RasType
+{
+ static final String rcsid = "@(#)Package rasj, class RasPointType: $Header: /home/rasdev/CVS-repository/rasdaman/java/rasj/RasPointType.java,v 1.4 2003/12/10 21:04:23 rasdev Exp $";
+
+
+}
diff --git a/java/rasj/RasPrimitiveType.java b/java/rasj/RasPrimitiveType.java
new file mode 100644
index 0000000..5d7543d
--- /dev/null
+++ b/java/rasj/RasPrimitiveType.java
@@ -0,0 +1,169 @@
+package rasj;
+
+import rasj.*;
+import rasj.global.*;
+
+import java.util.*;
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * This class represents the primitive types in the ODMG conformant
+ * representation of the RasDaMan type system.
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+public class RasPrimitiveType extends RasBaseType implements RasGlobalDefs
+{
+ static final String rcsid = "@(#)Package rasj, class RasPrimitiveType: $Header: /home/rasdev/CVS-repository/rasdaman/java/rasj/RasPrimitiveType.java,v 1.8 2003/12/10 21:04:23 rasdev Exp $";
+
+ private String rasTypeName = null;
+
+ public RasPrimitiveType()
+ {
+ super();
+ }
+
+ public RasPrimitiveType(String name, int type)
+ {
+ super(name, 0);
+ typeID = type;
+
+ switch(typeID)
+ {
+ case RAS_LONG: typeSize = SIZE_OF_RAS_LONG; rasTypeName = "RAS_LONG"; break;
+ case RAS_ULONG: typeSize = SIZE_OF_RAS_ULONG; rasTypeName = "RAS_ULONG"; break;
+ case RAS_SHORT: typeSize = SIZE_OF_RAS_SHORT; rasTypeName = "RAS_SHORT"; break;
+ case RAS_USHORT: typeSize = SIZE_OF_RAS_USHORT; rasTypeName = "RAS_USHORT"; break;
+ case RAS_BOOLEAN: typeSize = SIZE_OF_RAS_BOOLEAN; rasTypeName = "RAS_BOOLEAN"; break;
+ case RAS_BYTE: typeSize = SIZE_OF_RAS_BYTE; rasTypeName = "RAS_BYTE"; break;
+ case RAS_DOUBLE: typeSize = SIZE_OF_RAS_DOUBLE; rasTypeName = "RAS_DOUBLE"; break;
+ case RAS_FLOAT: typeSize = SIZE_OF_RAS_FLOAT; rasTypeName = "RAS_FLOAT"; break;
+ case RAS_CHAR: typeSize = SIZE_OF_RAS_CHAR; rasTypeName = "RAS_CHAR"; break;
+ }
+ }
+
+
+ public int getTypeID()
+ {
+ return typeID;
+ }
+
+ public String toString()
+ {
+ return super.toString();
+ }
+
+ public Boolean getBoolean(Object cell) throws RasTypeInvalidException
+ {
+ if(typeID != RAS_BOOLEAN)
+ {
+ throw new RasTypeInvalidException("RAS_BOOLEAN",rasTypeName);
+ }
+
+ return (Boolean)cell;
+ }
+
+
+ public Character getCharacter(Object cell) throws RasTypeInvalidException
+ {
+ if(typeID != RAS_CHAR)
+ {
+ throw new RasTypeInvalidException("RAS_CHAR",rasTypeName);
+ }
+
+ return (Character)cell;
+ }
+
+
+ public Byte getByte(Object cell) throws RasTypeInvalidException
+ {
+ if(typeID != RAS_BYTE)
+ {
+ throw new RasTypeInvalidException("RAS_BYTE",rasTypeName);
+ }
+
+ return (Byte)cell;
+ }
+
+
+ public Short getShort(Object cell) throws RasTypeInvalidException
+ {
+ if(typeID != RAS_SHORT)
+ {
+ throw new RasTypeInvalidException("RAS_SHORT",rasTypeName);
+ }
+
+ return (Short)cell;
+ }
+
+
+ public Integer getInteger(Object cell) throws RasTypeInvalidException
+ {
+ if((typeID != RAS_LONG) || (typeID != RAS_USHORT))
+ {
+ throw new RasTypeInvalidException("RAS_LONG",rasTypeName);
+ }
+
+ return (Integer)cell;
+ }
+
+ public Long getLong(Object cell) throws RasTypeInvalidException
+ {
+ if(typeID != RAS_ULONG)
+ {
+ throw new RasTypeInvalidException("RAS_ULONG",rasTypeName);
+ }
+
+ return (Long)cell;
+ }
+
+ public Float getFloat(Object cell) throws RasTypeInvalidException
+ {
+ if(typeID != RAS_FLOAT)
+ {
+ throw new RasTypeInvalidException("RAS_FLOAT",rasTypeName);
+ }
+
+ return (Float)cell;
+ }
+
+ public Double getDouble(Object cell) throws RasTypeInvalidException
+ {
+ if(typeID != RAS_DOUBLE)
+ {
+ throw new RasTypeInvalidException("RAS_DOUBLE",rasTypeName);
+ }
+
+ return (Double)cell;
+ }
+
+}
diff --git a/java/rasj/RasQueryExecutionFailedException.java b/java/rasj/RasQueryExecutionFailedException.java
new file mode 100644
index 0000000..697fe6c
--- /dev/null
+++ b/java/rasj/RasQueryExecutionFailedException.java
@@ -0,0 +1,172 @@
+package rasj;
+
+import java.util.*;
+import rasj.global.*;
+import org.odmg.*;
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * This exception extends the ODMGQueryInvalidException by offering direct access to the
+ * RasDaMan error number and the line, column and token in the querystring that produced the error.
+ * @version $Revision: 1.10 $
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+
+public class RasQueryExecutionFailedException extends QueryInvalidException
+{
+ static final String rcsid = "@(#)Package rasj, class RasQueryExecutionFailedException: $Header: /home/rasdev/CVS-repository/rasdaman/java/rasj/RasQueryExecutionFailedException.java,v 1.10 2003/12/19 16:22:27 rasdev Exp $";
+
+ /**
+ * the official RasDaMan error number
+ */
+ private int errNo;
+
+ /**
+ * line number of the error
+ */
+ private int line;
+
+ /**
+ * column of the error
+ */
+ private int column;
+
+ /**
+ * token that caused the error
+ */
+ private String token;
+
+ public RasQueryExecutionFailedException(String string)
+ {
+ if (string==null)
+ {
+ line = 0;
+ column = 0;
+ token = "(null)";
+ }
+ else
+ {
+ StringTokenizer tokenizer= new StringTokenizer( string, RasGlobalDefs.KEYWORD_TAB );
+ String Ttoken=tokenizer.nextToken();
+ Ttoken=tokenizer.nextToken();
+ errNo=Integer.parseInt(Ttoken);
+ if(tokenizer.hasMoreTokens())
+ {
+ line=Integer.parseInt(tokenizer.nextToken());
+ column=Integer.parseInt(tokenizer.nextToken());
+ token=tokenizer.nextToken();
+ }
+ else
+ {
+ line=0;
+ column=0;
+ token="";
+ }
+ }
+ }
+
+ /**
+ * Default Constructor setting the error specification
+ *@param errorNo official RasDaMan error number
+ *@param lineNo line in the query string that contained the error
+ *@param colNo column in the query string that contains the error
+ *@param tok token that caused the error
+ */
+ public RasQueryExecutionFailedException( int errorNo, int lineNo, int colNo, String tok )
+ {
+ super();
+ errNo = errorNo;
+ line = lineNo;
+ column = colNo;
+ token = ( (tok==null) ? "(null)" : tok );
+ }
+
+ public String getMessage()
+ {
+ int index;
+
+ if(super.getMessage() == null)
+
+ {
+ String msg = RasErrorTexts.getErrorMessage(errNo);
+
+ StringBuffer buf = new StringBuffer(msg);
+ index = msg.indexOf( RasGlobalDefs.KEYWORD_TOKEN );
+ if(index != -1)
+ buf.replace(index, index+RasGlobalDefs.KEYWORD_TOKEN.length(), token);
+
+ msg = buf.toString();
+ index = msg.indexOf( RasGlobalDefs.KEYWORD_ERRNO );
+ if(index != -1)
+ buf.replace(index, index+RasGlobalDefs.KEYWORD_ERRNO.length(), String.valueOf(errNo));
+
+ msg = buf.toString();
+ index = msg.indexOf( RasGlobalDefs.KEYWORD_LINENO );
+ if(index != -1)
+ buf.replace(index, index+RasGlobalDefs.KEYWORD_LINENO.length(), String.valueOf(line));
+
+ msg = buf.toString();
+ index = msg.indexOf( RasGlobalDefs.KEYWORD_COLNO );
+ if(index != -1)
+ buf.replace(index, index+RasGlobalDefs.KEYWORD_COLNO.length(), String.valueOf(column));
+
+ return buf.toString();
+ }
+ else
+ return super.getMessage();
+ }
+
+ /**
+ * returns the line number of the error
+ */
+ public int getLine()
+ {
+ return line;
+ }
+
+ /**
+ * return the column number of the error
+ */
+ public int getColumn()
+ {
+ return column;
+ }
+
+ /**
+ * returns the token that caused the error
+ */
+ public String getToken()
+ {
+ return token;
+ }
+
+ }
diff --git a/java/rasj/RasResultIsNoCellException.java b/java/rasj/RasResultIsNoCellException.java
new file mode 100644
index 0000000..f299137
--- /dev/null
+++ b/java/rasj/RasResultIsNoCellException.java
@@ -0,0 +1,69 @@
+package rasj;
+
+import rasj.global.*;
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * This exception is thrown if the result of an operation is no cell. This might happen
+ * if the cast operator for casting to the base type of class r_Marray is invoked
+ * on an object which is not 'zero-dimensional'.
+ * @version $Revision: 1.5 $
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+
+public class RasResultIsNoCellException extends RasException
+{
+ static final String rcsid = "@(#)Package rasj, class RasResultIsNoCellException: $Header: /home/rasdev/CVS-repository/rasdaman/java/rasj/RasResultIsNoCellException.java,v 1.5 2003/12/10 21:04:23 rasdev Exp $";
+
+ /**
+ * Standard constructor.
+ **/
+ protected RasResultIsNoCellException()
+ {
+ super(RasGlobalDefs.RESULT_IS_NO_CELL);
+ }
+
+ /**
+ * Returns the error message.
+ * @return the error message.
+ **/
+ public String getMessage()
+ {
+ if(super.getMessage() == null)
+ return RasErrorTexts.getErrorMessage(errNo);
+ else
+ return super.getMessage();
+ }
+
+}
+
diff --git a/java/rasj/RasResultIsNoIntervalException.java b/java/rasj/RasResultIsNoIntervalException.java
new file mode 100644
index 0000000..7dd6749
--- /dev/null
+++ b/java/rasj/RasResultIsNoIntervalException.java
@@ -0,0 +1,67 @@
+package rasj;
+
+import rasj.global.*;
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * This exception is thrown if the result of an operation is no interval.
+ * @version $Revision: 1.6 $
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+
+public class RasResultIsNoIntervalException extends RasException
+{
+ static final String rcsid = "@(#)Package rasj, class RasResultIsNoIntervalException: $Header: /home/rasdev/CVS-repository/rasdaman/java/rasj/RasResultIsNoIntervalException.java,v 1.6 2003/12/10 21:04:23 rasdev Exp $";
+
+ /**
+ * Standard constructor.
+ **/
+ protected RasResultIsNoIntervalException()
+ {
+ super(RasGlobalDefs.RESULT_IS_NO_INTERVAL);
+ }
+
+ /**
+ * Returns the error message.
+ * @return the error message.
+ **/
+ public String getMessage()
+ {
+ if(super.getMessage() == null)
+ return RasErrorTexts.getErrorMessage(errNo);
+ else
+ return super.getMessage();
+ }
+
+}
+
diff --git a/java/rasj/RasRuntimeException.java b/java/rasj/RasRuntimeException.java
new file mode 100644
index 0000000..afef833
--- /dev/null
+++ b/java/rasj/RasRuntimeException.java
@@ -0,0 +1,104 @@
+package rasj;
+
+import rasj.global.*;
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * This abstract class is the superclass of all runtime exceptions in the rasj package
+ * except for {@link rasj.RasConnectionFailedException RasConnectionFailedException}.
+ * @see rasj.RasException
+ * @version $Revision: 1.4 $
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+
+public abstract class RasRuntimeException extends RuntimeException
+{
+ static final String rcsid = "@(#)Package rasj, class RasRuntimeException: $Header: /home/rasdev/CVS-repository/rasdaman/java/rasj/RasRuntimeException.java,v 1.4 2003/12/19 16:22:27 rasdev Exp $";
+
+ protected int errNo = 0;
+ protected String errText = null;
+
+ /**
+ * Standard constructor.
+ **/
+ protected RasRuntimeException()
+ {
+ }
+
+ /**
+ * Constructor getting the error number.
+ * @param num the RasDaMan error number
+ **/
+ protected RasRuntimeException( int num )
+ {
+ errNo = num;
+ }
+
+ /**
+ * Constructor getting the error message.
+ * @param msg the error message
+ **/
+ protected RasRuntimeException( String msg )
+ {
+ errText = ( (msg==null) ? "(null)" : msg );
+ }
+
+ /**
+ * Constructor getting error number and error message.
+ * @param num the RasDaMan error number
+ * @param msg the error message
+ **/
+ protected RasRuntimeException( int num, String msg )
+ {
+ errNo = num;
+ errText = ( (msg==null) ? "(null)" : msg );
+ }
+
+ /**
+ * Method for retrieving the error number.
+ * @return the error number
+ **/
+ public int getErrNo()
+ {
+ return errNo;
+ }
+
+ /**
+ * Method retrieving the error message.
+ * @return the error message
+ **/
+ public String getMessage()
+ {
+ return errText;
+ }
+
+}
diff --git a/java/rasj/RasSInterval.java b/java/rasj/RasSInterval.java
new file mode 100644
index 0000000..9e6d4fe
--- /dev/null
+++ b/java/rasj/RasSInterval.java
@@ -0,0 +1,1343 @@
+package rasj;
+
+import java.lang.*;
+import java.util.*;
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * The class represents an interval with lower and upper bound.
+ * Operations on the interval are defined according to the
+ * ODMG-93 standard.
+ * The operations union, difference, and intersection are
+ * defined according to the following table:
+ *
+ * | ... fixed bound
+ * -* ... open bound
+ *
+ * class orientation union difference intersection
+ * -----------------------------------------------------------
+ * 1 |-a-| |-b-| error a error
+ *
+ * 2 |-a-| [a1,b2] [a1,b1] [b1,a2]
+ * 2 |-b-|
+ *
+ * 3 |--a--| a error b
+ * 3 |-b-|
+ *
+ * 4 |-b-| [b1,a2] [b2,a2] [a1,b2]
+ * 4 |-a-|
+ *
+ * 5 |--b--| b error a
+ * 5 |-a-|
+ *
+ * 6 |-b-| |-a-| error a error
+ *
+ * 7 |-a-|-b-| [a1,b2] a [a2,a2]
+ *
+ * 8 |-b-|-a-| [b1,a2] a [b2,b2]
+ *
+ * 9 |--a--| a [a1,b1] b
+ * 9 |-b-|
+ *
+ * 10 |--a--| a [b2,a2] b
+ * 10 |-b-|
+ *
+ * 11 |-a-| a error a
+ * 11 |-b-|
+ *
+ * 12 |--b--| b error a
+ * 12 |-a-|
+ *
+ * 13 |--b--| b error a
+ * 13 |-a-|
+ *
+ * -----------------------------------------------------
+ *
+ * 14 |--a--* a error b
+ * 14 |-b-|
+ *
+ * 15 |--a--* a [b2,a2] b
+ * 15 |-b-|
+ *
+ * 16 |-b-| |-a-* error a error
+ *
+ * 17 |-b-|-a-* [b1,a2] a [b2,b2]
+ *
+ * 18 |--a--* [b1,a2] [b2,a2] [a1,b2]
+ * 18 |-b-|
+ *
+ * -----------------------------------------------------
+ *
+ * 19 *--a--| a error b
+ * 19 |-b-|
+ *
+ * 20 *--a--| a [a1,b1] b
+ * 20 |-b-|
+ *
+ * 21 *-a-| |-b-| error a error
+ *
+ * 22 *-a-|-b-| [a1,b2] a [a2,a2]
+ *
+ * 23 *--a--| [a1,b2] [a1,b1] [b1,a2]
+ * 23 |-b-|
+ *
+ * -----------------------------------------------------
+ *
+ * 24 |--b--* b error a
+ * 24 |-a-|
+ *
+ * 25 |--b--* b error a
+ * 25 |-a-|
+ *
+ * 26 |-a-| |-b-* error a error
+ *
+ * 27 |-a-|-b-* [a1,b2] a [a2,a2]
+ *
+ * 28 |--b--* [a1,b2] [a1,b1] [b1,a2]
+ * 28 |-a-|
+ *
+ * -----------------------------------------------------
+ *
+ * 29 *--b--| b error a
+ * 29 |-a-|
+ *
+ * 30 *--b--| b error a
+ * 30 |-a-|
+ *
+ * 31 *-b-| |-a-| error a error
+ *
+ * 32 *-b-|-a-| [b1,a2] a [b2,b2]
+ *
+ * 33 *--b--| [b1,a2] [b2,a2] [a1,b2]
+ * 33 |-a-|
+ *
+ * -----------------------------------------------------
+ *
+ * 34 *-a-| |-b-* error a error
+ *
+ * 35 *-a-|-b-* [a1,b2] a [a2,a2]
+ *
+ * 36 *-a-| [a1,b2] [a1,b1] [b1,a2]
+ * 36 |-b-*
+ *
+ * -----------------------------------------------------
+ *
+ * 37 *-b-| |-a-* error a error
+ *
+ * 38 *-b-|-a-* [b1,a2] a [b2,b2]
+ *
+ * 39 *-b-| [b1,a2] [a1,b1] [a1,b2]
+ * 39 |-a-*
+ *
+ * -----------------------------------------------------
+ *
+ * 40 *-a-| b error a
+ * 40 *-b-|
+ *
+ * 41 *-a-| a error a
+ * 41 *-b-|
+ *
+ * 42 *-b-| a [b2,a2] b
+ * 42 *-a-|
+ *
+ * -----------------------------------------------------
+ *
+ * 43 |-a-* a [a1,b1] b
+ * 43 |-b-*
+ *
+ * 44 |-a-* a error a
+ * 44 |-b-*
+ *
+ * 45 |-b-* b error a
+ * 45 |-a-*
+ *
+ * -----------------------------------------------------
+ * 46 *-a-* |-b-| a error b
+ *
+ * 47 *-b-* |-a-| b error a
+ *
+ * 48 *-a-* a [b2,a2] b
+ * 48 *-b-|
+ *
+ * 49 *-a-* a [a1,b1] b
+ * 49 |-b-*
+ *
+ * 50 *-b-* b error a
+ * 50 *-a-|
+ *
+ * 51 *-b-* b error a
+ * 51 |-a-*
+ *
+ * 52 *-a-* a error a
+ * 52 *-b-*
+ *
+ * Attention: The difference operation has to be reconsidered in future
+ * concerning a discrete interpretation of the intervals.
+ *
+ * The closure operation defines an interval which is the smallest
+ * interval containing the two operands.
+ * The method intersectsWith() returns 0 in the error cases of the
+ * intersection operation and 1 otherwise.
+ *
+ * @version $Revision: 1.7 $
+ *
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+
+
+public class RasSInterval
+{
+ static final String rcsid = "@(#)Package rasj, class RasSInterval: $Header: /home/rasdev/CVS-repository/rasdaman/java/rasj/RasSInterval.java,v 1.7 2003/12/10 21:04:23 rasdev Exp $";
+
+ /**Attributes storing the bounds:*/
+ long lowerBound;
+ long upperBound;
+
+ /**Attributes specifying wheter the lower/upper bound is fixed or not:*/
+ boolean lowFixed;
+ boolean highFixed;
+
+ /**
+ * The default constructor creates an interval with open bounds.
+ **/
+ public RasSInterval()
+ {
+ lowerBound = 0;
+ upperBound = 0;
+ lowFixed = false;
+ highFixed = false;
+ }
+
+ /**
+ * Copy constructor.
+ * @param sint SInterval to be copied
+ **/
+ public RasSInterval(RasSInterval sint)
+ {
+ lowerBound = sint.lowerBound;
+ upperBound = sint.upperBound;
+ lowFixed = sint.lowFixed;
+ highFixed = sint.highFixed;
+ }
+
+ /**
+ * Constructor taking a string representation of the SInterval (for example "*:200").
+ * @param stringRep the string representation of the SInterval
+ **/
+ public RasSInterval(String stringRep) throws RasResultIsNoIntervalException
+ {
+ lowerBound = 0;
+ upperBound = 0;
+ lowFixed = false;
+ highFixed = false;
+
+
+ /**for parsing the string*/
+ StringTokenizer strTok = new StringTokenizer(stringRep.trim(), ":");
+ String strCurTok = strTok.nextToken();
+
+ if(strCurTok.equals("*"))
+ {
+ setLow('*');
+ }
+ else
+ {
+ setLow(Long.parseLong(strCurTok.trim()));
+ }
+
+
+ strCurTok = strTok.nextToken();
+
+ if(strCurTok.equals("*"))
+ {
+ setHigh('*');
+ }
+ else
+ {
+ setHigh(Long.parseLong(strCurTok.trim()));
+ }
+ }
+
+
+ /**
+ * Constructor for an SInterval with fixed bounds.
+ * @param low the lower bound
+ * @param high the upper bound
+ **/
+ public RasSInterval(long low, long high) throws RasResultIsNoIntervalException
+ {
+ lowerBound = low;
+ upperBound = high;
+ lowFixed = true;
+ highFixed = true;
+
+ if(low > high)
+ throw new RasResultIsNoIntervalException();
+ }
+
+
+ /**
+ * Constructor for an SInterval with an open lower bound.
+ * @param c arbitrary character, usually '*'. The value of this parameter is
+ * meaningless, it's only needed in order to provide a constructor similar to
+ * the one for fixed bounds.
+ * @param high the upper bound
+ **/
+ public RasSInterval(char c, long high)
+ {
+ lowerBound = 0;
+ upperBound = high;
+ lowFixed = false;
+ highFixed = true;
+ }
+
+ /**
+ * Constructor for an SInterval with an open upper bound.
+ * @param c arbitrary character, usually '*'. The value of this parameter is
+ * meaningless, it's only needed in order to provide a constructor similar to
+ * the one for fixed bounds.
+ * @param low the lower bound
+ **/
+ public RasSInterval(long low, char c)
+ {
+ lowerBound = low;
+ upperBound = 0;
+ lowFixed = true;
+ highFixed = false;
+ }
+
+ /**
+ * Constructor for an SInterval with an open bounds. For both parameters,
+ * arbitrary characters (usually '*') can be specified. The values of these parameters are
+ * meaningless, they are only needed in order to provide a constructor similar to
+ * the one for fixed bounds.
+ * @param c1 arbitrary character
+ * @param c2 arbitrary character
+ **/
+ public RasSInterval(char c1, char c2)
+ {
+ lowerBound = 0;
+ upperBound = 0;
+ lowFixed = false;
+ highFixed = false;
+ }
+
+ /**
+ * Method for testing equality of two SIntervals. Two SIntervals are equal
+ * if they have the same lower and upper bounds.
+ * @param interval the SInterval that is compared to this SInterval
+ * @return true if the two SIntervals are equal
+ **/
+ public boolean equals(final RasSInterval interval)
+ {
+ boolean returnValue = true;
+
+ if(lowFixed)
+ returnValue &= interval.lowFixed && lowerBound == interval.lowerBound;
+ else
+ returnValue &= !interval.lowFixed;
+
+ if(highFixed)
+ returnValue &= interval.highFixed && upperBound == interval.upperBound;
+ else
+ returnValue &= !interval.highFixed;
+
+ return returnValue;
+ }
+
+ /**
+ * Method for testing inequality of two SIntervals. Two SIntervals are inequal
+ * if they have different lower or upper bounds.
+ * @param interval the SInterval that is compared to this SInterval
+ * @return true if the two SIntervals are not equal
+ **/
+ public boolean notEquals(final RasSInterval interval)
+ {
+ return !equals(interval);
+ }
+
+
+ // Read/Write methods:
+ /**
+ * Gets the lower bound of the interval.
+ * @return the lower bound
+ **/
+ public long low()
+ {
+ return lowerBound;
+ }
+
+ /**
+ * Gets the upper bound of the interval.
+ * @return the upper bound
+ **/
+ public long high()
+ {
+ return upperBound;
+ }
+
+ /**
+ * Checks if the lower bound is fix.
+ * @return true if the lower bound is fix, false otherwise
+ **/
+ public boolean isLowFixed()
+ {
+ return lowFixed;
+ }
+
+ /**
+ * Checks if the upper bound is fix.
+ * @return true if the lower bound is fix, false otherwise
+ **/
+ public boolean isHighFixed()
+ {
+ return highFixed;
+ }
+
+ /**
+ * Sets the lower bound to a fixed value.
+ * @param low the new lower bound
+ **/
+ public void setLow(long low) throws RasResultIsNoIntervalException
+ {
+ if(highFixed && low > upperBound)
+ throw new RasResultIsNoIntervalException();
+
+ lowerBound = low;
+ lowFixed = true;
+ }
+
+ /**
+ * Sets the upper bound to a fixed value.
+ * @param high the new upper bound
+ **/
+ public void setHigh(long high) throws RasResultIsNoIntervalException
+ {
+ if(lowFixed && high < lowerBound)
+ throw new RasResultIsNoIntervalException();
+
+ upperBound = high;
+ highFixed = true;
+ }
+
+ /**
+ * Sets the lower bound open.
+ * @param c arbitrary character (usually '*')
+ **/
+ public void setLow(char c)
+ {
+ lowerBound = 0;
+ lowFixed = false;
+ }
+
+ /**
+ * Sets the upper bound open.
+ * @param c arbitrary character (usually '*')
+ **/
+ public void setHigh(char c)
+ {
+ upperBound = 0;
+ highFixed = false;
+ }
+
+ /**
+ * Sets both bounds to a fixed value.
+ * @param low the new lower bound
+ * @param high the new upper bound
+ **/
+ public void setInterval(long low, long high) throws RasResultIsNoIntervalException
+ {
+ if(low > high)
+ throw new RasResultIsNoIntervalException();
+
+ lowerBound = low;
+ upperBound = high;
+ lowFixed = true;
+ highFixed = true;
+ }
+
+ /**
+ * Sets the lower bound open and the upper bound to a fixed value.
+ * @param c arbitrary character (usually '*')
+ * @param high the new upper bound
+ **/
+ public void setInterval(char c, long high)
+ {
+ lowerBound = 0;
+ upperBound = high;
+ lowFixed = false;
+ highFixed = true;
+ }
+
+ /**
+ * Sets the upper bound open and the lower bound to a fixed value.
+ * @param c arbitrary character (usually '*')
+ * @param low the new lower bound
+ **/
+ public void setInterval(long low, char c)
+ {
+ lowerBound = low;
+ upperBound = 0;
+ lowFixed = true;
+ highFixed = false;
+ }
+
+ /**
+ * Sets both bounds open.
+ * @param c1 arbitrary character (usually '*')
+ * @param c2 arbitrary character (usually '*')
+ **/
+ public void setInterval(char c1, char c2)
+ {
+ lowerBound = 0;
+ upperBound = 0;
+ lowFixed = false;
+ highFixed = false;
+ }
+
+ /**
+ * Determines if the current interval intersects with the given one.
+ * @param interval the interval to be compared
+ * @return
+ * <TABLE BORDER=0 CELLPADDING=3>
+ * <TR><TD ALIGN=RIGHT><B>-1</B></TD><TD> if the intervals do not intersect</TD></TR>
+ * <TR><TD ALIGN=RIGHT VALIGN=TOP><B>&lt;classNo&gt;</B></TD><TD> if the intervals do intersect, where &lt;classNo&gt; is one of the classes specified in the description for class {@link RasSInterval RasSInterval}.</TD></TR>
+ * </TABLE>
+ **/
+ public int intersectsWith(RasSInterval interval)
+ {
+ int classnr = classify(this, interval);
+
+ if(classnr != 1 && classnr != 6 && classnr != 16 && classnr != 21 &&
+ classnr != 26 && classnr != 31 && classnr != 34 && classnr != 37)
+ {
+ return classnr;
+ }
+ else
+ {
+ return -1;
+ }
+ }
+
+ //Methods/Operators for the union operation:
+ /**
+ * Calculates the union of two SIntervals.
+ * <P>Note that this operation modifies the current object. If you want to get a new SInterval,
+ * use {@link #createUnion(RasSInterval) createUnion} instead.</P>
+ * @param interval1 the first SInterval
+ * @param interval2 the second SInterval
+ * @return the current SInterval (representing the union of interval1 and interval2)
+ **/
+ public RasSInterval unionOf(RasSInterval interval1, RasSInterval interval2)
+ throws RasResultIsNoIntervalException
+ {
+ copySInterval(calcUnion(interval1, interval2),this);
+ return this;
+ }
+
+ /**
+ * Calculates the union of the current SIntervall with another one.
+ * <P>Note that this operation modifies the current object. If you want to get a new SInterval,
+ * use {@link #createUnion(RasSInterval) createUnion} instead.</P>
+ * @param interval the SInterval to be used for the union
+ * @return the current SInterval (after the union with interval)
+ **/
+ public RasSInterval unionWith(RasSInterval interval)
+ throws RasResultIsNoIntervalException
+ {
+ copySInterval(calcUnion(this, interval),this);
+ return this;
+ }
+
+ /**
+ * @deprecated This methdod provides just another name for the
+ * unionWith method and might not be supported in future versions. Please
+ * use {@link #unionWith(RasSInterval) unionWith} instead.
+ * @param interval the SInterval to be unioned with this SInterval
+ * @return the union of this SInterval and interval
+ **/
+ public RasSInterval addToSelf(RasSInterval interval) throws RasResultIsNoIntervalException
+ {
+ RasSInterval retInterval = new RasSInterval();
+ retInterval = calcUnion(interval, this);
+ return retInterval;
+ }
+
+ /**
+ * Returns a new SInterval calculated from a union of the current SInterval
+ * and the given one.
+ * @param mint the SInterval to be unioned with this SInterval
+ * @return the union of this SInterval and interval
+ **/
+ public RasSInterval createUnion(RasSInterval interval) throws RasResultIsNoIntervalException
+ {
+ RasSInterval result = calcUnion(interval, this);
+ return result;
+ }
+
+ /**
+ * @deprecated This methdod provides just another name for the
+ * createUnion method and might not be supported in future versions. Please
+ * use {@link #createUnion(RasSInterval) createUnion} instead.
+ * @param interval the SInterval to be unioned with this SInterval
+ * @return the union of this SInterval and interval
+ **/
+ public RasSInterval add(RasSInterval interval) throws RasResultIsNoIntervalException
+ {
+ RasSInterval result;
+ result = calcUnion(interval, this);
+ return result;
+ }
+
+
+ // Methods/Operators for the difference operation:
+
+ /**
+ * Calculates the difference of two SIntervals.
+ * <P>Note that this operation modifies the current object. If you want to get a new SInterval,
+ * use {@link #createDifference(RasSInterval) createDifference} instead.</P>
+ * @param interval1 the first SInterval
+ * @param interval2 the second SInterval
+ * @return the current SInterval (representing the difference of interval1 and interval2)
+ **/
+ public RasSInterval differenceOf(RasSInterval interval1, RasSInterval interval2)
+ throws RasResultIsNoIntervalException
+ {
+ copySInterval(calcDifference(interval1, interval2),this);
+ return this;
+ }
+
+
+ /**
+ * Calculates the difference of the current SInterval and the given one.
+ * <P>Note that this operation modifies the current object. If you want to get a new SInterval,
+ * use {@link #createDifference(RasSInterval) createDifference} instead.</P>
+ * @param interval the SInterval used for building the difference
+ * @return the current SInterval (representing the difference of this SInterval and interval)
+ **/
+ public RasSInterval differenceWith(RasSInterval interval)
+ throws RasResultIsNoIntervalException
+ {
+ copySInterval(calcDifference(interval, this), this);
+ return this;
+ }
+
+ /**
+ * @deprecated This methdod provides just another name for the
+ * differenceWith method and might not be supported in future versions. Please
+ * use {@link #differenceWith(RasSInterval) differenceWith} instead.
+ * @param interval the SInterval used for building the difference
+ * @return the current SInterval (representing the difference of this SInterval and interval)
+ **/
+ public RasSInterval diffFromSelf(RasSInterval interval)
+ throws RasResultIsNoIntervalException
+ {
+ return differenceWith(interval);
+ }
+
+ /**
+ * Returns a new SInterval calculated from a difference of the current SInterval
+ * and the given one.
+ * @param interval the SInterval used for calculating the difference with the current SInterval
+ * @return the difference of this SInterval and interval
+ **/
+ public RasSInterval createDifference(RasSInterval interval)
+ throws RasResultIsNoIntervalException
+ {
+ RasSInterval result = calcDifference(interval, this);
+ return result;
+ }
+
+ /**
+ * @deprecated This methdod provides just another name for the
+ * createDifference method and might not be supported in future versions. Please
+ * use {@link #createDifference(RasSInterval) createDifference} instead.
+ * @param interval the SInterval used for calculating the difference with the current SInterval
+ * @return the difference of this SInterval and interval
+ **/
+ public RasSInterval diff(RasSInterval interval)
+ throws RasResultIsNoIntervalException
+ {
+ RasSInterval result = calcDifference(interval, this);
+ return result;
+ }
+
+
+ // Methods/Operators for the intersection operation:
+ /**
+ * This method calculates the intersection of two SIntervals.
+ * <P>Note that this operation modifies the current object. If you want to get a new SInterval,
+ * use {@link #createIntersection(RasSInterval) createIntersection} instead.</P>
+ * @param interval1 the first SInterval
+ * @param interval2 the second SInterval
+ * @return the current SInterval (representing the intersection of interval1 and interval2)
+ **/
+ public RasSInterval intersectionOf(final RasSInterval interval1, final RasSInterval interval2)
+ throws RasResultIsNoIntervalException
+ {
+ copySInterval(calcIntersection(interval1, interval2),this);
+ return this;
+ }
+
+ /**
+ * Calculates the intersection of the current SInterval and the given one.
+ * <P>Note that this operation modifies the current object. If you want to get a new SInterval,
+ * use {@link #createIntersection(RasSInterval) createIntersection} instead.</P>
+ * @param interval the SInterval used for building the intersection
+ * @return the current SInterval (representing the intersection of this SInterval and interval)
+ **/
+ public RasSInterval intersectionWith(final RasSInterval interval)
+ throws RasResultIsNoIntervalException
+ {
+ copySInterval(calcIntersection(interval, this),this);
+ return this;
+ }
+
+ /**
+ * @deprecated This methdod provides just another name for the
+ * intersectionWith method and might not be supported in future versions. Please
+ * use {@link #intersectionWith(RasSInterval) intersectionWith} instead.
+ * @param interval the SInterval used for building the intersection
+ * @return the intersection of this SInterval and interval
+ **/
+ public RasSInterval multWithSelf(final RasSInterval interval)
+ throws RasResultIsNoIntervalException
+ {
+ return intersectionWith(interval);
+ }
+
+ /**
+ * Returns a new SInterval calculated from the intersection of the current SInterval
+ * and the given one.
+ * @param interval the SInterval used for calculating the intersection with the current SInterval
+ * @return the intersection of this SInterval and interval
+ **/
+ public RasSInterval createIntersection(final RasSInterval interval)
+ throws RasResultIsNoIntervalException
+ {
+ RasSInterval result = calcIntersection(interval, this);
+ return result;
+ }
+
+ /**
+ * @deprecated This methdod provides just another name for the
+ * createIntersection method and might not be supported in future versions. Please
+ * use {@link #createIntersection(RasSInterval) createIntersection} instead.
+ * @param interval the SInterval used for calculating the intersection with the current SInterval
+ * @return the intersection of this SInterval and interval
+ **/
+ public RasSInterval mult(final RasSInterval interval)
+ throws RasResultIsNoIntervalException
+ {
+ return createIntersection(interval);
+ }
+
+
+ // Methods/Operators for the closure operation:
+ /**
+ * Calculates the closure of two SIntervals.
+ * <P>Note that this operation modifies the current object. If you want to get a new SInterval,
+ * use {@link #createClosure(RasSInterval) createClosure} instead.</P>
+ * @param interval1 the first SInterval
+ * @param interval2 the second SInterval
+ * @return the current SInterval (representing the closure of interval1 and interval2)
+ **/
+ public RasSInterval closureOf(final RasSInterval interval1, final RasSInterval interval2)
+ throws RasResultIsNoIntervalException
+ {
+ copySInterval(calcClosure(interval1, interval2),this);
+ return this;
+ }
+
+ /**
+ * Calculates the closure of the current SInterval and the given one.
+ * <P>Note that this operation modifies the current object. If you want to get a new SInterval,
+ * use {@link #createClosure(RasSInterval) createClosure} instead.</P>
+ * @param interval the SInterval used for building the closure
+ * @return the current SInterval (representing the closure of this SInterval and interval)
+ **/
+ public RasSInterval closureWith(final RasSInterval interval)
+ throws RasResultIsNoIntervalException
+ {
+ RasSInterval retInterval = new RasSInterval();
+ retInterval = calcClosure(interval, this);
+ return retInterval;
+ }
+
+ /**
+ * Returns a new SInterval calculated from the closure of the current SInterval
+ * and the given one.
+ * @param interval the SInterval used for calculating the closure with the current SInterval
+ * @return the closure of this SInterval and interval
+ **/
+ public RasSInterval createClosure(final RasSInterval interval)
+ throws RasResultIsNoIntervalException
+ {
+ RasSInterval result;
+ result = calcClosure(interval, this);
+ return result;
+ }
+
+
+ // Methods for internal use only:
+ // calculate the size of the storage space occupied
+ private long getStorageSize()
+ {
+ return (18); // 2 * (8 + 1)
+ }
+
+ // copy the values of source to target
+ private void copySInterval(RasSInterval source, RasSInterval target)
+ {
+ target.lowerBound = source.lowerBound;
+ target.upperBound = source.upperBound;
+ target.highFixed = source.highFixed;
+ target.lowFixed = source.lowFixed;
+ }
+
+ // Calculation methods for the operations:
+ private RasSInterval calcUnion(final RasSInterval a, final RasSInterval b)
+ throws RasResultIsNoIntervalException
+ {
+ RasSInterval result = new RasSInterval();
+
+ switch(classify(a, b))
+ {
+ case 2:
+ case 7:
+ case 9:
+ case 12:
+ case 22:
+ case 23:
+ case 27:
+ case 28:
+ case 35:
+ case 36:
+ // result = [a1:b2]
+
+ if(a.isLowFixed())
+ result.setLow(a.low());
+ else
+ result.setLow('*');
+
+ if(b.isHighFixed())
+ result.setHigh(b.high());
+ else
+ result.setHigh('*');
+
+ break;
+
+ case 4:
+ case 8:
+ case 10:
+ case 13:
+ case 17:
+ case 18:
+ case 32:
+ case 33:
+ case 38:
+ case 39:
+ // result = [b1:a2]
+
+ if(b.isLowFixed())
+ result.setLow(b.low());
+ else
+ result.setLow('*');
+
+ if(a.isHighFixed())
+ result.setHigh(a.high());
+ else
+ result.setHigh('*');
+
+ break;
+
+ case 3:
+ case 11:
+ case 14:
+ case 15:
+ case 19:
+ case 20:
+ case 41:
+ case 42:
+ case 43:
+ case 44:
+ case 46:
+ case 48:
+ case 49:
+ case 52:
+ result = a;
+ break;
+
+ case 5:
+ case 24:
+ case 25:
+ case 29:
+ case 30:
+ case 40:
+ case 45:
+ case 47:
+ case 50:
+ case 51:
+ result = b;
+ break;
+
+ default: // case in { 1, 6, 16, 21, 26, 31, 34, 37 }
+ throw new RasResultIsNoIntervalException();
+ }
+
+ return result;
+ }
+
+
+ //
+ private RasSInterval calcDifference(final RasSInterval a, final RasSInterval b)
+ throws RasResultIsNoIntervalException
+ {
+ RasSInterval result = new RasSInterval();
+
+ switch(classify(a, b))
+ {
+ case 2:
+ case 9:
+ case 20:
+ case 23:
+ case 28:
+ case 36:
+ case 39:
+ case 43:
+ case 49:
+ // result = [a1:b1]
+
+ if(a.isLowFixed())
+ result.setLow(a.low());
+ else
+ result.setLow('*');
+
+ if(b.isLowFixed())
+ result.setHigh(b.low());
+ else
+ result.setHigh('*');
+
+ break;
+
+ case 1:
+ case 6:
+ case 7:
+ case 8:
+ case 16:
+ case 17:
+ case 21:
+ case 22:
+ case 26:
+ case 27:
+ case 31:
+ case 32:
+ case 34:
+ case 35:
+ case 37:
+ case 38:
+ result = a;
+ break;
+
+ case 4:
+ case 10:
+ case 15:
+ case 18:
+ case 33:
+ case 42:
+ case 48:
+ // result = [b2:a2]
+
+ if(b.isHighFixed())
+ result.setLow(b.high());
+ else
+ result.setLow('*');
+
+ if(a.isHighFixed())
+ result.setHigh(a.high());
+ else
+ result.setHigh('*');
+
+ break;
+
+ default: // case in { 3, 5, 11, 12, 13, 14, 19, 24, 25, 29, 30, 40, 41, 44, 45, 46, 47, 50, 51, 52 }
+ throw new RasResultIsNoIntervalException();
+ }
+
+ return result;
+ }
+
+
+ //
+ private RasSInterval calcIntersection(final RasSInterval a, final RasSInterval b)
+ throws RasResultIsNoIntervalException
+ {
+ RasSInterval result = new RasSInterval();
+
+ switch(classify(a, b))
+ {
+ case 4:
+ case 18:
+ case 33:
+ case 39:
+ // result = [a1:b2]
+
+ if(a.isLowFixed())
+ result.setLow(a.low());
+ else
+ result.setLow('*');
+
+ if(b.isHighFixed())
+ result.setHigh(b.high());
+ else
+ result.setHigh('*');
+
+ break;
+
+ case 2:
+ case 23:
+ case 28:
+ case 36:
+ // result = [b1:a2]
+
+ if(b.isLowFixed())
+ result.setLow(b.low());
+ else
+ result.setLow('*');
+
+ if(a.isHighFixed())
+ result.setHigh(a.high());
+ else
+ result.setHigh('*');
+
+ break;
+
+ case 5:
+ case 11:
+ case 12:
+ case 13:
+ case 24:
+ case 25:
+ case 29:
+ case 30:
+ case 40:
+ case 41:
+ case 44:
+ case 45:
+ case 47:
+ case 50:
+ case 51:
+ case 52:
+ result = a;
+ break;
+
+ case 3:
+ case 9:
+ case 10:
+ case 14:
+ case 15:
+ case 19:
+ case 20:
+ case 42:
+ case 43:
+ case 46:
+ case 48:
+ case 49:
+ result = b;
+ break;
+
+ case 7:
+ case 22:
+ case 27:
+ case 35:
+ // result = [a2:a2]
+
+ if(a.isHighFixed())
+ result.setInterval(a.high(), a.high());
+ else
+ result.setInterval('*', '*');
+
+ break;
+
+ case 8:
+ case 17:
+ case 32:
+ case 38:
+ // result = [b2:b2]
+
+ if(b.isHighFixed())
+ result.setInterval(b.high(), b.high());
+ else
+ result.setInterval('*', '*');
+
+ break;
+
+ default: // case in { 1, 6, 16, 21, 26, 31, 34, 37 }
+ throw new RasResultIsNoIntervalException();
+ }
+
+ return result;
+ }
+
+
+
+ private RasSInterval calcClosure(final RasSInterval a, final RasSInterval b)
+ throws RasResultIsNoIntervalException
+ {
+ RasSInterval closure = new RasSInterval();
+
+ if(!a.isLowFixed() || !b.isLowFixed())
+ closure.setLow('*');
+ else
+ closure.setLow(Math.min(a.low(), b.low()));
+
+ if(!a.isHighFixed() || !b.isHighFixed())
+ closure.setHigh('*');
+ else
+ closure.setHigh(Math.max(a.high(), b.high()));
+
+ return closure;
+ }
+
+
+ // compute the class of the two operands
+
+
+ /*************************************************************
+ * Method name...: classify
+ *
+ * Arguments.....: Two intervals for the classification.
+ * Return value..: The classification class number (1..52).
+ * Description...: The method classifies the two intervals into
+ * one of 13 classes according to their spatial
+ * relationship. Based on the classification, the
+ * result of the operations union, difference,
+ * and intersection can be calculated as shown
+ * in the table
+ ************************************************************/
+
+
+ private int classify(final RasSInterval a, final RasSInterval b)
+ {
+ int classification = 0;
+
+ if(a.isLowFixed() && a.isHighFixed() && b.isLowFixed() && b.isHighFixed())
+ {
+ // classification 1..13
+
+ if(a.low() < b.low())
+ {
+ if(a.high() < b.high())
+ {
+ if(a.high() < b.low())
+ classification = 1;
+ else
+ if(a.high() == b.low())
+ classification = 7;
+ else
+ classification = 2;
+ }
+ else if(a.high() == b.high())
+ classification = 9;
+ else
+ classification = 3;
+ }
+ else if(a.low() == b.low())
+ {
+ if(a.high() < b.high())
+ classification = 12;
+ else if(a.high() == b.high())
+ classification = 11;
+ else
+ classification = 10;
+ }
+ else
+ if(a.high() < b.high())
+ classification = 5;
+ else if(a.high() == b.high())
+ classification = 13;
+ else
+ {
+ if(a.low() < b.high())
+ classification = 4;
+ else if(a.low() == b.high())
+ classification = 8;
+ else
+ classification = 6;
+ }
+ }
+ else if(a.isLowFixed() && !a.isHighFixed() && b.isLowFixed() && b.isHighFixed())
+ {
+ // classification 14..18
+
+ if(a.low() < b.low())
+ classification = 14;
+ else if(a.low() == b.low())
+ classification = 15;
+ else
+ {
+ if(b.high() < a.low())
+ classification = 16;
+ else if(b.high() == a.low())
+ classification = 17;
+ else
+ classification = 18;
+ }
+ }
+ else if(!a.isLowFixed() && a.isHighFixed() && b.isLowFixed() && b.isHighFixed())
+ {
+ // classification 19..23
+
+ if(a.high() > b.high())
+ classification = 19;
+ else if(a.high() == b.high())
+ classification = 20;
+ else
+ {
+ if(a.high() < b.low())
+ classification = 21;
+ else if(a.high() == b.low())
+ classification = 22;
+ else
+ classification = 23;
+ }
+ }
+ else if(a.isLowFixed() && a.isHighFixed() && b.isLowFixed() && !b.isHighFixed())
+ {
+ // classification 24..28
+
+ if(b.low() < a.low())
+ classification = 24;
+ else if(b.low() == a.low())
+ classification = 25;
+ else
+ {
+ if(a.high() < b.low())
+ classification = 26;
+ else if(a.high() == b.low())
+ classification = 27;
+ else
+ classification = 28;
+ }
+ }
+ else if(a.isLowFixed() && a.isHighFixed() && !b.isLowFixed() && b.isHighFixed())
+ {
+ // classification 29..33
+
+ if(b.high() > a.high())
+ classification = 29;
+ else if(b.high() == a.high())
+ classification = 30;
+ else
+ {
+ if(b.high() < a.low())
+ classification = 31;
+ else if(b.high() == a.low())
+ classification = 32;
+ else
+ classification = 33;
+ }
+ }
+ else if(!a.isLowFixed() && a.isHighFixed() && b.isLowFixed() && !b.isHighFixed())
+ {
+ // classification 34..36
+
+ if(a.high() < b.low())
+ classification = 34;
+ else if(a.high() == b.low())
+ classification = 35;
+ else
+ classification = 36;
+ }
+ else if(a.isLowFixed() && !a.isHighFixed() && !b.isLowFixed() && b.isHighFixed())
+ {
+ // classification 37..39
+
+ if(b.high() < a.low())
+ classification = 37;
+ else if(b.high() == a.low())
+ classification = 38;
+ else
+ classification = 39;
+ }
+ else if(!a.isLowFixed() && a.isHighFixed() && !b.isLowFixed() && b.isHighFixed())
+ {
+ // classification 40..42
+
+ if(a.high() < b.high())
+ classification = 40;
+ else if(a.high() == b.high())
+ classification = 41;
+ else
+ classification = 42;
+ }
+ else if(a.isLowFixed() && !a.isHighFixed() && b.isLowFixed() && !b.isHighFixed())
+ {
+ // classification 43..45
+
+ if(a.low() < b.low())
+ classification = 43;
+ else if(a.low() == b.low())
+ classification = 44;
+ else
+ classification = 45;
+ }
+ else if(!a.isLowFixed() && !a.isHighFixed() && b.isLowFixed() && b.isHighFixed())
+ classification = 46;
+ else if( a.isLowFixed() && a.isHighFixed() && !b.isLowFixed() && !b.isHighFixed())
+ classification = 47;
+ else if(!a.isLowFixed() && !a.isHighFixed() && !b.isLowFixed() && b.isHighFixed())
+ classification = 48;
+ else if(!a.isLowFixed() && !a.isHighFixed() && b.isLowFixed() && !b.isHighFixed())
+ classification = 49;
+ else if(!a.isLowFixed() && a.isHighFixed() && !b.isLowFixed() && !b.isHighFixed())
+ classification = 50;
+ else if( a.isLowFixed() && !a.isHighFixed() && !b.isLowFixed() && !b.isHighFixed())
+ classification = 51;
+ else // !a.isLowFixed() && !a.isHighFixed() && !b.isLowFixed() && !b.isHighFixed()
+ classification = 52;
+
+ return classification;
+ }
+
+
+ /** gives back the string representation */
+ public String toString()
+ {
+ return (lowFixed ? Long.toString(lowerBound) : "*")
+ + ":"
+ + (highFixed ? Long.toString(upperBound) : "*");
+ }
+
+}
+
diff --git a/java/rasj/RasSIntervalType.java b/java/rasj/RasSIntervalType.java
new file mode 100644
index 0000000..519e28c
--- /dev/null
+++ b/java/rasj/RasSIntervalType.java
@@ -0,0 +1,49 @@
+package rasj;
+
+import rasj.*;
+import java.util.*;
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * This class represents the SInterval type in the ODMG conformant
+ * representation of the RasDaMan type system.
+ * @version $Revision: 1.4 $
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+
+public class RasSIntervalType extends RasType
+{
+ static final String rcsid = "@(#)Package rasj, class RasSIntervalType: $Header: /home/rasdev/CVS-repository/rasdaman/java/rasj/RasSIntervalType.java,v 1.4 2003/12/10 21:04:23 rasdev Exp $";
+
+
+}
diff --git a/java/rasj/RasStorageLayout.java b/java/rasj/RasStorageLayout.java
new file mode 100644
index 0000000..ab1feae
--- /dev/null
+++ b/java/rasj/RasStorageLayout.java
@@ -0,0 +1,154 @@
+package rasj;
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * This class is used to express the storage options for MDD objects.
+ * In the current version, either the tile-size (for example 256000 bytes) or the
+ * tiling-domain (for example "[0:127,0:511]") can be specified. If
+ * neither is done, the default tile-size will be 128 kBytes.
+ *
+ * @version $Revision: 1.10 $
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+
+public class RasStorageLayout
+
+{
+ static final String rcsid = "@(#)Package rasj.odmg, class RasStorageLayout: $Header: /home/rasdev/CVS-repository/rasdaman/java/rasj/RasStorageLayout.java,v 1.10 2003/12/10 21:04:23 rasdev Exp $";
+
+ /**
+ * Default tile size in kBytes. This value is currently set
+ * to 128000 and is used if the user has not specified
+ * a tile size explicitly.
+ **/
+ static final int DEFAULT_TILE_SIZE = 128000;
+
+ /**
+ * the spatial domain of the current storageLayout
+ **/
+ private RasMInterval spatialDomain;
+
+ /**
+ * the current tile size in bytes
+ **/
+ private int tileSize;
+
+ /**
+ * Default constructor.
+ **/
+ public RasStorageLayout()
+ {
+ spatialDomain = null;
+ tileSize = DEFAULT_TILE_SIZE;
+ }
+
+ /**
+ * Copy constructor taking another storage layout object as a parameter.
+ * @param stl the sorage layout object to be copied
+ **/
+ public RasStorageLayout(RasStorageLayout stl)
+ {
+ spatialDomain = stl.getSpatialDomain();
+ tileSize = stl.getTileSize();
+ }
+
+ /**
+ * Returns the current tiling-domain of this storage layout object.
+ * @return the tiling-domain of this storage layout object
+ **/
+ public final RasMInterval getSpatialDomain()
+ {
+ return spatialDomain;
+ }
+
+ /**
+ * Sets the tile-size (in bytes) and resets the tiling-domain to null.
+ * @param size the tile-size (in bytes)
+ **/
+ public void setTileSize(int size)
+ {
+ tileSize = size;
+ spatialDomain = null;
+ }
+
+ /**
+ * Returns the current tile-size (in bytes).
+ * @return the tile-size
+ **/
+ public final int getTileSize()
+ {
+ return tileSize;
+ }
+
+ /**
+ * Sets the tiling-domain for this storage layout object and resets the tile-size
+ * to null.
+ * @param domain the tiling-domain
+ **/
+ public void setTileDomain(String domain)
+ throws RasResultIsNoIntervalException, RasStreamInputOverflowException, RasIndexOutOfBoundsException
+ {
+ spatialDomain = new RasMInterval(domain);
+ tileSize = 0;
+ }
+
+ /**
+ * This method tests if the current storageLayout object is compatible to a given domain.
+ * @param domain the domain to be compared
+ * @return true if the tiling-domain of this storage layout object is either null or
+ * has the same number of dimensions as the given domain, otherwise false
+ **/
+ public boolean isCompatible(RasMInterval domain)
+ {
+ if(spatialDomain == null)
+ return true;
+ else
+ return (domain.dimension() == spatialDomain.dimension());
+
+ }
+
+ /**
+ * Returns a string representation of this class.
+ **/
+ public String toString()
+ {
+ if(spatialDomain != null)
+ return "\nTileDomain: " + spatialDomain + "\n";
+ else
+ return "\nTileSize: " + tileSize + "\n";
+
+ }
+
+
+}
+
diff --git a/java/rasj/RasStreamInputOverflowException.java b/java/rasj/RasStreamInputOverflowException.java
new file mode 100644
index 0000000..60b7ca1
--- /dev/null
+++ b/java/rasj/RasStreamInputOverflowException.java
@@ -0,0 +1,69 @@
+package rasj;
+
+import rasj.global.*;
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * This exception is thrown if an initialization overflow has occured.
+ * It typically arises when a stream input operator is invoked more
+ * often than the object has dimensions.
+ * @version $Revision: 1.5 $
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+
+public class RasStreamInputOverflowException extends RasException
+{
+ static final String rcsid = "@(#)Package rasj, class RasStreamInputOverflowException: $Header: /home/rasdev/CVS-repository/rasdaman/java/rasj/RasStreamInputOverflowException.java,v 1.5 2003/12/10 21:04:23 rasdev Exp $";
+
+ /**
+ * Standard constructor.
+ */
+ protected RasStreamInputOverflowException()
+ {
+ super(RasGlobalDefs.STREAM_INPUT_OVERFLOW);
+ }
+
+ /**
+ * Returns the error message.
+ * @return the error message.
+ **/
+ public String getMessage()
+ {
+ if(super.getMessage() == null)
+ return RasErrorTexts.getErrorMessage(errNo);
+ else
+ return super.getMessage();
+ }
+
+}
+
diff --git a/java/rasj/RasStructureType.java b/java/rasj/RasStructureType.java
new file mode 100644
index 0000000..e996c4a
--- /dev/null
+++ b/java/rasj/RasStructureType.java
@@ -0,0 +1,100 @@
+package rasj;
+
+import rasj.*;
+import rasj.global.*;
+
+import java.util.*;
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * This class represents all user defined structured types in the ODMG conformant
+ * representation of the RasDaMan type system.
+ * @version $Revision: 1.8 $
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+public class RasStructureType extends RasBaseType
+{
+ static final String rcsid = "@(#)Package rasj, class RasStructureType: $Header: /home/rasdev/CVS-repository/rasdaman/java/rasj/RasStructureType.java,v 1.8 2003/12/10 21:04:23 rasdev Exp $";
+
+ private RasBaseType[] baseTypes;
+ private String[] attributes;
+
+ public RasStructureType()
+ {
+ super();
+ baseTypes = null;
+ attributes = null;
+ }
+
+ public RasStructureType(String name, RasBaseType[] btyp, String[] attr)
+ {
+ super(name, 0);
+ baseTypes = btyp;
+ attributes = attr;
+
+ for(int i=0; i < baseTypes.length/2; i++)
+ {
+ typeSize = typeSize + baseTypes[i].getSize();
+ //System.out.println(typeSize);
+ }
+ typeID = RasGlobalDefs.RAS_STRUCTURE;
+ }
+
+ public int getTypeID()
+ {
+ return RasGlobalDefs.RAS_STRUCTURE;
+ }
+
+
+ public boolean isStructType()
+ {
+ return true;
+ }
+
+ public String toString()
+ {
+ //System.out.println("struct type: ");
+ String s = super.toString() + "struct " + super.typeName + "\n{\n";
+ for(int i=0; i < (attributes.length/2)-1; i++)
+ {
+ s = s + " " + baseTypes[i] + " " + attributes[i] + ", \n";
+
+ if(i == (attributes.length/2)-2)
+ {
+ s = s + baseTypes[i+1] + " " + attributes[i+1] + "\n}\n";
+ }
+
+ }
+ return s;
+ }
+}
diff --git a/java/rasj/RasType.java b/java/rasj/RasType.java
new file mode 100644
index 0000000..1e3afda
--- /dev/null
+++ b/java/rasj/RasType.java
@@ -0,0 +1,365 @@
+package rasj;
+
+import rasj.*;
+import rasj.global.*;
+import java.util.*;
+
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * This class the superclass for all types in the ODMG conformant
+ * representation of the RasDaMan type system.
+ * @version $Revision: 1.10 $
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+
+public class RasType
+{
+ static final String rcsid = "@(#)Package rasj, class RasType: $Header: /home/rasdev/CVS-repository/rasdaman/java/rasj/RasType.java,v 1.10 2003/12/10 21:04:23 rasdev Exp $";
+
+ protected String typeName;
+ protected int typeID;
+
+ /**
+ * Default constructor.
+ **/
+ public RasType()
+ {
+ typeName = "";
+ typeID = 0;
+ }
+
+ /**
+ * Constructor getting the name of the new type.
+ * @param newTypeName the name of the new type
+ **/
+ public RasType(String newTypeName)
+ {
+ typeName = newTypeName;
+ typeID = 0;
+ }
+
+ /**
+ * Retrieves the id of this type.
+ * @return the type id
+ **/
+ public int getTypeID()
+ {
+ return typeID;
+ }
+
+ /**
+ * Retrieves the name of this type.
+ * @return the type name
+ **/
+ public String getName()
+ {
+ return typeName;
+ }
+
+ /**
+ * Checks if this type is a primitive or structured type.
+ * @return true if this is a structured type, otherwise false
+ **/
+ public boolean isStructType()
+ {
+ return false;
+ }
+
+ /**
+ * Checks if this type is a base type (primitive type or structure type).
+ * @return true for a primitive or structured type, otherwise false
+ **/
+ public boolean isBaseType()
+ {
+ return false;
+ }
+
+
+ /**
+ * Builds the type schema from a string representation.
+ * @param typeString the string representation of the type
+ **/
+ public static RasType getAnyType(String typeString)
+ {
+ StringTokenizer strTok = new StringTokenizer(typeString, "{}[]<>,: ");
+ String currentStr = "";
+ RasType returnValue = null;
+ if(strTok.hasMoreTokens())
+ {
+ currentStr = strTok.nextToken();
+ if(currentStr.equals("set"))
+ {
+ //System.out.println("getSet");
+ returnValue = getSet(strTok.nextToken(""));
+ }
+ else if(currentStr.equals("marray"))
+ {
+ //System.out.println("getMArray");
+ returnValue = getMArrayType(strTok.nextToken(""));
+ }
+ else
+ {
+ //System.out.println("getType");
+ returnValue = getType(typeString);
+ }
+ }
+ return returnValue;
+ }
+
+ // converts array of cells from NT byte order to Unix byte order.
+ //public void convertToLittleEndian(String cells, int noCells)
+ //{
+ //}
+
+ // converts array of cells from Unix byte order to NT byte order.
+ //public void convertToBigEndian(String cells, int noCells)
+ //{
+ //}
+
+ private static RasType getSet(String setStr)
+ {
+ StringTokenizer setTok = new StringTokenizer(setStr, "{}[]<>,: ");
+ String currentStr = "";
+ RasType returnValue = null;
+ RasType elementType = null;
+ if(setTok.hasMoreTokens())
+ {
+ currentStr = setTok.nextToken();
+ //Fehler falls kein <!
+ if(currentStr.equals("marray"))
+ elementType = getMArrayType(setTok.nextToken(""));
+ else elementType = getType(setStr);
+ }
+
+ returnValue = new RasCollectionType(elementType);
+
+ return returnValue;
+ }
+
+ private static RasType getType(String typeStr)
+ {
+ StringTokenizer typeTok = new StringTokenizer(typeStr, "{}[]<>,: ");
+ String currentStr = "";
+ RasType returnValue = null;
+ if(typeTok.hasMoreTokens())
+ {
+ currentStr = typeTok.nextToken();
+ if(currentStr.equals("struct"))
+ {
+ //System.out.println("getStructureType");
+ returnValue = getStructureType(typeTok.nextToken(""));
+ }
+ else if(currentStr.equals("interval"))
+ {
+ returnValue = getSIntervalType(typeTok.nextToken(""));
+ returnValue.typeID = RasGlobalDefs.RAS_SINTERVAL;
+ }
+ else if(currentStr.equals("minterval"))
+ {
+ returnValue = getMIntervalType(typeTok.nextToken(""));
+ returnValue.typeID = RasGlobalDefs.RAS_MINTERVAL;
+ }
+ else if(currentStr.equals("point"))
+ {
+ returnValue = getPointType(typeTok.nextToken(""));
+ returnValue.typeID = RasGlobalDefs.RAS_POINT;
+ }
+ else if(currentStr.equals("oid"))
+ {
+ returnValue = getOIDType(typeTok.nextToken(""));
+ returnValue.typeID = RasGlobalDefs.RAS_OID;
+ }
+ else
+ {
+ //System.out.println("getPrimitiveType");
+ returnValue = getPrimitiveType(typeStr);
+ }
+ }
+ return returnValue;
+ }
+
+ private static RasMArrayType getMArrayType(String mArrayStr)
+ {
+ //StringTokenizer mArrayTok = new StringTokenizer(mArrayStr, "{}[]<>,: ");
+ //System.out.println("enter getMArrayType" + mArrayStr);
+ RasMArrayType returnValue = null;
+ RasBaseType baseType = null;
+ //Fehler falls kein <!
+ // get base type (structure or primitive type)
+ baseType = getBaseType(mArrayStr);
+ //System.out.println("base type: " + baseType);
+ returnValue = new RasMArrayType(baseType);
+
+ return returnValue;
+ }
+
+
+ private static RasBaseType getBaseType(String baseStr)
+ {
+ StringTokenizer baseTok = new StringTokenizer(baseStr, "{}[]<>,: ");
+ String currentStr = "";
+ //System.out.println(baseStr);
+ RasBaseType returnValue = null;
+ if(baseTok.hasMoreTokens())
+ {
+ currentStr = baseTok.nextToken();
+ if(currentStr.equals("struct"))
+ {
+ returnValue = getStructureType(baseTok.nextToken(""));
+ }
+ else
+ {
+ returnValue = getPrimitiveType(baseStr);
+ //System.out.println("getPrimitiveType");
+ }
+ }
+
+ return returnValue;
+ }
+
+
+ private static RasPrimitiveType getPrimitiveType(String primStr) throws RasTypeUnknownException
+ {
+ StringTokenizer primTok = new StringTokenizer(primStr, "{}[]<>,: ");
+ String currentStr = "";
+ RasPrimitiveType returnValue = null;
+ if(primTok.hasMoreTokens())
+ {
+ currentStr = primTok.nextToken();
+ if(currentStr.equals("char"))
+ returnValue = new RasPrimitiveType("RAS_CHAR", RasGlobalDefs.RAS_CHAR);
+ else if(currentStr.equals("octet"))
+ returnValue = new RasPrimitiveType("RAS_BYTE", RasGlobalDefs.RAS_BYTE);
+ else if(currentStr.equals("short"))
+ returnValue = new RasPrimitiveType("RAS_SHORT", RasGlobalDefs.RAS_SHORT);
+ else if(currentStr.equals("ushort"))
+ returnValue = new RasPrimitiveType("RAS_USHORT", RasGlobalDefs.RAS_USHORT);
+ else if(currentStr.equals("long"))
+ returnValue = new RasPrimitiveType("RAS_LONG", RasGlobalDefs.RAS_LONG);
+ else if(currentStr.equals("ulong"))
+ returnValue = new RasPrimitiveType("RAS_ULONG", RasGlobalDefs.RAS_ULONG);
+ else if(currentStr.equals("bool"))
+ returnValue = new RasPrimitiveType("RAS_BOOLEAN", RasGlobalDefs.RAS_BOOLEAN);
+ else if(currentStr.equals("float"))
+ returnValue = new RasPrimitiveType("RAS_FLOAT", RasGlobalDefs.RAS_FLOAT);
+ else if(currentStr.equals("double"))
+ returnValue = new RasPrimitiveType("RAS_DOUBLE", RasGlobalDefs.RAS_DOUBLE);
+ else
+ throw new RasTypeUnknownException(currentStr);
+ }
+
+ return returnValue;
+ }
+
+
+ private static RasStructureType getStructureType(String structStr) throws RasTypeUnknownException
+ {
+ StringTokenizer structTok = new StringTokenizer(structStr, "[]<>,: ");
+ RasStructureType returnValue = null;
+ String structName = "";
+ RasBaseType[] baseType = new RasBaseType[structTok.countTokens()/2];
+ String[] attributeName = new String[structTok.countTokens()/2];
+ //System.out.println("enter getStructureType");
+ // get struct name
+ if(structTok.hasMoreTokens())
+ {
+ structName = structTok.nextToken();
+ if(structName.equals("{"))
+ structName="";
+ else
+ structTok.nextToken();
+ //System.out.println("StructName:" + structName);
+ }
+ else
+ {
+ // no struct name
+ throw new RasTypeUnknownException("");
+ }
+
+ //Fehler falls kein { so lange bis } dazwischen ,!!!
+ for(int i=0; i < attributeName.length; i++)
+ {
+ // get type
+ String more = structTok.nextToken();
+ if(more.equals("}"))
+ break;
+ else
+ {
+ baseType[i] = getBaseType(more);
+ //System.out.println("BaseType:"+ i + baseType[i]);
+ // get attribut name
+ if(structTok.hasMoreTokens())
+ {
+ attributeName[i] = structTok.nextToken();
+ //System.out.println("Attribut:"+ i + attributeName[i]);
+ }
+ else
+ // no attribut name
+ throw new RasTypeUnknownException("");
+ }
+ }
+
+ returnValue = new RasStructureType(structName, baseType, attributeName);
+ return returnValue;
+ }
+
+ private static RasSIntervalType getSIntervalType(String sintStr)
+ {
+ return new RasSIntervalType();
+ }
+
+ private static RasMIntervalType getMIntervalType(String mintStr)
+ {
+ return new RasMIntervalType();
+ }
+
+ private static RasPointType getPointType(String pointStr)
+ {
+ return new RasPointType();
+ }
+
+ private static RasOIDType getOIDType(String oidStr)
+ {
+ return new RasOIDType();
+ }
+
+ /**
+ * @return the string represntation of this type
+ **/
+ public String toString()
+ {
+ return "typeName: " + typeName + "\n typeID: " + typeID +"\n ";
+ }
+
+}
diff --git a/java/rasj/RasTypeInvalidException.java b/java/rasj/RasTypeInvalidException.java
new file mode 100644
index 0000000..540e15a
--- /dev/null
+++ b/java/rasj/RasTypeInvalidException.java
@@ -0,0 +1,93 @@
+package rasj;
+
+import rasj.global.*;
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * This exception is thrown if a {@link rasj.RasPrimitiveType primitive type} is accessed by a method
+ * having the wrong type.
+ * @see rasj.RasPrimitiveType
+ * @version $Revision: 1.7 $
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+
+public class RasTypeInvalidException extends RasException
+{
+ static final String rcsid = "@(#)Package rasj, class RasTypeInvalidException: $Header: /home/rasdev/CVS-repository/rasdaman/java/rasj/RasTypeInvalidException.java,v 1.7 2003/12/19 16:22:27 rasdev Exp $";
+
+ // the base type
+ String bType = null;
+
+ // the type of the access method
+ String aType = null;
+
+ /**
+ * Standard constructor getting the type of the base type and the type of the
+ * access method that caused the error.
+ * @param baseType the type of the base type
+ * @param accessType the type of the access method that caused the error
+ **/
+ protected RasTypeInvalidException(String baseType, String accessType)
+ {
+ super(RasGlobalDefs.TYPE_INVALID);
+ bType = ( (baseType==null) ? "(null)" : baseType );
+ aType = ( (accessType==null) ? "(null)" : accessType );
+ }
+
+ /**
+ * Returns the error message.
+ * @return the error message.
+ **/
+ public String getMessage()
+ {
+ int i;
+
+ if(super.getMessage() == null)
+ {
+ String msg = RasErrorTexts.getErrorMessage(errNo);
+
+ StringBuffer buf = new StringBuffer(msg);
+ i = msg.indexOf( RasGlobalDefs.KEYWORD_ATYPE );
+ if(i != -1)
+ buf.replace(i, i+RasGlobalDefs.KEYWORD_ATYPE.length(), String.valueOf(bType));
+ msg = buf.toString();
+ i = msg.indexOf( RasGlobalDefs.KEYWORD_BTYPE );
+ if(i != -1)
+ buf.replace(i, i+RasGlobalDefs.KEYWORD_BTYPE.length(), String.valueOf(aType));
+ msg = buf.toString();
+ return msg;
+ }
+ else
+ return super.getMessage();
+ }
+
+}
diff --git a/java/rasj/RasTypeNotSupportedException.java b/java/rasj/RasTypeNotSupportedException.java
new file mode 100644
index 0000000..911e837
--- /dev/null
+++ b/java/rasj/RasTypeNotSupportedException.java
@@ -0,0 +1,82 @@
+package rasj;
+
+import rasj.global.*;
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * This runtime exception is raised when the
+ * {@link rasj.RasType BaseType} of a query result is not supported
+ * by the current version of the rasj package.
+ * @version $Revision: 1.3 $
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+public class RasTypeNotSupportedException extends RasRuntimeException
+{
+ static final String rcsid = "@(#)Package rasj, class RasDimensionMismatchException: $Header: /home/rasdev/CVS-repository/rasdaman/java/rasj/RasTypeNotSupportedException.java,v 1.3 2003/12/19 16:22:27 rasdev Exp $";
+
+ // the unknown type
+ private String rType = null;
+
+ /**
+ * Standard constructor getting the type that caused the error.
+ * @param type the unknown type that caused this exception
+ **/
+ public RasTypeNotSupportedException(String type)
+ {
+ super(RasGlobalDefs.TYPE_NOT_SUPPORTED);
+ rType = ( (type==null) ? "(null)" : type );
+ }
+
+ /**
+ * Returns the error message.
+ * @return the error message.
+ **/
+ public String getMessage()
+ {
+ int i;
+
+ if(super.getMessage() == null)
+ {
+ String msg = RasErrorTexts.getErrorMessage(errNo);
+
+ StringBuffer buf = new StringBuffer(msg);
+ i = msg.indexOf( RasGlobalDefs.KEYWORD_TYPE );
+ if(i != -1)
+ buf.replace(i, i+RasGlobalDefs.KEYWORD_TYPE.length(), String.valueOf(rType));
+ msg = buf.toString();
+ return msg;
+ }
+ else
+ return super.getMessage();
+ }
+
+}
diff --git a/java/rasj/RasTypeUnknownException.java b/java/rasj/RasTypeUnknownException.java
new file mode 100644
index 0000000..5f27808
--- /dev/null
+++ b/java/rasj/RasTypeUnknownException.java
@@ -0,0 +1,83 @@
+package rasj;
+
+import rasj.global.*;
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * This runtime exception is raised when the
+ * {@link rasj.RasType RasType} of a query result is unknown
+ * on client-side.
+ * @version $Revision: 1.6 $
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+
+public class RasTypeUnknownException extends RasRuntimeException
+{
+ static final String rcsid = "@(#)Package rasj, class RasDimensionMismatchException: $Header: /home/rasdev/CVS-repository/rasdaman/java/rasj/RasTypeUnknownException.java,v 1.6 2003/12/19 16:22:27 rasdev Exp $";
+
+ // the unknown type
+ private String rType = null;
+
+ /**
+ * Standard constructor getting the type that caused the error.
+ * @param type the unknown type that caused this exception
+ **/
+ protected RasTypeUnknownException(String type)
+ {
+ super(RasGlobalDefs.TYPE_UNKNOWN);
+ rType = ( (type==null) ? "(null)" : type );
+ }
+
+ /**
+ * Returns the error message.
+ * @return the error message.
+ **/
+ public String getMessage()
+ {
+ int i;
+
+ if(super.getMessage() == null)
+ {
+ String msg = RasErrorTexts.getErrorMessage(errNo);
+
+ StringBuffer buf = new StringBuffer(msg);
+ i = msg.indexOf( RasGlobalDefs.KEYWORD_TYPE );
+ if(i != -1)
+ buf.replace( i, i+RasGlobalDefs.KEYWORD_TYPE.length(), String.valueOf(rType) );
+ msg = buf.toString();
+ return msg;
+ }
+ else
+ return super.getMessage();
+ }
+
+}
diff --git a/java/rasj/Rasj.el b/java/rasj/Rasj.el
new file mode 100644
index 0000000..3dd7e16
--- /dev/null
+++ b/java/rasj/Rasj.el
@@ -0,0 +1,91 @@
+
+
+
+(jde-set-project-name "Rasj")
+(jde-set-variables
+ '(jde-use-font-lock t)
+ '(jde-db-set-initial-breakpoint t)
+ '(jde-run-option-garbage-collection (quote (t t)))
+ '(jde-db-option-stack-size (quote ((128 . "kilobytes") (400 . "kilobytes"))))
+ '(jde-compiler "javac")
+ '(jde-compile-option-extdirs nil)
+ '(jde-db-read-vm-args nil)
+ '(jde-compile-option-bootclasspath nil)
+ '(jde-run-working-directory "./")
+ '(jde-compile-option-debug (quote ("selected" (t nil nil))))
+ '(jde-db-option-verbose (quote (nil nil nil)))
+ '(jde-run-option-heap-size (quote ((1 . "megabytes") (16 . "megabytes"))))
+ '(jde-run-read-app-args nil)
+ '(jde-db-option-java-profile (quote (nil . "./java.prof")))
+ '(jde-entering-java-buffer-hooks (quote (jde-reload-project-file)))
+ '(jde-run-option-java-profile (quote (nil . "./java.prof")))
+ '(jde-gen-window-listener-template (quote ("'& (P \"Window name: \")" "\".addWindowListener(new WindowAdapter() {\" 'n>" "\"public void windowActivated(WindowEvent e) {}\" 'n>" "\"public void windowClosed(WindowEvent e) {}\" 'n>" "\"public void windowClosing(WindowEvent e) {System.exit(0);}\" 'n>" "\"public void windowDeactivated(WindowEvent e) {}\" 'n>" "\"public void windowDeiconified(WindowEvent e) {}\" 'n>" "\"public void windowIconified(WindowEvent e) {}\" 'n>" "\"public void windowOpened(WindowEvent e) {}});\" 'n>")))
+ '(jde-db-option-vm-args nil)
+ '(jde-make-program "gmake")
+ '(jde-compile-option-target (quote ("1.1")))
+ '(jde-run-application-class "")
+ '(jde-global-classpath nil)
+ '(jde-run-option-verbose (quote (nil nil nil)))
+ '(jde-db-option-heap-size (quote ((1 . "megabytes") (16 . "megabytes"))))
+ '(jde-db-mode-hook nil)
+ '(jde-key-bindings (quote (("" . jde-compile) ("" . jde-run) ("" . jde-db) ("" . jde-build) ("" . jde-run-menu-run-applet) ("" . jde-browse-jdk-doc) ("" . jde-save-project) (" " . jde-gen-println))))
+ '(jde-db-option-garbage-collection (quote (t t)))
+ '(jde-run-option-properties nil)
+ '(jde-compile-option-nowarn nil)
+ '(jde-compile-option-depend nil)
+ '(jde-compile-option-vm-args nil)
+ '(jde-db-read-app-args nil)
+ '(jde-read-compile-args nil)
+ '(jde-db-option-properties nil)
+ '(jde-run-applet-doc "index.html")
+ '(jde-compile-option-directory "")
+ '(jde-run-java-vm "java")
+ '(jde-project-file-name "Rasj.el")
+ '(jde-db-option-verify (quote (nil t)))
+ '(jde-gen-property-change-support (quote ("'&" "\"protected PropertyChangeSupport pcs = new PropertyChangeSupport(this);\" 'n>" "\"/**\" 'n>\"* Adds a PropertyChangeListener to the listener list.\" 'n>" "\"* The listener is registered for all properties.\" 'n>" "\"*\" 'n> \"* @param listener The PropertyChangeListener to be added\" 'n> \"*/\" 'n>" "\"public void addPropertyChangeListener(PropertyChangeListener listener) {\" 'n>" "\"pcs.addPropertyChangeListener(listener);\" 'n> \"}\" 'n> 'n>" "\"/**\" 'n>\"* Removes a PropertyChangeListener from the listener list.\" 'n>" "\"* This removes a PropertyChangeListener that was registered for all properties.\" 'n>" "\"*\" 'n> \"* @param listener The PropertyChangeListener to be removed\" 'n> \"*/\" 'n>" "\"public void removePropertyChangeListener(PropertyChangeListener listener) {\" 'n>" "\"pcs.removePropertyChangeListener(listener);\" 'n> \"}\" 'n> 'n>" "\"/**\" 'n>\"* Adds a PropertyChangeListener for a specific property.\" 'n>" "\"* The listener will be invoked only when a call on firePropertyChange\" 'n>" "\"* names that specific property.\" 'n>" "\"*\" 'n> \"* @param propertyName The name of the property to listen on\" 'n>" "\"* @param listener The PropertyChangeListener to be added\" 'n> \"*/\" 'n>" "\"public void addPropertyChangeListener(String propertyName,\" 'n>" "\"PropertyChangeListener listener) {\" 'n>" "\"pcs.addPropertyChangeListener(propertyName, listener);\" 'n> \"}\" 'n> 'n>" "\"/**\" 'n>\"* Removes a PropertyChangeListener for a specific property.\" 'n>" "\"*\" 'n> \"* @param propertyName The name of the property that was listened on\" 'n>" "\"* @param listener The PropertyChangeListener to be removed\" 'n> \"*/\" 'n>" "\"public void removePropertyChangeListener(String propertyName,\" 'n>" "\"PropertyChangeListener listener) {\" 'n>" "\"pcs.removePropertyChangeListener(propertyName, listener);\" 'n> \"}\" 'n> 'n>" "\"/**\" 'n>\"* Reports a bound property update to any registered listeners. \" 'n>" "\"* No event is fired if old and new are equal and non-null.\" 'n>" "\"*\" 'n> \"* @param propertyName The programmatic name of the property that was changed\" 'n>" "\"* @param oldValue The old value of the property\" 'n>" "\"* @param newValue The new value of the property.\" 'n> \"*/\" 'n>" "\"public void firePropertyChange(String propertyName, Object oldValue, Object newValue) {\" 'n>" "\"pcs.firePropertyChange(propertyName, oldValue, newValue);\" 'n> \"}\" 'n> 'n>" "\"/**\" 'n>\"* Reports a bound property update to any registered listeners. \" 'n>" "\"* No event is fired if old and new are equal and non-null.\" 'n>" "\"* This is merely a convenience wrapper around the more general\" 'n>" "\"* firePropertyChange method that takes Object values.\" 'n>" "\"* No event is fired if old and new are equal and non-null.\" 'n>" "\"*\" 'n> \"* @param propertyName The programmatic name of the property that was changed\" 'n>" "\"* @param oldValue The old value of the property\" 'n>" "\"* @param newValue The new value of the property.\" 'n> \"*/\" 'n>" "\"public void firePropertyChange(String propertyName, int oldValue, int newValue) {\" 'n>" "\"pcs.firePropertyChange(propertyName, oldValue, newValue);\" 'n> \"}\" 'n> 'n>" "\"/**\" 'n>\"* Reports a bound property update to any registered listeners. \" 'n>" "\"* No event is fired if old and new are equal and non-null.\" 'n>" "\"* This is merely a convenience wrapper around the more general\" 'n>" "\"* firePropertyChange method that takes Object values.\" 'n>" "\"* No event is fired if old and new are equal and non-null.\" 'n>" "\"*\" 'n> \"* @param propertyName The programmatic name of the property that was changed\" 'n>" "\"* @param oldValue The old value of the property\" 'n>" "\"* @param newValue The new value of the property.\" 'n> \"*/\" 'n>" "\"public void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) {\" 'n>" "\"pcs.firePropertyChange(propertyName, oldValue, newValue);\" 'n> \"}\" 'n> 'n>" "\"/**\" 'n>\"* Fires an existing PropertyChangeEvent to any registered listeners.\" 'n>" "\"* No event is fired if the given event's old and new values are equal and non-null. \" 'n>" "\"*\" 'n> \"* @param evt The PropertyChangeEvent object.\" 'n>\"*/\" 'n>" "\"public void firePropertyChange(PropertyChangeEvent evt) {\" 'n>" "\"pcs.firePropertyChange(evt);\" 'n> \"}\" 'n> 'n>" "\"/**\" 'n>\"* Checks if there are any listeners for a specific property.\" 'n>" "\"*\" 'n> \"* @param evt The PropertyChangeEvent object.\" 'n>" "\"* @return <code>true</code>if there are one or more listeners for the given property\" 'n>" "\"*/\" 'n>" "\"public boolean hasListeners(String propertyName) {\" 'n>" "\"return pcs.hasListeners(propertyName);\" 'n> \"}\" 'n> 'n>")))
+ '(jde-gen-mouse-motion-listener-template (quote ("'& (P \"Component name: \")" "\".addMouseMotionListener(new MouseMotionAdapter() {\" 'n>" "\"public void mouseDragged(MouseEvent e) {}\" 'n>" "\"public void mouseMoved(MouseEvent e) {}});\" 'n>")))
+ '(jde-run-option-vm-args nil)
+ '(jde-gen-console-buffer-template (quote ("(funcall jde-gen-boilerplate-function) 'n" "\"/**\" 'n" "\" * \"" "(file-name-nondirectory buffer-file-name) 'n" "\" *\" 'n" "\" *\" 'n" "\" * Created: \" (current-time-string) 'n" "\" *\" 'n" "\" * @author \" (user-full-name) 'n" "\" * @version\" 'n" "\" */\" 'n>" "'n>" "\"public class \"" "(file-name-sans-extension (file-name-nondirectory buffer-file-name))" "\" {\" 'n> 'n>" "\"public \"" "(file-name-sans-extension (file-name-nondirectory buffer-file-name))" "\"() {\" 'n>" "'n>" "\"}\" 'n>" "'n>" "\"public static void main(String[] args) {\" 'n>" "'p 'n>" "\"}\" 'n> 'n>" "\"} // \"" "(file-name-sans-extension (file-name-nondirectory buffer-file-name))" "'n>")))
+ '(jde-jdk-doc-url "http://www.javasoft.com/products/jdk/1.2/docs/index.html")
+ '(jde-run-option-stack-size (quote ((128 . "kilobytes") (400 . "kilobytes"))))
+ '(jde-db-option-heap-profile (quote (nil "./java.hprof" 5 20 "Allocation objects")))
+ '(jde-db-option-classpath nil)
+ '(jde-run-option-verify (quote (nil t)))
+ '(jde-db-option-application-args nil)
+ '(jde-gen-get-set-var-template (quote ("'n>" "(P \"Variable type: \" type) \" \"" "(P \"Variable name: \" name) \";\" 'n> 'n>" "\"/**\" 'n>" "\"* Get the value of \" (s name) \".\" 'n>" "\"* @return Value of \" (s name) \".\" 'n>" "\"*/\" 'n>" "\"public \" (s type) \" get\" (jde-gen-init-cap (jde-gen-lookup-named 'name))" "\"() {return \" (s name) \";}\" 'n> 'n>" "\"/**\" 'n>" "\"* Set the value of \" (s name) \".\" 'n>" "\"* @param v Value to assign to \" (s name) \".\" 'n>" "\"*/\" 'n>" "\"public void set\" (jde-gen-init-cap (jde-gen-lookup-named 'name))" "\"(\" (s type) \" v) {this.\" (s name) \" = v;}\" 'n>")))
+ '(jde-gen-println (quote ("'&" "\"System.out.println(\" (P \"Print out: \") \");\" 'n>")))
+ '(jde-run-mode-hook nil)
+ '(jde-compile-option-sourcepath nil)
+ '(jde-compile-option-depend-switch (quote ("-Xdepend")))
+ '(jde-gen-buffer-boilerplate nil)
+ '(jde-build-use-make nil)
+ '(jde-db-startup-commands nil)
+ '(jde-compile-option-verbose-path nil)
+ '(jde-compile-option-command-line-args "")
+ '(jde-mode-abbreviations (quote (("ab" . "abstract") ("bo" . "boolean") ("br" . "break") ("by" . "byte") ("byv" . "byvalue") ("cas" . "cast") ("ca" . "catch") ("ch" . "char") ("cl" . "class") ("co" . "const") ("con" . "continue") ("de" . "default") ("dou" . "double") ("el" . "else") ("ex" . "extends") ("fa" . "false") ("fi" . "final") ("fin" . "finally") ("fl" . "float") ("fo" . "for") ("fu" . "future") ("ge" . "generic") ("go" . "goto") ("impl" . "implements") ("impo" . "import") ("ins" . "instanceof") ("in" . "int") ("inte" . "interface") ("lo" . "long") ("na" . "native") ("ne" . "new") ("nu" . "null") ("pa" . "package") ("pri" . "private") ("pro" . "protected") ("pu" . "public") ("re" . "return") ("sh" . "short") ("st" . "static") ("su" . "super") ("sw" . "switch") ("sy" . "synchronized") ("th" . "this") ("thr" . "throw") ("throw" . "throws") ("tra" . "transient") ("tr" . "true") ("vo" . "void") ("vol" . "volatile") ("wh" . "while"))))
+ '(jde-gen-code-templates (quote (("Get Set Pair" . jde-gen-get-set) ("toString method" . jde-gen-to-string-method) ("Action Listener" . jde-gen-action-listener) ("Window Listener" . jde-gen-window-listener) ("Mouse Listener" . jde-gen-mouse-listener) ("Mouse Motion Listener" . jde-gen-mouse-motion-listener) ("Inner Class" . jde-gen-inner-class) ("println" . jde-gen-println) ("property change support" . jde-gen-property-change-support))))
+ '(jde-compile-option-classpath nil)
+ '(jde-gen-boilerplate-function (quote jde-gen-create-buffer-boilerplate))
+ '(jde-gen-class-buffer-template (quote ("(funcall jde-gen-boilerplate-function) 'n" "\"/**\" 'n" "\" * \"" "(file-name-nondirectory buffer-file-name) 'n" "\" *\" 'n" "\" *\" 'n" "\" * Created: \" (current-time-string) 'n" "\" *\" 'n" "\" * @author \" (user-full-name) 'n" "\" * @version\" 'n" "\" */\" 'n>" "'n>" "\"public class \"" "(file-name-sans-extension (file-name-nondirectory buffer-file-name))" "\" \" (jde-gen-get-super-class) \" {\" 'n> 'n>" "\"public \"" "(file-name-sans-extension (file-name-nondirectory buffer-file-name))" "\"() {\" 'n>" "'p 'n>" "\"}\" 'n>" "'n>" "\"} // \"" "(file-name-sans-extension (file-name-nondirectory buffer-file-name))" "'n>")))
+ '(jde-gen-action-listener-template (quote ("'& (P \"Component name: \")" "\".addActionListener(new ActionListener() {\" 'n>" "\"public void actionPerformed(ActionEvent e) {\" 'n>" "\"}});\" 'n>")))
+ '(jde-enable-abbrev-mode nil)
+ '(jde-quote-classpath t)
+ '(jde-run-option-application-args nil)
+ '(jde-run-java-vm-w "javaw")
+ '(jde-run-read-vm-args nil)
+ '(jde-run-applet-viewer "appletviewer")
+ '(jde-gen-inner-class-template (quote ("'& \"class \" (P \"Class name: \" class)" "(P \"Superclass: \" super t)" "(let ((parent (jde-gen-lookup-named 'super)))" "(if (not (string= parent \"\"))" "(concat \" extends \" parent))) \" {\" 'n>" "\"public \" (s class) \"() {\" 'n> \"}\" 'n> \"}\" 'n>")))
+ '(jde-compile-option-deprecation nil)
+ '(jde-db-marker-regexp "^Breakpoint hit: .*(\\([^$]*\\).*:\\([0-9]*\\))")
+ '(jde-db-debugger (quote ("jdb" . "Executable")))
+ '(jde-db-source-directories (quote ("./")))
+ '(jde-gen-jfc-app-buffer-template (quote ("(funcall jde-gen-boilerplate-function) 'n" "\"import java.awt.*;\" 'n" "\"import java.awt.event.*;\" 'n" "\"import com.sun.java.swing.*;\" 'n 'n" "\"/**\" 'n" "\" * \"" "(file-name-nondirectory buffer-file-name) 'n" "\" *\" 'n" "\" *\" 'n" "\" * Created: \" (current-time-string) 'n" "\" *\" 'n" "\" * @author \" (user-full-name) 'n" "\" * @version\" 'n" "\" */\" 'n>" "'n>" "\"public class \"" "(file-name-sans-extension (file-name-nondirectory buffer-file-name))" "\" extends JFrame {\" 'n> 'n>" "\"public \"" "(file-name-sans-extension (file-name-nondirectory buffer-file-name))" "\"() {\" 'n>" "\"super(\\\"\" (P \"Enter app title: \") \"\\\");\" 'n>" "\"setSize(600, 400);\" 'n>" "\"addWindowListener(new WindowAdapter() {\" 'n>" "\"public void windowClosing(WindowEvent e) {System.exit(0);}\" 'n>" "\"public void windowOpened(WindowEvent e) {}});\" 'n>" "\"}\" 'n>" "'n>" "\"public static void main(String[] args) {\" 'n>" "'n>" "(file-name-sans-extension (file-name-nondirectory buffer-file-name))" "\" f = new \"" "(file-name-sans-extension (file-name-nondirectory buffer-file-name))" "\"();\" 'n>" "\"f.show();\" 'n>" "'p 'n>" "\"}\" 'n> 'n>" "\"} // \"" "(file-name-sans-extension (file-name-nondirectory buffer-file-name))" "'n>")))
+ '(jde-make-args "")
+ '(jde-gen-mouse-listener-template (quote ("'& (P \"Component name: \")" "\".addMouseListener(new MouseAdapter() {\" 'n>" "\"public void mouseClicked(MouseEvent e) {}\" 'n>" "\"public void mouseEntered(MouseEvent e) {}\" 'n>" "\"public void mouseExited(MouseEvent e) {}\" 'n>" "\"public void mousePressed(MouseEvent e) {}\" 'n>" "\"public void mouseReleased(MouseEvent e) {}});\" 'n>")))
+ '(jde-run-option-classpath nil)
+ '(jde-gen-buffer-templates (quote (("Class" . jde-gen-class) ("Console" . jde-gen-console) ("Swing App" . jde-gen-jfc-app))))
+ '(jde-compile-option-verbose nil)
+ '(jde-compile-option-optimize nil)
+ '(jde-compile-option-encoding nil)
+ '(jde-run-option-heap-profile (quote (nil "./java.hprof" 5 20 "Allocation objects")))
+ '(jde-gen-to-string-method-template (quote ("'&" "\"public String toString() {\" 'n>" "\"return super.toString();\" 'n>" "\"}\" 'n>"))))
diff --git a/java/rasj/clientcommhttp/Makefile b/java/rasj/clientcommhttp/Makefile
new file mode 100644
index 0000000..7c9dc43
--- /dev/null
+++ b/java/rasj/clientcommhttp/Makefile
@@ -0,0 +1,62 @@
+# -*-Makefile-*- (for Emacs)
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>. # Top Level makefile. This points to the various modules that have to be build
+# and/or deployed
+#
+# MAKEFILE FOR:
+# package rasj/clientcommhttp
+#
+# COMMENTS:
+#
+##################################################################
+######################### Definitions ############################
+
+# standard include with general options
+include $(RMANBASE)/Makefile.inc
+
+# directory where HTML documentation is created
+DOCDIR := $(DOCBASE)/rasdaman/java/rasj/clientcommhttp
+
+SRCS = RasCommDefs.java RasHttpRequest.java RasUtils.java
+OBJS = ${SRCS:%.java=%.class}
+MISCCLEAN = *.class
+
+########################### Targets ##############################
+
+# compile everything
+.PHONY : all
+all: $(OBJS)
+
+# HTML docu
+docj:
+ -rm -rf $(DOCDIR)/rasj/clientcommhttp
+ $(JAVADOC) -author -d $(DOCDIR) rasj/clientcommhttp
+
+# delete all object files
+clean:
+ -rm -f $(MISCCLEAN)
+
+############################ Dependencies #######################
+# general rules
+# FIXME: should not be used here (only for relational adapter modules in rel*/), but is needed for Java targets
+include $(RMANBASE)/Makefile.rel
+
diff --git a/java/rasj/clientcommhttp/Makefile.dep b/java/rasj/clientcommhttp/Makefile.dep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/java/rasj/clientcommhttp/Makefile.dep
diff --git a/java/rasj/clientcommhttp/RasCommDefs.class b/java/rasj/clientcommhttp/RasCommDefs.class
new file mode 100644
index 0000000..19067da
--- /dev/null
+++ b/java/rasj/clientcommhttp/RasCommDefs.class
Binary files differ
diff --git a/java/rasj/clientcommhttp/RasCommDefs.java b/java/rasj/clientcommhttp/RasCommDefs.java
new file mode 100644
index 0000000..f08fae3
--- /dev/null
+++ b/java/rasj/clientcommhttp/RasCommDefs.java
@@ -0,0 +1,54 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+package rasj.clientcommhttp;
+
+public interface RasCommDefs
+{
+ static final String rcsid = "@(#)Package rasj.clientcommhttp, class RasCommDefs: $Header: /home/rasdev/CVS-repository/rasdaman/java/rasj/clientcommhttp/RasCommDefs.java,v 1.5 2003/12/10 21:04:26 rasdev Exp $";
+
+ final public byte RASCLIENT = 1;
+ final public byte BROWSER = 2;
+
+ final public byte RESPONSE_ERROR = 0;
+ final public byte RESPONSE_MDDS = 1;
+ final public byte RESPONSE_SKALARS = 2;
+ final public byte RESPONSE_INT = 3;
+ final public byte RESPONSE_OID = 4;
+ final static byte RESPONSE_OK_NEGATIVE = 98;
+ final public byte RESPONSE_OK = 99;
+
+ final public byte BIG_ENDIAN = 0;
+ final public byte LITTLE_ENDIAN = 1;
+}
diff --git a/java/rasj/clientcommhttp/RasHttpRequest.class b/java/rasj/clientcommhttp/RasHttpRequest.class
new file mode 100644
index 0000000..43ecc52
--- /dev/null
+++ b/java/rasj/clientcommhttp/RasHttpRequest.class
Binary files differ
diff --git a/java/rasj/clientcommhttp/RasHttpRequest.java b/java/rasj/clientcommhttp/RasHttpRequest.java
new file mode 100644
index 0000000..f80a2ca
--- /dev/null
+++ b/java/rasj/clientcommhttp/RasHttpRequest.java
@@ -0,0 +1,805 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ * - return type complex not yet supported.
+ * </pre>
+ *********************************************************** */
+
+package rasj.clientcommhttp;
+
+import rasj.*;
+import org.odmg.*;
+import rasj.odmg.*;
+import rasj.global.*;
+
+import java.io.*;
+import java.net.*;
+import java.lang.*;
+import java.util.*;
+
+/**
+ * This class handles a HTTP-request to the RasDaMan server.
+ * The specified RasDaMan server is contacted, the specified command is sent to
+ * the server, and the result of the query is retrieved and stored in a byte array.
+ * The specification of the communication protocol is given below.
+ * <P>
+ *
+ * @version $Revision: 1.35 $
+ *
+ * </UL><P>
+ * <B>Request structure</B><P><UL>
+ * The rasj HTTP request to the rasdaman server uses the HTTP POST-Format with the following
+ * parameters:
+ * <P>
+ * <TABLE BORDER=1 WIDTH=100%>
+ * <TR><TH>Parameter:</TH><TH>Description:</TH><TH>Required for</TH></TR>
+ * <TR><TD>Command</TD>
+ * <TD>Integer value specifying the desired action (e.g. OpenDB, BT, CT, CloseDB ...)</TD>
+ * <TD>all requests</TD></TR>
+ * <TR><TD>Database</TD>
+ * <TD>String value specifying the database</TD>
+ * <TD>OpenDB, CloseDB</TD></TR>
+ * <TR><TD>ClientType</TD>
+ * <TD>Integer value defining the type of the client (at the moment always RasClient)</TD>
+ * <TD>all requests</TD></TR>
+ * <TR><TD>ClientID</TD>
+ * <TD>Integer value specifying the ClientID (currently set to 1 for every client)</TD>
+ * <TD>all requests</TD></TR>
+ * <TR><TD>QueryString</TD>
+ * <TD>String value containing the RasQL query</TD>
+ * <TD>executeQuery</TD></TR>
+ * <TR><TD>Endianess</TD>
+ * <TD>Integer value containing the Client Endianess</TD>
+ * <TD>only insert queries</TD></TR>
+ * <TR><TD>NumberOfQueryParameters</TD>
+ * <TD>Integer value specifying the number of query parameters</TD>
+ * <TD>only insert queries</TD></TR>
+ * <TR><TD>QueryParameters</TD>
+ * <TD>Byte Array containing the query parameters (MDDs) using the following format:<BR>
+ * <TABLE BORDER=1>
+ * <TR><TH>Integer</TH><TH>String</TH><TH>String</TH><TH>Integer</TH><TH>String</TH><TH>String</TH>
+ * <TH>String</TH><TH>Long</TH><TH>Byte[]</TH>
+ * </TR>
+ * <TR><TD>objectType</TD><TD>objectTypeName</TD><TD>typeStructure</TD><TD>typeLength</TD>
+ * <TD>domain</TD><TD>storageLayout</TD><TD>OID</TD><TD>dataSize</TD><TD>binary data</TD></TR>
+ * </TABLE>
+ *</TD>
+ * <TD>only insert queries</TD></TR>
+ * </TABLE>
+ * </P>
+ * </UL><P>
+ *
+ * <B>Result formats / internal representation:</B><P><UL>
+ * The result of a HTTP request has one of the following forms:<P>
+ * MDD Collections:<BR>
+ * <TABLE BORDER=1><TR><TH ROWSPAN=2>Byte</TH><TH ROWSPAN=2>Byte</TH>
+ * <TH ROWSPAN=2>String</TH><TH ROWSPAN=2>Long(4Bytes)</TH>
+ * <TH COLSPAN=5>resultElement 1</TH><TH ROWSPAN=3> ... </TH></TR>
+ * <TR><TD>String</TD><TD>String</TD><TD>String</TD><TD>Long(4Bytes)</TD><TD>Byte[]</TD></TR>
+ * <TR><TD>Result type<P>1=MDDCollection</TD>
+ * <TD>Endianess</TD>
+ * <TD>Collection type</TD>
+ * <TD>Number of results</TD>
+ * <TD>BaseType description</TD>
+ * <TD>Spatial domain</TD>
+ * <TD>OID</TD>
+ * <TD>Size of the Binary Data Block</TD>
+ * <TD>Binary Data Block</TD></TR>
+ * </TABLE><P>
+ *
+ * Skalar Collections:<BR>
+ * <TABLE BORDER=1><TR><TH ROWSPAN=2>Byte</TH><TH ROWSPAN=2>Byte</TH>
+ * <TH ROWSPAN=2>String</TH><TH ROWSPAN=2>Long(4Bytes)</TH>
+ * <TH COLSPAN=4>resultElement 1</TH><TH ROWSPAN=3> ... </TH></TR>
+ * <TR><TD>String</TD><TD>Long(4Bytes)</TD><TD>Byte[]</TD></TR>
+ * <TR><TD>Result type<P>2=SkalarCollection</TD>
+ * <TD>Endianess</TD>
+ * <TD>Collection type</TD>
+ * <TD>Number of results</TD>
+ * <TD>ElementType description</TD>
+ * <TD>Size of the Binary Data Block</TD>
+ * <TD>Binary Data Block</TD></TR>
+ * </TABLE><P>
+ *
+ * Errors:<BR>
+ * <TABLE BORDER=1><TR><TH>Byte</TH><TH>Byte</TH>
+ * <TH>Long(4Bytes)</TH><TH>Long(4Bytes)</TH><TH>Long(4Bytes)</TH>
+ * <TH>String</TH></TR>
+ * <TR><TD>Result type<P>0=Error</TD>
+ * <TD>Endianess</TD>
+ * <TD>Error number</TD>
+ * <TD>Line number</TD>
+ * <TD>Column number</TD>
+ * <TD>Token</TD>
+ * </TABLE><P>
+ *
+ * Single Integer Value:<BR>
+ * <TABLE BORDER=1><TR><TH>Byte</TH><TH>Integer</TH></TR>
+ * <TR><TD>Result type<P>3=Integer</TD><TD>Value</TD></TR>
+ * </TABLE><P>
+ *
+ * OID:<BR>
+ * <TABLE BORDER=1><TR><TH>Byte</TH><TH>String</TH><TH>String</TH><TH>Double</TH></TR>
+ * <TR><TD>Result type<P>4=OID</TD><TD>system</TD><TD>basename</TD><TD>localOID</TD></TR>
+ * </TABLE><P>
+ *
+ * Acknowledgement:<BR>
+ * <TABLE BORDER=1><TR><TH>Byte</TH></TR>
+ * <TR><TD>Result type<P>99=OK</TD></TR>
+ * </TABLE><P>
+ *
+ * </UL>
+ *
+ */
+
+public class RasHttpRequest implements RasCommDefs, RasGlobalDefs
+{
+
+ static final String rcsid = "@(#)Package rasj.clientcommhttp, class RasRequest: $Header: /home/rasdev/CVS-repository/rasdaman/java/rasj/clientcommhttp/RasHttpRequest.java,v 1.35 2003/12/19 15:36:43 rasdev Exp $";
+
+/**
+ * The type of this client */
+ private String client = "RASCLIENT";
+
+/**
+ * The result type ( MDD Collection, Skalar Collection, Error, Integer ). This field is set
+ * automatically when a query has been executed, so there's no setResultType method.
+ */
+ private byte resultType = 0;
+
+/**
+ * The result of the query
+**/
+ private Object result = null;
+
+/**
+ * This method sends a query to the RasDaMan Server and retrieves the results.
+ *
+ * @param con server connection
+ * @param parameters the parameters for the request as name/value pairs (for example "clientID=4354351&queryString=select img from test")
+ */
+ public void execute( String serverURL, String parameters )
+ throws RasQueryExecutionFailedException, RasConnectionFailedException
+ {
+ Debug.enterVerbose( "RasHttpRequest.execute: start. serverURL=" + serverURL + ", parameters=" + parameters );
+
+ BenchmarkTimer httpTimer = new BenchmarkTimer("httpRequest");
+ BenchmarkTimer rcvTimer = new BenchmarkTimer("receive");
+
+ try
+ {
+ URL url = new URL( serverURL );
+
+ Debug.talkVerbose( "RasHttpRequest.execute: sending to " + url + " POST request=" + parameters );
+
+ httpTimer.startTimer();
+
+ BenchmarkTimer sendTimer = new BenchmarkTimer("send");
+ sendTimer.startTimer();
+
+ // Send the query
+ HttpURLConnection con = (HttpURLConnection) url.openConnection();
+ con.setRequestProperty("Content-type","application/octet-stream");
+ con.setRequestProperty("User-Agent","RasDaMan Java Client");
+ con.setRequestProperty("Version","1.0");
+ con.setRequestMethod("POST");
+ con.setDoInput(true);
+ con.setDoOutput(true);
+ con.setUseCaches(false);
+
+ OutputStreamWriter out = new OutputStreamWriter(con.getOutputStream(),"8859_1");
+ out.write(parameters,0,parameters.length());
+ out.flush();
+ out.close();
+
+ sendTimer.stopTimer();
+ sendTimer.print();
+
+ rcvTimer.startTimer();
+
+ // Read response
+ BenchmarkTimer getInputTimer = new BenchmarkTimer("getInputStream");
+ getInputTimer.startTimer();
+ DataInputStream in = new DataInputStream(con.getInputStream());
+ // int BuffSize = con.getContentLength(); // not used -- PB 2003-jun-14
+ // Debug.talkVerbose("RasHttpRequest.execute: buffSize=" + BuffSize);
+ getInputTimer.stopTimer();
+ getInputTimer.print();
+
+
+ /* variables for later use */
+ byte[] b1 = new byte[1];
+ byte[] b4 = new byte[4];
+ byte endianess = 0;
+ String collType = null;
+ int numberOfResults = 0;
+ int dataSize = 0;
+ byte[] binData = null;
+ int readBytes = 0;
+ int readBytesTmp = 0;
+ DBag resultBag;
+ RasGMArray res = null;
+
+ in.read(b1);
+
+ resultType = b1[0];
+ Debug.talkVerbose("RasHttpRequest.execute: resultType=" + resultType );
+ switch( resultType )
+ {
+ case RESPONSE_OK:
+ case RESPONSE_OK_NEGATIVE:
+ //Nothing todo
+ break;
+
+ // +++++++++++++++++++++++++++++++++++++++++++++++++
+ case RESPONSE_MDDS:
+ Debug.talkVerbose("RasHttpRequest.execute: result type is MDD." );
+ // read Endianess
+ while(in.read(b1) == 0)
+ ;
+ endianess = b1[0];
+
+ // read Collection Type
+ collType = RasUtils.readString(in);
+ Debug.talkVerbose("RasHttpRequest.execute: colltype=" + collType);
+
+ // read NumberOfResults
+ while(in.available() < 4)
+ ;
+ in.read(b4);
+ numberOfResults = RasUtils.ubytesToInt(b4,endianess);
+ Debug.talkVerbose("RasHttpRequest.execute: number of results: " + numberOfResults);
+
+ // Initialize return-set and parameters
+ resultBag = new RasBag();
+ String mddBaseType = null;
+ String domain = null;
+ String oid = "";
+ RasOID roid = null;
+
+ // do this for each result
+ for(int x = 0; x < numberOfResults; x++)
+ {
+ Debug.talkVerbose("RasHttpRequest.execute: handling result #" + (x+1) );
+ //read mddBaseType
+ mddBaseType = RasUtils.readString(in);
+
+ // read spatialDomain
+ domain = RasUtils.readString(in);
+
+ // read OID
+ oid = RasUtils.readString(in);
+ //System.err.println("OID is " + oid);
+ roid = new RasOID(oid);
+
+ // read size of binData
+ while(in.available() < 4)
+ ;
+ in.read(b4);
+
+ dataSize = RasUtils.ubytesToInt(b4,endianess);
+
+ Debug.talkVerbose("RasHttpRequest.execute: mddBaseType is " + mddBaseType + ", spatialDomain=" + domain + ", size of BinData=" + dataSize );
+
+ // read binData
+ binData = new byte[dataSize];
+ readBytes = 0;
+ readBytesTmp = 0;
+
+ while( (readBytesTmp != -1) && (readBytes < dataSize) )
+ {
+ readBytesTmp = in.read(binData,readBytes,dataSize-readBytes);
+ readBytes += readBytesTmp;
+ }
+
+ Debug.talkVerbose("RasHttpRequest.execute: read " + readBytes + " bytes.");
+
+ RasType rType = RasType.getAnyType(mddBaseType);
+ //System.out.println(rType);
+ RasBaseType rb = null;
+
+ if(rType.getClass().getName().equals("rasj.RasMArrayType"))
+ {
+ RasMArrayType tmp = (RasMArrayType)rType;
+ rb = tmp.getBaseType();
+ }
+ else
+ {
+ Debug.talkCritical("RasHttpRequest.execute: exception: element of MDD Collection is no MArray" );
+ throw new RasClientInternalException("RasHttpRequest","execute()","element of MDD Collection is no MArray");
+ }
+
+ if(rb.isBaseType())
+ {
+ if(rb.isStructType())
+ {
+ // It is a structType
+ //System.err.println("It is a structType");
+ RasStructureType sType = (RasStructureType)rb;
+ //System.out.println(sType);
+ res = new RasGMArray(new RasMInterval(domain), 0);
+ res.setTypeLength(rb.getSize());
+ res.setArraySize(dataSize);
+ res.setArray(binData);
+ //insert into result set
+ resultBag.add(res);
+ break;
+
+ } else
+ {
+ // It is a primitiveType
+ RasPrimitiveType pType = (RasPrimitiveType)rb;
+
+ //System.err.println("It's a primitive type: " + pType);
+ switch(pType.getTypeID())
+ {
+ case RAS_BOOLEAN:
+ case RAS_BYTE:
+ case RAS_CHAR:
+ //System.err.println("It's a byte array!");
+ res = new RasMArrayByte(new RasMInterval(domain));
+ break;
+ case RAS_SHORT:
+ //System.err.println("It's a short array!");
+ res = new RasMArrayShort(new RasMInterval(domain));
+ break;
+
+ case RAS_USHORT:
+ //System.err.println("It's a ushort array!");
+ byte[] tmData = new byte[dataSize*2];
+ for(int i=0;i<dataSize*2;)
+ {
+ tmData[i] = 0;
+ tmData[i+1] = 0;
+ tmData[i+2] = binData[i/2];
+ tmData[i+3] = binData[i/2+1];
+ i = i+SIZE_OF_INTEGER;
+ }
+ binData = tmData;
+ res = new RasMArrayInteger(new RasMInterval(domain));
+ break;
+
+ case RAS_INT:
+ case RAS_LONG:
+ //System.err.println("It's a integer array!");
+ res = new RasMArrayInteger(new RasMInterval(domain));
+ break;
+ case RAS_ULONG:
+ //System.err.println("It's a ulong array!");
+ byte[] tmpData = new byte[dataSize*2];
+ for(int i=0;i<dataSize*2;)
+ {
+ tmpData[i] = 0;
+ tmpData[i+1] = 0;
+ tmpData[i+2] = 0;
+ tmpData[i+3] = 0;
+ tmpData[i+4] = binData[i/2];
+ tmpData[i+5] = binData[i/2+1];
+ tmpData[i+6] = binData[i/2+2];
+ tmpData[i+7] = binData[i/2+3];
+ i = i+SIZE_OF_LONG;
+ }
+ binData = tmpData;
+ res = new RasMArrayLong(new RasMInterval(domain));
+ break;
+ case RAS_FLOAT:
+ //System.err.println("It's a float array!");
+ res = new RasMArrayFloat(new RasMInterval(domain));
+ break;
+ case RAS_DOUBLE:
+ //System.err.println("It's a double array!");
+ res = new RasMArrayDouble(new RasMInterval(domain));
+ break;
+ default:
+ //System.err.println("It's a GMArray!");
+ res = new RasGMArray(new RasMInterval(domain), pType.getSize());
+ //throw new RasTypeNotSupportedException(pType.getName());
+ }
+ // set array data
+ res.setArray(binData);
+ // set oid
+ res.setOID(roid);
+ //insert into result set
+ resultBag.add(res);
+ }
+
+ }
+ else throw new RasClientInternalException("RasHttpRequest","execute()","Type of MDD is no Base Type");
+ }
+
+ result = resultBag;
+
+ // close stream
+ in.close();
+
+ break;
+
+ // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ case RESPONSE_SKALARS:
+ //System.err.println("Skalar = 2");
+ // read Endianess
+ while(in.read(b1) == 0);
+ endianess = b1[0];
+
+ // read Collection Type
+ collType = RasUtils.readString(in);
+ RasType rt = new RasType();
+ try
+ {
+ rt = rt.getAnyType(collType);
+ //System.err.println("Colltype is " + rt);
+ }
+ catch(Exception e)
+ {
+ throw new RasTypeNotSupportedException(rt + " as RasCollectionType");
+ }
+ if(rt.getTypeID()!=RasGlobalDefs.RAS_COLLECTION)
+ throw new RasTypeNotSupportedException(rt + " as RasCollectionType");
+
+ // read NumberOfResults
+ while(in.available() < 4);
+ in.read(b4);
+ numberOfResults = RasUtils.ubytesToInt(b4,endianess);
+ //System.err.println("Number of results: " + numberOfResults);
+
+ // Initailize return-list
+ resultBag = new RasBag();
+
+ // do this for each result
+ for(int x = 0; x < numberOfResults; x++)
+ {
+ // read elementType
+ String elementType = RasUtils.readString(in);
+ RasType et = new RasType();
+ et = ((RasCollectionType)rt).getElementType();
+ //System.err.println("ElementType is " + et);
+
+ // read size of binData
+ while(in.available() < 4);
+ in.read(b4);
+ dataSize = RasUtils.ubytesToInt(b4,endianess);
+ //System.err.print("Size of BinData: ");
+ //System.err.println(dataSize);
+
+ // read binData
+ binData = new byte[dataSize];
+ readBytes = 0;
+ readBytesTmp = 0;
+ while( (readBytesTmp != -1) && (readBytes < dataSize) )
+ {
+ readBytesTmp = in.read(binData,readBytes,dataSize-readBytes);
+ readBytes += readBytesTmp;
+ /*
+ System.err.println("Read " + readBytesTmp +" Bytes ("
+ + readBytes + " Bytes overall)");
+ */
+ }
+ //System.err.println("Füge ein ..." + new String(binData));
+
+ ByteArrayInputStream bis = new ByteArrayInputStream(binData);
+ DataInputStream dis = new DataInputStream(bis);
+ // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ switch(et.getTypeID())
+ {
+ case RasGlobalDefs.RAS_MINTERVAL:
+ resultBag.add(new RasMInterval(new String(binData)));
+ break;
+ case RasGlobalDefs.RAS_SINTERVAL:
+ resultBag.add(new RasSInterval(new String(binData)));
+ break;
+ case RasGlobalDefs.RAS_POINT:
+ resultBag.add(new RasPoint(new String(binData)));
+ break;
+ case RasGlobalDefs.RAS_OID:
+ resultBag.add(new RasOID(new String(binData)));
+ break;
+ case RAS_BOOLEAN:
+ case RAS_BYTE:
+ case RAS_CHAR:
+ byte b = binData[0];
+ resultBag.add(new Byte(b));
+ break;
+ case RAS_DOUBLE:
+ double d = dis.readDouble();
+ resultBag.add(new Double(d));
+ break;
+ case RAS_FLOAT:
+ float f = dis.readFloat();
+ resultBag.add(new Float(f));
+ break;
+ case RAS_ULONG:
+ byte[] bu = new byte[8];
+ bu[0] = 0;
+ bu[1] = 0;
+ bu[2] = 0;
+ bu[3] = 0;
+ bu[4] = dis.readByte();
+ bu[5] = dis.readByte();
+ bu[6] = dis.readByte();
+ bu[7] = dis.readByte();
+ ByteArrayInputStream bis2 = new ByteArrayInputStream(bu);
+ DataInputStream dis2 = new DataInputStream(bis2);
+ long ul = dis2.readLong();
+ resultBag.add(new Long(ul));
+ break;
+ case RAS_LONG:
+ case RAS_INT:
+ int i = dis.readInt();
+ resultBag.add(new Integer(i));
+ break;
+ case RAS_USHORT:
+ int j = dis.readUnsignedShort();
+ resultBag.add(new Integer(j));
+ break;
+ case RAS_SHORT:
+ short s = dis.readShort();
+ resultBag.add(new Short(s));
+ break;
+ default:
+ throw new RasTypeNotSupportedException(et + " as ElementType ");
+ }
+ }
+ result = resultBag;
+
+ // close stream
+ in.close();
+ break;
+
+ //++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ case RESPONSE_ERROR:
+ Debug.talkCritical("RasHttpRequest.execute: execution failed. Error = 0");
+
+ // read Endianess
+ while(in.read(b1) == 0)
+ ;
+ endianess = b1[0];
+
+ // read Error Number
+ while(in.available() < 4)
+ ;
+ in.read(b4);
+ int errNo = RasUtils.ubytesToInt(b4,endianess);
+
+ // read Line Number
+ while(in.available() < 4)
+ ;
+ in.read(b4);
+ int lineNo = RasUtils.ubytesToInt(b4,endianess);
+
+ // read Column Number
+ while(in.available() < 4)
+ ;
+ in.read(b4);
+ int colNo = RasUtils.ubytesToInt(b4,endianess);
+
+ // read token
+ String token = RasUtils.readString(in);
+
+ Debug.talkCritical("RasHttpRequest.execute: Errno=" + errNo + ", lineNo=" + lineNo + ", colNo=" + colNo + ", Token=" + token);
+
+ throw new RasQueryExecutionFailedException(errNo,lineNo,colNo,token);
+ //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ case RESPONSE_INT:
+ // read Integer Value
+ //System.err.println("Now reading integer value...");
+ while(in.available() < 4);
+ in.read(b4);
+ result = new Integer(RasUtils.ubytesToInt(b4,endianess));
+ //System.err.println("Int Value is : " + result.getInt());
+ break;
+
+ //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ case RESPONSE_OID:
+ // read Values
+ String sys = RasUtils.readString(in);
+ String base = RasUtils.readString(in);
+ double d = in.readDouble();
+ //System.out.println(sys+base+"localOID als double = " + d);
+ resultBag = new RasBag();
+ resultBag.add(new RasOID(sys, base, d));
+ result = resultBag;
+ // close stream
+ in.close();
+ break;
+ default:
+ Debug.talkCritical( "RasHttpRequest.execute: illegal response type: " + resultType );
+ break;
+
+ }
+
+ con.disconnect(); // close connection to server -- PB 2003-jun-15
+ }
+ catch( MalformedURLException e )
+ {
+ Debug.leaveCritical( "RasHttpRequest.execute: leave. malformed URL: " + e.getMessage() );
+ throw new RasConnectionFailedException(MANAGER_CONN_FAILED, serverURL );
+ }
+ catch( IOException e )
+ {
+ Debug.leaveCritical( "RasHttpRequest.execute: leave. IO exception: " + e.getMessage() );
+ throw new RasClientInternalException("RasHttpRequest","execute()",e.getMessage());
+ }
+ catch( RasResultIsNoIntervalException e )
+ {
+ Debug.leaveCritical( "RasHttpRequest.execute: leave. result no interval: " + e.getMessage() );
+ throw new RasClientInternalException("RasHttpRequest","execute()",e.getMessage());
+ }
+
+ rcvTimer.stopTimer();
+ rcvTimer.print();
+
+ httpTimer.stopTimer();
+ httpTimer.print();
+
+ Debug.leaveVerbose( "RasHttpRequest.execute: leave. resultType=" + resultType );
+ } // execute()
+
+
+/**
+ * returns the result type (MDDColl, SkalarColl, Error, Integer)
+ */
+ public byte getResultType()
+ {
+ return resultType;
+ }
+
+/**
+ * returns the result of the query
+ */
+ public Object getResult()
+ {
+ return result;
+ }
+
+/**
+ * returns the result of the query as an Integer
+ */
+ public int getIntegerResult()
+ {
+ if (result != null)
+ {
+ Integer myInt = (Integer)result;
+ return myInt.intValue();
+ }
+ else
+ return 0;
+ }
+
+/**
+ * returns the result of the query as a DCollection
+ */
+ public DCollection getDCollection()
+ {
+ return (DCollection)result;
+ }
+
+/**
+ * returns the result of the query as a DBag
+ */
+ public DBag getDBag()
+ {
+ return (DBag)result;
+ }
+
+/**
+ * This method specifies the type of the client. The clientType determines
+ * how the results are coded
+ * and returned by the server. Default type and the only type supported right now
+ * is "RASCLIENT". The results are sent back using the "application/octet-stream"
+ * mime type and are coded as a byte stream as described in the class documentation.
+ * <P>
+ * Future versions will support other types like, for example, "BROWSER", where the
+ * results will be coded as standard HTTP-responses of certain mime types (for example
+ * "image/gif").
+ *
+ * @param clientType currently only "RASCLIENT" supported
+ */
+ public void setClientType ( String clientType )
+ {
+ client = clientType;
+ }
+
+/**
+ * main program for testing purposes
+ */
+
+/* BEGIN experimental ***********************
+ public static void main( String[] args )
+ {
+ String server = "localhost";
+ String port = "7001";
+ String base = "RASBASE";
+ String user = "rasguest";
+ String passwd = "rasguest";
+ String query = "select r from RAS_COLLECTIONNAMES as r";
+ int count = 1;
+
+ System.out.println( "Query test started." );
+
+ for (int i=args.length-1; i>=0; i--)
+ {
+ if (args[i].equals("--server"))
+ server = args[i+1];
+ if (args[i].equals("--port"))
+ port = args[i+1];
+ if (args[i].equals("--database"))
+ base = args[i+1];
+ if (args[i].equals("--user"))
+ user = args[i+1];
+ if (args[i].equals("--passwd"))
+ passwd = args[i+1];
+ if (args[i].equals("--query"))
+ query = args[i+1];
+ if (args[i].equals("--count"))
+ count = Integer.parseInt(args[i+1]);
+ }
+
+ try
+ {
+ RasImplementation myApp = new RasImplementation("http://"+server+":"+port);
+ myApp.setUserIdentification(user, passwd);
+
+ System.out.println( "opening database..." );
+ Database myDb = myApp.newDatabase();
+ myDb.open( base, Database.OPEN_READ_ONLY );
+
+ System.out.println( "starting transaction..." );
+ Transaction myTa = myApp.newTransaction();
+ myTa.begin();
+
+ String parameters = "Command=8&ClientID=1&QueryString=" + query;
+ String serverUrl = "http://" + server + ":" + 7102; // port;
+
+ for (int i = 0; i < count; i++)
+ {
+ System.out.println( "sending query #" + i + "..." );
+ execute( serverUrl, parameters );
+ }
+
+ System.out.println( "closing transaction..." );
+ myTa.abort();
+
+ System.out.println( "closing database..." );
+ myDb.close();
+ System.out.println( "all done." );
+
+ }
+ catch(Exception e)
+ {
+ System.err.println( e.getMessage() );
+ }
+
+ System.out.println( "Query test done." );
+
+ } // main()
+END experimental ***********************/
+}
+
+
+
diff --git a/java/rasj/clientcommhttp/RasUtils.class b/java/rasj/clientcommhttp/RasUtils.class
new file mode 100644
index 0000000..33c59a3
--- /dev/null
+++ b/java/rasj/clientcommhttp/RasUtils.class
Binary files differ
diff --git a/java/rasj/clientcommhttp/RasUtils.java b/java/rasj/clientcommhttp/RasUtils.java
new file mode 100644
index 0000000..1ffa049
--- /dev/null
+++ b/java/rasj/clientcommhttp/RasUtils.java
@@ -0,0 +1,110 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+package rasj.clientcommhttp;
+
+import java.io.*;
+import java.net.*;
+import java.lang.*;
+
+/**
+ *
+ * This class provides some useful methods for reading binary data from a stream
+ * or converting objects to a byte array for transmission.
+ *
+ */
+public final class RasUtils implements RasCommDefs
+{
+ static final String rcsid = "@(#)Package rasj.clientcommhttp, class RasUtils: $Header: /home/rasdev/CVS-repository/rasdaman/java/rasj/clientcommhttp/RasUtils.java,v 1.5 2003/12/10 21:04:26 rasdev Exp $";
+
+ public RasUtils()
+ {
+ }
+
+ /**
+ * This method is used for turning up to 4 unsigned bytes into signed integers.
+ *
+ * @param uBytes one to four Bytes which are interpreted as an unsigned Integer
+ * @param endianess determines the order of the bytes: 0 = bigendian, 1 = little endian
+ */
+ public static int ubytesToInt( byte[] uBytes, byte endianess )
+ {
+ int tmpi;
+ byte tmpb;
+ int retval = 0;
+
+ for( int i = 0; i < uBytes.length; i++ )
+ {
+ if( endianess == BIG_ENDIAN )
+ tmpb = uBytes[uBytes.length-i-1];
+ else
+ tmpb = uBytes[i];
+
+ tmpi = 0;
+ /* Byte < 0 */
+ if( (int)tmpb < 0 )
+ tmpi = 256 + tmpb;
+ else
+ tmpi = tmpb;
+
+ tmpi <<= (i*8);
+ retval += tmpi;
+ }
+ return retval;
+ }
+
+ /**
+ * Reads characters from a stream until a '\0' character is reached.
+ *
+ * @param in BufferedInputStream to be read from ( must have been initialized before! )
+ */
+ public static String readString( InputStream in )
+ throws IOException
+ {
+ byte b = (byte) '\0';
+ byte[] b1 = new byte[1];
+ String retval = "";
+
+ while(in.read(b1) == 0);
+ while(b1[0] != b)
+ {
+ retval =retval + (char)b1[0];
+ while(in.read(b1) == 0);
+ }
+ return retval;
+ }
+
+
+
+}
diff --git a/java/rasj/global/BenchmarkTimer.class b/java/rasj/global/BenchmarkTimer.class
new file mode 100644
index 0000000..75ec8de
--- /dev/null
+++ b/java/rasj/global/BenchmarkTimer.class
Binary files differ
diff --git a/java/rasj/global/BenchmarkTimer.java b/java/rasj/global/BenchmarkTimer.java
new file mode 100644
index 0000000..18c2638
--- /dev/null
+++ b/java/rasj/global/BenchmarkTimer.java
@@ -0,0 +1,109 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ * - keep consistent with rasj.global.BenchmarkTimer!
+ * </pre>
+ *********************************************************** */
+
+package rasj.global;
+
+import java.util.*;
+import java.lang.Float;
+
+public class BenchmarkTimer
+ {
+
+ private static final String srcFileVersion = "CVS version information: $Source: /home/rasdev/CVS-repository/rasdaman/java/rasj/global/BenchmarkTimer.java,v $ $Revision: 1.1 $";
+
+ private static final String OUTPUTPREFIX = "-- Timer ";
+
+ String text;
+ long startTime;
+ long endTime;
+ long totalTime;
+
+ public BenchmarkTimer(String t)
+ {
+ text = t==null ? "(no text)" : t;
+ reset();
+ }
+
+ public void reset()
+ {
+ startTime = 0;
+ endTime = 0;
+ totalTime = 0;
+ // Debug.talkVerbose( OUTPUTPREFIX + text + " reset.");
+ }
+
+ public void startTimer()
+ {
+ Debug.talkSparse( OUTPUTPREFIX + text + " started."); // level must be less than verbose to get crisp output
+ startTime = System.currentTimeMillis();
+ }
+
+ public void stopTimer()
+ {
+ endTime = System.currentTimeMillis();
+ totalTime += endTime;
+ // Debug.talkVerbose( OUTPUTPREFIX + text + " stopped.");
+ }
+
+ public long getTotalTime()
+ {
+ return totalTime;
+ }
+
+ public void print()
+ {
+ Debug.talkSparse( OUTPUTPREFIX + text + ": " + (totalTime-startTime) + " ms elapsed.");
+ // level must be less than verbose to get crisp output
+ }
+
+// ----------------------------------------------------------------------------------
+
+ /**
+ test routine for timer
+ */
+ public static void main(String a[])
+ {
+ Debug.enterVerbose( "Benchmark test start" );
+
+ BenchmarkTimer timer = new BenchmarkTimer("Test");
+
+ timer.startTimer();
+ for(int i=0;i<20000000;i++);
+ timer.stopTimer();
+
+ timer.print();
+
+ Debug.leaveVerbose( "Benchmark test stop" );
+ }
+ }
+
diff --git a/java/rasj/global/Debug.class b/java/rasj/global/Debug.class
new file mode 100644
index 0000000..7c07ae5
--- /dev/null
+++ b/java/rasj/global/Debug.class
Binary files differ
diff --git a/java/rasj/global/Debug.java b/java/rasj/global/Debug.java
new file mode 100644
index 0000000..408c36b
--- /dev/null
+++ b/java/rasj/global/Debug.java
@@ -0,0 +1,229 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ * <pre>
+ *
+ * PURPOSE: generate debug output into servlet log
+ * Methods of this static class perform debugging output into
+ * the servlet log (usually /opt/jakarta/logs/servlet.log).
+ * For entering a method to be traced, logging indent level is
+ * increased; the logging methods for leaving a method decrease
+ * indent, and the trace methods inbetween leave indentation unchanged.
+ * [Needless to say that both statically and dynamically the number
+ * of enters and leaves should match.]
+ * Four trace levels are provided, intended for reporting increasingly
+ * verbose (i.e., for decreasingly dangerous events):
+ * critical (always logged),
+ * warning (default level),
+ * sparse,
+ * verbose.
+ * For each combination of enter/inside/leave of a method and trace
+ * levels corresponding report functions are provided.
+ * Finally, the debug level can be changed any time with
+ * setDebugLevel().
+ * Initialisation requires passing the servlet object to gain an
+ * output stream to write to.
+ *
+ *
+ * COMMENTS:
+ * - keep consistent with rasogc.Debug !!!
+ * - documentation to be done
+ * </pre>
+ ************************************************************/
+
+package rasj.global;
+
+import java.lang.System;
+
+/**
+ * Methods of this static class perform debugging output into
+ * the servlet log (usually /opt/jakarta/logs/servlet.log).
+ * For entering a method to be traced, logging indent level is
+ * increased; the logging methods for leaving a method decrease
+ * indent, and the trace methods inbetween leave indentation unchanged.
+ * [Needless to say that both statically and dynamically the number
+ * of enters and leaves should match.]
+ * <P>
+ * Four trace levels are provided, intended for reporting increasingly
+ * verbose (i.e., for decreasingly dangerous events):
+ * <UL>
+ * <LI>critical (always logged),
+ * <LI>warning (default level),
+ * <LI>sparse,
+ * <LI>verbose.
+ * </UL>
+ * For each combination of enter/inside/leave of a method and trace
+ * levels corresponding report functions are provided.
+ * Finally, the debug level can be changed any time with
+ * setDebugLevel().
+ * <P>
+ * Initialisation requires passing the servlet object to gain an
+ * output stream to write to.
+ * <P>
+ *
+ * @version $Revision: 1.2 $
+ *
+ */
+
+public class Debug
+ {
+ static final String rcsid = "@(#)Package rasj.global, class Debug: $Header: /home/rasdev/CVS-repository/rasdaman/java/rasj/global/Debug.java,v 1.2 2006/01/19 18:24:16 rasdev Exp $";
+
+ //
+ // debug threshold levels (constant defs):
+ //
+
+ /** log only critical events **/
+ public static final int CRITICAL_LEVEL = 0; // print always
+
+ /** log also warnings which do not really impede processing **/
+ public static final int WARNING_LEVEL = 1;
+
+ /** log also occasional output interesting for debugging **/
+ public static final int SPARSE_LEVEL = 2;
+
+ /** log all information available to aid debugging **/
+ public static final int VERBOSE_LEVEL = 3;
+
+
+ /**
+ * debug threshold default
+ **/
+ public static final int DEFAULT_LEVEL = WARNING_LEVEL;
+
+ /**
+ * debug threshold - only levels below it are displayed:
+ **/
+ private static int debugThreshold = DEFAULT_LEVEL;
+
+ /**
+ unit of indentation to display calling hierarchy
+ **/
+ private static final String INDENT = ". ";
+
+ /**
+ * indentation counter
+ **/
+ private static int indentLevel = 0;
+
+ /**
+ * set debug threshold to control further output
+ **/
+ public static void setDebugThreshold(int level)
+ {
+ if (level >= 0)
+ {
+ debugThreshold = level;
+ System.err.println( "Debug::setDebugThreshold: setting debug level to " + level );
+ }
+ else
+ System.err.println( "Debug::setDebugThreshold: ignoring illegal debug level value: " + level );
+ }
+
+ /**
+ the following set of methods logs for entering/within/leaving a method.
+ Entering increases printing indent level, talk leaves it unchanged, and leaving decreases indentation.
+ these choices are crossed with the debug levels to achieve handy, short calls.
+ **/
+
+ /** method enter msg, output only with critical level **/
+ public static void enterCritical( String what ) { enter( CRITICAL_LEVEL, what ); }
+ /** method enter msg, output only with warning level **/
+ public static void enterWarning( String what ) { enter( WARNING_LEVEL, what ); }
+ /** method enter msg, output only with sparse level **/
+ public static void enterSparse( String what ) { enter( SPARSE_LEVEL, what ); }
+ /** method enter msg, output only with verbose log level **/
+ public static void enterVerbose( String what ) { enter( VERBOSE_LEVEL, what ); }
+
+ /** method leave msg, output only with critical level **/
+ public static void leaveCritical( String what ) { leave( CRITICAL_LEVEL, what ); }
+ /** method leave msg, output only with warning level **/
+ public static void leaveWarning( String what ) { leave( WARNING_LEVEL, what ); }
+ /** method leave msg, output only with sparse level **/
+ public static void leaveSparse( String what ) { leave( SPARSE_LEVEL, what ); }
+ /** method leave msg, output only with verbose log level **/
+ public static void leaveVerbose( String what ) { leave( VERBOSE_LEVEL, what ); }
+
+ /** method inside msg, output only with critical level **/
+ public static void talkCritical( String what ) { talk( CRITICAL_LEVEL, what ); }
+ /** method inside msg, output only with warning level **/
+ public static void talkWarning( String what ) { talk( WARNING_LEVEL, what ); }
+ /** method inside msg, output only with sparse level **/
+ public static void talkSparse( String what ) { talk( SPARSE_LEVEL, what ); }
+ /** method inside msg, output only with verbose log level **/
+ public static void talkVerbose( String what ) { talk( VERBOSE_LEVEL, what ); }
+
+ /**
+ * writes messages to the "standard" error log stream, increments indentation
+ **/
+ private static void enter(int level, String what)
+ {
+ StringBuffer s = new StringBuffer(100); // to hold indent prefix
+
+ if(level <= debugThreshold)
+ {
+ indentLevel++; // indent one more to the right
+ s.append( "rasj[" + Integer.toString(level) + "] " ); // document log level
+ for (int i=0; i<indentLevel; i++)
+ s.append( INDENT );
+ s.append( what );
+ System.err.println( s );
+ }
+ }
+
+
+ /**
+ * writes messages to the "standard" error log stream, decrements indentation
+ **/
+ static void leave(int level, String what)
+ {
+ StringBuffer s = new StringBuffer(100); // to hold indent prefix
+
+ if(level <= debugThreshold)
+ {
+ s.append( "rasj[" + Integer.toString(level) + "] " ); // document log level
+ for (int i=0; i<indentLevel; i++)
+ s.append( INDENT );
+ s.append( what );
+ System.err.println( s );
+ indentLevel--; // indent one less, go left
+ }
+ }
+
+ /**
+ * writes messages to the "standard" error log stream; indentation unchanged
+ **/
+ static void talk(int level, String what)
+ {
+ StringBuffer s = new StringBuffer(100); // to hold indent prefix
+
+ if(level <= debugThreshold)
+ {
+ s.append( "rasj[" + Integer.toString( level) + "] " ); // document log level
+ for (int i=0; i<indentLevel; i++)
+ s.append( INDENT );
+ s.append( what );
+ System.err.println( s );
+ }
+ }
+ }
diff --git a/java/rasj/global/Makefile b/java/rasj/global/Makefile
new file mode 100644
index 0000000..a658fdd
--- /dev/null
+++ b/java/rasj/global/Makefile
@@ -0,0 +1,86 @@
+# -*-Makefile-*- (for Emacs)
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>. # Top Level makefile. This points to the various modules that have to be build
+# and/or deployed
+#
+# MAKEFILE FOR:
+# package RasJ.global
+#
+# COMMENTS:
+# - FIXME: errtxts has been i18nalized, reflect it in the RasError code!
+#
+##################################################################
+######################### Definitions ############################
+
+# standard include with general options
+include $(RMANBASE)/Makefile.inc
+
+# error text file
+ERRTXT_FILE = $(RMANBASE)/bin/errtxts_en
+
+SRCS = RasErrorTexts.java RasGlobalDefs.java Debug.java BenchmarkTimer.java
+OBJS = ${SRCS:%.java=%.class} Version.class
+MISCCLEAN = *.class Version.java
+
+# directory where HTML documentation is created
+DOCDIR := $(DOCBASE)/java/rasj/global
+
+########################### Targets ##############################
+
+# compile everything
+.PHONY : all
+all: Version.java errortexts
+ $(MAKE) $(OBJS)
+
+.PHONY : errortexts
+# create array of error messages in class RasErrorTexts
+errortexts:
+ if (test -f $(ERRTXT_FILE)) \
+ then \
+ grep "\^E\^" $(ERRTXT_FILE) \
+ | sed -e '/^#/ d' \
+ | sed -e 's+\^E\^+:+g' \
+ | sed -e 's+^+"+g' \
+ | sed -e 's+$$+\",+g' > tmpfile; \
+ cat RasErrorTexts.template1 tmpfile RasErrorTexts.template2 > RasErrorTexts.java; \
+ else \
+ echo "Error: errtxts file $(ERRTXT_FILE) not found."; \
+ exit 1; \
+ fi
+ -rm tmpfile
+
+# always generate to have an up-to date version & generation time info:
+.PHONY: Version.java
+Version.java:
+ @ sed s/%%DATE%%/`date +%Y-%b-%d`/ <Version.java.template \
+ | sed s/%%VERSION%%/$(RMANVERSIONNAME)/ \
+ | sed "s/%%GENERATION_DATE%%/`date`/" >Version.java
+
+# delete all files
+.PHONY: clean
+clean:
+ -rm -f $(SRCS) $(MISCCLEAN)
+
+############################ Dependencies #######################
+# general rules
+include $(RMANBASE)/Makefile.rel
+
diff --git a/java/rasj/global/Makefile.dep b/java/rasj/global/Makefile.dep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/java/rasj/global/Makefile.dep
diff --git a/java/rasj/global/RasErrorTexts.class b/java/rasj/global/RasErrorTexts.class
new file mode 100644
index 0000000..b3e0cd7
--- /dev/null
+++ b/java/rasj/global/RasErrorTexts.class
Binary files differ
diff --git a/java/rasj/global/RasErrorTexts.java b/java/rasj/global/RasErrorTexts.java
new file mode 100644
index 0000000..c208a4c
--- /dev/null
+++ b/java/rasj/global/RasErrorTexts.java
@@ -0,0 +1,313 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * first part of three constituting RasErrorTexts.java:
+ * - part 1: Java src
+ * - part 2: generated from errtxts file
+ * - part 3: Java src
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+package rasj.global;
+
+import java.io.*;
+
+// This file is created automatically - do not edit unless allowed explicitly (look for
+// a message "changes can only be made after here")!
+
+public abstract class RasErrorTexts
+{
+
+ public static String[] errorMessages = {
+
+// end of RasErrorTexts.template1
+"66:Exception: Memory allocation failed.",
+"100:Exception: Internal error: DL parse error.",
+"200:Exception: The result is no point.",
+"201:Exception: The result is no interval.",
+"202:Exception: Index violation ( index range [$low,$high], index $index ).",
+"203:Exception: Dimension mismatch between $dim1 and $dim2.",
+"204:Exception: Stream initialization overflow.",
+"205:Exception: Result is no cell.",
+"206:Serialisable exception r_Ebase_dbms: error in base DBMS.",
+"207:Internal client exception in class $class, method $method: $code.",
+"208:Exception: Access type $aType does not fit base type $bType.",
+"209:Exception: RasType $type is unknown.",
+"210:Exception: Base type $type is not supported yet.",
+"211:Exception: Database is not open.",
+"212:Exception: RPC layer connection to RasDaMan failed.",
+"213:Exception: Wrong URL format (should be http://address:port)",
+"214:Exception: Illegal java long value $val for server base type ULong.",
+"215:Exception: Illegal java integer value $val for server base type UShort.",
+"216:Exception: System collection is not writable.",
+"217:Exception: System collection has no OID.",
+"218:Exception: Conversion format is not supported.",
+"219:Exception: The specified tile size is smaller than the length of the base type of the mdd object.",
+"220:Exception: The tiling strategy in the storage layout is not compatible with the marray.",
+"221:Exception: The domain passed as an argument was not initialised correctly (dimension is 0).",
+"222:Exception: The type name or type structure does not represent a marray type.",
+"223:Exception: The rc index requires a marray type that has a specified domain (with fixed borders in all dimensions).",
+"224:Exception: The tile configuration is incompatible to the marray domain.",
+"229:Exception: The parameterized query has invalid parameter format.",
+"230:Exception: The r_Object was already assigned a type.",
+"231:Exception: The Marray has no base type.",
+"232:Exception: The interval has at least one open bound.",
+"233:Exception: The intervals don't have the same dimension.",
+"234:Exception: The string passed to the tiling object was not correct.",
+"235:Exception: Connection to server already closed.",
+"236:Exception: Error in compression engine",
+"237:Exception: Client communication failure",
+"238:Exception: Base type not supported by conversion/compression module.",
+"239:Exception: Standard overlay using types larger than 16 bytes is not supported.",
+"240:Exception: Insert into a RC index is not allowed.",
+"241:Exception: No tiling defined at that region. Update not possible.",
+"300:Parsing error $errorNo in line $lineNo, column $columnNo: Unexpected name $token.",
+"301:Parsing error $errorNo in line $lineNo, column $columnNo, token $token: All cell values of an MDD must be of the same type. ",
+"302:Parsing error $errorNo in line $lineNo, column $columnNo, token $token: Number of cells specified does not match the number of cells of the given spatial domain.",
+"303:Parsing error $errorNo in line $lineNo, column $columnNo, token $token: OId is not valid.",
+"308:Parsing error: Unexpected end of query.",
+"309:Parsing error: Unknown error.",
+"310:Lexical analysing error $errorNo in line $lineNo, column $columnNo: Unexpected characters $token.",
+"311:Parsing error $errorNo in line $lineNo, column $columnNo, token $token: Complex constructor must have both arguments of the same type (i.e. float or double). ",
+"312:Parsing error $errorNo in line $lineNo, column $columnNo, token $token: Variable already defined. ",
+"313:Parsing error $errorNo in line $lineNo, column $columnNo, token $token: Only constant interval bounds allowed. ",
+"330:Preprocessing error $errorNo in line $lineNo, column $columnNo: Unexpected name $token: ",
+"331:Preprocessing error $errorNo in line $lineNo, column $columnNo, token $token: attempt to redefine function.",
+"332:Preprocessing error $errorNo in line $lineNo, column $columnNo, token $token: number of actual arguments for the called function differs from the number of formal arguments.",
+"333:Preprocessing error $errorNo in line $lineNo, column $columnNo, token $token: the called function name is ambiguous, try the full qualified name.",
+"349:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operand out of range.",
+"350:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: General. ",
+"351:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Spatial domains of the binary induce operands are incompatible.",
+"352:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operand types are incompatible.",
+"353:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operand of quantifier must be multidimensional.",
+"354:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operand of quantifier must be of type r_Marray<d_Boolean>.",
+"355:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Collection name is unknown.",
+"356:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Specified domain does not intersect with spatial domain of MDD.",
+"357:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Variable is unknown.",
+"358:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Projection operand is not of type r_Marray<T>.",
+"359:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Result of the where clause must be of type boolean.",
+"360:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Type of operand is not supported.",
+"361:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Multiple query targets are not supported.",
+"362:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Specified domain dimensionality does not equal defined dimensionality of MDD.",
+"363:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Cell base types of binary induce operation are incompatible.",
+"364:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Cell base type and scalar type of binary induce operation are incompatible.",
+"365:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Scalar types of binary operation are incompatible.",
+"366:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Cell base type of unary induce operation is not supported.",
+"367:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Scalar type of unary operation is not supported.",
+"368:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Cell base type for induced dot operation must be complex.",
+"369:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Scalar type for dot operation must be complex.",
+"370:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Struct selector is not valid.",
+"371:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Retrieval query must start with a SELECT statement.",
+"372:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Update query must start with an INSERT, UPDATE, DELETE, DROP or CREATE statement.",
+"373:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Unsatisfied MDD constant parameter.",
+"380:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Data type can not be converted to selected data exchange format.",
+"381:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Error in convertor of the selected data exchange format.",
+"382:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Unknown conversion format.",
+"383:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Parameter of oid function must be a persistent object of type MDD.",
+"384:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: OId is not valid.",
+"385:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operation is not supported on strings.",
+"386:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Base name of oid is not matching the currently opened one.",
+"387:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: System name of oid is not matching the currently used one.",
+"388:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Interval bound must be either an integer expression or an asterisk.",
+"389:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: No interval (in case of fixed bounds, the upper one can not be smaller than the lower one).",
+"390:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Minterval dimension specifications must be either of type interval or integer.",
+"391:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Spatial operation must be either of type minterval, point, or integer.",
+"393:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operand of operation lo/hi must be of type interval.",
+"394:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operation lo/hi can not be used for an open bound.",
+"395:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operand of function sdom() must be of type MDD.",
+"396:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Selection operation is not supported on this data type.",
+"397:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operand of minterval selection must be of type integer.",
+"398:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Index for minterval selection is out of range.",
+"399:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operand of point selection must be of type integer.",
+"400:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Domain of MDD constructor has to be defined.",
+"401:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Can not evaluate domain expression to an minterval.",
+"402:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Projected cell is not defined.",
+"403:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Binary operation is not supported on these data types.",
+"404:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Type of cell expression is not supported.",
+"405:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: First operand of shift function must be of type MDD.",
+"406:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Second operand of shift function must be of type Point.",
+"407:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Dimensionality of MDD and point expression are not matching.",
+"408:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Second operand of shift function must be a constant expression.",
+"409:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Spatial domain shift of open bounds is not supported.",
+"410:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operand of point expression must be of type integer.",
+"411:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Index for point selection is out of range.",
+"412:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Value expression must be either of type atomic or complex.",
+"413:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Condition expression must be of type boolean.",
+"415:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operand of count_cells must be of type r_Marray<d_Boolean>.",
+"416:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: First operand of scale function must be of type MDD.",
+"417:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Second operand of scale function must be either of type Point, Integer or Float.",
+"418:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Second operand of bit function must be of integral type.",
+"419:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Could not scale the domain.",
+"420:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Extend operation with open bounds is not supported.",
+"421:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Target interval of extend operation does not cover MDD to be extended.",
+"422:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Second operand of extend function must be an minterval.",
+"499:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Language feature is not supported.",
+"510:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: The argument is outside the function domain.",
+"511:Execution error $errorNo in line $lineNo, column $columnNo, near token $token: The function result exceeds the allowed range.",
+"700:Admin error: General error creating RasDaMan database.",
+"701:Admin error: Error creating table in tablespace RAS_DB_SCHEMA.",
+"702:Admin error: Error inserting into table RAS_COUNTERS.",
+"703:Admin error: Error creating table in tablespace RAS_DB_BLOB.",
+"704:Admin error: Error creating index in tablespace RAS_DB_INDEX.",
+"705:Admin error: Error inserting into table RAS_BASETYPENAMES.",
+"706:Admin error: Error creating table in default tablespace.",
+"707:Admin error: Error on COMMIT creating RasDaMan database.",
+"708:Admin error: Database to be created already exists.",
+"800:RasManager Error: Could not connect to RasServer $url.",
+"801:RasManager Error: System overloaded, please try again later.",
+"802:RasManager Error: Access denied, incorrect user/password.",
+"803:RasManager Error: Access denied, no permission for operation.",
+"804:RasManager Error: Access denied, capability refused.",
+"805:RasManager Error: No suitable servers started, call administrator.",
+"806:RasManager Error: Write transaction in progress, please retry again later.",
+"807:RasManager Error: Requested database unknown.",
+"808:RasManager Error: Request format error.",
+"820:RNP Error: First parameter has to be the clientID (clientcomm internal).",
+"821:RNP Error: Client ID invalid, probably a timeout occurred.",
+"822:RNP Error: Unknown command in client request.",
+"830:base DBMS Error: Cannot connect to base DBMS server (invalid connect string in rasmgr config file?).",
+"900:Evaluation error $errorNo in line $lineNo, column $columnNo, near token $token: Type in typedef definition not supported.",
+"901:Evaluation error $errorNo in line $lineNo, column $columnNo, near token $token: Set template type has to be a type reference.",
+"902:Evaluation error $errorNo in line $lineNo, column $columnNo, near token $token: Type reference not found.",
+"903:Evaluation error $errorNo in line $lineNo, column $columnNo, near token $token: MDD base type has to be a type reference or an atomic type.",
+"904:Evaluation error $errorNo in line $lineNo, column $columnNo, near token $token: MDD type must have a domain specification.",
+"905:Evaluation error $errorNo in line $lineNo, column $columnNo, near token $token: Struct type name exists already.",
+"906:Evaluation error $errorNo in line $lineNo, column $columnNo, near token $token: MDD type name exists already.",
+"907:Evaluation error $errorNo in line $lineNo, column $columnNo, near token $token: Set type name exists already.",
+"950:Update error $errorNo in line $lineNo, column $columnNo, near token $token: Update target must be an iterator variable.",
+"951:Update error $errorNo in line $lineNo, column $columnNo, near token $token: Update source must be an expression resulting in an r_Marray<>.",
+"952:Update error $errorNo in line $lineNo, column $columnNo, near token $token: Update base type does not match MDD base type.",
+"953:Update error $errorNo in line $lineNo, column $columnNo, near token $token: Update domain is not within MDD definition domain.",
+"954:Update error $errorNo in line $lineNo, column $columnNo, near token $token: Update target expression must be an assignable value (l-value).",
+"955:Update error $errorNo in line $lineNo, column $columnNo, near token $token: Collection name exists already.",
+"956:Update error $errorNo in line $lineNo, column $columnNo, near token $token: Unknown collection type.",
+"957:Update error $errorNo in line $lineNo, column $columnNo, near token $token: Unknown collection name.",
+"958:Update error $errorNo in line $lineNo, column $columnNo, near token $token: Allocation of new oid failed.",
+"959:Update error $errorNo in line $lineNo, column $columnNo, near token $token: MDD and collection types are incompatible.",
+"960:Update error $errorNo in line $lineNo, column $columnNo, near token $token: Insert expression must be of type MDD.",
+"961:Update error $errorNo in line $lineNo, column $columnNo, near token $token: Update domain must be of type Minterval.",
+"962:Update error $errorNo in line $lineNo, column $columnNo, near token $token: Number of update intervals must match source dimensionaltiy.",
+"963:Update error $errorNo in line $lineNo, column $columnNo, near token $token: Update domain dimensionality must match target MDD dimensionaltiy.",
+"964:Update error $errorNo in line $lineNo, column $columnNo, near token $token: Type is not persistent.",
+"965:Update error $errorNo: MDD type $token unknown.",
+"966:Update error $errorNo: MDD type is missing.",
+"1000:General error: RasDaMan tables inconsistent.",
+"1001:General error: RasDaMan server incompatible with database.",
+"1002:General error: Blob with zero length encountered.",
+"1003:General error: Tile container for TC index not found.",
+"1004:General error: Index of MDD Object is not defined.",
+"1005:General error: Storage structure of MDD Object is not defined.",
+"1006:General error: Unknown index type requested.",
+"1007:General error: Illegal index type requested.",
+"1008:General error: No valid collection type passed to MDD collection.",
+"1009:General error: MDD object not valid or not persistent.",
+"1010:General error: No valid MDD type passed to MDD object.",
+"1011:General error: An illegal state has been reached. This is caused by a compiler bug or a library bug.",
+"1012:General error: Invalid collection type passed to MDD collection.",
+"1013:General error: The name of the type is too long.",
+"1014:General error: Invalid name of the object, should contain only [a-zA-Z0-9_]",
+"2000:Internal error: There seems to be another database open.",
+"2001:Internal error: Invalid OId type encountered.",
+"2002:Internal error: Entry in user defined type not found.",
+"2003:Internal error: Entry in user defined type out of bounds.",
+"2004:Internal error: Transient index used instead of persistent index.",
+"2005:Internal error: Index returned tiles multiple times.",
+"2006:Internal error: Tile was not inserted into index.",
+"2007:Internal error: Transient index access out of bounds.",
+"2008:Internal error: MDD object exists multiple times in cache.",
+"2009:Internal error: Some tile(s) were not inserted into the MDD object.",
+"2010:Internal error: A conversion module returned an incorrect base type.",
+"2011:Internal error: The collection type has no element type.",
+"2012:Internal error: The marray type has no base type.",
+"2013:Internal error: The property has no base type.",
+"2014:Internal error: The scalar was passed a NULL value.",
+"2015:Internal error: The index node that had to be split was not found in its parent.",
+"2016:Internal error: The index found more cells than allowed.",
+"2017:Internal error: The storage layout is incompatible with the index entries.",
+"2018:Internal error: Object does not support swapping.",
+"2019:Internal error: Error encountered during swapping.",
+"2020:Internal error: Binary export for object is not supported.",
+"2021:Internal error: Binary import for object is not supported.",
+"2022:Internal error: Operands and result types don't match.",
+"3000:Format conversion error: DEM area does not contain any non-null value, empty result generated.",
+"10000:Unexpected internal server error.",
+/** ***********************************************************
+ * <pre>
+ *
+ * SOURCE: RasErrorTexts.template2
+ *
+ * PACKAGE: rasj.global
+ * CLASS: RasErrorTexts
+ *
+ * PURPOSE:
+ * third part of three constituting RasErrorTexts.java:
+ * - part 1: Java src
+ * - part 2: generated from errtxts file
+ * - part 3: Java src
+ *
+ *
+ * </pre>
+ *********************************************************** */
+
+// end of error code array, start of RasErrorTexts.template2
+
+ "" // this last, empty string is needed because the last one, generated from errtxts, has a "," at the end
+ };
+
+ public static String getErrorMessage( int errNo )
+ {
+ StringBuffer buf;
+ String prefix = String.valueOf(errNo)+":";
+ int index = 0;
+ String retVal = null;
+
+ while(index < errorMessages.length-1) // last string is empty, see above
+ {
+ if(errorMessages[index].startsWith(prefix))
+ {
+ buf = new StringBuffer(errorMessages[index]);
+ index = errorMessages[index].indexOf(":");
+ buf.delete(0,index+1);
+ retVal = buf.toString();
+ index = errorMessages.length+1;
+ }
+ else
+ index++;
+
+ }
+ if(retVal == null)
+ retVal = "No error message available for error number " + errNo + ".";
+
+ return retVal;
+ }
+
+}
+
+
diff --git a/java/rasj/global/RasErrorTexts.template1 b/java/rasj/global/RasErrorTexts.template1
new file mode 100644
index 0000000..ce36ab7
--- /dev/null
+++ b/java/rasj/global/RasErrorTexts.template1
@@ -0,0 +1,50 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * first part of three constituting RasErrorTexts.java:
+ * - part 1: Java src
+ * - part 2: generated from errtxts file
+ * - part 3: Java src
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+package rasj.global;
+
+import java.io.*;
+
+// This file is created automatically - do not edit unless allowed explicitly (look for
+// a message "changes can only be made after here")!
+
+public abstract class RasErrorTexts
+{
+
+ public static String[] errorMessages = {
+
+// end of RasErrorTexts.template1
diff --git a/java/rasj/global/RasErrorTexts.template2 b/java/rasj/global/RasErrorTexts.template2
new file mode 100644
index 0000000..03c4ac5
--- /dev/null
+++ b/java/rasj/global/RasErrorTexts.template2
@@ -0,0 +1,72 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * third part of three constituting RasErrorTexts.java:
+ * - part 1: Java src
+ * - part 2: generated from errtxts file
+ * - part 3: Java src
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+// end of error code array, start of RasErrorTexts.template2
+
+ "" // this last, empty string is needed because the last one, generated from errtxts, has a "," at the end
+ };
+
+ public static String getErrorMessage( int errNo )
+ {
+ StringBuffer buf;
+ String prefix = String.valueOf(errNo)+":";
+ int index = 0;
+ String retVal = null;
+
+ while(index < errorMessages.length-1) // last string is empty, see above
+ {
+ if(errorMessages[index].startsWith(prefix))
+ {
+ buf = new StringBuffer(errorMessages[index]);
+ index = errorMessages[index].indexOf(":");
+ buf.delete(0,index+1);
+ retVal = buf.toString();
+ index = errorMessages.length+1;
+ }
+ else
+ index++;
+
+ }
+ if(retVal == null)
+ retVal = "No error message available for error number " + errNo + ".";
+
+ return retVal;
+ }
+
+}
+
+
diff --git a/java/rasj/global/RasGlobalDefs.class b/java/rasj/global/RasGlobalDefs.class
new file mode 100644
index 0000000..63224d6
--- /dev/null
+++ b/java/rasj/global/RasGlobalDefs.class
Binary files differ
diff --git a/java/rasj/global/RasGlobalDefs.java b/java/rasj/global/RasGlobalDefs.java
new file mode 100644
index 0000000..51ea769
--- /dev/null
+++ b/java/rasj/global/RasGlobalDefs.java
@@ -0,0 +1,173 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+package rasj.global;
+
+public interface RasGlobalDefs
+{
+ static final String rcsid = "@(#)Package rasj, class RasGlobalDefs: $Header: /home/rasdev/CVS-repository/rasdaman/java/rasj/global/RasGlobalDefs.java,v 1.23 2006/01/17 23:49:11 rasdev Exp $";
+
+ // rasj version string (similar to executables startup message) -- can't we get rasdaman version info automatically?
+ // static final String RASJ_VERSION = "rasj: rasdaman Java API. rasdaman v5.1revC -- generated Mit Jun 25 10:46:59 CEST 2003.";
+ static final String RASJ_VERSION = "rasj: rasdaman Java API. rasdaman " + Version.VERSION + " -- generated " + Version.DATE + ".";
+
+ // fastscale predefines; FIXME: should be used dynamically! -- PB 2003-jun-25
+ static final int NUM_FAST_PRE_SCALE = 8;
+ static final double[] FAST_PRE_SCALE_FACTORS = {1.0/2, 1.0/4, 1.0/8, 1.0/16, 1.0/32, 1.0/64, 1.0/128, 1.0/256};
+ static final String[] FAST_PRE_SCALE_SUFFIXES = {"_1", "_2", "_3", "_4", "_5", "_6", "_7", "_8"};
+
+ //RasDataFormat
+ static final int RAS_ARRAY = 0; // no compression, row-major memory representation
+ static final int RAS_TIFF = RAS_ARRAY + 1; // TIFF format
+ static final int RAS_JPEG = RAS_TIFF + 1; // JPEG format
+ static final int RAS_HDF = RAS_JPEG + 1; // HDF format
+ static final int RAS_PNG = RAS_HDF + 1; // PNG format
+ static final int RAS_ZLIB = RAS_PNG + 1; // ZLIB format
+ static final int RAS_AUTO_COMPRESSION = RAS_ZLIB + 1; // automatic compression
+
+ //RasTypeID
+ static final int RAS_UNKNOWN = 0;
+ static final int RAS_MARRAY = RAS_UNKNOWN + 1;
+ static final int RAS_COLLECTION = RAS_MARRAY + 1;
+ static final int RAS_SINTERVAL = RAS_COLLECTION + 1;
+ static final int RAS_MINTERVAL = RAS_SINTERVAL + 1;
+ static final int RAS_POINT = RAS_MINTERVAL + 1;
+ static final int RAS_OID = RAS_POINT + 1;
+ static final int RAS_STRUCTURE = RAS_OID + 1;
+ static final int RAS_RGB = RAS_STRUCTURE + 1;
+ static final int RAS_INT = RAS_RGB + 1;
+ static final int RAS_SHORT = RAS_INT + 1;
+ static final int RAS_USHORT = RAS_SHORT + 1;
+ static final int RAS_LONG = RAS_USHORT + 1;
+ static final int RAS_ULONG = RAS_LONG + 1;
+ static final int RAS_FLOAT = RAS_ULONG + 1;
+ static final int RAS_DOUBLE = RAS_FLOAT + 1;
+ static final int RAS_BOOLEAN = RAS_DOUBLE + 1;
+ static final int RAS_BYTE = RAS_BOOLEAN + 1;
+ static final int RAS_CHAR = RAS_BYTE + 1;
+ static final int RAS_STRING = RAS_CHAR + 1;
+ static final int RAS_COMPLEX1 = RAS_STRING +1;
+
+
+ //object status
+ public static final int NO_STATUS = 0;
+ public static final int DELETED = NO_STATUS + 1;
+ public static final int CREATED = DELETED + 1;
+ public static final int MODIFIED = CREATED + 1;
+ public static final int READ = MODIFIED + 1;
+ public static final int TRANSIENT = READ + 1;
+
+ // java BaseType sizes
+ public final int SIZE_OF_INTEGER = 4;
+ public final int SIZE_OF_LONG = 8;
+ public final int SIZE_OF_FLOAT = 4;
+ public final int SIZE_OF_BYTE = 1;
+ public final int SIZE_OF_SHORT = 2;
+ public final int SIZE_OF_CHAR = 2;
+ public final int SIZE_OF_BOOLEAN = 1;
+ public final int SIZE_OF_DOUBLE = 8;
+
+ // RasPrimitiveType sizes
+ public final int SIZE_OF_RAS_LONG = 4;
+ public final int SIZE_OF_RAS_ULONG = 4;
+ public final int SIZE_OF_RAS_FLOAT = 4;
+ public final int SIZE_OF_RAS_BYTE = 1;
+ public final int SIZE_OF_RAS_SHORT = 2;
+ public final int SIZE_OF_RAS_USHORT = 2;
+ public final int SIZE_OF_RAS_CHAR = 1;
+ public final int SIZE_OF_RAS_BOOLEAN = 1;
+ public final int SIZE_OF_RAS_DOUBLE = 8;
+
+ // error codes - these match the errtxts file
+ final static int INTERNAL_DL_PARSE_EXCEPTION = 100;
+
+ final static int RESULT_IS_NO_INTERVAL = 201;
+ final static int INDEX_OUT_OF_BOUNDS = 202;
+ final static int DIMENSION_MISMATCH = 203;
+ final static int STREAM_INPUT_OVERFLOW = 204;
+ final static int RESULT_IS_NO_CELL = 205;
+ final static int BASE_DBS_ERROR = 206;
+ final static int INTERNAL_CLIENT_ERROR = 207;
+ final static int TYPE_INVALID = 208;
+ final static int TYPE_UNKNOWN = 209;
+ final static int TYPE_NOT_SUPPORTED = 210;
+ final static int DB_NOT_OPEN = 211;
+ final static int DB_CONN_FAILED = 212;
+ final static int URL_FORMAT_ERROR = 213;
+ final static int ILLEGAL_ULONG_VALUE = 214;
+ final static int ILLEGAL_USHORT_VALUE = 215;
+
+ final static int MANAGER_CONN_FAILED = 800;
+ final static int MANAGER_BUSY = 801;
+ final static int ACC_DEN_INC_LOGIN = 802;
+ final static int ACC_DEN_NO_PERMISSION = 803;
+ final static int ACC_DEN_CAPABILITY_WRONG = 804;
+ final static int NO_ACTIVE_SERVERS = 805;
+ final static int WRITE_TRANS_IN_PROGRESS = 806;
+ final static int DATABASE_NOT_DEFINED = 807;
+ final static int REQUEST_FORMAT_ERROR = 808;
+
+ final static int INVALID_OBJECT_NAME_ERROR = 1014;
+
+ // time constants for retries in RasODMGImplementation.getFreeServer():
+ // if we sum up we achieve a total of (.2 + .4 +...+ 3.2) = 6.3 secs maximum wait time. that looks ok.
+ final static int MAX_GETFREESERVER_ATTEMPTS = 5; // # of tries in total until giving up on current request
+ final static int GETFREESERVER_WAIT_INITIAL = 100; // first waiting period
+ final static int GETFREESERVER_WAIT_INCREMENT = 2; // multiplication factor for subsequent wait cycles
+
+ // server connection constants
+ final static int RASMGRPORT_DEFAULT = 7001; // default port used to caontact rasmgr
+ final static String GUESTIDENT_DEFAULT = "rasguest:8e70a429be359b6dace8b5b2500dedb0";
+ // default read-only user
+
+ public final static String KEYWORD_TAB = "\t";
+ public final static String KEYWORD_CLASS = "$class";
+ public final static String KEYWORD_METHOD = "$method";
+ public final static String KEYWORD_CODE = "$code";
+ public final static String KEYWORD_URL = "$url";
+ public final static String KEYWORD_DIM1 = "$dim1";
+ public final static String KEYWORD_DIM2 = "$dim2";
+ public final static String KEYWORD_VAL = "$val";
+ public final static String KEYWORD_LOW = "$low";
+ public final static String KEYWORD_HIGH = "$high";
+ public final static String KEYWORD_INDEX = "$index";
+ public final static String KEYWORD_INVNAME = "$InvName";
+ public final static String KEYWORD_TOKEN = "$token";
+ public final static String KEYWORD_ERRNO = "$errorNo";
+ public final static String KEYWORD_LINENO = "$lineNo";
+ public final static String KEYWORD_COLNO = "$columnNo";
+ public final static String KEYWORD_ATYPE = "$aType";
+ public final static String KEYWORD_BTYPE = "$bType";
+ public final static String KEYWORD_TYPE = "$type";
+}
diff --git a/java/rasj/global/Version.class b/java/rasj/global/Version.class
new file mode 100644
index 0000000..0274d62
--- /dev/null
+++ b/java/rasj/global/Version.class
Binary files differ
diff --git a/java/rasj/global/Version.java b/java/rasj/global/Version.java
new file mode 100644
index 0000000..6adb1a0
--- /dev/null
+++ b/java/rasj/global/Version.java
@@ -0,0 +1,46 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * provide version information.
+ *
+ *
+ * COMMENTS:
+ * ./.
+ *
+ * </pre>
+ ********************************************************** **/
+
+package rasj.global;
+
+public class Version
+{
+ // version information
+ public static final String VERSION = "6.1test";
+
+ // date of .jar generation
+ public static final String DATE = "Tue Jan 6 17:52:20 CET 2009";
+}
+
diff --git a/java/rasj/global/Version.java.template b/java/rasj/global/Version.java.template
new file mode 100644
index 0000000..9865b1c
--- /dev/null
+++ b/java/rasj/global/Version.java.template
@@ -0,0 +1,46 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * provide version information.
+ *
+ *
+ * COMMENTS:
+ * ./.
+ *
+ * </pre>
+ ********************************************************** **/
+
+package rasj.global;
+
+public class Version
+{
+ // version information
+ public static final String VERSION = "%%VERSION%%";
+
+ // date of .jar generation
+ public static final String DATE = "%%GENERATION_DATE%%";
+}
+
diff --git a/java/rasj/odmg/MD5.class b/java/rasj/odmg/MD5.class
new file mode 100644
index 0000000..00f1f09
--- /dev/null
+++ b/java/rasj/odmg/MD5.class
Binary files differ
diff --git a/java/rasj/odmg/MD5State.class b/java/rasj/odmg/MD5State.class
new file mode 100644
index 0000000..07ab66a
--- /dev/null
+++ b/java/rasj/odmg/MD5State.class
Binary files differ
diff --git a/java/rasj/odmg/Makefile b/java/rasj/odmg/Makefile
new file mode 100644
index 0000000..6c768a7
--- /dev/null
+++ b/java/rasj/odmg/Makefile
@@ -0,0 +1,59 @@
+# -*-Makefile-*- (for Emacs)
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>. # Top Level makefile. This points to the various modules that have to be build
+# and/or deployed
+#
+# MAKEFILE FOR:
+# package rasj/odmg
+#
+# COMMENTS:
+#
+##################################################################
+######################### Definitions ############################
+
+# standard include with general options
+include $(RMANBASE)/Makefile.inc
+
+SRCS = RasBag.java RasCollection.java RasDatabase.java RasList.java \
+ RasODMGGlobal.java RasODMGImplementation.java RasOID.java \
+ RasOQLQuery.java RasObject.java RasSet.java RasTransaction.java
+OBJS = ${SRCS:%.java=%.class}
+MISCCLEAN = *.class
+
+# directory where HTML documentation is created
+DOCDIR := $(DOCBASE)/java/rasj/odmg
+
+########################### Targets ##############################
+
+# compile everything
+.PHONY : all
+all: $(OBJS)
+
+# delete all files
+empty:
+ -rm -f $(SRCS) $(MISCCLEAN)
+
+############################ Dependencies #######################
+
+# general rules
+include $(RMANBASE)/Makefile.rel
+
diff --git a/java/rasj/odmg/Makefile.dep b/java/rasj/odmg/Makefile.dep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/java/rasj/odmg/Makefile.dep
diff --git a/java/rasj/odmg/RasBag.class b/java/rasj/odmg/RasBag.class
new file mode 100644
index 0000000..9d443fa
--- /dev/null
+++ b/java/rasj/odmg/RasBag.class
Binary files differ
diff --git a/java/rasj/odmg/RasBag.java b/java/rasj/odmg/RasBag.java
new file mode 100644
index 0000000..5ed1843
--- /dev/null
+++ b/java/rasj/odmg/RasBag.java
@@ -0,0 +1,178 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+package rasj.odmg;
+
+import org.odmg.*;
+import rasj.global.*;
+import java.util.*;
+
+/**
+ * This class implements the ODMG DBag interface.
+ * @version $Revision: 1.3 $
+ */
+public class RasBag extends RasCollection implements DBag
+ {
+ static final String rcsid = "@(#)Package rasj.odmg, class RasBag: $Header: /home/rasdev/CVS-repository/rasdaman/java/rasj/odmg/RasBag.java,v 1.3 2003/12/19 15:42:56 rasdev Exp $";
+
+ List content;
+
+ /**
+ * constructor
+ */
+ public RasBag()
+ {
+ Debug.enterVerbose( "RasBag.constructor start." );
+ content = new ArrayList();
+ Debug.leaveVerbose( "RasBag.constructor done." );
+ }
+
+ /**
+ * Appends the specified element to this Bag.
+ */
+ public boolean add(Object o)
+ {
+ boolean result = content.add(o);
+ Debug.talkVerbose( "RasBag.add: result=" + result );
+ return result;
+ }
+
+ /**
+ * This method returns the number of occurrences of the object obj in the DBag collection.
+ */
+ public int occurrences(java.lang.Object obj)
+ {
+ Debug.enterVerbose( "RasBag.occurrences start." );
+
+ DBag tmpBag = new RasBag();
+ tmpBag.addAll(content);
+ int count = 0;
+ while(tmpBag.contains(obj))
+ {
+ count++;
+ tmpBag.remove(obj);
+ }
+
+ Debug.leaveVerbose( "RasBag.occurrences done. count=" + count );
+ return count;
+ }
+
+ /**
+ * A new DBag instance is created that contains the difference of this object and the DBag instance referenced by otherBag.
+ */
+ public DBag difference(DBag otherBag)
+ {
+ Debug.enterVerbose( "RasBag.difference start." );
+
+ DBag diffBag = new RasBag();
+ diffBag.addAll(otherBag);
+ DBag retBag = new RasBag();
+ Iterator it = content.iterator();
+ Object tmp;
+ while(it.hasNext())
+ {
+ tmp = it.next();
+ if(!diffBag.contains(tmp))
+ retBag.add(tmp);
+ else
+ diffBag.remove(tmp);
+ }
+ retBag.addAll(diffBag);
+
+ Debug.leaveVerbose( "RasBag.difference done." );
+ return retBag;
+ }
+
+ /**
+ * A new DBag instance is created that contains the intersection of this object and the DBag referenced by otherBag.
+ */
+ public DBag intersection(DBag otherBag)
+ {
+ Debug.enterVerbose( "RasBag.intersection start." );
+
+ DBag intBag = new RasBag();
+ intBag.addAll(otherBag);
+ DBag retBag = new RasBag();
+ Iterator it = content.iterator();
+ Object tmp;
+ while(it.hasNext())
+ {
+ tmp = it.next();
+ if(intBag.contains(tmp))
+ {
+ retBag.add(tmp);
+ intBag.remove(tmp);
+ }
+ }
+
+ Debug.leaveVerbose( "RasBag.intersection done." );
+ return retBag;
+ }
+
+ /**
+ * A new DBag instance is created that is the union of this object and otherBag.
+ */
+ public DBag union(DBag otherBag)
+ {
+ Debug.enterVerbose( "RasBag.union start." );
+
+ DBag retBag = new RasBag();
+ retBag.addAll(content);
+ retBag.addAll(otherBag);
+
+ Debug.leaveVerbose( "RasBag.union done." );
+ return retBag;
+ }
+
+ /**
+ * Returns an iterator over the elements in this Bag in proper sequence.
+ */
+ public Iterator iterator()
+ {
+ Debug.talkVerbose( "RasBag.iterator." );
+ return content.iterator();
+ }
+
+ /**
+ * Returns the number of elements in this Bag.
+ */
+ public int size()
+ {
+ int result = content.size();
+ Debug.talkVerbose( "RasBag.size: size=" + result );
+ return result;
+ }
+
+} // RasBag
+
diff --git a/java/rasj/odmg/RasCollection.class b/java/rasj/odmg/RasCollection.class
new file mode 100644
index 0000000..de260fc
--- /dev/null
+++ b/java/rasj/odmg/RasCollection.class
Binary files differ
diff --git a/java/rasj/odmg/RasCollection.java b/java/rasj/odmg/RasCollection.java
new file mode 100644
index 0000000..f782c94
--- /dev/null
+++ b/java/rasj/odmg/RasCollection.java
@@ -0,0 +1,105 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+package rasj.odmg;
+
+import org.odmg.*;
+import java.util.*;
+
+/**
+ * This abstract class should implement the ODMG DCollection interface but is not implemented yet,
+ * please use subclass RasBag
+ * @version $Revision: 1.5 $
+ */
+public abstract class RasCollection extends AbstractCollection implements DCollection //extends RasObject
+
+{
+ static final String rcsid = "@(#)Package rasj.odmg, class RasCollection: $Header: /home/rasdev/CVS-repository/rasdaman/java/rasj/odmg/RasCollection.java,v 1.5 2003/12/19 15:42:56 rasdev Exp $";
+
+ public RasCollection()
+ {
+ }
+
+ /**
+ * Not implemented yet.
+ */
+ public DCollection query(String predicate)
+ {
+ throw new NotImplementedException();
+ }
+
+ /**
+ * Not implemented yet.
+ */
+ public Iterator select(String predicate)
+ {
+ throw new NotImplementedException();
+ }
+
+ /**
+ * Not implemented yet.
+ */
+ public boolean existsElement(String predicate)
+ {
+ throw new NotImplementedException();
+ }
+
+ /**
+ * Not implemented yet.
+ */
+ public Object selectElement(String predicate)
+ {
+ throw new NotImplementedException();
+ }
+
+ /**
+ * Not implemented yet.
+ */
+ public int size()
+ {
+ throw new NotImplementedException();
+ }
+
+ /**
+ * Not implemented yet.
+ */
+ public Iterator iterator()
+ {
+ throw new NotImplementedException();
+ }
+
+}
+
+
+
diff --git a/java/rasj/odmg/RasDatabase.class b/java/rasj/odmg/RasDatabase.class
new file mode 100644
index 0000000..287b753
--- /dev/null
+++ b/java/rasj/odmg/RasDatabase.class
Binary files differ
diff --git a/java/rasj/odmg/RasDatabase.java b/java/rasj/odmg/RasDatabase.java
new file mode 100644
index 0000000..d494b37
--- /dev/null
+++ b/java/rasj/odmg/RasDatabase.java
@@ -0,0 +1,133 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+package rasj.odmg;
+
+import org.odmg.*;
+import rasj.global.*;
+import rasj.*;
+
+/**
+ * This class implements the ODMG Database interface.
+ *
+ * @version 1.0 (07-Apr-2000)
+ *
+ * @author Peter Zoller
+ */
+public class RasDatabase implements Database
+{
+ /**
+ * This variable holds a reference to the RasODMGImplementation object which created
+ * this RasDatabase object
+ */
+ //private RasODMGImplementation rasImplementation=null;
+ private RasImplementationInterface rasImplementation=null;
+
+ public RasDatabase(RasImplementationInterface imp)
+ {
+ Debug.enterVerbose( "RasDatabase.constructor start." );
+ rasImplementation=imp;
+ Debug.leaveVerbose( "RasDatabase.constructor done." );
+ }
+
+ /**
+ * Opens a database on the RasDaMan server ( which has been specified when the
+ * RasODMG bootstrap object has been initialized).
+ *
+ * @param name Name of the database
+ * @param accessMode access mode. Available options: OPEN_READ_ONLY, OPEN_READ_WRITE, OPEN_EXCLUSIVE
+ */
+ public void open(String name, int accessMode) throws ODMGException
+ {
+ Debug.enterVerbose( "RasDatabase.open start. name=" + name + ", accessmode=" + accessMode + "." );
+ rasImplementation.openDB(name,accessMode);
+ Debug.leaveVerbose( "RasDatabase.open done." );
+ }
+
+ /**
+ * Closes an open database. At the moment, only one database can be open at
+ * a given time and thus no parameter "database" is necessary here.
+ */
+ public void close() throws ODMGException
+ {
+ Debug.enterVerbose( "RasDatabase.close start." );
+ rasImplementation.closeDB();
+ Debug.leaveVerbose( "RasDatabase.close done." );
+ }
+
+ /**
+ * Not implemented yet.
+ */
+ public void bind(Object object, String name) throws ObjectNameNotUniqueException
+ {
+ Debug.talkCritical( "RasDatabase.bind: not yet implemented." );
+ throw new NotImplementedException();
+ }
+
+ /**
+ * Not implemented yet.
+ */
+ public Object lookup(String name) throws ObjectNameNotFoundException
+ {
+ Debug.talkCritical( "RasDatabase.lookup: not yet implemented." );
+ throw new NotImplementedException();
+ }
+
+ /**
+ * Not implemented yet.
+ */
+ public void unbind(String name) throws ObjectNameNotFoundException
+ {
+ Debug.talkCritical( "RasDatabase.unbind: not yet implemented." );
+ throw new NotImplementedException();
+ }
+
+ /**
+ * Not implemented yet.
+ */
+ public void makePersistent(Object object)
+ {
+ Debug.talkCritical( "RasDatabase.makePersistent: not yet implemented." );
+ throw new NotImplementedException();
+ }
+
+ /**
+ * Not implemented yet.
+ */
+ public void deletePersistent(Object object)
+ {
+ Debug.talkCritical( "RasDatabase.deletePersistent: not yet implemented." );
+ throw new NotImplementedException();
+ }
+
+}
+
diff --git a/java/rasj/odmg/RasList.class b/java/rasj/odmg/RasList.class
new file mode 100644
index 0000000..e43cbba
--- /dev/null
+++ b/java/rasj/odmg/RasList.class
Binary files differ
diff --git a/java/rasj/odmg/RasList.java b/java/rasj/odmg/RasList.java
new file mode 100644
index 0000000..210daf0
--- /dev/null
+++ b/java/rasj/odmg/RasList.java
@@ -0,0 +1,183 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+package rasj.odmg;
+
+import org.odmg.*;
+import java.util.*;
+
+/**
+ * This class implements the ODMG DList interface.
+ * @version $Revision: 1.3 $
+ */
+public class RasList extends RasCollection implements DList
+
+{
+ static final String rcsid = "@(#)Package rasj.odmg, class RasList: $Header: /home/rasdev/CVS-repository/rasdaman/java/rasj/odmg/RasList.java,v 1.3 2003/12/19 15:42:56 rasdev Exp $";
+
+ List content;
+
+ /**
+ * constructor
+ */
+ public RasList()
+ {
+ content = new ArrayList();
+ }
+
+ /**
+ * Creates a new DList object that contains the contents of this DList object concatenated with the contents of the otherList object.
+ */
+ public DList concat(DList otherList)
+ {
+ for(int i=0; i<otherList.size(); i++)
+ {
+ content.add(otherList.get(i));
+ }
+ return this;
+ }
+
+ /**
+ * Returns a view of the portion of this list between fromIndex, inclusive, and toIndex, exclusive.
+ */
+ public List subList(int fromIndex, int toIndex)
+ {
+ List l = new RasList();
+ for(int j=fromIndex; j<toIndex; j++)
+ {
+ l.add(content.get(j));
+ }
+ return l;
+ }
+
+ /**
+ * Returns a list iterator of the elements in this list (in proper sequence).
+ */
+ public ListIterator listIterator()
+ {
+ return content.listIterator();
+ }
+
+ /**
+ * Returns an iterator over the elements in this list in proper sequence.
+ */
+ public Iterator iterator()
+ {
+ return content.iterator();
+ }
+
+
+ /**
+ * Returns a list iterator of the elements in this list (in proper sequence), starting at the specified position in the list.
+ */
+ public ListIterator listIterator(int index)
+ {
+ return content.listIterator(index);
+ }
+
+ /**
+ * Returns the index in this list of the last occurence of the specified element, or -1 if the list does not contain this element.
+ */
+ public int lastIndexOf(Object o)
+ {
+ return content.lastIndexOf(o);
+ }
+
+
+ /**
+ * Returns the index in this list of the first occurence of the specified element, or -1 if the list does not contain this element.
+ */
+ public int indexOf(Object o)
+ {
+ return content.indexOf(o);
+ }
+
+ /**
+ * Removes the element at the specified position in this list.
+ */
+ public Object remove(int index)
+ {
+ return content.remove(index);
+ }
+
+ /**
+ * Appends the specified element to the end of this List.
+ */
+ public boolean add(Object o)
+ {
+ return content.add(o);
+ }
+
+ /**
+ * Inserts the specified element at the specified position in this list.
+ */
+ public void add(int index, Object element)
+ {
+ content.add(index, element);
+ }
+
+ /**
+ * Replaces the element at the specified position in this list with the specified element.
+ */
+ public Object set(int index, Object element)
+ {
+ return content.set(index, element);
+ }
+
+ /**
+ * Returns the element at the specified position in this list.
+ */
+ public Object get(int index)
+ {
+ return content.get(index);
+ }
+
+ /**
+ * Inserts all of the elements in the specified collection into this list at the specified position.
+ */
+ public boolean addAll(int index, Collection c)
+ {
+ return content.addAll(index, c);
+ }
+
+ /**
+ * Returns the number of elements in this List.
+ */
+ public int size()
+ {
+ return content.size();
+ }
+
+}
+
diff --git a/java/rasj/odmg/RasODMGGlobal.class b/java/rasj/odmg/RasODMGGlobal.class
new file mode 100644
index 0000000..7ddf33e
--- /dev/null
+++ b/java/rasj/odmg/RasODMGGlobal.class
Binary files differ
diff --git a/java/rasj/odmg/RasODMGGlobal.java b/java/rasj/odmg/RasODMGGlobal.java
new file mode 100644
index 0000000..431cefc
--- /dev/null
+++ b/java/rasj/odmg/RasODMGGlobal.java
@@ -0,0 +1,60 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE: Stores Global information for the RasODMGInterface
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+package rasj.odmg;
+
+/**
+ * This class provides some global defines and variables needed for the
+ * ODMG implementation of the RasDaMan httpserver. This information is
+ * only used for internal purposes and not visible to the user of the
+ * ODMG interface.
+ *
+ * @version 1.0 (07-Apr-2000)
+ *
+ * @author Peter Zoller
+ */
+public abstract class RasODMGGlobal
+{
+ // client requests allowed
+ public static final int commOpenDB = 1;
+ public static final int commCloseDB = 2;
+ public static final int commBTreadOnly = 3;
+ public static final int commBTreadWrite = 4;
+ public static final int commCT = 5;
+ public static final int commAT = 6;
+ public static final int commIsOpenTA = 7;
+ public static final int commQueryExec = 8;
+ public static final int commUpdateQueryExec = 9;
+ public static final int commGetNewOID = 10;
+}
+
+
diff --git a/java/rasj/odmg/RasODMGImplementation.class b/java/rasj/odmg/RasODMGImplementation.class
new file mode 100644
index 0000000..f8b6fa5
--- /dev/null
+++ b/java/rasj/odmg/RasODMGImplementation.class
Binary files differ
diff --git a/java/rasj/odmg/RasODMGImplementation.java b/java/rasj/odmg/RasODMGImplementation.java
new file mode 100644
index 0000000..cc6a569
--- /dev/null
+++ b/java/rasj/odmg/RasODMGImplementation.java
@@ -0,0 +1,1366 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE: ODMG Implementation Bootstrap Object
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+package rasj.odmg;
+
+import rasj.*;
+import rasj.global.*;
+import rasj.clientcommhttp.*;
+import org.odmg.*;
+
+import java.io.*;
+import java.net.*;
+import java.lang.*;
+import java.util.*;
+
+
+/**
+ * This class implements the internal ODMG Bootstrap Object used by the rasj.odmg package.
+ * Because it contains a lot of functionality for internal purposes (e.g. methods for
+ * the RasManager), this class is not the official Implementation object the user works
+ * with, it is only used by the rasj.odmg package.
+ * <P>
+ * The public Implementation object is the class
+ * {@link rasj.RasImplementation rasj.RasImplementation}, which internally works with a
+ * RasODMGImplementation object.
+ *
+ * @see rasj.RasImplementation
+ */
+
+public class RasODMGImplementation implements RasImplementationInterface,RasCommDefs//implements Implementation
+ {
+
+ private String rasServer = "";
+ private String rasMgr = "";
+ private int rasMgrPort= RasGlobalDefs.RASMGRPORT_DEFAULT;
+ private String userIdentification = RasGlobalDefs.GUESTIDENT_DEFAULT;
+ private String databaseName = "";
+ private String capability = "dummy";
+ private int maxRetry = RasGlobalDefs.MAX_GETFREESERVER_ATTEMPTS;
+
+ /**
+ * current state of transaction
+ **/
+ private boolean isOpenTA = false;
+
+ /**
+ /**
+ * This variable holds the current RasTransaction object.
+ */
+ private RasTransaction transaction = null;
+
+ /**
+ * This variable holds the current Rasdatabase object.
+ */
+ private RasDatabase database = null;
+
+ /**
+ * This variable holds the current RasOQLQuery object.
+ */
+ private RasOQLQuery query = null;
+
+ /**
+ * The standard ODMG implementation sets the access mode when the database
+ * is opened, whereas the RasDaMan server expects this information when a
+ * transaction is started. Therefore it is saved in this variable.
+ *
+ * Available modes:
+ * OPEN_READ_ONLY = 1
+ * OPEN_READ_WRITE = 2
+ * OPEN_EXCLUSIVE = 3
+ */
+ private int accessMode = 0;
+
+ /**
+ * Since ODMG does not specify a "isDatabaseOpen" method but provides a
+ * DatabaseClosedException, this variable is set to 1 if an openDB command is
+ * executed (closeDB sets it back to 0).
+ */
+ private int dbIsOpen = 0;
+
+ /**
+ * This value is set to 1 if a transaction has been opened. Commiting or aborting
+ * a transaction sets it back to 0.
+ */
+ private int taIsOpen = 0;
+
+ private int clientID = 0;
+
+ /**
+ * This value is used to store possible error messages of exceptions occuring
+ * when opening or closing transactions.
+ * The ODMG specification does not allow these operations to throw
+ * any exceptions, but our implementation could produce exceptions when connecting
+ * to the RasDaMan httpserver. In order to not get lost, these exception messages
+ * are stored in this variable.
+ */
+ private String errorStatus = "";
+ // later: private String strUserAndPasswd = "anonymous:anonymouspasswd";
+
+ /**
+ * Standard constructor.
+ * @param server Complete URL of the RasDaMan httpserver (including port number)
+ */
+ public RasODMGImplementation(String server)
+ {
+ Debug.enterVerbose( "RasODMGImplementation.constructor: start, server=" + server + "." );
+ try
+ {
+ // server address is http://server:port, we need server and port
+ StringTokenizer t=new StringTokenizer (server,"/");
+ String xxx=t.nextToken();
+ rasMgr =t.nextToken("/:");
+ String portStr = t.nextToken(":");
+ rasMgrPort = Integer.parseInt(portStr);
+ }
+ catch(NoSuchElementException e)
+ {
+ Debug.leaveVerbose( "RasODMGImplementation.constructor: done. server URL format error." );
+ throw new RasConnectionFailedException(RasGlobalDefs.URL_FORMAT_ERROR, server);
+ }
+
+ isOpenTA = false;
+
+ Debug.leaveVerbose( "RasODMGImplementation.constructor: done. ok." );
+ }
+
+ /**
+ * Gets the name of the actual server.
+ * @return the name of the RasDaMan server used
+ */
+ public String getRasServer()
+ {
+ Debug.talkVerbose( "RasODMGImplementation.getRasServer: server=" + rasServer + "." );
+ return rasServer;
+ }
+
+ /**
+ * Tells whether database is open.
+ * @return open status of database
+ */
+ public int dbIsOpen()
+ {
+ Debug.talkVerbose( "RasODMGImplementation.dbIsOpen: dbIsOpen=" + dbIsOpen + "." );
+ return dbIsOpen;
+ }
+
+ /**
+ * Gets the client ID
+ * @return ID of this client
+ */
+ public int getClientID()
+ {
+ Debug.talkVerbose( "RasODMGImplementation.getClientID: clientID=" + clientID + "." );
+ return clientID;
+ }
+
+ /**
+ * Gets the database access mode
+ * @return accessMode code: OPEN_READ_ONLY = 1; OPEN_READ_WRITE = 2; OPEN_EXCLUSIVE = 3
+ */
+ public int getAccessMode()
+ {
+ Debug.talkVerbose( "RasODMGImplementation.getAccessMode: accessMode=" + accessMode + "." );
+ return accessMode;
+ }
+
+ /**
+ * Gets the current error status
+ * @return error status string
+ */
+ public String getErrorStatus()
+ {
+ Debug.talkVerbose( "RasODMGImplementation.getErrorStatus: errorStatus=" + errorStatus + "." );
+ return errorStatus;
+ }
+
+
+ /**
+ * Create a new transaction object and associate it with the current thread.
+ */
+ public Transaction newTransaction()
+ {
+ Debug.enterVerbose( "RasODMGImplementation.newTransaction: start." );
+ transaction= new RasTransaction(this);
+ Debug.leaveVerbose( "RasODMGImplementation.newTransaction: done." );
+ return transaction;
+ }
+
+ /**
+ * Get current transaction for thread, or NULL if none.
+ */
+ public Transaction currentTransaction()
+ {
+ Debug.talkVerbose( "RasODMGImplementation.currentTransaction." );
+ return transaction;
+ }
+
+ /**
+ * Create a new database object.
+ */
+ public Database newDatabase()
+ {
+ Debug.enterVerbose( "RasODMGImplementation.newDatabase: start." );
+ database = new RasDatabase(this);
+ Debug.leaveVerbose( "RasODMGImplementation.newDatabase: done." );
+ return database;
+ }
+
+ /**
+ * Create a new query object.
+ */
+ public OQLQuery newOQLQuery()
+ {
+ Debug.enterVerbose( "RasODMGImplementation.newOQLQuery: start." );
+ query = new RasOQLQuery(this);
+ Debug.leaveVerbose( "RasODMGImplementation.newOQLQuery: done." );
+ return query;
+ }
+
+ /**
+ * Create a new DList object.
+ */
+ public DList newDList()
+ {
+ Debug.talkVerbose( "RasODMGImplementation.newDList." );
+ return new RasList();
+ }
+
+ /**
+ * Create a new DBag object.
+ */
+ public DBag newDBag()
+ {
+ return new RasBag();
+ }
+
+ /**
+ * Create a new DSet object.
+ */
+ public DSet newDSet()
+ {
+ Debug.talkVerbose( "RasODMGImplementation.newDSet." );
+ return new RasSet();
+ }
+
+ /**
+ * Not implemented yet.
+ */
+ public DArray newDArray()
+ {
+ Debug.talkWarning( "RasODMGImplementation.newDArray: not yet implemented." );
+ throw new NotImplementedException();
+ }
+
+ /**
+ * Not implemented yet.
+ */
+ public DMap newDMap()
+ {
+ Debug.talkWarning( "RasODMGImplementation.newDMap: not yet implemented." );
+ throw new NotImplementedException();
+ }
+
+ /**
+ * Get a String representation of the object's identifier.
+ * @returns: OID string on success, null otherwise
+ */
+ public String getObjectId(Object obj)
+ {
+ Debug.enterVerbose( "RasODMGImplementation.getObjectId: start." );
+
+ if( ! (obj instanceof RasObject) ) // currently all must be derived from RasObject
+ {
+ Debug.leaveWarning( "RasODMGImplementation.getObjectId: not yet implemented." );
+ throw new NotImplementedException();
+ }
+
+ // if we come here: yes, we are derived from RasObject, let's proceed
+ RasOID roid = ((RasObject)obj).getOID();
+ String oid = roid.toString();
+ DBag resultBag = null;
+ if(!((RasObject)obj).getOID().isValid()) // OID of our object is not valid -> get one
+ {
+ Debug.talkWarning( "RasODMGImplementation.getObjectId: OID not Valid: " + roid + "." );
+ String params = "ClientID=" + clientID + "&Command=10";
+ RasHttpRequest request = new RasHttpRequest();
+ if(((RasTransaction)this.currentTransaction()).isOpenLocally()) // TA is open, we can proceed
+ // (decide w/o asking server -- PB 2003-jun-25)
+ {
+ // get new oid
+ try
+ {
+ request.execute(rasServer,params); // get it from server
+ }
+ catch(RasQueryExecutionFailedException e)
+ {
+ // this cannot occur (theoretically)
+ Debug.talkCritical( "RasODMGImplementation.getObjectId: query execution failed: " + e.getMessage() );
+ }
+ }
+ else // TA is not open, so we do an open here
+ {
+ Debug.talkSparse( "RasODMGImplementation.getObjectId: db not open, opening: " + databaseName + "." );
+ boolean openedDbHere = false; // did we open a db locally?
+ boolean openedTaHere = false; // did we open a db locally?
+ Database d = null;
+ Transaction t = null;
+ try
+ {
+ if(this.dbIsOpen == Database.NOT_OPEN) // we even open the db if not done already
+ {
+ Debug.talkSparse( "RasODMGImplementation.getObjectId: db not open, opening: " + databaseName + "." );
+ d = this.newDatabase();
+ d.open( databaseName, Database.OPEN_READ_WRITE);
+ // fix: was: "RASBASE"; now: take name of last opened db. not good, but better maybe -- PB 2003-jun-13
+ // FIXME: r/w open not good, do we have info at this point? Maybe getOid needs r/w
+ openedDbHere = true;
+ }
+ t = this.newTransaction();
+ t.begin();
+ openedTaHere = true; // we know now we have an open TA
+ // get new oid
+ request.execute(rasServer,params); // get it from server
+ t.commit();
+ if(openedDbHere)
+ {
+ Debug.talkSparse( "RasODMGImplementation.getObjectId: closing locally opened DB. " );
+ d.close();
+ openedDbHere = false; // no more locally opened DB to close
+ }
+ }
+ catch(ODMGException e)
+ {
+ Debug.talkCritical( "RasODMGImplementation.getObjectId: failed: " + e.getMessage() );
+ try
+ {
+ if (openedTaHere)
+ t.abort();
+ if(openedDbHere)
+ d.close();
+ }
+ catch (ODMGException e3)
+ {
+ Debug.talkSparse( "RasODMGImplementation.getObjectId: error closing locally opened DB (ignored): " + e3.getMessage() );
+ }
+ }
+ } // if (TA open)
+
+ resultBag = (DBag)request.getResult(); // if all went fine we now have OID in result
+ if(resultBag != null)
+ {
+ Iterator iter = resultBag.iterator();
+ if(iter.hasNext())
+ roid = (RasOID)iter.next();
+ oid = roid.toString();
+ ((RasObject)obj).setOID(roid);
+ }
+ else
+ {
+ Debug.talkCritical( "RasODMGImplementation.getObjectId: empty query result, cannot fetch OID." );
+ oid = null;
+ }
+ } // valid OID
+
+ Debug.leaveVerbose( "RasODMGImplementation.getObjectId: done. oid=" + oid + "." );
+ return oid;
+ } // getObjectId()
+
+ /**
+ * Not implemented yet.
+ */
+ public Database getDatabase(Object obj)
+ {
+ Debug.talkCritical( "RasODMGImplementation.getDatabase: not yet implemented." );
+ throw new NotImplementedException();
+ }
+
+ /**
+ * Open database
+ */
+ public void openDB(String name, int accessMode) throws ODMGException, ODMGRuntimeException
+ {
+ Debug.enterVerbose( "RasODMGImplementation.openDB: start, db=" + name + ", accessMode=" + accessMode );
+
+ databaseName = name;
+ this.accessMode = accessMode;
+
+ try
+ {
+ getFreeServer(); // sets rasServer
+ executeOpenDB(databaseName,accessMode);
+ // executeCloseDB(); // does nothing, so clean away -- PB 2003-jun-25
+ dbIsOpen = 1;
+ }
+ catch (ODMGException e) // catch just for logging, then rethrow immediately
+ {
+ Debug.leaveCritical( "RasODMGImplementation.openDB: done. Exception: " + e.getMessage() );
+ throw new ODMGException( e.getMessage() );
+ }
+ catch (ODMGRuntimeException x) // catch just for logging, then rethrow immediately
+ {
+ Debug.leaveCritical( "RasODMGImplementation.openDB: done. ODMGRuntimeException: " + x.getMessage() );
+ throw new ODMGException( x.getMessage() );
+ }
+
+ Debug.leaveVerbose( "RasODMGImplementation.openDB: done. OK." );
+ }
+
+ private void executeOpenDB(String name, int accessMode) throws ODMGException
+ {
+ Debug.enterVerbose( "RasODMGImplementation.executeOpenDB: start, name=" + name + ", accessMode=" + accessMode );
+ String params = "Command=" + RasODMGGlobal.commOpenDB + "&Database=" + name + "&Capability=" + capability;
+ RasHttpRequest request = new RasHttpRequest();
+ request.execute(rasServer,params);
+ // Later, the client ID is determined here
+ clientID = 1; // not used anymore
+ Debug.leaveVerbose( "RasODMGImplementation.executeOpenDB: done." );
+ }
+
+ /**
+ * Closes an open database. At the moment, only one database can be open at
+ * a given time and thus no parameter "database" is necessary here.
+ */
+ public void closeDB() throws ODMGException
+ {
+ Debug.enterVerbose( "RasODMGImplementation.closeDB start." );
+
+ // not necessary, others do close already
+ // PB: this is due to an old bug in O2 which needed a closeDB in order to free objects, hence we do this in commitTA/abortTA
+
+ dbIsOpen = 0;
+ Debug.leaveVerbose( "RasODMGImplementation.closeDB done." );
+ }
+
+ private void executeCloseDB() throws ODMGException
+ {
+ String params = "ClientID=" + clientID + "&Command=" + RasODMGGlobal.commCloseDB;
+ RasHttpRequest request = new RasHttpRequest();
+ request.execute(rasServer,params);
+ }
+
+ /**
+ * Begin a transaction.
+ */
+ public void beginTA()
+ {
+ Debug.enterVerbose( "RasODMGImplementation.beginTA start." );
+
+ // exception handling deactivated, as not thrown any longer -- PB 2004-jul-03
+ // try
+ // {
+ // this hurts in several ways, so deactivated it: -- PB 2004-jul-03
+ // - "getFreeServer();executeOpenDB();" done in openDB(). ODMG says: to begin a TA DB must be open
+ // - this sucks up an additional server process for clean clients doing "openDB();beginTA()"
+ // getFreeServer();
+ // executeOpenDB(databaseName,accessMode);
+ executeBeginTA();
+ // }
+ // catch(ODMGException e)
+ // {
+ // Debug.talkWarning( "RasODMGImplementation.beginTA: " + e.getMessage() );
+ // errorStatus = e.getMessage();
+ // }
+ Debug.leaveVerbose( "RasODMGImplementation.beginTA done." );
+ }
+
+ private void executeBeginTA()
+ {
+ String errorMsg = "Could not open transaction: ";
+ if(dbIsOpen == 0)
+ throw new DatabaseClosedException(errorMsg + "database not open");
+
+ String params = "ClientID=" + clientID + "&Command=";
+ // Is the database opened READ_ONLY or READ_WRITE ?
+ if(accessMode == Database.OPEN_READ_ONLY)
+ params = params + RasODMGGlobal.commBTreadOnly;
+ else
+ params = params + RasODMGGlobal.commBTreadWrite;
+ params = params + "&Capability=" + capability;
+ RasHttpRequest request = new RasHttpRequest();
+ try
+ {
+ request.execute(rasServer,params);
+ }
+ catch(RasQueryExecutionFailedException e)
+ {
+ // this cannot occur (theoretically)
+ Debug.talkWarning( "RasODMGImplementation.executeBeginTA: " + e.getMessage() );
+ errorStatus = e.getMessage();
+ }
+ }
+
+ /**
+ * Returns TRUE if a transaction is currently open.
+ * This method MUST be sincere in that it asks the server about its state! (some apps use it to override timeout)
+ */
+ public boolean isOpenTA()
+ {
+ Debug.enterVerbose( "RasODMGImplementation.isOpenTA start." );
+ boolean result = false;
+
+ String params = "ClientID=" + clientID + "&Command=" + RasODMGGlobal.commIsOpenTA;
+ RasHttpRequest request = new RasHttpRequest();
+ try
+ {
+ request.execute(rasServer,params);
+ result= (request.getResultType() == 99) ? true : false;
+ }
+ catch(RasQueryExecutionFailedException e)
+ {
+ // this cannot occur (theoretically)
+ Debug.talkWarning( "RasODMGImplementation.isOpenTA: " + e.getMessage() );
+ errorStatus = e.getMessage();
+ result = false;
+ }
+
+ Debug.leaveVerbose( "RasODMGImplementation.isOpenTA done. result=" + result );
+ return result;
+ }
+
+ /**
+ * Commit a transaction.
+ */
+ public void commitTA()
+ {
+ Debug.enterVerbose( "RasODMGImplementation.commitTA start." );
+
+ try
+ {
+ executeCommitTA();
+ executeCloseDB(); // FIXME: why close here??? -- PB 2003-jun-13
+ }
+ catch(ODMGException e)
+ {
+ Debug.talkWarning( "RasODMGImplementation.commitTA: " + e.getMessage() );
+ errorStatus = e.getMessage();
+ }
+
+ Debug.leaveVerbose( "RasODMGImplementation.commitTA done." );
+ }
+
+ private void executeCommitTA()
+ {
+ String errorMsg = "Could not commit transaction: ";
+ if(dbIsOpen == 0)
+ throw new DatabaseClosedException(errorMsg + "database not open");
+ String params = "ClientID=" + clientID + "&Command=" + RasODMGGlobal.commCT;
+ RasHttpRequest request = new RasHttpRequest();
+ try
+ {
+ request.execute(rasServer,params);//RasODMGGlobal.getRasServer(),params);
+ }
+ catch(RasQueryExecutionFailedException e)
+ {
+ // this cannot occur (theoretically)
+ Debug.talkWarning( "RasODMGImplementation.executeCommitTA: " + e.getMessage() );
+ errorStatus = e.getMessage();
+ }
+ }
+
+ /**
+ * Abort a transaction.
+ */
+ public void abortTA()
+ {
+ Debug.enterVerbose( "RasODMGImplementation.abortTA start." );
+
+ try
+ {
+ executeAbortTA();
+ executeCloseDB();
+ }
+ catch(ODMGException e)
+ {
+ Debug.talkWarning( "RasODMGImplementation.abortTA: " + e.getMessage() );
+ errorStatus = e.getMessage();
+ }
+
+ Debug.leaveVerbose( "RasODMGImplementation.abortTA done." );
+ }
+
+ private void executeAbortTA()
+ {
+ String errorMsg = "Cannot abort transaction: ";
+ if(dbIsOpen == 0)
+ throw new DatabaseClosedException(errorMsg + "database not open");
+ String params = "ClientID=" + clientID + "&Command=" + RasODMGGlobal.commAT;
+ RasHttpRequest request = new RasHttpRequest();
+ try
+ {
+ request.execute(rasServer,params);
+ }
+ catch(RasQueryExecutionFailedException e)
+ {
+ // this cannot occur (theoretically)
+ Debug.talkWarning( "RasODMGImplementation.executeAbortTA: " + e.getMessage() );
+ errorStatus = e.getMessage();
+ }
+ }
+
+ /**
+ * Set the maximum retry parameter
+ */
+ public void setMaxRetry(int newRetry)
+ {
+ Debug.talkVerbose( "RasODMGImplementation.setMaxRetry to " + newRetry + "." );
+ maxRetry = newRetry;
+ }
+
+ /**
+ * Get the maximum retry parameter
+ */
+ public int getMaxRetry()
+ {
+ Debug.talkVerbose( "RasODMGImplementation.getMaxRetry: maxRetry=" + maxRetry + "." );
+ return maxRetry;
+ }
+
+ /**
+ * Requests a free server and retry's
+ */
+ //private void getFreeServer( )
+ public void getFreeServer( )
+ throws RasQueryExecutionFailedException, RasConnectionFailedException
+ {
+ Debug.enterVerbose( "RasODMGImplementation.getFreeServer: start." );
+
+ String uniqueID = uniqueRequestID();
+
+ int millisec = RasGlobalDefs.GETFREESERVER_WAIT_INITIAL;
+ for (int retryCount = 1; retryCount <= maxRetry; retryCount++)
+ {
+ try
+ {
+ executeGetFreeServer(uniqueID);
+ // if no error, we have the server, so break
+ break;
+ }
+ catch(RasConnectionFailedException e)
+ {
+ Debug.talkCritical( "RasODMGImplementation.getFreeServer: cannot obtain a free server:" + e.getMessage() );
+ // the following errors justify that we try again, maybe we get a free server a little later
+ int errno = e.getErrorNo();
+ if (errno==RasGlobalDefs.MANAGER_BUSY
+ /* || errno==RasGlobalDefs.NO_ACTIVE_SERVERS */ // if no such server is started, waiting won't help
+ || errno==RasGlobalDefs.WRITE_TRANS_IN_PROGRESS)
+ {
+ // retry, but with increasing wait period
+ millisec = millisec * RasGlobalDefs.GETFREESERVER_WAIT_INCREMENT;
+
+ Debug.talkCritical( "RasODMGImplementation.getFreeServer: no free server available, errno=" + errno + ", retry #" + retryCount + " of " + maxRetry + " after " + millisec + " msecs." );
+ try
+ {
+ Thread.sleep(millisec);
+ }
+ catch(InterruptedException intex)
+ { // wake up
+ }
+ }
+ else
+ {
+ Debug.talkCritical( "RasODMGImplementation.getFreeServer: giving up, cannot obtain free server. marking connection as closed." );
+ Debug.leaveVerbose( "RasODMGImplementation.getFreeServer: done." );
+
+ // reset ta & db
+ isOpenTA = false;
+ dbIsOpen = 0;
+ throw(e); // we give up, or we shouldn't retry with this kind of error
+ }
+ }
+ } // for
+
+ Debug.leaveVerbose( "RasODMGImplementation.getFreeServer: done." );
+ }
+
+ /**
+ * Requests a free server from rasmgr
+ */
+
+ private void executeGetFreeServer( String uniqueID ) throws RasQueryExecutionFailedException, RasConnectionFailedException
+ {
+ Debug.enterVerbose( "RasODMGImplementation.executeGetFreeServer: enter, uniqueID=" + uniqueID );
+
+ try
+ {
+ Socket soclu = new Socket(rasMgr,rasMgrPort); // FIXME: where is this socket closed ??? PB
+ Debug.talkVerbose( "RasODMGImplementation.executeGetFreeServer: socket=" + soclu );
+ PrintStream ps = new PrintStream(soclu.getOutputStream());
+ String body = databaseName + " HTTP " + (accessMode == Database.OPEN_READ_ONLY ? "ro":"rw") + " " + uniqueID + " \0";
+ ps.print("POST getfreeserver HTTP/1.1\r\nAccept: text/plain\r\nContent-type: text/plain\r\n"
+ + "User-Agent: RasDaMan Java Client1.0\r\nAuthorization: ras " + userIdentification
+ + "\r\nContent length: " + body.length()+"\r\n\r\n" + body);
+ ps.flush();
+ Debug.talkVerbose( "RasODMGImplementation.executeGetFreeServer: sent body=" + body );
+
+ BufferedReader ds = new BufferedReader(new InputStreamReader(soclu.getInputStream()));
+ int resultCode = getResultCode(ds);
+ String bodyLine = getBodyLine(ds);
+ Debug.talkVerbose( "RasODMGImplementation.executeGetFreeServer: received result code=" + resultCode + ", bodyLine=" + bodyLine );
+
+ ps.close();
+ ds.close();
+ soclu.close(); // this one was missing all the time -- PB
+ Debug.talkVerbose( "RasODMGImplementation.executeGetFreeServer: socket closed: " + soclu );
+
+ if(resultCode==200)
+ {
+ StringTokenizer t=new StringTokenizer(bodyLine," ");
+ String host=t.nextToken();
+ String port=t.nextToken(" ");
+ capability=t.nextToken(" \t\r\n\0");
+ rasServer="http://" + host + ":" + port;
+ }
+ else
+ {
+ // if error =>bodyLine: errorCode someText
+ Debug.talkSparse( "RasODMGImplementation.executeGetFreeServer: bodyLine=" + bodyLine);
+ StringTokenizer t=new StringTokenizer(bodyLine," ");
+ String errorStr = t.nextToken();
+ int errorCode = Integer.parseInt(errorStr);
+ if( resultCode < 1000 )
+ {
+ Debug.leaveVerbose( "RasODMGImplementation.executeGetFreeServer: done. connection failed, code=" + errorCode );
+ throw new RasConnectionFailedException(errorCode,null);
+ }
+ else
+ {
+ Debug.leaveVerbose( "RasODMGImplementation.executeGetFreeServer: done. request format error, code=" + errorCode );
+ throw new RasConnectionFailedException(RasGlobalDefs.REQUEST_FORMAT_ERROR," code=" + errorCode);
+ }
+ }
+ }
+ catch( MalformedURLException e )
+ {
+ Debug.talkCritical( "RasODMGImplementation.executeGetFreeServer: malformed URL exception: " + e.getMessage() );
+ Debug.leaveVerbose( "RasODMGImplementation.executeGetFreeServer: done with exception: " + e.getMessage() );
+ throw new RasConnectionFailedException(RasGlobalDefs.MANAGER_CONN_FAILED,rasMgr);
+ }
+ catch( IOException e )
+ {
+ Debug.talkCritical( "RasODMGImplementation.executeGetFreeServer: IO exception: " + e.getMessage() );
+ Debug.leaveVerbose( "RasODMGImplementation.executeGetFreeServer: done with exception: " + e.getMessage() );
+ throw new RasClientInternalException( "RasODMGImplementation","executeGetFreeServer()", e.getMessage() );
+ }
+
+ Debug.leaveVerbose( "RasODMGImplementation.executeGetFreeServer: done." );
+ } // executeGetFreeServer()
+
+ public Object queryRequest(String parameters) throws RasQueryExecutionFailedException
+ {
+ Debug.enterVerbose( "RasODMGImplementation.queryRequest start. parameters=" + parameters + "." );
+
+ BenchmarkTimer qTimer = new BenchmarkTimer("queryRequest");
+ qTimer.startTimer();
+
+ RasHttpRequest request= new RasHttpRequest();
+ request.execute(rasServer,parameters);
+
+ qTimer.stopTimer();
+ qTimer.print();
+
+ Debug.leaveVerbose( "RasODMGImplementation.executeGetFreeServer done." );
+ return request.getResult();
+ }
+
+
+ //private int getResultCode(BufferedReader ds) throws IOException
+ public int getResultCode(BufferedReader ds) throws IOException
+ {
+ Debug.enterVerbose( "RasODMGImplementation.getResultCode start." );
+
+ String s = ds.readLine();
+ StringTokenizer t = new StringTokenizer(s," ");
+ String http = t.nextToken();
+ String resultString = t.nextToken(" ");
+ int result = Integer.parseInt(resultString);
+
+ Debug.leaveVerbose( "RasODMGImplementation.getResultCode done. result=" + result + "." );
+ return result;
+ }
+
+ //private String getBodyLine(BufferedReader ds) throws IOException
+ public String getBodyLine(BufferedReader ds) throws IOException
+ {
+ Debug.enterVerbose( "RasODMGImplementation.getBodyLine start." );
+
+ String s;
+ do // was a "for(;;)" loop, cleaned it -- PB 2003-jun-13
+ {
+ s = ds.readLine();
+ if(s==null)
+ {
+ Debug.talkCritical( "RasODMGImplementation.getBodyLine: Unexpected EOF in rasmgr answer." );
+ throw new IOException("Unexpected EOF in rasmgr answer.");
+ }
+ }
+ while (s.length() != 0);
+
+ String result = ds.readLine();
+ Debug.leaveVerbose( "RasODMGImplementation.getBodyLine done. result=" + result + "." );
+ return result;
+ }
+
+ public void setUserIdentification(String userName, String plainPass)
+ {
+ Debug.enterVerbose( "RasODMGImplementation.setUserIdentification start." );
+
+ MD5 md5 = new MD5();
+ String hex;
+ md5.Init();
+ md5.Update(plainPass);
+ hex = md5.asHex();
+ userIdentification= userName + ":" + hex;
+
+ Debug.leaveVerbose( "RasODMGImplementation.setUserIdentification done." );
+ }
+
+ private String strHostID = null;
+ static private int idcounter = 0;
+
+ private String uniqueRequestID()
+ {
+ Debug.enterVerbose( "RasODMGImplementation.uniqueRequestID start." );
+
+ if(strHostID == null)
+ {
+ long hostid = 0;
+ try
+ {
+ InetAddress addr = InetAddress.getLocalHost();
+ // Get IP Address
+ byte[] ipAddr = addr.getAddress();
+
+ for(int i=0;i<ipAddr.length; i++)
+ {
+ int ss = (int)ipAddr[i];
+ if(ss<0)
+ ss = 256 + ss;
+ hostid = hostid * 256 + ss;
+ }
+ }
+ catch (UnknownHostException e)
+ {
+ Random random = new Random();
+ hostid = random.nextInt();
+ }
+ idcounter = (idcounter + 1) & 0xF;
+ // it's unique enough, we don't need such a huge number
+ strHostID = "" + hostid + ':' + (System.currentTimeMillis() & 0xFFFFFFF0) + idcounter;
+ }
+
+ Debug.leaveVerbose( "RasODMGImplementation.uniqueRequestID done. strHostID=" + strHostID + "." );
+ return strHostID;
+ }
+
+}
+
+//##################################################################################
+/**
+ * Contains internal state of the MD5 class
+ */
+
+class MD5State
+ {
+ /**
+ * 128-byte state
+ */
+ int state[];
+
+ /**
+ * 64-bit character count (could be true Java long?)
+ */
+ int count[];
+
+ /**
+ * 64-byte buffer (512 bits) for storing to-be-hashed characters
+ */
+ byte buffer[];
+
+ public MD5State()
+ {
+ Debug.enterVerbose( "MD5State.constructor start." );
+
+ buffer = new byte[64];
+ count = new int[2];
+ state = new int[4];
+
+ state[0] = 0x67452301;
+ state[1] = 0xefcdab89;
+ state[2] = 0x98badcfe;
+ state[3] = 0x10325476;
+
+ count[0] = count[1] = 0;
+
+ Debug.leaveVerbose( "MD5State.constructor done." );
+ }
+
+ /**
+ Create this State as a copy of another state
+ **/
+ public MD5State (MD5State from)
+ {
+ this();
+
+ Debug.enterVerbose( "MD5State.cloner start." );
+
+ int i;
+
+ for (i = 0; i < buffer.length; i++)
+ this.buffer[i] = from.buffer[i];
+
+ for (i = 0; i < state.length; i++)
+ this.state[i] = from.state[i];
+
+ for (i = 0; i < count.length; i++)
+ this.count[i] = from.count[i];
+
+ Debug.leaveVerbose( "MD5State.cloner done." );
+ }
+
+ }; // MD5State
+
+/**
+ * Implementation of RSA's MD5 hash generator
+ *
+ * @version $Revision: 1.25 $
+ * @author Santeri Paavolainen <sjpaavol@cc.helsinki.fi>
+ */
+
+class MD5
+{
+ /**
+ * MD5 state
+ */
+ MD5State state;
+
+ /**
+ * If Final() has been called, finals is set to the current finals
+ * state. Any Update() causes this to be set to null.
+ */
+ MD5State finals;
+
+ /**
+ * Padding for Final()
+ */
+ static byte padding[] = {
+ (byte) 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ /**
+ * Initialize MD5 internal state (object can be reused just by
+ * calling Init() after every Final()
+ */
+ public synchronized void Init () {
+ state = new MD5State();
+ finals = null;
+ }
+
+ /**
+ * Class constructor
+ */
+ public MD5 () {
+ this.Init();
+ }
+
+ /**
+ * Initialize class, and update hash with ob.toString()
+ *
+ * @param ob Object, ob.toString() is used to update hash
+ * after initialization
+ */
+ public MD5 (Object ob) {
+ this();
+ Update(ob.toString());
+ }
+
+ private int rotate_left (int x, int n) {
+ return (x << n) | (x >>> (32 - n));
+ }
+
+ /* I wonder how many loops and hoops you'll have to go through to
+ get unsigned add for longs in java */
+
+ private int uadd (int a, int b) {
+ long aa, bb;
+ aa = ((long) a) & 0xffffffffL;
+ bb = ((long) b) & 0xffffffffL;
+
+ aa += bb;
+
+ return (int) (aa & 0xffffffffL);
+ }
+
+ private int uadd (int a, int b, int c) {
+ return uadd(uadd(a, b), c);
+ }
+
+ private int uadd (int a, int b, int c, int d) {
+ return uadd(uadd(a, b, c), d);
+ }
+
+ private int FF (int a, int b, int c, int d, int x, int s, int ac) {
+ a = uadd(a, ((b & c) | (~b & d)), x, ac);
+ return uadd(rotate_left(a, s), b);
+ }
+
+ private int GG (int a, int b, int c, int d, int x, int s, int ac) {
+ a = uadd(a, ((b & d) | (c & ~d)), x, ac);
+ return uadd(rotate_left(a, s), b);
+ }
+
+ private int HH (int a, int b, int c, int d, int x, int s, int ac) {
+ a = uadd(a, (b ^ c ^ d), x, ac);
+ return uadd(rotate_left(a, s) , b);
+ }
+
+ private int II (int a, int b, int c, int d, int x, int s, int ac) {
+ a = uadd(a, (c ^ (b | ~d)), x, ac);
+ return uadd(rotate_left(a, s), b);
+ }
+
+ private int[] Decode (byte buffer[], int len, int shift) {
+ int out[];
+ int i, j;
+
+ out = new int[16];
+
+ for (i = j = 0; j < len; i++, j += 4) {
+ out[i] = ((int) (buffer[j + shift] & 0xff)) |
+ (((int) (buffer[j + 1 + shift] & 0xff)) << 8) |
+ (((int) (buffer[j + 2 + shift] & 0xff)) << 16) |
+ (((int) (buffer[j + 3 + shift] & 0xff)) << 24);
+
+/* System.out.println("out[" + i + "] = \t" +
+ ((int) buffer[j + 0 + shift] & 0xff) + "\t|\t" +
+ ((int) buffer[j + 1 + shift] & 0xff) + "\t|\t" +
+ ((int) buffer[j + 2 + shift] & 0xff) + "\t|\t" +
+ ((int) buffer[j + 3 + shift] & 0xff));*/
+ }
+
+ return out;
+ }
+
+ private void Transform (MD5State state, byte buffer[], int shift) {
+ int
+ a = state.state[0],
+ b = state.state[1],
+ c = state.state[2],
+ d = state.state[3],
+ x[];
+
+ x = Decode(buffer, 64, shift);
+
+ /* Round 1 */
+ a = FF (a, b, c, d, x[ 0], 7, 0xd76aa478); /* 1 */
+ d = FF (d, a, b, c, x[ 1], 12, 0xe8c7b756); /* 2 */
+ c = FF (c, d, a, b, x[ 2], 17, 0x242070db); /* 3 */
+ b = FF (b, c, d, a, x[ 3], 22, 0xc1bdceee); /* 4 */
+ a = FF (a, b, c, d, x[ 4], 7, 0xf57c0faf); /* 5 */
+ d = FF (d, a, b, c, x[ 5], 12, 0x4787c62a); /* 6 */
+ c = FF (c, d, a, b, x[ 6], 17, 0xa8304613); /* 7 */
+ b = FF (b, c, d, a, x[ 7], 22, 0xfd469501); /* 8 */
+ a = FF (a, b, c, d, x[ 8], 7, 0x698098d8); /* 9 */
+ d = FF (d, a, b, c, x[ 9], 12, 0x8b44f7af); /* 10 */
+ c = FF (c, d, a, b, x[10], 17, 0xffff5bb1); /* 11 */
+ b = FF (b, c, d, a, x[11], 22, 0x895cd7be); /* 12 */
+ a = FF (a, b, c, d, x[12], 7, 0x6b901122); /* 13 */
+ d = FF (d, a, b, c, x[13], 12, 0xfd987193); /* 14 */
+ c = FF (c, d, a, b, x[14], 17, 0xa679438e); /* 15 */
+ b = FF (b, c, d, a, x[15], 22, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+ a = GG (a, b, c, d, x[ 1], 5, 0xf61e2562); /* 17 */
+ d = GG (d, a, b, c, x[ 6], 9, 0xc040b340); /* 18 */
+ c = GG (c, d, a, b, x[11], 14, 0x265e5a51); /* 19 */
+ b = GG (b, c, d, a, x[ 0], 20, 0xe9b6c7aa); /* 20 */
+ a = GG (a, b, c, d, x[ 5], 5, 0xd62f105d); /* 21 */
+ d = GG (d, a, b, c, x[10], 9, 0x2441453); /* 22 */
+ c = GG (c, d, a, b, x[15], 14, 0xd8a1e681); /* 23 */
+ b = GG (b, c, d, a, x[ 4], 20, 0xe7d3fbc8); /* 24 */
+ a = GG (a, b, c, d, x[ 9], 5, 0x21e1cde6); /* 25 */
+ d = GG (d, a, b, c, x[14], 9, 0xc33707d6); /* 26 */
+ c = GG (c, d, a, b, x[ 3], 14, 0xf4d50d87); /* 27 */
+ b = GG (b, c, d, a, x[ 8], 20, 0x455a14ed); /* 28 */
+ a = GG (a, b, c, d, x[13], 5, 0xa9e3e905); /* 29 */
+ d = GG (d, a, b, c, x[ 2], 9, 0xfcefa3f8); /* 30 */
+ c = GG (c, d, a, b, x[ 7], 14, 0x676f02d9); /* 31 */
+ b = GG (b, c, d, a, x[12], 20, 0x8d2a4c8a); /* 32 */
+
+ /* Round 3 */
+ a = HH (a, b, c, d, x[ 5], 4, 0xfffa3942); /* 33 */
+ d = HH (d, a, b, c, x[ 8], 11, 0x8771f681); /* 34 */
+ c = HH (c, d, a, b, x[11], 16, 0x6d9d6122); /* 35 */
+ b = HH (b, c, d, a, x[14], 23, 0xfde5380c); /* 36 */
+ a = HH (a, b, c, d, x[ 1], 4, 0xa4beea44); /* 37 */
+ d = HH (d, a, b, c, x[ 4], 11, 0x4bdecfa9); /* 38 */
+ c = HH (c, d, a, b, x[ 7], 16, 0xf6bb4b60); /* 39 */
+ b = HH (b, c, d, a, x[10], 23, 0xbebfbc70); /* 40 */
+ a = HH (a, b, c, d, x[13], 4, 0x289b7ec6); /* 41 */
+ d = HH (d, a, b, c, x[ 0], 11, 0xeaa127fa); /* 42 */
+ c = HH (c, d, a, b, x[ 3], 16, 0xd4ef3085); /* 43 */
+ b = HH (b, c, d, a, x[ 6], 23, 0x4881d05); /* 44 */
+ a = HH (a, b, c, d, x[ 9], 4, 0xd9d4d039); /* 45 */
+ d = HH (d, a, b, c, x[12], 11, 0xe6db99e5); /* 46 */
+ c = HH (c, d, a, b, x[15], 16, 0x1fa27cf8); /* 47 */
+ b = HH (b, c, d, a, x[ 2], 23, 0xc4ac5665); /* 48 */
+
+ /* Round 4 */
+ a = II (a, b, c, d, x[ 0], 6, 0xf4292244); /* 49 */
+ d = II (d, a, b, c, x[ 7], 10, 0x432aff97); /* 50 */
+ c = II (c, d, a, b, x[14], 15, 0xab9423a7); /* 51 */
+ b = II (b, c, d, a, x[ 5], 21, 0xfc93a039); /* 52 */
+ a = II (a, b, c, d, x[12], 6, 0x655b59c3); /* 53 */
+ d = II (d, a, b, c, x[ 3], 10, 0x8f0ccc92); /* 54 */
+ c = II (c, d, a, b, x[10], 15, 0xffeff47d); /* 55 */
+ b = II (b, c, d, a, x[ 1], 21, 0x85845dd1); /* 56 */
+ a = II (a, b, c, d, x[ 8], 6, 0x6fa87e4f); /* 57 */
+ d = II (d, a, b, c, x[15], 10, 0xfe2ce6e0); /* 58 */
+ c = II (c, d, a, b, x[ 6], 15, 0xa3014314); /* 59 */
+ b = II (b, c, d, a, x[13], 21, 0x4e0811a1); /* 60 */
+ a = II (a, b, c, d, x[ 4], 6, 0xf7537e82); /* 61 */
+ d = II (d, a, b, c, x[11], 10, 0xbd3af235); /* 62 */
+ c = II (c, d, a, b, x[ 2], 15, 0x2ad7d2bb); /* 63 */
+ b = II (b, c, d, a, x[ 9], 21, 0xeb86d391); /* 64 */
+
+ state.state[0] += a;
+ state.state[1] += b;
+ state.state[2] += c;
+ state.state[3] += d;
+ }
+
+ /**
+ * Updates hash with the bytebuffer given (using at maximum length bytes from
+ * that buffer)
+ *
+ * @param state Which state is updated
+ * @param buffer Array of bytes to be hashed
+ * @param offset Offset to buffer array
+ * @param length Use at maximum `length' bytes (absolute
+ * maximum is buffer.length)
+ */
+ public void Update (MD5State stat, byte buffer[], int offset, int length) {
+ int index, partlen, i, start;
+
+/* System.out.print("Offset = " + offset + "\tLength = " + length + "\t");
+ System.out.print("Buffer = ");
+ for (i = 0; i < buffer.length; i++)
+ System.out.print((int) (buffer[i] & 0xff) + " ");
+ System.out.print("\n");*/
+
+ finals = null;
+
+ /* Length can be told to be shorter, but not inter */
+ if ((length - offset)> buffer.length)
+ length = buffer.length - offset;
+
+ /* compute number of bytes mod 64 */
+ index = (int) (stat.count[0] >>> 3) & 0x3f;
+
+ if ((stat.count[0] += (length << 3)) <
+ (length << 3))
+ stat.count[1]++;
+
+ stat.count[1] += length >>> 29;
+
+ partlen = 64 - index;
+
+ if (length >= partlen) {
+ for (i = 0; i < partlen; i++)
+ stat.buffer[i + index] = buffer[i + offset];
+
+ Transform(stat, stat.buffer, 0);
+
+ for (i = partlen; (i + 63) < length; i+= 64)
+ Transform(stat, buffer, i);
+
+ index = 0;
+ } else
+ i = 0;
+
+ /* buffer remaining input */
+ if (i < length) {
+ start = i;
+ for (; i < length; i++)
+ stat.buffer[index + i - start] = buffer[i + offset];
+ }
+ }
+
+ /*
+ * Update()s for other datatypes than byte[] also. Update(byte[], int)
+ * is only the main driver.
+ */
+
+ /**
+ * Plain update, updates this object
+ */
+
+ public void Update (byte buffer[], int offset, int length) {
+ Update(this.state, buffer, offset, length);
+ }
+
+ public void Update (byte buffer[], int length) {
+ Update(this.state, buffer, 0, length);
+ }
+
+ /**
+ * Updates hash with given array of bytes
+ *
+ * @param buffer Array of bytes to use for updating the hash
+ */
+ public void Update (byte buffer[]) {
+ Update(buffer, 0, buffer.length);
+ }
+
+ /**
+ * Updates hash with a single byte
+ *
+ * @param b Single byte to update the hash
+ */
+ public void Update (byte b) {
+ byte buffer[] = new byte[1];
+ buffer[0] = b;
+
+ Update(buffer, 1);
+ }
+
+ /**
+ * Update buffer with given string.
+ *
+ * @param s String to be update to hash (is used as
+ * s.getBytes())
+ */
+ public void Update (String s) {
+ byte chars[];
+
+ /* deprecated chars = new byte[s.length()];
+ s.getBytes(0, s.length(), chars, 0);
+ */
+ chars = s.getBytes();
+
+ Update(chars, chars.length);
+ }
+
+ /**
+ * Update buffer with a single integer (only & 0xff part is used,
+ * as a byte)
+ *
+ * @param i Integer value, which is then converted to
+ * byte as i & 0xff
+ */
+
+ public void Update (int i) {
+ Update((byte) (i & 0xff));
+ }
+
+ private byte[] Encode (int input[], int len) {
+ int i, j;
+ byte out[];
+
+ out = new byte[len];
+
+ for (i = j = 0; j < len; i++, j += 4) {
+ out[j] = (byte) (input[i] & 0xff);
+ out[j + 1] = (byte) ((input[i] >>> 8) & 0xff);
+ out[j + 2] = (byte) ((input[i] >>> 16) & 0xff);
+ out[j + 3] = (byte) ((input[i] >>> 24) & 0xff);
+ }
+
+ return out;
+ }
+
+ /**
+ * Returns array of bytes (16 bytes) representing hash as of the
+ * current state of this object. Note: getting a hash does not
+ * invalidate the hash object, it only creates a copy of the real
+ * state which is finalized.
+ *
+ * @return Array of 16 bytes, the hash of all updated bytes
+ */
+ public synchronized byte[] Final () {
+ byte bits[];
+ int index, padlen;
+ MD5State fin;
+
+ if (finals == null) {
+ fin = new MD5State(state);
+
+ bits = Encode(fin.count, 8);
+
+ index = (int) ((fin.count[0] >>> 3) & 0x3f);
+ padlen = (index < 56) ? (56 - index) : (120 - index);
+
+ Update(fin, padding, 0, padlen);
+ /**/
+ Update(fin, bits, 0, 8);
+
+ /* Update() sets finalds to null */
+ finals = fin;
+ }
+
+ return Encode(finals.state, 16);
+ }
+
+ /**
+ * Turns array of bytes into string representing each byte as
+ * unsigned hex number.
+ *
+ * @param hash Array of bytes to convert to hex-string
+ * @return Generated hex string
+ */
+ public static String asHex (byte hash[]) {
+ StringBuffer buf = new StringBuffer(hash.length * 2);
+ int i;
+
+ for (i = 0; i < hash.length; i++) {
+ if (((int) hash[i] & 0xff) < 0x10)
+ buf.append("0");
+
+ buf.append(Long.toString((int) hash[i] & 0xff, 16));
+ }
+
+ return buf.toString();
+ }
+
+ /**
+ * Returns 32-character hex representation of this objects hash
+ *
+ * @return String of this object's hash
+ */
+ public String asHex () {
+ return asHex(this.Final());
+ }
+
+} // MD5
+
diff --git a/java/rasj/odmg/RasODMGImplementation.java.BEFORE_Connection b/java/rasj/odmg/RasODMGImplementation.java.BEFORE_Connection
new file mode 100644
index 0000000..4d7f76d
--- /dev/null
+++ b/java/rasj/odmg/RasODMGImplementation.java.BEFORE_Connection
@@ -0,0 +1,1344 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE: ODMG Implementation Bootstrap Object
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+package rasj.odmg;
+
+import rasj.*;
+import rasj.global.*;
+import rasj.clientcommhttp.*;
+import org.odmg.*;
+
+import java.io.*;
+import java.net.*;
+import java.lang.*;
+import java.util.*;
+
+
+/**
+ * This class implements the internal ODMG Bootstrap Object used by the rasj.odmg package.
+ * Because it contains a lot of functionality for internal purposes (e.g. methods for
+ * the RasManager), this class is not the official Implementation object the user works
+ * with, it is only used by the rasj.odmg package.
+ * <P>
+ * The public Implementation object is the class
+ * {@link rasj.RasImplementation rasj.RasImplementation}, which internally works with a
+ * RasODMGImplementation object.
+ *
+ * @see rasj.RasImplementation
+ */
+
+public class RasODMGImplementation implements RasImplementationInterface,RasCommDefs//implements Implementation
+ {
+
+ private String rasServer = "";
+ private String rasMgr = "";
+ private int rasMgrPort=7001;
+ private String userIdentification = "rasguest:8e70a429be359b6dace8b5b2500dedb0";
+ private String databaseName = "";
+ private String capability = "dummy";
+ private int maxRetry = RasGlobalDefs.MAX_GETFREESERVER_ATTEMPTS;
+
+ /**
+ * This variable holds the current RasTransaction object.
+ */
+ private RasTransaction transaction = null;
+
+ /**
+ * This variable holds the current Rasdatabase object.
+ */
+ private RasDatabase database = null;
+
+ /**
+ * This variable holds the current RasOQLQuery object.
+ */
+ private RasOQLQuery query = null;
+
+ /**
+ * The standard ODMG implementation sets the access mode when the database
+ * is opened, whereas the RasDaMan server expects this information when a
+ * transaction is started. Therefore it is saved in this variable.
+ *
+ * Available modes:
+ * OPEN_READ_ONLY = 1
+ * OPEN_READ_WRITE = 2
+ * OPEN_EXCLUSIVE = 3
+ */
+ private int accessMode = 0;
+
+ /**
+ * Since ODMG does not specify a "isDatabaseOpen" method but provides a
+ * DatabaseClosedException, this variable is set to 1 if an openDB command is
+ * executed (closeDB sets it back to 0).
+ */
+ private int dbIsOpen = 0;
+
+ /**
+ * This value is set to 1 if a transaction has been opened. Commiting or aborting
+ * a transaction sets it back to 0.
+ */
+ private int taIsOpen = 0;
+
+ private int clientID = 0;
+
+ /**
+ * This value is used to store possible error messages of exceptions occuring
+ * when opening or closing transactions.
+ * The ODMG specification does not allow these operations to throw
+ * any exceptions, but our implementation could produce exceptions when connecting
+ * to the RasDaMan httpserver. In order to not get lost, these exception messages
+ * are stored in this variable.
+ */
+ private String errorStatus = "";
+ // later: private String strUserAndPasswd = "anonymous:anonymouspasswd";
+
+ /**
+ * Standard constructor.
+ * @param server Complete URL of the RasDaMan httpserver (including port number)
+ */
+ public RasODMGImplementation(String server)
+ {
+ Debug.enterVerbose( "RasODMGImplementation.constructor: start, server=" + server + "." );
+ try
+ {
+ // server address is http://server:port, we need server and port
+ StringTokenizer t=new StringTokenizer (server,"/");
+ String xxx=t.nextToken();
+ rasMgr =t.nextToken("/:");
+ String portStr = t.nextToken(":");
+ rasMgrPort = Integer.parseInt(portStr);
+ }
+ catch(NoSuchElementException e)
+ {
+ Debug.leaveVerbose( "RasODMGImplementation.constructor: done. server URL format error." );
+ throw new RasConnectionFailedException(RasGlobalDefs.URL_FORMAT_ERROR, server);
+ }
+ Debug.leaveVerbose( "RasODMGImplementation.constructor: done. ok." );
+ }
+
+ /**
+ * Gets the name of the actual server.
+ * @return the name of the RasDaMan server used
+ */
+ public String getRasServer()
+ {
+ Debug.talkVerbose( "RasODMGImplementation.getRasServer: server=" + rasServer + "." );
+ return rasServer;
+ }
+
+ /**
+ * Tells whether database is open.
+ * @return open status of database
+ */
+ public int dbIsOpen()
+ {
+ Debug.talkVerbose( "RasODMGImplementation.dbIsOpen: dbIsOpen=" + dbIsOpen + "." );
+ return dbIsOpen;
+ }
+
+ /**
+ * Gets the client ID
+ * @return ID of this client
+ */
+ public int getClientID()
+ {
+ Debug.talkVerbose( "RasODMGImplementation.getClientID: clientID=" + clientID + "." );
+ return clientID;
+ }
+
+ /**
+ * Gets the database access mode
+ * @return accessMode code: OPEN_READ_ONLY = 1; OPEN_READ_WRITE = 2; OPEN_EXCLUSIVE = 3
+ */
+ public int getAccessMode()
+ {
+ Debug.talkVerbose( "RasODMGImplementation.getAccessMode: accessMode=" + accessMode + "." );
+ return accessMode;
+ }
+
+ /**
+ * Gets the current error status
+ * @return error status string
+ */
+ public String getErrorStatus()
+ {
+ Debug.talkVerbose( "RasODMGImplementation.getErrorStatus: errorStatus=" + errorStatus + "." );
+ return errorStatus;
+ }
+
+
+ /**
+ * Create a new transaction object and associate it with the current thread.
+ */
+ public Transaction newTransaction()
+ {
+ Debug.enterVerbose( "RasODMGImplementation.newTransaction: enter." );
+ transaction= new RasTransaction(this);
+ Debug.leaveVerbose( "RasODMGImplementation.newTransaction: done." );
+ return transaction;
+ }
+
+ /**
+ * Get current transaction for thread, or NULL if none.
+ */
+ public Transaction currentTransaction()
+ {
+ Debug.talkVerbose( "RasODMGImplementation.currentTransaction." );
+ return transaction;
+ }
+
+ /**
+ * Create a new database object.
+ */
+ public Database newDatabase()
+ {
+ Debug.enterVerbose( "RasODMGImplementation.newDatabase: enter." );
+ database = new RasDatabase(this);
+ Debug.leaveVerbose( "RasODMGImplementation.newDatabase: done." );
+ return database;
+ }
+
+ /**
+ * Create a new query object.
+ */
+ public OQLQuery newOQLQuery()
+ {
+ Debug.enterVerbose( "RasODMGImplementation.newOQLQuery: enter." );
+ query = new RasOQLQuery(this);
+ Debug.leaveVerbose( "RasODMGImplementation.newOQLQuery: done." );
+ return query;
+ }
+
+ /**
+ * Create a new DList object.
+ */
+ public DList newDList()
+ {
+ Debug.talkVerbose( "RasODMGImplementation.newDList." );
+ return new RasList();
+ }
+
+ /**
+ * Create a new DBag object.
+ */
+ public DBag newDBag()
+ {
+ return new RasBag();
+ }
+
+ /**
+ * Create a new DSet object.
+ */
+ public DSet newDSet()
+ {
+ Debug.talkVerbose( "RasODMGImplementation.newDSet." );
+ return new RasSet();
+ }
+
+ /**
+ * Not implemented yet.
+ */
+ public DArray newDArray()
+ {
+ Debug.talkWarning( "RasODMGImplementation.newDArray: not yet implemented." );
+ throw new NotImplementedException();
+ }
+
+ /**
+ * Not implemented yet.
+ */
+ public DMap newDMap()
+ {
+ Debug.talkWarning( "RasODMGImplementation.newDMap: not yet implemented." );
+ throw new NotImplementedException();
+ }
+
+ /**
+ * Get a String representation of the object's identifier.
+ * @returns: OID string on success, null otherwise
+ */
+ public String getObjectId(Object obj)
+ {
+ Debug.enterVerbose( "RasODMGImplementation.getObjectId: enter." );
+
+ if( ! (obj instanceof RasObject) ) // currently all must be derived from RasObject
+ {
+ Debug.leaveWarning( "RasODMGImplementation.getObjectId: not yet implemented." );
+ throw new NotImplementedException();
+ }
+
+ // if we come here: yes, we are derived from RasObject, let's proceed
+ RasOID roid = ((RasObject)obj).getOID();
+ String oid = roid.toString();
+ DBag resultBag = null;
+ if(!((RasObject)obj).getOID().isValid()) // OID of our object is not valid -> get one
+ {
+ Debug.talkWarning( "RasODMGImplementation.getObjectId: OID not Valid: " + roid + "." );
+ String params = "ClientID=" + clientID + "&Command=10";
+ RasHttpRequest request = new RasHttpRequest();
+ if(this.currentTransaction().isOpen()) // TA is open, we can proceed
+ {
+ // get new oid
+ try
+ {
+ request.execute(rasServer,params); // get it from server
+ }
+ catch(RasQueryExecutionFailedException e)
+ {
+ // this cannot occur (theoretically)
+ Debug.talkCritical( "RasODMGImplementation.getObjectId: query execution failed: " + e.getMessage() );
+ }
+ }
+ else // TA is not open, so we do an open here
+ {
+ Debug.talkSparse( "RasODMGImplementation.getObjectId: db not open, opening: " + databaseName + "." );
+ boolean openedDbHere = false; // did we open a db locally?
+ boolean openedTaHere = false; // did we open a db locally?
+ Database d = null;
+ Transaction t = null;
+ try
+ {
+ if(this.dbIsOpen == Database.NOT_OPEN) // we even open the db if not done already
+ {
+ Debug.talkSparse( "RasODMGImplementation.getObjectId: db not open, opening: " + databaseName + "." );
+ d = this.newDatabase();
+ d.open( databaseName, Database.OPEN_READ_WRITE);
+ // fix: was: "RASBASE"; now: take name of last opened db. not good, but better maybe -- PB 2003-jun-13
+ // FIXME: r/w open not good, do we have info at this point? Maybe getOid needs r/w
+ openedDbHere = true;
+ }
+ t = this.newTransaction();
+ t.begin();
+ openedTaHere = true; // we know now we have an open TA
+ // get new oid
+ request.execute(rasServer,params); // get it from server
+ t.commit();
+ if(openedDbHere)
+ {
+ Debug.talkSparse( "RasODMGImplementation.getObjectId: closing locally opened DB. " );
+ d.close();
+ openedDbHere = false; // no more locally opened DB to close
+ }
+ }
+ catch(ODMGException e)
+ {
+ Debug.talkCritical( "RasODMGImplementation.getObjectId: failed: " + e.getMessage() );
+ try
+ {
+ if (openedTaHere)
+ t.abort();
+ if(openedDbHere)
+ d.close();
+ }
+ catch (ODMGException e3)
+ {
+ Debug.talkSparse( "RasODMGImplementation.getObjectId: error closing locally opened DB (ignored): " + e3.getMessage() );
+ }
+ }
+ } // if (TA open)
+
+ resultBag = (DBag)request.getResult(); // if all went fine we now have OID in result
+ if(resultBag != null)
+ {
+ Iterator iter = resultBag.iterator();
+ if(iter.hasNext())
+ roid = (RasOID)iter.next();
+ oid = roid.toString();
+ ((RasObject)obj).setOID(roid);
+ }
+ else
+ {
+ Debug.talkCritical( "RasODMGImplementation.getObjectId: empty query result, cannot fetch OID." );
+ oid = null;
+ }
+ } // valid OID
+
+ Debug.leaveVerbose( "RasODMGImplementation.getObjectId: done. oid=" + oid + "." );
+ return oid;
+ } // getObjectId()
+
+ /**
+ * Not implemented yet.
+ */
+ public Database getDatabase(Object obj)
+ {
+ Debug.talkWarning( "RasODMGImplementation.getDatabase: not yet implemented." );
+ throw new NotImplementedException();
+ }
+
+ /**
+ * Open database
+ */
+ public void openDB(String name, int accessMode) throws ODMGException, ODMGRuntimeException
+ {
+ Debug.enterVerbose( "RasODMGImplementation.openDB: start, db=" + name + ", accessMode=" + accessMode );
+
+ databaseName = name;
+ this.accessMode = accessMode;
+ try
+ {
+ openConnection( serverURL ); // establish connection to database -- PB 2003-jun-13
+ getFreeServer();
+ executeOpenDB(databaseName,accessMode);
+ executeCloseDB(); // FIXME: why in heaven do we close the db??? -- PB 2003-jun-06
+ dbIsOpen = 1;
+ }
+ catch (ODMGException e) // catch just for logging, then rethrow immediately
+ {
+ Debug.leaveCritical( "RasODMGImplementation.openDB: done. Exception: " + e.getMessage() );
+ throw new ODMGException( e.getMessage() );
+ }
+ catch (ODMGRuntimeException x) // catch just for logging, then rethrow immediately
+ {
+ Debug.leaveCritical( "RasODMGImplementation.openDB: done. ODMGRuntimeException: " + x.getMessage() );
+ throw new ODMGException( x.getMessage() );
+ }
+
+ Debug.leaveVerbose( "RasODMGImplementation.openDB: done. OK." );
+ }
+
+ private void executeOpenDB(String name, int accessMode) throws ODMGException
+ {
+ String params = "Command=" + RasODMGGlobal.commOpenDB + "&Database=" + name + "&Capability=" + capability;
+ RasHttpRequest request = new RasHttpRequest();
+ request.execute(rasServer,params);
+ // Later, the client ID is determined here
+ clientID = 1; // not used anymore
+ }
+
+ /**
+ * Closes an open database. At the moment, only one database can be open at
+ * a given time and thus no parameter "database" is necessary here.
+ */
+ public void closeDB() throws ODMGException
+ {
+ Debug.enterVerbose( "RasODMGImplementation.closeDB start." );
+
+ // not necessary, others do close already
+ // PB: this is due to an old bug in O2 which needed a closeDB in order to free objects, hence we do this in commitTA/abortTA
+
+ // close connection to server -- PB 2003-jun-13
+ closeConnection();
+
+ dbIsOpen = 0;
+ Debug.leaveVerbose( "RasODMGImplementation.closeDB done." );
+ }
+
+ private void executeCloseDB() throws ODMGException
+ {
+ String params = "ClientID=" + clientID + "&Command=" + RasODMGGlobal.commCloseDB;
+ RasHttpRequest request = new RasHttpRequest();
+ request.execute(rasServer,params);
+ }
+
+ /**
+ * Begin a transaction.
+ */
+ public void beginTA()
+ {
+ Debug.enterVerbose( "RasODMGImplementation.beginTA start." );
+ try
+ {
+ getFreeServer();
+ executeOpenDB(databaseName,accessMode);
+ executeBeginTA();
+ }
+ catch(ODMGException e)
+ {
+ Debug.talkWarning( "RasODMGImplementation.beginTA: " + e.getMessage() );
+ errorStatus = e.getMessage();
+ }
+ Debug.leaveVerbose( "RasODMGImplementation.beginTA done." );
+ }
+
+ private void executeBeginTA()
+ {
+ String errorMsg = "Could not open transaction: ";
+ if(dbIsOpen == 0)
+ throw new DatabaseClosedException(errorMsg + "database not open");
+
+ String params = "ClientID=" + clientID + "&Command=";
+ // Is the database opened READ_ONLY or READ_WRITE ?
+ if(accessMode == Database.OPEN_READ_ONLY)
+ params = params + RasODMGGlobal.commBTreadOnly;
+ else
+ params = params + RasODMGGlobal.commBTreadWrite;
+ params = params + "&Capability=" + capability;
+ RasHttpRequest request = new RasHttpRequest();
+ try
+ {
+ request.execute(rasServer,params);
+ }
+ catch(RasQueryExecutionFailedException e)
+ {
+ // this cannot occur (theoretically)
+ Debug.talkWarning( "RasODMGImplementation.executeBeginTA: " + e.getMessage() );
+ errorStatus = e.getMessage();
+ }
+ }
+
+ /**
+ * Returns TRUE if a transaction is currently open.
+ */
+ public boolean isOpenTA()
+ {
+ Debug.enterVerbose( "RasODMGImplementation.isOpenTA start." );
+ boolean result = false;
+
+ String params = "ClientID=" + clientID + "&Command=" + RasODMGGlobal.commIsOpenTA;
+ RasHttpRequest request = new RasHttpRequest();
+ try
+ {
+ request.execute(rasServer,params);
+ result= (request.getResultType() == 99) ? true : false;
+ }
+ catch(RasQueryExecutionFailedException e)
+ {
+ // this cannot occur (theoretically)
+ Debug.talkWarning( "RasODMGImplementation.isOpenTA: " + e.getMessage() );
+ errorStatus = e.getMessage();
+ result = false;
+ }
+ Debug.leaveVerbose( "RasODMGImplementation.isOpenTA done. result=" + result );
+ return result;
+ }
+
+ /**
+ * Commit a transaction.
+ */
+ public void commitTA()
+ {
+ Debug.enterVerbose( "RasODMGImplementation.commitTA start." );
+
+ try
+ {
+ executeCommitTA();
+ executeCloseDB(); // FIXME: why close here??? -- PB 2003-jun-13
+ }
+ catch(ODMGException e)
+ {
+ Debug.talkWarning( "RasODMGImplementation.commitTA: " + e.getMessage() );
+ errorStatus = e.getMessage();
+ }
+
+ Debug.leaveVerbose( "RasODMGImplementation.commitTA done." );
+ }
+
+ private void executeCommitTA()
+ {
+ String errorMsg = "Could not commit transaction: ";
+ if(dbIsOpen == 0)
+ throw new DatabaseClosedException(errorMsg + "database not open");
+ String params = "ClientID=" + clientID + "&Command=" + RasODMGGlobal.commCT;
+ RasHttpRequest request = new RasHttpRequest();
+ try
+ {
+ request.execute(rasServer,params);//RasODMGGlobal.getRasServer(),params);
+ }
+ catch(RasQueryExecutionFailedException e)
+ {
+ // this cannot occur (theoretically)
+ Debug.talkWarning( "RasODMGImplementation.executeCommitTA: " + e.getMessage() );
+ errorStatus = e.getMessage();
+ }
+ }
+
+ /**
+ * Abort a transaction.
+ */
+ public void abortTA()
+ {
+ Debug.enterVerbose( "RasODMGImplementation.abortTA start." );
+
+ try
+ {
+ executeAbortTA();
+ executeCloseDB();
+ }
+ catch(ODMGException e)
+ {
+ Debug.talkWarning( "RasODMGImplementation.abortTA: " + e.getMessage() );
+ errorStatus = e.getMessage();
+ }
+
+ Debug.leaveVerbose( "RasODMGImplementation.abortTA done." );
+ }
+
+ private void executeAbortTA()
+ {
+ String errorMsg = "Cannot abort transaction: ";
+ if(dbIsOpen == 0)
+ throw new DatabaseClosedException(errorMsg + "database not open");
+ String params = "ClientID=" + clientID + "&Command=" + RasODMGGlobal.commAT;
+ RasHttpRequest request = new RasHttpRequest();
+ try
+ {
+ request.execute(rasServer,params);
+ }
+ catch(RasQueryExecutionFailedException e)
+ {
+ // this cannot occur (theoretically)
+ Debug.talkWarning( "RasODMGImplementation.executeAbortTA: " + e.getMessage() );
+ errorStatus = e.getMessage();
+ }
+ }
+
+ /**
+ * Set the maximum retry parameter
+ */
+ public void setMaxRetry(int newRetry)
+ {
+ Debug.talkVerbose( "RasODMGImplementation.setMaxRetry to " + newRetry + "." );
+ maxRetry = newRetry;
+ }
+
+ /**
+ * Get the maximum retry parameter
+ */
+ public int getMaxRetry()
+ {
+ Debug.talkVerbose( "RasODMGImplementation.getMaxRetry: maxRetry=" + maxRetry + "." );
+ return maxRetry;
+ }
+
+ /**
+ * Requests a free server and retry's
+ */
+ //private void getFreeServer( )
+ public void getFreeServer( )
+ throws RasQueryExecutionFailedException, RasConnectionFailedException
+ {
+ Debug.enterVerbose( "RasODMGImplementation.getFreeServer: enter." );
+
+ String uniqueID = uniqueRequestID();
+
+ int millisec = RasGlobalDefs.GETFREESERVER_WAIT_INITIAL;
+ for (int retryCount = 1; retryCount <= maxRetry; retryCount++)
+ {
+ try
+ {
+ executeGetFreeServer(uniqueID);
+ // if no error, we have the server, so break
+ break;
+ }
+ catch(RasConnectionFailedException e)
+ {
+ Debug.talkCritical( "RasODMGImplementation.getFreeServer: cannot obtain a free server:" + e.getMessage() );
+ // the following errors justify that we try again, maybe we get a free server a little later
+ int errno = e.getErrorNo();
+ if (errno==RasGlobalDefs.MANAGER_BUSY
+ /* || errno==RasGlobalDefs.NO_ACTIVE_SERVERS */ // if no such server is started, waiting won't help
+ || errno==RasGlobalDefs.WRITE_TRANS_IN_PROGRESS)
+ {
+ // retry, but with increasing wait period
+ millisec = millisec * RasGlobalDefs.GETFREESERVER_WAIT_INCREMENT;
+
+ Debug.talkCritical( "RasODMGImplementation.getFreeServer: no free server available, errno=" + errno + ", retry #" + retryCount + " of " + maxRetry + " after " + millisec + " msecs." );
+ try
+ {
+ Thread.sleep(millisec);
+ }
+ catch(InterruptedException intex)
+ {
+ }
+ }
+ else
+ {
+ Debug.leaveCritical( "RasODMGImplementation.getFreeServer: giving up, cannot obtain free server." );
+ throw(e); // we give up, or we shouldn't retry with this kind of error
+ }
+ }
+ } // for
+
+ Debug.leaveVerbose( "RasODMGImplementation.getFreeServer: done." );
+ }
+
+ /**
+ * Requests a free server
+ */
+
+ private void executeGetFreeServer( String uniqueID ) throws RasQueryExecutionFailedException, RasConnectionFailedException
+ {
+ Debug.enterVerbose( "RasODMGImplementation.executeGetFreeServer: enter, uniqueID=" + uniqueID );
+
+ try
+ {
+ Socket soclu = new Socket(rasMgr,rasMgrPort); // FIXME: where is this socket closed ??? PB
+ Debug.talkVerbose( "RasODMGImplementation.executeGetFreeServer: socket=" + soclu );
+ PrintStream ps = new PrintStream(soclu.getOutputStream());
+ String body = databaseName + " HTTP " + (accessMode == Database.OPEN_READ_ONLY ? "ro":"rw") + " " + uniqueID + " \0";
+ ps.print("POST getfreeserver HTTP/1.1\r\nAccept: text/plain\r\nContent-type: text/plain\r\n"
+ + "User-Agent: RasDaMan Java Client1.0\r\nAuthorization: ras " + userIdentification
+ + "\r\nContent length: " + body.length()+"\r\n\r\n" + body);
+ ps.flush();
+ Debug.talkVerbose( "RasODMGImplementation.executeGetFreeServer: sent body=" + body );
+
+ BufferedReader ds = new BufferedReader(new InputStreamReader(soclu.getInputStream()));
+ int resultCode = getResultCode(ds);
+ String bodyLine = getBodyLine(ds);
+ Debug.talkVerbose( "RasODMGImplementation.executeGetFreeServer: received result code=" + resultCode + ", bodyLine=" + bodyLine );
+
+ ps.close();
+ ds.close();
+ soclu.close(); // this one was missing all the time -- PB
+ Debug.talkVerbose( "RasODMGImplementation.executeGetFreeServer: socket closed: " + soclu );
+
+ if(resultCode==200)
+ {
+ StringTokenizer t=new StringTokenizer(bodyLine," ");
+ String host=t.nextToken();
+ String port=t.nextToken(" ");
+ capability=t.nextToken(" \t\r\n\0");
+ rasServer="http://" + host + ":" + port;
+ }
+ else
+ {
+ // if error =>bodyLine: errorCode someText
+ Debug.talkSparse( "RasODMGImplementation.executeGetFreeServer: bodyLine=" + bodyLine);
+ StringTokenizer t=new StringTokenizer(bodyLine," ");
+ String errorStr = t.nextToken();
+ int errorCode = Integer.parseInt(errorStr);
+ if( resultCode < 1000 )
+ {
+ Debug.leaveVerbose( "RasODMGImplementation.executeGetFreeServer: done. connection failed, code=" + errorCode );
+ throw new RasConnectionFailedException(errorCode,null);
+ }
+ else
+ {
+ Debug.leaveVerbose( "RasODMGImplementation.executeGetFreeServer: done. request format error, code=" + errorCode );
+ throw new RasConnectionFailedException(RasGlobalDefs.REQUEST_FORMAT_ERROR," code=" + errorCode);
+ }
+ }
+ }
+ catch( MalformedURLException e )
+ {
+ Debug.talkCritical( "RasODMGImplementation.executeGetFreeServer: malformed URL exception: " + e.getMessage() );
+ throw new RasConnectionFailedException(RasGlobalDefs.MANAGER_CONN_FAILED,rasMgr);
+ }
+ catch( IOException e )
+ {
+ Debug.talkCritical( "RasODMGImplementation.executeGetFreeServer: IO exception: " + e.getMessage() );
+ throw new RasClientInternalException( "RasODMGImplementation","executeGetFreeServer()", e.getMessage() );
+ }
+
+ Debug.leaveVerbose( "RasODMGImplementation.executeGetFreeServer: done." );
+ } // executeGetFreeServer()
+
+
+ public Object queryRequest(String parameters) throws RasQueryExecutionFailedException
+ {
+ Debug.enterVerbose( "RasODMGImplementation.queryRequest start. parameters=" + parameters + "." );
+
+ BenchmarkTimer qTimer = new BenchmarkTimer("queryRequest");
+ qTimer.startTimer();
+
+ RasHttpRequest request= new RasHttpRequest();
+ request.execute(getRasServer(),parameters);
+
+ qTimer.stopTimer();
+ qTimer.print();
+
+ Debug.leaveVerbose( "RasODMGImplementation.executeGetFreeServer done." );
+ return request.getResult();
+ }
+
+
+ //private int getResultCode(BufferedReader ds) throws IOException
+ public int getResultCode(BufferedReader ds) throws IOException
+ {
+ Debug.enterVerbose( "RasODMGImplementation.getResultCode start." );
+
+ String s = ds.readLine();
+ StringTokenizer t = new StringTokenizer(s," ");
+ String http = t.nextToken();
+ String resultString = t.nextToken(" ");
+ int result = Integer.parseInt(resultString);
+
+ Debug.leaveVerbose( "RasODMGImplementation.getResultCode done. result=" + result + "." );
+ return result;
+ }
+
+ //private String getBodyLine(BufferedReader ds) throws IOException
+ public String getBodyLine(BufferedReader ds) throws IOException
+ {
+ Debug.enterVerbose( "RasODMGImplementation.getBodyLine start." );
+
+ String s;
+ do // was a "for(;;)" loop, cleaned it -- PB 2003-jun-13
+ {
+ s = ds.readLine();
+ if(s==null)
+ {
+ Debug.talkCritical( "RasODMGImplementation.getBodyLine: Unexpected EOF in rasmgr answer." );
+ throw new IOException("Unexpected EOF in rasmgr answer.");
+ }
+ }
+ while (s.length() != 0);
+
+ String result = ds.readLine();
+ Debug.leaveVerbose( "RasODMGImplementation.getBodyLine done. result=" + result + "." );
+ return result;
+ }
+
+ public void setUserIdentification(String userName, String plainPass)
+ {
+ Debug.enterVerbose( "RasODMGImplementation.setUserIdentification start." );
+
+ MD5 md5 = new MD5();
+ String hex;
+ md5.Init();
+ md5.Update(plainPass);
+ hex = md5.asHex();
+ userIdentification= userName + ":" + hex;
+
+ Debug.leaveVerbose( "RasODMGImplementation.setUserIdentification done." );
+ }
+
+ private String strHostID = null;
+ static private int idcounter = 0;
+
+ private String uniqueRequestID()
+ {
+ Debug.leaveVerbose( "RasODMGImplementation.uniqueRequestID start." );
+
+ if(strHostID == null)
+ {
+ long hostid = 0;
+ try
+ {
+ InetAddress addr = InetAddress.getLocalHost();
+ // Get IP Address
+ byte[] ipAddr = addr.getAddress();
+
+ for(int i=0;i<ipAddr.length; i++)
+ {
+ int ss = (int)ipAddr[i];
+ if(ss<0)
+ ss = 256 + ss;
+ hostid = hostid * 256 + ss;
+ }
+ }
+ catch (UnknownHostException e)
+ {
+ Random random = new Random();
+ hostid = random.nextInt();
+ }
+ idcounter = (idcounter + 1) & 0xF;
+ // it's unique enough, we don't need such a huge number
+ strHostID = "" + hostid + ':' + (System.currentTimeMillis() & 0xFFFFFFF0) + idcounter;
+ }
+
+ Debug.leaveVerbose( "RasODMGImplementation.uniqueRequestID done. strHostID=" + strHostID + "." );
+ return strHostID;
+ }
+
+}
+
+//##################################################################################
+/**
+ * Contains internal state of the MD5 class
+ */
+
+class MD5State
+ {
+ /**
+ * 128-byte state
+ */
+ int state[];
+
+ /**
+ * 64-bit character count (could be true Java long?)
+ */
+ int count[];
+
+ /**
+ * 64-byte buffer (512 bits) for storing to-be-hashed characters
+ */
+ byte buffer[];
+
+ public MD5State()
+ {
+ Debug.enterVerbose( "MD5State.constructor start." );
+
+ buffer = new byte[64];
+ count = new int[2];
+ state = new int[4];
+
+ state[0] = 0x67452301;
+ state[1] = 0xefcdab89;
+ state[2] = 0x98badcfe;
+ state[3] = 0x10325476;
+
+ count[0] = count[1] = 0;
+
+ Debug.leaveVerbose( "MD5State.constructor done." );
+ }
+
+ /**
+ Create this State as a copy of another state
+ **/
+ public MD5State (MD5State from)
+ {
+ this();
+
+ Debug.enterVerbose( "MD5State.cloner start." );
+
+ int i;
+
+ for (i = 0; i < buffer.length; i++)
+ this.buffer[i] = from.buffer[i];
+
+ for (i = 0; i < state.length; i++)
+ this.state[i] = from.state[i];
+
+ for (i = 0; i < count.length; i++)
+ this.count[i] = from.count[i];
+
+ Debug.leaveVerbose( "MD5State.cloner done." );
+ }
+
+ }; // MD5State
+
+/**
+ * Implementation of RSA's MD5 hash generator
+ *
+ * @version $Revision: 1.19 $
+ * @author Santeri Paavolainen <sjpaavol@cc.helsinki.fi>
+ */
+
+class MD5
+{
+ /**
+ * MD5 state
+ */
+ MD5State state;
+
+ /**
+ * If Final() has been called, finals is set to the current finals
+ * state. Any Update() causes this to be set to null.
+ */
+ MD5State finals;
+
+ /**
+ * Padding for Final()
+ */
+ static byte padding[] = {
+ (byte) 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ /**
+ * Initialize MD5 internal state (object can be reused just by
+ * calling Init() after every Final()
+ */
+ public synchronized void Init () {
+ state = new MD5State();
+ finals = null;
+ }
+
+ /**
+ * Class constructor
+ */
+ public MD5 () {
+ this.Init();
+ }
+
+ /**
+ * Initialize class, and update hash with ob.toString()
+ *
+ * @param ob Object, ob.toString() is used to update hash
+ * after initialization
+ */
+ public MD5 (Object ob) {
+ this();
+ Update(ob.toString());
+ }
+
+ private int rotate_left (int x, int n) {
+ return (x << n) | (x >>> (32 - n));
+ }
+
+ /* I wonder how many loops and hoops you'll have to go through to
+ get unsigned add for longs in java */
+
+ private int uadd (int a, int b) {
+ long aa, bb;
+ aa = ((long) a) & 0xffffffffL;
+ bb = ((long) b) & 0xffffffffL;
+
+ aa += bb;
+
+ return (int) (aa & 0xffffffffL);
+ }
+
+ private int uadd (int a, int b, int c) {
+ return uadd(uadd(a, b), c);
+ }
+
+ private int uadd (int a, int b, int c, int d) {
+ return uadd(uadd(a, b, c), d);
+ }
+
+ private int FF (int a, int b, int c, int d, int x, int s, int ac) {
+ a = uadd(a, ((b & c) | (~b & d)), x, ac);
+ return uadd(rotate_left(a, s), b);
+ }
+
+ private int GG (int a, int b, int c, int d, int x, int s, int ac) {
+ a = uadd(a, ((b & d) | (c & ~d)), x, ac);
+ return uadd(rotate_left(a, s), b);
+ }
+
+ private int HH (int a, int b, int c, int d, int x, int s, int ac) {
+ a = uadd(a, (b ^ c ^ d), x, ac);
+ return uadd(rotate_left(a, s) , b);
+ }
+
+ private int II (int a, int b, int c, int d, int x, int s, int ac) {
+ a = uadd(a, (c ^ (b | ~d)), x, ac);
+ return uadd(rotate_left(a, s), b);
+ }
+
+ private int[] Decode (byte buffer[], int len, int shift) {
+ int out[];
+ int i, j;
+
+ out = new int[16];
+
+ for (i = j = 0; j < len; i++, j += 4) {
+ out[i] = ((int) (buffer[j + shift] & 0xff)) |
+ (((int) (buffer[j + 1 + shift] & 0xff)) << 8) |
+ (((int) (buffer[j + 2 + shift] & 0xff)) << 16) |
+ (((int) (buffer[j + 3 + shift] & 0xff)) << 24);
+
+/* System.out.println("out[" + i + "] = \t" +
+ ((int) buffer[j + 0 + shift] & 0xff) + "\t|\t" +
+ ((int) buffer[j + 1 + shift] & 0xff) + "\t|\t" +
+ ((int) buffer[j + 2 + shift] & 0xff) + "\t|\t" +
+ ((int) buffer[j + 3 + shift] & 0xff));*/
+ }
+
+ return out;
+ }
+
+ private void Transform (MD5State state, byte buffer[], int shift) {
+ int
+ a = state.state[0],
+ b = state.state[1],
+ c = state.state[2],
+ d = state.state[3],
+ x[];
+
+ x = Decode(buffer, 64, shift);
+
+ /* Round 1 */
+ a = FF (a, b, c, d, x[ 0], 7, 0xd76aa478); /* 1 */
+ d = FF (d, a, b, c, x[ 1], 12, 0xe8c7b756); /* 2 */
+ c = FF (c, d, a, b, x[ 2], 17, 0x242070db); /* 3 */
+ b = FF (b, c, d, a, x[ 3], 22, 0xc1bdceee); /* 4 */
+ a = FF (a, b, c, d, x[ 4], 7, 0xf57c0faf); /* 5 */
+ d = FF (d, a, b, c, x[ 5], 12, 0x4787c62a); /* 6 */
+ c = FF (c, d, a, b, x[ 6], 17, 0xa8304613); /* 7 */
+ b = FF (b, c, d, a, x[ 7], 22, 0xfd469501); /* 8 */
+ a = FF (a, b, c, d, x[ 8], 7, 0x698098d8); /* 9 */
+ d = FF (d, a, b, c, x[ 9], 12, 0x8b44f7af); /* 10 */
+ c = FF (c, d, a, b, x[10], 17, 0xffff5bb1); /* 11 */
+ b = FF (b, c, d, a, x[11], 22, 0x895cd7be); /* 12 */
+ a = FF (a, b, c, d, x[12], 7, 0x6b901122); /* 13 */
+ d = FF (d, a, b, c, x[13], 12, 0xfd987193); /* 14 */
+ c = FF (c, d, a, b, x[14], 17, 0xa679438e); /* 15 */
+ b = FF (b, c, d, a, x[15], 22, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+ a = GG (a, b, c, d, x[ 1], 5, 0xf61e2562); /* 17 */
+ d = GG (d, a, b, c, x[ 6], 9, 0xc040b340); /* 18 */
+ c = GG (c, d, a, b, x[11], 14, 0x265e5a51); /* 19 */
+ b = GG (b, c, d, a, x[ 0], 20, 0xe9b6c7aa); /* 20 */
+ a = GG (a, b, c, d, x[ 5], 5, 0xd62f105d); /* 21 */
+ d = GG (d, a, b, c, x[10], 9, 0x2441453); /* 22 */
+ c = GG (c, d, a, b, x[15], 14, 0xd8a1e681); /* 23 */
+ b = GG (b, c, d, a, x[ 4], 20, 0xe7d3fbc8); /* 24 */
+ a = GG (a, b, c, d, x[ 9], 5, 0x21e1cde6); /* 25 */
+ d = GG (d, a, b, c, x[14], 9, 0xc33707d6); /* 26 */
+ c = GG (c, d, a, b, x[ 3], 14, 0xf4d50d87); /* 27 */
+ b = GG (b, c, d, a, x[ 8], 20, 0x455a14ed); /* 28 */
+ a = GG (a, b, c, d, x[13], 5, 0xa9e3e905); /* 29 */
+ d = GG (d, a, b, c, x[ 2], 9, 0xfcefa3f8); /* 30 */
+ c = GG (c, d, a, b, x[ 7], 14, 0x676f02d9); /* 31 */
+ b = GG (b, c, d, a, x[12], 20, 0x8d2a4c8a); /* 32 */
+
+ /* Round 3 */
+ a = HH (a, b, c, d, x[ 5], 4, 0xfffa3942); /* 33 */
+ d = HH (d, a, b, c, x[ 8], 11, 0x8771f681); /* 34 */
+ c = HH (c, d, a, b, x[11], 16, 0x6d9d6122); /* 35 */
+ b = HH (b, c, d, a, x[14], 23, 0xfde5380c); /* 36 */
+ a = HH (a, b, c, d, x[ 1], 4, 0xa4beea44); /* 37 */
+ d = HH (d, a, b, c, x[ 4], 11, 0x4bdecfa9); /* 38 */
+ c = HH (c, d, a, b, x[ 7], 16, 0xf6bb4b60); /* 39 */
+ b = HH (b, c, d, a, x[10], 23, 0xbebfbc70); /* 40 */
+ a = HH (a, b, c, d, x[13], 4, 0x289b7ec6); /* 41 */
+ d = HH (d, a, b, c, x[ 0], 11, 0xeaa127fa); /* 42 */
+ c = HH (c, d, a, b, x[ 3], 16, 0xd4ef3085); /* 43 */
+ b = HH (b, c, d, a, x[ 6], 23, 0x4881d05); /* 44 */
+ a = HH (a, b, c, d, x[ 9], 4, 0xd9d4d039); /* 45 */
+ d = HH (d, a, b, c, x[12], 11, 0xe6db99e5); /* 46 */
+ c = HH (c, d, a, b, x[15], 16, 0x1fa27cf8); /* 47 */
+ b = HH (b, c, d, a, x[ 2], 23, 0xc4ac5665); /* 48 */
+
+ /* Round 4 */
+ a = II (a, b, c, d, x[ 0], 6, 0xf4292244); /* 49 */
+ d = II (d, a, b, c, x[ 7], 10, 0x432aff97); /* 50 */
+ c = II (c, d, a, b, x[14], 15, 0xab9423a7); /* 51 */
+ b = II (b, c, d, a, x[ 5], 21, 0xfc93a039); /* 52 */
+ a = II (a, b, c, d, x[12], 6, 0x655b59c3); /* 53 */
+ d = II (d, a, b, c, x[ 3], 10, 0x8f0ccc92); /* 54 */
+ c = II (c, d, a, b, x[10], 15, 0xffeff47d); /* 55 */
+ b = II (b, c, d, a, x[ 1], 21, 0x85845dd1); /* 56 */
+ a = II (a, b, c, d, x[ 8], 6, 0x6fa87e4f); /* 57 */
+ d = II (d, a, b, c, x[15], 10, 0xfe2ce6e0); /* 58 */
+ c = II (c, d, a, b, x[ 6], 15, 0xa3014314); /* 59 */
+ b = II (b, c, d, a, x[13], 21, 0x4e0811a1); /* 60 */
+ a = II (a, b, c, d, x[ 4], 6, 0xf7537e82); /* 61 */
+ d = II (d, a, b, c, x[11], 10, 0xbd3af235); /* 62 */
+ c = II (c, d, a, b, x[ 2], 15, 0x2ad7d2bb); /* 63 */
+ b = II (b, c, d, a, x[ 9], 21, 0xeb86d391); /* 64 */
+
+ state.state[0] += a;
+ state.state[1] += b;
+ state.state[2] += c;
+ state.state[3] += d;
+ }
+
+ /**
+ * Updates hash with the bytebuffer given (using at maximum length bytes from
+ * that buffer)
+ *
+ * @param state Which state is updated
+ * @param buffer Array of bytes to be hashed
+ * @param offset Offset to buffer array
+ * @param length Use at maximum `length' bytes (absolute
+ * maximum is buffer.length)
+ */
+ public void Update (MD5State stat, byte buffer[], int offset, int length) {
+ int index, partlen, i, start;
+
+/* System.out.print("Offset = " + offset + "\tLength = " + length + "\t");
+ System.out.print("Buffer = ");
+ for (i = 0; i < buffer.length; i++)
+ System.out.print((int) (buffer[i] & 0xff) + " ");
+ System.out.print("\n");*/
+
+ finals = null;
+
+ /* Length can be told to be shorter, but not inter */
+ if ((length - offset)> buffer.length)
+ length = buffer.length - offset;
+
+ /* compute number of bytes mod 64 */
+ index = (int) (stat.count[0] >>> 3) & 0x3f;
+
+ if ((stat.count[0] += (length << 3)) <
+ (length << 3))
+ stat.count[1]++;
+
+ stat.count[1] += length >>> 29;
+
+ partlen = 64 - index;
+
+ if (length >= partlen) {
+ for (i = 0; i < partlen; i++)
+ stat.buffer[i + index] = buffer[i + offset];
+
+ Transform(stat, stat.buffer, 0);
+
+ for (i = partlen; (i + 63) < length; i+= 64)
+ Transform(stat, buffer, i);
+
+ index = 0;
+ } else
+ i = 0;
+
+ /* buffer remaining input */
+ if (i < length) {
+ start = i;
+ for (; i < length; i++)
+ stat.buffer[index + i - start] = buffer[i + offset];
+ }
+ }
+
+ /*
+ * Update()s for other datatypes than byte[] also. Update(byte[], int)
+ * is only the main driver.
+ */
+
+ /**
+ * Plain update, updates this object
+ */
+
+ public void Update (byte buffer[], int offset, int length) {
+ Update(this.state, buffer, offset, length);
+ }
+
+ public void Update (byte buffer[], int length) {
+ Update(this.state, buffer, 0, length);
+ }
+
+ /**
+ * Updates hash with given array of bytes
+ *
+ * @param buffer Array of bytes to use for updating the hash
+ */
+ public void Update (byte buffer[]) {
+ Update(buffer, 0, buffer.length);
+ }
+
+ /**
+ * Updates hash with a single byte
+ *
+ * @param b Single byte to update the hash
+ */
+ public void Update (byte b) {
+ byte buffer[] = new byte[1];
+ buffer[0] = b;
+
+ Update(buffer, 1);
+ }
+
+ /**
+ * Update buffer with given string.
+ *
+ * @param s String to be update to hash (is used as
+ * s.getBytes())
+ */
+ public void Update (String s) {
+ byte chars[];
+
+ /* deprecated chars = new byte[s.length()];
+ s.getBytes(0, s.length(), chars, 0);
+ */
+ chars = s.getBytes();
+
+ Update(chars, chars.length);
+ }
+
+ /**
+ * Update buffer with a single integer (only & 0xff part is used,
+ * as a byte)
+ *
+ * @param i Integer value, which is then converted to
+ * byte as i & 0xff
+ */
+
+ public void Update (int i) {
+ Update((byte) (i & 0xff));
+ }
+
+ private byte[] Encode (int input[], int len) {
+ int i, j;
+ byte out[];
+
+ out = new byte[len];
+
+ for (i = j = 0; j < len; i++, j += 4) {
+ out[j] = (byte) (input[i] & 0xff);
+ out[j + 1] = (byte) ((input[i] >>> 8) & 0xff);
+ out[j + 2] = (byte) ((input[i] >>> 16) & 0xff);
+ out[j + 3] = (byte) ((input[i] >>> 24) & 0xff);
+ }
+
+ return out;
+ }
+
+ /**
+ * Returns array of bytes (16 bytes) representing hash as of the
+ * current state of this object. Note: getting a hash does not
+ * invalidate the hash object, it only creates a copy of the real
+ * state which is finalized.
+ *
+ * @return Array of 16 bytes, the hash of all updated bytes
+ */
+ public synchronized byte[] Final () {
+ byte bits[];
+ int index, padlen;
+ MD5State fin;
+
+ if (finals == null) {
+ fin = new MD5State(state);
+
+ bits = Encode(fin.count, 8);
+
+ index = (int) ((fin.count[0] >>> 3) & 0x3f);
+ padlen = (index < 56) ? (56 - index) : (120 - index);
+
+ Update(fin, padding, 0, padlen);
+ /**/
+ Update(fin, bits, 0, 8);
+
+ /* Update() sets finalds to null */
+ finals = fin;
+ }
+
+ return Encode(finals.state, 16);
+ }
+
+ /**
+ * Turns array of bytes into string representing each byte as
+ * unsigned hex number.
+ *
+ * @param hash Array of bytes to convert to hex-string
+ * @return Generated hex string
+ */
+ public static String asHex (byte hash[]) {
+ StringBuffer buf = new StringBuffer(hash.length * 2);
+ int i;
+
+ for (i = 0; i < hash.length; i++) {
+ if (((int) hash[i] & 0xff) < 0x10)
+ buf.append("0");
+
+ buf.append(Long.toString((int) hash[i] & 0xff, 16));
+ }
+
+ return buf.toString();
+ }
+
+ /**
+ * Returns 32-character hex representation of this objects hash
+ *
+ * @return String of this object's hash
+ */
+ public String asHex () {
+ return asHex(this.Final());
+ }
+
+} // MD5
+
diff --git a/java/rasj/odmg/RasODMGImplementation.java.getFreeServer_beginTA b/java/rasj/odmg/RasODMGImplementation.java.getFreeServer_beginTA
new file mode 100644
index 0000000..2fb2cb2
--- /dev/null
+++ b/java/rasj/odmg/RasODMGImplementation.java.getFreeServer_beginTA
@@ -0,0 +1,1361 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE: ODMG Implementation Bootstrap Object
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+package rasj.odmg;
+
+import rasj.*;
+import rasj.global.*;
+import rasj.clientcommhttp.*;
+import org.odmg.*;
+
+import java.io.*;
+import java.net.*;
+import java.lang.*;
+import java.util.*;
+
+
+/**
+ * This class implements the internal ODMG Bootstrap Object used by the rasj.odmg package.
+ * Because it contains a lot of functionality for internal purposes (e.g. methods for
+ * the RasManager), this class is not the official Implementation object the user works
+ * with, it is only used by the rasj.odmg package.
+ * <P>
+ * The public Implementation object is the class
+ * {@link rasj.RasImplementation rasj.RasImplementation}, which internally works with a
+ * RasODMGImplementation object.
+ *
+ * @see rasj.RasImplementation
+ */
+
+public class RasODMGImplementation implements RasImplementationInterface,RasCommDefs//implements Implementation
+ {
+
+ private String rasServer = "";
+ private String rasMgr = "";
+ private int rasMgrPort= RasGlobalDefs.RASMGRPORT_DEFAULT;
+ private String userIdentification = RasGlobalDefs.GUESTIDENT_DEFAULT;
+ private String databaseName = "";
+ private String capability = "dummy";
+ private int maxRetry = RasGlobalDefs.MAX_GETFREESERVER_ATTEMPTS;
+
+ /**
+ * current state of transaction
+ **/
+ private boolean isOpenTA = false;
+
+ /**
+ /**
+ * This variable holds the current RasTransaction object.
+ */
+ private RasTransaction transaction = null;
+
+ /**
+ * This variable holds the current Rasdatabase object.
+ */
+ private RasDatabase database = null;
+
+ /**
+ * This variable holds the current RasOQLQuery object.
+ */
+ private RasOQLQuery query = null;
+
+ /**
+ * The standard ODMG implementation sets the access mode when the database
+ * is opened, whereas the RasDaMan server expects this information when a
+ * transaction is started. Therefore it is saved in this variable.
+ *
+ * Available modes:
+ * OPEN_READ_ONLY = 1
+ * OPEN_READ_WRITE = 2
+ * OPEN_EXCLUSIVE = 3
+ */
+ private int accessMode = 0;
+
+ /**
+ * Since ODMG does not specify a "isDatabaseOpen" method but provides a
+ * DatabaseClosedException, this variable is set to 1 if an openDB command is
+ * executed (closeDB sets it back to 0).
+ */
+ private int dbIsOpen = 0;
+
+ /**
+ * This value is set to 1 if a transaction has been opened. Commiting or aborting
+ * a transaction sets it back to 0.
+ */
+ private int taIsOpen = 0;
+
+ private int clientID = 0;
+
+ /**
+ * This value is used to store possible error messages of exceptions occuring
+ * when opening or closing transactions.
+ * The ODMG specification does not allow these operations to throw
+ * any exceptions, but our implementation could produce exceptions when connecting
+ * to the RasDaMan httpserver. In order to not get lost, these exception messages
+ * are stored in this variable.
+ */
+ private String errorStatus = "";
+ // later: private String strUserAndPasswd = "anonymous:anonymouspasswd";
+
+ /**
+ * Standard constructor.
+ * @param server Complete URL of the RasDaMan httpserver (including port number)
+ */
+ public RasODMGImplementation(String server)
+ {
+ Debug.enterVerbose( "RasODMGImplementation.constructor: start, server=" + server + "." );
+ try
+ {
+ // server address is http://server:port, we need server and port
+ StringTokenizer t=new StringTokenizer (server,"/");
+ String xxx=t.nextToken();
+ rasMgr =t.nextToken("/:");
+ String portStr = t.nextToken(":");
+ rasMgrPort = Integer.parseInt(portStr);
+ }
+ catch(NoSuchElementException e)
+ {
+ Debug.leaveVerbose( "RasODMGImplementation.constructor: done. server URL format error." );
+ throw new RasConnectionFailedException(RasGlobalDefs.URL_FORMAT_ERROR, server);
+ }
+
+ isOpenTA = false;
+
+ Debug.leaveVerbose( "RasODMGImplementation.constructor: done. ok." );
+ }
+
+ /**
+ * Gets the name of the actual server.
+ * @return the name of the RasDaMan server used
+ */
+ public String getRasServer()
+ {
+ Debug.talkVerbose( "RasODMGImplementation.getRasServer: server=" + rasServer + "." );
+ return rasServer;
+ }
+
+ /**
+ * Tells whether database is open.
+ * @return open status of database
+ */
+ public int dbIsOpen()
+ {
+ Debug.talkVerbose( "RasODMGImplementation.dbIsOpen: dbIsOpen=" + dbIsOpen + "." );
+ return dbIsOpen;
+ }
+
+ /**
+ * Gets the client ID
+ * @return ID of this client
+ */
+ public int getClientID()
+ {
+ Debug.talkVerbose( "RasODMGImplementation.getClientID: clientID=" + clientID + "." );
+ return clientID;
+ }
+
+ /**
+ * Gets the database access mode
+ * @return accessMode code: OPEN_READ_ONLY = 1; OPEN_READ_WRITE = 2; OPEN_EXCLUSIVE = 3
+ */
+ public int getAccessMode()
+ {
+ Debug.talkVerbose( "RasODMGImplementation.getAccessMode: accessMode=" + accessMode + "." );
+ return accessMode;
+ }
+
+ /**
+ * Gets the current error status
+ * @return error status string
+ */
+ public String getErrorStatus()
+ {
+ Debug.talkVerbose( "RasODMGImplementation.getErrorStatus: errorStatus=" + errorStatus + "." );
+ return errorStatus;
+ }
+
+
+ /**
+ * Create a new transaction object and associate it with the current thread.
+ */
+ public Transaction newTransaction()
+ {
+ Debug.enterVerbose( "RasODMGImplementation.newTransaction: start." );
+ transaction= new RasTransaction(this);
+ Debug.leaveVerbose( "RasODMGImplementation.newTransaction: done." );
+ return transaction;
+ }
+
+ /**
+ * Get current transaction for thread, or NULL if none.
+ */
+ public Transaction currentTransaction()
+ {
+ Debug.talkVerbose( "RasODMGImplementation.currentTransaction." );
+ return transaction;
+ }
+
+ /**
+ * Create a new database object.
+ */
+ public Database newDatabase()
+ {
+ Debug.enterVerbose( "RasODMGImplementation.newDatabase: start." );
+ database = new RasDatabase(this);
+ Debug.leaveVerbose( "RasODMGImplementation.newDatabase: done." );
+ return database;
+ }
+
+ /**
+ * Create a new query object.
+ */
+ public OQLQuery newOQLQuery()
+ {
+ Debug.enterVerbose( "RasODMGImplementation.newOQLQuery: start." );
+ query = new RasOQLQuery(this);
+ Debug.leaveVerbose( "RasODMGImplementation.newOQLQuery: done." );
+ return query;
+ }
+
+ /**
+ * Create a new DList object.
+ */
+ public DList newDList()
+ {
+ Debug.talkVerbose( "RasODMGImplementation.newDList." );
+ return new RasList();
+ }
+
+ /**
+ * Create a new DBag object.
+ */
+ public DBag newDBag()
+ {
+ return new RasBag();
+ }
+
+ /**
+ * Create a new DSet object.
+ */
+ public DSet newDSet()
+ {
+ Debug.talkVerbose( "RasODMGImplementation.newDSet." );
+ return new RasSet();
+ }
+
+ /**
+ * Not implemented yet.
+ */
+ public DArray newDArray()
+ {
+ Debug.talkWarning( "RasODMGImplementation.newDArray: not yet implemented." );
+ throw new NotImplementedException();
+ }
+
+ /**
+ * Not implemented yet.
+ */
+ public DMap newDMap()
+ {
+ Debug.talkWarning( "RasODMGImplementation.newDMap: not yet implemented." );
+ throw new NotImplementedException();
+ }
+
+ /**
+ * Get a String representation of the object's identifier.
+ * @returns: OID string on success, null otherwise
+ */
+ public String getObjectId(Object obj)
+ {
+ Debug.enterVerbose( "RasODMGImplementation.getObjectId: start." );
+
+ if( ! (obj instanceof RasObject) ) // currently all must be derived from RasObject
+ {
+ Debug.leaveWarning( "RasODMGImplementation.getObjectId: not yet implemented." );
+ throw new NotImplementedException();
+ }
+
+ // if we come here: yes, we are derived from RasObject, let's proceed
+ RasOID roid = ((RasObject)obj).getOID();
+ String oid = roid.toString();
+ DBag resultBag = null;
+ if(!((RasObject)obj).getOID().isValid()) // OID of our object is not valid -> get one
+ {
+ Debug.talkWarning( "RasODMGImplementation.getObjectId: OID not Valid: " + roid + "." );
+ String params = "ClientID=" + clientID + "&Command=10";
+ RasHttpRequest request = new RasHttpRequest();
+ if(((RasTransaction)this.currentTransaction()).isOpenLocally()) // TA is open, we can proceed
+ // (decide w/o asking server -- PB 2003-jun-25)
+ {
+ // get new oid
+ try
+ {
+ request.execute(rasServer,params); // get it from server
+ }
+ catch(RasQueryExecutionFailedException e)
+ {
+ // this cannot occur (theoretically)
+ Debug.talkCritical( "RasODMGImplementation.getObjectId: query execution failed: " + e.getMessage() );
+ }
+ }
+ else // TA is not open, so we do an open here
+ {
+ Debug.talkSparse( "RasODMGImplementation.getObjectId: db not open, opening: " + databaseName + "." );
+ boolean openedDbHere = false; // did we open a db locally?
+ boolean openedTaHere = false; // did we open a db locally?
+ Database d = null;
+ Transaction t = null;
+ try
+ {
+ if(this.dbIsOpen == Database.NOT_OPEN) // we even open the db if not done already
+ {
+ Debug.talkSparse( "RasODMGImplementation.getObjectId: db not open, opening: " + databaseName + "." );
+ d = this.newDatabase();
+ d.open( databaseName, Database.OPEN_READ_WRITE);
+ // fix: was: "RASBASE"; now: take name of last opened db. not good, but better maybe -- PB 2003-jun-13
+ // FIXME: r/w open not good, do we have info at this point? Maybe getOid needs r/w
+ openedDbHere = true;
+ }
+ t = this.newTransaction();
+ t.begin();
+ openedTaHere = true; // we know now we have an open TA
+ // get new oid
+ request.execute(rasServer,params); // get it from server
+ t.commit();
+ if(openedDbHere)
+ {
+ Debug.talkSparse( "RasODMGImplementation.getObjectId: closing locally opened DB. " );
+ d.close();
+ openedDbHere = false; // no more locally opened DB to close
+ }
+ }
+ catch(ODMGException e)
+ {
+ Debug.talkCritical( "RasODMGImplementation.getObjectId: failed: " + e.getMessage() );
+ try
+ {
+ if (openedTaHere)
+ t.abort();
+ if(openedDbHere)
+ d.close();
+ }
+ catch (ODMGException e3)
+ {
+ Debug.talkSparse( "RasODMGImplementation.getObjectId: error closing locally opened DB (ignored): " + e3.getMessage() );
+ }
+ }
+ } // if (TA open)
+
+ resultBag = (DBag)request.getResult(); // if all went fine we now have OID in result
+ if(resultBag != null)
+ {
+ Iterator iter = resultBag.iterator();
+ if(iter.hasNext())
+ roid = (RasOID)iter.next();
+ oid = roid.toString();
+ ((RasObject)obj).setOID(roid);
+ }
+ else
+ {
+ Debug.talkCritical( "RasODMGImplementation.getObjectId: empty query result, cannot fetch OID." );
+ oid = null;
+ }
+ } // valid OID
+
+ Debug.leaveVerbose( "RasODMGImplementation.getObjectId: done. oid=" + oid + "." );
+ return oid;
+ } // getObjectId()
+
+ /**
+ * Not implemented yet.
+ */
+ public Database getDatabase(Object obj)
+ {
+ Debug.talkCritical( "RasODMGImplementation.getDatabase: not yet implemented." );
+ throw new NotImplementedException();
+ }
+
+ /**
+ * Open database
+ */
+ public void openDB(String name, int accessMode) throws ODMGException, ODMGRuntimeException
+ {
+ Debug.enterVerbose( "RasODMGImplementation.openDB: start, db=" + name + ", accessMode=" + accessMode );
+
+ databaseName = name;
+ this.accessMode = accessMode;
+
+ try
+ {
+ getFreeServer(); // sets rasServer
+ executeOpenDB(databaseName,accessMode);
+ // executeCloseDB(); // does nothing, so clean away -- PB 2003-jun-25
+ dbIsOpen = 1;
+ }
+ catch (ODMGException e) // catch just for logging, then rethrow immediately
+ {
+ Debug.leaveCritical( "RasODMGImplementation.openDB: done. Exception: " + e.getMessage() );
+ throw new ODMGException( e.getMessage() );
+ }
+ catch (ODMGRuntimeException x) // catch just for logging, then rethrow immediately
+ {
+ Debug.leaveCritical( "RasODMGImplementation.openDB: done. ODMGRuntimeException: " + x.getMessage() );
+ throw new ODMGException( x.getMessage() );
+ }
+
+ Debug.leaveVerbose( "RasODMGImplementation.openDB: done. OK." );
+ }
+
+ private void executeOpenDB(String name, int accessMode) throws ODMGException
+ {
+ Debug.enterVerbose( "RasODMGImplementation.executeOpenDB: start, name=" + name + ", accessMode=" + accessMode );
+ String params = "Command=" + RasODMGGlobal.commOpenDB + "&Database=" + name + "&Capability=" + capability;
+ RasHttpRequest request = new RasHttpRequest();
+ request.execute(rasServer,params);
+ // Later, the client ID is determined here
+ clientID = 1; // not used anymore
+ Debug.leaveVerbose( "RasODMGImplementation.executeOpenDB: done." );
+ }
+
+ /**
+ * Closes an open database. At the moment, only one database can be open at
+ * a given time and thus no parameter "database" is necessary here.
+ */
+ public void closeDB() throws ODMGException
+ {
+ Debug.enterVerbose( "RasODMGImplementation.closeDB start." );
+
+ // not necessary, others do close already
+ // PB: this is due to an old bug in O2 which needed a closeDB in order to free objects, hence we do this in commitTA/abortTA
+
+ dbIsOpen = 0;
+ Debug.leaveVerbose( "RasODMGImplementation.closeDB done." );
+ }
+
+ private void executeCloseDB() throws ODMGException
+ {
+ String params = "ClientID=" + clientID + "&Command=" + RasODMGGlobal.commCloseDB;
+ RasHttpRequest request = new RasHttpRequest();
+ request.execute(rasServer,params);
+ }
+
+ /**
+ * Begin a transaction.
+ */
+ public void beginTA()
+ {
+ Debug.enterVerbose( "RasODMGImplementation.beginTA start." );
+ try
+ {
+ getFreeServer();
+ executeOpenDB(databaseName,accessMode);
+ executeBeginTA();
+ }
+ catch(ODMGException e)
+ {
+ Debug.talkWarning( "RasODMGImplementation.beginTA: " + e.getMessage() );
+ errorStatus = e.getMessage();
+ }
+ Debug.leaveVerbose( "RasODMGImplementation.beginTA done." );
+ }
+
+ private void executeBeginTA()
+ {
+ String errorMsg = "Could not open transaction: ";
+ if(dbIsOpen == 0)
+ throw new DatabaseClosedException(errorMsg + "database not open");
+
+ String params = "ClientID=" + clientID + "&Command=";
+ // Is the database opened READ_ONLY or READ_WRITE ?
+ if(accessMode == Database.OPEN_READ_ONLY)
+ params = params + RasODMGGlobal.commBTreadOnly;
+ else
+ params = params + RasODMGGlobal.commBTreadWrite;
+ params = params + "&Capability=" + capability;
+ RasHttpRequest request = new RasHttpRequest();
+ try
+ {
+ request.execute(rasServer,params);
+ }
+ catch(RasQueryExecutionFailedException e)
+ {
+ // this cannot occur (theoretically)
+ Debug.talkWarning( "RasODMGImplementation.executeBeginTA: " + e.getMessage() );
+ errorStatus = e.getMessage();
+ }
+ }
+
+ /**
+ * Returns TRUE if a transaction is currently open.
+ * This method MUST be sincere in that it asks the server about its state! (some apps use it to override timeout)
+ */
+ public boolean isOpenTA()
+ {
+ Debug.enterVerbose( "RasODMGImplementation.isOpenTA start." );
+ boolean result = false;
+
+ String params = "ClientID=" + clientID + "&Command=" + RasODMGGlobal.commIsOpenTA;
+ RasHttpRequest request = new RasHttpRequest();
+ try
+ {
+ request.execute(rasServer,params);
+ result= (request.getResultType() == 99) ? true : false;
+ }
+ catch(RasQueryExecutionFailedException e)
+ {
+ // this cannot occur (theoretically)
+ Debug.talkWarning( "RasODMGImplementation.isOpenTA: " + e.getMessage() );
+ errorStatus = e.getMessage();
+ result = false;
+ }
+
+ Debug.leaveVerbose( "RasODMGImplementation.isOpenTA done. result=" + result );
+ return result;
+ }
+
+ /**
+ * Commit a transaction.
+ */
+ public void commitTA()
+ {
+ Debug.enterVerbose( "RasODMGImplementation.commitTA start." );
+
+ try
+ {
+ executeCommitTA();
+ executeCloseDB(); // FIXME: why close here??? -- PB 2003-jun-13
+ }
+ catch(ODMGException e)
+ {
+ Debug.talkWarning( "RasODMGImplementation.commitTA: " + e.getMessage() );
+ errorStatus = e.getMessage();
+ }
+
+ Debug.leaveVerbose( "RasODMGImplementation.commitTA done." );
+ }
+
+ private void executeCommitTA()
+ {
+ String errorMsg = "Could not commit transaction: ";
+ if(dbIsOpen == 0)
+ throw new DatabaseClosedException(errorMsg + "database not open");
+ String params = "ClientID=" + clientID + "&Command=" + RasODMGGlobal.commCT;
+ RasHttpRequest request = new RasHttpRequest();
+ try
+ {
+ request.execute(rasServer,params);//RasODMGGlobal.getRasServer(),params);
+ }
+ catch(RasQueryExecutionFailedException e)
+ {
+ // this cannot occur (theoretically)
+ Debug.talkWarning( "RasODMGImplementation.executeCommitTA: " + e.getMessage() );
+ errorStatus = e.getMessage();
+ }
+ }
+
+ /**
+ * Abort a transaction.
+ */
+ public void abortTA()
+ {
+ Debug.enterVerbose( "RasODMGImplementation.abortTA start." );
+
+ try
+ {
+ executeAbortTA();
+ executeCloseDB();
+ }
+ catch(ODMGException e)
+ {
+ Debug.talkWarning( "RasODMGImplementation.abortTA: " + e.getMessage() );
+ errorStatus = e.getMessage();
+ }
+
+ Debug.leaveVerbose( "RasODMGImplementation.abortTA done." );
+ }
+
+ private void executeAbortTA()
+ {
+ String errorMsg = "Cannot abort transaction: ";
+ if(dbIsOpen == 0)
+ throw new DatabaseClosedException(errorMsg + "database not open");
+ String params = "ClientID=" + clientID + "&Command=" + RasODMGGlobal.commAT;
+ RasHttpRequest request = new RasHttpRequest();
+ try
+ {
+ request.execute(rasServer,params);
+ }
+ catch(RasQueryExecutionFailedException e)
+ {
+ // this cannot occur (theoretically)
+ Debug.talkWarning( "RasODMGImplementation.executeAbortTA: " + e.getMessage() );
+ errorStatus = e.getMessage();
+ }
+ }
+
+ /**
+ * Set the maximum retry parameter
+ */
+ public void setMaxRetry(int newRetry)
+ {
+ Debug.talkVerbose( "RasODMGImplementation.setMaxRetry to " + newRetry + "." );
+ maxRetry = newRetry;
+ }
+
+ /**
+ * Get the maximum retry parameter
+ */
+ public int getMaxRetry()
+ {
+ Debug.talkVerbose( "RasODMGImplementation.getMaxRetry: maxRetry=" + maxRetry + "." );
+ return maxRetry;
+ }
+
+ /**
+ * Requests a free server and retry's
+ */
+ //private void getFreeServer( )
+ public void getFreeServer( )
+ throws RasQueryExecutionFailedException, RasConnectionFailedException
+ {
+ Debug.enterVerbose( "RasODMGImplementation.getFreeServer: start." );
+
+ String uniqueID = uniqueRequestID();
+
+ int millisec = RasGlobalDefs.GETFREESERVER_WAIT_INITIAL;
+ for (int retryCount = 1; retryCount <= maxRetry; retryCount++)
+ {
+ try
+ {
+ executeGetFreeServer(uniqueID);
+ // if no error, we have the server, so break
+ break;
+ }
+ catch(RasConnectionFailedException e)
+ {
+ Debug.talkCritical( "RasODMGImplementation.getFreeServer: cannot obtain a free server:" + e.getMessage() );
+ // the following errors justify that we try again, maybe we get a free server a little later
+ int errno = e.getErrorNo();
+ if (errno==RasGlobalDefs.MANAGER_BUSY
+ /* || errno==RasGlobalDefs.NO_ACTIVE_SERVERS */ // if no such server is started, waiting won't help
+ || errno==RasGlobalDefs.WRITE_TRANS_IN_PROGRESS)
+ {
+ // retry, but with increasing wait period
+ millisec = millisec * RasGlobalDefs.GETFREESERVER_WAIT_INCREMENT;
+
+ Debug.talkCritical( "RasODMGImplementation.getFreeServer: no free server available, errno=" + errno + ", retry #" + retryCount + " of " + maxRetry + " after " + millisec + " msecs." );
+ try
+ {
+ Thread.sleep(millisec);
+ }
+ catch(InterruptedException intex)
+ { // wake up
+ }
+ }
+ else
+ {
+ Debug.talkCritical( "RasODMGImplementation.getFreeServer: giving up, cannot obtain free server. marking connection as closed." );
+ Debug.leaveVerbose( "RasODMGImplementation.getFreeServer: done." );
+
+ // reset ta & db
+ isOpenTA = false;
+ dbIsOpen = 0;
+ throw(e); // we give up, or we shouldn't retry with this kind of error
+ }
+ }
+ } // for
+
+ Debug.leaveVerbose( "RasODMGImplementation.getFreeServer: done." );
+ }
+
+ /**
+ * Requests a free server from rasmgr
+ */
+
+ private void executeGetFreeServer( String uniqueID ) throws RasQueryExecutionFailedException, RasConnectionFailedException
+ {
+ Debug.enterVerbose( "RasODMGImplementation.executeGetFreeServer: enter, uniqueID=" + uniqueID );
+
+ try
+ {
+ Socket soclu = new Socket(rasMgr,rasMgrPort); // FIXME: where is this socket closed ??? PB
+ Debug.talkVerbose( "RasODMGImplementation.executeGetFreeServer: socket=" + soclu );
+ PrintStream ps = new PrintStream(soclu.getOutputStream());
+ String body = databaseName + " HTTP " + (accessMode == Database.OPEN_READ_ONLY ? "ro":"rw") + " " + uniqueID + " \0";
+ ps.print("POST getfreeserver HTTP/1.1\r\nAccept: text/plain\r\nContent-type: text/plain\r\n"
+ + "User-Agent: RasDaMan Java Client1.0\r\nAuthorization: ras " + userIdentification
+ + "\r\nContent length: " + body.length()+"\r\n\r\n" + body);
+ ps.flush();
+ Debug.talkVerbose( "RasODMGImplementation.executeGetFreeServer: sent body=" + body );
+
+ BufferedReader ds = new BufferedReader(new InputStreamReader(soclu.getInputStream()));
+ int resultCode = getResultCode(ds);
+ String bodyLine = getBodyLine(ds);
+ Debug.talkVerbose( "RasODMGImplementation.executeGetFreeServer: received result code=" + resultCode + ", bodyLine=" + bodyLine );
+
+ ps.close();
+ ds.close();
+ soclu.close(); // this one was missing all the time -- PB
+ Debug.talkVerbose( "RasODMGImplementation.executeGetFreeServer: socket closed: " + soclu );
+
+ if(resultCode==200)
+ {
+ StringTokenizer t=new StringTokenizer(bodyLine," ");
+ String host=t.nextToken();
+ String port=t.nextToken(" ");
+ capability=t.nextToken(" \t\r\n\0");
+ rasServer="http://" + host + ":" + port;
+ }
+ else
+ {
+ // if error =>bodyLine: errorCode someText
+ Debug.talkSparse( "RasODMGImplementation.executeGetFreeServer: bodyLine=" + bodyLine);
+ StringTokenizer t=new StringTokenizer(bodyLine," ");
+ String errorStr = t.nextToken();
+ int errorCode = Integer.parseInt(errorStr);
+ if( resultCode < 1000 )
+ {
+ Debug.leaveVerbose( "RasODMGImplementation.executeGetFreeServer: done. connection failed, code=" + errorCode );
+ throw new RasConnectionFailedException(errorCode,null);
+ }
+ else
+ {
+ Debug.leaveVerbose( "RasODMGImplementation.executeGetFreeServer: done. request format error, code=" + errorCode );
+ throw new RasConnectionFailedException(RasGlobalDefs.REQUEST_FORMAT_ERROR," code=" + errorCode);
+ }
+ }
+ }
+ catch( MalformedURLException e )
+ {
+ Debug.talkCritical( "RasODMGImplementation.executeGetFreeServer: malformed URL exception: " + e.getMessage() );
+ Debug.leaveVerbose( "RasODMGImplementation.executeGetFreeServer: done with exception: " + e.getMessage() );
+ throw new RasConnectionFailedException(RasGlobalDefs.MANAGER_CONN_FAILED,rasMgr);
+ }
+ catch( IOException e )
+ {
+ Debug.talkCritical( "RasODMGImplementation.executeGetFreeServer: IO exception: " + e.getMessage() );
+ Debug.leaveVerbose( "RasODMGImplementation.executeGetFreeServer: done with exception: " + e.getMessage() );
+ throw new RasClientInternalException( "RasODMGImplementation","executeGetFreeServer()", e.getMessage() );
+ }
+
+ Debug.leaveVerbose( "RasODMGImplementation.executeGetFreeServer: done." );
+ } // executeGetFreeServer()
+
+ public Object queryRequest(String parameters) throws RasQueryExecutionFailedException
+ {
+ Debug.enterVerbose( "RasODMGImplementation.queryRequest start. parameters=" + parameters + "." );
+
+ BenchmarkTimer qTimer = new BenchmarkTimer("queryRequest");
+ qTimer.startTimer();
+
+ RasHttpRequest request= new RasHttpRequest();
+ request.execute(rasServer,parameters);
+
+ qTimer.stopTimer();
+ qTimer.print();
+
+ Debug.leaveVerbose( "RasODMGImplementation.executeGetFreeServer done." );
+ return request.getResult();
+ }
+
+
+ //private int getResultCode(BufferedReader ds) throws IOException
+ public int getResultCode(BufferedReader ds) throws IOException
+ {
+ Debug.enterVerbose( "RasODMGImplementation.getResultCode start." );
+
+ String s = ds.readLine();
+ StringTokenizer t = new StringTokenizer(s," ");
+ String http = t.nextToken();
+ String resultString = t.nextToken(" ");
+ int result = Integer.parseInt(resultString);
+
+ Debug.leaveVerbose( "RasODMGImplementation.getResultCode done. result=" + result + "." );
+ return result;
+ }
+
+ //private String getBodyLine(BufferedReader ds) throws IOException
+ public String getBodyLine(BufferedReader ds) throws IOException
+ {
+ Debug.enterVerbose( "RasODMGImplementation.getBodyLine start." );
+
+ String s;
+ do // was a "for(;;)" loop, cleaned it -- PB 2003-jun-13
+ {
+ s = ds.readLine();
+ if(s==null)
+ {
+ Debug.talkCritical( "RasODMGImplementation.getBodyLine: Unexpected EOF in rasmgr answer." );
+ throw new IOException("Unexpected EOF in rasmgr answer.");
+ }
+ }
+ while (s.length() != 0);
+
+ String result = ds.readLine();
+ Debug.leaveVerbose( "RasODMGImplementation.getBodyLine done. result=" + result + "." );
+ return result;
+ }
+
+ public void setUserIdentification(String userName, String plainPass)
+ {
+ Debug.enterVerbose( "RasODMGImplementation.setUserIdentification start." );
+
+ MD5 md5 = new MD5();
+ String hex;
+ md5.Init();
+ md5.Update(plainPass);
+ hex = md5.asHex();
+ userIdentification= userName + ":" + hex;
+
+ Debug.leaveVerbose( "RasODMGImplementation.setUserIdentification done." );
+ }
+
+ private String strHostID = null;
+ static private int idcounter = 0;
+
+ private String uniqueRequestID()
+ {
+ Debug.enterVerbose( "RasODMGImplementation.uniqueRequestID start." );
+
+ if(strHostID == null)
+ {
+ long hostid = 0;
+ try
+ {
+ InetAddress addr = InetAddress.getLocalHost();
+ // Get IP Address
+ byte[] ipAddr = addr.getAddress();
+
+ for(int i=0;i<ipAddr.length; i++)
+ {
+ int ss = (int)ipAddr[i];
+ if(ss<0)
+ ss = 256 + ss;
+ hostid = hostid * 256 + ss;
+ }
+ }
+ catch (UnknownHostException e)
+ {
+ Random random = new Random();
+ hostid = random.nextInt();
+ }
+ idcounter = (idcounter + 1) & 0xF;
+ // it's unique enough, we don't need such a huge number
+ strHostID = "" + hostid + ':' + (System.currentTimeMillis() & 0xFFFFFFF0) + idcounter;
+ }
+
+ Debug.leaveVerbose( "RasODMGImplementation.uniqueRequestID done. strHostID=" + strHostID + "." );
+ return strHostID;
+ }
+
+}
+
+//##################################################################################
+/**
+ * Contains internal state of the MD5 class
+ */
+
+class MD5State
+ {
+ /**
+ * 128-byte state
+ */
+ int state[];
+
+ /**
+ * 64-bit character count (could be true Java long?)
+ */
+ int count[];
+
+ /**
+ * 64-byte buffer (512 bits) for storing to-be-hashed characters
+ */
+ byte buffer[];
+
+ public MD5State()
+ {
+ Debug.enterVerbose( "MD5State.constructor start." );
+
+ buffer = new byte[64];
+ count = new int[2];
+ state = new int[4];
+
+ state[0] = 0x67452301;
+ state[1] = 0xefcdab89;
+ state[2] = 0x98badcfe;
+ state[3] = 0x10325476;
+
+ count[0] = count[1] = 0;
+
+ Debug.leaveVerbose( "MD5State.constructor done." );
+ }
+
+ /**
+ Create this State as a copy of another state
+ **/
+ public MD5State (MD5State from)
+ {
+ this();
+
+ Debug.enterVerbose( "MD5State.cloner start." );
+
+ int i;
+
+ for (i = 0; i < buffer.length; i++)
+ this.buffer[i] = from.buffer[i];
+
+ for (i = 0; i < state.length; i++)
+ this.state[i] = from.state[i];
+
+ for (i = 0; i < count.length; i++)
+ this.count[i] = from.count[i];
+
+ Debug.leaveVerbose( "MD5State.cloner done." );
+ }
+
+ }; // MD5State
+
+/**
+ * Implementation of RSA's MD5 hash generator
+ *
+ * @version $Revision: 1.24 $
+ * @author Santeri Paavolainen <sjpaavol@cc.helsinki.fi>
+ */
+
+class MD5
+{
+ /**
+ * MD5 state
+ */
+ MD5State state;
+
+ /**
+ * If Final() has been called, finals is set to the current finals
+ * state. Any Update() causes this to be set to null.
+ */
+ MD5State finals;
+
+ /**
+ * Padding for Final()
+ */
+ static byte padding[] = {
+ (byte) 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ /**
+ * Initialize MD5 internal state (object can be reused just by
+ * calling Init() after every Final()
+ */
+ public synchronized void Init () {
+ state = new MD5State();
+ finals = null;
+ }
+
+ /**
+ * Class constructor
+ */
+ public MD5 () {
+ this.Init();
+ }
+
+ /**
+ * Initialize class, and update hash with ob.toString()
+ *
+ * @param ob Object, ob.toString() is used to update hash
+ * after initialization
+ */
+ public MD5 (Object ob) {
+ this();
+ Update(ob.toString());
+ }
+
+ private int rotate_left (int x, int n) {
+ return (x << n) | (x >>> (32 - n));
+ }
+
+ /* I wonder how many loops and hoops you'll have to go through to
+ get unsigned add for longs in java */
+
+ private int uadd (int a, int b) {
+ long aa, bb;
+ aa = ((long) a) & 0xffffffffL;
+ bb = ((long) b) & 0xffffffffL;
+
+ aa += bb;
+
+ return (int) (aa & 0xffffffffL);
+ }
+
+ private int uadd (int a, int b, int c) {
+ return uadd(uadd(a, b), c);
+ }
+
+ private int uadd (int a, int b, int c, int d) {
+ return uadd(uadd(a, b, c), d);
+ }
+
+ private int FF (int a, int b, int c, int d, int x, int s, int ac) {
+ a = uadd(a, ((b & c) | (~b & d)), x, ac);
+ return uadd(rotate_left(a, s), b);
+ }
+
+ private int GG (int a, int b, int c, int d, int x, int s, int ac) {
+ a = uadd(a, ((b & d) | (c & ~d)), x, ac);
+ return uadd(rotate_left(a, s), b);
+ }
+
+ private int HH (int a, int b, int c, int d, int x, int s, int ac) {
+ a = uadd(a, (b ^ c ^ d), x, ac);
+ return uadd(rotate_left(a, s) , b);
+ }
+
+ private int II (int a, int b, int c, int d, int x, int s, int ac) {
+ a = uadd(a, (c ^ (b | ~d)), x, ac);
+ return uadd(rotate_left(a, s), b);
+ }
+
+ private int[] Decode (byte buffer[], int len, int shift) {
+ int out[];
+ int i, j;
+
+ out = new int[16];
+
+ for (i = j = 0; j < len; i++, j += 4) {
+ out[i] = ((int) (buffer[j + shift] & 0xff)) |
+ (((int) (buffer[j + 1 + shift] & 0xff)) << 8) |
+ (((int) (buffer[j + 2 + shift] & 0xff)) << 16) |
+ (((int) (buffer[j + 3 + shift] & 0xff)) << 24);
+
+/* System.out.println("out[" + i + "] = \t" +
+ ((int) buffer[j + 0 + shift] & 0xff) + "\t|\t" +
+ ((int) buffer[j + 1 + shift] & 0xff) + "\t|\t" +
+ ((int) buffer[j + 2 + shift] & 0xff) + "\t|\t" +
+ ((int) buffer[j + 3 + shift] & 0xff));*/
+ }
+
+ return out;
+ }
+
+ private void Transform (MD5State state, byte buffer[], int shift) {
+ int
+ a = state.state[0],
+ b = state.state[1],
+ c = state.state[2],
+ d = state.state[3],
+ x[];
+
+ x = Decode(buffer, 64, shift);
+
+ /* Round 1 */
+ a = FF (a, b, c, d, x[ 0], 7, 0xd76aa478); /* 1 */
+ d = FF (d, a, b, c, x[ 1], 12, 0xe8c7b756); /* 2 */
+ c = FF (c, d, a, b, x[ 2], 17, 0x242070db); /* 3 */
+ b = FF (b, c, d, a, x[ 3], 22, 0xc1bdceee); /* 4 */
+ a = FF (a, b, c, d, x[ 4], 7, 0xf57c0faf); /* 5 */
+ d = FF (d, a, b, c, x[ 5], 12, 0x4787c62a); /* 6 */
+ c = FF (c, d, a, b, x[ 6], 17, 0xa8304613); /* 7 */
+ b = FF (b, c, d, a, x[ 7], 22, 0xfd469501); /* 8 */
+ a = FF (a, b, c, d, x[ 8], 7, 0x698098d8); /* 9 */
+ d = FF (d, a, b, c, x[ 9], 12, 0x8b44f7af); /* 10 */
+ c = FF (c, d, a, b, x[10], 17, 0xffff5bb1); /* 11 */
+ b = FF (b, c, d, a, x[11], 22, 0x895cd7be); /* 12 */
+ a = FF (a, b, c, d, x[12], 7, 0x6b901122); /* 13 */
+ d = FF (d, a, b, c, x[13], 12, 0xfd987193); /* 14 */
+ c = FF (c, d, a, b, x[14], 17, 0xa679438e); /* 15 */
+ b = FF (b, c, d, a, x[15], 22, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+ a = GG (a, b, c, d, x[ 1], 5, 0xf61e2562); /* 17 */
+ d = GG (d, a, b, c, x[ 6], 9, 0xc040b340); /* 18 */
+ c = GG (c, d, a, b, x[11], 14, 0x265e5a51); /* 19 */
+ b = GG (b, c, d, a, x[ 0], 20, 0xe9b6c7aa); /* 20 */
+ a = GG (a, b, c, d, x[ 5], 5, 0xd62f105d); /* 21 */
+ d = GG (d, a, b, c, x[10], 9, 0x2441453); /* 22 */
+ c = GG (c, d, a, b, x[15], 14, 0xd8a1e681); /* 23 */
+ b = GG (b, c, d, a, x[ 4], 20, 0xe7d3fbc8); /* 24 */
+ a = GG (a, b, c, d, x[ 9], 5, 0x21e1cde6); /* 25 */
+ d = GG (d, a, b, c, x[14], 9, 0xc33707d6); /* 26 */
+ c = GG (c, d, a, b, x[ 3], 14, 0xf4d50d87); /* 27 */
+ b = GG (b, c, d, a, x[ 8], 20, 0x455a14ed); /* 28 */
+ a = GG (a, b, c, d, x[13], 5, 0xa9e3e905); /* 29 */
+ d = GG (d, a, b, c, x[ 2], 9, 0xfcefa3f8); /* 30 */
+ c = GG (c, d, a, b, x[ 7], 14, 0x676f02d9); /* 31 */
+ b = GG (b, c, d, a, x[12], 20, 0x8d2a4c8a); /* 32 */
+
+ /* Round 3 */
+ a = HH (a, b, c, d, x[ 5], 4, 0xfffa3942); /* 33 */
+ d = HH (d, a, b, c, x[ 8], 11, 0x8771f681); /* 34 */
+ c = HH (c, d, a, b, x[11], 16, 0x6d9d6122); /* 35 */
+ b = HH (b, c, d, a, x[14], 23, 0xfde5380c); /* 36 */
+ a = HH (a, b, c, d, x[ 1], 4, 0xa4beea44); /* 37 */
+ d = HH (d, a, b, c, x[ 4], 11, 0x4bdecfa9); /* 38 */
+ c = HH (c, d, a, b, x[ 7], 16, 0xf6bb4b60); /* 39 */
+ b = HH (b, c, d, a, x[10], 23, 0xbebfbc70); /* 40 */
+ a = HH (a, b, c, d, x[13], 4, 0x289b7ec6); /* 41 */
+ d = HH (d, a, b, c, x[ 0], 11, 0xeaa127fa); /* 42 */
+ c = HH (c, d, a, b, x[ 3], 16, 0xd4ef3085); /* 43 */
+ b = HH (b, c, d, a, x[ 6], 23, 0x4881d05); /* 44 */
+ a = HH (a, b, c, d, x[ 9], 4, 0xd9d4d039); /* 45 */
+ d = HH (d, a, b, c, x[12], 11, 0xe6db99e5); /* 46 */
+ c = HH (c, d, a, b, x[15], 16, 0x1fa27cf8); /* 47 */
+ b = HH (b, c, d, a, x[ 2], 23, 0xc4ac5665); /* 48 */
+
+ /* Round 4 */
+ a = II (a, b, c, d, x[ 0], 6, 0xf4292244); /* 49 */
+ d = II (d, a, b, c, x[ 7], 10, 0x432aff97); /* 50 */
+ c = II (c, d, a, b, x[14], 15, 0xab9423a7); /* 51 */
+ b = II (b, c, d, a, x[ 5], 21, 0xfc93a039); /* 52 */
+ a = II (a, b, c, d, x[12], 6, 0x655b59c3); /* 53 */
+ d = II (d, a, b, c, x[ 3], 10, 0x8f0ccc92); /* 54 */
+ c = II (c, d, a, b, x[10], 15, 0xffeff47d); /* 55 */
+ b = II (b, c, d, a, x[ 1], 21, 0x85845dd1); /* 56 */
+ a = II (a, b, c, d, x[ 8], 6, 0x6fa87e4f); /* 57 */
+ d = II (d, a, b, c, x[15], 10, 0xfe2ce6e0); /* 58 */
+ c = II (c, d, a, b, x[ 6], 15, 0xa3014314); /* 59 */
+ b = II (b, c, d, a, x[13], 21, 0x4e0811a1); /* 60 */
+ a = II (a, b, c, d, x[ 4], 6, 0xf7537e82); /* 61 */
+ d = II (d, a, b, c, x[11], 10, 0xbd3af235); /* 62 */
+ c = II (c, d, a, b, x[ 2], 15, 0x2ad7d2bb); /* 63 */
+ b = II (b, c, d, a, x[ 9], 21, 0xeb86d391); /* 64 */
+
+ state.state[0] += a;
+ state.state[1] += b;
+ state.state[2] += c;
+ state.state[3] += d;
+ }
+
+ /**
+ * Updates hash with the bytebuffer given (using at maximum length bytes from
+ * that buffer)
+ *
+ * @param state Which state is updated
+ * @param buffer Array of bytes to be hashed
+ * @param offset Offset to buffer array
+ * @param length Use at maximum `length' bytes (absolute
+ * maximum is buffer.length)
+ */
+ public void Update (MD5State stat, byte buffer[], int offset, int length) {
+ int index, partlen, i, start;
+
+/* System.out.print("Offset = " + offset + "\tLength = " + length + "\t");
+ System.out.print("Buffer = ");
+ for (i = 0; i < buffer.length; i++)
+ System.out.print((int) (buffer[i] & 0xff) + " ");
+ System.out.print("\n");*/
+
+ finals = null;
+
+ /* Length can be told to be shorter, but not inter */
+ if ((length - offset)> buffer.length)
+ length = buffer.length - offset;
+
+ /* compute number of bytes mod 64 */
+ index = (int) (stat.count[0] >>> 3) & 0x3f;
+
+ if ((stat.count[0] += (length << 3)) <
+ (length << 3))
+ stat.count[1]++;
+
+ stat.count[1] += length >>> 29;
+
+ partlen = 64 - index;
+
+ if (length >= partlen) {
+ for (i = 0; i < partlen; i++)
+ stat.buffer[i + index] = buffer[i + offset];
+
+ Transform(stat, stat.buffer, 0);
+
+ for (i = partlen; (i + 63) < length; i+= 64)
+ Transform(stat, buffer, i);
+
+ index = 0;
+ } else
+ i = 0;
+
+ /* buffer remaining input */
+ if (i < length) {
+ start = i;
+ for (; i < length; i++)
+ stat.buffer[index + i - start] = buffer[i + offset];
+ }
+ }
+
+ /*
+ * Update()s for other datatypes than byte[] also. Update(byte[], int)
+ * is only the main driver.
+ */
+
+ /**
+ * Plain update, updates this object
+ */
+
+ public void Update (byte buffer[], int offset, int length) {
+ Update(this.state, buffer, offset, length);
+ }
+
+ public void Update (byte buffer[], int length) {
+ Update(this.state, buffer, 0, length);
+ }
+
+ /**
+ * Updates hash with given array of bytes
+ *
+ * @param buffer Array of bytes to use for updating the hash
+ */
+ public void Update (byte buffer[]) {
+ Update(buffer, 0, buffer.length);
+ }
+
+ /**
+ * Updates hash with a single byte
+ *
+ * @param b Single byte to update the hash
+ */
+ public void Update (byte b) {
+ byte buffer[] = new byte[1];
+ buffer[0] = b;
+
+ Update(buffer, 1);
+ }
+
+ /**
+ * Update buffer with given string.
+ *
+ * @param s String to be update to hash (is used as
+ * s.getBytes())
+ */
+ public void Update (String s) {
+ byte chars[];
+
+ /* deprecated chars = new byte[s.length()];
+ s.getBytes(0, s.length(), chars, 0);
+ */
+ chars = s.getBytes();
+
+ Update(chars, chars.length);
+ }
+
+ /**
+ * Update buffer with a single integer (only & 0xff part is used,
+ * as a byte)
+ *
+ * @param i Integer value, which is then converted to
+ * byte as i & 0xff
+ */
+
+ public void Update (int i) {
+ Update((byte) (i & 0xff));
+ }
+
+ private byte[] Encode (int input[], int len) {
+ int i, j;
+ byte out[];
+
+ out = new byte[len];
+
+ for (i = j = 0; j < len; i++, j += 4) {
+ out[j] = (byte) (input[i] & 0xff);
+ out[j + 1] = (byte) ((input[i] >>> 8) & 0xff);
+ out[j + 2] = (byte) ((input[i] >>> 16) & 0xff);
+ out[j + 3] = (byte) ((input[i] >>> 24) & 0xff);
+ }
+
+ return out;
+ }
+
+ /**
+ * Returns array of bytes (16 bytes) representing hash as of the
+ * current state of this object. Note: getting a hash does not
+ * invalidate the hash object, it only creates a copy of the real
+ * state which is finalized.
+ *
+ * @return Array of 16 bytes, the hash of all updated bytes
+ */
+ public synchronized byte[] Final () {
+ byte bits[];
+ int index, padlen;
+ MD5State fin;
+
+ if (finals == null) {
+ fin = new MD5State(state);
+
+ bits = Encode(fin.count, 8);
+
+ index = (int) ((fin.count[0] >>> 3) & 0x3f);
+ padlen = (index < 56) ? (56 - index) : (120 - index);
+
+ Update(fin, padding, 0, padlen);
+ /**/
+ Update(fin, bits, 0, 8);
+
+ /* Update() sets finalds to null */
+ finals = fin;
+ }
+
+ return Encode(finals.state, 16);
+ }
+
+ /**
+ * Turns array of bytes into string representing each byte as
+ * unsigned hex number.
+ *
+ * @param hash Array of bytes to convert to hex-string
+ * @return Generated hex string
+ */
+ public static String asHex (byte hash[]) {
+ StringBuffer buf = new StringBuffer(hash.length * 2);
+ int i;
+
+ for (i = 0; i < hash.length; i++) {
+ if (((int) hash[i] & 0xff) < 0x10)
+ buf.append("0");
+
+ buf.append(Long.toString((int) hash[i] & 0xff, 16));
+ }
+
+ return buf.toString();
+ }
+
+ /**
+ * Returns 32-character hex representation of this objects hash
+ *
+ * @return String of this object's hash
+ */
+ public String asHex () {
+ return asHex(this.Final());
+ }
+
+} // MD5
+
diff --git a/java/rasj/odmg/RasOID.class b/java/rasj/odmg/RasOID.class
new file mode 100644
index 0000000..6911374
--- /dev/null
+++ b/java/rasj/odmg/RasOID.class
Binary files differ
diff --git a/java/rasj/odmg/RasOID.java b/java/rasj/odmg/RasOID.java
new file mode 100644
index 0000000..9ebd948
--- /dev/null
+++ b/java/rasj/odmg/RasOID.java
@@ -0,0 +1,153 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+package rasj.odmg;
+
+import java.util.*;
+
+/**
+ * class represents an object identifier
+ */
+public class RasOID
+{
+ static final String rcsid = "@(#)Package rasj.odmg, class RasOID: $Header: /home/rasdev/CVS-repository/rasdaman/java/rasj/odmg/RasOID.java,v 1.5 2003/12/10 21:04:30 rasdev Exp $";
+
+ /**
+ * system name
+ */
+ private String systemName;
+
+ /**
+ * database name
+ */
+ private String baseName;
+
+ /**
+ * local oid
+ */
+ private double localOID;
+
+ /**
+ * default constructor
+ */
+ public RasOID()
+ {
+ systemName = "";
+ baseName = "";
+ localOID = 0;
+ }
+
+
+ /**
+ * constructor
+ */
+ public RasOID(String system, String base, double oid)
+ {
+ systemName = system;
+ baseName = base;
+ localOID = oid;
+ }
+
+ /**
+ * String constructor
+ */
+ public RasOID(String oidString)
+ {
+ StringTokenizer str = new StringTokenizer(oidString, "|");
+ if(str.hasMoreTokens())
+ systemName = str.nextToken();
+ if(str.hasMoreTokens())
+ baseName = str.nextToken();
+ if(str.hasMoreTokens())
+ localOID = Double.parseDouble(str.nextToken());
+ }
+
+ /**
+ * returns system name as a string
+ */
+ public String getSystemName()
+ {
+ return systemName;
+ }
+
+ /**
+ * returns database name as a string
+ */
+ public String getBaseName()
+ {
+ return baseName;
+ }
+
+ /**
+ * returns local oid as a double
+ */
+ public double getLocalOID()
+ {
+ return localOID;
+ }
+
+ /**
+ * determines if oid is valid
+ */
+ public boolean isValid()
+ {
+ if (localOID != 0.0)
+ return true;
+ else
+ return false;
+ }
+
+
+ public void rasDeactivate()
+ {
+ if(!systemName.equals(""))
+ {
+ systemName = "";
+ }
+
+ if(!baseName.equals(""))
+ {
+ baseName = "";
+ }
+ }
+
+
+ /** gets the String representation of the oid */
+ public String toString()
+ {
+ return systemName+"|"+baseName+"|"+localOID;
+ }
+
+}
+
diff --git a/java/rasj/odmg/RasOQLQuery.class b/java/rasj/odmg/RasOQLQuery.class
new file mode 100644
index 0000000..08eefbe
--- /dev/null
+++ b/java/rasj/odmg/RasOQLQuery.class
Binary files differ
diff --git a/java/rasj/odmg/RasOQLQuery.java b/java/rasj/odmg/RasOQLQuery.java
new file mode 100644
index 0000000..939a92e
--- /dev/null
+++ b/java/rasj/odmg/RasOQLQuery.java
@@ -0,0 +1,425 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+package rasj.odmg;
+
+import org.odmg.*;
+import rasj.*;
+import rasj.clientcommhttp.*;
+import rasj.global.*;
+
+import java.util.*;
+import java.io.*;
+
+/**
+ * This class implements the ODMG OQLQuery interface.
+ *
+ * @version 1.0 (07-Apr-2000)
+ *
+ * @author Peter Zoller
+ */
+public class RasOQLQuery implements OQLQuery, RasCommDefs
+{
+ /**
+ * This variable holds a reference to the RasImplementation object which created
+ * this RasOQLQuery object
+ */
+
+ //private RasODMGImplementation rasImplementation=null;
+ private RasImplementationInterface rasImplementation=null;
+
+ /**
+ * Stores the query string.
+ */
+ private String queryString = "";
+
+ /**
+ * Stores the MDD parameter list
+ */
+ private LinkedList qParams = null;
+
+ /**
+ * Stores the number of MDD parameters
+ */
+ private int numberOfParams = 0;
+
+ /**
+ * Constructor
+ */
+ public RasOQLQuery(RasImplementationInterface imp)//RasODMGImplementation imp)
+ {
+ Debug.enterVerbose( "RasOQLQuery.constructor start." );
+ rasImplementation=imp;
+ Debug.leaveVerbose( "RasOQLQuery.constructor done." );
+ }
+
+ /**
+ * Defines the query to be executed.
+ *
+ * @param query The OQL query string.
+ */
+ public void create(String query) throws QueryInvalidException
+ {
+ Debug.talkVerbose( "RasOQLQuery.create query=" + query );
+ queryString = query;
+ }
+
+ /**
+ * Binds a parameter to the query.
+ */
+ public void bind(Object parameter)
+ throws QueryParameterCountInvalidException, QueryParameterTypeInvalidException
+ {
+ Debug.enterVerbose( "RasOQLQuery.bind start." );
+
+ // add the parameter to the set
+ if(qParams == null) qParams = new LinkedList();
+ qParams.add(parameter);
+ numberOfParams++;
+
+ Debug.enterVerbose( "RasOQLQuery.bind done." );
+ }
+
+ /**
+ * Execute the OQL query.
+ */
+ public Object execute() throws QueryException
+ {
+ Debug.enterVerbose( "RasOQLQuery.execute start." );
+
+ BenchmarkTimer rasjQueryTimer = new BenchmarkTimer("rasjQuery");
+ rasjQueryTimer.startTimer();
+
+ String mddData = null;
+ String params = null;
+ String dummy = null;
+ //RasHttpRequest request;
+ Object item;
+ StringBuffer buff;
+ int offset;
+ int buffIndex;
+ Object result = null;
+
+ try
+ {
+ String errorMsg = "Could not execute OQL-Query: ";
+ // test if database is open
+ if(rasImplementation.dbIsOpen() == 0)
+ {
+ Debug.leaveVerbose( "RasQOLQuery.execute done. database not open." );
+ throw new DatabaseClosedException(errorMsg + "database not open");
+ }
+
+ // test if we have an open transaction
+ params = "ClientID=" + rasImplementation.getClientID() + "&Command=" + RasODMGGlobal.commIsOpenTA;
+
+ /*
+ request = new RasHttpRequest();
+
+ request.execute(rasImplementation.getRasServer(),params);//RasODMGGlobal.getRasServer(),params);
+ if(request.getResultType() == 98)
+ throw new TransactionNotInProgressException(errorMsg + "no open transaction");
+ */
+ if(rasImplementation.isOpenTA()==false)
+ {
+ Debug.leaveVerbose( "RasQOLQuery.execute done. Error: no open transaction." );
+ throw new TransactionNotInProgressException(errorMsg + "no open transaction");
+ }
+
+ // test for correct number of query parameters
+ StringTokenizer strTok = new StringTokenizer(queryString);
+ String token = "";
+ int counter = 0;
+ while(strTok.hasMoreTokens())
+ {
+ token = strTok.nextToken();
+ if(token.charAt(0) == '$')
+ {
+ try
+ {
+ if(Integer.parseInt(token.substring(1, 2)) > counter)
+ counter++;
+ }
+ catch(NumberFormatException e)
+ {
+ // should not happen!
+ Debug.leaveVerbose( "RasOQLQuery.execute done. number format exception in query parsing." );
+ throw new QueryParameterCountInvalidException("There are was a NumberFormatException while parsing the query.");
+ }
+ }
+ }
+ if(counter != numberOfParams)
+ {
+ Debug.leaveVerbose( "RasOQLQuery.execute done. number of parameters does not match query." );
+ throw new QueryParameterCountInvalidException( counter + " variable(s) in the query string vs. " + numberOfParams + " parameter(s) bound to the query.");
+ }
+
+ // process the parameters
+ dummy = queryString.trim();
+ queryString = dummy;
+ if(numberOfParams > 0)
+ {
+ counter = 0;
+ ListIterator iter = qParams.listIterator(0);
+ while (iter.hasNext())
+ {
+ counter++;
+ item = iter.next();
+ if(item instanceof RasGMArray)
+ {
+ // we have a MDD parameter => substitute the $x occurance in
+ // the query string with #MDDx# and get the transfer encoding of
+ // the MDDs. The format is specified in the file
+ // clientcommhttp/RasHttprequest.java.
+ RasGMArray mdd = (RasGMArray)item;
+ if(mddData == null)
+ mddData = utils.getTransferEncoding(mdd);
+ else
+ mddData = mddData + utils.getTransferEncoding(mdd);
+ queryString = utils.substitute(queryString,"$"+counter,"#MDD"+counter+"#");
+ }
+ else
+ {
+ // no MDD parameter => substitute each occurence of the
+ // corresponding $ parameter in the query string with the
+ // value of this parameter
+ queryString = utils.substitute(queryString,"$"+counter,item.toString());
+ iter.remove();
+ numberOfParams--;
+ }
+ }
+ }
+
+ // what kind of query do we have?
+ // FIXME: this way you don't see it keyword is in comment, and you miss mixed case!! -- PB 2003-jun-15
+ if((queryString.indexOf("select") != -1) || (queryString.indexOf("SELECT") != -1))
+ {
+ //select query
+ params = "Command=" + RasODMGGlobal.commQueryExec + "&ClientID=" +
+ rasImplementation.getClientID() + "&QueryString=" + queryString;
+ }
+ else
+ {
+ // update query
+ params = "Command=" + RasODMGGlobal.commUpdateQueryExec + "&ClientID=" +
+ rasImplementation.getClientID() + "&QueryString=" + queryString +
+ "&Endianess=" + BIG_ENDIAN + "&NumberOfQueryParameters=" +
+ numberOfParams;
+ if(numberOfParams > 0)
+ params = params + "&BinDataSize=" + mddData.length() + "&BinData=" + mddData;
+ }
+
+ //request.execute(rasImplementation.getRasServer(),params);//RasODMGGlobal.getRasServer(),params);
+ //return request.getResult();
+ result = rasImplementation.queryRequest(params);
+ }
+ catch(RasQueryExecutionFailedException e)
+ {
+ Debug.leaveVerbose( "RasOQLQuery.execute done. query execution failed: " + e.getMessage() );
+ throw new QueryException(e.getMessage());
+ }
+ catch(IOException e2)
+ {
+ Debug.leaveVerbose( "RasOQLQuery.execute done. error while generating transfer encoding: " + e2.getMessage() );
+ throw new QueryException("Error while generating transfer encoding:\n" + e2.getMessage());
+ }
+
+ rasjQueryTimer.stopTimer();
+ rasjQueryTimer.print();
+
+ Debug.leaveVerbose( "RasOQLQuery.execute done. result=" + result );
+ return result;
+ } // execute()
+
+} // RasOQLQuery
+
+/*
+ * Utilities
+ */
+
+abstract class utils
+ {
+ static String substitute(final String sourceString, final String oldString, final String newString)
+ {
+ Debug.enterVerbose( "utils.substitute start." );
+
+ StringBuffer buff = new StringBuffer(sourceString);
+ int offset = 0;
+ int buffIndex = sourceString.indexOf(oldString,offset);
+ while(buffIndex != -1)
+ {
+ buff.replace(buffIndex,buffIndex+oldString.length(),newString);
+ offset = buffIndex+1;
+ buffIndex = buff.toString().indexOf(oldString,offset);
+ }
+
+ String result = buff.toString();
+ Debug.leaveVerbose( "utils.substitute done. result=" + result );
+ return result;
+ }
+
+ /** returns a byte array representing the GMArray. This byte array is used for uploading query
+ * parameters to the server.
+ * The exact format of the byte array is described in the documentation of class
+ * @see rasj.clientcommhttp.RasHttpRequest.
+ */
+ static String getTransferEncoding(RasGMArray mdd) throws IOException
+ {
+ Debug.enterVerbose( "utils.getTransferEncoding start." );
+
+ String tileDomain = null;
+ RasMInterval domain = mdd.spatialDomain();
+ long typeLength = mdd.getTypeLength();
+
+ ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+ DataOutputStream dStream = new DataOutputStream(outStream);
+
+ // get tilingDomain from the storageLayout object
+ if(mdd.getStorageLayout().getSpatialDomain() == null)
+ {
+ tileDomain = getTilingDomain(domain,typeLength,mdd.getStorageLayout());
+ }
+ else
+ tileDomain = mdd.getStorageLayout().getSpatialDomain().toString();
+
+
+ // write object type
+ //dStream.writeInt((int)getObjectType());
+ dStream.writeInt(1);
+ dStream.writeBytes(mdd.getObjectTypeName()+String.valueOf('\0'));
+ dStream.writeBytes(mdd.getTypeStructure()+String.valueOf('\0'));
+ dStream.writeInt((int)typeLength);
+ dStream.writeBytes(domain+String.valueOf('\0'));
+ dStream.writeBytes(tileDomain+String.valueOf('\0'));
+ dStream.writeBytes(mdd.getOID().toString()+String.valueOf('\0'));
+
+ // if we have an MArray of type ulong: test that each cell value does not
+ // exceed 2^32, because the server does only store 4 byte ushorts, and
+ // convert the java-8-byte-long-array to a java-byte-array containing
+ // only the 4 least bytes of each long value.
+ if(mdd instanceof RasMArrayLong)
+ {
+ int arraySize = (int)mdd.getArraySize();
+ byte[] longArray = mdd.getArray();
+ // we skip the first 4 bytes of each long => arraySize / 2
+ dStream.writeInt(arraySize / 2);
+ for(int i=0; i<arraySize; i+=RasGlobalDefs.SIZE_OF_LONG)
+ {
+ for(int j=0; j<4; j++)
+ {
+ // read the first 4 bytes of the former long value and check
+ // if they are 0. If not, the value is too large to fit into
+ // a 4 byte ulong => throw exception
+ if(longArray[i+j] != 0)
+ {
+ DataInputStream dis = new DataInputStream(new ByteArrayInputStream(longArray));
+ dis.skipBytes(i);
+ long illegalValue = dis.readLong();
+ Debug.leaveVerbose( "utils.getTransferEncoding done. illegal long value." );
+ throw new RasIllegalULongValueException(illegalValue);
+ }
+ }
+ for(int j=4; j<RasGlobalDefs.SIZE_OF_LONG; j++)
+ {
+ // now write the next 4 bytes
+ dStream.writeByte(longArray[i+j]);
+ }
+ }
+ }
+ // if we have an MArray of type ushort: test that each cell value does not
+ // exceed 2^16, because the server does only store 2 byte ushorts, and
+ // convert the java-4-byte-integer-array to a java-byte-array containing
+ // only the 2 least bytes of each integer value.
+ else if(mdd instanceof RasMArrayInteger && mdd.getObjectTypeName().regionMatches(0, "UShort", 0, 5))
+ {
+ int arraySize = (int)mdd.getArraySize();
+ byte[] intArray = mdd.getArray();
+ // we skip the first 2 bytes of each integer => arraySize / 2
+ dStream.writeInt(arraySize / 2);
+ for(int i=0; i<arraySize; i+=RasGlobalDefs.SIZE_OF_INTEGER)
+ {
+ for(int j=0; j<2; j++)
+ {
+ // read the first 2 bytes of the former integer value and check
+ // if they are 0. If not, the value is too large to fit into
+ // a 2 byte ushort => throw exception
+ if(intArray[i+j] != 0)
+ {
+ DataInputStream dis = new DataInputStream(new ByteArrayInputStream(intArray));
+ dis.skipBytes(i);
+ int illegalValue = dis.readInt();
+ Debug.leaveVerbose( "utils.getTransferEncoding done. illegal short value." );
+ throw new RasIllegalUShortValueException(illegalValue);
+ }
+ }
+ for(int j=2; j<RasGlobalDefs.SIZE_OF_INTEGER; j++)
+ {
+ // now write the next 2 bytes
+ dStream.writeByte(intArray[i+j]);
+ }
+ }
+ }
+ // all marrays other than ulong or ushort
+ else
+ {
+ dStream.writeInt((int)mdd.getArraySize());
+ dStream.write(mdd.getArray());
+ }
+ dStream.flush();
+
+ String result = outStream.toString("8859_1");
+ Debug.leaveVerbose( "utils.getTransferEncoding done. result=" + result );
+ return result;
+ } // getTransferEncoding()
+
+ // calculates the tiling domain based on the original MDD, the type length and the tileSize
+ // of the MDD's storageLayout.
+ static String getTilingDomain(final RasMInterval originalDomain, final long typeLength, final RasStorageLayout layout)
+ {
+ Debug.enterVerbose( "utils.getTilingDomain start." );
+
+ long tileSize = layout.getTileSize();
+ int dim = originalDomain.dimension();
+ double tmp = 1.0/dim;
+ int size=(int)(Math.pow((double)(tileSize / typeLength),tmp))-1;
+
+ String retVal = "0:"+String.valueOf(size);
+ for(int x=1; x<dim; x++)
+ retVal = retVal + ",0:" + size;
+ retVal = "[" + retVal + "]";
+
+ Debug.leaveVerbose( "utils.getTilingDomain done. result=" + retVal );
+ return retVal;
+ }
+
+ } // utils
diff --git a/java/rasj/odmg/RasObject.class b/java/rasj/odmg/RasObject.class
new file mode 100644
index 0000000..c067738
--- /dev/null
+++ b/java/rasj/odmg/RasObject.class
Binary files differ
diff --git a/java/rasj/odmg/RasObject.java b/java/rasj/odmg/RasObject.java
new file mode 100644
index 0000000..d24f966
--- /dev/null
+++ b/java/rasj/odmg/RasObject.java
@@ -0,0 +1,244 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+package rasj.odmg;
+
+import rasj.*;
+import rasj.global.*;
+import org.odmg.*;
+
+public class RasObject implements RasGlobalDefs
+{
+ static final String rcsid = "@(#)Package rasj.odmg, class RasObject: $Header: /home/rasdev/CVS-repository/rasdaman/java/rasj/odmg/RasObject.java,v 1.9 2003/12/10 21:04:30 rasdev Exp $";
+
+ /**
+ * stores object name if it has one
+ */
+ protected String objectName;
+
+ /**
+ * stores object type name if it has one
+ */
+ private String typeName;
+
+ private int status;
+ private int lock;
+ private int type;
+ private String typeStructure = "";
+
+ /**
+ * object identifier
+ */
+ private RasOID oid;
+
+ /**
+ * default constructor
+ */
+ public RasObject()
+ {
+ objectName = "";
+ typeName = "";
+ status = 0;
+ lock = 0;
+ oid = new RasOID();
+ type = 0;
+ }
+
+ public RasObject(int objType)
+ {
+ objectName = "";
+ typeName = "";
+ status = 0;
+ lock = 0;
+ oid = new RasOID();
+ type = objType;
+ }
+
+ public RasObject(RasObject obj, int objType)
+ {
+ objectName = "";
+ typeName = "";
+ status = 0;
+ lock = 0;
+ oid = new RasOID();
+ type = objType;
+ }
+
+ /**
+ * get oid
+ */
+ public RasOID getOID()
+ {
+ return oid;
+ }
+
+ /**
+ * set oid
+ */
+ public void setOID(RasOID o)
+ {
+ oid = o;
+ }
+
+ /**
+ * set object name
+ */
+ public void setObjectName(String name) throws RasInvalidNameException
+ {
+ verifyName(name);
+
+ objectName = name;
+ }
+
+ /**
+ * set object type
+ */
+ public void setObjectType(int t)
+ {
+ type = t;
+ }
+
+ /**
+ * set object type
+ */
+ public void setObjectTypeName(String name) throws RasInvalidNameException
+ {
+ verifyName(name);
+
+ typeName = name;
+ }
+
+ /**
+ * set object type structure
+ */
+ public void setTypeStructure(String structure)
+ {
+ typeStructure = structure;
+ }
+
+ /**
+ * get type Structure
+ */
+ public String getTypeStructure()
+ {
+ return typeStructure;
+ }
+
+ /**
+ * get object name
+ */
+ public String getObjectName()
+ {
+ return objectName;
+ }
+
+ /**
+ * get object status
+ */
+ public int getStatus()
+ {
+ return status;
+ }
+
+
+ /**
+ * get object type
+ */
+ public int getObjectType()
+ {
+ return type;
+ }
+
+ /**
+ * get object typeName
+ */
+ public String getObjectTypeName()
+ {
+ return typeName;
+ }
+
+ /**
+ * set object status
+ */
+ public void setStatus(int newStatus)
+ {
+ status = newStatus;
+ }
+
+ /**
+ * get object lock
+ */
+ public int getLock()
+ {
+ return lock;
+ }
+
+ /**
+ * set object lock
+ */
+ public void setLock(int lockMode)
+ {
+ lock = lockMode;
+ }
+
+ public void rasDeactivate()
+ {
+ objectName = "";
+ status = 0;
+ lock = 0;
+ oid.rasDeactivate();
+ }
+
+ public RasType getTypeSchema()
+ {
+ return null;
+ }
+
+
+ private void verifyName(String name) throws RasInvalidNameException
+ {
+ for(int i = 0;i < name.length(); i++)
+ {
+ char c = name.charAt(i);
+
+ if(c == '_' || Character.isLetter(c)) continue;
+
+ if(Character.isDigit(c) && i > 0) continue;
+
+ throw new RasInvalidNameException(name);
+ }
+ }
+
+}
+
diff --git a/java/rasj/odmg/RasSet.class b/java/rasj/odmg/RasSet.class
new file mode 100644
index 0000000..2a6e974
--- /dev/null
+++ b/java/rasj/odmg/RasSet.class
Binary files differ
diff --git a/java/rasj/odmg/RasSet.java b/java/rasj/odmg/RasSet.java
new file mode 100644
index 0000000..a38f33d
--- /dev/null
+++ b/java/rasj/odmg/RasSet.java
@@ -0,0 +1,172 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+package rasj.odmg;
+
+import org.odmg.*;
+import java.util.*;
+
+/**
+ * This class implements the ODMG DSet interface.
+ * @version $Revision: 1.7 $
+ */
+public class RasSet extends RasCollection implements DSet
+
+{
+ static final String rcsid = "@(#)Package rasj.odmg, class RasSet: $Header: /home/rasdev/CVS-repository/rasdaman/java/rasj/odmg/RasSet.java,v 1.7 2003/12/19 15:42:56 rasdev Exp $";
+
+ Set content;
+
+ /**
+ * constructor
+ */
+ public RasSet()
+ {
+ content = new HashSet();
+ }
+
+ /**
+ * Returns an iterator over the elements in this Set in proper sequence.
+ */
+ public Iterator iterator()
+ {
+ return content.iterator();
+ }
+
+ /**
+ * Not implemented yet.
+ */
+ public DSet difference(DSet otherSet)
+ {
+ throw new NotImplementedException();
+ }
+
+ /**
+ * Not implemented yet.
+ */
+ public DSet intersection(DSet otherSet)
+ {
+ throw new NotImplementedException();
+ }
+
+ /**
+ * Not implemented yet.
+ */
+ public boolean properSubsetOf(DSet otherSet)
+ {
+ throw new NotImplementedException();
+ }
+
+ /**
+ * Not implemented yet.
+ */
+ public boolean properSupersetOf(DSet otherSet)
+ {
+ throw new NotImplementedException();
+ }
+
+ /**
+ * Not implemented yet.
+ */
+ public boolean subsetOf(DSet otherSet)
+ {
+ throw new NotImplementedException();
+ }
+
+ /**
+ * Not implemented yet.
+ */
+ public boolean supersetOf(DSet otherSet)
+ {
+ throw new NotImplementedException();
+ }
+
+ /**
+ * Not implemented yet.
+ */
+ public DSet union(DSet otherSet)
+ {
+ throw new NotImplementedException();
+ }
+
+ /**
+ * Appends the specified element to this Bag.
+ */
+ public boolean add(Object element)
+ {
+ return content.add(element);
+ }
+
+ /**
+ * Removes all of the elements from this set.
+ */
+ public void clear()
+ {
+ content.clear();
+ }
+
+ /**
+ * Returns true if this set contains the specified element.
+ */
+ public boolean contains(Object o)
+ {
+ return content.contains(o);
+ }
+
+ /**
+ * Returns true if this set contains no elements.
+ */
+ public boolean isEmpty()
+ {
+ return content.isEmpty();
+ }
+
+ /**
+ * Removes the given element from this set if it is present.
+ */
+ public boolean remove(Object o)
+ {
+ return content.remove(o);
+ }
+
+ /**
+ * Returns the number of elements in this Set.
+ */
+ public int size()
+ {
+ return content.size();
+ }
+
+}
+
diff --git a/java/rasj/odmg/RasTransaction.LOCAL_isOpenTA b/java/rasj/odmg/RasTransaction.LOCAL_isOpenTA
new file mode 100644
index 0000000..10ea687
--- /dev/null
+++ b/java/rasj/odmg/RasTransaction.LOCAL_isOpenTA
@@ -0,0 +1,173 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+package rasj.odmg;
+
+import org.odmg.*;
+import rasj.*;
+import rasj.global.*;
+import rasj.clientcommhttp.*;
+
+/**
+ * This class implements the ODMG Transaction interface.
+ *
+ * @version 1.0 (07-Apr-2000)
+ *
+ * @author Peter Zoller
+ */
+public class RasTransaction implements Transaction
+{
+ /**
+ * This variable holds a reference to the RasODMGImplementation object which created
+ * this RasDatabase object
+ */
+ //private RasODMGImplementation rasImplementation=null;
+ private RasImplementationInterface rasImplementation=null;
+
+ /**
+ * local state keeper whether TA is open;
+ * serves to optimize OQL queries: special method isOpenLocally() does not require server calls
+ */
+ private boolean isOpenTA = false;
+
+ public RasTransaction(RasImplementationInterface imp)
+ {
+ rasImplementation=imp;
+ isOpenTA = false; // local state keeper, maintained by TA methods
+ }
+
+ /**
+ * Not implemented yet.
+ */
+ public void join()
+ {
+ Debug.talkCritical( "RasTransaction::join: not yet implemented." );
+ throw new NotImplementedException();
+ }
+
+ /**
+ * Not implemented yet.
+ */
+ public void leave()
+ {
+ Debug.talkCritical( "RasTransaction::leave: not yet implemented." );
+ throw new NotImplementedException();
+ }
+
+ /**
+ * Begin a transaction.
+ */
+ public void begin()
+ {
+ rasImplementation.beginTA();
+ isOpenTA = true; // TA is considered open if everything went fine.
+ }
+
+ /**
+ * Returns TRUE if a transaction is currently open.
+ */
+ public boolean isOpen()
+ {
+ boolean result = rasImplementation.isOpenTA();
+ Debug.talkVerbose( "RasTransaction::isOpen: result=" + result );
+ return result;
+ }
+
+ /**
+ * Returns TRUE if a transaction is supposed to be open as seen from client side.
+ * This is an optimization to save one server call within query execution,
+ * it is NOT an official interface method.
+ */
+ public boolean isOpenLocally()
+ {
+ boolean result = isOpenTA;
+ Debug.talkVerbose( "RasTransaction::isOpenLocally: result=" + result );
+ return result;
+ }
+
+ /**
+ * Commit a transaction.
+ */
+ public void commit()
+ {
+ isOpenTA = false; // if commit fails something went wrong, so consider TA closed anyway
+ rasImplementation.commitTA();
+ }
+
+ /**
+ * Abort a transaction.
+ */
+ public void abort()
+ {
+ isOpenTA = false; // if abort tails something went wrong, so consider TA closed anyway
+ rasImplementation.abortTA();
+ }
+
+ /**
+ * Not implemented yet.
+ */
+ public void checkpoint()
+ {
+ Debug.talkCritical( "RasTransaction::checkpoint: not yet implemented." );
+ throw new NotImplementedException();
+ }
+
+ /**
+ * Not implemented yet.
+ */
+ public void lock(Object obj, int mode) throws LockNotGrantedException
+ {
+ Debug.talkCritical( "RasTransaction::lock: not yet implemented." );
+ throw new NotImplementedException();
+ }
+
+ /**
+ * Not implemented yet.
+ */
+ public boolean tryLock(Object obj, int mode)
+ {
+ Debug.talkCritical( "RasTransaction::tryLock: not yet implemented." );
+ throw new NotImplementedException();
+ }
+
+ /**
+ * Returns the errorStatus.
+ */
+
+ public String getErrorStatus()
+ {
+ String result = rasImplementation.getErrorStatus();
+ Debug.talkSparse( "RasTransaction::getErrorStatus: status=" + result );
+ return result;
+ }
+
+} // RasTransaction
diff --git a/java/rasj/odmg/RasTransaction.class b/java/rasj/odmg/RasTransaction.class
new file mode 100644
index 0000000..1bca570
--- /dev/null
+++ b/java/rasj/odmg/RasTransaction.class
Binary files differ
diff --git a/java/rasj/odmg/RasTransaction.java b/java/rasj/odmg/RasTransaction.java
new file mode 100644
index 0000000..10ea687
--- /dev/null
+++ b/java/rasj/odmg/RasTransaction.java
@@ -0,0 +1,173 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+package rasj.odmg;
+
+import org.odmg.*;
+import rasj.*;
+import rasj.global.*;
+import rasj.clientcommhttp.*;
+
+/**
+ * This class implements the ODMG Transaction interface.
+ *
+ * @version 1.0 (07-Apr-2000)
+ *
+ * @author Peter Zoller
+ */
+public class RasTransaction implements Transaction
+{
+ /**
+ * This variable holds a reference to the RasODMGImplementation object which created
+ * this RasDatabase object
+ */
+ //private RasODMGImplementation rasImplementation=null;
+ private RasImplementationInterface rasImplementation=null;
+
+ /**
+ * local state keeper whether TA is open;
+ * serves to optimize OQL queries: special method isOpenLocally() does not require server calls
+ */
+ private boolean isOpenTA = false;
+
+ public RasTransaction(RasImplementationInterface imp)
+ {
+ rasImplementation=imp;
+ isOpenTA = false; // local state keeper, maintained by TA methods
+ }
+
+ /**
+ * Not implemented yet.
+ */
+ public void join()
+ {
+ Debug.talkCritical( "RasTransaction::join: not yet implemented." );
+ throw new NotImplementedException();
+ }
+
+ /**
+ * Not implemented yet.
+ */
+ public void leave()
+ {
+ Debug.talkCritical( "RasTransaction::leave: not yet implemented." );
+ throw new NotImplementedException();
+ }
+
+ /**
+ * Begin a transaction.
+ */
+ public void begin()
+ {
+ rasImplementation.beginTA();
+ isOpenTA = true; // TA is considered open if everything went fine.
+ }
+
+ /**
+ * Returns TRUE if a transaction is currently open.
+ */
+ public boolean isOpen()
+ {
+ boolean result = rasImplementation.isOpenTA();
+ Debug.talkVerbose( "RasTransaction::isOpen: result=" + result );
+ return result;
+ }
+
+ /**
+ * Returns TRUE if a transaction is supposed to be open as seen from client side.
+ * This is an optimization to save one server call within query execution,
+ * it is NOT an official interface method.
+ */
+ public boolean isOpenLocally()
+ {
+ boolean result = isOpenTA;
+ Debug.talkVerbose( "RasTransaction::isOpenLocally: result=" + result );
+ return result;
+ }
+
+ /**
+ * Commit a transaction.
+ */
+ public void commit()
+ {
+ isOpenTA = false; // if commit fails something went wrong, so consider TA closed anyway
+ rasImplementation.commitTA();
+ }
+
+ /**
+ * Abort a transaction.
+ */
+ public void abort()
+ {
+ isOpenTA = false; // if abort tails something went wrong, so consider TA closed anyway
+ rasImplementation.abortTA();
+ }
+
+ /**
+ * Not implemented yet.
+ */
+ public void checkpoint()
+ {
+ Debug.talkCritical( "RasTransaction::checkpoint: not yet implemented." );
+ throw new NotImplementedException();
+ }
+
+ /**
+ * Not implemented yet.
+ */
+ public void lock(Object obj, int mode) throws LockNotGrantedException
+ {
+ Debug.talkCritical( "RasTransaction::lock: not yet implemented." );
+ throw new NotImplementedException();
+ }
+
+ /**
+ * Not implemented yet.
+ */
+ public boolean tryLock(Object obj, int mode)
+ {
+ Debug.talkCritical( "RasTransaction::tryLock: not yet implemented." );
+ throw new NotImplementedException();
+ }
+
+ /**
+ * Returns the errorStatus.
+ */
+
+ public String getErrorStatus()
+ {
+ String result = rasImplementation.getErrorStatus();
+ Debug.talkSparse( "RasTransaction::getErrorStatus: status=" + result );
+ return result;
+ }
+
+} // RasTransaction
diff --git a/java/rasj/odmg/RasTransaction.java.ORIG b/java/rasj/odmg/RasTransaction.java.ORIG
new file mode 100644
index 0000000..29b7c90
--- /dev/null
+++ b/java/rasj/odmg/RasTransaction.java.ORIG
@@ -0,0 +1,146 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+package rasj.odmg;
+
+import org.odmg.*;
+import rasj.*;
+import rasj.clientcommhttp.*;
+import rasj.global.*;
+
+/**
+ * This class implements the ODMG Transaction interface.
+ *
+ * @version 1.0 (07-Apr-2000)
+ *
+ * @author Peter Zoller
+ */
+public class RasTransaction implements Transaction
+{
+ /**
+ * This variable holds a reference to the RasODMGImplementation object which created
+ * this RasDatabase object
+ */
+ //private RasODMGImplementation rasImplementation=null;
+ private RasImplementationInterface rasImplementation=null;
+
+
+ public RasTransaction(RasImplementationInterface imp)
+ {
+ rasImplementation=imp;
+ }
+ /**
+ * Not implemented yet.
+ */
+ public void join()
+ {
+ throw new NotImplementedException();
+ }
+
+ /**
+ * Not implemented yet.
+ */
+ public void leave()
+ {
+ throw new NotImplementedException();
+ }
+
+ /**
+ * Begin a transaction.
+ */
+ public void begin()
+ {
+
+ rasImplementation.beginTA();
+ }
+
+ /**
+ * Returns TRUE if a transaction is currently open.
+ */
+ public boolean isOpen()
+ {
+ Debug.talkCritical( "RasTransaction::isOpen: calling rasImplementation.isOpenTA()" );
+ return rasImplementation.isOpenTA();
+ }
+
+ /**
+ * Commit a transaction.
+ */
+ public void commit()
+ {
+
+ rasImplementation.commitTA();
+ }
+
+ /**
+ * Abort a transaction.
+ */
+ public void abort()
+ {
+ rasImplementation.abortTA();
+ }
+
+ /**
+ * Not implemented yet.
+ */
+ public void checkpoint()
+ {
+ throw new NotImplementedException();
+ }
+
+ /**
+ * Not implemented yet.
+ */
+ public void lock(Object obj, int mode) throws LockNotGrantedException
+ {
+ throw new NotImplementedException();
+ }
+
+ /**
+ * Not implemented yet.
+ */
+ public boolean tryLock(Object obj, int mode)
+ {
+ throw new NotImplementedException();
+ }
+
+ /**
+ * Returns the errorStatus.
+ */
+
+ public String getErrorStatus()
+ {
+ return rasImplementation.getErrorStatus();
+ }
+
+}
diff --git a/java/rasj/odmg/utils.class b/java/rasj/odmg/utils.class
new file mode 100644
index 0000000..3b868a0
--- /dev/null
+++ b/java/rasj/odmg/utils.class
Binary files differ
diff --git a/java/rasj/rasj-protocol.html b/java/rasj/rasj-protocol.html
new file mode 100644
index 0000000..eea7bf9
--- /dev/null
+++ b/java/rasj/rasj-protocol.html
@@ -0,0 +1,109 @@
+<H1>rasdaman c/s protocol</H1>
+(taken from rasdaman/java/rasj/clientcomm/RasHttpRequest.java)
+<P>
+
+<B>Request structure</B><P>
+
+<UL>
+The rasj HTTP request to the rasdaman server uses the HTTP POST-Format with the following
+parameters:
+<P>
+<TABLE BORDER=1 WIDTH=100%>
+<TR><TH>Parameter:</TH><TH>Description:</TH><TH>Required for</TH></TR>
+<TR><TD>Command</TD>
+<TD>Integer value specifying the desired action (e.g. OpenDB, BT, CT, CloseDB ...)</TD>
+<TD>all requests</TD></TR>
+<TR><TD>Database</TD>
+<TD>String value specifying the database</TD>
+<TD>OpenDB, CloseDB</TD></TR>
+<TR><TD>ClientType</TD>
+<TD>Integer value defining the type of the client (at the moment always RasClient)</TD>
+<TD>all requests</TD></TR>
+<TR><TD>ClientID</TD>
+<TD>Integer value specifying the ClientID (currently set to 1 for every client)</TD>
+<TD>all requests</TD></TR>
+<TR><TD>QueryString</TD>
+<TD>String value containing the RasQL query</TD>
+<TD>executeQuery</TD></TR>
+<TR><TD>Endianess</TD>
+<TD>Integer value containing the Client Endianess</TD>
+<TD>only insert queries</TD></TR>
+<TR><TD>NumberOfQueryParameters</TD>
+<TD>Integer value specifying the number of query parameters</TD>
+<TD>only insert queries</TD></TR>
+<TR><TD>QueryParameters</TD>
+<TD>Byte Array containing the query parameters (MDDs) using the following format:<BR>
+<TABLE BORDER=1>
+<TR><TH>Integer</TH><TH>String</TH><TH>String</TH><TH>Integer</TH><TH>String</TH><TH>String</TH>
+<TH>String</TH><TH>Long</TH><TH>Byte[]</TH>
+</TR>
+<TR><TD>objectType</TD><TD>objectTypeName</TD><TD>typeStructure</TD><TD>typeLength</TD>
+<TD>domain</TD><TD>storageLayout</TD><TD>OID</TD><TD>dataSize</TD><TD>binary data</TD></TR>
+</TABLE>
+/TD>
+<TD>only insert queries</TD></TR>
+</TABLE>
+</P>
+</UL><P>
+
+<B>Result formats / internal representation:</B><P><UL>
+The result of a HTTP request has one of the following forms:<P>
+MDD Collections:<BR>
+<TABLE BORDER=1><TR><TH ROWSPAN=2>Byte</TH><TH ROWSPAN=2>Byte</TH>
+<TH ROWSPAN=2>String</TH><TH ROWSPAN=2>Long(4Bytes)</TH>
+<TH COLSPAN=5>resultElement 1</TH><TH ROWSPAN=3> ... </TH></TR>
+<TR><TD>String</TD><TD>String</TD><TD>String</TD><TD>Long(4Bytes)</TD><TD>Byte[]</TD></TR>
+<TR><TD>Result type<P>1=MDDCollection</TD>
+<TD>Endianess</TD>
+<TD>Collection type</TD>
+<TD>Number of results</TD>
+<TD>BaseType description</TD>
+<TD>Spatial domain</TD>
+<TD>OID</TD>
+<TD>Size of the Binary Data Block</TD>
+<TD>Binary Data Block</TD></TR>
+</TABLE><P>
+
+Skalar Collections:<BR>
+<TABLE BORDER=1><TR><TH ROWSPAN=2>Byte</TH><TH ROWSPAN=2>Byte</TH>
+<TH ROWSPAN=2>String</TH><TH ROWSPAN=2>Long(4Bytes)</TH>
+<TH COLSPAN=4>resultElement 1</TH><TH ROWSPAN=3> ... </TH></TR>
+<TR><TD>String</TD><TD>Long(4Bytes)</TD><TD>Byte[]</TD></TR>
+<TR><TD>Result type<P>2=SkalarCollection</TD>
+<TD>Endianess</TD>
+<TD>Collection type</TD>
+<TD>Number of results</TD>
+<TD>ElementType description</TD>
+<TD>Size of the Binary Data Block</TD>
+<TD>Binary Data Block</TD></TR>
+</TABLE><P>
+
+Errors:<BR>
+<TABLE BORDER=1><TR><TH>Byte</TH><TH>Byte</TH>
+<TH>Long(4Bytes)</TH><TH>Long(4Bytes)</TH><TH>Long(4Bytes)</TH>
+<TH>String</TH></TR>
+<TR><TD>Result type<P>0=Error</TD>
+<TD>Endianess</TD>
+<TD>Error number</TD>
+<TD>Line number</TD>
+<TD>Column number</TD>
+<TD>Token</TD>
+</TABLE><P>
+
+Single Integer Value:<BR>
+<TABLE BORDER=1><TR><TH>Byte</TH><TH>Integer</TH></TR>
+<TR><TD>Result type<P>3=Integer</TD><TD>Value</TD></TR>
+</TABLE><P>
+
+OID:<BR>
+<TABLE BORDER=1><TR><TH>Byte</TH><TH>String</TH><TH>String</TH><TH>Double</TH></TR>
+<TR><TD>Result type<P>4=OID</TD><TD>system</TD><TD>basename</TD><TD>localOID</TD></TR>
+</TABLE><P>
+
+Acknowledgement:<BR>
+<TABLE BORDER=1><TR><TH>Byte</TH></TR>
+<TR><TD>Result type<P>99=OK</TD></TR>
+</TABLE><P>
+
+</UL>
+
diff --git a/java/rasj/rnp/MD5.class b/java/rasj/rnp/MD5.class
new file mode 100644
index 0000000..03ef314
--- /dev/null
+++ b/java/rasj/rnp/MD5.class
Binary files differ
diff --git a/java/rasj/rnp/MD5State.class b/java/rasj/rnp/MD5State.class
new file mode 100644
index 0000000..0feea29
--- /dev/null
+++ b/java/rasj/rnp/MD5State.class
Binary files differ
diff --git a/java/rasj/rnp/Makefile b/java/rasj/rnp/Makefile
new file mode 100644
index 0000000..8597847
--- /dev/null
+++ b/java/rasj/rnp/Makefile
@@ -0,0 +1,61 @@
+# -*-Makefile-*- (for Emacs)
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>. # Top Level makefile. This points to the various modules that have to be build
+# and/or deployed
+#
+# MAKEFILE FOR:
+# package rasj/odmg
+#
+# COMMENTS:
+#
+##################################################################
+######################### Definitions ############################
+
+# standard include with general options
+include $(RMANBASE)/Makefile.inc
+
+SRCS = RasRNPImplementation.java Rnp.java RnpBaseClientComm.java \
+ RnpDecoder.java RnpEncoder.java RnpException.java RnpFragment.java\
+ RnpFragmentHeader.java RnpMessage.java RnpMessageHeader.java \
+ RnpParameter.java
+OBJS = ${SRCS:%.java=%.class}
+MISCCLEAN = *.class
+
+# directory where HTML documentation is created
+DOCDIR := $(DOCBASE)/java/rasj/odmg
+
+########################### Targets ##############################
+
+# compile everything
+.PHONY : all
+all: $(OBJS)
+
+# delete all files
+empty:
+ -rm -f $(SRCS) $(MISCCLEAN)
+
+############################ Dependencies #######################
+
+# general rules
+include $(RMANBASE)/Makefile.rel
+
+
diff --git a/java/rasj/rnp/Makefile.dep b/java/rasj/rnp/Makefile.dep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/java/rasj/rnp/Makefile.dep
diff --git a/java/rasj/rnp/ParameterDouble64.class b/java/rasj/rnp/ParameterDouble64.class
new file mode 100644
index 0000000..3e9136b
--- /dev/null
+++ b/java/rasj/rnp/ParameterDouble64.class
Binary files differ
diff --git a/java/rasj/rnp/ParameterFloat32.class b/java/rasj/rnp/ParameterFloat32.class
new file mode 100644
index 0000000..d231c42
--- /dev/null
+++ b/java/rasj/rnp/ParameterFloat32.class
Binary files differ
diff --git a/java/rasj/rnp/ParameterInt32.class b/java/rasj/rnp/ParameterInt32.class
new file mode 100644
index 0000000..40874de
--- /dev/null
+++ b/java/rasj/rnp/ParameterInt32.class
Binary files differ
diff --git a/java/rasj/rnp/ParameterOpaque.class b/java/rasj/rnp/ParameterOpaque.class
new file mode 100644
index 0000000..df732e9
--- /dev/null
+++ b/java/rasj/rnp/ParameterOpaque.class
Binary files differ
diff --git a/java/rasj/rnp/ParameterString.class b/java/rasj/rnp/ParameterString.class
new file mode 100644
index 0000000..98dd4c3
--- /dev/null
+++ b/java/rasj/rnp/ParameterString.class
Binary files differ
diff --git a/java/rasj/rnp/RasRNPImplementation.class b/java/rasj/rnp/RasRNPImplementation.class
new file mode 100644
index 0000000..913fa64
--- /dev/null
+++ b/java/rasj/rnp/RasRNPImplementation.class
Binary files differ
diff --git a/java/rasj/rnp/RasRNPImplementation.java b/java/rasj/rnp/RasRNPImplementation.java
new file mode 100644
index 0000000..23baac2
--- /dev/null
+++ b/java/rasj/rnp/RasRNPImplementation.java
@@ -0,0 +1,1761 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+package rasj.rnp;
+
+import rasj.odmg.*;
+import rasj.*;
+import rasj.global.*;
+import rasj.clientcommhttp.*;
+import org.odmg.*;
+import rasj.odmg.RasOQLQuery;
+
+import java.io.*;
+import java.net.*;
+import java.lang.*;
+import java.util.*;
+
+public class RasRNPImplementation extends RnpBaseClientComm implements RasImplementationInterface, RasCommDefs,RasGlobalDefs
+ {
+ public static final int pmt_none = 0;
+ public static final int pmt_clientid = 1;
+ public static final int pmt_rErrorString = 2;
+ public static final int pmt_dbname = 3;
+ public static final int pmt_accesmode = 4;
+ public static final int pmt_queryString = 5;
+ public static final int pmt_httpqanswer = 6;
+ public static final int pmt_oidstring = 7;
+ public static final int pmt_capability = 8;
+ public static final int pmt_transstatus = 9;
+ public static final int pmt_objecttype =10;
+
+ public static final int cmd_none = 0;
+ public static final int cmd_connect = 1;
+ public static final int cmd_disconnect = 2;
+ public static final int cmd_opendb = 3;
+ public static final int cmd_closedb = 4;
+ public static final int cmd_beginta = 5;
+ public static final int cmd_committa = 6;
+ public static final int cmd_abortta = 7;
+ public static final int cmd_istaopen = 8;
+ public static final int cmd_queryhttp = 9;
+ public static final int cmd_getnewoid =10;
+
+ public static final int rasServerId = 3072002;
+
+ private String rasServer = "";
+ private String rasMgr = "";
+ private int rasMgrPort = 7001;
+ private String userIdentification = "rasguest:8e70a429be359b6dace8b5b2500dedb0";
+ private String databaseName = "";
+ private String capability = "dummy";
+ private int maxRetry = 5; // was 120; -- PB 2003-nov-20
+
+ private RasTransaction transaction = null;
+ private RasDatabase database = null;
+ private RasOQLQuery query = null;
+
+ private int accessMode = 0;
+ private boolean readWrite = false;
+ private int dbIsOpen = 0;
+ private int taIsOpen = 0;
+ private int clientID = 0;
+
+ private String errorStatus = "";
+
+ public static boolean useTurbo = true; // whenever possible pack multiple requests into one call
+
+
+
+ public RasRNPImplementation(String server)
+ {
+ super(rasServerId);
+
+ Debug.enterVerbose( "RasRNPImplementation.RasRNPImplementation start. server=" + server );
+ try
+ {
+ StringTokenizer t=new StringTokenizer (server,"/");
+ String xxx=t.nextToken();
+ rasMgr =t.nextToken("/:");
+ String portStr = t.nextToken(":");
+ rasMgrPort = Integer.parseInt(portStr);
+ }
+ catch(NoSuchElementException e)
+ {
+ Debug.talkCritical( "RasRNPImplementation.RasRNPImplementation: " + e.getMessage() );
+ Debug.leaveVerbose( "RasRNPImplementation.RasRNPImplementation done: " + e.getMessage() );
+ throw new RasConnectionFailedException(RasGlobalDefs.URL_FORMAT_ERROR, server);
+ }
+ Debug.leaveVerbose( "RasRNPImplementation.RasRNPImplementation done." );
+ } // RasRNPImplementation()
+
+ public String getErrorStatus()
+ {
+ Debug.talkSparse( "RasRNPImplementation.getErrorStatus: " + errorStatus );
+ return errorStatus;
+ }
+
+ public String getRasServer()
+ {
+ Debug.talkSparse( "RasRNPImplementation.getRasServer: " + rasServer );
+ return rasServer;
+ }
+
+ public int dbIsOpen()
+ {
+ Debug.talkSparse( "RasRNPImplementation.dbIsOpen: " + dbIsOpen );
+ return dbIsOpen;
+ }
+
+ public int getClientID()
+ {
+ Debug.talkSparse( "RasRNPImplementation.getClientID: " + clientID );
+ return clientID;
+ }
+
+ public int getAccessMode()
+ {
+ Debug.talkSparse( "RasRNPImplementation.getAccessMode: " + accessMode );
+ return accessMode;
+ }
+
+ public Transaction newTransaction()
+ {
+ transaction = new RasTransaction(this);
+ Debug.talkSparse( "RasRNPImplementation.newTransaction." );
+ return transaction;
+ }
+
+ public Transaction currentTransaction()
+ {
+ Debug.talkSparse( "RasRNPImplementation.currentTransaction." );
+ return transaction;
+ }
+
+ public Database newDatabase()
+ {
+ database=new RasDatabase(this);
+ Debug.talkSparse( "RasRNPImplementation.newDatabase." );
+ return database;
+ }
+
+ public OQLQuery newOQLQuery()
+ {
+ query=new RasOQLQuery(this);
+ Debug.talkSparse( "RasRNPImplementation.newOQLQuery." );
+ return query;
+ }
+
+ public DList newDList()
+ {
+ Debug.talkSparse( "RasRNPImplementation.newDList." );
+ return new RasList();
+ }
+
+ public DBag newDBag()
+ {
+ Debug.talkSparse( "RasRNPImplementation.newDBag." );
+ return new RasBag();
+ }
+
+ public DSet newDSet()
+ {
+ Debug.talkSparse( "RasRNPImplementation.newDSet." );
+ return new RasSet();
+ }
+
+ public DArray newDArray()
+ {
+ Debug.talkCritical( "RasRNPImplementation.newDArray: not yet implemented." );
+ throw new NotImplementedException();
+ }
+
+ public DMap newDMap()
+ {
+ Debug.talkCritical( "RasRNPImplementation.newDMap: not yet implemented." );
+ throw new NotImplementedException();
+ }
+
+ public Database getDatabase(Object obj)
+ {
+ Debug.talkCritical( "RasRNPImplementation.getDatabase: not yet implemented." );
+ throw new NotImplementedException();
+ }
+
+ public String getObjectId(Object obj)
+ {
+ Debug.enterVerbose( "RasRNPImplementation.getObjectId start." );
+ String oid = null;
+ if (obj instanceof RasObject)
+ {
+ RasOID roid = ((RasObject)obj).getOID();
+ oid = roid.toString();
+ if (!((RasObject)obj).getOID().isValid())
+ {
+ roid = executeGetNewObjectId();
+ oid = roid.toString();
+ ((RasObject)obj).setOID(roid);
+ }
+ else
+ {
+ Debug.leaveCritical( "RasRNPImplementation.getObjectId done. not yet implemented." );
+ throw new NotImplementedException();
+ }
+ }
+ Debug.leaveVerbose( "RasRNPImplementation.getObjectId done. oid=" + oid );
+ return oid;
+ }
+
+ public void setMaxRetry(int newRetry)
+ {
+ Debug.talkVerbose( "RasRNPImplementation.setMaxRetry: setting to " + newRetry );
+ maxRetry = newRetry;
+ }
+
+ public int getMaxRetry()
+ {
+ Debug.talkVerbose( "RasRNPImplementation.getMaxRetry: is " + maxRetry );
+ return maxRetry;
+ }
+
+ public void openDB(String name, int accessMode) throws ODMGException
+ {
+ Debug.enterVerbose( "RasRNPImplementation.openDB start. db=" + name + ", accessMode=" + accessMode );
+ databaseName = name;
+ this.accessMode = accessMode;
+ readWrite = (accessMode != Database.OPEN_READ_ONLY) ? true:false;
+ getFreeServer(false); // fake server
+
+ // "turbo" doesn't work because connect delivers the client id needed for later calls
+ // if(useTurbo==false)
+ // {
+ executeConnect();
+ executeOpenDB(databaseName);
+ executeCloseDB();
+ executeDisconnect();
+ // }
+ // else executeTurboOpen(name);
+
+ dbIsOpen = 1;
+ Debug.leaveVerbose( "RasRNPImplementation.openDB done." );
+ }
+
+ public void closeDB() throws ODMGException
+ {
+ Debug.talkVerbose( "RasRNPImplementation.closeDB." );
+ dbIsOpen = 0;
+ }
+
+ public void beginTA()
+ {
+ Debug.enterVerbose( "RasRNPImplementation.beginTA start." );
+ if(useTurbo==false)
+ {
+ try
+ {
+ getFreeServer(true);
+ executeConnect();
+ executeOpenDB(databaseName);
+ executeBeginTA();
+ }
+ catch(ODMGException e)
+ {
+ errorStatus = e.getMessage();
+ Debug.talkCritical( "RasRNPImplementation.beginTA: " + errorStatus );
+ }
+ }
+ else
+ {
+ try
+ {
+ getFreeServer(true);
+ executeTurboBegin(databaseName);
+ }
+ catch(ODMGException e)
+ {
+ errorStatus = e.getMessage();
+ Debug.talkCritical( "RasRNPImplementation.beginTA: " + errorStatus );
+ }
+ }
+ Debug.leaveVerbose( "RasRNPImplementation.beginTA done." );
+ }
+
+ public boolean isOpenTA()
+ {
+ Debug.enterVerbose( "RasRNPImplementation.isOpenTA start." );
+ boolean result = false;
+ try
+ {
+ if(executeIsOpenTA()!=0)
+ result = true;
+ }
+ catch(ODMGException e)
+ {
+ errorStatus = e.getMessage();
+ Debug.talkCritical( "RasRNPImplementation.isOpenTA: " + errorStatus );
+ }
+ Debug.leaveVerbose( "RasRNPImplementation.isOpenTA done. result=" + result );
+ return result;
+ }
+
+ public void commitTA()
+ {
+ Debug.enterVerbose( "RasRNPImplementation.commitTA start." );
+ if(useTurbo==false)
+ {
+ try
+ {
+ executeCommitTA();
+ executeCloseDB();
+ executeDisconnect();
+ }
+ catch(ODMGException e)
+ {
+ errorStatus = e.getMessage();
+ Debug.talkCritical( "RasRNPImplementation.commitTA: " + errorStatus );
+ }
+ }
+ else
+ {
+ try
+ {
+ executeTurboCommit();
+ }
+ catch(ODMGException e)
+ {
+ errorStatus = e.getMessage();
+ Debug.talkCritical( "RasRNPImplementation.commitTA: " + errorStatus );
+ }
+ }
+ Debug.leaveVerbose( "RasRNPImplementation.commitTA done." );
+ }
+
+ public void abortTA()
+ {
+ Debug.enterVerbose( "RasRNPImplementation.abortTA done." );
+ if (useTurbo==false)
+ {
+ try
+ {
+ executeAbortTA();
+ executeCloseDB();
+ executeDisconnect();
+ }
+ catch(ODMGException e)
+ {
+ errorStatus = e.getMessage();
+ Debug.talkCritical( "RasRNPImplementation.abortTA: " + errorStatus );
+ }
+ }
+ else
+ {
+ try
+ {
+ executeTurboAbort();
+ }
+ catch(ODMGException e)
+ {
+ errorStatus = e.getMessage();
+ Debug.talkCritical( "RasRNPImplementation.abortTA: " + errorStatus );
+ }
+ }
+ Debug.leaveVerbose( "RasRNPImplementation.abortTA done." );
+ }
+
+ public Object queryRequest(String parameters) throws RasQueryExecutionFailedException
+ {
+ Debug.talkVerbose( "RasRNPImplementation.queryRequest." );
+ return executeQueryRequest(parameters);
+ }
+
+ private void executeTurboOpen(String name) throws ODMGException
+ {
+ Debug.enterVerbose( "RasRNPImplementation.executeTurboOpen start. name=" + name );
+ clientID = 0;
+ startMessage();
+
+ //connect
+ startFragment(cmd_connect);
+ encoder.addParameterInt32(pmt_clientid,clientID);
+ encoder.addParameterString(pmt_capability,capability);
+ endFragment();
+
+ //opendb
+ startFragment(cmd_opendb);
+ encoder.addParameterInt32(pmt_clientid,clientID);
+ encoder.addParameterString(pmt_dbname,name);
+ endFragment();
+
+ //close db
+ startFragment(cmd_closedb);
+ encoder.addParameterInt32(pmt_clientid,clientID);
+ endFragment();
+
+ //disconnect
+ startFragment(cmd_disconnect);
+ encoder.addParameterInt32(pmt_clientid,clientID);
+ endFragment();
+
+ endMessage();
+
+ //send message and receive answer
+ turboSendRequestGetAnswer();
+
+ // connect answer
+ RnpFragment fragment=decoder.getFirstFragment();
+ checkForError();
+ decoder.getFirstParameter();
+ clientID=decoder.getDataAsInteger();
+
+ //opendb answer
+ fragment=decoder.getNextFragment(fragment);
+ checkForError();
+
+ //closedb answer
+ fragment=decoder.getNextFragment(fragment);
+ checkForError();
+
+ //disconnect answer
+ decoder.getNextFragment(fragment);
+ checkForError();
+ clientID = 0;
+ Debug.leaveVerbose( "RasRNPImplementation.executeTurboOpen done." );
+ }
+
+ private void executeTurboBegin(String name) throws ODMGException
+ {
+ Debug.enterVerbose( "RasRNPImplementation.executeTurboBegin start. name=" + name );
+ clientID = 0;
+ startMessage();
+
+ //connect
+ startFragment(cmd_connect);
+ encoder.addParameterInt32(pmt_clientid,clientID);
+ encoder.addParameterString(pmt_capability,capability);
+ endFragment();
+
+ //opendb
+ startFragment(cmd_opendb);
+ encoder.addParameterInt32(pmt_clientid,clientID);
+ encoder.addParameterString(pmt_dbname,name);
+ endFragment();
+
+ // begin ta
+ startFragment(cmd_beginta);
+ encoder.addParameterInt32(pmt_clientid,clientID);
+ encoder.addParameterInt32(pmt_accesmode, readWrite ? 1:0);
+ endFragment();
+
+ endMessage();
+
+ //send message and receive answer
+ turboSendRequestGetAnswer();
+
+ // connect answer
+ RnpFragment fragment=decoder.getFirstFragment();
+ checkForError();
+ decoder.getFirstParameter();
+ clientID=decoder.getDataAsInteger();
+
+ //opendb answer
+ fragment=decoder.getNextFragment(fragment);
+ checkForError();
+
+ // begin ta answer
+ decoder.getNextFragment(fragment);
+ checkForError();
+ Debug.leaveVerbose( "RasRNPImplementation.executeTurboBegin done." );
+ }
+
+ private void executeTurboCommit() throws ODMGException
+ {
+ Debug.enterVerbose( "RasRNPImplementation.executeTurboCommit start." );
+ startMessage();
+
+ //commit
+ startFragment(cmd_committa);
+ encoder.addParameterInt32(pmt_clientid,clientID);
+ endFragment();
+
+ //close
+ startFragment(cmd_closedb);
+ encoder.addParameterInt32(pmt_clientid,clientID);
+ endFragment();
+
+ //disconnect
+ startFragment(cmd_disconnect);
+ encoder.addParameterInt32(pmt_clientid,clientID);
+ endFragment();
+
+ endMessage();
+
+ //send message and receive answer
+ turboSendRequestGetAnswer();
+
+ //commit answer
+ RnpFragment fragment=decoder.getFirstFragment();
+ checkForError();
+
+ //close answer
+ fragment=decoder.getNextFragment(fragment);
+ checkForError();
+
+ //disconnect answer
+ decoder.getNextFragment(fragment);
+ checkForError();
+ clientID = 0;
+ Debug.leaveVerbose( "RasRNPImplementation.executeTurboCommit done." );
+ }
+
+ private void executeTurboAbort() throws ODMGException
+ {
+ Debug.enterVerbose( "RasRNPImplementation.executeTurboAbort start." );
+ startMessage();
+
+ //abort
+ startFragment(cmd_abortta);
+ encoder.addParameterInt32(pmt_clientid,clientID);
+ endFragment();
+
+ //close
+ startFragment(cmd_closedb);
+ encoder.addParameterInt32(pmt_clientid,clientID);
+ endFragment();
+
+ //disconnect
+ startFragment(cmd_disconnect);
+ encoder.addParameterInt32(pmt_clientid,clientID);
+ endFragment();
+
+ endMessage();
+
+ //send message and receive answer
+ turboSendRequestGetAnswer();
+
+ //abort answer
+ RnpFragment fragment=decoder.getFirstFragment();
+ checkForError();
+
+ //close answer
+ fragment=decoder.getNextFragment(fragment);
+ checkForError();
+
+ //disconnect answer
+ decoder.getNextFragment(fragment);
+ checkForError();
+ clientID = 0;
+ Debug.leaveVerbose( "RasRNPImplementation.executeTurboAbort done." );
+ }
+
+ private RasOID executeGetNewObjectId()
+ {
+ Debug.enterVerbose( "RasRNPImplementation.executeGetNewObjectId start." );
+ startRequest(cmd_getnewoid);
+ encoder.addParameterInt32(pmt_clientid,clientID);
+ encoder.addParameterInt32(pmt_objecttype,1);
+ sendRequestGetAnswer();
+ decoder.getFirstParameter();
+ RasOID result = new RasOID(decoder.getDataAsString());
+ Debug.leaveVerbose( "RasRNPImplementation.executeGetNewObjectId done." );
+ return result;
+ }
+
+ private int executeIsOpenTA()throws ODMGException
+ {
+ startRequest(cmd_istaopen);
+ encoder.addParameterInt32(pmt_clientid,clientID);
+ sendRequestGetAnswer();
+ decoder.getFirstParameter();
+ int result = decoder.getDataAsInteger();
+ Debug.leaveVerbose( "RasRNPImplementation.executeIsOpenTA done. result=" + result );
+ return result;
+ }
+
+//######## These functions are kept only for testing purpose, we will emove them soon ####
+ private void executeConnect() throws ODMGException
+ {
+ startRequest(cmd_connect);
+ encoder.addParameterInt32(pmt_clientid,clientID);
+ encoder.addParameterString(pmt_capability,capability);
+ sendRequestGetAnswer();
+ checkForError();
+ decoder.getFirstParameter();
+ clientID=decoder.getDataAsInteger();
+ }
+
+ private void executeDisconnect() throws ODMGException
+ {
+ startRequest(cmd_disconnect);
+ encoder.addParameterInt32(pmt_clientid,clientID);
+ sendRequestGetAnswer();
+ checkForError();
+ }
+
+ private void executeOpenDB(String name) throws ODMGException
+ {
+ startRequest(cmd_opendb);
+ encoder.addParameterInt32(pmt_clientid,clientID);
+ encoder.addParameterString(pmt_dbname,name);
+ sendRequestGetAnswer();
+ checkForError();
+ }
+
+ private void executeCloseDB() throws ODMGException
+ {
+ startRequest(cmd_closedb);
+ encoder.addParameterInt32(pmt_clientid,clientID);
+ sendRequestGetAnswer();
+ checkForError();
+ }
+
+ private void executeBeginTA() throws ODMGException
+ {
+ startRequest(cmd_beginta);
+ encoder.addParameterInt32(pmt_clientid,clientID);
+ encoder.addParameterInt32(pmt_accesmode, readWrite ? 1:0);
+ sendRequestGetAnswer();
+ checkForError();
+ }
+
+ private void executeCommitTA()throws ODMGException
+ {
+ startRequest(cmd_committa);
+ encoder.addParameterInt32(pmt_clientid,clientID);
+ sendRequestGetAnswer();
+ checkForError();
+ }
+
+ private void executeAbortTA()throws ODMGException
+ {
+ startRequest(cmd_abortta);
+ encoder.addParameterInt32(pmt_clientid,clientID);
+ sendRequestGetAnswer();
+ checkForError();
+ }
+
+//################################################################################
+
+ public void getFreeServer(boolean realServer)throws RasQueryExecutionFailedException, RasConnectionFailedException
+ {
+ Debug.enterVerbose( "RasRNPImplementation.getFreeServer start. realServer=" + realServer );
+ String uniqueID = uniqueRequestID();
+
+ for (int retryCount = 0; ;retryCount++)
+ {
+ try
+ {
+ executeGetFreeServer(realServer,uniqueID);
+ break;
+ }
+ catch(RasConnectionFailedException e)
+ {
+ int errno = e.getErrorNo();
+ // FIXME: adapt algorithm to that of http, see RasODMGImplementation.java
+ if ( ( errno==RasGlobalDefs.MANAGER_BUSY
+ // || errno==RasGlobalDefs.NO_ACTIVE_SERVERS // if server doesn't run waiting won't help -- PB 2003-nov-20
+ || errno==RasGlobalDefs.WRITE_TRANS_IN_PROGRESS)
+ && retryCount < maxRetry)
+ {
+ int millisec = 50 * retryCount + 50;
+ if(millisec > 1000)
+ millisec = 1000;
+ Debug.talkVerbose( "RasRNPImplementation.getFreeServer: retry #" + retryCount + ", sleeping " + millisec + "msecs" );
+ try
+ {
+ Thread.sleep(millisec);
+ }
+ catch(InterruptedException intex)
+ {
+ // wake up
+ }
+ }
+ else
+ {
+ Debug.talkCritical( "RasRNPImplementation.getFreeServer: " + e.getMessage() );
+ Debug.leaveVerbose( "RasRNPImplementation.getFreeServer done: " + e.getMessage() );
+ throw(e);
+ }
+ } // catch
+ } // for
+
+ Debug.leaveVerbose( "RasRNPImplementation.getFreeServer done." );
+ } // getFreeServer
+
+ private void executeGetFreeServer(boolean realServer, String uniqueID)
+ throws RasQueryExecutionFailedException, RasConnectionFailedException
+ {
+ Debug.enterVerbose( "RasRNPImplementation.executeGetFreeServer start. realServer=" + realServer + ", uniqueID=" + uniqueID );
+ try
+ {
+ Debug.talkVerbose( "RasRNPImplementation.executeGetFreeServer: rasmgr=" + rasMgr + ", port=" + rasMgrPort );
+ Socket socket = new Socket(rasMgr,rasMgrPort);
+ Debug.talkVerbose( "RasRNPImplementation.executeGetFreeServer: socket=" + socket );
+ PrintStream ps = new PrintStream(socket.getOutputStream());
+ String accessFlag = (accessMode == Database.OPEN_READ_ONLY ? "ro":"rw");
+ String body = databaseName + " RNP " + accessFlag + ' ' + uniqueID + " \0";
+ if (realServer)
+ ps.print("POST getfreeserver RNP/1.1\r\nAccept: text/plain\r\nContent-type: text/plain\r\n"
+ + "User-Agent: RasDaMan Java Client1.0\r\nAuthorization: ras " + userIdentification
+ + "\r\nContent length: " + body.length()+"\r\n\r\n" + body);
+ else
+ ps.print("POST getfreeserver2 RNP/1.1\r\nAccept: text/plain\r\nContent-type: text/plain\r\n"
+ + "User-Agent: RasDaMan Java Client1.0\r\nAuthorization: ras " + userIdentification
+ + "\r\nContent length: " + body.length()+"\r\n\r\n" + body);
+ ps.flush();
+
+ BufferedReader ds = new BufferedReader(new InputStreamReader(socket.getInputStream()));
+ int resultCode = getResultCode(ds);
+ String bodyLine = getBodyLine(ds);
+ Debug.talkVerbose( "RasRNPImplementation.executeGetFreeServer: bodyLine: " + bodyLine );
+
+ ps.close();
+ ds.close();
+ socket.close();
+ Debug.talkVerbose( "RasRNPImplementation.executeGetFreeServer: socket closed: " + socket );
+
+ if (resultCode==200)
+ {
+ StringTokenizer t=new StringTokenizer(bodyLine," ");
+ String host=t.nextToken();
+ String port=t.nextToken(" ");
+ capability=t.nextToken(" \t\r\n\0");
+ rasServer="http://" + host + ":" + port;
+ setConnectionParameters(host,Integer.parseInt(port));
+ }
+ else
+ {
+ StringTokenizer t=new StringTokenizer(bodyLine," ");
+ String errorStr = t.nextToken();
+ int errorCode = Integer.parseInt(errorStr);
+ if( resultCode < 1000 )
+ {
+ Debug.talkCritical( "RasRNPImplementation.executeGetFreeServer: " + errorCode );
+ Debug.leaveVerbose( "RasRNPImplementation.executeGetFreeServer: done. errorcode=" + errorCode );
+ throw new RasConnectionFailedException(errorCode,null);
+ }
+ else
+ {
+ Debug.talkCritical( "RasRNPImplementation.executeGetFreeServer: " + errorCode );
+ Debug.leaveVerbose( "RasRNPImplementation.executeGetFreeServer: done. errorcode=" + errorCode );
+ throw new RasConnectionFailedException(RasGlobalDefs.REQUEST_FORMAT_ERROR," code=" + errorCode);
+ }
+ }
+ }
+ catch(MalformedURLException e)
+ {
+ Debug.talkCritical( "RasRNPImplementation.executeGetFreeServer: " + e.getMessage() );
+ Debug.leaveVerbose( "RasRNPImplementation.executeGetFreeServer: done. " + e.getMessage() );
+ throw new RasConnectionFailedException(RasGlobalDefs.MANAGER_CONN_FAILED,rasMgr);
+ }
+ catch(IOException e)
+ {
+ Debug.talkCritical( "RasRNPImplementation.executeGetFreeServer: " + e.getMessage() );
+ Debug.leaveVerbose( "RasRNPImplementation.executeGetFreeServer: done. " + e.getMessage() );
+ throw new RasClientInternalException("RasODMGImplementation","getFreeServer()",e.getMessage());
+ }
+ catch(NumberFormatException e)
+ {
+ Debug.talkCritical( "RasRNPImplementation.executeGetFreeServer: cannot decode integer: " + e.getMessage() );
+ Debug.leaveVerbose( "RasRNPImplementation.executeGetFreeServer: done. " + e.getMessage() );
+ throw new RasClientInternalException("RasODMGImplementation","getFreeServer()",e.getMessage());
+ }
+ Debug.leaveVerbose( "RasRNPImplementation.executeGetFreeServer done." );
+ }
+
+ public int getResultCode(BufferedReader ds) throws IOException
+ {
+ Debug.enterVerbose( "RasRNPImplementation.getResultCode: start." );
+
+ String s = ds.readLine();
+ StringTokenizer t = new StringTokenizer(s," ");
+ String http = t.nextToken(); // FIXME: never used
+ String resultString = t.nextToken(" ");
+ int result = 0;
+ try
+ {
+ result = Integer.parseInt(resultString);
+ }
+ catch(NumberFormatException e)
+ {
+ Debug.talkCritical( "RasRNPImplementation.getResultCode: cannot decode integer: " + e.getMessage() );
+ result = 0; // FIXME: set to some real error code
+ }
+
+ Debug.leaveVerbose( "RasRNPImplementation.getResultCode: done. result=" + result );
+ return result;
+ }
+
+ public String getBodyLine(BufferedReader ds)throws IOException
+ {
+ Debug.enterVerbose( "RasRNPImplementation.getBodyLine: start." );
+
+ // obviously we are searching for what follows an empty line:
+ for(;;)
+ {
+ String s=ds.readLine();
+ if(s==null)
+ {
+ Debug.talkCritical( "RasRNPImplementation.getBodyLine: done. Unexpected EOF in rasmgr answer." );
+ Debug.leaveVerbose( "RasRNPImplementation.getBodyLine: done, with eof exception." );
+ throw new IOException("Unexpected EOF in rasmgr answer.");
+ }
+ if(s.length()==0)
+ break;
+ }
+ String result = ds.readLine();
+
+ Debug.leaveVerbose( "RasRNPImplementation.getBodyLine: done. result=" + result );
+ return result;
+ }
+
+ private Object executeQueryRequest(String parameters) throws RasQueryExecutionFailedException
+ {
+ Debug.enterVerbose( "RasRNPImplementation.executeQueryRequest: start. parameters=" + parameters );
+
+ startRequest(cmd_queryhttp);
+ encoder.addParameterInt32(pmt_clientid,clientID);
+ try
+ {
+ encoder.addParameterOpaque(pmt_queryString,parameters.getBytes("8859_1"));
+ }
+ catch(UnsupportedEncodingException e)
+ {
+ Debug.talkCritical( "RasRNPImplementation.executeQueryRequest: " + e.getMessage() );
+ Debug.leaveVerbose( "RasRNPImplementation.executeQueryRequest: done, " + e.getMessage() );
+ throw new RasClientInternalException("RasRNPImplementation","executeQueryRequest()",e.getMessage());
+ }
+ sendRequestGetAnswer();
+ checkForError();
+ decoder.getFirstParameter();
+ Object result= getResponse(decoder.getDataOpaque());
+
+ Debug.leaveVerbose( "RasRNPImplementation.executeQueryRequest: done. result=" + result );
+ return result;
+ }
+
+ private Object getResponse(byte[] opaqueAnswer)
+ throws RasQueryExecutionFailedException
+ {
+ Debug.enterVerbose( "RasRNPImplementation.getResponse: start." );
+
+ Object result=null;
+ DataInputStream in =new DataInputStream(new ByteArrayInputStream(opaqueAnswer));
+ byte[] b1 = new byte[1];
+ byte[] b4 = new byte[4];
+ byte endianess = 0;
+ String collType = null;
+ int numberOfResults = 0;
+ int dataSize = 0;
+ byte[] binData = null;
+ int readBytes = 0;
+ int readBytesTmp = 0;
+ DBag resultBag;
+ RasGMArray res = null;
+ try
+ {
+ in.read(b1);
+ int resultType = b1[0];
+ switch( resultType )
+ {
+ case RESPONSE_OK:
+ case RESPONSE_OK_NEGATIVE:
+ //Nothing todo
+ break;
+
+ // +++++++++++++++++++++++++++++++++++++++++++++++++
+ case RESPONSE_MDDS:
+ // read Endianess
+ while(in.read(b1) == 0);
+ endianess = b1[0];
+
+ // read Collection Type
+ collType = RasUtils.readString(in);
+
+ // read NumberOfResults
+ while(in.available() < 4);
+ in.read(b4);
+ numberOfResults = RasUtils.ubytesToInt(b4,endianess);
+
+ // Initialize return-set and parameters
+ resultBag = new RasBag();
+ String mddBaseType = null;
+ String domain = null;
+ String oid = "";
+ RasOID roid = null;
+
+ // do this for each result
+ for(int x = 0; x < numberOfResults; x++)
+ {
+ //read mddBaseType
+ mddBaseType = RasUtils.readString(in);
+
+ // read spatialDomain
+ domain = RasUtils.readString(in);
+
+ // read OID
+ oid = RasUtils.readString(in);
+ roid = new RasOID(oid);
+
+ // read size of binData
+ while(in.available() < 4);
+ in.read(b4);
+
+ dataSize = RasUtils.ubytesToInt(b4,endianess);
+
+ // read binData
+ binData = new byte[dataSize];
+ readBytes = 0;
+ readBytesTmp = 0;
+
+ while( (readBytesTmp != -1) && (readBytes < dataSize) )
+ {
+ readBytesTmp = in.read(binData,readBytes,dataSize-readBytes);
+ readBytes += readBytesTmp;
+ }
+
+ RasType rType = RasType.getAnyType(mddBaseType);
+ RasBaseType rb = null;
+
+ if(rType.getClass().getName().equals("rasj.RasMArrayType"))
+ {
+ RasMArrayType tmp = (RasMArrayType)rType;
+ rb = tmp.getBaseType();
+ }
+ else
+ {
+ Debug.talkCritical( "RasRNPImplementation.getResponse: collection element is no MArray." );
+ Debug.leaveVerbose( "RasRNPImplementation.getResponse: done, with exception." );
+ throw new RasClientInternalException("RasHttpRequest","execute()","element of MDD Collection is no MArray");
+ }
+ if(rb.isBaseType())
+ {
+ if(rb.isStructType())
+ {
+ RasStructureType sType = (RasStructureType)rb;
+ res = new RasGMArray(new RasMInterval(domain), 0);
+ res.setTypeLength(rb.getSize());
+ res.setArraySize(dataSize);
+ res.setArray(binData);
+ //insert into result set
+ resultBag.add(res);
+ break;
+ }
+ else
+ {
+ // It is a primitiveType
+ RasPrimitiveType pType = (RasPrimitiveType)rb;
+ switch(pType.getTypeID())
+ {
+ case RAS_BOOLEAN:
+ case RAS_BYTE:
+ case RAS_CHAR:
+ res = new RasMArrayByte(new RasMInterval(domain));
+ break;
+ case RAS_SHORT:
+ res = new RasMArrayShort(new RasMInterval(domain));
+ break;
+
+ case RAS_USHORT:
+ byte[] tmData = new byte[dataSize*2];
+ for(int i=0;i<dataSize*2;)
+ {
+ tmData[i] = 0;
+ tmData[i+1] = 0;
+ tmData[i+2] = binData[i/2];
+ tmData[i+3] = binData[i/2+1];
+ i = i+SIZE_OF_INTEGER;
+ }
+ binData = tmData;
+ res = new RasMArrayInteger(new RasMInterval(domain));
+ break;
+
+ case RAS_INT:
+ case RAS_LONG:
+ res = new RasMArrayInteger(new RasMInterval(domain));
+ break;
+ case RAS_ULONG:
+ byte[] tmpData = new byte[dataSize*2];
+ for(int i=0;i<dataSize*2;)
+ {
+ tmpData[i] = 0;
+ tmpData[i+1] = 0;
+ tmpData[i+2] = 0;
+ tmpData[i+3] = 0;
+ tmpData[i+4] = binData[i/2];
+ tmpData[i+5] = binData[i/2+1];
+ tmpData[i+6] = binData[i/2+2];
+ tmpData[i+7] = binData[i/2+3];
+ i = i+SIZE_OF_LONG;
+ }
+ binData = tmpData;
+ res = new RasMArrayLong(new RasMInterval(domain));
+ break;
+ case RAS_FLOAT:
+ res = new RasMArrayFloat(new RasMInterval(domain));
+ break;
+ case RAS_DOUBLE:
+ res = new RasMArrayDouble(new RasMInterval(domain));
+ break;
+ default:
+ res = new RasGMArray(new RasMInterval(domain), pType.getSize());
+ }
+ res.setArray(binData);
+ res.setOID(roid);
+ resultBag.add(res);
+ }
+ }
+ else
+ {
+ Debug.talkCritical( "RasRNPImplementation.getResponse: type is not base type." );
+ Debug.leaveVerbose( "RasRNPImplementation.getResponse: done, type is not base type." );
+ throw new RasClientInternalException("RasHttpRequest","execute()","Type of MDD is no Base Type");
+ }
+ } // for
+
+ result = resultBag;
+ in.close();
+
+ break;
+
+ // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ case RESPONSE_SKALARS:
+ // read Endianess
+ while(in.read(b1) == 0);
+ endianess = b1[0];
+ // read Collection Type
+ collType = RasUtils.readString(in);
+ RasType rt = new RasType();
+ try
+ {
+ rt = rt.getAnyType(collType);
+ }
+ catch(Exception e)
+ {
+ Debug.talkCritical( "RasRNPImplementation.getResponse: type not supported: " + rt );
+ Debug.leaveVerbose( "RasRNPImplementation.getResponse: done, unsupported type" );
+ throw new RasTypeNotSupportedException(rt + " as RasCollectionType");
+ }
+ if(rt.getTypeID()!=RasGlobalDefs.RAS_COLLECTION)
+ {
+ Debug.leaveCritical( "RasRNPImplementation.getResponse: done. type not supported: " + rt );
+ throw new RasTypeNotSupportedException(rt + " as RasCollectionType");
+ }
+
+ // read NumberOfResults
+ while(in.available() < 4)
+ ;
+ in.read(b4);
+ numberOfResults = RasUtils.ubytesToInt(b4,endianess);
+
+ // Initailize return-list
+ resultBag = new RasBag();
+
+ // do this for each result
+ for(int x = 0; x < numberOfResults; x++)
+ {
+ // read elementType
+ String elementType = RasUtils.readString(in);
+ RasType et = new RasType();
+ et = ((RasCollectionType)rt).getElementType();
+ // read size of binData
+ while(in.available() < 4)
+ ;
+ in.read(b4);
+ dataSize = RasUtils.ubytesToInt(b4,endianess);
+ // read binData
+ binData = new byte[dataSize];
+ readBytes = 0;
+ readBytesTmp = 0;
+ while( (readBytesTmp != -1) && (readBytes < dataSize) )
+ {
+ readBytesTmp = in.read(binData,readBytes,dataSize-readBytes);
+ readBytes += readBytesTmp;
+ }
+
+ ByteArrayInputStream bis = new ByteArrayInputStream(binData);
+ DataInputStream dis = new DataInputStream(bis);
+ // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ switch(et.getTypeID())
+ {
+ case RasGlobalDefs.RAS_MINTERVAL:
+ resultBag.add(new RasMInterval(new String(binData)));
+ break;
+ case RasGlobalDefs.RAS_SINTERVAL:
+ resultBag.add(new RasSInterval(new String(binData)));
+ break;
+ case RasGlobalDefs.RAS_POINT:
+ resultBag.add(new RasPoint(new String(binData)));
+ break;
+ case RasGlobalDefs.RAS_OID:
+ resultBag.add(new RasOID(new String(binData)));
+ break;
+ case RAS_BOOLEAN:
+ case RAS_BYTE:
+ case RAS_CHAR:
+ byte b = binData[0];
+ resultBag.add(new Byte(b));
+ break;
+ case RAS_DOUBLE:
+ double d = dis.readDouble();
+ resultBag.add(new Double(d));
+ break;
+ case RAS_FLOAT:
+ float f = dis.readFloat();
+ resultBag.add(new Float(f));
+ break;
+ case RAS_ULONG:
+ byte[] bu = new byte[8];
+ bu[0] = 0;
+ bu[1] = 0;
+ bu[2] = 0;
+ bu[3] = 0;
+ bu[4] = dis.readByte();
+ bu[5] = dis.readByte();
+ bu[6] = dis.readByte();
+ bu[7] = dis.readByte();
+ ByteArrayInputStream bis2 = new ByteArrayInputStream(bu);
+ DataInputStream dis2 = new DataInputStream(bis2);
+ long ul = dis2.readLong();
+ resultBag.add(new Long(ul));
+ break;
+ case RAS_LONG:
+ case RAS_INT:
+ int i = dis.readInt();
+ resultBag.add(new Integer(i));
+ break;
+ case RAS_USHORT:
+ int j = dis.readUnsignedShort();
+ resultBag.add(new Integer(j));
+ break;
+ case RAS_SHORT:
+ short s = dis.readShort();
+ resultBag.add(new Short(s));
+ break;
+ default:
+ Debug.talkCritical( "RasRNPImplementation.getResponse: type not supported: " + et );
+ Debug.leaveVerbose( "RasRNPImplementation.getResponse: done, unsupported type." );
+ throw new RasTypeNotSupportedException(et + " as ElementType ");
+ }
+ }
+ result = resultBag;
+ // close stream
+ in.close();
+ break;
+
+ //++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ case RESPONSE_ERROR:
+ // read Endianess
+ while(in.read(b1) == 0);
+ endianess = b1[0];
+ // read Error Number
+ while(in.available() < 4)
+ ;
+ in.read(b4);
+ int errNo = RasUtils.ubytesToInt(b4,endianess);
+ // read Line Number
+ while(in.available() < 4)
+ ;
+ in.read(b4);
+ int lineNo = RasUtils.ubytesToInt(b4,endianess);
+ // read Column Number
+ while(in.available() < 4)
+ ;
+ in.read(b4);
+ int colNo = RasUtils.ubytesToInt(b4,endianess);
+ // read token
+ String token = RasUtils.readString(in);
+ Debug.leaveCritical( "RasRNPImplementation.getResponse: query failed, errNo=" + errNo + ", lineNo=" + lineNo + ", colNo=" + colNo + ", token=" + token );
+ throw new RasQueryExecutionFailedException(errNo,lineNo,colNo,token);
+ //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ case RESPONSE_INT:
+ // read Integer Value
+ while(in.available() < 4)
+ ;
+ in.read(b4);
+ result = new Integer(RasUtils.ubytesToInt(b4,endianess));
+ break;
+
+ //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ case RESPONSE_OID:
+ // read Values
+ String sys = RasUtils.readString(in);
+ String base = RasUtils.readString(in);
+ double d = in.readDouble();
+ resultBag = new RasBag();
+ resultBag.add(new RasOID(sys, base, d));
+ result = resultBag;
+ // close stream
+ in.close();
+ break;
+ default:
+ break;
+ }
+ }
+ catch( IOException e )
+ {
+ Debug.talkCritical( "RasRNPImplementation.getResponse: " + e.getMessage() );
+ Debug.leaveVerbose( "RasRNPImplementation.getResponse: done, communication exception." );
+ throw new RasClientInternalException("RasRNPImplementation","getResponse()",e.getMessage());
+ }
+ catch( RasResultIsNoIntervalException e )
+ {
+ Debug.talkCritical( "RasRNPImplementation.getResponse: " + e.getMessage() );
+ Debug.leaveVerbose( "RasRNPImplementation.getResponse: done, result not an interval." );
+ throw new RasClientInternalException("RasRNPImplementation","getResponse()",e.getMessage());
+ }
+
+ Debug.leaveVerbose( "RasRNPImplementation.getResponse: done. result=" + result );
+ return result;
+ }
+
+ public void setUserIdentification(String userName, String plainPass)
+ {
+ Debug.enterVerbose( "RasRNPImplementation.setUserIdentification: start." );
+ MD5 md5 = new MD5();
+ String hex;
+ md5.Init();
+ md5.Update(plainPass);
+ hex = md5.asHex();
+ userIdentification= userName + ":" + hex;
+ Debug.leaveVerbose( "RasRNPImplementation.setUserIdentification: done." );
+ }
+
+ private String strHostID = null;
+ static private int idcounter = 0;
+
+ /**
+ generate a unique request ID using IP address, some bit mangling
+ is done only once, this id then is used always
+ **/
+ private String uniqueRequestID()
+ {
+ Debug.enterVerbose( "RasRNPImplementation.uniqueRequestID: start." );
+ if(strHostID == null)
+ {
+ long hostid = 0;
+ try
+ {
+ InetAddress addr = InetAddress.getLocalHost();
+ // Get IP Address
+ byte[] ipAddr = addr.getAddress();
+
+ for(int i=0;i<ipAddr.length; i++)
+ {
+ int ss = (int)ipAddr[i];
+ if(ss<0) ss = 256 + ss;
+ hostid = hostid * 256 + ss;
+ }
+ }
+ catch (UnknownHostException e) // cannot obtain IP address?
+ {
+ Random random = new Random(); // then use other mechanism
+ hostid = random.nextInt();
+ }
+ idcounter = (idcounter + 1) &0xF;
+ // it's unique enough, we don't need such a huge number
+ strHostID = "" + hostid + ':' + (System.currentTimeMillis() & 0xFFFFFFF0) + idcounter;
+ }
+
+ Debug.leaveVerbose( "RasRNPImplementation.uniqueRequestID: done. result=" + strHostID );
+ return strHostID;
+ }
+
+ } // RasRNPImplementation
+
+//##########################################################################################
+class MD5State
+ {
+ /**
+ * 128-byte state
+ */
+ int state[];
+
+ /**
+ * 64-bit character count (could be true Java long?)
+ */
+ int count[];
+
+ /**
+ * 64-byte buffer (512 bits) for storing to-be-hashed characters
+ */
+ byte buffer[];
+
+ public MD5State()
+ {
+ buffer = new byte[64];
+ count = new int[2];
+ state = new int[4];
+
+ state[0] = 0x67452301;
+ state[1] = 0xefcdab89;
+ state[2] = 0x98badcfe;
+ state[3] = 0x10325476;
+
+ count[0] = count[1] = 0;
+ }
+
+ /** Create this State as a copy of another state */
+ public MD5State (MD5State from)
+ {
+ this();
+
+ int i;
+
+ for (i = 0; i < buffer.length; i++)
+ this.buffer[i] = from.buffer[i];
+
+ for (i = 0; i < state.length; i++)
+ this.state[i] = from.state[i];
+
+ for (i = 0; i < count.length; i++)
+ this.count[i] = from.count[i];
+ }
+ }; // MD5State
+
+/**
+ * Implementation of RSA's MD5 hash generator
+ *
+ * @version $Revision: 1.8 $
+ * @author Santeri Paavolainen <sjpaavol@cc.helsinki.fi>
+ */
+
+class MD5
+ {
+ /**
+ * MD5 state
+ */
+ MD5State state;
+
+ /**
+ * If Final() has been called, finals is set to the current finals
+ * state. Any Update() causes this to be set to null.
+ */
+ MD5State finals;
+
+ /**
+ * Padding for Final()
+ */
+ static byte padding[] =
+ {
+ (byte) 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ /**
+ * Initialize MD5 internal state (object can be reused just by
+ * calling Init() after every Final()
+ */
+ public synchronized void Init ()
+ {
+ state = new MD5State();
+ finals = null;
+ }
+
+ /**
+ * Class constructor
+ */
+ public MD5 ()
+ {
+ this.Init();
+ }
+
+ /**
+ * Initialize class, and update hash with ob.toString()
+ *
+ * @param ob Object, ob.toString() is used to update hash
+ * after initialization
+ */
+ public MD5 (Object ob)
+ {
+ this();
+ Update(ob.toString());
+ }
+
+ private int rotate_left (int x, int n)
+ {
+ return (x << n) | (x >>> (32 - n));
+ }
+
+ /* I wonder how many loops and hoops you'll have to go through to
+ get unsigned add for longs in java */
+
+ private int uadd (int a, int b)
+ {
+ long aa, bb;
+ aa = ((long) a) & 0xffffffffL;
+ bb = ((long) b) & 0xffffffffL;
+
+ aa += bb;
+
+ return (int) (aa & 0xffffffffL);
+ }
+
+ private int uadd (int a, int b, int c)
+ {
+ return uadd(uadd(a, b), c);
+ }
+
+ private int uadd (int a, int b, int c, int d)
+ {
+ return uadd(uadd(a, b, c), d);
+ }
+
+ private int FF (int a, int b, int c, int d, int x, int s, int ac)
+ {
+ a = uadd(a, ((b & c) | (~b & d)), x, ac);
+ return uadd(rotate_left(a, s), b);
+ }
+
+ private int GG (int a, int b, int c, int d, int x, int s, int ac)
+ {
+ a = uadd(a, ((b & d) | (c & ~d)), x, ac);
+ return uadd(rotate_left(a, s), b);
+ }
+
+ private int HH (int a, int b, int c, int d, int x, int s, int ac)
+ {
+ a = uadd(a, (b ^ c ^ d), x, ac);
+ return uadd(rotate_left(a, s) , b);
+ }
+
+ private int II (int a, int b, int c, int d, int x, int s, int ac)
+ {
+ a = uadd(a, (c ^ (b | ~d)), x, ac);
+ return uadd(rotate_left(a, s), b);
+ }
+
+ private int[] Decode (byte buffer[], int len, int shift)
+ {
+ int out[];
+ int i, j;
+
+ out = new int[16];
+
+ for (i = j = 0; j < len; i++, j += 4)
+ {
+ out[i] = ((int) (buffer[j + shift] & 0xff)) |
+ (((int) (buffer[j + 1 + shift] & 0xff)) << 8) |
+ (((int) (buffer[j + 2 + shift] & 0xff)) << 16) |
+ (((int) (buffer[j + 3 + shift] & 0xff)) << 24);
+ }
+ return out;
+ }
+
+ private void Transform (MD5State state, byte buffer[], int shift)
+ {
+ int
+ a = state.state[0],
+ b = state.state[1],
+ c = state.state[2],
+ d = state.state[3],
+ x[];
+
+ x = Decode(buffer, 64, shift);
+
+ /* Round 1 */
+ a = FF (a, b, c, d, x[ 0], 7, 0xd76aa478); /* 1 */
+ d = FF (d, a, b, c, x[ 1], 12, 0xe8c7b756); /* 2 */
+ c = FF (c, d, a, b, x[ 2], 17, 0x242070db); /* 3 */
+ b = FF (b, c, d, a, x[ 3], 22, 0xc1bdceee); /* 4 */
+ a = FF (a, b, c, d, x[ 4], 7, 0xf57c0faf); /* 5 */
+ d = FF (d, a, b, c, x[ 5], 12, 0x4787c62a); /* 6 */
+ c = FF (c, d, a, b, x[ 6], 17, 0xa8304613); /* 7 */
+ b = FF (b, c, d, a, x[ 7], 22, 0xfd469501); /* 8 */
+ a = FF (a, b, c, d, x[ 8], 7, 0x698098d8); /* 9 */
+ d = FF (d, a, b, c, x[ 9], 12, 0x8b44f7af); /* 10 */
+ c = FF (c, d, a, b, x[10], 17, 0xffff5bb1); /* 11 */
+ b = FF (b, c, d, a, x[11], 22, 0x895cd7be); /* 12 */
+ a = FF (a, b, c, d, x[12], 7, 0x6b901122); /* 13 */
+ d = FF (d, a, b, c, x[13], 12, 0xfd987193); /* 14 */
+ c = FF (c, d, a, b, x[14], 17, 0xa679438e); /* 15 */
+ b = FF (b, c, d, a, x[15], 22, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+ a = GG (a, b, c, d, x[ 1], 5, 0xf61e2562); /* 17 */
+ d = GG (d, a, b, c, x[ 6], 9, 0xc040b340); /* 18 */
+ c = GG (c, d, a, b, x[11], 14, 0x265e5a51); /* 19 */
+ b = GG (b, c, d, a, x[ 0], 20, 0xe9b6c7aa); /* 20 */
+ a = GG (a, b, c, d, x[ 5], 5, 0xd62f105d); /* 21 */
+ d = GG (d, a, b, c, x[10], 9, 0x2441453); /* 22 */
+ c = GG (c, d, a, b, x[15], 14, 0xd8a1e681); /* 23 */
+ b = GG (b, c, d, a, x[ 4], 20, 0xe7d3fbc8); /* 24 */
+ a = GG (a, b, c, d, x[ 9], 5, 0x21e1cde6); /* 25 */
+ d = GG (d, a, b, c, x[14], 9, 0xc33707d6); /* 26 */
+ c = GG (c, d, a, b, x[ 3], 14, 0xf4d50d87); /* 27 */
+ b = GG (b, c, d, a, x[ 8], 20, 0x455a14ed); /* 28 */
+ a = GG (a, b, c, d, x[13], 5, 0xa9e3e905); /* 29 */
+ d = GG (d, a, b, c, x[ 2], 9, 0xfcefa3f8); /* 30 */
+ c = GG (c, d, a, b, x[ 7], 14, 0x676f02d9); /* 31 */
+ b = GG (b, c, d, a, x[12], 20, 0x8d2a4c8a); /* 32 */
+
+ /* Round 3 */
+ a = HH (a, b, c, d, x[ 5], 4, 0xfffa3942); /* 33 */
+ d = HH (d, a, b, c, x[ 8], 11, 0x8771f681); /* 34 */
+ c = HH (c, d, a, b, x[11], 16, 0x6d9d6122); /* 35 */
+ b = HH (b, c, d, a, x[14], 23, 0xfde5380c); /* 36 */
+ a = HH (a, b, c, d, x[ 1], 4, 0xa4beea44); /* 37 */
+ d = HH (d, a, b, c, x[ 4], 11, 0x4bdecfa9); /* 38 */
+ c = HH (c, d, a, b, x[ 7], 16, 0xf6bb4b60); /* 39 */
+ b = HH (b, c, d, a, x[10], 23, 0xbebfbc70); /* 40 */
+ a = HH (a, b, c, d, x[13], 4, 0x289b7ec6); /* 41 */
+ d = HH (d, a, b, c, x[ 0], 11, 0xeaa127fa); /* 42 */
+ c = HH (c, d, a, b, x[ 3], 16, 0xd4ef3085); /* 43 */
+ b = HH (b, c, d, a, x[ 6], 23, 0x4881d05); /* 44 */
+ a = HH (a, b, c, d, x[ 9], 4, 0xd9d4d039); /* 45 */
+ d = HH (d, a, b, c, x[12], 11, 0xe6db99e5); /* 46 */
+ c = HH (c, d, a, b, x[15], 16, 0x1fa27cf8); /* 47 */
+ b = HH (b, c, d, a, x[ 2], 23, 0xc4ac5665); /* 48 */
+
+ /* Round 4 */
+ a = II (a, b, c, d, x[ 0], 6, 0xf4292244); /* 49 */
+ d = II (d, a, b, c, x[ 7], 10, 0x432aff97); /* 50 */
+ c = II (c, d, a, b, x[14], 15, 0xab9423a7); /* 51 */
+ b = II (b, c, d, a, x[ 5], 21, 0xfc93a039); /* 52 */
+ a = II (a, b, c, d, x[12], 6, 0x655b59c3); /* 53 */
+ d = II (d, a, b, c, x[ 3], 10, 0x8f0ccc92); /* 54 */
+ c = II (c, d, a, b, x[10], 15, 0xffeff47d); /* 55 */
+ b = II (b, c, d, a, x[ 1], 21, 0x85845dd1); /* 56 */
+ a = II (a, b, c, d, x[ 8], 6, 0x6fa87e4f); /* 57 */
+ d = II (d, a, b, c, x[15], 10, 0xfe2ce6e0); /* 58 */
+ c = II (c, d, a, b, x[ 6], 15, 0xa3014314); /* 59 */
+ b = II (b, c, d, a, x[13], 21, 0x4e0811a1); /* 60 */
+ a = II (a, b, c, d, x[ 4], 6, 0xf7537e82); /* 61 */
+ d = II (d, a, b, c, x[11], 10, 0xbd3af235); /* 62 */
+ c = II (c, d, a, b, x[ 2], 15, 0x2ad7d2bb); /* 63 */
+ b = II (b, c, d, a, x[ 9], 21, 0xeb86d391); /* 64 */
+
+ state.state[0] += a;
+ state.state[1] += b;
+ state.state[2] += c;
+ state.state[3] += d;
+ }
+
+ /**
+ * Updates hash with the bytebuffer given (using at maximum length bytes from
+ * that buffer)
+ *
+ * @param state Which state is updated
+ * @param buffer Array of bytes to be hashed
+ * @param offset Offset to buffer array
+ * @param length Use at maximum `length' bytes (absolute
+ * maximum is buffer.length)
+ */
+ public void Update (MD5State stat, byte buffer[], int offset, int length)
+ {
+ int index, partlen, i, start;
+ finals = null;
+ /* Length can be told to be shorter, but not inter */
+ if ((length - offset)> buffer.length)
+ length = buffer.length - offset;
+ /* compute number of bytes mod 64 */
+ index = (int) (stat.count[0] >>> 3) & 0x3f;
+ if ((stat.count[0] += (length << 3)) <
+ (length << 3))
+ stat.count[1]++;
+ stat.count[1] += length >>> 29;
+ partlen = 64 - index;
+ if (length >= partlen)
+ {
+ for (i = 0; i < partlen; i++)
+ stat.buffer[i + index] = buffer[i + offset];
+
+ Transform(stat, stat.buffer, 0);
+
+ for (i = partlen; (i + 63) < length; i+= 64)
+ Transform(stat, buffer, i);
+
+ index = 0;
+ }
+ else
+ i = 0;
+ /* buffer remaining input */
+ if (i < length)
+ {
+ start = i;
+ for (; i < length; i++)
+ stat.buffer[index + i - start] = buffer[i + offset];
+ }
+ }
+
+
+ public void Update (byte buffer[], int offset, int length)
+ {
+ Update(this.state, buffer, offset, length);
+ }
+
+ public void Update (byte buffer[], int length)
+ {
+ Update(this.state, buffer, 0, length);
+ }
+
+ /**
+ * Updates hash with given array of bytes
+ *
+ * @param buffer Array of bytes to use for updating the hash
+ */
+ public void Update (byte buffer[])
+ {
+ Update(buffer, 0, buffer.length);
+ }
+
+ /**
+ * Updates hash with a single byte
+ *
+ * @param b Single byte to update the hash
+ */
+ public void Update (byte b)
+ {
+ byte buffer[] = new byte[1];
+ buffer[0] = b;
+
+ Update(buffer, 1);
+ }
+
+ /**
+ * Update buffer with given string.
+ *
+ * @param s String to be update to hash (is used as
+ * s.getBytes())
+ */
+ public void Update (String s)
+ {
+ byte chars[];
+
+ /* deprecated chars = new byte[s.length()];
+ s.getBytes(0, s.length(), chars, 0);
+ */
+ chars = s.getBytes();
+
+ Update(chars, chars.length);
+ }
+
+ /**
+ * Update buffer with a single integer (only & 0xff part is used,
+ * as a byte)
+ *
+ * @param i Integer value, which is then converted to
+ * byte as i & 0xff
+ */
+
+ public void Update (int i)
+ {
+ Update((byte) (i & 0xff));
+ }
+
+ private byte[] Encode (int input[], int len)
+ {
+ int i, j;
+ byte out[];
+
+ out = new byte[len];
+
+ for (i = j = 0; j < len; i++, j += 4)
+ {
+ out[j] = (byte) (input[i] & 0xff);
+ out[j + 1] = (byte) ((input[i] >>> 8) & 0xff);
+ out[j + 2] = (byte) ((input[i] >>> 16) & 0xff);
+ out[j + 3] = (byte) ((input[i] >>> 24) & 0xff);
+ }
+
+ return out;
+ }
+
+ /**
+ * Returns array of bytes (16 bytes) representing hash as of the
+ * current state of this object. Note: getting a hash does not
+ * invalidate the hash object, it only creates a copy of the real
+ * state which is finalized.
+ *
+ * @return Array of 16 bytes, the hash of all updated bytes
+ */
+ public synchronized byte[] Final ()
+ {
+ byte bits[];
+ int index, padlen;
+ MD5State fin;
+
+ if (finals == null)
+ {
+ fin = new MD5State(state);
+
+ bits = Encode(fin.count, 8);
+
+ index = (int) ((fin.count[0] >>> 3) & 0x3f);
+ padlen = (index < 56) ? (56 - index) : (120 - index);
+
+ Update(fin, padding, 0, padlen);
+ /**/
+ Update(fin, bits, 0, 8);
+
+ /* Update() sets finalds to null */
+ finals = fin;
+ }
+
+ return Encode(finals.state, 16);
+ }
+
+ /**
+ * Turns array of bytes into string representing each byte as
+ * unsigned hex number.
+ *
+ * @param hash Array of bytes to convert to hex-string
+ * @return Generated hex string
+ */
+ public static String asHex (byte hash[])
+ {
+ StringBuffer buf = new StringBuffer(hash.length * 2);
+ int i;
+
+ for (i = 0; i < hash.length; i++)
+ {
+ if (((int) hash[i] & 0xff) < 0x10)
+ buf.append("0");
+
+ buf.append(Long.toString((int) hash[i] & 0xff, 16));
+ }
+
+ return buf.toString();
+ }
+
+ /**
+ * Returns 32-character hex representation of this objects hash
+ *
+ * @return String of this object's hash
+ */
+ public String asHex ()
+ {
+ return asHex(this.Final());
+ }
+ } // MD5
+
+
diff --git a/java/rasj/rnp/Rnp.class b/java/rasj/rnp/Rnp.class
new file mode 100644
index 0000000..1eb010e
--- /dev/null
+++ b/java/rasj/rnp/Rnp.class
Binary files differ
diff --git a/java/rasj/rnp/Rnp.java b/java/rasj/rnp/Rnp.java
new file mode 100644
index 0000000..7b2c311
--- /dev/null
+++ b/java/rasj/rnp/Rnp.java
@@ -0,0 +1,54 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+package rasj.rnp;
+
+import java.io.*;
+
+public class Rnp
+ {
+ public static final int rnpProtocolId = 0xc12d7f01; // this is swap(25112001);
+
+ public static final int fgt_None = 0;
+ public static final int fgt_Command = 1;
+ public static final int fgt_OkAnswer = 2;
+ public static final int fgt_Error = 3;
+ public static final int fgt_DiscardedRequest = 4;
+
+ public static final int dtt_None = 0;
+ public static final int dtt_Asciiz = 1;
+ public static final int dtt_Int32 = 2;
+ public static final int dtt_Float32 = 3;
+ public static final int dtt_Double64 = 4;
+ public static final int dtt_Opaque = 5;
+ }
+
diff --git a/java/rasj/rnp/RnpBaseClientComm.class b/java/rasj/rnp/RnpBaseClientComm.class
new file mode 100644
index 0000000..0849f81
--- /dev/null
+++ b/java/rasj/rnp/RnpBaseClientComm.class
Binary files differ
diff --git a/java/rasj/rnp/RnpBaseClientComm.java b/java/rasj/rnp/RnpBaseClientComm.java
new file mode 100644
index 0000000..1da636f
--- /dev/null
+++ b/java/rasj/rnp/RnpBaseClientComm.java
@@ -0,0 +1,207 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+package rasj.rnp;
+
+import rasj.*;
+import rasj.global.*;
+import java.io.*;
+import java.net.*;
+
+
+public class RnpBaseClientComm
+ {
+ RnpEncoder encoder;
+ RnpDecoder decoder;
+ int serverID;
+ String rasServerHost;
+ int rasServerPort;
+
+ public RnpBaseClientComm(int serverType)
+ {
+ Debug.enterVerbose( "RnpBaseClientComm.RnpBaseClientComm: start. serverType=" + serverType );
+ encoder = new RnpEncoder();
+ serverID = serverType;
+ Debug.leaveVerbose( "RnpBaseClientComm.RnpBaseClientComm: done." );
+ }
+
+ public void setConnectionParameters(String s, int p)
+ {
+ Debug.enterVerbose( "RnpBaseClientComm.setConnectionParameters: start. server=" + s + ", port=" + p );
+ rasServerHost = s;
+ rasServerPort = p;
+ Debug.leaveVerbose( "RnpBaseClientComm.setConnectionParameters: done." );
+ }
+
+ public void startRequest(int commandCode)
+ {
+ Debug.enterVerbose( "RnpBaseClientComm.startRequest: start. cmdCode=" + commandCode );
+ encoder.startMessage(serverID);
+ encoder.startFragment(Rnp.fgt_Command,commandCode);
+ Debug.leaveVerbose( "RnpBaseClientComm.startRequest: done." );
+ }
+
+ public void startMessage()
+ {
+ Debug.enterVerbose( "RnpBaseClientComm.startMessage: start." );
+ encoder.startMessage(serverID);
+ Debug.leaveVerbose( "RnpBaseClientComm.startMessage: done." );
+ }
+
+ public void startFragment(int commandCode)
+ {
+ Debug.enterVerbose( "RnpBaseClientComm.startFragment: start. cmdCode=" + commandCode );
+ encoder.startFragment(Rnp.fgt_Command,commandCode);
+ Debug.leaveVerbose( "RnpBaseClientComm.startFragment: done." );
+ }
+
+ public void endFragment()
+ {
+ Debug.enterVerbose( "RnpBaseClientComm.endFragment: start." );
+ encoder.endFragment();
+ Debug.leaveVerbose( "RnpBaseClientComm.endFragment: done." );
+ }
+
+ public void endMessage()
+ {
+ Debug.enterVerbose( "RnpBaseClientComm.endMessage: start." );
+ encoder.endMessage();
+ Debug.leaveVerbose( "RnpBaseClientComm.endMessage: done." );
+ }
+
+ public void turboSendRequestGetAnswer()
+ {
+ Debug.enterVerbose( "RnpBaseClientComm.turboSendRequestGetAnswer: start." );
+ RnpMessage answer=communicate(rasServerHost,rasServerPort,encoder.message);
+ decoder = new RnpDecoder(answer);
+ Debug.leaveVerbose( "RnpBaseClientComm.turboSendRequestGetAnswer: done." );
+ }
+
+ public void sendRequestGetAnswer()
+ {
+ Debug.enterVerbose( "RnpBaseClientComm.sendRequestGetAnswer: start." );
+
+ encoder.endFragment();
+ encoder.endMessage();
+ RnpMessage answer=communicate(rasServerHost,rasServerPort,encoder.message);
+ decoder = new RnpDecoder(answer);
+ decoder.getFirstFragment();
+
+ Debug.leaveVerbose( "RnpBaseClientComm.sendRequestGetAnswer: done." );
+ }
+
+ public void checkForError() throws RasQueryExecutionFailedException
+ {
+ Debug.enterVerbose( "RnpBaseClientComm.checkForError: start." );
+ if(decoder.getFragmentType() != Rnp.fgt_Error)
+ {
+ Debug.leaveVerbose( "RnpBaseClientComm.checkForError: done." );
+ return;
+ }
+ decoder.getFirstParameter();// error type
+ int errorType = decoder.getParameterType();
+ if(errorType == 3) //"ert_Other"
+ {
+ decoder.getNextParameter();
+ String s = decoder.getDataAsString();
+ Debug.leaveCritical( "RnpBaseClientComm.checkForError: done. query failed: " + s );
+ throw new RasQueryExecutionFailedException(s);
+ }
+ else
+ {
+ Debug.leaveCritical( "RnpBaseClientComm.checkForError: done. query failed, unexpected error: " + errorType );
+ throw new RasQueryExecutionFailedException(1000,0,0,"");
+ }
+ // we never get here
+ }
+
+ public RnpMessage communicate(String server, int port, RnpMessage message)
+ {
+ Debug.enterVerbose( "RnpBaseClientComm.communicate: start. server=" + server + ", port=" + port );
+
+ Socket socket=null;
+ RnpMessage receivedMessage= null;
+ DataOutputStream dos = null;
+
+ try
+ {
+ Debug.talkVerbose( "RnpBaseClientComm.communicate: server=" + server + ", port=" + port );
+ socket=new Socket(server, port);
+ }
+ catch(UnknownHostException e11)
+ {
+ Debug.leaveCritical( "RnpBaseClientComm.communicate: error: socket target unknown: " + e11.getMessage() );
+ throw new RasConnectionFailedException(RasGlobalDefs.MANAGER_CONN_FAILED,server);
+ }
+ catch(IOException e12)
+ {
+ Debug.leaveCritical( "RnpBaseClientComm.communicate: error: socket io exception: " + e12.getMessage() );
+ throw new RasClientInternalException("RnpBaseClientComm","communicate()",e12.getMessage());
+ }
+
+ try
+ {
+ dos = new DataOutputStream(socket.getOutputStream());
+ message.write(dos);
+ }
+ catch(IOException e2)
+ {
+ Debug.leaveCritical( "RnpBaseClientComm.communicate: error: cannot write to socket: " + e2.getMessage() );
+ throw new RasClientInternalException("RnpBaseClientComm","communicate()",e2.getMessage());
+ }
+
+ try
+ {
+ DataInputStream dis = new DataInputStream(socket.getInputStream());
+ receivedMessage = new RnpMessage();
+ receivedMessage.read(dis);
+ //receivedMessage.print();
+ dos.close();
+ dis.close();
+ }
+ catch(IOException e3)
+ {
+ Debug.leaveCritical( "RnpBaseClientComm.communicate: error: rcv io exception: " + e3.getMessage() );
+ throw new RasClientInternalException("RnpBaseClientComm","communicate()", e3.getMessage() );
+ }
+ catch(RnpException e4)
+ {
+ Debug.leaveCritical( "RnpBaseClientComm.communicate: error: RnpException: " + e4.getMessage() );
+ throw new RasClientInternalException("RnpBaseClientComm","communicate()",e4.getMessage());
+ }
+
+ Debug.leaveVerbose( "RnpBaseClientComm.communicate: done. result=" + receivedMessage );
+ return receivedMessage;
+ }
+
+ } // RnpBaseClientComm
+
diff --git a/java/rasj/rnp/RnpDecoder.class b/java/rasj/rnp/RnpDecoder.class
new file mode 100644
index 0000000..56ab0ef
--- /dev/null
+++ b/java/rasj/rnp/RnpDecoder.class
Binary files differ
diff --git a/java/rasj/rnp/RnpDecoder.java b/java/rasj/rnp/RnpDecoder.java
new file mode 100644
index 0000000..5eea077
--- /dev/null
+++ b/java/rasj/rnp/RnpDecoder.java
@@ -0,0 +1,170 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+package rasj.rnp;
+
+import java.io.*;
+
+
+public class RnpDecoder
+ {
+
+ public RnpMessage message;
+ private RnpFragment currentFragment;
+ private RnpParameter currentParameter;
+ private int fragmentIndex;
+
+
+ RnpDecoder(RnpMessage rnpmessage)
+ {
+ message=rnpmessage;
+ currentFragment = null;
+ currentParameter = null;
+ fragmentIndex = 0;
+ }
+
+ void verify() throws RnpException
+ {
+ if(message.header.protocolId != Rnp.rnpProtocolId)
+ throw new RnpException("Not a RNP message");
+
+ if(message.header.messageEndianness != 0)
+ throw new RnpException("Incorrect endianness");
+
+ if(message.header.majorVersion != 1 || message.header.minorVersion != 0 || message.header.dataStart != RnpMessageHeader.length)
+ throw new RnpException("Incorrect message version");
+ }
+
+ int getServerType()
+ {
+ return message.header.serverType;
+ }
+
+ byte getDesiredEndianness()
+ {
+ return message.header.desiredEndianness;
+ }
+
+ byte getMessageEndianness()
+ {
+ return message.header.messageEndianness;
+ }
+
+ int getMessageLength()
+ {
+ return message.header.totalMessageLength;
+ }
+
+ int countFragments()
+ {
+ return message.header.nrFragments;
+ }
+ byte getMajorVersion()
+ {
+ return message.header.majorVersion;
+ }
+ byte getMinorVersion()
+ {
+ return message.header.minorVersion;
+ }
+
+ RnpFragment getFirstFragment()
+ {
+ fragmentIndex = 0;
+ currentFragment = (RnpFragment)message.fragments.get(0);
+ return currentFragment;
+ }
+
+ RnpFragment getNextFragment(RnpFragment fragment)
+ {
+ fragmentIndex++;
+ currentFragment = (RnpFragment)message.fragments.get(fragmentIndex);
+ return currentFragment;
+ }
+
+ int getFragmentType()
+ {
+ //fgt_None, fgt_Command, fgt_OkAnswer, fgt_Error, fgt_DiscardedRequest
+ return currentFragment.getFragmentType();
+ }
+ int countParameters()
+ {
+ return currentFragment.countParameters();
+ }
+ RnpParameter getFirstParameter()
+ {
+ currentParameter = currentFragment.getFirstParameter();
+ return currentParameter;
+ }
+ RnpParameter getNextParameter()
+ {
+ currentParameter = currentFragment.getNextParameter();
+ return currentParameter;
+ }
+ int getParameterType()
+ {
+ return currentParameter.paramType;
+ }
+ int getDataLength()
+ {
+ return currentParameter.getDataLength();
+ }
+
+ int getDataType()
+ {
+ // dtt_None,dtt_Asciiz, dtt_Int32,dtt_Double64, dtt_Opaque
+ return currentParameter.dataType;
+ }
+
+ int getDataAsInteger()
+ {
+ return ((ParameterInt32)currentParameter).data;
+ }
+ float getDataAsFloat()
+ {
+ return((ParameterFloat32)currentParameter).data;
+ }
+ double getDataAsDouble()
+ {
+ return((ParameterDouble64)currentParameter).data;
+ }
+ String getDataAsString()
+ {
+ return new String(((ParameterString)currentParameter).data);
+ }
+ byte[] getDataOpaque()
+ {
+ return((ParameterOpaque)currentParameter).data;
+ }
+ }
+
diff --git a/java/rasj/rnp/RnpEncoder.class b/java/rasj/rnp/RnpEncoder.class
new file mode 100644
index 0000000..c4a9fdf
--- /dev/null
+++ b/java/rasj/rnp/RnpEncoder.class
Binary files differ
diff --git a/java/rasj/rnp/RnpEncoder.java b/java/rasj/rnp/RnpEncoder.java
new file mode 100644
index 0000000..d27bfe2
--- /dev/null
+++ b/java/rasj/rnp/RnpEncoder.java
@@ -0,0 +1,102 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+package rasj.rnp;
+
+import java.io.*;
+import java.util.*;
+
+public class RnpEncoder
+ {
+ public int serverType = 0;
+ RnpMessage message = null;
+
+ public void startMessage(int serverType)
+ {
+ message=new RnpMessage();
+ message.header = new RnpMessageHeader(serverType);
+ message.fragments = new Vector();
+ }
+ public void setEndianess()
+ {
+ }
+ public void startFragment(int fragmentType, int command)
+ {
+ message.currentFragment = new RnpFragment(fragmentType,command);
+ }
+ void addFragment(RnpFragmentHeader fHeader)
+ {
+ message.header.nrFragments++;
+ message.header.dataLength += fHeader.totalLength;
+ message.header.totalMessageLength += fHeader.totalLength;
+ }
+
+ void addParameterInt32(int parameterType, int data)
+ {
+ message.currentFragment.addParameterInt32(parameterType,data);
+ }
+
+ void addParameterFloat32(int parameterType, float data)
+ {
+ message.currentFragment.addParameterFloat32(parameterType,data);
+ }
+
+ void addParameterDouble64(int parameterType, double data)
+ {
+ message.currentFragment.addParameterDouble64(parameterType,data);
+ }
+
+ void addParameterString(int parameterType, String data)
+ {
+ message.currentFragment.addParameterString(parameterType,data);
+ }
+
+ void addParameterOpaque(int parameterType, byte[] data)
+ {
+ message.currentFragment.addParameterOpaque(parameterType,data);
+ }
+
+ void endFragment()
+ {
+ if(message.currentFragment == null) return; // correct "assert"
+ message.fragments.add(message.currentFragment);
+ addFragment(message.currentFragment.getHeader());
+ message.currentFragment = null;
+ }
+
+ void endMessage()
+ {
+ }
+
+ }
+
diff --git a/java/rasj/rnp/RnpException.class b/java/rasj/rnp/RnpException.class
new file mode 100644
index 0000000..8422a28
--- /dev/null
+++ b/java/rasj/rnp/RnpException.class
Binary files differ
diff --git a/java/rasj/rnp/RnpException.java b/java/rasj/rnp/RnpException.java
new file mode 100644
index 0000000..254c304
--- /dev/null
+++ b/java/rasj/rnp/RnpException.java
@@ -0,0 +1,44 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+package rasj.rnp;
+
+
+public class RnpException extends Exception
+ {
+ public RnpException(String s)
+ {
+ super(s);
+ }
+ }
+
diff --git a/java/rasj/rnp/RnpFragment.class b/java/rasj/rnp/RnpFragment.class
new file mode 100644
index 0000000..3927ada
--- /dev/null
+++ b/java/rasj/rnp/RnpFragment.class
Binary files differ
diff --git a/java/rasj/rnp/RnpFragment.java b/java/rasj/rnp/RnpFragment.java
new file mode 100644
index 0000000..204744f
--- /dev/null
+++ b/java/rasj/rnp/RnpFragment.java
@@ -0,0 +1,152 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+package rasj.rnp;
+
+import java.util.*;
+import java.io.*;
+
+
+public class RnpFragment
+ {
+ RnpFragmentHeader header;
+ Vector parameters;
+ int parameterIndex = 0;
+
+ RnpFragment(int fragmentType, int command)
+ {
+ header = new RnpFragmentHeader(fragmentType, command);
+ parameters = new Vector();
+ }
+
+ RnpFragmentHeader getHeader()
+ {
+ return header;
+ }
+
+ void addParameterInt32(int parameterType, int data)
+ {
+ addParameter(new ParameterInt32(parameterType,data));
+ }
+
+ void addParameterFloat32(int parameterType, float data)
+ {
+ addParameter(new ParameterFloat32(parameterType,data));
+ }
+
+ void addParameterDouble64(int parameterType, double data)
+ {
+ addParameter(new ParameterDouble64(parameterType,data));
+ }
+ void addParameterString(int parameterType, String data)
+ {
+ addParameter(new ParameterString(parameterType,data));
+ }
+
+ void addParameterOpaque(int parameterType, byte[] data)
+ {
+ addParameter(new ParameterOpaque(parameterType,data));
+ }
+
+ private void addParameter(RnpParameter param)
+ {
+ parameters.add(param);
+ header.addParameter(param.getTotalLength());
+ }
+
+ void write(DataOutputStream dataStream) throws IOException
+ {
+ header.write(dataStream);
+ for(int i=0; i < header.countParameters(); i++)
+ {
+ RnpParameter param = (RnpParameter)parameters.get(i);
+ param.write(dataStream);
+ }
+ }
+
+ void read(DataInputStream dataStream) throws IOException, RnpException
+ {
+ header.read(dataStream);
+ for(int i=0; i < header.countParameters(); i++)
+ {
+ RnpParameter param = RnpParameter.constructFromStream(dataStream);
+ parameters.add(param);
+ }
+ }
+
+ void print()
+ {
+ header.print();
+ for(int i=0; i < header.countParameters(); i++)
+ {
+ System.out.print(" " + i+ " ");
+ RnpParameter param = (RnpParameter)parameters.get(i);
+ param.print();
+ }
+ }
+
+
+ int getFragmentType()
+ {
+ return header.fragmType;
+ }
+
+ int getCommand()
+ {
+ return header.command;
+ }
+
+ int countParameters()
+ {
+ return header.nrParams;
+ }
+
+ int getFragmentLength()
+ {
+ return header.totalLength;
+ }
+
+ RnpParameter getFirstParameter()
+ {
+ parameterIndex = 0;
+ return (RnpParameter)parameters.get(0);
+ }
+
+ RnpParameter getNextParameter()
+ {
+ parameterIndex++;
+ return (RnpParameter)parameters.get(parameterIndex);
+ }
+
+ }
+
diff --git a/java/rasj/rnp/RnpFragmentHeader.class b/java/rasj/rnp/RnpFragmentHeader.class
new file mode 100644
index 0000000..685e967
--- /dev/null
+++ b/java/rasj/rnp/RnpFragmentHeader.class
Binary files differ
diff --git a/java/rasj/rnp/RnpFragmentHeader.java b/java/rasj/rnp/RnpFragmentHeader.java
new file mode 100644
index 0000000..e18e0f4
--- /dev/null
+++ b/java/rasj/rnp/RnpFragmentHeader.java
@@ -0,0 +1,93 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+package rasj.rnp;
+
+import java.util.*;
+import java.io.*;
+
+
+public class RnpFragmentHeader
+ {
+ int fragmType; //{FragmentType command, okAnswer, error}
+ int command;
+ int nrParams;
+ int totalLength;
+
+ public static final int length = 16;
+
+ RnpFragmentHeader(int fragmentType, int nCommand)
+ {
+ fragmType = fragmentType;
+ command = nCommand;
+ nrParams = 0;
+ totalLength = length;
+ }
+
+ int countParameters()
+ {
+ return nrParams;
+ }
+
+ void print()
+ {
+ System.out.print(" type=" + fragmType);
+ System.out.print(" Command=" + command);
+ System.out.print(" nrParams=" + nrParams);
+ System.out.print(" totalLength=" + totalLength);
+ System.out.println();
+ }
+
+ void write(DataOutputStream dataStream) throws IOException
+ {
+ dataStream.writeInt(fragmType);
+ dataStream.writeInt(command);
+ dataStream.writeInt(nrParams);
+ dataStream.writeInt(totalLength);
+ }
+ void read(DataInputStream dataStream) throws IOException
+ {
+ fragmType = dataStream.readInt();
+ command = dataStream.readInt();
+ nrParams = dataStream.readInt();
+ totalLength = dataStream.readInt();
+ }
+
+ void addParameter(int size)
+ {
+ nrParams++;
+ totalLength += size;
+ }
+ }
+
+
diff --git a/java/rasj/rnp/RnpMessage.class b/java/rasj/rnp/RnpMessage.class
new file mode 100644
index 0000000..effbe2d
--- /dev/null
+++ b/java/rasj/rnp/RnpMessage.class
Binary files differ
diff --git a/java/rasj/rnp/RnpMessage.java b/java/rasj/rnp/RnpMessage.java
new file mode 100644
index 0000000..5739ee7
--- /dev/null
+++ b/java/rasj/rnp/RnpMessage.java
@@ -0,0 +1,83 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+package rasj.rnp;
+
+
+import java.util.*;
+import java.io.*;
+
+
+public class RnpMessage
+ {
+ public RnpMessageHeader header;
+ public Vector fragments;
+ public RnpFragment currentFragment = null;
+
+ void write(DataOutputStream dataStream) throws IOException
+ {
+ header.write(dataStream);
+ for(int i=0; i < header.countFragments(); i++)
+ {
+ RnpFragment frag = (RnpFragment)fragments.get(i);
+ frag.write(dataStream);
+ }
+ }
+
+ void read(DataInputStream dataStream) throws IOException, RnpException
+ {
+ header = new RnpMessageHeader(0);
+ header.read(dataStream);
+ fragments = new Vector();
+ for(int i=0; i < header.countFragments(); i++)
+ {
+ currentFragment = new RnpFragment(0,0);
+ currentFragment.read(dataStream);
+ fragments.add(currentFragment);
+ }
+ currentFragment = null;
+ }
+
+ void print()
+ {
+ header.print();
+ for(int i=0; i < header.countFragments(); i++)
+ {
+ System.out.print("Fragment " + i + " ");
+ RnpFragment frag = (RnpFragment)fragments.get(i);
+ frag.print();
+ }
+ }
+
+ }
+
diff --git a/java/rasj/rnp/RnpMessageHeader.class b/java/rasj/rnp/RnpMessageHeader.class
new file mode 100644
index 0000000..edd6cfc
--- /dev/null
+++ b/java/rasj/rnp/RnpMessageHeader.class
Binary files differ
diff --git a/java/rasj/rnp/RnpMessageHeader.java b/java/rasj/rnp/RnpMessageHeader.java
new file mode 100644
index 0000000..5191940
--- /dev/null
+++ b/java/rasj/rnp/RnpMessageHeader.java
@@ -0,0 +1,150 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+package rasj.rnp;
+
+
+import java.util.*;
+import java.io.*;
+
+
+public class RnpMessageHeader
+ {
+ int protocolId;
+ byte messageEndianness;
+ byte desiredEndianness;
+ byte majorVersion;
+ byte minorVersion;
+ int totalMessageLength;
+ int nrFragments;
+ int serverType;
+ int authInfoStart;
+ int authInfoLength;
+ int comprInfoStart;
+ int comprInfoLength;
+ int dataStart;
+ int dataLength;
+ //int _unused[5];
+
+ public static final int length = 64;
+
+ RnpMessageHeader(int nServerType)
+ {
+ protocolId = Rnp.rnpProtocolId;
+ messageEndianness = 0; // big endianness
+ desiredEndianness = 0; // big also
+ majorVersion = 1;
+ minorVersion = 0;
+ totalMessageLength = length;
+ nrFragments = 0;
+ serverType = nServerType;
+ authInfoStart = 0;
+ authInfoLength = 0;
+ comprInfoStart = 0;
+ comprInfoLength = 0;
+ dataStart = length;
+ dataLength = 0;
+ }
+
+ int countFragments()
+ {
+ return nrFragments;
+ }
+
+ void print()
+ {
+ System.out.println("RNP Header");
+ System.out.println(" totalLength=" + totalMessageLength);
+ System.out.println(" nrFragments=" + nrFragments);
+ System.out.println(" serverType=" + serverType);
+ System.out.println(" dataStart=" + dataStart);
+ System.out.println(" dataLength=" + dataLength);
+ System.out.println("");
+ }
+
+ void write(DataOutputStream dataStream) throws IOException
+ {
+ dataStream.writeInt(protocolId);
+ dataStream.writeByte(messageEndianness);
+ dataStream.writeByte(desiredEndianness);
+ dataStream.writeByte(majorVersion);
+ dataStream.writeByte(minorVersion);
+
+ dataStream.writeInt(totalMessageLength);
+ dataStream.writeInt(nrFragments);
+ dataStream.writeInt(serverType);
+ dataStream.writeInt(authInfoStart);
+ dataStream.writeInt(authInfoLength);
+ dataStream.writeInt(comprInfoStart);
+ dataStream.writeInt(comprInfoLength);
+ dataStream.writeInt(dataStart);
+ dataStream.writeInt(dataLength);
+
+ // the unused 5 ints
+ dataStream.writeInt(0);
+ dataStream.writeInt(0);
+ dataStream.writeInt(0);
+ dataStream.writeInt(0);
+ dataStream.writeInt(0);
+
+ }
+
+ void read(DataInputStream dataStream) throws IOException, RnpException
+ {
+ protocolId = dataStream.readInt();
+ messageEndianness = dataStream.readByte();
+ desiredEndianness = dataStream.readByte();
+ majorVersion = dataStream.readByte();
+ minorVersion = dataStream.readByte();
+
+ totalMessageLength = dataStream.readInt();
+ nrFragments = dataStream.readInt();
+ serverType = dataStream.readInt();
+ authInfoStart = dataStream.readInt();
+ authInfoLength = dataStream.readInt();
+ comprInfoStart = dataStream.readInt();
+ comprInfoLength = dataStream.readInt();
+ dataStart = dataStream.readInt();
+ dataLength = dataStream.readInt();
+
+ // the unused 5 ints
+ dataStream.readInt();
+ dataStream.readInt();
+ dataStream.readInt();
+ dataStream.readInt();
+ dataStream.readInt();
+
+ //verify();
+ }
+ }
+
diff --git a/java/rasj/rnp/RnpParameter.class b/java/rasj/rnp/RnpParameter.class
new file mode 100644
index 0000000..183302c
--- /dev/null
+++ b/java/rasj/rnp/RnpParameter.class
Binary files differ
diff --git a/java/rasj/rnp/RnpParameter.java b/java/rasj/rnp/RnpParameter.java
new file mode 100644
index 0000000..01cba64
--- /dev/null
+++ b/java/rasj/rnp/RnpParameter.java
@@ -0,0 +1,325 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+package rasj.rnp;
+
+import java.io.*;
+
+public abstract class RnpParameter
+ {
+ int paramType;
+ int dataType;
+ int dataLength;
+ int totalLength;
+
+ public static final int headerSize = 16;
+
+ protected RnpParameter(int pT, int dT, int dL,int tL)
+ {
+ paramType = pT;
+ dataType = dT;
+ dataLength = dL;
+ totalLength = tL;
+ }
+
+ void print()
+ {
+ System.out.print(" Parameter type=" + paramType);
+ System.out.print(" data type=" + dataType);
+ System.out.print(" dataLength="+dataLength);
+ System.out.print(" totalLength=" + totalLength);
+ printSpecific();
+ }
+
+ void write(DataOutputStream dataStream) throws IOException
+ {
+ dataStream.writeInt(paramType);
+ dataStream.writeInt(dataType);
+ dataStream.writeInt(dataLength);
+ dataStream.writeInt(totalLength);
+ writeSpecific(dataStream);
+ }
+
+ int getTotalLength()
+ {
+ return totalLength;
+ }
+ int getDataLength()
+ {
+ return dataLength;
+ }
+ int getPaddLength()
+ {
+ return totalLength - dataLength - headerSize;
+ }
+
+ void computeTotalAlignedLength()
+ {
+ totalLength = (dataLength + headerSize + 3) & 0xFFFFFFFC;
+ }
+
+ static RnpParameter constructFromStream(DataInputStream dataStream) throws IOException, RnpException
+ {
+ int paramType = dataStream.readInt();
+ int dataType = dataStream.readInt();
+ int dataLength = dataStream.readInt();
+ int totalLength = dataStream.readInt();
+
+ RnpParameter result = null;
+ switch(dataType)
+ {
+ case Rnp.dtt_Int32: result = new ParameterInt32(paramType, dataType, dataLength, totalLength);
+ break;
+ case Rnp.dtt_Float32: result = new ParameterFloat32(paramType, dataType, dataLength, totalLength);
+ break;
+ case Rnp.dtt_Double64: result = new ParameterDouble64(paramType, dataType, dataLength, totalLength);
+ break;
+ case Rnp.dtt_Asciiz: result = new ParameterString(paramType, dataType, dataLength, totalLength);
+ break;
+ case Rnp.dtt_Opaque: result = new ParameterOpaque(paramType, dataType, dataLength, totalLength);
+ break;
+ default: throw new RnpException("Incorrect parameter data type: " + dataType);
+ }
+ result.readSpecific(dataStream);
+ //System.out.println("constructFromStream: "); result.print();
+ return result;
+ }
+
+ int getParameterType() { return paramType; }
+ int getDataType() { return dataType; }
+
+ abstract void writeSpecific(DataOutputStream dataStream) throws IOException;
+ abstract void readSpecific(DataInputStream dataStream) throws IOException;
+ abstract void printSpecific();
+ }
+
+
+
+ class ParameterInt32 extends RnpParameter
+ {
+ int data;
+ public static final int length = 4;
+
+ ParameterInt32(int parameterType, int nData)
+ {
+ super(parameterType,Rnp.dtt_Int32, length, length + headerSize);
+ data = nData;
+ }
+
+ ParameterInt32(int pT, int dT, int dL, int tL)
+ {
+ super(pT, dT, dL,tL);
+ }
+
+ void printSpecific()
+ {
+ System.out.println(" value=" + data);
+ }
+
+ void writeSpecific(DataOutputStream dataStream) throws IOException
+ {
+ dataStream.writeInt(data);
+ }
+
+ void readSpecific(DataInputStream dataStream) throws IOException
+ {
+ data = dataStream.readInt();
+ }
+
+ int getData()
+ {
+ return data;
+ }
+ }
+
+
+ class ParameterFloat32 extends RnpParameter
+ {
+ float data;
+ public static final int length = 4;
+
+ ParameterFloat32(int parameterType, float nData)
+ {
+ super(parameterType,Rnp.dtt_Float32, length, length + headerSize);
+ data = nData;
+ }
+
+ ParameterFloat32(int pT, int dT, int dL, int tL)
+ {
+ super(pT, dT, dL,tL);
+ }
+
+ void printSpecific()
+ {
+ System.out.println(" value=" + data);
+ }
+
+ void writeSpecific(DataOutputStream dataStream) throws IOException
+ {
+ dataStream.writeFloat(data);
+ }
+
+ void readSpecific(DataInputStream dataStream) throws IOException
+ {
+ data = dataStream.readFloat();
+ }
+
+ float getData()
+ {
+ return data;
+ }
+ }
+
+
+ class ParameterDouble64 extends RnpParameter
+ {
+ double data;
+ public static final int length = 8;
+
+ ParameterDouble64(int parameterType, double nData)
+ {
+ super(parameterType,Rnp.dtt_Double64, length, length + headerSize);
+ data = nData;
+ }
+ ParameterDouble64(int pT, int dT, int dL, int tL)
+ {
+ super(pT, dT, dL, tL);
+ }
+
+ void printSpecific()
+ {
+ System.out.println(" value=" + data);
+ }
+
+ void writeSpecific(DataOutputStream dataStream) throws IOException
+ {
+ dataStream.writeDouble(data);
+ }
+
+ void readSpecific(DataInputStream dataStream) throws IOException
+ {
+ data = dataStream.readDouble();
+ }
+
+ double getData()
+ {
+ return data;
+ }
+ }
+
+ class ParameterString extends RnpParameter
+ {
+ byte[] data;
+
+ ParameterString(int parameterType, String nData)
+ {
+ super(parameterType,Rnp.dtt_Asciiz,0,0);
+ data = nData.getBytes();
+ // do not forget: Strings are ASCIIZ in RNP!!
+ dataLength = data.length+1;
+ computeTotalAlignedLength();
+ }
+
+ ParameterString(int pT, int dT, int dL,int tL)
+ {
+ super(pT, dT, dL,tL);
+ }
+
+ void printSpecific()
+ {
+ System.out.println(" value=" + getData());
+ }
+
+ void writeSpecific(DataOutputStream dataStream) throws IOException
+ {
+ dataStream.write(data,0,dataLength - 1);
+ dataStream.writeByte(0);
+
+ for(int i=0;i<getPaddLength();i++) dataStream.writeByte(0);
+ }
+
+ void readSpecific(DataInputStream dataStream) throws IOException
+ {
+ data = new byte[dataLength - 1];
+ dataStream.readFully(data,0,dataLength - 1);
+ dataStream.readByte();
+ for(int i=0;i<getPaddLength();i++) dataStream.readByte();
+ }
+
+ String getData()
+ {
+ return new String(data);
+ }
+ }
+
+ class ParameterOpaque extends RnpParameter
+ {
+ byte[] data;
+
+ ParameterOpaque(int parameterType, byte[] nData)
+ {
+ super(parameterType,Rnp.dtt_Opaque,nData.length,0);
+ data = nData;
+ computeTotalAlignedLength();
+ }
+
+ ParameterOpaque(int pT, int dT, int dL,int tL)
+ {
+ super(pT, dT, dL,tL);
+ }
+
+ void printSpecific()
+ {
+ System.out.println(" value=(opaque data, size=" + data.length +")");
+ }
+
+ void writeSpecific(DataOutputStream dataStream) throws IOException
+ {
+ dataStream.write(data,0,dataLength);
+ for(int i=0;i<getPaddLength();i++) dataStream.writeByte(0);
+ }
+
+ void readSpecific(DataInputStream dataStream) throws IOException
+ {
+ data = new byte[dataLength];
+ dataStream.readFully(data,0,dataLength);
+
+ for(int i=0;i<getPaddLength();i++) dataStream.readByte();
+ }
+
+ byte[] getData()
+ {
+ return data;
+ }
+ }
+
diff --git a/java/rasj/rnp/test/Client.java b/java/rasj/rnp/test/Client.java
new file mode 100644
index 0000000..34c9c45
--- /dev/null
+++ b/java/rasj/rnp/test/Client.java
@@ -0,0 +1,104 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * test socket communication.
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+import java.io.*;
+import java.net.*;
+import java.lang.*;
+import java.util.*;
+
+public class Client
+{
+ private static final String DEFAULT_SERVER = "localhost";
+ private static final int DEFAULT_PORT = 7001;
+
+ private static String server = DEFAULT_SERVER;
+ private static int port = DEFAULT_PORT;
+
+ private static void communicate()
+ {
+ System.out.println( "server=" + server + ", port=" + port );
+
+ try
+ {
+ Socket socket = new Socket( server, port );
+
+ PrintStream ps = new PrintStream(socket.getOutputStream());
+ ps.print("Hello " + server + " at port " + port + " !\n" );
+ ps.flush();
+
+ BufferedReader ds = new BufferedReader(new InputStreamReader(socket.getInputStream()));
+ System.out.println( "server delivered: '" + ds.readLine() );
+
+ ps.close();
+ ds.close();
+ socket.close();
+ System.out.println( "socket closed." );
+ }
+ catch(UnknownHostException e2)
+ {
+ System.out.println( "host unknown: " + e2.getMessage() );
+ }
+ catch(IOException e1)
+ {
+ System.out.println( "io exception: " + e1.getMessage() );
+ }
+ }
+
+ public static void main( String args[] )
+ {
+ System.out.println( "Socket test started." );
+
+ if (args.length != 0 && args.length != 2)
+ System.out.println( "usage: java Client [server port]" );
+ else if (args.length == 2)
+ {
+ server = args[0];
+ try
+ {
+ port = Integer.parseInt( args[1] );
+ }
+ catch(NumberFormatException e)
+ {
+ System.err.println( "Error: illegal port parameter: " + args[1] );
+ return;
+ }
+ }
+
+ communicate();
+
+ System.out.println( "Socket test done." );
+ }
+}
+
+
diff --git a/java/rasj/test/Makefile b/java/rasj/test/Makefile
new file mode 100644
index 0000000..2538fb1
--- /dev/null
+++ b/java/rasj/test/Makefile
@@ -0,0 +1,116 @@
+# -*-Makefile-*- (for Emacs)
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>. # Top Level makefile. This points to the various modules that have to be build
+# and/or deployed
+#
+# MAKEFILE FOR:
+# package RasJ
+#
+# COMMENTS:
+# - incomplete!
+# - not part of systemtest: TestHttp.java
+# - test env settings to be taken from next higher Makefile when ready
+# - move .log manually to .log.orig if you want to set this as new reference output
+##################################################################
+######################### Definitions ############################
+
+# standard include with general options
+include $(RMANBASE)/Makefile.inc
+
+SRCS = TestRasPoint.java TestRasInterval.java TestMArray.java \
+ TestException.java TestDbTa.java TestOdmg.java TestQuery.java \
+ MassLoadTest.java
+
+OBJS = ${SRCS:%.java=%.class}
+
+# test programs (java needs them without .class suffix)
+TESTS = TestRasPoint TestRasInterval TestDbTa TestException
+# TESTS = ${OBJS:%.class=%}
+
+MISCCLEAN = *.class *.log
+
+# FIXME: should make use of general variable
+JAVA = java
+# Java options needed for testing
+JAVAOPTS = -cp .:$(CLASSPATH)
+
+# directory where HTML documentation is created
+DOCDIR := $(DOCBASE)/java/rasj/test
+
+########################### Targets ##############################
+
+# compile everything
+.PHONY : all
+all: $(OBJS)
+
+# run the test for all classes, compare log generated with archived log, abort on first error
+.PHONY: systemtest
+systemtest: $(TESTS)
+
+# later this should be of that structure:
+# $(JAVA) $(JAVAOPTS) $@ > $@.log && diff $@.log.orig $@.log
+
+TestRasPoint: TestRasPoint.class
+ $(JAVA) $(JAVAOPTS) $@
+
+TestRasInterval: TestRasInterval.class
+ $(JAVA) $(JAVAOPTS) $@
+
+TestMArray: TestMArray.class
+ $(JAVA) $(JAVAOPTS) $@ --server NONE_YET --database RASBASE --collname NONEXISTENT
+
+MassLoadTest: MassLoadTest.class
+ $(JAVA) $(JAVAOPTS) $@ --server $(SERVER) --port $(PORT) --database $(DATABASE) --user $(USER) --passwd $(PASSWD)
+
+TestException: TestException.class
+ $(JAVA) $(JAVAOPTS) $@ --server $(SERVER) --port $(PORT) --database $(DATABASE) --user $(USER) --passwd $(PASSWD)
+
+TestDbTa: TestDbTa.class
+ $(JAVA) $(JAVAOPTS) $@ --server $(SERVER) --port $(PORT) --database $(DATABASE) --user $(USER) --passwd $(PASSWD)
+
+TestOdmg: TestOdmg.class
+ $(JAVA) $(JAVAOPTS) $@ --server $(SERVER) --port $(PORT) --database $(DATABASE) --user $(USER) --passwd $(PASSWD)
+
+TestQuery: TestQuery.class
+ $(JAVA) $(JAVAOPTS) $@
+
+# not part of systemtest: TestHttp.java
+
+# create javadoc HTML doc:
+.PHONY: docu
+docu: $(SRCS)
+ -mkdir -p $(DOCDIR_RASJTEST)
+ $(JAVADOC) -private -author -d $(DOCDIR_RASJTEST) -sourcepath . *.java
+
+# remove all that can be generated
+clean:
+ -rm -f $(MISCCLEAN)
+ -rm -rf $(DOCDIR)
+
+# delete all files
+empty:
+ -rm -f $(SRCS) $(MISCCLEAN)
+
+############################ Dependencies #######################
+
+# general rules
+include $(RMANBASE)/Makefile.rel
diff --git a/java/rasj/test/Makefile.dep b/java/rasj/test/Makefile.dep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/java/rasj/test/Makefile.dep
diff --git a/java/rasj/test/MassLoadTest.java b/java/rasj/test/MassLoadTest.java
new file mode 100644
index 0000000..6ec4fbe
--- /dev/null
+++ b/java/rasj/test/MassLoadTest.java
@@ -0,0 +1,324 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+package rasj.test;
+
+import rasj.*;
+import rasj.global.*;
+import org.odmg.*;
+
+import java.util.*;
+import java.io.*;
+
+
+public class MassLoadTest implements RasGlobalDefs
+{
+
+ public static void main(String[] args)
+ {
+
+ String hostname = null;
+ String port = null;
+ Database mydb = null;
+ Transaction myta = null;
+ RasGMArray myMDD = null;
+ Implementation myApp = null;
+ OQLQuery myQuery = null;
+ String collectionName = "testCollection";
+ int tileSize = 1000;
+ int overallSize = 200000;
+ int commitInterval = 50;
+
+
+ /*******************************************
+ * *
+ * Usage: MassLoadTest hostname [port] *
+ * *
+ *******************************************/
+
+ // we need the hostname
+ if(args.length>0 && args[0] == null)
+ {
+ System.out.println("Please provide the hostname as a parameter when calling this test-program.");
+ System.exit(-1);
+ }
+ else
+ hostname = args[0];
+
+ // is there a port specified?
+ if(args.length>1 && args[1] != null)
+ port = args[1];
+ else
+ port = "8080";
+
+ try {
+ myApp = new RasImplementation("http://" + hostname + ":" + port);
+ mydb = myApp.newDatabase();
+ System.err.println("Open Database ...");
+ mydb.open("RASBASE",Database.OPEN_READ_WRITE);
+ System.err.println(" ok.");
+ myta = myApp.newTransaction();
+ System.err.println("Begin transaction ...");
+ myta.begin();
+ System.err.println(" ok.");
+
+ //create test collection
+ System.err.println("Create a test collection ...");
+ myQuery = myApp.newOQLQuery();
+ myQuery.create("create collection $1 GreySet");
+ //myQuery.create("drop collection $1");
+
+ myQuery.bind(collectionName);
+ myQuery.execute();
+ System.err.println(" ok.");
+ myta.commit();
+
+ // init insertion tile
+ System.err.println("create test arrays ...");
+ myMDD = new RasGMArray(new RasMInterval("[0:" + (tileSize-1) + ",0:" + (tileSize-1) + "]"),1);
+ int cells = tileSize*tileSize;
+ byte[] mydata = new byte[cells];
+ for(int i = 0; i < cells; i++)
+ mydata[i]=0;
+ myMDD.setArray(mydata);
+ myMDD.setObjectTypeName("GreyImage");
+
+ // now insert tiles
+ boolean first = true;
+ myta.begin();
+ int dimX = 0;
+ int dimY = 0;
+ String domain = null;
+ int finished = 1;
+
+ int counter = (int)Math.abs(overallSize/tileSize);
+ for(int x = 0; x < counter; x++)
+ {
+ dimX += tileSize;
+ dimY = 0;
+ for(int y = 0; y < counter; y++)
+ {
+ dimY += tileSize;
+
+ // init mdd
+ RasGMArray myMDD2 = new RasGMArray(new RasMInterval("[" + String.valueOf(dimX-tileSize) + ":" + String.valueOf(dimX-1) + "," +
+ String.valueOf(dimY-tileSize) + ":" + String.valueOf(dimY-1) + "]"),1);
+ cells = tileSize*tileSize;
+ byte[] mydata2 = new byte[cells];
+ for(int i = 0; i < cells; i++)
+ mydata2[i]=0;
+ myMDD2.setArray(mydata2);
+ myMDD2.setObjectTypeName("GreyImage");
+
+ // prepare query
+ myQuery = myApp.newOQLQuery();
+ if(first)
+ {
+ myQuery.create("insert into $1 values $2");
+ first = false;
+ }
+ else
+ myQuery.create("update $1 AS img SET img ASSIGN $2");
+ myQuery.bind(collectionName);
+ myQuery.bind(myMDD2);
+
+ // execute query
+ System.err.println("Inserting tile " + myMDD2.spatialDomain());
+ myQuery.execute();
+ finished += 1;
+
+ // commit?
+ if(finished == commitInterval)
+ {
+ myta.commit();
+ System.err.println("... committed, begin new transaction ...");
+ myta = myApp.newTransaction();
+ myta.begin();
+ finished = 1;
+ }
+
+ }
+ // now write the rest of y if there is something left:
+ if(dimY < overallSize-1)
+ {
+ RasGMArray myMDD3 = new RasGMArray(new RasMInterval("[" + String.valueOf(dimX-tileSize) + ":" + String.valueOf(dimX-1) + "," +
+ String.valueOf(dimY) + ":" + String.valueOf(overallSize-1) + "]"),1);
+ cells = tileSize*(overallSize-dimY);
+ byte[] mydata3 = new byte[cells];
+ for(int i = 0; i < cells; i++)
+ mydata3[i]=0;
+ myMDD3.setArray(mydata3);
+ myMDD3.setObjectTypeName("GreyImage");
+
+ // prepare query
+ myQuery = myApp.newOQLQuery();
+ if(first)
+ {
+ myQuery.create("insert into $1 values $2");
+ first = false;
+ }
+ else
+ myQuery.create("update $1 AS img SET img ASSIGN $2");
+ myQuery.bind(collectionName);
+ myQuery.bind(myMDD3);
+
+ // execute query
+ System.err.println("Inserting tile " + myMDD3.spatialDomain());
+ myQuery.execute();
+ finished += 1;
+
+ // commit?
+ if(finished == commitInterval)
+ {
+ myta.commit();
+ System.err.println("... committed, begin new transaction ...");
+ myta = myApp.newTransaction();
+ myta.begin();
+ finished = 1;
+ }
+ }
+ }
+
+ // now write the rest of x if there is something left
+ dimY = 0;
+ if(dimX < overallSize-1)
+ {
+ for(int y = 0; y < counter; y++)
+ {
+ dimY += tileSize;
+
+ // init mdd
+ RasGMArray myMDD4 = new RasGMArray(new RasMInterval("[" + String.valueOf(dimX) + ":" + String.valueOf(overallSize-1) + "," +
+ String.valueOf(dimY-tileSize) + ":" + String.valueOf(dimY-1) + "]"),1);
+ cells = (overallSize-dimX)*tileSize;
+ byte[] mydata4 = new byte[cells];
+ for(int i = 0; i < cells; i++)
+ mydata4[i]=0;
+ myMDD4.setArray(mydata4);
+ myMDD4.setObjectTypeName("GreyImage");
+
+ // prepare query
+ myQuery = myApp.newOQLQuery();
+ if(first)
+ {
+ myQuery.create("insert into $1 values $2");
+ first = false;
+ }
+ else
+ myQuery.create("update $1 AS img SET img ASSIGN $2");
+ myQuery.bind(collectionName);
+ myQuery.bind(myMDD4);
+
+ // execute query
+ System.err.println("Inserting tile " + myMDD4.spatialDomain());
+ myQuery.execute();
+ finished += 1;
+
+ // commit?
+ if(finished == commitInterval)
+ {
+ myta.commit();
+ System.err.println("... committed, begin new transaction ...");
+ myta = myApp.newTransaction();
+ myta.begin();
+ finished = 1;
+ }
+ }
+
+ // now write the rest of y if available
+ if(dimY < overallSize-1)
+ {
+ RasGMArray myMDD5 = new RasGMArray(new RasMInterval("[" + String.valueOf(dimX) + ":" + String.valueOf(overallSize-1) + "," +
+ String.valueOf(dimY) + ":" + String.valueOf(overallSize-1) + "]"),1);
+ cells = (overallSize-dimX)*(overallSize-dimY);
+ byte[] mydata5 = new byte[cells];
+ for(int i = 0; i < cells; i++)
+ mydata5[i]=0;
+ myMDD5.setArray(mydata5);
+ myMDD5.setObjectTypeName("GreyImage");
+
+ // prepare query
+ myQuery = myApp.newOQLQuery();
+ if(first)
+ {
+ myQuery.create("insert into $1 values $2");
+ first = false;
+ }
+ else
+ myQuery.create("update $1 AS img SET img ASSIGN $2");
+ myQuery.bind(collectionName);
+ myQuery.bind(myMDD5);
+
+ // execute query
+ System.err.println("Inserting tile " + myMDD5.spatialDomain());
+ myQuery.execute();
+ finished += 1;
+ }
+ }
+
+ // READY!
+ myta.commit();
+ System.err.println("FINISHED!");
+
+
+ // drop test collection
+ myta = myApp.newTransaction();
+ myta.begin();
+ System.err.println("Drop test collection ...");
+ myQuery = myApp.newOQLQuery();
+ myQuery.create("drop collection $1");
+ myQuery.bind(collectionName);
+ myQuery.execute();
+ System.err.println(" ok.");
+ myta.commit();
+ myta = myApp.newTransaction();
+ myta.commit();
+
+
+
+ }
+
+ catch ( Exception e ) {
+ System.out.println("ERROR: ");
+ System.out.println(e.getMessage());
+
+ if(myta.isOpen())
+ {
+ System.err.println("Abort transaction ...");
+ myta.abort();
+ }
+ System.err.println("Close database ...");
+ try {
+ mydb.close();
+ System.err.println(" ok.");
+ }
+ catch ( Exception e2 ) {
+ }
+ System.err.println("Exiting...");
+ System.exit(-1);
+ }
+ }
+
+}
+
+
+
diff --git a/java/rasj/test/Systemtest_rasj.java b/java/rasj/test/Systemtest_rasj.java
new file mode 100644
index 0000000..50c33c5
--- /dev/null
+++ b/java/rasj/test/Systemtest_rasj.java
@@ -0,0 +1,295 @@
+package rasj.test;
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+import java.io.*;
+
+import rasj.*;
+import rasj.global.*;
+import org.odmg.*;
+
+
+// auxiliary classes for exception testing
+class TestRasResultIsNoCellException extends RasResultIsNoCellException
+{
+ TestRasResultIsNoCellException()
+ {
+ super();
+ }
+}
+
+class TestRasResultIsNoIntervalException extends RasResultIsNoIntervalException
+{
+ TestRasResultIsNoIntervalException()
+ {
+ super();
+ }
+}
+
+class TestRasClientInternalException extends RasClientInternalException
+{
+ TestRasClientInternalException(String msg)
+ {
+ super("Systemtest_rasj","TestExceptions",msg);
+ }
+}
+
+// main program
+/**
+ * class for testing rasj interface
+ * @version $$
+ */
+public class Systemtest_rasj
+{
+
+public static void main(String[] args)
+ {
+ String server = null;
+ String port = "7001";
+ boolean wrongUsage = false;
+
+ // get args
+ if(args.length == 0)
+ wrongUsage = true;
+ for(int i = 0; i < args.length; i+=2)
+ {
+ if (args[i].equals("-server"))
+ server = args[i+1];
+ else if (args[i].equals("-port"))
+ port = args[i+1];
+ else
+ wrongUsage = true;
+ }
+
+ if(wrongUsage)
+ {
+ System.err.println("Usage: Systemtest_rasj -s <servername> [ -p <port> ]");
+ System.exit(-1);
+ }
+
+ // start
+ Implementation myApp = new RasImplementation("http://" + server + ":" + port);
+
+ testExceptions(myApp);
+
+ testMArrays marrayTest = new testMArrays(server);
+
+ testIntervals intervalTest = new testIntervals();
+
+ }
+
+ // exception testing
+ static void testExceptions(Implementation imp)
+ {
+
+ boolean resultIsOk = false;
+ Database myDb = null;
+ Transaction myTa = null;
+ OQLQuery myQu = null;
+
+ System.err.println("\n### Testing exceptions:");
+
+ // RasConnectionFailedException
+ Implementation errorApp;
+ String logMsg;
+ try {
+ errorApp = new RasImplementation("wrongserver:8080");
+ myDb = errorApp.newDatabase();
+ logMsg = "Exception was not thrown";
+ myDb.open("RASBASE",Database.OPEN_READ_WRITE);
+ }
+ catch(RasConnectionFailedException e1) {
+ resultIsOk = true;
+ logMsg = e1.getMessage();
+ }
+ catch(ODMGException e2) {
+ logMsg = e2.getMessage();
+ }
+ log("RasConnectionFailedException",resultIsOk,logMsg);
+
+ // RasDimensionMismatchException
+ resultIsOk = false;
+ logMsg = "Exception was not thrown";
+ try {
+ RasMInterval test1;
+ RasMInterval test2 = new RasMInterval("[1:20,1:20]");
+ RasMInterval test3 = new RasMInterval("[1:4,1:9,1:6]");
+
+ test1 = test2.intersectionWith(test3);
+ }
+ catch(RasDimensionMismatchException e1) {
+ resultIsOk = true;
+ logMsg = e1.getMessage();
+ }
+ catch(Exception e2) {
+ logMsg = e2.getClass().getName() + ", " + e2.getMessage();
+ }
+ log("RasDimensionMismatchException",resultIsOk,logMsg);
+
+ // RasIndexOutOfBoundsException
+ resultIsOk = false;
+ logMsg = "Exception was not thrown";
+ try {
+ RasGMArray myMDD = new RasGMArray(new RasMInterval("[1:5,1:5]"),1);
+ byte[] retVal = myMDD.getCell(new RasPoint(4,7));
+ }
+ catch(RasIndexOutOfBoundsException e1) {
+ resultIsOk = true;
+ logMsg = e1.getMessage();
+ }
+ catch(RasResultIsNoIntervalException e2) {
+ //this cannot occur
+ }
+ catch(RasDimensionMismatchException e3) {
+ // this cannot occur
+ }
+ log("RasIndexOutOfBoundsException",resultIsOk,logMsg);
+
+ // RasClientInternalException
+ resultIsOk = false;
+ logMsg = "Exception was not thrown";
+ try {
+ throw new TestRasClientInternalException("This is a test error");
+ }
+ catch(RasClientInternalException e1) {
+ resultIsOk = true;
+ logMsg = e1.getMessage();
+ }
+ log("RasClientInternalException",resultIsOk,logMsg);
+
+ // RasResultIsNoCellException
+ resultIsOk = false;
+ logMsg = "Exception was not thrown";
+ try {
+ throw new TestRasResultIsNoCellException();
+ }
+ catch(RasResultIsNoCellException e1) {
+ resultIsOk = true;
+ logMsg = e1.getMessage();
+ }
+ log("RasResultIsNoCellException",resultIsOk,logMsg);
+
+ // RasResultIsNoIntervalException
+ resultIsOk = false;
+ logMsg = "Exception was not thrown";
+ try {
+ throw new TestRasResultIsNoIntervalException();
+ }
+ catch(RasResultIsNoIntervalException e1) {
+ resultIsOk = true;
+ logMsg = e1.getMessage();
+ }
+ log("RasResultIsNoIntervalException",resultIsOk,logMsg);
+
+ // RasStreamInputOverflowException
+ resultIsOk = false;
+ logMsg = "Exception was not thrown";
+ try {
+ RasMInterval int1 = new RasMInterval(2);
+ int1.stream(new RasSInterval("1:10"));
+ int1.stream(new RasSInterval("1:5"));
+ int1.stream(new RasSInterval("1:20"));
+ }
+ catch(RasResultIsNoIntervalException e1) {
+ //
+ }
+ catch(RasStreamInputOverflowException e3) {
+ resultIsOk = true;
+ logMsg = e3.getMessage();
+ }
+ log("RasStreamInputOverflowException",resultIsOk,logMsg);
+
+
+ // RasTypeInvalidException
+ resultIsOk = false;
+ logMsg = "Exception was not thrown";
+ try {
+ RasPrimitiveType myType = new RasPrimitiveType("myType",RasGlobalDefs.RAS_BOOLEAN);
+ myType.getFloat(new Object());
+ }
+ catch(RasTypeInvalidException e3) {
+ resultIsOk = true;
+ logMsg = e3.getMessage();
+ }
+ log("RasTypeInvalidException",resultIsOk,logMsg);
+
+ // RasTypeNotSupportedException
+ resultIsOk = false;
+ logMsg = "Exception was not thrown";
+ try {
+ throw new RasTypeNotSupportedException("RAS_TEST");
+ }
+ catch(RasTypeNotSupportedException e3) {
+ resultIsOk = true;
+ logMsg = e3.getMessage();
+ }
+ log("RasTypeNotSupportedException",resultIsOk,logMsg);
+ }
+
+
+
+
+
+ static void log(String testObject, boolean resultOK, String message)
+ {
+ if(resultOK)
+ System.err.println(testObject + " ... OK\n (" + message + ")");
+ else
+ {
+ System.err.println(testObject + " ... FAILED!\n (" + message + ")");
+ System.err.println("Continue? [y/n]");
+ BufferedReader br = new BufferedReader( new InputStreamReader(System.in));
+ try {
+ String answer = br.readLine();
+ while(answer != "")
+ {
+ if(answer.equals("n"))
+ System.exit(1);
+ else if(!answer.equals("y"))
+ {
+ System.err.println("Please answer y or n: ");
+ answer = br.readLine();
+ }
+ }
+ }
+ catch(IOException e1) {
+ //
+ }
+
+ }
+ }
+
+
+}
diff --git a/java/rasj/test/TestDbTa.java b/java/rasj/test/TestDbTa.java
new file mode 100644
index 0000000..846e337
--- /dev/null
+++ b/java/rasj/test/TestDbTa.java
@@ -0,0 +1,549 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * test rasj ODMG-level interface (database, TA, and basic query logic).
+ * TO BE DONE!
+ *
+ * PREREQUISITES:
+ * - Must have a database with at least one HTTP server running.
+ * - database must know basic types, in particular: GreySet.
+ * - login must allow read/write access to database
+ *
+ *
+ * COMMENTS:
+ * - testing philosophy is to run all tests and report. no exit code / exception
+ * is used for error indication; look into the output for ERROR_TAG instead.
+ * - unexpected exceptions are not caught, hence will make gmake fail and show the error
+ * - every test that fails must print a line containing ERROR_TAG
+ * </pre>
+ *********************************************************** */
+
+import java.lang.Integer;
+import org.odmg.*;
+import rasj.*;
+import rasj.odmg.*;
+
+public class TestDbTa
+ {
+ /**
+ * prefixes for test output
+ **/
+ static final String PREFIX_PROGRAM = "+++ +++ +++ ";
+ static final String PREFIX_TESTSET = "+++ +++ ";
+ static final String PREFIX_TESTCASE = "+++ ";
+
+ /**
+ * std error tag printed if a test fails
+ **/
+ static final String ERROR_TAG = "ERROR: ";
+
+ /**
+ * default values (override with cmd line option)
+ **/
+ static final String DEFAULT_HOST = "localhost";
+ static final int DEFAULT_PORT = 7001;
+ static final String DEFAULT_BASE = "RASBASE";
+ static final String DEFAULT_USER = "rasguest";
+ static final String DEFAULT_PASSWD = "rasguest";
+
+ /**
+ * global ODMG implementation object for use by all methods
+ **/
+ static RasImplementation myApp = null;
+
+ /**
+ * main program for testing
+ * on error, an exception is thrown (java main() knows no exit status)
+ **/
+ public static void main(String argv[]) throws Exception
+ {
+ String serv = DEFAULT_HOST;
+ int port = DEFAULT_PORT;
+ String base = DEFAULT_BASE;
+ String user = DEFAULT_USER;
+ String passwd = DEFAULT_PASSWD;
+ boolean wrongUsage = false; // error in cmd line params?
+
+ for (int i=argv.length-1; i>=0; i--)
+ {
+ if (argv[i].equals("--server"))
+ serv = argv[i+1];
+ else if (argv[i].equals("--port"))
+ {
+ try
+ {
+ port = Integer.parseInt(argv[i+1]);
+ }
+ catch(Exception e)
+ {
+ wrongUsage = true;
+ }
+ }
+ else if (argv[i].equals("--database"))
+ base = argv[i+1];
+ else if (argv[i].equals("--user"))
+ user = argv[i+1];
+ else if (argv[i].equals("--passwd"))
+ passwd = argv[i+1];
+ }
+
+ if (wrongUsage)
+ {
+ System.out.println( "Usage: TestDbTa [--server s] [--port p] [--database d] [--user u] [--passwd p]" );
+ System.out.println( "defaults: server=" + DEFAULT_HOST + ", port=" + DEFAULT_PORT + ", database=" + DEFAULT_BASE + ", user=" + DEFAULT_USER + ", passwd=" + DEFAULT_PASSWD );
+ System.exit(-1);
+ }
+
+ System.out.println( "rasdaman system test v5.1revC: testing class ODMG logic." );
+ System.out.println( PREFIX_PROGRAM + "system test started, using server " + serv + ", port " + port + ", database " + base + ", user=" + user + ", passwd=" + passwd );
+
+ myApp = new RasImplementation( "http://" + serv + ":" + port );
+ myApp.setUserIdentification(user, passwd);
+
+ // -- START test cases -------------------------------------------------
+ testDatabase( myApp, base );
+ testTransaction( myApp, base );
+ testAccessMode( myApp, base );
+ // -- END test cases ---------------------------------------------------
+
+ System.out.println( PREFIX_PROGRAM + "system test done." );
+ return;
+ } // main()
+
+ /**
+ * test database open/close
+ * any eventual exception that is not caught here is an error, and will cause an abort
+ **/
+ static void testDatabase( RasImplementation myApp, String database )
+ // throws RasDimensionMismatchException, RasIndexOutOfBoundsException
+ {
+ Database myDb = null;
+ System.out.println( PREFIX_TESTSET + "testing database open/close started." );
+
+ System.out.print( PREFIX_TESTCASE + "open db, null name..." );
+ try
+ {
+ myDb = myApp.newDatabase();
+ myDb.open( null, Database.OPEN_READ_ONLY );
+ System.out.println( ERROR_TAG + "does not catch this." );
+ }
+ catch(Exception e)
+ {
+ System.out.println( "OK, recognized: " + e.getMessage() );
+ }
+
+ // FIXME: PB6: inappropriate error message
+ System.out.print( PREFIX_TESTCASE + "open db, empty name..." );
+ try
+ {
+ myDb = myApp.newDatabase();
+ myDb.open( "", Database.OPEN_READ_ONLY );
+ System.out.println( ERROR_TAG + "does not catch this." );
+ }
+ catch(Exception e)
+ {
+ System.out.println( "OK, recognized: " + e.getMessage() );
+ }
+
+ System.out.print( PREFIX_TESTCASE + "open db, nonexisting db..." );
+ try
+ {
+ myDb = myApp.newDatabase();
+ myDb.open( "NO_SUCH_DATABASE", Database.OPEN_READ_ONLY );
+ System.out.println( ERROR_TAG + "does not catch this." );
+ }
+ catch(Exception e)
+ {
+ System.out.println( "OK, recognized: " + e.getMessage() );
+ }
+
+ // FIXME: PB6: inappropriate error message
+ // System.out.print( PREFIX_TESTCASE + "open db, negative accessMode value..." );
+ // try
+ // {
+ // myDb = myApp.newDatabase();
+ // myDb.open( database, -1 );
+ // System.out.println( ERROR_TAG + "does not catch this." );
+ // }
+ // catch(Exception e)
+ // {
+ // System.out.println( "OK, recognized: " + e.getMessage() );
+ // }
+
+ // FIXME: PB6: inappropriate error message
+ // System.out.print( PREFIX_TESTCASE + "open db, illegal accessMode..." );
+ // try
+ // {
+ // myDb = myApp.newDatabase();
+ // myDb.open( "NO_SUCH_DATABASE", 100 );
+ // System.out.println( ERROR_TAG + "does not catch this." );
+ // }
+ // catch(Exception e)
+ // {
+ // System.out.println( "OK, recognized: " + e.getMessage() );
+ // }
+
+ System.out.print( PREFIX_TESTCASE + "open db, good call..." );
+ try
+ {
+ myDb = myApp.newDatabase();
+ myDb.open( database, Database.OPEN_READ_ONLY );
+ Transaction myTa = myApp.newTransaction();
+ myTa.begin();
+ myTa.abort();
+ System.out.println( "OK, tested through beginTA." );
+ }
+ catch(Exception e)
+ {
+ System.out.println( ERROR_TAG + "good call does not open db: " + e.getMessage() );
+ }
+
+ System.out.print( PREFIX_TESTCASE + "close previously opened db..." );
+ try
+ {
+ myDb.close();
+ System.out.println( "OK." );
+ }
+ catch (Exception e)
+ {
+ System.out.println( ERROR_TAG + e.getMessage() );
+ }
+
+ System.out.print( PREFIX_TESTCASE + "can we open a transaction after closing db..." );
+ try
+ {
+ Transaction myTa = myApp.newTransaction();
+ myTa.begin();
+ System.out.println( ERROR_TAG + "unfortunately yes." );
+ }
+ catch(Exception e)
+ {
+ System.out.println( "OK, we can't." );
+ }
+
+ System.out.print( PREFIX_TESTCASE + "close db already closed..." );
+ try
+ {
+ myDb.close();
+ System.out.println( ERROR_TAG + "repeated close possible, alas." );
+ }
+ catch (Exception e)
+ {
+ System.out.println( "OK." );
+ }
+
+ System.out.println( PREFIX_TESTSET + "testing database open/close done.\n" );
+ return;
+ } // testDatabase()
+
+ /**
+ * test transaction open/close
+ * any eventual exception that is not caught here is an error, and will cause an abort
+ **/
+ static void testTransaction( RasImplementation myApp, String database ) throws ODMGException
+ {
+ Database myDb = null;
+ Transaction myTa = null;
+ System.out.println( PREFIX_TESTSET + "testing transaction start." );
+
+ System.out.print( PREFIX_TESTCASE + "isOpen on open DB, closed TA..." );
+ try
+ {
+ myDb = myApp.newDatabase();
+ myDb.open( database, Database.OPEN_READ_ONLY );
+ myTa = myApp.newTransaction();
+ if ( myTa.isOpen() )
+ System.out.println( ERROR_TAG + "TA open on closed DB." );
+ else
+ System.out.println( "OK, is not open." );
+ }
+ catch (Exception e)
+ {
+ System.out.println( "OK: " + e.getMessage() );
+ }
+
+ System.out.print( PREFIX_TESTCASE + "isOpen on open DB/TA..." );
+ try
+ {
+ myTa.begin();
+ if ( myTa.isOpen() )
+ System.out.println( "OK, is open." );
+ else
+ System.out.println( ERROR_TAG + "TA not open after opening." );
+ }
+ catch (Exception e)
+ {
+ System.out.println( ERROR_TAG + e.getMessage() );
+ }
+
+ System.out.print( PREFIX_TESTCASE + "sending query to check open TA..." );
+ try
+ {
+ OQLQuery myQu = myApp.newOQLQuery();
+ myQu.create( "select r from RAS_COLLECTIONNAMES as r" );
+ DBag result = (DBag) myQu.execute();
+ if ( result == null )
+ System.out.println( ERROR_TAG + "standard query failed." );
+ else
+ System.out.println( "OK, query done." );
+ }
+ catch (Exception e)
+ {
+ System.out.println( ERROR_TAG + e.getMessage() );
+ }
+
+ System.out.print( PREFIX_TESTCASE + "open TA on an already open TA..." );
+ try
+ {
+ myTa.begin();
+ if ( myTa.isOpen() )
+ System.out.println( "OK, should remain open." );
+ else
+ System.out.println( ERROR_TAG + "TA not open after 2nd opening." );
+ }
+ catch (Exception e)
+ {
+ System.out.println( ERROR_TAG + e.getMessage() );
+ }
+
+ System.out.print( PREFIX_TESTCASE + "abort TA..." );
+ try
+ {
+ myTa.abort();
+ if ( myTa.isOpen() )
+ System.out.println( ERROR_TAG + "TA open after abort." );
+ else
+ System.out.println( "OK, is not open." );
+ }
+ catch (Exception e)
+ {
+ System.out.println( ERROR_TAG + e.getMessage() );
+ }
+
+ System.out.print( PREFIX_TESTCASE + "query on aborted TA..." );
+ try
+ {
+ OQLQuery myQu = myApp.newOQLQuery();
+ myQu.create( "select r from RAS_COLLECTIONNAMES as r" );
+ DBag result = (DBag) myQu.execute();
+ if ( result == null )
+ System.out.println( "OK, standard query failed." );
+ else
+ System.out.println( ERROR_TAG + "query got through." );
+ }
+ catch (Exception e)
+ {
+ System.out.println( "OK, failed: " + e.getMessage() );
+ }
+
+ System.out.print( PREFIX_TESTCASE + "abort TA on aborted TA..." );
+ try
+ {
+ myTa.abort();
+ if ( myTa.isOpen() )
+ System.out.println( ERROR_TAG + "TA open after abort." );
+ else
+ System.out.println( "OK, is not open." );
+ }
+ catch (Exception e)
+ {
+ System.out.println( "OK, noticed: " + e.getMessage() );
+ }
+
+ System.out.print( PREFIX_TESTCASE + "open new TA, send query..." );
+ try
+ {
+ myTa.begin();
+ if ( ! myTa.isOpen() )
+ System.out.println( ERROR_TAG + "TA not open." );
+ else
+ {
+ OQLQuery myQu = myApp.newOQLQuery();
+ myQu.create( "select r from RAS_COLLECTIONNAMES as r" );
+ DBag result = (DBag) myQu.execute();
+ if ( result == null )
+ System.out.println( ERROR_TAG + "standard query failed." );
+ else
+ System.out.println( "OK." );
+ }
+ }
+ catch (Exception e)
+ {
+ System.out.println( ERROR_TAG + e.getMessage() );
+ }
+
+ System.out.print( PREFIX_TESTCASE + "commit TA..." );
+ try
+ {
+ myTa.commit();
+ if ( myTa.isOpen() )
+ System.out.println( "OK, closed now. " );
+ else
+ System.out.println( ERROR_TAG + "TA still open. " );
+ OQLQuery myQu = myApp.newOQLQuery();
+ myQu.create( "select r from RAS_COLLECTIONNAMES as r" );
+ DBag result = (DBag) myQu.execute();
+ if ( result == null )
+ System.out.println( "OK, query failed." );
+ else
+ System.out.println( ERROR_TAG + "query got through." );
+ }
+ catch (TransactionNotInProgressException e)
+ {
+ System.out.println( "...OK, query failed: " + e.getMessage() );
+ }
+ catch (Exception e)
+ {
+ System.out.println( ERROR_TAG + e.getMessage() );
+ }
+
+ System.out.println( PREFIX_TESTSET + "testing transaction done.\n" );
+ return;
+ } // testTransaction()
+
+ /**
+ * test access modes
+ * any eventual exception that is not caught here is an error, and will cause an abort
+ **/
+ static void testAccessMode( RasImplementation myApp, String database )
+ // throws RasDimensionMismatchException, RasIndexOutOfBoundsException
+ {
+ Database myDb = null;
+ Transaction myTa = null;
+ System.out.println( PREFIX_TESTSET + "testing accessMode start." );
+
+ System.out.print( PREFIX_TESTCASE + "open readonly, read query..." );
+ try
+ {
+ myDb = myApp.newDatabase();
+ myDb.open( database, Database.OPEN_READ_ONLY );
+ myTa = myApp.newTransaction();
+ myTa.begin();
+
+ OQLQuery myQu = myApp.newOQLQuery();
+ myQu.create( "select r from RAS_COLLECTIONNAMES as r" );
+ DBag result = (DBag) myQu.execute();
+ if ( result == null )
+ System.out.println( ERROR_TAG + "query failed." );
+ else
+ System.out.println( "OK, query got through." );
+ }
+ catch (Exception e)
+ {
+ System.out.println( ERROR_TAG + e.getMessage() );
+ }
+
+ System.out.print( PREFIX_TESTCASE + "open readonly, update query (create collection)..." );
+ try
+ {
+ myDb = myApp.newDatabase();
+ myDb.open( database, Database.OPEN_READ_ONLY );
+ myTa = myApp.newTransaction();
+ myTa.begin();
+
+ OQLQuery myQu = myApp.newOQLQuery();
+ myQu.create( "create collection TestDbTa_collection GreySet" );
+ DBag result = (DBag) myQu.execute();
+ }
+ catch (DatabaseIsReadOnlyException e)
+ {
+ System.out.println( "OK, update failed." );
+ }
+ catch (Exception e)
+ {
+ System.out.println( ERROR_TAG + e.getMessage() );
+ }
+
+ System.out.print( PREFIX_TESTCASE + "commit TA, close DB..." );
+ try
+ {
+ myTa.commit();
+ myDb.close();
+ System.out.println( "OK." );
+ }
+ catch (Exception e)
+ {
+ System.out.println( ERROR_TAG + e.getMessage() );
+ }
+
+ System.out.print( PREFIX_TESTCASE + "open DB readwrite, open TA, read query..." );
+ try
+ {
+ myDb.open( database, Database.OPEN_READ_WRITE );
+ myTa = myApp.newTransaction();
+ myTa.begin();
+
+ OQLQuery myQu = myApp.newOQLQuery();
+ myQu.create( "select r from RAS_COLLECTIONNAMES as r" );
+ DBag result = (DBag) myQu.execute();
+ if ( result == null )
+ System.out.println( ERROR_TAG + "query failed." );
+ else
+ System.out.println( "OK, query got through." );
+ }
+ catch (Exception e)
+ {
+ System.out.println( ERROR_TAG + e.getMessage() );
+ }
+
+ System.out.print( PREFIX_TESTCASE + "update query (create & drop collection)..." );
+ try
+ {
+ OQLQuery myQu = myApp.newOQLQuery();
+ myQu.create( "create collection TestDbTa_collection GreySet" );
+ DBag result = (DBag) myQu.execute();
+
+ // we want to see that a commit really preserves changes:
+ System.out.print( "re-opening TA..." );
+ myTa.commit();
+ myTa.begin();
+
+ myQu.create( "drop collection TestDbTa_collection" );
+ result = (DBag) myQu.execute();
+ System.out.println( "OK, query got through." );
+ }
+ catch (Exception e)
+ {
+ System.out.println( ERROR_TAG + e.getMessage() );
+ }
+
+ System.out.print( PREFIX_TESTCASE + "commit TA, close DB..." );
+ try
+ {
+ myTa.commit();
+ myDb.close();
+ System.out.println( "OK." );
+ }
+ catch (Exception e)
+ {
+ System.out.println( ERROR_TAG + e.getMessage() );
+ }
+
+ System.out.println( PREFIX_TESTSET + "testing accessMode done.\n" );
+ return;
+ } // testAccessMode()
+
+ } // TestDbTa
diff --git a/java/rasj/test/TestException.java b/java/rasj/test/TestException.java
new file mode 100644
index 0000000..9cfe894
--- /dev/null
+++ b/java/rasj/test/TestException.java
@@ -0,0 +1,361 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * exception testing (was: Systemtest_rasj).
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+import java.io.*;
+
+import rasj.*;
+import rasj.global.*;
+import org.odmg.*;
+
+
+// auxiliary classes for exception testing
+class TestRasResultIsNoCellException extends RasResultIsNoCellException
+ {
+ TestRasResultIsNoCellException()
+ {
+ super();
+ }
+ }
+
+class TestRasResultIsNoIntervalException extends RasResultIsNoIntervalException
+ {
+ TestRasResultIsNoIntervalException()
+ {
+ super();
+ }
+ }
+
+class TestRasClientInternalException extends RasClientInternalException
+ {
+ TestRasClientInternalException(String msg)
+ {
+ super("TestException","TestExceptions",msg);
+ }
+ }
+
+/**
+ * class for testing rasj interface
+ * @version $$
+ */
+public class TestException
+ {
+ /**
+ * prefixes for test output
+ **/
+ static final String PREFIX_PROGRAM = "+++ +++ +++ ";
+ static final String PREFIX_TESTSET = "+++ +++ ";
+ static final String PREFIX_TESTCASE = "+++ ";
+
+ /**
+ * std error tag printed if a test fails
+ **/
+ static final String ERROR_TAG = "ERROR: ";
+
+ /**
+ * default values (override with cmd line option)
+ **/
+ static final String DEFAULT_HOST = "localhost";
+ static final int DEFAULT_PORT = 7001;
+ static final String DEFAULT_BASE = "RASBASE";
+ static final String DEFAULT_USER = "rasguest";
+ static final String DEFAULT_PASSWD = "rasguest";
+
+ // main program
+ public static void main(String[] args) throws Exception
+ {
+ String server = DEFAULT_HOST;
+ int port = DEFAULT_PORT;
+ String base = DEFAULT_BASE;
+ String user = DEFAULT_USER;
+ String passwd = DEFAULT_PASSWD;
+ boolean wrongUsage = false;
+
+ // get args
+ if(args.length == 0)
+ wrongUsage = true;
+ for(int i = 0; i < args.length; i+=2)
+ {
+ if (args[i].equals("--server"))
+ server = args[i+1];
+ else if (args[i].equals("--port"))
+ {
+ try
+ {
+ port = Integer.parseInt(args[i+1]);
+ }
+ catch(Exception e)
+ {
+ wrongUsage = true;
+ }
+ }
+ else if (args[i].equals("--database"))
+ base = args[i+1];
+ else if (args[i].equals("--user"))
+ user = args[i+1];
+ else if (args[i].equals("--passwd"))
+ passwd = args[i+1];
+ }
+
+ if(wrongUsage)
+ {
+ System.err.println("Usage: TestException [--server s] [--port p] [--database d]");
+ System.out.println( "defaults: server=" + DEFAULT_HOST + ", port=" + DEFAULT_PORT + ", database=" + DEFAULT_BASE
++ ", user=" + DEFAULT_USER + ", passwd=" + DEFAULT_PASSWD );
+ System.exit(-1);
+ }
+
+
+
+ System.out.println( "rasdaman system test v5.1revC: testing exceptions." );
+ System.out.println( PREFIX_PROGRAM + "system test started, using server " + server + ", port " + port + ", database " + base + ", user=" + user + ", passwd=" + passwd );
+
+ // Implementation myApp = new RasImplementation("http://" + server + ":" + port);
+ RasImplementation myApp = new RasImplementation( "http://" + server + ":" + port );
+ myApp.setUserIdentification(user, passwd);
+
+ // -- START test cases -------------------------------------------------
+ testExceptions( myApp, base );
+ // -- END test cases ---------------------------------------------------
+
+ System.out.println( PREFIX_PROGRAM + "system test done." );
+ return;
+ } // main()
+
+ /**
+ * test exceptions
+ * any eventual exception that is not caught here is an error, and will cause an abort
+ **/
+ static void testExceptions( RasImplementation imp, String database ) throws Exception
+ {
+ boolean resultIsOk = false;
+ Database myDb = null;
+ Transaction myTa = null;
+ OQLQuery myQu = null;
+
+ System.out.println( PREFIX_TESTSET + "testing exceptions started." );
+
+ System.out.print( PREFIX_TESTCASE + "provoking RasConnectionFailedException..." );
+ RasImplementation errorApp;
+ String logMsg;
+ try
+ {
+ errorApp = new RasImplementation("wrongserver:8080");
+ myDb = errorApp.newDatabase();
+ myDb.open( database, Database.OPEN_READ_WRITE );
+ System.out.println( ERROR_TAG + "does not catch this." );
+ myDb.close();
+ }
+ catch(RasConnectionFailedException e)
+ {
+ System.out.println( "OK, recognized: " + e.getMessage() );
+ }
+
+ System.out.print( PREFIX_TESTCASE + "provoking RasDimensionMismatchException..." );
+ try
+ {
+ RasMInterval test1;
+ RasMInterval test2 = new RasMInterval("[1:20,1:20]");
+ RasMInterval test3 = new RasMInterval("[1:4,1:9,1:6]");
+ test1 = test2.intersectionWith(test3);
+ System.out.println( ERROR_TAG + "does not catch this." );
+ }
+ catch(RasDimensionMismatchException e)
+ {
+ System.out.println( "OK, recognized: " + e.getMessage() );
+ }
+
+ System.out.print( PREFIX_TESTCASE + "provoking RasIndexOutOfBoundsException..." );
+ try
+ {
+ RasGMArray myMDD = new RasGMArray(new RasMInterval("[1:5,1:5]"),1);
+ byte[] retVal = myMDD.getCell(new RasPoint(4,7));
+ System.out.println( ERROR_TAG + "does not catch this." );
+ }
+ catch(RasIndexOutOfBoundsException e)
+ {
+ System.out.println( "OK, recognized: " + e.getMessage() );
+ }
+
+ System.out.print( PREFIX_TESTCASE + "provoking RasClientInternalException (via subclassed e.)..." );
+ try
+ {
+ throw new TestRasClientInternalException("This is a test error");
+ }
+ catch(RasClientInternalException e)
+ {
+ System.out.println( "OK, recognized: " + e.getMessage() );
+ }
+
+ System.out.print( PREFIX_TESTCASE + "provoking RasResultIsNoCellException (via subclassed e.)..." );
+ try
+ {
+ throw new TestRasResultIsNoCellException();
+ }
+ catch(RasResultIsNoCellException e)
+ {
+ System.out.println( "OK, recognized: " + e.getMessage() );
+ }
+
+ System.out.print( PREFIX_TESTCASE + "provoking RasResultIsNoIntervalException (via subclassed e.)..." );
+ try
+ {
+ throw new TestRasResultIsNoIntervalException();
+ }
+ catch(RasResultIsNoIntervalException e)
+ {
+ System.out.println( "OK, recognized: " + e.getMessage() );
+ }
+
+ System.out.print( PREFIX_TESTCASE + "provoking RasStreamInputOverflowException..." );
+ try
+ {
+ RasMInterval int1 = new RasMInterval(2);
+ int1.stream(new RasSInterval("1:10"));
+ int1.stream(new RasSInterval("1:5"));
+ int1.stream(new RasSInterval("1:20"));
+ System.out.println( ERROR_TAG + "does not catch this." );
+ }
+ catch(RasStreamInputOverflowException e)
+ {
+ System.out.println( "OK, recognized: " + e.getMessage() );
+ }
+
+ System.out.print( PREFIX_TESTCASE + "provoking RasTypeInvalidException..." );
+ try
+ {
+ RasPrimitiveType myType = new RasPrimitiveType("myPrivateType",RasGlobalDefs.RAS_BOOLEAN);
+ myType.getFloat(new Object());
+ System.out.println( ERROR_TAG + "does not catch this." );
+ }
+ catch(RasTypeInvalidException e)
+ {
+ System.out.println( "OK, recognized: " + e.getMessage() );
+ }
+
+ System.out.print( PREFIX_TESTCASE + "provoking RasTypeNotSupportedException..." );
+ try
+ {
+ throw new RasTypeNotSupportedException("test");
+ }
+ catch(RasTypeNotSupportedException e)
+ {
+ System.out.println( "OK, recognized: " + e.getMessage() );
+ }
+
+ System.out.print( PREFIX_TESTCASE + "provoking RasIllegalULongValueException (faked)..." );
+ try
+ {
+ throw new RasIllegalULongValueException( 42 );
+ }
+ catch(RasIllegalULongValueException e)
+ {
+ System.out.println( "OK, recognized: " + e.getMessage() );
+ }
+
+ System.out.print( PREFIX_TESTCASE + "provoking RasIllegalUShortValueException (faked)..." );
+ try
+ {
+ throw new RasIllegalUShortValueException( 42 );
+ }
+ catch(RasIllegalUShortValueException e)
+ {
+ System.out.println( "OK, recognized: " + e.getMessage() );
+ }
+
+ System.out.print( PREFIX_TESTCASE + "provoking RasInvalidNameException (illegal chars in obj type name)..." );
+ try
+ {
+ RasGMArray myMDD = new RasGMArray(new RasMInterval("[1:400,1:400]"),1);
+ myMDD.setObjectTypeName("_!_$_%_&_ _");
+ System.out.println( ERROR_TAG + "does not catch this." );
+ }
+ catch(RasInvalidNameException e)
+ {
+ System.out.println( "OK, recognized: " + e.getMessage() );
+ }
+
+ // FIXME: PB9
+ System.out.print( PREFIX_TESTCASE + "provoking RasInvalidNameException (name too long)..." );
+ try
+ {
+ RasGMArray myMDD = new RasGMArray(new RasMInterval("[1:400,1:400]"),1);
+ myMDD.setObjectTypeName("loooongname__1234567890_1234567890_1234567890_1234567890_1234567890_1234567890_1234567890_1234567890_1234567890_1234567890_1234567890_1234567890_1234567890_1234567890_1234567890_1234567890_1234567890_1234567890_1234567890_1234567890_" );
+ System.out.println( ERROR_TAG + "does not catch this." );
+ }
+ catch(RasInvalidNameException e)
+ {
+ System.out.println( "OK, recognized: " + e.getMessage() );
+ }
+
+ System.out.print( PREFIX_TESTCASE + "provoking RasQueryExecutionFailedException..." );
+ try
+ {
+ // Database myDb2 = imp.newDatabase();
+ // myDb2.open( database, Database.OPEN_READ_ONLY );
+ // Transaction myTa2 = imp.newTransaction();
+ // myTa2.begin();
+
+ // OQLQuery myQu2 = imp.newOQLQuery();
+ // myQu2.create( "select r r from RAS_COLLECTIONNAMES as r" );
+ // DBag result = (DBag) myQu2.execute();
+
+ // myTa2.abort();
+ // myDb2.close();
+ System.out.print( "this is meant for a severe internal problem which I cannot provoke; will fake..." );
+ throw new RasQueryExecutionFailedException( 1, 2, 3, "(fake)" );
+ }
+ catch(RasQueryExecutionFailedException e)
+ {
+ System.out.println( "OK, recognized: " + e.getMessage() );
+ }
+
+ // protected exception in rasj, not accessible
+ // System.out.print( PREFIX_TESTCASE + "provoking RasTypeUnknownException..." );
+ // try
+ // {
+ // // RasGMArray myMDD = new RasGMArray(new RasMInterval("[1:400,1:400]"),1);
+ // // myMDD.setObjectTypeName( "charrrrr" );
+ // System.out.print( "superseded by RasTypeNotSupportedException - cannot catch it; will fake..." );
+ // throw new RasTypeUnknownException("test");
+ // }
+ // catch(RasTypeUnknownException e)
+ // {
+ // System.out.println( "OK, recognized: " + e.getMessage() );
+ // }
+
+ System.out.println( PREFIX_TESTSET + "testing exceptions done." );
+ return;
+ } // testExceptions()
+
+ } // TestException
diff --git a/java/rasj/test/TestHttp.java b/java/rasj/test/TestHttp.java
new file mode 100644
index 0000000..aca0e40
--- /dev/null
+++ b/java/rasj/test/TestHttp.java
@@ -0,0 +1,642 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ * - not part of the standard systemtest, because it does not use std
+ * interface but copies internal ras/clientcomm code
+ * </pre>
+ *********************************************************** */
+
+import rasj.*;
+import rasj.odmg.*;
+import org.odmg.*;
+import rasj.global.*;
+
+import java.io.*;
+import java.util.*;
+
+import java.lang.*;
+import java.net.*;
+
+/**
+ * This class handles a HTTP-request to the RasDaMan server.
+ * The specified RasDaMan server is contacted, the specified command is sent to
+ * the server, and the result of the query is retrieved and stored in a byte array.
+ * The specification of the communication protocol is given below.
+ * <P>
+ *
+ * @version $Revision: 1.1 $
+ */
+
+public class TestHttp implements RasCommDefs, RasGlobalDefs
+{
+
+ static final String rcsid = "@(#)Package rasj.test, class TestHttp: $Header: /home/rasdev/CVS-repository/rasdaman/java/rasj/test/TestHttp.java,v 1.1 2003/12/19 16:05:43 rasdev Exp $";
+
+
+/**
+ * The type of this client
+ */
+ private String client = "RASCLIENT";
+
+/**
+ * The result type ( MDD Collection, Skalar Collection, Error, Integer ). This field is set
+ * automatically when a query has been executed, so there's no setResultType method.
+ */
+ private static byte resultType = 0;
+
+/**
+ * The result of the query
+**/
+ private static Object result = null;
+
+
+/**
+ * This method sends a query to the RasDaMan Server and retrieves the results.
+ *
+ * @param con server connection
+ * @param parameters the parameters for the request as name/value pairs (for example "clientID=4354351&queryString=select img from test")
+ */
+ public static void execute( String serverURL, String parameters )
+ throws RasQueryExecutionFailedException, RasConnectionFailedException
+ {
+ System.out.println( "RasHttpRequest.execute: start. parameters=" + parameters );
+
+ BenchmarkTimer httpTimer = new BenchmarkTimer("httpRequest direct");
+ BenchmarkTimer rcvTimer = new BenchmarkTimer("receive direct");
+
+ try
+ {
+ URL url = new URL( serverURL );
+
+ System.out.println( "RasHttpRequest.execute: sending to " + url + " POST request=" + parameters );
+
+ httpTimer.startTimer();
+
+ BenchmarkTimer sendTimer = new BenchmarkTimer("send direct");
+ sendTimer.startTimer();
+
+ // Send the query
+ HttpURLConnection con = (HttpURLConnection) url.openConnection();
+ con.setRequestProperty("Content-type","application/octet-stream");
+ con.setRequestProperty("User-Agent","RasDaMan Java Client");
+ con.setRequestProperty("Version","1.0");
+ con.setRequestMethod("POST");
+ con.setDoInput(true);
+ con.setDoOutput(true);
+ con.setUseCaches(false);
+
+ OutputStreamWriter out = new OutputStreamWriter(con.getOutputStream(),"8859_1");
+ out.write(parameters,0,parameters.length());
+ out.flush();
+ out.close();
+
+ sendTimer.stopTimer();
+ sendTimer.print();
+
+ rcvTimer.startTimer();
+
+ // Read response
+ BenchmarkTimer getInputTimer = new BenchmarkTimer("getInputStream direct");
+ getInputTimer.startTimer();
+ DataInputStream in = new DataInputStream(con.getInputStream());
+ System.out.println("RasHttpRequest.execute: received " + in );
+ getInputTimer.stopTimer();
+ getInputTimer.print();
+
+ // read binData
+ // binData = new byte[dataSize];
+ // readBytes = 0;
+ // readBytesTmp = 0;
+ // while( (readBytesTmp != -1) && (readBytes < dataSize) )
+ // {
+ // readBytesTmp = in.read(binData,readBytes,dataSize-readBytes);
+ // readBytes += readBytesTmp;
+ // System.out.println("Read " + readBytesTmp +" Bytes:" + binData);
+ // }
+ // in.close();
+ // con.disconnect();
+
+ /* variables for later use */
+ byte[] b1 = new byte[1];
+ byte[] b4 = new byte[4];
+ byte endianess = 0;
+ String collType = null;
+ int numberOfResults = 0;
+ int dataSize = 0;
+ byte[] binData = null;
+ int readBytes = 0;
+ int readBytesTmp = 0;
+ DBag resultBag;
+ RasGMArray res = null;
+
+ in.read(b1);
+
+ resultType = b1[0];
+ Debug.talkVerbose("RasHttpRequest.execute: resultType=" + resultType );
+ switch( resultType )
+ {
+ case RESPONSE_OK:
+ case RESPONSE_OK_NEGATIVE:
+ //Nothing todo
+ break;
+
+ // +++++++++++++++++++++++++++++++++++++++++++++++++
+ case RESPONSE_MDDS:
+ Debug.talkVerbose("RasHttpRequest.execute: result type is MDD." );
+ // read Endianess
+ while(in.read(b1) == 0)
+ ;
+ endianess = b1[0];
+
+ // read Collection Type
+ collType = RasUtils.readString(in);
+ Debug.talkVerbose("RasHttpRequest.execute: colltype=" + collType);
+
+ // read NumberOfResults
+ while(in.available() < 4)
+ ;
+ in.read(b4);
+ numberOfResults = RasUtils.ubytesToInt(b4,endianess);
+ Debug.talkVerbose("RasHttpRequest.execute: number of results: " + numberOfResults);
+
+ // Initialize return-set and parameters
+ resultBag = new RasBag();
+ String mddBaseType = null;
+ String domain = null;
+ String oid = "";
+ RasOID roid = null;
+
+ // do this for each result
+ for(int x = 0; x < numberOfResults; x++)
+ {
+ Debug.talkVerbose("RasHttpRequest.execute: handling result #" + (x+1) );
+ //read mddBaseType
+ mddBaseType = RasUtils.readString(in);
+
+ // read spatialDomain
+ domain = RasUtils.readString(in);
+
+ // read OID
+ oid = RasUtils.readString(in);
+ //System.err.println("OID is " + oid);
+ roid = new RasOID(oid);
+
+ // read size of binData
+ while(in.available() < 4)
+ ;
+ in.read(b4);
+
+ dataSize = RasUtils.ubytesToInt(b4,endianess);
+
+ Debug.talkVerbose("RasHttpRequest.execute: mddBaseType is " + mddBaseType + ", spatialDomain=" + domain + ", size of BinData=" + dataSize );
+
+ // read binData
+ binData = new byte[dataSize];
+ readBytes = 0;
+ readBytesTmp = 0;
+
+ while( (readBytesTmp != -1) && (readBytes < dataSize) )
+ {
+ readBytesTmp = in.read(binData,readBytes,dataSize-readBytes);
+ readBytes += readBytesTmp;
+ }
+
+ Debug.talkVerbose("RasHttpRequest.execute: read " + readBytes + " bytes.");
+
+ RasType rType = RasType.getAnyType(mddBaseType);
+ //System.out.println(rType);
+ RasBaseType rb = null;
+
+ if(rType.getClass().getName().equals("rasj.RasMArrayType"))
+ {
+ RasMArrayType tmp = (RasMArrayType)rType;
+ rb = tmp.getBaseType();
+ }
+ else
+ {
+ Debug.talkCritical("RasHttpRequest.execute: exception: element of MDD Collection is no MArray" );
+ throw new RasClientInternalException("RasHttpRequest","execute()","element of MDD Collection is no MArray");
+ }
+
+ if(rb.isBaseType())
+ {
+ if(rb.isStructType())
+ {
+ // It is a structType
+ //System.err.println("It is a structType");
+ RasStructureType sType = (RasStructureType)rb;
+ //System.out.println(sType);
+ res = new RasGMArray(new RasMInterval(domain), 0);
+ res.setTypeLength(rb.getSize());
+ res.setArraySize(dataSize);
+ res.setArray(binData);
+ //insert into result set
+ resultBag.add(res);
+ break;
+
+ } else
+ {
+ // It is a primitiveType
+ RasPrimitiveType pType = (RasPrimitiveType)rb;
+
+ //System.err.println("It's a primitive type: " + pType);
+ switch(pType.getTypeID())
+ {
+ case RAS_BOOLEAN:
+ case RAS_BYTE:
+ case RAS_CHAR:
+ //System.err.println("It's a byte array!");
+ res = new RasMArrayByte(new RasMInterval(domain));
+ break;
+ case RAS_SHORT:
+ //System.err.println("It's a short array!");
+ res = new RasMArrayShort(new RasMInterval(domain));
+ break;
+
+ case RAS_USHORT:
+ //System.err.println("It's a ushort array!");
+ byte[] tmData = new byte[dataSize*2];
+ for(int i=0;i<dataSize*2;)
+ {
+ tmData[i] = 0;
+ tmData[i+1] = 0;
+ tmData[i+2] = binData[i/2];
+ tmData[i+3] = binData[i/2+1];
+ i = i+SIZE_OF_INTEGER;
+ }
+ binData = tmData;
+ res = new RasMArrayInteger(new RasMInterval(domain));
+ break;
+
+ case RAS_INT:
+ case RAS_LONG:
+ //System.err.println("It's a integer array!");
+ res = new RasMArrayInteger(new RasMInterval(domain));
+ break;
+ case RAS_ULONG:
+ //System.err.println("It's a ulong array!");
+ byte[] tmpData = new byte[dataSize*2];
+ for(int i=0;i<dataSize*2;)
+ {
+ tmpData[i] = 0;
+ tmpData[i+1] = 0;
+ tmpData[i+2] = 0;
+ tmpData[i+3] = 0;
+ tmpData[i+4] = binData[i/2];
+ tmpData[i+5] = binData[i/2+1];
+ tmpData[i+6] = binData[i/2+2];
+ tmpData[i+7] = binData[i/2+3];
+ i = i+SIZE_OF_LONG;
+ }
+ binData = tmpData;
+ res = new RasMArrayLong(new RasMInterval(domain));
+ break;
+ case RAS_FLOAT:
+ //System.err.println("It's a float array!");
+ res = new RasMArrayFloat(new RasMInterval(domain));
+ break;
+ case RAS_DOUBLE:
+ //System.err.println("It's a double array!");
+ res = new RasMArrayDouble(new RasMInterval(domain));
+ break;
+ default:
+ //System.err.println("It's a GMArray!");
+ res = new RasGMArray(new RasMInterval(domain), pType.getSize());
+ //throw new RasTypeNotSupportedException(pType.getName());
+ }
+ // set array data
+ res.setArray(binData);
+ // set oid
+ res.setOID(roid);
+ //insert into result set
+ resultBag.add(res);
+ }
+
+ }
+ else throw new RasClientInternalException("RasHttpRequest","execute()","Type of MDD is no Base Type");
+ }
+
+ result = resultBag;
+
+ // close stream
+ in.close();
+
+ break;
+
+ // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ case RESPONSE_SKALARS:
+ //System.err.println("Skalar = 2");
+ // read Endianess
+ while(in.read(b1) == 0);
+ endianess = b1[0];
+
+ // read Collection Type
+ collType = RasUtils.readString(in);
+ RasType rt = new RasType();
+ try
+ {
+ rt = rt.getAnyType(collType);
+ //System.err.println("Colltype is " + rt);
+ }
+ catch(Exception e)
+ {
+ throw new RasTypeNotSupportedException(rt + " as RasCollectionType");
+ }
+ if(rt.getTypeID()!=RasGlobalDefs.RAS_COLLECTION)
+ throw new RasTypeNotSupportedException(rt + " as RasCollectionType");
+
+ // read NumberOfResults
+ while(in.available() < 4);
+ in.read(b4);
+ numberOfResults = RasUtils.ubytesToInt(b4,endianess);
+ //System.err.println("Number of results: " + numberOfResults);
+
+ // Initailize return-list
+ resultBag = new RasBag();
+
+ // do this for each result
+ for(int x = 0; x < numberOfResults; x++)
+ {
+ // read elementType
+ String elementType = RasUtils.readString(in);
+ RasType et = new RasType();
+ et = ((RasCollectionType)rt).getElementType();
+ //System.err.println("ElementType is " + et);
+
+ // read size of binData
+ while(in.available() < 4);
+ in.read(b4);
+ dataSize = RasUtils.ubytesToInt(b4,endianess);
+ //System.err.print("Size of BinData: ");
+ //System.err.println(dataSize);
+
+ // read binData
+ binData = new byte[dataSize];
+ readBytes = 0;
+ readBytesTmp = 0;
+ while( (readBytesTmp != -1) && (readBytes < dataSize) )
+ {
+ readBytesTmp = in.read(binData,readBytes,dataSize-readBytes);
+ readBytes += readBytesTmp;
+ /*
+ System.err.println("Read " + readBytesTmp +" Bytes ("
+ + readBytes + " Bytes overall)");
+ */
+ }
+ //System.err.println("Füge ein ..." + new String(binData));
+
+ ByteArrayInputStream bis = new ByteArrayInputStream(binData);
+ DataInputStream dis = new DataInputStream(bis);
+ // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ switch(et.getTypeID())
+ {
+ case RasGlobalDefs.RAS_MINTERVAL:
+ resultBag.add(new RasMInterval(new String(binData)));
+ break;
+ case RasGlobalDefs.RAS_SINTERVAL:
+ resultBag.add(new RasSInterval(new String(binData)));
+ break;
+ case RasGlobalDefs.RAS_POINT:
+ resultBag.add(new RasPoint(new String(binData)));
+ break;
+ case RasGlobalDefs.RAS_OID:
+ resultBag.add(new RasOID(new String(binData)));
+ break;
+ case RAS_BOOLEAN:
+ case RAS_BYTE:
+ case RAS_CHAR:
+ byte b = binData[0];
+ resultBag.add(new Byte(b));
+ break;
+ case RAS_DOUBLE:
+ double d = dis.readDouble();
+ resultBag.add(new Double(d));
+ break;
+ case RAS_FLOAT:
+ float f = dis.readFloat();
+ resultBag.add(new Float(f));
+ break;
+ case RAS_ULONG:
+ byte[] bu = new byte[8];
+ bu[0] = 0;
+ bu[1] = 0;
+ bu[2] = 0;
+ bu[3] = 0;
+ bu[4] = dis.readByte();
+ bu[5] = dis.readByte();
+ bu[6] = dis.readByte();
+ bu[7] = dis.readByte();
+ ByteArrayInputStream bis2 = new ByteArrayInputStream(bu);
+ DataInputStream dis2 = new DataInputStream(bis2);
+ long ul = dis2.readLong();
+ resultBag.add(new Long(ul));
+ break;
+ case RAS_LONG:
+ case RAS_INT:
+ int i = dis.readInt();
+ resultBag.add(new Integer(i));
+ break;
+ case RAS_USHORT:
+ int j = dis.readUnsignedShort();
+ resultBag.add(new Integer(j));
+ break;
+ case RAS_SHORT:
+ short s = dis.readShort();
+ resultBag.add(new Short(s));
+ break;
+ default:
+ throw new RasTypeNotSupportedException(et + " as ElementType ");
+ }
+ }
+ result = resultBag;
+
+ // close stream
+ in.close();
+ break;
+
+ //++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ case RESPONSE_ERROR:
+ Debug.talkCritical("RasHttpRequest.execute: execution failed. Error = 0");
+
+ // read Endianess
+ while(in.read(b1) == 0)
+ ;
+ endianess = b1[0];
+
+ // read Error Number
+ while(in.available() < 4)
+ ;
+ in.read(b4);
+ int errNo = RasUtils.ubytesToInt(b4,endianess);
+
+ // read Line Number
+ while(in.available() < 4)
+ ;
+ in.read(b4);
+ int lineNo = RasUtils.ubytesToInt(b4,endianess);
+
+ // read Column Number
+ while(in.available() < 4)
+ ;
+ in.read(b4);
+ int colNo = RasUtils.ubytesToInt(b4,endianess);
+
+ // read token
+ String token = RasUtils.readString(in);
+
+ Debug.talkCritical("RasHttpRequest.execute: Errno=" + errNo + ", lineNo=" + lineNo + ", colNo=" + colNo + ", Token=" + token);
+
+ throw new RasQueryExecutionFailedException(errNo,lineNo,colNo,token);
+ //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ case RESPONSE_INT:
+ // read Integer Value
+ //System.err.println("Now reading integer value...");
+ while(in.available() < 4);
+ in.read(b4);
+ result = new Integer(RasUtils.ubytesToInt(b4,endianess));
+ //System.err.println("Int Value is : " + result.getInt());
+ break;
+
+ //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ case RESPONSE_OID:
+ // read Values
+ String sys = RasUtils.readString(in);
+ String base = RasUtils.readString(in);
+ double d = in.readDouble();
+ //System.out.println(sys+base+"localOID als double = " + d);
+ resultBag = new RasBag();
+ resultBag.add(new RasOID(sys, base, d));
+ result = resultBag;
+ // close stream
+ in.close();
+ break;
+ default:
+ Debug.talkCritical( "RasHttpRequest.execute: illegal response type: " + resultType );
+ break;
+
+ }
+
+ con.disconnect(); // close connection to server -- PB 2003-jun-15
+ }
+ catch( MalformedURLException e )
+ {
+ Debug.leaveCritical( "RasHttpRequest.execute: leave. malformed URL: " + e.getMessage() );
+ throw new RasConnectionFailedException(MANAGER_CONN_FAILED, serverURL );
+ }
+ catch( IOException e )
+ {
+ Debug.leaveCritical( "RasHttpRequest.execute: leave. IO exception: " + e.getMessage() );
+ throw new RasClientInternalException("RasHttpRequest","execute()",e.getMessage());
+ }
+ catch( RasResultIsNoIntervalException e )
+ {
+ Debug.leaveCritical( "RasHttpRequest.execute: leave. result no interval: " + e.getMessage() );
+ throw new RasClientInternalException("RasHttpRequest","execute()",e.getMessage());
+ }
+
+ rcvTimer.stopTimer();
+ rcvTimer.print();
+
+ httpTimer.stopTimer();
+ httpTimer.print();
+
+ System.out.println( "RasHttpRequest.execute: leave. resultType=" + resultType );
+ } // execute()
+
+ public static void main( String[] args )
+ {
+ String server = "localhost";
+ String port = "7001";
+ String base = "RASBASE";
+ String user = "rasguest";
+ String passwd = "rasguest";
+ String query = "select r from RAS_COLLECTIONNAMES as r";
+ int count = 1;
+
+ System.out.println( "Query test started." );
+
+ for (int i=args.length-1; i>=0; i--)
+ {
+ if (args[i].equals("--server"))
+ server = args[i+1];
+ if (args[i].equals("--port"))
+ port = args[i+1];
+ if (args[i].equals("--database"))
+ base = args[i+1];
+ if (args[i].equals("--user"))
+ user = args[i+1];
+ if (args[i].equals("--passwd"))
+ passwd = args[i+1];
+ if (args[i].equals("--query"))
+ query = args[i+1];
+ if (args[i].equals("--count"))
+ count = Integer.parseInt(args[i+1]);
+ }
+
+ try
+ {
+ RasImplementation myApp = new RasImplementation("http://"+server+":"+port);
+ myApp.setUserIdentification(user, passwd);
+
+ System.out.println( "opening database..." );
+ Database myDb = myApp.newDatabase();
+ myDb.open( base, Database.OPEN_READ_ONLY );
+
+ System.out.println( "starting transaction..." );
+ Transaction myTa = myApp.newTransaction();
+ myTa.begin();
+
+ String parameters = "Command=8&ClientID=1&QueryString=" + query;
+ String serverUrl = "http://" + server + ":" + 7102; // port;
+
+ for (int i = 0; i < count; i++)
+ {
+ System.out.println( "sending query #" + i + "..." );
+ execute( serverUrl, parameters );
+ }
+
+ System.out.println( "closing transaction..." );
+ myTa.abort();
+
+ System.out.println( "closing database..." );
+ myDb.close();
+ System.out.println( "all done." );
+
+ }
+ catch(Exception e)
+ {
+ System.err.println( e.getMessage() );
+ }
+
+ System.out.println( "Query test done." );
+
+ } // main()
+
+} // TestHttp
+
diff --git a/java/rasj/test/TestMArray.java b/java/rasj/test/TestMArray.java
new file mode 100644
index 0000000..e8f817f
--- /dev/null
+++ b/java/rasj/test/TestMArray.java
@@ -0,0 +1,904 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE: class for testing special MArrays
+ *
+ *
+ * COMMENTS:
+ * - adapt to general testbed structure
+ * </pre>
+ *********************************************************** */
+
+import java.io.*;
+import java.net.*;
+import rasj.clientcommhttp.*;
+import rasj.odmg.*;
+import org.odmg.*;
+import rasj.*;
+import java.util.*;
+
+/**
+ * class for testing special MArrays
+ * for testing please enable test data output in toString method of RASGMArray
+ * @version $$
+ */
+public class TestMArray
+{
+ /**
+ * constants used in this test
+ **/
+ // prefixes for test output
+ static final String PREFIX_PROGRAM = "+++ +++ +++ ";
+ static final String PREFIX_TESTSET = "+++ +++ ";
+ static final String PREFIX_TESTCASE = "+++ ";
+
+ static final String DEFAULT_HOST = "localhost";
+ static final String DEFAULT_BASE = "RASBASE";
+ static final String DEFAULT_COLL = "test";
+ /**
+ * std error tag printed if a test fails
+ **/
+ static final String ERROR_TAG = "ERROR: ";
+
+ /**
+ * main program for testing
+ * on error, an exception is thrown (java main() knows no exit status)
+ **/
+ public static void main(String[] args)
+ {
+ String serv = DEFAULT_HOST;
+ String base = DEFAULT_BASE;
+ String coll = DEFAULT_COLL;
+ boolean wrongUsage = false; // error in cmd line params?
+
+ for (int i=args.length-1; i>=0; i--)
+ {
+ if (args[i].equals("--server"))
+ serv = args[i+1];
+ else if (args[i].equals("--database"))
+ base = args[i+1];
+ else if (args[i].equals("--collname"))
+ coll = args[i+1];
+ else
+ wrongUsage = true;
+ }
+
+ if (wrongUsage)
+ {
+ System.out.println( "Usage: TestMArray [--server s] [--database d] [--collname c]" );
+ System.out.println( "defaults: s=" + DEFAULT_HOST + ", d=" + DEFAULT_BASE + ", c=" + DEFAULT_COLL );
+ return;
+ }
+
+ System.out.println( "rasdaman system test v5.1revC: testing class MArray." );
+ System.out.println( PREFIX_PROGRAM + "system test started, using server" + serv + ", database " + base + ", collection" + coll );
+
+ // -- START test cases -------------------------------------------------
+ TestMArray marrayTest = new TestMArray(serv);
+ // -- END test cases ---------------------------------------------------
+
+ System.out.println( PREFIX_PROGRAM + "system test done." );
+ return;
+ } // main()
+
+ public TestMArray(String server)
+ {
+ DBag resultBag = null;
+ Object result = null;
+ Transaction myTa = null;
+ Database myDb = null;
+ OQLQuery myQu = null;
+
+ boolean equal = false;
+
+ try
+ {
+ System.out.println("### Testing MArrays: ...");
+ Implementation myApp = new RasImplementation("http://"+server+":7001");
+ myDb = myApp.newDatabase();
+
+ System.out.println("Opening database ...");
+ myDb.open("RASBASE", Database.OPEN_READ_WRITE);
+ myTa = myApp.newTransaction();
+
+ int width, height, len;
+ width = 18;
+ height = 18;
+ len = (width+1)*(height+1);
+ RasMInterval domain = new RasMInterval("[0:"+width+",0:"+height+"]");
+ RasMInterval domain2 = new RasMInterval("[1:3,1:3]");
+ RasStorageLayout stl = new RasStorageLayout();
+ stl.setTileSize(128);
+
+
+ /**
+ * test the GMArray
+ */
+ System.out.println("\n\n### Testing GMArray with OID: ################################################");
+ myQu = myApp.newOQLQuery();
+
+ myQu.create("drop collection test");
+ myTa.begin();
+ try
+ {
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("collection dropped");
+ }
+ catch(ODMGException e)
+ {
+ myTa.abort();
+ System.err.println("Collection test does not exist: " + e.getMessage());
+ }
+
+ myQu.create("create collection test GreySet");
+ RasGMArray mddConst = new RasGMArray(domain, 1, stl);
+ //RasGMArray mddConst = new RasGMArray(domain, 1);
+ byte[] data = new byte[len];
+ mddConst.setObjectTypeName("GreyImage");
+
+ // test: get new OID from the server for GMArray and insert
+ System.out.println("new OID from server: " + myApp.getObjectId(mddConst));
+
+ for(int j = 0; j < data.length; j++)
+ data[j] = (byte)j;
+
+ mddConst.setArray(data);
+ /*
+ System.out.println("\nbyte array: ");
+ for(int j=0; j<mddConst.getArray().length; j++)
+ {
+ System.out.print(" "+ mddConst.getArray()[j]);
+ }
+ */
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("\ncollection created");
+ myQu.create("insert into test values $1 ");
+
+ //System.out.println("mdd before sending: " + mddConst);
+ myQu.bind(mddConst);
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("collection inserted");
+
+ myQu = myApp.newOQLQuery();
+ myQu.create("select img from test as img");
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("collection selected");
+ if (resultBag != null)
+ {
+ Iterator iter = resultBag.iterator();
+ while (iter.hasNext())
+ {
+ result = iter.next();
+ equal = true;
+ for(int j=0; j<mddConst.getArray().length; j++)
+ {
+ if(mddConst.getArray()[j] != ((RasGMArray)result).getArray()[j])
+ equal = false;
+ }
+ if(!(myApp.getObjectId(mddConst).toString()).equals(myApp.getObjectId((RasGMArray)result).toString()))
+ equal = false;
+ System.out.println("result mdd: " + ((RasGMArray)mddConst).toTestString());
+ System.out.println("result mdd: " + ((RasGMArray)result).toTestString());
+ }
+ System.out.println("inserted and selected GMArray and OIDs are equal: " + equal);
+ //System.out.println("All results for test GMArray");
+ }
+
+
+ // testing copy constructor
+ System.out.println("### Testing copy constructor:");
+ RasGMArray mddConst2 = new RasGMArray(mddConst);
+ mddConst2.setArray(data);
+ //System.out.println("\nbyte array2: ");
+ data = null;
+ equal = true;
+ for(int j=0; j<mddConst.getArray().length; j++)
+ {
+ //System.out.print(" "+ mddConst2.getArray()[j]);
+ if(mddConst.getArray()[j] != mddConst2.getArray()[j])
+ equal = false;
+ }
+ System.out.println("Copy constructor is OK: " + equal);
+
+ /**
+ * test the MArrayByte
+ */
+ System.out.println("\n\n### Testing MArrayByte: ################################################");
+ myQu = myApp.newOQLQuery();
+
+ myQu.create("drop collection test");
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("collection dropped");
+
+ myQu.create("create collection test GreySet");
+ RasMArrayByte mddByte = new RasMArrayByte(domain, stl);
+ byte[] dataByte = new byte[len];
+ mddByte.setObjectTypeName("GreyImage");
+
+ for(int j = 0; j < dataByte.length; j++)
+ dataByte[j] = (byte)j;
+
+ mddByte.setArray(dataByte);
+
+ //System.out.println("\nbyte array: ");
+ //for(int j=0; j<mddByte.getArray().length; j++)
+ //{
+ //System.out.print(" "+ mddByte.getArray()[j]);
+ //}
+
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("\ncollection created");
+ myQu.create("insert into test values $1 ");
+
+ //System.out.println("mdd before sending: " + mddByte);
+ myQu.bind(mddByte);
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("collection inserted");
+
+ myQu = myApp.newOQLQuery();
+ myQu.create("select img from test as img");
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("collection selected");
+ if (resultBag != null)
+ {
+ Iterator iter = resultBag.iterator();
+ while (iter.hasNext())
+ {
+ result = iter.next();
+ System.out.println("result mdd: " + ((RasGMArray)mddByte).toTestString());
+ System.out.println("result mdd: " + ((RasGMArray)result).toTestString());
+ equal = true;
+ for(int j=0; j<mddByte.getArray().length; j++)
+ {
+ if(mddByte.getArray()[j] != ((RasGMArray)result).getArray()[j])
+ equal = false;
+ }
+ }
+ //System.out.println("All results for MArrayByte");
+ System.out.println("inserted and selected MArrayByte are equal: " + equal);
+ }
+
+ // testing copy constructor
+ System.out.println("### Testing copy constructor:");
+ RasMArrayByte mddByte2 = new RasMArrayByte(mddByte);
+ mddByte2.setArray(dataByte);
+ //System.out.println("\nbyte array2: ");
+ dataByte = null;
+ equal = true;
+ for(int j=0; j<mddByte.getArray().length; j++)
+ {
+ //System.out.print(" "+ mddByte2.getArray()[j]);
+ if(mddByte.getArray()[j] != mddByte2.getArray()[j])
+ equal = false;
+ }
+ System.out.println("Copy constructor is OK: " + equal);
+
+ /**
+ * test the MArrayInteger
+ */
+ System.out.println("\n\n### Testing MArrayInteger: ################################################");
+ myQu = myApp.newOQLQuery();
+
+ myQu.create("drop collection test");
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("collection dropped");
+
+ myQu.create("create collection test UShortSet");
+ RasMArrayInteger mddInteger = new RasMArrayInteger(domain, stl);
+ int[] dataInteger = new int[len];
+ //byte[] dataInteger = new byte[144];
+ mddInteger.setObjectTypeName("UShortImage");
+
+ for(int j = 0; j < dataInteger.length; j++)
+ dataInteger[j] = j;
+
+ mddInteger.setArray(dataInteger);
+
+ //System.out.println("\nbyte array: ");
+ //for(int j=0; j<mddInteger.getArray().length; j++)
+ //{
+ //System.out.print(" "+ mddInteger.getArray()[j]);
+ //}
+
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("\ncollection created");
+ myQu.create("insert into test values $1 ");
+
+ //System.out.println("mdd before sending: " + mddInteger);
+ myQu.bind(mddInteger);
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("collection inserted");
+
+ myQu = myApp.newOQLQuery();
+ myQu.create("select img from test as img");
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("collection selected");
+ if (resultBag != null)
+ {
+ Iterator iter = resultBag.iterator();
+ while (iter.hasNext())
+ {
+ result = iter.next();
+ System.out.println("result mdd: " + ((RasGMArray)mddInteger).toTestString());
+ System.out.println("result mdd: " + ((RasGMArray)result).toTestString());
+ equal = true;
+ for(int j=0; j<mddInteger.getArray().length; j++)
+ {
+ if(mddInteger.getArray()[j] != ((RasGMArray)result).getArray()[j])
+ equal = false;
+ }
+ }
+ //System.out.println("All results for MArrayInteger");
+ System.out.println("inserted and selected MArrayInteger are equal: " + equal);
+ }
+
+ // testing copy constructor
+ System.out.println("### Testing copy constructor:");
+ RasMArrayInteger mddInteger2 = new RasMArrayInteger(mddInteger);
+ mddInteger2.setArray(dataInteger);
+ dataInteger = null;
+ equal = true;
+ for(int j=0; j<mddInteger2.getArray().length; j++)
+ {
+ //System.out.print(" "+ mddInteger2.getArray()[j]);
+ if(mddInteger.getArray()[j] != mddInteger2.getArray()[j])
+ equal = false;
+ }
+ System.out.println("Copy constructor is OK: " + equal);
+
+ /*
+ System.out.println("\nspecial array2: ");
+ for(int j=0; j<mddInteger2.getIntArray().length; j++)
+ {
+ System.out.print(" "+ mddInteger2.getIntArray()[j]);
+ }
+ */
+
+ /**
+ * test the MArrayDouble
+ */
+ System.out.println("\n\n### Testing MArrayDouble: ################################################");
+ myQu = myApp.newOQLQuery();
+
+ myQu.create("drop collection test");
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("collection dropped");
+
+ myQu.create("create collection test DoubleSet");
+ RasMArrayDouble mddDouble = new RasMArrayDouble(domain, stl);
+ double[] dataDouble = new double[len];
+ //byte[] dataDouble = new byte[288];
+ mddDouble.setObjectTypeName("DoubleImage");
+
+ for(double j = 0; j < dataDouble.length; j++)
+ dataDouble[(int)j] = j;
+
+ mddDouble.setArray(dataDouble);
+
+ //System.out.println("\nbyte array: ");
+ //for(int j=0; j<mddDouble.getArray().length; j++)
+ //{
+ //System.out.print(" "+ mddDouble.getArray()[j]);
+ //}
+
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("\ncollection created");
+ myQu.create("insert into test values $1 ");
+
+ //System.out.println("mdd before sending: " + mddDouble);
+ myQu.bind(mddDouble);
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("collection inserted");
+
+ myQu = myApp.newOQLQuery();
+ myQu.create("select img from test as img");
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("collection selected");
+ if (resultBag != null)
+ {
+ Iterator iter = resultBag.iterator();
+ while (iter.hasNext())
+ {
+ result = iter.next();
+ equal = true;
+ for(int j=0; j<mddDouble.getDoubleArray().length; j++)
+ {
+ if(mddDouble.getArray()[j] != ((RasGMArray)result).getArray()[j])
+ equal = false;
+ }
+ System.out.println("result mdd: " + ((RasGMArray)mddDouble).toTestString());
+ System.out.println("result mdd: " + ((RasGMArray)result).toTestString());
+ }
+ //System.out.println("All results for MArrayDouble");
+ System.out.println("inserted and selected MArrayDouble are equal: " + equal);
+ }
+
+
+ // testing copy constructor
+ System.out.println("### Testing copy constructor:");
+ RasMArrayDouble mddDouble2 = new RasMArrayDouble(mddDouble);
+ mddDouble2.setArray(dataDouble);
+ //System.out.println("byte array2: ");
+ dataDouble = null;
+ equal = true;
+ for(int j=0; j<mddDouble2.getArray().length; j++)
+ {
+ //System.out.print(" "+ mddDouble2.getArray()[j]);
+ if(mddDouble.getArray()[j] != mddDouble2.getArray()[j])
+ equal = false;
+ }
+ System.out.println("Copy constructor is OK: " + equal);
+
+ /*
+ System.out.println("\nspecial array2: ");
+ for(int j=0; j<mddDouble2.getDoubleArray().length; j++)
+ {
+ System.out.print(" "+ mddDouble2.getDoubleArray()[j]);
+ }
+ */
+
+ /**
+ * test the MArrayFloat
+ */
+ System.out.println("\n\n### Testing MArrayFloat: ################################################");
+ myQu = myApp.newOQLQuery();
+
+ myQu.create("drop collection test");
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("collection dropped");
+
+ myQu.create("create collection test FloatSet");
+ RasMArrayFloat mddFloat = new RasMArrayFloat(domain, stl);
+ float[] dataFloat = new float[len];
+ //byte[] dataFloat = new byte[144];
+ mddFloat.setObjectTypeName("FloatImage");
+
+ for(float j = 0; j < dataFloat.length; j++)
+ dataFloat[(int)j] = j;
+
+ mddFloat.setArray(dataFloat);
+
+ //System.out.println("\nbyte array: ");
+ //for(int j=0; j<mddFloat.getArray().length; j++)
+ //{
+ //System.out.print(" "+ mddFloat.getArray()[j]);
+ //}
+
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("\ncollection created");
+ myQu.create("insert into test values $1 ");
+
+ //System.out.println("mdd before sending: " + mddFloat);
+ myQu.bind(mddFloat);
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("collection inserted");
+
+ myQu = myApp.newOQLQuery();
+ myQu.create("select img from test as img");
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("collection selected");
+ if (resultBag != null)
+ {
+ Iterator iter = resultBag.iterator();
+ while (iter.hasNext())
+ {
+ result = iter.next();
+ equal = true;
+ for(int j=0; j<mddFloat.getArray().length; j++)
+ {
+ if(mddFloat.getArray()[j] != ((RasGMArray)result).getArray()[j])
+ equal = false;
+ }
+ System.out.println("result mdd: " + ((RasGMArray)mddFloat).toTestString());
+ System.out.println("result mdd: " + ((RasGMArray)result).toTestString());
+ }
+ //System.out.println("All results for MArrayFloat");
+ System.out.println("inserted and selected MArrayFloat are equal: " + equal);
+ }
+
+ // testing copy constructor
+ System.out.println("### Testing copy constructor:");
+ RasMArrayFloat mddFloat2 = new RasMArrayFloat(mddFloat);
+ mddFloat2.setArray(dataFloat);
+ //System.out.println("\nbyte array2: ");
+ dataFloat = null;
+ equal = true;
+ for(int j=0; j<mddFloat2.getArray().length; j++)
+ {
+ //System.out.print(" "+ mddFloat2.getArray()[j]);
+ if(mddFloat.getArray()[j] != mddFloat2.getArray()[j])
+ equal = false;
+ }
+ System.out.println("Copy constructor is OK: " + equal);
+ /*
+ System.out.println("\nspecial array2: ");
+ for(int j=0; j<mddFloat2.getFloatArray().length; j++)
+ {
+ System.out.print(" "+ mddFloat2.getFloatArray()[j]);
+ }
+ */
+
+ /**
+ * test the MArrayShort
+ */
+ System.out.println("\n\n### Testing MArrayShort: ################################################");
+ myQu = myApp.newOQLQuery();
+
+ myQu.create("drop collection test");
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("collection dropped");
+
+ myQu.create("create collection test ShortSet");
+ RasMArrayShort mddShort = new RasMArrayShort(domain, stl);
+ //RasMArrayShort mddShort4 = new RasMArrayShort(domain, stl);
+ //RasMArrayShort mddShort3 = new RasMArrayShort(domain, stl);
+ short[] dataShort = new short[len];
+ //short[] dataShort4 = new short[len];
+ //short[] dataShort3 = new short[len];
+ //byte[] dataShort = new byte[72];
+ mddShort.setObjectTypeName("ShortImage");
+ //mddShort4.setObjectTypeName("ShortImage");
+ //mddShort3.setObjectTypeName("ShortImage");
+
+ //System.out.println("new OID from server: " + myApp.getObjectId(mddShort));
+ //System.out.println("new OID from server: " + myApp.getObjectId(mddShort4));
+ for(int j = 0; j < dataShort.length; j++)
+ dataShort[j] = (short)j;
+
+ //for(int j = 0; j < dataShort.length; j++)
+ //dataShort[j] = 1;
+ //for(int j = 0; j < dataShort4.length; j++)
+ //dataShort4[j] = 2;
+ //for(int j = 0; j < dataShort3.length; j++)
+ //dataShort3[j] = 3;
+
+
+ mddShort.setArray(dataShort);
+ //mddShort4.setArray(dataShort4);
+ //mddShort3.setArray(dataShort3);
+ /*
+ System.out.println("\nbyte array: ");
+ for(int j=0; j<mddShort.getArray().length; j++)
+ {
+ System.out.print(" "+ mddShort.getArray()[j]);
+ }
+ */
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ myQu = myApp.newOQLQuery();
+ //System.out.println("\ncollection created");
+ //myQu.create("insert into test values $1");
+ myQu.create("insert into test values $1");
+ //System.out.println("mdd before sending: " + mddShort);
+ //myQu.bind("test");
+ myQu.bind(mddShort);
+ //myQu.bind(mddShort4);
+ //myQu.bind(mddShort3);
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ /*
+ myTa.begin();
+ myQu = myApp.newOQLQuery();
+ myQu.create("insert into test values $1");
+ myQu.bind(mddShort4);
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ myTa.begin();
+ myQu = myApp.newOQLQuery();
+ myQu.create("insert into test values $1");
+ myQu.bind(mddShort3);
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ */
+ //System.out.println("collection inserted");
+ myQu = myApp.newOQLQuery();
+ myQu.create("select img from test as img");
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("collection selected");
+ if (resultBag != null)
+ {
+ Iterator iter = resultBag.iterator();
+ while (iter.hasNext())
+ {
+ result = iter.next();
+ equal = true;
+ for(int j=0; j<mddShort.getArray().length; j++)
+ {
+ if(mddShort.getArray()[j] != ((RasGMArray)result).getArray()[j])
+ equal = false;
+ }
+ System.out.println("result mdd: " + ((RasGMArray)mddShort).toTestString());
+ System.out.println("result mdd: " + ((RasGMArray)result).toTestString());
+ }
+ //System.out.println("All results for MArrayShort");
+ System.out.println("inserted and selected MArrayShort are equal: " + equal);
+ }
+
+ // testing copy constructor
+ System.out.println("### Testing copy constructor:");
+ RasMArrayShort mddShort2 = new RasMArrayShort(mddShort);
+ mddShort2.setArray(dataShort);
+ //System.out.println("\nbyte array2: ");
+ dataShort = null;
+ equal = true;
+ for(int j=0; j<mddShort2.getArray().length; j++)
+ {
+ //System.out.print(" "+ mddShort2.getArray()[j]);
+ if(mddShort.getArray()[j] != mddShort2.getArray()[j])
+ equal = false;
+ }
+ System.out.println("Copy constructor is OK: " + equal);
+ /*
+ System.out.println("\nspecial array2: ");
+ for(int j=0; j<mddShort2.getShortArray().length; j++)
+ {
+ System.out.print(" "+ mddShort2.getShortArray()[j]);
+ }
+ */
+
+ /**
+ * test the MArrayLong
+ */
+ System.out.println("\n\n### Testing MArrayLong: ################################################");
+ myQu = myApp.newOQLQuery();
+
+ myQu.create("drop collection test");
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("collection dropped");
+
+ myQu.create("create collection test ULongSet");
+ RasMArrayLong mddLong = new RasMArrayLong(domain, stl);
+ long[] dataLong = new long[len];
+ //byte[] dataLong = new byte[288];
+ mddLong.setObjectTypeName("ULongImage");
+
+ for(long j = 0; j < dataLong.length; j++)
+ dataLong[(int)j] = j;
+ mddLong.setArray(dataLong);
+
+ /*
+ System.out.println("\nbyte array: ");
+ for(int j=0; j<mddLong.getArray().length; j++)
+ {
+ System.out.print(" "+ mddLong.getArray()[j]);
+ }
+ */
+
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("\ncollection created");
+ myQu.create("insert into test values $1 ");
+
+ //System.out.println("mdd before sending: " + mddLong);
+ myQu.bind(mddLong);
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("collection inserted");
+
+ myQu = myApp.newOQLQuery();
+ myQu.create("select img from test as img");
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("collection selected");
+ if (resultBag != null)
+ {
+ Iterator iter = resultBag.iterator();
+ while (iter.hasNext())
+ {
+ result = iter.next();
+ equal = true;
+ for(int j=0; j<((RasGMArray)result).getArray().length; j++)
+ {
+ if(mddLong.getArray()[j] != ((RasGMArray)result).getArray()[j])
+ equal = false;
+ }
+ System.out.println("result mdd: " + ((RasGMArray)mddLong).toTestString());
+ System.out.println("result mdd: " + ((RasGMArray)result).toTestString());
+ }
+ //System.out.println("All results for MArrayLong");
+ System.out.println("inserted MArrayInteger and selected MArrayLong are equal: " + equal);
+ }
+
+ // testing copy constructor
+ System.out.println("### Testing copy constructor:");
+ RasMArrayLong mddLong2 = new RasMArrayLong(mddLong);
+ mddLong2.setArray(dataLong);
+ //System.out.println("\nbyte array2: ");
+ dataLong = null;
+ equal = true;
+ for(int j=0; j<mddLong2.getArray().length; j++)
+ {
+ //System.out.print(" "+ mddLong2.getArray()[j]);
+ if(mddLong.getArray()[j] != mddLong2.getArray()[j])
+ equal = false;
+ }
+ System.out.println("Copy constructor is OK: " + equal);
+
+ System.out.println("\nspecial array: ");
+ for(int j=0; j<((RasMArrayLong)result).getLongArray().length; j++)
+ {
+ System.out.print(" "+ ((RasMArrayLong)result).getLongArray()[j]);
+ }
+
+
+ /**
+ * testing intersection
+ */
+ System.out.println("\n\n### Testing intersection:");
+ mddConst2.intersectionWith(domain2);
+ mddByte2.intersectionWith(domain2);
+ mddDouble2.intersectionWith(domain2);
+ mddFloat2.intersectionWith(domain2);
+ mddInteger2.intersectionWith(domain2);
+ mddLong2.intersectionWith(domain2);
+ mddShort2.intersectionWith(domain2);
+ System.out.println("OK\n");
+
+ /**
+ * testing OIDs
+ */
+ myQu = myApp.newOQLQuery();
+ myQu.create("SELECT oid(img) FROM test AS img");
+ //myQu.create("SELECT img FROM test AS img where (oid(img)=231425)");
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ if (resultBag != null)
+ {
+ Iterator iter = resultBag.iterator();
+ while (iter.hasNext())
+ {
+ result = iter.next();
+ //System.out.println("OID: " + result);
+ }
+ //System.out.println("All results");
+
+ }
+
+ /**
+ * get new OID
+ */
+ System.out.println("### Testing OIDs:");
+ myTa.begin();
+ myApp.getObjectId(new RasGMArray());
+ myTa.commit();
+
+ System.out.println( "Closing database ..." );
+ myDb.close();
+
+ // get new OID without open TA
+ RasGMArray gmar = new RasGMArray();
+ equal = true;
+ if(!myApp.getObjectId(gmar).equals(gmar.getOID().toString()))
+ equal = false;
+ System.out.println("same OID on client and server side: " + equal);
+
+ }
+ catch (RasException e)
+ {
+ System.out.println("!!!!!!!!!!!!!!!!!!!!While testing!!!!!!!!!!!!!!!!!!");
+ System.out.println("An RasException has occurred: " + e.getMessage());
+ System.out.println("Try to abort the transaction ...");
+ if(myTa != null) myTa.abort();
+
+ try
+ {
+ System.out.println("Try to close the database ...");
+ if(myDb != null) myDb.close();
+ }
+ catch ( org.odmg.ODMGException exp )
+ {
+ System.err.println("Could not close the database: " + exp.getMessage());
+ }
+ }
+ catch (RasRuntimeException e)
+ {
+ System.out.println("!!!!!!!!!!!!!!!!!!!!While testing!!!!!!!!!!!!!!!!!!");
+ System.out.println("An RasRuntimeException has occurred: " + e.getMessage());
+ System.out.println("Try to abort the transaction ...");
+ if(myTa != null) myTa.abort();
+
+ try
+ {
+ System.out.println("Try to close the database ...");
+ if(myDb != null) myDb.close();
+ }
+ catch ( org.odmg.ODMGException exp )
+ {
+ System.err.println("Could not close the database: " + exp.getMessage());
+ }
+ }
+ catch (org.odmg.ODMGException e)
+ {
+ System.out.println("!!!!!!!!!!!!!!!!!!!!While testing!!!!!!!!!!!!!!!!!!");
+ System.out.println("An ODMGException has occurred: " + e.getMessage());
+ System.out.println("Try to abort the transaction ...");
+ if(myTa != null) myTa.abort();
+
+ try
+ {
+ System.out.println("Try to close the database ...");
+ if(myDb != null) myDb.close();
+ }
+ catch ( org.odmg.ODMGException exp )
+ {
+ System.err.println("Could not close the database: " + exp.getMessage());
+ }
+ }
+ System.out.println( "Done." );
+
+ }
+}
+
diff --git a/java/rasj/test/TestOdmg.java b/java/rasj/test/TestOdmg.java
new file mode 100644
index 0000000..da10505
--- /dev/null
+++ b/java/rasj/test/TestOdmg.java
@@ -0,0 +1,430 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * test rasj with some queries
+ * @param --server s - use server s (default: localhost)
+ * @param --port p - use server port p (default: 7001)
+ * @param --database d - use database d (default: RASBASE)
+ * @param --user u - log in as user u (default: rasguest)
+ * @param --passwd p - log in with password p (default: rasguest)
+ *
+ * PREREQUISITES:
+ * - needs an HTTP server
+ * - needs write access to database
+ * - database must know type GreySet
+ *
+ *
+ * COMMENTS:
+ * - no parameter line error handling
+ * was formerly in rasj/odmg/test, this has been merged
+ ************************************************************/
+
+import rasj.*;
+import rasj.global.*;
+import org.odmg.*;
+import rasj.odmg.*;
+
+import java.util.*;
+import java.io.*;
+
+public class TestOdmg implements RasGlobalDefs
+ {
+
+ /**
+ * prefixes for test output
+ **/
+ static final String PREFIX_PROGRAM = "+++ +++ +++ ";
+ static final String PREFIX_TESTSET = "+++ +++ ";
+ static final String PREFIX_TESTCASE = "+++ ";
+
+ /**
+ * std error tag printed if a test fails
+ **/
+ static final String ERROR_TAG = "ERROR: ";
+
+ /**
+ * default values (override with cmd line option)
+ **/
+ static final String DEFAULT_HOST = "localhost";
+ static final int DEFAULT_PORT = 7001;
+ static final String DEFAULT_BASE = "RASBASE";
+ static final String DEFAULT_USER = "rasguest";
+ static final String DEFAULT_PASSWD = "rasguest";
+
+ public static void main(String[] args) throws Exception
+ {
+
+ String serv = DEFAULT_HOST;
+ int port = DEFAULT_PORT;
+ String base = DEFAULT_BASE;
+ String user = DEFAULT_USER;
+ String passwd = DEFAULT_PASSWD;
+ boolean wrongUsage = false; // error in cmd line params?
+ RasImplementation myImp = null;
+
+ for (int i=args.length-1; i>=0; i--)
+ {
+ if (args[i].equals("--server"))
+ serv = args[i+1];
+ else if (args[i].equals("--port"))
+ {
+ try
+ {
+ port = Integer.parseInt(args[i+1]);
+ }
+ catch(Exception e)
+ {
+ wrongUsage = true;
+ }
+ }
+ else if (args[i].equals("--database"))
+ base = args[i+1];
+ else if (args[i].equals("--user"))
+ user = args[i+1];
+ else if (args[i].equals("--passwd"))
+ passwd = args[i+1];
+ }
+
+ if (wrongUsage)
+ {
+ System.out.println( "Usage: ODMGtest [--server s] [--port p] [--database d] [--user u] [--passwd p]" );
+ System.out.println( "defaults: server=" + DEFAULT_HOST + ", port=" + DEFAULT_PORT + ", database=" + DEFAULT_BASE
++ ", user=" + DEFAULT_USER + ", passwd=" + DEFAULT_PASSWD );
+ System.exit(-1);
+ }
+
+ System.out.println( "rasdaman system test v5.1revC: testing ODMG queries." );
+ System.out.println( PREFIX_PROGRAM + "system test started, using server " + serv + ", port " + port + ", database " + base + ", user=" + user + ", passwd=" + passwd );
+
+ myImp = new RasImplementation("http://" + serv + ":" + port);
+
+ // START tests ----------------------------------------------
+ testQueries( myImp, base );
+ // END tests ------------------------------------------------
+
+ System.out.println( PREFIX_PROGRAM + "system test done." );
+ return;
+ } // main()
+
+ /**
+ * test database queries
+ * any eventual exception that is not caught here is an error, and will cause an abort
+ **/
+ static void testQueries( RasImplementation imp, String database ) throws Exception
+ {
+ System.out.println( PREFIX_TESTSET + "testing queries started." );
+
+ // objectTest(); // - just to test setObjectName() which now verifies that the name is a valid identifier
+
+ Database mydb = null;
+ Transaction myta = null;
+ RasGMArray myMDD = null;
+ OQLQuery myQuery = null;
+
+
+ /*********************
+ * test update query *
+ *********************/
+ // create some test data
+ try
+ {
+ System.out.println("Start creating test arrays ...");
+ myMDD = new RasGMArray(new RasMInterval("[1:400,1:400]"),1);
+ byte[] mydata = new byte[160000];
+ for(int y=0; y<400; y++)
+ {
+ for(int x=0; x<400; x++)
+ {
+ if((x>99 && x<151) || (x>299 && x<351))
+ mydata[y*399+x]=100;
+ else
+ mydata[y*399+x]=0;
+ }
+ }
+ myMDD.setArray(mydata);
+ myMDD.setObjectTypeName("GreyImage");
+
+ RasStorageLayout myLayout = new RasStorageLayout();
+ //myLayout.setTileSize(640000);
+ myLayout.setTileDomain("[1:100,1:70]");
+ myMDD.setStorageLayout(myLayout);
+
+ System.out.println("Created Test Data:");
+ System.out.println(myMDD);
+ }
+
+ catch ( Exception e )
+ {
+ System.out.println("ERROR: ");
+ System.out.println(e.getMessage());
+ System.exit(-1);
+ }
+
+ // now access the database and start a transaction
+ try {
+ mydb = imp.newDatabase();
+ System.out.println("Open Database ...");
+ mydb.open( database, Database.OPEN_READ_WRITE );
+ System.out.println(" ok.");
+ myta = imp.newTransaction();
+ System.out.println("Begin transaction ...");
+ myta.begin();
+ System.out.println(" ok.");
+ }
+
+ catch ( Exception e ) {
+ System.out.println("ERROR: ");
+ System.out.println(e.getMessage());
+
+ if(myta.isOpen())
+ {
+ System.out.println("Abort transaction ...");
+ myta.abort();
+ }
+ System.out.println("Close database ...");
+ try {
+ mydb.close();
+ System.out.println(" ok.");
+ }
+ catch ( Exception e2 ) {
+ }
+ System.out.println("Exiting...");
+ System.exit(-1);
+ }
+
+ // create the test collection
+ try {
+ System.out.println("Create a new test collection ...");
+ myQuery = imp.newOQLQuery();
+ myQuery.create("create collection testCollection GreySet");
+ //myQuery.create("create collection $1 GreySet");
+ //myQuery.bind("testCollection");
+ myQuery.execute();
+ myta.commit();
+ myta.begin();
+ System.out.println(" ok.");
+ }
+
+ catch ( Exception e) {
+ System.out.println("ERROR: ");
+ System.out.println(e.getMessage());
+ System.out.println("Try to remove the test collection ...");
+ try {
+ myQuery.create("drop collection testCollection");
+ myQuery.execute();
+ myta.commit();
+ }
+ catch ( Exception e2 ) {
+ }
+
+ if(myta.isOpen())
+ {
+ System.out.println("Abort transaction ...");
+ myta.abort();
+ }
+ System.out.println("Close database ...");
+ try {
+ mydb.close();
+ System.out.println(" ok.");
+ }
+ catch ( Exception e3 ) {
+ }
+
+ System.out.println("Exiting...");
+ System.exit(-1);
+ }
+
+ // testquery with empty result
+ /*
+ try {
+ System.out.println("Define a testquery with an empty result... ");
+ myQuery.create("select a from ImgRGBA as a where oid(a) <= 0");
+ System.out.println("Send the query ...");
+ DSet myResult = (DSet) myQuery.execute();
+
+ Iterator iter = myResult.iterator();
+ System.out.println("Number of results: " + myResult.size());
+
+
+ while(iter.hasNext())
+ {
+ System.out.println("Ergebnis:");
+ System.out.println(iter.next());
+ }
+
+ System.out.println(" ok.");
+ System.out.println("Commit transaction ...");
+ System.out.println(" ok.");
+ }
+
+ catch ( Exception e ) {
+ System.out.println("ERROR: ");
+ System.out.println(e.getMessage());
+
+ if(myta.isOpen())
+ {
+ System.out.println("Abort transaction ...");
+ myta.abort();
+ }
+ System.out.println("Close database ...");
+ try {
+ mydb.close();
+ System.out.println(" ok.");
+ }
+ catch ( Exception e2 ) {
+ }
+ System.out.println("Exiting...");
+ System.exit(-1);
+ }
+ */
+
+ // now insert MDDS and commit
+ try {
+ System.out.println("Define the update query and bind the parameters ...");
+ myQuery.create("insert into testCollection VALUES $1");
+ //myQuery.create("insert into testCollection VALUES $1");
+ myQuery.bind(myMDD);
+ System.out.println(" ok.");
+ System.out.println("Send the query ...");
+ myQuery.execute();
+ System.out.println(" ok.");
+ System.out.println("Commit transaction ...");
+ myta.commit();
+ System.out.println(" ok.");
+ }
+
+ catch ( Exception e ) {
+ System.out.println("ERROR: ");
+ System.out.println(e.getMessage());
+
+ if(myta.isOpen())
+ {
+ System.out.println("Abort transaction ...");
+ myta.abort();
+ }
+ System.out.println("Close database ...");
+ try {
+ mydb.close();
+ System.out.println(" ok.");
+ }
+ catch ( Exception e2 ) {
+ }
+ System.out.println("Exiting...");
+ System.exit(-1);
+ }
+
+ // start new transaction and todo: read back the testimage
+ try {
+ System.out.println("Start new transaction ...");
+ myta.begin();
+ myQuery = imp.newOQLQuery();
+ myQuery.create("select testCollection from testCollection");
+ //myQuery.create("create collection $1 GreySet");
+ //myQuery.bind("testCollection");
+ myQuery.execute();
+ myta.commit();
+ System.out.println(" ok.");
+ myta.begin();
+
+ }
+
+ catch ( Exception e ) {
+ System.out.println("ERROR: ");
+ System.out.println(e.getMessage());
+
+ if(myta.isOpen())
+ {
+ System.out.println("Abort transaction ...");
+ myta.abort();
+ }
+ System.out.println("Close database ...");
+ try {
+ mydb.close();
+ System.out.println(" ok.");
+ }
+ catch ( Exception e2 ) {
+ }
+ System.out.println("Exiting...");
+ System.exit(-1);
+ }
+
+ // todo: compare to the original image
+
+ // drop test collection
+ try {
+ System.out.println("Drop test collection ...");
+ myQuery = imp.newOQLQuery();
+ myQuery.create("drop collection testCollection");
+ myQuery.execute();
+ myta.commit();
+ mydb.close();
+ System.out.println(" ok.");
+ }
+
+ catch ( Exception e) {
+ System.out.println("ERROR: ");
+ System.out.println(e.getMessage());
+
+ if(myta.isOpen())
+ {
+ System.out.println("Abort transaction ...");
+ myta.abort();
+ }
+ System.out.println("Close database ...");
+ try {
+ mydb.close();
+ System.out.println(" ok.");
+ }
+ catch ( Exception e2 ) {
+ }
+ System.out.println("Exiting...");
+ System.exit(-1);
+ }
+
+ System.out.println( PREFIX_TESTSET + "testing queries done.\n" );
+ return;
+ } // testQueries()
+
+ public static void objectTest()
+ {
+ System.out.println("Set object name test - in");
+
+ RasObject dummy = new RasObject();
+
+ dummy.setObjectName("goodName");
+
+ System.out.println("Set name=" + dummy.getObjectName());
+
+ dummy.setObjectName("bad-Name");
+
+ System.out.println("Set name=" + dummy.getObjectName());
+
+ System.out.println("Set object name test - out");
+
+ }
+
+} // TestOdmg
+
diff --git a/java/rasj/test/TestQuery.java b/java/rasj/test/TestQuery.java
new file mode 100644
index 0000000..362b99f
--- /dev/null
+++ b/java/rasj/test/TestQuery.java
@@ -0,0 +1,143 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * test rasj: simple open/read query/close cycle.
+ * rasj test program for executing a query against some rasdaman database.
+ * Note: database is opened readonly, so send only SELECT queries.
+ *
+ * @param --server s - use server s (default: localhost)
+ * @param --port p - use server port p (default: 7001)
+ * @param --database d - use database d (default: RASBASE)
+ * @param --user u - log in as user u (default: rasguest)
+ * @param --passwd p - log in with password p (default: rasguest)
+ * @param --query q - send SELECT query string q to server (default: "select r from RAS_COLLECTIONNAMES as r"")
+ * @param --count c - execute query c times (default: 1)
+ *
+ *
+ * COMMENTS:
+ * - no parameter line error handling
+ ************************************************************/
+
+import rasj.*;
+import rasj.odmg.*;
+import org.odmg.*;
+import java.util.*;
+import java.io.*;
+
+public class TestQuery
+ {
+
+ public static void main( String[] args )
+ {
+ String server = "localhost";
+ String port = "7001";
+ String base = "RASBASE";
+ String user = "rasguest";
+ String passwd = "rasguest";
+ String query = "select r from RAS_COLLECTIONNAMES as r";
+ int count = 1;
+
+ if (args.length == 0)
+ {
+ System.out.println( "usage: TestQuery [options]" );
+ System.out.println( "options:" );
+ System.out.println( " --server s - use server s (default: localhost)" );
+ System.out.println( " --port p - use server port p (default: 7001)" );
+ System.out.println( " --database d - use database d (default: RASBASE)" );
+ System.out.println( " --user u - log in as user u (default: rasguest)" );
+ System.out.println( " --passwd p - log in with password p (default: rasguest)" );
+ System.out.println( " --query q - send SELECT query string q to server (default: select r from RAS_COLLECTIONNAMES as r)" );
+ System.out.println( " --count c - execute query c times (default: 1)" );
+ return;
+ }
+
+ for (int i=args.length-1; i>=0; i--)
+ {
+ if (args[i].equals("--server"))
+ server = args[i+1];
+ if (args[i].equals("--port"))
+ port = args[i+1];
+ if (args[i].equals("--database"))
+ base = args[i+1];
+ if (args[i].equals("--user"))
+ user = args[i+1];
+ if (args[i].equals("--passwd"))
+ passwd = args[i+1];
+ if (args[i].equals("--query"))
+ query = args[i+1];
+ if (args[i].equals("--count"))
+ count = Integer.parseInt(args[i+1]);
+ }
+
+ System.out.println( "Query test started with server=" + server + ", port=" + port + ", database=" + base + ", user=" + user + ", count=" + count + ", query=" + query );
+
+ try
+ {
+ RasImplementation myApp = new RasImplementation("http://"+server+":"+port);
+ myApp.setUserIdentification(user, passwd);
+
+ System.out.println( "opening database..." );
+ Database myDb = myApp.newDatabase();
+ myDb.open( base, Database.OPEN_READ_WRITE );
+
+ System.out.println( "starting transaction..." );
+ Transaction myTa = myApp.newTransaction();
+ myTa.begin();
+
+ for (int i = 1; i <= count; i++)
+ {
+
+ System.out.print( "sending query #" + i + "..." );
+ OQLQuery myQu = myApp.newOQLQuery();
+ myQu.create(query);
+ DBag result = (DBag) myQu.execute();
+
+ System.out.println( "result is: " + result );
+
+ }
+
+ System.out.println( "closing transaction..." );
+ myTa.commit();
+
+ // System.out.println( "sending query out of TA, must produce an error..." );
+ // OQLQuery myQu2 = myApp.newOQLQuery();
+ // myQu2.create(query);
+ // DBag result2 = (DBag) myQu2.execute();
+
+ System.out.println( "closing database..." );
+ myDb.close();
+
+ }
+ catch(Exception e)
+ {
+ System.err.println( e.getMessage() );
+ }
+
+ System.out.println( "Query test done." );
+
+ } // main()
+
+} // TestQuery
diff --git a/java/rasj/test/TestQuery.sh b/java/rasj/test/TestQuery.sh
new file mode 100644
index 0000000..ca3b2fe
--- /dev/null
+++ b/java/rasj/test/TestQuery.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+# TestQuery.sh: test rasj query interface
+# where rasj.jar is expected:
+export RASJ=$RMANBASE/java/rasj.jar
+#export RASJ=~rasdaman/jlib/rasj.jar
+
+java -DRMANPROTOCOL=RNP -cp .:$RASJ:$CLASSPATH TestQuery --query "SELECT jpeg(( marray x in [0:599,0:599] values {255c,255c,0c} ) overlay scale(img0[2011:2315,2543:2847],[1:600,1:600]) * { 1c, 1c, 1c}) FROM vat_rgbdop2_8 AS img0" $* 2>&1
+
diff --git a/java/rasj/test/TestRasInterval.java b/java/rasj/test/TestRasInterval.java
new file mode 100644
index 0000000..27450fd
--- /dev/null
+++ b/java/rasj/test/TestRasInterval.java
@@ -0,0 +1,314 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ * - on error, an exception is thrown (java main() knows no exit status)
+ *
+ * </pre>
+ *********************************************************** */
+
+import java.util.StringTokenizer;
+import java.lang.Integer;
+import java.lang.Long;
+import rasj.*;
+import rasj.odmg.*;
+
+public class TestRasInterval
+ {
+ /**
+ * constants used in this test
+ **/
+ // prefixes for test output
+ static final String PREFIX_PROGRAM = "+++ +++ +++ ";
+ static final String PREFIX_TESTSET = "+++ +++ ";
+ static final String PREFIX_TESTCASE = "+++ ";
+
+ /**
+ * std error tag printed upon failure
+ **/
+ static final String ERROR_TAG = "ERROR: ";
+
+ /**
+ * main program for testing
+ * on error, an exception is thrown (java main() knows no exit status)
+ **/
+ public static void main(String argv[]) throws Exception
+ {
+ System.out.println( "rasdaman system test v5.1revC: TestRasInterval." );
+ System.out.println( PREFIX_PROGRAM + "system test started." );
+
+ // -- START test cases -------------------------------------------------
+ testInterval();
+ // -- END test cases ---------------------------------------------------
+
+ System.out.println( PREFIX_PROGRAM + "system test done." );
+ return;
+ }
+
+ /**
+ * test the RasInterval class (no db access)
+ * any eventual exception that is not caught here is an error, and will cause an abort
+ **/
+ static void testInterval() throws RasResultIsNoIntervalException, RasDimensionMismatchException, RasIndexOutOfBoundsException, RasStreamInputOverflowException
+ {
+ // create a new RasSInterval
+ System.out.println("\n############################ test sintervals: ");
+ RasSInterval s1 = new RasSInterval(100,200);
+ RasSInterval s2 = new RasSInterval("150:400");
+
+ // get upper bound
+ boolean b1 = false;
+ if(s2.high() == 400)
+ b1 = true;
+ System.out.println("upper bound is correct: " + b1);
+
+ // test if lower bound is fixed
+ boolean b2;
+ b1 = false;
+ b1 = s2.isLowFixed();
+ System.out.println("lower bound is fix: " + b1);
+
+ // test if interval intersects with another interval
+ // (the return value shows the kind of intersection)
+ int j;
+ j = s1.intersectsWith(s2);
+ b1 = false;
+ if(j != -1)
+ b1 = true;
+ System.out.println("s1 intersects with s2: " + b1);
+
+ RasSInterval sint1 = new RasSInterval(100,200);
+ RasSInterval sint2 = new RasSInterval("150 :400 ");
+ RasSInterval sint3 = new RasSInterval("50:180");
+
+ b1 = false;
+ sint1.setHigh('*');
+ sint1.setLow(400);
+ if(sint1.low() == 400)
+ b1 = true;
+ sint1.setLow('*');
+ sint1.setHigh(500);
+ if((sint1.high() == 500) && b1)
+ b1 = true;
+ else
+ b1 = false;
+ System.out.println("setLow and setHigh are OK: " + b1);
+
+ sint1.setInterval('*',500);
+ b1 = !sint1.isLowFixed();
+ b1 = sint1.isHighFixed() && b1;
+ System.out.println("low is open high is fixed: " + b1);
+
+ b1 = false;
+ if(sint1.intersectsWith(sint1) != -1)
+ b1 = true;
+
+ if(sint3.closureOf(sint2, sint1).equals(sint1) &&
+ sint3.closureWith(sint2).equals(sint1) &&
+ sint3.createClosure(sint2).equals(sint1))
+ b1 = b1 && true;
+
+ sint1.setInterval(90, 105);
+ sint2.setInterval(100, 110);
+ if(sint2.createDifference(sint1).equals(new RasSInterval(90, 100)) &&
+ sint3.createIntersection(sint2).equals(new RasSInterval(100, 110)))
+ b1 = b1 && true;
+
+ if(sint3.createUnion(sint2).equals(sint1) &&
+ sint1.differenceOf(sint1, sint2).equals(new RasSInterval(90, 100)) &&
+ sint1.differenceWith(sint2).equals(new RasSInterval(100, 110)))
+ b1 = b1 && true;
+
+ if(sint3.intersectionOf(sint2, sint1).equals(new RasSInterval(100, 100)) &&
+ sint3.intersectionWith(sint2).equals(new RasSInterval(100, 100)))
+ b1 = b1 && true;
+
+ b1 = b1 && !sint3.equals(sint2);
+ if(sint3.unionOf(sint1, sint2).equals(new RasSInterval(90, 110)) &&
+ sint3.unionWith(sint2).equals(new RasSInterval(90, 110)))
+ b1 = b1 && true;
+ System.out.println("operations of sintervals are correct: " + b1);
+
+
+
+ // create new RasMInterval
+ System.out.println("\n############################ test mintervals: ");
+ RasMInterval mint1 = new RasMInterval("[567:3253,666:888]");
+ RasMInterval mint2 = new RasMInterval("[678:4000,777:999]");
+ RasMInterval mint3 = new RasMInterval("[777:900,888:1000]");
+ RasMInterval mint4 = new RasMInterval(2);
+ b1 = false;
+ if((mint2.dimension() == 2) && (mint1.dimension() == 2))
+ b1 = true;
+ System.out.println("dimensions of mintervals are correct: " + b1);
+
+ b1 = false;
+ mint1 = new RasMInterval("[500:3000,600:800]");
+ mint2 = new RasMInterval("[600:1000,700:750]");
+ b1 = mint1.intersectsWith(mint2);
+ mint1 = new RasMInterval("[567:3253,666:888]");
+ mint2 = new RasMInterval("[678:4000,777:999]");
+ if(mint3.closureOf(mint2, mint1).toString().equals(new RasMInterval("[567:4000,666:999]").toString()))
+ b1 = b1 && true;
+ else b1 = false;
+ if(mint3.closureWith(mint2).toString().equals(new RasMInterval("[567:4000,666:999]").toString()))
+ b1 = b1 && true;
+ else b1 = false;
+ if(mint3.createClosure(mint2).toString().equals(new RasMInterval("[567:4000,666:999]").toString()))
+ b1 = b1 && true;
+ else b1 = false;
+ mint3 = new RasMInterval("[678:2000,777:888]");
+ mint3 = mint3.createDifference(mint2);
+ if(mint3.toString().equals(new RasMInterval("[2000:4000,888:999]").toString()))
+ b1 = b1 && true;
+ else b1 = false;
+ mint3 = new RasMInterval("[678:2000,777:888]");
+ mint3 = mint3.createDifference(mint2);
+ if(mint3.toString().equals(new RasMInterval("[2000:4000,888:999]").toString()))
+ b1 = b1 && true;
+ else b1 = false;
+ mint3 = new RasMInterval("[678:2000,777:888]");
+ mint3 = mint3.createIntersection(mint2);
+ if(mint3.toString().equals(new RasMInterval("[678:2000,777:888]").toString()))
+ b1 = b1 && true;
+ else b1 = false;
+ mint3 = new RasMInterval("[678:2000,777:888]");
+ mint2 = new RasMInterval("[1000:4000,750:999]");
+ mint3 = mint3.createUnion(mint2);
+ if(mint3.toString().equals(new RasMInterval("[678:4000, 750:999]").toString()))
+ b1 = b1 && true;
+ else b1 = false;
+ mint2 = new RasMInterval("[1000:4000,800:999]");
+ mint1 = mint1.differenceOf(mint3, mint2);
+ if(mint1.toString().equals(new RasMInterval("[678:1000,750:800]").toString()))
+ b1 = b1 && true;
+ else b1 = false;
+ mint3 = mint3.intersectionOf(mint2, mint1);
+ if(mint3.toString().equals(new RasMInterval("[1000:1000,800:800]").toString()))
+ b1 = b1 && true;
+ else b1 = false;
+ mint3 = mint3.intersectionWith(mint2);
+ if(mint3.toString().equals(new RasMInterval("[1000:1000,800:800]").toString()))
+ b1 = b1 && true;
+ else b1 = false;
+ b1 = b1 && !mint3.equals(mint2);
+ mint3 = mint3.unionOf(mint1, mint2);
+ if(mint3.toString().equals(new RasMInterval("[678:4000,750:999]").toString()))
+ b1 = b1 && true;
+ else b1 = false;
+ mint3 = mint3.unionWith(mint2);
+ if(mint3.toString().equals(new RasMInterval("[678:4000,750:999]").toString()))
+ b1 = b1 && true;
+ else b1 = false;
+ mint2 = mint2.differenceWith(mint3);
+ if(mint2.toString().equals(new RasMInterval("[678:1000,750:800]").toString()))
+ b1 = b1 && true;
+ else b1 = false;
+ System.out.println("operations of mintervals are correct: " + b1);
+
+ // Types
+ ///////////////////////////////////////////
+ System.out.println("\n############################ test types: ");
+ String s = "marray <char, 1>";
+ RasType rType = RasType.getAnyType(s);
+ RasBaseType rb;
+
+ if(rType.getClass().getName().equals("rasj.RasMArrayType"))
+ {
+ RasMArrayType tmp = (RasMArrayType)rType;
+ rb = tmp.getBaseType();
+
+ System.out.println("OK");
+ }
+ else
+ System.out.println("element of MDD Collection is no MArray.");
+
+ boolean b3;
+ b3 = !rType.isStructType();
+ System.out.println(b3);
+
+
+ // StorageLayout
+ ///////////////////////////////////////////
+ System.out.println("\n############################ test storage layout: ");
+ RasGMArray myMDD = new RasGMArray(new RasMInterval("[1:400,1:400]"),1);
+ byte[] mydata = new byte[160000];
+ for(int y=0; y<400; y++)
+ {
+ for(int x=0; x<400; x++)
+ {
+ if((x>99 && x<151) || (x>299 && x<351))
+ mydata[y*399+x]=100;
+ else
+ mydata[y*399+x]=0;
+ }
+ }
+
+ myMDD.setArray(mydata);
+ myMDD.setObjectTypeName("GreyImage");
+
+ RasStorageLayout myLayout = new RasStorageLayout();
+
+ myLayout.setTileDomain("[1:100,1:70]");
+ // you can either set the TileSize or the TileDomain
+ myLayout.setTileSize(32);
+ myMDD.setStorageLayout(myLayout);
+ if(myMDD.getStorageLayout().getTileSize() == 32)
+ System.out.println("OK");
+
+
+ //GMarray////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ RasGMArray array1 = new RasGMArray();
+ RasGMArray array2 = new RasGMArray(mint1, 8);
+
+ myMDD.getCell(new RasPoint(1,1));
+
+ System.out.println("OK");
+
+
+ //Ausgabe////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ /*
+ System.out.println("Array1 " + array1);
+ System.out.println("Array2 " + array2);
+
+ System.out.println("Punkt1 " + p1);
+ System.out.println("Punkt2 " + p2);
+
+ System.out.println("Sinterval1 " + s1);
+ System.out.println("Sinterval2 " + s2);
+ System.out.println("Sinterval3 " + sint3);
+
+ System.out.println("j = " + j);
+ //System.out.println("b1 = " + b1);
+ //System.out.println("b2 = " + b2);
+ System.out.println("b3 = " + b3);
+ */
+
+ }
+
+ } // TestRasInterval
diff --git a/java/rasj/test/TestRasPoint.java b/java/rasj/test/TestRasPoint.java
new file mode 100644
index 0000000..6402bf0
--- /dev/null
+++ b/java/rasj/test/TestRasPoint.java
@@ -0,0 +1,373 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE:
+ * test rasj class RasPoint.
+ *
+ *
+ * COMMENTS:
+ * - testing philosophy is to run all tests and report. no exit code / exception
+ * is used for error indication; look into the output for ERROR_TAG instead.
+ * - unexpected exceptions are not caught, hence will make gmake fail and show the error
+ * - every test that fails must print a line containing ERROR_TAG
+ * </pre>
+ *********************************************************** */
+
+import java.util.StringTokenizer;
+import java.lang.Integer;
+import java.lang.Long;
+import rasj.*;
+import rasj.odmg.*;
+
+public class TestRasPoint
+ {
+ /**
+ * constants used in this test
+ **/
+ // prefixes for test output
+ static final String PREFIX_PROGRAM = "+++ +++ +++ ";
+ static final String PREFIX_TESTSET = "+++ +++ ";
+ static final String PREFIX_TESTCASE = "+++ ";
+
+ static final int COORD_1 = 11;
+ static final int COORD_2 = 22;
+ static final int COORD_3 = 33;
+ static final int COORD_4 = 44;
+ static final int COORD_5 = 55;
+
+ /**
+ * std error tag printed if a test fails
+ **/
+ static final String ERROR_TAG = "ERROR: ";
+
+ /**
+ * main program for testing
+ * on error, an exception is thrown (java main() knows no exit status)
+ **/
+ public static void main(String argv[]) throws Exception
+ {
+ System.out.println( "rasdaman system test v5.1revC: testing class RasPoint." );
+ System.out.println( PREFIX_PROGRAM + "system test started." );
+
+ // -- START test cases -------------------------------------------------
+ testConstructor();
+ // testcomparedWith();
+ // testEquals();
+ // testStream();
+ // testSetItem();
+ // testSetTo();
+ testAdd();
+ // testmult();
+ // -- END test cases ---------------------------------------------------
+
+ System.out.println( PREFIX_PROGRAM + "system test done." );
+ return;
+ }
+
+ /**
+ * test the RasPoint class constructor
+ * any eventual exception that is not caught here is an error, and will cause an abort
+ **/
+ static void testConstructor() throws RasDimensionMismatchException, RasIndexOutOfBoundsException
+ {
+ System.out.println( PREFIX_TESTSET + "testing constructor started." );
+
+ // default constructor
+ System.out.print( PREFIX_TESTCASE + "default constructor..." );
+ RasPoint p_default = new RasPoint();
+ if (p_default == null)
+ System.out.println( ERROR_TAG + "result is null." );
+ else if (! p_default.equals( p_default ) )
+ System.out.println( ERROR_TAG + "point notEqual to itself." );
+ else
+ System.out.println( "OK, result=" + p_default + ", dimension is " + p_default.dimension() );
+
+ // stream constructor
+ // ------------------
+
+ System.out.print( PREFIX_TESTCASE + "stream constructor, illegal dimension -1..." );
+ try
+ {
+ RasPoint p_stream_m1 = new RasPoint( -1 );
+ if (p_stream_m1 != null)
+ System.out.println( ERROR_TAG + "result is not null." );
+ else
+ System.out.println( "OK." );
+ }
+ catch(NegativeArraySizeException e)
+ {
+ System.out.println( "OK: " + e.getMessage() );
+ }
+
+ System.out.print( PREFIX_TESTCASE + "stream constructor, dimension 0..." );
+ RasPoint p_stream_0 = new RasPoint( 0 );
+ if (p_stream_0.dimension() != 0)
+ System.out.println( ERROR_TAG + "wrong dimension." );
+ else
+ System.out.println( "OK." );
+
+ // --- easy-to-use constructor -------------------------------------------------------
+
+ // 2-D constructor
+ System.out.print( PREFIX_TESTCASE + "2D easy to use constructor..." );
+ RasPoint p_2d_easy = new RasPoint( COORD_1, COORD_2 );
+ if (p_2d_easy == null)
+ System.out.println( ERROR_TAG + "result is null." );
+ else if (p_2d_easy.dimension() != 2)
+ System.out.println( ERROR_TAG + "dimension is not 2 but " + p_2d_easy.dimension() );
+ else if (p_2d_easy.item(0) != COORD_1)
+ System.out.println( ERROR_TAG + "item(0) returns wrong component " + p_2d_easy.item(0) );
+ else if (p_2d_easy.item(1) != COORD_2)
+ System.out.println( ERROR_TAG + "item(1) returns wrong component " + p_2d_easy.item(0) );
+ else if (! p_2d_easy.equals( p_2d_easy ) )
+ System.out.println( ERROR_TAG + "point not equal to itself." );
+ else if ( p_2d_easy.notEquals( p_2d_easy ) )
+ System.out.println( ERROR_TAG + "point notEqual to itself." );
+ else
+ System.out.println( "OK, result=" + p_2d_easy );
+
+ // 3-D constructor
+ System.out.print( PREFIX_TESTCASE + "3D easy to use constructor..." );
+ RasPoint p_3d_easy= new RasPoint( COORD_1, COORD_2, COORD_3 );
+ if (p_3d_easy== null)
+ System.out.println( ERROR_TAG + "result is null." );
+ else if (p_3d_easy.dimension() != 3)
+ System.out.println( ERROR_TAG + "dimension is not 3 but " + p_3d_easy.dimension() );
+ else if (p_3d_easy.item(2) != COORD_3)
+ System.out.println( ERROR_TAG + "item(2) returns wrong component " + p_3d_easy.item(0) );
+ else if (! p_3d_easy.equals( p_3d_easy) )
+ System.out.println( ERROR_TAG + "point not equal to itself." );
+ else if ( p_3d_easy.notEquals( p_3d_easy) )
+ System.out.println( ERROR_TAG + "point notEqual to itself." );
+ else
+ System.out.println( "OK, result=" + p_3d_easy);
+
+ // 4-D constructor
+ System.out.print( PREFIX_TESTCASE + "4D easy to use constructor..." );
+ RasPoint p_4d_easy = new RasPoint( COORD_1, COORD_2, COORD_3, COORD_4 );
+ if (p_4d_easy == null)
+ System.out.println( ERROR_TAG + "result is null." );
+ else if (p_4d_easy.dimension() != 4)
+ System.out.println( ERROR_TAG + "dimension is not 4 but " + p_4d_easy.dimension() );
+ else if (p_4d_easy.item(3) != COORD_4)
+ System.out.println( ERROR_TAG + "item(3) returns wrong component " + p_4d_easy.item(0) );
+ else if (! p_4d_easy.equals( p_4d_easy ) )
+ System.out.println( ERROR_TAG + "point not equal to itself." );
+ else if ( p_4d_easy.notEquals( p_4d_easy ) )
+ System.out.println( ERROR_TAG + "point notEqual to itself." );
+ else
+ System.out.println( "OK, result=" + p_4d_easy );
+
+ // 5-D constructor
+ System.out.print( PREFIX_TESTCASE + "5D easy to use constructor..." );
+ RasPoint p_5d_easy = new RasPoint( COORD_1, COORD_2, COORD_3, COORD_4, COORD_5 );
+ if (p_5d_easy == null)
+ System.out.println( ERROR_TAG + "result is null." );
+ else if (p_5d_easy.dimension() != 5)
+ System.out.println( ERROR_TAG + "dimension is not 5 but " + p_5d_easy.dimension() );
+ else if (p_5d_easy.item(4) != COORD_5)
+ System.out.println( ERROR_TAG + "item(4) returns wrong component " + p_5d_easy.item(0) );
+ else if (! p_5d_easy.equals( p_5d_easy ) )
+ System.out.println( ERROR_TAG + "point not equal to itself." );
+ else if ( p_5d_easy.notEquals( p_5d_easy ) )
+ System.out.println( ERROR_TAG + "point notEqual to itself." );
+ else
+ System.out.println( "OK, result=" + p_5d_easy );
+
+ // --- string constructor -------------------------------------------------------
+
+ // illegal string format
+ // FIXME: bug PB4
+ System.out.println( ERROR_TAG + "PB4: string constructor, illegal string formats." );
+
+ // System.out.print( PREFIX_TESTCASE + "string constructor, illegal string format (no [)..." );
+ // RasPoint p_si = new RasPoint( COORD_1 + "," + COORD_2 + "]" );
+ // System.out.println( "point is: " + p_si );
+ // if (! p_si.equals( new RasPoint( "[" + COORD_1 + "," + COORD_2 + "]" ) ) )
+ // System.out.println( ERROR_TAG + "wrong point value." );
+
+ // System.out.print( PREFIX_TESTCASE + "string constructor, illegal string format (no ])..." );
+ // p_si = new RasPoint( "[" + COORD_1 + "," + COORD_2 );
+ // System.out.println( "point is: " + p_si );
+ // if (! p_si.equals( new RasPoint( "[" + COORD_1 + "," + COORD_2 + "]" ) ) )
+ // System.out.println( ERROR_TAG + "wrong point value." );
+
+ // System.out.print( PREFIX_TESTCASE + "string constructor, illegal string format (no ,)..." );
+ // p_si = new RasPoint( "[" + COORD_1 + " " + COORD_2 + "]" );
+ // System.out.println( "point is: " + p_si );
+ // if (! p_si.equals( new RasPoint( "[" + COORD_1 + "," + COORD_2 + "]" ) ) )
+ // System.out.println( ERROR_TAG + "wrong point value." );
+
+ // System.out.print( PREFIX_TESTCASE + "string constructor, illegal string format (bad int)..." );
+ // p_si = new RasPoint( "[" + "abc" + "," + "xyz" + "]" );
+ // System.out.println( "point is: " + p_si );
+ // if (! p_si.equals( p_si ) )
+ // System.out.println( ERROR_TAG + "point not equal to itself." );
+
+ // System.out.print( PREFIX_TESTCASE + "string constructor, illegal string format (missing int)..." );
+ // p_si = new RasPoint( "[" + "," + "]" );
+ // System.out.println( "point is: " + p_si );
+ // if (! p_si.equals( p_si ) )
+ // System.out.println( ERROR_TAG + "point not equal to itself." );
+
+ // 2-D constructor
+ System.out.print( PREFIX_TESTCASE + "2D string constructor..." );
+ RasPoint p_2d = new RasPoint( "[" + COORD_1 + "," + COORD_2 + "]" );
+ if (p_2d == null)
+ System.out.println( ERROR_TAG + "result is null." );
+ else if (p_2d.dimension() != 2)
+ System.out.println( ERROR_TAG + "dimension is not 2 but " + p_2d.dimension() );
+ else if (p_2d.item(0) != COORD_1)
+ System.out.println( ERROR_TAG + "item(0) returns wrong component " + p_2d.item(0) );
+ else if (p_2d.item(1) != COORD_2)
+ System.out.println( ERROR_TAG + "item(1) returns wrong component " + p_2d.item(0) );
+ else if (! p_2d.equals( p_2d ) )
+ System.out.println( ERROR_TAG + "point not equal to itself." );
+ else if ( p_2d.notEquals( p_2d ) )
+ System.out.println( ERROR_TAG + "point notEqual to itself." );
+ else
+ System.out.println( "OK, result=" + p_2d );
+
+ // 3-D constructor
+ System.out.print( PREFIX_TESTCASE + "3D string constructor..." );
+ RasPoint p_3d = new RasPoint( "[" + COORD_1 + "," + COORD_2 + "," + COORD_3 + "]" );
+ if (p_3d == null)
+ System.out.println( ERROR_TAG + "result is null." );
+ else if (p_3d.dimension() != 3)
+ System.out.println( ERROR_TAG + "dimension is not 3 but " + p_3d.dimension() );
+ else if (p_3d.item(2) != COORD_3)
+ System.out.println( ERROR_TAG + "item(2) returns wrong component " + p_3d.item(0) );
+ else if (! p_3d.equals( p_3d ) )
+ System.out.println( ERROR_TAG + "point not equal to itself." );
+ else if ( p_3d.notEquals( p_3d ) )
+ System.out.println( ERROR_TAG + "point notEqual to itself." );
+ else
+ System.out.println( "OK, result=" + p_3d );
+
+ // 4-D constructor
+ System.out.print( PREFIX_TESTCASE + "4D string constructor..." );
+ RasPoint p_4d = new RasPoint( "[" + COORD_1 + "," + COORD_2 + "," + COORD_3 + "," + COORD_4 + "]" );
+ if (p_4d == null)
+ System.out.println( ERROR_TAG + "result is null." );
+ else if (p_4d.dimension() != 4)
+ System.out.println( ERROR_TAG + "dimension is not 4 but " + p_4d.dimension() );
+ else if (p_4d.item(3) != COORD_4)
+ System.out.println( ERROR_TAG + "item(3) returns wrong component " + p_4d.item(0) );
+ else if (! p_4d.equals( p_4d ) )
+ System.out.println( ERROR_TAG + "point not equal to itself." );
+ else if ( p_4d.notEquals( p_4d ) )
+ System.out.println( ERROR_TAG + "point notEqual to itself." );
+ else
+ System.out.println( "OK, result=" + p_4d );
+
+ // 5-D constructor
+ System.out.print( PREFIX_TESTCASE + "5D string constructor..." );
+ RasPoint p_5d = new RasPoint( "[" + COORD_1 + "," + COORD_2 + "," + COORD_3 + "," + COORD_4 + "," + COORD_5 + "]" );
+ if (p_5d == null)
+ System.out.println( ERROR_TAG + "result is null." );
+ else if (p_5d.dimension() != 5)
+ System.out.println( ERROR_TAG + "dimension is not 5 but " + p_5d.dimension() );
+ else if (p_5d.item(4) != COORD_5)
+ System.out.println( ERROR_TAG + "item(4) returns wrong component " + p_5d.item(0) );
+ else if (! p_5d.equals( p_5d ) )
+ System.out.println( ERROR_TAG + "point not equal to itself." );
+ else if ( p_5d.notEquals( p_5d ) )
+ System.out.println( ERROR_TAG + "point notEqual to itself." );
+ else
+ System.out.println( "OK, result=" + p_5d );
+
+ // copy constructor
+ System.out.print( PREFIX_TESTCASE + "copy constructor..." );
+ RasPoint p_cp = new RasPoint( p_2d );
+ if (p_cp == null)
+ System.out.println( ERROR_TAG + "result is null." );
+ else if (p_cp.dimension() != p_2d.dimension())
+ System.out.println( ERROR_TAG + "dimension mismatch." );
+ else if (p_cp.item(0) != p_2d.item(0))
+ System.out.println( ERROR_TAG + "item(0) returns wrong component " + p_cp.item(0) );
+ else if (p_cp.item(1) != p_2d.item(1))
+ System.out.println( ERROR_TAG + "item(1) returns wrong component " + p_cp.item(1) );
+ else if (! p_cp.equals( p_2d ) )
+ System.out.println( ERROR_TAG + "point not equal to origin." );
+ else if ( p_cp.notEquals( p_2d ) )
+ System.out.println( ERROR_TAG + "point notEqual to origin." );
+ else
+ System.out.println( "OK, result=" + p_cp );
+
+ System.out.println( PREFIX_TESTSET + "testing constructor done.\n" );
+ return;
+ } // testConstructor()
+
+ /**
+ * test Point addition -- TO BE DONE
+ * any eventual exception that is not caught here is an error, and will cause an abort
+ **/
+ static void testAdd() throws RasDimensionMismatchException, RasIndexOutOfBoundsException, RasStreamInputOverflowException
+ {
+ System.out.println( PREFIX_TESTSET + "testing add started." );
+
+ RasPoint p1 = new RasPoint(COORD_3,COORD_4);
+ RasPoint p2 = new RasPoint(COORD_3,COORD_4);
+ p2 = p2.add(p2);
+
+ // test if two points are equal
+ boolean b1 = false;
+ if(p2.comparedWith(p1) == 0)
+ b1 = p1.equals(p2);
+ else
+ b1 = false;
+ System.out.println("points are equal: " + b1);
+
+ // get the dimension of a Point
+ int i;
+ b1 = false;
+ if((p1.dimension() == 2) && (2 == p2.dimension()))
+ b1 = true;
+ System.out.println("dimensions of points are correct: " + b1);
+
+ b1 = false;
+ p2.setItem(1, 48);
+ if(p2.item(1) == 48)
+ b1 = true;
+ System.out.println("read and write access of points is OK: " + b1);
+
+ b1 = false;
+ p2.setTo(p2.mult(p1));
+ if(p2.equals(new RasPoint(443556, 42624)))
+ b1 = true;
+ System.out.println("mult and setTo is OK: " + b1);
+
+ b1 = false;
+ RasPoint ps = new RasPoint( 3 );
+ ps.stream( 42 );
+ if(ps.item(0) == 42)
+ b1 = true;
+ System.out.println("stream initializing of points is OK: " + b1);
+
+ System.out.println( PREFIX_TESTSET + "testing add done.\n" );
+ return;
+ } // testAdd()
+
+ } // TestRasPoint
diff --git a/java/rasj/test/count.sh b/java/rasj/test/count.sh
new file mode 100644
index 0000000..83b7ece
--- /dev/null
+++ b/java/rasj/test/count.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+
+awk < $1 '
+BEGIN { COUNT=0; MIN=1000; MAX=0; SMALL=0; LARGE=0;}
+ { COUNT++;
+ if ($6>1000) LARGE++; else SMALL++;
+ if ($6>MAX) MAX = $6;
+ if ($6<MIN) MIN = $6;
+ }
+END { printf("count=%d, small=%d, large=%d, min=%d, max=%d, percent=%f\n", COUNT, SMALL, LARGE, MIN, MAX, LARGE/COUNT*100 ); } '
diff --git a/java/rasj/test/httptest.java b/java/rasj/test/httptest.java
new file mode 100644
index 0000000..4754ec7
--- /dev/null
+++ b/java/rasj/test/httptest.java
@@ -0,0 +1,53 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+package rasj.test;
+
+import rasj.*;
+import rasj.clientcommhttp.*;
+
+public class httptest
+{
+
+ public static void main(String[] args)
+ {
+
+
+ System.err.println("Start ...");
+ RasHttpRequest test = new RasHttpRequest();
+ try
+ {
+ test.execute("http://maitai.akglocal.de:8080/","SELECT img[0:200,0:200] FROM lva AS img");
+ }
+ catch( RasQueryExecutionFailedException e)
+ {
+ System.err.println(e.getMessage());
+ }
+
+
+
+
+ }
+
+
+
+}
diff --git a/java/rasj/test/testEva.java b/java/rasj/test/testEva.java
new file mode 100644
index 0000000..907afd0
--- /dev/null
+++ b/java/rasj/test/testEva.java
@@ -0,0 +1,229 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+package rasj.test;
+
+import java.util.StringTokenizer;
+import java.lang.Integer;
+import java.lang.Long;
+import rasj.*;
+import rasj.odmg.*;
+
+public class testEva
+{
+
+ public static void main(String argv[]) throws RasException
+ {
+
+ // Points and Intervals
+ //////////////////////////////////////////////
+ // create a new RasPoint
+ RasPoint p1 = new RasPoint("[666, 777]");
+ RasPoint p2 = new RasPoint(5,4);
+
+ // test if two points are equal
+ boolean b1;
+ b1 = p1.equals(p2);
+
+ // get the dimension of a Point
+ int i;
+ i = p1.dimension();
+
+
+
+ // create a new RasSInterval
+ RasSInterval s1 = new RasSInterval(100,200);
+ RasSInterval s2 = new RasSInterval("150:400");
+
+ // get upper bound
+ long l1;
+ l1 = s2.high();
+
+ // test if lower bound is fixed
+ boolean b2;
+ b2 = s2.isLowFixed();
+
+ // test if interval intersects with another interval
+ // (the return value shows the kind of intersection)
+ int j;
+ j = s1.intersectsWith(s2);
+
+
+ // create new RasMInterval
+ RasMInterval m1 = new RasMInterval("[567:3253,666:777]");
+ RasMInterval m2 = new RasMInterval(4);
+
+ // get number of cells
+ long l2 = 1;
+ RasPoint m1Ext = m1.getExtent();
+ for (int dimi =0; dimi < m1Ext.dimension() ; dimi++)
+ {
+ l2 = l2 * m1Ext.item(dimi);
+ }
+
+ // Types
+ ///////////////////////////////////////////
+ String s = "marray <char, 1>";
+ RasType rType = RasType.getAnyType(s);
+ RasBaseType rb;
+
+ if(rType.getClass().getName().equals("rasj.RasMArrayType"))
+ {
+ RasMArrayType tmp = (RasMArrayType)rType;
+ rb = tmp.getBaseType();
+
+ System.out.println(rb);
+ }
+ else
+ System.out.println("element of MDD Collection is no MArray.");
+
+ boolean b3;
+ b3 = rType.isStructType();
+
+
+
+ // StorageLayout
+ ///////////////////////////////////////////
+ RasGMArray myMDD = new RasGMArray(new RasMInterval("[1:400,1:400]"),1);
+ byte[] mydata = new byte[160000];
+ for(int y=0; y<400; y++)
+ {
+ for(int x=0; x<400; x++)
+ {
+ if((x>99 && x<151) || (x>299 && x<351))
+ mydata[y*399+x]=100;
+ else
+ mydata[y*399+x]=0;
+ }
+ }
+
+ myMDD.setArray(mydata);
+ myMDD.setObjectTypeName("GreyImage");
+
+ RasStorageLayout myLayout = new RasStorageLayout();
+
+ myLayout.setTileSize(32);
+ // you can either set the TileSize or the TileDomain
+ myLayout.setTileDomain("[1:100,1:70]");
+ //myMDD.setStorageLayout();
+
+
+ i = p2.dimension();
+ b1 = p1.equals(p2);
+ //System.out.println(p1);
+ //p1.setTo(p1.mult(p2));
+
+ //sinterval//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ RasSInterval sint1 = new RasSInterval(100,200);
+ RasSInterval sint2 = new RasSInterval("150 :400 ");
+ RasSInterval sint3 = new RasSInterval("50:250");
+
+
+
+ sint1.setHigh(500);
+ sint1.setLow(400);
+ sint1.setLow('*');
+ sint1.setHigh('*');
+
+ sint1.setInterval('*',500);
+
+ l1 = sint1.low();
+ l2 = sint1.high();
+ b1 = sint1.isLowFixed();
+
+ i = sint1.intersectsWith(sint1);
+
+ //System.out.println(sint1);
+ //System.out.println(l1);
+ //System.out.println(l2);
+ //System.out.println(b1);
+ //System.out.println(i);
+
+ sint3 = sint3.unionOf(sint1, sint2);
+ sint3 = sint3.unionWith(sint2);
+ sint3 = sint3.addToSelf(sint2);
+ sint3 = sint3.createUnion(sint2);
+ sint3 = sint3.add(sint2);
+ //sint3 = sint3.differenceOf(sint2, sint1);
+ //sint3 = sint3.differenceWith(sint1);
+ sint3 = sint3.intersectionOf(sint2, sint1);
+ sint3 = sint3.intersectionWith(sint2);
+ sint3 = sint3.multWithSelf(sint2);
+ sint3 = sint3.createIntersection(sint2);
+ sint3 = sint3.mult(sint2);
+ sint3 = sint3.closureOf(sint2, sint1);
+ sint3 = sint3.closureWith(sint2);
+ sint3 = sint3.createClosure(sint2);
+
+ //Minterval//////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ RasMInterval mint1 = new RasMInterval("[567 :3253,666 :777]");
+ RasMInterval mint2 = new RasMInterval(4);
+
+ //GMarray////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ RasGMArray array1 = new RasGMArray();
+ RasGMArray array2 = new RasGMArray(mint1, 8);
+
+
+ byte[] bya = new byte[8];
+
+
+
+ l1 = 1;
+ RasPoint mint1Ext = mint1.getExtent();
+ for (int dimi =0; dimi < mint1Ext.dimension() ; dimi++)
+ {
+ l1 = l1 * mint1Ext.item(dimi);
+ }
+
+ array1.setTo(array2);
+ //bya = array2.getCell(p1);
+ array2.intersectionWith(mint1);
+
+
+ //Ausgabe////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ System.out.println("Array1 " + array1);
+ System.out.println("Array2 " + array2);
+
+
+
+ System.out.println("Punkt1 " + p1);
+ System.out.println("Punkt2 " + p2);
+
+ System.out.println("Sinterval1 " + s1);
+ System.out.println("Sinterval2 " + s2);
+ //System.out.println("Sinterval3 " + sint3);
+
+ System.out.println("Minterval1 " + m1);
+ System.out.println("Minterval2 " + m2);
+
+
+ System.out.println("i = " + i);
+ System.out.println("j = " + j);
+ System.out.println("b1 = " + b1);
+ System.out.println("b2 = " + b2);
+ System.out.println("b3 = " + b3);
+ System.out.println("l1 = " + l1);
+ System.out.println("l2 = " + l2);
+ //System.out.println(bya);
+
+ }
+}
diff --git a/java/rasj/test/testIntervals.java b/java/rasj/test/testIntervals.java
new file mode 100644
index 0000000..a06d980
--- /dev/null
+++ b/java/rasj/test/testIntervals.java
@@ -0,0 +1,326 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+package rasj.test;
+
+import java.util.StringTokenizer;
+import java.lang.Integer;
+import java.lang.Long;
+import rasj.*;
+import rasj.odmg.*;
+
+public class testIntervals
+{
+
+ public static void main(String argv[]) throws RasException
+ {
+ testIntervals intervalTest = new testIntervals();
+ }
+
+ public testIntervals()
+ {
+ try
+ {
+ // Points and Intervals
+ //////////////////////////////////////////////
+ System.out.println("\n############################ test points: ");
+ // create a new RasPoint
+ RasPoint p1 = new RasPoint("[666, 888]");
+ RasPoint p2 = new RasPoint(333,444);
+ p2 = p2.add(p2);
+
+ // test if two points are equal
+ boolean b1 = false;
+ if(p2.comparedWith(p1) == 0)
+ b1 = p1.equals(p2);
+ else
+ b1 = false;
+ System.out.println("points are equal: " + b1);
+
+ // get the dimension of a Point
+ int i;
+ b1 = false;
+ if((p1.dimension() == 2) && (2 == p2.dimension()))
+ b1 = true;
+ System.out.println("dimensions of points are correct: " + b1);
+
+ b1 = false;
+ p2.setItem(1, 48);
+ if(p2.item(1) == 48)
+ b1 = true;
+ System.out.println("read and write access of points is OK: " + b1);
+
+ b1 = false;
+ p2.setTo(p2.mult(p1));
+ if(p2.equals(new RasPoint(443556, 42624)))
+ b1 = true;
+ System.out.println("mult and setTo is OK: " + b1);
+
+ b1 = false;
+ p1.stream(3);
+ if(p1.item(0) == 3)
+ b1 = true;
+ System.out.println("stream initializing of points is OK: " + b1);
+
+
+ // create a new RasSInterval
+ System.out.println("\n############################ test sintervals: ");
+ RasSInterval s1 = new RasSInterval(100,200);
+ RasSInterval s2 = new RasSInterval("150:400");
+
+ // get upper bound
+ b1 = false;
+ if(s2.high() == 400)
+ b1 = true;
+ System.out.println("upper bound is correct: " + b1);
+
+ // test if lower bound is fixed
+ boolean b2;
+ b1 = false;
+ b1 = s2.isLowFixed();
+ System.out.println("lower bound is fix: " + b1);
+
+ // test if interval intersects with another interval
+ // (the return value shows the kind of intersection)
+ int j;
+ j = s1.intersectsWith(s2);
+ b1 = false;
+ if(j != -1)
+ b1 = true;
+ System.out.println("s1 intersects with s2: " + b1);
+
+ RasSInterval sint1 = new RasSInterval(100,200);
+ RasSInterval sint2 = new RasSInterval("150 :400 ");
+ RasSInterval sint3 = new RasSInterval("50:180");
+
+ b1 = false;
+ sint1.setHigh('*');
+ sint1.setLow(400);
+ if(sint1.low() == 400)
+ b1 = true;
+ sint1.setLow('*');
+ sint1.setHigh(500);
+ if((sint1.high() == 500) && b1)
+ b1 = true;
+ else
+ b1 = false;
+ System.out.println("setLow and setHigh are OK: " + b1);
+
+ sint1.setInterval('*',500);
+ b1 = !sint1.isLowFixed();
+ b1 = sint1.isHighFixed() && b1;
+ System.out.println("low is open high is fixed: " + b1);
+
+ b1 = false;
+ if(sint1.intersectsWith(sint1) != -1)
+ b1 = true;
+
+ if(sint3.closureOf(sint2, sint1).equals(sint1) &&
+ sint3.closureWith(sint2).equals(sint1) &&
+ sint3.createClosure(sint2).equals(sint1))
+ b1 = b1 && true;
+
+ sint1.setInterval(90, 105);
+ sint2.setInterval(100, 110);
+ if(sint2.createDifference(sint1).equals(new RasSInterval(90, 100)) &&
+ sint3.createIntersection(sint2).equals(new RasSInterval(100, 110)))
+ b1 = b1 && true;
+
+ if(sint3.createUnion(sint2).equals(sint1) &&
+ sint1.differenceOf(sint1, sint2).equals(new RasSInterval(90, 100)) &&
+ sint1.differenceWith(sint2).equals(new RasSInterval(100, 110)))
+ b1 = b1 && true;
+
+ if(sint3.intersectionOf(sint2, sint1).equals(new RasSInterval(100, 100)) &&
+ sint3.intersectionWith(sint2).equals(new RasSInterval(100, 100)))
+ b1 = b1 && true;
+
+ b1 = b1 && !sint3.equals(sint2);
+ if(sint3.unionOf(sint1, sint2).equals(new RasSInterval(90, 110)) &&
+ sint3.unionWith(sint2).equals(new RasSInterval(90, 110)))
+ b1 = b1 && true;
+ System.out.println("operations of sintervals are correct: " + b1);
+
+
+
+ // create new RasMInterval
+ System.out.println("\n############################ test mintervals: ");
+ RasMInterval mint1 = new RasMInterval("[567:3253,666:888]");
+ RasMInterval mint2 = new RasMInterval("[678:4000,777:999]");
+ RasMInterval mint3 = new RasMInterval("[777:900,888:1000]");
+ RasMInterval mint4 = new RasMInterval(2);
+ b1 = false;
+ if((mint2.dimension() == 2) && (mint1.dimension() == 2))
+ b1 = true;
+ System.out.println("dimensions of mintervals are correct: " + b1);
+
+ b1 = false;
+ mint1 = new RasMInterval("[500:3000,600:800]");
+ mint2 = new RasMInterval("[600:1000,700:750]");
+ b1 = mint1.intersectsWith(mint2);
+ mint1 = new RasMInterval("[567:3253,666:888]");
+ mint2 = new RasMInterval("[678:4000,777:999]");
+ if(mint3.closureOf(mint2, mint1).toString().equals(new RasMInterval("[567:4000,666:999]").toString()))
+ b1 = b1 && true;
+ else b1 = false;
+ if(mint3.closureWith(mint2).toString().equals(new RasMInterval("[567:4000,666:999]").toString()))
+ b1 = b1 && true;
+ else b1 = false;
+ if(mint3.createClosure(mint2).toString().equals(new RasMInterval("[567:4000,666:999]").toString()))
+ b1 = b1 && true;
+ else b1 = false;
+ mint3 = new RasMInterval("[678:2000,777:888]");
+ mint3 = mint3.createDifference(mint2);
+ if(mint3.toString().equals(new RasMInterval("[2000:4000,888:999]").toString()))
+ b1 = b1 && true;
+ else b1 = false;
+ mint3 = new RasMInterval("[678:2000,777:888]");
+ mint3 = mint3.createDifference(mint2);
+ if(mint3.toString().equals(new RasMInterval("[2000:4000,888:999]").toString()))
+ b1 = b1 && true;
+ else b1 = false;
+ mint3 = new RasMInterval("[678:2000,777:888]");
+ mint3 = mint3.createIntersection(mint2);
+ if(mint3.toString().equals(new RasMInterval("[678:2000,777:888]").toString()))
+ b1 = b1 && true;
+ else b1 = false;
+ mint3 = new RasMInterval("[678:2000,777:888]");
+ mint2 = new RasMInterval("[1000:4000,750:999]");
+ mint3 = mint3.createUnion(mint2);
+ if(mint3.toString().equals(new RasMInterval("[678:4000, 750:999]").toString()))
+ b1 = b1 && true;
+ else b1 = false;
+ mint2 = new RasMInterval("[1000:4000,800:999]");
+ mint1 = mint1.differenceOf(mint3, mint2);
+ if(mint1.toString().equals(new RasMInterval("[678:1000,750:800]").toString()))
+ b1 = b1 && true;
+ else b1 = false;
+ mint3 = mint3.intersectionOf(mint2, mint1);
+ if(mint3.toString().equals(new RasMInterval("[1000:1000,800:800]").toString()))
+ b1 = b1 && true;
+ else b1 = false;
+ mint3 = mint3.intersectionWith(mint2);
+ if(mint3.toString().equals(new RasMInterval("[1000:1000,800:800]").toString()))
+ b1 = b1 && true;
+ else b1 = false;
+ b1 = b1 && !mint3.equals(mint2);
+ mint3 = mint3.unionOf(mint1, mint2);
+ if(mint3.toString().equals(new RasMInterval("[678:4000,750:999]").toString()))
+ b1 = b1 && true;
+ else b1 = false;
+ mint3 = mint3.unionWith(mint2);
+ if(mint3.toString().equals(new RasMInterval("[678:4000,750:999]").toString()))
+ b1 = b1 && true;
+ else b1 = false;
+ mint2 = mint2.differenceWith(mint3);
+ if(mint2.toString().equals(new RasMInterval("[678:1000,750:800]").toString()))
+ b1 = b1 && true;
+ else b1 = false;
+ System.out.println("operations of mintervals are correct: " + b1);
+
+ // Types
+ ///////////////////////////////////////////
+ System.out.println("\n############################ test types: ");
+ String s = "marray <char, 1>";
+ RasType rType = RasType.getAnyType(s);
+ RasBaseType rb;
+
+ if(rType.getClass().getName().equals("rasj.RasMArrayType"))
+ {
+ RasMArrayType tmp = (RasMArrayType)rType;
+ rb = tmp.getBaseType();
+
+ System.out.println("OK");
+ }
+ else
+ System.out.println("element of MDD Collection is no MArray.");
+
+ boolean b3;
+ b3 = !rType.isStructType();
+ System.out.println(b3);
+
+
+ // StorageLayout
+ ///////////////////////////////////////////
+ System.out.println("\n############################ test storage layout: ");
+ RasGMArray myMDD = new RasGMArray(new RasMInterval("[1:400,1:400]"),1);
+ byte[] mydata = new byte[160000];
+ for(int y=0; y<400; y++)
+ {
+ for(int x=0; x<400; x++)
+ {
+ if((x>99 && x<151) || (x>299 && x<351))
+ mydata[y*399+x]=100;
+ else
+ mydata[y*399+x]=0;
+ }
+ }
+
+ myMDD.setArray(mydata);
+ myMDD.setObjectTypeName("GreyImage");
+
+ RasStorageLayout myLayout = new RasStorageLayout();
+
+ myLayout.setTileDomain("[1:100,1:70]");
+ // you can either set the TileSize or the TileDomain
+ myLayout.setTileSize(32);
+ myMDD.setStorageLayout(myLayout);
+ if(myMDD.getStorageLayout().getTileSize() == 32)
+ System.out.println("OK");
+
+
+ //GMarray////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ RasGMArray array1 = new RasGMArray();
+ RasGMArray array2 = new RasGMArray(mint1, 8);
+
+ myMDD.getCell(new RasPoint(1,1));
+
+ System.out.println("OK");
+
+
+ //Ausgabe////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ /*
+ System.out.println("Array1 " + array1);
+ System.out.println("Array2 " + array2);
+
+ System.out.println("Punkt1 " + p1);
+ System.out.println("Punkt2 " + p2);
+
+ System.out.println("Sinterval1 " + s1);
+ System.out.println("Sinterval2 " + s2);
+ System.out.println("Sinterval3 " + sint3);
+
+ System.out.println("j = " + j);
+ //System.out.println("b1 = " + b1);
+ //System.out.println("b2 = " + b2);
+ System.out.println("b3 = " + b3);
+ */
+
+
+ }
+ catch (RasException e)
+ {
+ System.out.println("!!!!!!!!!!!!!!!!!!!!While testing!!!!!!!!!!!!!!!!!!");
+ System.out.println("An RasException has occurred: " + e.getMessage());
+ }
+ }
+}
diff --git a/java/rasj/test/testMArrays.java b/java/rasj/test/testMArrays.java
new file mode 100644
index 0000000..272ece1
--- /dev/null
+++ b/java/rasj/test/testMArrays.java
@@ -0,0 +1,871 @@
+package rasj.test;
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/** ***********************************************************
+ * <pre>
+ *
+ * PURPOSE: class for testing special MArrays
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ * </pre>
+ *********************************************************** */
+
+import java.io.*;
+import java.net.*;
+import rasj.clientcommhttp.*;
+import rasj.odmg.*;
+import org.odmg.*;
+import rasj.*;
+import java.util.*;
+
+/**
+ * class for testing special MArrays
+ * for testing please enable test data output in toString method of RASGMArray
+ * @version $$
+ */
+public class testMArrays
+{
+ public static void main(String[] args)
+ {
+ String serv = "localhost";
+ String base = "RASBASE";
+ String coll = "test";
+
+ for (int i=args.length-1; i>=0; i--)
+ {
+ //System.out.println(args[i]);
+ if (args[i].equals("-server"))
+ serv = args[i+1];
+ if (args[i].equals("-database"))
+ base = args[i+1];
+ if (args[i].equals("-collection"))
+ coll = args[i+1];
+ }
+ //System.out.println(server+base+coll);
+ testMArrays marrayTest = new testMArrays(serv);
+
+ }
+
+ public testMArrays(String server)
+ {
+ DBag resultBag = null;
+ Object result = null;
+ Transaction myTa = null;
+ Database myDb = null;
+ OQLQuery myQu = null;
+
+ boolean equal = false;
+
+ try
+ {
+ System.out.println("### Testing MArrays: ...");
+ Implementation myApp = new RasImplementation("http://"+server+":7001");
+ myDb = myApp.newDatabase();
+
+ System.out.println("Opening database ...");
+ myDb.open("RASBASE", Database.OPEN_READ_WRITE);
+ myTa = myApp.newTransaction();
+
+ int width, height, len;
+ width = 18;
+ height = 18;
+ len = (width+1)*(height+1);
+ RasMInterval domain = new RasMInterval("[0:"+width+",0:"+height+"]");
+ RasMInterval domain2 = new RasMInterval("[1:3,1:3]");
+ RasStorageLayout stl = new RasStorageLayout();
+ stl.setTileSize(128);
+
+
+ /**
+ * test the GMArray
+ */
+ System.out.println("\n\n### Testing GMArray with OID: ################################################");
+ myQu = myApp.newOQLQuery();
+
+ myQu.create("drop collection test");
+ myTa.begin();
+ try
+ {
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("collection dropped");
+ }
+ catch(ODMGException e)
+ {
+ myTa.abort();
+ System.err.println("Collection test does not exist: " + e.getMessage());
+ }
+
+ myQu.create("create collection test GreySet");
+ RasGMArray mddConst = new RasGMArray(domain, 1, stl);
+ //RasGMArray mddConst = new RasGMArray(domain, 1);
+ byte[] data = new byte[len];
+ mddConst.setObjectTypeName("GreyImage");
+
+ // test: get new OID from the server for GMArray and insert
+ System.out.println("new OID from server: " + myApp.getObjectId(mddConst));
+
+ for(int j = 0; j < data.length; j++)
+ data[j] = (byte)j;
+
+ mddConst.setArray(data);
+ /*
+ System.out.println("\nbyte array: ");
+ for(int j=0; j<mddConst.getArray().length; j++)
+ {
+ System.out.print(" "+ mddConst.getArray()[j]);
+ }
+ */
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("\ncollection created");
+ myQu.create("insert into test values $1 ");
+
+ //System.out.println("mdd before sending: " + mddConst);
+ myQu.bind(mddConst);
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("collection inserted");
+
+ myQu = myApp.newOQLQuery();
+ myQu.create("select img from test as img");
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("collection selected");
+ if (resultBag != null)
+ {
+ Iterator iter = resultBag.iterator();
+ while (iter.hasNext())
+ {
+ result = iter.next();
+ equal = true;
+ for(int j=0; j<mddConst.getArray().length; j++)
+ {
+ if(mddConst.getArray()[j] != ((RasGMArray)result).getArray()[j])
+ equal = false;
+ }
+ if(!(myApp.getObjectId(mddConst).toString()).equals(myApp.getObjectId((RasGMArray)result).toString()))
+ equal = false;
+ System.out.println("result mdd: " + ((RasGMArray)mddConst).toTestString());
+ System.out.println("result mdd: " + ((RasGMArray)result).toTestString());
+ }
+ System.out.println("inserted and selected GMArray and OIDs are equal: " + equal);
+ //System.out.println("All results for test GMArray");
+ }
+
+
+ // testing copy constructor
+ System.out.println("### Testing copy constructor:");
+ RasGMArray mddConst2 = new RasGMArray(mddConst);
+ mddConst2.setArray(data);
+ //System.out.println("\nbyte array2: ");
+ data = null;
+ equal = true;
+ for(int j=0; j<mddConst.getArray().length; j++)
+ {
+ //System.out.print(" "+ mddConst2.getArray()[j]);
+ if(mddConst.getArray()[j] != mddConst2.getArray()[j])
+ equal = false;
+ }
+ System.out.println("Copy constructor is OK: " + equal);
+
+ /**
+ * test the MArrayByte
+ */
+ System.out.println("\n\n### Testing MArrayByte: ################################################");
+ myQu = myApp.newOQLQuery();
+
+ myQu.create("drop collection test");
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("collection dropped");
+
+ myQu.create("create collection test GreySet");
+ RasMArrayByte mddByte = new RasMArrayByte(domain, stl);
+ byte[] dataByte = new byte[len];
+ mddByte.setObjectTypeName("GreyImage");
+
+ for(int j = 0; j < dataByte.length; j++)
+ dataByte[j] = (byte)j;
+
+ mddByte.setArray(dataByte);
+
+ //System.out.println("\nbyte array: ");
+ //for(int j=0; j<mddByte.getArray().length; j++)
+ //{
+ //System.out.print(" "+ mddByte.getArray()[j]);
+ //}
+
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("\ncollection created");
+ myQu.create("insert into test values $1 ");
+
+ //System.out.println("mdd before sending: " + mddByte);
+ myQu.bind(mddByte);
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("collection inserted");
+
+ myQu = myApp.newOQLQuery();
+ myQu.create("select img from test as img");
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("collection selected");
+ if (resultBag != null)
+ {
+ Iterator iter = resultBag.iterator();
+ while (iter.hasNext())
+ {
+ result = iter.next();
+ System.out.println("result mdd: " + ((RasGMArray)mddByte).toTestString());
+ System.out.println("result mdd: " + ((RasGMArray)result).toTestString());
+ equal = true;
+ for(int j=0; j<mddByte.getArray().length; j++)
+ {
+ if(mddByte.getArray()[j] != ((RasGMArray)result).getArray()[j])
+ equal = false;
+ }
+ }
+ //System.out.println("All results for MArrayByte");
+ System.out.println("inserted and selected MArrayByte are equal: " + equal);
+ }
+
+ // testing copy constructor
+ System.out.println("### Testing copy constructor:");
+ RasMArrayByte mddByte2 = new RasMArrayByte(mddByte);
+ mddByte2.setArray(dataByte);
+ //System.out.println("\nbyte array2: ");
+ dataByte = null;
+ equal = true;
+ for(int j=0; j<mddByte.getArray().length; j++)
+ {
+ //System.out.print(" "+ mddByte2.getArray()[j]);
+ if(mddByte.getArray()[j] != mddByte2.getArray()[j])
+ equal = false;
+ }
+ System.out.println("Copy constructor is OK: " + equal);
+
+ /**
+ * test the MArrayInteger
+ */
+ System.out.println("\n\n### Testing MArrayInteger: ################################################");
+ myQu = myApp.newOQLQuery();
+
+ myQu.create("drop collection test");
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("collection dropped");
+
+ myQu.create("create collection test UShortSet");
+ RasMArrayInteger mddInteger = new RasMArrayInteger(domain, stl);
+ int[] dataInteger = new int[len];
+ //byte[] dataInteger = new byte[144];
+ mddInteger.setObjectTypeName("UShortImage");
+
+ for(int j = 0; j < dataInteger.length; j++)
+ dataInteger[j] = j;
+
+ mddInteger.setArray(dataInteger);
+
+ //System.out.println("\nbyte array: ");
+ //for(int j=0; j<mddInteger.getArray().length; j++)
+ //{
+ //System.out.print(" "+ mddInteger.getArray()[j]);
+ //}
+
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("\ncollection created");
+ myQu.create("insert into test values $1 ");
+
+ //System.out.println("mdd before sending: " + mddInteger);
+ myQu.bind(mddInteger);
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("collection inserted");
+
+ myQu = myApp.newOQLQuery();
+ myQu.create("select img from test as img");
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("collection selected");
+ if (resultBag != null)
+ {
+ Iterator iter = resultBag.iterator();
+ while (iter.hasNext())
+ {
+ result = iter.next();
+ System.out.println("result mdd: " + ((RasGMArray)mddInteger).toTestString());
+ System.out.println("result mdd: " + ((RasGMArray)result).toTestString());
+ equal = true;
+ for(int j=0; j<mddInteger.getArray().length; j++)
+ {
+ if(mddInteger.getArray()[j] != ((RasGMArray)result).getArray()[j])
+ equal = false;
+ }
+ }
+ //System.out.println("All results for MArrayInteger");
+ System.out.println("inserted and selected MArrayInteger are equal: " + equal);
+ }
+
+ // testing copy constructor
+ System.out.println("### Testing copy constructor:");
+ RasMArrayInteger mddInteger2 = new RasMArrayInteger(mddInteger);
+ mddInteger2.setArray(dataInteger);
+ dataInteger = null;
+ equal = true;
+ for(int j=0; j<mddInteger2.getArray().length; j++)
+ {
+ //System.out.print(" "+ mddInteger2.getArray()[j]);
+ if(mddInteger.getArray()[j] != mddInteger2.getArray()[j])
+ equal = false;
+ }
+ System.out.println("Copy constructor is OK: " + equal);
+
+ /*
+ System.out.println("\nspecial array2: ");
+ for(int j=0; j<mddInteger2.getIntArray().length; j++)
+ {
+ System.out.print(" "+ mddInteger2.getIntArray()[j]);
+ }
+ */
+
+ /**
+ * test the MArrayDouble
+ */
+ System.out.println("\n\n### Testing MArrayDouble: ################################################");
+ myQu = myApp.newOQLQuery();
+
+ myQu.create("drop collection test");
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("collection dropped");
+
+ myQu.create("create collection test DoubleSet");
+ RasMArrayDouble mddDouble = new RasMArrayDouble(domain, stl);
+ double[] dataDouble = new double[len];
+ //byte[] dataDouble = new byte[288];
+ mddDouble.setObjectTypeName("DoubleImage");
+
+ for(double j = 0; j < dataDouble.length; j++)
+ dataDouble[(int)j] = j;
+
+ mddDouble.setArray(dataDouble);
+
+ //System.out.println("\nbyte array: ");
+ //for(int j=0; j<mddDouble.getArray().length; j++)
+ //{
+ //System.out.print(" "+ mddDouble.getArray()[j]);
+ //}
+
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("\ncollection created");
+ myQu.create("insert into test values $1 ");
+
+ //System.out.println("mdd before sending: " + mddDouble);
+ myQu.bind(mddDouble);
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("collection inserted");
+
+ myQu = myApp.newOQLQuery();
+ myQu.create("select img from test as img");
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("collection selected");
+ if (resultBag != null)
+ {
+ Iterator iter = resultBag.iterator();
+ while (iter.hasNext())
+ {
+ result = iter.next();
+ equal = true;
+ for(int j=0; j<mddDouble.getDoubleArray().length; j++)
+ {
+ if(mddDouble.getArray()[j] != ((RasGMArray)result).getArray()[j])
+ equal = false;
+ }
+ System.out.println("result mdd: " + ((RasGMArray)mddDouble).toTestString());
+ System.out.println("result mdd: " + ((RasGMArray)result).toTestString());
+ }
+ //System.out.println("All results for MArrayDouble");
+ System.out.println("inserted and selected MArrayDouble are equal: " + equal);
+ }
+
+
+ // testing copy constructor
+ System.out.println("### Testing copy constructor:");
+ RasMArrayDouble mddDouble2 = new RasMArrayDouble(mddDouble);
+ mddDouble2.setArray(dataDouble);
+ //System.out.println("byte array2: ");
+ dataDouble = null;
+ equal = true;
+ for(int j=0; j<mddDouble2.getArray().length; j++)
+ {
+ //System.out.print(" "+ mddDouble2.getArray()[j]);
+ if(mddDouble.getArray()[j] != mddDouble2.getArray()[j])
+ equal = false;
+ }
+ System.out.println("Copy constructor is OK: " + equal);
+
+ /*
+ System.out.println("\nspecial array2: ");
+ for(int j=0; j<mddDouble2.getDoubleArray().length; j++)
+ {
+ System.out.print(" "+ mddDouble2.getDoubleArray()[j]);
+ }
+ */
+
+ /**
+ * test the MArrayFloat
+ */
+ System.out.println("\n\n### Testing MArrayFloat: ################################################");
+ myQu = myApp.newOQLQuery();
+
+ myQu.create("drop collection test");
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("collection dropped");
+
+ myQu.create("create collection test FloatSet");
+ RasMArrayFloat mddFloat = new RasMArrayFloat(domain, stl);
+ float[] dataFloat = new float[len];
+ //byte[] dataFloat = new byte[144];
+ mddFloat.setObjectTypeName("FloatImage");
+
+ for(float j = 0; j < dataFloat.length; j++)
+ dataFloat[(int)j] = j;
+
+ mddFloat.setArray(dataFloat);
+
+ //System.out.println("\nbyte array: ");
+ //for(int j=0; j<mddFloat.getArray().length; j++)
+ //{
+ //System.out.print(" "+ mddFloat.getArray()[j]);
+ //}
+
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("\ncollection created");
+ myQu.create("insert into test values $1 ");
+
+ //System.out.println("mdd before sending: " + mddFloat);
+ myQu.bind(mddFloat);
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("collection inserted");
+
+ myQu = myApp.newOQLQuery();
+ myQu.create("select img from test as img");
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("collection selected");
+ if (resultBag != null)
+ {
+ Iterator iter = resultBag.iterator();
+ while (iter.hasNext())
+ {
+ result = iter.next();
+ equal = true;
+ for(int j=0; j<mddFloat.getArray().length; j++)
+ {
+ if(mddFloat.getArray()[j] != ((RasGMArray)result).getArray()[j])
+ equal = false;
+ }
+ System.out.println("result mdd: " + ((RasGMArray)mddFloat).toTestString());
+ System.out.println("result mdd: " + ((RasGMArray)result).toTestString());
+ }
+ //System.out.println("All results for MArrayFloat");
+ System.out.println("inserted and selected MArrayFloat are equal: " + equal);
+ }
+
+ // testing copy constructor
+ System.out.println("### Testing copy constructor:");
+ RasMArrayFloat mddFloat2 = new RasMArrayFloat(mddFloat);
+ mddFloat2.setArray(dataFloat);
+ //System.out.println("\nbyte array2: ");
+ dataFloat = null;
+ equal = true;
+ for(int j=0; j<mddFloat2.getArray().length; j++)
+ {
+ //System.out.print(" "+ mddFloat2.getArray()[j]);
+ if(mddFloat.getArray()[j] != mddFloat2.getArray()[j])
+ equal = false;
+ }
+ System.out.println("Copy constructor is OK: " + equal);
+ /*
+ System.out.println("\nspecial array2: ");
+ for(int j=0; j<mddFloat2.getFloatArray().length; j++)
+ {
+ System.out.print(" "+ mddFloat2.getFloatArray()[j]);
+ }
+ */
+
+ /**
+ * test the MArrayShort
+ */
+ System.out.println("\n\n### Testing MArrayShort: ################################################");
+ myQu = myApp.newOQLQuery();
+
+ myQu.create("drop collection test");
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("collection dropped");
+
+ myQu.create("create collection test ShortSet");
+ RasMArrayShort mddShort = new RasMArrayShort(domain, stl);
+ //RasMArrayShort mddShort4 = new RasMArrayShort(domain, stl);
+ //RasMArrayShort mddShort3 = new RasMArrayShort(domain, stl);
+ short[] dataShort = new short[len];
+ //short[] dataShort4 = new short[len];
+ //short[] dataShort3 = new short[len];
+ //byte[] dataShort = new byte[72];
+ mddShort.setObjectTypeName("ShortImage");
+ //mddShort4.setObjectTypeName("ShortImage");
+ //mddShort3.setObjectTypeName("ShortImage");
+
+ //System.out.println("new OID from server: " + myApp.getObjectId(mddShort));
+ //System.out.println("new OID from server: " + myApp.getObjectId(mddShort4));
+ for(int j = 0; j < dataShort.length; j++)
+ dataShort[j] = (short)j;
+
+ //for(int j = 0; j < dataShort.length; j++)
+ //dataShort[j] = 1;
+ //for(int j = 0; j < dataShort4.length; j++)
+ //dataShort4[j] = 2;
+ //for(int j = 0; j < dataShort3.length; j++)
+ //dataShort3[j] = 3;
+
+
+ mddShort.setArray(dataShort);
+ //mddShort4.setArray(dataShort4);
+ //mddShort3.setArray(dataShort3);
+ /*
+ System.out.println("\nbyte array: ");
+ for(int j=0; j<mddShort.getArray().length; j++)
+ {
+ System.out.print(" "+ mddShort.getArray()[j]);
+ }
+ */
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ myQu = myApp.newOQLQuery();
+ //System.out.println("\ncollection created");
+ //myQu.create("insert into test values $1");
+ myQu.create("insert into test values $1");
+ //System.out.println("mdd before sending: " + mddShort);
+ //myQu.bind("test");
+ myQu.bind(mddShort);
+ //myQu.bind(mddShort4);
+ //myQu.bind(mddShort3);
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ /*
+ myTa.begin();
+ myQu = myApp.newOQLQuery();
+ myQu.create("insert into test values $1");
+ myQu.bind(mddShort4);
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ myTa.begin();
+ myQu = myApp.newOQLQuery();
+ myQu.create("insert into test values $1");
+ myQu.bind(mddShort3);
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ */
+ //System.out.println("collection inserted");
+ myQu = myApp.newOQLQuery();
+ myQu.create("select img from test as img");
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("collection selected");
+ if (resultBag != null)
+ {
+ Iterator iter = resultBag.iterator();
+ while (iter.hasNext())
+ {
+ result = iter.next();
+ equal = true;
+ for(int j=0; j<mddShort.getArray().length; j++)
+ {
+ if(mddShort.getArray()[j] != ((RasGMArray)result).getArray()[j])
+ equal = false;
+ }
+ System.out.println("result mdd: " + ((RasGMArray)mddShort).toTestString());
+ System.out.println("result mdd: " + ((RasGMArray)result).toTestString());
+ }
+ //System.out.println("All results for MArrayShort");
+ System.out.println("inserted and selected MArrayShort are equal: " + equal);
+ }
+
+ // testing copy constructor
+ System.out.println("### Testing copy constructor:");
+ RasMArrayShort mddShort2 = new RasMArrayShort(mddShort);
+ mddShort2.setArray(dataShort);
+ //System.out.println("\nbyte array2: ");
+ dataShort = null;
+ equal = true;
+ for(int j=0; j<mddShort2.getArray().length; j++)
+ {
+ //System.out.print(" "+ mddShort2.getArray()[j]);
+ if(mddShort.getArray()[j] != mddShort2.getArray()[j])
+ equal = false;
+ }
+ System.out.println("Copy constructor is OK: " + equal);
+ /*
+ System.out.println("\nspecial array2: ");
+ for(int j=0; j<mddShort2.getShortArray().length; j++)
+ {
+ System.out.print(" "+ mddShort2.getShortArray()[j]);
+ }
+ */
+
+ /**
+ * test the MArrayLong
+ */
+ System.out.println("\n\n### Testing MArrayLong: ################################################");
+ myQu = myApp.newOQLQuery();
+
+ myQu.create("drop collection test");
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("collection dropped");
+
+ myQu.create("create collection test ULongSet");
+ RasMArrayLong mddLong = new RasMArrayLong(domain, stl);
+ long[] dataLong = new long[len];
+ //byte[] dataLong = new byte[288];
+ mddLong.setObjectTypeName("ULongImage");
+
+ for(long j = 0; j < dataLong.length; j++)
+ dataLong[(int)j] = j;
+ mddLong.setArray(dataLong);
+
+ /*
+ System.out.println("\nbyte array: ");
+ for(int j=0; j<mddLong.getArray().length; j++)
+ {
+ System.out.print(" "+ mddLong.getArray()[j]);
+ }
+ */
+
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("\ncollection created");
+ myQu.create("insert into test values $1 ");
+
+ //System.out.println("mdd before sending: " + mddLong);
+ myQu.bind(mddLong);
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("collection inserted");
+
+ myQu = myApp.newOQLQuery();
+ myQu.create("select img from test as img");
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ //System.out.println("collection selected");
+ if (resultBag != null)
+ {
+ Iterator iter = resultBag.iterator();
+ while (iter.hasNext())
+ {
+ result = iter.next();
+ equal = true;
+ for(int j=0; j<((RasGMArray)result).getArray().length; j++)
+ {
+ if(mddLong.getArray()[j] != ((RasGMArray)result).getArray()[j])
+ equal = false;
+ }
+ System.out.println("result mdd: " + ((RasGMArray)mddLong).toTestString());
+ System.out.println("result mdd: " + ((RasGMArray)result).toTestString());
+ }
+ //System.out.println("All results for MArrayLong");
+ System.out.println("inserted MArrayInteger and selected MArrayLong are equal: " + equal);
+ }
+
+ // testing copy constructor
+ System.out.println("### Testing copy constructor:");
+ RasMArrayLong mddLong2 = new RasMArrayLong(mddLong);
+ mddLong2.setArray(dataLong);
+ //System.out.println("\nbyte array2: ");
+ dataLong = null;
+ equal = true;
+ for(int j=0; j<mddLong2.getArray().length; j++)
+ {
+ //System.out.print(" "+ mddLong2.getArray()[j]);
+ if(mddLong.getArray()[j] != mddLong2.getArray()[j])
+ equal = false;
+ }
+ System.out.println("Copy constructor is OK: " + equal);
+
+ System.out.println("\nspecial array: ");
+ for(int j=0; j<((RasMArrayLong)result).getLongArray().length; j++)
+ {
+ System.out.print(" "+ ((RasMArrayLong)result).getLongArray()[j]);
+ }
+
+
+ /**
+ * testing intersection
+ */
+ System.out.println("\n\n### Testing intersection:");
+ mddConst2.intersectionWith(domain2);
+ mddByte2.intersectionWith(domain2);
+ mddDouble2.intersectionWith(domain2);
+ mddFloat2.intersectionWith(domain2);
+ mddInteger2.intersectionWith(domain2);
+ mddLong2.intersectionWith(domain2);
+ mddShort2.intersectionWith(domain2);
+ System.out.println("OK\n");
+
+ /**
+ * testing OIDs
+ */
+ myQu = myApp.newOQLQuery();
+ myQu.create("SELECT oid(img) FROM test AS img");
+ //myQu.create("SELECT img FROM test AS img where (oid(img)=231425)");
+ myTa.begin();
+ resultBag = (DBag)myQu.execute();
+ myTa.commit();
+ if (resultBag != null)
+ {
+ Iterator iter = resultBag.iterator();
+ while (iter.hasNext())
+ {
+ result = iter.next();
+ //System.out.println("OID: " + result);
+ }
+ //System.out.println("All results");
+
+ }
+
+ /**
+ * get new OID
+ */
+ System.out.println("### Testing OIDs:");
+ myTa.begin();
+ myApp.getObjectId(new RasGMArray());
+ myTa.commit();
+
+ System.out.println( "Closing database ..." );
+ myDb.close();
+
+ // get new OID without open TA
+ RasGMArray gmar = new RasGMArray();
+ equal = true;
+ if(!myApp.getObjectId(gmar).equals(gmar.getOID().toString()))
+ equal = false;
+ System.out.println("same OID on client and server side: " + equal);
+
+ }
+ catch (RasException e)
+ {
+ System.out.println("!!!!!!!!!!!!!!!!!!!!While testing!!!!!!!!!!!!!!!!!!");
+ System.out.println("An RasException has occurred: " + e.getMessage());
+ System.out.println("Try to abort the transaction ...");
+ if(myTa != null) myTa.abort();
+
+ try
+ {
+ System.out.println("Try to close the database ...");
+ if(myDb != null) myDb.close();
+ }
+ catch ( org.odmg.ODMGException exp )
+ {
+ System.err.println("Could not close the database: " + exp.getMessage());
+ }
+ }
+ catch (RasRuntimeException e)
+ {
+ System.out.println("!!!!!!!!!!!!!!!!!!!!While testing!!!!!!!!!!!!!!!!!!");
+ System.out.println("An RasRuntimeException has occurred: " + e.getMessage());
+ System.out.println("Try to abort the transaction ...");
+ if(myTa != null) myTa.abort();
+
+ try
+ {
+ System.out.println("Try to close the database ...");
+ if(myDb != null) myDb.close();
+ }
+ catch ( org.odmg.ODMGException exp )
+ {
+ System.err.println("Could not close the database: " + exp.getMessage());
+ }
+ }
+ catch (org.odmg.ODMGException e)
+ {
+ System.out.println("!!!!!!!!!!!!!!!!!!!!While testing!!!!!!!!!!!!!!!!!!");
+ System.out.println("An ODMGException has occurred: " + e.getMessage());
+ System.out.println("Try to abort the transaction ...");
+ if(myTa != null) myTa.abort();
+
+ try
+ {
+ System.out.println("Try to close the database ...");
+ if(myDb != null) myDb.close();
+ }
+ catch ( org.odmg.ODMGException exp )
+ {
+ System.err.println("Could not close the database: " + exp.getMessage());
+ }
+ }
+ System.out.println( "Done." );
+
+ }
+}
+
diff --git a/m4/ac_prog_ecpg.m4 b/m4/ac_prog_ecpg.m4
new file mode 100644
index 0000000..b1025a9
--- /dev/null
+++ b/m4/ac_prog_ecpg.m4
@@ -0,0 +1,30 @@
+dnl @synopsis AC_PROG_ECPG
+dnl
+dnl Finds e precompiler for PostgreSQL embedded code.
+dnl
+dnl @category PostgreSQL
+dnl @author Sorin Stancu-Mara <smsorin@gmail.com>
+dnl @version 2009-02-22
+dnl @license GPLWithACException
+
+AC_DEFUN([AC_PROG_ECPG],
+[
+ AC_ARG_WITH([ecpg],
+ [AS_HELP_STRING([--with-ecpg=PATH],
+ [path to ecpg])],
+ [
+ ECPG="$withval"
+ ],
+ [with_ecpg=check])
+ if test "x$with_ecpg" = xcheck; then
+ AC_PATH_PROG([ECPG], [ecpg], [])
+ fi
+
+ if test ! -x "$ECPG"; then
+ AC_MSG_ERROR([Unable to find ecpg or it's an executable file.])
+ fi
+
+ AC_SUBST([ECPG])
+
+])
+
diff --git a/m4/ac_prog_java_cc.m4 b/m4/ac_prog_java_cc.m4
new file mode 100644
index 0000000..66c44b1
--- /dev/null
+++ b/m4/ac_prog_java_cc.m4
@@ -0,0 +1,68 @@
+dnl @synopsis AC_PROG_JAVA_CC
+dnl
+dnl Finds the appropriate java compiler on your path. By preference the
+dnl java compiler is gcj, then jikes then javac.
+dnl
+dnl The macro can take one argument specifying a space separated list
+dnl of java compiler names.
+dnl
+dnl For example:
+dnl
+dnl AC_PROG_JAVA_CC(javac, gcj)
+dnl
+dnl The macro also sets the compiler options variable: JAVA_CC_OPTS to
+dnl something sensible:
+dnl
+dnl - for GCJ it sets it to: @GCJ_OPTS@
+dnl (if GCJ_OPTS is not yet defined then it is set to "-C")
+dnl
+dnl - no other compiler has applicable options yet
+dnl
+dnl Here's an example configure.in:
+dnl
+dnl AC_INIT(Makefile.in)
+dnl AC_PROG_JAVA_CC()
+dnl AC_OUTPUT(Makefile)
+dnl dnl End.
+dnl
+dnl And here's the start of the Makefile.in:
+dnl
+dnl PROJECT_ROOT := @srcdir@
+dnl # Tool definitions.
+dnl JAVAC := @JAVA_CC@
+dnl JAVAC_OPTS := @JAVA_CC_OPTS@
+dnl JAR_TOOL := @jar_tool@
+dnl
+dnl @category Java
+dnl @author Nic Ferrier <nferrier@tapsellferrier.co.uk>
+dnl @version 2002-03-04
+dnl @license GPLWithACException
+
+# AC_PROG_JAVA_CC([COMPILER ...])
+# --------------------------
+# COMPILER ... is a space separated list of java compilers to search for.
+# This just gives the user an opportunity to specify an alternative
+# search list for the java compiler.
+AC_DEFUN([AC_PROG_JAVA_CC],
+[AC_ARG_VAR([JAVA_CC], [java compiler command])dnl
+AC_ARG_VAR([JAVA_CC_FLAGS], [java compiler flags])dnl
+m4_ifval([$1],
+ [AC_CHECK_TOOLS(JAVA_CC, [$1])],
+[AC_CHECK_TOOL(JAVA_CC, gcj)
+if test -z "$JAVA_CC"; then
+ AC_CHECK_TOOL(JAVA_CC, javac)
+fi
+if test -z "$JAVA_CC"; then
+ AC_CHECK_TOOL(JAVA_CC, jikes)
+fi
+])
+GCJ="$JAVA_CC"
+if test "$JAVA_CC" = "gcj"; then
+ if test "$GCJ_OPTS" = ""; then
+ AC_SUBST(GCJ_OPTS,-C)
+ fi
+ AC_SUBST(JAVA_CC_OPTS, @GCJ_OPTS@,
+ [Define the compilation options for GCJ])
+fi
+test -z "$JAVA_CC" && AC_MSG_ERROR([no acceptable java compiler found in \$PATH])
+])# AC_PROG_JAVA_CC
diff --git a/m4/ac_prog_rpcgen.m4 b/m4/ac_prog_rpcgen.m4
new file mode 100644
index 0000000..852044f
--- /dev/null
+++ b/m4/ac_prog_rpcgen.m4
@@ -0,0 +1,30 @@
+dnl @synopsis AC_PROG_RPCGEN
+dnl
+dnl Finds a RPC compiler
+dnl
+dnl @category RPC Networking
+dnl @author Sorin Stancu-Mara <smsorin@gmail.com>
+dnl @version 2009-02-22
+dnl @license GPLWithACException
+
+AC_DEFUN([AC_PROG_RPCGEN],
+[
+ AC_ARG_WITH([rpcgen],
+ [AS_HELP_STRING([--with-rpcgen=PATH],
+ [path to rpcgen])],
+ [
+ RPCGEN="$withval"
+ ],
+ [with_rpcgen=check])
+ if test "x$with_rpcgen" = xcheck; then
+ AC_PATH_PROG([RPCGEN], [rpcgen], [])
+ fi
+
+ if test ! -x "$RPCGEN"; then
+ AC_MSG_ERROR([Unable to find rpcgen or it's an executable file.])
+ fi
+
+ AC_SUBST([RPCGEN])
+
+])
+
diff --git a/m4/ac_prog_sed.m4 b/m4/ac_prog_sed.m4
new file mode 100644
index 0000000..69253cc
--- /dev/null
+++ b/m4/ac_prog_sed.m4
@@ -0,0 +1,30 @@
+dnl @synopsis AC_PROG_SED
+dnl
+dnl Finds a sed editor
+dnl
+dnl @category editors
+dnl @author Sorin Stancu-Mara <smsorin@gmail.com>
+dnl @version 2009-02-22
+dnl @license GPLWithACException
+
+AC_DEFUN([AC_PROG_SED],
+[
+ AC_ARG_WITH([sed],
+ [AS_HELP_STRING([--with-sed=PATH],
+ [path to sed])],
+ [
+ SED="$withval"
+ ],
+ [with_sed=check])
+ if test "x$with_sed" = xcheck; then
+ AC_PATH_PROG([SED], [sed], [])
+ fi
+
+ if test ! -x "$SED"; then
+ AC_MSG_ERROR([Unable to find sed or it's an executable file.])
+ fi
+
+ AC_SUBST([SED])
+
+])
+
diff --git a/m4/ax_lib_postgresql.m4 b/m4/ax_lib_postgresql.m4
new file mode 100644
index 0000000..b51134e
--- /dev/null
+++ b/m4/ax_lib_postgresql.m4
@@ -0,0 +1,155 @@
+# ===========================================================================
+# http://autoconf-archive.cryp.to/ax_lib_postgresql.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_LIB_POSTGRESQL([MINIMUM-VERSION])
+#
+# DESCRIPTION
+#
+# This macro provides tests of availability of PostgreSQL 'libpq' library
+# of particular version or newer.
+#
+# AX_LIB_POSTGRESQL macro takes only one argument which is optional. If
+# there is no required version passed, then macro does not run version
+# test.
+#
+# The --with-postgresql option takes one of three possible values:
+#
+# no - do not check for PostgreSQL client library
+#
+# yes - do check for PostgreSQL library in standard locations (pg_config
+# should be in the PATH)
+#
+# path - complete path to pg_config utility, use this option if pg_config
+# can't be found in the PATH
+#
+# This macro calls:
+#
+# AC_SUBST(POSTGRESQL_CFLAGS)
+# AC_SUBST(POSTGRESQL_LDFLAGS)
+# AC_SUBST(POSTGRESQL_VERSION)
+#
+# And sets:
+#
+# HAVE_POSTGRESQL
+#
+# LAST MODIFICATION
+#
+# 2008-04-12
+#
+# COPYLEFT
+#
+# Copyright (c) 2008 Mateusz Loskot <mateusz@loskot.net>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved.
+
+AC_DEFUN([AX_LIB_POSTGRESQL],
+[
+ AC_ARG_WITH([postgresql],
+ AC_HELP_STRING([--with-postgresql=@<:@ARG@:>@],
+ [use PostgreSQL library @<:@default=yes@:>@, optionally specify path to pg_config]
+ ),
+ [
+ if test "$withval" = "no"; then
+ want_postgresql="no"
+ elif test "$withval" = "yes"; then
+ want_postgresql="yes"
+ else
+ want_postgresql="yes"
+ PG_CONFIG="$withval"
+ fi
+ ],
+ [want_postgresql="yes"]
+ )
+
+ POSTGRESQL_CFLAGS=""
+ POSTGRESQL_LDFLAGS=""
+ POSTGRESQL_VERSION=""
+
+ dnl
+ dnl Check PostgreSQL libraries (libpq)
+ dnl
+
+ if test "$want_postgresql" = "yes"; then
+
+ if test -z "$PG_CONFIG" -o test; then
+ AC_PATH_PROG([PG_CONFIG], [pg_config], [])
+ fi
+
+ if test ! -x "$PG_CONFIG"; then
+ AC_MSG_ERROR([$PG_CONFIG does not exist or it is not an exectuable file])
+ PG_CONFIG="no"
+ found_postgresql="no"
+ fi
+
+ if test "$PG_CONFIG" != "no"; then
+ AC_MSG_CHECKING([for PostgreSQL libraries])
+ POSTGRESQL_CFLAGS="-I`$PG_CONFIG --includedir`"
+ POSTGRESQL_LDFLAGS="-L`$PG_CONFIG --libdir` -lpq"
+
+ POSTGRESQL_VERSION=`$PG_CONFIG --version | sed -e 's#PostgreSQL ##'`
+
+ AC_DEFINE([HAVE_POSTGRESQL], [1],
+ [Define to 1 if PostgreSQL libraries are available])
+
+ found_postgresql="yes"
+ AC_MSG_RESULT([yes])
+ else
+ found_postgresql="no"
+ AC_MSG_RESULT([no])
+ fi
+ fi
+
+ dnl
+ dnl Check if required version of PostgreSQL is available
+ dnl
+
+
+ postgresql_version_req=ifelse([$1], [], [], [$1])
+
+ if test "$found_postgresql" = "yes" -a -n "$postgresql_version_req"; then
+
+ AC_MSG_CHECKING([if PostgreSQL version is >= $postgresql_version_req])
+
+ dnl Decompose required version string of PostgreSQL
+ dnl and calculate its number representation
+ postgresql_version_req_major=`expr $postgresql_version_req : '\([[0-9]]*\)'`
+ postgresql_version_req_minor=`expr $postgresql_version_req : '[[0-9]]*\.\([[0-9]]*\)'`
+ postgresql_version_req_micro=`expr $postgresql_version_req : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'`
+ if test "x$postgresql_version_req_micro" = "x"; then
+ postgresql_version_req_micro="0"
+ fi
+
+ postgresql_version_req_number=`expr $postgresql_version_req_major \* 1000000 \
+ \+ $postgresql_version_req_minor \* 1000 \
+ \+ $postgresql_version_req_micro`
+
+ dnl Decompose version string of installed PostgreSQL
+ dnl and calculate its number representation
+ postgresql_version_major=`expr $POSTGRESQL_VERSION : '\([[0-9]]*\)'`
+ postgresql_version_minor=`expr $POSTGRESQL_VERSION : '[[0-9]]*\.\([[0-9]]*\)'`
+ postgresql_version_micro=`expr $POSTGRESQL_VERSION : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'`
+ if test "x$postgresql_version_micro" = "x"; then
+ postgresql_version_micro="0"
+ fi
+
+ postgresql_version_number=`expr $postgresql_version_major \* 1000000 \
+ \+ $postgresql_version_minor \* 1000 \
+ \+ $postgresql_version_micro`
+
+ postgresql_version_check=`expr $postgresql_version_number \>\= $postgresql_version_req_number`
+ if test "$postgresql_version_check" = "1"; then
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ fi
+ fi
+
+ AC_SUBST([POSTGRESQL_VERSION])
+ AC_SUBST([POSTGRESQL_CFLAGS])
+ AC_SUBST([POSTGRESQL_LDFLAGS])
+])
diff --git a/m4/ax_lib_rasdaman.m4 b/m4/ax_lib_rasdaman.m4
new file mode 100644
index 0000000..f16be78
--- /dev/null
+++ b/m4/ax_lib_rasdaman.m4
@@ -0,0 +1,151 @@
+dnl @synopsis AX_LIB_RASDAMAN([Action-if-found, [Action-if-not-fonund]])
+dnl
+dnl Checks if the necessary libraries and headers are available in order
+dnl to compile a program that uses raslib.
+dnl
+dnl @author Sorin Stancu-Mara <smsorin@gmail.com>
+dnl @version 2009-03-16
+dnl @licence GPLWithACException
+
+AC_DEFUN([AX_LIB_RASDAMAN],
+[
+ dnl prerequisites
+ dnl ****************
+ raslib_requirements_ok="yes"
+ raslib_missing=""
+ AC_CHECK_LIB([crypto], [EVP_DigestInit],
+ [
+ LIBS="-lcrypto $LIBS"
+ AC_DEFINE([HAVE_LIBCRYPTO])
+ ],
+ [
+ raslib_requirements_ok="no"
+ raslib_missing="$raslib_missing libcrypto"
+ ])
+ AC_CHECK_LIB([tiff], [TIFFClientOpen],
+ [
+ LIBS="-ltiff $LIBS"
+ AC_DEFINE([HAVE_LIBTIFF])
+ ],
+ [
+ raslib_requirements_ok="no"
+ raslib_missing="$raslib_missing libtiff"
+ ])
+ AC_CHECK_LIB([mfhdf], [SDstart],
+ [
+ LIBS="-lmfhdf $LIBS"
+ AC_DEFINE([HAVE_LIBHDF])
+ ],
+ [
+ raslib_requirements_ok="no"
+ raslib_missing="$raslib_missing libmfhdf"
+ ])
+ AC_CHECK_LIB([png], [png_set_read_fn],
+ [
+ LIBS="-lpng $LIBS"
+ AC_DEFINE([HAVE_LIBHDF])
+ ],
+ [
+ raslib_requirements_ok="no"
+ raslib_missing="$raslib_missing libpng"
+ ])
+ if test "$raslib_requirements_ok" = "no"; then
+ AC_MSG_NOTICE([rasdaman prerequisites not met. You need to install$raslib_missing.])
+ { echo -n; $2 }
+ else
+ AC_LANG_PUSH([C++])
+ AC_ARG_WITH([rasdaman],
+ [AS_HELP_STRING([--with-rasdaman=PATH],
+ [path to rasdaman directory hint])],
+ [HINT_RASLIB="$withval"])
+
+ raslib_found="no"
+ raslib_headers_found="no"
+ dnl find the headers
+ dnl ************
+ raslib_save_CPPFLAGS="$CPPFLAGS"
+ if test "x$HINT_RASLIB" != "x"; then
+ CPPFLAGS="$CPPFLAGS -I$HINT_RASLIB/include -I$HINT_RASLIB"
+ fi
+ AC_CHECK_HEADERS([rasdaman.hh],
+ [raslib_headers_found="yes"])
+ dnl find raslib
+ dnl *************
+ if test "$raslib_headers_found" = "yes"; then
+ CPPFLAGS="$CPPFLAGS -DDEBUG -DDEBUG_MAIN -DEARLY_TEMPLATE -D__EXECUTABLE__"
+ raslib_save_LIBS="$LIBS"
+ raslib_save_LDFLAGS="$LDFLAGS"
+ LIBS="-lclientcomm -lrasodmg -lcompression -lconversion -lclientcomm -lrasodmg -lraslib -lnetwork $LIBS"
+ AC_MSG_CHECKING([raslib])
+ AC_TRY_LINK([
+ #include "rasdaman.hh"
+ #include "raslib/template_inst.hh"
+ #include "debug/debug.hh"
+ ],
+ [
+ r_Database database;
+ database.open("");
+ ],
+ [raslib_found="yes"])
+ if test "$raslib_found" = "yes"; then
+ AC_MSG_RESULT([yes])
+ fi
+ if test "$raslib_found" = "no"; then
+ dnl Not in the default path.
+ dnl Take the hint and assume it's an install directory
+ dnl This means the libs are under lib
+ LDFLAGS="$LDFLAGS -L$HINT_RASLIB/lib"
+ AC_TRY_LINK([
+ #include "rasdaman.hh"
+ #include "raslib/template_inst.hh"
+ #include "debug/debug.hh"
+ ],
+ [
+ r_Database database;
+ database.open("");
+ ],
+ [raslib_found="yes"])
+ if test "$raslib_found" = "yes"; then
+ AC_MSG_RESULT([$HINT_RASLIB/lib])
+ fi
+ fi
+ if test "$raslib_found" = "no"; then
+ dnl Maybe the directory is a dev directory
+ LDFLAGS="$raslib_save_LDFLAGS -L$HINT_RASLIB/clientcomm"
+ LDFLAGS="$LDFLAGS -L$HINT_RASLIB/rasodmg -L$HINT_RASLIB/compression"
+ LDFLAGS="$LDFLAGS -L$HINT_RASLIB/conversion -L$HINT_RASLIB/clientcomm"
+ LDFLAGS="$LDFLAGS -L$HINT_RASLIB/raslib -L$HINT_RASLIB/network"
+ AC_TRY_LINK([
+ #include "rasdaman.hh"
+ #include "raslib/template_inst.hh"
+ #include "debug/debug.hh"
+ ],
+ [
+ r_Database database;
+ database.open("");
+ ],
+ [raslib_found="yes"])
+ if test "$raslib_found" = "yes"; then
+ AC_MSG_RESULT([$HINT_RASLIB])
+ fi
+ fi
+ if test "$raslib_found" = "no"; then
+ AC_MSG_RESULT([no])
+ fi
+ fi
+
+ if test "$raslib_found" = "no"; then
+ dnl We can't find raslib... restore everything
+ LDFLAGS="$raslib_save_LDFLAGS"
+ LIBS="$raslib_save_LIBS"
+ CXXCPPFLAGS="$raslib_save_CXXCPPFLAGS"
+ dnl Run user give commands
+ { echo -n ; $2 }
+ else
+ dnl Run user given commands
+ { echo -n ; $1 }
+ fi
+
+ AC_LANG_POP
+ fi dnl raslib_requirements_ok = no
+])
diff --git a/m4/ct_check_postgres_db.m4 b/m4/ct_check_postgres_db.m4
new file mode 100644
index 0000000..6e2b7d6
--- /dev/null
+++ b/m4/ct_check_postgres_db.m4
@@ -0,0 +1,74 @@
+dnl @synopsis CT_CHECK_POSTGRES_DB
+dnl
+dnl This macro tries to find the headers and librarys for the
+dnl PostgreSQL database to build client applications.
+dnl
+dnl If includes are found, the variable PQINCPATH will be set. If
+dnl librarys are found, the variable PQLIBPATH will be set. if no check
+dnl was successful, the script exits with a error message.
+dnl
+dnl @category InstalledPackages
+dnl @author Christian Toepp <c.toepp@gmail.com>
+dnl @version 2005-12-30
+dnl @license AllPermissive
+
+AC_DEFUN([CT_CHECK_POSTGRES_DB], [
+
+AC_ARG_WITH(pgsql,
+ [ --with-pgsql=PREFIX Prefix of your PostgreSQL installation],
+ [pg_prefix=$withval], [pg_prefix=])
+AC_ARG_WITH(pgsql-inc,
+ [ --with-pgsql-inc=PATH Path to the include directory of PostgreSQL],
+ [pg_inc=$withval], [pg_inc=])
+AC_ARG_WITH(pgsql-lib,
+ [ --with-pgsql-lib=PATH Path to the librarys of PostgreSQL],
+ [pg_lib=$withval], [pg_lib=])
+
+
+AC_SUBST(PQINCPATH)
+AC_SUBST(PQLIBPATH)
+
+if test "$pg_prefix" != ""; then
+ AC_MSG_CHECKING([for PostgreSQL includes in $pg_prefix/include])
+ if test -f "$pg_prefix/include/libpq-fe.h" ; then
+ PQINCPATH="-I$pg_prefix/include"
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_ERROR(libpq-fe.h not found)
+ fi
+ AC_MSG_CHECKING([for PostgreSQL librarys in $pg_prefix/lib])
+ if test -f "$pg_prefix/lib/libpq.so" ; then
+ PQLIBPATH="-L$pg_prefix/lib"
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_ERROR(libpq.so not found)
+ fi
+else
+ if test "$pg_inc" != ""; then
+ AC_MSG_CHECKING([for PostgreSQL includes in $pg_inc])
+ if test -f "$pg_inc/libpq-fe.h" ; then
+ PQINCPATH="-I$pg_inc"
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_ERROR(libpq-fe.h not found)
+ fi
+ fi
+ if test "$pg_lib" != ""; then
+ AC_MSG_CHECKING([for PostgreSQL librarys in $pg_lib])
+ if test -f "$pg_lib/libpq.so" ; then
+ PQLIBPATH="-L$pg_lib"
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_ERROR(libpq.so not found)
+ fi
+ fi
+fi
+
+if test "$PQINCPATH" = "" ; then
+ AC_CHECK_HEADER([postgresql/libpq-fe.h], [], AC_MSG_ERROR(libpq-fe.h not found))
+fi
+if test "$PQLIBPATH" = "" ; then
+ AC_CHECK_LIB(pq, PQconnectdb, [], AC_MSG_ERROR(libpq.so not found))
+fi
+
+])
diff --git a/manuals_and_examples/Makefile.am b/manuals_and_examples/Makefile.am
new file mode 100644
index 0000000..016e27f
--- /dev/null
+++ b/manuals_and_examples/Makefile.am
@@ -0,0 +1,28 @@
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+####################################################################
+
+nobase_dist_pkgdata_DATA=examples/images/* examples/c++/* \
+ examples/java/* examples/queries/* \
+ examples/rasdl/basictypes.dl
+
+
diff --git a/manuals_and_examples/examples/c++/Makefile b/manuals_and_examples/examples/c++/Makefile
new file mode 100644
index 0000000..3a23dd1
--- /dev/null
+++ b/manuals_and_examples/examples/c++/Makefile
@@ -0,0 +1,165 @@
+# -*-Makefile-*-
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>. # Top Level makefile. This points to the various modules that have to be build
+# and/or deployed
+#
+# MAKEFILE FOR:
+# Compile and link example C++ programs;
+# right now, works only with GNU Make!
+#
+#
+##################################################################
+
+
+######################### Definitions ############################
+
+# choose C++ compiler
+ifeq ($(OSTYPE),linux)
+OSTYPE=linux-gnu
+endif
+ifeq ($(OSTYPE),Linux)
+OSTYPE=linux-gnu
+endif
+
+ifneq ($(OSTYPE),linux-gnu)
+endif
+ifneq ($(OSTYPE),linux-gnu)
+CXX = CC
+else
+CXX = g++
+endif
+
+# RasDaMan central includes
+CXXFLAGS = -I$(RMANHOME)/include
+
+ifeq ($(OSTYPE),solaris)
+
+ CXXFLAGS += -DSOLARIS
+
+ # enable exception handling
+ # exceptions are supported by default
+
+ # use ANSI C
+ # is used by default
+
+else
+ifeq ($(OSTYPE),linux-gnu)
+
+ CXXFLAGS += -DLINUX -DEARLY_TEMPLATE
+
+ # enable exception handling
+ # exceptions are supported by default
+
+ # use ANSI C
+ # is used by default
+
+else
+
+ CXXFLAGS += -DHPUX
+
+ # enable exception handling
+ CXXFLAGS += +eh
+
+ # use ANSI C
+ CXXFLAGS += +a1
+
+ # necessary for templates because of bug in nm
+ CXXFLAGS += -ptb
+
+endif
+endif
+
+ifeq ($(OSTYPE),solaris)
+ LDFLAGS += -lmalloc -lsocket -lnsl
+endif
+
+# add communication flags
+CXXFLAGS += -DONCRPC
+
+# pre-installed exchange format libraries needed
+FMTLIBS = /usr/lib/libnetpbm.a /usr/lib/libjpeg.a /usr/local/lib/libpng.a /usr/local/lib/libtiff.a
+
+# libraries needed for linkage (in particular: rasdaman + exchange formats)
+LIBS += -L/usr/lib -L$(RMANHOME)/lib \
+ -lclientcomm -lrasodmg -lcompression -lconversion -lclientcomm -lrasodmg -lraslib \
+ -lppm -lpgm -lnetpbm -ljpeg -lpng -ltiff -lmfhdf -ldf -lcrypto \
+ -lm -lz
+
+
+########################### Targets ##############################
+
+# this global target first checks for required libraries
+# disable target 'check' if you don't want this to be run
+all: check avg-cell avg-cell-red lookup query insertppm
+
+# check whether exchange format libraries have been installed
+.PHONY: check
+check:
+ @for lib in $(FMTLIBS); \
+ do \
+ if [[ ! -f $$lib ]]; \
+ then \
+ echo "error: cannot find required library $$lib - package not installed?"; \
+ fi \
+ done
+
+avg-cell: avg-cell.o
+ $(CXX) $(LDFLAGS) -o $@ $^ $(LIBS)
+
+avg-cell-red: avg-cell-red.o
+ $(CXX) $(LDFLAGS) -o $@ $^ $(LIBS)
+
+lookup: lookup.o
+ $(CXX) $(LDFLAGS) -o $@ $^ $(LIBS)
+
+query: query.o
+ $(CXX) $(LDFLAGS) -o $@ $^ $(LIBS)
+
+insertppm: insertppm.o
+ $(CXX) $(LDFLAGS) -o $@ $^ $(LIBS)
+
+.PHONY : clean
+clean:
+ -rm *.o *.log *.dbg *.bm
+ -rm query insertppm lookup avg-cell avg-cell-red
+ifeq ($(OSTYPE),solaris)
+ cd $(RMANHOME)/include/rasodmg/ptrepository; ptclean
+else
+ifneq ($(OSTYPE),linux-gnu)
+ -rm -R $(RMANHOME)/include/rasodmg/ptrepository/*
+endif
+endif
+
+######################## Dependencies ############################
+
+avg-cell.o: avg-cell.cc
+
+avg-cell-red.o: avg-cell-red.cc
+
+lookup.o: lookup.cc
+
+query.o: query.cc
+
+insertppm.o: insertppm.cc
+ $(CXX) $(CXXFLAGS) -c insertppm.cc -I/usr/X11R6/include
+
+# end of Makefile
diff --git a/manuals_and_examples/examples/c++/avg-cell-red.cc b/manuals_and_examples/examples/c++/avg-cell-red.cc
new file mode 100644
index 0000000..4896a83
--- /dev/null
+++ b/manuals_and_examples/examples/c++/avg-cell-red.cc
@@ -0,0 +1,144 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * Example program for computing the avg cell value
+ * for each image in a given 2-D RGB collection.
+ *
+ *
+ ************************************************************/
+
+#include <iostream>
+
+// Linux needs this for template instantiation
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#ifdef __GNUG__
+#include "raslib/template_inst.hh"
+#endif
+#endif
+
+
+// rasdl generated data type file:
+// (contains predefined RGB pixel structure)
+#include "basictypes.hh"
+
+
+int main( int ac, char** av )
+{
+ char rasmgrName[255];
+ int rasmgrPort;
+ char baseName[255];
+ char collName[255];
+ char userName[255];
+ char userPass[255];
+
+ double sum;
+
+ if( ac != 7 )
+ {
+ cout << "Usage: avg-cell-red rasmgr_name rasmgr_port base_name collection_name user_name user_passwd" << endl;
+ return -1;
+ }
+
+ strcpy( rasmgrName, av[1] );
+ rasmgrPort = strtoul( av[2], NULL, 0);
+ strcpy( baseName, av[3] );
+ strcpy( collName, av[4] );
+ strcpy( userName, av[5] );
+ strcpy( userPass, av[6] );
+
+ r_Database database;
+ r_Transaction transaction;
+ r_Ref< r_Set< r_Ref< r_Marray< RGBPixel > > > > image_set;
+ r_Iterator< r_Ref< r_Marray< RGBPixel > > > iter;
+ r_Ref< r_Marray< RGBPixel > > image;
+ r_Range i,j;
+ long pixelcount;
+
+ try
+ {
+ database.set_servername( rasmgrName, rasmgrPort );
+ database.set_useridentification( userName, userPass );
+
+ cout << "Opening database " << baseName
+ << " on " << rasmgrName << "... " << flush;
+ database.open( baseName );
+ cout << "OK" << endl;
+
+ cout << "Starting read-only transaction ... " << flush;
+ transaction.begin( r_Transaction::read_only );
+ cout << "OK" << endl;
+
+ cout << "Looking up collection " << collName << " ..." << flush;
+ image_set = database.lookup_object( collName );
+ cout << "OK" << endl;
+
+ cout << "Collection contains " << image_set->cardinality()
+ << " entries" << endl;
+
+ iter = image_set->create_iterator();
+ for( iter.reset(); iter.not_done(); iter++ )
+ {
+ RGBPixel pixel;
+ image = *iter;
+ sum = 0.0;
+ for ( i=image->spatial_domain()[0].low(); i<=image->spatial_domain()[0].high(); i++ )
+ {
+ for ( j=image->spatial_domain()[1].low(); j<=image->spatial_domain()[1].high(); j++ )
+ {
+ pixel = (*image)[ r_Point(i,j) ];
+ sum += pixel.red;
+ }
+ }
+ pixelcount =
+ ( image->spatial_domain()[0].high() - image->spatial_domain()[0].low() + 1 )
+ * ( image->spatial_domain()[1].high() - image->spatial_domain()[1].low() + 1 );
+ cout << " avg over " << pixelcount
+ << " red pixels is "
+ << sum / pixelcount
+ << endl << flush;
+ }
+
+ cout << "Committing transaction ... " << flush;
+ transaction.commit();
+ cout << "OK" << endl;
+
+ cout << "Closing database ... " << flush;
+ database.close();
+ cout << "OK" << endl;
+ }
+ catch( r_Error& errorObj )
+ {
+ cerr << errorObj.what() << endl;
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * end of avg-cell-red.cc
+ */
diff --git a/manuals_and_examples/examples/c++/avg-cell.cc b/manuals_and_examples/examples/c++/avg-cell.cc
new file mode 100644
index 0000000..c0012e1
--- /dev/null
+++ b/manuals_and_examples/examples/c++/avg-cell.cc
@@ -0,0 +1,136 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * Example program for computing the avg cell value
+ * for each n-D 8-bit grey image in a given collection.
+ *
+ *
+ ************************************************************/
+
+#include <iostream>
+
+// Linux needs this for template instantiation
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#ifdef __GNUG__
+#include "raslib/template_inst.hh"
+#endif
+#endif
+
+// rasdl generated data type file:
+// (contains predefined RGBPixel structure)
+#include "basictypes.hh"
+
+
+int main( int ac, char** av )
+{
+ char rasmgrName[255];
+ int rasmgrPort;
+ char baseName[255];
+ char collName[255];
+ char userName[255];
+ char userPass[255];
+ r_Base_Type *celltype;
+ double sum;
+
+ if( ac != 7 )
+ {
+ cout << "Usage: avg-cell rasmgr_name rasmgr_port base_name collection_name user_name user_passwd" << endl;
+ return -1;
+ }
+
+ strcpy( rasmgrName, av[1] );
+ rasmgrPort = strtoul( av[2], NULL, 0);
+ strcpy( baseName, av[3] );
+ strcpy( collName, av[4] );
+ strcpy( userName, av[5] );
+ strcpy( userPass, av[6] );
+
+ r_Database database;
+ r_Transaction transaction;
+ r_Ref< r_Set< r_Ref< r_Marray< RGBPixel > > > > image_set;
+ r_Iterator< r_Ref< r_Marray< RGBPixel > > > iter;
+ r_Ref< r_Marray< RGBPixel > > image;
+ r_Range i;
+
+ try
+ {
+ database.set_servername( rasmgrName, rasmgrPort );
+ database.set_useridentification( userName, userPass );
+
+ cout << "Opening database " << baseName
+ << " on " << rasmgrName << "... " << flush;
+ database.open( baseName );
+ cout << "OK" << endl;
+
+ cout << "Starting read-only transaction ... " << flush;
+ transaction.begin( r_Transaction::read_only );
+ cout << "OK" << endl;
+
+ cout << "Looking up collection " << collName << " ..." << flush;
+ image_set = database.lookup_object( collName );
+ cout << "OK" << endl;
+
+ cout << "Collection contains " << image_set->cardinality()
+ << " entries" << endl;
+
+ iter = image_set->create_iterator();
+ for( iter.reset(); iter.not_done(); iter++ )
+ {
+ image = *iter;
+ if ( image->get_type_length() != 1 )
+ cout << "skipping image because of non-int cell type" << endl;
+ else
+ {
+ unsigned char *pixelfield = (unsigned char*) image->get_array();
+ sum = 0.0;
+ for ( i=0; i < image->get_array_size(); i++ )
+ sum += pixelfield[i];
+ cout << " avg over " << image->get_array_size()
+ << " pixels is " << sum/image->get_array_size() << endl;
+ }
+ }
+
+ cout << "Committing transaction ... " << flush;
+ transaction.commit();
+ cout << "OK" << endl;
+
+ cout << "Closing database ... " << flush;
+ database.close();
+ cout << "OK" << endl;
+ }
+ catch( r_Error& errorObj )
+ {
+ cerr << errorObj.what() << endl;
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * end of avg-cell.cc
+ */
diff --git a/manuals_and_examples/examples/c++/basictypes.hh b/manuals_and_examples/examples/c++/basictypes.hh
new file mode 100644
index 0000000..adbda31
--- /dev/null
+++ b/manuals_and_examples/examples/c++/basictypes.hh
@@ -0,0 +1,206 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+//------------------------------------------------------------
+// This file is created automatically by the rasdl processor.
+//
+// DO NOT EDIT
+//------------------------------------------------------------
+
+#ifndef __BASICTYPES_HH_
+#define __BASICTYPES_HH_
+
+//------------------------------------------------------------
+// Includes
+//------------------------------------------------------------
+
+#include "rasdaman.hh"
+
+/*[2,25]*//* TYPEDEF ------------------------- GreyImage */
+typedef r_Marray<r_Char> GreyImage;
+
+/*[3,24]*//* TYPEDEF ------------------------- GreySet */
+typedef r_Set<r_Ref<GreyImage> > GreySet;
+
+/*[6,28]*//* TYPEDEF ------------------------- BoolImage */
+typedef r_Marray<r_Boolean> BoolImage;
+
+/*[7,24]*//* TYPEDEF ------------------------- BoolSet */
+typedef r_Set<r_Ref<BoolImage> > BoolSet;
+
+/*[10,1]*//* STRUCT -------------------------- RGBPixel */
+struct RGBPixel {
+ r_Char red;
+ r_Char green;
+ r_Char blue;
+};
+/*[11,29]*//* TYPEDEF ------------------------- RGBImage */
+typedef r_Marray<RGBPixel> RGBImage;
+
+/*[12,23]*//* TYPEDEF ------------------------- RGBSet */
+typedef r_Set<r_Ref<RGBImage> > RGBSet;
+
+/*[15,35]*//* TYPEDEF ------------------------- ULongImage */
+typedef r_Marray<r_ULong > ULongImage;
+
+/*[16,25]*//* TYPEDEF ------------------------- ULongSet */
+typedef r_Set<r_Ref<ULongImage> > ULongSet;
+
+/*[19,26]*//* TYPEDEF ------------------------- GreyCube */
+typedef r_Marray<r_Char> GreyCube;
+
+/*[20,23]*//* TYPEDEF ------------------------- GreySet3 */
+typedef r_Set<r_Ref<GreyCube> > GreySet3;
+
+/*[24,29]*//* TYPEDEF ------------------------- BoolString */
+typedef r_Marray<r_Boolean> BoolString;
+
+/*[25,25]*//* TYPEDEF ------------------------- BoolSet1 */
+typedef r_Set<r_Ref<BoolString> > BoolSet1;
+
+/*[27,29]*//* TYPEDEF ------------------------- BoolCube */
+typedef r_Marray<r_Boolean> BoolCube;
+
+/*[28,23]*//* TYPEDEF ------------------------- BoolSet3 */
+typedef r_Set<r_Ref<BoolCube> > BoolSet3;
+
+/*[30,26]*//* TYPEDEF ------------------------- GreyString */
+typedef r_Marray<r_Char> GreyString;
+
+/*[31,25]*//* TYPEDEF ------------------------- GreySet1 */
+typedef r_Set<r_Ref<GreyString> > GreySet1;
+
+/*[33,27]*//* TYPEDEF ------------------------- ShortString */
+typedef r_Marray<r_Short > ShortString;
+
+/*[34,26]*//* TYPEDEF ------------------------- ShortSet1 */
+typedef r_Set<r_Ref<ShortString> > ShortSet1;
+
+/*[36,27]*//* TYPEDEF ------------------------- ShortImage */
+typedef r_Marray<r_Short > ShortImage;
+
+/*[37,25]*//* TYPEDEF ------------------------- ShortSet */
+typedef r_Set<r_Ref<ShortImage> > ShortSet;
+
+/*[39,27]*//* TYPEDEF ------------------------- ShortCube */
+typedef r_Marray<r_Short > ShortCube;
+
+/*[40,24]*//* TYPEDEF ------------------------- ShortSet3 */
+typedef r_Set<r_Ref<ShortCube> > ShortSet3;
+
+/*[42,36]*//* TYPEDEF ------------------------- UShortString */
+typedef r_Marray<r_UShort > UShortString;
+
+/*[43,27]*//* TYPEDEF ------------------------- UShortSet1 */
+typedef r_Set<r_Ref<UShortString> > UShortSet1;
+
+/*[45,36]*//* TYPEDEF ------------------------- UShortImage */
+typedef r_Marray<r_UShort > UShortImage;
+
+/*[46,26]*//* TYPEDEF ------------------------- UShortSet */
+typedef r_Set<r_Ref<UShortImage> > UShortSet;
+
+/*[48,36]*//* TYPEDEF ------------------------- UShortCube */
+typedef r_Marray<r_UShort > UShortCube;
+
+/*[49,25]*//* TYPEDEF ------------------------- UShortSet3 */
+typedef r_Set<r_Ref<UShortCube> > UShortSet3;
+
+/*[51,26]*//* TYPEDEF ------------------------- LongString */
+typedef r_Marray<r_Long > LongString;
+
+/*[52,25]*//* TYPEDEF ------------------------- LongSet1 */
+typedef r_Set<r_Ref<LongString> > LongSet1;
+
+/*[54,26]*//* TYPEDEF ------------------------- LongImage */
+typedef r_Marray<r_Long > LongImage;
+
+/*[55,24]*//* TYPEDEF ------------------------- LongSet */
+typedef r_Set<r_Ref<LongImage> > LongSet;
+
+/*[57,26]*//* TYPEDEF ------------------------- LongCube */
+typedef r_Marray<r_Long > LongCube;
+
+/*[58,23]*//* TYPEDEF ------------------------- LongSet3 */
+typedef r_Set<r_Ref<LongCube> > LongSet3;
+
+/*[60,35]*//* TYPEDEF ------------------------- ULongString */
+typedef r_Marray<r_ULong > ULongString;
+
+/*[61,26]*//* TYPEDEF ------------------------- ULongSet1 */
+typedef r_Set<r_Ref<ULongString> > ULongSet1;
+
+/*[63,35]*//* TYPEDEF ------------------------- ULongCube */
+typedef r_Marray<r_ULong > ULongCube;
+
+/*[64,24]*//* TYPEDEF ------------------------- ULongSet3 */
+typedef r_Set<r_Ref<ULongCube> > ULongSet3;
+
+/*[66,30]*//* TYPEDEF ------------------------- RGBString */
+typedef r_Marray<RGBPixel> RGBString;
+
+/*[67,24]*//* TYPEDEF ------------------------- RGBSet1 */
+typedef r_Set<r_Ref<RGBString> > RGBSet1;
+
+/*[69,30]*//* TYPEDEF ------------------------- RGBCube */
+typedef r_Marray<RGBPixel> RGBCube;
+
+/*[70,22]*//* TYPEDEF ------------------------- RGBSet3 */
+typedef r_Set<r_Ref<RGBCube> > RGBSet3;
+
+/*[72,27]*//* TYPEDEF ------------------------- FloatString */
+typedef r_Marray<r_Float> FloatString;
+
+/*[73,26]*//* TYPEDEF ------------------------- FloatSet1 */
+typedef r_Set<r_Ref<FloatString> > FloatSet1;
+
+/*[75,27]*//* TYPEDEF ------------------------- FloatImage */
+typedef r_Marray<r_Float> FloatImage;
+
+/*[76,25]*//* TYPEDEF ------------------------- FloatSet */
+typedef r_Set<r_Ref<FloatImage> > FloatSet;
+
+/*[78,27]*//* TYPEDEF ------------------------- FloatCube */
+typedef r_Marray<r_Float> FloatCube;
+
+/*[79,24]*//* TYPEDEF ------------------------- FloatSet3 */
+typedef r_Set<r_Ref<FloatCube> > FloatSet3;
+
+/*[81,28]*//* TYPEDEF ------------------------- DoubleString */
+typedef r_Marray<r_Double> DoubleString;
+
+/*[82,27]*//* TYPEDEF ------------------------- DoubleSet1 */
+typedef r_Set<r_Ref<DoubleString> > DoubleSet1;
+
+/*[84,28]*//* TYPEDEF ------------------------- DoubleImage */
+typedef r_Marray<r_Double> DoubleImage;
+
+/*[85,26]*//* TYPEDEF ------------------------- DoubleSet */
+typedef r_Set<r_Ref<DoubleImage> > DoubleSet;
+
+/*[87,28]*//* TYPEDEF ------------------------- DoubleCube */
+typedef r_Marray<r_Double> DoubleCube;
+
+/*[88,25]*//* TYPEDEF ------------------------- DoubleSet3 */
+typedef r_Set<r_Ref<DoubleCube> > DoubleSet3;
+
+#endif
diff --git a/manuals_and_examples/examples/c++/lookup.cc b/manuals_and_examples/examples/c++/lookup.cc
new file mode 100644
index 0000000..b4817fa
--- /dev/null
+++ b/manuals_and_examples/examples/c++/lookup.cc
@@ -0,0 +1,146 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * Example program for looking up the content of a collection.
+ *
+ *
+ ************************************************************/
+
+#include <iostream>
+
+// Linux needs this for template instantiation
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#ifdef __GNUG__
+#include "raslib/template_inst.hh"
+#endif
+#endif
+
+
+// this file is generated by the rasdl processor
+#include "basictypes.hh"
+
+
+int main( int ac, char** av )
+{
+ char rasmgrName[255];
+ int rasmgrPort;
+ char baseName[255];
+ char collName[255];
+ char userName[255];
+ char userPass[255];
+
+ if( ac != 7 )
+ {
+ cout << "Usage: lookup rasmgr_name rasmgr_port base_name collection_name user_name user_passwd" << endl;
+ return -1;
+ }
+
+ strcpy( rasmgrName, av[1] );
+ rasmgrPort = strtoul( av[2], NULL, 0);
+ strcpy( baseName, av[3] );
+ strcpy( collName, av[4] );
+ strcpy( userName, av[5] );
+ strcpy( userPass, av[6] );
+
+ r_Database database;
+ r_Transaction transaction;
+ r_Ref< r_Set< r_Ref< r_GMarray > > > image_set;
+ r_Ref< r_GMarray > image;
+ r_Iterator< r_Ref< r_GMarray > > iter;
+ int i;
+
+ try
+ {
+ database.set_servername( rasmgrName, rasmgrPort );
+ database.set_useridentification( userName, userPass );
+
+ cout << "Opening database " << baseName
+ << " on " << rasmgrName << "... " << flush;
+
+ database.open( baseName );
+ cout << "OK" << endl;
+
+ cout << "Starting read-only transaction ... " << flush;
+ transaction.begin( r_Transaction::read_only );
+ cout << "OK" << endl;
+
+ cout << "Looking up collection " << collName << " ..." << flush;
+ image_set = database.lookup_object( collName );
+ cout << "OK" << endl;
+
+ cout << "Collection" << endl;
+ cout << " oid...................: " << image_set->get_oid() << endl;
+ cout << " type name.............: " << image_set->get_object_name() << endl;
+ cout << " type structure........: "
+ << ( image_set->get_type_structure() ? image_set->get_type_structure() : "<nn>" )
+ << endl;
+
+ cout << " type schema...........: " << flush;
+ if( image_set->get_type_schema() )
+ image_set->get_type_schema()->print_status( cout );
+ else
+ cout << "<nn>" << flush;
+ cout << endl;
+ cout << " number of entries.....: " << image_set->cardinality() << endl;
+
+ cout << " Element type schema...: " << flush;
+ if( image_set->get_element_type_schema() )
+ image_set->get_element_type_schema()->print_status( cout );
+ else
+ cout << "<nn>" << flush;
+ cout << endl << endl;
+
+ iter = image_set->create_iterator();
+ for( i=1, iter.reset(); iter.not_done(); iter++, i++ )
+ {
+ cout << "Image " << i << endl;
+ image = *iter;
+ image->print_status( cout );
+ cout << endl;
+ }
+ cout << endl;
+
+ cout << "Committing transaction ... " << flush;
+ transaction.commit();
+ cout << "OK" << endl;
+
+ cout << "Closing database ... " << flush;
+ database.close();
+ cout << "OK" << endl;
+ }
+ catch( r_Error& errorObj )
+ {
+ cerr << errorObj.what() << endl;
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * end of lookup.cc
+ */
diff --git a/manuals_and_examples/examples/c++/query.cc b/manuals_and_examples/examples/c++/query.cc
new file mode 100644
index 0000000..9bcf16e
--- /dev/null
+++ b/manuals_and_examples/examples/c++/query.cc
@@ -0,0 +1,172 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * Example program for RasML query invocation from C++.
+ *
+ *
+ ************************************************************/
+
+#include <iostream>
+
+// Linux needs this for template instantiation
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#ifdef __GNUG__
+#include "raslib/template_inst.hh"
+#endif
+#endif
+
+// this file is generated by the rasdl processor
+#include "basictypes.hh"
+
+
+int main( int ac, char** av )
+{
+ char rasmgrName[255];
+ int rasmgrPort;
+ char baseName[255];
+ char collName[255];
+ char userName[255];
+ char userPass[255];
+
+ if( ac != 7 )
+ {
+ cout << "Usage: query rasmgr_name rasmgr_port base_name collection_name user_name user_passwd" << endl;
+ return -1;
+ }
+
+ strcpy( rasmgrName, av[1] );
+ rasmgrPort = strtoul( av[2], NULL, 0);
+ strcpy( baseName, av[3] );
+ strcpy( collName, av[4] );
+ strcpy( userName, av[5] );
+ strcpy( userPass, av[6] );
+
+ r_Minterval select_domain = r_Minterval("[0:4,0:4]");
+ r_Minterval where_domain = r_Minterval("[8:9,8:9]");
+ r_ULong threshold_value = 10;
+
+ r_Database database;
+ r_Transaction transaction;
+ r_Set< r_Ref< r_GMarray > > image_set;
+ r_Ref< r_GMarray > image;
+ r_Iterator< r_Ref< r_GMarray > > iter;
+
+ try
+ {
+ database.set_servername( rasmgrName, rasmgrPort );
+ database.set_useridentification( userName, userPass );
+
+ cout << "Opening database " << baseName
+ << " on " << rasmgrName << "... " << flush;
+
+ database.open( baseName );
+ cout << "OK" << endl;
+
+ cout << "Starting read-only transaction ... " << flush;
+ transaction.begin( r_Transaction::read_only );
+ cout << "OK" << endl;
+
+ cout << "Creating the query object ..." << flush;
+ r_OQL_Query query("select a$1 from $2 as a where some_cells( a$3 > $4 )");
+ cout << "OK, Query string is: " << query.get_query() << endl;
+
+ cout << "Substituting query parameters ..." << flush;
+ query << select_domain << collName << where_domain << threshold_value;
+ cout << "OK, Query string is: " << query.get_query() << endl;
+
+ cout << "Executing the query ..." << flush;
+ try
+ {
+ r_oql_execute( query, image_set );
+ }
+ catch( r_Error& errorObj )
+ {
+ cout << "FAILED" << endl << errorObj.what() << endl;
+
+ cout << "Aborting transaction ... " << flush;
+ transaction.abort();
+ cout << "OK" << endl;
+
+ cout << "Closing database ... " << flush;
+ database.close();
+ cout << "OK" << endl;
+ return -1;
+ }
+ cout << "OK" << endl << endl;
+
+ cout << "Collection" << endl;
+ cout << " Oid...................: " << image_set.get_oid() << endl;
+ cout << " Type Name.............: " << image_set.get_object_name() << endl;
+ cout << " Type Structure........: "
+ << ( image_set.get_type_structure() ? image_set.get_type_structure() : "<nn>" )
+ << endl;
+ cout << " Type Schema...........: " << flush;
+ if( image_set.get_type_schema() )
+ image_set.get_type_schema()->print_status( cout );
+ else
+ cout << "<nn>" << flush;
+ cout << endl;
+ cout << " Number of entries.....: " << image_set.cardinality() << endl;
+ cout << " Element Type Schema...: " << flush;
+ if( image_set.get_element_type_schema() )
+ image_set.get_element_type_schema()->print_status( cout );
+ else
+ cout << "<nn>" << flush;
+ cout << endl << endl;
+
+ iter = image_set.create_iterator();
+
+ int i;
+ for ( i=1, iter.reset(); iter.not_done(); iter++, i++ )
+ {
+ cout << "Image " << i << endl;
+ image= *iter;
+ image->print_status( cout );
+ cout << endl;
+ }
+ cout << endl;
+
+ cout << "Committing transaction ... " << flush;
+ transaction.commit();
+ cout << "OK" << endl;
+
+ cout << "Closing database ... " << flush;
+ database.close();
+ cout << "OK" << endl;
+ }
+ catch( r_Error& errorObj )
+ {
+ cerr << errorObj.what() << endl;
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * end of query.cc
+ */
diff --git a/manuals_and_examples/examples/c++/query2.cc b/manuals_and_examples/examples/c++/query2.cc
new file mode 100644
index 0000000..6388e78
--- /dev/null
+++ b/manuals_and_examples/examples/c++/query2.cc
@@ -0,0 +1,181 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * Example program for rasql query invocation from C++, showing a
+ * typical mapping scenario.
+ *
+ *
+ * BUGS:
+ * - needs this link cmd line
+ * query2: query2.o
+ * $(CXX) $(LDFLAGS) -o $@ $^ \
+ * -L$(RMANHOME)/lib -lrasodmg -lclientcomm -lcompression -lconversion -lraslib -lnetwork -ljpeg -lpng -ltiff -lmfhdf -ldf -lcrypt o -lclientcomm -lm -lz
+ *
+ ************************************************************/
+
+#include <iostream>
+
+// Linux needs this for template instantiation
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#ifdef __GNUG__
+#include "raslib/template_inst.hh"
+#endif
+#endif
+
+// this file is generated by the rasdl processor
+#include "basictypes.hh"
+
+// connectivity constants
+char *host = "localhost";
+int port = 7001;
+char *db = "RASBASE";
+char *userName = "rasguest";
+char *userPass = "rasguest";
+
+// demo program settings
+// - collection ("map") name
+char *collection = "rgb";
+// - coordinates of map bbox to be retrieved
+unsigned int xImageLo = 100;
+unsigned int xImageHi = 200;
+unsigned int yImageLo = 100;
+unsigned int yImageHi = 200;
+// - target window size
+unsigned int xSize = 10;
+unsigned int ySize = 10;
+
+// global connection objects
+r_Database database;
+r_Transaction transaction;
+
+// sample image accessing function, typical for mapping applications
+// input: collection ("map") name, source image coordinates, target window size
+// output: ptr to image array
+// precondition: we're accessing an RGB image, so that we can select the "green" channel of it
+// note: the most important parts contain markups at the beginning of the line
+unsigned char *readImage( const char *collection, int xImageLo, int xImageHi, int yImageLo, int yImageHi, int xSize, int ySize ) throw (r_Error)
+{
+ r_Set< r_Ref< r_GMarray > > imageSet; // result set
+ r_Ref< r_GMarray > image;
+ r_Iterator< r_Ref< r_GMarray > > iter;
+
+ // function result
+ unsigned char *result = NULL;
+
+ try
+ {
+ cout << "creating query..." << flush;
+ // parameters:
+ // $1 map bbox coordinate, lower x
+ // $2 map bbox coordinate, upper x
+ // $3 map bbox coordinate, lower y
+ // $4 map bbox coordinate, upper y
+ // $5 result window x size
+ // $6 result window y size
+ // $7 collection (i.e., map) name
+/* 1 */ r_OQL_Query query("select scale(img.green[$1:$2,$3:$4],[1:$5,1:$6]) from $7 as img");
+
+ cout << "substituting parameters ..." << flush;
+/* 2 */ query << xImageLo << xImageHi << yImageLo << yImageHi << xSize << ySize << collection;
+ cout << "[query: " << query.get_query() << "]...";
+
+ cout << "executing query..." << flush;
+/* 3 */ r_oql_execute( query, imageSet );
+
+ // now we assume a result has come back
+ iter = imageSet.create_iterator();
+ iter.reset();
+/* 4 */ result = (unsigned char*) (*iter)->get_array();
+
+ }
+ catch(r_Error& e)
+ {
+ cout << "Error: query failed: " << e.what() << flush;
+ throw;
+ }
+
+ return result;
+}
+
+// simple wrapper, handling db connectivity and demo output
+int main()
+{
+ try
+ {
+ database.set_servername( host, port );
+ database.set_useridentification( userName, userPass );
+
+ cout << "Opening database " << db << " on " << host << "..." << flush;
+ database.open( db );
+
+ cout << "starting read-only transaction..." << flush;
+ transaction.begin( r_Transaction::read_only );
+
+ // the real workhorse: fetch image data
+ unsigned char *imgPtr = readImage( collection, xImageLo, xImageHi, yImageLo, yImageHi, xSize, ySize );
+
+ cout << "result image:" << endl << hex;
+ for (int i = 0; i < xSize; i++)
+ {
+ for (int j = 0; j < ySize; j++)
+ {
+ register unsigned char c = *imgPtr;
+ cout << " " << setw(2) << (unsigned short) (c & 0xFF);
+ imgPtr++;
+ }
+ cout << endl;
+ }
+ cout << dec;
+ }
+ catch(r_Error& e)
+ {
+ cout << "Error: cannot access database: " << e.what() << endl << flush;
+ }
+
+
+ // ignore any (previous) errors for connection close
+ try
+ {
+ cout << "aborting transaction..." << flush;
+ transaction.abort();
+
+ cout << "closing database..." << flush;
+ database.close();
+
+ cout << "done." << endl;
+ }
+ catch(r_Error &e)
+ {
+ cout << "Error closing connection: " << e.what() << endl << flush;
+ }
+
+ return 0;
+}
+
+/*
+ * end of query2.cc
+ */
diff --git a/manuals_and_examples/examples/images/anthur.ppm b/manuals_and_examples/examples/images/anthur.ppm
new file mode 100644
index 0000000..38a7be3
--- /dev/null
+++ b/manuals_and_examples/examples/images/anthur.ppm
@@ -0,0 +1,5 @@
+P6
+# CREATOR: XV Version 3.10b Rev: 12/31/97
+400 344
+255
+wÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøÿÿÿÿÿÿwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐø" " wÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐøwÐø" 
diff --git a/manuals_and_examples/examples/images/anthur.tif b/manuals_and_examples/examples/images/anthur.tif
new file mode 100644
index 0000000..2f841d2
--- /dev/null
+++ b/manuals_and_examples/examples/images/anthur.tif
Binary files differ
diff --git a/manuals_and_examples/examples/images/arrow.pgm b/manuals_and_examples/examples/images/arrow.pgm
new file mode 100644
index 0000000..74feaa0
--- /dev/null
+++ b/manuals_and_examples/examples/images/arrow.pgm
Binary files differ
diff --git a/manuals_and_examples/examples/images/arrow.tif b/manuals_and_examples/examples/images/arrow.tif
new file mode 100644
index 0000000..2911b21
--- /dev/null
+++ b/manuals_and_examples/examples/images/arrow.tif
Binary files differ
diff --git a/manuals_and_examples/examples/images/mr_1.pgm b/manuals_and_examples/examples/images/mr_1.pgm
new file mode 100644
index 0000000..6722dbd
--- /dev/null
+++ b/manuals_and_examples/examples/images/mr_1.pgm
Binary files differ
diff --git a/manuals_and_examples/examples/images/mr_1.tif b/manuals_and_examples/examples/images/mr_1.tif
new file mode 100644
index 0000000..785fcb9
--- /dev/null
+++ b/manuals_and_examples/examples/images/mr_1.tif
Binary files differ
diff --git a/manuals_and_examples/examples/images/mr_2.pgm b/manuals_and_examples/examples/images/mr_2.pgm
new file mode 100644
index 0000000..1fc6b18
--- /dev/null
+++ b/manuals_and_examples/examples/images/mr_2.pgm
Binary files differ
diff --git a/manuals_and_examples/examples/images/mr_2.tif b/manuals_and_examples/examples/images/mr_2.tif
new file mode 100644
index 0000000..d3c92cc
--- /dev/null
+++ b/manuals_and_examples/examples/images/mr_2.tif
Binary files differ
diff --git a/manuals_and_examples/examples/images/mr_3.pgm b/manuals_and_examples/examples/images/mr_3.pgm
new file mode 100644
index 0000000..f9a0499
--- /dev/null
+++ b/manuals_and_examples/examples/images/mr_3.pgm
Binary files differ
diff --git a/manuals_and_examples/examples/images/mr_3.tif b/manuals_and_examples/examples/images/mr_3.tif
new file mode 100644
index 0000000..29c6f58
--- /dev/null
+++ b/manuals_and_examples/examples/images/mr_3.tif
Binary files differ
diff --git a/manuals_and_examples/examples/java/AvgCell.java b/manuals_and_examples/examples/java/AvgCell.java
new file mode 100644
index 0000000..787f2a4
--- /dev/null
+++ b/manuals_and_examples/examples/java/AvgCell.java
@@ -0,0 +1,145 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE: Example Java program for computing the avg cell value
+ * for each n-D 8-bit grey image in a given collection.
+ *
+ *
+ ************************************************************/
+
+import rasj.*;
+import rasj.odmg.*;
+import org.odmg.*;
+import java.util.*;
+
+/** Example Java program for computing the avg cell value
+ * for each n-D 8-bit grey image in a given collection.
+ *
+ * set the server name with -server, the database name with -database, the collection name with -collection,
+ * the port number with -port, the user login with -user, the password with -passwd
+ */
+public class AvgCell
+{
+ public static void main(String[] args)
+ {
+ String server = "localhost";
+ String base = "RASBASE";
+ String coll = "mr";
+ String port = "7001";
+ String user = "rasguest";
+ String passwd = "rasguest";
+
+ double sum;
+
+ for (int i=args.length-1; i>=0; i--)
+ {
+ //System.out.println(args[i]);
+ if (args[i].equals("-server"))
+ server = args[i+1];
+ if (args[i].equals("-database"))
+ base = args[i+1];
+ if (args[i].equals("-collection"))
+ coll = args[i+1];
+ if (args[i].equals("-port"))
+ port = args[i+1];
+ if (args[i].equals("-user"))
+ user = args[i+1];
+ if (args[i].equals("-passwd"))
+ passwd = args[i+1];
+ }
+ //System.out.println(server+base+coll+port+user+passwd);
+
+ DBag resultBag = null;
+ RasGMArray result = null;
+ Transaction myTa = null;
+ Database myDb = null;
+ OQLQuery myQu = null;
+
+ try
+ {
+ Implementation myApp = new RasImplementation("http://"+server+":"+port);
+ ((RasImplementation)myApp).setUserIdentification(user, passwd);
+ myDb = myApp.newDatabase();
+
+ System.out.println("Opening database ...");
+ myDb.open(base, Database.OPEN_READ_ONLY);
+
+ System.out.println("Starting transaction ...");
+ myTa = myApp.newTransaction();
+ myTa.begin();
+
+ System.out.println("Retrieving MDDs ...");
+ myQu = myApp.newOQLQuery();
+ myQu.create("select img from " + coll + " as img");
+ resultBag = (DBag)myQu.execute();
+ if (resultBag != null)
+ {
+ Iterator iter = resultBag.iterator();
+ while (iter.hasNext())
+ {
+ result = (RasGMArray)iter.next();
+ System.out.println(result);
+ if(result.getTypeLength() != 1)
+ System.out.println("skipping image because of non-int cell type");
+ else
+ {
+ byte[] pixelfield = result.getArray();
+ sum = 0.0;
+ long size = result.getArraySize();
+ for(int i=0; i<size; i++)
+ sum += pixelfield[i];
+ System.out.println("Avarage over " + size + " pixels is " + ((sum/size)+128));
+ }
+
+ }
+ System.out.println("All results");
+ }
+
+ System.out.println( "Committing transaction ..." );
+ myTa.commit();
+
+ System.out.println( "Closing database ..." );
+ myDb.close();
+
+ }
+ catch (org.odmg.ODMGException e)
+ {
+ System.out.println("An exception has occurred: " + e.getMessage());
+ System.out.println("Try to abort the transaction ...");
+ if(myTa != null) myTa.abort();
+
+ try
+ {
+ System.out.println("Try to close the database ...");
+ if(myDb != null) myDb.close();
+ }
+ catch ( org.odmg.ODMGException exp )
+ {
+ System.err.println("Could not close the database: " + exp.getMessage());
+ }
+ }
+ System.out.println( "Done." );
+ }
+}
diff --git a/manuals_and_examples/examples/java/Lookup.java b/manuals_and_examples/examples/java/Lookup.java
new file mode 100644
index 0000000..4b5eefc
--- /dev/null
+++ b/manuals_and_examples/examples/java/Lookup.java
@@ -0,0 +1,130 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE: Example Java program for looking up a collection
+ *
+ *
+ ************************************************************/
+
+import rasj.*;
+import rasj.odmg.*;
+import org.odmg.*;
+import java.util.*;
+
+/**
+ * Example Java program for looking up a collection
+ *
+ * set the server name with -server, the database name with -database, the collection name with -collection,
+ * the port number with -port, the user login with -user, the password with -passwd
+ */
+public class Lookup
+{
+ public static void main(String[] args)
+ {
+ String server = "localhost";
+ String base = "RASBASE";
+ String coll = "rockies";
+ String port = "7001";
+ String user = "rasguest";
+ String passwd = "rasguest";
+
+ for (int i=args.length-1; i>=0; i--)
+ {
+ //System.out.println(args[i]);
+ if (args[i].equals("-server"))
+ server = args[i+1];
+ if (args[i].equals("-database"))
+ base = args[i+1];
+ if (args[i].equals("-collection"))
+ coll = args[i+1];
+ if (args[i].equals("-port"))
+ port = args[i+1];
+ if (args[i].equals("-user"))
+ user = args[i+1];
+ if (args[i].equals("-passwd"))
+ passwd = args[i+1];
+ }
+ //System.out.println(server+base+coll+port+user+passwd);
+
+ DBag resultBag = null;
+ Object result = null;
+ Transaction myTa = null;
+ Database myDb = null;
+ OQLQuery myQu = null;
+
+ try
+ {
+ Implementation myApp = new RasImplementation("http://"+server+":"+port);
+ ((RasImplementation)myApp).setUserIdentification(user, passwd);
+ myDb = myApp.newDatabase();
+
+ System.out.println("Opening database ...");
+ myDb.open(base, Database.OPEN_READ_ONLY);
+
+ System.out.println("Starting transaction ...");
+ myTa = myApp.newTransaction();
+ myTa.begin();
+
+ System.out.println("Retrieving results ...");
+ myQu = myApp.newOQLQuery();
+ myQu.create("select img from "+coll+" as img");
+ resultBag = (DBag)myQu.execute();
+ if (resultBag != null)
+ {
+ Iterator iter = resultBag.iterator();
+ while (iter.hasNext())
+ {
+ result = iter.next();
+ System.out.println(result);
+ }
+ System.out.println("All results");
+ }
+
+ System.out.println( "Committing transaction ..." );
+ myTa.commit();
+
+ System.out.println( "Closing database ..." );
+ myDb.close();
+
+ }
+ catch (org.odmg.ODMGException e)
+ {
+ System.out.println("An exception has occurred: " + e.getMessage());
+ System.out.println("Try to abort the transaction ...");
+ if(myTa != null) myTa.abort();
+
+ try
+ {
+ System.out.println("Try to close the database ...");
+ if(myDb != null) myDb.close();
+ }
+ catch ( org.odmg.ODMGException exp )
+ {
+ System.err.println("Could not close the database: " + exp.getMessage());
+ }
+ }
+ System.out.println( "Done." );
+ }
+}
diff --git a/manuals_and_examples/examples/java/Makefile b/manuals_and_examples/examples/java/Makefile
new file mode 100644
index 0000000..c97eff2
--- /dev/null
+++ b/manuals_and_examples/examples/java/Makefile
@@ -0,0 +1,45 @@
+# -*-Makefile-*-
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>. # Top Level makefile. This points to the various modules that have to be build
+# and/or deployed
+#
+# MAKEFILE FOR:
+# Compile example Java programs;
+#
+##################################################################
+
+######################## Dependencies ############################
+
+all: AvgCell.class Lookup.class Query.class
+clean:
+ rm *.class
+
+AvgCell.class: AvgCell.java
+ javac $<
+
+Lookup.class: Lookup.java
+ javac $<
+
+Query.class: Query.java
+ javac $<
+
+# end of Makefile
diff --git a/manuals_and_examples/examples/java/Query.java b/manuals_and_examples/examples/java/Query.java
new file mode 100644
index 0000000..9fd3d9c
--- /dev/null
+++ b/manuals_and_examples/examples/java/Query.java
@@ -0,0 +1,225 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE: Example Java program for reading a query out of a file
+ * and send it to the server and write the result into a log file
+ *
+ *
+ ************************************************************/
+
+import rasj.*;
+import rasj.odmg.*;
+import org.odmg.*;
+import java.util.*;
+import java.io.*;
+
+/**
+ * Example Java program for reading a query out of a file
+ * and send it to the server and write the result into a log file
+ *
+ * set the server name with -server, the database name with -database, the collection name with -collection,
+ * set port number with -port, the user login with -user, the password with -passwd,
+ * the path to log file with -logfile, path to query file with -queryfile
+ */
+public class Query
+{
+
+ public static void main( String[] args )
+ {
+ String server = "localhost";
+ String port = "7001";
+ String base = "RASBASE";
+ String coll = "rockies";
+ String user = "rasguest";
+ String passwd = "rasguest";
+ String file = "";
+ String query = "";
+ String log = "";
+ String ret = "";
+
+ for (int i=args.length-1; i>=0; i--)
+ {
+ //System.out.println(args[i]);
+ if (args[i].equals("-server"))
+ server = args[i+1];
+ if (args[i].equals("-port"))
+ port = args[i+1];
+ if (args[i].equals("-database"))
+ base = args[i+1];
+ if (args[i].equals("-collection"))
+ coll = args[i+1];
+ if (args[i].equals("-logfile"))
+ log = args[i+1];
+ if (args[i].equals("-user"))
+ user = args[i+1];
+ if (args[i].equals("-passwd"))
+ passwd = args[i+1];
+ if (args[i].equals("-queryfile"))
+ {
+ try
+ {
+ file = args[i+1];
+ //System.out.println(file);
+ FileReader fr = new FileReader(file);
+ BufferedReader in = new BufferedReader(fr);
+ String s;
+
+ while((s = in.readLine()) != null)
+ {
+ String t = s.trim();
+ while(t.regionMatches(0, "--", 0, 2))
+ {
+ s = in.readLine();
+ t = s.trim();
+ }
+ query = query +" "+ s;
+ }
+
+ }
+ catch(FileNotFoundException e)
+ {
+ ret = ret+" Query-file not found!"+e.getMessage();
+ System.err.println(ret);
+ }
+ catch(IOException e)
+ {
+ ret = ret+" Could not read Query-file!"+e.getMessage();
+ System.err.println(ret);
+ }
+
+ }
+
+ }
+
+
+ Transaction myTa = null;
+ Database myDb = null;
+ int accessMode = Database.OPEN_READ_ONLY;
+
+ try
+ {
+ Implementation myApp = new RasImplementation("http://"+server+":"+port);
+ ((RasImplementation)myApp).setUserIdentification(user, passwd);
+ OQLQuery myQu = myApp.newOQLQuery();
+
+ if(query.equals(""))
+ query="select avg_cells(a) from "+ coll+" as a";
+ //query="create collection UpdateULong1 ULongSet";
+ //query="insert into UpdateULong1 values $1";
+
+ myQu.create(query);
+
+ StringTokenizer strTok = new StringTokenizer(query, "$");
+ RasMInterval domain;
+ RasGMArray mddConst;
+ if(strTok.hasMoreTokens())
+ strTok.nextToken();
+
+ while(strTok.hasMoreTokens())
+ {
+ strTok.nextToken();
+ domain = new RasMInterval("[0:10,0:10]");
+ RasStorageLayout stl = new RasStorageLayout();
+ stl.setTileSize(100);
+ mddConst = new RasGMArray(domain, 4, stl);
+ mddConst.setObjectTypeName("ULongImage");
+ //System.out.println(mddConst);
+ myQu.bind(mddConst);
+ }
+
+ //check if is an update Query
+ if((query.indexOf("select") == -1) &&
+ (query.indexOf("SELECT") == -1))
+ accessMode = Database.OPEN_READ_WRITE;
+
+ myDb = myApp.newDatabase();
+ //System.out.println( "Opening database ..." );
+ myDb.open( base, accessMode );
+
+ //System.out.println( "Starting transaction ..." );
+ myTa = myApp.newTransaction();
+ myTa.begin();
+
+ //System.out.println( "Executing query..." );
+ DBag result = (DBag) myQu.execute();
+
+ //System.out.println( "Committing transaction ..." );
+ myTa.commit();
+
+ //System.out.println( "Closing database ..." );
+ myDb.close();
+
+ //System.out.println( " Done." );
+ }
+ catch(RasException e)
+ {
+ ret = ret+"RasException: "+e.getMessage();
+ System.err.println(ret);
+ }
+ catch (org.odmg.ODMGException e)
+ {
+ ret = ret + query + "\n Failed:\n " + e.getMessage() + "\n";
+ System.err.println(ret);
+ //System.err.println("Try to abort the transaction ...");
+ if(myTa != null) myTa.abort();
+
+ try
+ {
+ //System.err.println("Try to close the database ...");
+ if(myDb != null) myDb.close();
+ }
+ catch ( org.odmg.ODMGException exp )
+ {
+ ret = ret+" Could not close the database: " + exp.getMessage();
+ System.err.println(ret);
+ }
+
+ }
+ if(!log.equals(""))
+ {
+ try
+ {
+ FileOutputStream fos = new FileOutputStream(log, true);
+ PrintWriter pw = new PrintWriter(fos);
+ if(ret.equals(""))
+ ret = "OK.";
+ pw.write(ret);
+ pw.close();
+ }
+ catch(FileNotFoundException e)
+ {
+ ret = ret+" Log-file not found!"+e.getMessage();
+ System.out.println(ret);
+ }
+ catch(IOException e)
+ {
+ ret = ret+" Could not write Log-file!"+e.getMessage();
+ System.out.println(ret);
+ }
+ }
+
+ }
+
+}
diff --git a/manuals_and_examples/examples/queries/boolean-masking.ql b/manuals_and_examples/examples/queries/boolean-masking.ql
new file mode 100644
index 0000000..d5b7282
--- /dev/null
+++ b/manuals_and_examples/examples/queries/boolean-masking.ql
@@ -0,0 +1,5 @@
+-- rview-Query
+select rgb.green > 130c
+ and rgb.red < 150c
+ and rgb.blue < 140c
+from rgb
diff --git a/manuals_and_examples/examples/queries/sdom.ql b/manuals_and_examples/examples/queries/sdom.ql
new file mode 100644
index 0000000..aa39b24
--- /dev/null
+++ b/manuals_and_examples/examples/queries/sdom.ql
@@ -0,0 +1,3 @@
+-- rview-Query
+select sdom( mr )[1].hi
+from mr
diff --git a/manuals_and_examples/examples/queries/trim-sdom.ql b/manuals_and_examples/examples/queries/trim-sdom.ql
new file mode 100644
index 0000000..d881db2
--- /dev/null
+++ b/manuals_and_examples/examples/queries/trim-sdom.ql
@@ -0,0 +1,4 @@
+-- rview-Query
+select rgb[ sdom(rgb)[0].hi - 99 : sdom(rgb)[0].hi,
+ sdom(rgb)[1].hi - 99 : sdom(rgb)[1].hi ]
+from rgb
diff --git a/manuals_and_examples/examples/queries/trim.ql b/manuals_and_examples/examples/queries/trim.ql
new file mode 100644
index 0000000..16079ec
--- /dev/null
+++ b/manuals_and_examples/examples/queries/trim.ql
@@ -0,0 +1,3 @@
+-- rview-Query
+select rgb[ 0:99, 0:99 ]
+from rgb
diff --git a/manuals_and_examples/examples/queries/where.ql b/manuals_and_examples/examples/queries/where.ql
new file mode 100644
index 0000000..9e4eb14
--- /dev/null
+++ b/manuals_and_examples/examples/queries/where.ql
@@ -0,0 +1,4 @@
+-- rview-Query
+select mr
+from mr
+where some_cells( mr[ 120:160, 55:75 ] > 110 )
diff --git a/manuals_and_examples/examples/rasdl/basictypes.dl b/manuals_and_examples/examples/rasdl/basictypes.dl
new file mode 100644
index 0000000..60c9123
--- /dev/null
+++ b/manuals_and_examples/examples/rasdl/basictypes.dl
@@ -0,0 +1,157 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+// ---------------------------------------------------------------------
+//
+//
+// PURPOSE:
+// This file contains type definitions to challenge the rasdl utilit.
+// Rasdl needs to read them and react appropriately. Reports are done
+// to stdout.
+//
+//
+// COMMENTS:
+// ./.
+//
+//
+// ---------------------------------------------------------------------
+
+
+// --- good defs -------------------------------------------------------
+// --- bad defs --------------------------------------------------------
+
+
+
+// example 1
+typedef marray <char,2> GreyImage;
+typedef set<GreyImage> GreySet;
+
+// example 2
+typedef marray <boolean,2> BoolImage;
+typedef set<BoolImage> BoolSet;
+
+// example 3
+struct RGBPixel { char red, green, blue; };
+typedef marray <RGBPixel,2> RGBImage;
+typedef set<RGBImage> RGBSet;
+
+// example 4
+typedef marray <unsigned long, 2> ULongImage;
+typedef set<ULongImage> ULongSet;
+
+// example 5
+typedef marray <char, 3> GreyCube;
+typedef set<GreyCube> GreySet3;
+
+
+// heavily expanded types (Andreas)
+typedef marray <boolean, 1> BoolString;
+typedef set<BoolString> BoolSet1;
+
+typedef marray <boolean, 3> BoolCube;
+typedef set<BoolCube> BoolSet3;
+
+typedef marray <char, 1> GreyString;
+typedef set<GreyString> GreySet1;
+
+typedef marray <octet, 1> OctetString;
+typedef set<OctetString> OctetSet1;
+
+typedef marray <octet, 2> OctetImage;
+typedef set<OctetImage> OctetSet;
+
+typedef marray <octet, 3> OctetCube;
+typedef set<OctetCube> OctetSet3;
+
+typedef marray <short, 1> ShortString;
+typedef set<ShortString> ShortSet1;
+
+typedef marray <short, 2> ShortImage;
+typedef set<ShortImage> ShortSet;
+
+typedef marray <short, 3> ShortCube;
+typedef set<ShortCube> ShortSet3;
+
+typedef marray <unsigned short, 1> UShortString;
+typedef set<UShortString> UShortSet1;
+
+typedef marray <unsigned short, 2> UShortImage;
+typedef set<UShortImage> UShortSet;
+
+typedef marray <unsigned short, 3> UShortCube;
+typedef set<UShortCube> UShortSet3;
+
+typedef marray <long, 1> LongString;
+typedef set<LongString> LongSet1;
+
+typedef marray <long, 2> LongImage;
+typedef set<LongImage> LongSet;
+
+typedef marray <long, 3> LongCube;
+typedef set<LongCube> LongSet3;
+
+typedef marray <unsigned long, 1> ULongString;
+typedef set<ULongString> ULongSet1;
+
+typedef marray <unsigned long, 3> ULongCube;
+typedef set<ULongCube> ULongSet3;
+
+typedef marray <RGBPixel, 1> RGBString;
+typedef set<RGBString> RGBSet1;
+
+typedef marray <RGBPixel, 3> RGBCube;
+typedef set<RGBCube> RGBSet3;
+
+typedef marray <float, 1> FloatString;
+typedef set<FloatString> FloatSet1;
+
+typedef marray <float, 2> FloatImage;
+typedef set<FloatImage> FloatSet;
+
+typedef marray <float, 3> FloatCube;
+typedef set<FloatCube> FloatSet3;
+
+typedef marray <float, 4> FloatCube4;
+typedef set<FloatCube4> FloatSet4;
+
+typedef marray <double, 1> DoubleString;
+typedef set<DoubleString> DoubleSet1;
+
+typedef marray <double, 2> DoubleImage;
+typedef set<DoubleImage> DoubleSet;
+
+typedef marray <double, 3> DoubleCube;
+typedef set<DoubleCube> DoubleSet3;
+
+typedef marray <complex, 1> Gauss1;
+typedef set<Gauss1> GaussSet1;
+
+typedef marray<complexd, 1> Gauss2;
+typedef set<Gauss2> GaussSet2;
+
+typedef marray <complex, 2> Gauss1Image;
+typedef set<Gauss1Image> Gauss1Set;
+
+typedef marray<complexd, 2> Gauss2Image;
+typedef set<Gauss2Image> Gauss2Set;
+
+// --- end -----------------------------------------------------------
diff --git a/manuals_and_examples/manuals/banner.html b/manuals_and_examples/manuals/banner.html
new file mode 100644
index 0000000..5e83699
--- /dev/null
+++ b/manuals_and_examples/manuals/banner.html
@@ -0,0 +1,31 @@
+
+<i><a href="aindex.html">alphabetic index</a></i>
+<br>
+<br>
+<hr size="1">
+
+<p>
+Rasdaman community is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+</p>
+<p>
+Rasdaman community is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+</p>
+<p>
+You should have received a copy of the GNU General Public License along with Rasdaman. If not, see <http://www.gnu.org/licenses/>.
+</p>
+<p>
+Copyright &copy; 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / <a href="http://www.rasdaman.com">rasdaman GmbH</a> Germany.
+</p>
+<p>
+For more information please see <http://www.rasdaman.org> or contact Peter Baumann via <baumann@rasdaman.com>.
+</p>
+
+<br>
+Documentation generated by doxygen.
+
diff --git a/manuals_and_examples/manuals/body.html b/manuals_and_examples/manuals/body.html
new file mode 100644
index 0000000..da9c6be
--- /dev/null
+++ b/manuals_and_examples/manuals/body.html
@@ -0,0 +1,54 @@
+<!DOCTYPE HTML PUBliC "-//IETF//DTD HTML//EN">
+<html>
+ <head>
+ <title>rasdaman, the intelligent multidimensional raster server</title>
+ </head>
+
+<body bgcolor=white style="font-family:Helvetica,Arial">
+<table align=center>
+<tr>
+ <td>
+ <br><br>
+ <li><a href=pdf/inst-guide.pdf target=_top>installation and administration guide</A>
+ <li><a href=pdf/external-guide-POSTGRESQL.pdf target=_top>PostgreSQL external products guide</A>
+ <p>
+ <li><a href=pdf/rview-guide.pdf target=_top>rview guide</A>
+ <li><a href=pdf/ql-guide.pdf target=_top>query language guide</A><P>
+ <li>C++ <a href=pdf/dev-guide-c++.pdf target=_top>development guide</A> and <a href=html/raslib/index.html target=_top>API reference</A>
+ <li>Java <a href=pdf/dev-guide-java.pdf target=_top>development guide</A> and <a href=html/rasj/index.html target=_top>API reference</A>
+ <P>
+ <li><a href=pdf/error-messages.pdf target=_top>error messages</A>
+ </td>
+</tr>
+</table>
+
+<br>
+<hr size="1">
+<br>
+
+<p>
+Rasdaman community is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+</p>
+<p>
+Rasdaman community is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+</p>
+<p>
+You should have received a copy of the GNU General Public License along with Rasdaman. If not, see <http://www.gnu.org/licenses/>.
+</p>
+<p>
+Copyright &copy; 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / <a href="http://www.rasdaman.com">rasdaman GmbH</a> Germany.
+</p>
+<p>
+For more information see <a href="http://www.rasdaman.org" target="_new">http://www.rasdaman.org</a>
+or contact Peter Baumann via <em>baumann &auml;tt rasdaman dot com</em>.
+</p>
+
+</body>
+</html>
+
diff --git a/manuals_and_examples/manuals/header.html b/manuals_and_examples/manuals/header.html
new file mode 100644
index 0000000..e26f680
--- /dev/null
+++ b/manuals_and_examples/manuals/header.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>rasdaman - the intelligent multidimensional raster server</title>
+</head>
+
+<body bgcolor="white" style="font-family:Helvetica,Arial,sans-serif">
+
+<table cellspacing="0" cellpadding="5" width="100%">
+<tr>
+ <td>
+ <br>
+ <a href="http://www.rasdaman.org/" target="_top"><img src="logo-rasdaman.gif" height="100" alt="rasdaman logo" border="0"></a>
+ the intelligent multidimensional raster server
+ </td>
+ <td valign="bottom" align="right">
+ version 7.0
+ </td>
+</tr>
+</table>
+
+<hr size="1">
+
+</body>
+</html>
diff --git a/manuals_and_examples/manuals/index.html b/manuals_and_examples/manuals/index.html
new file mode 100644
index 0000000..f14f431
--- /dev/null
+++ b/manuals_and_examples/manuals/index.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>rasdaman, the intelligent multidimensional raster server</title>
+</head>
+
+<frameset rows="150,*" border=0 frameborder=0 framespacing=0>
+ <frame src="header.html" name=header scrolling=NO noresize marginwidth=0 marginheight=0>
+ <frame src="body.html" name=body marginwidth=0 marginheight=0>
+</frameset>
+
+</body>
+</html>
diff --git a/manuals_and_examples/manuals/logo-rasdaman.gif b/manuals_and_examples/manuals/logo-rasdaman.gif
new file mode 100644
index 0000000..1b62e6c
--- /dev/null
+++ b/manuals_and_examples/manuals/logo-rasdaman.gif
Binary files differ
diff --git a/manuals_and_examples/manuals/logo.gif b/manuals_and_examples/manuals/logo.gif
new file mode 100644
index 0000000..d92bbc6
--- /dev/null
+++ b/manuals_and_examples/manuals/logo.gif
Binary files differ
diff --git a/manuals_and_examples/manuals/pdf/dev-guide-c++.doc b/manuals_and_examples/manuals/pdf/dev-guide-c++.doc
new file mode 100644
index 0000000..0d72b99
--- /dev/null
+++ b/manuals_and_examples/manuals/pdf/dev-guide-c++.doc
Binary files differ
diff --git a/manuals_and_examples/manuals/pdf/dev-guide-c++.pdf b/manuals_and_examples/manuals/pdf/dev-guide-c++.pdf
new file mode 100644
index 0000000..c12d4e4
--- /dev/null
+++ b/manuals_and_examples/manuals/pdf/dev-guide-c++.pdf
Binary files differ
diff --git a/manuals_and_examples/manuals/pdf/dev-guide-java.doc b/manuals_and_examples/manuals/pdf/dev-guide-java.doc
new file mode 100644
index 0000000..93cecb5
--- /dev/null
+++ b/manuals_and_examples/manuals/pdf/dev-guide-java.doc
Binary files differ
diff --git a/manuals_and_examples/manuals/pdf/dev-guide-java.pdf b/manuals_and_examples/manuals/pdf/dev-guide-java.pdf
new file mode 100644
index 0000000..acef92a
--- /dev/null
+++ b/manuals_and_examples/manuals/pdf/dev-guide-java.pdf
Binary files differ
diff --git a/manuals_and_examples/manuals/pdf/external-guide-POSTGRESQL.doc b/manuals_and_examples/manuals/pdf/external-guide-POSTGRESQL.doc
new file mode 100644
index 0000000..1441d95
--- /dev/null
+++ b/manuals_and_examples/manuals/pdf/external-guide-POSTGRESQL.doc
Binary files differ
diff --git a/manuals_and_examples/manuals/pdf/external-guide-POSTGRESQL.pdf b/manuals_and_examples/manuals/pdf/external-guide-POSTGRESQL.pdf
new file mode 100644
index 0000000..91ef5b0
--- /dev/null
+++ b/manuals_and_examples/manuals/pdf/external-guide-POSTGRESQL.pdf
Binary files differ
diff --git a/manuals_and_examples/manuals/pdf/inst-guide.doc b/manuals_and_examples/manuals/pdf/inst-guide.doc
new file mode 100644
index 0000000..32c290f
--- /dev/null
+++ b/manuals_and_examples/manuals/pdf/inst-guide.doc
Binary files differ
diff --git a/manuals_and_examples/manuals/pdf/inst-guide.pdf b/manuals_and_examples/manuals/pdf/inst-guide.pdf
new file mode 100644
index 0000000..9e02c01
--- /dev/null
+++ b/manuals_and_examples/manuals/pdf/inst-guide.pdf
Binary files differ
diff --git a/manuals_and_examples/manuals/pdf/ql-guide.doc b/manuals_and_examples/manuals/pdf/ql-guide.doc
new file mode 100644
index 0000000..9fc02c6
--- /dev/null
+++ b/manuals_and_examples/manuals/pdf/ql-guide.doc
Binary files differ
diff --git a/manuals_and_examples/manuals/pdf/ql-guide.pdf b/manuals_and_examples/manuals/pdf/ql-guide.pdf
new file mode 100644
index 0000000..17ccd8b
--- /dev/null
+++ b/manuals_and_examples/manuals/pdf/ql-guide.pdf
Binary files differ
diff --git a/manuals_and_examples/manuals/pdf/rview-guide.doc b/manuals_and_examples/manuals/pdf/rview-guide.doc
new file mode 100644
index 0000000..0f6f923
--- /dev/null
+++ b/manuals_and_examples/manuals/pdf/rview-guide.doc
Binary files differ
diff --git a/manuals_and_examples/manuals/pdf/rview-guide.pdf b/manuals_and_examples/manuals/pdf/rview-guide.pdf
new file mode 100644
index 0000000..88ba2ea
--- /dev/null
+++ b/manuals_and_examples/manuals/pdf/rview-guide.pdf
Binary files differ
diff --git a/manuals_and_examples/manuals/raslibheader.html b/manuals_and_examples/manuals/raslibheader.html
new file mode 100644
index 0000000..296f798
--- /dev/null
+++ b/manuals_and_examples/manuals/raslibheader.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>rasdaman - the intelligent multidimensional raster server</title>
+</head>
+<body bgcolor="white" style="font-family:Arial,Helvetica,sans-serif">
+
+<table width="100%">
+ <tr>
+ <td>
+ <br>
+ <a href="http://www.rasdaman.com" target="_top"><img src="logo-rasdaman.gif" height="100" alt="rasdaman" border="none"></a>
+ the intelligent multi-dimensional raster server
+ </td>
+ <td align="right" valign="bottom">
+ raslib C++ API Reference
+ <br>
+ Version 5.2
+ </td>
+ </tr>
+</table>
+
+<hr width="100%" size="1">
+
+</body>
+</html>
diff --git a/manuals_and_examples/manuals/raslibindex.html b/manuals_and_examples/manuals/raslibindex.html
new file mode 100644
index 0000000..0205616
--- /dev/null
+++ b/manuals_and_examples/manuals/raslibindex.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>TOC ClassDoc</title>
+</head>
+
+<frameset rows="150,*" border=0 frameborder=0 framespacing=0>
+ <frame src="header.html" name=header scrolling=NO noresize marginwidth=0 marginheight=0>
+ <frame src="HIER.html" name=body marginwidth=0 marginheight=0>
+</frameset>
+
+</body>
+</html>
diff --git a/mddmgr/Makefile.am b/mddmgr/Makefile.am
new file mode 100644
index 0000000..5aac570
--- /dev/null
+++ b/mddmgr/Makefile.am
@@ -0,0 +1,37 @@
+# -*-Makefile-*- (for Emacs)
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+#
+# MAKEFILE FOR:
+# cachetamgr
+#
+# COMMENTS:
+#
+##################################################################
+
+AM_CXXFLAGS=@BASEDBCXXFLAGS@
+
+noinst_LIBRARIES= libmddmgr.a
+libmddmgr_a_SOURCES= mddobj.cc mddobj.hh \
+ mddcoll.cc mddcoll.hh \
+ mddcolliter.cc mddcolliter.icc mddcolliter.hh
+
diff --git a/mddmgr/mddcoll.cc b/mddmgr/mddcoll.cc
new file mode 100644
index 0000000..56a1afe
--- /dev/null
+++ b/mddmgr/mddcoll.cc
@@ -0,0 +1,411 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: mddcoll.cc
+ *
+ * MODULE: cachetamgr
+ * CLASS: MDDColl
+ *
+ * COMMENTS:
+ * none
+ *
+*/
+
+#include "mymalloc/mymalloc.h"
+
+#include <iostream>
+#include "mddcoll.hh"
+#include "mddcolliter.hh"
+#include "relmddif/dbmddset.hh"
+#include "relcatalogif/mdddomaintype.hh"
+#include "relcatalogif/settype.hh"
+#include "mddobj.hh"
+#include "relmddif/dbmddobj.hh"
+#include "reladminif/objectbroker.hh"
+#include "raslib/rmdebug.hh"
+#include "reladminif/oidif.hh"
+#include "relcatalogif/collectiontype.hh" // from base catalogif DBMS interface module
+#include "reladminif/databaseif.hh"
+#include "relmddif/dbmddset.hh"
+#include "reladminif/eoid.hh"
+#include "catalogmgr/typefactory.hh"
+#include "tilemgr/tile.hh"
+
+#include <cstring>
+
+MDDColl::MDDColl(const CollectionType* newType, const char* name)
+ {
+ RMDBGONCE(2, RMDebug::module_mddmgr, "MDDColl", "MDDColl(" << newType->getName() << ", " << (name?name:"null") << ") " << (r_Ptr)this);
+ const char* theName = name;
+ if (theName == NULL)
+ {
+ theName = "rasdaman temporary collection";
+ }
+ dbColl = new DBMDDSet(theName, newType);
+ }
+
+const char*
+MDDColl::getName() const
+ {
+ return dbColl->getName();
+ }
+
+const CollectionType*
+MDDColl::getCollectionType() const
+ {
+ return dbColl->getCollType();
+ }
+
+unsigned long
+MDDColl::getCardinality() const
+ {
+ return dbColl->getCardinality();
+ }
+
+bool
+MDDColl::getOId(OId& pOId) const
+ {
+ if (isPersistent())
+ {
+ pOId = dbColl->getOId();
+ return true;
+ }
+ return false;
+ }
+
+bool
+MDDColl::getEOId(EOId& pEOId) const
+ {
+ if (isPersistent())
+ {
+ pEOId = dbColl->getEOId();
+ return true;
+ }
+ return false;
+ }
+
+void
+MDDColl::insert(const MDDObj* newObj)
+ {
+ RMDBGIF(0, RMDebug::module_mddmgr, "MDDColl", if (newObj == 0) \
+ { \
+ RMInit::dbgOut << "MDDColl::insert(const MDDObj*) assertion failed" << endl;\
+ throw r_Error(MDD_NOT_VALID);\
+ })
+ RMDBGONCE(2, RMDebug::module_mddmgr, "MDDColl", "insert(" << (r_Ptr)newObj << ")")
+ dbColl->insert(newObj->getDBMDDObjId());
+ insertIntoCache(newObj);
+ RMDBGIF(2, RMDebug::module_mddmgr, "MDDColl", dbColl->printStatus(0, RMInit::dbgOut);)
+ }
+
+void
+MDDColl::releaseAll() {
+ MDDObj* tempMDD = 0;
+ while (!mddCache.empty()){
+ tempMDD = (*mddCache.begin()).second;
+ (*mddCache.begin()).second = NULL;
+ delete tempMDD;
+ mddCache.erase(mddCache.begin());
+ }
+}
+
+MDDColl::~MDDColl()
+ {
+ RMDBGONCE(2, RMDebug::module_mddmgr, "MDDColl", "~MDDColl() " << (r_Ptr)this);
+ if (isPersistent())
+ releaseAll();
+ //else released by release transfer structures
+ }
+
+MDDColl::MDDColl(const DBMDDSetId& coll)
+ :dbColl(coll)
+ {
+ }
+
+DBMDDSetId
+MDDColl::getDBMDDSet() const
+ {
+ return dbColl;
+ }
+
+void
+MDDColl::insertIntoCache(const MDDObj* objToInsert) const
+ {
+ RMDBGONCE(2, RMDebug::module_mddmgr, "MDDColl", "insertIntoCache(" << (r_Ptr)objToInsert << ")")
+ mddCache[objToInsert->getDBMDDObjId().ptr()] = (MDDObj*)objToInsert;
+ }
+
+MDDObj*
+MDDColl::getMDDObj(const DBMDDObj* objToGet) const
+ {
+ MDDObj* persMDDObjToGet = NULL;
+ MDDObjMap::const_iterator i = mddCache.find((DBMDDObj*)objToGet);
+ if (i != mddCache.end())
+ persMDDObjToGet = (MDDObj*)(*i).second;
+ else {
+ persMDDObjToGet = new MDDObj((DBMDDObj*)objToGet);
+ insertIntoCache(persMDDObjToGet);
+ }
+ return persMDDObjToGet;
+ }
+
+bool
+MDDColl::isPersistent() const
+ {
+ return dbColl->isPersistent();
+ }
+
+void
+MDDColl::printStatus(unsigned int level, std::ostream& stream) const
+ {
+ dbColl->printStatus(level, stream);
+ char* indent = new char[level*2 +1];
+ for (int j = 0; j < level*2 ; j++)
+ indent[j] = ' ';
+ indent[level*2] = '\0';
+ stream << indent;
+ for (MDDObjMap::iterator i = mddCache.begin(); i != mddCache.end(); i++)
+ {
+ stream << (r_Ptr)(*i).second;
+ }
+ delete[] indent;
+ indent=0;
+ }
+
+MDDCollIter*
+MDDColl::createIterator() const
+ {
+ MDDCollIter* iter = new MDDCollIter((MDDColl*)this);
+ return iter;
+ }
+
+void
+MDDColl::remove(const MDDObj* obj)
+ {
+ if (obj != NULL)
+ {
+ DBMDDObjId t2 = obj->getDBMDDObjId();
+ dbColl->remove(t2);
+
+ //remove from cache ;(
+ MDDObjMap::iterator i = mddCache.find(t2.ptr());
+ if(i != mddCache.end())
+ {
+ RMDBGONCE(2, RMDebug::module_mddmgr, "MDDColl", "remove(" << (r_Ptr)obj << ") found in cache")
+ mddCache.erase(i);
+ }
+ else
+ {
+ RMDBGONCE(0, RMDebug::module_mddmgr, "MDDColl", "remove(" << (r_Ptr)obj << ") not in collection cache")
+ }
+ }
+ else {
+ RMDBGONCE(0, RMDebug::module_mddmgr, "MDDColl", "remove(MDDObj*) NULL");
+ throw r_Error(MDD_NOT_VALID);
+ }
+ }
+
+/*
+void
+MDDColl::removeFromCache(const PersMDDObj* objToRemove)
+ {
+ DBMDDObj* objIdVoidAddress = objToRemove->getDBMDDObjId().ptr();
+ MDDObjMap::iterator i = mddCache.find(objIdVoidAddress);
+
+ if (i != mddCache.end())
+ {
+ persMDDObjToRemove = (*i).second;
+ (*i).second = NULL;
+ delete persMDDObjToRemove;
+ mddCache.erase(i);
+ RMDBGIF(0, RMDebug::module_mddmgr, "MDDColl", \
+ if (mddCache.find(objIdVoidAddress) != mddCache.end()) \
+ { \
+ RMInit::dbgOut << "MDDColl::removeMDDObjfromCache() object multiple times in cache" << endl; \
+ throw r_Error(MDD_EXISTS_MULTIPLE_TIMES); \
+ })
+ }
+ else {
+ RMDBGONCE(0, RMDebug::module_mddmgr, "MDDColl", "removeMDDObjfromCache(" << objToRemove << ") not in collection")
+ }
+ }
+*/
+
+void
+MDDColl::removeAll()
+ {
+ dbColl->removeAll();
+ }
+
+
+const char*
+MDDColl::AllCollectionnamesName = "RAS_COLLECTIONNAMES";
+
+MDDColl*
+MDDColl::createMDDCollection(const char* name, const CollectionType* ct) throw (r_Error)
+ {
+ if (name == NULL)
+ {
+ RMDBGONCE(0, RMDebug::module_mddmgr, "MDDColl", "createMDDColl(NULL, colltype)")
+ throw r_Error(r_Error::r_Error_NameNotUnique);
+ }
+ if (ct == NULL)
+ {
+ RMDBGONCE(0, RMDebug::module_mddmgr, "MDDColl", "createMDDColl(" << name << ", NULL)")
+ throw r_Error(COLLTYPE_NULL);
+ }
+ if (!ct->isPersistent())
+ {
+ r_Error t(209);
+ t.setTextParameter("type", ct->getName());
+ RMDBGONCE(0, RMDebug::module_mddmgr, "MDDColl", "createMDDColl(" << name << ", " << ct->getName() << " not persistent)")
+ throw t;
+ }
+ // may generate an exception:
+ DBMDDSetId newDBColl = new DBMDDSet(name, ct);
+ return new MDDColl(newDBColl);
+ }
+
+MDDColl*
+MDDColl::createMDDCollection(const char* name, const OId& o, const CollectionType* ct) throw (r_Error)
+ {
+ // may generate an exception:
+ if (name == NULL)
+ {
+ RMDBGONCE(0, RMDebug::module_mddmgr, "MDDColl", "createMDDColl(NULL, " << o << ", colltype)")
+ throw r_Error(r_Error::r_Error_NameNotUnique);
+ }
+ if (ct == NULL)
+ {
+ RMDBGONCE(0, RMDebug::module_mddmgr, "MDDColl", "createMDDColl(" << name << ", " << o << ", NULL)")
+ throw r_Error(COLLTYPE_NULL);
+ }
+ if (!ct->isPersistent())
+ {
+ r_Error t(209);
+ t.setTextParameter("type", ct->getName());
+ RMDBGONCE(0, RMDebug::module_mddmgr, "MDDColl", "createMDDColl(" << name << ", " << o << ", " << ct->getName() << " not persistent)")
+ throw t;
+ }
+ DBMDDSetId newDBColl = new DBMDDSet(name, o, ct);
+ return new MDDColl(newDBColl);
+ }
+
+bool
+MDDColl::dropMDDCollection(const char* name)
+ {
+ return DBMDDSet::deleteDBMDDSet(name);
+ }
+
+bool
+MDDColl::dropMDDCollection(const OId& o)
+ {
+ return DBMDDSet::deleteDBMDDSet(o);
+ }
+
+MDDColl*
+MDDColl::getMDDCollection(const OId& collOId) throw (r_Error)
+ {
+ RMDBGENTER(2, RMDebug::module_mddmgr, "MDDColl", "getMDDCollection(" << collOId << ")")
+ DBMDDSetId t(collOId);
+ //this will throw an exception
+ t->isModified();
+ MDDColl* retval = new MDDColl(t);
+ RMDBGEXIT(2, RMDebug::module_mddmgr, "MDDColl", "getMDDCollection(" << collOId << ") " << retval)
+ return retval;
+ }
+
+MDDColl*
+MDDColl::getMDDCollection(const char* collName) throw (r_Error)
+ {
+ RMDBGENTER(2, RMDebug::module_mddmgr, "MDDColl", "getMDDCollection(" << collName << ")")
+ MDDColl* retval = 0;
+ DBMDDSetId dbset;
+ if (strcmp(collName, AllCollectionnamesName) == 0)
+ {
+ r_Minterval transDomain("[0:*]");
+ r_Minterval nameDomain("[0:0]");
+ const BaseType* bt = TypeFactory::mapType("Char");
+ MDDDomainType* mt = new MDDDomainType("RAS_NAMETYPE", bt, transDomain);
+ TypeFactory::addTempType(mt);
+ CollectionType* ct = new SetType("RAS_NAMESETTYPE", mt);
+ TypeFactory::addTempType(ct);
+ retval = new MDDColl(ct, AllCollectionnamesName);
+ OIdSet* list = ObjectBroker::getAllObjects(OId::MDDCOLLOID);
+ MDDObj* transObj = 0;
+ Tile* transTile = 0;
+ char* transName = 0;
+ const char* nameBuffer = 0;
+ r_Range namelen = 0;
+ while (!list->empty())
+ {
+ dbset = *(list->begin());
+ RMDBGMIDDLE(2, RMDebug::module_mddmgr, "MDDColl", "Coll OId : " << dbset.getOId())
+ nameBuffer = dbset->getName();
+ RMDBGMIDDLE(2, RMDebug::module_mddmgr, "MDDColl", "Coll Name : " << nameBuffer)
+ namelen = strlen(nameBuffer);
+ RMDBGMIDDLE(2, RMDebug::module_mddmgr, "MDDColl", "Coll Name Len: " << namelen)
+ transName = (char*)mymalloc(sizeof(char) * (namelen + 1));
+ memset(transName, 0, namelen + 1);
+ strcpy(transName, nameBuffer);
+ RMDBGMIDDLE(2, RMDebug::module_mddmgr, "MDDColl", "Domain : " << namelen)
+ nameDomain[0].set_high((r_Range)namelen);
+ transObj = new MDDObj(mt, nameDomain);
+ transTile = new Tile(nameDomain, bt, transName, 0, r_Array);
+ transObj->insertTile(transTile);
+ retval->insert(transObj);
+ list->erase(list->begin());
+ }
+ delete list;
+ }
+ else {
+ dbset = DBMDDSet::getDBMDDSet(collName);
+ retval = new MDDColl(dbset);
+ }
+ RMDBGEXIT(2, RMDebug::module_mddmgr, "MDDColl", "getMDDCollection(" << collName << ") " << retval)
+ return retval;
+ }
+
+bool
+MDDColl::removeMDDObject(const OId& collOId, const OId& mddOId)
+ {
+ bool retval = true;
+ DBMDDSetId coll(collOId);
+ DBMDDObjId mdd(mddOId);
+
+ if (coll.is_null())
+ {//does not exist
+ retval = false;
+ }
+ else {
+ if (mdd.is_null())
+ {
+ retval = false;
+ }
+ else {
+ coll->remove(mdd);
+ }
+ }
+ return retval;
+ }
+
diff --git a/mddmgr/mddcoll.hh b/mddmgr/mddcoll.hh
new file mode 100644
index 0000000..c44cb8f
--- /dev/null
+++ b/mddmgr/mddcoll.hh
@@ -0,0 +1,254 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: mddcoll.hh
+ *
+ * MODULE: cachetamgr
+ * CLASS: MDDColl
+ *
+ * COMMENTS:
+ *
+*/
+
+#ifndef _MDDCOLL_HH_
+#define _MDDCOLL_HH_
+
+#include <iostream>
+#include <map>
+#include <stdlib.h>
+
+#include "mddobj.hh"
+#include "mddcolliter.hh"
+#include "mddcoll.hh"
+#include "reladminif/oidif.hh"
+#include "raslib/error.hh"
+#include "relmddif/mddid.hh"
+#include "relcatalogif/collectiontype.hh" // from catalogif base DBMS interface module
+
+class CollectionType;
+class DatabaseIf;
+
+//@ManMemo: Module: {\bf cachetamgr}
+/*@Doc:
+ An MDDColl object is a collection of references to MDD objects.
+ This class is the abstract base class for all persistent and
+ transient collection classes.
+
+ The objects pointed to by the collection exist in a storage domain
+ which may be either the main memory for the transient collections
+ or the database for the persistent cases.
+
+ An MDDColl is responsible for managing the memory allocated for the
+ MDDObjs which belong to it. In the future, more functions will be provided
+ to allow selected releasing or keeping of MDD objects in an MDDColl.
+
+ {\bf Example }
+
+ {\tt MDDObj* accessedObj; }
+
+ {\tt MDDColl* mddObjsColl; }
+
+ {\tt mddObjsColl = new ... }
+
+ {\tt // Initialize mddObjsColl to a PersMDDColl or TransMDDColl. }
+
+ {\tt MDDCollIter* objsIt = mddObjsColl->createIterator(); }
+
+ {\tt for(int i = 1 ; objsIt->notDone(); i++, objsIt->advance()) }
+
+ {\tt \{ }
+
+ {\tt accessedObj = objsIt->getElement(); }
+
+ {\tt ...}
+
+ {\tt } }
+
+ {\tt delete objsIt; // Deallocate iterator. }
+
+ {\tt ... // Here accessedObj may be used. }
+
+ {\tt mddObjsColl->releaseAll(); }
+
+ {\bf {\tt ... // In this part accessedObj is no longer valid. } }
+
+ {\tt delete mddObjsColl; }
+*/
+
+class MDDColl
+ {
+
+ public:
+ ///transient collection
+ MDDColl(const CollectionType* newType, const char* name = 0);
+
+ static const char* AllCollectionnamesName;
+
+ static MDDColl* getMDDCollection(const char* collName) throw (r_Error);
+ /**
+ Retrieve a mdd collection from database.
+ Throws r_Error::r_Error_ObjectUnknown if the name is unknown.
+ */
+
+ static MDDColl* getMDDCollection(const OId& collOId) throw (r_Error);
+ /**
+ Retrieve a mdd collection from database.
+ Throws r_Error::r_Error_ObjectUnknown if the oid is unknown.
+ */
+
+ static MDDColl* createMDDCollection(const char* name, const CollectionType* ct) throw (r_Error);
+ /**
+ Throws r_Error::r_Error_NameNotUnique if the name exists already or is NULL.
+ */
+
+ static MDDColl* createMDDCollection(const char* name, const OId& o, const CollectionType* ct) throw (r_Error);
+ /**
+ Throws r_Error::r_Error_NameNotUnique if the name exists already or is NULL.
+ Throws r_Error::r_Error_OIdNotUnique if the oid exists already.
+ */
+ static bool dropMDDCollection(const char* name);
+ /**
+ Delete a mdd collection from database.
+ Returns false if the name is unknown.
+ */
+
+ static bool dropMDDCollection(const OId& id);
+ /**
+ Delete a mdd collection from database.
+ Returns false if the oid is unknown.
+ */
+
+ static bool removeMDDObject(const OId& coll, const OId& id);
+ /**
+ Remove an mdd object from the collection.
+ Returns always true.
+ */
+
+ void printStatus(unsigned int level = 0, ostream& stream = cout) const;
+ /**
+ Prints current status of the MDD Collection.
+ */
+
+ const CollectionType* getCollectionType() const;
+ /**
+ Returns the type of this MDD collection.
+ */
+
+ unsigned long getCardinality() const;
+ /**
+ Returns the cardinality of the collection.
+ */
+
+ bool getOId(OId& pOId) const;
+ /**
+ Returns true if collection has an OId.
+ */
+
+ bool getEOId(EOId& pEOId) const;
+ /**
+ Returns true0 if collection has an EOId.
+ */
+
+ void insert(const MDDObj* newObj);
+ /**
+ Inserts reference to MDD object into the collection.
+ If the type of the object (transient/persistent) does not fit the collection an exception is thrown.
+ */
+
+ MDDCollIter* createIterator() const;
+ /**
+ Creates a new iterator for this collection. Returns a pointer to the new allocated iterator object. Returned pointer must be freed afterwards.
+ */
+
+ void remove(const MDDObj* obj);
+ /**
+ Remove reference to MDD object from the current collection. The object itself is not obligatorily destroyed from the storage domain where it exists. If the object does not live in the collection nothing is done.
+ */
+
+ void removeAll();
+ /**
+ Empties the current collection by removing all references to MDD objects from it.
+ The objects are not obligatorily destroyed from the storage domain where they exist.
+ */
+
+ void releaseAll();
+ /**
+ Releases all dynamic memory allocated for the current collection.
+ This method has to be called explicitely, since the destructor doesn't deallocate memory for the elements of the collection.
+ The reason for this is to allow the user to use MDDObjs from this collection, even after the collection itself is no longer in main memory.
+ This is only true for transient collections.
+ */
+
+ bool isPersistent() const;
+ /**
+ Tells if collection is persistent.
+ */
+
+ const char* getName() const;
+
+ ~MDDColl();
+ /**
+ Doesn't free main memory allocated for the objects of the collection.
+ See ReleaseAll() for an explanation on this issue. Even if it does nothing, it has to be defined because derived classes may have non-trivial destructors.
+ */
+ protected:
+
+ friend class MDDCollIter;
+
+ MDDObj* getMDDObj(const DBMDDObj*) const;
+ /**
+ Will get from cache/instantiate and return an MDDObj.
+ Instantiation: it will just create a new one if isPersistent() == true -> passing it a oid that does not belong to the collection -> problem.
+ **/
+
+ MDDColl(const DBMDDSetId& coll);
+
+ DBMDDSetId getDBMDDSet() const;
+ /**
+ Return the reference to the actual persistent object in the base DBMS.
+ returned reference must be const -> impossible
+ */
+
+ void insertIntoCache(const MDDObj* objToInsert) const;
+ /**
+ Insert persistent MDD object in the internal cache.
+ */
+
+ //void removeFromCache(DBMDDObjId& objToGet);
+
+ DBMDDSetId dbColl;
+ /**
+ Pointer to the actual class stored in the base DBMS.
+ Based on the Base DBMS DBMDDSet class from relmddif.
+ */
+
+ typedef std::map<DBMDDObj*, MDDObj*, std::less<DBMDDObj*> > MDDObjMap;
+ mutable MDDObjMap mddCache;
+ /**
+ The mdd objs that are instantiated may not be twice in memory. Therefore it has to be checked if an mdd obj was already created for a specific dbmddobj.
+ This is achieved by maintaining this map.
+ */
+ };
+
+#endif
+
diff --git a/mddmgr/mddcolliter.cc b/mddmgr/mddcolliter.cc
new file mode 100644
index 0000000..bcf5092
--- /dev/null
+++ b/mddmgr/mddcolliter.cc
@@ -0,0 +1,110 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: persmddcolliter.cc
+ *
+ * MODULE: cachetamgr
+ * CLASS: MDDCollIter
+ *
+ * COMMENTS:
+ * none
+ *
+*/
+
+#include <iostream>
+
+#include "mddcolliter.hh"
+#include "mddcoll.hh"
+#include "mddobj.hh"
+#include "relmddif/dbmddobj.hh"
+#include "relmddif/dbmddset.hh"
+#include "reladminif/dbobjectiditerator.hh"
+#include "raslib/rmdebug.hh"
+
+MDDCollIter::MDDCollIter(MDDColl* targetColl)
+ : dbIter(0),
+ persColl(targetColl)
+ {
+ RMDBGONCE(2, RMDebug::module_mddmgr, "MDDCollIter", "MDDCollIter(" << targetColl->getName() << ")");
+ dbColl = targetColl->getDBMDDSet();
+ dbIter = dbColl->newIterator();
+ }
+
+void
+MDDCollIter::printStatus(unsigned int level, ostream& stream) const
+ {
+ stream << " MDDCollIter printStatus: " ;
+ }
+
+MDDObj*
+MDDCollIter::getElement() const
+ {
+ RMDBGENTER(2, RMDebug::module_mddmgr, "MDDCollIter", "getElement()");
+ // Initialization to null: make sure null pointer is returned if the
+ // collection is empty or if the iterator has come to the end already
+
+ MDDObj* persEl = NULL;
+
+ if (dbIter->not_done())
+ {
+ DBMDDObjId el = dbIter->get_element();
+
+ if (!el.is_null())
+ {
+ persEl = persColl->getMDDObj((DBMDDObj*)el);
+ }
+ }
+
+ // persEl is null if there is nothing to return
+ RMDBGEXIT(2, RMDebug::module_mddmgr, "MDDCollIter", "getElement() " << (r_Ptr)persEl);
+ return persEl;
+ }
+
+void
+MDDCollIter::reset()
+ {
+ RMDBGONCE(2, RMDebug::module_mddmgr, "MDDCollIter", "reset()");
+ dbIter->reset();
+ }
+
+bool
+MDDCollIter::notDone() const
+ {
+ RMDBGONCE(2, RMDebug::module_mddmgr, "MDDCollIter", "notDone()");
+ return dbIter->not_done();
+ }
+
+void
+MDDCollIter::advance()
+ {
+ RMDBGONCE(2, RMDebug::module_mddmgr, "MDDCollIter", "advance()");
+ dbIter->advance();
+ }
+
+MDDCollIter::~MDDCollIter()
+ {
+ RMDBGONCE(2, RMDebug::module_mddmgr, "MDDCollIter", "~MDDCollIter()");
+ delete dbIter;
+ dbIter = NULL;
+ }
+
diff --git a/mddmgr/mddcolliter.hh b/mddmgr/mddcolliter.hh
new file mode 100644
index 0000000..0f86209
--- /dev/null
+++ b/mddmgr/mddcolliter.hh
@@ -0,0 +1,97 @@
+#ifndef _MDDCOLLITER_HH_
+#define _MDDCOLLITER_HH_
+
+class MDDCollIter;
+class MDDColl;
+class MDDObj;
+
+#include "mddobj.hh"
+#include "relmddif/mddid.hh" // from mddif interface module
+
+#include <stdlib.h>
+#include <iostream>
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: persmddcolliter.hh
+ *
+ * MODULE: cachetamgr
+ * CLASS: MDDCollIter
+ *
+ * COMMENTS:
+ * Check List:
+ * - printStatus
+ * - Functionality: stream operator, inc/dec operators,...
+ *
+*/
+
+
+//@ManMemo: Module: {\bf cachetamgr}
+/*@Doc:
+ A MDDCollIter represents an iterator for a persistent MDD collection.
+ If a collection is changed (elements are removed or added to/from the
+ collection) between creation of an iterator for it and the execution of
+ other operations on the iterator, the behavior of the istent Iterator
+ is undefined.
+ The {\tt MDDColl::createIterator()} for the object to be scanned should
+ be used to create a new iterator object.
+*/
+
+class MDDCollIter
+ {
+ public:
+ void printStatus(unsigned int level = 0, ostream& stream = cout) const;
+
+ void reset();
+
+ bool notDone() const;
+
+ void advance();
+
+ MDDObj* getElement() const;
+
+ ~MDDCollIter();
+
+ protected:
+
+ friend class MDDColl;
+
+ MDDCollIter(MDDColl* targetColl);
+ /**
+ Constructor - to be used only by MDDColl
+ The iterator is reset after it is created.
+ */
+
+ private:
+
+ // Corresponding iterator in the base DBMS.
+ DBMDDObjIdIter* dbIter;
+
+ // dbColl has to be kept because of error control.
+ DBMDDSetId dbColl;
+
+ // Collection to iterate.
+ MDDColl* persColl;
+ };
+
+#endif
diff --git a/mddmgr/mddcolliter.icc b/mddmgr/mddcolliter.icc
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/mddmgr/mddcolliter.icc
diff --git a/mddmgr/mddobj.cc b/mddmgr/mddobj.cc
new file mode 100644
index 0000000..59cc4aa
--- /dev/null
+++ b/mddmgr/mddobj.cc
@@ -0,0 +1,392 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: persmddobj.cc
+ *
+ * MODULE: cachetamgr
+ * CLASS: MDDObj
+ *
+ * COMMENTS:
+ * none
+ *
+*/
+
+#include "mymalloc/mymalloc.h"
+
+static const char rcsid[] = "@(#)persmddobj, PersMDDObj: $Id: mddobj.cc,v 1.26 2005/07/06 22:43:20 rasdev Exp $";
+
+#include <iostream>
+#include <stdlib.h>
+#include <cstring>
+
+#include "mddobj.hh"
+#include "relmddif/dbmddobj.hh"
+#include "relindexif/indexid.hh"
+#include "reladminif/eoid.hh"
+
+#include "tilemgr/tile.hh"
+#include "relcatalogif/mdddomaintype.hh"
+#include "raslib/mddtypes.hh"
+#include "raslib/rmdebug.hh"
+#include "indexmgr/mddobjix.hh"
+
+const r_Minterval&
+MDDObj::checkStorage(const r_Minterval& domain2) throw (r_Error)
+ {
+ r_Minterval domain(domain2.dimension());
+ if (myStorageLayout->getIndexType() == r_Reg_Computed_Index)
+ {
+ if (myStorageLayout->getTilingScheme() != r_RegularTiling)
+ {
+ RMInit::logOut << "MDDObj::checkStorage(" << domain2 << ") the rc index needs a regular tiling defined" << endl;
+ throw r_Error(RCINDEXWITHOUTREGULARTILING);
+ }
+ r_Dimension dim = domain2.dimension();
+ // make sure the tileConfig is fixed
+ r_Minterval tileConfig = myStorageLayout->getTileConfiguration();
+ myStorageLayout->setTileConfiguration(tileConfig);
+ r_Point mddDomainExtent = domain2.get_extent();
+ r_Point tileConfigExtent = tileConfig.get_extent();
+ for (r_Dimension i = 0; i < dim; i++)
+ {
+ if (!domain2[i].is_high_fixed() || !domain2[i].is_low_fixed() || !tileConfig[i].is_high_fixed() || !tileConfig[i].is_low_fixed())
+ {
+ RMInit::logOut << "MDDObj::checkStorage(" << domain2 << ") the rc index needs a domain and tile configuration with fixed domains in all dimensions. Dimension " << i << " seems not to be fixed." << endl;
+ throw r_Error(RCINDEXWITHINCOMPATIBLEMARRAYTYPE);
+ }
+ if (mddDomainExtent[i]%tileConfigExtent[i] != 0)
+ {
+ RMInit::logOut << "MDDObj::checkStorage(" << domain2 << ") the tile configuration (" << tileConfig << ") does not fit the domain of the marray (" << domain << ")." << endl;
+ throw r_Error(TILECONFIGMARRAYINCOMPATIBLE);
+ }
+ }
+ }
+ return domain2;
+ }
+
+MDDObj::MDDObj(const MDDBaseType* mddType, const r_Minterval& domain)
+ : myMDDIndex(NULL),
+ myDBMDDObj(),
+ myStorageLayout(NULL)
+ {
+ if (!mddType)
+ {
+ RMInit::logOut << "MDD type is NULL. Please report query or raslib program to Customer Support." << endl;
+ throw r_Error(MDDTYPE_NULL);
+ }
+
+ RMDBGONCE(2, RMDebug::module_mddmgr, "MDDObj", "MDDObj(" << mddType->getName() << ", " << domain << ") " << (r_Ptr)this);
+ myStorageLayout = new StorageLayout(r_Directory_Index);
+ myMDDIndex = new MDDObjIx(*myStorageLayout, domain);
+ myDBMDDObj = new DBMDDObj(mddType, domain, myMDDIndex->getDBMDDObjIxId(), myStorageLayout->getDBStorageLayout());
+ }
+
+MDDObj::MDDObj(const MDDBaseType* mddType, const r_Minterval& domain, const OId& newOId, const StorageLayout& ms) throw (r_Error)
+ : myMDDIndex(NULL),
+ myDBMDDObj(),
+ myStorageLayout(NULL)
+ {
+ if (!mddType)
+ {
+ RMInit::logOut << "MDD type is NULL. Please report query or raslib program to Customer Support." << endl;
+ throw r_Error(MDDTYPE_NULL);
+ }
+
+ RMDBGONCE(2, RMDebug::module_mddmgr, "MDDObj", "MDDObj(" << mddType->getName() << ", " << domain << ", " << newOId << ", " << ms.getDBStorageLayout().getOId() << ") " << (r_Ptr)this);
+ myStorageLayout = new StorageLayout(ms);
+ myMDDIndex = new MDDObjIx(*myStorageLayout, checkStorage(domain), mddType->getBaseType());
+ myDBMDDObj = new DBMDDObj(mddType, domain, myMDDIndex->getDBMDDObjIxId(), ms.getDBStorageLayout(), newOId);
+ }
+
+MDDObj::MDDObj(const DBMDDObjId& dbmddobj) throw(r_Error)
+ : myMDDIndex(NULL),
+ myDBMDDObj(dbmddobj),
+ myStorageLayout(NULL)
+ {
+ RMDBGONCE(2, RMDebug::module_mddmgr, "MDDObj", "MDDObj(DBRef " << dbmddobj.getOId() << ") " << (r_Ptr)this);
+ myStorageLayout = new StorageLayout(myDBMDDObj->getDBStorageLayout());
+ myMDDIndex = new MDDObjIx(myDBMDDObj->getDBIndexDS(), *myStorageLayout, myDBMDDObj->getMDDBaseType()->getBaseType());
+ }
+
+MDDObj::MDDObj(const OId& givenOId) throw(r_Error)
+ : myMDDIndex(NULL),
+ myDBMDDObj(OId()),
+ myStorageLayout(NULL)
+ {
+ RMDBGONCE(2, RMDebug::module_mddmgr, "MDDObj", "MDDObj(" << givenOId << ") " << (r_Ptr)this);
+ myDBMDDObj = DBMDDObjId(givenOId);
+ myStorageLayout = new StorageLayout(myDBMDDObj->getDBStorageLayout());
+ myMDDIndex = new MDDObjIx(myDBMDDObj->getDBIndexDS(), *myStorageLayout, myDBMDDObj->getMDDBaseType()->getBaseType());
+ }
+
+MDDObj::MDDObj(const MDDBaseType* mddType, const r_Minterval& domain, const StorageLayout& ms)
+ : myMDDIndex(NULL),
+ myDBMDDObj(OId()),
+ myStorageLayout(NULL)
+ {
+ RMDBGONCE(2, RMDebug::module_mddmgr, "MDDObj", "MDDObj(" << mddType->getName() << ", " << domain << ", " << ms.getDBStorageLayout().getOId() << ") " <<(r_Ptr)this);
+ if (!mddType)
+ {
+ RMInit::logOut << "MDD type is NULL. Please report query or raslib program to Customer Support." << endl;
+ throw r_Error(MDDTYPE_NULL);
+ }
+ myStorageLayout = new StorageLayout(ms);
+ myMDDIndex = new MDDObjIx(*myStorageLayout, checkStorage(domain), mddType->getBaseType());
+ myDBMDDObj = new DBMDDObj(mddType, domain, myMDDIndex->getDBMDDObjIxId(), ms.getDBStorageLayout());
+ myDBMDDObj->setPersistent();
+ }
+
+
+/*
+insert tile:
+ tiles may have to be retiled.
+ the storage layout returns the domains into which the tile should be divided before insertion.
+ if there is not enough data to fill a complete layout domain, then 0 will be set.
+*/
+void
+MDDObj::insertTile(Tile* newTile)
+ {
+ RMDBGENTER(2, RMDebug::module_mddmgr, "MDDObj", "insertTile(Tile " << newTile->getDomain() << ")")
+ std::vector <r_Minterval> layoutDoms = myStorageLayout->getLayout(newTile->getDomain());
+RMDBGIF(10, RMDebug::module_mddmgr, "printlayoutdoms", \
+ RMDBGMIDDLE(2, RMDebug::module_mddmgr, "MDDObj", "storage layout returned the following domains") \
+ for (std::vector <r_Minterval>::iterator domit = layoutDoms.begin(); domit != layoutDoms.end(); domit++) \
+ RMDBGMIDDLE(2, RMDebug::module_mddmgr, "MDDObj", *domit) \
+ RMDBGMIDDLE(2, RMDebug::module_mddmgr, "MDDObj", "end of storage layout domains"))
+
+ Tile* tile = NULL;
+ Tile* tile2 = NULL;
+ r_Area tempArea = 0;
+ r_Area completeArea = 0;
+ r_Minterval tempDom;
+ r_Minterval tileDom = newTile->getDomain();
+ std::vector<Tile*>* indexTiles = NULL;
+ char* newContents = NULL;
+ size_t sizeOfData = 0;
+ bool checkEquality = true;
+ for (std::vector<r_Minterval>::iterator it = layoutDoms.begin(); it != layoutDoms.end(); it++)
+ {
+ if (checkEquality && tileDom == *it)
+ {// normal case. just insert the tile.
+ // this case also means that there was no insertion in the previous loops
+ RMDBGMIDDLE(2, RMDebug::module_mddmgr, "MDDObj", "tile domain is same as layout domain, just inserting data")
+ myMDDIndex->insertTile((Tile*)newTile);
+ // set to NULL so it will not get deleted at the end of the method
+ newTile = NULL;
+ if (layoutDoms.size() != 1)
+ {
+ RMInit::logOut << "MDDObj::insertTile(Tile " << tileDom << ") the layout has more than one element but the tile domain completely covers the layout domain" << endl;
+ throw r_Error(LAYOUTALGORITHMPROBLEM);
+ }
+ }
+ else {// we need to check if there is already a tile defined here
+ // this could have been created in a previous loop run
+ // we are using retiling here. *it is therefore an indivisible layout domain.
+ RMDBGMIDDLE(2, RMDebug::module_mddmgr, "MDDObj", "tile domain (" << tileDom << ") is not the same as layout domain (" << *it << ")")
+ indexTiles = myMDDIndex->intersect(*it);
+ if (indexTiles)
+ {// there was a tile in the run before, which overlapped with this layout domain
+ // there may only be one entry in the index for this domain.
+ RMDBGMIDDLE(2, RMDebug::module_mddmgr, "MDDObj", "found tiles (" << indexTiles->size() << ") in layout domain " << *it)
+ if (indexTiles->size() != 1)
+ {
+ RMInit::logOut << "MDDObj::insertTile(Tile " << tileDom << ") the index contains many entries for one layout domain" << endl;
+ throw r_Error(LAYOUTALGORITHMPROBLEM);
+ }
+ // update the existing tile with the new data
+ tempDom = (*it).create_intersection(tileDom);
+ (*(indexTiles->begin()))->copyTile(tempDom, newTile, tempDom);
+ //RMInit::dbgOut << "updated tile to" << endl;
+ // (*(indexTiles->begin()))->printStatus(99,RMInit::dbgOut);
+ }
+ else {// there was no tile overlapping the current layout domain yet
+ // create a new tile covering the whole layout domain
+ // must be computed everytime because layoutDoms may change in size
+ RMDBGMIDDLE(2, RMDebug::module_mddmgr, "MDDObj", "found no tiles in layout domain " << *it)
+ // generate a tile of the domain : layout domain
+ completeArea = (*it).cell_count();
+ sizeOfData = sizeof(char) * completeArea * getMDDBaseType()->getBaseType()->getSize();
+ newContents = (char*)mymalloc(sizeOfData);
+ // initialise to 0
+ memset(newContents, 0, sizeOfData);
+ tile = new Tile(*it, getMDDBaseType()->getBaseType(), newContents, 0, newTile->getDataFormat());
+ tile->setParameters(newTile->getParameters());
+ tempDom = (*it).create_intersection(tileDom);
+ // only update the actual data - the rest was set to 0
+ tile->copyTile(tempDom, newTile, tempDom);
+ RMDBGMIDDLE(2, RMDebug::module_mddmgr, "MDDObj", "created tile with domain " << tile->getDomain())
+ //RMInit::dbgOut << "insert tile" << endl;
+ // tile->printStatus(99,RMInit::dbgOut);
+ //FIXME: should not be neccessary
+ tile->compress();
+ myMDDIndex->insertTile((Tile*)tile);
+ }
+ }
+ checkEquality = false;
+ }
+ if (newTile)
+ {
+ RMDBGMIDDLE(2, RMDebug::module_mddmgr, "MDDObj", "have to delete newTile")
+ if (newTile->isPersistent())
+ ((Tile*)newTile)->getDBTile()->setPersistent(false);
+ delete newTile;
+ }
+ RMDBGEXIT(2, RMDebug::module_mddmgr, "MDDObj", "insertTile(Tile)")
+ }
+
+std::vector< Tile* >*
+MDDObj::intersect(const r_Minterval& searchInter) const
+ {
+ std::vector<Tile*>* retval = myMDDIndex->intersect(searchInter);
+RMDBGIF(10, RMDebug::module_mddmgr, "printtiles", \
+ if (retval) \
+ { \
+ int t = RManDebug; \
+ RManDebug = 0; \
+ for (std::vector<Tile*>::iterator it = retval->begin(); it != retval->end();it++) \
+ { \
+ RMInit::dbgOut << "FOUND " << (*it)->getDomain() << " " << endl; \
+ (*it)->printStatus(0, RMInit::dbgOut); \
+ } \
+ RManDebug = t; \
+ })
+ return retval;
+ }
+
+std::vector< Tile* >*
+MDDObj::getTiles() const
+ {
+ return myMDDIndex->getTiles();
+ }
+
+char*
+MDDObj::pointQuery(const r_Point& searchPoint)
+ {
+ return myMDDIndex->pointQuery(searchPoint);
+ }
+
+const char*
+MDDObj::pointQuery(const r_Point& searchPoint) const
+ {
+ return myMDDIndex->pointQuery(searchPoint);
+ }
+
+DBMDDObjId
+MDDObj::getDBMDDObjId() const
+ {
+ return myDBMDDObj;
+ }
+
+const MDDBaseType*
+MDDObj::getMDDBaseType() const
+ {
+ return myDBMDDObj->getMDDBaseType();
+ }
+
+r_Minterval
+MDDObj::getDefinitionDomain() const
+ {
+ return myDBMDDObj->getDefinitionDomain();
+ }
+
+r_Minterval
+MDDObj::getCurrentDomain() const
+ {
+ return myMDDIndex->getCurrentDomain();
+ }
+
+const char*
+MDDObj::getCellTypeName() const
+ {
+ return myDBMDDObj->getCellTypeName();
+ }
+
+const BaseType*
+MDDObj::getCellType() const
+ {
+ return myDBMDDObj->getCellType();
+ }
+
+r_Dimension
+MDDObj::getDimension() const
+ {
+ return myDBMDDObj->dimensionality();
+ }
+
+bool
+MDDObj::isPersistent() const
+ {
+ return myDBMDDObj->isPersistent();
+ }
+
+
+int
+MDDObj::getOId(OId* pOId) const
+ {
+ *pOId = myDBMDDObj->getOId();
+ return (pOId->getCounter() == 0);
+ }
+
+int
+MDDObj::getEOId(EOId* pEOId) const
+ {
+ *pEOId = myDBMDDObj->getEOId();
+ return (pEOId->getCounter() == 0);
+ }
+
+void
+MDDObj::printStatus(unsigned int level, std::ostream& stream) const
+ {
+ myDBMDDObj->printStatus(level, stream);
+ myMDDIndex->printStatus(level, stream);
+ }
+
+void
+MDDObj::removeTile(Tile*& tileToRemove)
+ {
+ int found = myMDDIndex->removeTile(tileToRemove);
+ if (found)
+ {
+ // frees its memory. Persistent freeing??
+ RMDBGONCE(2, RMDebug::module_mddmgr, "MDDObj", "removeTile() about to delete tile")
+ ((Tile*) tileToRemove)->getDBTile().delete_object();
+ delete tileToRemove;
+ tileToRemove = 0;
+ }
+ }
+
+MDDObj::~MDDObj()
+ {
+ RMDBGONCE(2, RMDebug::module_mddmgr, "MDDObj", "~MDDObj() " << (r_Ptr)this)
+
+ delete myMDDIndex;
+ myMDDIndex = NULL;
+ delete myStorageLayout;
+ myStorageLayout = NULL;
+ }
+
+void
+MDDObj::releaseTiles()
+ {
+ myMDDIndex->releasePersTiles();
+ }
diff --git a/mddmgr/mddobj.hh b/mddmgr/mddobj.hh
new file mode 100644
index 0000000..a444681
--- /dev/null
+++ b/mddmgr/mddobj.hh
@@ -0,0 +1,255 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: mddobj.hh
+ *
+ * MODULE: cachetamgr
+ * CLASS: MDDObj
+ *
+ * COMMENTS:
+ *
+*/
+
+#ifndef _MDDOBJ_HH_
+#define _MDDOBJ_HH_
+
+#include <vector>
+
+#include "tilemgr/tile.hh"
+#include "relcatalogif/mddbasetype.hh" // from catalogif base DBMS class
+#include "raslib/minterval.hh"
+#include "storagemgr/sstoragelayout.hh"
+#include "relmddif/mddid.hh"
+
+class MDDObjIx;
+
+//@ManMemo: Module: {\bf cachetamgr}
+/*@Doc:
+
+An MDDObj object (Multidimensional Discrete Data Object) is a multidimensional array of cells of a fixed base type.
+Each MDDObj object keeps information about its cell base type, definition domain, the storage layout and the index.
+Actual data is stored in tiles which are linked to the MDDObj via the index.
+
+When the object is first created, a spatial {\bf definition domain} for the object is given, which specifies the extents of the object array. This is expressed through an interval which may have open bounds along some (or all) directions.
+An open bound along a direction specifies that the object may grow arbitrarily along this direction.
+
+At each point in time, an MDDObj has a fixed {\bf current domain} which specifies the actual extent of the object at the moment.
+The current domain is an interval with fixed bounds corresponding to the coverage of all the tiles already inserted in the MDDObj.
+The current domain should be a subinterval of the definition domain, so that tiles inserted in the object should always be completely contained in the definition domain of the object. This is not checked here!
+
+Objects of this class provide the needed functionality of MDDObjs to the RasDaMan server, namely, access to the tiles (which are the actual units of execution, processing and management internally at the server).
+
+Even though tiles are the units of execution in RasDaMan, once a tile is inserted in an MDDObj, it is no longer an independent entity. It should only be deleted from its storage domain through the MDD object it belongs to. Each MDDObj is responsible for managing its own tiles, including deallocation of memory occupied by the tiles.
+The memory management is delegated to the index. Only when the MDDObjIx is deleted the tiles that were accessed during the transaction will be removed from memory.
+
+*/
+class MDDObj
+ {
+ public:
+ //@Man: Constructors
+ //@{
+
+ MDDObj(const MDDBaseType* mddType, const r_Minterval& domain);
+ /**
+ Creates a new transient MDD object with definition domain {\tt domain } and type (\tt mddType).
+ The newly created object has no tiles.
+ */
+
+ /// Creates a new persistent MDD object using preallocated OId {\ttnewOId}.
+ MDDObj(const MDDBaseType* mddType, const r_Minterval& domain, const OId& newOId, const StorageLayout& ms) throw (r_Error);
+ /**
+ Creates a new persistent MDD object with definition domaini {\tt domain} and type (\tt mddType).
+ The newly created object has no tiles.
+ {\ttnewOId } must have been previously allocated with {\tt OIdIf::allocateOId() }
+ Throws an exception if the object already exists or if the OId is not valid.
+ */
+
+ /// Opens an existent transient/persistent MDD object
+ MDDObj(const DBMDDObjId& dbmddobj) throw (r_Error);
+ /**
+ Throws an exception if the object does not exists.
+ */
+
+ /// Opens an existent persistent MDD object which has the OIdi {\tt givenOId }
+ MDDObj(const OId& givenOId) throw (r_Error);
+ /**
+ Throws an exception if the object does not exists.
+ */
+
+ ///
+ MDDObj(const MDDBaseType* mddType, const r_Minterval& domain, const StorageLayout& ms);
+ /**
+ Creates a new persistent MDD object with definition domain {\tt domain}, storage layout {\tt ms} and type {\tt mddType}.
+ The newly created object has no tiles.
+ */
+
+ //@}
+
+ //@Man: Object Identification:
+ //@{
+ int getOId(OId* pOId) const;
+ /**
+ returns 0 if object has an OId.
+ */
+
+ int getEOId(EOId* pEOId) const;
+ /**
+ returns 0 if object has an EOId.
+ */
+ //@}
+
+ //@Man: Printing the status of the object.
+ //@{
+ /// Prints current status of the object.
+ void printStatus(unsigned int level = 0, std::ostream& stream = std::cout) const;
+ //@}
+
+ //@Man: Insertion of new tiles in the MDD object:
+ //@{
+ /**
+ After insertion of tiles in an MDDObj, the object becomes responsible for managing the memory allocated for the tiles inserted.
+ Deallocation is done by the destructor of the index which is called in ~MDDObj.
+ When new tiles are inserted in an MDDObj, the current domain for the object is updated. This information is kept in the index.
+ Neither type nor domain compatibility is checked.
+ */
+
+ /// Inserts new tile into the object.
+ void insertTile(Tile* newTile);
+
+ //@}
+
+ //@Man: Removal of tiles from the MDD object:
+ //@{
+ /**
+ */
+ void removeTile(Tile*& tileToRemove);
+ /**
+ Removes tile from the object.
+ This functon is not implemented yet.
+ */
+ //@}
+
+ //@Man: Retrieval of tiles from the MDD object:
+ //@{
+ /**
+ The methods which allow access to tiles of the MDDObj return pointers to tiles in the object, which continue being managed by the MDDObject. For that reason, the caller should not free the returned pointers to tiles.
+ */
+
+ /// Finds all tiles of the object which intersect searchInter.
+ std::vector< Tile* >* intersect(const r_Minterval& searchInter) const;
+ /**
+ Returns a vector of pointers to the intersected tiles which belong to the MDDObj.
+ The returned vector but not the tiles must be freed by the caller.
+ */
+
+ /// Returns all the tiles belonging to the object.
+ std::vector< Tile* >* getTiles() const;
+ /**
+ Returns a vector with all the tiles which belong to the MDDObj.
+ The returned vector but not the tiles must be freed by the caller.
+ */
+
+ /// Gets the cell with coordinates {\tt searchPoint} in the MDD.
+ const char* pointQuery(const r_Point& searchPoint) const;
+ /**
+ Returns null pointer if cell doesnt exist in the object.
+ */
+
+ /// Gets the cell with coordinates {\tt searchPoint} in the MDD.
+ char* pointQuery(const r_Point& searchPoint);
+ /**
+ Returns null pointer if cell doesnt exist in the object.
+ */
+ //@}
+
+
+ //@Man: Cell and domain properties of the MDD Object:
+ //@{
+
+ /// Returns the MDDBaseType of the object.
+ const MDDBaseType* getMDDBaseType() const;
+
+ /// Returns the domain of the object as it was given in the definition.
+ r_Minterval getDefinitionDomain() const;
+
+ /// Returns the current domain for the object.
+ r_Minterval getCurrentDomain() const;
+
+ /// Get cell type name.
+ const char* getCellTypeName() const;
+
+ /// Get base type.
+ const BaseType* getCellType() const;
+
+ /// Returns the dimensionality of the object.
+ r_Dimension getDimension() const;
+ //@}
+
+
+ //@Man: Miscellaneous Methods
+ //@{
+ ///This method is used to get around a bug in the qlparser.
+// void setDoNotUseThisMethodItIsABugFix(bool yes);
+
+ ///This method is used to get around a bug in the qlparser.
+// bool isDoNotUseThisMethodItIsABugFix() const;
+
+ /// Tells if object is persistent.
+ bool isPersistent() const;
+
+ /// Returns a pointer to the actual object in the base DBMS.
+ DBMDDObjId getDBMDDObjId() const;
+ //@}
+
+ //@Man: Destructor
+ //@{
+ /// Destructor - frees dynamic memory.
+ ~MDDObj();
+ //@}
+
+ /// release all tiles from the index
+ void releaseTiles();
+
+ protected:
+
+ /// does some consistency checks for regular tiling with rc index
+ const r_Minterval& checkStorage(const r_Minterval& domain) throw (r_Error);
+
+ ///The data class that holds all information
+ DBMDDObjId myDBMDDObj;
+
+ ///The index class that is used to access tile, before deleting thems
+ MDDObjIx* myMDDIndex;
+
+ ///The storage class which is reponsible for the tiling
+ StorageLayout* myStorageLayout;
+
+// bool doNotUseThisBugFix;
+ /**
+ The qlparser deletes transient mdd objects also in some cases (when passing transient mddobjs to a transient collection) this is bad.
+ Therefore the qlparser checks for transient mdds if they have this switch set to on, before deleting them.
+ */
+
+ };
+
+#endif
diff --git a/mddmgr/test/Makefile b/mddmgr/test/Makefile
new file mode 100644
index 0000000..c5e03c8
--- /dev/null
+++ b/mddmgr/test/Makefile
@@ -0,0 +1,109 @@
+# -*-Makefile-*-
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>. # Top Level makefile. This points to the various modules that have to be build
+# and/or deployed
+#
+# MAKEFILE FOR:
+# test programs of module mddmgr
+#
+# COMMENTS:
+#
+##################################################################
+######################### Definitions ############################
+
+# standard include with general options
+include $(RMANBASE)/Makefile.inc
+
+# all test programs
+SRCCXX = test_extendobjs.cc test_mddobj.cc test_persmddcoll.cc test_transmddcoll.cc \
+ test_extbmarkint.cc test_mddjoin.cc test_mddops.cc test_persmddobj.cc \
+ test_transmddobj.cc
+
+OBJS = ${SRCCXX:%.cc=%.o}
+
+ALLTESTS = ${SRCCXX:%.cc=%}
+
+MISCCLEAN = core
+
+# Sun Solaris: -lposix4 is needed for test_tile because of clock_gettime
+ifeq ($(OSTYPE),$(OSTYPE_SOLARIS))
+ LDFLAGS += -lposix4
+endif
+
+ALLFLAGS = $(BASEDBLDFLAGS) $(LDFLAGS) $(STLLDFLAGS) -L$(SUPPORT_BASE)/lib -lz
+
+MAINLIBS = $(RASLIB) $(CACHETAMGR) $(MDDIF) $(CATALOGIF) \
+ $(INDEXMGR) $(BLOBIF) $(ADMINIF) $(QLPARSER) $(INDEXIF)
+
+########################### Targets ##############################
+
+# make all tests
+.PHONY: test
+test: ALLTESTS
+
+
+######################## Dependencies ############################
+
+test_persmddcoll: test_persmddcoll.o $(MAINLIBS)
+ $(PURIFY) $(CXX) $(ALLFLAGS) -o $@ $^ $(STLLDFLAGS) -lm $(CACHETAMGR) \
+ $(INDEXIF)
+
+test_transmddcoll: test_transmddcoll.o $(RASLIB) $(CACHETAMGR)\
+ $(MDDIF) $(CATALOGIF) $(INDEXIF) $(INDEXMGR) $(BLOBIF) $(ADMINIF)
+ $(PURIFY) $(CXX) $(BASEDBLDFLAGS) $(STLLDFLAGS) $(LDFLAGS) -o $@ $^
+
+test_mddobj: test_mddobj.o $(RASLIB) $(CACHETAMGR)\
+ $(MDDIF) $(CATALOGIF) $(INDEXIF) $(INDEXMGR) $(BLOBIF) $(ADMINIF)
+ $(PURIFY) $(CXX) $(BASEDBLDFLAGS) $(STLLDFLAGS) $(LDFLAGS) -o $@ $^ -lm \
+ $(CACHETAMGR)
+
+test_transmddobj: test_transmddobj.o $(MAINLIBS)
+ $(PURIFY) $(CXX) $(ALLFLAGS) -o $@ $^ $(INDEXIF)
+
+# can not be used as a target (module library is not remade!)
+test_mddops: test_mddops.o $(RASLIB) $(CACHETAMGR)\
+ $(MDDIF) $(CATALOGIF) $(INDEXIF) $(INDEXMGR) $(BLOBIF) $(ADMINIF)
+ $(PURIFY) $(CXX) $(STLLDFLAGS) $(LDFLAGS) $(BASEDBLDFLAGS) -o $@ $^
+
+# can not be used as a target (module library is not remade!)
+test_mddjoin: test_mddjoin.o $(RASLIB) $(CACHETAMGR)\
+ $(MDDIF) $(CATALOGIF) $(INDEXIF) $(INDEXMGR) $(BLOBIF) $(ADMINIF)
+ $(PURIFY) $(CXX) $(STLLDFLAGS) $(LDFLAGS) $(BASEDBLDFLAGS) -o $@ $^
+
+test_persmddobj: test_persmddobj.o $(RASLIB) $(CACHETAMGR)\
+ $(MDDIF) $(CATALOGIF) $(INDEXMGR) $(BLOBIF) $(ADMINIF) $(QLPARSER) \
+ $(INDEXIF)
+ $(PURIFY) $(CXX) $(BASEDBLDFLAGS) $(LDFLAGS) $(STLLDFLAGS) -o $@ $^ \
+ $(STLLDFLAGS) -lm $(CACHETAMGR) -L$(SUPPORT_BASE)/lib -lz
+
+test_extbmarkint: test_extbmarkint.o $(MAINLIBS)
+ $(PURIFY) $(CXX) $(BASEDBLDFLAGS) $(LDFLAGS) $(STLLDFLAGS) -o $@ $^ \
+ $(STLLDFLAGS) -lm $(CACHETAMGR) $(INDEXIF) -L$(SUPPORT_BASE)/lib -lz
+
+# general rules
+include $(RMANBASE)/Makefile.rel
+
+# general dependencies for module libraries
+include $(RMANBASE)/Makefile.dep
+
+# automatically created dependencies
+include Makefile.dep
diff --git a/mddmgr/test/test_extbmarkint.cc b/mddmgr/test/test_extbmarkint.cc
new file mode 100644
index 0000000..3cc0caa
--- /dev/null
+++ b/mddmgr/test/test_extbmarkint.cc
@@ -0,0 +1,374 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_extbmarkint.cc
+ *
+ * MODULE: mddmgr
+ *
+ * PURPOSE:
+ * Extends the objects created by the test of areas of interest tiling
+ * rasodmg/test/test_int1 (the resulting objects have 5000 frames more
+ * than the original ones ).
+ * Needed because rasodmg doens't support updating of MDDobjects
+ * at the time this was created.
+ *
+ *
+ * COMMENTS:
+ * none
+ *
+*/
+
+#define TEST_PROTECTED
+#define TEST_PRIVATE
+
+#include <stdlib.h>
+#include <iostream>
+
+#include "ulongtype.hh"
+
+#include "mddmgr/persmddcoll.hh"
+#include "mddmgr/persmddobj.hh"
+#include "mddmgr/perstile.hh"
+
+#include "mddmgr/persmddcolliter.hh"
+
+#include "adminif.hh"
+#include "databaseif.hh"
+#include "transactionif.hh"
+#include "oidif.hh"
+
+#include "raslib/rminit.hh"
+#include "typefactory.hh"
+
+#include "mddif/dbmddobj.hh"
+#include "mddif/dbmddcoll.hh"
+
+#include "mddbasetype.hh"
+#include "mdddomaintype.hh"
+#include "settype.hh"
+
+
+/*
+ Global Variables
+*/
+extern char* myExecArgv0 = "";
+
+RMINITGLOBALS('C')
+
+static char* O2DBName;
+char *collName;
+char defaultCollName[]= "ObjsContainer";
+
+TransactionIf ta;
+
+/*
+ Functions
+*/
+
+// 2 - Populate collection with MDD objects
+static void testConstructors( OId o,
+ int numberFramesTile,
+ int f, // first frame
+ int n ); // number frames
+
+// 3 - Retrieves an MDD collection with name cn and prints contents:
+static void testAccessing( char* cn );
+
+
+/*************************************************************
+ * Function name.: int main( int argc, char** argv)
+ *
+ * Arguments.....:
+ * argc: number of arguments given to program
+ * argv: array of char* with arguments
+ * Return value..: exit status
+ * Description...: none
+ ************************************************************/
+int
+main( int argc, char** argv)
+{
+ // variables representing O2 database, ta and session
+ DatabaseIf database;
+
+
+
+ if( argc < 2 ) {
+ cout << "Usage: test_extbmarkint <database> [collName] [oid] [frames] " << endl;
+ return -1;
+ }
+ O2DBName = strdup( argv[1] );
+ if ( argc >= 3 ) collName = strdup( argv[2] );
+ else
+ collName = defaultCollName;
+
+ int numberFramesTile = 3; // 9
+ OId o( double( 2)); //
+ if( argc >= 4 )
+ {
+ int oid;
+ o = OId( double( atoi( argv[3] )));
+ cout << "OId " << o << endl;
+ }
+ if( argc >= 5 )
+ {
+ numberFramesTile = atoi( argv[4] );
+ cout << "Number of frames per tile "<< numberFramesTile << endl;
+ }
+
+ // don't forget to initialize before using AdminIf!
+ myExecArgv0 = argv[0];
+ AdminIf* myAdmin = AdminIf::instance();
+
+
+ // connect to the database
+ cout << "Connecting to database " << O2DBName
+ << "..." << endl;
+ int errorDBOpen;
+ try{
+ errorDBOpen = database.open( O2DBName );
+ }
+ catch( ...)
+ {
+ cout << "Caught Exception " << endl;
+ errorDBOpen = -6;
+ }
+ if ( errorDBOpen < 0 )
+ {
+ cout << "Database doesn't exist. Create it new ... " << endl;
+ cout << "Creating new database " << O2DBName
+ << "..." << endl;
+ database.create( O2DBName, "TestSMSchema" );
+ cout << "Connecting to database " << O2DBName
+ << "..." << endl;
+ try{
+ errorDBOpen = database.open( O2DBName );
+ }
+ catch(...)
+ {
+ errorDBOpen = -6;
+ }
+ }
+ if ( errorDBOpen < 0 )
+ {
+ cout << "Failed at opening newly created database " << errorDBOpen << endl;
+ cout << "Exiting " << endl;
+ return errorDBOpen;
+ }
+
+ char c;
+
+ unsigned totalNumberFrames = 200; /* 2000 */
+
+ // The first 2000 frames
+ for( int i = 0; i < totalNumberFrames ; i+= numberFramesTile*30 )
+ {
+ ta.begin( &database );
+ cout << endl << "Populate collection " << i << " ..." << endl;
+ int numberFrames = numberFramesTile*30;
+ if ( i+numberFrames > totalNumberFrames ) numberFrames = totalNumberFrames-i;
+ testConstructors( o, numberFramesTile, i, numberFrames );
+
+/*
+ cout <<"Transaction abort (A/a) or commit (default)? ";
+ cin >> c;
+ if ( c == 'A' || c == 'a' )
+ {
+ ta.abort( );
+ cout <<"End of Transaction Abort..."<<endl;
+ }
+ else
+ {
+*/
+ ta.commit( );
+
+ cout <<"End of transaction commit... "<<endl;
+// }
+ }
+
+
+ const int lastFrame = 2400; // 5120
+
+ // The last frames up to lastFrame
+ for( i = 2121 ; i < lastFrame ; i+= numberFramesTile*30 ) // 2121
+ {
+ ta.begin( &database );
+ cout << endl << "Populate collection " << i << " ..." << endl;
+ int numberFrames = numberFramesTile*30;
+ if ( i+numberFrames > lastFrame ) numberFrames = lastFrame-i;
+ testConstructors( o, numberFramesTile, i, numberFrames );
+
+/*
+ cout <<"Transaction abort (A/a) or commit (default)? ";
+ cin >> c;
+ if ( c == 'A' || c == 'a' )
+ {
+ ta.abort( );
+ cout <<"End of Transaction Abort..."<<endl;
+ }
+ else
+ {
+*/
+ ta.commit( );
+/*
+ cout <<"End of transaction commit... "<<endl;
+ }
+*/
+ }
+
+
+ ta.begin(&database );
+ // read coll and print contents
+ cout << endl << "Read collection " << collName << " and print contents..." << endl;
+ testAccessing( collName );
+ ta.commit( );
+ cout <<"End of transaction commit... "<<endl;
+
+ cout << endl << "Ending O2 session..." << endl;
+ database.close( );
+ delete myAdmin;
+
+ free( O2DBName );
+ if ( collName != defaultCollName ) free( collName );
+ return 0;
+
+}
+
+/*************************************************************
+ * Functions......:
+ *
+ * static void
+ * testConstructors( char* collName )
+ *
+ ************************************************************/
+static void testConstructors( OId o,
+ int numberFramesTile,
+ int f, // first frame
+ int n ) // number frames
+{
+
+ const BaseType* mddType;
+
+ cout << "....testConstructors"<< endl;
+
+ try{
+
+ PersMDDObj* accessedObj = new PersMDDObj( O2DBName, o );
+ int typeSize= accessedObj->getCellType( )->getSize( );
+ cout << "currDom " << accessedObj->getCurrentDomain( ) << endl;
+ accessedObj->printStatus();
+
+ EOId eoid;
+ if ( accessedObj->getEOId( &eoid ) ==0 )
+ cout <<"EOId: " << eoid;
+ cout << endl << endl;
+ mddType = accessedObj->getCellType( );
+
+ r_Minterval firstTile( 3 );
+ firstTile << r_Sinterval( long ( 0 ), long ( numberFramesTile-1 ) )
+ << r_Sinterval( long ( 0 ), long ( 79 ) )
+ << r_Sinterval( long ( 0 ), long ( 119 ) );
+
+ r_Minterval secondTile( 3 );
+ secondTile << r_Sinterval( long ( 0 ) , long ( numberFramesTile-1 ) )
+ << r_Sinterval( long ( 80 ), long ( 159 ) )
+ << r_Sinterval( long ( 0 ) , long ( 119 ) );
+
+ for ( int j = f; j < f+n ; j+=numberFramesTile )
+ {
+ r_Minterval dom1 = firstTile;
+ r_Minterval dom2 = secondTile;
+ r_Point desl( (r_Range) j, 0, 0 );
+ dom1.translate( desl );
+ dom2.translate( desl );
+ if ( dom1[0].high( ) >= f+n )
+ {
+ dom1[0].set_high( long( f+n-1) );
+ dom2[0].set_high( long( f+n-1) );
+ }
+ cout << "dom1" << dom1 << " dom2 " << dom2
+ << " type " << mddType->getTypeName( ) << endl;
+
+ int sz1 = dom1.cell_count( ) * typeSize;
+ char* cells1 = new char[sz1];
+ PersTile* tile1 = new PersTile( dom1, mddType, cells1);
+ accessedObj->insertTile(tile1);
+
+ int sz2 = dom2.cell_count( ) * typeSize;
+ char* cells2 = new char[sz2];
+ PersTile* tile2 = new PersTile( dom2, mddType, cells2 );
+
+ accessedObj->insertTile(tile2);
+ // accessedObj->printStatus( );
+ }
+
+ delete accessedObj;
+
+ }
+ catch ( r_Error& errObj)
+ {
+ cout << "Error caught when opening object" << endl;
+ }
+
+}
+
+
+/*************************************************************
+ * Function......: testAccessing( char* cn )
+ ************************************************************/
+
+static void testAccessing( char* cn )
+{
+ PersMDDObj* accessedObj;
+
+ cout << "....testAccessing collection "<< cn << endl;
+
+ try{
+ PersMDDColl objsSet( cn );
+
+ // To test PersMDDColl::printStatus( )
+ // objsSet.printStatus( );
+
+ // To test PersMDDObj::printStatus( ), MDDCollIter::createIterator( ) and
+ // MDDCollIter methods :
+
+ cout << "Iterating through the collection with PersMDDCollIter " << endl;
+ MDDCollIter* objsIt = objsSet.createIterator( );
+
+ for( int i = 1 ; objsIt->notDone( ); i++, objsIt->advance( ))
+ {
+ cout << i<<". MDD object in set:" << endl;
+ accessedObj = (PersMDDObj*) objsIt->getElement();
+ accessedObj->printStatus();
+ EOId eoid;
+ if ( accessedObj->getEOId( &eoid ) ==0 )
+ cout <<"EOId: " << eoid;
+ }
+ delete objsIt;
+ objsSet.releaseAll( );
+ }
+ catch ( r_Error& errObj)
+ {
+ cout <<"Error caught ................."<< endl;
+ }
+}
+
diff --git a/mddmgr/test/test_extendobjs.cc b/mddmgr/test/test_extendobjs.cc
new file mode 100644
index 0000000..73f82b3
--- /dev/null
+++ b/mddmgr/test/test_extendobjs.cc
@@ -0,0 +1,324 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_extendobjs.cc
+ *
+ * MODULE: cachetamgr
+ *
+ * PURPOSE:
+ * Extends the objects created by the test of directional tiling
+ * rasodmg/test/test_dir1 (the resulting objects have 4 times more
+ * products and 2 times more stores than the original ones ).
+ * Needed because rasodmg doens't support updating of MDDobjects
+ * at the time this was created.
+ *
+ *
+ * COMMENTS:
+ * none
+ *
+*/
+
+#define TEST_PROTECTED
+#define TEST_PRIVATE
+
+#include <stdlib.h>
+#include <iostream>
+
+#include "ulongtype.hh"
+
+#include "mddmgr/persmddcoll.hh"
+#include "mddmgr/persmddobj.hh"
+#include "mddmgr/perstile.hh"
+
+#include "mddmgr/persmddcolliter.hh"
+
+#include "adminif.hh"
+#include "databaseif.hh"
+#include "transactionif.hh"
+#include "oidif.hh"
+
+#include "raslib/rminit.hh"
+#include "typefactory.hh"
+
+#include "mddif/dbmddobj.hh"
+#include "mddif/dbmddcoll.hh"
+
+#include "mddbasetype.hh"
+#include "mdddomaintype.hh"
+#include "settype.hh"
+
+
+/*
+ Global Variables
+*/
+extern char* myExecArgv0 = "";
+
+RMINITGLOBALS('C')
+
+static char* O2DBName;
+char *collName;
+char defaultCollName[]= "ObjsContainer";
+
+TransactionIf ta;
+
+/*
+ Functions
+*/
+
+// 2 - Populate collection with MDD objects
+static void testConstructors( char* cn , int s, int p);
+
+// 3 - Retrieves an MDD collection with name cn and prints contents:
+static void testAccessing( char* cn );
+
+
+/*************************************************************
+ * Function name.: int main( int argc, char** argv)
+ *
+ * Arguments.....:
+ * argc: number of arguments given to program
+ * argv: array of char* with arguments
+ * Return value..: exit status
+ * Description...: none
+ ************************************************************/
+int
+main( int argc, char** argv)
+{
+ // variables representing O2 database, ta and session
+ DatabaseIf database;
+
+ if( argc < 2 ) {
+ cout << "Usage: test_persmddcoll <database> [collName]" << endl;
+ return -1;
+ }
+ O2DBName = strdup( argv[1] );
+ if ( argc == 3 ) collName = strdup( argv[2] );
+ else
+ collName = defaultCollName;
+
+ // don't forget to initialize before using AdminIf!
+ myExecArgv0 = argv[0];
+ AdminIf* myAdmin = AdminIf::instance();
+
+
+ // connect to the database
+ cout << "Connecting to database " << O2DBName
+ << "..." << endl;
+ int errorDBOpen;
+ try{
+ errorDBOpen = database.open( O2DBName );
+ }
+ catch( ...)
+ {
+ cout << "Caught Exception " << endl;
+ errorDBOpen = -6;
+ }
+ if ( errorDBOpen < 0 )
+ {
+ cout << "Database doesn't exist. Create it new ... " << endl;
+ cout << "Creating new database " << O2DBName
+ << "..." << endl;
+ database.create( O2DBName, "TestSMSchema" );
+ cout << "Connecting to database " << O2DBName
+ << "..." << endl;
+ try{
+ errorDBOpen = database.open( O2DBName );
+ }
+ catch(...)
+ {
+ errorDBOpen = -6;
+ }
+ }
+ if ( errorDBOpen < 0 )
+ {
+ cout << "Failed at opening newly created database " << errorDBOpen << endl;
+ cout << "Exiting " << endl;
+ return errorDBOpen;
+ }
+
+ char c;
+
+ for( int p = 0; p < 4; p++ )
+ {
+ for ( int s = 0; s < 2 ; s++)
+ {
+ ta.begin( &database );
+ cout << endl << "Populate collection " << s <<" " << p << " ..." << endl;
+ testConstructors( collName, s, p );
+ cout <<"Transaction abort (A/a) or commit (default)? ";
+ cin >> c;
+ if ( c == 'A' || c == 'a' )
+ {
+ ta.abort( );
+ cout <<"End of Transaction Abort..."<<endl;
+ }
+ else
+ {
+ ta.commit( );
+ cout <<"End of transaction commit... "<<endl;
+ }
+ }
+ }
+
+
+ ta.begin(&database );
+ // read coll and print contents
+ cout << endl << "Read collection " << collName << " and print contents..." << endl;
+ testAccessing( collName );
+ ta.commit( );
+ cout <<"End of transaction commit... "<<endl;
+
+ cout << endl << "Ending O2 session..." << endl;
+ database.close( );
+ delete myAdmin;
+
+ free( O2DBName );
+ if ( collName != defaultCollName ) free( collName );
+ return 0;
+
+}
+
+/*************************************************************
+ * Functions......:
+ *
+ * static void
+ * testConstructors( char* collName )
+ *
+ ************************************************************/
+static void testConstructors( char* collName, int s, int p )
+{
+
+ const BaseType* mddType;
+ char* uLongCells;
+
+ cout << "....testConstructors"<< endl;
+
+
+ PersMDDObj* accessedObj;
+
+ try{
+ PersMDDColl objsSet(collName);
+
+ cout << "Iterating through the collection with PersMDDCollIter " << endl;
+ MDDCollIter* objsIt = objsSet.createIterator( );
+
+ for( int i = 1 ; objsIt->notDone( ); i++, objsIt->advance( ))
+ {
+ cout << endl << i<<". MDD object in set:" << endl;
+ accessedObj = (PersMDDObj*) objsIt->getElement();
+ // accessedObj->printStatus();
+ EOId eoid;
+ if ( accessedObj->getEOId( &eoid ) ==0 )
+ cout <<"EOId: " << eoid;
+ cout << endl << endl;
+
+ mddType = accessedObj->getCellType( );
+
+ r_Minterval firstYear("[1:365,1:60,1:100]");
+
+ vector< Tile* >* firstYearTiles = accessedObj->intersect( firstYear );
+
+ for ( int j = 0; j < firstYearTiles->size( ); j++ )
+ {
+ r_Minterval dom = (*firstYearTiles)[j]->getDomain( );
+
+/*
+ for( int p = 0; p < 4; p++ )
+ {
+ for ( int s = 0; s < 2 ; s++)
+ {
+*/
+ r_Point desl( (r_Range) 730, (p+1)*60, (s+1)* 100 );
+
+ r_Minterval newDom( dom.dimension( ) );
+ newDom.intersection_of( dom, "[1:365,1:60,1:100]");
+ newDom.translate( desl );
+ cout << "dom" << dom << "newDom " << newDom << endl;
+
+ int sz = mddType->getSize( ) * newDom.cell_count( );
+ uLongCells = new char[sz];
+ PersTile* tile1Obj1 = new PersTile( newDom, mddType, uLongCells );
+ accessedObj->insertTile(tile1Obj1);
+
+/*
+ }
+ }
+
+*/
+ }
+ delete firstYearTiles;
+ }
+
+ delete objsIt;
+
+ cout << "Release all " << endl;
+ objsSet.releaseAll( );
+ }
+ catch ( r_Error& errObj)
+ {
+ cout << "Error caught when opening collection" << endl;
+ }
+
+}
+
+
+/*************************************************************
+ * Function......: testAccessing( char* cn )
+ ************************************************************/
+
+static void testAccessing( char* cn )
+{
+ PersMDDObj* accessedObj;
+
+ cout << "....testAccessing collection "<< cn << endl;
+
+ try{
+ PersMDDColl objsSet( cn );
+
+ // To test PersMDDColl::printStatus( )
+ // objsSet.printStatus( );
+
+ // To test PersMDDObj::printStatus( ), MDDCollIter::createIterator( ) and
+ // MDDCollIter methods :
+
+ cout << "Iterating through the collection with PersMDDCollIter " << endl;
+ MDDCollIter* objsIt = objsSet.createIterator( );
+
+ for( int i = 1 ; objsIt->notDone( ); i++, objsIt->advance( ))
+ {
+ cout << i<<". MDD object in set:" << endl;
+ accessedObj = (PersMDDObj*) objsIt->getElement();
+ accessedObj->printStatus();
+ EOId eoid;
+ if ( accessedObj->getEOId( &eoid ) ==0 )
+ cout <<"EOId: " << eoid;
+ }
+ delete objsIt;
+ objsSet.releaseAll( );
+ }
+ catch ( r_Error& errObj)
+ {
+ cout <<"Error caught ................."<< endl;
+ }
+}
+
diff --git a/mddmgr/test/test_mddjoin.cc b/mddmgr/test/test_mddjoin.cc
new file mode 100644
index 0000000..c7ae617
--- /dev/null
+++ b/mddmgr/test/test_mddjoin.cc
@@ -0,0 +1,228 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_mddjoin.cc
+ *
+ * MODULE: example for making one tile out of a vector of
+ * Tiles
+ *
+ * COMMENTS:
+ * later has to be moved to the executor
+ *
+*/
+
+static const char rcsid[] = "@(#)blobif,test_mddops: $Id: test_mddjoin.cc,v 1.9 2002/09/03 14:46:50 coman Exp $";
+
+#include <stdlib.h>
+#include <iostream>
+#include "ulongtype.hh"
+#include "booltype.hh"
+#include "mddmgr/persmddobj.hh"
+#include "mddmgr/perstile.hh"
+#include "mddmgr/transtile.hh"
+#include "adminif.hh"
+#include "databaseif.hh"
+#include "transactionif.hh"
+#include "raslib/rminit.hh"
+#include "typefactory.hh"
+
+// global variable for AdminIf because of O2 d_Session::begin()
+extern char* myExecArgv0 = "";
+
+RMINITGLOBALS('C')
+
+static char O2BenchDBName[] = "NorbertBase";
+static char O2BenchSchemaName[] = "NorbertSchema";
+
+static void testOperations( DatabaseIf myDB );
+
+static BaseType* myType;
+static BaseType* boolType;
+
+/*************************************************************
+ * Function name.: int main( int argc, char** argv)
+ *
+ * Arguments.....:
+ * argc: number of arguments given to program
+ * argv: array of char* with arguments
+ * Return value..: exit status
+ * Description...: none
+ ************************************************************/
+
+int
+main( int /* argc */, char** argv)
+{
+ // variables representing O2 database, ta and session
+ DatabaseIf database;
+ TransactionIf ta;
+
+ // don't forget to initialize before using AdminIf!
+ myExecArgv0 = argv[0];
+ AdminIf* myAdmin = AdminIf::instance();
+
+ // connect to the database
+ cout << "Connecting to database " << O2BenchDBName
+ << "..." << endl;
+ database.open( O2BenchDBName );
+ ta.begin(&database);
+
+ // only possible after AdminIf::instance on Sun!
+ myType = TypeFactory::mapType("ULong");
+ boolType = TypeFactory::mapType("Bool");
+
+ testOperations( database );
+
+ ta.commit();
+ cout << "Ending O2 session..." << endl;
+ database.close();
+ delete myAdmin;
+}
+
+void
+printAllTiles(const MDDObj* mdd)
+{
+ // contains all tiles of MDD
+ vector<Tile*>* allTiles;
+ // iterator
+ vector<Tile*>::iterator tileIt;
+ // domains of a tile
+ r_Minterval tileDom;
+
+ // domain of MDD object
+ r_Minterval dom;
+ dom = mdd->getCurrentDomain();
+
+ // get all tiles of result MDD
+ allTiles = mdd->intersect(dom);
+
+ // and iterate over them
+ tileIt = allTiles->begin();
+ while (tileIt != allTiles->end())
+ {
+ tileDom = (*tileIt)->getDomain();
+ cout << "Domain of Tile: ";
+ tileDom.print_status();
+ cout << endl;
+
+ cout << "Tile: " << endl;
+ (*tileIt)->printStatus();
+ cout << endl;
+
+ tileIt++;
+ }
+}
+
+/*************************************************************
+ * Function......: testConstructors( DatabaseIf myDB )
+ *
+ * Arguments.....:
+ * myDB: database to use (should be opened)
+ * Return value..: none
+ * Description...: constructs BLOBTiles and inserts them
+ * in root collection.
+ ************************************************************/
+
+static void testOperations( DatabaseIf /* myDB */)
+{
+ unsigned long cell = 1000;
+
+ ULongType ulongtype;
+ BaseType* type = &ulongtype;
+ Tile* res;
+ Tile* boolTile;
+
+ vector<Tile*>* result = new vector<Tile*>;
+ vector<Tile*>::iterator tileIt;
+ Tile* bigTile;
+
+ cout << "Creating Tile: ";
+ r_Minterval bigDom =
+ r_Minterval(3) << r_Sinterval(1l,10l) << r_Sinterval(1l,10l)
+ << r_Sinterval(1l,10l);
+ bigDom.print_status();
+ cout << endl;
+
+ bigTile = new PersTile(bigDom, type, (char*)&cell);
+
+ r_Minterval smallDom
+ = r_Minterval(3) << r_Sinterval(1l,6l) << r_Sinterval(1l,6l)
+ << r_Sinterval(1l,6l);
+
+ cout << "Splitting it into ";
+ smallDom.print_status();
+ cout << " tiles." << endl;
+
+ result = bigTile->splitTile(smallDom);
+
+ cout << "Result tiles: " << endl;
+ // and iterate over them
+ tileIt = result->begin();
+ while (tileIt != result->end())
+ {
+ cout << " Domain of Tile " << (tileIt - result->begin()) << ": ";
+ ((*tileIt)->getDomain()).print_status();
+ cout << endl;
+
+ tileIt++;
+ }
+
+ cout << "Joining the Tiles again:" << endl;
+
+ r_Minterval proj =
+ r_Minterval(3) << r_Sinterval(2l,9l) << r_Sinterval(2l,9l)
+ << r_Sinterval(2l,9l);
+
+ res = new TransTile(result, proj );
+
+ cout << " Result MDD equals original MDD: ";
+ boolTile = new TransTile(res->getDomain(), boolType);
+ cout << "Domain of result Tile: ";
+ (res->getDomain()).print_status();
+ cout << endl;
+ res->printStatus();
+ boolTile->execBinaryOp(Ops::OP_EQUAL, proj,
+ res, proj,
+ bigTile, proj);
+
+ char init = 1;
+
+ cout << "Checking if Tile are equal: ";
+ cout << (int)(*(boolTile->execCondenseOp(Ops::OP_ALL,
+ res->getDomain(),
+ &init ))) << endl;
+
+ cout << "Creating a trimmed, projected 2-D Tile out of the Tile:" << endl;
+ set<r_Dimension, less<r_Dimension> >* projSet =
+ new set<r_Dimension, less<r_Dimension> >;
+ projSet->insert(1);
+
+ r_Minterval projDom =
+ r_Minterval(3) << r_Sinterval(2l, 9l) << r_Sinterval(5l, 5l)
+ << r_Sinterval(2l, 9l);
+
+ Tile* projectedTile = new TransTile(res, projDom, projSet);
+
+ projectedTile->printStatus();
+
+ cout << endl;
+}
diff --git a/mddmgr/test/test_mddobj.cc b/mddmgr/test/test_mddobj.cc
new file mode 100644
index 0000000..5bb70c0
--- /dev/null
+++ b/mddmgr/test/test_mddobj.cc
@@ -0,0 +1,473 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_mddobj.cc
+ *
+ * MODULE: test for mddobj of mddmgr
+ *
+ * COMMENTS:
+ * in order to compile this test program, getDBMDDObjId from
+ * PersMDDObj has to be made public, which is not the normal
+ * and expected case.
+ *
+*/
+
+#include <stdlib.h>
+#include <iostream>
+#include "mddmgr/perstile.hh"
+#include "ulongtype.hh"
+#include "mddmgr/persmddobj.hh"
+#include "mddmgr/persmddcoll.hh"
+#include "mddmgr/mddcoll.hh"
+#include "mddmgr/mddcolliter.hh"
+
+
+#include "raslib/rminit.hh"
+RMINITGLOBALS('C')
+
+#include "mddif/dbmddobj.hh"
+#include "raslib/minterval.hh"
+#include "raslib/sinterval.hh"
+
+// perhaps used later
+static char O2BenchDBName[] = "PaulaRasDaBase";
+static char O2BenchSchemaName[] = "SMRasDaSchema";
+
+static void ClearDB( d_Database &DB );
+static void testAccessing();
+static void testConstructors();
+static void testSearch();
+static void testGetFunctions();
+static void printInterval(r_Minterval* inter);
+void printMemInfo( );
+
+
+/*************************************************************
+ * Function name.: int main( int argc, char** argv)
+ *
+ * Arguments.....:
+ * argc: number of arguments given to program
+ * argv: array of char* with arguments
+ * Return value..: exit status
+ * Description...: none
+ ************************************************************/
+int
+main( int argc, char** argv)
+{
+ // variables representing O2 database, ta and session
+ d_Session session;
+ d_Database database;
+ d_Transaction ta;
+
+
+ // initialize the O2 session
+ cout << "Initializing O2 session..." << endl;
+ session.set_default_env();
+ if (session.begin(argc, argv)){
+ cerr << "Something wrong to start o2" << endl;
+ exit(1);
+ }
+
+ // clear the DB (in case the base already exists)
+ cout << "Deleting TestMDDObjContainer of database..." << endl;
+ database.open( O2BenchDBName);
+ ta.begin( );
+ Handle collHandle = 0;
+ collHandle = o2_get_root( "TestMDDObjContainer" );
+ if ( collHandle )
+ {
+ // I don't know if this is needed.
+ o2_unref_handle ( collHandle );
+ database.destroy_persistent_root( "TestMDDObjContainer" );
+ }
+ ta.commit( );
+
+ // connect to the database
+ cout << "Connecting to database " << O2BenchDBName
+ << "..." << endl;
+ database.open( O2BenchDBName );
+
+ // create root collection
+ cout << "Creating root collection..." << endl;
+ ta.begin();
+ database.create_persistent_root( "TestMDDObjContainer",
+ "d_List< d_Ref<DBMDDObj> >",
+ OL_CONSTANT);
+ ta.commit();
+
+ // create indexes and put them in TestMDDObjContainer
+ cout << "Create objects and put in TestMDDObjContainer..." << endl;
+ ta.begin();
+ testConstructors();
+ ta.commit();
+
+ // read index and print contents
+ cout << "Read objects and print contents..." << endl;
+ ta.begin();
+ testAccessing();
+ ta.commit();
+
+ // test search operation and print contents
+ cout << "Search a rectangular region and print contents..." << endl;
+ ta.begin();
+ testSearch();
+ ta.commit();
+
+ /*
+ // test get member functions
+ cout << "Get * from object and print result..." << endl;
+ ta.begin();
+ testGetFunctions();
+ ta.commit();
+ */
+
+ cout << "Ending O2 session..." << endl;
+ session.end();
+ database.close();
+}
+
+/*************************************************************
+ * Function......: testConstructors()
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: constructs Indices and inserts them
+ * in root collection.
+ ************************************************************/
+
+static void testConstructors()
+{
+ ULongType anyType;
+ char anyCell[] = {0,0,0,0};
+ unsigned long MDDObj1sz = 0;
+
+ cout << "....testConstructors"<< endl;
+
+ // read root object
+ d_List< d_Ref<DBMDDObj> > objsList("TestMDDObjContainer");
+
+ // create MDD Object
+ cout << " mddObj1" << endl;
+
+ cout << " tile 1 = nil, 10-12, 20-24 "<< endl;
+ r_Sinterval limits1Obj1(10l,12l);
+ r_Sinterval limits2Obj1(20l,24l);
+ r_Minterval dom(2);
+ dom << limits1Obj1 << limits2Obj1;
+ PersTile* tile1Obj1 = new PersTile( dom, &anyType, (const char*) anyCell);
+ MDDObj1sz += tile1Obj1->getSize( );
+ PersMDDObj* MDDObj1=new PersMDDObj( dom, "ULong");
+ MDDObj1->insertTile(tile1Obj1);
+
+ cout << " tile 2 = nil, 0-400, 22-24 "<< endl;
+ dom[0].set_interval(0l,400l);
+ dom[1].set_interval(22l,24l);
+ PersTile* tile2Obj1 = new PersTile( dom, &anyType, (const char*) anyCell);
+
+ MDDObj1sz += tile1Obj1->getSize( );
+ // MDDObj1->insertTile(tile2Obj1);
+
+ cout << " tile 3 = nil, 0-600, 10-1000 "<< endl;
+ dom[0].set_interval(0l,600l);
+ dom[1].set_interval(10l,1000l);
+ PersTile* tile3Obj1= new PersTile( dom, &anyType, (const char*) anyCell);
+ MDDObj1sz += tile3Obj1->getSize( );
+ // MDDObj1->insertTile(tile3Obj1);
+
+ vector<Tile*>* newTiles = new vector< Tile* >;
+ newTiles->push_back(tile2Obj1);
+ newTiles->push_back(tile3Obj1);
+ MDDObj1->insertTiles(*newTiles);
+ delete newTiles;
+
+ objsList.insert_element_last(MDDObj1->getDBMDDObjId());
+
+ cout << "Size of MDDObj1 : " << MDDObj1sz << " - " << MDDObj1sz/1024 << endl;
+ printMemInfo( );
+ cout << "Delete MDDObj1 ..........." << endl;
+ delete MDDObj1;
+ printMemInfo( );
+ cout << endl << endl;
+
+
+ unsigned long MDDObj2sz = 0;
+ cout << " mddObj2 "<< endl;
+ cout << " tile 1 = nil, 0-19, 20-59, 30-59 "<< endl;
+ r_Sinterval limits1Obj2(0l,19l);
+ r_Sinterval limits2Obj2(20l,59l);
+ r_Sinterval limits3Obj2(30l,59l);
+ r_Minterval dom2(3);
+ dom2 << limits1Obj2 << limits2Obj2 << limits3Obj2;
+ PersTile* tile1Obj2 = new PersTile( dom2, &anyType, (const char*) anyCell);
+ MDDObj2sz += tile1Obj2->getSize( );
+ PersMDDObj* MDDObj2 = new PersMDDObj( dom2, "ULong");
+ MDDObj2->insertTile(tile1Obj2);
+
+ cout << " tile 2 = nil, 20-39, 60-79, 60-89 "<< endl;
+ dom2[0].set_interval(20l,39l);
+ dom2[1].set_interval(60l,79l);
+ dom2[2].set_interval(60l,89l);
+ PersTile* tile2Obj2 = new PersTile( dom2, &anyType, (const char*) anyCell);
+ MDDObj2sz += tile2Obj2->getSize( );
+
+ MDDObj2->insertTile(tile2Obj2);
+
+ objsList.insert_element_last(MDDObj2->getDBMDDObjId());
+
+ cout << "Size of MDDObj2 : " << MDDObj2sz << " - " << MDDObj2sz/1024 << endl;
+ printMemInfo( );
+ cout << "Delete MDDObj2 ..........." << endl;
+ delete MDDObj2;
+ printMemInfo( );
+ cout << endl << endl;
+}
+
+/*************************************************************
+ * Function......: testAccessing()
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: reads DirTilesIx's and shows contents
+ ************************************************************/
+
+static void testAccessing()
+{
+ DBMDDObjId accessedObj;
+
+ cout << "....testAccessing"<<endl;
+
+ // read root object
+ d_List< DBMDDObjId > objsList("TestMDDObjContainer");
+ // used for iterating
+ d_Iterator< DBMDDObjId > objsIt = objsList.create_iterator();
+
+ for( int i = 1 ; objsIt.not_done(); i++, objsIt.advance())
+ {
+ accessedObj = objsIt.get_element();
+ cout << " --"<<i<<". MDD object in list:" << endl;
+ accessedObj->printStatus();
+ cout << " -- CellTypeName: " << accessedObj->getCellTypeName( ) << endl;
+ }
+
+}
+
+/*************************************************************
+ * Function......: testSearch()
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: reads Index's and shows contents
+ ************************************************************/
+
+static void testSearch()
+{
+
+ PersMDDColl mddObjsColl ( "TestMDDObjContainer" );
+ MDDObj* accessedObj;
+ MDDCollIter* objsIt = mddObjsColl.createIterator( );
+
+
+/*
+ DBMDDObjId accessedObj;
+
+ cout << "....testSearch"<<endl;
+
+ // read root object
+ d_List< DBMDDObjId > objsList("TestMDDObjContainer");
+ // used for iterating
+ d_Iterator< DBMDDObjId > objsIt = objsList.create_iterator();
+
+*/
+
+ for( int i = 0 ; objsIt->notDone(); i++, objsIt->advance())
+ {
+
+ accessedObj = objsIt->getElement();
+
+ if (i == 0 || i == 1)
+ {
+ vector< Tile* >* entriesList = 0;
+
+ r_Minterval searchInt1(2);
+ r_Minterval searchInt2(3);
+
+ printMemInfo( );
+
+ cout << " -- " << i+1 << ". MDD object in list. Search for:";
+ switch (i) {
+ case 0: searchInt1[0].set_interval(10l,20l);
+ searchInt1[1].set_interval(10l,30l);
+ cout << " 10-20, 10-30" << endl;
+ entriesList = accessedObj->intersect(searchInt1);
+ break;
+ case 1: searchInt2[0].set_interval(10l,20l);
+ searchInt2[1].set_interval(10l,30l);
+ searchInt2[2].set_interval(40l,50l);
+ cout << " 10-20, 10-30, 40-50" <<endl;
+ entriesList = accessedObj->intersect(searchInt2);
+ break;
+ default: break;
+ }
+
+ printMemInfo( );
+
+ cout << " -- Search result: " << endl;
+ vector<Tile*>::iterator entryIt = entriesList->begin();
+
+ while (entryIt != entriesList->end())
+ {
+ // (*entryIt)->printStatus();
+ r_Minterval tileInterval = (*entryIt)->getDomain();
+ int dimensionality = tileInterval.dimension();
+
+ cout << " PersTile printStatus";
+ cout << " domain == " << dimensionality << ": ";
+ for (int i = 0; i <dimensionality; i++)
+ cout << tileInterval[i].low() << "-" << tileInterval[i].high() <<", ";
+ cout << endl << " Access contents " ;
+ char* tileContents = ( *entryIt )->getContents( );
+
+ cout << endl;
+
+ entryIt++;
+ }
+
+ printMemInfo( );
+ cout << " Release entriesList " << endl;
+
+ delete entriesList;
+ }
+ }
+ delete objsIt;
+}
+
+/*************************************************************
+ * Function......: testGetFunctions()
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: reads Index's and shows contents
+ ************************************************************/
+
+static void testGetFunctions()
+{
+
+ MDDObj* accessedObj;
+ PersMDDColl persMDDObjsColl ( "TestMDDObjContainer" );
+ MDDColl* mddObjsColl = &persMDDObjsColl;
+
+ MDDCollIter* objsIt = mddObjsColl->createIterator( );
+
+ vector< Tile* >* entriesList;
+
+ cout << "....testGetTiles"<<endl;
+
+ for( int i = 0 ; objsIt->notDone(); i++, objsIt->advance())
+ {
+ r_Minterval currDom;
+ r_Minterval defDom;
+
+ cout << " " << i << ". Object" << endl;
+ accessedObj = objsIt->getElement( );
+
+ defDom = accessedObj->getDefinitionDomain( );
+ cout << " GetDefinitionDomain result: ";
+ printInterval( &defDom );
+ cout << endl;
+
+ currDom = accessedObj->getCurrentDomain( );
+ cout << " GetCurrentDomain result: ";
+ printInterval( &currDom );
+ cout << endl;
+
+ entriesList = accessedObj->getTiles( );
+ cout << " -- GetTiles result: " << endl;
+ vector<Tile*>::iterator entryIt = entriesList->begin();
+
+ while (entryIt != entriesList->end())
+ {
+ // (*entryIt)->printStatus();
+ r_Minterval tileInterval = (*entryIt)->getDomain();
+ int dimensionality = tileInterval.dimension();
+
+ cout << " PersTile printStatus";
+ cout << " domain == " << dimensionality << ": ";
+ for (int i = 0; i <dimensionality; i++)
+ cout << tileInterval[i].low() << "-" << tileInterval[i].high() <<", ";
+ cout << endl;
+ entryIt++;
+ }
+ delete entriesList;
+ }
+ delete objsIt;
+ mddObjsColl->releaseAll( );
+}
+
+/*************************************************************
+ * Function......:
+ *
+ * Arguments.....:
+ * Return value..:
+ * Description...:
+ ************************************************************/
+
+static void printInterval(r_Minterval* inter)
+{
+ for (int i = 0; i <inter->dimension( ); i++)
+ {
+ (*inter)[i].is_low_fixed( )? cout << (*inter)[i].low( ): cout << "*";
+ cout << " - ";
+ (*inter)[i].is_high_fixed( )? cout << (*inter)[i].high( ): cout << "*";
+ cout << ",";
+ }
+}
+
+/*************************************************************
+ * Function......:
+ *
+ * Arguments.....:
+ * Return value..:
+ * Description...:
+ ************************************************************/
+
+void printMemInfo( )
+{
+
+
+ // allows to store values in the program
+ struct mallinfo meminfo = mallinfo();
+
+ cout << " Memory Usage Information : bytes - Kbytes" ;
+ cout << endl;
+
+ cout << " space in arena : " << meminfo.arena << " - " << meminfo.arena/1024 << endl;
+ cout << " number of small blocks : " << meminfo.smblks << " - " << meminfo.smblks/1024 << endl;
+ cout << " number of ordinary blocks : " << meminfo.ordblks << " - " << meminfo.ordblks/1024 << endl;
+ cout << " space in free ordinary blocks : " << meminfo.fordblks << " - " << meminfo.fordblks/1024 << endl;
+ cout << " space in used ordinary blocks : " << meminfo.uordblks << " - " << meminfo.uordblks/1024 << endl;
+
+ // cout << "additional space from last call: " << meminfo.uordblks - memUsed < < endl;
+
+}
+
+
diff --git a/mddmgr/test/test_mddops.cc b/mddmgr/test/test_mddops.cc
new file mode 100644
index 0000000..5a81bc8
--- /dev/null
+++ b/mddmgr/test/test_mddops.cc
@@ -0,0 +1,335 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_mddops.cc
+ *
+ * MODULE: example for executing operations on MDDs
+ *
+ * PURPOSE:
+ * makes operations on MDDs or parts of them
+ *
+ * COMMENTS:
+ * later has to be moved to the executor
+ *
+*/
+
+static const char rcsid[] = "@(#)blobif,test_mddops: $Id: test_mddops.cc,v 1.10 2002/09/03 14:46:50 coman Exp $";
+
+#include <stdlib.h>
+#include <iostream>
+#include "o2lib_CC.hxx"
+#include "o2template_CC.hxx"
+#include "ulongtype.hh"
+#include "mddmgr/persmddobj.hh"
+#include "mddmgr/perstile.hh"
+#include "adminif.hh"
+#include "databaseif.hh"
+#include "transactionif.hh"
+#include "raslib/rminit.hh"
+#include "typefactory.hh"
+
+
+// global variable for AdminIf because of O2 d_Session::begin()
+extern char* myExecArgv0 = "";
+
+RMINITGLOBALS('C')
+
+static char O2BenchDBName[] = "DemoBase";
+static char O2BenchSchemaName[] = "RasDaSchema";
+
+static void testOperations( DatabaseIf myDB );
+
+BaseType* myType;
+static long myCell = 0;
+
+/*************************************************************
+ * Function name.: int main( int argc, char** argv)
+ *
+ * Arguments.....:
+ * argc: number of arguments given to program
+ * argv: array of char* with arguments
+ * Return value..: exit status
+ * Description...: none
+ ************************************************************/
+
+int
+main( int argc, char** argv)
+{
+ // variables representing O2 database, ta and session
+ DatabaseIf database;
+ TransactionIf ta;
+
+ // don't forget to initialize before using AdminIf!
+ myExecArgv0 = argv[0];
+
+ AdminIf* myAdmin = AdminIf::instance();
+
+ // only possible after AdminIf::instance on Sun!
+ myType = TypeFactory::mapType("ULong");
+
+ // connect to the database
+ cout << "Connecting to database " << O2BenchDBName
+ << "..." << endl;
+ database.open( O2BenchDBName );
+
+ testOperations( database );
+
+ cout << "Ending O2 session..." << endl;
+ database.close();
+ delete myAdmin;
+}
+
+void
+printAllTiles(const MDDObj* mdd)
+{
+ // contains all tiles of MDD
+ vector<Tile*>* allTiles;
+ // iterator
+ vector<Tile*>::iterator tileIt;
+ // domains of a tile
+ r_Minterval tileDom;
+
+ // domain of MDD object
+ r_Minterval dom;
+ dom = mdd->getCurrentDomain();
+
+ // get all tiles of result MDD
+ allTiles = mdd->intersect(dom);
+
+ // and iterate over them
+ tileIt = allTiles->begin();
+ while (tileIt != allTiles->end())
+ {
+ tileDom = (*tileIt)->getDomain();
+ cout << "Domain of Tile: ";
+ tileDom.print_status();
+ cout << endl;
+
+ cout << "Tile: " << endl;
+ (*tileIt)->printStatus();
+ cout << endl;
+
+ tileIt++;
+ }
+}
+
+/*************************************************************
+ * Function......: testOperations( DatabaseIf myDB )
+ *
+ * Arguments.....:
+ * myDB: database to use (should be opened)
+ * Return value..: none
+ * Description...: constructs BLOBTiles and inserts them
+ * in root collection.
+ ************************************************************/
+
+MDDObj*
+execBinaryOp( Ops::OpType op,
+ const MDDObj* op1, const r_Minterval& areaOp1,
+ const MDDObj* op2, const r_Minterval& areaOp2 )
+{
+ // contains all tiles of op1
+ vector<Tile*>* allTilesOp1;
+ // contains all tiles of op2 which intersect a given op1 Tile
+ // in the relevant area.
+ vector<Tile*>* intersectTilesOp2;
+ // iterators for tiles of the MDDs
+ vector<Tile*>::iterator tileOp1It;
+ vector<Tile*>::iterator intersectTileOp2It;
+ // domain of tile of Op1
+ r_Minterval tileOp1Dom;
+ // domain of tile of Op2
+ r_Minterval tileOp2Dom;
+ // intersection of domains in relevant area.
+ r_Minterval intersectDom;
+ // pointer to generated result tile
+ PersTile* resTile;
+ // MDDObj for result
+ PersMDDObj* mddres;
+ // translations between the two areas
+ r_Point offset12(areaOp1.dimension());
+ r_Point offset21(areaOp1.dimension());
+ // dummy
+ r_Minterval dummy;
+
+ // calculate translations
+ r_Point originOp1 = areaOp1.get_origin();
+ r_Point originOp2 = areaOp2.get_origin();
+ for(r_Dimension i = 0; i<areaOp1.dimension(); i++)
+ {
+ offset12[i] = originOp2[i] - originOp1[i];
+ offset21[i] = originOp1[i] - originOp2[i];
+ }
+
+ // create MDDObj for result (type has later to be
+ // retrieved from one of the operands)
+ mddres = new PersMDDObj( areaOp1, "ULong" );
+
+ // get all tiles in relevant area of MDD op1
+ allTilesOp1 = op1->intersect(areaOp1);
+
+ // and iterate over them
+ tileOp1It = allTilesOp1->begin();
+ while (tileOp1It != allTilesOp1->end())
+ {
+ // domain of the op1 tile
+ tileOp1Dom = (*tileOp1It)->getDomain();
+
+ // intersect the tile with MDD op2 (including translation)
+ intersectTilesOp2 =
+ op2->intersect(tileOp1Dom.create_translation(offset12));
+
+ // iterate over intersecting tiles
+ intersectTileOp2It = intersectTilesOp2->begin();
+ while (intersectTileOp2It != intersectTilesOp2->end())
+ {
+ tileOp2Dom = (*intersectTileOp2It)->getDomain();
+
+ // the relevant domain is the intersection of the
+ // domains of the two tiles with the relevant area.
+ intersectDom = tileOp1Dom.create_intersection(
+ tileOp2Dom.create_translation(offset21));
+ intersectDom.intersection_with(areaOp1);
+
+ // Creating tile for result. Type should later come from
+ // operand.
+ resTile = new PersTile(intersectDom, myType);
+
+ // carry out operation on the relevant area of the tiles
+ resTile->execBinaryOp(op, intersectDom,
+ (*tileOp1It), intersectDom,
+ (*intersectTileOp2It),
+ intersectDom.create_translation(offset12));
+
+ // insert Tile in result tile
+ mddres->insertTile(resTile);
+
+ intersectTileOp2It++;
+ }
+ tileOp1It++;
+ }
+
+ return mddres;
+}
+
+/*************************************************************
+ * Function......: testConstructors( DatabaseIf myDB )
+ *
+ * Arguments.....:
+ * myDB: database to use (should be opened)
+ * Return value..: none
+ * Description...: constructs BLOBTiles and inserts them
+ * in root collection.
+ ************************************************************/
+
+// function for creating demo tiles
+
+Tile*
+create2DTile( long xmin, long xmax, long ymin, long ymax,
+ BaseType* type )
+{
+ // is copied anyway in constructor
+ unsigned long cell = 0x10000L;
+
+ r_Sinterval s1(xmin, xmax);
+ r_Sinterval s2(ymin, ymax);
+ r_Minterval dom(2);
+ dom << s1 << s2;
+ cout << " Domain of Tile ";
+ dom.print_status();
+ cout << endl;
+ return new PersTile( dom, type, (char*)&cell);
+}
+
+static void testOperations( DatabaseIf myDB )
+{
+ Tile* aTile;
+ ULongType ulongtype;
+ BaseType* type = &ulongtype;
+ MDDObj* res;
+
+ r_Sinterval limits1(1l,10l);
+ r_Sinterval limits2(1l,10l);
+ r_Minterval dom(2);
+ dom << limits1 << limits2;
+
+ r_Sinterval oplimits1(2l,9l);
+ r_Sinterval oplimits2(2l,9l);
+ r_Minterval opdom(2);
+ opdom << oplimits1 << oplimits2;
+
+ r_Sinterval limits21(11l,20l);
+ r_Sinterval limits22(11l,20l);
+ r_Minterval dom2(2);
+ dom2 << limits21 << limits22;
+
+ r_Sinterval oplimits21(12l,19l);
+ r_Sinterval oplimits22(12l,19l);
+ r_Minterval opdom2(2);
+ opdom2 << oplimits21 << oplimits22;
+
+ // create MDD Object for 1st operand
+ cout << "MDD Op1" << endl;
+
+ PersMDDObj* mddop1 = new PersMDDObj( dom, "ULong" );
+
+ cout << " Tile 1 [ 1:5, 1:10 ] " << endl;
+ aTile = create2DTile(1, 5, 1, 10, type);
+ mddop1->insertTile(aTile);
+
+ cout << " Tile 2 [ 6:10, 1:5 ] " << endl;
+ aTile = create2DTile(6, 10, 1, 5, type);
+ mddop1->insertTile(aTile);
+
+ cout << " Tile 3 [ 6:10, 6:10 ] " << endl;
+ aTile = create2DTile(6, 10, 6, 10, type);
+ mddop1->insertTile(aTile);
+
+ mddop1->printStatus();
+
+ // create MDD Object for 2nd operand
+ cout << "MDD Op2" << endl;
+
+ PersMDDObj* mddop2 = new PersMDDObj( dom2, "ULong" );
+
+ cout << " Tile 1 [ 11:17, 11:15 ] " << endl;
+ aTile = create2DTile(11, 17, 11, 15, type);
+ mddop2->insertTile(aTile);
+
+ cout << " Tile 2 [ 11:17, 16:20 ] " << endl;
+ aTile = create2DTile(11, 17, 16, 20, type);
+ mddop2->insertTile(aTile);
+
+ cout << " Tile 3 [ 18:20, 11:20 ] " << endl;
+ aTile = create2DTile(18, 20, 11, 20, type);
+ mddop2->insertTile(aTile);
+
+ mddop2->printStatus();
+
+ res = execBinaryOp(Ops::OP_PLUS, mddop1, opdom, mddop2, opdom2);
+
+ // output result (cast should not be necessary!)
+ ((PersMDDObj*)res)->printStatus();
+ printAllTiles(res);
+
+}
diff --git a/mddmgr/test/test_persmddcoll.cc b/mddmgr/test/test_persmddcoll.cc
new file mode 100644
index 0000000..1a08546
--- /dev/null
+++ b/mddmgr/test/test_persmddcoll.cc
@@ -0,0 +1,768 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+ /**
+ * SOURCE: test_persmddcoll.cc
+ *
+ * MODULE: test for mddobj of cachetamgr
+ *
+ * PURPOSE:
+ * creates a persistent collection of objects and iterators.
+ *
+ * COMMENTS:
+ * none
+ *
+*/
+
+#include "mymalloc/mymalloc.h"
+
+#include <stdlib.h>
+#include <iostream>
+
+#define TEST_PROTECTED
+#define TEST_PRIVATE
+
+
+#include "ulongtype.hh"
+
+#include "tilemgr/persmddcoll.hh"
+#include "tilemgr/persmddobj.hh"
+#include "tilemgr/perstile.hh"
+
+#include "tilemgr/persmddcolliter.hh"
+
+#include "adminif.hh"
+#include "databaseif.hh"
+#include "transactionif.hh"
+
+#include "raslib/rminit.hh"
+#include "typefactory.hh"
+
+#include "mddbasetype.hh"
+#include "mdddomaintype.hh"
+#include "settype.hh"
+
+extern char* myExecArgv0 = "";
+
+RMINITGLOBALS('C')
+
+static char* O2DBName;
+char *collName;
+char defaultCollName[]= "ObjsContainer";
+static int createMDDColl( const char* collName, DatabaseIf* db );
+static void ClearDB( d_Database &DB );
+static void testAccessing( );
+static void testConstructors( );
+static void testRemove( );
+static void testSearch( );
+static void testGetFunctions( );
+static void testLaterInsert( );
+PersTile* createPersTile( const r_Minterval& dom, const BaseType* type );
+static int openCreateDB( const char* O2DBName, DatabaseIf& database );
+
+TransactionIf ta;
+
+/*************************************************************
+ * Function name.: int main( int argc, char** argv)
+ *
+ * Arguments.....:
+ * argc: number of arguments given to program
+ * argv: array of char* with arguments
+ * Return value..: exit status
+ * Description...: none
+ ************************************************************/
+
+int
+main( int argc, char** argv)
+{
+ // variables representing O2 database, ta and session
+ DatabaseIf database;
+ DatabaseIf database1;
+
+ if( argc < 2 ) {
+ cout << "Usage: test_persmddcoll <database> [collName]" << endl;
+ return -1;
+ }
+ O2DBName = argv[1];
+ if ( argc == 3 ) collName = argv[2];
+ else
+ collName = defaultCollName;
+
+ // don't forget to initialize before using AdminIf!
+ myExecArgv0 = argv[0];
+ AdminIf* myAdmin = AdminIf::instance();
+
+ // connect to the database
+ cout << "Connecting to database " << O2DBName
+ << "..." << endl;
+
+ int errorDBOpen = openCreateDB( O2DBName, database );
+ if ( errorDBOpen < 0 )
+ {
+ cout << "Failed at opening newly created database " << errorDBOpen << endl;
+ cout << "Exiting " << endl;
+ return errorDBOpen;
+ }
+
+
+
+ cout << endl << "Deleting root object from the database ..." <<endl;
+ ta.begin( &database );
+ int i = PersMDDColl::destroyRoot( collName, &database );
+ cout << " i == " << i << endl;
+ cout << " &database = " << long( &database) << endl;
+ // database.destroyRootObj( collName );
+ ta.commit( );
+
+
+ ta.begin( &database);
+ createMDDColl( collName, &database );
+ ta.commit( );
+
+ // create collection and objects and put them in the collection
+ cout << endl << "Populate collection ..." << endl;
+ ta.begin( &database );
+ testConstructors( );
+ ta.commit( );
+
+ // read coll and print contents
+ cout << endl << "Read collection and print contents..." << endl;
+ ta.begin( &database );
+ testAccessing( );
+ ta.commit( );
+
+ // connect to the database
+ cout << "Closing database " << O2DBName
+ << "..." << endl;
+ database.close( );
+
+ // connect to the database
+ cout << endl << "Connecting to database SecondBase "
+ << "..." << endl;
+ // database1.open( "SecondBase" );
+
+ errorDBOpen = openCreateDB( "SecondBase", database1 );
+ if ( errorDBOpen < 0 )
+ {
+ cout << "Failed at opening database SecondBase " << errorDBOpen << endl;
+ cout << "Exiting " << endl;
+ return errorDBOpen;
+ }
+
+ // read coll and print contents
+ cout << endl << "Read collection and print contents..." << endl;
+ cout << "Read only? "<< endl;
+ int ro;
+ cin >> ro;
+ ta.begin( &database1, ro );
+ cout << endl << " testAccessing before "<<endl;
+ testAccessing( );
+ ta.commit( );
+
+/*
+ // add some new tiles
+ cout << endl << "Insert more tiles to the existing objects" << endl;
+ ta.begin( &database );
+ testLaterInsert( );
+ ta.commit( );
+
+ // read coll and print contents
+ cout << endl << "Read collection and print contents..." << endl;
+ ta.begin( &database );
+ testAccessing( );
+ ta.commit( );
+
+
+ // search for an interval
+ cout << endl << "Test region search ..." << endl;
+ ta.begin( &database );
+ testSearch( );
+ ta.commit( );
+
+ // search for an interval
+ cout << endl << "Test get functions of MDDObj ..." << endl;
+ ta.begin( &database );
+ testGetFunctions( );
+ ta.commit( );
+
+ // test remove operation and print contents
+ cout << endl << "Test remove ..." << endl;
+ ta.begin( &database );
+ testRemove( );
+ ta.commit( );
+
+ // read coll and print contents
+ cout << endl << "Read collection and print contents..." << endl;
+ ta.begin( &database );
+ testAccessing( );
+ ta.commit( );
+*/
+ cout << endl << "Ending O2 session..." << endl;
+ database.close( );
+ delete myAdmin;
+}
+/*************************************************************
+ * Function......: testConstructors()
+ *
+ ************************************************************/
+PersTile*
+createPersTile( const r_Minterval& dom, const BaseType* type )
+{
+ char* cells = (char*)mymalloc(dom.cell_count() * type->getSize());
+ PersTile* t = new PersTile( dom, type, cells );
+ return t;
+}
+
+/*************************************************************
+ * Function......: testConstructors()
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: constructs Indices and inserts them
+ * in root collection.
+ ************************************************************/
+
+static void testConstructors()
+{
+ const BaseType* ulongTypeObj = TypeFactory::mapType("ULong");
+ const BaseType* boolTypeObj = TypeFactory::mapType("Bool");
+ char* uLongCells;
+ char* boolCells;
+
+ const MDDBaseType* mType1 =
+ (const MDDBaseType* ) TypeFactory::mapMDDType("TestSMDomainType2D");
+ const MDDBaseType* mType2 =
+ (const MDDBaseType* ) TypeFactory::mapMDDType("TestSMDomainType3D");
+
+ cout << "....testConstructors"<< endl;
+
+
+ // read root object
+
+ try {
+ PersMDDColl objsSet1("WrongName");
+ }
+ catch (...)
+ {
+ cout <<"Error caught ................."<< endl;
+ }
+
+ PersMDDColl objsSet(collName);
+
+/*
+ // test for crash of O2 iterator reset in case the collection is empty
+ cout << "createIterator " << endl;
+ MDDCollIter* it = objsSet.createIterator( );
+ // cout << " Iterator not Done returns " << it->notDone( );
+ // if ( it->notDone( ) ) it->reset( );
+ cout << " Iterator reset " << endl;
+ it->reset( );
+ // cout << " Testing advance on an empty collection" << endl;
+ // it->advance( ); // OK
+ // cout <<" Testing get_element on an empty collection" << endl;
+ // MDDObj* testIterMDDObj = it->getElement( ); // FATAL ERROR
+ // cout <<" get_element returned " << testIterMDDObj << endl;
+*/
+
+ // create MDD Object 1
+
+ cout << " mddObj1" << endl;
+ cout << " tile 1 = nil, 10-12, 20-24 "<< endl;
+ r_Sinterval limits1Obj1(10l,12l);
+ r_Sinterval limits2Obj1(20l,24l);
+ r_Minterval dom(2);
+ dom << limits1Obj1 << limits2Obj1;
+
+
+ r_Minterval tmpInt = *( ( MDDDomainType* ) mType1 )->getDomain( );
+ PersMDDObj* MDDObj1 = new PersMDDObj( mType1, tmpInt );
+
+ PersTile* tile1Obj1 = createPersTile( dom, ulongTypeObj);
+ MDDObj1->insertTile(tile1Obj1);
+
+ cout << " tile 2 = nil, 0-400, 22-24 "<< endl;
+ dom[0].set_interval(0l,400l);
+ dom[1].set_interval(22l,24l);
+ PersTile* tile2Obj1 = createPersTile( dom, ulongTypeObj);
+ MDDObj1->insertTile(tile2Obj1);
+
+ cout << " tile 3 = nil, 0-600, 10-1000 "<< endl;
+ dom[0].set_interval(0l,600l);
+ dom[1].set_interval(10l,1000l);
+ PersTile* tile3Obj1 = createPersTile( dom, ulongTypeObj);
+ MDDObj1->insertTile(tile3Obj1);
+
+ cout << " MDDObj1 == isPersistent:" << MDDObj1->isPersistent( )<< ";" ;
+ MDDObj1->printStatus( );
+ cout << endl;
+
+ objsSet.insert(MDDObj1);
+
+
+ // create MDD Object
+
+ cout << " mddObj2 "<< endl;
+ cout << " tile 1 = nil, 0-19, 20-59, 30-59 "<< endl;
+ r_Sinterval limits1Obj2(0l,19l);
+ r_Sinterval limits2Obj2(20l,59l);
+ r_Sinterval limits3Obj2(30l,59l);
+ r_Minterval dom2(3);
+ dom2 << limits1Obj2 << limits2Obj2 << limits3Obj2;
+ // PersMDDObj* MDDObj2 = new PersMDDObj( dom2, "Bool");
+
+ tmpInt = *( ( MDDDomainType* ) mType2 )->getDomain( );
+ PersMDDObj* MDDObj2 = new PersMDDObj( mType2, tmpInt );
+
+ PersTile* tile1Obj2 = createPersTile( dom2, boolTypeObj);
+ MDDObj2->insertTile( tile1Obj2 );
+
+ cout << " tile 2 = nil, 20-39, 60-79, 60-89 "<< endl;
+ dom2[0].set_interval(20l,39l);
+ dom2[1].set_interval(60l,79l);
+ dom2[2].set_interval(60l,89l);
+ PersTile* tile2Obj2 = createPersTile( dom2, boolTypeObj);
+
+ MDDObj2->insertTile(tile2Obj2);
+
+ cout << " MDDObj2 == isPersistent:" << MDDObj2->isPersistent( )<< ";" ;
+ MDDObj2->printStatus( );
+ cout << endl;
+
+ objsSet.insert(MDDObj2);
+
+ objsSet.releaseAll( );
+
+}
+
+/*************************************************************
+ * Function......: testAccessing()
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: reads DirTilesIx's and shows contents
+ ************************************************************/
+
+static void testAccessing()
+{
+ PersMDDObj* accessedObj;
+
+ cout << "....testAccessing"<<endl;
+ try{
+ PersMDDColl objsSet(collName);
+
+ // To test PersMDDColl::printStatus( )
+ // objsSet.printStatus( );
+
+ // To test PersMDDObj::printStatus( ), MDDCollIter::createIterator( ) and
+ // MDDCollIter methods :
+
+
+ cout << "Iterating through the collection with PersMDDCollIter " << endl;
+ MDDCollIter* objsIt = objsSet.createIterator( );
+
+ for( int i = 1 ; objsIt->notDone( ); i++, objsIt->advance( ))
+ {
+ accessedObj = (PersMDDObj*) objsIt->getElement();
+ cout << i<<". MDD object in set:" << endl;
+ accessedObj->printStatus();
+ cout << endl << endl;
+ }
+ delete objsIt;
+ objsSet.releaseAll( );
+ }
+ catch(...)
+ {
+ cout << "Error opening collection !!!! "<<endl;
+ exit(-1);
+ }
+}
+
+/*************************************************************
+ * Function......: testLaterInsert()
+ *
+ * Description...:
+ ************************************************************/
+
+static void testLaterInsert()
+{
+ PersMDDObj* accessedObj;
+
+ cout << "....testAccessing"<<endl;
+
+ PersMDDColl objsSet(collName);
+
+ // To test PersMDDColl::printStatus( )
+ // objsSet.printStatus( );
+
+ // To test PersMDDObj::printStatus( ), MDDCollIter::createIterator( ) and
+ // MDDCollIter methods :
+
+
+ cout << "Iterating through the collection with PersMDDCollIter " << endl;
+ MDDCollIter* objsIt = objsSet.createIterator( );
+
+
+ PersTile *t, *t2, *t3;
+ for( int i = 1 ; objsIt->notDone( ); i++, objsIt->advance( ))
+ {
+ accessedObj = (PersMDDObj*) objsIt->getElement();
+ switch( accessedObj->getDimension( ) )
+ {
+ case 2 :
+ t2 = new PersTile( r_Minterval("[40:60,80:100]"),
+ accessedObj->getCellType( ) );
+ t = t2;
+ break;
+ case 3 :
+ t3 = new PersTile(r_Minterval("[40:60,80:100,0:20]"),
+ accessedObj->getCellType( ) );
+ t = t3;
+ break;
+ default:
+ cout << "Error Dimensionality not expected" << endl;
+ break;
+ }
+ accessedObj->insertTile(t);
+ cout << i<<". MDD object in set:" << endl;
+ accessedObj->printStatus();
+ cout << endl << endl;
+ }
+ delete objsIt;
+ objsSet.releaseAll( );
+}
+
+
+/*************************************************************
+ * Function......: testSearch()
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: reads Index's and shows contents
+ ************************************************************/
+
+static void testSearch()
+{
+
+ MDDObj* accessedObj;
+
+ cout << "....testSearch"<<endl;
+
+ PersMDDColl objsSet(collName);
+
+ MDDCollIter* objsIt = objsSet.createIterator( );
+
+ for( int i = 1 ; objsIt->notDone( ); i++, objsIt->advance( ))
+ {
+ accessedObj = objsIt->getElement();
+
+ cout << "Accessed Object " << endl;
+ accessedObj->printStatus( );
+ cout << endl;
+
+ if (i == 1 || i == 2)
+ {
+ r_Minterval searchInt1(2);
+ r_Minterval searchInt2(3);
+ vector< Tile* >* entriesList;
+
+ cout << " -- " << i << ". MDD object in list. Search for:";
+ switch (i) {
+ case 1: searchInt1[0].set_interval(10l,20l);
+ searchInt1[1].set_interval(10l,30l);
+ cout << " 10-20, 10-30" << endl;
+ entriesList = accessedObj->intersect(searchInt1);
+ break;
+ case 2: searchInt2[0].set_interval(10l,20l);
+ searchInt2[1].set_interval(10l,30l);
+ searchInt2[2].set_interval(40l,50l);
+ cout << " 10-20, 10-30, 40-50" <<endl;
+ entriesList = accessedObj->intersect(searchInt2);
+ break;
+ default: break;
+ }
+ cout << " -- Search result: " << endl;
+ vector<Tile*>::iterator entryIt = entriesList->begin();
+
+ while (entryIt != entriesList->end())
+ {
+ // (*entryIt)->printStatus();
+ r_Minterval tileInterval = (*entryIt)->getDomain();
+ int dimensionality = tileInterval.dimension();
+
+ cout << " PersTile printStatus";
+ cout << " domain == " << dimensionality << ": ";
+ for (int i = 0; i <dimensionality; i++)
+ cout << tileInterval[i].low() << "-"
+ << tileInterval[i].high() <<", ";
+ cout << endl;
+
+ entryIt++;
+ }
+ delete entriesList;
+ }
+ }
+ delete objsIt;
+ objsSet.releaseAll( );
+}
+
+/*************************************************************
+ * Function......: testGetFunctions()
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: reads Index's and shows contents
+ ************************************************************/
+
+static void testGetFunctions()
+{
+ PersMDDObj* accessedObj;
+
+ cout << "....testGetFunctions"<<endl;
+
+ PersMDDColl objsSet(collName);
+
+ MDDCollIter* objsIt = objsSet.createIterator( );
+
+ vector< Tile* >* entriesList;
+
+ for( int i = 1 ; objsIt->notDone( ); i++, objsIt->advance( ))
+ {
+ r_Minterval currDom;
+ r_Minterval defDom;
+
+ cout << " " << i << ". Object" << endl;
+ accessedObj = (PersMDDObj*) objsIt->getElement();
+
+
+ defDom = accessedObj->getDefinitionDomain( );
+ cout << " GetDefinitionDomain result: ";
+ defDom.print_status( );
+ cout << endl;
+
+ currDom = accessedObj->getCurrentDomain( );
+ cout << " GetCurrentDomain result: ";
+ currDom.print_status( );
+ cout << endl;
+
+ entriesList = accessedObj->getTiles( );
+ cout << " -- GetTiles result: " << endl;
+ vector<Tile*>::iterator entryIt = entriesList->begin();
+
+ while (entryIt != entriesList->end())
+ {
+ // (*entryIt)->printStatus();
+ r_Minterval tileInterval = (*entryIt)->getDomain();
+ int dimensionality = tileInterval.dimension();
+
+ cout << " PersTile ";
+ cout << " domain == " << dimensionality << ": ";
+ for (int i = 0; i <dimensionality; i++)
+ cout << tileInterval[i].low() << "-" << tileInterval[i].high() <<", ";
+ cout << endl;
+ entryIt++;
+ }
+ delete entriesList;
+ }
+ delete objsIt;
+ objsSet.releaseAll( );
+}
+
+/*************************************************************
+ * Function......: testRemove()
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: reads DirTilesIx's and shows contents
+ ************************************************************/
+
+static void testRemove()
+{
+ PersMDDObj* accessedObj;
+
+ cout << "....testRemove"<<endl;
+
+ PersMDDColl objsSet(collName);
+ // PersMDDColl objsSet("Qualquercoisa");
+ // To test PersMDDColl::printStatus and PersMDDColl::remove
+
+
+ MDDCollIter* objsIt = objsSet.createIterator( );
+
+ cout << "-- Remove second element from collection " << endl;
+
+ for( int i = 1 ; objsIt->notDone( ) && i < 2; i++, objsIt->advance( ))
+ {
+ accessedObj = (PersMDDObj*) objsIt->getElement();
+ }
+ cout << "Delete of objsIt:" << endl;
+ delete objsIt;
+ cout << "Finished Delete of objsIt." << endl;
+ cout << "Remove accessedObj:" << endl;
+ objsSet.remove( accessedObj );
+ cout << "Finished Remove accessedObj." << endl;
+}
+
+/*************************************************************
+ * Function......: openCreateDB()
+ *
+ ************************************************************/
+
+static int openCreateDB( const char* O2DBName, DatabaseIf& database )
+{
+ cout << "openCreateDB " << O2DBName << endl;
+
+ int errorDBOpen;
+ try{
+ errorDBOpen = database.open( O2DBName );
+ }
+ catch( ...)
+ {
+ cout << "Caught Exception " << endl;
+ errorDBOpen = -6;
+ }
+ if ( errorDBOpen < 0 )
+ {
+ cout << "Database doesn't exist. Create it new ... " << endl;
+ cout << "Creating new database " << O2DBName
+ << "..." << endl;
+ database.create( O2DBName, "TestSMSchema" );
+ cout << endl << "Connecting to database " << O2DBName
+ << "..." << endl;
+
+ try{
+ errorDBOpen = database.open( O2DBName );
+ }
+ catch(...)
+ {
+ errorDBOpen = -6;
+ }
+ }
+ if ( errorDBOpen < 0 )
+ {
+ cout << "Failed at opening newly created database " << errorDBOpen << endl;
+ cout << "Exiting " << endl;
+ return errorDBOpen;
+ }
+ return errorDBOpen;
+}
+
+/*************************************************************
+ * Function......: createMDDColl( )
+ ************************************************************/
+static int
+createMDDColl( const char* collName, DatabaseIf* db )
+{
+ MDDDomainType* mType1 = 0;
+ MDDDomainType* mType2 = 0;
+ MDDType* mt = 0;
+ CollectionType* collType1 = 0;
+
+ const BaseType* ulongTypeObj = TypeFactory::mapType("ULong");
+
+ const MDDDomainType* cmType1 =
+ ( MDDDomainType* ) TypeFactory::mapMDDType( "TestSMDomainType2D" );
+ const MDDDomainType* cmType2 =
+ ( MDDDomainType* ) TypeFactory::mapMDDType( "TestSMDomainType3D" );
+
+ const CollectionType* collType =
+ (CollectionType*)TypeFactory::mapSetType( "ObjsContainerType" );
+
+
+ if( !cmType1 || !cmType2 || !collType )
+ {
+ char name1[] = "TestSMDomainType2D";
+ char name2[] = "TestSMDomainType3D";
+
+ r_Sinterval limits1Obj1(0l,1000l);
+ r_Sinterval limits2Obj1(0l,800l);
+ r_Minterval dom1(2);
+ dom1 << limits1Obj1 << limits2Obj1;
+ cout << "MDD Type 1 , domain "<< dom1 << endl;
+
+ cout << " tile 1 = nil, 0-19, 20-59, 30-59 "<< endl;
+ r_Sinterval limits1Obj2(0l,19l);
+ r_Sinterval limits2Obj2(20l,59l);
+ r_Sinterval limits3Obj2(30l,59l);
+ r_Minterval dom2(3);
+ dom2 << limits1Obj2 << limits2Obj2 << limits3Obj2;
+ cout << "MDD Type 2 , domain "<< dom2 << endl;
+
+ // MDDDomainType* mType1 =
+ mType1 =
+ new MDDDomainType((char*) name1, ( BaseType* ) ulongTypeObj, dom1 );
+ // MDDDomainType* mType2 =
+ mType2 =
+ new MDDDomainType((char*) name2, ( BaseType* ) ulongTypeObj, dom2 );
+
+ cout << "MDD Type1 == ";
+ mType1->print_status( cout );
+ cout << endl;
+ cout << "MDD Type2 == ";
+ mType2->print_status( cout );
+ cout << endl;
+
+ TypeFactory::addMDDType( mType1 );
+ TypeFactory::addMDDType( mType2 );
+
+ if ( !collType )
+ {
+ cout << "Collection type newly created " << endl;
+ // MDDType* mt = new MDDType( );
+ mt = new MDDType( );
+ cout << "MDDtype created "<< endl;
+ collType1 = new SetType( "ObjsContainerType", mType1 );
+ cout << "Set Type created ... ";
+ collType = collType1;
+ TypeFactory::addSetType( (SetType*) collType );
+ cout <<" and added "<< endl;
+
+ }
+
+ }
+ cout << "Creating root collection" << endl;
+
+ OId oColl;
+ if( OId::allocateMDDCollOId( &oColl ) == 0 )
+ cout <<"Successfully allocated OId for collection " << oColl << endl;
+ else
+ cout <<"Error allocating OId for collection " << endl;
+
+ PersMDDColl* col;
+ try {
+ // CollectionType* ct = TypeFactory::mapSetType( "ObjsContainerType" );
+ col = PersMDDColl::createRoot( collName, oColl, collType, db );
+ }
+ catch (...)
+ {
+ cout <<"Error caught ................."<< endl;
+ return -1;
+ }
+
+ cout << "Committing TA ..."<< endl;
+ ta.commit( );
+
+ if ( col ) delete col;
+ cout << "Col freed . "<< endl;
+
+ ta.begin( db );
+ return 0;
+}
diff --git a/mddmgr/test/test_persmddobj.cc b/mddmgr/test/test_persmddobj.cc
new file mode 100644
index 0000000..b54a851
--- /dev/null
+++ b/mddmgr/test/test_persmddobj.cc
@@ -0,0 +1,1125 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_persmddobj.cc
+ *
+ * MODULE: test for PersMDDObj of mddmgr
+ *
+ * PURPOSE:
+ * creates a persistent collection of objects and iterators and tests
+ * usage of O2 OIds.
+ *
+ * COMMENTS:
+ * none
+ *
+*/
+
+#include "mymalloc/mymalloc.h"
+
+#define TEST_PROTECTED
+#define TEST_PRIVATE
+
+#include <stdlib.h>
+#include <iostream>
+
+#include "ulongtype.hh"
+
+#include "mddmgr/persmddcoll.hh"
+#include "mddmgr/persmddobj.hh"
+#include "mddmgr/perstile.hh"
+
+#include "mddmgr/persmddcolliter.hh"
+
+#include "adminif.hh"
+#include "databaseif.hh"
+#include "transactionif.hh"
+#include "oidif.hh"
+
+#include "raslib/rminit.hh"
+#include "typefactory.hh"
+
+#include "mddif/dbmddobj.hh"
+#include "mddif/dbmddcoll.hh"
+
+#include "mddbasetype.hh"
+#include "mdddomaintype.hh"
+#include "settype.hh"
+
+
+/*
+ Global Variables
+*/
+extern char* myExecArgv0 = "";
+
+RMINITGLOBALS('C')
+
+static char* O2DBName;
+char *collName;
+char defaultCollName[]= "ObjsContainer";
+OId globalOId1, globalOId2;
+OId globalCollOId;
+EOId globalEOId[4];
+int numObjsCreated;
+TransactionIf ta;
+int ExitNo;
+
+/*
+ Functions
+*/
+
+int
+getOption( )
+{
+ unsigned int result;
+ cout << endl;
+ cout << "Choose Option : " << endl;
+ cout << "-----------------------------------------------------------------"<<endl;
+ cout << " 1 - Create MDD collection with name .. " << collName << endl;
+ cout << " 2 - Populate collection with MDD objects (testConstructors) " << endl;
+ cout << " 3 - Access MDD collection given name (testAccessing) " << endl;
+ cout << " 4 - Access MDD collection given OId (testAccessing)" << endl;
+ cout << " 5 - Access MDD object given OId (testAccessingMDDObj) " << endl;
+ cout << " 6 - Remove MDD object from the collection given OId (testRemove) "<<endl;
+ cout << " 7 - Test PersMDDObj::intersect( ) (testSearch) " <<endl;
+ cout << " 8 - Test PersMDDColl::getCardinality( ) "<<endl;
+ cout << " 9 - Test PersMDDObj get functions "<< endl;
+ cout << " 10 - Remove MDD Collection given OId " << endl;
+ cout << " 11 - Insert MDD given OId in a second collection "<< endl;
+ cout << " 12 - Insert tile in MDD given OId "<< globalOId1 <<endl;
+ cout << " 13 - Test removeTile from MDD "<< globalOId1 << endl;
+ ExitNo = 14;
+ cout << " " << ExitNo << " - Exit " << endl;
+ cout << "------------------------------------------------------------------"<<endl;
+ cout << "Enter option: ";
+ cin >> result;
+ return result;
+}
+
+// 1 - Create MDD collection
+static int createMDDColl( const char* collName, DatabaseIf* db );
+
+// 2 - Populate collection with MDD objects
+static void testConstructors( char* cn );
+
+// 3 - Retrieves an MDD collection with name cn and prints contents:
+static void testAccessing( char* cn );
+
+// 4 - Retrieves an MDD collection with OId o and prints contents:
+static void testAccessing( OId o );
+
+// 5 - Retrieves an MDD object with OId o and prints contents:
+static void testAccessingMDDObj( OId o );
+
+// Removes one of the MDD objects in the collection
+static void testRemove( );
+
+// 6 - Removes MDD object with OId o in the collection
+static void testRemove( OId o );
+
+// 7 - Test PersMDDObj::intersect( ) objects of the collection
+static void testSearch( );
+
+// 8 - Test PersMDDColl::getCardinality( )
+static void testGetCardinality( char* cn);
+
+// 9 - Scans collection and tests PersMDDObj get functions
+static void testGetFunctions( );
+
+//10 - Remove MDD collection given OId
+
+//11 - Insert MDD given OId in a second collection
+static void testInsertMDDObjColl( OId o, char* cn );
+
+//12 - Test later insertion of tile in PersMDDObj
+static void testLaterInsert( OId o );
+
+//13 - Test removeTile from an MDD obj
+static void testRemoveTile( OId o );
+
+// Tries accessing several OIds, including ilegal ones, to test
+// several error conditions.
+static void testAccessingOId( );
+
+
+/*************************************************************
+ * Function name.: int main( int argc, char** argv)
+ *
+ * Arguments.....:
+ * argc: number of arguments given to program
+ * argv: array of char* with arguments
+ * Return value..: exit status
+ * Description...: none
+ ************************************************************/
+int
+main( int argc, char** argv)
+{
+ // variables representing O2 database, ta and session
+ DatabaseIf database;
+
+ if( argc < 2 ) {
+ cout << "Usage: test_persmddcoll <database> [collName]" << endl;
+ return -1;
+ }
+ O2DBName = strdup( argv[1] );
+ if ( argc == 3 ) collName = strdup( argv[2] );
+ else
+ collName = defaultCollName;
+
+ // don't forget to initialize before using AdminIf!
+ myExecArgv0 = argv[0];
+ AdminIf* myAdmin = AdminIf::instance();
+
+
+ // connect to the database
+ cout << "Connecting to database " << O2DBName
+ << "..." << endl;
+ int errorDBOpen;
+ try{
+ errorDBOpen = database.open( O2DBName );
+ }
+ catch( ...)
+ {
+ cout << "Caught Exception " << endl;
+ errorDBOpen = -6;
+ }
+ if ( errorDBOpen < 0 )
+ {
+ cout << "Database doesn't exist. Create it new ... " << endl;
+ cout << "Creating new database " << O2DBName
+ << "..." << endl;
+ database.create( O2DBName, "TestSMSchema" );
+ cout << "Connecting to database " << O2DBName
+ << "..." << endl;
+ try{
+ errorDBOpen = database.open( O2DBName );
+ }
+ catch(...)
+ {
+ errorDBOpen = -6;
+ }
+ }
+ if ( errorDBOpen < 0 )
+ {
+ cout << "Failed at opening newly created database " << errorDBOpen << endl;
+ cout << "Exiting " << endl;
+ return errorDBOpen;
+ }
+
+ ta.begin( &database );
+ cout << endl << "Deleting root object from the database ..." <<endl;
+ int i = PersMDDColl::destroyRoot( collName, &database );
+ cout << " i == " << i << endl;
+ // cout << " &database = " << long( &database) << endl;
+ ta.commit( );
+
+ char c;
+ int error;
+
+ for( unsigned opt = getOption( ); opt != ExitNo ; opt = getOption( ) )
+ {
+ cout <<"Transaction begin ... " << endl;
+ ta.begin( &database );
+ switch ( opt )
+ {
+ case 1: // 1 - Create MDD collection with name
+ // create root collection
+ cout << endl << "Creating mdd types and root collection..." << endl;
+ if ( createMDDColl( collName, &database ) != 0 )
+ {
+ cout <<"Error caught ................."<< endl;
+ cout << endl << "Ending O2 session..." << endl;
+ ta.commit( );
+ database.close( );
+ delete myAdmin;
+ exit( 1 );
+ }
+ break;
+
+ case 2: // 2 - Populate collection with MDD objects (testConstructors)
+ // create objects and put them in the collection
+ cout << endl << "Populate collection ..." << endl;
+ testConstructors( collName );
+ break;
+
+ case 3: // 3 - Access MDD collection given name (testAccessing)
+ // read coll and print contents
+ cout << endl << "Read collection " << collName << " and print contents..." << endl;
+ testAccessing( collName );
+ break;
+
+ case 4: // 4 - Access MDD collection given OId (testAccessing)
+ cout << endl << "Read collection " << globalCollOId << " and print contents..." << endl;
+ testAccessing( globalCollOId );
+ break;
+
+ case 5: // 5 - Access MDD object given OId (testAccessingMDDObj)
+ cout << endl << "Test Accessing MDD with OId " << globalOId1 << " ... " << endl;
+ testAccessingMDDObj( globalOId1 );
+ break;
+
+ case 6: // 6 - Remove MDD object from the collection given OId (testRemove)
+ cout<< endl << "Remove MDD with OId " << globalOId1 << " ..." << endl;
+ testRemove( globalOId1 );
+ break;
+
+ case 7: // 7 - Test PersMDDObj::intersect( ) (testSearch)
+ cout << endl << "Test region search ..." << endl;
+ testSearch( );
+ break;
+
+ case 8: // 8 - Test PersMDDColl::getCardinality( )
+ cout << endl << "Get cardinality of collection" << collName <<" ..." << endl;
+ testGetCardinality( collName );
+ break;
+
+ case 9: // 9 - Test PersMDDObj get functions
+ cout << endl <<"Test PersMDDObj get functions " << endl;
+ testGetFunctions( );
+ break;
+
+ case 10: // 10 - Remove MDD Collection given OId
+ cout << endl << "Remove MDD collection with OId ";
+ cout << globalCollOId << " ..." << endl;
+ error = PersMDDColl::destroyRoot( globalCollOId, &database );
+ if (error )
+ cout << " Error destroying root " << endl;
+ break;
+
+ case 11: // 11 - Insert MDD given OId in a second collection
+ cout << endl << "Insert Object with OId " << globalOId1;
+ cout << " in collection Coleccao1 " << endl;
+ cout << "First, create collection" << endl;
+ if ( createMDDColl( "Coleccao1", &database ) != 0 )
+ {
+ cout <<"Error caught ................."<< endl;
+ cout << endl << "Ending O2 session..." << endl;
+ ta.commit( );
+ database.close( );
+ delete myAdmin;
+ exit( 1 );
+ }
+ cout << "Then insert object with OId "<< globalOId1 << endl;
+ testInsertMDDObjColl( globalOId1 , "Coleccao1");
+ cout << endl;
+ break;
+
+ case 12: // 12 - Insert new tiles in the MDD object
+ cout << endl << "Insert Tile in object with OId " << globalOId1;
+ testLaterInsert( globalOId1 );
+ cout << endl;
+ break;
+
+ case 13: // 13 - Remove a tile from the MDD object
+ cout << endl << "Remove Tile from object with OId " << globalOId1;
+ testRemoveTile( globalOId1 );
+ cout << endl;
+ break;
+
+ default:
+ break;
+ }
+ cout <<"Transaction abort (A/a) or commit (default)? ";
+ cin >> c;
+ if ( c == 'A' || c == 'a' )
+ {
+ ta.abort( );
+ cout <<"End of Transaction Abort..."<<endl;
+ }
+ else ta.commit( );
+ if ( opt == 6 )
+ {
+ cout<<"Garbage ? ( y /n ) ";
+ cin >> c;
+ if (c =='y' || c == 'Y' )
+ {
+ cout <<"Garbaging ..."<< endl;
+ ta.begin( &database );
+ database.garbage( );
+ ta.commit( );
+ }
+ }
+ cout <<"End of transaction commit... "<<endl;
+ } // for opt
+
+
+ cout << endl << "Ending O2 session..." << endl;
+ database.close( );
+ delete myAdmin;
+
+ free( O2DBName );
+ if ( collName != defaultCollName ) free( collName );
+ return 0;
+
+}
+
+/*************************************************************
+ * Functions......:
+ *
+ * static void
+ * testInsertMDDObjColl( OId o, char* cn )
+ *
+ * static void
+ * testConstructors( char* collName )
+ *
+ ************************************************************/
+static void
+testInsertMDDObjColl( OId o, char* cn )
+{
+ cout << "....testInsertMDDObjColl "<< o <<","<< cn << endl;
+ PersMDDObj* obj = new PersMDDObj( O2DBName,o );
+ PersMDDColl objsSet( cn );
+ objsSet.insert( obj );
+ delete obj;
+
+}
+
+static void testConstructors( char* collName )
+{
+
+ const BaseType* ulongTypeObj = TypeFactory::mapType("ULong");
+ const BaseType* boolTypeObj = TypeFactory::mapType("Bool");
+ // char uLongCell[] = {0,0,0,0};
+ char* uLongCells;
+ // char boolCell = 0;
+ char* boolCells;
+
+
+ const MDDBaseType* mType1 =
+ (const MDDBaseType* ) TypeFactory::mapMDDType("TestSMDomainType2D");
+ const MDDBaseType* mType2 =
+ (const MDDBaseType* ) TypeFactory::mapMDDType("TestSMDomainType3D");
+
+ cout << "....testConstructors"<< endl;
+
+ OId oid1;
+ if ( OId::allocateMDDOId( &oid1 ) == 0)
+ cout << "Successfull allocation of OId " << oid1 <<endl;
+ else
+ {
+ cout << "Error by allocation of OId" <<endl;
+ exit(1);
+ }
+ OId oid2;
+ if ( OId::allocateMDDOId( &oid2 ) == 0)
+ cout << "Successfull allocation of OId " << oid2 <<endl;
+ else
+ {
+ cout << "Error by allocation of OId" <<endl;
+ exit(1);
+ }
+
+ globalOId1 = oid1;
+ globalOId2 = oid2;
+
+ // read root object
+
+ PersMDDColl objsSet(collName);
+
+
+ // create MDD Object 1
+
+ cout << "Creating mddObj1" << endl;
+ cout << "tile 1 = nil, 10-12, 20-24 "<< endl;
+ r_Sinterval limits1Obj1(10l,12l);
+ r_Sinterval limits2Obj1(20l,24l);
+ r_Minterval dom(2);
+ dom << limits1Obj1 << limits2Obj1;
+
+ r_Minterval tmpInt = *( ( MDDDomainType* ) mType1 )->getDomain( );
+ PersMDDObj* MDDObj1 = new PersMDDObj( mType1, tmpInt, O2DBName, oid1 );
+
+
+ uLongCells = (char*) mymalloc( dom.cell_count() * ulongTypeObj->getSize() );
+ PersTile* tile1Obj1 = new PersTile( dom, ulongTypeObj, uLongCells );
+
+ MDDObj1->insertTile(tile1Obj1);
+
+ cout << "tile 2 = nil, 0-400, 22-24 "<< endl;
+ dom[0].set_interval(0l,400l);
+ dom[1].set_interval(22l,24l);
+
+ uLongCells = (char*) mymalloc( dom.cell_count() * ulongTypeObj->getSize() );
+ PersTile* tile2Obj1 = new PersTile( dom, ulongTypeObj, uLongCells );
+ MDDObj1->insertTile(tile2Obj1);
+
+ cout << "tile 3 = nil, 0-600, 10-1000 "<< endl;
+ dom[0].set_interval(0l,600l);
+ dom[1].set_interval(10l,1000l);
+ uLongCells = (char*) mymalloc( dom.cell_count() * ulongTypeObj->getSize() );
+ PersTile* tile3Obj1 = new PersTile( dom, ulongTypeObj, uLongCells );
+ MDDObj1->insertTile(tile3Obj1);
+
+ cout << "MDDObj1 == isPersistent:" << MDDObj1->isPersistent( )<< ";" <<endl;
+ MDDObj1->printStatus( );
+ cout << endl;
+
+ objsSet.insert(MDDObj1);
+
+ // create MDD Object
+ cout << "Creating mddObj2 "<< endl;
+ cout << "tile 1 = nil, 0-19, 20-59, 30-59 "<< endl;
+ r_Sinterval limits1Obj2(0l,19l);
+ r_Sinterval limits2Obj2(20l,59l);
+ r_Sinterval limits3Obj2(30l,59l);
+ r_Minterval dom2(3);
+ dom2 << limits1Obj2 << limits2Obj2 << limits3Obj2;
+
+ tmpInt = *( ( MDDDomainType* ) mType2 )->getDomain( );
+ PersMDDObj* MDDObj2 = new PersMDDObj( mType2, tmpInt, O2DBName, oid2 );
+
+ boolCells = (char*) mymalloc( dom2.cell_count() * boolTypeObj->getSize() );
+ PersTile* tile1Obj2 = new PersTile( dom2, boolTypeObj, boolCells);
+ MDDObj2->insertTile( tile1Obj2 );
+
+ cout << "tile 2 = nil, 20-39, 60-79, 60-89 "<< endl;
+ dom2[0].set_interval(20l,39l);
+ dom2[1].set_interval(60l,79l);
+ dom2[2].set_interval(60l,89l);
+ boolCells = (char*) mymalloc( dom2.cell_count() * boolTypeObj->getSize() );
+ PersTile* tile2Obj2 = new PersTile( dom2, boolTypeObj, boolCells );
+
+ MDDObj2->insertTile(tile2Obj2);
+
+
+ cout << "MDDObj2 == isPersistent:" << MDDObj2->isPersistent( )<< ";" <<endl;
+ MDDObj2->printStatus( );
+ cout << endl;
+
+/*
+ // This program doesn't work if the TA is aborted when OIds are
+ // allocated, even if all allocated OIds are binded. Question: is it
+ // because of dangling handles? This little test was done to
+ // check that.
+ // This without oids works with ta.abort
+ // conclusion: the problem with abort is not due to the handles
+ Handle hd;
+ d_Ref<DBMDDObj> refObj = MDDObj2->getDBMDDObjId();
+ hd = refObj.o2_get_handle();
+*/
+
+
+ objsSet.insert(MDDObj2);
+ numObjsCreated = 2;
+
+ cout << "Release all " << endl;
+
+ ( ( PersMDDColl ) objsSet ).releaseAll( );
+
+}
+
+
+/*************************************************************
+ * Function......: testAccessing( char* cn )
+ * testAccessing( OId o )
+ ************************************************************/
+
+static void testAccessing( char* cn )
+{
+ PersMDDObj* accessedObj;
+
+ cout << "....testAccessing collection "<< cn << endl;
+
+ try{
+ PersMDDColl objsSet( cn );
+
+ // To test PersMDDColl::printStatus( )
+ // objsSet.printStatus( );
+
+ // To test PersMDDObj::printStatus( ), MDDCollIter::createIterator( ) and
+ // MDDCollIter methods :
+
+ cout << "Iterating through the collection with PersMDDCollIter " << endl;
+ MDDCollIter* objsIt = objsSet.createIterator( );
+
+ for( int i = 1 ; objsIt->notDone( ); i++, objsIt->advance( ))
+ {
+ cout << i<<". MDD object in set:" << endl;
+ accessedObj = (PersMDDObj*) objsIt->getElement();
+ accessedObj->printStatus();
+ EOId eoid;
+ if ( accessedObj->getEOId( &eoid ) ==0 )
+ cout <<"EOId: " << eoid;
+ // old version cout <<"EOId: " << eoid.getSystemName( ) << eoid.getBaseName( ) << eoid.getOId( );
+ cout << endl << endl;
+ accessedObj->getEOId( &globalEOId[i-1] );
+ }
+ delete objsIt;
+ objsSet.releaseAll( );
+ }
+ catch ( r_Error& errObj)
+ {
+ cout <<"Error caught ................."<< endl;
+ }
+}
+
+static void testAccessing( OId o )
+{
+ PersMDDObj* accessedObj;
+
+ cout << "....testAccessing collection "<< o << endl;
+
+ try {
+ PersMDDColl objsSet( o, O2DBName );
+
+ OId o;
+ if ( objsSet.getOId( &o ) == 0 )
+ cout <<"getOId " << o << endl;
+ else
+ cout <<"Error getOId " << endl;
+
+ EOId eo;
+ if ( objsSet.getEOId( &eo ) == 0 )
+ cout << "getEOId " << eo <<endl;
+ // cout << "getEOId " << eo.getSystemName( ) <<":"<<eo.getBaseName( )<<":"<<eo.getOId( ) << endl;
+ else
+ cout <<"Error getEOId " << endl;
+
+ // To test PersMDDColl::printStatus( )
+ objsSet.printStatus( );
+
+ // To test PersMDDObj::printStatus( ), MDDCollIter::createIterator( ) and
+ // MDDCollIter methods :
+
+ cout << "Iterating through the collection with PersMDDCollIter " << endl;
+ MDDCollIter* objsIt = objsSet.createIterator( );
+
+ for( int i = 1 ; objsIt->notDone( ); i++, objsIt->advance( ))
+ {
+ cout << i<<". MDD object in set:" << endl;
+ accessedObj = (PersMDDObj*) objsIt->getElement();
+ accessedObj->printStatus();
+ EOId eoid;
+ if ( accessedObj->getEOId( &eoid ) ==0 )
+ cout <<"EOId: " << eoid ;
+ // cout <<"EOId: " << eoid.getSystemName( ) << eoid.getBaseName() << eoid.getOId( );
+ cout << endl << endl;
+ accessedObj->getEOId( &globalEOId[i-1] );
+ }
+ delete objsIt;
+ objsSet.releaseAll( );
+ }
+ catch ( r_Error& errObj)
+ {
+ cout <<"Error caught ................."<< endl;
+ }
+
+}
+
+/*************************************************************
+ * Function......: testAccessingMDDObj(OId o )
+ * testAccessingOId( )
+ *
+ ************************************************************/
+static void testAccessingMDDObj(OId o)
+{
+ PersMDDObj *mObj;
+
+ cout << "....testAccessingMDDObj"<<endl;
+
+ try{
+ mObj = new PersMDDObj( O2DBName, o);
+ mObj->printStatus( );
+ delete mObj;
+ }
+ catch (...)
+ {
+ cout <<" Object not found..." << endl;
+
+ }
+}
+
+static void testAccessingOId()
+{
+ PersMDDObj *mObj1, *mObj2, *mObj;
+ Handle hdObj;
+ int result;
+ OId o(70000);
+ OId o1(5010);
+ OId o2(0);
+ OId o3(5);
+
+ cout << "....testAccessingOId"<<endl;
+
+
+ cout << "Test OIdIf::getType( )..."<<endl;
+ cout << "1.st MDDObj " << endl;
+ cout << "getType " << globalOId1.getType( O2DBName ) << endl;
+
+ cout << "2.nd MDDObj " << endl;
+ cout << "getType " << globalOId2.getType( O2DBName ) << endl;
+
+ // This crashes
+ // cout << "OId == 0 " << endl;
+ // cout << "getType " << o2.getType( O2DBName ) << endl;
+
+ cout << "OId == 5 " << endl;
+ cout << "getType " << o3.getType( O2DBName ) << endl;
+
+ cout << "MDDCollection " << endl;
+ cout << "getType " << globalCollOId.getType( O2DBName ) << endl;
+ // mObj2 = new PersMDDObj( O2DBName, globalOId2);
+ // mObj2->printStatus( );
+
+ cout << "Not used OId " << endl;
+ cout << "getType " << o1.getType( O2DBName ) << endl;
+
+ cout << "Nonexistent OId " << endl;
+ cout << "getType " << o.getType( O2DBName ) << endl;
+ // mObj2 = new PersMDDObj( O2DBName, globalOId2);
+ // mObj2->printStatus( );
+
+ cout <<"Loading PersMDDObjs from OIds " << endl;
+ mObj1 = new PersMDDObj( O2DBName, globalOId1);
+ mObj1->printStatus( );
+ mObj2 = new PersMDDObj( O2DBName, globalOId2);
+ mObj2->printStatus( );
+
+ delete mObj1;
+ delete mObj2;
+
+
+ for ( int i = 0; i < numObjsCreated; i++ )
+ {
+ cout << "Reading with " << i+1<< ".th EOId " ;
+ cout << globalEOId[i];
+ // cout << globalEOId[i].getSystemName( );
+ // cout << " ; "<< globalEOId[i].getBaseName( ) << ";" << globalEOId[i].getOId( );
+ cout << endl;
+
+
+ // result = o2_externalNameGetObject( &globalEOId[i], &hdObj );
+ result = globalEOId[i].getObject( &hdObj );
+ if ( result == 0 )
+ {
+ DBMDDObjId obj1(hdObj);
+ mObj = new PersMDDObj(obj1);
+ mObj->printStatus( );
+ }
+ else
+ cout << "No such object!!" << endl;
+ // o2_unref_handle( );
+ delete mObj;
+ }
+
+}
+
+/*************************************************************
+ * Function......: testLaterInsert()
+ *
+ ************************************************************/
+
+static void testLaterInsert( OId o )
+{
+ PersMDDObj* accessedObj;
+
+ cout << "....testLaterInsert"<<endl;
+
+ try{
+ accessedObj = new PersMDDObj( O2DBName, o);
+ }
+ catch (...)
+ {
+ cout <<" Object not found..." << endl;
+ return;
+ }
+
+ cout << "Current status of MDD object : " << endl;
+ accessedObj->printStatus( );
+ cout << endl << "Inserting new Tile ..."<< endl;
+
+ PersTile *t, *t2, *t3;
+ switch( accessedObj->getDimension( ) )
+ {
+ case 2 :
+ t2 = new PersTile( r_Minterval("[40:60,80:1200]"),
+ accessedObj->getCellType( ) );
+ t = t2;
+ break;
+ case 3 :
+ t3 = new PersTile(r_Minterval("[40:60,80:100,0:20]"),
+ accessedObj->getCellType( ) );
+ t = t3;
+ break;
+ default:
+ cout << "Error Dimensionality not expected" << endl;
+ break;
+ }
+ accessedObj->insertTile(t);
+ cout << " New status after insertion:" << endl;
+ accessedObj->printStatus();
+ cout << endl << endl;
+
+ delete accessedObj;
+}
+
+
+/*************************************************************
+ * Function......: testSearch()
+ *
+ ************************************************************/
+static void testSearch()
+{
+
+ MDDObj* accessedObj;
+
+ cout << "....testSearch"<<endl;
+
+ PersMDDColl objsSet(collName);
+
+ MDDCollIter* objsIt = objsSet.createIterator( );
+
+ for( int i = 1 ; objsIt->notDone( ); i++, objsIt->advance( ))
+ {
+ accessedObj = objsIt->getElement();
+
+ cout << "Accessed Object " << endl;
+ accessedObj->printStatus( );
+ cout << endl;
+
+ if (i == 1 || i == 2)
+ {
+ r_Minterval searchInt1(2);
+ r_Minterval searchInt2(3);
+ vector< Tile* >* entriesList;
+
+ cout << " -- " << i << ". MDD object in list. Search for:";
+ switch (i) {
+ case 1: searchInt1[0].set_interval(10l,20l);
+ searchInt1[1].set_interval(10l,30l);
+ cout << " 10-20, 10-30" << endl;
+ entriesList = accessedObj->intersect(searchInt1);
+ break;
+ case 2: searchInt2[0].set_interval(10l,20l);
+ searchInt2[1].set_interval(10l,30l);
+ searchInt2[2].set_interval(40l,50l);
+ cout << " 10-20, 10-30, 40-50" <<endl;
+ entriesList = accessedObj->intersect(searchInt2);
+ break;
+ default: break;
+ }
+ cout << " -- Search result: " << endl;
+ vector<Tile*>::iterator entryIt = entriesList->begin();
+
+ while (entryIt != entriesList->end())
+ {
+ // (*entryIt)->printStatus();
+ r_Minterval tileInterval = (*entryIt)->getDomain();
+ int dimensionality = tileInterval.dimension();
+
+ cout << " PersTile printStatus";
+ cout << " domain == " << dimensionality << ": ";
+ for (int i = 0; i <dimensionality; i++)
+ cout << tileInterval[i].low() << "-"
+ << tileInterval[i].high() <<", ";
+ cout << endl;
+
+ entryIt++;
+ }
+ delete entriesList;
+ }
+ }
+ delete objsIt;
+ // objsSet.releaseAll( );
+}
+
+/*************************************************************
+ * Function......: testRemoveTile(OId o )
+ *
+ ************************************************************/
+static void testRemoveTile(OId o)
+{
+ PersMDDObj *mObj;
+
+ cout << "....testRemoveTile from MDD Obj "<< o << endl;
+
+ try{
+ mObj = new PersMDDObj( O2DBName, o);
+ mObj->printStatus( );
+ }
+ catch (...)
+ {
+ cout <<" Object not found..." << endl;
+ return;
+ }
+
+ vector<Tile*>* tiles = mObj->getTiles( );
+
+ if ( tiles->size( ) == 0 )
+ {
+ cout <<"MDD object has no tiles !! "<< endl;
+ return;
+ }
+ else
+ {
+ int ix = tiles->size( )/2;
+
+ cout << "Removing "<< ix <<". tile from MDD Obj "<< endl;
+ cout << "Tile Description: " << (*tiles)[ix]->getDomain( ) << endl;
+
+ PersTile* t = (PersTile*) (*tiles)[ix];
+
+ mObj->removeTile( (*tiles)[ix] );
+
+ delete tiles;
+ delete mObj;
+ }
+}
+
+/*************************************************************
+ * Function......: testGetCardinality( const char* cn )
+ * testGetFunctions()
+ *
+ ************************************************************/
+static void testGetCardinality( char* cn )
+{
+ cout << "....testGetCardinality( "<< cn << " )" << endl;
+
+ try{
+ PersMDDColl objsSet( cn );
+ cout<< "Cardinality of collection " << objsSet.getCardinality( ) <<endl;
+ }
+ catch( r_Error& errObj)
+ {
+ cout <<"Error caught ................."<< endl;
+ }
+}
+
+static void testGetFunctions()
+{
+ PersMDDObj* accessedObj;
+
+ cout << "....testGetFunctions"<<endl;
+
+ PersMDDColl objsSet(collName);
+
+ MDDCollIter* objsIt = objsSet.createIterator( );
+
+ vector< Tile* >* entriesList;
+
+ for( int i = 1 ; objsIt->notDone( ); i++, objsIt->advance( ))
+ {
+ r_Minterval currDom;
+ r_Minterval defDom;
+
+ cout << " " << i << ". Object" << endl;
+ accessedObj = (PersMDDObj*) objsIt->getElement();
+
+
+ defDom = accessedObj->getDefinitionDomain( );
+ cout << " GetDefinitionDomain result: ";
+ defDom.print_status( );
+ cout << endl;
+
+ currDom = accessedObj->getCurrentDomain( );
+ cout << " GetCurrentDomain result: ";
+ currDom.print_status( );
+ cout << endl;
+
+ entriesList = accessedObj->getTiles( );
+ cout << " -- GetTiles result: " << endl;
+ vector<Tile*>::iterator entryIt = entriesList->begin();
+
+ while (entryIt != entriesList->end())
+ {
+ // (*entryIt)->printStatus();
+ r_Minterval tileInterval = (*entryIt)->getDomain();
+ int dimensionality = tileInterval.dimension();
+
+ cout << " PersTile ";
+ cout << " domain == " << dimensionality << ": ";
+ for (int i = 0; i <dimensionality; i++)
+ cout << tileInterval[i].low() << "-" << tileInterval[i].high() <<", ";
+ cout << endl;
+ entryIt++;
+ }
+ delete entriesList;
+ }
+ delete objsIt;
+ objsSet.releaseAll( );
+}
+
+/*************************************************************
+ * Function......: testRemove()
+ * testRemove( OId o )
+ *
+ ************************************************************/
+
+static void testRemove()
+{
+ PersMDDObj* accessedObj;
+
+ cout << "....testRemove"<<endl;
+
+ PersMDDColl objsSet(collName);
+ // PersMDDColl objsSet("Qualquercoisa");
+ // To test PersMDDColl::printStatus and PersMDDColl::remove
+
+
+ MDDCollIter* objsIt = objsSet.createIterator( );
+
+ cout << "-- Remove second element from collection " << endl;
+
+ for( int i = 1 ; objsIt->notDone( ) && i < 2; i++, objsIt->advance( ))
+ {
+ accessedObj = (PersMDDObj*) objsIt->getElement();
+ }
+ cout << "Delete of objsIt:" << endl;
+ delete objsIt;
+ cout << "Finished Delete of objsIt." << endl;
+ cout << "Remove accessedObj:" << endl;
+ objsSet.remove( accessedObj );
+ cout << "Finished Remove accessedObj." << endl;
+}
+
+static void testRemove( OId o )
+{
+
+ cout << "....testRemove( OId == " << o <<" ) "<< endl;
+
+ PersMDDColl objsSet(collName);
+ objsSet.remove( o, O2DBName );
+}
+
+
+/*************************************************************
+ * Function......: createMDDColl( )
+ ************************************************************/
+static int
+createMDDColl( const char* collName, DatabaseIf* db )
+{
+ MDDDomainType* mType1 = 0;
+ MDDDomainType* mType2 = 0;
+ MDDType* mt = 0;
+ CollectionType* collType1 = 0;
+
+ const BaseType* ulongTypeObj = TypeFactory::mapType("ULong");
+
+ const MDDDomainType* cmType1 =
+ ( MDDDomainType* ) TypeFactory::mapMDDType( "TestSMDomainType2D" );
+ const MDDDomainType* cmType2 =
+ ( MDDDomainType* ) TypeFactory::mapMDDType( "TestSMDomainType3D" );
+
+ const CollectionType* collType =
+ (CollectionType*)TypeFactory::mapSetType( "ObjsContainerType" );
+
+
+ if( !cmType1 || !cmType2 || !collType )
+ {
+ char name1[] = "TestSMDomainType2D";
+ char name2[] = "TestSMDomainType3D";
+
+ r_Sinterval limits1Obj1(0l,1000l);
+ r_Sinterval limits2Obj1(0l,800l);
+ r_Minterval dom1(2);
+ dom1 << limits1Obj1 << limits2Obj1;
+ cout << "MDD Type 1 , domain "<< dom1 << endl;
+
+ cout << " tile 1 = nil, 0-19, 20-59, 30-59 "<< endl;
+ r_Sinterval limits1Obj2(0l,19l);
+ r_Sinterval limits2Obj2(20l,59l);
+ r_Sinterval limits3Obj2(30l,59l);
+ r_Minterval dom2(3);
+ dom2 << limits1Obj2 << limits2Obj2 << limits3Obj2;
+ cout << "MDD Type 2 , domain "<< dom2 << endl;
+
+ // MDDDomainType* mType1 =
+ mType1 =
+ new MDDDomainType((char*) name1, ( BaseType* ) ulongTypeObj, dom1 );
+ // MDDDomainType* mType2 =
+ mType2 =
+ new MDDDomainType((char*) name2, ( BaseType* ) ulongTypeObj, dom2 );
+
+ cout << "MDD Type1 == ";
+ mType1->print_status( cout );
+ cout << endl;
+ cout << "MDD Type2 == ";
+ mType2->print_status( cout );
+ cout << endl;
+
+ TypeFactory::addMDDType( mType1 );
+ TypeFactory::addMDDType( mType2 );
+
+ if ( !collType )
+ {
+ cout << "Collection type newly created " << endl;
+ // MDDType* mt = new MDDType( );
+ mt = new MDDType( );
+ cout << "MDDtype created "<< endl;
+ collType1 = new SetType( "ObjsContainerType", mType1 );
+ cout << "Set Type created ... ";
+ collType = collType1;
+ TypeFactory::addSetType( (SetType*) collType );
+ cout <<" and added "<< endl;
+
+ }
+
+ }
+ //ta.commit( );
+
+ //ta.begin( );
+
+ cout << "Creating root collection" << endl;
+
+ // cout << " &database = " << long( db ) << endl;
+
+ OId oColl;
+ if( OId::allocateMDDCollOId( &oColl ) == 0 )
+ cout <<"Successfully allocated OId for collection " << oColl << endl;
+ else
+ cout <<"Error allocating OId for collection " << endl;
+ globalCollOId = oColl;
+
+ PersMDDColl* col;
+ try {
+ // CollectionType* ct = TypeFactory::mapSetType( "ObjsContainerType" );
+ col = PersMDDColl::createRoot( collName, oColl, collType, db );
+ }
+ catch (...)
+ {
+ cout <<"Error caught ................."<< endl;
+ return -1;
+ }
+
+ cout << "Committing TA ..."<< endl;
+ ta.commit( );
+
+ /*
+
+ cout <<"Freeing types ... "<< endl;
+
+ // if ( mType1 ) delete mType1;
+ cout << "Type 1 freed . "<< endl;
+ // if ( mType2 ) delete mType2;
+ cout << "Type 2 freed . "<< endl;
+ // if ( mt ) delete mt;
+ cout << "Type mt freed . "<< endl;
+ // if ( collType1 ) delete collType1;
+ cout << "Types collType1 freed . "<< endl;
+ */
+ if ( col ) delete col;
+ cout << "Col freed . "<< endl;
+
+
+ ta.begin( db );
+ return 0;
+}
diff --git a/mddmgr/test/test_transmddcoll.cc b/mddmgr/test/test_transmddcoll.cc
new file mode 100644
index 0000000..b3045c3
--- /dev/null
+++ b/mddmgr/test/test_transmddcoll.cc
@@ -0,0 +1,180 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_transmddcoll.cc
+ *
+ * MODULE: test for transmddobj of cachetamgr
+ *
+ * COMMENTS:
+ * none
+ *
+*/
+
+#include <stdlib.h>
+#include <iostream>
+#include <vector.h> // STL
+#include "tilemgr/transtile.hh"
+#include "tilemgr/transmddobj.hh"
+#include "ulongtype.hh" // from catalogif
+#include "raslib/minterval.hh"
+#include "tilemgr/transmddcoll.hh"
+#include "tilemgr/mddcolliter.hh"
+#include "adminif.hh"
+
+// Needed by Adminif. Adminif has to be instantiated because
+// of cell base types.
+extern char* myExecArgv0 = "";
+#include "raslib/rminit.hh"
+RMINITGLOBALS('C')
+
+
+/*************************************************************
+ * Function name.: int main( int argc, char** argv)
+ *
+ * Arguments.....:
+ * argc: number of arguments given to program
+ * argv: array of char* with arguments
+ * Return value..: exit status
+ * Description...:
+ * The cellType of the MDD objects in this program is
+ * not set correctly because no database is open and no
+ * transaction is started.
+ ************************************************************/
+
+int
+main( int argc, char** argv)
+{
+ myExecArgv0 = argv[0];
+
+ const int numObjs = 10;
+ const int numTilesObj = 10;
+ r_Sinterval domSinterval;
+
+ // In order to work with cell base types, AdminIf has to be
+ // instantiated.
+ // cout << " Adminif::instance " << endl;
+ AdminIf* myAdmin = AdminIf::instance();
+
+ ULongType anyType;
+
+ char anyCell[4];
+ int i;
+ MDDColl* tCollMDDObjs = new TransMDDColl( );
+
+ cout << " Allocating new TransMDDColl ..."<<endl;
+ tCollMDDObjs = new TransMDDColl( );
+ cout << " new TransMDDColl allocated..."<<endl;
+
+ cout << "Creating transient tiles for the MDD objects ... " << endl;
+ vector<TransTile*>* tilesVectsArr[numObjs];
+
+ // initialize array of vectors of tiles
+ for (i=0; i<numObjs; i++)
+ {
+ tilesVectsArr[i] = new vector<TransTile*>(numTilesObj);
+ for (int j=0; j<numTilesObj ; j++)
+ {
+ r_Minterval dom(2);
+ domSinterval.set_interval( r_Range(j* 10), r_Range((j+1)*10-1) );
+ dom << domSinterval << domSinterval;
+ (*tilesVectsArr[i])[j] = new TransTile( dom, &anyType, anyCell );
+ }
+ }
+
+
+ cout << "Creating transient MDD objects ... " << endl;
+ TransMDDObj* MDDObjsArr[numObjs];
+
+ for ( i=0; i<numObjs; i++ )
+ {
+ r_Minterval dom(2);
+ domSinterval.set_interval( r_Range( i ), r_Range( 100 + i*10 ) );
+ if( i == 3 || i == 5 || i == 7 )
+ domSinterval.set_low( '*' );
+ if( i == 2 || i == 4 || i == 6 )
+ domSinterval.set_high( '*' );
+ dom << domSinterval << domSinterval;
+ MDDObjsArr[i] = new TransMDDObj( dom, "ULong" );
+ for( int j=0; j < numTilesObj; j++)
+ {
+ vector<TransTile*>* pTilesVec = tilesVectsArr[i];
+ MDDObjsArr[i]->insertTile( (*pTilesVec)[j] );
+ }
+ }
+
+ cout << "Printing contents of created objects ... " << endl;
+ for( i = 0; i< numObjs; i++)
+ {
+ cout << "- " << i << ". Transient MDD Object contents: " <<endl;
+ MDDObjsArr[i]->printStatus( );
+ cout << endl;
+ }
+
+ cout << "Creating a transient collection of objects ... " << endl;
+ for( i = 0; i< numObjs; i++)
+ {
+ // cout << "- " << i << ". Transient MDD Object contents: " <<endl;
+ tCollMDDObjs->insert(MDDObjsArr[i]);
+ // cout << endl;
+ }
+ cout << "Contents of the Transient Collection: ... : " << endl;
+ tCollMDDObjs->printStatus( );
+
+ cout << "Testing TransMDDCollIter ... : " << endl;
+ MDDCollIter* transIter = tCollMDDObjs->createIterator( );
+ MDDObj* currObj;
+
+ for ( i=0; transIter->notDone( ) ; transIter->advance( ), i++)
+ {
+ cout << "- " << i << ". Trans. MDD Object returned by Iterator contents: " <<endl;
+ currObj = transIter->getElement( );
+ currObj->printStatus( );
+ }
+
+ // delete iterator from TransMDDColl
+ delete transIter;
+
+ // releases all contents from the collection. It should free all the MDD
+ // objects and tiles created in this program.
+ tCollMDDObjs->releaseAll( );
+
+ // delete transient MDD Collection
+ delete tCollMDDObjs;
+
+ /*
+ This shouldn't be needed if realeaseAll from the TransMDDColl works fine
+ for ( i = 0 ; i < numObjs; i++ )
+ {
+ delete MDDObjsArr[i];
+ }
+ */
+
+
+ // delete dynamically allocated vectors of tiles (not the tiles themselves,
+ // which should have been freed by releaseAll of TransMDDColl)
+ for (i = 0; i < numObjs; i++)
+ delete tilesVectsArr[i];
+
+ delete myAdmin;
+
+}
diff --git a/mddmgr/test/test_transmddobj.cc b/mddmgr/test/test_transmddobj.cc
new file mode 100644
index 0000000..28c50d2
--- /dev/null
+++ b/mddmgr/test/test_transmddobj.cc
@@ -0,0 +1,443 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_transmddcoll.cc
+ *
+ * MODULE: test for transmddobj of cachetamgr
+ *
+ * COMMENTS:
+ * none
+ *
+*/
+
+#include "rt_odb_Database.hxx"
+
+#define TEST_PRIVATE
+
+#include <stdlib.h>
+#include <iostream>
+#include <vector.h> // STL
+#include "mddmgr/transtile.hh"
+#include "mddmgr/transmddobj.hh"
+
+#include "typefactory.hh"
+#include "ulongtype.hh" // from catalogif
+#include "mddbasetype.hh" // from catalogif
+
+#include "raslib/minterval.hh"
+#include "mddmgr/transmddcoll.hh"
+#include "mddmgr/mddcolliter.hh"
+#include "adminif.hh"
+#include "databaseif.hh"
+#include "transactionif.hh"
+
+#include "raslib/rminit.hh"
+RMINITGLOBALS('C')
+
+#include <malloc.h>
+
+// Needed by Adminif. Adminif has to be instantiated because
+// of cell base types.
+extern char* myExecArgv0 = "";
+
+void testConstruction( );
+void testRemovetile( );
+void testIntersection( );
+void printMemInfo( );
+
+
+/*************************************************************
+ * Function name.: int main( int argc, char** argv)
+ *
+ * Arguments.....:
+ * argc: number of arguments given to program
+ * argv: array of char* with arguments
+ * Return value..: exit status
+ * Description...: none
+ ************************************************************/
+
+int
+main( int argc, char** argv)
+{
+ myExecArgv0 = argv[0];
+ AdminIf* myAdmin = AdminIf::instance();
+ TransactionIf ta;
+ char O2DBName[] = "BaseTestTransMDDObj";
+
+ // variables representing O2 database, ta and session
+ DatabaseIf database;
+ // connect to the database
+ cout << "Connecting to database " << O2DBName
+ << "..." << endl;
+ int errorDBOpen;
+ try{
+ errorDBOpen = database.open( O2DBName );
+ }
+ catch( ...)
+ {
+ cout << "Caught Exception " << endl;
+ errorDBOpen = -6;
+ }
+ if ( errorDBOpen < 0 )
+ {
+ cout << "Database doesn't exist. Create it new ... " << endl;
+ cout << "Creating new database " << O2DBName
+ << "..." << endl;
+ database.create( O2DBName, "TestSMSchema" );
+ cout << "Connecting to database " << O2DBName
+ << "..." << endl;
+ try{
+ errorDBOpen = database.open( O2DBName );
+ }
+ catch(...)
+ {
+ errorDBOpen = -6;
+ }
+ }
+ if ( errorDBOpen < 0 )
+ {
+ cout << "Failed at opening newly created database " << errorDBOpen << endl;
+ cout << "Exiting " << endl;
+ return errorDBOpen;
+ }
+
+ ta.begin( &database, 1 );
+
+ cout << " Main - begin " << endl;
+ printMemInfo( );
+
+ /*
+ cout << "---------- ";
+ cout << "Testing constructor and insertTile for TransMDDObj: " << endl;
+ testConstruction( );
+ cout << "Testing constructor - end " << endl;
+ printMemInfo( );
+ */
+
+ cout << "Testing intersection for TransMDDObj: " << endl;
+ testIntersection( );
+ cout << "Testing intersection - end " << endl;
+ printMemInfo( );
+
+
+ /*
+ cout << "---------- ";
+ cout << "Testing removeTile from TransMDDObj: " << endl;
+ testRemovetile( );
+ cout << "Main - end " << endl;
+ printMemInfo( );
+ */
+
+ ta.abort( );
+ database.close( );
+
+ delete myAdmin;
+
+}
+
+void testConstruction( )
+{
+ const int numTilesObj = 20;
+ r_Sinterval domSinterval;
+ cout <<"here 1" << endl;
+ ULongType ult;
+ BaseType* anyType = new( (d_Database*)(d_Database::transient_memory) ) ULongType; // anyType;
+
+ cout << "here 2"<< endl;
+ const MDDBaseType* anyBaseType =
+ new( (d_Database*)(d_Database::transient_memory) ) MDDBaseType( "AnyType", &ult/* anyType */ );
+
+ // const MDDBaseType anyBaseType( "AnyType", &ult );
+
+ char anyCell[4];
+ int j;
+ MDDObj* testMDDObj;
+
+
+ cout << "Creating transient tiles for the MDD object ... " << endl;
+ vector<TransTile*> tilesVect(numTilesObj);
+
+
+ // initialize array of tiles
+ for (j=0; j<numTilesObj ; j++)
+ {
+ r_Minterval dom(2);
+ TransTile* tt;
+
+ domSinterval.set_interval( r_Range(j* 10), r_Range((j+1)*10-1) );
+ dom << domSinterval << domSinterval;
+ cout << "Newly created tile domain : " << dom << " " << endl;
+ // printMemInfo();
+ tt = new TransTile( dom, anyType, anyCell );
+ cout << "Tile created " << endl;
+ // printMemInfo();
+ tilesVect[j] = tt ;
+ }
+
+ // Test trans tiles part - BEGIN
+ // works fine
+ /*
+ for ( int h=0; h < tilesVect.size(); h++)
+ delete tilesVect[h];
+ */
+ // release (tilesVect.begin( ), tilesVect.end( ) );
+
+ // Test trans tiles part - END
+
+
+ cout << "Creating the transient MDD object ... " << endl;
+
+ r_Minterval dom(2);
+ domSinterval.set_interval( r_Range( 0 ), r_Range( 100 ) );
+ domSinterval.set_low( '*' );
+ dom << domSinterval << domSinterval;
+ // testMDDObj = new TransMDDObj( dom, "ULong" );
+ testMDDObj = new TransMDDObj( anyBaseType, dom );
+ for(j=0; j < numTilesObj; j++)
+ {
+ testMDDObj->insertTile( tilesVect[j] );
+ }
+ // printMemInfo();
+
+ cout << "Printing contents of the created object ... " << endl;
+ testMDDObj->printStatus( );
+
+ cout << "Deleting the created object ... " << endl;
+ delete testMDDObj;
+ // printMemInfo();
+
+
+}
+
+
+void testIntersection( )
+{
+ const int numTilesObj = 20;
+ r_Sinterval domSinterval;
+
+ const BaseType* ulongTypeObj = TypeFactory::mapType("ULong");
+
+ char uLongCell[] = {0,1,2,3};
+
+ const MDDBaseType* anyBaseType =
+ new MDDBaseType( "AnyType1", (BaseType*) ulongTypeObj );
+
+ TypeFactory::addTempType( (Type*) anyBaseType );
+
+ BaseType* bt = ( (MDDBaseType* ) anyBaseType )->getBaseType( );
+ cout << "Base type size " << bt->getSize( )<< endl;
+
+
+ int j;
+ MDDObj* testMDDObj;
+
+
+ cout << "Creating transient tiles for the MDD object ... " << endl;
+ vector<TransTile*> tilesVect(numTilesObj);
+
+
+ // initialize array of tiles
+ for (j=0; j<numTilesObj ; j++)
+ {
+ r_Minterval dom(2);
+ TransTile* tt;
+
+ domSinterval.set_interval( r_Range(j* 10), r_Range((j+1)*10-1) );
+ dom << domSinterval << domSinterval;
+ cout << "Newly created tile domain : " << dom << " " << endl;
+ // printMemInfo();
+ tt = new TransTile( dom, (BaseType*) ulongTypeObj, uLongCell );
+ cout << "Tile created " << endl;
+ if (!j)
+ tt->printStatus( );
+ // printMemInfo();
+ tilesVect[j] = tt ;
+ }
+
+ // Test trans tiles part - BEGIN
+ // works fine
+ /*
+ for ( int h=0; h < tilesVect.size(); h++)
+ delete tilesVect[h];
+ */
+ // release (tilesVect.begin( ), tilesVect.end( ) );
+
+ // Test trans tiles part - END
+
+
+ cout << "Creating the transient MDD object ... " << endl;
+
+ r_Minterval dom(2);
+ domSinterval.set_interval( r_Range( 0 ), r_Range( 100 ) );
+ domSinterval.set_low( '*' );
+ dom << domSinterval << domSinterval;
+ testMDDObj = new TransMDDObj( anyBaseType, dom );
+ for(j=0; j < numTilesObj; j++)
+ {
+ testMDDObj->insertTile( tilesVect[j] );
+ }
+ // printMemInfo();
+
+ cout << "Printing contents of the created object ... " << endl;
+ testMDDObj->printStatus( );
+
+ r_Minterval searchInterval(2);
+ domSinterval.set_interval( r_Range( 4 ), r_Range( 96 ) );
+ searchInterval<< domSinterval ;
+ domSinterval.set_interval( r_Range( 22 ), r_Range( 84 ) );
+ searchInterval<< domSinterval ;
+ cout << "Intersection with "<< searchInterval << " :" << endl ;
+
+ vector<Tile*>* intersectResult =
+ ( testMDDObj )->intersect( searchInterval );
+ cout << "Result of intersection:" << endl;
+ cout << "Intersect result size " << intersectResult->size( ) << endl;
+ for (int tilesIter = 0; tilesIter < intersectResult->size( ) ; tilesIter++)
+ {
+ Tile* currTile;
+ currTile = (*intersectResult)[tilesIter];
+ cout << "Tile " << tilesIter << " domain : " ;
+ cout << currTile->getDomain( ) << endl;
+ }
+
+ // printMemInfo();
+ cout << "Deleting intersection result " << endl;
+ // Individual tiles in the intersectResult shouldn't be deleted, since
+ // they are part of the TransMDDObj. They are deleted whenever the object
+ // is deleted.
+ delete intersectResult;
+ // printMemInfo();
+
+ cout << "Testing point query " << endl;
+ r_Point pnt1( r_Range(2) , r_Range(3) );
+ unsigned long* c1 = (unsigned long*) testMDDObj->pointQuery( pnt1 );
+ // char* c1 = testMDDObj->pointQuery( pnt1 );
+ cout << "1. Result "<< pnt1 << ": "<< *c1 << endl;
+
+ r_Point pnt2( r_Range(20) , r_Range(30) );
+ unsigned long* c2 = (unsigned long*) testMDDObj->pointQuery( pnt2 );
+ // char* c2 = testMDDObj->pointQuery( pnt2 );
+ cout << "2. Result "<< pnt2 << ": "<< c2 << endl;
+
+ cout << "Deleting the created object ... " << endl;
+ delete testMDDObj;
+ printMemInfo();
+}
+
+
+void testRemovetile( )
+{
+ const int numTilesObj = 20;
+ r_Sinterval domSinterval;
+ BaseType* anyType = new( (d_Database*)(d_Database::transient_memory) ) ULongType; // ULongType anyType;
+ char anyCell[4]= {'a','b','c','\0'};
+ int j,i;
+ TransMDDObj* testMDDObj;
+ vector<Tile*>* allTilesObj;
+ vector<Tile*> tilesToDelete;
+ const MDDBaseType* anyBaseType =
+ new( (d_Database*)(d_Database::transient_memory) ) MDDBaseType( "AnyType", anyType );
+
+ cout << "Creating transient tiles for the MDD object ... " << endl;
+ vector<TransTile*> tilesVect;
+
+ // initialize array of tiles
+ for ( j=0; j<numTilesObj ; j++)
+ {
+ r_Minterval dom(2);
+ domSinterval.set_interval( r_Range(j* 10), r_Range((j+1)*10-1) );
+ dom << domSinterval << domSinterval;
+ cout << "New TransTile " << endl;
+ tilesVect.push_back( new TransTile( dom, anyType, anyCell ) );
+ // printMemInfo( );
+ }
+
+ cout << "Creating the transient MDD object ... " << endl;
+
+ r_Minterval dom(2);
+ domSinterval.set_interval( r_Range( 0 ), r_Range( 100 ) );
+ domSinterval.set_low( '*' );
+ dom << domSinterval << domSinterval;
+ testMDDObj = new TransMDDObj( anyBaseType, dom );
+ for( j=0; j < numTilesObj; j++)
+ {
+ cout << "InsertTile " << endl ;
+ testMDDObj->insertTile( ( Tile*) tilesVect[j] );
+ // printMemInfo( );
+ }
+
+ cout << "Printing contents of the created object ... " << endl;
+ testMDDObj->printStatus( );
+
+ cout << "Getting all tiles from the object... " << endl;
+ allTilesObj = testMDDObj->getTiles( );
+ // printMemInfo( );
+
+ cout << "Removing tile 2, 4, 6, and 12 from the object... " << endl;
+ for ( i = 0; i < allTilesObj->size( ); i++)
+ {
+ if ( i==2 || i == 4 || i == 6 || i == 12 )
+ {
+ tilesToDelete.push_back( (*allTilesObj)[i]);
+ }
+ }
+ for ( i = 0; i < tilesToDelete.size( ); i++)
+ {
+ cout << " Tile is going to be removed " << endl;
+ testMDDObj->removeTile(tilesToDelete[i] );
+ cout << endl << " Value of pointer to tile : " << tilesToDelete[i] << endl<< endl;
+ // printMemInfo();
+ }
+ testMDDObj->printStatus( );
+
+ cout << "Deleting the created object ... " << endl;
+ // printMemInfo( );
+ delete testMDDObj;
+ cout << "Already deleted " << endl;
+ // printMemInfo( );
+
+ delete allTilesObj;
+}
+
+
+void printMemInfo( )
+{
+
+
+ // allows to store values in the program
+ struct mallinfo meminfo = mallinfo();
+
+ cout << " Memory Usage Information : " ;
+ cout << endl;
+
+ cout << " space in arena : " << meminfo.arena << endl;
+ cout << " number of small blocks : " << meminfo.smblks << endl;
+ cout << " number of ordinary blocks : " << meminfo.ordblks << endl;
+ cout << " space in free ordinary blocks : " << meminfo.fordblks << endl;
+ cout << " space in used ordinary blocks : " << meminfo.uordblks << endl;
+
+ // cout << "additional space from last call: " << meminfo.uordblks - memUsed << endl;
+
+}
+
+
diff --git a/mymalloc/Makefile.am b/mymalloc/Makefile.am
new file mode 100644
index 0000000..0709bfd
--- /dev/null
+++ b/mymalloc/Makefile.am
@@ -0,0 +1,29 @@
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+#
+# MAKEFILE FOR:
+# Top level makefile
+#
+# COMMENTS:
+#
+##################################################################
+
diff --git a/mymalloc/mymalloc.h b/mymalloc/mymalloc.h
new file mode 100644
index 0000000..1e78ffb
--- /dev/null
+++ b/mymalloc/mymalloc.h
@@ -0,0 +1,31 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#ifndef __MYMALLOC_H__
+#define __MYMALLOC_H__
+
+#include <stdlib.h>
+
+extern void* mymalloc(size_t); // throw(std::bad_alloc); // FIXME: gcc3 doesn't like it, & can't do this unless other places are fixed as well
+
+#endif
diff --git a/mymalloc/mymalloc_cln.cc b/mymalloc/mymalloc_cln.cc
new file mode 100644
index 0000000..6064112
--- /dev/null
+++ b/mymalloc/mymalloc_cln.cc
@@ -0,0 +1,35 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+//
+// wrapper for malloc on client side - does nothing
+//
+
+//using std::bad_alloc; // added for gcc3 -- PB 2005-feb-13
+
+#include "mymalloc/mymalloc.h"
+
+// added throw to be conformant with mymalloc_svc -- PB 2005-feb-01
+void* mymalloc(size_t size) // throw (std::bad_alloc) // FIXME: gcc3 doesn't like it
+{
+ return malloc(size);
+}
diff --git a/mymalloc/mymalloc_svc.cc b/mymalloc/mymalloc_svc.cc
new file mode 100644
index 0000000..3324fb7
--- /dev/null
+++ b/mymalloc/mymalloc_svc.cc
@@ -0,0 +1,78 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+//
+// wrapper for malloc on server side - throw bad_alloc if malloc fails
+//
+#include "mymalloc/mymalloc.h"
+#include "reladminif/objectbroker.hh"
+#include "raslib/rmdebug.hh"
+#include <stdlib.h>
+#include <new>
+
+using namespace std;
+
+// try to allocate requested memory;
+// if impossible, try to free some, then retry allocation (by recursion)
+// if nothing can be freed & allocated, give up & throw exception
+
+void* mymalloc(size_t size) // throw(bad_alloc) // FIXME: gcc3 doesn't like it, & can't do that unless other places are adapted too
+{
+ void* p = malloc(size);
+
+#ifdef OLD_VERSION
+// replaced this weird coding by the following below which should be semantically equivalent -- PB 2005-feb-01
+ // ...except for more detailed error messages
+ // FIXME: And SITF resolve this totally screwed up recursion to a while loop.
+ if(!p)
+ if(!ObjectBroker::freeMemory() || !(p = mymalloc(size))) {
+ RMInit::logOut << "mymalloc: memory allocation failed." << endl;
+ throw bad_alloc();
+ }
+#else // improved structure, same logic:
+ if (p == (void*) NULL)
+ {
+ bool freePossible = ObjectBroker::freeMemory();
+ if (freePossible)
+ {
+ p = mymalloc(size);
+ if (p == (void*) NULL)
+ {
+ RMInit::logOut << "Error: mymalloc(): memory allocation failed." << endl;
+ throw bad_alloc();
+ }
+ else
+ {
+ // all went fine, nothing to do, return p
+ }
+ }
+ else // mem full, according to ObjectBroker, so throw alloc exception
+ {
+ RMInit::logOut << "Error: mymalloc(): ObjectBroker::freeMemory() failed." << endl;
+ throw bad_alloc();
+ }
+ }
+#endif OLD_VERSION
+
+ return p;
+}
diff --git a/network/Makefile.am b/network/Makefile.am
new file mode 100644
index 0000000..4f930ac
--- /dev/null
+++ b/network/Makefile.am
@@ -0,0 +1,43 @@
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+#
+# MAKEFILE FOR:
+# network
+#
+# COMMENTS:
+# - still waits to be really integrated completely (akg namespace, ...)
+#
+##################################################################
+
+noinst_LIBRARIES=libnetwork.a
+libnetwork_a_SOURCES= akgnet_commbuffer.cc akgnet_commbuffer.hh \
+ akgnet_file.cc akgnet_file.hh \
+ akgnet_nbcomm.cc akgnet_nbcomm.hh \
+ akgnet_server.cc akgnet_server.hh \
+ akgnet_fdescr.cc akgnet_fdescr.hh \
+ akgnet_inetaddr.cc akgnet_inetaddr.hh \
+ akgnet_selector.cc akgnet_selector.hh \
+ akgnet_socket.cc akgnet_socket.hh \
+ akgnetwork.hh akgnet_common.hh
+
+
+CLEANFILES=core
diff --git a/network/akgnet_commbuffer.cc b/network/akgnet_commbuffer.cc
new file mode 100644
index 0000000..3c5c561
--- /dev/null
+++ b/network/akgnet_commbuffer.cc
@@ -0,0 +1,190 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: akgnet_commbuffer.cc
+ *
+ * MODULE: akg network
+ * CLASS: CommBuffer
+ *
+ * COMMENTS:
+ *
+ */
+
+#include <akgnet_commbuffer.hh>
+#include <string>
+#include <assert.h>
+
+
+akg::CommBuffer::CommBuffer() throw()
+ {
+ data = NULL;
+ buffSize = 0;
+ fillSize = 0;
+ sendSize = 0;
+ allocated= false;
+ }
+
+akg::CommBuffer::CommBuffer(int size) throw()
+ {
+ assert(size > 0);
+ allocate(size);
+ }
+
+akg::CommBuffer::CommBuffer(void *externalBuffer,int totalSize, int dataSize) throw()
+ {
+ data = NULL;
+ takeOver(externalBuffer,totalSize,dataSize);
+ }
+
+akg::CommBuffer::~CommBuffer() throw()
+ {
+ freeBuffer();
+ }
+
+bool akg::CommBuffer::allocate(int size) throw()
+ {
+ assert(size > 0);
+
+ freeBuffer();
+ data = new char[size];
+ // new throws?
+ buffSize=size;
+ allocated=true;
+ return true;
+ }
+
+void akg::CommBuffer::freeBuffer() throw()
+ {
+ if(allocated == true && data != NULL) delete[] data;
+ data = NULL;
+ buffSize = 0;
+ fillSize = 0;
+ sendSize = 0;
+ allocated= false;
+ }
+
+void akg::CommBuffer::takeOver(void *externalBuffer,int totalSize, int dataSize) throw()
+ {
+ assert(externalBuffer != 0);
+ assert(totalSize > 0);
+ assert(dataSize >= 0);
+ assert(totalSize >= dataSize);
+
+ freeBuffer();
+ data = (char*)externalBuffer;
+ buffSize = totalSize;
+ fillSize = dataSize;
+ }
+
+bool akg::CommBuffer::resize(int newSize) throw()
+ {
+ assert(data != 0);
+
+ // we can't make the buffer smaller by truncating inside data!
+ if(newSize < fillSize) return false;
+
+ char *newData = new char[newSize];
+ memcpy(newData, data, fillSize);
+ if(allocated == true ) delete[] data;
+
+ data = newData;
+ buffSize = newSize;
+ allocated = true;
+ return true;
+ }
+
+void* akg::CommBuffer::getData() throw(){ return data;}
+int akg::CommBuffer::getDataSize() throw(){ return fillSize;}
+int akg::CommBuffer::getBufferSize() throw(){ return buffSize;}
+int akg::CommBuffer::getSendedSize() throw(){ return sendSize;}
+int akg::CommBuffer::getNotFilledSize() throw(){ return buffSize-fillSize;}
+int akg::CommBuffer::getNotSendedSize() throw(){ return fillSize-sendSize;}
+bool akg::CommBuffer::isAllocated() throw(){ return allocated;}
+
+int akg::CommBuffer::read(FileDescriptor &socket) throw()
+ {
+ int rasp = socket.read(data+fillSize,buffSize-fillSize);
+
+ if(rasp>=0) fillSize += rasp;
+
+ return rasp;
+ }
+
+int akg::CommBuffer::read(const void *externalBuffer,int size) throw()
+ {
+ assert(externalBuffer != 0);
+ assert(size >= 0);
+
+ int cpSize = size<(buffSize-fillSize) ? size:(buffSize-fillSize);
+
+ memcpy(data+fillSize,externalBuffer,cpSize);
+ fillSize += cpSize;
+
+ return cpSize;
+ }
+
+int akg::CommBuffer::reserve(int size) throw()
+ {
+ assert(size >= 0);
+
+ int cpSize = size<(buffSize-fillSize) ? size:(buffSize-fillSize);
+
+ fillSize += cpSize;
+
+ return cpSize;
+ }
+
+int akg::CommBuffer::write(FileDescriptor &socket) throw()
+ {
+ DBTALK("CommBuffer write fillSize="<<fillSize<<" sendSize="<<sendSize);
+ int rasp = socket.write(data+sendSize,fillSize-sendSize);
+
+ if(rasp>=0) sendSize+=rasp;
+
+ return rasp;
+ }
+
+int akg::CommBuffer::write(void *externalBuffer,int size) throw()
+ {
+ assert(externalBuffer != 0);
+ assert(size >= 0);
+
+ int cpSize = size<(fillSize-sendSize) ? size:(fillSize-sendSize);
+
+ memcpy(externalBuffer,data+sendSize,cpSize);
+ sendSize+=cpSize;
+
+ return cpSize;
+ }
+
+void akg::CommBuffer::clearToRead() throw()
+ {
+ DBTALK("CommBuffer clearToRead");
+ fillSize=0;sendSize=0;
+ }
+void akg::CommBuffer::clearToWrite() throw()
+ {
+ DBTALK("CommBuffer clearToWrite");
+ sendSize=0;
+ }
+
diff --git a/network/akgnet_commbuffer.hh b/network/akgnet_commbuffer.hh
new file mode 100644
index 0000000..0e28ee4
--- /dev/null
+++ b/network/akgnet_commbuffer.hh
@@ -0,0 +1,169 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: akgnet_commbuffer.hh
+ *
+ * MODULE: akg network
+ * CLASS: CommBuffer
+ *
+ * COMMENTS:
+ * Namespace akg
+ *
+*/
+
+#ifndef AKGNET_BUFFER_HH
+#define AKGNET_BUFFER_HH
+
+#include "akgnet_fdescr.hh"
+
+namespace akg
+ {
+
+/** This class is a specialized buffer used for communication by the elements
+ of this library.
+ Important:
+ - if the internal buffer overflows, it is not reallocated, even there is a resize() function. This is not an error!
+ Please think twice before you change this
+ - 'new' is supposed to throw
+*/
+
+class CommBuffer
+ {
+ public:
+ /// Default constructor, no data is allocated
+ CommBuffer() throw();
+
+ /** Constructor allocating a 'size' bytes buffer
+ Assert: size > 0
+ */
+ CommBuffer(int size) throw();
+
+ /** Constructor taking over an existing buffer
+ totalSize - the total size of the buffer
+ dataSize - the size of the usefull data
+ */
+ CommBuffer(void*,int totalSize,int dataSize=0) throw();
+
+ /// Destructor. If the internal buffer is allocated, it will be deallocated
+ ~CommBuffer() throw();
+
+ /** Allocates a new buffer. The old one, if allocated, will be deallocated
+ Assert: size > 0
+ */
+ bool allocate(int size) throw();
+
+ /// Frees the internal buffer, if allocated.
+ void freeBuffer() throw();
+
+ /** Takes over an external buffer
+ totalSize - the total size of the buffer
+ dataSize - the size of the usefull data
+ Assert: externalBuffer != 0, totalSize > 0, dataSize>=0, totalSize>=dataSize
+ */
+ void takeOver(void *externalBuffer,int totalSize,int dataSize=0) throw();
+
+ /** Resizes the internal buffer, by allocating and copying the data.
+ Returns false if the new buffer is smaller than the actual data
+ Assert: there is a buffer, so 'data != 0'*/
+ bool resize(int newSize) throw();
+
+ /// Returns a pointer to the internal buffer. You are on your own!
+ void* getData() throw();
+
+ /// Returns the size of the data stored in the buffer
+ int getDataSize() throw();
+
+ /// Returns the total capacity of the buffer
+ int getBufferSize() throw();
+
+ /// Returns the size already written
+ int getSendedSize() throw();
+
+ /// Returns the size not filled yet
+ int getNotFilledSize() throw();
+
+ /// Returns the size not written yet
+ int getNotSendedSize() throw();
+
+ /// Returns true if the internal buffer is allocated
+ bool isAllocated() throw();
+
+ /** Reads as much as possible from the specified FileDescriptor
+ It stops if the buffer is full or there are are no more bytes to read
+ Returns the number of bytes red
+ */
+ int read(FileDescriptor&) throw();
+
+ /** Reads at most 'size' bytes from the specified memory address
+ It stops if the buffer is full or there are are no more bytes to read
+ Returns the number of bytes red
+ Assert: externalBuffer != 0, size >=0
+ */
+ int read(const void *externalBuffer,int size) throw();
+
+ /** Fake read, used to reserve space for future direct write
+ Returns the number of bytes reserverd, which can be less
+ than 'size' if there is not enough space
+ Assert: size >=0
+ */
+ int reserve(int size) throw();
+
+
+ /** Write as much as possible to the specified FileDescriptor
+ It stops if there are no more bytes to write or the FileDescriptor
+ can't accept more bytes
+ Returns the number of bytes written
+ */
+ int write(FileDescriptor&) throw();
+
+ /** Writes at most 'size' bytes to the specified memory address
+ It stops if the there are no more bytes to write
+ Returns the number of bytes written
+ Assert: externalBuffer != 0, size >=0
+ */
+ int write(void *externalBuffer,int size) throw();
+
+ /// Resets the buffer for reading. The data inside is discarded
+ void clearToRead() throw();
+
+ /** Resets the buffer for writing. The data inside is not touched,
+ just the writing counters are reset
+ */
+ void clearToWrite() throw();
+
+ private:
+ /// the internal buffer
+ char *data;
+ /// the size of the internal buffer
+ int buffSize;
+ /// the filled size
+ int fillSize;
+ /// the send size.
+ int sendSize;
+ /// is the buffer allocated?
+ bool allocated;
+ };
+
+} //namespace
+#endif
+
diff --git a/network/akgnet_common.hh b/network/akgnet_common.hh
new file mode 100644
index 0000000..aaf8ca6
--- /dev/null
+++ b/network/akgnet_common.hh
@@ -0,0 +1,100 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: akgnet_common.hh
+ *
+ * MODULE: akg network
+ * CLASS:
+ *
+ * COMMENTS:
+ * Namespace akg
+ * Contains common definitions for the whole package
+ *
+*/
+
+#ifndef AKGNET_COMMON_HH
+#define AKGNET_COMMON_HH
+
+#if defined(DECALPHA) || defined(LINUX)
+ #ifndef _XOPEN_SOURCE_EXTENDED
+ #define _XOPEN_SOURCE_EXTENDED // for gethostid
+ #endif //_XOPEN_SOURCE_EXTENDED
+#endif //DECALPHA || LINUX
+
+
+#include<stdio.h>
+#include<stdlib.h>
+#include<errno.h>
+
+#if defined(DECALPHA)
+ #include<strings.h>
+ #include <arpa/inet.h>
+#endif
+#include<string.h>
+
+
+
+#include<unistd.h>
+#include<sys/types.h>
+#include<sys/socket.h>
+#include<netinet/in.h>
+#include<netdb.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <time.h>
+
+
+#include <iostream>
+
+//##### System dependent data types #############
+
+#ifdef X86
+ #define akgSocklen_t socklen_t
+#endif
+
+#ifdef AIX
+ #define akgSocklen_t socklen_t
+#endif
+
+#ifdef SOLARIS
+ #define akgSocklen_t socklen_t
+ #define INADDR_NONE ((uint32_t) 0xffffffff)
+#endif
+
+#ifdef DECALPHA
+ #define akgSocklen_t size_t
+ typedef in_addr_t uint32_t;
+#endif
+
+#ifndef akgSocklen_t
+ #error "What Operating System is this?"
+#endif
+//##### Debugging stuff ########################
+
+#define DBTALK(a)
+//#define DBTALK(a) cout<<a<<endl
+
+using namespace std;
+//##############################################
+
+#endif
diff --git a/network/akgnet_fdescr.cc b/network/akgnet_fdescr.cc
new file mode 100644
index 0000000..bc5df7d
--- /dev/null
+++ b/network/akgnet_fdescr.cc
@@ -0,0 +1,113 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: akgnet_fdescr.cc
+ *
+ * MODULE: akg network
+ * CLASS: FileDescriptor
+ *
+ * COMMENTS:
+ *
+ */
+
+#include <akgnet_fdescr.hh>
+
+akg::FileDescriptor::FileDescriptor() throw()
+ {
+ fileDescriptor = -1;
+ savedErrno = 0;
+ }
+
+akg::FileDescriptor::~FileDescriptor() throw()
+ {
+ close();
+ }
+
+int akg::FileDescriptor::operator()() throw()
+ {
+ return fileDescriptor;
+ }
+
+bool akg::FileDescriptor::isOpen() throw()
+ {
+ return fileDescriptor == -1 ? false:true;
+ }
+
+void akg::FileDescriptor::close() throw()
+ {
+ if(isOpen())
+ { ::close(fileDescriptor);
+ saveErrno();
+ }
+ fileDescriptor = -1;
+ }
+
+int akg::FileDescriptor::write(const void *buffer, int count) throw()
+ {
+ savedErrno = 0;
+ DBTALK("FileDescriptor write: "<<buffer<<" count="<<count);
+ int nbytes = ::write(fileDescriptor,buffer,count);
+ if(nbytes < 0) saveErrno();
+ return nbytes;
+ }
+
+int akg::FileDescriptor::read (void *buffer, int count) throw()
+ {
+ savedErrno = 0;
+ DBTALK("FileDescriptor read: "<<buffer<<" count="<<count);
+ int nbytes = ::read(fileDescriptor,buffer,count);
+ if(nbytes < 0) saveErrno();
+ return nbytes;
+ }
+
+bool akg::FileDescriptor::setNonBlocking(bool nonBlocking) throw()
+ {
+ if(isOpen())
+ { int val = fcntl(fileDescriptor,F_GETFL,0);
+
+ if( nonBlocking) val |= O_NONBLOCK;
+ else val &=~O_NONBLOCK;
+
+ fcntl(fileDescriptor,F_SETFL,val);
+ return true;
+ }
+
+ return false;
+ }
+bool akg::FileDescriptor::isNonBlocking() throw()
+ {
+ if(isOpen())
+ { int val = fcntl(fileDescriptor,F_GETFL,0);
+ return (val & O_NONBLOCK) ? true:false;
+ }
+ return false;
+ }
+
+int akg::FileDescriptor::getErrno() throw()
+ { return savedErrno;
+ }
+void akg::FileDescriptor::saveErrno() throw()
+ { savedErrno=errno;
+ }
+
+
diff --git a/network/akgnet_fdescr.hh b/network/akgnet_fdescr.hh
new file mode 100644
index 0000000..7c41a7a
--- /dev/null
+++ b/network/akgnet_fdescr.hh
@@ -0,0 +1,107 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: akgnet_fdescr.hh
+ *
+ * MODULE: akg network
+ * CLASS: FileDescriptor
+ *
+ * COMMENTS:
+ * Namespace akg
+ *
+*/
+
+#ifndef AKGNET_FDESCR_HH
+#define AKGNET_FDESCR_HH
+
+#include "akgnet_common.hh"
+
+namespace akg
+ {
+
+/**
+ This class the base class for a hierarchie, which are
+ envelopes for the usual OS file descriptors. They offer
+ only that much functionallity as needed for our library
+ The objects of this hierarchie can't be copied!
+*/
+
+class FileDescriptor
+ {
+ public:
+ /// Destructor, if open, closes the file descriptor
+ ~FileDescriptor() throw();
+
+ /// Returns the OS file descriptor
+ int operator()() throw ();
+
+ /** Returns true if the descriptor is open.
+ Be aware that closing the file descriptor by
+ using SO specific functions instead of the
+ methods of this class can lead to incorrect results
+ */
+ bool isOpen() throw();
+
+ /// Closes the descriptor
+ void close() throw();
+
+ /// Returns the error number of the last operation
+ int getErrno() throw();
+
+ /** Writes the specified number of bytes from the
+ specified buffer.
+ Returns the number of bytes actually written
+ */
+ int write(const void *buffer, int count) throw();
+
+ /** Reads the specified number of bytes into the
+ specified buffer.
+ Returns the number of bytes actually read
+ */
+ int read (void *buffer, int count) throw();
+
+ /** Sets the non-blocking mode on or off
+ Returns true o succes
+ */
+ bool setNonBlocking(bool nonBlocking) throw();
+
+ /// Returns true if the descriptors is in non-blocking mode
+ bool isNonBlocking() throw();
+ protected:
+ /// Protected constructor
+ FileDescriptor() throw();
+
+ /// Saves the errno
+ void saveErrno() throw();
+
+ int fileDescriptor;
+ int savedErrno;
+ private:
+ /// unimplemented, objects can't be copied
+ FileDescriptor(const FileDescriptor&);
+ /// unimplemented, objects can't be copied
+ FileDescriptor& operator=(const FileDescriptor&);
+ };
+
+} // namespace
+#endif
diff --git a/network/akgnet_file.cc b/network/akgnet_file.cc
new file mode 100644
index 0000000..aa20e30
--- /dev/null
+++ b/network/akgnet_file.cc
@@ -0,0 +1,51 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: akgnet_file.cc
+ *
+ * MODULE: akg network
+ * CLASS: File
+ *
+ * COMMENTS:
+ *
+ */
+
+#include <assert.h>
+#include<akgnet_file.hh>
+
+akg::File::File() throw()
+ {
+ }
+
+akg::File::File(int osFileDescriptor) throw()
+ {
+ assert(osFileDescriptor > 0);
+ fileDescriptor = osFileDescriptor;
+ }
+
+void akg::File::connectToDescriptor(int osFileDescriptor) throw()
+ {
+ assert(osFileDescriptor > 0);
+ fileDescriptor = osFileDescriptor;
+ }
+
diff --git a/network/akgnet_file.hh b/network/akgnet_file.hh
new file mode 100644
index 0000000..4d1ee23
--- /dev/null
+++ b/network/akgnet_file.hh
@@ -0,0 +1,73 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: akgnet_file.hh
+ *
+ * MODULE: akg network
+ * CLASS: File
+ *
+ * COMMENTS:
+ * Namespace akg
+ *
+*/
+
+#ifndef AKGNET_FILE_HH
+#define AKGNET_FILE_HH
+
+#include "akgnet_fdescr.hh"
+
+namespace akg
+ {
+
+/** This class represents the files in the file descriptor hierarchie.
+ Since this is a network library, our concearn is only for the
+ descriptor of the files. The primary use of this class is access
+ to file descriptors opened in other ways than sockets, like stdin or stdout
+*/
+
+class File : public FileDescriptor
+ {
+ public:
+ /// Default constructor
+ File() throw();
+
+ /** Constructor taking an already opened file descriptor
+ Assert: osFileDescriptor > 0
+ */
+ File(int osFileDescriptor) throw();
+
+ /** Connect to an already opened file descriptor
+ Assert: osFileDescriptor > 0
+ */
+ void connectToDescriptor(int osFileDescriptor) throw();
+
+ private:
+ /// unimplemented, objects of this type can't be copied
+ File(const File&);
+
+ /// unimplemented, objects of this type can't be copied
+ File& operator=(const File&);
+ };
+
+} //namespace
+#endif
diff --git a/network/akgnet_inetaddr.cc b/network/akgnet_inetaddr.cc
new file mode 100644
index 0000000..e66dd47
--- /dev/null
+++ b/network/akgnet_inetaddr.cc
@@ -0,0 +1,181 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: akgnet_inetaddr.cc
+ *
+ * MODULE: akg network
+ * CLASS: HostAddress, SocketAddress
+ *
+ * COMMENTS:
+ *
+*/
+
+#include <akgnet_inetaddr.hh>
+#include <arpa/inet.h>
+#include <string.h>
+#include <assert.h>
+
+akg::HostAddress::HostAddress() throw()
+ {
+ initDefault();
+ }
+
+akg::HostAddress::HostAddress(uint32_t x)
+ {
+ initDefault();
+
+ address.s_addr = htonl(x);
+ struct hostent *host = gethostbyaddr((const char*)&address, sizeof(in_addr), AF_INET);
+ init(host);
+ }
+
+akg::HostAddress::HostAddress(const char *theHostName)
+ {
+ assert(theHostName != 0);
+
+ initDefault();
+
+ struct hostent *host = gethostbyname (theHostName);
+ init(host);
+ }
+
+akg::HostAddress::HostAddress(const akg::HostAddress &ha)
+ {
+ fullHostName = new char[strlen(ha.fullHostName) + 1];
+ strcpy(fullHostName, ha.fullHostName);
+
+ shortHostName = new char[strlen(ha.shortHostName) + 1];
+ strcpy(shortHostName, ha.shortHostName);
+
+ strAddress = new char[strlen(ha.strAddress) + 1];
+ strcpy(strAddress, ha.strAddress);
+ }
+akg::HostAddress::~HostAddress() throw()
+ {
+ if(fullHostName) delete[] fullHostName;
+ if(shortHostName) delete[] shortHostName;
+ if(strAddress) delete[] strAddress;
+ }
+
+bool akg::HostAddress::isValid() const throw()
+ {
+ return address.s_addr == addrNone ? false:true;
+ }
+
+void akg::HostAddress::initDefault() throw()
+ {
+ fullHostName = NULL;
+ shortHostName = NULL;
+ strAddress = NULL;
+ address.s_addr = addrNone;
+ }
+
+// New is supposed to throw
+bool akg::HostAddress::init(hostent *host)
+ {
+ if(host == NULL) return false;
+
+ in_addr *ptr = (in_addr*)host->h_addr_list[0];
+ if(host->h_name == NULL || ptr == NULL) return false;
+
+ fullHostName = new char[ strlen(host->h_name) +1];
+ strcpy(fullHostName,host->h_name);
+
+ char *dotPos = strchr(fullHostName,'.');
+ int copyLen = dotPos ? dotPos-fullHostName : strlen(fullHostName);
+
+ shortHostName = new char[copyLen+1];
+ strncpy(shortHostName,fullHostName,copyLen);
+ shortHostName[copyLen] = 0;
+
+ char *nta = inet_ntoa(*ptr);
+ strAddress = new char[strlen(nta) + 1];
+ strcpy(strAddress,nta);
+ address = *ptr;
+
+ return true;
+ }
+
+const char* akg::HostAddress::getFullHostName() const throw()
+ {
+ return fullHostName;
+ }
+
+const char* akg::HostAddress::getShortHostName() const throw()
+ {
+ return shortHostName;
+ }
+
+uint32_t akg::HostAddress::getAddress() const throw()
+ {
+ return ntohl(address.s_addr);
+ }
+
+const char* akg::HostAddress::getStringAddress() const throw()
+ {
+ return strAddress;
+ }
+
+//############################################################
+
+akg::SocketAddress::SocketAddress() throw()
+ {
+ clear();
+ }
+
+akg::SocketAddress::SocketAddress(sockaddr_in &x) throw()
+ {
+ init(x);
+ }
+
+void akg::SocketAddress::init(sockaddr_in &x) throw()
+ {
+ valid = true;
+ address = x;
+ }
+
+bool akg::SocketAddress::isValid() const throw()
+ {
+ return valid;
+ }
+void akg::SocketAddress::clear() throw()
+ {
+ valid = false;
+ address.sin_family = AF_INET;
+ }
+
+akg::HostAddress akg::SocketAddress::getHostAddress() const throw()
+ {
+ return valid ? HostAddress(getAddress()) : HostAddress();
+ }
+
+uint32_t akg::SocketAddress::getAddress() const throw()
+ {
+ return ntohl(address.sin_addr.s_addr);
+ }
+
+int akg::SocketAddress::getPort() const throw()
+ {
+ return ntohs(address.sin_port);
+ }
+
diff --git a/network/akgnet_inetaddr.hh b/network/akgnet_inetaddr.hh
new file mode 100644
index 0000000..ad9c5c3
--- /dev/null
+++ b/network/akgnet_inetaddr.hh
@@ -0,0 +1,148 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: akgnet_inetaddr.hh
+ *
+ * MODULE: akg network
+ * CLASS: HostAddress, SocketAddress
+ *
+ * COMMENTS:
+ * Namespace akg
+ *
+*/
+#ifndef AKGNET_INETADDR_HH
+#define AKGNET_INETADDR_HH
+
+#include "akgnet_common.hh"
+
+
+namespace akg
+ {
+
+/** This class represents the internet address of a computer and envelops
+ the OS data structure 'in_addr'
+ Important: new is supposed to throw
+*/
+
+
+class HostAddress
+ {
+ public:
+ static const uint32_t addrLocalhost = INADDR_LOOPBACK;
+ static const uint32_t addrBroadcast = INADDR_BROADCAST;
+ static const uint32_t addrAny = INADDR_ANY;
+ static const uint32_t addrNone = INADDR_NONE;
+
+ /// Default constructor, creating an 'invalid' object
+ HostAddress() throw();
+
+ /// Copy constructor
+ HostAddress(const HostAddress&);
+
+ /// Constructor taking a 32-bit internet address
+ HostAddress(uint32_t);
+
+ /** Constructor taking a string representation of the address
+ It can be the the name or the internet address
+ Assert: theHostName != 0
+ */
+ HostAddress(const char* theHostName);
+
+ /// Destructor
+ ~HostAddress() throw();
+
+ /// Returns true if the object was initialized correctly
+ bool isValid() const throw();
+
+ /// Returns the full host name, meaning hostname.domainname
+ const char* getFullHostName() const throw();
+
+ /// Returns the short form of the host name
+ const char* getShortHostName() const throw();
+
+ /// Returns the IP-Address as a 32-bit value
+ uint32_t getAddress() const throw();
+
+ /// Returns the string representation of the IP-Address
+ const char* getStringAddress() const throw();
+
+ private:
+ /// Initializes the object with default values. Used by the constructors
+ void initDefault() throw();
+
+ /// Initializes the object from a OS 'hostent' object. Used by the constructors
+ bool init(hostent *);
+
+ char *fullHostName;
+ char *shortHostName;
+ char *strAddress;
+ in_addr address;
+
+ ///unimplemented
+ HostAddress operator=(const HostAddress&);
+
+ };
+
+
+/** This class represents the IP address of a OS socket and envelops
+ the OS data structure 'sockaddr_in'
+*/
+class SocketAddress
+ {
+ public:
+ /// Default constructor
+ SocketAddress() throw();
+
+ /// Constructor taking a 'sockaddr_in'
+ SocketAddress(sockaddr_in&) throw();
+
+ /// Initialization from a 'sockaddr_in'
+ void init(sockaddr_in&) throw();
+
+ /// Returns true if the object is initialized
+ bool isValid() const throw();
+
+ /// Returns the HostAddress of this socket
+ HostAddress getHostAddress() const throw();
+
+ /// Returns the IP Address
+ uint32_t getAddress() const throw();
+ int getPort() const throw();
+ private:
+ bool valid;
+ void clear() throw();
+
+ private:
+ sockaddr_in address;
+ /*
+ sa_family_t sin_family
+ struct inaddr
+ { uint32_t s_addr;
+ }
+ sin_addr
+ ushort sin_port
+ */
+ };
+
+} // namespace
+#endif
diff --git a/network/akgnet_nbcomm.cc b/network/akgnet_nbcomm.cc
new file mode 100644
index 0000000..92e4ad2
--- /dev/null
+++ b/network/akgnet_nbcomm.cc
@@ -0,0 +1,579 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: akgnet_nbcomm.cc
+ *
+ * MODULE: akg network
+ * CLASS: NbJob, NbServerJob, NbClientJob, NbCommunicator
+ *
+ * COMMENTS:
+ *
+*/
+
+#include <akgnet_nbcomm.hh>
+#include <assert.h>
+
+//### NBJob - static members #########################
+time_t akg::NbJob::timeOutInterv = 30;
+time_t akg::NbJob::currentTime = 0;
+
+void akg::NbJob::setCurrentTime() throw()
+ {
+ currentTime = time(NULL);
+ }
+
+void akg::NbJob::setTimeoutInterval(time_t x) throw()
+ {
+ timeOutInterv = x;
+ }
+
+time_t akg::NbJob::getTimeoutInterval() throw()
+ {
+ return timeOutInterv;
+ }
+
+//####################################################
+akg::NbJob::NbJob(FileDescriptor &fd) throw()
+:fdRef(fd)
+ {
+ status = wks_notdefined;
+ selectorPtr = NULL;
+ currentBufferPtr = NULL;
+ lastActionTime = 0;
+ }
+
+akg::NbJob::~NbJob() throw()
+ {
+ }
+
+akg::NbJob::workingStatus akg::NbJob::getStatus() throw()
+ {
+ return status;
+ }
+
+bool akg::NbJob::isOperationPending() throw()
+ {
+ return (status != wks_notdefined &&
+ status != wks_accepting) ? true:false;
+ }
+
+bool akg::NbJob::isAccepting() throw()
+ {
+ return status == wks_accepting ? true:false;
+ }
+bool akg::NbJob::isReading() throw()
+ {
+ return status == wks_reading ? true:false;
+ }
+bool akg::NbJob::isWriting() throw()
+ {
+ return status == wks_writing ? true:false;
+ }
+bool akg::NbJob::isProcessing() throw()
+ {
+ return status == wks_processing ? true:false;
+ }
+
+bool akg::NbJob::readPartialMessage() throw()
+ {
+ assert(currentBufferPtr != NULL);
+
+ action();
+
+ int nbytes = currentBufferPtr->read(fdRef);
+
+ if(nbytes>0)
+ {
+ DBTALK("..read socket("<<fdRef()<<") "<<nbytes);
+ return validateMessage();
+ }
+
+ else
+ { int saveerrno = fdRef.getErrno();
+ switch(saveerrno)
+ {
+ case EINTR: //DBTALK("EINTR, retry please");
+ break;
+
+ case EAGAIN: //DBTALK("EAGAIN, retry please");
+ break;
+
+ //case 0: DBTALK("Premature End-of-file");
+ // executeOnReadError() ???
+ // break;
+
+ default: DBTALK("Read error "<<saveerrno);
+ executeOnReadError();
+ break;
+ }
+ }
+ return false;
+ }
+
+bool akg::NbJob::writePartialMessage() throw()
+ {
+ assert(currentBufferPtr != NULL);
+
+ action();
+ int nbytes = currentBufferPtr->write(fdRef);
+
+ if(nbytes>0)
+ {
+ DBTALK("..write socket("<<fdRef()<<") "<<nbytes);
+
+ if(currentBufferPtr->getNotSendedSize()==0)
+ {
+ DBTALK("Write ready");
+ executeOnWriteReady();
+ return true;
+ }
+ }
+ else
+ {int saveerrno = fdRef.getErrno();
+ switch(saveerrno)
+ {
+ case EINTR: //DBTALK("EINTR, retry please");
+ break;
+
+ case EAGAIN: //DBTALK("EAGAIN, retry please");
+ break;
+
+ //case 0: DBTALK("Premature partner hang up"); //?? valabil la write
+ // break;
+
+ default: DBTALK("Write error "<<saveerrno);
+ executeOnWriteError();
+ break;
+ }
+ }
+ return false;
+ }
+
+bool akg::NbJob::cleanUpIfTimeout() throw()
+ {
+ if(fdRef.isOpen() == false ) return false;
+ if(lastActionTime + timeOutInterv > currentTime) return false;
+
+ DBTALK("Client socket "<<fdRef()<<" timeout");
+ clearConnection();
+
+ //********************
+ specificCleanUpOnTimeout();
+ //********************
+ return true;
+ }
+
+void akg::NbJob::clearConnection() throw()
+ {
+ if(fdRef.isOpen() && selectorPtr)
+ { selectorPtr->clearRead(fdRef());
+ selectorPtr->clearWrite(fdRef());
+ fdRef.close();
+ }
+ }
+
+void akg::NbJob::action() throw()
+ { lastActionTime = currentTime;
+ }
+
+int akg::NbJob::getSocket() throw()
+ { return fdRef();
+ }
+
+void akg::NbJob::executeOnAccept() throw()
+ {
+ }
+bool akg::NbJob::setReading() throw()
+ {
+ if(selectorPtr == NULL) return false;
+ selectorPtr->setRead(fdRef());
+ status = wks_reading;
+ return true;
+ }
+
+bool akg::NbJob::setWriting() throw()
+ {
+ if(selectorPtr == NULL) return false;
+ selectorPtr->setWrite(fdRef());
+ status = wks_writing;
+ return true;
+ }
+
+int akg::NbJob::getErrno() throw()
+ {
+ return fdRef.getErrno();
+ }
+
+//##################################################################
+akg::NbServerJob::NbServerJob() throw()
+:NbJob(serverSocket)
+ {
+ }
+
+void akg::NbServerJob::initOnAttach(Selector *pSelector) throw()
+ {
+ selectorPtr = pSelector;
+ }
+
+
+akg::NbJob::acceptStatus akg::NbServerJob::acceptConnection(ListenSocket& listenSocket) throw()
+ {
+ DBTALK("Am intrat in accepting");
+ assert(currentBufferPtr != NULL);
+
+ if(status != wks_accepting) return acs_Iambusy;
+ action();
+
+ if(serverSocket.acceptFrom(listenSocket) == false)
+ {
+ int saveerrno = serverSocket.getErrno();
+ if(saveerrno==EAGAIN) DBTALK("No pending connections");
+ else DBTALK("Accept error "<<saveerrno);
+ return acs_nopending;
+ }
+
+ serverSocket.setNonBlocking(true);
+
+ setReading();
+
+ executeOnAccept();
+ DBTALK("Accept: Socket="<<fdRef());
+ return acs_accepted;
+ }
+
+
+akg::SocketAddress akg::NbServerJob::getClientSocketAddress() throw()
+ {
+ return serverSocket.getPeerAddress();
+ }
+
+akg::HostAddress akg::NbServerJob::getClientHostAddress() throw()
+ {
+ return serverSocket.getPeerAddress().getHostAddress();
+ }
+
+void akg::NbServerJob::readyToWriteAnswer() throw()
+ {
+ currentBufferPtr->clearToWrite();
+
+ selectorPtr->clearRead(serverSocket());
+ selectorPtr->setWrite(serverSocket());
+ action();
+
+ status = wks_writing;
+ }
+//##################################################################
+
+akg::NbClientJob::NbClientJob() throw()
+:NbJob(clientSocket)
+ {
+ }
+
+bool akg::NbClientJob::connectToServer(const char* serverHost,int serverPort) throw()
+ {
+ if(clientSocket.open(serverHost,serverPort))
+ {
+ clientSocket.setNonBlocking(true);
+ selectorPtr->setWrite(clientSocket());
+ status = wks_writing;
+ action();
+ return true;
+ }
+ return false;
+ }
+
+void akg::NbClientJob::initOnAttach(Selector *pselector) throw()
+ {
+ selectorPtr = pselector;
+
+ if(status == wks_writing)
+ { selectorPtr->setWrite(clientSocket());
+ }
+ }
+
+akg::NbJob::acceptStatus
+akg::NbClientJob::acceptConnection(ListenSocket&) throw()
+ {
+ // we don't accept connections
+ return acs_Iambusy;
+ }
+
+void akg::NbClientJob::readyToReadAnswer() throw()
+ {
+ currentBufferPtr->clearToRead();
+
+ selectorPtr->clearWrite(clientSocket());
+ selectorPtr->setRead(clientSocket());
+ action();
+
+ status = wks_reading;
+ }
+
+//##################################################################
+akg::NbCommunicator::NbCommunicator() throw()
+ {
+ maxJobs = 0;
+ jobPtr = NULL;
+ }
+akg::NbCommunicator::NbCommunicator(int newMaxJobs)
+ {
+ jobPtr = NULL;
+ initJobs(newMaxJobs);
+ }
+
+bool akg::NbCommunicator::initJobs(int newMaxJobs)
+ {
+ if(jobPtr != NULL) return false;
+ maxJobs = newMaxJobs;
+ jobPtr = new JobPtr[maxJobs];
+
+ for(int i=0;i<maxJobs;i++)
+ { jobPtr[i]=0;
+ }
+ return true;
+ }
+
+akg::NbCommunicator::~NbCommunicator() throw()
+ {
+ if(jobPtr != NULL) delete[] jobPtr;
+ }
+
+bool akg::NbCommunicator::attachJob(NbJob &newJob) throw()
+ {
+ int freeSlot = -1;
+ for(int i=0;i<maxJobs;i++)
+ {
+ if(jobPtr[i]== &newJob) return false; // job e in lista
+ if(jobPtr[i]== NULL && freeSlot ==-1 ) freeSlot = i;
+ }
+ if(freeSlot ==-1 ) return false;
+
+ jobPtr[freeSlot]= &newJob;
+ newJob.initOnAttach(&selector);
+ return true;
+ }
+
+bool akg::NbCommunicator::deattachJob(NbJob &oldJob) throw()
+ {
+ for(int i=0;i<maxJobs;i++)
+ {
+ if(jobPtr[i]== &oldJob)
+ {
+ jobPtr[i] = NULL;
+ oldJob.clearConnection();
+ oldJob.initOnAttach(NULL);
+ return true;
+ }
+ }
+ return false;
+ }
+
+bool akg::NbCommunicator::mayExit() throw()
+ {
+ if(exitRequest == false) return false;
+
+ closeSocket(listenSocket); // we don't accept requests any more
+
+ for(int i=0;i<maxJobs;i++)
+ {
+ if(jobPtr[i] == NULL) continue;
+ if(jobPtr[i]->isOperationPending()) return false; // no, we have pending
+ }
+ return true; // ok, we may exit
+ }
+
+bool akg::NbCommunicator::runServer() throw()
+ {
+ if(listenPort == 0) return false;
+
+ if(initListenSocket(listenPort,true) == false) return false;
+
+ return mainLoop();
+ }
+
+bool akg::NbCommunicator::runClient() throw()
+ {
+ return mainLoop();
+ }
+
+bool akg::NbCommunicator::mainLoop() throw()
+ {
+ exitRequest=false;
+
+ while( mayExit() == false)
+ {
+ DBTALK("Waiting for calls");
+
+ if(executeBeforeSelect() == false) return false;
+
+ int rasp = selector();
+
+ akg::NbJob::setCurrentTime();
+
+ if(executeAfterSelect() == false) return false;
+
+ if(rasp > 0)
+ {
+ DBTALK("Ringing");
+ // first this, to increase the chance to free a client
+ dispatchWriteRequest();
+ connectNewClients();
+ dispatchReadRequest();
+ processJobs();
+ lookForTimeout(); // important!
+ }
+ if(rasp == 0)
+ {
+ DBTALK("Timeout");
+ lookForTimeout();
+ if(executeOnTimeout() == false) return false;
+ }
+ if(rasp < 0)
+ {
+ DBTALK("select error: "<<strerror(errno));
+ }
+ }
+ return true;
+ }
+
+void akg::NbCommunicator::processJobs() throw()
+ {
+ DBTALK("process Jobs - entering");
+
+ for(int i=0;i<maxJobs;i++)
+ {
+ if(jobPtr[i]==NULL) continue;
+
+ JobPtr& currentJob = jobPtr[i];
+
+ if(currentJob->isProcessing())
+ {
+ DBTALK("job "<<i<<" is processing");
+
+ currentJob->processRequest();
+ }
+ }
+ }
+
+void akg::NbCommunicator::lookForTimeout() throw()
+ {
+ DBTALK("Looking for timeout");
+
+ for(int i=0;i<maxJobs;i++)
+ {
+ if(jobPtr[i]==NULL) continue;
+
+ jobPtr[i]->cleanUpIfTimeout();
+ }
+ }
+
+void akg::NbCommunicator::dispatchWriteRequest() throw()
+ {
+ DBTALK("Dispatch writing");
+ int i;
+ for(i=0;i<maxJobs;i++)
+ {
+ if(jobPtr[i]==NULL) continue;
+
+ JobPtr& currentJob = jobPtr[i];
+
+ if(currentJob->isWriting())
+ {
+ DBTALK("job "<<i<<' '<<currentJob->getSocket()<<" is active");
+ if(selector.isWrite(currentJob->getSocket()))
+ {
+ DBTALK("...and may write ");
+ currentJob->writePartialMessage();
+ }
+ }
+ }
+ }
+
+void akg::NbCommunicator::dispatchReadRequest() throw()
+ {
+ DBTALK("Dispatch reading");
+ int i;
+ for(i=0;i<maxJobs;i++)
+ {
+ if(jobPtr[i]==NULL) continue;
+
+ JobPtr& currentJob = jobPtr[i];
+
+ if(currentJob->isReading())
+ {
+ DBTALK("job "<<i<<' '<<currentJob->getSocket()<<" is active");
+ if(selector.isRead(currentJob->getSocket()))
+ {
+ DBTALK("... and has message");
+ currentJob->readPartialMessage();
+ }
+ }
+ }
+ }
+
+void akg::NbCommunicator::connectNewClients() throw()
+ {
+ DBTALK("connect listenSocket="<<listenSocket());
+
+ if(selector.isRead(listenSocket()) == false) return;
+
+ DBTALK("Client is calling");
+
+ akg::NbJob::acceptStatus status;
+
+ for(int i=0;i<maxJobs;i++)
+ {
+ if(jobPtr[i] == NULL) continue;
+
+ JobPtr& currentJob = jobPtr[i];
+
+ if(currentJob->isAccepting())
+ {
+ // we try to connect as much pending connections as possible
+ status = currentJob->acceptConnection(listenSocket);
+
+ if(status == akg::NbJob::acs_nopending ) break;
+ // there is no pending request,
+ DBTALK("Connected client "<<i<<" on socket "<<currentJob->getSocket());
+ }
+ }
+ }
+
+bool akg::NbCommunicator::executeBeforeSelect() throw()
+ {
+ // false means server exit immediately
+ return true;
+ }
+
+bool akg::NbCommunicator::executeAfterSelect() throw()
+ {
+ // false means server exit immediately
+ return true;
+ }
+
+bool akg::NbCommunicator::executeOnTimeout() throw()
+ {
+ // false means server exit immediately
+ return true;
+ }
+
diff --git a/network/akgnet_nbcomm.hh b/network/akgnet_nbcomm.hh
new file mode 100644
index 0000000..441d8e4
--- /dev/null
+++ b/network/akgnet_nbcomm.hh
@@ -0,0 +1,370 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: akgnet_nbcomm.hh
+ *
+ * MODULE: akg network
+ * CLASS: NbJob, NbServerJob, NbClientJob, NbCommunicator
+ *
+ * COMMENTS:
+ * Namespace akg
+ *
+*/
+
+#ifndef AKGNET_NBCOMM_HH
+#define AKGNET_NBCOMM_HH
+
+#include "akgnet_server.hh"
+
+namespace akg
+ {
+
+/** Base class for non-blocking communication jobs
+*/
+
+class NbJob
+ {
+ public:
+ /** Static function for setting the current time. Used
+ for marking the last action time, so timeout can be monitorized
+ */
+ static void setCurrentTime() throw();
+
+ /** Static function for setting the timeout interval
+ We use the same timeout for all jobs because the
+ server doesn't do any distinction between jobs
+ */
+ static void setTimeoutInterval(time_t x) throw();
+
+ /// Returns the timeout interval set for the jobs
+ static time_t getTimeoutInterval() throw();
+
+ public:
+ /// Status regarding accepting a new job
+ enum acceptStatus
+ { acs_nopending = 0,
+ acs_Iambusy = 1,
+ acs_accepted = 2
+ };
+ /// Status during the lifetime of a job
+ enum workingStatus
+ { wks_notdefined = 0,
+ wks_accepting = 1, // job is ready to accept a connection
+ wks_reading = 2, // job is reading data
+ wks_writing = 3, // job is writing data
+ wks_processing = 4 // job is processing the request
+ };
+
+ virtual ~NbJob() throw();
+ /// Returns the working status
+ workingStatus getStatus() throw();
+
+ /** Returns true if there is an operation in progress
+ this means reading, writing or processing
+ */
+ bool isOperationPending() throw();
+
+ /// Returns true if the job is ready to accept a connection
+ bool isAccepting() throw();
+
+ /// Returns true if the job is reading data
+ bool isReading() throw();
+
+ /// Returns true if the job is writing data
+ bool isWriting() throw();
+
+ /// Returns true if the job is processing
+ bool isProcessing() throw();
+
+ /** Pure function to do initialization when attached to a Selector
+ Don't throw!
+ */
+ virtual void initOnAttach(Selector *pselector) throw() =0;
+
+ /** Pure function to do initialization when accepting a connection
+ Returns:
+ - acs_nopending when there is connection pending
+ - acs_Iambusy when the job can't accept this connection
+ - acs_accepted when the connection was accepted
+ Assert:
+ the 'currentBufferPtr' is initialized. This would be a software error
+ Don't throw!
+ */
+ virtual acceptStatus acceptConnection(ListenSocket& listenSocket) throw() =0;
+
+ /** Reads as much data as it can. After every read it calls the
+ 'validateMessage()' function and returns whatever this function returns.
+ If there is a read error, other than EINTR or EAGAIN, the function
+ 'executeOnReadError()' is called
+ Returns 'true' if the message is completelly red
+ Returns 'false' if there should be some more data
+ */
+ bool readPartialMessage() throw();
+
+ /** Writes as much data as it can. After writing all data the function
+ 'executeOnWriteReady()' is called.
+ If there is a write error, other than EINTR or EAGAIN, the function
+ 'executeOnWriteError()' is called
+ Returns 'true' if the message is completelly written
+ Returns 'false' if there should be some more data to write
+ */
+ bool writePartialMessage() throw();
+
+ /// Clears the connection - closes the socket and removes it from the Selector
+ void clearConnection() throw();
+
+ /// Returns the OS file descriptor for the socket
+ int getSocket() throw();
+
+ /// Returns the errno of the last socket operation
+ int getErrno() throw();
+ //######################################
+ /** Virtual function to clean up if timeout occured
+ This version returns 'false' if no timeout or no connection
+ If timeout it clears the connection and calls
+ 'specificCleanUpOnTimeout()'
+ Don't throw!
+ */
+ virtual bool cleanUpIfTimeout() throw();
+
+ /** Pure function to process the request
+ It has to set the appropriate status, so the server
+ knows how to continue with this job
+ Don't throw!
+ */
+ virtual void processRequest() throw() =0;
+ //######################################
+ protected:
+ /// called after every read, returns 'true' if the message is all here
+ virtual bool validateMessage() throw() =0;
+
+ /// called when client is accepted, default does nothing
+ virtual void executeOnAccept() throw();
+
+ /// called when message is written
+ virtual void executeOnWriteReady() throw() =0;
+
+ /// called when timeout, it has to set the status apropriate and do other cleanup
+ virtual void specificCleanUpOnTimeout() throw() =0;
+
+ /// called when a read error occurs, usual a message and clean up
+ virtual void executeOnReadError() throw() =0;
+
+ /// called when a write error occurs, usual a message and clean up
+ virtual void executeOnWriteError() throw() =0;
+ //######################################
+ protected:
+ /// Protected constructor, taking a FileDescriptor, usually a Socket
+ NbJob(FileDescriptor&) throw() ;
+
+ /// Helper function for setting the job in read modus
+ bool setReading() throw();
+
+ /// Helper function for setting the job in write modus
+ bool setWriting() throw();
+ workingStatus status;
+
+ /** Reference to a FileDescriptor, usually a Socket. It has to be provided by the
+ derived class
+ */
+ FileDescriptor &fdRef;
+
+ /** Pointer to a Selector, which has to be provided by the Server object
+ to which this job is attached
+ */
+ Selector *selectorPtr;
+
+ /** Pointer to a CommBuffer, which has to be provided by the derived class
+ */
+ CommBuffer *currentBufferPtr;
+
+ // for timeout
+ time_t lastActionTime;
+
+ /// Helper function which marks the current moment, so timeout counter is reset
+ void action() throw();
+
+ static time_t timeOutInterv;
+ static time_t currentTime;
+ };
+
+/* Base class for generic non-blocking server jobs
+ */
+class NbServerJob : public NbJob
+ {
+ public:
+ /// Default constructor
+ NbServerJob() throw();
+
+ /** The version for servers, it just initializes the 'Selector*'
+ It doesn't have to be overloaded, it's OK for servers
+ */
+ void initOnAttach(Selector *pselector) throw();
+
+ /** The version for servers
+ It doesn't have to be overloaded, it's OK for most servers
+ */
+ acceptStatus acceptConnection(ListenSocket& listenSocket) throw();
+
+ /// Returns the SocketAddress of the client
+ SocketAddress getClientSocketAddress() throw();
+
+ /// Returns the HostAddress of the client
+ HostAddress getClientHostAddress() throw();
+ protected:
+
+ /// helper function, call it in "processRequest" to switch to writing
+ void readyToWriteAnswer() throw();
+
+ ServerSocket serverSocket;
+ };
+
+/* Base class for generic non-blocking client jobs
+ */
+class NbClientJob : public NbJob
+ {
+ public:
+ /// Default constructor
+ NbClientJob() throw();
+
+ /// Returns 'true' if connection succeded
+ bool connectToServer(const char* serverHost, int serverPort) throw();
+
+
+ /** The version for clients, it initializes the 'Selector*'
+ and prepares for writing. It has to be called AFTER the
+ connection to the server succeded!
+ It doesn't have to be overloaded, it's OK for most clients
+ */
+ void initOnAttach(Selector *pselector) throw();
+
+ /** The version for clients. It just returns 'acs_Iambusy' since
+ clients don't accept connections
+ It doesn't have to be overloaded, it's OK for most clients
+ */
+ acceptStatus acceptConnection(ListenSocket& listenSocket) throw();
+ protected:
+
+ /// helper function, call it in 'executeOnWriteReady()' to switch to reading
+ void readyToReadAnswer() throw();
+
+ ClientSocket clientSocket;
+ };
+
+/**
+ The heart of the non-blocking communication. It's derived from GenericServer but
+ it is called 'Communicator' since it not only for servers but also for clients
+ You can use this class for most communication purposes, special ones have to
+ reimplement 'executeBeforeSelect()' or 'executeOnTimeout()'
+ A better implementation should use 'vector'
+ Important: new is supposed to throw!
+ */
+
+class NbCommunicator : public GenericServer
+ {
+ public:
+ /// Default constructor
+ NbCommunicator() throw();
+
+ /// Constructor setting also the maximal number of simultan jobs
+ NbCommunicator(int newMaxJobs);
+
+ /// Destructor
+ ~NbCommunicator() throw();
+
+ /// Sets the maximal number of simultan jobs
+ bool initJobs(int newMaxJobs);
+
+ /// returns the maximal number of simultan jobs
+ int getMaxJobs() throw();
+
+ /** Attaches a new job. Returns 'true' if succeded, 'false' if the
+ job is already attached or if the maximal number of jobs
+ is already attached
+ */
+ bool attachJob(NbJob&) throw();
+
+ /** Deattach job. Returns 'true' if succeded, 'false' if the
+ job is not attached
+ */
+ bool deattachJob(NbJob&) throw();
+
+ /// This runs the main loop for servers, this means it initializes the listen socket first
+ bool runServer() throw();
+
+ /// This runs the main loop for clients, this means without initializing the listen socket
+ bool runClient() throw();
+ protected:
+ /** Called before select, if it returns 'false' the loop exits.
+ This version just returns 'true'
+ */
+ virtual bool executeBeforeSelect() throw();
+
+ /** Called after select, if it returns 'false' the loop exits.
+ This version just returns 'true'
+ */
+ virtual bool executeAfterSelect() throw();
+ /** Called if select times out, if it returns 'false' the loop exits.
+ This version just returns 'true'
+ */
+ virtual bool executeOnTimeout() throw();
+ private:
+ typedef NbJob *JobPtr;
+
+ JobPtr *jobPtr;
+ int maxJobs;
+
+ /** The main loop of the communication: it waits for clients, dispatches them to the
+ accepting jobs, then offers the jobs the possibility to read, process and write
+ It returns 'false' only if 'executeBeforeSelect()' or 'executeOnTimeout()'
+ return 'false'
+ Otherwise it returns 'true'
+ */
+ bool mainLoop() throw();
+
+ /// Helper function for dispatching read requests
+ void dispatchReadRequest() throw();
+
+ /// Helper function for dispatching write requests
+ void dispatchWriteRequest() throw();
+
+ /// Helper function for dispatching connect requests
+ void connectNewClients() throw();
+
+ /// Helper function which looks for timeouted jobs
+ void lookForTimeout() throw();
+
+ /// Helper function which calls 'processRequest()' of all jobs that are processing
+ void processJobs() throw();
+
+ /** Helper function which returns 'true' if somebody called 'shouldExit()'
+ and there is no job which processes anything. But it closes the listen socket
+ so no more jobs are accepted and returns 'true' when all jobs finish
+ */
+ bool mayExit() throw();
+
+ };
+
+} //namespace
+#endif
+
diff --git a/network/akgnet_selector.cc b/network/akgnet_selector.cc
new file mode 100644
index 0000000..7ad2f64
--- /dev/null
+++ b/network/akgnet_selector.cc
@@ -0,0 +1,97 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#include "akgnet_selector.hh"
+
+
+akg::Selector::Selector() throw()
+ {
+ FD_ZERO(& watchReadFdSet);
+ FD_ZERO(& watchWriteFdSet);
+ FD_ZERO(& watchExceptFdSet);
+ tvptr = NULL;
+ }
+void akg::Selector::setTimeout(int sec,int milisec) throw()
+ { tvinit.tv_sec=sec;
+ tvinit.tv_usec=milisec;
+ tvptr=&tv; // yes, yes, &tv
+ }
+void akg::Selector::disableTimeout() throw()
+ { tvptr=NULL;
+ }
+void akg::Selector::setRead(int fdescr) throw()
+ {
+ if(fdescr < 0) return;
+ FD_SET(fdescr,&watchReadFdSet);
+ }
+void akg::Selector::clearRead(int fdescr) throw()
+ {
+ if(fdescr < 0) return;
+ FD_CLR(fdescr,&watchReadFdSet);
+ }
+void akg::Selector::setWrite(int fdescr) throw()
+ {
+ if(fdescr < 0) return;
+ FD_SET(fdescr,&watchWriteFdSet);
+ }
+void akg::Selector::clearWrite(int fdescr) throw()
+ {
+ if(fdescr < 0) return;
+ FD_CLR(fdescr,&watchWriteFdSet);
+ }
+
+int akg::Selector::operator()() throw()
+ {
+ resultReadFdSet =watchReadFdSet;
+ resultWriteFdSet=watchWriteFdSet;
+ // error unused
+ // tv has to be reloaded every time; if tvptr is NULL it doesn't matter
+ tv.tv_sec = tvinit.tv_sec;
+ tv.tv_usec = tvinit.tv_usec;
+
+ return select(FD_SETSIZE,&resultReadFdSet,&resultWriteFdSet,NULL,tvptr);
+ }
+
+bool akg::Selector::isRead(int fdescr) throw()
+ {
+ if(fdescr < 0) return false;
+ return FD_ISSET(fdescr,&resultReadFdSet);
+ }
+bool akg::Selector::isWrite(int fdescr) throw()
+ {
+ if(fdescr < 0) return false;
+ return FD_ISSET(fdescr,&resultWriteFdSet);
+ }
+
+void akg::Selector::closeForcedAllFileDescriptors() throw()
+ {
+ for(int i=0;i<FD_SETSIZE;i++)
+ {
+ if(FD_ISSET(i,&watchReadFdSet) || FD_ISSET(i,&watchWriteFdSet))
+ {
+ close(i);
+ }
+ }
+ }
+
+
diff --git a/network/akgnet_selector.hh b/network/akgnet_selector.hh
new file mode 100644
index 0000000..fde8462
--- /dev/null
+++ b/network/akgnet_selector.hh
@@ -0,0 +1,95 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: akgnet_selector.hh
+ *
+ * MODULE: akg network
+ * CLASS: Selector
+ *
+ * COMMENTS:
+ * Namespace akg
+ *
+*/
+
+#ifndef AKGNET_SELECTOR
+#define AKGNET_SELECTOR
+
+#include "akgnet_common.hh"
+
+namespace akg
+ {
+
+/** This class envelops the 'select' function of the C-library
+*/
+
+class Selector
+ {
+ public:
+ /// Default constructor
+ Selector() throw();
+
+ /// Sets the timeout interval
+ void setTimeout(int sec,int milisec) throw();
+
+ /// Disables the timeout
+ void disableTimeout() throw();
+
+ /// Registers the file descriptor for reading
+ void setRead(int fdescr) throw();
+ /// Unregisters the file descriptor from reading
+ void clearRead(int fdescr) throw();
+
+ /// Registers the file descriptor for writing
+ void setWrite(int fdescr) throw();
+ /// Unregisters the file descriptor from writing
+ void clearWrite(int fdescr) throw();
+
+ /// The real 'select' operation. The return value is the one of 'select'
+ int operator()() throw();
+
+ /// Returns true if the file descriptor is registered for read
+ bool isRead(int fdescr) throw();
+ /// Returns true if the file descriptor is registered for write
+ bool isWrite(int fdescr) throw();
+
+ /** Closes all file descriptors. Usefull when forking so
+ child processes don't inherit this file descriptors
+ */
+ void closeForcedAllFileDescriptors() throw();
+ private:
+ fd_set watchReadFdSet;
+ fd_set watchWriteFdSet;
+ fd_set watchExceptFdSet; // unused but ...
+
+ fd_set resultReadFdSet;
+ fd_set resultWriteFdSet;
+ fd_set resultExceptFdSet; // unused but ...
+
+ struct timeval tvinit;
+ struct timeval tv;
+ timeval *tvptr;
+
+ };
+
+} // namespace
+#endif
diff --git a/network/akgnet_server.cc b/network/akgnet_server.cc
new file mode 100644
index 0000000..8fcc5e0
--- /dev/null
+++ b/network/akgnet_server.cc
@@ -0,0 +1,173 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: akgnet_server.cc
+ *
+ * MODULE: akg network
+ * CLASS: GenericServer, BlockingServer
+ *
+ * COMMENTS:
+ *
+ */
+
+#include "debug.hh"
+
+#include <akgnet_server.hh>
+
+//#include<iostream>
+
+
+akg::GenericServer::GenericServer() throw()
+ {
+ listenPort = 0;
+ exitRequest = false;
+ }
+akg::GenericServer::~GenericServer() throw()
+ {
+ }
+
+void akg::GenericServer::setListenPort(int x) throw()
+ {
+ listenPort = x;
+ }
+int akg::GenericServer::getListenPort() throw()
+ {
+ return listenPort;
+ }
+
+void akg::GenericServer::setTimeout(int sec,int milisec) throw()
+ { selector.setTimeout(sec,milisec);
+ }
+void akg::GenericServer::disableTimeout() throw()
+ { selector.disableTimeout();
+ }
+
+void akg::GenericServer::shouldExit() throw()
+ {
+ exitRequest = true;
+ }
+
+
+bool akg::GenericServer::initListenSocket(int port, bool nonblocking) throw()
+ {
+ if(listenSocket.open(port) == false) return false;
+
+ if(nonblocking) listenSocket.setNonBlocking(true);
+
+ selector.setRead(listenSocket());
+
+ DBTALK("Listen socket="<<listenSocket());
+ return true;
+ }
+
+bool akg::GenericServer::connectNewClient(ServerSocket &s) throw()
+ {
+ if(s.acceptFrom(listenSocket)==false) return false;
+
+ selector.setRead(s());
+
+ return true;
+ }
+void akg::GenericServer::closeSocket(Socket &s) throw()
+ {
+ if(s.isOpen())
+ { selector.clearRead(s());
+ selector.clearWrite(s());
+ s.close();
+ }
+ }
+
+
+//###########################
+
+akg::BlockingServer::BlockingServer() throw()
+ {
+ }
+akg::BlockingServer::~BlockingServer() throw()
+ {
+ }
+
+bool akg::BlockingServer::runServer() throw()
+{
+ ENTER( "akg::BlockingServer::runServer" );
+
+ if(listenPort == 0)
+ {
+ LEAVE( "akg::BlockingServer::runServer, listenPort=0, result=false" );
+ return false;
+ }
+
+ if(initListenSocket(listenPort,false)==false)
+ {
+ LEAVE( "akg::BlockingServer::runServer, Error: init socket failed for port " << listenPort << ", result=false" );
+ return false;
+ }
+
+ while(exitRequest == false)
+ {
+ int rasp = selector();
+ TALK( "rasp=" << rasp );
+ if(rasp>0)
+ {
+ if(serverSocket.isOpen())
+ {
+ TALK( "socket is open." );
+ if(selector.isRead(serverSocket()))
+ {
+ TALK( "socket is readable, executing request." );
+ executeRequest(serverSocket);
+ TALK( "closing socket." );
+ closeSocket(serverSocket);
+ TALK( "socket closed." );
+ }
+ }
+ else if(selector.isRead(listenSocket()))
+ {
+ TALK( "socket not open, but readable (???). connecting new client." );
+ connectNewClient(serverSocket);
+ TALK( "after client connect." );
+ // we don't care why it could fail
+ }
+ else
+ {
+ TALK( "no read socket - should never have reached this point." );
+ }
+ }
+
+ if(rasp == 0)
+ {
+ TALK( "exec timeout" );
+ executeTimeout();
+ }
+
+ if(rasp<0)
+ {
+ TALK( "Internal connect error: bad selector." );
+ }
+ }
+
+ LEAVE( "akg::BlockingServer::runServer, result=true" );
+ return true;
+}
+
+
diff --git a/network/akgnet_server.hh b/network/akgnet_server.hh
new file mode 100644
index 0000000..40d9129
--- /dev/null
+++ b/network/akgnet_server.hh
@@ -0,0 +1,157 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: akgnet_server.hh
+ *
+ * MODULE: akg network
+ * CLASS: GenericServer, BlockingServer
+ *
+ * COMMENTS:
+ * Namespace akg
+ *
+*/
+
+#ifndef AKGNET_SERVER_HH
+#define AKGNET_SERVER_HH
+
+//#### Includes #################################
+
+#include "akgnet_socket.hh"
+#include "akgnet_selector.hh"
+#include "akgnet_commbuffer.hh"
+
+//###############################################
+
+
+namespace akg
+ {
+/** Abstract base class for servers. Offers basic functionality
+ for opening the listen socket and accepting a new connection
+ and other helper functions for more evoluate servers
+*/
+class GenericServer
+ {
+ public:
+ /// Default constructor
+ GenericServer() throw();
+
+ /// Destructor
+ virtual ~GenericServer() throw();
+
+ //*************************
+ /** Pure function to run the server. Has to initialize
+ the listen socket, than makes a loop by listening,
+ accepting and dispatching the connection
+ for processing. It should'n throw, it has to handle
+ correcty every exception
+ */
+ virtual bool runServer() throw() =0;
+ //*************************
+
+ /// Instructs the server to leave the loop (runServer())
+ void shouldExit() throw();
+
+ /// Sets the listen port
+ void setListenPort(int) throw();
+
+ /// Returns the listen port
+ int getListenPort() throw();
+
+ /** Sets the timeout, how much time the selector should
+ wait for incomming requests
+ */
+ void setTimeout(int sec,int milisec) throw();
+
+ /// Disables timeout, means wait unlimited
+ void disableTimeout() throw();
+
+ protected:
+ /// Init the listen socket
+ bool initListenSocket(int port, bool nonblocking) throw();
+
+ /** Connects a new client by accepting the connection
+ and setting the ServerSocket in read modus
+ */
+ bool connectNewClient(ServerSocket&) throw();
+
+ /** Closes the given Socket and removes it
+ from the Selector
+ */
+ void closeSocket(Socket&) throw();
+
+ ListenSocket listenSocket;
+ int listenPort;
+
+ Selector selector;
+
+ bool exitRequest;
+
+ private:
+ /// unimplemented, objects of this type can't be copied
+ GenericServer(const GenericServer&);
+ /// unimplemented, objects of this type can't be copied
+ GenericServer& operator=(const GenericServer&);
+ };
+
+
+/** Base class for a simple blocking server, capable
+ of dealing with a single client. Don't use except for
+ very simple cases.
+ This version doesn't care much about errors
+*/
+class BlockingServer : public GenericServer
+ {
+ public:
+ /// Default constructor
+ BlockingServer() throw();
+ /// Destructor
+ ~BlockingServer() throw();
+
+ /** runs the server. Accepts only one connection
+ and blocks until the request is done
+ */
+ bool runServer() throw();
+ protected:
+ //************************************************
+ /** Pure function to process the request. It has to read,
+ process and write the answer, because afterwards
+ the socket is closed. Don't throw!
+ */
+ virtual void executeRequest(ServerSocket&) throw() =0;
+
+ /** Pure function to execute on timeout. Don't throw!
+ */
+ virtual void executeTimeout() throw() =0;
+ //************************************************
+ private:
+ ServerSocket serverSocket;
+
+ /// unimplemented, objects of this type can't be copied
+ BlockingServer(const BlockingServer&);
+ /// unimplemented, objects of this type can't be copied
+ BlockingServer& operator=(const BlockingServer&);
+ };
+
+
+} //namespace
+#endif
diff --git a/network/akgnet_socket.cc b/network/akgnet_socket.cc
new file mode 100644
index 0000000..91d7d6d
--- /dev/null
+++ b/network/akgnet_socket.cc
@@ -0,0 +1,174 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: akgnet_socket.cc
+ *
+ * MODULE: akg network
+ * CLASS: Socket, ListenSocket, ServerSocket, ClientSocket
+ *
+ * COMMENTS:
+ *
+ */
+
+#include <assert.h>
+#include <akgnet_socket.hh>
+
+akg::Socket::Socket() throw()
+ {
+ }
+
+bool akg::Socket::createTcpSocket() throw()
+ {
+ struct protoent *getprotoptr = getprotobyname("tcp");
+ fileDescriptor= socket(PF_INET,SOCK_STREAM,getprotoptr->p_proto);
+ if(fileDescriptor<0)
+ { saveErrno();return false;}
+ return true;
+ }
+
+akg::SocketAddress akg::Socket::getAddress() throw()
+ {
+ akgSocklen_t size = sizeof(sockaddr_in);
+ sockaddr_in buffer;
+
+ getsockname(fileDescriptor, (sockaddr*)&buffer,&size);
+
+ return SocketAddress(buffer);
+ }
+
+akg::SocketAddress akg::Socket::getPeerAddress() throw()
+ {
+ akgSocklen_t size = sizeof(sockaddr_in);
+ sockaddr_in buffer;
+
+ int rasp=getpeername(fileDescriptor, (sockaddr*)&buffer,&size);
+ saveErrno();
+ return rasp != -1 ? SocketAddress(buffer) : SocketAddress();
+ }
+
+//###########################################################
+
+akg::ListenSocket::ListenSocket() throw()
+ {
+ queuesize = SOMAXCONN;
+ }
+
+akg::ListenSocket::~ListenSocket() throw()
+ {
+ }
+
+bool akg::ListenSocket::open(int port) throw()
+ {
+ close();
+ if(createTcpSocket() == false) return false;
+
+ struct sockaddr_in internetAddress;
+ internetAddress.sin_family = AF_INET;
+ internetAddress.sin_port = htons(port);
+ internetAddress.sin_addr.s_addr= htonl(INADDR_ANY);
+
+#ifdef SO_REUSEADDR
+ int val = 1;
+ int len = sizeof( val );
+ if(setsockopt( fileDescriptor, SOL_SOCKET, SO_REUSEADDR, (char*)&val, len ))
+ {
+ DBTALK("Can't set address reusable: "<<strerror(errno));
+ }
+#endif
+
+ if(bind(fileDescriptor,(sockaddr*)&internetAddress,sizeof(sockaddr_in)) <0)
+ { saveErrno();return false;}
+
+ if(listen(fileDescriptor,queuesize) < 0)
+ { saveErrno();return false;}
+
+ return true;
+ }
+
+void akg::ListenSocket::setQueueSize(int newSize) throw()
+ {
+ assert(newSize > 0);
+ queuesize = newSize < SOMAXCONN ? newSize : SOMAXCONN;
+ }
+
+int akg::ListenSocket::getQueueSize() throw()
+ { return queuesize;
+ }
+
+
+//###########################################################
+akg::ServerSocket::ServerSocket() throw()
+ {
+ }
+
+akg::ServerSocket::~ServerSocket() throw()
+ {
+ }
+
+bool akg::ServerSocket::acceptFrom(ListenSocket& listenSocket) throw()
+ {
+ close();
+ struct sockaddr_in internetAddress;
+ akgSocklen_t size=sizeof(sockaddr_in);
+
+ savedErrno = 0;
+ fileDescriptor=accept(listenSocket(),(struct sockaddr*)&internetAddress,&size);
+ if(fileDescriptor < 0) { saveErrno();return false;}
+
+ return true;
+ }
+
+//###########################################################
+
+akg::ClientSocket::ClientSocket() throw()
+ {
+ }
+akg::ClientSocket::~ClientSocket() throw()
+ {
+ }
+
+bool akg::ClientSocket::open(const char *serverHost,int serverPort) throw()
+ {
+
+ close();
+ savedErrno=0;
+
+ if(createTcpSocket() == false) return false;
+
+ struct hostent *hostinfo=gethostbyname(serverHost);
+ if(hostinfo==NULL)
+ { saveErrno();return false;
+ }
+
+ sockaddr_in internetAddress;
+
+ internetAddress.sin_family = AF_INET;
+ internetAddress.sin_port = htons(serverPort);
+ internetAddress.sin_addr = *(struct in_addr*)hostinfo->h_addr;
+
+ if(connect(fileDescriptor,(struct sockaddr*)&internetAddress,sizeof(sockaddr_in)) < 0)
+ { saveErrno();return false;
+ }
+ return true;
+ }
+
diff --git a/network/akgnet_socket.hh b/network/akgnet_socket.hh
new file mode 100644
index 0000000..c17039d
--- /dev/null
+++ b/network/akgnet_socket.hh
@@ -0,0 +1,147 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: akgnet_socket.hh
+ *
+ * MODULE: akg network
+ * CLASS: Socket, ListenSocket, ServerSocket, ClientSocket
+ *
+ * COMMENTS:
+ * Namespace akg
+ *
+ */
+
+#ifndef AKGNET_SOCKET_HH
+#define AKGNET_SOCKET_HH
+
+#include "akgnet_fdescr.hh"
+#include "akgnet_inetaddr.hh"
+
+namespace akg
+ {
+
+/** This class represents the sockets in the file descriptor hierarchie.
+ Socket is the base class of the socket hierarchie, which contains also
+ ListenSocket, ServerSocket and ClientSocket
+*/
+
+class Socket : public FileDescriptor
+ {
+ public:
+ /// Default constructor
+ Socket() throw();
+
+ /// Returns the SocketAddress of this socket
+ SocketAddress getAddress() throw();
+
+ /** Returns the SocketAddress of the peer. If the Socket is not connected
+ returns the SocketAddress of this socket
+ */
+ SocketAddress getPeerAddress() throw();
+ protected:
+ /// helper function to initialize this Socket as a TCP/IP socket
+ bool createTcpSocket() throw();
+
+ private:
+ /// unimplemented, objects of this type can't be copied
+ Socket(const Socket&);
+ /// unimplemented, objects of this type can't be copied
+ Socket& operator=(const Socket&);
+ };
+
+/** ListenSocket - socket for servers, to listen for clients
+*/
+class ListenSocket : public Socket
+ {
+ public:
+ /// Default constructor
+ ListenSocket() throw();
+
+ /// Destructor, closes, indirectly, the socket
+ ~ListenSocket() throw();
+
+ /// Opens the listen socket. Returns true if succes
+ bool open(int port) throw();
+
+ /** Sets the OS queue size for this socket. Maximal size is SOMAXCONN
+ Assert: newSize > 0
+ */
+ void setQueueSize(int newSize) throw();
+
+ /// Returns the OS queue size for this socket
+ int getQueueSize() throw();
+
+ private:
+ int queuesize;
+
+ /// unimplemented, objects of this type can't be copied
+ ListenSocket(const ListenSocket&);
+ /// unimplemented, objects of this type can't be copied
+ ListenSocket& operator=(const ListenSocket&);
+ };
+
+/** ServerSocket - socket for servers, to communicate with clients
+ It opens by accepting a pending connection from a ListenSocket
+*/
+
+class ServerSocket : public Socket
+ {
+ public:
+ /// Default constructor
+ ServerSocket() throw();
+
+ /// Destructor
+ ~ServerSocket() throw();
+
+ /// Accepts a pending connection from a ListenSocket. Returns true on succes
+ bool acceptFrom(ListenSocket&) throw();
+ private:
+ /// unimplemented, objects of this type can't be copied
+ ServerSocket(const ServerSocket&);
+ /// unimplemented, objects of this type can't be copied
+ ServerSocket& operator=(const ServerSocket&);
+ };
+
+/** ClientSocket - socket for clients, to communicate with servers
+*/
+class ClientSocket : public Socket
+ {
+ public:
+ /// Default constructor
+ ClientSocket() throw();
+
+ /// Destructor
+ ~ClientSocket() throw();
+
+ /// Opens the connection with the given server. Returns true on succes
+ bool open(const char *serverHost,int serverPort) throw();
+ private:
+ /// unimplemented, objects of this type can't be copied
+ ClientSocket(const ClientSocket&);
+ /// unimplemented, objects of this type can't be copied
+ ClientSocket& operator=(const ClientSocket&);
+ };
+
+
+} // namespace
+#endif
diff --git a/network/akgnetwork.hh b/network/akgnetwork.hh
new file mode 100644
index 0000000..7a34444
--- /dev/null
+++ b/network/akgnetwork.hh
@@ -0,0 +1,56 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: akgnetwork.hh
+ *
+ * MODULE: akg network
+ * CLASS:
+ *
+ * COMMENTS:
+ * Namespace akg
+ * Include this file if you need services from the akgnetwork package
+ *
+ */
+
+#ifndef AKGNETWORK_HH
+#define AKGNETWORK_HH
+
+#include "akgnet_common.hh"
+
+#include "akgnet_fdescr.hh"
+
+#include "akgnet_file.hh"
+
+#include "akgnet_selector.hh"
+
+#include "akgnet_commbuffer.hh"
+
+#include "akgnet_socket.hh"
+
+#include "akgnet_server.hh"
+
+#include "akgnet_nbcomm.hh"
+
+#include "akgnet_inetaddr.hh"
+
+#endif
diff --git a/qlparser/Makefile.am b/qlparser/Makefile.am
new file mode 100644
index 0000000..7638cea
--- /dev/null
+++ b/qlparser/Makefile.am
@@ -0,0 +1,93 @@
+# -*-Makefile-*- (for Emacs)
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+#
+# MAKEFILE FOR:
+# module qlparser
+#
+#
+# COMMENTS:
+#
+#
+##################################################################
+
+noinst_LIBRARIES=libqlparser.a
+
+# -I gnererates an interactive scanner which doesn't try to look ahead past a newline
+# -i generates a scanner which doesn't care about upper and lower case; doesn't work
+AM_LFLAGS=-i -I
+
+YACC = bison
+# -d generates token definitions in .h file
+AM_YFLAGS=-d -y
+AM_CXXFLAGS=@BASEDBCXXFLAGS@
+AM_CFLAGS=$(CXXFLAGS)
+libqlparser_a_SOURCES=oql.yy lex.ll alloca.c\
+ symtab.cc symtab.hh \
+ qtoncstream.cc qtoncstream.hh qtoncstream.icc \
+ qtmddaccess.cc qtmddaccess.hh qtmddaccess.icc \
+ qtiterator.cc qtiterator.hh qtiterator.icc \
+ qtoperationiterator.cc qtoperationiterator.hh qtoperationiterator.icc \
+ qtselectioniterator.cc qtselectioniterator.hh qtselectioniterator.icc \
+ qtjoiniterator.cc qtjoiniterator.hh qtjoiniterator.icc \
+ qtoperation.cc qtoperation.hh qtoperation.icc \
+ qtbinaryoperation.cc qtbinaryoperation.hh qtbinaryoperation.icc \
+ qtbinaryinduce.cc qtbinaryinduce.hh qtbinaryinduce.icc \
+ qtbinaryinduce2.cc qtbinaryinduce2.hh qtbinaryinduce2.icc \
+ qtunaryoperation.cc qtunaryoperation.hh qtunaryoperation.icc \
+ qtunaryinduce.cc qtunaryinduce.hh qtunaryinduce.icc \
+ qtvariable.cc qtvariable.hh qtvariable.icc \
+ qtconst.cc qtconst.hh qtconst.icc \
+ qtdata.cc qtdata.hh qtdata.icc \
+ qtscalardata.cc qtscalardata.hh qtscalardata.icc \
+ qtatomicdata.cc qtatomicdata.hh qtatomicdata.icc \
+ qtcomplexdata.cc qtcomplexdata.hh qtcomplexdata.icc \
+ qtmdd.cc qtmdd.hh qtmdd.icc \
+ qtstringdata.cc qtstringdata.hh qtstringdata.icc \
+ qtcondense.cc qtcondense.hh qtcondense.icc \
+ parseinfo.cc parseinfo.hh parseinfo.icc \
+ qtdomainoperation.cc qtdomainoperation.hh qtdomainoperation.icc \
+ qtconversion.cc qtconversion.hh qtconversion.icc\
+ qtupdate.cc qtupdate.hh qtupdate.icc \
+ qtinsert.cc qtinsert.hh qtinsert.icc \
+ qtdelete.cc qtdelete.hh \
+ qtcommand.cc qtcommand.hh qtcommand.icc \
+ qtoid.cc qtoid.hh qtoid.icc\
+ qtintervalop.cc qtintervalop.hh qtintervalop.icc \
+ qtmintervalop.cc qtmintervalop.hh qtmintervalop.icc \
+ qtintervaldata.cc qtintervaldata.hh qtintervaldata.icc \
+ qtpointop.cc qtpointop.hh qtpointop.icc \
+ qtmintervaldata.cc qtmintervaldata.hh qtmintervaldata.icc \
+ qtpointdata.cc qtpointdata.hh qtpointdata.icc \
+ qtnaryoperation.cc qtnaryoperation.hh qtnaryoperation.icc \
+ qtunaryfunc.cc qtunaryfunc.hh qtunaryfunc.icc \
+ qtbinaryfunc.cc qtbinaryfunc.hh qtbinaryfunc.icc \
+ qtmarrayop.cc qtmarrayop.hh qtmarrayop.icc \
+ qtmarrayop2.cc qtmarrayop2.hh qtmarrayop2.icc \
+ qtcondenseop.cc qtcondenseop.hh qtcondenseop.icc \
+ qtnode.cc qtnode.hh qtnode.icc \
+ querytree.cc querytree.hh querytree.icc \
+ qtexecute.hh qtdelete.icc
+EXTRA_libqlparser_a_SOURCES = autogen_qtui.hh autogen_qtui.icc autogen_qtui.cc
+
+BUILT_SOURCES=lex.cc oql.cc oql.h
+CLEANFILES=lex.cc oql.cc oql.h
diff --git a/qlparser/alloca.c b/qlparser/alloca.c
new file mode 100644
index 0000000..d9a7ba2
--- /dev/null
+++ b/qlparser/alloca.c
@@ -0,0 +1,531 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include "mymalloc/mymalloc.h"
+/* alloca.c -- allocate automatically reclaimed memory
+ (Mostly) portable public-domain implementation -- D A Gwyn
+
+ This implementation of the PWB library alloca function,
+ which is used to allocate space off the run-time stack so
+ that it is automatically reclaimed upon procedure exit,
+ was inspired by discussions with J. Q. Johnson of Cornell.
+ J.Otto Tennant <jot@cray.com> contributed the Cray support.
+
+ There are some preprocessor constants that can
+ be defined when compiling for your specific system, for
+ improved efficiency; however, the defaults should be okay.
+
+ The general concept of this implementation is to keep
+ track of all alloca-allocated blocks, and reclaim any
+ that are found to be deeper in the stack than the current
+ invocation. This heuristic does not reclaim storage as
+ soon as it becomes invalid, but it will do so eventually.
+
+ As a special case, alloca(0) reclaims storage without
+ allocating any. It is a good idea to use alloca(0) in
+ your main control loop, etc. to force garbage collection. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#ifdef emacs
+#include "blockinput.h"
+#endif
+
+/* If compiling with GCC 2, this file's not needed. */
+#if !defined (__GNUC__) || __GNUC__ < 2
+#ifndef SOLARIS
+
+/* If someone has defined alloca as a macro,
+ there must be some other way alloca is supposed to work. */
+#ifndef alloca
+
+#ifdef emacs
+#ifdef static
+/* actually, only want this if static is defined as ""
+ -- this is for usg, in which emacs must undefine static
+ in order to make unexec workable
+ */
+#ifndef STACK_DIRECTION
+you
+lose
+-- must know STACK_DIRECTION at compile-time
+#endif /* STACK_DIRECTION undefined */
+#endif /* static */
+#endif /* emacs */
+
+/* If your stack is a linked list of frames, you have to
+ provide an "address metric" ADDRESS_FUNCTION macro. */
+
+#if defined (CRAY) && defined (CRAY_STACKSEG_END)
+long i00afunc ();
+#define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg))
+#else
+#define ADDRESS_FUNCTION(arg) &(arg)
+#endif
+
+#if __STDC__
+typedef void *pointer;
+#else
+typedef char *pointer;
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+/* Different portions of Emacs need to call different versions of
+ malloc. The Emacs executable needs alloca to call xmalloc, because
+ ordinary malloc isn't protected from input signals. On the other
+ hand, the utilities in lib-src need alloca to call malloc; some of
+ them are very simple, and don't have an xmalloc routine.
+
+ Non-Emacs programs expect this to call use xmalloc.
+
+ Callers below should use malloc. */
+
+/*
+#ifndef emacs
+#define malloc xmalloc
+#endif
+*/
+extern pointer mymalloc ();
+
+/* Define STACK_DIRECTION if you know the direction of stack
+ growth for your system; otherwise it will be automatically
+ deduced at run-time.
+
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown */
+
+#ifndef STACK_DIRECTION
+#define STACK_DIRECTION 0 /* Direction unknown. */
+#endif
+
+#if STACK_DIRECTION != 0
+
+#define STACK_DIR STACK_DIRECTION /* Known at compile-time. */
+
+#else /* STACK_DIRECTION == 0; need run-time code. */
+
+static int stack_dir; /* 1 or -1 once known. */
+#define STACK_DIR stack_dir
+
+static void
+find_stack_direction ()
+{
+ static char *addr = NULL; /* Address of first `dummy', once known. */
+ auto char dummy; /* To get stack address. */
+
+ if (addr == NULL)
+ { /* Initial entry. */
+ addr = ADDRESS_FUNCTION (dummy);
+
+ find_stack_direction (); /* Recurse once. */
+ }
+ else
+ {
+ /* Second entry. */
+ if (ADDRESS_FUNCTION (dummy) > addr)
+ stack_dir = 1; /* Stack grew upward. */
+ else
+ stack_dir = -1; /* Stack grew downward. */
+ }
+}
+
+#endif /* STACK_DIRECTION == 0 */
+
+/* An "alloca header" is used to:
+ (a) chain together all alloca'ed blocks;
+ (b) keep track of stack depth.
+
+ It is very important that sizeof(header) agree with malloc
+ alignment chunk size. The following default should work okay. */
+
+#ifndef ALIGN_SIZE
+#define ALIGN_SIZE sizeof(double)
+#endif
+
+typedef union hdr
+{
+ char align[ALIGN_SIZE]; /* To force sizeof(header). */
+ struct
+ {
+ union hdr *next; /* For chaining headers. */
+ char *deep; /* For stack depth measure. */
+ } h;
+} header;
+
+static header *last_alloca_header = NULL; /* -> last alloca header. */
+
+/* Return a pointer to at least SIZE bytes of storage,
+ which will be automatically reclaimed upon exit from
+ the procedure that called alloca. Originally, this space
+ was supposed to be taken from the current stack frame of the
+ caller, but that method cannot be made to work for some
+ implementations of C, for example under Gould's UTX/32. */
+
+pointer
+alloca (size)
+ unsigned size;
+{
+ auto char probe; /* Probes stack depth: */
+ register char *depth = ADDRESS_FUNCTION (probe);
+
+#if STACK_DIRECTION == 0
+ if (STACK_DIR == 0) /* Unknown growth direction. */
+ find_stack_direction ();
+#endif
+
+ /* Reclaim garbage, defined as all alloca'd storage that
+ was allocated from deeper in the stack than currently. */
+
+ {
+ register header *hp; /* Traverses linked list. */
+
+#ifdef emacs
+ BLOCK_INPUT;
+#endif
+
+ for (hp = last_alloca_header; hp != NULL;)
+ if ((STACK_DIR > 0 && hp->h.deep > depth)
+ || (STACK_DIR < 0 && hp->h.deep < depth))
+ {
+ register header *np = hp->h.next;
+
+ free ((pointer) hp); /* Collect garbage. */
+
+ hp = np; /* -> next header. */
+ }
+ else
+ break; /* Rest are not deeper. */
+
+ last_alloca_header = hp; /* -> last valid storage. */
+
+#ifdef emacs
+ UNBLOCK_INPUT;
+#endif
+ }
+
+ if (size == 0)
+ return NULL; /* No allocation required. */
+
+ /* Allocate combined header + user data storage. */
+
+ {
+ register pointer new = mymalloc (sizeof (header) + size);
+ /* Address of header. */
+
+ if (new == 0)
+ abort();
+
+ ((header *) new)->h.next = last_alloca_header;
+ ((header *) new)->h.deep = depth;
+
+ last_alloca_header = (header *) new;
+
+ /* User storage begins just after header. */
+
+ return (pointer) ((char *) new + sizeof (header));
+ }
+}
+
+#if defined (CRAY) && defined (CRAY_STACKSEG_END)
+
+#ifdef DEBUG_I00AFUNC
+#include <stdio.h>
+#endif
+
+#ifndef CRAY_STACK
+#define CRAY_STACK
+#ifndef CRAY2
+/* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */
+struct stack_control_header
+ {
+ long shgrow:32; /* Number of times stack has grown. */
+ long shaseg:32; /* Size of increments to stack. */
+ long shhwm:32; /* High water mark of stack. */
+ long shsize:32; /* Current size of stack (all segments). */
+ };
+
+/* The stack segment linkage control information occurs at
+ the high-address end of a stack segment. (The stack
+ grows from low addresses to high addresses.) The initial
+ part of the stack segment linkage control information is
+ 0200 (octal) words. This provides for register storage
+ for the routine which overflows the stack. */
+
+struct stack_segment_linkage
+ {
+ long ss[0200]; /* 0200 overflow words. */
+ long sssize:32; /* Number of words in this segment. */
+ long ssbase:32; /* Offset to stack base. */
+ long:32;
+ long sspseg:32; /* Offset to linkage control of previous
+ segment of stack. */
+ long:32;
+ long sstcpt:32; /* Pointer to task common address block. */
+ long sscsnm; /* Private control structure number for
+ microtasking. */
+ long ssusr1; /* Reserved for user. */
+ long ssusr2; /* Reserved for user. */
+ long sstpid; /* Process ID for pid based multi-tasking. */
+ long ssgvup; /* Pointer to multitasking thread giveup. */
+ long sscray[7]; /* Reserved for Cray Research. */
+ long ssa0;
+ long ssa1;
+ long ssa2;
+ long ssa3;
+ long ssa4;
+ long ssa5;
+ long ssa6;
+ long ssa7;
+ long sss0;
+ long sss1;
+ long sss2;
+ long sss3;
+ long sss4;
+ long sss5;
+ long sss6;
+ long sss7;
+ };
+
+#else /* CRAY2 */
+/* The following structure defines the vector of words
+ returned by the STKSTAT library routine. */
+struct stk_stat
+ {
+ long now; /* Current total stack size. */
+ long maxc; /* Amount of contiguous space which would
+ be required to satisfy the maximum
+ stack demand to date. */
+ long high_water; /* Stack high-water mark. */
+ long overflows; /* Number of stack overflow ($STKOFEN) calls. */
+ long hits; /* Number of internal buffer hits. */
+ long extends; /* Number of block extensions. */
+ long stko_mallocs; /* Block allocations by $STKOFEN. */
+ long underflows; /* Number of stack underflow calls ($STKRETN). */
+ long stko_free; /* Number of deallocations by $STKRETN. */
+ long stkm_free; /* Number of deallocations by $STKMRET. */
+ long segments; /* Current number of stack segments. */
+ long maxs; /* Maximum number of stack segments so far. */
+ long pad_size; /* Stack pad size. */
+ long current_address; /* Current stack segment address. */
+ long current_size; /* Current stack segment size. This
+ number is actually corrupted by STKSTAT to
+ include the fifteen word trailer area. */
+ long initial_address; /* Address of initial segment. */
+ long initial_size; /* Size of initial segment. */
+ };
+
+/* The following structure describes the data structure which trails
+ any stack segment. I think that the description in 'asdef' is
+ out of date. I only describe the parts that I am sure about. */
+
+struct stk_trailer
+ {
+ long this_address; /* Address of this block. */
+ long this_size; /* Size of this block (does not include
+ this trailer). */
+ long unknown2;
+ long unknown3;
+ long link; /* Address of trailer block of previous
+ segment. */
+ long unknown5;
+ long unknown6;
+ long unknown7;
+ long unknown8;
+ long unknown9;
+ long unknown10;
+ long unknown11;
+ long unknown12;
+ long unknown13;
+ long unknown14;
+ };
+
+#endif /* CRAY2 */
+#endif /* not CRAY_STACK */
+
+#ifdef CRAY2
+/* Determine a "stack measure" for an arbitrary ADDRESS.
+ I doubt that "lint" will like this much. */
+
+static long
+i00afunc (long *address)
+{
+ struct stk_stat status;
+ struct stk_trailer *trailer;
+ long *block, size;
+ long result = 0;
+
+ /* We want to iterate through all of the segments. The first
+ step is to get the stack status structure. We could do this
+ more quickly and more directly, perhaps, by referencing the
+ $LM00 common block, but I know that this works. */
+
+ STKSTAT (&status);
+
+ /* Set up the iteration. */
+
+ trailer = (struct stk_trailer *) (status.current_address
+ + status.current_size
+ - 15);
+
+ /* There must be at least one stack segment. Therefore it is
+ a fatal error if "trailer" is null. */
+
+ if (trailer == 0)
+ abort ();
+
+ /* Discard segments that do not contain our argument address. */
+
+ while (trailer != 0)
+ {
+ block = (long *) trailer->this_address;
+ size = trailer->this_size;
+ if (block == 0 || size == 0)
+ abort ();
+ trailer = (struct stk_trailer *) trailer->link;
+ if ((block <= address) && (address < (block + size)))
+ break;
+ }
+
+ /* Set the result to the offset in this segment and add the sizes
+ of all predecessor segments. */
+
+ result = address - block;
+
+ if (trailer == 0)
+ {
+ return result;
+ }
+
+ do
+ {
+ if (trailer->this_size <= 0)
+ abort ();
+ result += trailer->this_size;
+ trailer = (struct stk_trailer *) trailer->link;
+ }
+ while (trailer != 0);
+
+ /* We are done. Note that if you present a bogus address (one
+ not in any segment), you will get a different number back, formed
+ from subtracting the address of the first block. This is probably
+ not what you want. */
+
+ return (result);
+}
+
+#else /* not CRAY2 */
+/* Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP.
+ Determine the number of the cell within the stack,
+ given the address of the cell. The purpose of this
+ routine is to linearize, in some sense, stack addresses
+ for alloca. */
+
+static long
+i00afunc (long address)
+{
+ long stkl = 0;
+
+ long size, pseg, this_segment, stack;
+ long result = 0;
+
+ struct stack_segment_linkage *ssptr;
+
+ /* Register B67 contains the address of the end of the
+ current stack segment. If you (as a subprogram) store
+ your registers on the stack and find that you are past
+ the contents of B67, you have overflowed the segment.
+
+ B67 also points to the stack segment linkage control
+ area, which is what we are really interested in. */
+
+ stkl = CRAY_STACKSEG_END ();
+ ssptr = (struct stack_segment_linkage *) stkl;
+
+ /* If one subtracts 'size' from the end of the segment,
+ one has the address of the first word of the segment.
+
+ If this is not the first segment, 'pseg' will be
+ nonzero. */
+
+ pseg = ssptr->sspseg;
+ size = ssptr->sssize;
+
+ this_segment = stkl - size;
+
+ /* It is possible that calling this routine itself caused
+ a stack overflow. Discard stack segments which do not
+ contain the target address. */
+
+ while (!(this_segment <= address && address <= stkl))
+ {
+#ifdef DEBUG_I00AFUNC
+ fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl);
+#endif
+ if (pseg == 0)
+ break;
+ stkl = stkl - pseg;
+ ssptr = (struct stack_segment_linkage *) stkl;
+ size = ssptr->sssize;
+ pseg = ssptr->sspseg;
+ this_segment = stkl - size;
+ }
+
+ result = address - this_segment;
+
+ /* If you subtract pseg from the current end of the stack,
+ you get the address of the previous stack segment's end.
+ This seems a little convoluted to me, but I'll bet you save
+ a cycle somewhere. */
+
+ while (pseg != 0)
+ {
+#ifdef DEBUG_I00AFUNC
+ fprintf (stderr, "%011o %011o\n", pseg, size);
+#endif
+ stkl = stkl - pseg;
+ ssptr = (struct stack_segment_linkage *) stkl;
+ size = ssptr->sssize;
+ pseg = ssptr->sspseg;
+ result += size;
+ }
+ return (result);
+}
+
+#endif /* not CRAY2 */
+#endif /* CRAY */
+
+#endif /* no alloca */
+#endif /* no solaris */
+#endif /* not GCC version 2 */
diff --git a/qlparser/autogen_qtui.cc b/qlparser/autogen_qtui.cc
new file mode 100644
index 0000000..408fed3
--- /dev/null
+++ b/qlparser/autogen_qtui.cc
@@ -0,0 +1,1151 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS: Automaticaly generated
+ *
+ ************************************************************/
+
+
+const QtNode::QtNodeType QtAbs::nodeType = QtNode::QT_ABS;
+
+QtAbs::QtAbs(QtOperation* initInput): QtUnaryInduce(initInput) {}
+QtData* QtAbs::evaluate(QtDataList* inputList) {
+ QtData* returnValue = NULL;
+ QtData* operand = NULL;
+
+ if(getOperand(inputList, operand)) {
+ try {
+ returnValue = computeOp( operand, Ops::OP_ABS );
+ }
+ catch(...) {
+ operand->deleteRef();
+ throw;
+ }
+ }
+ // delete old operand
+ if(operand) operand->deleteRef();
+ return returnValue;
+}
+
+void QtAbs::printTree(int tab, ostream& s, QtChildType mode) {
+ s << SPACE_STR(tab).c_str() << "QtAbsObject " << getNodeType() << endl;
+ QtUnaryInduce::printTree( tab + 2, s, mode );
+}
+
+void QtAbs::printAlgebraicExpression(ostream& s) {
+ s << "abs(";
+ if(input)
+ input->printAlgebraicExpression(s);
+ else
+ s << "<nn>";
+ s << ")";
+}
+
+const QtTypeElement& QtAbs::checkType(QtTypeTuple* typeTuple) {
+ RMDBCLASS( "QtAbs", "checkType( QtTypeTuple* )", "qlparser", __FILE__, __LINE__ )
+ dataStreamType.setDataType( QT_TYPE_UNKNOWN );
+ // check operand branches
+ if(input) {
+ // get input types
+ const QtTypeElement& inputType = input->checkType( typeTuple );
+ RMDBGIF( 4, RMDebug::module_qlparser, "AutoGen", \
+ RMInit::dbgOut << "Operand: " << flush; \
+ inputType.printStatus( RMInit::dbgOut ); \
+ RMInit::dbgOut << endl; \
+ )
+ if(inputType.getDataType() == QT_MDD) {
+ const BaseType* baseType = ((MDDBaseType*)(inputType.getType()))->getBaseType();
+ BaseType* resultBaseType = (BaseType*)(Ops::getResultType( Ops::OP_ABS, baseType ));
+ if(!resultBaseType) {
+ RMInit::logOut << "Error: QtAbs::checkType() - induce operand type is not support" << endl;
+ parseInfo.setErrorNo(366);
+ throw parseInfo;
+ }
+ MDDBaseType* resultMDDType = new MDDBaseType( "tmp", resultBaseType );
+ TypeFactory::addTempType( resultMDDType );
+ dataStreamType.setType( resultMDDType );
+ }
+ else if(inputType.isBaseType()) {
+ BaseType* baseType = (BaseType*)(inputType.getType());
+ BaseType* resultBaseType = (BaseType*)(Ops::getResultType( Ops::OP_ABS, baseType ));
+ if(!resultBaseType) {
+ RMInit::logOut << "Error: QtAbs::checkType() - operand type is not supported." << endl;
+ parseInfo.setErrorNo(367);
+ throw parseInfo;
+ }
+ dataStreamType.setType( resultBaseType );
+ }
+ else {
+ RMInit::logOut << "Error: QtAbs::checkType() - operation is not supported for strings." << endl;
+ parseInfo.setErrorNo(385);
+ throw parseInfo;
+ }
+ }
+ else
+ RMInit::logOut << "Error: QtAbs::checkType() - operand branch invalid." << endl;
+
+ return dataStreamType;
+}
+
+const QtNode::QtNodeType QtSqrt::nodeType = QtNode::QT_SQRT;
+
+QtSqrt::QtSqrt(QtOperation* initInput): QtUnaryInduce(initInput) {}
+QtData* QtSqrt::evaluate(QtDataList* inputList) {
+ QtData* returnValue = NULL;
+ QtData* operand = NULL;
+
+ if(getOperand(inputList, operand)) {
+ try {
+ returnValue = computeOp( operand, Ops::OP_SQRT );
+ }
+ catch(...) {
+ operand->deleteRef();
+ throw;
+ }
+ }
+ // delete old operand
+ if(operand) operand->deleteRef();
+ return returnValue;
+}
+
+void QtSqrt::printTree(int tab, ostream& s, QtChildType mode) {
+ s << SPACE_STR(tab).c_str() << "QtSqrtObject " << getNodeType() << endl;
+ QtUnaryInduce::printTree( tab + 2, s, mode );
+}
+void QtSqrt::printAlgebraicExpression(ostream& s) {
+ s << "sqrt(";
+ if(input)
+ input->printAlgebraicExpression(s);
+ else
+ s << "<nn>";
+ s << ")";
+}
+
+const QtTypeElement& QtSqrt::checkType(QtTypeTuple* typeTuple) {
+ RMDBCLASS( "QtSqrt", "checkType( QtTypeTuple* )", "qlparser", __FILE__, __LINE__ )
+ dataStreamType.setDataType( QT_TYPE_UNKNOWN );
+ // check operand branches
+ if(input) {
+ // get input types
+ const QtTypeElement& inputType = input->checkType( typeTuple );
+ RMDBGIF( 4, RMDebug::module_qlparser, "AutoGen", \
+ RMInit::dbgOut << "Operand: " << flush; \
+ inputType.printStatus( RMInit::dbgOut ); \
+ RMInit::dbgOut << endl; \
+ )
+ if(inputType.getDataType() == QT_MDD) {
+ const BaseType* baseType = ((MDDBaseType*)(inputType.getType()))->getBaseType();
+ BaseType* resultBaseType = (BaseType*)(Ops::getResultType( Ops::OP_SQRT, baseType ));
+ if(!resultBaseType) {
+ RMInit::logOut << "Error: QtSqrt::checkType() - induce operand type is not support" << endl;
+ parseInfo.setErrorNo(366);
+ throw parseInfo;
+ }
+ MDDBaseType* resultMDDType = new MDDBaseType( "tmp", resultBaseType );
+ TypeFactory::addTempType( resultMDDType );
+ dataStreamType.setType( resultMDDType );
+ }
+ else if(inputType.isBaseType()) {
+ BaseType* baseType = (BaseType*)(inputType.getType());
+ BaseType* resultBaseType = (BaseType*)(Ops::getResultType( Ops::OP_SQRT, baseType ));
+ if(!resultBaseType) {
+ RMInit::logOut << "Error: QtSqrt::checkType() - operand type is not supported." << endl;
+ parseInfo.setErrorNo(367);
+ throw parseInfo;
+ }
+ dataStreamType.setType( resultBaseType );
+ }
+ else {
+ RMInit::logOut << "Error: QtSqrt::checkType() - operation is not supported for strings." << endl;
+ parseInfo.setErrorNo(385);
+ throw parseInfo;
+ }
+ }
+ else
+ RMInit::logOut << "Error: QtSqrt::checkType() - operand branch invalid." << endl;
+
+ return dataStreamType;
+}
+
+const QtNode::QtNodeType QtExp::nodeType = QtNode::QT_EXP;
+
+QtExp::QtExp(QtOperation* initInput): QtUnaryInduce(initInput) {}
+QtData* QtExp::evaluate(QtDataList* inputList) {
+ QtData* returnValue = NULL;
+ QtData* operand = NULL;
+
+ if(getOperand(inputList, operand)) {
+ try {
+ returnValue = computeOp( operand, Ops::OP_EXP );
+ }
+ catch(...) {
+ operand->deleteRef();
+ throw;
+ }
+ }
+ // delete old operand
+ if(operand) operand->deleteRef();
+ return returnValue;
+}
+
+void QtExp::printTree(int tab, ostream& s, QtChildType mode) {
+ s << SPACE_STR(tab).c_str() << "QtExpObject " << getNodeType() << endl;
+ QtUnaryInduce::printTree( tab + 2, s, mode );
+}
+void QtExp::printAlgebraicExpression(ostream& s) {
+ s << "exp(";
+ if(input)
+ input->printAlgebraicExpression(s);
+ else
+ s << "<nn>";
+ s << ")";
+}
+
+const QtTypeElement& QtExp::checkType(QtTypeTuple* typeTuple) {
+ RMDBCLASS( "QtExp", "checkType( QtTypeTuple* )", "qlparser", __FILE__, __LINE__ )
+ dataStreamType.setDataType( QT_TYPE_UNKNOWN );
+ // check operand branches
+ if(input) {
+ // get input types
+ const QtTypeElement& inputType = input->checkType( typeTuple );
+ RMDBGIF( 4, RMDebug::module_qlparser, "AutoGen", \
+ RMInit::dbgOut << "Operand: " << flush; \
+ inputType.printStatus( RMInit::dbgOut ); \
+ RMInit::dbgOut << endl; \
+ )
+ if(inputType.getDataType() == QT_MDD) {
+ const BaseType* baseType = ((MDDBaseType*)(inputType.getType()))->getBaseType();
+ BaseType* resultBaseType = (BaseType*)(Ops::getResultType( Ops::OP_EXP, baseType ));
+ if(!resultBaseType) {
+ RMInit::logOut << "Error: QtExp::checkType() - induce operand type is not support" << endl;
+ parseInfo.setErrorNo(366);
+ throw parseInfo;
+ }
+ MDDBaseType* resultMDDType = new MDDBaseType( "tmp", resultBaseType );
+ TypeFactory::addTempType( resultMDDType );
+ dataStreamType.setType( resultMDDType );
+ }
+ else if(inputType.isBaseType()) {
+ BaseType* baseType = (BaseType*)(inputType.getType());
+ BaseType* resultBaseType = (BaseType*)(Ops::getResultType( Ops::OP_EXP, baseType ));
+ if(!resultBaseType) {
+ RMInit::logOut << "Error: QtExp::checkType() - operand type is not supported." << endl;
+ parseInfo.setErrorNo(367);
+ throw parseInfo;
+ }
+ dataStreamType.setType( resultBaseType );
+ }
+ else {
+ RMInit::logOut << "Error: QtExp::checkType() - operation is not supported for strings." << endl;
+ parseInfo.setErrorNo(385);
+ throw parseInfo;
+ }
+ }
+ else
+ RMInit::logOut << "Error: QtExp::checkType() - operand branch invalid." << endl;
+
+ return dataStreamType;
+}
+
+const QtNode::QtNodeType QtLog::nodeType = QtNode::QT_LOG;
+
+QtLog::QtLog(QtOperation* initInput): QtUnaryInduce(initInput) {}
+QtData* QtLog::evaluate(QtDataList* inputList) {
+ QtData* returnValue = NULL;
+ QtData* operand = NULL;
+
+ if(getOperand(inputList, operand)) {
+ try {
+ returnValue = computeOp( operand, Ops::OP_LOG );
+ }
+ catch(...) {
+ operand->deleteRef();
+ throw;
+ }
+ }
+ // delete old operand
+ if(operand) operand->deleteRef();
+ return returnValue;
+}
+
+void QtLog::printTree(int tab, ostream& s, QtChildType mode) {
+ s << SPACE_STR(tab).c_str() << "QtLogObject " << getNodeType() << endl;
+ QtUnaryInduce::printTree( tab + 2, s, mode );
+}
+void QtLog::printAlgebraicExpression(ostream& s) {
+ s << "log(";
+ if(input)
+ input->printAlgebraicExpression(s);
+ else
+ s << "<nn>";
+ s << ")";
+}
+
+const QtTypeElement& QtLog::checkType(QtTypeTuple* typeTuple) {
+ RMDBCLASS( "QtLog", "checkType( QtTypeTuple* )", "qlparser", __FILE__, __LINE__ )
+ dataStreamType.setDataType( QT_TYPE_UNKNOWN );
+ // check operand branches
+ if(input) {
+ // get input types
+ const QtTypeElement& inputType = input->checkType( typeTuple );
+ RMDBGIF( 4, RMDebug::module_qlparser, "AutoGen", \
+ RMInit::dbgOut << "Operand: " << flush; \
+ inputType.printStatus( RMInit::dbgOut ); \
+ RMInit::dbgOut << endl; \
+ )
+ if(inputType.getDataType() == QT_MDD) {
+ const BaseType* baseType = ((MDDBaseType*)(inputType.getType()))->getBaseType();
+ BaseType* resultBaseType = (BaseType*)(Ops::getResultType( Ops::OP_LOG, baseType ));
+ if(!resultBaseType) {
+ RMInit::logOut << "Error: QtLog::checkType() - induce operand type is not support" << endl;
+ parseInfo.setErrorNo(366);
+ throw parseInfo;
+ }
+ MDDBaseType* resultMDDType = new MDDBaseType( "tmp", resultBaseType );
+ TypeFactory::addTempType( resultMDDType );
+ dataStreamType.setType( resultMDDType );
+ }
+ else if(inputType.isBaseType()) {
+ BaseType* baseType = (BaseType*)(inputType.getType());
+ BaseType* resultBaseType = (BaseType*)(Ops::getResultType( Ops::OP_LOG, baseType ));
+ if(!resultBaseType) {
+ RMInit::logOut << "Error: QtLog::checkType() - operand type is not supported." << endl;
+ parseInfo.setErrorNo(367);
+ throw parseInfo;
+ }
+ dataStreamType.setType( resultBaseType );
+ }
+ else {
+ RMInit::logOut << "Error: QtLog::checkType() - operation is not supported for strings." << endl;
+ parseInfo.setErrorNo(385);
+ throw parseInfo;
+ }
+ }
+ else
+ RMInit::logOut << "Error: QtLog::checkType() - operand branch invalid." << endl;
+
+ return dataStreamType;
+}
+
+const QtNode::QtNodeType QtLn::nodeType = QtNode::QT_LN;
+
+QtLn::QtLn(QtOperation* initInput): QtUnaryInduce(initInput) {}
+QtData* QtLn::evaluate(QtDataList* inputList) {
+ QtData* returnValue = NULL;
+ QtData* operand = NULL;
+
+ if(getOperand(inputList, operand)) {
+ try {
+ returnValue = computeOp( operand, Ops::OP_LN );
+ }
+ catch(...) {
+ operand->deleteRef();
+ throw;
+ }
+ }
+ // delete old operand
+ if(operand) operand->deleteRef();
+ return returnValue;
+}
+
+void QtLn::printTree(int tab, ostream& s, QtChildType mode) {
+ s << SPACE_STR(tab).c_str() << "QtLnObject " << getNodeType() << endl;
+ QtUnaryInduce::printTree( tab + 2, s, mode );
+}
+void QtLn::printAlgebraicExpression(ostream& s) {
+ s << "ln(";
+ if(input)
+ input->printAlgebraicExpression(s);
+ else
+ s << "<nn>";
+ s << ")";
+}
+
+const QtTypeElement& QtLn::checkType(QtTypeTuple* typeTuple) {
+ RMDBCLASS( "QtLn", "checkType( QtTypeTuple* )", "qlparser", __FILE__, __LINE__ )
+ dataStreamType.setDataType( QT_TYPE_UNKNOWN );
+ // check operand branches
+ if(input) {
+ // get input types
+ const QtTypeElement& inputType = input->checkType( typeTuple );
+ RMDBGIF( 4, RMDebug::module_qlparser, "AutoGen", \
+ RMInit::dbgOut << "Operand: " << flush; \
+ inputType.printStatus( RMInit::dbgOut ); \
+ RMInit::dbgOut << endl; \
+ )
+ if(inputType.getDataType() == QT_MDD) {
+ const BaseType* baseType = ((MDDBaseType*)(inputType.getType()))->getBaseType();
+ BaseType* resultBaseType = (BaseType*)(Ops::getResultType( Ops::OP_LN, baseType ));
+ if(!resultBaseType) {
+ RMInit::logOut << "Error: QtLn::checkType() - induce operand type is not support" << endl;
+ parseInfo.setErrorNo(366);
+ throw parseInfo;
+ }
+ MDDBaseType* resultMDDType = new MDDBaseType( "tmp", resultBaseType );
+ TypeFactory::addTempType( resultMDDType );
+ dataStreamType.setType( resultMDDType );
+ }
+ else if(inputType.isBaseType()) {
+ BaseType* baseType = (BaseType*)(inputType.getType());
+ BaseType* resultBaseType = (BaseType*)(Ops::getResultType( Ops::OP_LN, baseType ));
+ if(!resultBaseType) {
+ RMInit::logOut << "Error: QtLn::checkType() - operand type is not supported." << endl;
+ parseInfo.setErrorNo(367);
+ throw parseInfo;
+ }
+ dataStreamType.setType( resultBaseType );
+ }
+ else {
+ RMInit::logOut << "Error: QtLn::checkType() - operation is not supported for strings." << endl;
+ parseInfo.setErrorNo(385);
+ throw parseInfo;
+ }
+ }
+ else
+ RMInit::logOut << "Error: QtLn::checkType() - operand branch invalid." << endl;
+
+ return dataStreamType;
+}
+
+const QtNode::QtNodeType QtSin::nodeType = QtNode::QT_SIN;
+
+QtSin::QtSin(QtOperation* initInput): QtUnaryInduce(initInput) {}
+QtData* QtSin::evaluate(QtDataList* inputList) {
+ QtData* returnValue = NULL;
+ QtData* operand = NULL;
+
+ if(getOperand(inputList, operand)) {
+ try {
+ returnValue = computeOp( operand, Ops::OP_SIN );
+ }
+ catch(...) {
+ operand->deleteRef();
+ throw;
+ }
+ }
+ // delete old operand
+ if(operand) operand->deleteRef();
+ return returnValue;
+}
+
+void QtSin::printTree(int tab, ostream& s, QtChildType mode) {
+ s << SPACE_STR(tab).c_str() << "QtSinObject " << getNodeType() << endl;
+ QtUnaryInduce::printTree( tab + 2, s, mode );
+}
+void QtSin::printAlgebraicExpression(ostream& s) {
+ s << "sin(";
+ if(input)
+ input->printAlgebraicExpression(s);
+ else
+ s << "<nn>";
+ s << ")";
+}
+
+const QtTypeElement& QtSin::checkType(QtTypeTuple* typeTuple) {
+ RMDBCLASS( "QtSin", "checkType( QtTypeTuple* )", "qlparser", __FILE__, __LINE__ )
+ dataStreamType.setDataType( QT_TYPE_UNKNOWN );
+ // check operand branches
+ if(input) {
+ // get input types
+ const QtTypeElement& inputType = input->checkType( typeTuple );
+ RMDBGIF( 4, RMDebug::module_qlparser, "AutoGen", \
+ RMInit::dbgOut << "Operand: " << flush; \
+ inputType.printStatus( RMInit::dbgOut ); \
+ RMInit::dbgOut << endl; \
+ )
+ if(inputType.getDataType() == QT_MDD) {
+ const BaseType* baseType = ((MDDBaseType*)(inputType.getType()))->getBaseType();
+ BaseType* resultBaseType = (BaseType*)(Ops::getResultType( Ops::OP_SIN, baseType ));
+ if(!resultBaseType) {
+ RMInit::logOut << "Error: QtSin::checkType() - induce operand type is not support" << endl;
+ parseInfo.setErrorNo(366);
+ throw parseInfo;
+ }
+ MDDBaseType* resultMDDType = new MDDBaseType( "tmp", resultBaseType );
+ TypeFactory::addTempType( resultMDDType );
+ dataStreamType.setType( resultMDDType );
+ }
+ else if(inputType.isBaseType()) {
+ BaseType* baseType = (BaseType*)(inputType.getType());
+ BaseType* resultBaseType = (BaseType*)(Ops::getResultType( Ops::OP_SIN, baseType ));
+ if(!resultBaseType) {
+ RMInit::logOut << "Error: QtSin::checkType() - operand type is not supported." << endl;
+ parseInfo.setErrorNo(367);
+ throw parseInfo;
+ }
+ dataStreamType.setType( resultBaseType );
+ }
+ else {
+ RMInit::logOut << "Error: QtSin::checkType() - operation is not supported for strings." << endl;
+ parseInfo.setErrorNo(385);
+ throw parseInfo;
+ }
+ }
+ else
+ RMInit::logOut << "Error: QtSin::checkType() - operand branch invalid." << endl;
+
+ return dataStreamType;
+}
+
+const QtNode::QtNodeType QtCos::nodeType = QtNode::QT_COS;
+
+QtCos::QtCos(QtOperation* initInput): QtUnaryInduce(initInput) {}
+QtData* QtCos::evaluate(QtDataList* inputList) {
+ QtData* returnValue = NULL;
+ QtData* operand = NULL;
+
+ if(getOperand(inputList, operand)) {
+ try {
+ returnValue = computeOp( operand, Ops::OP_COS );
+ }
+ catch(...) {
+ operand->deleteRef();
+ throw;
+ }
+ }
+ // delete old operand
+ if(operand) operand->deleteRef();
+ return returnValue;
+}
+
+void QtCos::printTree(int tab, ostream& s, QtChildType mode) {
+ s << SPACE_STR(tab).c_str() << "QtCosObject " << getNodeType() << endl;
+ QtUnaryInduce::printTree( tab + 2, s, mode );
+}
+void QtCos::printAlgebraicExpression(ostream& s) {
+ s << "cos(";
+ if(input)
+ input->printAlgebraicExpression(s);
+ else
+ s << "<nn>";
+ s << ")";
+}
+
+const QtTypeElement& QtCos::checkType(QtTypeTuple* typeTuple) {
+ RMDBCLASS( "QtCos", "checkType( QtTypeTuple* )", "qlparser", __FILE__, __LINE__ )
+ dataStreamType.setDataType( QT_TYPE_UNKNOWN );
+ // check operand branches
+ if(input) {
+ // get input types
+ const QtTypeElement& inputType = input->checkType( typeTuple );
+ RMDBGIF( 4, RMDebug::module_qlparser, "AutoGen", \
+ RMInit::dbgOut << "Operand: " << flush; \
+ inputType.printStatus( RMInit::dbgOut ); \
+ RMInit::dbgOut << endl; \
+ )
+ if(inputType.getDataType() == QT_MDD) {
+ const BaseType* baseType = ((MDDBaseType*)(inputType.getType()))->getBaseType();
+ BaseType* resultBaseType = (BaseType*)(Ops::getResultType( Ops::OP_COS, baseType ));
+ if(!resultBaseType) {
+ RMInit::logOut << "Error: QtCos::checkType() - induce operand type is not support" << endl;
+ parseInfo.setErrorNo(366);
+ throw parseInfo;
+ }
+ MDDBaseType* resultMDDType = new MDDBaseType( "tmp", resultBaseType );
+ TypeFactory::addTempType( resultMDDType );
+ dataStreamType.setType( resultMDDType );
+ }
+ else if(inputType.isBaseType()) {
+ BaseType* baseType = (BaseType*)(inputType.getType());
+ BaseType* resultBaseType = (BaseType*)(Ops::getResultType( Ops::OP_COS, baseType ));
+ if(!resultBaseType) {
+ RMInit::logOut << "Error: QtCos::checkType() - operand type is not supported." << endl;
+ parseInfo.setErrorNo(367);
+ throw parseInfo;
+ }
+ dataStreamType.setType( resultBaseType );
+ }
+ else {
+ RMInit::logOut << "Error: QtCos::checkType() - operation is not supported for strings." << endl;
+ parseInfo.setErrorNo(385);
+ throw parseInfo;
+ }
+ }
+ else
+ RMInit::logOut << "Error: QtCos::checkType() - operand branch invalid." << endl;
+
+ return dataStreamType;
+}
+
+const QtNode::QtNodeType QtTan::nodeType = QtNode::QT_TAN;
+
+QtTan::QtTan(QtOperation* initInput): QtUnaryInduce(initInput) {}
+QtData* QtTan::evaluate(QtDataList* inputList) {
+ QtData* returnValue = NULL;
+ QtData* operand = NULL;
+
+ if(getOperand(inputList, operand)) {
+ try {
+ returnValue = computeOp( operand, Ops::OP_TAN );
+ }
+ catch(...) {
+ operand->deleteRef();
+ throw;
+ }
+ }
+ // delete old operand
+ if(operand) operand->deleteRef();
+ return returnValue;
+}
+
+void QtTan::printTree(int tab, ostream& s, QtChildType mode) {
+ s << SPACE_STR(tab).c_str() << "QtTanObject " << getNodeType() << endl;
+ QtUnaryInduce::printTree( tab + 2, s, mode );
+}
+void QtTan::printAlgebraicExpression(ostream& s) {
+ s << "tan(";
+ if(input)
+ input->printAlgebraicExpression(s);
+ else
+ s << "<nn>";
+ s << ")";
+}
+
+const QtTypeElement& QtTan::checkType(QtTypeTuple* typeTuple) {
+ RMDBCLASS( "QtTan", "checkType( QtTypeTuple* )", "qlparser", __FILE__, __LINE__ )
+ dataStreamType.setDataType( QT_TYPE_UNKNOWN );
+ // check operand branches
+ if(input) {
+ // get input types
+ const QtTypeElement& inputType = input->checkType( typeTuple );
+ RMDBGIF( 4, RMDebug::module_qlparser, "AutoGen", \
+ RMInit::dbgOut << "Operand: " << flush; \
+ inputType.printStatus( RMInit::dbgOut ); \
+ RMInit::dbgOut << endl; \
+ )
+ if(inputType.getDataType() == QT_MDD) {
+ const BaseType* baseType = ((MDDBaseType*)(inputType.getType()))->getBaseType();
+ BaseType* resultBaseType = (BaseType*)(Ops::getResultType( Ops::OP_TAN, baseType ));
+ if(!resultBaseType) {
+ RMInit::logOut << "Error: QtTan::checkType() - induce operand type is not support" << endl;
+ parseInfo.setErrorNo(366);
+ throw parseInfo;
+ }
+ MDDBaseType* resultMDDType = new MDDBaseType( "tmp", resultBaseType );
+ TypeFactory::addTempType( resultMDDType );
+ dataStreamType.setType( resultMDDType );
+ }
+ else if(inputType.isBaseType()) {
+ BaseType* baseType = (BaseType*)(inputType.getType());
+ BaseType* resultBaseType = (BaseType*)(Ops::getResultType( Ops::OP_TAN, baseType ));
+ if(!resultBaseType) {
+ RMInit::logOut << "Error: QtTan::checkType() - operand type is not supported." << endl;
+ parseInfo.setErrorNo(367);
+ throw parseInfo;
+ }
+ dataStreamType.setType( resultBaseType );
+ }
+ else {
+ RMInit::logOut << "Error: QtTan::checkType() - operation is not supported for strings." << endl;
+ parseInfo.setErrorNo(385);
+ throw parseInfo;
+ }
+ }
+ else
+ RMInit::logOut << "Error: QtTan::checkType() - operand branch invalid." << endl;
+
+ return dataStreamType;
+}
+
+const QtNode::QtNodeType QtSinh::nodeType = QtNode::QT_SINH;
+
+QtSinh::QtSinh(QtOperation* initInput): QtUnaryInduce(initInput) {}
+QtData* QtSinh::evaluate(QtDataList* inputList) {
+ QtData* returnValue = NULL;
+ QtData* operand = NULL;
+
+ if(getOperand(inputList, operand)) {
+ try {
+ returnValue = computeOp( operand, Ops::OP_SINH );
+ }
+ catch(...) {
+ operand->deleteRef();
+ throw;
+ }
+ }
+ // delete old operand
+ if(operand) operand->deleteRef();
+ return returnValue;
+}
+
+void QtSinh::printTree(int tab, ostream& s, QtChildType mode) {
+ s << SPACE_STR(tab).c_str() << "QtSinhObject " << getNodeType() << endl;
+ QtUnaryInduce::printTree( tab + 2, s, mode );
+}
+void QtSinh::printAlgebraicExpression(ostream& s) {
+ s << "sinh(";
+ if(input)
+ input->printAlgebraicExpression(s);
+ else
+ s << "<nn>";
+ s << ")";
+}
+
+const QtTypeElement& QtSinh::checkType(QtTypeTuple* typeTuple) {
+ RMDBCLASS( "QtSinh", "checkType( QtTypeTuple* )", "qlparser", __FILE__, __LINE__ )
+ dataStreamType.setDataType( QT_TYPE_UNKNOWN );
+ // check operand branches
+ if(input) {
+ // get input types
+ const QtTypeElement& inputType = input->checkType( typeTuple );
+ RMDBGIF( 4, RMDebug::module_qlparser, "AutoGen", \
+ RMInit::dbgOut << "Operand: " << flush; \
+ inputType.printStatus( RMInit::dbgOut ); \
+ RMInit::dbgOut << endl; \
+ )
+ if(inputType.getDataType() == QT_MDD) {
+ const BaseType* baseType = ((MDDBaseType*)(inputType.getType()))->getBaseType();
+ BaseType* resultBaseType = (BaseType*)(Ops::getResultType( Ops::OP_SINH, baseType ));
+ if(!resultBaseType) {
+ RMInit::logOut << "Error: QtSinh::checkType() - induce operand type is not support" << endl;
+ parseInfo.setErrorNo(366);
+ throw parseInfo;
+ }
+ MDDBaseType* resultMDDType = new MDDBaseType( "tmp", resultBaseType );
+ TypeFactory::addTempType( resultMDDType );
+ dataStreamType.setType( resultMDDType );
+ }
+ else if(inputType.isBaseType()) {
+ BaseType* baseType = (BaseType*)(inputType.getType());
+ BaseType* resultBaseType = (BaseType*)(Ops::getResultType( Ops::OP_SINH, baseType ));
+ if(!resultBaseType) {
+ RMInit::logOut << "Error: QtSinh::checkType() - operand type is not supported." << endl;
+ parseInfo.setErrorNo(367);
+ throw parseInfo;
+ }
+ dataStreamType.setType( resultBaseType );
+ }
+ else {
+ RMInit::logOut << "Error: QtSinh::checkType() - operation is not supported for strings." << endl;
+ parseInfo.setErrorNo(385);
+ throw parseInfo;
+ }
+ }
+ else
+ RMInit::logOut << "Error: QtSinh::checkType() - operand branch invalid." << endl;
+
+ return dataStreamType;
+}
+
+const QtNode::QtNodeType QtCosh::nodeType = QtNode::QT_COSH;
+
+QtCosh::QtCosh(QtOperation* initInput): QtUnaryInduce(initInput) {}
+QtData* QtCosh::evaluate(QtDataList* inputList) {
+ QtData* returnValue = NULL;
+ QtData* operand = NULL;
+
+ if(getOperand(inputList, operand)) {
+ try {
+ returnValue = computeOp( operand, Ops::OP_COSH );
+ }
+ catch(...) {
+ operand->deleteRef();
+ throw;
+ }
+ }
+ // delete old operand
+ if(operand) operand->deleteRef();
+ return returnValue;
+}
+
+void QtCosh::printTree(int tab, ostream& s, QtChildType mode) {
+ s << SPACE_STR(tab).c_str() << "QtCoshObject " << getNodeType() << endl;
+ QtUnaryInduce::printTree( tab + 2, s, mode );
+}
+void QtCosh::printAlgebraicExpression(ostream& s) {
+ s << "cosh(";
+ if(input)
+ input->printAlgebraicExpression(s);
+ else
+ s << "<nn>";
+ s << ")";
+}
+
+const QtTypeElement& QtCosh::checkType(QtTypeTuple* typeTuple) {
+ RMDBCLASS( "QtCosh", "checkType( QtTypeTuple* )", "qlparser", __FILE__, __LINE__ )
+ dataStreamType.setDataType( QT_TYPE_UNKNOWN );
+ // check operand branches
+ if(input) {
+ // get input types
+ const QtTypeElement& inputType = input->checkType( typeTuple );
+ RMDBGIF( 4, RMDebug::module_qlparser, "AutoGen", \
+ RMInit::dbgOut << "Operand: " << flush; \
+ inputType.printStatus( RMInit::dbgOut ); \
+ RMInit::dbgOut << endl; \
+ )
+ if(inputType.getDataType() == QT_MDD) {
+ const BaseType* baseType = ((MDDBaseType*)(inputType.getType()))->getBaseType();
+ BaseType* resultBaseType = (BaseType*)(Ops::getResultType( Ops::OP_COSH, baseType ));
+ if(!resultBaseType) {
+ RMInit::logOut << "Error: QtCosh::checkType() - induce operand type is not support" << endl;
+ parseInfo.setErrorNo(366);
+ throw parseInfo;
+ }
+ MDDBaseType* resultMDDType = new MDDBaseType( "tmp", resultBaseType );
+ TypeFactory::addTempType( resultMDDType );
+ dataStreamType.setType( resultMDDType );
+ }
+ else if(inputType.isBaseType()) {
+ BaseType* baseType = (BaseType*)(inputType.getType());
+ BaseType* resultBaseType = (BaseType*)(Ops::getResultType( Ops::OP_COSH, baseType ));
+ if(!resultBaseType) {
+ RMInit::logOut << "Error: QtCosh::checkType() - operand type is not supported." << endl;
+ parseInfo.setErrorNo(367);
+ throw parseInfo;
+ }
+ dataStreamType.setType( resultBaseType );
+ }
+ else {
+ RMInit::logOut << "Error: QtCosh::checkType() - operation is not supported for strings." << endl;
+ parseInfo.setErrorNo(385);
+ throw parseInfo;
+ }
+ }
+ else
+ RMInit::logOut << "Error: QtCosh::checkType() - operand branch invalid." << endl;
+
+ return dataStreamType;
+}
+
+const QtNode::QtNodeType QtTanh::nodeType = QtNode::QT_TANH;
+
+QtTanh::QtTanh(QtOperation* initInput): QtUnaryInduce(initInput) {}
+QtData* QtTanh::evaluate(QtDataList* inputList) {
+ QtData* returnValue = NULL;
+ QtData* operand = NULL;
+
+ if(getOperand(inputList, operand)) {
+ try {
+ returnValue = computeOp( operand, Ops::OP_TANH );
+ }
+ catch(...) {
+ operand->deleteRef();
+ throw;
+ }
+ }
+ // delete old operand
+ if(operand) operand->deleteRef();
+ return returnValue;
+}
+
+void QtTanh::printTree(int tab, ostream& s, QtChildType mode) {
+ s << SPACE_STR(tab).c_str() << "QtTanhObject " << getNodeType() << endl;
+ QtUnaryInduce::printTree( tab + 2, s, mode );
+}
+void QtTanh::printAlgebraicExpression(ostream& s) {
+ s << "tanh(";
+ if(input)
+ input->printAlgebraicExpression(s);
+ else
+ s << "<nn>";
+ s << ")";
+}
+
+const QtTypeElement& QtTanh::checkType(QtTypeTuple* typeTuple) {
+ RMDBCLASS( "QtTanh", "checkType( QtTypeTuple* )", "qlparser", __FILE__, __LINE__ )
+ dataStreamType.setDataType( QT_TYPE_UNKNOWN );
+ // check operand branches
+ if(input) {
+ // get input types
+ const QtTypeElement& inputType = input->checkType( typeTuple );
+ RMDBGIF( 4, RMDebug::module_qlparser, "AutoGen", \
+ RMInit::dbgOut << "Operand: " << flush; \
+ inputType.printStatus( RMInit::dbgOut ); \
+ RMInit::dbgOut << endl; \
+ )
+ if(inputType.getDataType() == QT_MDD) {
+ const BaseType* baseType = ((MDDBaseType*)(inputType.getType()))->getBaseType();
+ BaseType* resultBaseType = (BaseType*)(Ops::getResultType( Ops::OP_TANH, baseType ));
+ if(!resultBaseType) {
+ RMInit::logOut << "Error: QtTanh::checkType() - induce operand type is not support" << endl;
+ parseInfo.setErrorNo(366);
+ throw parseInfo;
+ }
+ MDDBaseType* resultMDDType = new MDDBaseType( "tmp", resultBaseType );
+ TypeFactory::addTempType( resultMDDType );
+ dataStreamType.setType( resultMDDType );
+ }
+ else if(inputType.isBaseType()) {
+ BaseType* baseType = (BaseType*)(inputType.getType());
+ BaseType* resultBaseType = (BaseType*)(Ops::getResultType( Ops::OP_TANH, baseType ));
+ if(!resultBaseType) {
+ RMInit::logOut << "Error: QtTanh::checkType() - operand type is not supported." << endl;
+ parseInfo.setErrorNo(367);
+ throw parseInfo;
+ }
+ dataStreamType.setType( resultBaseType );
+ }
+ else {
+ RMInit::logOut << "Error: QtTanh::checkType() - operation is not supported for strings." << endl;
+ parseInfo.setErrorNo(385);
+ throw parseInfo;
+ }
+ }
+ else
+ RMInit::logOut << "Error: QtTanh::checkType() - operand branch invalid." << endl;
+
+ return dataStreamType;
+}
+
+const QtNode::QtNodeType QtArcsin::nodeType = QtNode::QT_ARCSIN;
+
+QtArcsin::QtArcsin(QtOperation* initInput): QtUnaryInduce(initInput) {}
+QtData* QtArcsin::evaluate(QtDataList* inputList) {
+ QtData* returnValue = NULL;
+ QtData* operand = NULL;
+
+ if(getOperand(inputList, operand)) {
+ try {
+ returnValue = computeOp( operand, Ops::OP_ARCSIN );
+ }
+ catch(...) {
+ operand->deleteRef();
+ throw;
+ }
+ }
+ // delete old operand
+ if(operand) operand->deleteRef();
+ return returnValue;
+}
+
+void QtArcsin::printTree(int tab, ostream& s, QtChildType mode) {
+ s << SPACE_STR(tab).c_str() << "QtArcsinObject " << getNodeType() << endl;
+ QtUnaryInduce::printTree( tab + 2, s, mode );
+}
+void QtArcsin::printAlgebraicExpression(ostream& s) {
+ s << "arcsin(";
+ if(input)
+ input->printAlgebraicExpression(s);
+ else
+ s << "<nn>";
+ s << ")";
+}
+
+const QtTypeElement& QtArcsin::checkType(QtTypeTuple* typeTuple) {
+ RMDBCLASS( "QtArcsin", "checkType( QtTypeTuple* )", "qlparser", __FILE__, __LINE__ )
+ dataStreamType.setDataType( QT_TYPE_UNKNOWN );
+ // check operand branches
+ if(input) {
+ // get input types
+ const QtTypeElement& inputType = input->checkType( typeTuple );
+ RMDBGIF( 4, RMDebug::module_qlparser, "AutoGen", \
+ RMInit::dbgOut << "Operand: " << flush; \
+ inputType.printStatus( RMInit::dbgOut ); \
+ RMInit::dbgOut << endl; \
+ )
+ if(inputType.getDataType() == QT_MDD) {
+ const BaseType* baseType = ((MDDBaseType*)(inputType.getType()))->getBaseType();
+ BaseType* resultBaseType = (BaseType*)(Ops::getResultType( Ops::OP_ARCSIN, baseType ));
+ if(!resultBaseType) {
+ RMInit::logOut << "Error: QtArcsin::checkType() - induce operand type is not support" << endl;
+ parseInfo.setErrorNo(366);
+ throw parseInfo;
+ }
+ MDDBaseType* resultMDDType = new MDDBaseType( "tmp", resultBaseType );
+ TypeFactory::addTempType( resultMDDType );
+ dataStreamType.setType( resultMDDType );
+ }
+ else if(inputType.isBaseType()) {
+ BaseType* baseType = (BaseType*)(inputType.getType());
+ BaseType* resultBaseType = (BaseType*)(Ops::getResultType( Ops::OP_ARCSIN, baseType ));
+ if(!resultBaseType) {
+ RMInit::logOut << "Error: QtArcsin::checkType() - operand type is not supported." << endl;
+ parseInfo.setErrorNo(367);
+ throw parseInfo;
+ }
+ dataStreamType.setType( resultBaseType );
+ }
+ else {
+ RMInit::logOut << "Error: QtArcsin::checkType() - operation is not supported for strings." << endl;
+ parseInfo.setErrorNo(385);
+ throw parseInfo;
+ }
+ }
+ else
+ RMInit::logOut << "Error: QtArcsin::checkType() - operand branch invalid." << endl;
+ return dataStreamType;
+}
+
+const QtNode::QtNodeType QtArccos::nodeType = QtNode::QT_ARCCOS;
+
+QtArccos::QtArccos(QtOperation* initInput): QtUnaryInduce(initInput) {}
+QtData* QtArccos::evaluate(QtDataList* inputList) {
+ QtData* returnValue = NULL;
+ QtData* operand = NULL;
+
+ if(getOperand(inputList, operand)) {
+ try {
+ returnValue = computeOp( operand, Ops::OP_ARCCOS );
+ }
+ catch(...) {
+ operand->deleteRef();
+ throw;
+ }
+ }
+ // delete old operand
+ if(operand) operand->deleteRef();
+ return returnValue;
+}
+
+void QtArccos::printTree(int tab, ostream& s, QtChildType mode) {
+ s << SPACE_STR(tab).c_str() << "QtArccosObject " << getNodeType() << endl;
+ QtUnaryInduce::printTree( tab + 2, s, mode );
+}
+void QtArccos::printAlgebraicExpression(ostream& s) {
+ s << "arccos(";
+ if(input)
+ input->printAlgebraicExpression(s);
+ else
+ s << "<nn>";
+ s << ")";
+}
+
+const QtTypeElement& QtArccos::checkType(QtTypeTuple* typeTuple) {
+ RMDBCLASS( "QtArccos", "checkType( QtTypeTuple* )", "qlparser", __FILE__, __LINE__ )
+ dataStreamType.setDataType( QT_TYPE_UNKNOWN );
+ // check operand branches
+ if(input) {
+ // get input types
+ const QtTypeElement& inputType = input->checkType( typeTuple );
+ RMDBGIF( 4, RMDebug::module_qlparser, "AutoGen", \
+ RMInit::dbgOut << "Operand: " << flush; \
+ inputType.printStatus( RMInit::dbgOut ); \
+ RMInit::dbgOut << endl; \
+ )
+ if(inputType.getDataType() == QT_MDD) {
+ const BaseType* baseType = ((MDDBaseType*)(inputType.getType()))->getBaseType();
+ BaseType* resultBaseType = (BaseType*)(Ops::getResultType( Ops::OP_ARCCOS, baseType ));
+ if(!resultBaseType) {
+ RMInit::logOut << "Error: QtArccos::checkType() - induce operand type is not support" << endl;
+ parseInfo.setErrorNo(366);
+ throw parseInfo;
+ }
+ MDDBaseType* resultMDDType = new MDDBaseType( "tmp", resultBaseType );
+ TypeFactory::addTempType( resultMDDType );
+ dataStreamType.setType( resultMDDType );
+ }
+ else if(inputType.isBaseType()) {
+ BaseType* baseType = (BaseType*)(inputType.getType());
+ BaseType* resultBaseType = (BaseType*)(Ops::getResultType( Ops::OP_ARCCOS, baseType ));
+ if(!resultBaseType) {
+ RMInit::logOut << "Error: QtArccos::checkType() - operand type is not supported." << endl;
+ parseInfo.setErrorNo(367);
+ throw parseInfo;
+ }
+ dataStreamType.setType( resultBaseType );
+ }
+ else {
+ RMInit::logOut << "Error: QtArccos::checkType() - operation is not supported for strings." << endl;
+ parseInfo.setErrorNo(385);
+ throw parseInfo;
+ }
+ }
+ else
+ RMInit::logOut << "Error: QtArccos::checkType() - operand branch invalid." << endl;
+ return dataStreamType;
+}
+
+const QtNode::QtNodeType QtArctan::nodeType = QtNode::QT_ARCTAN;
+
+QtArctan::QtArctan(QtOperation* initInput): QtUnaryInduce(initInput) {}
+QtData* QtArctan::evaluate(QtDataList* inputList) {
+ QtData* returnValue = NULL;
+ QtData* operand = NULL;
+
+ if(getOperand(inputList, operand)) {
+ try {
+ returnValue = computeOp( operand, Ops::OP_ARCTAN );
+ }
+ catch(...) {
+ operand->deleteRef();
+ throw;
+ }
+ }
+ // delete old operand
+ if(operand) operand->deleteRef();
+ return returnValue;
+}
+
+void QtArctan::printTree(int tab, ostream& s, QtChildType mode) {
+ s << SPACE_STR(tab).c_str() << "QtArctanObject " << getNodeType() << endl;
+ QtUnaryInduce::printTree( tab + 2, s, mode );
+}
+
+void QtArctan::printAlgebraicExpression(ostream& s) {
+ s << "arctan(";
+ if(input)
+ input->printAlgebraicExpression(s);
+ else
+ s << "<nn>";
+ s << ")";
+}
+
+const QtTypeElement& QtArctan::checkType(QtTypeTuple* typeTuple) {
+ RMDBCLASS( "QtArctan", "checkType( QtTypeTuple* )", "qlparser", __FILE__, __LINE__ )
+ dataStreamType.setDataType( QT_TYPE_UNKNOWN );
+ // check operand branches
+ if(input)
+ {
+ // get input types
+ const QtTypeElement& inputType = input->checkType( typeTuple );
+ RMDBGIF( 4, RMDebug::module_qlparser, "AutoGen", \
+ RMInit::dbgOut << "Operand: " << flush; \
+ inputType.printStatus( RMInit::dbgOut ); \
+ RMInit::dbgOut << endl; \
+ )
+ if(inputType.getDataType() == QT_MDD) {
+ const BaseType* baseType = ((MDDBaseType*)(inputType.getType()))->getBaseType();
+ BaseType* resultBaseType = (BaseType*)(Ops::getResultType( Ops::OP_ARCTAN, baseType ));
+ if(!resultBaseType) {
+ RMInit::logOut << "Error: QtArctan::checkType() - induce operand type is not support" << endl;
+ parseInfo.setErrorNo(366);
+ throw parseInfo;
+ }
+ MDDBaseType* resultMDDType = new MDDBaseType( "tmp", resultBaseType );
+ TypeFactory::addTempType( resultMDDType );
+ dataStreamType.setType( resultMDDType );
+ }
+ else if(inputType.isBaseType()) {
+ BaseType* baseType = (BaseType*)(inputType.getType());
+ BaseType* resultBaseType = (BaseType*)(Ops::getResultType( Ops::OP_ARCTAN, baseType ));
+ if(!resultBaseType) {
+ RMInit::logOut << "Error: QtArctan::checkType() - operand type is not supported." << endl;
+ parseInfo.setErrorNo(367);
+ throw parseInfo;
+ }
+ dataStreamType.setType( resultBaseType );
+ }
+ else {
+ RMInit::logOut << "Error: QtArctan::checkType() - operation is not supported for strings." << endl;
+ parseInfo.setErrorNo(385);
+ throw parseInfo;
+ }
+ }
+ else
+ RMInit::logOut << "Error: QtArctan::checkType() - operand branch invalid." << endl;
+
+ return dataStreamType;
+}
+
diff --git a/qlparser/autogen_qtui.hh b/qlparser/autogen_qtui.hh
new file mode 100644
index 0000000..f3ce42d
--- /dev/null
+++ b/qlparser/autogen_qtui.hh
@@ -0,0 +1,296 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS: Automaticaly generated
+ *
+ ************************************************************/
+
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+*/
+
+class QtAbs : public QtUnaryInduce {
+public:
+ QtAbs(QtOperation*);
+ QtData* evaluate(QtDataList*);
+ virtual void printTree(int, std::ostream& = std::cout, QtChildType = QT_ALL_NODES );
+ virtual void printAlgebraicExpression(std::ostream& = std::cout);
+ inline virtual const QtNodeType getNodeType() const;
+ virtual const QtTypeElement& checkType(QtTypeTuple* = NULL );
+
+private:
+ static const QtNodeType nodeType;
+};
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+*/
+
+class QtSqrt : public QtUnaryInduce {
+public:
+ QtSqrt(QtOperation*);
+ QtData* evaluate(QtDataList*);
+ virtual void printTree(int, std::ostream& = std::cout, QtChildType = QT_ALL_NODES );
+ virtual void printAlgebraicExpression(std::ostream& = std::cout);
+ inline virtual const QtNodeType getNodeType() const;
+ virtual const QtTypeElement& checkType(QtTypeTuple* = NULL );
+
+private:
+ static const QtNodeType nodeType;
+};
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+*/
+
+class QtExp : public QtUnaryInduce {
+public:
+ QtExp(QtOperation*);
+ QtData* evaluate(QtDataList*);
+ virtual void printTree(int, std::ostream& = std::cout, QtChildType = QT_ALL_NODES );
+ virtual void printAlgebraicExpression(std::ostream& = std::cout);
+ inline virtual const QtNodeType getNodeType() const;
+ virtual const QtTypeElement& checkType(QtTypeTuple* = NULL );
+
+private:
+ static const QtNodeType nodeType;
+};
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+*/
+
+class QtLog : public QtUnaryInduce {
+public:
+ QtLog(QtOperation*);
+ QtData* evaluate(QtDataList*);
+ virtual void printTree(int, std::ostream& = std::cout, QtChildType = QT_ALL_NODES );
+ virtual void printAlgebraicExpression(std::ostream& = std::cout);
+ inline virtual const QtNodeType getNodeType() const;
+ virtual const QtTypeElement& checkType(QtTypeTuple* = NULL );
+
+private:
+ static const QtNodeType nodeType;
+};
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+*/
+
+class QtLn : public QtUnaryInduce {
+public:
+ QtLn(QtOperation*);
+ QtData* evaluate(QtDataList*);
+ virtual void printTree(int, std::ostream& = std::cout, QtChildType = QT_ALL_NODES );
+ virtual void printAlgebraicExpression(std::ostream& = std::cout);
+ inline virtual const QtNodeType getNodeType() const;
+ virtual const QtTypeElement& checkType(QtTypeTuple* = NULL );
+
+private:
+ static const QtNodeType nodeType;
+};
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+*/
+
+class QtSin : public QtUnaryInduce {
+public:
+ QtSin(QtOperation*);
+ QtData* evaluate(QtDataList*);
+ virtual void printTree(int, std::ostream& = std::cout, QtChildType = QT_ALL_NODES );
+ virtual void printAlgebraicExpression(std::ostream& = std::cout);
+ inline virtual const QtNodeType getNodeType() const;
+ virtual const QtTypeElement& checkType(QtTypeTuple* = NULL );
+
+private:
+ static const QtNodeType nodeType;
+};
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+*/
+
+class QtCos : public QtUnaryInduce {
+public:
+ QtCos(QtOperation*);
+ QtData* evaluate(QtDataList*);
+ virtual void printTree(int, std::ostream& = std::cout, QtChildType = QT_ALL_NODES );
+ virtual void printAlgebraicExpression(std::ostream& = std::cout);
+ inline virtual const QtNodeType getNodeType() const;
+ virtual const QtTypeElement& checkType(QtTypeTuple* = NULL );
+
+private:
+ static const QtNodeType nodeType;
+};
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+*/
+
+class QtTan : public QtUnaryInduce {
+public:
+ QtTan(QtOperation*);
+ QtData* evaluate(QtDataList*);
+ virtual void printTree(int, std::ostream& = std::cout, QtChildType = QT_ALL_NODES );
+ virtual void printAlgebraicExpression(std::ostream& = std::cout);
+ inline virtual const QtNodeType getNodeType() const;
+ virtual const QtTypeElement& checkType(QtTypeTuple* = NULL );
+
+private:
+ static const QtNodeType nodeType;
+};
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+*/
+
+class QtSinh : public QtUnaryInduce {
+public:
+ QtSinh(QtOperation*);
+ QtData* evaluate(QtDataList*);
+ virtual void printTree(int, std::ostream& = std::cout, QtChildType = QT_ALL_NODES );
+ virtual void printAlgebraicExpression(std::ostream& = std::cout);
+ inline virtual const QtNodeType getNodeType() const;
+ virtual const QtTypeElement& checkType(QtTypeTuple* = NULL );
+
+private:
+ static const QtNodeType nodeType;
+};
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+*/
+
+class QtCosh : public QtUnaryInduce {
+public:
+ QtCosh(QtOperation*);
+ QtData* evaluate(QtDataList*);
+ virtual void printTree(int, std::ostream& = std::cout, QtChildType = QT_ALL_NODES );
+ virtual void printAlgebraicExpression(std::ostream& = std::cout);
+ inline virtual const QtNodeType getNodeType() const;
+ virtual const QtTypeElement& checkType(QtTypeTuple* = NULL );
+
+private:
+ static const QtNodeType nodeType;
+};
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+*/
+
+class QtTanh : public QtUnaryInduce {
+public:
+ QtTanh(QtOperation*);
+ QtData* evaluate(QtDataList*);
+ virtual void printTree(int, std::ostream& = std::cout, QtChildType = QT_ALL_NODES );
+ virtual void printAlgebraicExpression(std::ostream& = std::cout);
+ inline virtual const QtNodeType getNodeType() const;
+ virtual const QtTypeElement& checkType(QtTypeTuple* = NULL );
+
+private:
+ static const QtNodeType nodeType;
+};
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+*/
+
+class QtArcsin : public QtUnaryInduce {
+public:
+ QtArcsin(QtOperation*);
+ QtData* evaluate(QtDataList*);
+ virtual void printTree(int, std::ostream& = std::cout, QtChildType = QT_ALL_NODES );
+ virtual void printAlgebraicExpression(std::ostream& = std::cout);
+ inline virtual const QtNodeType getNodeType() const;
+ virtual const QtTypeElement& checkType(QtTypeTuple* = NULL );
+
+private:
+ static const QtNodeType nodeType;
+};
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+*/
+
+class QtArccos : public QtUnaryInduce {
+public:
+ QtArccos(QtOperation*);
+ QtData* evaluate(QtDataList*);
+ virtual void printTree(int, std::ostream& = std::cout, QtChildType = QT_ALL_NODES );
+ virtual void printAlgebraicExpression(std::ostream& = std::cout);
+ inline virtual const QtNodeType getNodeType() const;
+ virtual const QtTypeElement& checkType(QtTypeTuple* = NULL );
+
+private:
+ static const QtNodeType nodeType;
+};
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+*/
+
+class QtArctan : public QtUnaryInduce {
+public:
+ QtArctan(QtOperation*);
+ QtData* evaluate(QtDataList*);
+ virtual void printTree(int, std::ostream& = std::cout, QtChildType = QT_ALL_NODES );
+ virtual void printAlgebraicExpression(std::ostream& = std::cout);
+ inline virtual const QtNodeType getNodeType() const;
+ virtual const QtTypeElement& checkType(QtTypeTuple* = NULL );
+
+private:
+ static const QtNodeType nodeType;
+};
+
diff --git a/qlparser/autogen_qtui.icc b/qlparser/autogen_qtui.icc
new file mode 100644
index 0000000..0a339a8
--- /dev/null
+++ b/qlparser/autogen_qtui.icc
@@ -0,0 +1,44 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS: Automaticaly generated
+ *
+ ************************************************************/
+
+
+inline const QtNode::QtNodeType QtAbs::getNodeType() const { return nodeType; }
+inline const QtNode::QtNodeType QtSqrt::getNodeType() const { return nodeType; }
+inline const QtNode::QtNodeType QtExp::getNodeType() const { return nodeType; }
+inline const QtNode::QtNodeType QtLog::getNodeType() const { return nodeType; }
+inline const QtNode::QtNodeType QtLn::getNodeType() const { return nodeType; }
+inline const QtNode::QtNodeType QtSin::getNodeType() const { return nodeType; }
+inline const QtNode::QtNodeType QtCos::getNodeType() const { return nodeType; }
+inline const QtNode::QtNodeType QtTan::getNodeType() const { return nodeType; }
+inline const QtNode::QtNodeType QtSinh::getNodeType() const { return nodeType; }
+inline const QtNode::QtNodeType QtCosh::getNodeType() const { return nodeType; }
+inline const QtNode::QtNodeType QtTanh::getNodeType() const { return nodeType; }
+inline const QtNode::QtNodeType QtArcsin::getNodeType() const { return nodeType; }
+inline const QtNode::QtNodeType QtArccos::getNodeType() const { return nodeType; }
+inline const QtNode::QtNodeType QtArctan::getNodeType() const { return nodeType; }
diff --git a/qlparser/lex.ll b/qlparser/lex.ll
new file mode 100644
index 0000000..8a1b140
--- /dev/null
+++ b/qlparser/lex.ll
@@ -0,0 +1,354 @@
+%{
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ * COMMENTS:
+ * - token BY seems unused
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)qlparser, lexer: $Id: oql.l,v 1.64 2005/07/06 22:48:34 rasdev Exp $";
+
+#include "qlparser/qtoperation.hh"
+#include "qlparser/querytree.hh"
+#include "qlparser/qtmddaccess.hh"
+#include "qlparser/qtcomplexdata.hh"
+#include "qlparser/qtiterator.hh"
+#include "qlparser/qtunaryinduce.hh"
+
+std::list<ParseInfo> infoList;
+
+ParseInfo *currInfo=0;
+
+struct QtUpdateSpecElement
+{
+ QtOperation* iterator;
+ QtOperation* domain;
+};
+
+#include "oql.h"
+
+QueryTree* parseQueryTree = NULL;
+char* beginParseString = NULL;
+char* iterParseString = NULL;
+void yyreset();
+
+unsigned int lineNo = 1;
+unsigned int columnNo = 1;
+void llerror( char* s );
+int yyparse( );
+
+int string_yyinput( char* buf, int max_size )
+{
+ int lenParseString = strlen( iterParseString );
+ int bufLength = max_size < lenParseString ? max_size : lenParseString;
+ if( bufLength > 0 )
+ {
+ memcpy( buf, iterParseString, bufLength );
+ iterParseString += bufLength;
+ }
+ return bufLength;
+}
+
+#undef YY_INPUT
+#define YY_INPUT( buff, buffLen, maxSize ) ( buffLen = string_yyinput( buff, maxSize ) )
+
+#define SETTOKEN( TOKEN, TYPE, VALUE ) \
+ yylval.TYPE.value = VALUE; \
+ if(!infoList.empty()) { \
+ currInfo = new ParseInfo(infoList.front()); \
+ infoList.pop_front(); \
+ } \
+ else { \
+ currInfo = new ParseInfo( yytext, lineNo, columnNo ); \
+ } \
+ yylval.TYPE.info = currInfo; \
+ columnNo += yyleng; \
+ parseQueryTree->addDynamicObject( yylval.TYPE.info ); \
+ return TOKEN;
+
+
+#define SETSTRTOKEN( TOKEN, TYPE, VALUE ) \
+ char* temp = strdup(VALUE); \
+ parseQueryTree->addCString( temp ); \
+ yylval.TYPE.value = temp; \
+ if(!infoList.empty()) { \
+ currInfo = new ParseInfo(infoList.front()); \
+ infoList.pop_front(); \
+ } \
+ else { \
+ currInfo = new ParseInfo( yytext, lineNo, columnNo ); \
+ } \
+ yylval.TYPE.info = currInfo; \
+ columnNo += yyleng; \
+ parseQueryTree->addDynamicObject( yylval.TYPE.info ); \
+ return TOKEN;
+
+
+#define SETINTTOKEN( VALUE, NEGATIVE, BYTES ) \
+ yylval.integerToken.negative = NEGATIVE; \
+ yylval.integerToken.bytes = BYTES; \
+ if( NEGATIVE ) \
+ yylval.integerToken.svalue = VALUE; \
+ else \
+ yylval.integerToken.uvalue = (unsigned long)VALUE; \
+ if(!infoList.empty()) { \
+ currInfo = new ParseInfo(infoList.front()); \
+ infoList.pop_front(); \
+ } \
+ else { \
+ currInfo = new ParseInfo( yytext, lineNo, columnNo ); \
+ } \
+ yylval.integerToken.info = currInfo; \
+ columnNo += yyleng; \
+ parseQueryTree->addDynamicObject( yylval.integerToken.info ); \
+ return IntegerLit;
+
+
+#define SETFLTTOKEN( VALUE, BYTES ) \
+ yylval.floatToken.value = VALUE; \
+ yylval.floatToken.bytes = BYTES; \
+ if(!infoList.empty()) { \
+ currInfo = new ParseInfo(infoList.front()); \
+ infoList.pop_front(); \
+ } \
+ else { \
+ currInfo = new ParseInfo(yytext, lineNo, columnNo); \
+ } \
+ yylval.floatToken.info = currInfo; \
+ columnNo += yyleng; \
+ parseQueryTree->addDynamicObject( yylval.floatToken.info ); \
+ return FloatLit;
+
+%}
+
+%option noyywrap
+
+%%
+
+"/*""/"*([^*/]|[^*]"/"|"*"[^/])*"*"*"*/" {
+ if( !strncmp( yytext, "/*+", 3 ) )
+ {
+ if( strstr( yytext, "opt 0" ) )
+ parseQueryTree->setOptimizationLevel(0);
+ if( strstr( yytext, "opt 1" ) )
+ parseQueryTree->setOptimizationLevel(1);
+ if( strstr( yytext, "opt 2" ) )
+ parseQueryTree->setOptimizationLevel(2);
+ if( strstr( yytext, "opt 3" ) )
+ parseQueryTree->setOptimizationLevel(3);
+ if( strstr( yytext, "opt 4" ) )
+ parseQueryTree->setOptimizationLevel(4);
+ }
+ columnNo += yyleng;
+ }
+"//".* { columnNo += yyleng; }
+"--".* { columnNo += yyleng; }
+
+"[opt 0]" { parseQueryTree->setOptimizationLevel(0); columnNo += yyleng; }
+"[opt 1]" { parseQueryTree->setOptimizationLevel(1); columnNo += yyleng; }
+"[opt 2]" { parseQueryTree->setOptimizationLevel(2); columnNo += yyleng; }
+"[opt 3]" { parseQueryTree->setOptimizationLevel(3); columnNo += yyleng; }
+"[opt 4]" { parseQueryTree->setOptimizationLevel(4); columnNo += yyleng; }
+
+"complex" { SETTOKEN( COMPLEX, commandToken, COMPLEX ) }
+"re" { SETTOKEN( RE, commandToken, RE ) }
+"im" { SETTOKEN( IM, commandToken, IM ) }
+
+"struct" { SETTOKEN( STRCT, commandToken, STRCT ) }
+"fastscale" { SETTOKEN( FASTSCALE, commandToken, FASTSCALE ) }
+"members" { SETTOKEN( MEMBERS, commandToken, MEMBERS ) }
+"add" { SETTOKEN( ADD, commandToken, ADD ) }
+"alter" { SETTOKEN( ALTER, commandToken, ALTER ) }
+"list" { SETTOKEN( LIST, commandToken, LIST ) }
+"select" { SETTOKEN( SELECT, commandToken, SELECT ) }
+"from" { SETTOKEN( FROM, commandToken, FROM ) }
+"where" { SETTOKEN( WHERE, commandToken, WHERE ) }
+"as" { SETTOKEN( AS, commandToken, AS ) }
+"restrict" { SETTOKEN( RESTRICT, commandToken, RESTRICT ) }
+"to" { SETTOKEN( TO, commandToken, TO ) }
+"extend" { SETTOKEN( EXTEND, commandToken, EXTEND ) }
+"by" { SETTOKEN( BY, commandToken, BY ) }
+"project" { SETTOKEN( PROJECT, commandToken, PROJECT ) }
+"at" { SETTOKEN( AT, commandToken, AT ) }
+"dimension" { SETTOKEN( DIMENSION, commandToken, DIMENSION ) }
+"all_cell"|"all_cells" { SETTOKEN( ALL, commandToken, ALL ) }
+"some_cell"|"some_cells" { SETTOKEN( SOME, commandToken, SOME ) }
+"count_cell"|"count_cells" { SETTOKEN( COUNTCELLS, commandToken, COUNTCELLS ) }
+"add_cell"|"add_cells" { SETTOKEN( ADDCELLS, commandToken, ADDCELLS ) }
+"avg_cell"|"avg_cells" { SETTOKEN( AVGCELLS, commandToken, AVGCELLS ) }
+"min_cell"|"min_cells" { SETTOKEN( MINCELLS, commandToken, MINCELLS ) }
+"max_cell"|"max_cells" { SETTOKEN( MAXCELLS, commandToken, MAXCELLS ) }
+"sdom" { SETTOKEN( SDOM, commandToken, SDOM ) }
+"over" { SETTOKEN( OVER, commandToken, OVER ) }
+"overlay" { SETTOKEN( OVERLAY, commandToken, OVERLAY ) }
+"using" { SETTOKEN( USING, commandToken, USING ) }
+"lo" { SETTOKEN( LO, commandToken, LO ) }
+"hi" { SETTOKEN( HI, commandToken, HI ) }
+
+"insert" { SETTOKEN( INSERT, commandToken, INSERT ) }
+"into" { SETTOKEN( INTO, commandToken, INTO ) }
+"values" { SETTOKEN( VALUES, commandToken, VALUES ) }
+"delete" { SETTOKEN( DELETE, commandToken, DELETE ) }
+"drop" { SETTOKEN( DROP, commandToken, DROP ) }
+"create" { SETTOKEN( CREATE, commandToken, CREATE ) }
+"collection" { SETTOKEN( COLLECTION, commandToken, COLLECTION ) }
+
+"update" { SETTOKEN( UPDATE, commandToken, UPDATE ) }
+"set" { SETTOKEN( SET, commandToken, SET ) }
+"assign" { SETTOKEN( ASSIGN, commandToken, ASSIGN ) }
+"in" { SETTOKEN( IN, commandToken, IN ) }
+"marray" { SETTOKEN( MARRAY, commandToken, MARRAY ) }
+"condense" { SETTOKEN( CONDENSE, commandToken, CONDENSE ) }
+
+"oid" { SETTOKEN( OID, commandToken, OID ) }
+"shift" { SETTOKEN( SHIFT, commandToken, SHIFT ) }
+"scale" { SETTOKEN( SCALE, commandToken, SCALE ) }
+
+"." { SETTOKEN( DOT, commandToken, DOT ) }
+"," { SETTOKEN( COMMA, commandToken, COMMA ) }
+"is" { SETTOKEN( IS, commandToken, IS ) }
+"not" { SETTOKEN( NOT, commandToken, NOT ) }
+"sqrt" { SETTOKEN( SQRT, commandToken, SQRT ) }
+
+"tiff" { SETTOKEN( TIFF, commandToken, TIFF ) }
+"bmp" { SETTOKEN( BMP, commandToken, BMP ) }
+"hdf" { SETTOKEN( HDF, commandToken, HDF ) }
+"jpeg" { SETTOKEN( JPEG, commandToken, JPEG ) }
+"csv" { SETTOKEN( CSV, commandToken, CSV ) }
+"png" { SETTOKEN( PNG, commandToken, PNG ) }
+"vff" { SETTOKEN( VFF, commandToken, VFF ) }
+"tor" { SETTOKEN( TOR, commandToken, TOR ) }
+"dem" { SETTOKEN( DEM, commandToken, DEM ) }
+
+"inv_tiff" { SETTOKEN( INV_TIFF, commandToken, INV_TIFF ) }
+"inv_bmp" { SETTOKEN( INV_BMP, commandToken, INV_BMP ) }
+"inv_hdf" { SETTOKEN( INV_HDF, commandToken, INV_HDF ) }
+"inv_jpeg" { SETTOKEN( INV_JPEG, commandToken, INV_JPEG ) }
+"inv_csv" { SETTOKEN( INV_CSV, commandToken, INV_CSV ) }
+"inv_png" { SETTOKEN( INV_PNG, commandToken, INV_PNG ) }
+"inv_vff" { SETTOKEN( INV_VFF, commandToken, INV_VFF ) }
+"inv_tor" { SETTOKEN( INV_TOR, commandToken, INV_TOR ) }
+"inv_dem" { SETTOKEN( INV_DEM, commandToken, INV_DEM ) }
+
+"abs" { SETTOKEN( ABS, commandToken, ABS ) }
+"exp" { SETTOKEN( EXP, commandToken, EXP ) }
+"log" { SETTOKEN( LOG, commandToken, LOG ) }
+"ln" { SETTOKEN( LN, commandToken, LN ) }
+"sin" { SETTOKEN( SIN, commandToken, SIN ) }
+"cos" { SETTOKEN( COS, commandToken, COS ) }
+"tan" { SETTOKEN( TAN, commandToken, TAN ) }
+"sinh" { SETTOKEN( SINH, commandToken, SINH ) }
+"cosh" { SETTOKEN( COSH, commandToken, COSH ) }
+"tanh" { SETTOKEN( TANH, commandToken, TANH ) }
+"arcsin" { SETTOKEN( ARCSIN, commandToken, ARCSIN ) }
+"arccos" { SETTOKEN( ARCCOS, commandToken, ARCCOS ) }
+"arctan" { SETTOKEN( ARCTAN, commandToken, ARCTAN ) }
+
+"unsigned" { SETTOKEN( TUNSIG, typeToken, TUNSIG) }
+"bool" { SETTOKEN( TBOOL, typeToken, TBOOL) }
+"char" { SETTOKEN( TCHAR, typeToken, TCHAR) }
+"octet" { SETTOKEN( TOCTET, typeToken, TOCTET) }
+"short" { SETTOKEN( TSHORT, typeToken, TSHORT) }
+"ushort" { SETTOKEN( TUSHORT, typeToken, TUSHORT) }
+"long" { SETTOKEN( TLONG, typeToken, TLONG) }
+"ulong" { SETTOKEN( TULONG, typeToken, TULONG) }
+"float" { SETTOKEN( TFLOAT, typeToken, TFLOAT) }
+"double" { SETTOKEN( TDOUBLE, typeToken, TDOUBLE) }
+
+"bit" { SETTOKEN( BIT, commandToken, BIT ) }
+"and" { SETTOKEN( AND, commandToken, AND ) }
+"or" { SETTOKEN( OR, commandToken, OR ) }
+"xor" { SETTOKEN( XOR, commandToken, XOR ) }
+"+" { SETTOKEN( PLUS, commandToken, PLUS ) }
+"-" { SETTOKEN( MINUS, commandToken, MINUS ) }
+"*" { SETTOKEN( MULT, commandToken, MULT ) }
+"/" { SETTOKEN( DIV, commandToken, DIV ) }
+"=" { SETTOKEN( EQUAL, commandToken, EQUAL ) }
+"<" { SETTOKEN( LESS, commandToken, LESS ) }
+">" { SETTOKEN( GREATER, commandToken, GREATER ) }
+"<=" { SETTOKEN( LESSEQUAL, commandToken, LESSEQUAL ) }
+">=" { SETTOKEN( GREATEREQUAL, commandToken, GREATEREQUAL ) }
+"<>" { SETTOKEN( NOTEQUAL, commandToken, NOTEQUAL ) }
+"!=" { SETTOKEN( NOTEQUAL, commandToken, NOTEQUAL ) }
+":" { SETTOKEN( COLON, commandToken, COLON ) }
+";" { SETTOKEN( SEMICOLON, commandToken, SEMICOLON ) }
+"[" { SETTOKEN( LEPAR, commandToken, LEPAR ) }
+"]" { SETTOKEN( REPAR, commandToken, REPAR ) }
+"(" { SETTOKEN( LRPAR, commandToken, LRPAR ) }
+")" { SETTOKEN( RRPAR, commandToken, RRPAR ) }
+"{" { SETTOKEN( LCPAR, commandToken, LCPAR ) }
+"}" { SETTOKEN( RCPAR, commandToken, RCPAR ) }
+#MDD[0-9]+# { SETTOKEN( MDDPARAM, commandToken, atoi(&(yytext[1])) ) }
+$[0-9]+ { llerror("unresolved query parameter"); columnNo++; }
+
+"true"|"false"|"TRUE"|"FALSE" { SETTOKEN( BooleanLit, booleanToken, yytext[0] == 't' || yytext[0] == 'T') }
+[a-zA-Z_][a-zA-Z0-9_]* { SETSTRTOKEN( Identifier, identifierToken, yytext ) }
+"'"[^']"'" { SETTOKEN( CharacterLit, characterToken, yytext[1] ) }
+\"([^"]|\\["\n])*\" {
+ yytext[strlen(yytext)-1] = '\0';
+ SETSTRTOKEN( StringLit, stringToken, &(yytext[1]) )
+ }
+
+0x[0-f]+[cC] { SETINTTOKEN( strtoul( yytext, (char**)NULL, 16 ), 0, 1 ) }
+0x[0-f]+"us"|"US" { SETINTTOKEN( strtoul( yytext, (char**)NULL, 16 ), 0, 2 ) }
+0x[0-f]+"ul"|"UL" { SETINTTOKEN( strtoul( yytext, (char**)NULL, 16 ), 0, 4 ) }
+-?0x[0-f]+[oO] { SETINTTOKEN( strtol ( yytext, (char**)NULL, 16 ), 1, 1 ) }
+-?0x[0-f]+[sS] { SETINTTOKEN( strtol ( yytext, (char**)NULL, 16 ), 1, 2 ) }
+-?0x[0-f]+[lL]? { SETINTTOKEN( strtol ( yytext, (char**)NULL, 16 ), 1, 4 ) }
+
+[0-9]+[cC] { SETINTTOKEN( strtoul( yytext, (char**)NULL, 10 ), 0, 1 ) }
+[0-9]+"us"|"US" { SETINTTOKEN( strtoul( yytext, (char**)NULL, 10 ), 0, 2 ) }
+[0-9]+"ul"|"UL" { SETINTTOKEN( strtoul( yytext, (char**)NULL, 10 ), 0, 4 ) }
+-?[0-9]+[oO] { SETINTTOKEN( strtol ( yytext, (char**)NULL, 10 ), 1, 1 ) }
+-?[0-9]+[sS] { SETINTTOKEN( strtol ( yytext, (char**)NULL, 10 ), 1, 2 ) }
+-?[0-9]+[lL]? { SETINTTOKEN( strtol ( yytext, (char**)NULL, 10 ), 1, 4 ) }
+
+-?([0-9]+|([0-9]+(\.[0-9]+)?)([eE][-+]?[0-9]+)?)[dD] { SETFLTTOKEN( strtod( yytext, (char**)NULL ), 8 ) }
+-?([0-9]+|([0-9]+(\.[0-9]+)?)([eE][-+]?[0-9]+)?)[fF]? { SETFLTTOKEN( strtod( yytext, (char**)NULL ), 4 ) }
+
+[ ]+ { columnNo += yyleng; }
+\t { columnNo += 3; }
+\r { }
+\n { columnNo = 1; lineNo++; }
+. { SETTOKEN(UNKNOWN, commandToken, UNKNOWN ) }
+
+%%
+
+void yyreset()
+{
+ // Reset the input buffer of the scanner so that the next call of yylex() invokes
+ // YY_INPUT to fill the buffer with new data.
+ if ( YY_CURRENT_BUFFER )
+ yy_flush_buffer( YY_CURRENT_BUFFER );
+ lineNo = 1;
+ columnNo = 1;
+ currInfo = 0;
+}
+
+
+void llerror( char* s )
+{
+ RMInit::logOut << "Lex error: line " << lineNo << ", " << s << " at " << yytext << std::endl;
+}
diff --git a/qlparser/oql.yy b/qlparser/oql.yy
new file mode 100644
index 0000000..006ed88
--- /dev/null
+++ b/qlparser/oql.yy
@@ -0,0 +1,2185 @@
+%{
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * Grammar for RasQL
+ *
+ *
+ * COMMENTS:
+ * - token BY unused
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)qlparser, yacc parser: $Header: /home/rasdev/CVS-repository/rasdaman/qlparser/oql.y,v 1.95 2006/01/03 00:21:40 rasdev Exp $";
+
+#include "qlparser/qtconversion.hh"
+#include "qlparser/qtmarrayop.hh"
+#include "qlparser/qtcondense.hh"
+#include "qlparser/qtbinaryinduce2.hh"
+#include "qlparser/qtbinaryfunc.hh"
+#include "qlparser/qtoid.hh"
+#include "qlparser/qtcondenseop.hh"
+#include "qlparser/qtstringdata.hh"
+#include "qlparser/qtconst.hh"
+#include "qlparser/qtintervalop.hh"
+#include "qlparser/qtmintervalop.hh"
+#include "qlparser/qtunaryfunc.hh"
+#include "qlparser/qtupdate.hh"
+#include "qlparser/qtinsert.hh"
+#include "qlparser/qtdelete.hh"
+#include "qlparser/qtjoiniterator.hh"
+#include "qlparser/qtselectioniterator.hh"
+#include "qlparser/qtoperationiterator.hh"
+#include "qlparser/qtcommand.hh"
+#include "qlparser/qtunaryinduce.hh"
+#include "qlparser/qtiterator.hh"
+#include "qlparser/qtcomplexdata.hh"
+#include "qlparser/qtmddaccess.hh"
+#include "qlparser/querytree.hh"
+#include "servercomm/servercomm.hh"
+
+extern ServerComm::ClientTblElt* currentClientTblElt;
+extern ParseInfo *currInfo;
+
+void yyerror( char* s );
+
+extern int yylex();
+extern unsigned int lineNo;
+extern unsigned int columnNo;
+extern char* yytext;
+
+//defined in oql.l
+extern QueryTree* parseQueryTree;
+
+ParseInfo* parseError = NULL;
+
+struct QtUpdateSpecElement
+{
+ QtOperation* iterator;
+ QtOperation* domain;
+};
+
+#define FREESTACK( ARG ) \
+ parseQueryTree->removeDynamicObject( ARG.info ); \
+ delete ARG.info; \
+ ARG.info=NULL;
+
+// simple context dependancy for marray
+#define YYPARSE_PARAM mflag
+#define MF_IN_CONTEXT (void *)1
+#define MF_NO_CONTEXT (void *)0
+
+%}
+
+// definition section
+
+%union {
+
+ struct {
+ bool value;
+ ParseInfo* info;
+ } booleanToken;
+
+ struct {
+ char value;
+ ParseInfo* info;
+ } characterToken;
+
+ struct {
+ unsigned short negative; // 1 = signed value, 0 = unsigned value
+ r_Long svalue; // stores the signed value -> negative = 1
+ r_ULong uvalue; // stores the unsigned value -> negative = 0;
+ unsigned short bytes; // stores the length in bytes (1,2,3,4)
+ ParseInfo* info;
+ } integerToken;
+
+ struct {
+ double value;
+ unsigned short bytes; // stores the length in bytes (4,8)
+ ParseInfo* info;
+ } floatToken;
+
+ struct {
+ char* value;
+ ParseInfo* info;
+ } stringToken;
+
+ struct {
+ int value;
+ ParseInfo* info;
+ } typeToken;
+
+
+ struct {
+ int value;
+ ParseInfo* info;
+ } commandToken;
+
+ struct {
+ char* value;
+ ParseInfo* info;
+ } identifierToken;
+
+//--------------------------------------------------
+ QtMarrayOp2::mddIntervalType * mddIntervalType;
+ QtMarrayOp2::mddIntervalListType * mddIntervalListType;
+//---------------------------------------------------
+
+ r_Sinterval* Sinterval;
+
+ QtNode* qtNodeValue;
+ QtOperation* qtOperationValue;
+ QtUnaryOperation* qtUnaryOperationValue;
+ QtDomainOperation* qtDomainValue;
+ QtMDDAccess* qtMDDAccessValue;
+
+ QtData* qtDataValue;
+ QtScalarData* qtScalarDataValue;
+ QtAtomicData* qtAtomicDataValue;
+ QtComplexData* qtComplexDataValue;
+
+ QtIterator::QtONCStreamList* qtONCStreamListValue;
+ QtComplexData::QtScalarDataList* qtScalarDataListValue;
+ QtNode::QtOperationList* qtOperationListValue;
+
+ QtUpdateSpecElement qtUpdateSpecElement;
+
+ Ops::OpType operationValue;
+ int dummyValue;
+
+ struct {
+ QtCast::cast_types qtCastType;
+ ParseInfo *info;
+ } castTypes;
+
+}
+
+%token <identifierToken> Identifier
+%token <booleanToken> BooleanLit
+%token <characterToken> CharacterLit
+%token <integerToken> IntegerLit
+%token <floatToken> FloatLit
+%token <stringToken> StringLit
+%token <typeToken> TUNSIG TBOOL TOCTET TCHAR TSHORT TUSHORT TLONG TULONG TFLOAT TDOUBLE
+%token <commandToken> SELECT FROM WHERE AS RESTRICT TO EXTEND BY PROJECT AT DIMENSION ALL SOME
+ COUNTCELLS ADDCELLS AVGCELLS MINCELLS MAXCELLS SDOM OVER USING LO HI UPDATE
+ SET ASSIGN MARRAY CONDENSE IN DOT COMMA IS NOT AND OR XOR PLUS MINUS MULT
+ DIV EQUAL LESS GREATER LESSEQUAL GREATEREQUAL NOTEQUAL COLON SEMICOLON LEPAR
+ REPAR LRPAR RRPAR LCPAR RCPAR INSERT INTO VALUES DELETE DROP CREATE COLLECTION
+ MDDPARAM OID SHIFT SCALE SQRT ABS EXP LOG LN SIN COS TAN SINH COSH TANH ARCSIN
+ ARCCOS ARCTAN OVERLAY BIT UNKNOWN FASTSCALE MEMBERS ADD ALTER LIST
+ STRCT COMPLEX RE IM TIFF BMP HDF CSV JPEG PNG VFF TOR DEM INV_TIFF INV_BMP INV_HDF
+ INV_JPEG INV_PNG INV_VFF INV_CSV INV_TOR INV_DEM
+
+%left COLON VALUES USING WHERE
+%left OVERLAY
+%left OR XOR
+%left AND
+%left NOT
+%left IS
+%left EQUAL LESS GREATER LESSEQUAL GREATEREQUAL NOTEQUAL
+%left PLUS MINUS
+%left MULT DIV
+%left UNARYOP BIT
+%left DOT LEPAR SDOM
+
+// The LEPAR precedence is for the trimming operation. Context dependent
+// precedence would be better in that case but it did not work.
+
+%type <qtUpdateSpecElement> updateSpec
+%type <qtMDDAccessValue> iteratedCollection
+%type <qtONCStreamListValue> collectionList
+%type <qtUnaryOperationValue> reduceIdent structSelection trimExp
+%type <qtOperationValue> mddExp inductionExp generalExp resultList reduceExp functionExp spatialOp
+ integerExp mintervalExp intervalExp condenseExp variable
+%type <qtOperationListValue> spatialOpList spatialOpList2
+%type <integerToken> intLitExp
+%type <operationValue> condenseOpLit
+%type <castTypes> castType
+%type <dummyValue> qlfile query selectExp createExp insertExp deleteExp updateExp dropExp
+%type <identifierToken> namedCollection collectionIterator typeName attributeIdent pyrName
+ marrayVariable condenseVariable
+
+// literal data
+%type <qtDataValue> generalLit mddLit oidLit
+%type <qtScalarDataValue> scalarLit
+%type <qtAtomicDataValue> atomicLit
+%type <qtComplexDataValue> complexLit
+%type <qtScalarDataListValue> scalarLitList dimensionLitList
+
+// marray2 with multiple intervals
+%type <mddIntervalListType> ivList
+%type <mddIntervalType> iv marray_head
+
+%% // rules section
+/*--------------------------------------------------------------------
+ * Grammar starts here
+ *--------------------------------------------------------------------
+ */
+
+qlfile: query
+ {
+ // clear all symbols in table at the end of parsing
+ QueryTree::symtab.wipe();
+ };
+
+query: createExp
+ | dropExp
+ | selectExp
+ | updateExp
+ | insertExp
+ | deleteExp;
+
+
+createExp: CREATE COLLECTION namedCollection typeName
+ {
+ try {
+ accessControl.wantToWrite();
+ }
+ catch(...) {
+ // save the parse error info and stop the parser
+ if ( parseError ) delete parseError;
+ parseError = new ParseInfo( 803, $2.info->getToken().c_str(),
+ $2.info->getLineNo(), $2.info->getColumnNo() );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($3)
+ FREESTACK($4)
+ QueryTree::symtab.wipe();
+ YYABORT;
+ }
+
+ // create the command node
+ QtCommand* commandNode = new QtCommand( QtCommand::QT_CREATE_COLLECTION, $3.value, $4.value );
+ commandNode->setParseInfo( *($1.info) );
+
+ // set insert node as root of the Query Tree
+ parseQueryTree->setRoot( commandNode );
+
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($3)
+ FREESTACK($4)
+ };
+
+dropExp: DROP COLLECTION namedCollection
+ {
+ try {
+ accessControl.wantToWrite();
+ }
+ catch(...) {
+ // save the parse error info and stop the parser
+ if ( parseError ) delete parseError;
+ parseError = new ParseInfo( 803, $2.info->getToken().c_str(),
+ $2.info->getLineNo(), $2.info->getColumnNo() );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($3)
+ QueryTree::symtab.wipe();
+ YYABORT;
+ }
+
+ // create the command node
+ QtCommand* commandNode = new QtCommand( QtCommand::QT_DROP_COLLECTION, $3.value );
+ commandNode->setParseInfo( *($1.info) );
+
+ // set insert node as root of the Query Tree
+ parseQueryTree->setRoot( commandNode );
+
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($3)
+ };
+
+selectExp: SELECT resultList FROM collectionList WHERE generalExp
+ {
+ try {
+ accessControl.wantToRead();
+ }
+ catch(...) {
+ // save the parse error info and stop the parser
+ if ( parseError ) delete parseError;
+ parseError = new ParseInfo( 803, $1.info->getToken().c_str(),
+ $1.info->getLineNo(), $1.info->getColumnNo() );
+ FREESTACK($1)
+ FREESTACK($3)
+ FREESTACK($5)
+ QueryTree::symtab.wipe();
+ YYABORT;
+ }
+
+ for( QtIterator::QtONCStreamList::iterator iter=$4->begin(); iter!=$4->end(); iter++ )
+ parseQueryTree->removeDynamicObject( *iter );
+
+ // create a JoinIterator
+ QtJoinIterator* ji = new QtJoinIterator();
+ ji->setStreamInputs( $4 );
+ parseQueryTree->removeDynamicObject( $4 );
+
+ // create a QtONCStreamList and add the Join Iterator
+ QtIterator::QtONCStreamList* inputListS = new QtIterator::QtONCStreamList(1);
+ (*inputListS)[0] = ji;
+
+ // create a SelectionIterator
+ QtSelectionIterator* si = new QtSelectionIterator();
+ si->setStreamInputs( inputListS );
+ si->setParseInfo( *($5.info) );
+ si->setConditionTree( $6 );
+ parseQueryTree->removeDynamicObject( $6 );
+
+ // create a QtONCStreamList and add the Selection Iterator
+ QtIterator::QtONCStreamList* inputListO = new QtIterator::QtONCStreamList(1);
+ (*inputListO)[0] = si;
+
+ // create a OperationIterator and set its inputs
+ QtOperationIterator* oi = new QtOperationIterator();
+ oi->setStreamInputs( inputListO );
+ oi->setParseInfo( *($1.info) );
+ oi->setOperationTree( $2 );
+ parseQueryTree->removeDynamicObject( $2 );
+
+ // set the OperationIterator as root of the Query Tree
+ parseQueryTree->setRoot( oi );
+
+ FREESTACK($1)
+ FREESTACK($3)
+ FREESTACK($5)
+ }
+ | SELECT resultList FROM collectionList
+ {
+ try {
+ accessControl.wantToRead();
+ }
+ catch(...) {
+ // save the parse error info and stop the parser
+ if ( parseError ) delete parseError;
+ parseError = new ParseInfo( 803, $1.info->getToken().c_str(),
+ $1.info->getLineNo(), $1.info->getColumnNo() );
+ FREESTACK($1)
+ FREESTACK($3)
+ QueryTree::symtab.wipe();
+ YYABORT;
+ }
+
+ for( QtIterator::QtONCStreamList::iterator iter=$4->begin(); iter!=$4->end(); iter++ )
+ parseQueryTree->removeDynamicObject( *iter );
+
+ // create a JoinIterator
+ QtJoinIterator* ji = new QtJoinIterator();
+ ji->setStreamInputs( $4 );
+ parseQueryTree->removeDynamicObject( $4 );
+
+ // create a QtONCStreamList and add the Join Iterator
+ QtIterator::QtONCStreamList* inputList = new QtIterator::QtONCStreamList(1);
+ (*inputList)[0] = ji;
+
+ // create a OperationIterator and set its inputs
+ QtOperationIterator* oi = new QtOperationIterator();
+ oi->setStreamInputs( inputList );
+ oi->setParseInfo( *($1.info) );
+ oi->setOperationTree( $2 );
+ parseQueryTree->removeDynamicObject( $2 );
+
+ // set the OperationIterator as root of the Query Tree
+ parseQueryTree->setRoot( oi );
+
+ FREESTACK($1)
+ FREESTACK($3)
+ };
+
+updateExp: UPDATE iteratedCollection SET updateSpec ASSIGN generalExp WHERE generalExp
+ {
+ try {
+ accessControl.wantToWrite();
+ }
+ catch(...) {
+ // save the parse error info and stop the parser
+ if ( parseError ) delete parseError;
+ parseError = new ParseInfo( 803, $1.info->getToken().c_str(),
+ $1.info->getLineNo(), $1.info->getColumnNo() );
+ FREESTACK($1)
+ FREESTACK($3)
+ FREESTACK($5)
+ FREESTACK($7)
+ QueryTree::symtab.wipe();
+ YYABORT;
+ }
+
+ // create a QtONCStreamList and add the QtAccess object of collection Spec
+ QtIterator::QtONCStreamList* streamList = new QtIterator::QtONCStreamList(1);
+ (*streamList)[0] = $2;
+ parseQueryTree->removeDynamicObject( $2 );
+
+ // create a SelectionIterator
+ QtSelectionIterator* si = new QtSelectionIterator();
+ si->setStreamInputs( streamList );
+ si->setConditionTree( $8 );
+ si->setParseInfo( *($7.info) );
+ parseQueryTree->removeDynamicObject( $8 );
+
+ // create an update node
+ QtUpdate* update = new QtUpdate( $4.iterator, $4.domain, $6 );
+ update->setStreamInput( si );
+ update->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $4.iterator );
+ parseQueryTree->removeDynamicObject( $4.domain );
+ parseQueryTree->removeDynamicObject( $6 );
+
+ // set the update node as root of the Query Tree
+ parseQueryTree->setRoot( update );
+
+ FREESTACK($1)
+ FREESTACK($3)
+ FREESTACK($5)
+ FREESTACK($7)
+ }
+ | UPDATE iteratedCollection SET updateSpec ASSIGN generalExp
+ {
+ try {
+ accessControl.wantToWrite();
+ }
+ catch(...) {
+ // save the parse error info and stop the parser
+ if ( parseError ) delete parseError;
+ parseError = new ParseInfo( 803, $1.info->getToken().c_str(),
+ $1.info->getLineNo(), $1.info->getColumnNo() );
+ FREESTACK($1)
+ FREESTACK($3)
+ FREESTACK($5)
+ QueryTree::symtab.wipe();
+ YYABORT;
+ }
+
+ // create an update node
+ QtUpdate* update = new QtUpdate( $4.iterator, $4.domain, $6 );
+ update->setStreamInput( $2 );
+ update->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $2 );
+ parseQueryTree->removeDynamicObject( $4.iterator );
+ parseQueryTree->removeDynamicObject( $4.domain );
+ parseQueryTree->removeDynamicObject( $6 );
+
+ // set the update node as root of the Query Tree
+ parseQueryTree->setRoot( update );
+
+ FREESTACK($1)
+ FREESTACK($3)
+ FREESTACK($5)
+ };
+
+insertExp: INSERT INTO namedCollection VALUES generalExp
+ {
+ try {
+ accessControl.wantToWrite();
+ }
+ catch(...) {
+ // save the parse error info and stop the parser
+ if ( parseError ) delete parseError;
+ parseError = new ParseInfo( 803, $2.info->getToken().c_str(),
+ $2.info->getLineNo(), $2.info->getColumnNo() );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($3)
+ FREESTACK($4)
+ QueryTree::symtab.wipe();
+ YYABORT;
+ }
+
+ // create an update node
+ QtInsert* insert = new QtInsert( $3.value, $5 );
+ insert->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $5 );
+
+ // set insert node as root of the Query Tree
+ parseQueryTree->setRoot( insert );
+
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($3)
+ FREESTACK($4)
+ };
+
+deleteExp: DELETE FROM iteratedCollection WHERE generalExp
+ {
+ try {
+ accessControl.wantToWrite();
+ }
+ catch(...) {
+ // save the parse error info and stop the parser
+ if ( parseError ) delete parseError;
+ parseError = new ParseInfo( 803, $2.info->getToken().c_str(),
+ $2.info->getLineNo(), $2.info->getColumnNo() );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ QueryTree::symtab.wipe();
+ YYABORT;
+ }
+
+ // create a QtONCStreamList and add the QtAccess object of collection Spec
+ QtIterator::QtONCStreamList* streamList = new QtIterator::QtONCStreamList(1);
+ (*streamList)[0] = $3;
+ parseQueryTree->removeDynamicObject( $3 );
+
+ // create a SelectionIterator
+ QtSelectionIterator* si = new QtSelectionIterator();
+ si->setStreamInputs( streamList );
+ si->setConditionTree( $5 );
+ si->setParseInfo( *($4.info) );
+ parseQueryTree->removeDynamicObject( $5 );
+
+ // create delete node
+ QtDelete* delNode = new QtDelete();
+ delNode->setStreamInput( si );
+ delNode->setParseInfo( *($1.info) );
+
+ // set insert node as root of the Query Tree
+ parseQueryTree->setRoot( delNode );
+
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ }
+/* // doesn't work yet, somewhere later the server crashes -- PB 2006-jan-03
+ | DELETE FROM iteratedCollection
+ {
+ try {
+ accessControl.wantToWrite();
+ }
+ catch(...) {
+ // save the parse error info and stop the parser
+ if ( parseError ) delete parseError;
+ parseError = new ParseInfo( 803, $2.info->getToken().c_str(),
+ $2.info->getLineNo(), $2.info->getColumnNo() );
+ FREESTACK($1)
+ FREESTACK($2)
+ QueryTree::symtab.wipe();
+ YYABORT;
+ }
+
+ // create delete node
+ QtDelete* delNode = new QtDelete();
+ delNode->setStreamInput( $3 );
+ delNode->setParseInfo( *($1.info) );
+
+ // set insert node as root of the Query Tree
+ parseQueryTree->setRoot( delNode );
+
+ FREESTACK($1)
+ FREESTACK($2)
+ }
+*/
+ ;
+
+updateSpec: variable
+ {
+ $$.iterator = $1;
+ $$.domain = 0;
+ }
+ | variable mintervalExp
+ {
+ $$.iterator = $1;
+ $$.domain = $2;
+ };
+
+resultList: resultList COMMA generalExp
+ {
+ $$ = $3;
+ FREESTACK($2)
+ }
+ | generalExp
+ {
+ $$ = $1;
+ };
+
+generalExp: mddExp { $$ = $1; }
+ | trimExp { $$ = $1; }
+ | reduceExp { $$ = $1; }
+ | inductionExp { $$ = $1; }
+ | functionExp { $$ = $1; }
+ | integerExp { $$ = $1; }
+ | condenseExp { $$ = $1; }
+ | variable { $$ = $1; }
+ | mintervalExp { $$ = $1; }
+ | intervalExp { $$ = $1; }
+ | generalLit
+ {
+ $$ = new QtConst( $1 );
+ parseQueryTree->removeDynamicObject( $1 );
+ parseQueryTree->addDynamicObject( $$ );
+ };
+
+integerExp: generalExp DOT LO
+ {
+ $$ = new QtIntervalLoOp( $1 );
+ $$->setParseInfo( *($3.info) );
+ parseQueryTree->removeDynamicObject( $1 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($2)
+ FREESTACK($3)
+ }
+ | generalExp DOT HI
+ {
+ $$ = new QtIntervalHiOp( $1 );
+ $$->setParseInfo( *($3.info) );
+ parseQueryTree->removeDynamicObject( $1 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($2)
+ FREESTACK($3)
+ };
+
+mintervalExp: LEPAR spatialOpList REPAR
+ {
+ if (($2->size() > 1) ||
+ ($2->size() == 1 && (*$2)[0]->getNodeType() == QtNode::QT_INTERVALOP))
+ {
+ // Check if the list consists of integers only and
+ // create a point operation in this case.
+ int isPoint = 1;
+ QtNode::QtOperationList::iterator iter;
+
+ for( iter=$2->begin(); iter!=$2->end(); ++iter )
+ isPoint &= (*iter)->getNodeType() != QtNode::QT_INTERVALOP;
+
+ for( iter=$2->begin(); iter!=$2->end(); ++iter )
+ parseQueryTree->removeDynamicObject( *iter );
+
+ if( isPoint )
+ $$ = new QtPointOp( $2 );
+ else
+ $$ = new QtMintervalOp( $2 );
+
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->addDynamicObject( $$ );
+ }
+ else
+ if ($2->size() == 1)
+ {
+ // take the single element
+ $$ = (*$2)[0];
+ (*$2)[0] = 0;
+ delete $2;
+ }
+ else
+ {
+ RMInit::logOut << "MINTERVAL error: empty expression between brackets encountered!" << std::endl;
+ // save the parse error info and stop the parser
+ if ( parseError )
+ delete parseError;
+ // TODO: Define an error number for this one!!!! 312 is not correct.
+ parseError = new ParseInfo( 312, $1.info->getToken().c_str(),
+ $1.info->getLineNo(),
+ $1.info->getColumnNo() );
+ FREESTACK($1)
+ FREESTACK($3)
+ QueryTree::symtab.wipe();
+ YYABORT;
+ }
+ FREESTACK($1)
+ FREESTACK($3)
+ }
+ | SDOM LRPAR collectionIterator RRPAR
+ {
+ QtVariable* var = new QtVariable( $3.value );
+ var->setParseInfo( *($3.info) );
+ $$ = new QtSDom( var );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($3)
+ FREESTACK($4)
+ };
+
+spatialOpList:
+ {
+ $$ = new QtNode::QtOperationList();
+ }
+ | spatialOpList2
+ {
+ $$ = $1;
+ };
+
+spatialOpList2: spatialOpList2 COMMA spatialOp
+ {
+ $1->push_back( $3 );
+ $$ = $1;
+ FREESTACK($2)
+ }
+ | spatialOp
+ {
+ $$ = new QtNode::QtOperationList(1);
+ (*$$)[0] = $1;
+ };
+
+spatialOp: generalExp { $$ = $1; };
+
+intervalExp: generalExp COLON generalExp
+ {
+ $$ = new QtIntervalOp( $1, $3 );
+ $$->setParseInfo( *($2.info) );
+ parseQueryTree->removeDynamicObject( $1 );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($2)
+ }
+ | MULT COLON generalExp
+ {
+ QtConst* const1 = new QtConst( new QtStringData("*") );
+ const1->setParseInfo( *($1.info) );
+ $$ = new QtIntervalOp( const1, $3 );
+ $$->setParseInfo( *($2.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ }
+ | generalExp COLON MULT
+ {
+ QtConst* const1 = new QtConst( new QtStringData("*") );
+ const1->setParseInfo( *($3.info) );
+ $$ = new QtIntervalOp( $1, const1 );
+ $$->setParseInfo( *($2.info) );
+ parseQueryTree->removeDynamicObject( $1 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($2)
+ FREESTACK($3)
+ }
+ | MULT COLON MULT
+ {
+ QtConst* const1 = new QtConst( new QtStringData("*") );
+ const1->setParseInfo( *($1.info) );
+ QtConst* const2 = new QtConst( new QtStringData("*") );
+ const2->setParseInfo( *($3.info) );
+ $$ = new QtIntervalOp( const1, const2 );
+ $$->setParseInfo( *($2.info) );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($3)
+ };
+
+condenseExp: CONDENSE condenseOpLit OVER condenseVariable IN generalExp WHERE generalExp USING generalExp
+ {
+ $$ = new QtCondenseOp( $2, $4.value, $6, $10, $8 );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $6 );
+ parseQueryTree->removeDynamicObject( $8 );
+ parseQueryTree->removeDynamicObject( $10 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($3)
+ FREESTACK($4)
+ FREESTACK($5)
+ FREESTACK($7)
+ FREESTACK($9)
+ }
+ | CONDENSE condenseOpLit OVER condenseVariable IN generalExp USING generalExp
+ {
+ $$ = new QtCondenseOp( $2, $4.value, $6, $8 );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $6 );
+ parseQueryTree->removeDynamicObject( $8 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($3)
+ FREESTACK($4)
+ FREESTACK($5)
+ FREESTACK($7)
+ };
+
+condenseOpLit: PLUS
+ {
+ $$ = Ops::OP_PLUS;
+ FREESTACK($1)
+ }
+ | MINUS
+ {
+ $$ = Ops::OP_MINUS;
+ FREESTACK($1)
+ }
+ | MULT
+ {
+ $$ = Ops::OP_MULT;
+ FREESTACK($1)
+ }
+ | DIV
+ {
+ $$ = Ops::OP_DIV;
+ FREESTACK($1)
+ }
+ | AND
+ {
+ $$ = Ops::OP_AND;
+ FREESTACK($1)
+ }
+ | OR
+ {
+ $$ = Ops::OP_OR;
+ FREESTACK($1)
+ };
+
+functionExp: OID LRPAR collectionIterator RRPAR
+ {
+ QtVariable* var = new QtVariable( $3.value );
+ var->setParseInfo( *($3.info) );
+ $$ = new QtOId( var );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($3)
+ FREESTACK($4)
+ }
+ | SHIFT LRPAR generalExp COMMA generalExp RRPAR
+ {
+ $$ = new QtShift( $3, $5 );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->removeDynamicObject( $5 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ FREESTACK($6)
+ }
+ // added -- PB 2005-jun-18
+ | EXTEND LRPAR generalExp COMMA generalExp RRPAR
+ {
+ $$ = new QtExtend( $3, $5 );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->removeDynamicObject( $5 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ FREESTACK($6)
+ }
+ | SCALE LRPAR generalExp COMMA generalExp RRPAR
+ {
+ $$ = new QtScale( $3, $5 );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->removeDynamicObject( $5 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ FREESTACK($6)
+ }
+ | BIT LRPAR generalExp COMMA generalExp RRPAR
+ {
+ $$ = new QtBit( $3, $5 );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->removeDynamicObject( $5 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ FREESTACK($6)
+ }
+ | TIFF LRPAR generalExp COMMA StringLit RRPAR
+ {
+ $$ = new QtConversion( $3, QtConversion::QT_TOTIFF, $5.value );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ FREESTACK($6)
+ }
+ | TIFF LRPAR generalExp RRPAR
+ {
+ $$ = new QtConversion( $3, QtConversion::QT_TOTIFF );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ }
+ | BMP LRPAR generalExp COMMA StringLit RRPAR
+ {
+ $$ = new QtConversion( $3, QtConversion::QT_TOBMP, $5.value );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ FREESTACK($6)
+ }
+ | BMP LRPAR generalExp RRPAR
+ {
+ $$ = new QtConversion( $3, QtConversion::QT_TOBMP );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ }
+ | HDF LRPAR generalExp COMMA StringLit RRPAR
+ {
+ $$ = new QtConversion( $3, QtConversion::QT_TOHDF, $5.value );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ FREESTACK($6)
+ }
+ | HDF LRPAR generalExp RRPAR
+ {
+ $$ = new QtConversion( $3, QtConversion::QT_TOHDF );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ }
+ | CSV LRPAR generalExp COMMA StringLit RRPAR
+ {
+ $$ = new QtConversion( $3, QtConversion::QT_TOCSV, $5.value );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ FREESTACK($6)
+ }
+ | CSV LRPAR generalExp RRPAR
+ {
+ $$ = new QtConversion( $3, QtConversion::QT_TOCSV );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ }
+ | JPEG LRPAR generalExp COMMA StringLit RRPAR
+ {
+ $$ = new QtConversion( $3, QtConversion::QT_TOJPEG, $5.value );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ FREESTACK($6)
+ }
+ | JPEG LRPAR generalExp RRPAR
+ {
+ $$ = new QtConversion( $3, QtConversion::QT_TOJPEG );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ }
+ | PNG LRPAR generalExp COMMA StringLit RRPAR
+ {
+ $$ = new QtConversion( $3, QtConversion::QT_TOPNG, $5.value );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ FREESTACK($6)
+ }
+ | PNG LRPAR generalExp RRPAR
+ {
+ $$ = new QtConversion( $3, QtConversion::QT_TOPNG );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ }
+ | VFF LRPAR generalExp COMMA StringLit RRPAR
+ {
+ $$ = new QtConversion( $3, QtConversion::QT_TOVFF, $5.value );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ FREESTACK($6)
+ }
+ | VFF LRPAR generalExp RRPAR
+ {
+ $$ = new QtConversion( $3, QtConversion::QT_TOVFF );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ }
+ | TOR LRPAR generalExp COMMA StringLit RRPAR
+ {
+ $$ = new QtConversion( $3, QtConversion::QT_TOTOR, $5.value );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ FREESTACK($6)
+ }
+ | TOR LRPAR generalExp RRPAR
+ {
+ $$ = new QtConversion( $3, QtConversion::QT_TOTOR );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ }
+ | DEM LRPAR generalExp COMMA StringLit RRPAR
+ {
+ $$ = new QtConversion( $3, QtConversion::QT_TODEM, $5.value );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ FREESTACK($6)
+ }
+ | DEM LRPAR generalExp RRPAR
+ {
+ $$ = new QtConversion( $3, QtConversion::QT_TODEM );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ }
+ | INV_TIFF LRPAR generalExp COMMA StringLit RRPAR
+ {
+ $$ = new QtConversion( $3, QtConversion::QT_FROMTIFF, $5.value );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ FREESTACK($6)
+ }
+ | INV_TIFF LRPAR generalExp RRPAR
+ {
+ $$ = new QtConversion( $3, QtConversion::QT_FROMTIFF );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ }
+ | INV_BMP LRPAR generalExp COMMA StringLit RRPAR
+ {
+ $$ = new QtConversion( $3, QtConversion::QT_FROMBMP, $5.value );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ FREESTACK($6)
+ }
+ | INV_BMP LRPAR generalExp RRPAR
+ {
+ $$ = new QtConversion( $3, QtConversion::QT_FROMBMP );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ }
+ | INV_HDF LRPAR generalExp COMMA StringLit RRPAR
+ {
+ $$ = new QtConversion( $3, QtConversion::QT_FROMHDF, $5.value );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ FREESTACK($6)
+ }
+ | INV_HDF LRPAR generalExp RRPAR
+ {
+ $$ = new QtConversion( $3, QtConversion::QT_FROMHDF );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ }
+ | INV_CSV LRPAR generalExp COMMA StringLit RRPAR
+ {
+ $$ = new QtConversion( $3, QtConversion::QT_FROMCSV, $5.value );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ FREESTACK($6)
+ }
+ | INV_CSV LRPAR generalExp RRPAR
+ {
+ $$ = new QtConversion( $3, QtConversion::QT_FROMCSV );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ }
+ | INV_JPEG LRPAR generalExp COMMA StringLit RRPAR
+ {
+ $$ = new QtConversion( $3, QtConversion::QT_FROMJPEG, $5.value );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ FREESTACK($6)
+ }
+ | INV_JPEG LRPAR generalExp RRPAR
+ {
+ $$ = new QtConversion( $3, QtConversion::QT_FROMJPEG );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ }
+ | INV_PNG LRPAR generalExp COMMA StringLit RRPAR
+ {
+ $$ = new QtConversion( $3, QtConversion::QT_FROMPNG, $5.value );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ FREESTACK($6)
+ }
+ | INV_PNG LRPAR generalExp RRPAR
+ {
+ $$ = new QtConversion( $3, QtConversion::QT_FROMPNG );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ }
+ | INV_VFF LRPAR generalExp COMMA StringLit RRPAR
+ {
+ $$ = new QtConversion( $3, QtConversion::QT_FROMVFF, $5.value );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ FREESTACK($6)
+ }
+ | INV_VFF LRPAR generalExp RRPAR
+ {
+ $$ = new QtConversion( $3, QtConversion::QT_FROMVFF );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ }
+ | INV_TOR LRPAR generalExp COMMA StringLit RRPAR
+ {
+ $$ = new QtConversion( $3, QtConversion::QT_FROMTOR, $5.value );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ FREESTACK($6)
+ }
+ | INV_TOR LRPAR generalExp RRPAR
+ {
+ $$ = new QtConversion( $3, QtConversion::QT_FROMTOR );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ }
+ | INV_DEM LRPAR generalExp COMMA StringLit RRPAR
+ {
+ $$ = new QtConversion( $3, QtConversion::QT_FROMDEM, $5.value );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ FREESTACK($6)
+ }
+ | INV_DEM LRPAR generalExp RRPAR
+ {
+ $$ = new QtConversion( $3, QtConversion::QT_FROMDEM );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ };
+
+
+structSelection: DOT attributeIdent
+ {
+ $$ = new QtDot( $2.value );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ }
+ | DOT intLitExp
+ {
+ if( $2.negative )
+ if( $2.svalue < 0 )
+ yyerror("non negative integer expected");
+ else
+ $$ = new QtDot( (unsigned int)$2.svalue );
+ else
+ $$ = new QtDot( (unsigned int)$2.uvalue );
+ parseQueryTree->addDynamicObject( $$ );
+ $$->setParseInfo( *($1.info) );
+ FREESTACK($1)
+ FREESTACK($2)
+ };
+
+inductionExp: SQRT LRPAR generalExp RRPAR
+ {
+ $$ = new QtSqrt( $3 );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ }
+ | ABS LRPAR generalExp RRPAR
+ {
+ $$ = new QtAbs( $3 );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ }
+ | EXP LRPAR generalExp RRPAR
+ {
+ $$ = new QtExp( $3 );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ }
+ | LOG LRPAR generalExp RRPAR
+ {
+ $$ = new QtLog( $3 );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ }
+ | LN LRPAR generalExp RRPAR
+ {
+ $$ = new QtLn( $3 );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ }
+ | SIN LRPAR generalExp RRPAR
+ {
+ $$ = new QtSin( $3 );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ }
+ | COS LRPAR generalExp RRPAR
+ {
+ $$ = new QtCos( $3 );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ }
+ | TAN LRPAR generalExp RRPAR
+ {
+ $$ = new QtTan( $3 );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ }
+ | SINH LRPAR generalExp RRPAR
+ {
+ $$ = new QtSinh( $3 );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ }
+ | COSH LRPAR generalExp RRPAR
+ {
+ $$ = new QtCosh( $3 );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ }
+ | TANH LRPAR generalExp RRPAR
+ {
+ $$ = new QtTanh( $3 );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ }
+ | ARCSIN LRPAR generalExp RRPAR
+ {
+ $$ = new QtArcsin( $3 );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ }
+ | ARCCOS LRPAR generalExp RRPAR
+ {
+ $$ = new QtArccos( $3 );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ }
+ | ARCTAN LRPAR generalExp RRPAR
+ {
+ $$ = new QtArctan( $3 );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ }
+ | generalExp DOT RE
+ {
+ $$ = new QtRealPartOp( $1 );
+ $$->setParseInfo( *($3.info) );
+ parseQueryTree->removeDynamicObject( $1 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($2)
+ FREESTACK($3)
+ }
+ | generalExp DOT IM
+ {
+ $$ = new QtImaginarPartOp( $1 );
+ $$->setParseInfo( *($3.info) );
+ parseQueryTree->removeDynamicObject( $1 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($2)
+ FREESTACK($3)
+ }
+ | NOT generalExp
+ {
+ $$ = new QtNot( $2 );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->removeDynamicObject( $2 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ }
+ | generalExp OVERLAY generalExp
+ {
+ $$ = new QtOverlay ( $3, $1 );
+ $$->setParseInfo( *($2.info) );
+ FREESTACK($2)
+ parseQueryTree->removeDynamicObject( $1 );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ }
+ | generalExp IS generalExp
+ {
+ $$ = new QtIs ( $1, $3 );
+ $$->setParseInfo( *($2.info) );
+ parseQueryTree->removeDynamicObject( $1 );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($2)
+ }
+ | generalExp AND generalExp
+ {
+ $$ = new QtAnd( $1, $3 );
+ $$->setParseInfo( *($2.info) );
+ parseQueryTree->removeDynamicObject( $1 );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($2)
+ }
+ | generalExp OR generalExp
+ {
+ $$ = new QtOr ( $1, $3 );
+ $$->setParseInfo( *($2.info) );
+ parseQueryTree->removeDynamicObject( $1 );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($2)
+ }
+ | generalExp XOR generalExp
+ {
+ $$ = new QtXor( $1, $3 );
+ $$->setParseInfo( *($2.info) );
+ parseQueryTree->removeDynamicObject( $1 );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($2)
+ }
+ | generalExp PLUS generalExp
+ {
+ $$ = new QtPlus ( $1, $3 );
+ $$->setParseInfo( *($2.info) );
+ parseQueryTree->removeDynamicObject( $1 );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($2)
+ }
+ | generalExp MINUS generalExp
+ {
+ $$ = new QtMinus( $1, $3 );
+ $$->setParseInfo( *($2.info) );
+ parseQueryTree->removeDynamicObject( $1 );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($2)
+ }
+ | generalExp MULT generalExp
+ {
+ $$ = new QtMult ( $1, $3 );
+ $$->setParseInfo( *($2.info) );
+ parseQueryTree->removeDynamicObject( $1 );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($2)
+ }
+ | generalExp DIV generalExp
+ {
+ $$ = new QtDiv ( $1, $3 );
+ $$->setParseInfo( *($2.info) );
+ parseQueryTree->removeDynamicObject( $1 );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($2)
+ }
+ | generalExp EQUAL generalExp
+ {
+ $$ = new QtEqual( $1, $3 );
+ $$->setParseInfo( *($2.info) );
+ FREESTACK($2)
+ parseQueryTree->removeDynamicObject( $1 );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ }
+ | generalExp LESS generalExp
+ {
+ $$ = new QtLess( $1, $3 );
+ $$->setParseInfo( *($2.info) );
+ parseQueryTree->removeDynamicObject( $1 );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($2)
+ }
+ | generalExp GREATER generalExp
+ {
+ $$ = new QtLess( $3, $1 );
+ $$->setParseInfo( *($2.info) );
+ parseQueryTree->removeDynamicObject( $1 );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($2)
+ }
+ | generalExp LESSEQUAL generalExp
+ {
+ $$ = new QtLessEqual( $1, $3 );
+ $$->setParseInfo( *($2.info) );
+ parseQueryTree->removeDynamicObject( $1 );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($2)
+ }
+ | generalExp GREATEREQUAL generalExp
+ {
+ $$ = new QtLessEqual( $3, $1 );
+ $$->setParseInfo( *($2.info) );
+ parseQueryTree->removeDynamicObject( $1 );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($2)
+ }
+ | generalExp NOTEQUAL generalExp
+ {
+ $$ = new QtNotEqual ( $1, $3 );
+ $$->setParseInfo( *($2.info) );
+ parseQueryTree->removeDynamicObject( $1 );
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($2)
+ }
+ | PLUS generalExp %prec UNARYOP
+ {
+ $$ = $2;
+ FREESTACK($1)
+ }
+ | MINUS generalExp %prec UNARYOP
+ {
+ $$ = new QtMult( $2, new QtConst( new QtAtomicData( (r_Long)-1, 1 ) ) );
+ parseQueryTree->removeDynamicObject( $2 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ }
+ | LRPAR castType RRPAR generalExp %prec UNARYOP
+ {
+ $$ = new QtCast($4, $2.qtCastType);
+ $$->setParseInfo( *($2.info) );
+ parseQueryTree->removeDynamicObject($4);
+ parseQueryTree->addDynamicObject($$);
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($3)
+ }
+ | LRPAR generalExp RRPAR
+ {
+ $$ = $2;
+ FREESTACK($1)
+ FREESTACK($3)
+ }
+ | generalExp structSelection
+ {
+ $2->setInput($1);
+ $$ = $2;
+ parseQueryTree->removeDynamicObject( $1 );
+ };
+
+castType: TBOOL { $$.info = $1.info; $$.qtCastType = QtCast::t_bool; }
+ | TCHAR { $$.info = $1.info; $$.qtCastType = QtCast::t_char; }
+ | TOCTET { $$.info = $1.info; $$.qtCastType = QtCast::t_octet; }
+ | TSHORT { $$.info = $1.info; $$.qtCastType = QtCast::t_short; }
+ | TUSHORT { $$.info = $1.info; $$.qtCastType = QtCast::t_ushort; }
+ | TLONG { $$.info = $1.info; $$.qtCastType = QtCast::t_long; }
+ | TULONG { $$.info = $1.info; $$.qtCastType = QtCast::t_ulong; }
+ | TFLOAT { $$.info = $1.info; $$.qtCastType = QtCast::t_float; }
+ | TDOUBLE { $$.info = $1.info; $$.qtCastType = QtCast::t_double; }
+ | TUNSIG TSHORT { $$.info = $1.info; $$.qtCastType = QtCast::t_ushort; }
+ | TUNSIG TLONG { $$.info = $1.info; $$.qtCastType = QtCast::t_ulong; };
+
+collectionList: collectionList COMMA iteratedCollection
+ {
+ // add the QtMDDAccess object and give back the list
+ $1->push_back($3);
+ $$ = $1;
+ FREESTACK($2)
+ }
+ | iteratedCollection
+ {
+ // create a new list and add the QtMDDAccess object
+ $$ = new QtIterator::QtONCStreamList();
+ $$->push_back($1);
+ parseQueryTree->addDynamicObject( $$ );
+ };
+
+iteratedCollection: namedCollection AS collectionIterator
+ {
+ $$ = new QtMDDAccess( $1.value, $3.value );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($3)
+ }
+ | namedCollection collectionIterator
+ {
+ $$ = new QtMDDAccess( $1.value, $2.value );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ }
+ | namedCollection
+ {
+ $$ = new QtMDDAccess( $1.value, $1.value );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ };
+
+variable: Identifier
+ {
+ $$ = new QtVariable( $1.value );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ };
+
+namedCollection: Identifier;
+
+collectionIterator: Identifier;
+
+pyrName: Identifier;
+
+attributeIdent: Identifier;
+
+typeName: Identifier;
+
+marrayVariable: Identifier;
+
+condenseVariable: Identifier;
+
+reduceExp: reduceIdent LRPAR generalExp RRPAR
+ {
+ $1->setInput( $3 );
+ $$ = $1;
+ parseQueryTree->removeDynamicObject( $3 );
+ FREESTACK($2)
+ FREESTACK($4)
+ };
+
+reduceIdent: ALL
+ {
+ $$ = new QtAll();
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ }
+ | SOME
+ {
+ $$ = new QtSome();
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ }
+ | COUNTCELLS
+ {
+ $$ = new QtCountCells();
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ }
+ | ADDCELLS
+ {
+ $$ = new QtAddCells();
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ }
+ | AVGCELLS
+ {
+ $$ = new QtAvgCells();
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ }
+ | MINCELLS
+ {
+ $$ = new QtMinCells();
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ }
+ | MAXCELLS
+ {
+ $$ = new QtMaxCells();
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ };
+
+intLitExp: IntegerLit { $$ = $1; };
+
+generalLit: scalarLit { $$ = $1; }
+ | mddLit { $$ = $1; }
+ | StringLit
+ {
+ $$ = new QtStringData( std::string($1.value) );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ }
+ | oidLit { $$ = $1; };
+
+oidLit: LESS StringLit GREATER
+ {
+ r_OId oid;
+ try {
+ oid = r_OId( $2.value );
+ }
+ catch(...) {
+ // save the parse error info and stop the parser
+ if ( parseError ) delete parseError;
+ parseError = new ParseInfo( 303, $2.info->getToken().c_str(),
+ $2.info->getLineNo(), $2.info->getColumnNo() );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($3)
+ QueryTree::symtab.wipe();
+ YYABORT;
+ }
+
+ // test if database match the current one
+ int mismatch = oid.get_base_name() == 0;
+
+ if( !mismatch ) {
+ // check for question mark
+ char* baseName = strdup( oid.get_base_name() );
+ char* end = strchr( baseName, '?' );
+ if( end )
+ *end = '\0';
+ mismatch = strcmp( baseName, currentClientTblElt->database.getName() ) !=0;
+ free( baseName );
+ baseName = 0;
+ }
+
+ if( mismatch ) {
+ // save the parse error info and stop the parser
+ if( parseError ) delete parseError;
+ parseError = new ParseInfo( 386, $2.info->getToken().c_str(),
+ $2.info->getLineNo(), $2.info->getColumnNo() );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($3)
+ QueryTree::symtab.wipe();
+ YYABORT;
+ }
+
+ // take the local oid
+ $$ = new QtAtomicData( oid.get_local_oid(), 8 );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($3)
+ };
+
+mddLit: LESS mintervalExp dimensionLitList GREATER
+ {
+ // create a QtMDD object representing the literal
+ try {
+ $$ = new QtMDD( $2, $3 );
+ }
+ catch( ParseInfo& obj ) {
+ delete $3;
+
+ // save the parse error info and stop the parser
+ if( parseError ) delete parseError;
+ parseError = new ParseInfo( obj.getErrorNo(), $1.info->getToken().c_str(),
+ $1.info->getLineNo(), $1.info->getColumnNo() );
+ FREESTACK($1)
+ FREESTACK($4)
+ QueryTree::symtab.wipe();
+ YYABORT;
+ }
+ $$->setParseInfo( *($1.info) );
+
+ for( std::list<QtScalarData*>::iterator iter=$3->begin(); iter!=$3->end(); iter++ ) {
+ delete *iter;
+ parseQueryTree->removeDynamicObject( *iter );
+ }
+
+ delete $2;
+ delete $3;
+ parseQueryTree->removeDynamicObject( $2 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($4)
+ }
+ | MDDPARAM
+ {
+ try {
+ $$ = new QtMDD( $1.value );
+ }
+ catch( ParseInfo& obj ) {
+ // save the parse error info and stop the parser
+ if( parseError ) delete parseError;
+ parseError = new ParseInfo( obj.getErrorNo(), $1.info->getToken().c_str(),
+ $1.info->getLineNo(), $1.info->getColumnNo() );
+ FREESTACK($1)
+ QueryTree::symtab.wipe();
+ YYABORT;
+ }
+ parseQueryTree->addDynamicObject( $$ );
+ $$->setParseInfo( *($1.info) );
+ FREESTACK($1)
+ };
+
+dimensionLitList: dimensionLitList SEMICOLON scalarLitList
+ {
+ // concatenate the lists
+ $1->splice( $1->end(), *$3 );
+ $$ = $1;
+ delete $3;
+ FREESTACK($2)
+ }
+ | scalarLitList
+ {
+ // simply take the list
+ $$ = $1;
+ };
+
+scalarLit: complexLit
+ {
+ $$ = $1;
+ }
+ | atomicLit
+ {
+ $$ = $1;
+ };
+
+atomicLit: BooleanLit
+ {
+ $$ = new QtAtomicData( $1.value );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ }
+ | IntegerLit
+ {
+ if( $1.negative )
+ $$ = new QtAtomicData( $1.svalue, $1.bytes );
+ else
+ $$ = new QtAtomicData( $1.uvalue, $1.bytes );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ }
+ | FloatLit
+ {
+ $$ = new QtAtomicData( $1.value, $1.bytes );
+ $$->setParseInfo( *($1.info) );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ }
+ | COMPLEX LRPAR FloatLit COMMA FloatLit RRPAR
+ {
+ // this should construct a complex type
+ // for both float and double cell type
+ if($3.bytes + $5.bytes == 2 * sizeof(float) || $3.bytes + $5.bytes == 2 * sizeof(double))
+ $$ = new QtAtomicData($3.value, $5.value, $3.bytes + $5.bytes);
+ else {
+ if(parseError) delete parseError;
+ parseError = new ParseInfo(311, $2.info->getToken().c_str(),
+ $2.info->getLineNo(), $2.info->getColumnNo());
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ FREESTACK($6)
+ QueryTree::symtab.wipe();
+ YYABORT;
+ }
+ $$->setParseInfo(*($3.info));
+ parseQueryTree->addDynamicObject($$);
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ FREESTACK($6)
+ };
+
+complexLit: LCPAR scalarLitList RCPAR
+ {
+ for( std::list<QtScalarData*>::iterator iter=$2->begin(); iter!=$2->end(); iter++ )
+ parseQueryTree->removeDynamicObject( *iter );
+ $$ = new QtComplexData( $2 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($3)
+ }
+ | STRCT LCPAR scalarLitList RCPAR
+ {
+ for( std::list<QtScalarData*>::iterator iter=$3->begin(); iter!=$3->end(); iter++ )
+ parseQueryTree->removeDynamicObject( *iter );
+ $$ = new QtComplexData( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($1)
+ FREESTACK($2)
+ FREESTACK($4)
+ };
+
+scalarLitList: scalarLitList COMMA scalarLit
+ {
+ // add the literal element and give back the list
+ $1->push_back($3);
+ $$ = $1;
+ FREESTACK($2)
+ }
+ | scalarLit
+ {
+ // create a new list and add the literal element
+ $$ = new QtComplexData::QtScalarDataList();
+ $$->push_back($1);
+ };
+
+
+
+
+trimExp: generalExp mintervalExp
+ {
+ QtDomainOperation *dop = new QtDomainOperation( $2 );
+ dop->setInput( $1 ); // e.g. variable name
+ parseQueryTree->removeDynamicObject( $1 );
+ parseQueryTree->removeDynamicObject( $2 );
+ parseQueryTree->addDynamicObject( dop );
+ $$ = dop;
+ if (mflag == MF_IN_CONTEXT)
+ parseQueryTree->addDomainObject( dop );
+ };
+
+marray_head:
+ MARRAY
+ {
+ mflag = MF_IN_CONTEXT;
+ QueryTree::symtab.initScope();
+ }
+ iv
+ {
+ $$ = $3;
+ $$->parseInfo = *($1.info);
+ FREESTACK($1)
+ };
+
+mddExp: marray_head VALUES generalExp
+ {
+ // create a new list and add the element
+ QtMarrayOp2::mddIntervalListType *dlist = new QtMarrayOp2::mddIntervalListType();
+ dlist->push_back(*($1));
+
+ // concatenate intervals and variable names, then do a domain rewrite
+ QtMarrayOp2 *qma = new QtMarrayOp2( dlist, $3 );
+ qma->setOldMarray(true);
+ qma->rewriteVars( );
+
+ char *stra = strdup( $1->variable.c_str() );
+ $$ = new QtMarrayOp( stra, $1->tree, qma->getInput());
+ parseQueryTree->addCString(stra);
+
+ QueryTree::symtab.exitScope();
+ mflag = MF_NO_CONTEXT;
+
+ // release memory
+ while (!(dlist->empty()))
+ {
+ dlist->erase(dlist->begin());
+ }
+ delete dlist;
+ delete qma;
+ delete $1;
+ parseQueryTree->removeDynamicObject( $3 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($2)
+ }
+ | marray_head COMMA ivList VALUES generalExp
+ {
+ // create a new list and add the element
+ QtMarrayOp2::mddIntervalListType *dlist = new QtMarrayOp2::mddIntervalListType();
+ dlist->push_back(*($1));
+
+ // concatenate the lists
+ dlist->insert(
+ dlist->end(),
+ $3->begin(),
+ $3->end()
+ );
+
+ // concatenate intervals and variable names, then do a domain rewrite
+ QtMarrayOp2 *qma = new QtMarrayOp2( dlist, $5 );
+ qma->setOldMarray(false);
+ qma->rewriteVars( );
+ if (!(qma->concatenateIntervals()))
+ {
+ // TODO: change error code!
+ // save the parse error info and stop the parser
+ if ( parseError )
+ delete parseError;
+ parseError = new ParseInfo( 313, ($1->parseInfo).getToken().c_str(),
+ ($1->parseInfo).getLineNo(),
+ ($1->parseInfo).getColumnNo() );
+ QueryTree::symtab.exitScope();
+ mflag = MF_NO_CONTEXT;
+
+ // release memory
+ while (!(dlist->empty()))
+ {
+ dlist->erase(dlist->begin());
+ }
+ delete dlist;
+ delete qma;
+ delete $1;
+ parseQueryTree->removeDynamicObject( $5 );
+ FREESTACK($2)
+ FREESTACK($4)
+ YYABORT;
+ }
+
+ r_Minterval *dinterval = new r_Minterval(qma->greatDomain);
+ std::string *dvariable = new std::string(qma->greatIterator);
+ parseQueryTree->rewriteDomainObjects(dinterval, dvariable, dlist);
+
+ // initialize old good QtMarray with the translated data
+ QtMintervalData *mddIntervalData = new QtMintervalData(*dinterval);
+ $$ = new QtMarrayOp( dvariable->c_str(), new QtConst(mddIntervalData), qma->getInput());
+// $$->setParseInfo( *($1.info) );
+
+ QueryTree::symtab.exitScope();
+ mflag = MF_NO_CONTEXT;
+
+ // release memory
+ while (!(dlist->empty()))
+ {
+ dlist->erase(dlist->begin());
+ }
+ delete dlist;
+ delete qma;
+ delete $1;
+ parseQueryTree->removeDynamicObject( $5 );
+ parseQueryTree->addDynamicObject( $$ );
+ FREESTACK($2)
+ FREESTACK($4)
+ };
+
+ivList: ivList COMMA iv
+ {
+ // add the element and give back the list
+ $1->push_back(*($3));
+ $$ = $1;
+ delete $3;
+ FREESTACK($2)
+ }
+ | iv
+ {
+ // create a new list and add the element
+ $$ = new QtMarrayOp2::mddIntervalListType();
+ $$->push_back(*($1));
+ delete $1;
+ };
+
+iv: marrayVariable IN generalExp
+ {
+ if (!QueryTree::symtab.putSymbol($1.value, 1)) // instead of 1 put the dimensionality
+ {
+ // save the parse error info and stop the parser
+ if ( parseError )
+ delete parseError;
+ parseError = new ParseInfo( 312, $1.info->getToken().c_str(),
+ $1.info->getLineNo(),
+ $1.info->getColumnNo() );
+ parseQueryTree->removeDynamicObject( $3 );
+ FREESTACK($2)
+ QueryTree::symtab.wipe();
+ YYABORT;
+ }
+ $$ = new QtMarrayOp2::mddIntervalType();
+ $$->variable = $1.value;
+ $$->tree = $3;
+ $$->parseInfo = *($1.info);
+ parseQueryTree->removeDynamicObject( $3 );
+ FREESTACK($2);
+ };
+
+/*--------------------------------------------------------------------
+ * Grammar ends here
+ *--------------------------------------------------------------------
+ */
+%% // C code section
+
+void yyerror( char* /*s*/ ) {
+ if( !parseError ) {
+
+ if( yytext[0] == '\0' ) {
+ // unexpected end of query
+ parseError = new ParseInfo( 308, yytext, lineNo, columnNo - strlen(yytext) );
+ }
+ else {
+ // general parse error
+ parseError = new ParseInfo( 300, yytext, lineNo, columnNo - strlen(yytext) );
+ }
+ }
+}
diff --git a/qlparser/parseinfo.cc b/qlparser/parseinfo.cc
new file mode 100644
index 0000000..d16dad6
--- /dev/null
+++ b/qlparser/parseinfo.cc
@@ -0,0 +1,102 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)qlparser, ParseInfo: $Id: parseinfo.cc,v 1.6 2002/06/19 14:36:23 coman Exp $";
+
+#include <iostream>
+using namespace std;
+
+#include "qlparser/parseinfo.hh"
+
+
+ParseInfo::ParseInfo()
+ : errorNo( 0 ),
+ token( "" ),
+ lineNo( 0 ),
+ columnNo( 0 )
+{
+}
+
+ParseInfo::ParseInfo(const ParseInfo& old)
+ : errorNo( 0 ),
+ token( "" ),
+ lineNo( 0 ),
+ columnNo( 0 )
+{
+ errorNo=old.errorNo;
+ lineNo=old.lineNo;
+ columnNo=old.columnNo;
+ token=old.token;
+}
+
+ParseInfo::ParseInfo( const char* initToken, unsigned int initLineNo, unsigned initColumnNo )
+ : errorNo( 0 ),
+ token( "" ),
+ lineNo( initLineNo ),
+ columnNo( initColumnNo )
+{
+ if(initToken) {
+ token=initToken;
+ }
+}
+
+
+
+ParseInfo::ParseInfo( unsigned long initErrorNo, const char* initToken, unsigned int initLineNo, unsigned initColumnNo )
+ : errorNo( initErrorNo ),
+ token( "" ),
+ lineNo( initLineNo ),
+ columnNo( initColumnNo )
+{
+ if(initToken) {
+ token=initToken;
+ }
+}
+
+ParseInfo&
+ParseInfo::operator=(const ParseInfo& old)
+{
+ if(this != &old) {
+ errorNo=old.errorNo;
+ lineNo=old.lineNo;
+ columnNo=old.columnNo;
+ token=old.token;
+ }
+ return *this;
+}
+
+void
+ParseInfo::printStatus( ostream& s ) const
+{
+ s << "Error number: " << errorNo << " Token: " << token.c_str() << " Line: " << lineNo << " Column: " << columnNo << endl;
+}
+
diff --git a/qlparser/parseinfo.hh b/qlparser/parseinfo.hh
new file mode 100644
index 0000000..7097139
--- /dev/null
+++ b/qlparser/parseinfo.hh
@@ -0,0 +1,111 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#ifndef _PARSEINFO_
+#define _PARSEINFO_
+
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+#endif
+
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+ This class holds some information about a token and its
+ location in the parse string. Additionally, it can keep
+ an error number which is used in the query tree to report
+ error with some context information within the query string.
+
+*/
+
+class ParseInfo
+{
+ public:
+
+ /// default constructor
+ ParseInfo();
+
+ /// constructor getting error number, token and location information
+ ParseInfo( unsigned long errorNo, const char* token, unsigned int lineNo, unsigned columnNo );
+
+ /// copy constructor
+ ParseInfo( const ParseInfo& old);
+
+ /// constructor getting token and location information
+ ParseInfo( const char* token, unsigned int lineNo, unsigned columnNo );
+
+ //@Man: Read/Write methods
+ //@{
+ ///
+ inline unsigned long getErrorNo() const;
+ ///
+ inline const std::string& getToken() const;
+ ///
+ inline unsigned int getLineNo() const;
+ ///
+ inline unsigned int getColumnNo() const;
+ ///
+ inline void setErrorNo( unsigned long errorNo );
+ ///
+ inline void setToken( const std::string& text );
+ ///
+ inline void setToken( const char* text );
+ ///
+ inline void setLineNo( unsigned int lineNo );
+ ///
+ inline void setColumnNo( unsigned int columnNo );
+ ///
+ //@}
+
+ void printStatus( std::ostream& s= std::cout ) const;
+
+ ParseInfo& operator=(const ParseInfo& old);
+
+ private:
+ //@Man: Attributes
+ //@{
+ ///
+ unsigned long errorNo;
+ ///
+ unsigned int lineNo;
+ ///
+ unsigned int columnNo;
+ ///
+ std::string token;
+ ///
+ //@}
+};
+
+#include "parseinfo.icc"
+
+#endif
diff --git a/qlparser/parseinfo.icc b/qlparser/parseinfo.icc
new file mode 100644
index 0000000..91e2dd0
--- /dev/null
+++ b/qlparser/parseinfo.icc
@@ -0,0 +1,100 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+inline
+unsigned long
+ParseInfo::getErrorNo() const
+{
+ return errorNo;
+}
+
+
+
+inline const std::string&
+ParseInfo::getToken() const
+{
+ return token;
+}
+
+
+
+inline
+unsigned int
+ParseInfo::getLineNo() const
+{
+ return lineNo;
+}
+
+
+
+inline unsigned int
+ParseInfo::getColumnNo() const
+{
+ return columnNo;
+}
+
+
+
+inline void
+ParseInfo::setErrorNo( unsigned long newNo )
+{
+ errorNo = newNo;
+}
+
+
+
+inline void
+ParseInfo::setToken( const std::string& text )
+{
+ token = text;
+}
+
+
+
+inline void
+ParseInfo::setToken( const char* text )
+{
+ token = std::string(text);
+}
+
+
+
+inline void
+ParseInfo::setLineNo( unsigned int newNo )
+{
+ lineNo = newNo;
+}
+
+
+
+inline void
+ParseInfo::setColumnNo( unsigned int newNo )
+{
+ columnNo = newNo;
+}
diff --git a/qlparser/qtatomicdata.cc b/qlparser/qtatomicdata.cc
new file mode 100644
index 0000000..a8b12f8
--- /dev/null
+++ b/qlparser/qtatomicdata.cc
@@ -0,0 +1,212 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)qlparser, QtAtomicData: $Header: /home/rasdev/CVS-repository/rasdaman/qlparser/qtatomicdata.cc,v 1.18 2003/12/27 20:51:28 rasdev Exp $";
+
+#include "qlparser/qtatomicdata.hh"
+#include "relcatalogif/basetype.hh"
+#include "relcatalogif/alltypes.hh"
+
+#include <iostream>
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+using namespace std;
+#endif
+
+#include <iostream>
+
+#include "raslib/rmdebug.hh"
+
+
+QtAtomicData::QtAtomicData()
+ : QtScalarData()
+{
+}
+
+
+
+QtAtomicData::QtAtomicData( r_Long value, unsigned short byteLength )
+ : QtScalarData()
+{
+ switch( byteLength )
+ {
+ case 1: valueType = TypeFactory::mapType("Octet"); break;
+ case 2: valueType = TypeFactory::mapType("Short"); break;
+ case 4: valueType = TypeFactory::mapType("Long"); break;
+
+ default:
+ RMInit::logOut << "Error: QtAtomicData::QtAtomicData() - signed integer value with length "
+ << byteLength << " is not supported." << endl;
+ }
+
+ if( valueType )
+ {
+ r_Long temp = value;
+ valueBuffer = new char[ valueType->getSize() ];
+ valueType->makeFromCLong( valueBuffer, &temp );
+ }
+}
+
+
+QtAtomicData::QtAtomicData( r_ULong value, unsigned short byteLength )
+ : QtScalarData()
+{
+ switch( byteLength )
+ {
+ case 1: valueType = TypeFactory::mapType("Char"); break;
+ case 2: valueType = TypeFactory::mapType("UShort"); break;
+ case 4: valueType = TypeFactory::mapType("ULong"); break;
+
+ default:
+ RMInit::logOut << "Error: QtAtomicData::QtAtomicData() - unsigned integer value with length "
+ << byteLength << " is not supported." << endl;
+ }
+
+
+ if( valueType )
+ {
+ r_ULong temp = value;
+ valueBuffer = new char[ valueType->getSize() ];
+ valueType->makeFromCULong( valueBuffer, &temp );
+ }
+}
+
+
+
+QtAtomicData::QtAtomicData( bool value )
+ : QtScalarData()
+{
+ r_ULong valueULong = (r_ULong)value;
+
+ valueType = TypeFactory::mapType("Bool");
+ valueBuffer = new char[ valueType->getSize() ];
+ valueType->makeFromCULong( valueBuffer, &valueULong );
+}
+
+
+
+QtAtomicData::QtAtomicData( double value, unsigned short byteLength )
+ : QtScalarData()
+{
+ switch( byteLength )
+ {
+ case 4: valueType = TypeFactory::mapType("Float"); break;
+ case 8: valueType = TypeFactory::mapType("Double"); break;
+
+ default:
+ RMInit::logOut << "Error: QtAtomicData::QtAtomicData() - float value with length "
+ << byteLength << " is not supported." << endl;
+ }
+
+
+ if( valueType )
+ {
+ valueBuffer = new char[ valueType->getSize() ];
+ valueType->makeFromCDouble( valueBuffer, &value );
+ }
+}
+
+
+
+
+QtAtomicData::QtAtomicData( const QtAtomicData& obj )
+ : QtScalarData( obj )
+{
+}
+
+QtAtomicData::~QtAtomicData()
+{
+}
+
+r_ULong
+QtAtomicData::getUnsignedValue() const
+{
+ r_ULong value=0;
+
+ if( valueType )
+ valueType->convertToCULong( valueBuffer, &value );
+
+ return value;
+}
+
+
+
+r_Long
+QtAtomicData::getSignedValue() const
+{
+ r_Long value=0;
+
+ if( valueType )
+ valueType->convertToCLong( valueBuffer, &value );
+
+ return value;
+}
+
+
+
+double
+QtAtomicData::getDoubleValue() const
+{
+ double value=0;
+
+ if( valueType )
+ valueType->convertToCDouble( valueBuffer, &value );
+
+ return value;
+}
+
+
+
+void
+QtAtomicData::printStatus( ostream& stream ) const
+{
+ stream << "atomic, " << flush;
+
+ QtScalarData::printStatus( stream );
+}
+
+
+// for complex types
+QtAtomicData::QtAtomicData(double valRe, double valIm, unsigned short size)
+: QtScalarData() {
+ double dummyRe = valRe;
+ double dummyIm = valIm;
+
+ if(size == 2 * sizeof(float))
+ valueType = TypeFactory::mapType("Complex1");
+ else
+ valueType = TypeFactory::mapType("Complex2");
+
+ valueBuffer = new char[valueType->getSize()];
+ valueType->makeFromCDouble(valueBuffer + ((GenericComplexType *)valueType)->getReOffset(), &dummyRe);
+ valueType->makeFromCDouble(valueBuffer + ((GenericComplexType *)valueType)->getImOffset(), &dummyIm);
+}
+
diff --git a/qlparser/qtatomicdata.hh b/qlparser/qtatomicdata.hh
new file mode 100644
index 0000000..769744d
--- /dev/null
+++ b/qlparser/qtatomicdata.hh
@@ -0,0 +1,134 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#ifndef _QTATOMICDATA_HH_
+#define _QTATOMICDATA_HH_
+
+#include "qlparser/qtscalardata.hh"
+#include "raslib/odmgtypes.hh"
+
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+ The class represents an atomic value handled by the query tree.
+
+*/
+
+class QtAtomicData : public QtScalarData
+{
+ public:
+ /// default constructor
+ QtAtomicData();
+
+ /// constructor getting signed integer data
+ QtAtomicData( r_Long value, unsigned short byteLength );
+ /**
+ The value for {\tt byteLength} specifies the type of the constant.
+
+ \begin{tabular}{lll}
+ 1 && OCTET\\
+ 2 && SHORT\\
+ 4 && LONG\\
+ \end{tabular}
+ */
+
+ /// constructor getting unsigned integer data
+ QtAtomicData( r_ULong value, unsigned short byteLength );
+ /**
+ The value for {\tt byteLength} specifies the type of the constant.
+
+ \begin{tabular}{lll}
+ 1 && CHAR\\
+ 2 && USHORT\\
+ 4 && ULONG\\
+ \end{tabular}
+ */
+
+ /// constructor getting boolean data
+ QtAtomicData( bool value );
+
+ /// constructor getting float data
+ QtAtomicData( double value, unsigned short byteLength );
+ /**
+ The value for {\tt byteLength} specifies the type of the constant.
+
+ \begin{tabular}{lll}
+ 4 && FLOAT\\
+ 8 && DOUBLE\\
+ \end{tabular}
+ */
+
+ /// constructor getting complex data
+ QtAtomicData(double valRe, double valIm, unsigned short size);
+
+ /// copy constructor
+ QtAtomicData( const QtAtomicData& obj );
+
+ /// destructor
+ virtual ~QtAtomicData();
+
+ /// returning unsigned value of an unsigned atomic type if it is one, 0 otherwise
+ r_ULong getUnsignedValue() const;
+
+ /// returning signed value of a signed atomic type if it is one, 0 otherwise
+ r_Long getSignedValue() const;
+
+ /// returning double value if it is one, 0 otherwise
+ double getDoubleValue() const;
+
+ /// print status of the object to the specified stream
+ virtual void printStatus( std::ostream& stream = std::cout ) const;
+};
+
+#include "qlparser/qtatomicdata.icc"
+
+#endif
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/qlparser/qtatomicdata.icc b/qlparser/qtatomicdata.icc
new file mode 100644
index 0000000..2651f9c
--- /dev/null
+++ b/qlparser/qtatomicdata.icc
@@ -0,0 +1,29 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
diff --git a/qlparser/qtbinaryfunc.cc b/qlparser/qtbinaryfunc.cc
new file mode 100644
index 0000000..9b77888
--- /dev/null
+++ b/qlparser/qtbinaryfunc.cc
@@ -0,0 +1,1174 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ * - QtScale is expected to have rounding errors with >1 tiles
+ * - shift, extend, scale release input tiles only at end; this
+ * shouldbe optimized (release immediately after evaluating)
+ * - why is this file called "binary"? all ops have just one MDD!
+ * - QtShift(), QtExtend() deliver for >1 tiles under PG an error
+ * "libpq 'select' did not yield 1 result but 0"
+ * which however does not seem to affect the result.
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)qlparser, QtMintervalSelect, QtShift: $Header: /home/rasdev/CVS-repository/rasdaman/qlparser/qtbinaryfunc.cc,v 1.37 2005/09/03 20:17:55 rasdev Exp $";
+
+#include "mymalloc/mymalloc.h"
+
+#include "mymalloc/mymalloc.h"
+
+#include "qlparser/qtbinaryfunc.hh"
+#include "qlparser/qtdata.hh"
+#include "qlparser/qtintervaldata.hh"
+#include "qlparser/qtmintervaldata.hh"
+#include "qlparser/qtatomicdata.hh"
+#include "qlparser/qtmdd.hh"
+#include "qlparser/qtpointdata.hh"
+
+#include "mddmgr/mddobj.hh"
+#include "tilemgr/tile.hh"
+
+#include "raslib/rmdebug.hh"
+#include "raslib/dlist.hh"
+
+#include <iostream>
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+using namespace std;
+#endif
+
+
+// --- QtShift --------------------------------------------------
+
+const QtNode::QtNodeType QtShift::nodeType = QT_SHIFT;
+
+QtShift::QtShift( QtOperation* mddOp, QtOperation* pointOp )
+ : QtBinaryOperation( mddOp, pointOp )
+{
+}
+
+
+
+bool
+QtShift::isCommutative() const
+{
+ return false; // NOT commutative
+}
+
+
+
+QtData*
+QtShift::evaluate( QtDataList* inputList )
+{
+ RMDBCLASS( "QtShift", "evaluate( QtDataList* )", "qlparser", __FILE__, __LINE__ )
+
+ QtData* returnValue = NULL;
+ QtData* operand1 = NULL;
+ QtData* operand2 = NULL;
+
+ // evaluate sub-nodes to obtain operand values
+ if( getOperands( inputList, operand1, operand2 ) )
+ {
+ //
+ // This implementation simply creates a new transient MDD object with the new
+ // domain while copying the data. Optimization of this is left for future work.
+ //
+
+ QtMDD* qtMDDObj = (QtMDD*)operand1;
+ const r_Point& transPoint = ((QtPointData*)operand2)->getPointData();
+ MDDObj* currentMDDObj = qtMDDObj->getMDDObject();
+
+ if( transPoint.dimension() != qtMDDObj->getLoadDomain().dimension() )
+ {
+ // delete the old operands
+ if( operand1 ) operand1->deleteRef();
+ if( operand2 ) operand2->deleteRef();
+
+ RMInit::logOut << "Error: QtShift::evaluate( QtDataList* ) - dimensionality of MDD and point expression do not match." << endl;
+ parseInfo.setErrorNo(407);
+ throw parseInfo;
+ }
+
+ // compute new domain
+ r_Minterval destinationDomain( qtMDDObj->getLoadDomain().create_translation( transPoint ) );
+
+ // create a transient MDD object for the query result
+ MDDObj* resultMDD = new MDDObj( currentMDDObj->getMDDBaseType(), destinationDomain );
+
+ // get all tiles
+ vector<Tile* >* tiles = currentMDDObj->intersect( qtMDDObj->getLoadDomain() );
+
+ // iterate over source tiles
+ for( vector<Tile*>::iterator tileIter = tiles->begin(); tileIter != tiles->end(); tileIter++ )
+ {
+ // get relevant area of source tile
+ r_Minterval sourceTileDomain = qtMDDObj->getLoadDomain().create_intersection( (*tileIter)->getDomain() );
+
+ // compute translated tile domain
+ r_Minterval destinationTileDomain = sourceTileDomain.create_translation( transPoint );
+
+ // create a new transient tile, copy the transient data, and insert it into the mdd object
+ // FIXME: how can this work without tile area allocation??? -- PB 2005-jun-19
+ Tile* newTransTile = new Tile( destinationTileDomain, currentMDDObj->getCellType() );
+ newTransTile->copyTile( destinationTileDomain, *tileIter, sourceTileDomain );
+ resultMDD->insertTile( newTransTile );
+ }
+
+ // create a new QtMDD object as carrier object for the transient MDD object
+ returnValue = new QtMDD( (MDDObj*)resultMDD );
+
+ // delete the tile vector, the tiles itself are deleted when the destructor
+ // of the MDD object is called
+ delete tiles;
+ tiles=NULL;
+
+ // delete the old operands
+ if( operand1 ) operand1->deleteRef();
+ if( operand2 ) operand2->deleteRef();
+ }
+
+ return returnValue;
+}
+
+
+
+void
+QtShift::printTree( int tab, ostream& s, QtChildType mode )
+{
+ s << SPACE_STR(tab).c_str() << "QtShift Object " << getNodeType() << endl;
+
+ QtBinaryOperation::printTree( tab, s, mode );
+}
+
+
+
+void
+QtShift::printAlgebraicExpression( ostream& s )
+{
+ s << "shift(";
+
+ if( input1 )
+ input1->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << ",";
+
+ if( input2 )
+ input2->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << ")";
+}
+
+
+
+void
+QtShift::optimizeLoad( QtTrimList* trimList )
+{
+ RMDBCLASS( "QtShift", "optimizeLoad( QtTrimList* )", "qlparser", __FILE__, __LINE__ )
+
+ QtNode::QtTrimList *list1=NULL, *list2=NULL;
+
+ if( input1 && input2 )
+ {
+ QtNode::QtTrimList::iterator iter;
+
+ //
+ // The result of input2 has to be a constant expression.
+ //
+
+ // shift of trimList is just possible, if no open bounds are available
+ bool openBounds = false;
+ for( iter=trimList->begin(); iter!=trimList->end() && !openBounds; iter++ )
+ openBounds = !((*iter)->interval.is_low_fixed()) || !((*iter)->interval.is_high_fixed());
+
+ if( openBounds )
+ {
+ // release( trimList->begin(), trimList->end() );
+ for( QtNode::QtTrimList::iterator iter=trimList->begin(); iter!=trimList->end(); iter++ )
+ {
+ delete *iter;
+ *iter=NULL;
+ }
+ delete trimList;
+ trimList=NULL;
+
+ RMInit::logOut << "Error: QtShift::optimizeLoad() - spatial domain shift of open bounds is not supported" << endl;
+ parseInfo.setErrorNo(409);
+ throw parseInfo;
+ }
+
+ QtData* operand = input2->evaluate(NULL);
+
+ if( !operand )
+ {
+ // release( trimList->begin(), trimList->end() );
+ for( QtNode::QtTrimList::iterator iter=trimList->begin(); iter!=trimList->end(); iter++ )
+ {
+ delete *iter;
+ *iter=NULL;
+ }
+ delete trimList;
+ trimList=NULL;
+
+ RMInit::logOut << "Error: QtShift::optimizeLoad() - second operand of shift function must be a constant expression." << endl;
+ parseInfo.setErrorNo(408);
+ throw parseInfo;
+ }
+
+ if( operand->getDataType() != QT_POINT )
+ {
+ // release( trimList->begin(), trimList->end() );
+ for( QtNode::QtTrimList::iterator iter=trimList->begin(); iter!=trimList->end(); iter++ )
+ {
+ delete *iter;
+ *iter=NULL;
+ }
+ delete trimList;
+ trimList=NULL;
+
+ operand->deleteRef();
+
+ RMInit::logOut << "Error: QtShift::optimizeLoad() - second operand must be of type Point." << endl;
+ parseInfo.setErrorNo(406);
+ throw parseInfo;
+ }
+
+ // get transPoint
+ const r_Point& transPoint = ((QtPointData*)operand)->getPointData();
+
+ // shift trim elements by -transPoint
+ for( iter=trimList->begin(); iter!=trimList->end(); iter++ )
+ {
+ QtTrimElement* elem = *iter;
+
+ if( elem->dimension <= transPoint.dimension() )
+ elem->interval.set_interval( elem->interval.low() - transPoint[elem->dimension], elem->interval.high() - transPoint[elem->dimension] );
+ }
+
+ // point is not needed anymore
+ operand->deleteRef();
+
+ input1->optimizeLoad( trimList );
+ }
+ else
+ {
+ // release( trimList->begin(), trimList->end() );
+ for( QtNode::QtTrimList::iterator iter=trimList->begin(); iter!=trimList->end(); iter++ )
+ {
+ delete *iter;
+ *iter=NULL;
+ }
+ delete trimList;
+ trimList=NULL;
+ }
+}
+
+
+
+const QtTypeElement&
+QtShift::checkType( QtTypeTuple* typeTuple )
+{
+ RMDBCLASS( "QtShift", "checkType( QtTypeTuple* )", "qlparser", __FILE__, __LINE__ )
+
+ dataStreamType.setDataType( QT_TYPE_UNKNOWN );
+
+ // check operand branches
+ if( input1 && input2 )
+ {
+
+ // get input types
+ const QtTypeElement& inputType1 = input1->checkType( typeTuple );
+ const QtTypeElement& inputType2 = input2->checkType( typeTuple );
+
+ if( inputType1.getDataType() != QT_MDD )
+ {
+ RMInit::logOut << "Error: QtShift::checkType() - first operand must be of type MDD." << endl;
+ parseInfo.setErrorNo(405);
+ throw parseInfo;
+ }
+
+ if( inputType2.getDataType() != QT_POINT )
+ {
+ RMInit::logOut << "Error: QtShift::checkType() - second operand must be of type Point." << endl;
+ parseInfo.setErrorNo(406);
+ throw parseInfo;
+ }
+
+ // pass MDD type
+ dataStreamType = inputType1;
+ }
+ else
+ RMInit::logOut << "Error: QtShift::checkType() - operand branch invalid." << endl;
+
+ return dataStreamType;
+}
+
+
+// --- QtExtend --------------------------------------------------
+
+const QtNode::QtNodeType QtExtend::nodeType = QT_EXTEND;
+
+QtExtend::QtExtend( QtOperation* mddOp, QtOperation* mintervalOp )
+ : QtBinaryOperation( mddOp, mintervalOp )
+{
+}
+
+
+
+bool
+QtExtend::isCommutative() const
+{
+ return false; // NOT commutative
+}
+
+
+
+QtData*
+QtExtend::evaluate( QtDataList* inputList )
+{
+ RMDBCLASS( "QtExtend", "evaluate( QtDataList* )", "qlparser", __FILE__, __LINE__ )
+
+ QtData* returnValue = NULL; // operation result
+ QtData* operand1 = NULL; // 1st operand: MDD expression
+ QtData* operand2 = NULL; // 2nd operand: Minterval expression
+ vector<Tile*> completeAreaList; // list of tiles comprising the whole area (possibly with holes); needed for 1-code below
+
+ if( getOperands( inputList, operand1, operand2 ) )
+ {
+ //
+ // This implementation simply creates a single new transient MDD object with the new
+ // domain while copying the data.
+ // FIXME: create a tiled object
+ //
+
+ QtMDD* qtMDDObj = (QtMDD*)operand1; // object to be extended
+ r_Minterval targetDomain = ((QtMintervalData*)operand2)->getMintervalData(); // new domain of extended object
+ MDDObj* currentMDDObj = qtMDDObj->getMDDObject();
+
+ // precondition checks (we call the MDD C and the Minterval M):
+ // - dim(C) == dim(M)
+ if( targetDomain.dimension() != qtMDDObj->getLoadDomain().dimension() )
+ {
+ // delete the old operands
+ if( operand1 ) operand1->deleteRef();
+ if( operand2 ) operand2->deleteRef();
+
+ RMInit::logOut << "Error: QtExtend::evaluate( QtDataList* ) - dimensionality of MDD and point expression do not match." << endl;
+ parseInfo.setErrorNo(407);
+ throw parseInfo;
+ }
+
+ // - M does not contain open bounds (i.e., "*")
+ if( ! targetDomain.is_origin_fixed() || ! targetDomain.is_high_fixed() )
+ {
+ // delete the old operands
+ if( operand1 ) operand1->deleteRef();
+ if( operand2 ) operand2->deleteRef();
+
+ RMInit::logOut << "Error: QtExtend::evaluate( QtDataList* ) - target domain must not have open bounds." << endl;
+ parseInfo.setErrorNo(420);
+ throw parseInfo;
+ }
+ // - M.subset( sdom(C) ); can we relieve this?
+ if( ! targetDomain.covers( qtMDDObj->getLoadDomain() ) )
+ {
+ // delete the old operands
+ if( operand1 ) operand1->deleteRef();
+ if( operand2 ) operand2->deleteRef();
+
+ RMInit::logOut << "Error: QtExtend::evaluate( QtDataList* ) - new interval does not cover MDD to be extended." << endl;
+ parseInfo.setErrorNo(421);
+ throw parseInfo;
+ }
+
+ // RMInit::logOut << "QtExtend::evaluate( QtDataList* ) - extending MDD with basetype " << currentMDDObj->getMDDBaseType() << " and load domain " << qtMDDObj->getLoadDomain() << " to domain " << targetDomain << endl;
+
+ // create a transient MDD object for the query result
+ MDDObj* resultMDD = new MDDObj( currentMDDObj->getMDDBaseType(), targetDomain );
+
+ // --- 1: put all existing tiles into their place ------------------------
+
+ // get all tiles
+ vector<Tile* >* tiles = currentMDDObj->intersect( qtMDDObj->getLoadDomain() );
+
+ // iterate over source tiles
+ // Note that source and target MDD have the same coordinate basis
+ for( vector<Tile*>::iterator tileIter = tiles->begin(); tileIter != tiles->end(); tileIter++ )
+ {
+ // RMInit::logOut << "QtExtend::evaluate( QtDataList* ) - load domain is " << qtMDDObj->getLoadDomain() << endl;
+ // get relevant area of source tile
+ r_Minterval sourceTileDomain = qtMDDObj->getLoadDomain().create_intersection( (*tileIter)->getDomain() );
+
+ Tile* newTransTile = new Tile( sourceTileDomain, currentMDDObj->getCellType() );
+ // RMInit::logOut << "QtExtend::evaluate( QtDataList* ) - adding source part " << sourceTileDomain << " of tile " << (*tileIter)->getDomain() << endl;
+ newTransTile->copyTile( sourceTileDomain, *tileIter, sourceTileDomain );
+
+ resultMDD->insertTile( newTransTile ); // needed for 2-code below
+ // completeAreaList.push_back( newTransTile ); // needed for 1-code below
+ }
+
+ // --- 2: fill up new space with null values -----------------------------
+
+#if 0 // this 1-code does the same thing as the 2-code, but easier & more efficiently -- PB 2005-jun-24
+ // INCOMPLETE!
+ // create minimal (1x1) tiles at origin and high end, but only if the source domain isn't there
+ if (targetDomain.get_origin() != qtMDDObj->getLoadDomain().get_origin())
+ {
+ RMInit::logOut << "QtExtend::evaluate( QtDataList* ) - adding aux tile at origin." << endl;
+-> Tile* originTile = new Tile( origin..origin+1 , currentMDDObj->getCellType() );
+ extendDomainList.push_back( originTile );
+ }
+ if (targetDomain.get_high() != qtMDDObj->getLoadDomain().get_high())
+ {
+ RMInit::logOut << "QtExtend::evaluate( QtDataList* ) - adding aux tile at high." << endl;
+-> Tile* highTile = new Tile( high-1..high, currentMDDObj->getCellType() );
+ extendDomainList.push_back( highTile );
+ }
+
+ // merge all tiles into one & free not-used-any-longer stuff
+ Tile* completeTile = new Tile( extendDomainList );
+ delete[] extendDomainList;
+ resultMDD->insertTile( completeTile );
+ delete completeTile;
+
+#else // 2-code; unused -- PB 2005-jun-24
+ // the part below does the trick explicitly, leading to a larger number of result tiles.
+ // establish list of domains
+ vector<r_Minterval> extendDomainList;
+
+ // inspect 2*d lower/upper neighbours
+ // RMInit::logOut << "QtExtend::evaluate( QtDataList* ): - inspect 2*d lower/upper neighbours, dimension is " << targetDomain.dimension() << endl;
+ for (r_Dimension d=0; d<targetDomain.dimension(); d++)
+ {
+ // is there any space left of original MDD; ie, has MDD been extended left?
+ if (targetDomain.get_origin()[d] < qtMDDObj->getLoadDomain().get_origin()[d])
+ {
+ // this domain is identical to original MDD except for dim d where it is left of original
+ r_Minterval lowerNeighbour = qtMDDObj->getLoadDomain();
+ lowerNeighbour[d] = r_Sinterval( targetDomain.get_origin()[d], qtMDDObj->getLoadDomain().get_origin()[d]-1 );
+ // RMInit::logOut << "QtExtend::evaluate( QtDataList* ): adding lower neighbour domain " << lowerNeighbour << endl;
+ extendDomainList.push_back( lowerNeighbour );
+ }
+ // is there any space right of original MDD; ie, has MDD been extended right?
+ if (targetDomain.get_high()[d] > qtMDDObj->getLoadDomain().get_high()[d])
+ {
+ // this domain is identical to original MDD except for dim d where it is right of original
+ r_Minterval upperNeighbour = qtMDDObj->getLoadDomain();
+ upperNeighbour[d] =r_Sinterval( qtMDDObj->getLoadDomain().get_high()[d]+1, targetDomain.get_high()[d] );
+ // RMInit::logOut << "QtExtend::evaluate( QtDataList* ): adding upper neighbour domain " << upperNeighbour << endl;
+ extendDomainList.push_back( upperNeighbour );
+ }
+ }
+
+ // inspect 2^d corner points
+
+ // RMInit::logOut << "QtExtend::evaluate( QtDataList* ): - inspect 2^d corner neighbours, dimension is " << targetDomain.dimension() << endl;
+ r_Minterval cornerBoxDomain = r_Minterval( targetDomain.dimension() );
+ QtExtend::extendGetCornerTiles( targetDomain, qtMDDObj->getLoadDomain(), 0, targetDomain.dimension(), cornerBoxDomain, &extendDomainList );
+
+ // merge where possible to minimize tile number
+ // ...just an optimization, tbd later
+
+ // create tiles for all domains found
+ // RMInit::logOut << "QtExtend::evaluate( QtDataList* ): - creating " << extendDomainList.size() << " tiles..." << endl;
+ for( vector<r_Minterval>::iterator domainIter = extendDomainList.begin(); domainIter != extendDomainList.end(); domainIter++ )
+ {
+ // RMInit::logOut << "QtExtend::evaluate( QtDataList* ): creating tile for domain " << (*domainIter) << endl;
+ Tile* newTransTile = new Tile( *domainIter, currentMDDObj->getCellType() );
+ resultMDD->insertTile( newTransTile );
+ }
+#endif 0
+
+ // --- 3: package into MDD object & finalize -----------------------------
+
+ // create a new QtMDD object as carrier object for the transient MDD object
+ returnValue = new QtMDD( (MDDObj*)resultMDD );
+
+ // delete the tile vector, the tiles itself are deleted when the destructor
+ // of the MDD object is called
+
+ delete tiles;
+ tiles=NULL;
+
+ // delete the old operands
+ if( operand1 ) operand1->deleteRef();
+ if( operand2 ) operand2->deleteRef();
+
+ // temporary: dump result tile
+ // RMInit::logOut << "QtExtend::evaluate( QtDataList* ) - result tile = " << newTransTile->printStatus() << endl;
+ // newTransTile->printStatus(99,RMInit::logOut);
+ }
+
+ // RMInit::logOut << "QtExtend::evaluate( QtDataList* ) - done." << endl;
+ return returnValue;
+}
+
+#if 1 // needed for 1-code above -- PB 2005-jun-24
+/**
+aux function for QtExtend::evaluate(): build up (recursing the dimension) a list of all spatial domains that sit in the corners between outerDomain and innerDomain; at the recursion bottom the resulting domain is added to the cornerList.
+**/
+
+void
+QtExtend::extendGetCornerTiles( r_Minterval outerDomain, r_Minterval innerDomain, const r_Dimension currentDim, const r_Dimension maxDim, r_Minterval currentInterval, vector<r_Minterval>* cornerList )
+{
+ // RMInit::logOut << "QtExtend::extendGetCornerTiles( " << outerDomain << ", " << innerDomain << ", " << currentDim << ", " << maxDim << ", " << currentInterval << ", _ ) start" << endl;
+
+ // not yet addressed all dimensions in the current coordinate?
+// note: what about 1D? 0D?
+ if (currentDim < maxDim)
+ {
+ // add domain's lower end, continue building up the minterval
+ // ...but only if the area is nonempty
+ if (outerDomain.get_origin()[currentDim] < innerDomain.get_origin()[currentDim])
+ {
+ // make local working copy
+ r_Minterval extendedInterval( currentInterval );
+ // add i-th coordinate to domain, up to (but excluding) innerDomain
+ extendedInterval[currentDim] = r_Sinterval( outerDomain.get_origin()[currentDim], innerDomain.get_origin()[currentDim]-1 );
+ // inspect next dimension
+ // RMInit::logOut << "QtExtend::extendGetCornerTiles(): recursing for lower end box in next dimension " << currentDim+1 << " using extendedInterval " << extendedInterval << endl;
+ extendGetCornerTiles( outerDomain, innerDomain, currentDim+1, maxDim, extendedInterval, cornerList );
+ }
+ // add domain's upper end, continue building up the minterval
+ if (innerDomain.get_high()[currentDim] < outerDomain.get_high()[currentDim])
+ {
+ // make local working copy
+ r_Minterval extendedInterval( currentInterval );
+ // add i-th coordinate to domain, starting from (but excluding) innerDomain
+ extendedInterval[currentDim] = r_Sinterval( innerDomain.get_high()[currentDim]+1, outerDomain.get_high()[currentDim] );
+ // inspect next dimension
+ // RMInit::logOut << "QtExtend::extendGetCornerTiles(): recursing for upper end box in next dimension " << currentDim+1 << " using extendedInterval " << extendedInterval << endl;
+ extendGetCornerTiles( outerDomain, innerDomain, currentDim+1, maxDim, extendedInterval, cornerList );
+ }
+ }
+ else if (currentDim > maxDim)
+ {
+ // this is an error, see preconditions
+ RMInit::logOut << "QtExtend::extendGetCornerTiles(): error: dimension overflow." << endl;
+ }
+ else // then we've reached currentDim==maxDim
+ {
+ // add this minterval to the tile domain list
+ cornerList->push_back( currentInterval );
+ // RMInit::logOut << "QtExtend::extendGetCornerTiles(): added " << currentInterval << " to tile domain list." << endl;
+ }
+
+ // RMInit::logOut << "QtExtend::extendGetCornerTiles() done." << endl;
+}
+#endif 1
+
+void
+QtExtend::printTree( int tab, ostream& s, QtChildType mode )
+{
+ s << SPACE_STR(tab).c_str() << "QtExtend Object " << getNodeType() << endl;
+
+ QtBinaryOperation::printTree( tab, s, mode );
+}
+
+
+
+void
+QtExtend::printAlgebraicExpression( ostream& s )
+{
+ s << "extend(";
+
+ if( input1 )
+ input1->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << ",";
+
+ if( input2 )
+ input2->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << ")";
+}
+
+
+
+void
+QtExtend::optimizeLoad( QtTrimList* trimList )
+{
+ RMDBCLASS( "QtExtend", "optimizeLoad( QtTrimList* )", "qlparser", __FILE__, __LINE__ )
+
+ QtNode::QtTrimList *list1=NULL, *list2=NULL;
+
+ if( input1 && input2 )
+ {
+#if 0 // not yet sure what to do -- PB 2005-06-18
+
+ QtNode::QtTrimList::iterator iter;
+
+ //
+ // The result of input2 has to be a constant expression.
+ //
+
+ // shift of trimList is just possible, if no open bounds are available
+ bool openBounds = false;
+ for( iter=trimList->begin(); iter!=trimList->end() && !openBounds; iter++ )
+ openBounds = !((*iter)->interval.is_low_fixed()) || !((*iter)->interval.is_high_fixed());
+
+ if( openBounds )
+ {
+ // release( trimList->begin(), trimList->end() );
+ for( QtNode::QtTrimList::iterator iter=trimList->begin(); iter!=trimList->end(); iter++ )
+ {
+ delete *iter;
+ *iter=NULL;
+ }
+ delete trimList;
+ trimList=NULL;
+
+ RMInit::logOut << "Error: QtExtend::optimizeLoad() - spatial domain shift of open bounds is not supported" << endl;
+// XXX need new error code
+ parseInfo.setErrorNo(409);
+ throw parseInfo;
+ }
+
+ QtData* operand = input2->evaluate(NULL);
+
+ if( !operand )
+ {
+ // release( trimList->begin(), trimList->end() );
+ for( QtNode::QtTrimList::iterator iter=trimList->begin(); iter!=trimList->end(); iter++ )
+ {
+ delete *iter;
+ *iter=NULL;
+ }
+ delete trimList;
+ trimList=NULL;
+
+ RMInit::logOut << "Error: QtExtend::optimizeLoad() - second operand of extend function must be a constant expression." << endl;
+// XXX correct new error code
+ parseInfo.setErrorNo(408);
+ throw parseInfo;
+ }
+
+ if( operand->getDataType() != QT_MINTERVAL )
+ {
+ // release( trimList->begin(), trimList->end() );
+ for( QtNode::QtTrimList::iterator iter=trimList->begin(); iter!=trimList->end(); iter++ )
+ {
+ delete *iter;
+ *iter=NULL;
+ }
+ delete trimList;
+ trimList=NULL;
+
+ operand->deleteRef();
+
+ RMInit::logOut << "Error: QtExtend::optimizeLoad() - second operand must be of type Minterval." << endl;
+// XXX correct new error code
+ parseInfo.setErrorNo(406);
+ throw parseInfo;
+ }
+
+ // get extend target domain
+ const r_Minterval& targetDomain = ((QtPointData*)operand)->getMintervalData();
+
+ // shift trim elements by -transPoint
+ // XXX replace with extend() code
+ for( iter=trimList->begin(); iter!=trimList->end(); iter++ )
+ {
+ QtTrimElement* elem = *iter;
+
+ if( elem->dimension <= transPoint.dimension() )
+ elem->interval.set_interval( elem->interval.low() - transPoint[elem->dimension], elem->interval.high() - transPoint[elem->dimension] );
+ }
+
+ // point is not needed anymore
+ operand->deleteRef();
+#endif 0 // not yet sure what to do -- PB 2005-06-18
+
+ input1->optimizeLoad( trimList );
+ }
+ else
+ {
+ // release( trimList->begin(), trimList->end() );
+ for( QtNode::QtTrimList::iterator iter=trimList->begin(); iter!=trimList->end(); iter++ )
+ {
+ delete *iter;
+ *iter=NULL;
+ }
+ delete trimList;
+ trimList=NULL;
+ }
+}
+
+
+
+const QtTypeElement&
+QtExtend::checkType( QtTypeTuple* typeTuple )
+{
+ RMDBCLASS( "QtExtend", "checkType( QtTypeTuple* )", "qlparser", __FILE__, __LINE__ )
+
+ dataStreamType.setDataType( QT_TYPE_UNKNOWN );
+
+ // check operand branches
+ if( input1 && input2 )
+ {
+
+ // get input types
+ const QtTypeElement& inputType1 = input1->checkType( typeTuple );
+ const QtTypeElement& inputType2 = input2->checkType( typeTuple );
+
+ if( inputType1.getDataType() != QT_MDD )
+ {
+ RMInit::logOut << "Error: QtExtend::checkType() - first operand must be of type MDD." << endl;
+ parseInfo.setErrorNo(405);
+ throw parseInfo;
+ }
+
+ if( inputType2.getDataType() != QT_MINTERVAL )
+ {
+ RMInit::logOut << "Error: QtExtend::checkType() - second operand must be of type Minterval." << endl;
+ parseInfo.setErrorNo(422);
+ throw parseInfo;
+ }
+
+ // pass MDD type
+ dataStreamType = inputType1;
+ }
+ else
+ RMInit::logOut << "Error: QtExtend::checkType() - operand branch invalid." << endl;
+
+ return dataStreamType;
+}
+
+
+
+// --- QtScale --------------------------------------------------
+
+const QtNode::QtNodeType QtScale::nodeType = QT_SCALE;
+
+QtScale::QtScale( QtOperation* mddOp, QtOperation* pointOp )
+ : QtBinaryOperation( mddOp, pointOp )
+{
+}
+
+
+
+bool
+QtScale::isCommutative() const
+{
+ return false; // NOT commutative
+}
+
+#include <iomanip>
+#include <math.h>
+
+// this define was used during testing, we had a problem
+inline double FLOOR(double a) {
+ return floor(a);
+}
+
+QtData*
+QtScale::evaluate( QtDataList* inputList )
+{
+ RMDBCLASS( "QtScale", "evaluate( QtDataList* )", "qlparser", __FILE__, __LINE__ )
+
+ QtData* returnValue = NULL;
+ QtData* operand1 = NULL;
+ QtData* operand2 = NULL;
+
+ if(!getOperands( inputList, operand1, operand2 ) )
+ return returnValue;
+
+ QtMDD* qtMDDObj = (QtMDD*)operand1;
+ MDDObj* currentMDDObj = qtMDDObj->getMDDObject();
+ vector<r_Double> scaleVector(0);
+
+ scaleVector = vector<r_Double>( qtMDDObj->getLoadDomain().dimension() );
+
+ r_Minterval sourceDomain = qtMDDObj->getLoadDomain();
+ r_Minterval targetDomain;
+ r_Point origin1 = sourceDomain.get_origin();
+ r_Point origin2 = qtMDDObj->getMDDObject()->getCurrentDomain().get_origin();
+
+ r_Minterval wishedTargetDomain;
+ r_Point translation;
+
+ //used for scale with wishedIv
+ bool isWishedTargetSet = false;
+ r_Double sourceRange=0., targetRange=0., f=0., Tl=0., Th=0.;
+
+ switch( operand2->getDataType() )
+ {
+ case QT_POINT:
+ {
+ const r_Point& transPoint = ((QtPointData*)operand2)->getPointData();
+
+ if( transPoint.dimension() != qtMDDObj->getLoadDomain().dimension() )
+ {
+ // delete the old operands
+ if( operand1 ) operand1->deleteRef();
+ if( operand2 ) operand2->deleteRef();
+
+ RMInit::logOut << "Error: QtScale::evaluate( QtDataList* ) - dimensionalities of MDD and scale expression are not matching." << endl;
+ parseInfo.setErrorNo(418);
+ throw parseInfo;
+ }
+
+ for( int i=0; i<scaleVector.size(); i++ )
+ scaleVector[i] = transPoint[i];
+ }
+ break;
+
+ case QT_CHAR:
+ case QT_USHORT:
+ case QT_ULONG:
+ {
+ for( int i=0; i<scaleVector.size(); i++ )
+ scaleVector[i] = ((QtAtomicData*)operand2)->getUnsignedValue();;
+ }
+ break;
+
+ case QT_OCTET:
+ case QT_SHORT:
+ case QT_LONG:
+ {
+ for( int i=0; i<scaleVector.size(); i++ )
+ scaleVector[i] = ((QtAtomicData*)operand2)->getSignedValue();;
+ }
+ break;
+
+ case QT_DOUBLE:
+ case QT_FLOAT:
+ {
+ RMDBGMIDDLE( 1, RMDebug::module_qlparser, "QtScale", "Scaling: " << ((QtAtomicData*)operand2)->getDoubleValue() )
+ for( int i=0; i<scaleVector.size(); i++ )
+ scaleVector[i] = ((QtAtomicData*)operand2)->getDoubleValue();
+ }
+ break;
+
+ case QT_MINTERVAL:
+ {
+ wishedTargetDomain = ((QtMintervalData*)operand2)->getMintervalData();
+ isWishedTargetSet=true;
+
+ if( wishedTargetDomain.dimension() != sourceDomain.dimension())
+ {
+ // delete the old operands
+ if( operand1 ) operand1->deleteRef();
+ if( operand2 ) operand2->deleteRef();
+
+ RMInit::logOut << "Error: QtScale::evaluate( QtDataList* ) - dimensionalities of MDD and scale expression are not matching." << endl;
+ parseInfo.setErrorNo(418);
+ throw parseInfo;
+ }
+
+ for( int i=0; i<scaleVector.size(); i++ )
+ {
+ sourceRange = (r_Double)sourceDomain[i].get_extent();
+ targetRange = (r_Double)wishedTargetDomain[i].get_extent();
+
+ if(sourceRange != 0.)
+ {
+ scaleVector[i] = targetRange / sourceRange;
+ f = scaleVector[i];
+
+ Tl = FLOOR(f*sourceDomain[i].low());
+ //correction by 1e-6 to avoid the strage bug when Th was a
+ //integer value and floor return value-1(e.g. query 47.ql)
+ Th = FLOOR(f*(sourceDomain[i].high()+1) + 0.000001)-1;
+
+// FIXME BUG if(Tl != Th)
+// Th--;
+
+ RMDBGMIDDLE( 1, RMDebug::module_qlparser, "QtScale", "Scale: before f="<<setprecision(12)<<f)
+ RMDBGMIDDLE( 2, RMDebug::module_qlparser, "QtScale", "Scale: " << endl
+ <<"precalculated: "<<Tl<<':'<<Th<<"<-->"<<wishedTargetDomain[i].low()<<':'<<wishedTargetDomain[i].high()<<endl
+ <<"pro memoria: "<<(r_Range)(f*(sourceDomain[i].high()+1))<<", "<<(f*(sourceDomain[i].high()+1))
+ <<", "<<floor(f*(sourceDomain[i].high()+1))
+ <<", "<<ceil(f*(sourceDomain[i].high()+1)))
+
+ if( (Th-Tl+1) != targetRange )
+ {
+ RMDBGMIDDLE( 1, RMDebug::module_qlparser, "QtScale", "Scale: correction necessary: "<<Tl<<':'<<Th<<"<-->"<<wishedTargetDomain[i].low()<<':'<<wishedTargetDomain[i].high())
+
+ f = f + (targetRange - (Th-Tl+1))/sourceRange;
+
+ // cout<<"f="<<setprecision(12)<<f<<" scale[i]="<<setprecision(12)<<scaleVector[i]<<endl;
+
+ Tl = FLOOR(f*sourceDomain[i].low());
+ //correction by 1e-6 to avoid the strage bug when Th was a
+ //integer value and floor return value-1(e.g. query 47.ql)
+ Th = FLOOR(f*(sourceDomain[i].high()+1) + 0.000001)-1;
+// FIXME BUG if(Tl != Th)
+// Th--;
+
+ RMDBGMIDDLE( 1, RMDebug::module_qlparser, "QtScale", "Scale: ->: "<<Tl<<':'<<Th<<"<-->"<<wishedTargetDomain[i].low()<<':'<<wishedTargetDomain[i].high())
+
+ scaleVector[i]=f;
+ RMDBGMIDDLE( 1, RMDebug::module_qlparser, "QtScale", "Scale: after f="<<setprecision(12)<<f)
+ }
+ }
+ else
+ {
+ scaleVector[i] =0; //exception? it can't heapen, this error is filtered long before reaching this point
+ }
+ }
+ }
+ break;
+ default:
+ RMDBGONCE(0, RMDebug::module_qlparser, "r_QtScale", "evaluate() bad type operand2" << operand2->getDataType());
+ break;
+ }
+
+// ----------------------------------------------------------
+
+#ifdef RMANDEBUG
+ RMDBGMIDDLE( 1, RMDebug::module_qlparser, "QtScale", "Scale vector : " )
+ for( int i=0; i<scaleVector.size(); i++ )
+ {
+ RMDBGMIDDLE( 1, RMDebug::module_qlparser, "QtScale", scaleVector[i] << "," )
+ }
+#endif
+
+ // scale domain
+ if( !scaleDomain( sourceDomain, scaleVector, targetDomain ) )
+ {
+ // delete the old operands
+ if( operand1 ) operand1->deleteRef();
+ if( operand2 ) operand2->deleteRef();
+
+ RMInit::logOut << "Error: QtScale::evaluate( QtDataList* ) - empty result after scaling." << endl;
+ parseInfo.setErrorNo(419);
+ throw parseInfo;
+ }
+ RMDBGMIDDLE( 2, RMDebug::module_qlparser, "QtBinaryFunc", "Dummy target domain: " << targetDomain << endl )
+
+ if(isWishedTargetSet)
+ {
+ translation = wishedTargetDomain.get_origin() - targetDomain.get_origin();
+ targetDomain.translate(translation);
+ }
+
+ // create a transient MDD object for the query result
+ MDDObj* resultMDD = new MDDObj( currentMDDObj->getMDDBaseType(), targetDomain );
+
+ //**********************
+ origin1 = r_Point(scaleVector.size()); // all zero!!
+ //**********************
+
+ // get all tiles
+ vector<Tile* >* tiles = currentMDDObj->intersect( qtMDDObj->getLoadDomain() );
+
+ //tile domain before & after
+ r_Minterval sourceTileDomain, destinationTileDomain;
+
+ //
+ // Algorithm A: Scale each Tile
+ //
+
+ // iterate over source tiles
+ for( vector<Tile*>::iterator tileIter = tiles->begin(); tileIter != tiles->end(); tileIter++ )
+ {
+ // get relevant area of source tile
+ sourceTileDomain = qtMDDObj->getLoadDomain().create_intersection( (*tileIter)->getDomain() );
+
+ // compute scaled tile domain and check if it exists
+ if( (*tileIter)->scaleGetDomain( sourceTileDomain, scaleVector, destinationTileDomain) )
+ {
+ RMDBGMIDDLE( 2, RMDebug::module_qlparser, "QtBinaryFunc", "Destination tile domain: " << destinationTileDomain << endl )
+ // create a new transient tile
+ Tile* newTransTile = new Tile( destinationTileDomain, currentMDDObj->getCellType() );
+ newTransTile->execScaleOp( *tileIter, sourceTileDomain, origin1, scaleVector );
+
+ if(isWishedTargetSet)
+ ((r_Minterval&)newTransTile->getDomain()).translate(translation);
+
+ resultMDD->insertTile( newTransTile );
+ }
+ }
+
+ // create a new QtMDD object as carrier object for the transient MDD object
+ returnValue = new QtMDD( (MDDObj*)resultMDD );
+
+ // delete the tile vector, the tiles itself are deleted when the destructor
+ // of the MDD object is called
+ delete tiles;
+ tiles=NULL;
+
+ // delete the old operands
+ if( operand1 ) operand1->deleteRef();
+ if( operand2 ) operand2->deleteRef();
+
+ return returnValue;
+}
+
+
+void
+QtScale::printTree( int tab, ostream& s, QtChildType mode )
+{
+ s << SPACE_STR(tab).c_str() << "QtScale Object " << getNodeType() << endl;
+
+ QtBinaryOperation::printTree( tab, s, mode );
+}
+
+
+
+void
+QtScale::printAlgebraicExpression( ostream& s )
+{
+ s << "scale(";
+
+ if( input1 )
+ input1->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << ",";
+
+ if( input2 )
+ input2->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << ")";
+}
+
+
+
+void
+QtScale::optimizeLoad( QtTrimList* trimList )
+{
+ RMDBCLASS( "QtScale", "optimizeLoad( QtTrimList* )", "qlparser", __FILE__, __LINE__ )
+
+ // by default, pass load domain to input1
+ if( input1 )
+ input1->optimizeLoad( trimList );
+ else
+ {
+ delete trimList;
+ trimList=NULL;
+ }
+}
+
+
+
+const QtTypeElement&
+QtScale::checkType( QtTypeTuple* typeTuple )
+{
+ RMDBCLASS( "QtScale", "checkType( QtTypeTuple* )", "qlparser", __FILE__, __LINE__ )
+
+ dataStreamType.setDataType( QT_TYPE_UNKNOWN );
+
+ // check operand branches
+ if( input1 && input2 )
+ {
+
+ // get input types
+ const QtTypeElement& inputType1 = input1->checkType( typeTuple );
+ const QtTypeElement& inputType2 = input2->checkType( typeTuple );
+
+ if( inputType1.getDataType() != QT_MDD )
+ {
+ RMInit::logOut << "Error: QtScale::checkType() - first operand must be of type MDD." << endl;
+ parseInfo.setErrorNo(416);
+ throw parseInfo;
+ }
+
+ if( inputType2.getDataType() != QT_POINT && inputType2.getDataType() != QT_MINTERVAL &&
+ inputType2.getDataType() != QT_FLOAT && inputType2.getDataType() != QT_DOUBLE &&
+ !inputType2.isInteger() )
+ {
+ RMInit::logOut << "Error: QtScale::checkType() - second operand must be either of type Point, Integer or Float." << endl;
+ parseInfo.setErrorNo(417);
+ throw parseInfo;
+ }
+
+ // pass MDD type
+ dataStreamType = inputType1;
+ }
+ else
+ RMInit::logOut << "Error: QtScale::checkType() - operand branch invalid." << endl;
+
+ return dataStreamType;
+}
+
+
+int QtScale::scaleDomain( const r_Minterval& areaOp,
+ const vector<double>& scaleFactors,
+ r_Minterval &areaScaled )
+{
+ RMDBGENTER( 2, RMDebug::module_qlparser, "QtScale",
+ "scaleDomain( D: " << areaOp << ", F: " << scaleFactors << ", D: " << areaScaled << " )" )
+
+ try
+ {
+ areaScaled = areaOp.create_scale(scaleFactors);
+ }
+ catch(r_Error)
+ {
+ //error scaling
+ RMInit::logOut << "Error: QtScale::scaleDomain() - exception while determining scale target interval for " << areaOp << " and " << scaleFactors << endl;
+ return 0;
+ }
+
+ RMDBGEXIT( 2, RMDebug::module_qlparser, "QtScale", "scaleDomain(...) D: " << areaOp << " mapped to D: " << areaScaled )
+
+ return 1;
+}
+
+// origin1 von getLoadDomain
+// origin2 von getCurrentDomain
+
+int QtScale::scaleDomain( const r_Minterval& areaOp, const r_Point& origin1, const r_Point& origin2,
+ const vector<double>& scaleFactors, r_Minterval &areaScaled )
+{
+ RMDBGENTER( 2, RMDebug::module_qlparser,
+ "QtScale", "scaleDomain( D: " << areaOp << ", O1: " << origin1 << ", O2: " << origin2
+ << ", F: " << scaleFactors << " D: " << areaScaled << " )" )
+
+ r_Minterval tempIv=areaOp;
+
+ //reverse_translated with origin1
+ tempIv.reverse_translate(origin1);
+
+ //scale it normaly
+ if(!scaleDomain(tempIv, scaleFactors, areaScaled))
+ return 0;
+
+ //translate areaScaled to origin2
+ areaScaled.translate(origin2);
+
+ RMDBGEXIT( 2, RMDebug::module_qlparser, "QtScale", "scaledDomain(...) D: " << areaOp << " translated to D: " << areaScaled )
+
+ return 1;
+}
+
diff --git a/qlparser/qtbinaryfunc.hh b/qlparser/qtbinaryfunc.hh
new file mode 100644
index 0000000..a96a877
--- /dev/null
+++ b/qlparser/qtbinaryfunc.hh
@@ -0,0 +1,201 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#ifndef _QTBINARYFUNC_
+#define _QTBINARYFUNC_
+
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+#endif
+
+#include "qlparser/qtbinaryoperation.hh"
+#include "raslib/sinterval.hh"
+#include "raslib/minterval.hh"
+#include <vector>
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ * - why is this "binary"? they all have just one MDD!
+ *
+ ************************************************************/
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+ The class represents a shift operation on MDD objects.
+
+*/
+
+class QtShift : public QtBinaryOperation
+{
+ public:
+ /// constructor getting the two operands
+ QtShift( QtOperation* mddOp, QtOperation* pointOp );
+
+ /// returns FALSE saying that the operation IS NOT commutative
+ virtual bool isCommutative() const;
+
+ /// method for evaluating the node
+ QtData* evaluate( QtDataList* inputList );
+ /**
+ */
+
+ /// prints the tree
+ virtual void printTree( int tab, std::ostream& s = std::cout, QtChildType mode = QT_ALL_NODES );
+
+ /// prints the algebraic expression
+ virtual void printAlgebraicExpression( std::ostream& s = std::cout );
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ /// optimizing load access
+ virtual void optimizeLoad( QtTrimList* trimList );
+
+ /// type checking of the subtree
+ virtual const QtTypeElement& checkType( QtTypeTuple* typeTuple = NULL );
+
+ private:
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+ The class represents an extend operation on MDD objects.
+
+*/
+
+class QtExtend : public QtBinaryOperation
+{
+ public:
+ /// constructor getting the two operands
+ QtExtend( QtOperation* mddOp, QtOperation* mintervalOp );
+ /**
+ FIXME: creates one single output tile, but should have a result tiling
+ */
+
+ /// returns FALSE saying that the operation IS NOT commutative
+ virtual bool isCommutative() const;
+
+ /// method for evaluating the node
+ QtData* evaluate( QtDataList* inputList );
+ /**
+ */
+
+ /// prints the tree
+ virtual void printTree( int tab, std::ostream& s = std::cout, QtChildType mode = QT_ALL_NODES );
+
+ /// prints the algebraic expression
+ virtual void printAlgebraicExpression( std::ostream& s = std::cout );
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ /// optimizing load access
+ virtual void optimizeLoad( QtTrimList* trimList );
+
+ /// type checking of the subtree
+ virtual const QtTypeElement& checkType( QtTypeTuple* typeTuple = NULL );
+
+ private:
+ /**
+ aux function for QtExtend::evaluate(): build up (recursing the dimension) a list of all spatial domains that sit in the corners between outerDomain and innerDomain; at the recursion bottom the resulting domain is added to the cornerList.
+ Preconditions:
+ - outerDomain, innerDomain defined values, of dimension maxDim
+ - currentDimension <= maxDim
+ - currentInterval has coordinates (no "*") set up to dimension currentDimension
+ @params outerDomain extended domain
+ @params innerDomain inner domain
+ @params currentDim current dimension to be inspected (0..maxDim)
+ @params maxDim maximum dimension to be inspected (#dimensions-1, suitable for indexing an r_Point or r_Minterval)
+ @params currentInterval current interval which is being built by iterating over its dimensions
+ @params cornerList list of corner intervals that is to be built; has to be deallocated by caller.
+ **/
+ void extendGetCornerTiles( r_Minterval outerDomain, r_Minterval innerDomain, r_Dimension currentDim, r_Dimension maxDim, r_Minterval currentInterval, vector<r_Minterval>* cornerList );
+
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+ The class represents a scale operation on MDD objects.
+
+*/
+
+class QtScale : public QtBinaryOperation
+{
+ public:
+ /// constructor getting the two operands
+ QtScale( QtOperation* mddOp, QtOperation* pointOp );
+
+ /// returns FALSE saying that the operation IS NOT commutative
+ virtual bool isCommutative() const;
+
+ /// method for evaluating the node
+ QtData* evaluate( QtDataList* inputList );
+ /**
+ */
+
+ /// prints the tree
+ virtual void printTree( int tab, std::ostream& s = std::cout, QtChildType mode = QT_ALL_NODES );
+
+ /// prints the algebraic expression
+ virtual void printAlgebraicExpression( std::ostream& s = std::cout );
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ /// optimizing load access
+ virtual void optimizeLoad( QtTrimList* trimList );
+
+ /// type checking of the subtree
+ virtual const QtTypeElement& checkType( QtTypeTuple* typeTuple = NULL );
+
+ /// scale domains - initial version
+ virtual int scaleDomain( const r_Minterval& areaOp, const r_Point& origin1, const r_Point& origin2, const vector<double>& scaleFactors, r_Minterval &areaScaled );
+
+ /// scale domains - the used version
+ virtual int scaleDomain( const r_Minterval& areaOp, const vector<double>& scaleFactors, r_Minterval &areaScaled );
+
+ private:
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+#include "qlparser/qtbinaryfunc.icc"
+
+#endif
+
diff --git a/qlparser/qtbinaryfunc.icc b/qlparser/qtbinaryfunc.icc
new file mode 100644
index 0000000..a808b4a
--- /dev/null
+++ b/qlparser/qtbinaryfunc.icc
@@ -0,0 +1,47 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+inline const QtNode::QtNodeType
+QtShift::getNodeType() const
+{
+ return nodeType;
+}
+
+inline const QtNode::QtNodeType
+QtExtend::getNodeType() const
+{
+ return nodeType;
+}
+
+
+inline const QtNode::QtNodeType
+QtScale::getNodeType() const
+{
+ return nodeType;
+}
diff --git a/qlparser/qtbinaryinduce.cc b/qlparser/qtbinaryinduce.cc
new file mode 100644
index 0000000..9f7b1ba
--- /dev/null
+++ b/qlparser/qtbinaryinduce.cc
@@ -0,0 +1,959 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)qlparser, QtBinaryInduce: $Id: qtbinaryinduce.cc,v 1.47 2003/12/27 20:39:35 rasdev Exp $";
+
+#include "raslib/rmdebug.hh"
+#include "debug.hh"
+
+#include "qlparser/qtbinaryinduce.hh"
+#include "qlparser/qtatomicdata.hh"
+#include "qlparser/qtcomplexdata.hh"
+#include "qlparser/qtconst.hh"
+#include "qlparser/qtstringdata.hh"
+
+#include "mddmgr/mddobj.hh"
+
+#include "catalogmgr/typefactory.hh"
+#include "relcatalogif/mdddomaintype.hh"
+
+#include "tilemgr/tile.hh"
+
+#include <iostream>
+#include <string>
+#include <vector>
+#include <memory>
+using namespace std;
+
+const QtNode::QtNodeType QtBinaryInduce::nodeType = QtNode::QT_BINARY_INDUCE;
+
+QtBinaryInduce::QtBinaryInduce( QtOperation* initInput1, QtOperation* initInput2, Ops::OpType initOpType )
+ : QtBinaryOperation( initInput1, initInput2 ),
+ opType( initOpType )
+{
+}
+
+
+
+QtData*
+QtBinaryInduce::computeOp( QtData* operand1, QtData* operand2 )
+{
+ RMDBCLASS( "QtBinaryInduce", "computeOp( QtData*, QtData* )", "qlparser", __FILE__, __LINE__ )
+
+ QtData* returnValue = NULL;
+
+ if ( operand1->getDataType() == QT_MDD &&
+ operand2->getDataType() == QT_MDD )
+ {
+ QtMDD* mdd1 = (QtMDD*) operand1;
+ QtMDD* mdd2 = (QtMDD*) operand2;
+
+ const BaseType* resultBaseType = ((MDDBaseType*)(dataStreamType.getType()))->getBaseType();
+
+ returnValue = computeBinaryMDDOp( mdd1, mdd2, resultBaseType );
+ }
+ else if( operand1->getDataType() == QT_MDD &&
+ operand2->isScalarData() )
+ {
+ QtMDD* mdd = (QtMDD*) operand1;
+ QtScalarData* scalar = (QtScalarData*) operand2;
+
+ const BaseType* resultBaseType = ((MDDBaseType*)(dataStreamType.getType()))->getBaseType();
+
+ returnValue = computeUnaryMDDOp( mdd, scalar, resultBaseType, 2 );
+ }
+ else if( operand1->isScalarData() &&
+ operand2->getDataType() == QT_MDD )
+ {
+ QtMDD* mdd = (QtMDD*) operand2;
+ QtScalarData* scalar = (QtScalarData*) operand1;
+
+ const BaseType* resultBaseType = ((MDDBaseType*)(dataStreamType.getType()))->getBaseType();
+
+ returnValue = computeUnaryMDDOp( mdd, scalar, resultBaseType, 1 );
+ }
+ else if( operand1->isScalarData() &&
+ operand2->isScalarData() )
+ {
+ QtScalarData* scalar1 = (QtScalarData*) operand1;
+ QtScalarData* scalar2 = (QtScalarData*) operand2;
+
+ BaseType* resultBaseType = (BaseType*)(dataStreamType.getType());
+
+ returnValue = computeBinaryOp( scalar1, scalar2, resultBaseType );
+ }
+ else if( operand1->getDataType() == QT_STRING && operand2->getDataType() == QT_STRING )
+ {
+ // opType == Ops::OP_EQUAL
+ QtStringData* strObj1 = (QtStringData*) operand1;
+ QtStringData* strObj2 = (QtStringData*) operand2;
+
+ bool booleanResult = strObj1->getStringData() == strObj2->getStringData();
+
+ returnValue = new QtAtomicData( booleanResult );
+ }
+
+ return returnValue;
+}
+
+
+
+QtData*
+QtBinaryInduce::computeUnaryMDDOp( QtMDD* operand1, QtScalarData* operand2, const BaseType* resultBaseType, int scalarPos )
+{
+ RMDBCLASS( "QtBinaryInduce", "computeUnaryMDDOp( QtMDD*, QtScalarData*, BaseType*, int )", "qlparser", __FILE__, __LINE__ )
+
+ QtData* returnValue = NULL;
+
+ // get the MDD object
+ MDDObj* op = operand1->getMDDObject();
+
+ // create ULong type with QtIntData value
+ const BaseType* constBaseType = operand2->getValueType();
+ const char* constValue = operand2->getValueBuffer();
+
+ // get the area, where the operation has to be applied
+ const r_Minterval &areaOp = operand1->getLoadDomain();
+
+ // contains all tiles of the operand
+ vector<Tile*>* allTiles=NULL;
+
+ // iterator for tiles
+ vector<Tile*>::iterator tileIt;
+
+ // create MDDObj for result
+ MDDDomainType* mddBaseType = new MDDDomainType( "tmp", resultBaseType, areaOp );
+ TypeFactory::addTempType( mddBaseType );
+
+ MDDObj* mddres = new MDDObj( mddBaseType, areaOp );
+
+ // get all tiles in relevant area
+ allTiles = op->intersect(areaOp);
+ tileIt = allTiles->begin();
+ //auto_ptr<BinaryOp> myOp(NULL);
+ BinaryOp* myOp = NULL;
+ if (tileIt != allTiles->end())
+ {
+ if (scalarPos == 1)
+ //myOp.reset(Ops::getBinaryOp(opType, resultBaseType, constBaseType, (*tileIt)->getType()));
+ myOp = (Ops::getBinaryOp(opType, resultBaseType, constBaseType, (*tileIt)->getType()));
+ else
+ //myOp.reset(Ops::getBinaryOp(opType, resultBaseType, (*tileIt)->getType(), constBaseType));
+ myOp = (Ops::getBinaryOp(opType, resultBaseType, (*tileIt)->getType(), constBaseType));
+ }
+ // and iterate over them
+ for( ; tileIt != allTiles->end(); tileIt++ )
+ {
+ // domain of the actual tile
+ const r_Minterval &tileDom = (*tileIt)->getDomain();
+
+ // domain of the relevant area of the actual tile
+ r_Minterval intersectDom( tileDom.create_intersection( areaOp ) );
+
+ // create tile for result
+ Tile* resTile = new Tile( intersectDom, resultBaseType );
+
+ //
+ // carry out operation on the relevant area of the tiles
+ //
+
+ RMDBGIF( 4, RMDebug::module_qlparser, "QtScale", \
+ char* typeStructure = resTile->getType()->getTypeStructure(); \
+ RMDBGMIDDLE( 4, RMDebug::module_qlparser, "QtBinaryInduce", " result tile, area " << intersectDom << \
+ ", type " << resTile->getType()->getTypeName() << \
+ ", structure " << typeStructure << endl ) \
+ free( typeStructure ); typeStructure=NULL; \
+ \
+ typeStructure = (*tileIt)->getType()->getTypeStructure(); \
+ RMDBGMIDDLE( 4, RMDebug::module_qlparser, "QtBinaryInduce", " operand1 tile, area " << intersectDom << \
+ ", type " << (*tileIt)->getType()->getTypeName() << \
+ ", structure " << typeStructure << endl ) \
+ free( typeStructure ); typeStructure=NULL; \
+
+ typeStructure = constBaseType->getTypeStructure(); \
+ RMDBGMIDDLE( 4, RMDebug::module_qlparser, "QtBinaryInduce", " constant type " << constBaseType->getTypeName() << \
+ ", structure " << typeStructure << \
+ ", value " ) \
+ free( typeStructure ); typeStructure=NULL; \
+ \
+ for( int x=0; x<constBaseType->getSize(); x++ ) \
+ RMInit::dbgOut << hex << (int)(constValue[x]); \
+ RMInit::dbgOut << dec << endl; \
+ )
+
+ RMDBGMIDDLE( 4, RMDebug::module_qlparser, "QtBinaryInduce", " before execConstOp" << endl )
+
+ resTile->execConstOp( myOp, intersectDom, (*tileIt), intersectDom, constValue, scalarPos );
+ //resTile->execConstOp( opType, intersectDom, (*tileIt), intersectDom, constValue, constBaseType, scalarPos );
+ RMDBGMIDDLE( 4, RMDebug::module_qlparser, "QtBinaryInduce", " after execConstOp" << endl )
+
+ // insert Tile in result tile
+ mddres->insertTile( resTile );
+ }
+ delete myOp;
+ myOp = NULL;
+
+ // delete tile vector
+ delete allTiles;
+ allTiles=NULL;
+
+ // create a new QtMDD object as carrier object for the transient MDD object
+ returnValue = new QtMDD( (MDDObj*)mddres );
+
+ // The following is now done, when the last reference is deleted.
+ // delete the obsolete MDD object
+ // delete op;
+
+ return returnValue;
+}
+
+
+
+QtData*
+QtBinaryInduce::computeBinaryMDDOp( QtMDD* operand1, QtMDD* operand2, const BaseType* resultBaseType )
+{
+ RMDBCLASS( "QtBinaryInduce", "computeBinaryMDDOp( QtMDD*, QtMDD*, BaseType* )", "qlparser", __FILE__, __LINE__ )
+
+ QtData* returnValue = NULL;
+
+ // get the MDD objects
+ MDDObj* op1 = operand1->getMDDObject();
+ MDDObj* op2 = operand2->getMDDObject();
+
+ // get the areas, where the operation has to be applied
+ const r_Minterval &areaOp1 = operand1->getLoadDomain();
+ const r_Minterval &areaOp2 = operand2->getLoadDomain();
+
+ // Check, if the domains are compatible which means that they have the same
+ // dimensionality and each dimension has the same number of elements.
+ if( areaOp1.get_extent() == areaOp2.get_extent() )
+ {
+ // contains all tiles of op1
+ vector<Tile*>* allTilesOp1=NULL;
+
+ // contains all tiles of op2 which intersect a given op1 Tile in the relevant area.
+ vector<Tile*>* intersectTilesOp2=NULL;
+
+ // iterators for tiles of the MDDs
+ vector<Tile*>::iterator tileOp1It;
+ vector<Tile*>::iterator intersectTileOp2It;
+
+ // intersection of domains in relevant area.
+ r_Minterval intersectDom;
+
+ // pointer to generated result tile
+ Tile* resTile=NULL;
+
+ // MDDObj for result
+ MDDObj* mddres=NULL;
+
+ // translations between the two areas
+ r_Point offset12(areaOp1.dimension());
+ r_Point offset21(areaOp1.dimension());
+
+ // calculate translations
+ r_Point originOp1 = areaOp1.get_origin();
+ r_Point originOp2 = areaOp2.get_origin();
+ for(r_Dimension i = 0; i<areaOp1.dimension(); i++)
+ {
+ offset12[i] = originOp2[i] - originOp1[i];
+ offset21[i] = originOp1[i] - originOp2[i];
+ }
+
+ RMDBGMIDDLE( 4, RMDebug::module_qlparser, "QtBinaryInduce", " Domain op1 " << areaOp1 << " op2 " << areaOp2 )
+ RMDBGMIDDLE( 4, RMDebug::module_qlparser, "QtBinaryInduce", " Translation vector " << offset12 )
+
+ // create MDDObj for result
+ MDDDomainType* mddBaseType = new MDDDomainType( "tmp", resultBaseType, areaOp1 );
+ TypeFactory::addTempType( mddBaseType );
+
+ mddres = new MDDObj( mddBaseType, areaOp1 );
+
+ // get all tiles in relevant area of MDD op1
+ allTilesOp1 = op1->intersect(areaOp1);
+
+ // cout << "INTERSECT" << areaOp1 << endl;
+ // for( tileOp1It = allTilesOp1->begin(); tileOp1It != allTilesOp1->end(); tileOp1It++ )
+ // cout << (*tileOp1It)->getDomain() << endl;
+
+ // and iterate over them
+ auto_ptr<BinaryOp> myOp(Ops::getBinaryOp(opType, mddBaseType->getBaseType(), op1->getCellType(), op2->getCellType()));
+ for( tileOp1It = allTilesOp1->begin(); tileOp1It != allTilesOp1->end(); tileOp1It++ )
+ {
+ // domain of the op1 tile
+ const r_Minterval &tileOp1Dom = (*tileOp1It)->getDomain();
+
+ // relevant area of op1's domain
+ r_Minterval intersectionTileOp1Dom( tileOp1Dom.create_intersection( areaOp1 ) );
+
+ // intersect relevant area of the tile with MDD op2 (including translation)
+ intersectTilesOp2 = op2->intersect(intersectionTileOp1Dom.create_translation(offset12));
+
+ // cout << "INTERSECT" << tileOp1Dom.create_translation(offset12) << endl;
+ // for( intersectTileOp2It = intersectTilesOp2->begin();
+ // intersectTileOp2It != intersectTilesOp2->end();
+ // intersectTileOp2It++ )
+ // cout << (*intersectTileOp2It)->getDomain() << endl;
+
+ // iterate over intersecting tiles
+ for( intersectTileOp2It = intersectTilesOp2->begin();
+ intersectTileOp2It != intersectTilesOp2->end();
+ intersectTileOp2It++ )
+ {
+ const r_Minterval &tileOp2Dom = (*intersectTileOp2It)->getDomain();
+
+ // the relevant domain is the intersection of the
+ // domains of the two tiles with the relevant area.
+ intersectDom = tileOp1Dom.create_intersection(tileOp2Dom.create_translation(offset21));
+
+ intersectDom.intersection_with(areaOp1);
+
+ // create tile for result
+ resTile = new Tile( intersectDom, resultBaseType );
+
+ //
+ // carry out operation on the relevant area of the tiles
+ //
+
+ RMDBGMIDDLE( 4, RMDebug::module_qlparser, "QtBinaryInduce", " before execBinaryOp" << endl )
+ RMDBGMIDDLE( 4, RMDebug::module_qlparser, "QtBinaryInduce", " result tile, area " << intersectDom <<
+ ", type " << resTile->getType()->getTypeName() << endl )
+ RMDBGMIDDLE( 4, RMDebug::module_qlparser, "QtBinaryInduce", " operand1 tile, area " << intersectDom <<
+ ", type " << (*tileOp1It)->getType()->getTypeName() << endl )
+ RMDBGMIDDLE( 4, RMDebug::module_qlparser, "QtBinaryInduce", " operand2 tile, type " << (*tileOp1It)->getType()->getTypeName() << endl )
+ resTile->execBinaryOp(&(*myOp), intersectDom, (*tileOp1It), intersectDom, (*intersectTileOp2It), intersectDom.create_translation(offset12));
+ RMDBGMIDDLE( 4, RMDebug::module_qlparser, "QtBinaryInduce", " after execBinaryOp" << endl )
+
+ // insert Tile in result mddobj
+ mddres->insertTile( resTile );
+ }
+
+ delete intersectTilesOp2;
+ intersectTilesOp2=NULL;
+ }
+
+ delete allTilesOp1;
+ allTilesOp1=NULL;
+
+ // create a new QtMDD object as carrier object for the transient MDD object
+ returnValue = new QtMDD( (MDDObj*)mddres );
+ }
+ else
+ {
+ RMInit::logOut << "Error: QtBinaryInduce::computeBinaryMDDOp() - domains of the operands are incompatible." << endl;
+ RMInit::logOut << "areaOp1 " << areaOp1 << " with extent " << areaOp1.get_extent() << endl;
+ RMInit::logOut << "areaOp2 " << areaOp2 << " with extent " << areaOp2.get_extent() << endl;
+
+ parseInfo.setErrorNo(351);
+ throw parseInfo;
+ }
+
+ // The following is now done, when the last reference is deleted.
+ // delete obsolete MDD objects
+ // delete op1;
+ // delete op2;
+
+ return returnValue;
+}
+
+
+
+QtData*
+QtBinaryInduce::computeBinaryOp( QtScalarData* operand1, QtScalarData* operand2, const BaseType* resultBaseType )
+{
+ RMDBCLASS( "QtBinaryInduce", "computeBinaryOp( QtScalarData*, QtScalarData*, BaseType*, Ops::OpType )", "qlparser", __FILE__, __LINE__ )
+
+ QtScalarData* scalarDataObj = NULL;
+
+ // allocate memory for the result
+ char* resultBuffer = new char[ resultBaseType->getSize() ];
+
+ Ops::execBinaryConstOp( opType, resultBaseType,
+ operand1->getValueType(), operand2->getValueType(),
+ resultBuffer,
+ operand1->getValueBuffer(), operand2->getValueBuffer() );
+
+ if( resultBaseType->getType() == STRUCT )
+ scalarDataObj = new QtComplexData();
+ else
+ scalarDataObj = new QtAtomicData();
+
+ scalarDataObj->setValueType ( resultBaseType );
+ scalarDataObj->setValueBuffer( resultBuffer );
+
+ return scalarDataObj;
+}
+
+
+
+QtData*
+QtBinaryInduce::evaluate( QtDataList* inputList )
+{
+ QtData* returnValue = NULL;
+ QtData* operand1 = NULL;
+ QtData* operand2 = NULL;
+
+ if( getOperands( inputList, operand1, operand2 ) )
+ {
+ returnValue = computeOp( operand1, operand2 );
+
+ // delete the old operands
+ if( operand1 ) operand1->deleteRef();
+ if( operand2 ) operand2->deleteRef();
+ }
+ return returnValue;
+}
+
+
+
+const QtTypeElement&
+QtBinaryInduce::checkType( QtTypeTuple* typeTuple )
+{
+ RMDBCLASS( "QtBinaryInduce", "checkType( QtTypeTuple* )", "qlparser", __FILE__, __LINE__ )
+
+ dataStreamType.setDataType( QT_TYPE_UNKNOWN );
+
+ // check operand branches
+ if( input1 && input2 )
+ {
+
+ // get input types
+ const QtTypeElement& inputType1 = input1->checkType( typeTuple );
+ const QtTypeElement& inputType2 = input2->checkType( typeTuple );
+
+ RMDBGIF( 1, RMDebug::module_qlparser, "QtBinaryInduce", \
+ RMInit::dbgOut << "Operand 1: " << flush; \
+ inputType1.printStatus( RMInit::dbgOut ); \
+ RMInit::dbgOut << endl; \
+ \
+ RMInit::dbgOut << "Operand 2: " << flush; \
+ inputType2.printStatus( RMInit::dbgOut ); \
+ RMInit::dbgOut << endl; \
+ \
+ RMDBGMIDDLE( 4, RMDebug::module_qlparser, "QtBinaryInduce", "Operation " << opType ) \
+ )
+
+ if( inputType1.getDataType() == QT_MDD &&
+ inputType2.getDataType() == QT_MDD )
+ {
+ const BaseType* baseType1 = ((MDDBaseType*)(inputType1.getType()))->getBaseType();
+ const BaseType* baseType2 = ((MDDBaseType*)(inputType2.getType()))->getBaseType();
+
+ const BaseType* resultBaseType = Ops::getResultType( opType, baseType1, baseType2 );
+
+ if( !resultBaseType )
+ {
+ RMInit::logOut << "Error: QtBinaryInduce::checkType() - binary induce (MDD + MDD): operand types are incompatible." << endl;
+ parseInfo.setErrorNo(363);
+ throw parseInfo;
+ }
+
+ MDDBaseType* resultMDDType = new MDDBaseType( "tmp", resultBaseType );
+ TypeFactory::addTempType( resultMDDType );
+
+ dataStreamType.setType( resultMDDType );
+ }
+ else if( inputType1.getDataType() == QT_MDD &&
+ inputType2.isBaseType() )
+ {
+ const BaseType* baseType1 = ((MDDBaseType*)(inputType1.getType()))->getBaseType();
+ BaseType* baseType2 = (BaseType*)(inputType2.getType());
+
+ const BaseType* resultBaseType = Ops::getResultType( opType, baseType1, baseType2 );
+
+ if( !resultBaseType )
+ {
+ RMInit::logOut << "Error: QtBinaryInduce::checkType() - unary induce (MDD + BaseType): operand types are incompatible." << endl;
+ parseInfo.setErrorNo(364);
+ throw parseInfo;
+ }
+
+ MDDBaseType* resultMDDType = new MDDBaseType( "tmp", resultBaseType );
+ TypeFactory::addTempType( resultMDDType );
+
+ dataStreamType.setType( resultMDDType );
+ }
+ else if( inputType1.isBaseType() &&
+ inputType2.getDataType() == QT_MDD )
+ {
+ BaseType* baseType1 = (BaseType*)(inputType1.getType());
+ const BaseType* baseType2 = ((MDDBaseType*)(inputType2.getType()))->getBaseType();
+
+ const BaseType* resultBaseType = Ops::getResultType( opType, baseType1, baseType2 );
+
+ if( !resultBaseType )
+ {
+ RMInit::logOut << "Error: QtBinaryInduce::checkType() - unary induce (BaseType + MDD): operand types are incompatible." << endl;
+ parseInfo.setErrorNo(364);
+ throw parseInfo;
+ }
+
+ MDDBaseType* resultMDDType = new MDDBaseType( "tmp", resultBaseType );
+ TypeFactory::addTempType( resultMDDType );
+
+ dataStreamType.setType( resultMDDType );
+ }
+ else if( inputType1.isBaseType() &&
+ inputType2.isBaseType() )
+ {
+ BaseType* baseType1 = (BaseType*)(inputType1.getType());
+ BaseType* baseType2 = (BaseType*)(inputType2.getType());
+
+ const BaseType* resultBaseType = Ops::getResultType( opType, baseType1, baseType2 );
+
+ if( !resultBaseType )
+ {
+ RMInit::logOut << "Error: QtBinaryInduce::checkType() - BaseType + BaseType : operand types are incompatible." << endl;
+
+ parseInfo.setErrorNo(365);
+ throw parseInfo;
+ }
+
+ dataStreamType.setType( resultBaseType );
+ }
+ else if( inputType1.getDataType() == QT_STRING &&
+ inputType2.getDataType() == QT_STRING )
+ {
+ if( opType != Ops::OP_EQUAL )
+ {
+ RMInit::logOut << "Error: QtBinaryInduce::checkType() - String + String : operation is not supported on strings." << endl;
+ parseInfo.setErrorNo(385);
+ throw parseInfo;
+ }
+
+ dataStreamType.setDataType( QT_BOOL );
+ }
+ else
+ {
+ RMInit::logOut << "Error: QtBinaryInduce::checkType() - operation is not supported on these data types." << endl;
+ parseInfo.setErrorNo(403);
+ throw parseInfo;
+ }
+ }
+ else
+ RMInit::logOut << "Error: QtBinaryInduce::checkType() - operand branch invalid." << endl;
+
+ return dataStreamType;
+}
+
+
+
+const QtNode::QtNodeType QtPlus::nodeType = QT_PLUS;
+
+QtPlus::QtPlus( QtOperation* initInput1, QtOperation* initInput2 )
+ : QtBinaryInduce( initInput1, initInput2, Ops::OP_PLUS )
+{
+}
+
+
+/*
+void
+QtPlus::rewriteOps()
+{
+ RMDBCLASS( "QtPlus", "rewriteOps()", "qlparser", __FILE__, __LINE__ )
+
+ if( input1 && input2 )
+ {
+ if( nodeType == input2->getNodeType() )
+ {
+ // changed from log to debug output -- PB 2003-nov-20
+ RMDBGMIDDLE( 1, RMDebug::module_qlparser, "QtPlus", "rewriteOps: rule (left deep tree): A+(B+C) -> (B+C)+A" );
+
+ // more than one equal binary operator, make standard form of the tree
+
+ QtBinaryOperation* nodeR = (QtBinaryOperation*) input2;
+ QtOperation* nodeRL = nodeR->getInput1();
+
+ getParent()->setInput( this, nodeR );
+ nodeR->setInput1( this );
+ this->setInput2( nodeRL );
+ nodeR->rewriteOps();
+ }
+ else
+ {
+ input1->rewriteOps();
+ input2->rewriteOps();
+ }
+ }
+ else
+ RMInit::logOut << "Error: QtPlus::rewriteOps() - the operand branch is invalid." << endl;
+}
+*/
+
+/*
+void
+QtPlus::sortAssociativeOps()
+{
+ ENTER( "QtPlus::sortAssociativeOps() -- input1 is " << (input1?"not null":"null") << ", input 2 is " << (input2?"not null":"null") );
+
+ if( input1 && input2 )
+ {
+ if( nodeType == input1->getNodeType() )
+ {
+ // associative law is applicable
+
+ QtOperation* node = input1->getUniqueOrder( nodeType );
+
+ if( node && node->getSpelling().compare( input2->getSpelling() ) > 0 )
+ {
+ node->getParent()->setInput( node, input2 );
+ setInput2( node );
+ }
+ }
+ else
+ {
+ bool compare = ( input1->getSpelling().compare( input2->getSpelling() ) > 0 );
+ TALK( "QtPlus::sortAssociativeOps(): compare -> " << compare );
+ if( compare )
+ {
+ // changed from log to debug output -- PB 2003-nov-20
+ RMDBGMIDDLE( 1, RMDebug::module_qlparser, "QtPlus", "sortAssociativeOps: applying rule 'associativity'" );
+
+ QtOperation* node = input1;
+
+ setInput1( input2 );
+ setInput2( node );
+ };
+
+ };
+
+ input1->sortAssociativeOps();
+ }
+ else
+ RMInit::logOut << "Error: QtPlus::sortAssociativeOps() - the operand branch is invalid." << endl;
+
+ LEAVE( "QtPlus::sortAssociativeOps()" );
+}
+*/
+
+
+QtOperation*
+QtPlus::getUniqueOrder( const QtNode::QtNodeType ID )
+{
+ RMDBCLASS( "QtPlus", "getUniqueOrder( const QtNode::QtNodeType )", "qlparser", __FILE__, __LINE__ )
+
+ QtOperation* returnValue = NULL;
+
+ if( nodeType == ID )
+ {
+ QtOperation* node = input1->getUniqueOrder( nodeType );
+
+ if( node )
+ {
+ if( ( node->getSpelling().compare( input2->getSpelling() ) ) > 0 )
+ returnValue = node;
+ else
+ returnValue = input2;
+ }
+ else
+ RMInit::logOut << "Error: QtMult::getUniqueOrder(): Query tree invalid" << endl;
+ }
+ else
+ returnValue = this;
+
+ return returnValue;
+}
+
+
+
+void
+QtPlus::printTree( int tab, ostream& s, QtChildType mode )
+{
+ s << SPACE_STR(tab).c_str() << "QtPlus Object " << getNodeType() << endl;
+
+ QtBinaryInduce::printTree( tab, s, mode );
+}
+
+
+
+void
+QtPlus::printAlgebraicExpression( ostream& s )
+{
+ s << "(";
+
+ if( input1 )
+ input1->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << " + ";
+
+ if( input2 )
+ input2->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << ")";
+}
+
+
+
+const QtNode::QtNodeType QtMinus::nodeType = QT_MINUS;
+
+QtMinus::QtMinus( QtOperation* initInput1, QtOperation* initInput2 )
+ : QtBinaryInduce( initInput1, initInput2, Ops::OP_MINUS )
+{
+}
+
+
+
+bool
+QtMinus::isCommutative() const
+{
+ return false; // NOT commutative
+}
+
+
+
+void
+QtMinus::printTree( int tab, ostream& s, QtChildType mode )
+{
+ s << SPACE_STR(tab).c_str() << "QtMinus Object " << getNodeType() << endl;
+
+ QtBinaryInduce::printTree( tab, s, mode );
+}
+
+
+
+void
+QtMinus::printAlgebraicExpression( ostream& s )
+{
+ s << "(";
+
+ if( input1 )
+ input1->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << " - ";
+
+ if( input2 )
+ input2->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << ")";
+}
+
+
+
+
+const QtNode::QtNodeType QtMult::nodeType = QT_MULT;
+
+QtMult::QtMult( QtOperation* initInput1, QtOperation* initInput2 )
+ : QtBinaryInduce( initInput1, initInput2, Ops::OP_MULT )
+{
+}
+
+
+/*
+void
+QtMult::rewriteOps()
+{
+ RMDBCLASS( "QtMult", "rewriteOps()", "qlparser", __FILE__, __LINE__ )
+
+ if( input1 && input2 )
+ {
+ if( nodeType == input2->getNodeType() )
+ {
+ RMInit::logOut << "> rule (left deep tree): A*(B*C) -> (B*C)*A" << endl;
+
+ // more than one equal binary operator, make standard form of the tree
+
+ QtBinaryOperation* nodeR = (QtBinaryOperation*) input2;
+ QtOperation* nodeRL = nodeR->getInput1();
+
+ getParent()->setInput( this, nodeR );
+ nodeR->setInput1( this );
+ this->setInput2( nodeRL );
+ nodeR->rewriteOps();
+ }
+ else
+ {
+ input1->rewriteOps();
+ input2->rewriteOps();
+ }
+ }
+ else
+ RMInit::logOut << "Error: QtMult::rewriteOps() - the operand branch is invalid." << endl;
+}
+*/
+
+/*
+void
+QtMult::sortAssociativeOps()
+{
+ RMDBCLASS( "QtMult", "sortAssociativeOps()", "qlparser", __FILE__, __LINE__ )
+
+ if( input1 && input2 )
+ {
+ if( nodeType == input1->getNodeType() )
+ {
+ // associative law is applicable
+
+ QtOperation* node = input1->getUniqueOrder( nodeType );
+
+ if( node && node->getSpelling().compare( input2->getSpelling() ) > 0 )
+ {
+ node->getParent()->setInput( node, input2 );
+ setInput2( node );
+ };
+ }
+ else
+ {
+ if( input1->getSpelling().compare( input2->getSpelling() ) > 0 )
+ {
+ RMDBGMIDDLE( 1, RMDebug::module_qlparser, "QtMult", "sortAssociativeOps: rule (associativity): A * B -> B * A" );
+
+ QtOperation* node = input1;
+
+ setInput1( input2 );
+ setInput2( node );
+ };
+ }
+
+ input1->sortAssociativeOps();
+ }
+ else
+ RMInit::logOut << "Error: QtMult::sortAssociativeOps() - the operand branch is invalid." << endl;
+}
+*/
+
+
+QtOperation*
+QtMult::getUniqueOrder( const QtNode::QtNodeType ID )
+{
+ RMDBCLASS( "QtMult", "getUniqueOrder( const string )", "qlparser", __FILE__, __LINE__ )
+
+ QtOperation* returnValue = NULL;
+
+ if( nodeType == ID )
+ {
+ QtOperation* node = input1->getUniqueOrder( nodeType );
+
+ if( node )
+ {
+ if( node->getSpelling().compare( input2->getSpelling() ) > 0 )
+ returnValue = node;
+ else
+ returnValue = input2;
+ }
+ else
+ RMInit::logOut << "Error: QtMult::getUniqueOrder(): Query tree invalid" << endl;
+ }
+ else
+ returnValue = this;
+
+ return returnValue;
+}
+
+
+
+void
+QtMult::printTree( int tab, ostream& s, QtChildType mode )
+{
+ s << SPACE_STR(tab).c_str() << "QtMult Object " << getNodeType() << endl;
+
+ QtBinaryInduce::printTree( tab, s, mode );
+}
+
+
+
+void
+QtMult::printAlgebraicExpression( ostream& s )
+{
+ s << "(";
+
+ if( input1 )
+ input1->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << " * ";
+
+ if( input2 )
+ input2->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << ")";
+}
+
+
+
+const QtNode::QtNodeType QtDiv::nodeType = QT_DIV;
+
+QtDiv::QtDiv( QtOperation* initInput1, QtOperation* initInput2 )
+ : QtBinaryInduce( initInput1, initInput2, Ops::OP_DIV )
+{
+}
+
+
+
+bool
+QtDiv::isCommutative() const
+{
+ return false; // NOT commutative
+}
+
+
+
+void
+QtDiv::printTree( int tab, ostream& s, QtChildType mode )
+{
+ s << SPACE_STR(tab).c_str() << "QtDiv Object " << getNodeType() << endl;
+
+ QtBinaryInduce::printTree( tab, s, mode );
+}
+
+
+
+void
+QtDiv::printAlgebraicExpression( ostream& s )
+{
+ s << "(";
+
+ if( input1 )
+ input1->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << " / ";
+
+ if( input2 )
+ input2->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << ")";
+}
+
diff --git a/qlparser/qtbinaryinduce.hh b/qlparser/qtbinaryinduce.hh
new file mode 100644
index 0000000..de744e3
--- /dev/null
+++ b/qlparser/qtbinaryinduce.hh
@@ -0,0 +1,261 @@
+#ifndef _QTBINARYINDUCE_
+#define _QTBINARYINDUCE_
+
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+#endif
+
+#include "qlparser/qtbinaryoperation.hh"
+#include "qlparser/qtdata.hh"
+#include "qlparser/qtmdd.hh"
+#include "qlparser/qtscalardata.hh"
+
+#include "catalogmgr/ops.hh"
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+The class hierarchy guarantees no type safety. Type checking is done at
+execution time.
+
+The operations greater and greater equal are mapped to QtLess and QtLessEqual.
+*/
+
+class QtBinaryInduce : public QtBinaryOperation
+{
+ public:
+ /// constructor getting the two operands
+ QtBinaryInduce( QtOperation* input1, QtOperation* input2, Ops::OpType initOpType );
+
+ /// method for evaluating the node
+ QtData* evaluate( QtDataList* inputList );
+
+ /// type checking of the subtree
+ virtual const QtTypeElement& checkType( QtTypeTuple* typeTuple = NULL );
+
+ protected:
+ /// computes the binary operation
+ QtData* computeOp( QtData* operand1, QtData* operand2 );
+
+ /// computes an unary induce operation with one MDD object and a scalar value either being atomic or complex constant
+ QtData* computeUnaryMDDOp( QtMDD* operand1, QtScalarData* operand2, const BaseType* resultBaseType, int scalarPos=1 );
+ /**
+ The method carries out the unary induce operation specified by {\tt operation} on the two operands. {\tt scalarPos }
+ determines if the scalar value is the first (=1, default) or the second (=2) operand in the operation. For
+ the result, a new transient MDD object is created and returned. In the end, the MDD object of the first operand
+ is freed.
+ */
+
+ /// computes a binary induce operation on two MDD objects
+ QtData* computeBinaryMDDOp( QtMDD* operand1, QtMDD* operand2, const BaseType* resultBaseType );
+ /**
+ The method carries out the binary induce operation specified by {\tt operation} on the two operands. For
+ the result, a new transient MDD object is created and returned. In the end, the MDD objects of the operands
+ are freed.
+ */
+
+ /// computes a binary operation on two scalar objects
+ QtData* computeBinaryOp( QtScalarData* operand1, QtScalarData* operand2, const BaseType* resultBaseType );
+ /**
+ The method carries out the binary operation specified by {\tt operation} on the two operands.
+ */
+
+// private:
+ // type of operation
+ Ops::OpType opType;
+
+ private:
+ /// atribute for identification of nodes
+ static const QtNodeType nodeType;
+
+};
+
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+*/
+
+class QtPlus : public QtBinaryInduce
+{
+ public:
+ /// constructor getting the two operands
+ QtPlus( QtOperation* input1, QtOperation* input2 );
+
+ /// optimizes the tree
+// virtual void rewriteOps();
+
+ /// optimizes the tree
+// virtual void sortAssociativeOps();
+
+ ///for associative law
+ virtual QtOperation* getUniqueOrder( const QtNode::QtNodeType ID );
+
+ /// prints the tree
+ virtual void printTree( int tab, std::ostream& s = std::cout, QtChildType mode = QT_ALL_NODES );
+
+ /// prints the algebraic expression
+ virtual void printAlgebraicExpression( std::ostream& s = std::cout );
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ private:
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+*/
+
+class QtMinus : public QtBinaryInduce
+{
+ public:
+ /// constructor getting the two operands
+ QtMinus( QtOperation* input1, QtOperation* input2 );
+
+ /// prints the tree
+ virtual void printTree( int tab, std::ostream& s = std::cout, QtChildType mode = QT_ALL_NODES );
+
+ /// prints the algebraic expression
+ virtual void printAlgebraicExpression( std::ostream& s = std::cout );
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ /// returns FALSE saying that the operation IS NOT commutative
+ virtual bool isCommutative() const;
+
+ private:
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+*/
+
+class QtMult : public QtBinaryInduce
+{
+ public:
+ /// constructor getting the two operands
+ QtMult( QtOperation* input1, QtOperation* input2 );
+
+ /// optimizes the tree
+// virtual void rewriteOps();
+
+ /// optimizes the tree
+// virtual void sortAssociativeOps();
+
+ /// optimizes the tree
+ virtual QtOperation* getUniqueOrder( const QtNode::QtNodeType ID );
+
+ /// prints the tree
+ virtual void printTree( int tab, std::ostream& s = std::cout, QtChildType mode = QT_ALL_NODES );
+
+ /// prints the algebraic expression
+ virtual void printAlgebraicExpression( std::ostream& s = std::cout );
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ private:
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+*/
+
+class QtDiv : public QtBinaryInduce
+{
+ public:
+ /// constructor getting the two operands
+ QtDiv( QtOperation* input1, QtOperation* input2 );
+
+ /// prints the tree
+ virtual void printTree( int tab, std::ostream& s = std::cout, QtChildType mode = QT_ALL_NODES );
+
+ /// prints the algebraic expression
+ virtual void printAlgebraicExpression( std::ostream& s = std::cout );
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ /// returns FALSE saying that the operation IS NOT commutative
+ virtual bool isCommutative() const;
+
+ private:
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+
+#include "qlparser/qtbinaryinduce.icc"
+
+#endif
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/qlparser/qtbinaryinduce.icc b/qlparser/qtbinaryinduce.icc
new file mode 100644
index 0000000..6a7caa9
--- /dev/null
+++ b/qlparser/qtbinaryinduce.icc
@@ -0,0 +1,56 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+inline const QtNode::QtNodeType
+QtPlus::getNodeType() const
+{
+ return nodeType;
+}
+
+
+inline const QtNode::QtNodeType
+QtMinus::getNodeType() const
+{
+ return nodeType;
+}
+
+
+inline const QtNode::QtNodeType
+QtMult::getNodeType() const
+{
+ return nodeType;
+}
+
+
+inline const QtNode::QtNodeType
+QtDiv::getNodeType() const
+{
+ return nodeType;
+}
+
diff --git a/qlparser/qtbinaryinduce2.cc b/qlparser/qtbinaryinduce2.cc
new file mode 100644
index 0000000..c12479c
--- /dev/null
+++ b/qlparser/qtbinaryinduce2.cc
@@ -0,0 +1,919 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)qlparser, QtBinaryInduce: $Id: qtbinaryinduce2.cc,v 1.25 2002/09/11 14:48:51 hoefner Exp $";
+
+#include "raslib/rmdebug.hh"
+
+#include "qlparser/qtbinaryinduce2.hh"
+#include "qlparser/qtatomicdata.hh"
+#include "qlparser/qtconst.hh"
+
+#include "mddmgr/mddobj.hh"
+
+#include "catalogmgr/typefactory.hh"
+
+#include <iostream>
+#include <string>
+#include <vector>
+using namespace std;
+
+const QtNode::QtNodeType QtIs::nodeType = QT_IS;
+
+QtIs::QtIs( QtOperation* initInput1, QtOperation* initInput2 )
+ : QtBinaryInduce( initInput1, initInput2, Ops::OP_EQUAL )
+{
+}
+
+/*
+void
+QtIs::checkIdempotency()
+{
+ if( input1->getSpelling().compare( input2->getSpelling() ) == 0 )
+ {
+ RMInit::logOut << "> rule (idempotency): A IS A -> TRUE" << endl;
+
+ getParent()->setInput( this, new QtConst( new QtAtomicData( 1 ) ) );
+
+ // delete the node itself and its descendants
+ delete this;
+ };
+}
+*/
+
+void
+QtIs::printTree( int tab, ostream& s, QtChildType mode )
+{
+ s << SPACE_STR(tab).c_str() << "QtIs Object " << getNodeType() << endl;
+
+ QtBinaryInduce::printTree( tab, s, mode );
+}
+
+
+void
+QtIs::printAlgebraicExpression( ostream& s )
+{
+ s << "(";
+
+ if( input1 )
+ input1->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << " is ";
+
+ if( input2 )
+ input2->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << ")";
+}
+
+
+const QtNode::QtNodeType QtAnd::nodeType = QT_AND;
+
+QtAnd::QtAnd( QtOperation* initInput1, QtOperation* initInput2 )
+ : QtBinaryInduce( initInput1, initInput2, Ops::OP_AND )
+{
+}
+
+/*
+void
+QtAnd::checkIdempotency()
+{
+ if( input2->getNodeType() == QtNode::QT_CONST &&
+ ((QtConst*)input2)->getDataObj()->getDataType() == QT_BOOL )
+ {
+ QtAtomicData* boolData = (QtAtomicData*)((QtConst*)input2)->getDataObj();
+
+ if( boolData->getUnsignedValue() )
+ {
+ RMInit::logOut << "> rule (idempotency): A AND TRUE -> A" << endl;
+
+ getParent()->setInput( this, input1 );
+
+ // delete the node itself and its descendants but not input1
+ setInput1(NULL);
+ delete this;
+ }
+ else
+ {
+ if( input1->getAreaType() == QtNode::QT_AREA_SCALAR )
+ {
+ RMInit::logOut << "> rule (idempotency): A (scalar) AND FALSE -> FALSE" << endl;
+
+ getParent()->setInput( this, input2 );
+
+ // delete the node itself and its descendants but not input2
+ setInput2(NULL);
+ delete this;
+ };
+ }
+ }
+ else
+ if( input1->getNodeType() == QtNode::QT_CONST &&
+ ((QtConst*)input1)->getDataObj()->getDataType() == QT_BOOL )
+ {
+ QtAtomicData* boolData = (QtAtomicData*)((QtConst*)input1)->getDataObj();
+
+ if( boolData->getUnsignedValue() )
+ {
+ RMInit::logOut << "> rule (idempotency): TRUE AND A -> A" << endl;
+
+ getParent()->setInput( this, input2 );
+
+ // delete the node itself and its descendants but not input2
+ setInput2(NULL);
+ delete this;
+ }
+ else
+ {
+ if( input2->getAreaType() == QtNode::QT_AREA_SCALAR )
+ {
+ RMInit::logOut << "> rule (idempotency): FALSE AND A (scalar) -> FALSE" << endl;
+
+ getParent()->setInput( this, input1 );
+
+ // delete the node itself and its descendants but not input1
+ setInput1(NULL);
+ delete this;
+ };
+ };
+ }
+ else
+ if( input1->getSpelling().compare( input2->getSpelling() ) == 0 )
+ {
+ RMInit::logOut << "> rule (idempotency): A AND A -> A" << endl;
+
+ getParent()->setInput( this, input1 );
+
+ // delete the node itself and its descendants but not input1
+ setInput1(NULL);
+ delete this;
+ }
+}
+*/
+
+
+
+/*
+void
+QtAnd::rewriteOps()
+{
+ if( input1 && input2 )
+ {
+ if( input1->getNodeType() == QtNode::QT_SOME &&
+ input2->getNodeType() == QtNode::QT_ALL )
+ {
+ RMInit::logOut << "> rule (condenser order): SOME_CELLS AND ALL_CELLS -> ALL_CELLS AND SOME_CELLS" << endl;
+
+ // order condenser expressions
+
+ QtOperation* node1 = getInput1();
+ QtOperation* node2 = getInput2();
+
+ setInput1( node2 );
+ setInput2( node1 );
+ };
+ }
+ else
+ RMInit::logOut << "Error: QtAnd::rewriteOps() - the operand branch is invalid." << endl;
+}
+*/
+
+
+QtData*
+QtAnd::evaluate( QtDataList* inputList )
+{
+ /*
+ // RUNTIME OPTIMIZATION: FALSE AND A -> MDD(FALSE)
+ // A AND FALSE -> MDD(FALSE)
+ // TRUE AND A -> A
+ // A AND TRUE -> A
+ */
+
+ QtData* returnValue = NULL;
+
+ if( input1->getDataStreamType().getDataType() == QT_BOOL &&
+ input2->getDataStreamType().getDataType() == QT_BOOL )
+ {
+ // RUNTIME OPTIMIZATION: FALSE AND A -> FALSE
+ // TRUE AND A -> A
+
+ QtData* operand1=NULL;
+
+ if( getOperand( inputList, operand1, 1 ) )
+ {
+ bool op1 = ((QtAtomicData*)operand1)->getUnsignedValue();
+
+ if( op1 )
+ {
+ // first operand is obsolete
+ if( operand1 ) operand1->deleteRef();
+
+ QtData* operand2=NULL;
+
+ if( getOperand( inputList, operand2, 2 ) )
+ {
+ returnValue = operand2;
+ }
+ }
+ else
+ {
+ returnValue = operand1;
+ RMDBGONCE(1, RMDebug::module_qlparser, "QtAnd", " -> FALSE AND A evaluates FALSE")
+ }
+ }
+ }
+ else
+ returnValue = QtBinaryInduce::evaluate( inputList );
+
+ return returnValue;
+}
+
+
+void
+QtAnd::printTree( int tab, ostream& s, QtChildType mode )
+{
+ s << SPACE_STR(tab).c_str() << "QtAnd Object " << getNodeType() << endl;
+
+ QtBinaryInduce::printTree( tab, s, mode );
+}
+
+
+void
+QtAnd::printAlgebraicExpression( ostream& s )
+{
+ s << "(";
+
+ if( input1 )
+ input1->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << " and ";
+
+ if( input2 )
+ input2->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << ")";
+}
+
+
+
+const QtNode::QtNodeType QtOr::nodeType = QT_OR;
+
+QtOr::QtOr( QtOperation* initInput1, QtOperation* initInput2 )
+ : QtBinaryInduce( initInput1, initInput2, Ops::OP_OR )
+{
+}
+
+/*
+void
+QtOr::checkIdempotency()
+{
+ if( input2->getNodeType() == QtNode::QT_CONST &&
+ ((QtConst*)input2)->getDataObj()->getDataType() == QT_BOOL )
+ {
+ QtAtomicData* boolData = (QtAtomicData*)((QtConst*)input2)->getDataObj();
+
+ if( boolData->getUnsignedValue() )
+ {
+ if( input1->getAreaType() == QtNode::QT_AREA_SCALAR )
+ {
+ RMInit::logOut << "> rule (idempotency): A (scalar) OR TRUE -> TRUE" << endl;
+
+ getParent()->setInput( this, input2 );
+
+ // delete the node itself and its descendants but not input2
+ setInput2(NULL);
+ delete this;
+ };
+ }
+ else
+ {
+ RMInit::logOut << "> rule (idempotency): A OR FALSE -> A" << endl;
+
+ getParent()->setInput( this, input1 );
+
+ // delete the node itself and its descendants but not input1
+ setInput1(NULL);
+ delete this;
+ }
+ }
+ else
+ if( input1->getNodeType() == QtNode::QT_CONST &&
+ ((QtConst*)input1)->getDataObj()->getDataType() == QT_BOOL )
+ {
+ QtAtomicData* boolData = (QtAtomicData*)((QtConst*)input1)->getDataObj();
+
+ if( boolData->getUnsignedValue() )
+ {
+ if( input2->getAreaType() == QtNode::QT_AREA_SCALAR )
+ {
+ RMInit::logOut << "> rule (idempotency): TRUE OR A (scalar) -> TRUE" << endl;
+
+ getParent()->setInput( this, input1 );
+
+ // delete the node itself and its descendants but not input1
+ setInput1(NULL);
+ delete this;
+ };
+ }
+ else
+ {
+ RMInit::logOut << "> rule (idempotency): FALSE OR A -> A" << endl;
+
+ getParent()->setInput( this, input2 );
+
+ // delete the node itself and its descendants but not input2
+ setInput2(NULL);
+ delete this;
+ };
+ }
+ else
+ if( input1->getSpelling().compare( input2->getSpelling() ) == 0 )
+ {
+ RMInit::logOut << "> rule (idempotency): A OR A -> A" << endl;
+
+ getParent()->setInput( this, input1 );
+
+ // delete the node itself and its descendants but not input1
+ setInput1(NULL);
+ delete this;
+ };
+}
+*/
+
+
+/*
+void
+QtOr::rewriteOps()
+{
+ if( input1 && input2 )
+ {
+ if( input1->getNodeType() == QtNode::QT_ALL &&
+ input2->getNodeType() == QtNode::QT_SOME )
+ {
+ RMInit::logOut << "> rule (condenser order): ALL_CELLS OR SOME_CELLS -> SOME_CELLS OR ALL_CELLS" << endl;
+
+ // order condenser expressions
+
+ QtOperation* node1 = getInput1();
+ QtOperation* node2 = getInput2();
+
+ setInput1( node2 );
+ setInput2( node1 );
+ };
+ }
+ else
+ RMInit::logOut << "Error: QtOr::rewriteOps() - the operand branch is invalid." << endl;
+}
+*/
+
+QtData*
+QtOr::evaluate( QtDataList* inputList )
+{
+ /*
+ // RUNTIME OPTIMIZATION: TRUE OR A -> MDD(TRUE)
+ // A OR TRUE -> MDD(TRUE)
+ // FALSE OR A -> A
+ // A OR FALSE -> A
+ */
+
+ QtData* returnValue = NULL;
+
+ if( input1->getDataStreamType().getDataType() == QT_BOOL &&
+ input2->getDataStreamType().getDataType() == QT_BOOL )
+ {
+ // RUNTIME OPTIMIZATION: FALSE OR A -> A
+ // TRUE OR A -> TRUE
+
+ QtData* operand1=NULL;
+
+ if( getOperand( inputList, operand1, 1 ) )
+ {
+ bool op1 = ((QtAtomicData*)operand1)->getUnsignedValue();
+
+ if( !op1 )
+ {
+ // first operand is obsolete
+ if( operand1 ) operand1->deleteRef();
+
+ QtData* operand2=NULL;
+
+ if( getOperand( inputList, operand2, 2 ) )
+ {
+ returnValue = operand2;
+ }
+ }
+ else
+ {
+ returnValue = operand1;
+ RMDBGONCE(1, RMDebug::module_qlparser, "QtOr", " -> TRUE OR A evaluates TRUE")
+ }
+ }
+ }
+ else
+ returnValue = QtBinaryInduce::evaluate( inputList );
+
+ return returnValue;
+}
+
+
+void
+QtOr::printTree( int tab, ostream& s, QtChildType mode )
+{
+ s << SPACE_STR(tab).c_str() << "QtOr Object " << getNodeType() << endl;
+
+ QtBinaryInduce::printTree( tab, s, mode );
+}
+
+
+void
+QtOr::printAlgebraicExpression( ostream& s )
+{
+ s << "(";
+
+ if( input1 )
+ input1->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << " or ";
+
+ if( input2 )
+ input2->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << ")";
+}
+
+
+
+const QtNode::QtNodeType QtXor::nodeType = QT_XOR;
+
+
+QtXor::QtXor( QtOperation* initInput1, QtOperation* initInput2 )
+ : QtBinaryInduce( initInput1, initInput2, Ops::OP_XOR )
+{
+}
+
+/*
+void
+QtXor::checkIdempotency()
+{
+ RMDBGENTER(1, RMDebug::module_qlparser, "QtXor", "enter Xor::checkIdempotency()" )
+
+ if( input1->getSpelling().compare( input2->getSpelling() ) == 0 )
+ {
+ RMInit::logOut << "> rule (idempotency): A XOR A -> FALSE" << endl;
+
+ getParent()->setInput( this, new QtConst( new QtAtomicData( 0 ) ) );
+
+ // delete the node itself and its descendants
+ delete this;
+ };
+
+ RMDBGEXIT(1, RMDebug::module_qlparser, "QtXor", "exit Xor::checkIdempotency()" )
+}
+*/
+
+void
+QtXor::printTree( int tab, ostream& s, QtChildType mode )
+{
+ s << SPACE_STR(tab).c_str() << "QtXor Object " << getNodeType() << endl;
+
+ QtBinaryInduce::printTree( tab, s, mode );
+}
+
+
+void
+QtXor::printAlgebraicExpression( ostream& s )
+{
+ s << "(";
+
+ if( input1 )
+ input1->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << " xor ";
+
+ if( input2 )
+ input2->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << ")";
+}
+
+
+
+const QtNode::QtNodeType QtEqual::nodeType = QT_EQUAL;
+
+QtEqual::QtEqual( QtOperation* initInput1, QtOperation* initInput2 )
+ : QtBinaryInduce( initInput1, initInput2, Ops::OP_EQUAL )
+{
+}
+
+/*
+void
+QtEqual::checkIdempotency()
+{
+ if( input1->getSpelling().compare( input2->getSpelling() ) == 0 )
+ {
+ RMInit::logOut << "> rule (idempotency): A == A -> TRUE" << endl;
+
+ getParent()->setInput( this, new QtConst( new QtAtomicData( 1 ) ) );
+
+ // delete the node itself and its descendants
+ delete this;
+ };
+}
+*/
+
+
+void
+QtEqual::printTree( int tab, ostream& s, QtChildType mode )
+{
+ s << SPACE_STR(tab).c_str() << "QtEqual Object " << getNodeType() << endl;
+
+ QtBinaryInduce::printTree( tab, s, mode );
+}
+
+
+
+void
+QtEqual::printAlgebraicExpression( ostream& s )
+{
+ s << "(";
+
+ if( input1 )
+ input1->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << " = ";
+
+ if( input2 )
+ input2->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << ")";
+}
+
+
+
+const QtNode::QtNodeType QtLess::nodeType = QT_LESS;
+
+
+QtLess::QtLess( QtOperation* initInput1, QtOperation* initInput2 )
+ : QtBinaryInduce( initInput1, initInput2, Ops::OP_LESS )
+{
+}
+
+
+bool
+QtLess::isCommutative() const
+{
+ return false; // NOT commutative
+}
+
+
+
+void
+QtLess::printTree( int tab, ostream& s, QtChildType mode )
+{
+ s << SPACE_STR(tab).c_str() << "QtLess Object " << getNodeType() << endl;
+
+ QtBinaryInduce::printTree( tab, s, mode );
+}
+
+
+
+void
+QtLess::printAlgebraicExpression( ostream& s )
+{
+ s << "(";
+
+ if( input1 )
+ input1->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << " < ";
+
+ if( input2 )
+ input2->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << ")";
+}
+
+
+
+const QtNode::QtNodeType QtLessEqual::nodeType = QT_LESS_EQUAL;
+
+
+QtLessEqual::QtLessEqual( QtOperation* initInput1, QtOperation* initInput2 )
+ : QtBinaryInduce( initInput1, initInput2, Ops::OP_LESSEQUAL )
+{
+}
+
+
+bool
+QtLessEqual::isCommutative() const
+{
+ return false; // NOT commutative
+}
+
+
+
+void
+QtLessEqual::printTree( int tab, ostream& s, QtChildType mode )
+{
+ s << SPACE_STR(tab).c_str() << "QtLessEqual Object " << getNodeType() << endl;
+
+ QtBinaryInduce::printTree( tab, s, mode );
+}
+
+
+void
+QtLessEqual::printAlgebraicExpression( ostream& s )
+{
+ s << "(";
+
+ if( input1 )
+ input1->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << " <= ";
+
+ if( input2 )
+ input2->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << ")";
+}
+
+
+
+const QtNode::QtNodeType QtNotEqual::nodeType = QT_NOT_EQUAL;
+
+QtNotEqual::QtNotEqual( QtOperation* initInput1, QtOperation* initInput2 )
+ : QtBinaryInduce( initInput1, initInput2, Ops::OP_NOTEQUAL )
+{
+}
+
+/*
+void
+QtNotEqual::checkIdempotency()
+{
+ if( input1->getSpelling().compare( input2->getSpelling() ) == 0 )
+ {
+ RMInit::logOut << "> rule (idempotency): A != A -> FALSE" << endl;
+
+ getParent()->setInput( this, new QtConst( new QtAtomicData( 0 ) ) );
+
+ // delete the node itself and its descendants
+ delete this;
+ };
+}
+*/
+
+void
+QtNotEqual::printTree( int tab, ostream& s, QtChildType mode )
+{
+ s << SPACE_STR(tab).c_str() << "QtNotEqual Object " << getNodeType() << endl;
+
+ QtBinaryInduce::printTree( tab, s, mode );
+}
+
+
+
+void
+QtNotEqual::printAlgebraicExpression( ostream& s )
+{
+ s << "(";
+
+ if( input1 )
+ input1->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << " != ";
+
+ if( input2 )
+ input2->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << ")";
+}
+
+
+
+
+
+const QtNode::QtNodeType QtOverlay::nodeType = QT_OVERLAY;
+
+QtOverlay::QtOverlay( QtOperation* initInput1, QtOperation* initInput2 )
+ : QtBinaryInduce( initInput1, initInput2, Ops::OP_OVERLAY )
+{
+}
+
+/*
+void QtOverlay::checkIdempotency()
+{
+}
+*/
+
+
+bool QtOverlay::isCommutative() const
+{
+ return false; // NOT commutative
+}
+
+
+
+void
+QtOverlay::printTree( int tab, ostream& s, QtChildType mode )
+{
+ s << SPACE_STR(tab).c_str() << "QtOverlay Object " << getNodeType() << endl;
+
+ QtBinaryInduce::printTree( tab, s, mode );
+}
+
+
+
+void
+QtOverlay::printAlgebraicExpression( ostream& s )
+{
+ s << "(";
+
+ if( input2 )
+ input2->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << " overlay ";
+
+ if( input1 )
+ input1->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << ")";
+}
+
+/********************************************************
+ * QtBit
+ ********************************************************
+ */
+
+
+const QtNode::QtNodeType QtBit::nodeType = QT_BIT;
+
+QtBit::QtBit(QtOperation* initInput1, QtOperation* initInput2)
+ : QtBinaryInduce(initInput1, initInput2, Ops::OP_BIT) {}
+
+
+bool QtBit::isCommutative() const {
+ return false;
+}
+
+void QtBit::printTree(int tab, ostream& s, QtChildType mode) {
+ s << SPACE_STR(tab).c_str() << "QtBit Object " << getNodeType() << endl;
+ QtBinaryInduce::printTree(tab, s, mode);
+}
+
+void QtBit::printAlgebraicExpression(ostream& s) {
+ s << "(";
+
+ if( input2 )
+ input2->printAlgebraicExpression(s);
+ else
+ s << "<nn>";
+
+ s << " bit ";
+
+ if( input1 )
+ input1->printAlgebraicExpression(s);
+ else
+ s << "<nn>";
+
+ s << ")";
+}
+
+const QtTypeElement& QtBit::checkType(QtTypeTuple* typeTuple) {
+ RMDBCLASS( "QtBit", "checkType( QtTypeTuple* )", "qlparser", __FILE__, __LINE__ )
+
+ dataStreamType.setDataType(QT_TYPE_UNKNOWN);
+
+ // check operand branches
+ if(input1 && input2)
+ {
+
+ // get input types
+ const QtTypeElement& inputType1 = input1->checkType(typeTuple);
+ const QtTypeElement& inputType2 = input2->checkType(typeTuple);
+
+ if(RManDebug >= 4) {
+ RMInit::dbgOut << "Operand 1: " << flush;
+ inputType1.printStatus( RMInit::dbgOut );
+ RMInit::dbgOut << endl;
+
+ RMInit::dbgOut << "Operand 2: " << flush;
+ inputType2.printStatus( RMInit::dbgOut );
+ RMInit::dbgOut << endl;
+
+ RMDBGONCE( 4, RMDebug::module_qlparser, "QtBit", "Operation " << opType )
+ }
+
+ if(inputType2.getDataType() < QT_BOOL || inputType2.getDataType() > QT_LONG) {
+ RMInit::logOut << "Error: QtBit::checkType() - second operand must be of integral type." << endl;
+ parseInfo.setErrorNo(418);
+ throw parseInfo;
+ }
+
+ if(inputType1.getDataType() == QT_MDD) {
+ const BaseType* baseType1 = ((MDDBaseType*)(inputType1.getType()))->getBaseType();
+ BaseType* baseType2 = (BaseType*)(inputType2.getType());
+
+ const BaseType* resultBaseType = Ops::getResultType(opType, baseType1, baseType2);
+
+ if(!resultBaseType) {
+ RMInit::logOut << "Error: QtBit::checkType() - unary induce: operand types are incompatible." << endl;
+ parseInfo.setErrorNo(364);
+ throw parseInfo;
+ }
+
+ MDDBaseType* resultMDDType = new MDDBaseType("tmp", resultBaseType);
+ TypeFactory::addTempType(resultMDDType);
+
+ dataStreamType.setType(resultMDDType);
+ }
+
+ else if(inputType1.isBaseType()) {
+ BaseType* baseType1 = (BaseType*)(inputType1.getType());
+ BaseType* baseType2 = (BaseType*)(inputType2.getType());
+
+ const BaseType* resultBaseType = Ops::getResultType(opType, baseType1, baseType2);
+
+ if(!resultBaseType) {
+ RMInit::logOut << "Error: QtBit::computeOp() - operand types are incompatible." << endl;
+ parseInfo.setErrorNo(365);
+ throw parseInfo;
+ }
+
+ dataStreamType.setType(resultBaseType);
+ }
+ else {
+ RMInit::logOut << "Error: QtBit::checkType() - operation is not supported on these data types." << endl;
+ parseInfo.setErrorNo(403);
+ throw parseInfo;
+ }
+ }
+ else
+ RMInit::logOut << "Error: QtBit::checkType() - operand branch invalid." << endl;
+
+ return dataStreamType;
+}
diff --git a/qlparser/qtbinaryinduce2.hh b/qlparser/qtbinaryinduce2.hh
new file mode 100644
index 0000000..96928fb
--- /dev/null
+++ b/qlparser/qtbinaryinduce2.hh
@@ -0,0 +1,358 @@
+#ifndef _QTBINARY2INDUCE_
+#define _QTBINARY2INDUCE_
+
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+#endif
+
+#include "qlparser/qtbinaryinduce.hh"
+
+#include "catalogmgr/ops.hh"
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+*/
+
+class QtIs : public QtBinaryInduce
+{
+ public:
+ /// constructor getting the two operands
+ QtIs( QtOperation* input1, QtOperation* input2 );
+
+ /// check idempetency rules
+// virtual void checkIdempotency();
+
+ /// prints the tree
+ virtual void printTree( int tab, std::ostream& s = std::cout, QtChildType mode = QT_ALL_NODES );
+
+ /// prints the algebraic expression
+ virtual void printAlgebraicExpression( std::ostream& s = std::cout );
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ private:
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+*/
+
+class QtAnd : public QtBinaryInduce
+{
+ public:
+ /// constructor getting the two operands
+ QtAnd( QtOperation* input1, QtOperation* input2 );
+
+ /// heuristic ordering of operands
+// virtual void rewriteOps();
+
+ /// check idempetency rules
+// virtual void checkIdempotency();
+
+ /// method for evaluating the node
+ QtData* evaluate( QtDataList* inputList );
+
+ /// prints the tree
+ virtual void printTree( int tab, std::ostream& s = std::cout, QtChildType mode = QT_ALL_NODES );
+
+ /// prints the algebraic expression
+ virtual void printAlgebraicExpression( std::ostream& s = std::cout );
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ private:
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+*/
+
+class QtOr : public QtBinaryInduce
+{
+ public:
+ /// constructor getting the two operands
+ QtOr( QtOperation* input1, QtOperation* input2 );
+
+ /// heuristic ordering of operands
+// virtual void rewriteOps();
+
+ /// check idempetency rules
+ // virtual void checkIdempotency();
+
+ /// method for evaluating the node
+ QtData* evaluate( QtDataList* inputList );
+
+ /// prints the tree
+ virtual void printTree( int tab, std::ostream& s = std::cout, QtChildType mode = QT_ALL_NODES );
+
+ /// prints the algebraic expression
+ virtual void printAlgebraicExpression( std::ostream& s = std::cout );
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ private:
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+*/
+
+class QtXor : public QtBinaryInduce
+{
+ public:
+ /// constructor getting the two operands
+ QtXor( QtOperation* input1, QtOperation* input2 );
+
+ /// check idempetency rules
+// virtual void checkIdempotency();
+
+ /// prints the tree
+ virtual void printTree( int tab, std::ostream& s = std::cout, QtChildType mode = QT_ALL_NODES );
+
+ /// prints the algebraic expression
+ virtual void printAlgebraicExpression( std::ostream& s = std::cout );
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ private:
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+*/
+
+class QtEqual : public QtBinaryInduce
+{
+ public:
+ /// constructor getting the two operands
+ QtEqual( QtOperation* input1, QtOperation* input2 );
+
+ /// check idempetency rules
+// virtual void checkIdempotency();
+
+ /// prints the tree
+ virtual void printTree( int tab, std::ostream& s = std::cout, QtChildType mode = QT_ALL_NODES );
+
+ /// prints the algebraic expression
+ virtual void printAlgebraicExpression( std::ostream& s = std::cout );
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ private:
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+*/
+
+class QtLess : public QtBinaryInduce
+{
+ public:
+ /// constructor getting the two operands
+ QtLess( QtOperation* input1, QtOperation* input2 );
+
+ /// prints the tree
+ virtual void printTree( int tab, std::ostream& s = std::cout, QtChildType mode = QT_ALL_NODES );
+
+ /// prints the algebraic expression
+ virtual void printAlgebraicExpression( std::ostream& s = std::cout );
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ /// returns false saying that the operation IS NOT commutative
+ virtual bool isCommutative() const;
+
+ private:
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+*/
+
+class QtLessEqual : public QtBinaryInduce
+{
+ public:
+ /// constructor getting the two operands
+ QtLessEqual( QtOperation* input1, QtOperation* input2 );
+
+ /// prints the tree
+ virtual void printTree( int tab, std::ostream& s = std::cout, QtChildType mode = QT_ALL_NODES );
+
+ /// prints the algebraic expression
+ virtual void printAlgebraicExpression( std::ostream& s = std::cout );
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ /// returns false saying that the operation IS NOT commutative
+ virtual bool isCommutative() const;
+
+ private:
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+*/
+
+class QtNotEqual : public QtBinaryInduce
+{
+ public:
+ /// constructor getting the two operands
+ QtNotEqual( QtOperation* input1, QtOperation* input2 );
+
+ /// check idempetency rules
+// virtual void checkIdempotency();
+
+ /// prints the tree
+ virtual void printTree( int tab, std::ostream& s = std::cout, QtChildType mode = QT_ALL_NODES );
+
+ /// prints the algebraic expression
+ virtual void printAlgebraicExpression( std::ostream& s = std::cout );
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ private:
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+*/
+
+class QtOverlay : public QtBinaryInduce
+{
+ public:
+ /// constructor getting the two operands
+ QtOverlay( QtOperation* input1, QtOperation* input2 );
+
+ /// check idempetency rules
+// virtual void checkIdempotency();
+
+ /// check commutativity
+ bool isCommutative() const;
+
+ /// prints the tree
+ virtual void printTree( int tab, std::ostream& s = std::cout, QtChildType mode = QT_ALL_NODES );
+
+ /// prints the algebraic expression
+ virtual void printAlgebraicExpression( std::ostream& s = std::cout );
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ private:
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+
+class QtBit : public QtBinaryInduce {
+public:
+ /// constructor getting the two operands
+ QtBit( QtOperation* input1, QtOperation* input2 );
+
+ /// check commutativity
+ bool isCommutative() const;
+
+ /// prints the tree
+ virtual void printTree( int tab, std::ostream& s = std::cout, QtChildType mode = QT_ALL_NODES );
+
+ /// prints the algebraic expression
+ virtual void printAlgebraicExpression( std::ostream& s = std::cout );
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ /// checkType
+ const QtTypeElement& checkType( QtTypeTuple* typeTuple );
+
+private:
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+
+#include "qlparser/qtbinaryinduce2.icc"
+
+#endif
+
diff --git a/qlparser/qtbinaryinduce2.icc b/qlparser/qtbinaryinduce2.icc
new file mode 100644
index 0000000..134b2ea
--- /dev/null
+++ b/qlparser/qtbinaryinduce2.icc
@@ -0,0 +1,95 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+inline const QtNode::QtNodeType
+QtIs::getNodeType() const
+{
+ return nodeType;
+}
+
+
+inline const QtNode::QtNodeType
+QtAnd::getNodeType() const
+{
+ return nodeType;
+}
+
+
+inline const QtNode::QtNodeType
+QtOr::getNodeType() const
+{
+ return nodeType;
+}
+
+
+inline const QtNode::QtNodeType
+QtXor::getNodeType() const
+{
+ return nodeType;
+}
+
+
+inline const QtNode::QtNodeType
+QtEqual::getNodeType() const
+{
+ return nodeType;
+}
+
+
+inline const QtNode::QtNodeType
+QtLess::getNodeType() const
+{
+ return nodeType;
+}
+
+
+inline const QtNode::QtNodeType
+QtLessEqual::getNodeType() const
+{
+ return nodeType;
+}
+
+
+inline const QtNode::QtNodeType
+QtNotEqual::getNodeType() const
+{
+ return nodeType;
+}
+
+inline const QtNode::QtNodeType
+QtOverlay::getNodeType() const
+{
+ return nodeType;
+}
+
+inline const QtNode::QtNodeType
+QtBit::getNodeType() const
+{
+ return nodeType;
+}
diff --git a/qlparser/qtbinaryoperation.cc b/qlparser/qtbinaryoperation.cc
new file mode 100644
index 0000000..ed05b79
--- /dev/null
+++ b/qlparser/qtbinaryoperation.cc
@@ -0,0 +1,432 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)qlparser, QtBinaryOperation: $Id: qtbinaryoperation.cc,v 1.25 2002/04/12 09:51:53 coman Exp $";
+
+#include "qlparser/qtbinaryoperation.hh"
+#include "qlparser/qtconst.hh"
+
+#include <iostream>
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+using namespace std;
+#endif
+
+// constructors
+
+QtBinaryOperation::QtBinaryOperation() :
+ QtOperation(),
+ input1(NULL),
+ input2(NULL)
+{
+}
+
+
+QtBinaryOperation::QtBinaryOperation( QtNode* node ) :
+ QtOperation( node ),
+ input1(NULL),
+ input2(NULL)
+{
+}
+
+
+QtBinaryOperation::QtBinaryOperation( QtOperation* initInput1, QtOperation* initInput2 ) :
+ QtOperation(),
+ input1( initInput1 ),
+ input2( initInput2 )
+{
+ if ( input1 )
+ input1->setParent( this );
+
+ if ( input2 )
+ input2->setParent( this );
+}
+
+// destructor
+
+QtBinaryOperation::~QtBinaryOperation()
+{
+ if ( input1 )
+ {
+ delete input1;
+ input1=NULL;
+ }
+ if ( input2 )
+ {
+ delete input2;
+ input2=NULL;
+ }
+}
+
+
+// pre-evaluate the operation if the nodes contain constant data
+
+void
+QtBinaryOperation::simplify()
+{
+ RMDBCLASS( "QtBinaryOperation", "simplify()", "qlparser", __FILE__, __LINE__ )
+
+ // In order to work bottom up, first inspect the descendants
+ QtNode::simplify();
+
+ // Test, if both operands are available.
+ if( input1 && input2 )
+ {
+ // Test, if both operands are of const type.
+ if( input1->getNodeType() == QT_CONST && input2->getNodeType() == QT_CONST )
+ {
+ // evaluate the self node with no input list
+ QtData* newConst = this->evaluate( NULL );
+
+ if( newConst )
+ {
+ // create a new constant node and fill it with newConst
+ QtConst* newNode = new QtConst( newConst );
+
+ // set its data stream type
+ newNode->checkType( NULL );
+
+ // link it to the parent
+ getParent()->setInput( this, newNode );
+
+ // delete the self node and its descendants
+ delete this;
+ }
+ }
+ }
+
+}
+
+
+// compare this to another node
+
+bool
+QtBinaryOperation::equalMeaning( QtNode* node )
+{
+ RMDBCLASS( "QtBinaryOperation", "equalMeaning( QtNode* )", "qlparser", __FILE__, __LINE__ )
+
+ bool result = false;
+
+ // are the nodes of the same type?
+ if ( getNodeType() == node->getNodeType() )
+ {
+ QtBinaryOperation* binNode = (QtBinaryOperation *) node; // by force
+
+ if ( input1 && input2 ) {
+ if ( isCommutative() )
+ // operation is commutative
+ result = ( input1->equalMeaning( binNode->getInput1() ) &&
+ input2->equalMeaning( binNode->getInput2() ) ) ||
+ ( input1->equalMeaning( binNode->getInput2() ) &&
+ input2->equalMeaning( binNode->getInput1() ) );
+ else
+ // not commutative
+ result = input1->equalMeaning( binNode->getInput1() ) &&
+ input2->equalMeaning( binNode->getInput2() );
+ };
+ };
+
+ return result;
+}
+
+
+// get childs
+
+QtNode::QtNodeList*
+QtBinaryOperation::getChilds( QtChildType flag )
+{
+ RMDBCLASS( "QtBinaryOperation", "getChilds( QtChildType )", "qlparser", __FILE__, __LINE__ )
+
+ QtNodeList* resultList = new QtNodeList();
+
+ if ( flag == QT_LEAF_NODES || flag == QT_ALL_NODES ) {
+ QtNodeList* subList=NULL;
+
+ if ( input1 ) {
+ subList = input1->getChilds( flag );
+ resultList->splice(resultList->begin(), *subList);
+ delete subList;
+ subList=NULL;
+ };
+
+ if ( input2 ) {
+ subList = input2->getChilds( flag );
+ resultList->splice(resultList->begin(), *subList);
+ delete subList;
+ subList=NULL;
+ };
+ };
+
+ if ( flag == QT_DIRECT_CHILDS || flag == QT_ALL_NODES ) {
+ if ( input1 )
+ resultList->push_back( input1 );
+ if ( input2 )
+ resultList->push_back( input2 );
+ };
+
+ return resultList;
+}
+
+
+// get the two operands
+
+bool
+QtBinaryOperation::getOperands( QtDataList* inputList, QtData* &operand1, QtData* &operand2 )
+{
+ RMDBCLASS( "QtBinaryOperation", "getOperands( QtDataList*, QtData*, QtData* )", "qlparser", __FILE__, __LINE__ )
+
+ bool success = false;
+
+ // get the operands
+ try {
+ if ( input1 ) operand1 = input1->evaluate( inputList );
+ if ( input2 ) operand2 = input2->evaluate( inputList );
+ }
+ catch(...)
+ {
+ //clean up code
+ if( operand1 ) {
+ operand1->deleteRef();
+ operand1 = NULL;
+ }
+
+ if( operand2 ){
+ operand2->deleteRef();
+ operand2 = NULL;
+ }
+
+ throw;
+ }
+
+ // test if the operands are valid
+ success = operand1 && operand2;
+
+ if( !success )
+ {
+
+ if( operand1 )
+ {
+ operand1->deleteRef();
+ operand1 = NULL;
+ }
+
+ if( operand2 )
+ {
+ operand2->deleteRef();
+ operand2 = NULL;
+ }
+
+ RMDBGONCE( 1, RMDebug::module_qlparser, "QtBinaryOperation", "Error: QtBinaryOperation::getOperands() - at least one operand is not provided." )
+
+ }
+
+ return success;
+}
+
+
+// get the first or the second operand
+
+bool
+QtBinaryOperation::getOperand( QtDataList* inputList, QtData* &operand, int number )
+{
+ RMDBCLASS( "QtBinaryOperation", "getOperand( QtDataList*, QtData*, int )", "qlparser", __FILE__, __LINE__ )
+
+ bool success = false;
+
+ // get the operand
+ if ( number == 1 ) {
+ if ( input1 ) {
+ operand = input1->evaluate( inputList );
+ } else {
+ if ( input2 )
+ operand = input2->evaluate( inputList );
+ }
+ } else {
+ if ( input2 )
+ operand = input2->evaluate( inputList );
+ }
+
+ // test if the operands are valid
+ if ( operand )
+ success = true;
+ else {
+ RMDBGONCE( 1, RMDebug::module_qlparser, "QtBinaryOperation", "Error: QtBinaryOperation::getOperand() - operand is not provided." )
+ }
+
+ return success;
+}
+
+
+// get spelling
+
+string
+QtBinaryOperation::getSpelling()
+{
+ char tempStr[20];
+ sprintf(tempStr, "%ud", (unsigned long)getNodeType());
+ string result = string(tempStr);
+ result.append( "(" );
+
+ if ( input1 && input2 ) {
+ string result1 = input1->getSpelling();
+ string result2 = input2->getSpelling();
+
+ if( result1.compare( result2 ) < 0 || !isCommutative() )
+ {
+ result.append( result1 );
+ result.append( "," );
+ result.append( result2 );
+ }
+ else
+ {
+ result.append( result2 );
+ result.append( "," );
+ result.append( result1 );
+ };
+ };
+
+ result.append( ")" );
+ RMDBGONCE(2, RMDebug::module_qlparser, "QtBinaryOperation", "Result:" << result.c_str())
+ return result;
+}
+
+
+// get area type
+
+QtNode::QtAreaType
+QtBinaryOperation::getAreaType()
+{
+ QtNode::QtAreaType result = QT_AREA_MDD;
+
+ if ( input1 && input2 )
+ if ( input1->getAreaType() == QtNode::QT_AREA_SCALAR &&
+ input2->getAreaType() == QtNode::QT_AREA_SCALAR )
+ result = QT_AREA_SCALAR;
+
+ return result;
+}
+
+
+// idempotent
+
+/*
+void
+QtBinaryOperation::checkIdempotency()
+{
+}
+*/
+
+// optimize load
+
+void
+QtBinaryOperation::optimizeLoad( QtTrimList* trimList )
+{
+ RMDBCLASS( "QtBinaryOperation", "optimizeLoad( QtTrimList* )", "qlparser", __FILE__, __LINE__ )
+
+ QtNode::QtTrimList *list1=NULL;
+ QtNode::QtTrimList *list2=NULL;
+
+ if( input1 && input2 )
+ {
+ list1 = trimList;
+
+ // for list2 make a copy of list1
+ list2 = new QtNode::QtTrimList();
+
+ for( QtNode::QtTrimList::iterator iter=trimList->begin(); iter!=trimList->end(); iter++ )
+ {
+ QtTrimElement* elem = new QtTrimElement;
+ *elem = **iter;
+ list2->push_back( elem );
+ }
+
+ if ( input1 )
+ input1->optimizeLoad( list1 );
+
+ if ( input2 )
+ input2->optimizeLoad( list2 );
+
+ }
+ else
+ {
+ // release( trimList->begin(), trimList->end() );
+ for( QtNode::QtTrimList::iterator iter=trimList->begin(); iter!=trimList->end(); iter++ )
+ {
+ delete *iter;
+ *iter=NULL;
+ }
+ delete trimList;
+ trimList=NULL;
+ }
+}
+
+
+void
+QtBinaryOperation::printTree( int tab, ostream& s, QtChildType mode )
+{
+ if( mode != QT_DIRECT_CHILDS )
+ {
+ if( input1 )
+ {
+ s << SPACE_STR(tab).c_str() << "input1: " << endl;
+ input1->printTree( tab+2, s, mode );
+ }
+ else
+ s << SPACE_STR(tab).c_str() << "no input1" << endl;
+
+ if( input2 )
+ {
+ s << SPACE_STR(tab).c_str() << "input2: " << endl;
+ input2->printTree( tab+2, s, mode );
+ }
+ else
+ s << SPACE_STR(tab).c_str() << "no input2" << endl;
+ }
+}
+
+
+
+bool
+QtBinaryOperation::isCommutative() const
+{
+ return true; // by default, a binary operation is commutative
+}
+
+
+
+
+
+
+
+
diff --git a/qlparser/qtbinaryoperation.hh b/qlparser/qtbinaryoperation.hh
new file mode 100644
index 0000000..cf15666
--- /dev/null
+++ b/qlparser/qtbinaryoperation.hh
@@ -0,0 +1,150 @@
+#ifndef _QTBINARYOPERATION_
+#define _QTBINARYOPERATION_
+
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+#endif
+
+#include <stdio.h>
+
+#include "qlparser/qtoperation.hh"
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/**************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+The class serves as superclass for all operation classes taking two
+arguments.
+
+*/
+
+class QtBinaryOperation : public QtOperation
+{
+ public:
+ /// default constructor
+ QtBinaryOperation();
+
+ /// constructor getting the node to the parent
+ QtBinaryOperation( QtNode* node );
+
+ /// constructor getting pointers to its operands
+ QtBinaryOperation( QtOperation* input1, QtOperation* input2 );
+
+ /// virtual destructor
+ virtual ~QtBinaryOperation();
+
+ /// simplifies the tree
+ virtual void simplify();
+
+ /// test if the two nodes have an equal meaning in the query tree
+ virtual bool equalMeaning( QtNode* node );
+ /**
+ The meaning of a binary operation is equal, iff both operands have
+ the same meaning. In case of a commutative operation, the operands
+ can be switched.
+ */
+
+ /// return childs of the node
+ virtual QtNodeList* getChilds( QtChildType flag );
+
+ /// creates a unique name for a subexpression
+ virtual std::string getSpelling();
+
+ /// test if the edge to the parent node is of type mdd or atomic
+ virtual QtAreaType getAreaType();
+
+ /// method for query rewrite
+ inline virtual void setInput( QtOperation* inputOld, QtOperation* inputNew );
+
+ /// method for checking idempotency rules
+// virtual void checkIdempotency();
+
+ /// optimizing load access
+ virtual void optimizeLoad( QtTrimList* trimList );
+ /**
+ The method deletes the given {\tt trimList} and passes the {\tt optimizeLoad}
+ message with empty triming lists to its input trees. The method is rewritten
+ by some subclasses.
+ */
+
+ /// debugging method
+ virtual void printTree( int tab, std::ostream& s = std::cout, QtChildType mode = QT_ALL_NODES );
+
+ //@Man: read/write methods for the operands
+ //@{
+ ///
+ ///
+ inline void setInput1( QtOperation* input );
+ ///
+ inline void setInput2( QtOperation* input );
+ ///
+ inline QtOperation* getInput1();
+ ///
+ inline QtOperation* getInput2();
+ ///
+ //@}
+
+ /// returns commutativity information (by default, an operation IS commutative)
+ virtual bool isCommutative() const;
+
+ protected:
+ /// method for testing and evaluating the input branches
+ bool getOperands( QtDataList* inputList, QtData* &operand1, QtData* &operand2 );
+ /**
+ The method checks if the input branches are valid. Then it passes the evaluate message to its two
+ operands with the {\tt inputList} as argument. The returned results are provided through the arguments
+ {\tt operand1} and {\tt operand2} called by reference. The method returns {\tt true} it the operands are
+ valid, otherwise {\tt false}.
+ */
+
+ /// method for testing and evaluating the input branches
+ bool getOperand( QtDataList* inputList, QtData* &operand1, int number);
+ /**
+ The method checks if the by number specified input branch si valid. Then it passes the evaluate message to the
+ operand with the {\tt inputList} as argument. The returned result are provided through the argument
+ {\tt operand} called by reference. The method returns {\tt true} it the operand is
+ valid, otherwise {\tt false}.
+ */
+
+ /// first operation operand
+ QtOperation* input1;
+ /// second operation operand
+ QtOperation* input2;
+};
+
+#include "qlparser/qtbinaryoperation.icc"
+
+#endif
+
+
diff --git a/qlparser/qtbinaryoperation.icc b/qlparser/qtbinaryoperation.icc
new file mode 100644
index 0000000..7cb55cb
--- /dev/null
+++ b/qlparser/qtbinaryoperation.icc
@@ -0,0 +1,89 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+inline void
+QtBinaryOperation::setInput1( QtOperation* input )
+{
+ input1 = input;
+
+ if( input )
+ input->setParent( this );
+};
+
+
+
+inline void
+QtBinaryOperation::setInput2( QtOperation* input )
+{
+ input2 = input;
+
+ if( input )
+ input->setParent( this );
+};
+
+
+
+inline QtOperation*
+QtBinaryOperation::getInput1()
+{
+ return input1;
+};
+
+
+
+inline QtOperation*
+QtBinaryOperation::getInput2()
+{
+ return input2;
+};
+
+
+
+inline void
+QtBinaryOperation::setInput( QtOperation* inputOld, QtOperation* inputNew )
+{
+ if( inputOld == input1 )
+ {
+ setInput1( inputNew );
+
+ if( inputNew )
+ inputNew->setParent( this );
+ }
+
+ if( inputOld == input2 )
+ {
+ setInput2( inputNew );
+
+ if( inputNew )
+ inputNew->setParent( this );
+ }
+};
+
+
+
diff --git a/qlparser/qtcommand.cc b/qlparser/qtcommand.cc
new file mode 100644
index 0000000..3574519
--- /dev/null
+++ b/qlparser/qtcommand.cc
@@ -0,0 +1,182 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)qlparser, QtCommand: $Header: /home/rasdev/CVS-repository/rasdaman/qlparser/qtcommand.cc,v 1.21 2005/09/03 20:17:55 rasdev Exp $";
+
+#include "qlparser/qtcommand.hh"
+#include "mddmgr/mddcoll.hh"
+#include "catalogmgr/typefactory.hh"
+#include "reladminif/databaseif.hh"
+#include "relcatalogif/settype.hh"
+#include "servercomm/servercomm.hh"
+
+#include <iostream>
+
+
+extern ServerComm::ClientTblElt* currentClientTblElt;
+
+const QtNode::QtNodeType QtCommand::nodeType = QtNode::QT_COMMAND;
+
+
+
+QtCommand::QtCommand( QtCommandType initCommand, const std::string& initCollection, const std::string& initType )
+ : QtExecute(),
+ command( initCommand ),
+ collectionName( initCollection ),
+ typeName( initType )
+{
+}
+
+
+
+QtCommand::QtCommand( QtCommandType initCommand, const std::string& initCollection )
+ : QtExecute(),
+ command( initCommand ),
+ collectionName( initCollection )
+{
+}
+
+
+
+int
+QtCommand::evaluate()
+{
+ RMDBGENTER(2, RMDebug::module_qlparser, "QtCommand", "evaluate()")
+
+ switch( command )
+ {
+ case QT_DROP_COLLECTION:
+ if( currentClientTblElt )
+ if (!MDDColl::dropMDDCollection(collectionName.c_str()))
+ {
+ RMInit::logOut << "Error during query evaluation: collection name not found: " << collectionName.c_str() << std::endl;
+ parseInfo.setErrorNo(957);
+ throw parseInfo;
+ }
+ break;
+ case QT_CREATE_COLLECTION:
+ if( currentClientTblElt )
+ {
+ // get collection type
+ CollectionType* collType = (CollectionType*)TypeFactory::mapSetType( (char*)typeName.c_str() );
+
+ if( collType )
+ {
+ // allocate a new oid within the current db
+ OId oid;
+#ifdef BASEDB_O2
+ if( !OId::allocateMDDCollOId( &oid ) )
+ {
+#else
+ OId::allocateOId(oid, OId::MDDCOLLOID);
+#endif
+ try
+ {
+ MDDColl* coll = MDDColl::createMDDCollection(collectionName.c_str(), oid, collType);
+ delete coll;
+ coll=NULL;
+ }
+ catch( r_Error& obj )
+ {
+ RMInit::logOut << "Error during query evaluation: collection name exists already: " << collectionName.c_str() << std::endl;
+ if (obj.get_kind() != r_Error::r_Error_NameNotUnique)
+ RMInit::logOut << "Exception: " << obj.what() << std::endl;;
+ parseInfo.setErrorNo(955);
+ throw parseInfo;
+ }
+#ifdef BASEDB_O2
+ }
+ else
+ {
+ RMInit::logOut << "Error: QtCommand::evaluate() - oid allocation failed" << std::endl;
+ parseInfo.setErrorNo(958);
+ throw parseInfo;
+ }
+#endif
+ }
+ else
+ {
+ RMInit::logOut << "Error during query evaluation: collection type not found: " << (char*)typeName.c_str() << std::endl;
+ parseInfo.setErrorNo(956);
+ throw parseInfo;
+ }
+ break;
+ }
+ }
+
+ RMDBGEXIT(2, RMDebug::module_qlparser, "QtCommand", "evaluate()")
+
+ return 0;
+}
+
+
+
+void
+QtCommand::printTree( int tab, std::ostream& s, QtChildType mode )
+{
+ s << SPACE_STR(tab).c_str() << "QtCommand Object" << std::endl;
+
+ switch( command )
+ {
+ case QT_DROP_COLLECTION: s << SPACE_STR(tab).c_str() << " drop collection(" << collectionName.c_str() << ")"; break;
+ case QT_CREATE_COLLECTION: s << SPACE_STR(tab).c_str() << " create collection(" << collectionName.c_str() << ", " << typeName.c_str() <<")"; break;
+ default: s << "<command unknown>";
+ }
+
+ s << std::endl;
+}
+
+
+
+void
+QtCommand::printAlgebraicExpression( std::ostream& s )
+{
+ s << "command<";
+
+ switch( command )
+ {
+ case QT_DROP_COLLECTION: s << "drop collection(" << collectionName.c_str() << ")"; break;
+ case QT_CREATE_COLLECTION: s << "create collection(" << collectionName.c_str() << ", " << typeName.c_str() <<")"; break;
+ default: s << "unknown";
+ }
+
+ s << ">";
+}
+
+
+
+void
+QtCommand::checkType()
+{
+ // nothing to do here
+}
+
diff --git a/qlparser/qtcommand.hh b/qlparser/qtcommand.hh
new file mode 100644
index 0000000..76c4375
--- /dev/null
+++ b/qlparser/qtcommand.hh
@@ -0,0 +1,97 @@
+#ifndef __QTCOMMAND_HH__
+#define __QTCOMMAND_HH___
+
+#include "qlparser/qtexecute.hh"
+
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+#endif
+#include <iostream>
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+//@ManMemo: Module: {\bf qlparser}
+
+/**
+
+*/
+
+class QtCommand : public QtExecute
+{
+ public:
+ enum QtCommandType
+ {
+ QT_DROP_COLLECTION,
+ QT_CREATE_COLLECTION
+ };
+
+ /// constructor getting command, collection and type name (create collection)
+ QtCommand( QtCommandType initCommand, const std::string& initCollection, const std::string& initType );
+
+ /// constructor getting command and collection name (drop collection)
+ QtCommand( QtCommandType initCommand, const std::string& initCollection );
+
+ /// method for evaluating the node
+ virtual int evaluate();
+
+ /// prints the tree
+ virtual void printTree( int tab, std::ostream& s = std::cout, QtChildType mode = QT_ALL_NODES );
+
+ /// prints the algebraic expression
+ virtual void printAlgebraicExpression( std::ostream& s = std::cout );
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ /// type checking
+ virtual void checkType();
+
+ private:
+ /// command type
+ QtCommandType command;
+
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+
+ /// collection name for drop/create collection
+ std::string collectionName;
+
+ /// type name for create collection
+ std::string typeName;
+};
+
+#include "qlparser/qtcommand.icc"
+
+#endif
+
+
+
diff --git a/qlparser/qtcommand.icc b/qlparser/qtcommand.icc
new file mode 100644
index 0000000..cb8353b
--- /dev/null
+++ b/qlparser/qtcommand.icc
@@ -0,0 +1,35 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+inline const QtNode::QtNodeType
+QtCommand::getNodeType() const
+{
+ return nodeType;
+}
+
diff --git a/qlparser/qtcomplexdata.cc b/qlparser/qtcomplexdata.cc
new file mode 100644
index 0000000..36a822d
--- /dev/null
+++ b/qlparser/qtcomplexdata.cc
@@ -0,0 +1,109 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)qlparser, QtComplexData: $Header: /home/rasdev/CVS-repository/rasdaman/qlparser/qtcomplexdata.cc,v 1.12 2003/12/27 20:51:28 rasdev Exp $";
+
+#include "qlparser/qtcomplexdata.hh"
+#include "relcatalogif/structtype.hh"
+#include <stdio.h>
+#include <cstring>
+
+QtComplexData::QtComplexData()
+ : QtScalarData()
+{
+}
+
+
+
+QtComplexData::QtComplexData( QtComplexData::QtScalarDataList* &scalarDataList )
+ : QtScalarData()
+{
+ char elementName[256];
+ unsigned int i=0;
+ std::list<QtScalarData*>::iterator iter;
+
+ // Take care of dynamic memory management:
+ //
+ // Types, which are not in the typeFactory, have to be deleted. This means that, in general,
+ // all complex types have to be deleted because they are constructed temporarily.
+
+ // create a new struct type
+ StructType* structType = new StructType( "", scalarDataList->size() );
+
+ // add type elements, the first element inserted has no 0, the second no 1, and so on
+ for( iter=scalarDataList->begin(), i=0; iter!=scalarDataList->end(); iter++, i++ )
+ {
+ sprintf( elementName, "%d", i );
+ structType->addElement( elementName, (*iter)->getValueType() );
+ }
+
+ // add type to typeFactory
+ TypeFactory::addTempType( structType );
+
+ valueBuffer = new char[ structType->getSize() ];
+ valueType = structType;
+
+ // copy data
+ for( iter=scalarDataList->begin(), i=0; iter!=scalarDataList->end(); iter++, i++ )
+ {
+ char* destination = ((char*)valueBuffer) + structType->getOffset( i );
+
+ memcpy( (void*)destination, (void*)((*iter)->getValueBuffer()), (*iter)->getValueType()->getSize() );
+ }
+
+ // delete the list of type elements
+ // release( scalarDataList->begin(), scalarDataList->end() );
+ for( iter=scalarDataList->begin(); iter!=scalarDataList->end(); iter++ )
+ {
+ delete *iter;
+ *iter=NULL;
+ }
+ delete scalarDataList;
+ scalarDataList = NULL;
+}
+
+
+
+QtComplexData::QtComplexData( const QtComplexData& obj )
+ : QtScalarData( obj )
+{
+}
+
+
+
+void
+QtComplexData::printStatus( ostream& stream ) const
+{
+ stream << "complex, " << std::flush;
+ QtScalarData::printStatus( stream );
+ stream << std::endl;
+}
diff --git a/qlparser/qtcomplexdata.hh b/qlparser/qtcomplexdata.hh
new file mode 100644
index 0000000..51178b8
--- /dev/null
+++ b/qlparser/qtcomplexdata.hh
@@ -0,0 +1,92 @@
+#ifndef _QTCOMPLEXDATA_HH
+#define _QTCOMPLEXDATA_HH
+
+#include "qlparser/qtscalardata.hh"
+
+#include <list>
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+//@ManMemo: Module: {\bf qlparser}
+
+/**
+
+ The class represents a complex scalar value handled by the query tree.
+
+*/
+
+class QtComplexData : public QtScalarData
+{
+ public:
+ /// list of \Ref{QtScalarData} objects
+ typedef std::list<QtScalarData*> QtScalarDataList;
+
+ /// default constructor
+ QtComplexData();
+
+ /// constructor getting a pointer to a list of \Ref{QtScalarData} objects
+ QtComplexData( QtScalarDataList* &scalarDataList );
+ /**
+ Construct an object with \Ref{QtScalarData} elements of the list and
+ destroy the list afterwards. {\ttscalarDataList} is set to zero.
+ */
+
+ /// copy constructor
+ QtComplexData( const QtComplexData& obj );
+
+ /// print status of the object to the specified stream
+ virtual void printStatus( std::ostream& stream = std::cout ) const;
+};
+
+#include "qlparser/qtcomplexdata.icc"
+
+#endif
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/qlparser/qtcomplexdata.icc b/qlparser/qtcomplexdata.icc
new file mode 100644
index 0000000..2651f9c
--- /dev/null
+++ b/qlparser/qtcomplexdata.icc
@@ -0,0 +1,29 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
diff --git a/qlparser/qtcondense.cc b/qlparser/qtcondense.cc
new file mode 100644
index 0000000..7a17b93
--- /dev/null
+++ b/qlparser/qtcondense.cc
@@ -0,0 +1,801 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)qlparser, QtCondense: $Header: /home/rasdev/CVS-repository/rasdaman/qlparser/qtcondense.cc,v 1.47 2005/09/03 20:17:55 rasdev Exp $";
+
+#include "raslib/rmdebug.hh"
+#include "debug.hh"
+
+#include "qlparser/qtcondense.hh"
+#include "qlparser/qtmdd.hh"
+#include "qlparser/qtatomicdata.hh"
+#include "qlparser/qtscalardata.hh"
+#include "qlparser/qtcomplexdata.hh"
+#include "qlparser/qtbinaryinduce.hh"
+#include "qlparser/qtbinaryinduce2.hh"
+
+#include "mddmgr/mddobj.hh"
+
+#include "catalogmgr/typefactory.hh"
+#include "catalogmgr/ops.hh"
+
+#include <iostream>
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+using namespace std;
+#endif
+
+const QtNode::QtNodeType QtCondense::nodeType = QtNode::QT_CONDENSE;
+
+QtCondense::QtCondense( Ops::OpType newOpType )
+ : QtUnaryOperation(), opType( newOpType )
+{
+}
+
+
+
+QtCondense::QtCondense( Ops::OpType newOpType, QtOperation* initInput )
+ : QtUnaryOperation( initInput ), opType( newOpType )
+{
+}
+
+
+QtNode::QtAreaType
+QtCondense::getAreaType()
+{
+ return QT_AREA_SCALAR;
+}
+
+
+
+void
+QtCondense::optimizeLoad( QtTrimList* trimList )
+{
+ // reset trimList because optimization enters a new MDD area
+
+ // delete list
+ // release( trimList->begin(), trimList->end() );
+ vector<QtNode::QtTrimElement*>::iterator iter;
+ for( iter=trimList->begin(); iter!=trimList->end(); iter++ )
+ {
+ delete *iter;
+ *iter=NULL;
+ }
+
+ delete trimList;
+ trimList=NULL;
+
+ if( input )
+ input->optimizeLoad( new QtNode::QtTrimList );
+}
+
+
+
+QtData*
+QtCondense::computeFullCondense( QtDataList* inputList, r_Minterval& areaOp )
+{
+ RMDBCLASS( "QtCondense", "computeFullCondense( QtDataList*, r_Minterval& )", "qlparser", __FILE__, __LINE__ )
+
+ QtScalarData* returnValue = NULL;
+
+ // get the operand
+ QtData* operand = input->evaluate( inputList );
+
+ if( operand )
+ {
+
+#ifdef QT_RUNTIME_TYPE_CHECK
+ if( operand->getDataType() != QT_MDD )
+ {
+ RMInit::logOut << "Internal error in QtCountCells::computeFullCondense() - "
+ << "runtime type checking failed (MDD)." << endl;
+
+ // delete old operand
+ if( operand ) operand->deleteRef();
+
+ return 0;
+ }
+#endif
+
+ QtMDD* mdd = (QtMDD*)operand;
+
+#ifdef QT_RUNTIME_TYPE_CHECK
+ if( opType == Ops::OP_SOME || opType == Ops::OP_ALL || opType == Ops::OP_COUNT )
+ {
+ if( mdd->getCellType()->getType() != BOOLTYPE )
+ {
+ RMInit::logOut << "Internal error in QtCondense::computeFullCondense() - "
+ << "runtime type checking failed (BOOL)." << endl;
+
+ // delete old operand
+ if( operand ) operand->deleteRef();
+
+ return 0;
+ }
+ }
+#endif
+
+ // get result type
+ const BaseType* resultType = Ops::getResultType( opType, mdd->getCellType() );
+
+ // get the MDD object
+ MDDObj* op = ((QtMDD*)operand)->getMDDObject();
+
+ // get the area, where the operation has to be applied
+ areaOp = mdd->getLoadDomain();
+
+TALK( "computeFullCondense-last-good\n" );
+ // get all tiles in relevant area
+ vector<Tile*>* allTiles = op->intersect(areaOp);
+
+TALK( "computeFullCondense-8\n" );
+ // get new operation object
+ CondenseOp* condOp = Ops::getCondenseOp( opType, resultType, mdd->getCellType() );
+
+TALK( "computeFullCondense-9\n" );
+ // and iterate over them
+ for( vector<Tile*>::iterator tileIt = allTiles->begin();
+ tileIt!=allTiles->end(); tileIt++ )
+ {
+ // domain of the actual tile
+ r_Minterval tileDom = (*tileIt)->getDomain();
+
+ // domain of the relevant area of the actual tile
+ r_Minterval intersectDom = tileDom.create_intersection( areaOp );
+
+ (*tileIt)->execCondenseOp( condOp, intersectDom );
+ }
+
+ // delete tile vector
+ delete allTiles;
+ allTiles=NULL;
+
+TALK( "computeFullCondense-a\n" );
+ // create result object
+ if( resultType->getType() == STRUCT )
+ returnValue = new QtComplexData();
+ else
+ returnValue = new QtAtomicData();
+
+TALK( "computeFullCondense-b\n" );
+ // allocate buffer for the result
+ char* resultBuffer = new char[resultType->getSize()];
+ memcpy( (void*)resultBuffer, (void*)condOp->getAccuVal(), (size_t)resultType->getSize() );
+
+TALK( "computeFullCondense-c\n" );
+ returnValue->setValueType ( resultType );
+ returnValue->setValueBuffer( resultBuffer );
+
+TALK( "computeFullCondense-d\n" );
+ // delete operation object
+ delete condOp;
+ condOp=NULL;
+
+TALK( "computeFullCondense-e\n" );
+ // delete old operand
+ if( operand ) operand->deleteRef();
+ }
+
+RMDBGIF(3, RMDebug::module_qlparser, "QtCondense", \
+ RMInit::dbgOut << endl << "opType of QtCondense::computeFullCondense(): " << opType << endl; \
+ RMInit::dbgOut << "Result.....................................: " << flush; \
+ returnValue->printStatus( RMInit::dbgOut ); \
+ RMInit::dbgOut << endl; )
+ return returnValue;
+}
+
+
+
+const QtTypeElement&
+QtCondense::checkType( QtTypeTuple* typeTuple )
+{
+ RMDBCLASS( "QtCondense", "checkType( QtTypeTuple* )", "qlparser", __FILE__, __LINE__ )
+
+ dataStreamType.setDataType( QT_TYPE_UNKNOWN );
+
+ // check operand branches
+ if( input )
+ {
+
+ // get input types
+ const QtTypeElement& inputType = input->checkType( typeTuple );
+
+RMDBGIF(3, RMDebug::module_qlparser, "QtCondense", \
+ RMInit::dbgOut << "Class..: " << getClassName() << endl; \
+ RMInit::dbgOut << "Operand: " << flush; \
+ inputType.printStatus( RMInit::dbgOut ); \
+ RMInit::dbgOut << endl; )
+
+ if( inputType.getDataType() != QT_MDD )
+ {
+ RMInit::logOut << "Error: QtCondense::evaluate() - operand must be multidimensional." << endl;
+ parseInfo.setErrorNo(353);
+ throw parseInfo;
+ }
+
+ const BaseType* baseType = ((const MDDBaseType*)(inputType.getType()))->getBaseType();
+
+ if( opType == Ops::OP_SOME || opType == Ops::OP_ALL )
+ {
+ if( baseType->getType() != BOOLTYPE )
+ {
+ RMInit::logOut << "Error: QtCondense::evaluate() - operand of quantifiers must be of type r_Marray<d_Boolean>." << endl;
+ parseInfo.setErrorNo(354);
+ throw parseInfo;
+ }
+ }
+
+ if( opType == Ops::OP_COUNT )
+ {
+ if( baseType->getType() != BOOLTYPE )
+ {
+ RMInit::logOut << "Error: QtCondense::evaluate() - operand of count_cells must be of type r_Marray<d_Boolean>." << endl;
+ parseInfo.setErrorNo(415);
+ throw parseInfo;
+ }
+ }
+
+ const BaseType* resultType = Ops::getResultType( opType, baseType );
+
+ if( getNodeType() == QT_AVGCELLS )
+ {
+ // consider division by the number of cells
+
+ const BaseType* DoubleType = TypeFactory::mapType("Double");
+ const BaseType* finalResultType = Ops::getResultType( Ops::OP_DIV, resultType, DoubleType );
+
+ resultType = finalResultType;
+ }
+
+ dataStreamType.setType( resultType );
+ }
+ else
+ RMInit::logOut << "Error: QtCondense::checkType() - operand branch invalid." << endl;
+
+ return dataStreamType;
+}
+
+
+void
+QtCondense::printTree( int tab, ostream& s, QtChildType mode )
+{
+ s << SPACE_STR(tab).c_str() << getClassName() << " object" << endl;
+
+ QtUnaryOperation::printTree( tab, s, mode );
+}
+
+
+
+void
+QtCondense::printAlgebraicExpression( ostream& s )
+{
+ s << getAlgebraicName() << "(";
+
+ if( input )
+ input->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << ")";
+}
+
+
+
+const QtNode::QtNodeType QtSome::nodeType = QtNode::QT_SOME;
+
+
+QtSome::QtSome()
+ : QtCondense( Ops::OP_SOME )
+{
+}
+
+
+QtSome::QtSome( QtOperation* inputNew )
+ : QtCondense( Ops::OP_SOME, inputNew )
+{
+}
+
+/*
+void
+QtSome::rewriteOps()
+{
+ if( input )
+ {
+ if( input->getNodeType() == QtNode::QT_OR )
+ {
+ // pushdown of condenser expression
+
+ QtOr* orNode = (QtOr*) input;
+ QtOperation* node1 = orNode->getInput1();
+ QtOperation* node2 = orNode->getInput2();
+
+ if( node1 && node2 &&
+ node1->getAreaType() == QtNode::QT_AREA_MDD &&
+ node2->getAreaType() == QtNode::QT_AREA_MDD )
+ {
+ RMInit::logOut << "> rule (pushdown condenser): SOME_CELLS(A OR B) -> SOME_CELLS(A) OR SOME_CELLS(B)" << endl;
+
+ QtSome* newNode = new QtSome( node1 );
+ setInput( node2 );
+ newNode->setDataStreamType( QtTypeElement(QT_BOOL) );
+
+ this->getParent()->setInput( this, orNode );
+ orNode->setInput1( newNode );
+ orNode->setInput2( this );
+ orNode->setDataStreamType( QtTypeElement(QT_BOOL) );
+
+ newNode->rewriteOps();
+ }
+ };
+
+ input->rewriteOps();
+ }
+ else
+ RMInit::logOut << "Error: QtSome::rewriteOps() - the operand branch is invalid." << endl;
+}
+*/
+
+QtData*
+QtSome::evaluate( QtDataList* inputList )
+{
+ RMDBCLASS( "QtSome", "evaluate( QtDataList* )", "qlparser", __FILE__, __LINE__ )
+
+ QtData* returnValue = NULL;
+ r_ULong dummy=0; // needed for conversion to and from CULong
+
+ // get the operand
+ QtData* operand = input->evaluate( inputList );
+
+ if( operand )
+ {
+#ifdef QT_RUNTIME_TYPE_CHECK
+ if( operand->getDataType() != QT_MDD )
+ {
+ RMInit::logOut << "Internal error in QtSome::evaluate() - "
+ << "runtime type checking failed (MDD)." << endl;
+
+ // delete old operand
+ if( operand ) operand->deleteRef();
+
+ return 0;
+ }
+#endif
+
+ QtMDD* mdd = (QtMDD*)operand;
+
+ // get result type
+ BaseType* resultType = (BaseType*)dataStreamType.getType();
+
+#ifdef QT_RUNTIME_TYPE_CHECK
+ if( mdd->getCellType()->getType() != BOOLTYPE )
+ RMInit::logOut << "Internal error in QtSome::evaluate() - "
+ << "runtime type checking failed (BOOL)." << endl;
+
+ // delete old operand
+ if( operand ) operand->deleteRef();
+
+ return 0;
+ }
+#endif
+
+ // get the MDD object
+ MDDObj* op = mdd->getMDDObject();
+
+ // get the area, where the operation has to be applied
+ r_Minterval areaOp = mdd->getLoadDomain();
+
+ // get all tiles in relevant area
+ vector<Tile*>* allTiles = op->intersect(areaOp);
+
+ // allocate buffer for the result
+ unsigned int typeSize = resultType->getSize();
+ char* resultBuffer = new char[typeSize];
+
+ // initialize result buffer with false
+ dummy = 0;
+ resultType->makeFromCULong( resultBuffer, &dummy );
+ CondenseOp* condOp = Ops::getCondenseOp(Ops::OP_SOME, resultType, resultBuffer, resultType, 0, 0);
+
+ // and iterate over them
+ for( vector<Tile*>::iterator tileIt = allTiles->begin(); tileIt != allTiles->end() && !dummy ; tileIt++ )
+ {
+ // domain of the actual tile
+ r_Minterval tileDom = (*tileIt)->getDomain();
+
+ // domain of the relevant area of the actual tile
+ r_Minterval intersectDom = tileDom.create_intersection( areaOp );
+ (*tileIt)->execCondenseOp( condOp, intersectDom );
+ resultType->convertToCULong( condOp->getAccuVal(), &dummy );
+ }
+
+ delete condOp;
+ condOp = NULL;
+ // delete tile vector
+ delete allTiles;
+ allTiles=NULL;
+
+ // create QtAtomicData object for the result
+ returnValue = new QtAtomicData( (bool)(dummy) );
+
+ // delete result buffer
+ delete[] resultBuffer;
+ resultBuffer = NULL;
+
+ // The following is now then when deleting the last reference to the operand.
+ // delete the obsolete MDD object
+ // delete op;
+
+ // delete old operand
+ if( operand ) operand->deleteRef();
+ }
+
+ return returnValue;
+}
+
+
+
+const QtAll::QtNodeType QtAll::nodeType = QtNode::QT_ALL;
+
+
+QtAll::QtAll()
+ : QtCondense( Ops::OP_ALL )
+{
+}
+
+
+QtAll::QtAll( QtOperation* inputNew )
+ : QtCondense( Ops::OP_ALL, inputNew )
+{
+}
+
+/*
+void
+QtAll::rewriteOps()
+{
+ if( input )
+ {
+ if( input->getNodeType() == QtNode::QT_AND )
+ {
+ // pushdown of condenser expression
+
+ QtAnd* andNode = (QtAnd*) input;
+ QtOperation* node1 = andNode->getInput1();
+ QtOperation* node2 = andNode->getInput2();
+
+ if( node1 && node2 &&
+ node1->getAreaType() == QtNode::QT_AREA_MDD &&
+ node2->getAreaType() == QtNode::QT_AREA_MDD )
+ {
+ RMInit::logOut << "> rule (pushdown condenser): ALL_CELLS(A AND B) -> ALL_CELLS(A) AND ALL_CELLS(B)" << endl;
+
+ QtAll* newNode = new QtAll( node1 );
+ setInput( node2 );
+ newNode->setDataStreamType( QtTypeElement(QT_BOOL) );
+
+ this->getParent()->setInput( this, andNode );
+ andNode->setInput1( newNode );
+ andNode->setInput2( this );
+ andNode->setDataStreamType( QtTypeElement(QT_BOOL) );
+
+ newNode->rewriteOps();
+ }
+ };
+
+ input->rewriteOps();
+
+ }
+ else
+ RMInit::logOut << "Error: QtAll::rewriteOps() - the operand branch is invalid." << endl;
+}
+*/
+
+QtData*
+QtAll::evaluate( QtDataList* inputList )
+{
+ RMDBCLASS( "QtAll", "evaluate( QtDataList* )", "qlparser", __FILE__, __LINE__ )
+
+ QtData* returnValue = NULL;
+ r_ULong dummy=0; // needed for conversion to and from CULong
+
+ // get the operand
+ QtData* operand = input->evaluate( inputList );
+
+ if( operand )
+ {
+
+#ifdef QT_RUNTIME_TYPE_CHECK
+ if( operand->getDataType() != QT_MDD )
+ {
+ RMInit::logOut << "Internal error in QtAll::evaluate() - "
+ << "runtime type checking failed (MDD)." << endl;
+
+ // delete old operand
+ if( operand ) operand->deleteRef();
+
+ return 0;
+ }
+#endif
+
+ QtMDD* mdd = (QtMDD*)operand;
+
+ // get result type
+ const BaseType* resultType = (BaseType*)dataStreamType.getType();
+
+#ifdef QT_RUNTIME_TYPE_CHECK
+ if( mdd->getCellType()->getType() != BOOLTYPE )
+ RMInit::logOut << "Internal error in QtAll::evaluate() - "
+ << "runtime type checking failed (BOOL)." << endl;
+
+ // delete old operand
+ if( operand ) operand->deleteRef();
+
+ return 0;
+ }
+#endif
+
+ // get the MDD object
+ MDDObj* op = ((QtMDD*)operand)->getMDDObject();
+
+ // get the area, where the operation has to be applied
+ r_Minterval areaOp = mdd->getLoadDomain();
+
+ // get all tiles in relevant area
+ vector<Tile*>* allTiles = op->intersect(areaOp);
+
+ // allocate buffer for the result
+ unsigned int tempTypeSize = resultType->getSize();
+ char* resultBuffer = new char[tempTypeSize];
+
+ // initialize result buffer with true
+ dummy = 1;
+ resultType->makeFromCULong( resultBuffer, &dummy );
+ CondenseOp* condOp = Ops::getCondenseOp(Ops::OP_ALL, resultType, resultBuffer, resultType, 0, 0);
+
+ for( std::vector<Tile*>::iterator tileIt = allTiles->begin(); tileIt!=allTiles->end() && dummy; tileIt++ )
+ {
+ // domain of the actual tile
+ r_Minterval tileDom = (*tileIt)->getDomain();
+
+ // domain of the relevant area of the actual tile
+ r_Minterval intersectDom = tileDom.create_intersection( areaOp );
+
+ (*tileIt)->execCondenseOp( condOp, intersectDom );
+ resultType->convertToCULong( condOp->getAccuVal(), &dummy );
+ }
+ delete condOp;
+ condOp = NULL;
+ // delete tile vector
+ delete allTiles;
+ allTiles=NULL;
+
+ // create QtBoolData object for the result
+ returnValue = new QtAtomicData( (bool)(dummy) );
+
+ // delete result buffer done in delete CondOp
+ delete[] resultBuffer;
+ resultBuffer=NULL;
+
+ // delete old operand
+ if( operand ) operand->deleteRef();
+ }
+
+ return returnValue;
+}
+
+
+
+const QtCountCells::QtNodeType QtCountCells::nodeType = QtNode::QT_COUNTCELLS;
+
+
+QtCountCells::QtCountCells()
+ : QtCondense( Ops::OP_COUNT )
+{
+}
+
+
+QtCountCells::QtCountCells( QtOperation* inputNew )
+ : QtCondense( Ops::OP_COUNT, inputNew )
+{
+}
+
+
+QtData*
+QtCountCells::evaluate( QtDataList* inputList )
+{
+ RMDBCLASS( "QtCountCells", "evaluate( QtDataList* )", "qlparser", __FILE__, __LINE__ )
+r_Minterval dummyint;
+ QtData* returnValue = QtCondense::computeFullCondense( inputList, dummyint );
+
+ return returnValue;
+}
+
+
+
+const QtAddCells::QtNodeType QtAddCells::nodeType = QtNode::QT_ADDCELLS;
+
+
+QtAddCells::QtAddCells()
+ : QtCondense( Ops::OP_SUM )
+{
+}
+
+
+QtAddCells::QtAddCells( QtOperation* inputNew )
+ : QtCondense( Ops::OP_SUM, inputNew )
+{
+}
+
+
+QtData*
+QtAddCells::evaluate( QtDataList* inputList )
+{
+ RMDBCLASS( "QtAddCells", "evaluate( QtDataList* )", "qlparser", __FILE__, __LINE__ )
+r_Minterval dummyint;
+
+ QtData* returnValue = QtCondense::computeFullCondense( inputList, dummyint );
+
+ return returnValue;
+}
+
+
+
+const QtAvgCells::QtNodeType QtAvgCells::nodeType = QtNode::QT_AVGCELLS;
+
+
+QtAvgCells::QtAvgCells()
+ : QtCondense( Ops::OP_SUM )
+{
+}
+
+
+QtAvgCells::QtAvgCells( QtOperation* inputNew )
+ : QtCondense( Ops::OP_SUM, inputNew )
+{
+}
+
+
+QtData*
+QtAvgCells::evaluate( QtDataList* inputList )
+{
+ RMDBCLASS( "QtAvgCells", "evaluate( QtDataList* )", "qlparser", __FILE__, __LINE__ )
+
+ // domain for condensing operation
+ r_Minterval areaOp;
+
+ QtData* dataCond = QtCondense::computeFullCondense( inputList, areaOp );
+
+ //
+ // divide by the number of cells
+ //
+
+ QtScalarData* scalarDataResult = NULL;
+ QtScalarData* scalarDataCond = (QtScalarData*)dataCond;
+ BaseType* resultType = (BaseType*)dataStreamType.getType();
+
+
+ // allocate memory for the result
+ char* resultBuffer = new char[ resultType->getSize() ];
+
+ // allocate ulong constant with number of cells
+ r_ULong constValue = areaOp.cell_count();
+ const BaseType* constType = TypeFactory::mapType("ULong");
+ char* constBuffer = new char[ constType->getSize() ];
+
+ constType->makeFromCULong( constBuffer, &constValue );
+
+RMDBGIF(3, RMDebug::module_qlparser, "QtCondense", \
+ RMInit::dbgOut << "Number of cells....: " << flush; \
+ constType->printCell( RMInit::dbgOut, constBuffer ); \
+ RMInit::dbgOut << endl; )
+
+ Ops::execBinaryConstOp( Ops::OP_DIV, resultType,
+ scalarDataCond->getValueType(), constType,
+ resultBuffer,
+ scalarDataCond->getValueBuffer(), constBuffer );
+
+ delete[] constBuffer;
+ constBuffer=NULL;
+ delete dataCond;
+ dataCond=NULL;
+
+ if( resultType->getType() == STRUCT )
+ scalarDataResult = new QtComplexData();
+ else
+ scalarDataResult = new QtAtomicData();
+
+ scalarDataResult->setValueType ( resultType );
+ scalarDataResult->setValueBuffer( resultBuffer );
+
+RMDBGIF(3, RMDebug::module_qlparser, "QtCondense", \
+ RMInit::dbgOut << endl << "Result.............: " << flush; \
+ scalarDataResult->printStatus( RMInit::dbgOut ); \
+ RMInit::dbgOut << endl; )
+
+ return scalarDataResult;
+}
+
+
+const QtMinCells::QtNodeType QtMinCells::nodeType = QtNode::QT_MINCELLS;
+
+
+QtMinCells::QtMinCells()
+ : QtCondense( Ops::OP_MIN )
+{
+}
+
+
+QtMinCells::QtMinCells( QtOperation* inputNew )
+ : QtCondense( Ops::OP_MIN, inputNew )
+{
+}
+
+
+QtData*
+QtMinCells::evaluate( QtDataList* inputList )
+{
+ RMDBCLASS( "QtMinCells", "evaluate( QtDataList* )", "qlparser", __FILE__, __LINE__ )
+r_Minterval dummyint;
+
+ QtData* returnValue = QtCondense::computeFullCondense( inputList, dummyint );
+
+ return returnValue;
+}
+
+
+
+const QtMaxCells::QtNodeType QtMaxCells::nodeType = QtNode::QT_MAXCELLS;
+
+
+QtMaxCells::QtMaxCells()
+ : QtCondense( Ops::OP_MAX )
+{
+}
+
+
+QtMaxCells::QtMaxCells( QtOperation* inputNew )
+ : QtCondense( Ops::OP_MAX, inputNew )
+{
+}
+
+
+QtData*
+QtMaxCells::evaluate( QtDataList* inputList )
+{
+ RMDBCLASS( "QtMaxCells", "evaluate( QtDataList* )", "qlparser", __FILE__, __LINE__ )
+r_Minterval dummyint;
+
+ QtData* returnValue = QtCondense::computeFullCondense( inputList, dummyint );
+
+ return returnValue;
+}
diff --git a/qlparser/qtcondense.hh b/qlparser/qtcondense.hh
new file mode 100644
index 0000000..46f2fac
--- /dev/null
+++ b/qlparser/qtcondense.hh
@@ -0,0 +1,352 @@
+#ifndef _QTCONDENSE_
+#define _QTCONDENSE_
+
+#include "qlparser/qtunaryoperation.hh"
+#include "raslib/minterval.hh"
+#include "catalogmgr/ops.hh"
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/**************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+ The class represents a condense operation in the query tree.
+
+*/
+
+class QtCondense : public QtUnaryOperation
+{
+ public:
+ /// constructor getting operation
+ QtCondense( Ops::OpType newOpType);
+
+ /// constructor getting operation and operand
+ QtCondense( Ops::OpType newOpType, QtOperation* input );
+
+ /// method for computing full condense operation (without early termination option)
+ QtData* computeFullCondense( QtDataList* inputList, r_Minterval& areaOp);// = r_Minterval() );
+
+ /// test if the edge to the parent node is of type mdd or atomic
+ virtual QtAreaType getAreaType();
+
+ /// optimizing load access
+ virtual void optimizeLoad( QtTrimList* trimList );
+ /**
+ The method deletes the given {\tt trimList} and passes the {\tt optimizeLoad}
+ message with empty triming list to its operand tree.
+
+ Optimization process enters a new MDD area.
+ */
+
+ /// type checking of the subtree
+ virtual const QtTypeElement& checkType( QtTypeTuple* typeTuple = NULL );
+
+ /// prints the tree
+ virtual void printTree( int tab, std::ostream& s = std::cout, QtChildType mode = QT_ALL_NODES );
+
+ /// prints the algebraic expression
+ virtual void printAlgebraicExpression( std::ostream& s = std::cout );
+
+ /// method returning class name
+ inline virtual const char* getClassName() const;
+
+ /// method returning algebraic identifier
+ inline virtual const char* getAlgebraicName() const;
+
+ protected:
+ /// operation type
+ Ops::OpType opType;
+
+ private:
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+
+
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+ The class represents the specialized condenser {\tt some_cells()} in the query tree.
+
+*/
+
+class QtSome : public QtCondense
+{
+ public:
+ /// default constructor
+ QtSome();
+
+ /// constructor getting the operand
+ QtSome( QtOperation* input );
+
+ /// optimizes the tree
+// virtual void rewriteOps();
+
+ /// method for evaluating the node
+ QtData* evaluate( QtDataList* inputList );
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ /// method returning class name
+ inline virtual const char* getClassName() const;
+
+ /// method returning algebraic identifier
+ inline virtual const char* getAlgebraicName() const;
+
+ private:
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+ The class represents the specialized condenser {\tt all_cells()} in the query tree.
+
+*/
+
+class QtAll : public QtCondense
+{
+ public:
+ /// default constructor
+ QtAll();
+
+ /// constructor getting the operand
+ QtAll( QtOperation* input );
+
+ /// optimizes the tree
+// virtual void rewriteOps();
+
+ /// method for evaluating the node
+ QtData* evaluate( QtDataList* inputList );
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ /// method returning class name
+ inline virtual const char* getClassName() const;
+
+ /// method returning algebraic identifier
+ inline virtual const char* getAlgebraicName() const;
+
+ private:
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+ The class represents the specialized condenser {\tt count_cells()} in the query tree.
+
+*/
+
+class QtCountCells : public QtCondense
+{
+ public:
+ /// default constructor
+ QtCountCells();
+
+ /// constructor getting the operand
+ QtCountCells( QtOperation* input );
+
+ /// method for evaluating the node
+ QtData* evaluate( QtDataList* inputList );
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ /// method returning class name
+ inline virtual const char* getClassName() const;
+
+ /// method returning algebraic identifier
+ inline virtual const char* getAlgebraicName() const;
+
+ private:
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+ The class represents the specialized condenser {\tt add_cells()} in the query tree.
+
+*/
+
+class QtAddCells : public QtCondense
+{
+ public:
+ /// default constructor
+ QtAddCells();
+
+ /// constructor getting the operand
+ QtAddCells( QtOperation* input );
+
+ /// method for evaluating the node
+ QtData* evaluate( QtDataList* inputList );
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ /// method returning class name
+ inline virtual const char* getClassName() const;
+
+ /// method returning algebraic identifier
+ inline virtual const char* getAlgebraicName() const;
+
+ private:
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+ The class represents the specialized condenser {\tt avg_cells()} in the query tree.
+
+*/
+
+class QtAvgCells : public QtCondense
+{
+ public:
+ /// default constructor
+ QtAvgCells();
+
+ /// constructor getting the operand
+ QtAvgCells( QtOperation* input );
+
+ /// method for evaluating the node
+ QtData* evaluate( QtDataList* inputList );
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ /// method returning class name
+ inline virtual const char* getClassName() const;
+
+ /// method returning algebraic identifier
+ inline virtual const char* getAlgebraicName() const;
+
+ private:
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+ The class represents the specialized condenser {\tt min_cells()} in the query tree.
+
+*/
+
+class QtMinCells : public QtCondense
+{
+ public:
+ /// default constructor
+ QtMinCells();
+
+ /// constructor getting the operand
+ QtMinCells( QtOperation* input );
+
+ /// method for evaluating the node
+ QtData* evaluate( QtDataList* inputList );
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ /// method returning class name
+ inline virtual const char* getClassName() const;
+
+ /// method returning algebraic identifier
+ inline virtual const char* getAlgebraicName() const;
+
+ private:
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+ The class represents the specialized condenser {\tt max_cells()} in the query tree.
+
+*/
+
+class QtMaxCells : public QtCondense
+{
+ public:
+ /// default constructor
+ QtMaxCells();
+
+ /// constructor getting the operand
+ QtMaxCells( QtOperation* input );
+
+ /// method for evaluating the node
+ QtData* evaluate( QtDataList* inputList );
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ /// method returning class name
+ inline virtual const char* getClassName() const;
+
+ /// method returning algebraic identifier
+ inline virtual const char* getAlgebraicName() const;
+
+ private:
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+
+#include "qlparser/qtcondense.icc"
+
+#endif
+
diff --git a/qlparser/qtcondense.icc b/qlparser/qtcondense.icc
new file mode 100644
index 0000000..81d8552
--- /dev/null
+++ b/qlparser/qtcondense.icc
@@ -0,0 +1,197 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+
+inline const char*
+QtCondense::getClassName() const
+{
+ return "QtCondense";
+}
+
+
+inline const char*
+QtCondense::getAlgebraicName() const
+{
+ return "condense_cells";
+}
+
+
+
+inline const QtNode::QtNodeType
+QtSome::getNodeType() const
+{
+ return nodeType;
+}
+
+
+inline const char*
+QtSome::getClassName() const
+{
+ return "QtSome";
+}
+
+
+inline const char*
+QtSome::getAlgebraicName() const
+{
+ return "some_cells";
+}
+
+
+
+inline const QtNode::QtNodeType
+QtAll::getNodeType() const
+{
+ return nodeType;
+}
+
+
+inline const char*
+QtAll::getClassName() const
+{
+ return "QtAll";
+}
+
+
+inline const char*
+QtAll::getAlgebraicName() const
+{
+ return "all_cells";
+}
+
+
+inline const QtNode::QtNodeType
+QtCountCells::getNodeType() const
+{
+ return nodeType;
+}
+
+
+inline const char*
+QtCountCells::getClassName() const
+{
+ return "QtCountCells";
+}
+
+
+inline const char*
+QtCountCells::getAlgebraicName() const
+{
+ return "count_cells";
+}
+
+
+inline const QtNode::QtNodeType
+QtAddCells::getNodeType() const
+{
+ return nodeType;
+}
+
+
+inline const char*
+QtAddCells::getClassName() const
+{
+ return "QtAddCells";
+}
+
+
+inline const char*
+QtAddCells::getAlgebraicName() const
+{
+ return "add_cells";
+}
+
+
+inline const QtNode::QtNodeType
+QtAvgCells::getNodeType() const
+{
+ return nodeType;
+}
+
+
+inline const char*
+QtAvgCells::getClassName() const
+{
+ return "QtAvgCells";
+}
+
+
+inline const char*
+QtAvgCells::getAlgebraicName() const
+{
+ return "avg_cells";
+}
+
+
+
+inline const QtNode::QtNodeType
+QtMinCells::getNodeType() const
+{
+ return nodeType;
+}
+
+
+inline const char*
+QtMinCells::getClassName() const
+{
+ return "QtMinCells";
+}
+
+
+inline const char*
+QtMinCells::getAlgebraicName() const
+{
+ return "min_cells";
+}
+
+
+
+inline const QtNode::QtNodeType
+QtMaxCells::getNodeType() const
+{
+ return nodeType;
+}
+
+
+inline const char*
+QtMaxCells::getClassName() const
+{
+ return "QtMaxCells";
+}
+
+
+inline const char*
+QtMaxCells::getAlgebraicName() const
+{
+ return "max_cells";
+}
+
+
+
+
diff --git a/qlparser/qtcondenseop.cc b/qlparser/qtcondenseop.cc
new file mode 100644
index 0000000..a20f956
--- /dev/null
+++ b/qlparser/qtcondenseop.cc
@@ -0,0 +1,440 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)qlparser, QtCondenseOp: $Header: /home/rasdev/CVS-repository/rasdaman/qlparser/qtcondenseop.cc,v 1.18 2003/12/27 20:51:28 rasdev Exp $";
+
+#include "raslib/rmdebug.hh"
+
+#include "qlparser/qtcondenseop.hh"
+#include "qlparser/qtdata.hh"
+#include "qlparser/qtmdd.hh"
+#include "qlparser/qtpointdata.hh"
+#include "qlparser/qtmintervaldata.hh"
+#include "qlparser/qtatomicdata.hh"
+#include "qlparser/qtcomplexdata.hh"
+
+#include "mddmgr/mddobj.hh"
+
+#include "catalogmgr/typefactory.hh"
+
+#include "catalogmgr/algebraops.hh"
+
+#include <iostream>
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+using namespace std;
+#endif
+
+
+const QtNode::QtNodeType QtCondenseOp::nodeType = QT_CONDENSEOP;
+
+QtCondenseOp::QtCondenseOp( Ops::OpType newOperation,
+ const string &initIteratorName,
+ QtOperation* mintervalExp,
+ QtOperation* cellExp,
+ QtOperation* condExp )
+ : operation( newOperation ),
+ iteratorName( initIteratorName ),
+ QtBinaryOperation( mintervalExp, cellExp ),
+ condOp( condExp )
+{
+}
+
+
+
+QtCondenseOp::~QtCondenseOp()
+{
+ if( condOp )
+ {
+ delete condOp;
+ condOp=NULL;
+ }
+}
+
+
+
+QtNode::QtNodeList*
+QtCondenseOp::getChilds( QtChildType flag )
+{
+ RMDBCLASS( "QtCondenseOp", "getChilds( QtChildType )", "qlparser", __FILE__, __LINE__ )
+ QtNodeList* resultList;
+ resultList = QtBinaryOperation::getChilds( flag );
+ if( condOp )
+ {
+ if( flag == QT_LEAF_NODES || flag == QT_ALL_NODES )
+ {
+ QtNodeList* subList=NULL;
+ subList = condOp->getChilds( flag );
+ // remove all elements in subList and insert them at the beginning in resultList
+ resultList->splice( resultList->begin(), *subList );
+ // delete temporary subList
+ delete subList;
+ subList=NULL;
+ }
+
+ // add the nodes of the current level
+ if( flag == QT_DIRECT_CHILDS || flag == QT_ALL_NODES )
+ resultList->push_back( condOp );
+ }
+
+ return resultList;
+}
+
+
+
+bool
+QtCondenseOp::equalMeaning( QtNode* node )
+{
+ RMDBCLASS( "QtCondenseOp", "equalMeaning( QtNode* )", "qlparser", __FILE__, __LINE__ )
+
+ bool result = false;
+
+ if( nodeType == node->getNodeType() )
+ {
+ QtCondenseOp* condNode;
+ condNode = (QtCondenseOp*) node; // by force
+
+ // check domain and cell expression
+ result = QtBinaryOperation::equalMeaning( condNode );
+
+ // check condition expression
+ result &= ( !condOp && !condNode->getCondOp() ) ||
+ condOp->equalMeaning( condNode->getCondOp() );
+ };
+
+ return ( result );
+}
+
+
+
+string
+QtCondenseOp::getSpelling()
+{
+ char tempStr[20];
+ sprintf(tempStr, "%ud", (unsigned long)getNodeType());
+ string result = string(tempStr);
+ result.append( "(" );
+ result.append( QtBinaryOperation::getSpelling() );
+ result.append( "," );
+
+ if( condOp )
+ result.append( condOp->getSpelling() );
+ else
+ result.append( "<nn>" );
+
+ result.append( ")" );
+
+ return result;
+}
+
+
+void
+QtCondenseOp::setInput( QtOperation* inputOld, QtOperation* inputNew )
+{
+ QtBinaryOperation::setInput( inputOld, inputNew );
+
+ if( condOp == inputOld )
+ {
+ condOp = inputNew;
+
+ if( inputNew )
+ inputNew->setParent( this );
+ }
+};
+
+
+
+void
+QtCondenseOp::optimizeLoad( QtTrimList* trimList )
+{
+ RMDBCLASS( "QtCondenseOp", "optimizeLoad( QtTrimList* )", "qlparser", __FILE__, __LINE__ )
+
+ // delete the trimList and optimize subtrees
+
+ // release( trimList->begin(), trimList->end() );
+ for( QtNode::QtTrimList::iterator iter=trimList->begin(); iter!=trimList->end(); iter++ )
+ {
+ delete *iter;
+ *iter=NULL;
+ }
+ delete trimList;
+ trimList=NULL;
+
+ QtBinaryOperation::optimizeLoad( new QtNode::QtTrimList() );
+
+ if( condOp )
+ condOp->optimizeLoad( new QtNode::QtTrimList() );
+}
+
+
+void
+QtCondenseOp::simplify()
+{
+ RMDBCLASS( "QtCondenseOp", "simplify()", "qlparser", __FILE__, __LINE__ )
+
+ RMDBGMIDDLE(1, RMDebug::module_qlparser, "QtCondenseOp", "simplify() warning: QtCondenseOp itself is not simplified yet")
+
+ // Default method for all classes that have no implementation.
+ // Method is used bottom up.
+
+ QtNodeList* resultList=NULL;
+ QtNodeList::iterator iter;
+
+ resultList = getChilds( QT_DIRECT_CHILDS );
+ for( iter=resultList->begin(); iter!=resultList->end(); iter++ )
+ (*iter)->simplify();
+
+ delete resultList;
+ resultList=NULL;
+}
+
+
+bool
+QtCondenseOp::isCommutative() const
+{
+ return false; // NOT commutative
+}
+
+
+
+QtData*
+QtCondenseOp::evaluate( QtDataList* inputList )
+{
+ RMDBCLASS( "QtCondenseOp", "evaluate( QtDataList* )", "qlparser", __FILE__, __LINE__ )
+
+ QtData* returnValue = NULL;
+ QtData* operand1 = NULL;
+
+ if( getOperand( inputList, operand1, 1 ) )
+ {
+
+#ifdef QT_RUNTIME_TYPE_CHECK
+ if( operand1->getDataType() != QT_MINTERVAL )
+ RMInit::logOut << "Internal error in QtMarrayOp::evaluate() - "
+ << "runtime type checking failed (Minterval)." << endl;
+
+ // delete old operand
+ if( operand1 ) operand1->deleteRef();
+
+ return 0;
+ }
+#endif
+
+ r_Minterval domain = ((QtMintervalData*)operand1)->getMintervalData();
+
+ RMDBGMIDDLE(1, RMDebug::module_qlparser, "QtCondenseOp", "Marray domain " << domain)
+
+ // determine aggregation type
+ BaseType* cellType = (BaseType*) input2->getDataStreamType().getType();
+
+ // get operation object
+ BinaryOp* cellBinOp = Ops::getBinaryOp( operation, cellType, cellType, cellType );
+
+ // create execution object QLCondenseOp
+ QLCondenseOp* qlCondenseOp = new QLCondenseOp( input2, condOp, inputList, iteratorName,
+ cellType, 0, cellBinOp );
+
+ // result buffer
+ char* result=NULL;
+
+ try
+ {
+ // execute query engine marray operation
+ result = Tile::execGenCondenseOp( qlCondenseOp, domain );
+ }
+ catch(...)
+ {
+ // free ressources
+ delete qlCondenseOp;
+ qlCondenseOp=NULL;
+ delete cellBinOp;
+ cellBinOp=NULL;
+ if( operand1 ) operand1->deleteRef();
+
+ throw;
+ }
+
+ // allocate cell buffer
+ char* resultBuffer = new char[ cellType->getSize() ];
+
+ // copy cell content
+ memcpy( (void*)resultBuffer, (void*)result, cellType->getSize() );
+
+ delete qlCondenseOp;
+ qlCondenseOp=NULL;
+ delete cellBinOp;
+ cellBinOp=NULL;
+
+ // create data object for the cell
+ QtScalarData* scalarDataObj = NULL;
+ if( cellType->getType() == STRUCT )
+ scalarDataObj = new QtComplexData();
+ else
+ scalarDataObj = new QtAtomicData();
+
+ scalarDataObj->setValueType ( cellType );
+ scalarDataObj->setValueBuffer( resultBuffer );
+
+ // set return data object
+ returnValue = scalarDataObj;
+
+ // delete old operands
+ if( operand1 ) operand1->deleteRef();
+ }
+
+ return returnValue;
+}
+
+
+
+void
+QtCondenseOp::printTree( int tab, ostream& s, QtChildType mode )
+{
+ s << SPACE_STR(tab).c_str() << "QtCondenseOp Object " << getNodeType() << endl;
+
+ s << SPACE_STR(tab).c_str() << "Iterator Name: " << iteratorName.c_str() << endl;
+
+ QtBinaryOperation::printTree( tab, s, mode );
+}
+
+
+
+void
+QtCondenseOp::printAlgebraicExpression( ostream& s )
+{
+ s << "(";
+
+ s << iteratorName.c_str() << ",";
+
+ if( input1 )
+ input1->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << ",";
+
+ if( input2 )
+ input2->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << ")";
+}
+
+
+
+const QtTypeElement&
+QtCondenseOp::checkType( QtTypeTuple* typeTuple )
+{
+ RMDBCLASS( "QtCondenseOp", "checkType( QtTypeTuple* )", "qlparser", __FILE__, __LINE__ )
+
+ dataStreamType.setDataType( QT_TYPE_UNKNOWN );
+
+ // check operand branches
+ if( input1 && input2 )
+ {
+
+ // check domain expression
+ const QtTypeElement& domainExp = input1->checkType( typeTuple );
+
+ if( domainExp.getDataType() != QT_MINTERVAL )
+ {
+ RMInit::logOut << "Error: QtMarrayOp::checkType() - Can not evaluate domain expression to an minterval" << endl;
+ parseInfo.setErrorNo(401);
+ throw parseInfo;
+ }
+
+ // add domain iterator to the list of bounded variables
+ bool newList = false;
+ if( !typeTuple )
+ {
+ typeTuple = new QtTypeTuple();
+ newList = true;
+ }
+ typeTuple->tuple.push_back( QtTypeElement( QT_POINT, iteratorName.c_str() ) );
+
+ //
+ // check value expression
+ //
+
+ // get value expression type
+ const QtTypeElement& valueExp = input2->checkType( typeTuple );
+
+ // check type
+ if( valueExp.getDataType() != QT_BOOL && valueExp.getDataType() != QT_COMPLEX &&
+ valueExp.getDataType() != QT_CHAR && valueExp.getDataType() != QT_OCTET &&
+ valueExp.getDataType() != QT_USHORT && valueExp.getDataType() != QT_SHORT &&
+ valueExp.getDataType() != QT_ULONG && valueExp.getDataType() != QT_LONG &&
+ valueExp.getDataType() != QT_FLOAT && valueExp.getDataType() != QT_DOUBLE )
+ {
+ RMInit::logOut << "Error: QtMarrayOp::checkType() - Value expression must be either of type atomic or complex" << endl;
+ parseInfo.setErrorNo(412);
+ throw parseInfo;
+ }
+
+ dataStreamType = valueExp;
+
+ //
+ // check condition expression
+ //
+
+ if( condOp )
+ {
+ // get value expression type
+ const QtTypeElement& condExp = condOp->checkType( typeTuple );
+
+ // check type
+ if( condExp.getDataType() != QT_BOOL )
+ {
+ RMInit::logOut << "Error: QtMarrayOp::checkType() - Condition expression must be of type boolean" << endl;
+ parseInfo.setErrorNo(413);
+ throw parseInfo;
+ }
+ }
+
+ // remove iterator again
+ typeTuple->tuple.pop_back();
+ if( newList )
+ {
+ delete typeTuple;
+ typeTuple = NULL;
+ }
+ }
+ else
+ RMInit::logOut << "Error: QtCondenseOp::checkType() - operand branch invalid." << endl;
+
+ return dataStreamType;
+}
+
+
diff --git a/qlparser/qtcondenseop.hh b/qlparser/qtcondenseop.hh
new file mode 100644
index 0000000..d1c3e8e
--- /dev/null
+++ b/qlparser/qtcondenseop.hh
@@ -0,0 +1,131 @@
+#ifndef _QTCONDENSEOP_
+#define _QTCONDENSEOP_
+
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+#endif
+
+#include "qlparser/qtbinaryoperation.hh"
+
+#include "catalogmgr/ops.hh"
+#include <stdio.h>
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+ The class represents the root of a cond expression.
+
+*/
+
+class QtCondenseOp : public QtBinaryOperation
+{
+ public:
+ /// constructor getting iterator, minterval exp, cell exp, and cell condition exp (optional)
+ QtCondenseOp( Ops::OpType newOperation,
+ const std::string& initIteratorName,
+ QtOperation* mintervalExp,
+ QtOperation* cellExp,
+ QtOperation* condExp = NULL );
+
+ /// virtual destructor
+ ~QtCondenseOp();
+
+ /// return childs of the node
+ virtual QtNodeList* getChilds( QtChildType flag );
+
+ /// test if the two nodes have an equal meaning in a subtree
+ virtual bool equalMeaning( QtNode* node );
+
+ /// creates a unique name for a common subexpression
+ virtual std::string getSpelling();
+
+ /// method for query rewrite
+ virtual void setInput( QtOperation* inputOld, QtOperation* inputNew );
+
+ /// optimizing load access
+ void optimizeLoad( QtTrimList* trimList );
+
+ /// simplifies the tree
+ virtual void simplify();
+
+ /// returns FALSE saying that the operation IS NOT commutative
+ virtual bool isCommutative() const;
+
+ /// method for evaluating the node
+ QtData* evaluate( QtDataList* inputList );
+ /**
+ */
+
+ /// prints the tree
+ virtual void printTree( int tab, std::ostream& s = std::cout, QtChildType mode = QT_ALL_NODES );
+
+ /// prints the algebraic expression
+ virtual void printAlgebraicExpression( std::ostream& s = std::cout );
+
+ //@Man: Read/Write methods:
+ //@{
+ ///
+
+ ///
+ inline QtOperation* getCondOp();
+
+ ///
+ //@}
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ /// type checking of the subtree
+ virtual const QtTypeElement& checkType( QtTypeTuple* typeTuple = NULL );
+
+ private:
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+
+ /// attribute storing the iterator name
+ std::string iteratorName;
+
+ /// attribute storing optional cell condition expression
+ QtOperation* condOp;
+
+ /// attribute storing condensing operation
+ Ops::OpType operation;
+};
+
+
+#include "qlparser/qtcondenseop.icc"
+
+#endif
+
diff --git a/qlparser/qtcondenseop.icc b/qlparser/qtcondenseop.icc
new file mode 100644
index 0000000..6ba6fad
--- /dev/null
+++ b/qlparser/qtcondenseop.icc
@@ -0,0 +1,44 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+inline const QtNode::QtNodeType
+QtCondenseOp::getNodeType() const
+{
+ return nodeType;
+}
+
+
+
+inline QtOperation*
+QtCondenseOp::getCondOp()
+{
+ return condOp;
+}
+
+
diff --git a/qlparser/qtconst.cc b/qlparser/qtconst.cc
new file mode 100644
index 0000000..b4896f0
--- /dev/null
+++ b/qlparser/qtconst.cc
@@ -0,0 +1,265 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)qlparser, QtConst: $Header: /home/rasdev/CVS-repository/rasdaman/qlparser/qtconst.cc,v 1.22 2005/07/06 22:48:34 rasdev Exp $";
+
+#include "qlparser/qtconst.hh"
+#include "qlparser/qtscalardata.hh"
+#include "qlparser/qtstringdata.hh"
+
+#include "qlparser/qtmdd.hh" // these three can be deleted with new memory management
+
+#include "relcatalogif/basetype.hh"
+#include "mddmgr/mddobj.hh"
+
+#include <iostream>
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+using namespace std;
+#endif
+
+#include <iostream>
+
+// deprecated, not available any longer -- PB 2005-jan-14
+// #include <strstream.h>
+
+const QtNode::QtNodeType QtConst::nodeType = QtNode::QT_CONST;
+
+
+QtConst::QtConst( QtData* newDataObj )
+ : QtOperation(),
+ dataObj( newDataObj )
+{
+ // store parse info of the data object
+ setParseInfo( dataObj->getParseInfo() );
+}
+
+
+
+QtConst::~QtConst()
+{
+ if( dataObj ) dataObj->deleteRef();
+}
+
+
+
+bool
+QtConst::equalMeaning( QtNode* node )
+{
+ RMDBCLASS( "QtConst", "equalMeaning( QtNode* )", "qlparser", __FILE__, __LINE__ )
+
+ bool result = false;
+
+ if( nodeType == node->getNodeType() )
+ {
+ QtConst* constObj = (QtConst*) node;
+
+ result = dataObj->equal( constObj->getDataObj() );
+ }
+
+ return result;
+}
+
+
+string
+QtConst::getSpelling()
+{
+ char tempStr[20];
+ sprintf(tempStr, "%ud", (unsigned long)getNodeType());
+ string result = string(tempStr);
+ result.append( dataObj->getSpelling() );
+
+ return result;
+}
+
+
+QtNode::QtAreaType
+QtConst::getAreaType()
+{
+ if( dataObj && dataObj->getDataType() == QT_MDD )
+ return QT_AREA_MDD;
+ else
+ return QT_AREA_SCALAR;
+}
+
+
+void
+QtConst::optimizeLoad( QtTrimList* trimList )
+{
+ RMDBCLASS( "QtConst", "optimizeLoad( QtTrimList* )", "qlparser", __FILE__, __LINE__ )
+
+ if( trimList )
+ {
+ if( trimList->size() )
+ {
+ if( dataObj && dataObj->getDataType() == QT_MDD )
+ {
+ // get the highest specified dimension
+ r_Dimension maxDimension=0;
+ QtTrimList::iterator i;
+
+ for( i=trimList->begin(); i!=trimList->end(); i++ )
+ // get the maximum
+ maxDimension = maxDimension > (*i)->dimension ? maxDimension : (*i)->dimension;
+
+ // create a new loadDomain object and initialize it with open bounds
+ r_Minterval loadDomain(maxDimension+1);
+
+ // fill the loadDomain object with the QtTrimList specifications
+ for( i=trimList->begin(); i!=trimList->end(); i++ )
+ loadDomain[(*i)->dimension] = (*i)->interval;
+
+ ((QtMDD*)dataObj)->setLoadDomain( loadDomain );
+ }
+
+ // release( trimList->begin(), trimList->end() );
+ vector<QtNode::QtTrimElement*>::iterator iter;
+ for( iter=trimList->begin(); iter!=trimList->end(); iter++ )
+ {
+ delete *iter;
+ *iter=NULL;
+ }
+ }
+
+ delete trimList;
+ trimList=NULL;
+ }
+}
+
+
+QtData*
+QtConst::evaluate( QtDataList* /*inputList*/ )
+{
+ RMDBCLASS( "QtConst", "evaluate( QtDataList* )", "qlparser", __FILE__, __LINE__ )
+
+ QtData* returnValue = NULL;
+
+ if( dataObj )
+ {
+ dataObj->incRef();
+ returnValue = dataObj;
+ }
+
+ return returnValue;
+}
+
+
+
+void
+QtConst::printTree( int tab, ostream& s, QtChildType /*mode*/ )
+{
+ s << SPACE_STR(tab).c_str() << "QtConst Object: type " << flush;
+ dataStreamType.printStatus( s );
+ s << endl;
+
+ s << SPACE_STR(tab).c_str() << " ";
+
+ if( dataObj )
+ dataObj->printStatus( s );
+ else
+ s << "<no data object>";
+
+ s << endl;
+}
+
+
+
+void
+QtConst::printAlgebraicExpression( ostream& s )
+{
+ if( dataObj->isScalarData() )
+ {
+ QtScalarData* scalarDataObj = (QtScalarData*)dataObj;
+
+ if( scalarDataObj->getValueType() )
+ {
+ // Print the value but first cut leading blanks.
+ char valueString[1024];
+ // replaced deprecated ostrstream -- PB 2005-jan-14
+ // ostrstream valueStream( valueString, 1024 );
+ ostringstream valueStream( valueString );
+
+ scalarDataObj->getValueType()->printCell( valueStream, scalarDataObj->getValueBuffer() );
+
+ valueStream << ends;
+
+ char* p = valueString;
+ while( *p == ' ' ) p++;
+
+ s << p;
+ }
+ else
+ s << "<nn>";
+ }
+ else if( dataObj->getDataType() == QT_STRING )
+ {
+ s << ((QtStringData*)dataObj)->getStringData().c_str();
+ }
+ else
+ s << "<nn>";
+}
+
+
+
+const QtTypeElement&
+QtConst::checkType( QtTypeTuple* typeTuple )
+{
+ RMDBCLASS( "QtConst", "checkType( QtTypeTuple* )", "qlparser", __FILE__, __LINE__ )
+
+ dataStreamType.setDataType( QT_TYPE_UNKNOWN );
+
+ if( dataObj )
+ {
+ switch( dataObj->getDataType() )
+ {
+ case QT_STRING:
+ case QT_INTERVAL:
+ case QT_MINTERVAL:
+ case QT_POINT:
+ dataStreamType.setDataType( dataObj->getDataType() );
+ break;
+ case QT_MDD:
+ if( ((QtMDD*)dataObj)->getMDDObject() )
+ dataStreamType.setType((Type*)((QtMDD*)dataObj)->getMDDObject()->getMDDBaseType() );
+ break;
+ default:
+ dataStreamType.setType( ((QtScalarData*)dataObj)->getValueType() );
+ }
+ }
+
+ return dataStreamType;
+}
+
+
+
diff --git a/qlparser/qtconst.hh b/qlparser/qtconst.hh
new file mode 100644
index 0000000..6dce957
--- /dev/null
+++ b/qlparser/qtconst.hh
@@ -0,0 +1,117 @@
+#ifndef _QTCONST_
+#define _QTCONST_
+
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+#endif
+
+#include "qlparser/qtdata.hh"
+#include "qlparser/qtoperation.hh"
+#include <stdio.h>
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+ The class serves as a carrier for a {\tt QtData} object
+ and, additionally, provides functionality necessary in
+ the query tree.
+
+*/
+
+class QtConst : public QtOperation
+{
+ public:
+ /// constructor getting a pointer to the data object
+ QtConst( QtData* newDataObj );
+ /**
+ Lifetime of {\tt newDataObj} is managed by this class from now on.
+ */
+
+ /// virtual destructor
+ virtual ~QtConst();
+
+ /// test if the two nodes have an equal meaning in the query tree
+ virtual bool equalMeaning( QtNode* node );
+
+ /// creates a unique name for a common subexpression
+ virtual std::string getSpelling();
+
+ /// test if the edge to the parent node is of type mdd or atomic
+ virtual QtAreaType getAreaType();
+
+ /// optimizing load access
+ virtual void optimizeLoad( QtTrimList* trimList );
+
+ /// method for evaluating the node
+ QtData* evaluate( QtDataList* inputList );
+
+ /// prints the tree
+ virtual void printTree( int tab, std::ostream& s = std::cout, QtChildType mode = QT_ALL_NODES );
+
+ /// prints the algebraic expression
+ virtual void printAlgebraicExpression( std::ostream& s = std::cout );
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ //@Man: Operations of the ONC protocol:
+ //@{
+ ///
+ QtDataList* next();
+ //@}
+
+ //@Man: Read/Write methods:
+ //@{
+ ///
+ /// return the data object
+ inline QtData* getDataObj();
+ ///
+ //@}
+
+ /// type checking of the subtree
+ virtual const QtTypeElement& checkType( QtTypeTuple* typeTuple = NULL );
+
+ private:
+ /// pointer to the data object
+ QtData* dataObj;
+
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+#include "qlparser/qtconst.icc"
+
+#endif
+
diff --git a/qlparser/qtconst.icc b/qlparser/qtconst.icc
new file mode 100644
index 0000000..9d968d6
--- /dev/null
+++ b/qlparser/qtconst.icc
@@ -0,0 +1,43 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+inline const QtNode::QtNodeType
+QtConst::getNodeType() const
+{
+ return nodeType;
+}
+
+
+
+inline QtData*
+QtConst::getDataObj()
+{
+ return dataObj;
+}
+
diff --git a/qlparser/qtconversion.cc b/qlparser/qtconversion.cc
new file mode 100644
index 0000000..72d751f
--- /dev/null
+++ b/qlparser/qtconversion.cc
@@ -0,0 +1,590 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)qlparser, QtConversion: $Header: /home/rasdev/CVS-repository/rasdaman/qlparser/qtconversion.cc,v 1.36 2003/12/27 20:51:28 rasdev Exp $";
+
+#include "raslib/rmdebug.hh"
+#include "raslib/basetype.hh"
+#include "raslib/structuretype.hh"
+#include "conversion/convertor.hh"
+#include "conversion/convfactory.hh"
+
+#include "qlparser/qtconversion.hh"
+#include "qlparser/qtmdd.hh"
+
+#include "mddmgr/mddobj.hh"
+#include "tilemgr/tile.hh"
+
+#include "catalogmgr/typefactory.hh"
+#include "relcatalogif/typeiterator.hh"
+#include "relcatalogif/structtype.hh"
+#include "relcatalogif/chartype.hh"
+
+#include <iostream>
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+using namespace std;
+#endif
+
+const QtNode::QtNodeType QtConversion::nodeType = QtNode::QT_CONVERSION;
+
+
+QtConversion::QtConversion( QtOperation* newInput, QtConversionType
+newConversionType, const char* s )
+ : conversionType( newConversionType ), QtUnaryOperation( newInput ), paramStr(s)
+{
+ RMDBGONCE(2, RMDebug::module_qlparser, "QtConversion", "QtConversion()" )
+}
+
+void
+QtConversion::setConversionTypeByName( string formatName )
+{
+ if(string("bmp") == formatName)
+ conversionType = QtConversion::QT_TOBMP;
+ else if(string("hdf") == formatName )
+ conversionType = QtConversion::QT_TOHDF;
+ else if(string("png") == formatName)
+ conversionType = QtConversion::QT_TOPNG;
+ else if (string("jpeg") == formatName)
+ conversionType = QtConversion::QT_TOJPEG;
+ else if (string("tiff") == formatName)
+ conversionType = QtConversion::QT_TOTIFF;
+ else if (string("vff") == formatName)
+ conversionType = QtConversion::QT_TOVFF;
+ else if (string("csv") == formatName)
+ conversionType = QtConversion::QT_TOCSV;
+ else if (string("tor") == formatName)
+ conversionType = QtConversion::QT_TOTOR;
+ else if (string("dem") == formatName)
+ conversionType = QtConversion::QT_TODEM;
+ else if(string("inv_bmp") == formatName )
+ conversionType = QtConversion::QT_FROMBMP;
+ else if(string("inv_hdf") == formatName )
+ conversionType = QtConversion::QT_FROMHDF;
+ else if(string("inv_csv") == formatName )
+ conversionType = QtConversion::QT_FROMCSV;
+ else if(string("inv_png") == formatName)
+ conversionType = QtConversion::QT_FROMPNG;
+ else if (string("inv_jpeg") == formatName)
+ conversionType = QtConversion::QT_FROMJPEG;
+ else if (string("inv_tiff") == formatName)
+ conversionType = QtConversion::QT_FROMTIFF;
+ else if (string("inv_vff") == formatName)
+ conversionType = QtConversion::QT_FROMVFF;
+ else if (string("inv_tor") == formatName)
+ conversionType = QtConversion::QT_FROMTOR;
+ else if (string("inv_dem") == formatName)
+ conversionType = QtConversion::QT_FROMDEM;
+ else
+ conversionType = QtConversion::QT_UNKNOWN;
+}
+
+bool
+QtConversion::lookupConversionTypeByName( string formatName )
+{
+ return (( string("bmp") == formatName ) || ( string("hdf") == formatName ) ||
+ ( string("png") == formatName ) || ( string("jpeg") == formatName ) ||
+ ( string("dem") == formatName ) || ( string("tor") == formatName ) ||
+ ( string("csv") == formatName ) || ( string("inv_csv") == formatName ) ||
+ ( string("tiff") == formatName ) || ( string("vff") == formatName ) ||
+ ( string("inv_bmp") == formatName ) || ( string("inv_hdf") == formatName ) ||
+ ( string("inv_png") == formatName ) || ( string("inv_jpeg") == formatName ) ||
+ ( string("inv_dem") == formatName ) || ( string("inv_tor") == formatName ) ||
+ ( string("inv_tiff") == formatName ) || ( string("inv_vff") == formatName ));
+
+}
+
+bool
+QtConversion::equalMeaning( QtNode* node )
+{
+
+ bool result = false;
+
+ if( nodeType == node->getNodeType() )
+ {
+ QtConversion* convNode;
+ convNode = (QtConversion*) node; // by force
+
+ result = input->equalMeaning( convNode->getInput() );
+
+ result &= conversionType == convNode->conversionType;
+ };
+
+ return ( result );
+}
+
+
+QtData*
+QtConversion::evaluate( QtDataList* inputList )
+{
+ RMDBCLASS( "QtConversion", "evaluate( QtDataList* )", "qlparser", __FILE__, __LINE__ )
+
+ QtData* returnValue = NULL;
+ QtData* operand = NULL;
+
+ if( conversionType == QT_UNKNOWN )
+ {
+ RMInit::logOut << "Error: QtConversion::evaluate() - unknown conversion format." << std::endl;
+ parseInfo.setErrorNo(382);
+ throw parseInfo;
+ }
+
+ operand = input->evaluate( inputList );
+
+ if( operand )
+ {
+#ifdef QT_RUNTIME_TYPE_CHECK
+ if( operand->getDataType() != QT_MDD )
+ {
+ RMInit::logOut << "Internal error in QtConversion::evaluate() - "
+ << "runtime type checking failed (MDD)." << std::endl;
+
+ // delete old operand
+ if( operand ) operand->deleteRef();
+ return 0;
+ }
+#endif
+
+ QtMDD* qtMDD = (QtMDD*) operand;
+ MDDObj* currentMDDObj = qtMDD->getMDDObject();
+ Tile* sourceTile = NULL;
+ vector< Tile* >* tiles = NULL;
+ if (qtMDD->getLoadDomain().is_origin_fixed() && qtMDD->getLoadDomain().is_high_fixed())
+ {
+ // get relevant tiles
+ tiles = currentMDDObj->intersect( qtMDD->getLoadDomain() );
+ }
+ else {
+ RMDBGONCE(2, RMDebug::module_qlparser, "QtConversion", "evalutate() - no tile available to convert." )
+ return operand;
+ }
+
+ // check the number of tiles
+ if( !tiles->size() )
+ {
+ RMDBGONCE(2, RMDebug::module_qlparser, "QtConversion", "evalutate() - no tile available to convert." )
+ return operand;
+ }
+
+ // create one single tile with the load domain
+ sourceTile = new Tile( tiles, qtMDD->getLoadDomain() );
+
+ // delete the tile vector
+ delete tiles;
+ tiles = NULL;
+
+ // get type structure of the operand base type
+ char* typeStructure = qtMDD->getCellType()->getTypeStructure();
+
+ // convert structure to r_Type
+ r_Type* baseSchema = r_Type::get_any_type( typeStructure );
+
+ free( typeStructure );
+ typeStructure = NULL;
+ RMDBGONCE(2, RMDebug::module_qlparser, "QtConversion", "evalutate() - no tile available to convert." )
+ RMDBGIF(2, RMDebug::module_qlparser, "QtConversion", \
+ RMInit::dbgOut << "Cell base type for conversion: " << std::flush; \
+ baseSchema->print_status( RMInit::dbgOut ); \
+ RMInit::dbgOut << std::endl; )
+
+ //
+ // real conversion
+ //
+
+ r_convDesc convResult;
+ r_Minterval tileDomain = sourceTile->getDomain();
+
+ //convertor type
+ r_Data_Format convType = r_Array;
+ //result type from convertor
+ r_Data_Format convFormat = r_Array;
+
+ switch (conversionType)
+ {
+ case QT_TOTIFF:
+ convType = r_TIFF;
+ convFormat = r_TIFF;
+ break;
+ case QT_FROMTIFF:
+ convType = r_TIFF;
+ convFormat = r_Array;
+ break;
+ case QT_TOBMP:
+ convType = r_BMP;
+ convFormat = r_BMP;
+ break;
+ case QT_FROMBMP:
+ convType = r_BMP;
+ convFormat = r_Array;
+ break;
+ case QT_TOHDF:
+ convType = r_HDF;
+ convFormat = r_HDF;
+ break;
+ case QT_TOCSV:
+ convType = r_CSV;
+ convFormat = r_CSV;
+ break;
+ case QT_FROMHDF:
+ convType = r_HDF;
+ convFormat = r_Array;
+ break;
+ case QT_FROMCSV:
+ convType = r_CSV;
+ convFormat = r_Array;
+ break;
+ case QT_TOJPEG:
+ convType = r_JPEG;
+ convFormat = r_JPEG;
+ break;
+ case QT_FROMJPEG:
+ convType = r_JPEG;
+ convFormat = r_Array;
+ break;
+ case QT_TOPNG:
+ convType = r_PNG;
+ convFormat = r_PNG;
+ break;
+ case QT_FROMPNG:
+ convType = r_PNG;
+ convFormat = r_Array;
+ break;
+ case QT_TOVFF:
+ convType = r_VFF;
+ convFormat = r_VFF;
+ break;
+ case QT_FROMVFF:
+ convType = r_VFF;
+ convFormat = r_Array;
+ break;
+ case QT_TOTOR:
+ convType = r_TOR;
+ convFormat = r_TOR;
+ break;
+ case QT_FROMTOR:
+ convType = r_TOR;
+ convFormat = r_Array;
+ break;
+ case QT_TODEM:
+ convType = r_DEM;
+ convFormat = r_DEM;
+ break;
+ case QT_FROMDEM:
+ convType = r_DEM;
+ convFormat = r_Array;
+ break;
+ default:
+ RMInit::logOut << "Error: QtConversion::evaluate(): unsupported format " << conversionType << std::endl;
+ throw r_Error(CONVERSIONFORMATNOTSUPPORTED);
+ break;
+ }
+ convFormat = r_Array;
+
+ r_Convertor *convertor = NULL;
+
+ try {
+ convertor = r_Convertor_Factory::create(convType, sourceTile->getContents(), tileDomain, baseSchema);
+ if(conversionType < QT_FROMTIFF) {
+ RMDBGONCE(2, RMDebug::module_qlparser, "QtConversion", "evalutate() - convertor " << convType << " converting to " << convFormat << "...");
+ convResult = convertor->convertTo(paramStr);
+ }
+ else {
+ RMDBGONCE(2, RMDebug::module_qlparser, "QtConversion", "evalutate() - convertor " << convType << " converting from " << convFormat << "...");
+ convResult = convertor->convertFrom(paramStr);
+ }
+ }
+ catch (r_Error &err) {
+ RMInit::logOut << "Error: QtConversion::evaluate(): conversion failed" << std::endl;
+ delete sourceTile;
+ sourceTile = NULL;
+ delete baseSchema;
+ baseSchema = NULL;
+ // delete old operand
+ if( operand ) operand->deleteRef();
+ if (convertor != NULL) {
+ delete convertor;
+ convertor=NULL;
+ }
+
+ parseInfo.setErrorNo(381);
+ throw parseInfo;
+ }
+ if (convertor != NULL) {
+ delete convertor;
+ convertor=NULL;
+ }
+
+ RMDBGMIDDLE(2, RMDebug::module_qlparser, "QtConversion", "evalutate() - ok")
+
+
+ //
+ // done
+ //
+
+ // delete sourceTile
+ delete sourceTile;
+ sourceTile = NULL;
+
+ // create a transient tile for the compressed data
+ const BaseType* myType = NULL;
+ const r_Type* currStruct = NULL;
+ if(convResult.destType->isPrimitiveType()) {
+ myType=TypeFactory::mapType(convResult.destType->name());
+ if(myType == NULL) {
+ RMInit::logOut << "Error: QtConversion::evaluate() no primitive type compatible found" << std::endl;
+ delete convResult.destType;
+ convResult.destType=NULL;
+ delete convResult.dest;
+ convResult.dest=NULL;
+ throw r_Error(BASETYPENOTSUPPORTED);
+ }
+
+ if(strcasecmp( dataStreamType.getType()->getTypeName(), myType->getTypeName())) {
+ //FIXME here we have to change the dataStreamType.getType(), is not char for
+ //conversion from_DEF all the time, we don't know the result type until we parse the data
+ MDDBaseType* mddBaseType = new MDDBaseType( "tmp", TypeFactory::mapType(myType->getTypeName()) );
+ TypeFactory::addTempType( mddBaseType );
+
+ dataStreamType.setType( mddBaseType );
+ RMInit::logOut << " QtConversion::evaluate() for conversion " << conversionType << " real result is " << std::flush;
+ dataStreamType.printStatus(RMInit::logOut);
+ RMInit::logOut << std::endl;
+ }
+ }
+ else { //we assume that we deal with structure types
+ TypeIterator<StructType> structIter = TypeFactory::createStructIter();
+ while(structIter.not_done()) {
+ // get type structure of current structtype
+ typeStructure = structIter.get_element()->getTypeStructure();
+ // convert structure to r_Type
+ currStruct = r_Type::get_any_type( typeStructure );
+
+ if(currStruct == NULL) {
+ RMInit::logOut << "Error: QtConversion::evaluate() no structure type compatible found" << std::endl;
+ delete convResult.destType;
+ convResult.destType=NULL;
+ delete convResult.dest;
+ convResult.dest=NULL;
+ throw r_Error(STRUCTTYPE_ELEMENT_UNKNOWN);
+ }
+
+ free(typeStructure);
+ typeStructure = NULL;
+
+ if(((r_Structure_Type*)currStruct)->compatibleWith((r_Structure_Type*)convResult.destType)) {
+ //we found a type
+ delete currStruct;
+ currStruct = NULL;
+ myType=structIter.get_element().ptr();
+ break;
+ }
+
+ delete currStruct;
+ currStruct = NULL;
+ structIter.advance();
+ }
+ if(myType == NULL) {
+ RMInit::logOut << "Error: QtConversion::evaluate() no structure type compatible found" << std::endl;
+ delete convResult.destType;
+ convResult.destType=NULL;
+ delete convResult.dest;
+ convResult.dest=NULL;
+ throw r_Error(STRUCTTYPE_ELEMENT_UNKNOWN);
+ }
+
+ if(strcasecmp(dataStreamType.getType()->getTypeName(), myType->getTypeName())) {
+ //FIXME here we have to change the dataStreamType.getType(), is not char for
+ //conversion from_DEF all the time, we don't know the result type until we parse the data
+ MDDBaseType* mddBaseType = new MDDBaseType( "tmp", TypeFactory::mapType(myType->getTypeName()) );
+ TypeFactory::addTempType( mddBaseType );
+
+ dataStreamType.setType( mddBaseType );
+ RMInit::logOut << " QtConversion::evaluate() for conversion " << conversionType << " real result is " << std::flush;
+ dataStreamType.printStatus(RMInit::logOut);
+ RMInit::logOut << std::endl;
+ }
+ }
+
+ Tile* resultTile = new Tile( convResult.destInterv,
+ myType,
+ convResult.dest,
+ 0,
+ convFormat );
+
+ // delete destination type
+ if( convResult.destType ) {
+ delete convResult.destType;
+ convResult.destType=NULL;
+ }
+
+ // create a transient MDD object for the query result
+ MDDBaseType* mddBaseType = (MDDBaseType*)dataStreamType.getType();
+ MDDObj* resultMDD = new MDDObj( mddBaseType, convResult.destInterv );
+ resultMDD->insertTile( resultTile );
+
+ // create a new QtMDD object as carrier object for the transient MDD object
+ returnValue = new QtMDD( (MDDObj*)resultMDD );
+
+ // delete base type schema
+ delete baseSchema;
+ baseSchema = NULL;
+
+ // delete old operand
+ if( operand ) operand->deleteRef();
+ }
+ else
+ RMInit::logOut << "Error: QtConversion::evaluate() - operand is not provided." << std::endl;
+
+ return returnValue;
+}
+
+
+void
+QtConversion::printTree( int tab, ostream& s, QtChildType mode )
+{
+ s << SPACE_STR(tab).c_str() << "QtConversion Object: ";
+
+ switch( conversionType )
+ {
+ case QT_TOTIFF: s << "to TIFF"; break;
+ case QT_TOBMP: s << "to BMP"; break;
+ case QT_TOHDF: s << "to HDF"; break;
+ case QT_TOCSV: s << "to CSV"; break;
+ case QT_TOJPEG: s << "to JPEG"; break;
+ case QT_TOPNG: s << "to PNG"; break;
+ case QT_TOVFF: s << "to VFF"; break;
+ case QT_TOTOR: s << "to TOR"; break;
+ case QT_TODEM: s << "to DEM"; break;
+ case QT_FROMTIFF: s << "from TIFF"; break;
+ case QT_FROMBMP: s << "from BMP"; break;
+ case QT_FROMHDF: s << "from HDF"; break;
+ case QT_FROMCSV: s << "from CSV"; break;
+ case QT_FROMJPEG: s << "from JPEG"; break;
+ case QT_FROMPNG: s << "from PNG"; break;
+ case QT_FROMVFF: s << "from VFF"; break;
+ case QT_FROMTOR: s << "from TOR"; break;
+ case QT_FROMDEM: s << "from DEM"; break;
+ default: s << "unknown conversion"; break;
+ }
+
+ s << std::endl;
+
+ QtUnaryOperation::printTree( tab, s, mode );
+}
+
+
+
+void
+QtConversion::printAlgebraicExpression( ostream& s )
+{
+ s << conversionType << "(";
+
+ if( input )
+ input->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << ")";
+}
+
+
+
+const QtTypeElement&
+QtConversion::checkType( QtTypeTuple* typeTuple )
+{
+ RMDBCLASS( "QtConversion", "checkType( QtTypeTuple* )", "qlparser", __FILE__, __LINE__ )
+
+ dataStreamType.setDataType( QT_TYPE_UNKNOWN );
+
+ // check operand branches
+ if( input )
+ {
+
+ // get input type
+ const QtTypeElement& inputType = input->checkType( typeTuple );
+
+ if( inputType.getDataType() != QT_MDD )
+ {
+ RMInit::logOut << "Error: QtConversion::checkType() - operand is not of type MDD." << std::endl;
+ parseInfo.setErrorNo(380);
+ throw parseInfo;
+ }
+
+ //FIXME we set for every kind of conversion the result type char
+ //for conversion from_DEF we don't know the result type until we parse the data
+ MDDBaseType* mddBaseType = new MDDBaseType( "Char", TypeFactory::mapType("Char") );
+ TypeFactory::addTempType( mddBaseType );
+
+ dataStreamType.setType( mddBaseType );
+
+ if(conversionType>QT_TODEM) {
+ RMInit::logOut << std::endl << "QtConversion::checkType() for conversion " << conversionType << " assume the result " << std::flush;
+ dataStreamType.printStatus(RMInit::logOut);
+ RMInit::logOut << std::endl;
+ }
+ }
+ else
+ RMInit::logOut << "Error: QtConversion::checkType() - operand branch invalid." << std::endl;
+
+ return dataStreamType;
+}
+
+std::ostream&
+operator<< (std::ostream& os, QtConversion::QtConversionType type) {
+ switch( type )
+ {
+ case QtConversion::QT_TOTIFF: os << "tiff"; break;
+ case QtConversion::QT_TOBMP: os << "bmp"; break;
+ case QtConversion::QT_TOHDF: os << "hdf"; break;
+ case QtConversion::QT_TOCSV: os << "csv"; break;
+ case QtConversion::QT_TOJPEG: os << "jpeg"; break;
+ case QtConversion::QT_TOPNG: os << "png"; break;
+ case QtConversion::QT_TOVFF: os << "vff"; break;
+ case QtConversion::QT_TOTOR: os << "tor"; break;
+ case QtConversion::QT_TODEM: os << "dem"; break;
+ case QtConversion::QT_FROMTIFF: os << "inv_tiff"; break;
+ case QtConversion::QT_FROMBMP: os << "inv_bmp"; break;
+ case QtConversion::QT_FROMHDF: os << "inv_hdf"; break;
+ case QtConversion::QT_FROMCSV: os << "inv_csv"; break;
+ case QtConversion::QT_FROMJPEG: os << "inv_jpeg"; break;
+ case QtConversion::QT_FROMPNG: os << "inv_png"; break;
+ case QtConversion::QT_FROMVFF: os << "inv_vff"; break;
+ case QtConversion::QT_FROMTOR: os << "inv_tor"; break;
+ case QtConversion::QT_FROMDEM: os << "inv_dem"; break;
+ default: os << "unknown Conversion"; break;
+ }
+
+ return os;
+}
+
diff --git a/qlparser/qtconversion.hh b/qlparser/qtconversion.hh
new file mode 100644
index 0000000..6bb44bc
--- /dev/null
+++ b/qlparser/qtconversion.hh
@@ -0,0 +1,113 @@
+#ifndef _QTCONVERSION_HH__
+#define _QTCONVERSION_HH___
+
+#include "qlparser/qtunaryoperation.hh"
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+ The class represents a format conversion. The conversion is described by
+ an enumerator.
+
+*/
+
+class QtConversion : public QtUnaryOperation
+{
+ public:
+ enum QtConversionType
+ {
+ QT_UNKNOWN,
+ QT_TOTIFF,
+ QT_TOBMP,
+ QT_TOHDF,
+ QT_TOCSV,
+ QT_TOJPEG,
+ QT_TOPNG,
+ QT_TOVFF,
+ QT_TOTOR,
+ QT_TODEM,
+ QT_FROMTIFF,
+ QT_FROMBMP,
+ QT_FROMHDF,
+ QT_FROMCSV,
+ QT_FROMJPEG,
+ QT_FROMPNG,
+ QT_FROMVFF,
+ QT_FROMTOR,
+ QT_FROMDEM
+ };
+
+ /// constructor getting operand and format conversion type
+ QtConversion( QtOperation* newInput, QtConversionType newConversionType, const char* = NULL );
+
+ /// set the format conversion type by name
+ void setConversionTypeByName( std::string formatName );
+
+ /// look up the format conversion type by name
+ static bool lookupConversionTypeByName( std::string formatName );
+
+ /// test if the two nodes have an equal meaning in a subtree
+ virtual bool equalMeaning( QtNode* node );
+
+ /// evaluates the node
+ QtData* evaluate( QtDataList* inputList );
+
+ /// prints the tree
+ virtual void printTree( int tab, std::ostream& s = std::cout, QtChildType mode = QT_ALL_NODES );
+
+ /// prints the algebraic expression
+ virtual void printAlgebraicExpression( std::ostream& s = std::cout );
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ /// type checking of the subtree
+ virtual const QtTypeElement& checkType( QtTypeTuple* typeTuple = NULL );
+
+ private:
+ /// attribute storing conversion type
+ QtConversionType conversionType;
+
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+
+ const char* paramStr;
+};
+
+extern std::ostream& operator<<(std::ostream& os, QtConversion::QtConversionType t);
+
+#include "qlparser/qtconversion.icc"
+
+#endif
+
diff --git a/qlparser/qtconversion.icc b/qlparser/qtconversion.icc
new file mode 100644
index 0000000..410e34e
--- /dev/null
+++ b/qlparser/qtconversion.icc
@@ -0,0 +1,35 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+
+inline const QtNode::QtNodeType
+QtConversion::getNodeType() const
+{
+ return nodeType;
+}
diff --git a/qlparser/qtdata.cc b/qlparser/qtdata.cc
new file mode 100644
index 0000000..1ef0735
--- /dev/null
+++ b/qlparser/qtdata.cc
@@ -0,0 +1,127 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)qlparser, QtData: $Id: qtdata.cc,v 1.17 2002/06/05 18:18:17 coman Exp $";
+
+#include "raslib/rmdebug.hh"
+#include "qlparser/qtdata.hh"
+
+
+QtData::QtData()
+ : referenceCounter(1),
+ persistent( QT_TRANSIENT ),
+ parseInfo(NULL)
+{
+ RMDBGONCE( 10, RMDebug::module_qlparser, "QtData", "QtData::QtData() Obj: " << this )
+}
+
+
+
+QtData::QtData( const std::string name )
+ : iteratorName( name ),
+ referenceCounter(1),
+ persistent( QT_TRANSIENT ),
+ parseInfo(NULL)
+{
+ RMDBGONCE( 10, RMDebug::module_qlparser, "QtData", "QtData::QtData( const std::string ) Obj: " << this )
+}
+
+
+
+QtData::QtData( const QtData &obj )
+ : iteratorName( obj.iteratorName ),
+ persistent( obj.persistent ),
+ referenceCounter(1),
+ parseInfo(NULL)
+{
+ RMDBGONCE( 10, RMDebug::module_qlparser, "QtData", "QtData::QtData( QtData& ) Obj: " << this )
+
+ if( obj.parseInfo )
+ parseInfo = new ParseInfo( *(obj.parseInfo) );
+}
+
+
+
+QtData::~QtData()
+{
+ RMDBGONCE( 10, RMDebug::module_qlparser, "QtData", "QtData::~QtData() Obj: " << this )
+
+ if( parseInfo )
+ {
+ delete parseInfo;
+ parseInfo=NULL;
+ }
+}
+
+
+
+bool
+QtData::isScalarData() const
+{
+ // default implementation returns false
+ return false;
+}
+
+
+
+const QtData&
+QtData::operator=( const QtData& obj )
+{
+ RMDBGONCE( 10, RMDebug::module_qlparser, "QtData", "QtData::operator=" )
+
+ if( this != &obj )
+ {
+ iteratorName = obj.iteratorName;
+ persistent = obj.persistent;
+ referenceCounter = 1;
+
+ if( parseInfo )
+ {
+ delete parseInfo;
+ parseInfo = NULL;
+ }
+
+ if( obj.parseInfo )
+ parseInfo = new ParseInfo( *(obj.parseInfo) );
+ }
+
+ return *this;
+}
+
+
+
+void
+QtData::printStatus( std::ostream& stream ) const
+{
+ if( iteratorName.size() )
+ stream << ", iter name: " << iteratorName.c_str() << std::flush;
+
+ stream << ", ref#: " << referenceCounter
+ << ( persistent == QT_TRANSIENT ? " trans " : " pers " ) << std::flush;
+}
diff --git a/qlparser/qtdata.hh b/qlparser/qtdata.hh
new file mode 100644
index 0000000..ee2e285
--- /dev/null
+++ b/qlparser/qtdata.hh
@@ -0,0 +1,200 @@
+#ifndef _QTDATA_
+#define _QTDATA_
+
+#include <iostream>
+
+#include "qlparser/parseinfo.hh"
+#include "raslib/rminit.hh"
+
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+#endif
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+//@Man: TypeEnum
+//@Type: typedef
+//@Memo: Module: {\bf qlparser}.
+
+enum QtDataType
+{
+ QT_TYPE_UNKNOWN,
+ QT_BOOL,
+ QT_CHAR,
+ QT_OCTET,
+ QT_USHORT,
+ QT_SHORT,
+ QT_ULONG,
+ QT_LONG,
+ QT_FLOAT,
+ QT_DOUBLE,
+ QT_COMPLEXTYPE1, // with float members
+ QT_COMPLEXTYPE2, // with double
+ QT_MDD,
+ QT_COMPLEX,
+ QT_STRING,
+ QT_INTERVAL,
+ QT_MINTERVAL,
+ QT_POINT
+};
+
+
+
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+This class is superclass for the classes representing a
+specific data type handled by the query tree.
+
+*/
+
+class QtData
+{
+ public:
+ // construktor
+ QtData();
+
+ // constructor
+ QtData( const std::string name );
+
+ /// copy constructor
+ QtData( const QtData &obj );
+
+ /// destructor
+ virtual ~QtData();
+
+ /// assignement operator
+ const QtData& operator=( const QtData& obj );
+
+ enum QtLifetime
+ {
+ QT_PERSISTENT,
+ QT_TRANSIENT
+ };
+
+ /// returns type of data represented by the QtData object
+ virtual QtDataType getDataType() const = 0;
+ /**
+ \begin{tabular}{lll}
+ QtMDD&&QT_MDD\\
+ QtAtomicData&&QT_BOOL\\
+ &&QT_CHAR\\
+ &&QT_OCTET\\
+ &&QT_USHORT\\
+ &&QT_SHORT\\
+ &&QT_ULONG\\
+ &&QT_FLOAT\\
+ &&QT_DOUBLE\\
+ QtComplexData&&QT_COMPLEX\\
+ QtString&&QT_STRING\\
+ QtInterval&&QT_INTERVAL\\
+ QtMinterval&&QT_MINTERVAL\\
+ QtPoint&&QT_POINT\\
+ \end{tabular}
+ */
+
+ /// returns a null-terminated string describing the type structure
+ virtual char* getTypeStructure() const = 0;
+ /**
+ The string pointer has to be free using free() by the caller.
+ */
+
+ /// determines, if the data is of type scalar
+ virtual bool isScalarData() const;
+
+ /// compares data content
+ virtual bool equal( const QtData* obj ) const = 0;
+
+ /// returns content dependent string representation
+ virtual std::string getSpelling() const = 0;
+
+ //@Man: Read/Write methods:
+ //@{
+ ///
+
+ /// get the iterator name
+ inline std::string const getIteratorName() const;
+ ///
+ inline void setIteratorName( const std::string & iteratorNameNew );
+ ///
+ inline QtLifetime const getLifetime() const;
+ ///
+ inline void setLifetime( QtLifetime flag );
+ /// return number of references to the self object
+ inline unsigned int getRefNo() const;
+ /// increases the reference counter by one
+ inline void incRef();
+ /// deletes one reference and the object if it was the last one
+ inline int deleteRef();
+ /**
+ In case the object is deleted, 1 is returned, 0 otherwise.
+ */
+
+ ///
+ inline ParseInfo getParseInfo();
+ ///
+ inline void setParseInfo( const ParseInfo &info );
+
+ ///
+ //@}
+
+ /// print status of the object to the specified stream
+ virtual void printStatus( std::ostream& stream = std::cout ) const;
+
+ protected:
+ /// pointer to an optional parser info
+ ParseInfo* parseInfo;
+
+ private:
+ /// decreases the reference counter by one and returns the new value
+ inline unsigned int decRef();
+
+ /// attribute storing the iterator name
+ std::string iteratorName;
+
+ /// attribute storing the lifetime (persistent, transient)
+ QtLifetime persistent;
+ /**
+ Objects of subclasses of QtScalarData (QtAtomicData and QtComplexdata) are always transient.
+ Objects of subclass QtMDD are persistent or transient.
+ */
+
+ /// counts the number of references to the data object
+ unsigned int referenceCounter;
+};
+
+#include "qlparser/qtdata.icc"
+
+#endif
+
diff --git a/qlparser/qtdata.icc b/qlparser/qtdata.icc
new file mode 100644
index 0000000..677559e
--- /dev/null
+++ b/qlparser/qtdata.icc
@@ -0,0 +1,137 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+inline void
+QtData::setIteratorName( const std::string &iteratorNameNew )
+{
+ iteratorName = iteratorNameNew;
+}
+
+
+inline const std::string
+QtData::getIteratorName() const
+{
+ return iteratorName;
+}
+
+
+inline const QtData::QtLifetime
+QtData::getLifetime() const
+{
+ return persistent;
+}
+
+
+inline void
+QtData::setLifetime( QtLifetime flag)
+{
+ persistent = flag;
+}
+
+
+
+inline unsigned int
+QtData::getRefNo() const
+{
+ return referenceCounter;
+}
+
+
+
+inline ParseInfo
+QtData::getParseInfo()
+{
+ if( parseInfo )
+ return *parseInfo;
+ else
+ return ParseInfo();
+}
+
+
+inline void
+QtData::setParseInfo( const ParseInfo &info )
+{
+ if( parseInfo )
+ *parseInfo = info;
+ else
+ parseInfo = new ParseInfo( info );
+}
+
+
+
+inline
+int
+QtData::deleteRef()
+{
+ int objDeleted = 0;
+
+#if 0
+ if (parseInfo==NULL)
+ {
+ // RMInit::logOut << "QtData::deleteRef() - error: null parseinfo, resetting before doing delete." << endl;
+ parseInfo = new ParseInfo();
+ }
+#endif
+
+ if( !decRef() )
+ {
+ objDeleted = 1;
+ delete this;
+ }
+
+ return objDeleted;
+}
+
+
+
+inline
+unsigned int
+QtData::decRef()
+{
+ if( referenceCounter > 0 )
+ referenceCounter--;
+ else
+ RMInit::logOut << "Internal Error: QtData::decRef() - decrease of a zero reference counter" << endl;
+
+ return referenceCounter;
+}
+
+
+
+inline
+void
+QtData::incRef()
+{
+ referenceCounter++;
+}
+
+
+
+
+
diff --git a/qlparser/qtdelete.cc b/qlparser/qtdelete.cc
new file mode 100644
index 0000000..0b09179
--- /dev/null
+++ b/qlparser/qtdelete.cc
@@ -0,0 +1,268 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)qlparser, QtDelete: $Header: /home/rasdev/CVS-repository/rasdaman/qlparser/qtdelete.cc,v 1.14 2003/12/27 20:51:28 rasdev Exp $";
+
+#include "qlparser/qtdelete.hh"
+#include "qlparser/qtdata.hh"
+#include "qlparser/qtmdd.hh"
+#include "qlparser/qtmddaccess.hh"
+#include "mddmgr/mddobj.hh"
+#include "mddmgr/mddcoll.hh"
+
+#include <iostream>
+
+
+
+const QtNode::QtNodeType QtDelete::nodeType = QtNode::QT_DELETE;
+
+
+
+QtDelete::QtDelete()
+ : QtExecute(), input(NULL)
+{
+}
+
+
+
+QtDelete::~QtDelete()
+{
+ if( input )
+ {
+ delete input;
+ input=NULL;
+ }
+}
+
+
+
+int
+QtDelete::evaluate()
+{
+ RMDBCLASS( "QtDelete", "evaluate()", "qlparser", __FILE__, __LINE__ )
+
+ QtNode::QtDataList* nextTupel=NULL;
+
+ // open input stream
+ try
+ {
+ input->open();
+ }
+ catch( ... )
+ {
+ input->close();
+ throw;
+ }
+
+ try
+ {
+ while( (nextTupel = input->next()) )
+ {
+ QtData* target = (*nextTupel)[0];
+
+ // check delete target
+ if( target->getDataType() != QT_MDD )
+ {
+ RMInit::logOut << "Error: QtDelete::evaluate() - delete target must be an expression resulting in an r_Marray<>" << std::endl;
+
+ // delete tupel vector received by next()
+ vector<QtData*>::iterator dataIter;
+ for( dataIter=nextTupel->begin(); dataIter!=nextTupel->end(); dataIter++ )
+ if( *dataIter ) (*dataIter)->deleteRef();
+ delete nextTupel;
+ nextTupel=NULL;
+
+ parseInfo.setErrorNo(951);
+ throw parseInfo;
+ }
+
+ QtMDD* targetMDD = (QtMDD*) target;
+ MDDObj* targetObj = targetMDD->getMDDObject();
+
+ // get leaf of ONC input
+ QtNodeList* leafList = input->getChilds( QtNode::QT_LEAF_NODES );
+ QtMDDAccess* inputLeaf = NULL;
+ // take the last QtMDDAccess object from the list assuming that it is the right one
+ for( std::list<QtNode*>::iterator iter=leafList->begin(); iter!=leafList->end(); iter++ )
+ if( (*iter)->getNodeType() == QT_MDD_ACCESS )
+ inputLeaf = (QtMDDAccess*)*iter;
+ delete leafList;
+ leafList=NULL;
+
+ // delete the MDD object
+ if( inputLeaf )
+ {
+ inputLeaf->getMDDColl()->remove( targetObj );
+ RMInit::logOut << "deleted..." << std::flush;
+ }
+
+ if(targetMDD && targetObj && !targetObj->isPersistent());
+ targetMDD->setLifetime( QtData::QT_TRANSIENT );
+
+ // delete tupel vector received by next()
+ vector<QtData*>::iterator dataIter;
+ for( dataIter=nextTupel->begin(); dataIter!=nextTupel->end(); dataIter++ )
+ if( *dataIter ) (*dataIter)->deleteRef();
+ delete nextTupel;
+ nextTupel=NULL;
+ } // while
+
+ }
+ catch( ... )
+ {
+ input->close();
+ throw;
+ }
+
+ input->close();
+
+ return 0;
+}
+
+
+
+QtNode::QtNodeList*
+QtDelete::getChilds( QtChildType flag )
+{
+ QtNodeList* resultList=NULL;
+
+ if( input )
+ {
+ // allocate resultList
+ if( flag == QT_DIRECT_CHILDS );
+ resultList = new QtNodeList();
+
+ if( flag == QT_LEAF_NODES || flag == QT_ALL_NODES )
+ resultList = input->getChilds( flag );
+
+ // add the nodes of the current level
+ if( flag == QT_DIRECT_CHILDS || flag == QT_ALL_NODES )
+ resultList->push_back( input );
+ }
+ else
+ resultList = new QtNodeList();
+
+ return resultList;
+}
+
+
+
+void
+QtDelete::printTree( int tab, std::ostream& s, QtChildType mode )
+{
+ s << SPACE_STR(tab).c_str() << "QtDelete Object" << std::endl;
+
+ if( mode != QtNode::QT_DIRECT_CHILDS )
+ {
+ if( input )
+ {
+ s << SPACE_STR(tab).c_str() << "input: " << std::endl;
+ input->printTree( tab+2, s, mode );
+ }
+ else
+ s << SPACE_STR(tab).c_str() << "no input" << std::endl;
+
+ s << std::endl;
+ }
+}
+
+
+
+void
+QtDelete::printAlgebraicExpression( std::ostream& s )
+{
+ s << "delete";
+
+ if( input )
+ {
+ s << "( ";
+ input->printAlgebraicExpression( s );
+ s << " )";
+ }
+ else
+ s << "(<no input>)";
+}
+
+
+
+void
+QtDelete::setStreamInput( QtONCStream* newInput )
+{
+ input = newInput;
+ input->setParent( this );
+};
+
+QtONCStream::QtONCStream*
+QtDelete::getStreamInput()
+{
+ return input;
+}
+
+
+/*
+void
+QtDelete::preOptimize()
+{
+ if( input )
+ input->preOptimize();
+}
+*/
+
+
+void
+QtDelete::checkType()
+{
+ RMDBCLASS( "QtDelete", "checkType()", "qlparser", __FILE__, __LINE__ )
+
+ // check operand branches
+ if( input )
+ {
+
+ // get input type
+ QtTypeTuple inputType = input->checkType();
+
+ if( inputType.tuple[0].getDataType() != QT_MDD )
+ {
+ RMInit::logOut << "Error: QtDelete::checkType() - delete target must be an expression resulting in an r_Marray<>" << std::endl;
+ parseInfo.setErrorNo(951);
+ throw parseInfo;
+ }
+ }
+ else
+ RMInit::logOut << "Error: QtDelete::checkType() - operand branch invalid." << std::endl;
+
+}
+
+
+
+
+
+
+
+
diff --git a/qlparser/qtdelete.hh b/qlparser/qtdelete.hh
new file mode 100644
index 0000000..c16f243
--- /dev/null
+++ b/qlparser/qtdelete.hh
@@ -0,0 +1,100 @@
+#ifndef __QTDELETE_HH__
+#define __QTDELETE_HH___
+
+#include "qlparser/qtexecute.hh"
+#include "qlparser/qtoncstream.hh"
+
+#include <iostream>
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+*/
+
+class QtDelete : public QtExecute
+{
+ public:
+ /// default constructor
+ QtDelete();
+
+ /// virtual destructor
+ virtual ~QtDelete();
+
+ /// method for evaluating the node
+ virtual int evaluate();
+
+ /// return childs of the node
+ virtual QtNodeList* getChilds( QtChildType flag );
+
+ /// prints the tree
+ virtual void printTree( int tab, std::ostream& s = std::cout, QtChildType mode = QT_ALL_NODES );
+
+ /// prints the algebraic expression
+ virtual void printAlgebraicExpression( std::ostream& s = std::cout );
+
+ //@Man: Read/Write methods:
+ //@{
+ ///
+ ///
+ void setStreamInput( QtONCStream* newInput );
+ ///
+ /// returns input
+ QtONCStream* getStreamInput();
+ //@}
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ /// pre optimization
+// virtual void preOptimize();
+ /**
+ Pre-Optimization step is passed to the input streams.
+ */
+
+ /// type checking
+ virtual void checkType();
+
+ private:
+ /// one input stream
+ QtONCStream* input;
+
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+#include "qlparser/qtdelete.icc"
+
+#endif
+
+
+
diff --git a/qlparser/qtdelete.icc b/qlparser/qtdelete.icc
new file mode 100644
index 0000000..db18e76
--- /dev/null
+++ b/qlparser/qtdelete.icc
@@ -0,0 +1,35 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+inline const QtNode::QtNodeType
+QtDelete::getNodeType() const
+{
+ return nodeType;
+}
+
diff --git a/qlparser/qtdomainoperation.cc b/qlparser/qtdomainoperation.cc
new file mode 100644
index 0000000..950c49d
--- /dev/null
+++ b/qlparser/qtdomainoperation.cc
@@ -0,0 +1,950 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)qlparser, QtTrim: $Id: qtdomainoperation.cc,v 1.35 2002/06/15 20:16:42 coman Exp $";
+
+#include <vector>
+#include <string>
+using namespace std;
+
+#include "raslib/rmdebug.hh"
+
+#include "qlparser/qtmdd.hh"
+#include "qlparser/qtunaryoperation.hh"
+#include "qlparser/qtdomainoperation.hh"
+#include "qlparser/qtnode.hh"
+#include "qlparser/qtconst.hh"
+#include "qlparser/qtmintervaldata.hh"
+#include "qlparser/qtintervaldata.hh"
+#include "qlparser/qtpointdata.hh"
+#include "qlparser/qtatomicdata.hh"
+#include "qlparser/qtcomplexdata.hh"
+
+#include "mddmgr/mddobj.hh"
+#include "tilemgr/tile.hh"
+
+#include "catalogmgr/ops.hh"
+#include "relcatalogif/mddbasetype.hh"
+#include "relcatalogif/ulongtype.hh"
+
+#include <iostream>
+
+
+const QtNode::QtNodeType QtDomainOperation::nodeType = QtNode::QT_DOMAIN_OPERATION;
+
+
+QtDomainOperation::QtDomainOperation( QtOperation* mintOp )
+ : mintervalOp( mintOp ),
+ dynamicMintervalExpression( true )
+{
+ RMDBCLASS( "QtDomainOperation", "QtDomainOperation( QtOperation* )", "qlparser", __FILE__, __LINE__ )
+
+ if( mintervalOp ) mintervalOp->setParent( this );
+}
+
+
+
+QtDomainOperation::QtDomainOperation( r_Minterval domainNew, const vector<bool>* newTrimFlags )
+ : mintervalOp(0),
+ dynamicMintervalExpression( false )
+{
+ RMDBCLASS( "QtDomainOperation", "QtDomainOperation( r_Minterval, const vector<bool>* )", "qlparser", __FILE__, __LINE__ )
+
+ // make a copy
+ vector<bool>* trimFlags = new vector<bool>( *newTrimFlags );
+ mintervalOp = new QtConst( new QtMintervalData( domainNew, trimFlags ) );
+ mintervalOp->setParent( this );
+}
+
+
+
+QtDomainOperation::~QtDomainOperation()
+{
+ RMDBCLASS( "QtDomainOperation", "~QtDomainOperation()", "qlparser", __FILE__, __LINE__ )
+
+ if( mintervalOp )
+ {
+ delete mintervalOp;
+ mintervalOp=NULL;
+ }
+}
+
+
+
+QtNode::QtNodeList*
+QtDomainOperation::getChilds( QtChildType flag )
+{
+ RMDBCLASS( "QtDomainOperation", "getChilds( QtChildType )", "qlparser", __FILE__, __LINE__ )
+
+ QtNodeList* resultList=NULL;
+
+ resultList = QtUnaryOperation::getChilds( flag );
+
+ if( mintervalOp )
+ {
+ if( flag == QT_LEAF_NODES || flag == QT_ALL_NODES )
+ {
+ QtNodeList* subList;
+
+ subList = mintervalOp->getChilds( flag );
+
+ // remove all elements in subList and insert them at the beginning in resultList
+ resultList->splice( resultList->begin(), *subList );
+
+ // delete temporary subList
+ delete subList;
+ subList=NULL;
+ }
+
+ // add the nodes of the current level
+ if( flag == QT_DIRECT_CHILDS || flag == QT_ALL_NODES )
+ resultList->push_back( mintervalOp );
+ }
+
+ return resultList;
+}
+
+
+
+bool
+QtDomainOperation::equalMeaning( QtNode* node )
+{
+ RMDBCLASS( "QtDomainOperation", "equalMeaning( QtNode* )", "qlparser", __FILE__, __LINE__ )
+
+ bool result = false;
+
+ if( nodeType == node->getNodeType() )
+ {
+ QtDomainOperation* domainNode;
+ domainNode = (QtDomainOperation*) node; // by force
+
+ result = input->equalMeaning( domainNode->getInput() ) &&
+ mintervalOp->equalMeaning( domainNode->getMintervalOp() );
+ };
+
+ return ( result );
+}
+
+
+string
+QtDomainOperation::getSpelling()
+{
+ char tempStr[20];
+ sprintf(tempStr, "%ud", (unsigned long)getNodeType());
+ string result = string(tempStr);
+ result.append( mintervalOp->getSpelling() );
+ result.append( "(" );
+ result.append( input->getSpelling() );
+ result.append( ")" );
+
+ return result;
+}
+
+
+void
+QtDomainOperation::setInput( QtOperation* inputOld, QtOperation* inputNew )
+{
+ QtUnaryOperation::setInput( inputOld, inputNew );
+
+ if( mintervalOp == inputOld )
+ {
+ mintervalOp = inputNew;
+
+ if( inputNew )
+ inputNew->setParent( this );
+ }
+};
+
+
+
+void
+QtDomainOperation::optimizeLoad( QtTrimList* trimList )
+{
+ RMDBCLASS( "QtDomainOperation", "optimizeLoad( QtTrimList* )", "qlparser", __FILE__, __LINE__ )
+
+ // test, if there is already a specification for that dimension
+ bool trimming = false;
+
+ if( mintervalOp )
+ {
+ // pass optimization to minterval tree
+ mintervalOp->optimizeLoad( new QtNode::QtTrimList );
+
+ // evaluate minterval tree
+ QtData* operand = mintervalOp->evaluate(NULL);
+
+ // if spatial operation could be determined, it is static
+ dynamicMintervalExpression = !operand;
+
+ if( operand )
+ {
+ if( operand->getDataType() == QT_MINTERVAL )
+ {
+ r_Minterval domain = ((QtMintervalData*)operand)->getMintervalData();
+ vector<bool>* trimFlags = new vector<bool>( *(((QtMintervalData*)operand)->getTrimFlags()) );
+
+ if( trimList && trimList->empty() )
+ {
+ // no previous specification for that dimension
+ trimming = true;
+ for( int i=0; i!=domain.dimension(); i++ )
+ {
+ // create a new element
+ QtTrimElement* elem = new QtTrimElement;
+
+ elem->interval = domain[i];
+ elem->intervalFlag = (*trimFlags)[i];
+ elem->dimension = i;
+
+ // and add it to the list
+ trimList->push_back( elem );
+
+ trimming &= (*trimFlags)[i];
+ }
+ }
+ else
+ {
+ // previous specification exists, test for compatibility
+ }
+
+ if( trimFlags )
+ {
+ delete trimFlags;
+ trimFlags = NULL;
+ }
+ }
+
+ // else if( operand->getDataType() == QtData::QT_POINT )
+
+ // delete the operand
+ operand->deleteRef();
+ }
+ }
+
+ // pass optimization process to the input tree
+ if( input ) input->optimizeLoad( trimList );
+
+ // Eliminate node QtDomainOperation if only trimming occurs.
+ if( trimming )
+ {
+ RMDBGMIDDLE(2, RMDebug::module_qlparser, "QtDomainOperation", "all trimming")
+
+ getParent()->setInput( this, input );
+
+ // Delete the node itself after resetting its input because
+ // otherwise the input is delete either.
+ setInput( input, NULL );
+ delete this;
+ }
+}
+
+
+
+QtData*
+QtDomainOperation::evaluate( QtDataList* inputList )
+{
+ RMDBCLASS( "QtDomainOperation", "evaluate( QtDataList* )", "qlparser", __FILE__, __LINE__ )
+
+ QtData* returnValue = NULL;
+
+ switch( input->getDataStreamType().getDataType() )
+ {
+ case QT_MDD:
+ {
+ if( mintervalOp->getDataStreamType().getDataType() == QT_POINT ||
+ mintervalOp->getDataStreamType().isInteger() )
+ {
+ //
+ // Projection to one cell.
+ //
+
+ QtData* indexData = mintervalOp->evaluate( inputList );
+
+ if( !indexData )
+ return 0;
+
+#ifdef QT_RUNTIME_TYPE_CHECK
+ if( indexData->getDataType() != QT_POINT &&
+ !indexData->getDataType().isInteger() )
+ {
+ RMInit::logOut << "Internal error in QtDomainOperation::evaluate() - "
+ << "runtime type checking failed (QT_POINT, INTEGER)." << endl;
+
+ // delete index data
+ indexData->deleteRef();
+
+ return 0;
+ }
+#endif
+
+ // get projection point
+ r_Point projPoint;
+
+ if( indexData->getDataType() == QT_POINT )
+ {
+ projPoint = ((QtPointData*)indexData)->getPointData();
+ }
+ else
+ {
+ projPoint = r_Point(1);
+
+ if( indexData->getDataType() == QT_SHORT ||
+ indexData->getDataType() == QT_OCTET ||
+ indexData->getDataType() == QT_LONG )
+ projPoint[0] = ((QtAtomicData*)indexData)->getSignedValue();
+ else
+ projPoint[0] = ((QtAtomicData*)indexData)->getUnsignedValue();
+
+ }
+
+ //
+ // In case of dynamic index expressions, load optimization has to
+ // be performed for the current input expression.
+ //
+ /*
+ if( dynamicMintervalExpression )
+ {
+ QtNode::QtTrimList* trimList = new QtNode::QtTrimList;
+
+ for( int i=0; i!=domain.dimension(); i++ )
+ {
+ // create a new element
+ QtTrimElement* elem = new QtTrimElement;
+
+ elem->interval = domain[i];
+ elem->intervalFlag = (*trimFlags)[i];
+ elem->dimension = i;
+
+ // and add it to the list
+ trimList->push_back( elem );
+ }
+
+ // pass optimization process to the input tree
+ input->optimizeLoad( trimList );
+ }
+ */
+
+ // get operand data
+ QtData* operand = input->evaluate( inputList );
+
+ if( !operand )
+ {
+ // delete indexData
+ indexData->deleteRef();
+
+ return 0;
+ }
+
+#ifdef QT_RUNTIME_TYPE_CHECK
+ if( operand->getDataType() != QT_MDD )
+ {
+ RMInit::logOut << "Internal error in QtDomainOperation::evaluate() - runtime type checking failed (QT_MDD)." << endl;
+
+ // delete index and operand data
+ indexData->deleteRef();
+ operand ->deleteRef();
+
+ return 0;
+ }
+#endif
+
+ QtMDD* qtMDD = (QtMDD*) operand;
+ MDDObj* currentMDDObj = qtMDD->getMDDObject();
+
+ if( currentMDDObj )
+ {
+ RMDBGMIDDLE(2, RMDebug::module_qlparser, "QtDomainOperation", " mdd domain: " << currentMDDObj->getCurrentDomain() )
+ RMDBGMIDDLE(2, RMDebug::module_qlparser, "QtDomainOperation", " mdd load domain: " << qtMDD->getLoadDomain() )
+
+ // reset loadDomain to intersection of domain and loadDomain
+ // if( domain.intersection_with( qtMDD->getLoadDomain() ) != qtMDD->getLoadDomain() )
+ // qtMDD->setLoadDomain( domain.intersection_with( qtMDD->getLoadDomain() ) );
+
+ // get type of cell
+ const BaseType* cellType = ((MDDBaseType*)(currentMDDObj->getMDDBaseType()))->getBaseType();
+
+ RMDBGMIDDLE(2, RMDebug::module_qlparser, "QtDomainOperation", " point access: " << projPoint )
+ const char* resultCell = NULL;
+ if (projPoint.dimension() == currentMDDObj->getDimension())
+ resultCell = currentMDDObj->pointQuery( projPoint );
+ if (resultCell == NULL)
+ {
+ RMInit::logOut << "Error: QtDomainOperation::evaluate() - projected cell is not defined." << endl;
+ parseInfo.setErrorNo(356);
+
+ // delete index and operand data
+ indexData->deleteRef();
+ operand ->deleteRef();
+
+ throw parseInfo;
+ }
+
+ // allocate cell buffer
+ char* resultBuffer = new char[ cellType->getSize() ];
+
+ // copy cell content
+ memcpy( (void*)resultBuffer, (void*)resultCell, cellType->getSize() );
+
+ // create data object for the cell
+ QtScalarData* scalarDataObj = NULL;
+ if( cellType->getType() == STRUCT )
+ scalarDataObj = new QtComplexData();
+ else
+ scalarDataObj = new QtAtomicData();
+
+ scalarDataObj->setValueType ( cellType );
+ scalarDataObj->setValueBuffer( resultBuffer );
+
+ // set return data object
+ returnValue = scalarDataObj;
+ }
+
+ // delete indexData
+ indexData->deleteRef();
+
+ // delete old operand
+ operand->deleteRef();
+
+ }
+ else // mintervalOp->getDataStreamType() == QT_MINTERVAL
+ {
+ //
+ // Trimming/Projection to an MDD object
+ //
+ QtData* indexData = mintervalOp->evaluate( inputList );
+
+ if( !indexData )
+ return 0;
+
+#ifdef QT_RUNTIME_TYPE_CHECK
+ if( indexData->getDataType() != QT_MINTERVAL )
+ {
+ RMInit::logOut << "Internal error in QtDomainOperation::evaluate() - "
+ << "runtime type checking failed (QT_MINTERVAL)." << endl;
+
+ // delete index data
+ indexData->deleteRef();
+
+ return 0;
+ }
+#endif
+
+ // get minterval data
+ vector<bool>* trimFlags = new vector<bool>( *(((QtMintervalData*)indexData)->getTrimFlags()) );
+ r_Minterval domain = ((QtMintervalData*)indexData)->getMintervalData();
+
+ //
+ // In case of dynamic index expressions, load optimization has to
+ // be performed for the current input expression.
+ //
+
+ if( dynamicMintervalExpression )
+ {
+ QtNode::QtTrimList* trimList = new QtNode::QtTrimList;
+
+ for( int i=0; i!=domain.dimension(); i++ )
+ {
+ // create a new element
+ QtTrimElement* elem = new QtTrimElement;
+
+ elem->interval = domain[i];
+ elem->intervalFlag = (*trimFlags)[i];
+ elem->dimension = i;
+
+ // and add it to the list
+ trimList->push_back( elem );
+ }
+
+ // pass optimization process to the input tree
+ input->optimizeLoad( trimList );
+ }
+
+ // get operand data
+ QtData* operand = input->evaluate( inputList );
+
+ if( !operand )
+ {
+ // delete index data
+ indexData->deleteRef();
+ return 0;
+ }
+
+#ifdef QT_RUNTIME_TYPE_CHECK
+ if( operand->getDataType() != QT_MDD )
+ {
+ RMInit::logOut << "Internal error in QtDomainOperation::evaluate() - runtime type checking failed (QT_MDD)." << endl;
+
+ // delete index and operand data
+ indexData->deleteRef();
+ operand ->deleteRef();
+
+ return 0;
+ }
+#endif
+
+ QtMDD* qtMDD = (QtMDD*) operand;
+ MDDObj* currentMDDObj = qtMDD->getMDDObject();
+
+ if( currentMDDObj )
+ {
+ bool trimming = false;
+ bool projection = false;
+
+ // reset loadDomain to intersection of domain and loadDomain
+ if( domain.intersection_with( qtMDD->getLoadDomain() ) != qtMDD->getLoadDomain() )
+ qtMDD->setLoadDomain( domain.intersection_with( qtMDD->getLoadDomain() ) );
+
+ // Test, if trimming has to be done; trimming = 1 if !(load domain is subset of spatial operation)
+ trimming = ( domain.intersection_with( qtMDD->getLoadDomain() ) == qtMDD->getLoadDomain() );
+
+ // Test, if a projection has to be made and build the projSet in projection case
+ set< r_Dimension, less<r_Dimension> > projSet;
+
+ for( int i=0; i<trimFlags->size(); i++ )
+ if( !(*trimFlags)[i] )
+ {
+ projection = true;
+ projSet.insert( i );
+ }
+
+ r_Minterval projectedDom( domain.dimension() - projSet.size() );
+
+ // build the projected domain
+ for( int i = 0; i < domain.dimension(); i++ )
+ // do not include dimensions projected away
+ if(projSet.find(i) == projSet.end())
+ projectedDom << domain[i];
+
+ if( trimFlags )
+ {
+ delete trimFlags;
+ trimFlags = NULL;
+ }
+
+ RMDBGMIDDLE(2, RMDebug::module_qlparser, "QtDomainOperation", " operation domain..: " << domain << " with projection " << projectedDom )
+ RMDBGMIDDLE(2, RMDebug::module_qlparser, "QtDomainOperation", " mdd load domain: " << qtMDD->getLoadDomain() )
+ RMDBGMIDDLE(2, RMDebug::module_qlparser, "QtDomainOperation", " mdd current domain: " << currentMDDObj->getCurrentDomain() )
+
+ if( trimming || projection )
+ {
+ // get relevant tiles
+ vector<Tile* >* relevantTiles = currentMDDObj->intersect( domain );
+
+ if( relevantTiles->size() > 0 )
+ {
+ // iterator for tiles
+ vector<Tile*>::iterator tileIt;
+
+ // create a transient MDD object for the query result
+ MDDObj* resultMDD = new MDDObj( currentMDDObj->getMDDBaseType(), projectedDom );
+
+ // and iterate over them
+ for( tileIt = relevantTiles->begin(); tileIt != relevantTiles->end(); tileIt++ )
+ {
+ // domain of the actual tile
+ r_Minterval tileDom = (*tileIt)->getDomain();
+
+ // domain of the relevant area of the actual tile
+ r_Minterval intersectDom = tileDom.create_intersection( domain );
+
+ RMDBGMIDDLE(2, RMDebug::module_qlparser, "QtDomainOperation", " trimming/projecting tile with domain " << tileDom << " to domain " << intersectDom )
+
+ // create projected tile
+ Tile* resTile = new Tile( (*tileIt), intersectDom, &projSet );
+
+ // insert Tile in result mddObj
+ resultMDD->insertTile( resTile );
+ }
+
+ // create a new QtMDD object as carrier object for the transient MDD object
+ returnValue = new QtMDD( (MDDObj*)resultMDD );
+
+ // delete the tile vector
+ delete relevantTiles;
+ relevantTiles=NULL;
+ }
+ else
+ {
+ RMInit::logOut << "Error: QtDomainOperation::evaluate() - the load domain does not intersect with tiles in the current MDD." << endl;
+ parseInfo.setErrorNo(356);
+
+ // delete index and operand data
+ indexData->deleteRef();
+ operand ->deleteRef();
+
+ throw parseInfo;
+ }
+
+ } // trimming || projection
+ else
+ // operand is passed through
+ returnValue = operand;
+
+ } // if( currentMDDObj )
+
+ // delete index and operand data
+ if( indexData ) indexData->deleteRef();
+ if( operand ) operand ->deleteRef();
+
+ }
+ break;
+ }
+ case QT_MINTERVAL:
+ {
+ QtData* operandData = NULL;
+ QtData* indexData = NULL;
+
+ operandData = input->evaluate( inputList );
+
+ if( operandData )
+ {
+#ifdef QT_RUNTIME_TYPE_CHECK
+ if( operandData->getDataType() != QT_MINTERVAL )
+ {
+ RMInit::logOut << "Internal error in QtDomainOperation::evaluate() - runtime type checking failed (QT_MINTERVAL)." << endl;
+ return 0;
+ }
+#endif
+ // get point
+ const r_Minterval& minterval = ((QtMintervalData*)operandData)->getMintervalData();
+
+ // get index
+ indexData = mintervalOp->evaluate( inputList );
+
+#ifdef QT_RUNTIME_TYPE_CHECK
+ if( indexData->getDataType() != QT_POINT && indexData->getDataType() != QT_CHAR &&
+ indexData->getDataType() != QT_USHORT && indexData->getDataType() != QT_ULONG )
+ {
+ RMInit::logOut << "Internal error in QtDomainOperation::evaluate() - runtime type checking failed." << endl;
+ return 0;
+ }
+#endif
+ r_Dimension indexValue = 0;
+
+ switch( indexData->getDataType() )
+ {
+ case QT_POINT:
+ {
+ // get first element as index
+ const r_Point& indexPoint = ((QtPointData*)indexData)->getPointData();
+
+ if( indexPoint.dimension() != 1 )
+ {
+ RMInit::logOut << "Error: QtDomainOperation::evaluate() - Operand of minterval selection must be of type unsigned integer." << endl;
+ parseInfo.setErrorNo(397);
+
+ // delete ressources
+ if( operandData ) operandData->deleteRef();
+ if( indexData ) indexData ->deleteRef();
+
+ throw parseInfo;
+ }
+
+ indexValue = indexPoint[0];
+ }
+ break;
+
+ case QT_CHAR:
+ case QT_USHORT:
+ case QT_ULONG:
+ indexValue = ((QtAtomicData*)indexData)->getUnsignedValue();
+ break;
+
+ case QT_OCTET:
+ case QT_SHORT:
+ case QT_LONG:
+ indexValue = ((QtAtomicData*)indexData)->getSignedValue();
+ break;
+ default:
+ RMDBGONCE(0, RMDebug::module_qlparser, "r_QtDomainOperation", "evaluate() bad type " << indexData->getDataType());
+ break;
+ }
+//indexValue is a unsigned type -> there will never be a indexVAlue < 0
+ if( /*indexValue < 0 ||*/ indexValue >= minterval.dimension() )
+ {
+ RMInit::logOut << "Error: QtDomainOperation::evaluate() - index for minterval selection is out of range." << endl;
+ parseInfo.setErrorNo(398);
+
+ // delete ressources
+ if( operandData ) operandData->deleteRef();
+ if( indexData ) indexData ->deleteRef();
+
+ throw parseInfo;
+ }
+
+ returnValue = new QtIntervalData( minterval[indexValue] );
+ }
+
+ // delete ressources
+ if( operandData ) operandData->deleteRef();
+ if( indexData ) indexData ->deleteRef();
+ break;
+ }
+
+ case QT_POINT:
+ {
+ QtData* operandData = NULL;
+ QtData* indexData = NULL;
+
+ operandData = input->evaluate( inputList );
+
+ if( operandData )
+ {
+#ifdef QT_RUNTIME_TYPE_CHECK
+ if( operandData->getDataType() != QT_POINT )
+ {
+ RMInit::logOut << "Internal error in QtDomainOperation::evaluate() - runtime type checking failed (QT_POINT)." << endl;
+ return 0;
+ }
+#endif
+ // get point
+ const r_Point& pt = ((QtPointData*)operandData)->getPointData();
+
+ // get index
+ indexData = mintervalOp->evaluate( inputList );
+
+#ifdef QT_RUNTIME_TYPE_CHECK
+ if( indexData->getDataType() != QT_POINT && indexData->getDataType() != QT_CHAR &&
+ indexData->getDataType() != QT_USHORT && indexData->getDataType() != QT_ULONG )
+ {
+ RMInit::logOut << "Internal error in QtDomainOperation::evaluate() - runtime type checking failed." << endl;
+ return 0;
+ }
+#endif
+ r_Dimension indexValue = 0;
+
+ switch( indexData->getDataType() )
+ {
+ case QT_POINT:
+ {
+ // get first element as index
+ const r_Point& indexPoint = ((QtPointData*)indexData)->getPointData();
+
+ if( indexPoint.dimension() != 1 )
+ {
+ RMInit::logOut << "Error: QtDomainOperation::evaluate() - Operand of point selection must be of type unsigned integer." << endl;
+ parseInfo.setErrorNo(399);
+
+ // delete ressources
+ if( operandData ) operandData->deleteRef();
+ if( indexData ) indexData ->deleteRef();
+
+ throw parseInfo;
+ }
+
+ indexValue = indexPoint[0];
+ }
+ break;
+
+ case QT_CHAR:
+ case QT_USHORT:
+ case QT_ULONG:
+ indexValue = ((QtAtomicData*)indexData)->getUnsignedValue();
+ break;
+
+ case QT_OCTET:
+ case QT_SHORT:
+ case QT_LONG:
+ indexValue = ((QtAtomicData*)indexData)->getSignedValue();
+ break;
+ default:
+ RMDBGONCE(0, RMDebug::module_qlparser, "r_QtDomainOperation", "evaluate() 2 - bad type " << indexData->getDataType());
+ break;
+ }
+
+ //indexValue is a unsigned type -> there will never be a indexValue < 0
+ if( /*indexValue < 0 ||*/ indexValue >= pt.dimension() )
+ {
+ RMInit::logOut << "Error: QtDomainOperation::evaluate() - index for point selection is out of range." << endl;
+ parseInfo.setErrorNo(411);
+
+ // delete ressources
+ if( operandData ) operandData->deleteRef();
+ if( indexData ) indexData ->deleteRef();
+
+ throw parseInfo;
+ }
+
+ returnValue = new QtAtomicData( (r_Long)pt[indexValue], 4 );
+ }
+
+ // delete ressources
+ if( operandData ) operandData->deleteRef();
+ if( indexData ) indexData ->deleteRef();
+ break;
+ }
+
+ default:
+ {
+ RMInit::logOut << "Error: QtDomainOperation::evaluate() - selection operation is not supported on this data type." << endl;
+ parseInfo.setErrorNo(396);
+ throw parseInfo;
+ }
+ }
+
+ return returnValue;
+}
+
+
+void
+QtDomainOperation::printTree( int tab, ostream& s, QtChildType mode )
+{
+ s << SPACE_STR(tab).c_str() << "QtDomainOperation Object: type " << flush;
+ dataStreamType.printStatus( s );
+ s << endl;
+
+ if( mintervalOp )
+ {
+ s << SPACE_STR(tab).c_str() << "spatial operation: " << endl;
+ mintervalOp->printTree( tab + 2, s );
+ }
+ else
+ s << SPACE_STR(tab).c_str() << "no spatial operation" << endl;
+
+ QtUnaryOperation::printTree( tab, s, mode );
+}
+
+
+
+void
+QtDomainOperation::printAlgebraicExpression( ostream& s )
+{
+ s << "geo(";
+
+ if( mintervalOp )
+ mintervalOp->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << ",";
+
+ if( input )
+ input->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << ")";
+}
+
+
+
+const QtTypeElement&
+QtDomainOperation::checkType( QtTypeTuple* typeTuple )
+{
+ RMDBCLASS( "QtDomainOperation", "checkType( QtTypeTuple* )", "qlparser", __FILE__, __LINE__ )
+
+ dataStreamType.setDataType( QT_TYPE_UNKNOWN );
+
+ //
+ // operation signatures
+ //
+ // MDD<T,D> x Minterval -> MDD<T,D>
+ // // MDD<T,D> x Interval -> MDD<T,D>
+ // MDD<T,D> x Point -> T
+ // MDD<T,D> x Integer -> T
+ // Minterval x Integer -> Interval
+ // Minterval x Point(1) -> Interval
+ // Point x Integer -> Integer
+ // Point x Point(1) -> Integer
+ //
+
+ // check operand branches
+ if( input && mintervalOp )
+ {
+
+ // 1. check input expression type
+ const QtTypeElement& inputType = input->checkType( typeTuple );
+
+ // 2. check index expression type
+ const QtTypeElement& indexType = mintervalOp->checkType( typeTuple );
+
+ // 3. determine result type
+ if( inputType.getDataType() == QT_MDD )
+ {
+ // check index type
+ if( indexType.getDataType() != QT_MINTERVAL
+ // && indexType.getDataType() != QT_INTERVAL
+ && indexType.getDataType() != QT_POINT
+ && !indexType.isInteger()
+ )
+ {
+ RMInit::logOut << "Error: QtDomainOperation::checkType() - spatial domain expressions must be either of type minterval, point, or integer." << endl;
+ parseInfo.setErrorNo(391);
+ throw parseInfo;
+ }
+
+ // MDD
+ if( indexType.getDataType() == QT_MINTERVAL /* || indexType.getDataType() == QT_INTERVAL */ )
+ // pass MDD type
+ dataStreamType = inputType;
+ else
+ // use MDD cell type
+ dataStreamType.setType( ((MDDBaseType*)inputType.getType())->getBaseType() );
+ }
+ else if( inputType.getDataType() == QT_MINTERVAL )
+ {
+ // check index type
+ if( !indexType.isInteger() && indexType.getDataType() != QT_POINT )
+ {
+ RMInit::logOut << "Error: QtDomainOperation::checkType() - Operand of minterval selection must be of type integer." << endl;
+ parseInfo.setErrorNo(397);
+ throw parseInfo;
+ }
+
+ dataStreamType.setDataType( QT_INTERVAL );
+ }
+ else if( inputType.getDataType() == QT_POINT )
+ {
+ // check index type
+ if( !indexType.isInteger() && indexType.getDataType() != QT_POINT )
+ {
+ RMInit::logOut << "Error: QtDomainOperation::checkType() - Operand of point selection must be of type integer." << endl;
+ parseInfo.setErrorNo(399);
+ throw parseInfo;
+ }
+
+ dataStreamType.setDataType( QT_ULONG );
+ }
+ else
+ {
+ RMInit::logOut << "Error: QtDomainOperation::checkType() - selection operation is not supported on this data type." << endl;
+ parseInfo.setErrorNo(396);
+ throw parseInfo;
+ }
+ }
+ else
+ RMInit::logOut << "Error: QtDomainOperation::checkType() - input or index branch invalid." << endl;
+
+ return dataStreamType;
+}
+
+
diff --git a/qlparser/qtdomainoperation.hh b/qlparser/qtdomainoperation.hh
new file mode 100644
index 0000000..0806ca8
--- /dev/null
+++ b/qlparser/qtdomainoperation.hh
@@ -0,0 +1,124 @@
+#ifndef _QTDOMAINOPERATION_
+#define _QTDOMAINOPERATION_
+
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+#endif
+
+#include "qlparser/qtunaryoperation.hh"
+#include "qlparser/qtmintervaldata.hh"
+#include "raslib/sinterval.hh"
+#include "raslib/minterval.hh"
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+The class represents a spatial domain operation, e.g. trimming or projections.
+
+*/
+
+class QtDomainOperation : public QtUnaryOperation
+{
+ public:
+
+ /// constructor getting an minterval expression
+ QtDomainOperation( QtOperation* mintOp );
+
+ /// constructor
+ QtDomainOperation( r_Minterval domainNew, const vector<bool>* newTrimFlags );
+
+ /// destructor
+ virtual ~QtDomainOperation();
+
+ /// return childs of the node
+ virtual QtNodeList* getChilds( QtChildType flag );
+
+ /// test if the two nodes have an equal meaning in a subtree
+ virtual bool equalMeaning( QtNode* node );
+
+ /// creates a unique name for a common subexpression
+ virtual std::string getSpelling();
+
+ /// method for query rewrite
+ virtual void setInput( QtOperation* inputOld, QtOperation* inputNew );
+
+ /// optimizing load access
+ void optimizeLoad( QtTrimList* trimList );
+
+ /// evaluates the node
+ QtData* evaluate( QtDataList* inputList );
+
+ /// prints the tree
+ virtual void printTree( int tab, std::ostream& s = std::cout, QtChildType mode = QT_ALL_NODES );
+
+ /// prints the algebraic expression
+ virtual void printAlgebraicExpression( std::ostream& s = std::cout );
+
+ //@Man: Read/Write methods:
+ //@{
+ ///
+
+ ///
+ inline virtual void setInput( QtOperation* newInput );
+ ///
+ inline virtual void setMintervalOp(QtOperation* miop);
+ ///
+ inline QtOperation* getMintervalOp();
+
+ ///
+ //@}
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ /// type checking of the subtree
+ virtual const QtTypeElement& checkType( QtTypeTuple* typeTuple = NULL );
+
+ private:
+ /// pointer to an minterval expression
+ QtOperation* mintervalOp;
+
+ /// the flag determines if the minterval expression has to be calculated at runtime or not
+ bool dynamicMintervalExpression;
+
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+#include "qlparser/qtdomainoperation.icc"
+
+#endif
+
diff --git a/qlparser/qtdomainoperation.icc b/qlparser/qtdomainoperation.icc
new file mode 100644
index 0000000..2541c7c
--- /dev/null
+++ b/qlparser/qtdomainoperation.icc
@@ -0,0 +1,66 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+
+inline void
+QtDomainOperation::setMintervalOp(QtOperation* miop)
+{
+ mintervalOp = miop;
+}
+
+inline QtOperation*
+QtDomainOperation::getMintervalOp()
+{
+ return mintervalOp;
+}
+
+
+inline const QtNode::QtNodeType
+QtDomainOperation::getNodeType() const
+{
+ return nodeType;
+}
+
+
+inline void
+QtDomainOperation::setInput( QtOperation* newInput )
+{
+ QtUnaryOperation::setInput( newInput );
+}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/qlparser/qtexecute.hh b/qlparser/qtexecute.hh
new file mode 100644
index 0000000..94352ec
--- /dev/null
+++ b/qlparser/qtexecute.hh
@@ -0,0 +1,66 @@
+#ifndef __QTEXECUTE_HH__
+#define __QTEXECUTE_HH__
+
+#include "qlparser/qtnode.hh"
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+*/
+
+class QtExecute : public QtNode
+{
+ public:
+ /// method for evaluating the execute node node
+ virtual int evaluate() = 0;
+
+ /// type checking
+ virtual void checkType() = 0;
+ /**
+ The method triggers type checking of the node's subtree. If an error occurs, an exception
+ is raised.
+ */
+};
+
+#endif
+
+
+
+
+
+
+
+
+
+
+
diff --git a/qlparser/qtinsert.cc b/qlparser/qtinsert.cc
new file mode 100644
index 0000000..bfcfbc5
--- /dev/null
+++ b/qlparser/qtinsert.cc
@@ -0,0 +1,361 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)qlparser, QtInsert: $Header: /home/rasdev/CVS-repository/rasdaman/qlparser/qtinsert.cc,v 1.27 2003/12/27 20:40:21 rasdev Exp $";
+
+#include "qlparser/qtinsert.hh"
+#include "qlparser/qtdata.hh"
+#include "qlparser/qtmdd.hh"
+
+#include "tilemgr/tile.hh"
+#include "mddmgr/mddcoll.hh"
+#include "mddmgr/mddobj.hh"
+
+#include <iostream>
+
+#include "servercomm/servercomm.hh"
+
+extern ServerComm::ClientTblElt* currentClientTblElt;
+
+const QtNode::QtNodeType QtInsert::nodeType = QtNode::QT_INSERT;
+
+
+QtInsert::QtInsert( const std::string& initCollectionName, QtOperation* initSource )
+ : QtExecute(), collectionName( initCollectionName ), source( initSource )
+{
+ source->setParent( this );
+}
+
+
+
+QtInsert::~QtInsert()
+{
+ if( source )
+ {
+ delete source;
+ source=NULL;
+ }
+}
+
+
+
+int
+QtInsert::evaluate()
+{
+ RMDBCLASS( "QtInsert", "evaluate()", "qlparser", __FILE__, __LINE__ )
+
+ // empty data list for evaluation of insert expression including constant
+ QtNode::QtDataList* nextTupel = new QtNode::QtDataList(0);
+
+ // get the operands
+ QtData* sourceData = source->evaluate( nextTupel );
+
+ if( sourceData )
+ {
+ QtMDD* sourceMDD = (QtMDD*) sourceData;
+ MDDObj* sourceObj = sourceMDD->getMDDObject();
+
+ MDDColl* persColl = NULL;
+ MDDColl* almost = NULL;
+
+ try
+ {
+ almost = MDDColl::getMDDCollection( collectionName.c_str() );
+ }
+ catch(...)
+ {
+
+ RMInit::logOut << "Error: QtInsert::evaluate() - collection name not found" << std::endl;
+
+ // delete the operand
+ if( sourceData ) sourceData->deleteRef();
+
+ parseInfo.setErrorNo(355);
+ throw parseInfo;
+ }
+if (!almost->isPersistent())
+ {
+ RMInit::logOut << "QtInsert: User tries to insert into system table" << std::endl;
+ if( sourceData ) sourceData->deleteRef();
+
+ parseInfo.setErrorNo(355);
+ throw parseInfo;
+ }
+else {
+ persColl = (MDDColl*)almost;
+ }
+
+ //
+ // check MDD and collection type for compatibility
+ //
+
+RMDBGIF(3, RMDebug::module_qlparser, "QtInsert", \
+ char* collTypeStructure = persColl->getCollectionType()->getTypeStructure(); \
+ char* mddTypeStructure = sourceObj->getMDDBaseType()->getTypeStructure(); \
+ RMInit::dbgOut << std::endl << "Collection type structure.: " << collTypeStructure << std::endl \
+ << "MDD type structure........: " << mddTypeStructure << std::endl \
+ << "MDD domain................: " << sourceObj->getDefinitionDomain() << std::endl; \
+ free( collTypeStructure ); collTypeStructure=NULL; \
+ free( mddTypeStructure ); mddTypeStructure=NULL; )
+
+ // bug fix: "insert into" found claimed non-existing type mismatch -- PB 2003-aug-25, based on fix by K.Hahn
+ // if( !persColl->getCollectionType()->compatibleWith( (Type*) sourceObj->getMDDBaseType() ) )
+ if( !((MDDType*) sourceObj->getMDDBaseType())->compatibleWith( persColl->getCollectionType()->getMDDType() ) )
+ {
+ // free resources
+ persColl->releaseAll();
+ delete persColl;
+ persColl=NULL;
+ if( sourceData ) sourceData->deleteRef(); // delete the operand
+
+ // return error
+ RMInit::logOut << "Error: QtInsert::evaluate() - MDD and collection types are incompatible" << std::endl;
+ parseInfo.setErrorNo(959);
+ throw parseInfo;
+ }
+
+ if( !persColl->getCollectionType()->getMDDType()->compatibleWithDomain( &(sourceObj->getDefinitionDomain()) ) )
+ {
+ // free resources
+ persColl->releaseAll();
+ delete persColl;
+ persColl=NULL;
+ if( sourceData ) sourceData->deleteRef(); // delete the operand
+
+ // return error
+ RMInit::logOut << "Error: QtInsert::evaluate() - MDD and collection domains are incompatible" << std::endl;
+ parseInfo.setErrorNo(959);
+ throw parseInfo;
+ }
+
+ //
+ // convert a transient MDD object to a persistent one
+ //
+
+ // allocate a new oid within the current db
+ OId oid;
+#ifdef BASEDB_O2
+ if( !OId::allocateMDDOId( &oid ) )
+ {
+#else
+ OId::allocateOId( oid, OId::MDDOID );
+#endif
+ // get all tiles
+ vector<Tile*>* sourceTiles = sourceObj->getTiles();
+
+ // get a persistent type pointer
+ MDDBaseType* persMDDType = (MDDBaseType*)TypeFactory::ensurePersistence( (Type*)sourceObj->getMDDBaseType() );
+
+ if( !persMDDType )
+ {
+ RMInit::logOut << "Error: QtInsert::evaluate() - type not persistent" << std::endl;
+
+ // delete dynamic data
+ if( sourceData ) sourceData->deleteRef();
+ delete sourceTiles;
+ sourceTiles=NULL;
+ delete nextTupel;
+ nextTupel=NULL;
+ persColl->releaseAll();
+ delete persColl;
+ persColl=NULL;
+ parseInfo.setErrorNo(964);
+ throw parseInfo;
+ }
+
+ // create a persistent MDD object
+ // need a StorageLayout here
+ StorageLayout tempStorageLayout;
+ tempStorageLayout.setTileSize(StorageLayout::DefaultTileSize);
+ tempStorageLayout.setIndexType(StorageLayout::DefaultIndexType);
+ tempStorageLayout.setTilingScheme(StorageLayout::DefaultTilingScheme);
+ if (sourceObj->getDefinitionDomain().dimension() ==
+ StorageLayout::DefaultTileConfiguration.dimension())
+ tempStorageLayout.setTileConfiguration(StorageLayout::DefaultTileConfiguration);
+ MDDObj* persMDDObj = new MDDObj( persMDDType, sourceObj->getDefinitionDomain(), oid,
+ tempStorageLayout );
+
+ // iterate over source tiles
+ for( vector<Tile*>::iterator sourceIt = sourceTiles->begin(); sourceIt != sourceTiles->end(); sourceIt++ )
+ {
+ // create a new persistent tile, copy the transient data, and insert it into the target mdd object
+ Tile* newPersTile = new Tile( (*sourceIt)->getDomain(), persMDDType->getBaseType(), (*sourceIt)->getDataFormat() );
+ newPersTile->copyTile( (*sourceIt)->getDomain(), *sourceIt, (*sourceIt)->getDomain() );
+ persMDDObj->insertTile( newPersTile );
+ }
+
+ // delete tile vector
+ delete sourceTiles;
+ sourceTiles=NULL;
+ persColl->insert( persMDDObj );
+#ifdef BASEDB_O2
+ }
+ else
+ {
+ RMInit::logOut << "Error: QtInsert::evaluate() - allocation of oid failed" << std::endl;
+
+ // delete dynamic data
+ if( sourceData ) sourceData->deleteRef();
+ delete nextTupel;
+ nextTupel=NULL;
+ persColl->releaseAll();
+ delete persColl;
+ persColl=NULL;
+ parseInfo.setErrorNo(958);
+ throw parseInfo;
+ }
+#else
+#endif
+ // free transient memory
+ persColl->releaseAll();
+ delete persColl;
+ persColl=NULL;
+ }
+ else
+ RMInit::logOut << "Error: QtInsert::evaluate() - insert data is invalid." << std::endl;
+
+ // delete source operand
+ if( sourceData ) sourceData->deleteRef();
+
+ // delete dummy tupel vector
+ delete nextTupel;
+ nextTupel=NULL;
+
+ return 0;
+}
+
+
+
+QtNode::QtNodeList*
+QtInsert::getChilds( QtChildType flag )
+{
+ QtNodeList* resultList=NULL;
+
+ RMDBGENTER(0, RMDebug::module_qlparser, "QtInsert", "QtInsert::getChilds()")
+
+ if( source )
+ {
+ // allocate resultList
+ if( flag == QT_DIRECT_CHILDS );
+ resultList = new QtNodeList();
+
+ if( flag == QT_LEAF_NODES || flag == QT_ALL_NODES )
+ resultList = source->getChilds( flag );
+
+ // add the nodes of the current level
+ if( flag == QT_DIRECT_CHILDS || flag == QT_ALL_NODES )
+ resultList->push_back( source );
+ }
+ else
+ resultList = new QtNodeList();
+
+
+ RMDBGEXIT(0, RMDebug::module_qlparser, "QtInsert", "QtInsert::getChilds()")
+ return resultList;
+}
+
+
+
+void
+QtInsert::printTree( int tab, std::ostream& s, QtChildType mode )
+{
+ s << SPACE_STR(tab).c_str() << "QtInsert Object" << std::endl;
+
+ if( mode != QtNode::QT_DIRECT_CHILDS )
+ {
+ if( source )
+ {
+ s << SPACE_STR(tab).c_str() << "source : " << std::endl;
+ source->printTree( tab + 2, s );
+ }
+ else
+ s << SPACE_STR(tab).c_str() << "no source" << std::endl;
+
+ s << std::endl;
+ }
+}
+
+
+
+void
+QtInsert::printAlgebraicExpression( std::ostream& s )
+{
+ s << "insert<";
+
+ if( source )
+ source->printAlgebraicExpression( s );
+ else
+ s << "<no source>";
+
+ s << ">";
+}
+
+
+QtOperation*
+QtInsert::getSource()
+{
+ return source;
+}
+
+
+/*
+void
+QtInsert::preOptimize()
+{
+ if( source )
+ source->optimizeLoad( new QtNode::QtTrimList );
+}
+*/
+
+
+void
+QtInsert::checkType()
+{
+ RMDBCLASS( "QtInsert", "checkType()", "qlparser", __FILE__, __LINE__ )
+
+ // check operand branches
+ if( source )
+ {
+
+ // get input type
+ const QtTypeElement& inputType = source->checkType();
+
+ if( inputType.getDataType() != QT_MDD )
+ {
+ RMInit::logOut << "Error: QtInsert::checkType() - insert expression must be of type r_Marray<T>" << std::endl;
+ parseInfo.setErrorNo(960);
+ throw parseInfo;
+ }
+ }
+ else
+ RMInit::logOut << "Error: QtInsert::checkType() - operand branch invalid." << std::endl;
+}
diff --git a/qlparser/qtinsert.hh b/qlparser/qtinsert.hh
new file mode 100644
index 0000000..5c928b9
--- /dev/null
+++ b/qlparser/qtinsert.hh
@@ -0,0 +1,104 @@
+#ifndef __QTINSERT_HH__
+#define __QTINSERT_HH___
+
+#include "qlparser/qtexecute.hh"
+#include "qlparser/qtoperation.hh"
+
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+#endif
+#include <iostream>
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+//@ManMemo: Module: {\bf qlparser}
+
+/**
+
+*/
+
+class QtInsert : public QtExecute
+{
+ public:
+ /// constructor getting name of collection and insert expression
+ QtInsert( const std::string& initCollectionName, QtOperation* initSource );
+
+ /// virtual destructor
+ virtual ~QtInsert();
+
+ /// method for evaluating the node
+ virtual int evaluate();
+
+ /// return childs of the node
+ virtual QtNodeList* getChilds( QtChildType flag );
+
+ /// prints the tree
+ virtual void printTree( int tab, std::ostream& s = std::cout, QtChildType mode = QT_ALL_NODES );
+
+ /// prints the algebraic expression
+ virtual void printAlgebraicExpression( std::ostream& s = std::cout );
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ /// method for query rewrite
+ inline virtual void setInput( QtOperation* child, QtOperation* input);
+
+ /// returns source
+ QtOperation* getSource();
+
+ /// pre optimization
+// virtual void preOptimize();
+ /**
+ Pre-Optimization step is passed to the input streams.
+ */
+
+ /// type checking
+ virtual void checkType();
+
+ private:
+ /// insert expression
+ QtOperation* source;
+
+ /// collection name
+ std::string collectionName;
+
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+#include "qlparser/qtinsert.icc"
+
+#endif
+
+
+
diff --git a/qlparser/qtinsert.icc b/qlparser/qtinsert.icc
new file mode 100644
index 0000000..eb98e55
--- /dev/null
+++ b/qlparser/qtinsert.icc
@@ -0,0 +1,49 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+inline const QtNode::QtNodeType
+QtInsert::getNodeType() const
+{
+ return nodeType;
+}
+
+
+inline void
+QtInsert::setInput( QtOperation* inputOld, QtOperation* inputNew )
+{
+ if( inputOld == source )
+ {
+ source = inputNew;
+
+ if( inputNew )
+ inputNew->setParent( this );
+ }
+};
+
+
diff --git a/qlparser/qtintervaldata.cc b/qlparser/qtintervaldata.cc
new file mode 100644
index 0000000..0d80cc2
--- /dev/null
+++ b/qlparser/qtintervaldata.cc
@@ -0,0 +1,128 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)qlparser, QtIntervalData: $Header: /home/rasdev/CVS-repository/rasdaman/qlparser/qtintervaldata.cc,v 1.10 2005/09/03 20:17:55 rasdev Exp $";
+
+using namespace std;
+
+using namespace std;
+
+#include "qlparser/qtintervaldata.hh"
+
+#include <iostream>
+#include <cstring>
+
+
+QtIntervalData::QtIntervalData( const r_Sinterval& interval )
+ : intervalData(interval), QtData()
+{
+}
+
+
+
+QtDataType
+QtIntervalData::getDataType() const
+{
+ return QT_INTERVAL;
+}
+
+
+
+bool
+QtIntervalData::equal( const QtData* obj ) const
+{
+ int returnValue = false; // not equal by initialization
+
+ if( obj->getDataType() == QT_INTERVAL )
+ returnValue = (intervalData == ((QtIntervalData*)obj)->getIntervalData());
+
+ return returnValue;
+}
+
+
+
+std::string
+QtIntervalData::getSpelling() const
+{
+ std::string result;
+
+ // buffer
+ int bufferLen = 256; // on the save side for two integers plus colon
+ char* buffer = new char[ bufferLen ];
+ // replaced deprecated ostrstream -- PB 2005-jan-14
+ // ostrstream bufferStream( buffer, bufferLen );
+ ostringstream bufferStream( buffer );
+
+ bufferStream << intervalData << std::ends;
+
+ result.append( std::string( buffer ) );
+
+ delete[] buffer;
+ buffer = NULL;
+
+ return result;
+}
+
+
+
+char* QtIntervalData::getTypeStructure() const
+{
+ return strdup("interval");
+}
+
+
+
+void
+QtIntervalData::printStatus( std::ostream& stream ) const
+{
+ stream << "interval, value: " << intervalData << std::flush;
+ QtData::printStatus( stream );
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/qlparser/qtintervaldata.hh b/qlparser/qtintervaldata.hh
new file mode 100644
index 0000000..af4f421
--- /dev/null
+++ b/qlparser/qtintervaldata.hh
@@ -0,0 +1,102 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#ifndef _QTINTERVALDATA_
+#define _QTINTERVALDATA_
+
+#include "qlparser/qtdata.hh"
+
+#include "raslib/sinterval.hh"
+
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+#endif
+
+#include <iostream>
+// removed deprecated ostrstream -- PB 2005-jan-14
+// #include <strstream.h>
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+ The class encapsulates an interval.
+*/
+
+class QtIntervalData : public QtData
+{
+ public:
+ /// constructor getting the interval
+ QtIntervalData( const r_Sinterval& interval );
+
+ //@Man: Read/Write methods:
+ //@{
+ ///
+ ///
+ inline const r_Sinterval& getIntervalData() const;
+ ///
+ inline void setIntervalData( const r_Sinterval& interval );
+
+ /// returns a null-terminated string describing the type structure
+ virtual char* getTypeStructure() const;
+ /**
+ The string pointer has to be free using free() by the caller.
+ */
+
+ ///
+ //@}
+
+ /// returns {\tt QT_INTERVAL}
+ virtual QtDataType getDataType() const;
+
+ /// compares data content
+ virtual bool equal( const QtData* obj ) const;
+
+ /// returns content dependent string representation
+ virtual std::string getSpelling() const;
+
+ /// print status of the object to the specified stream
+ virtual void printStatus( std::ostream& stream = std::cout ) const;
+
+ private:
+ /// prevents from using the default constructor
+ QtIntervalData(){};
+
+ ///
+ r_Sinterval intervalData;
+};
+
+#include "qlparser/qtintervaldata.icc"
+
+#endif
+
+
+
+
diff --git a/qlparser/qtintervaldata.icc b/qlparser/qtintervaldata.icc
new file mode 100644
index 0000000..46e32a1
--- /dev/null
+++ b/qlparser/qtintervaldata.icc
@@ -0,0 +1,42 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+
+inline const r_Sinterval&
+QtIntervalData::getIntervalData() const
+{
+ return intervalData;
+}
+
+
+inline void
+QtIntervalData::setIntervalData( const r_Sinterval& interval )
+{
+ intervalData = interval;
+}
diff --git a/qlparser/qtintervalop.cc b/qlparser/qtintervalop.cc
new file mode 100644
index 0000000..d5884cc
--- /dev/null
+++ b/qlparser/qtintervalop.cc
@@ -0,0 +1,311 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)qlparser, QtIntervalOp: $Header: /home/rasdev/CVS-repository/rasdaman/qlparser/qtintervalop.cc,v 1.13 2003/12/27 20:51:28 rasdev Exp $";
+
+#include "raslib/rmdebug.hh"
+
+#include "qlparser/qtintervalop.hh"
+#include "qlparser/qtdata.hh"
+#include "qlparser/qtintervaldata.hh"
+#include "qlparser/qtstringdata.hh"
+#include "qlparser/qtatomicdata.hh"
+
+#include <iostream>
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+using namespace std;
+#endif
+
+
+const QtNode::QtNodeType QtIntervalOp::nodeType = QT_INTERVALOP;
+
+QtIntervalOp::QtIntervalOp( QtOperation* initInput1, QtOperation* initInput2 )
+ : QtBinaryOperation( initInput1, initInput2 )
+{
+}
+
+
+
+bool
+QtIntervalOp::isCommutative() const
+{
+ return false; // NOT commutative
+}
+
+
+
+QtData*
+QtIntervalOp::evaluate( QtDataList* inputList )
+{
+ QtData* returnValue = NULL;
+ QtData* operand1 = NULL;
+ QtData* operand2 = NULL;
+
+ if( getOperands( inputList, operand1, operand2 ) )
+ {
+ r_Sinterval sinterval;
+
+ switch( operand1->getDataType() )
+ {
+ case QT_LONG:
+ case QT_SHORT:
+ case QT_OCTET:
+ try{
+ sinterval.set_low( (r_Range)(((QtAtomicData*)operand1)->getSignedValue()) );
+ }
+ catch(...)
+ {
+ RMInit::logOut << "Error: QtIntervalOp::evaluate() - interval bound must be of type integer or '*'." << endl;
+ parseInfo.setErrorNo(389);
+
+ // delete the old operands
+ if( operand1 ) operand1->deleteRef();
+ if( operand2 ) operand2->deleteRef();
+
+ throw parseInfo;
+ }
+ break;
+
+ case QT_ULONG:
+ case QT_USHORT:
+ case QT_CHAR:
+ try{
+ sinterval.set_low( (r_Range)((QtAtomicData*)operand1)->getUnsignedValue() );
+ }
+ catch(...)
+ {
+ RMInit::logOut << "Error: QtIntervalOp::evaluate() - interval bound must be of type integer or '*'." << endl;
+ parseInfo.setErrorNo(389);
+
+ // delete the old operands
+ if( operand1 ) operand1->deleteRef();
+ if( operand2 ) operand2->deleteRef();
+
+ throw parseInfo;
+ }
+ break;
+
+ case QT_STRING:
+ QtStringData *p;
+ p = dynamic_cast<QtStringData *>(operand1);
+
+ if (p && (p->getStringData() == string("*")) )
+ sinterval.set_low('*');
+ else
+ {
+ RMInit::logOut << "Error: QtIntervalOp::evaluate() - interval bound must be '*'." << endl;
+ parseInfo.setErrorNo(389);
+
+ // delete the old operands
+ if( operand1 ) operand1->deleteRef();
+ if( operand2 ) operand2->deleteRef();
+
+ throw parseInfo;
+ }
+ break;
+
+ default:
+ RMInit::logOut << "Error: QtIntervalOp::evaluate() - interval bound must be of type integer or '*'." << endl;
+ parseInfo.setErrorNo(388);
+
+ // delete the old operands
+ if( operand1 ) operand1->deleteRef();
+ if( operand2 ) operand2->deleteRef();
+
+ throw parseInfo;
+ }
+
+
+ switch( operand2->getDataType() )
+ {
+ case QT_LONG:
+ case QT_SHORT:
+ case QT_OCTET:
+ try{
+ sinterval.set_high( (r_Range)(((QtAtomicData*)operand2)->getSignedValue()) );
+ }
+ catch(...)
+ {
+ RMInit::logOut << "Error: QtIntervalOp::evaluate() - interval bound must be of type integer or '*'." << endl;
+ parseInfo.setErrorNo(389);
+
+ // delete the old operands
+ if( operand1 ) operand1->deleteRef();
+ if( operand2 ) operand2->deleteRef();
+
+ throw parseInfo;
+ }
+ break;
+
+ case QT_ULONG:
+ case QT_USHORT:
+ case QT_CHAR:
+ try{
+ sinterval.set_high( (r_Range)((QtAtomicData*)operand2)->getUnsignedValue() );
+ }
+ catch(...)
+ {
+ RMInit::logOut << "Error: QtIntervalOp::evaluate() - interval bound must be of type integer or '*'." << endl;
+ parseInfo.setErrorNo(389);
+ // delete the old operands
+ if( operand1 ) operand1->deleteRef();
+ if( operand2 ) operand2->deleteRef();
+
+ throw parseInfo;
+ }
+ break;
+
+ case QT_STRING:
+ QtStringData *p;
+ p = dynamic_cast<QtStringData *>(operand2);
+
+ if (p && (p->getStringData() == string("*")) )
+ sinterval.set_high('*');
+ else
+ {
+ RMInit::logOut << "Error: QtIntervalOp::evaluate() - interval bound must be '*'." << endl;
+ parseInfo.setErrorNo(389);
+
+ // delete the old operands
+ if( operand1 ) operand1->deleteRef();
+ if( operand2 ) operand2->deleteRef();
+
+ throw parseInfo;
+ }
+ break;
+
+ default:
+ RMInit::logOut << "Error: QtIntervalOp::evaluate() - interval bound must be of type integer or '*'." << endl;
+ parseInfo.setErrorNo(388);
+
+ // delete the old operands
+ if( operand1 ) operand1->deleteRef();
+ if( operand2 ) operand2->deleteRef();
+
+ throw parseInfo;
+ }
+
+ returnValue = new QtIntervalData( sinterval );
+
+ // delete the old operands
+ if( operand1 ) operand1->deleteRef();
+ if( operand2 ) operand2->deleteRef();
+ }
+
+ return returnValue;
+}
+
+
+
+void
+QtIntervalOp::printTree( int tab, ostream& s, QtChildType mode )
+{
+ s << SPACE_STR(tab).c_str() << "QtIntervalOp Object " << getNodeType() << endl;
+
+ QtBinaryOperation::printTree( tab, s, mode );
+}
+
+
+
+void
+QtIntervalOp::printAlgebraicExpression( ostream& s )
+{
+ s << "(";
+
+ if( input1 )
+ input1->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << ":";
+
+ if( input2 )
+ input2->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << ")";
+}
+
+
+
+const QtTypeElement&
+QtIntervalOp::checkType( QtTypeTuple* typeTuple )
+{
+ RMDBCLASS( "QtIintervalOp", "checkType( QtTypeTuple* )", "qlparser", __FILE__, __LINE__ )
+
+ dataStreamType.setDataType( QT_TYPE_UNKNOWN );
+
+ // check operand branches
+ if( input1 && input2 )
+ {
+
+ const QtTypeElement& input1Type = input1->checkType( typeTuple );
+ const QtTypeElement& input2Type = input2->checkType( typeTuple );
+
+ bool opTypesValid = true;
+
+ // check operand1
+ opTypesValid &= input1Type.getDataType() == QT_STRING ||
+ input1Type.getDataType() == QT_LONG ||
+ input1Type.getDataType() == QT_SHORT ||
+ input1Type.getDataType() == QT_OCTET ||
+ input1Type.getDataType() == QT_ULONG ||
+ input1Type.getDataType() == QT_USHORT ||
+ input1Type.getDataType() == QT_CHAR;
+
+ // check operand2
+ opTypesValid &= input2Type.getDataType() == QT_STRING ||
+ input2Type.getDataType() == QT_LONG ||
+ input2Type.getDataType() == QT_SHORT ||
+ input2Type.getDataType() == QT_OCTET ||
+ input2Type.getDataType() == QT_ULONG ||
+ input2Type.getDataType() == QT_USHORT ||
+ input2Type.getDataType() == QT_CHAR;
+
+ if( !opTypesValid )
+ {
+ RMInit::logOut << "Error: QtIntervalOp::evaluate() - interval bound must be of type integer or '*'." << endl;
+ parseInfo.setErrorNo(389);
+ throw parseInfo;
+ }
+
+ dataStreamType.setDataType( QT_INTERVAL );
+ }
+ else
+ RMInit::logOut << "Error: QtIntervalOp::checkType() - input branch invalid." << endl;
+
+ return dataStreamType;
+}
diff --git a/qlparser/qtintervalop.hh b/qlparser/qtintervalop.hh
new file mode 100644
index 0000000..de43b78
--- /dev/null
+++ b/qlparser/qtintervalop.hh
@@ -0,0 +1,84 @@
+#ifndef _QTINTERVALOP_
+#define _QTINTERVALOP_
+
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+#endif
+
+#include "qlparser/qtbinaryoperation.hh"
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+ The class represents the root of an interval expression.
+
+*/
+
+class QtIntervalOp : public QtBinaryOperation
+{
+ public:
+ /// constructor getting the two operands
+ QtIntervalOp( QtOperation* input1, QtOperation* input2 );
+
+ /// returns FALSE saying that the operation IS NOT commutative
+ virtual bool isCommutative() const;
+
+ /// method for evaluating the node
+ QtData* evaluate( QtDataList* inputList );
+ /**
+ */
+
+ /// prints the tree
+ virtual void printTree( int tab, std::ostream& s = std::cout, QtChildType mode = QT_ALL_NODES );
+
+ /// prints the algebraic expression
+ virtual void printAlgebraicExpression( std::ostream& s = std::cout );
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ /// type checking of the subtree
+ virtual const QtTypeElement& checkType( QtTypeTuple* typeTuple = NULL );
+
+ private:
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+
+#include "qlparser/qtintervalop.icc"
+
+#endif
+
diff --git a/qlparser/qtintervalop.icc b/qlparser/qtintervalop.icc
new file mode 100644
index 0000000..331e0f0
--- /dev/null
+++ b/qlparser/qtintervalop.icc
@@ -0,0 +1,34 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+inline const QtNode::QtNodeType
+QtIntervalOp::getNodeType() const
+{
+ return nodeType;
+}
diff --git a/qlparser/qtiterator.cc b/qlparser/qtiterator.cc
new file mode 100644
index 0000000..ef0615f
--- /dev/null
+++ b/qlparser/qtiterator.cc
@@ -0,0 +1,260 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)qlparser, QtIterator: $Id: qtiterator.cc,v 1.20 2001/08/14 10:48:17 rastest Exp $";
+
+#include "qlparser/qtiterator.hh"
+#include <iostream>
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+using namespace std;
+#endif
+
+const QtNode::QtNodeType QtIterator::nodeType = QtNode::QT_ITERATOR;
+
+QtIterator::QtIterator()
+ : QtONCStream(),
+ inputs(NULL)
+{
+}
+
+
+QtIterator::QtIterator( QtNode* node )
+ : QtONCStream( node ),
+ inputs(NULL)
+{
+}
+
+
+QtIterator::~QtIterator()
+{
+ if( inputs )
+ {
+ // delete the inputs
+ for( int i=0; i<inputs->size(); i++ )
+ {
+ delete (*inputs)[i];
+ (*inputs)[i] = NULL;
+ }
+
+ // delete the list
+ delete inputs;
+ inputs=NULL;
+ }
+}
+
+
+QtNode::QtNodeList*
+QtIterator::getChilds( QtChildType flag )
+{
+ QtNodeList* resultList=NULL;
+ list<QtNode*>::iterator it; //default
+ QtNode::QtNodeList::iterator iter;
+
+ RMDBCLASS( "QtIterator", "getChilds( QtChildType )", "qlparser", __FILE__, __LINE__ )
+
+ // allocate resultList
+ resultList = new QtNodeList();
+
+ if( flag == QT_LEAF_NODES || flag == QT_ALL_NODES )
+ {
+ for(int i=0; i<inputs->size(); i++ )
+ {
+ QtNodeList* subList=NULL;
+ subList = (*inputs)[i]->getChilds( flag );
+ // remove all elements in subList and insert them at the beginning in resultList
+ resultList->splice( resultList->begin(), *subList );
+ // delete temporary subList
+ delete subList;
+ subList=NULL;
+ };
+ };
+
+ // add the nodes of the current level
+ if( flag == QT_DIRECT_CHILDS || flag == QT_ALL_NODES )
+ for(int i=0; i<inputs->size(); i++ )
+ resultList->push_back( (*inputs)[i] );
+
+ return resultList;
+}
+
+
+void
+QtIterator::open()
+{
+ RMDBCLASS( "QtIterator", "open()", "qlparser", __FILE__, __LINE__ )
+
+ if( inputs )
+ {
+ QtONCStreamList::iterator i;
+
+ for( i=inputs->begin(); i!=inputs->end(); i++ )
+ (*i)->open();
+ }
+}
+
+
+void
+QtIterator::close()
+{
+ RMDBCLASS( "QtIterator", "close()", "qlparser", __FILE__, __LINE__ )
+
+ if( inputs )
+ {
+ QtONCStreamList::iterator i;
+
+ for( i=inputs->begin(); i!=inputs->end(); i++ )
+ (*i)->close();
+ }
+}
+
+
+void
+QtIterator::reset()
+{
+ if( inputs )
+ {
+ QtONCStreamList::iterator i;
+
+ for( i=inputs->begin(); i!=inputs->end(); i++ )
+ (*i)->reset();
+ }
+}
+
+
+void
+QtIterator::printTree( int tab, ostream& s, QtChildType mode )
+{
+ if( mode != QtNode::QT_DIRECT_CHILDS )
+ {
+ if( inputs )
+ for( int i=0; i<inputs->size(); i++ )
+ {
+ s << SPACE_STR(tab).c_str() << "input " << i+1 << ": " << endl;
+ (*inputs)[i]->printTree( tab+2, s, mode );
+ }
+ else
+ s << SPACE_STR(tab).c_str() << "no inputs" << endl;
+
+ s << endl;
+ }
+}
+
+
+
+void
+QtIterator::printAlgebraicExpression( ostream& s )
+{
+ if( inputs )
+ {
+ s << "( ";
+
+ for( int i=0; i<inputs->size(); i++ )
+ {
+ (*inputs)[i]->printAlgebraicExpression( s );
+
+ if( i < inputs->size()-1 )
+ s << ", ";
+ }
+
+ s << " )";
+ }
+ else
+ s << "(<no input>)";
+}
+
+
+
+void
+QtIterator::setStreamInput( QtONCStream* oldInput, QtONCStream* newInput )
+{
+ QtONCStreamList::iterator iter;
+ bool notDone=true;
+
+ for( iter=inputs->begin(); iter!=inputs->end() && notDone; iter++ )
+ if( *iter && (*iter) == oldInput )
+ {
+ *iter = newInput;
+ if( newInput )
+ newInput->setParent( this );
+
+ notDone = false;
+ }
+
+ if( notDone )
+ RMInit::logOut << "QtIterator::setStreamInput() - Error: Old input stream not found." << endl;
+}
+
+QtIterator::QtONCStreamList*
+QtIterator::getStreamInputs()
+{
+ return inputs;
+}
+
+/*
+void
+QtIterator::preOptimize()
+{
+ if( inputs )
+ {
+ QtONCStreamList::iterator i;
+
+ for( i=inputs->begin(); i!=inputs->end(); i++ )
+ (*i)->preOptimize();
+ }
+}
+*/
+
+
+void
+QtIterator::getInputTypeTuple( QtTypeTuple& typeTuple )
+{
+ typeTuple = QtTypeTuple(0);
+
+ if( inputs )
+ {
+ QtONCStreamList::iterator inputIter;
+
+ for( inputIter=inputs->begin(); inputIter!=inputs->end(); inputIter++ )
+ {
+ if( *inputIter )
+ typeTuple.concat( (*inputIter)->checkType() );
+ else
+ RMInit::logOut << "Error: QtIterator::getInputTypeTuple() - input branch is invalid." << endl;
+ }
+ }
+ else
+ RMInit::logOut << "Error: QtIterator::getInputTypeTuple() - inputs branch is invalid." << endl;
+}
+
diff --git a/qlparser/qtiterator.hh b/qlparser/qtiterator.hh
new file mode 100644
index 0000000..d2fad41
--- /dev/null
+++ b/qlparser/qtiterator.hh
@@ -0,0 +1,118 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#ifndef _QTITERATOR_
+#define _QTITERATOR_
+
+#include "qlparser/qtoncstream.hh"
+
+#include <vector>
+
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+It is super class for every class capable of iterating over collections of MDD.
+It has a list of inputs of type QtONCStream, so every instance of type
+QtONCStream or of a subtype of it can serve as an input stream for a QtIterator
+object. The input streams can be combined differently, as cross product of the
+inputs in class QtSelectionIterator or as simple tupels in the order they occure
+in the input streams in class QtOperationIterator.
+
+*/
+
+class QtIterator : public QtONCStream
+{
+ public:
+ /// list of QtONCStream objects
+ typedef std::vector<QtONCStream*> QtONCStreamList;
+
+ /// default constructor
+ QtIterator();
+
+ /// constructor getting a pointer to the parent
+ QtIterator( QtNode* node );
+
+ /// destructor
+ virtual ~QtIterator();
+
+ /// return childs of the node
+ virtual QtNodeList* getChilds( QtChildType flag );
+
+ /// prints the tree
+ virtual void printTree( int tab, std::ostream& s = std::cout, QtChildType mode = QT_ALL_NODES );
+
+ /// prints the algebraic expression
+ virtual void printAlgebraicExpression( std::ostream& s = std::cout );
+
+ //@Man: Operations of the ONC protocol
+ //@{
+ ///
+ virtual void open();
+ ///
+ virtual void close();
+ ///
+ virtual void reset();
+ //@}
+
+ //@Man: Read/Write methods:
+ //@{
+ ///
+ inline void setStreamInputs( QtONCStreamList* inputs );
+
+ /// Returns inputs
+ QtONCStreamList* getStreamInputs();
+ /// exchange the stream input {\tt oldInput} with {\tt newInput}
+ void setStreamInput( QtONCStream* oldInput, QtONCStream* newInput );
+ ///
+ //inline virtual void setParents();
+ //@}
+
+ /// pre optimization
+ //virtual void preOptimize();
+ /**
+ Pre-Optimization step is passed to the input streams.
+ */
+
+ /// get input type tuple
+ void getInputTypeTuple( QtTypeTuple& typeTuple );
+
+ protected:
+ /// list of input streams
+ QtONCStreamList* inputs;
+
+ private:
+ /// atribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+#include "qlparser/qtiterator.icc"
+
+#endif
+
diff --git a/qlparser/qtiterator.icc b/qlparser/qtiterator.icc
new file mode 100644
index 0000000..ede86ed
--- /dev/null
+++ b/qlparser/qtiterator.icc
@@ -0,0 +1,36 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+inline void
+QtIterator::setStreamInputs( QtONCStreamList* inputsNew )
+{
+ inputs = inputsNew;
+ for( int i=0; i<inputs->size(); i++ )
+ (*inputs)[i]->setParent( this );
+};
diff --git a/qlparser/qtjoiniterator.cc b/qlparser/qtjoiniterator.cc
new file mode 100644
index 0000000..12277ab
--- /dev/null
+++ b/qlparser/qtjoiniterator.cc
@@ -0,0 +1,338 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+
+#include "raslib/rmdebug.hh"
+
+#include "qlparser/qtjoiniterator.hh"
+#include "qlparser/qtmdd.hh"
+
+#include <iostream>
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+using namespace std;
+#endif
+
+const QtNode::QtNodeType QtJoinIterator::nodeType = QtNode::QT_JOIN_ITERATOR;
+
+
+QtJoinIterator::QtJoinIterator()
+ : QtIterator(),
+ actualTupel(NULL),
+ outputStreamIsEmpty(false)
+{
+}
+
+
+QtJoinIterator::QtJoinIterator( QtNode* node )
+ : QtIterator( node ),
+ actualTupel(NULL),
+ outputStreamIsEmpty(false)
+{
+}
+
+
+QtJoinIterator::~QtJoinIterator()
+{
+ vector<QtData*>::iterator i; //default
+
+ if( actualTupel )
+ {
+ // first delete still existing data carriers
+ for( QtDataList::iterator iter=actualTupel->begin(); iter!=actualTupel->end(); iter++ )
+ if( *iter ) (*iter)->deleteRef();
+
+ delete actualTupel;
+ actualTupel=NULL;
+ }
+}
+
+
+void
+QtJoinIterator::printTree( int tab, ostream& s, QtChildType mode )
+{
+ s << SPACE_STR(tab).c_str() << "QtJoinIterator Object: type " << flush;
+ dataStreamType.printStatus( s );
+ s << endl;
+
+ QtIterator::printTree( tab, s, mode );
+}
+
+
+
+void
+QtJoinIterator::printAlgebraicExpression( ostream& s )
+{
+ s << "join";
+
+ QtIterator::printAlgebraicExpression( s );
+}
+
+
+void
+QtJoinIterator::open()
+{
+ RMDBCLASS( "QtJoinIterator", "open()", "qlparser", __FILE__, __LINE__ )
+
+ QtIterator::open();
+
+ outputStreamIsEmpty = false; // initialization
+
+ if( inputs )
+ {
+ // The idea of actualTupel initialization:
+ //
+ // tupel[0] tupel[1] tupel[2] ... |
+ // -----------------------------------------------------
+ // 0 0 0 | initial phase
+ // 0 b1 c1 | open
+ // a1 b1 c1 | next invocation
+ // a2 b1 c1 | "
+ // a1 b2 c1 | "
+ // : : : | "
+
+ // allocate an empty tupel, right now each input stream provides one data element
+ actualTupel = new QtDataList( inputs->size() );
+
+ // set the first element of the tupel to NULL
+ (*actualTupel)[0] = NULL;
+
+ // fill the tupel, except of the first element, with the first elements of the input streams
+ //the first element is filled in the ::next() method
+ for( int tupelPos=1; tupelPos<actualTupel->size(); tupelPos++ )
+ {
+ QtDataList* resultList = (*inputs)[tupelPos]->next();
+
+ if( resultList )
+ {
+ // take the first data element of the input stream result
+ (*actualTupel)[tupelPos] = (*resultList)[0];
+
+ // delete the result vector (only the first data carriers is taken, the others are never deleted)
+ delete resultList;
+ resultList = NULL;
+ }
+ else
+ {
+ // In that case, one of the input streams is empty. Therefore, the output stream of
+ // the self object is empty either.
+ (*actualTupel)[tupelPos] = NULL;
+ outputStreamIsEmpty = true;
+ }
+ }
+
+ // Reset the first stream again, because the first tupel element is catched when next() is
+ // called for the first time.
+ // (*inputs)[0]->reset();
+ }
+}
+
+
+QtNode::QtDataList*
+QtJoinIterator::next()
+{
+ RMDBCLASS( "QtJoinIterator", "next()", "qlparser", __FILE__, __LINE__ )
+
+
+ QtDataList* returnValue = NULL;
+
+ if( inputs && actualTupel && !outputStreamIsEmpty )
+ {
+ bool nextTupelAvailable = true;
+ bool nextTupelValid = false;
+ int tupelPos;
+ QtDataList* resultList = NULL;
+ QtONCStreamList::iterator iter;
+
+ while( !nextTupelValid && nextTupelAvailable && !outputStreamIsEmpty )
+ {
+ // switch to the next tupel which means
+
+ nextTupelAvailable = false;
+ tupelPos = 0;
+ iter = inputs->begin();
+
+ while( !nextTupelAvailable && iter!=inputs->end() )
+ {
+ resultList = (*iter)->next();
+
+ // Test, if the first input stream is empty, because this is not tested in open()
+ if( resultList == NULL && tupelPos==0 && (*actualTupel)[0] == 0 )
+ outputStreamIsEmpty = true;
+
+ if( resultList == NULL )
+ {
+ (*iter)->reset(); // reset the stream ...
+ //this causes the first element of the list to be deleted - not the others
+ resultList = (*iter)->next(); // ... and read the first element again
+ // this was commented out because it will cause problems when the stream is closed
+ // if it is commented out it will break join queries
+ }
+ else
+ nextTupelAvailable = true;
+
+ //
+ // exchange the actual element in the tupel
+ //
+
+ // delete the data carrier
+ if( (*actualTupel)[tupelPos] )
+ {
+ (*actualTupel)[tupelPos]->deleteRef();
+ (*actualTupel)[tupelPos] = NULL;
+ }
+
+ if( resultList )
+ {
+ // take the first data element of the input stream result - copy the data carrier pointer
+ (*actualTupel)[tupelPos] = (*resultList)[0];
+
+ // delete the result vector (only the first data carrier is taken, the others are never deleted)
+ delete resultList;
+ resultList = NULL;
+ }
+
+ iter++;
+ tupelPos++;
+ }
+
+ if( nextTupelAvailable )
+ nextTupelValid = true;
+ }
+
+ if( nextTupelAvailable )
+ {
+ // Copy the actual tupel in order to pass it as the next stream element
+ // which means increase references to data elements.
+ returnValue = new QtDataList( actualTupel->size() );
+
+ for( tupelPos=0; tupelPos < actualTupel->size(); tupelPos++ )
+ if( (*actualTupel)[tupelPos] )
+ {
+ (*returnValue)[tupelPos] = (*actualTupel)[tupelPos];
+ (*actualTupel)[tupelPos]->incRef();
+ }
+ else
+ {
+ // should not come here, because now the next tupel isn't valid
+
+ // delete return value again
+ for( tupelPos=0; tupelPos < returnValue->size(); tupelPos++ )
+ if( (*returnValue)[tupelPos] )
+ (*returnValue)[tupelPos]->deleteRef();
+
+ delete returnValue;
+ returnValue = NULL;
+
+ RMInit::logOut << "Internal Error in QtJoinIterator::next()" << endl;
+ }
+ }
+ }
+
+ return returnValue;
+}
+
+
+
+void
+QtJoinIterator::close()
+{
+ RMDBCLASS( "QtJoinIterator", "close()", "qlparser", __FILE__, __LINE__ )
+
+ if( actualTupel )
+ {
+ // first delete still existing data carriers
+ for( QtDataList::iterator iter=actualTupel->begin(); iter!=actualTupel->end(); iter++ )
+ if( *iter ) (*iter)->deleteRef();
+
+ delete actualTupel;
+ actualTupel = NULL;
+ }
+
+ QtIterator::close();
+}
+
+
+void
+QtJoinIterator::reset()
+{
+ RMDBCLASS( "QtJoinIterator", "reset()", "qlparser", __FILE__, __LINE__ )
+
+ // reset the input streams
+ QtIterator::reset();
+
+ if( inputs )
+ {
+ // first delete still existing data carriers
+ for( QtDataList::iterator iter=actualTupel->begin(); iter!=actualTupel->end(); iter++ )
+ if( *iter )
+ {
+ (*iter)->deleteRef();
+ (*iter) = NULL;
+ }
+
+ // fill the tupel with the first elements of the input streams except of the first element
+ for( int tupelPos=1; tupelPos<actualTupel->size(); tupelPos++ )
+ {
+ QtDataList* resultList = (*inputs)[tupelPos]->next();
+
+ if( resultList )
+ {
+ // take the first data element of the input stream result
+ (*actualTupel)[tupelPos] = (*resultList)[0];
+
+ // delete the result vector (only the first data carriers is taken, the others are never deleted)
+ delete resultList;
+ resultList = NULL;
+ }
+ else
+ (*actualTupel)[tupelPos] = NULL;
+
+ }
+
+ (*actualTupel)[0] = NULL; // fist tupel element is catched when next() is called for the first time
+ }
+}
+
+
+
+const QtTypeTuple&
+QtJoinIterator::checkType()
+{
+ RMDBCLASS( "QtJoinIterator", "checkType()", "qlparser", __FILE__, __LINE__ )
+
+ getInputTypeTuple( dataStreamType );
+
+ return dataStreamType;
+}
diff --git a/qlparser/qtjoiniterator.hh b/qlparser/qtjoiniterator.hh
new file mode 100644
index 0000000..ca1403f
--- /dev/null
+++ b/qlparser/qtjoiniterator.hh
@@ -0,0 +1,120 @@
+#ifndef _QTJOINITERATOR_
+#define _QTJOINITERATOR_
+
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+#endif
+
+#include "qlparser/qtiterator.hh"
+#include "qlparser/qtoperation.hh"
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+An object of this class takes its inputs and computes a tupel for every element
+of the cross product. The result is passed to the output stream.
+The class represents the FROM part of a query.
+
+*/
+
+class QtJoinIterator : public QtIterator
+{
+ public:
+ /// default constructor
+ QtJoinIterator();
+
+ /// constructor getting a pointer to the parent
+ QtJoinIterator( QtNode* node );
+
+ /// virtual destructor
+ virtual ~QtJoinIterator();
+
+ /// prints the tree
+ virtual void printTree( int tab, std::ostream& s = std::cout, QtChildType mode = QT_ALL_NODES );
+
+ /// prints the algebraic expression
+ virtual void printAlgebraicExpression( std::ostream& s = std::cout );
+
+ //@Man: Operations of the ONC protocol:
+ //@{
+ ///
+ void open();
+ ///
+ QtDataList* next();
+ /**
+ According to the producer/consumer protocol of ONC streams, the {/tt next()}
+ method has to store the last tupel of the crossproduct and update it with a new
+ element everytime it is invoked. Than it makes a copy of the tupel and pass
+ it to the caller.
+ */
+ ///
+ void close();
+ ///
+ void reset();
+ ///
+ //@}
+
+ //@Man: Read/Write methods:
+ //@{
+ ///
+ //inline virtual void setParents();
+ //@}
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ /// type checking
+ virtual const QtTypeTuple& checkType();
+
+ private:
+ /// inidicates if the output stream is empty or not
+ bool outputStreamIsEmpty;
+ /** The output stream is empty if at least one of the input streams is empty.
+ In that case, the cross product has no elements. This is indicated
+ by the variable {\tt outputStreamIsEmpty} which is set in the method
+ {\tt open()}.
+ */
+
+ /// pointer to a copy of the last passed tupel
+ QtDataList* actualTupel;
+
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+#include "qlparser/qtjoiniterator.icc"
+
+#endif
+
diff --git a/qlparser/qtjoiniterator.icc b/qlparser/qtjoiniterator.icc
new file mode 100644
index 0000000..741c048
--- /dev/null
+++ b/qlparser/qtjoiniterator.icc
@@ -0,0 +1,35 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+inline const QtNode::QtNodeType
+QtJoinIterator::getNodeType() const
+{
+ return nodeType;
+}
+
diff --git a/qlparser/qtmarrayop.cc b/qlparser/qtmarrayop.cc
new file mode 100644
index 0000000..dbcbc84
--- /dev/null
+++ b/qlparser/qtmarrayop.cc
@@ -0,0 +1,314 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)qlparser, QtMarrayOp: $Header: /home/rasdev/CVS-repository/rasdaman/qlparser/qtmarrayop.cc,v 1.19 2003/12/27 20:51:28 rasdev Exp $";
+
+#include "raslib/rmdebug.hh"
+
+#include "qlparser/qtmarrayop.hh"
+#include "qlparser/qtdata.hh"
+#include "qlparser/qtmdd.hh"
+#include "qlparser/qtpointdata.hh"
+#include "qlparser/qtmintervaldata.hh"
+
+#include "mddmgr/mddobj.hh"
+#include "tilemgr/tile.hh"
+
+#include "catalogmgr/typefactory.hh"
+
+#include "catalogmgr/algebraops.hh"
+
+#include <iostream>
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+using namespace std;
+#endif
+
+
+const QtNode::QtNodeType QtMarrayOp::nodeType = QT_MARRAYOP;
+
+QtMarrayOp::QtMarrayOp( const string &initIteratorName, QtOperation* mintervalExp, QtOperation* cellExp )
+ : iteratorName( initIteratorName ), QtBinaryOperation( mintervalExp, cellExp )
+{
+}
+
+
+
+void
+QtMarrayOp::optimizeLoad( QtTrimList* trimList )
+{
+ RMDBCLASS( "QtMarrayOp", "optimizeLoad( QtTrimList* )", "qlparser", __FILE__, __LINE__ )
+
+ // delete the trimList and optimize subtrees
+
+ // release( trimList->begin(), trimList->end() );
+ for( QtNode::QtTrimList::iterator iter=trimList->begin(); iter!=trimList->end(); iter++ )
+ {
+ delete *iter;
+ *iter=NULL;
+ }
+ delete trimList;
+ trimList=NULL;
+
+ QtBinaryOperation::optimizeLoad( new QtNode::QtTrimList() );
+}
+
+
+
+bool
+QtMarrayOp::isCommutative() const
+{
+ return false; // NOT commutative
+}
+
+
+
+QtData*
+QtMarrayOp::evaluate( QtDataList* inputList )
+{
+ RMDBCLASS( "QtMarrayOp", "evaluate( QtDataList* )", "qlparser", __FILE__, __LINE__ )
+
+ QtData* returnValue = NULL;
+ QtData* operand1 = NULL;
+
+ if( getOperand( inputList, operand1, 1 ) )
+ {
+
+#ifdef QT_RUNTIME_TYPE_CHECK
+ if( operand1->getDataType() != QT_MINTERVAL )
+ RMInit::logOut << "Internal error in QtMarrayOp::evaluate() - "
+ << "runtime type checking failed (Minterval)." << endl;
+
+ // delete old operand
+ if( operand1 ) operand1->deleteRef();
+
+ return 0;
+ }
+#endif
+
+ r_Minterval domain = ((QtMintervalData*)operand1)->getMintervalData();
+
+ RMDBGONCE( 4, RMDebug::module_qlparser, "QtMarrayOp", "Marray domain " << domain )
+
+ //
+ // add point data with its iterator name to the input list
+ //
+
+ // create a QtPointData object with corner point
+ QtPointData* point = new QtPointData( domain.get_origin() );
+ // set its iterator name
+ point->setIteratorName( iteratorName );
+ // if the list of binding variables is empty, create a new one and delete it afterwards
+ bool newInputList = false;
+ if( !inputList )
+ {
+ inputList = new QtDataList();
+ newInputList = true;
+ }
+ // add it to the list
+ inputList->push_back( point );
+
+ // determine types
+ BaseType* cellType = (BaseType*) input2->getDataStreamType().getType();
+ MDDBaseType* mddBaseType = (MDDBaseType*)dataStreamType.getType();
+
+ // create tile for result
+ Tile* resTile = new Tile( domain, cellType );
+
+ // create execution object QLArrayOp
+ QLMarrayOp* qlMarrayOp = new QLMarrayOp( input2, inputList, iteratorName, cellType );
+
+ try
+ {
+ // execute query engine marray operation
+ resTile->execMarrayOp( qlMarrayOp, domain, domain );
+ }
+ catch(...)
+ {
+ // free ressources
+ delete qlMarrayOp;
+ qlMarrayOp=NULL;
+ delete resTile;
+ resTile=NULL;
+
+ // remove point data object from inputList again
+ inputList->back()->deleteRef();
+ inputList->pop_back();
+ if( newInputList )
+ {
+ delete inputList;
+ inputList=NULL;
+ }
+
+ if( operand1 ) operand1->deleteRef();
+
+ throw;
+ }
+
+ // delete execution object again
+ delete qlMarrayOp;
+ qlMarrayOp=NULL;
+
+ // remove point data object from inputList again
+ inputList->back()->deleteRef();
+ inputList->pop_back();
+ if( newInputList )
+ {
+ delete inputList;
+ inputList=NULL;
+ }
+ // create MDDObj for result
+ MDDObj* mddres = new MDDObj( mddBaseType, domain );
+
+ // insert Tile in result mdd
+ mddres->insertTile( resTile );
+
+ // create a new QtMDD object as carrier object for the transient MDD object
+ returnValue = new QtMDD( (MDDObj*)mddres );
+
+ // delete old operands
+ if( operand1 ) operand1->deleteRef();
+ }
+
+ return returnValue;
+}
+
+
+
+void
+QtMarrayOp::printTree( int tab, ostream& s, QtChildType mode )
+{
+ s << SPACE_STR(tab).c_str() << "QtMarrayOp Object " << getNodeType() << endl;
+
+ s << SPACE_STR(tab).c_str() << "Iterator Name: " << iteratorName.c_str() << endl;
+
+ QtBinaryOperation::printTree( tab, s, mode );
+}
+
+
+
+void
+QtMarrayOp::printAlgebraicExpression( ostream& s )
+{
+ s << "(";
+
+ s << iteratorName.c_str() << ",";
+
+ if( input1 )
+ input1->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << ",";
+
+ if( input2 )
+ input2->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << ")";
+}
+
+
+
+const QtTypeElement&
+QtMarrayOp::checkType( QtTypeTuple* typeTuple )
+{
+ RMDBCLASS( "QtMarrayOp", "checkType( QtTypeTuple* )", "qlparser", __FILE__, __LINE__ )
+
+ dataStreamType.setDataType( QT_TYPE_UNKNOWN );
+
+ // check operand branches
+ if( input1 && input2 )
+ {
+
+ // check domain expression
+ const QtTypeElement& domainExp = input1->checkType( typeTuple );
+
+ if( domainExp.getDataType() != QT_MINTERVAL )
+ {
+ RMInit::logOut << "Error: QtMarrayOp::checkType() - Can not evaluate domain expression to an minterval." << endl;
+ parseInfo.setErrorNo(401);
+ throw parseInfo;
+ }
+
+ //
+ // check value expression
+ //
+
+ // add domain iterator to the list of bounded variables
+ bool newList = false;
+ if( !typeTuple )
+ {
+ typeTuple = new QtTypeTuple();
+ newList = true;
+ }
+ typeTuple->tuple.push_back( QtTypeElement( QT_POINT, iteratorName.c_str() ) );
+
+ // get type
+ const QtTypeElement& valueExp = input2->checkType( typeTuple );
+
+ // remove iterator again
+ typeTuple->tuple.pop_back();
+ if( newList )
+ {
+ delete typeTuple;
+ typeTuple = NULL;
+ }
+
+ // check type
+ if( valueExp.getDataType() != QT_BOOL && valueExp.getDataType() != QT_COMPLEX &&
+ valueExp.getDataType() != QT_CHAR && valueExp.getDataType() != QT_OCTET &&
+ valueExp.getDataType() != QT_USHORT && valueExp.getDataType() != QT_SHORT &&
+ valueExp.getDataType() != QT_ULONG && valueExp.getDataType() != QT_LONG &&
+ valueExp.getDataType() != QT_FLOAT && valueExp.getDataType() != QT_DOUBLE &&
+ valueExp.getDataType() != QT_COMPLEXTYPE1 && valueExp.getDataType() != QT_COMPLEXTYPE2 )
+ {
+ RMInit::logOut << "Error: QtMarrayOp::checkType() - Value expression must be either of type atomic or complex." << endl;
+ parseInfo.setErrorNo(412);
+ throw parseInfo;
+ }
+
+ // create MDD type
+ BaseType* cellType = (BaseType*)valueExp.getType();
+ MDDBaseType* mddBaseType = new MDDBaseType( "tmp", cellType );
+ TypeFactory::addTempType( mddBaseType );
+
+ dataStreamType.setType( mddBaseType );
+ }
+ else
+ RMInit::logOut << "Error: QtMarrayOp::checkType() - operand branch invalid." << endl;
+
+ return dataStreamType;
+}
diff --git a/qlparser/qtmarrayop.hh b/qlparser/qtmarrayop.hh
new file mode 100644
index 0000000..98b651c
--- /dev/null
+++ b/qlparser/qtmarrayop.hh
@@ -0,0 +1,90 @@
+#ifndef _QTMARRAYOP_
+#define _QTMARRAYOP_
+
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+#endif
+
+#include "qlparser/qtbinaryoperation.hh"
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+ The class represents the root of an marray expression.
+
+*/
+
+class QtMarrayOp : public QtBinaryOperation
+{
+ public:
+ /// constructor getting iterator, minterval expression, and cell expression
+ QtMarrayOp( const std::string& initIteratorName, QtOperation* mintervalExp, QtOperation* cellExp );
+
+ /// returns FALSE saying that the operation IS NOT commutative
+ virtual bool isCommutative() const;
+
+ /// optimizing load access
+ void optimizeLoad( QtTrimList* trimList );
+
+ /// method for evaluating the node
+ QtData* evaluate( QtDataList* inputList );
+ /**
+ */
+
+ /// prints the tree
+ virtual void printTree( int tab, std::ostream& s = std::cout, QtChildType mode = QT_ALL_NODES );
+
+ /// prints the algebraic expression
+ virtual void printAlgebraicExpression( std::ostream& s = std::cout );
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ /// type checking of the subtree
+ virtual const QtTypeElement& checkType( QtTypeTuple* typeTuple = NULL );
+
+ private:
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+
+ /// attribute storing the iterator name
+ std::string iteratorName;
+};
+
+
+#include "qlparser/qtmarrayop.icc"
+
+#endif
+
diff --git a/qlparser/qtmarrayop.icc b/qlparser/qtmarrayop.icc
new file mode 100644
index 0000000..5acc69e
--- /dev/null
+++ b/qlparser/qtmarrayop.icc
@@ -0,0 +1,34 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+inline const QtNode::QtNodeType
+QtMarrayOp::getNodeType() const
+{
+ return nodeType;
+}
diff --git a/qlparser/qtmarrayop2.cc b/qlparser/qtmarrayop2.cc
new file mode 100644
index 0000000..4393486
--- /dev/null
+++ b/qlparser/qtmarrayop2.cc
@@ -0,0 +1,369 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)qlparser, QtMarrayOp2: $Header: /home/rasdev/CVS-repository/rasdaman/qlparser/qtmarrayop2.cc,v 1.17 2003/12/27 20:51:28 rasdev Exp $";
+
+#include "raslib/rmdebug.hh"
+
+#include "qlparser/qtmarrayop2.hh"
+#include "qlparser/qtdata.hh"
+#include "qlparser/qtmdd.hh"
+#include "qlparser/qtpointdata.hh"
+#include "qlparser/qtmintervaldata.hh"
+#include "qlparser/qtmintervalop.hh"
+
+#include "mddmgr/mddobj.hh"
+#include "qlparser/querytree.hh"
+
+#include "catalogmgr/typefactory.hh"
+#include "relcatalogif/basetype.hh"
+#include "relcatalogif/longtype.hh"
+
+#include "catalogmgr/algebraops.hh"
+
+#include <iostream>
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+using namespace std;
+#endif
+
+extern QueryTree* parseQueryTree;
+
+QtMarrayOp2::QtMarrayOp2( mddIntervalListType* & aList, QtOperation* & cellExp )
+: iterators( *aList ), qtOperation( cellExp ) {
+}
+
+QtMarrayOp2::~QtMarrayOp2(){
+}
+
+bool QtMarrayOp2::concatenateIntervals() {
+ QtData* data=NULL;
+ RMDBGENTER( 2, RMDebug::module_qlparser, "QtMarrayOp2", "Validity Check: " )
+
+ // check for validity
+ bool eflag=true;
+ mddIntervalListType::const_iterator ii;
+ QtNode::QtOperationList::const_iterator j;
+ QtNode::QtOperationList *ddd=NULL;
+ QtOperation *op1=NULL;
+ QtOperation *op2=NULL;
+
+ for (ii = iterators.begin(); ii != iterators.end() ; ii++) {
+ ddd = ((QtMintervalOp *)(ii->tree))->getInputs();
+ for (j = ddd->begin(); j != ddd->end(); j++) {
+ if((QtNode *)*j) {
+ if ((((QtNode *)*j)->getNodeType() == QtNode::QT_INTERVALOP))
+ {
+ op1 = ((QtBinaryOperation *)*j)->getInput1();
+ if (((QtNode *)op1)->getNodeType() != QtNode::QT_CONST) eflag=false;
+ op2 = ((QtBinaryOperation *)*j)->getInput2();
+ if (((QtNode *)op2)->getNodeType() != QtNode::QT_CONST) eflag=false;
+ } else
+ if (((QtNode *)*j)->getNodeType() != QtNode::QT_CONST)
+ eflag=false;
+ }
+ }
+ }
+ RMDBGMIDDLE( 2, RMDebug::module_qlparser, "QtMarrayOp2", "Validity check completed." )
+ if (eflag) {
+ RMDBGMIDDLE( 2, RMDebug::module_qlparser, "QtMarrayOp2", "eflag is true!" << endl )
+ // compute total dimension
+ RMDBGMIDDLE( 2, RMDebug::module_qlparser, "QtMarrayOp2", endl << "QtMarrayOp2: Dimensions: " )
+ greatDimension=0;
+ mddIntervalListType::const_iterator i;
+ for (i = iterators.begin(); i != iterators.end() ; i++) {
+ // evaluate intervals
+ data = (i->tree)->evaluate(0);
+ r_Dimension dimension = ((QtMintervalData*)data)->getMintervalData().dimension();
+ RMDBGMIDDLE( 2, RMDebug::module_qlparser, "QtMarrayOp2", dimension << " | " );
+ greatDimension += dimension;
+ }
+ RMDBGMIDDLE( 2, RMDebug::module_qlparser, "QtMarrayOp2", " Total " << greatDimension << endl )
+
+ // concatenate the data of the intervals into one big interval
+ RMDBGMIDDLE( 2, RMDebug::module_qlparser, "QtMarrayOp2", "QtMarray2: Domains: " )
+ greatDomain = r_Minterval( greatDimension );
+ for (i = iterators.begin(); i != iterators.end() ; i++) {
+ // evaluate intervals
+ data = i->tree->evaluate(0);
+ r_Minterval domain = ((QtMintervalData*)data)->getMintervalData();
+ r_Dimension dimension = domain.dimension();
+ r_Dimension jj;
+ for (jj=0; jj != dimension; jj++) {
+ r_Sinterval part = domain[jj];
+ greatDomain << part;
+ }
+ RMDBGMIDDLE( 2, RMDebug::module_qlparser, "QtMarrayOp2", domain << " | " )
+ }
+ RMDBGMIDDLE( 2, RMDebug::module_qlparser, "QtMarrayOp2", " Total: " << greatDomain << endl )
+
+ // concatenate the identifier names to one big identifier name
+ RMDBGMIDDLE( 2, RMDebug::module_qlparser, "QtMarrayOp2", "QtMarray2: Iterators: " )
+ greatIterator = string("");
+ string iname("");
+ for (i = iterators.begin(); i != iterators.end() ; i++) {
+ // get iterator name
+ iname = string(i->variable);
+ greatIterator = greatIterator + string(" ") + string(i->variable);
+ RMDBGMIDDLE( 2, RMDebug::module_qlparser, "QtMarrayOp2", i->variable << " | " )
+ }
+ RMDBGEXIT( 2, RMDebug::module_qlparser, "QtMarrayOp2", " Total: " << greatIterator << endl )
+ } else
+ RMDBGEXIT( 2, RMDebug::module_qlparser, "QtMarrayOp2", " eflag is false! " << greatIterator << endl )
+ return eflag;
+}
+
+
+
+void QtMarrayOp2::rewriteVars( ) {
+ if (!oldMarray) {
+ RMDBGMIDDLE( 2, RMDebug::module_qlparser, "QtMarrayOp2", "concatenateIteratorNames: " )
+ mddIntervalListType::const_iterator i;
+ // concatenate the identifier names to one big identifier name
+ RMDBGMIDDLE( 2, RMDebug::module_qlparser, "QtMarrayOp2", "QtMarray2: Iterators: " )
+ greatIterator = string("");
+ string iname("");
+ for (i = iterators.begin(); i != iterators.end() ; i++) {
+ // get iterator name
+ iname = string(i->variable);
+ greatIterator = greatIterator + string(" ") + string(i->variable);
+ RMDBGMIDDLE( 2, RMDebug::module_qlparser, "QtMarrayOp2", i->variable << " | " )
+ }
+ RMDBGMIDDLE( 2, RMDebug::module_qlparser, "QtMarrayOp2", " Total: " << greatIterator << endl )
+ }
+ traverse(qtOperation);
+}
+
+void QtMarrayOp2::traverse(QtOperation *&node) {
+
+ if (node != 0)
+ {
+ QtOperation* temp = NULL;
+
+
+ if (((QtNode *)node)->getNodeType() == QtNode::QT_DOMAIN_OPERATION)
+ {
+ // syntax: dinput [ dmiop ]
+
+ // traverse dmiop
+ QtOperation *dmiop = ((QtDomainOperation *)node)->getMintervalOp();
+ temp = (QtOperation*)dmiop;
+ traverse(temp);
+ dmiop = temp;
+ ((QtDomainOperation *)node)->setMintervalOp(dmiop);
+
+ // if dinput == QtVariable then rewrite it
+ QtOperation *dinput = ((QtDomainOperation *)node)->getInput();
+
+ // if not a variable, then recurse
+ if (((QtNode *)dinput)->getNodeType() != QtNode::QT_MDD_VAR)
+ {
+ // traverse dinput
+ temp = (QtOperation *)dinput;
+ traverse(temp);
+ dinput = temp;
+ ((QtDomainOperation *)node)->setInput(dinput);
+
+ // get childs and traverse them
+ QtNode::QtNodeList* childList = node->getChilds(QtNode::QT_DIRECT_CHILDS);
+ for( QtNode::QtNodeList::iterator iter = childList->begin(); iter != childList->end(); iter++ )
+ {
+ temp = (QtOperation*)*iter;
+ traverse(temp);
+ *iter = temp;
+ };
+ delete childList;
+ childList=NULL;
+ };
+ } else
+ {
+
+ if (node->getNodeType() == QtNode::QT_MDD_VAR) {
+ if (QueryTree::symtab.lookupSymbol(((QtVariable *)node)->getIteratorName()))
+ {
+ if (!oldMarray)
+ {
+ RMDBGMIDDLE( 2, RMDebug::module_qlparser, "QtMarrayOp2", endl << "marray2 var identifier:" << ((QtVariable *)node)->getIteratorName() << " replacing with " << greatIterator << endl )
+ ((QtVariable *)node)->setIteratorName(greatIterator);
+ };
+ // replace with var[0]
+ QtDomainOperation *dop = new QtDomainOperation( new QtConst (new QtAtomicData((r_Long)0, sizeof(r_Long))) /*new QtPointOp( lop )*/ );
+ dop->setInput( (QtVariable *)node );
+ node = dop;
+ parseQueryTree->addDomainObject( dop );
+ };
+ } else
+ {
+
+ // traverse inputs
+ switch (((QtNode *)node)->getNodeType()) {
+/*
+ // with no input
+ case QtNode::QT_UNDEFINED_NODE:
+ case QtNode::QT_MDD_ACCESS:
+ case QtNode::QT_OPERATION_ITERATOR:
+ case QtNode::QT_SELECTION_ITERATOR:
+ case QtNode::QT_JOIN_ITERATOR:
+ case QtNode::QT_UPDATE:
+ case QtNode::QT_INSERT:
+ case QtNode::QT_DELETE:
+ case QtNode::QT_COMMAND:
+ case QtNode::QT_PYRAMID:
+ case QtNode::QT_MDD_VAR:
+ case QtNode::QT_UDFCALLOP:
+ case QtNode::QT_CONST:
+ case QtNode::QT_MDD_STREAM:
+*/
+ // from Unary
+ case QtNode::QT_TANH:
+ case QtNode::QT_TAN:
+ case QtNode::QT_SQRT:
+ case QtNode::QT_SINH:
+ case QtNode::QT_SIN:
+ case QtNode::QT_NOT:
+ case QtNode::QT_LOG:
+ case QtNode::QT_LN:
+ case QtNode::QT_EXP:
+ case QtNode::QT_DOT:
+ case QtNode::QT_COSH:
+ case QtNode::QT_COS:
+ case QtNode::QT_ARCTAN:
+ case QtNode::QT_ARCSIN:
+ case QtNode::QT_ARCCOS:
+ case QtNode::QT_ABS:
+ case QtNode::QT_REALPART:
+ case QtNode::QT_IMAGINARPART:
+ case QtNode::QT_CAST:
+ case QtNode::QT_SDOM:
+ case QtNode::QT_OID:
+ case QtNode::QT_LO:
+ case QtNode::QT_HI:
+// case QtNode::QT_DOMAIN_OPERATION:
+ case QtNode::QT_CONVERSION:
+ case QtNode::QT_SOME:
+ case QtNode::QT_MINCELLS:
+ case QtNode::QT_MAXCELLS:
+ case QtNode::QT_COUNTCELLS:
+ case QtNode::QT_AVGCELLS:
+ case QtNode::QT_ALL:
+ case QtNode::QT_ADDCELLS:
+ case QtNode::QT_CSE_ROOT:
+ {
+ QtOperation *uinput = ((QtUnaryOperation *)node)->getInput();
+
+ temp = (QtOperation *)uinput;
+ traverse(temp);
+ uinput = temp;
+
+ ((QtUnaryOperation *)node)->setInput(uinput);
+ };
+ break;
+
+ // from Binary
+ case QtNode::QT_SHIFT:
+ case QtNode::QT_SCALE:
+ case QtNode::QT_MARRAYOP:
+ case QtNode::QT_INTERVALOP:
+ case QtNode::QT_CONDENSEOP:
+ case QtNode::QT_XOR:
+ case QtNode::QT_PLUS:
+ case QtNode::QT_OR:
+ case QtNode::QT_NOT_EQUAL:
+ case QtNode::QT_MULT:
+ case QtNode::QT_MINUS:
+ case QtNode::QT_LESS_EQUAL:
+ case QtNode::QT_LESS:
+ case QtNode::QT_IS:
+ case QtNode::QT_EQUAL:
+ case QtNode::QT_DIV:
+ case QtNode::QT_AND:
+ case QtNode::QT_OVERLAY:
+ case QtNode::QT_BIT:
+ {
+ QtOperation *binput1 = ((QtBinaryOperation *)node)->getInput1();
+ QtOperation *binput2 = ((QtBinaryOperation *)node)->getInput2();
+
+ QtOperation* temp1 = 0;
+ QtOperation* temp2 = 0;
+ temp1 = (QtOperation *)binput1;
+ temp2 = (QtOperation *)binput2;
+ traverse(temp1);
+ traverse(temp2);
+ binput1 = temp1;
+ binput2 = temp2;
+
+ ((QtBinaryOperation *)node)->setInput1(binput1);
+ ((QtBinaryOperation *)node)->setInput2(binput2);
+ };
+ break;
+
+ // from Nary
+ case QtNode::QT_POINTOP:
+ case QtNode::QT_MINTERVALOP:
+ {
+ QtNode::QtOperationList *ninput = ((QtNaryOperation *)node)->getInputs();
+
+ for( QtNode::QtOperationList::iterator iter = ninput->begin(); iter != ninput->end(); iter++ )
+ {
+ temp = (QtOperation *)*iter;
+ traverse(temp);
+ *iter = temp;
+ };
+
+ ((QtNaryOperation *)node)->setInputs(ninput);
+ };
+ break;
+ default: {
+ // do nothing
+ }; break;
+ };
+
+ // get childs and traverse them
+ QtNode::QtNodeList* childList = node->getChilds(QtNode::QT_DIRECT_CHILDS);
+ for( QtNode::QtNodeList::iterator iter = childList->begin(); iter != childList->end(); iter++ )
+ {
+ temp = (QtOperation*)*iter;
+ traverse(temp);
+ *iter = temp;
+ };
+ delete childList;
+ childList=NULL;
+ };
+ };
+ };
+}
+
+
+
+
diff --git a/qlparser/qtmarrayop2.hh b/qlparser/qtmarrayop2.hh
new file mode 100644
index 0000000..94e67e6
--- /dev/null
+++ b/qlparser/qtmarrayop2.hh
@@ -0,0 +1,113 @@
+#ifndef _QTMARRAYOP2_
+#define _QTMARRAYOP2_
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+ The class represents the root of a fake marray expression.
+
+*/
+
+#include "raslib/minterval.hh"
+
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+#endif
+
+#include <vector>
+#include "qlparser/qtoperation.hh"
+#include "qlparser/qtdomainoperation.hh"
+#include "qlparser/qtvariable.hh"
+#include "qlparser/qtatomicdata.hh"
+#include "qlparser/qtpointop.hh"
+#include "qlparser/qtconst.hh"
+
+class QtMarrayOp2 {
+ public:
+ /// variables to pass to old marray
+ r_Dimension greatDimension;
+ r_Minterval greatDomain;
+ std::string greatIterator;
+
+ /// pair (Identifier, Interval)
+ typedef struct {
+ std::string variable;
+ QtOperation* tree;
+ ParseInfo parseInfo;
+ } mddIntervalType;
+
+ /// list storing pairs (Identifier, Interval)
+ typedef vector<mddIntervalType> mddIntervalListType;
+
+ /// constructor getting iterator, minterval expression, and cell expression
+ QtMarrayOp2( mddIntervalListType* & aList, QtOperation* & cellExp );
+
+ /// destructor
+ virtual ~QtMarrayOp2();
+
+ /// optimizing load access
+ virtual bool concatenateIntervals();
+ virtual void rewriteVars();
+ inline QtOperation *getInput() const;
+ ///
+ inline const ParseInfo& getParseInfo();
+ ///
+ inline void setParseInfo( const ParseInfo &info );
+ ///
+ inline void setOldMarray( bool value );
+
+ protected:
+ /// attribute for parser info
+ ParseInfo parseInfo;
+
+ private:
+ /// attribute storing the iterators
+ mddIntervalListType iterators;
+
+ /// attribute storing the cellExp
+ QtOperation *qtOperation;
+
+ /// tree traversal
+ virtual void traverse(QtOperation *&node);
+
+ /// replace Iterator name if this is false
+ bool oldMarray;
+
+};
+
+#include "qlparser/qtmarrayop2.icc"
+
+#endif
+
diff --git a/qlparser/qtmarrayop2.icc b/qlparser/qtmarrayop2.icc
new file mode 100644
index 0000000..8155712
--- /dev/null
+++ b/qlparser/qtmarrayop2.icc
@@ -0,0 +1,54 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+inline QtOperation *QtMarrayOp2::getInput() const
+{
+ return qtOperation;
+}
+
+inline const ParseInfo&
+QtMarrayOp2::getParseInfo()
+{
+ return parseInfo;
+}
+
+inline void
+QtMarrayOp2::setParseInfo( const ParseInfo &info )
+{
+ parseInfo = info;
+}
+
+inline void
+QtMarrayOp2::setOldMarray( bool value )
+{
+ oldMarray = value;
+};
diff --git a/qlparser/qtmdd.cc b/qlparser/qtmdd.cc
new file mode 100644
index 0000000..b3e994f
--- /dev/null
+++ b/qlparser/qtmdd.cc
@@ -0,0 +1,329 @@
+#include "mymalloc/mymalloc.h"
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)qlparser, QtMDD: $Header: /home/rasdev/CVS-repository/rasdaman/qlparser/qtmdd.cc,v 1.44 2003/12/27 20:51:28 rasdev Exp $";
+
+#include "qlparser/qtmdd.hh"
+#include "qlparser/qtscalardata.hh"
+#include "qlparser/qtmintervaldata.hh"
+#include "qlparser/qtoperation.hh"
+
+#include "mddmgr/mddobj.hh"
+#include "tilemgr/tile.hh"
+#include "mddmgr/mddcoll.hh"
+#include "catalogmgr/typefactory.hh"
+
+#include "raslib/rmdebug.hh"
+
+#include "relcatalogif/mdddimensiontype.hh"
+
+#include <iostream>
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+using namespace std;
+#endif
+#include <iostream>
+
+extern MDDColl* mddConstants;
+
+QtMDD::QtMDD( MDDObj* ptr )
+ : QtData(),
+ mddObject( ptr )
+{
+ if( ptr && ptr->isPersistent() )
+ setLifetime( QtData::QT_PERSISTENT );
+ else
+ setLifetime( QtData::QT_TRANSIENT );
+
+ if( ptr )
+ loadDomain = ptr->getDefinitionDomain();
+}
+
+
+QtMDD::QtMDD( MDDObj* ptr, string name )
+ : QtData( name ),
+ mddObject( ptr )
+{
+ if( ptr && ptr->isPersistent() )
+ setLifetime( QtData::QT_PERSISTENT );
+ else
+ setLifetime( QtData::QT_TRANSIENT );
+
+ if( ptr )
+ loadDomain = ptr->getCurrentDomain();
+}
+
+
+QtMDD::QtMDD( QtOperation* mintervalOp, list<QtScalarData*>* literalList )
+ : QtData(), mddObject(0)
+{
+ list< QtScalarData* >::iterator elemIter;
+ QtScalarData* scalarElem=NULL;
+
+ //
+ // evaluate domain
+ //
+
+ if( mintervalOp )
+ {
+
+ QtData* operand = mintervalOp->evaluate(NULL);
+
+ if( operand->getDataType() != QT_MINTERVAL )
+ {
+ RMInit::logOut << "Error: QtMDD( QtOperation*, list<QtScalarData*>* ) - Can not evaluate domain expression to an minterval." << endl;
+ ParseInfo errorInfo = getParseInfo();
+ errorInfo.setErrorNo(401);
+ throw errorInfo;
+ }
+
+ r_Minterval domain = ((QtMintervalData*)operand)->getMintervalData();
+
+ // delete old operand
+ if( operand ) operand->deleteRef();
+
+ //
+ // determine base type
+ //
+
+ if( literalList->size()!=0 )
+ {
+ scalarElem = *(literalList->begin());
+ const BaseType* baseType = scalarElem->getValueType();
+
+ //
+ // allocate memory and fill it with cell values of the list
+ //
+ unsigned long cellCount = 0;
+ unsigned long cellSize = baseType->getSize();
+ char* cellBuffer = (char*)mymalloc( domain.cell_count()*cellSize );
+ char* bufferOffset = cellBuffer;
+
+ for( elemIter = literalList->begin(); elemIter != literalList->end(); elemIter++ )
+ {
+ scalarElem = *elemIter;
+ cellCount++;
+
+ // do not write beyond array boundary
+ if( cellCount <= domain.cell_count() )
+ {
+ if( scalarElem->getValueType() != baseType )
+ {
+ RMDBGONCE(2, RMDebug::module_qlparser, "QtMDD", "Error: QtMDD() - All cell values of an MDD must be of the same type." )
+ free( cellBuffer );
+ cellBuffer=NULL;
+ ParseInfo errorInfo = getParseInfo();
+ errorInfo.setErrorNo(301);
+ throw errorInfo;
+ }
+ memcpy( (void*)bufferOffset, (void*)(scalarElem->getValueBuffer()), (unsigned int)cellSize );
+ bufferOffset += cellSize;
+ }
+ }
+
+ // delete literal list - done by caller
+ // delete literalList;
+
+ if( cellCount != domain.cell_count() )
+ {
+ RMDBGONCE(2, RMDebug::module_qlparser, "QtMDD", "Error: QtMDD() - Number of cells specified does not match the number of cells of the given spatial domain." )
+ free( cellBuffer );
+ cellBuffer=NULL;
+ ParseInfo errorInfo = getParseInfo();
+ errorInfo.setErrorNo(302);
+ throw errorInfo;
+ }
+
+ //
+ // create transient tile
+ //
+ Tile* tile = new Tile( domain, baseType, cellBuffer, 0 );
+
+ //
+ // create transiend mddObject and attach created tile
+ //
+ MDDDimensionType* mddDimensionType = new MDDDimensionType( "tmp", baseType, domain.dimension() );
+ TypeFactory::addTempType( mddDimensionType );
+ mddObject = new MDDObj( mddDimensionType, domain );
+ mddObject->insertTile( tile );
+ loadDomain = domain;
+ }
+ else
+ RMInit::logOut << "Internal Error: QtMDD( domain, literalList ) - list of literal lists is empty" << endl;
+ }
+ else
+ {
+ RMInit::logOut << "Error: QtMDD( QtOperation*, list<QtScalarData*>* ) - Domain of MDD constructor has to be defined." << endl;
+ ParseInfo errorInfo = getParseInfo();
+ errorInfo.setErrorNo(400);
+ throw errorInfo;
+ }
+
+}
+
+
+
+QtMDD::QtMDD( int constantNo )
+ : QtData(),
+ mddObject( NULL )
+{
+ RMDBGONCE(2, RMDebug::module_qlparser, "QtMDD", "QtMDD() - constant no " << constantNo )
+
+ if( mddConstants )
+ {
+
+ MDDCollIter* mddIter = mddConstants->createIterator();
+ //for( mddIter->reset(); mddIter->notDone(); mddIter->advance() )
+ mddIter->reset();
+
+ // take the MDD object
+ mddObject = mddIter->getElement();
+
+ // remove it from the constant list
+ mddConstants->remove( mddObject );
+
+ delete mddIter;
+ mddIter = NULL;
+
+ if( mddObject )
+ loadDomain = mddObject->getCurrentDomain();
+ }
+ else
+ {
+ RMInit::logOut << "Error: QtMDD() - Unsatisfied MDD constant parameter." << endl;
+ ParseInfo errorInfo = getParseInfo();
+ errorInfo.setErrorNo(373);
+ throw errorInfo;
+ }
+
+}
+
+
+
+QtMDD::QtMDD( const QtMDD& obj )
+ : QtData( obj ),
+ mddObject( obj.mddObject )
+{
+}
+
+
+QtMDD::~QtMDD()
+{
+ //this causes problems when passing more than one trans mddobj
+ if( mddObject && getLifetime() == QtData::QT_TRANSIENT )
+ {
+ RMDBGONCE( 2, RMDebug::module_qlparser, "QtMDD", "~QtMDD() - transient MDD object " << mddObject << " deleted" )
+ delete mddObject;
+ mddObject = NULL;
+ }
+}
+
+
+BaseType*
+QtMDD::getCellType() const
+{
+ return (BaseType*)mddObject->getCellType();
+}
+
+
+
+unsigned long
+QtMDD::getCellSize() const
+{
+ return mddObject->getCellType()->getSize();
+}
+
+
+
+QtDataType
+QtMDD::getDataType() const
+{
+ return QT_MDD;
+}
+
+
+
+bool
+QtMDD::equal( const QtData* /*obj*/ ) const
+{
+ int returnValue = false; // not equal by initialization
+
+ // Later on, MDD constants can be compared.
+
+ return returnValue;
+}
+
+
+
+string
+QtMDD::getSpelling() const
+{
+ string result;
+
+ // no spelling right now
+
+ return result;
+}
+
+
+
+char* QtMDD::getTypeStructure() const
+{
+ if( mddObject )
+ return mddObject->getMDDBaseType()->getTypeStructure();
+ else
+ return NULL;
+}
+
+
+
+void
+QtMDD::printStatus( ostream& stream ) const
+{
+ if( mddObject )
+ stream << "MDD object: load domain: " << loadDomain << endl;
+ else
+ stream << "<no object>" << endl;
+
+ QtData::printStatus( stream );
+
+RMDBGIF(3, RMDebug::module_qlparser, "QtMDD", mddObject->printStatus(0, stream); )
+
+RMDBGIF(30, RMDebug::module_qlparser, "QtMDD", \
+ vector<Tile*>* vec = mddObject->getTiles(); \
+ for( int i = 0; i<vec->size(); i++ ) \
+ ((*vec)[i])->printStatus(); \
+ delete vec; vec=NULL; )
+}
diff --git a/qlparser/qtmdd.hh b/qlparser/qtmdd.hh
new file mode 100644
index 0000000..bbbe195
--- /dev/null
+++ b/qlparser/qtmdd.hh
@@ -0,0 +1,138 @@
+#ifndef _QTMDD_
+#define _QTMDD_
+
+#include "qlparser/qtdata.hh"
+#include "qlparser/qtscalardata.hh"
+#include "catalogmgr/typefactory.hh"
+#include "raslib/minterval.hh"
+
+#include <string>
+#include <list>
+
+// forward declarations
+class MDDObj;
+class QtOperation;
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+ The class encapsulates a pointer to an object of type {\tt MDDObj}.
+ Its purpose is to have the {\tt MDDObj} object available as a descendant
+ of class {\tt QtData}. The class does not care of the memory management
+ of the {\tt MDDObj} object.
+
+ Note: The attribute lifetime of the superclass QtData ist set implicit
+ in the constructor functions!
+*/
+
+class QtMDD : public QtData
+{
+ public:
+ // list of lists of \Ref{QtScalarData} objects
+ // typedef list< list<QtScalarData*>* > QtDimensionList;
+
+ /// constructor getting the pointer to the MDDObj object
+ QtMDD( MDDObj* ptr );
+
+ /// constructor getting the pointer to the MDDObj object and an iterator name
+ QtMDD( MDDObj* ptr, std::string name );
+
+ /// constructor getting a domain expression and a literal list for initializing a transient constant object
+ QtMDD( QtOperation* mintervalOp, std::list<QtScalarData*>* literalList );
+ /**
+ The list of literal objects is not deleted.
+ */
+
+ /// constructor getting the number of an mdd constant
+ QtMDD( int constantNo );
+
+ /// copy constructor
+ QtMDD( const QtMDD& obj );
+
+ /// destructor
+ virtual ~QtMDD();
+
+ //@Man: Read/Write methods:
+ //@{
+ ///
+ /// gets the pointer to the MDDObj object
+ inline MDDObj* getMDDObject() const;
+ /// sets the pointer to the MDDObj object and it does not care about the old pointer
+ inline void setMDDObject( MDDObj* ptr );
+ /// read method for loadDomain
+ inline const r_Minterval& getLoadDomain() const;
+ /// write method for loadDomain
+ inline void setLoadDomain( r_Minterval& newLoadDomain );
+
+ /// returns a null-terminated string describing the type structure
+ virtual char* getTypeStructure() const;
+ /**
+ The string pointer has to be free using free() by the caller.
+ */
+ ///
+ ///
+ //@}
+
+ /// returns a pointer to the cell type
+ BaseType* getCellType() const;
+
+ /// returns size of one cell in bytes
+ unsigned long getCellSize() const;
+
+ /// returns {\tt QT_MDD}
+ virtual QtDataType getDataType() const;
+
+ /// compares data content
+ virtual bool equal( const QtData* obj ) const;
+
+ /// returns content dependent string representation
+ virtual std::string getSpelling() const;
+
+ /// print status of the object to the specified stream
+ virtual void printStatus( std::ostream& stream = std::cout ) const;
+
+ private:
+ /// prevents from using the default constructor
+ QtMDD(){};
+
+ /// pointer to the MDDObj object
+ MDDObj* mddObject;
+
+ /// load domain
+ r_Minterval loadDomain;
+};
+
+#include "qlparser/qtmdd.icc"
+
+#endif
+
diff --git a/qlparser/qtmdd.icc b/qlparser/qtmdd.icc
new file mode 100644
index 0000000..8fee948
--- /dev/null
+++ b/qlparser/qtmdd.icc
@@ -0,0 +1,59 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+
+inline MDDObj*
+QtMDD::getMDDObject() const
+{
+ return mddObject;
+}
+
+
+inline void
+QtMDD::setMDDObject( MDDObj* ptr )
+{
+ mddObject = ptr;
+}
+
+
+
+inline const r_Minterval&
+QtMDD::getLoadDomain() const
+{
+ return loadDomain;
+}
+
+
+inline void
+QtMDD::setLoadDomain( r_Minterval& newLoadDomain )
+{
+ loadDomain = newLoadDomain;
+}
+
+
diff --git a/qlparser/qtmddaccess.cc b/qlparser/qtmddaccess.cc
new file mode 100644
index 0000000..db009e3
--- /dev/null
+++ b/qlparser/qtmddaccess.cc
@@ -0,0 +1,250 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)qlparser, QtMDDAccess: $Id: qtmddaccess.cc,v 1.30 2002/04/23 16:22:41 purify Exp $";
+
+#include "raslib/rmdebug.hh"
+
+#include "qlparser/qtmddaccess.hh"
+#include "qlparser/qtmdd.hh"
+
+#include <iostream>
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+using namespace std;
+#endif
+
+#include "mddmgr/mddcoll.hh"
+#include "mddmgr/mddcolliter.hh"
+
+#include "servercomm/servercomm.hh"
+
+extern ServerComm::ClientTblElt* currentClientTblElt;
+
+const QtNode::QtNodeType QtMDDAccess::nodeType = QT_MDD_ACCESS;
+
+QtMDDAccess::QtMDDAccess( const string& collectionNameNew )
+ : QtONCStream(),
+ collectionName( collectionNameNew ),
+ mddColl(NULL),
+ mddIter(NULL)
+{
+}
+
+
+QtMDDAccess::QtMDDAccess( const string& collectionNameNew, const string& initName )
+ : QtONCStream(),
+ collectionName( collectionNameNew ),
+ iteratorName( initName ),
+ mddColl(NULL),
+ mddIter(NULL)
+{
+}
+
+
+QtMDDAccess::~QtMDDAccess()
+{
+ //just to be on the safe side
+ close();
+}
+
+
+void
+QtMDDAccess::open()
+{
+ RMDBCLASS( "QtMDDAccess", "open()", "qlparser", __FILE__, __LINE__ )
+
+ // delete an existing iterator
+ if( mddIter )
+ {
+ delete mddIter;
+ mddIter=NULL;
+ }
+
+ // create the iterator
+ mddIter = mddColl->createIterator();
+
+ //for( mddIter->reset(); mddIter->notDone(); mddIter->advance() )
+ // mddIter->getElement()->printStatus();
+
+ mddIter->reset();
+}
+
+
+QtNode::QtDataList*
+QtMDDAccess::next()
+{
+ RMDBCLASS( "QtMDDAccess", "next()", "qlparser", __FILE__, __LINE__ )
+
+ QtDataList* returnValue = NULL;
+ MDDObj* ptr = NULL;
+
+ if( mddColl && mddIter && mddIter->notDone() )
+ {
+ //
+ // create a list with a pointer to the next element of the mdd collection
+ //
+
+ // encapsulate the next MDDObj in an QtMDD object
+ ptr = mddIter->getElement();
+ QtMDD* elem = new QtMDD( ptr, iteratorName );
+
+
+
+ // create the list
+ QtNode::QtDataList* dataList = new QtNode::QtDataList(1); // create container to contain one element
+
+ // insert the element into the list
+ (*dataList)[0] = elem;
+
+ // if mddColl is not persistent delete thist from
+ // collection to avoid multiple destruction
+ if(!mddColl->isPersistent()) {
+ mddColl->remove(ptr);
+ mddIter->reset();
+ }
+ else {
+ // increment the iterator
+ mddIter->advance();
+ }
+
+ returnValue = dataList;
+ }
+
+ return returnValue;
+}
+
+
+void
+QtMDDAccess::close()
+{
+ RMDBCLASS( "QtMDDAccess", "close()", "qlparser", __FILE__, __LINE__ )
+
+ // delete the mdd iterator
+ if( mddIter )
+ {
+ delete mddIter;
+ mddIter=NULL;
+ }
+
+ // This is now done in ServerComm::ClientTblElt::releaseTransferStructures().
+ //
+ // delete the mdd objects and the mdd collection
+ // if( mddColl )
+ // {
+ // mddColl->releaseAll();
+ // delete mddColl;
+ // }
+}
+
+
+void
+QtMDDAccess::reset()
+{
+ if( mddIter ) mddIter->reset();
+}
+
+
+void
+QtMDDAccess::printTree( int tab, ostream& s, QtChildType /*mode*/ )
+{
+ s << SPACE_STR(tab).c_str() << "QtMDDAccess Object: type " << flush;
+ dataStreamType.printStatus( s );
+ s << endl;
+
+ s << SPACE_STR(tab).c_str() << collectionName.c_str()
+ << " <- " << iteratorName.c_str() << endl;
+}
+
+
+
+void
+QtMDDAccess::printAlgebraicExpression( ostream& s )
+{
+ s << collectionName.c_str() << " as " << iteratorName.c_str() << flush;
+}
+
+
+
+const QtTypeTuple&
+QtMDDAccess::checkType()
+{
+ RMDBCLASS( "QtMDDAccess", "checkType()", "qlparser", __FILE__, __LINE__ )
+
+ dataStreamType = QtTypeTuple(0);
+
+ //
+ // create the collection and add it to the list in the client table entry
+ //
+
+ try
+ {
+ mddColl = MDDColl::getMDDCollection( collectionName.c_str() );
+
+ if( currentClientTblElt )
+ {
+ if (mddColl->isPersistent())
+ {
+ if( !(currentClientTblElt->persMDDCollections) )
+ currentClientTblElt->persMDDCollections = new vector<MDDColl*>();
+
+ currentClientTblElt->persMDDCollections->push_back( (MDDColl*)mddColl );
+ }
+ else {
+ currentClientTblElt->transferColl = mddColl;
+ }
+ }
+ else {
+ RMInit::logOut << "Internal Error in QtMDDAccess::open(): No client context available" << endl;
+ }
+ }
+ catch(...)
+ {
+ RMInit::logOut << "Error: QtMDDAccess::open() collection: " << collectionName.c_str() << " is unknown" << endl;
+ parseInfo.setErrorNo(355);
+ throw parseInfo;
+ }
+
+ CollectionType* collType = (CollectionType*) mddColl->getCollectionType();
+
+ if( !collType )
+ RMInit::logOut << "Internal error in QtMDDAccess::checkType() - no collection type available" << endl;
+
+ dataStreamType = QtTypeTuple( 1 );
+
+ dataStreamType.tuple[0].setType( collType->getMDDType() );
+ dataStreamType.tuple[0].setName( iteratorName.c_str() );
+
+ return dataStreamType;
+}
diff --git a/qlparser/qtmddaccess.hh b/qlparser/qtmddaccess.hh
new file mode 100644
index 0000000..433f805
--- /dev/null
+++ b/qlparser/qtmddaccess.hh
@@ -0,0 +1,114 @@
+#ifndef _QTMDDACCESS_
+#define _QTMDDACCESS_
+
+#include "qlparser/qtoncstream.hh"
+
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+#endif
+
+// forward declarations
+class MDDColl;
+class MDDCollIter;
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+This class encapsulates a MDDCollection. It gives access to the elements
+through the ONC protocol. The list returned by next() consists of just one
+element.
+
+*/
+
+class QtMDDAccess : public QtONCStream
+{
+ public:
+ /// constructor getting the collection name if no iterator name is specified
+ QtMDDAccess( const std::string& collectionName );
+
+ /// constructor getting collection and iterator name
+ QtMDDAccess( const std::string& collectionName, const std::string& iteratorName );
+
+ /// destructor
+ virtual ~QtMDDAccess();
+
+ //@Man: Operations of the ONC protocol
+ //@{
+ ///
+ void open();
+ ///
+ QtDataList* next();
+ ///
+ void close();
+ ///
+ void reset();
+ //@}
+
+ /// prints the tree
+ virtual void printTree( int tab, std::ostream& s = std::cout, QtChildType mode = QT_ALL_NODES );
+
+ /// prints the algebraic expression
+ virtual void printAlgebraicExpression( std::ostream& s = std::cout );
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ /// method for retrieving the current MDD collection
+ inline MDDColl* getMDDColl();
+
+ /// type checking
+ virtual const QtTypeTuple& checkType();
+
+ private:
+ /// name of the MDD collection
+ std::string collectionName;
+
+ /// name of the iterator
+ std::string iteratorName;
+
+ /// pointer to the MDD collection
+ MDDColl* mddColl;
+
+ /// pointer to the curent iterator
+ MDDCollIter* mddIter;
+
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+#include "qlparser/qtmddaccess.icc"
+
+#endif
+
diff --git a/qlparser/qtmddaccess.icc b/qlparser/qtmddaccess.icc
new file mode 100644
index 0000000..37a8e3b
--- /dev/null
+++ b/qlparser/qtmddaccess.icc
@@ -0,0 +1,42 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+inline const QtNode::QtNodeType
+QtMDDAccess::getNodeType() const
+{
+ return nodeType;
+}
+
+
+
+inline MDDColl*
+QtMDDAccess:: getMDDColl()
+{
+ return mddColl;
+}
diff --git a/qlparser/qtmintervaldata.cc b/qlparser/qtmintervaldata.cc
new file mode 100644
index 0000000..da5343d
--- /dev/null
+++ b/qlparser/qtmintervaldata.cc
@@ -0,0 +1,188 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)qlparser, QtMintervalData: $Header: /home/rasdev/CVS-repository/rasdaman/qlparser/qtmintervaldata.cc,v 1.10 2005/09/03 20:17:55 rasdev Exp $";
+
+using namespace std;
+
+using namespace std;
+
+#include "qlparser/qtmintervaldata.hh"
+
+#include <iostream>
+#include <cstring>
+
+QtMintervalData::QtMintervalData( const r_Minterval& minterval, vector<bool>* initTrimFlags )
+ : mintervalData(minterval), QtData(), trimFlags( initTrimFlags )
+{
+ if( !trimFlags )
+ {
+ trimFlags = new vector<bool>( minterval.dimension() );
+
+ for( int i=0; i<trimFlags->size(); i++ )
+ (*trimFlags)[i] = true;
+ }
+}
+
+
+
+QtMintervalData::~QtMintervalData()
+{
+ if( trimFlags ) {delete trimFlags; trimFlags=NULL; }
+}
+
+
+
+QtDataType
+QtMintervalData::getDataType() const
+{
+ return QT_MINTERVAL;
+}
+
+
+
+bool
+QtMintervalData::equal( const QtData* obj ) const
+{
+ bool returnValue = false; // not equal by initialization
+
+ if( obj->getDataType() == QT_MINTERVAL )
+ {
+ QtMintervalData* mint = (QtMintervalData*)obj;
+
+ // 1. check domains
+ returnValue = (mintervalData == mint->getMintervalData());
+
+ // 2. check projection flags !!!
+ if( returnValue && trimFlags && mint->getTrimFlags() )
+ for( int i=0; i<mintervalData.dimension(); i++ )
+ if (!((*trimFlags)[i] == (*(mint->getTrimFlags()))[i]))
+ {
+ returnValue = false;
+ break;
+ }
+ }
+
+ return returnValue;
+}
+
+
+
+std::string
+QtMintervalData::getSpelling() const
+{
+ std::string result;
+
+ // buffer
+ int bufferLen = mintervalData.dimension() * 50; // on the save side for two integers per dimension plus colon and brackets
+ char* buffer = new char[ bufferLen ];
+ // replaced deprecated ostrstream -- PB 2005-jan-14
+ // ostrstream bufferStream( buffer, bufferLen );
+ ostringstream bufferStream( buffer );
+
+ if( trimFlags )
+ {
+ bufferStream << "[" << std::flush;
+ for( int i=0; i<mintervalData.dimension(); i++ )
+ {
+ if( i > 0 ) bufferStream << "'" << std::flush;
+
+ if( (*trimFlags)[i] )
+ bufferStream << mintervalData[i] << std::flush;
+ else
+ bufferStream << mintervalData[i].low() << std::flush;
+ }
+ bufferStream << "]" << std::ends;
+ }
+ else
+ bufferStream << mintervalData << std::ends;
+
+ result.append( std::string( buffer ) );
+
+ delete[] buffer;
+ buffer = NULL;
+
+ return result;
+}
+
+
+
+char* QtMintervalData::getTypeStructure() const
+{
+ return strdup("minterval");
+}
+
+
+
+void
+QtMintervalData::printStatus( std::ostream& stream ) const
+{
+ stream << "minterval, value: " << std::flush;
+
+ if( trimFlags )
+ {
+ stream << "[" << std::flush;
+ for( int i=0; i<mintervalData.dimension(); i++ )
+ {
+ if( i > 0 ) stream << "," << std::flush;
+
+ if( (*trimFlags)[i] )
+ stream << mintervalData[i] << std::flush;
+ else
+ stream << mintervalData[i].low() << std::flush;
+ }
+ stream << "]" << std::flush;
+ }
+ else
+ stream << mintervalData << std::flush;
+
+ QtData::printStatus( stream );
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/qlparser/qtmintervaldata.hh b/qlparser/qtmintervaldata.hh
new file mode 100644
index 0000000..9fcd705
--- /dev/null
+++ b/qlparser/qtmintervaldata.hh
@@ -0,0 +1,108 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#ifndef _QTMINTERVALDATA_
+#define _QTMINTERVALDATA_
+
+#include "qlparser/qtdata.hh"
+
+#include "raslib/minterval.hh"
+#include "raslib/point.hh"
+
+#include <string>
+#include <vector>
+#include <iostream>
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+ The class encapsulates an minterval.
+*/
+
+class QtMintervalData : public QtData
+{
+ public:
+ /// constructor getting the minterval
+ QtMintervalData( const r_Minterval& minterval, vector<bool>* initTrimFlags = NULL );
+
+ /// virtual destructor
+ virtual ~QtMintervalData();
+
+ //@Man: Read/Write methods:
+ //@{
+ ///
+
+ ///
+ inline const r_Minterval& getMintervalData() const;
+ ///
+ inline void setMintervalData( const r_Minterval& interval );
+ //
+ // inline void setMintervalData( const r_Point& point );
+ ///
+ inline const vector<bool>* getTrimFlags() const;
+
+ /// returns a null-terminated string describing the type structure
+ virtual char* getTypeStructure() const;
+ /**
+ The string pointer has to be free using free() by the caller.
+ */
+
+ ///
+ //@}
+
+ /// returns {\tt QT_INTERVAL}
+ virtual QtDataType getDataType() const;
+
+ /// compares data content
+ virtual bool equal( const QtData* obj ) const;
+
+ /// returns content dependent string representation
+ virtual std::string getSpelling() const;
+
+ /// print status of the object to the specified stream
+ virtual void printStatus( std::ostream& stream = std::cout ) const;
+
+ private:
+ /// prevents from using the default constructor
+ QtMintervalData(){};
+
+ /// attribute storing the minterval
+ r_Minterval mintervalData;
+
+ /// bitvector indicating real projections
+ vector<bool>* trimFlags;
+};
+
+#include "qlparser/qtmintervaldata.icc"
+
+#endif
+
+
+
+
diff --git a/qlparser/qtmintervaldata.icc b/qlparser/qtmintervaldata.icc
new file mode 100644
index 0000000..b5a003f
--- /dev/null
+++ b/qlparser/qtmintervaldata.icc
@@ -0,0 +1,59 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+
+inline const r_Minterval&
+QtMintervalData::getMintervalData() const
+{
+ return mintervalData;
+}
+
+
+inline void
+QtMintervalData::setMintervalData( const r_Minterval& minterval )
+{
+ mintervalData = minterval;
+
+ // reset trim flags
+
+ if( trimFlags ) delete trimFlags;
+ trimFlags = new vector<bool>( minterval.dimension() );
+
+ for( int i=0; i<trimFlags->size(); i++ )
+ (*trimFlags)[i] = true;
+}
+
+
+inline const vector<bool>*
+QtMintervalData::getTrimFlags() const
+{
+ return trimFlags;
+}
+
+
diff --git a/qlparser/qtmintervalop.cc b/qlparser/qtmintervalop.cc
new file mode 100644
index 0000000..e112f18
--- /dev/null
+++ b/qlparser/qtmintervalop.cc
@@ -0,0 +1,222 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)qlparser, QtMintervalOp: $Header: /home/rasdev/CVS-repository/rasdaman/qlparser/qtmintervalop.cc,v 1.12 2003/12/27 20:51:28 rasdev Exp $";
+
+#include "raslib/rmdebug.hh"
+
+#include "qlparser/qtmintervalop.hh"
+#include "qlparser/qtdata.hh"
+#include "qlparser/qtmintervaldata.hh"
+#include "qlparser/qtintervaldata.hh"
+#include "qlparser/qtatomicdata.hh"
+
+#include "catalogmgr/ops.hh"
+#include "relcatalogif/type.hh"
+
+#include <iostream>
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+using namespace std;
+#endif
+
+
+const QtNode::QtNodeType QtMintervalOp::nodeType = QT_MINTERVALOP;
+
+QtMintervalOp::QtMintervalOp( QtOperationList* opList )
+ : QtNaryOperation( opList )
+{
+}
+
+
+
+QtData*
+QtMintervalOp::evaluate( QtDataList* inputList )
+{
+ RMDBCLASS( "QtMintervalOp", "evaluate( QtDataList* )", "qlparser", __FILE__, __LINE__ )
+
+ QtData* returnValue = NULL;
+ QtDataList* operandList = NULL;
+
+ if( getOperands( inputList, operandList ) )
+ {
+ vector<QtData*>::iterator dataIter;
+ bool goOn=true;
+
+ // check for point operand
+ if( operandList->size() == 1 && ((*operandList)[0])->getDataType() == QT_MINTERVAL )
+ {
+ // pass point as minterval projection
+ returnValue = (*operandList)[0];
+
+ delete operandList;
+ operandList=NULL;
+ }
+ else
+ {
+ // first check operand types
+ for( dataIter=operandList->begin(); dataIter!=operandList->end() && goOn; dataIter++ )
+ if (!( (*dataIter)->getDataType() == QT_SHORT || (*dataIter)->getDataType() == QT_USHORT ||
+ (*dataIter)->getDataType() == QT_LONG || (*dataIter)->getDataType() == QT_ULONG ||
+ (*dataIter)->getDataType() == QT_OCTET || (*dataIter)->getDataType() == QT_CHAR ||
+ (*dataIter)->getDataType() == QT_INTERVAL))
+ {
+ goOn=false;
+ break;
+ }
+
+ if( !goOn )
+ {
+ RMInit::logOut << "Error: QtMintervalOp::evaluate() - expressions for minterval dimensions must be either of type integer or interval." << endl;
+ parseInfo.setErrorNo(390);
+
+ // delete the old operands
+ if( operandList )
+ {
+ for( dataIter=operandList->begin(); dataIter!=operandList->end(); dataIter++ )
+ if( (*dataIter) ) (*dataIter)->deleteRef();
+
+ delete operandList;
+ operandList=NULL;
+ }
+
+ throw parseInfo;
+ }
+
+ //
+ // create a QtMintervalData object and fill it
+ //
+ r_Minterval domainData( operandList->size() );
+ vector<bool>* trimFlags = new vector<bool>( operandList->size() );
+ int pos;
+
+ for( dataIter=operandList->begin(), pos=0; dataIter!=operandList->end(); dataIter++,pos++ )
+ {
+ if( (*dataIter)->getDataType() == QT_INTERVAL )
+ {
+ domainData << ((QtIntervalData*)(*dataIter))->getIntervalData();
+ (*trimFlags)[pos] = true;
+ }else
+ {
+ if( (*dataIter)->getDataType() == QT_SHORT ||
+ (*dataIter)->getDataType() == QT_LONG ||
+ (*dataIter)->getDataType() == QT_OCTET )
+ domainData << ((QtAtomicData*)(*dataIter))->getSignedValue();
+ else
+ domainData << ((QtAtomicData*)(*dataIter))->getUnsignedValue();
+
+ (*trimFlags)[pos] = false;
+ }
+ }
+
+ returnValue = new QtMintervalData( domainData, trimFlags );
+
+ // delete the old operands
+ if( operandList )
+ {
+ for( dataIter=operandList->begin(); dataIter!=operandList->end(); dataIter++ )
+ if( (*dataIter) ) (*dataIter)->deleteRef();
+
+ delete operandList;
+ operandList=NULL;
+ }
+ }
+ }
+
+ return returnValue;
+}
+
+
+
+void
+QtMintervalOp::printTree( int tab, ostream& s, QtChildType mode )
+{
+ s << SPACE_STR(tab).c_str() << "QtMintervalOp Object " << getNodeType() << endl;
+
+ QtNaryOperation::printTree( tab, s, mode );
+}
+
+
+
+void
+QtMintervalOp::printAlgebraicExpression( ostream& s )
+{
+ s << "[";
+
+ QtNaryOperation::printAlgebraicExpression( s );
+
+ s << "]";
+}
+
+
+
+const QtTypeElement&
+QtMintervalOp::checkType( QtTypeTuple* typeTuple )
+{
+ RMDBCLASS( "QtMintervalOp", "checkType( QtTypeTuple* )", "qlparser", __FILE__, __LINE__ )
+
+ dataStreamType.setDataType( QT_TYPE_UNKNOWN );
+
+ QtOperationList::iterator iter;
+ bool opTypesValid = true;
+
+ for( iter=operationList->begin(); iter!=operationList->end() && opTypesValid; iter++ )
+ {
+ const QtTypeElement& type = (*iter)->checkType( typeTuple );
+
+ // valid types: interval, integers
+ if (!( type.getDataType() == QT_INTERVAL ||
+ type.getDataType() == QT_SHORT ||
+ type.getDataType() == QT_LONG ||
+ type.getDataType() == QT_OCTET ||
+ type.getDataType() == QT_USHORT ||
+ type.getDataType() == QT_ULONG ||
+ type.getDataType() == QT_CHAR))
+ {
+ opTypesValid=false;
+ break;
+ }
+ }
+
+ if( !opTypesValid )
+ {
+ RMInit::logOut << "Error: QtMintervalOp::checkType() - expressions for minterval dimensions must be either of type integer or interval." << endl;
+ parseInfo.setErrorNo(390);
+ throw parseInfo;
+ }
+
+ dataStreamType.setDataType( QT_MINTERVAL );
+
+ return dataStreamType;
+}
diff --git a/qlparser/qtmintervalop.hh b/qlparser/qtmintervalop.hh
new file mode 100644
index 0000000..9d3316e
--- /dev/null
+++ b/qlparser/qtmintervalop.hh
@@ -0,0 +1,81 @@
+#ifndef _QTMINTERVALOP_
+#define _QTMINTERVALOP_
+
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+#endif
+
+#include "qlparser/qtnaryoperation.hh"
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+ The class represents the root of an minterval expression.
+
+*/
+
+class QtMintervalOp : public QtNaryOperation
+{
+ public:
+ /// constructor getting the two operands
+ QtMintervalOp( QtOperationList* opList );
+
+ /// method for evaluating the node
+ QtData* evaluate( QtDataList* inputList );
+ /**
+ */
+
+ /// prints the tree
+ virtual void printTree( int tab, std::ostream& s = std::cout, QtChildType mode = QT_ALL_NODES );
+
+ /// prints the algebraic expression
+ virtual void printAlgebraicExpression( std::ostream& s = std::cout );
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ /// type checking of the subtree
+ virtual const QtTypeElement& checkType( QtTypeTuple* typeTuple = NULL );
+
+ private:
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+
+#include "qlparser/qtmintervalop.icc"
+
+#endif
+
diff --git a/qlparser/qtmintervalop.icc b/qlparser/qtmintervalop.icc
new file mode 100644
index 0000000..3cadc8f
--- /dev/null
+++ b/qlparser/qtmintervalop.icc
@@ -0,0 +1,34 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+inline const QtNode::QtNodeType
+QtMintervalOp::getNodeType() const
+{
+ return nodeType;
+}
diff --git a/qlparser/qtnaryoperation.cc b/qlparser/qtnaryoperation.cc
new file mode 100644
index 0000000..4923004
--- /dev/null
+++ b/qlparser/qtnaryoperation.cc
@@ -0,0 +1,414 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)qlparser, QtNaryOperation: $Header: /home/rasdev/CVS-repository/rasdaman/qlparser/qtnaryoperation.cc,v 1.13 2003/12/27 20:51:28 rasdev Exp $";
+
+#include "qlparser/qtnaryoperation.hh"
+#include "qlparser/qtconst.hh"
+
+#include <iostream>
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+using namespace std;
+#endif
+
+const QtNode::QtNodeType QtNaryOperation::nodeType = QtNode::QT_NARY_OPERATION;
+
+QtNaryOperation::QtNaryOperation()
+ : QtOperation(),
+ operationList(NULL)
+{
+}
+
+
+QtNaryOperation::QtNaryOperation( QtNode* node )
+ : QtOperation( node ),
+ operationList(NULL)
+{
+}
+
+
+QtNaryOperation::QtNaryOperation( QtOperationList* opList )
+ : QtOperation(),
+ operationList( opList )
+{
+ if( operationList )
+ {
+ QtOperationList::iterator iter;
+
+ for( iter=operationList->begin(); iter!=operationList->end(); iter++)
+ (*iter)->setParent( this );
+ }
+}
+
+
+QtNaryOperation::~QtNaryOperation()
+{
+ if( operationList )
+ {
+ QtOperationList::iterator iter;
+
+ for( iter=operationList->begin(); iter!=operationList->end(); iter++)
+ {
+ delete *iter;
+ *iter=NULL;
+ }
+
+ delete operationList;
+ operationList=NULL;
+ }
+}
+
+
+void
+QtNaryOperation::simplify()
+{
+ RMDBCLASS( "QtNaryOperation", "simplify()", "qlparser", __FILE__, __LINE__ )
+
+ // In order to work bottom up, first inspect the descendants
+ QtNode::simplify();
+
+ // Test, if all operands are available.
+ bool success = (operationList != NULL);
+ QtOperationList::iterator iter;
+
+ if( success )
+ for( iter=operationList->begin(); iter!=operationList->end(); iter++)
+ if ((*iter) == NULL)
+ {
+ success = false;
+ break;
+ }
+
+ if( success )
+ {
+ // Test, if all operands are of const type.
+ for( iter=operationList->begin(); iter!=operationList->end(); iter++)
+ if ((*iter)->getNodeType() != QT_CONST)
+ {
+ success = false;
+ break;
+ }
+
+ if( success )
+ {
+ // evaluate the self node with no input list
+ QtData* newConst = this->evaluate( NULL );
+
+ if( newConst )
+ {
+ // create a new constant node and fill it with newConst
+ QtConst* newNode = new QtConst( newConst );
+
+ // set its data stream type
+ newNode->checkType( NULL );
+
+ // link it to the parent
+ getParent()->setInput( this, newNode );
+
+ // delete the self node and its descendants
+ delete this;
+ }
+ }
+ }
+}
+
+
+
+bool
+QtNaryOperation::equalMeaning( QtNode* node )
+{
+ RMDBCLASS( "QtNaryOperation", "equalMeaning( QtNode* )", "qlparser", __FILE__, __LINE__ )
+
+ bool result;
+ result=false;
+
+ if( getNodeType() == node->getNodeType() )
+ {
+ QtNaryOperation* naryNode;
+ naryNode = (QtNaryOperation* ) node; // by force
+
+ // get 2nd operation list
+ QtOperationList* operationList2 = naryNode->getInputs();
+
+ // create iterators
+ QtOperationList::iterator iter, iter2;
+
+ result = true;
+ for( iter =operationList->begin(), iter2 =operationList2->begin();
+ iter!=operationList->end() && iter2!=operationList2->end();
+ iter++, iter2++ )
+ if (!( (*iter)->equalMeaning( *iter2 ) ))
+ {
+ result=false;
+ break;
+ }
+
+ // input lists must have the same length
+ result &= ( iter==operationList->end() && iter2==operationList2->end() );
+ };
+
+ return result;
+}
+
+
+
+QtNode::QtNodeList*
+QtNaryOperation::getChilds( QtChildType flag )
+{
+ RMDBCLASS( "QtNaryOperation", "getChilds( QtChildType )", "qlparser", __FILE__, __LINE__ )
+
+ QtNodeList* resultList=NULL;
+ QtNodeList* subList=NULL;
+
+ QtOperationList::iterator iter;
+
+ resultList = new QtNodeList();
+
+ for( iter=operationList->begin(); iter!=operationList->end(); iter++ )
+ {
+ if( flag == QT_LEAF_NODES || flag == QT_ALL_NODES )
+ {
+ subList = (*iter)->getChilds( flag );
+ resultList->splice(resultList->begin(), *subList);
+ delete subList;
+ subList=NULL;
+ };
+
+ if( flag == QT_DIRECT_CHILDS || flag == QT_ALL_NODES )
+ resultList->push_back( *iter );
+ };
+
+ return resultList;
+}
+
+
+bool
+QtNaryOperation::getOperands( QtDataList* inputList, QtDataList* &operandList )
+{
+ RMDBCLASS( "QtNaryOperation", "getOperands( QtDataList*, QtDataList* )", "qlparser", __FILE__, __LINE__ )
+
+ bool success = (operationList != 0);
+
+ // Test, if all operands are available.
+ QtOperationList::iterator iter;
+
+ if( success )
+ for( iter=operationList->begin(); iter!=operationList->end(); iter++)
+ if ((*iter) == NULL)
+ {
+ success=false;
+ break;
+ }
+
+ if( success )
+ {
+ // get the operands
+ operandList = new QtDataList( operationList->size() );
+
+ int pos=0;
+
+ for( iter=operationList->begin(); iter!=operationList->end(); iter++)
+ {
+ if( *iter )
+ (*operandList)[pos] = (*iter)->evaluate( inputList );
+
+ pos++;
+ }
+
+ // Test, if all operands are valid.
+ for( pos=0; pos<operandList->size(); pos++ )
+ if ((*operandList)[pos] == NULL)
+ {
+ success=false;
+ break;
+ }
+
+ if( !success )
+ {
+ // if not all operands are valid, delete the old ones
+ QtDataList::iterator dataIter;
+
+ for( dataIter=operandList->begin(); dataIter!=operandList->end(); dataIter++ )
+ if( (*dataIter) ) (*dataIter)->deleteRef();
+
+ delete operandList;
+ operandList = NULL;
+
+ RMDBGONCE(2, RMDebug::module_qlparser, "QtNaryOperation", "Information: QtNaryOperation::getOperands() - at least one operand is not provided." )
+ }
+ }
+ else
+ RMInit::logOut << endl << "Error: QtNaryOperation::getOperands() - at least one operand branch is invalid." << endl;
+
+ return success;
+}
+
+
+
+string
+QtNaryOperation::getSpelling()
+{
+ QtOperationList::iterator iter;
+
+ char tempStr[20];
+ sprintf(tempStr, "%ud", (unsigned long)getNodeType());
+ string result = string(tempStr);
+
+ result.append( "(" );
+
+ for( iter=operationList->begin(); iter!=operationList->end(); iter++ )
+ {
+ if( iter!=operationList->begin() ) result.append( "," );
+
+ result.append( (*iter)->getSpelling() );
+ }
+
+ result.append( ")" );
+
+ RMDBGONCE(2, RMDebug::module_qlparser, "QtNaryOperation", "Result:" << result.c_str() )
+
+ return result;
+}
+
+
+
+void
+QtNaryOperation::setInput( QtOperation* inputOld, QtOperation* inputNew )
+{
+ QtOperationList::iterator iter;
+
+ for( iter=operationList->begin(); iter!=operationList->end(); iter++)
+ {
+ if( *iter == inputOld )
+ {
+ (*iter) = inputNew;
+
+ if( inputNew )
+ inputNew->setParent( this );
+ };
+ };
+};
+
+
+
+QtNode::QtAreaType
+QtNaryOperation::getAreaType()
+{
+ return QT_AREA_SCALAR;
+}
+
+/*
+void
+QtNaryOperation::checkIdempotency()
+{
+ // default method: do nothing
+}
+*/
+
+void
+QtNaryOperation::optimizeLoad( QtTrimList* trimList )
+{
+ RMDBCLASS( "QtNaryOperation", "optimizeLoad( QtTrimList* )", "qlparser", __FILE__, __LINE__ )
+
+ // delete trimList
+ // release( trimList->begin(), trimList->end() );
+ for( QtNode::QtTrimList::iterator iter=trimList->begin(); iter!=trimList->end(); iter++ )
+ {
+ delete *iter;
+ *iter=NULL;
+ }
+ delete trimList;
+ trimList=NULL;
+
+ if( operationList )
+ {
+ QtOperationList::iterator iter;
+
+ for( iter=operationList->begin(); iter!=operationList->end(); iter++)
+ if( *iter )
+ (*iter)->optimizeLoad( new QtNode::QtTrimList );
+ }
+}
+
+
+void
+QtNaryOperation::printTree( int tab, ostream& s, QtChildType mode )
+{
+ if( mode != QT_DIRECT_CHILDS )
+ {
+ if( operationList )
+ {
+ QtOperationList::iterator iter;
+ int no;
+
+ for( no=1, iter=operationList->begin(); iter!=operationList->end(); iter++, no++ )
+ if( *iter )
+ {
+ s << SPACE_STR(tab).c_str() << "input" << no << ": " << endl;
+ (*iter)->printTree( tab+2, s, mode );
+ }
+ }
+ }
+}
+
+
+
+void
+QtNaryOperation::printAlgebraicExpression( ostream& s )
+{
+ s << "(";
+
+ if( operationList )
+ {
+ QtOperationList::iterator iter;
+
+ for( iter=operationList->begin(); iter!=operationList->end(); iter++ )
+ {
+ if( iter!=operationList->begin() ) s << ",";
+
+ if( *iter )
+ (*iter)->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+ }
+ }
+ else
+ s << "<nn>";
+
+ s << ")";
+}
+
+
+
diff --git a/qlparser/qtnaryoperation.hh b/qlparser/qtnaryoperation.hh
new file mode 100644
index 0000000..142ea40
--- /dev/null
+++ b/qlparser/qtnaryoperation.hh
@@ -0,0 +1,137 @@
+#ifndef _QTNARYOPERATION_
+#define _QTNARYOPERATION_
+
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+#endif
+
+#include <stdio.h>
+
+#include "qlparser/qtoperation.hh"
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/**************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+ The class serves as superclass for all operation classes taking n
+ (more than two) arguments.
+
+*/
+
+class QtNaryOperation : public QtOperation
+{
+ public:
+ /// default constructor
+ QtNaryOperation();
+
+ /// constructor getting the node to the parent
+ QtNaryOperation( QtNode* node );
+
+ /// constructor getting a list of operands
+ QtNaryOperation( QtOperationList* opList );
+
+ /// virtual destructor
+ virtual ~QtNaryOperation();
+
+ /// simplifies the tree
+ virtual void simplify();
+
+ /// test if the two nodes have an equal meaning in the query tree
+ virtual bool equalMeaning( QtNode* node );
+ /**
+ The meaning of a binary operation is equal, iff all operands have
+ the same meaning.
+ */
+
+ /// return childs of the node
+ virtual QtNodeList* getChilds( QtChildType flag );
+
+ /// creates a unique name for a subexpression
+ virtual std::string getSpelling();
+
+ /// method for query rewrite
+ virtual void setInput( QtOperation*, QtOperation* inputNew );
+
+ /// tests if the edge to the parent node is of type mdd or atomic
+ virtual QtAreaType getAreaType();
+
+ /// method for checking idempotency rules
+// virtual void checkIdempotency();
+
+ /// optimizing load access
+ virtual void optimizeLoad( QtTrimList* trimList );
+ /**
+ The method deletes the given {\tt trimList} and passes the {\tt optimizeLoad}
+ message with empty triming lists to its input trees.
+ */
+
+ /// debugging method
+ virtual void printTree( int tab, std::ostream& s = std::cout, QtChildType mode = QT_ALL_NODES );
+
+ /// prints the algebraic expression
+ virtual void printAlgebraicExpression( std::ostream& s = std::cout );
+
+ //@Man: read/write methods for the operands
+ //@{
+ ///
+ ///
+ inline void setInputs( QtOperationList* opList );
+ ///
+ inline QtNode::QtOperationList* getInputs();
+ ///
+ //@}
+
+ protected:
+ /// method for testing and evaluating the input branches
+ bool getOperands( QtDataList* inputList, QtDataList* &operandList );
+ /**
+ The method checks if the input branches are valid. Then it passes the evaluate message to its two
+ operands with the {\tt inputList} as argument. The returned results are provided through the arguments
+ {\tt operand1} and {\tt operand2} called by reference. The method returns {\tt true} if the operands are
+ valid, otherwise {\tt false}.
+ */
+
+ /// operation trees
+ QtOperationList* operationList;
+
+ private:
+ /// atribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+#include "qlparser/qtnaryoperation.icc"
+
+#endif
+
+
diff --git a/qlparser/qtnaryoperation.icc b/qlparser/qtnaryoperation.icc
new file mode 100644
index 0000000..18f104c
--- /dev/null
+++ b/qlparser/qtnaryoperation.icc
@@ -0,0 +1,50 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+inline void
+QtNaryOperation::setInputs( QtOperationList* opList )
+{
+ operationList = opList;
+
+ if( operationList )
+ {
+ QtOperationList::iterator iter;
+
+ for( iter=operationList->begin(); iter!=operationList->end(); iter++ )
+ if( *iter )
+ (*iter)->setParent( this );
+ }
+};
+
+
+inline QtNode::QtOperationList*
+QtNaryOperation::getInputs()
+{
+ return operationList;
+};
diff --git a/qlparser/qtnode.cc b/qlparser/qtnode.cc
new file mode 100644
index 0000000..77313db
--- /dev/null
+++ b/qlparser/qtnode.cc
@@ -0,0 +1,645 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)qlparser, QtNode: $Id: qtnode.cc,v 1.27 2002/06/05 18:18:17 coman Exp $";
+
+#include "qlparser/qtnode.hh"
+#include "catalogmgr/typefactory.hh"
+#include "relcatalogif/type.hh"
+#include "relcatalogif/basetype.hh"
+
+#include <iostream>
+#include <algorithm>
+
+
+const QtNode::QtNodeType QtNode::nodeType = QT_UNDEFINED_NODE;
+
+ const int QtNode::QtNodes = 80;
+
+ const QtNode::QtNodeType QtNode::QtRoot = QT_UNDEFINED_NODE;
+
+ const QtNode::QtNodeType QtNode::QtInheritance[][2] = {
+ {QT_UNDEFINED_NODE, QT_EXECUTE},
+ {QT_EXECUTE, QT_COMMAND},
+ {QT_EXECUTE, QT_DELETE},
+ {QT_EXECUTE, QT_INSERT},
+ {QT_EXECUTE, QT_PYRAMID},
+ {QT_EXECUTE, QT_UPDATE},
+ {QT_UNDEFINED_NODE, QT_ONC_STREAM},
+ {QT_ONC_STREAM, QT_ITERATOR},
+ {QT_ITERATOR, QT_JOIN_ITERATOR},
+ {QT_ITERATOR, QT_OPERATION_ITERATOR},
+ {QT_ITERATOR, QT_SELECTION_ITERATOR},
+ {QT_ONC_STREAM, QT_MDD_ACCESS},
+ {QT_UNDEFINED_NODE, QT_OPERATION},
+ {QT_OPERATION, QT_BINARY_OPERATION},
+ {QT_BINARY_OPERATION, QT_BINARY_INDUCE},
+ {QT_BINARY_INDUCE, QT_AND},
+ {QT_BINARY_INDUCE, QT_BIT},
+ {QT_BINARY_INDUCE, QT_DIV},
+ {QT_BINARY_INDUCE, QT_EQUAL},
+ {QT_BINARY_INDUCE, QT_IS},
+ {QT_BINARY_INDUCE, QT_LESS},
+ {QT_BINARY_INDUCE, QT_LESS_EQUAL},
+ {QT_BINARY_INDUCE, QT_MINUS},
+ {QT_BINARY_INDUCE, QT_MULT},
+ {QT_BINARY_INDUCE, QT_NOT_EQUAL},
+ {QT_BINARY_INDUCE, QT_OR},
+ {QT_BINARY_INDUCE, QT_OVERLAY},
+ {QT_BINARY_INDUCE, QT_PLUS},
+ {QT_BINARY_INDUCE, QT_XOR},
+ {QT_BINARY_OPERATION, QT_CONDENSEOP},
+ {QT_BINARY_OPERATION, QT_EXTEND},
+ {QT_BINARY_OPERATION, QT_INTERVALOP},
+ {QT_BINARY_OPERATION, QT_MARRAYOP},
+ {QT_BINARY_OPERATION, QT_SCALE},
+ {QT_BINARY_OPERATION, QT_SHIFT},
+ {QT_OPERATION, QT_CONST},
+ {QT_OPERATION, QT_GROUP_ITERATOR},
+ {QT_OPERATION, QT_IDENT},
+ {QT_OPERATION, QT_MDD_STREAM},
+ {QT_OPERATION, QT_NARY_OPERATION},
+ {QT_NARY_OPERATION, QT_MINTERVALOP},
+ {QT_NARY_OPERATION, QT_POINTOP},
+ {QT_OPERATION, QT_UNARY_OPERATION},
+ {QT_UNARY_OPERATION, QT_CONDENSE},
+ {QT_CONDENSE, QT_ADDCELLS},
+ {QT_CONDENSE, QT_ALL},
+ {QT_CONDENSE, QT_AVGCELLS},
+ {QT_CONDENSE, QT_COUNTCELLS},
+ {QT_CONDENSE, QT_MAXCELLS},
+ {QT_CONDENSE, QT_MINCELLS},
+ {QT_CONDENSE, QT_SOME},
+ {QT_UNARY_OPERATION, QT_CONVERSION},
+ {QT_UNARY_OPERATION, QT_CSE_ROOT},
+ {QT_UNARY_OPERATION, QT_DOMAIN_OPERATION},
+ {QT_UNARY_OPERATION, QT_HI},
+ {QT_UNARY_OPERATION, QT_LO},
+ {QT_UNARY_OPERATION, QT_OID},
+ {QT_UNARY_OPERATION, QT_SDOM},
+ {QT_UNARY_OPERATION, QT_UNARY_INDUCE},
+ {QT_UNARY_INDUCE, QT_CAST},
+ {QT_UNARY_INDUCE, QT_DOT},
+ {QT_UNARY_INDUCE, QT_IMAGINARPART},
+ {QT_UNARY_INDUCE, QT_NOT},
+ {QT_UNARY_INDUCE, QT_REALPART},
+ {QT_UNARY_INDUCE, QT_ABS},
+ {QT_UNARY_INDUCE, QT_SQRT},
+ {QT_UNARY_INDUCE, QT_EXP},
+ {QT_UNARY_INDUCE, QT_LOG},
+ {QT_UNARY_INDUCE, QT_LN},
+ {QT_UNARY_INDUCE, QT_SIN},
+ {QT_UNARY_INDUCE, QT_COS},
+ {QT_UNARY_INDUCE, QT_TAN},
+ {QT_UNARY_INDUCE, QT_SINH},
+ {QT_UNARY_INDUCE, QT_COSH},
+ {QT_UNARY_INDUCE, QT_TANH},
+ {QT_UNARY_INDUCE, QT_ARCSIN},
+ {QT_UNARY_INDUCE, QT_ARCCOS},
+ {QT_UNARY_INDUCE, QT_ARCTAN},
+ {QT_OPERATION, QT_MDD_VAR}
+};
+
+
+
+int QtNode::minim[QtNodes];
+int QtNode::maxim[QtNodes];
+int QtNode::child_range[QtNodes+1];
+
+bool QtNode::MinMaxDone = false;
+
+QtNode::QtNode()
+ : parent(NULL)
+{
+ if (!MinMaxDone) {
+ MinMaxDone = true;
+ SetMinMax();
+ }
+}
+
+
+QtNode::QtNode( QtNode* node )
+ : parent( node )
+{
+ if (!MinMaxDone) {
+ MinMaxDone = true;
+ SetMinMax();
+ }
+}
+
+
+QtNode::~QtNode()
+{
+}
+
+bool
+QtNode::subtype( enum QtNodeType a, enum QtNodeType b )
+{
+ return (minim[a]<=minim[b] && maxim[b]<=maxim[a]);
+}
+
+
+QtNode::QtNodeList*
+QtNode::getChilds( QtChildType flag )
+{
+ RMDBCLASS( "QtNode", "getChilds( QtChildType )", "qlparser", __FILE__, __LINE__ )
+
+ // Default definition is used for all leaf nodes.
+
+ // Algorithm:
+ //
+ // In mode QT_ALL_NODES each node calls getChild() of every son,
+ // merges these lists and inserts direct childs but not the node
+ // itself.
+ // In mode QT_DIRECT_CHILDS each node inserts just direct childs.
+ // In mode QT_LEAF_NODES the method call is passed to the sons
+ // and just the leaf nodes insert themselves.
+
+ QtNodeList* resultList=NULL;
+
+ resultList = new QtNodeList();
+
+ if( flag == QT_LEAF_NODES )
+ resultList->push_back( this );
+
+ return resultList;
+}
+
+
+QtNode::QtNodeList*
+QtNode::getChild( const QtNodeType node, QtChildType flag )
+{
+ RMDBCLASS( "QtNode", "getChild( QtChildType )", "qlparser", __FILE__, __LINE__ )
+
+ QtNodeList* resultList=NULL;
+ QtNodeList::iterator iter;
+
+ resultList = getChilds( flag );
+
+ for( iter=resultList->begin(); iter!=resultList->end(); iter++ )
+ if( node != (*iter)->getNodeType() )
+ resultList->erase( iter-- );
+
+ return resultList;
+}
+
+
+bool
+QtNode::equalMeaning( QtNode* /*node*/ )
+{
+ return false;
+}
+
+
+std::string
+QtNode::getSpelling()
+{
+ return "";
+}
+
+QtNode::QtAreaType
+QtNode::getAreaType()
+{
+ return QT_AREA_SCALAR;
+}
+
+
+
+void
+QtNode::simplify()
+{
+ RMDBCLASS( "QtNode", "simplify()", "qlparser", __FILE__, __LINE__ )
+
+ // Default method for all classes that have no implementation.
+ // Method is used bottom up.
+
+ QtNodeList* resultList=NULL;
+ QtNodeList::iterator iter;
+
+ try
+ {
+ resultList = getChilds( QT_DIRECT_CHILDS );
+ for( iter=resultList->begin(); iter!=resultList->end(); iter++ )
+ (*iter)->simplify();
+ }
+ catch(...)
+ {
+ if( resultList )
+ {
+ delete resultList;
+ resultList=NULL;
+ }
+ throw;
+ }
+
+ delete resultList;
+ resultList=NULL;
+}
+
+
+/*
+void
+QtNode::rewriteOps()
+{
+ RMDBGONCE( 1, RMDebug::module_qlparser, "QtNode", " QtNode::rewriteOps() " )
+
+ // Default method for all classes that have no implementation.
+ // Method is used top down.
+
+ QtNodeList* resultList=NULL;
+ QtNodeList::iterator iter;
+
+ resultList = getChilds( QT_DIRECT_CHILDS );
+ for( iter=resultList->begin(); iter!=resultList->end(); iter++ )
+ (*iter)->rewriteOps();
+
+ delete resultList;
+ resultList=NULL;
+}
+*/
+
+/*
+void
+QtNode::sortAssociativeOps()
+{
+ RMDBGONCE( 1, RMDebug::module_qlparser, "QtScale", " QtNode::sortAssociativeOps()" )
+
+ // Default method for all nodes that have no own method
+ // method is used top down
+
+ QtNodeList* resultList=NULL;
+ QtNodeList::iterator iter;
+
+ resultList = getChilds( QT_DIRECT_CHILDS );
+
+ for( iter=resultList->begin(); iter!=resultList->end(); iter++ )
+ (*iter)->sortAssociativeOps();
+
+ delete resultList;
+ resultList=NULL;
+}
+*/
+
+
+/*
+void
+QtNode::checkIdempotency()
+{
+ RMDBGONCE( 1, RMDebug::module_qlparser, "QtNode", " QtNode::checkIdempotency()" )
+
+ // method is used bottom up
+ // default method for all nodes that have no own method
+}
+*/
+
+QtNode::QtNodeType
+QtNode::getQtNodeTypeParent (QtNode::QtNodeType node) {
+ int i = 0;
+ for (i=0; i<QtNodes; i++)
+ if ( QtInheritance[i][1] == node ) return QtInheritance[i][0];
+ throw r_Error(QTNODETYPEPARENTDOESNOTEXIST);
+}
+
+
+bool
+operator<(const QtNode::QtNodePair a, const QtNode::QtNodePair b){
+ return (a.base < b.base);
+}
+
+void
+QtNode::num_node (const QtNodePair *arr, const enum QtNodeType x) {
+ int i;
+ static int ID = 0 ;
+ enum QtNodeType child;
+ minim[x] = ID++;
+ for (i = child_range[x]; i < child_range[x+1]; i++)
+ num_node(arr, arr[i].deriv);
+ maxim[x] = ID++;
+}
+
+void
+QtNode::set_child_range(const QtNodePair *arr) {
+ int i;
+ child_range[QtNodes] = QtNodes-1;
+ for (i=QtNodes-3; i>=0; i--)
+ if (arr[i].base != arr[i+1].base) child_range[arr[i+1].base] = i+1;
+ child_range[arr[0].base] = 0;
+ for (i=QtNodes-1; i>0; i--)
+ if (child_range[i] == 0) child_range[i] = child_range[i+1];
+}
+
+void
+QtNode::SetMinMax()
+{
+ int i;
+ QtNodePair arr[QtNodes-1];
+ for (i=0; i<(QtNodes-1); i++) {
+ arr[i].base = QtInheritance[i][0];
+ arr[i].deriv = QtInheritance[i][1];
+ }
+ std::sort(arr,arr+QtNodes-1);
+ //creating child_range
+ set_child_range(arr);
+ //numbering the nodes
+ num_node(arr, QtRoot);
+}
+
+
+QtTypeElement::QtTypeElement()
+ : dataType( QT_TYPE_UNKNOWN ),
+ type(NULL),
+ name(NULL)
+{
+}
+
+
+
+QtTypeElement::QtTypeElement( const QtDataType initDataType,
+ const char* initName )
+ : dataType( QT_TYPE_UNKNOWN ),
+ type( NULL ),
+ name( NULL )
+{
+ setDataType( initDataType );
+
+ if( initName ) name = strdup( initName );
+}
+
+
+
+QtTypeElement::QtTypeElement( const Type* initType,
+ const char* initName )
+ : dataType( QT_TYPE_UNKNOWN ),
+ type( NULL ),
+ name( NULL )
+{
+ setType( initType );
+
+ if( initName ) name = strdup( initName );
+}
+
+
+
+QtTypeElement::QtTypeElement( const QtTypeElement& typeElement )
+ : dataType( typeElement.dataType ),
+ type( typeElement.type ),
+ name(NULL)
+{
+ if( typeElement.name ) name = strdup( typeElement.name );
+}
+
+
+
+QtTypeElement::~QtTypeElement()
+{
+ // Note: Types are free by the type factory.
+
+ if( name )
+ {
+ free( name );
+ name=NULL;
+ }
+}
+
+
+
+const QtTypeElement&
+QtTypeElement::operator=( const QtTypeElement& obj )
+{
+ if( this != &obj )
+ {
+ if( name )
+ {
+ free( name );
+ name = NULL;
+ }
+
+ dataType = obj.dataType;
+ type = obj.type;
+
+ if( obj.name ) name = strdup( obj.name );
+
+ }
+
+ return *this;
+}
+
+
+
+void
+QtTypeElement::printStatus( std::ostream& s ) const
+{
+ if( type )
+ {
+ char* typeStructure = type->getTypeStructure();
+ s << typeStructure << std::flush;
+ free( typeStructure );
+ typeStructure=NULL;
+ }
+ else
+ {
+ switch( dataType )
+ {
+ case QT_STRING:
+ s << "string" << std::flush;
+ break;
+
+ case QT_INTERVAL:
+ s << "interval" << std::flush;
+ break;
+
+ case QT_MINTERVAL:
+ s << "minterval" << std::flush;
+ break;
+
+ case QT_POINT:
+ s << "point" << std::flush;
+ break;
+
+ default:
+ // including case QT_TYPE_UNKNOWN
+ s << "<unknown type>" << std::flush;
+ break;
+ }
+ }
+
+ if( name )
+ s << ":" << name << std::flush;
+}
+
+
+
+void
+QtTypeElement::setDataType( const QtDataType newDataType )
+{
+ dataType = newDataType;
+
+ // reset type information
+ type = NULL;
+
+ switch( dataType )
+ {
+ case QT_TYPE_UNKNOWN:
+ break;
+ case QT_BOOL:
+ type = TypeFactory::mapType("Bool");
+ break;
+ case QT_CHAR:
+ type = TypeFactory::mapType("Char");
+ break;
+ case QT_OCTET:
+ type = TypeFactory::mapType("Octet");
+ break;
+ case QT_USHORT:
+ type = TypeFactory::mapType("UShort");
+ break;
+ case QT_SHORT:
+ type = TypeFactory::mapType("Short");
+ break;
+ case QT_ULONG:
+ type = TypeFactory::mapType("ULong");
+ break;
+ case QT_LONG:
+ type = TypeFactory::mapType("Long");
+ break;
+ case QT_FLOAT:
+ type = TypeFactory::mapType("Float");
+ break;
+ case QT_DOUBLE:
+ type = TypeFactory::mapType("Double");
+ break;
+ case QT_COMPLEXTYPE1:
+ type = TypeFactory::mapType("Complex1");
+ break;
+ case QT_COMPLEXTYPE2:
+ type = TypeFactory::mapType("Complex2");
+ break;
+
+ case QT_MDD:
+ case QT_COMPLEX:
+ RMInit::logOut << "QtTypeElement::setDataType() - MDD and complex types need to be specified further." << std::endl;
+ break;
+
+ case QT_STRING:
+ case QT_INTERVAL:
+ case QT_MINTERVAL:
+ case QT_POINT:
+ default:
+ // transient types
+ break;
+ }
+}
+
+
+
+void
+QtTypeElement::setType(const Type* newType )
+{
+ type = NULL;
+ dataType = QT_TYPE_UNKNOWN;
+
+ if( newType )
+ switch( newType->getType() )
+ {
+ case BOOLTYPE: dataType = QT_BOOL; break;
+ case CHAR: dataType = QT_CHAR; break;
+ case OCTET: dataType = QT_OCTET; break;
+ case USHORT: dataType = QT_USHORT; break;
+ case SHORT: dataType = QT_SHORT; break;
+ case ULONG: dataType = QT_ULONG; break;
+ case LONG: dataType = QT_LONG; break;
+ case FLOAT: dataType = QT_FLOAT; break;
+ case DOUBLE: dataType = QT_DOUBLE; break;
+ case COMPLEXTYPE1: dataType = QT_COMPLEXTYPE1; break;
+ case COMPLEXTYPE2: dataType = QT_COMPLEXTYPE2; break;
+ case MDDTYPE: dataType = QT_MDD; break;
+ case STRUCT: dataType = QT_COMPLEX; break;
+ default: dataType = QT_TYPE_UNKNOWN; break;
+ }
+
+ // if type is supported
+ if( dataType != QT_TYPE_UNKNOWN )
+ type = newType;
+}
+
+
+
+QtTypeTuple::QtTypeTuple( unsigned int length )
+ : tuple( length )
+{
+}
+
+
+
+void
+QtTypeTuple::concat( const QtTypeTuple& typeTuple )
+{
+ // reserve space for concatenated type
+ tuple.reserve( tuple.size() + typeTuple.tuple.size() );
+
+ // concatenate tuples
+ for( std::vector<QtTypeElement>::const_iterator iter = typeTuple.tuple.begin();
+ iter != typeTuple.tuple.end(); iter++ )
+ tuple.push_back( *iter );
+}
+
+
+
+void
+QtTypeTuple::concat( const QtTypeElement& typeElement )
+{
+ tuple.push_back( typeElement );
+}
+
+
+
+void
+QtTypeTuple::printStatus( std::ostream& s ) const
+{
+ s << "<" << std::flush;
+
+ for( std::vector<QtTypeElement>::const_iterator iter = tuple.begin();
+ iter != tuple.end();
+ iter++ )
+ {
+ if( iter != tuple.begin() )
+ s << ", " << std::flush;
+
+ (*iter).printStatus( s );
+ }
+
+ s << ">" << std::flush;
+}
+
+
+
+
diff --git a/qlparser/qtnode.hh b/qlparser/qtnode.hh
new file mode 100644
index 0000000..53a038e
--- /dev/null
+++ b/qlparser/qtnode.hh
@@ -0,0 +1,503 @@
+#ifndef _QTNODE_
+#define _QTNODE_
+
+#ifndef CPPSTDLIB
+#include <vector.h> // STL<ToolKit>
+#include <list.h> // STL<ToolKit>
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <vector>
+#include <list>
+#include <string>
+#endif
+
+#include "raslib/rmdebug.hh"
+#include "raslib/sinterval.hh"
+#include "qlparser/parseinfo.hh"
+#include "qlparser/qtdata.hh"
+
+// define used in lots of qlparser files to indent output
+#ifdef CPPSTDLIB
+#define SPACE_STR(numSpace) std::string(numSpace,' ')
+#else
+#define SPACE_STR(numSpace) std::string(' ',numSpace)
+#endif
+
+class QtOperation; // forward declarations of subclasses of QtNode
+class Type;
+class QtTypeElement;
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+
+//@ManMemo: Module: {\bf qlparser}
+
+/**
+
+ The class QtNode is the common super class of all node
+ classes of the query tree. It provides a reference to its
+ parent node in the tree. The parent of root is null.
+
+*/
+
+
+class QtNode
+{
+ public:
+ /// list of QtData pointers
+ typedef std::vector<QtData*> QtDataList;
+
+ /// struct containing dimension and triming information
+ struct QtTrimElement
+ {
+ r_Dimension dimension;
+ r_Sinterval interval;
+ bool intervalFlag;
+ };
+
+ /// list of QtTrimData structures
+ typedef std::vector<QtTrimElement*> QtTrimList;
+
+ /// list of QtNode pointers
+ typedef std::list<QtNode*> QtNodeList;
+
+ enum QtNodeType
+ {
+ QT_UNDEFINED_NODE,
+ QT_MDD_ACCESS,
+ QT_OPERATION_ITERATOR,
+ QT_SELECTION_ITERATOR,
+ QT_JOIN_ITERATOR,
+ QT_UPDATE,
+ QT_INSERT,
+ QT_DELETE,
+ QT_COMMAND,
+ QT_PLUS,
+ QT_MINUS,
+ QT_MULT,
+ QT_DIV,
+ QT_OR,
+ QT_AND,
+ QT_XOR,
+ QT_IS,
+ QT_EQUAL,
+ QT_NOT_EQUAL,
+ QT_LESS,
+ QT_LESS_EQUAL,
+ QT_NOT,
+ QT_SQRT,
+// added by CStancuMara
+ QT_EXECUTE,
+ QT_ONC_STREAM,
+ QT_ITERATOR,
+ QT_OPERATION,
+ QT_BINARY_OPERATION,
+ QT_BINARY_INDUCE,
+ QT_GROUP_ITERATOR,
+ QT_IDENT,
+ QT_NARY_OPERATION,
+ QT_UNARY_OPERATION,
+ QT_CONDENSE,
+ QT_UNARY_INDUCE,
+
+//**************
+ QT_ABS, QT_EXP, QT_LOG, QT_LN, QT_SIN, QT_COS,
+ QT_TAN, QT_SINH, QT_COSH, QT_TANH, QT_ARCSIN,
+ QT_ARCCOS, QT_ARCTAN,
+ QT_REALPART,
+ QT_IMAGINARPART,
+ QT_CAST,
+//**************
+
+ QT_CSE_ROOT,
+ QT_DOMAIN_OPERATION,
+ QT_ALL,
+ QT_SOME,
+ QT_COUNTCELLS,
+ QT_ADDCELLS,
+ QT_AVGCELLS,
+ QT_MINCELLS,
+ QT_MAXCELLS,
+ QT_MDD_VAR,
+ QT_MDD_STREAM,
+ QT_CONST,
+ QT_DOT,
+ QT_CONVERSION,
+ QT_OID,
+ QT_INTERVALOP,
+ QT_MINTERVALOP,
+ QT_POINTOP,
+ QT_LO,
+ QT_HI,
+ QT_SDOM,
+ QT_SHIFT,
+ QT_EXTEND,
+ //QT_MINTERVAL_SELECT,
+ QT_MARRAYOP,
+ QT_CONDENSEOP,
+ QT_SCALE,
+ QT_OVERLAY,
+ QT_BIT,
+ QT_PYRAMID,
+ QT_LAST_NODE_TYPE
+ };
+
+
+
+ enum QtAreaType
+ {
+ QT_AREA_MDD,
+ QT_AREA_SCALAR
+ };
+
+ enum QtChildType
+ {
+ QT_DIRECT_CHILDS,
+ QT_LEAF_NODES,
+ QT_ALL_NODES
+ };
+
+ /// list of QtOperation pointers
+ typedef std::vector<QtOperation*> QtOperationList;
+
+ /// default constructor
+ QtNode();
+
+ /// constructor getting a pointer to the parent
+ QtNode( QtNode* node );
+
+ /// destructor
+ virtual ~QtNode();
+
+ /// returns weather class b is a subtype of class a
+ bool subtype( enum QtNodeType a, enum QtNodeType b );
+
+ /// return childs of the node
+ virtual QtNodeList* getChilds( QtChildType flag );
+ /**
+ The method allows different retrieval of the subtree nodes. Dependent on the content of {\tt flag}
+ one of the following semantics is used:
+ {\tt DIRECT_CHILDS} - A list of all direct child nodes of the current node is returned.
+ {\tt LEAF_NODES } - A list of all leaf nodes of the subtree with the current node as root is returned.
+ {\tt ALL_NODES } - A list of all nodes of the subtree with the current node as root is returned.
+ The nodes in the result list have a special order. Every node comes before its parent node in
+ the result list.
+ */
+
+ /// return childs of a certain class
+ QtNodeList* getChild( const QtNodeType node, QtChildType flag = QT_DIRECT_CHILDS );
+ /**
+ The method allows to specify the class of childs to be considered according to method {\tt getChilds}.
+ By default, just direct childs are considered
+ */
+
+ /// test if the two nodes have an equal meaning in a subtree
+ virtual bool equalMeaning( QtNode* node );
+
+ /**
+ The method checks, if the two nodes have an equal meaning in a subtree.
+ {\tt equalMeaning()} depends on the type of the node and the information in the node.
+ For unary and binary operators the method {\tt equalMeaning()} is invoked on the input nodes.
+ */
+
+ /// creates a unique name for a common subexpression
+ virtual std::string getSpelling();
+
+ /**
+ The method creates a unique name for common subexpressions by concatenating operators
+ and variables in the subtree of the common subexpression.
+ */
+
+ /// test if the edge to the parent node is of type mdd or atomic
+ virtual QtAreaType getAreaType();
+ /**
+ The method tests if the edge to the parent node belongs to a multidimensional or
+ atomic area.
+ */
+
+ /// simplifies the tree
+ virtual void simplify();
+ /**
+ The method evaluates constant expressions.
+ */
+
+ /// optimizes the tree
+// virtual void rewriteOps();
+ /**
+ The method applies some algebraic rules:
+
+ \begin{verbatim}
+ some( x or y ) -> some( x ) or some( y )
+ all ( x and y ) -> all ( x ) and all ( y )
+ all() or some() -> some() or all()
+ some() and all() -> all() and some()
+ \end{verbatim}
+
+ Further, a left deep tree is produced (for +,*)::
+
+ \begin{verbatim}
+ (T1 o T2) + (T3 o T4) -> ((T1 o T2) o T3) o T4
+ \end{verbatim}
+
+ The method has to be supplied top-down in the query tree.
+ */
+
+ /// optimizes the tree
+// virtual void sortAssociativeOps();
+ /**
+ Operators of commutative binary operations are ordered in a
+ unique sequence.
+ */
+
+ /// check idempetency rules
+// virtual void checkIdempotency();
+ /**
+ The method applies idempotency rules on binary operations.
+ The method is supplied bottom-up in the query tree.
+ */
+
+ /// prints the tree
+ virtual void printTree( int tab, std::ostream& s = std::cout, QtChildType mode = QT_ALL_NODES )=0;
+
+ /// prints the algebraic expression
+ virtual void printAlgebraicExpression( std::ostream& s = std::cout )=0;
+
+ //@Man: Read/Write methods
+ //@{
+ ///
+
+ ///
+ inline virtual void setInput( QtOperation* inputOld, QtOperation* inputNew);
+ ///
+ inline QtNode* getParent() const;
+ ///
+ inline void setParent( QtNode* node );
+ ///
+ inline const ParseInfo& getParseInfo();
+ ///
+ inline void setParseInfo( const ParseInfo &info );
+
+ ///
+ //@}
+
+ /// methods for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+ /**
+ The method allows you to differ between the different node types.
+ */
+
+ /// method for pre optimizations (basically load optimization)
+ //virtual void preOptimize(){};
+ /**
+ {\em Load Optimization}
+ The method is invoked through the whole query tree. The information of
+ every triming and projection node is collected and stored in a {\tt QtTrimList}
+ structure which is passed down. While collecting the information consistency
+ of the data is checked. At the leafs, which are load operations, the structure
+ is converted to a minterval object and stored in the leaf node.
+ The list is dynamically created in the node which is on top of an operation subtree
+ and deleted where the information is stored or dropped.
+
+ Defined empty to do nothing in case it is not defined for a subclass.
+ */
+
+ /// returns the QtNodeType parent of the argument (do not use for the root)
+ enum QtNodeType getQtNodeTypeParent(enum QtNodeType);
+
+ /// number of QtNodeTypes
+ static const int QtNodes;
+
+ /// the root of the inheritance tree
+ static const QtNodeType QtRoot;
+
+ /// the inheritance relations list
+ static const QtNodeType QtInheritance[][2];
+
+
+ protected:
+ /// attribute for parser info
+ ParseInfo parseInfo;
+
+ private:
+ /// pointer to its parent
+ QtNode* parent;
+
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+
+ /// (base_class, derived_class) pair
+ struct QtNodePair {
+ enum QtNodeType base, deriv;
+ };
+
+
+ ///operator overload for QtNodePair struct
+ friend bool operator<( const QtNodePair a, const QtNodePair b);
+
+ /// starting point of elements having node as base class
+ static int child_range[];
+
+ /// sets up the child_range[] array
+ void set_child_range(const QtNodePair *arr);
+
+ /// minim and maxim labels to determine subtypes
+ static int minim[], maxim[];
+
+ /// keeps track if SetMinMax was already called
+ static bool MinMaxDone;
+
+ /// sets minim and maxim values for each QtNodeType
+ void SetMinMax();
+
+ /// sets min max values once child_range is set up, for subtree with x as root
+ void num_node (const QtNodePair *arr, enum QtNodeType x);
+
+};
+
+
+
+
+//@ManMemo: Module: {\bf qlparser}
+
+/**
+
+ The class encapsulates type information. It additionally
+ can hold a name in order to be identifyable in a list.
+
+ The type is specified by {\tt dataType} and {\tt type}.
+ This is necessary because not all types are supported by
+ subclasses of \Ref{Type}, e.g. not all types are persistent ones.
+
+ In case of QT_MDD and QT_COMPLEX, further type information
+ can be optained from {\tt type}.
+
+*/
+
+class QtTypeElement
+{
+ public:
+ ///
+ QtTypeElement();
+
+ ///
+ QtTypeElement( const QtDataType initDataType, const char* initName = NULL );
+
+ ///
+ QtTypeElement( const Type* initType, const char* initName = NULL );
+
+ ///
+ QtTypeElement( const QtTypeElement& typeElement );
+
+ ///
+ ~QtTypeElement();
+
+ /// assignment: cleanup + copy
+ const QtTypeElement& operator= ( const QtTypeElement& );
+
+ //@Man: Read/Write methods
+ //@{
+ ///
+ ///
+ void setDataType( const QtDataType newDataType );
+ ///
+ void setType( const Type* newType );
+ ///
+ inline void setName( const char* newName );
+ ///
+ inline const QtDataType getDataType() const;
+ ///
+ inline const Type* getType() const;
+ ///
+ inline const char* getName() const;
+ ///
+ inline bool isBaseType() const;
+ ///
+ inline bool isInteger() const;
+ ///
+ //@}
+ ///
+
+ /// print type
+ void printStatus( std::ostream& s = std::cout ) const;
+
+ private:
+ ///
+ QtDataType dataType;
+
+ ///
+ const Type* type;
+
+ ///
+ char* name;
+};
+
+
+
+//@ManMemo: Module: {\bf qlparser}
+
+/**
+
+ The class encapsulates a tuple of \Ref{QtTypeElement}
+ objects.
+
+*/
+
+class QtTypeTuple
+{
+ public:
+ ///
+ QtTypeTuple( unsigned int length = 0 );
+
+ /// concatenate type tuple
+ void concat( const QtTypeTuple& typeTuple );
+
+ /// concatenate type element
+ void concat( const QtTypeElement& typeElement );
+
+ ///
+ std::vector<QtTypeElement> tuple;
+
+ /// print type
+ void printStatus( std::ostream& s = std::cout ) const;
+};
+
+#include "qlparser/qtnode.icc"
+
+#endif
+
+
+
+
+
+
+
+
+
+
diff --git a/qlparser/qtnode.icc b/qlparser/qtnode.icc
new file mode 100644
index 0000000..0bdddeb
--- /dev/null
+++ b/qlparser/qtnode.icc
@@ -0,0 +1,130 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#include <cstdlib>
+#include <cstring>
+
+inline QtNode*
+QtNode::getParent() const
+{
+ return parent;
+};
+
+
+inline void
+QtNode::setParent( QtNode* node )
+{
+ parent = node;
+};
+
+
+inline const QtNode::QtNodeType
+QtNode::getNodeType() const
+{
+ return nodeType;
+}
+
+
+
+inline void
+QtNode::setInput( QtOperation* , QtOperation* )
+{
+ RMInit::logOut << "Error: Method setInput(...) is undefined for node type " << getNodeType() << " in the query tree." << endl;
+}
+
+
+inline const ParseInfo&
+QtNode::getParseInfo()
+{
+ return parseInfo;
+}
+
+
+inline void
+QtNode::setParseInfo( const ParseInfo &info )
+{
+ parseInfo = info;
+}
+
+
+
+inline void
+QtTypeElement::setName( const char* newName )
+{
+ if( name ) free( name );
+ name = strdup( newName );
+}
+
+
+
+
+inline const QtDataType
+QtTypeElement::getDataType() const
+{
+ return dataType;
+}
+
+
+
+inline const Type*
+QtTypeElement::getType() const
+{
+ return type;
+}
+
+
+inline const char*
+QtTypeElement::getName() const
+{
+ return name;
+}
+
+
+inline bool
+QtTypeElement::isBaseType() const
+{
+ return dataType == QT_BOOL || dataType == QT_COMPLEX ||
+ dataType == QT_CHAR || dataType == QT_OCTET ||
+ dataType == QT_USHORT || dataType == QT_SHORT ||
+ dataType == QT_ULONG || dataType == QT_LONG ||
+ dataType == QT_FLOAT || dataType == QT_DOUBLE ||
+ dataType == QT_COMPLEXTYPE1 || dataType == QT_COMPLEXTYPE2;
+}
+
+
+
+inline bool
+QtTypeElement::isInteger() const
+{
+ return dataType == QT_CHAR || dataType == QT_OCTET ||
+ dataType == QT_USHORT || dataType == QT_SHORT ||
+ dataType == QT_ULONG || dataType == QT_LONG;
+}
+
+
diff --git a/qlparser/qtoid.cc b/qlparser/qtoid.cc
new file mode 100644
index 0000000..6b6d01b
--- /dev/null
+++ b/qlparser/qtoid.cc
@@ -0,0 +1,179 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)qlparser, QtOId: $Header: /home/rasdev/CVS-repository/rasdaman/qlparser/qtoid.cc,v 1.13 2003/12/27 20:51:28 rasdev Exp $";
+
+#include "qlparser/qtoid.hh"
+#include "qlparser/qtvariable.hh"
+#include "qlparser/qtatomicdata.hh"
+#include "qlparser/qtmdd.hh"
+
+#include "mddmgr/mddobj.hh"
+
+#include "raslib/oid.hh"
+
+const QtNode::QtNodeType QtOId::nodeType = QtNode::QT_OID;
+
+
+QtOId::QtOId( QtVariable* newInput )
+ : QtUnaryOperation( newInput )
+{
+ RMDBCLASS( "QtOId", "QtOId( QtVariable* )", "qlparser", __FILE__, __LINE__ )
+}
+
+
+
+QtData*
+QtOId::evaluate( QtDataList* inputList )
+{
+ RMDBCLASS( "QtOId", "evaluate( QtDataList* )", "qlparser", __FILE__, __LINE__ )
+
+ QtData* returnValue = NULL;
+ QtData* operand = NULL;
+
+ operand = input->evaluate( inputList );
+
+ if( operand )
+ {
+#ifdef QT_RUNTIME_TYPE_CHECK
+ if( operand->getDataType() == QT_MDD )
+ {
+ RMInit::logOut << "Internal error in QtOId::evaluate() - "
+ << "runtime type checking failed (MDD)." << std::endl;
+
+ // delete old operand
+ if( operand ) operand->deleteRef();
+
+ return 0;
+ }
+#endif
+
+ QtMDD* qtMDD = (QtMDD*) operand;
+ MDDObj* mddObj = qtMDD->getMDDObject();
+
+ if( mddObj->isPersistent() )
+ {
+ MDDObj* persMDD = (MDDObj*) mddObj;
+
+ // get local oid and pass it as double
+ OId localOId;
+ if( !persMDD->getOId( &localOId ) )
+ {
+ RMDBGMIDDLE( 1, RMDebug::module_qlparser, "QtOid", " oid = " << (double)localOId )
+
+ returnValue = new QtAtomicData( (double)localOId, (unsigned short)8 );
+ }
+ else
+ {
+ RMInit::logOut << "Error: QtOId::evaluate() - could not get oid." << std::endl;
+
+ // delete old operand
+ if( operand ) operand->deleteRef();
+
+ parseInfo.setErrorNo(384);
+ throw parseInfo;
+ }
+ }
+ else
+ {
+ RMInit::logOut << "Error: QtOId::evaluate() - operand is not a persistent MDD." << std::endl;
+
+ // delete old operand
+ if( operand ) operand->deleteRef();
+ parseInfo.setErrorNo(383);
+ throw parseInfo;
+ }
+
+ // delete old operand
+ if( operand ) operand->deleteRef();
+ }
+ else
+ RMInit::logOut << "Error: QtOId::evaluate() - operand is not provided." << std::endl;
+
+ return returnValue;
+}
+
+
+
+void
+QtOId::printTree( int tab, std::ostream& s, QtChildType mode )
+{
+ s << SPACE_STR(tab).c_str() << "QtOId Object: " << std::endl;
+
+ QtUnaryOperation::printTree( tab, s, mode );
+}
+
+
+
+void
+QtOId::printAlgebraicExpression( std::ostream& s )
+{
+ s << "oid(" << std::flush;
+
+ if( input )
+ input->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << ")";
+}
+
+
+
+const QtTypeElement&
+QtOId::checkType( QtTypeTuple* typeTuple )
+{
+ RMDBCLASS( "QtOId", "checkType( QtTypeTuple* )", "qlparser", __FILE__, __LINE__ )
+
+ dataStreamType.setDataType( QT_TYPE_UNKNOWN );
+
+ // check operand branches
+ if( input )
+ {
+
+ // get input type
+ const QtTypeElement& inputType = input->checkType( typeTuple );
+
+ if( inputType.getDataType() != QT_MDD )
+ {
+ RMInit::logOut << "Error: QtOId::checkType() - operand is not of type MDD." << std::endl;
+ parseInfo.setErrorNo(383);
+ throw parseInfo;
+ }
+
+ dataStreamType.setDataType( QT_DOUBLE );
+ }
+ else
+ RMInit::logOut << "Error: QtOId::checkType() - operand branch invalid." << std::endl;
+
+ return dataStreamType;
+}
diff --git a/qlparser/qtoid.hh b/qlparser/qtoid.hh
new file mode 100644
index 0000000..03dbbdb
--- /dev/null
+++ b/qlparser/qtoid.hh
@@ -0,0 +1,78 @@
+#ifndef _QTOID_HH__
+#define _QTOID_HH___
+
+#include "qlparser/qtunaryoperation.hh"
+
+
+// forward declarations
+class QtVariable;
+
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+ The class represents an oid node.
+
+*/
+
+class QtOId : public QtUnaryOperation
+{
+ public:
+ /// constructor getting operand
+ QtOId( QtVariable* newInput );
+
+ /// evaluates the node
+ QtData* evaluate( QtDataList* inputList );
+
+ /// prints the tree
+ virtual void printTree( int tab, std::ostream& s = std::cout, QtChildType mode = QT_ALL_NODES );
+
+ /// prints the algebraic expression
+ virtual void printAlgebraicExpression( std::ostream& s = std::cout );
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ /// type checking of the subtree
+ virtual const QtTypeElement& checkType( QtTypeTuple* typeTuple = NULL );
+
+ private:
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+#include "qlparser/qtoid.icc"
+
+#endif
+
diff --git a/qlparser/qtoid.icc b/qlparser/qtoid.icc
new file mode 100644
index 0000000..8efdc80
--- /dev/null
+++ b/qlparser/qtoid.icc
@@ -0,0 +1,35 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+
+inline const QtNode::QtNodeType
+QtOId::getNodeType() const
+{
+ return nodeType;
+}
diff --git a/qlparser/qtoncstream.cc b/qlparser/qtoncstream.cc
new file mode 100644
index 0000000..53e72c2
--- /dev/null
+++ b/qlparser/qtoncstream.cc
@@ -0,0 +1,49 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)qlparser, QtONCStream: $Id: qtoncstream.cc,v 1.10 1997/09/04 14:34:46 ritsch Exp $";
+
+#include "qlparser/qtoncstream.hh"
+
+const QtNode::QtNodeType QtONCStream::nodeType = QtNode::QT_ONC_STREAM;
+
+QtONCStream::QtONCStream()
+ : QtNode()
+{
+}
+
+
+QtONCStream::QtONCStream( QtNode* node )
+ : QtNode( node )
+{
+}
+
diff --git a/qlparser/qtoncstream.hh b/qlparser/qtoncstream.hh
new file mode 100644
index 0000000..d267d7a
--- /dev/null
+++ b/qlparser/qtoncstream.hh
@@ -0,0 +1,102 @@
+#ifndef _QTONCSTREAM_
+#define _QTONCSTREAM_
+
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+#endif
+
+#include "qlparser/qtnode.hh"
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+This class is super class for every class supporting the ONC protocol
+which means that, first, a stream has to be opened with open(),
+then the elements are received through invoking next(),
+and at the end, the stream is closed with the close() method. The
+next() method returns a tupel of QtData or any subclass of QtData.
+
+*/
+
+class QtONCStream : public QtNode
+{
+ public:
+ /// default constructor
+ QtONCStream();
+
+ /// constructor getting a pointer to the parent
+ QtONCStream( QtNode* node );
+
+ //@Man: Operations of the ONC protocol
+ //@{
+ ///
+ virtual void open()=0;
+ ///
+ virtual QtDataList* next()=0;
+ ///
+ virtual void close()=0;
+ ///
+ virtual void reset()=0;
+ //@}
+
+ /// type checking of the subtree
+ virtual const QtTypeTuple& checkType() = 0;
+ /**
+ The method triggers type checking of the node's subtree. If an error occurs, an exception
+ is raised.
+ */
+
+ //@Man: Read/Write methods
+ //@{
+ ///
+ ///
+ inline void setDataStreamType( const QtTypeTuple& type );
+ ///
+ inline const QtTypeTuple& getDataStreamType() const;
+ ///
+ //@}
+
+ protected:
+ /// result type of the node
+ QtTypeTuple dataStreamType;
+
+ private:
+ /// atribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+#endif
+
diff --git a/qlparser/qtoncstream.icc b/qlparser/qtoncstream.icc
new file mode 100644
index 0000000..e1d59df
--- /dev/null
+++ b/qlparser/qtoncstream.icc
@@ -0,0 +1,42 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+inline void
+QtONCStream::setDataStreamType( const QtTypeTuple &type )
+{
+ dataStreamType = type;
+}
+
+
+
+inline const QtTypeTuple&
+QtONCStream::getDataStreamType() const
+{
+ return dataStreamType;
+}
diff --git a/qlparser/qtoperation.cc b/qlparser/qtoperation.cc
new file mode 100644
index 0000000..23bf378
--- /dev/null
+++ b/qlparser/qtoperation.cc
@@ -0,0 +1,126 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)qlparser, QtOperation: $Id: qtoperation.cc,v 1.17 2002/06/05 18:18:17 coman Exp $";
+
+
+#include "qlparser/qtoperation.hh"
+
+#include <iostream>
+
+const QtNode::QtNodeType QtOperation::nodeType = QtNode::QT_OPERATION;
+
+QtOperation::QtOperation()
+ : QtNode()
+{
+}
+
+
+QtOperation::QtOperation( QtNode* node )
+ : QtNode( node )
+{
+}
+
+
+QtOperation*
+QtOperation::getUniqueOrder( const QtNode::QtNodeType )
+{
+ // default method;
+
+ return this;
+}
+
+
+QtData*
+QtOperation::evaluate( QtDataList* /*inputList*/ )
+{
+ RMInit::logOut << "Error: Method evaluate(...) is undefined for a node in the query tree." << std::endl;
+ return NULL;
+}
+
+
+void
+QtOperation::optimizeLoad( QtTrimList* trimList )
+{
+ if( trimList )
+ {
+ std::vector<QtNode::QtTrimElement*>::iterator iter;
+ for( iter=trimList->begin(); iter!=trimList->end(); iter++ )
+ {
+ delete *iter;
+ *iter=NULL;
+ }
+ delete trimList;
+ trimList=NULL;
+ }
+
+ RMInit::logOut << "Error: Method optimizeLoad(...) is undefined for a QtOperation node in the query tree." << std::endl;
+}
+
+
+
+const QtTypeElement&
+QtOperation::checkType( QtTypeTuple* typeTuple )
+{
+ RMDBCLASS( "QtOperation", "checkType( QtTypeElement, QtTypeTuple* )", "qlparser", __FILE__, __LINE__ )
+
+ dataStreamType.setDataType( QT_TYPE_UNKNOWN );
+
+ return dataStreamType;
+}
+
+
+void
+QtOperation::printTree( int tab, std::ostream& s, QtChildType mode )
+{
+ s << SPACE_STR(tab).c_str() << "QtOperation Object: type " << std::flush;
+ dataStreamType.printStatus( s );
+ s << std::endl;
+
+ if( mode != QtNode::QT_DIRECT_CHILDS )
+ {
+ s << SPACE_STR(tab).c_str() << "no operation" << std::endl;
+ }
+
+}
+
+
+
+void
+QtOperation::printAlgebraicExpression( std::ostream& s )
+{
+ s << "op<";
+
+ s << "no ops";
+
+ s << ">";
+}
diff --git a/qlparser/qtoperation.hh b/qlparser/qtoperation.hh
new file mode 100644
index 0000000..eab3d7e
--- /dev/null
+++ b/qlparser/qtoperation.hh
@@ -0,0 +1,120 @@
+#ifndef _QTOPERATION_
+#define _QTOPERATION_
+
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+#endif
+
+#include "qlparser/qtnode.hh"
+
+class QtData; // forward declaration of a subclass of QtOperation
+
+#include <iostream>
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+QtOperation defines a method {\tt evaluate()} getting a tupel of {\tt QtData} and returning
+a {\tt QtData} element. Every subclass has to redefine this method to compute its specific
+operation. Therefore, it takes its inputs which are also of type {\tt QtOperation}, and
+invokes the {\tt evaluate()} method again. The results are used as operands and the
+computed value is returned.
+
+*/
+
+class QtOperation : public QtNode
+{
+ public:
+ /// default constructor
+ QtOperation();
+
+ /// constructor getting a pointer to the parent
+ QtOperation( QtNode* parent );
+
+ ///for associative law
+ virtual QtOperation* getUniqueOrder( const QtNode::QtNodeType ID );
+
+ /**
+ The method gives back a node that has the same QtNodeType and has the lowest
+ Spelling of all nodes in the subtree with the same QtNodeType.
+ */
+
+ /// method for evaluating the node
+ virtual QtData* evaluate( QtDataList* inputList );
+
+ /**
+ The method takes the {\tt inputList} to compute the result of the node which is returned in the end.
+ The semantics is that elements of the {\tt inputList} are not allowed to be used as a result because
+ the {\tt inputList} is freed by the caller. If this is needed, they have to be copied.
+ */
+
+ /// optimizing load access
+ virtual void optimizeLoad( QtTrimList* trimList );
+
+ /// type checking of the subtree
+ virtual const QtTypeElement& checkType( QtTypeTuple* typeTuple = NULL );
+ /**
+ The method triggers type checking of the node's subtree. If an error occurs, an exception
+ is raised.
+ */
+
+ //@Man: Read/Write methods
+ //@{
+ ///
+ ///
+ inline void setDataStreamType( const QtTypeElement& type );
+ ///
+ inline const QtTypeElement& getDataStreamType() const;
+ ///
+ //@}
+
+ void printTree( int tab, std::ostream& s, QtChildType mode=QT_ALL_NODES );
+
+ void printAlgebraicExpression( std::ostream& s );
+
+ protected:
+ /// result type of the node
+ QtTypeElement dataStreamType;
+
+ private:
+ /// atribute for indetification of nodes
+ static const QtNodeType nodeType;
+};
+
+#include "qlparser/qtoperation.icc"
+
+#endif
+
+
diff --git a/qlparser/qtoperation.icc b/qlparser/qtoperation.icc
new file mode 100644
index 0000000..c5703c1
--- /dev/null
+++ b/qlparser/qtoperation.icc
@@ -0,0 +1,43 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+
+inline void
+QtOperation::setDataStreamType( const QtTypeElement &type )
+{
+ dataStreamType = type;
+}
+
+
+
+inline const QtTypeElement&
+QtOperation::getDataStreamType() const
+{
+ return dataStreamType;
+}
diff --git a/qlparser/qtoperationiterator.cc b/qlparser/qtoperationiterator.cc
new file mode 100644
index 0000000..6a1008a
--- /dev/null
+++ b/qlparser/qtoperationiterator.cc
@@ -0,0 +1,303 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)qlparser, QtOperationIterator: $Id: qtoperationiterator.cc,v 1.24 2001/08/07 12:36:49 barbat Exp $";
+
+
+#include "raslib/rmdebug.hh"
+
+#include "qlparser/qtoperationiterator.hh"
+#include "qlparser/qtmdd.hh"
+#include "qlparser/qtdata.hh"
+
+#include <iostream>
+#include <string>
+#include <vector>
+using namespace std;
+
+const QtNode::QtNodeType QtOperationIterator::nodeType = QT_OPERATION_ITERATOR;
+
+
+QtOperationIterator::QtOperationIterator()
+ : QtIterator()
+{
+ operationTreeList = new QtOperationList();
+}
+
+
+QtOperationIterator::QtOperationIterator( QtNode* node )
+ : QtIterator( node )
+{
+ operationTreeList = new QtOperationList();
+}
+
+
+QtOperationIterator::~QtOperationIterator()
+{
+ // release( operationTreeList->begin(), operationTreeList->end() );
+ QtOperationList::iterator iter;
+ for( iter = operationTreeList->begin(); iter!=operationTreeList->end(); iter++ )
+ {
+ delete *iter;
+ *iter=NULL;
+ }
+ delete operationTreeList;
+ operationTreeList=NULL;
+}
+
+
+QtNode::QtNodeList*
+QtOperationIterator::getChilds( QtChildType flag )
+{
+ RMDBCLASS( "QtOperationIterator", "getChilds( QtChildType )", "qlparser", __FILE__, __LINE__ )
+
+ QtNodeList* resultList=NULL;
+ QtNodeList* subList=NULL;
+
+ QtOperationList::iterator iter;
+
+ resultList = QtIterator::getChilds( flag );
+
+RMDBGIF(3, RMDebug::module_qlparser, "QtOperationIterator", \
+ RMInit::dbgOut << "1. childs from stream subtree " << endl; \
+ list<QtNode*>::iterator debugIter; \
+ for( debugIter=resultList->begin(); debugIter!=resultList->end(); debugIter++ ) \
+ (*debugIter)->printTree( 2, RMInit::dbgOut, QtNode::QT_DIRECT_CHILDS ); )
+
+ for( iter=operationTreeList->begin(); iter!=operationTreeList->end(); iter++ )
+ {
+ if( flag == QT_LEAF_NODES || flag == QT_ALL_NODES )
+ {
+ subList = (*iter)->getChilds( flag ) ;
+
+RMDBGIF(3, RMDebug::module_qlparser, "QtOperationIterator", \
+ RMInit::dbgOut << "2. childs from operation subtree (without direct childs) " << endl; \
+ list<QtNode*>::iterator debugIter; \
+ for( debugIter=subList->begin(); debugIter!=subList->end(); debugIter++ ) \
+ (*debugIter)->printTree( 2, RMInit::dbgOut, QtNode::QT_DIRECT_CHILDS ); )
+
+ // remove all elements in subList and insert them at the beginning of resultList
+ resultList->splice( resultList->begin(), *subList );
+
+RMDBGIF(3, RMDebug::module_qlparser, "QtOperationIterator", \
+ RMInit::dbgOut << "3. merge of the lists " << endl; \
+ list<QtNode*>::iterator debugIter; \
+ for( debugIter=resultList->begin(); debugIter!=resultList->end(); debugIter++ ) \
+ (*debugIter)->printTree( 2, RMInit::dbgOut, QtNode::QT_DIRECT_CHILDS ); )
+
+RMDBGIF(3, RMDebug::module_qlparser, "QtOperationIterator", \
+ RMInit::dbgOut << "4. old list (must be empty)" << endl; \
+ list<QtNode*>::iterator debugIter; \
+ for( debugIter=subList->begin(); debugIter!=subList->end(); debugIter++ ) \
+ (*debugIter)->printTree( 2, RMInit::dbgOut, QtNode::QT_DIRECT_CHILDS ); )
+
+ // delete temporary subList
+ delete subList;
+ subList=NULL;
+ };
+
+ // add nodes of next level
+ if( flag == QT_DIRECT_CHILDS || flag == QT_ALL_NODES )
+ resultList->push_back( *iter );
+
+RMDBGIF(3, RMDebug::module_qlparser, "QtOperationIterator", \
+ RMInit::dbgOut << "4. current child list including direct childs " << endl; \
+ list<QtNode*>::iterator debugIter; \
+ for( debugIter=resultList->begin(); debugIter!=resultList->end(); debugIter++ ) \
+ (*debugIter)->printTree( 2, RMInit::dbgOut, QtNode::QT_DIRECT_CHILDS ); )
+
+ };
+
+ return resultList;
+}
+
+
+void
+QtOperationIterator::printTree( int tab, ostream& s, QtChildType mode )
+{
+ QtOperationList::iterator iter;
+
+ s << SPACE_STR(tab).c_str() << "QtOperationIterator Object: type " << flush;
+ dataStreamType.printStatus( s );
+ s << endl;
+
+ if( mode != QtNode::QT_DIRECT_CHILDS )
+ {
+ if( operationTreeList->empty() )
+ s << SPACE_STR(tab).c_str() << "no operation" << endl;
+ else
+ for( iter=operationTreeList->begin(); iter!=operationTreeList->end(); iter++ )
+ {
+ s << SPACE_STR(tab).c_str() << "operation: " << endl;
+ (*iter)->printTree( tab + 2, s, mode );
+ }
+ }
+
+ QtIterator::printTree( tab, s, mode );
+}
+
+
+
+void
+QtOperationIterator::printAlgebraicExpression( ostream& s )
+{
+ s << "op<";
+
+ if( operationTreeList )
+ {
+ for( int i=0; i<operationTreeList->size(); i++ )
+ {
+ (*operationTreeList)[i]->printAlgebraicExpression( s );
+
+ if( i < operationTreeList->size()-1 )
+ s << ", ";
+ }
+ }
+ else
+ s << "no ops";
+
+ s << ">";
+
+ QtIterator::printAlgebraicExpression( s );
+}
+
+
+
+QtNode::QtDataList*
+QtOperationIterator::next()
+{
+ RMDBCLASS( "QtOperationIterator", "next()", "qlparser", __FILE__, __LINE__ )
+
+ QtDataList* returnValue = NULL;
+
+ if( inputs )
+ {
+ QtDataList* nextTupel=NULL;
+ QtDataList* resultList=NULL;
+
+ // create a composed tupel of type QtDataList of the next elements of the input streams
+ // right now, just take the QtDataList vector of the first input stream
+ nextTupel = (*inputs)[0]->next();
+
+ if( nextTupel )
+ {
+ QtOperationList::iterator iter;
+ vector<QtData*>::iterator dataIter;
+
+ resultList = new QtDataList( operationTreeList->size() );
+
+ int pos=0;
+
+ for( iter=operationTreeList->begin(); iter!=operationTreeList->end(); iter++)
+ {
+ // send them through the operand tree
+
+ try
+ {
+ if( *iter )
+ (*resultList)[pos] = (*iter)->evaluate( nextTupel );
+ }
+ catch(...)
+ {
+ // Delete the tupel vector received by next(). Just tupel elements which are not
+ // further referenced are deleted.
+ for( dataIter=nextTupel->begin(); dataIter!=nextTupel->end(); dataIter++ )
+ if( (*dataIter) ) (*dataIter)->deleteRef();
+
+ for (QtDataList::iterator deleteIter = resultList->begin(); deleteIter != resultList->end(); deleteIter++)
+ {
+ delete *deleteIter;
+ *deleteIter = NULL;
+ }
+ delete resultList;
+ resultList = NULL;
+ delete nextTupel;
+ nextTupel = NULL;
+
+ throw;
+ }
+
+ pos++;
+ }
+
+ // Delete the tupel vector received by next(). Just tupel elements which are not
+ // further referenced are deleted.
+ for( dataIter=nextTupel->begin(); dataIter!=nextTupel->end(); dataIter++ )
+ if( (*dataIter) ) (*dataIter)->deleteRef();
+
+ // ... and now the vector itself
+ delete nextTupel;
+ nextTupel=NULL;
+
+ returnValue = resultList;
+ }
+ }
+ return returnValue;
+}
+
+/*
+void
+QtOperationIterator::preOptimize()
+{
+ QtOperationList::iterator iter;
+
+ for( iter=operationTreeList->begin(); iter!=operationTreeList->end(); iter++ )
+ (*iter)->optimizeLoad( new QtNode::QtTrimList );
+
+ // pass it to the input streams
+ QtIterator::preOptimize();
+};
+*/
+
+
+const QtTypeTuple&
+QtOperationIterator::checkType()
+{
+ RMDBCLASS( "QtOperationIterator", "checkType()", "qlparser", __FILE__, __LINE__ )
+
+ dataStreamType = QtTypeTuple();
+
+ QtTypeTuple inputTypeTuple;
+
+ getInputTypeTuple( inputTypeTuple );
+
+ // type check of operation trees
+ QtOperationList::iterator iter;
+
+ for( iter=operationTreeList->begin(); iter!=operationTreeList->end(); iter++ )
+ if( *iter )
+ dataStreamType.concat( (*iter)->checkType( &inputTypeTuple ) );
+
+ return dataStreamType;
+}
+
+
diff --git a/qlparser/qtoperationiterator.hh b/qlparser/qtoperationiterator.hh
new file mode 100644
index 0000000..78ab11e
--- /dev/null
+++ b/qlparser/qtoperationiterator.hh
@@ -0,0 +1,120 @@
+#ifndef _QTOPERATIONITERATOR_
+#define _QTOPERATIONITERATOR_
+
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+#endif
+
+#include "qlparser/qtiterator.hh"
+#include "qlparser/qtoperation.hh"
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+A QtOperationIterator takes the next element of its input streams an creates
+a tupel out of them. The operation specified through an operation tree of type
+QtOperation is evaluated for this tupel and the result is passed to its output
+stream. The class stands for the SELECT part of a query. The operations in the
+SELECT clause are expressed through an operation tree which is attached to this
+class.
+
+*/
+
+class QtOperationIterator : public QtIterator
+{
+ public:
+ /// default constructor
+ QtOperationIterator();
+
+ /// constructor getting a pointer to the parent
+ QtOperationIterator( QtNode* node );
+
+ /// virtual destructor
+ virtual ~QtOperationIterator();
+
+ /// return childs of the node
+ virtual QtNodeList* getChilds( QtChildType flag );
+
+ /// method for query rewrite
+ inline virtual void setInput( QtOperation* child, QtOperation* input);
+
+ /// optimizing load access
+ //virtual void preOptimize();
+ /**
+ Trigger load optimization in the operation tree and pass the optimization step to
+ the input streams.
+ */
+
+ /// prints the tree
+ virtual void printTree( int tab, std::ostream& s = std::cout, QtChildType mode = QT_ALL_NODES );
+
+ /// prints the algebraic expression
+ virtual void printAlgebraicExpression( std::ostream& s = std::cout );
+
+ //@Man: Read/Write methods:
+ //@{
+ ///
+ //inline virtual void setParents();
+ ///
+ inline void setOperationTree( QtOperation* operation );
+ ///
+ inline QtNode::QtOperationList* getOperationTreeList();
+ //@}
+
+ //@Man: Operations of the ONC protocol:
+ //@{
+ ///
+ QtDataList* next();
+ //@}
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ /// type checking
+ virtual const QtTypeTuple& checkType();
+
+ private:
+ /// operation trees
+ QtOperationList* operationTreeList;
+
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+#include "qlparser/qtoperationiterator.icc"
+
+#endif
+
diff --git a/qlparser/qtoperationiterator.icc b/qlparser/qtoperationiterator.icc
new file mode 100644
index 0000000..4abe3fc
--- /dev/null
+++ b/qlparser/qtoperationiterator.icc
@@ -0,0 +1,74 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+inline void
+QtOperationIterator::setOperationTree( QtOperation* operation )
+{
+ if( operation )
+ {
+ operationTreeList->push_back( operation );
+ operation->setParent( this );
+ };
+};
+
+
+
+inline QtNode::QtOperationList*
+QtOperationIterator::getOperationTreeList()
+{
+ return( operationTreeList );
+};
+
+
+
+inline void
+QtOperationIterator::setInput( QtOperation* inputOld, QtOperation* inputNew )
+{
+ QtOperationList::iterator iter;
+
+ for( iter=operationTreeList->begin(); iter!=operationTreeList->end(); iter++)
+ {
+ if( *iter == inputOld )
+ {
+ (*iter) = inputNew;
+
+ if( inputNew )
+ inputNew->setParent( this );
+ };
+ };
+};
+
+
+
+inline const QtNode::QtNodeType
+QtOperationIterator::getNodeType() const
+{
+ return nodeType;
+}
+
diff --git a/qlparser/qtpointdata.cc b/qlparser/qtpointdata.cc
new file mode 100644
index 0000000..acc1a3d
--- /dev/null
+++ b/qlparser/qtpointdata.cc
@@ -0,0 +1,114 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)qlparser, QtPointData: $Id: qtpointdata.cc,v 1.7 2005/09/03 20:17:55 rasdev Exp $";
+
+using namespace std;
+
+using namespace std;
+
+#include "qlparser/qtpointdata.hh"
+#include <cstring>
+// deprecated, not any longer available -- PB 2005-jan-14
+// #include <iostream>
+
+
+QtPointData::QtPointData( const r_Point& point )
+ : pointData(point), QtData()
+{
+}
+
+
+QtPointData::~QtPointData()
+{
+}
+
+
+QtDataType
+QtPointData::getDataType() const
+{
+ return QT_POINT;
+}
+
+
+bool
+QtPointData::equal( const QtData* obj ) const
+{
+ int returnValue = false; // not equal by initialization
+
+ if( obj->getDataType() == QT_POINT )
+ {
+ QtPointData* pt = (QtPointData*)obj;
+
+ // check domains
+ returnValue = (pointData == pt->getPointData());
+ }
+
+ return returnValue;
+}
+
+
+std::string
+QtPointData::getSpelling() const
+{
+ std::string result;
+
+ // buffer
+ int bufferLen = pointData.dimension() * 50; // on the save side for one integers per dimension plus colon and brackets
+ char* buffer = new char[ bufferLen ];
+ // replaced deprecated ostrstream -- PB 2005-jan-14
+ // ostrstream bufferStream( buffer, bufferLen );
+ ostringstream bufferStream( buffer );
+
+ bufferStream << pointData << std::ends;
+
+ result.append( std::string( buffer ) );
+
+ delete[] buffer;
+ buffer=NULL;
+ return result;
+}
+
+
+char* QtPointData::getTypeStructure() const
+{
+ return strdup("point");
+}
+
+
+void
+QtPointData::printStatus( std::ostream& stream ) const
+{
+ stream << "point, value: " << std::flush;
+ stream << pointData << std::flush;
+ QtData::printStatus( stream );
+}
diff --git a/qlparser/qtpointdata.hh b/qlparser/qtpointdata.hh
new file mode 100644
index 0000000..11695f2
--- /dev/null
+++ b/qlparser/qtpointdata.hh
@@ -0,0 +1,101 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#ifndef _QTPOINTDATA_
+#define _QTPOINTDATA_
+
+#include "qlparser/qtdata.hh"
+
+#include "raslib/point.hh"
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+// removed deprecated ostrsteam -- PB 2005-jan-14
+// #include <strstream.h>
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+ The class encapsulates a point of type \Ref{r_Point}.
+*/
+
+class QtPointData : public QtData
+{
+ public:
+ /// constructor getting a point
+ QtPointData( const r_Point& point );
+
+ /// virtual destructor
+ virtual ~QtPointData();
+
+ //@Man: Read/Write methods:
+ //@{
+ ///
+
+ ///
+ inline const r_Point& getPointData() const;
+ ///
+ inline void setPointData( const r_Point& point );
+
+ /// returns a null-terminated string describing the type structure
+ virtual char* getTypeStructure() const;
+ /**
+ The string pointer has to be free using free() by the caller.
+ */
+
+ ///
+ //@}
+
+ /// returns {\tt QT_POINT}
+ virtual QtDataType getDataType() const;
+
+ /// compares data content
+ virtual bool equal( const QtData* obj ) const;
+
+ /// returns content dependent string representation
+ virtual std::string getSpelling() const;
+
+ /// print status of the object to the specified stream
+ virtual void printStatus( std::ostream& stream = std::cout ) const;
+
+ private:
+ /// attribute storing the minterval
+ r_Point pointData;
+};
+
+#include "qlparser/qtpointdata.icc"
+
+#endif
+
+
+
+
+
diff --git a/qlparser/qtpointdata.icc b/qlparser/qtpointdata.icc
new file mode 100644
index 0000000..d47ce57
--- /dev/null
+++ b/qlparser/qtpointdata.icc
@@ -0,0 +1,45 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+
+inline const r_Point&
+QtPointData::getPointData() const
+{
+ return pointData;
+}
+
+
+inline void
+QtPointData::setPointData( const r_Point& point )
+{
+ pointData = point;
+}
+
+
+
diff --git a/qlparser/qtpointop.cc b/qlparser/qtpointop.cc
new file mode 100644
index 0000000..2f9f89b
--- /dev/null
+++ b/qlparser/qtpointop.cc
@@ -0,0 +1,214 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)qlparser, QtPointOp: $Id: qtpointop.cc,v 1.7 2002/06/05 18:18:17 coman Exp $";
+
+#include "raslib/rmdebug.hh"
+
+#include "qlparser/qtpointop.hh"
+#include "qlparser/qtdata.hh"
+#include "qlparser/qtpointdata.hh"
+#include "qlparser/qtatomicdata.hh"
+
+#include "catalogmgr/ops.hh"
+#include "relcatalogif/type.hh"
+
+#include <iostream>
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+using namespace std;
+#endif
+
+
+const QtNode::QtNodeType QtPointOp::nodeType = QT_POINTOP;
+
+QtPointOp::QtPointOp( QtOperationList* opList )
+ : QtNaryOperation( opList )
+{
+}
+
+
+
+QtData*
+QtPointOp::evaluate( QtDataList* inputList )
+{
+ RMDBCLASS( "QtPointOp", "evaluate( QtDataList* )", "qlparser", __FILE__, __LINE__ )
+
+ QtData* returnValue = NULL;
+ QtDataList* operandList = NULL;
+
+ if( getOperands( inputList, operandList ) )
+ {
+ vector<QtData*>::iterator dataIter;
+ bool goOn=true;
+
+ if( operandList )
+ {
+ // first check operand types
+ for( dataIter=operandList->begin(); dataIter!=operandList->end() && goOn; dataIter++ )
+ if (!( (*dataIter)->getDataType() == QT_SHORT || (*dataIter)->getDataType() == QT_USHORT ||
+ (*dataIter)->getDataType() == QT_LONG || (*dataIter)->getDataType() == QT_ULONG ||
+ (*dataIter)->getDataType() == QT_OCTET || (*dataIter)->getDataType() == QT_CHAR ))
+ {
+ goOn=false;
+ break;
+ }
+
+ if( !goOn )
+ {
+ RMInit::logOut << "Error: QtPointOp::evaluate() - operands of point expression must be of type integer." << std::endl;
+
+ parseInfo.setErrorNo(410);
+
+ // delete the old operands
+ if( operandList )
+ {
+ for( dataIter=operandList->begin(); dataIter!=operandList->end(); dataIter++ )
+ if( (*dataIter) ) (*dataIter)->deleteRef();
+
+ delete operandList;
+ operandList=NULL;
+ }
+
+ throw parseInfo;
+ }
+
+ //
+ // create a QtPointData object and fill it
+ //
+ r_Point pt( operandList->size() );
+
+ for( dataIter=operandList->begin(); dataIter!=operandList->end(); dataIter++ )
+ if( (*dataIter)->getDataType() == QT_SHORT ||
+ (*dataIter)->getDataType() == QT_LONG ||
+ (*dataIter)->getDataType() == QT_OCTET )
+ pt << ((QtAtomicData*)(*dataIter))->getSignedValue();
+ else
+ pt << ((QtAtomicData*)(*dataIter))->getUnsignedValue();
+
+ returnValue = new QtPointData( pt );
+
+ // delete the old operands
+ if( operandList )
+ {
+ for( dataIter=operandList->begin(); dataIter!=operandList->end(); dataIter++ )
+ if( (*dataIter) ) (*dataIter)->deleteRef();
+
+ delete operandList;
+ operandList=NULL;
+ }
+ }
+ }
+
+ return returnValue;
+}
+
+
+
+void
+QtPointOp::printTree( int tab, std::ostream& s, QtChildType mode )
+{
+ s << SPACE_STR(tab).c_str() << "QtPointOp Object " << getNodeType() << std::endl;
+
+ QtNaryOperation::printTree( tab, s, mode );
+}
+
+
+
+void
+QtPointOp::printAlgebraicExpression( std::ostream& s )
+{
+ s << "[";
+
+ QtNaryOperation::printAlgebraicExpression( s );
+
+ s << "]";
+}
+
+
+
+const QtTypeElement&
+QtPointOp::checkType( QtTypeTuple* typeTuple )
+{
+ RMDBCLASS( "QtPointOp", "checkType( QtTypeTuple* )", "qlparser", __FILE__, __LINE__ )
+
+ dataStreamType.setDataType( QT_TYPE_UNKNOWN );
+
+ QtOperationList::iterator iter;
+ bool opTypesValid = true;
+
+ for( iter=operationList->begin(); iter!=operationList->end() && opTypesValid; iter++ )
+ {
+ const QtTypeElement& type = (*iter)->checkType( typeTuple );
+
+ // valid types: integers
+ if (!( type.getDataType() == QT_SHORT ||
+ type.getDataType() == QT_LONG ||
+ type.getDataType() == QT_OCTET ||
+ type.getDataType() == QT_USHORT ||
+ type.getDataType() == QT_ULONG ||
+ type.getDataType() == QT_CHAR))
+ {
+ opTypesValid = false;
+ break;
+ }
+ }
+
+ if( !opTypesValid )
+ {
+ RMInit::logOut << "Error: QtPointOp::checkType() - operand of point expression must be of type integer." << std::endl;
+ parseInfo.setErrorNo(410);
+ throw parseInfo;
+ }
+
+ dataStreamType.setDataType( QT_POINT );
+
+ return dataStreamType;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/qlparser/qtpointop.hh b/qlparser/qtpointop.hh
new file mode 100644
index 0000000..08f671a
--- /dev/null
+++ b/qlparser/qtpointop.hh
@@ -0,0 +1,81 @@
+#ifndef _QTPOINTOP_
+#define _QTPOINTOP_
+
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+#endif
+
+#include "qlparser/qtnaryoperation.hh"
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+ The class represents the root of a point expression.
+
+*/
+
+class QtPointOp : public QtNaryOperation
+{
+ public:
+ /// constructor getting the two operands
+ QtPointOp( QtOperationList* opList );
+
+ /// method for evaluating the node
+ QtData* evaluate( QtDataList* inputList );
+ /**
+ */
+
+ /// prints the tree
+ virtual void printTree( int tab, std::ostream& s = std::cout, QtChildType mode = QT_ALL_NODES );
+
+ /// prints the algebraic expression
+ virtual void printAlgebraicExpression( std::ostream& s = std::cout );
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ /// type checking of the subtree
+ virtual const QtTypeElement& checkType( QtTypeTuple* typeTuple = NULL );
+
+ private:
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+
+#include "qlparser/qtpointop.icc"
+
+#endif
+
diff --git a/qlparser/qtpointop.icc b/qlparser/qtpointop.icc
new file mode 100644
index 0000000..c9b8bf1
--- /dev/null
+++ b/qlparser/qtpointop.icc
@@ -0,0 +1,34 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+inline const QtNode::QtNodeType
+QtPointOp::getNodeType() const
+{
+ return nodeType;
+}
diff --git a/qlparser/qtscalardata.cc b/qlparser/qtscalardata.cc
new file mode 100644
index 0000000..670204d
--- /dev/null
+++ b/qlparser/qtscalardata.cc
@@ -0,0 +1,204 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)qlparser, QtScalarData: $Header: /home/rasdev/CVS-repository/rasdaman/qlparser/qtscalardata.cc,v 1.17 2005/07/06 22:48:34 rasdev Exp $";
+
+#include "qlparser/qtscalardata.hh"
+
+#include "relcatalogif/basetype.hh"
+
+#include "raslib/rmdebug.hh"
+
+#include <iostream>
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+#include <cstring>
+#include <cstdlib>
+using namespace std;
+#endif
+
+#include <iostream>
+
+// deprecated, not available any longer -- PB 2005-jan-14
+// #include <strstream.h>
+
+QtScalarData::QtScalarData()
+ : valueBuffer(NULL),
+ valueType(NULL)
+{
+}
+
+
+
+QtScalarData::QtScalarData( const QtScalarData& obj )
+ : QtData( obj )
+{
+ setLifetime( obj.getLifetime() );
+
+ // Pointer received from TypeFactory just can be copied.
+ valueType = obj.valueType;
+
+ if( valueType && obj.valueBuffer )
+ {
+ valueBuffer = new char[ valueType->getSize() ];
+ memcpy( (void*)valueBuffer, (void*)obj.valueBuffer, valueType->getSize() );
+ }
+ else
+ valueBuffer = NULL;
+}
+
+
+
+QtScalarData::~QtScalarData()
+{
+ // valueType is not deleted because it is maintained by the typeFactory
+
+ if( valueBuffer )
+ {
+ delete[] valueBuffer;
+ valueBuffer=NULL;
+ }
+}
+
+
+
+QtDataType
+QtScalarData::getDataType() const
+{
+ QtDataType returnValue = QT_BOOL;
+
+ if( valueType )
+ switch( valueType->getType() )
+ {
+ case BOOLTYPE: returnValue = QT_BOOL; break;
+ case CHAR: returnValue = QT_CHAR; break;
+ case OCTET: returnValue = QT_OCTET; break;
+ case USHORT: returnValue = QT_USHORT; break;
+ case SHORT: returnValue = QT_SHORT; break;
+ case ULONG: returnValue = QT_ULONG; break;
+ case LONG: returnValue = QT_LONG; break;
+ case FLOAT: returnValue = QT_FLOAT; break;
+ case DOUBLE: returnValue = QT_DOUBLE; break;
+ case STRUCT: returnValue = QT_COMPLEX; break;
+ default:
+ RMDBGONCE(0, RMDebug::module_qlparser, "r_QtScalarData", "getDataType() bad type " << valueType->getType());
+ break;
+ }
+
+ return returnValue;
+}
+
+
+
+bool
+QtScalarData::isScalarData() const
+{
+ return true;
+}
+
+
+bool
+QtScalarData::equal( const QtData* obj ) const
+{
+ int returnValue = false; // not equal by initialization
+
+ if( obj->isScalarData() )
+ {
+ QtScalarData* scalarObj = (QtScalarData*)obj;
+
+ if( getDataType() == scalarObj->getDataType() ) // Attention: this is not correct for structs
+ // compare value buffers
+ returnValue = (memcmp( (void*)valueBuffer, (void*)scalarObj->valueBuffer, valueType->getSize() ) == 0);
+
+ }
+
+ return returnValue;
+}
+
+
+
+string
+QtScalarData::getSpelling() const
+{
+ string result;
+
+ // buffer for hex representation of chars
+ int bufferLen = valueType->getSize() * 2 + 1 + 2; // added final "+2" to remove memleak -- PB 2006-aug-17
+ char* buffer = new char[ bufferLen ];
+ // replaced deprecated ostrstream -- PB 2005-jan-14
+ // ostrstream bufferStream( buffer, bufferLen );
+ ostringstream bufferStream( buffer );
+
+ for( int i=0; i<valueType->getSize(); i++ )
+ bufferStream << hex << valueBuffer[i];
+
+ bufferStream << ends;
+
+ result.append( string( buffer ) );
+
+ delete[] buffer;
+ buffer = NULL;
+ return result;
+}
+
+
+char* QtScalarData::getTypeStructure() const
+{
+ if( valueType )
+ return valueType->getTypeStructure();
+ else
+ return NULL;
+}
+
+
+void
+QtScalarData::printStatus( ostream& stream ) const
+{
+ if( valueType )
+ {
+ char* typeStructure = valueType->getTypeStructure();
+
+ stream << "type: " << flush << valueType->getTypeName()
+ << ", structure: " << flush << typeStructure
+ << ", value: " << flush;
+
+ valueType->printCell( stream, valueBuffer );
+
+ free( typeStructure );
+ typeStructure=NULL;
+ QtData::printStatus( stream );
+ }
+ else
+ stream << "<no type>";
+}
diff --git a/qlparser/qtscalardata.hh b/qlparser/qtscalardata.hh
new file mode 100644
index 0000000..9ef33cb
--- /dev/null
+++ b/qlparser/qtscalardata.hh
@@ -0,0 +1,137 @@
+#ifndef _QTSCALARDATA_HH_
+#define _QTSCALARDATA_HH_
+
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+#endif
+
+#include "qlparser/qtdata.hh"
+#include "catalogmgr/typefactory.hh"
+
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+ The abstract class represents a scalar data handled by the
+ query tree. It can either be atomic (\Ref{QtAtomicData})
+ or complex (\Ref{QtComplexData}).
+
+*/
+
+class QtScalarData : public QtData
+{
+ public:
+ /// default constructor
+ QtScalarData();
+
+ /// copy constructor
+ QtScalarData( const QtScalarData& obj );
+
+ /// virtual destructor
+ virtual ~QtScalarData();
+
+ //@Man: Read/Write methods:
+ //@{
+ ///
+
+ /// returns data type
+ virtual QtDataType getDataType() const;
+
+ /// returns true meaning that the data is of type scalar
+ virtual bool isScalarData() const;
+
+ /// returns a pointer to the value type
+ inline const BaseType* getValueType() const;
+
+ /// sets the value type
+ inline void setValueType( const BaseType* newType );
+
+ /// returns a pointer to the internal character representation
+ inline const char* getValueBuffer() const;
+
+ /// sets the value buffer
+ inline void setValueBuffer( char* buffer );
+
+ /// returns a null-terminated string describing the type structure
+ virtual char* getTypeStructure() const;
+ /**
+ The string pointer has to be free using free() by the caller.
+ */
+
+ ///
+ //@}
+
+ /// compares data content
+ virtual bool equal( const QtData* obj ) const;
+
+ /// returns content dependent string representation
+ virtual std::string getSpelling() const;
+
+ /// print status of the object to the specified stream
+ virtual void printStatus( std::ostream& stream = std::cout ) const;
+
+ protected:
+ /// pointer to the value type
+ const BaseType* valueType;
+
+ /// pointer to the value buffer
+ char* valueBuffer;
+};
+
+#include "qlparser/qtscalardata.icc"
+
+#endif
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/qlparser/qtscalardata.icc b/qlparser/qtscalardata.icc
new file mode 100644
index 0000000..873f0b7
--- /dev/null
+++ b/qlparser/qtscalardata.icc
@@ -0,0 +1,58 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+inline const BaseType*
+QtScalarData::getValueType() const
+{
+ return valueType;
+}
+
+
+
+inline void
+QtScalarData::setValueType( const BaseType* newType )
+{
+ valueType = newType;
+}
+
+
+
+inline const char*
+QtScalarData::getValueBuffer() const
+{
+ return valueBuffer;
+}
+
+
+
+inline void
+QtScalarData::setValueBuffer( char* buffer )
+{
+ valueBuffer = buffer;
+}
diff --git a/qlparser/qtselectioniterator.cc b/qlparser/qtselectioniterator.cc
new file mode 100644
index 0000000..f6d2529
--- /dev/null
+++ b/qlparser/qtselectioniterator.cc
@@ -0,0 +1,281 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)qlparser, QtSelectionIterator: $Id: qtselectioniterator.cc,v 1.24 2001/08/07 12:00:12 barbat Exp $";
+
+#include "raslib/rmdebug.hh"
+
+#include "qlparser/qtselectioniterator.hh"
+#include "qlparser/qtatomicdata.hh"
+
+#include "relcatalogif/type.hh"
+
+#include <iostream>
+#include <string>
+#include <vector>
+using namespace std;
+
+const QtNode::QtNodeType QtSelectionIterator::nodeType = QtNode::QT_SELECTION_ITERATOR;
+
+
+QtSelectionIterator::QtSelectionIterator()
+ : QtIterator(),
+ conditionTree(NULL)
+{
+}
+
+
+QtSelectionIterator::QtSelectionIterator( QtNode* node )
+ : QtIterator( node ),
+ conditionTree(NULL)
+{
+}
+
+
+QtSelectionIterator::~QtSelectionIterator()
+{
+ if( conditionTree )
+ {
+ delete conditionTree;
+ conditionTree=NULL;
+ }
+}
+
+
+QtNode::QtNodeList*
+QtSelectionIterator::getChilds( QtChildType flag )
+{
+ QtNodeList* resultList=NULL;
+ QtNodeList* subList=NULL;
+
+ RMDBGENTER( 1, RMDebug::module_qlparser, "QtSelectionIterator", " QtSelectionIterator::getChilds() ")
+
+ resultList = QtIterator::getChilds( flag );
+
+ RMDBGIF( 4, RMDebug::module_qlparser, "QtSelectionIterator", \
+ RMInit::dbgOut << "1. childs from stream subtree " << endl; \
+ list<QtNode*>::iterator debugIter; \
+ for( debugIter=resultList->begin(); debugIter!=resultList->end(); debugIter++ ) \
+ (*debugIter)->printTree( 2, RMInit::dbgOut, QtNode::QT_DIRECT_CHILDS ); \
+ )
+
+ if( conditionTree )
+ {
+ if( flag == QT_LEAF_NODES || flag == QT_ALL_NODES )
+ {
+ subList = conditionTree->getChilds( flag );
+
+ RMDBGIF( 4, RMDebug::module_qlparser, "QtSelectionIterator", \
+ RMInit::dbgOut << "2. childs from operation subtree (without direct childs) " << endl; \
+ list<QtNode*>::iterator debugIter; \
+ for( debugIter=subList->begin(); debugIter!=subList->end(); debugIter++ ) \
+ (*debugIter)->printTree( 2, RMInit::dbgOut, QtNode::QT_DIRECT_CHILDS ); \
+ )
+
+ // remove all elements in subList and insert them at the beginning in resultList
+ resultList->splice( resultList->begin(), *subList );
+
+ RMDBGIF( 4, RMDebug::module_qlparser, "QtSelectionIterator", \
+ RMInit::dbgOut << "3. merge of the lists " << endl; \
+ list<QtNode*>::iterator debugIter; \
+ for( debugIter=resultList->begin(); debugIter!=resultList->end(); debugIter++ ) \
+ (*debugIter)->printTree( 2, RMInit::dbgOut, QtNode::QT_DIRECT_CHILDS ); \
+ )
+
+
+ RMDBGIF( 4, RMDebug::module_qlparser, "QtSelectionIterator", \
+ RMInit::dbgOut << "4. old list (must be empty)" << endl; \
+ list<QtNode*>::iterator debugIter; \
+ for( debugIter=subList->begin(); debugIter!=subList->end(); debugIter++ ) \
+ (*debugIter)->printTree( 2, RMInit::dbgOut, QtNode::QT_DIRECT_CHILDS ); \
+ )
+
+ // delete temporary subList
+ delete subList;
+ subList=NULL;
+ };
+
+ // add nodes of next level
+ if( flag == QT_DIRECT_CHILDS || flag == QT_ALL_NODES )
+ resultList->push_back( conditionTree );
+
+ RMDBGIF( 4, RMDebug::module_qlparser, "QtSelectionIterator",
+ RMInit::dbgOut << "4. current child list including direct childs " << endl; \
+ list<QtNode*>::iterator debugIter; \
+ for( debugIter=resultList->begin(); debugIter!=resultList->end(); debugIter++ ) \
+ (*debugIter)->printTree( 2, RMInit::dbgOut, QtNode::QT_DIRECT_CHILDS ); \
+ )
+
+ };
+
+ return resultList;
+}
+
+
+void
+QtSelectionIterator::printTree( int tab, ostream& s, QtChildType mode )
+{
+ s << SPACE_STR(tab).c_str() << "QtSelectionIterator Object: type " << flush;
+ dataStreamType.printStatus( s );
+ s << endl;
+
+ if( mode != QtNode::QT_DIRECT_CHILDS )
+ {
+ if( conditionTree )
+ {
+ s << SPACE_STR(tab).c_str() << "condition : " << endl;
+ conditionTree->printTree( tab + 2, s );
+ }
+ else
+ s << SPACE_STR(tab).c_str() << "no condition" << endl;
+ }
+
+ QtIterator::printTree( tab, s, mode );
+}
+
+
+
+void
+QtSelectionIterator::printAlgebraicExpression( ostream& s )
+{
+ s << "sel<";
+
+ conditionTree->printAlgebraicExpression( s );
+
+ s << ">";
+
+ QtIterator::printAlgebraicExpression( s );
+}
+
+
+
+QtNode::QtDataList*
+QtSelectionIterator::next()
+{
+ RMDBGENTER( 1, RMDebug::module_qlparser, "QtSelectionIterator", "QtSelectionIterator::next()" )
+
+ QtDataList* returnValue = NULL;
+
+ if( inputs )
+ {
+ bool nextTupelValid = false;
+ QtDataList* actualTupel=NULL;
+
+ while( !nextTupelValid )
+ {
+ actualTupel = (*inputs)[0]->next();
+
+ if( actualTupel )
+ {
+ if( conditionTree )
+ {
+ // evaluate the condition tree
+ QtData* resultData = conditionTree->evaluate( actualTupel );
+
+ if( resultData )
+ {
+ if( resultData->getDataType() == QT_BOOL )
+ nextTupelValid = (bool)((QtAtomicData*)resultData)->getUnsignedValue();
+ else
+ {
+ RMInit::logOut << "Error: QtSelectionIterator::next() - result of the WHERE part must be of type Bool." << endl;
+ parseInfo.setErrorNo(359);
+ throw parseInfo;
+ }
+
+ resultData->deleteRef();
+
+ if( !nextTupelValid )
+ {
+ // delete transient objects
+ vector<QtData*>::iterator iter;
+
+ for( iter=actualTupel->begin(); iter!=actualTupel->end(); iter++)
+ if( *iter ) (*iter)->deleteRef();
+
+ // delete vector itself
+ delete actualTupel;
+ actualTupel = NULL;
+ };
+ }
+ }
+ else
+ nextTupelValid = true;
+ }
+ else
+ break;
+ }
+
+ returnValue = actualTupel;
+ }
+
+ RMDBGEXIT( 1, RMDebug::module_qlparser, "QtSelectionIterator", "QtSelectionIterator::next()" )
+
+ return returnValue;
+}
+
+/*
+inline void
+QtSelectionIterator::preOptimize()
+{
+ if( conditionTree )
+ conditionTree->optimizeLoad( new QtNode::QtTrimList );
+
+ // pass it to the input streams
+ QtIterator::preOptimize();
+};
+*/
+
+const QtTypeTuple&
+QtSelectionIterator::checkType()
+{
+ RMDBCLASS( "QtSelectionIterator", "checkType()", "qlparser", __FILE__, __LINE__ )
+
+ // concatenate types of inputs
+ getInputTypeTuple( dataStreamType );
+
+ // type check for condition tree
+ if( conditionTree )
+ {
+ const QtTypeElement& type = conditionTree->checkType( (QtTypeTuple*)&dataStreamType );
+
+ if( type.getDataType() != QT_BOOL )
+ {
+ RMInit::logOut << "Error: QtSelectionIterator::next() - result of the WHERE part must be of type Bool." << endl;
+ parseInfo.setErrorNo(359);
+ throw parseInfo;
+ }
+ }
+
+ // pass type tuple
+ return dataStreamType;
+}
diff --git a/qlparser/qtselectioniterator.hh b/qlparser/qtselectioniterator.hh
new file mode 100644
index 0000000..d187e68
--- /dev/null
+++ b/qlparser/qtselectioniterator.hh
@@ -0,0 +1,119 @@
+#ifndef _QTSELECTIONITERATOR_
+#define _QTSELECTIONITERATOR_
+
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+#endif
+
+#include "qlparser/qtiterator.hh"
+#include "qlparser/qtoperation.hh"
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+An condition expression specified through a reference to
+an instance of the QtOperation sub-hierarchy, is evaluated for the actual input
+The boolean result determines if the tupel is passed to the output stream or not.
+So the method {\tt next()} reads tupels from its inputs until one can be
+passed to its caller. The class represents the WHERE condition in the query
+
+*/
+
+class QtSelectionIterator : public QtIterator
+{
+ public:
+ /// default constructor
+ QtSelectionIterator();
+
+ /// constructor getting a pointer to the parent
+ QtSelectionIterator( QtNode* node );
+
+ /// virtual destructor
+ virtual ~QtSelectionIterator();
+
+ /// return childs of the node
+ virtual QtNodeList* getChilds( QtChildType flag );
+
+ /// method for query rewrite
+ inline virtual void setInput( QtOperation* child, QtOperation* input);
+
+ /// optimizing load access
+// virtual void preOptimize();
+ /**
+ Trigger load optimization in the condition tree and pass the optimization step to
+ the input streams.
+ */
+
+ /// prints the tree
+ virtual void printTree( int tab, std::ostream& s = std::cout, QtChildType mode = QT_ALL_NODES );
+
+ /// prints the algebraic expression
+ virtual void printAlgebraicExpression( std::ostream& s = std::cout );
+
+ //@Man: Operations of the ONC protocol:
+ //@{
+ ///
+ QtDataList* next();
+ //@}
+
+ //@Man: Read/Write methods:
+ //@{
+ ///
+ //inline virtual void setParents();
+ ///
+ inline void setConditionTree( QtOperation* operation );
+ ///
+ inline QtOperation* getConditionTree();
+ //@}
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ /// type checking
+ virtual const QtTypeTuple& checkType();
+
+ private:
+ /// pointer to a tree representing the where part of the query
+ QtOperation* conditionTree;
+
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+#include "qlparser/qtselectioniterator.icc"
+
+#endif
+
+
diff --git a/qlparser/qtselectioniterator.icc b/qlparser/qtselectioniterator.icc
new file mode 100644
index 0000000..5947f9c
--- /dev/null
+++ b/qlparser/qtselectioniterator.icc
@@ -0,0 +1,68 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+inline void
+QtSelectionIterator::setConditionTree( QtOperation* operation )
+{
+ conditionTree = operation;
+
+ if( operation )
+ operation->setParent( this );
+};
+
+
+
+inline QtOperation*
+QtSelectionIterator::getConditionTree()
+{
+ return( conditionTree );
+};
+
+
+
+inline void
+QtSelectionIterator::setInput( QtOperation* inputOld, QtOperation* inputNew )
+{
+ if( conditionTree == inputOld )
+ {
+ setConditionTree( inputNew );
+
+ if( inputNew )
+ inputNew->setParent( this );
+ }
+};
+
+
+
+inline const QtNode::QtNodeType
+QtSelectionIterator::getNodeType() const
+{
+ return nodeType;
+}
+
diff --git a/qlparser/qtstringdata.cc b/qlparser/qtstringdata.cc
new file mode 100644
index 0000000..41abcfa
--- /dev/null
+++ b/qlparser/qtstringdata.cc
@@ -0,0 +1,88 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)qlparser, QtStringData: $Header: /home/rasdev/CVS-repository/rasdaman/qlparser/qtstringdata.cc,v 1.8 2003/12/27 20:51:28 rasdev Exp $";
+
+#include "qlparser/qtstringdata.hh"
+
+#include <iostream>
+#include <cstring>
+
+
+
+QtStringData::QtStringData( const std::string& str )
+ : stringData(str), QtData()
+{
+}
+
+
+
+QtDataType
+QtStringData::getDataType() const
+{
+ return QT_STRING;
+}
+
+
+
+bool
+QtStringData::equal( const QtData* obj ) const
+{
+ bool returnValue = false; // not equal by initialization
+
+ if( obj->getDataType() == QT_STRING )
+ returnValue = (stringData == ((QtStringData*)obj)->getStringData());
+
+ return returnValue;
+}
+
+
+
+std::string
+QtStringData::getSpelling() const
+{
+ return stringData;
+}
+
+
+
+char* QtStringData::getTypeStructure() const
+{
+ return strdup("string");
+}
+
+
+
+void
+QtStringData::printStatus( std::ostream& stream ) const
+{
+ stream << "string, value: " << stringData.c_str() << std::flush;
+
+ QtData::printStatus( stream );
+}
diff --git a/qlparser/qtstringdata.hh b/qlparser/qtstringdata.hh
new file mode 100644
index 0000000..837ac05
--- /dev/null
+++ b/qlparser/qtstringdata.hh
@@ -0,0 +1,97 @@
+#ifndef _QTSTRINGDATA_
+#define _QTSTRINGDATA_
+
+#include "qlparser/qtdata.hh"
+
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+#endif
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+ The class encapsulates a string.
+*/
+
+class QtStringData : public QtData
+{
+ public:
+ /// constructor getting the string
+ QtStringData( const std::string& str );
+
+ //@Man: Read/Write methods:
+ //@{
+ ///
+
+ ///
+ inline const std::string& getStringData() const;
+ ///
+ inline void setStringData( const std::string& str );
+
+ /// returns a null-terminated string describing the type structure
+ virtual char* getTypeStructure() const;
+ /**
+ The string pointer has to be free using free() by the caller.
+ */
+
+ ///
+ //@}
+
+ /// returns {\tt QT_STRING}
+ virtual QtDataType getDataType() const;
+
+ /// compares data content
+ virtual bool equal( const QtData* obj ) const;
+
+ /// returns content dependent string representation
+ virtual std::string getSpelling() const;
+
+ /// print status of the object to the specified stream
+ virtual void printStatus( std::ostream& stream = std::cout ) const;
+
+ private:
+ /// prevents from using the default constructor
+ QtStringData(){};
+
+ ///
+ std::string stringData;
+};
+
+#include "qlparser/qtstringdata.icc"
+
+#endif
+
+
+
+
diff --git a/qlparser/qtstringdata.icc b/qlparser/qtstringdata.icc
new file mode 100644
index 0000000..eea6747
--- /dev/null
+++ b/qlparser/qtstringdata.icc
@@ -0,0 +1,42 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+
+inline const std::string&
+QtStringData::getStringData() const
+{
+ return stringData;
+}
+
+
+inline void
+QtStringData::setStringData( const std::string& str )
+{
+ stringData = str;
+}
diff --git a/qlparser/qtunaryfunc.cc b/qlparser/qtunaryfunc.cc
new file mode 100644
index 0000000..fa151fd
--- /dev/null
+++ b/qlparser/qtunaryfunc.cc
@@ -0,0 +1,414 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)qlparser, QtIntervalLoOp, QtIntervalHiOp, QtSDom: $Header: /home/rasdev/CVS-repository/rasdaman/qlparser/qtunaryfunc.cc,v 1.11 2003/12/27 20:51:28 rasdev Exp $";
+
+#include "qlparser/qtunaryfunc.hh"
+#include "qlparser/qtintervaldata.hh"
+#include "qlparser/qtatomicdata.hh"
+#include "qlparser/qtmintervaldata.hh"
+#include "qlparser/qtmdd.hh"
+
+const QtNode::QtNodeType QtIntervalLoOp::nodeType = QtNode::QT_LO;
+
+
+QtIntervalLoOp::QtIntervalLoOp( QtOperation* newInput )
+ : QtUnaryOperation( newInput )
+{
+}
+
+
+
+QtData*
+QtIntervalLoOp::evaluate( QtDataList* inputList )
+{
+ RMDBCLASS( "QtIntervalLoOp", "evaluate( QtDataList* )", "qlparser", __FILE__, __LINE__ )
+
+ QtData* returnValue = NULL;
+ QtData* operand = NULL;
+
+ operand = input->evaluate( inputList );
+
+ if( operand )
+ {
+#ifdef QT_RUNTIME_TYPE_CHECK
+ if( operand->getDataType() != QT_INTERVAL )
+ {
+ RMInit::logOut << "Internal error in QtIntervalLoOp::evaluate() - "
+ << "runtime type checking failed (INTERVAL)." << std::endl;
+
+ // delete old operand
+ if( operand ) operand->deleteRef();
+ return 0;
+ }
+#endif
+
+ QtIntervalData* intervalData = (QtIntervalData*)operand;
+
+ r_Sinterval sinterval = intervalData->getIntervalData();
+
+ if( sinterval.is_low_fixed() )
+ {
+ returnValue = new QtAtomicData( (r_Long)(sinterval.low()), 4 );
+ }
+ else
+ {
+ RMInit::logOut << "Error: QtIntervalLoOp::evaluate() - operation lo() can not be used for an open bound." << std::endl;
+
+ // delete old operand
+ if( operand ) operand->deleteRef();
+
+ parseInfo.setErrorNo(394);
+ throw parseInfo;
+ }
+
+ // delete old operand
+ if( operand ) operand->deleteRef();
+
+ }
+ else
+ {
+ RMDBGMIDDLE( 1, RMDebug::module_qlparser, "QtIntervalLoOp", "Information: QtIntervalLoOp::evaluate() - operand is not provided." )
+ }
+
+ return returnValue;
+}
+
+
+
+void
+QtIntervalLoOp::printTree( int tab, std::ostream& s, QtChildType mode )
+{
+ s << SPACE_STR(tab).c_str() << "QtIntervalLoOp Object: " << std::endl;
+
+ QtUnaryOperation::printTree( tab, s, mode );
+}
+
+
+
+void
+QtIntervalLoOp::printAlgebraicExpression( std::ostream& s )
+{
+ s << "(" << std::flush;
+
+ if( input )
+ input->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << ").lo ";
+}
+
+
+
+const QtTypeElement&
+QtIntervalLoOp::checkType( QtTypeTuple* typeTuple )
+{
+ RMDBCLASS( "QtIntervalLoOp", "checkType( QtTypeTuple* )", "qlparser", __FILE__, __LINE__ )
+
+ dataStreamType.setDataType( QT_TYPE_UNKNOWN );
+
+ // check operand branches
+ if( input )
+ {
+
+ // get input type
+ const QtTypeElement& inputType = input->checkType( typeTuple );
+
+ if( inputType.getDataType() != QT_INTERVAL )
+ {
+ RMInit::logOut << "Error: QtIntervalLoOp::checkType() - operation lo() must be of type interval." << std::endl;
+ parseInfo.setErrorNo(393);
+ throw parseInfo;
+ }
+
+ dataStreamType.setDataType( QT_LONG );
+ }
+ else
+ RMInit::logOut << "Error: QtIntervalLoOp::checkType() - operand branch invalid." << std::endl;
+
+ return dataStreamType;
+}
+
+
+
+const QtNode::QtNodeType QtIntervalHiOp::nodeType = QtNode::QT_HI;
+
+
+QtIntervalHiOp::QtIntervalHiOp( QtOperation* newInput )
+ : QtUnaryOperation( newInput )
+{
+}
+
+
+
+QtData*
+QtIntervalHiOp::evaluate( QtDataList* inputList )
+{
+ RMDBCLASS( "QtIntervalHiOp", "evaluate( QtDataList* )", "qlparser", __FILE__, __LINE__ )
+
+ QtData* returnValue = NULL;
+ QtData* operand = NULL;
+
+ operand = input->evaluate( inputList );
+
+ if( operand )
+ {
+#ifdef QT_RUNTIME_TYPE_CHECK
+ if( operand->getDataType() != QT_INTERVAL )
+ {
+ RMInit::logOut << "Internal error in QtIntervalHiOp::evaluate() - "
+ << "runtime type checking failed (INTERVAL)." << std::endl;
+
+ // delete old operand
+ if( operand ) operand->deleteRef();
+ return 0;
+ }
+#endif
+
+ QtIntervalData* intervalData = (QtIntervalData*)operand;
+
+ r_Sinterval sinterval = intervalData->getIntervalData();
+
+ if( sinterval.is_high_fixed() )
+ {
+ returnValue = new QtAtomicData( (r_Long)(sinterval.high()), 4 );
+ }
+ else
+ {
+ RMInit::logOut << "Error: QtIntervalHiOp::evaluate() - operation lo() can not be used for an open bound." << std::endl;
+
+ // delete old operand
+ if( operand ) operand->deleteRef();
+
+ parseInfo.setErrorNo(394);
+ throw parseInfo;
+ }
+
+ // delete old operand
+ if( operand ) operand->deleteRef();
+ }
+ else
+ {
+ RMDBGMIDDLE( 1, RMDebug::module_qlparser, "QtIntervalHiOp", "Information: QtIntervalHiOp::evaluate() - operand is not provided." )
+ }
+
+ return returnValue;
+}
+
+
+
+void
+QtIntervalHiOp::printTree( int tab, std::ostream& s, QtChildType mode )
+{
+ s << SPACE_STR(tab).c_str() << "QtIntervalHiOp Object: " << std::endl;
+
+ QtUnaryOperation::printTree( tab, s, mode );
+}
+
+
+
+void
+QtIntervalHiOp::printAlgebraicExpression( std::ostream& s )
+{
+ s << "(" << std::flush;
+
+ if( input )
+ input->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << ").hi ";
+}
+
+
+
+const QtTypeElement&
+QtIntervalHiOp::checkType( QtTypeTuple* typeTuple )
+{
+ RMDBCLASS( "QtIntervalHiOp", "checkType( QtTypeTuple* )", "qlparser", __FILE__, __LINE__ )
+
+ dataStreamType.setDataType( QT_TYPE_UNKNOWN );
+
+ // check operand branches
+ if( input )
+ {
+
+ // get input type
+ const QtTypeElement& inputType = input->checkType( typeTuple );
+
+ if( inputType.getDataType() != QT_INTERVAL )
+ {
+ RMInit::logOut << "Error: QtIntervalHiOp::checkType() - operation lo() must be of type interval." << std::endl;
+ parseInfo.setErrorNo(393);
+ throw parseInfo;
+ }
+
+ dataStreamType.setDataType( QT_LONG );
+ }
+ else
+ RMInit::logOut << "Error: QtIntervalHiOp::checkType() - operand branch invalid." << std::endl;
+ return dataStreamType;
+}
+
+
+
+
+const QtNode::QtNodeType QtSDom::nodeType = QtNode::QT_SDOM;
+
+
+QtSDom::QtSDom( QtOperation* newInput )
+ : QtUnaryOperation( newInput )
+{
+}
+
+
+
+QtData*
+QtSDom::evaluate( QtDataList* inputList )
+{
+ RMDBCLASS( "QtSDom", "evaluate( QtDataList* )", "qlparser", __FILE__, __LINE__ )
+
+ QtData* returnValue = NULL;
+ QtData* operand = NULL;
+
+ operand = input->evaluate( inputList );
+
+ if( operand )
+ {
+#ifdef QT_RUNTIME_TYPE_CHECK
+ if( operand->getDataType() != QT_MDD )
+ {
+ RMInit::logOut << "Internal error in QtSDom::evaluate() - "
+ << "runtime type checking failed (MDD)." << std::endl;
+
+ // delete old operand
+ if( operand ) operand->deleteRef();
+ return 0;
+ }
+#endif
+
+ QtMDD* qtMDD = (QtMDD*) operand;
+
+ returnValue = new QtMintervalData( qtMDD->getLoadDomain() );
+
+ // delete old operand
+ if( operand ) operand->deleteRef();
+ }
+ else
+ {
+ RMDBGMIDDLE( 1, RMDebug::module_qlparser, "QtSDom", "Information: QtSDom::evaluate() - operand is not provided." )
+ }
+
+ return returnValue;
+}
+
+
+
+void
+QtSDom::optimizeLoad( QtTrimList* trimList )
+{
+ RMDBCLASS( "QtSDom", "optimizeLoad( QtTrimList* )", "qlparser", __FILE__, __LINE__ )
+
+ // reset trimList because optimization enters a new MDD area
+
+ // delete list
+ vector<QtNode::QtTrimElement*>::iterator iter;
+ for( iter=trimList->begin(); iter!=trimList->end(); iter++ )
+ {
+ delete *iter;
+ *iter=NULL;
+ }
+ delete trimList;
+ trimList=NULL;
+
+ if( input )
+ input->optimizeLoad( new QtNode::QtTrimList );
+}
+
+
+
+void
+QtSDom::printTree( int tab, std::ostream& s, QtChildType mode )
+{
+ s << SPACE_STR(tab).c_str() << "QtSDom Object: " << std::endl;
+
+ QtUnaryOperation::printTree( tab, s, mode );
+}
+
+
+
+void
+QtSDom::printAlgebraicExpression( std::ostream& s )
+{
+ s << "sdom(" << std::flush;
+
+ if( input )
+ input->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << ")";
+}
+
+
+
+const QtTypeElement&
+QtSDom::checkType( QtTypeTuple* typeTuple )
+{
+ RMDBCLASS( "QtSDom", "checkType( QtTypeTuple* )", "qlparser", __FILE__, __LINE__ )
+
+ dataStreamType.setDataType( QT_TYPE_UNKNOWN );
+
+ // check operand branches
+ if( input )
+ {
+
+ // get input type
+ const QtTypeElement& inputType = input->checkType( typeTuple );
+
+ if( inputType.getDataType() != QT_MDD )
+ {
+ RMInit::logOut << "Error: QtSDom::checkType() - operand must be of type MDD." << std::endl;
+ parseInfo.setErrorNo(395);
+ throw parseInfo;
+ }
+
+ dataStreamType.setDataType( QT_MINTERVAL );
+ }
+ else
+ RMInit::logOut << "Error: QtSDom::checkType() - operand branch invalid." << std::endl;
+
+ return dataStreamType;
+}
+
+
diff --git a/qlparser/qtunaryfunc.hh b/qlparser/qtunaryfunc.hh
new file mode 100644
index 0000000..b78ea35
--- /dev/null
+++ b/qlparser/qtunaryfunc.hh
@@ -0,0 +1,161 @@
+#ifndef _QTUNARYFUNC_HH__
+#define _QTUNARYFUNC_HH___
+
+#include "qlparser/qtunaryoperation.hh"
+
+// forward declarations
+class QtOperation;
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+ The class represenst a function returning the lower bound of an interval.
+
+*/
+
+class QtIntervalLoOp : public QtUnaryOperation
+{
+ public:
+ /// constructor getting operand
+ QtIntervalLoOp( QtOperation* newInput );
+
+ /// evaluates the node
+ QtData* evaluate( QtDataList* inputList );
+
+ /// prints the tree
+ virtual void printTree( int tab, std::ostream& s = std::cout, QtChildType mode = QT_ALL_NODES );
+
+ /// prints the algebraic expression
+ virtual void printAlgebraicExpression( std::ostream& s = std::cout );
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ /// type checking of the subtree
+ virtual const QtTypeElement& checkType( QtTypeTuple* typeTuple = NULL );
+
+ private:
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+
+
+
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+ The class represenst a function returning the higher bound of an interval.
+
+*/
+
+class QtIntervalHiOp : public QtUnaryOperation
+{
+ public:
+ /// constructor getting operand
+ QtIntervalHiOp( QtOperation* newInput );
+
+ /// evaluates the node
+ QtData* evaluate( QtDataList* inputList );
+
+ /// prints the tree
+ virtual void printTree( int tab, std::ostream& s = std::cout, QtChildType mode = QT_ALL_NODES );
+
+ /// prints the algebraic expression
+ virtual void printAlgebraicExpression( std::ostream& s = std::cout );
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ /// type checking of the subtree
+ virtual const QtTypeElement& checkType( QtTypeTuple* typeTuple = NULL );
+
+ private:
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+
+
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+ The class represenst a function returning the spatial domain of an mdd object.
+
+*/
+
+class QtSDom : public QtUnaryOperation
+{
+ public:
+ /// constructor getting operand
+ QtSDom( QtOperation* newInput );
+
+ /// evaluates the node
+ QtData* evaluate( QtDataList* inputList );
+
+ /// optimizing load access
+ virtual void optimizeLoad( QtTrimList* trimList );
+ /**
+ The method deletes the given {\tt trimList} and passes the {\tt optimizeLoad}
+ message with empty triming list to its operand tree.
+
+ Optimization process enters a new MDD area.
+ */
+
+ /// prints the tree
+ virtual void printTree( int tab, std::ostream& s = std::cout, QtChildType mode = QT_ALL_NODES );
+
+ /// prints the algebraic expression
+ virtual void printAlgebraicExpression( std::ostream& s = std::cout );
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ /// type checking
+ virtual const QtTypeElement& checkType( QtTypeTuple* typeTuple = NULL );
+
+ private:
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+
+#include "qlparser/qtunaryfunc.icc"
+
+#endif
+
diff --git a/qlparser/qtunaryfunc.icc b/qlparser/qtunaryfunc.icc
new file mode 100644
index 0000000..c6cccf1
--- /dev/null
+++ b/qlparser/qtunaryfunc.icc
@@ -0,0 +1,51 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+
+inline const QtNode::QtNodeType
+QtIntervalLoOp::getNodeType() const
+{
+ return nodeType;
+}
+
+
+inline const QtNode::QtNodeType
+QtIntervalHiOp::getNodeType() const
+{
+ return nodeType;
+}
+
+
+inline const QtNode::QtNodeType
+QtSDom::getNodeType() const
+{
+ return nodeType;
+}
+
+
diff --git a/qlparser/qtunaryinduce.cc b/qlparser/qtunaryinduce.cc
new file mode 100644
index 0000000..60322d1
--- /dev/null
+++ b/qlparser/qtunaryinduce.cc
@@ -0,0 +1,1013 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)qlparser, QtUnaryInduce: $Id: qtunaryinduce.cc,v 1.47 2002/08/19 11:13:27 coman Exp $";
+
+#include "raslib/rmdebug.hh"
+
+#include "qlparser/qtunaryinduce.hh"
+#include "qlparser/qtmdd.hh"
+#include "qlparser/qtatomicdata.hh"
+#include "qlparser/qtcomplexdata.hh"
+#include "qlparser/qtnode.hh"
+
+#include "mddmgr/mddobj.hh"
+#include "tilemgr/tile.hh"
+
+#include "catalogmgr/typefactory.hh"
+#include "relcatalogif/structtype.hh"
+
+#include <sstream>
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+using namespace std;
+#endif
+
+const QtNode::QtNodeType QtUnaryInduce::nodeType = QtNode::QT_UNARY_INDUCE;
+
+QtUnaryInduce::QtUnaryInduce( QtOperation* initInput )
+ : QtUnaryOperation( initInput )
+{
+}
+
+
+
+bool
+QtUnaryInduce::getOperand( QtDataList* inputList, QtData* &operand )
+{
+ bool success = false;
+
+ // get the operands
+ operand = input->evaluate( inputList );
+
+ // Test, if the operands are valid.
+ if( operand )
+ success = true;
+ else
+ {
+ RMDBGMIDDLE( 1, RMDebug::module_qlparser, "QtUnaryInduce", "Information: QtUnaryInduce::getOperand() - operand is not provided." )
+ }
+
+ return success;
+}
+
+
+
+QtData*
+QtUnaryInduce::computeOp( QtData* operand, Ops::OpType operation )
+{
+ QtData* returnValue = NULL;
+
+ if( operand->getDataType() == QT_MDD )
+ {
+ QtMDD* mdd = (QtMDD*) operand;
+
+ const BaseType* resultCellType = (BaseType*)(Ops::getResultType( operation, mdd->getCellType() ));
+
+ returnValue = computeUnaryMDDOp( mdd, resultCellType, operation);
+ }
+ else if( operand->isScalarData() )
+ {
+ QtScalarData* scalar = (QtScalarData*) operand;
+
+ const BaseType* resultCellType = (BaseType*)(Ops::getResultType( operation, scalar->getValueType() ));
+
+ returnValue = computeUnaryOp( scalar, resultCellType, operation );
+ }
+
+ return returnValue;
+}
+
+
+
+QtData*
+QtUnaryInduce::computeUnaryMDDOp( QtMDD* operand, const BaseType* resultBaseType,
+ Ops::OpType operation, unsigned int operandOffset )
+{
+ RMDBCLASS( "QtUnaryInduce", "computeUnaryMDDOp( QtMDD*, BaseType*, Ops::OpType, unsigned int ) ", "qlparser", __FILE__, __LINE__ )
+
+ QtData* returnValue = NULL;
+
+ // get the MDD object
+ MDDObj* op = ((QtMDD*)operand)->getMDDObject();
+
+ // get the area, where the operation has to be applied
+ const r_Minterval &areaOp = ((QtMDD*)operand)->getLoadDomain();
+
+ // contains all tiles of the operand
+ vector<Tile*>* allTiles=NULL;
+
+ // iterator for tiles
+
+ // create MDDObj for result
+ MDDBaseType* mddBaseType = new MDDBaseType( "tmp", resultBaseType );
+ TypeFactory::addTempType( mddBaseType );
+
+ MDDObj* mddres = new MDDObj( mddBaseType, areaOp );
+
+ // get all tiles in relevant area
+ allTiles = op->intersect(areaOp);
+ std::vector<Tile*>::iterator tileIt = allTiles->begin();
+ if (tileIt != allTiles->end())
+ {
+ Tile* resTile = NULL;
+ UnaryOp* myOp = NULL;
+ if (operation == Ops::OP_IDENTITY)
+ {
+ myOp = Ops::getUnaryOp(operation, resultBaseType, resultBaseType, 0, operandOffset);
+ }
+ else {
+ myOp = Ops::getUnaryOp(operation, resultBaseType, (*tileIt)->getType(), 0, 0);
+ }
+ if (myOp == NULL)
+ {
+ RMInit::logOut << "QtUnaryInduce::computeUnaryMDDOp(...) could not get operation for result type " << resultBaseType->getName() << " argument type " << (*tileIt)->getType() << " operation " << operation << endl;
+ delete myOp;
+ myOp = NULL;
+ delete allTiles;
+ allTiles = NULL;
+ //contents of allTiles are deleted when index is deleted
+ delete mddres;
+ mddres = NULL;
+ delete resTile;
+ resTile = NULL;
+ delete mddres;
+ mddres = NULL;
+ // i am not sure about that error number...
+ parseInfo.setErrorNo(366);
+ throw parseInfo;
+ }
+ // and iterate over them
+ try {
+ for( ; tileIt != allTiles->end(); tileIt++ )
+ {
+ // domain of the actual tile
+ const r_Minterval &tileDom = (*tileIt)->getDomain();
+
+ // domain of the relevant area of the actual tile
+ r_Minterval intersectDom( tileDom.create_intersection( areaOp ) );
+
+ // create tile for result
+ resTile = new Tile( intersectDom, resultBaseType );
+
+ // carry out operation on the relevant area of the tiles
+ resTile->execUnaryOp(myOp, intersectDom, (*tileIt), intersectDom);
+ // insert Tile in result mdd
+ mddres->insertTile( resTile );
+ }
+ }
+ catch(r_Error& err)
+ {
+ RMInit::logOut << "QtUnaryInduce::computeUnaryMDDOp caught " << err.get_errorno() << " " << err.what() << endl;
+ delete myOp;
+ myOp = NULL;
+ delete allTiles;
+ allTiles = NULL;
+ //contents of allTiles are deleted when index is deleted
+ delete mddres;
+ mddres = NULL;
+ delete resTile;
+ resTile = NULL;
+ delete mddres;
+ mddres = NULL;
+ parseInfo.setErrorNo(err.get_errorno());
+ throw parseInfo;
+ }
+ catch (int err)
+ {
+ RMInit::logOut << "QtUnaryInduce::computeUnaryMDDOp caught errno error (" << err << ") in unaryinduce" << endl;
+ delete myOp;
+ myOp = NULL;
+ delete allTiles;
+ allTiles = NULL;
+ //contents of allTiles are deleted when index is deleted
+ delete mddres;
+ mddres = NULL;
+ delete resTile;
+ resTile = NULL;
+ delete mddres;
+ mddres = NULL;
+ parseInfo.setErrorNo(err);
+ throw parseInfo;
+ }
+
+ delete myOp;
+ myOp = NULL;
+ }
+ // delete tile vector
+ delete allTiles;
+ allTiles = NULL;
+
+ // create a new QtMDD object as carrier object for the transient MDD object
+ returnValue = new QtMDD( (MDDObj*)mddres );
+
+ // The following is now done when deleting the last reference to the operand
+ // delete the obsolete MDD object
+ // delete op;
+
+ return returnValue;
+}
+
+
+QtData*
+QtUnaryInduce::computeUnaryOp( QtScalarData* operand, const BaseType* resultBaseType,
+ Ops::OpType operation, unsigned int operandOffset )
+{
+ RMDBCLASS( "QtUnaryInduce", "computeUnaryOp( QtScalarData*, BaseType*, Ops::OpType, unsigned int ) ", "qlparser", __FILE__, __LINE__ )
+
+ QtScalarData* scalarDataObj = NULL;
+
+ // allocate memory for the result
+ char* resultBuffer = new char[ resultBaseType->getSize() ];
+
+ RMDBGIF( 4, RMDebug::module_qlparser, "QtUnaryInduce", \
+ RMInit::dbgOut << "Operand value "; \
+ operand->getValueType()->printCell( RMInit::dbgOut, operand->getValueBuffer() ); \
+ RMInit::dbgOut << endl; \
+ )
+
+ if(( operation == Ops::OP_IDENTITY )) // || ( operation == Ops::OP_SQRT ))
+ // operand type is the same as result type
+ Ops::execUnaryConstOp( operation, resultBaseType,
+ resultBaseType,
+ resultBuffer,
+ operand->getValueBuffer(),
+ 0, operandOffset );
+ else
+ try
+ {
+ Ops::execUnaryConstOp( operation, resultBaseType,
+ operand->getValueType(),
+ resultBuffer,
+ operand->getValueBuffer(),
+ 0, operandOffset );
+ }
+ catch(int err)
+ {
+ delete[] resultBuffer;
+ resultBuffer = NULL;
+ parseInfo.setErrorNo(err);
+ throw parseInfo;
+ }
+
+ RMDBGIF( 4, RMDebug::module_qlparser, "QtUnaryInduce", \
+ RMInit::dbgOut << "Result value "; \
+ resultBaseType->printCell( RMInit::dbgOut, resultBuffer ); \
+ RMInit::dbgOut << endl; \
+ )
+
+ if( resultBaseType->getType() == STRUCT )
+ scalarDataObj = new QtComplexData();
+ else
+ scalarDataObj = new QtAtomicData();
+
+ scalarDataObj->setValueType ( resultBaseType );
+ scalarDataObj->setValueBuffer( resultBuffer );
+
+ return scalarDataObj;
+}
+
+
+const QtNode::QtNodeType QtNot::nodeType = QtNode::QT_NOT;
+
+QtNot::QtNot( QtOperation* initInput )
+ : QtUnaryInduce( initInput )
+{
+}
+
+
+QtData*
+QtNot::evaluate( QtDataList* inputList )
+{
+ QtData* returnValue = NULL;
+ QtData* operand = NULL;
+
+ if( getOperand( inputList, operand ) )
+ {
+ returnValue = computeOp( operand, Ops::OP_NOT );
+
+ // delete old operand
+ if( operand ) operand->deleteRef();
+ }
+ return returnValue;
+}
+
+
+
+void
+QtNot::printTree( int tab, ostream& s, QtChildType mode )
+{
+ s << SPACE_STR(tab).c_str() << "QtNot Object" << endl;
+
+ QtUnaryInduce::printTree( tab+2, s, mode );
+}
+
+
+
+void
+QtNot::printAlgebraicExpression( ostream& s )
+{
+ s << "not(";
+
+ if( input )
+ input->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << ")";
+}
+
+
+
+const QtTypeElement&
+QtNot::checkType( QtTypeTuple* typeTuple )
+{
+ RMDBCLASS( "QtNot", "checkType( QtTypeTuple* )", "qlparser", __FILE__, __LINE__ )
+
+ dataStreamType.setDataType( QT_TYPE_UNKNOWN );
+
+ // check operand branches
+ if( input )
+ {
+
+ // get input types
+ const QtTypeElement& inputType = input->checkType( typeTuple );
+
+ RMDBGIF( 4, RMDebug::module_qlparser, "QtNot", \
+ RMInit::dbgOut << "Operand: " << flush; \
+ inputType.printStatus( RMInit::dbgOut ); \
+ RMInit::dbgOut << endl; \
+ )
+
+ if( inputType.getDataType() == QT_MDD )
+ {
+ const BaseType* baseType = ((const MDDBaseType*)(inputType.getType()))->getBaseType();
+
+ const BaseType* resultBaseType = (BaseType*)(Ops::getResultType( Ops::OP_NOT, baseType ));
+
+ if( !resultBaseType )
+ {
+ RMInit::logOut << "Error: QtNot::checkType() - induce operand type is not supported." << endl;
+ parseInfo.setErrorNo(366);
+ throw parseInfo;
+ }
+
+ MDDBaseType* resultMDDType = new MDDBaseType( "tmp", resultBaseType );
+ TypeFactory::addTempType( resultMDDType );
+
+ dataStreamType.setType( resultMDDType );
+ }
+ else if( inputType.isBaseType() )
+ {
+ BaseType* baseType = (BaseType*)(inputType.getType());
+
+ const BaseType* resultBaseType = (BaseType*)(Ops::getResultType( Ops::OP_NOT, baseType ));
+
+ if( !resultBaseType )
+ {
+ RMInit::logOut << "Error: QtNot::checkType() - operand type is not supported." << endl;
+ parseInfo.setErrorNo(367);
+ throw parseInfo;
+ }
+
+ // MDDBaseType* resultMDDType = new MDDBaseType( "tmp", resultBaseType );
+ // TypeFactory::addTempType( resultMDDType );
+
+ // dataStreamType.setType( resultMDDType );
+ dataStreamType.setType( resultBaseType );
+ }
+ else
+ {
+ RMInit::logOut << "Error: QtNot::checkType() - operation is not supported for strings." << endl;
+ parseInfo.setErrorNo(385);
+ throw parseInfo;
+ }
+ }
+ else
+ RMInit::logOut << "Error: QtNot::checkType() - operand branch invalid." << endl;
+
+ return dataStreamType;
+}
+
+
+
+
+const QtNode::QtNodeType QtDot::nodeType = QtNode::QT_DOT;
+
+
+
+QtDot::QtDot( const string& initElementName )
+ : QtUnaryInduce( NULL ),
+ elementName( initElementName ),
+ elementNo(-1)
+{
+}
+
+
+
+QtDot::QtDot( unsigned initElementNo )
+ : QtUnaryInduce( NULL ),
+ elementNo( initElementNo )
+{
+}
+
+
+
+bool
+QtDot::equalMeaning( QtNode* node )
+{
+ bool result = false;
+
+ if( nodeType == node->getNodeType() )
+ {
+ QtDot* dotNode = (QtDot* ) node; // by force
+
+ // In future, elementName have to be converted to elementNo
+ // and then just the numbers are compared.
+ if( (elementNo != -1 && elementNo == dotNode->elementNo) ||
+ (elementNo == -1 && elementName == dotNode->elementName) )
+ result = input->equalMeaning( dotNode->getInput() );
+ };
+
+ return result;
+}
+
+
+string
+QtDot::getSpelling()
+{
+ char tempStr[20];
+ sprintf(tempStr, "%ud", (unsigned long)getNodeType());
+ string result = string(tempStr);
+
+ if( elementNo == -1 )
+ result.append( elementName );
+ else
+ {
+ std::ostringstream bufferStream;
+ bufferStream << elementNo << ends;
+
+ result.append( bufferStream.str() );
+ }
+
+ result.append( "(" );
+ result.append( input->getSpelling() );
+ result.append( ")" );
+
+ return result;
+}
+
+
+QtData*
+QtDot::evaluate( QtDataList* inputList )
+{
+ RMDBCLASS( "QtDot", "evaluate( QtDataList* )", "qlparser", __FILE__, __LINE__ )
+
+ QtData* returnValue = NULL;
+ QtData* operand = NULL;
+
+ if( getOperand( inputList, operand ) )
+ {
+ if( operand->getDataType() == QT_MDD )
+ {
+ QtMDD* mdd = (QtMDD*) operand;
+
+#ifdef QT_RUNTIME_TYPE_CHECK
+ // test, if operand has complex base type
+ if( mdd->getCellType()->getType() != STRUCT )
+ {
+ RMInit::logOut << "Internal error in QtDot::evaluate() - "
+ << "runtime type checking failed." << endl;
+
+ // delete old operand
+ if( operand ) operand->deleteRef();
+
+ return 0;
+ }
+#endif
+
+ StructType* operandType = (StructType*)mdd->getCellType();
+ unsigned int operandOffset;
+ const BaseType* resultCellType = NULL;
+
+ if( elementNo == -1 )
+ resultCellType = operandType->getElemType( (char*)(elementName.c_str()) );
+ else
+ resultCellType = operandType->getElemType( (unsigned int)elementNo );
+
+ if( !resultCellType )
+ {
+ RMInit::logOut << "Error: QtDot::evaluate() - struct selector is not valid." << endl;
+ parseInfo.setErrorNo(370);
+ throw parseInfo;
+ }
+
+ if( elementNo == -1 )
+ operandOffset = operandType->getOffset( (char*)(elementName.c_str()) );
+ else
+ operandOffset = operandType->getOffset( (unsigned int)elementNo );
+
+ RMDBGIF( 1, RMDebug::module_qlparser, "QtUnaryInduce", \
+ char* typeStructure = operandType->getTypeStructure(); \
+ RMDBGMIDDLE( 4, RMDebug::module_qlparser, "QtUnaryInduce", "Operand base type " << operandType->getTypeName() << ", structure " << typeStructure ) \
+ free( typeStructure ); typeStructure=NULL; \
+ RMDBGMIDDLE( 4, RMDebug::module_qlparser, "QtUnaryInduce", "Operand base offset " << operandOffset ) \
+ typeStructure = resultCellType->getTypeStructure(); \
+ RMDBGMIDDLE( 4, RMDebug::module_qlparser, "QtUnaryInduce", "Result base type " << resultCellType->getTypeName() << ", structure " << typeStructure ) \
+ free( typeStructure ); typeStructure=NULL; \
+ )
+
+ returnValue = computeUnaryMDDOp( mdd, resultCellType, Ops::OP_IDENTITY, operandOffset );
+ }
+ else if( operand->isScalarData() )
+ {
+ QtScalarData* scalar = (QtScalarData*) operand;
+
+#ifdef QT_RUNTIME_TYPE_CHECK
+ // test, if operand has complex base type
+ if( scalar->getValueType()->getType() != STRUCT )
+ {
+ RMInit::logOut << "Internal error in QtDot::evaluate() - "
+ << "runtime type checking failed." << endl;
+
+ // delete old operand
+ if( operand ) operand->deleteRef();
+
+ return 0;
+ }
+#endif
+
+ StructType* operandType = (StructType*)scalar->getValueType();
+ unsigned int operandOffset;
+ const BaseType* resultCellType=NULL;
+
+ if( elementNo == -1 )
+ resultCellType = operandType->getElemType( (char*)(elementName.c_str()) );
+ else
+ resultCellType = operandType->getElemType( (unsigned int)elementNo );
+
+ if( !resultCellType )
+ {
+ RMInit::logOut << "Error: QtDot::evaluate() - struct selector is not valid." << endl;
+ parseInfo.setErrorNo(370);
+ throw parseInfo;
+ }
+
+ if( elementNo == -1 )
+ operandOffset = operandType->getOffset( (char*)(elementName.c_str()) );
+ else
+ operandOffset = operandType->getOffset( (unsigned int)elementNo );
+
+ RMDBGIF( 1, RMDebug::module_qlparser, "QtUnaryInduce", \
+ char* typeStructure = operandType->getTypeStructure(); \
+ RMDBGMIDDLE( 4, RMDebug::module_qlparser, "QtUnaryInduce", "Operand scalar type " << operandType->getTypeName() << ", structure " << typeStructure ) \
+ free( typeStructure ); typeStructure=NULL; \
+ RMDBGMIDDLE( 4, RMDebug::module_qlparser, "QtUnaryInduce", "Operand scalar offset " << operandOffset ) \
+ typeStructure = resultCellType->getTypeStructure(); \
+ RMDBGMIDDLE( 4, RMDebug::module_qlparser, "QtUnaryInduce", "Result scalar type " << resultCellType->getTypeName() << ", structure " << typeStructure ) \
+ free( typeStructure ); typeStructure=NULL; \
+ )
+
+ returnValue = computeUnaryOp( scalar, resultCellType, Ops::OP_IDENTITY, operandOffset );
+ }
+ else
+ {
+ RMInit::logOut << "Error: QtDot::evaluate() - operation is not supported for strings." << endl;
+ parseInfo.setErrorNo(385);
+ throw parseInfo;
+ }
+
+ // delete old operand
+ if( operand ) operand->deleteRef();
+ }
+
+ return returnValue;
+}
+
+
+
+void
+QtDot::printTree( int tab, ostream& s, QtChildType mode )
+{
+ if( elementNo == -1 )
+ s << SPACE_STR(tab).c_str() << "QtDot Object: access " << elementName.c_str() << endl;
+ else
+ s << SPACE_STR(tab).c_str() << "QtDot Object: access no " << elementNo << endl;
+
+ QtUnaryInduce::printTree( tab+2, s, mode );
+}
+
+void
+QtDot::printAlgebraicExpression( ostream& s )
+{
+ s << "(";
+
+ if( input )
+ input->printAlgebraicExpression( s );
+ else
+ s << "<nn>";
+
+ s << ").";
+
+ if( elementNo == -1 )
+ s << elementName.c_str();
+ else
+ s << elementNo;
+
+ s << " ";
+}
+
+const QtTypeElement&
+QtDot::checkType( QtTypeTuple* typeTuple )
+{
+ RMDBCLASS( "QtDot", "checkType( QtTypeTuple* )", "qlparser", __FILE__, __LINE__ )
+
+ dataStreamType.setDataType( QT_TYPE_UNKNOWN );
+
+ // check operand branches
+ if( input )
+ {
+
+ // get input types
+ const QtTypeElement& inputType = input->checkType( typeTuple );
+
+ RMDBGIF( 4, RMDebug::module_qlparser, "QtDot", \
+ RMInit::dbgOut << "Operand: " << flush; \
+ inputType.printStatus( RMInit::dbgOut ); \
+ RMInit::dbgOut << endl; \
+ )
+
+ if( inputType.getDataType() == QT_MDD )
+ {
+ const BaseType* baseType = ((MDDBaseType*)(inputType.getType()))->getBaseType();
+
+ // test, if operand has complex base type
+ if( baseType->getType() != STRUCT )
+ {
+ RMInit::logOut << "Error: QtDot::evaluate() - operand of induce dot operation must be complex." << endl;
+ parseInfo.setErrorNo(368);
+ throw parseInfo;
+ }
+
+ StructType* structType = (StructType*)baseType;
+ const BaseType* resultBaseType = NULL;
+
+ if( elementNo == -1 )
+ resultBaseType = structType->getElemType( (char*)(elementName.c_str()) );
+ else
+ resultBaseType = structType->getElemType( (unsigned int)elementNo );
+
+ if( !resultBaseType )
+ {
+ RMInit::logOut << "Error: QtDot::evaluate() - struct selector is not valid." << endl;
+ parseInfo.setErrorNo(370);
+ throw parseInfo;
+ }
+
+ MDDBaseType* resultMDDType = new MDDBaseType( "tmp", resultBaseType );
+ TypeFactory::addTempType( resultMDDType );
+
+ dataStreamType.setType( resultMDDType );
+ }
+ else if( inputType.isBaseType() )
+ {
+ BaseType* baseType = (BaseType*)(inputType.getType());
+
+ // test, if operand has complex base type
+ if( baseType->getType() != STRUCT )
+ {
+ RMInit::logOut << "Error: QtDot::evaluate() - operand of dot operation must be complex." << endl;
+ parseInfo.setErrorNo(369);
+ throw parseInfo;
+ }
+
+ StructType* structType = (StructType*)baseType;
+ const BaseType* resultBaseType = NULL;
+
+ if( elementNo == -1 )
+ resultBaseType = structType->getElemType( (char*)(elementName.c_str()) );
+ else
+ resultBaseType = structType->getElemType( (unsigned int)elementNo );
+
+ if( !resultBaseType )
+ {
+ RMInit::logOut << "Error: QtDot::evaluate() - struct selector is not valid." << endl;
+ parseInfo.setErrorNo(370);
+ throw parseInfo;
+ }
+
+ dataStreamType.setType( resultBaseType );
+ }
+ else
+ {
+ RMInit::logOut << "Error: QtDot::checkType() - operation is not supported for strings." << endl;
+ parseInfo.setErrorNo(385);
+ throw parseInfo;
+ }
+ } else
+ RMInit::logOut << "Error: QtDot::checkType() - operand branch invalid." << endl;
+ return dataStreamType;
+}
+
+//--------------------------------------------
+// QtCast
+//--------------------------------------------
+
+const QtNode::QtNodeType QtCast::nodeType = QtNode::QT_CAST;
+
+QtCast::QtCast(QtOperation* initInput, cast_types t):
+ QtUnaryInduce(initInput), castType(t) {}
+
+QtData* QtCast::evaluate(QtDataList* inputList) {
+ QtData* returnValue = NULL;
+ QtData* operand = NULL;
+
+ if(getOperand(inputList, operand))
+ returnValue = computeOp( operand, getOp(castType));
+
+ // delete old operand
+ if(operand) operand->deleteRef();
+ return returnValue;
+}
+
+void QtCast::printTree(int tab, ostream& s, QtChildType mode) {
+ const char *type_name[] = {
+ "bool", "octet", "char", "short", "ushort",
+ "long", "ulong", "float", "double"
+ };
+ s << SPACE_STR(tab).c_str() << "QtCastObject "
+ << getNodeType()
+ << "<" << type_name[castType] << ">"
+ << endl;
+ QtUnaryInduce::printTree( tab + 2, s, mode );
+}
+
+void QtCast::printAlgebraicExpression(ostream& s) {
+ const char *type_name[] = {
+ "bool", "octet", "char", "short", "ushort",
+ "long", "ulong", "float", "double"
+ };
+ s << "cast<" << type_name[castType] << ">(";
+ if(input)
+ input->printAlgebraicExpression(s);
+ else
+ s << "<nn>";
+ s << ")";
+}
+
+const QtTypeElement& QtCast::checkType(QtTypeTuple* typeTuple) {
+
+ RMDBCLASS( "QtCast", "checkType( QtTypeTuple* )", "qlparser", __FILE__, __LINE__ )
+
+ dataStreamType.setDataType( QT_TYPE_UNKNOWN );
+
+ // check operand branches
+ if(input) {
+
+ // get input types
+ const QtTypeElement& inputType = input->checkType( typeTuple );
+ RMDBGIF( 4, RMDebug::module_qlparser, "QtCast", \
+ RMInit::dbgOut << "Operand: " << flush; \
+ inputType.printStatus( RMInit::dbgOut ); \
+ RMInit::dbgOut << endl; \
+ )
+
+ if(inputType.getDataType() == QT_MDD) {
+ const BaseType* baseType = ((MDDBaseType*)(inputType.getType()))->getBaseType();
+ BaseType* resultBaseType = (BaseType*)(Ops::getResultType( getOp(castType), baseType ));
+
+
+ if(!resultBaseType) {
+ RMInit::logOut << "Error: QtCast::checkType() - induce operand type is not support" << endl;
+ parseInfo.setErrorNo(366);
+ throw parseInfo;
+ }
+
+ MDDBaseType* resultMDDType = new MDDBaseType( "tmp", resultBaseType );
+ TypeFactory::addTempType( resultMDDType );
+ dataStreamType.setType( resultMDDType );
+ }
+
+ else if(inputType.isBaseType()) {
+ BaseType* baseType = (BaseType*)(inputType.getType());
+ BaseType* resultBaseType = (BaseType*)(Ops::getResultType( getOp(castType), baseType ));
+
+ if(!resultBaseType) {
+ RMInit::logOut << "Error: QtCast::checkType() - operand type is not supported." << endl;
+ parseInfo.setErrorNo(367);
+ throw parseInfo;
+ }
+
+ dataStreamType.setType( resultBaseType );
+ }
+ else {
+ RMInit::logOut << "Error: QtCast::checkType() - operation is not supported for strings." << endl;
+ parseInfo.setErrorNo(385);
+ throw parseInfo;
+ }
+ }
+ else
+ RMInit::logOut << "Error: QtCast::checkType() - operand branch invalid." << endl;
+
+ return dataStreamType;
+}
+
+
+//--------------------------------------------
+// QtRealPartOp
+//--------------------------------------------
+
+const QtNode::QtNodeType QtRealPartOp::nodeType = QtNode::QT_REALPART;
+
+QtRealPartOp::QtRealPartOp(QtOperation* initInput): QtUnaryInduce(initInput) {}
+
+QtData* QtRealPartOp::evaluate(QtDataList* inputList) {
+ QtData* returnValue = NULL;
+ QtData* operand = NULL;
+
+ if(getOperand(inputList, operand))
+ returnValue = computeOp( operand, Ops::OP_REALPART );
+ // delete old operand
+ if(operand) operand->deleteRef();
+ return returnValue;
+}
+
+void QtRealPartOp::printTree(int tab, ostream& s, QtChildType mode) {
+ s << SPACE_STR(tab).c_str() << "QtRealPartOpObject " << getNodeType() << endl;
+ QtUnaryInduce::printTree( tab + 2, s, mode );
+}
+
+void QtRealPartOp::printAlgebraicExpression(ostream& s) {
+ s << "Re(";
+ if(input)
+ input->printAlgebraicExpression(s);
+ else
+ s << "<nn>";
+ s << ")";
+}
+
+const QtTypeElement& QtRealPartOp::checkType(QtTypeTuple* typeTuple) {
+ RMDBCLASS( "QtRealPartOp", "checkType( QtTypeTuple* )", "qlparser", __FILE__, __LINE__ )
+
+ dataStreamType.setDataType( QT_TYPE_UNKNOWN );
+
+ // check operand branches
+ if(input) {
+
+ // get input types
+ const QtTypeElement& inputType = input->checkType( typeTuple );
+ RMDBGIF( 1, RMDebug::module_qlparser, "QtRealPartOp", \
+ RMInit::dbgOut << "Operand: " << flush; \
+ inputType.printStatus( RMInit::dbgOut ); \
+ RMInit::dbgOut << endl;
+ )
+
+ if(inputType.getDataType() == QT_MDD) {
+ const BaseType* baseType = ((MDDBaseType*)(inputType.getType()))->getBaseType();
+ BaseType* resultBaseType = (BaseType*)(Ops::getResultType( Ops::OP_REALPART, baseType ));
+ if(!resultBaseType) {
+ RMInit::logOut << "Error: QtRealPartOp::checkType() - induce operand type is not support" << endl;
+ parseInfo.setErrorNo(366);
+ throw parseInfo;
+ }
+ MDDBaseType* resultMDDType = new MDDBaseType( "tmp", resultBaseType );
+ TypeFactory::addTempType( resultMDDType );
+ dataStreamType.setType( resultMDDType );
+ }
+ else if(inputType.isBaseType()) {
+ BaseType* baseType = (BaseType*)(inputType.getType());
+ BaseType* resultBaseType = (BaseType*)(Ops::getResultType( Ops::OP_REALPART, baseType ));
+ if(!resultBaseType) {
+ RMInit::logOut << "Error: QtRealPartOp::checkType() - operand type is not supported." << endl;
+ parseInfo.setErrorNo(367);
+ throw parseInfo;
+ }
+ dataStreamType.setType( resultBaseType );
+ }
+ else {
+ RMInit::logOut << "Error: QtRealPartOp::checkType() - operation is not supported for strings." << endl;
+ parseInfo.setErrorNo(385);
+ throw parseInfo;
+ }
+ } else
+ RMInit::logOut << "Error: QtRealPartOp::checkType() - operand branch invalid." << endl;
+
+ return dataStreamType;
+}
+
+//--------------------------------------------
+// QtImaginarPartOp
+//--------------------------------------------
+
+const QtNode::QtNodeType QtImaginarPartOp::nodeType = QtNode::QT_IMAGINARPART;
+
+QtImaginarPartOp::QtImaginarPartOp(QtOperation* initInput): QtUnaryInduce(initInput) {}
+
+QtData* QtImaginarPartOp::evaluate(QtDataList* inputList) {
+ QtData* returnValue = NULL;
+ QtData* operand = NULL;
+
+ if(getOperand(inputList, operand))
+ returnValue = computeOp( operand, Ops::OP_IMAGINARPART );
+ // delete old operand
+ if(operand) operand->deleteRef();
+ return returnValue;
+}
+
+void QtImaginarPartOp::printTree(int tab, ostream& s, QtChildType mode) {
+ s << SPACE_STR(tab).c_str() << "QtImaginarPartObject " << getNodeType() << endl;
+ QtUnaryInduce::printTree( tab + 2, s, mode );
+}
+
+void QtImaginarPartOp::printAlgebraicExpression(ostream& s) {
+ s << "Im(";
+ if(input)
+ input->printAlgebraicExpression(s);
+ else
+ s << "<nn>";
+ s << ")";
+}
+
+const QtTypeElement& QtImaginarPartOp::checkType(QtTypeTuple* typeTuple) {
+ RMDBCLASS( "QtImaginarPart", "checkType( QtTypeTuple* )", "qlparser", __FILE__, __LINE__ )
+
+ dataStreamType.setDataType( QT_TYPE_UNKNOWN );
+
+ // check operand branches
+ if(input)
+ {
+
+ // get input types
+ const QtTypeElement& inputType = input->checkType( typeTuple );
+
+ RMDBGIF( 4, RMDebug::module_qlparser, "QtImaginarPartOp", \
+ RMInit::dbgOut << "Operand: " << flush; \
+ inputType.printStatus( RMInit::dbgOut ); \
+ RMInit::dbgOut << endl; \
+ )
+
+ if(inputType.getDataType() == QT_MDD) {
+ const BaseType* baseType = ((MDDBaseType*)(inputType.getType()))->getBaseType();
+ BaseType* resultBaseType = (BaseType*)(Ops::getResultType( Ops::OP_IMAGINARPART, baseType ));
+ if(!resultBaseType) {
+ RMInit::logOut << "Error: QtImaginarPart::checkType() - induce operand type is not support" << endl;
+ parseInfo.setErrorNo(366);
+ throw parseInfo;
+ }
+ MDDBaseType* resultMDDType = new MDDBaseType( "tmp", resultBaseType );
+ TypeFactory::addTempType( resultMDDType );
+ dataStreamType.setType( resultMDDType );
+ }
+ else if(inputType.isBaseType()) {
+ BaseType* baseType = (BaseType*)(inputType.getType());
+ BaseType* resultBaseType = (BaseType*)(Ops::getResultType(Ops::OP_IMAGINARPART, baseType));
+ if(!resultBaseType) {
+ RMInit::logOut << "Error: QtImaginarPart::checkType() - operand type is not supported." << endl;
+ parseInfo.setErrorNo(367);
+ throw parseInfo;
+ }
+ dataStreamType.setType( resultBaseType );
+ }
+ else {
+ RMInit::logOut << "Error: QtImaginarPart::checkType() - operation is not supported for strings." << endl;
+ parseInfo.setErrorNo(385);
+ throw parseInfo;
+ }
+ }
+ else
+ RMInit::logOut << "Error: QtImaginarPart::checkType() - operand branch invalid." << endl;
+ return dataStreamType;
+}
+
+#include "autogen_qtui.cc"
diff --git a/qlparser/qtunaryinduce.hh b/qlparser/qtunaryinduce.hh
new file mode 100644
index 0000000..ebd69d4
--- /dev/null
+++ b/qlparser/qtunaryinduce.hh
@@ -0,0 +1,267 @@
+#ifndef _QTUNARYINDUCE_HH_
+#define _QTUNARYINDUCE_HH_
+
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+#endif
+
+#include "qlparser/qtunaryoperation.hh"
+#include "qlparser/qtmdd.hh"
+#include "qlparser/qtatomicdata.hh"
+
+#include "catalogmgr/ops.hh"
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+This class has just QtNot as subclass which represents the not operations
+{\tt MDD<Bool> -> MDD<Bool>} and {\tt MDD<Int> -> MDD<Int>}.
+
+*/
+
+class QtUnaryInduce : public QtUnaryOperation
+{
+ public:
+ /// constructor getting the operand
+ QtUnaryInduce( QtOperation* input );
+
+ protected:
+ /// computes the unary operation
+ QtData* computeOp( QtData* operand, Ops::OpType operation );
+
+ /// method for testing and evaluating the input branch
+ bool getOperand( QtDataList* inputList, QtData* &operand );
+ /**
+ The method checks if the input branch is valid. Then it passes the evaluate message to its
+ operand with the {\tt inputList} as argument. The returned result is provided through the argument
+ {\tt operand} called by reference. The method returns {\tt true} it the operand is
+ valid, otherwise {\tt false}.
+ */
+
+ /// computes an unary induce operation with one MDD object
+ QtData* computeUnaryMDDOp( QtMDD* operand, const BaseType* resultBaseType, Ops::OpType operation, unsigned int operandOffset = 0 );
+ /**
+ The method carries out the unary induce operation specified by {\tt operation} on the operand. For
+ the result, a new transient MDD object is created and returned. In the end, the MDD object of the operand
+ is freed.
+ */
+
+ /// computes an unary induce operation with one MDD object
+ QtData* computeUnaryOp( QtScalarData* operand, const BaseType* resultBaseType, Ops::OpType operation, unsigned int operandOffset = 0 );
+ /**
+ The method carries out the unary operation specified by {\tt operation} on the operand.
+ */
+
+ private:
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+*/
+
+class QtNot : public QtUnaryInduce
+{
+ public:
+ /// constructor getting the operand
+ QtNot( QtOperation* input );
+
+ /// method for evaluating the node
+ QtData* evaluate( QtDataList* inputList );
+
+ /**
+ The method invokes the evaluate method of its superclass {\tt QtUnaryInduce} with the not
+ operation as an additional argument to compute the result of the node.
+ */
+
+ /// prints the tree
+ virtual void printTree( int tab, std::ostream& s = std::cout, QtChildType mode = QT_ALL_NODES );
+
+ /// prints the algebraic expression
+ virtual void printAlgebraicExpression( std::ostream& s = std::cout );
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ /// type checking of the subtree
+ virtual const QtTypeElement& checkType( QtTypeTuple* typeTuple = NULL );
+
+ private:
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+*/
+
+class QtDot : public QtUnaryInduce
+{
+ public:
+ /// constructor getting operand and element name
+ QtDot( const std::string& elementName );
+
+ /// constructor getting operand and element number
+ QtDot( unsigned int elementNo );
+
+ /// creates a unique name for a common subexpression
+ virtual std::string getSpelling();
+
+ /// tests if the two nodes have an equal meaning in the query tree
+ virtual bool equalMeaning( QtNode* node );
+
+ /// method for evaluating the node
+ QtData* evaluate( QtDataList* inputList );
+ /**
+ The method invokes the evaluate method of its superclass {\tt QtUnaryInduce} with the not
+ operation as an additional argument to compute the result of the node.
+ */
+
+ /// prints the tree
+ virtual void printTree( int tab, std::ostream& s = std::cout, QtChildType mode = QT_ALL_NODES );
+
+ /// prints the algebraic expression
+ virtual void printAlgebraicExpression( std::ostream& s = std::cout );
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ /// type checking of the subtree
+ virtual const QtTypeElement& checkType( QtTypeTuple* typeTuple = NULL );
+
+ private:
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+
+ /// attribute storing selection element name
+ std::string elementName;
+
+ /// attribute storing selection element number
+ int elementNo;
+ /**
+ The number is either positive, which means that the number
+ is valid, or -1 saying that the element name is valid for
+ selection.
+ */
+};
+
+
+//--------------------------------------------
+// QtCast
+//--------------------------------------------
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+QtCast provides type conversions
+*/
+
+class QtCast : public QtUnaryInduce {
+public:
+ enum cast_types {
+ t_bool, t_octet, t_char, t_short, t_ushort,
+ t_long, t_ulong, t_float, t_double
+ };
+
+ QtCast(QtOperation*, cast_types);
+ /// method for evaluating the node
+ QtData* evaluate(QtDataList*);
+ /// prints the tree
+ virtual void printTree(int, std::ostream& = std::cout, QtChildType = QT_ALL_NODES);
+ /// prints the algebraic expression
+ virtual void printAlgebraicExpression(std::ostream& = std::cout);
+ /// retrives node type
+ inline virtual const QtNodeType getNodeType() const;
+ /// semantics check
+ virtual const QtTypeElement& checkType(QtTypeTuple* = NULL );
+
+private:
+ Ops::OpType getOp(cast_types);
+
+ static const QtNodeType nodeType;
+ cast_types castType;
+};
+
+
+//--------------------------------------------
+// QtRealPartOp
+//--------------------------------------------
+
+class QtRealPartOp : public QtUnaryInduce {
+public:
+ QtRealPartOp(QtOperation*);
+ QtData* evaluate(QtDataList*);
+ virtual void printTree(int, std::ostream& = std::cout, QtChildType = QT_ALL_NODES);
+ virtual void printAlgebraicExpression(std::ostream& = std::cout);
+ inline virtual const QtNodeType getNodeType() const;
+ virtual const QtTypeElement& checkType(QtTypeTuple* = NULL);
+
+private:
+ static const QtNodeType nodeType;
+};
+
+//--------------------------------------------
+// QtImaginarPartOp
+//--------------------------------------------
+
+class QtImaginarPartOp : public QtUnaryInduce {
+public:
+ QtImaginarPartOp(QtOperation*);
+ QtData* evaluate(QtDataList*);
+ virtual void printTree(int, std::ostream& = std::cout, QtChildType = QT_ALL_NODES);
+ virtual void printAlgebraicExpression(std::ostream& = std::cout);
+ inline virtual const QtNodeType getNodeType() const;
+ virtual const QtTypeElement& checkType(QtTypeTuple* = NULL);
+
+private:
+ static const QtNodeType nodeType;
+};
+
+#include "autogen_qtui.hh"
+#include "qlparser/qtunaryinduce.icc"
+#include "autogen_qtui.icc"
+
+
+#endif
+
diff --git a/qlparser/qtunaryinduce.icc b/qlparser/qtunaryinduce.icc
new file mode 100644
index 0000000..80691a4
--- /dev/null
+++ b/qlparser/qtunaryinduce.icc
@@ -0,0 +1,84 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+
+inline const QtNode::QtNodeType
+QtNot::getNodeType() const
+{
+ return nodeType;
+}
+
+
+
+inline const QtNode::QtNodeType
+QtDot::getNodeType() const
+{
+ return nodeType;
+}
+
+
+//---- QtCast ----
+
+inline const QtNode::QtNodeType QtCast::getNodeType() const {
+ return nodeType;
+}
+
+inline Ops::OpType QtCast::getOp(QtCast::cast_types t) {
+ Ops::OpType c=Ops::OP_CAST_BOOL;
+ switch(t) {
+ case QtCast::t_bool: c=Ops::OP_CAST_BOOL; break;
+ case QtCast::t_octet: c=Ops::OP_CAST_OCTET; break;
+ case QtCast::t_char: c=Ops::OP_CAST_CHAR; break;
+ case QtCast::t_short: c=Ops::OP_CAST_SHORT; break;
+ case QtCast::t_ushort: c=Ops::OP_CAST_USHORT; break;
+ case QtCast::t_long: c=Ops::OP_CAST_LONG; break;
+ case QtCast::t_ulong: c=Ops::OP_CAST_ULONG; break;
+ case QtCast::t_float: c=Ops::OP_CAST_FLOAT; break;
+ case QtCast::t_double: c=Ops::OP_CAST_DOUBLE; break;
+ default: RMInit::logOut << "Error: QtCast::getOp - undefined cast type." << endl; break;
+ }
+ return c;
+}
+
+
+//---- QtRealPartOp ----
+
+inline const QtNode::QtNodeType QtRealPartOp::getNodeType() const {
+ return nodeType;
+}
+
+//---- QtImaginarPartOp ----
+
+inline const QtNode::QtNodeType QtImaginarPartOp::getNodeType() const {
+ return nodeType;
+}
+
+
+//----------------
+
diff --git a/qlparser/qtunaryoperation.cc b/qlparser/qtunaryoperation.cc
new file mode 100644
index 0000000..e05bb23
--- /dev/null
+++ b/qlparser/qtunaryoperation.cc
@@ -0,0 +1,204 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)qlparser, QtUnaryOperation: $Header: /home/rasdev/CVS-repository/rasdaman/qlparser/qtunaryoperation.cc,v 1.23 2003/12/27 20:51:28 rasdev Exp $";
+
+#include "qlparser/qtunaryoperation.hh"
+#include "qlparser/qtconst.hh"
+
+#include <iostream>
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+using namespace std;
+#endif
+
+QtUnaryOperation::QtUnaryOperation()
+ : QtOperation(),
+ input(NULL)
+{
+}
+
+
+QtUnaryOperation::QtUnaryOperation( QtOperation* inputInit )
+ : QtOperation(),
+ input( inputInit )
+{
+ if( input )
+ input->setParent( this );
+}
+
+
+QtUnaryOperation::~QtUnaryOperation()
+{
+ if( input )
+ {
+ delete input;
+ input=NULL;
+ }
+}
+
+
+
+string
+QtUnaryOperation::getSpelling()
+{
+ char tempStr[20];
+ sprintf(tempStr, "%ud", (unsigned long)getNodeType());
+ string result = string(tempStr);
+ result.append( "(" );
+ result.append( input->getSpelling() );
+ result.append( ")" );
+
+ return result;
+}
+
+
+
+void
+QtUnaryOperation::simplify()
+{
+ RMDBCLASS( "QtUnaryOperation", "simplify()", "qlparser", __FILE__, __LINE__ )
+
+ // In order to work bottom up, first inspect the descendants
+ QtNode::simplify();
+
+ // Test, if operand is available.
+ if( input )
+ {
+ // Test, if operand is of const type.
+ if( input->getNodeType() == QT_CONST )
+ {
+ // evaluate the self node with no input list
+ QtData* newConst = this->evaluate( NULL );
+
+ if( newConst )
+ {
+ // create a new constant node and fill it with newConst
+ QtConst* newNode = new QtConst( newConst );
+
+ // set its data stream type
+ newNode->checkType( NULL );
+
+ // link it to the parent
+ getParent()->setInput( this, newNode );
+
+ // delete the self node and its descendants
+ delete this;
+ }
+ }
+ }
+}
+
+
+
+bool
+QtUnaryOperation::equalMeaning( QtNode* node )
+{
+ RMDBCLASS( "QtUnaryOperation", "equalMeaning( QtNode* )", "qlparser", __FILE__, __LINE__ )
+
+ bool result = false;
+
+ if( getNodeType() == node->getNodeType() )
+ {
+ QtUnaryOperation* unaryNode = (QtUnaryOperation*) node; // by force
+
+ result = input->equalMeaning( unaryNode->getInput() );
+ };
+
+ return ( result );
+}
+
+
+
+QtNode::QtNodeList*
+QtUnaryOperation::getChilds( QtChildType flag )
+{
+ RMDBCLASS( "QtUnaryOperation", "getChilds( QtChildType )", "qlparser", __FILE__, __LINE__ )
+
+ QtNodeList* resultList=NULL;
+
+ if( flag == QT_DIRECT_CHILDS )
+ resultList = new QtNodeList();
+
+ if( flag == QT_LEAF_NODES || flag == QT_ALL_NODES )
+ resultList = input->getChilds( flag );
+
+ if( flag == QT_DIRECT_CHILDS || flag == QT_ALL_NODES )
+ resultList->push_back( input );
+
+ return resultList;
+}
+
+
+QtNode::QtAreaType
+QtUnaryOperation::getAreaType()
+{
+ return( input->getAreaType() );
+}
+
+
+void
+QtUnaryOperation::optimizeLoad( QtTrimList* trimList )
+{
+ RMDBCLASS( "QtUnaryOperation", "optimizeLoad( QtTrimList* )", "qlparser", __FILE__, __LINE__ )
+
+ // by default, pass load domain to the input
+ if( input )
+ input->optimizeLoad( trimList );
+ else
+ {
+ delete trimList;
+ trimList=NULL;
+ }
+}
+
+
+void
+QtUnaryOperation::printTree( int tab, ostream& s, QtChildType mode )
+{
+ if( mode != QtNode::QT_DIRECT_CHILDS )
+ if( input )
+ {
+ s << SPACE_STR(tab).c_str() << "input: " << endl;
+ input->printTree( tab+2, s, mode );
+ }
+ else
+ s << SPACE_STR(tab).c_str() << "no input" << endl;
+}
+
+
+
+
+
+
diff --git a/qlparser/qtunaryoperation.hh b/qlparser/qtunaryoperation.hh
new file mode 100644
index 0000000..e7602b8
--- /dev/null
+++ b/qlparser/qtunaryoperation.hh
@@ -0,0 +1,111 @@
+#ifndef _QTUNARYOPERATION_
+#define _QTUNARYOPERATION_
+
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+#endif
+
+#include <stdio.h>
+
+#include "qlparser/qtoperation.hh"
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/**************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+The class serves as superclass for all operation classes taking one
+argument.
+
+*/
+
+class QtUnaryOperation : public QtOperation
+{
+ public:
+ /// default constructor
+ QtUnaryOperation();
+
+ /// constructor getting the node to its operand
+ QtUnaryOperation( QtOperation* input );
+
+ /// virtual destructor
+ virtual ~QtUnaryOperation();
+
+ /// creates a unique name for a common subexpression
+ virtual std::string getSpelling();
+
+ /// simplifies the tree
+ virtual void simplify();
+
+ /// return childs of the node
+ virtual QtNodeList* getChilds( QtChildType flag );
+
+ /// test if the edge to the parent node is of type mdd or atomic
+ virtual QtAreaType getAreaType();
+
+ /// tests if the two nodes have an equal meaning in the query tree
+ virtual bool equalMeaning( QtNode* node );
+
+ /// method for query rewrite
+ inline virtual void setInput( QtOperation* inputOld, QtOperation* inputNew );
+
+ /// optimizing load access
+ virtual void optimizeLoad( QtTrimList* trimList );
+
+ /**
+ The method passes the given {\tt trimList} list to its input tree.
+ */
+
+ /// debugging method
+ virtual void printTree( int tab, std::ostream& s = std::cout, QtChildType mode = QT_ALL_NODES );
+
+ //@Man: Read/Write methods for the operand
+ //@{
+ ///
+
+ ///
+ inline virtual void setInput( QtOperation* input );
+ ///
+ inline QtOperation* getInput();
+
+ //@}
+
+ protected:
+ /// operation operand
+ QtOperation* input;
+};
+
+#include "qlparser/qtunaryoperation.icc"
+
+#endif
+
diff --git a/qlparser/qtunaryoperation.icc b/qlparser/qtunaryoperation.icc
new file mode 100644
index 0000000..a208cdc
--- /dev/null
+++ b/qlparser/qtunaryoperation.icc
@@ -0,0 +1,59 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+inline void
+QtUnaryOperation::setInput( QtOperation* inputNew )
+{
+ input = inputNew;
+
+ if( inputNew )
+ inputNew->setParent( this );
+};
+
+
+inline void
+QtUnaryOperation::setInput( QtOperation* inputOld, QtOperation* inputNew )
+{
+ if( input == inputOld )
+ {
+ input = inputNew;
+
+ if( inputNew )
+ inputNew->setParent( this );
+ }
+};
+
+
+inline QtOperation*
+QtUnaryOperation::getInput()
+{
+ return input;
+};
+
+
diff --git a/qlparser/qtupdate.cc b/qlparser/qtupdate.cc
new file mode 100644
index 0000000..a5ca731
--- /dev/null
+++ b/qlparser/qtupdate.cc
@@ -0,0 +1,812 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)qlparser, QtUpdate: $Header: /home/rasdev/CVS-repository/rasdaman/qlparser/qtupdate.cc,v 1.28 2003/12/27 20:51:28 rasdev Exp $";
+
+#include "raslib/dlist.hh"
+
+#include "qlparser/qtupdate.hh"
+#include "qlparser/qtdata.hh"
+#include "qlparser/qtmdd.hh"
+#include "qlparser/qtmintervaldata.hh"
+
+#include "tilemgr/tile.hh"
+#include "tilemgr/tiler.hh"
+
+#include "mddmgr/mddobj.hh"
+
+#include <iostream>
+#include <memory>
+
+
+const QtNode::QtNodeType QtUpdate::nodeType = QtNode::QT_UPDATE;
+
+
+
+QtUpdate::QtUpdate( QtOperation* initUpdateTarget, QtOperation* initUpdateDomain, QtOperation* initUpdateSource )
+ : QtExecute(), input(NULL),
+ updateTarget( initUpdateTarget ),
+ updateDomain( initUpdateDomain ),
+ updateSource( initUpdateSource )
+{
+ if( updateTarget ) updateTarget->setParent( this );
+ if( updateDomain ) updateDomain->setParent( this );
+ if( updateSource ) updateSource->setParent( this );
+}
+
+
+
+QtUpdate::~QtUpdate()
+{
+ if( updateTarget )
+ {
+ delete updateTarget;
+ updateTarget=NULL;
+ }
+
+ if( updateDomain )
+ {
+ delete updateDomain;
+ updateDomain=NULL;
+ }
+
+ if( updateSource )
+ {
+ delete updateSource;
+ updateSource=NULL;
+ }
+
+ if( input )
+ {
+ delete input;
+ input=NULL;
+ }
+}
+
+
+
+int
+QtUpdate::evaluate()
+{
+ RMDBCLASS( "QtUpdate", "evaluate()", "qlparser", __FILE__, __LINE__ )
+
+ // Test, if all necessary operands are available.
+ if( updateTarget && updateSource && input )
+ {
+ QtNode::QtDataList* nextTupel;
+
+ // open input stream
+ try
+ {
+ input->open();
+ }
+ catch( ... )
+ {
+ input->close();
+ throw;
+ }
+
+ try
+ {
+ while( (nextTupel = input->next()) )
+ {
+ // get obligatory operands
+ QtData* target = updateTarget->evaluate( nextTupel );
+ QtData* source = updateSource->evaluate( nextTupel );
+
+ // Test, if the operands are valid.
+ if( target && source )
+ {
+ // check update target
+ if( target->getDataType() != QT_MDD )
+ {
+ RMInit::logOut << "Error: QtUpdate::evaluate() - update target must be an iterator variable." << endl;
+
+ // delete tupel vector received by next()
+ for( vector<QtData*>::iterator dataIter=nextTupel->begin();
+ dataIter!=nextTupel->end(); dataIter++ )
+ if( *dataIter ) (*dataIter)->deleteRef();
+ delete nextTupel;
+ nextTupel=NULL;
+
+ // delete the operands
+ if( target ) target->deleteRef();
+ if( source ) source->deleteRef();
+
+ parseInfo.setErrorNo(950);
+ throw parseInfo;
+ }
+
+ // check update source
+ if( source->getDataType() != QT_MDD )
+ {
+ RMInit::logOut << "Error: QtUpdate::evaluate() - update source must be an expression resulting in an MDD" << endl;
+
+ // delete tupel vector received by next()
+ for( vector<QtData*>::iterator dataIter=nextTupel->begin();
+ dataIter!=nextTupel->end(); dataIter++ )
+ if( *dataIter ) (*dataIter)->deleteRef();
+ delete nextTupel;
+ nextTupel=NULL;
+
+ // delete the operands
+ if( target ) target->deleteRef();
+ if( source ) source->deleteRef();
+
+ parseInfo.setErrorNo(951);
+ throw parseInfo;
+ }
+
+ QtMDD* targetMDD = (QtMDD*) target;
+ QtMDD* sourceMDD = (QtMDD*) source;
+
+ MDDObj* targetObj = targetMDD->getMDDObject();
+ MDDObj* sourceObj = sourceMDD->getMDDObject();
+
+ // test, if target is a persistent object
+ if( !targetObj->isPersistent() )
+ {
+ RMInit::logOut << "Error: QtUpdate::evaluate() - result of target expression must be an assignable value (l-value)." << endl;
+
+ // delete tupel vector received by next()
+ for( vector<QtData*>::iterator dataIter=nextTupel->begin();
+ dataIter!=nextTupel->end(); dataIter++ )
+ if( *dataIter ) (*dataIter)->deleteRef();
+ delete nextTupel;
+ nextTupel=NULL;
+
+ // delete the operands
+ if( target ) target->deleteRef();
+ if( source ) source->deleteRef();
+
+ parseInfo.setErrorNo(954);
+ throw parseInfo;
+ }
+
+ // get optional domain
+ QtData* domainData = NULL;
+ r_Minterval domain;
+
+ if( updateDomain )
+ {
+ domainData = updateDomain->evaluate( nextTupel );
+
+ if( domainData )
+ domain = ((QtMintervalData*)domainData)->getMintervalData();
+ }
+
+ RMDBGIF( 1, RMDebug::module_qlparser, "QtUpdate", \
+ if( domainData ) \
+ RMInit::dbgOut << endl << " target MDD, domain " << domain << endl; \
+ else \
+ RMInit::dbgOut << endl << " target MDD" << endl; \
+
+ targetMDD->printStatus( RMInit::dbgOut ); \
+ RMInit::dbgOut << endl << " source MDD" << endl; \
+ sourceMDD->printStatus( RMInit::dbgOut ); \
+ RMInit::dbgOut << endl; \
+ )
+
+ // 1st update strategy:
+ //
+ // 1. All cell values of the source domain which are already defined are
+ // updated with the corresponding new values.
+ // 2. If a source tile does not intersect with any tile of the target
+ // object, it is inserted.
+
+ // In case of update domain existence, test for compatibility.
+ if( domainData )
+ {
+ // Dimensionality of the udate domain specification has to be equal to
+ // the target MDD dimensionality.
+ if( domain.dimension() != targetMDD->getLoadDomain().dimension() )
+ {
+ RMInit::logOut << "Error: QtUpdate::evaluate() - Update domain dimensionality must match target MDD dimensionaltiy." << endl;
+
+ // delete tupel vector received by next()
+ for( vector<QtData*>::iterator dataIter=nextTupel->begin();
+ dataIter!=nextTupel->end(); dataIter++ )
+ if( *dataIter ) (*dataIter)->deleteRef();
+ delete nextTupel;
+ nextTupel=NULL;
+
+ // delete the operands
+ if( target ) target->deleteRef();
+ if( domainData ) domainData->deleteRef();
+ if( source ) source->deleteRef();
+
+ parseInfo.setErrorNo(963);
+ throw parseInfo;
+ }
+
+ // The number of interval dimension of the update domain has to be
+ // equal to the number of dimensions of the source domain.
+ int updateIntervals = 0;
+
+ const vector<bool>* trimFlags = ((QtMintervalData*)domainData)->getTrimFlags();
+ for( int i=0; i<trimFlags->size(); i++ )
+ if( (*trimFlags)[i] )
+ updateIntervals++;
+
+ if( updateIntervals != sourceMDD->getLoadDomain().dimension() )
+ {
+ RMInit::logOut << "Error: QtUpdate::evaluate() - Number of update intervals must match source dimensionality." << endl;
+
+ // delete tupel vector received by next()
+ for( vector<QtData*>::iterator dataIter=nextTupel->begin();
+ dataIter!=nextTupel->end(); dataIter++ )
+ if( *dataIter ) (*dataIter)->deleteRef();
+ delete nextTupel;
+ nextTupel=NULL;
+
+ // delete the operands
+ if( target ) target->deleteRef();
+ if( domainData ) domainData->deleteRef();
+ if( source ) source->deleteRef();
+
+ parseInfo.setErrorNo(962);
+ throw parseInfo;
+ }
+
+ // Warning: Fixed bounds in update domain specifications are ignored.
+ }
+
+ r_Minterval sourceMDDDomain( sourceMDD->getLoadDomain() );
+ RMDBGMIDDLE( 2, RMDebug::module_qlparser, "QtUpdate", "source mdd domain " << sourceMDDDomain )
+
+ // compute source MDD domain taking into account update domain
+ if( domainData )
+ {
+ const vector<bool>* trimFlags = ((QtMintervalData*)domainData)->getTrimFlags();
+ r_Minterval newSourceMDDDomain( targetMDD->getLoadDomain().dimension() );
+
+ for( int i=0, j=0; i<trimFlags->size(); i++ )
+ if( (*trimFlags)[i] )
+ newSourceMDDDomain << sourceMDDDomain[j++];
+ else
+ newSourceMDDDomain << domain[i];
+
+ sourceMDDDomain = newSourceMDDDomain;
+
+ RMDBGMIDDLE( 2, RMDebug::module_qlparser, "QtUpdate", "source update domain " << sourceMDDDomain )
+ }
+ // check if you may update that are ( you should not go out of bounds for mdddomaintype )
+ if (!targetObj->getMDDBaseType()->compatibleWithDomain(&sourceMDDDomain))
+ {
+ RMInit::logOut << "Error: QtUpdate::evaluate() - The update domain is outside the allowed domain of the target mdd." << endl;
+
+ // delete tupel vector received by next()
+ for( vector<QtData*>::iterator dataIter=nextTupel->begin();
+ dataIter!=nextTupel->end(); dataIter++ )
+ if( *dataIter ) (*dataIter)->deleteRef();
+ delete nextTupel;
+ nextTupel=NULL;
+
+ // delete the operands
+ if( target ) target->deleteRef();
+ if( domainData ) domainData->deleteRef();
+ if( source ) source->deleteRef();
+
+ parseInfo.setErrorNo(953);
+ throw parseInfo;
+
+ }
+ //
+ // get all source tiles
+ //
+ vector<Tile*>* sourceTiles = sourceObj->getTiles();
+RMDBGIF(1, RMDebug::module_qlparser, "QtUpdate", \
+ if (sourceTiles) \
+ RMDBGMIDDLE(1, RMDebug::module_qlparser, "QtUpdate", "there are " << sourceTiles->size() << " source tiles") \
+ else \
+ RMDBGMIDDLE(1, RMDebug::module_qlparser, "QtUpdate", "there are no source tiles") )
+
+ //
+ // get all target tiles in the relevant area
+ //
+
+ vector<Tile*>* targetTiles = NULL;
+//this is not a very good idea
+// try{
+ targetTiles = targetObj->intersect( sourceMDDDomain );
+/* }
+ catch(...)
+ {
+ RMInit::logOut << "BUG of MDDObj::intersect" << endl;
+ targetTiles = new vector<Tile*>;
+ }
+*/
+ if( !targetTiles )
+ {
+ targetTiles = new vector<Tile*>;
+ RMDBGMIDDLE(1, RMDebug::module_qlparser, "QtUpdate", "found no target tiles")
+ }
+ else {
+ RMDBGMIDDLE(1, RMDebug::module_qlparser, "QtUpdate", "found " << targetTiles->size() << " target tiles in mdd")
+ }
+
+ //
+ // iterate over source tiles
+ //
+ unsigned long targetTileArea = 0;
+ unsigned long sourceTileArea = 0;
+ unsigned long targetTileDomain = 0;
+ unsigned long updatedArea = 0;
+ bool computed = false;
+ vector<r_Minterval> insertedDomains;
+ vector<r_Minterval> sourceDomains;
+ vector<r_Minterval> targetDomains;
+ vector<r_Minterval>::iterator domIt;
+ vector<r_Minterval>::iterator intervalIt;
+ vector<Tile*> retval;
+ vector<Tile*>::iterator retvalIt;
+ vector<Tile*>::iterator sourceIt;
+ vector<Tile*>::iterator targetIt;
+ sourceIt = sourceTiles->begin();
+ //this lives here because we don't want memory leaks because of exceptions
+ //of course we seldom use this operation ( as we use copy tile most of the time )
+
+ UnaryOp* tempOp = NULL;
+ if (sourceIt != sourceTiles->end())
+ tempOp = Ops::getUnaryOp(Ops::OP_IDENTITY, targetObj->getCellType(), (*sourceIt)->getType(), 0, 0);
+ std::auto_ptr<UnaryOp> myOp(tempOp);
+ for( ; sourceIt != sourceTiles->end(); sourceIt++ )
+ {
+ // calculate relevant area of source tile
+ r_Minterval sourceTileDomain = (*sourceIt)->getDomain().create_intersection( sourceMDD->getLoadDomain() );
+
+ RMDBGMIDDLE( 2, RMDebug::module_qlparser, "QtUpdate", "original source tile domain " << sourceTileDomain )
+
+ // compute update source tile domain taking into account update domain
+ r_Minterval updateSourceTileDomain;
+
+ if( domainData )
+ {
+ updateSourceTileDomain = r_Minterval( targetMDD->getLoadDomain().dimension() );
+ const vector<bool>* trimFlags = ((QtMintervalData*)domainData)->getTrimFlags();
+
+ for( int i=0, j=0; i<trimFlags->size(); i++ )
+ if( (*trimFlags)[i] )
+ updateSourceTileDomain << sourceTileDomain[j++];
+ else
+ updateSourceTileDomain << domain[i];
+ }
+ else
+ updateSourceTileDomain = sourceTileDomain;
+
+ //calculate number of cells in this area
+ sourceTileArea = sourceTileArea + sourceTileDomain.cell_count();
+ RMDBGMIDDLE( 2, RMDebug::module_qlparser, "QtUpdate", "update source tile domain " << updateSourceTileDomain )
+
+ bool intersection = false;
+
+ for( targetIt = targetTiles->begin(); targetIt != targetTiles->end(); targetIt++ )
+ {
+ RMDBGMIDDLE( 2, RMDebug::module_qlparser, "QtUpdate", "target tile domain " << (*targetIt)->getDomain())
+ if (!computed)
+ {
+ targetTileArea = targetTileArea + sourceMDDDomain.create_intersection((*targetIt)->getDomain()).cell_count();
+ RMDBGMIDDLE( 2, RMDebug::module_qlparser, "QtUpdate", "target area sum " << targetTileArea)
+ }
+ // if tiles are intersecting
+ if( updateSourceTileDomain.intersects_with( (*targetIt)->getDomain() ) )
+ {
+ RMDBGMIDDLE( 2, RMDebug::module_qlparser, "QtUpdate", "source tile domain " << updateSourceTileDomain << " intersects with target domain " << (*targetIt)->getDomain())
+ intersection = true;
+
+ // get intersecting updateSourceTileDomain
+ r_Minterval intersectUpdateSourceTileDomain = updateSourceTileDomain.create_intersection( (*targetIt)->getDomain() );
+
+ // compute corresponding sourceTileDomain
+ r_Minterval intersectSourceTileDomain = intersectUpdateSourceTileDomain;
+ if( domainData )
+ {
+ const vector<bool>* trimFlags = ((QtMintervalData*)domainData)->getTrimFlags();
+
+ for( int i=0, j=0; i<trimFlags->size(); i++ )
+ if( !((*trimFlags)[i]) )
+ intersectSourceTileDomain.delete_dimension( j );
+ else
+ j++;
+ }
+
+ RMDBGMIDDLE( 2, RMDebug::module_qlparser, "QtUpdate", "update domains: target tile " << (*targetIt)->getDomain() << " update target at " << intersectUpdateSourceTileDomain << ", source tile " << (*sourceIt)->getDomain() << " update with data at " << intersectSourceTileDomain )
+ //(*targetIt)->execUnaryOp( Ops::OP_IDENTITY, intersectUpdateSourceTileDomain, *sourceIt, intersectSourceTileDomain );
+ (*targetIt)->copyTile(intersectUpdateSourceTileDomain, *sourceIt, intersectSourceTileDomain);
+ updatedArea = updatedArea + intersectUpdateSourceTileDomain.cell_count();
+ }
+ }
+ computed = true;
+ // insert the tile
+ if (!intersection)
+ {
+ // Create a new persistent tile, copy the transient data,
+ // and insert it into the target mdd object.
+ Tile* newPersTile = new Tile(updateSourceTileDomain, targetObj->getCellType(), (*sourceIt)->getDataFormat());
+ if (updateSourceTileDomain.dimension() == sourceTileDomain.dimension())
+ newPersTile->copyTile( updateSourceTileDomain, *sourceIt, sourceTileDomain );
+ else
+ newPersTile->execUnaryOp( &(*myOp), updateSourceTileDomain, *sourceIt, sourceTileDomain );
+ RMDBGMIDDLE( 2, RMDebug::module_qlparser, "QtUpdate", "update domains: target tile " << newPersTile->getDomain() << " update target at " << updateSourceTileDomain << ", source tile " << (*sourceIt)->getDomain() << " update with data at " << sourceTileDomain )
+ // this will make a crash in updateset3 because of a strange triming doman
+ //newPersTile->copyTile(updateSourceTileDomain, *sourceIt, sourceTileDomain);
+
+ targetObj->insertTile( newPersTile );
+ updatedArea = updatedArea + updateSourceTileDomain.cell_count();
+ insertedDomains.push_back((*sourceIt)->getDomain());
+ }
+ }//for is done
+
+ if (sourceTileArea > updatedArea)
+ {
+ RMDBGMIDDLE( 2, RMDebug::module_qlparser, "QtUpdate", "the source area was not updated completely, tiling the rest")
+ while (!insertedDomains.empty())
+ {
+ intervalIt = insertedDomains.begin();
+ for (sourceIt = sourceTiles->begin(); sourceIt != sourceTiles->end(); sourceIt++)
+ if ((*sourceIt)->getDomain() == *intervalIt)
+ {
+ sourceTiles->erase(sourceIt);
+ break;
+ }
+ insertedDomains.erase(intervalIt);
+ }
+ for (sourceIt = sourceTiles->begin(); sourceIt != sourceTiles->end(); sourceIt++)
+ sourceDomains.push_back((*sourceIt)->getDomain());
+ for (targetIt = targetTiles->begin(); targetIt != targetTiles->end(); targetIt++)
+ targetDomains.push_back((*targetIt)->getDomain());
+ r_Tiler t(sourceDomains, targetDomains);
+ t.split();
+ t.removeDoubleDomains();
+ t.removeCoveredDomains();
+ t.mergeDomains();
+ retval = t.generateTiles(*sourceTiles);
+ for (retvalIt = retval.begin(); retvalIt != retval.end(); retvalIt++)
+ {
+ targetObj->insertTile((Tile*)(*retvalIt));
+ }
+ RMDBGMIDDLE( 2, RMDebug::module_qlparser, "QtUpdate", "insertion of the rest is done")
+ }
+
+ // delete tile vectors
+ delete sourceTiles;
+ sourceTiles=NULL;
+ delete targetTiles;
+ targetTiles=NULL;
+
+ // delete optional operand
+ if( domainData ) domainData->deleteRef();
+ }
+ else
+ RMInit::logOut << "Error: QtUpdate::evaluate() - target or source is not provided." << endl;
+
+ // delete the operands
+ if( target ) target->deleteRef();
+ if( source ) source->deleteRef();
+
+ // delete tupel vector received by next()
+ for( vector<QtData*>::iterator dataIter=nextTupel->begin();
+ dataIter!=nextTupel->end(); dataIter++ )
+ if( *dataIter ) (*dataIter)->deleteRef();
+ delete nextTupel;
+ nextTupel=NULL;
+
+ } // while
+
+ }
+ catch( ... )
+ {
+ input->close();
+ throw;
+ }
+
+ input->close();
+ }
+ else
+ RMInit::logOut << "Error: QtUpdate::evaluate() - at least one operand branch is invalid." << endl;
+
+ return 0;
+}
+
+
+
+QtNode::QtNodeList*
+QtUpdate::getChilds( QtChildType flag )
+{
+ RMDBCLASS( "QtUpdate", "getChilds( QtChildType flag )", "qlparser", __FILE__, __LINE__ )
+
+ QtNodeList* resultList=NULL;
+
+ // allocate resultList
+ resultList = new QtNodeList();
+
+ if( flag == QT_LEAF_NODES || flag == QT_ALL_NODES )
+ {
+ if( input )
+ {
+ QtNodeList* subList = input->getChilds( flag );
+
+ // remove all elements in subList and insert them at the beginning in resultList
+ resultList->splice( resultList->begin(), *subList );
+
+ // delete temporary subList
+ delete subList;
+ subList=NULL;
+ }
+
+ if( updateTarget )
+ {
+ QtNodeList* subList = updateTarget->getChilds( flag );
+
+ // remove all elements in subList and insert them at the beginning in resultList
+ resultList->splice( resultList->begin(), *subList );
+
+ // delete temporary subList
+ delete subList;
+ subList=NULL;
+ }
+
+ if( updateDomain )
+ {
+ QtNodeList* subList = updateDomain->getChilds( flag );
+
+ // remove all elements in subList and insert them at the beginning in resultList
+ resultList->splice( resultList->begin(), *subList );
+
+ // delete temporary subList
+ delete subList;
+ subList=NULL;
+ }
+
+ if( updateSource )
+ {
+ QtNodeList* subList = updateSource->getChilds( flag );
+
+ // remove all elements in subList and insert them at the beginning in resultList
+ resultList->splice( resultList->begin(), *subList );
+
+ // delete temporary subList
+ delete subList;
+ subList=NULL;
+ }
+ };
+
+ // add the nodes of the current level
+ if( flag == QT_DIRECT_CHILDS || flag == QT_ALL_NODES )
+ {
+ resultList->push_back( input );
+ resultList->push_back( updateTarget );
+ resultList->push_back( updateDomain );
+ resultList->push_back( updateSource );
+ }
+
+ return resultList;
+}
+
+
+
+void
+QtUpdate::printTree( int tab, ostream& s, QtChildType mode )
+{
+ s << SPACE_STR(tab).c_str() << "QtUpdate Object" << endl;
+
+ if( mode != QtNode::QT_DIRECT_CHILDS )
+ {
+ if( updateTarget )
+ {
+ s << SPACE_STR(tab).c_str() << "target: " << endl;
+ updateTarget->printTree( tab + 2, s );
+
+ if( updateDomain )
+ {
+ s << SPACE_STR(tab+2).c_str() << "domain: " << endl;
+ updateDomain->printTree( tab + 4, s );
+ }
+ else
+ s << SPACE_STR(tab+2).c_str() << "no domain" << endl;
+ }
+ else
+ s << SPACE_STR(tab).c_str() << "no target" << endl;
+
+ if( updateSource )
+ {
+ s << SPACE_STR(tab).c_str() << "source: " << endl;
+ updateSource->printTree( tab + 2, s );
+ }
+ else
+ s << SPACE_STR(tab).c_str() << "no source" << endl;
+
+ if( input )
+ {
+ s << SPACE_STR(tab).c_str() << "input: " << endl;
+ input->printTree( tab+2, s, mode );
+ }
+ else
+ s << SPACE_STR(tab).c_str() << "no input" << endl;
+
+ s << endl;
+ }
+}
+
+
+
+void
+QtUpdate::printAlgebraicExpression( ostream& s )
+{
+ s << "update<" << std::flush;
+
+ if( updateTarget )
+ updateTarget->printAlgebraicExpression( s );
+ else
+ s << "<no target>";
+
+ if( updateDomain )
+ updateDomain->printAlgebraicExpression( s );
+
+ s << "," << std::flush;
+
+ if( updateSource )
+ updateSource->printAlgebraicExpression( s );
+ else
+ s << "<no source>";
+
+ s << ">" << std::flush;
+
+ if( input )
+ {
+ s << "( ";
+ input->printAlgebraicExpression( s );
+ s << " )";
+ }
+ else
+ s << "(<no input>)" << std::flush;
+}
+
+
+
+void
+QtUpdate::setStreamInput( QtONCStream* newInput )
+{
+ input = newInput;
+ input->setParent( this );
+};
+
+QtOperation*
+QtUpdate::getUpdateTarget()
+{
+ return updateTarget;
+}
+
+QtOperation*
+QtUpdate::getUpdateDomain()
+{
+ return updateDomain;
+}
+
+QtOperation*
+QtUpdate::getUpdateSource()
+{
+ return updateSource;
+}
+
+QtONCStream*
+QtUpdate::getInput()
+{
+ return input;
+}
+
+/*
+void
+QtUpdate::preOptimize()
+{
+ if( updateTarget )
+ updateTarget->optimizeLoad( new QtNode::QtTrimList );
+
+ if( updateDomain )
+ updateDomain->optimizeLoad( new QtNode::QtTrimList );
+
+ if( updateSource )
+ updateSource->optimizeLoad( new QtNode::QtTrimList );
+
+ if( input )
+ input->preOptimize();
+}
+*/
+
+
+void
+QtUpdate::checkType()
+{
+ RMDBCLASS( "QtUpdate", "checkType()", "qlparser", __FILE__, __LINE__ )
+
+ // check operand branches
+ if( updateTarget && updateSource && input )
+ {
+
+ // get input type
+ QtTypeTuple inputType = input->checkType();
+
+ // check target
+ const QtTypeElement& targetType = updateTarget->checkType( &inputType );
+ if( targetType.getDataType() != QT_MDD )
+ {
+ RMInit::logOut << "Error: QtUpdate::checkType() - update target must be an iterator variable." << endl;
+ parseInfo.setErrorNo(950);
+ throw parseInfo;
+ }
+
+ // check domain
+ if( updateDomain )
+ {
+ const QtTypeElement& domainType = updateDomain->checkType( &inputType );
+ if( domainType.getDataType() != QT_MINTERVAL )
+ {
+ RMInit::logOut << "Error: QtUpdate::checkType() - update domain must be of type Minterval." << endl;
+ parseInfo.setErrorNo(961);
+ throw parseInfo;
+ }
+ }
+
+ // check source
+ const QtTypeElement& sourceType = updateSource->checkType( &inputType );
+ if( sourceType.getDataType() != QT_MDD )
+ {
+ RMInit::logOut << "Error: QtUpdate::checkType() - update source must be an expression resulting in an MDD." << endl;
+ parseInfo.setErrorNo(951);
+ throw parseInfo;
+ }
+
+ // test for compatible base types
+ bool compatible = false;
+ char* type1 = ((MDDBaseType*)(targetType.getType()))->getBaseType()->getTypeStructure();
+ char* type2 = ((MDDBaseType*)(sourceType.getType()))->getBaseType()->getTypeStructure();
+ compatible = (strcmp(type1, type2) == 0);
+ free(type1);
+ free(type2);
+ type1 = NULL;
+ type2 = NULL;
+
+ if( !compatible )
+ {
+ RMInit::logOut << "Error: QtUpdate::checkType() - update base type does not match mdd base type." << endl;
+ parseInfo.setErrorNo(952);
+ throw parseInfo;
+ }
+ }
+ else
+ RMInit::logOut << "Error: QtUpdate::checkType() - operand branch invalid." << endl;
+}
+
+
+
+
+
diff --git a/qlparser/qtupdate.hh b/qlparser/qtupdate.hh
new file mode 100644
index 0000000..429a6e2
--- /dev/null
+++ b/qlparser/qtupdate.hh
@@ -0,0 +1,119 @@
+#ifndef __QTUPDATE_HH__
+#define __QTUPDATE_HH___
+
+#include "qlparser/qtexecute.hh"
+#include "qlparser/qtoncstream.hh"
+#include "qlparser/qtoperation.hh"
+
+#include <iostream>
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+*/
+
+class QtUpdate : public QtExecute
+{
+ public:
+ /// constructor getting target, domain, and source expressions of the update
+ QtUpdate( QtOperation* initUpdateTarget, QtOperation* initUpdateDomain, QtOperation* initUpdateSource );
+
+ /// virtual destructor
+ virtual ~QtUpdate();
+
+ /// method for evaluating the node
+ virtual int evaluate();
+
+ /// return childs of the node
+ virtual QtNodeList* getChilds( QtChildType flag );
+
+ /// prints the tree
+ virtual void printTree( int tab, std::ostream& s = std::cout, QtChildType mode = QT_ALL_NODES );
+
+ /// prints the algebraic expression
+ virtual void printAlgebraicExpression( std::ostream& s = std::cout );
+
+ //@Man: Read/Write methods:
+ //@{
+ ///
+ ///
+ void setStreamInput( QtONCStream* newInput );
+ ///
+ /// returns updateTarget
+ QtOperation* getUpdateTarget();
+ /// returns updateDomain
+ QtOperation* getUpdateDomain();
+ ///returns updateSource
+ QtOperation* getUpdateSource();
+ ///returns input
+ QtONCStream* getInput();
+ //@}
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ /// method for query rewrite
+ inline virtual void setInput( QtOperation* child, QtOperation* input);
+
+ /// pre optimization
+ //virtual void preOptimize();
+ /**
+ Pre-Optimization step is passed to the input streams.
+ */
+
+ /// type checking
+ virtual void checkType();
+
+ private:
+ /// one input stream
+ QtONCStream* input;
+
+ /// target expression
+ QtOperation* updateTarget;
+
+ /// target domain expression
+ QtOperation* updateDomain;
+
+ /// target expression
+ QtOperation* updateSource;
+
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+#include "qlparser/qtupdate.icc"
+
+#endif
+
+
+
diff --git a/qlparser/qtupdate.icc b/qlparser/qtupdate.icc
new file mode 100644
index 0000000..5b98b0e
--- /dev/null
+++ b/qlparser/qtupdate.icc
@@ -0,0 +1,65 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+inline const QtNode::QtNodeType
+QtUpdate::getNodeType() const
+{
+ return nodeType;
+}
+
+
+inline void
+QtUpdate::setInput( QtOperation* inputOld, QtOperation* inputNew )
+{
+ if( inputOld == updateTarget )
+ {
+ updateTarget = inputNew;
+
+ if( inputNew )
+ inputNew->setParent( this );
+ }
+
+ if( inputOld == updateDomain )
+ {
+ updateDomain = inputNew;
+
+ if( inputNew )
+ inputNew->setParent( this );
+ }
+
+ if( inputOld == updateSource )
+ {
+ updateSource = inputNew;
+
+ if( inputNew )
+ inputNew->setParent( this );
+ }
+};
+
+
diff --git a/qlparser/qtvariable.cc b/qlparser/qtvariable.cc
new file mode 100644
index 0000000..730ad16
--- /dev/null
+++ b/qlparser/qtvariable.cc
@@ -0,0 +1,392 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)qlparser, QtVariable: $Header: /home/rasdev/CVS-repository/rasdaman/qlparser/qtvariable.cc,v 1.24 2003/12/27 20:40:52 rasdev Exp $";
+
+#include <iostream>
+#include <sstream>
+#include <vector>
+using namespace std;
+
+#include "raslib/rmdebug.hh"
+
+#include "qlparser/qtvariable.hh"
+#include "qlparser/qtmdd.hh"
+
+#include "mddmgr/mddobj.hh"
+
+
+const QtNode::QtNodeType QtVariable::nodeType = QT_MDD_VAR;
+
+
+QtVariable::QtVariable( const string& initName )
+ : iteratorName( initName ),
+ loadDomain(),
+ oldLoadDomain(),
+ dataIndex(-1)
+{
+ domainFlag = new vector<bool>();
+}
+
+
+QtVariable::QtVariable( const string& initName, const r_Minterval& initDomain )
+ : iteratorName( initName ),
+ loadDomain( initDomain ),
+ oldLoadDomain(),
+ dataIndex(-1)
+{
+ domainFlag = new vector<bool>();
+}
+
+
+QtVariable::~QtVariable()
+{
+ // delete STL vector including its elements
+ delete domainFlag;
+ domainFlag=NULL;
+}
+
+
+bool
+QtVariable::equalMeaning( QtNode* node )
+{
+ RMDBCLASS( "QtVariable", "equalMeaning( QtNode* )", "qlparser", __FILE__, __LINE__ )
+
+ bool result = false;
+
+ if( nodeType == node->getNodeType() )
+ {
+ QtVariable* mddVarNode;
+
+ mddVarNode = (QtVariable*) node; // by force
+
+ if( iteratorName.compare ( mddVarNode->getIteratorName()) == 0 )
+ if( ( loadDomain.dimension() == 0 ) ||
+ ( (mddVarNode->getLoadDomain()).dimension() == 0 ) )
+ result = true;
+ else
+ if( loadDomain.dimension() == (mddVarNode->getLoadDomain()).dimension() )
+ result = loadDomain.intersects_with( mddVarNode->getLoadDomain() );
+ };
+
+ // equalMeaning() depends only on the loadDomain and not on the domainFlag!
+
+ return result;
+}
+
+
+string
+QtVariable::getSpelling()
+{
+ r_Point point;
+ r_Dimension d;
+
+ char tempStr[20];
+ ostringstream os;
+ sprintf(tempStr, "%ud", (unsigned long)getNodeType());
+ string result = string(tempStr);
+
+ result.append( iteratorName );
+
+ if( loadDomain.dimension() > 0)
+ {
+ os << loadDomain << ends;
+ result.append(os.str());
+ };
+
+ return result;
+}
+
+
+QtNode::QtAreaType
+QtVariable::getAreaType()
+{
+ return QT_AREA_MDD;
+}
+
+
+void
+QtVariable::optimizeLoad( QtTrimList* trimList )
+{
+ RMDBCLASS( "QtVariable", "optimizeLoad( QtTrimList* )", "qlparser", __FILE__, __LINE__ )
+
+ if( !trimList->empty() )
+ {
+ // get the highest specified dimension
+ r_Dimension maxDimension=0;
+ QtTrimList::iterator i;
+
+ for( i=trimList->begin(); i!=trimList->end(); i++ )
+ // get the maximum
+ maxDimension = maxDimension > (*i)->dimension ? maxDimension : (*i)->dimension;
+
+ // create a new loadDomain object and initialize it with open bounds
+ loadDomain = r_Minterval(maxDimension+1);
+
+ delete domainFlag; // delete the old array
+ domainFlag = new vector<bool>(maxDimension+1);
+
+ for( int j=0; j<loadDomain.dimension(); j++ )
+ {
+ loadDomain[j] = r_Sinterval('*','*');
+ (*domainFlag)[j] = true;
+ }
+
+ // fill the loadDomain object with the QtTrimList specifications
+ for( i=trimList->begin(); i!=trimList->end(); i++ )
+ {
+ loadDomain[(*i)->dimension] = (*i)->interval;
+ (*domainFlag)[(*i)->dimension] = (*i)->intervalFlag;
+ }
+
+ // delete heap based elements
+ // release( trimList->begin(), trimList->end() );
+ for( QtNode::QtTrimList::iterator iter=trimList->begin(); iter!=trimList->end(); iter++ )
+ {
+ delete *iter;
+ *iter=NULL;
+ }
+
+ // changed from RMInit:logOut -- PB 2003-nov-20
+ RMDBGMIDDLE( 1, RMDebug::module_qlparser, "QtVariable", "optimizeLoad: geometric load optimization: " << iteratorName << loadDomain );
+ }
+
+ // delete list
+ delete trimList;
+ trimList=NULL;
+}
+
+
+
+QtData*
+QtVariable::evaluate( QtDataList* inputList ) throw (ParseInfo)
+{
+ RMDBCLASS( "QtVariable", "evaluate( QtDataList* )", "qlparser", __FILE__, __LINE__ )
+
+ RMDBGENTER( 2, RMDebug::module_qlparser, "QtVariable", "QtVariable::evaluate() - " << iteratorName.c_str() << endl )
+
+ vector<QtData*>::iterator i; //default
+
+ QtData* returnValue = NULL;
+
+ if( inputList /* && inputList->size() > dataIndex*/ )
+ {
+ QtData* dataObject = 0;
+
+ if( dataIndex == -1 )
+ {
+ // Search for the data object matching the iterator name
+ int pos = 0;
+
+ for( QtDataList::iterator iter=inputList->begin(); iter!=inputList->end() && !dataObject; iter++ )
+ {
+ if( iteratorName == (*iter)->getIteratorName() )
+ dataObject = *iter;
+ else
+ pos++;
+ }
+
+ if( dataObject ) dataIndex = pos;
+ }
+ else
+ // For performance reasons, take the data element from position determined in the first run.
+ dataObject = (*inputList)[dataIndex];
+
+ if( !dataObject )
+ {
+ RMInit::logOut << "Error: QtVariable::evaluate() - collection iterator " <<
+ iteratorName.c_str() << " is unknwon." << endl;
+ parseInfo.setErrorNo(357);
+ throw parseInfo;
+ }
+
+ if( dataObject->getDataType() == QT_MDD )
+ {
+ if( loadDomain.dimension() == 0 )
+ {
+ // If no domain is specified, the load domain equals the current domain.
+ // This means that the data object is passed with an incremented reference.
+ // This mainly occurs with point accesses.
+
+ dataObject->incRef();
+ returnValue = dataObject;
+ }
+ else
+ {
+ QtMDD* qtMDD = (QtMDD*)dataObject;
+ MDDObj* currentMDDObj = qtMDD->getMDDObject();
+
+ RMDBGMIDDLE( 1, RMDebug::module_qlparser, "QtVariable", " definitionDomain: " << currentMDDObj->getDefinitionDomain() )
+ RMDBGMIDDLE( 1, RMDebug::module_qlparser, "QtVariable", " currentDomain...: " << currentMDDObj->getCurrentDomain() )
+
+ // load domain for the actual MDDObj
+ r_Minterval actLoadDomain;
+
+ // intersect actLoadDomain with defined domain
+ try{
+ actLoadDomain.intersection_of( loadDomain, currentMDDObj->getCurrentDomain() );
+ }
+ catch( r_Edim_mismatch& )
+ {
+ RMInit::logOut << "Error: QtVariable::evaluate() - specified domain dimensionality does not equal defined dimensionality." << endl;
+ parseInfo.setErrorNo(362);
+ throw parseInfo;
+ }
+ catch( r_Eno_interval )
+ {
+ RMInit::logOut << "Error: QtVariable::evaluate() - Specified domain does not intersect with spatial domain of MDD." << endl;
+ parseInfo.setErrorNo(356);
+ throw parseInfo;
+ }
+ catch( r_Error& err )
+ {
+ RMInit::logOut << "Error: QtVariable::evaluate() - general error." << endl;
+ parseInfo.setErrorNo(350);
+ throw parseInfo;
+ }
+
+ RMDBGMIDDLE( 1, RMDebug::module_qlparser, "QtVariable", " loadDomain......: " << actLoadDomain )
+
+ if( qtMDD->getLifetime() == QtData::QT_PERSISTENT )
+ {
+ //
+ // Create a new QtMDD object as carrier object for the persistent MDD object
+ // and attach the load domain. Now there are more than one MDD objects pointing
+ // to the same persistent MDD object which should not cause any problem.
+ //
+ // Note: Taking the same MDD object would mean sharing also the load domain which
+ // is not possible if the iterator variable occurs with different spatial operations.
+ //
+
+ QtMDD* result = new QtMDD( (MDDObj*)currentMDDObj );
+ result->setLoadDomain( actLoadDomain );
+
+ returnValue = result;
+ }
+ else
+ {
+ // Take the transient data object and increase its reference.
+ //
+ // Note: For a transient MDD object just one QtMDD carrier object is allowed.
+
+ qtMDD->incRef();
+ returnValue = qtMDD;
+ }
+
+ }
+
+ }
+ else
+ {
+ // Take the atomic data object and increase its reference.
+ dataObject->incRef();
+ returnValue = dataObject;
+ }
+
+ }
+ else
+ {
+ RMDBGMIDDLE( 1, RMDebug::module_qlparser, "QtVariable", "Error: QtVariable::evaluate() - the input list is empty." )
+ }
+ return returnValue;
+}
+
+
+void
+QtVariable::printTree( int tab, ostream& s, QtChildType /*mode*/ )
+{
+ s << SPACE_STR(tab).c_str() << "QtVariable Object: type " << flush;
+ dataStreamType.printStatus( s );
+ s << " name |" << iteratorName.c_str() << "|" /* << " pos " << dataIndex */ << endl;
+
+ if( loadDomain.dimension() > 0 )
+ {
+ s << SPACE_STR(tab).c_str() << "load domain: ";
+ loadDomain.print_status( s );
+ s << " - Trimflag: ";
+
+ for( int i=0; i<domainFlag->size(); i++)
+ s << (*domainFlag)[i];
+ s << endl;
+ }
+
+ if( oldLoadDomain.dimension() > 0 )
+ {
+ s << SPACE_STR(tab).c_str() << "old domain: ";
+ oldLoadDomain.print_status( s );
+ s << endl;
+ };
+}
+
+
+
+void
+QtVariable::printAlgebraicExpression( ostream& s )
+{
+ s << iteratorName.c_str() << flush;
+}
+
+
+
+const QtTypeElement&
+QtVariable::checkType( QtTypeTuple* typeTuple ) throw (ParseInfo)
+{
+ RMDBCLASS( "QtVariable", "checkType( QtTypeTuple* )", "qlparser", __FILE__, __LINE__ )
+
+ dataStreamType.setDataType( QT_TYPE_UNKNOWN );
+
+ if( typeTuple )
+ {
+ vector<QtTypeElement>::iterator iter;
+
+ // search for the type matching the variable name
+ for( iter=typeTuple->tuple.begin();
+ iter!=typeTuple->tuple.end() && dataStreamType.getDataType() == QT_TYPE_UNKNOWN;
+ iter++ )
+ {
+ if( (*iter).getName() && iteratorName == string( (*iter).getName() ) )
+ dataStreamType = *iter;
+ }
+ }
+
+ if( (dataStreamType.getDataType() == QT_TYPE_UNKNOWN) )
+ {
+ RMInit::logOut << "Error: QtVariable::checkType() - variable " << iteratorName.c_str() << " is unknwon." << endl;
+ parseInfo.setErrorNo(357);
+ throw parseInfo;
+ }
+
+ return dataStreamType;
+}
+
+
+
diff --git a/qlparser/qtvariable.hh b/qlparser/qtvariable.hh
new file mode 100644
index 0000000..f056da7
--- /dev/null
+++ b/qlparser/qtvariable.hh
@@ -0,0 +1,136 @@
+#ifndef _QTVARIABLE_
+#define _QTVARIABLE_
+
+#include "qlparser/qtoperation.hh"
+#include "raslib/minterval.hh"
+
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+#endif
+
+#include <stdio.h>
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+ //@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+ The class stands for a MDD variable which corresponds to an element of the
+ tupel passed by the evaluate() method.
+
+*/
+
+
+class QtVariable : public QtOperation
+{
+ public:
+ /// constructor getting iterator variable name
+ QtVariable( const std::string& iteratorName );
+
+ /// constructor getting iterator variable name and load domain
+ QtVariable( const std::string& iteratorName, const r_Minterval& loadDomain );
+
+ /// destructor
+ virtual ~QtVariable();
+
+ /// test if the two nodes have an equal meaning in the query tree
+ virtual bool equalMeaning( QtNode* node );
+
+ /// creates a unique name for a common subexpression
+ virtual std::string getSpelling();
+
+ /// test if the edge to the parent node is of type mdd or atomic
+ virtual QtAreaType getAreaType();
+
+ /// optimizing load access
+ void optimizeLoad( QtTrimList* trimList );
+
+ /// method for evaluating the node
+ QtData* evaluate( QtDataList* inputList ) throw (ParseInfo);
+
+ /// prints the tree
+ virtual void printTree( int tab, std::ostream& s = std::cout, QtChildType mode = QT_ALL_NODES );
+
+ /// prints the algebraic expression
+ virtual void printAlgebraicExpression( std::ostream& s = std::cout );
+
+ /// methods for iterator name
+ inline const std::string getIteratorName() const;
+ inline void setIteratorName( std::string& str );
+
+ /// method for loadDomain
+ inline const r_Minterval getLoadDomain() const;
+
+ /// method for loadDomain
+ inline void setLoadDomain( r_Minterval& loadDomain );
+
+ /// method for oldLoadDomain
+ inline void setOldLoadDomain();
+
+ /// method for oldLoadDomain
+ inline const r_Minterval getOldLoadDomain();
+
+ /// method for LoadDomain
+ inline vector<bool>* getLoadDomainFlag();
+
+ /// method for identification of nodes
+ inline virtual const QtNodeType getNodeType() const;
+
+ /// type checking of the subtree
+ virtual const QtTypeElement& checkType( QtTypeTuple* typeTuple = NULL ) throw (ParseInfo);
+
+ private:
+
+ /// attribute storing the iterator name
+ std::string iteratorName;
+
+ /// minterval storing the minimal domain which is needed in the upper tree
+ r_Minterval loadDomain;
+
+ /// unique backup of the loadDomain
+ r_Minterval oldLoadDomain;
+
+ /// bitvector for discrimination of trimming and projections
+ vector<bool>* domainFlag;
+
+ /// attribute storing the index of the variable's data element in the data vector
+ int dataIndex;
+
+ /// attribute for identification of nodes
+ static const QtNodeType nodeType;
+};
+
+#include "qlparser/qtvariable.icc"
+
+#endif
+
diff --git a/qlparser/qtvariable.icc b/qlparser/qtvariable.icc
new file mode 100644
index 0000000..0625b32
--- /dev/null
+++ b/qlparser/qtvariable.icc
@@ -0,0 +1,84 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+inline const QtNode::QtNodeType
+QtVariable::getNodeType() const
+{
+ return nodeType;
+}
+
+
+inline const std::string
+QtVariable::getIteratorName() const
+{
+ return iteratorName;
+}
+
+inline void
+QtVariable::setIteratorName( std::string& str )
+{
+ iteratorName = str;
+}
+
+
+inline const r_Minterval
+QtVariable::getLoadDomain() const
+{
+ return loadDomain;
+}
+
+
+inline void
+QtVariable::setLoadDomain( r_Minterval& loadDomainNew )
+{
+ if( oldLoadDomain.dimension() == 0 )
+ oldLoadDomain = loadDomain;
+ loadDomain = loadDomainNew;
+}
+
+
+inline void
+QtVariable::setOldLoadDomain()
+{
+ loadDomain = oldLoadDomain;
+}
+
+
+inline const r_Minterval
+QtVariable::getOldLoadDomain()
+{
+ return oldLoadDomain;
+}
+
+
+inline std::vector<bool>*
+QtVariable::getLoadDomainFlag()
+{
+ return domainFlag;
+}
diff --git a/qlparser/querytree.cc b/qlparser/querytree.cc
new file mode 100644
index 0000000..4a14ed6
--- /dev/null
+++ b/qlparser/querytree.cc
@@ -0,0 +1,489 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ * SOURCE: querytree.cc
+ *
+ * MODULE: qlparser
+ * CLASS: QueryTree
+ *
+ * PURPOSE:
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)qlparser, QueryTree: $Id: querytree.cc,v 1.52 2005/06/28 08:42:13 rasdev Exp $";
+
+
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+using namespace std;
+#endif
+#include <iostream>
+#include <dlfcn.h>
+
+#include "raslib/rmdebug.hh"
+#include "globals.hh"
+
+#include "qlparser/querytree.hh"
+#include "qlparser/qtnode.hh"
+#include "qlparser/qtoperationiterator.hh"
+#include "qlparser/qtselectioniterator.hh"
+#include "qlparser/qtjoiniterator.hh"
+#include "qlparser/qtvariable.hh"
+#include "qlparser/qtmdd.hh"
+#include "qlparser/qtdomainoperation.hh"
+#include "qlparser/qtexecute.hh"
+
+#include "catalogmgr/typefactory.hh"
+#include "relcatalogif/mdddomaintype.hh"
+#include "relcatalogif/settype.hh"
+
+void (*QueryTree::optimizationFnc)(unsigned int, QtNode*) = NULL;
+
+unsigned int QueryTree::nextCSENo = 0;
+
+SymbolTable<int> QueryTree::symtab;
+
+QueryTree::QueryTree()
+ : rootNode(NULL),
+ optimizationLevel(4)
+{
+}
+
+
+QueryTree::QueryTree( QtNode* root )
+ : rootNode( root ),
+ optimizationLevel(4)
+{
+}
+
+
+QueryTree::~QueryTree()
+{
+ if( rootNode )
+ {
+ delete rootNode;
+ rootNode=NULL;
+ }
+ releaseDynamicObjects();
+}
+
+
+void
+QueryTree::checkSemantics()
+{
+ RMDBCLASS( "QueryTree", "checkSemantics()", "qlparser", __FILE__, __LINE__ )
+
+ switch( rootNode->getNodeType() )
+ {
+ case QtNode::QT_MDD_ACCESS:
+ case QtNode::QT_OPERATION_ITERATOR:
+ case QtNode::QT_JOIN_ITERATOR:
+ case QtNode::QT_SELECTION_ITERATOR:
+ {
+ const QtTypeTuple& resultType = ((QtONCStream*)rootNode)->checkType();
+ // RMInit::logOut << "result type: " << flush;
+ // resultType.printStatus( RMInit::logOut );
+ }
+ break;
+
+ case QtNode::QT_UPDATE:
+ case QtNode::QT_INSERT:
+ case QtNode::QT_DELETE:
+ case QtNode::QT_COMMAND:
+ case QtNode::QT_PYRAMID:
+ ((QtExecute*)rootNode)->checkType();
+ break;
+
+ default:
+ {
+ const QtTypeElement& resultType = ((QtOperation*)rootNode)->checkType();
+ // RMInit::logOut << "result type: " << flush;
+ // resultType.printStatus( RMInit::logOut );
+ }
+ break;
+ }
+}
+
+
+void
+QueryTree::optimize( unsigned int currentOptimizationLevel )
+{
+ RMDBCLASS( "QueryTree", "optimize( unsigned int )", "qlparser", __FILE__, __LINE__ )
+
+ if (optimizationFnc == NULL) {
+ char *dir = CONFDIR;
+ char libName[255];
+ sprintf(libName,"%s/lib/libqloptimizer.so", dir);
+
+ if (access(libName, X_OK | R_OK) == 0) {
+ void *handle = dlopen(libName, RTLD_NOW);
+ if (handle == NULL) {
+ RMInit::logOut << "Optimization library found, however could not be loaded" << endl;
+ printf("DLERROR = %s\n", dlerror());
+ RMInit::logOut << dlerror() << endl;
+ return;
+ }
+
+ *(void **)(&optimizationFnc) = dlsym(handle, "runOptimizations");
+ if (optimizationFnc == NULL) {
+ RMInit::logOut << "Optimization library found, however the entry point was not found" << endl;
+ return;
+ }
+ } else {
+ RMInit::logOut << "No optimization library found" << endl;
+ return;
+ }
+ }
+
+ optimizationFnc(currentOptimizationLevel, rootNode);
+
+ RMDBGIF( 1, RMDebug::module_qlparser, "QueryTree", \
+ RMInit::logOut << endl << " "; \
+ rootNode->printAlgebraicExpression( RMInit::logOut ); \
+ RMInit::logOut << endl << endl; \
+ rootNode->printTree( 2, RMInit::logOut ); \
+ RMInit::logOut << endl; \
+ )
+}
+
+vector<QtData*>*
+QueryTree::evaluateRetrieval() throw (r_Error, ParseInfo)
+{
+ vector<QtData*>* returnValue=NULL;
+
+ if( rootNode )
+ {
+ if( rootNode->getNodeType() != QtNode::QT_MDD_ACCESS &&
+ rootNode->getNodeType() != QtNode::QT_OPERATION_ITERATOR &&
+ rootNode->getNodeType() != QtNode::QT_JOIN_ITERATOR &&
+ rootNode->getNodeType() != QtNode::QT_SELECTION_ITERATOR )
+ {
+ RMInit::logOut << "QueryTree::evaluateRetrieval() - Retrieval query must start with an ONC node." << endl;
+ ParseInfo errorInfo = rootNode->getParseInfo();
+ errorInfo.setErrorNo(371);
+ throw errorInfo;
+ }
+
+ QtNode::QtDataList* dataList=NULL;
+ QtNode::QtDataList::iterator dataIter;
+ QtONCStream* oncRootNode = (QtONCStream*)rootNode;
+
+ try
+ {
+ oncRootNode->open();
+ }
+ catch( ... )
+ {
+ oncRootNode->close();
+ RMInit::logOut << "QueryTree::evaluateRetrieval() - rethrow exception from oncRootNode->open()." << endl;
+ throw;
+ }
+
+ // removed to have uniform, compact log output -- PB 2003-nov-20
+ // RMInit::logOut << endl;
+
+ // create result collection
+ vector<QtData*>* resultData = new vector<QtData*>();
+
+ try
+ {
+ while( (dataList = oncRootNode->next()) )
+ {
+ if( dataList->size() > 1 || (*dataList)[0] == NULL )
+ {
+ // Delete the tupel vector received by next(). Just tupel elements which are not
+ // further referenced are deleted.
+ for( dataIter=dataList->begin(); dataIter!=dataList->end(); dataIter++ )
+ if( *dataIter ) (*dataIter)->deleteRef();
+ delete dataList;
+ dataList=NULL;
+
+ if( resultData )
+ {
+ // Delete the result vector
+ for( dataIter=resultData->begin(); dataIter!=resultData->end(); dataIter++ )
+ if( *dataIter ) (*dataIter)->deleteRef();
+ delete resultData;
+ resultData = NULL;
+ }
+
+ RMInit::logOut << "QueryTree::evaluateTree() - multiple query targets are not supported." << endl;
+ ParseInfo errorInfo = oncRootNode->getParseInfo();
+ errorInfo.setErrorNo(361);
+ throw errorInfo;
+ }
+
+ QtData* resultElement = (*dataList)[0];
+
+ // take the data element as result data and reset it in the tupel vector
+ resultData->push_back( resultElement );
+ (*dataList)[0] = NULL;
+
+ RMDBGMIDDLE( 2, RMDebug::module_qlparser, "QueryTree", endl << endl << "NEXT RESULT ITEM OF THE QUERY INSERTED" << endl << endl )
+
+ // Delete the tupel vector received by next(). Just tupel elements which are not
+ // set to zero and which are not further referenced are deleted.
+ for( dataIter=dataList->begin(); dataIter!=dataList->end(); dataIter++ )
+ if( *dataIter ) (*dataIter)->deleteRef();
+
+ // delete the tuple vector
+ delete dataList;
+ dataList=NULL;
+ }
+ }
+ catch(r_Error& myErr) {
+ RMInit::logOut << endl << "Caught BAD exception when evaluating query! " << endl;
+ RMInit::logOut << myErr.what() << endl;
+ if( resultData )
+ {
+ // Delete the result vector
+ for( dataIter=resultData->begin(); dataIter!=resultData->end(); dataIter++ )
+ if( *dataIter ) (*dataIter)->deleteRef();
+ delete resultData;
+ resultData = NULL;
+ }
+
+ oncRootNode->close();
+ RMInit::logOut << "QueryTree::evaluateTree() - rethrow exception." << endl;
+ throw;
+ }
+ catch( ... )
+ {
+ if( resultData )
+ {
+ // Delete the result vector
+ for( dataIter=resultData->begin(); dataIter!=resultData->end(); dataIter++ )
+ if( *dataIter ) (*dataIter)->deleteRef();
+ delete resultData;
+ resultData = NULL;
+ }
+
+ oncRootNode->close();
+ RMInit::logOut << "QueryTree::evaluateTree() - rethrow exception." << endl;
+ throw;
+ }
+
+ oncRootNode->close();
+
+ returnValue = resultData;
+ }
+
+ return returnValue;
+}
+
+
+
+void
+QueryTree::evaluateUpdate() throw (r_Error,ParseInfo)
+{
+ if( rootNode )
+ {
+ if( rootNode->getNodeType() != QtNode::QT_UPDATE &&
+ rootNode->getNodeType() != QtNode::QT_INSERT &&
+ rootNode->getNodeType() != QtNode::QT_DELETE &&
+ rootNode->getNodeType() != QtNode::QT_COMMAND &&
+ rootNode->getNodeType() != QtNode::QT_PYRAMID
+ )
+ {
+ RMInit::logOut << "QueryTree::evaluateUpdate() - update query must start with an INSERT, UPDATE, DELETE, DROP or CREATE statement." << endl;
+ ParseInfo errorInfo = rootNode->getParseInfo();
+ errorInfo.setErrorNo(372);
+ throw errorInfo;
+ }
+
+ QtExecute* executeNode = (QtExecute*) rootNode;
+
+ // evaluate the update query
+ executeNode->evaluate();
+ }
+}
+
+
+
+void QueryTree::printTree( int tab, ostream& s ) {
+ if ( rootNode ) {
+ s << SPACE_STR(tab).c_str() << "QueryTree:" << endl;
+ rootNode->printTree( tab + 2, s );
+ } else
+ s << SPACE_STR(tab).c_str() << "QueryTree: Qt has no root node." << endl;
+}
+
+void QueryTree::addDynamicObject( QtNode *node ) {
+ qtNodeList.push_back( node );
+}
+
+void QueryTree::removeDynamicObject( QtNode *node ) {
+ qtNodeList.remove( node );
+}
+
+void QueryTree::addDynamicObject( QtData *node ) {
+ qtDataList.push_back( node );
+}
+
+void QueryTree::removeDynamicObject( QtData *node ) {
+ qtDataList.remove( node );
+}
+
+void QueryTree::addDynamicObject( ParseInfo *node ) {
+ parseInfoList.push_back( node );
+}
+
+void QueryTree::removeDynamicObject( ParseInfo *node ) {
+ parseInfoList.remove( node );
+}
+
+void QueryTree::addDynamicObject( vector<QtONCStream *> *node ) {
+ vectorList.push_back( node );
+}
+
+void QueryTree::removeDynamicObject( vector<QtONCStream*> *node ) {
+ vectorList.remove( node );
+}
+
+void QueryTree::releaseDynamicObjects() {
+ list<QtNode*>::iterator iter1;
+ for( iter1 = qtNodeList.begin(); iter1 != qtNodeList.end(); iter1++ )
+ {
+ delete *iter1;
+ *iter1=NULL;
+ }
+
+ list<QtData*>::iterator iter2;
+ for( iter2 = qtDataList.begin(); iter2 != qtDataList.end(); iter2++ )
+ {
+ delete *iter2;
+ *iter2=NULL;
+ }
+
+ list<ParseInfo*>::iterator iter3;
+ for( iter3 = parseInfoList.begin(); iter3 != parseInfoList.end(); iter3++ )
+ {
+ delete *iter3;
+ *iter3=NULL;
+ }
+
+ list<vector<QtONCStream*>*>::iterator iter4;
+ for( iter4 = vectorList.begin(); iter4 != vectorList.end(); iter4++ )
+ {
+ delete *iter4;
+ *iter4=NULL;
+ }
+
+ list<char *>::iterator iter5;
+ for( iter5 = lexedCStringList.begin(); iter5 != lexedCStringList.end(); iter5++ )
+ {
+ free(*iter5);
+ *iter5=NULL;
+ }
+}
+
+void QueryTree::addDomainObject( QtDomainOperation *dop ) {
+ dopList.push_back( dop );
+}
+
+void QueryTree::removeDomainObject( QtDomainOperation *dop ) {
+ dopList.remove( dop );
+}
+
+void QueryTree::printDomainObjects() {
+ list<QtDomainOperation*>::iterator iter;
+ for( iter = dopList.begin(); iter != dopList.end(); iter++ ) {
+ cout << endl;
+ (*iter)->printTree( 2 );
+ }
+}
+
+void QueryTree::releaseDomainObjects() {
+ list<QtDomainOperation*>::iterator iter;
+ for( iter = dopList.begin(); iter != dopList.end(); iter++ )
+ {
+ delete *iter;
+ *iter=NULL;
+ }
+}
+
+void QueryTree::rewriteDomainObjects(r_Minterval *greatDomain, string *greatIterator, QtMarrayOp2::mddIntervalListType *greatList) {
+
+ RMDBGENTER( 2, RMDebug::module_qlparser, "QueryTree", endl << "QueryTree: Iterator: <" << *greatIterator << "> Domain: " << *greatDomain << endl )
+ list<QtDomainOperation*>::iterator iter;
+
+ for( iter = dopList.begin(); iter != dopList.end(); iter++ ) {
+
+ // 1. get var name from iter
+ QtVariable *qtVar = ((QtVariable *)((*iter)->getInput()));
+ string stVar = qtVar->getIteratorName();
+ const char *varname = stVar.c_str();
+
+ // 2. get position of varname in varList
+ bool bcond = false;
+ QtMarrayOp2::mddIntervalListType *varList = greatList;
+ QtMarrayOp2::mddIntervalListType::iterator varIter;
+ r_Long varpos = 0;
+ for (varIter = varList->begin(); varIter != varList->end(); varIter++) {
+
+ if (!strcmp(varname, varIter->variable.c_str())) {
+ bcond = true;
+ break;
+ };
+ QtData *data = varIter->tree->evaluate(0);
+ r_Dimension dimension = ((QtMintervalData*)data)->getMintervalData().dimension();
+ varpos = varpos+dimension;
+ };
+ // postcond: bcond == false: varname not found in list. else varpos gives the position.
+
+ if (bcond) {
+
+ // 3. set domain expression to old one incremented by varpos
+ QtNode::QtOperationList *lop = new QtNode::QtOperationList(1);
+ (*lop)[0] =
+ new QtPlus(
+ (*iter)->getMintervalOp(),
+ new QtConst(
+ new QtAtomicData(
+ varpos, sizeof(varpos)
+ )
+ )
+ );
+
+ (*iter)->setMintervalOp( new QtPointOp( lop ) );
+
+ // 4. set varname to greatIterator
+ QtVariable *var1 = new QtVariable( string(*greatIterator) );
+ (*iter)->setInput(var1);
+
+ } else
+ {
+ // TODO: insert some error notify code here!
+ RMDBGMIDDLE( 1, RMDebug::module_qlparser, "QueryTree", " variable name not found in list " )
+ }
+ }
+}
+
+void QueryTree::addCString( char *str ) {
+ lexedCStringList.push_back( str );
+}
diff --git a/qlparser/querytree.hh b/qlparser/querytree.hh
new file mode 100644
index 0000000..d6f28cc
--- /dev/null
+++ b/qlparser/querytree.hh
@@ -0,0 +1,265 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#ifndef _QUERYTREE_
+#define _QUERYTREE_
+
+#ifndef CPPSTDLIB
+#include <ospace/string.h> // STL<ToolKit>
+#else
+#include <string>
+#endif
+#include <algorithm>
+
+#include "mddmgr/mddcoll.hh"
+
+#include "qlparser/qtnode.hh"
+#include "qlparser/qtatomicdata.hh"
+#include "qlparser/qtbinaryinduce.hh"
+#include "qlparser/qtconst.hh"
+#include "qlparser/qtdomainoperation.hh"
+#include "qlparser/qtmarrayop2.hh"
+#include "qlparser/qtpointop.hh"
+#include "qlparser/symtab.hh"
+
+// forward declarations
+class MDDObj;
+class QtONCStream;
+class QtDomainOperation;
+
+
+/*************************************************************
+ *
+ *
+ * INCLUDE: querytree.hh
+ *
+ * MODULE: qlparser
+ * CLASS: QueryTree
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+The Query Tree is the internal representation of a RasML query string. It
+consists of instances of the above class hierarchy. The tree is created in
+the Query Parser Modul in the action sections of the yacc grammar. According
+to the parser semantics, the tree is built bottom up which means that the leaf
+objects are created first. They are given up via the parse stack. Inner objects
+get references to the subobjects after they are created. The whole tree is a
+dynamic data structure. The semantics is that if an object is deleted also its
+subobjects are deleted which means that the deletion of the root object cleans
+up the whole tree.
+
+The class QueryTree encapsulates a query tree consisting of suclasses of type
+QtNode. It consists of the entry point and methods working on the whole tree
+(e.g. traversing).
+
+*/
+
+class QueryTree
+{
+ public:
+
+
+ /// default constructor
+ QueryTree();
+
+ /// constructor getting the root of the query tree
+ QueryTree( QtNode* root );
+
+ /// destructor (deletes the whole query tree)
+ ~QueryTree();
+
+ /// checks semantics (e.g., type checking)
+ void checkSemantics();
+
+ /// optimizes the tree
+ void optimize( unsigned int optimizationLevel );
+
+ /*@Doc:
+ The method optimizes the query tree.
+ */
+
+ /// recognize common subexpressions
+ vector<QtNode::QtNodeList>* seeSubexpression();
+
+ /*@Doc:
+ The method returns a list of all common subexpressions in the query tree.
+ The private methods seeSubexpression(..) are used.
+ */
+
+ /// build in common subexpressions in the query tree
+ void insertSubexpression( vector<QtNode::QtNodeList>* nodeList );
+
+ /*@Doc:
+ The method manipulates the query tree to handle common subexpressions.
+ */
+
+ /// executes a retrieval tree and gives back the result collection
+ vector<QtData*>* evaluateRetrieval() throw (r_Error, ParseInfo);
+
+ /*@Doc:
+ The method evaluates a retrieval tree and returns the result collection. For this purpose,
+ first, the {\tt open()} message is sent to the root node of the tree. Then {\tt next()}
+ is invoked on the root node which, each time, returns one element of the result
+ collection. It indicates the end of the evaluation process through returning a null pointer.
+ At the end, {\tt close()} is called to clean up the ressources. If errors occur, various exceptions
+ are thrown.
+ */
+
+ /// executes an update tree and throws a ParseInfo if query does not begin with INSERT, DELETE, UPDATE, ...
+ void evaluateUpdate() throw (r_Error,ParseInfo);
+
+ /// debugging method
+ void printTree( int tab, ostream& s = cout );
+
+ //@Man: read/write methods
+ //@{
+ ///
+
+ ///
+ inline QtNode* getRoot() const;
+ ///
+ inline void setRoot( QtNode* root );
+ ///
+ inline void setOptimizationLevel( unsigned int level );
+ ///
+ inline unsigned int getOptimizationLevel();
+
+ ///
+ //@}
+
+ //@Man: methods used to maintain pointers to dynamic data structures used in the parse process
+ //@{
+ ///
+
+ ///
+ void addDynamicObject( QtNode* );
+ ///
+ void removeDynamicObject( QtNode* );
+ ///
+ void addDynamicObject( QtData* );
+ ///
+ void removeDynamicObject( QtData* );
+ ///
+ void addDynamicObject( ParseInfo* );
+ ///
+ void removeDynamicObject( ParseInfo* );
+ ///
+ void addDynamicObject( vector<QtONCStream*>* );
+ ///
+ void removeDynamicObject( vector<QtONCStream*>* );
+ ///
+ void releaseDynamicObjects();
+ ///
+ void addDomainObject( QtDomainOperation * );
+ ///
+ void removeDomainObject( QtDomainOperation * );
+ ///
+ void rewriteDomainObjects(r_Minterval *greatDomain, std::string *greatIterator, QtMarrayOp2::mddIntervalListType *greatList);
+ ///
+ void printDomainObjects();
+ ///
+ void releaseDomainObjects();
+ ///
+ void addCString( char * );
+ ///
+ //@}
+
+ ///
+ static SymbolTable<int> symtab;
+
+ private:
+ /// attribute storing the root of the query tree
+ QtNode* rootNode;
+
+ static void (*optimizationFnc)(unsigned int, QtNode*);
+
+ /// used by public seeSubexpression()
+ vector<QtNode::QtNodeList>* seeSubexpression( QtNode::QtNodeList* leafList );
+
+ /// used by public seeSubexpression()
+ QtNode::QtNodeList* seeSubexpression( QtNode::QtNodeList* leafList, vector<QtNode::QtNodeList>* leafListsNew );
+
+ /// level of optimization restricted for this query
+ unsigned int optimizationLevel;
+
+ /// attribute carrying next free number for CSE iterator
+ static unsigned int nextCSENo;
+
+ /// list of unlinked subtrees
+ std::list<QtNode*> qtNodeList;
+ /**
+ This list is used to store subtrees of type \Ref{QtNode} generated in the parse
+ process and not linked to the result tree yet. In case of an error
+ during the parse process, this list is freed.
+ */
+
+ /// list of unlinked subtrees
+ std::list<QtData*> qtDataList;
+ /**
+ This list is used to store subtrees of type \Ref{QtData} generated in the parse
+ process and not linked to the result tree yet. In case of an error
+ during the parse process, this list is freed.
+ */
+
+ /// list of unlinked subtrees
+ std::list<ParseInfo*> parseInfoList;
+ /**
+ This list is used to store elements of type \Ref{ParseInfo} generated in the parse
+ process and not linked to the result tree yet. In case of an error
+ during the parse process, this list is freed.
+ */
+
+ /// list of unlinked lists
+ std::list<vector<QtONCStream*>*> vectorList;
+ /**
+ This list is used to store elements of type \Ref{vector<QtONCStream*>} generated
+ in the parse process and not linked to the result tree yet. In case of an error
+ during the parse process, this list is freed.
+ */
+
+ /// list of domain operations relevant to variables in an MArray.
+ std::list<QtDomainOperation *> dopList; // contains basically QtDomainOperation (everything else is evil :-) )
+ /**
+ This list is used to store elements of type \Ref{QtDomainOperation *} generated
+ in the parse process for the purpose of a tree rewrite. In case of an error
+ during the parse process, this list is freed.
+ */
+
+ /// list of lexed c-strings
+ std::list<char *> lexedCStringList;
+ /**
+ This list is used to store elements of type char* generated during the lexing
+ process and not freed yet. In case of an error this list is freed.
+ */
+
+};
+
+#include "querytree.icc"
+
+#endif
+
diff --git a/qlparser/querytree.icc b/qlparser/querytree.icc
new file mode 100644
index 0000000..251704d
--- /dev/null
+++ b/qlparser/querytree.icc
@@ -0,0 +1,47 @@
+/*************************************************************
+ *
+ * Copyright (C) 1996 FORWISS
+ *
+ * INLINE SOURCE: querytree.icc
+ *
+ * MODULE: qlparser
+ * CLASS: QueryTree
+ *
+ * CHANGE HISTORY (append further entries):
+ * when who what
+ * ----------------------------------------------------------
+ * 04-09-96 Ritsch created
+ * 11-08-97 Ritsch merged with version 1.5.1.2
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+inline QtNode*
+QueryTree::getRoot() const
+{
+ return rootNode;
+};
+
+
+inline void
+QueryTree::setRoot( QtNode* root )
+{
+ rootNode = root;
+};
+
+
+inline void
+QueryTree::setOptimizationLevel( unsigned int level )
+{
+ optimizationLevel = level;
+};
+
+
+inline unsigned int
+QueryTree::getOptimizationLevel()
+{
+ return optimizationLevel;
+};
+
+
diff --git a/qlparser/rasml.awk b/qlparser/rasml.awk
new file mode 100644
index 0000000..124d6ab
--- /dev/null
+++ b/qlparser/rasml.awk
@@ -0,0 +1,9 @@
+BEGIN { paren = 0; sec = 0 }
+/\%\%/ { sec += 1; next; }
+sec!=1 { next; }
+# /^ *$/ { next; }
+/\/\// && !paren { x=$0; sub(/\/\/.*/, "", x); print x; next; }
+/{/ { x=$0; sub(/\{.*/, "", x); if(!paren) print x; paren += 1; }
+/(\/\*)/ { paren += 1; }
+/}|(\*\/)/ { paren -= 1; next; }
+!paren { print $0; }
diff --git a/qlparser/rasmlgrammar.html b/qlparser/rasmlgrammar.html
new file mode 100644
index 0000000..d192d21
--- /dev/null
+++ b/qlparser/rasmlgrammar.html
@@ -0,0 +1,27 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+ <TITLE>RasDaMan: Specification</TITLE>
+ <META NAME="GENERATOR" CONTENT="Mozilla/3.0b6Gold (X11; I; HP-UX B.10.01 9000/770) [Netscape]">
+</HEAD>
+<BODY>
+
+<!-- BASE HREF=http://www.forwiss.tu-muenchen.de/ -->
+
+<H1><IMG SRC="/public/forwiss/projekte/rasdaman/rmanlogo-s.gif" ALT="[RasDaMan-Logo]" >Implementation
+Specification: RasML Grammar</H1>
+
+<P>The following grammar specifies RasML.</P>
+
+<PRE>
+
+<grammar>
+
+</PRE>
+
+<P><HR WIDTH="100%"></P>
+
+<P><A HREF="mailto:ritsch@forwiss.tu-muenchen.de">Roland Ritsch</A>, 1997-09-10</P>
+
+</BODY>
+</HTML> \ No newline at end of file
diff --git a/qlparser/symtab.cc b/qlparser/symtab.cc
new file mode 100644
index 0000000..f96e49e
--- /dev/null
+++ b/qlparser/symtab.cc
@@ -0,0 +1,159 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************************
+ *
+ *
+ * PURPOSE:
+ * store symbols (identifiers) during the parse process
+ *
+ *
+ * COMMENTS:
+ * none
+ *
+ ***********************************************************************/
+
+//**************************************************************
+// Symbol Table class
+//**************************************************************
+
+//**************************************************************
+// Implementation
+//**************************************************************
+
+#include "symtab.hh"
+
+// constructor
+template <class T>
+SymbolTable<T>::SymbolTable() {
+ initScope();
+ STVars.clear();
+}
+
+// destructor
+template <class T>
+SymbolTable<T>::~SymbolTable() {
+ exitScope();
+}
+
+// put symbol in keys and in the hash-table
+template <class T>
+bool SymbolTable<T>::putSymbol(const std::string& symbol, T value) {
+ bool retVal = false;
+ // if not locally declared
+ if ( (STVars.find(symbol) == STVars.end()) ) {
+ if (getSymbol(symbol) == 0)
+ keys.push_back(symbol);
+ STVars[symbol] = value;
+ retVal = true;
+ } else
+ retVal = false;
+ return retVal;
+}
+
+// store symbol into hash-table
+template <class T>
+void SymbolTable<T>::storeSymbol( const std::string& symbol, T value ) {
+ STVars[symbol] = value;
+}
+
+// get symbol from table
+template <class T>
+T SymbolTable<T>::getSymbol( const std::string& symbol ) {
+ T retVal=NULL;
+
+ // find if locally declared
+ if ( !(STVars.find(symbol) == STVars.end()) )
+ {
+ retVal=STVars[symbol];
+ }
+ else
+ {
+ // find if declared in outer scopes
+ size_t idx=STScopes.size();
+ while (idx > 0) {
+ idx--;
+ if ( !(STScopes[idx].find(symbol) == STScopes[idx].end()) )
+ retVal=STScopes[idx][symbol];
+ }
+ }
+ return retVal;
+}
+
+// lookup symbol in table
+template <class T>
+bool SymbolTable<T>::lookupSymbol( const std::string& symbol ) {
+ bool retVal=false;
+
+ // find if locally declared
+ if ( !(STVars.find(symbol) == STVars.end()) )
+ {
+ retVal=true;
+ }
+ else
+ {
+ // find if declared in outer scopes
+ size_t idx = STScopes.size();
+ while (idx > 0) {
+ idx--;
+ if ( !(STScopes[idx].find(symbol) == STScopes[idx].end()) )
+ retVal=true;
+ }
+ }
+ return retVal;
+}
+
+// output the current scope
+template <class T>
+void SymbolTable<T>::outScope() {
+ RMInit::logOut << "Scope: " << STScopes.size() << endl;
+}
+
+// init scope by clearing inner symbols
+template <class T>
+void SymbolTable<T>::clearScope() {
+ STVars.clear();
+}
+
+// enter new scope
+template <class T>
+void SymbolTable<T>::initScope() {
+ STScopes.push_back(STVars);
+ STVars.clear();
+}
+
+// exit current scope to previous one
+template <class T>
+void SymbolTable<T>::exitScope() {
+ if (!STScopes.empty()) {
+ STVars = STScopes[STScopes.size() - 1];
+ STScopes.pop_back();
+ }
+}
+
+// wipe out everything from symbol table
+template <class T>
+void SymbolTable<T>::wipe() {
+ keys.clear();
+ STVars.clear();
+ STScopes.clear();
+}
diff --git a/qlparser/symtab.hh b/qlparser/symtab.hh
new file mode 100644
index 0000000..c3e5fba
--- /dev/null
+++ b/qlparser/symtab.hh
@@ -0,0 +1,110 @@
+#ifndef _SYMTAB_HH_
+#define _SYMTAB_HH_
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************************
+ *
+ *
+ * PURPOSE:
+ * store symbols (identifiers) during the parse process
+ *
+ *
+ * COMMENTS:
+ * none
+ *
+ ***********************************************************************/
+
+#include <iostream>
+#include <vector>
+#include <map>
+#include <string>
+#include "raslib/rmdebug.hh"
+
+//@ManMemo: Module: {\bf qlparser}
+
+/*@Doc:
+
+ This class represents a generic symbol table. The operations on
+ symbols in the symbol table are: putSymbol, getSymbol, lookupSymbol.
+ The operations on scopes are: initScope, exitScope, outScope, clearScope,
+ wipe.
+
+*/
+
+template <class T>
+class SymbolTable {
+public:
+ /// This vector stores keys available in the map.
+ std::vector<std::string > keys;
+ /// This is an iterator for the vector storing the keys available in the map.
+ std::vector<std::string >::iterator keyIterator;
+
+ /// default constructor creates an empty symbol table, calls initScope(), clears local symbols.
+ SymbolTable();
+
+ /// default destructor, calls exitScope().
+ ~SymbolTable();
+
+ //@Man: Methods for symbol manipulation
+ //@{
+ /// Puts value at position symbol in the table. Returns true if it succeeded, otherwise false.
+ bool putSymbol( const std::string& symbol, T value );
+ /// Get value at position symbol from the table. If symbol doesn't exist, it returns NULL.
+ T getSymbol( const std::string& symbol );
+ /// Returns true if symbol is in table.
+ bool lookupSymbol( const std::string& symbol );
+ //@}
+
+ //@Man: Methods for scope manipulation
+ //@{
+ /// Enter new scope.
+ void initScope();
+ /// Exit current scope.
+ void exitScope();
+ /// Output current scope to RMInit::logOut.
+ void outScope();
+ /// Init scope by clearing inner symbols.
+ void clearScope();
+ /// Clear all symbols in all scopes.
+ void wipe();
+ //@}
+
+private:
+ /// Store symbol in map.
+ void storeSymbol( const std::string& symbol, T value ); // put only in the hash_map
+
+ /// Stores local variables.
+ std::map<std::string , T> STVars;
+
+ /// Stores scopes.
+ std::vector<std::map<std::string , T> > STScopes;
+};
+
+#ifdef EARLY_TEMPLATE
+#ifdef __EXECUTABLE__
+#include "symtab.cc"
+#endif
+#endif
+
+#endif
diff --git a/qlparser/test/Makefile b/qlparser/test/Makefile
new file mode 100644
index 0000000..fbf0bff
--- /dev/null
+++ b/qlparser/test/Makefile
@@ -0,0 +1,89 @@
+# -*-Makefile-*-
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>. # Top Level makefile. This points to the various modules that have to be build
+# and/or deployed
+#
+# MAKEFILE FOR:
+# test programs of module qlparser
+#
+# COMMENTS:
+#
+##################################################################
+#
+# This is just an example Makefile for a test program.
+# The dependency of the test program on the lib of the
+# corresponding module is in the Makefile of the module.
+#
+
+######################### Definitions ############################
+
+# all test programs
+SRCCXX = test_qlparser.cc test_evaluate.cc
+OBJS = ${SRCCXX:%.cc=%.o}
+ALLTESTS = ${SRCCXX:%.cc=%}
+MISCCLEAN := core
+
+# add compile and link options for STL
+CXXFLAGS += $(STLCXXFLAGS)
+LDFLAGS += $(STLLDFLAGS)
+
+########################### Targets ##############################
+
+# test target for qlparser
+.PHONY : qlparser
+qlparser: test_module test_qlparser
+
+.PHONY : evaluate
+evaluate: test_module test_evaluate
+
+.PHONY : test_module
+test_module:
+ cd $(RMANBASE)/qlparser; $(MAKE)
+
+test_evaluate: test_evaluate.o $(QLPARSER) \
+ $(RASLIB) \
+ $(CACHETAMGR) \
+ $(MDDIF) \
+ $(CATALOGIF) \
+ $(INDEXIF) \
+ $(INDEXMGR) \
+ $(BLOBIF) \
+ $(ADMINIF) \
+ $(CONVERSION)
+ $(PURIFY) $(CXX) $(LDFLAGS) $(BASEDBLDFLAGS) -o $@ $^
+
+
+test_qlparser: $(QLPARSER) test_qlparser.o $(RMANHOME)/qlparser/*.o \
+ $(QLPARSER) \
+ $(RMANHOME)/lib/librasodmg.a \
+ $(RASLIB) \
+ $(CACHETAMGR) \
+ $(MDDIF) \
+ $(CATALOGIF) \
+ $(INDEXIF) \
+ $(INDEXMGR) \
+ $(BLOBIF) \
+ $(ADMINIF) \
+ $(CONVERSION) \
+ $(RMANHOME)/rasdl/symbtbl.o
+ $(PURIFY) $(CXX) $(LDFLAGS) $(BASEDBLDFLAGS) -o $@ $^
+
diff --git a/qlparser/test/insertbin.cpp b/qlparser/test/insertbin.cpp
new file mode 100644
index 0000000..7779472
--- /dev/null
+++ b/qlparser/test/insertbin.cpp
@@ -0,0 +1,316 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ *
+ *
+ ************************************************************/
+
+#define FASTCONNECT
+#define DEBUG_MAIN
+#define DEBUG
+#define __EXECUTABLE__
+#include "debug.hh"
+#include "template_inst.hh"
+
+#define RMANVERSION 6100
+#define RASARCHITECTURE X86
+
+extern unsigned long maxTransferBufferSize = 4000000;
+bool udfEnabled = true;
+extern char* dbSchema = 0;
+extern int noTimeOut= 0;
+
+#include <iostream> // cout
+#include <vector>
+#include <stdio.h> // fopen, perror
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+
+#include "qlparser/querytree.hh"
+#include "raslib/rminit.hh"
+#include "raslib/rmdebug.hh"
+
+
+#include "adminif.hh"
+#include "databaseif.hh"
+#include "transactionif.hh"
+
+#include "mddmgr/mddobj.hh"
+#include "mddmgr/mddcoll.hh"
+#include "mddmgr/mddcolliter.hh"
+
+char globalConnectId[256]="RASBASE";
+
+// init globals for server initialization
+
+extern int yyparse(void *);
+extern char* myExecArgv0 = "";
+extern int globalOptimizationLevel = 4;
+extern char* beginParseString;
+extern char* iterParseString;
+
+extern int RManDebug;
+extern int RManInfo = 0;
+extern int rewrite = 0;
+extern int loadopt = 0;
+
+extern QueryTree* parseQueryTree;
+
+
+int checkArguments( int argc, char** argv, const char* searchText, int& optionValueIndex )
+{
+ int found = 0;
+ int i=1;
+
+ while( !found && i<argc )
+ found = !strcmp( searchText, argv[i++] );
+
+ if( found && i<argc && !strchr(argv[i],'-') )
+ optionValueIndex = i;
+ else
+ optionValueIndex = 0;
+
+ return found;
+}
+
+
+int main( int argc, char** argv )
+{
+ FILE* inFile;
+ char baseName[255];
+ char query[4096];
+ struct timezone tzp;
+ struct timeval startTime, stopTime, deltaTime;
+ int timeTest;
+ int optionValueIndex;
+ int noOutput;
+
+ if( checkArguments( argc, argv, "-h", optionValueIndex ) )
+ {
+ cout << "Usage: test_evaluate basename queryfile [options]" << endl;
+ cout << "Options: -h ... this help" << endl;
+ cout << " -l <file> ... log is printed to <file> (default: server.log)" << endl;
+ cout << " -l log is printed to standard out" << endl;
+ cout << " -d <file> ... debug output is printed to <file> (default: server.dbg)" << endl;
+ cout << " -d debug output is printed to standard out" << endl;
+ cout << " -dl n ... debug level is set to n (0-4, default: 0)" << endl;
+ cout << " - 0 = no / 4 = maximal debug information" << endl;
+ cout << " -opt n ... maximal optimization level (0-4, default: 4)" << endl;
+ cout << " - 0 = no / 4 = maximal optimization" << endl;
+ cout << " -t time test is enabled" << endl;
+ cout << " -nooutput ... no output of result" << endl;
+ cout << endl;
+ return 0;
+ }
+
+ strcpy( baseName, "RASBASE" );
+
+ inFile = fopen( "query", "r" );
+
+ if( inFile == NULL )
+ {
+ cout << "Error opening query file " << argv[2] << endl;
+ return -1;
+ }
+
+ fread( &query, 1, 4095, inFile );
+ fclose( inFile );
+
+ cout << endl << "Query:" << endl << endl << query << endl;
+
+ //
+ // open database, start transaction
+ //
+
+ // variables representing O2 database, ta and session
+ DatabaseIf db;
+ TransactionIf ta;
+
+ // don't forget to initialize before using AdminIf!
+ cout << "Connecting to O2 ..." << flush;
+ myExecArgv0 = argv[0];
+ AdminIf* myAdmin = AdminIf::instance();
+ cout << "OK" << endl;
+
+ // connect to the database
+ cout << "Opening database " << baseName << "... " << flush;
+ db.open( baseName );
+ cout << "OK" << endl;
+
+ cout << "Starting transaction ... " << flush;
+ ta.begin(&db);
+ cout << "OK" << endl;
+
+ //
+ // body of test program
+ //
+
+ beginParseString = query;
+ iterParseString = query;
+
+ parseQueryTree = new QueryTree(); // create a query tree object...
+
+ if( timeTest )
+ gettimeofday (&startTime, &tzp);
+
+ RMInit::logOut << "Parsing..." << flush;
+
+ if( yyparse(NULL) == 0 )
+ {
+ RMInit::logOut << "OK" << endl << endl;
+
+ parseQueryTree->printTree( 2, RMInit::logOut );
+ RMInit::logOut << endl;
+
+ parseQueryTree->getRoot()->printAlgebraicExpression();
+ cout << endl << endl;
+
+ unsigned int localOptimizationLevel = globalOptimizationLevel < parseQueryTree->getOptimizationLevel() ?
+ globalOptimizationLevel : parseQueryTree->getOptimizationLevel();
+
+ RMInit::logOut << "Optimizing query on level " << localOptimizationLevel << endl;
+ try
+ {
+ parseQueryTree->optimize( localOptimizationLevel );
+ }
+ catch( ParseInfo& info )
+ {
+ RMInit::logOut << endl << "Optimization Error" << endl;
+ info.printStatus();
+ cout << endl;
+
+ return 0;
+ }
+
+ RMInit::logOut << endl;
+ parseQueryTree->printTree( 2, RMInit::logOut );
+ RMInit::logOut << endl;
+ parseQueryTree->getRoot()->printAlgebraicExpression( RMInit::logOut );
+ RMInit::logOut << endl << endl;
+
+ RMInit::logOut << "Evaluating... " << flush;
+
+ vector<QtData*>* transColl = 0;
+
+ try
+ {
+ transColl = parseQueryTree->evaluateRetrieval();
+ }
+ catch( ParseInfo& info )
+ {
+ RMInit::logOut << endl << "Query Execution Error" << endl;
+ info.printStatus();
+ cout << endl;
+
+ return 0;
+ }
+
+ RMInit::logOut << "OK" << endl << endl;
+
+ if( timeTest )
+ {
+ gettimeofday(&stopTime, &tzp);
+
+ if(startTime.tv_usec > stopTime.tv_usec) {
+ stopTime.tv_usec += 1000000;
+ stopTime.tv_sec--;
+ }
+
+ deltaTime.tv_usec = stopTime.tv_usec - startTime.tv_usec;
+ deltaTime.tv_sec = stopTime.tv_sec - startTime.tv_sec;
+
+ cout << "Time for query processing " << deltaTime.tv_sec << " sec " << deltaTime.tv_usec << " msec " << endl;
+ }
+
+ vector<QtData*>::iterator transIter;
+ int collNum;
+ collNum = transColl->size();
+
+ cout << "The result collection has " << collNum << " entries." << endl;
+
+ if( transColl != 0 && !noOutput )
+ {
+ int i;
+
+ for( transIter = transColl->begin(), i=0; transIter != transColl->end(); transIter++, i++ )
+ {
+ QtData* mddObj = *transIter;
+
+ cout << endl << " --" << i << ". MDD object in set:" << endl << " ";
+ mddObj->printStatus();
+
+ /*vector<Tile* >* tiles = mddObj->getTiles();
+ vector<Tile* >::iterator tileIter;
+
+ for( tileIter = tiles->begin(); tileIter!=tiles->end(); tileIter++ )
+ {
+ cout << endl << " Tile" << endl;
+ (*tileIter)->printStatus();
+ }
+
+ // delete the Tile elements of the vector and the vector itself
+ // release( tiles->begin(), tiles->end() );
+ for( tileIter = tiles->begin(); tileIter!=tiles->end(); tileIter++ )
+ delete *tileIter;
+
+ delete tiles;*/
+ }
+
+ // release dynamic memory for the collection (delete MDDObjs)
+ // transColl->eraseAll();
+ delete transColl;
+
+ // delete transIter;
+ };
+
+ }
+ else {
+ RMInit::logOut << " failed" << endl;
+ printf("Error parsing query\n");
+ }
+
+ delete parseQueryTree;
+
+ //
+ // end of body
+ //
+
+ cout << "Committing transaction ... " << flush;
+ ta.commit();
+ cout << "OK" << endl;
+
+ cout << "Closing database ..." << flush;
+ db.close();
+ cout << "OK" << endl;
+ cout << "Ending O2 session ..." << endl;
+ delete myAdmin;
+ cout << "OK" << endl;
+
+ return 0;
+}
diff --git a/qlparser/test/template_inst.hh b/qlparser/test/template_inst.hh
new file mode 100644
index 0000000..9ce08ed
--- /dev/null
+++ b/qlparser/test/template_inst.hh
@@ -0,0 +1,152 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+// This version was created based on rview. Let's see if the other programs compile
+// also.
+
+#ifndef _TEMPLATE_INST_RASLIB_
+#define _TEMPLATE_INST_RASLIB_
+
+#include <vector>
+
+#include "qlparser/symtab.hh"
+
+#include "raslib/attribute.hh"
+#include "raslib/itertype.hh"
+#include "raslib/dlist.hh"
+
+#include "tile.hh"
+
+#include "indexmgr/keyobject.hh"
+
+#include "reladminif/dbref.hh"
+#include "reladminif/dbobjectiditerator.hh"
+
+#include "relblobif/blobtile.hh"
+#include "relblobif/dbtile.hh"
+#include "relblobif/inlinetile.hh"
+
+#include "relcatalogif/typeiterator.hh"
+#include "relcatalogif/settype.hh"
+#include "relcatalogif/structtype.hh"
+#include "relcatalogif/mddtype.hh"
+#include "relcatalogif/inlineminterval.hh"
+#include "relcatalogif/dbminterval.hh"
+
+#include "relindexif/dbtcindex.hh"
+#include "relindexif/hierindex.hh"
+#include "relindexif/dbrcindexds.hh"
+
+#include "relmddif/dbmddobj.hh"
+#include "relmddif/dbmddset.hh"
+
+#include "relstorageif/dbudfds.hh"
+#include "relstorageif/dbudfpackageds.hh"
+#include "relstorageif/dbstoragelayout.hh"
+
+
+#include <qlparser/symtab.hh>
+#include <raslib/attribute.hh>
+#include <raslib/itertype.hh>
+#include <raslib/dlist.hh>
+#include <raslib/minterval.hh>
+
+
+#include "reladminif/dbref.hh"
+#include "reladminif/dbobjectiditerator.hh"
+
+#include "relindexif/dbtcindex.hh"
+#include "relindexif/hierindex.hh"
+#include "relindexif/dbrcindexds.hh"
+
+
+template class DBRef<DBHierIndex>;
+template class DBRef<DBRCIndexDS>;
+template class DBRef<DBTCIndex>;
+template class DBRef<BLOBTile>;
+template class DBRef<DBTile>;
+template class DBRef<InlineTile>;
+template class DBRef<DBMDDSet>;
+template class DBRef<DBMinterval>;
+template class DBRef<DBStorageLayout>;
+template class DBRef<DBUDFDS>;
+template class DBRef<DBUDFPackageDS>;
+template bool operator< (const DBRef<DBMDDObj>&, const DBRef<DBMDDObj>&);
+
+
+#include <rasodmg/tiling.hh>
+#include <rasodmg/stattiling.hh>
+#include <rasodmg/iterator.hh>
+#include <rasodmg/transaction.hh>
+#include <rasodmg/ref.hh>
+#include <rasodmg/object.hh>
+#include <rasodmg/set.hh>
+#include <rasodmg/collection.hh>
+#include <rasodmg/gmarray.hh>
+#include <rasodmg/marray.hh>
+#include <rasodmg/dirdecompose.hh>
+
+template class r_Ref<r_Object>;
+template class r_Ref<r_Minterval>;
+template class r_Collection<r_Transaction::GenRefElement *>;
+template class r_Set<r_Transaction::GenRefElement *>;
+template class r_Iterator<r_GMarray *>;
+template class r_Iterator<r_Ref<r_GMarray > >;
+template class r_Collection<r_Ref<r_GMarray> >;
+template class r_Collection<r_GMarray *>;
+template class r_Set<r_GMarray *>;
+template class r_Iterator<r_Ref<r_Object> >;
+template class r_IterType<r_Attribute>;
+template class r_Collection<r_Ref<r_Object> >;
+template class r_Set<r_Ref<r_Object> >;
+template class r_Iterator<r_Ref_Any>;
+template class r_Ref<r_GMarray>;
+template class r_Collection<r_Ref_Any>;
+template class std::vector<r_Minterval>;
+template class r_Iterator<r_Transaction::GenRefElement *>;
+template class r_Set<r_Ref<r_GMarray> >;
+template class r_Ref<r_Set<r_Ref<r_GMarray> > >;
+template class r_Set<r_Ref_Any>;
+template class r_Marray<r_ULong>;
+template class r_Marray<r_Char>;
+
+template class DBRef<DBMDDObj>;
+template class DBRef<DBObject>;
+
+template class DBObjectIdIterator<DBMDDObj>;
+template class DBObjectIterator<DBMDDObj>;
+template class DBObjectIterator<DBMDDSet>;
+template class DBObjectIterator<StructType>;
+template class DBObjectIterator<SetType>;
+template class DBObjectIterator<MDDType>;
+template class DBRef<StructType>;
+template class DBRef<SetType>;
+template class DBRef<MDDType>;
+
+
+template std::ostream& operator << (std::ostream& os, const std::vector<r_Minterval>& list);
+template std::ostream& operator << (std::ostream& os, const std::vector<r_Dir_Decompose>& list);
+template std::ostream& operator << (std::ostream& os, const std::vector<r_Access>& list);
+template std::ostream& operator << (std::ostream& os, const std::vector<double>& list);
+template class SymbolTable<int>;
+
+#endif
diff --git a/qlparser/test/test_evaluate.cc b/qlparser/test/test_evaluate.cc
new file mode 100644
index 0000000..b34ce9d
--- /dev/null
+++ b/qlparser/test/test_evaluate.cc
@@ -0,0 +1,338 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ *
+ *
+ ************************************************************/
+
+#include <iostream.h> // cout
+#include <stdio.h> // fopen, perror
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "qlparser/querytree.hh"
+#include "raslib/rminit.hh"
+#include "raslib/rmdebug.hh"
+
+#include "adminif.hh"
+#include "databaseif.hh"
+#include "transactionif.hh"
+
+#include "mddmgr/mddobj.hh"
+#include "mddmgr/mddcoll.hh"
+#include "mddmgr/mddcolliter.hh"
+
+// init globals for server initialization
+RMINITGLOBALS('S')
+
+extern int yyparse();
+extern char* myExecArgv0 = "";
+extern int globalOptimizationLevel = 4;
+extern char* beginParseString;
+extern char* iterParseString;
+
+extern int RManDebug;
+extern int RManInfo = 0;
+extern int rewrite = 0;
+extern int loadopt = 0;
+
+extern QueryTree* parseQueryTree;
+
+
+int checkArguments( int argc, char** argv, const char* searchText, int& optionValueIndex )
+{
+ int found = 0;
+ int i=1;
+
+ while( !found && i<argc )
+ found = !strcmp( searchText, argv[i++] );
+
+ if( found && i<argc && !strchr(argv[i],'-') )
+ optionValueIndex = i;
+ else
+ optionValueIndex = 0;
+
+ return found;
+}
+
+
+int main( int argc, char** argv )
+{
+ FILE* inFile;
+ char baseName[255];
+ char query[4096];
+ struct timezone tzp;
+ struct timeval startTime, stopTime, deltaTime;
+ int timeTest;
+ int optionValueIndex;
+ int noOutput;
+
+ if( checkArguments( argc, argv, "-h", optionValueIndex ) )
+ {
+ cout << "Usage: test_evaluate basename queryfile [options]" << endl;
+ cout << "Options: -h ... this help" << endl;
+ cout << " -l <file> ... log is printed to <file> (default: server.log)" << endl;
+ cout << " -l log is printed to standard out" << endl;
+ cout << " -d <file> ... debug output is printed to <file> (default: server.dbg)" << endl;
+ cout << " -d debug output is printed to standard out" << endl;
+ cout << " -dl n ... debug level is set to n (0-4, default: 0)" << endl;
+ cout << " - 0 = no / 4 = maximal debug information" << endl;
+ cout << " -opt n ... maximal optimization level (0-4, default: 4)" << endl;
+ cout << " - 0 = no / 4 = maximal optimization" << endl;
+ cout << " -t time test is enabled" << endl;
+ cout << " -nooutput ... no output of result" << endl;
+ cout << endl;
+ return 0;
+ }
+
+ strcpy( baseName, argv[1] );
+
+ if( checkArguments( argc, argv, "-l", optionValueIndex ) )
+ if( optionValueIndex )
+ {
+ RMInit::logFileOut.open( argv[optionValueIndex] );
+ // RMInit::logOut = RMInit::logFileOut;
+ }
+ else {
+ // RMInit::logOut = cout.rdbuf();
+ }
+ else
+ {
+ // default
+ RMInit::logFileOut.open("server.log");
+ // RMInit::logOut = RMInit::logFileOut;
+ }
+
+ if( checkArguments( argc, argv, "-d", optionValueIndex ) )
+ if( optionValueIndex )
+ {
+ RMInit::dbgFileOut.open( argv[optionValueIndex] );
+ // RMInit::dbgOut = RMInit::dbgFileOut;
+ }
+ else {
+ // RMInit::logOut = cout.rdbuf();
+ }
+ else
+ {
+ // default
+ RMInit::dbgFileOut.open("server.dbg");
+ // RMInit::dbgOut = RMInit::dbgFileOut;
+ }
+
+ if( checkArguments( argc, argv, "-dl", optionValueIndex ) )
+ if( optionValueIndex )
+ RManDebug = (int)strtoul( argv[optionValueIndex], (char **)NULL, 10);
+
+ if( checkArguments( argc, argv, "-opt", optionValueIndex ) )
+ if( optionValueIndex )
+ globalOptimizationLevel = (int)strtoul( argv[optionValueIndex], (char **)NULL, 10);
+
+ timeTest = checkArguments( argc, argv, "-t", optionValueIndex );
+ noOutput = checkArguments( argc, argv, "-nooutput", optionValueIndex );
+
+ inFile = fopen( argv[2], "r" );
+
+ if( inFile == NULL )
+ {
+ cout << "Error opening query file " << argv[2] << endl;
+ return -1;
+ }
+
+ fread( &query, 1, 4095, inFile );
+ fclose( inFile );
+
+ cout << endl << "Query:" << endl << endl << query << endl;
+
+ //
+ // open database, start transaction
+ //
+
+ // variables representing O2 database, ta and session
+ DatabaseIf db;
+ TransactionIf ta;
+
+ // don't forget to initialize before using AdminIf!
+ cout << "Connecting to O2 ..." << flush;
+ myExecArgv0 = argv[0];
+ AdminIf* myAdmin = AdminIf::instance();
+ cout << "OK" << endl;
+
+ // connect to the database
+ cout << "Opening database " << baseName << "... " << flush;
+ db.open( baseName );
+ cout << "OK" << endl;
+
+ cout << "Starting transaction ... " << flush;
+ ta.begin(&db);
+ cout << "OK" << endl;
+
+ //
+ // body of test program
+ //
+
+ beginParseString = query;
+ iterParseString = query;
+
+ parseQueryTree = new QueryTree(); // create a query tree object...
+
+ if( timeTest )
+ gettimeofday (&startTime, &tzp);
+
+ RMInit::logOut << "Parsing..." << flush;
+
+ if( yyparse() == 0 )
+ {
+ RMInit::logOut << "OK" << endl << endl;
+
+ parseQueryTree->printTree( 2, RMInit::logOut );
+ RMInit::logOut << endl;
+
+ parseQueryTree->getRoot()->printAlgebraicExpression();
+ cout << endl << endl;
+
+ unsigned int localOptimizationLevel = globalOptimizationLevel < parseQueryTree->getOptimizationLevel() ?
+ globalOptimizationLevel : parseQueryTree->getOptimizationLevel();
+
+ RMInit::logOut << "Optimizing query on level " << localOptimizationLevel << endl;
+ try
+ {
+ parseQueryTree->optimize( localOptimizationLevel );
+ }
+ catch( ParseInfo& info )
+ {
+ RMInit::logOut << endl << "Optimization Error" << endl;
+ info.printStatus();
+ cout << endl;
+
+ return 0;
+ }
+
+ RMInit::logOut << endl;
+ parseQueryTree->printTree( 2, RMInit::logOut );
+ RMInit::logOut << endl;
+ parseQueryTree->getRoot()->printAlgebraicExpression( RMInit::logOut );
+ RMInit::logOut << endl << endl;
+
+ RMInit::logOut << "Evaluating... " << flush;
+
+ vector<QtData*>* transColl = 0;
+
+ try
+ {
+ transColl = parseQueryTree->evaluateRetrieval();
+ }
+ catch( ParseInfo& info )
+ {
+ RMInit::logOut << endl << "Query Execution Error" << endl;
+ info.printStatus();
+ cout << endl;
+
+ return 0;
+ }
+
+ RMInit::logOut << "OK" << endl << endl;
+
+ if( timeTest )
+ {
+ gettimeofday(&stopTime, &tzp);
+
+ if(startTime.tv_usec > stopTime.tv_usec) {
+ stopTime.tv_usec += 1000000;
+ stopTime.tv_sec--;
+ }
+
+ deltaTime.tv_usec = stopTime.tv_usec - startTime.tv_usec;
+ deltaTime.tv_sec = stopTime.tv_sec - startTime.tv_sec;
+
+ cout << "Time for query processing " << deltaTime.tv_sec << " sec " << deltaTime.tv_usec << " msec " << endl;
+ }
+
+ vector<QtData*>::iterator transIter;
+ int collNum;
+ collNum = transColl->size();
+
+ cout << "The result collection has " << collNum << " entries." << endl;
+
+ if( transColl != 0 && !noOutput )
+ {
+ int i;
+
+ for( transIter = transColl->begin(), i=0; transIter != transColl->end(); transIter++, i++ )
+ {
+ QtData* mddObj = *transIter;
+
+ cout << endl << " --" << i << ". MDD object in set:" << endl << " ";
+ mddObj->printStatus();
+
+ /*vector<Tile* >* tiles = mddObj->getTiles();
+ vector<Tile* >::iterator tileIter;
+
+ for( tileIter = tiles->begin(); tileIter!=tiles->end(); tileIter++ )
+ {
+ cout << endl << " Tile" << endl;
+ (*tileIter)->printStatus();
+ }
+
+ // delete the Tile elements of the vector and the vector itself
+ // release( tiles->begin(), tiles->end() );
+ for( tileIter = tiles->begin(); tileIter!=tiles->end(); tileIter++ )
+ delete *tileIter;
+
+ delete tiles;*/
+ }
+
+ // release dynamic memory for the collection (delete MDDObjs)
+ // transColl->eraseAll();
+ delete transColl;
+
+ // delete transIter;
+ };
+
+ }
+ else
+ RMInit::logOut << " failed" << endl;
+
+ delete parseQueryTree;
+
+ //
+ // end of body
+ //
+
+ cout << "Committing transaction ... " << flush;
+ ta.commit();
+ cout << "OK" << endl;
+
+ cout << "Closing database ..." << flush;
+ db.close();
+ cout << "OK" << endl;
+ cout << "Ending O2 session ..." << endl;
+ delete myAdmin;
+ cout << "OK" << endl;
+
+ return 0;
+}
diff --git a/qlparser/test/test_qlparser.cc b/qlparser/test/test_qlparser.cc
new file mode 100644
index 0000000..7753f2c
--- /dev/null
+++ b/qlparser/test/test_qlparser.cc
@@ -0,0 +1,205 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * Test program for the RasQL parser.
+ *
+ *
+ * COMMENTS:
+ *
+ *
+ ************************************************************/
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#ifdef __GNUG__
+#include "qlparser/symtab.hh"
+#include "raslib/template_inst.hh"
+#endif
+#endif
+
+
+using namespace std;
+
+#define DEBUG_MAIN
+#include "debug-clt.hh"
+
+
+#include <iostream.h> // cout
+#include <stdio.h> // fopen, perror
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "qlparser/querytree.hh"
+
+#include "raslib/rminit.hh"
+#include "raslib/rmdebug.hh"
+
+#include "adminif.hh"
+#include "databaseif.hh"
+#include "transactionif.hh"
+
+#include "mddmgr/mddobj.hh"
+#include "mddmgr/mddcoll.hh"
+#include "mddmgr/mddcolliter.hh"
+
+// init globals for server initialization
+// RMINITGLOBALS('C')
+
+extern int yyparse();
+extern char* myExecArgv0 = "";
+extern char* beginParseString;
+extern char* iterParseString;
+
+extern QueryTree* parseQueryTree;
+
+int main( int ac, char** av )
+{
+ FILE* inFile;
+ char baseName[255];
+ char query[4096];
+
+ //
+ // read program arguments
+ //
+
+ if( ac <= 2 )
+ {
+ cout << "usage: test_qlparser basename queryfile" << endl;
+ return -1;
+ }
+
+ strcpy( baseName, av[1] );
+
+ inFile = fopen( av[2], "r" );
+
+ if( inFile == NULL )
+ {
+ cout << "Error opening file " << av[1] << endl;
+ return -1;
+ }
+
+ fread( &query, 1, 4095, inFile );
+ fclose( inFile );
+
+ cout << "Query:" << endl << endl << query << endl;
+
+ //
+ // open database, start transaction
+ //
+
+ // variables representing O2 database, ta and session
+ DatabaseIf db;
+ TransactionIf ta;
+
+ // don't forget to initialize before using AdminIf!
+ cout << "Connecting to O2 ..." << flush;
+ myExecArgv0 = av[0];
+ AdminIf* myAdmin = AdminIf::instance();
+ cout << "OK" << endl;
+
+ // connect to the database
+ cout << "Opening database " << baseName << "... " << flush;
+ db.open( baseName );
+ cout << "OK" << endl;
+
+ cout << "Starting transaction ... " << flush;
+ ta.begin(&db);
+ cout << "OK" << endl;
+
+ //
+ // body of test program
+ //
+
+ beginParseString = query;
+ iterParseString = query;
+
+ parseQueryTree = new QueryTree(); // create a query tree object...
+
+ cout << endl << "Parsing ..." << flush;
+
+ if( !yyparse() )
+ cout << " worked" << endl;
+ else
+ cout << " failed" << endl;
+
+ cout << endl;
+ parseQueryTree->printTree(2);
+ cout << endl;
+ parseQueryTree->getRoot()->printAlgebraicExpression();
+ cout << endl;
+
+ cout << "Simplifying ..." << flush;
+ try
+ {
+ parseQueryTree->getRoot()->simplify();
+ }
+ catch( ParseInfo& info )
+ {
+ info.printStatus( RMInit::logOut );
+ cout << "FAILED" << endl;
+ }
+
+ cout << "OK" << endl;
+
+ cout << endl;
+ parseQueryTree->printTree(2);
+ cout << endl;
+ parseQueryTree->getRoot()->printAlgebraicExpression();
+ cout << endl;
+
+ delete parseQueryTree;
+
+ //
+ // end of body
+ //
+
+ cout << "Committing transaction ... " << flush;
+ ta.commit();
+ cout << "OK" << endl;
+
+ cout << "Closing database ..." << flush;
+ db.close();
+ cout << "OK" << endl;
+ cout << "Ending O2 session ..." << endl;
+ delete myAdmin;
+ cout << "OK" << endl;
+
+ return 0;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/rascontrol/Makefile.am b/rascontrol/Makefile.am
new file mode 100644
index 0000000..16d4ee0
--- /dev/null
+++ b/rascontrol/Makefile.am
@@ -0,0 +1,53 @@
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+# *
+# * MODULE: rascontrol
+# * CLASS:
+# *
+# * COMMENTS:
+# *
+######################## Defines ###############################
+
+CRYPTO=../rasmgr/ras_crypto.o
+
+SRCCXX=rascontrol.cc rasmgr_utils_comm.cc rasmgrtest.cc raspasswd.cc \
+ rascontrol_class.cc rasmgr_tester.cc rasmgr_utils_conf.cc rasmgrtester_conf.cc
+
+bin_PROGRAMS=rascontrol raspasswd
+
+rascontrol_SOURCES=rascontrol.cc rascontrol_class.cc rascontrol.hh \
+ ../rasmgr/ras_crypto.cc ../rasmgr/ras_crypto.hh \
+ rasmgr_utils_conf.cc rasmgr_utils_conf.hh \
+ rasmgr_utils_comm.cc rasmgr_utils_comm.hh
+rascontrol_LDADD = ../network/libnetwork.a ../commline/libcommline.a
+
+raspasswd_SOURCES=raspasswd.cc raspasswd.hh \
+ ../rasmgr/ras_crypto.cc ../rasmgr/ras_crypto.hh \
+ rasmgr_utils_comm.cc rasmgr_utils_comm.hh \
+ rasmgr_utils_conf.cc rasmgr_utils_conf.hh
+raspasswd_LDADD = ../network/libnetwork.a ../commline/libcommline.a
+
+SUBDIRS=../network ../commline
+
+$(RECURSIVE_CLEAN_TARGETS):
+ @$(MAKE) $(AM_MAKEFLAGS) `echo $@ | sed s/-recursive/-am/`
+
diff --git a/rascontrol/rascontrol.cc b/rascontrol/rascontrol.cc
new file mode 100644
index 0000000..0b186f9
--- /dev/null
+++ b/rascontrol/rascontrol.cc
@@ -0,0 +1,341 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/**
+ * SOURCE: rascontrol.cc
+ *
+ * MODULE: rascontrol
+ * CLASS:
+ *
+ * PURPOSE:
+ * RasControl is the remote control utility for the rasmgr
+ *
+ * COMMENTS:
+ * - should normalize cmd interpretation with rasmgr: strcmp vs strncmp
+*/
+
+#define DEBUG_MAIN // to allocate static vars for trace macros
+#include "debug-clt.hh"
+
+#include "rascontrol.hh"
+#include <fstream>
+#include <signal.h>
+
+#ifndef RMANVERSION
+#error "Please specify RMANVERSION variable!"
+#endif
+
+#ifndef COMPDATE
+#error "Please specify the COMPDATE variable!"
+/*
+COMPDATE=`date +"%d.%m.%Y %H:%M:%S"`
+
+and -DCOMPDATE="\"$(COMPDATE)\"" when compiling
+*/
+#endif
+
+UserLogin userLogin;
+EditLine editLine;
+RasMgrClientComm httpClient;
+RascontrolConfig config;
+
+bool redirStdin = false;
+bool redirStdout = false;
+
+const int NOERROR = 0;
+const int CANTCONNECT = 1;
+const int LOGINERROR = 2;
+const int ACCESSDENIED = 3;
+
+// flag to indicate whether conf or auth file have been modified.
+// if true files must be saved before terminating.
+static bool confFileDirty = false;
+static bool authFileDirty = false;
+
+int interactiveWork();
+int loginOnly();
+int batchMode();
+int testLogin();
+
+int main(int argc, char **argv)
+{
+ if(config.interpretArguments(argc,argv)==false) return 1;
+
+ // /*for debug only: */ config.printDebugInfo(); return 0;
+ if(config.beQuiet()==false)
+ {
+ std::cout << "rascontrol: rasdaman server remote control utility. rasdaman v" << RMANVERSION / 1000. << " -- generated on " << COMPDATE << "." << std::endl;
+ std::cout << " Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann rasdaman GmbH." << std::endl
+ << "Rasdaman community is free software: you can redistribute it and/or modify "
+ "it under the terms of the GNU General Public License as published by "
+ "the Free Software Foundation, either version 3 of the License, or "
+ "(at your option) any later version. \n"
+ "Rasdaman community is distributed in the hope that it will be useful, "
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of "
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the "
+ "GNU General Public License for more details. \n\n";
+ std::cout << "This software contains software which is in the public domain:" << std::endl;
+ std::cout << "- openssl 0.96c (C) 1998-2002 The OpenSSL Project, (C) 1995-1998 Eric A. Young, Tim J. Hudson" << std::endl;
+ }
+ if(config.showHelp())
+ {
+ config.printHelp();
+ return 0;
+ }
+
+ if(testIsMessageDigestAvailable("MD5")==false)
+ {
+ std::cout<<"Error: Message Digest MD5 not available."<<std::endl;
+ return 2;
+ }
+
+ if(!isatty(0) )
+ redirStdin =true;
+ if(!isatty(1))
+ redirStdout=true;
+
+ httpClient.setRasMgrHost(config.getRasMgrHost(), config.getRasMgrPort());
+
+ int loginOK = (config.getLoginModus()==LGIINTERACTIV) ? userLogin.interactiveLogin() : userLogin.environmentLogin();
+
+ if(loginOK<0)
+ {
+ std::cout<<"Login error."<<std::endl;
+ return LOGINERROR;
+ }
+
+ httpClient.setUserIdentification(userLogin.getUserName(),userLogin.getEncrPass());
+
+ int answer=NOERROR;
+ switch(config.getWorkModus())
+ {
+ case WKMINTERACTIV: answer=interactiveWork(); break;
+ case WKMLOGIN : answer=loginOnly(); break;
+ case WKMBATCH : answer=batchMode(); break;
+ case WKMTESTLOGIN : answer=testLogin(); break;
+ }
+
+ if(config.beQuiet()==false)
+ std::cout<< "rascontrol terminated." <<std::endl;
+
+ return answer;
+ } // main()
+
+// check whether command fits with given keyword (case insensitive), maybe after stripping leading whitespace
+bool isCommand( const char *command, const char *key)
+ {
+ bool result;
+
+ if (command == NULL || key == NULL)
+ result = false;
+ else
+ {
+ while (*command == ' ' || *command == '\t') // skip white space; newline cannot occur
+ command++;
+ result = strcasecmp( command, key );
+ }
+
+ return result;
+ }
+
+int interactiveWork()
+ {
+ int result = 0;
+ const char *answer = NULL;
+ int comm = COMM_CONT; // COMM_* values ; should be enum
+
+ std::ofstream history;
+ bool historyFile=config.histRequest();
+
+ comm = httpClient.sendMessageGetAnswer( RASMGRCMD_HELLO, &answer );
+
+ if(answer)
+ std::cout<<" "<<answer<<std::endl;
+
+ if(comm==COMM_ERR)
+ { std::cout<<"Cannot connect to main host "<<httpClient.getRasMgrHost()<<std::endl;
+ return CANTCONNECT;
+ }
+ if(comm==COMM_ACDN)
+ { //std::cout<<"Access denied."<<std::endl;
+ return ACCESSDENIED;
+ }
+
+ // shifted here, after return, so that it always will be closed
+ if(historyFile)
+ {
+ TALK( "RasControl::interactiveWork: using history file " << config.getHistFileName() );
+ history.open(config.getHistFileName(),std::ios::out|std::ios::trunc);
+ }
+
+ do{
+ TALK( "RasControl::interactiveWork: entering new request cycle." );
+
+ const char *command=editLine.interactiveCommand(config.getPrompt());
+ if(command == NULL || strlen(command)==0) // empty cmd line
+ continue;
+
+ if(historyFile)
+ history<<command<<std::endl;
+
+ TALK( "RasControl::interactiveWork: cmd=" << command );
+
+ // send message to rasmgr & receive answer
+ const char *answer = NULL;
+ if ( (isCommand(command,"exit") == 0)
+ || (isCommand(command,"quit") == 0)
+ || (isCommand(command,"bye" ) == 0) )
+ {
+ // normalize "quit", "bye" to "exit"; do so after history to maintain original cmd there
+ comm = httpClient.sendMessageGetAnswer( RASMGRCMD_EXIT, &answer );
+ comm = COMM_EXIT; // ignore any result, we have to terminate anyway
+ }
+ else
+ {
+ comm = httpClient.sendMessageGetAnswer( command, &answer );
+ }
+
+ if(answer!=0 && strlen(answer)>0)
+ std::cout<<" "<<answer<<std::endl;
+ else
+ answer = "Internal error: cannot decode rasmgr result.";
+
+ // EXPERIMENTAL: close socket as early and as always as possible
+ //TALK( "RasControl::interactiveWork: closing socket." );
+ //httpClient.closeSocket();
+
+ TALK( "RasControl::interactiveWork: comm=" << comm );
+
+ }while( comm != COMM_EXIT && comm != COMM_ACDN); // COMM_ERR is no reason to terminate interactive session
+
+ if(historyFile)
+ history.close();
+
+ switch(comm)
+ {
+ case COMM_ERR: result = CANTCONNECT; break;
+ case COMM_ACDN: result = ACCESSDENIED; break;
+ default: result = NOERROR; break;
+ }
+ return result;
+ }
+
+int loginOnly()
+ {
+ std::cout<<userLogin.getUserName()<<':'<<userLogin.getEncrPass()<<std::endl;
+ // Thats all
+ return NOERROR;
+ }
+int batchMode()
+ {
+ int result = 0; // COMM_* values
+
+ bool fromCommandLine = strlen(config.getCommand()) ? true: false;
+ const char *prompt = !redirStdin ? config.getPrompt():"";
+
+ //std::cout<<"batch mode "<<fromCommandLine<<" comm="<<config.getCommand()<<std::endl;
+
+ int comm=0;
+ do{
+ const char *command= fromCommandLine ? config.getCommand():editLine.fromStdinCommand(prompt);
+
+ TALK( "batch: Command=" << command );
+
+ if(command == NULL ) return CANTCONNECT;
+
+ if(strlen(command)==0 )
+ if( fromCommandLine)
+ return CANTCONNECT;
+ else
+ continue;
+
+ bool printCommand=false;
+
+ if( redirStdout ) printCommand = true;
+ else
+ { if(redirStdin) printCommand = true;
+ }
+
+ if(printCommand == true)
+ std::cout<<config.getPrompt()<<command<<std::endl;
+
+ // normalize "quit", "bye" to "exit"
+ const char *answer = NULL;
+ if ( (isCommand(command,"exit") == 0)
+ || (isCommand(command,"quit") == 0)
+ || (isCommand(command,"bye" ) == 0) )
+ {
+ // normalize "quit", "bye" to "exit"; do so after history to maintain original cmd there
+ comm = httpClient.sendMessageGetAnswer( RASMGRCMD_EXIT, &answer );
+ comm = COMM_EXIT; // ignore any result, we have to terminate anyway
+ }
+ else
+ {
+ comm = httpClient.sendMessageGetAnswer( command, &answer );
+ }
+
+ if(answer==0 || strlen(answer)==0)
+ answer = "Error: cannot decode rasmgr result.";
+ else
+ {
+ if(comm==COMM_ERR)
+ std::cout<<" "<<"Cannot connect to main host."<<std::endl;
+ else if(comm==COMM_ACDN)
+ std::cout<<" "<<"Access denied by rasmgr."<<std::endl;
+ else
+ std::cout<<" "<<answer<<std::endl;
+ }
+
+ }while(fromCommandLine==false && redirStdin
+ && comm != COMM_ERR
+ && comm != COMM_ACDN
+ && comm != COMM_EXIT); //process the whole "< file"
+
+ switch(comm)
+ {
+ case COMM_ERR: result = CANTCONNECT; break;
+ case COMM_ACDN: result = ACCESSDENIED; break;
+ default: result = NOERROR; break;
+ }
+ return result;
+ }
+
+int testLogin()
+ {
+ int comm = 0; // COMM_* values
+ const char *answer = NULL;
+
+ comm = httpClient.sendMessageGetAnswer( RASMGRCMD_HELLO, &answer );
+
+ if(comm==COMM_ERR)
+ { //std::cout<<"Cannot connect to main host "<<httpClient.getRasMgrHost()<<std::endl;
+ return CANTCONNECT;
+ }
+ if(comm==COMM_ACDN)
+ { //std::cout<<"Acces denied."<<std::endl;
+ return ACCESSDENIED;
+ }
+
+ std::cout<<"Login OK."<<std::endl;
+ return NOERROR;
+ }
+
diff --git a/rascontrol/rascontrol.hh b/rascontrol/rascontrol.hh
new file mode 100644
index 0000000..feb8ad7
--- /dev/null
+++ b/rascontrol/rascontrol.hh
@@ -0,0 +1,164 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: rascontrol.hh
+ *
+ * MODULE: rascontrol
+ * CLASS:
+ *
+ * PURPOSE:
+ * RasControl is the remote control utility for the rasmgr
+ *
+ * COMMENTS:
+ *
+*/
+
+#ifndef RASCONTROL_H
+#define RASCONTROL_H
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <iostream>
+#include <string.h>
+#include <string>
+
+#include "commline/cmlparser.hh"
+
+#include "../rasmgr/ras_crypto.hh"
+#include "rasmgr_utils_comm.hh"
+#include "rasmgr_utils_conf.hh"
+
+const int WKMUNKNOWN = 0;
+const int WKMINTERACTIV = 1;
+const int WKMBATCH = 2;
+const int WKMLOGIN = 3;
+const int WKMTESTLOGIN = 4;
+const int WKMCREATE = 5;
+const int WKMTSLANG = 6;
+
+const int LGIUNKNOWN = 0;
+const int LGIINTERACTIV = 1;
+const int LGIENVIRONM = 2;
+
+const int PROMPTSING = 0;
+const int PROMPTRASC = 1;
+const int PROMPTFULL = 2;
+
+
+// ----------------
+// global constants
+// ----------------
+
+#define EOS_CHAR '\0'
+
+// rasmgr command words
+#define RASMGRCMD_EXIT "exit"
+#define RASMGRCMD_HELLO "Hello"
+#define RASMGRCMD_LIST_MODUS "list modus"
+
+
+// interim debug solution, should be replaced by std rasdaman mechanism -- now with ../rasmgr/debug.hh
+// #define TALK(a) cout << a << endl;
+//#define TALK(a) { /* TALK(a) */ }
+
+void printCommandLineHelp();
+int getCommand();
+
+int sendCommandandPrintAnswer(const char*);
+bool exitbyerror(char*);
+int createSocket();
+
+class EditLine
+ {
+ public:
+ EditLine();
+ ~EditLine();
+
+ const char *interactiveCommand(const char *prompt);
+ const char *fromStdinCommand(const char *prompt);
+
+ private:
+ char *rl_gets(const char *prompt);
+ char line[MAXMSG];
+
+ };
+
+class RascontrolConfig:public ConfigurationBase
+ {
+ public:
+ RascontrolConfig();
+
+ // false means program shouldn't continue
+ bool interpretArguments(int argc, char **argv);
+
+ int getWorkModus();
+ int getLoginModus();
+ const char* getRasMgrHost();
+ int getRasMgrPort();
+ bool histRequest();
+ const char* getHistFileName();
+ const char* getPrompt();
+ const char* getCommand();
+ bool beQuiet();
+ bool showHelp();
+
+ void printDebugInfo();
+
+ void printHelp();
+ private:
+
+ bool paramError();
+
+ int workModus;
+ int loginModus;
+
+ char rasmgrHost[100];
+ int rasmgrPort;
+ bool reqHist;
+ char histFileName[100];
+
+ int promptType;
+ char prompt[100];
+ char command[100];
+ bool quiet;
+
+ bool isCommand( const char *command, const char *key );
+
+ //-- parameters of this program
+ CommandLineParser &cmlInter;
+ CommandLineParameter &cmlHelp, &cmlHost, &cmlPort, &cmlLogin;
+#ifdef NO_OFFICIAL_RELEASE
+ CommandLineParameter &cmlHist;
+#endif
+ CommandLineParameter &cmlPrompt, &cmlTestLogin;
+ CommandLineParameter &cmlInteractive, &cmlQuiet, &cmlExecute;
+
+ };
+
+#endif
diff --git a/rascontrol/rascontrol_class.cc b/rascontrol/rascontrol_class.cc
new file mode 100644
index 0000000..dd3be0d
--- /dev/null
+++ b/rascontrol/rascontrol_class.cc
@@ -0,0 +1,398 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: rascontrol_class.hh
+ *
+ * MODULE: rascontrol
+ * CLASS: EditLine, RascontrolConfig
+ *
+ * PURPOSE:
+ * RasControl helper classes
+ *
+ * COMMENTS:
+ *
+*/
+
+#include "debug-clt.hh"
+
+#include "globals.hh"
+
+#include "rascontrol.hh"
+
+#include <readline/readline.h>
+#include <readline/history.h>
+
+#define READLINELIB
+
+/*
+// if we have readline library on this machine ...
+#ifdef READLINELIB
+
+extern "C"
+{
+char * rl_gets (char *prompt);
+char * readline(char *prompt);
+void add_history (char * line_read);
+int rl_insert();
+int rl_bind_key (int KEY, int (*FUNCTION)());
+void using_history ();
+}
+
+#endif
+*/
+
+extern UserLogin userLogin;
+
+//int readWholeMessage(int socket,char *destBuffer,int buffSize);
+//int writeWholeMessage(int socket,char *destBuffer,int buffSize);
+
+EditLine::EditLine()
+ {
+ line[0]= EOS_CHAR;
+
+#ifdef READLINELIB
+ using_history ();
+ rl_bind_key ('\t', rl_insert);
+#endif
+ }
+EditLine::~EditLine()
+ {
+ }
+
+const char *EditLine::interactiveCommand(const char *prompt)
+ {
+#ifdef READLINELIB
+ char *rasp=rl_gets (prompt);
+
+#else
+ std::cout<<prompt<<std::flush;
+ char *rasp=fgets(line,MAXMSG-1,stdin);
+
+#endif
+
+ if(rasp==0) return 0;
+ strcpy(line, rasp);
+ return line;
+
+ }
+
+const char *EditLine::fromStdinCommand(const char* prompt)
+ {
+ if(prompt) std::cout<<prompt<<std::flush;
+ char *rasp=fgets(line,MAXMSG-1,stdin);
+
+ if(rasp==0) { return 0;}
+
+ int i;
+ for(i=0;line[i];i++)
+ {
+ if(line[i]=='\r' || line[i]=='\n') {line[i]=0; break;}
+ }
+
+ for(i=0;line[i];i++)
+ {
+ if(line[i]==' ' || line[i]=='\t') continue;
+ break;
+ }
+ return line +i;
+ }
+
+char * EditLine::rl_gets(const char *prompt)
+ {
+#ifdef READLINELIB
+ static char *line_read = (char *)NULL;
+
+ /* If the buffer has already been allocated, return the memory
+ to the free pool. */
+
+ if (line_read)
+ {
+ free (line_read);
+ line_read = (char *)NULL;
+ }
+
+ /* Get a line from the user. */
+ line_read = readline ((char*)prompt);
+
+ /* If the line has any text in it, save it on the history. */
+ if (line_read && *line_read)
+ add_history (line_read);
+
+ return (line_read);
+#else
+ return " ";
+#endif
+
+ }
+
+//################ Config ##################################
+RascontrolConfig::RascontrolConfig() :
+ cmlInter (CommandLineParser::getInstance()),
+ cmlHost (cmlInter.addStringParameter(CommandLineParser::noShortName,"host", "<name> name of host where master rasmgr runs", DEFAULT_HOSTNAME)),
+ cmlPort (cmlInter.addLongParameter(CommandLineParser::noShortName,"port", "<nnnn> rasmgr port",DEFAULT_PORT)),
+ cmlLogin (cmlInter.addFlagParameter('l',"login", "just login prompt, used to set the environment variable RASLOGIN")),
+ cmlTestLogin (cmlInter.addFlagParameter('t',"testlogin", "test if environment variable RASLOGIN is OK to login")),
+ cmlInteractive (cmlInter.addFlagParameter('e',"interactive", "interactive mode, login from environment variable RASLOGIN")),
+ cmlQuiet (cmlInter.addFlagParameter('q',"quiet", "quiet, don't print header (default on for -login and -testlogin)")),
+#ifdef NO_OFFICIAL_RELEASE
+ cmlHist (cmlInter.addStringParameter(CommandLineParser::noShortName, "hist", "<file-name> used to store your commands in file, as help for batch file.")),
+#endif
+ cmlPrompt (cmlInter.addStringParameter(CommandLineParser::noShortName, "prompt", "<nnn> change rascontrol prompt as following:\n\t\t 0 - prompt '>'\n\t\t 1 - prompt 'rasc>'\n\t\t 2 - prompt 'user:host>'","2")),
+ cmlExecute (cmlInter.addFlagParameter('x',"execute", "batch mode, login from environment variable RASLOGIN\n <rasmgr-cmd>\ta rasmgr command (only in batch mode)\n\t\tif no command if provided, command is read from stdin\n\t\t(used for batch mode with '<inputfile')")),
+ cmlHelp (cmlInter.addFlagParameter('h',"help", "this help"))
+ {
+ workModus = WKMINTERACTIV;
+ loginModus= LGIINTERACTIV;
+
+// done by default value of command line parameters
+// strcpy(rasmgrHost, cmlHost.getValueAsString());
+// rasmgrPort = cmlPort.getValueAsLong();
+
+ reqHist = false;
+ strcpy(histFileName,"rascontrol.hist");
+
+ promptType=PROMPTFULL;
+ prompt[0]= EOS_CHAR;
+ command[0]= EOS_CHAR;
+ quiet =false;
+ }
+
+bool RascontrolConfig::interpretArguments(int argc, char **argv)
+ {
+ //FIXME workarround for batch mode commands given to rascontrol
+ //in current version it is generated an error if a parameter has many values:
+ //e.g. -a c d f where c,d,f are values(not parameters)
+ int lastArg = argc;
+ string shortX = string("") + CommandLineParser::ShortSign + cmlExecute.getShortName();
+ string longX = string("") + CommandLineParser::LongSign + cmlExecute.getLongName();
+
+ for(lastArg = 1;lastArg<argc;lastArg++)
+ {
+ if( (strcmp(argv[lastArg], shortX.c_str())==0) ||
+ (strcmp(argv[lastArg], longX.c_str())==0) )
+ { lastArg++;
+ break;
+ }
+ }
+
+ //std::cout<<"argc="<<argc<<" lastarg="<<lastArg<<std::endl;
+
+ try
+ {
+ if(lastArg != argc)
+ cmlInter.processCommandLine(lastArg, argv);
+ else
+ cmlInter.processCommandLine(argc, argv);
+ }
+ catch(CmlException& err)
+ {
+ std::cout << "Command Line Parsing Error:" << std::endl << err.what() << std::endl;
+ return false;
+ }
+
+
+
+ if( cmlHelp.isPresent() ) {
+ //we stop processing
+ return true;
+ }
+
+ try
+ {
+ rasmgrPort = cmlPort.getValueAsLong();
+ }
+ catch(CmlException& err)
+ {
+ std::cout << "Command Line Parsing Error:" << std::endl << err.what() << std::endl;
+ return false;
+ }
+
+ strcpy(rasmgrHost, cmlHost.getValueAsString());
+
+ if( cmlLogin.isPresent() )
+ {
+ workModus = WKMLOGIN;
+ quiet = true;
+ }
+
+ if( cmlQuiet.isPresent() )
+ {
+ quiet = true;
+ }
+
+ if( cmlTestLogin.isPresent() )
+ {
+ if(workModus==WKMINTERACTIV) { workModus = WKMTESTLOGIN;
+ loginModus = LGIENVIRONM;
+ }
+ else return paramError();
+ quiet = true;
+ }
+
+ if( cmlInteractive.isPresent() )
+ {
+ if(workModus==WKMINTERACTIV) loginModus = LGIENVIRONM;
+ else return paramError();
+ }
+
+ if( cmlExecute.isPresent() )
+ {
+ if(workModus==WKMINTERACTIV)
+ { loginModus = LGIENVIRONM;
+ workModus = WKMBATCH;
+
+ for(int i=lastArg;i<argc;i++)
+ {
+ strcat(command,argv[i]);
+ strcat(command," ");
+ }
+ }
+ else return paramError();
+ }
+
+#ifdef NO_OFFICIAL_RELEASE
+ if( cmlHist.isPresent() )
+ {
+ reqHist = true;
+ strcpy(histFileName, cmlHist.getValueAsString());
+ }
+#endif
+
+ try
+ {
+ promptType = cmlPrompt.getValueAsLong();
+ }
+ catch(CmlException& err)
+ {
+ std::cout << "Command Line Parsing Error:" << std::endl << err.what() << std::endl;
+ return false;
+ }
+
+ if(promptType<PROMPTSING || promptType>PROMPTFULL) promptType=PROMPTFULL;
+
+ return true;
+ }
+
+bool RascontrolConfig::paramError()
+ {
+ std::cout<<"Invalid parameter combination in command line!"<<std::endl;
+ return false;
+ }
+
+void RascontrolConfig::printHelp()
+ {
+ std::cout <<"Usage: " << std::endl << "\trascontrol\t["
+ << CommandLineParser::LongSign << cmlHelp.getLongName() << "]["
+ << CommandLineParser::LongSign << cmlHost.getLongName() << "<mainhost>]["
+ << CommandLineParser::LongSign << cmlPort.getLongName() << " <nn>]["
+#ifdef NO_OFFICIAL_RELEASE
+ << CommandLineParser::LongSign << cmlHist.getLongName() << " <file>]["
+#endif
+ << CommandLineParser::LongSign << cmlPrompt.getLongName() << " <n>]["
+ << CommandLineParser::LongSign << cmlQuiet.getLongName() << "]\n\t\t\t["
+ << CommandLineParser::LongSign << cmlLogin.getLongName() << "|"
+ << CommandLineParser::LongSign << cmlTestLogin.getLongName() << "|"
+ << CommandLineParser::LongSign << cmlInteractive.getLongName() << "|"
+ << CommandLineParser::LongSign << cmlExecute.getLongName() << " <rasmgr-command>]"
+ << std::endl;
+ std::cout << "Option description:" << std::endl;
+ cmlInter.printHelp();
+ std::cout<<std::endl;
+ }
+
+int RascontrolConfig::getWorkModus()
+ { return workModus;
+ }
+int RascontrolConfig::getLoginModus()
+ { return loginModus;
+ }
+
+const char* RascontrolConfig::getRasMgrHost()
+ { return rasmgrHost;
+ }
+int RascontrolConfig::getRasMgrPort()
+ { return rasmgrPort;
+ }
+bool RascontrolConfig::histRequest()
+ { return reqHist;
+ }
+bool RascontrolConfig::beQuiet()
+ { return quiet;
+ }
+
+bool RascontrolConfig::showHelp()
+ { return cmlHelp.isPresent();
+ }
+
+const char* RascontrolConfig::getHistFileName()
+ { return histFileName;
+ }
+const char* RascontrolConfig::getPrompt()
+ {
+ if(prompt[0]!= EOS_CHAR) return prompt;
+
+ switch(promptType)
+ {
+ case PROMPTSING : strcpy(prompt,"> ");
+ break;
+ case PROMPTRASC : strcpy(prompt,"rasc> ");
+ break;
+ case PROMPTFULL : sprintf(prompt,"%s:%s> ",userLogin.getUserName(),rasmgrHost);
+ break;
+ }
+ return prompt;
+ }
+const char* RascontrolConfig::getCommand()
+ { return command;
+ }
+
+void RascontrolConfig::printDebugInfo()
+ {
+ std::cout<<"Working modus:.";
+ switch(workModus)
+ {
+ case WKMUNKNOWN : std::cout<<"unknown";break;
+ case WKMINTERACTIV : std::cout<<"interactiv";break;
+ case WKMBATCH : std::cout<<"batch";break;
+ case WKMLOGIN : std::cout<<"login";break;
+ }
+
+ std::cout<<std::endl<<"Login modus:...";
+ switch(loginModus)
+ {
+ case LGIUNKNOWN : std::cout<<"unknown";break;
+ case LGIINTERACTIV : std::cout<<"interactiv";break;
+ case LGIENVIRONM : std::cout<<"environm";break;
+ }
+
+ std::cout<<std::endl<<"Rasmgr:........"<<rasmgrHost<<":"<<rasmgrPort;
+
+ std::cout<<std::endl<<"History:......."<<(reqHist ? histFileName : "not requested");
+
+ std::cout<<std::endl<<"Prompt:........"<<getPrompt();
+
+ std::cout<<std::endl<<"Command:......."<<command;
+
+ std::cout<<std::endl;
+ }
+
diff --git a/rascontrol/rasmgr_tester.cc b/rascontrol/rasmgr_tester.cc
new file mode 100644
index 0000000..f9523d0
--- /dev/null
+++ b/rascontrol/rasmgr_tester.cc
@@ -0,0 +1,171 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: rasmgr_tester.cc
+ *
+ * MODULE: rascontrol
+ * CLASS: RasMgrTester
+ *
+ * PURPOSE:
+ *
+ * COMMENTS:
+ *
+*/
+
+#include "debug-clt.hh"
+#include "rascontrol.hh"
+#include "rasmgr_tester.hh"
+
+
+RasMgrTester::RasMgrTester()
+ {
+
+ command = new char[MAXCOMMAND];
+ expected= new char[MAXMSGRASCONTROL];
+
+ }
+RasMgrTester::~RasMgrTester()
+ {
+ delete[] command;
+ delete[] expected;
+ }
+
+void RasMgrTester::setRasMgrHost(const char *rasmgrHost, int rasmgrPort)
+ {
+ rasmgrClient.setRasMgrHost(rasmgrHost, rasmgrPort); // The first argument is the RasMgr host
+ userLogin.quickLogin();
+ rasmgrClient.setUserIdentification(userLogin.getUserName(),userLogin.getEncrPass());
+ }
+
+bool RasMgrTester::mayWeDoTest()
+ {
+ int result = 0; // COMM_* values
+ const char *modus = NULL;
+
+ result = rasmgrClient.sendMessageGetAnswer( RASMGRCMD_LIST_MODUS, &modus );
+ const char *expect = "RasMGR running as master in test modus";
+ if(modus == NULL) return false; //if connection refused, no rasmgr running
+ //cout<<"A:"<<modus<<endl;
+ //cout<<"E:"<<expect <<endl;
+ if(strcasecmp(modus,expect)!=0)
+ { //cout<<"RasMgr is not running in test modus, so we can't do the test!"<<endl;
+ return false;
+ }
+ return true;
+ }
+
+bool RasMgrTester::loadCommand(const char *x)
+ { strncpy(command,x,100);
+ return true;
+ }
+bool RasMgrTester::loadCommand(std::ifstream &ifs)
+ {
+ command[0] = EOS_CHAR;
+ ifs.getline(command,MAXCOMMAND);
+ clearCR(command);
+ return command[0] ? true:false;
+ }
+
+bool RasMgrTester::loadExpected(const char *x)
+ {
+ strncpy(expected,x,MAXMSGRASCONTROL);
+ clearFinalCRLF(expected);
+ return true;
+ }
+bool RasMgrTester::loadExpected(std::ifstream &ifs,char delim)
+ {
+ int i;
+ const std::streamoff off=-1;
+ for(i=0;i<MAXMSGRASCONTROL;i++)
+ { char c;
+ ifs.read(&c,1);
+ if(!ifs) break;
+
+ if(c==delim) { ifs.seekg(off, std::ios::cur);
+ break;
+ }
+ expected[i]=c;
+ }
+ expected[i]=0;
+
+ clearFinalCRLF(expected);
+
+ return strlen(expected) ? true:false;
+ }
+
+bool RasMgrTester::sendCommandGetAnswer()
+ {
+ int result = 0; // COMM_* values
+ const char *r = NULL;
+
+ result = rasmgrClient.sendMessageGetAnswer(command, &r );
+ if(r == NULL)
+ return false;
+
+ return true;
+ }
+
+bool RasMgrTester::isAnswerOK()
+ { const char *r=rasmgrClient.getBody();
+
+ return strcasecmp(r,expected)==0 ? true:false;
+ }
+const char* RasMgrTester::getCommand()
+ { return command;
+ }
+
+const char* RasMgrTester::getExpected()
+ { return expected;
+ }
+
+const char* RasMgrTester::getAnswer()
+ { return rasmgrClient.getBody();
+ }
+
+bool RasMgrTester::saveCommand(std::ofstream &ofs)
+ { ofs<<command<<endl;
+ return true;
+ }
+bool RasMgrTester::saveExpected(std::ofstream &ofs)
+ { ofs<<expected<<endl;
+ return true;
+ }
+bool RasMgrTester::saveAnswer(std::ofstream &ofs)
+ { ofs<<rasmgrClient.getBody()<<endl;
+ return true;
+ }
+
+void RasMgrTester::clearCR(char *line)
+ { // This func clears the CR from the end of the line read by getline
+ int len = strlen(line);
+ if(len==0) return;
+ if(line[len-1]=='\r') line[len-1]=0;
+ }
+void RasMgrTester::clearFinalCRLF(char *string)
+ { // reading the expected answer from a file can bring and ending CRLF, which has to be removed
+ int len = strlen(string);
+ if(len<2) return;
+ if(string[len-1]=='\r' || string[len-1]=='\n') string[len-1]=0;
+ if(string[len-2]=='\r' || string[len-2]=='\n') string[len-2]=0;
+ }
+
diff --git a/rascontrol/rasmgr_tester.hh b/rascontrol/rasmgr_tester.hh
new file mode 100644
index 0000000..b9d36f9
--- /dev/null
+++ b/rascontrol/rasmgr_tester.hh
@@ -0,0 +1,85 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: rasmgr_tester.hh
+ *
+ * MODULE: rascontrol
+ * CLASS: RasMgrTester
+ *
+ * COMMENTS:
+ *
+ *
+*/
+
+#ifndef RASMGR_TESTER_HH
+#define RASMGR_TESTER_HH
+
+#include "rasmgr_utils_comm.hh"
+#include <fstream>
+
+class RasMgrTester
+ {
+ public:
+ RasMgrTester();
+ ~RasMgrTester();
+ void setRasMgrHost(const char *rasmgrHost, int port);
+ bool mayWeDoTest();
+
+ // load command from string
+ bool loadCommand(const char*);
+
+ // load command from file, one line only
+ bool loadCommand(std::ifstream&);
+
+ // load expected from string
+ bool loadExpected(const char*);
+
+ // load expected from file, until delim, without it
+ // if delim==0, until EOF
+ bool loadExpected(std::ifstream&,char delim);
+
+ bool sendCommandGetAnswer();
+
+ bool isAnswerOK();
+
+ const char* getCommand();
+ const char* getExpected();
+ const char* getAnswer();
+
+ bool saveCommand(std::ofstream&);
+ bool saveExpected(std::ofstream&);
+ bool saveAnswer(std::ofstream&);
+
+ private:
+ // STL ifstream::getline() drops the '\n', but let's a '\r' live
+ // so this function clears this stupid '\r'
+ void clearCR(char *line);
+ void clearFinalCRLF(char *string);
+ UserLogin userLogin;
+ RasMgrClientComm rasmgrClient;
+
+ char *command;
+ char *expected;
+
+ };
+#endif
diff --git a/rascontrol/rasmgr_utils_comm.cc b/rascontrol/rasmgr_utils_comm.cc
new file mode 100644
index 0000000..01b504c
--- /dev/null
+++ b/rascontrol/rasmgr_utils_comm.cc
@@ -0,0 +1,359 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: rasmgr_utils_comm.cc
+ *
+ * MODULE: rascontrol
+ * CLASS: RasMgrClientComm, UserLogin
+ *
+ * PURPOSE:
+ * rasmgr-Client communication and login classes
+ *
+ * COMMENTS:
+ *
+ *
+*/
+
+// trace macros
+#include "debug-clt.hh"
+
+#include "globals.hh"
+
+#include "rasmgr_utils_comm.hh"
+#include "rascontrol.hh"
+
+
+RasMgrClientComm::RasMgrClientComm()
+ {
+ rasmgrSocket=-1;
+ userName[0]= EOS_CHAR;
+ encrPass[0]= EOS_CHAR;
+ rasmgrHost[0]= EOS_CHAR;
+ answerBody=answerMessage;
+ answerMessage[0]= EOS_CHAR;
+ }
+
+RasMgrClientComm::~RasMgrClientComm()
+ {
+ }
+void RasMgrClientComm::setRasMgrHost(const char *rasmgrHost, int rasmgrPort)
+ {
+ strcpy(this->rasmgrHost,rasmgrHost);
+ this->rasmgrPort=rasmgrPort;
+ }
+
+const char* RasMgrClientComm::getRasMgrHost()
+ { return rasmgrHost;
+ }
+
+void RasMgrClientComm::setUserIdentification(const char *userName, const char *encrPass)
+ {
+ strcpy(this->userName,userName);
+ strcpy(this->encrPass,encrPass);
+ }
+
+int RasMgrClientComm::openSocket()
+ {
+ ENTER("RasMgrClientComm::openSocket: enter." );
+
+ // if open already, close beforehand
+ if(rasmgrSocket!=-1)
+ {
+ TALK ("RasMgrClientComm::openSocket: socket was open, closing it." );
+ closeSocket();
+ }
+
+ struct protoent *getprotoptr = getprotoptr=getprotobyname("tcp"); // FIXME: what is this???
+ struct hostent *hostinfo = gethostbyname(rasmgrHost);
+
+ if(hostinfo==NULL)
+ {
+ TALK ("RasMgrClientComm::openSocket: leave. unknown host " << rasmgrHost );
+ return -1;
+ }
+
+ sockaddr_in internetAddress;
+ internetAddress.sin_family=AF_INET;
+ internetAddress.sin_port=htons(rasmgrPort);
+ internetAddress.sin_addr=*(struct in_addr*)hostinfo->h_addr;
+
+ rasmgrSocket=socket(PF_INET,SOCK_STREAM,getprotoptr->p_proto);
+
+ if(rasmgrSocket<0)
+ {
+ int tempErrno = errno;
+ TALK ("RasMgrClientComm::openSocket: leave. error opening socket: " << strerror(tempErrno ) );
+ return -1;
+ }
+
+ if(0>connect(rasmgrSocket,(struct sockaddr*)&internetAddress,sizeof(internetAddress)))
+ {
+ int tempErrno = errno;
+ TALK ("RasMgrClientComm::openSocket: leave. error connecting socket: " << strerror(tempErrno ) );
+ return -1;
+ }
+
+ LEAVE( "RasMgrClientComm::openSocket: leave. ok." );
+ return 0;
+ }
+
+void RasMgrClientComm::closeSocket()
+ {
+ ENTER( "RasMgrClientComm::closeSocket. enter." );
+ if(rasmgrSocket >0)
+ {
+ TALK( "RasMgrClientComm::closeSocket. closing, socket=" << rasmgrSocket );
+ close(rasmgrSocket);
+ rasmgrSocket=-1;
+ }
+ LEAVE( "RasMgrClientComm::closeSocket. leave." );
+ }
+
+int RasMgrClientComm::sendMessage(const char *message)
+ {
+ char request[MAXMSG];
+ int result = COMM_CONT; // was: 0, but this is same value
+
+ ENTER( "RasMgrClientComm::sendMessage: enter. message=" << message );
+
+ sprintf(request, "POST rascontrol HTTP/1.1\r\nAccept: text/plain\r\nUserAgent: rascontrol/2.0");
+ sprintf(request+strlen(request),"\r\nAuthorization: ras %s:%s",userName,encrPass);//"rasadmin","d293a15562d3e70b6fdc5ee452eaed40");
+ sprintf(request+strlen(request),"\r\nContent length: %d\r\n\r\n%s ",strlen(message)+1,message);
+
+ int reqLen=strlen(request)+1; // including final '\0'!!
+ if(writeWholeMessage(rasmgrSocket,request,reqLen)<reqLen)
+ { closeSocket(); // redundant, but ok as safety measure^
+ TALK( "RasMgrClientComm::sendMessage: cannot write, socket closed." );
+ result = COMM_ERR;
+ }
+
+ LEAVE( "RasMgrClientComm::sendMessage: leave. result=" << result );
+ return result;
+ }
+
+const char* RasMgrClientComm::readMessage()
+ {
+ ENTER( "RasMgrClientComm::readMessage: enter." );
+
+ if(readWholeMessage(rasmgrSocket,answerMessage,MAXMSGRASCONTROL)<0)
+ { closeSocket(); // redundant, but ok as safety measure^
+ TALK( "RasMgrClientComm::readMessage: cannot read message from rasmgr." );
+ answerBody=answerMessage;
+ answerMessage[0] = EOS_CHAR;
+ return NULL;
+ }
+
+ answerMessage[MAXMSGRASCONTROL-1]='\0';
+
+ answerBody=strstr(answerMessage,"\r\n\r\n");
+ if(answerBody)
+ { *answerBody=0;
+ answerBody+=4;
+ }
+ else
+ answerBody=answerMessage+strlen(answerMessage);
+
+ LEAVE( "RasMgrClientComm::readMessage: leave. answerBody=" << answerBody );
+ return answerBody;
+ }
+
+const char* RasMgrClientComm::getHeader()
+ {
+ return answerMessage;
+ }
+
+const char* RasMgrClientComm::getBody()
+ {
+ return answerBody;
+ }
+
+// bugfix: socket was not closed in case of send or receive error (was done in subroutines, dispersed)
+int RasMgrClientComm::sendMessageGetAnswer(const char *message, const char **responsePtr)
+ {
+ int result = COMM_CONT; // actually, in the end COMM_* from rasmgr_utils_comm.hh; COMM_CONT means OK
+ const char *rcvMsg = NULL; // message ptr delivered by readMessage()
+
+ ENTER( "RasMgrClientComm::sendMessageGetAnswer: enter. message=" << message );
+
+ TALK( "RasMgrClientComm::sendMessageGetAnswer: opening socket." );
+ result = openSocket(); // open socket to rasmgr
+ if ( result < 0 ) // open went wrong?
+ {
+ TALK( "RasMgrClientComm::sendMessageGetAnswer: cannot open socket." );
+ result = COMM_ERR;
+ }
+ else // we have a good socket, proceed
+ {
+ result = sendMessage(message); // send message to rasmgr, get a COMM_* answer
+ if ( result == COMM_CONT ) // "continue, no error"
+ rcvMsg = readMessage(); // receive result from rasmgr
+ result = ( result == COMM_CONT && rcvMsg != NULL) ? COMM_CONT : COMM_ERR;
+ // FIXME: should be refined
+ TALK( "RasMgrClientComm::sendMessageGetAnswer: closing socket." );
+ closeSocket(); // close socket again, in any case
+ // (due to current implementation, may have been closed before, no problem)
+ }
+
+ if (result == COMM_CONT && rcvMsg != NULL)
+ {
+ rcvMsg = stripBlanks( rcvMsg );
+ *responsePtr = rcvMsg;
+ }
+
+ LEAVE( "RasMgrClientComm::sendMessageGetAnswer: leave. result=" << result );
+ return result;
+ }
+
+// strip leading blanks from message string
+const char* RasMgrClientComm::stripBlanks(const char *r)
+ {
+ if (r==NULL)
+ return NULL;
+
+ const char *s = r;
+ while ( *s == ' ' || *s == '\t' )
+ s++;
+
+ return s;
+ }
+
+int RasMgrClientComm::writeWholeMessage(int socket,char *destBuffer,int buffSize)
+ {
+ ENTER( "RasMgrClientComm::writeWholeMessage: enter. socket=" << socket );
+
+ // we write the whole message, including the ending '\0', which is already in
+ // the buffSize provided by the caller
+ int totalLength=0;
+ int writeNow;
+ while(1)
+ {
+ writeNow = write(socket,destBuffer+totalLength,buffSize-totalLength);
+ if(writeNow == -1)
+ { if(errno == EINTR) continue; // read was interrupted by signal
+
+ LEAVE( "RasMgrClientComm::writeWholeMessage: leave. EINTR." );
+ return -1; // another error
+ }
+ totalLength+=writeNow;
+
+ if( totalLength==buffSize ) break; // THE END
+ }
+
+ LEAVE( "RasMgrClientComm::writeWholeMessage: leave. totalLength=" << totalLength );
+ return totalLength;
+ }
+
+int RasMgrClientComm::readWholeMessage(int socket,char *destBuffer,int buffSize)
+ {
+ ENTER( "RasMgrClientComm::readWholeMessage: enter. socket=" << socket );
+
+ // we read what is comming in until we encounter a '\0'
+ // this is our end-sign.
+ int totalLength=0;
+ int redNow;
+ while(1)
+ {
+ redNow = read(socket,destBuffer+totalLength,buffSize-totalLength);
+ if(redNow == -1)
+ { if(errno == EINTR) continue; // read was interrupted by signal
+
+ LEAVE( "RasMgrClientComm::readWholeMessage: leave. EINTR." );
+ return -1; // another error
+ }
+ totalLength+=redNow;
+
+ if(destBuffer[totalLength-1]==0) break; // THE END
+ }
+
+ LEAVE( "RasMgrClientComm::readWholeMessage: leave. totalLength=" << totalLength );
+ return totalLength;
+ }
+
+
+
+//################################################################################
+UserLogin::UserLogin()
+ {
+ userName[0]= EOS_CHAR;
+ encrPass[0]= EOS_CHAR;
+ }
+UserLogin::~UserLogin()
+ {
+ }
+int UserLogin::interactiveLogin()
+ {
+ std::cerr<<"Login name: ";
+ char *rasp=fgets(userName,99,stdin);
+ if(!rasp) return -1;
+ //strtok(userName,"\r\n"); //removes the ending \r\n
+
+ for(int i=0;userName[i];i++)
+ {
+ if(userName[i]==' ' || userName[i]=='\t' || userName[i]=='\r' || userName[i]=='\n')
+ { userName[i]=0;break;
+ }
+ }
+
+ char *plainPass=getpass(" Password: ");
+ messageDigest(plainPass,encrPass,"MD5");
+ for(int i=0;i<strlen(plainPass);i++) plainPass[i]=0;
+ std::cerr<<std::endl;
+
+ // cout<<"name="<<username<<" pass="<<encrPass<<endl;
+ return 0;
+ }
+int UserLogin::environmentLogin()
+ {
+ char *s=getenv("RASLOGIN");
+ if(s==NULL) return -1;
+ int i;
+
+ for(i=0;i<99 && *s!=':' && *s ;i++,s++)
+ {
+ userName[i]=*s;
+ }
+ userName[i]=0;
+
+ if(*s != ':') return -1;
+
+ s++;
+ strcpy(encrPass,s);
+ return 0;
+ }
+
+int UserLogin::quickLogin()
+ {
+ strcpy(userName,"rasadmin");
+ messageDigest("rasadmin",encrPass,"MD5");
+ return 0;
+ }
+
+const char *UserLogin::getUserName()
+ {
+ return userName;
+ }
+const char *UserLogin::getEncrPass()
+ {
+ return encrPass;
+ }
+
diff --git a/rascontrol/rasmgr_utils_comm.hh b/rascontrol/rasmgr_utils_comm.hh
new file mode 100644
index 0000000..008ad3b
--- /dev/null
+++ b/rascontrol/rasmgr_utils_comm.hh
@@ -0,0 +1,127 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: rasmgr_utils_comm.hh
+ *
+ * MODULE: rascontrol
+ * CLASS: RasMgrClientComm, UserLogin
+ *
+ * PURPOSE:
+ * rasmgr-Client communication and login classes
+ *
+ * COMMENTS:
+ * - RASMGRPORT should have central definition outside
+ *
+*/
+#ifndef RASMGR_UTILS_COMM_HH
+#define RASMGR_UTILS_COMM_HH
+
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <iostream>
+#include <string.h>
+
+#include "../rasmgr/ras_crypto.hh"
+
+// now defined vid -D as compile flag -- PB 2003-sep-03
+// const int RMANVERSION = 5100;
+
+const int RASMGRPORT = 7001;
+extern const char* RASMGRPORTS;
+extern const char* RASMGRHOST;
+
+
+const int MAXMSG = 2048;
+const int MAXCOMMAND = 100;
+const int MAXMSGRASCONTROL = 20000;
+
+const int MAXUSERNAME = 100;
+const int MAXENCRPASS = 35;
+const int MAXHOSTNAME = 100;
+
+const int COMM_CONT = 0;
+const int COMM_SEND = 1;
+const int COMM_EXIT = 2;
+const int COMM_ERR = 3;
+const int COMM_ACDN = 4;
+
+class RasMgrClientComm
+ {
+ public:
+ RasMgrClientComm();
+ ~RasMgrClientComm();
+
+ void setRasMgrHost(const char *rasmgrHost, int rasmgrPort);
+ const char* getRasMgrHost();
+ void setUserIdentification(const char *userName, const char *encrPass);
+
+ int openSocket();
+ void closeSocket();
+
+ int sendMessage(const char *message);
+ int sendMessageGetAnswer(const char *message, const char **responsePtr);
+ const char* readMessage();
+ const char* getHeader();
+ const char* getBody();
+
+ private:
+ int writeWholeMessage(int socket,char *destBuffer,int buffSize);
+ int readWholeMessage(int socket,char *destBuffer,int buffSize);
+ const char *stripBlanks(const char*);
+
+ char answerMessage[MAXMSGRASCONTROL];
+ char *answerBody;
+
+ char userName[MAXUSERNAME];
+ char encrPass[MAXENCRPASS];
+
+ int rasmgrSocket;
+ char rasmgrHost[MAXHOSTNAME];
+ int rasmgrPort;
+ };
+
+//#####################################################################
+class UserLogin
+ {
+ public:
+ UserLogin();
+ ~UserLogin();
+ int interactiveLogin();
+ int environmentLogin();
+ int quickLogin();
+ const char *getUserName();
+ const char *getEncrPass();
+ private:
+
+ char userName[MAXUSERNAME];
+ char encrPass[MAXENCRPASS];
+ };
+
+#endif
diff --git a/rascontrol/rasmgr_utils_conf.cc b/rascontrol/rasmgr_utils_conf.cc
new file mode 100644
index 0000000..8cb3775
--- /dev/null
+++ b/rascontrol/rasmgr_utils_conf.cc
@@ -0,0 +1,71 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: rasmgr_utils_conf.hh
+ *
+ * MODULE: rascontrol
+ * CLASS: ConfigurationBase
+ *
+ * PURPOSE:
+ * Base class for other configuration classes, to interpret commandline arguments and environment settings
+ *
+ * COMMENTS:
+ *
+*/
+
+#include "debug-clt.hh"
+
+#include "rasmgr_utils_conf.hh"
+
+ConfigurationBase::ConfigurationBase()
+ {
+ }
+
+bool ConfigurationBase::interpretArguments(int argc, char **argv)
+ {
+ return false;
+ }
+
+
+int ConfigurationBase::checkArguments( int argc, char** argv, const char* searchText, int& optionValueIndex )
+{
+ int found = 0;
+ int i=1;
+
+ while( !found && i<argc )
+ found = !strcmp( searchText, argv[i++] );
+
+ if( found && i<argc && !strchr(argv[i],'-') )
+ optionValueIndex = i;
+ else
+ optionValueIndex = 0;
+
+ return found;
+}
+
+
+void ConfigurationBase::printHelp()
+ {
+ std::cout<<"Help not available..."<< std::endl;
+ }
+
diff --git a/rascontrol/rasmgr_utils_conf.hh b/rascontrol/rasmgr_utils_conf.hh
new file mode 100644
index 0000000..676abed
--- /dev/null
+++ b/rascontrol/rasmgr_utils_conf.hh
@@ -0,0 +1,61 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: rasmgr_utils_conf.hh
+ *
+ * MODULE: rascontrol
+ * CLASS: ConfigurationBase
+ *
+ * PURPOSE:
+ * Base class for other configuration classes, to interpret commandline arguments and environment settings
+ *
+ * COMMENTS:
+ *
+ *
+*/
+#ifndef RASMGR_UTILS_CONF_HH
+#define RASMGR_UTILS_CONF_HH
+
+// This is the base class for every programs configuration class
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <iostream>
+
+class ConfigurationBase
+ {
+ public:
+ ConfigurationBase();
+
+ // false means program shouldn't continue
+ virtual bool interpretArguments(int argc, char **argv);
+
+ protected:
+
+ int checkArguments( int argc, char** argv, const char* searchText, int& optionValueIndex );
+
+ virtual void printHelp();
+
+ };
+
+#endif
diff --git a/rascontrol/raspasswd.cc b/rascontrol/raspasswd.cc
new file mode 100644
index 0000000..be7c91a
--- /dev/null
+++ b/rascontrol/raspasswd.cc
@@ -0,0 +1,241 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: raspasswd.cc
+ *
+ * MODULE: rascontrol
+ * CLASS:
+ *
+ * PURPOSE:
+ * RasDaMan password utility
+ *
+ * COMMENTS:
+ *
+ *
+*/
+
+// for trace macros
+#define DEBUG_MAIN
+#include "debug-clt.hh"
+
+#include "globals.hh"
+
+#include "rascontrol.hh"
+#include "raspasswd.hh"
+#include "rasmgr_utils_comm.hh"
+
+#ifndef RMANVERSION
+#error "Please specify the RMANVERSION variable!"
+#endif
+
+#ifndef COMPDATE
+#error "Please specify the COMPDATE variable!"
+/*
+COMPDATE=`date +"%d.%m.%Y %H:%M:%S"`
+
+and -DCOMPDATE="\"$(COMPDATE)\"" when compiling
+*/
+#endif
+
+RasPasswdConfig config;
+UserLogin userLogin;
+RasMgrClientComm rasmgrComm;
+
+char message[100];
+char encrNewPass1[35];
+char encrNewPass2[35];
+
+
+int main(int argc, char **argv)
+{
+ cout << "raspasswd: rasdaman password utility. rasdaman v" << RMANVERSION / 1000. << " -- generated on " << COMPDATE << "." <<endl;
+ std::cout << " Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann rasdaman GmbH." << std::endl
+ << "Rasdaman community is free software: you can redistribute it and/or modify "
+ "it under the terms of the GNU General Public License as published by "
+ "the Free Software Foundation, either version 3 of the License, or "
+ "(at your option) any later version. \n"
+ "Rasdaman community is distributed in the hope that it will be useful, "
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of "
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the "
+ "GNU General Public License for more details. \n\n";
+
+ cout << "This software contains software which is in the public domain:" << endl;
+ cout << "- openssl 0.96c (C) 1998-2002 The OpenSSL Project, (C) 1995-1998 Eric A. Young, Tim J. Hudson" << endl;
+
+ if( config.interpretArguments(argc, argv) == false) return 0;
+
+ if(testIsMessageDigestAvailable("MD5")==false)
+ { cout<<"No MD5-Algorithm."<<endl;
+ return 2;
+ }
+
+ if(userLogin.interactiveLogin()<0) return 1;
+
+ rasmgrComm.setRasMgrHost(config.getRasMgrHost(),config.getRasMgrPort());
+ rasmgrComm.setUserIdentification(userLogin.getUserName(),userLogin.getEncrPass());
+
+ if(execute( RASMGRCMD_HELLO ) == false) return 3;
+
+ getPasswdKeyboard(" Type your new password: ",encrNewPass1);
+ getPasswdKeyboard(" Retype the new password: ",encrNewPass2);
+
+ if(strcmp(encrNewPass1,encrNewPass2)!=0)
+ { cout<<"Passwords don't match."<<endl;
+ return 2;
+ }
+
+ // cout<<"name="<<username<<" pass="<<encrPass<<endl;
+
+ sprintf(message,"change user %s -encrPasswd %s ",userLogin.getUserName(),encrNewPass1);
+
+ if(execute(message) == false) return 3;
+
+ return 0;
+}
+
+bool execute(const char *message)
+ {
+ bool result = true; // function result
+ int comm = 0; // COMM_* values
+ const char *answer = NULL; // rasmgr response
+
+ comm = rasmgrComm.sendMessageGetAnswer(message, &answer);
+
+ switch(comm)
+ {
+ case COMM_ERR:
+ cout << "Cannot connect to rasmgr host "<<config.getRasMgrHost() <<"." << endl;
+ result = false;
+ break;
+ case COMM_ACDN:
+ cout << "Access denied." << endl;
+ result = false;
+ break;
+ default: // then it's ok
+ break;
+ }
+ cout << rasmgrComm.getBody() << endl;
+
+ return result;
+ }
+
+const char* getPasswdKeyboard(const char*text, char*dest)
+ {
+ char *plainPass=getpass(text);
+ messageDigest(plainPass,dest,"MD5");
+ for(int i=0;i<strlen(plainPass);i++) plainPass[i]=0;
+ //cout<<endl;
+ return dest;
+ }
+
+
+bool exitbyerror(char* text)
+{ perror(text);return false;
+}
+
+//################ Config ##################################
+RasPasswdConfig::RasPasswdConfig() :
+ cmlInter (CommandLineParser::getInstance()),
+ cmlHost (cmlInter.addStringParameter(CommandLineParser::noShortName,"host", "<name> name of host where master rasmgr runs", DEFAULT_HOSTNAME)),
+ cmlPort (cmlInter.addLongParameter(CommandLineParser::noShortName,"port", "<nnnn> the rasmgr port", DEFAULT_PORT )),
+ cmlHelp (cmlInter.addFlagParameter('h',"help","this help"))
+ {
+// done by default value of commandlineparser
+// strcpy(rasmgrHost,RASMGRHOST.c_str());
+// rasmgrPort = RASMGRPORT;
+ }
+
+bool RasPasswdConfig::interpretArguments(int argc, char **argv)
+ {
+ try {
+ cmlInter.processCommandLine(argc, argv);
+ }
+ catch(CmlException& err) {
+ cerr << "Command Line Parsing Error:" << endl << err.what() << endl;
+ return false;
+ }
+
+ if( cmlHelp.isPresent() ) {
+ printHelp();
+ return false;
+ }
+
+ try {
+ rasmgrPort = cmlPort.getValueAsLong();
+ }
+ catch(CmlException& err) {
+ cerr << "Command Line Parsing Error:" << endl << err.what() << endl;
+ return false;
+ }
+
+ strcpy(rasmgrHost, cmlHost.getValueAsString());
+
+ return true;
+ }
+
+void RasPasswdConfig::printHelp()
+ {
+ cout << "Usage: raspasswd [options]"<<endl;
+ cout << "Options:" << endl;
+ cmlInter.printHelp();
+ cout<<endl;
+ }
+
+const char* RasPasswdConfig::getRasMgrHost()
+ { return rasmgrHost;
+ }
+int RasPasswdConfig::getRasMgrPort()
+ { return rasmgrPort;
+ }
+
+/*
+void RasPasswdConfig::printDebugInfo()
+ {
+ cout<<"Working modus:.";
+ switch(workModus)
+ {
+ case WKMUNKNOWN : cout<<"unknown";break;
+ case WKMINTERACTIV : cout<<"interactiv";break;
+ case WKMBATCH : cout<<"batch";break;
+ case WKMLOGIN : cout<<"login";break;
+ }
+
+ cout<<endl<<"Login modus:...";
+ switch(loginModus)
+ {
+ case LGIUNKNOWN : cout<<"unknown";break;
+ case LGIINTERACTIV : cout<<"interactiv";break;
+ case LGIENVIRONM : cout<<"environm";break;
+ }
+
+ cout<<endl<<"Rasmgr:........"<<rasmgrHost<<":"<<rasmgrPort;
+
+ cout<<endl<<"History:......."<<(reqHist ? histFileName : "not requested");
+
+ cout<<endl<<"Prompt:........"<<getPrompt();
+
+ cout<<endl<<"Command:......."<<command;
+
+ cout<<endl;
+ }
+*/
diff --git a/rascontrol/raspasswd.hh b/rascontrol/raspasswd.hh
new file mode 100644
index 0000000..e13a947
--- /dev/null
+++ b/rascontrol/raspasswd.hh
@@ -0,0 +1,89 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: raspasswd.hh
+ *
+ * MODULE: rascontrol
+ * CLASS:
+ *
+ * PURPOSE:
+ * RasDaMan password utility
+ *
+ * COMMENTS:
+ *
+*/
+
+#ifndef RASPASSWD_HH
+#define RASPASSWD_HH
+
+#include<stdio.h>
+#include<errno.h>
+#include<stdlib.h>
+#include<unistd.h>
+#include<sys/types.h>
+#include<sys/socket.h>
+#include<netinet/in.h>
+#include<netdb.h>
+#include<iostream>
+#include<string.h>
+#include <string>
+
+#include "commline/cmlparser.hh"
+
+#include "../rasmgr/ras_crypto.hh"
+#include "rasmgr_utils_conf.hh"
+
+using namespace std;
+
+void printCommandLineHelp();
+
+bool exitbyerror(char*);
+
+const char* getPasswdKeyboard(const char*text,char*dest);
+bool execute(const char *message);
+
+class RasPasswdConfig:public ConfigurationBase
+ {
+ public:
+ RasPasswdConfig();
+
+ // false means program shouldn't continue
+ bool interpretArguments(int argc, char **argv);
+
+ const char* getRasMgrHost();
+ int getRasMgrPort();
+ // void printDebugInfo();
+ private:
+
+ void printHelp();
+ //bool paramError();
+
+ char rasmgrHost[100];
+ int rasmgrPort;
+
+ //-- parameters of this program
+ CommandLineParser &cmlInter;
+ CommandLineParameter &cmlHost, &cmlPort, &cmlHelp;
+ };
+
+#endif
diff --git a/rascontrol/test/rasmgrtest.cc b/rascontrol/test/rasmgrtest.cc
new file mode 100644
index 0000000..3a969f6
--- /dev/null
+++ b/rascontrol/test/rasmgrtest.cc
@@ -0,0 +1,178 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: rasmgrtest.cc
+ *
+ * MODULE: rascontrol
+ * CLASS:
+ *
+ * PURPOSE:
+ * Utility to test the rasmgr command language.
+ *
+ * COMMENTS:
+ *
+ *
+ */
+
+#include <fstream>
+#include <iomanip>
+
+#define DEBUG_MAIN
+#include "debug-clt.hh"
+
+#include "rascontrol.hh"
+#include "rasmgr_tester.hh"
+#include "rasmgrtester_conf.hh"
+
+TesterConf config;
+
+RasMgrTester rasmgrTester;
+
+#define TESTERCOMMENT '§'
+
+void testCommandLanguage();
+void createTestFile();
+
+int main(int argc, char **argv)
+{
+
+ if(config.interpretArguments(argc,argv) == false) return 0;
+
+ if(config.getWorkModus() == WKMUNKNOWN )
+ { cout << "And what should I do?"<<endl;
+ return 1;
+ }
+
+ if(testIsMessageDigestAvailable("MD5")==false)
+ { cout<<"No MD5-Algorythm!"<<endl;
+ return 2;
+ }
+
+ rasmgrTester.setRasMgrHost(config.getRasMgrHost(), config.getRasMgrPort());
+
+ // tre sa testezi modul de lucru al rasmgr, sa nu faci test cind e activ!!
+ if(rasmgrTester.mayWeDoTest()==false)
+ { cout<<"Can't do test while RasMgr is not running in test modus"<<endl;
+ return 3;
+ }
+
+ if(config.getWorkModus() == WKMCREATE) createTestFile();
+
+ if(config.getWorkModus() == WKMTSLANG) testCommandLanguage();
+
+ return 0;
+ }
+
+void createTestFile()
+ { // preia history file si face din el testfile-ul
+ cout<<"Creating test file "<<config.getTestFile()<<" from command list file "<<config.getCommandListFile()<<endl;
+ std::ifstream history(config.getCommandListFile());
+ if(!history) { cout<<"Can't open command list file "<<config.getCommandListFile()<<endl;
+ return;
+ }
+
+ std::ofstream testofs(config.getTestFile(),ios::out|ios::trunc);
+ if(!testofs) { cout<<"Can't open test file "<<config.getTestFile()<<endl;
+ return;
+ }
+
+ while(rasmgrTester.loadCommand(history))
+ {
+ if(rasmgrTester.sendCommandGetAnswer()==false) break;
+
+ rasmgrTester.saveCommand(testofs);
+ rasmgrTester.saveAnswer(testofs);
+ testofs<<"§§§- new command -§§§"<<endl;
+ }
+
+ cout<<"OK"<<endl;
+ }
+
+void removeComments(std::ifstream &ifs)
+ {
+ char *line = new char[MAXCOMMAND];
+
+ for(;;)
+ {
+ std::streampos poz=ifs.tellg();
+ ifs.getline(line,MAXCOMMAND);
+ if(!ifs) break;
+ if(line[0]!=TESTERCOMMENT)
+ { ifs.seekg(poz, std::ios::beg);
+ break;
+ }
+ }
+ delete[] line;
+ }
+void testCommandLanguage()
+ {
+ bool quiet = config.beQuiet();
+
+ cout<<"Testing the command language"<<endl;
+ std::ifstream iftestfile(config.getTestFile());
+ if(!iftestfile) { cout<<"Can't find testfile: "<<config.getTestFile()<<endl;
+ return;
+ }
+ std::ofstream logfile(config.getLogFile(),ios::out|ios::trunc);
+ if(!logfile) { cout<<"Can't open logfile: "<<config.getLogFile()<<endl;
+ return;
+ }
+
+ int countOk = 0;
+ int countFailed = 0;
+ int countTotal = 0;
+
+ for(int i=0;;i++)
+ {
+ removeComments(iftestfile);
+ if(rasmgrTester.loadCommand(iftestfile) == false) break;
+ rasmgrTester.loadExpected(iftestfile,TESTERCOMMENT);
+ rasmgrTester.sendCommandGetAnswer();
+
+ if(!quiet) cout <<std::setw(3)<<i<<". "<<rasmgrTester.getCommand()<<" ... ";
+ logfile<<std::setw(3)<<i<<". "<<rasmgrTester.getCommand()<<" ... ";
+
+ if(rasmgrTester.isAnswerOK())
+ {
+ if(!quiet) cout <<"OK"<<endl;
+ logfile<<"OK"<<endl;
+ countOk++;
+ }
+ else
+ {
+ if(!quiet) cout <<"FAILED"<<endl;
+ logfile<<"FAILED"<<endl;
+ logfile<<"§expected:"<<endl<<rasmgrTester.getExpected()<<'*'<<endl;
+ logfile<<"$got:"<<endl<<rasmgrTester.getAnswer()<<endl;
+ countFailed++;
+ }
+
+ countTotal++;
+ }
+
+ iftestfile.close();
+ logfile.close();
+
+ cout<<"Total: "<<countTotal<<" Passed="<<countOk<<" Failed="<<countFailed<<endl;
+ }
+
diff --git a/rascontrol/test/rasmgrtester_conf.cc b/rascontrol/test/rasmgrtester_conf.cc
new file mode 100644
index 0000000..a6bf7cc
--- /dev/null
+++ b/rascontrol/test/rasmgrtester_conf.cc
@@ -0,0 +1,133 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: rasmgrtester_conf.cc
+ *
+ * MODULE: rascontrol
+ * CLASS: TesterConf
+ *
+ * PURPOSE:
+ * Configuration from commandline and environment for rasmgrtest
+ *
+ * COMMENTS:
+ *
+*/
+
+
+#include "rasmgrtester_conf.hh"
+#include "rascontrol.hh"
+
+
+TesterConf::TesterConf()
+ {
+ strcpy(rasmgrHost,"localhost");
+ rasmgrPort = RASMGRPORT;
+
+ commandListFile[0] = EOS_CHAR;
+ testFile[0] = EOS_CHAR;
+
+ strcpy(logFile,"rasmgrtest.log");
+
+ workModus=WKMUNKNOWN;
+ quiet = false;
+ }
+
+bool TesterConf::interpretArguments(int argc, char **argv)
+ {
+ if(argc < 2) { printHelp(); return false;}
+
+ if(argv[1][0] != '-') strcpy(rasmgrHost,argv[1]);
+
+ int optionValueIndex;
+
+ if( checkArguments( argc, argv, "-h", optionValueIndex ) )
+ { printHelp();
+ return false;
+ }
+
+ if(checkArguments( argc, argv, "-port", optionValueIndex ) )
+ { if(optionValueIndex)
+ rasmgrPort = strtoul(argv[optionValueIndex],(char**)NULL,10);
+ }
+ if(checkArguments( argc, argv, "-cf", optionValueIndex ) )
+ { if(optionValueIndex)
+ strcpy(commandListFile,argv[optionValueIndex]);
+ }
+
+ if(checkArguments( argc, argv, "-tf", optionValueIndex ) )
+ { if(optionValueIndex)
+ strcpy(testFile,argv[optionValueIndex]);
+ }
+
+ if(checkArguments( argc, argv, "-lf", optionValueIndex ) )
+ { if(optionValueIndex)
+ strcpy(logFile,argv[optionValueIndex]);
+ }
+
+ if(checkArguments( argc, argv, "-quiet", optionValueIndex ) )
+ { quiet = true;
+ }
+
+ if( commandListFile[0] && testFile[0]) workModus = WKMCREATE;
+
+ else if(testFile[0]) workModus = WKMTSLANG;
+
+ return true;
+ }
+int TesterConf::getWorkModus()
+ { return workModus;
+ }
+const char* TesterConf::getRasMgrHost()
+ { return rasmgrHost;
+ }
+
+int TesterConf::getRasMgrPort()
+ { return rasmgrPort;
+ }
+
+const char* TesterConf::getCommandListFile()
+ { return commandListFile;
+ }
+const char* TesterConf::getTestFile()
+ { return testFile;
+ }
+const char* TesterConf::getLogFile()
+ { return logFile;
+ }
+
+bool TesterConf::beQuiet()
+ { return quiet;
+ }
+
+void TesterConf::printHelp()
+ {
+ cout<<"Usage: rasmgrtest mainhost [options]"<<endl;
+ cout<<"\tmainhost ... the hostname where the master RasMgr runs"<<endl;
+ cout<<"\t-port ... the listen port of the master RasMgr (default: "<<RASMGRPORT<<") "<<endl;
+ cout<<"\t-cf <file> ... command list file, from which the test file should be created"<<endl;
+ cout<<" (if none the test file is used to test the RasMgr)"<<endl;
+ cout<<"\t-tf <file> ... test file"<<endl;
+ cout<<"\t-lf <file> ... log file (default rasmgrtest.log)"<<endl;
+ cout<<endl;
+ }
+
diff --git a/rascontrol/test/rasmgrtester_conf.hh b/rascontrol/test/rasmgrtester_conf.hh
new file mode 100644
index 0000000..231508c
--- /dev/null
+++ b/rascontrol/test/rasmgrtester_conf.hh
@@ -0,0 +1,79 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: rasmgrtester_conf.hh
+ *
+ * MODULE: rascontrol
+ * CLASS: TesterConf
+ *
+ * PURPOSE:
+ * Configuration from commandline and environment for rasmgrtest
+ *
+ * COMMENTS:
+ *
+ *
+*/
+
+#ifndef RASMGRTESTER_CONF_HH
+#define RASMGRTESTER_CONF_HH
+
+#include "rasmgr_utils_conf.hh"
+#include "rasmgr_utils_comm.hh"
+
+#define MAXFILENAME 200
+
+// This is the base class for every programs configuration class
+class TesterConf:public ConfigurationBase
+ {
+ public:
+ TesterConf();
+
+ bool interpretArguments(int argc, char **argv);
+
+ const char* getRasMgrHost();
+ int getRasMgrPort();
+
+ int getWorkModus();
+ const char* getCommandListFile();
+ const char* getTestFile();
+ const char* getLogFile();
+ bool beQuiet();
+ private:
+
+ void printHelp();
+
+ char rasmgrHost[MAXHOSTNAME];
+ int rasmgrPort;
+
+ char commandListFile[MAXFILENAME];
+ char testFile[MAXFILENAME];
+ char logFile[MAXFILENAME];
+
+ int workModus;
+ bool quiet;
+
+ };
+
+extern TesterConf config;
+
+#endif
diff --git a/rasdl/Makefile.am b/rasdl/Makefile.am
new file mode 100644
index 0000000..87f26a2
--- /dev/null
+++ b/rasdl/Makefile.am
@@ -0,0 +1,70 @@
+# -*-Makefile-*- (for Emacs)
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+#
+# MAKEFILE FOR:
+# module rasdl
+#
+# COMMENTS:
+# For static linking you have to do first: setenv STATIC_LIBS=true
+#
+##################################################################
+
+AM_LFLAGS=-I
+YACC = bison
+AM_YFLAGS=-d -y
+AM_CXXFLAGS=@BASEDBCXXFLAGS@
+AM_LDFLAGS=@BASEDBLDFLAGS@
+
+bin_PROGRAMS=rasdl
+rasdl_SOURCES=lex.ll odl.yy parse.cc parse.hh symbtbl.cc symbtbl.hh \
+ alloca.cc rasdl.cc rasdl_error.cc rasdl_error.hh \
+ template_inst.hh yparse.hh \
+ ../mymalloc/mymalloc.h ../mymalloc/mymalloc_svc.cc
+rasdl_LDADD = ../reladminif/libreladminif.a ../relmddif/librelmddif.a \
+ ../relstorageif/librelstorageif.a ../relindexif/librelindexif.a \
+ ../relcatalogif/librelcatalogif.a ../relblobif/librelblobif.a \
+ ../indexmgr/libindexmgr.a ../catalogmgr/libcatalogmgr.a \
+ ../storagemgr/libstoragemgr.a ../tilemgr/libtilemgr.a \
+ ../compression/libcompression.a ../commline/libcommline.a ../raslib/libraslib.a \
+ ../conversion/libconversion.a
+
+BUILT_SOURCES=lex.cc odl.cc odl.h
+CLEANFILES=lex.cc odl.cc odl.h
+
+SUBDIRS=../reladminif ../relmddif ../relstorageif ../relindexif ../relcatalogif \
+ ../relblobif ../indexmgr ../catalogmgr ../storagemgr ../tilemgr \
+ ../compression ../raslib ../conversion ../commline
+
+$(RECURSIVE_CLEAN_TARGETS):
+ @$(MAKE) $(AM_MAKEFLAGS) `echo $@ | sed s/-recursive/-am/`
+
+#.PHONY : doc
+#doc:
+# -rm $(DOCDIR)/*
+# gawk -f rasdl.awk odl.y > odl.grammar
+# head -n 16 rasdlgrammar.html > $(DOCDIR)/rasdlgrammar.html
+# cat odl.grammar >> $(DOCDIR)/rasdlgrammar.html
+# tail -n 8 rasdlgrammar.html >> $(DOCDIR)/rasdlgrammar.html
+# $(DOCXX) -d $(DOCDIR) *.hh
+# chmod 664 $(DOCDIR)/* $(DOCDIR)/.??*
+
diff --git a/rasdl/alloca.cc b/rasdl/alloca.cc
new file mode 100644
index 0000000..e6fb8fa
--- /dev/null
+++ b/rasdl/alloca.cc
@@ -0,0 +1,530 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include "mymalloc/mymalloc.h"
+/* alloca.c -- allocate automatically reclaimed memory
+ (Mostly) portable public-domain implementation -- D A Gwyn
+
+ This implementation of the PWB library alloca function,
+ which is used to allocate space off the run-time stack so
+ that it is automatically reclaimed upon procedure exit,
+ was inspired by discussions with J. Q. Johnson of Cornell.
+ J.Otto Tennant <jot@cray.com> contributed the Cray support.
+
+ There are some preprocessor constants that can
+ be defined when compiling for your specific system, for
+ improved efficiency; however, the defaults should be okay.
+
+ The general concept of this implementation is to keep
+ track of all alloca-allocated blocks, and reclaim any
+ that are found to be deeper in the stack than the current
+ invocation. This heuristic does not reclaim storage as
+ soon as it becomes invalid, but it will do so eventually.
+
+ As a special case, alloca(0) reclaims storage without
+ allocating any. It is a good idea to use alloca(0) in
+ your main control loop, etc. to force garbage collection. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#ifdef emacs
+#include "blockinput.h"
+#endif
+
+/* If compiling with GCC 2, this file's not needed. */
+#if !defined (__GNUC__) || __GNUC__ < 2
+#ifndef SOLARIS
+/* If someone has defined alloca as a macro,
+ there must be some other way alloca is supposed to work. */
+#ifndef alloca
+
+#ifdef emacs
+#ifdef static
+/* actually, only want this if static is defined as ""
+ -- this is for usg, in which emacs must undefine static
+ in order to make unexec workable
+ */
+#ifndef STACK_DIRECTION
+you
+lose
+-- must know STACK_DIRECTION at compile-time
+#endif /* STACK_DIRECTION undefined */
+#endif /* static */
+#endif /* emacs */
+
+/* If your stack is a linked list of frames, you have to
+ provide an "address metric" ADDRESS_FUNCTION macro. */
+
+#if defined (CRAY) && defined (CRAY_STACKSEG_END)
+long i00afunc ();
+#define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg))
+#else
+#define ADDRESS_FUNCTION(arg) &(arg)
+#endif
+
+#if __STDC__
+typedef void *pointer;
+#else
+typedef char *pointer;
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+/* Different portions of Emacs need to call different versions of
+ malloc. The Emacs executable needs alloca to call xmalloc, because
+ ordinary malloc isn't protected from input signals. On the other
+ hand, the utilities in lib-src need alloca to call malloc; some of
+ them are very simple, and don't have an xmalloc routine.
+
+ Non-Emacs programs expect this to call use xmalloc.
+
+ Callers below should use malloc. */
+
+/*
+#ifndef emacs
+#define malloc xmalloc
+#endif
+*/
+extern pointer mymalloc ();
+
+/* Define STACK_DIRECTION if you know the direction of stack
+ growth for your system; otherwise it will be automatically
+ deduced at run-time.
+
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown */
+
+#ifndef STACK_DIRECTION
+#define STACK_DIRECTION 0 /* Direction unknown. */
+#endif
+
+#if STACK_DIRECTION != 0
+
+#define STACK_DIR STACK_DIRECTION /* Known at compile-time. */
+
+#else /* STACK_DIRECTION == 0; need run-time code. */
+
+static int stack_dir; /* 1 or -1 once known. */
+#define STACK_DIR stack_dir
+
+static void
+find_stack_direction ()
+{
+ static char *addr = NULL; /* Address of first `dummy', once known. */
+ auto char dummy; /* To get stack address. */
+
+ if (addr == NULL)
+ { /* Initial entry. */
+ addr = ADDRESS_FUNCTION (dummy);
+
+ find_stack_direction (); /* Recurse once. */
+ }
+ else
+ {
+ /* Second entry. */
+ if (ADDRESS_FUNCTION (dummy) > addr)
+ stack_dir = 1; /* Stack grew upward. */
+ else
+ stack_dir = -1; /* Stack grew downward. */
+ }
+}
+
+#endif /* STACK_DIRECTION == 0 */
+
+/* An "alloca header" is used to:
+ (a) chain together all alloca'ed blocks;
+ (b) keep track of stack depth.
+
+ It is very important that sizeof(header) agree with malloc
+ alignment chunk size. The following default should work okay. */
+
+#ifndef ALIGN_SIZE
+#define ALIGN_SIZE sizeof(double)
+#endif
+
+typedef union hdr
+{
+ char align[ALIGN_SIZE]; /* To force sizeof(header). */
+ struct
+ {
+ union hdr *next; /* For chaining headers. */
+ char *deep; /* For stack depth measure. */
+ } h;
+} header;
+
+static header *last_alloca_header = NULL; /* -> last alloca header. */
+
+/* Return a pointer to at least SIZE bytes of storage,
+ which will be automatically reclaimed upon exit from
+ the procedure that called alloca. Originally, this space
+ was supposed to be taken from the current stack frame of the
+ caller, but that method cannot be made to work for some
+ implementations of C, for example under Gould's UTX/32. */
+
+pointer
+alloca (size)
+ unsigned size;
+{
+ auto char probe; /* Probes stack depth: */
+ register char *depth = ADDRESS_FUNCTION (probe);
+
+#if STACK_DIRECTION == 0
+ if (STACK_DIR == 0) /* Unknown growth direction. */
+ find_stack_direction ();
+#endif
+
+ /* Reclaim garbage, defined as all alloca'd storage that
+ was allocated from deeper in the stack than currently. */
+
+ {
+ register header *hp; /* Traverses linked list. */
+
+#ifdef emacs
+ BLOCK_INPUT;
+#endif
+
+ for (hp = last_alloca_header; hp != NULL;)
+ if ((STACK_DIR > 0 && hp->h.deep > depth)
+ || (STACK_DIR < 0 && hp->h.deep < depth))
+ {
+ register header *np = hp->h.next;
+
+ free ((pointer) hp); /* Collect garbage. */
+
+ hp = np; /* -> next header. */
+ }
+ else
+ break; /* Rest are not deeper. */
+
+ last_alloca_header = hp; /* -> last valid storage. */
+
+#ifdef emacs
+ UNBLOCK_INPUT;
+#endif
+ }
+
+ if (size == 0)
+ return NULL; /* No allocation required. */
+
+ /* Allocate combined header + user data storage. */
+
+ {
+ register pointer new = mymalloc (sizeof (header) + size);
+ /* Address of header. */
+
+ if (new == 0)
+ abort();
+
+ ((header *) new)->h.next = last_alloca_header;
+ ((header *) new)->h.deep = depth;
+
+ last_alloca_header = (header *) new;
+
+ /* User storage begins just after header. */
+
+ return (pointer) ((char *) new + sizeof (header));
+ }
+}
+
+#if defined (CRAY) && defined (CRAY_STACKSEG_END)
+
+#ifdef DEBUG_I00AFUNC
+#include <stdio.h>
+#endif
+
+#ifndef CRAY_STACK
+#define CRAY_STACK
+#ifndef CRAY2
+/* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */
+struct stack_control_header
+ {
+ long shgrow:32; /* Number of times stack has grown. */
+ long shaseg:32; /* Size of increments to stack. */
+ long shhwm:32; /* High water mark of stack. */
+ long shsize:32; /* Current size of stack (all segments). */
+ };
+
+/* The stack segment linkage control information occurs at
+ the high-address end of a stack segment. (The stack
+ grows from low addresses to high addresses.) The initial
+ part of the stack segment linkage control information is
+ 0200 (octal) words. This provides for register storage
+ for the routine which overflows the stack. */
+
+struct stack_segment_linkage
+ {
+ long ss[0200]; /* 0200 overflow words. */
+ long sssize:32; /* Number of words in this segment. */
+ long ssbase:32; /* Offset to stack base. */
+ long:32;
+ long sspseg:32; /* Offset to linkage control of previous
+ segment of stack. */
+ long:32;
+ long sstcpt:32; /* Pointer to task common address block. */
+ long sscsnm; /* Private control structure number for
+ microtasking. */
+ long ssusr1; /* Reserved for user. */
+ long ssusr2; /* Reserved for user. */
+ long sstpid; /* Process ID for pid based multi-tasking. */
+ long ssgvup; /* Pointer to multitasking thread giveup. */
+ long sscray[7]; /* Reserved for Cray Research. */
+ long ssa0;
+ long ssa1;
+ long ssa2;
+ long ssa3;
+ long ssa4;
+ long ssa5;
+ long ssa6;
+ long ssa7;
+ long sss0;
+ long sss1;
+ long sss2;
+ long sss3;
+ long sss4;
+ long sss5;
+ long sss6;
+ long sss7;
+ };
+
+#else /* CRAY2 */
+/* The following structure defines the vector of words
+ returned by the STKSTAT library routine. */
+struct stk_stat
+ {
+ long now; /* Current total stack size. */
+ long maxc; /* Amount of contiguous space which would
+ be required to satisfy the maximum
+ stack demand to date. */
+ long high_water; /* Stack high-water mark. */
+ long overflows; /* Number of stack overflow ($STKOFEN) calls. */
+ long hits; /* Number of internal buffer hits. */
+ long extends; /* Number of block extensions. */
+ long stko_mallocs; /* Block allocations by $STKOFEN. */
+ long underflows; /* Number of stack underflow calls ($STKRETN). */
+ long stko_free; /* Number of deallocations by $STKRETN. */
+ long stkm_free; /* Number of deallocations by $STKMRET. */
+ long segments; /* Current number of stack segments. */
+ long maxs; /* Maximum number of stack segments so far. */
+ long pad_size; /* Stack pad size. */
+ long current_address; /* Current stack segment address. */
+ long current_size; /* Current stack segment size. This
+ number is actually corrupted by STKSTAT to
+ include the fifteen word trailer area. */
+ long initial_address; /* Address of initial segment. */
+ long initial_size; /* Size of initial segment. */
+ };
+
+/* The following structure describes the data structure which trails
+ any stack segment. I think that the description in 'asdef' is
+ out of date. I only describe the parts that I am sure about. */
+
+struct stk_trailer
+ {
+ long this_address; /* Address of this block. */
+ long this_size; /* Size of this block (does not include
+ this trailer). */
+ long unknown2;
+ long unknown3;
+ long link; /* Address of trailer block of previous
+ segment. */
+ long unknown5;
+ long unknown6;
+ long unknown7;
+ long unknown8;
+ long unknown9;
+ long unknown10;
+ long unknown11;
+ long unknown12;
+ long unknown13;
+ long unknown14;
+ };
+
+#endif /* CRAY2 */
+#endif /* not CRAY_STACK */
+
+#ifdef CRAY2
+/* Determine a "stack measure" for an arbitrary ADDRESS.
+ I doubt that "lint" will like this much. */
+
+static long
+i00afunc (long *address)
+{
+ struct stk_stat status;
+ struct stk_trailer *trailer;
+ long *block, size;
+ long result = 0;
+
+ /* We want to iterate through all of the segments. The first
+ step is to get the stack status structure. We could do this
+ more quickly and more directly, perhaps, by referencing the
+ $LM00 common block, but I know that this works. */
+
+ STKSTAT (&status);
+
+ /* Set up the iteration. */
+
+ trailer = (struct stk_trailer *) (status.current_address
+ + status.current_size
+ - 15);
+
+ /* There must be at least one stack segment. Therefore it is
+ a fatal error if "trailer" is null. */
+
+ if (trailer == 0)
+ abort ();
+
+ /* Discard segments that do not contain our argument address. */
+
+ while (trailer != 0)
+ {
+ block = (long *) trailer->this_address;
+ size = trailer->this_size;
+ if (block == 0 || size == 0)
+ abort ();
+ trailer = (struct stk_trailer *) trailer->link;
+ if ((block <= address) && (address < (block + size)))
+ break;
+ }
+
+ /* Set the result to the offset in this segment and add the sizes
+ of all predecessor segments. */
+
+ result = address - block;
+
+ if (trailer == 0)
+ {
+ return result;
+ }
+
+ do
+ {
+ if (trailer->this_size <= 0)
+ abort ();
+ result += trailer->this_size;
+ trailer = (struct stk_trailer *) trailer->link;
+ }
+ while (trailer != 0);
+
+ /* We are done. Note that if you present a bogus address (one
+ not in any segment), you will get a different number back, formed
+ from subtracting the address of the first block. This is probably
+ not what you want. */
+
+ return (result);
+}
+
+#else /* not CRAY2 */
+/* Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP.
+ Determine the number of the cell within the stack,
+ given the address of the cell. The purpose of this
+ routine is to linearize, in some sense, stack addresses
+ for alloca. */
+
+static long
+i00afunc (long address)
+{
+ long stkl = 0;
+
+ long size, pseg, this_segment, stack;
+ long result = 0;
+
+ struct stack_segment_linkage *ssptr;
+
+ /* Register B67 contains the address of the end of the
+ current stack segment. If you (as a subprogram) store
+ your registers on the stack and find that you are past
+ the contents of B67, you have overflowed the segment.
+
+ B67 also points to the stack segment linkage control
+ area, which is what we are really interested in. */
+
+ stkl = CRAY_STACKSEG_END ();
+ ssptr = (struct stack_segment_linkage *) stkl;
+
+ /* If one subtracts 'size' from the end of the segment,
+ one has the address of the first word of the segment.
+
+ If this is not the first segment, 'pseg' will be
+ nonzero. */
+
+ pseg = ssptr->sspseg;
+ size = ssptr->sssize;
+
+ this_segment = stkl - size;
+
+ /* It is possible that calling this routine itself caused
+ a stack overflow. Discard stack segments which do not
+ contain the target address. */
+
+ while (!(this_segment <= address && address <= stkl))
+ {
+#ifdef DEBUG_I00AFUNC
+ fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl);
+#endif
+ if (pseg == 0)
+ break;
+ stkl = stkl - pseg;
+ ssptr = (struct stack_segment_linkage *) stkl;
+ size = ssptr->sssize;
+ pseg = ssptr->sspseg;
+ this_segment = stkl - size;
+ }
+
+ result = address - this_segment;
+
+ /* If you subtract pseg from the current end of the stack,
+ you get the address of the previous stack segment's end.
+ This seems a little convoluted to me, but I'll bet you save
+ a cycle somewhere. */
+
+ while (pseg != 0)
+ {
+#ifdef DEBUG_I00AFUNC
+ fprintf (stderr, "%011o %011o\n", pseg, size);
+#endif
+ stkl = stkl - pseg;
+ ssptr = (struct stack_segment_linkage *) stkl;
+ size = ssptr->sssize;
+ pseg = ssptr->sspseg;
+ result += size;
+ }
+ return (result);
+}
+
+#endif /* not CRAY2 */
+#endif /* CRAY */
+
+#endif /* no alloca */
+#endif /*SOLARIS*/
+#endif /* not GCC version 2 */
diff --git a/rasdl/lex.ll b/rasdl/lex.ll
new file mode 100644
index 0000000..ddf36e4
--- /dev/null
+++ b/rasdl/lex.ll
@@ -0,0 +1,240 @@
+%a 3000
+%p 2700
+%o 5000
+
+%{
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+//==============================================================================
+//
+// NAME: ODL.lex
+//
+//
+// DESCRIPTION : Pattern description for lexical analyzer generators.
+//
+//==============================================================================
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "parse.hh"
+#include "yparse.hh"
+
+#include "odl.h"
+
+/* for error output */
+long lineNumber = 1; /* number of line in current file */
+int columnNumber= 1; /* number of column in current line */
+int commentLevel= 0; /* Level of nested Comments */
+
+int TAB_SIZE = 3; /* TAB size is always set to 3 */
+
+#define ID(token,length)\
+{\
+ columnNumber+=length;\
+ return(token);\
+}\
+
+#define SET_WHERE(WHERE) \
+{ \
+ WHERE.line =lineNumber; \
+ WHERE.column=columnNumber; \
+ WHERE.file ="main file"; \
+}
+
+#define COMMAND(token,length) \
+{ \
+ SET_WHERE(yylval.Command.where); \
+ \
+ yylval.Command.command=token; \
+ \
+ columnNumber+=length; \
+ return(token); \
+}
+
+%}
+%option noyywrap
+%x Comment
+
+%%
+
+<INITIAL,Comment>"/*" {
+ if(commentLevel++<1)
+ BEGIN(Comment);
+
+ columnNumber+=2;
+ }
+<Comment>"*/" {
+ if(--commentLevel==0)
+ BEGIN(INITIAL);
+
+ columnNumber+=2;
+ }
+<Comment>\n {
+ lineNumber++;
+ columnNumber=1;
+ }
+<Comment>. {
+ columnNumber++;
+ } // skip any character and count
+
+"//".* ;
+
+";" COMMAND(SEMI,1)
+"{" COMMAND(LPAR,1)
+"}" COMMAND(RPAR,1)
+":" COMMAND(COLON,1)
+"," COMMAND(COMMA,1)
+"*" COMMAND(TIMES,1)
+"typedef" COMMAND(TYPEDEF,7)
+"float" COMMAND(PFLOAT,5)
+"double" COMMAND(PDOUBLE,6)
+"long" COMMAND(PLONG,4)
+"short" COMMAND(PSHORT,5)
+"unsigned" COMMAND(PUNSIGNED,8)
+"char" COMMAND(PCHAR,4)
+"boolean" COMMAND(PBOOLEAN,7)
+"octet" COMMAND(POCTET,5)
+"complexd" COMMAND(PCOMPLEX2,8)
+"complex" COMMAND(PCOMPLEX1,7)
+"struct" COMMAND(PSTRUCT,6)
+"<" COMMAND(LEFT,1)
+">" COMMAND(RIGHT,1)
+"[" COMMAND(LEPAR,1)
+"]" COMMAND(REPAR,1)
+"set" COMMAND(SET,3)
+"marray" COMMAND(MARRAY,6)/* FORWISS */
+
+%{
+/*
+"module" COMMAND(MODULE,6)
+"::" COMMAND(DOUBLE_COLON,2)
+"persistent" COMMAND(PERSISTENT,10)
+"transient" COMMAND(TRANSIENT,9)
+"interface" COMMAND(INTERFACE,9)
+"(" COMMAND(LRPAR,1)
+")" COMMAND(RRPAR,1)
+"extent" COMMAND(EXTENT,6)
+"key" COMMAND(KEY,3)
+"keys" COMMAND(KEYS,4)
+"const" COMMAND(CONST,5)
+"=" COMMAND(EQUAL,1)
+"|" COMMAND(VERT,1)
+"^" COMMAND(HAT,1)
+"&" COMMAND(AMPER,1)
+">>" COMMAND(DOUBLE_RIGHT,1)
+"<<" COMMAND(DOUBLE_LEFT,1)
+"+" COMMAND(PLUS,1)
+"-" COMMAND(MINUS,1)
+"/" COMMAND(SLASH,1)
+"%" COMMAND(PERCENT,1)
+"~" COMMAND(TILDE,1)
+"TRUE" COMMAND(TRUE,4)
+"FALSE" COMMAND(FALSE,5)
+"any" COMMAND(ANY,3)
+"union" COMMAND(UNION,5)
+"switch" COMMAND(SWITCH,6)
+"case" COMMAND(CASE,4)
+"default" COMMAND(DEFAULT,7)
+"enum" COMMAND(ENUM,4)
+"Array" COMMAND(ARRAY,5)
+"Sequence" COMMAND(SEQUENCE,8)
+"String" COMMAND(STRING,6)
+"readonly" COMMAND(READONLY,8)
+"attribute" COMMAND(ATTRIBUTE,9)
+"List" COMMAND(LIST,4)
+"Bag" COMMAND(BAG,3)
+"inverse" COMMAND(INVERSE,7)
+"relationship" COMMAND(RELATIONSHIP,12)
+"order_by" COMMAND(ORDER_BY,8)
+"exception" COMMAND(EXCEPTION,9)
+"oneway" COMMAND(ONEWAY,6)
+"void" COMMAND(VOID,4)
+"in" COMMAND(IN,2)
+"out" COMMAND(OUT,3)
+"inout" COMMAND(INOUT,5)
+"raises" COMMAND(RAISES,6)
+"context" COMMAND(CONTEXT,7)
+*/
+%}
+
+[0-9]+ {
+ yylval.LEX_integer.value=atol(yytext);
+
+ SET_WHERE(yylval.LEX_integer.where);
+
+ ID(IntegerLiteral,yyleng);
+ }
+
+%{
+/*
+[0-9]+"."[0-9]+ {
+ yylval.Real.value=atof(yytext);
+
+ SET_WHERE(yylval.Real.where);
+
+ ID(FloatingPtLiteral,yyleng);
+ }
+
+\"([^"]|\\["\n])*\" {
+ yylval.String.string=(const char*)malloc(yyleng+1-2);
+ strcpy((char*)yylval.String.string,yytext);
+
+ SET_WHERE(yylval.String.where);
+
+ ID(StringLiteral,yyleng);
+ }
+
+"'"[^']"'" {
+ yylval.Character.character=yytext[1];
+
+ SET_WHERE(yylval.Character.where);
+
+ ID(CharacterLiteral,3);
+ }
+*/
+%}
+
+[a-zA-Z_][a-zA-Z0-9_]* {
+ yylval.Entry.name =(const char*)malloc(yyleng+1);
+
+ SET_WHERE(yylval.Entry.where);
+
+ strcpy((char*)yylval.Entry.name,yytext);
+
+ ID(Identifier,yyleng);
+ }
+
+\n {
+ lineNumber++;
+ columnNumber=1;
+ }
+
+\t {
+ columnNumber=((columnNumber-1)/TAB_SIZE+1)*TAB_SIZE+1;
+ }
+
+" " {
+ columnNumber++;
+ }
diff --git a/rasdl/odl.yy b/rasdl/odl.yy
new file mode 100644
index 0000000..9194d11
--- /dev/null
+++ b/rasdl/odl.yy
@@ -0,0 +1,631 @@
+%{
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+//==============================================================================
+//
+//
+//
+// DESCRIPTION : Grammar description used to parse ODL files.
+//
+//==============================================================================
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <iostream>
+
+#include "parse.hh"
+#include "yparse.hh"
+#include "symbtbl.hh"
+
+#include "raslib/minterval.hh"
+
+int yyparse();
+
+extern int yylex();
+extern long lineNumber;
+extern int columnNumber;
+
+YSymbolTable *Symbols=new YSymbolTable();
+YSymbol *unique_symbol(const char*name,const YWhere&);
+
+// error handling
+void yyerror(const char* s);
+extern const YWhere *error_where; // associatted place in source code with error is NULL if no available
+extern const YWhere *error_source; // place where source of error
+extern const char *error_token;
+
+// outputs an error with an argument like "...%s.." or "...%i.."
+#define error_arg(OUTPUT,ARGUMENT,WHERE) \
+{ \
+ char buffer[1024]; \
+ sprintf(buffer,OUTPUT,ARGUMENT); \
+ \
+ error_where =WHERE; \
+ yyerror(buffer); \
+};
+
+%}
+
+%union{
+ // types for LEX
+ struct
+ {
+ YWhere where;
+ const char *name;
+ } Entry;
+
+ struct
+ {
+ YWhere where;
+ int command;
+ } Command;
+
+ struct
+ {
+ YWhere where;
+ long value;
+ } LEX_integer;
+
+ struct
+ {
+ YWhere where;
+ double value;
+ } Real;
+
+ struct
+ {
+ YWhere where;
+ char character;
+ } Character;
+
+ struct
+ {
+ YWhere where;
+ const char *string;
+ } String;
+
+ // types for YACC
+ YSymbol* Symbol;
+
+ Parse_type* Type;
+ Parse_interface* Interface;
+ Parse_composite::Element* element;
+ Parse_interface::Base_class* Base_Classes;
+
+ Parse_interface::Lifetime Persistence;
+ Parse_enum::Enumerator* enumerator;
+ bool Boolean;
+ rINT_list* INT_list;
+ YLiteral Literal;
+ YDeclarator* Declarator;
+
+ // spatial domain
+ r_Sinterval* dimension;
+
+ struct
+ {
+ r_Minterval* domain;
+ unsigned long dimensionality;
+ } domainSpec;
+
+ r_Minterval* domain;
+
+ int dummyValue;
+ }
+
+%token <Entry> Identifier
+%token <LEX_integer> IntegerLiteral
+
+%token <Command> SEMI
+ LPAR
+ RPAR
+ COLON
+ COMMA
+ TIMES
+ TYPEDEF
+ PFLOAT
+ PDOUBLE
+ PLONG
+ PSHORT
+ PUNSIGNED
+ PCHAR
+ PBOOLEAN
+ POCTET
+ PCOMPLEX1
+ PCOMPLEX2
+ PSTRUCT
+ LEFT
+ RIGHT
+ LEPAR
+ REPAR
+ SET
+ MARRAY
+
+/* types of nonterminals */
+%type<dummyValue> model,specification,definition;
+%type <Literal> literal,primary_expr
+%type <element> member,member_list
+%type <Symbol> scoped_name
+// enum_name
+%type <Type> type_spec,simple_type_spec,type_declarator,
+ floating_pt_type,integer_type,signed_int,signed_long_int,
+ signed_short_int,unsigned_int,unsigned_long_int,
+ unsigned_short_int,char_type,boolean_type,octet_type,complex1_type,complex2_type,
+ struct_type,marray_type, type_dcl,constr_type_spec,
+ opt_marray_base,collection_type,base_type_spec,
+ template_type_spec
+%type <Declarator> declarator,declarators,simple_declarator
+
+%type <dimension> dimension_spec
+%type <domainSpec> opt_spatial_domain
+%type <domain> spatial_domain,dimension_spec_list
+
+%%
+
+/*(0)*/
+model : { Symbols->push_scope(NULL); }
+ specification
+ { Symbols->pop_scope(); }
+
+/*(1)*/
+specification : definition
+ | definition specification
+
+/*(2)*/
+definition : type_dcl SEMI { $$ = NULL; }
+
+/*(11)*/
+/*<Symbol>*/
+scoped_name : Identifier
+ {
+ if(!Symbols->search_scopes($1.name,$$))
+ error_arg("undefined symbol[%s]",$1.name,&$1.where);
+ }
+
+/*(23)*/
+/*<Literal>*/
+primary_expr : literal { $$ = $1; }
+
+/*(24)*/
+/*<Literal>*/
+literal : IntegerLiteral
+ {
+ $$.Integer =$1.value;
+ $$.type =YLiteral::dLinteger;
+ }
+
+/*(27)*/
+type_dcl : TYPEDEF type_declarator { $$ = $2; }
+ | struct_type
+
+/*(28)*/
+type_declarator : type_spec declarators
+ {
+ // for each declarator there exists a symbol
+ // therefore generate only aliases
+ for(YDeclarator*scan=$2;scan!=NULL;scan=scan->next)
+ {
+ Parse_alias *alias=new Parse_alias;
+
+ alias->type=$1;
+ alias->name=scan->symbol->get_name();
+ alias->symbol=scan->symbol;
+
+ scan->symbol->Type =alias;
+ scan->symbol->type =YSymbol::dParse_Type;
+ scan->symbol->owned_by_symbol =false; // never owned by symbol
+ };
+ }
+
+/*(29)*/
+/*<Type>*/
+type_spec : simple_type_spec
+ | constr_type_spec
+ {
+ Parse_typereference *reference=new Parse_typereference;
+ reference->type=$1;
+ reference->setParseInfo( $1->getParseInfo() );
+
+ $$=reference;
+ }
+
+/*(30)*/
+/*<Type>*/
+simple_type_spec : base_type_spec
+ | template_type_spec
+ | scoped_name
+ {
+ Parse_typereference *reference=new Parse_typereference;
+ reference->type=$1->Type;
+ reference->setParseInfo( Parse_info( $1->where, $1->get_name() ) );
+
+ $$=reference;
+ }
+
+/*(31)*/
+/*<Type>*/
+base_type_spec : floating_pt_type
+ | integer_type
+ | char_type
+ | boolean_type
+ | octet_type
+ | complex1_type
+ | complex2_type
+
+/*(32)*/
+/*<Type>*/
+template_type_spec : collection_type
+ | marray_type
+
+/*(32a)*/
+/*<Type>*/
+collection_type : SET LEFT simple_type_spec RIGHT
+ {
+ $$=new Parse_set;
+ $$->setParseInfo( Parse_info( $1.where, "Set" ) );
+ ((Parse_set*)$$)->base_type=$3;
+ };
+
+/*(33)*/
+/*<Type>*/
+constr_type_spec : struct_type
+
+/*(34)*/
+/*<Declarator>*/
+declarators : declarator
+ | declarator COMMA declarators
+ {
+ $1->next =$3;
+ $$ =$1;
+ };
+
+/*(35)*/
+/*<Declarator>*/
+declarator : simple_declarator
+
+/*(36)*/
+/*<Declarator>*/
+simple_declarator : Identifier
+ {
+ YSymbol *symbol=unique_symbol($1.name,$1.where);
+
+ $$=new YDeclarator;
+ $$->next =NULL;
+ $$->symbol =symbol;
+ $$->array_size =NULL;
+ }
+
+/*(38)*/
+/*<Type>*/
+floating_pt_type : PFLOAT
+ {
+ Parse_float *real=new Parse_float;
+ real->accurance=Parse_float::Single;
+ real->setParseInfo( Parse_info( $1.where, "float") );
+
+ $$=real;
+ }
+ | PDOUBLE
+ {
+ Parse_float *real=new Parse_float;
+ real->accurance=Parse_float::Double;
+ real->setParseInfo( Parse_info( $1.where, "double") );
+
+ $$=real;
+ }
+
+/*(39)*/
+/*<Type>*/
+integer_type : signed_int
+ | unsigned_int
+
+/*(40)*/
+/*<Type>*/
+signed_int : signed_long_int
+ | signed_short_int
+
+/*(41)*/
+/*<Type>*/
+signed_long_int : PLONG
+ {
+ Parse_int *integer=new Parse_int;
+
+ integer->width =Parse_int::Long;
+ integer->sign =Parse_int::Signed;
+ integer->setParseInfo( Parse_info( $1.where, "long") );
+
+ $$=integer;
+ }
+
+/*(42)*/
+/*<Type>*/
+signed_short_int : PSHORT
+ {
+ Parse_int *integer=new Parse_int;
+
+ integer->width =Parse_int::Short;
+ integer->sign =Parse_int::Signed;
+ integer->setParseInfo( Parse_info( $1.where, "short") );
+
+ $$=integer;
+ }
+
+/*(43)*/
+/*<Type>*/
+unsigned_int : unsigned_long_int
+ | unsigned_short_int
+
+/*(44)*/
+/*<Type>*/
+unsigned_long_int : PUNSIGNED PLONG
+ {
+ Parse_int *integer=new Parse_int;
+
+ integer->width =Parse_int::Long;
+ integer->sign =Parse_int::Unsigned;
+ integer->setParseInfo( Parse_info( $1.where, "unsigned long") );
+
+ $$=integer;
+ }
+
+/*(45)*/
+/*<Type>*/
+unsigned_short_int : PUNSIGNED PSHORT
+ {
+ Parse_int *integer=new Parse_int;
+
+ integer->width =Parse_int::Short;
+ integer->sign =Parse_int::Unsigned;
+ integer->setParseInfo( Parse_info( $1.where, "unsigned short") );
+
+ $$=integer;
+ }
+
+/*(46)*/
+/*<Type>*/
+char_type : PCHAR
+ {
+ $$=new Parse_char;
+ $$->setParseInfo( Parse_info( $1.where, "char") );
+ }
+
+/*(47)*/
+/*<Type>*/
+boolean_type : PBOOLEAN
+ {
+ $$=new Parse_boolean;
+ $$->setParseInfo( Parse_info( $1.where, "boolean") );
+ }
+
+/*(48)*/
+/*<Type>*/
+octet_type : POCTET
+ {
+ $$=new Parse_octet;
+ $$->setParseInfo( Parse_info( $1.where, "octet") );
+ }
+
+/*(48a)*/
+/*<Type>*/
+complex1_type : PCOMPLEX1
+ {
+ $$=new Parse_complex1;
+ $$->setParseInfo( Parse_info( $1.where, "complex") );
+ }
+
+
+/*(48b)*/
+/*<Type>*/
+complex2_type : PCOMPLEX2
+ {
+ $$=new Parse_complex2;
+ $$->setParseInfo( Parse_info( $1.where, "complexd") );
+ }
+
+/*(50)*/
+/*<Type>*/
+struct_type : PSTRUCT Identifier
+ {
+ YSymbol *symbol=unique_symbol($2.name,$1.where);
+
+ symbol->type =YSymbol::dParse_Type;
+ symbol->Type =new Parse_struct;
+ symbol->Type->symbol =symbol;
+ symbol->owned_by_symbol =false; // never owned by a symbol
+
+ symbol->Type->setParseInfo( Parse_info( $1.where, "struct") );
+
+ Symbols->push_scope(symbol);
+ }
+ LPAR member_list RPAR
+ {
+ const YSymbol *symbol=Symbols->pop_scope();
+
+ $$=symbol->Type;
+
+ $$->name =symbol->get_name();
+ ((Parse_struct*)$$)->elements =$5;
+ }
+
+/*(51)*/
+/*<Element>*/
+member_list : member
+ | member member_list
+ {
+ Parse_composite::Element *scan=$1;
+ while(scan->next!=NULL)
+ scan=scan->next;
+
+ scan->next=$2;
+ $$=$1;
+ }
+
+/*(52)*/
+/*<Element>*/
+member : type_spec declarators SEMI
+ {
+ YDeclarator *scan=$2;
+ Parse_composite::Element *current=NULL;
+
+ for(;scan!=NULL;scan=scan->next)
+ {
+ if(current==NULL)
+ {
+ current=new Parse_composite::Element;
+ $$=current;
+ }
+ else
+ {
+ current->next=new Parse_composite::Element;
+ current=current->next;
+ };
+
+ current->type=$1;
+ current->name=scan->symbol->get_name();
+ };
+ };
+
+/*(75)*/
+/*<Type>*/
+marray_type : MARRAY LEFT
+ opt_marray_base
+ opt_spatial_domain
+ RIGHT
+ {
+ $$=new Parse_MDD;
+
+ ((Parse_MDD*)$$)->base_type =$3;
+ ((Parse_MDD*)$$)->domain =$4.domain;
+ ((Parse_MDD*)$$)->dimensionality =$4.dimensionality;
+ }
+
+/*<Type>*/
+opt_marray_base : { $$=NULL; }
+ | simple_type_spec
+
+/*<domain>*/
+opt_spatial_domain : { $$.domain=NULL; $$.dimensionality = 0; }
+ | COMMA primary_expr { $$.domain=NULL; $$.dimensionality = $2.Integer; }
+ | COMMA spatial_domain { $$.domain=$2; $$.dimensionality = 0; };
+
+/*(76)*/
+/*<domain>*/
+spatial_domain : LEPAR dimension_spec_list REPAR { $$ = $2; }
+
+
+/*(77)*/
+/*<dimension>*/
+dimension_spec_list : dimension_spec
+ {
+ $$ = new r_Minterval(1);
+ (*$$)[0] = (*$1);
+ delete $1; $1=NULL;
+ }
+ | dimension_spec COMMA dimension_spec_list
+ {
+ $$ = new r_Minterval( $3->dimension() + 1 );
+
+ (*$$)[0] = (*$1);
+ delete $1; $1=NULL;
+
+ for( int i=0; i<$3->dimension(); i++ )
+ (*$$)[i+1] = (*$3)[i];
+
+ delete $3; $3=NULL;
+ }
+
+
+/*(78)*/
+/*<dimension>*/
+dimension_spec : primary_expr COLON primary_expr { $$=new r_Sinterval( (r_Range)$1.Integer, (r_Range)$3.Integer ); }
+ | TIMES COLON primary_expr { $$=new r_Sinterval( '*' , (r_Range)$3.Integer ); }
+ | primary_expr COLON TIMES { $$=new r_Sinterval( (r_Range)$1.Integer, '*' ); }
+ | TIMES COLON TIMES { $$=new r_Sinterval( '*' , '*' ); }
+
+
+%%
+//****************************************************************************
+//
+// name : unique_symbol
+// purpose : tries to create an unique symbol within scope
+// remarks : calls yyerror if name already exists in scope
+//
+//****************************************************************************
+YSymbol *unique_symbol(const char*name,const YWhere&where)
+{
+ YSymbol *symbol;
+
+ if(!Symbols->scoped_symbol(&symbol,name,where))
+ {
+ error_source=&symbol->where;
+ error_token =name;
+
+ error_arg("[%s] symbol already defined within scope",name,&where);
+ };
+
+ return(symbol);
+};
+
+const YWhere *error_source =NULL;
+const YWhere *error_where =NULL;
+const char *error_token =NULL;
+// associatted place in source code with error
+// is NULL if no available
+
+void yyerror(const char* s)
+{
+ std::cout<<"error!\n";
+
+ if(error_where!=NULL)
+ {
+ std::cerr<<"\n pos : line "<<error_where->line<<" colmun "<<error_where->column;
+
+ if(error_where->file!=NULL)
+ std::cerr<<" in \""<<error_where->file<<"\"";
+
+ std::cerr<<".\n";
+ }
+ else
+ std::cerr<<"\n near : line "<<lineNumber<<" column "<<columnNumber<<".\n";
+
+ if(error_token!=NULL)
+ std::cerr<<"at token <"<<error_token<<"> ";
+
+ std::cerr<<"error : "<<s<<".\n";
+
+ if(error_source!=NULL)
+ {
+ std::cerr<<"source: line "<<error_source->line<<" column "<<error_source->column;
+
+ if(error_source->file!=NULL)
+ std::cerr<<" in \""<<error_source->file<<"\"";
+
+ std::cerr<<".\n";
+ };
+
+ error_where =NULL;
+ error_source=NULL;
+
+ exit(-2);
+};
+
diff --git a/rasdl/parse.cc b/rasdl/parse.cc
new file mode 100644
index 0000000..127b821
--- /dev/null
+++ b/rasdl/parse.cc
@@ -0,0 +1,996 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include "rasdl/parse.hh"
+#include "symbtbl.hh"
+#include "yparse.hh"
+
+#include <stdlib.h>
+
+#include "debug/debug.hh"
+
+#include "raslib/rmdebug.hh"
+#include "catalogmgr/typefactory.hh"
+#include "relcatalogif/alltypes.hh"
+
+extern void output_scope(FILE*out,const YSymbolTable::Scope*scope);
+
+Parse_info::Parse_info()
+ : line(0), column(0), file(NULL), token(NULL)
+{
+}
+
+
+Parse_info::Parse_info( long lineNo, int columnNo, const char* fileName, const char* tokenName )
+ : line( lineNo ), column( columnNo ), file(NULL), token(NULL)
+{
+ if( fileName )
+ file = strdup( fileName );
+
+ if( tokenName )
+ token = strdup( tokenName );
+}
+
+
+
+Parse_info::Parse_info( YWhere &where, const char* tokenName )
+ : line( where.line ), column( where.column ), file(NULL), token(NULL)
+{
+ if( where.file )
+ file = strdup( where.file );
+
+ if( tokenName )
+ token = strdup( tokenName );
+}
+
+
+
+Parse_info::Parse_info( const Parse_info& obj )
+{
+ line = obj.line;
+ column = obj.column;
+
+ file = obj.file ? strdup( obj.file ) : NULL;
+ token = obj.token ? strdup( obj.token ) : NULL;
+}
+
+
+
+Parse_info::~Parse_info()
+{
+ if( file ) { free( file ); file = NULL; }
+ if( token ) { free( token ); token = NULL; }
+}
+
+
+
+const Parse_info&
+Parse_info::operator=( const Parse_info& obj )
+{
+ if( this != &obj )
+ {
+ line = obj.line;
+ column = obj.column;
+
+ file = obj.file ? strdup( obj.file ) : NULL;
+ token = obj.token ? strdup( obj.token ) : NULL;
+ }
+
+ return *this;
+}
+
+
+
+/* THE ATOM */
+Parse_atom::Parse_atom()
+{
+ kind =Atom;
+ name =NULL;
+ symbol =NULL;
+}
+
+Parse_atom::~Parse_atom()
+{
+}
+
+void Parse_atom::insertData() const throw( r_Equery_execution_failed )
+{
+ RMDBGONCE(4, RMDebug::module_rasdl, "Parse_atom", "printData() kind " << kind << ", name " << name << ", symbol " << symbol)
+ TALK( "Parse_atom::insertData: doing nothing with name=" << name << ", symbol=" << symbol)
+}
+
+
+void Parse_atom::setParseInfo( const Parse_info &token )
+{
+ parseInfo = token;
+}
+
+
+const Parse_info& Parse_atom::getParseInfo()
+{
+ return parseInfo;
+}
+
+
+
+/* THE TYPE */
+Parse_type::Parse_type()
+{
+ kind =Type;
+ forward =false;
+};
+
+Parse_type::~Parse_type()
+{
+}
+
+const Type*
+Parse_type::getType( const char* /*typeName*/ ) const
+{
+ std::cerr << "Internal error: getType() for a subclass of Parse_type not implemented." << std::endl;
+ return NULL;
+}
+
+Parse_typereference::Parse_typereference()
+{
+ kind =Typereference;
+ type =NULL;
+}
+
+Parse_typereference::~Parse_typereference()
+{
+}
+
+void Parse_typereference::output(FILE*stream)const
+{
+ fprintf(stream,"%s",type->name);
+};
+
+const Type*
+Parse_typereference::getType( const char* /*typeName*/ ) const
+{
+ const BaseType* catBaseType = TypeFactory::mapType( (char*)type->name );
+
+ if( !catBaseType )
+ // Error: Type reference not found..
+ throw( r_Equery_execution_failed( 902, symbol->where.line, symbol->where.column, symbol->get_name() ) );
+
+ return catBaseType;
+}
+
+
+/* composite */
+Parse_composite::Parse_composite()
+{
+ kind =Composite;
+ elements =NULL;
+};
+
+Parse_composite::Element::Element()
+{
+ readonly =false;
+ type =NULL;
+ name =NULL;
+ access =Private;
+
+ next =NULL;
+};
+
+Parse_composite::Element::~Element()
+{
+}
+
+void Parse_composite::Element::output(FILE*stream)const
+{
+ fprintf(stream," ");
+ type->output(stream);
+ fprintf(stream," %s;",name);
+
+ if(readonly)
+ fprintf(stream,"// ___readonly___\n");
+ else
+ fprintf(stream,"\n");
+};
+
+/* struct */
+Parse_struct::Parse_struct()
+{
+ kind =Struct;
+};
+
+Parse_struct::~Parse_struct()
+{
+}
+
+void Parse_struct::output(FILE*stream)const
+{
+ fprintf(stream,"/* STRUCT -------------------------- %s */\n",name);
+ fprintf(stream,"struct %s {\n",name);
+
+ for(Element*scan=elements;scan!=NULL;scan=scan->next)
+ scan->output(stream);
+
+ fprintf(stream,"};\n");
+};
+
+
+
+void Parse_struct::insertData() const throw( r_Equery_execution_failed )
+{
+ ENTER( "Parse_struct::insertData" );
+ RMDBGENTER(4, RMDebug::module_rasdl, "Parse_struct", "insertData()")
+
+ // get catalog type structure
+ StructType* catType = (StructType*)getType();
+ TALK( "got type " << (char*)catType->getTypeName() );
+
+ RMDBGMIDDLE(4, RMDebug::module_rasdl, "Parse_struct", "inserting type " << catType->getTypeName())
+
+ if( TypeFactory::mapType( (char*)catType->getTypeName() ) )
+ // Error: Struct type name exists already.
+ throw( r_Equery_execution_failed( 905, symbol->where.line, symbol->where.column, symbol->get_name() ) );
+
+ TALK( "adding to the database as cell struct type" );
+ TypeFactory::addStructType( catType );
+
+ RMDBGEXIT(4, RMDebug::module_rasdl, "Parse_struct", "insertData()")
+ LEAVE( "Parse_struct::insertData" );
+};
+
+
+
+const Type*
+Parse_struct::getType( const char* /*typeName*/ ) const
+{
+ unsigned int noElements=0;
+ StructType* structType=NULL;
+ Element* scan=NULL;
+
+RMDBGENTER(4, RMDebug::module_rasdl, "Parse_struct", "getType()")
+
+ for( scan=elements; scan!=NULL; scan=scan->next, noElements++ );
+
+RMDBGMIDDLE(4, RMDebug::module_rasdl, "Parse_struct", "Struct " << name << " has " << noElements << " elements.")
+
+ structType = new StructType( (char*)name, noElements );
+
+ for( scan=elements; scan!=NULL; scan=scan->next)
+ if( !scan->type )
+ std::cerr << "Internal error: struct element doesn't deliver a catalog type" << std::endl;
+ else
+ {
+RMDBGMIDDLE(4, RMDebug::module_rasdl, "Parse_struct", "Scan->name " << scan->name)
+ structType->addElement( (char*)(scan->name), (BaseType*)(scan->type->getType()) );
+ }
+
+RMDBGEXIT(4, RMDebug::module_rasdl, "Parse_struct", "getType()" )
+
+ return structType;
+}
+
+
+
+/* union */
+Parse_union::Parse_union()
+{
+ kind =Union;
+};
+
+Parse_union::~Parse_union()
+{
+}
+
+void Parse_union::output(FILE*stream)const
+{
+ fprintf(stream,"/* UNION --------------------------- %s */\n",name);
+ fprintf(stream,"struct %s {\n",name);
+
+ for(Element*scan=elements;scan!=NULL;scan=scan->next)
+ scan->output(stream);
+
+ fprintf(stream,"};\n");
+};
+
+/* interface */
+Parse_interface::Parse_interface()
+{
+ kind =Interface;
+
+ base_classes =NULL;
+ lifetime =undefined;
+
+ methods =NULL;
+ relationships =NULL;
+};
+
+void print_access_mode(FILE*stream,Parse_composite::Access_mode access)
+{
+ switch(access)
+ {
+ case Parse_composite::Private:
+ {
+ fprintf(stream,"private:\n");
+ break;
+ };
+ case Parse_composite::Public:
+ {
+ fprintf(stream,"public:\n");
+ break;
+ };
+ case Parse_composite::Protected:
+ {
+ fprintf(stream,"protected:\n");
+ break;
+ };
+ };
+};
+
+void Parse_interface::output(FILE*stream)const
+{
+ if(forward)
+ {
+ fprintf(stream,"class %s;/*<forward definition>*/\n",name);
+ return;
+ };
+
+ fprintf(stream,"/* CLASS --------------------------- %s */\n",name);
+ if(base_classes!=NULL)
+ {
+ fprintf(stream,"class %s : ",name);
+
+ for(Base_class *scan=base_classes;scan!=NULL;scan=scan->next)
+ {
+ scan->output(stream);
+ if(scan->next!=NULL)
+ fprintf(stream,",");
+ };
+
+ fprintf(stream,"\n{\n");
+ }
+ else
+ fprintf(stream,"class %s {\n",name);
+
+// output all symbols
+ symbol->defines->output(stream);
+
+ Access_mode current_access=Private;
+
+ if(methods!=NULL)
+ {
+ fprintf(stream,"// operations\n");
+ methods->output(stream);
+ };
+
+ if(elements!=NULL)
+ {
+ fprintf(stream,"// attributes\n");
+
+ for(Element *scan=elements;scan!=NULL;scan=scan->next)
+ {
+ if(scan->access!=current_access)
+ {
+ current_access=scan->access;
+ print_access_mode(stream,current_access);
+ };
+ scan->output(stream);
+ };
+ };
+
+ if(relationships!=NULL)
+ {
+ fprintf(stream,"//relationships\n");
+ }
+
+ fprintf(stream,"};\n");
+};
+
+Parse_interface::Base_class::Base_class()
+{
+ base_class =NULL;
+ access =Private;
+
+ next =NULL;
+};
+
+void Parse_interface::Base_class::output(FILE*stream)const
+{
+ if(base_class==NULL)
+ fprintf(stream,"<none>");
+ else
+ switch(access)
+ {
+ case Private:
+ fprintf(stream,"private %s",base_class->name);
+ break;
+ case Public:
+ fprintf(stream,"public %s",base_class->name);
+ break;
+ case Protected:
+ fprintf(stream,"protected %s",base_class->name);
+ break;
+ };
+};
+
+Parse_interface::Method::Method()
+{
+ function =NULL;
+ access =Private;
+
+ next =NULL;
+};
+
+void Parse_interface::Method::output(FILE*stream)const
+{
+ function->output(stream);
+ fprintf(stream,";\n");
+};
+
+/* function */
+Parse_function::Parse_function()
+{
+ kind =Function;
+
+ parameters =NULL;
+ return_type =NULL;
+};
+
+void Parse_function::output(FILE*stream)const
+{
+ return_type->output(stream);
+ fprintf(stream," %s(",name);
+
+ if(parameters!=NULL)
+ {
+ parameters->output(stream);
+ };
+ fprintf(stream,")");
+};
+
+Parse_function::Parameter::Parameter()
+{
+ type =NULL;
+ state =Unknown;
+ name =NULL;
+
+ next =NULL;
+};
+
+void Parse_function::Parameter::output(FILE*stream)const
+{
+ if(state==In)
+ fprintf(stream,"const ");
+
+ type->output(stream);
+
+ if(state==Out)
+ fprintf(stream,"&");
+ else
+ fprintf(stream," ");
+
+ fprintf(stream,"%s",name);
+};
+
+/* operation */
+Parse_operation::Parse_operation()
+{
+ kind =Operation;
+ scope_class =NULL;
+};
+
+/* pointer */
+Parse_pointer::Parse_pointer()
+{
+ kind =Pointer;
+ type =NULL;
+};
+
+void Parse_pointer::output(FILE*stream)const
+{
+ type->output(stream);
+ fprintf(stream,"*");
+};
+
+/* array */
+Parse_array::Parse_array()
+{
+ kind =Array;
+ size =0;
+};
+
+void Parse_array::output(FILE*stream)const
+{
+ type->output(stream);
+ fprintf(stream,"[%i]",size);
+};
+
+/* alias */
+Parse_alias::Parse_alias()
+{
+ kind =Alias;
+
+ type =NULL;
+ name =NULL;
+};
+
+void Parse_alias::output(FILE*stream)const
+{
+ fprintf(stream,"/* TYPEDEF ------------------------- %s */\n",name);
+ fprintf(stream,"typedef ");
+ type->output(stream);
+ fprintf(stream," %s",name);
+ fprintf(stream,";\n\n");
+};
+
+void Parse_alias::insertData() const throw( r_Equery_execution_failed )
+{
+ ENTER( "Parse_alias::insertData" );
+ RMDBGENTER(4, RMDebug::module_rasdl, "Parse_alias", "insertData()")
+
+ // get catalog type structure
+
+ const CType* catType = type->getType( name );
+ if( !catType )
+ {
+ std::cerr << "Internal error: no type in alias definition." << std::endl;
+ return;
+ }
+ TALK( "got type " << name );
+
+RMDBGIF(5, RMDebug::module_rasdl, "Parse_alias", \
+ { \
+ char* typeStructure = catType->getTypeStructure(); \
+ RMInit::dbgOut << "Name " << catType->getTypeName() << ", structure " << typeStructure << std::endl; \
+ free( typeStructure ); typeStructure = NULL; \
+ } )
+
+ switch( catType->getType() )
+ {
+ case MDDTYPE:
+ if( TypeFactory::mapMDDType( (char*)catType->getTypeName() ) )
+ {
+ delete catType;
+ // Error: MDD type name exists already.
+ throw( r_Equery_execution_failed( 906, symbol->where.line, symbol->where.column, symbol->get_name() ) );
+ }
+ TALK( "adding to the database as MDD type" );
+ TypeFactory::addMDDType( (MDDType*)catType );
+ break;
+
+ case SETTYPE:
+ if( TypeFactory::mapType( (char*)catType->getTypeName() ) )
+ {
+ delete catType;
+ // Error: Set type name exists already.
+ throw( r_Equery_execution_failed( 907, symbol->where.line, symbol->where.column, symbol->get_name() ) );
+ }
+ TALK( "adding to the database as set type" );
+ TypeFactory::addSetType( (SetType*)catType );
+ break;
+
+ default:
+ delete catType;
+ // Error: Type in typedef definition not supported
+ throw( r_Equery_execution_failed( 900, symbol->where.line, symbol->where.column, symbol->get_name() ) );
+ }
+
+ delete catType;
+
+ RMDBGEXIT( 4, RMDebug::module_rasdl, "Parse_alias", "insertData()")
+ LEAVE( "Parse_alias::insertData" );
+};
+
+/* enumerator */
+Parse_enum::Parse_enum()
+{
+ kind =Enum;
+ enumerators =NULL;
+};
+
+void Parse_enum::output(FILE*stream)const
+{
+ fprintf(stream,"/* ENUMERATION --------------------- %s */\n",name);
+ fprintf(stream,"enum %s {",name);
+
+ const Enumerator *scan=enumerators;
+ while(scan!=NULL)
+ {
+ fprintf(stream,"%s=%i",scan->name,scan->value);
+
+ scan=scan->next;
+ if(scan!=NULL)
+ fprintf(stream,",");
+ };
+
+ fprintf(stream,"};\n");
+};
+
+void Parse_enum::Enumerator::output(FILE*stream)const
+{
+ fprintf(stream,"// %s = %6i\n",name,value);
+};
+
+/* atomic types&classes */
+void Parse_atomic::output(FILE*stream)const
+{
+ fprintf(stream,"%s",name);
+};
+/* any */
+Parse_any::Parse_any()
+{
+ kind =Any;
+ name ="r_Any";
+};
+
+/* void */
+Parse_void::Parse_void()
+{
+ kind =Void;
+ name ="void";
+};
+
+/* string */
+Parse_string::Parse_string()
+{
+ kind =String;
+ name ="r_String";
+
+ length =0;
+};
+
+/* boolean */
+Parse_boolean::Parse_boolean()
+{
+ kind =Boolean;
+ name ="r_Boolean";
+};
+
+const Type*
+Parse_boolean::getType( const char* /*typeName*/ ) const
+{
+ return TypeFactory::mapType("Bool" );
+}
+
+/* float */
+Parse_float::Parse_float()
+{
+ kind =Float;
+ name ="float";
+ accurance =Single;
+};
+
+void Parse_float::output(FILE*stream)const
+{
+ switch(accurance)
+ {
+ case Single:
+ fprintf(stream,"r_Float");
+ break;
+ case Double:
+ fprintf(stream,"r_Double");
+ break;
+ }
+};
+
+
+
+const Type*
+Parse_float::getType( const char* /*typeName*/ ) const
+{
+ const BaseType* type;
+
+ if( accurance == Single )
+ type = TypeFactory::mapType("Float");
+ else
+ type = TypeFactory::mapType("Double");
+
+ return type;
+}
+
+
+
+/* int */
+Parse_int::Parse_int()
+{
+ kind =Integer;
+ name ="int";
+
+ width =Short;
+ sign =Signed;
+};
+
+void Parse_int::output(FILE*stream)const
+{
+ switch(sign)
+ {
+ case Signed:
+ switch(width)
+ {
+ case Long:
+ fprintf(stream,"r_Long ");
+ break;
+ case Short:
+ fprintf(stream,"r_Short ");
+ break;
+ }
+ break;
+ case Unsigned:
+ switch(width)
+ {
+ case Long:
+ fprintf(stream,"r_ULong ");
+ break;
+ case Short:
+ fprintf(stream,"r_UShort ");
+ break;
+ }
+ break;
+ }
+};
+
+
+
+const Type*
+Parse_int::getType( const char* /*typeName*/ ) const
+{
+ const BaseType* type;
+
+ if( sign == Signed )
+ {
+ switch(width)
+ {
+ case Long:
+ type = TypeFactory::mapType("Long" );
+ break;
+ case Short:
+ type = TypeFactory::mapType("Short");
+ break;
+ }
+ }
+ else
+ {
+ switch(width)
+ {
+ case Long:
+ type = TypeFactory::mapType("ULong" );
+ break;
+ case Short:
+ type = TypeFactory::mapType("UShort");
+ break;
+ }
+ }
+
+ return type;
+}
+
+
+
+/* octet */
+Parse_octet::Parse_octet()
+{
+ kind =Octet;
+ name ="r_Octet";
+};
+
+
+
+const Type*
+Parse_octet::getType( const char* /*typeName*/ ) const
+{
+ return TypeFactory::mapType("Octet");
+}
+
+
+/* complex1 */
+Parse_complex1::Parse_complex1()
+{
+ kind = Complex1;
+ name = "r_Complex1";
+};
+
+
+
+const Type*
+Parse_complex1::getType( const char* /*typeName*/ ) const
+{
+ return TypeFactory::mapType("Complex1");
+}
+
+/* complex2 */
+Parse_complex2::Parse_complex2()
+{
+ kind = Complex2;
+ name = "r_Complex2";
+};
+
+
+
+const Type*
+Parse_complex2::getType( const char* /*typeName*/ ) const
+{
+ return TypeFactory::mapType("Complex2");
+}
+
+
+
+
+/* char */
+Parse_char::Parse_char()
+{
+ kind =Char;
+ name ="r_Char";
+};
+
+const Type*
+Parse_char::getType( const char* /*typeName*/ ) const
+{
+ return TypeFactory::mapType("Char");
+}
+
+
+
+// forwiss atomics
+Parse_atomic_templates::Parse_atomic_templates()
+{
+ kind =Atomic_template;
+ base_type =NULL;
+};
+
+Parse_MDD::Parse_MDD()
+{
+ kind =MDD;
+ domain =NULL;
+};
+
+void Parse_MDD::output(FILE*stream)const
+{
+ fprintf(stream,"r_Marray<");
+ if(base_type!=NULL)
+ base_type->output(stream);
+ else
+ fprintf(stream,"no_type");
+
+ if(domain!=NULL)
+ {
+ fprintf(stream,"/*");
+ char* stringDomain = domain->get_string_representation();
+ fprintf(stream,"%s",stringDomain);
+ free(stringDomain);
+ fprintf(stream,"*/");
+ };
+ fprintf(stream,"> ");
+};
+
+
+
+const Type*
+Parse_MDD::getType( const char* typeName ) const
+{
+ RMDBGENTER( 4, RMDebug::module_rasdl, "Parse_MDD", "getType()" )
+
+ if( !base_type ||
+ ( base_type->kind != Typereference && base_type->kind != Boolean &&
+ base_type->kind != Float && base_type->kind != Integer &&
+ base_type->kind != Char && base_type->kind != Octet &&
+ base_type->kind != Complex1 && base_type->kind != Complex2
+ )
+ )
+ // Error: MDD base type has to be a type reference or an atomic type.
+ throw( r_Equery_execution_failed( 903, parseInfo.line, parseInfo.column, parseInfo.token ) );
+
+ // if( !domain )
+ // // Error: MDD type must have a domain specification.
+ // throw( r_Equery_execution_failed( 904, parseInfo.line, parseInfo.column, parseInfo.token ) );
+
+ if( !typeName )
+ {
+ std::cerr << "Internal error: mdd type needs a type name" << std::endl;
+ return 0;
+ }
+
+ const BaseType* catBaseType = (BaseType*)base_type->getType();
+
+RMDBGIF(4, RMDebug::module_rasdl, "Parse_MDD", \
+ { \
+ char* typeStructure = catBaseType->getTypeStructure(); \
+ RMInit::dbgOut << " Base type name " << catBaseType->getTypeName() << ", structure " << typeStructure << std::endl; \
+ free( typeStructure ); typeStructure = NULL; \
+ } )
+
+ RMDBGMIDDLE(4, RMDebug::module_rasdl, "Parse_MDD", "type name " << typeName << ", base typIe name " << catBaseType->getTypeName() )
+
+ const MDDType* mddType;
+
+ if( domain )
+ mddType = new MDDDomainType( (char*)typeName, catBaseType, *domain );
+ else if( dimensionality )
+ mddType = new MDDDimensionType( (char*)typeName, catBaseType, (r_Dimension)dimensionality );
+ else
+ mddType = new MDDBaseType( (char*)typeName, catBaseType );
+
+ RMDBGEXIT(4, RMDebug::module_rasdl, "Parse_MDD", "getType()")
+
+ return mddType;
+}
+
+
+
+Parse_set::Parse_set()
+{
+ kind =Set;
+};
+
+void Parse_set::output(FILE*stream)const
+{
+ fprintf(stream,"r_Set<r_Ref<");
+ base_type->output(stream);
+ fprintf(stream,"> >");
+};
+
+
+
+const Type*
+Parse_set::getType( const char* typeName ) const
+{
+ RMDBGENTER(4, RMDebug::module_rasdl, "Parse_set", "getType()")
+
+ if( !base_type || base_type->kind != Typereference )
+ // Error: Set template type has to be a type reference.
+ throw( r_Equery_execution_failed( 901, parseInfo.line, parseInfo.column, parseInfo.token ) );
+
+ if( !typeName )
+ {
+ std::cerr << "Internal error: mdd type needs a type name" << std::endl;
+ return NULL;
+ }
+
+ const char* baseTypeName = ((Parse_typereference*)base_type)->type->name;
+
+ if( !baseTypeName )
+ {
+ std::cerr << "Internal error: set type needs a base type name" << std::endl;
+ return NULL;
+ }
+
+ RMDBGMIDDLE(4, RMDebug::module_rasdl, "Parse_set", "Base type name " << baseTypeName)
+
+ const MDDType* catBaseType = TypeFactory::mapMDDType( (char*)baseTypeName );
+
+ if( !catBaseType )
+ // Error: Type reference not found..
+ throw( r_Equery_execution_failed( 902, base_type->symbol->where.line, base_type->symbol->where.column, base_type->name ) );
+
+RMDBGIF(5, RMDebug::module_rasdl, "Parse_set", \
+ { \
+ char* typeStructure = catBaseType->getTypeStructure(); \
+ RMInit::dbgOut << " Name " << catBaseType->getTypeName() << ", structure " << typeStructure << std::endl; \
+ free( typeStructure ); typeStructure = NULL; \
+ })
+
+ RMDBGMIDDLE(4, RMDebug::module_rasdl, "Parse_set", "type name " << typeName << ", base type name " << baseTypeName )
+
+ const SetType* setType = new SetType( (char*)typeName, catBaseType );
+
+ RMDBGEXIT(4, RMDebug::module_rasdl, "Parse_set", "getType()")
+
+ return setType;
+}
+
diff --git a/rasdl/parse.hh b/rasdl/parse.hh
new file mode 100644
index 0000000..0afc177
--- /dev/null
+++ b/rasdl/parse.hh
@@ -0,0 +1,748 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#ifndef __PARSE_H
+#define __PARSE_H
+
+// Put it in front of any typedef bool ... because o2 is using bool as a variable.
+// #include "o2template_CC.hxx"
+
+#include "raslib/minterval.hh"
+#include "raslib/error.hh"
+
+#include "relcatalogif/basetype.hh"
+#include "relcatalogif/type.hh"
+
+#include <stdio.h>
+
+class YSymbol;
+
+typedef Type CType;
+
+//@ManMemo: Module: {\bf rasdl}
+
+/**
+ C structure representing a position in source.
+*/
+struct YWhere
+{
+ ///
+ long line;
+ ///
+ int column;
+ ///
+ const char* file;
+};
+
+
+
+//@ManMemo: Module: {\bf rasdl}
+
+/**
+ C++ structure representing a position in source.
+*/
+class Parse_info
+{
+ public:
+ ///
+ Parse_info();
+
+ ///
+ Parse_info( long lineNo, int columnNo, const char* fileName, const char* tokenName );
+
+ ///
+ Parse_info( YWhere &where, const char* tokenName );
+
+ /// copy constructor
+ Parse_info( const Parse_info& obj );
+
+ /// destructor
+ ~Parse_info();
+
+ /// assignment operator
+ const Parse_info& operator=( const Parse_info& obj );
+
+ ///
+ long line;
+ ///
+ int column;
+ ///
+ char* file;
+ ///
+ char* token;
+};
+
+
+
+//@ManMemo: Module: {\bf rasdl}
+
+/**
+ Base class for all types which can easily be converted to numbers.
+*/
+class Parse_number
+{
+};
+
+
+
+//@ManMemo: Module: {\bf rasdl}
+
+/**
+ Virtual base class for all objects with kind and output.
+*/
+
+class Parse_atom {
+public:
+ ///
+ Parse_atom();
+ ///
+ virtual ~Parse_atom();
+ ///
+ virtual void output(FILE*)const=0;
+ ///
+ virtual void insertData() const throw( r_Equery_execution_failed );
+
+ ///
+ void setParseInfo( const Parse_info &token );
+
+ ///
+ const Parse_info& getParseInfo();
+
+ ///
+ enum Kind {
+ Atom,Type,
+ Typedefinition,
+ Typereference,
+
+ Composite,
+ Struct,Union,Interface,
+
+ Function,
+ Operation,
+
+ Pointer,
+ Array,
+ Alias,
+
+ Enum,
+
+ Atomic,
+ Any,Void,Boolean,Float,Integer,Char,Octet,Complex1,Complex2,String,
+
+ Atomic_template,
+ Domain,Set,MDD
+ };
+
+ ///
+ Kind kind;
+ ///
+ const char *name;
+ ///
+ YSymbol *symbol;
+
+ /// definition of corresponding token
+ Parse_info parseInfo;
+};
+
+
+
+//@ManMemo: Module: {\bf rasdl}
+
+/**
+ Virtual base class for all types.
+*/
+class Parse_type : public Parse_atom {
+public:
+ ///
+ Parse_type();
+ ///
+ virtual ~Parse_type();
+ ///
+ Parse_type(char*);
+
+ ///
+ virtual const CType* getType( const char* typeName = NULL ) const;
+
+ /// this type is defined as forward {should be moved into YSymbol}
+ bool forward;
+};
+
+
+
+
+//@ManMemo: Module: {\bf rasdl}
+
+/**
+ Virtual base class for all types that create a new one.
+*/
+class Parse_typedefinition : public Parse_type
+{
+};
+
+
+
+//@ManMemo: Module: {\bf rasdl}
+
+/**
+ Represents a reference to a type.
+*/
+class Parse_typereference : public Parse_type
+{
+public:
+ ///
+ Parse_typereference();
+ ///
+ virtual ~Parse_typereference();
+ ///
+ virtual void output(FILE*)const;
+
+ ///
+ virtual const CType* getType( const char* typeName = NULL ) const;
+
+ ///
+ const Parse_type *type;
+};
+
+
+
+//@ManMemo: Module: {\bf rasdl}
+
+/**
+ Virtual base class for all types that are a kind of composite.
+*/
+class Parse_composite : public Parse_typedefinition {
+public:
+ ///
+ Parse_composite();
+
+ ///
+ enum Access_mode {Private,Public,Protected};
+
+ ///
+ class Element : public Parse_atom
+ {
+ public:
+ ///
+ Element();
+ ///
+ virtual ~Element();
+ ///
+ virtual void output(FILE*)const;
+
+ ///
+ bool readonly;
+ ///
+ const Parse_type *type;
+ ///
+ Access_mode access;
+
+ ///
+ Element *next;
+ };
+
+ ///
+ Element *elements;
+};
+
+
+
+//@ManMemo: Module: {\bf rasdl}
+
+/**
+ Class that represents the STRUCT type.
+*/
+class Parse_struct : public Parse_composite {
+public:
+ ///
+ Parse_struct();
+ ///
+ virtual ~Parse_struct();
+ ///
+ virtual void output(FILE*)const;
+ ///
+ virtual void insertData() const throw( r_Equery_execution_failed );
+ ///
+ virtual const CType* getType( const char* typeName = NULL ) const;
+};
+
+
+
+//@ManMemo: Module: {\bf rasdl}
+
+/**
+ Class that represents the UNION type.
+*/
+class Parse_union : public Parse_composite {
+ ///
+ Parse_union();
+ ///
+ virtual ~Parse_union();
+ ///
+ virtual void output(FILE*)const;
+};
+
+
+class Parse_operation;
+
+
+//@ManMemo: Module: {\bf rasdl}
+
+/**
+ class that represents the INTERFACE type
+*/
+class Parse_interface : public Parse_composite {
+public:
+ ///
+ Parse_interface();
+ ///
+ virtual void output(FILE*)const;
+
+ ///
+ enum Lifetime{persistend,transient,undefined};
+
+ ///
+ class Base_class : public Parse_atom
+ {
+ public:
+ ///
+ Base_class();
+ ///
+ virtual void output(FILE*)const;
+
+ ///
+ Parse_interface *base_class;
+ ///
+ Access_mode access;
+
+ ///
+ Base_class *next;
+ };
+
+ ///
+ class Method : public Parse_atom
+ {
+ public:
+ ///
+ Method();
+ ///
+ virtual void output(FILE*)const;
+
+ ///
+ Parse_operation *function;
+
+ ///
+ Access_mode access;
+
+ ///
+ Method *next;
+ };
+
+ ///
+ Base_class *base_classes;
+ ///
+ Lifetime lifetime;
+ ///
+ Method *methods;
+ ///
+ void *relationships;
+};
+
+
+
+//@ManMemo: Module: {\bf rasdl}
+
+/**
+ Represents a simple function with parameters and return value.
+*/
+class Parse_function : public Parse_atom {
+public:
+ ///
+ Parse_function();
+ ///
+ virtual void output(FILE*)const;
+
+ ///
+ class Parameter : public Parse_atom
+ {
+ public:
+ ///
+ Parameter();
+ ///
+ virtual void output(FILE*)const;
+
+ ///
+ Parse_typereference *type;
+ ///
+ enum {In,Out,Unknown} state;
+
+ ///
+ Parameter *next;
+ };
+
+ ///
+ Parameter *parameters;
+ ///
+ Parse_typereference *return_type;
+};
+
+
+
+//@ManMemo: Module: {\bf rasdl}
+
+/**
+ Is a operation of an Parse_interface.
+*/
+class Parse_operation : public Parse_function {
+public:
+ ///
+ Parse_operation();
+
+ ///
+ Parse_interface *scope_class;
+};
+
+
+
+//@ManMemo: Module: {\bf rasdl}
+
+/**
+ Class that represents pointer like types.
+*/
+class Parse_pointer : public Parse_typedefinition {
+public:
+ ///
+ Parse_pointer();
+ ///
+ virtual void output(FILE*)const;
+
+ ///
+ const Parse_type *type;
+};
+
+
+
+//@ManMemo: Module: {\bf rasdl}
+
+/**
+ Class that represents an ARRAY.
+*/
+class Parse_array : public Parse_pointer {
+public:
+ ///
+ Parse_array();
+ ///
+ virtual void output(FILE*)const;
+ ///
+ int size;
+};
+
+
+
+//@ManMemo: Module: {\bf rasdl}
+
+/**
+ Gives a type another name.
+*/
+class Parse_alias : public Parse_typedefinition {
+public:
+ ///
+ Parse_alias();
+ ///
+ virtual void output(FILE*)const;
+ ///
+ virtual void insertData() const throw( r_Equery_execution_failed );
+ ///
+ const Parse_type *type;
+};
+
+
+
+//@ManMemo: Module: {\bf rasdl}
+
+/**
+*/
+class Parse_enum : public Parse_typedefinition,public Parse_number
+{
+public:
+ ///
+ Parse_enum();
+ ///
+ virtual void output(FILE*)const;
+
+ ///
+ class Enumerator : public Parse_atom
+ {
+ public:
+ ///
+ virtual void output(FILE*)const;
+
+ ///
+ const char *name;
+ ///
+ int value;
+ ///
+ Enumerator *next;
+ };
+
+ ///
+ Enumerator *enumerators;
+};
+
+
+
+//@ManMemo: Module: {\bf rasdl}
+
+/**
+*/
+class Parse_atomic : public Parse_typedefinition {
+public:
+ ///
+ virtual void output(FILE*)const;
+};
+
+
+
+//@ManMemo: Module: {\bf rasdl}
+
+/**
+*/
+class Parse_any : public Parse_atomic {
+public:
+ ///
+ Parse_any();
+};
+
+
+
+//@ManMemo: Module: {\bf rasdl}
+
+/**
+*/
+class Parse_void : public Parse_atomic {
+public:
+ ///
+ Parse_void();
+};
+
+
+
+//@ManMemo: Module: {\bf rasdl}
+
+/**
+*/
+class Parse_string : public Parse_atomic
+{
+public:
+ ///
+ Parse_string();
+
+ ///
+ int length;
+};
+
+
+
+//@ManMemo: Module: {\bf rasdl}
+
+/**
+ A fractional number.
+*/
+class Parse_float : public Parse_atomic,public Parse_number {
+public:
+ ///
+ Parse_float();
+ ///
+ virtual void output(FILE*)const;
+ ///
+ virtual const CType* getType( const char* typeName = NULL ) const;
+
+ ///
+ enum {Double,Single} accurance;
+};
+
+
+
+//@ManMemo: Module: {\bf rasdl}
+
+/**
+ Represents a non-fractional number signed/unsigned or 16/32 number.
+*/
+class Parse_int : public Parse_atomic,public Parse_number {
+public:
+ ///
+ Parse_int();
+ ///
+ virtual void output(FILE*)const;
+ ///
+ virtual const CType* getType( const char* typeName = NULL ) const;
+
+ ///
+ enum {Short,Long} width;
+ ///
+ enum {Unsigned,Signed} sign;
+};
+
+
+
+//@ManMemo: Module: {\bf rasdl}
+
+/**
+ An 8-bit unsigned number.
+*/
+class Parse_octet : public Parse_atomic,public Parse_number
+{
+public:
+ ///
+ Parse_octet();
+ ///
+ virtual const CType* getType( const char* typeName = NULL ) const;
+};
+
+//@ManMemo: Module: {\bf rasdl}
+
+class Parse_complex1 : public Parse_atomic,public Parse_number
+{
+public:
+ ///
+ Parse_complex1();
+ ///
+ virtual const CType* getType( const char* typeName = NULL ) const;
+};
+
+
+class Parse_complex2 : public Parse_atomic,public Parse_number
+{
+public:
+ ///
+ Parse_complex2();
+ ///
+ virtual const CType* getType( const char* typeName = NULL ) const;
+};
+
+
+
+
+//@ManMemo: Module: {\bf rasdl}
+
+/**
+ Represents an 8-bit unsigned number.
+*/
+class Parse_char : public Parse_atomic,public Parse_number {
+public:
+ ///
+ Parse_char();
+ ///
+ virtual const CType* getType( const char* typeName = NULL ) const;
+};
+
+
+
+//@ManMemo: Module: {\bf rasdl}
+
+/**
+*/
+class Parse_boolean : public Parse_atomic,public Parse_number {
+public:
+ ///
+ Parse_boolean();
+ ///
+ virtual const CType* getType( const char* typeName = NULL ) const;
+};
+
+
+
+//@ManMemo: Module: {\bf rasdl}
+
+/**
+*/
+class Parse_atomic_templates : public Parse_atomic {
+public:
+ ///
+ Parse_atomic_templates();
+ ///
+ const Parse_type *base_type;
+};
+
+
+
+//@ManMemo: Module: {\bf rasdl}
+
+/**
+*/
+class Parse_set : public Parse_atomic_templates {
+public:
+ ///
+ Parse_set();
+ ///
+ virtual void output(FILE*)const;
+ ///
+ virtual const CType* getType( const char* typeName = NULL ) const;
+};
+
+
+
+//@ManMemo: Module: {\bf rasdl}
+
+/**
+*/
+class Parse_MDD : public Parse_atomic_templates {
+public:
+ ///
+ Parse_MDD();
+
+ ///
+ virtual void output(FILE*)const;
+
+ ///
+ virtual const CType* getType( const char* typeName = NULL ) const;
+
+ ///
+ r_Minterval* domain;
+
+ ///
+ unsigned long dimensionality;
+};
+#endif
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/rasdl/rasdl.awk b/rasdl/rasdl.awk
new file mode 100644
index 0000000..79f99dc
--- /dev/null
+++ b/rasdl/rasdl.awk
@@ -0,0 +1,11 @@
+BEGIN { paren = 0; sec = 0; comm = 0 }
+/^ *$/ { next; }
+/\%\%/ { sec += 1; next; }
+sec!=1 { next; }
+/^\/\*$/ { comm = 1; next; }
+/^\*\// { comm = 0; next; }
+comm == 1 { next; }
+/^\/\*.*\*\// { next; }
+/{/ { x=$0; sub(/\{.*/, "", x); if(!paren) print x; paren += 1; }
+/}/ { paren -= 1; next; }
+!paren { print $0; }
diff --git a/rasdl/rasdl.cc b/rasdl/rasdl.cc
new file mode 100644
index 0000000..6202c39
--- /dev/null
+++ b/rasdl/rasdl.cc
@@ -0,0 +1,724 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ * The internal functions return 0 on error, 1 on success. Not really common,
+ * but it was used in some routines and so I stuck with it. Norbert 25-05-2001.
+ *
+ * BUGS:
+ * - for inconsistent dictionnaries strange output might be generated
+ * which is not syntactically correct.
+ *
+ ************************************************************/
+
+static const char rasdl_rcsid[] = "@(#)rasdl,rasdl.cc: $Id: rasdl.cc,v 1.48 2007/02/21 19:47:28 rasdev Exp $";
+
+#define DEBUG
+#define DEBUG_MAIN
+#include "debug/debug.hh"
+
+#ifndef RMANVERSION
+#error "Please specify RMANVERSION variable!"
+#endif
+
+#ifndef COMPDATE
+#error "Please specify the COMPDATE variable!"
+/*
+COMPDATE=`date +"%d.%m.%Y %H:%M:%S"`
+
+and -DCOMPDATE="\"$(COMPDATE)\"" when compiling
+*/
+#endif
+
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#ifdef __GNUG__
+#include "template_inst.hh"
+#endif
+#endif
+
+#include <iostream> // cout
+#include <sstream> // cout
+#include <iomanip>
+#include <set>
+#include <map>
+using namespace std;
+
+#include <stdio.h> // fopen, perror
+#include <stdlib.h> // for atol()
+#include <string.h>
+#include <ctype.h>
+#include <sys/times.h> // time(), ctime()
+
+#include "globals.hh" // DEFAULT_DBNAME
+
+#include "reladminif/adminif.hh"
+#include "reladminif/databaseif.hh"
+#include "reladminif/transactionif.hh"
+
+#include "relcatalogif/settype.hh"
+#include "relcatalogif/mdddomaintype.hh"
+#include "relcatalogif/mdddimensiontype.hh"
+#include "relcatalogif/alltypes.hh"
+#include "catalogmgr/typefactory.hh"
+#ifndef BASEDB_O2
+ #include "reladminif/dbref.hh"
+#endif
+
+#include "raslib/rminit.hh"
+#include "raslib/rmdebug.hh"
+
+
+// error codes, exceptions
+#include "rasdl_error.hh"
+
+// error texts
+#define ERROR_NOACTION "EDL000 Error: no action specified."
+#define ERROR_UNKNOWNACTION "EDL001 Error: unknown action type: "
+#define ERROR_PANIC "EDL002 panic: unexpected internal exception."
+#define ERROR_RASDAMAN "EDL003 rasdaman error: "
+
+
+// init globals for server initialization
+RMINITGLOBALS('S')
+
+#include "commline/cmlparser.hh"
+
+// command line flags and options
+
+#define FLAG_DATABASE 'd'
+#define PARAM_DATABASE "database"
+#define HELP_DATABASE "<db-name> name of the database"
+
+#define PARAM_BASENAME "basename"
+#define HELP_BASENAME "<db-name> name of the database (deprecated, use --database)"
+#define DEFAULT_BASENAME DEFAULT_DBNAME
+
+#define FLAG_CREATE 'c'
+#define PARAM_CREATE "createdatabase"
+#define HELP_CREATE "create database and initialize schema information"
+
+#define PARAM_DELDB "deldatabase"
+#define HELP_DELDB "delete database"
+
+#define FLAG_PRINT 'p'
+#define PARAM_PRINT "print"
+#define HELP_PRINT "print all types"
+
+#define FLAG_READ 'r'
+#define PARAM_READ "read"
+#define HELP_READ "<file> read data definition file"
+
+#define PARAM_DELBASETYPE "delbasetype"
+#define HELP_DELBASETYPE "<base-name> delete base type with name <base-name>"
+
+#define PARAM_DELMDDTYPE "delmddtype"
+#define HELP_DELMDDTYPE "<mdd-name> delete mdd type with name <mdd-name>"
+
+#define PARAM_DELSETTYPE "delsettype"
+#define HELP_DELSETTYPE "<set-name> delete set type with name <set-name>"
+
+#define FLAG_INSERT 'i'
+#define PARAM_INSERT "insert"
+#define HELP_INSERT "insert types into database (requires -r)"
+
+#define PARAM_HH "hh"
+#define HELP_HH "<hh-file> print C++ header into <hh-file> (requires -r)"
+
+#define PARAM_CONNECT "connect"
+#define HELP_CONNECT "<connect-str> connect string for underlying database (syntax depending on base DBMS, e.g., rasbase@serverhost)"
+#define DEFAULT_CONNECT "/"
+
+#define PARAM_DEBUG "debug"
+#define HELP_DEBUG "print diagnostic output"
+
+#define FLAG_HELP 'h'
+#define PARAM_HELP "help"
+#define HELP_HELP "print this help"
+
+
+#ifdef EXIT_SUCCESS
+ #undef EXIT_SUCCESS
+#endif
+#ifdef EXIT_FAILURE
+ #undef EXIT_FAILURE
+#endif
+#ifdef EXIT_HELP
+ #undef EXIT_HELP
+#endif
+// program return codes
+#define EXIT_SUCCESS 0
+#define EXIT_FAILURE -1
+#define EXIT_HELP 2
+
+#include "rasdl/symbtbl.hh"
+#include "rasdl/yparse.hh"
+
+// globalso for lex and yacc code
+extern int yyparse();
+extern FILE *yyin;
+extern YSymbolTable *Symbols;
+
+// pointers representing O2, database, ta and session
+AdminIf* admin = NULL;
+DatabaseIf* db = NULL;
+TransactionIf* ta = NULL;
+
+// command indicator (what to do)
+enum ProgModes
+{
+ M_INVALID,
+ M_PRINT,
+ M_READ,
+ M_DELBASETYPE,
+ M_DELSETTYPE,
+ M_DELMDDTYPE,
+ M_CREATEDATABASE,
+ M_DELDATABASE,
+ M_HELP
+};
+
+ProgModes progMode = M_INVALID;
+
+// this variable is provided for Admin/DatabaseIf for opening connections, it holds the connect string
+char globalConnectId[256];
+
+
+const char *baseName = DEFAULT_BASENAME;
+const char *odlFileName = "";
+const char *headerFileName = "";
+const char *deleteName = "";
+const char *dbSchema = "";
+const char *dbVolume = "";
+int optionValueIndex;
+int insertIntoDb = 0;
+bool printToFile = false;
+
+
+void
+printNames()
+{
+ TypeIterator<StructType> structIter = TypeFactory::createStructIter();
+
+ cout << endl;
+ cout << "// rasdaman database '" << baseName << "' type definitions" << endl;
+ time_t now = time(NULL);
+ cout << "// generated on: " << ctime( &now );
+ cout << endl;
+
+ cout << "//" << endl;
+ cout << "// marray base types" << endl;
+ cout << "//" << endl;
+
+ while(structIter.not_done())
+ {
+ StructType* typePtr = structIter.get_element();
+ char* typeStructure = typePtr->getTypeStructure();
+
+ cout << "typedef " << typeStructure << " " << typePtr->getTypeName() << ";" << endl;
+
+ free( typeStructure );
+ typeStructure = NULL;
+
+ structIter.advance();
+ }
+
+ cout << endl;
+ cout << "//" << endl;
+ cout << "// marray types" << endl;
+ cout << "//" << endl;
+
+ TypeIterator<MDDType> mddIter = TypeFactory::createMDDIter();
+
+ while(mddIter.not_done())
+ {
+ MDDType* typePtr = mddIter.get_element();
+ char* typeStructure = typePtr->getTypeStructure();
+
+ cout << "typedef " << typeStructure << " " << typePtr->getTypeName() << ";" << endl;
+
+ free( typeStructure );
+ typeStructure = NULL;
+
+ mddIter.advance();
+ }
+
+ cout << endl;
+ cout << "//" << endl;
+ cout << "// set types" << endl;
+ cout << "//" << endl;
+
+ TypeIterator<SetType> setIter = TypeFactory::createSetIter();
+
+ while(setIter.not_done())
+ {
+ SetType* typePtr = setIter.get_element();
+ char* typeStructure = typePtr->getTypeStructure();
+
+ cout << "typedef " << typeStructure << " " << typePtr->getTypeName() << ";" << endl;
+
+ free( typeStructure );
+ typeStructure = NULL;
+
+ setIter.advance();
+ }
+
+ cout << endl;
+}
+
+
+void
+printHeader( const char* headerFileName )
+{
+ cout << "Generating header file " << headerFileName << "..." << flush;
+
+ FILE *file=fopen( headerFileName, "wt" );
+ if(!file)
+ throw RasdlError( CANNOTWRITEHDR );
+
+ char* defName = new char[strlen(headerFileName)+1];
+ if (defName == NULL)
+ throw RasdlError( CANNOTALLOC );
+
+ // generate upper case version for include guard
+ int i = 0;
+ while( headerFileName[i] != '.' && headerFileName[i] != '\0' )
+ {
+ defName[i] = toupper( headerFileName[i] );
+ i++;
+ }
+ defName[i] = '\0';
+
+ /* header description */
+ fprintf(file,"//------------------------------------------------------------\n");
+ fprintf(file,"// This file is created automatically by the rasdl processor.\n");
+ fprintf(file,"// better than modifying this file is to re-generate it. \n");
+ fprintf(file,"//------------------------------------------------------------\n");
+ fprintf(file,"\n");
+ fprintf(file,"#ifndef __%s_HH_\n", defName );
+ fprintf(file,"#define __%s_HH_\n", defName );
+ fprintf(file,"\n");
+ fprintf(file,"//------------------------------------------------------------\n");
+ fprintf(file,"// Includes\n");
+ fprintf(file,"//------------------------------------------------------------\n");
+ fprintf(file,"\n");
+ fprintf(file,"#include \"rasdaman.hh\"\n");
+ fprintf(file,"\n");
+
+ Symbols->global_scope->output(file);
+
+ fprintf(file,"#endif\n");
+
+ fclose(file);
+ delete[] defName;
+ defName = NULL;
+
+ cout << "ok" << endl;
+}
+
+void
+disconnectDB( bool commitTa )
+{
+ ENTER( "disconnectDB, commitTa =" << commitTa );
+
+ if( ta )
+ {
+ if(commitTa )
+ {
+ ta->commit();
+ TALK( "TA committed." );
+ }
+ else
+ {
+ ta->abort();
+ TALK( "TA aborted." );
+ }
+
+ delete ta;
+ ta = NULL;
+
+ if( db )
+ {
+ db->close();
+ TALK( "DB closed." );
+ delete db;
+ db = NULL;
+ }
+
+ if( admin )
+ {
+ delete admin;
+ admin = NULL;
+ }
+ }
+ LEAVE( "disconnectDB" );
+}
+
+void
+connectDB( const char* baseName, bool openDb, bool openTa ) throw (r_Error, RasdlError)
+{
+ ENTER( "connectDB, basename=" << baseName );
+
+ admin = AdminIf::instance();
+ if( !admin )
+ {
+ TALK( "cannot create adminIf instance" );
+ throw RasdlError( NOCONNECTION );
+ }
+
+ if ( openDb )
+ {
+ // connect to the database
+ db = new DatabaseIf();
+ // TALK( "adding dbf to adminif" );
+ // admin->setCurrentDatabaseIf( db );
+ TALK( "opening db" );
+ db->open( baseName );
+ }
+
+ if ( openTa )
+ {
+ // start transaction
+ ta = new TransactionIf();
+ TALK( "opening ta" );
+ ta->begin( db );
+ }
+
+ LEAVE( "connectDB" );
+}
+
+//analyse params
+void
+parseParams(int argc, char* argv[]) throw (r_Error, RasdlError)
+{
+ CommandLineParser &cmlInter = CommandLineParser::getInstance();
+
+ CommandLineParameter &cmlHelp = cmlInter.addFlagParameter( FLAG_HELP, PARAM_HELP, HELP_HELP );
+
+ CommandLineParameter &cmlDbName = cmlInter.addStringParameter( FLAG_DATABASE, PARAM_DATABASE, HELP_DATABASE, DEFAULT_BASENAME );
+ CommandLineParameter &cmlBaseName = cmlInter.addStringParameter(CommandLineParser::noShortName, PARAM_BASENAME, HELP_BASENAME, DEFAULT_BASENAME );
+ CommandLineParameter &cmlCreateDb = cmlInter.addFlagParameter( FLAG_CREATE, PARAM_CREATE, HELP_CREATE );
+ CommandLineParameter &cmlDelDb = cmlInter.addFlagParameter(CommandLineParser::noShortName, PARAM_DELDB, HELP_DELDB );
+ CommandLineParameter &cmlReadMeta = cmlInter.addStringParameter( FLAG_READ, PARAM_READ, HELP_READ );
+ CommandLineParameter &cmlInsertInDb = cmlInter.addFlagParameter( FLAG_INSERT, PARAM_INSERT, HELP_INSERT );
+
+ CommandLineParameter &cmlHHGen = cmlInter.addStringParameter(CommandLineParser::noShortName, PARAM_HH, HELP_HH );
+ CommandLineParameter &cmlPrintMeta = cmlInter.addFlagParameter( FLAG_PRINT, PARAM_PRINT, HELP_PRINT );
+
+ CommandLineParameter &cmlDelBaseType = cmlInter.addStringParameter(CommandLineParser::noShortName, PARAM_DELBASETYPE, HELP_DELBASETYPE );
+ CommandLineParameter &cmlDelMddType = cmlInter.addStringParameter(CommandLineParser::noShortName, PARAM_DELMDDTYPE, HELP_DELMDDTYPE );
+ CommandLineParameter &cmlDelSetType = cmlInter.addStringParameter(CommandLineParser::noShortName, PARAM_DELSETTYPE, HELP_DELSETTYPE );
+
+#ifdef BASEDB_O2
+ CommandLineParameter &cmlSchemaDb = cmlInter.addStringParameter(CommandLineParser::noShortName, "schema", "<sch-name> name of o2 schema used for new bases", "RasDaSchema");
+ CommandLineParameter &cmlVolumeDb = cmlInter.addStringParameter(CommandLineParser::noShortName, "volume", "<vol-name> name of o2 volume used for new bases");
+#endif
+
+ CommandLineParameter &cmlConnectStr = cmlInter.addStringParameter(CommandLineParser::noShortName, PARAM_CONNECT, HELP_CONNECT, DEFAULT_CONNECT );
+
+#ifdef DEBUG
+ CommandLineParameter &cmlDebug = cmlInter.addFlagParameter(CommandLineParser::noShortName, PARAM_DEBUG, HELP_DEBUG );
+#endif
+
+ try
+ {
+ cmlInter.processCommandLine(argc, argv);
+
+ if (argc == 1 || cmlHelp.isPresent())
+ {
+ static const char* ExDbName = DEFAULT_BASENAME;
+ static const char* ExBaseName = "char";
+ static const char* ExMddName = "GreyImage";
+ static const char* ExSetName = "GreySet";
+ static const char* ExMetaFile = "basictypes.dl";
+ static const char* ExHHFile = "basictypes.hh";
+
+ cout << "Usage: rasdl [options]" << endl;
+ cout << "Options:" << endl;
+ cmlInter.printHelp();
+
+ cout << "Examples:" << endl;
+ cout << " create database:\trasdl " << CommandLineParser::LongSign << cmlDbName.getLongName() << " " << ExDbName << " " << CommandLineParser::LongSign << cmlCreateDb.getLongName() << endl;
+ cout << " delete database:\trasdl " << CommandLineParser::LongSign << cmlDbName.getLongName() << " " << ExDbName << " " << CommandLineParser::LongSign << cmlDelDb.getLongName() << endl;
+ cout << " delete base type:\trasdl " << CommandLineParser::LongSign << cmlDbName.getLongName() << " " << ExDbName << " " << CommandLineParser::LongSign << cmlDelBaseType.getLongName() << " " << ExBaseName << endl;
+ cout << " delete mdd type:\trasdl " << CommandLineParser::LongSign << cmlDbName.getLongName() << " " << ExDbName << " " << CommandLineParser::LongSign << cmlDelMddType.getLongName() << " " << ExMddName << endl;
+ cout << " delete set type:\trasdl " << CommandLineParser::LongSign << cmlDbName.getLongName() << " " << ExDbName << " " << CommandLineParser::LongSign << cmlDelSetType.getLongName() << " " << ExSetName << endl;
+ cout << " print all types:\trasdl " << CommandLineParser::LongSign << cmlDbName.getLongName() << " " << ExDbName << " " << CommandLineParser::LongSign << cmlPrintMeta.getLongName() << endl;
+ cout << " insert types:\trasdl " << CommandLineParser::LongSign << cmlDbName.getLongName() << " " << ExDbName << " " << CommandLineParser::LongSign << cmlReadMeta.getLongName() << " " << ExMetaFile << " " << CommandLineParser::LongSign << cmlInsertInDb.getLongName() << endl;
+ cout << " generate C++ header from type file:\trasdl " << CommandLineParser::LongSign << cmlReadMeta.getLongName() << " " << ExMetaFile << " " << CommandLineParser::LongSign << cmlHHGen.getLongName() << " " << ExHHFile << endl;
+ exit( EXIT_HELP ); // bash ret code for usage; FIXME: exit() no good style!
+ }
+
+#ifdef DEBUG
+ // debug
+ SET_OUTPUT( cmlDebug.isPresent() );
+#endif
+
+ if (cmlBaseName.isPresent())
+ baseName = cmlBaseName.getValueAsString();
+
+ if (cmlDbName.isPresent())
+ baseName = cmlDbName.getValueAsString();
+
+ //read mode
+ if( cmlReadMeta.isPresent())
+ {
+ progMode = M_READ;
+ odlFileName = cmlReadMeta.getValueAsString();
+ }
+
+ //schema && volume
+#ifdef BASEDB_O2
+ // to be done
+ dbSchema = cmlSchemaDb.getValueAsString());
+ if( cmlVolumeDb.isPresent())
+ {
+ if( cmlVolumeDb.getValueAsString())
+ dbVolume = cmlVolumeDb.getValueAsString());
+ }
+#endif
+
+ //hhgen
+ if( cmlHHGen.isPresent())
+ {
+ if( cmlHHGen.getValueAsString())
+ {
+ headerFileName = cmlHHGen.getValueAsString();
+ printToFile = true;
+ }
+ }
+
+ //insertindb
+ insertIntoDb = cmlInsertInDb.isPresent();
+
+ //print mode
+ if( cmlPrintMeta.isPresent())
+ progMode = M_PRINT;
+
+ //create mode
+ if( cmlCreateDb.isPresent())
+ progMode = M_CREATEDATABASE;
+
+ //delete mode
+ if( cmlDelDb.isPresent() )
+ progMode = M_DELDATABASE;
+
+ //delbasetype mode
+ if( cmlDelBaseType.isPresent() )
+ {
+ progMode = M_DELBASETYPE;
+ if( cmlDelBaseType.getValueAsString() )
+ deleteName = cmlDelBaseType.getValueAsString();
+ }
+
+ //delmddtype mode
+ if( cmlDelMddType.isPresent() )
+ {
+ progMode = M_DELMDDTYPE;
+ if( cmlDelMddType.getValueAsString())
+ deleteName = cmlDelMddType.getValueAsString();
+ }
+
+ //delsettype mode
+ if( cmlDelSetType.isPresent() )
+ {
+ progMode = M_DELSETTYPE;
+ if( cmlDelSetType.getValueAsString() )
+ deleteName = cmlDelSetType.getValueAsString();
+ }
+
+ // connectstr
+ if( cmlConnectStr.isPresent() )
+ strcpy( globalConnectId, cmlConnectStr.getValueAsString() );
+ else
+ strcpy( globalConnectId, DEFAULT_CONNECT );
+ }
+ catch ( CmlException & err)
+ {
+ throw RasdlError( CMDLINE );
+ }
+
+ // --- plausi checks ------------------------------------
+ // FIXME: to complete
+
+ // if something is to be deleted in the database, then a name must be specified
+ if ( cmlDelBaseType.isPresent() || cmlDelMddType.isPresent() || cmlDelSetType.isPresent() )
+ {
+ if ( deleteName == NULL || strlen(deleteName) == 0)
+ throw RasdlError( EMPTYTYPENAME );
+ }
+
+ // -r needs either -i or -hh
+ if( cmlReadMeta.isPresent() && ( !cmlInsertInDb.isPresent() && !cmlHHGen.isPresent() ) )
+ throw RasdlError( ILLEGALREADCOMBI );
+ if( ( cmlInsertInDb.isPresent() && cmlHHGen.isPresent() ) )
+ throw RasdlError( ILLEGALREADCOMBI );
+
+ if( cmlInsertInDb.isPresent() && !cmlReadMeta.isPresent() )
+ throw RasdlError( ILLEGALINSERTCOMBI );
+
+ if( cmlHHGen.isPresent() && !cmlReadMeta.isPresent() )
+ throw RasdlError( ILLEGALHHCOMBI );
+
+ TALK( "connect=" << globalConnectId );
+} // parseParams()
+
+void
+readMode() throw (r_Error, RasdlError)
+{
+ cout << "Reading rasdaman data definition file " << odlFileName << "..." << flush;
+
+ // yyin is used by yyparse()
+ yyin=fopen( odlFileName,"r" );
+ if( yyin==NULL )
+ throw RasdlError( ODLFILEFAILED );
+
+ int parseResult = yyparse();
+ if(yyin && (yyin != stdin))
+ fclose( yyin );
+ if( parseResult != 0)
+ throw RasdlError( ODLPARSEERROR );
+
+ if( insertIntoDb )
+ {
+ cout << "inserting symbols into database..." << flush;
+ Symbols->global_scope->insertData();
+ cout << "ok" << endl;
+ }
+ if( printToFile )
+ printHeader( headerFileName );
+
+ cout << "ok" << endl;
+}
+
+
+
+int
+main( int argc, char* argv[] )
+{
+ int result = EXIT_FAILURE;
+
+ cout << "rasdl: rasdaman schema and database manipulation tool, rasdaman v" << RMANVERSION / 1000.0 << " on base DBMS " << BASEDBSTRING << " -- generated on " << COMPDATE << "." << endl;
+
+ try
+ {
+ parseParams(argc,argv);
+
+ switch( progMode )
+ {
+ case M_READ:
+ connectDB( baseName, true, true );
+ readMode();
+ disconnectDB( true );
+ break;
+ case M_DELBASETYPE:
+ cout << "Deleting basetype " << deleteName << "..." << flush;
+ connectDB( baseName, true, true );
+ TypeFactory::deleteStructType( deleteName );
+ disconnectDB( true );
+ cout << "ok" << endl;
+ break;
+ case M_DELMDDTYPE:
+ cout << "Deleting MDD type " << deleteName << "..." << flush;
+ connectDB( baseName, true, true );
+ TypeFactory::deleteMDDType( deleteName );
+ disconnectDB( true );
+ cout << "ok" << endl;
+ break;
+ case M_DELSETTYPE:
+ cout << "Deleting set type " << deleteName << "..." << flush;
+ connectDB( baseName, true, true );
+ TypeFactory::deleteSetType( deleteName );
+ disconnectDB( true );
+ cout << "ok" << endl;
+ break;
+ case M_CREATEDATABASE:
+ cout << "Creating base " << baseName;
+#ifdef BASEDB_O2
+ cout << " with schema " << dbSchema;
+#endif
+ if( strcasecmp(dbVolume,"") )
+ cout << " on volume " << dbVolume;
+ cout << "..." << flush;
+ connectDB( baseName, false, false );
+ db = new DatabaseIf();
+ if( !strlen(dbVolume) )
+ db->createDB( baseName, dbSchema, dbVolume );
+ else
+ db->createDB( baseName, dbSchema );
+ disconnectDB( true );
+ cout << "ok" << endl;
+ break;
+ case M_DELDATABASE:
+ cout << "Deleting database " << baseName << "...";
+ TALK( "connecting" );
+ connectDB( baseName, false, false );
+ TALK( "creating new DatabaseIf" );
+ db = new DatabaseIf();
+ TALK( "destroying db" );
+ db->destroyDB(baseName);
+ disconnectDB( true );
+ cout << "ok" << endl;
+ break;
+ case M_PRINT:
+ connectDB( baseName, true, true );
+ printNames();
+ disconnectDB( false ); // abort TA - we did only reading
+ break;
+ case M_INVALID:
+ cerr << ERROR_NOACTION << endl;
+ break;
+ default:
+ cerr << ERROR_UNKNOWNACTION << progMode << endl;
+ }
+ result = EXIT_SUCCESS;
+ }
+ catch ( RasdlError& e)
+ {
+ cout << argv[0] << ": " << e.what() << endl;
+ result = EXIT_FAILURE;
+ }
+ catch ( const r_Error& e )
+ {
+ cout << ERROR_RASDAMAN << e.get_errorno() << ": " << e.what() << endl;
+ result = EXIT_FAILURE;
+ }
+ catch (...)
+ {
+ cout << argv[0] << " " << ERROR_PANIC << endl;
+ result = EXIT_FAILURE;
+ }
+
+ if (result != EXIT_SUCCESS)
+ disconnectDB(false);
+
+ cout << argv[0] << " done." << endl;
+
+ return( result );
+}
diff --git a/rasdl/rasdl_error.cc b/rasdl/rasdl_error.cc
new file mode 100644
index 0000000..6544ef1
--- /dev/null
+++ b/rasdl/rasdl_error.cc
@@ -0,0 +1,124 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+using namespace std;
+
+static const char rcsid[] = "@(#)raslib, RasdlError: $Id: rasdl_error.cc,v 1.1 2003/12/19 17:11:59 rasdev Exp $";
+
+#include <exception>
+#include <cstring>
+
+// for sprintf():
+#include <stdio.h>
+
+#include "rasdl_error.hh"
+
+// debug facility; relies on -DDEBUG at compile time
+#include "debug.hh"
+
+/// error object, carrying int error code
+RasdlError::RasdlError( unsigned int e )
+{
+ TALK( "Exception: " << e );
+ errno = e;
+}
+
+/// default destructor
+RasdlError::~RasdlError()
+{
+}
+
+/// print error message (including error code)
+/// NB: not all messages can occur
+const char*
+RasdlError::what()
+{
+ const char *errorMsg;
+ switch (errno)
+ {
+ case CANNOTALLOC:
+ errorMsg = "Cannot allocate memoery.";
+ break;
+ case CANNOTWRITEHDR:
+ errorMsg = "Cannot write header file.";
+ break;
+ case NOCONNECTION:
+ errorMsg = "Cannot connect to database.";
+ break;
+ case EMPTYTYPENAME:
+ errorMsg = "Typename is empty.";
+ break;
+ case ILLEGALREADCOMBI:
+ errorMsg = "Parameter -r only in conjunction with -i or --hh.";
+ break;
+ case ODLFILEFAILED:
+ errorMsg = "Cannot access type definition file.";
+ break;
+ case ODLPARSEERROR:
+ errorMsg = "Syntax error in type definition file.";
+ break;
+ case ILLEGALHHCOMBI:
+ errorMsg = "Parameter -hh requires -r.";
+ break;
+ case ILLEGALINSERTCOMBI:
+ errorMsg = "Parameter -i requires -r.";
+ break;
+ case CMDLINE:
+ errorMsg = "Syntax error in command line.";
+ break;
+ default :
+ errorMsg = "Unknown error code.";
+ break;
+ case ALLDONE:
+ case 0:
+ errorMsg = "No errors.";
+ }
+
+// size of error text buffer below
+#define ERRTEXT_BUFSIZ 200
+
+ static char errorText[ERRTEXT_BUFSIZ];
+
+// text constants for error msg
+#define MODULE_TAG "DL"
+#define ERROR_TEXT " Error: "
+
+ // check for buffer overflow
+ if (strlen(MODULE_TAG) + 3 + strlen(ERROR_TEXT) + strlen(errorMsg) + 1 > ERRTEXT_BUFSIZ)
+ sprintf( errorText, "%s%03d%s", MODULE_TAG, errno, "(error message too long, cannot display)" );
+ else
+ sprintf( errorText, "%s%03d%s%s", MODULE_TAG, errno, ERROR_TEXT, errorMsg );
+
+ return errorText;
+} // what()
+
+
diff --git a/rasdl/rasdl_error.hh b/rasdl/rasdl_error.hh
new file mode 100644
index 0000000..7e69ffb
--- /dev/null
+++ b/rasdl/rasdl_error.hh
@@ -0,0 +1,77 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#ifndef _RASQL_ERROR_HH_
+#define _RASQL_ERROR_HH_
+
+#ifdef __VISUALC__
+#pragma warning( disable : 4290 )
+#endif
+
+//@ManMemo: Module: {\bf raslib}
+
+/*@Doc:
+
+ This class ...
+*/
+
+
+ /// valid error codes:
+#define ALLDONE -1
+#define OK 0
+#define CANNOTALLOC 1
+#define CANNOTWRITEHDR 2
+#define NOCONNECTION 3
+#define EMPTYTYPENAME 4
+#define ILLEGALREADCOMBI 5
+#define ODLFILEFAILED 6
+#define ODLPARSEERROR 7
+#define ILLEGALHHCOMBI 8
+#define ILLEGALINSERTCOMBI 9
+#define CMDLINE 10
+
+class RasdlError // : public std::exception
+{
+ public:
+
+ /// constructor receiving an error number
+ RasdlError( unsigned int e );
+
+ /// destructor
+ virtual ~RasdlError();
+
+ /// get an error description
+ virtual const char * what();
+
+ private:
+ /// error information
+ unsigned int errno;
+};
+
+#endif // _RASQL_ERROR_HH_
diff --git a/rasdl/rasdlgrammar.html b/rasdl/rasdlgrammar.html
new file mode 100644
index 0000000..73c2b2d
--- /dev/null
+++ b/rasdl/rasdlgrammar.html
@@ -0,0 +1,27 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+ <TITLE>RasDaMan: Specification</TITLE>
+ <META NAME="GENERATOR" CONTENT="Mozilla/3.0b6Gold (X11; I; HP-UX B.10.01 9000/770) [Netscape]">
+</HEAD>
+<BODY>
+
+<!-- BASE HREF=http://www.forwiss.tu-muenchen.de/ -->
+
+<H1><IMG SRC="/public/forwiss/projekte/rasdaman/rmanlogo-s.gif" ALT="[RasDaMan-Logo]" >Implementation
+Specification: RasDL Grammar</H1>
+
+<P>The following grammar specifies RasDL.</P>
+
+<PRE>
+
+<grammar>
+
+</PRE>
+
+<P><HR WIDTH="100%"></P>
+
+<P><A HREF="mailto:ritsch@forwiss.tu-muenchen.de">Roland Ritsch</A>, 1997-09-10</P>
+
+</BODY>
+</HTML> \ No newline at end of file
diff --git a/rasdl/symbtbl.cc b/rasdl/symbtbl.cc
new file mode 100644
index 0000000..02c6dfc
--- /dev/null
+++ b/rasdl/symbtbl.cc
@@ -0,0 +1,305 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ * The internal functions return 0 on error, 1 on success. Not really common,
+ * but it was used in some routines and so I stuck with it. Norbert 25-05-2001.
+ *
+ ************************************************************/
+
+#include "symbtbl.hh"
+
+#include "raslib/rmdebug.hh"
+
+#include "debug/debug.hh"
+
+YSymbol::YSymbol()
+{
+ TALK( "YSymbol::YSymbol default constructor" );
+
+ name =NULL;
+ next =NULL;
+ owned_by_symbol=true; // by default symbols owned by symbols
+
+ scope =NULL;
+ defines =NULL;
+};
+
+YSymbol::YSymbol(const char*_name)
+{
+ TALK( "YSymbol::YSymbol constructor, name=" << name );
+
+ name =_name;
+ next =NULL;
+ owned_by_symbol=true; // by default symbols owned by symbols
+
+ scope =NULL;
+ defines =NULL;
+};
+
+YSymbolTable::YSymbolTable()
+{
+ TALK( "YSymbolTable::YSymbolTable default constructor" );
+
+ scope =NULL;
+ global_scope =NULL;
+};
+
+void YSymbolTable::push_scope(YSymbol*owner)
+{
+ Scope *new_scope=new Scope;
+
+ new_scope->up =scope;
+ new_scope->son =NULL;
+ new_scope->symbols =NULL;
+ new_scope->last_symbol =NULL;
+ new_scope->owner =owner;
+
+ if(scope!=NULL)
+ {
+ new_scope->next =scope->son;
+ scope->son =new_scope;
+
+ owner->defines =new_scope;
+ }
+ else
+ {
+ new_scope->next =NULL;
+ };
+
+ if(owner==NULL)
+ global_scope=new_scope;
+
+ scope=new_scope;
+};
+
+const YSymbol *YSymbolTable::pop_scope()
+{
+ const YSymbol *old_symbol =scope->owner;
+ scope =scope->up;
+
+ return(old_symbol);
+};
+
+void YSymbolTable::insert_symbol(YSymbol*symbol)const
+{
+ ENTER( "YSymbolTable::insert_symbol" );
+
+ if(scope!=NULL)
+ {
+ TALK( "adding symbol " << symbol->get_name() );
+ if(scope->last_symbol==NULL)
+ scope->symbols=symbol;
+ else
+ scope->last_symbol->next=symbol;
+
+ scope->last_symbol = symbol;
+
+ symbol->next = NULL;
+ symbol->scope = scope;
+ }
+
+ LEAVE( "YSymbolTable::insert_symbol" );
+};
+
+bool YSymbolTable::search_this_scope(const char*name,const Scope*this_scope,YSymbol*&result)const
+{
+ ENTER( "YSymbolTable::search_this_scope" );
+
+ bool found = false;
+
+ if((name==NULL)||(this_scope==NULL))
+ found = false; /* no name or no scope */
+ else
+ {
+ for(YSymbol*scan=this_scope->symbols;scan!=NULL && found!=true;scan=scan->next)
+ {
+ if(!strcmp(name,scan->name))
+ {
+ result=scan;
+ found = true;
+ }
+ }
+ }
+
+ LEAVE( "YSymbolTable::search_this_scope -> " << found );
+ return( found );
+};
+
+bool YSymbolTable::search_scope(const char*name,YSymbol*&result)const
+{
+ return(search_this_scope(name,scope,result));
+};
+
+bool YSymbolTable::search_scopes(const char*name,YSymbol*&result)const
+{
+ for(Scope*scan=scope;scan!=NULL;scan=scan->up)
+ {
+ if(search_this_scope(name,scan,result))
+ return(true);
+ };
+ return(false);
+};
+
+bool YSymbolTable::search_scopes_above(const YSymbol*symbol,YSymbol*&result)const
+{
+ const char*name=symbol->get_name();
+ if(symbol->scope==NULL)
+ return(false);
+
+ for(Scope*scan=scope->up;scan!=NULL;scan=scan->up)
+ {
+ if(search_this_scope(name,scan,result))
+ return(true);
+ };
+ return(false);
+};
+
+bool YSymbolTable::search_my_scope(const char*name,const YSymbol*symbol,YSymbol*&result)const
+{
+ return(search_this_scope(name,symbol->defines,result));
+};
+
+bool YSymbolTable::search_global_scope(const char*name,YSymbol*&result)const
+{
+ if(scope==NULL)
+ return(false); /* no scope at all */
+
+ Scope*global;
+ for(global=scope;global->up!=NULL;global=global->up)
+ ; /* get up to the global scope */
+
+ return(search_this_scope(name,global,result));
+};
+
+//****************************************************************************
+//
+// name : get_symbol
+// purpose : returns symbol of name in current scope
+// remarks : returns NULL if no such symbol defined
+//
+//****************************************************************************
+const YSymbol *YSymbolTable::get_symbol(const char*name)const
+{
+ YSymbol*result;
+ if(search_scope(name,result))
+ return(result);
+ else
+ return(NULL);
+};
+
+//****************************************************************************
+//
+// name : scoped_symbol
+// purpose : creates symbol name within current scope
+// remarks : returns true if success full and false if name already exists
+// *result is always been changed to new or defined symbol
+//
+//****************************************************************************
+bool YSymbolTable::scoped_symbol(YSymbol**result,const char*name,const YWhere&where)
+{
+ if(search_scope(name,*result))
+ return(false); // duplicate identifier
+
+ *result=new YSymbol(name);
+ (*result)->where =where;
+
+ insert_symbol(*result);
+ return(true);
+};
+
+const YSymbol *YSymbolTable::get_defining_symbol()const
+{
+ if(scope==NULL)
+ return(NULL);
+ else
+ return(scope->owner);
+};
+
+
+
+void YSymbolTable::Scope::output(FILE*out)const
+{
+ ENTER( "YSymbolTable::Scope::output" );
+
+ YSymbol *scan=symbols;
+
+ while (scan!=NULL)
+ {
+ if(!scan->owned_by_symbol)
+ {
+ fprintf(out,"/*[%li,%i]*/",scan->where.line,scan->where.column);
+
+ switch(scan->type)
+ {
+ case YSymbol::dParse_Type:
+ scan->Type->output(out);
+ break;
+ case YSymbol::dParse_Enumerator:
+ scan->enumerator->output(out);
+ break;
+ default:
+ RMDBGONCE(0, RMDebug::module_rasdl, "YSymbolTable::Scope", "output() bad YSymbol_type " << scan->type);
+ break;
+ }
+ }
+ scan=(YSymbol*)scan->next;
+ }
+
+ LEAVE( "YSymbolTable::Scope::output" );
+};
+
+
+void YSymbolTable::Scope::insertData() const
+{
+ ENTER( "YSymbolTable::Scope::insertData" );
+
+ YSymbol *scan=symbols;
+
+ while(scan!=NULL)
+ {
+ if(!scan->owned_by_symbol)
+ {
+ switch(scan->type)
+ {
+ case YSymbol::dParse_Type:
+ scan->Type->insertData();
+ break;
+ case YSymbol::dParse_Enumerator:
+ // scan->enumerator->output(out);
+ break;
+ default:
+ RMDBGONCE(0, RMDebug::module_rasdl, "YSymbolTable::Scope", "output() bad YSymbol_type " << scan->type);
+ break;
+ }
+ }
+ scan=(YSymbol*)scan->next;
+ }
+
+ LEAVE( "YSymbolTable::Scope::insertData" );
+};
diff --git a/rasdl/symbtbl.hh b/rasdl/symbtbl.hh
new file mode 100644
index 0000000..ab2c0b4
--- /dev/null
+++ b/rasdl/symbtbl.hh
@@ -0,0 +1,196 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#ifndef __SYMBTABLE_H
+#define __SYMBTABLE_H
+
+#include "parse.hh"
+
+#include <string.h>
+
+class YSymbol;
+
+//@ManMemo: Module: {\bf rasdl}
+
+/**
+ Contains the all the symbols and the scopetree.
+*/
+class YSymbolTable {
+
+ friend class YSymbol;
+
+public:
+ ///
+ YSymbolTable();
+
+ /// get the corresponding symbol to name
+ const YSymbol *get_symbol(const char*name)const;
+ /// creates a symbol in the current scoped
+ bool scoped_symbol(YSymbol**result,const char*name,const YWhere&where);
+ /// get the symbol that defines this scope
+ const YSymbol *get_defining_symbol ()const;
+
+ /// search only current scope
+ bool search_scope (const char*,YSymbol*&)const;
+ /// search current scope and all abov
+ bool search_scopes (const char*,YSymbol*&)const;
+ /// search me all scopes above me, and not myself
+ bool search_scopes_above (const YSymbol*,YSymbol*&)const;
+ /// search a specified scope of a symbol
+ bool search_my_scope (const char*,const YSymbol*,YSymbol*&)const;
+ /// search the global_scope
+ bool search_global_scope (const char*,YSymbol*&)const;
+
+ ///
+ void insert_symbol (YSymbol*)const;
+
+ ///
+ void push_scope(YSymbol*);
+
+ ///
+ const YSymbol *pop_scope();
+
+ ///
+ struct Scope {
+ void output(FILE*out) const;
+ void insertData() const;
+
+ struct Scope *up;
+ struct Scope *next,*son;
+
+ YSymbol *symbols;
+ YSymbol *last_symbol; // last symbol defined in list {to assure correct order of symbols}
+
+ const YSymbol *owner; // which symbol is the owner of this scope
+ };
+
+ ///
+ Scope *scope;
+
+ ///
+ Scope *global_scope;
+
+ ///
+ inline bool search_this_scope (const char*,const Scope*,YSymbol*&)const;
+
+};
+
+
+
+//@ManMemo: Module: {\bf rasdl}
+
+/**
+ Literal used during parse process for result of an expression.
+*/
+struct YLiteral {
+ ///
+ enum Literal_type {dLfloat,dLinteger,dLchar,dLbool,dLstring} type;
+
+ ///
+ union {
+ ///
+ double Real;
+ ///
+ long Integer;
+ ///
+ const char *String;
+ ///
+ char Character;
+ ///
+ bool Boolean;
+ };
+};
+
+
+
+//@ManMemo: Module: {\bf rasdl}
+
+/**
+ To store constants durng parse process.
+*/
+struct YConstant
+{
+ ///
+ YLiteral value;
+ ///
+ Parse_type *type;
+};
+
+
+
+//@ManMemo: Module: {\bf rasdl}
+
+/**
+ Defines a symbol during parsing. It can represent various types of data.
+*/
+class YSymbol
+{
+ friend class YSymbolTable;
+
+public:
+ ///
+ YSymbol();
+ ///
+ YSymbol(const char*);
+
+ ///
+ const char *get_name()const{return(name);};
+
+ /// defined where
+ YWhere where;
+ /// defines wether this symbol is owned by another symbol or by a scope
+ bool owned_by_symbol;
+
+private:
+ ///
+ const char *name;
+
+public:
+ ///
+ YSymbol *next;
+ ///
+ const YSymbolTable::Scope *scope;
+ ///
+ const YSymbolTable::Scope *defines;
+
+ ///
+ enum YSymbol_type { dParse_Type,
+ dParse_Attribute,
+ dParse_Const,
+ dParse_Function,
+ dParse_Enumerator} type;
+ ///
+ union
+ {
+ ///
+ Parse_type *Type;
+ ///
+ Parse_composite::Element *Attribute;
+ ///
+ YConstant constant;
+
+ ///
+ Parse_enum::Enumerator *enumerator;
+ };
+};
+#endif
+
diff --git a/rasdl/template_inst.hh b/rasdl/template_inst.hh
new file mode 100644
index 0000000..c0b7eae
--- /dev/null
+++ b/rasdl/template_inst.hh
@@ -0,0 +1,83 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include <qlparser/symtab.hh>
+
+#include <raslib/itertype.hh>
+#include <raslib/attribute.hh>
+#include <raslib/dlist.hh>
+
+#include <indexmgr/keyobject.hh>
+
+#include <reladminif/dbref.hh>
+#include <reladminif/dbobjectiterator.hh>
+#include <reladminif/dbobjectiditerator.hh>
+#include <reladminif/dbobject.hh>
+
+#include <relblobif/dbtile.hh>
+#include <relblobif/blobtile.hh>
+#include <relblobif/inlinetile.hh>
+
+#include <relcatalogif/structtype.hh>
+#include <relcatalogif/settype.hh>
+#include <relcatalogif/mddtype.hh>
+#include <relcatalogif/dbminterval.hh>
+
+#include <relindexif/hierindex.hh>
+#include <relindexif/dbrcindexds.hh>
+#include <relindexif/dbtcindex.hh>
+
+#include <relmddif/dbmddobj.hh>
+#include <relmddif/dbmddset.hh>
+
+#include <relstorageif/dbstoragelayout.hh>
+
+template class DBObjectIterator<SetType>;
+template class DBObjectIterator<StructType>;
+template class DBObjectIterator<MDDType>;
+template class DBObjectIterator<DBMDDObj>;
+template class DBObjectIdIterator<DBMDDObj>;
+template bool operator< (const DBRef<DBMDDObj>&, const DBRef<DBMDDObj>&);
+
+template class DBRef<DBTile>;
+template class DBRef<InlineTile>;
+template class DBRef<BLOBTile>;
+template class DBRef<DBObject>;
+template class DBRef<DBMDDObj>;
+template class DBRef<DBMDDSet>;
+template class DBRef<DBHierIndex>;
+template class DBRef<DBTCIndex>;
+template class DBRef<DBRCIndexDS>;
+template class DBRef<DBMinterval>;
+template class DBRef<StructType>;
+template class DBRef<MDDType>;
+template class DBRef<SetType>;
+template class DBRef<DBStorageLayout>;
+
+template class r_IterType<r_Attribute>;
+
+template class SymbolTable<int>;
+
+template std::ostream& operator<< (const std::vector<KeyObject>&, std::ostream&);
+template std::ostream& operator<< (std::ostream &, const std::vector<KeyObject>&);
+template std::ostream& operator<< (std::ostream &, const std::vector<double>&);
+
diff --git a/rasdl/test/Makefile b/rasdl/test/Makefile
new file mode 100644
index 0000000..765ae1a
--- /dev/null
+++ b/rasdl/test/Makefile
@@ -0,0 +1,78 @@
+# -*-Makefile-*-
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+#
+# MAKEFILE FOR:
+# test programs of module qlparser
+#
+# COMMENTS:
+#
+##################################################################
+#
+# This is just an example Makefile for a test program.
+# The dependency of the test program on the lib of the
+# corresponding module is in the Makefile of the module.
+#
+
+######################### Definitions ############################
+
+# standard include with general options
+include $(RMANBASE)/Makefile.inc
+
+# all test programs
+SRCCXX = test_rasdl.cc
+OBJS = ${SRCCXX:%.cc=%.o}
+ALLTESTS = ${SRCCXX:%.cc=%}
+MISCCLEAN = core
+
+# add compile and link options for STL
+CXXFLAGS += $(STLCXXFLAGS)
+LDFLAGS += $(STLLDFLAGS)
+
+########################### Targets ##############################
+
+# general system test
+.PHONY: systemtest
+systemtest:
+ rasdl_test.sh > rasdl_test.log 2>&1
+ diff rasdl_test.log rasdl_test.log.orig || (echo deviation found in rasdl test; exit)
+
+# test target for qlparser
+.PHONY : rasdl
+rasdl: test_module test_rasdl
+
+.PHONY : test_module
+test_module:
+ cd $(RMANBASE)/rasdl; $(MAKE)
+
+test_rasdl: test_rasdl.o $(RASDL)
+ $(CXX) $(LDFLAGS) -o $@ $^
+
+######################## Dependencies ############################
+
+test_rasdl.o: test_rasdl.cc
+
+# general rules
+include $(RMANBASE)/Makefile.rel
+
+# automatically created dependencies
+include Makefile.dep
diff --git a/rasdl/test/basictypes.dl b/rasdl/test/basictypes.dl
new file mode 100644
index 0000000..60c9123
--- /dev/null
+++ b/rasdl/test/basictypes.dl
@@ -0,0 +1,157 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+// ---------------------------------------------------------------------
+//
+//
+// PURPOSE:
+// This file contains type definitions to challenge the rasdl utilit.
+// Rasdl needs to read them and react appropriately. Reports are done
+// to stdout.
+//
+//
+// COMMENTS:
+// ./.
+//
+//
+// ---------------------------------------------------------------------
+
+
+// --- good defs -------------------------------------------------------
+// --- bad defs --------------------------------------------------------
+
+
+
+// example 1
+typedef marray <char,2> GreyImage;
+typedef set<GreyImage> GreySet;
+
+// example 2
+typedef marray <boolean,2> BoolImage;
+typedef set<BoolImage> BoolSet;
+
+// example 3
+struct RGBPixel { char red, green, blue; };
+typedef marray <RGBPixel,2> RGBImage;
+typedef set<RGBImage> RGBSet;
+
+// example 4
+typedef marray <unsigned long, 2> ULongImage;
+typedef set<ULongImage> ULongSet;
+
+// example 5
+typedef marray <char, 3> GreyCube;
+typedef set<GreyCube> GreySet3;
+
+
+// heavily expanded types (Andreas)
+typedef marray <boolean, 1> BoolString;
+typedef set<BoolString> BoolSet1;
+
+typedef marray <boolean, 3> BoolCube;
+typedef set<BoolCube> BoolSet3;
+
+typedef marray <char, 1> GreyString;
+typedef set<GreyString> GreySet1;
+
+typedef marray <octet, 1> OctetString;
+typedef set<OctetString> OctetSet1;
+
+typedef marray <octet, 2> OctetImage;
+typedef set<OctetImage> OctetSet;
+
+typedef marray <octet, 3> OctetCube;
+typedef set<OctetCube> OctetSet3;
+
+typedef marray <short, 1> ShortString;
+typedef set<ShortString> ShortSet1;
+
+typedef marray <short, 2> ShortImage;
+typedef set<ShortImage> ShortSet;
+
+typedef marray <short, 3> ShortCube;
+typedef set<ShortCube> ShortSet3;
+
+typedef marray <unsigned short, 1> UShortString;
+typedef set<UShortString> UShortSet1;
+
+typedef marray <unsigned short, 2> UShortImage;
+typedef set<UShortImage> UShortSet;
+
+typedef marray <unsigned short, 3> UShortCube;
+typedef set<UShortCube> UShortSet3;
+
+typedef marray <long, 1> LongString;
+typedef set<LongString> LongSet1;
+
+typedef marray <long, 2> LongImage;
+typedef set<LongImage> LongSet;
+
+typedef marray <long, 3> LongCube;
+typedef set<LongCube> LongSet3;
+
+typedef marray <unsigned long, 1> ULongString;
+typedef set<ULongString> ULongSet1;
+
+typedef marray <unsigned long, 3> ULongCube;
+typedef set<ULongCube> ULongSet3;
+
+typedef marray <RGBPixel, 1> RGBString;
+typedef set<RGBString> RGBSet1;
+
+typedef marray <RGBPixel, 3> RGBCube;
+typedef set<RGBCube> RGBSet3;
+
+typedef marray <float, 1> FloatString;
+typedef set<FloatString> FloatSet1;
+
+typedef marray <float, 2> FloatImage;
+typedef set<FloatImage> FloatSet;
+
+typedef marray <float, 3> FloatCube;
+typedef set<FloatCube> FloatSet3;
+
+typedef marray <float, 4> FloatCube4;
+typedef set<FloatCube4> FloatSet4;
+
+typedef marray <double, 1> DoubleString;
+typedef set<DoubleString> DoubleSet1;
+
+typedef marray <double, 2> DoubleImage;
+typedef set<DoubleImage> DoubleSet;
+
+typedef marray <double, 3> DoubleCube;
+typedef set<DoubleCube> DoubleSet3;
+
+typedef marray <complex, 1> Gauss1;
+typedef set<Gauss1> GaussSet1;
+
+typedef marray<complexd, 1> Gauss2;
+typedef set<Gauss2> GaussSet2;
+
+typedef marray <complex, 2> Gauss1Image;
+typedef set<Gauss1Image> Gauss1Set;
+
+typedef marray<complexd, 2> Gauss2Image;
+typedef set<Gauss2Image> Gauss2Set;
+
+// --- end -----------------------------------------------------------
diff --git a/rasdl/test/rasdl_test.sh b/rasdl/test/rasdl_test.sh
new file mode 100644
index 0000000..c465f3a
--- /dev/null
+++ b/rasdl/test/rasdl_test.sh
@@ -0,0 +1,103 @@
+#!/bin/bash -x
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+#
+# rasdl_test.sh: test rasdl
+#
+# COMMENTS:
+# - deletes and recreates databases, needs base DBMS up and running
+# - FIXME: under work
+# - bash -x serves to log command lines
+# - has local copy of basictypes.dl; keep consistent!
+##################################################################
+
+# program to be tested
+RASDL=../rasdl
+
+# databases to be used (will be destroyed!)
+DB1=TESTDB1
+DB2=TESTDB2
+
+echo "$0: start rasdl test."
+
+# help
+$RASDL -h
+$RASDL --help
+
+# unknown parameter
+$RASDL --unknown
+$RASDL -y
+
+# inconsistent parameters and options
+$RASDL -i
+$RASDL --hh headerfile
+$RASDL
+
+# --- from here on we need database connection
+# clean starting point, result is of no interest
+$RASDL --database $DB1 --deldatabase
+$RASDL --database $DB2 --deldatabase
+
+# --- nonex. db
+
+#delete nonexisting database
+$RASDL --database $DB2 --deldatabase
+
+# fill into nonexisting database
+$RASDL --database $DB2 --read basictypes.dl --insert
+
+# --- good cases
+
+# create db, regular
+$RASDL --database $DB1 --createdatabase
+
+# create existing database
+$RASDL --database $DB1 --createdatabase
+
+# fill into existing database
+$RASDL --database $DB1 --read basictypes.dl --insert
+
+# print types
+$RASDL --database $DB1 --print
+
+# generate hh file
+rm basictypes.hh
+$RASDL --database $DB1 --hh basictypes.hh
+# for the diff lateron:
+cat basictypes.hh
+
+# delete base type
+$RASDL --database $DB1 --delbasetype char
+$RASDL --database $DB1 --print
+
+# delete MDD type
+$RASDL --database $DB1 --delmddtype GreyImage
+$RASDL --database $DB1 --print
+
+# delete set type
+$RASDL --database $DB1 --delsettype GreySet
+$RASDL --database $DB1 --print
+
+# delete database (cleanup)
+$RASDL --database $DB1 --deldatabase
+
+echo "$0: rasdl test done."
diff --git a/rasdl/test/test_rasdl.cc b/rasdl/test/test_rasdl.cc
new file mode 100644
index 0000000..9577168
--- /dev/null
+++ b/rasdl/test/test_rasdl.cc
@@ -0,0 +1,80 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+// #include <conio.h>
+#include <iostream>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "rasdl/symbtbl.hh"
+#include "rasdl/yparse.hh"
+
+extern int yyparse();
+extern FILE *yyin;
+extern YSymbolTable *Symbols;
+
+int main(int argc,char *argv[])
+{
+ if(argc!=3)
+ {
+ cerr<<"USAGE: odl odl-script cpp-header";
+ exit(-1);
+ };
+
+ cout<<"--BEGIN-------------------------------------------------------------------------";
+ cout<<"opening \""<<argv[1]<<"\"...";
+ yyin=fopen(argv[1],"r");
+
+ if(yyin==NULL)
+ {
+ cout<<"fail!\n";
+ cerr<<"\nfailed to open "<<argv[1]<<".\n";
+
+ exit(-1);
+ };
+
+ cout<<"ok!\n";
+
+ cout<<"parsing...";
+ yyparse();
+ cout<<"done!\n";
+
+ cout<<"output...";
+
+ FILE *file=fopen(argv[2],"wt");
+
+ /* header description */
+ fprintf(file,"//------------------------------------------------------------\n");
+ fprintf(file,"// automatic created C++-header \n");
+ fprintf(file,"//------------------------------------------------------------\n");
+ fprintf(file,"\n");
+
+ Symbols->global_scope->output(file);
+
+ fclose(file);
+
+ cout<<"done!\n";
+ cout<<"--END---------------------------------------------------------------------------";
+
+ return(0);
+};
+
diff --git a/rasdl/yparse.hh b/rasdl/yparse.hh
new file mode 100644
index 0000000..d8d9615
--- /dev/null
+++ b/rasdl/yparse.hh
@@ -0,0 +1,59 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#ifndef __YPARSE_H
+#define __YPARSE_H
+
+#include "symbtbl.hh"
+#include "parse.hh"
+
+//@ManMemo: Module: {\bf rasdl}
+
+/**
+ A list of integers.
+*/
+struct rINT_list
+{
+ ///
+ int data;
+
+ ///
+ rINT_list *next;
+};
+
+
+//@ManMemo: Module: {\bf rasdl}
+
+/**
+ A list of symbols.
+*/
+struct YDeclarator
+{
+ ///
+ YSymbol *symbol;
+ ///
+ rINT_list *array_size;
+ ///
+ YDeclarator *next;
+};
+
+#endif
diff --git a/rasdoc/Doxyfile_external b/rasdoc/Doxyfile_external
new file mode 100644
index 0000000..fa378a1
--- /dev/null
+++ b/rasdoc/Doxyfile_external
@@ -0,0 +1,1284 @@
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+#--------------------- doxygen header -----------------------------------------------
+#
+# PURPOSE:
+# doxygen settings for generating HTML documentation, EXTERNAL version.
+#
+# COMMENTS:
+# - written for doxygen 1.5.6
+# - IMPORTANT: paths are written for doxygen invocation IN THE ROOT DIRECTORY.
+#
+#-------------------------------------------------------------------------------------
+
+# Doxyfile 1.5.0
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = rasdaman
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = documentation/external/doc
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian,
+# Italian, Japanese, Japanese-en (Japanese with English messages), Korean,
+# Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian,
+# Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE = English
+
+# This tag can be used to specify the encoding used in the generated output.
+# The encoding is not always determined by the language that is chosen,
+# but also whether or not the output is meant for Windows or non-Windows users.
+# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES
+# forces the Windows encoding (this is the default for the Windows binary),
+# whereas setting the tag to NO uses a Unix-style encoding (the default for
+# all platforms other than Windows).
+
+#USE_WINDOWS_ENCODING = NO
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like the Qt-style comments (thus requiring an
+# explicit @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member
+# documentation.
+
+DETAILS_AT_TOP = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for Java.
+# For instance, namespaces will be presented as packages, qualified scopes
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to
+# include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = YES
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES = NO
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from the
+# version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = raslib rasodmg compression conversion
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py
+
+FILE_PATTERNS = *.hh
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output. If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default)
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default)
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code. Otherwise they will link to the documentstion.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader. This is useful
+# if you want to understand what is going on. On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = NO
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will
+# generate a call dependency graph for every global function or class method.
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then doxygen will
+# generate a caller dependency graph for every global function or class method.
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+#MAX_DOT_GRAPH_WIDTH = 1024
+
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+#MAX_DOT_GRAPH_HEIGHT = 1024
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that a graph may be further truncated if the graph's
+# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH
+# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default),
+# the graph is not depth-constrained.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, which results in a white background.
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE = NO
diff --git a/rasdoc/Doxyfile_internal b/rasdoc/Doxyfile_internal
new file mode 100644
index 0000000..400bf57
--- /dev/null
+++ b/rasdoc/Doxyfile_internal
@@ -0,0 +1,1284 @@
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+#--------------------- doxygen header -----------------------------------------------
+#
+# PURPOSE:
+# doxygen settings for generating HTML documentation, INTERNAL version.
+#
+# COMMENTS:
+# - written for doxygen 1.5.6
+# - IMPORTANT: paths are written for doxygen invocation IN THE ROOT DIRECTORY.
+#
+#-------------------------------------------------------------------------------------
+
+# Doxyfile 1.5.0
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = rasdaman/internal
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = documentation/internal/
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian,
+# Italian, Japanese, Japanese-en (Japanese with English messages), Korean,
+# Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian,
+# Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE = English
+
+# This tag can be used to specify the encoding used in the generated output.
+# The encoding is not always determined by the language that is chosen,
+# but also whether or not the output is meant for Windows or non-Windows users.
+# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES
+# forces the Windows encoding (this is the default for the Windows binary),
+# whereas setting the tag to NO uses a Unix-style encoding (the default for
+# all platforms other than Windows).
+
+#USE_WINDOWS_ENCODING = NO
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like the Qt-style comments (thus requiring an
+# explicit @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member
+# documentation.
+
+DETAILS_AT_TOP = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for Java.
+# For instance, namespaces will be presented as packages, qualified scopes
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to
+# include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = YES
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES = NO
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from the
+# version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = .
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py
+
+FILE_PATTERNS = *.hh
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE = CVS test SAVE Save
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output. If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default)
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default)
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code. Otherwise they will link to the documentstion.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = c++
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader. This is useful
+# if you want to understand what is going on. On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = NO
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will
+# generate a call dependency graph for every global function or class method.
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then doxygen will
+# generate a caller dependency graph for every global function or class method.
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+#MAX_DOT_GRAPH_WIDTH = 1024
+
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+#MAX_DOT_GRAPH_HEIGHT = 1024
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that a graph may be further truncated if the graph's
+# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH
+# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default),
+# the graph is not depth-constrained.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, which results in a white background.
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE = NO
diff --git a/rasdoc/Doxyfile_relational b/rasdoc/Doxyfile_relational
new file mode 100644
index 0000000..4510695
--- /dev/null
+++ b/rasdoc/Doxyfile_relational
@@ -0,0 +1,1284 @@
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+#
+# PURPOSE:
+# doxygen settings for generating HTML documentation, RELATIONAL ADAPTOR version.
+#
+#
+# COMMENTS:
+# - written for doxygen 1.5.6
+# - IMPORTANT: paths are written for doxygen invocation IN THE ROOT DIRECTORY.
+#
+#-------------------------------------------------------------------------------------
+
+# Doxyfile 1.5.0
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = rasdaman/relational
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = documentation/internal/
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian,
+# Italian, Japanese, Japanese-en (Japanese with English messages), Korean,
+# Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian,
+# Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE = English
+
+# This tag can be used to specify the encoding used in the generated output.
+# The encoding is not always determined by the language that is chosen,
+# but also whether or not the output is meant for Windows or non-Windows users.
+# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES
+# forces the Windows encoding (this is the default for the Windows binary),
+# whereas setting the tag to NO uses a Unix-style encoding (the default for
+# all platforms other than Windows).
+
+#USE_WINDOWS_ENCODING = NO
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like the Qt-style comments (thus requiring an
+# explicit @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member
+# documentation.
+
+DETAILS_AT_TOP = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for Java.
+# For instance, namespaces will be presented as packages, qualified scopes
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to
+# include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = YES
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES = NO
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from the
+# version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = reladminif/ relblobif/ relcatalogif/ relindexif/ relmddif/ relstorageif/
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py
+
+FILE_PATTERNS = *.hh
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE = CVS test SAVE Save
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output. If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default)
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default)
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code. Otherwise they will link to the documentstion.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = relational/
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader. This is useful
+# if you want to understand what is going on. On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = NO
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will
+# generate a call dependency graph for every global function or class method.
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then doxygen will
+# generate a caller dependency graph for every global function or class method.
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+#MAX_DOT_GRAPH_WIDTH = 1024
+
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+#MAX_DOT_GRAPH_HEIGHT = 1024
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that a graph may be further truncated if the graph's
+# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH
+# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default),
+# the graph is not depth-constrained.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, which results in a white background.
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE = NO
diff --git a/raslib/Makefile.am b/raslib/Makefile.am
new file mode 100644
index 0000000..6760b08
--- /dev/null
+++ b/raslib/Makefile.am
@@ -0,0 +1,54 @@
+# -*-Makefile-*- (for Emacs)
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+#
+# MAKEFILE FOR:
+# module raslib
+#
+# COMMENTS:
+#
+##################################################################
+
+AM_CXXFLAGS=@CLIENTCXXFLAGS@
+AM_LDFLAGS=@CLIENTLDFLAGS@
+
+noinst_LIBRARIES=libraslib.a
+libraslib_a_SOURCES= sinterval.hh dlist.hh point.hh minterval.hh error.hh \
+ rmdebug.hh rminit.hh metaobject.hh type.hh marraytype.hh \
+ basetype.hh primitivetype.hh sintervaltype.hh \
+ collectiontype.hh property.hh attribute.hh mintervaltype.hh \
+ pointtype.hh oidtype.hh structuretype.hh itertype.hh \
+ oid.hh scalar.hh primitive.hh structure.hh miter.hh mddtypes.hh \
+ miterd.hh mitera.hh memblockvec.hh parseparams.hh storageman.hh \
+ endian.hh flatbasetype.hh complex.hh complextype.hh shhopt.h \
+ sinterval.cc dlist.cc point.cc minterval.cc error.cc \
+ rmdebug.cc rminit.cc metaobject.cc type.cc marraytype.cc \
+ basetype.cc primitivetype.cc sintervaltype.cc \
+ collectiontype.cc property.cc attribute.cc mintervaltype.cc \
+ pointtype.cc oidtype.cc structuretype.cc itertype.cc \
+ oid.cc scalar.cc primitive.cc structure.cc miter.cc mddtypes.cc \
+ miterd.cc mitera.cc memblockvec.cc parseparams.cc storageman.cc \
+ endian.cc flatbasetype.cc complex.cc complextype.cc shhopt.c \
+ complex.icc complextype.icc error.icc minterval.icc miterd.icc miterf.icc \
+ miter.icc oid.icc point.icc rmdebug.icc sinterval.icc \
+ rmdebug.hh rm.hh odmgtypes.hh miterf.hh template_inst.hh
+
diff --git a/raslib/attribute.cc b/raslib/attribute.cc
new file mode 100644
index 0000000..6456810
--- /dev/null
+++ b/raslib/attribute.cc
@@ -0,0 +1,257 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+static const char rcsid[] = "@(#) raslib, r_Attribute: $Header: /home/rasdev/CVS-repository/rasdaman/raslib/attribute.cc,v 1.11 2003/12/27 23:01:21 rasdev Exp $";
+
+#include "raslib/attribute.hh"
+#include "raslib/basetype.hh"
+#include "raslib/structuretype.hh"
+#include "raslib/rminit.hh"
+#include "raslib/error.hh"
+
+r_Attribute::r_Attribute()
+ : r_Property(),
+ localOffset(0),
+ globalOffset(0)
+ {
+ }
+
+r_Attribute::r_Attribute(const char* newTypeName, const r_Base_Type& newType)
+ : r_Property(newTypeName, newType),
+ localOffset(0),
+ globalOffset(0)
+ {
+ }
+
+r_Attribute::r_Attribute(const r_Attribute& oldObj)
+ : r_Property(oldObj) ,
+ localOffset(oldObj.localOffset),
+ globalOffset(oldObj.globalOffset)
+ {
+ }
+
+const r_Attribute&
+r_Attribute::operator=(const r_Attribute& oldObj)
+ {
+ // Gracefully handle self assignment
+ if (this != &oldObj)
+ {
+ r_Property::operator=(oldObj) ;
+ localOffset = oldObj.localOffset;
+ globalOffset = oldObj.globalOffset;
+ }
+
+ return *this;
+ }
+
+r_Attribute::~r_Attribute()
+ {
+ }
+
+r_Bytes
+r_Attribute::offset() const
+ {
+ return localOffset;
+ }
+
+void
+r_Attribute::set_offset(r_Bytes newOffset)
+ {
+ localOffset = newOffset;
+ }
+
+r_Bytes
+r_Attribute::global_offset() const
+ {
+ return globalOffset;
+ }
+
+void
+r_Attribute::set_global_offset(r_Bytes newOffset)
+ {
+ globalOffset = newOffset;
+ }
+
+void
+r_Attribute::print_status(std::ostream& s) const
+ {
+ type_of().print_status(s);
+ s << " " << name() << std::flush;
+ }
+
+
+
+r_Attribute
+r_Attribute::operator[](unsigned int number) const throw(r_Error)
+ {
+ if (type_of().type_id() != r_Type::STRUCTURETYPE)
+ {
+ RMInit::logOut << "r_Attribute::operator[](" << number << ") not a struct type" << endl;
+ throw r_Error(r_Error::r_Error_TypeInvalid) ;
+ }
+
+ const r_Structure_Type& structValue = (const r_Structure_Type&)type_of();
+
+ return structValue[number];
+ }
+
+
+
+r_Boolean
+r_Attribute::get_boolean(const char* cell) const throw(r_Error)
+ {
+ if (type_of().type_id() != r_Type::BOOL)
+ {
+ RMInit::logOut << "r_Attribute::get_boolean(data) not a boolean" << endl;
+ r_Error err(r_Error::r_Error_TypeInvalid) ;
+ throw(err) ;
+ }
+
+ return *((r_Boolean*) (cell+globalOffset) ) ;
+ }
+
+
+
+r_Char
+r_Attribute::get_char(const char* cell) const throw(r_Error)
+ {
+ if (type_of() .type_id() != r_Type::CHAR)
+ {
+ RMInit::logOut << "r_Attribute::get_char(data) not a char" << endl;
+ r_Error err(r_Error::r_Error_TypeInvalid) ;
+ throw(err) ;
+ }
+
+ return *((r_Char*) (cell+globalOffset) ) ;
+ }
+
+
+
+r_Octet
+r_Attribute::get_octet(const char* cell) const throw(r_Error)
+ {
+ if (type_of() .type_id() != r_Type::OCTET)
+ {
+ RMInit::logOut << "r_Attribute::get_octet(data) not a octet" << endl;
+ r_Error err(r_Error::r_Error_TypeInvalid) ;
+ throw(err) ;
+ }
+
+ return *((r_Octet*) (cell+globalOffset) ) ;
+ }
+
+
+
+r_Short
+r_Attribute::get_short(const char* cell) const throw(r_Error)
+ {
+ if (type_of() .type_id() != r_Type::SHORT)
+ {
+ RMInit::logOut << "r_Attribute::get_short(data) not a short" << endl;
+ r_Error err(r_Error::r_Error_TypeInvalid) ;
+ throw(err) ;
+ }
+
+ return *((r_Short*) (cell+globalOffset) ) ;
+ }
+
+
+
+r_UShort
+r_Attribute::get_ushort(const char* cell) const throw(r_Error)
+ {
+ if (type_of() .type_id() != r_Type::USHORT)
+ {
+ RMInit::logOut << "r_Attribute::get_ushort(data) not a ushort" << endl;
+ r_Error err(r_Error::r_Error_TypeInvalid) ;
+ throw(err) ;
+ }
+
+ return *((r_UShort*) (cell+globalOffset) ) ;
+ }
+
+
+
+r_Long
+r_Attribute::get_long(const char* cell) const throw(r_Error)
+ {
+ if (type_of() .type_id() != r_Type::LONG)
+ {
+ RMInit::logOut << "r_Attribute::get_long(data) not a long" << endl;
+ r_Error err(r_Error::r_Error_TypeInvalid) ;
+ throw(err) ;
+ }
+
+ return *((r_Long*) (cell+globalOffset) ) ;
+ }
+
+
+
+r_ULong
+r_Attribute::get_ulong(const char* cell) const throw(r_Error)
+ {
+ if (type_of() .type_id() != r_Type::ULONG)
+ {
+ RMInit::logOut << "r_Attribute::get_ulong(data) not a ulong" << endl;
+ r_Error err(r_Error::r_Error_TypeInvalid) ;
+ throw(err) ;
+ }
+
+ return *((r_ULong*) (cell+globalOffset) ) ;
+ }
+
+
+
+r_Float
+r_Attribute::get_float(const char* cell) const throw(r_Error)
+ {
+ if (type_of() .type_id() != r_Type::FLOAT)
+ {
+ RMInit::logOut << "r_Attribute::get_float(data) not a float" << endl;
+ r_Error err(r_Error::r_Error_TypeInvalid) ;
+ throw(err) ;
+ }
+
+ return *((r_Float*) (cell+globalOffset) ) ;
+ }
+
+
+
+r_Double
+r_Attribute::get_double(const char* cell) const throw(r_Error)
+ {
+ if (type_of() .type_id() != r_Type::DOUBLE)
+ {
+ RMInit::logOut << "r_Attribute::get_double(data) not a double" << endl;
+ r_Error err(r_Error::r_Error_TypeInvalid) ;
+ throw(err) ;
+ }
+
+ return *((r_Double*) (cell+globalOffset) ) ;
+ }
+
+std::ostream &operator<<( std::ostream &str, const r_Attribute &type )
+{
+ type.print_status(str);
+ return str;
+}
diff --git a/raslib/attribute.hh b/raslib/attribute.hh
new file mode 100644
index 0000000..1bfed1c
--- /dev/null
+++ b/raslib/attribute.hh
@@ -0,0 +1,134 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: attribute.hh
+ *
+ * MODULE: raslib
+ * CLASS: r_Attribute
+ *
+ * COMMENTS:
+ * None
+*/
+
+#ifndef _D_ATTRIBUTE_
+#define _D_ATTRIBUTE_
+
+#include "raslib/property.hh"
+#include "raslib/odmgtypes.hh"
+#include "raslib/mddtypes.hh"
+
+class r_Base_Type;
+class r_Type_Id;
+class r_Error;
+
+
+//@ManMemo: Module: {\bf raslib}
+
+/*@Doc:
+ This class represents attributes of structs in the ODMG
+ conformant representation of the RasDaMan type system.
+*/
+
+
+class r_Attribute : public r_Property
+ {
+ public:
+ /// default constructor.
+ /// initialise important attributes to NULL
+ r_Attribute();
+
+ /// constructor getting name and type of attribute.
+ r_Attribute(const char* newTypeName, const r_Base_Type& newType);
+
+ /// copy constructor.
+ r_Attribute(const r_Attribute& oldObj);
+
+ /// assignment operator.
+ const r_Attribute& operator=(const r_Attribute& oldObj);
+
+ /// destructor.
+ virtual ~r_Attribute();
+
+ /// retrieve (local) offset
+ r_Bytes offset() const;
+
+ /// set (local) offset
+ void set_offset(r_Bytes newOffset);
+
+ /// retrieve global offset
+ r_Bytes global_offset() const;
+
+ /// set global offset
+ void set_global_offset(r_Bytes newOffset);
+
+ /// writes state of object to specified stream
+ virtual void print_status(std::ostream& s = std::cout) const;
+
+ /// subscript operator to access attributes of a structured attribute
+ /// throws error when type is not a struct type
+ r_Attribute operator[](unsigned int number) const throw(r_Error);
+
+ //@Man: Type-safe value access methods. In case of type mismatch, an exception is raised.
+ //@{
+ ///
+ r_Boolean get_boolean(const char* cell) const throw(r_Error);
+
+ ///
+ r_Char get_char(const char* cell) const throw(r_Error);
+
+ ///
+ r_Octet get_octet(const char* cell) const throw(r_Error);
+
+ ///
+ r_Short get_short(const char* cell) const throw(r_Error);
+
+ ///
+ r_UShort get_ushort(const char* cell) const throw(r_Error);
+
+ ///
+ r_Long get_long(const char* cell) const throw(r_Error);
+
+ ///
+ r_ULong get_ulong(const char* cell) const throw(r_Error);
+
+ ///
+ r_Float get_float(const char* cell) const throw(r_Error);
+
+ ///
+ r_Double get_double(const char* cell) const throw(r_Error);
+
+ ///
+ //@}
+
+ protected:
+ /// local offset
+ r_Bytes localOffset;
+
+ /// global offset
+ r_Bytes globalOffset;
+ };
+
+//@Doc: write the status of a attribute to a stream
+extern std::ostream &operator<<( std::ostream &str, const r_Attribute &type );
+
+#endif
diff --git a/raslib/basetype.cc b/raslib/basetype.cc
new file mode 100644
index 0000000..639073f
--- /dev/null
+++ b/raslib/basetype.cc
@@ -0,0 +1,77 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+static const char rcsid[] = "@(#)raslib, r_Type: $Header: /home/rasdev/CVS-repository/rasdaman/raslib/basetype.cc,v 1.4 2003/12/27 23:01:21 rasdev Exp $";
+
+#include <ctype.h> // for isalpha()
+#include <string.h> // for strncmp()
+
+#include "raslib/basetype.hh"
+#include "raslib/attribute.hh"
+
+r_Base_Type::r_Base_Type()
+ : r_Type(),
+ typeSize(0)
+ {
+ }
+
+r_Base_Type::r_Base_Type(const char* newTypeName, r_Bytes newTypeSize)
+ : r_Type(newTypeName),
+ typeSize(newTypeSize)
+ {
+ }
+
+r_Base_Type::r_Base_Type(const r_Base_Type& oldObj)
+ : r_Type(oldObj),
+ typeSize(oldObj.typeSize)
+ {
+ }
+
+const r_Base_Type&
+r_Base_Type::operator=(const r_Base_Type& oldObj)
+ {
+ // Gracefully handle self assignment
+ if (this == &oldObj) return *this;
+
+ r_Type::operator=(oldObj);
+ typeSize = oldObj.typeSize;
+
+ return *this;
+ }
+
+r_Base_Type::~r_Base_Type()
+ {
+ }
+
+bool
+r_Base_Type::isBaseType() const
+ {
+ return true;
+ }
+
+r_Bytes
+r_Base_Type::size() const
+ {
+ return typeSize;
+ }
+
diff --git a/raslib/basetype.hh b/raslib/basetype.hh
new file mode 100644
index 0000000..45e7446
--- /dev/null
+++ b/raslib/basetype.hh
@@ -0,0 +1,80 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: basetype.hh
+ *
+ * MODULE: raslib
+ * CLASS: r_Base_Type
+ *
+ * COMMENTS:
+ * None
+*/
+
+#ifndef _D_BASETYPE_
+#define _D_BASETYPE_
+
+#include "raslib/type.hh"
+
+
+
+//@ManMemo: Module: {\bf raslib}
+
+/**
+ This class is the superclass of the types r_Structure_Type and r_Primitive_Type in the
+ representation of the RasDaMan type system.
+*/
+
+class r_Base_Type : public r_Type
+ {
+ public:
+ /// default constructor.
+ r_Base_Type();
+
+ /// constructor getting name of basetype.
+ r_Base_Type(const char* newTypeName, r_Bytes newSize);
+
+ /// copy constructor
+ r_Base_Type(const r_Base_Type& oldObj);
+
+ /// assignment operator.
+ const r_Base_Type& operator=(const r_Base_Type& oldObj);
+
+ /// destructor.
+ virtual ~r_Base_Type();
+
+ /// check, if type is a base type (primitive type or structure type).
+ virtual bool isBaseType() const;
+
+ /// retrieve size of the type.
+ r_Bytes size() const;
+
+ /// prints value of a primitive type or values of a structured type
+ virtual void print_value(const char* storage, std::ostream& s = std::cout) const = 0;
+
+ protected:
+ /// storing size of type in bytes
+ r_Bytes typeSize;
+
+ };
+
+#endif
diff --git a/raslib/collectiontype.cc b/raslib/collectiontype.cc
new file mode 100644
index 0000000..035e201
--- /dev/null
+++ b/raslib/collectiontype.cc
@@ -0,0 +1,140 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+static const char rcsid[] = "@(#)raslib, r_Collection_Type: $Header: /home/rasdev/CVS-repository/rasdaman/raslib/collectiontype.cc,v 1.6 2003/12/27 23:01:21 rasdev Exp $";
+
+#include "raslib/collectiontype.hh"
+#include "raslib/rminit.hh"
+#include "raslib/error.hh"
+
+
+r_Collection_Type::r_Collection_Type()
+ : r_Type(),
+ elementType(NULL)
+ {
+ }
+
+r_Collection_Type::r_Collection_Type(r_Type& newElementType)
+ : r_Type(),
+ elementType(newElementType.clone())
+ {
+ }
+
+r_Collection_Type::r_Collection_Type(const r_Collection_Type& oldObj) throw (r_Error)
+ : r_Type(oldObj),
+ elementType(NULL)
+ {
+ if (oldObj.elementType)
+ elementType = oldObj.elementType->clone();
+ else {
+ RMInit::logOut << "r_Collection_Type::r_Collection_Type( oldObj ) the element type is NULL." << endl;
+ throw r_Error(COLLECTIONTYPEHASNOELEMENTTYPE);
+ }
+ }
+
+bool
+r_Collection_Type::isCollectionType() const
+ {
+ return true;
+ }
+
+const r_Collection_Type&
+r_Collection_Type::operator=(const r_Collection_Type& oldObj) throw (r_Error)
+ {
+ // Gracefully handle self assignment
+ if (this == &oldObj)
+ return *this;
+
+ r_Type::operator=(oldObj);
+ delete elementType;
+ elementType = NULL;
+ if (oldObj.elementType)
+ elementType = oldObj.elementType->clone();
+ else {
+ RMInit::logOut << "r_Collection_Type::operator=( oldObj ) the element type is NULL." << endl;
+ throw r_Error(COLLECTIONTYPEHASNOELEMENTTYPE);
+ }
+ return *this;
+ }
+
+const r_Type&
+r_Collection_Type::element_type() const throw (r_Error)
+ {
+ if (elementType == NULL)
+ {
+ RMInit::logOut << "r_Collection_Type::element_type() the element type is NULL." << endl;
+ throw r_Error(COLLECTIONTYPEHASNOELEMENTTYPE);
+ }
+ return *elementType;
+ }
+
+r_Type*
+r_Collection_Type::clone() const
+ {
+ return new r_Collection_Type(*this);
+ }
+
+r_Collection_Type::r_Kind
+r_Collection_Type::kind() const
+ {
+ return SET;
+ }
+
+r_Type::r_Type_Id
+r_Collection_Type::type_id() const
+ {
+ return COLLECTIONTYPE;
+ }
+
+void
+r_Collection_Type::convertToLittleEndian(char* cells, r_Area noCells) const
+ {
+ }
+
+void
+r_Collection_Type::convertToBigEndian(char* cells, r_Area noCells) const
+ {
+ }
+
+void
+r_Collection_Type::print_status(std::ostream& s) const
+ {
+ s << "set< ";
+ elementType->print_status(s);
+ s << " >";
+ }
+
+
+
+r_Collection_Type::~r_Collection_Type()
+ {
+ if (elementType)
+ delete elementType;
+ elementType = NULL;
+ }
+
+std::ostream &operator<<( std::ostream &str, const r_Collection_Type &type )
+{
+ type.print_status(str);
+ return str;
+}
diff --git a/raslib/collectiontype.hh b/raslib/collectiontype.hh
new file mode 100644
index 0000000..9e33106
--- /dev/null
+++ b/raslib/collectiontype.hh
@@ -0,0 +1,108 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: collectiontype.hh
+ *
+ * MODULE: raslib
+ * CLASS: r_Collection_Type
+ *
+ * COMMENTS:
+ * None
+*/
+
+#ifndef _D_COLLECTION_TYPE_
+#define _D_COLLECTION_TYPE_
+
+#include "raslib/type.hh"
+class r_Error;
+
+
+//@ManMemo: Module: {\bf raslib}
+
+/*@Doc:
+ This class represents the collection type in the ODMG conformant
+ representation of the RasDaMan type system.
+*/
+
+
+class r_Collection_Type : public r_Type
+ {
+ public:
+ /// Set type in the only one needed right now.
+ typedef enum { SET } r_Kind;
+
+ /// copy constructor
+ /// the exception is only raised when the element type of the copied type is NULL.
+ /// (this can not happen)
+ r_Collection_Type(const r_Collection_Type&) throw (r_Error);
+
+ /// constructor getting element type
+ r_Collection_Type(r_Type& newType);
+
+ /// returns identifier SET of enumeration r_Kind
+ r_Kind kind() const;
+
+ /// assignment operator
+ /// the exception is only raised when the element type of the copied type is NULL.
+ /// (this can not happen)
+ const r_Collection_Type& operator=(const r_Collection_Type& oldObj) throw (r_Error);
+
+ /// get element type
+ /// the exception is only raised when the element type of the copied type is NULL.
+ /// (this can not happen)
+ const r_Type& element_type() const throw (r_Error);
+
+ /// clone operation
+ virtual r_Type* clone() const;
+
+ /// retrieve id of the type.
+ virtual r_Type::r_Type_Id type_id() const;
+
+ virtual bool isCollectionType() const;
+
+ /// converts array of cells from NT byte order to Unix byte order.
+ virtual void convertToLittleEndian(char* cells, r_Area noCells) const;
+
+ /// converts array of cells from Unix byte order to NT byte order.
+ virtual void convertToBigEndian(char* cells, r_Area noCells) const;
+
+ /// writes state of object to specified stream
+ virtual void print_status(std::ostream& s = std::cout) const;
+
+ /// destructor
+ ~r_Collection_Type();
+
+ protected:
+ /// default constructor
+ /// no one should use that
+ r_Collection_Type();
+
+ /// element type
+ r_Type* elementType;
+ };
+
+//@Doc: write the status of a collection type to a stream
+extern std::ostream &operator<<( std::ostream &str, const r_Collection_Type &type );
+
+#endif
+
diff --git a/raslib/complex.cc b/raslib/complex.cc
new file mode 100644
index 0000000..9b8ed2e
--- /dev/null
+++ b/raslib/complex.cc
@@ -0,0 +1,110 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#include "raslib/complex.hh"
+#include "raslib/rminit.hh"
+#include "raslib/error.hh"
+#include "raslib/complextype.hh"
+
+r_Complex::r_Complex(const char* newBuffer, const r_Complex_Type* newType)
+ : r_Primitive(newBuffer, newType)
+ {
+ }
+
+r_Complex::r_Complex(const r_Complex& obj)
+ : r_Primitive(obj)
+ {
+ }
+
+r_Complex::~r_Complex()
+ {
+ }
+
+r_Scalar*
+r_Complex::clone() const
+ {
+ return new r_Complex(*this);
+ }
+
+const r_Complex&
+r_Complex::operator=(const r_Complex& obj)
+ {
+ r_Primitive::operator=(obj);
+ return *this;
+ }
+
+r_Double
+r_Complex::get_re() const throw (r_Error)
+ {
+ if (!get_buffer() || !valueType || !valueType->isComplexType())
+ {
+ RMInit::logOut << "r_Complex::get_re() value type is not a complex, not initialised or not buffered" << endl;
+ r_Error err(r_Error::r_Error_TypeInvalid);
+ throw err;
+ }
+ return ((r_Complex_Type *)valueType)->get_re(get_buffer());
+ }
+
+r_Double
+r_Complex::get_im() const throw (r_Error)
+ {
+ if(!get_buffer() || !valueType || !valueType->isComplexType())
+ {
+ RMInit::logOut << "r_Complex::get_im() value type is not a complex, not initialised or not buffered" << endl;
+ r_Error err(r_Error::r_Error_TypeInvalid);
+ throw err;
+ }
+ return ((r_Complex_Type *)valueType)->get_im(get_buffer());
+ }
+
+void
+r_Complex::set_re(r_Double re) throw (r_Error)
+ {
+ if (!valueType || !valueType->isComplexType())
+ {
+ RMInit::logOut << "r_Complex::set_re(" << re << ") value type is not a complex or not initialised" << endl;
+ r_Error err(r_Error::r_Error_TypeInvalid);
+ throw err;
+ }
+ ((r_Complex_Type *)valueType)->set_re((char*)get_buffer(), re);
+ }
+
+void
+r_Complex::set_im(r_Double im) throw (r_Error)
+ {
+ if(!valueType || !valueType->isComplexType())
+ {
+ RMInit::logOut << "r_Complex::get_im() value type is not a complex or not initialised" << endl;
+ r_Error err(r_Error::r_Error_TypeInvalid);
+ throw err;
+ }
+ ((r_Complex_Type *)valueType)->set_im((char*)get_buffer(), im);
+ }
+
+
+bool
+r_Complex::isComplex() const
+ {
+ return true;
+ }
+
diff --git a/raslib/complex.hh b/raslib/complex.hh
new file mode 100644
index 0000000..c67da82
--- /dev/null
+++ b/raslib/complex.hh
@@ -0,0 +1,87 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: complex.hh
+ *
+ * MODULE: raslib
+ * CLASS: r_Complex
+ *
+ * COMMENTS:
+ * The class represents a complex type value.
+ *
+*/
+
+#ifndef _D_COMPLEX_
+#define _D_COMPLEX_
+
+#include <iostream>
+class r_Error;
+class r_Complex_Type;
+
+#include "raslib/odmgtypes.hh"
+#include "raslib/mddtypes.hh"
+#include "raslib/primitive.hh"
+
+
+//@ManMemo: Module: {\bf raslib}
+
+/*@Doc:
+
+ Class \Ref{r_Complex} represents a complex type value.
+
+*/
+
+
+class r_Complex: public r_Primitive
+ {
+ public:
+
+ explicit
+ /// constructs a scalar type value
+ r_Complex(const char* newBuffer, const r_Complex_Type* newType);
+
+ /// copy constructor
+ r_Complex(const r_Complex& obj);
+
+ /// destructor
+ ~r_Complex();
+
+ virtual bool isComplex() const;
+
+ /// clone operator
+ virtual r_Scalar* clone() const;
+
+ /// operator for assigning a primitive
+ virtual const r_Complex& operator =(const r_Complex&);
+
+ r_Double get_re() const throw(r_Error);
+ r_Double get_im() const throw(r_Error);
+
+ void set_re(r_Double) throw(r_Error);
+ void set_im(r_Double) throw(r_Error);
+
+ };
+
+
+#endif
+
diff --git a/raslib/complex.icc b/raslib/complex.icc
new file mode 100644
index 0000000..bab562e
--- /dev/null
+++ b/raslib/complex.icc
@@ -0,0 +1 @@
+//this is moved to complex.cc
diff --git a/raslib/complextype.cc b/raslib/complextype.cc
new file mode 100644
index 0000000..e2b59b3
--- /dev/null
+++ b/raslib/complextype.cc
@@ -0,0 +1,284 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#include <iomanip>
+#include <string>
+#include <cstring>
+
+#include "raslib/complextype.hh"
+#include "raslib/endian.hh"
+#include "raslib/rmdebug.hh"
+#include "raslib/error.hh"
+
+r_Complex_Type::r_Complex_Type()
+ : r_Primitive_Type(),
+ imOff(0)
+ {
+ }
+
+r_Complex_Type::r_Complex_Type(const char* newTypeName, const r_Type::r_Type_Id newTypeId)
+ : r_Primitive_Type(newTypeName, newTypeId)
+ {
+ imOff = 0;
+ switch (typeId)
+ {
+ case COMPLEXTYPE1:
+ imOff = sizeof(r_Float);
+ break;
+ case COMPLEXTYPE2:
+ imOff = sizeof(r_Double);
+ break;
+ default:
+ RMDBGONCE(3, RMDebug::module_raslib, "r_Complex_Type", "r_Complex_Type(...) bad typeId " << typeId);
+ break;
+ }
+ }
+
+r_Complex_Type::~r_Complex_Type()
+ {
+ }
+
+r_Complex_Type::r_Complex_Type(const r_Complex_Type& oldObj)
+ : r_Primitive_Type(oldObj),
+ imOff(oldObj.imOff)
+ {
+ }
+
+const r_Complex_Type&
+r_Complex_Type::operator=(const r_Complex_Type& oldObj)
+ {
+ if (this == &oldObj)
+ return *this;
+
+ r_Primitive_Type::operator =(oldObj);
+ imOff = oldObj.imOff;
+ return *this;
+ }
+
+r_Type*
+r_Complex_Type::clone() const
+ {
+ return new r_Complex_Type(*this);
+ }
+
+r_Double
+ r_Complex_Type::get_re(const char* cell) const throw(r_Error)
+ {
+ double res = 0;
+
+ if( (typeId != r_Type::COMPLEXTYPE1) &&
+ (typeId != r_Type::COMPLEXTYPE2) )
+ {
+ RMInit::logOut << "r_Complex_Type::get_re(cell) type not a complex1 or complex2" << endl;
+ r_Error err( r_Error::r_Error_TypeInvalid );
+ throw( err );
+ }
+
+
+ switch (typeId)
+ {
+ case COMPLEXTYPE1:
+ res = *(r_Float*)cell;
+ break;
+ case COMPLEXTYPE2:
+ res = *(r_Double *)cell;
+ break;
+ default:
+ RMDBGONCE(3, RMDebug::module_raslib, "r_Complex_Type", "get_re(...) bad typeId " << typeId);
+ break;
+ }
+ return res;
+ }
+
+r_Double
+r_Complex_Type::get_im(const char* cell) const throw(r_Error)
+ {
+ double res = 0;
+
+ if( (typeId != r_Type::COMPLEXTYPE1) &&
+ (typeId != r_Type::COMPLEXTYPE2) )
+ {
+ RMInit::logOut << "r_Complex_Type::get_im(cell) type not a complex1 or complex2" << endl;
+ r_Error err( r_Error::r_Error_TypeInvalid );
+ throw( err );
+ }
+
+ switch (typeId)
+ {
+ case COMPLEXTYPE1:
+ res = *(r_Float*)(cell + imOff);
+ break;
+ case COMPLEXTYPE2:
+ res = *(r_Double*)(cell + imOff);
+ break;
+ default:
+ RMDBGONCE(3, RMDebug::module_raslib, "r_Complex_Type", "get_im(...) bad typeId " << typeId);
+ break;
+ }
+ return res;
+ }
+
+
+
+
+void
+r_Complex_Type::set_re(char* cell, r_Double re) throw(r_Error)
+ {
+ r_Float ref=0.;
+ if( (typeId != r_Type::COMPLEXTYPE1) &&
+ (typeId != r_Type::COMPLEXTYPE2) )
+ {
+ RMInit::logOut << "r_Complex_Type::set_re(cell, re) type not a complex1 or complex2" << endl;
+ r_Error err( r_Error::r_Error_TypeInvalid );
+ throw( err );
+ }
+
+ switch (typeId)
+ {
+ case COMPLEXTYPE1:
+ ref=re;
+ memmove(cell, &ref, imOff);
+ break;
+ case COMPLEXTYPE2:
+ memmove(cell, &re, imOff);
+ break;
+ default:
+ RMDBGONCE(3, RMDebug::module_raslib, "r_Complex_Type", "set_re(...) bad typeId " << typeId);
+ break;
+ }
+ }
+
+void
+r_Complex_Type::set_im(char* cell, r_Double im) throw(r_Error)
+ {
+ r_Float imf= 0.;
+
+ if( (typeId != r_Type::COMPLEXTYPE1) &&
+ (typeId != r_Type::COMPLEXTYPE2) )
+ {
+ RMInit::logOut << "r_Complex_Type::set_im(cell, im) type not a complex1 or complex2" << endl;
+ r_Error err( r_Error::r_Error_TypeInvalid );
+ throw( err );
+ }
+
+ switch (typeId)
+ {
+ case COMPLEXTYPE1:
+ imf=im;
+ memmove((cell + imOff), &imf, imOff);
+ break;
+ case COMPLEXTYPE2:
+ memmove((cell + imOff), &im, imOff);
+ break;
+ default:
+ RMDBGONCE(3, RMDebug::module_raslib, "r_Complex_Type", "set_im(...) bad typeId " << typeId);
+ break;
+ }
+ }
+
+
+void
+r_Complex_Type::print_status(std::ostream& s) const
+ {
+ switch (typeId)
+ {
+ case COMPLEXTYPE1:
+ s << "complex(float, float)";
+ break;
+ case COMPLEXTYPE2:
+ s << "complex(double, double)";
+ break;
+ default:
+ RMDBGONCE(3, RMDebug::module_raslib, "r_Complex_Type", "print_status(...) bad typeId " << typeId);
+ break;
+ }
+ }
+
+void
+r_Complex_Type::print_value(const char* storage, std::ostream& s) const
+ {
+ s << "(" << get_re(storage) << ", " << get_im(storage) << ")";
+ }
+
+void
+r_Complex_Type::convertToLittleEndian(char* cells, r_Area noCells) const
+ {
+ switch (typeId)
+ {
+ case COMPLEXTYPE1:
+ for (r_Area i = 0; i < noCells; ++i)
+ {
+ *(r_Float*)(cells + i * typeSize) = r_Endian::swap((r_Float)get_re(cells + i * typeSize));
+ *(r_Float*)(cells + i * typeSize + imOff) = r_Endian::swap((r_Float)get_im(cells + i * typeSize));
+ }
+ break;
+
+ case COMPLEXTYPE2:
+ for (r_Area i = 0; i < noCells; ++i)
+ {
+ *(r_Double*)(cells + i * typeSize) = r_Endian::swap(get_re(cells + i * typeSize));
+ *(r_Double*)(cells + i * typeSize + imOff) = r_Endian::swap(get_im(cells + i * typeSize));
+ }
+ break;
+ default:
+ RMDBGONCE(3, RMDebug::module_raslib, "r_Complex_Type", "convertToLittleEndian(...) bad typeId " << typeId);
+ break;
+ }
+ }
+
+void
+r_Complex_Type::convertToBigEndian(char* cells, r_Area noCells) const
+ {
+ switch (typeId)
+ {
+ case COMPLEXTYPE1:
+ for (r_Area i = 0; i < noCells; ++i)
+ {
+ *(r_Float*)(cells + i * typeSize) = r_Endian::swap((r_Float)get_re(cells + i * typeSize));
+ *(r_Float*)(cells + i * typeSize + imOff) = r_Endian::swap((r_Float)get_im(cells + i * typeSize));
+ }
+ break;
+ case COMPLEXTYPE2:
+ for (r_Area i = 0; i < noCells; ++i)
+ {
+ *(r_Double*)(cells + i * typeSize) = r_Endian::swap(get_re(cells + i * typeSize));
+ *(r_Double*)(cells + i * typeSize + imOff) = r_Endian::swap(get_im(cells + i * typeSize));
+ }
+ break;
+ default:
+ RMDBGONCE(3, RMDebug::module_raslib, "r_Complex_Type", "convertToBigEndian(...) bad typeId " << typeId);
+ break;
+ }
+ }
+
+bool
+r_Complex_Type::isComplexType() const
+ {
+ return true;
+ }
+
+std::ostream &operator<<( std::ostream &str, const r_Complex_Type &type )
+{
+ type.print_status(str);
+ return str;
+}
diff --git a/raslib/complextype.hh b/raslib/complextype.hh
new file mode 100644
index 0000000..a496384
--- /dev/null
+++ b/raslib/complextype.hh
@@ -0,0 +1,71 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: complextype.hh
+ *
+ * MODULE: raslib
+ * CLASS: r_Complex_Type
+ *
+ * COMMENTS:
+ * None
+*/
+
+#ifndef _D_COMPLEXTYPE_TYPE_
+#define _D_COMPLEXTYPE_TYPE_
+
+#include "raslib/primitivetype.hh"
+#include "raslib/odmgtypes.hh"
+#include "raslib/mddtypes.hh"
+
+class r_Complex_Type : public r_Primitive_Type
+ {
+ public:
+ r_Complex_Type();
+ r_Complex_Type(const char* newTypeName, const r_Type::r_Type_Id newTypeId);
+ r_Complex_Type(const r_Complex_Type& oldObj);
+ const r_Complex_Type& operator=(const r_Complex_Type& oldObj);
+ virtual ~r_Complex_Type();
+
+ virtual r_Type* clone() const;
+ virtual void print_status(std::ostream& s = std::cout) const;
+ virtual void print_value(const char* storage, std::ostream& s = std::cout) const;
+
+ r_Double get_re(const char* cell) const throw(r_Error);
+ r_Double get_im(const char* cell) const throw(r_Error);
+
+ void set_re(char* cell, r_Double re) throw(r_Error);
+ void set_im(char* cell, r_Double im) throw(r_Error);
+
+
+ virtual void convertToLittleEndian(char* cells, r_Area noCells) const;
+ virtual void convertToBigEndian(char* cells, r_Area noCells) const;
+ virtual bool isComplexType() const;
+
+ private:
+ r_Bytes imOff;
+ };
+
+//@Doc: write the status of a complex type to a stream
+extern std::ostream &operator<<( std::ostream &str, const r_Complex_Type &type );
+
+#endif
diff --git a/raslib/complextype.icc b/raslib/complextype.icc
new file mode 100644
index 0000000..9bbb3dd
--- /dev/null
+++ b/raslib/complextype.icc
@@ -0,0 +1 @@
+//this is moved to complextype.cc
diff --git a/raslib/dlist.cc b/raslib/dlist.cc
new file mode 100644
index 0000000..9641580
--- /dev/null
+++ b/raslib/dlist.cc
@@ -0,0 +1,71 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#include <iostream>
+#include <vector>
+#include "raslib/dlist.hh"
+#include "raslib/minterval.hh"
+
+template <class T>
+std::ostream& operator<< (std::ostream& os, const std::vector<T>& list)
+{
+ os << "[ ";
+ for (typename std::vector<T>::const_iterator it = list.begin(); it != list.end(); it++)
+ os << (*it) << " ";
+ os << "]";
+ return os;
+}
+
+template <class T>
+std::ostream& operator<< (const std::vector<T>& list, std::ostream& os)
+{
+ os << "[ ";
+ for (typename std::vector<T>::const_iterator it = list.begin(); it != list.end(); it++)
+ os << (*it) << " ";
+ os << "]";
+ return os;
+}
+
+#if defined(SOLARIS) && ! defined(EARLY_TEMPLATE)
+//this is here to get around a template instantiation problem on sun
+template <>
+std::ostream& operator<< (std::ostream& os, const std::vector<r_Minterval>& list)
+{
+ os << "[ ";
+ for (typename std::vector<r_Minterval>::const_iterator it = list.begin(); it != list.end(); it++)
+ os << (*it) << " ";
+ os << "]";
+ return os;
+}
+
+template <>
+std::ostream& operator<< (const std::vector<r_Minterval>& list, std::ostream& os)
+{
+ os << "[ ";
+ for (typename std::vector<r_Minterval>::const_iterator it = list.begin(); it != list.end(); it++)
+ os << (*it) << " ";
+ os << "]";
+ return os;
+}
+
+#endif
diff --git a/raslib/dlist.hh b/raslib/dlist.hh
new file mode 100644
index 0000000..ea794e3
--- /dev/null
+++ b/raslib/dlist.hh
@@ -0,0 +1,42 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#ifndef _DLIST_H_
+#define _DLIST_H_
+#include <iostream>
+#include <vector>
+
+template <class T>
+std::ostream& operator<< (std::ostream& os, const std::vector<T>& list);
+
+template <class T>
+std::ostream& operator<< (const std::vector<T>& list, std::ostream& os);
+
+#ifdef EARLY_TEMPLATE
+#ifdef __EXECUTABLE__
+#include "raslib/dlist.cc"
+#endif
+#endif
+
+#endif
+
diff --git a/raslib/endian.cc b/raslib/endian.cc
new file mode 100644
index 0000000..45837a1
--- /dev/null
+++ b/raslib/endian.cc
@@ -0,0 +1,623 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: endian.cc
+ *
+ * MODULE: raslib
+ * CLASS: r_Endian
+ *
+ * COMMENTS:
+ * None
+*/
+
+#include <string.h>
+
+
+#include "raslib/endian.hh"
+#include "raslib/rmdebug.hh"
+#include "raslib/minterval.hh"
+#include "raslib/primitivetype.hh"
+#include "raslib/structuretype.hh"
+#include "raslib/miter.hh"
+
+
+
+
+/*
+ * Inline code used in several places in the r_Endian class
+ */
+
+static inline r_Octet eswap( r_Octet val )
+{
+ return val;
+}
+
+static inline void eswap( r_Octet val, void *dest )
+{
+ r_Char *d = (r_Char *)dest;
+ *d = val;
+}
+
+static inline r_Short eswap( r_Short val )
+{
+ return (r_Short)(((val & 0xff) << 8) | ((val >> 8) & 0xff));
+}
+
+static inline r_UShort eswap( r_UShort val )
+{
+ return (r_UShort)(((val & 0xff) << 8) | ((val >> 8) & 0xff));
+}
+
+static inline void eswap( r_Short val, void *dest )
+{
+ r_Short *d = (r_Short *)dest;
+ *d = eswap(val);
+}
+
+static inline void eswap( r_UShort val, void *dest )
+{
+ r_UShort *d = (r_UShort *)dest;
+ *d = eswap(val);
+}
+
+static inline r_Long eswap( r_Long val )
+{
+ return (r_Long)(((val & 0xff) << 24) | ((val & 0xff00) << 8) |
+ ((val >> 8) & 0xff00) | ((val >> 24) & 0xff));
+}
+
+static inline r_ULong eswap( r_ULong val )
+{
+ return (r_ULong)(((val & 0xff) << 24) | ((val & 0xff00) << 8) |
+ ((val >> 8) & 0xff00) | ((val >> 24) & 0xff));
+}
+
+static inline void eswap( r_Long val, void *dest )
+{
+ r_Long *d = (r_Long *)dest;
+ *d = eswap(val);
+}
+
+static inline void eswap( r_ULong val, void *dest )
+{
+ r_ULong *d = (r_ULong *)dest;
+ *d = eswap(val);
+}
+
+/*
+these types are not supported
+static inline long eswap( long val )
+{
+ return (long)(((val & 0xff) << 24) | ((val & 0xff00) << 8) |
+ ((val >> 8) & 0xff00) | ((val >> 24) & 0xff));
+}
+
+static inline r_ULong eswap( r_ULong val )
+{
+ return (r_ULong)(((val & 0xff) << 24) | ((val & 0xff00) << 8) |
+ ((val >> 8) & 0xff00) | ((val >> 24) & 0xff));
+}
+
+static inline void eswap( long val, void *dest )
+{
+ long *d = (long *)dest;
+ *d = eswap(val);
+}
+
+static inline void eswap( r_ULong val, void *dest )
+{
+ r_ULong *d = (r_ULong *)dest;
+ *d = eswap(val);
+}
+*/
+
+static inline r_Float eswap( r_Float val )
+{
+ r_Long *ptr = (r_Long*)&val;
+ r_Float result;
+
+ eswap(*ptr, &result);
+
+ return result;
+}
+
+static inline void eswap( r_Float val, void *dest )
+{
+ r_Long *ptr = (r_Long*)&val;
+
+ eswap(*ptr, dest);
+}
+
+
+#ifndef __GNUG__
+inline
+#endif
+static r_Double eswap( r_Double val )
+{
+ r_Long *ptr = (r_Long*)&val;
+ r_Double result;
+ eswap(ptr[0], ((r_Octet*)&result)+sizeof(r_Long));
+ eswap(ptr[1], (r_Octet*)&result);
+/*
+#ifndef DECALPHA
+ eswap(ptr[0], ((r_Octet*)&result)+sizeof(long));
+ eswap(ptr[1], (r_Octet*)&result);
+#else
+ eswap(*ptr, &result);
+#endif
+*/
+ return result;
+}
+
+#ifndef __GNUG__
+inline
+#endif
+static void eswap( r_Double val, void *dest )
+{
+ r_Long *ptr = (r_Long*)&val;
+ eswap(ptr[0], ((r_Octet*)dest)+sizeof(r_Long));
+ eswap(ptr[1], dest);
+/*
+#ifndef DECALPHA
+ eswap(ptr[0], ((r_Octet*)dest)+sizeof(long));
+ eswap(ptr[1], dest);
+#else
+ eswap(*ptr, dest);
+#endif
+*/
+}
+
+
+/*
+ * Template functions used throughout the code
+ */
+
+// template for special linear iteration
+template<class T>
+void swap_array_templ( r_Bytes size, T *dest, const T *src)
+{
+ const T *sptr = src;
+ T *dptr = dest;
+ r_Bytes ctr;
+
+ for (ctr = 0; ctr < size; ctr += sizeof(T), sptr++, dptr++)
+ eswap(*sptr, dptr);
+}
+
+
+// template for identical domains for src and dest
+template<class T>
+void swap_array_templ(r_Miter &iter, T *destBase, const T *srcBase)
+{
+ while (!iter.isDone())
+ {
+ const T *src = (const T*)iter.nextCell();
+ eswap(*src, destBase + (src - srcBase));
+ }
+}
+
+
+// template for generic iteration (src is just a dummy here)
+template<class T>
+void swap_array_templ(r_Miter &siter, r_Miter &diter, const T *srcBase)
+{
+ while (!siter.isDone())
+ {
+ const T *src = (const T*)siter.nextCell();
+ T *dest = (T*)diter.nextCell();
+ eswap(*src, dest);
+ }
+}
+
+// force the instantiations; we only need the templates r_Longernally anyway
+template void swap_array_templ(r_Bytes, r_Short *, const r_Short *);
+template void swap_array_templ(r_Bytes, r_UShort *, const r_UShort *);
+template void swap_array_templ(r_Bytes, r_Long *, const r_Long *);
+template void swap_array_templ(r_Bytes, r_ULong *, const r_ULong *);
+/*
+template void swap_array_templ(r_Bytes, long *, const long *);
+template void swap_array_templ(r_Bytes, r_ULong *, const r_ULong *);
+*/
+template void swap_array_templ(r_Bytes, r_Float *, const r_Float *);
+template void swap_array_templ(r_Bytes, r_Double *, const r_Double *);
+template void swap_array_templ(r_Miter &, r_Octet *, const r_Octet *);
+template void swap_array_templ(r_Miter &, r_Short *, const r_Short *);
+template void swap_array_templ(r_Miter &, r_Long *, const r_Long *);
+template void swap_array_templ(r_Miter &, r_Float *, const r_Float *);
+template void swap_array_templ(r_Miter &, r_Double *, const r_Double *);
+template void swap_array_templ(r_Miter &, r_Miter &, const r_Octet *);
+template void swap_array_templ(r_Miter &, r_Miter &, const r_Short *);
+template void swap_array_templ(r_Miter &, r_Miter &, const r_Long *);
+template void swap_array_templ(r_Miter &, r_Miter &, const r_Float *);
+template void swap_array_templ(r_Miter &, r_Miter &, const r_Double *);
+
+
+
+
+
+/*
+ * r_Endian members
+ */
+
+r_Short r_Endian::swap( r_Short val )
+{
+ return eswap(val);
+}
+
+r_UShort r_Endian::swap( r_UShort val )
+{
+ return eswap(val);
+}
+
+r_Long r_Endian::swap( r_Long val )
+{
+ return eswap(val);
+}
+
+r_ULong r_Endian::swap( r_ULong val )
+{
+ return eswap(val);
+}
+/*
+long r_Endian::swap( long val )
+{
+ return eswap(val);
+}
+
+r_ULong r_Endian::swap( r_ULong val )
+{
+ return eswap(val);
+}
+*/
+r_Float r_Endian::swap( r_Float val )
+{
+ return eswap(val);
+}
+
+r_Double r_Endian::swap( r_Double val )
+{
+ return eswap(val);
+}
+
+
+r_Endian::r_Endianness r_Endian::get_endianness( void )
+{
+#ifdef LITTLE_ENDIAN
+ return r_Endian_Little;
+#else
+ return r_Endian_Big;
+#endif
+}
+
+
+
+/*
+ * Simplest array swapping: linear buffer filled with atomic type
+ */
+
+void r_Endian::swap_array( const r_Primitive_Type *type, r_Bytes size, const void *src, void *dest )
+{
+ switch (type->type_id())
+ {
+ case r_Primitive_Type::BOOL:
+ case r_Primitive_Type::CHAR:
+ case r_Primitive_Type::OCTET:
+ if (src != (const void*)dest)
+ {
+ // change of endianness on 1 byte data is a NULL operation.
+ // if src and dest differ, we have to _copy_, though.
+ memcpy(dest, src, size);
+ }
+ break;
+ case r_Primitive_Type::SHORT:
+ swap_array_templ(size, (r_Short*)dest, (const r_Short*)src);
+ break;
+ case r_Primitive_Type::USHORT:
+ swap_array_templ(size, (r_UShort*)dest, (const r_UShort*)src);
+ break;
+ case r_Primitive_Type::LONG:
+ swap_array_templ(size, (r_Long*)dest, (const r_Long*)src);
+ break;
+ case r_Primitive_Type::ULONG:
+ swap_array_templ(size, (r_ULong*)dest, (const r_ULong*)src);
+ break;
+ case r_Primitive_Type::FLOAT:
+ case r_Primitive_Type::COMPLEXTYPE1:
+ swap_array_templ(size, (r_Float*)dest, (const r_Float*)src);
+ break;
+ case r_Primitive_Type::DOUBLE:
+ case r_Primitive_Type::COMPLEXTYPE2:
+ swap_array_templ(size, (r_Double*)dest, (const r_Double*)src);
+ break;
+ default:
+ RMDBGONCE(3, RMDebug::module_raslib, "r_Endian", "swap_array(type, size, src, dest) bad typeId " << type->type_id());
+ break;
+ }
+}
+
+
+/*
+ * Same functionality as function above, but with the types given implicitly
+ * by the parameters
+ */
+
+// Dummies, but useful when templates are used
+void r_Endian::swap_array( r_Bytes size, const r_Octet *src, r_Octet *dest )
+{
+}
+
+void r_Endian::swap_array( r_Bytes size, const r_Char *src, r_Char *dest )
+{
+}
+
+// Here go the real ones...
+void r_Endian::swap_array( r_Bytes size, const r_Short *src, r_Short *dest )
+{
+ swap_array_templ(size, dest, src);
+}
+
+void r_Endian::swap_array( r_Bytes size, const r_UShort *src, r_UShort *dest )
+{
+ swap_array_templ(size, dest, src);
+}
+
+void r_Endian::swap_array( r_Bytes size, const r_Long *src, r_Long *dest )
+{
+ swap_array_templ(size, dest, src);
+}
+
+void r_Endian::swap_array( r_Bytes size, const r_ULong *src, r_ULong *dest )
+{
+ swap_array_templ(size, dest, src);
+}
+/*
+void r_Endian::swap_array( r_Bytes size, const long *src, long *dest )
+{
+ swap_array_templ(size, dest, src);
+}
+
+void r_Endian::swap_array( r_Bytes size, const r_ULong *src, r_ULong *dest )
+{
+ swap_array_templ(size, dest, src);
+}
+*/
+void r_Endian::swap_array( r_Bytes size, const r_Float *src, r_Float *dest )
+{
+ swap_array_templ(size, dest, src);
+}
+
+void r_Endian::swap_array( r_Bytes size, const r_Double *src, r_Double *dest )
+{
+ swap_array_templ(size, dest, src);
+}
+
+
+/*
+ * Same functionality as above, but with the type size given as parameter
+ */
+
+void r_Endian::swap_array( r_Bytes size, r_Bytes tsize, const void *src, void *dest )
+{
+ switch (tsize)
+ {
+ case 2:
+ swap_array_templ(size, (r_Short*)dest, (const r_Short*)src);
+ break;
+ case 4:
+ swap_array_templ(size, (r_Long*)dest, (const r_Long*)src);
+ break;
+ case 8:
+ case 16: // complexd
+ swap_array_templ(size, (r_Double*)dest, (const r_Double*)src);
+ break;
+ default:
+ break;
+ }
+}
+
+
+
+/*
+ * ``Half-generic'': array with arbitrary total domain and iteration
+ * domain, but same domains for src and dest
+ */
+void r_Endian::swap_array( const r_Primitive_Type *type, const r_Minterval &srcDom, const r_Minterval &srcIterDom, const void *src, void *dest, r_ULong step )
+{
+ if ((srcDom == srcIterDom) && (step == type->size()))
+ {
+ r_ULong size = step * srcDom.cell_count();
+
+ swap_array(type, size, src, dest);
+ }
+ else
+ {
+ r_Miter iter(&srcIterDom, &srcDom, step, (const char*)src);
+
+ switch (type->type_id())
+ {
+ case r_Primitive_Type::BOOL:
+ case r_Primitive_Type::CHAR:
+ case r_Primitive_Type::OCTET:
+ if (src != (const void*)dest)
+ {
+ swap_array_templ(iter, (r_Octet*)dest, (const r_Octet*)src);
+ }
+ break;
+ case r_Primitive_Type::SHORT:
+ swap_array_templ(iter, (r_Short*)dest, (const r_Short*)src);
+ break;
+ case r_Primitive_Type::USHORT:
+ swap_array_templ(iter, (r_UShort*)dest, (const r_UShort*)src);
+ break;
+ case r_Primitive_Type::LONG:
+ swap_array_templ(iter, (r_Long*)dest, (const r_Long*)src);
+ break;
+ case r_Primitive_Type::ULONG:
+ swap_array_templ(iter, (r_ULong*)dest, (const r_ULong*)src);
+ break;
+ case r_Primitive_Type::FLOAT:
+ case r_Primitive_Type::COMPLEXTYPE1:
+ swap_array_templ(iter, (r_Float*)dest, (const r_Float*)src);
+ break;
+ case r_Primitive_Type::DOUBLE:
+ case r_Primitive_Type::COMPLEXTYPE2:
+ swap_array_templ(iter, (r_Double*)dest, (const r_Double*)src);
+ break;
+ default:
+ RMDBGONCE(3, RMDebug::module_raslib, "r_Endian", "swap_array(type, srcdom, srciterdom, src, dest, step) bad typeId " << type->type_id());
+ break;
+ }
+ }
+}
+
+
+static void swap_array_struct( const r_Structure_Type *structType, const r_Minterval &srcDom, const r_Minterval &srcIterDom, const void *src, void *dest, r_ULong step )
+{
+ r_Structure_Type::attribute_iterator iter(structType->defines_attribute_begin());
+
+ while (iter != structType->defines_attribute_end())
+ {
+ r_Type *newType = (*iter).type_of().clone();
+ const void *srcPtr = (const void*)(((const r_Octet*)src) + (*iter).offset());
+ void *destPtr = (void*)(((r_Octet*)dest) + (*iter).offset());
+ if (newType->isStructType())
+ swap_array_struct((const r_Structure_Type*)newType, srcDom, srcIterDom, srcPtr, destPtr, step);
+ else
+ r_Endian::swap_array((const r_Primitive_Type*)newType, srcDom, srcIterDom, srcPtr, destPtr, step);
+ delete newType;
+ iter++;
+ }
+}
+
+
+void r_Endian::swap_array( const r_Base_Type *type, const r_Minterval &srcDom, const r_Minterval &srcIterDom, const void *src, void *dest )
+{
+ if (type->isStructType())
+ swap_array_struct((const r_Structure_Type*)type, srcDom, srcIterDom, src, dest, type->size());
+ else
+ swap_array((const r_Primitive_Type*)type, srcDom, srcIterDom, src, dest, type->size());
+}
+
+
+
+
+/*
+ * Fully generic: different total domain and iteration domain for both
+ * src and dest. Beware that the number of cells in the iteration domains
+ * for src and dest must be identical!
+ */
+
+void r_Endian::swap_array( const r_Primitive_Type *type, const r_Minterval &srcDom, const r_Minterval &srcIterDom, const r_Minterval &destDom, const r_Minterval &destIterDom, const void *src, void *dest, r_ULong step )
+{
+ /// check if the whole thing reduces to a linear scan
+ if ((srcDom == srcIterDom) && (step == type->size()))
+ {
+ r_ULong size = step * srcDom.cell_count();
+
+ swap_array(type, size, src, dest);
+ }
+ /// no, generic code...
+ else
+ {
+ r_Miter siter(&srcIterDom, &srcDom, (r_Long)step, (const char*)src);
+ r_Miter diter(&destIterDom, &destDom, (r_Long)step, (const char*)dest);
+
+ switch (type->type_id())
+ {
+ case r_Primitive_Type::BOOL:
+ case r_Primitive_Type::CHAR:
+ case r_Primitive_Type::OCTET:
+ if (src != (const void*)dest)
+ {
+ swap_array_templ(siter, diter, (const r_Octet*)src);
+ }
+ break;
+ case r_Primitive_Type::SHORT:
+ swap_array_templ(siter, diter, (const r_Short*)src);
+ break;
+ case r_Primitive_Type::USHORT:
+ swap_array_templ(siter, diter, (const r_UShort*)src);
+ break;
+ case r_Primitive_Type::LONG:
+ swap_array_templ(siter, diter, (const r_Long*)src);
+ break;
+ case r_Primitive_Type::ULONG:
+ swap_array_templ(siter, diter, (const r_ULong*)src);
+ break;
+ case r_Primitive_Type::FLOAT:
+ case r_Primitive_Type::COMPLEXTYPE1:
+ swap_array_templ(siter, diter, (const r_Float*)src);
+ break;
+ case r_Primitive_Type::DOUBLE:
+ case r_Primitive_Type::COMPLEXTYPE2:
+ swap_array_templ(siter, diter, (const r_Double*)src);
+ break;
+ default:
+ RMDBGONCE(3, RMDebug::module_raslib, "r_Endian", "swap_array(type, srcdom, srciterdom, destdom, destiterdom, src, dest, step) bad typeId " << type->type_id());
+ break;
+ }
+ }
+}
+
+
+static void swap_array_struct( const r_Structure_Type *structType, const r_Minterval &srcDom, const r_Minterval &srcIterDom, const r_Minterval &destDom, const r_Minterval &destIterDom, const void *src, void *dest, r_ULong step)
+{
+ r_Structure_Type::attribute_iterator iter(structType->defines_attribute_begin());
+
+ while (iter != structType->defines_attribute_end())
+ {
+ r_Type *newType = (*iter).type_of().clone();
+ const void *srcPtr = (const void*)(((const r_Octet*)src) + (*iter).offset());
+ void *destPtr = (void*)(((r_Octet*)dest) + (*iter).offset());
+ if (newType->isStructType())
+ swap_array_struct((const r_Structure_Type*)newType, srcDom, srcIterDom, destDom, destIterDom, srcPtr, destPtr, step);
+ else
+ r_Endian::swap_array((const r_Primitive_Type*)newType, srcDom, srcIterDom, destDom, destIterDom, srcPtr, destPtr, step);
+ delete newType;
+ iter++;
+ }
+}
+
+void r_Endian::swap_array( const r_Base_Type *type, const r_Minterval &srcDom, const r_Minterval &srcIterDom, const r_Minterval &destDom, const r_Minterval &destIterDom, const void *src, void *dest )
+{
+ if (type->isStructType())
+ swap_array_struct((const r_Structure_Type*)type, srcDom, srcIterDom, destDom, destIterDom, src, dest, type->size());
+ else
+ swap_array((const r_Primitive_Type*)type, srcDom, srcIterDom, destDom, destIterDom, src, dest, type->size());
+}
+
+std::ostream& operator<<(std::ostream& s, r_Endian::r_Endianness& e)
+{
+ switch(e) {
+ case r_Endian::r_Endian_Little:
+ s << "Little_Endian";
+ break;
+ case r_Endian::r_Endian_Big:
+ s << "Big_Endian";
+ break;
+ default:
+ s << "Unkown r_Endiannes";
+ break;
+ }
+ return s;
+}
diff --git a/raslib/endian.hh b/raslib/endian.hh
new file mode 100644
index 0000000..fb8e0ff
--- /dev/null
+++ b/raslib/endian.hh
@@ -0,0 +1,118 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: endian.hh
+ *
+ * MODULE: raslib
+ * CLASS: r_Endian
+ *
+ * COMMENTS:
+ * None
+*/
+
+#ifndef _R_ENDIANTOOLS_HH_
+#define _R_ENDIANTOOLS_HH_
+
+#include <iostream>
+
+class r_Minterval;
+class r_Base_Type;
+class r_Primitive_Type;
+#include "raslib/odmgtypes.hh"
+#include "raslib/mddtypes.hh"
+
+//@ManMemo: Module {\bf raslib}
+
+/*@Doc:
+ Class to check the endianness of the host machine and to
+ swap the endianness of types and arrays. Don't instantiate,
+ static members only.
+*/
+
+class r_Endian
+{
+ public:
+ /// endianness identifiers
+ enum r_Endianness {
+ r_Endian_Big,
+ r_Endian_Little
+ };
+
+ /// swap endianness of atomic types
+ static r_Short swap( r_Short val );
+ static r_UShort swap( r_UShort val );
+ static r_Long swap( r_Long val );
+ static r_ULong swap( r_ULong val );
+ static r_Float swap( r_Float val );
+ static r_Double swap( r_Double val );
+
+ /// query host machine's endianness
+ static r_Endianness get_endianness( void );
+
+ /// change the endianness of a linear array of size <size> and type <type>
+ static void swap_array( const r_Primitive_Type *type, r_Bytes size, const void *src, void *dest );
+
+ /// change the endianness of a linear array of size <size>, type implicit
+ static void swap_array( r_Bytes size, const r_Octet *src, r_Octet *dest ); // dummy
+ static void swap_array( r_Bytes size, const r_Char *src, r_Char *dest ); // dummy
+ static void swap_array( r_Bytes size, const r_Short *src, r_Short *dest );
+ static void swap_array( r_Bytes size, const r_UShort *src, r_UShort *dest );
+ static void swap_array( r_Bytes size, const r_Long *src, r_Long *dest );
+ static void swap_array( r_Bytes size, const r_ULong *src, r_ULong *dest );
+ static void swap_array( r_Bytes size, const r_Float *src, r_Float *dest );
+ static void swap_array( r_Bytes size, const r_Double *src, r_Double *dest );
+
+ /// change the endianness of a linear array of size <size> with type size <tsize>
+ static void swap_array( r_Bytes size, r_Bytes tsize, const void *src, void *dest);
+
+ /// change the endianness of one type member of an array for identical domains
+ /// for src and dest; step is the increment between cells
+ static void swap_array( const r_Primitive_Type *type, const r_Minterval &srcDom,
+ const r_Minterval &srcIterDom, const void *src, void *dest,
+ r_ULong step );
+
+ /// change the endianness of the entire tile for identical domains for src and dest
+ static void swap_array( const r_Base_Type *type, const r_Minterval &srcDom,
+ const r_Minterval &srcIterDom, const void *src, void *dest );
+
+ /// change the endianness of one type member of an array for the generic case;
+ /// step is the increment between cells.
+ static void swap_array( const r_Primitive_Type *type, const r_Minterval &srcDom,
+ const r_Minterval &srcIterDom, const r_Minterval &destDom,
+ const r_Minterval &destIterDom, const void *src, void *dest,
+ r_ULong step );
+
+ /// change the endianness of the entire tile for the generic case
+ static void swap_array( const r_Base_Type *type, const r_Minterval &srcDom,
+ const r_Minterval &srcIterDom, const r_Minterval &destDom,
+ const r_Minterval &destIterDom, const void *src, void *dest );
+};
+
+//@ManMemo: Module: {\bf raslib}
+/**
+ Output stream operator for enum of type {\tt const} \Ref{r_Minterval}.
+ */
+ extern std::ostream& operator<<( std::ostream& s, r_Endian::r_Endianness& e );
+
+
+#endif
diff --git a/raslib/error.cc b/raslib/error.cc
new file mode 100644
index 0000000..1ccc3cc
--- /dev/null
+++ b/raslib/error.cc
@@ -0,0 +1,888 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/***
+ * SOURCE: error.cc
+ *
+ * MODULE: raslib
+ * CLASS: r_Error
+ *
+ * COMMENTS:
+ * - in general, string should be used instead of dynamic char* mgmnt
+ * - r_Error specializations must not use int literals
+ * - freeTextTable() does not free strings -> mem leak
+*/
+
+static const char rcsid[] = "@(#)raslib, r_Error: $Id: error.cc,v 1.60 2005/09/03 20:35:12 rasdev Exp $";
+
+using namespace std;
+
+using namespace std;
+
+#include "mymalloc/mymalloc.h"
+
+#include "raslib/error.hh"
+#include "raslib/rmdebug.hh"
+#include "debug.hh"
+
+
+#include <string.h>
+#ifdef __VISUALC__
+#include <strstrea.h>
+#else
+#include <strstream>
+#endif
+
+#include <fstream>
+#include <string>
+#include <utility>
+#include <list>
+#include <stdlib.h>
+#include <stdio.h>
+
+
+using std::endl;
+using std::ends;
+using std::ios;
+using std::ostrstream;
+
+r_Error::errorInfo* r_Error::textList = NULL;
+
+r_Error::r_Error()
+ : theKind(r_Error_General),
+ errorText(0),
+ errorNo(0)
+ {
+ resetErrorText();
+ }
+
+r_Error::r_Error(const r_Error& err)
+ : errorText(0),
+ errorNo(err.errorNo),
+ theKind(err.theKind)
+ {
+ if (err.errorText)
+ {
+ errorText = new char[ strlen(err.errorText)+1 ];
+ strcpy(errorText, err.errorText);
+ }
+ }
+
+r_Error::r_Error(kind the_kind, unsigned int newErrorNo)
+ : errorText(0),
+ theKind(the_kind),
+ errorNo(newErrorNo)
+ {
+ resetErrorText();
+ }
+
+r_Error::~r_Error() throw()
+ {
+ if (errorText)
+ delete[] errorText;
+ }
+
+
+
+const char*
+r_Error::what() const throw ()
+ {
+ return (const char*)errorText;
+ }
+
+
+
+const r_Error&
+r_Error::operator=(const r_Error& obj)
+ {
+ if (this != &obj)
+ {
+ if (errorText)
+ {
+ delete[] errorText;
+ errorText = NULL;
+ }
+
+ theKind = obj.theKind;
+ errorNo = obj.errorNo;
+
+ if (obj.errorText)
+ {
+ errorText = new char[ strlen(obj.errorText)+1 ];
+ strcpy(errorText, obj.errorText);
+ }
+ }
+
+ return *this;
+ }
+
+char*
+r_Error::serialiseError()
+ {
+ // default implementation for errors not of kind r_Error_SerialisableException
+ char* retVal = NULL;
+ char buf[80]; // should be enough for two numbers
+
+ sprintf(buf, "%d\t%d", theKind, errorNo);
+ retVal = (char*)mymalloc(strlen(buf) + 1);
+ strcpy(retVal, buf);
+ return retVal;
+ }
+
+
+r_Error*
+r_Error::getAnyError(char* serErr)
+{
+ r_Error* retVal = NULL;
+ char* currChar = NULL;
+ kind newTheKind;
+ unsigned int newErrNum = 0;
+ // first read the attributes of r_Error to find out which subclass it is
+ // (stored in errNum).
+ newTheKind = (r_Error::kind)strtol(serErr, &currChar, 10);
+ newErrNum = strtol(currChar+1, &currChar, 10);
+
+ if (newTheKind != r_Error_SerialisableException)
+ {
+ retVal = new r_Error(newTheKind, newErrNum);
+ }
+ else
+ {
+ // add new serialisable errors to this case!
+ switch (newErrNum)
+ {
+ case 206:
+ retVal = new r_Ebase_dbms(newTheKind, newErrNum, currChar+1);
+ break;
+ }
+ }
+ return retVal;
+}
+
+//
+// --- error text file table maintenance ---------------------------------
+//
+
+/*
+ * list of error codes, contining numerical error code, error flag char
+ * (warning or error), and error text.
+ * It is modelled as nested pairs to allow using standard classes.
+ * Filled from file.
+ */
+list<pair<pair<int,char>, char*> > errorTexts;
+
+/// has error text file been loaded, i.e., is table filled?
+bool errorTextsLoaded = false;
+
+void
+initTextTable()
+{
+ char errorFileName[FILENAME_MAX]; // error file path/name
+ std::ifstream errortexts;
+ string line; // current input line read from file
+ char errKind;
+ int errNo;
+ char errText[1000];
+ unsigned int numOfEntries = 0;
+ int result; // sscanf() result
+
+ // determine file name; use path if env var is set
+ strcpy( errorFileName, "" );
+ const char* rmanHome = getenv( RASDAMAN_PATH_VARNAME );
+ if (rmanHome)
+ {
+ strcat(errorFileName, rmanHome);
+ strcat(errorFileName, ERRORTEXXT_PATH );
+ strcat(errorFileName, "/" );
+ } else {
+ strcat(errorFileName, SHARE_DATA_DIR);
+ strcat(errorFileName, "/");
+ }
+ strcat(errorFileName, ERRORTEXT_FILE );
+ // RMInit::logOut << "using error text file: " << errorFileName << endl;
+
+ // errortexts.open(errorFileName, ios::nocreate | ios::in);
+ errortexts.open(errorFileName, ios::in);
+
+ // In case the file 'errtxts' can't be found
+#ifdef __VISUALC__
+ if (!errortexts.is_open())
+#else
+ if (!errortexts)
+#endif
+ {
+ r_Error::textList = NULL;
+ RMInit::logOut << "No error texts file found at: " << errorFileName << endl;
+ }
+ else // File errtxts found
+ {
+ // read entries from file
+ numOfEntries = 0; // just for displaying, currently not used otherwise
+ while ( ! errortexts.eof() )
+ {
+ getline( errortexts, line );
+ char *errText = (char*) mymalloc( line.length() + 1 );
+ if (errText == NULL)
+ {
+ RMInit::logOut << "Fatal error: cannot allocate error text table line #" << numOfEntries << endl;
+ throw r_Error( r_Error::r_Error_MemoryAllocation );
+ }
+ // general line format is (aside of comments and empty lines): ddd^f^text...
+ result = sscanf( line.c_str(), "%d^%c^%[^\n]s\n", &errNo, &errKind, errText );
+ if (result == 3) // consider only lines that match given structure
+ {
+ errorTexts.push_back( pair<pair<int,char>,char*> (pair<int,char>( errNo, errKind ), errText) );
+ numOfEntries++;
+ }
+ }
+ // RMInit::logOut << "number of error texts loaded: " << numOfEntries << endl;
+ errorTextsLoaded = true;
+ }
+ errortexts.close();
+}
+
+
+
+void
+freeTextTable()
+{
+ list<pair<pair<int,char>, char*> >::iterator iter = errorTexts.begin();
+ list<pair<pair<int,char>, char*> >::iterator end = errorTexts.end();
+
+ if (errorTextsLoaded) // have we initialized the table previously?
+ { // yes -> free each string
+#if 0 // doesn't work yet
+ while ( iter != NULL && iter != end )
+ {
+ cout << "freeing " << iter->second << endl << flush;
+ free( iter->second );
+ iter->second = NULL;
+ // delete[] iter->second;
+ }
+#endif
+ errorTexts.clear(); // now clear list itself
+ }
+}
+
+
+
+r_Error::r_Error(unsigned int errorno)
+ : errorText(NULL),
+ theKind(r_Error_General),
+ errorNo(errorno)
+{
+ resetErrorText();
+}
+
+
+
+void
+r_Error::setErrorTextOnKind()
+ {
+ char buffer[256];
+
+ switch (theKind)
+ {
+ case r_Error_General :
+ strcpy(buffer, " ODMG General");
+ break;
+
+ case r_Error_DatabaseClassMismatch :
+ strcpy(buffer, "Database Class Mismatch");
+ break;
+
+ case r_Error_DatabaseClassUndefined :
+ strcpy(buffer, "Database Class Undefined");
+ break;
+
+ case r_Error_DatabaseClosed :
+ strcpy(buffer, "Database Closed");
+ break;
+
+ case r_Error_DatabaseOpen :
+ strcpy(buffer, "Database Open");
+ break;
+
+ case r_Error_DateInvalid :
+ strcpy(buffer, "Date Invalid");
+ break;
+
+ case r_Error_IteratorExhausted :
+ strcpy(buffer, "Iterator Exhausted");
+ break;
+
+ case r_Error_NameNotUnique :
+ strcpy(buffer, "Name Not Unique");
+ break;
+
+ case r_Error_QueryParameterCountInvalid :
+ strcpy(buffer, "Query Parameter Count Invalid");
+ break;
+
+ case r_Error_QueryParameterTypeInvalid :
+ strcpy(buffer, "Query Parameter Type Invalid");
+ break;
+
+ case r_Error_RefInvalid :
+ strcpy(buffer, "Ref Invalid");
+ break;
+
+ case r_Error_RefNull :
+ strcpy(buffer, "Ref Null");
+ break;
+
+ case r_Error_TimeInvalid :
+ strcpy(buffer, "Time Invalid");
+ break;
+
+ case r_Error_TimestampInvalid :
+ strcpy(buffer, "Timestamp Invalid");
+ break;
+
+ case r_Error_TransactionOpen :
+ strcpy(buffer, "Transaction Open");
+ break;
+
+ case r_Error_TransactionNotOpen :
+ strcpy(buffer, "Transaction Not Open");
+ break;
+
+ case r_Error_TypeInvalid :
+ strcpy(buffer, "Type Invalid");
+ break;
+
+ case r_Error_DatabaseUnknown :
+ strcpy(buffer, "Database Unknown");
+ break;
+
+ case r_Error_TransferFailed :
+ strcpy(buffer, "Transfer Failed");
+ break;
+
+ case r_Error_HostInvalid :
+ strcpy(buffer, "Host Invalid");
+ break;
+
+ case r_Error_ServerInvalid :
+ strcpy(buffer, "Server Invalid");
+ break;
+
+ case r_Error_ClientUnknown :
+ strcpy(buffer, "Client Unknown");
+ break;
+
+ case r_Error_ObjectUnknown :
+ strcpy(buffer, "Object Unknown");
+ break;
+
+ case r_Error_ObjectInvalid :
+ strcpy(buffer, "Object Invalid");
+ break;
+
+ case r_Error_QueryExecutionFailed :
+ strcpy(buffer, "Query Execution Failed");
+ break;
+
+ case r_Error_BaseDBMSFailed :
+ strcpy(buffer, "Base DBMS Failed");
+ break;
+
+ case r_Error_CollectionElementTypeMismatch :
+ strcpy(buffer, "Collection Element Type Mismatch");
+ break;
+
+ case r_Error_CreatingOIdFailed :
+ strcpy(buffer, "Creation of OID failed");
+ break;
+
+ case r_Error_TransactionReadOnly :
+ strcpy(buffer, "Transaction is read only");
+ break;
+
+ case r_Error_LimitsMismatch :
+ strcpy(buffer, "Limits reported to an object mismatch");
+ break;
+
+ case r_Error_NameInvalid :
+ strcpy(buffer, "Name Invalid");
+ break;
+
+ case r_Error_FeatureNotSupported :
+ strcpy(buffer, "Feature is not supported");
+ break;
+
+ case r_Error_AccesDenied:
+ strcpy(buffer, "Access denied");
+ break;
+
+ case r_Error_MemoryAllocation:
+ strcpy(buffer, "Memory allocation failed");
+ break;
+
+ default:
+ strcpy(buffer, "not specified");
+ break;
+ }
+
+ if (errorText)
+ delete[] errorText;
+
+ char preText[] = "Exception: ";
+
+ errorText = new char[strlen(preText) + strlen(buffer) + 1];
+ strcpy(errorText, preText);
+ strcat(errorText, buffer);
+ }
+
+
+
+void
+r_Error::setErrorTextOnNumber()
+{
+ char *result = NULL; // ptr to error text constructed
+
+ // delete old error text, if any
+ if (errorText)
+ {
+ delete[] errorText;
+ errorText = 0;
+ }
+
+ // has list been built earlier?
+ if (errorTextsLoaded)
+ { // yes, we have a list -> search
+ // search through list to find entry
+ list<pair<pair<int,char>, char*> >::iterator iter = errorTexts.begin();
+ list<pair<pair<int,char>, char*> >::iterator end = errorTexts.end();
+ bool found = false;
+ while ( iter != end && ! found )
+ {
+ if (iter->first.first == errorNo)
+ found = true;
+ else
+ iter++;
+ }
+
+ if (found)
+ result = iter->second;
+ else
+ result = "(no explanation text available for this error code.)";
+ }
+ else // no, there is no spoon -err- list
+ result = "(no explanation text available - cannot find/load file with standard error messages.)";
+
+ errorText = new char[strlen(result) + 1];
+ if (errorText == NULL)
+ {
+ RMInit::logOut << "Error: cannot allocate error text." << endl;
+ throw r_Error( r_Error::r_Error_MemoryAllocation );
+ }
+ else
+ strcpy(errorText, result);
+
+ return;
+}
+
+
+
+void
+r_Error::setTextParameter(const char* parameterName, int value)
+ {
+ // convert long value to string
+ char valueString[256];
+ ostrstream valueStream(valueString, sizeof(valueString) );
+ valueStream << value << ends;
+
+ setTextParameter(parameterName, valueString);
+ }
+
+
+
+void
+r_Error::setTextParameter(const char* parameterName, const char* value)
+ {
+ if (errorText)
+ {
+ // locate the next matching parameter in the query string
+ char* paramStart = strstr(errorText, parameterName);
+
+ if (paramStart)
+ {
+ // allocate a new query string and fill it
+ char* paramEnd = NULL;
+ int paramLength = 0;
+ char* tmpText = NULL;
+ int newLength = 0;
+
+ tmpText = errorText;
+ paramLength = strlen(parameterName);
+ paramEnd = paramStart + paramLength;
+ newLength = strlen(tmpText) - paramLength + strlen(value) + 1;
+ errorText = new char[newLength];
+
+ *paramStart = '\0';
+
+ ostrstream queryStream(errorText, newLength);
+ queryStream << tmpText << value << paramEnd << ends;
+
+ delete[] tmpText;
+ }
+ }
+ }
+
+
+
+void
+r_Error::resetErrorText()
+ {
+ // If no error number is specified use the error kind for the text.
+ if (errorNo)
+ setErrorTextOnNumber();
+ else
+ setErrorTextOnKind();
+ }
+
+
+
+r_Eno_interval::r_Eno_interval()
+ : r_Error(201)
+ {
+ TALK( "r_Error::resetErrorText() - code 201" );
+ resetErrorText();
+ }
+
+
+
+r_Eindex_violation::r_Eindex_violation(r_Range dlow, r_Range dhigh, r_Range dindex)
+ : r_Error(202), low(dlow), high(dhigh), index(dindex)
+ {
+ TALK( "r_Error::r_Eindex_violation() - code 202" );
+ resetErrorText();
+ }
+
+
+
+void
+r_Eindex_violation::resetErrorText()
+ {
+ setErrorTextOnNumber();
+
+ setTextParameter("$low", low );
+ setTextParameter("$high", high );
+ setTextParameter("$index", index);
+ }
+
+
+
+r_Edim_mismatch::r_Edim_mismatch(r_Dimension pdim1, r_Dimension pdim2)
+ : r_Error(203), dim1(pdim1), dim2(pdim2)
+ {
+ TALK( "r_Error::r_Edim_mismatch() - code 203; dim1=" << pdim1 << ", dim2=" << pdim2 );
+ resetErrorText();
+ }
+
+
+
+void
+r_Edim_mismatch::resetErrorText()
+ {
+ setErrorTextOnNumber();
+
+ setTextParameter("$dim1", dim1);
+ setTextParameter("$dim2", dim2);
+ }
+
+
+
+r_Einit_overflow::r_Einit_overflow()
+ : r_Error(204)
+ {
+ TALK( "r_Error::r_Einit_overflow() - code 204" );
+ resetErrorText();
+ }
+
+
+
+r_Eno_cell::r_Eno_cell()
+ : r_Error(205)
+ {
+ TALK( "r_Error::r_Eno_cell() - code 205" );
+ resetErrorText();
+ }
+
+
+
+r_Equery_execution_failed::r_Equery_execution_failed(unsigned int errorno, unsigned int lineno, unsigned int columnno, const char* initToken)
+ : r_Error(errorno),
+ lineNo(lineno),
+ columnNo(columnno)
+ {
+ TALK( "r_Error::r_Equery_execution_failed() - errorno=" << errorno );
+
+ token = new char[strlen(initToken)+1];
+ strcpy(token, initToken);
+
+ resetErrorText();
+ }
+
+
+
+r_Equery_execution_failed::r_Equery_execution_failed(const r_Equery_execution_failed &err)
+ : r_Error(err),
+ lineNo(0),
+ columnNo(0)
+ {
+ TALK( "r_Error::r_Equery_execution_failed()" );
+
+ lineNo = err.lineNo;
+ columnNo = err.columnNo;
+
+ token = new char[strlen(err.token)+1];
+ strcpy(token, err.token);
+ }
+
+
+
+r_Equery_execution_failed::~r_Equery_execution_failed() throw()
+ {
+ if (token)
+ delete[] token;
+ }
+
+
+
+void
+r_Equery_execution_failed::resetErrorText()
+ {
+ setErrorTextOnNumber();
+
+ setTextParameter("$errorNo", errorNo);
+ setTextParameter("$lineNo", lineNo);
+ setTextParameter("$columnNo", columnNo);
+ setTextParameter("$token", token);
+ }
+
+
+
+r_Elimits_mismatch::r_Elimits_mismatch(r_Range lim1, r_Range lim2)
+ : r_Error(r_Error_LimitsMismatch), i1(lim1), i2(lim2)
+ {
+ TALK( "r_Error::r_Elimits_mismatch() - lim1=" << lim1 << ", lim2=" << lim2 );
+ resetErrorText();
+ }
+
+
+
+void
+r_Elimits_mismatch::resetErrorText()
+ {
+ setErrorTextOnNumber();
+
+ setTextParameter("$dim1", i1);
+ setTextParameter("$dim2", i2);
+ }
+
+/* ------------------------------------------------------------------
+ class r_Ebase_dbms
+ ------------------------------------------------------------------ */
+
+r_Ebase_dbms::r_Ebase_dbms(const long& newDbmsErrNum, const char* newDbmsErrTxt)
+ : r_Error(r_Error_SerialisableException, 206),
+ dbmsErrNum(newDbmsErrNum),
+ whatTxt(0)
+{
+ TALK( "r_Error::r_Ebase_dbms() code 206 - " << newDbmsErrTxt );
+ baseDBMS = strdup("Error in base DBMS, error number: ");
+ dbmsErrTxt = strdup(newDbmsErrTxt);
+ buildWhat();
+}
+
+r_Ebase_dbms::r_Ebase_dbms(const r_Ebase_dbms& obj)
+ : r_Error(obj),
+ dbmsErrNum(0),
+ whatTxt(0)
+{
+ TALK( "r_Error::r_Ebase_dbms()" );
+
+ dbmsErrNum = obj.dbmsErrNum;
+ if (obj.baseDBMS)
+ {
+ baseDBMS = (char*)mymalloc(strlen(obj.baseDBMS) + 1);
+ strcpy(baseDBMS, obj.baseDBMS);
+ }
+ else
+ {
+ baseDBMS = 0;
+ }
+ if (obj.dbmsErrTxt)
+ {
+ dbmsErrTxt = (char*)mymalloc(strlen(obj.dbmsErrTxt) + 1);
+ strcpy(dbmsErrTxt, obj.dbmsErrTxt);
+ }
+ else
+ {
+ dbmsErrTxt = 0;
+ }
+ buildWhat();
+}
+
+// r_Ebase_dbms: constructor receiving kind, errno, and descriptive string
+// NB: the string must have the format "<kind>\t<errno>\t<text>"
+// (currently the only location where this is used is getAnyError() above)
+r_Ebase_dbms::r_Ebase_dbms(kind newTheKind, unsigned long newErrNum, const char* myStr)
+ : r_Error(newTheKind, newErrNum), whatTxt(0)
+{
+ TALK( "r_Error::r_Ebase_dbms() - kind=" << newTheKind );
+
+ // as the const char* cannot be passed to strtol() - this was a bug anyway -
+ // we copy the string. Efficiency is not a concern here. -- PB 2005-jan-14
+ // const char* currChar = myStr;
+ char* tmpBuf = NULL; // temp copy of myStr
+ char* currChar = NULL; // ptr iterating over tmpBuf
+ tmpBuf = strdup( myStr );
+ currChar = tmpBuf; // initialize char ptr to begin of buffer
+
+ // read the attributes of r_Ebase_dbms from the string already partially parsed by
+ // r_Error::getAnyError(char* serErr)
+ dbmsErrNum = strtol(currChar, &currChar, 10);
+ // of course \t is part of the string, so we trick a little
+ char* tmpPtr = strchr(((char*)currChar)+1, '\t');
+ if (tmpPtr==NULL) // no trailing information found?
+ {
+ baseDBMS = strdup( "unknown" );
+ dbmsErrTxt = strdup( "unknown" );
+ }
+ else // yes -> analyse it
+ {
+ *tmpPtr = '\0'; // terminate item for strdup()
+ baseDBMS = strdup(currChar+1); // extract item (db name) from string
+ *tmpPtr = '\t'; // re-substitute EOS with tab
+ currChar = strchr(currChar+1, '\t'); // search for tab as item delimiter
+ dbmsErrTxt = strdup(currChar+1); // extract final item which is error text
+ }
+ buildWhat();
+
+ free( tmpBuf ); // allocated in strdup() -- PB 2005-jan-14
+}
+
+r_Ebase_dbms::~r_Ebase_dbms() throw()
+{
+ if (whatTxt)
+ free(whatTxt);
+ if (dbmsErrTxt)
+ free(dbmsErrTxt);
+ if (baseDBMS)
+ free(baseDBMS);
+}
+
+const r_Ebase_dbms&
+r_Ebase_dbms::operator=(const r_Ebase_dbms& obj)
+{
+ if (this != &obj)
+ {
+ dbmsErrNum = obj.dbmsErrNum;
+
+ if (obj.baseDBMS)
+ {
+ if (baseDBMS) free(baseDBMS);
+ baseDBMS = (char*)mymalloc(strlen(obj.baseDBMS) + 1);
+ strcpy(baseDBMS, obj.baseDBMS);
+ }
+ else
+ {
+ baseDBMS = 0;
+ }
+ if (obj.dbmsErrTxt)
+ {
+ if (dbmsErrTxt) free(dbmsErrTxt);
+ dbmsErrTxt = (char*)mymalloc(strlen(obj.dbmsErrTxt) + 1);
+ strcpy(dbmsErrTxt, obj.dbmsErrTxt);
+ }
+ else
+ {
+ dbmsErrTxt = 0;
+ }
+ buildWhat();
+ }
+ return *this;
+ }
+
+void
+r_Ebase_dbms::buildWhat()
+{
+ // Ok, we have to build the error message for this class. The problem is that ressource
+ // allocation is involved here!
+ if(whatTxt)
+ free(whatTxt);
+ // assumes 10 digits for errNum
+ whatTxt = (char*)mymalloc(strlen(baseDBMS) + strlen(dbmsErrTxt) + 12);
+ strcpy(whatTxt, baseDBMS);
+ sprintf(whatTxt + strlen(whatTxt), "%d\n", dbmsErrNum);
+ strcat(whatTxt, dbmsErrTxt);
+}
+
+const char*
+r_Ebase_dbms::what() const throw()
+{
+ return whatTxt;
+}
+
+char*
+r_Ebase_dbms::serialiseError()
+{
+ char* tmpRes = r_Error::serialiseError();
+ char buf[40];
+ char* retVal;
+
+ sprintf(buf, "\t%d\t", dbmsErrNum);
+ retVal = (char*)mymalloc(strlen(tmpRes) + strlen(buf) + strlen(baseDBMS) + strlen(dbmsErrTxt) + 2);
+ strcpy(retVal, tmpRes);
+ strcat(retVal, buf);
+ strcat(retVal, baseDBMS);
+ strcat(retVal, "\t");
+ strcat(retVal, dbmsErrTxt);
+
+ free(tmpRes);
+ return retVal;
+}
+
+r_Eno_permission::r_Eno_permission()
+:r_Error(r_Error_AccesDenied,NO_PERMISSION_FOR_OPERATION)
+{
+ TALK( "r_Error::r_Eno_permission()" );
+ resetErrorText();
+}
+
+
+r_Ememory_allocation::r_Ememory_allocation(): r_Error(r_Error_MemoryAllocation, 66) // 66 is: mem alloc failed
+{
+ TALK( "r_Error::r_Ememory_allocation() - code 66" );
+ resetErrorText();
+}
+
+r_Ecapability_refused::r_Ecapability_refused()
+:r_Error(r_Error_AccesDenied,CAPABILITY_REFUSED)
+{
+ TALK( "r_Error::r_Ecapability_refused()" );
+ resetErrorText();
+}
+
diff --git a/raslib/error.hh b/raslib/error.hh
new file mode 100644
index 0000000..074c37d
--- /dev/null
+++ b/raslib/error.hh
@@ -0,0 +1,583 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: error.hh
+ *
+ * MODULE: raslib
+ * CLASS: r_Error
+ *
+ * COMMENTS:
+ *
+*/
+
+#ifndef _D_ERROR_
+#define _D_ERROR_
+
+//@ManMemo: Module: {\bf raslib}
+
+/*@Doc:
+
+ This class implements partially the \Ref{r_Error} class of the
+ C++ binding of ODMG-93 v.1.2. It extends exception
+ handling through deriving special classes for MDD specific
+ errors.
+
+ In future, \Ref{r_Error} should be derived from the class exception
+ defined in the C++ standard.
+
+ The class allows the specification of an error number. The error number
+ is used as an index to a generic textual description of the error which
+ is read by {\tt setErrorTextOnNumber()}. Error text is loaded from a
+ text file by the friend method {\tt initTextTable()} which has to be
+ invoked at the beginning of the application. The table can be freed again
+ using {\tt freeTextTable()}.
+ The parameters in the generic text are substituted using {\tt setTextParameter()}.
+
+ If no error number is specified, the error kind is used as error text.
+
+ Attention: The content of an error object is not supposed to be changed after
+ creation because the error text is initialized only in the constructor. Therefore,
+ just read methods for error parameters are supported.
+
+ A standard error text file is read by {\tt initTextTable()}. The location and file
+ name expected is defined here. Ideally all programs using this mechanism should
+ include error.hh to use the same settings.
+*/
+
+#ifdef __VISUALC__
+#pragma warning( disable : 4290 )
+#endif
+
+#include <exception>
+
+#include "raslib/mddtypes.hh"
+
+/*
+ * error text file ------------------
+ */
+
+/// name of variable which should contain path to rasdaman home dir
+#define RASDAMAN_PATH_VARNAME "RMANHOME"
+
+/// relative path to error text file, starting from $RMANHOME
+#define ERRORTEXXT_PATH "/bin"
+
+/// error text file name
+#define ERRORTEXT_FILE "errtxts"
+
+/* end error text file ------------------ */
+
+class r_Error : public std::exception
+{
+ public:
+
+ /// error information
+ struct errorInfo {
+ int num;
+ char kind;
+ char* text;
+ };
+
+ /// error kinds
+ enum kind { r_Error_General,
+ r_Error_DatabaseClassMismatch,
+ r_Error_DatabaseClassUndefined,
+ r_Error_DatabaseClosed,
+ r_Error_DatabaseOpen,
+ r_Error_DateInvalid,
+ r_Error_IteratorExhausted,
+ r_Error_NameNotUnique,
+ r_Error_QueryParameterCountInvalid,
+ r_Error_QueryParameterTypeInvalid,
+ r_Error_RefInvalid,
+ r_Error_RefNull,
+ r_Error_TimeInvalid,
+ r_Error_TimestampInvalid,
+ r_Error_TransactionOpen,
+ r_Error_TransactionNotOpen,
+ r_Error_TypeInvalid,
+
+ r_Error_OIdInvalid,
+ r_Error_OIdNotUnique,
+
+ r_Error_DatabaseUnknown,
+ r_Error_TransferFailed,
+ r_Error_HostInvalid,
+ r_Error_ServerInvalid,
+ r_Error_RpcInterfaceIncompatible,
+ r_Error_ClientUnknown,
+ r_Error_ObjectUnknown,
+ r_Error_ObjectInvalid,
+
+ r_Error_QueryExecutionFailed,
+ r_Error_BaseDBMSFailed,
+ r_Error_CollectionElementTypeMismatch,
+ r_Error_CreatingOIdFailed,
+ r_Error_TransactionReadOnly,
+
+ r_Error_LimitsMismatch,
+ r_Error_NameInvalid,
+ r_Error_FeatureNotSupported,
+ // r_Error_SerialisableException is used for subclasses which can be serialised
+ // as strings for client / server transfer
+ r_Error_SerialisableException,
+
+ r_Error_AccesDenied,
+ r_Error_SystemOverloaded,
+
+ r_Error_MemoryAllocation
+
+ };
+
+ /// default constructor
+ r_Error();
+
+ /// copy constructor
+ r_Error( const r_Error& );
+
+ /// constructor getting the kind
+ r_Error( kind the_kind, unsigned int newErrorNo = 0 );
+
+ /// constructor getting an error number
+ r_Error( unsigned int errorno );
+
+ /// destructor
+ virtual ~r_Error() throw();
+
+ /// get an error description
+ virtual const char* what() const throw();
+
+ /// assignment operator
+ const r_Error& operator=( const r_Error& obj );
+
+ //@Man: Read/Write methods:
+ //@{
+ ///
+ inline kind get_kind() const;
+ ///
+ inline unsigned int get_errorno() const;
+ ///
+ //@}
+
+ /// used to transfer exceptions of kind r_Error_SerialisableException to the client.
+ virtual char* serialiseError();
+ /*@Doc:
+ The char* returned is allocated with malloc (for potential RPC transfer) and has
+ to be freed by the caller.
+ */
+
+ /// This function parses a serialised error.
+ static r_Error* getAnyError(char* serErr);
+ /*@Doc:
+ Useful results can only be expected for errors of kind r_Error_SerialisableException.
+ */
+
+ /// read error text file into text table
+ friend void initTextTable();
+
+ /// free the text table again
+ friend void freeTextTable();
+
+ /// replace the specified parameter by the integer value
+ void setTextParameter( const char* parameterName, int value );
+
+ /// replace the specified parameter by the string value
+ void setTextParameter( const char* parameterName, const char* value );
+
+ protected:
+ /// set error text according to the actual error kind
+ void setErrorTextOnKind();
+
+ /// set error text according to the actual error number
+ void setErrorTextOnNumber();
+
+ /// reset error text
+ virtual void resetErrorText();
+ /**
+ The virtual method is redefined in each subclass which supports text parameters.
+ Usually it is invoked in the constructor of the subclass.
+ */
+
+ /// attribute storing the error description text
+ char* errorText;
+
+ /// attribute storing the error kind
+ kind theKind;
+
+ /// attribute storing the number of the error
+ unsigned int errorNo;
+
+ private:
+ static errorInfo *textList;
+};
+
+
+/* Modified by Constantin Jucovschi */
+/* Added the definition of the initTextTable() and freeTextTable()*/
+ void initTextTable();
+ void freeTextTable();
+
+
+
+//@ManMemo: Module: {\bf raslib}
+
+/*@Doc:
+
+ This class represents an array object saying that the
+ result is no interval.
+
+*/
+
+class r_Eno_interval : public r_Error
+{
+ public:
+ /// default constructor
+ r_Eno_interval();
+};
+
+
+
+
+//@ManMemo: Module: {\bf raslib}
+
+/*@Doc:
+
+ This class represents an array object saying that the
+ specified index is not within the bounds.
+
+*/
+
+class r_Eindex_violation : public r_Error
+{
+ public:
+ /// constructor getting lower and upper bound, and the index
+ r_Eindex_violation( r_Range dlow, r_Range dhigh, r_Range dindex );
+
+ protected:
+ /// reset error text
+ virtual void resetErrorText();
+
+ private:
+ /// lower bound
+ r_Range low;
+ /// upper bound
+ r_Range high;
+ /// index which caused the error
+ r_Range index;
+};
+
+
+
+
+//@ManMemo: Module: {\bf raslib}
+
+/*@Doc:
+
+ This class represents an array object saying that the
+ dimensionalies of two objects do not match.
+
+*/
+
+class r_Edim_mismatch : public r_Error
+{
+ public:
+ /// constructor getting two dimensionalities
+ r_Edim_mismatch( r_Dimension pdim1, r_Dimension pdim2 );
+
+ protected:
+ /// reset error text
+ virtual void resetErrorText();
+
+ private:
+ /// first dimensionality
+ r_Dimension dim1;
+ /// second dimensionality
+ r_Dimension dim2;
+};
+
+
+
+//@ManMemo: Module: {\bf raslib}
+
+/*@Doc:
+
+ This class represents an error object saying that an
+ initialization overflow occured. This happens f.e. if the
+ stream input operator is invoked more often than the
+ object has dimensions.
+
+*/
+
+class r_Einit_overflow : public r_Error
+{
+ public:
+ /// default constructor
+ r_Einit_overflow();
+};
+
+
+
+//@ManMemo: Module: {\bf raslib}
+
+/*@Doc:
+
+ This class represents an error object saying that the
+ result is no cell. This happens f.e. if the cast operator
+ for casting to the base type of class \Ref{r_Marray} is invoked
+ on an object which is not 'zero-dimensional'.
+
+*/
+
+class r_Eno_cell : public r_Error
+{
+ public:
+ /// default constructor
+ r_Eno_cell();
+};
+
+
+
+//@ManMemo: Module: {\bf raslib}
+
+/*@Doc:
+
+ The class is used for errors occuring through query execution. In most cases, the position which
+ caused the error can be fixed. This position is specified by line number, column number, and
+ the token which is involved.
+ Additionally, the class is generic concerning the error type. Different error types can be specified
+ by stating the error number.
+
+*/
+
+class r_Equery_execution_failed : public r_Error
+{
+ public:
+ /// default constructor
+ r_Equery_execution_failed( unsigned int errorno, unsigned int lineno, unsigned int columnno, const char* token );
+
+ /// copy constructor
+ r_Equery_execution_failed( const r_Equery_execution_failed &err );
+
+ /// destructor
+ ~r_Equery_execution_failed() throw();
+
+ //@Man: Read methods:
+ //@{
+ ///
+ inline unsigned int get_lineno() const;
+ ///
+ inline unsigned int get_columnno() const;
+ ///
+ inline const char* get_token() const;
+ ///
+ //@}
+
+ protected:
+ /// reset error text
+ virtual void resetErrorText();
+
+ private:
+ /// line number in which the error is caused
+ unsigned int lineNo;
+
+ /// column number which caused the error or is near to the error position
+ unsigned int columnNo;
+
+ /// token which caused the error or is near to the error position
+ char* token;
+};
+
+
+
+//@ManMemo: Module: {\bf raslib}
+
+/*@Doc:
+
+ This class represents an error when the limits reported on the same
+ object (array) by two sources do not match (at least in one end).
+*/
+
+class r_Elimits_mismatch : public r_Error
+{
+ public:
+ /// constructor getting two limits on the same interval
+ r_Elimits_mismatch( r_Range lim1, r_Range lim2 );
+
+ protected:
+ /// reset error text
+ virtual void resetErrorText();
+
+ private:
+ /// first interval
+ r_Range i1;
+ /// second interval
+ r_Range i2;
+};
+
+//@ManMemo: Module: {\bf raslib}
+
+/*@Doc:
+ This class represents an error in the base DBMS. It stores the error
+ number in the base DBMS and the error text of the base DBMS. The
+ interpretation of the error is specific for the base DBMS. The
+ errtxt mechanism of RasDaMan is not used, instead what() returns the
+ error of the base DBMS. Note that the const char* parameters of the
+ constructor are not copied, but the pointers are stored. They are
+ never freed (to enable use of constants).
+*/
+
+class r_Ebase_dbms : public r_Error
+{
+public:
+ /// constructor.
+ r_Ebase_dbms( const long& newErrNum, const char* newErrTxt );
+
+ /// copy constructor
+ r_Ebase_dbms( const r_Ebase_dbms& oldErr );
+
+ /// constructor reading from a char* containing serialised representation.
+ r_Ebase_dbms( kind newTheKind, unsigned long newErrNum, const char* myStr );
+
+ /// destructor
+ ~r_Ebase_dbms() throw();
+
+ /// assignment operator
+ const r_Ebase_dbms& operator=( const r_Ebase_dbms& obj );
+
+ // overloads from r_Error
+ virtual const char* what() const throw();
+ virtual char* serialiseError();
+
+private:
+
+ /// build what text
+ void buildWhat();
+ /// the name of the base DBMS.
+ char* baseDBMS;
+ /// error number of the base DBMS.
+ long dbmsErrNum;
+ /// error text of the base DBMS.
+ char* dbmsErrTxt;
+ /// used as return value for what()
+ char* whatTxt;
+};
+
+class r_Eno_permission : public r_Error
+ {
+ public:
+ r_Eno_permission();
+
+ };
+
+class r_Ecapability_refused : public r_Error
+ {
+ public:
+ r_Ecapability_refused();
+
+ };
+
+class r_Ememory_allocation: public r_Error {
+public:
+ r_Ememory_allocation();
+};
+
+#define MEMMORYALLOCATIONERROR 66
+#define INTERNALDLPARSEERROR 100
+#define NOPOINT 200
+#define RASTYPEUNKNOWN 209
+#define BASETYPENOTSUPPORTED 210
+#define RPCCOMMUNICATIONFAILURE 212
+#define SYSTEM_COLLECTION_NOT_WRITABLE 216
+#define SYSTEM_COLLECTION_HAS_NO_OID 217
+#define CONVERSIONFORMATNOTSUPPORTED 218
+#define TILESIZETOOSMALL 219
+#define STORAGERLAYOUTINCOMPATIBLEWITHGMARRAY 220
+#define DOMAINUNINITIALISED 221
+#define NOTANMARRAYTYPE 222
+#define RCINDEXWITHINCOMPATIBLEMARRAYTYPE 223
+#define TILECONFIGMARRAYINCOMPATIBLE 224
+#define RCINDEXWITHOUTREGULARTILING 225
+#define UDFBODYTOOLARGE 226
+#define POLYGONWRONGPOINTDIMENSION 227
+#define POLYGONWRONGINITSTRING 228
+#define QUERYPARAMETERINVALID 229
+#define ILLEGALARGUMENT 230
+#define MARRAYHASNOBASETYPE 231
+#define INTERVALOPEN 232
+#define INTERVALSWITHDIFFERENTDIMENSION 233
+#define TILINGPARAMETERNOTCORRECT 234
+#define CONNECTIONCLOSED 235
+#define COMPRESSIONFAILED 236
+#define CLIENTCOMMUICATIONFAILURE 237
+#define BASETYPENOTSUPPORTEDBYOPERATION 238
+#define OVERLAYPATTERNTOOSMALL 239
+#define INSERTINTORCINDEX 240
+#define NOTILINGDEFINED 241
+#define UNSATIFIEDMDDCONSTANT 373
+#define DATABASE_EXISTS 708
+#define NO_PERMISSION_FOR_OPERATION 803
+#define CAPABILITY_REFUSED 804
+#define DATABASE_INCONSISTENT 1000
+#define DATABASE_INCOMPATIBLE 1001
+#define ZERO_LENGTH_BLOB 1002
+#define TILE_CONTAINER_NOT_FOUND 1003
+#define INDEX_OF_MDD_IS_NULL 1004
+#define STORAGE_OF_MDD_IS_NULL 1005
+#define UNKNOWN_INDEX_TYPE 1006
+#define ILLEGAL_INDEX_TYPE 1007
+#define COLLTYPE_NULL 1008
+#define MDD_NOT_VALID 1009
+#define MDDTYPE_NULL 1010
+#define ILLEGALSTATEREACHED 1011
+#define COLLECTIONTYPEISNULL 1012
+#define TYPENAMEISTOOLONG 1013
+#define INVALIDOBJECTNAME 1014
+#define DATABASE_OPEN 2000
+#define INVALID_OIDTYPE 2001
+#define STRUCTTYPE_ELEMENT_UNKNOWN 2002
+#define STRUCTTYPE_ELEMENT_OUT_OF_BOUNDS 2003
+#define TRANSIENT_INDEX_USED_AS_PERSISTENT 2004
+#define TILE_MULTIPLE_TIMES_RETRIEVED 2005
+#define TILE_NOT_INSERTED_INTO_INDEX 2006
+#define TRANSIENT_INDEX_OUT_OF_BOUNDS 2007
+#define MDD_EXISTS_MULTIPLE_TIMES 2008
+#define DATA_NOT_INSERTED_COMPLETELY 2009
+#define CONVERSION_RETURNED_WRONG_TYPE 2010
+#define COLLECTIONTYPEHASNOELEMENTTYPE 2011
+#define MARRAYTYPEHASNOELEMENTTYPE 2012
+#define PROPERTYTYPEHASNOELEMENTTYPE 2013
+#define SCALARWASPASSEDNULLTYPE 2014
+#define INDEXNOTFOUNDINPARENT 2015
+#define INDEXEXHAUSTEDAREA 2016
+#define LAYOUTALGORITHMPROBLEM 2017
+#define OBJECTDOESNOTSUPPORTSWAPING 2018
+#define ERRORDURINGSWAPING 2019
+#define BINARYEXPORTNOTSUPPORTEDFOROBJECT 2020
+#define BINARYIMPORTNOTSUPPORTEDFOROBJECT 2021
+#define OPERANDSRESULTTYPESNOMATCH 2022
+#define TRYINGTOINFERHOOKFROMNULLNODE 2023
+#define QTNODETYPEPARENTDOESNOTEXIST 2024
+
+#include "raslib/error.icc"
+
+#endif
diff --git a/raslib/error.icc b/raslib/error.icc
new file mode 100644
index 0000000..20aaa4f
--- /dev/null
+++ b/raslib/error.icc
@@ -0,0 +1,74 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INLINE SOURCE: error.icc
+ *
+ * MODULE: raslib
+ * CLASS: r_Error
+ *
+ * COMMENTS:
+ *
+*/
+
+
+inline r_Error::kind
+r_Error::get_kind() const
+{
+ return theKind;
+}
+
+
+
+inline unsigned int
+r_Error::get_errorno() const
+{
+ return errorNo;
+}
+
+
+
+inline unsigned int
+r_Equery_execution_failed::get_lineno() const
+{
+ return lineNo;
+}
+
+
+
+inline unsigned int
+r_Equery_execution_failed::get_columnno() const
+{
+ return columnNo;
+}
+
+
+
+inline const char*
+r_Equery_execution_failed::get_token() const
+{
+ return token;
+}
+
+
+
+
diff --git a/raslib/flatbasetype.cc b/raslib/flatbasetype.cc
new file mode 100644
index 0000000..13adbd3
--- /dev/null
+++ b/raslib/flatbasetype.cc
@@ -0,0 +1,301 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: flatbasetype.cc
+ *
+ * MODULE: raslib
+ * CLASS: r_Flat_Base_Type
+ *
+ * COMMENTS:
+ *
+*/
+
+#include <iostream>
+#include <stdio.h>
+
+#include "raslib/primitivetype.hh"
+#include "raslib/structuretype.hh"
+#include "raslib/flatbasetype.hh"
+#include "raslib/error.hh"
+#include "raslib/rminit.hh"
+
+
+r_Flat_Base_Type::r_Flat_Base_Type( void )
+{
+ init_shared();
+}
+
+
+r_Flat_Base_Type::r_Flat_Base_Type( const r_Base_Type *type )
+{
+ init_shared();
+ process_type(type);
+}
+
+
+r_Flat_Base_Type::r_Flat_Base_Type( const r_Flat_Base_Type &src )
+{
+ init_shared();
+ copy_flat_type(src);
+}
+
+
+r_Flat_Base_Type::~r_Flat_Base_Type( void )
+{
+ free_type_data();
+}
+
+
+unsigned int r_Flat_Base_Type::get_num_types( void ) const
+{
+ return numPrimTypes;
+}
+
+
+const r_Primitive_Type *r_Flat_Base_Type::type( unsigned int num ) const throw (r_Eindex_violation)
+{
+ if (num < numPrimTypes)
+ {
+ return primTypes[num];
+ }
+ else {
+ RMInit::logOut << "r_Flat_Base_Type::type(" << num << ") index out of bounds (" << numPrimTypes - 1 << ")" << endl;
+ throw r_Eindex_violation(0, numPrimTypes - 1, num);
+ }
+}
+
+
+const r_Primitive_Type *r_Flat_Base_Type::operator[]( unsigned int num ) const throw (r_Eindex_violation)
+{
+ if (num < numPrimTypes)
+ {
+ return primTypes[num];
+ }
+ else {
+ RMInit::logOut << "r_Flat_Base_Type::operator[](" << num << ") index out of bounds (" << numPrimTypes - 1 << ")" << endl;
+ throw r_Eindex_violation(0, numPrimTypes - 1, num);
+ }
+}
+
+
+unsigned int r_Flat_Base_Type::offset( unsigned int num ) const throw (r_Eindex_violation)
+{
+ if (num < numPrimTypes)
+ {
+ return offsets[num];
+ }
+ else {
+ RMInit::logOut << "r_Flat_Base_Type::offset(" << num << ") index out of bounds (" << numPrimTypes - 1 << ")" << endl;
+ throw r_Eindex_violation(0, numPrimTypes - 1, num);
+ }
+}
+
+
+r_Bytes r_Flat_Base_Type::size( void ) const
+{
+ return typeSize;
+}
+
+
+r_Flat_Base_Type &r_Flat_Base_Type::operator=( const r_Flat_Base_Type &src )
+{
+ free_type_data();
+ copy_flat_type(src);
+ return (*this);
+}
+
+
+r_Flat_Base_Type &r_Flat_Base_Type::operator=( const r_Base_Type *type )
+{
+ free_type_data();
+ process_type(type);
+ return (*this);
+}
+
+
+bool r_Flat_Base_Type::operator==( const r_Flat_Base_Type &src ) const
+{
+ if (numPrimTypes == src.numPrimTypes)
+ {
+ unsigned int i;
+ for (i=0; i<numPrimTypes; i++)
+ {
+ if (primTypes[i]->type_id() != src.primTypes[i]->type_id())
+ break;
+ }
+ if (i >= numPrimTypes)
+ return true;
+ }
+ return false;
+}
+
+
+void r_Flat_Base_Type::init_shared( void )
+{
+ typeSize = 0;
+ numPrimTypes = 0;
+ primTypes = NULL;
+ offsets = NULL;
+}
+
+
+void r_Flat_Base_Type::free_type_data( void )
+{
+ if (primTypes != NULL)
+ {
+ for (unsigned int i=0; i<numPrimTypes; i++)
+ delete primTypes[i];
+ delete [] primTypes;
+ primTypes = NULL;
+ }
+
+ if (offsets != NULL)
+ {
+ delete [] offsets;
+ offsets = NULL;
+ }
+ numPrimTypes = 0;
+}
+
+
+void r_Flat_Base_Type::process_type( const r_Base_Type *type )
+{
+ typeSize = type->size();
+
+ if (type->isStructType())
+ {
+ const r_Structure_Type *stype = (const r_Structure_Type*)type;
+ numPrimTypes = parse_structure_type(stype, 0, 0);
+ primTypes = new r_Primitive_Type*[numPrimTypes];
+ offsets = new unsigned int[numPrimTypes];
+ parse_structure_type(stype, 0, 0);
+ }
+ else
+ {
+ numPrimTypes = 1;
+ primTypes = new r_Primitive_Type*[1];
+ offsets = new unsigned int[1];
+ parse_primitive_type((r_Primitive_Type*)(type->clone()), 0, 0);
+ }
+}
+
+
+void r_Flat_Base_Type::copy_flat_type( const r_Flat_Base_Type &src )
+{
+ typeSize = src.typeSize;
+
+ if (src.numPrimTypes == 0)
+ {
+ numPrimTypes = 0;
+ primTypes = NULL;
+ offsets = NULL;
+ }
+ else
+ {
+ numPrimTypes = src.numPrimTypes;
+ primTypes = new r_Primitive_Type*[numPrimTypes];
+ offsets = new unsigned int[numPrimTypes];
+ for (unsigned int i=0; i<numPrimTypes; i++)
+ {
+ primTypes[i] = (r_Primitive_Type*)(src.primTypes[i]->clone());
+ offsets[i] = src.offsets[i];
+ }
+ }
+}
+
+
+void r_Flat_Base_Type::parse_primitive_type( r_Primitive_Type *type, unsigned int num, unsigned int off )
+{
+ if (primTypes == NULL)
+ {
+ delete type;
+ }
+ else
+ {
+ primTypes[num] = type;
+ offsets[num] = off;
+ //cout << "TYPE "; type->print_status(); cout << ", NUM " << num << ", OFF " << off << endl;
+ }
+}
+
+
+unsigned int r_Flat_Base_Type::parse_structure_type( const r_Structure_Type *type, unsigned int num, unsigned int off )
+{
+ r_Structure_Type::attribute_iterator iter(type->defines_attribute_begin());
+ unsigned int numPrim = 0;
+
+ while (iter != type->defines_attribute_end())
+ {
+ r_Type *newType = (*iter).type_of().clone();
+ if (newType->isStructType())
+ {
+ numPrim += parse_structure_type((const r_Structure_Type*)newType, num + numPrim, off + (*iter).offset());
+ delete newType;
+ }
+ else
+ {
+ parse_primitive_type((r_Primitive_Type*)newType, num + numPrim, off + (*iter).offset());
+ numPrim++;
+ }
+ iter++;
+ }
+
+ return numPrim;
+}
+
+
+void r_Flat_Base_Type::print_status( std::ostream &str ) const
+{
+ if (numPrimTypes == 0)
+ {
+ str << "<nn>";
+ }
+ else
+ {
+ str << typeSize << ':';
+ if (numPrimTypes == 1)
+ {
+ primTypes[0]->print_status(str);
+ }
+ else
+ {
+ unsigned int i;
+ str << '{'; primTypes[0]->print_status(str); str << '(' << offsets[0] << ')';
+ for (i=1; i<numPrimTypes; i++)
+ {
+ str << ", ";
+ primTypes[i]->print_status(str);
+ str << '(' << offsets[i] << ')';
+ }
+ str << '}';
+ }
+ }
+}
+
+
+
+std::ostream &operator<<( std::ostream &str, const r_Flat_Base_Type &type )
+{
+ type.print_status(str);
+ return str;
+}
diff --git a/raslib/flatbasetype.hh b/raslib/flatbasetype.hh
new file mode 100644
index 0000000..c92b4b1
--- /dev/null
+++ b/raslib/flatbasetype.hh
@@ -0,0 +1,123 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: flatbasetype.hh
+ *
+ * MODULE: raslib
+ * CLASS: r_Flat_Base_Type
+ *
+ * COMMENTS:
+ *
+*/
+
+#ifndef _FLAT_BASE_TYPE_HH_
+#define _FLAT_BASE_TYPE_HH_
+
+#include <iostream>
+
+#include "raslib/error.hh"
+
+class r_Base_Type;
+class r_Primitive_Type;
+class r_Structure_Type;
+
+//@ManMemo: Module {\bf raslib}
+
+
+/*@Doc:
+ This class can be used to get a more convenient view on a structured
+ base type. It eliminates all hierarchies and gives you the primitive
+ types only which can be iterated over with a normal linear loop. Used
+ in e.g. the compression module. Note that this is not a regular member
+ of the r_Type hierarchy!
+*/
+
+class r_Flat_Base_Type
+{
+ public:
+ /// default constructor, shouldn't be used
+ r_Flat_Base_Type( void );
+ /// constructor receiving the (hierarchical) base type
+ r_Flat_Base_Type( const r_Base_Type *type );
+ /// copy constructor
+ r_Flat_Base_Type( const r_Flat_Base_Type &src );
+ /// destructor
+ ~r_Flat_Base_Type( void );
+
+ /// return number of primitive types
+ unsigned int get_num_types( void ) const;
+ /// return pointer to primitive type num
+ /// index violation is thrown if higher index is requested than available
+ const r_Primitive_Type *type( unsigned int num ) const throw (r_Eindex_violation);
+ /// operator returns pointer to primitive type num or NULL if invalid
+ /// index violation is thrown if higher index is requested than available
+ const r_Primitive_Type *operator[]( unsigned int num ) const throw (r_Eindex_violation);
+ /// return offset of primitive type num
+ /// index violation is thrown if higher index is requested than available
+ unsigned int offset( unsigned int num ) const throw (r_Eindex_violation);
+ /// return size of entire type
+ r_Bytes size( void ) const;
+ /// assignment of another flat type
+ r_Flat_Base_Type &operator=( const r_Flat_Base_Type &src );
+ /// assignment of a base type
+ r_Flat_Base_Type &operator=( const r_Base_Type *type );
+ /// equality
+ bool operator==( const r_Flat_Base_Type &src ) const;
+ /// print status to a stream
+ void print_status( std::ostream &str ) const;
+
+
+ protected:
+ /// shared init code
+ void init_shared( void );
+ /// process a base type
+ void process_type( const r_Base_Type *type );
+ /// copy another flat type
+ void copy_flat_type( const r_Flat_Base_Type &type );
+ /// free type-specific data (destructor, assignment)
+ void free_type_data( void );
+
+ /// parse a structure type and return number of primitive types contained therein
+ unsigned int parse_structure_type( const r_Structure_Type *type, unsigned int number,
+ unsigned int offset );
+ /// parse a primitive type
+ void parse_primitive_type( r_Primitive_Type *type, unsigned int number,
+ unsigned int offset );
+
+ /// the number of primitive types
+ unsigned int numPrimTypes;
+ /// the total size of the entire type
+ r_Bytes typeSize;
+ /// the primitive types
+ r_Primitive_Type **primTypes;
+ /// the corresponding offsets
+ unsigned int *offsets;
+};
+
+
+//@ManMemo: Module {\bf raslib}
+
+//@Doc: write the status of a flat base type to a stream
+extern std::ostream &operator<<( std::ostream &str, const r_Flat_Base_Type &type );
+
+#endif
diff --git a/raslib/itertype.cc b/raslib/itertype.cc
new file mode 100644
index 0000000..c277c24
--- /dev/null
+++ b/raslib/itertype.cc
@@ -0,0 +1,97 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#include "raslib/itertype.hh"
+#include <stdlib.h>
+
+template<class T>
+r_IterType<T>::r_IterType() : lastElem(NULL), myElems(NULL), currPos(0)
+{
+}
+
+template<class T>
+r_IterType<T>::r_IterType(T* newLastElem, T* newElems)
+ : lastElem(newLastElem), myElems(newElems), currPos(newElems)
+{
+}
+
+template<class T>
+r_IterType<T>::r_IterType(T* newLastElem, T* newElems, T* newCurrPos)
+ : lastElem(newLastElem), myElems(newElems), currPos(newCurrPos)
+{
+}
+
+template<class T>
+r_IterType<T>::r_IterType( const r_IterType<T>& iter )
+ : lastElem(iter.lastElem), myElems(iter.myElems), currPos(iter.currPos)
+{
+}
+
+template<class T>
+r_IterType<T>::~r_IterType()
+{
+ // nothing to do, memory management is done by r_Attribute.
+}
+
+template<class T> r_IterType<T>&
+r_IterType<T>::operator=( const r_IterType<T>& iter )
+{
+ lastElem = iter.lastElem;
+ myElems = iter.myElems;
+ currPos = iter.currPos;
+ return *this;
+}
+
+template<class T> bool
+r_IterType<T>::operator==( const r_IterType<T>& otherIter )
+{
+ return currPos == otherIter.currPos;
+}
+
+template<class T> bool
+r_IterType<T>::operator!=( const r_IterType<T>& otherIter )
+{
+ return currPos != otherIter.currPos;
+}
+
+template<class T> r_IterType<T>&
+r_IterType<T>::operator++()
+{
+ currPos++;
+ return *this;
+}
+
+template<class T> r_IterType<T>
+r_IterType<T>::operator++( int )
+{
+ r_IterType<T> result( *this );
+ operator++();
+ return result;
+}
+
+template<class T> T
+r_IterType<T>::operator*()
+{
+ return *currPos;
+}
+
diff --git a/raslib/itertype.hh b/raslib/itertype.hh
new file mode 100644
index 0000000..daabc0f
--- /dev/null
+++ b/raslib/itertype.hh
@@ -0,0 +1,86 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: itertype.hh
+ *
+ * MODULE: raslib
+ * CLASS: r_IterType
+ *
+ * COMMENTS:
+ *
+*/
+
+#ifndef _D_ITER_TYPE_
+#define _D_ITER_TYPE_
+
+//@ManMemo: Module: {\bf raslib}
+
+/*@Doc:
+ This class realizes the iterator used to access
+ single elements of \Ref{r_Structure_Type}.
+*/
+
+template <class T>
+class r_IterType
+{
+public:
+ /// default constructor
+ r_IterType();
+ /// constructor used in r_Structure_Type
+ r_IterType( T* newLastElem, T* newElems );
+ /// constructor used in r_Structure_Type
+ r_IterType( T* newLastElem, T* newElems, T* newCurrPos );
+ /// copy constructor
+ r_IterType( const r_IterType<T>& iter );
+ /// destructor
+ ~r_IterType();
+ /// assignment operator
+ r_IterType<T>& operator=( const r_IterType<T>& iter );
+ /// equal comparison: equal if they point to the same element.
+ bool operator==( const r_IterType<T>& otherIter );
+ /// no equal comparison: not equal if they point to different elements
+ bool operator!=( const r_IterType<T>& otherIter );
+ /// prefix incrementor
+ r_IterType<T>& operator++();
+ /// postfix incrementor
+ r_IterType<T> operator++( int );
+ /// the dereference operator gets the actual element
+ T operator*();
+
+protected:
+ T* lastElem;
+ T* myElems;
+ T* currPos;
+};
+
+#ifdef EARLY_TEMPLATE
+#ifdef __EXECUTABLE__
+#ifdef __VISUALC__
+#include "itertype.cpp"
+#else
+#include "itertype.cc"
+#endif
+#endif
+#endif
+
+#endif
diff --git a/raslib/marraytype.cc b/raslib/marraytype.cc
new file mode 100644
index 0000000..ace70aa
--- /dev/null
+++ b/raslib/marraytype.cc
@@ -0,0 +1,131 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+static const char rcsid[] = "@(#)raslib, r_Marray_Type: $Header: /home/rasdev/CVS-repository/rasdaman/raslib/marraytype.cc,v 1.7 2003/12/27 23:01:21 rasdev Exp $";
+
+#include "raslib/marraytype.hh"
+#include "raslib/basetype.hh"
+#include "raslib/error.hh"
+#include "raslib/rminit.hh"
+
+r_Marray_Type::r_Marray_Type()
+ : r_Type(),
+ baseType(NULL)
+ {
+ }
+
+r_Marray_Type::r_Marray_Type(const r_Base_Type& newBaseType)
+ : r_Type(),
+ baseType((r_Base_Type*)newBaseType.clone())
+ {
+ }
+
+r_Marray_Type::r_Marray_Type(const r_Marray_Type& oldObj) throw (r_Error)
+ : r_Type(oldObj)
+ {
+ if (oldObj.baseType)
+ baseType = (r_Base_Type*)oldObj.baseType->clone();
+ else {
+ RMInit::logOut << "r_Marray_Type::r_Marray_Type( oldObj ) the element type is NULL." << endl;
+ throw r_Error(MARRAYTYPEHASNOELEMENTTYPE);
+ }
+ }
+
+const r_Marray_Type&
+r_Marray_Type::operator=(const r_Marray_Type& oldObj) throw (r_Error)
+ {
+ // Gracefully handle self assignment
+ if (this == &oldObj)
+ return *this;
+
+ r_Type::operator=(oldObj);
+ if (baseType)
+ {
+ delete baseType;
+ baseType = 0;
+ }
+
+ if (oldObj.baseType)
+ baseType = (r_Base_Type*)oldObj.baseType->clone();
+ else {
+ RMInit::logOut << "r_Marray_Type::operator=( oldObj ) the element type is NULL." << endl;
+ throw r_Error(MARRAYTYPEHASNOELEMENTTYPE);
+ }
+
+ return *this;
+ }
+
+bool
+r_Marray_Type::isMarrayType() const
+ {
+ return true;
+ }
+
+const r_Base_Type&
+r_Marray_Type::base_type() const
+ {
+ return *baseType;
+ }
+
+r_Type*
+r_Marray_Type::clone() const
+ {
+ return new r_Marray_Type(*this);
+ }
+
+r_Type::r_Type_Id
+r_Marray_Type::type_id() const
+ {
+ return MARRAYTYPE;
+ }
+
+void
+r_Marray_Type::convertToLittleEndian(char* cells, r_Area noCells) const
+ {
+ }
+
+void
+r_Marray_Type::convertToBigEndian(char* cells, r_Area noCells) const
+ {
+ }
+
+void
+r_Marray_Type::print_status(std::ostream& s) const
+ {
+ s << "marray< ";
+ baseType->print_status(s);
+ s << " >";
+ }
+
+r_Marray_Type::~r_Marray_Type()
+ {
+ if (baseType)
+ delete baseType;
+ }
+
+std::ostream &operator<<( std::ostream &str, const r_Marray_Type &type )
+{
+ type.print_status(str);
+ return str;
+}
+ \ No newline at end of file
diff --git a/raslib/marraytype.hh b/raslib/marraytype.hh
new file mode 100644
index 0000000..9876acf
--- /dev/null
+++ b/raslib/marraytype.hh
@@ -0,0 +1,101 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: marraytype.hh
+ *
+ * MODULE: raslib
+ * CLASS: r_Marray_Type
+ *
+ * COMMENTS:
+ *
+*/
+
+#ifndef _D_MARRAY_TYPE_
+#define _D_MARRAY_TYPE_
+
+#include "raslib/type.hh"
+
+class r_Base_Type;
+class r_Error;
+
+//@ManMemo: Module: {\bf raslib}
+
+/*@Doc:
+ This class represents the marray type in the ODMG conformant
+ representation of the RasDaMan type system.
+*/
+
+
+class r_Marray_Type : public r_Type
+ {
+ public:
+ /// constructor getting basetype
+ r_Marray_Type(const r_Base_Type&);
+
+ /// copy constructor
+ /// if base type is NULL an exception will be raised.
+ /// this is possible
+ r_Marray_Type(const r_Marray_Type&) throw (r_Error);
+
+ /// assignment operator
+ /// if base type is NULL an exception will be raised.
+ /// this is possible
+ const r_Marray_Type& operator=(const r_Marray_Type&) throw (r_Error);
+
+ bool isMarrayType() const;
+
+ /// get base type
+ const r_Base_Type& base_type() const;
+
+ /// clone operation
+ virtual r_Type* clone() const;
+
+ /// retrieve id of the type.
+ virtual r_Type::r_Type_Id type_id() const;
+
+ /// converts array of cells from NT byte order to Unix byte order.
+ virtual void convertToLittleEndian(char* cells, r_Area noCells) const;
+
+ /// converts array of cells from Unix byte order to NT byte order.
+ virtual void convertToBigEndian(char* cells, r_Area noCells) const;
+
+ /// writes state of object to specified stream
+ virtual void print_status(std::ostream& s = std::cout) const;
+
+ /// destructor
+ ~r_Marray_Type();
+
+ protected:
+ /// default constructor
+ /// should be used by noone
+ r_Marray_Type();
+
+ /// base type
+ r_Base_Type* baseType;
+ };
+
+//@Doc: write the status of a marray type to a stream
+extern std::ostream &operator<<( std::ostream &str, const r_Marray_Type &type );
+
+#endif
+
diff --git a/raslib/mddtypes.cc b/raslib/mddtypes.cc
new file mode 100644
index 0000000..4d7ec39
--- /dev/null
+++ b/raslib/mddtypes.cc
@@ -0,0 +1,416 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: mddtypes.cc
+ *
+ * MODULE: raslib
+ * CLASS:
+ *
+ * COMMENTS:
+ *
+*/
+
+
+static const char rcsid[] = "@(#)raslib, mddtypes: $Header: /home/rasdev/CVS-repository/rasdaman/raslib/mddtypes.cc,v 1.26 2005/09/03 20:33:10 rasdev Exp $";
+
+
+
+#ifdef AIX
+ #include <strings.h>
+#else
+ #include <string.h>
+#endif
+
+#include "raslib/mddtypes.hh"
+#include "raslib/rminit.hh"
+
+
+/*
+ * The names of all data formats
+ */
+const char *format_name_array = "Array";
+const char *format_name_tiff = "TIFF";
+const char *format_name_jpeg = "JPEG";
+const char *format_name_hdf = "HDF";
+const char *format_name_cvs = "CVS";
+const char *format_name_png = "PNG";
+const char *format_name_zlib = "ZLib";
+const char *format_name_auto_compression = "AutoCompression";
+const char *format_name_bmp = "BMP";
+const char *format_name_ppm = "PPM";
+const char *format_name_rle = "RLE";
+const char *format_name_wavelet_haar = "HaarWavelet";
+const char *format_name_wavelet_daubechies = "DaubechiesWavelet";
+const char *format_name_sep_zlib = "SepZLib";
+const char *format_name_sep_rle = "SepRLE";
+const char *format_name_wavelet_daub6 = "Daubechies6Wavelet";
+const char *format_name_wavelet_daub8 = "Daubechies8Wavelet";
+const char *format_name_wavelet_daub10 = "Daubechies10Wavelet";
+const char *format_name_wavelet_daub12 = "Daubechies12Wavelet";
+const char *format_name_wavelet_daub14 = "Daubechies14Wavelet";
+const char *format_name_wavelet_daub16 = "Daubechies16Wavelet";
+const char *format_name_wavelet_daub18 = "Daubechies18Wavelet";
+const char *format_name_wavelet_daub20 = "Daubechies20Wavelet";
+const char *format_name_wavelet_least8 = "LeastAsym8Wavelet";
+const char *format_name_wavelet_least10 = "LeastAsym10Wavelet";
+const char *format_name_wavelet_least12 = "LeastAsym12Wavelet";
+const char *format_name_wavelet_least14 = "LeastAsym14Wavelet";
+const char *format_name_wavelet_least16 = "LeastAsym16Wavelet";
+const char *format_name_wavelet_least18 = "LeastAsym18Wavelet";
+const char *format_name_wavelet_least20 = "LeastAsym20Wavelet";
+const char *format_name_wavelet_coiflet6 = "Coiflet6Wavelet";
+const char *format_name_wavelet_coiflet12 = "Coiflet12Wavelet";
+const char *format_name_wavelet_coiflet18 = "Coiflet18Wavelet";
+const char *format_name_wavelet_coiflet24 = "Coiflet24Wavelet";
+const char *format_name_wavelet_coiflet30 = "Coiflet30Wavelet";
+const char *format_name_vff = "VFF";
+const char *format_name_wavelet_qhaar = "QHaarWavelet";
+const char *format_name_tor = "TOR";
+const char *format_name_dem = "DEM";
+const char *format_name_pack_bits = "PACKBITS";
+const char *format_name_ecw = "ECW";
+const char *format_name_tmc = "TMC";
+const char *format_name_ntf = "NTF";
+
+const char *all_data_format_names[r_Data_Format_NUMBER] = {
+ format_name_array,
+ format_name_tiff,
+ format_name_jpeg,
+ format_name_cvs,
+ format_name_hdf,
+ format_name_png,
+ format_name_zlib,
+ format_name_auto_compression,
+ format_name_bmp,
+ format_name_rle,
+ format_name_wavelet_haar,
+ format_name_wavelet_daubechies,
+ format_name_sep_zlib,
+ format_name_sep_rle,
+ format_name_wavelet_daub6,
+ format_name_wavelet_daub8,
+ format_name_wavelet_daub10,
+ format_name_wavelet_daub12,
+ format_name_wavelet_daub14,
+ format_name_wavelet_daub16,
+ format_name_wavelet_daub18,
+ format_name_wavelet_daub20,
+ format_name_wavelet_least8,
+ format_name_wavelet_least10,
+ format_name_wavelet_least12,
+ format_name_wavelet_least14,
+ format_name_wavelet_least16,
+ format_name_wavelet_least18,
+ format_name_wavelet_least20,
+ format_name_wavelet_coiflet6,
+ format_name_wavelet_coiflet12,
+ format_name_wavelet_coiflet18,
+ format_name_wavelet_coiflet24,
+ format_name_wavelet_coiflet30,
+ format_name_vff,
+ format_name_wavelet_qhaar,
+ format_name_ppm,
+ format_name_tor,
+ format_name_dem,
+ format_name_pack_bits,
+ format_name_ecw,
+ format_name_tmc,
+ format_name_ntf
+};
+
+
+const char *get_name_from_data_format( r_Data_Format fmt )
+{
+ unsigned int idx = (unsigned int)fmt;
+
+ if (idx >= (unsigned int)r_Data_Format_NUMBER)
+ return "???";
+
+ return all_data_format_names[idx];
+}
+
+
+r_Data_Format get_data_format_from_name( const char *name )
+{
+ if(!name) {
+ RMInit::logOut << "get_data_format_from_name(" << (name?name: "NULL") << ")" << endl;
+ return r_Data_Format_NUMBER;
+ }
+
+ unsigned int i=r_Data_Format_NUMBER;
+
+ for (i=0; i<(unsigned int)r_Data_Format_NUMBER; i++)
+ {
+ if (strcasecmp(name, all_data_format_names[i]) == 0)
+ break;
+ }
+ return (r_Data_Format)i;
+}
+
+
+
+std::ostream& operator<<( std::ostream& s, r_Data_Format& d )
+{
+ s << (const r_Data_Format)d;
+ return s;
+}
+
+std::ostream& operator<<( std::ostream& s, const r_Data_Format& d )
+{
+ s << get_name_from_data_format(d);
+
+ return s;
+}
+
+const char* scale_function_name_subsampling = "subsampling";
+const char* scale_function_name_bitaggregation = "bitaggregation";
+
+const char* all_scale_function_names[r_Scale_Function_NUMBER] = {
+ scale_function_name_subsampling,
+ scale_function_name_bitaggregation
+ };
+
+const char *get_name_from_scale_function(r_Scale_Function fmt)
+{
+ unsigned int idx = (unsigned int)fmt;
+
+ if (idx >= (unsigned int)r_Scale_Function_NUMBER)
+ return "???";
+
+ return all_scale_function_names[idx];
+}
+
+
+r_Scale_Function get_scale_function_from_name(const char *name)
+{
+ if(!name) {
+ RMInit::logOut << "get_scale_function_from_name(" << (name?name: "NULL") << ")" << endl;
+ return r_Scale_Function_NUMBER;
+ }
+
+ unsigned int i=r_Scale_Function_NUMBER;
+
+ for (i=0; i<(unsigned int)r_Scale_Function_NUMBER; i++)
+ {
+ if (strcasecmp(name, all_scale_function_names[i]) == 0)
+ break;
+ }
+ return (r_Scale_Function)i;
+}
+
+std::ostream& operator<<( std::ostream& s, const r_Scale_Function& d )
+{
+ s << get_name_from_scale_function(d);
+
+ return s;
+}
+
+/*
+ * The names of all index type
+ */
+
+const char *index_name_auto="auto";
+const char *index_name_directory="dir";
+const char *index_name_regdirectory="rdir";
+const char *index_name_rplustree="nrp";
+const char *index_name_regrplustree="rnrp";
+const char *index_name_tilecontainer="tc";
+const char *index_name_regcomputed="rc";
+
+const char *all_index_type_names[r_Index_Type_NUMBER] = {
+ index_name_auto,
+ index_name_directory,
+ index_name_regdirectory,
+ index_name_rplustree,
+ index_name_regrplustree,
+ index_name_tilecontainer,
+ index_name_regcomputed
+ };
+
+const char *get_name_from_index_type( r_Index_Type it )
+{
+ unsigned int idx = (unsigned int)it;
+
+ if (idx >= (unsigned int)r_Index_Type_NUMBER)
+ return "UNKNOWN r_Index_Type";
+
+ if (idx == (unsigned int)r_Invalid_Index)
+ return "r_Invalid_Index";
+
+ return all_index_type_names[idx];
+}
+
+r_Index_Type get_index_type_from_name( const char *name )
+{
+ if(!name) {
+ RMInit::logOut << "get_index_type_from_name(" << (name?name: "NULL") << ")" << endl;
+ return r_Index_Type_NUMBER;
+ }
+
+ unsigned int i=r_Index_Type_NUMBER;
+
+ for (i=0; i<(unsigned int)r_Index_Type_NUMBER; i++)
+ {
+ if (strcasecmp(name, all_index_type_names[i]) == 0)
+ break;
+ }
+ return (r_Index_Type)i;
+}
+
+
+std::ostream& operator<<( std::ostream& s, r_Index_Type d )
+{
+ switch( d )
+ {
+ case r_Invalid_Index:
+ s << "r_Invalid_Index";
+ break;
+ case r_Auto_Index:
+ s << "r_Auto_Index";
+ break;
+ case r_Directory_Index:
+ s << "r_Directory_Index";
+ break;
+ case r_Reg_Directory_Index:
+ s << "r_Reg_Directory_Index";
+ break;
+ case r_RPlus_Tree_Index:
+ s << "r_RPlus_Tree_Index";
+ break;
+ case r_Reg_RPlus_Tree_Index:
+ s << "r_Reg_RPlus_Tree_Index";
+ break;
+ case r_Tile_Container_Index:
+ s << "r_Tile_Container_Index";
+ break;
+ case r_Reg_Computed_Index:
+ s << "r_Reg_Computed_Index";
+ break;
+ default:
+ s << "UNKNOWN r_Index_Type " << d;
+ break;
+ }
+
+ return s;
+}
+
+/*
+ * The names of all tiling schemes
+ */
+
+const char *tiling_name_notiling = "NoTiling";
+const char *tiling_name_regulartiling = "RegularTiling";
+const char *tiling_name_statisticaltiling = "StatisticalTiling";
+const char *tiling_name_interesttiling = "InterestTiling";
+const char *tiling_name_alignedtiling = "AlignedTiling";
+const char *tiling_name_directionaltiling = "DirectionalTiling";
+const char *tiling_name_sizetiling = "SizeTiling";
+
+const char *all_tiling_scheme_names[r_Tiling_Scheme_NUMBER] = {
+ tiling_name_notiling,
+ tiling_name_regulartiling,
+ tiling_name_statisticaltiling,
+ tiling_name_interesttiling,
+ tiling_name_alignedtiling,
+ tiling_name_directionaltiling,
+ tiling_name_sizetiling
+ };
+
+const char *get_name_from_tiling_scheme( r_Tiling_Scheme ts )
+{
+ unsigned int idx = (unsigned int)ts;
+
+ if (idx >= (unsigned int)r_Tiling_Scheme_NUMBER)
+ return "UNKNOWN r_Tiling_Scheme";
+
+ return all_tiling_scheme_names[idx];
+}
+
+r_Tiling_Scheme get_tiling_scheme_from_name( const char *name )
+{
+ if(!name) {
+ RMInit::logOut << "get_tiling_scheme_from_name(" << (name?name: "NULL") << ")" << endl;
+ return r_Tiling_Scheme_NUMBER;
+ }
+
+ unsigned int i=r_Tiling_Scheme_NUMBER;
+
+ for (i=0; i<(unsigned int)r_Tiling_Scheme_NUMBER; i++)
+ {
+ if (strcasecmp(name, all_tiling_scheme_names[i]) == 0)
+ break;
+ }
+ return (r_Tiling_Scheme)i;
+}
+
+std::ostream& operator<<(std::ostream& s, r_Tiling_Scheme d)
+{
+ s << get_name_from_tiling_scheme(d);
+ return s;
+}
+
+std::ostream& operator<<( std::ostream& s, const r_Clustering_Scheme d )
+{
+ switch( d )
+ {
+ case r_Insertion_Order_Clustering:
+ s << "r_Insertion_Order_Clustering";
+ break;
+ case r_Coords_Order_Clustering:
+ s << "r_Coords_Order_Clustering";
+ break;
+ case r_Index_Cluster_Clustering:
+ s << "r_Index_Cluster_Clustering";
+ break;
+ case r_Based_Cluster_Stat_Clustering:
+ s << "r_Based_Cluster_Stat_Clustering";
+ break;
+ default:
+ s << "UNKNOWN r_Clustering_Scheme " << d;
+ break;
+ }
+
+ return s;
+}
+
+
+#ifdef __VISUALC__
+#include <ctype.h>
+int strcasecmp(const char *s1, const char *s2)
+{
+ const char *b, *d;
+
+ b = s1; d = s2;
+ while ((*b != '\0') && (*d != '\0'))
+ {
+ if (tolower((unsigned int)*b) != tolower((unsigned int)*d))
+ break;
+ b++; d++;
+ }
+ if ((*b == '\0') && (*d == '\0'))
+ return 0;
+ if (tolower((unsigned int)*b) < tolower((unsigned int)*d))
+ return -1;
+ return 1;
+}
+#endif
diff --git a/raslib/mddtypes.hh b/raslib/mddtypes.hh
new file mode 100644
index 0000000..f8fb310
--- /dev/null
+++ b/raslib/mddtypes.hh
@@ -0,0 +1,491 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: mddtypes.hh
+ *
+ * MODULE: raslib
+ *
+ * PURPOSE:
+ * The file cotains MDD type definitions.
+ *
+ * COMMENTS:
+ * - always append new data formats to remain compatible with earlier compiled code
+ *
+*/
+
+#ifndef _D_MDDTYPES_
+#define _D_MDDTYPES_
+
+
+#ifdef __VISUALC__
+#include <strstrea.h>
+#else
+#include <sstream>
+#endif
+
+//typedef unsigned int uint32;
+//typedef int int32;
+
+//@Man: r_Bytes
+//@Type: typedef
+//@Args: as unsigned int
+//@Memo: Module: {\bf raslib}.
+
+typedef unsigned int r_Bytes;
+
+/**
+ {\tt typedef unsigned int r_Bytes;}
+
+ The typedef \Ref{r_Bytes} is used as type for the number of bytes in an tile or mdd or type.
+*/
+
+//@Man: r_Ptr
+//@Type: typedef
+//@Args: as unsigned long
+//@Memo: Module: {\bf raslib}.
+
+typedef unsigned long r_Ptr;
+
+/**
+ {\tt typedef unsigned long r_Ptr;}
+
+ The typedef \Ref{r_Ptr} was introduced to handle correctly convertions from
+ pointers to integer variables on 64bit architectures.
+*/
+
+
+
+//@Man: r_Area
+//@Type: typedef
+//@Args: as unsigned int
+//@Memo: Module: {\bf raslib}.
+
+typedef unsigned int r_Area;
+
+/**
+ {\tt typedef unsigned int r_Area;}
+
+ The typedef \Ref{r_Area} is used as type for the number of cells in an mdd object or tile.
+*/
+
+
+
+//@Man: r_Range
+//@Type: typedef
+//@Args: as int
+//@Memo: Module: {\bf raslib}.
+
+typedef int r_Range;
+
+/**
+ {\tt typedef int r_Range;}
+
+ The typedef \Ref{r_Range} is used as type for the point set
+ of one dimension of a spatial domain. This means that lower
+ and upper bounds of \Ref{r_Sinterval}, the projection value,
+ and the cooridnate values of \Ref{r_Point} are of this type.
+*/
+
+
+
+//@Man: r_Dimension
+//@Type: typedef
+//@Args: as unsigned int
+//@Memo: Module: {\bf raslib}.
+
+typedef unsigned int r_Dimension;
+
+/**
+ {\tt typedef unsigned int r_Dimension;}
+
+ This is used as type for the number of dimensions in
+ \Ref{r_Point} and \Ref{r_Minterval}.
+*/
+
+
+//@Man: r_Data_Format
+//@Type: enum
+//@Args:
+//@Memo: Module: {\bf raslib}.
+
+enum r_Data_Format
+{
+ r_Array,
+ r_TIFF,
+ r_JPEG,
+ r_HDF,
+ r_CSV,
+ r_PNG,
+ r_ZLib,
+ r_Auto_Compression,
+ r_BMP,
+ r_RLE,
+ r_Wavelet_Haar,
+ r_Wavelet_Daubechies, // = Daubechies 4 tap
+ r_Sep_ZLib,
+ r_Sep_RLE,
+ r_Wavelet_Daub6,
+ r_Wavelet_Daub8,
+ r_Wavelet_Daub10,
+ r_Wavelet_Daub12,
+ r_Wavelet_Daub14,
+ r_Wavelet_Daub16,
+ r_Wavelet_Daub18,
+ r_Wavelet_Daub20,
+ r_Wavelet_Least8,
+ r_Wavelet_Least10,
+ r_Wavelet_Least12,
+ r_Wavelet_Least14,
+ r_Wavelet_Least16,
+ r_Wavelet_Least18,
+ r_Wavelet_Least20,
+ r_Wavelet_Coiflet6,
+ r_Wavelet_Coiflet12,
+ r_Wavelet_Coiflet18,
+ r_Wavelet_Coiflet24,
+ r_Wavelet_Coiflet30,
+ r_VFF,
+ r_Wavelet_QHaar,
+ r_PPM,
+ r_TOR,
+ r_DEM,
+ r_Pack_Bits,
+ r_ECW,
+ r_TMC,
+ r_NTF,
+ r_Data_Format_NUMBER
+};
+
+/**
+ {\tt enum r_Data_Format}
+
+ \begin{tabular}{lll}
+ {\ttr_Array} && no compression, row-major memory representation\\
+
+ {\ttr_TIFF} && TIFF format (see \Ref{r_Conv_TIFF})\\
+ {\ttr_JPEG} && JPEG format (see \Ref{r_Conv_JPEG})\\
+ {\ttr_HDF} && HDF format (see \Ref{r_Conv_HDF})\\
+ {\ttr_PNG} && PNG format (see \Ref{r_Conv_PNG})\\
+ {\ttr_BMP} && BMP format (see \Ref{r_Conv_BMP})\\
+ {\ttr_VFF} && VFF format (see \Ref{r_Conv_VFF})\\
+ {\ttr_PPM} && PPM format (see \Ref{r_Conv_PPM})\\
+ {\ttr_TOR} && TOR format (see \Ref{r_Conv_TOR})\\
+ {\ttr_DEM} && DEM format (see \Ref{r_Conv_DEM})\\
+ {\ttr_ECW} && ECW format (see \Ref{r_Conv_ECW})\\
+ {\ttr_NTF} && NITF format (see \Ref{r_Conv_NTF})\\
+
+ {\ttr_Auto_Compression} && automatic compression\\
+ {\ttr_ZLib} && ZLIB compresion (see \Ref{r_Tile_Comp_RLE})\\
+ {\ttr_Pack_Bits} && Packbits rle compresion (see \Ref{r_Tile_Comp_Packbits})\\
+ {\ttr RLE} && RLE compression (see \Ref{r_Tile_Comp_RLE})\\
+ {\ttr_Wavelet_Haar} && Haar Wavelet compression (see \Ref{r_Haar_Wavelet_Compression})\\
+ {\ttr_Wavelet_Daubechies} && Daubechies 4-tap Wavelet compression (see \Ref{r_Daubechies_Wavelet_Compression})\\
+ {\ttr_Sep_ZLib} && ZLIB compression, compress base types separately (see \Ref{r_Tile_Separate_ZLIB})\\
+ {\ttr_Sep_RLE} && RLE compression, compress base types separately (see \Ref{r_Tile_Separate_RLE})\\
+ {\ttr_Wavelet_Daub<n>} && Daubechies n-tap Wavelet compression, n=6,8,...,18,20 (see \Ref{r_Ortho_Wavelet_Factory})\\
+ {\ttr_Wavelet_Least<n>} && Least asymmetric n-tap Wavelet comp., n=8,10,...,18,20 (see \Ref{r_Ortho_Wavelet_Factory})\\
+ {\ttr_Wavelet_Coiflet<n>} && Coiflet n-tap Wavelet compression, n=6,12,18,24,30 (see \Ref{r_Ortho_Wavelet_Factory})\\
+ {\ttr_Wavelet_QHaar} && Lossy Haar Wavelet compression (see \Ref{r_Haar_QWavelet_Compression})\\
+
+ \end{tabular}
+*/
+
+//@ManMemo: Module: {\bf raslib}
+/**
+ The names of all data types, to avoid redundant storage and inconsistencies.
+ The variable name convention is the prefix format_name_ followed by the name
+ of the data format in lower case without the r_ prefix, i.e. for r_Wavelet_Haar
+ format_name_wavelet_haar.
+ In addition there's an array of names all_data_format_names where the data format
+ can be used as index to get the name.
+*/
+
+extern const char *format_name_array;
+extern const char *format_name_tiff;
+extern const char *format_name_jpeg;
+extern const char *format_name_hdf;
+extern const char *format_name_png;
+extern const char *format_name_zlib;
+extern const char *format_name_auto_compression;
+extern const char *format_name_bmp;
+extern const char *format_name_ppm;
+extern const char *format_name_rle;
+extern const char *format_name_wavelet_haar;
+extern const char *format_name_wavelet_daubechies;
+extern const char *format_name_sep_zlib;
+extern const char *format_name_sep_rle;
+extern const char *format_name_wavelet_daub6;
+extern const char *format_name_wavelet_daub8;
+extern const char *format_name_wavelet_daub10;
+extern const char *format_name_wavelet_daub12;
+extern const char *format_name_wavelet_daub14;
+extern const char *format_name_wavelet_daub16;
+extern const char *format_name_wavelet_daub18;
+extern const char *format_name_wavelet_daub20;
+extern const char *format_name_wavelet_least8;
+extern const char *format_name_wavelet_least10;
+extern const char *format_name_wavelet_least12;
+extern const char *format_name_wavelet_least14;
+extern const char *format_name_wavelet_least16;
+extern const char *format_name_wavelet_least18;
+extern const char *format_name_wavelet_least20;
+extern const char *format_name_wavelet_coiflet6;
+extern const char *format_name_wavelet_coiflet12;
+extern const char *format_name_wavelet_coiflet18;
+extern const char *format_name_wavelet_coiflet24;
+extern const char *format_name_wavelet_coiflet30;
+extern const char *format_name_vff;
+extern const char *format_name_tor;
+extern const char *format_name_dem;
+extern const char *format_name_pack_bits;
+extern const char *format_name_wavelet_qhaar;
+extern const char *format_name_tmc;
+extern const char *format_name_ntf;
+
+extern const char *all_data_format_names[r_Data_Format_NUMBER];
+
+//@ManMemo: Module: {\bf raslib}
+/**
+ Get a data format name for a data format
+*/
+const char *get_name_from_data_format( r_Data_Format fmt );
+
+//@ManMemo: Module: {\bf raslib}
+/**
+ Get a data format for a data format name
+*/
+r_Data_Format get_data_format_from_name ( const char *name );
+
+
+//@ManMemo: Module: {\bf raslib}
+/**
+ Output stream operator for objects of type {\tt const} \Ref{r_Data_Format}.
+*/
+extern std::ostream& operator<<( std::ostream& s, const r_Data_Format& d );
+
+
+
+//@ManMemo: Module: {\bf raslib}
+/**
+ Output stream operator for objects of type \Ref{r_Data_Format}.
+*/
+extern std::ostream& operator<<( std::ostream& s, r_Data_Format& d );
+
+//@Man: r_Scale_Function
+//@Type: enum
+//@Args:
+//@Memo: Module: {\bf raslib}.
+
+enum r_Scale_Function {
+ r_SubSampling,
+ r_BitAggregation,
+ r_Scale_Function_NUMBER
+ };
+
+extern const char *scale_function_name_subsampling;
+extern const char *scale_function_name_bitaggregation;
+
+extern const char *all_scale_function_names[r_Scale_Function_NUMBER];
+
+//@ManMemo: Module: {\bf raslib}
+/**
+ Get a scale function name for a scale function
+*/
+const char *get_name_from_scale_function(r_Scale_Function func);
+
+//@ManMemo: Module: {\bf raslib}
+/**
+ Get a scale function from a scale function name
+*/
+r_Scale_Function get_scale_function_from_name(const char *name);
+
+
+//@ManMemo: Module: {\bf raslib}
+/**
+ Output stream operator for objects of type {\tt const} \Ref{r_Scale_Function}.
+*/
+extern std::ostream& operator<<( std::ostream& s, const r_Scale_Function& d );
+
+
+//@Man: r_Index_Type
+//@Type: enum
+//@Args:
+//@Memo: Module: {\bf raslib}.
+
+enum r_Index_Type
+ {
+ r_Invalid_Index = -1,
+ r_Auto_Index = 0,
+ r_Directory_Index = 1,
+ r_Reg_Directory_Index = 2,
+ r_RPlus_Tree_Index = 3,
+ r_Reg_RPlus_Tree_Index = 4,
+ r_Tile_Container_Index = 5,
+ r_Reg_Computed_Index = 6,
+ r_Index_Type_NUMBER = 7
+ };
+
+extern std::ostream& operator<<(std::ostream& in, r_Index_Type type);
+
+//@ManMemo: Module: {\bf raslib}
+/**
+ The names of all index type, to avoid redundant storage and inconsistencies.
+ The variable name convention is the prefix index_name_ followed by the name
+ of the index type in lower case without the r_ prefix, i.e. for r_Auto_Index
+ index_name_auto.
+ In addition there's an array of names all_index_type_names where the index type
+ can be used as index to get the name.
+*/
+
+extern const char *index_name_auto;
+extern const char *index_name_directory;
+extern const char *index_name_regdirectory;
+extern const char *index_name_rplustree;
+extern const char *index_name_regrplustree;
+extern const char *index_name_tilecontainer;
+extern const char *index_name_regcomputed;
+
+extern const char *all_index_type_names[r_Index_Type_NUMBER];
+
+//@ManMemo: Module: {\bf raslib}
+/**
+ Get a index type name for a index type
+*/
+const char *get_name_from_index_type( r_Index_Type it );
+
+//@ManMemo: Module: {\bf raslib}
+/**
+ Get a index type for a index type name
+*/
+r_Index_Type get_index_type_from_name ( const char *name );
+
+//@Man: r_Tiling_Scheme
+//@Type: enum
+//@Args:
+//@Memo: Module: {\bf raslib}.
+
+enum r_Tiling_Scheme
+ {
+ r_NoTiling = 0,
+ r_RegularTiling = 1,
+ r_StatisticalTiling = 2,
+ r_InterestTiling = 3,
+ r_AlignedTiling = 4,
+ r_DirectionalTiling = 5,
+ r_SizeTiling = 6,
+ r_Tiling_Scheme_NUMBER = 7
+ };
+/**
+ Tiling of the object:
+
+ \begin{tabular}{lll}
+ NoTiling && no tiling is done unless the object is too big;
+ in that case, tiling is done along the first direction only;
+ for objects which are to be accessed always as a whole \\
+ {\bf Aligned} && aligned tiling, needs tileConfig \\
+ LowVariationAreas && according to areas of low cell value variation \\
+ BasedTilesStat && based on statistics regarding access to this MDD object
+ \end{tabular}
+
+ In addition, it is possible to have a tiling according to areas of
+ interest, {\bf AreasInterest} mode.
+ The {\tt AreasInterest} mode is indicated by a non - null value of the
+ {\tt areasInterestPath} attribute.
+ This mode is not an alternative mode in {\tt TilingScheme} because it is
+ compatible with the other modes. For instance, an aligned tiling may be
+ adopted outside the areas of interest.
+ */
+
+//@ManMemo: Module: {\bf raslib}
+/**
+ The names of all tiling schems, to avoid redundant storage and inconsistencies.
+ The variable name convention is the prefix tiling_name_ followed by the name
+ of the tiling scheme in lower case without the r_ prefix, i.e. for r_SizeTiling
+ tiling_name_sizetiling.
+ In addition there's an array of names all_tiling_scheme_names where the tile scheme
+ can be used as index to get the name.
+*/
+
+extern const char *tiling_name_notiling;
+extern const char *tiling_name_regulartiling;
+extern const char *tiling_name_statisticaltiling;
+extern const char *tiling_name_interesttiling;
+extern const char *tiling_name_alignedtiling;
+extern const char *tiling_name_directionaltiling;
+extern const char *tiling_name_sizetiling;
+
+extern const char *all_tiling_scheme_names[r_Tiling_Scheme_NUMBER];
+
+//@ManMemo: Module: {\bf raslib}
+/**
+ Get a tiling scheme name for a tiling scheme
+*/
+const char *get_name_from_tiling_scheme( r_Tiling_Scheme ts );
+
+//@ManMemo: Module: {\bf raslib}
+/**
+ Get a tiling scheme for a tiling scheme name
+*/
+r_Tiling_Scheme get_tiling_scheme_from_name ( const char *name );
+
+//@ManMemo: Module: {\bf raslib}
+/**
+ Output stream operator for objects of type {\tt const} \Ref{r_Tiling_Scheme}.
+*/
+extern std::ostream& operator<<(std::ostream& in, r_Tiling_Scheme type);
+
+//@Man: r_Clustering_Scheme
+//@Type: enum
+//@Args:
+//@Memo: Module: {\bf raslib}.
+enum r_Clustering_Scheme
+ {
+ r_Insertion_Order_Clustering = 1,
+ r_Coords_Order_Clustering = 2,
+ r_Index_Cluster_Clustering = 3,
+ r_Based_Cluster_Stat_Clustering = 4
+ };
+ /**
+ Clustering of the Tiles according to:
+
+ \begin{tabular}{lll}
+ {\bf InsertionOrder } && the order of insertion of the tiles \\
+ CoordsOrder && the coordinates of the tiles \\
+ IndexCluster && the index structure \\
+ BasedClusterStat && statistics about access to the object
+ \end{tabular}
+
+ There is the additional {\bf PathCluster} mode, where clustering is
+ done according to a path of access to areas of interest.
+ The {\tt PathCluster} mode is indicated by setting the {\tt pathCluster}
+ attribute and a non - null value of the {\tt areasInterest}.
+ This mode is not an alternative mode in {\tt ClusteringScheme} because
+ it is compatible with the other modes.
+ */
+extern std::ostream& operator<<(std::ostream& in, r_Clustering_Scheme type);
+
+#ifdef __VISUALC__
+extern int strcasecmp( const char *str1, const char *str2 );
+#endif
+
+#endif
diff --git a/raslib/memblockvec.cc b/raslib/memblockvec.cc
new file mode 100644
index 0000000..9cffc51
--- /dev/null
+++ b/raslib/memblockvec.cc
@@ -0,0 +1,107 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: memblockvec.cc
+ *
+ * MODULE: raslib
+ * CLASS: r_Memory_Block_Vector
+ *
+ * COMMENTS:
+ *
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "raslib/memblockvec.hh"
+
+
+r_Memory_Block_Vector::r_Memory_Block_Vector( r_Bytes bsize, unsigned int gran )
+{
+ blockSize = bsize;
+ granularity = gran;
+
+ numBlocks = 0; maxBlocks = granularity;
+ blocks = new void*[granularity];
+}
+
+r_Memory_Block_Vector::~r_Memory_Block_Vector( void )
+{
+ free_data();
+ delete [] blocks;
+}
+
+void* r_Memory_Block_Vector::operator[]( unsigned int idx ) const
+{
+ if (idx >= numBlocks)
+ return NULL;
+
+ return blocks[idx];
+}
+
+void* r_Memory_Block_Vector::add( void )
+{
+ if (numBlocks >= maxBlocks)
+ {
+ void** newBlocks = new void*[maxBlocks + granularity];
+ memcpy(newBlocks, blocks, numBlocks * sizeof(void*));
+ delete [] blocks; blocks = newBlocks;
+ maxBlocks += granularity;
+ }
+ blocks[numBlocks++] = (void*)(new char[blockSize]);
+ return blocks[numBlocks-1];
+}
+
+void r_Memory_Block_Vector::free_data( void )
+{
+ unsigned int i;
+
+ for (i=0; i<numBlocks; i++)
+ {
+ delete [] blocks[i];
+ blocks[i] = NULL;
+ }
+ numBlocks = 0;
+}
+
+r_Bytes r_Memory_Block_Vector::get_size( r_Bytes lastFill ) const
+{
+ return (numBlocks == 0) ? 0 : (numBlocks-1)*blockSize + lastFill;
+}
+
+void r_Memory_Block_Vector::copy_data( void* dest, r_Bytes lastFill ) const
+{
+ unsigned int i;
+ void* destPtr = dest;
+
+ if (numBlocks == 0) return;
+
+ for (i=0; i<numBlocks-1; i++)
+ {
+ memcpy(destPtr, blocks[i], blockSize);
+ destPtr = (void*)(((char*)destPtr) + blockSize);
+ }
+ memcpy(destPtr, blocks[numBlocks-1], lastFill);
+}
diff --git a/raslib/memblockvec.hh b/raslib/memblockvec.hh
new file mode 100644
index 0000000..c026614
--- /dev/null
+++ b/raslib/memblockvec.hh
@@ -0,0 +1,84 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: memblockvec.hh
+ *
+ * MODULE: raslib
+ * CLASS: r_Memory_Block_Vector
+ *
+ * COMMENTS:
+ *
+*/
+
+#ifndef _MEMORY_BLOCK_VECTOR_H_
+#define _MEMORY_BLOCK_VECTOR_H_
+
+#include "raslib/mddtypes.hh"
+
+
+//@ManMemo: Module {\bf raslib}
+
+/*@Doc:
+ Auxiliary class, realizes a set of memory blocks of equal size that can
+ be extended to any size. Used by some children of r_LinCompStream.
+*/
+
+class r_Memory_Block_Vector
+{
+public:
+ /// constructor, receiving the size of each memory block and the granularity
+ /// for extending the number of blocks.
+ r_Memory_Block_Vector( r_Bytes bsize=4096, unsigned int gran=8 );
+ /// destructor
+ ~r_Memory_Block_Vector( void );
+ /// return number of blocks
+ inline unsigned int get_number( void ) const {return numBlocks;}
+ /// return block size
+ inline r_Bytes get_block_size( void ) const {return blockSize;}
+ /// return granularity
+ inline unsigned int get_granularity( void ) const {return granularity;}
+ /// get a block
+ void* operator[]( unsigned int idx ) const;
+ /// add a new block and return a pointer to it
+ void* add( void );
+ /// free all blocks (but not the vector, call the destructor for that)
+ void free_data( void );
+ /// get number of bytes stored. lastFill is the number of bytes used
+ /// in the last block
+ r_Bytes get_size( r_Bytes lastFill ) const;
+ /// Copy the data stored in blocks into linear memory. lastFill is the
+ /// number of bytes in the last block
+ void copy_data( void* dest, r_Bytes lastFill ) const;
+
+protected:
+ /// the array of memory block pointers
+ void** blocks;
+ unsigned int numBlocks;
+ unsigned int maxBlocks;
+ /// the size of the blocks
+ r_Bytes blockSize;
+ /// the granularity
+ unsigned int granularity;
+};
+
+#endif
diff --git a/raslib/metaobject.cc b/raslib/metaobject.cc
new file mode 100644
index 0000000..844aa48
--- /dev/null
+++ b/raslib/metaobject.cc
@@ -0,0 +1,81 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#include "mymalloc/mymalloc.h"
+static const char rcsid[] = "@(#)raslib, r_Meta_Object: $Header: /home/rasdev/CVS-repository/rasdaman/raslib/metaobject.cc,v 1.7 2003/12/27 23:01:21 rasdev Exp $";
+
+#include "raslib/metaobject.hh"
+
+#include <stdlib.h> // OSF1 has the definition for malloc here
+#include <malloc.h>
+#include <string.h>
+
+r_Meta_Object::r_Meta_Object()
+ : typeName(NULL)
+{
+}
+
+r_Meta_Object::r_Meta_Object( const char* newTypeName )
+{
+ typeName = (char*)mymalloc(strlen(newTypeName) + 1);
+ strcpy(typeName, newTypeName);
+}
+
+r_Meta_Object::r_Meta_Object( const r_Meta_Object& oldObj )
+ : typeName(NULL)
+{
+ if( oldObj.typeName )
+ {
+ typeName = (char*)mymalloc(strlen(oldObj.typeName) + 1);
+ strcpy(typeName, oldObj.typeName);
+ }
+}
+
+const r_Meta_Object&
+r_Meta_Object::operator=( const r_Meta_Object& oldObj )
+{
+ // Gracefully handle self assignment
+ if (this == &oldObj) return *this;
+
+ free(typeName);
+ typeName = NULL;
+ if( oldObj.typeName )
+ {
+ typeName = (char*)mymalloc(strlen(oldObj.typeName) + 1);
+ strcpy(typeName, oldObj.typeName);
+ }
+
+ return *this;
+}
+
+r_Meta_Object::~r_Meta_Object()
+{
+ if(typeName)
+ free(typeName);
+}
+
+const char*
+r_Meta_Object::name() const
+{
+ return typeName;
+}
diff --git a/raslib/metaobject.hh b/raslib/metaobject.hh
new file mode 100644
index 0000000..634ea98
--- /dev/null
+++ b/raslib/metaobject.hh
@@ -0,0 +1,77 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: metaobject.hh
+ *
+ * MODULE: raslib
+ * CLASS: r_Meta_Object
+ *
+ * COMMENTS:
+ *
+*/
+
+#ifndef _D_META_OBJECT_
+#define _D_META_OBJECT_
+
+#include <iostream>
+
+#ifdef __VISUALC__
+#include <strstrea.h>
+#else
+#include <sstream> // for istrstream
+#endif
+
+#include "raslib/error.hh"
+
+//@ManMemo: Module: {\bf raslib}
+
+/*@Doc:
+ This class the superclass for all classes in the ODMG conformant
+ representation of the RasDaMan type system.
+*/
+
+class r_Meta_Object
+{
+public:
+ /// default constructor.
+ r_Meta_Object();
+ /// constructor getting name of type.
+ r_Meta_Object( const char* newTypeName );
+ /// copy constructor
+ r_Meta_Object( const r_Meta_Object& oldObj );
+ /// assignment operator.
+ const r_Meta_Object& operator=( const r_Meta_Object& oldObj );
+ /// destructor.
+ virtual ~r_Meta_Object();
+
+ /// retrieve name of the type.
+ const char* name() const;
+
+ /// writes state of object to specified stream
+ virtual void print_status( std::ostream& s = std::cout ) const = 0;
+
+protected:
+ char* typeName;
+};
+
+#endif
diff --git a/raslib/minterval.cc b/raslib/minterval.cc
new file mode 100644
index 0000000..311c8e9
--- /dev/null
+++ b/raslib/minterval.cc
@@ -0,0 +1,1055 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: Minterval.cc
+ *
+ * MODULE: raslib
+ * CLASS: r_Minterval
+ *
+ * COMMENTS:
+ *
+*/
+
+static const char rcsid[] = "@(#)raslib, r_Minterval: $Header: /home/rasdev/CVS-repository/rasdaman/raslib/minterval.cc,v 1.54 2005/09/03 20:31:22 rasdev Exp $";
+
+using namespace std;
+
+using namespace std;
+
+#include "raslib/rmdebug.hh"
+#include "raslib/minterval.hh"
+#include "raslib/odmgtypes.hh"
+#include "raslib/dlist.hh"
+#include "mymalloc/mymalloc.h"
+
+#include <math.h>
+#include <string.h>
+#include <stdlib.h>
+#ifdef __VISUALC__
+#include <strstrea.h>
+#else
+#include <strstream>
+#endif
+
+r_Minterval::r_Minterval(r_Dimension dim)
+ : dimensionality(dim),
+ streamInitCnt(0),
+ intervals(NULL)
+ {
+ RMDBGONCE(20, RMDebug::module_raslib, "r_Minterval", "r_Minterval(r_Dimension), this=" << (long)this)
+ intervals = new r_Sinterval[ dimensionality ];
+ }
+
+void
+r_Minterval::constructorinit(char* mIntStr) throw(r_Eno_interval)
+{
+
+ if(!mIntStr)
+ {
+ RMInit::logOut << "r_Minterval::r_Minterval(" << (mIntStr?mIntStr:"NULL") << ")" << endl;
+ throw r_Eno_interval();
+ }
+
+ char* p = NULL; // for counting ','
+ // for parsing the string
+ std::istrstream str(mIntStr, strlen(mIntStr) + 1);
+ char c = 0;
+ r_Sinterval sint;
+ r_Range b = 0; // bound for Sinterval
+
+ if (intervals != NULL)
+ {
+ delete intervals;
+ intervals = NULL;
+ }
+
+ // calculate dimensionality
+ p = mIntStr;
+ while(p = strchr(++p, ','))
+ dimensionality++;
+
+ // allocate space for intervals
+ intervals = new r_Sinterval[ dimensionality ];
+
+ // check for left bracket '['
+ str >> c;
+ if (c != '[')
+ {
+ // error, should perhaps raise exception
+ dimensionality = 0;
+ delete[] intervals;
+ intervals = NULL;
+ RMInit::logOut << "r_Minterval::r_Minterval(" << mIntStr << "): the string doesn't have pattern [a:b,c:d]" << endl;
+ throw r_Eno_interval();
+ }
+
+ // for each dimension: get sinterval
+ for (r_Dimension i=0; i<dimensionality; i++)
+ {
+ // --- evaluate lower bound ------------------------------
+ str >> c; // test read first char
+ if (c == '*') // low bound is '*'
+ sint.set_low('*');
+ else // low bound must be a number
+ {
+ str.putback(c);
+ str >> b; // read type r_Range
+ if ( ! str ) // check for proper int recognition
+ {
+ RMInit::logOut << "minterval constructor failed on dim " << i << ", lo" << endl << flush;
+ throw r_Eno_interval();
+ }
+ sint.set_low(b); // store lo bound
+ }
+
+ // --- check for ':' between lower and upper bound -------
+ str >> c;
+ if (c != ':')
+ {
+ // error
+ dimensionality = 0;
+ delete[] intervals;
+ intervals = NULL;
+ RMInit::logOut << "r_Minterval::r_Minterval(" << mIntStr << "): missing ':', string not like [a:b,c:d]" << endl;
+ throw r_Eno_interval();
+ }
+
+ // --- evaluate upper bound ------------------------------
+ str >> c;
+ if (c == '*')
+ sint.set_high('*');
+ else
+ {
+ str.putback(c);
+ str >> b;
+ if ( ! str )
+ {
+ RMInit::logOut << "minterval constructor failed on dim " << i << ", hi" << endl << flush;
+ throw r_Eno_interval();
+ }
+ sint.set_high(b);
+ }
+ str >> c;
+
+ // --- next dimension needs either ',' separator or ']' end tag
+ if (i != dimensionality-1 && c != ',' || i == dimensionality-1 && c != ']')
+ {
+ dimensionality = 0;
+ delete[] intervals;
+ intervals = NULL;
+ RMInit::logOut << "r_Minterval::r_Minterval(" << mIntStr << "): missing ',' or ']', string not like [a:b,c:d]" << endl;
+ throw r_Eno_interval();
+ }
+
+ intervals[i] = sint;
+
+ sint.set_interval('*','*');
+ }
+}
+
+r_Minterval::r_Minterval(char* mIntStr) throw(r_Eno_interval)
+ : dimensionality(1),
+ streamInitCnt(0),
+ intervals(NULL)
+ {
+ RMDBGONCE(20, RMDebug::module_raslib, "r_Minterval", "r_Minterval(char*), this=" << (long)this)
+ constructorinit(mIntStr);
+ }
+
+r_Minterval::r_Minterval(const char* mIntStr) throw(r_Eno_interval)
+ : dimensionality(1),
+ streamInitCnt(0),
+ intervals(NULL)
+ {
+ RMDBGONCE(20, RMDebug::module_raslib, "r_Minterval", "r_Minterval(char*), this=" << (long)this)
+ char* temp = (char*)mymalloc((1 + strlen(mIntStr)) * sizeof(char));
+ strcpy(temp, mIntStr);
+
+ try
+ {
+ constructorinit(temp);
+ free(temp);
+ }
+ catch(r_Error err)
+ {
+ free(temp);
+ throw;
+ }
+
+ temp = 0;
+ }
+
+r_Minterval&
+r_Minterval::operator<<(const r_Sinterval& newInterval) throw(r_Einit_overflow)
+ {
+ if (streamInitCnt >= dimensionality)
+ {
+ RMInit::logOut << "r_Minterval::operator<<(" << newInterval << ") domain is already full" << endl;
+ throw r_Einit_overflow();
+ }
+
+ intervals[streamInitCnt++] = newInterval;
+ return *this;
+ }
+
+r_Minterval&
+r_Minterval::operator<<(r_Range p) throw(r_Einit_overflow)
+ {
+ if (streamInitCnt >= dimensionality)
+ {
+ RMInit::logOut << "r_Minterval::operator<<(" << p << ") domain is already full" << endl;
+ throw r_Einit_overflow();
+ }
+
+ intervals[streamInitCnt++] = r_Sinterval(p, p);
+ return *this;
+ }
+
+r_Minterval::r_Minterval()
+ : dimensionality(0),
+ streamInitCnt(0),
+ intervals(NULL)
+ {
+ RMDBGONCE(20, RMDebug::module_raslib, "r_Minterval", "r_Minterval(), this=" << this)
+ }
+
+//cannot use the initialise function because it will crash
+r_Minterval::r_Minterval(const r_Minterval& minterval)
+ : dimensionality(0),
+ streamInitCnt(0),
+ intervals(NULL)
+ {
+ RMDBGONCE(20, RMDebug::module_raslib, "r_Minterval", "r_Minterval(const r_Minterval&), this=" << this)
+ dimensionality = minterval.dimensionality;
+ streamInitCnt = minterval.streamInitCnt;
+ if(minterval.intervals)
+ {
+ intervals = new r_Sinterval[dimensionality];
+ for (r_Dimension i=0; i<dimensionality; i++)
+ intervals[i] = minterval[i];
+ }
+ }
+
+r_Minterval::~r_Minterval()
+ {
+ RMDBGONCE(20, RMDebug::module_raslib, "r_Minterval", "~r_Minterval(), this=" << this)
+ r_deactivate();
+ }
+
+void
+r_Minterval::r_deactivate()
+ {
+ if (intervals)
+ {
+ delete[] intervals;
+ intervals = NULL;
+ }
+ }
+
+bool
+r_Minterval::intersects_with(const r_Minterval& minterval) const
+ {
+ bool result = true;
+
+ if (dimensionality != minterval.dimension())
+ {
+ RMInit::logOut << "r_Minterval::intersects_with(" << minterval << ") do not share the same dimension" << endl;
+ return false;
+ }
+
+ // none of the interval pairs are allowed to be disjoint
+ for (r_Dimension i=0; i<dimensionality && result; i++)
+ {
+ if (!intervals[i].intersects_with(minterval[i]))
+ {
+ result = false;
+ break;
+ }
+ }
+
+ return result;
+ }
+
+#ifndef OPT_INLINE
+r_Sinterval
+r_Minterval::operator[](r_Dimension i) const
+ {
+ if (i < 0 || i >= dimensionality)
+ {
+ RMInit::logOut << "r_Minterval:::operator[](" << i << ") const index out of bounds (" << dimensionality << ")" << endl;
+ throw r_Eindex_violation(0, dimensionality-1, i);
+ }
+
+ return intervals[i];
+ }
+
+r_Sinterval&
+r_Minterval::operator[](r_Dimension i)
+ {
+ if (i < 0 || i >= dimensionality)
+ {
+ RMInit::logOut << "r_Minterval:::operator[](" << i << ") index out of bounds (" << dimensionality << ")" << endl;
+ throw r_Eindex_violation(0, dimensionality-1, i);
+ }
+
+ return intervals[i];
+ }
+#endif
+
+const r_Minterval&
+r_Minterval::operator=(const r_Minterval& minterval)
+ {
+ if (this != &minterval)
+ {
+ if (intervals && dimensionality != minterval.dimension())
+ {
+ delete[] intervals;
+ intervals = NULL;
+ }
+
+ dimensionality = minterval.dimension();
+ streamInitCnt = minterval.streamInitCnt;
+
+ if(minterval.intervals)
+ {
+ if (!intervals)
+ intervals = new r_Sinterval[ dimensionality ];
+
+ for (r_Dimension i=0; i<dimensionality; i++)
+ intervals[i] = minterval[i];
+ }
+ }
+
+ return *this;
+ }
+
+bool
+r_Minterval::operator==(const r_Minterval& mint) const
+ {
+ bool returnValue = false;
+
+ if (dimensionality == mint.dimensionality)
+ {
+ returnValue = true;
+
+ for (r_Dimension i=0; i<dimensionality && returnValue ; i++)
+ {
+ if (intervals[i] != mint[i])
+ {
+ returnValue = false;
+ break;
+ }
+ }
+ }
+
+ return returnValue;
+ }
+
+bool
+r_Minterval::operator!=(const r_Minterval& mint) const
+ {
+ return !operator==(mint);
+ }
+
+r_Point
+r_Minterval::get_origin() const throw(r_Error)
+ {
+ r_Point pt(dimensionality);
+
+ if(!is_origin_fixed())
+ {
+ RMInit::logOut << "r_Minterval::get_origin() " << *this << " is opened" << endl;
+ throw r_Error(INTERVALOPEN);
+ }
+
+ for (r_Dimension i=0; i<dimensionality; i++)
+ pt[i]=intervals[i].low();
+
+ return pt;
+ }
+
+r_Point
+r_Minterval::get_high() const throw(r_Error)
+ {
+ r_Point pt(dimensionality);
+
+ if(!is_high_fixed())
+ {
+ RMInit::logOut << "r_Minterval::get_high() " << *this << " is opened" << endl;
+ throw r_Error(INTERVALOPEN);
+ }
+
+ for (r_Dimension i=0; i<dimensionality; i++)
+ pt[i] = intervals[i].high();
+
+ return pt;
+ }
+
+r_Point
+r_Minterval::get_extent() const throw(r_Error)
+ {
+ r_Point pt(dimensionality);
+
+ if(!is_origin_fixed() || !is_high_fixed())
+ {
+ RMInit::logOut << "r_Minterval::get_high() " << *this << " is opened" << endl;
+ throw r_Error(INTERVALOPEN);
+ }
+
+ for (r_Dimension i=0; i<dimensionality; i++)
+ pt[i] = intervals[i].get_extent();
+
+ return pt;
+ }
+
+r_Minterval&
+r_Minterval::reverse_translate(const r_Point& t) throw(r_Error, r_Edim_mismatch, r_Eno_interval)
+ {
+ if (dimensionality != t.dimension())
+ {
+ RMInit::logOut << "r_Minterval::reverse_translate(" << t << ") dimensions (" << dimensionality << ") do not match" << endl;
+ throw(r_Edim_mismatch( dimensionality, t.dimension()));
+ }
+
+ if (!is_origin_fixed() || !is_high_fixed())
+ {
+ RMInit::logOut << "r_Minterval::reverse_translate(" << t << ") " << *this << " is opened" << endl;
+ throw r_Error(INTERVALOPEN);
+ }
+
+ for (r_Dimension i=0; i<dimensionality; i++)
+ intervals[i].set_interval(intervals[i].low() - t[i], intervals[i].high() - t[i]);
+
+ return *this;
+ }
+
+r_Minterval&
+r_Minterval::translate(const r_Point& t) throw(r_Error, r_Edim_mismatch, r_Eno_interval)
+ {
+ if (dimensionality != t.dimension())
+ {
+ RMInit::logOut << "r_Minterval::translate(" << t << ") dimensions (" << dimensionality << ") do not match" << endl;
+ throw(r_Edim_mismatch( dimensionality, t.dimension()));
+ }
+
+ if (!is_origin_fixed() || !is_high_fixed())
+ {
+ RMInit::logOut << "r_Minterval::translate(" << t << ") " << *this << " is opened" << endl;
+ throw r_Error(INTERVALOPEN);
+ }
+
+ for (r_Dimension i=0; i<dimensionality; i++)
+ intervals[i].set_interval(intervals[i].low() + t[i], intervals[i].high() + t[i]);
+
+ return *this;
+ }
+
+r_Minterval
+r_Minterval::create_reverse_translation(const r_Point& t) const throw(r_Error, r_Edim_mismatch, r_Eno_interval)
+ {
+ r_Minterval result(*this);
+
+ result.reverse_translate(t);
+
+ return result;
+ }
+
+r_Minterval
+r_Minterval::create_translation(const r_Point& t) const throw(r_Error, r_Edim_mismatch, r_Eno_interval)
+ {
+ r_Minterval result(*this);
+
+ result.translate(t);
+
+ return result;
+ }
+
+r_Minterval&
+r_Minterval::scale(const double& d) throw(r_Eno_interval)
+ {
+ vector<double> scaleVec;
+
+ //create scale vector
+ for (r_Dimension i = 0; i < dimensionality; i++){
+ scaleVec.push_back(d);
+ }
+
+ scale(scaleVec);
+
+ return *this;
+ }
+
+r_Minterval&
+r_Minterval::scale(const vector<double>& scaleVec) throw(r_Eno_interval)
+ {
+ double high = 0., low = 0.;
+
+ RMDBGENTER(1, RMDebug::module_raslib, "r_Minterval", "scale(" << scaleVec << ") before " << *this );
+
+ // if the size of scale vector is different from dimensionality, undefined behaviour
+ if(scaleVec.size() != dimensionality) {
+ RMDBGEXIT(1, RMDebug::module_raslib, "r_Minterval", "scale(" << scaleVec << ") scaleVec has wrong size " << *this );
+ throw r_Edim_mismatch(scaleVec.size(), dimensionality);
+ }
+
+ for (r_Dimension i = 0; i < dimensionality; i++)
+ {
+ // do explicit rounding, because the cast down in set_interval doesn't do the good rounding for negative values -- PB 2005-jun-19
+ low = floor( scaleVec[i] * intervals[i].low() );
+
+ //correction by 1e-6 to avoid the strage bug when high was a
+ //integer value and floor return value-1(e.g. query 47.ql)
+ high = floor(scaleVec[i] * (intervals[i].high() +1) + 0.000001) - 1;
+
+// FIXME BUG it was not forseen to be able to scale [a:a] with a very low factor f
+// to [af, af]
+// if((r_Range)high != (r_Range)low)
+// high--; // substract 1 which was added to high()
+
+ intervals[i].set_interval((r_Range)low, (r_Range)high);
+ }
+
+ RMDBGEXIT(1, RMDebug::module_raslib, "r_Minterval", "scale(" << scaleVec << ") after " << *this );
+
+ return *this;
+ }
+
+r_Minterval
+r_Minterval::create_scale(const double& d) const throw(r_Eno_interval)
+ {
+ r_Minterval result(*this);
+
+ result.scale(d);
+
+ return result;
+ }
+
+
+r_Minterval
+r_Minterval::create_scale(const vector<double>& scaleVec) const throw(r_Eno_interval)
+ {
+ r_Minterval result(*this);
+
+ result.scale(scaleVec);
+
+ return result;
+ }
+
+
+
+r_Minterval&
+r_Minterval::union_of(const r_Minterval& mint1, const r_Minterval& mint2) throw(r_Edim_mismatch, r_Eno_interval)
+ {
+ if (mint1.dimension() != mint2.dimension())
+ {
+ RMInit::logOut << "r_Minterval::union_of(" << mint1 << ", " << mint2 << ") dimensions do not match" << endl;
+ throw(r_Edim_mismatch( mint1.dimension(), mint2.dimension()));
+ }
+
+ // cleanup + initializing of this
+ if (dimensionality != mint1.dimension())
+ {
+ if (intervals)
+ delete[] intervals;
+ dimensionality = mint1.dimension();
+ streamInitCnt = dimensionality;
+ intervals = new r_Sinterval[ dimensionality ];
+ }
+ for (r_Dimension i=0; i<dimensionality; i++)
+ intervals[i].union_of(mint1[i], mint2[i]);
+
+ return *this;
+ }
+
+r_Minterval&
+r_Minterval::union_with(const r_Minterval& mint) throw(r_Edim_mismatch, r_Eno_interval)
+ {
+ if (dimensionality != mint.dimension())
+ {
+ RMInit::logOut << "r_Minterval::union_with(" << mint << ") dimensions (" << dimensionality << ") do not match" << endl;
+ throw(r_Edim_mismatch( dimensionality, mint.dimension()));
+ }
+
+ for (r_Dimension i=0; i<dimensionality; i++)
+ intervals[i].union_with(mint[i]);
+
+ return *this;
+ }
+
+r_Minterval&
+r_Minterval::operator+=(const r_Minterval& mint) throw(r_Edim_mismatch, r_Eno_interval)
+ {
+ return union_with(mint);
+ }
+
+r_Minterval
+r_Minterval::create_union(const r_Minterval& mint) const throw(r_Edim_mismatch, r_Eno_interval)
+ {
+ if (dimensionality != mint.dimension())
+ {
+ RMInit::logOut << "r_Minterval::create_union(" << mint << ") dimensions (" << dimensionality << ") do not match" << endl;
+ throw(r_Edim_mismatch( dimensionality, mint.dimension()));
+ }
+
+ r_Minterval result(dimensionality);
+
+ for (r_Dimension i=0; i<dimensionality; i++)
+ result << intervals[i].create_union(mint[i]);
+
+ return result;
+ }
+
+r_Minterval
+r_Minterval::operator+(const r_Minterval& mint) const throw(r_Edim_mismatch, r_Eno_interval)
+ {
+ return create_union(mint);
+ }
+
+r_Minterval&
+r_Minterval::difference_of(const r_Minterval& mint1, const r_Minterval& mint2) throw(r_Edim_mismatch, r_Eno_interval)
+ {
+ if (mint1.dimension() != mint2.dimension())
+ {
+ RMInit::logOut << "r_Minterval::difference_of(" << mint1 << ", " << mint2 << ") dimensions do not match" << endl;
+ throw(r_Edim_mismatch( mint1.dimension(), mint2.dimension()));
+ }
+
+ if (dimensionality != mint1.dimension())
+ {
+ // cleanup + initializing of this
+ if (intervals)
+ delete[] intervals;
+
+ dimensionality = mint1.dimension();
+ streamInitCnt = dimensionality;
+ intervals = new r_Sinterval[ dimensionality ];
+ }
+
+ for (r_Dimension i=0; i<dimensionality; i++)
+ intervals[i].difference_of(mint1[i], mint2[i]);
+
+ return *this;
+ }
+
+r_Minterval&
+r_Minterval::difference_with(const r_Minterval& mint) throw(r_Edim_mismatch, r_Eno_interval)
+ {
+ if (dimensionality != mint.dimension())
+ {
+ RMInit::logOut << "r_Minterval::difference_with(" << mint << ") dimensions (" << dimensionality << ") do not match" << endl;
+ throw(r_Edim_mismatch( dimensionality, mint.dimension()));
+ }
+
+ for (r_Dimension i=0; i<dimensionality; i++)
+ intervals[i].difference_with(mint[i]);
+
+ return *this;
+ }
+
+r_Minterval&
+r_Minterval::operator-=(const r_Minterval& mint) throw(r_Edim_mismatch, r_Eno_interval)
+ {
+ return difference_with(mint);
+ }
+
+r_Minterval
+r_Minterval::create_difference(const r_Minterval& mint) const throw(r_Edim_mismatch, r_Eno_interval)
+ {
+ if (dimensionality != mint.dimension())
+ {
+ RMInit::logOut << "r_Minterval::create_difference(" << mint << ") dimensions (" << dimensionality << ") do not match" << endl;
+ throw(r_Edim_mismatch( dimensionality, mint.dimension()));
+ }
+
+ r_Minterval result(dimensionality);
+
+ for (r_Dimension i=0; i<dimensionality; i++)
+ result << intervals[i].create_difference(mint[i]);
+
+ return result;
+ }
+
+r_Minterval
+r_Minterval::operator-(const r_Minterval& mint) const throw(r_Edim_mismatch, r_Eno_interval)
+ {
+ return create_difference(mint);
+ }
+
+r_Minterval&
+r_Minterval::intersection_of(const r_Minterval& mint1, const r_Minterval& mint2) throw(r_Edim_mismatch, r_Eno_interval)
+ {
+ if (mint1.dimension() != mint2.dimension())
+ {
+ RMInit::logOut << "r_Minterval::intersection_of(" << mint1 << ", " << mint2 << ") dimensions do not match" << endl;
+ throw(r_Edim_mismatch( mint1.dimension(), mint2.dimension()));
+ }
+ if (dimensionality != mint1.dimension())
+ {
+ // cleanup + initializing of this
+ if (intervals)
+ delete[] intervals;
+
+ dimensionality = mint1.dimension();
+ streamInitCnt = dimensionality;
+ intervals = new r_Sinterval[ dimensionality ];
+ }
+
+ for (r_Dimension i=0; i<dimensionality; i++)
+ intervals[i].intersection_of(mint1[i], mint2[i]);
+ return *this;
+ }
+
+r_Minterval&
+r_Minterval::intersection_with(const r_Minterval& mint) throw(r_Edim_mismatch, r_Eno_interval)
+ {
+ if (dimensionality != mint.dimension())
+ {
+ RMInit::logOut << "r_Minterval::intersection_with(" << mint << ") dimensions (" << dimensionality << ") do not match" << endl;
+ throw(r_Edim_mismatch( dimensionality, mint.dimension()));
+ }
+
+ for (r_Dimension i=0; i<dimensionality; i++)
+ intervals[i].intersection_with(mint[i]);
+
+ return *this;
+ }
+
+r_Minterval&
+r_Minterval::operator*=(const r_Minterval& mint) throw(r_Edim_mismatch, r_Eno_interval)
+ {
+ return intersection_with(mint);
+ }
+
+r_Minterval
+r_Minterval::create_intersection(const r_Minterval& mint) const throw(r_Edim_mismatch, r_Eno_interval)
+ {
+ if (dimensionality != mint.dimension())
+ {
+ RMInit::logOut << "r_Minterval::create_intersection(" << mint << ") dimensions (" << dimensionality << ") do not match" << endl;
+ throw(r_Edim_mismatch( dimensionality, mint.dimension()));
+ }
+
+ r_Minterval result(dimensionality);
+
+ for (r_Dimension i=0; i<dimensionality; i++)
+ result << intervals[i].create_intersection(mint[i]);
+
+ return result;
+ }
+
+r_Minterval
+r_Minterval::operator*(const r_Minterval& mint) const throw(r_Edim_mismatch, r_Eno_interval)
+ {
+ return create_intersection(mint);
+ }
+
+r_Minterval&
+r_Minterval::closure_of(const r_Minterval& mint1, const r_Minterval& mint2) throw(r_Edim_mismatch, r_Eno_interval)
+ {
+ if (mint1.dimension() != mint2.dimension())
+ {
+ RMInit::logOut << "r_Minterval::closure_of(" << mint1 << ", " << mint2 << ") dimensions do not match" << endl;
+ throw(r_Edim_mismatch( mint1.dimension(), mint2.dimension()));
+ }
+ if (mint1.dimension() != dimensionality)
+ {
+ // cleanup + initializing of this
+ if (intervals)
+ delete[] intervals;
+
+ dimensionality = mint1.dimension();
+ streamInitCnt = dimensionality;
+ intervals = new r_Sinterval[ dimensionality ];
+ }
+
+ for (r_Dimension i=0; i<dimensionality; i++)
+ intervals[i].closure_of(mint1[i], mint2[i]);
+
+ return *this;
+ }
+
+r_Minterval&
+r_Minterval::closure_with(const r_Minterval& mint) throw(r_Edim_mismatch, r_Eno_interval)
+ {
+ if (dimensionality != mint.dimension())
+ {
+ RMInit::logOut << "r_Minterval::closure_with(" << mint << ") dimensions (" << dimensionality << ") do not match" << endl;
+ throw(r_Edim_mismatch( dimensionality, mint.dimension()));
+ }
+
+ for (r_Dimension i=0; i<dimensionality; i++)
+ intervals[i].closure_with(mint[i]);
+
+ return *this;
+ }
+
+r_Minterval
+r_Minterval::create_closure(const r_Minterval& mint) const throw(r_Edim_mismatch, r_Eno_interval)
+ {
+ if (dimensionality != mint.dimension())
+ {
+ RMInit::logOut << "r_Minterval::create_closure(" << mint << ") dimensions (" << dimensionality << ") do not match" << endl;
+ throw(r_Edim_mismatch( dimensionality, mint.dimension()));
+ }
+
+ r_Minterval result(dimensionality);
+
+ for (r_Dimension i=0; i<dimensionality; i++)
+ result << intervals[i].create_closure(mint[i]);
+
+ return result;
+ }
+
+void
+r_Minterval::print_status(std::ostream& s) const
+ {
+ s << "[";
+
+ if (dimensionality > 0)
+ {
+ for (r_Dimension i=0; i<dimensionality-1; i++)
+ s << intervals[i] << ",";
+
+ s << intervals[dimensionality-1];
+ }
+
+ s << "]";
+ }
+
+char*
+r_Minterval::get_string_representation() const
+ {
+ unsigned int bufferSize = dimensionality*25+3; // should be enough
+
+ // allocate buffer and initialize string stream
+ char* buffer = new char[bufferSize];
+ std::ostrstream domainStream(buffer, bufferSize);
+
+ // write into string stream
+ domainStream << (*this) << std::ends;
+
+ // allocate memory taking the final string
+ char* returnString = strdup(buffer);
+
+ // delete buffer
+ delete[] buffer;
+
+ return returnString;
+ }
+
+r_Area
+r_Minterval::cell_count() const throw(r_Error)
+ {
+ r_Area cellCount = 1;
+ r_Point ptExt=get_extent();
+
+ for (r_Dimension i=0; i<dimensionality; i++)
+ cellCount *= ptExt[i];
+
+ return cellCount;
+ }
+
+// offset in cells for linear access of the data element referred by point in the data memory area
+// Lower dimensions are higher valued which means that the highest dimension is stored in a sequence.
+r_Area
+r_Minterval::cell_offset(const r_Point& point) const throw(r_Eindex_violation, r_Error)
+ {
+ r_Dimension i = 0;
+ r_Area offset = 0;
+ r_Point ptExt;
+
+ if (dimensionality != point.dimension())
+ {
+ RMInit::logOut << "r_Minterval::cell_offset(" << point << ") dimension of domain (" << dimensionality << ") does not match dimension of argument (" << point.dimension() << ")" << endl;
+ throw r_Edim_mismatch(point.dimension(), dimensionality);
+ }
+
+ ptExt=get_extent();
+
+ // calculate offset
+ for (i = 0; i < dimensionality - 1; i++)
+ {
+ if (point[i] < intervals[i].low() || point[i] > intervals[i].high())
+ {
+ RMInit::logOut << "r_Minterval::cell_offset(" << point << ") point is out of range (" << *this << ")" << endl;
+ throw(r_Eindex_violation(point[i], intervals[i].low(), intervals[i].high()));
+ }
+
+ offset = (offset + point[i] - intervals[i].low()) * ptExt[i+1];
+ }
+
+ // now i = dimensionality - 1
+ if (point[i] < intervals[i].low() || point[i] > intervals[i].high())
+ {
+ RMInit::logOut << "r_Minterval::cell_offset(" << point << ") point is out of range (" << *this << ")" << endl;
+ throw(r_Eindex_violation(point[i], intervals[i].low(), intervals[i].high()));
+ }
+ offset += point[i] - intervals[i].low();
+
+ return offset;
+ }
+
+// Arguments.....: linear offset
+// Return value..: point object which corresponds to the linear offset of the argument
+// Description...: The method calucaltes the spatial domain coordinates as a point out of an offset specification. Lower dimensions are higher valued which means that the highest dimension is stored in a sequence.
+r_Point
+r_Minterval::cell_point(r_Area offset) const throw(r_Eno_cell, r_Error)
+ {
+ r_Dimension i;
+ unsigned int factor=1;
+ r_Point pt(dimensionality), ptExt;
+
+ if (offset >= cell_count())
+ {
+ RMInit::logOut << "r_Minterval::cell_point(" << offset << ") offset is out of range (" << cell_count() << ")" << endl;
+ throw r_Eno_cell();
+ }
+
+ ptExt=get_extent();
+
+ for (i=0; i<dimensionality; i++)
+ factor *= ptExt[i];
+
+ for (i=0; i<dimensionality; i++)
+ {
+ factor /= ptExt[i];
+ pt[i] = intervals[i].low() + (offset - (offset%factor))/factor;
+ offset %= factor;
+ }
+
+ return pt;
+ }
+
+void
+r_Minterval::delete_dimension(r_Dimension dim) throw(r_Eindex_violation)
+ {
+ if (dim < 0 || dim >= dimensionality)
+ {
+ RMInit::logOut << "r_Minterval::delete_dimension(" << dim << ") dimension is out of range (" << dimensionality << ")" << endl;
+ throw r_Eindex_violation(0, dimensionality-1, dim);
+ }
+
+ dimensionality -= 1;
+ streamInitCnt = dimensionality;
+ r_Sinterval* newIntervals = new r_Sinterval[ dimensionality ];
+
+ for (r_Dimension i=0, j=0; i<dimensionality; i++, j++)
+ {
+ if (i==dim) j++;
+ newIntervals[i] = intervals[j];
+ }
+
+ delete[] intervals;
+
+ intervals = newIntervals;
+ }
+
+r_Bytes
+r_Minterval::get_storage_size() const
+ {
+ r_Bytes sz = sizeof(r_Sinterval*) + 2 * sizeof(r_Dimension);
+
+ if (dimensionality > 0)
+ sz += dimensionality * intervals->get_storage_size();
+
+ return sz;
+ }
+
+bool
+r_Minterval::is_mergeable(const r_Minterval& b) const
+ {
+ bool is_merg = true;
+ // An alias to this object
+ const r_Minterval& a = *this;
+
+ // The blocks must have the same dimensionality to be mergeable
+ if (a.dimensionality != b.dimensionality)
+ {
+ is_merg = false;
+ }
+ else {
+
+ // Count the number of adjacent frontiers
+ int ones_differences = 0;
+
+ // For all dimensions
+ for (r_Dimension i=0; i<dimensionality; i++)
+ {
+ // Diferente origins
+ if (a[i].low() != b[i].low())
+ {
+ if ((a[i].low() == b[i].high()+1) || (b[i].low() == a[i].high()+1))
+ // If borders are adjacent
+ {
+ // Update counter
+ ++ones_differences;
+ }
+ else {
+ // Else non-mergeable blocks
+ is_merg = false;
+ break;
+ }
+ }
+ else {
+ // Check ending
+ if (a[i].high() != b[i].high())
+ {
+ is_merg = false;
+ // Not the same, can't be
+ break;
+ // mergeable
+ }
+ }
+ }
+
+ // Only one adjacent borded
+ if (is_merg && (ones_differences!=1))
+ is_merg = false;
+ // allowed
+ }
+ return is_merg;
+ }
+
+std::ostream& operator<<(std::ostream& s, const r_Minterval& d)
+ {
+ d.print_status(s);
+ return s;
+ }
+
+std::ostream& operator<<(std::ostream& s, const vector<double>& doubleVec)
+ {
+ vector<double>::const_iterator iter, iterEnd;
+
+ iter=doubleVec.begin();
+ iterEnd=doubleVec.end();
+ s << "{";
+ while(iter != iterEnd){
+ s << *iter;
+ ++iter;
+ if(iter != iterEnd)
+ s << ", ";
+ }
+ s << "}";
+
+ return s;
+ }
diff --git a/raslib/minterval.hh b/raslib/minterval.hh
new file mode 100644
index 0000000..a9b596d
--- /dev/null
+++ b/raslib/minterval.hh
@@ -0,0 +1,567 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: minterval.hh
+ *
+ * MODULE: raslib
+ * CLASS: r_Minterval
+ *
+ * COMMENTS:
+ *
+*/
+
+#ifndef _D_MINTERVAL_
+#define _D_MINTERVAL_
+
+#include <iostream>
+#include <vector>
+using std::endl;
+using std::vector;
+
+#ifdef __VISUALC__
+// Diable warning for exception specification.
+#pragma warning( disable : 4290 )
+#include <strstrea.h>
+#else
+#include <sstream> // for istrstream
+#endif
+
+class r_Edim_mismatch;
+class r_Error;
+class r_Einit_overflow;
+class r_Eno_interval;
+class r_Eno_cell;
+class r_Error;
+
+
+#include "raslib/sinterval.hh"
+#include "raslib/point.hh"
+
+//@ManMemo: Module: {\bf raslib}
+
+/*@Doc:
+
+ The spatial domain of an MDD is represented by an object
+ of class \Ref{r_Minterval}. It specifies lower and upper bound
+ of the point set for each dimension of an MDD. Internally,
+ the class is realized through an array of intervals of type
+ \Ref{r_Sinterval}.
+
+ For the operations union, difference, and intersection the
+ dimensionalties of the operands must be equal, otherwise an
+ exception is raised. The semantics of the operations are
+ defined as follows for each dimension:
+
+ | ... fixed bound \\
+ * ... open bound
+
+ \begin{verbatim}
+
+ class orientation union difference intersection
+ -----------------------------------------------------------
+ 1 |-a-| |-b-| error a error
+
+ 2 |-a-| [a1,b2] [a1,b1] [b1,a2]
+ |-b-|
+
+ 3 |--a--| a error b
+ |-b-|
+
+ 4 |-b-| [b1,a2] [b2,a2] [a1,b2]
+ |-a-|
+
+ 5 |--b--| b error a
+ |-a-|
+
+ 6 |-b-| |-a-| error a error
+
+ 7 |-a-|-b-| [a1,b2] a [a2,a2]
+
+ 8 |-b-|-a-| [b1,a2] a [b2,b2]
+
+ 9 |--a--| a [a1,b1] b
+ |-b-|
+
+ 10 |--a--| a [b2,a2] b
+ |-b-|
+
+ 11 |-a-| a error a
+ |-b-|
+
+ 12 |--b--| b error a
+ |-a-|
+
+ 13 |--b--| b error a
+ |-a-|
+
+ -----------------------------------------------------
+
+ 14 |--a--* a error b
+ |-b-|
+
+ 15 |--a--* a [b2,a2] b
+ |-b-|
+
+ 16 |-b-| |-a-* error a error
+
+ 17 |-b-|-a-* [b1,a2] a [b2,b2]
+
+ 18 |--a--* [b1,a2] [b2,a2] [a1,b2]
+ |-b-|
+
+ -----------------------------------------------------
+
+ 19 *--a--| a error b
+ |-b-|
+
+ 20 *--a--| a [a1,b1] b
+ |-b-|
+
+ 21 *-a-| |-b-| error a error
+
+ 22 *-a-|-b-| [a1,b2] a [a2,a2]
+
+ 23 *--a--| [a1,b2] [a1,b1] [b1,a2]
+ |-b-|
+
+ -----------------------------------------------------
+
+ 24 |--b--* b error a
+ |-a-|
+
+ 25 |--b--* b error a
+ |-a-|
+
+ 26 |-a-| |-b-* error a error
+
+ 27 |-a-|-b-* [a1,b2] a [a2,a2]
+
+ 28 |--b--* [a1,b2] [a1,b1] [b1,a2]
+ |-a-|
+
+ -----------------------------------------------------
+
+ 29 *--b--| b error a
+ |-a-|
+
+ 30 *--b--| b error a
+ |-a-|
+
+ 31 *-b-| |-a-| error a error
+
+ 32 *-b-|-a-| [b1,a2] a [b2,b2]
+
+ 33 *--b--| [b1,a2] [b2,a2] [a1,b2]
+ |-a-|
+
+ -----------------------------------------------------
+
+ 34 *-a-| |-b-* error a error
+
+ 35 *-a-|-b-* [a1,b2] a [a2,a2]
+
+ 36 *-a-| [a1,b2] [a1,b1] [b1,a2]
+ |-b-*
+
+ -----------------------------------------------------
+
+ 37 *-b-| |-a-* error a error
+
+ 38 *-b-|-a-* [b1,a2] a [b2,b2]
+
+ 39 *-b-| [b1,a2] [a1,b1] [a1,b2]
+ |-a-*
+
+ -----------------------------------------------------
+
+ 40 *-a-| b error a
+ *-b-|
+
+ 41 *-a-| a error a
+ *-b-|
+
+ 42 *-b-| a [b2,a2] b
+ *-a-|
+
+ -----------------------------------------------------
+
+ 43 |-a-* a [a1,b1] b
+ |-b-*
+
+ 44 |-a-* a error a
+ |-b-*
+
+ 45 |-b-* b error a
+ |-a-*
+
+ -----------------------------------------------------
+ 46 *-a-* |-b-| a error b
+
+ 47 *-b-* |-a-| b error b
+
+ 48 *-a-* a [b2,a2] b
+ *-b-|
+
+ 49 *-a-* a [a1,b1] b
+ |-b-*
+
+ 50 *-b-* b error a
+ *-a-|
+
+ 51 *-b-* b error a
+ |-a-*
+
+ 52 *-a-* a error a
+ *-b-*
+
+ \end{verbatim}
+
+ Attention: The difference operation has to be reconsidered in future
+ concerning a discrete interpretation of the intervals.
+
+ The closure operation defines an interval which is the smallest
+ interval containing the two operands.
+ The method {\tt intersects_with()} returns 0 in the error cases of the
+ intersection operation and 1 otherwise.
+
+*/
+
+class r_Minterval
+{
+ public:
+ /// constructor getting dimensionality for stream initializing
+ r_Minterval( r_Dimension );
+ /// constructor taking string representation (e.g. [ 1:255, *:200, *:* ])
+ r_Minterval( const char* ) throw(r_Eno_interval);
+ /// constructor taking string representation (e.g. [ 1:255, *:200, *:* ])
+ r_Minterval( char* ) throw(r_Eno_interval);
+ /// for stream initializing with intervals
+ r_Minterval& operator<<( const r_Sinterval& )
+ throw( r_Einit_overflow );
+ /// for stream initializing with point intervals
+ r_Minterval& operator<<( r_Range )
+ throw( r_Einit_overflow );
+
+ /// default constructor
+ r_Minterval();
+ /// copy constructor
+ r_Minterval( const r_Minterval& );
+ /// destructor: cleanup dynamic memory
+ ~r_Minterval();
+
+ /// it is called when an object leaves transient memory
+ void r_deactivate();
+
+ /// determines if the self minterval intersects with the delivered one
+ bool intersects_with( const r_Minterval& ) const;
+
+#ifdef OPT_INLINE
+ inline
+#endif
+ /// read access the i-th interval
+ r_Sinterval operator[]( r_Dimension ) const;
+#ifdef OPT_INLINE
+ inline
+#endif
+ /// write access the i-th interval
+ r_Sinterval& operator[]( r_Dimension );
+
+ /// assignment: cleanup + copy
+ const r_Minterval& operator= ( const r_Minterval& );
+
+ /// equal operator
+ bool operator==( const r_Minterval& ) const;
+
+ /**
+ Two domains are equal if they have the same number of dimensions and
+ each dimension has the same lower and upper bounds.
+ */
+
+ /// non equal operator - negation of equal operator
+ bool operator!=( const r_Minterval& ) const;
+
+ /// does this interval cover the given point
+ inline const bool covers( const r_Point& pnt ) const;
+ /**
+ throws r_Edim_mismatch when dimensions do not match
+ */
+
+ /// does this interval cover the given interval
+ inline const bool covers( const r_Minterval& inter ) const;
+ /**
+ throws r_Edim_mismatch when dimensions do not match
+ */
+
+ /// get dimensionality
+ inline r_Dimension dimension() const;
+
+ /// checks if all lower bounds are fixed
+ inline const bool is_origin_fixed() const;
+ /*@Doc:
+ Returns true if all lower bounds are fixed, otherwise false.
+ */
+
+ /// get lower left corner of minterval.
+ r_Point get_origin() const throw(r_Error);
+ /*@Doc:
+ Returns a point with the minimum coordinates in all dimensions.
+ This is operation is only legal if all lower bounds are fixed!
+ */
+
+ /// checks if all upper bounds are fixed
+ inline const bool is_high_fixed() const;
+ /*@Doc:
+ Returns true if all upper bounds are fixed, otherwise false.
+ */
+
+ /// get highest corner of tile.
+ r_Point get_high() const throw(r_Error);
+ /*@Doc:
+ Returns a point with the maximum coordinates in all dimensions.
+ This is operation is only legal if all upper bounds are fixed!
+ */
+
+ /// get size of minterval as point.
+ r_Point get_extent() const throw(r_Error);
+ /*@Doc:
+ Returns a point with high() - low() + 1 of this in each
+ dimension when all bounds are fixed
+ */
+
+ /// Checks if this block is mergeable with another block (interval)
+ bool is_mergeable(const r_Minterval& other) const;
+ /**
+ This method checks if two r_Mintervals are "mergeable" side by side.
+ For this to be possible, they have to have the same low() and high()
+ values in all dimensions except in one where they differ by one point,
+ this is, a.low()==b.high()+1 or b.low()==a.high()+1. For instance, the
+ following two blocks are mergeable:
+
+ +-------------+---------------------------------------+
+ | A | B |
+ +-------------|---------------------------------------|
+
+ and the following two are not:
+
+ +-------------+-------------------------+
+ | | B |
+ | A +-------------------------+
+ +-------------+
+ */
+
+ //@Man: Methods for translation:
+ //@{
+ /// translates this by a point.
+ r_Minterval& reverse_translate( const r_Point& )
+ throw( r_Error, r_Edim_mismatch, r_Eno_interval );
+ /*@Doc:
+ Subtracts respective coordinate of a point to the lower bounds of an
+ interval. This operation is only legal if all bounds are
+ fixed!
+ */
+ /// returns new interval as translation of this by a point.
+ r_Minterval create_reverse_translation( const r_Point& ) const
+ throw( r_Error, r_Edim_mismatch, r_Eno_interval );
+ /*@Doc:
+ Subtracts respective coordinate of a point to the lower bounds of an
+ interval. This operation is only legal if all bounds are
+ fixed!
+ */
+ /// translates this by a point.
+ r_Minterval& translate( const r_Point& )
+ throw( r_Error, r_Edim_mismatch, r_Eno_interval );
+ /*@Doc:
+ Adds respective coordinate of a point to the lower bounds of an
+ interval. This operation is only legal if all bounds are
+ fixed!
+ */
+ /// returns new interval as translation of this by a point.
+ r_Minterval create_translation( const r_Point& ) const
+ throw( r_Error, r_Edim_mismatch, r_Eno_interval );
+ /*@Doc:
+ Adds respective coordinate of a point to the lower bounds of an
+ interval. This operation is only legal if all lower bounds are
+ fixed!
+ */
+ ///
+ //@}
+
+ //*****************************************
+
+ //@Man: Methods for scaling:
+ //@{
+ /// scales this by a factor.
+ r_Minterval& scale( const double& ) throw ( r_Eno_interval );
+ /*@Doc:
+ Scales respective extents by factor.
+ */
+ /// scales this by a factor.
+ r_Minterval& scale( const vector<double>& ) throw ( r_Eno_interval );
+ /*@Doc:
+ Scales respective extents by vector of factors.
+ */
+ /// returns new interval as scaled from this by a point.
+ r_Minterval create_scale( const double& ) const throw ( r_Eno_interval );
+ /*@Doc:
+ Scales respective extents by factor.
+ */
+ /// returns new interval as scaled from this by a point.
+ r_Minterval create_scale( const vector<double>& ) const throw ( r_Eno_interval );
+ /*@Doc:
+ Scales respective extents by vector of factors.
+ */
+ //@}
+
+ //*****************************************
+
+
+
+
+
+ //@Man: Methods/Operators for the union operation:
+ //@{
+ ///
+ r_Minterval& union_of ( const r_Minterval&, const r_Minterval& )
+ throw( r_Edim_mismatch, r_Eno_interval );
+ ///
+ r_Minterval& union_with ( const r_Minterval& )
+ throw( r_Edim_mismatch, r_Eno_interval );
+ ///
+ r_Minterval& operator+= ( const r_Minterval& )
+ throw( r_Edim_mismatch, r_Eno_interval );
+ ///
+ r_Minterval create_union ( const r_Minterval& ) const
+ throw( r_Edim_mismatch, r_Eno_interval );
+ ///
+ r_Minterval operator+ ( const r_Minterval& ) const
+ throw( r_Edim_mismatch, r_Eno_interval );
+ ///
+ //@}
+
+ //@Man: Methods/Operators for the difference operation:
+ //@{
+ ///
+ r_Minterval& difference_of ( const r_Minterval&, const r_Minterval& )
+ throw( r_Edim_mismatch, r_Eno_interval );
+ ///
+ r_Minterval& difference_with ( const r_Minterval& )
+ throw( r_Edim_mismatch, r_Eno_interval );
+ ///
+ r_Minterval& operator-= ( const r_Minterval& )
+ throw( r_Edim_mismatch, r_Eno_interval );
+ ///
+ r_Minterval create_difference ( const r_Minterval& ) const
+ throw( r_Edim_mismatch, r_Eno_interval );
+ ///
+ r_Minterval operator- ( const r_Minterval& ) const
+ throw( r_Edim_mismatch, r_Eno_interval );
+ ///
+ //@}
+
+ //@Man: Methods/Operators for the intersection operation:
+ //@{
+ ///
+ r_Minterval& intersection_of ( const r_Minterval&, const r_Minterval& )
+ throw( r_Edim_mismatch, r_Eno_interval );
+ ///
+ r_Minterval& intersection_with ( const r_Minterval& )
+ throw( r_Edim_mismatch, r_Eno_interval );
+ ///
+ r_Minterval& operator*= ( const r_Minterval&)
+ throw( r_Edim_mismatch, r_Eno_interval);
+ ///
+ r_Minterval create_intersection ( const r_Minterval& ) const
+ throw( r_Edim_mismatch, r_Eno_interval );
+ ///
+ r_Minterval operator* ( const r_Minterval& ) const
+ throw( r_Edim_mismatch, r_Eno_interval );
+ ///
+ //@}
+
+ //@Man: Methods/Operators for the closure operation:
+ //@{
+ ///
+ r_Minterval& closure_of ( const r_Minterval&, const r_Minterval& )
+ throw( r_Edim_mismatch, r_Eno_interval );
+ ///
+ r_Minterval& closure_with ( const r_Minterval& )
+ throw( r_Edim_mismatch, r_Eno_interval );
+ ///
+ r_Minterval create_closure ( const r_Minterval& ) const
+ throw( r_Edim_mismatch, r_Eno_interval );
+ ///
+ //@}
+
+ /// writes the state of the object to the specified stream
+ void print_status( std::ostream& s = std::cout ) const;
+
+ /// gives back the string representation
+ char* get_string_representation() const;
+ /**
+ The string representation delivered by this method is allocated using {\tt malloc()} and
+ has to be free unsing {\tt free()} in the end. It can be used to construct a {\tt r_Minterval}
+ again with a special constructor provided. The string representation is build using
+ {\tt print_status()}.
+ */
+
+ //@Man: Methods for internal use only:
+ //@{
+ /// calculate number of cells
+ r_Area cell_count() const throw(r_Error);
+ /// calculate offset in cells for one dimensional access (dimension ordering is high first)
+ r_Area cell_offset( const r_Point& ) const throw( r_Eindex_violation, r_Error );
+ /// calculate point index out of offset
+ r_Point cell_point( r_Area ) const throw( r_Eno_cell, r_Error );
+ /// delete the specified dimension
+ void delete_dimension( r_Dimension ) throw( r_Eindex_violation );
+ /// calculate the size of the storage space occupied
+ r_Bytes get_storage_size( ) const;
+ ///
+ //@}
+
+ protected:
+ /// array for storing the intervals
+ r_Sinterval* intervals;
+
+ /// dimensionality of the domain
+ r_Dimension dimensionality;
+
+ /// number of components initialized already
+ r_Dimension streamInitCnt;
+
+ /// initialization for constructors which take chars
+ void constructorinit(char* ) throw(r_Eno_interval);
+};
+
+
+
+
+//@ManMemo: Module: {\bf raslib}
+/**
+ Output stream operator for objects of type {\tt const} \Ref{r_Minterval}.
+*/
+extern std::ostream& operator<<( std::ostream& s, const r_Minterval& d );
+
+#include "raslib/minterval.icc"
+
+#endif
diff --git a/raslib/minterval.icc b/raslib/minterval.icc
new file mode 100644
index 0000000..aec847f
--- /dev/null
+++ b/raslib/minterval.icc
@@ -0,0 +1,138 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INLINE SOURCE: minterval.icc
+ *
+ * MODULE: raslib
+ * CLASS: r_Minterval
+ *
+ * COMMENTS:
+ *
+*/
+
+// -*-C++-*- (for Emacs)
+#include "raslib/rminit.hh"
+#include "raslib/error.hh"
+
+inline r_Dimension
+r_Minterval::dimension() const
+{
+ return dimensionality;
+}
+
+inline const bool
+r_Minterval::is_origin_fixed() const
+{
+ bool retval=true;
+
+ if(!dimensionality)
+ {
+ retval=false;
+ }
+ else
+ {
+ for(r_Dimension i=0; i < dimensionality; i++)
+ retval &= intervals[i].is_low_fixed();
+ }
+
+ return retval;
+}
+
+inline const bool
+r_Minterval::is_high_fixed() const
+{
+ bool retval=true;
+
+ if(!dimensionality)
+ {
+ //we have an uninitialized interval
+ retval=false;
+ }
+ else
+ {
+ for(r_Dimension i=0; i < dimensionality; i++)
+ retval &= intervals[i].is_high_fixed();
+ }
+
+ return retval;
+}
+
+
+
+inline const bool
+r_Minterval::covers( const r_Point& pnt ) const
+ {
+ bool retval = true;
+ if (dimensionality == pnt.dimension())
+ {
+ for (r_Dimension i = 0; i < pnt.dimension(); i++)
+ {
+ if ((intervals[i].is_low_fixed() && pnt[i] < intervals[i].low()) || (intervals[i].is_high_fixed() && pnt[i] > intervals[i].high()))
+ {
+ retval = false;
+ break;
+ }
+ }
+ }
+ else {
+ RMInit::logOut << "r_Minterval::covers(" << pnt << ") dimensions do not match" << endl;
+ retval=false;
+ }
+
+ return retval;
+ }
+
+
+inline const bool
+r_Minterval::covers( const r_Minterval& inter2 ) const
+ {
+ bool retval = true;
+ if (dimensionality == inter2.dimension())
+ {
+ for (r_Dimension i = 0; i < dimensionality ; i++)
+ {
+ // first check if i am low fixed and the other isn't: false
+ // both are low fixed
+ // check if i am smaller than the other: false
+ // second check if i am high fixed and the other isn't: false
+ // both are high fixed
+ // check if i am smaller than the other: false
+ if (
+ (intervals[i].is_low_fixed() && (!(inter2[i].is_low_fixed()) || intervals[i].low() > inter2[i].low()))
+ ||
+ (intervals[i].is_high_fixed() && (!(inter2[i].is_high_fixed()) || intervals[i].high() < inter2[i].high()))
+ )
+ {
+ retval = false;
+ break;
+ }
+ }
+ }
+ else {
+ RMInit::logOut << "r_Minterval::covers(" << inter2 << ") dimensions do not match" << endl;
+ retval=false;
+ }
+
+ return retval;
+ }
+
diff --git a/raslib/mintervaltype.cc b/raslib/mintervaltype.cc
new file mode 100644
index 0000000..beff527
--- /dev/null
+++ b/raslib/mintervaltype.cc
@@ -0,0 +1,80 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+static const char rcsid[] = "@(#)raslib, r_Minterval_Type: $Header: /home/rasdev/CVS-repository/rasdaman/raslib/mintervaltype.cc,v 1.6 2003/12/27 23:01:21 rasdev Exp $";
+
+#include "raslib/mintervaltype.hh"
+
+r_Minterval_Type::r_Minterval_Type()
+ : r_Type()
+{
+}
+
+r_Minterval_Type::r_Minterval_Type( const r_Minterval_Type& oldObj )
+ : r_Type(oldObj)
+{
+}
+
+bool
+r_Minterval_Type::isMintervalType() const
+ {
+ return true;
+ }
+
+r_Type*
+r_Minterval_Type::clone() const
+{
+ return new r_Minterval_Type( *this );
+}
+
+r_Type::r_Type_Id
+r_Minterval_Type::type_id() const
+{
+ return MINTERVALTYPE;
+}
+
+void
+r_Minterval_Type::convertToLittleEndian(char* cells, r_Area noCells) const
+{
+}
+
+void
+r_Minterval_Type::convertToBigEndian(char* cells, r_Area noCells) const
+{
+}
+
+void
+r_Minterval_Type::print_status( std::ostream& s ) const
+{
+ s << "minterval";
+}
+
+r_Minterval_Type::~r_Minterval_Type()
+{
+}
+
+std::ostream &operator<<( std::ostream &str, const r_Minterval_Type &type )
+{
+ type.print_status(str);
+ return str;
+}
diff --git a/raslib/mintervaltype.hh b/raslib/mintervaltype.hh
new file mode 100644
index 0000000..9f3f620
--- /dev/null
+++ b/raslib/mintervaltype.hh
@@ -0,0 +1,79 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: mintervaltype.hh
+ *
+ * MODULE: raslib
+ * CLASS: r_Minterval_Type
+ *
+ * COMMENTS:
+ *
+*/
+
+#ifndef _D_MINTERVAL_TYPE_
+#define _D_MINTERVAL_TYPE_
+
+#include "raslib/type.hh"
+
+//@ManMemo: Module: {\bf raslib}
+
+/*@Doc:
+ This class represents the multidimensional interval type in the ODMG conformant
+ representation of the RasDaMan type system.
+*/
+
+class r_Minterval_Type : public r_Type
+{
+public:
+ /// default constructor
+ r_Minterval_Type();
+
+ /// copy constructor
+ r_Minterval_Type( const r_Minterval_Type& oldObj );
+
+ /// clone operation
+ virtual r_Type* clone() const;
+
+ /// retrieve id of the type.
+ virtual r_Type::r_Type_Id type_id() const;
+
+ /// converts array of cells from NT byte order to Unix byte order.
+ virtual void convertToLittleEndian(char* cells, r_Area noCells) const;
+
+ /// converts array of cells from Unix byte order to NT byte order.
+ virtual void convertToBigEndian(char* cells, r_Area noCells) const;
+
+ /// writes state of object to specified stream
+ virtual void print_status( std::ostream& s = std::cout ) const;
+
+ virtual bool isMintervalType() const;
+
+ /// destructor
+ ~r_Minterval_Type();
+};
+
+//@Doc: write the status of a minterval type to a stream
+extern std::ostream &operator<<( std::ostream &str, const r_Minterval_Type &type );
+
+#endif
+
diff --git a/raslib/miter.cc b/raslib/miter.cc
new file mode 100644
index 0000000..35acb54
--- /dev/null
+++ b/raslib/miter.cc
@@ -0,0 +1,33 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: miter.cc
+ *
+ * MODULE: raslib
+ * CLASS: r_Miter
+ *
+*/
+
+static const char rcsid[] = "@(#)raslib, r_Miter: $Header: /home/rasdev/CVS-repository/rasdaman/raslib/miter.cc,v 1.5 2003/12/27 23:01:21 rasdev Exp $";
+
+// moved everything to miter.icc
diff --git a/raslib/miter.hh b/raslib/miter.hh
new file mode 100644
index 0000000..98ee03c
--- /dev/null
+++ b/raslib/miter.hh
@@ -0,0 +1,99 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: miter.hh
+ *
+ * MODULE: raslib
+ * CLASS: r_Miter
+ *
+*/
+
+#ifndef _D_MITER_
+#define _D_MITER_
+
+class r_Minterval;
+
+//@ManMemo: Module: {\bf raslib}
+
+/*@Doc:
+ r_Miter is used for iterating through parts of
+ multidimensional intervals. It is given the domain of
+ the object to be iterated through, the size of the base
+ base type, the address of the first cell in the Tile and
+ an Minterval specifying the area to be iterated through.
+
+ Going to the next cell is done with nextCell() which
+ returns the adress of the next cell. Test for the end
+ is done with isDone(). The iterator can be reset with
+ reset().
+*/
+
+class r_Miter
+{
+public:
+ /// constructor.
+ inline r_Miter( const r_Minterval* newAreaIter,
+ const r_Minterval* newAreaTile, r_Bytes newCellSize,
+ const char* newFirstCell );
+ /**
+ The pointers are stored, do not delete the objects as long
+ as the iterator is used!
+ */
+
+ /// destructor.
+ inline ~r_Miter();
+ /// resets iterator to first cell.
+ inline void reset();
+ /// returns current cell and sets iterator to next cell.
+ inline char* nextCell();
+ /// returns TRUE if iteration is finished.
+ inline bool isDone();
+protected:
+ // structure storing information on iteration for each dimension
+ // (perhaps add dimension for reordering later)
+ typedef struct {
+ int repeat; // total number of repeats
+ int inc; // increment per repeat
+ int curr; // current repeat
+ } incArrElem;
+ /// area to be iterated through
+ const r_Minterval* areaIter;
+ /// area of tile.
+ const r_Minterval* areaTile;
+ /// size of base type.
+ r_Bytes cellSize;
+ /// offset of first cell in tile.
+ const char* firstCell;
+ /// array with increments
+ incArrElem* incArrIter;
+ /// flag set if iteration is finished.
+ bool done;
+ /// current cell for iteration;
+ char* currCell;
+ /// counter for position in lowest dimension.
+ int lowCount;
+};
+
+#include "miter.icc"
+
+#endif
diff --git a/raslib/miter.icc b/raslib/miter.icc
new file mode 100644
index 0000000..f4578d2
--- /dev/null
+++ b/raslib/miter.icc
@@ -0,0 +1,144 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: miter.cc
+ *
+ * MODULE: raslib
+ * CLASS: r_Miter
+ *
+*/
+
+#include "raslib/miter.hh"
+#include "raslib/minterval.hh"
+#include "raslib/rmdebug.hh"
+
+inline
+r_Miter::r_Miter( const r_Minterval* newAreaIter,
+ const r_Minterval* newAreaTile,
+ r_Bytes newCellSize, const char* newFirstCell )
+ : areaIter(newAreaIter), areaTile(newAreaTile), cellSize(newCellSize),
+ firstCell(newFirstCell), done(false)
+{
+ RMDBGENTER(1, RMDebug::module_raslib, "r_Miter", "r_Miter()");
+ // the following initializes incArrIter and calculates the first offset
+ int tIncIter = 1; // total increment for current dimension
+ int prevTIncIter = 1; // total increment for previous dimension
+ r_Bytes incIter = cellSize; // current increment
+ r_Dimension i;
+ int firstOff = 0;
+
+ RMDBGMIDDLE(2, RMDebug::module_raslib, "r_Miter", "area for iteration: " << *newAreaIter);
+ RMDBGMIDDLE(2, RMDebug::module_raslib, "r_Miter", "whole area: " << *newAreaTile);
+
+ // dimensionality of both areaIter and areaTile
+ r_Dimension dim = areaIter->dimension();
+ // stores the increments
+ incArrIter = new incArrElem[dim];
+
+ for( i=0; i<dim; i++ ) {
+ // in RasDaMan the order of dimensions is the other way round!
+ int r = dim - i - 1;
+ // used for counting in iteration, initialize with 0
+ incArrIter[i].curr = 0;
+ // how often is the increment added?
+ incArrIter[i].repeat = (*areaIter)[r].high() - (*areaIter)[r].low() + 1;
+ RMDBGMIDDLE(4, RMDebug::module_raslib, "r_Miter", "repeat dim " << i << ": " << incArrIter[i].repeat );
+ // the increment for the result tile (higher dimensions calculated
+ // further down)
+ incArrIter[i].inc = incIter;
+ RMDBGMIDDLE(4, RMDebug::module_raslib, "r_Miter", "incIter dim " << i << ": " << incIter );
+
+ // calculate starting offset and increments for higher dimensions
+ // firstOff is the offset in chars of the first cell
+ firstOff += ((*areaIter)[r].low()-(*areaTile)[r].low()) * prevTIncIter * cellSize;
+ // tInc is the increment if the dimension would be skipped
+ tIncIter = ((*areaTile)[r].high()-(*areaTile)[r].low()+1) * prevTIncIter;
+ // inc is the real increment, after some cells in the dimensions
+ // have been iterated through.
+ incIter = (tIncIter - incArrIter[i].repeat*prevTIncIter) * cellSize;
+ // remember total increment of last dimension
+ prevTIncIter = tIncIter;
+ }
+ firstCell += firstOff;
+ reset();
+ RMDBGEXIT(1, RMDebug::module_raslib, "r_Miter", "r_Miter()");
+}
+
+inline
+r_Miter::~r_Miter()
+{
+ delete [] incArrIter;
+}
+
+inline void
+r_Miter::reset()
+{
+ currCell = (char*)firstCell;
+ done = false;
+ lowCount = 0;
+ for( r_Dimension i=0; i<areaIter->dimension(); i++ ) {
+ incArrIter[i].curr = 0;
+ }
+}
+
+inline char*
+r_Miter::nextCell()
+{
+ // return the current cell
+ char* retVal = currCell;
+ r_Dimension i = 0;
+
+ if(done)
+ return retVal;
+
+ // increment adresses
+ currCell += incArrIter[0].inc;
+ lowCount++;
+ if(lowCount == incArrIter[0].repeat) {
+ lowCount = 0;
+ // increment other dimensions
+ for(i=1; i < areaIter->dimension(); i++) {
+ incArrIter[i].curr++;
+ currCell += incArrIter[i].inc;
+ if(incArrIter[i].curr < incArrIter[i].repeat) {
+ // no overflow in this dimension
+ break;
+ } else {
+ // overflow in this dimension
+ incArrIter[i].curr = 0;
+ }
+ }
+ if( i == areaIter->dimension() ) {
+ // overflow in last dimension
+ done = true;
+ currCell = retVal;
+ }
+ }
+ return retVal;
+}
+
+bool
+r_Miter::isDone()
+{
+ return done;
+}
diff --git a/raslib/mitera.cc b/raslib/mitera.cc
new file mode 100644
index 0000000..b92cb72
--- /dev/null
+++ b/raslib/mitera.cc
@@ -0,0 +1,141 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: mitera.cc
+ *
+ * MODULE: raslib
+ * CLASS: r_MiterArea
+ *
+*/
+
+#include "raslib/mitera.hh"
+#include "raslib/minterval.hh"
+#include "raslib/rmdebug.hh"
+
+r_MiterArea::r_MiterArea( const r_Minterval* newIterDom,
+ const r_Minterval* newImgDom ) throw(r_Error)
+ : iterDom(newIterDom), imgDom(newImgDom), done(false)
+{
+ RMDBGENTER( 1, RMDebug::module_raslib, "r_MiterArea", "r_MiterArea()");
+
+ if (imgDom->dimension() != iterDom->dimension())
+ {
+ //in this case we have an undefined situation
+ RMInit::logOut << "r_MiterArea::rMiterArea(" << iterDom << ", " << imgDom << ") dimension mismatch" << endl;
+ throw r_Error(INTERVALSWITHDIFFERENTDIMENSION);
+ }
+
+ if(!imgDom->is_origin_fixed() ||
+ !imgDom->is_high_fixed())
+ {
+ //in this case we have an undefined situation
+ RMInit::logOut << "r_MiterArea::rMiterArea(" << iterDom << ", " << imgDom << ") imgDom is opened" << endl;
+ throw r_Error(INTERVALOPEN);
+ }
+
+ if(!iterDom->is_origin_fixed() ||
+ !iterDom->is_high_fixed())
+ {
+ //in this case we have an undefined situation
+ RMInit::logOut << "r_MiterArea::rMiterArea(" << iterDom << ", " << imgDom << ") iterDom is opened" << endl;
+ throw r_Error(INTERVALOPEN);
+ }
+
+
+ // dimensionality of both iterDom and imgDom
+ r_Dimension dim = imgDom->dimension();
+ // stores the increments
+ incArrIter = new incArrElem[dim];
+
+ for(r_Dimension i=0; i<dim; i++ ) {
+ // used for counting in iteration, initialize with 0
+ incArrIter[i].curr = 0;
+ // how often is the iterDom moved inside the imgDom
+ incArrIter[i].repeat = (imgDom->get_extent()[i] / iterDom->get_extent()[i]) +
+ ( imgDom->get_extent()[i] % iterDom->get_extent()[i] != 0 );
+
+ RMDBGMIDDLE( 4, RMDebug::module_raslib, "r_MiterArea", "repeat dim " << i << ": " << incArrIter[i].repeat );
+ }
+ reset();
+ RMDBGEXIT( 1, RMDebug::module_raslib, "r_MiterArea", "r_MiterArea()" );
+}
+
+
+r_MiterArea::~r_MiterArea()
+{
+ delete [] incArrIter;
+}
+
+void
+r_MiterArea::reset()
+{
+ done = false;
+ for( int i=0; i<iterDom->dimension(); i++ ) {
+ incArrIter[i].curr = 0;
+ }
+}
+
+r_Minterval
+r_MiterArea::nextArea()
+{
+ r_Dimension i = 0;
+
+ if(done)
+ return retVal;
+
+ r_Minterval currDom(iterDom->dimension());
+
+ // calculate new result domain here
+ if(!done) {
+ for(i=0; i < iterDom->dimension(); i++) {
+ currDom << r_Sinterval( (*imgDom)[i].low() + incArrIter[i].curr*iterDom->get_extent()[i],
+ (*imgDom)[i].low() + (incArrIter[i].curr+1)*iterDom->get_extent()[i]
+ - 1 );
+ }
+ }
+ retVal = currDom.intersection_with((*imgDom));
+
+ // increment dimensions
+ for(i=0; i < iterDom->dimension(); i++) {
+ incArrIter[i].curr++;
+ if(incArrIter[i].curr < incArrIter[i].repeat) {
+ // no overflow in this dimension
+ break;
+ } else {
+ // overflow in this dimension
+ incArrIter[i].curr = 0;
+ }
+ }
+ if( i == iterDom->dimension() ) {
+ // overflow in last dimension
+ done = true;
+ }
+
+ return retVal;
+}
+
+bool
+r_MiterArea::isDone()
+{
+ return done;
+}
diff --git a/raslib/mitera.hh b/raslib/mitera.hh
new file mode 100644
index 0000000..3784e44
--- /dev/null
+++ b/raslib/mitera.hh
@@ -0,0 +1,92 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: mitera.hh
+ *
+ * MODULE: raslib
+ * CLASS: r_MiterArea
+ *
+*/
+
+#ifndef _D_MITERA_
+#define _D_MITERA_
+
+#include "raslib/minterval.hh"
+
+//@ManMemo: Module: {\bf raslib}
+
+/*@Doc:
+ r_MiterArea is used for iterating r_Mintervals through larger
+ r_Mintervals. It is given the domain to be iterated through and
+ an Minterval specifying the shape of area to be iterated with.
+
+
+ Going to the next area is done with nextArea() which returns an
+ r_Minterval. Test for the end is done with isDone(). The
+ iterator can be reset with reset(). Iteration starts at the
+ lowest border in all dimensions. Note that if the shape of
+ r_Minterval iterated does not completely fit into the
+ r_Minterval iterated through the results at the border may have
+ a different (smaller) shape.
+*/
+
+class r_MiterArea
+{
+public:
+ /// constructor.
+ /// An exception is thrown if newIterDom and newImgDom have different dimension
+ r_MiterArea( const r_Minterval* newIterDom,
+ const r_Minterval* newImgDom ) throw(r_Error);
+ /**
+ The pointers are stored, do not delete the objects as long
+ as the iterator is used!
+ */
+
+ /// destructor.
+ ~r_MiterArea();
+ /// resets iterator to beginning.
+ void reset();
+ /// returns current cell and sets iterator to next cell.
+ r_Minterval nextArea();
+ /// returns TRUE if iteration is finished.
+ bool isDone();
+protected:
+ // structure storing information on iteration for each dimension
+ // (perhaps add dimension for reordering later)
+ typedef struct {
+ int repeat; // total number of repeats
+ int curr; // current repeat
+ } incArrElem;
+ /// area to be iterated through
+ const r_Minterval* iterDom;
+ /// area of tile.
+ const r_Minterval* imgDom;
+ /// array with increments
+ incArrElem* incArrIter;
+ /// flag set if iteration is finished.
+ bool done;
+ /// This is used for the return value in nextArea()
+ r_Minterval retVal;
+};
+
+#endif
diff --git a/raslib/miterd.cc b/raslib/miterd.cc
new file mode 100644
index 0000000..d50c50a
--- /dev/null
+++ b/raslib/miterd.cc
@@ -0,0 +1,117 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: miterd.cc
+ *
+ * MODULE: raslib
+ * CLASS: r_Miter
+ *
+*/
+
+#include <iostream>
+
+#include "raslib/miterd.hh"
+#include "raslib/minterval.hh"
+
+
+
+r_MiterDirect::r_MiterDirect(void *data, const r_Minterval &total, const r_Minterval &iter, unsigned int tlen, unsigned int step)
+ : done(false),
+ dim(total.dimension()),
+ length(step),
+ id(NULL),
+ baseAddress(data)
+{
+ int i = 0;
+ r_Range s = tlen;
+ r_Range offset = 0;
+
+ id=new r_miter_direct_data[dim];
+
+ for (i=(int)dim-1; i>=0; i--)
+ {
+ id[i].low = iter[i].low();
+ id[i].high = iter[i].high();
+ id[i].pos = id[i].low;
+ id[i].origin = total[i].low();
+ id[i].extent = (total[i].high() - total[i].low() + 1);
+ id[i].baseStep = s;
+ id[i].step = s * step;
+ offset += s * (id[i].pos - id[i].origin);
+ s *= id[i].extent;
+ }
+ for (i=0; i<(int)dim; i++)
+ {
+ id[i].data = (void*)(((r_Octet*)data) + offset);
+ }
+}
+
+r_MiterDirect::~r_MiterDirect(void)
+{
+ delete [] id;
+}
+
+
+void r_MiterDirect::reset(void)
+{
+ r_Dimension i = 0;
+ r_ULong offset = 0;
+
+ for (i=0; i<dim; i++)
+ {
+ id[i].pos = id[i].low;
+ offset += id[i].step * (id[i].low - id[i].origin);
+ }
+ for (i=0; i<dim; i++)
+ {
+ id[i].data = (void*)(((r_Octet*)baseAddress) + offset);
+ }
+ done = false;
+}
+
+
+void
+r_MiterDirect::print_pos(std::ostream &str) const
+{
+ str << '[' << id[0].pos;
+ for (r_Dimension i=1; i<dim; i++) str << ',' << id[i].pos;
+ str << ']';
+}
+
+
+
+std::ostream &operator<<(std::ostream &str, const r_MiterDirect &iter)
+{
+ iter.print_pos(str);
+ return str;
+}
+
+r_miter_direct_data::r_miter_direct_data()
+:data(NULL), pos(0), low(0), high(0),
+ step(0), baseStep(0), extent(0), origin(0)
+{
+}
+
+r_miter_direct_data::~r_miter_direct_data()
+{
+}
diff --git a/raslib/miterd.hh b/raslib/miterd.hh
new file mode 100644
index 0000000..a4c26d1
--- /dev/null
+++ b/raslib/miterd.hh
@@ -0,0 +1,165 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: miterd.hh
+ *
+ * MODULE: raslib
+ * CLASS: r_MiterDirect
+ *
+*/
+
+#ifndef _R_MITERD_
+#define _R_MITERD_
+
+#include "raslib/mddtypes.hh"
+#include "raslib/odmgtypes.hh"
+
+#include <iosfwd>
+
+class r_Minterval;
+
+class r_miter_direct_data;
+
+//@ManMemo: Module {\bf raslib}
+
+/*@Doc:
+ r_MiterDirect is similar to r_Miter, but allows stepping by more
+ than one cell in each direction, arbitrary order of dimensions in
+ the iteration and has a lot of its internal state variables as public
+ members.
+ It should be used in low-level, very time-critical code like
+ folding operations which would otherwise require construction
+ of a new iterator for each cell when only position and base
+ address need to change.
+*/
+
+class r_MiterDirect
+{
+ public:
+ /// constructor
+ r_MiterDirect(void *data, const r_Minterval &total, const r_Minterval &iter,
+ r_Bytes tlen, unsigned int step=1);
+ /**
+ constructor getting the data, the total domain, the iteration
+ domain, the base type length and the number of steps per
+ iteration.
+ */
+
+ /// destructor
+ ~r_MiterDirect(void);
+
+ /// increment the iterator in the default order, i.e. last dimension first
+ inline r_MiterDirect &operator++(void);
+ /// increment in user-specified order
+ inline r_MiterDirect &iterateUserOrder(const r_Dimension *order, const unsigned int *step);
+ /**
+ increment the iterator in a user-specified order. order points to an array
+ defining the order of the dimensions during iteration, e.g. for a 3D
+ iteration 0,1,2 would iterate over the first dimension first and the
+ last dimension last wheres 2,1,0 is equivalent to operator++(). step
+ is the number of steps to do in each dimension.
+ */
+ /// increment or decrement in user-specified order
+ inline r_MiterDirect &iterateUserOrder(const unsigned int *order, const int *step);
+ /**
+ see the other incrementUserOrder method for more details
+ */
+
+ /// returns != 0 if iteration is finished.
+ inline bool isDone(void) const;
+ /// returns pointer to data during normal iteration.
+ inline void* getData(void);
+ /// return pointer to data for non-standard iteration order
+ inline void* getData(unsigned int *order);
+ /**
+ returns pointer to data during user-defined iteration; order is as
+ defined in iterateUserOrder().
+ */
+ /// returns number of bytes to step in dimension d in one iteration
+ inline r_Range getDimStep(r_Dimension d) const;
+ /// returns number of bytes to step in dimension d when pos changes by 1.
+ inline r_Bytes getDimBaseStep(r_Dimension d) const;
+ /// returns extent in dimension d
+ inline r_Range getExtent(r_Dimension d) const;
+ /// notify that the position was changed and internal variables need to be recalculated
+ inline void posChanged( void );
+ /// reset the iterator (pos to low and data to baseAddress + offset)
+ void reset(void);
+ /// print the position
+ void print_pos(std::ostream &str) const;
+
+ bool done;
+ r_miter_direct_data* id;
+ void* baseAddress;
+
+ private:
+
+ /// if this data should change you must construct a new iterator,
+ /// therefore no public access.
+ r_Dimension dim;
+ r_ULong length;
+};
+
+
+
+/*@Doc:
+ r_miter_direct_data encapsulates data for each dimension.
+ It's an auxiliary class for r_MiterDirect. The only reason
+ not to make it a simple struct was data protection.
+ */
+
+class r_miter_direct_data
+{
+ friend class r_MiterDirect;
+
+ public:
+
+ r_miter_direct_data();
+ ~r_miter_direct_data();
+
+ /// Data concerning the iteration position and domain. May
+ /// be changed by the user.
+ void *data;
+ r_Range pos;
+ r_Range low;
+ r_Range high;
+
+ private:
+
+ /// Data concerning the domain of the source object. Is fixed
+ /// in the constructor.
+ r_Range step;
+ r_Range baseStep;
+ r_Range extent;
+ r_Range origin;
+};
+
+
+/// overloaded stream operator
+extern std::ostream &operator<<(std::ostream &str, const r_MiterDirect &iter);
+
+
+
+#include "raslib/miterd.icc"
+
+#endif
diff --git a/raslib/miterd.icc b/raslib/miterd.icc
new file mode 100644
index 0000000..a30ec98
--- /dev/null
+++ b/raslib/miterd.icc
@@ -0,0 +1,166 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/* ------------------------------------------------------------------------ */
+// r_MiterDirect inline functions
+
+inline bool r_MiterDirect::isDone( void ) const
+{
+ return done;
+}
+
+inline void *r_MiterDirect::getData( void )
+{
+ return id[dim-1].data;
+}
+
+inline void *r_MiterDirect::getData( unsigned int *order )
+{
+ return id[order[0]].data;
+}
+
+inline r_Range r_MiterDirect::getDimStep( r_Dimension d ) const
+{
+ return id[d].step;
+}
+
+inline r_Bytes r_MiterDirect::getDimBaseStep( r_Dimension d ) const
+{
+ return id[d].baseStep;
+}
+
+inline r_Range r_MiterDirect::getExtent( r_Dimension d ) const
+{
+ return id[d].extent;
+}
+
+inline r_MiterDirect&
+r_MiterDirect::operator++(void)
+{
+ int d = (int)dim-1;
+
+ while (d >= 0)
+ {
+ id[d].pos += length;
+ id[d].data = (void*)(((char*)(id[d].data)) + id[d].step);
+ if (id[d].pos <= id[d].high) break;
+ id[d].pos = id[d].low;
+ d--;
+ }
+ if (d >= 0)
+ {
+ int i;
+
+ for (i=d+1; i < (int)dim; i++)
+ {
+ id[i].data = id[d].data;
+ }
+ }
+ else
+ done = true;
+
+ return *this;
+}
+
+inline r_MiterDirect&
+r_MiterDirect::iterateUserOrder(const unsigned int *order, const int *step)
+{
+ r_Dimension d = 0;
+
+ while (d < dim)
+ {
+ r_miter_direct_data *idp = id + order[d];
+
+ idp->pos += step[d];
+ idp->data = (void*)(((char*)(idp->data)) + step[d] * idp->baseStep);
+ if (idp->pos <= idp->high) break;
+ idp->pos = idp->low;
+ d++;
+ }
+ if (d < dim)
+ {
+ r_Dimension i;
+ void *newData = id[order[d]].data;
+
+ for (i=d; i > 0; i--)
+ {
+ id[order[i-1]].data = newData;
+ }
+ }
+ else
+ done = true;
+
+ return *this;
+}
+
+inline r_MiterDirect&
+r_MiterDirect::iterateUserOrder(const r_Dimension *order, const unsigned int *step)
+{
+ r_Dimension d = 0;
+
+ while (d < dim)
+ {
+ r_miter_direct_data *idp = id + order[d];
+
+ idp->pos += step[d];
+ idp->data = (void*)(((char*)(idp->data)) + step[d] * idp->baseStep);
+ if (step[d] > 0)
+ {
+ if (idp->pos <= idp->high) break;
+ idp->pos = idp->low;
+ }
+ else
+ {
+ if (idp->pos >= idp->low) break;
+ idp->pos = idp->high;
+ }
+ d++;
+ }
+ if (d < dim)
+ {
+ r_Dimension i;
+ void *newData = id[order[d]].data;
+
+ for (i=d; i>0; i--)
+ {
+ id[order[i-1]].data = newData;
+ }
+ }
+ else
+ done = true;
+
+ return *this;
+}
+
+
+inline void
+r_MiterDirect::posChanged( void )
+{
+ r_Range offset = 0;
+ r_Dimension i = 0;
+
+ for (i=0; i<dim; i++)
+ offset += id[i].step * (id[i].pos - id[i].origin);
+
+ for (i=0; i<dim; i++)
+ id[i].data = (void*)(((char*)baseAddress) + offset);
+}
diff --git a/raslib/miterf.hh b/raslib/miterf.hh
new file mode 100644
index 0000000..18f38b6
--- /dev/null
+++ b/raslib/miterf.hh
@@ -0,0 +1,128 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: miter.hh
+ *
+ * MODULE: raslib
+ * CLASS: r_MiterFloat
+ *
+*/
+
+#ifndef _D_MITERF_
+#define _D_MITERF_
+
+class r_Minterval;
+
+
+#include "raslib/mddtypes.hh"
+
+class r_FixedPointNumber
+ {
+ public:
+ inline r_FixedPointNumber();
+ inline r_FixedPointNumber(const double&);
+
+ inline r_FixedPointNumber& operator=(const r_FixedPointNumber&);
+ inline r_FixedPointNumber& operator=(const double&);
+
+ // returns intPart_new - intPart_old -- used for tests
+ inline r_Range stepForward(const r_FixedPointNumber&);
+
+ // returns carry of fracPart
+ inline bool stepForwardFlag(const r_FixedPointNumber&);
+
+ inline r_Range getIntPart();
+
+ private:
+ inline void init(const double&);
+
+ r_Range intPart;
+ r_Range fracPart;
+
+ static const int FIXPREC;
+ static const r_Range carryPos;
+ static const r_Range fracMask;
+ static const double fixOne;
+
+ friend std::ostream& operator<<(std::ostream&,r_FixedPointNumber&);
+ };
+
+
+
+//@ManMemo: Module: {\bf raslib}
+
+/*@Doc:
+ r_MiterFloat is used for iterating through parts of
+ multidimensional intervals with arbitrary stepping size using
+ nearest neighbours. It is given the tile, the source domain
+ and the destination domain
+ Apart from that behaviour is exactly as in r_Miter.
+
+*/
+
+class r_MiterFloat
+ {
+ public:
+ /// Constructor getting the source tile, the source domain and the destination domain
+ inline r_MiterFloat(Tile *sourceTile, r_Minterval& sourceDomain, r_Minterval& destDomain);
+
+ /// destructor
+ inline ~r_MiterFloat();
+
+ /// iterator reset
+ inline void reset();
+
+ /// get the next cell
+ inline char* nextCell();
+
+ /// true if done
+ inline bool isDone();
+
+ protected:
+ struct iter_desc
+ {
+ r_FixedPointNumber min;
+ r_FixedPointNumber pos;
+ r_FixedPointNumber step;
+
+ r_Range countSteps;
+ r_Range maxSteps;
+
+ r_Range dimStep;
+ r_Range scaleStep;
+ char *cell;
+ };
+
+ r_Dimension dim;
+ char *currentCell;
+ const char *firstCell;
+
+ iter_desc *iterDesc;
+
+ bool done;
+ };
+
+
+#include "miterf.icc"
+
+#endif
diff --git a/raslib/miterf.icc b/raslib/miterf.icc
new file mode 100644
index 0000000..dad1b2e
--- /dev/null
+++ b/raslib/miterf.icc
@@ -0,0 +1,222 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: miterf.icc
+ *
+ * MODULE: raslib
+ * CLASS: r_MiterFloat
+ *
+*/
+
+#include "raslib/miterf.hh"
+#include "raslib/minterval.hh"
+#include "raslib/rmdebug.hh"
+
+#include <math.h>
+
+
+const int r_FixedPointNumber::FIXPREC = 30;
+const r_Range r_FixedPointNumber::carryPos = 1<<FIXPREC;
+const r_Range r_FixedPointNumber::fracMask = carryPos-1;
+const double r_FixedPointNumber::fixOne = pow(2,(double)FIXPREC);
+
+inline
+r_FixedPointNumber::r_FixedPointNumber()
+ {
+ intPart=0; fracPart=0;
+ }
+
+inline
+r_FixedPointNumber::r_FixedPointNumber(const double &d)
+ { init(d);
+ }
+
+inline
+r_FixedPointNumber& r_FixedPointNumber::operator=(const r_FixedPointNumber &f)
+ {
+ intPart = f.intPart;
+ fracPart = f.fracPart;
+ return *this;
+ }
+
+inline
+r_FixedPointNumber& r_FixedPointNumber::operator=(const double &d)
+ {
+ init(d);
+ return *this;
+ }
+
+inline
+void r_FixedPointNumber::init(const double &d)
+ {
+ intPart = (r_Range)d;
+
+ fracPart= (r_Range)fmod(fixOne*d,fixOne);
+
+ }
+
+inline
+r_Range r_FixedPointNumber::stepForward(const r_FixedPointNumber &f)
+ {
+ r_Range oldIntPart = intPart;
+
+ intPart+=f.intPart; fracPart+=f.fracPart;
+
+ if(fracPart & carryPos)
+ {
+ intPart++;
+ fracPart &= fracMask;
+
+ }
+ return intPart-oldIntPart;
+ }
+
+inline
+bool r_FixedPointNumber::stepForwardFlag(const r_FixedPointNumber &f)
+ {
+ intPart+=f.intPart; fracPart+=f.fracPart;
+
+ if(fracPart & carryPos)
+ {
+ intPart++;
+ fracPart &= fracMask;
+ return true;
+ }
+ return false;
+ }
+
+inline
+r_Range r_FixedPointNumber::getIntPart()
+ {
+ return intPart;
+ }
+
+inline
+std::ostream& operator<<(std::ostream &os,r_FixedPointNumber &f)
+ { os<<'('<<f.intPart<<':'<<f.fracPart<<')';
+ return os;
+ }
+
+//######################################
+
+inline
+r_MiterFloat::r_MiterFloat(Tile *sourceTile, r_Minterval& sourceDomain, r_Minterval& destDomain)
+ {
+ dim = sourceDomain.dimension();
+ iterDesc = new iter_desc[dim];
+
+ r_Bytes cellSize = sourceTile->getType()->getSize();
+ firstCell = sourceTile->getContents();
+
+ iter_desc *id = 0;
+ const r_Minterval& tileDomain = sourceTile->getDomain();
+
+ int i = 0;
+ r_Bytes step = cellSize;
+
+ id = iterDesc + dim-1;
+
+ for(i=dim-1; i>=0; i--, id-- )
+ {
+ id->min = (double)sourceDomain[i].low();
+ id->step = (double)(sourceDomain[i].high()-sourceDomain[i].low() +1) / ( destDomain[i].high() - destDomain[i].low()+1);
+ id->maxSteps = destDomain[i].high() - destDomain[i].low()+1;
+ id->dimStep = step;
+ id->scaleStep = step * id->step.getIntPart();
+ firstCell += step* (sourceDomain[i].low() - tileDomain[i].low());
+ step *= (tileDomain[i].high() - tileDomain[i].low() + 1);
+ }
+ reset();
+ }
+
+inline
+r_MiterFloat::~r_MiterFloat()
+ {
+ if(iterDesc) delete[] iterDesc;
+ }
+
+inline
+void r_MiterFloat::reset()
+ {
+ for(r_Dimension i=0;i<dim;i++)
+ {
+ iterDesc[i].pos = iterDesc[i].min;
+ iterDesc[i].cell = (char*)firstCell;
+ iterDesc[i].countSteps = iterDesc[i].maxSteps;
+ }
+
+ done=false;
+ }
+
+inline
+char* r_MiterFloat::nextCell()
+ {
+ if(done) return currentCell;
+
+ r_Dimension i = dim;
+ iter_desc *id = iterDesc + dim -1;
+ currentCell = iterDesc[dim-1].cell;
+
+ while( i>0 )
+ {
+ id->countSteps--;
+
+ if(id->countSteps)
+ {// one more step in this dimension
+ if(id->pos.stepForwardFlag(id->step))
+ id->cell += id->dimStep;
+
+ id->cell += id->scaleStep;
+ break;
+ }
+ else
+ { // we are finished with this dimension
+ id->pos = id->min;
+ id->countSteps = id-> maxSteps;
+ id--;
+ i--;
+ }
+ }
+
+ if(i<dim)
+ {
+ if(i == 0)
+ done = true;
+ else
+ {
+ r_Dimension j;
+ for( j=i; j<dim; j++)
+ iterDesc[j].cell = iterDesc[i-1].cell;
+ }
+ }
+ return currentCell;
+ }
+
+inline
+bool r_MiterFloat::isDone()
+ {
+ return done;
+ }
+
+
+
diff --git a/raslib/odmgtypes.hh b/raslib/odmgtypes.hh
new file mode 100644
index 0000000..21354e9
--- /dev/null
+++ b/raslib/odmgtypes.hh
@@ -0,0 +1,204 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: odmgtypes.hh
+ *
+ * MODULE: rasodmg
+ *
+ * PURPOSE:
+ * The file contains ODMG type definitions.
+ *
+ * COMMENTS:
+ * For further porting please adapt the typedef for r_Long and r_Ulong
+*/
+
+#ifndef _D_ODMGTYPES_
+#define _D_ODMGTYPES_
+
+// for type-limits
+#include <limits.h>
+#include <float.h>
+
+//@Man: r_Char
+//@Type: typedef
+//@Args: as unsigned char (1 byte)
+//@Memo: Module: {\bf rasodmg}.
+
+typedef unsigned char r_Char;
+
+/**
+ {\tt typedef unsigned char r_Char;}
+*/
+
+
+
+//@Man: r_Octet
+//@Type: typedef
+//@Args: as signed char (1 byte)
+//@Memo: Module: {\bf rasodmg}.
+
+typedef signed char r_Octet;
+
+/**
+ {\tt typedef signed char r_Octet;}
+ (Stroustroup: sign of plain char is implementation-defined)
+*/
+
+
+
+//@Man: r_Short
+//@Type: typedef
+//@Args: as short (2 bytes)
+//@Memo: Module: {\bf rasodmg}.
+
+typedef short r_Short;
+
+/**
+ {\tt typedef short r_Short;}
+*/
+
+
+
+//@Man: r_UShort
+//@Type: typedef
+//@Args: as unsigned short (2 bytes)
+//@Memo: Module: {\bf rasodmg}.
+
+typedef unsigned short r_UShort;
+
+/**
+ {\tt typedef short r_UShort;}
+*/
+
+
+
+//@Man: r_Long
+//@Type: typedef
+//@Args: as long (4 bytes)
+//@Memo: Module: {\bf rasodmg}.
+
+typedef int r_Long;
+/**
+ {\tt typedef int r_Long;}
+*/
+
+
+
+
+
+//@Man: r_ULong
+//@Type: typedef
+//@Args: as unsigned long (4 bytes)
+//@Memo: Module: {\bf rasodmg}.
+
+typedef unsigned int r_ULong;
+/**
+ {\tt typedef unsigned long r_ULong;}
+*/
+
+
+//@Man: r_Float
+//@Type: typedef
+//@Args: as float
+//@Memo: Module: {\bf rasodmg}.
+
+typedef float r_Float;
+
+/**
+ {\tt typedef float r_Float;}
+*/
+
+
+
+//@Man: r_Double
+//@Type: typedef
+//@Args: as double
+//@Memo: Module: {\bf rasodmg}.
+
+typedef double r_Double;
+
+/**
+ {\tt typedef double r_Double;}
+*/
+
+
+
+//@Man: r_Boolean
+//@Type: typedef
+//@Args: as unsigned char (1 byte)
+//@Memo: Module: {\bf rasodmg}.
+
+typedef unsigned char r_Boolean;
+
+/**
+ {\tt typedef unsigned char r_Boolean;}
+ Changed to unsigned char
+*/
+
+
+//@Man: get_limits()
+//@Type: function
+//@Args: as function
+//@Memo: Module: {\bf rasodmg}
+
+inline void get_limits( const r_Octet *tptr, double &min, double &max )
+{
+ min = (double)SCHAR_MIN; max = (double)SCHAR_MAX;
+}
+
+inline void get_limits( const r_Char *tptr, double &min, double &max )
+{
+ min = (double)0.0; max = (double)UCHAR_MAX;
+}
+
+inline void get_limits( const r_Short *tptr, double &min, double &max )
+{
+ min = (double)SHRT_MIN; max = (double)SHRT_MAX;
+}
+
+inline void get_limits( const r_UShort *tptr, double &min, double &max )
+{
+ min = (double)0.0; max = (double)USHRT_MAX;
+}
+
+inline void get_limits( const r_Long *tptr, double &min, double &max )
+{
+ min = (double)INT_MIN; max = (double)INT_MAX;
+}
+
+inline void get_limits( const r_ULong *tptr, double &min, double &max )
+{
+ min = (double)0.0; max = (double)UINT_MAX;
+}
+
+inline void get_limits( const r_Float *tptr, double &min, double &max )
+{
+ min = -((double)FLT_MAX); max = (double)FLT_MAX;
+}
+
+inline void get_limits( const r_Double *tptr, double &min, double &max )
+{
+ min = -((double)DBL_MAX); max = (double)DBL_MAX;
+}
+
+#endif
diff --git a/raslib/oid.cc b/raslib/oid.cc
new file mode 100644
index 0000000..402aeb3
--- /dev/null
+++ b/raslib/oid.cc
@@ -0,0 +1,352 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: oid.cc
+ *
+ * MODULE: raslib
+ * CLASS: r_OId
+ *
+ * COMMENTS:
+ *
+*/
+
+#include "raslib/oid.hh"
+
+#ifdef __VISUALC__
+#include <strstrea.h>
+#else
+#include <strstream>
+#endif
+#include <fstream>
+#include <iomanip>
+#include <string.h>
+#include <stdlib.h>
+
+
+r_OId::r_OId()
+ : oidString(NULL),
+ systemName(NULL),
+ baseName(NULL),
+ localOId(0)
+{
+}
+
+r_OId::r_OId( const char* initOIdString )
+ : oidString(NULL),
+ systemName(NULL),
+ baseName(NULL),
+ localOId(0)
+{
+ // set oidString
+ if( initOIdString )
+ {
+ oidString = new char[ strlen(initOIdString)+1 ];
+ strcpy( oidString, initOIdString );
+
+ //
+ // extract oid parts
+ //
+ char* startPtr = NULL;
+ char* endPtr = NULL;
+
+ // system name
+ startPtr = endPtr = oidString;
+ while( *endPtr != '|' && *endPtr != '\0' ) endPtr++;
+ if( endPtr - startPtr >= 1 )
+ {
+ systemName = new char[ endPtr - startPtr + 1 ];
+ strncpy( systemName, startPtr, endPtr - startPtr );
+ systemName[endPtr - startPtr] = '\0';
+ }
+
+ if( *endPtr != '\0' )
+ {
+ // base name
+ endPtr++;
+ startPtr = endPtr;
+ while( *endPtr != '|' && *endPtr != '\0' ) endPtr++;
+ if( endPtr - startPtr >= 1 )
+ {
+ baseName = new char[ endPtr - startPtr + 1 ];
+ strncpy( baseName, startPtr, endPtr - startPtr );
+ baseName[endPtr - startPtr] = '\0';
+ }
+
+ if( *endPtr != '\0' )
+ {
+ // local oid
+ endPtr++;
+ startPtr = endPtr;
+
+ localOId = atof( startPtr );
+ }
+
+ }
+
+ }
+}
+
+r_OId::r_OId( const char* initSystemName, const char* initBaseName, double initLocalOId )
+ : oidString(NULL),
+ systemName(NULL),
+ baseName(NULL),
+ localOId( initLocalOId )
+{
+ // set members
+ if( initSystemName )
+ {
+ systemName= new char[ strlen(initSystemName)+1 ];
+ strcpy( systemName, initSystemName );
+ }
+
+ if( initBaseName )
+ {
+ baseName= new char[ strlen(initBaseName)+1 ];
+ strcpy( baseName, initBaseName );
+ }
+
+ // allocate buffer which is big enough
+ int bufferSize = ( systemName ? strlen( systemName ) : 0 ) +
+ ( baseName ? strlen( baseName ) : 0 ) +
+ 1024;
+ char* buffer = new char[bufferSize];
+ std::ostrstream oidStream( buffer, bufferSize );
+
+ // write into the string stream
+ if( systemName )
+ oidStream << systemName << "|";
+ else
+ oidStream << "|";
+
+ if( baseName )
+ oidStream << baseName << "|";
+ else
+ oidStream << "|";
+
+ oidStream << std::setprecision(50) << localOId << std::ends;
+
+ // allocate memory taking the final string
+ oidString = new char[strlen(buffer)+1];
+
+ // copy string
+ strcpy( oidString, buffer );
+
+ // delete buffer
+ delete[] buffer;
+}
+
+r_OId::r_OId( const r_OId& obj )
+ : oidString(NULL),
+ systemName(NULL),
+ baseName(NULL),
+ localOId(0)
+{
+ if( obj.oidString )
+ {
+ oidString= new char[ strlen(obj.oidString)+1 ];
+ strcpy( oidString, obj.oidString );
+ }
+
+ if( obj.systemName )
+ {
+ systemName= new char[ strlen(obj.systemName)+1 ];
+ strcpy( systemName, obj.systemName );
+ }
+
+ if( obj.baseName )
+ {
+ baseName= new char[ strlen(obj.baseName)+1 ];
+ strcpy( baseName, obj.baseName );
+ }
+
+ localOId = obj.localOId;
+}
+
+r_OId::~r_OId()
+{
+ r_deactivate();
+}
+
+void
+r_OId::r_deactivate()
+{
+ if( oidString )
+ {
+ delete[] oidString;
+ oidString = NULL;
+ }
+
+ if( systemName )
+ {
+ delete[] systemName;
+ systemName = NULL;
+ }
+
+ if( baseName )
+ {
+ delete[] baseName;
+ baseName = NULL;
+ }
+}
+
+void
+r_OId::print_status( std::ostream& s ) const
+{
+ if( oidString )
+ s << oidString;
+}
+
+const r_OId&
+r_OId::operator=( const r_OId& obj )
+{
+ if( this != &obj )
+ {
+ if( oidString )
+ {
+ delete[] oidString;
+ oidString = NULL;
+ }
+
+ if( obj.oidString )
+ {
+ oidString = new char[ strlen(obj.oidString)+1 ];
+ strcpy( oidString, obj.oidString );
+ }
+
+ if( systemName )
+ {
+ delete[] systemName;
+ systemName = NULL;
+ }
+
+ if( obj.systemName )
+ {
+ systemName = new char[ strlen(obj.systemName)+1 ];
+ strcpy( systemName, obj.systemName );
+ }
+
+ if( baseName )
+ {
+ delete[] baseName;
+ baseName = NULL;
+ }
+
+ if( obj.baseName )
+ {
+ baseName = new char[ strlen(obj.baseName)+1 ];
+ strcpy( baseName, obj.baseName );
+ }
+
+ localOId = obj.localOId;
+ }
+
+ return *this;
+}
+
+bool
+r_OId::operator==( const r_OId& oid ) const
+{
+ bool equal = false;
+
+ if( oidString && oid.oidString )
+ equal = !strcmp( oidString, oid.oidString );
+
+ return equal;
+}
+
+bool
+r_OId::operator!=( const r_OId& oid ) const
+{
+ return !operator==( oid );
+}
+
+bool
+r_OId::operator> ( const r_OId& oid ) const
+{
+ int comparison;
+
+ if( systemName && oid.systemName )
+ {
+ comparison = strcmp( systemName, oid.systemName );
+
+ if( !comparison && baseName && oid.baseName )
+ {
+ comparison = strcmp( baseName, oid.baseName );
+
+ if( !comparison )
+ if( localOId < oid.localOId )
+ comparison = -1;
+ else if( localOId == oid.localOId )
+ comparison = 0;
+ else
+ comparison = 1;
+ }
+ }
+
+ return comparison > 0;
+}
+
+bool
+r_OId::operator< ( const r_OId& oid ) const
+{
+ int comparison;
+
+ if( systemName && oid.systemName )
+ {
+ comparison = strcmp( systemName, oid.systemName );
+
+ if( !comparison && baseName && oid.baseName )
+ {
+ comparison = strcmp( baseName, oid.baseName );
+
+ if( !comparison )
+ if( localOId < oid.localOId )
+ comparison = -1;
+ else if( localOId == oid.localOId )
+ comparison = 0;
+ else
+ comparison = 1;
+ }
+ }
+
+ return comparison < 0;
+}
+
+bool
+r_OId::operator>=( const r_OId& oid ) const
+{
+ return !operator< ( oid );
+}
+
+bool
+r_OId::operator<=( const r_OId& oid ) const
+{
+ return !operator> ( oid );
+}
+
+std::ostream& operator<<( std::ostream& s, const r_OId& oid )
+{
+ oid.print_status( s );
+ return s;
+}
+
diff --git a/raslib/oid.hh b/raslib/oid.hh
new file mode 100644
index 0000000..df2a824
--- /dev/null
+++ b/raslib/oid.hh
@@ -0,0 +1,137 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: oid.hh
+ *
+ * MODULE: raslib
+ * CLASS: r_OId
+ *
+ * COMMENTS:
+ * The class represents an object identifier (OId).
+ *
+*/
+
+#ifndef _D_OID_
+#define _D_OID_
+
+#include <iosfwd>
+
+//@ManMemo: Module: {\bf raslib}
+
+/*@Doc:
+
+ Class \Ref{r_OId} represents an object identifier.
+
+*/
+
+class r_OId
+{
+ public:
+ /// default constructor
+ r_OId();
+
+ /// constructs an OId from the string representation
+ r_OId( const char* );
+
+ /// constructor getting oid parts
+ r_OId( const char* initSystemName, const char* initBaseName, double initLocalOId );
+
+ /// copy constructor
+ r_OId( const r_OId& );
+
+ /// destructor
+ virtual ~r_OId();
+
+ /// it is called when an object leaves transient memory
+ virtual void r_deactivate();
+
+ /// debug output
+ void print_status(std::ostream& s) const;
+
+ /// operator for assigning an oid
+ const r_OId& operator= ( const r_OId& );
+
+ //@Man: Comparison operators:
+ //@{
+ ///
+
+ /// operator for equality
+ bool operator==( const r_OId& ) const;
+
+ /// operator for not equal
+ bool operator!=( const r_OId& ) const;
+
+ /// operator for greater than
+ bool operator> ( const r_OId& ) const;
+
+ /// operator for less than
+ bool operator< ( const r_OId& ) const;
+
+ /// operator for greater or equal than
+ bool operator>=( const r_OId& ) const;
+
+ /// operator for less than or equal
+ bool operator<=( const r_OId& ) const;
+
+ ///
+ //@}
+
+ /// gets the oid's string representation
+ inline const char* get_string_representation() const;
+
+ /// get system name
+ inline const char* get_system_name() const;
+
+ /// get base name
+ inline const char* get_base_name() const;
+
+ /// get local oid
+ inline double get_local_oid() const;
+
+ /// determines if oid is valid
+ inline bool is_valid() const;
+
+ private:
+ /// string representation
+ char* oidString;
+
+ /// system name
+ char* systemName;
+
+ /// base name
+ char* baseName;
+
+ /// local oid
+ double localOId;
+};
+
+
+
+//@ManMemo: Module: {\bf raslib}
+/**
+ Output stream operator for objects of type {\tt const} \Ref{r_Oid}.
+*/
+extern std::ostream& operator<<( std::ostream& s, const r_OId& oid );
+
+#include "raslib/oid.icc"
+#endif
diff --git a/raslib/oid.icc b/raslib/oid.icc
new file mode 100644
index 0000000..70b0ab1
--- /dev/null
+++ b/raslib/oid.icc
@@ -0,0 +1,62 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INLINE SOURCE: oid.icc
+ *
+ * MODULE: raslib
+ * CLASS: r_OId
+ *
+ * COMMENTS:
+ *
+*/
+
+inline const char*
+r_OId::get_string_representation() const
+{
+ return oidString;
+}
+
+inline const char*
+r_OId::get_system_name() const
+{
+ return systemName;
+}
+
+inline const char*
+r_OId::get_base_name() const
+{
+ return baseName;
+}
+
+inline double
+r_OId::get_local_oid() const
+{
+ return localOId;
+}
+
+inline bool
+r_OId::is_valid() const
+{
+ return localOId != 0;
+}
+
diff --git a/raslib/oidtype.cc b/raslib/oidtype.cc
new file mode 100644
index 0000000..df751c9
--- /dev/null
+++ b/raslib/oidtype.cc
@@ -0,0 +1,80 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+static const char rcsid[] = "@(#)raslib, r_Oid_Type: $Header: /home/rasdev/CVS-repository/rasdaman/raslib/oidtype.cc,v 1.6 2003/12/27 23:01:21 rasdev Exp $";
+
+#include "raslib/oidtype.hh"
+
+r_Oid_Type::r_Oid_Type()
+ : r_Type()
+{
+}
+
+bool
+r_Oid_Type::isOidType() const
+ {
+ return true;
+ }
+
+r_Oid_Type::r_Oid_Type( const r_Oid_Type& oldObj )
+ : r_Type(oldObj)
+{
+}
+
+r_Type*
+r_Oid_Type::clone() const
+{
+ return new r_Oid_Type( *this );
+}
+
+r_Type::r_Type_Id
+r_Oid_Type::type_id() const
+{
+ return OIDTYPE;
+}
+
+void
+r_Oid_Type::convertToLittleEndian(char* cells, r_Area noCells) const
+{
+}
+
+void
+r_Oid_Type::convertToBigEndian(char* cells, r_Area noCells) const
+{
+}
+
+void
+r_Oid_Type::print_status( std::ostream& s ) const
+{
+ s << "oid";
+}
+
+r_Oid_Type::~r_Oid_Type()
+{
+}
+
+std::ostream &operator<<( std::ostream &str, const r_Oid_Type &type )
+{
+ type.print_status(str);
+ return str;
+}
diff --git a/raslib/oidtype.hh b/raslib/oidtype.hh
new file mode 100644
index 0000000..e3018de
--- /dev/null
+++ b/raslib/oidtype.hh
@@ -0,0 +1,79 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: oidtype.hh
+ *
+ * MODULE: raslib
+ * CLASS: r_Oid_Type
+ *
+ * COMMENTS:
+ *
+*/
+
+#ifndef _D_OID_TYPE_
+#define _D_OID_TYPE_
+
+#include "raslib/type.hh"
+
+//@ManMemo: Module: {\bf raslib}
+
+/*@Doc:
+ This class represents the oid type in the ODMG conformant
+ representation of the RasDaMan type system.
+*/
+
+class r_Oid_Type : public r_Type
+{
+public:
+ /// default constructor
+ r_Oid_Type();
+
+ /// copy constructor
+ r_Oid_Type( const r_Oid_Type& oldObj );
+
+ /// clone operation
+ virtual r_Type* clone() const;
+
+ /// retrieve id of the type.
+ virtual r_Type::r_Type_Id type_id() const;
+
+ /// converts array of cells from NT byte order to Unix byte order.
+ virtual void convertToLittleEndian(char* cells, r_Area noCells) const;
+
+ /// converts array of cells from Unix byte order to NT byte order.
+ virtual void convertToBigEndian(char* cells, r_Area noCells) const;
+
+ /// writes state of object to specified stream
+ virtual void print_status( std::ostream& s = std::cout ) const;
+
+ virtual bool isOidType() const;
+
+ /// destructor
+ ~r_Oid_Type();
+};
+
+//@Doc: write the status of a oid type to a stream
+extern std::ostream &operator<<( std::ostream &str, const r_Oid_Type &type );
+
+#endif
+
diff --git a/raslib/parseparams.cc b/raslib/parseparams.cc
new file mode 100644
index 0000000..963d68f
--- /dev/null
+++ b/raslib/parseparams.cc
@@ -0,0 +1,283 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: parseparams.cc
+ *
+ * MODULE: raslib
+ * CLASS: r_Parse_Params
+ *
+ * COMMENTS:
+ *
+*/
+
+#include "mymalloc/mymalloc.h"
+
+#include <cstdio>
+#include <cstdlib>
+#include <cctype>
+#include <cstring>
+#include <cerrno>
+
+extern int errno;
+
+#include "raslib/rminit.hh"
+#include "raslib/rmdebug.hh"
+
+#include "raslib/parseparams.hh"
+
+
+
+const unsigned int r_Parse_Params::granularity = 4;
+
+r_Parse_Params::r_Parse_Params( void )
+{
+ params = NULL;
+ number = 0;
+ maxnum = 0;
+}
+
+
+r_Parse_Params::r_Parse_Params( unsigned int num )
+{
+ number = 0;
+ maxnum = num;
+ params = (parse_params_t*)mymalloc(maxnum * sizeof(parse_params_t));
+}
+
+
+r_Parse_Params::~r_Parse_Params( void )
+{
+ if (params != NULL)
+ free(params);
+}
+
+
+int r_Parse_Params::add( const char *key, void *store, parse_param_type type )
+{
+
+ RMDBGONCE(2, RMDebug::module_raslib, "r_Parse_Params", "add('"
+ << (key?key:"NULL") << "', "
+ << (store?store:"NULL") << ","
+ << type << ")");
+
+ if (number >= maxnum)
+ {
+ maxnum += granularity;
+ if (params == NULL)
+ params = (parse_params_t*)mymalloc(maxnum * sizeof(parse_params_t));
+ else
+ params = (parse_params_t*)realloc(params, maxnum * sizeof(parse_params_t));
+
+ if (params == NULL)
+ {
+ maxnum = 0; return -1;
+ }
+ }
+ params[number].key = key;
+ params[number].store = store;
+ params[number].type = type;
+ number++;
+
+ return 0;
+}
+
+
+int r_Parse_Params::process( const char *str ) const
+{
+ static const int lenBuff=256;
+ static char buff[lenBuff];
+ int numkeys = 0;
+ const char *b = str;
+
+ RMDBGONCE(2, RMDebug::module_raslib, "r_Parse_Params", "process('" << (str?str:"NULL") << ")");
+
+ if ( (number == 0) ||
+ (str == NULL) ||
+ (!strcmp(str,"")) ) {
+ return 0;
+ }
+
+ while (*b != '\0')
+ {
+ //cout << numkeys << '(' << b << ')' << std::endl;
+ while ((isspace((unsigned int)(*b))) || (*b == ',')) b++;
+ if (*b == '\0') break;
+ if (isalpha((unsigned int)(*b)))
+ {
+ const char *key = b;
+ unsigned int klen;
+ int knum;
+ int inquotes;
+
+ while (isalnum((unsigned int)(*b))) b++;
+
+ //store current item
+ klen = (b - key);
+ memset(buff,0, lenBuff);
+ memcpy(buff, key, klen);
+ for (knum=0; knum<number; knum++)
+ {
+ if (strcmp(buff, params[knum].key) == 0)
+ break;
+ }
+ // we actually understand this key
+ if (knum < number)
+ {
+ int statval = 0; // status: -1 error, 0 not found, 1 OK
+
+ while (isspace((unsigned int)(*b))) b++;
+ if (*b == '=')
+ {
+ b++;
+ while (isspace((unsigned int)(*b))) b++;
+ if ((*b != ',') && (*b != '\0'))
+ {
+ const char *aux=b;
+
+ switch (params[knum].type)
+ {
+ case param_type_int:
+ {
+ int val=0;
+
+ errno=0;
+ val = strtol(b, (char**)&aux, 10);
+ if ((b == aux) || errno)
+ statval = -1;
+ else
+ {
+ int *vptr = (int*)(params[knum].store);
+ *vptr = val;
+ b = aux; statval = 1;
+ }
+ }
+ break;
+ case param_type_double:
+ {
+ double val=0.;
+
+ errno=0;
+ val = strtod(b, (char**)&aux);
+ if ((b == aux) || errno)
+ statval = -1;
+ else
+ {
+ double *vptr = (double*)(params[knum].store);
+ *vptr = val;
+ b = aux; statval = 1;
+ }
+ }
+ break;
+ case param_type_string:
+ {
+ unsigned int vlen = 0;
+
+ if (*b == '\"')
+ {
+ aux = ++b;
+ while ((*b != '\"') && (*b != '\0')) b++;
+ if (*b == '\0')
+ statval = -1;
+ else
+ {
+ vlen = (b - aux);
+ b++; statval = 1;
+ }
+ }
+ else
+ {
+ aux = b;
+ while ((!isspace((unsigned int)(*b))) && (*b != '\0') && (*b != ',')) b++;
+ vlen = (b - aux); statval = 1;
+ }
+ if (vlen > 0)
+ {
+ char **vptr = (char**)(params[knum].store);
+ if (*vptr != NULL)
+ delete [] *vptr;
+ *vptr = new char[vlen+1];
+ strncpy(*vptr, aux, vlen);
+ (*vptr)[vlen] = '\0';
+ }
+ }
+ break;
+ }
+ }
+ }
+ switch (statval)
+ {
+ case -1:
+ RMInit::logOut << "r_Parse_Params::process('" << str << "'): error parsing value for keyword " << params[knum].key << std::endl;
+ return -1;
+ case 0:
+ RMInit::logOut << "r_Parse_Params::process('" << str << "'): keyword " << params[knum].key << " without value" << std::endl;
+ return -1;
+ case 1:
+ numkeys++;
+ break;
+ default:
+ break;
+ }
+ }
+ inquotes = 0;
+ while (((*b != ',') || (inquotes != 0)) && (*b != '\0'))
+ {
+ if (*b == '\"')
+ inquotes ^= 1;
+ b++;
+ }
+ if (inquotes != 0)
+ {
+ RMInit::logOut << "r_Parse_Params::process('" << str << "'): unterminated string" << std::endl;
+ return -1;
+ }
+ }
+ else
+ {
+ RMInit::logOut << "r_Parse_Params::process('" << str << "'): the string must start with alphabetic character" << std::endl;
+ return -1;
+ }
+ }
+
+ return numkeys;
+}
+
+std::ostream& operator<<( std::ostream& s, const r_Parse_Params::parse_param_type& d )
+{
+ switch( d )
+ {
+ case r_Parse_Params::param_type_int:
+ s << "param_type_int";
+ break;
+ case r_Parse_Params::param_type_double:
+ s << "param_type_double";
+ break;
+ case r_Parse_Params::param_type_string:
+ s << "param_type_string";
+ break;
+ default:
+ s << "UNKNOWN r_Parse_Params::parse_paramt_type" << d;
+ break;
+ }
+ return s;
+}
diff --git a/raslib/parseparams.hh b/raslib/parseparams.hh
new file mode 100644
index 0000000..b5ebed6
--- /dev/null
+++ b/raslib/parseparams.hh
@@ -0,0 +1,116 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: parseparams.hh
+ *
+ * MODULE: raslib
+ * CLASS: r_Parse_Params
+ *
+ * COMMENTS:
+ *
+*/
+
+#ifndef _PARSE_PARAMS_HH_
+#define _PARSE_PARAMS_HH_
+
+#include <iosfwd>
+
+//@ManMemo: Module {\bf raslib}
+
+/*@Doc:
+ Class for parsing a string consisting of key=value pairs separated by ",".
+*/
+
+class r_Parse_Params
+{
+public:
+
+ /// the possible parameter types used for add()
+ enum parse_param_type {
+ param_type_int,
+ param_type_double,
+ param_type_string
+ };
+ /**
+ Possible parameter types and their corresponding C types are
+
+ \begin{tabular}{ll}
+ param_type_int && int\\
+ param_type_double && double\\
+ param_type_string && char*\\
+ \end{tabular}
+ */
+
+ struct parse_params_s;
+
+ /// default constructor, should not be used
+ r_Parse_Params( void );
+ /// constructor, gets descriptor of the values to scan for
+ r_Parse_Params( unsigned int num );
+ /// destructor
+ ~r_Parse_Params( void );
+ /// add parameters to the list
+ int add( const char *key, void *store, parse_param_type type );
+ /**
+ Add a parameter to the list. key is the keyword, e.g. ``quality'', type
+ is one of the available types and describes the data type of the parameter
+ and store is a pointer to a variable of this type that will be updated
+ by process() if the parameter is encountered there. The variable pointed
+ to by store must not be initalized except for param_type_string where it
+ must be set to NULL before calling process() for the first time. The contents
+ of a string variable must be freed by the caller by first checking whether
+ the variable is NULL and if not doing a delete [] <var>.
+ */
+ /// process parameter string
+ int process( const char *str ) const;
+ /**
+ process the parameter string. Returns the number of keywords found
+ or -1 for error.
+ */
+
+
+protected:
+ //@Man: The parameter descriptor
+ //@{
+ typedef struct parse_params_s {
+ const char *key;
+ void *store;
+ parse_param_type type;
+ } parse_params_t;
+ //@}
+
+ parse_params_t *params;
+ unsigned int maxnum;
+ unsigned int number;
+
+ static const unsigned int granularity;
+};
+
+//@ManMemo: Module: {\bf raslib}
+/**
+ Output stream operator for objects of type {\tt const} \Ref{r_Parse_Params::parse_param_type}.
+ */
+extern std::ostream& operator<<( std::ostream& s, const r_Parse_Params::parse_param_type& d );
+
+
+#endif
diff --git a/raslib/point.cc b/raslib/point.cc
new file mode 100644
index 0000000..8679dc5
--- /dev/null
+++ b/raslib/point.cc
@@ -0,0 +1,372 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: point.cc
+ *
+ * MODULE: raslib
+ * CLASS: r_Point
+ *
+ * COMMENTS:
+ *
+*/
+
+static const char rcsid[] = "@(#)raslib, r_Point: $Id: point.cc,v 1.22 2002/08/28 11:58:13 coman Exp $";
+
+#include "point.hh"
+
+#include <string.h>
+#ifdef __VISUALC__
+#include <strstrea.h>
+#else
+#include <strstream>
+#endif
+
+#include "raslib/rminit.hh"
+#include "raslib/error.hh"
+
+r_Point::r_Point( char* stringRep ) throw (r_Error)
+ : dimensionality(1), streamInitCnt(0), points(NULL)
+{
+ char charToken = 0;
+ r_Range valueToken = 0;
+
+ // for parsing the string
+ std::istrstream str( stringRep, strlen(stringRep) + 1 );
+
+ // calculate dimensionality
+ char* p = stringRep;
+ while(p = strchr(++p, ','))
+ dimensionality++;
+
+ // allocate space for intervals
+ points = new r_Range[ dimensionality ];
+
+ str >> charToken;
+ if(charToken != '[')
+ {
+ // error
+ dimensionality = 0;
+ delete[] points;
+ points = NULL;
+ throw r_Error(NOPOINT);
+ }
+
+ for( r_Dimension i=0; i<dimensionality; i++ )
+ {
+ str >> valueToken;
+ points[i] = valueToken;
+
+ if( i < dimensionality-1 )
+ {
+ str >> charToken;
+ if(charToken != ',')
+ {
+ // error
+ dimensionality = 0;
+ delete[] points;
+ points = NULL;
+ throw r_Error(NOPOINT);
+ }
+ }
+ }
+}
+
+
+r_Point::r_Point( r_Dimension dim )
+ : dimensionality( dim ),
+ streamInitCnt(0)
+{
+ points = new r_Range[ dimensionality ];
+
+ for( r_Dimension i=0; i< dimensionality; i++ )
+ points[i] = 0;
+}
+
+
+r_Point& r_Point::operator<<( r_Range newElement ) throw( r_Einit_overflow )
+{
+ if( streamInitCnt >= dimensionality )
+ {
+ RMInit::logOut << "r_Point::operator<<(" << newElement << ") already fully initialised" << endl;
+ throw r_Einit_overflow();
+ }
+
+ points[streamInitCnt++] = newElement;
+ return *this;
+}
+
+
+r_Point::r_Point( r_Range p1, r_Range p2 )
+ : dimensionality(2),
+ streamInitCnt(2)
+{
+ points = new r_Range[dimensionality];
+ points[0] = p1;
+ points[1] = p2;
+}
+
+
+r_Point::r_Point( r_Range p1, r_Range p2, r_Range p3 )
+ : dimensionality(3),
+ streamInitCnt(3)
+{
+ points = new r_Range[dimensionality];
+ points[0] = p1;
+ points[1] = p2;
+ points[2] = p3;
+}
+
+
+r_Point::r_Point( r_Range p1, r_Range p2, r_Range p3, r_Range p4 )
+ : dimensionality(4),
+ streamInitCnt(4)
+{
+ points = new r_Range[dimensionality];
+ points[0] = p1;
+ points[1] = p2;
+ points[2] = p3;
+ points[3] = p4;
+}
+
+
+r_Point::r_Point( r_Range p1, r_Range p2, r_Range p3, r_Range p4, r_Range p5 )
+ : dimensionality(5),
+ streamInitCnt(5)
+{
+ points = new r_Range[dimensionality];
+ points[0] = p1;
+ points[1] = p2;
+ points[2] = p3;
+ points[3] = p4;
+ points[4] = p5;
+}
+
+
+r_Point::r_Point()
+ : dimensionality(0),
+ streamInitCnt(0),
+ points(NULL)
+{
+}
+
+
+r_Point::r_Point( const r_Point& pt )
+ : dimensionality(pt.dimensionality),
+ streamInitCnt(pt.streamInitCnt),
+ points(new r_Range[pt.dimensionality])
+{
+ for( r_Dimension i=0; i<dimensionality; i++ )
+ points[i] = pt[i];
+}
+
+
+r_Point::~r_Point()
+{
+ if( points )
+ {
+ delete[] points;
+ points = NULL;
+ }
+}
+
+
+r_Range
+r_Point::operator[]( r_Dimension i ) const throw( r_Eindex_violation )
+{
+ if( i < 0 || i >= dimensionality )
+ {
+ RMInit::logOut << "r_Point::operator[](" << i << ") const dimension out of bounds (" << dimensionality << ")" << endl;
+ throw r_Eindex_violation( 0, dimensionality-1, i );
+ }
+
+ return points[i];
+}
+
+
+r_Range&
+r_Point::operator[]( r_Dimension i ) throw( r_Eindex_violation )
+{
+ if( i < 0 || i >= dimensionality )
+ {
+ RMInit::logOut << "r_Point::operator[](" << i << ") dimension out of bounds (" << dimensionality << ")" << endl;
+ throw r_Eindex_violation( 0, dimensionality-1, i );
+ }
+
+ return points[i];
+}
+
+
+const r_Point&
+r_Point::operator=( const r_Point& pt )
+{
+ if( this != &pt )
+ {
+ if( points && dimensionality != pt.dimension() )
+ {
+ delete[] points;
+ points = NULL;
+ }
+
+ dimensionality = pt.dimension();
+ streamInitCnt = dimensionality;
+
+ if( !points )
+ points = new r_Range[ dimensionality ];
+
+ for( r_Dimension i=0; i<dimensionality; i++ )
+ points[i] = pt[i];
+
+ }
+
+ return *this;
+}
+
+
+
+bool
+r_Point::operator==( const r_Point& pt ) const
+{
+ bool returnValue = false;
+
+ if( dimensionality == pt.dimensionality )
+ {
+ returnValue = true;
+
+ for( r_Dimension i=0; i<dimensionality && returnValue ; i++ )
+ {
+ if (points[i] != pt[i])
+ {
+ returnValue = false;
+ break;
+ }
+ }
+ }
+
+ return returnValue;
+}
+
+
+
+bool
+r_Point::operator!=( const r_Point& pt ) const
+{
+ return !operator==( pt );
+}
+
+
+
+r_Point
+r_Point::operator+( const r_Point& pt ) const throw( r_Edim_mismatch )
+{
+ if( dimensionality != pt.dimension() )
+ {
+ RMInit::logOut << "r_Point::operator+(" << pt << ") dimensions (" << dimensionality << ") do not match" << endl;
+ throw r_Edim_mismatch( dimensionality, pt.dimension() );
+ }
+
+ r_Point result( dimensionality );
+
+ for( r_Dimension i=0; i<dimensionality; i++ )
+ result[i] = points[i] + pt[i];
+
+ return result;
+}
+
+r_Point
+r_Point::operator-( const r_Point& pt ) const throw( r_Edim_mismatch )
+{
+ if( dimensionality != pt.dimension() )
+ {
+ RMInit::logOut << "r_Point::operator-(" << pt << ") dimensions (" << dimensionality << ") do not match" << endl;
+ throw r_Edim_mismatch( dimensionality, pt.dimension() );
+ }
+
+ r_Point result( dimensionality );
+
+ for( r_Dimension i=0; i<dimensionality; i++ )
+ result[i] = points[i] - pt[i];
+
+ return result;
+}
+
+r_Point
+r_Point::operator*( const r_Point& pt ) const throw( r_Edim_mismatch )
+{
+ if( dimensionality != pt.dimension() )
+ {
+ RMInit::logOut << "r_Point::operator*(" << pt << ") dimensions (" << dimensionality << ") do not match" << endl;
+ throw r_Edim_mismatch( dimensionality, pt.dimension() );
+ }
+
+ r_Point result( dimensionality );
+
+ for( r_Dimension i=0; i<dimensionality; i++ )
+ result[i] = points[i] * pt[i];
+
+ return result;
+}
+
+void
+r_Point::print_status( std::ostream& s ) const
+{
+ s << "[";
+
+ if( dimensionality > 0 )
+ {
+ for( r_Dimension i=0; i<dimensionality-1; i++ )
+ s << points[i] << ",";
+
+ s << points[dimensionality-1];
+ }
+
+ s << "]";
+}
+
+
+char*
+r_Point::get_string_representation() const
+{
+ r_Bytes bufferSize = dimensionality*25+3; // should be enough
+
+ // allocate buffer and initialize string stream
+ char* buffer = new char[bufferSize];
+ std::ostrstream domainStream( buffer, bufferSize );
+
+ // write into string stream
+ domainStream << (*this) << std::ends;
+
+ // allocate memory taking the final string
+ char* returnString = strdup(buffer);
+
+ // delete buffer
+ delete[] buffer;
+
+ return returnString;
+}
+
+std::ostream& operator<<( std::ostream& s, const r_Point& d )
+{
+ d.print_status( s );
+ return s;
+}
+
diff --git a/raslib/point.hh b/raslib/point.hh
new file mode 100644
index 0000000..6f6e634
--- /dev/null
+++ b/raslib/point.hh
@@ -0,0 +1,165 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: point.hh
+ *
+ * MODULE: raslib
+ * CLASS: r_Point
+ *
+ * COMMENTS:
+ *
+*/
+
+#ifndef _D_POINT_
+#define _D_POINT_
+
+#ifdef __VISUALC__
+// disable warning for exception specification
+#pragma warning( disable : 4290 )
+#endif
+
+class r_Error;
+class r_Einit_overflow;
+class r_Eindex_violation;
+class r_Edim_mismatch;
+
+#include "raslib/mddtypes.hh"
+#include "raslib/error.hh"
+
+#include <iostream>
+
+//@ManMemo: Module: {\bf raslib}
+
+/*@Doc:
+
+ Class \Ref{r_Point} represents an n-dimensional point vector.
+
+*/
+
+class r_Point
+{
+ public:
+ /// constructor getting dimensionality for stream initializing
+ r_Point( r_Dimension );
+
+ /// stream-input operator for stream initializing
+ r_Point& operator<<( r_Range ) throw( r_Einit_overflow );
+
+ /// constructor taking string representation (e.g. [ 1, 2, 3])
+ r_Point( char* ) throw( r_Error );
+
+ //@Man: 'easy-to-use' constructors
+ //@{
+ ///
+ r_Point( r_Range, r_Range );
+ ///
+ r_Point( r_Range, r_Range, r_Range );
+ ///
+ r_Point( r_Range, r_Range, r_Range, r_Range );
+ ///
+ r_Point( r_Range, r_Range, r_Range, r_Range, r_Range );
+ ///
+ //@}
+
+ /// default constructor
+ r_Point();
+
+ /// copy constructor
+ r_Point( const r_Point& );
+
+ /// destructor: cleanup dynamic memory
+ ~r_Point();
+
+ /// subscriptor for read access
+ r_Range operator[]( r_Dimension ) const throw( r_Eindex_violation );
+ /// subscriptor for write access
+ r_Range& operator[]( r_Dimension ) throw( r_Eindex_violation );
+
+ /// assignment: cleanup + copy
+ const r_Point& operator= ( const r_Point& );
+
+ /// compares this point with the given point.
+ inline const int compare_with( const r_Point& p ) const;
+ /**
+ Returns 0 if this == p, -1 if this < p, 1 if this > p (considering
+ the coordinates in decreasing order of magnitude).
+ */
+
+ /// equal operator
+ bool operator==( const r_Point& ) const;
+
+ /**
+ Two points are equal if they have the same number of dimensions and
+ the same values.
+ */
+
+ /// non equal operator - negation of equal operator
+ bool operator!=( const r_Point& ) const;
+
+ /// vector addition
+ r_Point operator+( const r_Point& ) const
+ throw( r_Edim_mismatch );
+
+ /// vector subtraction
+ r_Point operator-( const r_Point& ) const
+ throw( r_Edim_mismatch );
+
+ /// vector multiplication
+ r_Point operator*( const r_Point& ) const
+ throw( r_Edim_mismatch );
+
+ /// get dimensionality
+ inline r_Dimension dimension() const;
+
+ /// writes the state of the object to the specified stream
+ void print_status( std::ostream& s = std::cout ) const;
+
+ /// gives back the string representation
+ char* get_string_representation() const;
+ /**
+ The string representation delivered by this method is allocated using {\tt malloc()} and
+ has to be free unsing {\tt free()} in the end. It can be used to construct a {\tt r_Point}
+ again with a special constructor provided. The string representation is build using
+ {\tt print_status()}.
+ */
+
+ private:
+ /// array holding the point coordinates
+ r_Range* points;
+ /// dimensionality of the point
+ r_Dimension dimensionality;
+ /// number of components initialized already
+ r_Dimension streamInitCnt;
+};
+
+
+
+//@ManMemo: Module: {\bf raslib}
+/**
+ Output stream operator for objects of type {\tt const} \Ref{r_Point}.
+*/
+extern std::ostream& operator<<( std::ostream& s, const r_Point& d );
+
+#include "raslib/point.icc"
+
+#endif
diff --git a/raslib/point.icc b/raslib/point.icc
new file mode 100644
index 0000000..5bbbd27
--- /dev/null
+++ b/raslib/point.icc
@@ -0,0 +1,54 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INLINE SOURCE: point.icc
+ *
+ * MODULE: raslib
+ * CLASS: r_Point
+ *
+ * COMMENTS:
+ *
+*/
+
+inline r_Dimension
+r_Point::dimension() const
+{
+ return dimensionality;
+};
+
+const int
+r_Point::compare_with( const r_Point& p ) const
+{
+ if( dimensionality != p.dimensionality )
+ return -2;
+
+ for ( r_Dimension i = 0; i < dimensionality; i++ )
+ {
+ if ( points[i] > p[i] )
+ return 1;
+ if ( points[i] < p[i] )
+ return -1 ;
+ }
+ return 0;
+}
+
diff --git a/raslib/pointtype.cc b/raslib/pointtype.cc
new file mode 100644
index 0000000..0a4f1a0
--- /dev/null
+++ b/raslib/pointtype.cc
@@ -0,0 +1,81 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+static const char rcsid[] = "@(#)raslib, r_Point_Type: $Header: /home/rasdev/CVS-repository/rasdaman/raslib/pointtype.cc,v 1.6 2003/12/27 23:01:21 rasdev Exp $";
+
+#include "raslib/pointtype.hh"
+
+r_Point_Type::r_Point_Type()
+ : r_Type()
+{
+}
+
+r_Point_Type::r_Point_Type( const r_Point_Type& oldObj )
+ : r_Type(oldObj)
+{
+}
+
+r_Type*
+r_Point_Type::clone() const
+{
+ return new r_Point_Type( *this );
+}
+
+r_Type::r_Type_Id
+r_Point_Type::type_id() const
+{
+ return POINTTYPE;
+}
+
+void
+r_Point_Type::convertToLittleEndian(char* cells, unsigned int noCells)
+ const
+{
+}
+
+void
+r_Point_Type::convertToBigEndian(char* cells, unsigned int noCells) const
+{
+}
+
+void
+r_Point_Type::print_status( std::ostream& s ) const
+{
+ s << "point";
+}
+
+r_Point_Type::~r_Point_Type()
+{
+}
+
+bool
+r_Point_Type::isPointType() const
+ {
+ return true;
+ }
+
+std::ostream &operator<<( std::ostream &str, const r_Point_Type &type )
+{
+ type.print_status(str);
+ return str;
+}
diff --git a/raslib/pointtype.hh b/raslib/pointtype.hh
new file mode 100644
index 0000000..53a1d26
--- /dev/null
+++ b/raslib/pointtype.hh
@@ -0,0 +1,81 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: pointtype.hh
+ *
+ * MODULE: raslib
+ * CLASS: r_Point_Type
+ *
+ * COMMENTS:
+ *
+*/
+
+#ifndef _D_POINT_TYPE_
+#define _D_POINT_TYPE_
+
+#include "raslib/type.hh"
+
+//@ManMemo: Module: {\bf raslib}
+
+/*@Doc:
+ This class represents the point type in the ODMG conformant
+ representation of the RasDaMan type system.
+*/
+
+class r_Point_Type : public r_Type
+{
+public:
+ /// default constructor
+ r_Point_Type();
+
+ /// copy constructor
+ r_Point_Type( const r_Point_Type& oldObj );
+
+ /// clone operation
+ virtual r_Type* clone() const;
+
+ /// retrieve id of the type.
+ virtual r_Type::r_Type_Id type_id() const;
+
+ /// converts array of cells from NT byte order to Unix byte order.
+ virtual void convertToLittleEndian(char* cells, unsigned int noCells) const;
+
+ /// converts array of cells from Unix byte order to NT byte order.
+ virtual void convertToBigEndian(char* cells, unsigned int noCells) const;
+
+ /// writes state of object to specified stream
+ virtual void print_status( std::ostream& s = std::cout ) const;
+
+ virtual bool isPointType() const;
+
+ /// destructor
+ ~r_Point_Type();
+};
+
+//@Doc: write the status of point type to a stream
+extern std::ostream &operator<<( std::ostream &str, const r_Point_Type &type );
+
+#endif
+
+
+
diff --git a/raslib/primitive.cc b/raslib/primitive.cc
new file mode 100644
index 0000000..a9ffc1e
--- /dev/null
+++ b/raslib/primitive.cc
@@ -0,0 +1,439 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: primitive.cc
+ *
+ * MODULE: raslib
+ * CLASS: r_Primitive
+ *
+ * COMMENTS:
+ *
+*/
+
+#include "mymalloc/mymalloc.h"
+
+#include "raslib/primitive.hh"
+#include "raslib/primitivetype.hh"
+#include "raslib/rminit.hh"
+#include "raslib/error.hh"
+
+#ifdef __VISUALC__
+#include <strstrea.h>
+#else
+#include <strstream>
+#endif
+#include <string.h>
+#include <fstream>
+#include <stdlib.h>
+
+r_Primitive::r_Primitive( const char* newBuffer, const r_Primitive_Type* newType )
+ : r_Scalar( newType )
+{
+ if( valueType )
+ {
+ valueBuffer = (char*)mymalloc( valueType->size() );
+ if( newBuffer)
+ memcpy( (void*)valueBuffer, (void*)newBuffer, valueType->size() );
+ else
+ memset( (void*)valueBuffer, 0, valueType->size() );
+ }
+}
+
+r_Primitive::r_Primitive( const r_Primitive& obj )
+ : r_Scalar( obj ),
+ valueBuffer(NULL)
+{
+ valueBuffer = (char*)mymalloc( valueType->size() );
+ if( obj.valueBuffer )
+ memcpy( (void*)valueBuffer, (void*)obj.valueBuffer, valueType->size() );
+ else
+ memset( (void*)valueBuffer, 0, valueType->size());
+}
+
+r_Primitive::~r_Primitive()
+{
+ if( valueBuffer ) free( valueBuffer );
+}
+
+bool
+r_Primitive::isPrimitive() const
+ {
+ return true;
+ }
+
+r_Scalar*
+r_Primitive::clone() const
+{
+ return new r_Primitive( *this );
+}
+
+
+
+const r_Primitive&
+r_Primitive::operator=( const r_Primitive& obj )
+{
+ if( this != &obj )
+ {
+ // assign scalar
+ r_Scalar::operator=( obj );
+
+ if( valueBuffer )
+ {
+ free( valueBuffer );
+ valueBuffer = NULL;
+ }
+
+ if( valueType )
+ {
+ valueBuffer = (char*)mymalloc( valueType->size() );
+ if( obj.valueBuffer )
+ memcpy( (void*)valueBuffer, (void*)obj.valueBuffer, valueType->size() );
+ else
+ memset((void*)valueBuffer, 0, valueType->size());
+ }
+ }
+
+ return *this;
+}
+
+
+
+const char*
+r_Primitive::get_buffer() const
+{
+ return valueBuffer;
+}
+
+
+
+void
+r_Primitive::print_status( std::ostream& s ) const
+{
+ if( valueType && valueBuffer )
+ valueType->print_value( valueBuffer, s );
+ else
+ s << "<nn>" << std::flush;
+}
+
+
+
+r_Boolean
+r_Primitive::get_boolean() const throw( r_Error )
+{
+ if( !valueBuffer || !valueType )
+ {
+ RMInit::logOut << "r_Primitive::get_boolean() buffer null or type null " << endl;
+ r_Error err( r_Error::r_Error_TypeInvalid );
+ throw err;
+ }
+
+ return ((r_Primitive_Type*)valueType)->get_boolean(valueBuffer);
+}
+
+
+
+r_Char
+r_Primitive::get_char() const throw( r_Error )
+{
+ if( !valueBuffer || !valueType)
+ {
+ RMInit::logOut << "r_Primitive::get_char() buffer null or type null" << endl;
+ r_Error err( r_Error::r_Error_TypeInvalid );
+ throw err;
+ }
+
+ return ((r_Primitive_Type*)valueType)->get_char(valueBuffer);
+}
+
+
+
+r_Octet
+r_Primitive::get_octet() const throw( r_Error )
+{
+ if( !valueBuffer || !valueType )
+ {
+ RMInit::logOut << "r_Primitive::get_octet() buffer null or type null" << endl;
+ r_Error err( r_Error::r_Error_TypeInvalid );
+ throw err;
+ }
+
+ return ((r_Primitive_Type*)valueType)->get_octet(valueBuffer);
+}
+
+
+
+r_Short
+r_Primitive::get_short() const throw( r_Error )
+{
+ if( !valueBuffer || !valueType )
+ {
+ RMInit::logOut << "r_Primitive::get_short() buffer null or type null" << endl;
+ r_Error err( r_Error::r_Error_TypeInvalid );
+ throw err;
+ }
+
+ return ((r_Primitive_Type*)valueType)->get_short(valueBuffer);
+}
+
+
+
+r_UShort
+r_Primitive::get_ushort() const throw( r_Error )
+{
+ if( !valueBuffer || !valueType )
+ {
+ RMInit::logOut << "r_Primitive::get_ushort() buffer null or type null" << endl;
+ r_Error err( r_Error::r_Error_TypeInvalid );
+ throw err;
+ }
+
+ return ((r_Primitive_Type*)valueType)->get_ushort(valueBuffer);
+}
+
+
+
+r_Long
+r_Primitive::get_long() const throw( r_Error )
+{
+ if( !valueBuffer || !valueType )
+ {
+ RMInit::logOut << "r_Primitive::get_long() buffer null or type null" << endl;
+ r_Error err( r_Error::r_Error_TypeInvalid );
+ throw err;
+ }
+
+ return ((r_Primitive_Type*)valueType)->get_long(valueBuffer);
+}
+
+
+
+r_ULong
+r_Primitive::get_ulong() const throw( r_Error )
+{
+ if( !valueBuffer || !valueType )
+ {
+ RMInit::logOut << "r_Primitive::get_ulong() buffer null or type null" << endl;
+ r_Error err( r_Error::r_Error_TypeInvalid );
+ throw err;
+ }
+
+ return ((r_Primitive_Type*)valueType)->get_ulong(valueBuffer);
+}
+
+
+
+r_Float
+r_Primitive::get_float() const throw( r_Error )
+{
+ if( !valueBuffer || !valueType )
+ {
+ RMInit::logOut << "r_Primitive::get_float() buffer null or type null" << endl;
+ r_Error err( r_Error::r_Error_TypeInvalid );
+ throw err;
+ }
+
+ return ((r_Primitive_Type*)valueType)->get_float(valueBuffer);
+}
+
+
+
+r_Double
+r_Primitive::get_double() const throw( r_Error )
+{
+ if( !valueBuffer || !valueType )
+ {
+ RMInit::logOut << "r_Primitive::get_double() buffer null or type null" << endl;
+ r_Error err( r_Error::r_Error_TypeInvalid );
+ throw err;
+ }
+
+ return ((r_Primitive_Type*)valueType)->get_double(valueBuffer);
+}
+
+
+void
+r_Primitive::set_boolean(r_Boolean val) throw( r_Error )
+{
+ if( !valueType || valueType->type_id() != r_Type::BOOL )
+ {
+ RMInit::logOut << "r_Primitive::set_boolean(" << val << ") not a boolean" << endl;
+ r_Error err( r_Error::r_Error_TypeInvalid );
+ throw err;
+ }
+
+ if( !valueBuffer )
+ valueBuffer = (char*)mymalloc( valueType->size());
+
+ memmove(valueBuffer, &val, valueType->size());
+}
+
+
+
+void
+r_Primitive::set_char(r_Char val) throw( r_Error )
+{
+ if( !valueType || valueType->type_id() != r_Type::CHAR )
+ {
+ RMInit::logOut << "r_Primitive::set_char(" << val << ") not a char" << endl;
+ r_Error err( r_Error::r_Error_TypeInvalid );
+ throw err;
+ }
+
+ if( !valueBuffer )
+ valueBuffer = (char*)mymalloc( valueType->size());
+
+ memmove(valueBuffer, &val, valueType->size());
+}
+
+
+
+void
+r_Primitive::set_octet(r_Octet val) throw( r_Error )
+{
+ if( !valueType || valueType->type_id() != r_Type::OCTET )
+ {
+ RMInit::logOut << "r_Primitive::set_octet(" << val << ") not a octet" << endl;
+ r_Error err( r_Error::r_Error_TypeInvalid );
+ throw err;
+ }
+
+ if( !valueBuffer )
+ valueBuffer = (char*)mymalloc( valueType->size());
+
+ memmove(valueBuffer, &val, valueType->size());
+}
+
+
+
+void
+r_Primitive::set_short(r_Short val) throw( r_Error )
+{
+ if( !valueType || valueType->type_id() != r_Type::SHORT )
+ {
+ RMInit::logOut << "r_Primitive::set_short(" << val << ") not a short" << endl;
+ r_Error err( r_Error::r_Error_TypeInvalid );
+ throw err;
+ }
+
+ if( !valueBuffer )
+ valueBuffer = (char*)mymalloc( valueType->size());
+
+ memmove(valueBuffer, &val, valueType->size());
+}
+
+
+
+void
+r_Primitive::set_ushort(r_UShort val) throw( r_Error )
+{
+ if( !valueType || valueType->type_id() != r_Type::USHORT )
+ {
+ RMInit::logOut << "r_Primitive::set_ushort(" << val << ") not a ushort" << endl;
+ r_Error err( r_Error::r_Error_TypeInvalid );
+ throw err;
+ }
+
+ if( !valueBuffer )
+ valueBuffer = (char*)mymalloc( valueType->size());
+
+ memmove(valueBuffer, &val, valueType->size());
+}
+
+
+
+void
+r_Primitive::set_long(r_Long val) throw( r_Error )
+{
+ if( !valueType || valueType->type_id() != r_Type::LONG )
+ {
+ RMInit::logOut << "r_Primitive::set_long(" << val << ") not a long" << endl;
+ r_Error err( r_Error::r_Error_TypeInvalid );
+ throw err;
+ }
+
+ if( !valueBuffer )
+ valueBuffer = (char*)mymalloc( valueType->size());
+
+ memmove(valueBuffer, &val, valueType->size());
+}
+
+
+
+void
+r_Primitive::set_ulong(r_ULong val) throw( r_Error )
+{
+ if( !valueType || valueType->type_id() != r_Type::ULONG )
+ {
+ RMInit::logOut << "r_Primitive::set_ulong(" << val << ") not a ulong" << endl;
+ r_Error err( r_Error::r_Error_TypeInvalid );
+ throw err;
+ }
+
+ if( !valueBuffer )
+ valueBuffer = (char*)mymalloc( valueType->size());
+
+ memmove(valueBuffer, &val, valueType->size());
+}
+
+
+
+void
+r_Primitive::set_float(r_Float val) throw( r_Error )
+{
+ if( !valueType || valueType->type_id() != r_Type::FLOAT )
+ {
+ RMInit::logOut << "r_Primitive::set_float(" << val << ") not a float" << endl;
+ r_Error err( r_Error::r_Error_TypeInvalid );
+ throw err;
+ }
+
+ if( !valueBuffer )
+ valueBuffer = (char*)mymalloc( valueType->size());
+
+ memmove(valueBuffer, &val, valueType->size());
+}
+
+
+
+void
+r_Primitive::set_double(r_Double val) throw( r_Error )
+{
+ if( !valueType || valueType->type_id() != r_Type::DOUBLE )
+ {
+ RMInit::logOut << "r_Primitive::set_double(" << val << ") not a double" << endl;
+ r_Error err( r_Error::r_Error_TypeInvalid );
+ throw err;
+ }
+
+ if( !valueBuffer )
+ valueBuffer = (char*)mymalloc( valueType->size());
+ memmove(valueBuffer, &val, valueType->size());
+}
+
+
+std::ostream& operator<<( std::ostream& s, const r_Primitive& obj )
+{
+ obj.print_status( s );
+ return s;
+}
+
diff --git a/raslib/primitive.hh b/raslib/primitive.hh
new file mode 100644
index 0000000..a4d1dc6
--- /dev/null
+++ b/raslib/primitive.hh
@@ -0,0 +1,143 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: primitive.hh
+ *
+ * MODULE: raslib
+ * CLASS: r_Primitive
+ *
+ * COMMENTS:
+ * The class represents a primitive type value.
+ *
+*/
+
+#ifndef _D_PRIMITIVE_
+#define _D_PRIMITIVE_
+
+#include <iostream>
+
+class r_Error;
+
+#include "raslib/scalar.hh"
+#include "raslib/odmgtypes.hh"
+
+class r_Primitive_Type;
+
+//@ManMemo: Module: {\bf raslib}
+
+/*@Doc:
+
+ Class \Ref{r_Primitive} represents a primitive type value.
+
+*/
+
+class r_Primitive : public r_Scalar
+{
+ public:
+
+ explicit
+
+ /// constructs a scalar type value
+ r_Primitive( const char* newBuffer, const r_Primitive_Type* newType );
+
+ /// copy constructor
+ r_Primitive( const r_Primitive& obj );
+
+ /// destructor
+ ~r_Primitive();
+
+ /// clone operator
+ virtual r_Scalar* clone() const;
+
+ /// operator for assigning a primitive
+ virtual const r_Primitive& operator= ( const r_Primitive& );
+
+ /// gets the pointer to the buffer
+ const char* get_buffer() const;
+
+ /// debug output
+ virtual void print_status(std::ostream& s) const;
+
+ virtual bool isPrimitive() const;
+
+ //@Man: Type-safe value access methods. In case of type mismatch, an exception is raised.
+ //@{
+ ///
+
+ ///
+ r_Boolean get_boolean() const throw( r_Error );
+ ///
+ r_Char get_char() const throw( r_Error );
+ ///
+ r_Octet get_octet() const throw( r_Error );
+ ///
+ r_Short get_short() const throw( r_Error );
+ ///
+ r_UShort get_ushort() const throw( r_Error );
+ ///
+ r_Long get_long() const throw( r_Error );
+ ///
+ r_ULong get_ulong() const throw( r_Error );
+ ///
+ r_Float get_float() const throw( r_Error );
+ ///
+ r_Double get_double() const throw( r_Error );
+
+ ///
+ void set_boolean(r_Boolean) throw( r_Error );
+ ///
+ void set_char(r_Char) throw( r_Error );
+ ///
+ void set_octet(r_Octet) throw( r_Error );
+ ///
+ void set_short(r_Short) throw( r_Error );
+ ///
+ void set_ushort(r_UShort) throw( r_Error );
+ ///
+ void set_long(r_Long) throw( r_Error );
+ ///
+ void set_ulong(r_ULong) throw( r_Error );
+ ///
+ void set_float(r_Float) throw( r_Error );
+ ///
+ void set_double(r_Double) throw( r_Error );
+
+
+ ///
+ //@}
+
+ private:
+ /// buffer
+ char* valueBuffer;
+};
+
+
+
+//@ManMemo: Module: {\bf raslib}
+/**
+ Output stream operator for objects of type {\tt const} \Ref{r_Primitive}.
+*/
+extern std::ostream& operator<<( std::ostream& s, const r_Primitive& obj );
+
+#endif
+
diff --git a/raslib/primitivetype.cc b/raslib/primitivetype.cc
new file mode 100644
index 0000000..a0dbb37
--- /dev/null
+++ b/raslib/primitivetype.cc
@@ -0,0 +1,601 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+static const char rcsid[] = "@(#)raslib, r_Primitive_Type: $Header: /home/rasdev/CVS-repository/rasdaman/raslib/primitivetype.cc,v 1.26 2003/12/27 23:01:21 rasdev Exp $";
+
+#include "raslib/primitivetype.hh"
+#include "raslib/rminit.hh"
+#include "raslib/rmdebug.hh"
+#include "raslib/odmgtypes.hh"
+#include "raslib/endian.hh"
+#include "raslib/error.hh"
+
+#include <iomanip>
+#include <string>
+#include <cstring>
+
+r_Primitive_Type::r_Primitive_Type()
+ : r_Base_Type(),
+ typeId(UNKNOWNTYPE)
+{
+}
+
+r_Primitive_Type::r_Primitive_Type( const char* newTypeName,
+ const r_Type::r_Type_Id newTypeId )
+ : r_Base_Type(newTypeName, 0),
+ typeId(newTypeId)
+{
+
+ switch( typeId )
+ {
+ case ULONG: typeSize = 4; break;
+ case USHORT: typeSize = 2; break;
+ case BOOL: typeSize = 1; break;
+ case LONG: typeSize = 4; break;
+ case SHORT: typeSize = 2; break;
+ case OCTET: typeSize = 1; break;
+ case DOUBLE: typeSize = 8; break;
+ case FLOAT: typeSize = 4; break;
+ case CHAR: typeSize = 1; break;
+ case COMPLEXTYPE1:
+ typeSize = 2 * sizeof(float);
+ break;
+ case COMPLEXTYPE2:
+ typeSize = 2 * sizeof(double);
+ break;
+ default:
+ RMDBGONCE(3, RMDebug::module_raslib, "r_Primitive_Type", "r_Primitive_Type(....) bad typeId " << typeId);
+ break;
+ }
+}
+
+r_Primitive_Type::r_Primitive_Type( const r_Primitive_Type& oldObj )
+ : r_Base_Type(oldObj),
+ typeId(oldObj.typeId)
+{
+}
+
+const r_Primitive_Type&
+r_Primitive_Type::operator=( const r_Primitive_Type& oldObj )
+{
+ // Gracefully handle self assignment
+ if (this == &oldObj) return *this;
+
+ r_Base_Type::operator=( oldObj );
+ typeId = oldObj.typeId;
+
+ return *this;
+}
+
+r_Primitive_Type::~r_Primitive_Type()
+{
+}
+
+r_Type*
+r_Primitive_Type::clone() const
+{
+ return new r_Primitive_Type( *this );
+}
+
+
+r_Type::r_Type_Id
+r_Primitive_Type::type_id() const
+{
+ return typeId;
+}
+
+bool
+r_Primitive_Type::isPrimitiveType() const
+{
+ return true;
+}
+
+void
+r_Primitive_Type::convertToLittleEndian(char* cells, r_Bytes noCells) const
+ {
+ char c0 = 0;
+ char c1 = 0;
+ char c2 = 0;
+ char c3 = 0;
+ r_Bytes i = 0;
+
+ switch( typeId )
+ {
+ case USHORT:
+ case SHORT:
+ for(i=0; i<noCells; i++ )
+ {
+ c1 = cells[i*typeSize];
+ c0 = cells[i*typeSize + 1];
+ cells[i*typeSize] = c0;
+ cells[i*typeSize + 1] = c1;
+ }
+ break;
+
+ case ULONG:
+ case LONG:
+ for(i=0; i<noCells; i++ )
+ {
+ c3 = cells[i*typeSize];
+ c2 = cells[i*typeSize + 1];
+ c1 = cells[i*typeSize + 2];
+ c0 = cells[i*typeSize + 3];
+ cells[i*typeSize] = c0;
+ cells[i*typeSize + 1] = c1;
+ cells[i*typeSize + 2] = c2;
+ cells[i*typeSize + 3] = c3;
+ }
+ break;
+
+ case FLOAT:
+ for(i = 0; i < noCells; ++i)
+ ((r_Float *)cells)[i] = r_Endian::swap( ((r_Float *)cells)[i] );
+ break;
+
+ case DOUBLE:
+ for(i = 0; i < noCells; ++i)
+ ((r_Double *)cells)[i] = r_Endian::swap( ((r_Double *)cells)[i] );
+ break;
+ default:
+ RMDBGONCE(3, RMDebug::module_raslib, "r_Primitive_Type", "convertToLittleEndian(....) bad typeId " << typeId);
+ break;
+ }
+ }
+
+void
+r_Primitive_Type::convertToBigEndian(char* cells, r_Bytes noCells) const
+ {
+ char c0 = 0;
+ char c1 = 0;
+ char c2 = 0;
+ char c3 = 0;
+ r_Bytes i = 0;
+
+ switch( typeId )
+ {
+ case USHORT:
+ case SHORT:
+ for(i=0; i<noCells; i++)
+ {
+ c1 = cells[i*typeSize];
+ c0 = cells[i*typeSize + 1];
+ cells[i*typeSize] = c0;
+ cells[i*typeSize + 1] = c1;
+ }
+ break;
+
+ case ULONG:
+ case LONG:
+ for(i=0; i<noCells; i++)
+ {
+ c3 = cells[i*typeSize];
+ c2 = cells[i*typeSize + 1];
+ c1 = cells[i*typeSize + 2];
+ c0 = cells[i*typeSize + 3];
+ cells[i*typeSize] = c0;
+ cells[i*typeSize + 1] = c1;
+ cells[i*typeSize + 2] = c2;
+ cells[i*typeSize + 3] = c3;
+ }
+ break;
+
+ case FLOAT:
+ for(i = 0; i < noCells; ++i)
+ ((r_Float *)cells)[i] = r_Endian::swap( ((r_Float *)cells)[i] );
+ break;
+
+ case DOUBLE:
+ for(i = 0; i < noCells; ++i)
+ ((r_Double *)cells)[i] = r_Endian::swap( ((r_Double *)cells)[i] );
+ break;
+ default:
+ RMDBGONCE(3, RMDebug::module_raslib, "r_Primitive_Type", "convertToBigEndian(....) bad typeId " << typeId);
+ break;
+ }
+ }
+
+void
+r_Primitive_Type::print_status( std::ostream& s ) const
+{
+ s << typeId;
+}
+
+void
+r_Primitive_Type::print_value( const char* storage, std::ostream& s ) const
+{
+ switch( typeId )
+ {
+ case r_Type::ULONG: s << std::setw(5) << get_ulong( storage ); break;
+ case r_Type::USHORT: s << std::setw(5) << get_ushort( storage ); break;
+ case r_Type::BOOL: s << std::setw(5) << ( get_boolean( storage ) ? "T" : "F" ); break;
+ case r_Type::LONG: s << std::setw(5) << get_long( storage ); break;
+ case r_Type::SHORT: s << std::setw(5) << get_short( storage ); break;
+ case r_Type::OCTET: s << std::setw(5) << (int)( get_octet( storage ) ); break;
+ case r_Type::DOUBLE: s << std::setw(5) << get_double( storage ) ; break;
+ case r_Type::FLOAT: s << std::setw(5) << get_float( storage ); break;
+ case r_Type::CHAR: s << std::setw(5) << (int)( get_char( storage ) ); break;
+ default:
+ RMInit::logOut << "r_Primitive_Type::print_value(...) type unknown" << endl;
+ break;
+ }
+}
+
+//FIXME
+// We have to return the value in the most powerfull type(e.g. now r_Double) without loss
+// This may change in future
+
+r_Double
+r_Primitive_Type::get_value( const char* storage ) const throw(r_Error)
+{
+ r_Double retVal=0.;
+
+ switch( typeId )
+ {
+ case r_Type::ULONG: retVal=get_ulong( storage ); break;
+ case r_Type::USHORT: retVal=get_ushort( storage ); break;
+ case r_Type::BOOL: retVal=get_boolean( storage ); break;
+ case r_Type::LONG: retVal=get_long( storage ); break;
+ case r_Type::SHORT: retVal=get_short( storage ); break;
+ case r_Type::OCTET: retVal=get_octet( storage ); break;
+ case r_Type::DOUBLE: retVal=get_double( storage ); break;
+ case r_Type::FLOAT: retVal=get_float( storage ); break;
+ case r_Type::CHAR: retVal=get_char( storage ); break;
+ default:
+ {
+ RMInit::logOut << "r_Primitive_Type::get_value(...) type unknown" << endl;
+ r_Error err( r_Error::r_Error_TypeInvalid );
+ throw( err );
+ };
+ break;
+ }
+ return retVal;
+}
+
+//FIXME
+// We have to set the value from the most powerfull type(e.g. now r_Double) without loss
+// This may change in future
+
+void
+r_Primitive_Type::set_value( char* storage, r_Double val ) throw(r_Error)
+{
+ switch( typeId )
+ {
+ case r_Type::ULONG: set_ulong( storage, (r_ULong)val ); break;
+ case r_Type::USHORT: set_ushort( storage, (r_UShort)val ); break;
+ case r_Type::BOOL: set_boolean( storage, (r_Boolean)val ); break;
+ case r_Type::LONG: set_long( storage, (r_Long)val ); break;
+ case r_Type::SHORT: set_short( storage, (r_Short)val ); break;
+ case r_Type::OCTET: set_octet( storage, (r_Octet)val ); break;
+ case r_Type::DOUBLE: set_double( storage, (r_Double)val); break;
+ case r_Type::FLOAT: set_float( storage, (r_Float)val ); break;
+ case r_Type::CHAR: set_char( storage, (r_Char)val ); break;
+ default:
+ {
+ RMInit::logOut << "r_Primitive_Type::set_value(...) type unknown" << endl;
+ r_Error err( r_Error::r_Error_TypeInvalid );
+ throw( err );
+ };
+ break;
+ }
+}
+
+//FIXME
+// We have to set the value from the most powerfull type(e.g. now r_Double) without loss
+// This may change in future
+
+void
+r_Primitive_Type::get_limits( r_Double& min, r_Double& max ) throw(r_Error)
+{
+ r_Double *type=NULL;
+ switch( typeId )
+ {
+ case r_Type::ULONG: ::get_limits( (r_ULong*)type, min, max ); break;
+ case r_Type::USHORT: ::get_limits( (r_UShort*)type, min, max ); break;
+ case r_Type::BOOL: ::get_limits( (r_Boolean*)type, min, max ); break;
+ case r_Type::LONG: ::get_limits( (r_Long*)type, min, max ); break;
+ case r_Type::SHORT: ::get_limits( (r_Short*)type, min, max ); break;
+ case r_Type::OCTET: ::get_limits( (r_Octet*)type, min, max ); break;
+ case r_Type::DOUBLE: ::get_limits( (r_Double*)type, min, max); break;
+ case r_Type::FLOAT: ::get_limits( (r_Float*)type, min, max ); break;
+ case r_Type::CHAR: ::get_limits( (r_Char*)type, min, max ); break;
+ default:
+ {
+ RMInit::logOut << "r_Primitive_Type::get_limits(...) type unknown" << endl;
+ r_Error err( r_Error::r_Error_TypeInvalid );
+ throw( err );
+ };
+ break;
+ }
+}
+
+r_Boolean
+r_Primitive_Type::get_boolean( const char* cell ) const throw( r_Error )
+{
+ if( typeId != r_Type::BOOL )
+ {
+ RMInit::logOut << "r_Primitive_Type::get_boolean(cell) type not a boolean" << endl;
+ r_Error err( r_Error::r_Error_TypeInvalid );
+ throw( err );
+ }
+
+ return *((r_Boolean*)cell);
+}
+
+
+
+r_Char
+r_Primitive_Type::get_char( const char* cell ) const throw( r_Error )
+{
+ if( typeId != r_Type::CHAR )
+ {
+ RMInit::logOut << "r_Primitive_Type::get_char(cell) type not a char" << endl;
+ r_Error err( r_Error::r_Error_TypeInvalid );
+ throw( err );
+ }
+
+ return *((r_Char*)cell);
+}
+
+
+
+r_Octet
+r_Primitive_Type::get_octet( const char* cell ) const throw( r_Error )
+{
+ if( typeId != r_Type::OCTET )
+ {
+ RMInit::logOut << "r_Primitive_Type::get_octet(cell) type not a octet" << endl;
+ r_Error err( r_Error::r_Error_TypeInvalid );
+ throw( err );
+ }
+
+ return *((r_Octet*)cell);
+}
+
+
+
+r_Short
+r_Primitive_Type::get_short( const char* cell ) const throw( r_Error )
+{
+ if( typeId != r_Type::SHORT )
+ {
+ RMInit::logOut << "r_Primitive_Type::get_short(cell) type not a short" << endl;
+ r_Error err( r_Error::r_Error_TypeInvalid );
+ throw( err );
+ }
+
+ return *((r_Short*)cell);
+}
+
+
+
+r_UShort
+r_Primitive_Type::get_ushort( const char* cell ) const throw( r_Error )
+{
+ if( typeId != r_Type::USHORT )
+ {
+ RMInit::logOut << "r_Primitive_Type::get_ushort(cell) type not a ushort" << endl;
+ r_Error err( r_Error::r_Error_TypeInvalid );
+ throw( err );
+ }
+
+ return *((r_UShort*)cell);
+}
+
+
+
+r_Long
+r_Primitive_Type::get_long( const char* cell ) const throw( r_Error )
+{
+ if( typeId != r_Type::LONG )
+ {
+ RMInit::logOut << "r_Primitive_Type::get_long(cell) type not a long" << endl;
+ r_Error err( r_Error::r_Error_TypeInvalid );
+ throw( err );
+ }
+
+ return *((r_Long*)cell);
+}
+
+
+
+r_ULong
+r_Primitive_Type::get_ulong( const char* cell ) const throw( r_Error )
+{
+ if( typeId != r_Type::ULONG )
+ {
+ RMInit::logOut << "r_Primitive_Type::get_ulong(cell) type not a ulong" << endl;
+ r_Error err( r_Error::r_Error_TypeInvalid );
+ throw( err );
+ }
+
+ return *((r_ULong*)cell);
+}
+
+
+
+r_Float
+r_Primitive_Type::get_float( const char* cell ) const throw( r_Error )
+{
+ if( typeId != r_Type::FLOAT )
+ {
+ RMInit::logOut << "r_Primitive_Type::get_float(cell) type not a float" << endl;
+ r_Error err( r_Error::r_Error_TypeInvalid );
+ throw( err );
+ }
+
+ return *((r_Float*)cell);
+}
+
+
+
+r_Double
+r_Primitive_Type::get_double( const char* cell ) const throw( r_Error )
+{
+ if( typeId != r_Type::DOUBLE )
+ {
+ RMInit::logOut << "r_Primitive_Type::get_double(cell) type not a double" << endl;
+ r_Error err( r_Error::r_Error_TypeInvalid );
+ throw( err );
+ }
+
+ return *((r_Double*)cell);
+}
+
+void
+r_Primitive_Type::set_boolean( char* cell, r_Boolean val ) throw( r_Error )
+{
+ if( typeId != r_Type::BOOL )
+ {
+ RMInit::logOut << "r_Primitive_Type::set_boolean(cell, val) type not a boolean" << endl;
+ r_Error err( r_Error::r_Error_TypeInvalid );
+ throw( err );
+ }
+
+ memmove(cell, &val, typeSize);
+}
+
+
+
+void
+r_Primitive_Type::set_char( char* cell, r_Char val ) throw( r_Error )
+{
+ if( typeId != r_Type::CHAR )
+ {
+ RMInit::logOut << "r_Primitive_Type::set_char(cell, val) type not a char" << endl;
+ r_Error err( r_Error::r_Error_TypeInvalid );
+ throw( err );
+ }
+
+ memmove(cell, &val, typeSize);
+}
+
+
+
+void
+r_Primitive_Type::set_octet( char* cell, r_Octet val ) throw( r_Error )
+{
+ if( typeId != r_Type::OCTET )
+ {
+ RMInit::logOut << "r_Primitive_Type::set_octet(cell, val) type not a octet" << endl;
+ r_Error err( r_Error::r_Error_TypeInvalid );
+ throw( err );
+ }
+
+ memmove(cell, &val, typeSize);
+}
+
+
+
+void
+r_Primitive_Type::set_short( char* cell, r_Short val ) throw( r_Error )
+{
+ if( typeId != r_Type::SHORT )
+ {
+ RMInit::logOut << "r_Primitive_Type::set_short(cell, val) type not a short" << endl;
+ r_Error err( r_Error::r_Error_TypeInvalid );
+ throw( err );
+ }
+
+ memmove(cell, &val, typeSize);
+}
+
+
+
+void
+r_Primitive_Type::set_ushort( char* cell, r_UShort val ) throw( r_Error )
+{
+ if( typeId != r_Type::USHORT )
+ {
+ RMInit::logOut << "r_Primitive_Type::set_ushort(cell, val) type not a ushort" << endl;
+ r_Error err( r_Error::r_Error_TypeInvalid );
+ throw( err );
+ }
+
+ memmove(cell, &val, typeSize);
+}
+
+
+
+void
+r_Primitive_Type::set_long( char* cell, r_Long val ) throw( r_Error )
+{
+ if( typeId != r_Type::LONG )
+ {
+ RMInit::logOut << "r_Primitive_Type::set_long(cell, val) type not a long" << endl;
+ r_Error err( r_Error::r_Error_TypeInvalid );
+ throw( err );
+ }
+
+ memmove(cell, &val, typeSize);
+}
+
+
+
+void
+r_Primitive_Type::set_ulong( char* cell, r_ULong val ) throw( r_Error )
+{
+ if( typeId != r_Type::ULONG )
+ {
+ RMInit::logOut << "r_Primitive_Type::set_ulong(cell, val) type not a ulong" << endl;
+ r_Error err( r_Error::r_Error_TypeInvalid );
+ throw( err );
+ }
+
+ memmove(cell, &val, typeSize);
+}
+
+
+
+void
+r_Primitive_Type::set_float( char* cell, r_Float val ) throw( r_Error )
+{
+ if( typeId != r_Type::FLOAT )
+ {
+ RMInit::logOut << "r_Primitive_Type::set_float(cell, val) type not a float" << endl;
+ r_Error err( r_Error::r_Error_TypeInvalid );
+ throw( err );
+ }
+
+ memmove(cell, &val, typeSize);
+}
+
+
+
+void
+r_Primitive_Type::set_double( char* cell, r_Double val ) throw( r_Error )
+{
+ if( typeId != r_Type::DOUBLE )
+ {
+ RMInit::logOut << "r_Primitive_Type::set_double(cell, val) type not a double" << endl;
+ r_Error err( r_Error::r_Error_TypeInvalid );
+ throw( err );
+ }
+
+ memmove(cell, &val, typeSize);
+}
+
+std::ostream &operator<<( std::ostream &str, const r_Primitive_Type &type )
+{
+ type.print_status(str);
+ return str;
+}
diff --git a/raslib/primitivetype.hh b/raslib/primitivetype.hh
new file mode 100644
index 0000000..9dac808
--- /dev/null
+++ b/raslib/primitivetype.hh
@@ -0,0 +1,147 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: primitivetype.hh
+ *
+ * MODULE: raslib
+ * CLASS: r_Primitive_Type
+ *
+ * COMMENTS:
+ *
+*/
+
+#ifndef _D_PRIMITIVE_TYPE_
+#define _D_PRIMITIVE_TYPE_
+
+class r_Error;
+
+#include "raslib/basetype.hh"
+#include "raslib/odmgtypes.hh"
+
+//@ManMemo: Module: {\bf raslib}
+
+/*@Doc:
+ This class represents all primitive types in the ODMG conformant
+ representation of the RasDaMan type system. Examples are ULONG or
+ BOOL.
+*/
+
+class r_Primitive_Type : public r_Base_Type
+{
+public:
+ /// constructor getting name of type, size of type and type id.
+ r_Primitive_Type( const char* newTypeName, const r_Type::r_Type_Id newTypeId );
+ /// copy constructor
+ r_Primitive_Type( const r_Primitive_Type& oldObj );
+ /// assignment operator.
+ const r_Primitive_Type& operator=( const r_Primitive_Type& oldObj );
+ /// destructor.
+ virtual ~r_Primitive_Type();
+
+ /// clone operation
+ virtual r_Type* clone() const;
+
+ /// retrieve id of the type.
+ virtual r_Type::r_Type_Id type_id() const;
+
+ /// converts array of cells from NT byte order to Unix byte order.
+ virtual void convertToLittleEndian(char* cells, r_Area noCells) const;
+
+ /// converts array of cells from Unix byte order to NT byte order.
+ virtual void convertToBigEndian(char* cells, r_Area noCells) const;
+
+ /// writes state of object to specified stream
+ virtual void print_status( std::ostream& s = std::cout ) const;
+
+ /// check, if type is primitive.
+ virtual bool isPrimitiveType() const;
+
+ /// prints value of a primitive type
+ virtual void print_value( const char* storage, std::ostream& s = std::cout ) const;
+
+ //@Man: Type-safe value access methods. In case of type mismatch, an exception is raised.
+ //@{
+ ///
+
+ ///
+ r_Double get_value( const char* cell ) const throw( r_Error );
+ ///
+ void set_value( char* cell, r_Double ) throw( r_Error );
+ ///
+ void get_limits( r_Double&, r_Double& ) throw( r_Error );
+
+
+ ///
+ r_Boolean get_boolean( const char* cell ) const throw( r_Error );
+ ///
+ r_Char get_char( const char* cell ) const throw( r_Error );
+ ///
+ r_Octet get_octet( const char* cell ) const throw( r_Error );
+ ///
+ r_Short get_short( const char* cell ) const throw( r_Error );
+ ///
+ r_UShort get_ushort( const char* cell ) const throw( r_Error );
+ ///
+ r_Long get_long( const char* cell ) const throw( r_Error );
+ ///
+ r_ULong get_ulong( const char* cell ) const throw( r_Error );
+ ///
+ r_Float get_float( const char* cell ) const throw( r_Error );
+ ///
+ r_Double get_double( const char* cell ) const throw( r_Error );
+
+ ///
+ void set_boolean( char* cell, r_Boolean ) throw( r_Error );
+ ///
+ void set_char( char* cell, r_Char ) throw( r_Error );
+ ///
+ void set_octet( char* cell, r_Octet ) throw( r_Error );
+ ///
+ void set_short( char* cell, r_Short ) throw( r_Error );
+ ///
+ void set_ushort( char* cell, r_UShort ) throw( r_Error );
+ ///
+ void set_long( char* cell, r_Long ) throw( r_Error );
+ ///
+ void set_ulong( char* cell, r_ULong ) throw( r_Error );
+ ///
+ void set_float( char* cell, r_Float ) throw( r_Error );
+ ///
+ void set_double( char* cell, r_Double ) throw( r_Error );
+
+
+ ///
+ //@}
+
+ protected:
+ /// default constructor.
+ r_Primitive_Type();
+
+ r_Type::r_Type_Id typeId;
+};
+
+//@Doc: write the status of a primitive type to a stream
+extern std::ostream &operator<<( std::ostream &str, const r_Primitive_Type &type );
+
+#endif
+
diff --git a/raslib/property.cc b/raslib/property.cc
new file mode 100644
index 0000000..ddd75c2
--- /dev/null
+++ b/raslib/property.cc
@@ -0,0 +1,99 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+static const char rcsid[] = "@(#)raslib, r_Meta_Object: $Header: /home/rasdev/CVS-repository/rasdaman/raslib/property.cc,v 1.7 2003/12/27 23:01:21 rasdev Exp $";
+
+#include "raslib/property.hh"
+#include "raslib/basetype.hh"
+#include "raslib/rminit.hh"
+#include "raslib/error.hh"
+
+
+#include <malloc.h>
+#include <string.h>
+
+r_Property::r_Property()
+ : r_Meta_Object(),
+ myType(NULL)
+ {
+ }
+
+r_Property::r_Property(const char* newTypeName, const r_Base_Type& newType)
+ : r_Meta_Object(newTypeName),
+ myType((r_Base_Type*)newType.clone())
+ {
+ }
+
+r_Property::r_Property(const r_Property& oldObj)
+ : r_Meta_Object(oldObj)
+ {
+ if (oldObj.myType)
+ myType = (r_Base_Type*)oldObj.myType->clone();
+ else {
+ RMInit::logOut << "r_Property::r_Property(oldObj) property does not have a base type" << endl;
+ throw r_Error(PROPERTYTYPEHASNOELEMENTTYPE);
+ }
+ }
+
+const r_Property&
+r_Property::operator=(const r_Property& oldObj)
+ {
+ // Gracefully handle self assignment
+ if (this != &oldObj)
+ {
+ r_Meta_Object::operator=(oldObj);
+ if (myType)
+ {
+ delete myType;
+ myType = 0;
+ }
+
+ if (oldObj.myType)
+ myType = (r_Base_Type*)oldObj.myType->clone();
+ else {
+ RMInit::logOut << "r_Property::operator=(oldObj) property does not have a base type" << endl;
+ throw r_Error(PROPERTYTYPEHASNOELEMENTTYPE);
+ }
+ }
+
+ return *this;
+ }
+
+r_Property::~r_Property()
+ {
+ if (myType)
+ delete myType;
+ }
+
+const r_Base_Type&
+r_Property::type_of() const
+ {
+ if (!myType)
+ {
+ RMInit::logOut << "r_Property::type_of() property does not have a base type" << endl;
+ throw r_Error(PROPERTYTYPEHASNOELEMENTTYPE);
+ }
+
+ return *myType;
+ }
+
diff --git a/raslib/property.hh b/raslib/property.hh
new file mode 100644
index 0000000..1985993
--- /dev/null
+++ b/raslib/property.hh
@@ -0,0 +1,77 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: property.hh
+ *
+ * MODULE: raslib
+ * CLASS: r_Property
+ *
+ * COMMENTS:
+ *
+*/
+
+#ifndef _D_PROPERTY_
+#define _D_PROPERTY_
+
+#include "metaobject.hh"
+
+
+class r_Base_Type;
+class r_Type_Id;
+
+//@ManMemo: Module: {\bf raslib}
+
+/*@Doc:
+ This class the superclass for properties of classes in the ODMG
+ conformant representation of the RasDaMan type system.
+*/
+
+class r_Property : public r_Meta_Object
+ {
+ public:
+
+ /// constructor getting name and type of property.
+ r_Property( const char* newTypeName, const r_Base_Type& newType );
+
+ /// copy constructor.
+ r_Property( const r_Property& oldObj );
+
+ /// assignment operator.
+ const r_Property& operator=( const r_Property& oldObj );
+
+ /// destructor.
+ virtual ~r_Property();
+
+ /// retrieve type of property.
+ const r_Base_Type& type_of() const;
+
+ protected:
+
+ r_Base_Type* myType;
+
+ /// default constructor.
+ r_Property();
+
+ };
+
+#endif
diff --git a/raslib/rm.cc b/raslib/rm.cc
new file mode 100644
index 0000000..4698f5b
--- /dev/null
+++ b/raslib/rm.cc
@@ -0,0 +1,31 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: rm.hh
+ *
+ * PURPOSE:
+ * Artificially created to manipulate hierarchy tree.
+ *
+ * COMMENTS:
+ *
+*/
diff --git a/raslib/rm.hh b/raslib/rm.hh
new file mode 100644
index 0000000..39643b9
--- /dev/null
+++ b/raslib/rm.hh
@@ -0,0 +1,38 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: rm.hh
+ *
+ * PURPOSE:
+ * Artificial class to manipulate hierarchy tree.
+ *
+ * COMMENTS:
+ *
+*/
+
+#ifndef _RM_CLASS_
+#define _RM_CLASS_
+
+class RM_Class {};
+
+#endif
diff --git a/raslib/rmdebug.cc b/raslib/rmdebug.cc
new file mode 100644
index 0000000..d047812
--- /dev/null
+++ b/raslib/rmdebug.cc
@@ -0,0 +1,430 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: rmdebug.cc
+ *
+ * MODULE: raslib
+ * CLASS:
+ *
+ * COMMENTS:
+ *
+*/
+
+static const char rcsid[] = "@(#)raslib, RMDebug: $Header: /home/rasdev/CVS-repository/rasdaman/raslib/rmdebug.cc,v 1.33 2005/12/02 14:51:55 rasdev Exp $";
+
+#include <iostream>
+using namespace std;
+
+#include <stdio.h> // fopen, getc
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <fstream>
+
+
+#include "raslib/rmdebug.hh"
+#include "raslib/odmgtypes.hh"
+
+int RManDebug = 0; // debug level (0-4), 0 means no debug info at all
+int RManBenchmark = 0; // benchmark level (0-4)
+
+// initialization of static variables for RMDebug
+int RMDebug::level = 0;
+int RMDebug::numDebugModules = 0;
+char** RMDebug::debugModules = 0;
+char* RMDebug::debugModulesText = 0;
+int* RMDebug::transDebugModules = 0;
+int RMDebug::numDebugClasses = 0;
+char** RMDebug::debugClasses = 0;
+char* RMDebug::debugClassesText = 0;
+
+// all module names
+const char* RMDebug::allModuleNames[] = {
+ "adminif",
+ "applications",
+ "blobif",
+ "cachetamgr",
+ "catalogif",
+ "catalogmgr",
+ "clientcomm",
+ "conversion",
+ "compression",
+ "httpserver",
+ "indexif",
+ "indexmgr",
+ "insertutils",
+ "mddif",
+ "mddmgr",
+ "qlparser",
+ "rasdl",
+ "raslib",
+ "rasodmg",
+ "rasql",
+ "server",
+ "servercomm",
+ "storageif",
+ "storagemgr",
+ "tools",
+ "tilemgr",
+ "utilities"
+};
+
+int RMDebug::allModuleLevels[RMDebug::module_number];
+
+
+// initialization of static variable for RMTimer
+#ifndef __VISUALC__
+struct timezone RMTimer::dummy;
+#endif
+
+RMDebug::RMDebug(const char* newClass, const char* newFunc, const char* newModule,
+ const char* newFile, int newLine)
+ : myClass(newClass), myFunc(newFunc), myModule(newModule),
+ myFile(newFile), myLine(newLine), myModuleNum(-1), myDebugLevel(2)
+{
+ myDebugOn = checkDebug();
+
+ int useLevel = -1;
+ if (myModuleNum >= 0)
+ useLevel = allModuleLevels[myModuleNum];
+
+ if (useLevel < 0)
+ useLevel = RManDebug;
+
+ myDebugOn = myDebugOn && (useLevel >= myDebugLevel);
+
+ if( myDebugOn )
+ {
+ indentLine();
+ // output, when entering function
+ RMInit::dbgOut << "D: " << myClass << "::" << myFunc << " entered "
+ << "(" << myModule << ", " << myFile << ": " << myLine
+ << ")." << endl;
+ // indentation
+ level++;
+ }
+}
+
+RMDebug::RMDebug(int newLevel, const char* newClass, const char* newFunc, int newModuleNum,
+ const char* newFile, int newLine)
+ : myClass(newClass), myFunc(newFunc), myModule(NULL), myFile(newFile),
+ myLine(newLine), myModuleNum(newModuleNum), myDebugLevel(newLevel)
+{
+ myDebugOn = checkDebug() && (allModuleLevels[newModuleNum] >= myDebugLevel);
+
+ if ( myDebugOn )
+ {
+ indentLine();
+ // output when entering function
+ RMInit::dbgOut << "D: " << myClass << "::" << myFunc << " entered "
+ << "(" << allModuleNames[myModuleNum] << ", " << myFile << ": "
+ << myLine << ")." << endl;
+ // indentation
+ level++;
+ }
+}
+
+RMDebug::~RMDebug(void)
+{
+ if( myDebugOn )
+ {
+ // indentation
+ level--;
+ indentLine();
+ // output, when exiting function
+ RMInit::dbgOut << "D: " << myClass << "::" << myFunc
+ << " exited." << endl;
+ }
+}
+
+char*
+RMDebug::loadTextFile(const char* name)
+{
+
+ std::ifstream f;
+ f.open(name);
+ if (f.is_open())
+ {
+ char* result;
+ f.seekg(0, std::ios::end);
+ std::streampos end = f.tellg();
+ r_Long resLen=(r_Long)end + 1;
+ result = new char[resLen];
+ memset(result, 0, resLen);
+ f.seekg(0, std::ios::beg);
+ f.read(result, end);
+ f.close();
+ result[resLen] = '\0';
+ return result;
+ }
+ return NULL;
+}
+
+int
+RMDebug::initRMDebug(void)
+{
+ int errmod=0;
+ int errclass=0;
+ int j;
+ const char* enVar;
+ char* myPtr;
+
+ // init all debug levels to global debug level
+ for (j=0; j<module_number; j++)
+ allModuleLevels[j] = RManDebug;
+
+ // -------------------
+ // reading rmdbmodules
+ // -------------------
+
+ // environment variable overrides text file
+ if ((enVar = getenv("RMDBGMODULES")) != NULL)
+ {
+ debugModulesText = new char[strlen(enVar)+1];
+ strcpy(debugModulesText, enVar);
+ }
+ else
+ {
+ if ((debugModulesText = loadTextFile("rmdbmodules")) == NULL)
+ errmod = -1;
+ }
+
+ if (debugModulesText != NULL)
+ {
+ // first switch off debugging info for all modules
+ for (j=0; j<module_number; j++)
+ allModuleLevels[j] = 0;
+
+ // count number of lines (whitespace separates)
+ myPtr = debugModulesText;
+ while (*myPtr != '\0')
+ {
+ while (isspace((unsigned int)(*myPtr))) myPtr++;
+ if (*myPtr != '\0')
+ {
+ numDebugModules++;
+ while ((*myPtr != '\0') && !isspace((unsigned int)(*myPtr))) myPtr++;
+ }
+ }
+ debugModules = new char*[numDebugModules];
+ transDebugModules = new int[numDebugModules];
+ // read text
+ j = 0;
+ myPtr = debugModulesText;
+ while (*myPtr != '\0')
+ {
+ int modLevel = RManDebug; // default debug level
+ transDebugModules[j] = -1;
+ while (isspace((unsigned int)(*myPtr))) myPtr++;
+ if (*myPtr != '\0')
+ {
+ debugModules[j] = myPtr;
+ while ((*myPtr != '\0') && !isspace((unsigned int)(*myPtr)))
+ {
+ if (*myPtr == ',')
+ {
+ char* rest;
+ *myPtr++ = '\0';
+ modLevel = strtol(myPtr, &rest, 10);
+ if (rest == myPtr)
+ {
+ cerr << "RMDebug::initRMDebug: Parse error in item " << j << endl;
+ }
+ myPtr = rest;
+ }
+ else myPtr++;
+ }
+ }
+ if (*myPtr != '\0') *myPtr++ = '\0';
+ for (int i=0; i<module_number; i++)
+ {
+ if (debugModules[j] == NULL)
+ RMInit::logOut << "RMDebug::initRMDebug: debugModules[" << j << "] is NULL, skipping this." << std::endl;
+ else if (allModuleNames[i] == NULL)
+ RMInit::logOut << "RMDebug::initRMDebug: allModuleNames[" << i << "] is NULL, skipping this." << std::endl;
+ else if (strcmp(debugModules[j], allModuleNames[i]) == 0)
+ {
+ transDebugModules[j] = i; break;
+ }
+ }
+ if (transDebugModules[j] >= 0)
+ allModuleLevels[transDebugModules[j]] = modLevel;
+ j++;
+ }
+ for (j=0; j<module_number; j++)
+ RMInit::dbgOut << allModuleNames[j] << " : " << allModuleLevels[j] << endl;
+ }
+
+ // -------------------
+ // reading rmdbclasses
+ // -------------------
+
+ if ((enVar = getenv("RMDBGCLASSES")) != NULL)
+ {
+ debugClassesText = new char[strlen(enVar)+1];
+ strcpy(debugClassesText, enVar);
+ }
+ else
+ {
+ if ((debugClassesText = loadTextFile("rmdbclasses")) == NULL)
+ errclass = -1;
+ }
+
+ if (debugClassesText != NULL)
+ {
+ myPtr = debugClassesText;
+ while (*myPtr != '\0')
+ {
+ while (isspace((unsigned int)(*myPtr))) myPtr++;
+ if (*myPtr != '\0')
+ {
+ numDebugClasses++;
+ while ((*myPtr != '\0') && !isspace((unsigned int)(*myPtr))) myPtr++;
+ }
+ }
+ debugClasses = new char*[numDebugClasses];
+ // read text
+ j = 0;
+ myPtr = debugClassesText;
+ while (*myPtr != '\0')
+ {
+ while (isspace((unsigned int)(*myPtr))) myPtr++;
+ if (*myPtr != '\0')
+ {
+ debugClasses[j++] = myPtr;
+ while ((*myPtr != '\0') && !isspace((unsigned int)(*myPtr))) myPtr++;
+ if (*myPtr != '\0') *myPtr++ = '\0';
+ }
+ }
+ }
+RMInit::dbgOut << endl;
+ for (j=0; j<numDebugClasses; j++)
+ RMInit::dbgOut << debugClasses[j] << endl;
+
+ if(errmod == -1 && errclass == -1)
+ return -1;
+ else
+ return 0;
+}
+
+int
+RMDebug::checkDebug(void)
+{
+ int i;
+
+ if(numDebugModules == 0 && numDebugClasses == 0)
+ // all classes should be debugged
+ return 1;
+ else
+ {
+ if (numDebugModules > 0)
+ {
+ if(myModuleNum >= 0)
+ {
+ if (allModuleLevels[myModuleNum] == 0)
+ return 0;
+ }
+ else
+ {
+ // check if module is mentioned
+ for(i = 0; i < numDebugModules; i++)
+ {
+ if(strcmp(debugModules[i], myModule) == 0)
+ {
+ myModuleNum = transDebugModules[i];
+ break;
+ }
+ }
+ if (i >= numDebugModules) return 0;
+ }
+ }
+ if((numDebugClasses > 0) && (myClass != NULL))
+ {
+ // check if class is mentioned
+ for(i = 0; i < numDebugClasses; i++)
+ if(strcmp(debugClasses[i], myClass) == 0)
+ break;
+ if (i >= numDebugClasses) return 0;
+ }
+ }
+ return 1;
+}
+
+int
+RMDebug::debugOutput(int dbgLevel, int modNum, const char* className)
+{
+ int retval = 0;
+ if ((numDebugModules == 0) && (numDebugClasses == 0))
+ {
+ retval = (RManDebug >= dbgLevel);
+ }
+ else {
+ if (numDebugModules > 0) {
+ retval = (allModuleLevels[modNum] >= dbgLevel);
+ }
+ else {
+ if ((numDebugClasses > 0) && (className != NULL))
+ {
+ int i;
+ for (i=0; i<numDebugClasses; i++)
+ {
+ if (strcmp(debugClasses[i], className) == 0)
+ {
+ break;
+ }
+ }
+ if (i >= numDebugClasses)
+ retval = 0;
+ else
+ retval = 1;
+ }
+ else {
+ //nothing to do
+ }
+ }
+ }
+ return retval;
+}
+
+RMCounter::RMCounter(int levell, int module, const char* cls)
+ : doStuff(false)
+ {
+ if (RMDebug::debugOutput( levell, module, cls ))
+ {
+ //RMInit::dbgOut << "RMCounter() " << RMDebug::level << " ";
+ doStuff = true;
+ RMDebug::level++;
+ //RMInit::dbgOut << RMDebug::level << endl;
+ }
+ }
+
+RMCounter::~RMCounter()
+ {
+ if (doStuff == true)
+ {
+ //RMInit::dbgOut << "~RMCounter() " << RMDebug::level << " ";
+ RMDebug::level--;
+ //RMInit::dbgOut << RMDebug::level << endl;
+ }
+ }
+
diff --git a/raslib/rmdebug.hh b/raslib/rmdebug.hh
new file mode 100644
index 0000000..08e38cc
--- /dev/null
+++ b/raslib/rmdebug.hh
@@ -0,0 +1,382 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: rmdebug.hh
+ *
+ * PURPOSE:
+ * Contains debug stuff.
+ *
+ * COMMENTS:
+ *
+*/
+
+#ifndef _RMDEBUG_
+#define _RMDEBUG_
+
+#ifdef __VISUALC__
+#include <time.h>
+#else
+#include <sys/time.h>
+#endif
+
+#include "raslib/rminit.hh"
+#include "raslib/rm.hh"
+
+extern int RManDebug;
+extern int RManBenchmark;
+
+#ifdef RMANDEBUG
+
+#define RMDBGIF( levell, module, cls, text ) \
+ if (RMDebug::debugOutput( levell, module, cls )) { text }
+
+#define RMDBGENTER( levell, module, cls, text ) \
+ RMCounter rmCounter(levell, module, cls); \
+ if (RMDebug::debugOutput( levell, module, cls )) { \
+ RMInit::dbgOut << "ENTER "; RMInit::dbgOut.width(18); RMInit::dbgOut.setf(ios::left, ios::adjustfield); RMInit::dbgOut << cls << " "; RMDebug::indentLine(); RMInit::dbgOut << text << endl << std::flush; \
+ }
+
+#define RMDBGMIDDLE( levell, module, cls, text ) \
+ if (RMDebug::debugOutput( levell, module, cls )) { \
+ RMInit::dbgOut << "MIDDLE "; RMInit::dbgOut.width(18); RMInit::dbgOut.setf(ios::left, ios::adjustfield); RMInit::dbgOut << cls << " "; RMDebug::indentLine(); RMInit::dbgOut << text << endl << std::flush; \
+ }
+
+#define RMDBGONCE( levell, module, cls, text ) \
+ RMCounter rmCounter(levell, module, cls); \
+ if (RMDebug::debugOutput(levell, module, cls)) \
+ { \
+ RMInit::dbgOut << "ONCE "; RMInit::dbgOut.width(18); RMInit::dbgOut.setf(ios::left, ios::adjustfield); RMInit::dbgOut << cls << " "; \
+ RMDebug::indentLine(); \
+ RMInit::dbgOut << text << endl << std::flush; \
+ }
+
+#define RMDBGEXIT( levell, module, cls, text ) \
+ if (RMDebug::debugOutput( levell, module, cls )) { \
+ RMInit::dbgOut << "EXIT "; RMInit::dbgOut.width(18); RMInit::dbgOut.setf(ios::left, ios::adjustfield); RMInit::dbgOut << cls << " "; RMDebug::indentLine(); RMInit::dbgOut << text << endl << std::flush; \
+ }
+
+#define RMDBCLASS( t1, t2, t3, t4, t5 ) RMDebug localRMDebug = RMDebug( t1, t2, t3, t4, t5 );
+
+#else
+
+// Note: some parts of the code rely on these to be terminated by a ';'!
+#define RMDBGENTER( level, module, cls, text ) ;
+#define RMDBGMIDDLE( level, module, cls, text ) ;
+#define RMDBGONCE( level, module, cls, text ) ;
+#define RMDBGEXIT( level, module, cls, text ) ;
+#define RMDBGIF( level, module, cls, text) ;
+
+#define RMDBCLASS( t1, t2, t3, t4, t5 ) ;
+#endif
+
+#ifdef RMANBENCHMARK
+
+#define RMTIMER(class, func) RMTimer localRMTimer = RMTimer(class, func);
+
+#else
+
+#define RMTIMER(class, func)
+
+#endif
+
+//@ManMemo: Module: {\bf raslib}.
+
+/*@Doc:
+RMDebug is not strictly part of RasLib. It is a class used for
+generating debug output if compiling with RMANDEBUG defined. One way
+of using it is to put the following at the beginning of a function:
+
+{\tt RMDebug localRMDebug = RMDebug("className", "functionName",
+"moduleName", __FILE__, __LINE__");}
+
+This can be patched in automatically by a modified funchead.pl script.
+
+{\bf Functionality}
+
+Debug output printing class name, function name, module name, file
+name and line number given as parameters to the constructor is
+created, whenever the constructor is called. The destructor
+outputs class name and function name. If the static members {\tt
+debugModules} or {\tt debugClasses} are set, then only modules
+which are mentioned in the array of strings {\tt debugModules} or
+classes which are mentioned {\tt debugClasses} give debug output.
+{\tt debugModules} and {\tt debugClasses} can either be read from
+files named "rmdbmodules" and "rmdbclasses" or from the environment
+variables RMDBGMODULES and RMDBGCLASSES. The environment variables
+override the files. The contents of the files / variables are the
+names of the modules / classes separated by whitespace (space,
+newlines, ...). In the case of the modules each modulename may
+be followed by ",<dbgLevel>" to set the debug level for that
+module explizitly, otherwise the default is used.
+
+{\bf Interdependencies}
+
+If only certain modules or classes are to be debugged, RMDebug
+has to be initialized in {\Ref RMInit}. This is done by reading
+the files {\tt rmdbmodules} and {\tt rmdbclasses}. The files
+should contain names of modules resp. classes to be debugged, each
+(including the last one!) followed by end of line. */
+
+/**
+ * \defgroup RMs RM Classes
+ */
+
+/**
+ * \ingroup RMs
+ */
+
+class RMDebug : public RM_Class
+{
+public:
+ /// constructor, initializes members and prints message.
+ RMDebug(const char* newClass, const char* newFunc, const char* newModule,
+ const char* newFile, int newLine);
+ /// constructor taking an identifier to the module for more efficiency
+ RMDebug(int newLevel, const char* newClass, const char* newFun, int newModuleNum,
+ const char* newFile, int newLine);
+ /// destructor, prints message.
+ ~RMDebug(void);
+
+ /// for initializing modules and classes to debug.
+ static int initRMDebug(void);
+
+ /// get the debug level of a module by its number
+ static inline int getModuleDebugLevel(int modNum) {
+ return allModuleLevels[modNum];
+ }
+ /// get the name of a module by its number
+ static inline const char* getModuleName(int modNum) {
+ return allModuleNames[modNum];
+ }
+ /// indent by the amount specified by level
+ static inline void indentLine(void) {
+ for (int i=0; i<level; i++) RMInit::dbgOut << " ";
+ }
+
+ /// return whether debug output should happen for the given module, class
+ /// and debugging level
+ static int debugOutput(int dbgLevel, int modNum, const char* className);
+
+ /// all modules for debugging
+ enum {
+ module_adminif = 0,
+ module_applications,
+ module_blobif,
+ module_cachetamgr,
+ module_catalogif,
+ module_catalogmgr,
+ module_clientcomm,
+ module_conversion,
+ module_compression,
+ module_httpserver,
+ module_indexif,
+ module_indexmgr,
+ module_insertutils,
+ module_mddif,
+ module_mddmgr,
+ module_qlparser,
+ module_rasdl,
+ module_raslib,
+ module_rasodmg,
+ module_rasql,
+ module_server,
+ module_servercomm,
+ module_storageif,
+ module_storagemgr,
+ module_tilemgr,
+ module_tools,
+ module_utilities,
+ module_number
+ } RMDebugModules;
+ /*@ManMemo level of function calls (incremented by constructor,
+ decremented by destrctor. */
+ static int level;
+
+private:
+ /// checks, if messages should be printed.
+ int checkDebug(void);
+ /// loads a file containing text and returns a 0-terminated string
+ static char* loadTextFile(const char* name);
+ /*@Doc:
+ If {\tt debugModules} or {\tt debugClasses} is set, checks
+ if myModule or myClass is in the corresponding array.
+ */
+
+ /// name of class.
+ const char* myClass;
+ /// name of function (no parameters).
+ const char* myFunc;
+ /// name of module.
+ const char* myModule;
+ /// name of source file.
+ const char* myFile;
+ /// line of code where destructor call is.
+ int myLine;
+ /// number of module
+ int myModuleNum;
+ /// debugging level for this instance
+ int myDebugLevel;
+ /// debugging on for this class?
+ int myDebugOn;
+ /// number of strings in {\tt debugModules}.
+ static int numDebugModules;
+ /// array with pointers into names of modules to be debugged.
+ static char** debugModules;
+ /// names of modules to be debugged.
+ static char* debugModulesText;
+ /// number of strings in {\tt debugClasses}.
+ static int numDebugClasses;
+ /// array with pointers into names of classes to be debugged.
+ static char** debugClasses;
+ /// names of class es to be debugged.
+ static char* debugClassesText;
+ /// translate index of debug module into index of all modules
+ static int* transDebugModules;
+ /// names of all modules
+ static const char* allModuleNames[];
+ /// the debug levels for all modules
+ static int allModuleLevels[];
+};
+
+///Module: {\bf raslib}.
+
+/**
+RMTimer is not strictly part of RasLib. It is a class used for taking
+timing measurements if compiling with RMANBENCHMARK defined. One way
+of using it is to put the following at the beginning of a function:
+
+{\tt RMTIMER("className", "functionName");}
+
+If RMANBENCHMARK is defined this is expanded to:
+
+{\tt RMTimer localRMTimer = RMTimer("className", "functionName");}
+
+Time is taken between this line and exiting the block where this line
+was. For more elaborate timing measurements an RMTimer object can be
+used directly. All timing information is stored in the object, so
+multiple RMTimer objects can be used at the same time.
+
+If output is generated on RMInit::bmOut depends on the flag {\tt
+output} and the benchmark level. Output is generated if {\tt output}
+is TRUE and {\tt bmLevel} is lower than the global benchmark level
+stored in RManBenchmark. The flag {\tt output} can be changed with
+setOutput(). The function start() sets {\tt output} to TRUE, stop()
+sets {\tt output} to FALSE.
+
+{\bf Important}: If a RMTimer is used as a static variable, it must be
+ensured that no output is generated in the destructor either by
+calling stop() or by manually setting {\tt output} to FALSE using
+setOutput() before termination of the program. The reason is that
+potentially RMInit::bmOut may be destructed before the RMTimer
+destructor is called possibly causing a crash.
+*/
+
+/**
+ * \ingroup RMs
+ */
+
+class RMTimer : public RM_Class
+{
+public:
+ /// constructor, initializes members and starts timer.
+ inline RMTimer(const char* newClass, const char* newFunc,
+ int newBmLevel = 0);
+ /**
+ The parameters newClass and newFunc have to be string literals. Just
+ a pointer to them is stored. No output is generated if RManBenchmark
+ < newBmLevel.
+ */
+ /// destructor, calls stop().
+ inline ~RMTimer();
+ /// switch output on RMInit::bmOut on and off.
+ inline void setOutput(int newOutput);
+ /**
+ If newOutoutput is FALSE no output is created on RMInit::bmOut on
+ the following calls to stop() and ~RMTimer() until the next start().
+ */
+ /// pauses timer.
+ inline void pause();
+ /// resumes timer.
+ inline void resume();
+ /// resets timer.
+ inline void start();
+ /**
+ Also switches output to RMInit::bmOut on again.
+ */
+ /// prints time spent if output is TRUE.
+ inline void stop();
+ /**
+ Time spent is the time since construction or last start() excluding
+ the times between pause() and resume().
+ */
+private:
+ /// name of class.
+ const char* myClass;
+ /// name of function (no parameters).
+ const char* myFunc;
+ /// flag, if stop() should print timing information
+ int output;
+ /// stores benchmark level, checked before output.
+ int bmLevel;
+ // reference parameter for gettimeofday().
+#ifdef __VISUALC__
+ time_t acttime;
+#else
+ timeval acttime;
+#endif
+ /// accu for saving time in us
+ long accuTime;
+ /// flag indicating if the timer is currently running.
+ unsigned short running;
+ // reference parameter for gettimeofday, not used.
+ static struct timezone dummy;
+ /// used to calculate time spent in function.
+ long oldsec;
+ /// used to calculate time spent in function.
+ long oldusec;
+};
+///Module: {\bf raslib}.
+
+/**
+Objects of this class increment the indent level of RMDebug at construction time and decrease this level at destruction time.
+*/
+
+/**
+ * \ingroup RMs
+ */
+
+class RMCounter : public RM_Class
+{
+public:
+ /// constructor, increments indent level if the class should be debugged.
+ RMCounter(int levell, int module, const char* cls);
+ /// destructor, decrements indent level.
+ ~RMCounter();
+private:
+ bool doStuff;
+};
+
+
+#include "raslib/rmdebug.icc"
+
+#endif
diff --git a/raslib/rmdebug.icc b/raslib/rmdebug.icc
new file mode 100644
index 0000000..5c7a292
--- /dev/null
+++ b/raslib/rmdebug.icc
@@ -0,0 +1,120 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+// -*-C++-*- (for Emacs)
+
+inline
+RMTimer::RMTimer(const char* newClass, const char* newFunc, int newBmLevel)
+ : myClass(newClass), myFunc(newFunc), bmLevel(newBmLevel), running(0)
+{
+#ifdef __VISUALC__
+ /* Set time zone from TZ environment variable.If TZ is not set,
+ * the operating system is queried to obtain the default value
+ * for the variable
+ */
+ _tzset();
+#endif
+ start();
+}
+
+inline
+RMTimer::~RMTimer()
+{
+ stop();
+}
+
+inline void
+RMTimer::setOutput(int newOutput)
+{
+ output = newOutput;
+}
+
+inline void
+RMTimer::start()
+{
+ // reset accu
+ accuTime = 0;
+ // set output to TRUE
+ output = 1;
+ resume();
+}
+
+inline void
+RMTimer::pause()
+{
+ if( running )
+ {
+#ifdef __VISUALC__
+ // save start time
+ oldsec = acttime;
+ oldusec = 0; // Windows only counts the seconds (too slow??!!)
+
+ // get stop time
+ time(&acttime);
+
+ // add new time to accu
+ accuTime += (acttime-oldsec)*1000000;
+#else
+ // save start time
+ oldsec = acttime.tv_sec;
+ oldusec = acttime.tv_usec;
+
+ // get stop time
+ gettimeofday(&acttime, &dummy);
+
+ // add new time to accu
+ accuTime += (acttime.tv_sec-oldsec)*1000000 + acttime.tv_usec - oldusec;
+
+ // reset acttime.tv_usec which means that no timer is running
+ acttime.tv_usec = 0;
+#endif
+ // timer is not running
+ running = 0;
+ }
+}
+
+inline void
+RMTimer::resume()
+{
+#ifdef __VISUALC__
+ time(&acttime);
+#else
+ gettimeofday(&acttime, &dummy);
+#endif
+
+ // timer is running
+ running = 1;
+}
+
+inline void
+RMTimer::stop()
+{
+ pause();
+
+ if(output && RManBenchmark >= bmLevel ) {
+ RMInit::bmOut << "T: " << myClass << "::" << myFunc << ": "
+ << accuTime << "us" << std::endl;
+ // set output to FALSE
+ output = 0;
+ }
+}
diff --git a/raslib/rminit.cc b/raslib/rminit.cc
new file mode 100644
index 0000000..78c68cf
--- /dev/null
+++ b/raslib/rminit.cc
@@ -0,0 +1,321 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: rminit.cc
+ *
+ * MODULE: raslib
+ * CLASS: RMInit
+ *
+ * COMMENTS:
+ *
+*/
+
+static const char rcsid[] = "@(#)raslib, RMInit: $Header: /home/rasdev/CVS-repository/rasdaman/raslib/rminit.cc,v 1.36 2005/09/09 16:14:24 rasdev Exp $";
+
+#include "raslib/rminit.hh"
+
+#include "raslib/error.hh"
+#include "raslib/rmdebug.hh"
+
+#include <string.h>
+#include <stdlib.h>
+
+using std::cout;
+using std::ios;
+
+char* RMInit::userName = 0;
+bool RMInit::useTileContainer = false;
+bool RMInit::tiling;
+unsigned long RMInit::timeOut;
+bool RMInit::noTimeOut = 0;
+unsigned int RMInit::clientcommMaxRetry = 6; // changed from 100, with new wait algorithm in rnprotocol/rnpclientcomm.cc this is ~6sec -- PB 2005-sep-09
+unsigned int RMInit::clientcommSleep = 0;
+unsigned int RMInit::rpcMaxRetry = 5;
+
+r_Bytes RMInit::clientTileSize = 786432;
+
+RMInit::RMInit( char initApplicationType )
+ : applicationType( initApplicationType )
+{
+ char* optString;
+
+ if( applicationType == 'C' )
+ {
+ char* value;
+
+ // read environment options
+ optString = getenv("RMANCLIENTOPT");
+
+ //
+ // set log stream
+ //
+ if( optString && checkOptionString( optString, "-l", value ) )
+ if( value )
+ {
+ logFileOut.open( value );
+ logOut.rdbuf(logFileOut.rdbuf());
+ delete[] value;
+ }
+ else {
+ logOut.rdbuf(cout.rdbuf());
+ }
+ else
+ {
+ // default
+ logFileOut.open("/dev/null",ios::app); //"client.log");
+ logOut.rdbuf(logFileOut.rdbuf());
+ }
+
+
+
+ //
+ // set dbg stream
+ //
+ if( optString && checkOptionString( optString, "-d", value ) )
+ if( value )
+ {
+ dbgFileOut.open( value );
+ dbgOut.rdbuf(dbgFileOut.rdbuf());
+ delete[] value;
+ }
+ else
+ dbgOut.rdbuf(cout.rdbuf());
+ else
+ {
+ // default
+ dbgFileOut.open("/dev/null",ios::app); //"client.dbg");
+ dbgOut.rdbuf(dbgFileOut.rdbuf());
+ }
+
+
+ //
+ // set debug level
+ //
+ if( optString && checkOptionString( optString, "-dl", value ) )
+ if( value )
+ {
+ RManDebug = (int)strtoul( value, (char **)NULL, 10 );
+// It is not clarrified why the delete statement crashes with VISUALC.
+#ifndef __VISUALC__
+ delete[] value;
+#endif
+ }
+
+
+ //
+ // set bm stream
+ //
+ if( optString && checkOptionString( optString, "-b", value ) )
+ if( value )
+ {
+ bmFileOut.open( value );
+ bmOut.rdbuf(bmFileOut.rdbuf());
+ delete[] value;
+ }
+ else
+ bmOut.rdbuf(cout.rdbuf());
+ else
+ {
+ // default
+ bmFileOut.open("/dev/null",ios::app); //"client.bm");
+ bmOut.rdbuf(bmFileOut.rdbuf());
+ }
+
+
+ //
+ // set benchmark level
+ //
+ if( optString && checkOptionString( optString, "-bl", value ) )
+ if( value )
+ {
+ RManBenchmark = (int)strtoul( value, (char **)NULL, 10 );
+// It is not clarrified why the delete statement crashes with VISUALC.
+#ifndef __VISUALC__
+ delete[] value;
+#endif
+ }
+
+
+ //
+ // set tiling parameters
+ //
+ if(optString)
+ tiling = !checkOptionString( optString, "-notiling", value );
+ else
+ tiling = 1;
+
+ if( optString && checkOptionString( optString, "-tilesize", value ) )
+ if( value )
+ {
+ RMInit::clientTileSize = strtoul( value, (char **)NULL, 10 );
+ delete[] value;
+ }
+
+ if(optString && checkOptionString( optString, "-useTC", value ))
+ useTileContainer = true;
+ else
+ useTileContainer = false;
+
+ timeOut = 3600; // default
+ if( optString && checkOptionString( optString, "-timeout", value ) )
+ if( value )
+ {
+ timeOut = strtoul( value, (char **)NULL, 10 );
+ delete[] value;
+ }
+
+ if( optString && checkOptionString( optString, "-notimeout", value ) )
+ noTimeOut = 1;
+ else
+ noTimeOut = 0;
+ }
+ else
+ {
+ // default
+ logOut.rdbuf(cout.rdbuf());
+ dbgOut.rdbuf(cout.rdbuf());
+ bmOut.rdbuf(cout.rdbuf());
+ }
+
+ // initialize error text table
+ initTextTable();
+
+ // initialize user name
+ if( userName )
+ {
+ delete [] userName;
+ userName = 0;
+ }
+
+ optString = getenv("USER");
+ if( optString )
+ {
+ userName = new char[strlen(optString)+1];
+ strcpy( userName, optString );
+ }
+ else
+ {
+ userName = new char[8];
+ strcpy( userName, "unknown" );
+ }
+
+#ifdef RMANDEBUG
+ RMDebug::initRMDebug();
+#endif
+}
+
+
+
+RMInit::~RMInit()
+{
+ // reset output streams
+ logOut.rdbuf(NULL);
+ dbgOut.rdbuf(NULL);
+ bmOut.rdbuf(NULL);
+
+ // free error text table
+ freeTextTable();
+
+ if( userName )
+ {
+ delete [] userName;
+ userName = 0;
+ }
+}
+
+
+
+int
+RMInit::checkOptionString( const char* optString, const char* option, char* &value )
+{
+ char* optPos=0;
+ char* optValueStart;
+ char* optValueEnd;
+ int valueLength;
+
+ using namespace std;
+
+ value = 0;
+
+ if( (optString != NULL) && (option != NULL) )
+ {
+ unsigned short found = 0;
+
+ optPos = (char*)optString;
+
+ do{
+ optPos = strstr( optPos, option );
+
+ if( optPos )
+ {
+ // Check if character after option is either a space or end of string.
+ // If not, continue with search.
+
+ char* continuePos = optPos + strlen(option);
+
+ found = (*continuePos == ' ') || (*continuePos == '\0');
+
+ if( !found ) optPos = continuePos;
+ }
+
+ }while( !found && optPos != 0 );
+
+ }
+
+ if( optPos )
+ {
+
+ optValueStart = optPos + strlen(option); // move over option
+ while( *optValueStart == ' ' ) optValueStart++; // move over spaces
+
+ if( *optValueStart != '-' && *optValueStart != '\0' )
+ {
+ optValueEnd = optValueStart;
+ while( *optValueEnd != ' ' && *optValueEnd != '\0' ) optValueEnd++; // move over option value
+
+ valueLength = optValueEnd - optValueStart;
+ if( valueLength )
+ {
+ value = new char[valueLength+1];
+ strncpy( value, optValueStart, valueLength );
+ value[valueLength] = '\0';
+ }
+ }
+ }
+
+ /*
+ if( optPos )
+ {
+ cout << "Option " << option << " specified;" << flush;
+
+ if( value )
+ cout << " value: " << value << " length: " << strlen(value) << endl;
+ else
+ cout << endl;
+ }
+ else
+ cout << "Option " << option << " not specified." << endl;
+ */
+
+ return optPos != 0;
+}
diff --git a/raslib/rminit.hh b/raslib/rminit.hh
new file mode 100644
index 0000000..fc1ef9e
--- /dev/null
+++ b/raslib/rminit.hh
@@ -0,0 +1,181 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: rminit.hh
+ *
+ * PURPOSE:
+ * Contains the RMInit class.
+ *
+ * COMMENTS:
+ * - RASMGRPORT should be centrally defined
+*/
+
+#ifndef _RMINIT_
+#define _RMINIT_
+
+#include <iostream>
+using std::ios;
+using std::endl;
+
+#include <fstream>
+#include <raslib/mddtypes.hh>
+#include <raslib/rm.hh>
+
+//@ManMemo: Module: {\bf raslib}
+
+/*@Doc:
+
+ RMANVERSION is the version of the RasDaMan server times 1000 (int).
+ RPCVERSION is the version of the RPC interface times 1000 (int);
+
+*/
+
+//@Man: Version numbers
+// RMANVERSION now comes in via -DRMANVERSION -- PB 2003-sep-03
+// const int RMANVERSION = 5100;
+const int RPCVERSION = 1003;
+
+// default rasmgr port
+const int RASMGRPORT = 7001;
+
+// RPC timeout [secs]; used in clientcomm/rpcclientcomm.cc -- PB 2005-sep-09
+const unsigned int RPC_TIMEOUT = 3;
+
+// timeout in RNP communication
+const unsigned int RNP_COMM_TIMEOUT = 60;
+
+// timeout in nerver.cc
+const unsigned int RNP_TIMEOUT_LISTEN = 30;
+
+// maximum number of retries in rnprotocol/rnpclientcomm2.cc
+const unsigned int RNP_MAX_RETRY = 10;
+
+//@ManMemo: Module: {\bf raslib}
+
+/*@Doc:
+
+ Class {\tt RMInit} is supposed to be instantiated just once. The scope
+ of this instance is equal to the program scope (global variable)
+ and therefore lifetime of the {\tt RMInit} instance and the application
+ are the same. The constructor is used to allocate ressources needed
+ during the whole application and the destructor cleans up memory at
+ the end of the application.
+
+*/
+
+/**
+ * \ingroup RMs
+ */
+
+class RMInit : public RM_Class
+{
+ public:
+ /// constructor
+ RMInit( char applicationType );
+
+ /// destructor
+ ~RMInit();
+
+ /// output stream for log information
+ static std::ostream logOut;
+
+ /// output stream for debug information
+ static std::ostream dbgOut;
+
+ /// output stream for benchmark information
+ static std::ostream bmOut;
+
+ /// file output for log information
+ static std::ofstream logFileOut;
+
+ /// file output for debug information
+ static std::ofstream dbgFileOut;
+
+ /// file output for benchmark information
+ static std::ofstream bmFileOut;
+
+ /// name of the user
+ static char* userName;
+
+ /// use inlinetiles and inlinetile container index
+ static bool useTileContainer;
+
+ /// switch for turning on/off tiling
+ static bool tiling;
+
+ /// specifies time out in seconds
+ static unsigned long timeOut;
+
+ /// flag, if time out checking is enabled (causes sometimes problems because of signal handler)
+ static bool noTimeOut;
+
+ static r_Bytes clientTileSize;
+
+ static unsigned int clientcommMaxRetry;
+
+ static unsigned int clientcommSleep;
+
+ static unsigned int rpcMaxRetry;
+
+ private:
+ /// check the option string for the occurance of an option and return its value if available
+ int checkOptionString( const char* optString, const char* option, char* &value );
+ /**
+ The method searches for an option of type {\tt -option value } in the option string specified.
+ It returns 1 if the option is in the string, otherwise 0. If a value is given for the option
+ to check, it is returned by the reference pointer {\tt value}. The value has to freed using
+ {\tt delete[] value} after it is not needed anymore.
+ */
+
+ /// type of application can either be 'S' for server or 'C' for client
+ char applicationType;
+};
+
+// Macro for initialization of static members and creation of global RMInit instance
+// ---------------------------------------------------------------------------------
+// The macro has to be invoked exactly once in each executable using raslib.
+//
+// rasserver -> in servercomm.o
+// rasdaman clients -> in clientcomm.o
+// test programms without clientcomm.o and servercomm.o -> in main.o
+//
+// The reason is that initialisation of globals can be initialized in any
+// order if they are in different files. Only in one file the order is defined.
+// As it is implemented now, the streams have to be defined somewhere. This
+// could easily be done in rminit.cc. But the call to the constructor of RMInit
+// has to get a flag for client ('C') or server ('S') as a parameter. This has
+// be done somewhere else. In that case the constructor may be called before
+// initialization of the streams, the pogram crashes! If all initialisations
+// are in the same file, the order is defined. That is what this macro is for.
+//
+// Note: At some point it may be useful to reimplement this mess.
+
+#define RMINITGLOBALS( appMode ) std::ostream RMInit::logOut(std::cout.rdbuf()); \
+ std::ostream RMInit::dbgOut(std::cout.rdbuf()); \
+ std::ostream RMInit::bmOut(std::cout.rdbuf()); \
+ std::ofstream RMInit::logFileOut; \
+ std::ofstream RMInit::dbgFileOut; \
+ std::ofstream RMInit::bmFileOut; \
+ RMInit rmInit( appMode );
+
+#endif
diff --git a/raslib/scalar.cc b/raslib/scalar.cc
new file mode 100644
index 0000000..23603e4
--- /dev/null
+++ b/raslib/scalar.cc
@@ -0,0 +1,120 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: scalar.cc
+ *
+ * MODULE: raslib
+ * CLASS: r_Scalar
+ *
+ * COMMENTS:
+ *
+*/
+
+#ifdef __VISUALC__
+#include <strstrea.h>
+#else
+#include <strstream>
+#endif
+#include <string.h>
+#include <fstream>
+#include <stdlib.h>
+
+#include "raslib/rminit.hh"
+#include "raslib/scalar.hh"
+#include "raslib/basetype.hh"
+#include "raslib/error.hh"
+
+
+
+
+r_Scalar::r_Scalar( const r_Base_Type* newType )
+ : valueType(NULL)
+{
+ if( newType )
+ valueType = (r_Base_Type*)newType->clone();
+ else {
+ RMInit::logOut << "r_Scalar::r_Scalar(NULL) base type must be not NULL" << endl;
+ throw r_Error(SCALARWASPASSEDNULLTYPE);
+ }
+}
+
+
+
+r_Scalar::r_Scalar( const r_Scalar& obj )
+ : valueType(obj.valueType)
+{
+}
+
+
+
+r_Scalar::~r_Scalar()
+{
+ delete valueType;
+}
+
+
+
+const r_Scalar&
+r_Scalar::operator=( const r_Scalar& obj )
+{
+ if( this != &obj )
+ {
+ delete valueType;
+ valueType = (r_Base_Type*)obj.valueType->clone();
+ }
+
+ return *this;
+}
+
+bool
+r_Scalar::isStructure() const
+ {
+ return false;
+ }
+
+bool
+r_Scalar::isComplex() const
+ {
+ return false;
+ }
+
+bool
+r_Scalar::isPrimitive() const
+ {
+ return false;
+ }
+
+const r_Base_Type*
+r_Scalar::get_type() const
+{
+ return valueType;
+}
+
+
+std::ostream& operator<<( std::ostream& s, const r_Scalar& obj )
+{
+ obj.print_status( s );
+ return s;
+}
+
+
diff --git a/raslib/scalar.hh b/raslib/scalar.hh
new file mode 100644
index 0000000..84132b4
--- /dev/null
+++ b/raslib/scalar.hh
@@ -0,0 +1,100 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: scalar.hh
+ *
+ * MODULE: raslib
+ * CLASS: r_Scalar
+ *
+ * COMMENTS:
+ *
+ * The class represents a scalar type value.
+ *
+*/
+
+#ifndef _D_SCALAR_
+#define _D_SCALAR_
+
+#include <iosfwd>
+
+#include "raslib/error.hh"
+
+class r_Base_Type;
+
+//@ManMemo: Module: {\bf raslib}
+
+/*@Doc:
+
+ Class \Ref{r_Scalar} represents a scalar type value which
+ is either \Ref{r_Primitive} or \Ref{r_Structure}.
+
+*/
+
+class r_Scalar
+{
+ public:
+ /// constructs a scalar value
+ r_Scalar( const r_Base_Type* newType );
+
+ /// copy constructor
+ r_Scalar( const r_Scalar& obj );
+
+ /// destructor
+ virtual ~r_Scalar();
+
+ /// clone operator
+ virtual r_Scalar* clone() const=0;
+
+ /// operator for assigning a scalar
+ virtual const r_Scalar& operator= ( const r_Scalar& );
+
+ /// debug output
+ virtual void print_status(std::ostream& s) const = 0;
+
+ /// get type
+ virtual const r_Base_Type* get_type() const;
+
+ ///
+ virtual bool isStructure() const;
+
+ ///
+ virtual bool isComplex() const;
+
+ ///
+ virtual bool isPrimitive() const;
+
+ protected:
+ /// type
+ r_Base_Type* valueType;
+};
+
+
+
+//@ManMemo: Module: {\bf raslib}
+/**
+ Output stream operator for objects of type {\tt const} \Ref{r_Scalar}.
+*/
+extern std::ostream& operator<<(std::ostream& s, const r_Scalar& obj );
+
+#endif
+
diff --git a/raslib/shhopt.c b/raslib/shhopt.c
new file mode 100644
index 0000000..217c096
--- /dev/null
+++ b/raslib/shhopt.c
@@ -0,0 +1,485 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/* $Id: shhopt.c,v 1.4 2000/09/20 14:41:56 widmann Exp $ */
+/* *
+ * FILE shhopt.c
+ *
+ * DESCRIPTION Functions for parsing command line arguments. Values
+ * of miscellaneous types may be stored in variables,
+ * or passed to functions as specified.
+ *
+ * REQUIREMENTS Some systems lack the ANSI C -function strtoul. If your
+ * system is one of those, you'll ned to write one yourself,
+ * or get the GNU liberty-library (from prep.ai.mit.edu).
+ *
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+#include <errno.h>
+
+#include "shhopt.h"
+
+/**************************************************************************
+ * *
+ * P R I V A T E D A T A *
+ * *
+ **************************************************************************/
+
+static void optFatalFunc(const char *, ...);
+static void (*optFatal)(const char *format, ...) = optFatalFunc;
+
+
+
+/**************************************************************************
+ * *
+ * P R I V A T E F U N C T I O N S *
+ * *
+ **************************************************************************/
+
+/*-------------------------------------------------------------------------
+ *
+ * NAME optFatalFunc
+ *
+ * FUNCTION Show given message and abort the program.
+ *
+ * INPUT format, ...
+ * Arguments used as with printf().
+ *
+ * RETURNS Never returns. The program is aborted.
+ *
+ */
+void optFatalFunc(const char *format, ...)
+{
+ va_list ap;
+
+ fflush(stdout);
+ va_start(ap, format);
+ vfprintf(stderr, format, ap);
+ va_end(ap);
+ exit(99);
+}
+
+
+
+/*-------------------------------------------------------------------------
+ *
+ * NAME optStructCount
+ *
+ * FUNCTION Get number of options in a optStruct.
+ *
+ * INPUT opt array of possible options.
+ *
+ * RETURNS Number of options in the given array.
+ *
+ * DESCRIPTION Count elements in an optStruct-array. The strcture must
+ * be ended using an element of type OPT_END.
+ *
+ */
+static int optStructCount(optStruct opt[])
+{
+ int ret = 0;
+
+ while (opt[ret].type != OPT_END)
+ ++ret;
+ return ret;
+}
+
+
+
+/*-------------------------------------------------------------------------
+ *
+ * NAME optMatch
+ *
+ * FUNCTION Find a matching option.
+ *
+ * INPUT opt array of possible options.
+ * s string to match, without `-' or `--'.
+ * lng match long option, otherwise short.
+ *
+ * RETURNS Index to the option if found, -1 if not found.
+ *
+ * DESCRIPTION Short options are matched from the first character in
+ * the given string.
+ *
+ */
+static int optMatch(optStruct opt[], const char *s, int lng)
+{
+ int nopt, q, matchlen = 0;
+ char *p;
+
+ nopt = optStructCount(opt);
+ if (lng) {
+ if ((p = (char*)strchr(s, '=')) != NULL)
+ matchlen = p - s;
+ else
+ matchlen = strlen(s);
+ }
+ for (q = 0; q < nopt; q++) {
+ if (lng) {
+ if (!opt[q].longName)
+ continue;
+ if (strncmp(s, opt[q].longName, matchlen) == 0)
+ return q;
+ } else {
+ if (!opt[q].shortName)
+ continue;
+ if (*s == opt[q].shortName)
+ return q;
+ }
+ }
+ return -1;
+}
+
+
+
+/*-------------------------------------------------------------------------
+ *
+ * NAME optString
+ *
+ * FUNCTION Return a (static) string with the option name.
+ *
+ * INPUT opt the option to stringify.
+ * lng is it a long option?
+ *
+ * RETURNS Pointer to static string.
+ *
+ */
+static char *optString(optStruct *opt, int lng)
+{
+ static char ret[31];
+
+ if (lng) {
+ strcpy(ret, "--");
+ strncpy(ret + 2, opt->longName, 28);
+ } else {
+ ret[0] = '-';
+ ret[1] = opt->shortName;
+ ret[2] = '\0';
+ }
+ return ret;
+}
+
+
+
+/*-------------------------------------------------------------------------
+ *
+ * NAME optNeedsArgument
+ *
+ * FUNCTION Check if an option requires an argument.
+ *
+ * INPUT opt the option to check.
+ *
+ * RETURNS Boolean value.
+ *
+ */
+static int optNeedsArgument(optStruct *opt)
+{
+ return opt->type == OPT_STRING
+ || opt->type == OPT_INT
+ || opt->type == OPT_UINT
+ || opt->type == OPT_LONG
+ || opt->type == OPT_ULONG;
+}
+
+
+
+/*-------------------------------------------------------------------------
+ *
+ * NAME argvRemove
+ *
+ * FUNCTION Remove an entry from an argv-array.
+ *
+ * INPUT argc pointer to number of options.
+ * argv array of option-/argument-strings.
+ * i index of option to remove.
+ *
+ * OUTPUT argc new argument count.
+ * argv array with given argument removed.
+ *
+ */
+static void argvRemove(int *argc, char *argv[], int i)
+{
+ if (i >= *argc)
+ return;
+ while (i++ < *argc)
+ argv[i - 1] = argv[i];
+ --*argc;
+}
+
+
+
+/*-------------------------------------------------------------------------
+ *
+ * NAME optExecute
+ *
+ * FUNCTION Perform the action of an option.
+ *
+ * INPUT opt array of possible options.
+ * arg argument to option, if it applies.
+ * lng was the option given as a long option?
+ *
+ * RETURNS Nothing. Aborts in case of error.
+ *
+ */
+void optExecute(optStruct *opt, char *arg, int lng)
+{
+ switch (opt->type) {
+ case OPT_FLAG:
+ if (opt->flags & OPT_CALLFUNC)
+ ((void (*)(void)) opt->arg)();
+ else
+ *((int *) opt->arg) = 1;
+ break;
+
+ case OPT_STRING:
+ if (opt->flags & OPT_CALLFUNC)
+ ((void (*)(char *)) opt->arg)(arg);
+ else
+ *((char **) opt->arg) = arg;
+ break;
+
+ case OPT_INT:
+ case OPT_LONG: {
+ long tmp;
+ char *e;
+
+ tmp = strtol(arg, &e, 10);
+ if (*e)
+ optFatal("invalid number `%s'\n", arg);
+ if (errno == ERANGE
+ || (opt->type == OPT_INT && (tmp > INT_MAX || tmp < INT_MIN)))
+ optFatal("number `%s' to `%s' out of range\n",
+ arg, optString(opt, lng));
+ if (opt->type == OPT_INT) {
+ if (opt->flags & OPT_CALLFUNC)
+ ((void (*)(int)) opt->arg)((int) tmp);
+ else
+ *((int *) opt->arg) = (int) tmp;
+ } else /* OPT_LONG */ {
+ if (opt->flags & OPT_CALLFUNC)
+ ((void (*)(long)) opt->arg)(tmp);
+ else
+ *((long *) opt->arg) = tmp;
+ }
+ break;
+ }
+
+ case OPT_UINT:
+ case OPT_ULONG: {
+ unsigned long tmp;
+ char *e;
+
+ tmp = strtoul(arg, &e, 10);
+ if (*e)
+ optFatal("invalid number `%s'\n", arg);
+ if (errno == ERANGE
+ || (opt->type == OPT_UINT && tmp > UINT_MAX))
+ optFatal("number `%s' to `%s' out of range\n",
+ arg, optString(opt, lng));
+ if (opt->type == OPT_UINT) {
+ if (opt->flags & OPT_CALLFUNC)
+ ((void (*)(unsigned)) opt->arg)((unsigned) tmp);
+ else
+ *((unsigned *) opt->arg) = (unsigned) tmp;
+ } else /* OPT_ULONG */ {
+ if (opt->flags & OPT_CALLFUNC)
+ ((void (*)(unsigned long)) opt->arg)(tmp);
+ else
+ *((unsigned long *) opt->arg) = tmp;
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+}
+
+
+
+/**************************************************************************
+ * *
+ * P U B L I C F U N C T I O N S *
+ * *
+ **************************************************************************/
+
+/*-------------------------------------------------------------------------
+ *
+ * NAME optSetFatalFunc
+ *
+ * FUNCTION Set function used to display error message and exit.
+ *
+ * SYNOPSIS #include "shhmsg.h"
+ * void optSetFatalFunc(void (*f)(const char *, ...));
+ *
+ * INPUT f function accepting printf()'like parameters,
+ * that _must_ abort the program.
+ *
+ */
+void optSetFatalFunc(void (*f)(const char *, ...))
+{
+ optFatal = f;
+}
+
+
+
+/*-------------------------------------------------------------------------
+ *
+ * NAME optParseOptions
+ *
+ * FUNCTION Parse commandline options.
+ *
+ * SYNOPSIS #include "shhopt.h"
+ * void optParseOptions(int *argc, char *argv[],
+ * optStruct opt[], int allowNegNum);
+ *
+ * INPUT argc Pointer to number of options.
+ * argv Array of option-/argument-strings.
+ * opt Array of possible options.
+ * allowNegNum
+ * a negative number is not to be taken as
+ * an option.
+ *
+ * OUTPUT argc new argument count.
+ * argv array with arguments removed.
+ *
+ * RETURNS Nothing. Aborts in case of error.
+ *
+ * DESCRIPTION This function checks each option in the argv-array
+ * against strings in the opt-array, and `executes' any
+ * matching action. Any arguments to the options are
+ * extracted and stored in the variables or passed to
+ * functions pointed to by entries in opt.
+ *
+ * Options and arguments used are removed from the argv-
+ * array, and argc is decreased accordingly.
+ *
+ * Any error leads to program abortion.
+ *
+ */
+void optParseOptions(int *argc, char *argv[], optStruct opt[], int allowNegNum)
+{
+ int ai, /* argv index. */
+ optarg, /* argv index of option argument, or -1 if none. */
+ mi, /* Match index in opt. */
+ done;
+ char *arg, /* Pointer to argument to an option. */
+ *o, /* pointer to an option character */
+ *p;
+
+ /*
+ * Loop through all arguments.
+ */
+ for (ai = 0; ai < *argc; ) {
+ /*
+ * "--" indicates that the rest of the argv-array does not
+ * contain options.
+ */
+ if (strcmp(argv[ai], "--") == 0) {
+ argvRemove(argc, argv, ai);
+ break;
+ }
+
+ if (allowNegNum && argv[ai][0] == '-' && isdigit(argv[ai][1])) {
+ ++ai;
+ continue;
+ } else if (strncmp(argv[ai], "--", 2) == 0) {
+ /* long option */
+ /* find matching option */
+ if ((mi = optMatch(opt, argv[ai] + 2, 1)) < 0)
+ optFatal("unrecognized option `%s'\n", argv[ai]);
+
+ /* possibly locate the argument to this option. */
+ arg = NULL;
+ if ((p = strchr(argv[ai], '=')) != NULL)
+ arg = p + 1;
+
+ /* does this option take an argument? */
+ optarg = -1;
+ if (optNeedsArgument(&opt[mi])) {
+ /* option needs an argument. find it. */
+ if (!arg) {
+ if ((optarg = ai + 1) == *argc)
+ optFatal("option `%s' requires an argument\n",
+ optString(&opt[mi], 1));
+ arg = argv[optarg];
+ }
+ } else {
+ if (arg)
+ optFatal("option `%s' doesn't allow an argument\n",
+ optString(&opt[mi], 1));
+ }
+ /* perform the action of this option. */
+ optExecute(&opt[mi], arg, 1);
+ /* remove option and any argument from the argv-array. */
+ if (optarg >= 0)
+ argvRemove(argc, argv, ai);
+ argvRemove(argc, argv, ai);
+ } else if (*argv[ai] == '-') {
+ /* A dash by itself is not considered an option. */
+ if (argv[ai][1] == '\0') {
+ ++ai;
+ continue;
+ }
+ /* Short option(s) following */
+ o = argv[ai] + 1;
+ done = 0;
+ optarg = -1;
+ while (*o && !done) {
+ /* find matching option */
+ if ((mi = optMatch(opt, o, 0)) < 0)
+ optFatal("unrecognized option `-%c'\n", *o);
+
+ /* does this option take an argument? */
+ optarg = -1;
+ arg = NULL;
+ if (optNeedsArgument(&opt[mi])) {
+ /* option needs an argument. find it. */
+ arg = o + 1;
+ if (!*arg) {
+ if ((optarg = ai + 1) == *argc)
+ optFatal("option `%s' requires an argument\n",
+ optString(&opt[mi], 0));
+ arg = argv[optarg];
+ }
+ done = 1;
+ }
+ /* perform the action of this option. */
+ optExecute(&opt[mi], arg, 0);
+ ++o;
+ }
+ /* remove option and any argument from the argv-array. */
+ if (optarg >= 0)
+ argvRemove(argc, argv, ai);
+ argvRemove(argc, argv, ai);
+ } else {
+ /* a non-option argument */
+ ++ai;
+ }
+ }
+}
diff --git a/raslib/shhopt.h b/raslib/shhopt.h
new file mode 100644
index 0000000..2fca504
--- /dev/null
+++ b/raslib/shhopt.h
@@ -0,0 +1,56 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+/* $Id: shhopt.h,v 1.4 2000/09/20 14:41:56 widmann Exp $ */
+#ifndef SHHOPT_H
+#define SHHOPT_H
+
+/* constants for recognized option types. */
+typedef enum {
+ OPT_END, /* nothing. used as ending element. */
+ OPT_FLAG, /* no argument following. sets variable to 1. */
+ OPT_STRING, /* string argument. */
+ OPT_INT, /* signed integer argument. */
+ OPT_UINT, /* unsigned integer argument. */
+ OPT_LONG, /* signed long integer argument. */
+ OPT_ULONG /* unsigned long integer argument. */
+} optArgType;
+
+/* flags modifying the default way options are handeled. */
+#define OPT_CALLFUNC 1 /* pass argument to a function. */
+
+typedef struct {
+ char shortName; /* Short option name. */
+ char *longName; /* Long option name, no including '--'. */
+ optArgType type; /* Option type. */
+ void *arg; /* Pointer to variable to fill with argument,
+ * or pointer to function if Type == OPT_FUNC. */
+ int flags; /* Modifier flags. */
+} optStruct;
+
+
+void optSetFatalFunc(void (*f)(const char *, ...));
+void optParseOptions(int *argc, char *argv[],
+ optStruct opt[], int allowNegNum);
+
+#endif
diff --git a/raslib/sinterval.cc b/raslib/sinterval.cc
new file mode 100644
index 0000000..e05857f
--- /dev/null
+++ b/raslib/sinterval.cc
@@ -0,0 +1,1018 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: sinterval.cc
+ *
+ * MODULE: raslib
+ * CLASS: r_Sinterval
+ *
+ * COMMENTS:
+ *
+*/
+
+static const char rcsid[] = "@(#)raslib, r_Sinterval: $Id: sinterval.cc,v 1.29 2002/08/19 11:11:25 coman Exp $";
+
+#include "sinterval.hh"
+
+#include <string>
+#include <cstring>
+
+#ifdef __VISUALC__
+#include <strstrea.h>
+#else
+#include <strstream>
+#endif
+
+// for min and max
+#include <algorithm>
+
+using namespace std;
+
+
+#include "raslib/error.hh"
+#include "raslib/rminit.hh"
+
+r_Sinterval::r_Sinterval()
+ : lower_bound(0),
+ upper_bound(0),
+ low_fixed(false),
+ high_fixed(false)
+{
+}
+
+
+r_Sinterval::r_Sinterval( char* stringRep ) throw(r_Eno_interval)
+ : lower_bound(0),
+ upper_bound(0),
+ low_fixed(false),
+ high_fixed(false)
+{
+ if(!stringRep) {
+ RMInit::dbgOut << "r_Sinterval::r_Sinterval(" << (stringRep?stringRep: "NULL") << ")" << std::endl;
+ throw r_Eno_interval();
+ }
+
+ char charToken = 0;
+ r_Range valueToken = 0;
+
+ // for parsing the string
+ std::istrstream str(stringRep, strlen(stringRep) + 1);
+
+ str >> charToken;
+ if(charToken == '*')
+ set_low('*');
+ else
+ {
+ str.putback(charToken);
+ str >> valueToken;
+ set_low(valueToken);
+ }
+
+ str >> charToken;
+ if(charToken != ':')
+ {
+ // error
+ lower_bound=0;
+ upper_bound=0;
+ low_fixed=false;
+ high_fixed=false;
+
+ RMInit::dbgOut << "r_Sinterval::r_Sinterval(" << stringRep << ") string doesn't have the pattern a:b" << endl;
+ throw r_Eno_interval();
+ }
+
+ str >> charToken;
+ if(charToken == '*')
+ set_high('*');
+ else
+ {
+ str.putback(charToken);
+ str >> valueToken;
+ set_high(valueToken);
+ }
+}
+
+
+r_Sinterval::r_Sinterval( r_Range low, r_Range high ) throw( r_Eno_interval )
+ : lower_bound(low),
+ upper_bound(high),
+ low_fixed(true),
+ high_fixed(true)
+{
+ if( low > high )
+ {
+ RMInit::dbgOut << "r_Sinterval::r_Sinterval(" << low << ", " << high << ") not a interval" << endl;
+ throw r_Eno_interval();
+ }
+}
+
+
+r_Sinterval::r_Sinterval( char, r_Range high )
+ : lower_bound(0),
+ upper_bound(high),
+ low_fixed(false),
+ high_fixed(true)
+{
+}
+
+
+r_Sinterval::r_Sinterval( r_Range low, char )
+ : lower_bound(low),
+ upper_bound(0),
+ low_fixed(true),
+ high_fixed(false)
+{
+}
+
+
+r_Sinterval::r_Sinterval( char, char)
+ : lower_bound(0),
+ upper_bound(0),
+ low_fixed(false),
+ high_fixed(false)
+{
+}
+
+
+bool
+r_Sinterval::operator==( const r_Sinterval& interval ) const
+{
+ bool returnValue=true;
+
+ if (low_fixed)
+ returnValue = interval.low_fixed && lower_bound == interval.lower_bound;
+ else
+ returnValue = !interval.low_fixed;//other is fixed -> false
+ if (returnValue)
+ {
+ if( high_fixed )
+ returnValue = interval.high_fixed && upper_bound == interval.upper_bound;
+ else
+ returnValue = !interval.high_fixed;
+ }
+
+ return returnValue;
+}
+
+
+
+bool
+r_Sinterval::operator!=( const r_Sinterval& interval ) const
+{
+ return !operator==( interval );
+}
+
+r_Range
+r_Sinterval::get_extent() const throw(r_Error)
+ {
+ r_Range ext;
+
+ if(!low_fixed || !high_fixed) {
+ RMInit::dbgOut << "r_Sinterval::get_extent() low or high are not fixed (" << *this << ")" << std::endl;
+ throw r_Error(INTERVALOPEN);
+ }
+
+ ext = upper_bound - lower_bound + 1;
+
+ return ext;
+ }
+
+void
+r_Sinterval::set_low ( r_Range low ) throw( r_Eno_interval ) {
+ if( high_fixed && low > upper_bound ) {
+ RMInit::dbgOut << "r_Sinterval::set_low(" << low << ") not an interval (" << *this << ")" << endl;
+ throw r_Eno_interval();
+ }
+
+ lower_bound = low;
+ low_fixed = true;
+}
+
+
+void
+r_Sinterval::set_high( r_Range high ) throw( r_Eno_interval )
+{
+ if( low_fixed && high < lower_bound ) {
+ RMInit::dbgOut << "r_Sinterval::set_high(" << high << ") not an interval (" << *this << ")" << endl;
+ throw r_Eno_interval();
+ }
+
+ upper_bound = high;
+ high_fixed = true;
+}
+
+
+void
+r_Sinterval::set_interval( r_Range low, r_Range high ) throw( r_Eno_interval )
+{
+ if( low > high ) {
+ RMInit::dbgOut << "r_Sinterval::set_interval(" << low << ", " << high << ") not an interval (" << *this << ")" << endl;
+ throw r_Eno_interval();
+ }
+
+ lower_bound = low;
+ upper_bound = high;
+ low_fixed = true;
+ high_fixed = true;
+}
+
+
+void
+r_Sinterval::set_interval( char, r_Range high )
+{
+ lower_bound = 0;
+ upper_bound = high;
+ low_fixed = false;
+ high_fixed = true;
+}
+
+
+void
+r_Sinterval::set_interval( r_Range low, char )
+{
+ lower_bound = low;
+ upper_bound = 0;
+ low_fixed = true;
+ high_fixed = false;
+}
+
+
+void
+r_Sinterval::set_interval( char, char )
+{
+ lower_bound = 0;
+ upper_bound = 0;
+ low_fixed = false;
+ high_fixed = false;
+}
+
+
+bool
+r_Sinterval::intersects_with( const r_Sinterval& interval ) const
+{
+ int classnr = classify( *this, interval );
+
+ return classnr != 1 && classnr != 6 && classnr != 16 && classnr != 21 &&
+ classnr != 26 && classnr != 31 && classnr != 34 && classnr != 37;
+}
+
+
+r_Sinterval&
+r_Sinterval::union_of( const r_Sinterval& interval1, const r_Sinterval& interval2 ) throw( r_Eno_interval )
+{
+ *this = calc_union( interval1, interval2 );
+
+ return *this;
+}
+
+
+r_Sinterval&
+r_Sinterval::union_with( const r_Sinterval& interval ) throw( r_Eno_interval )
+{
+ *this = calc_union( interval, *this );
+
+ return *this;
+}
+
+
+r_Sinterval&
+r_Sinterval::operator+=( const r_Sinterval& interval ) throw( r_Eno_interval )
+{
+ *this = calc_union( interval, *this );
+
+ return *this;
+}
+
+
+r_Sinterval
+r_Sinterval::create_union( const r_Sinterval& interval ) const throw( r_Eno_interval )
+{
+ r_Sinterval result;
+
+ result = calc_union( interval, *this );
+
+ return result;
+}
+
+
+r_Sinterval
+r_Sinterval::operator+( const r_Sinterval& interval ) const throw( r_Eno_interval )
+{
+ r_Sinterval result;
+
+ result = calc_union( interval, *this );
+
+ return result;
+}
+
+
+r_Sinterval&
+r_Sinterval::difference_of( const r_Sinterval& interval1, const r_Sinterval& interval2 ) throw( r_Eno_interval )
+{
+ *this = calc_difference( interval1, interval2 );
+
+ return *this;
+}
+
+
+r_Sinterval&
+r_Sinterval::difference_with( const r_Sinterval& interval ) throw( r_Eno_interval )
+{
+ *this = calc_difference( interval, *this );
+
+ return *this;
+}
+
+
+
+r_Sinterval&
+r_Sinterval::operator-=( const r_Sinterval& interval ) throw( r_Eno_interval )
+{
+ *this = calc_difference( interval, *this );
+
+ return *this;
+}
+
+
+r_Sinterval
+r_Sinterval::create_difference( const r_Sinterval& interval ) const throw( r_Eno_interval )
+{
+ r_Sinterval result;
+
+ result = calc_difference( interval, *this );
+
+ return result;
+}
+
+
+r_Sinterval
+r_Sinterval::operator-( const r_Sinterval& interval ) const throw( r_Eno_interval )
+{
+ r_Sinterval result;
+
+ result = calc_difference( interval, *this );
+
+ return result;
+}
+
+
+r_Sinterval&
+r_Sinterval::intersection_of( const r_Sinterval& interval1, const r_Sinterval& interval2 ) throw( r_Eno_interval )
+{
+ *this = calc_intersection( interval1, interval2 );
+
+ return *this;
+}
+
+
+r_Sinterval&
+r_Sinterval::intersection_with( const r_Sinterval& interval ) throw( r_Eno_interval )
+{
+ *this = calc_intersection( interval, *this );
+
+ return *this;
+}
+
+
+r_Sinterval&
+r_Sinterval::operator*=( const r_Sinterval& interval ) throw( r_Eno_interval )
+{
+ *this = calc_intersection( interval, *this );
+
+ return *this;
+}
+
+
+r_Sinterval
+r_Sinterval::create_intersection( const r_Sinterval& interval ) const throw( r_Eno_interval )
+{
+ r_Sinterval result;
+
+ result = calc_intersection( interval, *this );
+
+ return result;
+}
+
+
+r_Sinterval
+r_Sinterval::operator*( const r_Sinterval& interval ) const throw( r_Eno_interval )
+{
+ r_Sinterval result;
+
+ result = calc_intersection( interval, *this );
+
+ return result;
+}
+
+
+r_Sinterval&
+r_Sinterval::closure_of( const r_Sinterval& interval1, const r_Sinterval& interval2 ) throw( r_Eno_interval )
+{
+ *this = calc_closure( interval1, interval2 );
+
+ return *this;
+}
+
+
+r_Sinterval&
+r_Sinterval::closure_with( const r_Sinterval& interval ) throw( r_Eno_interval )
+{
+ *this = calc_closure( interval, *this );
+
+ return *this;
+}
+
+
+r_Sinterval
+r_Sinterval::create_closure( const r_Sinterval& interval ) const throw( r_Eno_interval )
+{
+ r_Sinterval result;
+
+ result = calc_closure( interval, *this );
+
+ return result;
+}
+
+
+void
+r_Sinterval::print_status( std::ostream& s ) const
+{
+ if( low_fixed )
+ s << lower_bound;
+ else
+ s << "*";
+
+ s << ":";
+
+ if( high_fixed )
+ s << upper_bound;
+ else
+ s << "*";
+}
+
+
+r_Bytes
+r_Sinterval::get_storage_size( ) const
+{
+ return ( 2 * ( sizeof( r_Range ) + sizeof(bool) ) );
+}
+
+r_Sinterval
+r_Sinterval::calc_union( const r_Sinterval& a, const r_Sinterval& b ) const throw( r_Eno_interval )
+{
+ r_Sinterval result;
+
+ switch( classify( a, b ) )
+ {
+ case 2:
+ case 7:
+ case 9:
+ case 12:
+ case 22:
+ case 23:
+ case 27:
+ case 28:
+ case 35:
+ case 36:
+ // result = [a1:b2]
+
+ if( a.is_low_fixed() )
+ result.set_low( a.low() );
+ else
+ result.set_low('*');
+
+ if( b.is_high_fixed() )
+ result.set_high( b.high() );
+ else
+ result.set_high('*');
+
+ break;
+
+ case 4:
+ case 8:
+ case 10:
+ case 13:
+ case 17:
+ case 18:
+ case 32:
+ case 33:
+ case 38:
+ case 39:
+ // result = [b1:a2]
+
+ if( b.is_low_fixed() )
+ result.set_low( b.low() );
+ else
+ result.set_low('*');
+
+ if( a.is_high_fixed() )
+ result.set_high( a.high() );
+ else
+ result.set_high('*');
+
+ break;
+
+ case 3:
+ case 11:
+ case 14:
+ case 15:
+ case 19:
+ case 20:
+ case 41:
+ case 42:
+ case 43:
+ case 44:
+ case 46:
+ case 48:
+ case 49:
+ case 52:
+ result = a;
+ break;
+
+ case 5:
+ case 24:
+ case 25:
+ case 29:
+ case 30:
+ case 40:
+ case 45:
+ case 47:
+ case 50:
+ case 51:
+ result = b;
+ break;
+
+ default: // case in { 1, 6, 16, 21, 26, 31, 34, 37 }
+ {
+ RMInit::dbgOut << "r_Sinterval::calc_union(" << a << ", " << b << ") not an interval" << endl;
+ throw r_Eno_interval();
+ }
+ }
+
+ return result;
+}
+
+
+r_Sinterval
+r_Sinterval::calc_difference( const r_Sinterval& a, const r_Sinterval& b ) const throw( r_Eno_interval )
+{
+ r_Sinterval result;
+
+ switch( classify( a, b ) )
+ {
+ case 2:
+ case 9:
+ case 20:
+ case 23:
+ case 28:
+ case 36:
+ case 39:
+ case 43:
+ case 49:
+ // result = [a1:b1]
+
+ if( a.is_low_fixed() )
+ result.set_low( a.low() );
+ else
+ result.set_low('*');
+
+ if( b.is_low_fixed() )
+ result.set_high( b.low() );
+ else
+ result.set_high('*');
+
+ break;
+
+ case 1:
+ case 6:
+ case 7:
+ case 8:
+ case 16:
+ case 17:
+ case 21:
+ case 22:
+ case 26:
+ case 27:
+ case 31:
+ case 32:
+ case 34:
+ case 35:
+ case 37:
+ case 38:
+ result = a;
+ break;
+
+ case 4:
+ case 10:
+ case 15:
+ case 18:
+ case 33:
+ case 42:
+ case 48:
+ // result = [b2:a2]
+
+ if( b.is_high_fixed() )
+ result.set_low( b.high() );
+ else
+ result.set_low('*');
+
+ if( a.is_high_fixed() )
+ result.set_high( a.high() );
+ else
+ result.set_high('*');
+
+ break;
+
+ default: // case in { 3, 5, 11, 12, 13, 14, 19, 24, 25, 29, 30, 40, 41, 44, 45, 46, 47, 50, 51, 52 }
+ {
+ RMInit::dbgOut << "r_Sinterval::calc_difference(" << a << ", " << b << ") not an interval" << endl;
+ throw r_Eno_interval();
+ }
+ }
+
+ return result;
+}
+
+
+r_Sinterval
+r_Sinterval::calc_intersection( const r_Sinterval& a, const r_Sinterval& b ) const throw( r_Eno_interval )
+{
+ r_Sinterval result;
+
+ switch( classify( a, b ) )
+ {
+ case 4:
+ case 18:
+ case 33:
+ case 39:
+ // result = [a1:b2]
+
+ if( a.is_low_fixed() )
+ result.set_low( a.low() );
+ else
+ result.set_low('*');
+
+ if( b.is_high_fixed() )
+ result.set_high( b.high() );
+ else
+ result.set_high('*');
+
+ break;
+
+ case 2:
+ case 23:
+ case 28:
+ case 36:
+ // result = [b1:a2]
+
+ if( b.is_low_fixed() )
+ result.set_low( b.low() );
+ else
+ result.set_low('*');
+
+ if( a.is_high_fixed() )
+ result.set_high( a.high() );
+ else
+ result.set_high('*');
+
+ break;
+
+ case 5:
+ case 11:
+ case 12:
+ case 13:
+ case 24:
+ case 25:
+ case 29:
+ case 30:
+ case 40:
+ case 41:
+ case 44:
+ case 45:
+ case 47:
+ case 50:
+ case 51:
+ case 52:
+ result = a;
+ break;
+
+ case 3:
+ case 9:
+ case 10:
+ case 14:
+ case 15:
+ case 19:
+ case 20:
+ case 42:
+ case 43:
+ case 46:
+ case 48:
+ case 49:
+ result = b;
+ break;
+
+ case 7:
+ case 22:
+ case 27:
+ case 35:
+ // result = [a2:a2]
+
+ if( a.is_high_fixed() )
+ result.set_interval( a.high(), a.high() );
+ else
+ result.set_interval( '*', '*' );
+
+ break;
+
+ case 8:
+ case 17:
+ case 32:
+ case 38:
+ // result = [b2:b2]
+
+ if( b.is_high_fixed() )
+ result.set_interval( b.high(), b.high() );
+ else
+ result.set_interval( '*', '*' );
+
+ break;
+
+ default: // case in { 1, 6, 16, 21, 26, 31, 34, 37 }
+ RMInit::dbgOut << "r_Sinterval::calc_intersection(" << a << ", " << b << ") not an interval" << endl;
+ throw r_Eno_interval();
+ }
+
+ return result;
+}
+
+
+r_Sinterval
+r_Sinterval::calc_closure( const r_Sinterval& a, const r_Sinterval& b ) const throw( r_Eno_interval )
+{
+ r_Sinterval closure;
+
+ if( !a.is_low_fixed() || !b.is_low_fixed() )
+ closure.set_low('*');
+ else
+ closure.set_low( std::min( a.low(), b.low() ) );
+
+ if( !a.is_high_fixed() || !b.is_high_fixed() )
+ closure.set_high('*');
+ else
+ closure.set_high( std::max( a.high(), b.high() ) );
+
+ return closure;
+}
+
+
+/*************************************************************
+ * Method name...: classify
+ *
+ * Arguments.....: Two intervals for the classification.
+ * Return value..: The classification class number (1..52).
+ * Description...: The method classifies the two intervals into
+ * one of 13 classes according to their spatial
+ * relationship. Based on the classification, the
+ * result of the operations union, difference,
+ * and intersection can be calculated as shown
+ * in the table in file sinterval.hh:
+ ************************************************************/
+
+int
+r_Sinterval::classify( const r_Sinterval& a, const r_Sinterval& b ) const
+{
+ int classification = 0;
+
+ if( a.is_low_fixed() && a.is_high_fixed() && b.is_low_fixed() && b.is_high_fixed() )
+ {
+ // classification 1..13
+
+ if( a.low() < b.low() )
+ {
+ if( a.high() < b.high() )
+ {
+ if( a.high() < b.low() )
+ classification = 1;
+ else
+ if( a.high() == b.low() )
+ classification = 7;
+ else
+ classification = 2;
+ }
+ else if( a.high() == b.high() )
+ classification = 9;
+ else
+ classification = 3;
+ }
+ else if( a.low() == b.low() )
+ {
+ if( a.high() < b.high() )
+ classification = 12;
+ else if( a.high() == b.high() )
+ classification = 11;
+ else
+ classification = 10;
+ }
+ else
+ if( a.high() < b.high() )
+ classification = 5;
+ else if( a.high() == b.high() )
+ classification = 13;
+ else
+ {
+ if( a.low() < b.high() )
+ classification = 4;
+ else if( a.low() == b.high() )
+ classification = 8;
+ else
+ classification = 6;
+ }
+ }
+ else if( a.is_low_fixed() && !a.is_high_fixed() && b.is_low_fixed() && b.is_high_fixed() )
+ {
+ // classification 14..18
+
+ if( a.low() < b.low() )
+ classification = 14;
+ else if( a.low() == b.low() )
+ classification = 15;
+ else
+ {
+ if( b.high() < a.low() )
+ classification = 16;
+ else if( b.high() == a.low() )
+ classification = 17;
+ else
+ classification = 18;
+ }
+ }
+ else if( !a.is_low_fixed() && a.is_high_fixed() && b.is_low_fixed() && b.is_high_fixed() )
+ {
+ // classification 19..23
+
+ if( a.high() > b.high() )
+ classification = 19;
+ else if( a.high() == b.high() )
+ classification = 20;
+ else
+ {
+ if( a.high() < b.low() )
+ classification = 21;
+ else if( a.high() == b.low() )
+ classification = 22;
+ else
+ classification = 23;
+ }
+ }
+ else if( a.is_low_fixed() && a.is_high_fixed() && b.is_low_fixed() && !b.is_high_fixed() )
+ {
+ // classification 24..28
+
+ if( b.low() < a.low() )
+ classification = 24;
+ else if( b.low() == a.low() )
+ classification = 25;
+ else
+ {
+ if( a.high() < b.low() )
+ classification = 26;
+ else if( a.high() == b.low() )
+ classification = 27;
+ else
+ classification = 28;
+ }
+ }
+ else if( a.is_low_fixed() && a.is_high_fixed() && !b.is_low_fixed() && b.is_high_fixed() )
+ {
+ // classification 29..33
+
+ if( b.high() > a.high() )
+ classification = 29;
+ else if( b.high() == a.high() )
+ classification = 30;
+ else
+ {
+ if( b.high() < a.low() )
+ classification = 31;
+ else if( b.high() == a.low() )
+ classification = 32;
+ else
+ classification = 33;
+ }
+ }
+ else if( !a.is_low_fixed() && a.is_high_fixed() && b.is_low_fixed() && !b.is_high_fixed() )
+ {
+ // classification 34..36
+
+ if( a.high() < b.low() )
+ classification = 34;
+ else if( a.high() == b.low() )
+ classification = 35;
+ else
+ classification = 36;
+ }
+ else if( a.is_low_fixed() && !a.is_high_fixed() && !b.is_low_fixed() && b.is_high_fixed() )
+ {
+ // classification 37..39
+
+ if( b.high() < a.low() )
+ classification = 37;
+ else if( b.high() == a.low() )
+ classification = 38;
+ else
+ classification = 39;
+ }
+ else if( !a.is_low_fixed() && a.is_high_fixed() && !b.is_low_fixed() && b.is_high_fixed() )
+ {
+ // classification 40..42
+
+ if( a.high() < b.high() )
+ classification = 40;
+ else if( a.high() == b.high() )
+ classification = 41;
+ else
+ classification = 42;
+ }
+ else if( a.is_low_fixed() && !a.is_high_fixed() && b.is_low_fixed() && !b.is_high_fixed() )
+ {
+ // classification 43..45
+
+ if( a.low() < b.low() )
+ classification = 43;
+ else if( a.low() == b.low() )
+ classification = 44;
+ else
+ classification = 45;
+ }
+ else if( !a.is_low_fixed() && !a.is_high_fixed() && b.is_low_fixed() && b.is_high_fixed() )
+ classification = 46;
+ else if( a.is_low_fixed() && a.is_high_fixed() && !b.is_low_fixed() && !b.is_high_fixed() )
+ classification = 47;
+ else if( !a.is_low_fixed() && !a.is_high_fixed() && !b.is_low_fixed() && b.is_high_fixed() )
+ classification = 48;
+ else if( !a.is_low_fixed() && !a.is_high_fixed() && b.is_low_fixed() && !b.is_high_fixed() )
+ classification = 49;
+ else if( !a.is_low_fixed() && a.is_high_fixed() && !b.is_low_fixed() && !b.is_high_fixed() )
+ classification = 50;
+ else if( a.is_low_fixed() && !a.is_high_fixed() && !b.is_low_fixed() && !b.is_high_fixed() )
+ classification = 51;
+ else // !a.is_low_fixed() && !a.is_high_fixed() && !b.is_low_fixed() && !b.is_high_fixed()
+ classification = 52;
+
+ return classification;
+}
+
+
+
+char*
+r_Sinterval::get_string_representation() const
+{
+ unsigned int bufferSize = 128; // should be enough
+
+ // allocate buffer and initialize string stream
+ char* buffer = new char[bufferSize];
+ std::ostrstream domainStream( buffer, bufferSize );
+
+ // write into string stream
+ domainStream << (*this) << ends;
+
+ // allocate memory taking the final string
+ char* returnString = strdup(buffer);
+
+ // delete buffer
+ delete[] buffer;
+
+ return returnString;
+}
+
+
+
+/*************************************************************
+ * Method name...: operator<<( std::ostream& s, r_Sinterval& d )
+ ************************************************************/
+std::ostream& operator<<( std::ostream& s, const r_Sinterval& d )
+{
+ d.print_status( s );
+ return s;
+}
+
diff --git a/raslib/sinterval.hh b/raslib/sinterval.hh
new file mode 100644
index 0000000..f3edfab
--- /dev/null
+++ b/raslib/sinterval.hh
@@ -0,0 +1,451 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: sinterval.hh
+ *
+ * MODULE: raslib
+ * CLASS: r_Sinterval
+ *
+ * COMMENTS:
+ *
+*/
+
+#ifndef _D_SINTERVAL_
+#define _D_SINTERVAL_
+
+#ifdef __VISUALC__
+// Disable warning about exception specification.
+#pragma warning( disable : 4290 )
+#endif
+
+class r_Error;
+class r_Eno_interval;
+
+#include <iostream>
+
+#include "raslib/point.hh"
+
+//@ManMemo: Module: {\bf raslib}
+
+/*@Doc:
+
+ The class represents an interval with lower and upper bound.
+ Operations on the interval are defined according to the
+ ODMG-93 standard.
+ The operations union, difference, and intersection are
+ defined according to the following table:
+
+ | ... fixed bound \\
+ * ... open bound
+
+
+ \begin{verbatim}
+
+ class orientation union difference intersection
+ -----------------------------------------------------------
+ 1 |-a-| |-b-| error a error
+
+ 2 |-a-| [a1,b2] [a1,b1] [b1,a2]
+ |-b-|
+
+ 3 |--a--| a error b
+ |-b-|
+
+ 4 |-b-| [b1,a2] [b2,a2] [a1,b2]
+ |-a-|
+
+ 5 |--b--| b error a
+ |-a-|
+
+ 6 |-b-| |-a-| error a error
+
+ 7 |-a-|-b-| [a1,b2] a [a2,a2]
+
+ 8 |-b-|-a-| [b1,a2] a [b2,b2]
+
+ 9 |--a--| a [a1,b1] b
+ |-b-|
+
+ 10 |--a--| a [b2,a2] b
+ |-b-|
+
+ 11 |-a-| a error a
+ |-b-|
+
+ 12 |--b--| b error a
+ |-a-|
+
+ 13 |--b--| b error a
+ |-a-|
+
+ -----------------------------------------------------
+
+ 14 |--a--* a error b
+ |-b-|
+
+ 15 |--a--* a [b2,a2] b
+ |-b-|
+
+ 16 |-b-| |-a-* error a error
+
+ 17 |-b-|-a-* [b1,a2] a [b2,b2]
+
+ 18 |--a--* [b1,a2] [b2,a2] [a1,b2]
+ |-b-|
+
+ -----------------------------------------------------
+
+ 19 *--a--| a error b
+ |-b-|
+
+ 20 *--a--| a [a1,b1] b
+ |-b-|
+
+ 21 *-a-| |-b-| error a error
+
+ 22 *-a-|-b-| [a1,b2] a [a2,a2]
+
+ 23 *--a--| [a1,b2] [a1,b1] [b1,a2]
+ |-b-|
+
+ -----------------------------------------------------
+
+ 24 |--b--* b error a
+ |-a-|
+
+ 25 |--b--* b error a
+ |-a-|
+
+ 26 |-a-| |-b-* error a error
+
+ 27 |-a-|-b-* [a1,b2] a [a2,a2]
+
+ 28 |--b--* [a1,b2] [a1,b1] [b1,a2]
+ |-a-|
+
+ -----------------------------------------------------
+
+ 29 *--b--| b error a
+ |-a-|
+
+ 30 *--b--| b error a
+ |-a-|
+
+ 31 *-b-| |-a-| error a error
+
+ 32 *-b-|-a-| [b1,a2] a [b2,b2]
+
+ 33 *--b--| [b1,a2] [b2,a2] [a1,b2]
+ |-a-|
+
+ -----------------------------------------------------
+
+ 34 *-a-| |-b-* error a error
+
+ 35 *-a-|-b-* [a1,b2] a [a2,a2]
+
+ 36 *-a-| [a1,b2] [a1,b1] [b1,a2]
+ |-b-*
+
+ -----------------------------------------------------
+
+ 37 *-b-| |-a-* error a error
+
+ 38 *-b-|-a-* [b1,a2] a [b2,b2]
+
+ 39 *-b-| [b1,a2] [a1,b1] [a1,b2]
+ |-a-*
+
+ -----------------------------------------------------
+
+ 40 *-a-| b error a
+ *-b-|
+
+ 41 *-a-| a error a
+ *-b-|
+
+ 42 *-b-| a [b2,a2] b
+ *-a-|
+
+ -----------------------------------------------------
+
+ 43 |-a-* a [a1,b1] b
+ |-b-*
+
+ 44 |-a-* a error a
+ |-b-*
+
+ 45 |-b-* b error a
+ |-a-*
+
+ -----------------------------------------------------
+ 46 *-a-* |-b-| a error b
+
+ 47 *-b-* |-a-| b error a
+
+ 48 *-a-* a [b2,a2] b
+ *-b-|
+
+ 49 *-a-* a [a1,b1] b
+ |-b-*
+
+ 50 *-b-* b error a
+ *-a-|
+
+ 51 *-b-* b error a
+ |-a-*
+
+ 52 *-a-* a error a
+ *-b-*
+
+ \end{verbatim}
+
+ Attention: The difference operation has to be reconsidered in future
+ concerning a discrete interpretation of the intervals.
+
+ The closure operation defines an interval which is the smallest
+ interval containing the two operands.
+ The method {\tt intersects_with()} returns 0 in the error cases of the
+ intersection operation and 1 otherwise.
+
+*/
+
+class r_Sinterval
+{
+ public:
+ /// default constructor creates an interval with open bounds
+ r_Sinterval();
+
+ /// constructor taking string representation (e.g. *:200 )
+ r_Sinterval( char* ) throw(r_Eno_interval);
+
+ /// constructor for an interval with fixed bounds
+ r_Sinterval( r_Range low, r_Range high ) throw( r_Eno_interval );
+
+ //@Man: Constructors for intervals with at least one open bound.
+ //@{
+ ///
+ r_Sinterval( char, r_Range high );
+ ///
+ r_Sinterval( r_Range low, char );
+ ///
+ r_Sinterval( char, char );
+ ///
+ //@}
+
+ /// equal operator
+ bool operator==( const r_Sinterval& ) const;
+
+ /**
+ Two intervals are equal if they have the same lower and upper bound.
+ */
+
+ /// non equal operator - negation of equal operator
+ bool operator!=( const r_Sinterval& ) const;
+
+ //@Man: Read/Write methods:
+ //@{
+ ///
+ inline r_Range low () const;
+ ///
+ inline r_Range high() const;
+ ///
+ inline bool is_low_fixed() const;
+ ///
+ inline bool is_high_fixed() const;
+
+ ///
+ void set_low ( r_Range low ) throw( r_Eno_interval );
+ ///
+ void set_high ( r_Range high ) throw( r_Eno_interval );
+ ///
+ inline void set_low ( char );
+ ///
+ inline void set_high( char );
+
+ /// get the size of one dimensional interval as range.
+ r_Range get_extent() const throw(r_Error);
+ /*@Doc:
+ Returns a range with high() - low() + 1 of this interval.
+ */
+
+ ///
+ void set_interval( r_Range low, r_Range high ) throw( r_Eno_interval );
+ ///
+ void set_interval( char, r_Range high );
+ ///
+ void set_interval( r_Range low, char );
+ ///
+ void set_interval( char, char );
+ ///
+ //@}
+
+ /// determines if the self interval intersects with the delivered one
+ bool intersects_with( const r_Sinterval& ) const;
+
+ //@Man: Methods/Operators for the union operation:
+ //@{
+ ///
+ r_Sinterval& union_of ( const r_Sinterval&, const r_Sinterval& )
+ throw( r_Eno_interval );
+ ///
+ r_Sinterval& union_with ( const r_Sinterval& )
+ throw( r_Eno_interval );
+ ///
+ r_Sinterval& operator+= ( const r_Sinterval& )
+ throw( r_Eno_interval );
+ ///
+ r_Sinterval create_union ( const r_Sinterval& ) const
+ throw( r_Eno_interval );
+ ///
+ r_Sinterval operator+ ( const r_Sinterval& ) const
+ throw( r_Eno_interval );
+ ///
+ //@}
+
+ //@Man: Methods/Operators for the difference operation:
+ //@{
+ ///
+ r_Sinterval& difference_of ( const r_Sinterval&, const r_Sinterval& )
+ throw( r_Eno_interval );
+ ///
+ r_Sinterval& difference_with ( const r_Sinterval& )
+ throw( r_Eno_interval );
+ ///
+ r_Sinterval& operator-= ( const r_Sinterval& )
+ throw( r_Eno_interval );
+ ///
+ r_Sinterval create_difference ( const r_Sinterval& ) const
+ throw( r_Eno_interval );
+ ///
+ r_Sinterval operator- ( const r_Sinterval& ) const
+ throw( r_Eno_interval );
+ ///
+ //@}
+
+ //@Man: Methods/Operators for the intersection operation:
+ //@{
+ ///
+ r_Sinterval& intersection_of ( const r_Sinterval&, const r_Sinterval& )
+ throw( r_Eno_interval );
+ ///
+ r_Sinterval& intersection_with ( const r_Sinterval& )
+ throw( r_Eno_interval );
+ ///
+ r_Sinterval& operator*= ( const r_Sinterval&)
+ throw( r_Eno_interval);
+ ///
+ r_Sinterval create_intersection ( const r_Sinterval& ) const
+ throw( r_Eno_interval );
+ ///
+ r_Sinterval operator* ( const r_Sinterval& ) const
+ throw( r_Eno_interval );
+ ///
+ //@}
+
+ //@Man: Methods/Operators for the closure operation:
+ //@{
+ ///
+ r_Sinterval& closure_of ( const r_Sinterval&, const r_Sinterval& )
+ throw( r_Eno_interval );
+ ///
+ r_Sinterval& closure_with ( const r_Sinterval& )
+ throw( r_Eno_interval );
+ ///
+ r_Sinterval create_closure ( const r_Sinterval& ) const
+ throw( r_Eno_interval );
+ ///
+ //@}
+
+ /// writes the state of the object to the specified stream
+ void print_status( std::ostream& s = std::cout ) const;
+
+ /// gives back the string representation
+ char* get_string_representation() const;
+ /**
+ The string representation delivered by this method is allocated using {\tt malloc()} and
+ has to be free unsing {\tt free()} in the end. It can be used to construct a {\tt r_Sinterval}
+ again with a special constructor provided. The string representation is build using
+ {\tt print_status()}.
+ */
+
+ //@Man: Methods for internal use only:
+ //@{
+ /// calculate the size of the storage space occupied
+ r_Bytes get_storage_size( ) const;
+ ///
+ //@}
+
+private:
+
+ //@Man: Calculation methods for the operations:
+ //@{
+ ///
+ r_Sinterval calc_union ( const r_Sinterval& a, const r_Sinterval& b ) const
+ throw( r_Eno_interval );
+ ///
+ r_Sinterval calc_difference ( const r_Sinterval& a, const r_Sinterval& b ) const
+ throw( r_Eno_interval );
+ ///
+ r_Sinterval calc_intersection( const r_Sinterval& a, const r_Sinterval& b ) const
+ throw( r_Eno_interval );
+ ///
+ r_Sinterval calc_closure ( const r_Sinterval& a, const r_Sinterval& b ) const
+ throw( r_Eno_interval );
+ ///
+ //@}
+
+ /// compute the class of the two operands
+ int classify( const r_Sinterval& a, const r_Sinterval& b ) const;
+
+ //@Man: Attributes storing the bounds:
+ //@{
+ ///
+ r_Range lower_bound;
+ ///
+ r_Range upper_bound;
+ ///
+ //@}
+
+ //@Man: Attributes specifying wheter the lower/upper bound is fixed or not:
+ //@{
+ ///
+ bool low_fixed;
+ ///
+ bool high_fixed;
+ ///
+ //@}
+};
+
+
+
+
+//@ManMemo: Module: {\bf raslib}
+/**
+ Output stream operator for objects of type {\tt const r_Sinterval}.
+*/
+extern std::ostream& operator<<( std::ostream& s, const r_Sinterval& d );
+
+#include "raslib/sinterval.icc"
+
+#endif
diff --git a/raslib/sinterval.icc b/raslib/sinterval.icc
new file mode 100644
index 0000000..5d3311e
--- /dev/null
+++ b/raslib/sinterval.icc
@@ -0,0 +1,76 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INLINE SOURCE: sinterval.icc
+ *
+ * MODULE: raslib
+ * CLASS: r_Sinterval
+ *
+ * COMMENTS:
+ *
+*/
+
+inline r_Range
+r_Sinterval::low() const
+{
+ return lower_bound;
+};
+
+
+inline r_Range
+r_Sinterval::high() const
+{
+ return upper_bound;
+};
+
+
+inline bool
+r_Sinterval::is_low_fixed() const
+{
+ return low_fixed;
+};
+
+
+inline bool
+r_Sinterval::is_high_fixed() const
+{
+ return high_fixed;
+};
+
+
+inline void
+r_Sinterval::set_low( char )
+{
+ lower_bound = 0;
+ low_fixed = false;
+};
+
+
+inline void
+r_Sinterval::set_high( char )
+{
+ upper_bound = 0;
+ high_fixed = false;
+};
+
+
diff --git a/raslib/sintervaltype.cc b/raslib/sintervaltype.cc
new file mode 100644
index 0000000..241d606
--- /dev/null
+++ b/raslib/sintervaltype.cc
@@ -0,0 +1,80 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+static const char rcsid[] = "@(#)raslib, r_Sinterval_Type: $Header: /home/rasdev/CVS-repository/rasdaman/raslib/sintervaltype.cc,v 1.6 2003/12/27 23:01:21 rasdev Exp $";
+
+#include "raslib/sintervaltype.hh"
+
+r_Sinterval_Type::r_Sinterval_Type()
+ : r_Type()
+{
+}
+
+r_Sinterval_Type::r_Sinterval_Type( const r_Sinterval_Type& oldObj )
+ : r_Type(oldObj)
+{
+}
+
+r_Type*
+r_Sinterval_Type::clone() const
+{
+ return new r_Sinterval_Type( *this );
+}
+
+r_Type::r_Type_Id
+r_Sinterval_Type::type_id() const
+{
+ return SINTERVALTYPE;
+}
+
+bool
+r_Sinterval_Type::isSintervalType() const
+ {
+ return true;
+ }
+
+void
+r_Sinterval_Type::convertToLittleEndian(char* cells, r_Bytes noCells) const
+{
+}
+
+void
+r_Sinterval_Type::convertToBigEndian(char* cells, r_Bytes noCells) const
+{
+}
+
+void
+r_Sinterval_Type::print_status( std::ostream& s ) const
+{
+ s << "interval";
+}
+
+r_Sinterval_Type::~r_Sinterval_Type()
+{
+}
+
+std::ostream &operator<<( std::ostream &str, const r_Sinterval_Type &type )
+{
+ type.print_status(str);
+ return str;
+}
diff --git a/raslib/sintervaltype.hh b/raslib/sintervaltype.hh
new file mode 100644
index 0000000..1a102cd
--- /dev/null
+++ b/raslib/sintervaltype.hh
@@ -0,0 +1,81 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: sintervaltype.hh
+ *
+ * MODULE: raslib
+ * CLASS: r_Sinterval_Type
+ *
+ * COMMENTS:
+ *
+*/
+
+#ifndef _D_SINTERVAL_TYPE_
+#define _D_SINTERVAL_TYPE_
+
+#include "raslib/type.hh"
+
+//@ManMemo: Module: {\bf raslib}
+
+/*@Doc:
+ This class represents the sinterval type in the ODMG conformant
+ representation of the RasDaMan type system.
+*/
+
+class r_Sinterval_Type : public r_Type
+{
+public:
+ /// default constructor
+ r_Sinterval_Type();
+
+ /// copy constructor
+ r_Sinterval_Type( const r_Sinterval_Type& oldObj );
+
+ /// clone operation
+ virtual r_Type* clone() const;
+
+ /// retrieve id of the type.
+ virtual r_Type::r_Type_Id type_id() const;
+
+ /// converts array of cells from NT byte order to Unix byte order.
+ virtual void convertToLittleEndian(char* cells, r_Area noCells) const;
+
+ /// converts array of cells from Unix byte order to NT byte order.
+ virtual void convertToBigEndian(char* cells, r_Area noCells) const;
+
+ /// writes state of object to specified stream
+ virtual void print_status( std::ostream& s = std::cout ) const;
+
+ virtual bool isSintervalType() const;
+
+ /// destructor
+ ~r_Sinterval_Type();
+};
+
+//@Doc: write the status of a sinterval type to a stream
+extern std::ostream &operator<<( std::ostream &str, const r_Sinterval_Type &type );
+
+#endif
+
+
+
diff --git a/raslib/storageman.cc b/raslib/storageman.cc
new file mode 100644
index 0000000..8527bde
--- /dev/null
+++ b/raslib/storageman.cc
@@ -0,0 +1,133 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: storageman.cc
+ *
+ * MODULE: raslib
+ *
+ * CLASSES: r_Storage_Man, r_Storage_Man_C, r_Storage_Man_CPP
+ *
+ * COMMENTS:
+ *
+ * Transparent handling of malloc/free vs. new/delete
+ *
+*/
+
+#include "mymalloc/mymalloc.h"
+
+#include "raslib/storageman.hh"
+
+
+// auxiliary static functions
+static void *alloc_c_style( size_t size )
+{
+ return mymalloc( size );
+}
+
+static void free_c_style( void *data )
+{
+ free(data);
+}
+
+static void *alloc_cpp_style( size_t size )
+{
+ return new char[size];
+}
+
+static void free_cpp_style( void *data )
+{
+ delete [] data;
+}
+
+
+
+r_Storage_Man::r_Storage_Man( void )
+{
+ myalloc = alloc_c_style;
+ myfree = free_c_style;
+}
+
+r_Storage_Man::r_Storage_Man( storage_man_alloc a, storage_man_free f )
+{
+ myalloc = a;
+ myfree = f;
+}
+
+r_Storage_Man::r_Storage_Man( const r_Storage_Man &src )
+{
+ myalloc = src.myalloc;
+ myfree = src.myfree;
+}
+
+r_Storage_Man::~r_Storage_Man( void )
+{
+}
+
+void r_Storage_Man::set_storage_functions( storage_man_alloc a, storage_man_free f )
+{
+ myalloc = a;
+ myfree = f;
+}
+
+r_Storage_Man &r_Storage_Man::operator=( const r_Storage_Man &src )
+{
+ myalloc = src.myalloc;
+ myfree = src.myfree;
+ return *this;
+}
+
+void *r_Storage_Man::storage_alloc( size_t size ) const throw(r_Error)
+{
+ void *result;
+
+ if ((result = myalloc(size)) == NULL)
+ {
+ r_Error err(r_Error::r_Error_General);
+ throw(err);
+ }
+ return result;
+}
+
+void r_Storage_Man::storage_free( void *data ) const
+{
+ myfree(data);
+}
+
+
+
+r_Storage_Man_C::r_Storage_Man_C( void ) : r_Storage_Man( alloc_c_style, free_c_style )
+{
+}
+
+r_Storage_Man_C::~r_Storage_Man_C( void )
+{
+}
+
+
+r_Storage_Man_CPP::r_Storage_Man_CPP( void ) : r_Storage_Man( alloc_cpp_style, free_cpp_style )
+{
+}
+
+r_Storage_Man_CPP::~r_Storage_Man_CPP( void )
+{
+}
diff --git a/raslib/storageman.hh b/raslib/storageman.hh
new file mode 100644
index 0000000..a985f8c
--- /dev/null
+++ b/raslib/storageman.hh
@@ -0,0 +1,116 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: storageman.hh
+ *
+ * MODULE: raslib
+ *
+ * CLASSES: r_Storage_Man, r_Storage_Man_C, r_Storage_Man_CPP
+ *
+ * COMMENTS:
+ *
+ * Transparent handling of malloc/free vs. new/delete
+ *
+*/
+
+#ifndef _R_STORAGE_MAN_
+#define _R_STORAGE_MAN_
+
+
+// for size_t
+#include <stdlib.h>
+
+#include "raslib/error.hh"
+
+
+
+//@ManMemo: Module {\bf raslib}
+
+/*@Doc:
+ r_Storage_Man provides an interface to a pair of heap management
+ functions for allocating and freeing blocks. I want to be able
+ to use constructs like sman1 = sman2, therefore I can't use
+ virtual functions to implement this.
+*/
+
+class r_Storage_Man
+{
+ public:
+
+ /// types of storage management functions
+ typedef void *(*storage_man_alloc)( size_t );
+ typedef void (*storage_man_free)( void *data );
+
+ /// default constructor, switches to c-style allocation
+ r_Storage_Man( void );
+ /// constructor setting the storage functions
+ r_Storage_Man( storage_man_alloc a, storage_man_free f );
+ /// copy constructor
+ r_Storage_Man( const r_Storage_Man &src );
+ /// destructor
+ ~r_Storage_Man( void );
+ /// setting the storage functions
+ void set_storage_functions( storage_man_alloc a, storage_man_free f );
+ /// assignment
+ r_Storage_Man &operator=( const r_Storage_Man &src );
+ /// allocation
+ void *storage_alloc( size_t size ) const throw(r_Error);
+ /// deallocation
+ void storage_free( void *data ) const;
+
+
+ protected:
+ /// the storage functions
+ storage_man_alloc myalloc;
+ storage_man_free myfree;
+};
+
+
+/*@Doc:
+ r_Storage_Man_C implements C-style allocation using malloc/free
+*/
+
+class r_Storage_Man_C : public r_Storage_Man
+{
+ public:
+ /// default constructor
+ r_Storage_Man_C( void );
+ /// default destructor
+ ~r_Storage_Man_C( void );
+};
+
+
+/*@Doc:
+ r_Storage_Man_CPP implements C++-style allocation using new/delete
+*/
+
+class r_Storage_Man_CPP : public r_Storage_Man
+{
+ public:
+ /// default constructor
+ r_Storage_Man_CPP( void );
+ /// destructor
+ ~r_Storage_Man_CPP( void );
+};
+
+#endif
diff --git a/raslib/structure.cc b/raslib/structure.cc
new file mode 100644
index 0000000..4c81015
--- /dev/null
+++ b/raslib/structure.cc
@@ -0,0 +1,282 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: structure.cc
+ *
+ * MODULE: raslib
+ * CLASS: r_Structure
+ *
+ * COMMENTS:
+ *
+*/
+
+#include "raslib/structure.hh"
+#include "raslib/primitive.hh"
+#include "raslib/structuretype.hh"
+#include "raslib/error.hh"
+#include "raslib/rminit.hh"
+#include "mymalloc/mymalloc.h"
+
+#ifdef __VISUALC__
+#include <strstrea.h>
+#else
+#include <strstream>
+#endif
+#include <string.h>
+#include <fstream>
+#include <stdlib.h>
+
+
+
+
+r_Structure::r_Structure( const char* newBuffer, const r_Structure_Type* newType )
+ : r_Scalar( newType ),
+ numElements(0),
+ elements(NULL),
+ valueBuffer(NULL)
+{
+ if( newType )
+ {
+
+ numElements = newType->count_elements();
+ elements = new r_Scalar*[numElements];
+
+ valueBuffer = (char*)mymalloc(newType->size());
+
+ if(newBuffer)
+ memcpy(valueBuffer, newBuffer, newType->size());
+ else
+ memset(valueBuffer, 0, newType->size());
+
+ r_Structure_Type::attribute_iterator iter( newType->defines_attribute_begin() );
+
+ for( int i=0; iter != newType->defines_attribute_end(); iter++, i++ )
+ {
+ if( (*iter).type_of().type_id() == r_Type::STRUCTURETYPE )
+ elements[i] = new r_Structure( valueBuffer + (*iter).offset(), (r_Structure_Type*)&((*iter).type_of()) );
+ else
+ elements[i] = new r_Primitive( valueBuffer + (*iter).offset(), (r_Primitive_Type*)&((*iter).type_of()) );
+ }
+ }
+}
+
+
+
+r_Structure::r_Structure( const r_Structure& obj )
+ : r_Scalar( obj ),
+ numElements(obj.numElements),
+ elements(NULL),
+ valueBuffer(NULL)
+{
+ if( numElements )
+ {
+ elements = new r_Scalar*[numElements];
+
+ for( unsigned int i=0; i < numElements; i++ )
+ elements[i] = obj.elements[i]->clone();
+ }
+
+ valueBuffer = (char*) mymalloc(valueType->size());
+
+ if(obj.valueBuffer)
+ memcpy(valueBuffer, obj.valueBuffer, valueType->size());
+ else
+ memset(valueBuffer, 0, valueType->size());
+}
+
+
+
+r_Structure::~r_Structure()
+{
+ if( numElements )
+ {
+ for( unsigned int i =0; i < numElements; i++ )
+ delete elements[i];
+
+ delete[] elements;
+ }
+
+ if(valueBuffer)
+ free(valueBuffer);
+}
+
+
+
+r_Scalar*
+r_Structure::clone() const
+{
+ return new r_Structure( *this );
+}
+
+
+
+const r_Structure&
+r_Structure::operator=( const r_Structure& obj )
+{
+ if( this != &obj )
+ {
+ // assign scalar
+ r_Scalar::operator=( obj );
+
+ if( numElements )
+ {
+ for( unsigned int i =0; i < numElements; i++ )
+ delete elements[i];
+
+ delete[] elements;
+ }
+
+ if( obj.numElements )
+ {
+ numElements = obj.numElements;
+ elements = new r_Scalar*[numElements];
+
+ for( unsigned int i =0; i < numElements; i++ )
+ elements[i] = obj.elements[i]->clone();
+ }
+
+ if(valueBuffer)
+ free(valueBuffer);
+
+ valueBuffer = (char*) mymalloc(valueType->size());
+
+ if(obj.valueBuffer)
+ memcpy(valueBuffer, obj.valueBuffer, valueType->size());
+ else
+ memset(valueBuffer, 0, valueType->size());
+
+ }
+
+ return *this;
+}
+
+
+
+unsigned int
+r_Structure::count_elements() const
+{
+ return numElements;
+}
+
+const char*
+r_Structure::get_buffer() const
+{
+ memset(valueBuffer, 0, valueType->size());
+
+ r_Structure_Type::attribute_iterator iter( ((r_Structure_Type*)valueType)->defines_attribute_begin() );
+
+ for( int i=0; iter != ((r_Structure_Type*)valueType)->defines_attribute_end(); iter++, i++ )
+ if( (*iter).type_of().type_id() == r_Type::STRUCTURETYPE )
+ memcpy( valueBuffer + (*iter).offset(), ((r_Structure*)elements[i])->get_buffer(), elements[i]->get_type()->size());
+ else
+ memcpy( valueBuffer + (*iter).offset(), ((r_Primitive*)elements[i])->get_buffer(), elements[i]->get_type()->size());
+
+ return valueBuffer;
+}
+
+
+bool
+r_Structure::isStructure() const
+{
+ return true;
+}
+
+
+
+const r_Scalar&
+r_Structure::operator[]( unsigned int index ) const throw( r_Error )
+{
+ if( !valueType )
+ {
+ RMInit::logOut << "r_Structure::operator[](" << index << ") const value type is NULL" << endl;
+ throw r_Error( r_Error::r_Error_TypeInvalid );
+ }
+
+ if( index > numElements )
+ {
+ RMInit::logOut << "r_Structure::operator[](" << index << ") const index is out of bounds (" << numElements - 1 << ")" << endl;
+ throw r_Eindex_violation( 0, numElements, index );
+ }
+
+ return *(elements[index]);
+}
+
+
+
+const r_Scalar&
+r_Structure::operator[]( const char* name ) const throw( r_Error )
+{
+ if( !valueType )
+ {
+ RMInit::logOut << "r_Structure::operator[](" << name << ") value type is NULL" << endl;
+ r_Error err( r_Error::r_Error_TypeInvalid );
+ throw( err );
+ }
+
+ r_Structure_Type* structType = (r_Structure_Type*)valueType;
+
+ r_Structure_Type::attribute_iterator iter( structType->defines_attribute_begin() );
+
+ int index = 0;
+ for( ; iter != structType->defines_attribute_end() && strcmp((*iter).name(), name); iter++, index++ );
+
+ if( iter == structType->defines_attribute_end() )
+ {
+ RMInit::logOut << "r_Structure::operator[](" << name << ") name is not valid" << endl;
+ r_Error err( r_Error::r_Error_NameInvalid );
+ throw( err );
+ }
+
+ return *(elements[index]);
+}
+
+
+void
+r_Structure::print_status( std::ostream& s ) const
+{
+ if( valueType )
+ {
+ s << "{ " << std::flush;
+
+ for( unsigned int i =0; i < numElements; i++ )
+ {
+ s << *(elements[i]) << std::flush;
+
+ if( i < numElements-1 )
+ s << ", " << std::flush;
+ }
+
+ s << " }" << std::flush;
+ }
+ else
+ s << "<nn>" << std::flush;
+}
+
+
+
+std::ostream& operator<<( std::ostream& s, const r_Structure& obj )
+{
+ obj.print_status( s );
+ return s;
+}
+
diff --git a/raslib/structure.hh b/raslib/structure.hh
new file mode 100644
index 0000000..a41cdbf
--- /dev/null
+++ b/raslib/structure.hh
@@ -0,0 +1,111 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: structure.hh
+ *
+ * MODULE: raslib
+ * CLASS: r_Structure
+ *
+ * COMMENTS:
+ *
+ * The class represents a structured value.
+ *
+*/
+
+#ifndef _D_STRUCTURE_
+#define _D_STRUCTURE_
+
+#include <iostream>
+
+class r_Error;
+
+#include "raslib/scalar.hh"
+
+class r_Structure_Type;
+
+//@ManMemo: Module: {\bf raslib}
+
+/*@Doc:
+
+ Class \Ref{r_Structure} represents a structured value.
+
+*/
+
+class r_Structure : public r_Scalar
+{
+ public:
+ /// constructs a structured type value
+ r_Structure( const char* newBuffer, const r_Structure_Type* newType );
+
+ /// copy constructor
+ r_Structure( const r_Structure& obj );
+
+ /// destructor
+ virtual ~r_Structure();
+
+ /// clone operator
+ virtual r_Scalar* clone() const;
+
+ /// operator for assigning a structure
+ virtual const r_Structure& operator= ( const r_Structure& );
+
+ /// debug output
+ virtual void print_status(std::ostream& s) const;
+
+ /// returns true to indicate that this is a structured value
+ virtual bool isStructure() const;
+
+ /// get number of elements
+ unsigned int count_elements() const;
+
+ /// get buffer
+ const char* get_buffer() const;
+
+ /// access an element by name
+ /// throws TypeInvalid and r_Eindex_violation
+ const r_Scalar& operator[]( const char* name ) const throw( r_Error );
+
+ /// access an element by number
+ /// throws TypeInvalid and NameInvalid
+ const r_Scalar& operator[]( unsigned int ) const throw( r_Error );
+
+ private:
+ /// number of elements
+ unsigned int numElements;
+
+ /// array of pointers to elements
+ r_Scalar** elements;
+
+ /// char representation
+ char* valueBuffer;
+};
+
+
+
+//@ManMemo: Module: {\bf raslib}
+/**
+ Output stream operator for objects of type {\tt const} \Ref{r_Structure}.
+*/
+extern std::ostream& operator<<( std::ostream& s, const r_Structure& oid );
+#endif
+
diff --git a/raslib/structuretype.cc b/raslib/structuretype.cc
new file mode 100644
index 0000000..ddfd9fb
--- /dev/null
+++ b/raslib/structuretype.cc
@@ -0,0 +1,276 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+static const char rcsid[] = "@(#)raslib, r_Structure_Type: $Header: /home/rasdev/CVS-repository/rasdaman/raslib/structuretype.cc,v 1.23 2003/12/27 23:01:21 rasdev Exp $";
+
+#include <malloc.h>
+#include <string.h>
+
+#include "raslib/structuretype.hh"
+#include "raslib/attribute.hh"
+#include "raslib/rminit.hh"
+#include "raslib/error.hh"
+
+r_Structure_Type::r_Structure_Type()
+ : r_Base_Type(),
+ myAttributes(NULL),
+ numAttrs(0)
+{
+}
+
+r_Structure_Type::r_Structure_Type( char* newTypeName,
+ unsigned int newNumAttrs,
+ r_Attribute* newAttrs, int offset )
+ : r_Base_Type(newTypeName, 0),
+ numAttrs(newNumAttrs),
+ myAttributes(new r_Attribute[newNumAttrs])
+{
+ for(unsigned int i = 0; i < numAttrs; i++)
+ {
+ myAttributes[i] = newAttrs[i];
+ myAttributes[i].set_offset( typeSize );
+ myAttributes[i].set_global_offset( typeSize + offset );
+ typeSize += myAttributes[i].type_of().size();
+ }
+}
+
+r_Structure_Type::r_Structure_Type( const r_Structure_Type& oldObj )
+ : r_Base_Type(oldObj), myAttributes(NULL), numAttrs(oldObj.numAttrs)
+{
+
+ if( oldObj.myAttributes )
+ {
+ myAttributes = new r_Attribute[numAttrs];
+ for( unsigned int i = 0; i < numAttrs; i++)
+ myAttributes[i] = oldObj.myAttributes[i];
+ }
+}
+
+const r_Structure_Type&
+r_Structure_Type::operator=( const r_Structure_Type& oldObj )
+{
+ // Gracefully handle self assignment
+ if (this == &oldObj) return *this;
+
+ r_Base_Type::operator=( oldObj );
+ numAttrs = oldObj.numAttrs;
+ if( myAttributes )
+ {
+ delete[] myAttributes;
+ myAttributes=NULL;
+ }
+
+ if( oldObj.myAttributes )
+ {
+ myAttributes = new r_Attribute[numAttrs];
+ for(unsigned int i = 0; i < numAttrs; i++)
+ myAttributes[i] = oldObj.myAttributes[i];
+ }
+
+ return *this;
+}
+
+r_Structure_Type::~r_Structure_Type()
+{
+ if( myAttributes )
+ delete[] myAttributes;
+}
+
+r_Type*
+r_Structure_Type::clone() const
+{
+ return new r_Structure_Type( *this );
+}
+
+
+r_Type::r_Type_Id
+r_Structure_Type::type_id() const
+{
+ return STRUCTURETYPE;
+}
+
+bool
+r_Structure_Type::isStructType() const
+{
+ return true;
+}
+
+bool
+r_Structure_Type::compatibleWith(const r_Structure_Type* myType) const
+{
+ if(myType == NULL)
+ return false;
+ if( count_elements() != myType->count_elements())
+ return false;
+
+ r_Structure_Type::attribute_iterator myIter(defines_attribute_begin());
+ r_Structure_Type::attribute_iterator myTypeIter(myType->defines_attribute_begin());
+ r_Structure_Type::attribute_iterator myIterEnd(defines_attribute_end());
+ // FIXME not used in curr implementation
+ // r_Structure_Type::attribute_iterator myTypeIterEnd(myType->defines_attribute_end());
+ while(myIter != myIterEnd) {
+ if((*myIter).type_of().type_id() != (*myTypeIter).type_of().type_id())
+ return false;
+ myIter++;
+ myTypeIter++;
+ }
+
+ return true;
+}
+
+r_Structure_Type::attribute_iterator
+r_Structure_Type::defines_attribute_begin() const
+{
+ return attribute_iterator(myAttributes + numAttrs, myAttributes);
+}
+
+r_Structure_Type::attribute_iterator
+r_Structure_Type::defines_attribute_end() const
+{
+ return attribute_iterator(myAttributes + numAttrs - 1, myAttributes,
+ myAttributes + numAttrs);
+}
+
+r_Attribute
+r_Structure_Type::resolve_attribute(const char* name) const throw( r_Error )
+{
+ r_Structure_Type::attribute_iterator iter(defines_attribute_begin());
+
+ while( iter != defines_attribute_end() && strcmp((*iter).name(), name) != 0 )
+ iter++;
+
+ if( iter == defines_attribute_end() )
+ {
+ RMInit::logOut << "r_Structure_Type::resolve_attribute(" << name << ") not a valid atribute name" << endl;
+ r_Error err(r_Error::r_Error_NameInvalid);
+ throw err;
+ }
+
+ return (*iter);
+}
+
+r_Attribute
+r_Structure_Type::resolve_attribute(unsigned int number) const throw( r_Error )
+{
+ r_Structure_Type::attribute_iterator iter(defines_attribute_begin());
+ unsigned int i = 0;
+ while( iter != defines_attribute_end() && i < number )
+ {
+ i++;
+ iter++;
+ }
+
+ if( iter == defines_attribute_end() || i < number )
+ {
+ RMInit::logOut << "r_Structure_Type::resolve_attribute(" << number << ") index out of bounds (" << i << ")" << endl;
+ throw r_Eindex_violation( 0, numAttrs-1, number );
+ }
+
+ return (*iter);
+}
+
+r_Attribute
+r_Structure_Type::operator[]( unsigned int number ) const throw( r_Error )
+{
+ return resolve_attribute( number );
+}
+
+unsigned int
+r_Structure_Type::count_elements() const
+{
+ return numAttrs;
+}
+
+void
+r_Structure_Type::convertToLittleEndian(char* cells, r_Area noCells) const
+{
+ r_Area i = 0;
+ unsigned int j = 0;
+
+ for(i=0; i<noCells; i++) {
+ for(j=0; j<numAttrs; j++) {
+ myAttributes[j].type_of().convertToLittleEndian(
+ &cells[i*typeSize + myAttributes[j].offset()], 1);
+ }
+ }
+}
+
+void
+r_Structure_Type::convertToBigEndian(char* cells, r_Area noCells) const
+{
+ r_Area i = 0;
+ unsigned int j = 0;
+
+ for(i=0; i<noCells; i++) {
+ for(j=0; j<numAttrs; j++) {
+ myAttributes[j].type_of().convertToBigEndian(
+ &cells[i*typeSize + myAttributes[j].offset()], 1);
+ }
+ }
+}
+
+void
+r_Structure_Type::print_status( std::ostream& s ) const
+{
+ r_Structure_Type::attribute_iterator iter(defines_attribute_begin());
+
+ s << "struct{ ";
+
+ while(iter != defines_attribute_end())
+ {
+ (*iter).print_status( s );
+
+ iter++;
+
+ if( iter != defines_attribute_end() )
+ s << ", ";
+ }
+
+ s << " }";
+}
+
+void
+r_Structure_Type::print_value( const char* storage, std::ostream& s ) const
+{
+ s << "{ ";
+
+ r_Structure_Type::attribute_iterator iter( defines_attribute_begin() );
+
+ while( iter != defines_attribute_end() )
+ {
+ (*iter).type_of().print_value( storage + (*iter).offset(), s );
+
+ iter++;
+
+ if( iter != defines_attribute_end() )
+ s << ", ";
+ }
+ s << "} ";
+}
+
+
+std::ostream &operator<<( std::ostream &str, const r_Structure_Type &type )
+{
+ type.print_status(str);
+ return str;
+} \ No newline at end of file
diff --git a/raslib/structuretype.hh b/raslib/structuretype.hh
new file mode 100644
index 0000000..fae53b4
--- /dev/null
+++ b/raslib/structuretype.hh
@@ -0,0 +1,118 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: structuretype.hh
+ *
+ * MODULE: raslib
+ * CLASS: r_Structure_Type
+ *
+ * COMMENTS:
+ *
+*/
+
+#ifndef _D_STRUCTURE_TYPE_
+#define _D_STRUCTURE_TYPE_
+
+#if (defined(__VISUALC__) && !defined(__EXECUTABLE__))
+ #define __EXECUTABLE__
+ #include "raslib/itertype.hh"
+ #undef __EXECUTABLE__
+#else
+ #include "raslib/itertype.hh"
+#endif
+
+class r_Error;
+#include "raslib/basetype.hh"
+#include "raslib/attribute.hh"
+
+
+//@ManMemo: Module: {\bf raslib}
+
+/*@Doc:
+ This class represents all user defined structured types in the
+ ODMG conformant representation of the RasDaMan type system.
+*/
+
+class r_Structure_Type : public r_Base_Type
+{
+public:
+ /// typedef for iterator iterating through all attributes;
+ typedef r_IterType<r_Attribute> attribute_iterator;
+ /// default constructor.
+ r_Structure_Type();
+ /// constructor getting name of type and type id.
+ r_Structure_Type( char* newTypeName, unsigned int newNumAttrs, r_Attribute* newAttrs, int offset = 0 );
+ /// copy constructor
+ r_Structure_Type( const r_Structure_Type& oldObj );
+ /// assignment operator.
+ const r_Structure_Type& operator=( const r_Structure_Type& oldObj );
+ /// destructor.
+ virtual ~r_Structure_Type();
+
+ /// clone operation
+ virtual r_Type* clone() const;
+
+ /// retrieve id of the type.
+ virtual r_Type::r_Type_Id type_id() const;
+
+ /// check, if type is primitive or structured.
+ virtual bool isStructType() const;
+
+ /// check, if this type is compatible with myType (e.g. check the structure ignoring then names of atributtes)
+ virtual bool compatibleWith(const r_Structure_Type* myType) const;
+
+ /// returns attribute iterator at begin position.
+ attribute_iterator defines_attribute_begin() const;
+ /// returns attribute iterator at end position (behind last attribute).
+ attribute_iterator defines_attribute_end() const;
+ /// return attribute specified by name.
+ r_Attribute resolve_attribute(const char* name) const throw( r_Error );
+ /// return attribute specified by number starting with zero.
+ r_Attribute resolve_attribute(unsigned int number) const throw( r_Error );
+ /// subscript operator to access attributes by index
+ r_Attribute operator[]( unsigned int number ) const throw( r_Error );
+
+ /// get number of attributes
+ unsigned int count_elements() const;
+
+ /// converts array of cells from NT byte order to Unix byte order.
+ virtual void convertToLittleEndian(char* cells, r_Area noCells) const;
+
+ /// converts array of cells from Unix byte order to NT byte order.
+ virtual void convertToBigEndian(char* cells, r_Area noCells) const;
+
+ /// writes state of object to specified stream
+ virtual void print_status( std::ostream& s = std::cout ) const;
+
+ /// prints values of a structured type
+ virtual void print_value( const char* storage, std::ostream& s = std::cout ) const;
+
+protected:
+ unsigned int numAttrs;
+ r_Attribute* myAttributes;
+};
+
+//@Doc: write the status of a structure type to a stream
+extern std::ostream &operator<<( std::ostream &str, const r_Structure_Type &type );
+
+#endif
diff --git a/raslib/template_inst.hh b/raslib/template_inst.hh
new file mode 100644
index 0000000..63874c6
--- /dev/null
+++ b/raslib/template_inst.hh
@@ -0,0 +1,78 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+// This version was created based on rview. Let's see if the other programs compile
+// also.
+
+#ifndef _TEMPLATE_INST_RASLIB_
+#define _TEMPLATE_INST_RASLIB_
+
+#include <vector>
+
+#include <raslib/attribute.hh>
+#include <raslib/itertype.hh>
+#include <raslib/dlist.hh>
+#include <raslib/minterval.hh>
+
+#include <rasodmg/tiling.hh>
+#include <rasodmg/stattiling.hh>
+#include <rasodmg/iterator.hh>
+#include <rasodmg/ref.hh>
+#include <rasodmg/object.hh>
+#include <rasodmg/set.hh>
+#include <rasodmg/collection.hh>
+#include <rasodmg/gmarray.hh>
+#include <rasodmg/transaction.hh>
+#include <rasodmg/marray.hh>
+#include <rasodmg/dirdecompose.hh>
+
+template class r_Ref<r_Object>;
+template class r_Ref<r_Minterval>;
+template class r_Collection<r_Transaction::GenRefElement *>;
+template class r_Set<r_Transaction::GenRefElement *>;
+template class r_Iterator<r_GMarray *>;
+template class r_Iterator<r_Ref<r_GMarray > >;
+template class r_Collection<r_Ref<r_GMarray> >;
+template class r_Collection<r_GMarray *>;
+template class r_Set<r_GMarray *>;
+template class r_Iterator<r_Ref<r_Object> >;
+template class r_IterType<r_Attribute>;
+template class r_Collection<r_Ref<r_Object> >;
+template class r_Set<r_Ref<r_Object> >;
+template class r_Iterator<r_Ref_Any>;
+template class r_Ref<r_GMarray>;
+template class r_Collection<r_Ref_Any>;
+template class std::vector<r_Minterval>;
+template class r_Iterator<r_Transaction::GenRefElement *>;
+template class r_Set<r_Ref<r_GMarray> >;
+template class r_Ref<r_Set<r_Ref<r_GMarray> > >;
+template class r_Set<r_Ref_Any>;
+template class r_Marray<r_ULong>;
+template class r_Marray<r_Char>;
+
+template std::ostream& operator << (std::ostream& os, const std::vector<r_Minterval>& list);
+template std::ostream& operator << (std::ostream& os, const std::vector<r_Dir_Decompose>& list);
+template std::ostream& operator << (std::ostream& os, const std::vector<r_Access>& list);
+template std::ostream& operator << (std::ostream& os, const std::vector<double>& list);
+
+#endif
diff --git a/raslib/test/Makefile b/raslib/test/Makefile
new file mode 100644
index 0000000..379b344
--- /dev/null
+++ b/raslib/test/Makefile
@@ -0,0 +1,192 @@
+# -*-Makefile-*-
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>. # Top Level makefile. This points to the various modules that have to be build
+# and/or deployed
+#
+# MAKEFILE FOR:
+# test programs of module raslib
+#
+#
+# COMMENTS:
+#
+##################################################################
+#
+# This is just an example Makefile for a test program.
+# The dependency of the test program on the lib of the
+# corresponding module is in the Makefile of the module.
+#
+
+######################### Definitions ############################
+
+# standard include with general options
+include $(RMANBASE)/Makefile.inc
+
+# uses our own mem management routine:
+MYMALLOC_H := ../../mymalloc/mymalloc.hh
+MYMALLOC_O := ../../mymalloc/mymalloc_cln.o
+
+# use client specific flags
+CXXFLAGS := $(CLIENTCXXFLAGS) $(I_SYM)$(MYMALLOC_H)
+LDFLAGS := $(CLIENTLDFLAGS) $(L_SYM)$(MYMALLOC_O)
+
+# raslib has its own template directory because of the name clashes with O2
+
+ifneq ($(OSTYPE),linux-gnu)
+ CXXFLAGS := -ptr$(RMANBASE)/rasodmg/ptrepository $(CXXFLAGS)
+ LDFLAGS := -ptr$(RMANBASE)/rasodmg/ptrepository $(LDFLAGS)
+endif
+
+# all test programs
+ALLTESTS = test_error
+
+# test_sinterval test_point test_minterval test_rmdebug \
+# test_metaobject test_oid test_timer test_miter test_miterf \
+# test_params
+
+########################### Targets ##############################
+
+# test target for class r_Minterval
+.PHONY : minterval
+minterval: test_module test_minterval
+
+# test target for class r_Miter
+.PHONY : miterd
+miterd: test_module test_miterd
+
+# test target for class r_Miter
+.PHONY : miter
+miter: test_module test_miter
+
+# test target for class r_MiterFloat
+.PHONY : miterf
+miterf: test_module test_miterf
+
+# test target for class r_Sinterval
+.PHONY : sinterval
+sinterval: test_module test_sinterval
+
+# test target for class r_Point
+.PHONY : point
+point: test_module test_point
+
+# test target for class r_Error and its subclasses
+.PHONY : error
+error: test_module test_error
+
+# test target for class RMDebug
+.PHONY : rmdebug
+rmdebug: test_module test_rmdebug
+
+# test target for class r_Meta_Object and its subclasses
+.PHONY : metaobject
+metaobject: test_module test_metaobject
+
+# test target for class r_OId
+.PHONY : oid
+oid: test_module test_oid
+
+# test target for RMTimer
+.PHONY : timer
+timer: test_module test_timer
+
+# test target for lincomstreams
+.PHONY : params
+params: test_module test_params
+
+.PHONY : test_module
+test_module:
+ cd $(RMANBASE)/raslib; $(MAKE)
+
+test_minterval: test_minterval.o $(RASLIB)
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^
+
+test_miterd: test_miterd.o $(RASLIB)
+ $(PURIFY) $(CXX) $(LDFLAGS) -lm -o $@ $^
+
+test_miter: test_miter.o $(RASLIB)
+ $(PURIFY) $(CXX) $(LDFLAGS) -lm -o $@ $^
+
+test_miterf: test_miterf.o $(RASLIB)
+ $(PURIFY) $(CXX) $(LDFLAGS) -lm -o $@ $^
+
+test_sinterval: test_sinterval.o $(RASLIB)
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^
+
+test_point: test_point.o $(RASLIB)
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^
+
+test_error: test_error.o $(RASLIB)
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^
+
+test_rmdebug: test_rmdebug.o $(RASLIB)
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^
+
+test_metaobject: test_metaobject.o $(RASLIB)
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^
+
+test_oid: test_oid.o $(RASLIB)
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^
+
+test_timer: test_timer.o $(RASLIB)
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^
+
+test_params: test_params.o $(RASLIB) $(CLIENTCOMM)
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^
+
+.PHONY : clean
+clean:
+ -rm $(ALLTESTS)
+ -rm *.o
+
+# deletes all non modified, but checked out files
+.PHONY : rcsclean
+rcsclean:
+ -rcsclean
+
+# perform all tests as part of general systemtest
+.PHONY: systemtest
+systemtest: $(ALLTESTS)
+ cp $(RMANBASE)/bin/errtxts . # needed by test_error
+ for PROG in $^; \
+ do \
+ $$PROG; \
+ done
+
+######################## Dependencies ############################
+
+test_minterval.o: test_minterval.cc $(RMANBASE)/raslib/minterval.hh
+
+test_miter.o: test_miter.cc $(RMANBASE)/raslib/miter.hh
+
+test_miterf.o: test_miterf.cc $(RMANBASE)/raslib/miterf.hh
+
+test_sinterval.o: test_sinterval.cc $(RMANBASE)/raslib/sinterval.hh
+
+test_point.o: test_point.cc $(RMANBASE)/raslib/point.hh
+
+test_error.o: test_error.cc $(RMANBASE)/raslib/error.hh
+
+test_oid.o: test_oid.cc $(RMANBASE)/raslib/oid.hh
+
+test_timer.o: test_timer.cc $(RMANBASE)/raslib/
+
+test_params.o: test_params.cc $(RMANBASE)/raslib/parseparams.hh
diff --git a/raslib/test/errtxts b/raslib/test/errtxts
new file mode 100644
index 0000000..0004f30
--- /dev/null
+++ b/raslib/test/errtxts
@@ -0,0 +1,244 @@
+190
+# Increment the number above every time you add a new exception
+#
+#
+# This file contains types and textual descriptions of RasDaMan errors.
+# The ascending error numbers are used as index to the descriptions. Each
+# line follows the following syntax:
+#
+# number^type^description.
+#
+# The character '^' is used as delimiter and with '#' a comment line is
+# started. Empty lines are not allowed.
+#
+#
+#
+#
+66^E^Exception: Memory allocation failed.
+100^E^Exception: Internal error: DL parse error.
+200^E^Exception: The result is no point.
+201^E^Exception: The result is no interval.
+202^E^Exception: Index violation ( index range [$low,$high], index $index ).
+203^E^Exception: Dimension mismatch between $dim1 and $dim2.
+204^E^Exception: Stream initialization overflow.
+205^E^Exception: Result is no cell.
+206^E^Serialisable exception r_Ebase_dbms: error in base DBMS.
+207^E^Internal client exception in class $class, method $method: $code.
+208^E^Exception: Access type $aType does not fit base type $bType.
+209^E^Exception: RasType $type is unknown.
+210^E^Exception: Base type $type is not supported yet.
+211^E^Exception: Database is not open.
+212^E^Exception: RPC layer connection to RasDaMan failed.
+213^E^Exception: Wrong URL format (should be http://address:port)
+214^E^Exception: Illegal java long value $val for server base type ULong.
+215^E^Exception: Illegal java integer value $val for server base type UShort.
+216^E^Exception: System collection is not writable.
+217^E^Exception: System collection has no OID.
+218^E^Exception: Conversion format is not supported.
+219^E^Exception: The specified tile size is smaller than the length of the base type of the mdd object.
+220^E^Exception: The tiling strategy in the storage layout is not compatible with the marray.
+221^E^Exception: The domain passed as an argument was not initialised correctly (dimension is 0).
+222^E^Exception: The type name or type structure does not represent a marray type.
+223^E^Exception: The rc index requires a marray type that has a specified domain (with fixed borders in all dimensions).
+224^E^Exception: The tile configuration is incompatible to the marray domain.
+229^E^Exception: The parameterized query has invalid parameter format.
+230^E^Exception: The r_Object was already assigned a type.
+231^E^Exception: The Marray has no base type.
+232^E^Exception: The interval has at least one open bound.
+233^E^Exception: The intervals don't have the same dimension.
+234^E^Exception: The string passed to the tiling object was not correct.
+235^E^Exception: Connection to server already closed.
+236^E^Exception: Error in compression engine
+237^E^Exception: Client communication failure
+#
+300^E^Parsing error $errorNo in line $lineNo, column $columnNo: Unexpected name $token.
+301^E^Parsing error $errorNo in line $lineNo, column $columnNo, token $token: All cell values of an MDD must be of the same type.
+302^E^Parsing error $errorNo in line $lineNo, column $columnNo, token $token: Number of cells specified does not match the number of cells of the given spatial domain.
+303^E^Parsing error $errorNo in line $lineNo, column $columnNo, token $token: OId is not valid.
+308^E^Parsing error: Unexpected end of query.
+309^E^Parsing error: Unknown error.
+310^E^Lexical analysing error $errorNo in line $lineNo, column $columnNo: Unexpected characters $token.
+311^E^Parsing error $errorNo in line $lineNo, column $columnNo, token $token: Complex constructor must have both arguments of the same type (i.e. float or double).
+312^E^Parsing error $errorNo in line $lineNo, column $columnNo, token $token: Variable already defined.
+313^E^Parsing error $errorNo in line $lineNo, column $columnNo, token $token: Only constant interval bounds allowed.
+#
+330^E^Preprocessing error $errorNo in line $lineNo, column $columnNo: Unexpected name $token:
+331^E^Preprocessing error $errorNo in line $lineNo, column $columnNo, token $token: attempt to redefine function.
+332^E^Preprocessing error $errorNo in line $lineNo, column $columnNo, token $token: number of actual arguments for the called function differs from the number of formal arguments.
+333^E^Preprocessing error $errorNo in line $lineNo, column $columnNo, token $token: the called function name is ambiguous, try the full qualified name.
+#
+349^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operand out of range.
+350^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: General.
+351^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Spatial domains of the binary induce operands are incompatible.
+352^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operand types are incompatible.
+353^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operand of quantifier must be multidimensional.
+354^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operand of quantifier must be of type r_Marray<d_Boolean>.
+355^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Collection name is unknown.
+356^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Specified domain does not intersect with spatial domain of MDD.
+357^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Variable is unknown.
+358^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Projection operand is not of type r_Marray<T>.
+359^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Result of the where clause must be of type boolean.
+360^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Type of operand is not supported.
+361^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Multiple query targets are not supported.
+362^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Specified domain dimensionality does not equal defined dimensionality of MDD.
+#
+363^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Cell base types of binary induce operation are incompatible.
+364^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Cell base type and scalar type of binary induce operation are incompatible.
+365^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Scalar types of binary operation are incompatible.
+366^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Cell base type of unary induce operation is not supported.
+367^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Scalar type of unary operation is not supported.
+368^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Cell base type for induced dot operation must be complex.
+369^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Scalar type for dot operation must be complex.
+370^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Struct selector is not valid.
+371^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Retrieval query must start with a SELECT statement.
+372^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Update query must start with an INSERT, UPDATE, DELETE, DROP or CREATE statement.
+373^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Unsatisfied MDD constant parameter.
+380^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Data type can not be converted to selected data exchange format.
+381^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Error in convertor of the selected data exchange format.
+382^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Unknown conversion format.
+383^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Parameter of oid function must be a persistent object of type MDD.
+384^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: OId is not valid.
+385^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operation is not supported on strings.
+386^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Base name of oid is not matching the currently opened one.
+387^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: System name of oid is not matching the currently used one.
+388^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Interval bound must be either an integer expression or an asterisk.
+389^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: No interval (in case of fixed bounds, the upper one can not be smaller than the lower one).
+390^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Minterval dimension specifications must be either of type interval or integer.
+391^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Spatial operation must be either of type minterval, point, or integer.
+393^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operand of operation lo/hi must be of type interval.
+394^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operation lo/hi can not be used for an open bound.
+395^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operand of function sdom() must be of type MDD.
+396^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Selection operation is not supported on this data type.
+397^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operand of minterval selection must be of type integer.
+398^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Index for minterval selection is out of range.
+399^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operand of point selection must be of type integer.
+#
+#
+#
+400^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Domain of MDD constructor has to be defined.
+401^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Can not evaluate domain expression to an minterval.
+402^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Projected cell is not defined.
+403^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Binary operation is not supported on these data types.
+404^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Type of cell expression is not supported.
+405^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: First operand of shift function must be of type MDD.
+406^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Second operand of shift function must be of type Point.
+407^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Dimensionality of MDD and point expression are not matching.
+408^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Second operand of shift function must be a constant expression.
+409^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Spatial domain shift of open bounds is not supported.
+#
+#
+#
+410^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operand of point expression must be of type integer.
+411^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Index for point selection is out of range.
+412^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Value expression must be either of type atomic or complex.
+413^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Condition expression must be of type boolean.
+415^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Operand of count_cells must be of type r_Marray<d_Boolean>.
+#
+416^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: First operand of scale function must be of type MDD.
+417^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Second operand of scale function must be either of type Point, Integer or Float.
+#
+418^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Second operand of bit function must be of integral type.
+419^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Could not scale the domain.
+#
+499^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: Language feature is not supported.
+#
+510^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: The argument is outside the function domain.
+511^E^Execution error $errorNo in line $lineNo, column $columnNo, near token $token: The function result exceeds the allowed range.
+#
+# 7XX errors for problems with Administration (some Oracle specific)
+#
+700^E^Admin error: General error creating RasDaMan database.
+701^E^Admin error: Error creating table in tablespace RAS_DB_SCHEMA.
+702^E^Admin error: Error inserting into table RAS_COUNTERS.
+703^E^Admin error: Error creating table in tablespace RAS_DB_BLOB.
+704^E^Admin error: Error creating index in tablespace RAS_DB_INDEX.
+705^E^Admin error: Error inserting into table RAS_BASETYPENAMES.
+706^E^Admin error: Error creating table in default tablespace.
+707^E^Admin error: Error on COMMIT creating RasDaMan database.
+708^E^Admin error: Database to be created already exists.
+#
+# 8xx errors for RasManager problems
+#
+800^E^RasManager Error: Could not connect to RasServer $url.
+801^E^RasManager Error: System overloaded, please try again later.
+802^E^RasManager Error: Acces denied, incorect user/password.
+803^E^RasManager Error: Acces denied, no permission for operation.
+804^E^RasManager Error: Acces denied, capability refused.
+805^E^RasManager Error: No suitable servers started, call rasadmin.
+806^E^RasManager Error: Write transaction in progress, please retry again later.
+807^E^RasManager Error: Requested database unknown.
+808^E^RasManager Error: Request format error.
+#
+# 9xx errors: Evaluation errors
+#
+900^E^Evaluation error $errorNo in line $lineNo, column $columnNo, near token $token: Type in typedef definition not supported.
+901^E^Evaluation error $errorNo in line $lineNo, column $columnNo, near token $token: Set template type has to be a type reference.
+902^E^Evaluation error $errorNo in line $lineNo, column $columnNo, near token $token: Type reference not found.
+903^E^Evaluation error $errorNo in line $lineNo, column $columnNo, near token $token: MDD base type has to be a type reference or an atomic type.
+904^E^Evaluation error $errorNo in line $lineNo, column $columnNo, near token $token: MDD type must have a domain specification.
+905^E^Evaluation error $errorNo in line $lineNo, column $columnNo, near token $token: Struct type name exists already.
+906^E^Evaluation error $errorNo in line $lineNo, column $columnNo, near token $token: MDD type name exists already.
+907^E^Evaluation error $errorNo in line $lineNo, column $columnNo, near token $token: Set type name exists already.
+#
+950^E^Update error $errorNo in line $lineNo, column $columnNo, near token $token: Update target must be an iterator variable.
+951^E^Update error $errorNo in line $lineNo, column $columnNo, near token $token: Update source must be an expression resulting in an r_Marray<>.
+952^E^Update error $errorNo in line $lineNo, column $columnNo, near token $token: Update base type does not match MDD base type.
+953^E^Update error $errorNo in line $lineNo, column $columnNo, near token $token: Update domain is not within MDD definition domain.
+954^E^Update error $errorNo in line $lineNo, column $columnNo, near token $token: Update target expression must be an assignable value (l-value).
+955^E^Update error $errorNo in line $lineNo, column $columnNo, near token $token: Collection name exists already.
+956^E^Update error $errorNo in line $lineNo, column $columnNo, near token $token: Unknown collection type.
+957^E^Update error $errorNo in line $lineNo, column $columnNo, near token $token: Unknown collection name.
+958^E^Update error $errorNo in line $lineNo, column $columnNo, near token $token: Allocation of new oid failed.
+959^E^Update error $errorNo in line $lineNo, column $columnNo, near token $token: MDD and collection types are incompatible.
+960^E^Update error $errorNo in line $lineNo, column $columnNo, near token $token: Insert expression must be of type MDD.
+961^E^Update error $errorNo in line $lineNo, column $columnNo, near token $token: Update domain must be of type Minterval.
+962^E^Update error $errorNo in line $lineNo, column $columnNo, near token $token: Number of update intervals must match source dimensionaltiy.
+963^E^Update error $errorNo in line $lineNo, column $columnNo, near token $token: Update domain dimensionality must match target MDD dimensionaltiy.
+964^E^Update error $errorNo in line $lineNo, column $columnNo, near token $token: Type is not persistent.
+965^E^Update error $errorNo: MDD type $token unknown.
+966^E^Update error $errorNo: MDD type is missing.
+#
+# 1xxx errors: General errors
+#
+1000^E^General error: RasDaMan tables inconsistent.
+1001^E^General error: RasDaMan server incompatible with database.
+1002^E^General error: Blob with zero length encountered.
+1003^E^General error: Tile container for TC index not found.
+1004^E^General error: Index of MDD Object is not defined.
+1005^E^General error: Storage structure of MDD Object is not defined.
+1006^E^General error: Unknown index type requested.
+1007^E^General error: Illegal index type choosen.
+1008^E^General error: No valid collection type passed to MDD collection.
+1009^E^General error: MDD object not valid or not persistent.
+1010^E^General error: No valid MDD type passed to MDD object.
+1011^E^General error: An illegal state has been reached. This is caused by a compiler bug or a library bug.
+1012^E^General error: Invalid collection type passed to MDD collection.
+1013^E^General error: The name of the type is too long.
+1014^E^General error: Invalid name of the object, should contain only [a-zA-Z0-9_]
+#
+# 2xxx errors: Internal errors
+#
+2000^E^Internal error: There seems to be another database open.
+2001^E^Internal error: Invalid OId type encountered.
+2002^E^Internal error: Entry in user defined type not found.
+2003^E^Internal error: Entry in user defined type out of bounds.
+2004^E^Internal error: Transient index used instead of persistent index.
+2005^E^Internal error: Index returned tiles multiple times.
+2006^E^Internal error: Tile was not inserted into index.
+2007^E^Internal error: Transient index access out of bounds.
+2008^E^Internal error: MDD object exists multiple times in cache.
+2009^E^Internal error: Some tile(s) were not inserted into the MDD object.
+2010^E^Internal error: A conversion module returned an incorrect base type.
+2011^E^Internal error: The collection type has no element type.
+2012^E^Internal error: The marray type has no base type.
+2013^E^Internal error: The property has no base type.
+2014^E^Internal error: The scalar was passed a NULL value.
+2015^E^Internal error: The index node that had to be split was not found in its parent.
+2016^E^Internal error: The index found more cells than allowed.
+2017^E^Internal error: The storage layout is incompatible with the index entries.
+2018^E^Internal error: Object does not support swaping.
+2019^E^Internal error: Error encountered during swaping.
+#
+# The last, the unexpected error in server
+#
+10000^E^Unexpected internal server error.
diff --git a/raslib/test/test_endian.cc b/raslib/test/test_endian.cc
new file mode 100644
index 0000000..250892a
--- /dev/null
+++ b/raslib/test/test_endian.cc
@@ -0,0 +1,156 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ * INCLUDE: test_endian.cc
+ *
+ * MODULE: raslib
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <iostream>
+
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#endif
+
+#include "raslib/basetype.hh"
+#include "raslib/primitivetype.hh"
+#include "raslib/minterval.hh"
+#include "raslib/rminit.hh"
+#include "raslib/endian.hh"
+
+
+RMINITGLOBALS('C')
+
+
+static void print_numbers(const unsigned char *data, int size)
+{
+ int i;
+
+ for (i=0; i<size; i++)
+ {
+ if ((i & 15) == 0)
+ {
+ if (i != 0)
+ printf("\n");
+
+ printf("%04x: ", i);
+ }
+ printf("%02x ", data[i]);
+ }
+ printf("\n"); fflush(stdout);
+}
+
+static void test_endian(const char *schema, const r_Minterval &dom)
+{
+ r_Base_Type *type;
+ r_Primitive_Type *primType;
+ unsigned char *srcArray;
+ unsigned char *testArray;
+ unsigned char *smallArray;
+ unsigned long size;
+ unsigned long smallSize;
+ unsigned long i;
+
+ cout << "test type <" << schema << ">" << endl;
+
+ type = (r_Base_Type*)r_Type::get_any_type(schema);
+ primType = (r_Primitive_Type*)r_Type::get_any_type("long");
+
+ size = type->size() * dom.cell_count();
+
+ srcArray = new unsigned char[size];
+
+ for (i=0; i<size; i++)
+ srcArray[i] = (unsigned char)(i & 0xff);
+
+ r_Minterval iterDom(dom.dimension());
+ for (i=0; i<dom.dimension(); i++)
+ iterDom << r_Sinterval(dom[i].low(), (r_Range)(dom[i].low() + (dom[i].high() - dom[i].low() + 1) / 2));
+
+ cout << "dom = " << dom << ", iterDom = " << iterDom << endl;
+
+ print_numbers(srcArray, 64);
+
+ smallSize = type->size() * iterDom.cell_count();
+
+ testArray = new unsigned char[size];
+ memset(testArray, 0, size);
+ smallArray = new unsigned char[smallSize];
+ memset(smallArray, 0, smallSize);
+
+ cout << "Linear change..." << endl;
+ r_Endian::swap_array(primType, size, srcArray, testArray);
+ print_numbers(testArray, 64);
+
+ cout << "Semi-generic change, full..." << endl;
+ r_Endian::swap_array(type, dom, dom, srcArray, testArray);
+ print_numbers(testArray, 64);
+
+ cout << "Semi-generic change, half..." << endl;
+ r_Endian::swap_array(type, dom, iterDom, srcArray, testArray);
+ print_numbers(testArray, 64);
+
+ cout << "Fully generic change, full..." << endl;
+ r_Endian::swap_array(type, dom, dom, dom, dom, srcArray, testArray);
+ print_numbers(testArray, 64);
+
+ cout << "Fully generic change, half..." << endl;
+ r_Endian::swap_array(type, dom, iterDom, iterDom, iterDom, srcArray, smallArray);
+ print_numbers(smallArray, 64);
+
+ delete type;
+ delete primType;
+
+ delete [] smallArray;
+ delete [] testArray;
+ delete [] srcArray;
+}
+
+
+int main(int argc, char *argv[])
+{
+ r_Minterval dom(2);
+
+ dom << r_Sinterval((r_Range)0, (r_Range)123)
+ << r_Sinterval((r_Range)10, (r_Range)456);
+
+ test_endian("char", dom);
+ test_endian("short", dom);
+ test_endian("long", dom);
+ test_endian("float", dom);
+ test_endian("double", dom);
+ test_endian("struct {short, short, long}", dom);
+
+ return 0;
+}
diff --git a/raslib/test/test_error.cc b/raslib/test/test_error.cc
new file mode 100644
index 0000000..1f5fdb9
--- /dev/null
+++ b/raslib/test/test_error.cc
@@ -0,0 +1,223 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ * SOURCE: test_error.cc
+ *
+ * MODULE: raslib
+ *
+ * PURPOSE:
+ *
+ * Test program to test class r_Error and its subclasses.
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#include <iostream>
+#include <malloc.h>
+#include "raslib/error.hh"
+
+#include "raslib/rminit.hh"
+
+RMINITGLOBALS('C')
+
+int main()
+{
+ cout << endl << "0. reading from errortxts table ----------------------------------" << endl;
+ try
+ {
+ throw r_Error( 10000 );
+ }
+ catch( r_Error &err )
+ {
+ cout << err.what() << endl;
+ }
+
+ cout << endl << "1. Throwing r_Error() -------------------------------------------" << endl;
+ try
+ {
+ throw r_Error();
+ }
+ catch( r_Error &err )
+ {
+ cout << err.what() << endl;
+ }
+
+ cout << endl << "2. Throwing r_Error( r_Error::r_Error_DatabaseUnknown ) ---------" << endl;
+ try
+ {
+ throw r_Error( r_Error::r_Error_DatabaseUnknown );
+ }
+ catch( r_Error &err )
+ {
+ cout << err.what() << endl;
+ }
+
+ cout << endl << "3. Throwing r_Eno_interval() ------------------------------------" << endl;
+ try
+ {
+ throw r_Eno_interval();
+ }
+ catch( r_Error &err )
+ {
+ cout << err.what() << endl;
+ }
+
+ cout << endl << "4. Throwing r_Eindex_violation( 10, 20, 25 ) --------------------" << endl;
+ try
+ {
+ throw r_Eindex_violation( 10, 20, 25 );
+ }
+ catch( r_Error &err )
+ {
+ cout << err.what() << endl;
+ }
+
+
+ cout << endl << "5. Throwing r_Edim_mismatch( 2, 3 ) -----------------------------" << endl;
+ try
+ {
+ throw r_Edim_mismatch( 2, 3 );
+ }
+ catch( r_Error &err )
+ {
+ cout << err.what() << endl;
+ }
+
+
+ cout << endl << "6. Throwing r_Einit_overflow() ----------------------------------" << endl;
+ try
+ {
+ throw r_Einit_overflow();
+ }
+ catch( r_Error &err )
+ {
+ cout << err.what() << endl;
+ }
+
+
+ cout << endl << "7. Throwing r_Eno_cell() ----------------------------------------" << endl;
+ try
+ {
+ throw r_Eno_cell();
+ }
+ catch( r_Error &err )
+ {
+ cout << err.what() << endl;
+ }
+
+ cout << endl << "8. Throwing r_Equery_execution_failed( 99, 5, 7, 'SELECT' ) -----" << endl;
+ try
+ {
+ throw r_Equery_execution_failed( 99, 5, 7, "SELECT" );
+ }
+ catch( r_Error &err )
+ {
+ cout << err.what() << endl;
+ }
+
+ cout << endl << "8. Testing r_Ebase_dbms ------------------------------------------" << endl;
+ cout << endl << "8.1 Throwing (4711, 'This is a test') ----------------------------" << endl;
+ try
+ {
+ throw r_Ebase_dbms( 4711, "This is a test" );
+ }
+ catch( r_Error &err )
+ {
+ cout << "Output of what() catching an r_Error &err" << endl;
+ cout << err.what() << endl;
+ }
+ try
+ {
+ throw r_Ebase_dbms( 4711, "This is a test" );
+ }
+ catch( r_Ebase_dbms &err )
+ {
+ cout << "Output of what() catching an r_Ebase_dbms &err" << endl;
+ cout << err.what() << endl;
+ }
+
+ cout << endl << "8.2 Testing serialisation of r_Ebase_dbms ------------------------" << endl;
+ char* serialErr;
+ try
+ {
+ throw r_Ebase_dbms( 4711, "This is a test" );
+ }
+ catch( r_Error &err )
+ {
+ serialErr = err.serialiseError();
+ cout << "serialised form: " << serialErr << endl;
+ }
+ try
+ {
+ cout << "Throwing error constructed from serialised form." << endl;
+ r_Error* testErr = r_Error::getAnyError(serialErr);
+ // for some strange reason a simple throw(*testErr) does not work here. It does not work
+ // if an r_Ebase_dbms is caught (core dump), it works if an r_Error is caught. Hmm, makes
+ // some sense since *r_Error is not polymorphic anymore. But it should not core dump.
+ // Well strange, but like this it works and this will be done only once in clientcomm.cc.
+ if(testErr->get_errorno () == 206) {
+ r_Ebase_dbms correctErr(*(r_Ebase_dbms*)testErr);
+ delete testErr;
+ throw correctErr;
+ }
+ else
+ cout << "Unexpected error read from serialised representation." << endl;
+ }
+ catch( r_Ebase_dbms &err )
+ {
+ cout << "Output of what() catching an r_Ebase_dbms &err" << endl;
+ cout << err.what() << endl;
+ }
+ try
+ {
+ cout << "Throwing error constructed from serialised form." << endl;
+ r_Error* testErr = r_Error::getAnyError(serialErr);
+ if(testErr->get_errorno () == 206) {
+ r_Ebase_dbms correctErr(*(r_Ebase_dbms*)testErr);
+ delete testErr;
+ throw correctErr;
+ }
+ else
+ cout << "Unexpected error read from serialised representation." << endl;
+ }
+ catch( r_Error &err )
+ {
+ cout << "Output of what() catching an r_Error &err" << endl;
+ cout << err.what() << endl;
+ }
+ cout << "Done" << endl;
+ free(serialErr);
+
+ cout << endl;
+
+ cout << "freeing error text table...";
+ freeTextTable();
+ cout << "ok." << endl;
+
+ cout << endl << "------------------------------------------------------------------" << endl;
+
+ return 0;
+}
diff --git a/raslib/test/test_metaobject.cc b/raslib/test/test_metaobject.cc
new file mode 100644
index 0000000..4f93882
--- /dev/null
+++ b/raslib/test/test_metaobject.cc
@@ -0,0 +1,332 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ * SOURCE: test_metaobject.cc
+ *
+ * MODULE: raslib
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#include <iostream>
+
+#ifdef __VISUALC__
+ #define __EXECUTABLE__
+ #include "raslib/itertype.hh"
+ #include "raslib/structuretype.hh"
+ #include "raslib/attribute.hh"
+ #include "raslib/primitivetype.hh"
+ #include "raslib/rminit.hh"
+ #include "raslib/basetype.hh"
+ #include "raslib/marraytype.hh"
+ #undef __EXECUTABLE__
+#else
+ #include "raslib/itertype.hh"
+ #include "raslib/structuretype.hh"
+ #include "raslib/attribute.hh"
+ #include "raslib/primitivetype.hh"
+ #include "raslib/rminit.hh"
+ #include "raslib/basetype.hh"
+ #include "raslib/marraytype.hh"
+#endif
+
+#include "raslib/error.hh"
+#include "raslib/type.hh"
+#include "raslib/structure.hh"
+#include "raslib/primitive.hh"
+
+RMINITGLOBALS('C')
+
+
+void testType( const char* stringType )
+{
+ r_Type* type = NULL;
+
+ cout << "Create " << stringType << endl;
+
+ try
+ {
+ type = r_Type::get_any_type( stringType );
+ }
+ catch( r_Error& errorObj )
+ {
+ cout << errorObj.what() << endl << endl;
+ }
+
+ cout << " Type: ";
+
+ if( type )
+ {
+ type->print_status( cout );
+ cout << endl;
+ cout << type->type_id() << endl;
+ }
+ else
+ {
+ cout << "<not available>" << endl;
+ }
+ cout << endl;
+ delete type;
+
+}
+
+/*
+void testEndian()
+{
+ r_Primitive_Type boolType("Bool", r_Primitive_Type::BOOL);
+ r_Primitive_Type shortType("Short", r_Primitive_Type::SHORT);
+ r_Primitive_Type uLongType("ULong", r_Primitive_Type::ULONG);
+ r_Type* structType;
+ structType = r_Type::get_any_type( "struct{bool e1, short e2, ulong e3}" );
+
+ char cChar = 47;
+ short cShort = 1065;
+ unsigned long cULong = 92753;
+
+ char *boolCell = (char*)&cChar;
+ char *shortCell = (char*)&cShort;
+ char *uLongCell = (char*)&cULong;
+ char structCell[7] = { 1, 2, 3, 4, 5, 6, 7 };
+
+ cout << "Before convertToLittleEndian:" << endl;
+ cout << "Char: " << (long)*boolCell << endl
+ << "Short: " << (long)*shortCell << " " << (long)*(shortCell+1) << endl
+ << "ULong: " << (long)*uLongCell << " " << (long)*(uLongCell+1) << " "
+ << (long)*(uLongCell+2) << " " << (long)*(uLongCell+3)
+ << endl
+ << "Struct: " << (long)*structCell << " " << (long)*(structCell+1)
+ << " " << (long)*(structCell+2) << " "
+ << (long)*(structCell+3) << " "
+ << (long)*(structCell+4) << " "
+ << (long)*(structCell+5) << " "
+ << (long)*(structCell+6) << " "
+ << endl;
+
+ boolType.convertToLittleEndian(boolCell, 1);
+ shortType.convertToLittleEndian(shortCell, 1);
+ uLongType.convertToLittleEndian(uLongCell, 1);
+ structType->convertToLittleEndian(structCell, 1);
+
+ cout << "After convertToLittleEndian:" << endl;
+ cout << "Char: " << (long)*boolCell << endl
+ << "Short: " << (long)*shortCell << " " << (long)*(shortCell+1) << endl
+ << "ULong: " << (long)*uLongCell << " " << (long)*(uLongCell+1) << " "
+ << (long)*(uLongCell+2) << " " << (long)*(uLongCell+3)
+ << endl
+ << "Struct: " << (long)*structCell << " " << (long)*(structCell+1)
+ << " " << (long)*(structCell+2) << " "
+ << (long)*(structCell+3) << " "
+ << (long)*(structCell+4) << " "
+ << (long)*(structCell+5) << " "
+ << (long)*(structCell+6) << " "
+ << endl;
+
+ boolType.convertToBigEndian(boolCell, 1);
+ shortType.convertToBigEndian(shortCell, 1);
+ uLongType.convertToBigEndian(uLongCell, 1);
+ structType->convertToLittleEndian(structCell, 1);
+
+ cout << "After convertToBigEndian:" << endl;
+ cout << "Char: " << (long)*boolCell << endl
+ << "Short: " << (long)*shortCell << " " << (long)*(shortCell+1) << endl
+ << "ULong: " << (long)*uLongCell << " " << (long)*(uLongCell+1) << " "
+ << (long)*(uLongCell+2) << " " << (long)*(uLongCell+3)
+ << endl
+ << "Struct: " << (long)*structCell << " " << (long)*(structCell+1)
+ << " " << (long)*(structCell+2) << " "
+ << (long)*(structCell+3) << " "
+ << (long)*(structCell+4) << " "
+ << (long)*(structCell+5) << " "
+ << (long)*(structCell+6) << " "
+ << endl;
+
+ delete structType;
+}
+*/
+
+int main()
+{
+ cout << "Creating definining primitive types ..." << endl;
+ r_Primitive_Type myBool("Bool", r_Primitive_Type::BOOL);
+ myBool.print_status( cout ); cout << endl;
+ r_Primitive_Type myULong("ULong", r_Primitive_Type::ULONG);
+ myULong.print_status( cout ); cout << endl;
+
+ r_Primitive_Type tmp = myBool;
+ tmp.print_status( cout ); cout << endl;
+
+ r_Attribute tmpAtt("tmpAtt",tmp );
+ tmpAtt.print_status( cout ); cout << endl;
+
+ cout << "Creating a struct out of them ..." << endl;
+ r_Attribute myAttrs[2];
+ myAttrs[0] = r_Attribute("Attr1", myBool );
+ myAttrs[1] = r_Attribute("Attr2", myULong );
+
+ r_Structure_Type myStruct("aStruct", 2, myAttrs);
+ myStruct.print_status( cout ); cout << endl;
+
+ cout << "Iterating attributes of struct:" << endl;
+ r_Structure_Type::attribute_iterator
+ iter(myStruct.defines_attribute_begin());
+ while(iter != myStruct.defines_attribute_end())
+ {
+ cout << " Name of Attribute: " << (*iter).name() << endl;
+ cout << " Offset of Attribute: " << (*iter).offset() << endl;
+ cout << " Size of type of Attribute: "
+ << (*iter).type_of().size() << endl;
+ cout << " Name of type of Attribute: "
+ << (*iter).type_of().name() << endl;
+ ++iter;
+ }
+
+ testType("char");
+
+ testType("octet");
+ testType("short");
+ testType("ushort");
+ testType("long");
+ testType("ulong");
+ testType("bool");
+ testType("float");
+ testType("double");
+
+ testType("struct{ char }");
+ testType("struct{ char band1 }");
+
+ testType("struct{ char, octet, ulong, short }");
+
+ testType("struct{ char elem1, octet elem2, ulong elem3, short elem4 }");
+ testType("struct{ char red, char green, char blue }" );
+ testType("struct{char red, char green, char blue}" );
+
+ testType("struct{ struct{ char, char, char }, ulong }");
+ testType("struct{ struct{ char elem1, char elem2, char elem3 } record, ulong value }");
+
+
+ testType("marray< char >");
+ testType("marray< char green>");
+ testType("marray< struct{ char red} >");
+
+ testType("marray< struct{char red, char green, char blue} >" );
+
+ testType("set< marray< char > >");
+ testType("set< marray< struct{ char red, char green, char blue } > >" );
+
+ testType("interval");
+ testType("minterval");
+ testType("point");
+ testType("oid");
+
+ testType("set< interval >");
+ testType("set< minterval >");
+ testType("set< point >");
+ testType("set< oid >");
+
+ /* shouldn't work */
+ cout << endl << "Testing combinations which are not allowed..." << endl;
+ testType("set< marray< interval > >");
+ testType("set< marray< minterval > >");
+ testType("set< marray< point > >");
+ testType("set< marray< oid > >");
+
+ testType("interval<set< marray< char > > >");
+ testType("interval<struct{ point blue, interval green}>");
+ testType("set< marray{ char > >");
+ testType("struct<char>");
+
+
+
+ r_Type* type = NULL;
+ char* stringType = "marray< char blue>";
+
+ cout << "Create " << stringType << endl;
+
+ try
+ {
+ type = r_Type::get_any_type( stringType );
+ }
+ catch( r_Error& errorObj )
+ {
+ cout << errorObj.what() << endl << endl;
+ }
+
+ cout << " Type: ";
+
+ if( type )
+ {
+ type->print_status( cout );
+ }
+ else
+ {
+ cout << "<not available>" << endl;
+ }
+ cout << endl;
+
+ // cout << ((r_Marray_Type*)type)->getBaseType() << endl;
+
+ cout << "Erzeugen einer Kopie und Ausgabe..." << endl;
+ r_Marray_Type my_marray;
+
+ my_marray = *((r_Marray_Type*)(type));
+ my_marray.print_status( cout );
+
+ cout << endl;
+ // cout << my_marray.getBaseType() << endl;
+
+ delete type;
+
+ r_Type* type2 = r_Type::get_any_type("struct{ short band1, char band2 }");
+
+ if( type2->isBaseType() )
+ {
+ r_Base_Type* baseType2 = (r_Base_Type*)type2;
+
+ cout << "Type: " << flush;
+ baseType2->print_status();
+ cout << endl;
+ cout << "Size: " << baseType2->size() << endl;
+ }
+
+ struct structType{ short band1r; char band2i; };
+
+ structType structValue = { 1, 2 };
+
+ r_Structure structObject( (const char*)&structValue, (const r_Structure_Type*)type2 );
+
+ structObject.print_status( cout );
+
+ cout << endl;
+
+ delete type2;
+
+ /* testEndian(); */
+ return 0;
+}
+
+
diff --git a/raslib/test/test_minterval.cc b/raslib/test/test_minterval.cc
new file mode 100644
index 0000000..f8f388f
--- /dev/null
+++ b/raslib/test/test_minterval.cc
@@ -0,0 +1,118 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ * SOURCE: test_sinterval.cc
+ *
+ * MODULE: raslib
+ *
+ * PURPOSE:
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#include <iostream>
+#include <malloc.h>
+
+#include "raslib/minterval.hh"
+#include "raslib/sinterval.hh"
+
+#include "raslib/rminit.hh"
+RMINITGLOBALS('C')
+
+int main()
+{
+ cout << endl << endl;
+ cout << "Minterval Examples" << endl;
+ cout << "===================" << endl << endl;
+
+ cout << "initializing interval [1:2,3:3] : " << endl;
+ r_Minterval m1 = r_Minterval(2);
+ m1 << r_Sinterval(1l,2l) << 3;
+ cout << m1 << endl << endl;
+
+ cout << "copy the interval with copy constructor" << endl;
+ r_Minterval copy( m1 );
+ cout << copy << endl << endl;
+
+ cout << "test for equality: ";
+ if( copy == m1 )
+ cout << "OK" << endl << endl;
+ else
+ cout << "FAILED" << endl << endl;
+
+ cout << "union of [1:4,3:6] and [3:6,1:4] :" << endl;
+ r_Minterval m2 = r_Minterval(2) << r_Sinterval(1l,4l) << r_Sinterval(3l,6l);
+ r_Minterval m3 = r_Minterval(2) << r_Sinterval(3l,6l) << r_Sinterval(1l,4l);
+ try
+ {
+ m2 += m3;
+ }
+ catch( r_Error& ex1 )
+ {
+ cerr << ex1.what() << endl;
+ }
+ cout << m2 << endl << endl;
+
+ cout << "union of [1:4,3:6] and [3:6,8:9] : " << endl;
+ r_Minterval m4 = r_Minterval(2) << r_Sinterval(1l,4l) << r_Sinterval(3l,6l);
+ r_Minterval m5 = r_Minterval(2) << r_Sinterval(3l,6l) << r_Sinterval(8l,9l);
+ try
+ {
+ m4 += m5;
+ }
+ catch( r_Error& ex2 )
+ {
+ cerr << ex2.what() << endl;
+ }
+ cout << m4 << endl << endl;
+
+ cout << "closure of [1:4,3:6] and [7:9,1:2] : " << endl;
+ r_Minterval m6 = r_Minterval(2) << r_Sinterval(1l,4l) << r_Sinterval(3l,6l);
+ r_Minterval m7 = r_Minterval(2) << r_Sinterval(7l,9l) << r_Sinterval(1l,2l);
+ try
+ {
+ m6.closure_with( m7 );
+ }
+ catch( r_Error& ex2 )
+ {
+ cerr << ex2.what() << endl;
+ }
+ cout << m6 << endl << endl;
+
+ cout << "intersection of [7:9,1:2] and [ " << m6[0].low() << ":" << m6[0].high() << "," << m6[1].low() << ":" << m6[1].high() << "]" << endl;
+ cout << m7.intersects_with( m6 );
+ cout << endl;
+
+ cout << "initializing domain [1:4,*:6,7:*]" << endl;
+ r_Minterval m8 = r_Minterval(3) << r_Sinterval(1l,4l) << r_Sinterval('*',6l) << r_Sinterval(7l,'*');
+ char* stringRepresentation = m8.get_string_representation();
+ cout << "string representation " << stringRepresentation << " should be " << m8 << endl;
+
+ r_Minterval m9 = r_Minterval( stringRepresentation );
+ cout << "recreation of the string delivers " << m9 << endl;
+ free( stringRepresentation );
+
+ return 0;
+}
diff --git a/raslib/test/test_miter.cc b/raslib/test/test_miter.cc
new file mode 100644
index 0000000..55b2930
--- /dev/null
+++ b/raslib/test/test_miter.cc
@@ -0,0 +1,334 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ * SOURCE: test_miter.cc
+ *
+ * MODULE: raslib
+ *
+ ************************************************************/
+
+#include <iostream>
+#include <math.h>
+#include <stdlib.h>
+
+#include "raslib/miter.hh"
+#include "raslib/minterval.hh"
+#include "raslib/rminit.hh"
+#include "raslib/rmdebug.hh"
+RMINITGLOBALS('C')
+
+// structure storing information on iteration for each dimension
+// (perhaps add dimension for reordering later)
+typedef struct {
+ int repeat; // total number of repeats
+ int inc; // increment per repeat
+ int curr; // current repeat
+} incArrElem;
+
+// for repeating inside the test functions
+const int numRepeat = 100;
+
+r_Minterval
+createCube(int size, int dim)
+{
+ int i;
+ long c = pow((double)size, 1.0/(double)dim);
+
+ r_Minterval res(dim);
+
+ for(i=0; i<dim; i++)
+ res << r_Sinterval(0l, c-1);
+
+ i = 0;
+ while(res.cell_count() < size) {
+ res[i].set_high(res[i].high() + 1);
+ i++;
+ }
+ if(res.cell_count() > size)
+ res[i-1].set_high(res[i-1].high() - 1);
+
+ return res;
+}
+
+void
+test_Miter( r_Minterval& m1, r_Minterval& m2, char* data )
+{
+ char* currCell;
+
+ // just to do something inside the loop
+ unsigned long sum = 0;
+
+ cout <<"Iteration r_Miter: ";
+
+ // for performance measurement
+ RMTimer mIterTimer("Iterator","r_Miter" );
+ mIterTimer.start( );
+
+ r_Miter iter(&m2, &m1, 4, (char*)data);
+ for(int i=0; i<numRepeat; i++) {
+ iter.reset();
+ while(!iter.isDone()) {
+ currCell = iter.nextCell();
+ sum += *(long*)currCell;
+ }
+ }
+
+ mIterTimer.stop( );
+ cout << sum << endl;
+}
+
+void
+test_DirectIter( r_Minterval& m1, r_Minterval& m2, char* data )
+{
+ int opSize = 4;
+ int dim = m1.dimension();
+ int i;
+ char* currCell;
+
+ // just to do something inside the loop
+ unsigned long sum = 0;
+
+ incArrElem* incArrIter;
+
+ cout <<"Iteration direct: ";
+
+ // for performance measurement
+ RMTimer iterTimer("Iterator","directIter" );
+ iterTimer.start( );
+
+ for(int r=0; r<numRepeat; r++) {
+
+ // stores the increments
+ incArrIter = new incArrElem[dim];
+
+ currCell = (char*)data;
+
+ // the following initializes incArrIter and calculates the first offset
+ int tIncIter = 1; // total increment for current dimension
+ int prevTIncIter = 1; // total increment for previous dimension
+ int incIter = 4; // current increment, corresponds to cell size
+ int firstOff = 0;
+
+ for( i=0; i<dim; i++ ) {
+ // in RasDaMan the order of dimensions is the other way round!
+ int r = dim - i - 1;
+ // used for counting in iteration, initialize with 0
+ incArrIter[i].curr = 0;
+ // how often is the increment added?
+ incArrIter[i].repeat = m2[r].high() - m2[r].low() + 1;
+ // the increment for the result tile (higher dimensions calculated
+ // further down)
+ incArrIter[i].inc = incIter;
+
+ // calculate starting offset and increments for higher dimensions
+ // firstOff is the offset in chars of the first cell
+ firstOff += (m2[r].low()-m1[r].low()) * prevTIncIter * 4;
+ // tInc is the increment if the dimension would be skipped
+ tIncIter = (m1[r].high() - m1[r].low()+1) * prevTIncIter;
+ // inc is the real increment, after some cells in the dimensions
+ // have been iterated through.
+ incIter = (tIncIter - incArrIter[i].repeat*prevTIncIter) * 4;
+ // remember total increment of last dimension
+ prevTIncIter = tIncIter;
+ }
+
+ currCell += firstOff;
+
+ int done = 0;
+ // get first adresses
+
+ while(!done) {
+ // iterate through lowest dimension
+ for(i=0; i<incArrIter[0].repeat; i++) {
+ // execute operation
+ sum += *(long*)currCell;
+ // increment adresses
+ currCell += incArrIter[0].inc;
+ }
+ // increment other dimensions
+ for(i=1; i<dim; i++) {
+ incArrIter[i].curr++;
+ currCell += incArrIter[i].inc;
+ if(incArrIter[i].curr < incArrIter[i].repeat) {
+ // no overflow in this dimension
+ break;
+ } else {
+ // overflow in this dimension
+ incArrIter[i].curr = 0;
+ }
+ }
+ if( i == dim ) {
+ // overflow in last dimension
+ done = 1;
+ }
+ }
+ delete [] incArrIter;
+ }
+ iterTimer.stop();
+ cout << sum << endl;
+}
+
+void
+test_OldIter( r_Minterval& m1, r_Minterval& m2, char* data )
+{
+ // just to do something inside the loop
+ unsigned long sum = 0;
+
+ cout <<"Iteration oldIter: ";
+ // for performance measurement
+ RMTimer oldIterTimer("Iterator","oldIter" );
+ oldIterTimer.start( );
+
+ r_Point pOp(m2.dimension());
+ int done;
+ int recalc;
+ int i, j;
+ const int opSize = 4;
+ int dim = m2.dimension();
+ int innerExtent = (m2.get_extent())[dim-1];
+ char* cellOp;
+
+ // initialize points
+ for(i = 0; i < dim; i++)
+ {
+ pOp << 0;
+ }
+
+ for(int r=0; r<numRepeat; r++) {
+ done = 0;
+ recalc = 0;
+
+ // initialize points
+ for(i = 0; i < dim; i++)
+ {
+ pOp[i] = m2[i].low();
+ }
+
+ cellOp = (char*)data + m1.cell_offset(pOp)*4;
+
+ // iterate over all cells
+ while(!done)
+ {
+ if( recalc )
+ {
+ cellOp = (char*)data + m1.cell_offset(pOp)*4;
+ recalc = 0;
+ }
+
+ // iterate through innermost dimension
+ for(j = 0; j < innerExtent; j++ ) {
+ // execute operation on cell
+ sum += *(long*)cellOp;
+ cellOp += opSize;
+ }
+
+ // increment coordinates
+ i = dim - 2;
+ // special case! 1-D operands!
+ if( i < 0 )
+ break;
+ ++pOp[i];
+ recalc = 1;
+ while( pOp[i] > m2[i].high() )
+ {
+ pOp[i] = m2[i].low();
+ i--;
+ if(i < 0)
+ {
+ done = 1;
+ break;
+ }
+ ++pOp[i];
+ }
+ }
+ }
+
+ oldIterTimer.stop();
+ cout << sum << endl;
+}
+
+void
+test_CppIter( unsigned long cells, char* data )
+{
+ unsigned long sum = 0;
+ RMTimer cppIterTimer("Iterator", "cppIter");
+ cppIterTimer.start();
+
+ for(int r=0; r<numRepeat; r++) {
+ for(int i = 0; i<1048576; i++) {
+ sum += data[i];
+ }
+ }
+
+ cppIterTimer.stop();
+ cout <<"Iteration C++: " << sum << endl;
+}
+
+int main()
+{
+ const unsigned long noCells = 1048576;
+ unsigned long* data;
+
+ for(int dim=1; dim<=7; dim++) {
+ r_Minterval m2;
+ r_Minterval m1(dim);
+
+ m2 = createCube(noCells, dim);
+
+ for(int i=0; i<dim; i++) {
+ m1 << r_Sinterval(m2[i].low()-1, m2[i].high()+1);
+ }
+
+ // as basis for the operations
+ data = new unsigned long[m1.cell_count()];
+ for(int i=0; i < m1.cell_count(); i++) {
+ data[i] = i;
+ }
+
+ cout <<"Iterate through " << m2 << " in "<< m1 << endl;
+
+ RMInit::bmOut << "Dimensionality: " << dim << ", cells: "
+ << m2.cell_count() << endl;
+
+ for(int i=0; i<5; i++) {
+ test_Miter( m1, m2, (char*)data );
+ test_OldIter( m1, m2, (char*)data );
+ test_DirectIter( m1, m2, (char*)data );
+ }
+ delete [] data;
+ }
+
+ RMInit::bmOut << "1-D Iteration in C++:" << endl;
+
+ data = new unsigned long[noCells];
+
+ for(int i=0; i < noCells; i++) {
+ data[i] = i;
+ }
+
+ for(int i=0; i<5; i++) {
+ test_CppIter( noCells, (char*)data );
+ }
+ delete [] data;
+}
diff --git a/raslib/test/test_miterd b/raslib/test/test_miterd
new file mode 100644
index 0000000..7ee9a45
--- /dev/null
+++ b/raslib/test/test_miterd
Binary files differ
diff --git a/raslib/test/test_miterd.cc b/raslib/test/test_miterd.cc
new file mode 100644
index 0000000..e664aec
--- /dev/null
+++ b/raslib/test/test_miterd.cc
@@ -0,0 +1,75 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ * SOURCE: test_miter.cc
+ *
+ * MODULE: raslib
+ *
+ ************************************************************/
+
+#include <iostream>
+#include <math.h>
+#include <stdlib.h>
+
+#include "raslib/miterd.hh"
+#include "raslib/minterval.hh"
+#include "raslib/rminit.hh"
+#include "raslib/rmdebug.hh"
+RMINITGLOBALS('C')
+
+int
+main(int i, char** argv)
+ {
+ unsigned short src[][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}, {13, 14, 15, 16}};
+ for (r_Dimension i = 0; i < 4; i++)
+ {
+ for (r_Dimension c = 0; c < 4; c++)
+ {
+ cout << src[i][c] << " ";
+ }
+ cout << endl;
+ }
+ for (r_Dimension i = 0; i < 4; i++)
+ {
+ for (r_Dimension c = 0; c < 4; c++)
+ {
+ cout << src[c][i] << " ";
+ }
+ cout << endl;
+ }
+ /*
+ r_MiterDirect iter(src, r_Minterval("[0:3,0:3]"), r_Minterval("[0:3,0:3]"), 2, 0);
+ r_Dimension order[] = {1,1};
+ unsigned int step[] = {1,0};
+ r_Dimension order2[] = {0};
+ while (!iter.isDone())
+ {
+ iter.iterateUserOrder(order, step);
+ cout << *(unsigned short*)(iter.getData()) << " " << endl;;
+ cout << "pos " << iter << endl;
+ // cout << *(unsigned short*)(iter.getData()) << " ";
+ iter.operator++();
+ }
+ */
+ }
diff --git a/raslib/test/test_miterf.cc b/raslib/test/test_miterf.cc
new file mode 100644
index 0000000..43660f9
--- /dev/null
+++ b/raslib/test/test_miterf.cc
@@ -0,0 +1,118 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ * SOURCE: test_miterf.cc
+ *
+ * MODULE: raslib
+ *
+ * PURPOSE:
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+
+#include <iostream>
+#include <math.h>
+#include <stdlib.h>
+
+#include "raslib/mddtypes.hh"
+#include "raslib/miterf.hh"
+#include "raslib/minterval.hh"
+#include "raslib/rminit.hh"
+#include "raslib/rmdebug.hh"
+
+
+
+RMINITGLOBALS('C')
+
+
+int main(int argc, char *argv[])
+{
+ r_Dimension dim = 3;
+ r_Minterval iv(dim);
+ r_Dimension i;
+ double *iterMin, *iterMax, *iterStep;
+ int typeLength = 1;
+ long totalSize = typeLength;
+ long totalSteps = 1;
+ double stepBy = 1.5;
+
+ i = 1;
+ while (i < argc)
+ {
+ if (strcmp(argv[i], "-s") == 0)
+ {
+ stepBy = atof(argv[++i]);
+ }
+ i++;
+ }
+
+ cout << "Step by " << stepBy << endl;
+
+ iterMin = new double[dim]; iterMax = new double[dim];
+ iterStep = new double[dim];
+ for (i=0; i<dim; i++)
+ {
+ int steps;
+
+ iterStep[i] = stepBy;
+ iterMin[i] = 0;
+ iterMax[i] = (1<<(4+i)) - 1;
+ iv << r_Sinterval((r_Range)(iterMin[i]), (r_Range)(iterMax[i]));
+ totalSize *= (r_Range)(iterMax[i]) - (r_Range)(iterMin[i]) + 1;
+ steps = (int)((iterMax[i] - iterMin[i]) / iterStep[i]);
+ totalSteps *= (steps + 1);
+ iterMax[i] = iterMin[i] + (steps + 0.5)*iterStep[i]; // rounding effects
+ }
+
+ char *srcData = new char[totalSize];
+
+ cout << "Total size: 0x" << hex << totalSize
+ << ", base address " << (void*)srcData << endl;
+
+ r_MiterFloat iter(&iv, iterMin, iterMax, iterStep, typeLength, srcData);
+
+ long steps = 0;
+ while (!iter.isDone())
+ {
+ char *cell = iter.nextCell();
+
+ if (cell + typeLength > srcData + totalSize)
+ {
+ cout << dec << "Overflow by " << (cell - srcData) - totalSize << endl;
+ }
+ steps++;
+ }
+
+ cout << dec << "Did " << steps << " steps out of " << totalSteps << endl;
+ if (steps != totalSteps)
+ cout << "!!! WRONG NUMBER OF STEPS !!!" << endl;
+
+ delete [] srcData;
+
+ delete [] iterMin; delete [] iterMax; delete [] iterStep;
+
+ return 0;
+}
diff --git a/raslib/test/test_oid.cc b/raslib/test/test_oid.cc
new file mode 100644
index 0000000..d7c3170
--- /dev/null
+++ b/raslib/test/test_oid.cc
@@ -0,0 +1,181 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ * SOURCE: test_oid.cc
+ *
+ * MODULE: raslib
+ *
+ * PURPOSE:
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#include <iostream>
+#include <iomanip.h>
+// #include <limits.h>
+#include "raslib/oid.hh"
+
+#include "raslib/rminit.hh"
+RMINITGLOBALS('C')
+
+int main()
+{
+ cout << endl << endl;
+ cout << "OId Examples" << endl;
+ cout << "============" << endl << endl;
+
+ cout << "Create oid1" << endl;
+ r_OId oid1( "testSystem", "testBase", 99 );
+ cout << " oid1........: " << oid1 << endl;
+ cout << " system name: " << oid1.get_system_name() << endl;
+ cout << " base name: " << oid1.get_base_name() << endl;
+ cout << " local oid..: " << oid1.get_local_oid() << endl << endl;
+
+ cout << "Create oid2 with string representation of oid1" << endl;
+ r_OId oid2( oid1.get_string_representation() );
+ cout << " oid2........: " << oid2 << endl;
+ cout << " system name: " << oid2.get_system_name() << endl;
+ cout << " base name: " << oid2.get_base_name() << endl;
+ cout << " local oid..: " << oid2.get_local_oid() << endl << endl;
+
+ cout << "Assign oid1 to oid2" << endl;
+ oid2 = oid1;
+ cout << " oid2........: " << oid2 << endl;
+ cout << " system name: " << oid2.get_system_name() << endl;
+ cout << " base name: " << oid2.get_base_name() << endl;
+ cout << " local oid..: " << oid2.get_local_oid() << endl << endl;
+
+ cout << "Assign temporary oid to oid2" << endl;
+ oid2 = r_OId( "testSystem|testBase|100" );
+ cout << " oid2........: " << oid2 << endl;
+ cout << " system name: " << oid2.get_system_name() << endl;
+ cout << " base name: " << oid2.get_base_name() << endl;
+ cout << " local oid..: " << oid2.get_local_oid() << endl << endl;
+
+ cout << "Assign oid1 to oid1" << endl;
+ oid1 = oid1;
+ cout << " oid1........: " << oid1 << endl;
+ cout << " system name: " << oid1.get_system_name() << endl;
+ cout << " base name: " << oid1.get_base_name() << endl;
+ cout << " local oid..: " << oid1.get_local_oid() << endl << endl;
+
+ cout << "Create oid3 as a copy of oid1 with the copy constructor" << endl;
+ r_OId oid3( oid1 );
+ cout << " oid3........: " << oid3 << endl;
+ cout << " system name: " << oid3.get_system_name() << endl;
+ cout << " base name: " << oid3.get_base_name() << endl;
+ cout << " local oid..: " << oid3.get_local_oid() << endl << endl;
+
+ cout << "Create oid4 with string testSystem|testBase|100" << endl;
+ r_OId oid4( "testSystem|testBase|100" );
+ cout << " oid4........: " << oid4 << endl;
+ cout << " system name: " << oid4.get_system_name() << endl;
+ cout << " base name: " << oid4.get_base_name() << endl;
+ cout << " local oid..: " << oid4.get_local_oid() << endl << endl;
+
+ cout << "Create oid5 with string |testBase|100" << endl;
+ r_OId oid5( "|testBase|100" );
+ cout << " oid5........: " << oid5 << endl;
+ cout << " system name: " << oid5.get_system_name() << endl;
+ cout << " base name: " << oid5.get_base_name() << endl;
+ cout << " local oid..: " << oid5.get_local_oid() << endl << endl;
+
+ cout << "Create oid6 with string ||100" << endl;
+ r_OId oid6( "||100" );
+ cout << " oid6........: " << oid6 << endl;
+ cout << " system name: " << oid6.get_system_name() << endl;
+ cout << " base name: " << oid6.get_base_name() << endl;
+ cout << " local oid..: " << oid6.get_local_oid() << endl << endl;
+
+ cout << "Create oid7 with string |||" << endl;
+ r_OId oid7( "|||" );
+ cout << " oid7........: " << oid7 << endl;
+ cout << " system name: " << oid7.get_system_name() << endl;
+ cout << " base name: " << oid7.get_base_name() << endl;
+ cout << " local oid..: " << oid7.get_local_oid() << endl << endl;
+
+ cout << "Create oid8 with an empty string" << endl;
+ r_OId oid8( "" );
+ cout << " oid8........: " << oid8 << endl;
+ cout << " system name: " << oid8.get_system_name() << endl;
+ cout << " base name: " << oid8.get_base_name() << endl;
+ cout << " local oid..: " << oid8.get_local_oid() << endl << endl;
+
+ cout << "Create oid9 with just a local oid" << endl;
+ r_OId oid9( 0, 0, 100 );
+ cout << " oid8........: " << oid9 << endl;
+ cout << " system name: " << oid9.get_system_name() << endl;
+ cout << " base name: " << oid9.get_base_name() << endl;
+ cout << " local oid..: " << oid9.get_local_oid() << endl << endl;
+
+ cout << "Create oid10 with copy constructor from oid1" << endl;
+ r_OId oid10( oid1 );
+ cout << " oid10.......: " << oid10 << endl;
+ cout << " system name: " << oid10.get_system_name() << endl;
+ cout << " base name: " << oid10.get_base_name() << endl;
+ cout << " local oid..: " << oid10.get_local_oid() << endl << endl;
+
+ cout << "Compare r_OId( \"testSystem1|testBase|99\") < r_OId( \"testSystem2|testBase|99\")" << endl;
+ cout << (r_OId( "testSystem1|testBase|99") < r_OId( "testSystem2|testBase|99")) << endl << endl;
+
+ cout << "Compare r_OId( \"testSystem|testBase1|99\") < r_OId( \"testSystem|testBase2|99\")" << endl;
+ cout << (r_OId( "testSystem|testBase1|99") < r_OId( "testSystem|testBase2|99")) << endl << endl;
+
+ cout << "Compare r_OId( \"testSystem|testBase|99\") < r_OId( \"testSystem|testBase|100\")" << endl;
+ cout << (r_OId( "testSystem1|testBase|99") < r_OId( "testSystem2|testBase|100")) << endl << endl;
+
+ cout << "Compare r_OId( \"testSystem1|testBase|99\") > r_OId( \"testSystem2|testBase|99\")" << endl;
+ cout << (r_OId( "testSystem1|testBase|99") > r_OId( "testSystem2|testBase|99")) << endl << endl;
+
+ cout << "Compare r_OId( \"testSystem|testBase1|99\") > r_OId( \"testSystem|testBase2|99\")" << endl;
+ cout << (r_OId( "testSystem|testBase1|99") > r_OId( "testSystem|testBase2|99")) << endl << endl;
+
+ cout << "Compare r_OId( \"testSystem|testBase|99\") > r_OId( \"testSystem|testBase|100\")" << endl;
+ cout << (r_OId( "testSystem1|testBase|99") > r_OId( "testSystem2|testBase|100")) << endl << endl;
+
+ cout << "Create oid11" << endl;
+ // cout << "Double limit: " << DBL_MAX << "= 0x" << hex << DBL_MAX << dec << endl;
+ double maxDouble = 0xffffffffffff;
+ cout << "48bit : " << setprecision(30) << maxDouble << endl;
+ cout << "48bit - 1 : " << setprecision(30) << maxDouble-1 << endl;
+ cout << "48bit + 1 : " << setprecision(30) << maxDouble+1 << endl;
+ r_OId oid11( "testSystem", "testBase", maxDouble );
+ cout << " oid11.......: " << oid11 << endl;
+ cout << " system name: " << oid11.get_system_name() << endl;
+ cout << " base name: " << oid11.get_base_name() << endl;
+ cout << " local oid..: " << oid11.get_local_oid() << endl << endl;
+
+ cout << endl;
+
+ cout << "Create oid12 with string ''" << endl;
+ r_OId oid12( "" );
+ cout << " oid12.......: " << oid12 << endl;
+ cout << " system name: " << oid12.get_system_name() << endl;
+ cout << " base name: " << oid12.get_base_name() << endl;
+ cout << " local oid..: " << oid12.get_local_oid() << endl << endl;
+
+ return 0;
+}
+
diff --git a/raslib/test/test_params.cc b/raslib/test/test_params.cc
new file mode 100644
index 0000000..4be15df
--- /dev/null
+++ b/raslib/test/test_params.cc
@@ -0,0 +1,101 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ * INCLUDE: test_params.cc
+ *
+ * MODULE: raslib
+ *
+ * PURPOSE:
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#include <stdio.h>
+#include <iostream>
+#include <string.h>
+#include <stdlib.h>
+
+#include "raslib/rminit.hh"
+#include "raslib/parseparams.hh"
+
+
+RMINITGLOBALS('C')
+
+
+typedef struct test_params_s {
+ r_Parse_Params *pp;
+ int zlevel;
+ double fidelity;
+ char *lstream;
+} test_params_t;
+
+
+static void test_params(test_params_t &params, char *str)
+{
+ cout << "Processing (" << str << ") ..." << endl;
+
+ params.pp->process(str);
+
+ cout << "zlevel = " << params.zlevel
+ << ", fidelity = " << params.fidelity
+ << ", stream = <" << params.lstream << ">" << endl;
+
+ // string was allocated with strdup, free now
+ free(str);
+}
+
+
+int main(int argc, char *argv[])
+{
+ r_Parse_Params pp;
+ test_params_t params = {&pp, -1, -1.0, NULL};
+
+ pp.add("zlevel", &params.zlevel, r_Parse_Params::param_type_int);
+ pp.add("fidelity", &params.fidelity, r_Parse_Params::param_type_double);
+ pp.add("stream", &params.lstream, r_Parse_Params::param_type_string);
+
+ // Note: must use strdup() because Purify doesn't find reads over the end of
+ // static strings!
+ test_params(params, strdup("0123"));
+ test_params(params, strdup("zlevel, fidelity=0.1"));
+ test_params(params, strdup("zlevel=a"));
+ test_params(params, strdup("zlevel=6"));
+ test_params(params, strdup("\"zlevel=6\""));
+ test_params(params, strdup("fidelity=0.90"));
+ test_params(params, strdup("stream=rle"));
+ test_params(params, strdup("stream=eee "));
+ test_params(params, strdup("stream=\"rle\""));
+ test_params(params, strdup("zlevel=9, fidelity=0.75, stream=zlib"));
+ test_params(params, strdup("stream=rle, zlevel=5"));
+ test_params(params, strdup("zlevel=1, foobar=hello"));
+ test_params(params, strdup("foobar=hello, zlevel=2"));
+ test_params(params, strdup(" stream=\"zlib\" "));
+ test_params(params, strdup(" foobar=\"hello, you there\", stream=\"rle\""));
+
+ if (params.lstream != NULL)
+ delete [] params.lstream;
+
+ return 0;
+}
diff --git a/raslib/test/test_point.cc b/raslib/test/test_point.cc
new file mode 100644
index 0000000..63b2f05
--- /dev/null
+++ b/raslib/test/test_point.cc
@@ -0,0 +1,90 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ * SOURCE: test_point.cc
+ *
+ * MODULE: raslib
+ *
+ * PURPOSE:
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#include <iostream>
+#include <stdlib.h>
+
+#include "raslib/point.hh"
+
+#include "raslib/rminit.hh"
+RMINITGLOBALS('C')
+
+int main()
+{
+ cout << endl << endl;
+ cout << "Point Examples" << endl;
+ cout << "===============" << endl << endl;
+
+ cout << "initialize 1D-point: " << flush;
+ r_Point d1(1);
+ cout << d1 << endl;
+
+ cout << "set value to 9 : " << flush;
+ d1[0] = 9;
+ cout << d1 << endl;
+
+ r_Point a(3);
+ a << 1 << 2 << 3;
+ cout << "stream initializing point (1,2,3) : " << a << endl << endl;
+
+ try{
+ cout << "read out of range : " << a[3] << endl;
+ }
+ catch( r_Eindex_violation& ex ){
+ cout << ex.what();
+ }
+ cout << endl << endl;
+
+ r_Point b = r_Point(3) << 1 << 2 << 3;
+ cout << "assignment point (1,2,3) : " << b << endl << endl;
+
+ cout << "temp. obj. (1,2,3), access second coord. : " << ( r_Point(3) << 1 << 2 << 3 )[1] << endl << endl;
+
+ a[1] = 4;
+ cout << "assignment a[1]=4 to a(1,2,3) : " << a << endl << endl;
+
+ r_Point c = b;
+ cout << "equal operator test: " << flush;
+ if( c == b )
+ cout << "OK" << endl;
+ else
+ cout << "FALSE" << endl;
+
+ char* stringRep = b.get_string_representation();
+ cout << endl << "String representation of point " << b << ": " << stringRep << endl;
+ cout << "Result of string constructor: " << r_Point( stringRep ) << endl;
+ free( stringRep );
+
+ cout << "Result of r_Point(\"[ 0, 5, 3]\"): " << r_Point("[ 0, 5, 3]") << endl;
+}
diff --git a/raslib/test/test_rmdebug.cc b/raslib/test/test_rmdebug.cc
new file mode 100644
index 0000000..c6f29ca
--- /dev/null
+++ b/raslib/test/test_rmdebug.cc
@@ -0,0 +1,179 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ * SOURCE: test_rmdebug.cc
+ *
+ * MODULE: raslib
+ *
+ * PURPOSE:
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#include <iostream>
+#include "raslib/rmdebug.hh"
+
+#include "raslib/rminit.hh"
+
+// number of repetitions for performance tests
+static const int repeat = 100000;
+
+RMINITGLOBALS('C')
+
+void testFunc1()
+{
+ RMDebug localRMDebug = RMDebug("Class1", "testFunc1", "Module1",
+ __FILE__, __LINE__);
+}
+
+void testFunc2(int reclevel)
+{
+ RMDebug localRMDebug = RMDebug("Class1", "testFunc2", "Module1",
+ __FILE__, __LINE__);
+
+ if(reclevel > 1)
+ testFunc2(reclevel - 1);
+}
+
+void testFunc3(void)
+{
+ RMDebug localRMDebug("Class1", "testFunc3", "server",
+ __FILE__, __LINE__);
+
+ RMDBGMOUT( 2, RMDebug::module_server, NULL, "D: testing 1" );
+ RMDBGMOUT( 3, RMDebug::module_server, "Class1", "D: testing 2" );
+ RMDBGMINOUT( 4, RMDebug::module_server, "Class1", "D: testing 3" );
+}
+
+void testFunc4(int reclevel)
+{
+ RMDebug localRMDebug(1, "Class2", "testFunc4", RMDebug::module_raslib,
+ __FILE__, __LINE__);
+
+ if (reclevel > 1)
+ testFunc4(reclevel - 1);
+}
+
+// this was used to test correctness
+
+void oldMain()
+{
+ int i;
+
+ for(i = 1; i<=5; i++)
+ testFunc1();
+
+ testFunc2(5);
+
+ testFunc3();
+
+ testFunc4(4);
+
+ cout << "Test of RMTimer" << endl;
+
+ cout << "The following should hold approximately: timer2 + timer3 = timer1" << endl << endl;
+
+ RMTimer* timer1 = new RMTimer("main","timer1");
+ RMTimer* timer2 = new RMTimer("main","timer2");
+
+ timer2->pause();
+
+ RMTimer* timer3 = new RMTimer("main","timer3");
+ for( long busy=0; busy <= 50000000; busy++ );
+ delete timer3;
+
+ timer2->resume();
+
+ for( busy=0; busy <= 30000000; busy++ );
+
+ delete timer2;
+ delete timer1;
+
+ cout << "Benchmark level set to " << RManBenchmark << endl;
+
+ RMInit::bmOut << "test output in benchmark stream" << endl;
+}
+
+double testStatic(double dummy)
+{
+ RMTIMER("test_rmdebug", "testStatic");
+
+ for(int i=0; i<repeat; i++)
+ dummy = dummy*4711.4712;
+ return dummy;
+}
+
+double testDynamic(double dummy)
+{
+#ifdef RMANBENCHMARK
+ RMTimer* localRMTimer = 0;
+
+ if( RManBenchmark >= 3 )
+ localRMTimer = new RMTimer("test_rmdebug", "testDynamic");
+#endif
+
+ for(int i=0; i<repeat; i++)
+ dummy = dummy*4711.4712;
+
+#ifdef RMANBENCHMARK
+ if( localRMTimer ) delete localRMTimer;
+#endif
+
+ return dummy;
+}
+
+// Evaluating time needed for measurement with different uses
+// of RMTimer.
+
+void testPerf()
+{
+ double dummy = 3.14;
+
+ cout << "Testing dynamic RMTimer vs. static RMTimer." << endl;
+
+ // to put in cache
+ dummy = testStatic(dummy);
+ cout << "Static:" << endl;
+ dummy = testStatic(dummy);
+
+ // to put in cache
+ dummy = testDynamic(dummy);
+ cout << "Dynamic:" << endl;
+ dummy = testDynamic(dummy);
+}
+
+int main()
+{
+ RMDebug::initRMDebug();
+ RManBenchmark = 4;
+ RMInit::bmOut = cout.rdbuf();
+
+ oldMain();
+ // testPerf();
+
+ return 0;
+}
+
+
diff --git a/raslib/test/test_sinterval.cc b/raslib/test/test_sinterval.cc
new file mode 100644
index 0000000..fa2fbc5
--- /dev/null
+++ b/raslib/test/test_sinterval.cc
@@ -0,0 +1,164 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ * SOURCE: test_sinterval.cc
+ *
+ * MODULE: raslib
+ *
+ * PURPOSE:
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#include <iostream>
+#include <stdlib.h>
+
+#include "raslib/sinterval.hh"
+
+#include "raslib/rminit.hh"
+RMINITGLOBALS('C')
+
+int main()
+{
+ r_Sinterval interval1, interval2;
+
+ char Buffer[256];
+
+ cout << "lower bound ? ";
+ cin >> Buffer;
+ cout << endl;
+
+ if( Buffer[0] == '*' )
+ interval1.set_low('*');
+ else
+ interval1.set_low( atol( Buffer ) );
+
+ cout << "upper bound ? ";
+ cin >> Buffer;
+ cout << endl;
+
+ if( Buffer[0] == '*' )
+ interval1.set_high('*');
+ else
+ interval1.set_high( atol( Buffer ) );
+
+ cout << "interval1 = [";
+ interval1.print_status( cout );
+ cout << "]" << endl << endl;
+
+ cout << "lower bound ? ";
+ cin >> Buffer;
+ cout << endl;
+
+ if( Buffer[0] == '*' )
+ interval2.set_low('*');
+ else
+ interval2.set_low( atol( Buffer ) );
+
+ cout << "upper bound ? ";
+ cin >> Buffer;
+ cout << endl;
+
+ if( Buffer[0] == '*' )
+ interval2.set_high('*');
+ else
+ interval2.set_high( atol( Buffer ) );
+
+ cout << "interval1 = [";
+ interval2.print_status( cout );
+ cout << "]" << endl << endl;
+
+ r_Sinterval result;
+
+ try{
+ result.union_of( interval1, interval2 );
+
+ cout << "union = [";
+ result.print_status( cout );
+ cout << "]" << endl;
+ }
+ catch( r_Eno_interval error )
+ {
+ cerr << "union " << error.what() << endl;
+ }
+
+ try{
+ result.difference_of( interval1, interval2 );
+
+ cout << "difference = [";
+ result.print_status( cout );
+ cout << "]" << endl;
+ }
+ catch( r_Eno_interval error )
+ {
+ cerr << "difference " << error.what() << endl;
+ }
+
+ try{
+ result.intersection_of( interval1, interval2 );
+
+ cout << "intersection = [";
+ result.print_status( cout );
+ cout << "]" << endl;
+ }
+ catch( r_Eno_interval error )
+ {
+ cerr << "intersection " << error.what() << endl;
+ }
+
+ try{
+ result.closure_of( interval1, interval2 );
+
+ cout << "closure = [";
+ result.print_status( cout );
+ cout << "]" << endl;
+ }
+ catch( r_Eno_interval error )
+ {
+ cerr << "closure " << error.what() << endl;
+ }
+
+ if( interval1.intersects_with( interval2 ) )
+ cerr << "The intervals intersect." << endl;
+ else
+ cerr << "The intervals do not intersect." << endl;
+
+ cerr << endl;
+
+ r_Sinterval b( 4l, 10l );
+ char* stringRep = b.get_string_representation();
+ cout << endl << "String representation of interval " << b << ": " << stringRep << endl;
+ cout << "Result of string constructor: " << r_Sinterval( stringRep ) << endl;
+ free( stringRep );
+
+ cout << "Result of r_Sinterval(\" 10 : 100\"): " << r_Sinterval(" 10 : 100") << endl;
+ cout << "Result of r_Sinterval(\" * : 100\"): " << r_Sinterval(" * : 100") << endl;
+ cout << "Result of r_Sinterval(\" 10 : * \"): " << r_Sinterval(" 10 : * ") << endl;
+ cout << "Result of r_Sinterval(\" * : * \"): " << r_Sinterval(" * : * ") << endl;
+
+ return 0;
+}
+
+
diff --git a/raslib/test/test_timer.cc b/raslib/test/test_timer.cc
new file mode 100644
index 0000000..797c0fa
--- /dev/null
+++ b/raslib/test/test_timer.cc
@@ -0,0 +1,101 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ * SOURCE: test_timer.cc
+ *
+ * MODULE: raslib
+ *
+ * PURPOSE:
+ *
+ * Test program to test class RMTimer.
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#include <iostream>
+#include "raslib/rmdebug.hh"
+
+
+RMINITGLOBALS('C')
+
+class Exp {
+
+public:
+ Exp( char* name );
+
+ void useTimer( );
+
+ ~Exp( );
+
+ RMTimer* t1;
+ RMTimer t2;
+ char* name;
+};
+
+Exp::Exp( char* n)
+ :t2("Test Timer ", "t2" ), name( n )
+{
+ t1 = new RMTimer( "Test Timer ", "t1" );
+}
+
+void Exp::useTimer( )
+{
+ cout << "useTimer "<< name << " t1 ... "<<endl;
+ t1->start( );
+ t1->stop( );
+ cout << "and t2"<<endl;
+ t2.start( );
+ t2.stop( );
+}
+
+Exp::~Exp( )
+{
+ cout << "Exp::~Exp( " << name << " ) "<< endl;
+ delete t1;
+}
+
+static const Exp exp1("Static Exp Object");
+
+int main()
+{
+
+ /*
+ RMTimer tt( "Test Timer ", "tt" );
+
+ cout << "RMTimer start( )" <<endl;
+ tt.start( );
+ tt.stop( );
+ */
+
+ Exp e( "Exp Object" );
+ e.useTimer( );
+
+ Exp* ep = new Exp("Pointer to Exp Object");
+ ep->useTimer( );
+ delete ep;
+
+ return 0;
+}
diff --git a/raslib/type.cc b/raslib/type.cc
new file mode 100644
index 0000000..690160c
--- /dev/null
+++ b/raslib/type.cc
@@ -0,0 +1,671 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+static const char rcsid[] = "@(#)raslib, r_Type: $Header: /home/rasdev/CVS-repository/rasdaman/raslib/type.cc,v 1.17 2003/12/27 23:01:21 rasdev Exp $";
+
+#include <ctype.h> // for isalpha()
+#include <string.h> // for strncmp()
+
+#include "raslib/type.hh"
+#include "raslib/collectiontype.hh"
+#include "raslib/primitivetype.hh"
+#include "raslib/complextype.hh"
+#include "raslib/structuretype.hh"
+#include "raslib/marraytype.hh"
+#include "raslib/sintervaltype.hh"
+#include "raslib/mintervaltype.hh"
+#include "raslib/pointtype.hh"
+#include "raslib/oidtype.hh"
+#include "raslib/attribute.hh"
+#include "raslib/error.hh"
+#include "raslib/rminit.hh"
+
+r_Type::r_Type()
+ : r_Meta_Object()
+{
+}
+
+r_Type::r_Type(const char* newTypeName)
+ : r_Meta_Object(newTypeName)
+{
+}
+
+r_Type::r_Type(const r_Type& oldObj)
+ : r_Meta_Object(oldObj)
+{
+}
+
+const r_Type&
+r_Type::operator=(const r_Type& oldObj)
+{
+ // Gracefully handle self assignment
+ if (this == &oldObj) return *this;
+
+ r_Meta_Object::operator=(oldObj);
+
+ return *this;
+}
+
+r_Type::~r_Type()
+{
+}
+
+bool
+r_Type::isStructType() const
+{
+ return false;
+}
+
+bool
+r_Type::isComplexType() const
+{
+ return false;
+}
+
+bool
+r_Type::isBaseType() const
+{
+ return false;
+}
+
+bool
+r_Type::isCollectionType() const
+{
+ return false;
+}
+
+bool
+r_Type::isMarrayType() const
+{
+ return false;
+}
+
+bool
+r_Type::isPrimitiveType() const
+{
+ return false;
+}
+
+bool
+r_Type::isSintervalType() const
+{
+ return false;
+}
+
+bool
+r_Type::isMintervalType() const
+{
+ return false;
+}
+
+bool
+r_Type::isPointType() const
+{
+ return false;
+}
+
+bool
+r_Type::isOidType() const
+{
+ return false;
+}
+
+r_Type*
+r_Type::get_any_type(const char* type_string)
+{
+ char* pos = (char*)type_string;
+ char* identifier = NULL;
+ r_Type* returnValue = NULL;
+ DLTOKEN token = DLUNKNOWN;
+
+ // one token look ahead
+ char* oldPos = pos;
+ token = getNextToken(pos, identifier);
+ pos = oldPos;
+
+ switch(token)
+ {
+ case DLMARRAY:
+ returnValue = getMarrayType(pos);
+ break;
+ case DLSET:
+ returnValue = getCollectionType(pos);
+ break;
+ default:
+ returnValue = getType(pos);
+ }
+
+ return returnValue;
+}
+
+r_Type::DLTOKEN
+r_Type::getNextToken(char* &pos, char* &identifier)
+{
+ DLTOKEN token = DLUNKNOWN;
+
+ while(*pos == ' ') pos ++;
+
+ if(!strncmp(pos, "marray", 6))
+ {
+ token = DLMARRAY;
+ pos += 6;
+ }
+ else if(!strncmp(pos, "set", 3))
+ {
+ token = DLSET;
+ pos += 3;
+ }
+ else if(!strncmp(pos, "struct", 6))
+ {
+ token = DLSTRUCT;
+ pos += 6;
+ }
+ else if(*pos == '[')
+ {
+ token = DLLEP;
+ pos += 1;
+ }
+ else if(*pos == ']')
+ {
+ token = DLREP;
+ pos += 1;
+ }
+ else if(*pos == '<')
+ {
+ token = DLLAP;
+ pos += 1;
+ }
+ else if(*pos == '>')
+ {
+ token = DLRAP;
+ pos += 1;
+ }
+ else if(*pos == '{')
+ {
+ token = DLLCP;
+ pos += 1;
+ }
+ else if(*pos == '}')
+ {
+ token = DLRCP;
+ pos += 1;
+ }
+ else if(*pos == ',')
+ {
+ token = DLCOMMA;
+ pos += 1;
+ }
+ else if(!strncmp(pos, "octet", 5))
+ {
+ token = DLOCTET;
+ pos += 5;
+ }
+ else if(!strncmp(pos, "char", 4))
+ {
+ token = DLCHAR;
+ pos += 4;
+ }
+ else if(!strncmp(pos, "ulong", 5))
+ {
+ token = DLULONG;
+ pos += 5;
+ }
+ else if(!strncmp(pos, "long", 4))
+ {
+ token = DLLONG;
+ pos += 4;
+ }
+ else if(!strncmp(pos, "short", 5))
+ {
+ token = DLSHORT;
+ pos += 5;
+ }
+ else if(!strncmp(pos, "ushort", 6))
+ {
+ token = DLUSHORT;
+ pos += 6;
+ }
+ else if(!strncmp(pos, "float", 5))
+ {
+ token = DLFLOAT;
+ pos += 5;
+ }
+ else if(!strncmp(pos, "double", 6))
+ {
+ token = DLDOUBLE;
+ pos += 6;
+ }
+ else if(!strncmp(pos, "bool", 4))
+ {
+ token = DLBOOL;
+ pos += 4;
+ }
+ else if(!strncmp(pos, "complexd", 8))
+ {
+ token = DLCOMPLEXTYPE2;
+ pos += 8;
+ }
+ // the order of testing it's important here
+ // (complex is a proper prefix of complexd!)
+ else if(!strncmp(pos, "complex", 7))
+ {
+ token = DLCOMPLEXTYPE1;
+ pos += 7;
+ }
+ else if(!strncmp(pos, "interval", 8))
+ {
+ token = DLINTERVAL;
+ pos += 8;
+ }
+ else if(!strncmp(pos, "minterval", 9))
+ {
+ token = DLMINTERVAL;
+ pos += 9;
+ }
+ else if(!strncmp(pos, "point", 5))
+ {
+ token = DLPOINT;
+ pos += 5;
+ }
+ else if(!strncmp(pos, "oid", 3))
+ {
+ token = DLOID;
+ pos += 3;
+ }
+ else
+ {
+ token = DLIDENTIFIER; // identifier
+
+ char* beginPos = pos;
+
+ // read identifier
+ while(isalnum(*pos) || *pos == '-' || *pos == '_') pos++;
+
+ identifier = new char[pos-beginPos+1];
+ strncpy(identifier, beginPos, pos-beginPos);
+ identifier[pos-beginPos] = '\0';
+ }
+
+ while(*pos == ' ') pos ++;
+
+ return token;
+}
+
+r_Collection_Type*
+r_Type::getCollectionType(char* &pos)
+{
+ char* identifier = NULL;
+ r_Collection_Type* returnValue = NULL;
+ r_Type* elementType = NULL;
+ DLTOKEN token = DLUNKNOWN;
+
+ // get 'set'
+ getNextToken(pos, identifier);
+
+ // get '<'
+ if(getNextToken(pos, identifier) != DLLAP)
+ {
+ RMInit::logOut << "r_Type::getCollectionType(" << pos << ") expected DLLAP" << endl;
+ throw r_Error(INTERNALDLPARSEERROR);
+ }
+
+ // one token look ahead
+ char* oldPos = pos;
+ token = getNextToken(pos, identifier);
+ pos = oldPos;
+
+ switch(token)
+ {
+ case DLMARRAY:
+ elementType = getMarrayType(pos);
+ break;
+ default:
+ elementType = getType(pos);
+ }
+
+ returnValue = new r_Collection_Type(*elementType);
+ delete elementType;
+
+ return returnValue;
+}
+
+r_Type*
+r_Type::getType(char* &pos)
+{
+ DLTOKEN token = DLUNKNOWN;
+ char* identifier = 0;
+ r_Type* returnValue = 0;
+
+ // one token look ahead
+ char* oldPos = pos;
+ token = getNextToken(pos, identifier);
+ pos = oldPos;
+
+ if(token == DLSTRUCT)
+ returnValue = getStructureType(pos);
+ else if(token == DLINTERVAL)
+ returnValue = getSintervalType(pos);
+ else if(token == DLMINTERVAL)
+ returnValue = getMintervalType(pos);
+ else if(token == DLPOINT)
+ returnValue = getPointType(pos);
+ else if(token == DLOID)
+ returnValue = getOidType(pos);
+ else
+ returnValue = getPrimitiveType(pos);
+
+ return returnValue;
+}
+
+r_Marray_Type*
+r_Type::getMarrayType(char* &pos)
+{
+ char* identifier = NULL;
+ r_Marray_Type* returnValue = NULL;
+ r_Base_Type* basetype = NULL;
+
+ // get 'marray'
+ getNextToken(pos, identifier);
+ // get '<'
+ if(getNextToken(pos, identifier) != DLLAP)
+ {
+ RMInit::logOut << "r_Type::getMarrayType(" << pos << ") expected DLLAP" << endl;
+ throw r_Error(INTERNALDLPARSEERROR);
+ }
+
+ // get base type (structure or primitive type)
+ basetype = getBaseType(pos);
+
+ returnValue = new r_Marray_Type(*basetype);
+
+ delete basetype;
+
+ return returnValue;
+}
+
+r_Base_Type*
+r_Type::getBaseType(char* &pos, int offset)
+{
+ DLTOKEN token = DLUNKNOWN;
+ char* identifier = NULL;
+ r_Base_Type* returnValue = NULL;
+
+ // one token look ahead
+ char* oldPos = pos;
+ token = getNextToken(pos, identifier);
+ pos = oldPos;
+
+ if(token == DLSTRUCT)
+ returnValue = getStructureType(pos, offset);
+ else
+ returnValue = getPrimitiveType(pos);
+
+ return returnValue;
+}
+
+r_Primitive_Type*
+r_Type::getPrimitiveType(char* &pos)
+{
+ char* dummy = NULL;
+ r_Primitive_Type* returnValue = NULL;
+
+ switch(getNextToken(pos, dummy))
+ {
+ case DLCHAR:
+ returnValue = new r_Primitive_Type("Char", r_Type::CHAR);
+ break;
+ case DLOCTET:
+ returnValue = new r_Primitive_Type("Octet", r_Type::OCTET);
+ break;
+ case DLSHORT:
+ returnValue = new r_Primitive_Type("Short", r_Type::SHORT);
+ break;
+ case DLUSHORT:
+ returnValue = new r_Primitive_Type("UShort", r_Type::USHORT);
+ break;
+ case DLLONG:
+ returnValue = new r_Primitive_Type("Long", r_Type::LONG);
+ break;
+ case DLULONG:
+ returnValue = new r_Primitive_Type("ULong", r_Type::ULONG);
+ break;
+ case DLBOOL:
+ returnValue = new r_Primitive_Type("Bool", r_Type::BOOL);
+ break;
+ case DLFLOAT:
+ returnValue = new r_Primitive_Type("Float", r_Type::FLOAT);
+ break;
+ case DLDOUBLE:
+ returnValue = new r_Primitive_Type("Double", r_Type::DOUBLE);
+ break;
+ case DLCOMPLEXTYPE1:
+ returnValue = new r_Complex_Type("Complex1", r_Type::COMPLEXTYPE1);
+ break;
+ case DLCOMPLEXTYPE2:
+ returnValue = new r_Complex_Type("Complex2", r_Type::COMPLEXTYPE2);
+ break;
+ default:
+ {
+ RMInit::logOut << "r_Type::getPrimitiveType(" << pos << ") unknown token" << endl;
+ throw r_Error(INTERNALDLPARSEERROR);
+ }
+ }
+
+ return returnValue;
+}
+
+r_Structure_Type*
+r_Type::getStructureType(char* &pos, int offset)
+{
+ r_Structure_Type* returnValue = NULL;
+ char* identifier = NULL;
+ DLTOKEN token = DLUNKNOWN;
+ r_Attribute* attributes = NULL;
+ int noAttributes=0;
+
+ // get 'struct'
+ getNextToken(pos, identifier);
+
+ // get '{'
+ if(getNextToken(pos, identifier) != DLLCP)
+ {
+ RMInit::logOut << "r_Type::getStructureType(" << pos << ", " << offset << ") expected DLLCP" << endl;
+ throw r_Error(INTERNALDLPARSEERROR);
+ }
+
+ int localOffset = offset;
+
+ while(token != DLRCP)
+ {
+ // get type
+ r_Base_Type* type = getBaseType(pos, localOffset);
+
+ // adjust local offset
+ localOffset += type->size();
+
+ // get optional name
+ token = getNextToken(pos, identifier);
+
+ // allocate another attribute (very inefficient)
+ noAttributes++;
+ r_Attribute* oldAttributes = attributes;
+ attributes = new r_Attribute[noAttributes];
+ for(int i=0; i < noAttributes-1; i++)
+ attributes[i] = oldAttributes[i];
+ if(oldAttributes)
+ delete[] oldAttributes;
+ oldAttributes = NULL;
+
+ if(token == DLIDENTIFIER)
+ {
+ // with identifier
+ attributes[noAttributes-1] = r_Attribute(identifier, *type);
+ delete[] identifier;
+ identifier = NULL;
+ // read next token
+ token = getNextToken(pos, identifier);
+ }
+ else
+ {
+ // without identifier
+ attributes[noAttributes-1] = r_Attribute("", *type);
+ }
+
+ delete type;
+ type = NULL;
+
+ if(token != DLCOMMA && token != DLRCP)
+ {
+ RMInit::logOut << "r_Type::getStructureType(" << pos << ", " << offset << ") expected DLRCP or DLCOMMA" << endl;
+ throw r_Error(INTERNALDLPARSEERROR);
+ }
+ }
+
+ returnValue = new r_Structure_Type("Structure", noAttributes, attributes, offset);
+
+ if(attributes)
+ delete[] attributes;
+ attributes = NULL;
+ return returnValue;
+}
+
+r_Sinterval_Type*
+r_Type::getSintervalType(char* &pos)
+{
+ char* dummy = NULL;
+ r_Sinterval_Type* returnValue = NULL;
+
+ getNextToken(pos, dummy);
+
+ returnValue = new r_Sinterval_Type();
+
+ return returnValue;
+}
+
+r_Minterval_Type*
+r_Type::getMintervalType(char* &pos)
+{
+ char* dummy = NULL;
+ r_Minterval_Type* returnValue = NULL;
+
+ getNextToken(pos, dummy);
+
+ returnValue = new r_Minterval_Type();
+
+ return returnValue;
+}
+
+r_Point_Type*
+r_Type::getPointType(char* &pos)
+{
+ char* dummy = NULL;
+ r_Point_Type* returnValue = NULL;
+
+ getNextToken(pos, dummy);
+
+ returnValue = new r_Point_Type();
+
+ return returnValue;
+}
+
+r_Oid_Type*
+r_Type::getOidType(char* &pos)
+{
+ char* dummy = NULL;
+ r_Oid_Type* returnValue = NULL;
+
+ getNextToken(pos, dummy);
+
+ returnValue = new r_Oid_Type();
+
+ return returnValue;
+}
+
+std::ostream& operator<<( std::ostream& s, r_Type::r_Type_Id t )
+{
+ switch( t )
+ {
+ case r_Type::ULONG:
+ s << "ulong";
+ break;
+ case r_Type::USHORT:
+ s << "ushort";
+ break;
+ case r_Type::BOOL:
+ s << "bool";
+ break;
+ case r_Type::LONG:
+ s << "long";
+ break;
+ case r_Type::SHORT:
+ s << "short";
+ break;
+ case r_Type::OCTET:
+ s << "octet";
+ break;
+ case r_Type::DOUBLE:
+ s << "double";
+ break;
+ case r_Type::FLOAT:
+ s << "float";
+ break;
+ case r_Type::CHAR:
+ s << "char";
+ break;
+ case r_Type::COMPLEXTYPE1:
+ s << "complextype1";
+ break;
+ case r_Type::COMPLEXTYPE2:
+ s << "complextype2";
+ break;
+ case r_Type::STRUCTURETYPE:
+ s << "structuretype";
+ break;
+ case r_Type::MARRAYTYPE:
+ s << "marraytype";
+ break;
+ case r_Type::COLLECTIONTYPE:
+ s << "collectiontype";
+ break;
+ case r_Type::SINTERVALTYPE:
+ s << "sintervaltype";
+ break;
+ case r_Type::MINTERVALTYPE:
+ s << "mintervaltype";
+ break;
+ case r_Type::POINTTYPE:
+ s << "pointtype";
+ break;
+ case r_Type::OIDTYPE:
+ s << "oidtype";
+ break;
+ case r_Type::UNKNOWNTYPE:
+ s << "unknowntype";
+ break;
+ default:
+ s << "UNKNOWN r_Type_Id" << t;
+ break;
+ }
+
+ return s;
+}
diff --git a/raslib/type.hh b/raslib/type.hh
new file mode 100644
index 0000000..da2272c
--- /dev/null
+++ b/raslib/type.hh
@@ -0,0 +1,167 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: type.hh
+ *
+ * MODULE: raslib
+ * CLASS: r_Type
+ *
+ * COMMENTS:
+ *
+*/
+
+#ifndef _D_TYPE_
+#define _D_TYPE_
+
+#include "raslib/metaobject.hh"
+#include "raslib/mddtypes.hh"
+
+class r_Primitive_Type;
+class r_Structure_Type;
+class r_Marray_Type;
+class r_Sinterval_Type;
+class r_Minterval_Type;
+class r_Point_Type;
+class r_Oid_Type;
+class r_Base_Type;
+class r_Collection_Type;
+
+//@ManMemo: Module: {\bf raslib}
+
+/**
+ This class the superclass for all types in the ODMG conformant
+ representation of the RasDaMan type system.
+*/
+
+class r_Type : public r_Meta_Object
+{
+public:
+ /// typedef for the enum specifying a primitive type, structure type, marray type,
+ /// interval type, minterval type, point type or oid type
+ enum r_Type_Id { ULONG, USHORT, BOOL, LONG, SHORT, OCTET,
+ DOUBLE, FLOAT, CHAR, COMPLEXTYPE1, COMPLEXTYPE2,
+ STRUCTURETYPE, MARRAYTYPE, COLLECTIONTYPE,
+ SINTERVALTYPE, MINTERVALTYPE, POINTTYPE, OIDTYPE,
+ UNKNOWNTYPE };
+ /// default constructor.
+ r_Type();
+ /// constructor getting name of type.
+ r_Type( const char* newTypeName);
+ /// copy constructor
+ r_Type( const r_Type& oldObj );
+ /// assignment operator.
+ const r_Type& operator=( const r_Type& oldObj );
+ /// destructor.
+ virtual ~r_Type();
+
+ /// clone operation
+ virtual r_Type* clone() const = 0;
+
+ /// retrieve id of the type.
+ virtual r_Type::r_Type_Id type_id() const = 0;
+
+ /// check, if type is primitive or structured.
+ virtual bool isStructType() const;
+
+ /// check, if type is a base type ( primitive type or structure type).
+ virtual bool isBaseType() const;
+
+ /// check, if type is a base type ( primitive type or structure type).
+ virtual bool isComplexType() const;
+
+ /// check, if type is a marray type.
+ virtual bool isMarrayType() const;
+
+ /// check, if type is a primitive type.
+ virtual bool isPrimitiveType() const;
+
+ /// check, if type is a Sinterval
+ virtual bool isSintervalType() const;
+
+ /// check, if type is a Minterval
+ virtual bool isMintervalType() const;
+
+ /// check, if type is a Colelction type
+ virtual bool isCollectionType() const;
+
+ /// check, if type is a Point
+ virtual bool isPointType() const;
+
+ /// check, if type is a oid
+ virtual bool isOidType() const;
+
+ /// build type schema from string representation
+ static r_Type* get_any_type( const char* type_string );
+
+ /// converts array of cells from NT byte order to Unix byte order.
+ virtual void convertToLittleEndian(char* cells, r_Area noCells) const = 0;
+
+ /// converts array of cells from Unix byte order to NT byte order.
+ virtual void convertToBigEndian(char* cells, r_Area noCells) const = 0;
+
+ /// token enumeration for parser
+ enum DLTOKEN { DLMARRAY, DLSET, DLSTRUCT, DLCOMMA,
+ DLLEP, DLREP, DLLAP, DLRAP, DLLCP, DLRCP,
+ DLIDENTIFIER, DLCHAR, DLOCTET, DLSHORT, DLUSHORT,
+ DLLONG, DLULONG, DLFLOAT, DLDOUBLE, DLBOOL, DLCOMPLEXTYPE1, DLCOMPLEXTYPE2,
+ DLINTERVAL, DLMINTERVAL, DLPOINT, DLOID, DLUNKNOWN };
+
+
+private:
+
+ //@Man: Methodes and structures for dl parser:
+ //@{
+ ///
+
+ ///
+ static DLTOKEN getNextToken( char* &pos, char* &identifier );
+ ///
+ static r_Collection_Type* getCollectionType( char* &pos );
+ ///
+ static r_Type* getType( char* &pos );
+ ///
+ static r_Marray_Type* getMarrayType( char* &pos );
+ ///
+ static r_Base_Type* getBaseType( char* &pos, int offset=0 );
+ ///
+ static r_Primitive_Type* getPrimitiveType( char* &pos );
+ ///
+ static r_Structure_Type* getStructureType( char* &pos, int offset=0 );
+ ///
+ static r_Sinterval_Type* getSintervalType( char* &pos );
+ ///
+ static r_Minterval_Type* getMintervalType( char* &pos );
+ ///
+ static r_Point_Type* getPointType( char* &pos );
+ ///
+ static r_Oid_Type* getOidType( char* &pos );
+
+ ///
+ //@}
+
+
+};
+
+extern std::ostream& operator<<( std::ostream& s, r_Type::r_Type_Id t );
+
+#endif
diff --git a/rasmgr/Makefile.am b/rasmgr/Makefile.am
new file mode 100644
index 0000000..f4b54e0
--- /dev/null
+++ b/rasmgr/Makefile.am
@@ -0,0 +1,60 @@
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+# *
+# * MODULE: rasmgr
+# *
+# * COMMENTS:
+##########################################################################
+bin_PROGRAMS=rasmgr
+rasmgr_SOURCES=ras_crypto.cc rasmgr_config.cc rasmgr_host.cc rasmgr_main.cc rasmgr_rascontrol.cc rasmgr_srv.cc \
+ rasmgr_comm.cc rasmgr_dbm.cc rasmgr_master_nb.cc rasmgr_rascontrol_help.cc \
+ rasmgr_users.cc rasmgr_comm_nb.cc rasmgr_error.cc rasmgr_localsrv.cc rasmgr_random.cc \
+ hostcmp.cc \
+ ras_crypto.hh rasmgr_config.hh rasmgr_host.hh rasmgr_rascontrol.hh rasmgr_srv.hh \
+ rasmgr_comm.hh rasmgr_dbm.hh \
+ rasmgr_users.hh rasmgr_comm_nb.hh rasmgr_error.hh rasmgr_localsrv.hh \
+ rasmgr.hh rasmgr_protocol.hh rasmgr_master.hh
+rasmgr_LDADD=../network/libnetwork.a ../commline/libcommline.a
+
+SUBDIRS=../network ../commline
+
+$(RECURSIVE_CLEAN_TARGETS):
+ @$(MAKE) $(AM_MAKEFLAGS) `echo $@ | sed s/-recursive/-am/`
+
+
+
+
+#ifdef STATIC_LIBS
+# EXTRASTATICLIBS= -Xlinker -Bstatic -nodefaultlibs -lstdc++
+# EXTRADINAMICLIBS= -Xlinker -Bdynamic -lm -lgcc -lc -lgcc
+#endif
+#SRCCXX = ras_crypto.cc rasmgr_config.cc rasmgr_host.cc rasmgr_main.cc rasmgr_rascontrol.cc rasmgr_srv.cc \
+# rasmgr_comm.cc rasmgr_dbm.cc rasmgr_master_nb.cc rasmgr_rascontrol_help.cc \
+# rasmgr_users.cc rasmgr_comm_nb.cc rasmgr_error.cc rasmgr_localsrv.cc rasmgr_random.cc rasmgr_slave.cc \
+# hostcmp.cc
+
+
+#rasmgr: rasmgr_main.o rasmgr_config.o rasmgr_comm.o rasmgr_comm_nb.o rasmgr_host.o rasmgr_dbm.o rasmgr_srv.o rasmgr_random.o \
+# rasmgr_master_nb.o rasmgr_rascontrol.always rasmgr_users.o ras_crypto.o rasmgr_slave.o rasmgr_localsrv.o rasmgr_error.o hostcmp.o
+# $(PURIFY) $(CXX) $(CXXFLAGS) -o rasmgr rasmgr_main.o rasmgr_config.o rasmgr_comm.o rasmgr_comm_nb.o rasmgr_host.o rasmgr_dbm.o rasmgr_master_nb.o rasmgr_rascontrol.o rasmgr_users.o ras_crypto.o rasmgr_slave.o rasmgr_localsrv.o rasmgr_error.o rasmgr_random.o rasmgr_srv.o hostcmp.o \
+# $(LDFLAGS) $(EXTRASTATICLIBS) -lcrypto $(EXTRADINAMICLIBS) $(NETWORK) $(COMMLINE)
+
diff --git a/rasmgr/hostcmp.cc b/rasmgr/hostcmp.cc
new file mode 100644
index 0000000..1d40e82
--- /dev/null
+++ b/rasmgr/hostcmp.cc
@@ -0,0 +1,66 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: hostcmp.cc
+ *
+ * MODULE: rasmgr
+ * CLASS: none
+ *
+ * PURPOSE:
+ * special comparison function for host names (cf. man gethostname).
+ * speciality: "a.x.y"=="a"
+ *
+ * COMMENTS:
+ * none
+ *
+*/
+
+#include "debug.hh"
+#include <cstring>
+
+bool hostCmp( const char *h1, const char *h2)
+{
+ ENTER( "hostCmp( " << h1 << ", " << h2 << " )" );
+
+ bool result = false;
+
+ if ( h1 == NULL && h2 == NULL )
+ result = true;
+ else if ( h1 == NULL )
+ result = false;
+ else if ( h2 == NULL )
+ result = false;
+ else
+ {
+ if (strlen(h1)==strlen(h2))
+ result = ( strcmp(h1,h2) == 0 );
+ else if (strlen(h1)>strlen(h2))
+ result = ( strncmp(h1,h2,strlen(h2))==0 && h1[strlen(h2)]=='.' );
+ else // (strlen(h1)<strlen(h2))
+ result = ( strncmp(h1,h2,strlen(h1))==0 && h2[strlen(h1)]=='.' );
+ }
+
+ LEAVE( "Configuration::hostCmp() -> " << result );
+ return result;
+}
+
diff --git a/rasmgr/ras_crypto.cc b/rasmgr/ras_crypto.cc
new file mode 100644
index 0000000..da2e973
--- /dev/null
+++ b/rasmgr/ras_crypto.cc
@@ -0,0 +1,79 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: ras_crypto.hh
+ *
+ * MODULE: rasmgr
+ * CLASS:
+ *
+ * PURPOSE:
+ * Interface to OpenSSL MD5 - functions
+ *
+ * COMMENTS:
+ * None
+*/
+
+#include "ras_crypto.hh"
+
+#if defined(SOLARIS)
+#include <strings.h>
+#else
+#include <string.h>
+#endif
+
+
+bool testIsMessageDigestAvailable(const char *mdName)
+ {
+ EVP_MD_CTX mdctx;
+ const EVP_MD *md;
+
+ OpenSSL_add_all_digests();
+
+ md = EVP_get_digestbyname(mdName);//"MD5");
+
+ if(!md) return false;
+ return true;
+ }
+
+int messageDigest(const char *input,char *output,const char *mdName)
+ {
+ EVP_MD_CTX mdctx;
+ const EVP_MD *md;
+ unsigned int md_len, i;
+ unsigned char md_value[100];
+
+ OpenSSL_add_all_digests();
+
+ md = EVP_get_digestbyname(mdName);
+
+ if(!md) return 0;
+
+ EVP_DigestInit(&mdctx, md);
+ EVP_DigestUpdate(&mdctx,input, strlen(input));
+ EVP_DigestFinal(&mdctx, md_value, &md_len);
+
+ for(i = 0; i < md_len; i++) sprintf(output+i+i,"%02x", md_value[i]);
+
+ return strlen(output);
+ }
+
diff --git a/rasmgr/ras_crypto.hh b/rasmgr/ras_crypto.hh
new file mode 100644
index 0000000..2ab46e6
--- /dev/null
+++ b/rasmgr/ras_crypto.hh
@@ -0,0 +1,49 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: ras_crypto.hh
+ *
+ * MODULE: rasmgr
+ * CLASS:
+ *
+ * PURPOSE:
+ * Interface to OpenSSL MD5 - functions
+ *
+ * COMMENTS:
+ * None
+*/
+
+#ifndef RAS_CRYPTO_HH
+#define RAS_CRYPTO_HH
+
+#include <openssl/evp.h>
+
+// to use this functions you have to link libcrypto ( parameter -lcrypto in gcc command line)
+
+
+bool testIsMessageDigestAvailable(const char *mdName);
+
+int messageDigest(const char *input,char *output,const char *mdName);
+
+
+#endif
diff --git a/rasmgr/rasmgr.hh b/rasmgr/rasmgr.hh
new file mode 100644
index 0000000..57b77b7
--- /dev/null
+++ b/rasmgr/rasmgr.hh
@@ -0,0 +1,116 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: rasmgr.hh
+ *
+ * MODULE: rasmgr
+ * CLASS:
+ *
+ * PURPOSE:
+ * Used for including system headers and general defines
+ *
+ * COMMENTS:
+ * - Beware using VLOG in: 'if (...) VLOG...;' !
+ * do it like this: 'if (...) { VLOG...; }'
+ *
+*/
+
+#ifndef RASMGR_HH
+#define RASMGR_HH
+
+#include<iostream>
+#include<stdio.h>
+#include<errno.h>
+#include<stdlib.h>
+#include<unistd.h>
+#include<sys/types.h>
+#include<sys/socket.h>
+#include<netinet/in.h>
+#include<netdb.h>
+#include<signal.h>
+#include<sys/wait.h>
+
+#include<string.h>
+
+#ifdef AIX
+#include<strings.h>
+#include<time.h>
+#endif
+
+#include<stdlib.h>
+#include<fstream>
+#include <fcntl.h>
+#include<sys/time.h>
+
+#include <vector>
+#include <list>
+#include <iterator>
+
+#include "rasmgr_protocol.hh" // protocol keyword definitions
+
+// clear this def for production release!
+// #define TALK(a) cout<<a<<endl << flush;
+//#define TALK(a) { /* TALK (a) */ }
+
+void exitbyerror(const char* text);
+
+char *strtolwr(char*); // should be somewhere in the C-library, but can't find it
+
+#ifdef RASMGR_IHC
+ #define INCLUDE_HIDDEN_COMMANDS
+#endif
+
+// global defs -- PB 2003-jun-05
+//------------
+
+/// name of the machine where we lock into portmapper to be a Highlander:
+#define HOSTNAME "localhost"
+/// RPC program number used by rasmgr:
+#define RPCIF 0x29990000
+/// RPC version number used by rasmgr:
+#define RPCVERS 1
+
+// rasmgr return codes
+// note: these were from -3 to +2 for errors, and none for OK from W.Schatz. I ordered them to 0 for ok, <0 for errors.
+#define RASMGR_RESULT_OK 0
+#define RASMGR_RESULT_NO_MD5 1
+#define RASMGR_RESULT_ILL_ARGS 2
+#define RASMGR_RESULT_LICENSE_FAIL 3
+#define RASMGR_RESULT_NOT_ALONE 4
+#define RASMGR_RESULT_AUTH_CORRUPT 5
+#define RASMGR_RESULT_AUTH_OTHERHOST 6
+#define RASMGR_RESULT_AUTH_INCOMPAT 7
+#define RASMGR_RESULT_NO_SLAVE_IN_TEST 8
+#define RASMGR_EXIT_FAILURE 9 // was: EXIT_FAILURE from stdlib.h
+#define RASMGR_RESULT_INTERNAL 10
+
+// these should be still more global, they are part of the c/s protocol
+// indicator for server type
+#define SERVERTYPE_FLAG_RPC 'r'
+#define SERVERTYPE_FLAG_HTTP 'h'
+#define SERVERTYPE_FLAG_RNP 'n'
+
+// output depending on verbose cmd line flag
+#define VLOG if (config.isVerbose()) cout
+
+#endif // RASMGR_HH
diff --git a/rasmgr/rasmgr_comm.cc b/rasmgr/rasmgr_comm.cc
new file mode 100644
index 0000000..02fffcf
--- /dev/null
+++ b/rasmgr/rasmgr_comm.cc
@@ -0,0 +1,294 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: rasmgr_comm.cc
+ *
+ * MODULE: rasmgr
+ * CLASS: HTTPComm
+ *
+ * PURPOSE:
+ * Performs reliable, but blocking HTTP communication. used by the slave rasmgr
+ *
+ * COMMENTS:
+ * Will be removed, the plan is to have only non-blocking communication
+ *
+*/
+
+#include "rasmgr_comm.hh"
+
+#ifdef X86
+ #define r_Socklen_t socklen_t
+#endif
+
+#ifdef AIX
+ #define r_Socklen_t socklen_t
+#endif
+
+#ifdef SOLARIS
+ #define r_Socklen_t socklen_t
+#endif
+
+#ifdef DECALPHA
+ #define r_Socklen_t int
+#endif
+
+#include "debug.hh"
+
+
+HTTPComm::HTTPComm()
+ { //parentPID=getpid();
+ listen_socket=-1;
+ exitRequest=false;;
+ }
+HTTPComm::~HTTPComm()
+ {
+ ENTER("HTTPComm::~HTTPComm: enter." );
+ closeListenSocket();
+ LEAVE("HTTPComm::~HTTPComm: leave." );
+ }
+
+void HTTPComm::closeListenSocket()
+ {
+ ENTER("HTTPComm::closeListenSocket: enter." );
+
+ if(listen_socket>=0) close(listen_socket);
+
+ LEAVE("HTTPComm::closeListenSocket: leave." );
+ }
+
+int HTTPComm::sendAnswer(int socket,int len)
+ {
+ int result = 0;
+
+ ENTER("HTTPComm::sendAnswer: enter." << std::endl );
+
+ int write_count=writeWholeMessage(socket,outBuffer,len);
+
+ // adapted logic to single point of return -- PB 26-may-2003
+ if(write_count<0)
+ { TALK( "HTTPComm::sendAnswer: Error writing answer" );
+ result = -1;
+ }
+ else
+ result = 0;
+
+ LEAVE("HTTPComm::sendAnswer: leave. result=" << result );
+ return result;
+ }
+
+int HTTPComm::getMessage()
+ {
+ ENTER("HTTPComm::getMessage: enter." << std::endl );
+
+ int socket=realGetMessage();
+
+ if(socket>0)
+ {
+ header=inBuffer;
+ body=strstr(inBuffer,"\r\n\r\n");
+ if(body!=NULL)
+ {
+ *body=0;
+ body+=4;
+ }
+ else
+ { close(socket);
+ socket = -1;
+ }
+ }
+
+ LEAVE("HTTPComm::getMessage: leave. socket=" << socket );
+ return socket;
+ }
+
+
+int HTTPComm::realGetMessage()
+ {
+ struct sockaddr_in clientname;
+ r_Socklen_t size=sizeof(clientname);
+
+ ENTER("HTTPComm::getRealMessage: enter." );
+
+ int socket=accept(listen_socket,(struct sockaddr*)&clientname,&size);
+ if(socket<0)
+ { TALK( "HTTPComm::realGetMessage: Error accepting connection.");
+ socket = -1; // normalize error feedback
+ }
+
+ if (socket >= 0) // accept() worked fine, so wa can continue
+ {
+ int read_count=readWholeMessage(socket,inBuffer,MAXMSG);
+
+ if(read_count<0)
+ { TALK( "HTTPComm::realGetMessage: Error reading message."<<std::endl );
+ close(socket);
+ socket = -1;
+ }
+ }
+
+ LEAVE("HTTPComm::getRealMessage: leave. socket=" << socket );
+ return socket;
+ }
+
+int HTTPComm::initListenSocket(int port)
+ {
+ int queuesize=SOMAXCONN; // the maximim number allowed by SO!!
+
+ ENTER("HTTPComm::initListenSocket: enter. port=" << port );
+
+ FD_ZERO(&active_fd_set);
+
+ listen_socket=makeSocket(port);
+ if(listen_socket<0)
+ {
+ TALK("HTTPComm::initListenSocket: makeSocket failed, errno=" << errno );
+ exitbyerror("listen"); // it's OK to exit, we didn't start yet
+ }
+
+ if(listen(listen_socket,queuesize)<0)
+ {
+ TALK("HTTPComm::initListenSocket: listen failed, errno=" << errno );
+ exitbyerror("listen"); // it's OK to exit, we didn't start yet
+ }
+
+ FD_SET(listen_socket,&active_fd_set);
+
+ LEAVE("HTTPComm::initListenSocket: leave. socket=" << socket );
+ return 0; // no error
+
+ }
+
+int HTTPComm::makeSocket(int port)
+ {
+ int sock;
+ struct sockaddr_in name;
+ struct protoent *getprotoptr;
+
+ ENTER("HTTPComm::makeSocket: enter. port=" << port );
+
+ getprotoptr=getprotobyname("tcp");
+ sock=socket(PF_INET,SOCK_STREAM,getprotoptr->p_proto);
+ if(sock<0)
+ {
+ TALK("HTTPComm::makeSocket: socket failed. errno=" << errno );
+ exitbyerror("make socket");
+ }
+
+ name.sin_family=AF_INET;
+ name.sin_port=htons(port);
+ name.sin_addr.s_addr=htonl(INADDR_ANY);
+
+#ifdef SO_REUSEADDR
+ int val = 1;
+ int len = sizeof( val );
+ if(setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, (char*)&val, len ))
+ {
+ TALK( "HTTPComm::makeSocket: Can't set address reusable: "<< strerror(errno) );
+ }
+#endif
+
+ int sockResult = bind(sock,(sockaddr*)&name,sizeof(name));
+ TALK( "HTTPComm::makeSocket: bind() with socket=" << sock << ", name.sin_port="<< name.sin_port << " returned " << sockResult );
+ if(sockResult < 0)
+ {
+ TALK( "HTTPComm::makeSocket: bind failed: "<< strerror(errno) );
+ exitbyerror("bind");
+ // This is OK to exit, program just starts and we can't have an address
+ }
+
+ ENTER("HTTPComm::makeSocket: leave. socket=" << sock << std::endl );
+ return sock;
+ }
+
+void HTTPComm::shouldExit()
+ {
+ exitRequest=true;
+ }
+
+bool HTTPComm::isMessage(const char *messageStart)
+ {
+ ENTER("HTTPComm::isMessage: enter. messageStarte=" << messageStart );
+
+ bool rasp= (strncasecmp(header,messageStart,strlen(messageStart))==0) ? true:false;
+ if(rasp)
+ {
+ TALK("HTTPComm::isMessage: (b) Message=" << messageStart );
+ }
+
+ LEAVE("HTTPComm::isMessage: leave. result=" << rasp );
+ return rasp;
+ }
+
+//
+int readWholeMessage(int socket,char *destBuffer,int buffSize)
+ {
+ ENTER("HTTPComm::readWholeMessage: enter. socket=" << socket << ", destBuffer=" << destBuffer << ", buffSize=" << buffSize );
+
+ // we read what is comming in until we encounter a '\0'
+ // this is our end-sign.
+ int totalLength=0;
+ int redNow;
+ while(1)
+ {
+ redNow = read(socket,destBuffer+totalLength,buffSize-totalLength);
+ if(redNow == -1)
+ { if(errno == EINTR) continue; // read was interrupted by signal
+
+ TALK("HTTPComm::readWholeMessage: read error. errno=" << errno );
+ return -1; // another error
+ }
+ totalLength+=redNow;
+
+ if(destBuffer[totalLength-1]==0) break; // THE END
+ }
+
+ LEAVE("HTTPComm::readWholeMessage: leave. totalLength=" << totalLength );
+ return totalLength;
+ }
+
+int writeWholeMessage(int socket,char *destBuffer,int buffSize)
+ {
+ ENTER("HTTPComm::writeWholeMessage: enter. socket=" << socket << ", destBuffer=" << destBuffer << ", buffSize=" << buffSize );
+
+ // we write the whole message, including the ending '\0', which is already in
+ // the buffSize provided by the caller
+ int totalLength=0;
+ int writeNow;
+ while(1)
+ {
+ writeNow = write(socket,destBuffer+totalLength,buffSize-totalLength);
+ if(writeNow == -1)
+ { if(errno == EINTR) continue; // read was interrupted by signal
+
+ TALK("HTTPComm::writeWholeMessage: read error. errno=" << errno );
+ return -1; // another error
+ }
+ totalLength+=writeNow;
+
+ if( totalLength==buffSize ) break; // THE END
+ }
+
+ LEAVE("HTTPComm::writeWholeMessage: leave. totalLength=" << totalLength );
+ return totalLength;
+ }
+
diff --git a/rasmgr/rasmgr_comm.hh b/rasmgr/rasmgr_comm.hh
new file mode 100644
index 0000000..492c9c0
--- /dev/null
+++ b/rasmgr/rasmgr_comm.hh
@@ -0,0 +1,100 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: rasmgr_comm.hh
+ *
+ * MODULE: rasmgr
+ * CLASS: HTTPComm
+ *
+ * PURPOSE:
+ * Performs reliable, but blocking HTTP communication. used by the slave rasmgr
+ *
+ * COMMENTS:
+ * Will be removed, the plan is to have only non-blocking communication
+ *
+*/
+
+#ifndef RASMGR_COMM_HH
+#define RASMGR_COMM_HH
+
+#include "rasmgr.hh"
+
+#define MAXMSG 1024
+#define MAXMSGOUTBUFF 20000
+
+
+class HTTPComm
+ {
+ public:
+ HTTPComm();
+ ~HTTPComm();
+ void closeListenSocket();
+ void shouldExit();
+ char *decodeFlag(int statusFlag);
+ protected:
+ int initListenSocket(int port);
+ int makeSocket(int port);
+ int sendAnswer(int socket,int len);
+ int getMessage();
+
+ protected:
+ bool isMessage(const char *messageStart);
+ // pid_t parentPID;
+ int listen_socket;
+ fd_set active_fd_set,read_fd_set;
+
+ struct timeval tv;
+ timeval *tvptr;
+ char *header;
+ char *body;
+ char inBuffer[MAXMSG];
+ char outBuffer[MAXMSGOUTBUFF];
+
+ bool exitRequest;
+ private:
+ int realGetMessage();
+ };
+
+// status flags that rasmgr understands
+// - these come from rasserver
+#define SERVER_DOWN 0
+#define SERVER_AVAILABLE 1
+#define SERVER_REGULARSIG 3
+// - this comes from slave rasmgr and LSM
+#define SERVER_CRASHED 2
+
+// textual representation of the above status flags -- PB 2004-jul-16
+#define SERVER_DOWN_TXT "server down"
+#define SERVER_AVAILABLE_TXT "server available"
+#define SERVER_REGULARSIG_TXT "server alive"
+#define SERVER_CRASHED_TXT "server aborted"
+
+
+ /* This two functions where written late in the night, when we came back from BLVA
+ (Bayerisches Landesvermessungsamt), where we had problems on DEC+CompaqTrue64
+ this &@$! operating system wasn't able to send a message in one piece which was written in one piece
+ */
+int readWholeMessage(int socket,char *destBuffer,int buffSize);
+int writeWholeMessage(int socket,char *destBuffer,int buffSize);
+
+#endif
diff --git a/rasmgr/rasmgr_comm_nb.cc b/rasmgr/rasmgr_comm_nb.cc
new file mode 100644
index 0000000..65b913b
--- /dev/null
+++ b/rasmgr/rasmgr_comm_nb.cc
@@ -0,0 +1,921 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: rasmgr_comm_nb.cc
+ *
+ * MODULE: rasmgr
+ * CLASS: IOSelector, NbJob, NbServerComm
+ *
+ * PURPOSE:
+ * Performs reliable, non-blocking HTTP communication. used by the master rasmgr
+ * Hierarchy: NbServerComm uses NbJob uses IOSelector
+ * IOSelector maintains a set of read and write file descriptors (ie, sockets)
+ * plus a timeout value common to all of them.
+ * NbJob maintains message streams allowing partial (piecewise) read/write.
+ * NbServerComm bundles all this, abstracting from the particular socket used.
+ *
+ * COMMENTS:
+ * none
+ *
+*/
+
+#include <time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "rasmgr_comm_nb.hh"
+
+#include "debug.hh"
+
+/*************************************************************************
+ *
+ * CLASS: IOSelector
+ *
+ * PURPOSE:
+ * IOSelector maintains a set of read and write file descriptors to be watched
+ * plus a timeout value common to all of them.
+ * ATTENTION: This class does not really care about socket status!
+ * Exceptions:
+ * - waitForRequest() performs blocking wait (w timeout) for incoming request on the sets.
+ * - closeForcedAllSockets() closes all open sockets in the read and write set (should go to NbJob where bind() etc is performed)
+ *
+ * CHANGE HISTORY (append further entries): [see module header]
+ *
+ * COMMENTS:
+ * - this class is (almost) internal to NbJob
+ * - when adding sockets there is no check for valid socket, duplicate insertion, etc
+ * - when clearing a socket from a set, there is no check whether it was really in there
+ *
+ ***********************************************************************/
+
+IOSelector::IOSelector()
+{
+ ENTER( "IOSelector::IOSelector: enter." );
+ FD_ZERO(& watchReadFdSet);
+ FD_ZERO(& watchWriteFdSet);
+ FD_ZERO(& watchExceptFdSet);
+ tvptr = NULL;
+ LEAVE( "IOSelector::IOSelector: leave." );
+}
+
+void IOSelector::setTimeout(int sec,int millisec)
+{
+ ENTER( "IOSelector::setTimeout: enter. timeout=" << sec << "." << millisec << " secs." );
+ tvinit.tv_sec=sec;
+ tvinit.tv_usec=millisec * 1000;
+ tvptr=&tv; // yes, yes, &tv
+ LEAVE( "IOSelector::setTimeout: leave." );
+}
+
+void IOSelector::disableTimeout()
+{
+ ENTER( "IOSelector::disableTimeout: enter." );
+ tvptr=NULL;
+ LEAVE( "IOSelector::disableTimeout: leave." );
+}
+
+// add socket to the socket set watched for incoming requests
+void IOSelector::setReadSocket(int socket)
+{
+ ENTER( "IOSelector::setReadSocket: enter. add to watchReadSet: " << socket );
+ FD_SET(socket,&watchReadFdSet);
+ LEAVE( "IOSelector::setReadSocket: leave." );
+}
+
+// remove socket from read socket set
+void IOSelector::clearReadSocket(int socket)
+{
+ ENTER( "IOSelector::clearReadSocket: enter. remove from watchReadSet: " << socket );
+ FD_CLR(socket,&watchReadFdSet);
+ LEAVE( "IOSelector::clearReadSocket: leave." );
+}
+
+// add socket to the socket set watched for outgoing requests
+void IOSelector::setWriteSocket(int socket)
+{
+ ENTER( "IOSelector::setWriteSocket: enter. add to watchWriteSet: " << socket );
+ FD_SET(socket,&watchWriteFdSet);
+ LEAVE( "IOSelector::setWriteSocket: leave." );
+}
+
+// remove socket from write socket set
+void IOSelector::clearWriteSocket(int socket)
+{
+ ENTER( "IOSelector::clearWriteSocket: enter. remove from watchWriteSet: " << socket );
+ FD_CLR(socket,&watchWriteFdSet);
+ LEAVE( "IOSelector::clearWriteSocket: leave." );
+}
+
+// result = outcome of select() request:
+// > 0: number of active sockets
+// ==0: timeout
+// < 0: error
+// preconditions:
+// - read set, write set contains valid sockets
+// - bind() on each socket in the read and write set
+
+int IOSelector::waitForRequest()
+{
+ int result;
+
+ ENTER( "IOSelector::waitForRequest: enter." );
+
+ resultReadFdSet =watchReadFdSet;
+ resultWriteFdSet=watchWriteFdSet;
+ // error unused
+ // tv has to be reloaded every time; if tvptr is NULL it doesn't matter
+ tv.tv_sec = tvinit.tv_sec;
+ tv.tv_usec = tvinit.tv_usec;
+ TALK( "IOSelector::waitForRequest: timeout=" << tv.tv_sec << "sec " << tv.tv_usec << "microsec." );
+
+ result = select(FD_SETSIZE,&resultReadFdSet,&resultWriteFdSet,NULL,tvptr);
+ if (result < 0)
+ {
+ TALK( "IOSelector::waitForRequest: select error: " << strerror(errno) );
+ }
+ else // if ( result == 0)
+ {
+ TALK( "IOSelector::waitForRequest: select() successful, result=" << result );
+ }
+
+#if 0 // unsuccessful try
+ else // (result > 0)
+ {
+ TALK( "IOSelector::waitForRequest: select() successful, returned " << result );
+ int isPending = 0;
+ for (int i=0; i<FD_SETSIZE && isPending==0; i++)
+ { // unfortunately, FD_ISSET() cannot be deployed within an if()
+ isPending = (int) FD_ISSET( i, &resultReadFdSet );
+ if ( isPending )
+ {
+ TALK( "IOSelector::waitForRequest: input pending on socket " << i );
+ result = i; // report this socket
+ }
+ isPending = (int) FD_ISSET( i, &resultWriteFdSet );
+ if ( isPending )
+ {
+ TALK( "IOSelector::waitForRequest: output pending on socket " << i );
+ result = i; // report this socket
+ }
+ }
+ }
+#endif // 0
+
+ LEAVE( "IOSelector::waitForRequest: leave. result=" << result );
+ return result;
+}
+
+// look into sockets if there is something pending
+// precondition: a select() call has been made soon before (ie, socket state hasn't changed inbetween)
+// returns:
+// pending socket if found
+// 0 otherwise
+// cycles through all FDs, read and write interleaved
+int IOSelector::someWaitingSocket()
+{
+ static int lastVisited = 0; // last inspecrted socket from last call, allows to run round robin strategy
+ int waitingSocket = 0; // some socket waiting to be treated
+ bool found = false; // result of FD_ISSET() call
+
+ ENTER( "IOSelector::someWaitingSocket: enter. lastVisited=" << lastVisited );
+
+ for ( int i=0; i<FD_SETSIZE && waitingSocket==0; i++ ) // walk through max all possible FDs
+ {
+ lastVisited = (lastVisited == FD_SETSIZE) ? 0 : lastVisited+1;
+ found = ( (int) FD_ISSET( lastVisited, &resultReadFdSet )
+ + (int) FD_ISSET( lastVisited, &resultWriteFdSet ) ) > 0 ? true : false;
+ if ( found ) // cannot use FD_ISSET in if()
+ waitingSocket = lastVisited;
+ }
+
+ LEAVE( "IOSelector::someWaitingSocket: leave. waitingSocket=" << waitingSocket );
+}
+
+bool IOSelector::isReadSocket(int socket)
+{
+ bool result = (socket < 0) ? false: true;
+ if (result == true)
+ result = FD_ISSET(socket,&resultReadFdSet);
+ return result;
+}
+
+bool IOSelector::isWriteSocket(int socket)
+{
+ bool result = (socket < 0) ? false: true;
+ if (result == true)
+ result = FD_ISSET(socket,&resultWriteFdSet);
+ return result;
+}
+
+void IOSelector::closeForcedAllSockets()
+{
+ ENTER( "IOSelector::closeForcedAllSockets: enter." );
+ for(int i=0;i<FD_SETSIZE;i++)
+ {
+ if(FD_ISSET(i,&watchReadFdSet) || FD_ISSET(i,&watchWriteFdSet))
+ {
+ TALK( "IOSelector::closeForcedAllSockets: closing " << i );
+ int result = close(i);
+ if (result < 0)
+ {
+ TALK( "IOSelector::closeListenSocket: error closing socket: " << strerror(errno) );
+ }
+ }
+ }
+ LEAVE( "IOSelector::closeForcedAllSockets: leave." );
+}
+
+
+// end of class IOSelector ###############################################
+
+/*************************************************************************
+ *
+ * CLASS: NbJob
+ *
+ * PURPOSE:
+ * NbJob maintains a message stream (socket) allowing partial (piecewise) read/write.
+ * Keeps an IOSelector instance for watching.
+ * Outbound messages need a NULL terminator; existence can be checked with isMessageOK().
+ *
+ * CHANGE HISTORY (append further entries): [see module header]
+ *
+ * COMMENTS:
+ * - sockets must be managed elsewhere: open/select/bind/listen/close
+ *
+ ***********************************************************************/
+
+// now declared private in .hh
+time_t NbJob::timeOutInterv = 30;
+time_t NbJob::currentTime = 0;
+
+NbJob::NbJob()
+{
+ ENTER( "NbJob::NbJob: enter." );
+ socket = -1;
+ lastActionTime=0;
+ outputBuffer = 0;
+ inputBuffer = 0;
+ bigError = false;
+ LEAVE( "NbJob::NbJob: leave." );
+}
+
+void NbJob::init(IOSelector *pselector,int maxInputBuffer)
+{
+ ENTER( "NbJob::init: enter. maxInputBuffer=" << maxInputBuffer );
+ this->pselector = pselector;
+ this->maxInputLength = maxInputBuffer;
+ messageTerminator = '\0';
+ LEAVE( "NbJob::init: leave." );
+}
+
+// dropped (being redundant) in favour of closeConnection() -- PB 2003-jun-04
+#ifdef NEVER_AGAIN
+void NbJob::reset()
+{
+ ENTER( "NbJob::reset: enter." );
+ clearConnection();
+ clearInputBuffer();
+ clearOutputBuffer();
+ LEAVE( "NbJob::reset: leave." );
+}
+#endif
+
+void NbJob::clearInputBuffer()
+{
+ ENTER( "NbJob::clearInputBuffer: enter." );
+ if(inputBuffer)
+ delete[] inputBuffer;
+ inputBuffer = 0;
+ nextReadPos = 0;
+ LEAVE( "NbJob::clearInputBuffer: leave." );
+}
+
+void NbJob::clearOutputBuffer()
+{
+ ENTER( "NbJob::clearOutputBuffer: enter." );
+ if(outputBuffer)
+ delete[] outputBuffer;
+ outputBuffer = 0;
+ nextWritePos = 0;
+ LEAVE( "NbJob::clearOutputBuffer: leave." );
+}
+
+// clear connection completely, close socket
+void NbJob::clearConnection()
+{
+ ENTER( "NbJob::clearConnection: enter." );
+ if(socket > 0)
+ {
+ pselector->clearReadSocket(socket);
+ pselector->clearWriteSocket(socket);
+ int result = close(socket);
+ int tempErrno = errno;
+ TALK( "NbJob::clearConnection: close() on socket " << socket << " returned " << result );
+ if (result != 0)
+ {
+ TALK( "NbJob::clearConnection: error closing socket: " << strerror(tempErrno) );
+ }
+ socket = -1;
+ bigError = false;
+ }
+ LEAVE( "NbJob::clearConnection: leave." );
+}
+
+// returns true if the current job is too old
+bool NbJob::processJobTimeout()
+{
+ bool result = (messageReadyTime + timeOutInterv > currentTime) ? false:true;
+ TALK( "NbJob::processJobTimeout: result=" << result );
+ return result;
+}
+
+// on timeout, reset all buffers but don't close socket
+bool NbJob::cleanUpIfTimeout()
+{
+ ENTER( "NbJob::cleanUpIfTimeout: enter." );
+
+ bool result = (socket < 0 ) || (lastActionTime + timeOutInterv > currentTime) ? false : true;
+
+ if (result==true)
+ {
+ TALK("NbJob::cleanUpIfTimeout: client timeout on socket " << socket);
+ closeConnection();
+ }
+
+ LEAVE( "NbJob::cleanUpIfTimeout: leave. result=" << result );
+ return result;
+}
+
+// reset all that's necessary, then do an accept() to wait [timeout] for incoming calls
+// upon success, set socket to the descriptor returned by accept()
+// preconditions:
+// - socket initialised with bind() etc.
+// Note: accept() works like an "open" in that it creates a separate socket which must be closed explicitly!
+
+NbJob::acceptStatus NbJob::acceptConnection(int listenSocket)
+{
+ ENTER( "NbJob::acceptConnection: enter. listenSocket=" << listenSocket );
+
+ if(socket>0)
+ {
+ bool result = cleanUpIfTimeout();
+ if(result == false)
+ {
+ LEAVE("NbJob::acceptConnection: leave. cleanUpIfIimeout() returned: no timeout yet.");
+ return acs_Iambusy;
+ // free again
+ }
+ }
+
+ markAction();
+
+ clearInputBuffer();
+ inputBuffer = new char[maxInputLength];
+ if(inputBuffer == NULL)
+ {
+ LEAVE("NbJob::acceptConnection: leave. out of memory.");
+ return acs_outofmem;
+ }
+
+ struct sockaddr_in internetAddress;
+ r_Socklen_t size=sizeof(sockaddr_in);
+
+ // extract the first pending request from the socket queue
+ // NB: accept() clones the socket.
+ errno = 0;
+
+// replace accept() code with a simple FD_ISSET() search
+#ifndef NEVER_AGAIN
+ // accept() here serves to clone the socket.
+ // there shouldn't be any wait because of the select() call just passed via waitForRequest()
+ socket=accept(listenSocket,(struct sockaddr*)&internetAddress,&size);
+ int saveerrno=errno;
+ TALK("NbJob::acceptConnection: accept() with socket " << listenSocket << " returned " << socket << ", sin_port=" << htons(internetAddress.sin_port) << ", requestor=" << inet_ntoa(internetAddress.sin_addr) );
+ if(socket<0)
+ {
+ if(saveerrno==EAGAIN)
+ {
+ LEAVE("NbJob::acceptConnection: leave. no pending connections");
+ }
+ else
+ {
+ LEAVE("NbJob::acceptConnection: leave. accept error " << strerror(saveerrno) );
+ }
+ return acs_nopending;
+ }
+
+ // several flags, such as non-blocking, are not inherited accross accept() - see manual
+ int val = fcntl(socket,F_GETFL,0);
+ val |= O_NONBLOCK;
+ fcntl(socket,F_SETFL,val);
+
+ pselector->setReadSocket(socket);
+
+#else // !NEVER_AGAIN -- but currently inactive.
+
+ // int activeSocket = pselector->someWaitingSocket();
+ // basically we should always have at least one pending request because a select() came before
+ if (activeSocket == 0)
+ {
+ TALK( "NbJob::acceptConnection: found NO active socket." );
+ }
+ else
+ {
+ TALK( "NbJob::acceptConnection: found active socket " << activeSocket );
+ }
+
+# endif // NEVER_AGAIN
+
+ LEAVE( "NbJob::acceptConnection: leave. acs_accepted, cloned socket is " << socket);
+ return acs_accepted;
+} // acceptConnection()
+
+// this method got the body of reset() which (being redundant) has been dropped -- PB 2003-jun-04
+void NbJob::closeConnection()
+{
+ ENTER( "NbJob::closeConnection: enter." );
+ clearConnection();
+ clearInputBuffer();
+ clearOutputBuffer();
+ LEAVE( "NbJob::closeConnection: leave." );
+}
+
+// PB 2003-may-29: to fix bug that connections cloned by accept() remain open, so the number grows infinitely
+// ...but this doesn't work yet, don't use it...
+void NbJob::closeSocket()
+{
+ ENTER( "NbJob::closeSocket: enter. socket=" << socket );
+ int result = close(socket);
+ if (result != 0)
+ {
+ TALK( "NbJob::closeSocket: error closing socket: " << strerror(errno) );
+ }
+ socket = -1;
+ LEAVE( "NbJob::closeSocket: leave." );
+}
+
+void NbJob::markAction()
+{
+ lastActionTime=currentTime;
+}
+
+int NbJob::getSocket()
+{
+ return socket;
+}
+
+bool NbJob::isMessageOK()
+{
+ return (nextReadPos > 1 && inputBuffer[nextReadPos - 1] == messageTerminator) ? true:false;
+}
+
+bool NbJob::wasError()
+{
+ return bigError;
+}
+
+// read from socket into input buffer as much as fits in or until NULL terminator
+// returns true iff some bytes could be written
+bool NbJob::readPartialMessage()
+{
+ bool messOK;
+
+ ENTER("NbJob::readPartialMessage: enter." );
+ markAction();
+ errno = 0;
+ int nbytes = read(socket,inputBuffer + nextReadPos,maxInputLength - nextReadPos);
+ TALK("NbJob::readPartialMessage: read() with socket=" << socket << " returned " << nbytes );
+
+ if(nbytes) // wrote some bytes
+ {
+ TALK( "NbJob::readPartialMessage: read socket("<<socket<<") "<<nbytes<<" bytes to pos="<<nextReadPos);
+ nextReadPos += nbytes;
+ inputBuffer[nextReadPos] = 0;
+ messOK = isMessageOK();
+
+ if(messOK)
+ {
+ TALK("NbJob::readPartialMessage: socket read completed on " << socket );
+ messageReadyTime = currentTime;
+ }
+ }
+ else // nothing written = error
+ {
+ int saveerrno=errno;
+ switch(saveerrno)
+ {
+ case EINTR:
+ TALK("NbJob::readPartialMessage: read: EINTR, retry please");
+ break;
+
+ case EAGAIN:
+ TALK("NbJob::readPartialMessage: read: EAGAIN, retry please");
+ break;
+
+ case 0:
+ TALK("NbJob::readPartialMessage: read: Premature End-of-file");
+ bigError=true;
+ break;
+
+ default:
+ TALK("NbJob::readPartialMessage: read: error " << saveerrno );
+ bigError = true;
+ break;
+ }
+ messOK = false;
+ }
+
+ LEAVE("NbJob::readPartialMessage: leave. read completed=" << messOK );
+ return messOK;
+} // readPartialMessage()
+
+const char* NbJob::getMessage()
+{
+ return inputBuffer;
+}
+
+// initialise answer sending, copy complete message in local buffer
+// set socket to write mode
+bool NbJob::initSendAnswer(const char *message)
+{
+ ENTER("NbJob::initSendAnswer: enter. message=" << message );
+ bool result = true;
+
+ markAction();
+ clearInputBuffer();
+ answerLength = strlen(message)+1;
+ outputBuffer = new char[answerLength];
+ if (outputBuffer == NULL)
+ {
+ TALK( "NbJob::initSendAnswer: error: out of memory." );
+ result = false;
+ // FIXME: close socket?
+ }
+
+ if (result == true)
+ {
+ strcpy(outputBuffer,message);
+ nextWritePos = 0;
+
+ pselector->setWriteSocket(socket);
+ pselector->clearReadSocket(socket); // sa fie
+ }
+
+ LEAVE("NbJob::initSendAnswer: leave. result=" << result );
+ return result;
+}
+
+// write current contents of output buffer to socket
+// result == true iff writing went fine
+bool NbJob::writePartialMessage()
+{
+ bool result = false;
+
+ ENTER("NbJob::writePartialMessage: enter." );
+
+ markAction();
+ errno = 0;
+ int nbytes = write(socket,outputBuffer + nextWritePos,answerLength - nextWritePos);
+ TALK("NbJob::writePartialMessage: write() with socket=" << socket << " returned " << nbytes );
+
+ if(nbytes)
+ {
+ TALK("NbJob::writePartialMessage: write to socket=" << socket << ", " << nbytes << " bytes to pos=" << nextWritePos << ", answerLength=" << answerLength );
+ nextWritePos += nbytes;
+
+ if(nextWritePos == answerLength) // everything written?
+ {
+ TALK("NbJob::writePartialMessage: write completed.");
+ // closeConnection(); // was here, now shifted up the hierarchy -- PB 2003-jun-10
+ result = true;
+ }
+ }
+ else
+ {
+ int saveerrno=errno;
+ switch(saveerrno)
+ {
+ case EINTR:
+ TALK("NbJob::writePartialMessage: EINTR, retry please");
+ break;
+
+ case EAGAIN:
+ TALK("NbJob::writePartialMessage: EAGAIN, retry please");
+ break;
+
+ case 0:
+ TALK("NbJob::writePartialMessage: premature client hang up.");
+ bigError=true;
+ break;
+
+ default:
+ TALK("NbJob::writePartialMessage: error "<< strerror(saveerrno) );
+ bigError = true;
+ break;
+ }
+ }
+ LEAVE("NbJob::writePartialMessage: leave. result=" << result );
+ return result;
+}
+
+// is socket still open? (actually; wrong name)
+bool NbJob::isOperationPending()
+{
+ bool result = socket > 0 ? true:false;
+ TALK("NbJob::isOperationPending (i.e.: socket open) -> " << result );
+ return result;
+}
+
+void NbJob::printStatus()
+{
+ TALK( "NbJob::printStatus: socket=" << socket << ", isRead=" << (int) pselector->isReadSocket(socket) << ", isWrite=" << (int) pselector->isWriteSocket(socket) );
+}
+
+//################################################################################################
+
+NbServerComm::NbServerComm()
+{
+ listenSocket = -1;
+ maxJobs = 0;
+ job = 0;
+ mypid = getpid();
+}
+
+void NbServerComm::initJobs(int maxJobs)
+{
+ ENTER( "NbServerComm::initJobs: enter. maxJobs=" << maxJobs );
+
+ this->maxJobs = maxJobs;
+ job = new NbJob[maxJobs];
+
+ for(int i=0;i<maxJobs;i++)
+ {
+ job[i].init(&selector,MAXMSG);
+ }
+
+ LEAVE( "NbServerComm::initJobs: leave." );
+}
+
+NbServerComm::~NbServerComm()
+{
+ ENTER( "NbServerComm::~NbServerComm: enter." );
+ closeListenSocket();
+ LEAVE( "NbServerComm::~NbServerComm: leave." );
+}
+
+// opens the central listen socket
+bool NbServerComm::initListenSocket(int listenPort)
+{
+ ENTER( "NbServerComm::initListenSocket: enter. listenPort=" << listenPort );
+
+ struct protoent *getprotoptr = getprotobyname("tcp");
+
+ struct sockaddr_in name;
+ name.sin_family=AF_INET;
+ name.sin_port=htons(listenPort); // translate listen port#
+ name.sin_addr.s_addr=htonl(INADDR_ANY);
+
+ listenSocket=socket(PF_INET,SOCK_STREAM,getprotoptr->p_proto);
+ if(listenSocket < 0)
+ {
+ TALK( "NbServerComm::initListenSocket: socket error: " << strerror(errno) );
+ exitbyerror("socket");
+ }
+
+ // make the socket nonblocking
+ int val =fcntl(listenSocket,F_GETFL,0);
+ val|=O_NONBLOCK;
+ fcntl(listenSocket,F_SETFL,val);
+
+ val =fcntl(listenSocket,F_GETFL,0);
+ if(val & O_NONBLOCK)
+ TALK("NbServerComm::initListenSocket: socket " << listenSocket << " is nonblocking" );
+
+#ifdef SO_REUSEADDR
+ val = 1;
+ int len = sizeof( val );
+ if(setsockopt( listenSocket, SOL_SOCKET, SO_REUSEADDR, (char*)&val, len ))
+ {
+ TALK( "NbServerComm::initListenSocket: cannot set address reusable using setsockopt: " << strerror(errno) );
+ }
+#endif
+
+ int sockResult = bind(listenSocket,(sockaddr*)&name,sizeof(name));
+ TALK( "NbServerComm::initListenSocket: bind() with socket=" << listenSocket << ", name.port=" << name.sin_port << " returned " << sockResult );
+ if (sockResult < 0)
+ {
+ TALK( "NbServerComm::initListenSocket: cannot set address reusable using bind: " << strerror(errno) );
+ exitbyerror("bind");
+ }
+
+ int queuesize=SOMAXCONN; // the maximum number allowed by SO!!
+ sockResult = listen(listenSocket,queuesize);
+ TALK("NbServerComm::initListenSocket: listen() with socket=" << listenSocket << ", queuesize=" << queuesize << " returned " << sockResult );
+ if(sockResult < 0)
+ {
+ TALK( "NbServerComm::initListenSocket: listen error: " << strerror(errno) );
+ exitbyerror("listen");
+ }
+
+ selector.setReadSocket(listenSocket); // add this socket to the read watch list
+
+ LEAVE( "NbServerComm::initListenSocket: leave." );
+ return true;
+}
+
+void NbServerComm::closeListenSocket()
+{
+ ENTER( "NbServerComm::closeListenSocket: enter." );
+ if(listenSocket>0)
+ {
+ selector.clearReadSocket(listenSocket);
+ TALK( "NbServerComm::closeListenSocket: closing socket " << listenSocket );
+ int result = close(listenSocket);
+ if (result < 0)
+ {
+ TALK( "NbServerComm::closeListenSocket: error closing socket: " << strerror(errno) );
+ }
+ listenSocket = -1;
+ }
+ LEAVE( "NbServerComm::closeListenSocket: leave." );
+}
+
+void NbServerComm::shouldExit()
+{
+ ENTER( "NbServerComm::shouldExit: enter." );
+ exitRequest=true;
+ LEAVE( "NbServerComm::shouldExit: leave." );
+}
+
+bool NbServerComm::mayExit()
+{
+ ENTER( "NbServerComm::mayExit: enter." );
+ bool result = true;
+
+ if(exitRequest==false)
+ result = false;
+ else
+ {
+ closeListenSocket(); // we don't accept requests any more
+
+ for(int i=0;i<maxJobs && (result==true);i++)
+ {
+ if(job[i].isOperationPending())
+ result = false; // no, we have pending operations, don't close
+ }
+ }
+
+ LEAVE( "NbServerComm::mayExit: leave. result=" << result );
+ return result;
+}
+
+void NbServerComm::lookForTimeout()
+{
+ ENTER( "NbServerComm::lookForTimeout: enter." );
+ for(int i=0;i<maxJobs;i++)
+ {
+ job[i].cleanUpIfTimeout();
+ }
+ LEAVE( "NbServerComm::lookForTimeout: leave." );
+}
+
+// look through all write jobs and write out pending message
+void NbServerComm::dispatchWriteRequest()
+{
+ ENTER( "NbServerComm::dispatchWriteRequest: enter." );
+
+ int i;
+ for(i=0;i<maxJobs;i++)
+ {
+ int socket=job[i].getSocket();
+ if(socket>0) // active job pending?
+ {
+ if(selector.isWriteSocket(socket))
+ {
+ TALK( "flushing write job " << i << ", socket " << socket );
+ bool result = job[i].writePartialMessage();
+ if (result == true)
+ {
+ TALK( "job done, closing connection " << i << ", socket " << socket );
+ job[i].closeConnection(); // was in writePartialMessage() -- PB 2003-jun-10
+ }
+ else
+ {
+ TALK( "connection " << i << "write error, socket " << socket );
+ }
+ }
+ else
+ {
+ TALK( "job " << i << ": socket not writable, nothing to do." );
+ }
+ }
+ } // for
+
+ LEAVE( "NbServerComm::dispatchWriteRequest: leave." );
+}
+
+// look through all read jobs and load msg buffers
+// NB: as opposed to write, here is no closeSocket! why??
+void NbServerComm::dispatchReadRequest()
+{
+ ENTER( "NbServerComm::dispatchReadRequest: enter." );
+
+ int i;
+ for(i=0;i<maxJobs;i++)
+ {
+ int socket=job[i].getSocket();
+ if(socket>0)
+ {
+ if(selector.isReadSocket(socket))
+ {
+ TALK( "NbServerComm::dispatchReadRequest: flush reading job " << i << ", socket " << socket << " -- NO CLOSE!?!" );
+ // result code was not queried, added it -- PB 2004-jul-16
+ bool allOk = job[i].readPartialMessage();
+ if (allOk)
+ {
+ TALK( "connection " << i << " done reading, socket " << socket );
+ // no close here, connection used for writing afterwards
+ }
+ else // could not read
+ {
+ TALK( "connection " << i << " read error, socket " << socket );
+ }
+ }
+ }
+ } // for
+
+ LEAVE( "NbServerComm::dispatchReadRequest: leave." );
+}
+
+void NbServerComm::connectNewClients()
+{
+ ENTER( "NbServerComm::connectNewClients: enter." );
+
+ // why only for read sockets? because we process _incoming_ requests
+ if(selector.isReadSocket(listenSocket))
+ {
+ for(int i=0;i<maxJobs;i++)
+ {
+ // we try to connect as many pending connections as possible
+
+ TALK( "NbServerComm::connectNewClients: trying to open #" << i << " of " << maxJobs << " sockets (initially: read)." );
+ // the accept() call inside this below will clone the socket, so we get many read sockets
+ NbJob::acceptStatus status = job[i].acceptConnection(listenSocket);
+
+ if(status == NbJob::acs_nopending || status == NbJob::acs_outofmem)
+ {
+ TALK( "NbServerComm::connectNewClients: aborting, bad status:" << status );
+ break;
+ // first, because there is no pending request, second, because out of mem is not solved by retry
+ }
+ } // for
+ }
+ else
+ {
+ TALK( "NbServerComm::connectNewClients: master socket is no read socket: " << listenSocket );
+ }
+
+ LEAVE( "NbServerComm::connectNewClients: leave." );
+}
+
+void NbServerComm::closeForcedAllSockets()
+{
+ ENTER( "NbServerComm::closeForcedAllSockets: enter." );
+ if(mypid != getpid())
+ selector.closeForcedAllSockets();
+ LEAVE( "NbServerComm::closeForcedAllSockets: leave." );
+}
+
+void NbServerComm::printStatus()
+{
+ int i;
+ for(i=0;i<maxJobs;i++)
+ {
+ TALK( "NbServerComm::printStatus: connection #" << i << ":" );
+ job[i].printStatus();
+ }
+ return;
+}
+
+//#######################################################
diff --git a/rasmgr/rasmgr_comm_nb.hh b/rasmgr/rasmgr_comm_nb.hh
new file mode 100644
index 0000000..c6d724c
--- /dev/null
+++ b/rasmgr/rasmgr_comm_nb.hh
@@ -0,0 +1,196 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: rasmgr_comm_nb.hh
+ *
+ * MODULE: rasmgr
+ * CLASS: <many>
+ *
+ * PURPOSE:
+ * Performs reliable, non-blocking HTTP communication. used by the master rasmgr
+ *
+ * COMMENTS:
+ * none
+ *
+*/
+#ifndef RASMGR_COMM_NB_HH
+#define RASMGR_COMM_NB_HH
+
+#include "rasmgr_comm.hh"
+
+// this is the NON-BLOCKING version, which will replace the other one
+
+// maximum number of slaves a master mgr can handle
+// #define MAXJOBSMASTER 50
+#define MAXJOBSMASTER 1
+
+
+class IOSelector
+ {
+ public:
+ IOSelector();
+ void setTimeout(int sec,int milisec);
+ void disableTimeout();
+ void setReadSocket(int socket);
+ void clearReadSocket(int socket);
+ void setWriteSocket(int socket);
+ void clearWriteSocket(int socket);
+
+ int waitForRequest();
+ int someWaitingSocket();
+
+ bool isReadSocket(int socket);
+ bool isWriteSocket(int socket);
+
+ void closeForcedAllSockets(); // useful for childs which don't have to inherit this sockets
+ private:
+ fd_set watchReadFdSet;
+ fd_set watchWriteFdSet;
+ fd_set watchExceptFdSet; // unused but ...
+
+ fd_set resultReadFdSet;
+ fd_set resultWriteFdSet;
+ fd_set resultExceptFdSet; // unused but ...
+
+ struct timeval tvinit;
+ struct timeval tv;
+ timeval *tvptr; // set to &tv... for timeout, NULL for no timeout
+
+ };
+
+class NbJob
+ {
+ public:
+ NbJob();
+ void init(IOSelector *pselector,int maxInputBuffer);
+
+ enum acceptStatus
+ { acs_nopending = 0,
+ acs_Iambusy = 1,
+ acs_accepted = 2,
+ acs_outofmem = 3,
+ acs_invalidsocket = 4
+ };
+ acceptStatus acceptConnection(int listenSocket);
+
+ bool readPartialMessage();
+ bool isMessageOK();
+ const char *getMessage();
+
+ bool initSendAnswer(const char*);
+ bool writePartialMessage();
+ bool isOperationPending();
+
+ int getSocket();
+ const char *getRequestor(); // added -- PB 2004-jul-16
+
+ bool wasError();
+ void closeConnection();
+ void closeSocket();
+ bool cleanUpIfTimeout();
+ bool processJobTimeout();
+ void printStatus();
+ // void reset(); replaced by closeConnection() -- PB 2003-jun-04
+ void clearConnection();
+ private:
+ void clearInputBuffer();
+ void clearOutputBuffer();
+ int socket;
+ IOSelector *pselector;
+
+ // reading
+ char *inputBuffer;
+ int nextReadPos;
+ int maxInputLength;
+ char messageTerminator;
+ // writing
+ char *outputBuffer;
+ int answerLength;
+ int nextWritePos;
+ // errors
+ bool bigError;
+
+ // timing
+ time_t lastActionTime;
+ time_t messageReadyTime;
+ void markAction();
+ // public:
+ static time_t timeOutInterv;
+ static time_t currentTime;
+
+ };
+
+//###################
+
+class NbServerComm
+ {
+ public:
+ NbServerComm();
+ ~NbServerComm();
+
+ // void work();
+ void shouldExit();
+ void closeForcedAllSockets(); // useful for children which don't have to inherit these sockets
+ void printStatus();
+ protected:
+ void initJobs(int maxJobs);
+ bool initListenSocket(int port);
+ void closeListenSocket();
+
+ // void itsRinging(); doesn't exit -- PB 2003-may-04
+ void dispatchReadRequest();
+ void dispatchWriteRequest();
+
+ void connectNewClients();
+
+ void lookForTimeout();
+ int listenSocket;
+
+ NbJob *job;
+ int maxJobs;
+
+ volatile bool exitRequest;
+ bool mayExit();
+
+ IOSelector selector;
+ pid_t mypid;
+
+ };
+
+#ifdef X86
+ #define r_Socklen_t socklen_t
+#endif
+
+#ifdef AIX
+ #define r_Socklen_t socklen_t
+#endif
+
+#ifdef SOLARIS
+ #define r_Socklen_t socklen_t
+#endif
+
+#ifdef DECALPHA
+ #define r_Socklen_t int
+#endif
+
+#endif
diff --git a/rasmgr/rasmgr_config.cc b/rasmgr/rasmgr_config.cc
new file mode 100644
index 0000000..e0e1f4c
--- /dev/null
+++ b/rasmgr/rasmgr_config.cc
@@ -0,0 +1,601 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: rasmgr_config.cc
+ *
+ * MODULE: rasmgr
+ * CLASS: Configuration, RasmgrLicense
+ *
+ * PURPOSE:
+ * Config info from commandline, environment and license
+ *
+ * COMMENTS:
+ * none
+ *
+*/
+
+using namespace std;
+
+#include "globals.hh" // DEFAULT_HOSTNAME, RMANHOME_VAR, DEFAULT_PORT, RASMGR_CONF_FILE
+
+#include "rasmgr_config.hh"
+#include "rasmgr.hh"
+#include "rasmgr_host.hh"
+#include "rasmgr_dbm.hh"
+#include "rasmgr_srv.hh"
+#include "ras_crypto.hh"
+#include "rasmgr_users.hh"
+#include "rasmgr_comm.hh"
+#include "rasmgr_rascontrol.hh"
+
+#include <stdlib.h> // mkstemp()
+#include <iomanip>
+#include <time.h>
+
+#include "debug.hh"
+
+extern bool hostCmp( const char *h1, const char *h2);
+
+
+Configuration::Configuration():
+ cmlInter (CommandLineParser::getInstance()),
+ cmlName (cmlInter.addStringParameter(CommandLineParser::noShortName, "name", "<name> symbolic name of this rasmgr (slave only, default: the host name)")),
+ cmlHostName (cmlInter.addStringParameter(CommandLineParser::noShortName, "hostname", "<name> the advertized host name (master only, default: same as UNIX command 'hostname')")),
+ cmlPort (cmlInter.addLongParameter(CommandLineParser::noShortName, "port", "<port> listen port number", DEFAULT_PORT)),
+ cmlPollFrequ (cmlInter.addLongParameter(CommandLineParser::noShortName, "poll", "<poll> polling timeout (in seconds) for rasmgr listen port", DEFAULT_POLLING_FREQUENCY )),
+ cmlMaster (cmlInter.addStringParameter(CommandLineParser::noShortName, "master", "<name> host of rasmgr master (slave only)")),
+ cmlMasterPort (cmlInter.addLongParameter(CommandLineParser::noShortName, "mport", "<port> listen port number of rasmgr master (slave only)", DEFAULT_PORT)),
+ cmlQuiet (cmlInter.addFlagParameter( 'q', CommandLineParser::noLongName, "quiet: don't log requests (default: log requests to stdout)")),
+#ifdef NO_OFFICIAL_RELEASE
+ cmlTest (cmlInter.addFlagParameter(CommandLineParser::noShortName, "test", "test mode")),
+ cmlDSup (cmlInter.addFlagParameter(CommandLineParser::noShortName, "dsup", "debug mode")),
+ cmlRandTest (cmlInter.addFlagParameter(CommandLineParser::noShortName, "rgt", "random generator test")),
+ cmlRth (cmlInter.addFlagParameter(CommandLineParser::noShortName, "rth", "disable rthl test")),
+ cmlMultiWT (cmlInter.addFlagParameter(CommandLineParser::noShortName, "amw", "allow multiple write transactions")),
+#endif
+ cmlHelp (cmlInter.addFlagParameter('h', RASMGRCMD_HELP, "print this help"))
+{
+ ENTER( "Configuration::Configuration: enter." );
+
+ int ghnResult = gethostname(hostName, sizeof(hostName) );
+ if (ghnResult != 0) // cannot get hostname?
+ {
+ int ghnErrno = errno;
+ std::cout << "Error: cannot get hostname of my machine: error " << ghnErrno << "; will use '" << DEFAULT_HOSTNAME << "' as heuristic." << endl;
+ strcpy( hostName, DEFAULT_HOSTNAME );
+ }
+ strcpy(slaveName,hostName);
+ strcpy(publicHostName,hostName);
+ listenPort=DEFAULT_PORT;
+ masterPort=DEFAULT_PORT;
+ masterName[0]=0;
+
+ pollFrequency = DEFAULT_POLLING_FREQUENCY;
+
+ configFileName[0]=0;
+ slave = false;
+
+ char *rasHome= CONFDIR;
+ if(rasHome!=0)
+ sprintf(configFileName,"%s/",rasHome);
+
+ strcat( configFileName, RASMGR_CONF_FILE );
+ altConfigFileName[0] = '\0';
+
+ testModus = false;
+ debugSupport = false;
+ rtHlTest = true; // by default RasMgr tests at runtime if it's the only one
+ allowMultiWT = false; // rasmgr doesn't allow multiple write transactions for a db, but for internal use we can try it
+
+ LEAVE( "Configuration::Configuration: leave." );
+}
+
+bool Configuration::readConfigFile()
+{
+ //insert internal host, it's not in config file
+ hostmanager.insertInternalHost();
+
+ char inBuffer[MAXMSG];
+ char outBuffer[MAXMSG];
+ bool result = true;
+ bool fileIsOpen = false;
+
+ ENTER( "Configuration::readConfigFile: enter. Looking for config file " << configFileName );
+
+ VLOG << "Inspecting config file " << configFileName << "...";
+
+ std::ifstream ifs(configFileName); // open config file
+
+ if(ifs)
+ fileIsOpen = true;
+ else
+ {
+ TALK( "Configuration::readConfigFile: cannot open config file." );
+ std::cout << "Warning: cannot open config file " << configFileName << endl;
+ fileIsOpen = false;
+ }
+ result = true; // was: false, but I want to allow a missing file
+
+ if (fileIsOpen)
+ {
+ authorization.startConfigFile();
+
+ while( ! ifs.eof() ) // was: while(1), I simplified this
+ // processRequest() will get an additional empty line at eof, but this is harmless
+ {
+ ifs.getline(inBuffer,MAXMSG);
+ // if(!strlen(inBuffer) && ifs.eof()) // FIXME: what happens if last line in file is empty?
+ // {
+ // TALK( "Configuration::readConfigFile: strlen(inBuffer)=" << strlen(inBuffer) << ", eof=" << ifs.eof());
+ // break;
+ // }
+
+ TALK( "Configuration::readConfigFile: processing line: " << inBuffer );
+ rascontrol.processRequest(inBuffer,outBuffer);
+ }
+
+ authorization.endConfigFile();
+
+ ifs.close(); // close config file handle
+ }
+
+ if (result == true && fileIsOpen)
+ VLOG << "ok" << endl;
+
+ LEAVE( "Configuration::readConfigFile: leave. result=" << result );
+ return true;
+}
+
+// return name of alternate config file;
+// takes value from preceding saveAltConfigFile() call.
+const char *Configuration::getAltConfigFileName()
+{
+ return altConfigFileName;
+}
+
+// in future this is not used directly, but through saveOrigConfigFile() and saveAltConfigFile() wrappers below
+bool Configuration::saveConfigFile()
+{
+ ENTER( "Configuration::saveConfigFile: enter." );
+
+ std::ofstream ofs(configFileName);
+ if(!ofs)
+ {
+ LEAVE( "Configuration::saveConfigFile: leave. cannot open config file " << configFileName << " for writing." );
+ return false;
+ }
+
+ ofs << "# rasmgr config file (v1.1)" << std::endl;
+ ofs << "# warning: do not edit this file, it may be overwritten by rasmgr!" << std::endl;
+ ofs << "#" << std::endl;
+
+ int i;
+ //serverhosts
+ for(i=0;i<hostmanager.countHosts();i++)
+ {
+ ServerHost &xx=hostmanager[i];
+
+ if(i > 0)
+ ofs<<"define host "<<xx.getName()<<" -net "<<xx.getNetworkName()<<" -port "<<xx.getListenPort()<<std::endl;
+ else
+ {
+ //by default the master RasMgr is init with the hostname as name => if we have to we change it here
+ if( ! hostCmp(xx.getName(),config.getHostName()) )
+ ofs << "change host "<<config.getHostName()<<" -name "<<xx.getName()<<std::endl;
+
+ if(xx.useLocalHost()==false)
+ ofs<<"change host "<<xx.getName()<<" -uselocalhost off"<<std::endl;
+ }
+ }
+ //databaseHosts
+ for(i=0;i<dbHostManager.countHosts();i++)
+ {
+ DatabaseHost &xx=dbHostManager[i];
+ ofs<<"define dbh "<<xx.getName()<<" -connect "<<xx.getConnectionString()<<std::endl;
+ }
+ //rasservers
+ for(i=0;i<rasManager.countServers();i++)
+ {
+ RasServer &xx=rasManager[i];
+
+ ofs<<"define srv "<<xx.getName()<<" -host "<<xx.getHostName()<<" -type "<<xx.getType();
+ if(xx.getType()==SERVERTYPE_FLAG_HTTP)
+ ofs<<" -port "<<xx.getPort();
+ else
+ ofs<<" -port 0x"<<std::hex<<xx.getPort()<<std::dec;
+ if(xx.isConnectedToDBHost())
+ ofs<<" -dbh "<<xx.getDBHostName();
+ ofs<<std::endl;
+
+ ofs<<"change srv "<<xx.getName()<<" -countdown "<<xx.getCountDown();
+
+ if(strcmp(xx.getExecutableName(),RASEXECUTABLE))
+ ofs<<" -exec "<<xx.getExecutableName();
+
+ ofs<<" -autorestart "<<(xx.isAutoRestart() ? "on":"off")<<" -xp "<<xx.getExtraParams()<<std::endl;
+ }
+
+ //databases
+ for(i=0;i<dbManager.countDatabases();i++)
+ {
+ Database &xx=dbManager[i];
+
+ for(int j=0;j<xx.countConnectionsToDBHosts();j++)
+ {
+ ofs<<"define db "<<xx.getName()<<" -dbh "<<xx.getDBHostName(j)<<std::endl;
+ }
+ }
+
+ ofs.close(); // this was missing, therefore sometimes the config file was cleared -- PB 2003-jun-06
+ LEAVE( "Configuration::saveConfigFile: leave." );
+ return true;
+} // saveConfigFile()
+
+// save config file at original place, i.e., under the name of configFile
+bool Configuration::saveOrigConfigFile()
+{
+ ENTER( "Configuration::saveOrigConfigFile: enter." );
+
+ bool result = saveConfigFile();
+
+ LEAVE( "Configuration::saveOrigAltConfigFile: leave. result=" << result );
+ return result;
+}
+
+// save configuration file in another file, same dir as config file
+bool Configuration::saveAltConfigFile()
+{
+ ENTER( "Configuration::saveAltConfigFile()" );
+
+ bool result = true;
+ char origFileName[ sizeof(configFileName) ]; // temp copy of origFileName
+
+ // save original file name
+ (void) strcpy( origFileName, configFileName );
+
+ // build temp file by appending a unique string
+ (void) strcpy( altConfigFileName, configFileName );
+ (void) strcat( altConfigFileName, ".XXXXXX" ); // 6 * 'X', see man mkstemp()
+
+ int altFile = mkstemp( altConfigFileName ); // replaces the Xs by unique string
+ if (altFile < 0) // error in creating file name
+ {
+ int tempError = errno;
+ TALK( "Configuration::saveAltConfigFile: error creating alternate file name: " << strerror(tempError) );
+ result = false;
+ }
+
+ if (result == true)
+ {
+ // now we have a valid + open file, but we can't use it like that, because we open down below.
+ // so close it again, being happy that we have a valid file name. bad hack, though.
+ int closeResult = close( altFile );
+ if (closeResult != 0)
+ TALK( "Configuration::saveAltConfigFile: error in temporary closing file, ignoring that." );
+ }
+
+ if (result == true)
+ {
+ (void) strcpy( configFileName, altConfigFileName ); // set file to be written to alternate name
+ result = saveConfigFile(); // save file, name has been substituted successfully
+ (void) strcpy( configFileName, origFileName ); // restore original config file name
+ }
+
+ LEAVE( "Configuration::saveAltConfigFile: leave. result=" << result );
+ return result;
+}
+
+bool Configuration::interpretArguments(int argc, char **argv, char **envp)
+{
+ ENTER( "Configuration::interpretArguments: enter." );
+
+ bool result = true;
+ //errorCode=0;
+
+ //process command line
+ try
+ {
+ cmlInter.processCommandLine(argc, argv);
+ }
+ catch(CmlException& err)
+ {
+ std::cout << "Error parsing command line: " << err.what() << std::endl;
+ printHelp();
+ result = false;
+ }
+
+ SET_OUTPUT( true ); // by default, enable trace (debug) output
+ verbose = true; // by default, be verbose
+ if( (result==true) && cmlQuiet.isPresent() )
+ {
+ SET_OUTPUT( false ); // disable trace (debug) output
+ // debugOutput = true; // done via the above macro
+ verbose = false; // only minimum messages
+ result = true;
+ }
+
+ if( (result==true) && cmlHelp.isPresent() )
+ {
+ printHelp();
+ result = false;
+ }
+
+ if( (result==true) && cmlHostName.isPresent() )
+ {
+ if (sizeof(hostName) > strlen(cmlHostName.getValueAsString()))
+ strcpy(publicHostName,cmlHostName.getValueAsString());
+ else
+ {
+ VLOG << "Error: host name exceeds length limit of " << sizeof(hostName) << " characters." << std::endl;
+ result = false;
+ }
+ }
+
+ if( (result==true) && cmlPort.isPresent() )
+ {
+ try
+ {
+ listenPort = cmlPort.getValueAsLong();
+ }
+ catch(CmlException& err)
+ {
+ VLOG << "Error converting port parameter " << cmlPort.getLongName() << " to integer: " << err.what() << std::endl;
+ result = false;
+ }
+ }
+
+ if( (result==true) && cmlMaster.isPresent() )
+ {
+ slave = true;
+ strcpy(masterName,cmlMaster.getValueAsString());
+ }
+
+ if( (result==true) && cmlMasterPort.isPresent() )
+ {
+ try
+ {
+ masterPort = cmlMasterPort.getValueAsLong();
+ }
+ catch(CmlException& err)
+ {
+ VLOG << "Error converting " << cmlMasterPort.getLongName() << " to integer: " << err.what() << std::endl;
+ result = false;
+ }
+ }
+
+ if( (result==true) && cmlPollFrequ.isPresent() )
+ {
+ try
+ {
+ pollFrequency = cmlPollFrequ.getValueAsLong();
+ }
+ catch(CmlException& err)
+ {
+ VLOG << "Error converting " << cmlPollFrequ.getLongName() << " to integer: " << err.what() << std::endl;
+ result = false;
+ }
+ if (result == true && pollFrequency <= 0)
+ {
+ VLOG << "Error: poll frequency must be a positive integer." << std::endl;
+ result = false;
+ }
+ }
+
+ if( (result==true) && cmlName.isPresent() )
+ {
+ if (sizeof(slaveName) > strlen(cmlName.getValueAsString()))
+ strcpy(slaveName,cmlName.getValueAsString());
+ else
+ {
+ VLOG << "Error: slave name exceeds length limit of " << sizeof(slaveName) << " characters." << std::endl;
+ result = false;
+ }
+ }
+
+#ifdef NO_OFFICIAL_RELEASE
+ testModus = cmlTest.isPresent();
+ debugSupport=cmlDSup.isPresent();
+ rtHlTest=cmlRth.isPresent();
+
+ if( (result==true) && cmlRandTest.isPresent() )
+ {
+ std::cout<<"Random generator test..."<<(randomGenerator.insideTest() ? "PASSED":"FAILED" )<<std::endl;
+ result = false;
+ }
+
+ allowMultiWT = cmlMultiWT.isPresent();
+
+#endif
+
+ LEAVE( "Configuration::interpretArguments: leave. result=" << result );
+ return result;
+}
+
+bool Configuration::allowMultipleWriteTransactions()
+{
+ return allowMultiWT;
+}
+
+bool Configuration::isDebugSupport()
+{
+ return debugSupport;
+}
+
+bool Configuration::isVerbose()
+{
+ return verbose;
+}
+
+bool Configuration::isTestModus()
+{
+ return testModus;
+}
+
+const char* Configuration::getHostName()
+{
+ return hostName;
+}
+
+const char* Configuration::getPublicHostName()
+{
+ return publicHostName;
+}
+
+int Configuration::getListenPort()
+{
+ return listenPort;
+}
+
+const char* Configuration::getMasterName()
+{
+ return masterName;
+}
+int Configuration::getMasterPort()
+{
+ return masterPort;
+}
+
+int Configuration::getPollFrequency()
+{
+ return pollFrequency;
+}
+
+const char* Configuration::getSlaveName()
+{
+ return slaveName[0] ? slaveName:hostName;
+}
+
+
+void Configuration::printHelp()
+{
+ std::cout << "Usage: rasmgr [options]" << std::endl;
+ std::cout << "Options:" << std::endl;
+ cmlInter.printHelp();
+ std::cout << std::endl;
+ return;
+}
+
+void Configuration::printStatus()
+{
+ std::cout << "rasmgr configuration parameter settings:" << std::endl;
+ std::cout << " symb name = " << publicHostName << std::endl;
+ std::cout << " hostname = " << publicHostName << std::endl;
+ std::cout << " port = " << listenPort << std::endl;
+ std::cout << " poll = " << pollFrequency << std::endl;
+ std::cout << " quiet = " << (!verbose) << std::endl;
+ return;
+}
+
+//****************************************************************************************************************
+
+// FIXME: this needs refinement -- PB 2003-jun-09
+BenchmarkTimer::BenchmarkTimer(const char *text)
+{
+ this->text = (char*)text;
+ time_t now = time(NULL);
+ char *n = ctime(&now);
+ n[strlen(n)-1] = '\0'; // delete trailing newline char
+ // cout << "--- rasmgr timer start for \'" << text << "\' at " << n << "." << endl;
+ gettimeofday(&start,NULL);
+}
+
+BenchmarkTimer::~BenchmarkTimer()
+{
+}
+
+void BenchmarkTimer::result()
+{
+ timeval result;
+ gettimeofday(&end,NULL);
+ int r=timeval_subtract(&result,&end,&start);
+ time_t now = time(NULL);
+ char *n = ctime(&now);
+ n[strlen(n)-1] = '\0'; // delete trailing newline char
+ VLOG << "rasmgr timer stop for \'" << text << "\' at " << n << ": " << result.tv_sec << '.' << std::setw(3) << std::setfill('0') << result.tv_usec << " seconds elapsed." << endl;
+}
+
+int BenchmarkTimer::timeval_subtract(timeval *result,timeval *x,timeval *y)
+{
+#define ONE_MILLION 1000000
+ /* Perform the carry for the later subtraction by updating Y. */
+ if (x->tv_usec < y->tv_usec)
+ {
+ int nsec = (y->tv_usec - x->tv_usec) / ONE_MILLION + 1;
+ y->tv_usec -= ONE_MILLION * nsec;
+ y->tv_sec += nsec;
+ }
+ if (x->tv_usec - y->tv_usec > ONE_MILLION)
+ {
+ int nsec = (x->tv_usec - y->tv_usec) / ONE_MILLION;
+ y->tv_usec += ONE_MILLION * nsec;
+ y->tv_sec -= nsec;
+ }
+
+ /* Compute the time remaining to wait.
+ `tv_usec' is certainly positive. */
+ result->tv_sec = x->tv_sec - y->tv_sec;
+ result->tv_usec = x->tv_usec - y->tv_usec;
+
+ /* Return 1 if result is negative. */
+ return x->tv_sec < y->tv_sec;
+}
+
+//####################################
+ /*/
+
+ //read-pacaleala
+ hostmanager.insertNewHost("Ras1","martini",8081);
+ hostmanager.insertNewHost("Ras2","coconutkiss",8082);
+ hostmanager.insertNewHost("Ras3","tequilla",8082);
+
+ dbHostManager.insertNewHost("julep", "rasdec/rasdec@julep.akglocal.de");
+ dbHostManager.insertNewHost("pinacolada","rasdec/rasdec@pinacolada.akglocal.de");
+
+ dbManager.insertNewDatabase("RasDemo");
+ dbManager[0].connectToDBHost("julep");
+ dbManager[0].connectToDBHost("pinacolada");
+
+ dbManager.insertNewDatabase("BLVA");
+ dbManager[1].connectToDBHost("pinacolada");
+
+ rasManager.insertNewServer("RasServer11","Ras1",SERVERTYPE_FLAG_RPC,0x29999998);
+ rasManager[0].connectToDBHost("julep");//,"\\");
+
+ rasManager.insertNewServer("RasServer12","Ras1",SERVERTYPE_FLAG_RPC,0x29999998);
+ rasManager[1].connectToDBHost("pinacolada");//,"\\");
+
+ rasManager.insertNewServer("RasServer21","Ras2",SERVERTYPE_FLAG_HTTP,8085);
+ rasManager[2].connectToDBHost("julep");//,"\\");
+
+ rasManager.insertNewServer("RasServer31","Ras3",SERVERTYPE_FLAG_HTTP,8084);
+ rasManager[3].connectToDBHost("julep");//,"\\");
+
+ rasManager.insertNewServer("RasServer00","RasMaster",SERVERTYPE_FLAG_HTTP,8083);
+ rasManager[4].connectToDBHost("julep");//,"\\");
+
+ dbManager.insertNewDatabase("RasNew");
+ dbManager[2].connectToDBHost("julep");
+
+ return true;
+ // */
+
diff --git a/rasmgr/rasmgr_config.hh b/rasmgr/rasmgr_config.hh
new file mode 100644
index 0000000..e8e7288
--- /dev/null
+++ b/rasmgr/rasmgr_config.hh
@@ -0,0 +1,134 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: rasmgr_config.hh
+ *
+ * MODULE: rasmgr
+ * CLASS: Configuration, RasmgrLicense
+ *
+ * PURPOSE:
+ * Config info from commandline, environment and license
+ *
+ * COMMENTS:
+ * none
+ *
+*/
+#ifndef RASMGR_CONFIG_HH
+#define RASMGR_CONFIG_HH
+
+#include <iostream>
+#include <string>
+#include <sys/time.h>
+
+#include "commline/cmlparser.hh"
+
+// default rasmgr listen port polling frequency [secs]
+// must be longer than the OS specific time to release TIM_WAIT sockets
+const int DEFAULT_POLLING_FREQUENCY = 200;
+// #define helps to avoid multiple defs in different .cc files:
+#define DEFAULT_POLLING_FREQUENCY_STR "200"
+
+/// host/domain name size (See man gethostname)
+#define HOSTNAME_SIZE 255
+
+class Configuration
+ {
+ public:
+ Configuration();
+
+ bool interpretArguments(int argc, char **argv,char **envp);
+ bool readConfigFile();
+ bool saveOrigConfigFile();
+ bool saveAltConfigFile();
+ const char *getAltConfigFileName();
+ const struct tm *getExpirationDate();
+ const char * getHostName();
+ const char * getPublicHostName();
+ int getListenPort();
+
+ const char * getMasterName();
+ int getMasterPort();
+ int getPollFrequency();
+ const char * getSlaveName();
+ bool isTestModus();
+ bool isDebugSupport();
+ bool isVerbose();
+
+ bool allowMultipleWriteTransactions();
+
+ void printStatus();
+
+ private:
+ void printHelp();
+
+ char hostName[HOSTNAME_SIZE];
+ char publicHostName[HOSTNAME_SIZE]; // usually ==hostName, but you might want to publish IP address or hostname.domainname instead
+ int listenPort;
+ // name of configuration file
+ char configFileName[HOSTNAME_SIZE];
+ // name of alternate configuration file for rescue save, generated by saveAltConfigFile()
+ char altConfigFileName[HOSTNAME_SIZE];
+
+ // if slave
+ char masterName[HOSTNAME_SIZE];
+ int masterPort;
+ char slaveName[HOSTNAME_SIZE]; //my name, when I'm slave and no HIGHLANDER
+
+ int pollFrequency; // listen port polling frequency in seconds
+ bool testModus;
+ bool debugSupport;
+ bool verbose;
+ bool slave;
+
+ bool saveConfigFile();
+
+ bool rtHlTest;
+ bool allowMultiWT;
+
+ //interface program
+ CommandLineParser &cmlInter;
+ CommandLineParameter &cmlHelp, &cmlHostName, &cmlPort, &cmlPollFrequ;
+ CommandLineParameter &cmlMaster, &cmlMasterPort, &cmlName, &cmlQuiet;
+#ifdef NO_OFFICIAL_RELEASE
+ CommandLineParameter &cmlTest, &cmlDSup, &cmlRandTest, &cmlRth, &cmlMultiWT;
+#endif
+ };
+
+extern Configuration config;
+
+class BenchmarkTimer
+ {
+ public:
+ BenchmarkTimer(const char *text);
+ ~BenchmarkTimer();
+ void result();
+ private:
+ int timeval_subtract(timeval *result,timeval *x,timeval *y);
+
+ struct timeval start;
+ struct timeval end;
+
+ char* text;
+
+ };
+#endif
diff --git a/rasmgr/rasmgr_dbm.cc b/rasmgr/rasmgr_dbm.cc
new file mode 100644
index 0000000..2890a4d
--- /dev/null
+++ b/rasmgr/rasmgr_dbm.cc
@@ -0,0 +1,573 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: rasmgr_dbm.cc
+ *
+ * MODULE: rasmgr
+ * CLASS: DatabaseHost, DatabaseHostManager, Database, DatabaseManager
+ *
+ * COMMENTS:
+ * none
+ *
+\*/
+
+#include "rasmgr_dbm.hh"
+#include "rasmgr_srv.hh"
+#include "rasmgr_users.hh"
+
+#include "debug.hh"
+
+extern bool hostCmp( const char *h1, const char *h2);
+
+
+DatabaseHost::DatabaseHost()
+ { hostName[0]=0;
+ connectString[0]=0;
+ valid=false;
+ activServers=0;
+ }
+DatabaseHost::~DatabaseHost()
+ {
+ }
+
+const char* DatabaseHost::getName()
+ { return hostName;
+ }
+
+const char* DatabaseHost::getConnectionString()
+ { return connectString;
+ }
+
+void DatabaseHost::changeConnectionString(const char *connectString)
+ { strcpy(this->connectString,connectString);
+ }
+void DatabaseHost::changeName(const char *newName)
+ { strcpy(hostName,newName);
+ }
+
+void DatabaseHost::init(const char* hostName,const char* connectString)
+ {
+ strcpy(this->hostName,hostName);
+ strcpy(this->connectString,connectString);
+ valid=true;
+ }
+
+void DatabaseHost::regStartServer() { activServers++;}
+
+void DatabaseHost::regDownServer() { activServers--;}
+
+//void DatabaseHost::incrConnServers() { connServers++;}
+
+//void DatabaseHost::decrConnServers() { connServers--;}
+
+//void DatabaseHost::incrConnDatabases() { connDatabases++;}
+
+//void DatabaseHost::decrConnDatabases() { connDatabases--;}
+
+bool DatabaseHost::isBusy()
+ {
+ //std::cout<<"DBH="<<hostName<<"s="<<connServers<<" d="<<connDatabases<<std::endl;
+ return activServers ? true:false; //(connServers + connDatabases) ? true:false;
+ }
+
+
+bool DatabaseHost::isValid()
+ {
+ return valid;
+ }
+
+bool DatabaseHost::prepareToBeRemoved()
+ {
+ if(isBusy()) return false;
+
+ //disconnect all servers from me
+ rasManager.disconnectAllServersFromDBH(hostName);
+
+ //disconnect all databases from me
+ dbManager.disconnectAllDatabasesFromDBH(hostName);
+
+ return true;
+ }
+
+//**********************************************************************
+DatabaseHostManager::DatabaseHostManager()
+ {
+ }
+DatabaseHostManager::~DatabaseHostManager()
+ {
+
+ }
+
+bool DatabaseHostManager::insertNewHost(const char* hostName,const char* connectString)
+ {
+ char tempHostName[200];
+ strcpy(tempHostName,hostName);
+ // why?? strtolwr(tempHostName);
+
+ if(testUniqueness(tempHostName)==false) return false;
+
+ DatabaseHost tempDatabaseHost;
+ hostList.push_back(tempDatabaseHost);
+ DatabaseHost &refDatabaseHost=hostList.back();
+
+ refDatabaseHost.init(tempHostName,connectString);
+
+ return true;
+ }
+
+bool DatabaseHostManager::removeHost(const char* hostName)
+ {
+ list<DatabaseHost>::iterator iter=hostList.begin();
+ for(int i=0;i<hostList.size();i++)
+ {
+ if(hostCmp(iter->getName(),hostName))
+ {
+ if(iter->isBusy())
+ return false;
+ iter->prepareToBeRemoved();
+ hostList.erase(iter);
+ return true;
+ }
+
+ iter++;
+ }
+ return false;
+ }
+
+bool DatabaseHostManager::testUniqueness(const char* hostName)
+ {
+ list<DatabaseHost>::iterator iter=hostList.begin();
+ for(int i=0;i<hostList.size();i++)
+ {
+ if(hostCmp(iter->getName(),hostName))
+ return false;
+ iter++;
+ }
+ return true;
+ }
+
+DatabaseHost& DatabaseHostManager::operator[](int x)
+ {
+ list<DatabaseHost>::iterator iter=hostList.begin();
+ for(int i=0;i<x;i++)
+ iter++;
+ return *iter;
+ }
+DatabaseHost& DatabaseHostManager::operator[](const char* hostName)
+ {
+
+ list<DatabaseHost>::iterator iter=hostList.begin();
+ for(int i=0;i<hostList.size();i++)
+ {
+ if(hostCmp(iter->getName(),hostName))
+ return *iter;
+ iter++;
+ }
+ return protElem;
+ }
+
+
+int DatabaseHostManager::countHosts()
+ {
+ return hostList.size();
+ }
+
+bool DatabaseHostManager::reset()
+ {
+ if(config.isTestModus()==false) return false;
+
+ list<DatabaseHost>::iterator iter=hostList.begin();
+ for(int i=0;i<hostList.size();i++,iter++)
+ {
+ iter->prepareToBeRemoved();
+ }
+
+ while(hostList.size())
+ {
+ hostList.pop_front();
+ }
+
+ return true;
+ }
+
+bool DatabaseHostManager::acceptChangeName(const char *oldName,const char *newName)
+ {
+ if(hostCmp(oldName,newName))
+ return true; // if someone really wants to change a name with the same,
+ return testUniqueness(newName);
+ }
+
+//*************************************************************************
+
+Database::Database()
+ { databaseName[0]=0;
+ valid=false;
+
+ traceWT = false;
+ countWriteTransactions =0;
+ countReadTransactions =0;
+ }
+Database::~Database()
+ {
+ }
+
+const char* Database::getName()
+ { return databaseName;
+ }
+void Database::changeName(const char* databaseName)
+ { strcpy(this->databaseName,databaseName);
+ }
+
+void Database::init(const char* databaseName)
+ {
+ strcpy(this->databaseName,databaseName);
+ valid=true;
+ }
+bool Database::isValid()
+ {
+ return valid;
+ }
+
+const char* Database::getDescriptionHeader(char *destBuffer)
+ {
+ sprintf(destBuffer," Database Name Open Trans.");
+ return destBuffer;
+ }
+const char* Database::getDescription(char *destBuffer)
+ {
+ sprintf(destBuffer,"%-20s (%dw + %dr)",databaseName,countWriteTransactions,countReadTransactions);
+ return destBuffer;
+ }
+
+bool Database::connectToDBHost(const char* hostName)
+ {
+ DatabaseHost &TempDBH=dbHostManager[hostName];
+
+ if(TempDBH.isValid()==false) return false; // no such hostName
+
+ if(checkConnection(TempDBH)) return false; // is already connected
+
+ hostPtrList.push_back(&TempDBH);
+ //removed TempDBH.incrConnDatabases();
+
+ // alse connecting to servers connected to this database host
+ for(int i=0;i<rasManager.countServers();i++)
+ {
+ RasServer &r = rasManager[i];
+ if(hostCmp(r.getDBHostName(),hostName))
+ {
+ connectToRasServer(r.getName());
+ }
+ }
+
+ return true;
+ }
+
+bool Database::disconnectFromDBHost(const char* hostName)
+ {
+ list<DatabaseHost*>::iterator iter=hostPtrList.begin();
+ for(int i=0;i<hostPtrList.size();i++)
+ {
+ DatabaseHost *ptrDBH=*iter;
+
+ if(hostCmp(ptrDBH->getName(),hostName))
+ {
+ for(int j=0;j<rasManager.countServers();j++)
+ { // disconnectig from the RasServers connected to the same database host
+ if(hostCmp(hostName,rasManager[j].getDBHostName()))
+ {
+ disconnectFromRasServer(rasManager[j].getName());
+ }
+ }
+
+ //removed ptrDBH->decrConnDatabases();
+ hostPtrList.erase(iter);
+ return true;
+ }
+ iter++;
+ }
+ return false;;
+ }
+void Database::disconnectForRemove()
+ {
+ // this means disconnect from all database hosts
+ list<DatabaseHost*>::iterator iter=hostPtrList.begin();
+ int listsize=hostPtrList.size();
+ for(int i=0;i<listsize;i++)
+ {
+ //removed (*iter)->decrConnDatabases();
+ iter++;
+ }
+ for(int i=0;i<listsize;i++)
+ { hostPtrList.pop_front();
+ }
+ //and revoke all trustees for it
+ userManager.removeDatabaseRights(databaseName);
+ }
+
+bool Database::isConnectedToDBHost(const char* hostName)
+ {
+ DatabaseHost &r = dbHostManager[hostName];
+
+ if(r.isValid()==false) return false;
+
+ return checkConnection(r);
+ }
+bool Database::checkConnection(DatabaseHost &databaseHost)
+ {
+ list<DatabaseHost*>::iterator iter=hostPtrList.begin();
+ for(int i=0;i<hostPtrList.size();i++)
+ {
+ if(*iter== &databaseHost) return true;
+
+ iter++;
+ }
+ return false;
+ }
+
+int Database::countConnectionsToDBHosts()
+ {
+ return hostPtrList.size();
+ }
+const char* Database::getDBHostName(int x)
+ {
+ if( x < hostPtrList.size() )
+ {
+ list<DatabaseHost*>::iterator iter=hostPtrList.begin();
+ for(int i=0;i<x;i++,iter++);
+ return (*iter)->getName();
+ }
+ return "noHost!";
+ }
+
+bool Database::connectToRasServer(const char *serverName)
+ {
+ RasServer &rasServer=rasManager[serverName];
+
+ if(rasServer.isValid()==false) return false; // no such serverName
+
+ if(checkConnection(rasServer)) return false; // is already connected
+
+ rasPtrList.push_back(&rasServer);
+
+ return true;
+
+ }
+bool Database::disconnectFromRasServer(const char *serverName)
+ {
+ list<RasServer*>::iterator iter=rasPtrList.begin();
+ for(int i=0;i<rasPtrList.size();i++)
+ {
+ RasServer *ptrRas=*iter;
+
+ if(hostCmp(ptrRas->getName(),serverName))
+ {
+ rasPtrList.erase(iter);
+ return true;
+ }
+ iter++;
+ }
+ return false;
+ }
+
+bool Database::isConnectedToRasServer(const char *serverName)
+ {
+ RasServer &r = rasManager[serverName];
+
+ if(r.isValid()==false) return false;
+
+ return checkConnection(r);
+ }
+
+int Database::countConnectionsToRasServers()
+ {
+ return rasPtrList.size();
+ }
+
+const char* Database::getRasServerName(int x)
+ {
+ if( x < rasPtrList.size() )
+ {
+ list<RasServer*>::iterator iter=rasPtrList.begin();
+ for(int i=0;i<x;i++,iter++);
+ return (*iter)->getName();
+ }
+ return "noRasServer!";
+ }
+
+bool Database::checkConnection(RasServer &rasServer)
+ {
+ list<RasServer*>::iterator iter=rasPtrList.begin();
+ for(int i=0;i<rasPtrList.size();i++)
+ {
+ if(*iter== &rasServer) return true;
+
+ iter++;
+ }
+ return false;
+ }
+
+void Database::setTraceWriteTrans(bool how)
+ {
+ traceWT=how;
+ }
+
+void Database::startWriteTransaction()
+ {
+ if(traceWT) std::cout<<" DbName="<<databaseName<<" rwTrans-in"<<std::endl;
+ countWriteTransactions++;
+ }
+
+void Database::endWriteTransaction()
+ {
+ if(traceWT) std::cout<<" DbName="<<databaseName<<" rwTrans-out"<<std::endl;
+ countWriteTransactions--;
+ }
+int Database::getWriteTransactionCount()
+ {
+ if(traceWT) std::cout<<" DbName="<<databaseName<<" ask rwTrans? ("<<countWriteTransactions<<")"<<std::endl;
+ return countWriteTransactions;
+ }
+
+void Database::startReadTransaction()
+ {
+ countReadTransactions++;
+ }
+
+void Database::endReadTransaction()
+ {
+ countReadTransactions--;
+ }
+int Database::getReadTransactionCount()
+ {
+ return countReadTransactions;
+ }
+bool Database::isBusy()
+ { return countReadTransactions+countWriteTransactions ? true:false;
+ }
+//**********************************************************************
+DatabaseManager::DatabaseManager()
+ {
+ }
+DatabaseManager::~DatabaseManager()
+ {
+
+ }
+
+bool DatabaseManager::insertNewDatabase(const char* databaseName)
+ {
+ if(testUniqueness(databaseName)==false) return false;
+
+ Database tempDatabase;
+ dtbList.push_back(tempDatabase);
+ Database &refDatabase=dtbList.back();
+ refDatabase.init(databaseName);
+ return true;
+ }
+
+bool DatabaseManager::removeDatabase(const char* databaseName)
+ {
+ list<Database>::iterator iter=dtbList.begin();
+ for(int i=0;i<dtbList.size();i++)
+ {
+ if(hostCmp(iter->getName(),databaseName))
+ {
+ iter->disconnectForRemove();
+ dtbList.erase(iter);
+ return true;
+ }
+
+ iter++;
+ }
+ return false;
+ }
+
+bool DatabaseManager::testUniqueness(const char* databaseName)
+ {
+ list<Database>::iterator iter=dtbList.begin();
+ for(int i=0;i<dtbList.size();i++)
+ {
+ if(hostCmp(iter->getName(),databaseName))
+ return false;
+ iter++;
+ }
+ return true;
+ }
+
+Database& DatabaseManager::operator[](int x)
+ {
+ list<Database>::iterator iter=dtbList.begin();
+ for(int i=0;i<x;i++) iter++;
+ return *iter;
+ }
+Database& DatabaseManager::operator[](const char* dbName)
+ {
+ list<Database>::iterator iter=dtbList.begin();
+ for(int i=0;i<dtbList.size();i++)
+ {
+ if(hostCmp(iter->getName(),dbName))
+ return *iter;
+
+ iter++;
+ }
+ return protElem;
+ }
+
+void DatabaseManager::disconnectAllDatabasesFromDBH(const char* dbhName)
+ {
+ list<Database>::iterator iter=dtbList.begin();
+ for(int i=0;i<dtbList.size();i++,iter++)
+ {
+ iter->disconnectFromDBHost(dbhName);
+ }
+ }
+int DatabaseManager::countDatabases()
+ {
+ return dtbList.size();
+ }
+
+bool DatabaseManager::reset()
+ {
+ if(config.isTestModus()==false) return false;
+
+ list<Database>::iterator iter=dtbList.begin();
+ for(int i=0;i<dtbList.size();i++,iter++)
+ {
+ iter->disconnectForRemove();
+ }
+
+ while(dtbList.size())
+ {
+ dtbList.pop_front();
+ }
+ return true;
+ }
+
+bool DatabaseManager::acceptChangeName(const char *oldName,const char *newName)
+ {
+ if(hostCmp(oldName,newName))
+ return true; // if someone really wants to change a name with the same,
+
+ return testUniqueness(newName);
+ }
+
diff --git a/rasmgr/rasmgr_dbm.hh b/rasmgr/rasmgr_dbm.hh
new file mode 100644
index 0000000..78e7a8c
--- /dev/null
+++ b/rasmgr/rasmgr_dbm.hh
@@ -0,0 +1,171 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: rasmgr_dbm.hh
+ *
+ * MODULE: rasmgr
+ * CLASS: DatabaseHost, DatabaseHostManager, Database, DatabaseManager
+ *
+ * COMMENTS:
+ * none
+ *
+*/
+
+#ifndef RASMGR_DBM_HH
+#define RASMGR_DBM_HH
+
+#include "rasmgr.hh"
+#include "rasmgr_config.hh"
+//#include "rasmgr_srv.hh"
+
+class DatabaseHost
+ {
+ public:
+ DatabaseHost();
+ ~DatabaseHost();
+
+ void init(const char* hostName,const char *connectString);
+
+ const char* getName();
+ const char* getConnectionString();
+ void changeConnectionString(const char *connectString);
+ void changeName(const char *newName);
+ void regStartServer();
+ void regDownServer();
+ //void incrConnServers();
+ //void decrConnServers();
+ //void incrConnDatabases();
+ //void decrConnDatabases();
+ bool prepareToBeRemoved();
+ bool isBusy();
+ bool isValid();
+ private:
+ char hostName[100];
+ char connectString[100];
+ int activServers;
+ //int connServers;
+ //int connDatabases;
+ bool valid;
+ };
+
+class DatabaseHostManager
+ {
+ public:
+ DatabaseHostManager();
+ ~DatabaseHostManager();
+ bool insertNewHost(const char* hostName,const char* connectString);
+ bool removeHost(const char* hostName);
+ int countHosts();
+ DatabaseHost& operator[](int);
+ DatabaseHost& operator[](const char* hostName);
+ bool reset();
+ bool acceptChangeName(const char *oldName,const char *newName);
+ private:
+ bool testUniqueness(const char* hostName);
+ list<DatabaseHost> hostList;
+ DatabaseHost protElem;
+ };
+
+extern DatabaseHostManager dbHostManager;
+
+
+//*****************************************************
+
+class RasServer;
+
+class Database
+ {
+ public:
+ Database();
+ ~Database();
+
+ void init(const char* databaseName);
+ const char* getName();
+ void changeName(const char* databaseName);
+
+ static const char* getDescriptionHeader(char *destBuffer);
+ const char* getDescription(char *destBuffer);
+
+ bool connectToDBHost(const char* hostName);
+ bool disconnectFromDBHost(const char* hostName);
+ bool isConnectedToDBHost(const char* hostName);
+ int countConnectionsToDBHosts();
+ const char* getDBHostName(int);
+
+ bool connectToRasServer(const char *serverName);
+ bool disconnectFromRasServer(const char *serverName);
+ bool isConnectedToRasServer(const char *serverName);
+ int countConnectionsToRasServers();
+ const char* getRasServerName(int);
+
+ void disconnectForRemove();
+
+ void startWriteTransaction();
+ void endWriteTransaction();
+ void startReadTransaction();
+ void endReadTransaction();
+
+ int getWriteTransactionCount();
+ int getReadTransactionCount();
+ bool isBusy();
+
+ void setTraceWriteTrans(bool);
+
+ bool isValid();
+ private:
+ bool checkConnection(DatabaseHost &);
+ bool checkConnection(RasServer &);
+ char databaseName[100];
+ list<DatabaseHost*> hostPtrList;
+ list<RasServer*> rasPtrList;
+
+ bool traceWT;
+ int countWriteTransactions;
+ int countReadTransactions;
+
+ bool valid;
+ };
+
+class DatabaseManager
+ {
+ public:
+ DatabaseManager();
+ ~DatabaseManager();
+ bool insertNewDatabase(const char* databaseName);
+ bool removeDatabase(const char* databaseName);
+ int countDatabases();
+ Database& operator[](int);
+ Database& operator[](const char*);
+ void disconnectAllDatabasesFromDBH(const char* dbhName);
+ bool reset();
+ bool acceptChangeName(const char *oldName,const char *newName);
+ private:
+ bool testUniqueness(const char* dbName);
+ list<Database> dtbList;
+ Database protElem;
+ };
+
+extern DatabaseManager dbManager;
+
+
+#endif
diff --git a/rasmgr/rasmgr_error.cc b/rasmgr/rasmgr_error.cc
new file mode 100644
index 0000000..cdc2e0e
--- /dev/null
+++ b/rasmgr/rasmgr_error.cc
@@ -0,0 +1,101 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: rasmgr_error.cc
+ *
+ * MODULE: rasmgr
+ * CLASS: RCError and derivates
+ *
+ * COMMENTS:
+ * none
+ *
+*/
+
+#include "rasmgr_error.hh"
+
+#include "debug.hh"
+
+
+RCError::RCError()
+ {
+ }
+
+
+RCErrorUnexpToken::RCErrorUnexpToken(const char *token)
+:pcc(token)
+ {
+ }
+
+const char* RCErrorUnexpToken::getString(char *destBuffer)
+ {
+ sprintf(destBuffer,"Unexpected token %s in command.",pcc);
+ return destBuffer;
+ }
+
+
+RCErrorNoPermission::RCErrorNoPermission()
+ {
+ }
+
+const char* RCErrorNoPermission::getString(char *destBuffer)
+ {
+ sprintf(destBuffer,"You don't have permission for this operation.");
+ return destBuffer;
+ }
+
+
+RCErrorInvalidName::RCErrorInvalidName(const char *name)
+:pcc(name)
+ {
+ }
+
+const char* RCErrorInvalidName::getString(char *destBuffer)
+ {
+ sprintf(destBuffer,"Invalid %s name.",pcc);
+ return destBuffer;
+ }
+
+
+RCErrorMissingParam::RCErrorMissingParam(const char *what)
+:pcc(what)
+ {
+ }
+
+const char* RCErrorMissingParam::getString(char *destBuffer)
+ {
+ sprintf(destBuffer,"Missing %s.",pcc);
+ return destBuffer;
+ }
+
+
+RCErrorIncorNumberValue::RCErrorIncorNumberValue(const char *what)
+:pcc(what)
+ {
+ }
+
+const char* RCErrorIncorNumberValue::getString(char *destBuffer)
+ {
+ sprintf(destBuffer,"Incorect number value for parameter %s.",pcc);
+ return destBuffer;
+ }
+
diff --git a/rasmgr/rasmgr_error.hh b/rasmgr/rasmgr_error.hh
new file mode 100644
index 0000000..bf16bb7
--- /dev/null
+++ b/rasmgr/rasmgr_error.hh
@@ -0,0 +1,91 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: rasmgr_error.hh
+ *
+ * MODULE: rasmgr
+ * CLASS: RCError and derivates
+ *
+ * COMMENTS:
+ * none
+ *
+*/
+
+#ifndef RASMGR_ERROR_HH
+#define RASMGR_ERROR_HH
+
+#include "rasmgr.hh"
+
+class RCError
+ {
+ public:
+ RCError();
+ virtual const char* getString(char *destBuffer)=0;
+
+ };
+
+class RCErrorUnexpToken : public RCError
+ {
+ public:
+ RCErrorUnexpToken(const char*);
+ const char* getString(char *destBuffer);
+ private:
+ const char *pcc;
+ };
+
+class RCErrorNoPermission : public RCError
+ {
+ public:
+ RCErrorNoPermission();
+ const char* getString(char *destBuffer);
+ private:
+ };
+
+class RCErrorInvalidName : public RCError
+ {
+ public:
+ RCErrorInvalidName(const char*);
+ const char* getString(char *destBuffer);
+ private:
+ const char *pcc;
+ };
+
+class RCErrorMissingParam : public RCError
+ {
+ public:
+ RCErrorMissingParam(const char*);
+ const char* getString(char *destBuffer);
+ private:
+ const char *pcc;
+ };
+
+class RCErrorIncorNumberValue : public RCError
+ {
+ public:
+ RCErrorIncorNumberValue(const char*);
+ const char* getString(char *destBuffer);
+ private:
+ const char *pcc;
+ };
+
+#endif
diff --git a/rasmgr/rasmgr_host.cc b/rasmgr/rasmgr_host.cc
new file mode 100644
index 0000000..0da6a43
--- /dev/null
+++ b/rasmgr/rasmgr_host.cc
@@ -0,0 +1,575 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: rasmgr_host.cc
+ *
+ * MODULE: rasmgr
+ * CLASS: ServerHost, HostManager
+ *
+ * COMMENTS:
+ * - undefine TALK_SECRET fpr production release!!!
+ *
+*/
+
+#include "rasmgr_host.hh"
+#include "rasmgr_srv.hh"
+#include "rasmgr_master.hh"
+
+#include "debug.hh"
+
+// clear this def for production release!!!
+#define TALK_SECRET(a) TALK(a)
+#ifndef DEBUG
+ #undef TALK_SECRET
+ #define TALK_SECRET(a) { /* TALK(a) */ }
+#endif // DEBUG
+
+#ifdef SOLARIS
+ #define PORTMAP // define to use function declarations for old interfaces
+ #include<rpc/rpc.h>
+ #include<rpc/pmap_clnt.h>
+#else
+ #include<rpc/rpc.h>
+ #include<rpc/pmap_clnt.h>
+#endif
+
+typedef unsigned long r_Ptr;
+
+//int _rpcpmstart = 0;
+
+// function prototype with C linkage
+//extern "C" int gethostname(char *name, int namelen);
+
+extern bool hostCmp( const char *h1, const char *h2);
+
+
+ServerHost::ServerHost()
+{
+ hostName[0]=0;
+ netwName[0]=0;
+ setNotUp();
+ isinternal=false;
+ valid=false;
+ startedServers=0;
+ isuseLocalHost=true;
+ TALK( "ServerHost::ServerHost(): hostName=" << this->hostName << ", netwName=" << this->netwName << ", listenPort=" << this->listenPort << ", isinternal=" << this->isinternal << ", valid=" << valid );
+}
+
+ServerHost::~ServerHost()
+{
+}
+
+bool ServerHost::isValid() // used for the protection element
+{
+ TALK( "ServerHost::isValid() -> " << valid );
+ return valid;
+}
+
+const char* ServerHost::getName()
+{
+ return hostName;
+}
+
+const char* ServerHost::getNetworkName()
+{
+ return netwName;
+}
+
+long ServerHost::getListenPort()
+{
+ return listenPort;
+}
+
+bool ServerHost::isInternal()
+{
+ return isinternal;
+}
+
+void ServerHost::init(const char* hostName,const char* netwName,int listenPort,bool isinternal)
+{
+ strcpy(this->hostName,hostName);
+ strcpy(this->netwName,netwName);
+
+ this->listenPort=listenPort;
+ this->isinternal=isinternal;
+
+ isup = isinternal;
+
+ valid=true;
+ TALK( "ServerHost::init(): hostName=" << this->hostName << ", netwName=" << this->netwName << ", listenPort=" << this->listenPort << ", isinternal=" << this->isinternal << ", valid=" << valid );
+}
+
+char* ServerHost::getDescriptionHeader(char *destBuffer)
+{
+ sprintf(destBuffer," %-10s %-32s %-4s %-4s %-10s ulh","Host Name","Netw. Addr","Port","Stat","Servers");
+ return destBuffer;
+}
+char* ServerHost::getDescription(char *destBuffer)
+{
+ const char* sUp= isup ? "UP ":"DOWN";
+ const char* uLh= " -";
+ long lPort = listenPort;
+
+ if(isinternal)
+ {
+ uLh = useLocalHost() ? "on":"off";
+ lPort = config.getListenPort();
+ }
+
+ sprintf(destBuffer,"%-10s %-32s %4d %-4s %2d %s",hostName,netwName,lPort,sUp,startedServers,uLh);
+
+ return destBuffer;
+}
+
+bool ServerHost::isUp()
+{
+ return isup;
+}
+
+bool ServerHost::downHost()
+{
+ // you can't stop the master with this
+ if(isinternal)
+ return false;
+
+ int socket=getConnectionSocket();
+
+ if(socket<0)
+ {
+ setNotUp();
+ //close(socket);
+ return false;
+ }
+
+ const char *text="POST downhost HTTP/1.1\r\nAccept: text/plain\r\nUserAgent: RasMGR/1.0\r\n\r\nRasMGR";
+
+ int nbytes=write(socket,text,strlen(text)+1);
+
+ isup=false;
+
+ return true;
+}
+
+bool ServerHost::checkStatus()
+{
+ if(isinternal)
+ {
+ isup=true;
+ return true;
+ }
+
+ int socket=getConnectionSocket();
+
+ if(socket<0)
+ {
+ setNotUp();
+ //close(socket);
+ TALK( "ServerHost::checkStatus() -> false (no socket)" );
+ return false;
+ }
+ const char *text="POST getstatus HTTP/1.1\r\nAccept: text/plain\r\nUserAgent: RasMGR/1.0\r\n\r\nRasMGR";
+
+ int nbytes=write(socket,text,strlen(text)+1);
+
+ if(nbytes<0)
+ {
+ setNotUp();
+ close(socket);
+ TALK( "ServerHost::checkStatus() -> false (cannot write socket)" );
+ return false;
+ }
+
+ char message[200];
+ nbytes=read(socket,message,200);
+ close(socket);
+ if(nbytes<0)
+ {
+ setNotUp();
+ TALK( "ServerHost::checkStatus() -> false (cannot read socket)" );
+ return false;
+ }
+
+ char *body=strstr(message,"\r\n\r\n");
+ if(body==NULL)
+ {
+ setNotUp();
+ TALK( "ServerHost::checkStatus() -> false (null body)" );
+ return false;
+ }
+
+ int localStartedServers; //not sure that we will provide this info
+ sscanf(body,"%d ",&localStartedServers);
+
+ isup=true;
+
+ TALK( "ServerHost::checkStatus() -> true (all done)" );
+ return true;
+} // checkStatus()
+
+int ServerHost::countDefinedServers()
+{
+ TALK_SECRET( "ServerHost::countDefinedServers enter." );
+
+ int count=0;
+ for(int i=0;i<rasManager.countServers();i++)
+ {
+ if(hostCmp(rasManager[i].getHostName(),hostName))
+ count++;
+ }
+
+ TALK_SECRET( "ServerHost::countDefinedServers leave -> " << count );
+ return count;
+}
+
+int ServerHost::getConnectionSocket()
+{
+ TALK_SECRET( "ServerHost::getConnectionSocket enter." );
+
+ // create socket
+ int sock;
+ struct protoent *getprotoptr;
+ getprotoptr=getprotobyname("tcp");
+ sock=socket(PF_INET,SOCK_STREAM,getprotoptr->p_proto);
+ int tempErrno = errno;
+ TALK_SECRET( "ServerHost::getConnectionSocket socket(PF_INET,SOCK_STREAM," << getprotoptr->p_proto << ") -> " << sock );
+ if (sock < 0)
+ {
+ TALK_SECRET( "ServerHost::getConnectionSocket cannot create socket: " << strerror( tempErrno ) );
+ return -1;
+ }
+
+ // init sockaddr
+ sockaddr_in servername;
+ struct hostent *hostinfo;
+ servername.sin_family=AF_INET;
+ servername.sin_port=htons(listenPort);
+ hostinfo=gethostbyname(netwName);
+ if(hostinfo==NULL)
+ {
+ close(sock);
+ TALK_SECRET( "ServerHost::getConnectionSocket leave (invalid hostinfo) -> -1" );
+ return -1;
+ }
+ servername.sin_addr=*(struct in_addr*)hostinfo->h_addr;
+
+ // connect to slave-manager
+ int connectResult = connect(sock,(struct sockaddr*)&servername,sizeof(servername));
+ TALK_SECRET( "ServerHost::getConnectionSocket connect() to host=" << hostinfo->h_name << ", listen port=" << servername.sin_port << " -> " << connectResult );
+ if(connectResult < 0)
+ {
+ close(sock);
+ if (errno)
+ {
+ tempErrno = errno;
+ TALK_SECRET( "ServerHost::getConnectionSocket close(" << sock << ") -> " << strerror(tempErrno) );
+ }
+ TALK_SECRET( "ServerHost::getConnectionSocket leave (cannot connect to slave mgr " << hostinfo << ") -> -1" );
+ return -1;
+ }
+
+ TALK_SECRET( "ServerHost::getConnectionSocket leave -> " << sock );
+ return sock;
+}
+
+void ServerHost::setNotUp()
+{
+ isup=false;
+ startedServers=0;
+}
+
+void ServerHost::setIsUp(bool x)
+{
+ isup=x;
+}
+
+void ServerHost::regStartServer()
+{
+ startedServers++;
+}
+
+void ServerHost::regDownServer()
+{
+ startedServers--;
+}
+
+int ServerHost::getStartedServers()
+{
+ return startedServers;
+}
+
+void ServerHost::useLocalHost(bool how)
+{
+ isuseLocalHost=how;
+}
+
+bool ServerHost::useLocalHost()
+{
+ return isinternal ? isuseLocalHost : false;
+}
+
+void ServerHost::changeName(const char *newName)
+{
+ strcpy(hostName,newName);
+}
+
+void ServerHost::changeNetName(const char *newNetName)
+{
+ strcpy(netwName,newNetName);
+}
+void ServerHost::changeListenPort(int newListenPort)
+{
+ listenPort=newListenPort;
+}
+
+//**********************************************************************
+HostManager::HostManager()
+{
+ TALK( "HostManager::HostManager()" );
+}
+
+HostManager::~HostManager()
+{
+ TALK( "HostManager::~HostManager()" );
+}
+
+bool HostManager::insertInternalHost()
+{
+ ENTER( "HostManager::insertInternalHost()" );
+
+ bool result = false; // function result
+
+ ServerHost tempServerHost;
+
+ if(hostList.empty()==false)
+ result = false;
+ else
+ {
+ //put the internal host, which is always defined, even if it has no servers attached
+ hostList.push_back(tempServerHost);
+ ServerHost &refServerHost=hostList.back();
+ const char *myhostName=config.getHostName();
+ const char *myPublicHostName=config.getPublicHostName();
+ refServerHost.init(myhostName,myPublicHostName,-1,true);
+ result = true;
+ }
+
+ LEAVE( "HostManager::insertInternalHost() -> " << result );
+ return result;
+}
+
+bool HostManager::insertNewHost(const char* hostName,const char *netwName,int listenport)
+{
+ bool result = true; // function result
+
+ ENTER( "HostManager::insertNewHost( hostName=" << hostName << ", netwName=" << netwName << ", listenport=" << listenport << " )" );
+
+ if(testUniqueness(hostName)==false)
+ result = false;
+
+ if (result == true)
+ {
+ ServerHost tempServerHost;
+
+ if(hostList.empty())
+ insertInternalHost(); // just protection, but shouldn't be necessary
+
+ hostList.push_back(tempServerHost);
+ ServerHost &refServerHost=hostList.back();
+ refServerHost.init(hostName,netwName,listenport,false); //always external
+ result = true;
+ }
+
+ LEAVE( "HostManager::insertNewHost() -> " << result );
+ return result;
+}
+
+bool HostManager::removeHost(const char *hostName)
+{
+ ENTER( "HostManager::removeHost( hostName=" << hostName << " )" );
+
+ list<ServerHost>::iterator iter=hostList.begin();
+ for(int i=0;i<hostList.size();i++)
+ {
+ if(hostCmp(iter->getName(),hostName))
+ {
+ if(iter->countDefinedServers()>0)
+ {
+ LEAVE( "HostManager::removeHost() -> false" );
+ return false;
+ }
+ hostList.erase(iter);
+ break;
+ }
+ iter++;
+ }
+
+ LEAVE( "HostManager::removeHost() -> true" );
+ return true;
+}
+
+// FIXME: check for end of list
+ServerHost& HostManager::operator[](int x)
+{
+ ENTER( "HostManager::operator[] ( x=" << x << " )" );
+
+ list<ServerHost>::iterator iter=hostList.begin();
+ for(int i=0;i<x;i++) iter++;
+
+ LEAVE( "HostManager::operator[]" );
+ return *iter;
+}
+
+// returns:
+// server host object if found
+// protElem (uninitialized object, not valid) if not found
+ServerHost& HostManager::operator[](const char* hostName)
+{
+ ENTER( "HostManager::operator[] ( hostName=" << hostName << " )" );
+
+ list<ServerHost>::iterator iter=hostList.begin();
+ for(int i=0;i<hostList.size();i++)
+ {
+ if(hostCmp(iter->getName(),hostName))
+ {
+ LEAVE( "HostManager::operator[] -> found" );
+ return *iter;
+ }
+
+ iter++;
+ }
+
+ LEAVE( "HostManager::operator[] -> not found" );
+ return protElem;
+}
+
+int HostManager::countHosts()
+{
+ return hostList.size();
+}
+int HostManager::countUpHosts()
+{
+ int count=0;
+ list<ServerHost>::iterator iter=hostList.begin();
+ for(int i=0;i<hostList.size();i++)
+ {
+ if(iter->isUp())
+ count++;
+ iter++;
+ }
+ return count;
+}
+
+bool HostManager::testUniqueness(const char* hostName)
+{
+ list<ServerHost>::iterator iter=hostList.begin();
+ for(int i=0;i<hostList.size();i++)
+ {
+ if(hostCmp(iter->getName(),hostName))
+ return false;
+ iter++;
+ }
+ return true;
+}
+
+int HostManager::postSlaveMGR(char *body,char *outBuffer)
+{
+ char answBuffer[100];
+
+ do
+ { // so we can break
+
+ if(body==NULL)
+ {
+ strcpy(answBuffer,"Missing identification, this is not a valid rasmgr."); // no rasmgr or soft error
+ break;
+ }
+
+ char name[100];
+ int licServ;
+ sscanf(body,"%s %d",name,&licServ);
+
+ TALK_SECRET( "HostManager::postSlaveMGR: name="<<name<<" lics="<<licServ );
+
+ ServerHost &sh=operator[](name);
+ if(sh.isValid()==false)
+ {
+ strcpy(answBuffer,"Unknown slave rasmgr.");
+ break;
+ }
+
+ TALK_SECRET( "HostManager::postSlaveMGR: Ok, valid." );
+ sh.setIsUp(true);
+ strcpy(answBuffer,"Welcome!");
+
+ } while(0);
+
+ sprintf(outBuffer,"HTTP/1.1 200 OK\r\nContent-type: text/plain\r\nContent-length: %d\r\n\r\n%s",strlen(answBuffer)+1,answBuffer);
+
+ return strlen(outBuffer)+1;
+}
+
+bool HostManager::reset()
+{
+ ENTER( "HostManager::reset()" );
+
+ if(config.isTestModus()==false)
+ {
+ LEAVE( "HostManager::reset() -> false" );
+ return false;
+ }
+
+ list<ServerHost>::iterator iter=hostList.begin();
+ for(int i=0;i<hostList.size();i++,iter++)
+ {
+ if(iter->countDefinedServers()>0)
+ {
+ LEAVE( "HostManager::reset() -> false" );
+ return false;
+ }
+ }
+
+ while(hostList.size())
+ {
+ hostList.pop_front();
+ }
+
+ LEAVE( "HostManager::reset() -> true" );
+ return true;
+}
+
+bool HostManager::acceptChangeName(const char *oldName,const char *newName)
+{
+ if(hostCmp(oldName,newName))
+ return true; // if someone really wants to change a name with the same,
+
+ return testUniqueness(newName);
+}
+
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+
+void rpcif_1(struct svc_req *rqstp, register SVCXPRT *transp)
+{ // this function is registered by rpc-system. No one can use it, because it's never called
+ //(we do not have a svc_run() - call, thus it's not doing anything
+}
+
diff --git a/rasmgr/rasmgr_host.hh b/rasmgr/rasmgr_host.hh
new file mode 100644
index 0000000..0e6e4e4
--- /dev/null
+++ b/rasmgr/rasmgr_host.hh
@@ -0,0 +1,122 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: rasmgr_host.hh
+ *
+ * MODULE: rasmgr
+ * CLASS: ServerHost, HostManager
+ *
+ * COMMENTS:
+ * none
+ *
+*/
+
+#ifndef RASMGR_HOST_HH
+#define RASMGR_HOST_HH
+
+#include "rasmgr.hh"
+#include "rasmgr_config.hh"
+
+//In normal release there can be just one RasMGR on a host
+//But for testing we provide the possibility to put more than one on a host
+//Just for fun, we call the unique RasMGR on a host the HIGHLANDER (thanks to Peter Zoller)
+//So, for normal release, just...
+//#define HIGHLANDER
+
+class ServerHost
+ {
+ public:
+ ServerHost();
+ ~ServerHost();
+ void init(const char* hostName,const char *netwName,int listenport,bool isInternal);
+ const char *getName();
+ const char *getNetworkName();
+ long getListenPort();
+ bool isInternal();
+ bool checkStatus();
+
+ int getStartedServers();
+ int getLicensedServers();
+
+ bool isUp();
+ bool downHost();
+
+ static char* getDescriptionHeader(char *destBuffer);
+ char* getDescription(char *destBuffer);
+
+ int countDefinedServers();
+ int getConnectionSocket();
+ void regStartServer();
+ void regDownServer();
+ void setIsUp(bool);
+
+ void useLocalHost(bool);
+ bool useLocalHost();
+
+ void changeName(const char*);
+ void changeNetName(const char*);
+ void changeListenPort(int);
+
+ bool isValid();
+ bool reset();
+ private:
+ void setNotUp();
+ char hostName[100];
+ char netwName[100];
+ int listenPort;
+ int startedServers;
+ bool isup;
+ bool isinternal;
+ bool isuseLocalHost; // if internal, use localhost instead of network name, default on!
+
+ bool valid;
+ };
+
+class HostManager
+ {
+ public:
+ HostManager();
+ ~HostManager();
+ bool insertInternalHost();
+ bool checkAcceptAnotherHost();
+ bool insertNewHost(const char* hostName,const char *netwName,int listenport);
+ bool removeHost(const char *hostName);
+ int countHosts();
+ int countUpHosts();
+ ServerHost& operator[](int);
+ ServerHost& operator[](const char* hostName);
+
+ int postSlaveMGR(char *body,char *outBuffer);
+ bool reset();
+ bool acceptChangeName(const char *oldName,const char *newName);
+ private:
+ bool testUniqueness(const char* srvName);
+ list<ServerHost> hostList;
+ ServerHost protElem;
+ };
+
+extern HostManager hostmanager;
+
+
+#endif
+
diff --git a/rasmgr/rasmgr_localsrv.cc b/rasmgr/rasmgr_localsrv.cc
new file mode 100644
index 0000000..0d16318
--- /dev/null
+++ b/rasmgr/rasmgr_localsrv.cc
@@ -0,0 +1,368 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: rasmgr_localsrv.cc
+ *
+ * MODULE: rasmgr
+ * CLASS: LocalServer, LocalServerManager
+ *
+ * PURPOSE:
+ * management of rasserver executables
+ *
+ * COMMENTS:
+ * None
+ *
+*/
+
+using namespace std;
+
+#include "rasmgr_localsrv.hh"
+#include "rasmgr_master.hh"
+#include "rasmgr_srv.hh"
+#include <signal.h>
+#include <time.h>
+
+#include "raslib/rminit.hh"
+
+#include "debug.hh"
+
+
+// aux function for now() to avoid a compiler warning (see 'man strftime')
+size_t my_strftime(char *s, size_t max, const char *fmt, const struct tm *tm)
+{
+ return strftime(s, max, fmt, tm);
+}
+
+// now(): aux function returning, as a static string, the current time
+// keep in sync with same function in rasserver
+const char* now()
+{
+ size_t strfResult = 0; // return value of strftime()
+ static char timestring[50]; // must hold 20+1 chars
+
+ time_t t = time(NULL); // get time
+ struct tm* tm = localtime(&t); // break down time
+ strfResult = my_strftime( timestring, sizeof(timestring), "[%F %T]", tm ); // format time
+ if (strfResult == 0) // bad luck? then take fallback message
+ (void) strncpy( timestring, "[-no time available-]", sizeof(timestring) );
+ return( timestring );
+}
+
+LocalServer::LocalServer()
+ { serverName[0]=0;
+ valid=false;
+ serverPid=0;
+ }
+
+void LocalServer::init(const char *name,pid_t p)
+ { strcpy(serverName,name);
+ serverPid=p;
+ valid=true;
+ }
+const char* LocalServer::getName()
+ { return serverName;
+ }
+
+pid_t LocalServer::getPID()
+ { return serverPid;
+ }
+bool LocalServer::isValid()
+ { return valid;
+ }
+
+//#######################################
+void catch_SIGCHLD(int)
+ { localServerManager.childSignalIn();
+ }
+//#######################################
+
+LocalServerManager::LocalServerManager()
+ { wasSignal=false;
+
+ signal (SIGCHLD, catch_SIGCHLD);
+ }
+LocalServerManager::~LocalServerManager()
+ {
+ }
+bool LocalServerManager::startNewServer(const char* commandline)
+ {
+ ENTER( "LocalServerManager::startNewServer: enter. cmdLine=" << commandline );
+ char localcomm[300];
+ strcpy(localcomm,commandline);
+
+ int i;
+ const int maxarg=50;
+ char* argv[maxarg]; // rasserver command line
+ char* fileName; // name of executable, e.g., "rasserver"
+ char* serverName; // symbolic server name, e.g., "S1"
+
+ char *pos=localcomm;
+
+ for(i=0;i<maxarg;i++)
+ {
+#define WHITESPACE " \t\r\n"
+ argv[i]=strtok(pos, WHITESPACE );
+ pos=NULL; // for subsequent calls to strtok
+ if(argv[i]==NULL) break;
+ }
+ argv[maxarg-1]=0; // for security reasons
+
+ serverName=argv[0];
+ fileName =argv[1];
+
+ LocalServer &lcs=operator[](serverName);
+ if(lcs.isValid())
+ { VLOG <<"Server "<<serverName<<" is already up."<<std::endl;
+ LEAVE( "LocalServerManager::startNewServer: leave. srv already up, result=false." );
+ return false;
+ }
+
+ // return false;
+ pid_t pid=fork();
+
+ if(pid!=0)
+ { //parent
+ LocalServer temp;
+ temp.init(serverName,pid);
+ srvList.push_back(temp);
+ TALK( "LocalServerManager::startNewServer: leave. parent process. result=true." );
+ VLOG << now() << " starting server "<<serverName<<", executable " << fileName << "; pid "<<pid<< "..." << flush;
+
+ }
+ else
+ { //child
+
+ TALK( "LocalServerManager::startNewServer: leave. child process, fileName=" << fileName );
+
+ masterCommunicator.closeForcedAllSockets();
+
+ execvp(fileName, argv+2);
+ int execErrno = errno;
+ std::cout<<"Error: cannot fork server "<<fileName<< ": " << strerror (execErrno) << std::endl;
+ TALK( "LocalServerManager::startNewServer: cannot fork server "<<fileName<< ": " << strerror (execErrno) );
+ exit(1); // if return from exec...
+ }
+
+ LEAVE( "LocalServerManager::startNewServer: leave. result=true." );
+ return true;
+ }
+int LocalServerManager::countStartedServers()
+ { return srvList.size();
+ }
+
+// sendTerminateSignal: terminate server process.
+// if name is in list of known servers, try to terminate; otherwise, complain & do nothing.
+// returns:
+// true iff server was found and killed successfully
+// false on error
+bool LocalServerManager::sendTerminateSignal(const char *serverName)
+{
+ ENTER( "LocalServerManager::sendTerminateSignal: enter. serverName=" << serverName );
+
+ bool found = false; // list entry pertaining to serverName found?
+ bool result = false; // function result
+
+ list<LocalServer>::iterator iter=srvList.begin();
+ for ( int i=0; i<srvList.size() && ! found; i++)
+ {
+ if(strcmp(iter->getName(),serverName)==0)
+ {
+ found = true;
+ VLOG << now() << " shutting down rasdaman server " << iter->getName() << ", pid " << iter->getPID() << "..." << flush;
+ int killResult = kill(iter->getPID(),SIGTERM);
+ if (killResult == -1)
+ {
+ cout << "Error: " << strerror(errno) << endl;
+ result = false;
+ }
+ else
+ {
+ iter = srvList.erase(iter);
+ VLOG << "ok" << endl;
+ result = true;
+ break;
+ }
+ }
+
+ iter++;
+ } // for
+
+ if (!found)
+ {
+ cout << "failed: server unknown." << endl;
+ result = false;
+ }
+
+ LEAVE( "LocalServerManager::sendTerminateSignal: leave. result=" << result );
+ return result;
+}
+
+// killServer: terminate server process.
+// if name is in list of known servers, try to kill; otherwise, complain & do nothing.
+// returns:
+// true iff server was found and killed successfully
+// false on error
+bool LocalServerManager::killServer(const char *serverName)
+{
+ ENTER( "LocalServerManager::killServer: enter. serverName=" << serverName );
+
+ bool found = false; // list entry pertaining to serverName found?
+ bool result = false; // function result
+
+ list<LocalServer>::iterator iter=srvList.begin();
+ for(int i=0;i<srvList.size();i++)
+ {
+ if(strcmp(iter->getName(),serverName)==0)
+ {
+ found = true;
+ VLOG << now() << " killing rasdaman server " << iter->getName() << ", pid " << iter->getPID() << "..." << flush;
+
+ int killResult = kill(iter->getPID(),SIGKILL);
+ if (killResult == -1)
+ {
+ cout << "Error: " << strerror(errno) << endl;
+ result = false;
+ }
+ else
+ {
+ iter = srvList.erase(iter);
+ VLOG << "ok" << endl;
+ result = true;
+ break;
+ }
+ }
+ iter++;
+ }
+
+ if (!found)
+ {
+ cout << "failed: server unknown." << endl;
+ result = false;
+ }
+
+ LEAVE( "LocalServerManager::killServer: leave. result=" << result );
+ return result;
+}
+
+LocalServer& LocalServerManager::operator[](int x)
+ { list<LocalServer>::iterator iter=srvList.begin();
+ for(int i=0;i<x;i++) iter++;
+ return *iter;
+
+ }
+LocalServer& LocalServerManager::operator[](const char* srvName)
+ {
+ ENTER( "LocalServerManager::operator[]: enter. srvName=" << srvName );
+ list<LocalServer>::iterator iter=srvList.begin();
+ for(int i=0;i<srvList.size();i++)
+ {
+ if(strcmp(iter->getName(),srvName)==0)
+ {
+ LEAVE( "LocalServerManager::operator[]: leave. valid=" << (*iter).isValid() );
+ return *iter;
+ }
+ iter++;
+ }
+ LEAVE( "LocalServerManager::operator[]: leave. valid=" << protElem.isValid() );
+ return protElem;
+ }
+
+void LocalServerManager::childSignalIn() //only signal calls this
+ { wasSignal=true;
+ }
+void LocalServerManager::cleanChild()
+ {
+ ENTER( "LocalServerManager::cleanChild: enter." );
+
+ if(wasSignal==false)
+ {
+ LEAVE( "LocalServerManager::cleanChild: leave. !wasSignal." );
+ return;
+ }
+
+#define WAITFORANYCHILD -1
+
+ while(1)
+ { signal (SIGCHLD, catch_SIGCHLD); // some SO requieres this, otherwise they reset to default
+
+ int status=0;
+ int exitpid=waitpid(WAITFORANYCHILD,&status,WNOHANG);
+
+ if(exitpid==0)
+ break; // no child died
+
+ // I'd love to put this code into a textbook as a negative example and cite you, Walter! -- PB 2003-nov-25
+ if(exitpid==-1)
+ {
+ if(errno == EINTR)
+ continue;
+ break; // another error;
+ }
+ VLOG << "rasdaman server process with pid " << exitpid << " has terminated." << std::endl;
+
+ list<LocalServer>::iterator iter=srvList.begin();
+ for(int i=0;i<srvList.size();i++)
+ {
+ TALK( "LocalServerManager::cleanChild: inspecting rasdaman server " << iter->getName() << "." );
+ if(iter->getPID()==exitpid)
+ {
+ TALK( "LocalServerManager::cleanChild: rasdaman server " << iter->getName() << " terminated illegally, status=" << status );
+
+ cout<<"Error: rasdaman server " << iter->getName() << ", pid " << exitpid << " terminated illegally, reason: ";
+ // see 'man waitpid': decoding of status variable
+ if (WIFEXITED(status) != 0)
+ cout << "exited with return code " << WEXITSTATUS(status);
+ else if (WIFSIGNALED(status))
+ cout << "uncaught signal " << WTERMSIG(status);
+ else
+ cout << "(unknown reason)";
+ cout << endl;
+
+ // choices: restart silently the dead server or
+ // just tell the manager about it
+ // Not restart from here, because of sync problem for capabilities, master has to do that!!!
+ LocalServer temp=*iter;
+ srvList.erase(iter);
+
+ reportDeadServer(temp);
+ break;
+ }
+ iter++;
+ } // for
+ } //while
+
+ wasSignal=false;
+ LEAVE( "LocalServerManager::cleanChild: leave." );
+ }
+
+void LocalServerManager::reportDeadServer(LocalServer &srv)
+ {
+ ENTER( "LocalServerManager::reportDeadServer: enter." );
+
+ int dummy = -1;
+ RasServer &r=rasManager[srv.getName()];
+
+ if(r.isValid()) r.changeStatus(SERVER_CRASHED,dummy);
+ LEAVE( "LocalServerManager::reportDeadServer: leave." );
+ }
+
diff --git a/rasmgr/rasmgr_localsrv.hh b/rasmgr/rasmgr_localsrv.hh
new file mode 100644
index 0000000..3e10fd2
--- /dev/null
+++ b/rasmgr/rasmgr_localsrv.hh
@@ -0,0 +1,81 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: rasmgr_localsrv.hh
+ *
+ * MODULE: rasmgr
+ * CLASS: LocalServer, LocalServerManager
+ *
+ * PURPOSE:
+ * management of rasserver executables
+ *
+ * COMMENTS:
+ * None
+ *
+*/
+
+#ifndef RASMGR_LOCALSRV_HH
+#define RASMGR_LOCALSRV_HH
+
+#include "rasmgr.hh"
+
+
+class LocalServer
+ {
+ public:
+ LocalServer();
+ void init(const char*,pid_t);
+ const char* getName();
+ pid_t getPID();
+ bool isValid();
+ private:
+ char serverName[30];
+ pid_t serverPid;
+ bool valid;
+ };
+
+class LocalServerManager
+ {
+ public:
+ LocalServerManager();
+ ~LocalServerManager();
+ bool startNewServer(const char* commandline);
+ int countStartedServers();
+ bool sendTerminateSignal(const char *serverName);
+ bool killServer(const char *serverName);
+
+ LocalServer& operator[](int);
+ LocalServer& operator[](const char* srvName);
+
+ void childSignalIn(); //only signal calls this
+ void cleanChild();
+ private:
+ void reportDeadServer(LocalServer &);
+ bool wasSignal;
+ std::list<LocalServer> srvList;
+ LocalServer protElem;
+
+ };
+
+extern LocalServerManager localServerManager;
+#endif
diff --git a/rasmgr/rasmgr_main.cc b/rasmgr/rasmgr_main.cc
new file mode 100644
index 0000000..4399d13
--- /dev/null
+++ b/rasmgr/rasmgr_main.cc
@@ -0,0 +1,256 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: rasmgr_main.cc
+ *
+ * MODULE: rasmgr
+ * CLASS:
+ *
+ * PURPOSE:
+ * management of rasserver executables
+ *
+ * COMMENTS:
+ * - FIXME: looks like a rasmgr slave still uses old comm scheme -- compatible?
+ *
+*/
+
+#include <iostream>
+
+#include "rasmgr.hh"
+#include "rasmgr_config.hh"
+#include "rasmgr_host.hh"
+#include "rasmgr_dbm.hh"
+#include "rasmgr_srv.hh"
+#include "rasmgr_master.hh"
+#include "rasmgr_rascontrol.hh"
+#include "rasmgr_users.hh"
+#include "ras_crypto.hh"
+#include "rasmgr_localsrv.hh"
+#include "rasmgr_error.hh"
+
+#ifndef COMPDATE
+#error "Please specify the COMPDATE variable!"
+/*
+COMPDATE=`date +"%d.%m.%Y %H:%M:%S"`
+
+and -DCOMPDATE="\"$(COMPDATE)\"" when compiling
+*/
+#endif
+
+#define DEBUG_MAIN
+#undef DEBUG_HH
+#include "debug.hh"
+
+
+Configuration config;
+
+HostManager hostmanager;
+DatabaseHostManager dbHostManager;
+DatabaseManager dbManager;
+RasServerManager rasManager;
+MasterComm masterCommunicator;
+RasControl rascontrol;
+UserManager userManager;
+Authorization authorization;
+LocalServerManager localServerManager;
+RandomGenerator randomGenerator;
+
+void installSignalHandlers();
+
+int main(int argc, char** argv, char** envp)
+{
+ SET_OUTPUT( true ); // enable debugging trace, if compiled so
+
+ ENTER( "main." );
+
+ std::cout<< "rasmgr: rasdaman server manager tool. rasdaman v" << RMANVERSION / 1000. << " -- generated on " << COMPDATE << "." << std::endl;
+
+// just to see the difference between an official release and the inside development version
+#ifdef NO_OFFICIAL_RELEASE
+ std::cout<<"This is not the official release version, it supports test modus and rasserver in debugger"<<std::endl;
+#else
+ std::cout << " Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann rasdaman GmbH." << std::endl
+ << "Rasdaman community is free software: you can redistribute it and/or modify "
+ "it under the terms of the GNU General Public License as published by "
+ "the Free Software Foundation, either version 3 of the License, or "
+ "(at your option) any later version. \n"
+ "Rasdaman community is distributed in the hope that it will be useful, "
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of "
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the "
+ "GNU General Public License for more details. \n\n";
+
+ std::cout << "This software contains software which is in the public domain:" << std::endl;
+ std::cout << "- openssl 0.96c (C) 1998-2002 The OpenSSL Project, (C) 1995-1998 Eric A. Young, Tim J. Hudson" << std::endl;
+#endif
+
+#ifdef INCLUDE_HIDDEN_COMMANDS
+ std::cout << "This version is 'inside only'" <<std::endl;
+#endif
+
+ if(testIsMessageDigestAvailable("MD5")==false)
+ {
+ std::cout<<"Error: Message Digest MD5 not available."<<std::endl;
+ return RASMGR_RESULT_NO_MD5;
+ }
+
+ installSignalHandlers();
+
+ bool result = config.interpretArguments(argc,argv,envp);
+ if (result == false)
+ return RASMGR_RESULT_ILL_ARGS;
+
+ if(config.isTestModus())
+ {
+ std::cout<<"rasmgr running in test modus ";
+ VLOG <<", listening on port=" << config.getListenPort() << std::endl;
+ }
+ else
+ {
+ VLOG << " rasmgr running on " << config.getHostName() << ", listening on port " << config.getListenPort();
+ VLOG << " with poll timeout " << config.getPollFrequency() << " seconds. ";
+ }
+
+ if(config.isTestModus()==false)
+ {
+ TALK( "hostname=" << config.getHostName() << ", publicHostname=" << config.getPublicHostName() );
+ if(strcmp(config.getHostName(),config.getPublicHostName()) != 0)
+ {
+ VLOG <<"Advertised host name is "<<config.getPublicHostName()<<std::endl;
+ }
+
+ bool resultConfig = config.readConfigFile();
+ TALK( "rasmgr::main: resultConfig=" << resultConfig );
+ rascontrol.setConfigDirty( false ); // all changes to config up to now come from config file, do not require save
+
+ int resultAuth = authorization.readAuthFile();
+ TALK( "rasmgr::main: resultAuth=" << resultAuth );
+ switch( resultAuth )
+ {
+ case RC_OK:
+ TALK( "rasmgr::main: auth file ok, set state to not dirty." );
+ rascontrol.setAuthDirty( false ); // auth file ok, so clean init state
+ break;
+ case ERRAUTHFNOTF:
+ TALK( "rasmgr::main: auth file not found, loading defaults." );
+ userManager.loadDefaults();
+ // disabled because otherwise tons of new auth files are generated -- PB 2005-jul-02
+ // rascontrol.setAuthDirty( true ); // auth file not present, write default
+ break;
+ case ERRAUTHFCORR:
+ LEAVE( "rasmgr::main: auth file corrupt." );
+ return RASMGR_RESULT_AUTH_CORRUPT;
+ break;
+ case ERRAUTHFWRHOST:
+ LEAVE( "rasmgr::main: auth file for another host." );
+ return RASMGR_RESULT_AUTH_OTHERHOST;
+ break;
+ case ERRAUTHFVERS:
+ LEAVE( "rasmgr::main: auth file version mismatch." );
+ return RASMGR_RESULT_AUTH_INCOMPAT;
+ break;
+ default: // should not occur, internal enum mismatch
+ LEAVE( "rasmgr::main: illegal auth file result code " << resultAuth << ", internal error." );
+ return RASMGR_RESULT_INTERNAL;
+ break;
+ }
+
+ try
+ {
+ BenchmarkTimer *totalTimePtr = new BenchmarkTimer("Total master time");
+
+ TALK( "launching masterCommunicator.Run()..." );
+ masterCommunicator.Run(); // central request handling loop
+ TALK( "masterCommunicator.Run() done." );
+
+ totalTimePtr->result(); // print total time elapsed
+ }
+ catch(RCError& e)
+ {
+ char *errorMsg;
+ e.getString(errorMsg);
+ std::cout<<"Error: "<<errorMsg<<std::endl;
+ }
+
+// write the config file only on explicit rascontrol request "save"
+// (and at that moment), or at rascontrol "exit" to a rescue file -- PB 2003-jun-06
+#ifdef NEVER_AGAIN
+ if(!config.saveConfigFile())
+ {
+ std::cout<<"Error saving configuration file."<<std::endl;
+ }
+
+ if(!authorization.saveAuthFile())
+ {
+ std::cout<<"Error saving user authorization file."<<std::endl;
+ }
+#endif
+ }
+
+ else if(config.isTestModus())
+ {
+ hostmanager.insertInternalHost();
+ userManager.loadDefaults();
+ masterCommunicator.Run();
+ }
+
+ cout <<"rasmgr terminated."<<std::endl;
+
+ int retval = RASMGR_RESULT_OK;
+ LEAVE( "main: leave. retval=" << retval );
+ return retval;
+} // main()
+
+// danger: cout in interrupt???
+// handler for SIGINT and SIGTERM = call for exit
+void SigIntHandler(int sig)
+{
+ std::cout<<"rasmgr received terminate signal...";
+ masterCommunicator.shouldExit();
+}
+
+void installSignalHandlers()
+{
+ signal (SIGINT, SigIntHandler);
+ signal (SIGTERM, SigIntHandler);
+ signal (SIGHUP, SIG_IGN);
+ signal (SIGPIPE,SIG_IGN);
+ signal (SIGTTOU,SIG_IGN); // no console, ei si?
+}
+
+// should be replaced by something cleaner, eventually
+void exitbyerror(const char* text)
+{
+ perror(text);
+ exit( RASMGR_EXIT_FAILURE );
+}
+
+char *strtolwr(char *string)// should be somewhere in the C-library, but can't find it
+{
+ char *t=string;
+ for(;*t;t++)
+ {
+ if(*t>='A' && *t<='Z') *t|='a'-'A';
+ }
+ return string;
+}
+
diff --git a/rasmgr/rasmgr_master.hh b/rasmgr/rasmgr_master.hh
new file mode 100644
index 0000000..d7b639e
--- /dev/null
+++ b/rasmgr/rasmgr_master.hh
@@ -0,0 +1,136 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: rasmgr_master.hh
+ *
+ * MODULE: rasmgr
+ * CLASS: MasterComm
+ *
+ * PURPOSE:
+ * Main loop of master rasmgr
+ *
+ * COMMENTS:
+ * None
+ *
+*/
+
+#ifndef RASMGR_MASTER_HH
+#define RASMGR_MASTER_HH
+
+#include "rasmgr_comm_nb.hh"
+#include <deque>
+#include<string>
+
+class ClientID
+ {
+ public:
+ ClientID();
+ void init(const char*);
+
+ bool operator==(const ClientID&);
+ bool operator!=(const ClientID&);
+
+ std::string getID() const;
+ bool isValid() const;
+ private:
+ std::string idstring;
+ bool valid;
+ friend std::ostream& operator<<(std::ostream&, const ClientID&);
+ };
+
+
+class ClientQueue
+ {
+ public:
+ ClientQueue();
+ ~ClientQueue();
+
+ void put(ClientID&, const char *dbName, char serverType, int errorCode);
+
+ // the answer is 0 or the errorcode
+ int canBeServed(ClientID&, const char *dbName, char serverType, bool fake);
+
+ private:
+ struct ClientEntry
+ {
+ bool activ;
+ ClientID clientID;
+ std::string dbName;
+ char serverType;
+ int errorCode;
+ time_t lastAction;
+ time_t timeLimit;
+
+ bool wasfake;
+
+ ClientEntry();
+ ClientEntry(ClientID &client, const char *dbName, char serverType, int errorCode);
+
+ bool shouldWeCleanup(bool fake);
+ void updateTime();
+
+ bool isTimeout();
+ };
+
+ std::deque<ClientEntry> clients;
+
+ };
+
+class MasterComm:public NbServerComm
+ {
+ public:
+ MasterComm();
+ ~MasterComm();
+ void Run();
+ void commitChanges();
+ void commitAuthFile();
+ private:
+ bool isMessage(const char *messageStart);
+ int getFreeServer(bool fake);
+ const char* convertAnswerCode(int code);
+
+// int getFakeFreeServer();
+ int answerAccessDenied();
+ int answerAccessDeniedCode();
+ void doCommit();
+
+ bool commit;
+ bool commitAuthOnly;
+
+ void processJob( NbJob &currentJob );
+ int processRequest( NbJob &currentJob );
+
+ bool fillInBuffer(const char*);
+ char *header;
+ char *body;
+ char inBuffer[MAXMSG];
+ char outBuffer[MAXMSGOUTBUFF];
+
+ bool allowMultipleWriteTransactions;
+
+ ClientQueue clientQueue;
+ };
+
+extern MasterComm masterCommunicator;
+
+#endif
diff --git a/rasmgr/rasmgr_master_nb.cc b/rasmgr/rasmgr_master_nb.cc
new file mode 100644
index 0000000..42e1cb4
--- /dev/null
+++ b/rasmgr/rasmgr_master_nb.cc
@@ -0,0 +1,1007 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: rasmgr_master_nb.cc
+ *
+ * MODULE: rasmgr
+ * CLASS: MasterComm
+ *
+ * PURPOSE:
+ * Main loop of master rasmgr
+ *
+ * COMMENTS:
+ * - MasterComm::processRequest() is the central dispatcher for rasmgr requests, recognising and executing them.
+ *
+*/
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "rasmgr_master.hh"
+#include "rasmgr_config.hh"
+#include "rasmgr_rascontrol.hh"
+#include "rasmgr_users.hh"
+#include "rasmgr_host.hh"
+#include "rasmgr_localsrv.hh"
+#include "rasmgr_srv.hh"
+
+using namespace std;
+
+#include "debug.hh"
+
+
+// from rasmgr_localsrv.cc; should go to a central location -- PB 2003-nov-25
+extern char *now();
+
+// rasserver error codes (see errtxts)
+// FIXME: should go into a central include file / class -- PB 2003-nov-20
+#define MSG_OK 200
+#define MSG_OK_STR "Ok"
+#define MSG_UNKNOWNSERVERTYPE 1001
+#define MSG_UNKNOWNSERVERTYPE_STR "Unknown server type"
+#define MSG_UNKNOWNACCESSTYPE 1002
+#define MSG_UNKNOWNACCESSTYPE_STR "Unknown access type"
+#define MSG_DATABASENOTFOUND 807
+#define MSG_DATABASENOTFOUND_STR "Database not found"
+#define MSG_WRITETRANSACTION 806
+#define MSG_WRITETRANSACTION_STR "Write transaction in progress"
+#define MSG_NOSUITABLESERVER 805
+#define MSG_NOSUITABLESERVER_STR "No suitable servers started"
+#define MSG_SYSTEMOVERLOADED 801
+#define MSG_SYSTEMOVERLOADED_STR "System overloaded"
+// the following code means: I got an error code which I don't know (FIXME: reconsider nr!)
+#define MSG_ILLEGAL 999
+#define MSG_ILLEGAL_STR "Internal error: Illegal response code."
+
+// here I start collecting rasmgr protocol tokens to eventually gather them all in one include file
+#define RASMGRPROT_EOL "\r\n"
+#define RASMGRPROT_DOUBLE_EOL "\r\n\r\n"
+
+// time [secs] until a client can be freed from the pending request list after a fake request
+#define WAITTIME_AFTER_FAKE 2
+// time increment [secs] of iterated timeout (see updateTime())
+#define WAITTIME_REPEATED 3
+
+
+MasterComm::MasterComm()
+ { commit=false;
+ allowMultipleWriteTransactions = false;
+ }
+
+MasterComm::~MasterComm()
+ {
+ }
+
+void MasterComm::Run()
+ {
+ ENTER("MasterComm::Run: enter." );
+
+ initListenSocket(config.getListenPort()); // connect/bind the central listen socket
+ // using IOSelector level here!
+
+ initJobs(MAXJOBSMASTER); // init jobs structure (nothing with sockets here)
+
+ allowMultipleWriteTransactions = config.allowMultipleWriteTransactions();
+
+ selector.setTimeout( config.getPollFrequency() , 0 );
+
+ VLOG << "Entering server mode, prepared to receive requests." << endl << endl;
+
+ while(mayExit()==false)
+ {
+ TALK("MasterComm::Run: new request cycle, status before processing is:" );
+ printStatus();
+
+ if(commit)
+ doCommit();
+
+ int answerLen=0;
+
+ TALK("MasterComm::Run: (c) Waiting...");
+
+ // wait for incoming requests, using select()
+ int r=selector.waitForRequest(); // 0 is timeout, <0 error, >0 success
+ // again, IOSelector level here!
+
+ TALK("MasterComm::Run: (d) It's ringing..." << r);
+
+ localServerManager.cleanChild(); // sa fie
+
+ if(r<0) // nothing to read
+ {
+ TALK("MasterComm::Run: (f1) it's a signal (or a socket failure)...");
+ continue;
+ }
+ if(r==0) // timeout, nothing to read
+ {
+ TALK("MasterComm::Run: (f2) nothing, look for timeouts...");
+ lookForTimeout();
+ continue;
+ }
+ if(r>0) // something is pending
+ {
+
+ TALK("MasterComm::Run: (e) Got request, r=" << r << "...");
+
+ // iterate over all jobs to see what we can read / reconnect (?) / write
+ dispatchWriteRequest(); // first this, to increase the chance to free a client
+ connectNewClients(); // wait for requests, using accept()
+ dispatchReadRequest(); // now read in new requests
+
+ for(int i=0;i<maxJobs;i++)
+ {
+ TALK( "- request processing: " << i ); // fake similar entry to benchmark logger
+ // creates too large log files, so omit in production:
+ // BenchmarkTimer *bPtr = new BenchmarkTimer("request processing");// print job start time to log
+
+ processJob(job[i]); // this can involve closing the connection!
+
+ // creates too large log files, so omit in production:
+ // bPtr->result(); // print stop time to log
+ }
+ }
+ }
+ LEAVE("MasterComm::Run: leave." );
+ } // Run()
+
+// keep connection open after processing request?
+// ...according to request type and comm success, shall we keep socket open?
+// Note: this is a bad hack, but I don't want to change the "answer" ret code of processRequest() unless I fully understand it -- PB 2003-jun-10
+static bool keepConnection;
+
+void MasterComm::processJob(NbJob &currentJob)
+ {
+ ENTER( "MasterComm::processJob: enter." );
+
+ if(currentJob.isOperationPending()==false )
+ {
+ LEAVE( "MasterComm::processJob: leave. isOperationPending=false" );
+ return;
+ }
+
+ if(currentJob.wasError()) // low-level comm error
+ {
+ TALK( "MasterComm::processJob: closing connection." );
+ currentJob.closeConnection();
+ LEAVE( "MasterComm::processJob: leave." );
+ return;
+ }
+
+ if(currentJob.isMessageOK() == false)
+ {
+ LEAVE( "MasterComm::processJob: leave. isMessageOK=false" );
+ return;
+ }
+
+ if(fillInBuffer(currentJob.getMessage())==false) // fill msg into answer buffer header + body
+ {
+ TALK( "MasterComm::processJob: closing connection." );
+ currentJob.closeConnection();
+ LEAVE( "MasterComm::processJob: leave. fillInBuffer=false" );
+ return;
+ }
+
+ // now we have the message in inBuffer, with header and body set correctly
+
+ int answer = processRequest( currentJob );
+
+ int outLen = strlen(outBuffer);
+
+ if(outLen && answer != 2) // sending the answer
+ // FIXME: what is answer==2 ? never happens! -- PB 2003-jun-10
+ {
+ TALK( "MasterComm::processJob: init sending answer for outBuffer, set socket to write mode." );
+ currentJob.initSendAnswer(outBuffer);
+ }
+
+ if(outLen == 0) // no answer to send
+ {
+ TALK( "MasterComm::processJob: no answer to send, closing connection." );
+ currentJob.closeConnection();
+ }
+
+ if( answer == 1 ) // means "delayedOperation"
+ // FIXME: according to processRequest, delOp is 0 !!! -- PB 2003-jun-10
+ // ...and 1 comes back for POST rasservernewstatus
+ { // the only known until now
+ TALK( "MasterComm::processJob: delayedOp, therefore changeServerStatus()." );
+ rasManager.changeServerStatus(body);
+ }
+ /* Two words about this delayedOperation. If a remote server crashes, the remote rasmgr
+ sends a message and does not wait for answer. But if the master rasmgr restarts
+ immediately the crashed server, it could come to a deadlock. Maybe not, but we
+ wish to avoid any possibility, so we close first the connection and then attempt
+ to restart the server.
+ */
+
+ // EXPERIMENTAL: close sockets as soon and as always as possible
+ // if (! keepConnection) // singleton request or comm error
+ // {
+ // TALK( "MasterComm::processJob: singleton request, closing connection." );
+ // currentJob.closeConnection();
+ // }
+
+ LEAVE( "MasterComm::processJob: leave." );
+ } // processJob()
+
+
+// printClientAddr(): aux fct to print client address to designated stream
+const char *getClientAddr( int mySocket )
+{
+ const char *result = NULL;
+ struct sockaddr_in s;
+ socklen_t sockaddrSize = (socklen_t) sizeof(s);
+ if ( getpeername( mySocket, (struct sockaddr*)&s, &sockaddrSize ) != 0)
+ result = strerror(errno);
+ else
+ result = inet_ntoa(s.sin_addr);
+ return result;
+}
+
+// process request which has been prepared in inBuffer
+// if 'verbose' is enabled in configuration then requests will be logged.
+// returns
+// 0 normally (?)
+// 1 for POST rasservernewstatus
+// NB: keepConnection is static above -- bad hack, see there
+int MasterComm::processRequest( NbJob &currentJob )
+{
+ ENTER( "MasterComm::processRequest: enter. inBuffer=" << inBuffer );
+
+ // inBuffer: header + body Ok, output in outBuffer, which is not initialized here
+ outBuffer[0]=0; // mark outBuffer as empty
+ int answer = 0;
+ // delayedOperation = 0;
+
+ bool fake = false; // getfreeserver request really wants to allocate a new server?
+
+ // --- this is the central dispatcher for rasmgr requests, recognising and executing them.
+
+ if(isMessage("POST rasmgrslave"))
+ {
+ VLOG << now() << " slave rasmgr request from "
+ << getClientAddr( currentJob.getSocket() )
+ << ": '" << body << "'..." << flush;
+
+ hostmanager.postSlaveMGR(body,outBuffer); // prepare outBuffer from body for send to slave
+ keepConnection = false; // master mgr passes thru, it's singleton commo, so don't keep conn
+ // FIXME: is this really correct?? -- PB 2003-jun-10
+ VLOG << "ok" << endl;
+ }
+ else if(isMessage("POST rasservernewstatus"))
+ {
+ // extract server status from msg body
+ char serverName[50];
+ int newstatus = 0;
+ long dummy = 0;
+ serverName[0] = '\0'; // initialize in case sscanf() fails
+
+ int result = sscanf( body, "%s %d %ld", serverName, &newstatus, &dummy);
+ if (result == 3) // we simply ignore malformed requests, reason see below
+ {
+ const char *statusText = NULL;
+ switch (newstatus)
+ {
+ case SERVER_DOWN:
+ statusText = SERVER_DOWN_TXT;
+ break;
+ case SERVER_AVAILABLE:
+ statusText = SERVER_AVAILABLE_TXT;
+ break;
+ case SERVER_REGULARSIG:
+ statusText = SERVER_REGULARSIG_TXT;
+ break;
+ case SERVER_CRASHED:
+ statusText = SERVER_CRASHED_TXT;
+ break;
+ default:
+ statusText = "(unknown message flag)";
+ break;
+ }
+ if (newstatus != SERVER_REGULARSIG) // don't blow up the log file with "still alive" signals
+ {
+ VLOG << now() << " status info from server " << serverName
+ << " @ " << getClientAddr( currentJob.getSocket() )
+ << ": '" << statusText << "'...ok" << endl;
+ }
+
+ keepConnection = false; // singleton msg slave -> master
+ answer = 1;
+ }
+ else // malformed request
+ {
+ VLOG << now() << " Error: malformed request (ignoring it) from "
+ << getClientAddr( currentJob.getSocket() )
+ << ": '" << body << "'" << endl;
+ }
+ }
+ else if( (fake = isMessage("POST getfreeserver2")) || isMessage("POST getfreeserver"))
+ {
+ VLOG << now() << " client request from "
+ << getClientAddr( currentJob.getSocket() )
+ << ": " << "'get server'..." << flush;
+
+ int rc = getFreeServer(fake); // returns std rasdaman errors -- FIXME: error ignored!
+ keepConnection = (rc == MSG_OK) ? true : false; // 200 is "ok"
+ VLOG << "ok" << endl;
+
+
+ }
+ else if(isMessage("POST rascontrol"))
+ {
+ VLOG << now() << " rascontrol request from "
+ << getClientAddr( currentJob.getSocket() )
+ << ": '" << body << "'..." << flush;
+
+ if(authorization.acceptEntry(header))
+ {
+ rascontrol.processRequest(body,outBuffer);
+ keepConnection = true; // rascontrol connection accepted, so keep it
+ VLOG << "ok" << endl;
+ }
+ else
+ {
+ answerAccessDenied();
+ keepConnection = false; // this is a final answer, don't keep conn open afterwards
+ VLOG << "denied." << endl;
+ }
+ }
+
+ LEAVE( "MasterComm::processRequest: leave. answer=" << answer << ", keepConnection=" << keepConnection );
+ return answer;
+} // processRequest()
+
+// fillInBuffer: fill parameter string passed into message header and body (both global)
+// separator is a double newline
+// FIXME: unstable and weird programming, improve! -- PB 2003-jun-10
+// input:
+// s message input string
+// returns:
+// true filled buffer properly
+// false NULL body string
+// inBuffer (global buffer) set to s; header string part properly NULL terminated in inBuffer
+// body (global ptr) set to beginning of message body in inBuffer
+// header (global ptr) set to beginning of inBuffer
+bool MasterComm::fillInBuffer(const char *s)
+{
+ strcpy(inBuffer,s);
+ header=inBuffer; // set header to begining of msg buffer
+ body=strstr(inBuffer, RASMGRPROT_DOUBLE_EOL ); // find double EOL, this is where body starts
+ if(body == NULL) // not found? this means a protocol syntax error
+ {
+ TALK( "MasterComm::fillInBuffer: Error in rasmgr protocol encountered (2xEOL missing). msg=" << inBuffer );
+ return false; // only if client is stupid
+ }
+
+ *body=0; // terminate header (!) string
+ body+= strlen( RASMGRPROT_DOUBLE_EOL ); // let body start after this double newline
+
+ return true;
+}
+
+// save config and auth file; deprecated
+void MasterComm::doCommit()
+{
+ if(config.isTestModus()==false)
+ {
+ TALK( "MasterComm::doCommit: deprecated, should not be called any longer." );
+#if 0 // now done by saveCommand() directly
+ if(commitAuthOnly==false)
+ { VLOG << "Save configuration file...";
+ if(config.saveConfigFile()) VLOG << "OK" << std::endl;
+ else VLOG << "Failed" << std::endl;
+ }
+
+ VLOG << "Save authorization file...";
+ if(authorization.saveAuthFile()) VLOG << "OK" << std::endl;
+ else VLOG << "Failed" << std::endl;
+#endif
+ }
+ else
+ { std::cout<<"Save requested, but not permitted during test modus!"<<std::endl;
+ }
+ commit=false;
+ }
+
+void MasterComm::commitChanges()
+ { commit=true;
+ commitAuthOnly=false;
+ }
+void MasterComm::commitAuthFile()
+ { commit=true;
+ commitAuthOnly=true;
+ }
+
+int MasterComm::answerAccessDenied()
+ { // send to rascontrol when wrong login
+ sprintf(outBuffer,"HTTP/1.1 400 Error\r\nContent-type: text/plain\r\nContent-length: %d\r\n\r\nAccess denied",strlen("Access denied")+1);
+ return strlen(outBuffer)+1;
+ }
+
+int MasterComm::answerAccessDeniedCode()
+ { // send to clients requesting free server when wrong login
+ sprintf(outBuffer,"HTTP/1.1 400 Error\r\nContent-type: text/plain\r\nContent-length: %d\r\n\r\n802 Access denied",strlen("802 Access denied")+1);
+ return strlen(outBuffer)+1;
+ }
+
+// input:
+// fake true if only testing, false if server is to be allocated
+// body (global var) holding string encoding of request parameters
+// syntax: <dbname> [RPC|HTTP|RNP] [rw|ro] <previousID>
+// where the flags are NOT case sensitive
+// returns: standard rasdasman error codes
+// 200 (ok), 801, 805, 999, ...
+int MasterComm::getFreeServer(bool fake)
+{
+ // creates too large log files, so omit in production:
+ // BenchmarkTimer *freeServerTimePtr = new BenchmarkTimer("Get free server");
+
+ char databaseName[100];
+ char serverType[10];
+ char serverName[100]; // name of rasserver found, if any
+ char accessType[5];
+ char prevID[200]="(none)";
+
+ ENTER("MasterComm::getFreeServer: enter. fake=" << fake << ", body="<<body<<'*');
+
+ // initialize server name
+ strcpy( serverName, "(none)" );
+
+ // extract components from body string
+ int count = sscanf(body,"%s %s %s %s",databaseName,serverType,accessType, prevID);
+ if (count != 4 && count != 3)
+ {
+ cout << "Error (internal): Cannot parse msg body received from client." << endl;
+ LEAVE("MasterComm::getFreeServer: leave. Fatal error: cannot parse msg body string '" << body << "'" );
+ return MSG_ILLEGAL;
+ }
+
+ ClientID clientID;
+ // if we got a previous ID then take this one
+ if(count >3)
+ clientID.init(prevID);
+
+ TALK("GetFreeServer: db = " << databaseName << ", requested server type = " << serverType << ", access type = " << accessType << ", clientID="<<clientID<<" prevID="<< prevID );
+
+ char sType=0; // type of server requested, values SERVERTYPE_*
+ bool writeTransaction; // true <=> write transaction requested
+
+ int answCode=MSG_OK; // request answer code
+ const char *answText=MSG_OK_STR; // string representation of above answer code
+
+ char answerString[200]=""; // response string sent back to caller
+
+ // this loop is executed at most once, it servers only to have
+ // a well-defined point of continuation upon evaluation errors
+ do
+ {
+ // --- evaluate message body ------------------------
+
+ // determine server type requested
+ if(strcasecmp(serverType,"HTTP")==0)
+ sType=SERVERTYPE_FLAG_HTTP;
+ if(strcasecmp(serverType,"RPC")==0)
+ sType=SERVERTYPE_FLAG_RPC;
+ if(strcasecmp(serverType,"RNP")==0)
+ sType=SERVERTYPE_FLAG_RNP;
+ if(sType==0)
+ {
+ cout << "Error: unknown server type: " << serverType << endl;
+ answCode=MSG_UNKNOWNSERVERTYPE;
+ break;
+ }
+
+ // determine transaction mode
+ if (strcasecmp(accessType,"ro")==0)
+ writeTransaction=false;
+ else if (strcasecmp(accessType,"rw")==0)
+ writeTransaction=true;
+ else
+ {
+ cout << "Error: unknown transaction type: " << accessType << endl;
+ answCode=MSG_UNKNOWNACCESSTYPE;
+ break;
+ }
+
+ TALK("accessType="<<accessType<<" writeTransaction="<<writeTransaction);
+
+ // --- check against database state ------------------------
+
+ // does requested database exist? (i.e., is it known?)
+ Database &db=dbManager[databaseName];
+ if(db.isValid()==false)
+ {
+ cout << "Error: database not found: " << databaseName << endl;
+ answCode=MSG_DATABASENOTFOUND;
+ break;
+ }
+
+ // if r/w TA requested: is this compatible with the database's transaction state?
+ if(writeTransaction==true && db.getWriteTransactionCount() && allowMultipleWriteTransactions == false)
+ {
+ cout << "Error: write transaction in progress, conflicts with request." << endl;
+ answCode=MSG_WRITETRANSACTION;
+ break;
+ }
+
+ // --- all fine, try to find a free server ------------------------
+
+ // iterate over registered servers, try to find a free one
+ // FIXME: should be "round robin" strategy wrt server hosts;
+ // take last used per server host is fine to reduce swapping
+ int countSuitableServers=0; // number of servers we can choose from
+ TALK( "starting to search for server of type " << sType << "..." );
+ for(int i=0; i<db.countConnectionsToRasServers(); i++)
+ {
+ // inspect next server
+ RasServer &r=rasManager[db.getRasServerName(i)];
+ TALK( " srv #" << i << ": name=" << r.getName() << ", type=" << r.getType() << ", isUp=" << r.isUp() << ", isAvailable=" << r.isAvailable() );
+ if(sType == r.getType()) // type matches request?
+ {
+ if(r.isUp()) // server is up?
+ countSuitableServers++;
+
+ if(r.isAvailable()) // server is free?
+ { // part A: we have what you want
+ int cbs = clientQueue.canBeServed(clientID, (const char*)databaseName, sType, fake);
+ // returns: 0=OK, otherwise rasdaman errors 801, 805 -- PB 2003-nov-20
+ if(cbs != 0)
+ {
+ TALK("MasterComm::getFreeServer: clientQueue.canBeServed(" << clientID << "," << databaseName << "," << sType << "," << fake << ") -> " << cbs );
+ cout << "Error: no server available, error code: " << cbs << endl;
+ answCode = cbs;
+ break;
+ }
+ if( fake == false) // server to be allocated?
+ {
+ // mark server found as unavailable to others
+ r.setNotAvailable();
+ // set transaction mode requested
+ if(writeTransaction==true)
+ r.startWriteTransaction(db); // nothing real happens, no error can occur
+ else
+ r.startReadTransaction(db); // nothing real happens, no error can occur
+ TALK("MasterComm::getFreeServer: You have the server.");
+ // answCode is same as initialised if we come here
+ }
+ sprintf(answerString,"%s %ld %s ",r.getHostNetwName(),r.getPort(),authorization.getCapability(r.getName(),databaseName,!writeTransaction) );
+ // remember server name
+ strncpy( serverName, r.getName(), sizeof(serverName) );
+;
+ TALK( "answerString=" << answerString );
+ break;
+ }
+ }
+ } // for
+
+ // any free server found?
+ if(countSuitableServers == 0)
+ {
+ cout << "Error: no suitable free server available." << endl;
+ answCode = MSG_NOSUITABLESERVER;
+ break;
+ }
+
+ // no answer string provided -> no server available
+ // oops?? why not uniformly check against answCode? -- PB 2003-nov-20
+ if(answerString[0]==0)
+ {
+ cout << "Error: cannot find any free server; answer code: " << answCode << " -> ";
+ answCode = MSG_SYSTEMOVERLOADED;
+ cout << answCode << endl;
+ break;
+ }
+
+ } while(0); // see comment at start of "loop"
+
+ answText = convertAnswerCode(answCode);
+
+ if(answCode == MSG_OK)
+ sprintf(outBuffer,"HTTP/1.1 %d %s\r\nContent-type: text/plain\r\nContent-length: %d\r\n\r\n%s",answCode,answText,strlen(answerString)+1,answerString);
+ else
+ {
+ sprintf(outBuffer,"HTTP/1.1 %d %s\r\nContent-type: text/plain\r\nContent-length: %d\r\n\r\n%d %s",400,"Error",strlen(answText)+1,answCode,answText);
+ clientQueue.put(clientID, (const char*)databaseName, sType, answCode);
+ }
+
+ // creates too large log files, so omit in production:
+ // freeServerTimePtr->result(); // print time elapsed
+
+ LEAVE("MasterComm::getFreeServer: leave. answCode=" << answCode << ", server=" << serverName << ", outBuffer=" << outBuffer );
+ return answCode; //strlen(outBuffer)+1;
+} // getFreeServer()
+
+// convertAnswerCode: convert numeric answer code to error text for selected errors + OK
+// input:
+// code numeric error code, cf. errtxts
+// returns:
+// answer ptr to static error text
+const char* MasterComm::convertAnswerCode(int code)
+{
+ const char *answer = MSG_ILLEGAL_STR; // return value, initialized to "illegal"
+ switch(code)
+ {
+ case MSG_OK:
+ answer = MSG_OK_STR;
+ break;
+ case MSG_UNKNOWNSERVERTYPE:
+ answer = MSG_UNKNOWNSERVERTYPE_STR;
+ break;
+ case MSG_UNKNOWNACCESSTYPE:
+ answer = MSG_UNKNOWNACCESSTYPE_STR;
+ break;
+ case MSG_DATABASENOTFOUND:
+ answer = MSG_DATABASENOTFOUND_STR;
+ break;
+ case MSG_WRITETRANSACTION:
+ answer = MSG_WRITETRANSACTION_STR;
+ break;
+ case MSG_NOSUITABLESERVER:
+ answer = MSG_NOSUITABLESERVER_STR;
+ break;
+ case MSG_SYSTEMOVERLOADED:
+ answer = MSG_SYSTEMOVERLOADED_STR;
+ break;
+ default:
+ // cout<<"Default value not allowed ="<<code<<endl; assert( 0 != 0); break;
+ // no program aborts deeply inside!!! -- PB 2003-jun-25
+ answer = MSG_ILLEGAL_STR;
+ break;
+ }
+
+ TALK("MasterComm::convertAnswerCode: code=" << code << ", answer=" << answer );
+ return answer;
+}
+
+// isMessage: determine whether header conforms with a given prefix; case insensitive
+// input:
+// messageStart prefix to compare with
+// header (global) message header to be inspected
+// returns:
+// true on match
+// false otherwise
+bool MasterComm::isMessage(const char *messageStart)
+{
+ ENTER( "MasterComm::isMessage, messageStart=" << messageStart );
+
+ bool rasp= (strncasecmp(header,messageStart,strlen(messageStart))==0) ? true:false;
+ if(rasp)
+ TALK("(b) Message="<<messageStart);
+
+ LEAVE( "MasterComm::isMessage, result=" << rasp );
+ return rasp;
+}
+
+
+//********************************************************************
+
+ClientID::ClientID()
+{
+ valid = false;
+}
+
+
+void ClientID::init(const char *stringrep)
+{
+ idstring = stringrep;
+ valid = true;
+}
+
+string ClientID::getID() const
+{
+ return idstring;
+}
+
+bool ClientID::isValid() const
+{
+ return valid;
+}
+
+bool ClientID::operator==(const ClientID& cl)
+{
+ return (idstring == cl.idstring && valid) ? true : false;
+}
+
+bool ClientID::operator!=(const ClientID& cl)
+{
+ return (idstring == cl.idstring && valid) ? false : true;
+}
+
+std::ostream& operator<<(std::ostream &os, const ClientID &cl)
+{
+ os<<cl.getID();
+ return os;
+}
+
+// ----------------------------------------
+
+/*
+list of pending client requests.
+requests are entered if for some reason server allocation failed, or if a "fake" request was sent.
+*/
+// member attributes are defined in rasmgr_master.hh
+
+ClientQueue::ClientQueue()
+{
+ // do nothing
+}
+
+ClientQueue::~ClientQueue()
+{
+ // do nothing
+}
+
+// put: put client request into (static) queue; do nothing if request is malformed
+// well formed if:
+// - valid client ID in clientID
+// - server assignment error in errorCode
+void ClientQueue::put(ClientID &clientID, const char *dbName, char serverType, int errorCode)
+{
+ ENTER("ClientQueue::put: start, clientID=" << clientID << ", db=" << dbName << ", serverType=" << serverType << ", errorCode=" << errorCode );
+
+ // --- input parameter check ---------------
+
+ if(clientID.isValid() == false) // invalid clientID's are not put in queue
+ return;
+
+ if (errorCode != MSG_SYSTEMOVERLOADED
+ && errorCode != MSG_NOSUITABLESERVER
+ && errorCode != MSG_WRITETRANSACTION) // only these codes are put in queue
+ return;
+
+ // --- walk through client list to find a matching entry ---------------
+
+ ClientEntry *client = 0; // ptr to a list entry
+
+ // iterate thru list of client requests
+ TALK( "iterating through list, client table size=" << clients.size() );
+ for(int i=0;i<clients.size(); i++)
+ {
+ ClientEntry& curClient = clients[i]; // list entry to be inspected
+
+ // on the fly, remove first list entry if outdated or inactive
+ // FIXME: what an ugly code -- PB 2003-nov-20
+ if(curClient.activ == false || curClient.isTimeout())
+ {
+ if(i==0) // do only for 1st element
+ {
+ TALK("ClientQueue::put: cleaned up client "<<curClient.clientID );
+ clients.pop_front(); // remove this first element
+ i--; // set back loop ctr
+ }
+ continue;
+ }
+
+ // have an entry with matching client ID?
+ if(curClient.clientID == clientID)
+ {
+ client = &clients[i]; // remember this entry
+ break;
+ }
+ } // for
+
+ if(client == 0) // no matching entry found
+ {
+ ClientEntry newClient(clientID, dbName, serverType, errorCode);
+ newClient.activ = true;
+ newClient.updateTime();
+ clients.push_back(newClient);
+ TALK("ClientQueue::put, new client first time, id="<<clientID );
+ }
+ else // matching entry found
+ {
+ // Attention: we compare ptrs, not string contents!! -- PB 2003-nov-20
+ if(client->dbName == dbName && client->serverType == serverType)
+ { // wants the same thing
+ client->errorCode = errorCode;
+ client->updateTime();
+ TALK("ClientQueue::put, id=" << clientID << ", db=" << dbName << ", serverType=" << serverType << ": updated" );
+ }
+ else
+ { // same client, wants something different, is a new client
+ client->activ = false;
+ ClientEntry newClient(clientID, dbName, serverType, errorCode);
+ newClient.activ = true;
+ newClient.updateTime();
+ clients.push_back(newClient);
+ TALK("ClientQueue::put, known client db=" << dbName << ", serverType=" << serverType << ", but different request: id="<<clientID );
+ }
+ }
+
+ LEAVE("ClientQueue::put: done." );
+} // ClientQueue::put()
+
+// canBeServed: determine whether given request can be served
+// by looking into client list; return code indicates yes/no/why not
+// returns:
+// 0 ok, can be served
+// else rasdaman error code
+int ClientQueue::canBeServed(ClientID &clientID, const char *dbName, char serverType, bool fake)
+{ // the answer is the errorcode, why it can't be served
+
+ if(clients.size() == 0)
+ return 0;
+
+ for(int i=0;i<clients.size();i++)
+ {
+ ClientEntry& client = clients[i];
+
+ // on the fly, clean first element if necessary
+ // FIXME: this is not just as ugly as above, it also duplicates code! -- PB 2003-nov-20
+ if(client.activ == false || client.isTimeout())
+ {
+ if(i==0)
+ {
+ TALK("ClientQueue::canBeServed id="<<client.clientID<<" cleaned up");
+ clients.pop_front();
+ i--;
+ }
+ continue;
+ }
+
+ if(client.dbName == dbName && client.serverType == serverType)
+ { // wants the same thing
+ if(client.clientID == clientID)
+ { // it's the same client
+ // first fake request is not cleaned up.
+ // Chances are 99.999% that the same client comes back very quickly with a true request
+ if(client.shouldWeCleanup(fake))
+ {
+ client.activ = false;
+ if(i==0)
+ {
+ TALK("ClientQueue::canBeServed id="<<client.clientID<<" cleaned up, you get a server");
+ clients.pop_front();
+ i--;
+ }
+ }
+ LEAVE("ClientQueue::canBeServed id="<<clientID<<" yes (1)");
+ return 0; // OK, it can be served
+ }
+ else // it's another client
+ {
+ if(client.errorCode == MSG_SYSTEMOVERLOADED || client.errorCode == MSG_NOSUITABLESERVER)
+ { // yes, only these two, 806 (Write trans in progr) is not inherited!
+ // If there would be a client waiting because of 806 then:
+ // - either we want to write and have also 806, and wouldn't be here at all,
+ // - or we want to read and we don't care for that 806
+ LEAVE("ClientQueue::canBeServed id="<<clientID<<" no:"<<client.errorCode);
+ return client.errorCode;
+ }
+ LEAVE("ClientQueue::canBeServed id="<<clientID<<" yes (r/w)");
+ return 0; // OK, can be served
+ }
+ }
+ }
+
+ // if we are here, it can be served. There are clients, but not for the same reason
+ LEAVE("ClientQueue::canBeServed id="<<clientID<<" yes (2)");
+ return 0;
+}
+
+// -----------------------------------------------
+
+/*
+ client entry in client request list.
+Requests are put into the list only if a server allocation error
+has happened before or if a fake request has been made, so that
+a retry is needed.
+Member attributes:
+ activ this entry active? (manipulated by several list functions external to this class!!)
+ serverType type of rasdaman server requested
+ errorCode error code of last call
+ timeLimit time when request is timed out
+ lastAction used by updateTime to determine timeout increment
+ wasfake last request was fake
+*/
+
+ClientQueue::ClientEntry::ClientEntry()
+ {
+ activ = false;
+ serverType = 'x';
+ errorCode = 0;
+ lastAction = 0;
+ timeLimit = 0;
+ wasfake = false;
+ }
+
+ClientQueue::ClientEntry::ClientEntry(ClientID &_clientID, const char *_dbName, char _serverType, int _errorCode)
+{
+ activ = false;
+ clientID = _clientID;
+ dbName = _dbName;
+ serverType = _serverType;
+ errorCode = _errorCode;
+ lastAction = 0;
+ timeLimit = 0;
+ wasfake = false;
+}
+
+// shouldWeCleanup: does current client need to be removed from pending request list?
+// true iff fake || wasfake
+// "we admit a first fake request without cleaning up, so the client gots a chance to come back
+// with a true request. It's important to do this only for the first time, since a client which
+// loops with openDB could lock the system!!!"
+// side effects:
+// if (fake && !wasfake): sets wasfake flag, increments update time
+// input:
+// fake true iff fake request
+// returns:
+// true cleanup recommended
+// false not recommended
+// major changes:
+// single exit logic -- PB 2003-nov-20
+bool ClientQueue::ClientEntry::shouldWeCleanup(bool fake)
+{
+ bool result = false; // in dubio don't remove
+
+ if(fake == false)
+ result = true; // yes, clean up
+ else
+ {
+ if(wasfake == true)
+ result = true; // clean up, there was a fake request already
+ else
+ {
+ wasfake = true; // why?? -- PB 2003-nov-20
+
+ // update time, but short time limit, client should come quickly
+ time_t now = time(NULL);
+ timeLimit = now + WAITTIME_AFTER_FAKE;
+
+ result = false;
+ }
+ }
+
+ return result;
+}
+
+// updateTime: set new timeout interval
+// "we will use an adaptative method. first the client will have 3 sec before timimg out
+// than we compute deltaT and give him deltaT + 3. So clients can start by being unpatience and
+// than reduce their frequency. This will reduce CPU usage and remain flexible"
+void ClientQueue::ClientEntry::updateTime()
+{
+
+ time_t now = time(NULL);
+
+ if(lastAction == 0)
+ { // first use
+ lastAction = now;
+ timeLimit = now + WAITTIME_REPEATED; // client has WAITTIME_REPEATED seconds time to ask again
+ }
+ else
+ {
+ time_t deltaT = now - lastAction;
+ lastAction = now;
+ timeLimit = now + deltaT + WAITTIME_REPEATED;
+ }
+}
+
+// isTimeout: has client request reached timeout limit?
+bool ClientQueue::ClientEntry::isTimeout()
+{
+ return timeLimit < time(NULL);
+}
+
diff --git a/rasmgr/rasmgr_master_nb_hack.cc b/rasmgr/rasmgr_master_nb_hack.cc
new file mode 100644
index 0000000..42e1cb4
--- /dev/null
+++ b/rasmgr/rasmgr_master_nb_hack.cc
@@ -0,0 +1,1007 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: rasmgr_master_nb.cc
+ *
+ * MODULE: rasmgr
+ * CLASS: MasterComm
+ *
+ * PURPOSE:
+ * Main loop of master rasmgr
+ *
+ * COMMENTS:
+ * - MasterComm::processRequest() is the central dispatcher for rasmgr requests, recognising and executing them.
+ *
+*/
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "rasmgr_master.hh"
+#include "rasmgr_config.hh"
+#include "rasmgr_rascontrol.hh"
+#include "rasmgr_users.hh"
+#include "rasmgr_host.hh"
+#include "rasmgr_localsrv.hh"
+#include "rasmgr_srv.hh"
+
+using namespace std;
+
+#include "debug.hh"
+
+
+// from rasmgr_localsrv.cc; should go to a central location -- PB 2003-nov-25
+extern char *now();
+
+// rasserver error codes (see errtxts)
+// FIXME: should go into a central include file / class -- PB 2003-nov-20
+#define MSG_OK 200
+#define MSG_OK_STR "Ok"
+#define MSG_UNKNOWNSERVERTYPE 1001
+#define MSG_UNKNOWNSERVERTYPE_STR "Unknown server type"
+#define MSG_UNKNOWNACCESSTYPE 1002
+#define MSG_UNKNOWNACCESSTYPE_STR "Unknown access type"
+#define MSG_DATABASENOTFOUND 807
+#define MSG_DATABASENOTFOUND_STR "Database not found"
+#define MSG_WRITETRANSACTION 806
+#define MSG_WRITETRANSACTION_STR "Write transaction in progress"
+#define MSG_NOSUITABLESERVER 805
+#define MSG_NOSUITABLESERVER_STR "No suitable servers started"
+#define MSG_SYSTEMOVERLOADED 801
+#define MSG_SYSTEMOVERLOADED_STR "System overloaded"
+// the following code means: I got an error code which I don't know (FIXME: reconsider nr!)
+#define MSG_ILLEGAL 999
+#define MSG_ILLEGAL_STR "Internal error: Illegal response code."
+
+// here I start collecting rasmgr protocol tokens to eventually gather them all in one include file
+#define RASMGRPROT_EOL "\r\n"
+#define RASMGRPROT_DOUBLE_EOL "\r\n\r\n"
+
+// time [secs] until a client can be freed from the pending request list after a fake request
+#define WAITTIME_AFTER_FAKE 2
+// time increment [secs] of iterated timeout (see updateTime())
+#define WAITTIME_REPEATED 3
+
+
+MasterComm::MasterComm()
+ { commit=false;
+ allowMultipleWriteTransactions = false;
+ }
+
+MasterComm::~MasterComm()
+ {
+ }
+
+void MasterComm::Run()
+ {
+ ENTER("MasterComm::Run: enter." );
+
+ initListenSocket(config.getListenPort()); // connect/bind the central listen socket
+ // using IOSelector level here!
+
+ initJobs(MAXJOBSMASTER); // init jobs structure (nothing with sockets here)
+
+ allowMultipleWriteTransactions = config.allowMultipleWriteTransactions();
+
+ selector.setTimeout( config.getPollFrequency() , 0 );
+
+ VLOG << "Entering server mode, prepared to receive requests." << endl << endl;
+
+ while(mayExit()==false)
+ {
+ TALK("MasterComm::Run: new request cycle, status before processing is:" );
+ printStatus();
+
+ if(commit)
+ doCommit();
+
+ int answerLen=0;
+
+ TALK("MasterComm::Run: (c) Waiting...");
+
+ // wait for incoming requests, using select()
+ int r=selector.waitForRequest(); // 0 is timeout, <0 error, >0 success
+ // again, IOSelector level here!
+
+ TALK("MasterComm::Run: (d) It's ringing..." << r);
+
+ localServerManager.cleanChild(); // sa fie
+
+ if(r<0) // nothing to read
+ {
+ TALK("MasterComm::Run: (f1) it's a signal (or a socket failure)...");
+ continue;
+ }
+ if(r==0) // timeout, nothing to read
+ {
+ TALK("MasterComm::Run: (f2) nothing, look for timeouts...");
+ lookForTimeout();
+ continue;
+ }
+ if(r>0) // something is pending
+ {
+
+ TALK("MasterComm::Run: (e) Got request, r=" << r << "...");
+
+ // iterate over all jobs to see what we can read / reconnect (?) / write
+ dispatchWriteRequest(); // first this, to increase the chance to free a client
+ connectNewClients(); // wait for requests, using accept()
+ dispatchReadRequest(); // now read in new requests
+
+ for(int i=0;i<maxJobs;i++)
+ {
+ TALK( "- request processing: " << i ); // fake similar entry to benchmark logger
+ // creates too large log files, so omit in production:
+ // BenchmarkTimer *bPtr = new BenchmarkTimer("request processing");// print job start time to log
+
+ processJob(job[i]); // this can involve closing the connection!
+
+ // creates too large log files, so omit in production:
+ // bPtr->result(); // print stop time to log
+ }
+ }
+ }
+ LEAVE("MasterComm::Run: leave." );
+ } // Run()
+
+// keep connection open after processing request?
+// ...according to request type and comm success, shall we keep socket open?
+// Note: this is a bad hack, but I don't want to change the "answer" ret code of processRequest() unless I fully understand it -- PB 2003-jun-10
+static bool keepConnection;
+
+void MasterComm::processJob(NbJob &currentJob)
+ {
+ ENTER( "MasterComm::processJob: enter." );
+
+ if(currentJob.isOperationPending()==false )
+ {
+ LEAVE( "MasterComm::processJob: leave. isOperationPending=false" );
+ return;
+ }
+
+ if(currentJob.wasError()) // low-level comm error
+ {
+ TALK( "MasterComm::processJob: closing connection." );
+ currentJob.closeConnection();
+ LEAVE( "MasterComm::processJob: leave." );
+ return;
+ }
+
+ if(currentJob.isMessageOK() == false)
+ {
+ LEAVE( "MasterComm::processJob: leave. isMessageOK=false" );
+ return;
+ }
+
+ if(fillInBuffer(currentJob.getMessage())==false) // fill msg into answer buffer header + body
+ {
+ TALK( "MasterComm::processJob: closing connection." );
+ currentJob.closeConnection();
+ LEAVE( "MasterComm::processJob: leave. fillInBuffer=false" );
+ return;
+ }
+
+ // now we have the message in inBuffer, with header and body set correctly
+
+ int answer = processRequest( currentJob );
+
+ int outLen = strlen(outBuffer);
+
+ if(outLen && answer != 2) // sending the answer
+ // FIXME: what is answer==2 ? never happens! -- PB 2003-jun-10
+ {
+ TALK( "MasterComm::processJob: init sending answer for outBuffer, set socket to write mode." );
+ currentJob.initSendAnswer(outBuffer);
+ }
+
+ if(outLen == 0) // no answer to send
+ {
+ TALK( "MasterComm::processJob: no answer to send, closing connection." );
+ currentJob.closeConnection();
+ }
+
+ if( answer == 1 ) // means "delayedOperation"
+ // FIXME: according to processRequest, delOp is 0 !!! -- PB 2003-jun-10
+ // ...and 1 comes back for POST rasservernewstatus
+ { // the only known until now
+ TALK( "MasterComm::processJob: delayedOp, therefore changeServerStatus()." );
+ rasManager.changeServerStatus(body);
+ }
+ /* Two words about this delayedOperation. If a remote server crashes, the remote rasmgr
+ sends a message and does not wait for answer. But if the master rasmgr restarts
+ immediately the crashed server, it could come to a deadlock. Maybe not, but we
+ wish to avoid any possibility, so we close first the connection and then attempt
+ to restart the server.
+ */
+
+ // EXPERIMENTAL: close sockets as soon and as always as possible
+ // if (! keepConnection) // singleton request or comm error
+ // {
+ // TALK( "MasterComm::processJob: singleton request, closing connection." );
+ // currentJob.closeConnection();
+ // }
+
+ LEAVE( "MasterComm::processJob: leave." );
+ } // processJob()
+
+
+// printClientAddr(): aux fct to print client address to designated stream
+const char *getClientAddr( int mySocket )
+{
+ const char *result = NULL;
+ struct sockaddr_in s;
+ socklen_t sockaddrSize = (socklen_t) sizeof(s);
+ if ( getpeername( mySocket, (struct sockaddr*)&s, &sockaddrSize ) != 0)
+ result = strerror(errno);
+ else
+ result = inet_ntoa(s.sin_addr);
+ return result;
+}
+
+// process request which has been prepared in inBuffer
+// if 'verbose' is enabled in configuration then requests will be logged.
+// returns
+// 0 normally (?)
+// 1 for POST rasservernewstatus
+// NB: keepConnection is static above -- bad hack, see there
+int MasterComm::processRequest( NbJob &currentJob )
+{
+ ENTER( "MasterComm::processRequest: enter. inBuffer=" << inBuffer );
+
+ // inBuffer: header + body Ok, output in outBuffer, which is not initialized here
+ outBuffer[0]=0; // mark outBuffer as empty
+ int answer = 0;
+ // delayedOperation = 0;
+
+ bool fake = false; // getfreeserver request really wants to allocate a new server?
+
+ // --- this is the central dispatcher for rasmgr requests, recognising and executing them.
+
+ if(isMessage("POST rasmgrslave"))
+ {
+ VLOG << now() << " slave rasmgr request from "
+ << getClientAddr( currentJob.getSocket() )
+ << ": '" << body << "'..." << flush;
+
+ hostmanager.postSlaveMGR(body,outBuffer); // prepare outBuffer from body for send to slave
+ keepConnection = false; // master mgr passes thru, it's singleton commo, so don't keep conn
+ // FIXME: is this really correct?? -- PB 2003-jun-10
+ VLOG << "ok" << endl;
+ }
+ else if(isMessage("POST rasservernewstatus"))
+ {
+ // extract server status from msg body
+ char serverName[50];
+ int newstatus = 0;
+ long dummy = 0;
+ serverName[0] = '\0'; // initialize in case sscanf() fails
+
+ int result = sscanf( body, "%s %d %ld", serverName, &newstatus, &dummy);
+ if (result == 3) // we simply ignore malformed requests, reason see below
+ {
+ const char *statusText = NULL;
+ switch (newstatus)
+ {
+ case SERVER_DOWN:
+ statusText = SERVER_DOWN_TXT;
+ break;
+ case SERVER_AVAILABLE:
+ statusText = SERVER_AVAILABLE_TXT;
+ break;
+ case SERVER_REGULARSIG:
+ statusText = SERVER_REGULARSIG_TXT;
+ break;
+ case SERVER_CRASHED:
+ statusText = SERVER_CRASHED_TXT;
+ break;
+ default:
+ statusText = "(unknown message flag)";
+ break;
+ }
+ if (newstatus != SERVER_REGULARSIG) // don't blow up the log file with "still alive" signals
+ {
+ VLOG << now() << " status info from server " << serverName
+ << " @ " << getClientAddr( currentJob.getSocket() )
+ << ": '" << statusText << "'...ok" << endl;
+ }
+
+ keepConnection = false; // singleton msg slave -> master
+ answer = 1;
+ }
+ else // malformed request
+ {
+ VLOG << now() << " Error: malformed request (ignoring it) from "
+ << getClientAddr( currentJob.getSocket() )
+ << ": '" << body << "'" << endl;
+ }
+ }
+ else if( (fake = isMessage("POST getfreeserver2")) || isMessage("POST getfreeserver"))
+ {
+ VLOG << now() << " client request from "
+ << getClientAddr( currentJob.getSocket() )
+ << ": " << "'get server'..." << flush;
+
+ int rc = getFreeServer(fake); // returns std rasdaman errors -- FIXME: error ignored!
+ keepConnection = (rc == MSG_OK) ? true : false; // 200 is "ok"
+ VLOG << "ok" << endl;
+
+
+ }
+ else if(isMessage("POST rascontrol"))
+ {
+ VLOG << now() << " rascontrol request from "
+ << getClientAddr( currentJob.getSocket() )
+ << ": '" << body << "'..." << flush;
+
+ if(authorization.acceptEntry(header))
+ {
+ rascontrol.processRequest(body,outBuffer);
+ keepConnection = true; // rascontrol connection accepted, so keep it
+ VLOG << "ok" << endl;
+ }
+ else
+ {
+ answerAccessDenied();
+ keepConnection = false; // this is a final answer, don't keep conn open afterwards
+ VLOG << "denied." << endl;
+ }
+ }
+
+ LEAVE( "MasterComm::processRequest: leave. answer=" << answer << ", keepConnection=" << keepConnection );
+ return answer;
+} // processRequest()
+
+// fillInBuffer: fill parameter string passed into message header and body (both global)
+// separator is a double newline
+// FIXME: unstable and weird programming, improve! -- PB 2003-jun-10
+// input:
+// s message input string
+// returns:
+// true filled buffer properly
+// false NULL body string
+// inBuffer (global buffer) set to s; header string part properly NULL terminated in inBuffer
+// body (global ptr) set to beginning of message body in inBuffer
+// header (global ptr) set to beginning of inBuffer
+bool MasterComm::fillInBuffer(const char *s)
+{
+ strcpy(inBuffer,s);
+ header=inBuffer; // set header to begining of msg buffer
+ body=strstr(inBuffer, RASMGRPROT_DOUBLE_EOL ); // find double EOL, this is where body starts
+ if(body == NULL) // not found? this means a protocol syntax error
+ {
+ TALK( "MasterComm::fillInBuffer: Error in rasmgr protocol encountered (2xEOL missing). msg=" << inBuffer );
+ return false; // only if client is stupid
+ }
+
+ *body=0; // terminate header (!) string
+ body+= strlen( RASMGRPROT_DOUBLE_EOL ); // let body start after this double newline
+
+ return true;
+}
+
+// save config and auth file; deprecated
+void MasterComm::doCommit()
+{
+ if(config.isTestModus()==false)
+ {
+ TALK( "MasterComm::doCommit: deprecated, should not be called any longer." );
+#if 0 // now done by saveCommand() directly
+ if(commitAuthOnly==false)
+ { VLOG << "Save configuration file...";
+ if(config.saveConfigFile()) VLOG << "OK" << std::endl;
+ else VLOG << "Failed" << std::endl;
+ }
+
+ VLOG << "Save authorization file...";
+ if(authorization.saveAuthFile()) VLOG << "OK" << std::endl;
+ else VLOG << "Failed" << std::endl;
+#endif
+ }
+ else
+ { std::cout<<"Save requested, but not permitted during test modus!"<<std::endl;
+ }
+ commit=false;
+ }
+
+void MasterComm::commitChanges()
+ { commit=true;
+ commitAuthOnly=false;
+ }
+void MasterComm::commitAuthFile()
+ { commit=true;
+ commitAuthOnly=true;
+ }
+
+int MasterComm::answerAccessDenied()
+ { // send to rascontrol when wrong login
+ sprintf(outBuffer,"HTTP/1.1 400 Error\r\nContent-type: text/plain\r\nContent-length: %d\r\n\r\nAccess denied",strlen("Access denied")+1);
+ return strlen(outBuffer)+1;
+ }
+
+int MasterComm::answerAccessDeniedCode()
+ { // send to clients requesting free server when wrong login
+ sprintf(outBuffer,"HTTP/1.1 400 Error\r\nContent-type: text/plain\r\nContent-length: %d\r\n\r\n802 Access denied",strlen("802 Access denied")+1);
+ return strlen(outBuffer)+1;
+ }
+
+// input:
+// fake true if only testing, false if server is to be allocated
+// body (global var) holding string encoding of request parameters
+// syntax: <dbname> [RPC|HTTP|RNP] [rw|ro] <previousID>
+// where the flags are NOT case sensitive
+// returns: standard rasdasman error codes
+// 200 (ok), 801, 805, 999, ...
+int MasterComm::getFreeServer(bool fake)
+{
+ // creates too large log files, so omit in production:
+ // BenchmarkTimer *freeServerTimePtr = new BenchmarkTimer("Get free server");
+
+ char databaseName[100];
+ char serverType[10];
+ char serverName[100]; // name of rasserver found, if any
+ char accessType[5];
+ char prevID[200]="(none)";
+
+ ENTER("MasterComm::getFreeServer: enter. fake=" << fake << ", body="<<body<<'*');
+
+ // initialize server name
+ strcpy( serverName, "(none)" );
+
+ // extract components from body string
+ int count = sscanf(body,"%s %s %s %s",databaseName,serverType,accessType, prevID);
+ if (count != 4 && count != 3)
+ {
+ cout << "Error (internal): Cannot parse msg body received from client." << endl;
+ LEAVE("MasterComm::getFreeServer: leave. Fatal error: cannot parse msg body string '" << body << "'" );
+ return MSG_ILLEGAL;
+ }
+
+ ClientID clientID;
+ // if we got a previous ID then take this one
+ if(count >3)
+ clientID.init(prevID);
+
+ TALK("GetFreeServer: db = " << databaseName << ", requested server type = " << serverType << ", access type = " << accessType << ", clientID="<<clientID<<" prevID="<< prevID );
+
+ char sType=0; // type of server requested, values SERVERTYPE_*
+ bool writeTransaction; // true <=> write transaction requested
+
+ int answCode=MSG_OK; // request answer code
+ const char *answText=MSG_OK_STR; // string representation of above answer code
+
+ char answerString[200]=""; // response string sent back to caller
+
+ // this loop is executed at most once, it servers only to have
+ // a well-defined point of continuation upon evaluation errors
+ do
+ {
+ // --- evaluate message body ------------------------
+
+ // determine server type requested
+ if(strcasecmp(serverType,"HTTP")==0)
+ sType=SERVERTYPE_FLAG_HTTP;
+ if(strcasecmp(serverType,"RPC")==0)
+ sType=SERVERTYPE_FLAG_RPC;
+ if(strcasecmp(serverType,"RNP")==0)
+ sType=SERVERTYPE_FLAG_RNP;
+ if(sType==0)
+ {
+ cout << "Error: unknown server type: " << serverType << endl;
+ answCode=MSG_UNKNOWNSERVERTYPE;
+ break;
+ }
+
+ // determine transaction mode
+ if (strcasecmp(accessType,"ro")==0)
+ writeTransaction=false;
+ else if (strcasecmp(accessType,"rw")==0)
+ writeTransaction=true;
+ else
+ {
+ cout << "Error: unknown transaction type: " << accessType << endl;
+ answCode=MSG_UNKNOWNACCESSTYPE;
+ break;
+ }
+
+ TALK("accessType="<<accessType<<" writeTransaction="<<writeTransaction);
+
+ // --- check against database state ------------------------
+
+ // does requested database exist? (i.e., is it known?)
+ Database &db=dbManager[databaseName];
+ if(db.isValid()==false)
+ {
+ cout << "Error: database not found: " << databaseName << endl;
+ answCode=MSG_DATABASENOTFOUND;
+ break;
+ }
+
+ // if r/w TA requested: is this compatible with the database's transaction state?
+ if(writeTransaction==true && db.getWriteTransactionCount() && allowMultipleWriteTransactions == false)
+ {
+ cout << "Error: write transaction in progress, conflicts with request." << endl;
+ answCode=MSG_WRITETRANSACTION;
+ break;
+ }
+
+ // --- all fine, try to find a free server ------------------------
+
+ // iterate over registered servers, try to find a free one
+ // FIXME: should be "round robin" strategy wrt server hosts;
+ // take last used per server host is fine to reduce swapping
+ int countSuitableServers=0; // number of servers we can choose from
+ TALK( "starting to search for server of type " << sType << "..." );
+ for(int i=0; i<db.countConnectionsToRasServers(); i++)
+ {
+ // inspect next server
+ RasServer &r=rasManager[db.getRasServerName(i)];
+ TALK( " srv #" << i << ": name=" << r.getName() << ", type=" << r.getType() << ", isUp=" << r.isUp() << ", isAvailable=" << r.isAvailable() );
+ if(sType == r.getType()) // type matches request?
+ {
+ if(r.isUp()) // server is up?
+ countSuitableServers++;
+
+ if(r.isAvailable()) // server is free?
+ { // part A: we have what you want
+ int cbs = clientQueue.canBeServed(clientID, (const char*)databaseName, sType, fake);
+ // returns: 0=OK, otherwise rasdaman errors 801, 805 -- PB 2003-nov-20
+ if(cbs != 0)
+ {
+ TALK("MasterComm::getFreeServer: clientQueue.canBeServed(" << clientID << "," << databaseName << "," << sType << "," << fake << ") -> " << cbs );
+ cout << "Error: no server available, error code: " << cbs << endl;
+ answCode = cbs;
+ break;
+ }
+ if( fake == false) // server to be allocated?
+ {
+ // mark server found as unavailable to others
+ r.setNotAvailable();
+ // set transaction mode requested
+ if(writeTransaction==true)
+ r.startWriteTransaction(db); // nothing real happens, no error can occur
+ else
+ r.startReadTransaction(db); // nothing real happens, no error can occur
+ TALK("MasterComm::getFreeServer: You have the server.");
+ // answCode is same as initialised if we come here
+ }
+ sprintf(answerString,"%s %ld %s ",r.getHostNetwName(),r.getPort(),authorization.getCapability(r.getName(),databaseName,!writeTransaction) );
+ // remember server name
+ strncpy( serverName, r.getName(), sizeof(serverName) );
+;
+ TALK( "answerString=" << answerString );
+ break;
+ }
+ }
+ } // for
+
+ // any free server found?
+ if(countSuitableServers == 0)
+ {
+ cout << "Error: no suitable free server available." << endl;
+ answCode = MSG_NOSUITABLESERVER;
+ break;
+ }
+
+ // no answer string provided -> no server available
+ // oops?? why not uniformly check against answCode? -- PB 2003-nov-20
+ if(answerString[0]==0)
+ {
+ cout << "Error: cannot find any free server; answer code: " << answCode << " -> ";
+ answCode = MSG_SYSTEMOVERLOADED;
+ cout << answCode << endl;
+ break;
+ }
+
+ } while(0); // see comment at start of "loop"
+
+ answText = convertAnswerCode(answCode);
+
+ if(answCode == MSG_OK)
+ sprintf(outBuffer,"HTTP/1.1 %d %s\r\nContent-type: text/plain\r\nContent-length: %d\r\n\r\n%s",answCode,answText,strlen(answerString)+1,answerString);
+ else
+ {
+ sprintf(outBuffer,"HTTP/1.1 %d %s\r\nContent-type: text/plain\r\nContent-length: %d\r\n\r\n%d %s",400,"Error",strlen(answText)+1,answCode,answText);
+ clientQueue.put(clientID, (const char*)databaseName, sType, answCode);
+ }
+
+ // creates too large log files, so omit in production:
+ // freeServerTimePtr->result(); // print time elapsed
+
+ LEAVE("MasterComm::getFreeServer: leave. answCode=" << answCode << ", server=" << serverName << ", outBuffer=" << outBuffer );
+ return answCode; //strlen(outBuffer)+1;
+} // getFreeServer()
+
+// convertAnswerCode: convert numeric answer code to error text for selected errors + OK
+// input:
+// code numeric error code, cf. errtxts
+// returns:
+// answer ptr to static error text
+const char* MasterComm::convertAnswerCode(int code)
+{
+ const char *answer = MSG_ILLEGAL_STR; // return value, initialized to "illegal"
+ switch(code)
+ {
+ case MSG_OK:
+ answer = MSG_OK_STR;
+ break;
+ case MSG_UNKNOWNSERVERTYPE:
+ answer = MSG_UNKNOWNSERVERTYPE_STR;
+ break;
+ case MSG_UNKNOWNACCESSTYPE:
+ answer = MSG_UNKNOWNACCESSTYPE_STR;
+ break;
+ case MSG_DATABASENOTFOUND:
+ answer = MSG_DATABASENOTFOUND_STR;
+ break;
+ case MSG_WRITETRANSACTION:
+ answer = MSG_WRITETRANSACTION_STR;
+ break;
+ case MSG_NOSUITABLESERVER:
+ answer = MSG_NOSUITABLESERVER_STR;
+ break;
+ case MSG_SYSTEMOVERLOADED:
+ answer = MSG_SYSTEMOVERLOADED_STR;
+ break;
+ default:
+ // cout<<"Default value not allowed ="<<code<<endl; assert( 0 != 0); break;
+ // no program aborts deeply inside!!! -- PB 2003-jun-25
+ answer = MSG_ILLEGAL_STR;
+ break;
+ }
+
+ TALK("MasterComm::convertAnswerCode: code=" << code << ", answer=" << answer );
+ return answer;
+}
+
+// isMessage: determine whether header conforms with a given prefix; case insensitive
+// input:
+// messageStart prefix to compare with
+// header (global) message header to be inspected
+// returns:
+// true on match
+// false otherwise
+bool MasterComm::isMessage(const char *messageStart)
+{
+ ENTER( "MasterComm::isMessage, messageStart=" << messageStart );
+
+ bool rasp= (strncasecmp(header,messageStart,strlen(messageStart))==0) ? true:false;
+ if(rasp)
+ TALK("(b) Message="<<messageStart);
+
+ LEAVE( "MasterComm::isMessage, result=" << rasp );
+ return rasp;
+}
+
+
+//********************************************************************
+
+ClientID::ClientID()
+{
+ valid = false;
+}
+
+
+void ClientID::init(const char *stringrep)
+{
+ idstring = stringrep;
+ valid = true;
+}
+
+string ClientID::getID() const
+{
+ return idstring;
+}
+
+bool ClientID::isValid() const
+{
+ return valid;
+}
+
+bool ClientID::operator==(const ClientID& cl)
+{
+ return (idstring == cl.idstring && valid) ? true : false;
+}
+
+bool ClientID::operator!=(const ClientID& cl)
+{
+ return (idstring == cl.idstring && valid) ? false : true;
+}
+
+std::ostream& operator<<(std::ostream &os, const ClientID &cl)
+{
+ os<<cl.getID();
+ return os;
+}
+
+// ----------------------------------------
+
+/*
+list of pending client requests.
+requests are entered if for some reason server allocation failed, or if a "fake" request was sent.
+*/
+// member attributes are defined in rasmgr_master.hh
+
+ClientQueue::ClientQueue()
+{
+ // do nothing
+}
+
+ClientQueue::~ClientQueue()
+{
+ // do nothing
+}
+
+// put: put client request into (static) queue; do nothing if request is malformed
+// well formed if:
+// - valid client ID in clientID
+// - server assignment error in errorCode
+void ClientQueue::put(ClientID &clientID, const char *dbName, char serverType, int errorCode)
+{
+ ENTER("ClientQueue::put: start, clientID=" << clientID << ", db=" << dbName << ", serverType=" << serverType << ", errorCode=" << errorCode );
+
+ // --- input parameter check ---------------
+
+ if(clientID.isValid() == false) // invalid clientID's are not put in queue
+ return;
+
+ if (errorCode != MSG_SYSTEMOVERLOADED
+ && errorCode != MSG_NOSUITABLESERVER
+ && errorCode != MSG_WRITETRANSACTION) // only these codes are put in queue
+ return;
+
+ // --- walk through client list to find a matching entry ---------------
+
+ ClientEntry *client = 0; // ptr to a list entry
+
+ // iterate thru list of client requests
+ TALK( "iterating through list, client table size=" << clients.size() );
+ for(int i=0;i<clients.size(); i++)
+ {
+ ClientEntry& curClient = clients[i]; // list entry to be inspected
+
+ // on the fly, remove first list entry if outdated or inactive
+ // FIXME: what an ugly code -- PB 2003-nov-20
+ if(curClient.activ == false || curClient.isTimeout())
+ {
+ if(i==0) // do only for 1st element
+ {
+ TALK("ClientQueue::put: cleaned up client "<<curClient.clientID );
+ clients.pop_front(); // remove this first element
+ i--; // set back loop ctr
+ }
+ continue;
+ }
+
+ // have an entry with matching client ID?
+ if(curClient.clientID == clientID)
+ {
+ client = &clients[i]; // remember this entry
+ break;
+ }
+ } // for
+
+ if(client == 0) // no matching entry found
+ {
+ ClientEntry newClient(clientID, dbName, serverType, errorCode);
+ newClient.activ = true;
+ newClient.updateTime();
+ clients.push_back(newClient);
+ TALK("ClientQueue::put, new client first time, id="<<clientID );
+ }
+ else // matching entry found
+ {
+ // Attention: we compare ptrs, not string contents!! -- PB 2003-nov-20
+ if(client->dbName == dbName && client->serverType == serverType)
+ { // wants the same thing
+ client->errorCode = errorCode;
+ client->updateTime();
+ TALK("ClientQueue::put, id=" << clientID << ", db=" << dbName << ", serverType=" << serverType << ": updated" );
+ }
+ else
+ { // same client, wants something different, is a new client
+ client->activ = false;
+ ClientEntry newClient(clientID, dbName, serverType, errorCode);
+ newClient.activ = true;
+ newClient.updateTime();
+ clients.push_back(newClient);
+ TALK("ClientQueue::put, known client db=" << dbName << ", serverType=" << serverType << ", but different request: id="<<clientID );
+ }
+ }
+
+ LEAVE("ClientQueue::put: done." );
+} // ClientQueue::put()
+
+// canBeServed: determine whether given request can be served
+// by looking into client list; return code indicates yes/no/why not
+// returns:
+// 0 ok, can be served
+// else rasdaman error code
+int ClientQueue::canBeServed(ClientID &clientID, const char *dbName, char serverType, bool fake)
+{ // the answer is the errorcode, why it can't be served
+
+ if(clients.size() == 0)
+ return 0;
+
+ for(int i=0;i<clients.size();i++)
+ {
+ ClientEntry& client = clients[i];
+
+ // on the fly, clean first element if necessary
+ // FIXME: this is not just as ugly as above, it also duplicates code! -- PB 2003-nov-20
+ if(client.activ == false || client.isTimeout())
+ {
+ if(i==0)
+ {
+ TALK("ClientQueue::canBeServed id="<<client.clientID<<" cleaned up");
+ clients.pop_front();
+ i--;
+ }
+ continue;
+ }
+
+ if(client.dbName == dbName && client.serverType == serverType)
+ { // wants the same thing
+ if(client.clientID == clientID)
+ { // it's the same client
+ // first fake request is not cleaned up.
+ // Chances are 99.999% that the same client comes back very quickly with a true request
+ if(client.shouldWeCleanup(fake))
+ {
+ client.activ = false;
+ if(i==0)
+ {
+ TALK("ClientQueue::canBeServed id="<<client.clientID<<" cleaned up, you get a server");
+ clients.pop_front();
+ i--;
+ }
+ }
+ LEAVE("ClientQueue::canBeServed id="<<clientID<<" yes (1)");
+ return 0; // OK, it can be served
+ }
+ else // it's another client
+ {
+ if(client.errorCode == MSG_SYSTEMOVERLOADED || client.errorCode == MSG_NOSUITABLESERVER)
+ { // yes, only these two, 806 (Write trans in progr) is not inherited!
+ // If there would be a client waiting because of 806 then:
+ // - either we want to write and have also 806, and wouldn't be here at all,
+ // - or we want to read and we don't care for that 806
+ LEAVE("ClientQueue::canBeServed id="<<clientID<<" no:"<<client.errorCode);
+ return client.errorCode;
+ }
+ LEAVE("ClientQueue::canBeServed id="<<clientID<<" yes (r/w)");
+ return 0; // OK, can be served
+ }
+ }
+ }
+
+ // if we are here, it can be served. There are clients, but not for the same reason
+ LEAVE("ClientQueue::canBeServed id="<<clientID<<" yes (2)");
+ return 0;
+}
+
+// -----------------------------------------------
+
+/*
+ client entry in client request list.
+Requests are put into the list only if a server allocation error
+has happened before or if a fake request has been made, so that
+a retry is needed.
+Member attributes:
+ activ this entry active? (manipulated by several list functions external to this class!!)
+ serverType type of rasdaman server requested
+ errorCode error code of last call
+ timeLimit time when request is timed out
+ lastAction used by updateTime to determine timeout increment
+ wasfake last request was fake
+*/
+
+ClientQueue::ClientEntry::ClientEntry()
+ {
+ activ = false;
+ serverType = 'x';
+ errorCode = 0;
+ lastAction = 0;
+ timeLimit = 0;
+ wasfake = false;
+ }
+
+ClientQueue::ClientEntry::ClientEntry(ClientID &_clientID, const char *_dbName, char _serverType, int _errorCode)
+{
+ activ = false;
+ clientID = _clientID;
+ dbName = _dbName;
+ serverType = _serverType;
+ errorCode = _errorCode;
+ lastAction = 0;
+ timeLimit = 0;
+ wasfake = false;
+}
+
+// shouldWeCleanup: does current client need to be removed from pending request list?
+// true iff fake || wasfake
+// "we admit a first fake request without cleaning up, so the client gots a chance to come back
+// with a true request. It's important to do this only for the first time, since a client which
+// loops with openDB could lock the system!!!"
+// side effects:
+// if (fake && !wasfake): sets wasfake flag, increments update time
+// input:
+// fake true iff fake request
+// returns:
+// true cleanup recommended
+// false not recommended
+// major changes:
+// single exit logic -- PB 2003-nov-20
+bool ClientQueue::ClientEntry::shouldWeCleanup(bool fake)
+{
+ bool result = false; // in dubio don't remove
+
+ if(fake == false)
+ result = true; // yes, clean up
+ else
+ {
+ if(wasfake == true)
+ result = true; // clean up, there was a fake request already
+ else
+ {
+ wasfake = true; // why?? -- PB 2003-nov-20
+
+ // update time, but short time limit, client should come quickly
+ time_t now = time(NULL);
+ timeLimit = now + WAITTIME_AFTER_FAKE;
+
+ result = false;
+ }
+ }
+
+ return result;
+}
+
+// updateTime: set new timeout interval
+// "we will use an adaptative method. first the client will have 3 sec before timimg out
+// than we compute deltaT and give him deltaT + 3. So clients can start by being unpatience and
+// than reduce their frequency. This will reduce CPU usage and remain flexible"
+void ClientQueue::ClientEntry::updateTime()
+{
+
+ time_t now = time(NULL);
+
+ if(lastAction == 0)
+ { // first use
+ lastAction = now;
+ timeLimit = now + WAITTIME_REPEATED; // client has WAITTIME_REPEATED seconds time to ask again
+ }
+ else
+ {
+ time_t deltaT = now - lastAction;
+ lastAction = now;
+ timeLimit = now + deltaT + WAITTIME_REPEATED;
+ }
+}
+
+// isTimeout: has client request reached timeout limit?
+bool ClientQueue::ClientEntry::isTimeout()
+{
+ return timeLimit < time(NULL);
+}
+
diff --git a/rasmgr/rasmgr_protocol.hh b/rasmgr/rasmgr_protocol.hh
new file mode 100644
index 0000000..726f45f
--- /dev/null
+++ b/rasmgr/rasmgr_protocol.hh
@@ -0,0 +1,68 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: rasmgr_protocol.hh
+ *
+ * MODULE: rasmgr
+ * CLASS: none
+ *
+ * PURPOSE:
+ * Centralize all keywords of the rasmgr c/s protocol
+ *
+ * COMMENTS:
+ * - to be completed
+ *
+*/
+
+#ifndef RASMGR_PROTOCOL_HH
+#define RASMGR_PROTOCOL_HH
+
+#define RASMGRCMD_HELLO "Hello"
+
+#define RASMGRCMD_LICENCE "licence"
+#define RASMGRCMD_LICENSE "license"
+
+#define RASMGRCMD_EXIT "exit"
+#define RASMGRCMD_QUIT "quit"
+#define RASMGRCMD_BYE "bye"
+
+#define RASMGRCMD_HELP "help"
+#define RASMGRCMD_USER "user"
+#define RASMGRCMD_HOST "host"
+#define RASMGRCMD_SRV "srv"
+#define RASMGRCMD_DATABASE "database"
+#define RASMGRCMD_LIST "list"
+#define RASMGRCMD_DEFINE "define"
+#define RASMGRCMD_REMOVE "remove"
+#define RASMGRCMD_CHECK "check"
+#define RASMGRCMD_CHANGE "change"
+#define RASMGRCMD_SAVE "save"
+#define RASMGRCMD_RESET "reset"
+#define RASMGRCMD_GRANT "grant"
+#define RASMGRCMD_REVOKE "revoke"
+
+#define RASMGRCMD_UP "up"
+#define RASMGRCMD_DOWN "down"
+
+
+#endif // RASMGR_PROTOCOL_HH
diff --git a/rasmgr/rasmgr_random.cc b/rasmgr/rasmgr_random.cc
new file mode 100644
index 0000000..1fc501c
--- /dev/null
+++ b/rasmgr/rasmgr_random.cc
@@ -0,0 +1,176 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: rasmgr_master.hh
+ *
+ * MODULE: rasmgr
+ * CLASS: RandomGenerator
+ *
+ * PURPOSE:
+ * Own "random number generator", used to scramble the authorization file
+ *
+ * COMMENTS:
+ * None
+ *
+*/
+#include "rasmgr_users.hh"
+
+RandomGenerator::RandomGenerator()
+ {
+ // if somebody want's seed=1 inside it's seed =0, due to table generation way
+ seed=0;
+ fileVersion=-1;
+ }
+
+bool RandomGenerator::setFileVersion(long version)
+ {
+ static bool firstCall=true;
+ fileVersion = version;
+ if(version == 2 ) return true; // the actual version
+
+ if(version == 1 ) { if(firstCall) std::cout<<"Authorization file will be migrated to the new version"<<std::endl;
+ firstCall=false;
+ return true;
+ }
+ return false;
+ }
+
+void
+RandomGenerator::init(unsigned int newSeed)
+ {
+ switch(fileVersion)
+ {
+ case 1: srand(newSeed);
+ break;
+
+ case 2: seed = (newSeed-1)%1000;
+ break;
+ }
+ }
+
+unsigned char
+RandomGenerator::operator()()
+ {
+ unsigned char rasp = 0;
+ switch(fileVersion)
+ {
+ case 1: rasp=rand();
+ break;
+
+ case 2: rasp= randomTable[seed];
+ seed=(seed+1)%1000;
+ break;
+ }
+ return rasp;
+ }
+
+bool RandomGenerator::insideTest()
+ {
+ //performs a test to see if rand() functions like the original one.
+ // usefull to see if we were paranoic for nothing
+
+ unsigned int oldSeed=seed;
+ init(1); srand(1); // with other than 1 it breaks
+
+ bool rasp=true;
+ for(int i=0;i<40;i++)
+ {
+ for(int j=0;j<25;j++)
+ {
+ unsigned char b=rand();
+ if( b!= this->operator()() )
+ { rasp=false;
+
+ }
+ }
+ }
+
+ seed=oldSeed;
+
+ return rasp;
+ }
+
+
+/* do not change this table by any means and any reason!!
+We used for scrambling the authorization file the standard rand() function, but we are paranoic
+that someone could upgrade some system and change the rand function, breaking the decoding of the file
+To avoid such trouble, we put a table here generated with:
+
+ srand(1);
+
+ for(int i=0;i<40;i++)
+ {
+ for(int j=0;j<25;j++)
+ {
+ unsigned char b=rand();
+ std::cout<<(unsigned int)b<<',';
+ }
+ std::cout<<std::endl;
+ }
+ return 0;
+
+*/
+
+
+unsigned char RandomGenerator::randomTable[1000]={
+103,198,105,115,81,255,74,236,41,205,186,171,242,251,227,70,124,194,84,248,27,232,231,141,118,
+90,46,99,51,159,201,154,102,50,13,183,49,88,163,90,37,93,5,23,88,233,94,212,171,178,
+205,198,155,180,84,17,14,130,116,65,33,61,220,135,112,233,62,161,65,225,252,103,62,1,126,
+151,234,220,107,150,143,56,92,42,236,176,59,251,50,175,60,84,236,24,219,92,2,26,254,67,
+251,250,170,58,251,41,209,230,5,60,124,148,117,216,190,97,137,249,92,187,168,153,15,149,177,
+235,241,179,5,239,247,0,233,161,58,229,202,11,203,208,72,71,100,189,31,35,30,168,28,123,
+100,197,20,115,90,197,94,75,121,99,59,112,100,36,17,158,9,220,170,212,172,242,27,16,175,
+59,51,205,227,80,72,71,21,92,187,111,34,25,186,155,125,245,11,225,26,28,127,35,248,41,
+248,164,27,19,181,202,78,232,152,50,56,224,121,77,61,52,188,95,78,119,250,203,108,5,172,
+134,33,43,170,26,85,162,190,112,181,115,59,4,92,211,54,148,179,175,226,240,228,158,79,50,
+21,73,253,130,78,169,8,112,212,178,138,41,84,72,154,10,188,213,14,24,168,68,172,91,243,
+142,76,215,45,155,9,66,229,6,196,51,175,205,163,132,127,45,173,212,118,71,222,50,28,236,
+74,196,48,246,32,35,133,108,251,178,7,4,244,236,11,185,32,186,134,195,62,5,241,236,217,
+103,51,183,153,80,163,227,20,211,217,52,247,94,160,242,16,168,246,5,148,1,190,180,188,68,
+120,250,73,105,230,35,208,26,218,105,106,126,76,126,81,37,179,72,132,83,58,148,251,49,153,
+144,50,87,68,238,155,188,233,229,37,207,8,245,233,226,94,83,96,170,210,178,208,133,250,84,
+216,53,232,212,102,130,100,152,217,168,135,117,101,112,90,138,63,98,128,41,68,222,124,165,137,
+78,87,89,211,81,173,172,134,149,128,236,23,228,133,241,140,12,102,241,124,192,124,187,34,252,
+228,102,218,97,11,99,175,98,188,131,180,105,47,58,255,175,39,22,147,172,7,31,184,109,17,
+52,45,141,239,79,137,212,182,99,53,193,199,228,36,131,103,216,237,150,18,236,69,57,2,216,
+229,10,248,157,119,9,209,165,150,193,244,31,149,170,130,202,108,73,174,144,205,22,104,186,172,
+122,166,242,180,168,202,153,178,194,55,42,203,8,207,97,201,195,128,94,110,3,40,218,76,215,
+106,25,237,210,211,153,76,121,139,0,34,86,154,212,24,209,254,228,217,205,69,163,145,198,1,
+255,201,42,217,21,1,67,47,238,21,2,135,97,124,19,98,158,105,252,114,129,205,113,101,166,
+62,171,73,207,113,75,206,58,117,167,79,118,234,126,100,255,129,235,97,253,254,195,155,103,191,
+13,233,140,126,78,50,189,249,124,140,106,199,91,164,60,2,244,178,237,114,22,236,243,1,77,
+240,0,16,139,103,207,153,80,91,23,159,142,212,152,10,97,3,209,188,167,13,190,155,191,171,
+14,213,152,1,214,229,242,214,246,125,62,197,22,142,33,46,45,175,2,198,185,99,201,138,31,
+112,151,222,12,86,137,26,43,33,27,1,7,13,216,253,139,22,194,161,164,227,207,210,146,210,
+152,75,53,97,213,85,209,108,51,221,194,188,247,237,222,19,239,229,32,199,226,171,221,164,77,
+129,136,28,83,26,238,235,102,36,76,59,121,30,168,172,251,106,104,243,88,70,6,71,43,38,
+14,13,210,235,178,31,108,58,59,192,84,42,171,186,78,248,246,199,22,158,115,17,8,219,4,
+96,34,10,167,77,49,181,91,3,160,13,34,13,71,93,205,155,135,120,86,213,112,76,156,134,
+234,15,152,242,235,156,83,13,167,250,90,216,176,181,219,80,194,253,93,9,90,42,165,226,163,
+251,183,19,71,84,154,49,99,50,35,78,206,118,91,117,113,182,77,33,107,40,113,46,37,207,
+55,128,249,220,98,156,215,25,176,30,109,74,79,209,124,115,31,74,233,123,192,90,49,13,123,
+156,54,237,202,91,188,2,219,181,222,61,82,182,87,2,212,196,76,36,149,200,151,181,18,128,
+48,210,219,97,224,86,253,22,67,200,113,255,202,77,181,168,138,7,94,225,9,51,166,85,87,
+59,29,238,240,47,110,32,2,73,129,226,160,127,248,227,71,105,227,17,182,152,185,65,159,24,
+34,168,75,200,253,162,4,26,144,244,73,254,21,75,72,150,45,232,21,37,203,92,143,174,109
+};
diff --git a/rasmgr/rasmgr_rascontrol.cc b/rasmgr/rasmgr_rascontrol.cc
new file mode 100644
index 0000000..3ec3822
--- /dev/null
+++ b/rasmgr/rasmgr_rascontrol.cc
@@ -0,0 +1,2187 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: rasmgr_rascontrol.cc
+ *
+ * MODULE: rasmgr
+ * CLASS: RasControl
+ *
+ * PURPOSE:
+ * Decodes, verifies and executes the commands
+ *
+ * COMMENTS:
+ * None
+ *
+*/
+
+using namespace std;
+
+#include "globals.hh" // DEFAULT_PORT
+#include "rasmgr_rascontrol.hh"
+#include "rasmgr_config.hh"
+#include "rasmgr_master.hh"
+#include "rasmgr_srv.hh"
+#include "rasmgr_users.hh"
+#include "rasmgr_error.hh"
+
+#ifndef RMANVERSION
+#error "Please specify RAMNVERSION variable!"
+#endif
+
+#ifndef COMPDATE
+#error "Please specify the COMPDATE variable!"
+/*
+COMPDATE=`date +"%d.%m.%Y %H:%M:%S"`
+and -DCOMPDATE="\"$(COMPDATE)\"" when compiling
+*/
+#endif
+
+//#include "rasmgr_rascontrol_help.cc"
+
+#include "debug.hh"
+
+extern bool hostCmp( const char *h1, const char *h2);
+
+// function to migrate -xp parameters, only for v5.1, remove after
+void migrateExtraParams(const char *orig, char *migrated);
+
+int RasControl::processRequest(char* reqMessage, char *answMessage)
+ {
+ ENTER( "RasControl::processRequest: enter. rascontrol msg: " << reqMessage );
+ splitRequest(reqMessage);
+
+ const char *command=argc ? token[0].take() : "#";
+
+ try
+ {
+ if(command)
+ {
+ TALK( "RasControl::processRequest: command=" << command );
+
+ if (isCommand(RASMGRCMD_HELLO)) helloCommand();
+ else if(isCommand(RASMGRCMD_HELP)) helpCommand();
+ else if(isCommand(RASMGRCMD_LIST)) listCommand();
+ else if(isCommand(RASMGRCMD_DEFINE)) defineCommand();
+ else if(isCommand(RASMGRCMD_REMOVE)) removeCommand();
+ else if(isCommand(RASMGRCMD_CHECK)) checkCommand();
+ else if(isCommand(RASMGRCMD_UP)) upCommand();
+ else if(isCommand(RASMGRCMD_DOWN)) downCommand();
+ else if(isCommand(RASMGRCMD_CHANGE)) changeCommand();
+ else if(isCommand(RASMGRCMD_SAVE)) saveCommand();
+ else if(isCommand(RASMGRCMD_EXIT)) exitCommand();
+ else if(isCommand(RASMGRCMD_RESET)) resetCommand();
+
+#ifdef INCLUDE_HIDDEN_COMMANDS
+ // both are unofficial, PB doesn't like them, but I do
+ else if(isCommand(RASMGRCMD_GRANT)) grantCommand();
+ else if(isCommand(RASMGRCMD_REVOKE)) revokeCommand();
+ //################
+#endif
+
+ else if(isCommand("#")) sprintf(answBuffer," "); // comment
+ else
+ {
+ errorInCommand("Invalid command; try HELP." );
+ cout << "Invalid command word: " << command << endl;
+ }
+ }
+ else
+ {
+ cout << "Error in request: " << reqMessage << endl;
+ errorInCommand("Error in request." );
+ }
+ }
+ catch(RCError& e)
+ {
+ strcpy(answBuffer,"Error: ");
+ e.getString(answBuffer + strlen(answBuffer));
+ cout << answBuffer << endl;
+ }
+
+ LEAVE( "RasControl::processRequest: leave. answerBuffer: " << answBuffer );
+ return prepareAnswer(answMessage);
+ }
+
+// set dirty flags
+// used to differentiate between config file read and real changes thru rascontrol
+void RasControl::setConfigDirty( bool isDirty )
+ {
+ configDirty = isDirty;
+ }
+
+void RasControl::setAuthDirty( bool isDirty )
+ {
+ authDirty = isDirty;
+ }
+
+int RasControl::prepareAnswer(char *answMessage)
+ {
+ sprintf(answMessage,"HTTP/1.1 200 OK\r\nContent-type: text/plain\r\nContent-length: %d\r\n\r\n%s",strlen(answBuffer)+1,answBuffer);
+ return strlen(answMessage)+1;
+ }
+
+//*************************************************
+void RasControl::helloCommand()
+ {
+ sprintf(answBuffer,"Hello %s, you are connected to %s",authorization.getUserName(),config.getHostName());
+ }
+//*************************************************
+
+void RasControl::exitCommand()
+ {
+ bool configResult = false;
+ bool authResult = false;
+
+ ENTER( "RasControl::exitCommand: enter" );
+
+ (void) strcpy( answBuffer, "Exiting rascontrol session." );
+
+ if (configDirty)
+ configResult = config.saveAltConfigFile();
+
+ if (authDirty)
+ authResult = authorization.saveAltAuthFile();
+
+ sprintf(answBuffer, "Exiting rascontrol session.%s\n%s%s%s%s%s%s%s%s%s%s",
+ ((argc <= 1) ? "" : " Ignoring extra parameters."),
+
+ (!configDirty ? "" : "Configuration file was changed but not saved, storing rescue copy to " ),
+ (!configDirty ? "" : config.getAltConfigFileName() ),
+ (!configDirty ? "" : "..." ),
+ (!configDirty ? "" : (configResult ? "ok" : "failed") ),
+ (!configDirty ? "" : "\n" ),
+
+ (!authDirty ? "" : "Authorisation file was changed but not saved, storing rescue copy to " ),
+ (!authDirty ? "" : authorization.getAltAuthFileName() ),
+ (!authDirty ? "" : "..." ),
+ (!authDirty ? "" : (authResult ? "ok" : "failed") ),
+ (!authDirty ? "" : "\n" ) );
+
+ // (!configDirty ? "" : "Configuration was changed but not saved, storing rescue copy to " << config.getAltConfigFileName() << "..." << (configResult ? "ok" : "failed") << "." << endl),
+ // (!authDirty ? "" : "Authorisation was changed but not saved, storing rescue copy to " << authorization.getAltAuthFileName() << "..." << (authResult ? "ok" : "failed") << "." << endl) );
+
+ LEAVE( "RasControl::exitCommand: leave. answBuffer=" << answBuffer );
+ }
+
+void RasControl::listCommand()
+ {
+ const char *listwhat = argc==1 ? "xxx":token[1].take();
+
+ if (strcasecmp(listwhat,RASMGRCMD_SRV)==0) listRasServers();
+ else if(strcasecmp(listwhat,"version")==0) listVersion();
+ else if(strcasecmp(listwhat,"modus" )==0) listModus();
+ else if(strcasecmp(listwhat,RASMGRCMD_USER )==0) listUsers();
+ else if(strcasecmp(listwhat,RASMGRCMD_HOST)==0) listRasHosts();
+ else if(strcasecmp(listwhat,"dbh")==0) listDBHosts();
+ else if(strcasecmp(listwhat,"db")==0) listDatabases();
+
+#ifdef INCLUDE_HIDDEN_COMMANDS
+ else if(strcasecmp(listwhat,"rights")==0) listRights();// unofficial
+#endif
+
+ else if(strcasecmp(listwhat,RASMGRCMD_HELP)==0) listHelp();
+
+
+ else errorInCommand("Illegal LIST modifier. Try HELP LIST." );
+ }
+
+void RasControl::listModus()
+ {
+ checkPermission(admR_info);
+
+ checkUnexpectedTokens();
+
+ const char *modus = config.isTestModus() ? "test" :"normal";
+
+ sprintf(answBuffer,"rasmgr running in %s modus",modus);
+ }
+void RasControl::listVersion()
+ {
+ checkPermission(admR_info);
+
+ checkUnexpectedTokens();
+
+ // Version 1.1 is 1.0 with changes P.B. wanted, 06.03.2001
+ // Version 1.2 is 1.1 with changes P.B. wanted, 17.04.2001
+ // Version 1.3 with "list srv -x" and "-hostname" parameter
+ // Version 1.4 with migration of command line options from v5.0 to v5.1
+ // Version 1.5 with new cmds, bug fixes in socket communication
+ sprintf(answBuffer,"rasdaman v%1f (rasmgr v1.5, compiled on %s)", RMANVERSION/1000, COMPDATE);
+
+
+#ifdef INCLUDE_HIDDEN_COMMANDS
+ strcat(answBuffer," ('inside only'-version)");
+#endif
+ }
+
+void RasControl::listUsers()
+ {
+ checkPermission(admR_info);
+
+ bool isRights = isFlag("-rights");
+
+ checkUnexpectedTokens();
+
+ sprintf(answBuffer,"List of defined users:");
+
+ for(int i=0;i<userManager.countUsers();i++)
+ {
+ User &user=userManager[i];
+ //sprintf(answBuffer+strlen(answBuffer),"\r\n%d. %s (%ld)",i,u.getName(),u.getUserID());
+ sprintf(answBuffer+strlen(answBuffer),"\r\n%2d. %-20s ",i+1,user.getName());
+
+ if(isRights)
+ { sprintf(answBuffer+strlen(answBuffer)," [%s]",authorization.convertAdminRights(user.getAdminRights()));
+ sprintf(answBuffer+strlen(answBuffer)," -[%s]",authorization.convertDatabRights(user.getDefaultDBRights()));
+ }
+ }
+ }
+
+void RasControl::listRasHosts()
+ {
+ checkPermission(admR_info);
+ checkUnexpectedTokens();
+
+ sprintf(answBuffer,"List of server hosts:\r\n");
+ ServerHost::getDescriptionHeader(answBuffer+strlen(answBuffer));
+ for(int i=0;i<hostmanager.countHosts();i++)
+ {
+ sprintf(answBuffer+strlen(answBuffer),"\r\n%2d. ",i+1);
+ hostmanager[i].getDescription(answBuffer+strlen(answBuffer));
+
+ }
+ }
+
+void RasControl::listDBHosts()
+ {
+ checkPermission(admR_info);
+ checkUnexpectedTokens();
+
+ sprintf(answBuffer,"List of database hosts:\r\n");
+ sprintf(answBuffer+strlen(answBuffer)," Database Host Connection String Databases");
+
+ for(int i=0;i<dbHostManager.countHosts();i++)
+ {
+ DatabaseHost &dbh = dbHostManager[i];
+ sprintf(answBuffer+strlen(answBuffer),"\r\n%2d. %-15s %-30s",(i+1),dbh.getName(),dbh.getConnectionString());
+
+ for(int j=0;j<dbManager.countDatabases();j++)
+ {
+ if(dbManager[j].isConnectedToDBHost(dbh.getName()))
+ sprintf(answBuffer+strlen(answBuffer)," %s",dbManager[j].getName());
+ }
+ }
+ }
+
+
+void RasControl::listRasServers()
+ {
+ checkPermission(admR_info);
+ int answLen=0;
+ int maxAnswLen=MAXMSGOUTBUFF-100; // if there are many servers, we could get an overflow
+
+ bool fports= isFlag("-p");
+ bool fexec = isFlag("-x");
+
+ if(fports && fexec)
+ {
+ // error, not both of them together!
+ }
+
+
+ const char *srvName = getValueOf(RASMGRCMD_SRV);
+ if(srvName)
+ {
+ checkUnexpectedTokens();
+ RasServer &serv=getServer(srvName);
+
+ sprintf(answBuffer,"Status of server %s\r\n",srvName);
+ if(fports) RasServer::getDescriptionPortHeader(answBuffer+strlen(answBuffer));
+ else if(fexec) RasServer::getDescriptionExecHeader(answBuffer+strlen(answBuffer));
+ else RasServer::getDescriptionHeader(answBuffer+strlen(answBuffer));
+ strcat(answBuffer,"\r\n ");
+ if(fports) serv.getDescriptionPort(answBuffer+strlen(answBuffer));
+ else if(fexec) serv.getDescriptionExec(answBuffer+strlen(answBuffer));
+ else serv.getDescription(answBuffer+strlen(answBuffer));
+
+ return;
+ }
+
+ bool isHost = isFlag("-host");
+ const char *hostName = getValueOf("-host");
+ bool listAll = false;
+ if (isHost)
+ {
+ checkUnexpectedTokens();
+ checkNotNull(hostName,"host name");
+ getServerHost(hostName);
+
+ }
+ else
+ {
+
+ // no -host hostName, so check for -all
+ listAll = isFlag("-all");
+ checkUnexpectedTokens();
+ // normally we should generate an error if -all is not, but for compatibility...
+ // put the error here
+ }
+
+ if(hostName == NULL) sprintf(answBuffer,"List of servers:\r\n");
+ else sprintf(answBuffer,"List of servers on host %s:\r\n",hostName);
+
+ if(fports) RasServer::getDescriptionPortHeader(answBuffer+strlen(answBuffer));
+ else if(fexec) RasServer::getDescriptionExecHeader(answBuffer+strlen(answBuffer));
+ else RasServer::getDescriptionHeader(answBuffer+strlen(answBuffer));
+ int crnt=1;
+ for(int i=0;i<rasManager.countServers();i++)
+ {
+ answLen=strlen(answBuffer);
+
+ if(answLen >=maxAnswLen)
+ { sprintf(answBuffer+answLen,"\r\n(Answer too long, overflow!)");
+ break;
+ }
+
+ if(hostName)
+ if(!hostCmp(hostName,rasManager[i].getHostName()))
+ continue;
+
+ sprintf(answBuffer+answLen,"\r\n%2d. ",crnt++);
+
+ if(fports) rasManager[i].getDescriptionPort(answBuffer+strlen(answBuffer));
+ else if(fexec) rasManager[i].getDescriptionExec(answBuffer+strlen(answBuffer));
+ else rasManager[i].getDescription(answBuffer+strlen(answBuffer));
+ }
+
+ }
+
+void RasControl::listDatabases()
+ {
+ checkPermission(admR_info);
+
+ const char* dbName = getValueOf("db");
+
+ if(dbName)
+ {
+ checkUnexpectedTokens();
+ Database &db = getDatabase(dbName);
+
+ sprintf(answBuffer,"List database: %s\r\n",dbName);
+ Database::getDescriptionHeader(answBuffer+strlen(answBuffer));
+ strcat(answBuffer,"\r\n ");
+ db.getDescription(answBuffer+strlen(answBuffer));
+ return;
+ }
+
+ bool flagDBH = isFlag("-dbh");
+ const char* dbhName = getValueOf("-dbh");
+
+ if(flagDBH)
+ {
+ checkUnexpectedTokens();
+ checkNotNull(dbhName,"database host name");
+ getDatabaseHost(dbhName);
+ }
+
+ bool flagAll = isFlag("-all");
+ // if flagALL is not, we should generate an error message, but we list all silently
+ checkUnexpectedTokens();
+
+ if(dbhName)
+ sprintf(answBuffer,"List of databases on host: %s\r\n",dbhName);
+ else sprintf(answBuffer,"List of databases:\r\n");// blanks necesary for nice output
+ Database::getDescriptionHeader(answBuffer+strlen(answBuffer));
+
+ int crnt=1;
+ for(int i=0;i<dbManager.countDatabases();i++)
+ {
+ Database &db=dbManager[i];
+
+ if(dbhName)
+ { bool found=false;
+ for(int j=0; j < db.countConnectionsToDBHosts();j++)
+ { if(hostCmp(db.getDBHostName(j),dbhName))
+ { found=true;break;}
+ }
+ if(found == false)
+ continue;
+ }
+ sprintf(answBuffer+strlen(answBuffer),"\r\n%2d. ",crnt++);
+ db.getDescription(answBuffer+strlen(answBuffer));
+ }
+
+ }
+//******************************************************
+void RasControl::defineCommand()
+ {
+ const char *what = argc==1 ? "xxx":token[1].take();
+
+ if (strcasecmp(what,RASMGRCMD_SRV)==0)
+ {
+ defineRasServers();
+ configDirty = true;
+ }
+ else if(strcasecmp(what,RASMGRCMD_HOST)==0)
+ {
+ defineRasHosts();
+ configDirty = true;
+ }
+ else if(strcasecmp(what,"dbh")==0)
+ {
+ defineDBHosts();
+ configDirty = true;
+ }
+ else if(strcasecmp(what,"db")==0)
+ {
+ defineDatabases();
+ configDirty = true;
+ }
+ else if(strcasecmp(what,RASMGRCMD_USER)==0)
+ {
+ defineUsers();
+ authDirty = true;
+ }
+ else if(strcasecmp(what,RASMGRCMD_HELP)==0)
+ defineHelp();
+ else
+ errorInCommand("Wrong DEFINE command");
+ }
+
+void RasControl::defineUsers()
+ {
+ checkPermission(admR_acctrl);
+
+ const char *userName = getValueOf(RASMGRCMD_USER);
+ const char *plainPass = getValueIfFlag("-passwd");
+ const char *rString = getValueIfFlag("-rights",true);
+ int admRights =0;
+ int dtbRights =0;
+ checkUnexpectedTokens();
+ checkNotNull(userName,"user name");
+
+ for(int i=0;userName[i];i++)
+ if(userName[i]==':')
+ { errorInCommand("Invalid character (':') in user name.");
+ return;
+ }
+
+ if(rString)
+ {
+ admRights=authorization.convertAdminRights(rString);
+ dtbRights=authorization.convertDatabRights(rString);
+ if(admRights==-1 || dtbRights==-1)
+ { errorInCommand("Unknown right in command");
+ return;
+ }
+ }
+
+ if(userManager.insertNewUser(userName)==false)
+ { errorInCommand("User name should be unique.");
+ return;
+ }
+
+ User &user = userManager[userName];
+
+ if(plainPass) user.changePTPassword(plainPass);
+ if(rString) { user.setAdminRights(admRights);
+ user.setDefaultDBRights(dtbRights);
+ }
+
+ sprintf(answBuffer,"Defining user %s",userName);
+ }
+
+void RasControl::defineDBHosts()
+ {
+ checkPermission(admR_config);
+
+ const char *dbhName=getValueOf("dbh");
+ const char *connStr=getValueOf("-connect");
+
+ checkUnexpectedTokens();
+ checkNotNull(dbhName,"database host name");
+ checkNotNull(connStr,"connection string");
+
+ if(dbHostManager.insertNewHost(dbhName,connStr))
+ {
+ sprintf(answBuffer,"Defining database host %s with connection string: %s",dbhName,connStr);
+ }
+ else
+ {
+ sprintf(answBuffer,"Database host %s already defined.",dbhName);
+ }
+ }
+
+void RasControl::defineDatabases()
+ {
+ checkPermission(admR_config);
+
+ const char *dbName = getValueOf("db");
+ const char *dbhName = getValueOf("-dbh");
+ checkUnexpectedTokens();
+ checkNotNull(dbName,"database name");
+ // we don't accept hostless databases any more, define goes together with connect from now on
+ checkNotNull(dbhName,"database host name");
+ getDatabaseHost(dbhName);// just check if valid
+
+ bool defDB = dbManager.insertNewDatabase(dbName);
+ Database &db = dbManager[dbName];
+
+ bool connDB = db.connectToDBHost(dbhName);
+
+ if(defDB)
+ {
+ sprintf(answBuffer,"Defining database %s on database host %s",dbName,dbhName);
+ }
+ else
+ { //database was already defined
+ if(connDB) sprintf(answBuffer,"Defining a mirrored instance of database %s on database host %s.",dbName,dbhName);
+ else sprintf(answBuffer,"Database %s already defined on database host %s.",dbName,dbhName);
+ }
+
+ }
+
+void RasControl::defineRasHosts()
+ {
+ checkPermission(admR_config);
+
+ const char *hostName=getValueOf(RASMGRCMD_HOST);
+ const char *netName =getValueOf("-net");
+ const char *portStr =getValueOf("-port");
+ checkUnexpectedTokens();
+
+ checkNotNull(hostName,"host name");
+
+ checkNotNull(netName,"-net parameter");
+
+ long listenPort;
+ if(portStr) listenPort=convertToULong(portStr,"port");
+ else listenPort=DEFAULT_PORT;
+
+ if(hostmanager.insertNewHost(hostName,netName,listenPort)==false)
+ { sprintf(answBuffer,"Error: Host %s already defined.",hostName);
+ return;
+ }
+ else
+ { sprintf(answBuffer,"Defining server host %s port=%d",hostName,listenPort);
+ }
+ }
+
+void RasControl::defineRasServers()
+ {
+ checkPermission(admR_config);
+ bool inConfigFile = authorization.isInConfigFile();
+
+ const char *serverName=getValueOf(RASMGRCMD_SRV);
+ const char *hostName =getValueOf("-host");
+ const char *portStr =getValueOf("-port");
+ const char *sTypeStr =getValueOf("-type");
+ const char *dbhName =getValueOf("-dbh");
+
+ const char *autoRestart = getValueIfFlag("-autorestart");
+ const char *countString = getValueIfFlag("-countdown");
+ const char *execString = getValueIfFlag("-exec");
+ bool isExtra = isFlag("-xp");
+ // make the -xp string first
+ char extraString[300]; extraString[0]=0;
+
+ if(isExtra)
+ {
+ bool found=false;
+ for(int i=0;i<argc;i++)
+ {
+ if(!found)
+ { if(strcasecmp(token[i].argv,"-xp")==0) found=true;
+ }
+ else
+ { strcat(extraString,token[i].take());
+ strcat(extraString," ");
+ }
+ }
+ }
+
+ checkUnexpectedTokens();
+
+ checkNotNull(serverName,"server name");
+
+ if(!sTypeStr)
+ { errorInCommand("Missing server type, specify one of r (RPC), h (HTTP) or n (RNP).");
+ return;
+ }
+
+ char serverType=0;
+ if(strcasecmp(sTypeStr,"r")==0) { serverType=SERVERTYPE_FLAG_RPC;}
+ if(strcasecmp(sTypeStr,"h")==0) { serverType=SERVERTYPE_FLAG_HTTP;}
+ if(strcasecmp(sTypeStr,"n")==0) { serverType=SERVERTYPE_FLAG_RNP;}
+ if(!serverType)
+ { errorInCommand("Illegal server type, use one of [r|h|n].");
+ return;
+ }
+
+ checkNotNull(hostName,"host name");
+ checkNotNull(portStr,"port number");
+
+ if(inConfigFile == false)
+ { // we accept connectionless servers in config file, because we do not remove
+ // the connected servers when we remove a database host
+ checkNotNull(dbhName,"database host name");
+ getDatabaseHost(dbhName);// just check if valid
+
+ }
+
+ long listenPort=convertToULong(portStr,"port");
+
+ if(autoRestart)
+ {
+ if(strcasecmp(autoRestart,"on")==0)
+ ;
+ else if(strcasecmp(autoRestart,"off")==0)
+ ;
+ else
+ {
+ errorInCommand("Incorrect autorestart option, use one of [on|off].");
+ return;
+ }
+ }
+
+ getServerHost(hostName);// just check
+ if(rasManager.insertNewServer(serverName,hostName,serverType,listenPort)==false)
+ { sprintf(answBuffer,"Error: server name already existing.");
+ return;
+ }
+
+ if(inConfigFile && !dbhName) return;
+
+ RasServer &srv = rasManager[serverName];
+ srv.connectToDBHost(dbhName);
+ // if ok, write what you defined
+
+ // we put this options in the config file with the change srv command, so it's ok that it could return before
+ if(countString) srv.changeCountDown(convertToULong(countString,"countdown"));
+
+ if(extraString) srv.changeExtraParam(extraString);
+
+ if(autoRestart) srv.changeAutoRestart( strcasecmp(autoRestart,"on")==0 ? true:false);
+
+ if(execString) srv.changeExecutableName(execString);
+
+ if(serverType==SERVERTYPE_FLAG_RPC)
+ sprintf(answBuffer,"Defining deprecated server %s of type RPC on host %s port=%#x",serverName,hostName,listenPort);
+
+ if(serverType==SERVERTYPE_FLAG_HTTP)
+ sprintf(answBuffer,"Defining deprecated server %s of type HTTP on host %s port=%d",serverName,hostName,listenPort);
+
+ if(serverType==SERVERTYPE_FLAG_RNP)
+ sprintf(answBuffer,"Defining server %s of type RNP on host %s port=%d",serverName,hostName,listenPort);
+
+ }
+
+//----------------------------------------
+void RasControl::removeCommand()
+ {
+ const char *what = argc==1 ? "xxx":token[1].take();
+
+ if (strcasecmp(what,RASMGRCMD_SRV)==0) removeRasServers();
+
+ else if(strcasecmp(what,RASMGRCMD_HOST)==0) removeRasHosts();
+
+ else if(strcasecmp(what,"dbh")==0) removeDBHosts();
+
+ else if(strcasecmp(what,"db")==0) removeDatabases();
+
+ else if(strcasecmp(what,RASMGRCMD_USER)==0) removeUsers();
+
+ else if(strcasecmp(what,RASMGRCMD_HELP)==0) removeHelp();
+
+ else errorInCommand("Error in REMOVE command");
+ }
+
+void RasControl::removeUsers()
+ {
+ checkPermission(admR_acctrl);
+
+ const char *userName=getValueOf(RASMGRCMD_USER);
+ checkUnexpectedTokens();
+
+ checkNotNull(userName,"user name");
+
+ User &user=getUser(userName);
+
+ if(user.getUserID()==0)
+ { errorInCommand("You cannot remove the rasadmin.");
+ return;
+ }
+
+ if(userManager.removeUser(userName)==false)
+ { errorInCommand("Cannot remove user, don't know why");
+ return;
+ }
+ sprintf(answBuffer,"User %s removed",userName);
+ }
+
+void RasControl::removeRasHosts()
+ {
+ checkPermission(admR_config);
+
+ const char *hostName=getValueOf(RASMGRCMD_HOST);
+ checkUnexpectedTokens();
+
+ checkNotNull(hostName,"host name");
+
+ ServerHost &host = getServerHost(hostName);
+
+ if(host.isInternal()==true)
+ { errorInCommand("You cannot remove the master rasmgr host.");
+ return;
+ }
+
+ if(hostmanager.removeHost(hostName)==false)
+ { errorInCommand("Cannot remove host, it still has defined servers.");
+ return;
+ }
+ sprintf(answBuffer,"Host %s removed",hostName);
+ }
+
+void RasControl::removeRasServers()
+ {
+ checkPermission(admR_config);
+
+ const char *srvName=getValueOf(RASMGRCMD_SRV);
+ checkUnexpectedTokens();
+
+ checkNotNull(srvName,"server name");
+
+ RasServer &srv = getServer(srvName);
+
+ if(srv.isUp())
+ { errorInCommand("Cannot remove the server, it's still up.");
+ return;
+ }
+
+ if(rasManager.removeServer(srvName)==false)
+ { errorInCommand("Cannot remove the server, is probably still up.");
+ return;
+ }
+ sprintf(answBuffer,"Server %s removed",srvName);
+ }
+
+void RasControl::removeDBHosts()
+ {
+ checkPermission(admR_config);
+
+ const char *dbhName=getValueOf("dbh");
+ checkUnexpectedTokens();
+
+ checkNotNull(dbhName,"database host name");
+
+ getDatabaseHost(dbhName);
+
+ if(dbHostManager.removeHost(dbhName)==false)
+ { errorInCommand("Cannot remove the database host, is probably still busy.");
+ return;
+ }
+ sprintf(answBuffer,"Database host %s removed",dbhName);
+
+ // now remove all databases not connected to any database host
+ for(int i=0;i<dbManager.countDatabases();i++)
+ {
+ if(dbManager[i].countConnectionsToDBHosts()==0)
+ { dbManager.removeDatabase(dbManager[i].getName());
+ i--; // you understand why
+ }
+ }
+ }
+void RasControl::removeDatabases()
+ {
+ checkPermission(admR_config);
+
+ const char *dbName = getValueOf("db");
+ const char *dbhName = getValueOf("-dbh");
+ checkUnexpectedTokens();
+
+ checkNotNull(dbName,"database name");
+
+ Database &db= getDatabase(dbName);
+
+ checkNotNull(dbhName,"database host name");
+
+ getDatabaseHost(dbhName);
+
+ if(db.isBusy())
+ { errorInCommand("Database is busy.");
+ return;
+ }
+
+ if(db.disconnectFromDBHost(dbhName) == false)
+ { sprintf(answBuffer,"No database %s on database host %s.",dbName,dbhName);
+ return;
+ }
+
+ if(db.countConnectionsToDBHosts() !=0 )
+ {
+ sprintf(answBuffer,"Database %s removed from database host %s",dbName,dbhName);
+ // this means disconnected
+ }
+ else
+ if(dbManager.removeDatabase(dbName))
+ { sprintf(answBuffer,"Database %s removed from database host %s",dbName,dbhName);
+ // this time removed completely
+ }
+ else
+ { errorInCommand("Cannot remove the database, but why? (There shouldn't be any reason for that)");
+ }
+ }
+
+//--------------------------------------------
+void RasControl::changeCommand()
+ {
+ const char *what = argc==1 ? "xxx":token[1].take();
+
+ if (strcasecmp(what,RASMGRCMD_USER)==0)
+ {
+ changeUser();
+ authDirty = true;
+ }
+ else if(strcasecmp(what,RASMGRCMD_SRV)==0)
+ {
+ changeRasServer();
+ configDirty = true;
+ }
+ else if(strcasecmp(what,"dbh")==0)
+ {
+ changeDBHost();
+ configDirty = true;
+ }
+ else if(strcasecmp(what,"db")==0)
+ {
+ changeDB();
+ configDirty = true;
+ }
+ else if(strcasecmp(what,RASMGRCMD_HOST)==0)
+ {
+ changeHost();
+ configDirty = true;
+ }
+ else if(strcasecmp(what,RASMGRCMD_HELP)==0)
+ changeHelp();
+ else
+ errorInCommand("Error in CHANGE command");
+
+ }
+void RasControl::changeHost()
+ {
+ checkPermission(admR_config);
+ // we accept all this parameters, but we make all changes or none
+ const char *hostName=getValueOf(RASMGRCMD_HOST);
+
+ const char *uselocal = getValueIfFlag("-uselocalhost");
+ const char *newName = getValueIfFlag("-name");
+ const char *newNet = getValueIfFlag("-net");
+ const char *newPort = getValueIfFlag("-port");
+
+ checkUnexpectedTokens();
+
+ // This means changes were requested
+ bool chUseLoc = false;
+ bool chName = false;
+ bool chNet = false;
+ bool chPort = false;
+
+ checkNotNull(hostName,"server host name");
+
+ ServerHost &sh= getServerHost(hostName);
+
+ answBuffer[0]=0;
+ int changes = 0;
+ int port = 0;
+
+ if(uselocal)
+ {
+ chUseLoc = true;
+ if(sh.isInternal()==false)
+ { errorInCommand("Option '-uselocalhost' is meaningfull only on master rasmgr host");
+ return;
+ }
+ else
+ {
+ if (strcasecmp(uselocal,"on" )==0); // ok
+ else if(strcasecmp(uselocal,"off")==0); // ok
+ else { errorInCommand("Option '-uselocalhost' - wrong parameter");
+ return;
+ }
+ }
+ }
+
+ if(newName)
+ {
+ if(hostmanager.acceptChangeName(hostName,newName)==false)
+ { errorInCommand("The new name is not unique.");
+ return;
+ }
+
+ chName = true;
+ }
+
+ if(newNet ) { chNet = true;
+ if(sh.isUp()){ errorInCommand("You cannot change the network address of a RasMgr while it is up.");
+ return;
+ }
+ }
+
+ if(newPort) { chPort = true;
+ if(sh.isUp()){ errorInCommand("You cannot change the listen port of a RasMgr while it is up.");
+ return;
+ }
+
+ port = convertToULong(newPort,"port");
+ }
+
+
+
+ if(chUseLoc) { changes++; sh.useLocalHost( strcasecmp(uselocal,"on") ==0 ? true : false); }
+
+ if(chName) { changes++; sh.changeName(newName); }
+
+ if(chNet) { changes++; sh.changeNetName(newNet);}
+
+ if(chPort) { changes++; sh.changeListenPort(port);}
+
+ if(changes) sprintf(answBuffer,"Ready");
+ else errorInCommand("Change what?");
+
+ }
+
+void RasControl::changeDBHost()
+ {
+ checkPermission(admR_config);
+ const char *dbhName = getValueOf("dbh");
+ const char *newName = getValueIfFlag("-name");
+ const char *connString = getValueIfFlag("-connect");
+ checkUnexpectedTokens();
+
+ checkNotNull(dbhName,"database host name");
+
+ DatabaseHost &dbh= getDatabaseHost(dbhName);
+
+ if(newName)
+ {
+ if(dbHostManager.acceptChangeName(dbhName,newName)==false)
+ { errorInCommand("The new name is not unique.");
+ return;
+ }
+
+ dbh.changeName(newName);
+ }
+ else if(connString) dbh.changeConnectionString(connString);
+
+ else { errorInCommand("Change what?");
+ return;
+ }
+
+ sprintf(answBuffer,"Ready");
+
+ }
+
+void RasControl::changeDB()
+ {
+ checkPermission(admR_config);
+ const char *dbName = getValueOf("db");
+ const char *dbNewName = getValueIfFlag("-name");
+
+ checkUnexpectedTokens();
+
+ checkNotNull(dbName,"database name");
+
+ Database &db= getDatabase(dbName);
+
+ if(dbNewName)
+ {
+ if(dbManager.acceptChangeName(dbName,dbNewName)==false)
+ { errorInCommand("The new name is not unique.");
+ return;
+ }
+ db.changeName(dbNewName);
+ }
+ else
+ { errorInCommand("Change what?");
+ return;
+ }
+
+ sprintf(answBuffer,"Ready");
+
+ }
+
+/** the version supporting only one server - the documented one
+void RasControl::changeRasServer()
+ {
+ checkPermission(admR_config);
+
+ const char *serverName = getValueOf(RASMGRCMD_SRV);
+ const char *newServerName = getValueIfFlag("-name");
+ const char *portString = getValueIfFlag("-port");
+ const char *autoRestart = getValueIfFlag("-autorestart");
+ const char *countString = getValueIfFlag("-countdown");
+ const char *dbhName = getValueIfFlag("-dbh");
+ bool isExtra = isFlag("-xp");
+ bool autorestartValue;
+ // make the -xp string first
+ char extraString[300]; extraString[0]=0;
+ if(isExtra)
+ {
+ bool found=false;
+ for(int i=0;i<argc;i++)
+ {
+ if(!found)
+ { if(strcasecmp(token[i].argv,"-xp")==0) found=true;
+ }
+ else
+ { strcat(extraString,token[i].take());
+ strcat(extraString," ");
+ }
+ }
+ }
+ // so we touch all tokens
+ checkUnexpectedTokens();
+
+ checkNotNull(serverName,"server name");
+
+ RasServer &r= getServer(serverName);
+
+ if(dbhName) getDatabaseHost(dbhName);
+
+ if(autoRestart)
+ { if(strcasecmp(autoRestart,"on")==0) autorestartValue=true;
+ else if(strcasecmp(autoRestart,"off")==0) autorestartValue=false;
+ else { errorInCommand("Incorect autorestart option");
+ return;
+ }
+ }
+
+ if(newServerName && r.isUp()==false) )
+ { errorInCommand("Cannot change the name of a running server.");
+ return;
+ }
+
+ // from here, it cannot fail any more
+ if(autoRestart) r.changeAutoRestart(autorestartValue);
+
+ if(dbhName)
+ { r.disconnectFromDBHost();
+ r.connectToDBHost(dbhName);
+ }
+ if(newServerName) r.changeName(newServerName);
+
+ if(portString) r.changePort(strtoul(portString,(char**)NULL,0));
+
+ if(countString) r.changeCountDown(strtoul(countString,(char**)NULL,0));
+
+ if(isExtra) r.changeExtraParam(extraString);
+
+ sprintf(answBuffer,"Ready");
+
+ }
+*/
+
+// The version supporting change srv [s| -hos h | -all ] { rest of params }
+void RasControl::changeRasServer()
+ {
+ checkPermission(admR_config);
+
+// first, see if params are ok
+
+ // only if "srv name": const char *newServerName = getValueIfFlag("-name");
+ // only if "srv name": const char *portString = getValueIfFlag("-port");
+ const char *autoRestart = getValueIfFlag("-autorestart");
+ const char *countString = getValueIfFlag("-countdown");
+ const char *execString = getValueIfFlag("-exec");
+ const char *dbhName = getValueIfFlag("-dbh");
+ bool isExtra = isFlag("-xp");
+ int countChanges = 0;
+ // make the -xp string first
+ char extraString[300]; extraString[0]=0;
+
+ if(isExtra)
+ {
+ bool found=false;
+ for(int i=0;i<argc;i++)
+ {
+ if(!found)
+ { if(strcasecmp(token[i].argv,"-xp")==0) found=true;
+ }
+ else
+ { strcat(extraString,token[i].take());
+ strcat(extraString," ");
+ }
+ }
+ countChanges++;
+ }
+ // so we touch all tokens
+
+
+ if(dbhName) { getDatabaseHost(dbhName); countChanges++; }
+
+ if(autoRestart)
+ { if(strcasecmp(autoRestart,"on")==0) ;
+ else if(strcasecmp(autoRestart,"off")==0) ;
+ else { errorInCommand("Incorect autorestart option");
+ return;
+ }
+ countChanges++;
+ }
+ if(countString) countChanges++;
+ if(execString) countChanges++;
+
+ // ok, the existing params are ok
+
+ const char *serverName = getValueOf(RASMGRCMD_SRV);
+ if(serverName)
+ {
+ // permitted only here
+ const char *newType = getValueIfFlag("-type");
+ const char *newServerName = getValueIfFlag("-name");
+ const char *portString = getValueIfFlag("-port");
+
+ checkUnexpectedTokens();
+ RasServer &r = getServer(serverName);
+ char serverType=0;
+ if(newType)
+ {
+ if(strcasecmp(newType,"r")==0) { serverType=SERVERTYPE_FLAG_RPC;}
+ if(strcasecmp(newType,"h")==0) { serverType=SERVERTYPE_FLAG_HTTP;}
+ if(strcasecmp(newType,"n")==0) { serverType=SERVERTYPE_FLAG_RNP;}
+ if(!serverType) { errorInCommand("Unknown server type.");
+ return;
+ }
+ else countChanges++;
+ }
+ if(newServerName)
+ {
+ if(r.isUp()) { errorInCommand("Cannot change the name of a running server.");
+ return;
+ }
+ if(rasManager.acceptChangeName(serverName,newServerName)==false)
+ { errorInCommand("The new name is not unique.");
+ return;
+ }
+ countChanges++;
+ }
+ if(portString) countChanges++;
+ //------------
+ if(countChanges==0) { errorInCommand("Change what?");
+ return;
+ }
+
+ if(newType) r.changeType(serverType);
+ if(portString) r.changePort(convertToULong(portString,"port"));
+
+ changeRasServer(serverName,dbhName,countString,(isExtra ? extraString : NULL), autoRestart, execString);
+
+ if(newServerName) r.changeName(newServerName);
+
+ sprintf(answBuffer,"Ready");
+ return;
+ }
+
+ const char *hostName = getValueOf("-host");
+ if(hostName)
+ {
+ ServerHost &host=getServerHost(hostName);
+ checkUnexpectedTokens();
+ }
+
+ bool flagAll = isFlag("-all");
+ checkUnexpectedTokens();
+
+ if(hostName == NULL && flagAll == false)
+ { errorInCommand("No server specified");
+ return;
+ }
+
+ if(countChanges==0) { errorInCommand("Change what?");
+ return;
+ }
+
+ for(int i=0;i<rasManager.countServers();i++)
+ {
+ serverName = rasManager[i].getName();
+ if(hostName)
+ if(!hostCmp(hostName,rasManager[i].getHostName()))
+ continue;
+ changeRasServer(serverName,dbhName,countString,(isExtra ? extraString : NULL), autoRestart, execString);
+ }
+
+ sprintf(answBuffer,"Ready");
+
+ }
+
+void RasControl::changeRasServer(const char *serverName, const char *dbhName, const char *countString, const char *extraString, const char *autoRestart, const char* execName)
+ {
+ // called only by by changedServer, after verification of parameters
+ RasServer &r = getServer(serverName);
+
+ if(dbhName)
+ { r.disconnectFromDBHost();
+ r.connectToDBHost(dbhName);
+ }
+
+ if(countString) r.changeCountDown(convertToULong(countString,"countdown"));
+
+ if(extraString) r.changeExtraParam(extraString);
+
+ if(autoRestart) r.changeAutoRestart( strcasecmp(autoRestart,"on")==0 ? true:false);
+
+ if(execName) r.changeExecutableName(execName);
+ }
+
+void RasControl::changeUser()
+ {
+ const char *userName = getValueOf(RASMGRCMD_USER);
+ const char *newName = getValueIfFlag("-name");
+ const char *plainPass = getValueIfFlag("-passwd");
+ const char *encrPass = getValueIfFlag("-encrPasswd");
+ const char *rString = getValueIfFlag("-rights",true);
+ checkUnexpectedTokens();
+
+ // encr passwd has priority
+ const char *newPass = encrPass ? encrPass:plainPass;
+ bool takeEncrPass = encrPass ? true:false;
+
+ bool okChName =false;
+ bool okChPasswd=false;
+ bool okChRights=false;
+ int admRights = 0;
+ int dtbRights = 0;
+
+ //for name change you need acces Control (you cannot change rasadmin)
+ //for passwd change you need also acces Control, or, without, only yourself.(only rasadmin can change his passwd)
+ if(userName==0)
+ { errorInCommand("You should provide a valid user name.");
+ return;
+ }
+ User &u=getUser(userName);
+
+ if(newName!=0)
+ { checkPermission(admR_acctrl);
+ if(strcmp(userName,"rasadmin")==0)
+ { errorInCommand("You cannot change rasadmin's name.");
+ return;
+ }
+ if(userManager.acceptChangeName(userName,newName)==false)
+ { errorInCommand("The new name is not unique.");
+ return;
+ }
+
+ okChName=true;
+ }
+
+ if(newPass!=0)
+ { if (strcmp(userName ,authorization.getUserName())==0) okChPasswd=true; // may change your own passwd
+
+ else if(strcmp("rasadmin",authorization.getUserName())==0) okChPasswd=true; // rasadmin may change all passwd
+
+ else if(authorization.hasAdminRights(admR_acctrl))
+ { if (strcmp("rasadmin",userName)!=0) okChPasswd=true; // may change all passwd, except rasadmin's one
+ else
+ { errorInCommand("You don't have permission to change rasadmin's password.");
+ return;
+ }
+ }
+ else { errorInCommand("You don't have permission for this operation.");
+ return;
+ }
+
+ }
+ if(rString!=0)
+ { checkPermission(admR_acctrl);
+ admRights=authorization.convertAdminRights(rString);
+ dtbRights=authorization.convertDatabRights(rString);
+
+ if(admRights==-1 || dtbRights==-1)
+ { errorInCommand("Unknown right in command");
+ return;
+ }
+
+ okChRights = true;
+ }
+
+ // we don't talk so much, just say 'Ready' answBuffer[0]=0;
+ int changes =0;
+
+ if(okChName)
+ { u.changeName(newName);
+ //sprintf(answBuffer,"User name changed: %s is now %s\r\n",userName,newName);
+ changes++;
+ }
+ if(okChPasswd)
+ { if(answBuffer[0]!=0) strcat(answBuffer,"\r\n");
+
+ if(takeEncrPass) u.changePassword(newPass);
+ else u.changePTPassword(newPass);
+ //sprintf(answBuffer+strlen(answBuffer),"Password for user %s was changed\r\n",userName);
+ changes++;
+ }
+ if(okChRights)
+ { User &user = u; // this is v1.1, is will not live long...
+ const char *warning = user.getUserID()!=0 ? "": (admRights=admR_full,"You cannot change rasadmin's system rights\r\n");
+ //^sorry, trick
+ user.setAdminRights(admRights);
+ user.setDefaultDBRights(dtbRights);
+ //sprintf(answBuffer+strlen(answBuffer),"%sRights of user %s set to [%s]-[%s]\r\n", warning,userName,authorization.convertAdminRights(admRights),authorization.convertDatabRights(dtbRights));
+ changes++;
+ }
+
+ if(okChRights || okChPasswd) masterCommunicator.commitAuthFile();
+
+ if(changes==0) errorInCommand("Change what?");
+ else strcpy(answBuffer,"Ready");
+
+ }
+//---------------------------------------------
+void RasControl::upCommand()
+ {
+ const char *what = argc==1 ? "xxx":token[1].take();
+
+ if(strcasecmp(what,RASMGRCMD_SRV)==0) upRasServers();
+
+ else if(strcasecmp(what,RASMGRCMD_HELP)==0) upHelp();
+
+ else errorInCommand("Error in UP command");
+
+ }
+
+void RasControl::upRasServers()
+ {
+ ENTER( "RasControl::upRasServers()" );
+
+ checkPermission(admR_sysup);
+
+ const char *srvName =getValueOf(RASMGRCMD_SRV);
+
+ if(srvName) // up a specified server
+ {
+ bool flagForce = config.isDebugSupport() ? isFlag("-force") : false;
+ bool flagDebug = config.isDebugSupport() ? isFlag("-debug") : false;
+
+ checkUnexpectedTokens();
+
+ TALK( "server name: " << srvName );
+ RasServer &r=getServer(srvName);
+
+ // just debug
+ if(flagForce && r.isUp())
+ { r.forceAvailable();
+ sprintf(answBuffer,"Server forced to be available again");
+ LEAVE( "RasControl::upRasServers() -- " << answBuffer );
+ return;
+ }
+
+ if(r.isUp())
+ { errorInCommand("Server is already up.");
+ LEAVE( "RasControl::upRasServers() -- " << answBuffer );
+ return;
+ }
+ int rasp = flagDebug ? r.startServerInDebugger(answBuffer):r.startServer();
+
+ switch(rasp)
+ { case 0: if(flagDebug==false) sprintf(answBuffer,"Server started");
+ break;
+ case -1: errorInCommand("Server is not connected to a database host.");
+ break;
+ case -2: errorInCommand("License violation.");
+ break;
+ case -3:
+ case -4: errorInCommand("Cannot contact the slave rasmgr.");
+ break;
+ case -5: errorInCommand("Server host is down.");
+ break;
+ }
+ LEAVE( "RasControl::upRasServers()" );
+ return;
+ }
+
+ const char *hostName=getValueOf("-host");
+ if(hostName)
+ {
+ checkUnexpectedTokens();
+
+ int rasp = upAllServersOnHost(hostName);
+ switch(rasp)
+ {
+ //case -1: errorInCommand("Wrong server host name."); break;
+ case -2: errorInCommand("Server host is down."); break;
+
+ default: sprintf(answBuffer,"Started %d servers on host %s",rasp,hostName);
+ break;
+
+ }
+ LEAVE( "RasControl::upRasServers()" );
+ return;
+ }
+
+ bool flagAll = isFlag("-all");
+
+ if(flagAll)
+ {
+ checkUnexpectedTokens();
+
+ int countUpSrv = 0;
+ int countUpHosts = 0;
+ for(int i=0;i<hostmanager.countHosts();i++)
+ {
+ int rasp = upAllServersOnHost(hostmanager[i].getName());
+
+ if(rasp>=0) { countUpSrv+=rasp;countUpHosts++;}
+
+ }
+ sprintf(answBuffer,"Started %d servers on %d hosts",countUpSrv,countUpHosts);
+ LEAVE( "RasControl::upRasServers() -- " << answBuffer );
+ return;
+ }
+
+ errorInCommand("Up what?");
+
+ LEAVE( "RasControl::upRasServers()" );
+ }
+
+int RasControl::upAllServersOnHost(const char*hostName)
+ {
+ //return value is negativ =>error
+ //return value is positiv =>nr of started servers
+
+ ServerHost &sh= getServerHost(hostName);
+
+ if(sh.checkStatus() == false)
+ { //errorInCommand("Server host is down.");
+ return -2;
+ }
+
+ int countStart=0;
+ int alreadyUp = sh.getStartedServers();
+
+ for(int i=0;i<rasManager.countServers();i++)
+ {
+ RasServer &r=rasManager[i];
+ if(r.isUp()) continue;
+ if(!hostCmp(hostName,r.getHostName())) continue;
+
+ if(r.startServer()==0) countStart++;
+ }
+ // sprintf(answBuffer,"Started %d servers on host %s",countStart,hostName);
+ return countStart;
+ }
+//--------------------------------------------------------
+void RasControl::downCommand()
+ {
+ const char *what = argc==1 ? "xxx":token[1].take();
+
+ if (strcasecmp(what,RASMGRCMD_HOST)==0) downRasHosts();
+
+ else if(strcasecmp(what,RASMGRCMD_SRV)==0) downRasServers();
+
+ else if(strcasecmp(what,RASMGRCMD_HELP)==0) downHelp();
+
+ else errorInCommand("Error in DOWN command");
+
+ }
+
+void RasControl::downRasServers()
+ {
+ checkPermission(admR_sysup);
+
+ const char *srvName=getValueOf(RASMGRCMD_SRV);
+
+ if(srvName)
+ {
+ bool killFlag=isFlag("-kill");
+ bool forceFlag=isFlag("-force");
+ checkUnexpectedTokens();
+
+ RasServer &r= getServer(srvName);
+ if(r.isUp()==false && r.isStarting()==false)
+ { errorInCommand("Server is already down.");
+ return;
+ }
+
+ int res=killFlag ? r.killServer():r.downServer(forceFlag);
+
+ if(res<0)
+ { errorInCommand("Cannot contact the slave rasmgr.");
+ return;
+ }
+
+ if(killFlag) sprintf(answBuffer,"Server %s was killed",srvName);
+ else sprintf(answBuffer,"Server %s is going down",srvName);
+
+ return;
+ }
+
+ const char *hostName=getValueOf("-host");
+
+ if(hostName)
+ {
+ checkUnexpectedTokens();
+
+ int rasp=downAllServersOnHost(hostName);
+ switch(rasp)
+ {
+// case -1 : errorInCommand("Error in server host name.");
+// break;
+ case -2 : errorInCommand("Server host is down.");
+ break;
+ case 0 : sprintf(answBuffer,"On host %s all servers are already down",hostName);
+ break;
+ default : // means >0
+ sprintf(answBuffer,"%d servers on host %s are going down",rasp,hostName);
+ break;
+ }
+ return;
+ }
+
+ bool flagAll = isFlag("-all");
+ if(flagAll)
+ {
+ checkUnexpectedTokens();
+
+ int countDownSrv = 0;
+ int countDownHosts = 0;
+ for(int i=0;i<hostmanager.countHosts();i++)
+ {
+ int rasp = downAllServersOnHost(hostmanager[i].getName());
+
+ if(rasp>=0) { countDownSrv+=rasp;countDownHosts++;}
+
+ }
+ sprintf(answBuffer,"%d servers on %d hosts are going down",countDownSrv,countDownHosts);
+ return;
+ }
+
+ errorInCommand("Down what?");
+ }
+
+int RasControl::downAllServersOnHost(const char *hostName)
+ {
+ ServerHost &sh= getServerHost(hostName);
+
+ if(sh.checkStatus()==false)
+ { //errorInCommand("Server host is down.");
+ return -2;
+ }
+
+ int countDownServers=0;
+ for(int i=0;i<rasManager.countServers();i++)
+ {
+ RasServer &r=rasManager[i];
+ if(r.isUp()==false && r.isStarting()==false) continue;
+
+ if(!hostCmp(hostName,r.getHostName()))
+ continue;
+ r.downServer(false);
+ countDownServers++;
+ }
+ return countDownServers;
+ }
+
+void RasControl::downRasHosts()
+ { // this is the new stop command, but this version is incipient
+ checkPermission(admR_sysup);
+
+ const char *hostName=getValueOf(RASMGRCMD_HOST);
+
+ if(hostName)
+ {
+ checkUnexpectedTokens();
+ int rasp = downRasHost(hostName);
+ switch(rasp)
+ {
+ case 0: sprintf(answBuffer,"Server host %s is going down", hostName);
+ break;
+// case -1: errorInCommand("Wrong server host name.");
+// break;
+ case -2: errorInCommand("Sorry, you should down all servers on this host first.");
+ break;
+ case -3: errorInCommand("Sorry, you should down all slave hosts first, the master should be the last one.");
+ break;
+ }
+ return;
+ }
+
+ bool flagAll = isFlag("-all");
+
+ if(flagAll)
+ {
+ checkUnexpectedTokens();
+ if(rasManager.countUpServers()!=0)
+ { errorInCommand("Sorry, you should down all servers first.");
+ return;
+ }
+
+ for(int i=1;i<hostmanager.countHosts();i++)
+ { //yes, from 1, master the last!
+ downRasHost(hostmanager[i].getName());
+ }
+ //now the master
+ masterCommunicator.shouldExit();
+ sprintf(answBuffer,"All hosts are down, bye");
+ return;
+ }
+
+ errorInCommand("Down what?");
+ return;
+ }
+
+int RasControl::downRasHost(const char *hostName)
+ {
+ ServerHost &sh= getServerHost(hostName);
+
+ if(sh.getStartedServers())
+ { //errorInCommand("Sorry, you should down all servers on this host first.");
+ return -2;
+ }
+
+ if(sh.isInternal() && hostmanager.countUpHosts()>1)
+ {// errorInCommand("Sorry, you should down all slave hosts first, the master should be the last one.");
+ return -3;
+ }
+
+ if(sh.isInternal()) masterCommunicator.shouldExit();
+ else { // later, sorry
+ sh.downHost();
+ }
+ return 0;
+ }
+
+//----------------------------------------------------
+void RasControl::saveCommand()
+ {
+ checkPermission(admR_config);
+ checkUnexpectedTokens();
+
+ bool resultConf = config.saveOrigConfigFile();
+ bool resultAuth = authorization.saveOrigAuthFile();
+
+ // this has been done by the lines above: -- PB 2003-jun-08
+ // masterCommunicator.commitChanges();
+
+ sprintf(answBuffer,"Saving configuration file...%s. Saving authorization file...%s.",
+ (resultConf==true ? "ok" : "failed"),
+ (resultAuth==true ? "ok" : "failed") );
+ }
+
+//----------------------------------------------------
+void RasControl::resetCommand()
+ {
+ checkPermission(admR_config);
+ checkUnexpectedTokens();
+
+ if(config.isTestModus()==false)
+ { errorInCommand("This operation is possible only in test modus.");
+ return;
+ }
+
+ if(rasManager.reset()==false)
+ { errorInCommand("Resetting not possible, there are active servers.");
+ return;
+ }
+
+ dbHostManager.reset();
+ dbManager.reset();
+
+ hostmanager.reset();
+ hostmanager.insertInternalHost();
+
+ userManager.reset();
+ userManager.loadDefaults();
+
+ VLOG <<"rasmgr was succesfully reset."<<std::endl;
+ sprintf(answBuffer,"rasmgr was succesfully reset.");
+ }
+
+//-----------------------------------------
+
+void RasControl::checkCommand()
+ {
+ const char *what = argc==1 ? "xxx":token[1].take();
+
+ if (strcasecmp(what,RASMGRCMD_HOST)==0) checkRasHosts();
+
+ else if(strcasecmp(what,RASMGRCMD_HELP)==0) checkHelp();
+
+ else errorInCommand("Error in CHECK command");
+
+ }
+
+void RasControl::checkRasHosts()
+ {
+ checkPermission(admR_sysup);
+
+ const char *hostName=getValueOf(RASMGRCMD_HOST);
+
+ if(hostName)
+ {
+ checkUnexpectedTokens();
+
+ ServerHost &sh=getServerHost(hostName);
+
+ sh.checkStatus();
+ sprintf(answBuffer,"The host %s is %s",sh.getName(),(sh.isUp() ? "up":"down"));
+ return;
+ }
+
+ bool flagAll = isFlag("-all");
+
+ if(flagAll)
+ {
+ checkUnexpectedTokens();
+ for(int i=0;i<hostmanager.countHosts();i++)
+ { hostmanager[i].checkStatus();
+ }
+ sprintf(answBuffer,"Checking status of all hosts ... done");
+ return;
+ }
+ errorInCommand("Check what?");
+ }
+
+
+
+
+//###---###---###---###---###---###---###---###---###---###---###
+void RasControl::errorInCommand(const char *errText)
+ {
+ sprintf(answBuffer,"Error: %s",errText);
+ }
+
+bool RasControl::isCommand( const char *key )
+ {
+ if(argc)
+ return (strcasecmp(token[0].argv,key)==0) ? true:false;
+ else
+ return (strcmp("#",key)==0) ? true:false;
+ }
+
+void RasControl::splitRequest(const char* reqMessage)
+ {
+ argc=0;
+ commandBuffer[0]=' ';
+ strncpy(commandBuffer+1,reqMessage,MAXMSG-1);
+ commandBuffer[MAXMSG]=0;
+
+ TALK("RasControl::splitRequest: (a) Com="<<commandBuffer);
+
+ char *temp = commandBuffer;
+
+ for(argc=0;argc<30;argc++)
+ {
+ token[argc].set(strtok(temp," \r\n\t\0"));
+ temp=NULL;
+
+ if(token[argc].argv == NULL) break;
+ if(token[argc].argv[0] == '#')
+ { token[argc].argv=NULL; // from here, comment
+ break;
+ }
+ }
+
+ }
+
+bool RasControl::isFlag(const char *flag, int pos)
+ {
+ if(pos<0) // doesn't matter
+ { for(int i=1;i<argc;i++) // flags are from 1->, 0 is the command itself
+ {
+ if(strcasecmp(flag,token[i].argv)==0)
+ {
+ token[i].used=true;
+ return true;
+ }
+ }
+ return false;
+ }
+ if(pos>1 && pos<argc)
+ {
+ if(strcasecmp(flag,token[pos].argv)==0)
+ {
+ token[pos].used=true;
+ return true;
+ }
+ }
+ return false;
+ }
+
+const char * RasControl::getValueOf(const char *flag, bool acceptMinus)
+ {
+ //no,not always if(flag[0]!='-') return NULL; // all flags start with '-'
+
+ for(int i=1;i<argc-1;i++)
+ {
+ if(strcasecmp(flag,token[i].argv)==0)
+ {
+ token[i].used=true;
+
+ if(acceptMinus)
+ { if(token[i+1].argv[0]=='-' && token[i+1].argv[1]!=0) return NULL; // values don't start with '-' (we don't have minus-signs)
+ } // except in void right string
+ else
+ { if(token[i+1].argv[0]=='-') return NULL;
+ }
+ token[i+1].used=true;
+ return token[i+1].argv;
+ }
+ }
+
+ if(strcasecmp(flag,token[argc-1].argv)==0) token[argc-1].used=true;
+
+ return NULL; // not found;
+ }
+const char * RasControl::getValueIfFlag(const char *flag,bool acceptMinus)
+ {
+ if(isFlag(flag)==false) return NULL;
+
+ const char *r = getValueOf(flag,acceptMinus);
+
+ if(r==NULL)
+ {
+ static char temp[30];
+ sprintf(temp,"'%s' value",flag);
+ throw RCErrorMissingParam(temp);
+ }
+ return r;
+ }
+
+void RasControl::checkUnexpectedTokens()
+ {
+ for(int i=2;i<argc;i++)
+ {
+ if(token[i].used == false) throw RCErrorUnexpToken(token[i].argv);
+ }
+ }
+void RasControl::checkPermission(int reqRights)
+ {
+ if(authorization.hasAdminRights(reqRights)==false)
+ throw RCErrorNoPermission();
+ }
+
+void RasControl::checkNotNull(const char *ptr, const char *what)
+ {
+ if(ptr==NULL) throw RCErrorMissingParam(what);
+ }
+
+RasServer& RasControl::getServer(const char *name)
+ {
+ RasServer &srv = rasManager[name];
+ if(srv.isValid()==false) throw RCErrorInvalidName("server");
+ return srv;
+ }
+Database& RasControl::getDatabase(const char *name)
+ {
+ Database &db = dbManager[name];
+ if(db.isValid()==false) throw RCErrorInvalidName(RASMGRCMD_DATABASE);
+ return db;
+ }
+DatabaseHost& RasControl::getDatabaseHost(const char *name)
+ {
+ DatabaseHost &dbh = dbHostManager[name];
+ if(dbh.isValid()==false) throw RCErrorInvalidName("database host");
+ return dbh;
+ }
+ServerHost& RasControl::getServerHost(const char *name)
+ {
+ TALK( "RasControl::getServerHost( " << name << " )" );
+ ServerHost &host = hostmanager[name];
+ if(host.isValid()==false) throw RCErrorInvalidName("server host");
+ return host;
+ }
+User& RasControl::getUser(const char *name)
+ {
+ User &user = userManager[name];
+ if(user.isValid()==false) throw RCErrorInvalidName(RASMGRCMD_USER);
+ return user;
+ }
+
+unsigned long RasControl::convertToULong(const char *stringValue,const char *what)
+ {
+ char *end;
+ unsigned long rasp = strtoul(stringValue,&end,0);
+
+ if(strlen(end)!=0) throw RCErrorIncorNumberValue(what);
+
+ return rasp;
+ }
+
+void RasControl::Token::set(char *p)
+ {
+ argv = p;
+ used = false;
+ }
+const char* RasControl::Token::take()
+ {
+ used=true;
+ return argv;
+ }
+
+//######### OBSOLETE in v1.1, but keep them, because could be usefull one day ################################
+
+#ifdef INCLUDE_HIDDEN_COMMANDS
+// removed in version 1.1, reimplemented in v1.3, but kept unofficial
+
+void RasControl::listRights()
+ {
+ const char *userName = getValueOf("-user");
+
+ if(userName==NULL)
+ {
+ errorInCommand("You have to provide an user name");
+ //checkPermission(admR_info);
+ // list global Initial Rights
+ // gi rights hidden in version 1.1 sprintf(answBuffer,"Initial global rights are set to: [%s]-[%s]:",authorization.convertGlobalInitAdminRights(),
+ // authorization.convertGlobalInitDatabRights());
+ return;
+ }
+ User &user=userManager[userName];
+
+ if(strcmp(userName,authorization.getUserName())!=0)
+ { checkPermission(admR_info);
+ }
+ if(user.isValid()==false)
+ { errorInCommand("Unknown user");
+ //sprintf(answBuffer,"Unknown user %s",userName);
+ return;
+ }
+ //std::cout<<"list rights of user "<<userName<<" "<<user.getAdminRights()<<" "<<user.getDefaultDBRights()<<std::endl;
+ sprintf(answBuffer,"List of rights defined for user %s",userName);
+ sprintf(answBuffer+strlen(answBuffer),"\r\n administrative rights: [%s]",authorization.convertAdminRights(user.getAdminRights()));
+ sprintf(answBuffer+strlen(answBuffer),"\r\n default database rights: [%s]",authorization.convertDatabRights(user.getDefaultDBRights()));
+
+ //sprintf(answBuffer+strlen(answBuffer),"\r\n List of defined rights on databases:");
+
+
+ for(int i=0;i<dbManager.countDatabases();i++)
+ {
+ const char *dbName=dbManager[i].getName();
+
+ if(user.isTrusteeOn(dbName))
+ {
+ int rights=user.getEffectiveDatabaseRights(dbName);
+ sprintf(answBuffer+strlen(answBuffer),"\r\n database %-20s [%s]",dbName,authorization.convertDatabRights(rights));
+ }
+ }
+
+ }
+
+
+
+void RasControl::grantCommand()
+ {
+ if(argc==1 || strcasecmp(token[1].argv,RASMGRCMD_HELP)==0)
+ { //grantHelp();
+ return;
+ }
+ checkPermission(admR_acctrl);
+
+ const char *rString = token[1].take();
+
+ const char *userName= getValueOf("-user");
+
+ const char *dbName = getValueOf("-db");
+
+ bool gi=isFlag("-gi");
+
+ int admRights=authorization.convertAdminRights(rString);
+ int dtbRights=authorization.convertDatabRights(rString);
+
+ if(admRights==-1 || dtbRights==-1)
+ { errorInCommand("Unknown right in command");
+ return;
+ }
+
+ if(userName!=NULL)
+ { User &user=userManager[userName];
+ if(user.isValid()==false)
+ { errorInCommand("Unknown user");
+ return;
+ }
+
+ if(dbName!=NULL)
+ { if(user.setDatabaseRights(dbName,dtbRights)==false)
+ errorInCommand("Unknown database name");
+
+ else sprintf(answBuffer,"Granted %s to user %s for database %s",rString,userName,dbName);
+ }
+ else
+ { const char *warning = user.getUserID()!=0 ? "": (admRights=admR_full,"You cannot change rasadmin's system rights\r\n");
+ //^sorry, trick
+ user.setAdminRights(admRights);
+ user.setDefaultDBRights(dtbRights);
+ sprintf(answBuffer,"%sGranted [%s]-[%s] to user %s",warning,authorization.convertAdminRights(admRights),authorization.convertDatabRights(dtbRights),userName);
+ }
+ }
+ else
+ { if(gi)
+ { authorization.setGlobalInitAdminRights(admRights);
+ authorization.setGlobalInitDatabRights(dtbRights);
+ sprintf(answBuffer,"Set global initial rights to [%s]-[%s]",authorization.convertAdminRights(admRights),authorization.convertDatabRights(dtbRights));
+ }
+ else
+ { errorInCommand("Error in GRANT command");
+ }
+ }
+ }
+
+// removed in version 1.1
+void RasControl::revokeCommand()
+ {
+ if(argc==1 || strcasecmp(token[1].argv,RASMGRCMD_HELP)==0)
+ { //revokeHelp();
+ return;
+ }
+ checkPermission(admR_acctrl);
+
+ const char *userName= token[1].take();
+
+ const char *dbName = getValueOf("-db");
+
+ User &user=userManager[userName];
+ if(user.isValid()==false)
+ { errorInCommand("Unknown user");
+ return;
+ }
+
+ if(dbName!=NULL)
+ {
+ if(user.removeDatabaseRights(dbName)==false)
+ errorInCommand("Unknown database name");
+
+ else sprintf(answBuffer,"Rights of user %s for database %s revoked",userName,dbName);
+ }
+ else
+ { errorInCommand("Error in REVOKE command");
+ }
+ }
+
+#endif
+
+/*
+--------
+from list servers
+
+ bool fdbh = isFlag("-dbh",2);
+ const char *dbhName = getValueOf("-dbh");
+ if(fdbh) listRasServersOnDBH(dbhName);
+
+ else if(fdb) listRasServersDatabase(dbName);
+
+ else if(hostName)
+ {
+ sprintf(answBuffer,"List of servers on host %s:",hostName);
+
+ int crnt=0;
+ for(int i=0;i<rasManager.countServers();i++)
+ {
+ answLen=strlen(answBuffer);
+
+ if(answLen >=maxAnswLen)
+ { sprintf(answBuffer+answLen,"\r\n(Answer too long, overflow danger!)");
+ break;
+ }
+ if(strcmp(hostName,rasManager[i].getHostName())!=0) continue;
+
+ sprintf(answBuffer+answLen,"\r\n%2d. ",crnt++);
+
+ if(fports) rasManager[i].getDescriptionPort(answBuffer+strlen(answBuffer));
+ else rasManager[i].getDescription(answBuffer+strlen(answBuffer));
+ }
+ }
+ else
+
+
+---------
+from list db
+ if(isFlag("-dbh",2))
+ {
+ const char *dbhName=getValueOf("-dbh");
+
+ if(dbhName)
+ sprintf(answBuffer,"List of databases on host: %s",dbhName);
+ else sprintf(answBuffer,"List of databases:");
+
+ int crnt=0;
+ for(int i=0;i<dbManager.countDatabases();i++)
+ {
+ Database &refTemp=dbManager[i];
+
+ if( dbhName && refTemp.isConnectedToDBHost(dbhName) )
+ { sprintf(answBuffer+strlen(answBuffer),"\r\n%2d. %s ",crnt++,refTemp.getName());
+ }
+
+ if( !dbhName )
+ { sprintf(answBuffer+strlen(answBuffer),"\r\n%2d. %s",crnt++,refTemp.getName());
+
+ for(int j=0;j<refTemp.countConnectionsToDBHosts();j++)
+ sprintf(answBuffer+strlen(answBuffer),"\r\n %s ",refTemp.getDBHostName(j));
+ }
+ }
+ }
+ else if(isFlag("-srv",2))
+ {
+ const char *srvName=getValueOf("-srv");
+
+ if(srvName)
+ sprintf(answBuffer,"List of databases accesible by server: %s",srvName);
+ else sprintf(answBuffer,"List of databases:");
+
+ int crnt=0;
+ for(int i=0;i<dbManager.countDatabases();i++)
+ {
+ Database &refTemp=dbManager[i];
+
+ if( srvName && refTemp.isConnectedToRasServer(srvName) )
+ { sprintf(answBuffer+strlen(answBuffer),"\r\n%2d. %s ",crnt++,refTemp.getName());
+ }
+
+ if( !srvName )
+ { sprintf(answBuffer+strlen(answBuffer),"\r\n%2d. %s",crnt++,refTemp.getName());
+
+ for(int j=0;j<refTemp.countConnectionsToRasServers();j++)
+ sprintf(answBuffer+strlen(answBuffer),"\r\n %s ",refTemp.getRasServerName(j));
+
+ }
+ }
+ }
+
+ else
+ { sprintf(answBuffer,"List of databases:");
+ int crnt=0;
+ for(int i=0;i<dbManager.countDatabases();i++)
+ {
+ Database &refTemp=dbManager[i];
+
+ sprintf(answBuffer+strlen(answBuffer),"\r\n%2d. %s ",crnt++,refTemp.getName());//,refTemp.isValid());
+
+ sprintf(answBuffer+strlen(answBuffer),"(%dw + %dr) ",refTemp.getWriteTransactionCount(),refTemp.getReadTransactionCount());
+
+ }
+ }
+
+---------
+
+*/
+
diff --git a/rasmgr/rasmgr_rascontrol.hh b/rasmgr/rasmgr_rascontrol.hh
new file mode 100644
index 0000000..2f5412d
--- /dev/null
+++ b/rasmgr/rasmgr_rascontrol.hh
@@ -0,0 +1,166 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: rasmgr_rascontrol.hh
+ *
+ * MODULE: rasmgr
+ * CLASS: RasControl
+ *
+ * PURPOSE:
+ * Decodes, verifies and xecutes the commands
+ *
+ * COMMENTS:
+ * None
+ *
+*/
+#ifndef RASMGR_RASCONTROL_HH
+#define RASMGR_RASCONTROL_HH
+
+#include "rasmgr.hh"
+#include "rasmgr_comm.hh"
+#include "rasmgr_users.hh"
+#include "rasmgr_host.hh"
+
+
+class RasControl
+ {
+ public:
+ int processRequest(char* reqMessage, char *answMessage);
+ void setConfigDirty( bool isDirty );
+ void setAuthDirty( bool isDirty );
+
+ private:
+ void helloCommand();
+ void exitCommand();
+ void helpCommand();
+ void helpHelp();
+ void exitHelp();
+ void listCommand();
+ void listRasServers();
+ void listRasHosts();
+ void listDBHosts();
+ void listDatabases();
+ void listUsers();
+ void listModus();
+ void listVersion();
+ void listConnections();
+ void listRights();
+ void listHelp();
+ void defineCommand();
+ void defineRasServers();
+ void defineRasHosts();
+ void defineDBHosts();
+ void defineDatabases();
+ void defineUsers();
+ void defineHelp();
+ void removeCommand();
+ void removeRasServers();
+ void removeRasHosts();
+ void removeDBHosts();
+ void removeDatabases();
+ void removeUsers();
+ void removeHelp();
+ void checkCommand();
+ void checkRasHosts();
+ void checkHelp();
+ void upCommand();
+ void upRasServers();
+ int upAllServersOnHost(const char*hostName);
+ void upHelp();
+ void downCommand();
+ void downRasServers();
+ int downAllServersOnHost(const char *hostName);
+ void downRasHosts();
+ int downRasHost(const char *hostName);
+ void downHelp();
+ void changeCommand();
+ void changeHost();
+ void changeUser();
+ void changeRasServer();
+ void changeRasServer(const char *serverName, const char *dbhName, const char *countString, const char *extraString, const char *autoRestart, const char* execName);
+ void changeDBHost();
+ void changeDB();
+ void changeHelp();
+ void saveCommand();
+ void saveHelp();
+ // void stopCommand();
+ void resetCommand();
+
+ void grantCommand();
+ void revokeCommand();
+
+ // flag whether conf or auth file must be written before exit
+ bool configDirty;
+ bool authDirty;
+
+ void errorInCommand(const char*);
+ int prepareAnswer(char *answMessage);
+ char answBuffer[MAXMSGOUTBUFF+20];
+ bool isCommand(const char *key);
+ char commandBuffer[MAXMSG+20]; //for bug search blva
+
+ void splitRequest(const char* reqMessage);
+ bool isFlag(const char*,int pos=-1);
+ const char * getValueOf(const char*,bool acceptMinus=false); //'-' alone, only void right string
+ const char * getValueIfFlag(const char*,bool acceptMinus=false);
+ void checkUnexpectedTokens();
+ void checkPermission(int reqRights);
+ void checkNotNull(const char *ptr, const char *what);
+ unsigned long convertToULong(const char *stringValue,const char *what);
+
+ RasServer& getServer(const char*); //later, just use rasmanager[serverName]
+ Database& getDatabase(const char *name);
+ DatabaseHost& getDatabaseHost(const char *name);
+ ServerHost& getServerHost(const char *name);
+ User& getUser(const char *name);
+
+ struct Token
+ { char *argv;
+ bool used;
+ void set(char*);
+ const char *take();
+ };
+ int argc;
+ Token token[30];
+
+ };
+extern RasControl rascontrol;
+
+/* obsolete, but in the future...
+ void grantCommand();
+ void revokeCommand();
+
+ void connectCommand();
+ void connectRasServerToDBH();
+ void connectDatabaseToDBH();
+ void connectHelp();
+ void disconnectCommand();
+ void disconnectRasServerFromDBH();
+ void disconnectDatabaseFromDBH();
+ void disconnectHelp();
+ void listRasServersOnDBH(const char*);
+ void listRasServersDatabase(const char*);
+
+*/
+#endif
+
diff --git a/rasmgr/rasmgr_rascontrol_help.cc b/rasmgr/rasmgr_rascontrol_help.cc
new file mode 100644
index 0000000..3ed170a
--- /dev/null
+++ b/rasmgr/rasmgr_rascontrol_help.cc
@@ -0,0 +1,521 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: rasmgr_rascontrol_help.hh
+ *
+ * MODULE: rasmgr
+ * CLASS: RasControl
+ *
+ * PURPOSE:
+ * Decodes, verifies and executes the help commands
+ *
+ * COMMENTS:
+ * Logicaly it's part of rasmgr_rascontrol.cc, but compilation unit was split
+ *
+*/
+
+// this file is a temporary file, used to keep rasmgr_rascontrol things as long as we check each one
+// here are the unchecked things!!
+
+#include "debug.hh"
+#include "rasmgr_rascontrol.hh"
+
+
+void RasControl::helpCommand()
+ {
+ const char *what = argc==1 ? RASMGRCMD_HELP:token[1].take();
+
+ if (strcasecmp(what,RASMGRCMD_LIST)==0) listHelp();
+ else if(strcasecmp(what,RASMGRCMD_DEFINE )==0) defineHelp();
+ else if(strcasecmp(what,RASMGRCMD_REMOVE)==0) removeHelp();
+ else if(strcasecmp(what,RASMGRCMD_CHANGE)==0) changeHelp();
+ else if(strcasecmp(what,RASMGRCMD_UP)==0) upHelp();
+ else if(strcasecmp(what,RASMGRCMD_DOWN)==0) downHelp();
+ else if(strcasecmp(what,RASMGRCMD_SAVE)==0) saveHelp();
+ else if(strcasecmp(what,RASMGRCMD_CHECK)==0) checkHelp();
+ else if(strcasecmp(what,RASMGRCMD_EXIT)==0) exitHelp();
+ else if(strcasecmp(what,RASMGRCMD_QUIT)==0) exitHelp();
+ else if(strcasecmp(what,RASMGRCMD_BYE)==0) exitHelp();
+ else helpHelp();
+
+ // no help for version and licence - they have no further params
+ }
+
+
+void RasControl::helpHelp()
+ {
+ sprintf(answBuffer,"Help for rascontrol command language\r\n"
+ "rasdaman uses the following terms:\r\n"
+ " host (server host) - a computer running a RasManager (rasmgr), with or without currently active servers\r\n"
+ " srv (server) - the rasdaman server (rasserver)\r\n"
+ " dbh (data base host) - a computer running the database software\r\n"
+ " db (database) - the rasdaman database, hosted by the underlying database instance\r\n"
+ " user - a person registered by rasdaman through user name and password\r\n"
+ "\r\nThe rascontrol utility allows to configure and do run-time administration work for the rasdaman system\r\n"
+ "Commands:\r\n"
+ " >help ...this help\r\n"
+ " >exit ...exit rascontrol\r\n"
+ " >list ...list information about the current status of the system\r\n"
+ " >up ...start servers\r\n"
+ " >down ...stop servers and rasmanagers\r\n"
+ " >define ...define a new object\r\n"
+ " >remove ...remove an object\r\n"
+ " >change ...change parameters of objects\r\n"
+ " >save ...make changes permanent\r\n"
+ " >check ...checks the current status of a slave rasmgr\r\n"
+ "Type 'help command' to get specific information about command\r\n"
+
+ );
+ }
+
+void RasControl::listHelp()
+ {
+ checkPermission(admR_info);
+
+ sprintf(answBuffer," The list command:\r\n"
+ "list srv [ s | -host h | -all ] [-p] \r\n"
+ " - list information about 'server s' or 'all servers on host h' or 'all defined servers' (default)\r\n"
+ " '-p' prints configuration information; default: runtime status information\r\n"
+ "list host\r\n"
+ " - list information about server hosts\r\n"
+ "list dbh\r\n"
+ " - list information about database hosts\r\n"
+ "list db [ d | -dbh h | -all ] \r\n"
+ " - list information about 'database s' or all 'databases on database host h' or 'all defined databases'\r\n"
+ "list user [ -rights]\r\n"
+ " - list the defined users\r\n"
+ " '-rights' additionally lists each user's rights\r\n"
+ "list [ license | licencce ]\r\n"
+ " - lists license information\r\n"
+ "list version\r\n"
+ " - list version information"
+ );
+
+ }
+
+void RasControl::defineHelp()
+ { sprintf(answBuffer," The define command:\r\n"
+ "define dbh 'dbhname' -connect 'connectstring'\r\n"
+ " - define database host with symbolic name 'dbhname'\r\n"
+ " 'connectstring' is the string used to connect a client to the underlying database instance\r\n"
+ " (example: user/passwd@hostaddress)\r\n"
+ "define db 'dbname' -dbh 'dbhname'\r\n"
+ " - define database 'dbname' on database host 'dbhname'\r\n"
+ " ('dbname' is not a symbolic name, it is the real name of the rasdaman database)\r\n"
+ "define host 'hostname' -net 'netaddress' [-port 'portnumber']\r\n"
+ " - define server host with symbolic name 'hostname', located at address 'netaddress:portnumber'\r\n"
+ " ('portnumber' defaults to 7001)\r\n"
+ "define srv 'srvname' -host 'hostname' -dbh 'dbhname' -type 'servertype' -port 'portnumber' \r\n"
+ " [-autorestart on|off] [-countdown 'number'] [-xp 'options']\r\n"
+ " - define server with symbolic name 'srvname' on server host 'hostname' connected to database host 'dbhname'\r\n"
+ " 'servertype' can be 'r' (RPC) or 'h' (HTTP) or 'n' (RNP)\r\n"
+ " 'portnumber' is the IP port number for HTTP servers / the 'prognum' for RPC/RNP servers\r\n"
+ " -autorestart (default: on): the server will autorestart after an unexpected termination\r\n"
+ " -countdown 'number' (default: 1000): the server will be restarted after 'number' transactions\r\n"
+ " -xp 'options': extra parameter string 'options' that will be passed to the server at startup \r\n"
+ " (default: \"\", see documentation for valid 'options')\r\n"
+ " this option has to be the last, because anything after it and until end of line is considered to be 'options'\r\n"
+ "define user 'username' [-passwd 'password'] [-rights 'rightsstring']\r\n"
+ " - define user account with symbolic name 'username'\r\n"
+ " 'password' defaults to 'username' (use the raspasswd utility to change)\r\n"
+ " -rights 'rightsstring': the rights granted to the user (default: none; see documentation for valid rights)\r\n"
+ );
+ }
+void RasControl::removeHelp()
+ {
+ sprintf(answBuffer," The remove command:\r\n"
+ "remove dbh 'dbhname'\r\n"
+ " - remove database host 'dbhname'\r\n"
+ "remove db 'dbname' -dbh 'dbhname'\r\n"
+ " - remove database 'dbname' from database host 'dbhname'\r\n"
+ " (the database itself is not deleted, only the name is removed from the config tables)\r\n"
+ "remove host 'hostname' \r\n"
+ " - remove server host 'hostname'\r\n"
+ "remove srv 'srvname'\r\n"
+ " - remove server 'srvname'\r\n"
+ "remove user 'username'\r\n"
+ " - remove the user 'username'\r\n"
+ );
+ }
+
+void RasControl::changeHelp()
+ { sprintf(answBuffer," The change command:\r\n"
+ "change dbh 'dbhname' [-name 'newname'] [-connect 'newconnectstring']\r\n"
+ "change db 'dbname' [-name 'newname']\r\n"
+ "change host 'hostname' [-name 'newname'] [-net 'newnetaddress'] [-port 'newportnumber']\r\n"
+ "change srv 'servername' [-name 'newname'][-dbh 'newdbhname'] [-type 'newservertype'] [-port 'newportnumber'] [-autorestart on|off] [-countdown 'newnumber'] [-xp 'newoptions']\r\n"
+ "change user 'username' [-name 'newname'] [-passwd 'newpasswd] [-rights 'rightsstring']\r\n"
+ " - see the help for the define command for option description\r\n"
+
+ );
+ }
+
+void RasControl::upHelp()
+ { sprintf(answBuffer," The up command:\r\n"
+ "up srv [ s | -host h | -all]\r\n"
+ " - start 'server s' or 'all servers on host h' or 'all defined servers'\r\n"
+ );
+ }
+
+
+void RasControl::downHelp()
+ {sprintf(answBuffer," The down command:\r\n"
+ "down srv [ s | -host h | -all] [ -force] [-kill]\r\n"
+ " - stops 'server s' or 'all started servers on host h' or 'all started servers'\r\n"
+ " -force: stops the 'server s' without waiting to complete the current transaction (using SIGTERM)\r\n"
+ " -kill: instantly stops the 'server s' (using SIGKILL)\r\n"
+ " (without -force or -kill the server completes the current transaction and exits)\r\n"
+ "down host [ h | -all]\r\n"
+ " - stops the rasmgr on 'host h' or all started rasmgr\r\n"
+ );
+ }
+
+void RasControl::checkHelp()
+ {
+ sprintf(answBuffer," The check command\r\n"
+ "check host 'hostname'\r\n"
+ " - checks the status of the slave rasmgr located on server host 'hostname'\r\n"
+ " (use this command if the master rasmgr started after the slave rasmgr for synchronising them)\r\n"
+ );
+ }
+
+void RasControl::saveHelp()
+ {
+ sprintf(answBuffer," The save command\r\n"
+ "save\r\n"
+ " - saves the current configuration information\r\n"
+ " (upon changes the files will be saved automatically to rescue files next to the config files when exiting rasmgr)\r\n"
+ );
+ }
+
+void RasControl::exitHelp()
+ {
+ sprintf(answBuffer," The exit command\r\n"
+ "exit | quit | bye\r\n"
+ " - finish this rascontrol session\r\n"
+ );
+ }
+
+
+
+//### ########### ############# ################ ##############
+
+
+/* obsolete in v1.1, but who knows, in future
+void RasControl::disconnectCommand()
+ {
+ const char *what = argc==1 ? RASMGRCMD_HELP:token[1].take();
+
+ if (strcasecmp(what,"srv")==0) disconnectRasServerFromDBH();
+
+ else if(strcasecmp(what,"db")==0) disconnectDatabaseFromDBH();
+
+ else if(strcasecmp(what,RASMGRCMD_HELP)==0) disconnectHelp();
+
+ else errorInCommand("Wrong DISCONNECT command");
+
+ }
+void RasControl::disconnectRasServerFromDBH()
+ {
+ CHECK(admR_config);
+
+ const char *serverName=getValueOf("srv");
+
+ if(!serverName)
+ { errorInCommand("Server name missing.");
+ return;
+ }
+ RasServer &r=rasManager[serverName];
+
+ if(!r.isValid())
+ { errorInCommand("Invalid server name.");
+ return;
+ }
+ if(r.isUp())
+ { errorInCommand("Cannot disconnet a running server.");
+ return;
+ }
+
+ const char *dbHost=r.getDBHostName();
+
+ if(strcasecmp(dbHost,"noDBHost!")!=0)
+ { sprintf(answBuffer,"Server %s isn't connected to any database host",serverName);
+ return;
+ }
+ if(r.disconnectFromDBHost())
+ { sprintf(answBuffer,"Disconnecting server %s from database host %s",serverName,dbHost);
+ }
+ errorInCommand("Internal error during disconnect.");
+ }
+void RasControl::disconnectDatabaseFromDBH()
+ {
+ CHECK(admR_config);
+
+ const char *dbName=getValueOf("db");
+
+ if(!dbName)
+ { errorInCommand("Database name missing.");
+ return;
+ }
+ const char *dbHost=getValueOf("-dbh");
+
+ if(!dbHost)
+ { errorInCommand("Database host name missing.");
+ return;
+ }
+
+ Database &r=dbManager[dbName];
+ DatabaseHost &d=dbHostManager[dbHost];
+
+ if(!r.isValid())
+ { errorInCommand("Invalid database name.");
+ return;
+ }
+ if(!d.isValid())
+ { errorInCommand("Invalid database host name.");
+ return;
+ }
+
+ if(r.disconnectFromDBHost(dbHost))
+ { sprintf(answBuffer,"Disconnecting database %s from database host %s",dbName,dbHost);
+ }
+ else
+ { sprintf(answBuffer,"Database %s is not connected to database host %s",dbName,dbHost);
+ }
+ }
+void RasControl::disconnectHelp()
+ {
+ sprintf(answBuffer,"Disconnect usage: -sorry, help not available yet");
+ }
+
+//--------------------------------------------------------------
+
+void RasControl::connectCommand()
+ {
+ const char *what = argc==1 ? RASMGRCMD_HELP:token[1].take();
+
+ if (strcasecmp(what,"srv")==0) connectRasServerToDBH();
+
+ else if(strcasecmp(what,"db")==0) connectDatabaseToDBH();
+
+ else if(strcasecmp(what,RASMGRCMD_HELP)==0) connectHelp();
+
+ else errorInCommand("Wrong CONNECT command");
+
+ }
+void RasControl::connectRasServerToDBH()
+ {
+ CHECK(admR_config);
+
+ const char *serverName=getValueOf("srv");
+
+ if(!serverName)
+ { errorInCommand("Server name missing.");
+ return;
+ }
+ const char *dbHost=getValueOf("-dbh");
+
+ if(!dbHost)
+ { errorInCommand("Database host name missing.");
+ return;
+ }
+ RasServer &r=rasManager[serverName];
+ DatabaseHost &d=dbHostManager[dbHost];
+
+ if(!r.isValid())
+ { errorInCommand("Invalid server name.");
+ return;
+ }
+ if(!d.isValid())
+ { errorInCommand("Invalid database host name.");
+ return;
+ }
+
+ // const char *connStr=getValueOf("-conn");
+ // if(!connStr) connStr="\\";
+
+ if(r.connectToDBHost(dbHost))//,connStr))
+ { sprintf(answBuffer,"Connecting server %s to database host %s",serverName,dbHost);
+ }
+ else
+ { sprintf(answBuffer,"Server %s already connected to database host %s",serverName,dbHost);
+ }
+
+ }
+void RasControl::connectDatabaseToDBH()
+ {
+ CHECK(admR_config);
+
+ const char *dbName=getValueOf("db");
+
+ if(!dbName)
+ { errorInCommand("Database name missing.");
+ return;
+ }
+ const char *dbHost=getValueOf("-dbh");
+
+ if(!dbHost)
+ { errorInCommand("Database host name missing.");
+ return;
+ }
+
+ Database &r=dbManager[dbName];
+ DatabaseHost &d=dbHostManager[dbHost];
+
+ if(!r.isValid())
+ { errorInCommand("Invalid database name.");
+ }
+ if(!d.isValid())
+ { errorInCommand("Invalid database host name.");
+ }
+
+ if(r.connectToDBHost(dbHost))
+ { sprintf(answBuffer,"Connecting database %s to database host %s",dbName,dbHost);
+ }
+ else
+ { sprintf(answBuffer,"Database %s already connected to database host %s",dbName,dbHost);
+ }
+ }
+void RasControl::connectHelp()
+ {
+ sprintf(answBuffer,"Connect usage: -sorry, help not available yet");
+ }
+
+void RasControl::listRasServersDatabase(const char *dbName)
+ {
+ CHECK(admR_info);
+
+ if(dbName)
+ { sprintf(answBuffer,"List of servers connected to database %s:",dbName);
+
+ Database &db = dbManager[dbName];
+ if(db.isValid()==false)
+ { sprintf(answBuffer+strlen(answBuffer),"\r\nNo such database");
+ return;
+ }
+ int crnt=0;
+ for(int i=0;i<db.countConnectionsToRasServers();i++)
+ {
+ sprintf(answBuffer+strlen(answBuffer),"\r\n%2d. %s",crnt++,db.getRasServerName(i));
+ }
+ }
+ else
+ {
+ errorInCommand("Database name missing.");
+ }
+ }
+
+void RasControl::listRasServersOnDBH(const char *dbhName)
+ {
+ CHECK(admR_info);
+
+ if(dbhName)
+ { sprintf(answBuffer,"List of servers connected to database host %s:",dbhName);
+
+ int crnt=0;
+ for(int i=0;i<rasManager.countServers();i++)
+ {
+ RasServer &r=rasManager[i];
+ if(strcmp(dbhName,r.getDBHostName())!=0) continue;
+
+ sprintf(answBuffer+strlen(answBuffer),"\r\n%2d. %s (%s)",crnt++,r.getName(),r.getHostName());
+ }
+ }
+ else
+ { sprintf(answBuffer,"List of servers with connected database host:");
+
+ int crnt=0;
+ for(int i=0;i<rasManager.countServers();i++)
+ {
+ RasServer &r=rasManager[i];
+ sprintf(answBuffer+strlen(answBuffer),"\r\n%2d. %-20s %s",crnt++,r.getName(),r.getDBHostName());
+ }
+ }
+ }
+
+*/
+
+
+
+/* no, out
+void RasControl::stopCommand()
+ {
+ CHECK(admR_sysup);
+
+ // sprintf(answBuffer,RASMGRCMD_EXIT);
+ // masterCommunicator.shouldExit();
+ if(rasManager.countUpServers()==0)
+ {
+ sprintf(answBuffer,RASMGRCMD_EXIT);
+ masterCommunicator.shouldExit();
+ }
+ else
+ {
+ sprintf(answBuffer,"Please shut down all servers first.");
+ }
+ }
+
+
+void RasControl::listConnections()
+ {
+ CHECK(admR_info);
+ bool full = isFlag("-full");
+
+ checkUnexpectedTokens();
+
+ int answLen=0;
+ int maxAnswLen=MAXMSGOUTBUFF-100; // if there are many servers, we could get an overflow
+
+ bool overflow=false;
+ sprintf(answBuffer,"List connections\r\n Database Database host Server");
+ for(int i=0;i<dbManager.countDatabases();i++)
+ {
+ Database&db = dbManager[i];
+ const char *dbName = db.getName();
+
+ for(int j=0;j<db.countConnectionsToDBHosts();j++)
+ {
+ const char *dbhName = db.getDBHostName(j);
+ const char* writtenDbhName = dbhName;
+
+ for(int k=0;k < rasManager.countServers();k++)
+ {
+ RasServer &srv = rasManager[k];
+
+ if(strcmp(srv.getDBHostName(),dbhName) == 0)
+ {
+ int len = strlen(answBuffer);
+
+ if(len < maxAnswLen)
+ { sprintf(answBuffer+len,"\r\n %-15s %-20s %-20s",dbName,writtenDbhName,srv.getName());
+ if(full==false) dbName = writtenDbhName =" -\"-";
+ }
+ else overflow=true;
+ }
+ }
+ }
+ }
+ if(overflow) sprintf(answBuffer+strlen(answBuffer),"\r\n(Answer too long, overflow!)");
+ }
+
+*/
diff --git a/rasmgr/rasmgr_srv.cc b/rasmgr/rasmgr_srv.cc
new file mode 100644
index 0000000..542f6dc
--- /dev/null
+++ b/rasmgr/rasmgr_srv.cc
@@ -0,0 +1,858 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: rasmgr_srv.cc
+ *
+ * MODULE: rasmgr
+ * CLASS: RasServer, RasServerManager
+ *
+ * COMMENTS:
+ * None
+*/
+
+#include "rasmgr_srv.hh"
+#include "rasmgr_localsrv.hh"
+#include "rasmgr_comm.hh"
+#include "rasmgr_users.hh"
+
+#include "debug.hh"
+
+// host name returned when we don't have a valid one:
+#define NO_VALID_HOST "noValidHost"
+
+// initial countdown value
+#define INITIAL_COUNTDOWN 1000
+RasServer::RasServer()
+{
+ serverName[0]=0;
+ extraParam[0]=0;
+ ptrServerHost=NULL;
+ ptrDatabaseHost=NULL;
+ //connStr[0]=0;
+ available=isup=isstarting=false;
+ valid=false;
+ downReq=false;
+ initialCountDown = INITIAL_COUNTDOWN;
+ currentCountDown = INITIAL_COUNTDOWN; // asa doreste management
+
+ writeTransaction=false; // no clearTransaction!!
+ readTransaction=false;
+ connDatabase = NULL;
+
+ activityExpected=false;
+ crashCount = 0;
+ activityCounter = 0; // will be changed in init()
+
+ autorestart = true;
+ strcpy(executableName,RASEXECUTABLE);
+}
+
+RasServer::~RasServer()
+{
+}
+
+const char* RasServer::getName()
+{
+ return serverName;
+}
+
+const char* RasServer::getHostName()
+{
+ if(ptrServerHost)
+ {
+ return ptrServerHost->getName();
+ }
+ return NO_VALID_HOST;
+}
+
+const char* RasServer::getHostNetwName()
+{
+ if(ptrServerHost)
+ {
+ return ptrServerHost->getNetworkName();
+ }
+ return NO_VALID_HOST;
+}
+
+long RasServer::getPort()
+{
+ return listenPort;
+}
+char RasServer::getType()
+{
+ return serverType;
+}
+
+void RasServer::changeName(const char *newName)
+{
+// FIXME: input parameter validity check!
+ strncpy( serverName, newName, sizeof(serverName) );
+}
+
+void RasServer::changeType(const char newType) // char not char*!!
+// FIXME: input parameter validity check!
+{
+ serverType=newType;
+}
+
+void RasServer::changePort(long newPort)
+{
+ listenPort=newPort;
+}
+
+void RasServer::changeExtraParam(const char *xParam)
+// FIXME: input parameter validity check!
+{
+ strncpy(extraParam,xParam,sizeof(extraParam) );
+}
+
+void RasServer::changeCountDown(int newCountDown)
+{
+ initialCountDown=newCountDown;
+ currentCountDown=newCountDown;
+}
+
+void RasServer::changeAutoRestart(bool x)
+{
+ autorestart = x;
+}
+
+const char* RasServer::getExtraParams()
+{
+ return extraParam;
+}
+int RasServer::getCountDown()
+{
+ return initialCountDown;
+}
+
+void RasServer::init(const char *srvName,const char* hostName,char serverType,long listenPort)
+{
+ strcpy(this->serverName,srvName);
+
+ ptrServerHost=&hostmanager[hostName];// should be valid!
+
+ isinternal=ptrServerHost->isInternal();
+ available=isup=false;
+ this->serverType=serverType;
+ this->listenPort=listenPort;
+
+ // RNP servers start with first action connectToDBMS() as opposed to the others,
+ // therefore set counter appropriately. -- PB 2002-nov-23
+ switch (serverType)
+ {
+ case SERVERTYPE_FLAG_RPC:
+ case SERVERTYPE_FLAG_HTTP:
+ TALK( "Initializing activity counter to 1 for RPC/HTTP type server." );
+ activityCounter = 1;
+ break;
+ case SERVERTYPE_FLAG_RNP:
+ TALK( "Initializing activity counter to 0 for RNP type server." );
+ activityCounter = 0;
+ break;
+ default:
+ TALK( "Error: illegal server type specifier " << serverType << ", assuming '" << SERVERTYPE_FLAG_RNP << "'." );
+ break;
+ }
+
+ valid=true;
+}
+
+bool RasServer::isValid()
+{
+ return valid;
+}
+
+bool RasServer::isUp()
+{
+ return isup;
+}
+
+bool RasServer::isStarting()
+{
+ return isstarting;
+}
+
+bool RasServer::isAvailable()
+{
+ return available;
+}
+
+bool RasServer::forceAvailable()
+{
+ // this function is just for advanced system debug, not for production work
+ if(isup)
+ {
+ available=true;
+ clearPendingTransaction();
+ return true;
+ }
+ return false;
+}
+
+void RasServer::setNotAvailable()
+{
+ available=false;
+ regularSignalCounter = MAXREGULARCOUNTER;
+}
+
+bool RasServer::isAutoRestart()
+{
+ return autorestart;
+}
+
+char* RasServer::getDescriptionHeader(char *destBuffer)
+{
+ sprintf(destBuffer," %-20s %s %-20s %-20s %-4s %-2s %s %s","Server Name","Type","Host","Db Host","Stat","Av","Acc","Crc");
+ return destBuffer;
+}
+
+char* RasServer::getDescription(char *destBuffer)
+{
+ char *sType="(none)";
+ if(serverType==SERVERTYPE_FLAG_RPC)
+ sType="(RPC) ";
+ if(serverType==SERVERTYPE_FLAG_HTTP)
+ sType="(HTTP)";
+ if(serverType==SERVERTYPE_FLAG_RNP)
+ sType="(RNP) ";
+
+ const char* sUp= isup ? "UP ":"DOWN";
+
+ const char* sAv= available ? "YES":"NO ";
+
+ const char* host= ptrServerHost->getName();//"(internal)";
+
+ const char* dbHost = getDBHostName();
+ //if(isinternal==false)
+ // { host=ptrServerHost->getName();
+ // }
+ sprintf(destBuffer,"%-20s %s %-20s %-20s %s %s %6ld %2d",serverName,sType,host,dbHost,sUp,sAv,activityCounter,crashCount);
+
+ return destBuffer;
+}
+
+char* RasServer::getDescriptionPortHeader(char *destBuffer)
+{
+ sprintf(destBuffer," %-20s %s %-20s %-10s %-3s %-3s","Server Name","Type","Host"," Port","Ars"," Icd");
+
+ return destBuffer;
+}
+
+char* RasServer::getDescriptionPort(char *destBuffer)
+{
+ char *sType="(none)";
+ if(serverType==SERVERTYPE_FLAG_RPC) sType="(RPC) ";
+ if(serverType==SERVERTYPE_FLAG_HTTP) sType="(HTTP)";
+ if(serverType==SERVERTYPE_FLAG_RNP) sType="(RNP) ";
+
+// const char* sUp= isup ? "UP ":"DOWN";
+
+// const char* sAv= available ? "YES":"NO ";
+
+ const char* host = ptrServerHost->getName();
+
+ const char *ars = autorestart ? "on":"off";
+
+ if(serverType==SERVERTYPE_FLAG_RPC)
+ sprintf(destBuffer,"%-20s %s %-20s %#10x %-3s %3d/%-3d",serverName,sType,host,listenPort,ars,currentCountDown,initialCountDown);
+ else
+ sprintf(destBuffer,"%-20s %s %-20s %10d %-3s %3d/%-3d",serverName,sType,host,listenPort,ars,currentCountDown,initialCountDown);
+ //countdown=%d InitialCountDown,
+ return destBuffer;
+}
+
+char* RasServer::getDescriptionExecHeader(char *destBuffer)
+{
+ sprintf(destBuffer," %-20s %-10s Executable Extraparameters","Server Name","Host");
+
+ return destBuffer;
+}
+
+char* RasServer::getDescriptionExec(char *destBuffer)
+{
+
+ const char* host = ptrServerHost->getName();
+
+ sprintf(destBuffer,"%-20s %-10s %-15s %s",serverName,host,executableName,extraParam);
+
+ return destBuffer;
+}
+
+bool RasServer::connectToDBHost(const char *dbHostName)//, const char *connString)
+{
+ if(ptrDatabaseHost)
+ return false;
+ DatabaseHost &dbh=dbHostManager[dbHostName];
+
+ if(dbh.isValid()==false)
+ return false;
+
+ ptrDatabaseHost = &dbh;
+ //removed dbh.incrConnServers();
+ //strcpy(connStr,connString);
+
+ for(int i=0;i<dbManager.countDatabases();i++)
+ {
+ if(dbManager[i].isConnectedToDBHost(dbHostName))
+ {
+ dbManager[i].connectToRasServer(serverName);
+ }
+ }
+ return true;
+}
+
+bool RasServer::disconnectFromDBHost()
+{
+ if(isup)
+ return false;
+ if(ptrDatabaseHost==NULL)
+ return false;
+
+ const char *dbHostname=ptrDatabaseHost->getName();
+
+ for(int i=0;i<dbManager.countDatabases();i++)
+ {
+ dbManager[i].disconnectFromRasServer(serverName);
+ }
+
+ // removed ptrDatabaseHost->decrConnServers();
+ ptrDatabaseHost=NULL;
+
+ return true;
+}
+
+const char* RasServer::getDBHostName()
+{
+ if(ptrDatabaseHost)
+ return ptrDatabaseHost->getName();
+ return "noDBHost!";
+}
+
+bool RasServer::isConnectedToDBHost()
+{
+ if(ptrDatabaseHost)
+ return true;
+ return false;
+}
+
+void RasServer::changeExecutableName(const char *newExecutable)
+{
+ if(newExecutable == NULL)
+ strcpy(executableName,RASEXECUTABLE);
+ else
+ strcpy(executableName,newExecutable);
+}
+
+const char* RasServer::getExecutableName()
+{
+ return executableName;
+}
+
+int RasServer::startServerInDebugger(char *command)
+{
+ // sorry for literals, I will change this soon
+ if(ptrDatabaseHost==NULL)
+ return -1;
+
+ if(ptrServerHost->isUp()==false)
+ return -5;
+
+ downReq=false;
+ const char *sTypeString= serverType==SERVERTYPE_FLAG_HTTP ? "--http":"";
+
+ const char *rasmgrHost = ptrServerHost->useLocalHost() ? "localhost" : config.getHostName();
+ sprintf(command, "%s --rsn %s %s --lport %ld ",executableName,serverName,sTypeString,listenPort);
+ sprintf(command+strlen(command),"--mgr %s --mgrport %ld --connect %s ",rasmgrHost,config.getListenPort(),ptrDatabaseHost->getConnectionString());
+ sprintf(command+strlen(command),"--sync %s %s",authorization.getSyncroString(),extraParam);
+
+ currentCountDown=initialCountDown;
+ activityExpected=true;
+ activityCounter = 0;
+
+ TALK( "RasServer::startServerInDebugger() -> " << command );
+ return 0;
+}
+
+int RasServer::startServer()
+{ // sorry for literals, I will change this soon
+ if(ptrDatabaseHost==NULL)
+ return -1;
+
+ if(ptrServerHost->isUp()==false)
+ return -5;
+
+ downReq=false;
+ const char *sTypeString= serverType==SERVERTYPE_FLAG_HTTP ? "--http" : "";
+ sTypeString= serverType==SERVERTYPE_FLAG_RNP ? "--rnp" : sTypeString;
+
+ const char *rasmgrHost = ptrServerHost->useLocalHost() ? "localhost" : config.getHostName();
+ char command[400];
+ sprintf(command, "%s %s %s --rsn %s %s --lport %ld ",serverName,executableName,executableName,serverName,sTypeString,listenPort);
+ sprintf(command+strlen(command),"--mgr %s --mgrport %ld --connect %s ",rasmgrHost,config.getListenPort(),ptrDatabaseHost->getConnectionString());
+ sprintf(command+strlen(command)," %s",extraParam);
+
+ if(isinternal)
+ {
+ TALK( "launching local server, command=" << command );
+ localServerManager.startNewServer(command);
+ }
+ else
+ {
+ TALK( "connecting to remote rasmgr" );
+ int socket=ptrServerHost->getConnectionSocket();
+ if(socket<0)
+ return -3;
+
+ char message[MAXMSG]="POST exec HTTP/1.1\r\nAccept: text/plain\r\nUserAgent: RasMGR/1.0\r\nContent-length: ";
+
+ sprintf(message+strlen(message),"%d\r\n\r\n%s",strlen(command)+1,command);
+
+ int nbytes=write(socket,message,strlen(message)+1);
+
+ close(socket);
+ if(nbytes<0)
+ return -4;
+ }
+
+ currentCountDown=initialCountDown;
+ activityExpected=true;
+ isstarting=true;
+ activityCounter = 0;
+ return 0;
+}
+int RasServer::downServer(bool forced)
+{
+ if(available==false && (forced == false || isstarting==true) )
+ {
+ downReq=true;
+ //std::cout<<"Down request, but working"<<std::endl;
+ return 0;
+ }
+ return downNow();
+}
+int RasServer::downNow()
+{
+ //std::cout<<"Down server"<<std::endl;
+ if(isinternal)
+ {
+ localServerManager.sendTerminateSignal(serverName);
+ }
+ else
+ {
+ int socket=ptrServerHost->getConnectionSocket();
+ if(socket<0)
+ return -2;
+
+ char message[MAXMSG]="POST downserver HTTP/1.1\r\nAccept: text/plain\r\nUserAgent: RasMGR/1.0\r\nContent-length: ";
+
+ sprintf(message+strlen(message),"%d\r\n\r\n%s",strlen(serverName)+1,serverName);
+
+ int nbytes=write(socket,message,strlen(message)+1);
+
+ close(socket);
+ if(nbytes<0)
+ return -3;
+ }
+
+ //ptrServerHost->regDownServer();
+
+ return 0;
+}
+int RasServer::killServer()
+{
+ if(isup)
+ {
+ ptrServerHost->regDownServer();
+ if(ptrDatabaseHost)
+ ptrDatabaseHost->regDownServer();
+ isup=available=0;
+ activityExpected=false;
+ }
+ if(isinternal)
+ {
+ localServerManager.killServer(serverName);
+ }
+ else
+ {
+ int socket=ptrServerHost->getConnectionSocket();
+ if(socket<0)
+ return -2;
+
+ char message[MAXMSG]="POST killserver HTTP/1.1\r\nAccept: text/plain\r\nUserAgent: RasMGR/1.0\r\nContent-length: ";
+
+ sprintf(message+strlen(message),"%d\r\n\r\n%s",strlen(serverName)+1,serverName);
+
+ int nbytes=write(socket,message,strlen(message)+1);
+
+ close(socket);
+ if(nbytes<0)
+ return -3;
+ }
+
+ return 0;
+}
+
+void RasServer::changeStatus(int newStatus,long infCount)
+{
+ ENTER( "RasServer::changeStatus: enter. servername="<<serverName<<", newStatus="<<newStatus<<", c="<<infCount );
+
+ if(activityExpected==false && newStatus==SERVER_AVAILABLE)
+ {
+ std::cout<<"Error: Server intruder detected in server '"<<serverName<< "' (trying to manually start rasserver?)"<<std::endl;
+ return;
+ }
+
+ if(newStatus == SERVER_REGULARSIG)
+ {
+ TALK( "RasServer::changeStatus: SERVER_REGULARSIG from "<<serverName<<", newStatus=" << newStatus );
+
+ if(available == false)
+ {
+ TALK( "RasServer::changeStatus: "<<serverName<<" not available, SERVER_REGULARSIG ok, regularSignalCounter="<<regularSignalCounter);
+ regularSignalCounter--;
+ if(regularSignalCounter > 0)
+ {
+ LEAVE( "RasServer::changeStatus: leave. regularSignalCounter nonzero: " << regularSignalCounter );
+ return;
+ }
+ newStatus = SERVER_AVAILABLE;
+ VLOG <<"rasmgr: Dead client detected, server "<<serverName<<" is set free again."<<std::endl;
+ }
+ else
+ {
+ LEAVE( "RasServer::changeStatus: leave. srv not available." );
+ return;
+ }
+ }
+ bool wasup=isup;
+
+ bool crashed= (newStatus == SERVER_CRASHED) ? true:false;
+
+ isup=available= (newStatus == SERVER_AVAILABLE) ? true:false;
+
+ TALK( "RasServer::changeStatus: wasup=" << wasup << ", isup=" << isup );
+
+ if(wasup==false && isup==true)
+ {
+ ptrServerHost->regStartServer();
+ if(ptrDatabaseHost)
+ ptrDatabaseHost->regStartServer();
+ isstarting=false;
+ }
+ if(wasup==true && isup==false)
+ {
+ //then, ok, I'm down
+ ptrServerHost->regDownServer();
+ if(ptrDatabaseHost)
+ ptrDatabaseHost->regDownServer();
+ activityExpected=false;
+ }
+
+ clearPendingTransaction(); // when the server talks to RasMgr, is always clear, without client
+
+ if(available)
+ {
+ activityCounter++; // just a counter
+ }
+
+ if(downReq && available)
+ {
+ downReq=false;
+ available=false; //until it's really down it shouldn't get any clients
+ TALK( "RasServer::changeStatus: srv down request, available - setting to unavailable and shutting down. ");
+ downNow();
+ }
+
+ if(crashed)
+ {
+ crashCount++;
+ TALK( "server has crashed, current crash count is " << crashCount << ", activity count is " << activityCounter );
+ // restart if "work has started already" (see init() comment on different counting wrt. server types)
+ // changed by PB 2003-nov-23
+ // if(activityCounter && autorestart)
+ if (activityCounter>1 && autorestart)
+ { // a crashed server doesn't autorestart if he crashes before starting work.
+ TALK( "auto restart activated, restarting." );
+ startServer();
+ }
+ }
+
+ // commented out due to some error
+ if(initialCountDown)
+ {
+ VLOG <<"rasmgr: initialCountDown==" << initialCountDown << std::endl;
+ if(available)
+ {
+ VLOG <<"rasmgr: available" << std::endl;
+ currentCountDown--;
+ if(currentCountDown==0)
+ {
+ available=false;
+ VLOG <<"rasmgr: Countdown reached for "<<serverName<< ", shutting down." << std::endl;
+ downNow();
+ }
+ }
+ if(wasup==true && isup==false && currentCountDown==0)
+ {
+ VLOG <<"rasmgr: wasup==true && isup==false && currentCountDown==0" << std::endl;
+ VLOG <<"rasmgr: Restart after countdown for server "<<serverName<< "." << std::endl;
+ currentCountDown=initialCountDown;
+ startServer();
+ }
+ }
+
+ LEAVE( "RasServer::changeStatus: leave. ns="<<newStatus<<" av="<<available );
+} // changeStatus()
+
+void RasServer::startWriteTransaction(Database& dataBase)
+{
+ ENTER( "RasServer::startWriteTransaction: enter." );
+ dataBase.startWriteTransaction();
+ writeTransaction=true;
+ connDatabase=&dataBase;
+ LEAVE( "RasServer::startWriteTransaction: leave. servername=" << serverName << ", rwTrans-in on db " << dataBase.getName() );
+}
+
+void RasServer::startReadTransaction(Database& dataBase)
+{
+ ENTER( "RasServer::startReadTransaction: enter." );
+ dataBase.startReadTransaction();
+ readTransaction=true;
+ connDatabase=&dataBase;
+ LEAVE( "RasServer::startReadTransaction: leave. servername=" << serverName << " roTrans-in on db " << dataBase.getName() );
+}
+
+void RasServer::clearPendingTransaction()
+{
+ if(connDatabase)
+ if(writeTransaction)
+ connDatabase->endWriteTransaction();
+ if(readTransaction )
+ connDatabase->endReadTransaction();
+ writeTransaction=false;
+ readTransaction =false;
+ connDatabase = NULL;
+}
+//**********************************************************************
+RasServerManager::RasServerManager()
+{
+}
+RasServerManager::~RasServerManager()
+{
+}
+
+bool RasServerManager::insertNewServer(const char *srvName,const char* hostName,char serverType,long listenPort)
+{
+ bool result = true;
+
+ if(testUniqueness(srvName)==false)
+ result = false;
+
+ if( result == true && hostmanager[hostName].isValid()==false)
+ result = false;
+
+ if(result == true && serverType!=SERVERTYPE_FLAG_RPC && serverType!=SERVERTYPE_FLAG_HTTP && serverType!=SERVERTYPE_FLAG_RNP)
+ {
+ TALK( "RasServerManager::insertNewServer: server " << srvName << " has illegal type " << serverType );
+ result = false;
+ }
+
+ if (result == true)
+ {
+ RasServer tempRasServer;
+ srvList.push_back(tempRasServer);
+ RasServer &refRasServer=srvList.back();
+ refRasServer.init(srvName,hostName,serverType,listenPort);
+ }
+
+ return result;
+}
+
+bool RasServerManager::removeServer(const char *srvName)
+{
+ list<RasServer>::iterator iter=srvList.begin();
+ for(int i=0;i<srvList.size();i++)
+ {
+ if(strcmp(iter->getName(),srvName)==0)
+ {
+ if(iter->isUp())
+ return false;
+
+ iter->disconnectFromDBHost(); //it's not up, so it fails only if it is not connected at all
+
+ srvList.erase(iter);
+ return true;
+ }
+ iter++;
+ }
+ return false;
+}
+
+bool RasServerManager::testUniqueness(const char* srvName)
+{
+ list<RasServer>::iterator iter=srvList.begin();
+ for(int i=0;i<srvList.size();i++)
+ {
+ if(strcmp(iter->getName(),srvName)==0)
+ return false;
+ iter++;
+ }
+ return true;
+}
+
+RasServer& RasServerManager::operator[](int x) // FIXME: check against upper limit
+{
+ list<RasServer>::iterator iter=srvList.begin();
+ for(int i=0;i<x;i++)
+ iter++;
+ return *iter;
+}
+
+RasServer& RasServerManager::operator[](const char* srvName) // FIXME: check against upper limit
+{
+ list<RasServer>::iterator iter=srvList.begin();
+ for(int i=0;i<srvList.size();i++)
+ {
+ if(strcmp(iter->getName(),srvName)==0)
+ return *iter;
+
+ iter++;
+ }
+ return protElem;
+}
+
+RasServer& RasServerManager::last()
+{
+ return srvList.back();
+}
+
+
+int RasServerManager::countServers()
+{
+ return srvList.size();
+}
+
+// return values of changeServerStatus:
+#define SERVERSTATUS_OK 0
+#define SERVERSTATUS_ERR -1
+int RasServerManager::changeServerStatus(char *reqMessage)
+{
+ char serverName[50];
+ int newstatus;
+ long infCount;
+
+ sscanf(reqMessage,"%s %d %ld",serverName,&newstatus,&infCount);
+ TALK( "RasServerManager::changeServerStatus: Trying to change status of "<<serverName<<" to "<<newstatus );
+ RasServer &r=operator[](serverName);
+
+ if(r.isValid()==false)
+ {
+ std::cout<<"Error: Unexpected message from rasserver '"<<serverName<<"'; new status is "<<newstatus<<std::endl;
+ return SERVERSTATUS_ERR;
+ }
+
+ r.changeStatus(newstatus,infCount);
+ return SERVERSTATUS_OK;
+}
+
+void RasServerManager::disconnectAllServersFromDBH(const char *dbhName)
+{
+ list<RasServer>::iterator iter=srvList.begin();
+ for(int i=0;i<srvList.size();i++,iter++)
+ {
+ const char *cDbhName=iter->getDBHostName();
+
+ if(cDbhName==NULL)
+ continue;
+
+ if(strcmp(cDbhName,dbhName)==0) iter->disconnectFromDBHost();
+ }
+
+}
+
+int RasServerManager::countUpServers()
+{
+ int count=0;
+ list<RasServer>::iterator iter=srvList.begin();
+ for(int i=0;i<srvList.size();i++)
+ {
+ if(iter->isUp())
+ count++;
+ iter++;
+ }
+
+ TALK( "RasServerManager::countUpServers() -> " << count );
+ return count;
+
+}
+
+void RasServerManager::printStatus()
+{
+ char buff[100];
+ list<RasServer>::iterator iter=srvList.begin();
+
+ TALK( "RasServerManager::printStatus. current status is:" );
+ for(int i=0;i<srvList.size();i++)
+ {
+ iter->getDescription(buff);
+ TALK( "\t" << i << ": " << buff );
+ iter++;
+ }
+
+}
+
+bool RasServerManager::reset()
+{ // test modus only
+ if(config.isTestModus()==false)
+ return false;
+
+ list<RasServer>::iterator iter=srvList.begin();
+ for(int i=0;i<srvList.size();i++, iter++)
+ {
+ if(iter->isUp())
+ return false;
+ }
+
+ iter=srvList.begin();
+ for(int i=0;i<srvList.size();i++, iter++)
+ {
+ iter->disconnectFromDBHost(); //it's not up, so it fails only if it is not connected at all
+ }
+
+ while(srvList.size())
+ {
+ srvList.pop_front();
+ }
+ return true;
+
+}
+
+bool RasServerManager::acceptChangeName(const char *oldName,const char *newName)
+{
+ if(strcmp(oldName,newName)==0)
+ return true; // if someone really wants to change a name with the same,
+ return testUniqueness(newName);
+}
+
+
diff --git a/rasmgr/rasmgr_srv.cc.ORIG b/rasmgr/rasmgr_srv.cc.ORIG
new file mode 100644
index 0000000..ed0dddc
--- /dev/null
+++ b/rasmgr/rasmgr_srv.cc.ORIG
@@ -0,0 +1,840 @@
+/*************************************************************************
+ *
+ * Copyright (C) 2003 Dr. Peter Baumann
+ *
+ * SOURCE: rasmgr_srv.cc
+ *
+ * MODULE: rasmgr
+ * CLASS: RasServer, RasServerManager
+ *
+ * PURPOSE:
+ *
+ *
+ * CHANGE HISTORY (append further entries):
+ * when who what
+ * -----------------------------------------------------------------------
+ * 05-Jan-01 schatz created
+ * 2003-jun-06 PB symbolic constants for server flags
+ *
+ * COMMENTS:
+ *
+ *
+ ***********************************************************************/
+
+#include "rasmgr_srv.hh"
+#include "rasmgr_localsrv.hh"
+#include "rasmgr_comm.hh"
+#include "rasmgr_users.hh"
+
+// the following is a quick hack until the real rminit/debug stuff links properly:
+#if 0
+ #include "raslib/rminit.hh"
+ #include "debug.hh"
+#else
+ #ifdef DEBUG
+ #define ENTER(a) { cout << "ENTER: " << a << endl; }
+ #define LEAVE(a) { cout << "LEAVE: " << a << endl; }
+ #define TALK(a) { cout << a << endl; }
+ #define SET_OUTPUT(a)
+ #else
+ #define ENTER(a) { ; }
+ #define LEAVE(a) { ; }
+ #define TALK(a) { ; }
+ #define SET_OUTPUT(a)
+ #endif
+#endif // 0
+
+
+RasServer::RasServer()
+{
+ serverName[0]=0;
+ extraParam[0]=0;
+ ptrServerHost=NULL;
+ ptrDatabaseHost=NULL;
+ //connStr[0]=0;
+ available=isup=isstarting=false;
+ valid=false;
+ downReq=false;
+ initialCountDown=1000;
+ currentCountDown=1000; // asa doreste management
+
+ writeTransaction=false; // no clearTransaction!!
+ readTransaction=false;
+ connDatabase = NULL;
+
+ activityExpected=false;
+ crashCount = 0;
+ activityCounter = 0; // will be changed in init()
+
+ autorestart = true;
+ strcpy(executableName,RASEXECUTABLE);
+}
+RasServer::~RasServer()
+{
+}
+
+const char* RasServer::getName()
+{
+ return serverName;
+}
+
+const char* RasServer::getHostName()
+{
+ if(ptrServerHost)
+ {
+ return ptrServerHost->getName();
+ }
+ return "noValidHost!";
+}
+
+const char* RasServer::getHostNetwName()
+{
+ if(ptrServerHost)
+ {
+ return ptrServerHost->getNetworkName();
+ }
+ return "noValidHost!";
+}
+
+long RasServer::getPort()
+{
+ return listenPort;
+}
+char RasServer::getType()
+{
+ return serverType;
+}
+
+void RasServer::changeName(const char *newName)
+{
+ strncpy( serverName, newName, sizeof(serverName) );
+}
+
+void RasServer::changeType(const char newType) // char not char*!!
+{ serverType=newType;
+}
+
+void RasServer::changePort(long newPort)
+{ listenPort=newPort;
+}
+
+void RasServer::changeExtraParam(const char *xParam)
+{
+ strncpy(this->extraParam,xParam,sizeof(extraParam) );
+}
+
+void RasServer::changeCountDown(int newCountDown)
+{
+ initialCountDown=newCountDown;
+ currentCountDown=newCountDown;
+}
+
+void RasServer::changeAutoRestart(bool x)
+{
+ autorestart = x;
+}
+
+const char* RasServer::getExtraParams()
+{
+ return extraParam;
+}
+int RasServer::getCountDown()
+{
+ return initialCountDown;
+}
+
+void RasServer::init(const char *srvName,const char* hostName,char serverType,long listenPort)
+{
+ strcpy(this->serverName,srvName);
+
+ ptrServerHost=&hostmanager[hostName];// should be valid!
+
+ isinternal=ptrServerHost->isInternal();
+ available=isup=false;
+ this->serverType=serverType;
+ this->listenPort=listenPort;
+
+ // RNP servers start with first action connectToDBMS() as opposed to the others,
+ // therefore adapt counter. -- PB 2002-nov-23
+ switch (serverType)
+ {
+ case 'r':
+ case 'h':
+ activityCounter = 1;
+ break:
+ case 'n':
+ activityCounter = 0;
+ break:
+ default:
+ TALK( "Error: illegal server type specifier " << serverType << ", assuming 'n'." );
+ break;
+ }
+
+ valid=true;
+}
+
+bool RasServer::isValid()
+{
+ return valid;
+}
+bool RasServer::isUp()
+{
+ return isup;
+}
+bool RasServer::isStarting()
+{
+ return isstarting;
+}
+
+bool RasServer::isAvailable()
+{
+ return available;
+}
+bool RasServer::forceAvailable()
+{
+ // this function is just for advanced system debug, not for production work
+ if(isup)
+ {
+ available=true;
+ clearPendingTransaction();
+ return true;
+ }
+ return false;
+}
+
+void RasServer::setNotAvailable()
+{
+ available=false;
+ regularSignalCounter = MAXREGULARCOUNTER;
+}
+bool RasServer::isAutoRestart()
+{
+ return autorestart;
+}
+
+char* RasServer::getDescriptionHeader(char *destBuffer)
+{
+ sprintf(destBuffer," %-20s %s %-20s %-20s %-4s %-2s %s %s","Server Name","Type","Host","Db Host","Stat","Av","Acc","Crc");
+ return destBuffer;
+}
+
+char* RasServer::getDescription(char *destBuffer)
+{
+ char *sType="(none)";
+ if(serverType==SERVERTYPE_FLAG_RPC) sType="(RPC) ";
+ if(serverType==SERVERTYPE_FLAG_HTTP) sType="(HTTP)";
+ if(serverType==SERVERTYPE_FLAG_RNP) sType="(RNP) ";
+
+ const char* sUp= isup ? "UP ":"DOWN";
+
+ const char* sAv= available ? "YES":"NO ";
+
+ const char* host= ptrServerHost->getName();//"(internal)";
+
+ const char* dbHost = getDBHostName();
+ //if(isinternal==false)
+ // { host=ptrServerHost->getName();
+ // }
+ sprintf(destBuffer,"%-20s %s %-20s %-20s %s %s %6ld %2d",serverName,sType,host,dbHost,sUp,sAv,activityCounter,crashCount);
+
+ return destBuffer;
+}
+
+char* RasServer::getDescriptionPortHeader(char *destBuffer)
+{
+ sprintf(destBuffer," %-20s %s %-20s %-10s %-3s %-3s","Server Name","Type","Host"," Port","Ars"," Icd");
+
+ return destBuffer;
+}
+
+char* RasServer::getDescriptionPort(char *destBuffer)
+{
+ char *sType="(none)";
+ if(serverType==SERVERTYPE_FLAG_RPC) sType="(RPC) ";
+ if(serverType==SERVERTYPE_FLAG_HTTP) sType="(HTTP)";
+ if(serverType==SERVERTYPE_FLAG_RNP) sType="(RNP) ";
+
+// const char* sUp= isup ? "UP ":"DOWN";
+
+// const char* sAv= available ? "YES":"NO ";
+
+ const char* host = ptrServerHost->getName();
+
+ const char *ars = autorestart ? "on":"off";
+
+ if(serverType==SERVERTYPE_FLAG_RPC)
+ sprintf(destBuffer,"%-20s %s %-20s %#10x %-3s %3d/%-3d",serverName,sType,host,listenPort,ars,currentCountDown,initialCountDown);
+ else
+ sprintf(destBuffer,"%-20s %s %-20s %10d %-3s %3d/%-3d",serverName,sType,host,listenPort,ars,currentCountDown,initialCountDown);
+ //countdown=%d InitialCountDown,
+ return destBuffer;
+}
+
+char* RasServer::getDescriptionExecHeader(char *destBuffer)
+{
+ sprintf(destBuffer," %-20s %-10s Executable Extraparameters","Server Name","Host");
+
+ return destBuffer;
+}
+
+char* RasServer::getDescriptionExec(char *destBuffer)
+{
+
+ const char* host = ptrServerHost->getName();
+
+ sprintf(destBuffer,"%-20s %-10s %-15s %s",serverName,host,executableName,extraParam);
+
+ return destBuffer;
+}
+
+bool RasServer::connectToDBHost(const char *dbHostName)//, const char *connString)
+{
+ if(ptrDatabaseHost)
+ return false;
+ DatabaseHost &dbh=dbHostManager[dbHostName];
+
+ if(dbh.isValid()==false)
+ return false;
+
+ ptrDatabaseHost = &dbh;
+ //removed dbh.incrConnServers();
+ //strcpy(connStr,connString);
+
+ for(int i=0;i<dbManager.countDatabases();i++)
+ {
+ if(dbManager[i].isConnectedToDBHost(dbHostName))
+ {
+ dbManager[i].connectToRasServer(serverName);
+ }
+ }
+ return true;
+}
+
+bool RasServer::disconnectFromDBHost()
+{
+ if(isup)
+ return false;
+ if(ptrDatabaseHost==NULL)
+ return false;
+
+ const char *dbHostname=ptrDatabaseHost->getName();
+
+ for(int i=0;i<dbManager.countDatabases();i++)
+ {
+ dbManager[i].disconnectFromRasServer(serverName);
+ }
+
+ // removed ptrDatabaseHost->decrConnServers();
+ ptrDatabaseHost=NULL;
+
+ return true;
+}
+
+const char* RasServer::getDBHostName()
+{
+ if(ptrDatabaseHost)
+ return ptrDatabaseHost->getName();
+ return "noDBHost!";
+}
+
+bool RasServer::isConnectedToDBHost()
+{
+ if(ptrDatabaseHost)
+ return true;
+ return false;
+}
+
+void RasServer::changeExecutableName(const char *newExecutable)
+{
+ if(newExecutable == NULL)
+ strcpy(executableName,RASEXECUTABLE);
+ else
+ strcpy(executableName,newExecutable);
+}
+
+const char* RasServer::getExecutableName()
+{
+ return executableName;
+}
+
+int RasServer::startServerInDebugger(char *command)
+{
+ // sorry for literals, I will change this soon
+ if(ptrDatabaseHost==NULL)
+ return -1;
+
+ if(ptrServerHost->isUp()==false)
+ return -5;
+
+ if(ptrServerHost->mayStartServer()==false)
+ return -2;
+
+ downReq=false;
+ const char *sTypeString= serverType==SERVERTYPE_FLAG_HTTP ? "--http":"";
+
+ const char *rasmgrHost = ptrServerHost->useLocalHost() ? "localhost" : config.getHostName();
+ sprintf(command, "%s --rsn %s %s --lport %ld ",executableName,serverName,sTypeString,listenPort);
+ sprintf(command+strlen(command),"--mgr %s --mgrport %ld --connect %s ",rasmgrHost,config.getListenPort(),ptrDatabaseHost->getConnectionString());
+ sprintf(command+strlen(command),"--sync %s %s",authorization.getSyncroString(),extraParam);
+
+ currentCountDown=initialCountDown;
+ activityExpected=true;
+ activityCounter = 0;
+ return 0;
+}
+
+int RasServer::startServer()
+{ // sorry for literals, I will change this soon
+ if(ptrDatabaseHost==NULL)
+ return -1;
+
+ if(ptrServerHost->isUp()==false)
+ return -5;
+
+ if(ptrServerHost->mayStartServer()==false)
+ return -2;
+
+ downReq=false;
+ const char *sTypeString= serverType==SERVERTYPE_FLAG_HTTP ? "--http" : "";
+ sTypeString= serverType==SERVERTYPE_FLAG_RNP ? "--rnp" : sTypeString;
+
+ const char *rasmgrHost = ptrServerHost->useLocalHost() ? "localhost" : config.getHostName();
+ char command[400];
+ sprintf(command, "%s %s %s --rsn %s %s --lport %ld ",serverName,executableName,executableName,serverName,sTypeString,listenPort);
+ sprintf(command+strlen(command),"--mgr %s --mgrport %ld --connect %s ",rasmgrHost,config.getListenPort(),ptrDatabaseHost->getConnectionString());
+ sprintf(command+strlen(command)," %s",extraParam);
+
+ if(isinternal)
+ {
+ TALK( "launching local server, command=" << command );
+ localServerManager.startNewServer(command);
+ }
+ else
+ {
+ TALK( "connecting to remote rasmgr" );
+ int socket=ptrServerHost->getConnectionSocket();
+ if(socket<0)
+ return -3;
+
+ char message[MAXMSG]="POST exec HTTP/1.1\r\nAccept: text/plain\r\nUserAgent: RasMGR/1.0\r\nContent-length: ";
+
+ sprintf(message+strlen(message),"%d\r\n\r\n%s",strlen(command)+1,command);
+
+ int nbytes=write(socket,message,strlen(message)+1);
+
+ close(socket);
+ if(nbytes<0)
+ return -4;
+ }
+
+ currentCountDown=initialCountDown;
+ activityExpected=true;
+ isstarting=true;
+ activityCounter = 0;
+ return 0;
+}
+int RasServer::downServer(bool forced)
+{
+ if(available==false && (forced == false || isstarting==true) )
+ {
+ downReq=true;
+ //std::cout<<"Down request, but working"<<std::endl;
+ return 0;
+ }
+ return downNow();
+}
+int RasServer::downNow()
+{
+ //std::cout<<"Down server"<<std::endl;
+ if(isinternal)
+ {
+ localServerManager.sendTerminateSignal(serverName);
+ }
+ else
+ {
+ int socket=ptrServerHost->getConnectionSocket();
+ if(socket<0)
+ return -2;
+
+ char message[MAXMSG]="POST downserver HTTP/1.1\r\nAccept: text/plain\r\nUserAgent: RasMGR/1.0\r\nContent-length: ";
+
+ sprintf(message+strlen(message),"%d\r\n\r\n%s",strlen(serverName)+1,serverName);
+
+ int nbytes=write(socket,message,strlen(message)+1);
+
+ close(socket);
+ if(nbytes<0)
+ return -3;
+ }
+
+ //ptrServerHost->regDownServer();
+
+ return 0;
+}
+int RasServer::killServer()
+{
+ if(isup)
+ {
+ ptrServerHost->regDownServer();
+ if(ptrDatabaseHost)
+ ptrDatabaseHost->regDownServer();
+ isup=available=0;
+ activityExpected=false;
+ }
+ if(isinternal)
+ {
+ localServerManager.killServer(serverName);
+ }
+ else
+ {
+ int socket=ptrServerHost->getConnectionSocket();
+ if(socket<0)
+ return -2;
+
+ char message[MAXMSG]="POST killserver HTTP/1.1\r\nAccept: text/plain\r\nUserAgent: RasMGR/1.0\r\nContent-length: ";
+
+ sprintf(message+strlen(message),"%d\r\n\r\n%s",strlen(serverName)+1,serverName);
+
+ int nbytes=write(socket,message,strlen(message)+1);
+
+ close(socket);
+ if(nbytes<0)
+ return -3;
+ }
+
+ return 0;
+}
+
+void RasServer::changeStatus(int newStatus,long infCount)
+{
+ ENTER( "RasServer::changeStatus: enter. servername="<<serverName<<", newStatus="<<newStatus<<", c="<<infCount );
+
+ if(activityExpected==false && newStatus==SERVER_AVAILABLE)
+ {
+ std::cout<<"Server intruder detected in server "<<serverName<< "; (not allowed to start rasserver manually)"<<std::endl;
+ return;
+ }
+
+ if(newStatus == SERVER_REGULARSIG)
+ {
+ TALK( "RasServer::changeStatus: SERVER_REGULARSIG from "<<serverName<<", newStatus=" << newStatus );
+
+ if(available == false)
+ {
+ TALK( "RasServer::changeStatus: "<<serverName<<" not available, SERVER_REGULARSIG ok, regularSignalCounter="<<regularSignalCounter);
+ regularSignalCounter--;
+ if(regularSignalCounter > 0)
+ {
+ LEAVE( "RasServer::changeStatus: leave. regularSignalCounter nonzero: " << regularSignalCounter );
+ return;
+ }
+ newStatus = SERVER_AVAILABLE;
+ std::cout<<"rasmgr: Dead client detected, server "<<serverName<<" is set free again."<<std::endl;
+ }
+ else
+ {
+ LEAVE( "RasServer::changeStatus: leave. srv not available." );
+ return;
+ }
+ }
+ bool wasup=isup;
+
+ bool crashed= (newStatus == SERVER_CRUSHED) ? true:false;
+
+ isup=available= (newStatus == SERVER_AVAILABLE) ? true:false;
+
+ if(wasup==false && isup==true)
+ {
+ ptrServerHost->regStartServer();
+ if(ptrDatabaseHost)
+ ptrDatabaseHost->regStartServer();
+ isstarting=false;
+ }
+ if(wasup==true && isup==false)
+ {
+ //then, ok, I'm down
+ ptrServerHost->regDownServer();
+ if(ptrDatabaseHost)
+ ptrDatabaseHost->regDownServer();
+ activityExpected=false;
+ }
+
+ clearPendingTransaction(); // when the server talks to RasMgr, is always clear, without client
+
+ if(available)
+ {
+ activityCounter++; // just a counter
+ }
+
+ if(downReq && available)
+ {
+ downReq=false;
+ available=false; //until it's really down it shouldn't get any clients
+ TALK( "RasServer::changeStatus: srv down request, available - setting to unavailable and shutting down. ");
+ downNow();
+ }
+
+ if(crashed)
+ {
+ crashCount++;
+ TALK( "server has crashed, current crash count is " << crashCount << ", activity count is " << activityCounter );
+ // restart if "work has started already" (see init() comment on different counting wrt. server types)
+ // changed by PB 2003-nov-23
+ // if(activityCounter && autorestart)
+ if (activityCounter>1 && autorestart)
+ { // a crashed server doesn't autorestart if he crashes before starting work.
+ TALK( "auto restart activated, restarting." );
+ startServer();
+ }
+ }
+
+ // commented out due to some error
+ if(initialCountDown)
+ {
+ if(available)
+ {
+ currentCountDown--;
+ if(currentCountDown==0)
+ {
+ available=false;
+ std::cout<<"rasmgr: Countdown reached for "<<serverName<< ", shutting down." << std::endl;
+ downNow();
+ }
+ }
+ if(wasup==true && isup==false && currentCountDown==0)
+ {
+ std::cout<<"rasmgr: Restart after countdown for server "<<serverName<< "." << std::endl;
+ currentCountDown=initialCountDown;
+ startServer();
+ }
+ }
+
+ LEAVE( "RasServer::changeStatus: leave. ns="<<newStatus<<" av="<<available );
+} // changeStatus()
+
+void RasServer::startWriteTransaction(Database& dataBase)
+{
+ ENTER( "RasServer::startWriteTransaction: enter." );
+ dataBase.startWriteTransaction();
+ writeTransaction=true;
+ connDatabase=&dataBase;
+ LEAVE( "RasServer::startWriteTransaction: leave. servername=" << serverName << ", rwTrans-in on db " << dataBase.getName() );
+}
+
+void RasServer::startReadTransaction(Database& dataBase)
+{
+ ENTER( "RasServer::startReadTransaction: enter." );
+ dataBase.startReadTransaction();
+ readTransaction=true;
+ connDatabase=&dataBase;
+ LEAVE( "RasServer::startReadTransaction: leave. servername=" << serverName << " roTrans-in on db " << dataBase.getName() );
+}
+
+void RasServer::clearPendingTransaction()
+{
+ if(connDatabase)
+ if(writeTransaction)
+ connDatabase->endWriteTransaction();
+ if(readTransaction )
+ connDatabase->endReadTransaction();
+ writeTransaction=false;
+ readTransaction =false;
+ connDatabase = NULL;
+}
+//**********************************************************************
+RasServerManager::RasServerManager()
+{
+}
+RasServerManager::~RasServerManager()
+{
+}
+
+bool RasServerManager::insertNewServer(const char *srvName,const char* hostName,char serverType,long listenPort)
+{
+ bool result = true;
+
+ if(testUniqueness(srvName)==false)
+ result = false;
+
+ if( result == true && hostmanager[hostName].isValid()==false)
+ result = false;
+
+ if(result == true && serverType!=SERVERTYPE_FLAG_RPC && serverType!=SERVERTYPE_FLAG_HTTP && serverType!=SERVERTYPE_FLAG_RNP)
+ {
+ TALK( "RasServerManager::insertNewServer: server " << srvName << " has illegal type " << serverType );
+ result = false;
+ }
+
+ if (result == true)
+ {
+ RasServer tempRasServer;
+ srvList.push_back(tempRasServer);
+ RasServer &refRasServer=srvList.back();
+ refRasServer.init(srvName,hostName,serverType,listenPort);
+ }
+
+ return result;
+}
+
+bool RasServerManager::removeServer(const char *srvName)
+{
+ list<RasServer>::iterator iter=srvList.begin();
+ for(int i=0;i<srvList.size();i++)
+ {
+ if(strcmp(iter->getName(),srvName)==0)
+ {
+ if(iter->isUp())
+ return false;
+
+ iter->disconnectFromDBHost(); //it's not up, so it fails only if it is not connected at all
+
+ srvList.erase(iter);
+ return true;
+ }
+ iter++;
+ }
+ return false;
+}
+
+bool RasServerManager::testUniqueness(const char* srvName)
+{
+ list<RasServer>::iterator iter=srvList.begin();
+ for(int i=0;i<srvList.size();i++)
+ {
+ if(strcmp(iter->getName(),srvName)==0)
+ return false;
+ iter++;
+ }
+ return true;
+}
+
+RasServer& RasServerManager::operator[](int x)
+{
+ list<RasServer>::iterator iter=srvList.begin();
+ for(int i=0;i<x;i++)
+ iter++;
+ return *iter;
+}
+
+RasServer& RasServerManager::operator[](const char* srvName)
+{
+ list<RasServer>::iterator iter=srvList.begin();
+ for(int i=0;i<srvList.size();i++)
+ {
+ if(strcmp(iter->getName(),srvName)==0)
+ return *iter;
+
+ iter++;
+ }
+ return protElem;
+}
+
+RasServer& RasServerManager::last()
+{
+ return srvList.back();
+}
+
+
+int RasServerManager::countServers()
+{
+ return srvList.size();
+}
+
+int RasServerManager::changeServerStatus(char *reqMessage)
+{
+ char serverName[50];
+ int newstatus;
+ long infCount;
+
+ sscanf(reqMessage,"%s %d %ld",serverName,&newstatus,&infCount);
+ TALK( "RasServerManager::changeServerStatus: Trying to change status of "<<serverName<<" to "<<newstatus );
+ RasServer &r=operator[](serverName);
+
+ if(r.isValid()==false)
+ {
+ std::cout<<"Incorrect message from rasserver "<<serverName<<"; new status="<<newstatus<<std::endl;
+ return -1;
+ }
+
+ r.changeStatus(newstatus,infCount);
+ return 0;
+}
+
+void RasServerManager::disconnectAllServersFromDBH(const char *dbhName)
+{
+ list<RasServer>::iterator iter=srvList.begin();
+ for(int i=0;i<srvList.size();i++,iter++)
+ {
+ const char *cDbhName=iter->getDBHostName();
+
+ if(cDbhName==NULL)
+ continue;
+
+ if(strcmp(cDbhName,dbhName)==0) iter->disconnectFromDBHost();
+ }
+
+}
+
+int RasServerManager::countUpServers()
+{
+ int count=0;
+ list<RasServer>::iterator iter=srvList.begin();
+ for(int i=0;i<srvList.size();i++)
+ {
+ if(iter->isUp())
+ count++;
+ iter++;
+ }
+ return count;
+
+}
+
+void RasServerManager::printStatus()
+{
+ char buff[100];
+ list<RasServer>::iterator iter=srvList.begin();
+
+ TALK( "RasServerManager::printStatus. current status is:" );
+ for(int i=0;i<srvList.size();i++)
+ {
+ iter->getDescription(buff);
+ TALK( "\t" << i << ": " << buff );
+ iter++;
+ }
+
+}
+
+bool RasServerManager::reset()
+{ // test modus only
+ if(config.isTestModus()==false)
+ return false;
+
+ list<RasServer>::iterator iter=srvList.begin();
+ for(int i=0;i<srvList.size();i++, iter++)
+ {
+ if(iter->isUp())
+ return false;
+ }
+
+ iter=srvList.begin();
+ for(int i=0;i<srvList.size();i++, iter++)
+ {
+ iter->disconnectFromDBHost(); //it's not up, so it fails only if it is not connected at all
+ }
+
+ while(srvList.size())
+ {
+ srvList.pop_front();
+ }
+ return true;
+
+}
+
+bool RasServerManager::acceptChangeName(const char *oldName,const char *newName)
+{
+ if(strcmp(oldName,newName)==0)
+ return true; // if someone really wants to change a name with the same,
+ return testUniqueness(newName);
+}
+
+
diff --git a/rasmgr/rasmgr_srv.hh b/rasmgr/rasmgr_srv.hh
new file mode 100644
index 0000000..30011e9
--- /dev/null
+++ b/rasmgr/rasmgr_srv.hh
@@ -0,0 +1,165 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: rasmgr_srv.hh
+ *
+ * MODULE: rasmgr
+ * CLASS: RasServer, RasServerManager
+ *
+ * COMMENTS:
+ * None
+ *
+*/
+
+#ifndef RASMGR_SRV_HH
+#define RASMGR_SRV_HH
+
+#include "rasmgr.hh"
+#include "rasmgr_config.hh"
+#include "rasmgr_host.hh"
+#include "rasmgr_dbm.hh"
+
+//#define RASEXECUTABLE "rst"
+#define RASEXECUTABLE BINDIR"rasserver"
+#define MAXREGULARCOUNTER 3
+
+class RasServer
+ {
+ public:
+ RasServer();
+ ~RasServer();
+ void init(const char *srvName,const char* hostName,char serverType,long listenPort);
+ const char *getName();
+ const char *getHostName();
+ const char *getHostNetwName();
+ long getPort();
+ char getType();
+ void changeName(const char *newName);
+ void changeType(const char newType); // char not char*!!
+
+ void changePort(long newPort);
+ void changeExtraParam(const char *extraParam);
+ void changeCountDown(int);
+ void changeAutoRestart(bool);
+ const char *getExtraParams();
+ int getCountDown();
+
+ bool connectToDBHost(const char *dbHostName);//,const char *connString);
+ bool disconnectFromDBHost();
+ const char *getDBHostName();
+
+ static char* getDescriptionHeader(char *destBuffer);
+ char* getDescription(char *destBuffer);
+ static char* getDescriptionExecHeader(char *destBuffer);
+ char* getDescriptionExec(char *destBuffer);
+ static char* getDescriptionPortHeader(char *destBuffer);
+ char* getDescriptionPort(char *destBuffer);
+
+ int startServer();
+ int startServerInDebugger(char *command); // test modus only
+
+ int downServer(bool forced);
+ int killServer();
+
+ void changeStatus(int,long);
+ bool isUp();
+ bool isStarting();
+ bool isValid();
+ bool isAvailable();
+ bool forceAvailable();
+
+ bool isConnectedToDBHost();
+ bool isAutoRestart();
+
+ void setNotAvailable();
+ void startWriteTransaction(Database& dataBase);
+ void startReadTransaction(Database& dataBase);
+ void changeExecutableName(const char*);
+ const char* getExecutableName();
+ private:
+ int downNow();
+ void clearPendingTransaction();
+
+ char serverName[100];
+ ServerHost *ptrServerHost;
+ bool isinternal;
+ char serverType; //'r','h'
+ long listenPort; // 'r' ->rpc prognum; 'h' ->TCP/IP port
+ char extraParam[100];
+
+ char executableName[100];
+
+ DatabaseHost *ptrDatabaseHost;
+ //char connStr[100];
+
+ bool downReq;
+ bool available;
+ bool isup;
+ bool isstarting;
+ bool activityExpected; // to avoid the possibility of starting rasserver by hand
+
+ int regularSignalCounter; // how namy times should a nonavailable server signal before we put it available again
+ unsigned long activityCounter; // counts "activities" per server, i.e., actions that are noticeable by the server
+
+ int initialCountDown;
+ int currentCountDown;
+ int crashCount;
+ bool autorestart;
+
+ bool writeTransaction;
+ bool readTransaction;
+ Database *connDatabase;
+
+ bool valid;
+ };
+
+class RasServerManager
+ {
+ public:
+ RasServerManager();
+ ~RasServerManager();
+ bool insertNewServer(const char *srvName,const char* hostName,char serverType,long listenPort);
+ bool removeServer(const char *srvName);
+ int countServers();
+ RasServer& operator[](int);
+ RasServer& operator[](const char*srvName);
+ RasServer& last();
+
+ int changeServerStatus(char *reqMessage);
+ void disconnectAllServersFromDBH(const char *dbhName);
+
+ int countUpServers();
+ void printStatus();
+ bool reset(); // test modus only
+ bool acceptChangeName(const char *oldName,const char *newName);
+ private:
+ bool testUniqueness(const char* srvName);
+ list<RasServer> srvList;
+ RasServer protElem;
+ };
+
+extern RasServerManager rasManager;
+
+#endif
+
+
diff --git a/rasmgr/rasmgr_users.cc b/rasmgr/rasmgr_users.cc
new file mode 100644
index 0000000..3b72308
--- /dev/null
+++ b/rasmgr/rasmgr_users.cc
@@ -0,0 +1,861 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: rasmgr_users.cc
+ *
+ * MODULE: rasmgr
+ * CLASS: User, UserManager, Authorization
+ *
+ * PURPOSE:
+ * User management
+ *
+ * COMMENTS:
+ * None
+ *
+*/
+
+using namespace std;
+
+#include "rasmgr_users.hh"
+#include "ras_crypto.hh"
+#include "rasmgr_host.hh"
+#include <time.h>
+
+#include "debug.hh"
+
+extern bool hostCmp( const char *h1, const char *h2);
+
+
+User::User()
+ { userID=-1;
+ userName[0]=0;
+ passWord[0]=0;
+ valid=false;
+ adminRight=authorization.getGlobalInitAdminRights();
+ databRight=authorization.getGlobalInitDatabRights();;
+ }
+
+void User::init(long userID, const char *name)
+ { strcpy(userName,name);
+ this->userID=userID;
+ changePTPassword(name);
+ valid=true;
+ }
+void User::changeName(const char *name)
+ { strcpy(userName,name);
+ }
+
+void User::changePassword(const char *encrPass)
+ { strcpy(passWord,encrPass);
+ }
+void User::changePTPassword(const char *plainTextPass)
+ {
+ messageDigest(plainTextPass,passWord,"MD5");
+ //std::cout<<"passwd="<<passWord<< " strlen="<<strlen(passWord)<<std::endl;
+ }
+
+const char* User::getName()
+ { return userName;
+ }
+
+long User::getUserID()
+ { return userID;
+ }
+
+bool User::isThisMe(const char *name,const char *encrPass)
+ { //std::cout<<"Is this me: "<<name<<'/'<<userName<<std::endl;
+ //std::cout<<"My Pass="<<passWord<<std::endl;
+ //std::cout<<"His one="<<encrPass<<std::endl;
+
+ return (strcmp(name,userName)==0 && strcmp(encrPass,passWord)==0) ? true:false;
+ }
+void User::setAdminRights(int r)
+ { adminRight = r;
+ }
+
+bool User::hasAdminRights(int r)
+ {
+ return ((adminRight & r)==r) ? true:false;
+ }
+int User::getAdminRights()
+ { return adminRight;
+ }
+
+void User::setDefaultDBRights(int r)
+ {
+ databRight=r;
+ }
+int User::getDefaultDBRights()
+ { return databRight;
+ }
+
+int User::getEffectiveDatabaseRights(const char *databName)
+ {
+ list<UserDBRight>::iterator iter=dbRList.begin();
+ for(int i=0;i<dbRList.size();i++)
+ {
+ if(strcmp(iter->ptrDatabase->getName(),databName)==0)
+ {
+ return iter->databRight;
+ }
+ iter++;
+ }
+ return databRight;
+ }
+
+bool User::isTrusteeOn(const char *databName)
+ {
+ list<UserDBRight>::iterator iter=dbRList.begin();
+ for(int i=0;i<dbRList.size();i++)
+ {
+ if(strcmp(iter->ptrDatabase->getName(),databName)==0)
+ {
+ return true;
+ }
+ iter++;
+ }
+ return false;
+ }
+
+bool User::setDatabaseRights(const char *databName,int rights)
+ {
+ Database &db=dbManager[databName];
+ if(db.isValid()==false) return false;
+
+ UserDBRight ur;
+ ur.ptrDatabase=&db;
+ ur.databRight=rights;
+
+ removeDatabaseRights(databName);
+ dbRList.push_back(ur);
+ return true;
+ }
+bool User::removeDatabaseRights(const char *databName)
+ {
+ list<UserDBRight>::iterator iter=dbRList.begin();
+ for(int i=0;i<dbRList.size();i++)
+ {
+ //if(iter->ptrDatabase==NULL) { std::cout<<"Huo!!"<<std::endl;break;}
+
+ if(strcmp(iter->ptrDatabase->getName(),databName)==0)
+ {
+ dbRList.erase(iter);
+ return true;
+ }
+ iter++;
+ }
+
+ return false;
+ }
+
+void User::loadToRec(AuthUserRec &rec)
+ {
+ rec.userID=userID;
+ strcpy(rec.userName,userName);
+ strcpy(rec.passWord,passWord);
+
+ rec.adminRight=adminRight;
+ rec.databRight=databRight;
+ rec.countRights=dbRList.size();
+ }
+void User::loadFromRec(AuthUserRec &rec)
+ {
+ userID=rec.userID;
+ strcpy(userName,rec.userName);
+ strcpy(passWord,rec.passWord);
+
+ adminRight =rec.adminRight;
+ databRight =rec.databRight;
+ valid=true;
+ }
+
+long User::countRights()
+ { return dbRList.size();
+ }
+
+bool User::loadRightToRec(int x,AuthDbRRec &rec)
+ {
+ if(x>=dbRList.size()) return false;
+
+ list<UserDBRight>::iterator iter=dbRList.begin();
+ for(int i=0;i<x;i++) iter++;
+
+ strcpy(rec.dbName,iter->ptrDatabase->getName());
+ rec.right=iter->databRight;
+ return true;
+ }
+
+bool User::loadRightFromRec(AuthDbRRec &rec)
+ { return setDatabaseRights(rec.dbName,rec.right);
+ }
+
+bool User::isValid()
+ { return valid;
+ }
+
+//------------------------------------------------------------------
+
+UserManager::UserManager()
+ {
+ lastUserID=0;
+ }
+UserManager::~UserManager()
+ {
+ }
+void UserManager::loadDefaults()
+ {
+ insertNewUser("rasadmin");
+ userList.back().changePTPassword("rasadmin");
+ userList.back().setAdminRights(admR_full);
+ userList.back().setDefaultDBRights(dbR_read+dbR_write);
+
+ // if there is a license for one user only, we don't have a rasguest
+ if(userManager.insertNewUser("rasguest"))
+ { userList.back().changePTPassword("rasguest");
+ userList.back().setAdminRights(admR_none);
+ userList.back().setDefaultDBRights(dbR_read);
+ }
+
+ }
+
+
+bool UserManager::insertNewUser(const char *userName)
+ {
+ if(testUniqueness(userName)==false) return false;
+
+ User tempUser;
+ userList.push_back(tempUser);
+ User &refUser=userList.back();
+
+ refUser.init(lastUserID++,userName);
+
+ return true;
+ }
+
+bool UserManager::removeUser(const char *userName)
+ {
+ list<User>::iterator iter=userList.begin();
+ for(int i=0;i<userList.size();i++)
+ {
+ if(strcmp(iter->getName(),userName)==0)
+ {
+ userList.erase(iter);
+ return true;
+ }
+
+ iter++;
+ }
+ return false;
+ }
+
+int UserManager::countUsers()
+ { return userList.size();
+ }
+
+User& UserManager::operator[](int x)
+ { list<User>::iterator iter=userList.begin();
+ for(int i=0;i<x;i++) iter++;
+ return *iter;
+ }
+
+User& UserManager::operator[](const char* userName)
+ {
+ list<User>::iterator iter=userList.begin();
+ //std::cout<<"Size="<<userList.size()<<std::endl;
+ for(int i=0;i<userList.size();i++)
+ {
+ //std::cout<<i<<" "<<iter->getName()<<" "<<iter->isValid()<<std::endl;
+ if(strcmp(iter->getName(),userName)==0) return *iter;
+ iter++;
+ }
+ return protElem;
+ }
+
+void UserManager::removeDatabaseRights(const char *databName)
+ {
+ list<User>::iterator iter=userList.begin();
+ for(int i=0;i<userList.size();i++)
+ {
+ iter->removeDatabaseRights(databName);
+ iter++;
+ }
+ }
+
+bool UserManager::testUniqueness(const char* userName)
+ {
+ list<User>::iterator iter=userList.begin();
+ for(int i=0;i<userList.size();i++)
+ {
+ if(strcmp(iter->getName(),userName)==0) return false;
+ iter++;
+ }
+ return true;
+ }
+
+User& UserManager::loadUser(AuthUserRec &rec)
+ { removeUser(rec.userName);
+
+ User tempUser;
+ userList.push_back(tempUser);
+ User &refUser=userList.back();
+
+ refUser.loadFromRec(rec);
+
+ return refUser;
+ }
+long UserManager::getLastUserID()
+ { return lastUserID;
+ }
+void UserManager::setLastUserID(long lastUserID)
+ { this->lastUserID=lastUserID;
+ }
+
+User* UserManager::acceptEntry(const char *name,const char *encrPass)
+ {
+ list<User>::iterator iter=userList.begin();
+ for(int i=0;i<userList.size();i++)
+ {
+ if(iter->isThisMe(name,encrPass)) return &(*iter);
+ iter++;
+ }
+ return NULL;
+ }
+bool UserManager::reset()
+ {
+ if(config.isTestModus()==false) return false;
+
+ while(userList.size())
+ {
+ userList.pop_front();
+ }
+ return true;
+ }
+
+bool UserManager::acceptChangeName(const char *oldName,const char *newName)
+ {
+ if(strcmp(oldName,newName)==0) return true; // if someone really wants to change a name with the same,
+
+ return testUniqueness(newName);
+ }
+
+//##################################################################
+
+Authorization::Authorization()
+ { inConfigFile=false;
+
+ authFileName[0]=0;
+
+#ifdef HIGHLANDER
+ char *rasHome=CONFDIR;
+ if(rasHome!=0) sprintf(authFileName,"%s/",rasHome);
+#endif
+
+ strcat(authFileName,"rasmgr_auth.dat");
+ globalInitAdminRight=admR_none;
+ globalInitDatabRight=dbR_none;
+ }
+
+bool Authorization::acceptEntry(const char *header)
+ {
+ char myheader[500]; strncpy(myheader,header,299); myheader[299]=0;
+ char *auth=strstr(myheader,"Authorization:");
+ if(!auth) return false;
+
+ //TALK("auth="<<auth);
+
+ char *scheme=strtok(auth+strlen("Authorization:")," ");
+ if(!scheme) return false;
+
+ char *uname=strtok(NULL,":");
+ char *upass=strtok(NULL," \r\n\t");
+
+ //TALK("Auth. scheme="<<scheme<<" user="<<uname<<" pass="<<upass);
+
+ curUser=userManager.acceptEntry(uname,upass);
+ if(curUser==NULL) return false;
+
+ return true;
+ }
+
+bool Authorization::hasFullAdmin()
+ { return curUser->hasAdminRights(admR_full);
+ }
+const char* Authorization::getUserName()
+ { return curUser->getName();
+ }
+
+const char* Authorization::getCapability(const char *serverName,const char *databaseName, bool readonly)
+ {
+ //Format of Capability (no brackets())
+ //$I(userID)$E(effectivRights)$B(databaseName)$T(timeout)$N(serverName)$D(messageDigest)$K
+ int rights=curUser->getEffectiveDatabaseRights(databaseName);
+
+ if(readonly) rights&=~dbR_write;
+
+ const char *rString=convertDatabRights(rights);
+
+ long userID=curUser->getUserID();
+
+ char capaS[300];
+ sprintf(capaS,"$I%d$E%s$B%s$T%s$N%s",userID,rString,databaseName,getFormatedTime(180),serverName);
+
+ static char capaQ[300];
+ sprintf(capaQ,"$Canci%s",capaS);
+
+ char digest[50]; // 33 is enough
+ messageDigest(capaQ,digest,"MD5");
+
+ sprintf(capaQ,"%s$D%s$K",capaS,digest);
+
+ return capaQ;
+ }
+
+void Authorization::startConfigFile()
+ { inConfigFile=true;
+ }
+
+void Authorization::endConfigFile()
+ { inConfigFile=false;
+ }
+bool Authorization::isInConfigFile()
+ { return inConfigFile;
+ }
+
+bool Authorization::saveAuthFile()
+ {
+
+ std::ofstream ofs(authFileName);
+ if(!ofs) return false;
+
+ EVP_MD_CTX mdctx;
+ const EVP_MD *md;
+ unsigned int md_len;
+ //unsigned char md_value[30];
+
+ OpenSSL_add_all_digests();
+ md = EVP_get_digestbyname("MD5");
+ if(!md) return false;
+ EVP_DigestInit(&mdctx, md);
+
+ AuthFileHeader header;
+ header.fileID =AUTHFILEID;
+ header.fileVersion =AUTHFILEVERS;
+ header.headerLength=sizeof(header);
+ header.lastUserID =userManager.getLastUserID();
+ strcpy(header.hostName,config.getHostName());
+ header.countUsers=userManager.countUsers();
+ for(int i=0;i< 50;i++) header.messageDigest[i]=0;
+ header.globalInitAdmR=authorization.getGlobalInitAdminRights();
+ header.globalInitDbsR=authorization.getGlobalInitDatabRights();
+
+ randomGenerator.setFileVersion(header.fileVersion);
+
+ for(int i=0;i<100;i++) header._unused[i]=0;
+ ofs.write((char*)&header,sizeof(header));
+
+ initcrypt(header.lastUserID);
+
+ for(int i=0;i<header.countUsers;i++)
+ {
+ User &u=userManager[i];
+ AuthUserRec uRec;
+
+ u.loadToRec(uRec);
+ EVP_DigestUpdate(&mdctx,&uRec,sizeof(uRec));
+
+ crypt(&uRec,sizeof(uRec));
+ ofs.write((char*)&uRec,sizeof(uRec));
+
+ for(int j=0;j<u.countRights();j++)
+ {
+ AuthDbRRec dbRec;
+ u.loadRightToRec(j,dbRec);
+ EVP_DigestUpdate(&mdctx,&dbRec,sizeof(dbRec));
+
+ crypt(&dbRec,sizeof(dbRec));
+ ofs.write((char*)&dbRec,sizeof(dbRec));
+ }
+
+ }
+
+ EVP_DigestFinal(&mdctx, header.messageDigest, &md_len);
+ ofs.seekp(0,std::ios::beg);
+ ofs.write((char*)&header,sizeof(header));
+ ofs.close();
+
+ return true;
+ }
+
+int Authorization::readAuthFile()
+ {
+ int result = RC_OK; // enum values from rasmgr_users.hh
+
+ ENTER( "Authorization::readAuthFile: enter." );
+
+ VLOG << "Inspecting authorization file '"<<authFileName<< "'...";
+
+ std::ifstream ifs(authFileName);
+ if(!ifs)
+ result = ERRAUTHFNOTF;
+
+ if (result == RC_OK)
+ {
+ int ver=verifyAuthFile(ifs);
+ if(ver)
+ result = ver;
+ TALK( "Authorization::readAuthFile: verifyAuthFile returned ." << result );
+ }
+
+ if (result == RC_OK)
+ {
+ AuthFileHeader header;
+ ifs.read((char*)&header,sizeof(header));
+
+ // not necessary, done by verify if(header.fileID != AUTHFIELID) return ERRAUTHFCORR;
+
+ // this is needed
+ if(!randomGenerator.setFileVersion(header.fileVersion)) return ERRAUTHFVERS;
+
+ userManager.setLastUserID(header.lastUserID);
+ authorization.setGlobalInitAdminRights(header.globalInitAdmR);
+ authorization.setGlobalInitDatabRights(header.globalInitDbsR);
+
+ TALK( "Authorization::readAuthFile: Auth file host="<<header.hostName<<" lastUserID="<<header.lastUserID );
+ initcrypt(header.lastUserID);
+
+ for(int i=0;i<header.countUsers;i++)
+ {
+ AuthUserRec uRec;
+ ifs.read((char*)&uRec,sizeof(uRec));
+
+ decrypt(&uRec,sizeof(uRec));
+
+ User &u=userManager.loadUser(uRec);
+ TALK( "Authorization::readAuthFile: User "<<i<<" "<<u.getName() );
+
+ for(int j=0;j<uRec.countRights;j++)
+ {
+ AuthDbRRec dbRec;
+ ifs.read((char*)&dbRec,sizeof(dbRec));
+
+ decrypt(&dbRec,sizeof(dbRec));
+ u.loadRightFromRec(dbRec);
+ }
+ }
+ }
+
+ if (result != ERRAUTHFNOTF)
+ ifs.close();
+
+ switch(result)
+ {
+ case RC_OK:
+ VLOG << "ok" << endl;
+ break;
+ case ERRAUTHFNOTF:
+ cout<<"Warning: User authorization file not found, using default user settings."<<std::endl;
+ break;
+ case ERRAUTHFCORR:
+ cout<<"Error: User authorization file is corrupt, aborting."<<std::endl;
+ break;
+ case ERRAUTHFWRHOST:
+ cout<<"Error: User authorization file is not for this host."<<std::endl;
+ break;
+ case ERRAUTHFVERS:
+ cout<<"Error: User authorization file is incompatible due to different encryption used - see migration documentation."<<std::endl;
+ break;
+ default: // should not occur, internal enum mismatch
+ cout<<"Error: Internal evaluation error."<<std::endl;
+ break;
+ }
+
+ LEAVE( "Authorization::readAuthFile: leave. result=" << result );
+ return result;
+ } // readAuthFile()
+
+int Authorization::verifyAuthFile(std::ifstream &ifs)
+ {
+ EVP_MD_CTX mdctx;
+ const EVP_MD *md;
+ unsigned int md_len;
+ unsigned char md_value[50];
+
+ OpenSSL_add_all_digests();
+ md = EVP_get_digestbyname("MD5");
+ if(!md)
+ return false;
+
+ EVP_DigestInit(&mdctx, md);
+
+ AuthFileHeader header;
+ ifs.read((char*)&header,sizeof(header));
+
+ if(header.fileID != AUTHFILEID)
+ return ERRAUTHFCORR;
+
+ if(!randomGenerator.setFileVersion(header.fileVersion))
+ return ERRAUTHFVERS;
+
+ if(!hostCmp(header.hostName,config.getHostName()))
+ return ERRAUTHFWRHOST;
+
+ initcrypt(header.lastUserID);
+
+ /*
+ for(int i=0;i<header.countUsers;i++)
+ {
+ AuthUserRec uRec;
+ ifs.read(&uRec,sizeof(uRec));
+ decrypt(&uRec,sizeof(uRec));
+
+ EVP_DigestUpdate(&mdctx,&uRec,sizeof(uRec));
+
+ for(int j=0;j<uRec.countRights;j++)
+ {
+ AuthDbRRec dbRec;
+ ifs.read(&dbRec,sizeof(dbRec));
+ decrypt(&dbRec,sizeof(dbRec));
+
+ EVP_DigestUpdate(&mdctx,&dbRec,sizeof(dbRec));
+ }
+
+ }
+ */
+ #define MAXBUFF 500
+ unsigned char buff[MAXBUFF];
+ long cpos = ifs.tellg();
+ ifs.seekg(0,std::ios::end);
+ long endpos=ifs.tellg();
+ ifs.seekg(cpos,std::ios::beg);
+ //std::cout<<"c="<<cpos<<" end="<<endpos<<std::endl;
+
+ for(;;)
+ {
+ int r = endpos-cpos > MAXBUFF ? MAXBUFF : endpos-cpos;
+ if(r==0)
+ break; //{ std::cout<<"xx"<<std::endl; break; }
+ ifs.read((char*)buff,r);
+ if(!ifs)
+ break; //{ std::cout<<"yy"<<std::endl; break; }
+ cpos +=r;
+
+ decrypt(buff,r);
+
+ EVP_DigestUpdate(&mdctx,buff,r);
+ //std::cout<<"verify "<<r<<std::endl;
+ }
+
+ EVP_DigestFinal(&mdctx, md_value, &md_len);
+
+ ifs.seekg(0,std::ios::beg);
+
+ for(int i=0;i<md_len;i++)
+ { if(md_value[i]!=header.messageDigest[i])
+ return ERRAUTHFCORR;
+ }
+ return 0;
+ }
+
+void Authorization::initcrypt(int seed)
+ { //srand(seed);
+ randomGenerator.init(seed);
+ }
+void Authorization::crypt(void *vbuffer,int length)
+ {
+ unsigned char *buff=(unsigned char*)vbuffer;
+ // std::cout<<" crypt length="<<length<<flush;
+ for(int i=0;i<length;i++) buff[i]^=randomGenerator();//rand();
+ }
+void Authorization::decrypt(void *vbuffer,int length)
+ {
+ crypt(vbuffer,length);
+ }
+
+const char* Authorization::getSyncroString()
+ {
+ return getFormatedTime(0);
+ }
+
+const char* Authorization::getFormatedTime(long int delta)
+ {
+ time_t tmx=time(NULL)+delta;
+ tm *b=localtime(&tmx);
+ static char buffer[30];
+ sprintf(buffer,"%d:%d:%d:%d:%d:%d",b->tm_mday,b->tm_mon+1,b->tm_year+1900,b->tm_hour,b->tm_min,b->tm_sec);
+ return buffer;
+ }
+
+
+void Authorization::setGlobalInitAdminRights(int rights)
+ { globalInitAdminRight=rights;
+ }
+void Authorization::setGlobalInitDatabRights(int rights)
+ { globalInitDatabRight=rights;
+ }
+int Authorization::getGlobalInitAdminRights()
+ { return globalInitAdminRight;
+ }
+int Authorization::getGlobalInitDatabRights()
+ { return globalInitDatabRight;
+ }
+
+const char * Authorization::convertAdminRights(int r)
+ { static char buffer[20];
+
+ char C= (r & admR_config) ? 'C':'.';
+ char A= (r & admR_acctrl) ? 'A':'.';
+ char S= (r & admR_sysup ) ? 'S':'.';
+ char I= (r & admR_info ) ? 'I':'.';
+
+ sprintf(buffer,"%c%c%c%c",C,A,S,I);
+ return buffer;
+ }
+const char * Authorization::convertDatabRights(int r)
+ { static char buffer[20];
+
+ char R= (r & dbR_read) ? 'R':'.';
+ char W= (r & dbR_write) ? 'W':'.';
+
+ sprintf(buffer,"%c%c",R,W);
+ return buffer;
+
+ }
+
+const char * Authorization::convertGlobalInitAdminRights()
+ { return convertAdminRights(globalInitAdminRight);
+ }
+const char * Authorization::convertGlobalInitDatabRights()
+ { return convertDatabRights(globalInitDatabRight);
+ }
+
+int Authorization::convertAdminRights(const char *rString)
+ {
+ int rights=admR_none;
+ for(int i=0;rString[i];i++)
+ {
+ switch(rString[i])
+ { case 'C': rights|=admR_config;break;
+ case 'A': rights|=admR_acctrl;break;
+ case 'S': rights|=admR_sysup; break;
+ case 'I': rights|=admR_info; break;
+ case 'R':
+ case 'W':
+ case '[':
+ case ']':
+ case '-':
+ case '.': break;
+ default : return -1; // error!!!
+ }
+ }
+ return rights;
+ }
+
+int Authorization::convertDatabRights(const char *rString)
+ {
+ int rights=dbR_none;
+ for(int i=0;rString[i];i++)
+ {
+ switch(rString[i])
+ {
+ case 'C':
+ case 'A':
+ case 'S':
+ case 'I': break;
+ case 'R': rights|=dbR_read; break;
+ case 'W': rights|=dbR_write;break;
+ case '[':
+ case ']':
+ case '-':
+ case '.': break;
+ default : return -1; // error!!!
+ }
+ }
+ return rights;
+ }
+
+bool Authorization::hasAdminRights(int right)
+ {
+ return inConfigFile ? true : curUser->hasAdminRights(right);
+ }
+
+// return name of alternate config file;
+// takes value from preceding saveAltAuthFile() call.
+const char *Authorization::getAltAuthFileName()
+ {
+ return altAuthFileName;
+ }
+
+// save auth file at original place, i.e., under the name of authFile
+bool Authorization::saveOrigAuthFile()
+ {
+ ENTER( "Authorization::saveOrigAuthFile: enter." );
+
+ bool result = saveAuthFile();
+
+ LEAVE( "Authorization::saveOrigAltAuthFile: leave. result=" << result );
+ return result;
+ }
+
+// save authorization file in another file, same dir as auth file
+bool Authorization::saveAltAuthFile()
+ {
+ bool result = true;
+ char origFileName[ sizeof(authFileName) ]; // temp copy of origFileName
+
+ ENTER( "Authorization::saveAltAuthFile: enter." );
+
+ // save original file name
+ (void) strcpy( origFileName, authFileName );
+
+ // build temp file by appending a unique string
+ (void) strcpy( altAuthFileName, authFileName );
+ (void) strcat( altAuthFileName, ".XXXXXX" ); // 6 * 'X', see man mkstemp()
+
+ int altFile = mkstemp( altAuthFileName ); // replaces the Xs by unique string
+ if (altFile < 0) // error in creating file name
+ {
+ int tempError = errno;
+ TALK( "Authorization::saveAltAuthFile: error creating alternate file name: " << strerror(tempError) );
+ result = false;
+ }
+ if (result == true)
+ {
+ // now we have a valid + open file, but we can't use it like that, because we open down below.
+ // so close it again, being happy that we have a valid file name. bad hack, though.
+ int closeResult = close( altFile );
+ if (closeResult != 0)
+ TALK( "Authorization::saveAltAuthFile: error in temporary closing file, ignoring that." );
+ }
+
+ if (result == true)
+ {
+ (void) strcpy( authFileName, altAuthFileName ); // set file to be written to alternate name
+ result = saveAuthFile(); // save file, name has been substituted successfully
+ TALK( "Authorization::saveAltAuthFile: save to " << authFileName << " done, result=" << result );
+ (void) strcpy( authFileName, origFileName ); // restore original auth file name
+ }
+
+ LEAVE( "Authorization::saveAltAuthFile: leave. result=" << result );
+ return result;
+ }
+
diff --git a/rasmgr/rasmgr_users.hh b/rasmgr/rasmgr_users.hh
new file mode 100644
index 0000000..0bffe90
--- /dev/null
+++ b/rasmgr/rasmgr_users.hh
@@ -0,0 +1,257 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: rasmgr_users.hh
+ *
+ * MODULE: rasmgr
+ * CLASS: User, UserManager, Authorization
+ *
+ * PURPOSE:
+ * User management
+ *
+ * COMMENTS:
+ * None
+ *
+*/
+
+#ifndef RASMGR_USERS_HH
+#define RASMGR_USERS_HH
+
+#include "rasmgr.hh"
+#include "rasmgr_config.hh"
+#include "rasmgr_dbm.hh"
+
+enum AdminRight
+ {
+ admR_none = 0,
+ admR_config= 1, // C
+ admR_acctrl= 2, // A
+ admR_sysup = 4, // S - up-down
+ admR_info = 8, // I
+ admR_full =255
+ };
+
+enum DatabRight // maybe we'll put them together one day
+ {
+ dbR_none = 0<<8,
+ dbR_read = 1<<8, // R
+ dbR_write = 2<<8 // W
+ };
+
+struct UserDBRight
+ {
+ Database *ptrDatabase;
+ int databRight;
+ };
+
+// For persistency
+#define AUTHFILEID 26012001
+#define AUTHFILEVERS 2;
+
+struct AuthFileHeader
+ {
+ long fileID;
+ long fileVersion;
+ long headerLength;
+ long lastUserID;
+ char hostName[100];
+ long countUsers;
+ unsigned char messageDigest[35];
+ int globalInitAdmR;
+ int globalInitDbsR;
+ char _unused[100];
+ };
+
+struct AuthUserRec
+ {
+ long userID;
+ char userName[100];
+ char passWord[50];
+
+ int adminRight;
+ int databRight;
+ long countRights;
+ char _unused[32];
+ };
+
+struct AuthDbRRec
+ {
+ char dbName[100];
+ int right;
+ };
+//++++++++++++++++++++++++++++++++++++++++++++++++
+
+class User
+ {
+ public:
+ User();
+ void init(long userID, const char *name);
+ void changeName(const char *name);
+ void changePassword(const char *encrPass);
+ void changePTPassword(const char *plainTextPass);
+
+ const char* getName();
+
+ long getUserID();
+
+ bool isThisMe(const char *name,const char *encrPass);
+
+ void setAdminRights(int rights);
+ bool hasAdminRights(int rights);
+ int getAdminRights();
+
+
+ void setDefaultDBRights(int);
+ int getDefaultDBRights();
+
+ int getEffectiveDatabaseRights(const char *databName);
+ bool setDatabaseRights(const char *databName,int rights);
+ bool removeDatabaseRights(const char *databName);
+ bool isTrusteeOn(const char *databName);
+
+ void loadToRec(AuthUserRec&);
+ void loadFromRec(AuthUserRec&);
+
+ long countRights();
+ bool loadRightToRec(int,AuthDbRRec&);
+ bool loadRightFromRec(AuthDbRRec&);
+ bool isValid();
+ private:
+ long userID;
+ char userName[100];
+ char passWord[50];
+
+ int adminRight;
+ int databRight;
+
+ list<UserDBRight> dbRList;
+ bool valid;
+ };
+
+class UserManager
+ {
+ public:
+ UserManager();
+ ~UserManager();
+ void loadDefaults();
+ bool insertNewUser(const char *userName);
+ bool removeUser(const char *userName);
+ int countUsers();
+ User& operator[](int);
+ User& operator[](const char* userName);
+
+ User* acceptEntry(const char *name,const char *encrPass);
+ void removeDatabaseRights(const char *databName);
+ // for loading only
+ User& loadUser(AuthUserRec&);
+ long getLastUserID();
+ void setLastUserID(long);
+ bool reset();
+ bool acceptChangeName(const char *oldName,const char *newName);
+ private:
+ bool testUniqueness(const char* userName);
+ list<User> userList;
+ User protElem;
+
+ long lastUserID;
+ };
+
+extern UserManager userManager;
+
+class Authorization
+ {
+ public:
+ Authorization();
+ bool acceptEntry(const char*message);
+ const char *getUserName();
+ bool hasFullAdmin();
+ //bool hasConfigAdmin();
+ const char* getSyncroString();
+ const char* getCapability(const char *serverName,const char *databaseName, bool readonly);
+ void startConfigFile();
+ void endConfigFile();
+ int readAuthFile();
+ bool saveOrigAuthFile();
+ bool saveAltAuthFile();
+ const char* getAltAuthFileName();
+
+ void setGlobalInitAdminRights(int rights);
+ void setGlobalInitDatabRights(int rights);
+ int getGlobalInitAdminRights();
+ int getGlobalInitDatabRights();
+ const char * convertGlobalInitAdminRights();
+ const char * convertGlobalInitDatabRights();
+ const char * convertAdminRights(int);
+ const char * convertDatabRights(int);
+ int convertAdminRights(const char *);
+ int convertDatabRights(const char *);
+
+ bool hasAdminRights(int);
+ bool isInConfigFile();
+ private:
+ int verifyAuthFile(std::ifstream&);
+ const char* getFormatedTime(long int);
+
+ bool saveAuthFile();
+
+ void initcrypt(int);
+ void crypt(void*,int);
+ void decrypt(void*,int);
+
+
+ User *curUser;
+ bool inConfigFile;
+ char authFileName[100];
+ char altAuthFileName[100];
+
+ int globalInitAdminRight;
+ int globalInitDatabRight;
+ };
+
+extern Authorization authorization;
+
+class RandomGenerator
+ {
+ public:
+ RandomGenerator();
+
+ bool setFileVersion(long); // false, if not supported encr. method
+
+ void init(unsigned int);
+ unsigned char operator()();
+ bool insideTest();
+ private:
+ static unsigned char randomTable[1000];
+ unsigned int seed;
+ int fileVersion;
+ };
+extern RandomGenerator randomGenerator;
+
+// return codes:
+#define RC_OK 0
+#define ERRAUTHFNOTF -1
+#define ERRAUTHFCORR -2
+#define ERRAUTHFWRHOST -3
+#define ERRAUTHFVERS -4
+
+#endif
diff --git a/rasmgr/test/Makefile b/rasmgr/test/Makefile
new file mode 100644
index 0000000..6150f87
--- /dev/null
+++ b/rasmgr/test/Makefile
@@ -0,0 +1,46 @@
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>. # Top Level makefile. This points to the various modules that have to be build
+# and/or deployed
+#
+######################### Definitions ############################
+
+# standard include with general options
+include $(RMANBASE)/Makefile.inc
+
+SRCCXX = test_hostcmp.cc
+
+OBJS = ${SRCCXX:%.cc=%.o}
+MISCCLEAN = test_hostcmp
+
+########################### Targets ##############################
+
+all: test_hostcmp
+
+test_hostcmp: test_hostcmp.o ../hostcmp.o
+ $(PURIFY) $(CXX) $(CXXFLAGS) -o test_hostcmp $^
+
+.PHONY: clean
+clean:
+ -rm $(OBJS) $(MISCCLEAN)
+
+######################## Dependencies ############################
+
diff --git a/rasmgr/test/Makefile.dep b/rasmgr/test/Makefile.dep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/rasmgr/test/Makefile.dep
diff --git a/rasmgr/test/check_opensockets.sh b/rasmgr/test/check_opensockets.sh
new file mode 100644
index 0000000..7ec3ab2
--- /dev/null
+++ b/rasmgr/test/check_opensockets.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+# check_opensockets.sh: periodically check the number of waiting sockets in the local system
+# parameters:
+# $1 sleep time between checks
+
+export SLEEPTIME=$1
+
+if test "$1" == ""
+then
+ echo usage: $0 sleepseconds
+ exit
+fi
+
+echo "$0: start checking for open (waiting) sockets, in intervals of $SLEEPTIME seconds."
+
+while echo \--- check time: `date` \----------------
+do
+ netstat -na | grep WAIT
+ echo summary: `netstat -na | grep WAIT | wc -l` TIME_WAIT state sockets.
+ sleep $SLEEPTIME
+done
+
+echo $0: done.
+
diff --git a/rasmgr/test/check_opensockets_idleresult.log b/rasmgr/test/check_opensockets_idleresult.log
new file mode 100644
index 0000000..a309b52
--- /dev/null
+++ b/rasmgr/test/check_opensockets_idleresult.log
@@ -0,0 +1,92 @@
+./check_opensockets.sh: start checking for open (waiting) sockets, in intervals of 1 seconds.
+--- check time: Die Jun 3 23:22:34 CEST 2003 ----------------
+tcp 0 0 127.0.0.1:620 127.0.0.1:686 TIME_WAIT
+--- check time: Die Jun 3 23:22:35 CEST 2003 ----------------
+tcp 0 0 127.0.0.1:620 127.0.0.1:686 TIME_WAIT
+--- check time: Die Jun 3 23:22:36 CEST 2003 ----------------
+tcp 0 0 127.0.0.1:620 127.0.0.1:686 TIME_WAIT
+--- check time: Die Jun 3 23:22:37 CEST 2003 ----------------
+tcp 0 0 127.0.0.1:620 127.0.0.1:686 TIME_WAIT
+--- check time: Die Jun 3 23:22:38 CEST 2003 ----------------
+tcp 0 0 127.0.0.1:620 127.0.0.1:686 TIME_WAIT
+--- check time: Die Jun 3 23:22:39 CEST 2003 ----------------
+tcp 0 0 127.0.0.1:620 127.0.0.1:686 TIME_WAIT
+--- check time: Die Jun 3 23:22:40 CEST 2003 ----------------
+tcp 0 0 127.0.0.1:620 127.0.0.1:686 TIME_WAIT
+--- check time: Die Jun 3 23:22:41 CEST 2003 ----------------
+tcp 0 0 127.0.0.1:620 127.0.0.1:686 TIME_WAIT
+--- check time: Die Jun 3 23:22:42 CEST 2003 ----------------
+tcp 0 0 127.0.0.1:620 127.0.0.1:686 TIME_WAIT
+--- check time: Die Jun 3 23:22:43 CEST 2003 ----------------
+tcp 0 0 127.0.0.1:620 127.0.0.1:686 TIME_WAIT
+--- check time: Die Jun 3 23:22:44 CEST 2003 ----------------
+tcp 0 0 127.0.0.1:620 127.0.0.1:686 TIME_WAIT
+--- check time: Die Jun 3 23:22:45 CEST 2003 ----------------
+tcp 0 0 127.0.0.1:620 127.0.0.1:686 TIME_WAIT
+--- check time: Die Jun 3 23:22:46 CEST 2003 ----------------
+tcp 0 0 127.0.0.1:620 127.0.0.1:686 TIME_WAIT
+--- check time: Die Jun 3 23:22:47 CEST 2003 ----------------
+tcp 0 0 127.0.0.1:620 127.0.0.1:686 TIME_WAIT
+--- check time: Die Jun 3 23:22:48 CEST 2003 ----------------
+tcp 0 0 127.0.0.1:620 127.0.0.1:686 TIME_WAIT
+--- check time: Die Jun 3 23:22:50 CEST 2003 ----------------
+tcp 0 0 127.0.0.1:620 127.0.0.1:686 TIME_WAIT
+--- check time: Die Jun 3 23:22:51 CEST 2003 ----------------
+tcp 0 0 127.0.0.1:620 127.0.0.1:686 TIME_WAIT
+--- check time: Die Jun 3 23:22:52 CEST 2003 ----------------
+tcp 0 0 127.0.0.1:620 127.0.0.1:686 TIME_WAIT
+--- check time: Die Jun 3 23:22:53 CEST 2003 ----------------
+tcp 0 0 127.0.0.1:620 127.0.0.1:686 TIME_WAIT
+--- check time: Die Jun 3 23:22:54 CEST 2003 ----------------
+tcp 0 0 127.0.0.1:620 127.0.0.1:686 TIME_WAIT
+--- check time: Die Jun 3 23:22:55 CEST 2003 ----------------
+tcp 0 0 127.0.0.1:620 127.0.0.1:686 TIME_WAIT
+--- check time: Die Jun 3 23:22:56 CEST 2003 ----------------
+tcp 0 0 127.0.0.1:620 127.0.0.1:686 TIME_WAIT
+--- check time: Die Jun 3 23:22:57 CEST 2003 ----------------
+tcp 0 0 127.0.0.1:620 127.0.0.1:686 TIME_WAIT
+--- check time: Die Jun 3 23:22:58 CEST 2003 ----------------
+tcp 0 0 127.0.0.1:620 127.0.0.1:686 TIME_WAIT
+--- check time: Die Jun 3 23:22:59 CEST 2003 ----------------
+tcp 0 0 127.0.0.1:620 127.0.0.1:686 TIME_WAIT
+--- check time: Die Jun 3 23:23:00 CEST 2003 ----------------
+tcp 0 0 127.0.0.1:620 127.0.0.1:686 TIME_WAIT
+--- check time: Die Jun 3 23:23:01 CEST 2003 ----------------
+tcp 0 0 127.0.0.1:620 127.0.0.1:686 TIME_WAIT
+--- check time: Die Jun 3 23:23:02 CEST 2003 ----------------
+tcp 0 0 127.0.0.1:620 127.0.0.1:686 TIME_WAIT
+--- check time: Die Jun 3 23:23:03 CEST 2003 ----------------
+tcp 0 0 127.0.0.1:620 127.0.0.1:686 TIME_WAIT
+--- check time: Die Jun 3 23:23:04 CEST 2003 ----------------
+tcp 0 0 127.0.0.1:620 127.0.0.1:686 TIME_WAIT
+--- check time: Die Jun 3 23:23:05 CEST 2003 ----------------
+tcp 0 0 127.0.0.1:620 127.0.0.1:686 TIME_WAIT
+--- check time: Die Jun 3 23:23:06 CEST 2003 ----------------
+tcp 0 0 127.0.0.1:620 127.0.0.1:686 TIME_WAIT
+--- check time: Die Jun 3 23:23:07 CEST 2003 ----------------
+tcp 0 0 127.0.0.1:620 127.0.0.1:686 TIME_WAIT
+--- check time: Die Jun 3 23:23:08 CEST 2003 ----------------
+tcp 0 0 127.0.0.1:620 127.0.0.1:686 TIME_WAIT
+--- check time: Die Jun 3 23:23:09 CEST 2003 ----------------
+tcp 0 0 127.0.0.1:620 127.0.0.1:686 TIME_WAIT
+--- check time: Die Jun 3 23:23:10 CEST 2003 ----------------
+tcp 0 0 127.0.0.1:620 127.0.0.1:686 TIME_WAIT
+--- check time: Die Jun 3 23:23:11 CEST 2003 ----------------
+tcp 0 0 127.0.0.1:620 127.0.0.1:686 TIME_WAIT
+--- check time: Die Jun 3 23:23:12 CEST 2003 ----------------
+tcp 0 0 127.0.0.1:620 127.0.0.1:686 TIME_WAIT
+--- check time: Die Jun 3 23:23:13 CEST 2003 ----------------
+tcp 0 0 127.0.0.1:620 127.0.0.1:686 TIME_WAIT
+--- check time: Die Jun 3 23:23:14 CEST 2003 ----------------
+tcp 0 0 127.0.0.1:620 127.0.0.1:686 TIME_WAIT
+--- check time: Die Jun 3 23:23:15 CEST 2003 ----------------
+tcp 0 0 127.0.0.1:620 127.0.0.1:686 TIME_WAIT
+--- check time: Die Jun 3 23:23:16 CEST 2003 ----------------
+tcp 0 0 127.0.0.1:620 127.0.0.1:686 TIME_WAIT
+--- check time: Die Jun 3 23:23:18 CEST 2003 ----------------
+--- check time: Die Jun 3 23:23:19 CEST 2003 ----------------
+--- check time: Die Jun 3 23:23:20 CEST 2003 ----------------
+--- check time: Die Jun 3 23:23:21 CEST 2003 ----------------
+--- check time: Die Jun 3 23:23:22 CEST 2003 ----------------
+--- check time: Die Jun 3 23:23:23 CEST 2003 ----------------
+--- check time: Die Jun 3 23:23:24 CEST 2003 ----------------
diff --git a/rasmgr/test/test_hostcmp b/rasmgr/test/test_hostcmp
new file mode 100644
index 0000000..774a6c6
--- /dev/null
+++ b/rasmgr/test/test_hostcmp
Binary files differ
diff --git a/rasmgr/test/test_hostcmp.cc b/rasmgr/test/test_hostcmp.cc
new file mode 100644
index 0000000..c88e330
--- /dev/null
+++ b/rasmgr/test/test_hostcmp.cc
@@ -0,0 +1,56 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_hostcmp.cc
+ *
+ * MODULE: rasmgr
+ * CLASS:
+ *
+ * SYNOPSIS:
+ * test_hostcmp hostname1 hostname2
+ *
+ * PURPOSE:
+ * test hostname comparison function of rasmgr, Configuration::hostCmp().
+ *
+ * COMMENTS:
+ * None
+ *
+*/
+
+using namespace std;
+
+#include <iostream>
+
+extern int hostCmp( const char *h1, const char *h2 );
+
+int main(int argc, char** argv)
+{
+ if (argc != 3)
+ {
+ cout << "usage: " << argv[0] << " hostname1 hostname2" << endl;
+ return -2;
+ }
+
+ cout << argv[0] << ": hostCmp( " << argv[1] << ", " << argv[2] << " ) -> " << (hostCmp( argv[1], argv[2]) ? "true" : "false") << endl;
+ return 0;
+}
diff --git a/rasmgr/test/test_hostcmp.sh b/rasmgr/test/test_hostcmp.sh
new file mode 100644
index 0000000..c9a99cc
--- /dev/null
+++ b/rasmgr/test/test_hostcmp.sh
@@ -0,0 +1,36 @@
+#!/bin/bash -x
+
+# test_hostcmp: test hostCmp() function of rasmgr
+
+# return codes
+export RC_OK=0
+export RC_ERROR=1
+
+INDENT="+++ "
+TESTPROG=./test_hostcmp
+
+HOST_SHORT=abc
+HOST_LONG=${HOST_SHORT}.def.ghi
+HOST_OTHER=xyz
+
+echo $0: testing rasmgr/rascontrol.
+
+echo $INDENT good cases, equal:
+$TESTPROG $HOST_SHORT $HOST_SHORT
+$TESTPROG $HOST_LONG $HOST_LONG
+$TESTPROG "" ""
+
+echo $INDENT general cases, equal:
+$TESTPROG $HOST_SHORT $HOST_LONG
+$TESTPROG $HOST_LONG $HOST_SHORT
+
+echo $INDENT general cases, NOT equal:
+$TESTPROG $HOST_SHORT $HOST_OTHER
+$TESTPROG $HOST_LONG $HOST_OTHER
+
+echo $INDENT special cases, NOT equal:
+$TESTPROG $HOST_SHORT ""
+$TESTPROG "" $HOST_SHORT
+
+echo $0: done.
+
diff --git a/rasmgr/test/test_rasmgr.sh b/rasmgr/test/test_rasmgr.sh
new file mode 100644
index 0000000..5d4f522
--- /dev/null
+++ b/rasmgr/test/test_rasmgr.sh
@@ -0,0 +1,103 @@
+#!/bin/bash -x
+
+# return codes
+export RC_OK=0
+export RC_ERROR=1
+
+export RASMGR=rasmgr
+export RASMGR_CONF=rasmgr.conf
+export RASMGR_AUTH=rasmgr_auth.dat
+
+# settings demanded by rasmgr
+export RMANHOME=.
+
+echo $0: testing rasmgr/rascontrol.
+
+# start rasmgr
+
+if [ -f nohup.out ]
+then
+ rm nohup.out || (echo "Error: cannot remove old nohup log file, exiting."; exit $RC_ERROR)
+fi
+
+export START_AND_KILL_RASMGR="
+ ( nohup $RASMGR & ; \
+ export RASMGR_PID=\$!; \
+ sleep 4; \
+ kill \$RASMGR_PID; \
+ cat nohup.out; \
+ rm nohup.out \
+ ) \
+ || echo Error: cannot start/terminate/... rasmgr. "
+
+echo $START_AND_KILL_RASMGR
+
+# -- conf file -------------------
+
+# conf file not present
+if [ -f $RASMGR_CONF ]
+then
+ rm $RASMGR_CONF || (echo "Error: cannot remove old $RASMGR_CONF file, exiting."; exit $RC_ERROR)
+fi
+eval $START_AND_KILL_RASMGR
+exit
+
+# empty conf file
+echo >$RASMGR_CONF
+$START_AND_KILL_RASMGR
+
+# conf file not readable
+chmod a-r $RASMGR_CONF
+$START_AND_KILL_RASMGR
+chmod a+rw $RASMGR_CONF
+
+# illegal cmd in conf file
+cat >$RASMGR_CONF <<EOF
+iiiiiiiiiiillegal cmd
+EOF
+$START_AND_KILL_RASMGR
+
+# for further tests, we provide a sane conf file
+cat >$RASMGR_CONF <<EOF
+define dbh melange_host -connect /
+define srv S1 -host `hostname` -type r -port 0x29999901 -dbh melange_host
+define db RASBASE -dbh melange_host
+EOF
+
+# -- auth file -------------------
+rm $RASMGR_AUTH || (echo "Error: cannot remove old $RASMGR_AUTH file, exiting."; exit $RC_ERROR)
+
+# auth file not present
+if [ -f $RASMGR_AUTH ]
+then
+ rm $RASMGR_AUTH || (echo "Error: cannot remove old $RASMGR_AUTH file, exiting."; exit $RC_ERROR)
+fi
+$START_AND_KILL_RASMGR
+
+# empty auth file
+echo >$RASMGR_AUTH
+$START_AND_KILL_RASMGR
+
+# auth file not readable
+chmod a-r $RASMGR_AUTH
+$START_AND_KILL_RASMGR
+chmod a+rw $RASMGR_AUTH
+
+# auth file has illegal contents
+echo iiiiiiiiillegal >$RAMGR_AUTH
+$START_AND_KILL_RASMGR
+
+# auth file has good contents -- let rasmgr generate the default file, then check
+rm $RASMGR_AUTH
+$START_AND_KILL_RASMGR
+$START_AND_KILL_RASMGR
+
+# -- highlander check ------------
+# start an additional rasmgr, see what it tells
+$START_RASMGR
+export SECOND_PID=$!
+$START_AND_KILL_RASMGR
+kill $SECOND_PID
+
+echo $0: done.
+
diff --git a/rasodmg/Makefile.am b/rasodmg/Makefile.am
new file mode 100644
index 0000000..a2da39c
--- /dev/null
+++ b/rasodmg/Makefile.am
@@ -0,0 +1,58 @@
+# -*-Makefile-*- (for Emacs)
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+#
+# MAKEFILE FOR:
+# module rasodmg
+#
+# COMMENTS:
+#
+##################################################################
+
+AM_CXXFLAGS=@CLIENTCXXFLAGS@
+AM_LDFLAGS=@CLIENTLDFLAGS@
+
+noinst_LIBRARIES=librasodmg.a
+
+librasodmg_a_SOURCES = collection.cc collection.hh collection.icc \
+ set.cc set.hh \
+ iterator.cc iterator.hh iterator.icc \
+ marray.cc marray.hh marray.icc \
+ ref.cc ref.hh ref.icc \
+ transaction.cc transaction.hh transaction.icc \
+ oqlquery.cc oqlquery.hh oqlquery.icc \
+ object.cc object.hh object.icc \
+ database.cc database.hh database.icc \
+ gmarray.cc gmarray.hh gmarray.icc \
+ storagelayout.cc storagelayout.hh storagelayout.icc \
+ tiling.cc tiling.hh \
+ alignedtiling.cc alignedtiling.hh alignedtiling.icc \
+ dirtiling.cc dirtiling.hh \
+ dirdecompose.cc dirdecompose.hh \
+ interesttiling.cc interesttiling.hh \
+ stattiling.cc stattiling.hh \
+ partinsert.cc partinsert.hh \
+ polygon.cc polygon.hh \
+ polycutout.cc polycutout.hh
+
+CLEANFILES = core
+
diff --git a/rasodmg/alignedtiling.cc b/rasodmg/alignedtiling.cc
new file mode 100644
index 0000000..13313f4
--- /dev/null
+++ b/rasodmg/alignedtiling.cc
@@ -0,0 +1,635 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: alignedtiling.cc
+ *
+ * MODULE: rasodmg
+ * CLASS: r_AlignedTiling, r_DefaultTiling
+ *
+ * COMMENTS:
+ * None
+*/
+
+#include <vector>
+#include <math.h>
+#include <cstring>
+#include <cstdlib>
+
+#include "rasodmg/alignedtiling.hh"
+#include "raslib/rmdebug.hh"
+#include "raslib/rminit.hh"
+
+#ifdef __VISUALC__
+#include <strstrea.h>
+#else
+#include <strstream>
+#endif
+
+const char*
+r_Aligned_Tiling::description = "tile configuration or tile dimension and tile size (in bytes) (ex: \"[0:9,0:9];100\" or \"2;100\")";
+
+r_Aligned_Tiling::r_Aligned_Tiling(const char* encoded) throw (r_Error)
+ : r_Dimension_Tiling(0, 0)
+ {
+
+ if(!encoded)
+ {
+ RMInit::logOut << "r_Aligned_Tiling::r_Aligned_Tiling(" << (encoded?encoded: "NULL") << ")" << std::endl;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+
+ r_Bytes tileS=0, lenToConvert=0;
+ r_Minterval* tileConf=NULL;
+ r_Dimension tileD=0;
+ bool state=false; //false for "tileconf;tilesize", true for "tiledim,tilesize"
+ const char *pStart=NULL, *pRes=NULL, *pEnd=NULL;
+ char *pToConvert=NULL;
+ pStart=encoded;
+ pEnd=pStart+strlen(pStart);
+ pRes=strstr(pStart, COLON);
+ if(!pRes)
+ {
+ RMInit::logOut << "r_Aligned_Tiling::r_Aligned_Tiling(" << encoded << "): Error decoding tile configuration from tilingparams." << std::endl;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+
+ //deal with first param
+ lenToConvert=pRes-pStart;
+ pToConvert = new char[lenToConvert+1];
+ memcpy(pToConvert,pStart,lenToConvert);
+ pToConvert[lenToConvert]='\0';
+
+ if(*pToConvert == *LSQRBRA)
+ {
+ try
+ {
+ tileConf=new r_Minterval(pToConvert);
+ }
+ catch(r_Error& err)
+ {
+ RMInit::logOut << "r_Aligned_Tiling::r_Aligned_Tiling(" << encoded << "): Error decoding tile configuration \"" << pToConvert << "\" from tileparams." << std::endl;
+ RMInit::logOut << "Error " << err.get_errorno() << " : " << err.what() << std::endl;
+ delete [] pToConvert;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+ }
+ else
+ {
+ tileD=strtol(pToConvert, (char**)NULL, DefaultBase);
+ if (!tileD)
+ {
+ RMInit::logOut << "r_Aligned_Tiling::r_Aligned_Tiling(" << encoded << "): Error decoding tile dimension \"" << pToConvert << "\" from tileparams." << std::endl;
+ delete[] pToConvert;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+ if (tileD < 0)
+ {
+ RMInit::logOut << "r_Aligned_Tiling::r_Aligned_Tiling(" << encoded << "): Error decoding tile dimension \"" << pToConvert << "\" from tileparams." << std::endl;
+ RMInit::logOut << "Dimension is negative." << std::endl;
+ delete[] pToConvert;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+ }
+
+ //skip COLON
+ delete[] pToConvert;
+ if(pRes != (pEnd-1))
+ pRes++;
+ else
+ {
+ RMInit::logOut << "r_Aligned_Tiling::r_Aligned_Tiling(" << encoded << "): Error decoding tiling, end of stream." << std::endl;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+
+ //deal with second param
+ tileS=strtol(pRes,(char**) NULL, DefaultBase);
+ if (!tileS)
+ {
+ RMInit::logOut << "r_Aligned_Tiling::r_Aligned_Tiling(" << encoded << "): Error decoding tile size \"" << pRes << "\"." << std::endl;
+
+ if(tileConf)
+ delete tileConf;
+
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+ if (tileS < 0)
+ {
+ RMInit::logOut << "r_Aligned_Tiling::r_Aligned_Tiling(" << encoded << "): Error decoding tile size \"" << pRes << "\", is negative." << std::endl;
+ if(tileConf)
+ delete tileConf;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+
+ //detect state
+ if(tileConf)
+ {
+ tile_config = *tileConf;
+ dimension = tile_config.dimension();
+ tile_size = tileS;
+ delete tileConf;
+ }
+ else
+ {
+ tile_config = r_Minterval(tileD);
+ dimension = tileD;
+ tile_size = tileS;
+ }
+
+ }
+
+r_Aligned_Tiling::r_Aligned_Tiling(r_Dimension dim, r_Bytes ts) throw (r_Error)
+ : r_Dimension_Tiling(dim, ts),
+ tile_config(dim)
+{
+ /// Default tile configuration - equal sides
+ for(r_Dimension i = 0; i < dim ; i++)
+ tile_config << r_Sinterval((r_Range)0, (r_Range)1);
+}
+
+r_Aligned_Tiling::r_Aligned_Tiling(const r_Minterval& tc, r_Bytes ts) throw (r_Error)
+ : r_Dimension_Tiling(tc.dimension(), ts),
+ tile_config(tc)
+{
+}
+
+r_Tiling*
+r_Aligned_Tiling::clone() const
+{
+ r_Aligned_Tiling* newAT = new r_Aligned_Tiling(tile_config, tile_size);
+ return newAT;
+}
+
+r_Aligned_Tiling::~r_Aligned_Tiling()
+{
+ tile_config.r_deactivate();
+}
+
+const r_Minterval&
+r_Aligned_Tiling::get_tile_config() const
+{
+ return tile_config;
+}
+
+r_Minterval
+r_Aligned_Tiling::compute_tile_domain(const r_Minterval& dom, r_Bytes cell_size) const
+{
+RMDBGENTER(3, RMDebug::module_rasodmg, "r_Aligned_Tiling", "compute_tile_domain(" << dom << ", " << cell_size << ")")
+ // Minimum optimal tile size. Below this value, the waste will be too big.
+ r_Bytes optMinTileSize = get_min_opt_tile_size();
+
+ // number of cells per tile according to storage options
+ r_Area numCellsTile = tile_size / cell_size;
+
+ // For final result.
+ r_Minterval tileDomain(dimension);
+
+ int startIx = -1;
+
+ for (r_Dimension i = 0; i < dimension ; i++)
+ {
+ if (tile_config[i].is_low_fixed() == 0 ||
+ tile_config[i].is_high_fixed() == 0)
+ startIx = i;
+ }
+ if (startIx >= 0) // Some limits are nonfixed
+ {
+ unsigned long size = cell_size;
+ int i;
+
+ for(i = startIx; i >=0 ; i--) // treat the non fixed limits first
+ {
+ r_Range l, h;
+
+ // If any of the limits is non-fixed along this direction, tiles
+ // will extend from one side to the other along this direction.
+ if ((tile_config[i].is_low_fixed() == 0) ||
+ (tile_config[i].is_high_fixed() == 0))
+ {
+
+ l = dom[i].low();
+ h = dom[i].high();
+
+ /*
+ Alternative interpretation of tile_config with non fixed limits
+ For the time being is useless because the splittile algorithm
+ doesn't take into account the origin of the tile
+ if (tile_config[i].is_low_fixed() == 0)
+ l = contentsDomain[i].low();
+ else
+ l = tile_config[i].low();
+ if (tileconfig[i].is_high_fixed() == 0)
+ h = contentsDomain[i].high();
+ else
+ h = tile_config[i].high();
+ */
+
+ if(size * (h - l + 1) > tile_size)
+ {
+ h = tile_size/size + l - 1;
+ }
+ size = size * (h - l + 1);
+ tileDomain[i] = r_Sinterval(r_Range(l) ,r_Range(h));
+ }
+ }
+ for(i = dimension-1; i >=0 ; i--) // treat fixed limits now
+ {
+ r_Range l, h;
+
+ // If any of the limits is non-fixed along this direction, tiles
+ // will extend from one side to the other along this direction.
+ if ((tile_config[i].is_low_fixed() != 0) &&
+ (tile_config[i].is_high_fixed() != 0))
+ {
+ l = tile_config[i].low();
+ h = tile_config[i].high();
+
+ if(size * (h - l + 1) > tile_size)
+ {
+ h = tile_size/size + l - 1;
+ }
+ size = size * (h - l + 1);
+ tileDomain[i] = r_Sinterval(r_Range(l) ,r_Range(h));
+ }
+ }
+
+ RMDBGEXIT(2, RMDebug::module_rasodmg, "r_Aligned_Tiling", "calculateTileDomain result : " << tileDomain <<std::endl)
+ return tileDomain;
+ }
+ else // tile_config has only fixed limits
+ {
+ unsigned long numCellsTileConfig = tile_config.cell_count();
+ unsigned long sizeTileConfig = numCellsTileConfig * cell_size;
+
+ if (sizeTileConfig > get_min_opt_tile_size() && sizeTileConfig < tile_size)
+ {
+ RMDBGEXIT(2, RMDebug::module_rasodmg, "r_Aligned_Tiling", "calculateTileDomain result : " << tile_config)
+ return tile_config;
+ }
+ else
+ {
+ float sizeFactor = (float) numCellsTile / numCellsTileConfig;
+
+ float f = float (1/ float(dimension));
+ float dimFactor = (float)pow(sizeFactor, f);
+ RMDBGMIDDLE(2, RMDebug::module_rasodmg, "r_Aligned_Tiling", "dim factor == " << dimFactor)
+
+ unsigned long l, h;
+ unsigned long newWidth;
+
+ // extending the bound of each r_Sinterval of tile_config by
+ // using the factor dimFactor
+ for (int i = 0; i < dimension ; i++)
+ {
+ l = tile_config[i].low();
+ h = tile_config[i].high();
+ newWidth = (unsigned long) ((h - l + 1) * dimFactor);
+ if (newWidth < 1) newWidth = 1;
+ tileDomain << r_Sinterval(r_Range(l), r_Range(l + newWidth - 1));
+ }
+
+ // Approximate the resulting tile size to the target one:
+
+ /*
+ r_Minterval tmpTileDomain =
+ get_opt_size(tileDomain, cell_size);
+ tileDomain = tmpTileDomain;
+ */
+
+/*
+ unsigned long sz = tileDomain.cell_count() * cell_size;
+
+ RMDBGOUT(2,"cell_size " << cell_size << " tileDomain "<< tileDomain << std::endl)
+ RMDBGOUT(2,"cell_count == " << tileDomain.cell_count() << " sz == " << sz << std::endl)
+
+ unsigned long newSz = sz;
+ for(i = dimension-1; i >= 0 && newSz < tile_size ; i--)
+ {
+ RMDBGOUT(2, "inside the cycle " << std::endl)
+ unsigned long deltaSz = cell_size;
+ for (int j = 0 ; j < dimension ; j++)
+ if (j != i)
+ deltaSz *= (tileDomain[j].high()-tileDomain[j].low()+1);
+
+ h = tileDomain[i].high();
+ if (deltaSz + newSz <= tile_size)
+ {
+ tileDomain[i].set_high(r_Range(h + 1));
+ newSz += deltaSz;
+ }
+ }
+*/
+
+ if (tileDomain.cell_count() * cell_size > tile_size)
+ RMDBGMIDDLE(2, RMDebug::module_rasodmg, "Error in r_Aligned_Tiling", "calculateTileDomain() " << std::endl);
+ if (tileDomain.cell_count() * cell_size < optMinTileSize)
+ RMDBGMIDDLE(2, RMDebug::module_rasodmg, "r_Aligned_Tiling", "calculateTileDomain() result non optimal " << std::endl);
+
+ RMDBGEXIT(2, RMDebug::module_rasodmg, "r_Aligned_Tiling", "calculateTileDomain result : " << tileDomain << std::endl)
+ // cout << "return 3"<<std::endl;
+ return tileDomain;
+ }
+ }
+}
+
+std::vector<r_Minterval>*
+r_Aligned_Tiling::compute_tiles(const r_Minterval& obj_domain, r_Bytes cell_size) const throw (r_Error)
+{
+ std::vector<r_Minterval>* result = new std::vector<r_Minterval>;
+
+ r_Dimension dim = tile_config.dimension();
+
+ r_Minterval bigDom = obj_domain;
+
+ r_Minterval tileDom = compute_tile_domain(obj_domain, cell_size);
+
+ // cout << "r_Aligned_Tiling::compute_tiles() " << tileDom << std::endl;
+
+ r_Minterval currDom(tileDom.dimension());
+ r_Point cursor(tileDom.dimension());
+ r_Point tileSize;
+ r_Point origin;
+ int done = 0;
+
+ // initialize cursor
+ for(dim = 0; dim < cursor.dimension(); dim++)
+ cursor[dim] = 0;
+
+ // calculate size of Tiles
+ tileSize = tileDom.get_extent();
+
+ // origin of bigTile
+ origin = bigDom.get_origin();
+
+ // initialize currDom
+ for(dim=0; dim < cursor.dimension(); dim++)
+ currDom << r_Sinterval((r_Range) (origin[dim]), (r_Range) (origin[dim] + tileSize[dim] - 1));
+ // resets tileDom to lower left side of bigTile
+ tileDom = currDom;
+
+ // intersect with bigTile
+ currDom.intersection_with(bigDom);
+
+ // iterate with smallTile over bigTile
+ while(!done)
+ {
+ currDom.intersection_with(bigDom);
+
+ // create new smallTile
+ r_Minterval smallTile(dim);
+
+ smallTile = currDom;
+
+ // insert tile in set
+ result->push_back(smallTile);
+
+ // increment cursor, start with highest dimension
+ long i = cursor.dimension() - 1;
+ cursor[(unsigned int)i] += tileSize[(unsigned int)i];
+ // move cursor
+ currDom = tileDom.create_translation(cursor);
+ while(!(currDom.intersects_with(bigDom)))
+ {
+ cursor[(unsigned int)i] = 0;
+ i--;
+ if(i < 0)
+ {
+ done = 1;
+ break;
+ }
+ cursor[(unsigned int)i] += tileSize[(unsigned int)i];
+ // move cursor
+ currDom = tileDom.create_translation(cursor);
+ }
+ }
+ return result;
+}
+
+r_Minterval
+r_Aligned_Tiling::get_opt_size(const r_Minterval& tileDomain, r_Bytes cellSize) const
+{
+
+ unsigned long tileSize = get_tile_size();
+ unsigned long newSize = tileDomain.cell_count() * cellSize;
+ r_Minterval result = tileDomain;
+ r_Dimension dim = tileDomain.dimension();
+ int* ixArr = new int[dim];
+ int* tmpIxArr = new int[dim];
+ r_Minterval tmpResult = result;
+ int j;
+
+ for (j = 0; j < dim; j++)
+ ixArr[j] = j;
+
+ for(j = dim - 1; j >=0 && newSize < tileSize ; j--)
+ {
+ int i=0;
+ unsigned long h, wd;
+ unsigned minWidthIx = 0;
+ unsigned long minWidth = tileDomain[0].high()-tileDomain[0].low()+1;
+ for(int k = j; k >=0 ; k--)
+ {
+ i = ixArr[k];
+
+ h = result[i].high() + 1;
+ wd = result[i].high() - result[i].low() + 1;
+ if (wd < minWidth)
+ {
+ minWidth = wd;
+ minWidthIx = i;
+ }
+ }
+
+ int tmpIx = ixArr[j];
+ ixArr[minWidthIx] = tmpIx;
+
+ tmpResult[minWidthIx].set_high(r_Range(h));
+ newSize = tmpResult.cell_count() * cellSize;
+ if (newSize > tileSize)
+ {
+ for(i = dim-1; i >=0 ; i--)
+ {
+ h = result[i].high() + 1;
+ wd = result[i].high() - result[i].low() + 1;
+ if (wd < minWidth)
+ {
+ minWidth = wd;
+ minWidthIx = i;
+ }
+ }
+ }
+
+ result[minWidthIx].set_high(r_Range(h));
+ newSize = result.cell_count() * cellSize;
+ if (newSize > tileSize)
+ {
+ result[minWidthIx].set_high(r_Range(h - 1));
+ }
+ }
+ delete[] ixArr;
+ return result;
+}
+
+r_Tiling_Scheme
+r_Aligned_Tiling::get_tiling_scheme() const
+{
+ return r_AlignedTiling;
+}
+
+r_Bytes
+r_Aligned_Tiling::get_min_opt_tile_size() const
+{
+ return (get_tile_size() - get_tile_size()/10);
+}
+
+char*
+r_Aligned_Tiling::get_string_representation() const
+{
+
+ unsigned int bufferSize = 25; // should be enough!
+
+ // allocate buffer and initialize string stream
+ char* buffer = new char[bufferSize];
+ std::ostrstream domainStream(buffer, bufferSize);
+
+ // write into string stream
+
+ print_status(domainStream);
+ domainStream << std::ends;
+
+ // allocate memory taking the final string
+ char* returnString = strdup(buffer);
+
+ // delete buffer
+ delete[] buffer;
+
+ return returnString;
+}
+
+void
+r_Aligned_Tiling::print_status(std::ostream& os) const
+{
+ os << "r_Aligned_Tiling[ ";
+ r_Dimension_Tiling::print_status(os);
+ os << " tile configuration = "<< tile_config <<" ]";
+}
+
+/*
+std::ostream&
+operator<<(std::ostream& s, const r_Aligned_Tiling& at)
+{
+ at.print_status(s);
+ return s;
+}
+*/
+
+/*
+std::vector<r_Minterval>*
+r_Default_Tiling::compute_tiles(const r_Minterval& obj_domain, long cell_size)
+ const
+{
+ std::vector<r_Minterval>* result = new std::vector<r_Minterval>;
+
+ RMDBGENTER(4, RMDebug::module_rasodmg, "r_Default_Tiling", "compute_tiles")
+
+
+ r_Minterval bigDom = obj_domain;
+
+ r_Minterval tileDom(bigDom.dimension());
+
+ // compute the domain of the small tiles
+ // tiles are n-dimensional cubes with edge length n-th root of max tile size
+ //old implementations:
+ //long edgeLength = (long)floor(exp((1/(double)tileDom.dimension())*
+ // log(RMInit::tileSize/mar->get_type_length())));
+ //long edgeLength = (long)floor(exp((1/(double)tileDom.dimension())*
+ // log(get_tile_size()/cell_size)));
+
+ RMDBGMIDDLE(4, RMDebug::module_rasodmg, "r_Default_Tiling", "tile size == " << get_tile_size())
+ long edgeLength = (long) floor(pow(get_tile_size()/cell_size,
+ 1/(double)tileDom.dimension()));
+ r_Dimension dim;
+
+ for(dim=0; dim<tileDom.dimension(); dim++)
+ tileDom << r_Sinterval((r_Range)0, (r_Range)edgeLength-1);
+
+ r_Minterval currDom(tileDom.dimension());
+ r_Point cursor(tileDom.dimension());
+ r_Point tileSize;
+ r_Point origin;
+ int done = 0;
+
+ // initialize cursor
+ for(dim = 0; dim < cursor.dimension(); dim++)
+ cursor[dim] = 0;
+
+ // calculate size of Tiles
+ tileSize = tileDom.get_extent();
+
+ // origin of bigTile
+ origin = bigDom.get_origin();
+
+ // initialize currDom
+ for(dim=0; dim < cursor.dimension(); dim++)
+ currDom << r_Sinterval((r_Range) (origin[dim]), (r_Range) (origin[dim] + tileSize[dim] - 1));
+ // resets tileDom to lower left side of bigTile
+ tileDom = currDom;
+
+ // intersect with bigTile
+ currDom.intersection_with(bigDom);
+
+ // iterate with smallTile over bigTile
+ while(!done)
+ {
+ currDom.intersection_with(bigDom);
+
+ // create new smallTile
+ r_Minterval smallTile(dim);
+
+ smallTile = currDom;
+
+ // insert tile in set
+ result->push_back(smallTile);
+
+ // increment cursor, start with highest dimension
+ long i = cursor.dimension() - 1;
+ cursor[(unsigned int)i] += tileSize[(unsigned int)i];
+ // move cursor
+ currDom = tileDom.create_translation(cursor);
+ while(!(currDom.intersects_with(bigDom)))
+ {
+ cursor[(unsigned int)i] = 0;
+ i--;
+ if(i < 0)
+ {
+ done = 1;
+ break;
+ }
+ cursor[(unsigned int)i] += tileSize[(unsigned int)i];
+ // move cursor
+ currDom = tileDom.create_translation(cursor);
+ }
+ }
+ RMDBGEXIT(4, RMDebug::module_rasodmg, "r_Default_Tiling", "compute_tiles")
+ return result;
+}
+*/
diff --git a/rasodmg/alignedtiling.hh b/rasodmg/alignedtiling.hh
new file mode 100644
index 0000000..ba8c2a4
--- /dev/null
+++ b/rasodmg/alignedtiling.hh
@@ -0,0 +1,211 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: alignedtiling.hh
+ *
+ * MODULE: rasodmg
+ * CLASS: r_Aligned_Tiling, r_Default_Tiling
+ *
+ * COMMENTS:
+ * None
+*/
+
+#ifndef _R_ALIGNEDTILING_HH_
+#define _R_ALIGNEDTILING_HH_
+
+class r_Aligned_Tiling;
+
+#include "rasodmg/tiling.hh"
+#include "raslib/minterval.hh"
+
+//@ManMemo: Module: {\bf rasodmg}
+
+/*@Doc:
+
+ The {\tt r_Aligned_Tiling} class is used to express the options
+ for aligned tiling of {\tt r_Marray} objects.
+
+ The following options may be set:
+
+ \begin{itemize}
+ \item {\bf Tile configuration}
+
+ describes which format tiles should have. The tile configuration
+ is expressed using a multidimensional interval {\tt r_Minterval}.
+ This interval should have null lower limits and
+ must have the same dimensionality as that of the
+ objects to which it is to be applied. Its lengths along each
+ direction are interpreted relative to the others.
+
+ For example, if tile configuration is {\tt[ 0:9, 0:9, 0:19]}, tiles
+ will be three dimensional arrays with two sides of equal length and
+ double that length along the third direction.
+
+ If a fixed tile is required, tile configuration and
+ tile size should be set in such a way that the size of a tile
+ with the given configuration is equal to the specified tile size.
+ For example, if the tile configuration is {\tt [ 0:29, 0:39, 0:59]}
+ and cell size is 2, then the tile size should be set to
+ 144000. This will also result in more efficient computation of
+ the tiling since the given tile configuration is used unchanged if
+
+ {\tt 90% * tile_size < size of tile_config < tile_size}
+
+ (i.e., no computation is necessary). This applies equally to tile
+ configurations with non-fixed limits.
+
+ Tiles with non-fixed limits are used to express preferential
+ directions for tiling. For example, {\tt [ 0:9 , 0:* ]} expresses that
+ tiles should be done along the first direction, i.e., they
+ should have domains :
+
+ \begin{verbatim}
+ [ 0 : 9 , 0 : marray.domain[1].high() ]
+ [ 10 : 19 , 0 : marray.domain[1].high() ]
+ ...
+ \end{verbatim}
+
+ assuming this results in a tile with the given tile size. If not,
+ the limits in the first direction are changed. The higher dimensions
+ are given preference in that tiles will be preferably
+ extended along a higher dimension than a lower one if two or
+ more limits are open.
+
+ The default configuration corresponds to an interval with equal
+ lengths along all directions.
+
+ \item {\bf Tile size }
+
+ describes the size for tiles of the object in characters.
+ Tiling is done so that tiles are as big as possible but wit a
+ smaller size than this one.
+ The default tile size is the size specified for the RasDaMan client.
+
+ Notice: the tiling options are invalid if the rasdaman client is running
+ with the option notiling. In that case, no tiling is done,
+ independently of the storage layout chosen.
+*/
+
+class r_Aligned_Tiling : public r_Dimension_Tiling
+{
+ public:
+ /// read everything from encoded string
+ /// (e.g. "[0:9,0:9];100" or "2;100")
+ r_Aligned_Tiling(const char* encoded) throw (r_Error);
+
+ /// dimension and tile size.
+ r_Aligned_Tiling(r_Dimension dim, r_Bytes ts = RMInit::clientTileSize) throw (r_Error);
+
+ /// dimension and tile size will be taken from RMInit::clientTileSize.
+ //r_Aligned_Tiling(r_Dimension dim) throw (r_Error);
+
+ /// tile configuration and tile size.
+ r_Aligned_Tiling(const r_Minterval& tc, r_Bytes ts = RMInit::clientTileSize) throw (r_Error);
+
+ virtual r_Tiling* clone() const;
+
+ virtual ~r_Aligned_Tiling();
+
+ /// returns the current value for the tile configuration option
+ const r_Minterval& get_tile_config() const;
+
+ std::vector<r_Minterval>* compute_tiles(const r_Minterval& obj_domain, r_Bytes cell_size) const throw (r_Error);
+
+ char* get_string_representation() const;
+ /**
+ The string representation delivered by this method is allocated using
+ {\tt malloc()} and has to be freed using {\tt free()} in the end.
+ */
+
+ /// writes the state of the object to the specified stream
+ void print_status(std::ostream& s = cout) const;
+
+ virtual r_Tiling_Scheme get_tiling_scheme() const;
+
+ static const char* description;
+
+ protected:
+
+ /// determines the individual tiles domains
+ r_Minterval compute_tile_domain(const r_Minterval& dom, r_Bytes cell_size) const;
+ /**
+ Determines the individual tiles domains for aligned tiling,
+ using the options expressed in this object.
+ Takes into account the tile size and the tile configuration,
+ as well as the cell size given by {\ttcell_size}.
+
+ Returns the domain for tiles in such a way that the tile
+ configuration is as close to {\tttile_config} set in this object and
+ the size is lower than {\tt tile_size}.
+
+ The origin of the returned interval is the same as that from
+ {\ttthis->tile_config}.
+
+ The data to partition has domain {\tt dom } and cells with size
+ {\tt cell_size}.
+ To be used before splitting a tile with domain {\tt dom} (typically,
+ containing all the cells belonging to an {\ttr_Marray} object).
+ */
+
+ /// tile configuration
+ r_Minterval tile_config;
+
+ ///
+ r_Bytes get_min_opt_tile_size() const;
+
+ ///
+ r_Minterval get_opt_size(const r_Minterval& tile_domain, r_Bytes cell_size) const;
+};
+
+//@ManMemo: Module: {\bf rasodmg}
+
+/*@Doc:
+
+ The {\tt r_Default_Tiling} class is used to express the default tiling
+ of {\tt r_Marray} objects. According to this algorithm, tiles are divided
+ into equal sized multidimensional blocks qith equal lengths along
+ all directions of the spatial domain.
+
+ The following parameter may be set:
+
+ \item {\bf Tile size }
+
+ describes the size for tiles of the object in characters.
+ Tiling is done so that tiles have a smaller size than this one.
+ The default tile size is the size specified for the RasDaMan client.
+ In bytes.
+*/
+
+
+//@ManMemo: Module: {\bf rasodmg }
+/**
+ Output stream operator for objects of type {\tt const}
+ \Ref{r_Aligned_Tiling}.
+*/
+//extern std::ostream& operator<<(std::ostream& s, const r_Aligned_Tiling& at);
+
+#endif
+
+
+
+
diff --git a/rasodmg/alignedtiling.icc b/rasodmg/alignedtiling.icc
new file mode 100644
index 0000000..6abeb23
--- /dev/null
+++ b/rasodmg/alignedtiling.icc
@@ -0,0 +1,31 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INLINE SOURCE: storage.icc
+ *
+ * MODULE: rasodmg
+ * CLASS: r_Storage
+ *
+ * COMMENTS:
+ * None
+*/
diff --git a/rasodmg/collection.cc b/rasodmg/collection.cc
new file mode 100644
index 0000000..c5da7de
--- /dev/null
+++ b/rasodmg/collection.cc
@@ -0,0 +1,627 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: collection.cc
+ *
+ * MODULE: rasodmg
+ * CLASS: r_Collection
+ *
+ * COMMENTS:
+ * None
+*/
+
+using namespace std;
+
+static const char rcsidcollection[] = "@(#)rasodmg, r_Collection: $Id: collection.cc,v 1.53 2005/07/06 23:30:22 rasdev Exp $";
+
+#include "raslib/rmdebug.hh"
+#include "raslib/collectiontype.hh"
+
+#include "rasodmg/collection.hh"
+#include "rasodmg/iterator.hh"
+#include "rasodmg/database.hh"
+
+#include "clientcomm/clientcomm.hh"
+#include <string.h>
+
+#ifndef __GNUG__
+#define NULL 0
+#endif
+
+template<class T>
+r_Collection<T>::r_Collection() throw(r_Error)
+ : r_Object( 2 ), card(0)
+{
+ init_node_list( coll );
+ init_node_list( removed_objects );
+}
+
+
+template<class T>
+r_Collection<T>::r_Collection( const r_Collection<T>& collection ) throw(r_Error)
+ : r_Object( collection, 2 )
+{
+ CNode* nptr;
+ CNode* optr;
+
+ coll = new CNode;
+ nptr = coll;
+ optr = collection.coll;
+
+ while ( optr->next != NULL )
+ {
+ nptr->next = new CNode;
+ nptr->elem = new T;
+ *(nptr->elem) = *(optr->elem);
+ nptr = nptr->next;
+ optr = optr->next;
+ }
+ if ( optr->elem != NULL )
+ {
+ nptr->elem = new T;
+ *(nptr->elem) = *(optr->elem);
+ }
+
+ nptr->next = NULL;
+ card = collection.cardinality();
+
+ init_node_list( removed_objects );
+}
+
+template<class T>
+r_Collection<T>::r_Collection( const void* node1 )
+{
+ // This constructor is nearly the same as a copy constrctor,
+ // except that the argument is not of type r_Collection but
+ // of type CNode* (the collection's internal representation).
+ // Does the same as function set_internal_representation.
+
+ // We assume that node1 is a correct CNode structure as
+ // defined in collection.hh
+ // copy it and determine cardinality
+ CNode* nptr;
+ CNode* optr;
+
+ card = 0;
+ coll = new CNode;
+ nptr = coll;
+ optr = (CNode*)node1;
+
+ while ( optr->next != NULL )
+ {
+ nptr->next = new CNode;
+ nptr->elem = new T;
+ card++;
+ *(nptr->elem) = *(optr->elem);
+ nptr = nptr->next;
+ optr = optr->next;
+ }
+ if ( optr->elem != NULL )
+ {
+ nptr->elem = new T;
+ card++;
+ *(nptr->elem) = *(optr->elem);
+ }
+
+ nptr->next = NULL;
+
+ init_node_list( removed_objects );
+}
+
+template<class T>
+r_Collection<T>::~r_Collection()
+{
+ RMDBGONCE(1, RMDebug::module_rasodmg, "r_Collection<T>", "~r_Collection")
+
+ r_deactivate();
+}
+
+
+
+/*************************************************************
+ * Method name...: r_deactivate()
+ *
+ * Arguments.....:
+ * none
+ * Return value..:
+ * none
+ * Description...: This method is called when the object leaves
+ * the application cache. It frees all dynamic
+ * memory allocated within the class.
+ ************************************************************/
+template<class T>
+void
+r_Collection<T>::r_deactivate()
+{
+ RMDBGONCE(1, RMDebug::module_rasodmg, "r_Collection<T>", "r_deactivate()")
+
+ remove_all_nodes( coll );
+ remove_all_nodes( removed_objects );
+}
+
+
+
+template<class T>
+int
+r_Collection<T>::contains_element( const T& element ) const
+{
+ CNode* ptr = coll;
+
+ while ( *(ptr->elem) != element && ptr->next != NULL )
+ ptr = ptr->next;
+
+ if ( *(ptr->elem) == element )
+ return true;
+ else
+ return false;
+}
+
+template<class T>
+void
+r_Collection<T>::insert_element( const T& element, int no_modification )
+{
+ // add node to list...
+ add_node( coll, element );
+
+ // increase cardinaltity
+ card++;
+
+ // ...and remove it from removed objects if it exists
+ remove_node( removed_objects, element );
+
+ if( !no_modification )
+ mark_modified(); // remember modification
+}
+
+template<class T>
+void
+r_Collection<T>::remove_element( const T& element )
+{
+ // remove node from list...
+ if( remove_node( coll, element ) )
+ {
+ // ...and add it to removed objects list
+ add_node( removed_objects, element );
+
+ // decrease cardinality
+ card--;
+
+ mark_modified(); // remember modification
+ }
+}
+
+template<class T>
+void
+r_Collection<T>::remove_all()
+{
+ CNode* ptr = coll;
+ CNode* ptrLast = coll;
+
+ if ( ptr->elem != NULL )
+ {
+ add_node( removed_objects, *ptr->elem );
+ delete ptr->elem;
+ ptr->elem = NULL;
+ }
+ if ( ptr->next != NULL )
+ {
+ ptr = ptr->next;
+ while ( ptr->next != NULL )
+ {
+ add_node( removed_objects, *ptr->elem );
+ delete ptr->elem;
+ ptrLast = ptr;
+ ptr = ptr->next;
+ delete ptrLast;
+ }
+ delete ptr->elem;
+ delete ptr;
+ }
+ coll->next = NULL;
+ card = 0;
+
+ mark_modified(); // remember modification
+}
+
+
+
+template<class T>
+const r_Collection<T>&
+r_Collection<T>::operator=( const r_Collection<T>& collection )
+{
+ CNode* nptr;
+ CNode* optr;
+
+ if( this != &collection )
+ {
+ if( coll )
+ remove_all();
+ else
+ coll = new CNode;
+
+ nptr = coll;
+ optr = collection.coll;
+
+ while ( optr->next != NULL )
+ {
+ nptr->next = new CNode;
+ nptr->elem = new T;
+ *(nptr->elem) = *(optr->elem);
+ nptr = nptr->next;
+ optr = optr->next;
+ }
+ if ( optr->elem != NULL )
+ {
+ nptr->elem = new T;
+ *(nptr->elem) = *(optr->elem);
+ }
+
+ nptr->next = NULL;
+ card = collection.cardinality();
+ }
+
+ return *this;
+}
+
+
+
+template<class T>
+void
+r_Collection<T>::set_internal_representation( const void* node1 )
+{
+ // We assume that node1 is a correct CNode structure as
+ // defined in collection.hh
+ // copy it and determine cardinality
+ CNode* nptr;
+ CNode* optr;
+
+ if( coll )
+ remove_all();
+ else
+ coll = new CNode;
+
+ card = 0;
+ nptr = coll;
+ optr = (CNode*)node1;
+
+ while ( optr->next != NULL )
+ {
+ nptr->next = new CNode;
+ nptr->elem = new T;
+ card++;
+ *(nptr->elem) = *(optr->elem);
+ nptr = nptr->next;
+ optr = optr->next;
+ }
+ if ( optr->elem != NULL )
+ {
+ nptr->elem = new T;
+ card++;
+ *(nptr->elem) = *(optr->elem);
+ }
+
+ nptr->next = NULL;
+}
+
+
+template<class T>
+r_Iterator<T>
+r_Collection<T>::create_removed_iterator()
+{
+ return r_Iterator<T>( *this, 1 );
+}
+
+
+template<class T>
+r_Iterator<T>
+r_Collection<T>::create_iterator()
+{
+ return r_Iterator<T>( *this );
+}
+
+
+
+template<class T>
+void
+r_Collection<T>::insert_obj_into_db()
+{
+ // Insert myself in database only if I have an object name. If the
+ // collection doesn't have a name an exception is thrown.
+ if( !object_name || !strlen( object_name ) )
+ {
+ r_Error err = r_Error( r_Error::r_Error_ObjectUnknown );
+ throw err;
+ }
+
+ // Insert myself in database only if I have a type name, otherwise
+ // an exception is thrown.
+ if( !type_name || !strlen( type_name ) )
+ {
+ r_Error err = r_Error( r_Error::r_Error_DatabaseClassUndefined );
+ throw err;
+ }
+
+ // Insert myself into the database even if i'm empty.
+// r_Database::actual_database->communication->insertColl( object_name, type_name, get_oid() );
+ r_Database::actual_database->insertColl( object_name, type_name, get_oid() );
+ if( !is_empty() )
+ {
+ r_Iterator<T> iter = create_iterator();
+ for ( iter.reset(); iter.not_done(); iter++ )
+ // Search for *1 for an explanation of the following cast.
+ ((r_Object*)((r_Ref<r_Object>)(*iter)).ptr())->insert_obj_into_db( object_name );
+ }
+}
+
+
+
+template<class T>
+void
+r_Collection<T>::update_obj_in_db()
+{
+ // Update myself in database only if I have an object name. If the
+ // collection doesn't have a name an exception is thrown.
+ if( !object_name || !strlen( object_name ) )
+ {
+ r_Error err = r_Error( r_Error::r_Error_ObjectUnknown );
+ throw err;
+ }
+
+ // inspect collection elements
+ if( !is_empty() )
+ {
+ r_Iterator<T> iter = create_iterator();
+ for ( iter.reset(); iter.not_done(); iter++ )
+ {
+ // *1
+ //
+ // The following is a very ugly cast, but necessary if collection elements are not restricted
+ // to r_Ref objects. Anyway, if the elements are not of type r_Ref, it is not possible to make
+ // them persistent. A workaround would be to call a global function instead having a template
+ // specification for our case.
+ r_Ref<r_Object> ref = (r_Ref<r_Object>)(*iter);
+
+ RMInit::logOut << " Collection object " << ref.get_oid() << " " << std::flush;
+
+ // check if object is loaded
+ if( ref.get_memory_ptr() != 0 )
+ {
+ // Search for *1 for an explanation of the following cast.
+ switch( ((r_Ref<r_Object>)(*iter))->get_status() )
+ {
+ case r_Object::deleted:
+ RMInit::logOut << "state DELETED, not implemented" << endl;
+ RMInit::logOut << "OK" << endl;
+ break;
+
+ case r_Object::created:
+ RMInit::logOut << "state CREATED, writing ... " << std::flush;
+ // Search for *1 for an explanation of the following cast.
+ ((r_Object*)((r_Ref<r_Object>)(*iter)).ptr())->insert_obj_into_db( object_name );
+ RMInit::logOut << "OK" << endl;
+ break;
+
+ case r_Object::modified:
+ RMInit::logOut << "state MODIFIED, not implemented" << endl;
+ break;
+
+ case r_Object::read:
+ RMInit::logOut << "state READ, OK" << endl;
+ break;
+
+ case r_Object::transient:
+ RMInit::logOut << "state TRANSIENT, OK" << endl;
+ break;
+
+ default:
+ RMInit::logOut << "state UNKNOWN" << endl;
+ break;
+ }
+ }
+ else
+ RMInit::logOut << "state NOT LOADED" << endl;
+ }
+ }
+
+ // inspect removed objects
+ if( removed_objects->elem )
+ {
+ r_Iterator<T> iter = create_removed_iterator();
+ for ( iter.reset( 1 ); iter.not_done(); iter++ )
+ {
+ // *1
+ //
+ // The following is a very ugly cast, but necessary if collection elements are not restricted
+ // to r_Ref objects. Anyway, if the elements are not of type r_Ref, it is not possible to make
+ // them persistent. A workaround would be to call a global function instead of having a template
+ // specification for our case.
+ // The oid could also be got by (*iter)->get_oid() from r_Object but in this case, dereferencing
+ // r_Ref would load the object from the server.
+ r_OId currentOId = ((r_Ref<r_Object>)(*iter)).get_oid();
+
+ RMInit::logOut << " Collection object " << currentOId << " " << std::flush;
+
+ RMInit::logOut << "state REMOVED, removing ... " << std::flush;
+ try
+ {
+// r_Database::actual_database->communication->removeObjFromColl( object_name, currentOId );
+ r_Database::actual_database->removeObjFromColl( object_name, currentOId );
+ RMInit::logOut << "OK" << endl;
+ }
+ catch( r_Error& obj )
+ {
+ RMInit::logOut << "FAILED" << endl;
+ RMInit::logOut << obj.what() << endl;
+ }
+ }
+ }
+}
+
+
+
+template<class T>
+void
+r_Collection<T>::add_node( r_Collection<T>::CNode* &root, const T& element )
+{
+ CNode* ptr = root;
+
+ if ( ptr->elem == NULL )
+ {
+ ptr->elem = new T;
+ *(ptr->elem) = element;
+ }
+ else
+ {
+ while ( ptr->next != NULL )
+ ptr = ptr->next;
+
+ ptr->next = new CNode;
+ ptr = ptr->next;
+ ptr->next = NULL;
+ ptr->elem = new T;
+ *(ptr->elem) = element;
+ }
+}
+
+template<class T>
+int
+r_Collection<T>::remove_node( CNode* &root, const T& element )
+{
+ CNode* ptr = root;
+ CNode* ptrLast = root;
+ int success = 0;
+
+ if( ptr && ptr->elem )
+ {
+ // Look for the element or end of list
+ while ( *(ptr->elem) != element && ptr->next != NULL )
+ {
+ ptrLast = ptr;
+ ptr = ptr->next;
+ }
+
+ // If element is found, destroy the element itself.
+ // After that, there are four cases
+ // case 1: The element was the only element of the list
+ // (if so, don't destroy the node itself, only set the elem field NULL)
+ // case 2: The element had no successor
+ // (if so, the node before the element becomes the last node)
+ // case 3: The element had no predecessor
+ // (if so, the node after the element becomes the first node)
+ // case 4: The element had a successor and a prodecessor
+ // (if so, the node after the element becomes the successor of the
+ // node before the element)
+ if ( *(ptr->elem) == element )
+ {
+ success = 1;
+
+ delete ptr->elem;
+ if ( ptr == ptrLast && ptr->next == NULL ) // case 1
+ ptr->elem = NULL;
+ else
+ if ( ptr->next == NULL ) // case 2
+ {
+ ptrLast->next = NULL;
+ delete ptr;
+ }
+ else
+ if ( ptr == ptrLast ) // case 3
+ {
+ root = ptr->next;
+ delete ptr;
+ }
+ else // case 4
+ {
+ ptrLast->next = ptr->next;
+ delete ptr;
+ }
+ }
+ }
+
+ return success;
+}
+
+
+
+template<class T>
+void
+r_Collection<T>::remove_all_nodes( CNode* &root )
+{
+ if( root )
+ {
+ CNode* ptr = root;
+ CNode* ptrLast = root;
+
+ while ( ptr->next != NULL )
+ {
+ delete ptr->elem;
+ ptrLast = ptr;
+ ptr = ptr->next;
+ delete ptrLast;
+ }
+ delete ptr->elem;
+ delete ptr;
+ }
+
+ root = 0;
+}
+
+
+template<class T>
+void
+r_Collection<T>::init_node_list( CNode* &root )
+{
+ root = new CNode;
+ root->next = NULL;
+ root->elem = NULL;
+}
+
+
+
+template<class T>
+const r_Type*
+r_Collection<T>::get_element_type_schema()
+{
+ const r_Type* typePtr = r_Object::get_type_schema();
+ const r_Type* elementTypePtr = 0;
+
+ if( typePtr )
+ {
+ if( typePtr->type_id() == r_Type::COLLECTIONTYPE )
+ {
+ const r_Collection_Type* collectionTypePtr = (const r_Collection_Type*)typePtr;
+ elementTypePtr = &(collectionTypePtr->element_type());
+ }
+ }
+
+ return elementTypePtr;
+}
+
+
+
+
+
+
+
+
+
diff --git a/rasodmg/collection.hh b/rasodmg/collection.hh
new file mode 100644
index 0000000..d90eb39
--- /dev/null
+++ b/rasodmg/collection.hh
@@ -0,0 +1,224 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: collection.hh
+ *
+ * MODULE: rasodmg
+ * CLASS: r_Collection
+ *
+ * COMMENTS:
+ * None
+*/
+
+#ifndef _D_COLLECTION_
+#define _D_COLLECTION_
+
+#include "raslib/error.hh"
+#include "rasodmg/object.hh"
+
+template <class T>
+class r_Iterator;
+
+//@ManMemo: Module: {\bf rasodmg}
+
+/*@Doc:
+
+ Basic class of a collection. Possible subclasses are \Ref{r_Set},
+ \Ref{r_Bag} and \Ref{r_List}. The protected members isOrdered and
+ allowsDuplicates are not initialized here, they have to be initialized
+ in the respective subclasses.
+
+*/
+
+template <class T>
+class r_Collection : public r_Object
+{
+ friend class r_Iterator<T>;
+
+ public:
+ /// default constructor
+ r_Collection() throw(r_Error);
+ /// copy constructor
+ r_Collection( const r_Collection<T>& collection ) throw(r_Error);
+ /// virtual destructor
+ virtual ~r_Collection();
+
+ /// it is called when an object leaves transient memory
+ virtual void r_deactivate();
+
+ /// get number of elements
+ inline unsigned long cardinality() const;
+
+ /// tells if the collection is empty or not
+ inline int is_empty() const;
+ /// tells if the collection is ordered or not
+ inline int is_ordered() const;
+ /// tells if the collections allowes duplicates or not
+ inline int allows_duplicates() const;
+
+ /// asks about the containment of a specific element
+ int contains_element( const T& element ) const;
+ /// inserts an alement at the beginning
+ virtual void insert_element( const T& element, int no_modification = 0 );
+ /**
+ The method inserts an element into the collection. If {\tt no_modification}
+ is set, the {\tt mark_modified()} method of r_Object is not invoked and, therefore,
+ a modification will not be recognized at the commit point.
+ */
+ /// removes an element
+ virtual void remove_element( const T& element );
+ /// removes all elements
+ void remove_all();
+
+ /// assignment operator
+ const r_Collection<T>& operator=( const r_Collection<T>& collection );
+
+ /// create an iterator pointing at the first element in the collection
+ r_Iterator<T> create_iterator();
+
+ /// get base type schema
+ const r_Type* get_element_type_schema();
+
+ //@Man: Methods for database communication (internal use only):
+ //@{
+ ///
+
+ /// insert myself into the database
+ virtual void insert_obj_into_db();
+
+ /// inserts an object into a specific collection in the database
+ virtual void insert_obj_into_db( const char* ){;};
+ /**
+ The method has no functionality in this class. It supposed to be removed in
+ future.
+ */
+
+ /// update myself
+ virtual void update_obj_in_db();
+
+ ///
+ //@}
+
+ //@Man: Constructors/Methods for internal use only:
+ //@{
+ ///
+
+ /// constructor getting an internal collection representation
+ r_Collection( const void* node1 );
+ ///
+ inline void* get_internal_representation() const;
+ ///
+ void set_internal_representation( const void* node1 );
+
+ ///
+ //@}
+
+ protected:
+ ///
+ typedef struct CNode
+ {
+ CNode* next;
+ T* elem;
+ };
+
+ //@Man: Methods/Attributes for maintainance of removed objects
+ //@{
+ ///
+
+ /// create an iterator for removed objects
+ r_Iterator<T> create_removed_iterator();
+
+ ///
+ /// pointer to list of removed elements
+ CNode* removed_objects;
+
+ ///
+ //@}
+
+ //@Man: Attributes storing some state information
+ //@{
+ ///
+ ///
+ int isOrdered;
+ ///
+ int allowsDuplicates;
+ ///
+ unsigned long card;
+ ///
+ //@}
+
+ // Normally, we would have used the following class to implement the
+ // internal structure of a r_Collection. But for RPC's sake, we use
+ // a simple structure. (RPC is not able to transfer C++ objects.)
+ //
+ // template <class T>
+ // class CNode
+ // {
+ // public:
+ // CNode();
+ // CNode( const CNode& cnode );
+ // ~CNode();
+ //
+ // inline CNode* get_next() const;
+ // inline void set_next( const CNode& cnode );
+ // inline T* get_elem() const;
+ // inline void set_elem( const T& element);
+ //
+ // private:
+ // CNode* next;
+ // T* elem;
+ // }
+
+ //@Man: Methods for manipulating CNode lists
+ //@{
+ ///
+
+ ///
+ void add_node( CNode* &root, const T& element );
+ ///
+ int remove_node( CNode* &root, const T& element );
+ ///
+ void remove_all_nodes( CNode* &root );
+ ///
+ void init_node_list( CNode* &root );
+
+ ///
+ //@}
+
+ /// pointer to collection elements
+ CNode* coll;
+};
+
+#include "rasodmg/collection.icc"
+
+#ifdef EARLY_TEMPLATE
+#ifdef __EXECUTABLE__
+#ifdef __VISUALC__
+#include "collection.cpp"
+#else
+#include "collection.cc"
+#endif
+#endif
+#endif
+
+#endif
diff --git a/rasodmg/collection.icc b/rasodmg/collection.icc
new file mode 100644
index 0000000..59b11ab
--- /dev/null
+++ b/rasodmg/collection.icc
@@ -0,0 +1,73 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INLINE SOURCE: collection.icc
+ *
+ * MODULE: rasodmg
+ * CLASS: r_Collection
+ *
+ * COMMENTS:
+ * None
+*/
+
+template<class T>
+inline unsigned long
+r_Collection<T>::cardinality() const
+{
+ return card;
+}
+
+
+template<class T>
+inline int
+r_Collection<T>::is_empty() const
+{
+ if ( coll->elem )
+ return false;
+ else
+ return true;
+}
+
+
+template<class T>
+inline int
+r_Collection<T>::is_ordered() const
+{
+ return isOrdered;
+}
+
+
+template<class T>
+inline int
+r_Collection<T>::allows_duplicates() const
+{
+ return allowsDuplicates;
+}
+
+
+template<class T>
+inline void*
+r_Collection<T>::get_internal_representation() const
+{
+ return (void*)coll;
+}
diff --git a/rasodmg/database.cc b/rasodmg/database.cc
new file mode 100644
index 0000000..bdf11b0
--- /dev/null
+++ b/rasodmg/database.cc
@@ -0,0 +1,475 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: database.cc
+ *
+ * MODULE: rasodmg
+ * CLASS: r_Database
+ *
+ * COMMENTS:
+ * None
+*/
+
+static const char rcsid[] = "@(#)rasodmg, r_Database: $Id: database.cc,v 1.47 2005/09/03 20:39:35 rasdev Exp $";
+
+#ifdef __VISUALC__
+#ifndef __EXECUTABLE__
+#define __EXECUTABLE__
+#define DATABASE_NOT_SET
+#endif
+#endif
+
+#include "rasodmg/database.hh"
+#include "rasodmg/transaction.hh"
+#include "clientcomm/clientcomm.hh"
+
+#ifdef DATABASE_NOT_SET
+#undef __EXECUTABLE__
+#endif
+
+#include <string.h>
+
+// At the beginning, no database is actually opened.
+r_Database* r_Database::actual_database = 0;
+
+
+r_Database::r_Database()
+ : db_status( not_open ),
+ rasmgrName(0),
+ userName(0),
+ plainPass(0),
+ communication(0)
+{
+}
+
+r_Database::r_Database( const char* name ) throw(r_Error)
+ : db_status( not_open ),
+ userName(0),
+ plainPass(0),
+ communication(0)
+{
+ if(!name)
+ {
+ RMInit::logOut << "Error: null database name." << std::endl;
+ throw r_Error(r_Error::r_Error_NameInvalid);
+ }
+ this->rasmgrName = strdup( name );
+}
+
+r_Type*
+r_Database::get_type_schema(const char* typeName, type_schema typeType) throw (r_Error)
+{
+ r_Type* retval = 0;
+
+ if ((typeName == NULL) || (strlen(typeName) == 0))
+ throw r_Error(r_Error::r_Error_NameInvalid);
+ else if ((typeType != COLLECTION ) && (typeType != MARRAY))
+ throw r_Error(r_Error::r_Error_TypeInvalid);
+ else if (r_Database::actual_database != NULL)
+ throw r_Error(r_Error::r_Error_DatabaseClosed);
+ else if (r_Database::actual_database->get_status() != r_Database::not_open)
+ throw r_Error(r_Error::r_Error_DatabaseClosed);
+ else if (r_Transaction::actual_transaction != NULL)
+ throw r_Error(r_Error::r_Error_TransactionNotOpen);
+ else if (r_Transaction::actual_transaction->get_status() == r_Transaction::active)
+ throw r_Error(r_Error::r_Error_TransactionNotOpen);
+ else
+ {
+ ClientComm::r_Type_Type type;
+ if (typeType == COLLECTION)
+ type = ClientComm::r_SetType_Type;
+ else
+ type = ClientComm::r_MDDType_Type;
+ char* temp = r_Database::actual_database->communication->getTypeStructure( typeName, type );
+ retval = r_Type::get_any_type(temp);
+ delete [] temp;
+ temp = 0;
+ }
+ return retval;
+}
+
+r_Database::~r_Database()
+{
+ if( db_status != not_open )
+ close();
+
+ if( rasmgrName )
+ free( rasmgrName );
+ if( userName )
+ free( userName );
+ if( plainPass )
+ free( plainPass );
+}
+
+void
+r_Database::open( const char* database_name, access_status new_status )
+ throw( r_Error )
+{
+ if( db_status != not_open || actual_database )
+ {
+ r_Error err = r_Error(r_Error::r_Error_DatabaseOpen);
+ throw err;
+ }
+
+ if(!database_name)
+ {
+ RMInit::logOut << "r_Database::open(name, new_status) name is null" << std::endl;
+ throw r_Error(r_Error::r_Error_NameInvalid);
+ }
+
+ // While instantiating the communication object, the first connection to
+ // the server is established. Any exception is given through to the caller
+ // of open(...).
+ try
+ {
+ communication = ClientComm::createObject( rasmgrName, rasmgrPort );
+ if( userName && plainPass )
+ communication->setUserIdentification( userName, plainPass );
+ }
+ catch( ... )
+ {
+ if(communication)
+ delete communication;
+ throw; // re-throw the exception (r_Error_HostInvalid, r_Error_ServerInvalid)
+ }
+
+ // open database
+ unsigned int status=0;
+ try
+ {
+ status = communication->openDB( (char*)database_name );
+ }
+ catch( ... )
+ {
+ if(communication)
+ delete communication;
+ throw;
+ }
+
+ if( status )
+ {
+ // translate error values into exceptions
+ r_Error err;
+
+ switch( status )
+ {
+ case 1:
+ err = r_Error( r_Error::r_Error_ClientUnknown );
+ break;
+
+ case 2:
+ err = r_Error( r_Error::r_Error_DatabaseUnknown );
+ break;
+
+ case 3:
+ err = r_Error( r_Error::r_Error_DatabaseOpen );
+ break;
+
+ case 4:
+ err = r_Error( r_Error::r_Error_RpcInterfaceIncompatible );
+ break;
+ case CONNECTIONCLOSED:
+ err = r_Error(CONNECTIONCLOSED);
+ break;
+ default:
+ err = r_Error( r_Error::r_Error_General );
+ }
+
+ if(communication)
+ delete communication;
+
+ throw err;
+ }
+
+ actual_database = this;
+ db_status = new_status;
+}
+
+void
+r_Database::close()
+{
+ if( db_status != not_open )
+ {
+ // if a communication object exists, close and delete it
+ if( communication )
+ {
+ // abort any open TA -- PB 2005-sep-02
+ // This is quite a hack (borrowed from fastscale.cc):
+ // Actual transaction is a pointer to this in a TA.
+ // Since the TA was allocated by the application program
+ // it should be save to use it like this.
+ if (r_Transaction::actual_transaction != 0)
+ { // make _very_ sure we have sequential evaluation -> nested ifs
+ if (r_Transaction::actual_transaction->get_status() == r_Transaction::active)
+ r_Transaction::actual_transaction->abort();
+ }
+
+ communication->closeDB();
+ delete communication;
+ communication = 0;
+ }
+
+ db_status = not_open;
+ actual_database = 0;
+ }
+}
+
+void
+r_Database::create( const char* name ) throw( r_Error )
+{
+ // this operation is not supported through this interface; use rasdl
+ throw( r_Error(803)); // Access denied, no permission
+}
+
+void
+r_Database::destroy( const char* name ) throw( r_Error )
+{
+ // this operation is not supported through this interface; use rasdl
+ throw( r_Error(803)); // Access denied, no permission
+}
+
+
+void
+r_Database::set_servername( const char* name, int port ) throw (r_Error)
+{
+ //We let the name of the function as it is, but it's about the rasmgr name
+
+ if(!name)
+ {
+ RMInit::logOut << "r_Database::set_servername(name, port) name is null" << std::endl;
+ throw r_Error(r_Error::r_Error_NameInvalid);
+ }
+
+ if( rasmgrName)
+ free( rasmgrName );
+
+ rasmgrName = strdup( name );
+ rasmgrPort = port;
+}
+void
+r_Database::set_useridentification( const char* name, const char *plain_pass ) throw(r_Error)
+{
+ if(!name)
+ {
+ RMInit::logOut << "r_Database::set_useridentification(name, plain_pass) name is null" << std::endl;
+ throw r_Error(r_Error::r_Error_NameInvalid);
+ }
+ if(!plain_pass)
+ {
+ RMInit::logOut << "r_Database::set_useridentification(name, plain_pass) plain_pass is null" << std::endl;
+ throw r_Error(r_Error::r_Error_NameInvalid);
+ }
+
+ if (userName)
+ free(userName);
+ if (plainPass)
+ free(plainPass);
+ userName = strdup( name );
+ plainPass = strdup( plain_pass );
+}
+
+void
+r_Database::set_object_name( r_Object &obj, const char* name ) throw(r_Error)
+{
+ obj.set_object_name( name );
+}
+
+r_Ref_Any
+r_Database::lookup_object( const char* name ) const throw( r_Error )
+{
+ r_Ref_Any returnValue;
+
+ if( db_status == not_open )
+ {
+ r_Error err = r_Error( r_Error::r_Error_DatabaseClosed );
+ throw err;
+ }
+
+ if(!name)
+ {
+ RMInit::logOut << "r_Database::lookup_object(name) name is null" << std::endl;
+ throw r_Error(r_Error::r_Error_NameInvalid);
+ }
+
+ if( !r_Transaction::actual_transaction
+ || r_Transaction::actual_transaction->get_status() != r_Transaction::active )
+ {
+ r_Error err = r_Error( r_Error::r_Error_TransactionNotOpen );
+ throw err;
+ }
+
+ try
+ {
+ // get collection
+ returnValue = communication->getCollOIdsByName( name );
+ }
+ catch( ... )
+ {
+ throw; // re-throw the exception
+ }
+
+ return returnValue;
+}
+
+
+
+r_Ref_Any
+r_Database::lookup_object( const r_OId& oid ) const throw( r_Error )
+{
+ r_Ref_Any returnValue;
+
+ if( db_status == not_open )
+ {
+ r_Error err = r_Error( r_Error::r_Error_DatabaseClosed );
+ throw err;
+ }
+
+ if( !r_Transaction::actual_transaction
+ || r_Transaction::actual_transaction->get_status() != r_Transaction::active )
+ {
+ r_Error err = r_Error( r_Error::r_Error_TransactionNotOpen );
+ throw err;
+ }
+
+ try
+ {
+ // determine type of object and get it
+ if( communication->getObjectType( oid ) == 1 )
+ returnValue = communication->getMDDByOId( oid );
+ else
+ returnValue = communication->getCollOIdsByOId( oid );
+ }
+ catch( ... )
+ {
+ throw; // re-throw the exception
+ }
+
+ return returnValue;
+}
+
+
+void
+r_Database::set_transfer_format( r_Data_Format format, const char *formatParams ) throw( r_Error )
+{
+ unsigned short result;
+
+ if ( db_status == not_open )
+ {
+ r_Error err = r_Error( r_Error::r_Error_DatabaseClosed );
+ throw (err);
+ }
+ //keeps from crashing in rpc on linux
+ if (formatParams == 0)
+ formatParams = "";
+ result = communication->setTransferFormat(format, formatParams);
+
+ switch (result)
+ {
+ case 1:
+ {
+ r_Error err = r_Error( r_Error::r_Error_ClientUnknown );
+ throw(err);
+ }
+ break;
+ case 2:
+ {
+ r_Error err = r_Error( r_Error::r_Error_FeatureNotSupported );
+ throw(err);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void
+r_Database::set_storage_format( r_Data_Format format, const char *formatParams ) throw( r_Error )
+{
+ unsigned short result;
+
+ if ( db_status == not_open )
+ {
+ r_Error err( r_Error::r_Error_DatabaseClosed );
+ throw(err);
+ }
+
+ //keeps from crashing in rpc on linux
+ if (formatParams == 0)
+ formatParams = "";
+
+ result = communication->setStorageFormat(format, formatParams);
+
+ switch (result)
+ {
+ case 1:
+ {
+ r_Error err( r_Error::r_Error_ClientUnknown );
+ throw(err);
+ }
+ break;
+ case 2:
+ {
+ r_Error err( r_Error::r_Error_FeatureNotSupported );
+ throw(err);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+
+
+const r_OId
+r_Database::get_new_oid( unsigned short objType ) const throw(r_Error)
+{
+ return communication->getNewOId( objType );
+}
+
+
+void r_Database::insertColl( const char* collName, const char* typeName, const r_OId& oid ) throw( r_Error )
+{
+ communication->insertColl(collName,typeName,oid );
+}
+
+void r_Database::removeObjFromColl( const char* name, const r_OId& oid ) throw ( r_Error )
+{
+ communication->removeObjFromColl(name,oid);
+}
+
+ClientComm* r_Database::getComm()
+{
+ return communication;
+}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/rasodmg/database.hh b/rasodmg/database.hh
new file mode 100644
index 0000000..7491eb0
--- /dev/null
+++ b/rasodmg/database.hh
@@ -0,0 +1,270 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: database.hh
+ *
+ * MODULE: rasodmg
+ * CLASS: r_Database
+ *
+ * COMMENTS:
+ * None
+*/
+
+#ifndef _D_DATABASE_
+#define _D_DATABASE_
+
+#include "raslib/rminit.hh"
+#include "raslib/error.hh"
+#include "rasodmg/object.hh"
+#include "raslib/mddtypes.hh"
+
+// forward declarations
+class r_Object;
+class r_Transaction;
+class ClientComm;
+class r_Ref_Any;
+
+//@ManMemo: Module: {\bf rasodmg}
+
+/*@Doc:
+
+ A database object must be instantiated and opened before
+ starting any transaction which uses the database, and closed
+ after ending these transactions.
+
+*/
+
+class r_Database
+{
+ public:
+ /// possible database states
+ enum access_status { not_open, read_write, read_only, exclusive };
+
+ /// possible types define by symbolic names
+ enum type_schema {
+ CELL = 3,
+ MARRAY = 2,
+ COLLECTION = 1
+ };
+
+ /// default constructor
+ r_Database();
+
+ /// constructor getting the rasmgr name
+ r_Database( const char* name ) throw(r_Error);
+ /**
+ One error situations can occur which raise an exception of type \Ref{r_Error} with
+ one of the following kinds:
+ r_Error_NameInvalid && Name is NULL.\\
+ */
+
+ /// destructor
+ ~r_Database();
+
+ /// open a database
+ void open( const char* database_name, access_status status = read_write )
+ throw( r_Error );
+ /**
+ The method opens the database specified with {\tt database_name}. Several error
+ situations can occur which raise an exception of type \Ref{r_Error} with
+ one of the following kinds:
+
+ \begin{tabular}{lll}
+ r_Error_HostInvalid && Host can not be found.\\
+ r_Error_ServerInvalid && Server can not be found.\\
+ r_Error_ClientUnknown && Client is not known by the server (earlier communication problems).\\
+ r_Error_DatabaseUnknown && Database does not exist.\\
+ r_Error_DatabaseOpen && Database is already open.\\
+ r_Error_TransferFailed && Other communication problem. \\
+ r_Error_NameInvalid && Name is NULL.\\
+ \end{tabular}
+ */
+
+ /// close a database
+ void close();
+
+ /// create a database with fixed schema RasDaSchema
+ void create( const char* name ) throw( r_Error );
+ /**
+ This method works only if a server host name has been specified with
+ {\tt set_servername()}.
+ One of error situations can occur will raise an exception of type \Ref{r_Error} with
+ one of the following kinds:
+ r_Error_NameInvalid && Name is NULL.\\
+ */
+
+ /// destroy a database
+ void destroy( const char* name ) throw( r_Error );
+ /**
+ This method works only if a server host name has been specified with
+ {\tt set_servername()}.
+ One of error situations can occur will raise an exception of type \Ref{r_Error} with
+ one of the following kinds:
+ r_Error_NameInvalid && Name is NULL.\\
+ */
+
+ /// set the server name
+ void set_servername( const char* name, int port = RASMGRPORT) throw(r_Error);
+ /**
+ One of error situations can occur will raise an exception of type \Ref{r_Error} with
+ one of the following kinds:
+ r_Error_NameInvalid && Name is NULL.\\
+ */
+ /// set the user name and password
+ void set_useridentification( const char* name, const char *plain_pass ) throw(r_Error);
+ /**
+ One of error situations can occur will raise an exception of type \Ref{r_Error} with
+ one of the following kinds:
+ r_Error_NameInvalid && Name is NULL.\\
+ */
+
+ /// get the actual status
+ inline access_status get_status() const;
+
+ /// give a name to an object (signature is not ODMG conformant because of compiler bug)
+ void set_object_name( r_Object& obj, const char* name ) throw(r_Error);
+ /**
+ The method gives the {\tt name} to the object {\tt obj}. The name is used for
+ further retrieval of the object. Right now, names can just be given to sets
+ of type {\tt r_Set}.
+ One of error situations can occur will raise an exception of type \Ref{r_Error} with
+ one of the following kinds:
+ r_Error_NameInvalid && Name is NULL.\\
+ */
+
+ /// lookup named objects in a database (must be called within open database and running transaction)
+ r_Ref_Any lookup_object( const char* name ) const
+ throw( r_Error );
+ /**
+ The method looks up an object with {\tt name}. Right now, just objects of type \Ref{r_Set} are
+ allowed. Error kinds:
+
+ \begin{tabular}{lll}
+ r_Error_ClientUnknown && Client is not known by the server (earlier communication problems).\\
+ r_Error_DatabaseClosed && Database is not open. \\
+ r_Error_TransactionNotOpen && No transaction is active. \\
+ r_Error_ObjectUnknown && The object with {\tt name} is not in the database.\\
+ r_Error_TransferFailed && Other communication problem. \\
+ r_Error_NameInvalid && Name is NULL.\\
+ \end{tabular}
+ */
+
+ /// lookup objects by oids in a database (must be called within open database and running transaction)
+ r_Ref_Any lookup_object( const r_OId& oid ) const
+ throw( r_Error );
+ /**
+ The method looks up an object with {\tt oid}. Right now, just objects of type \Ref{r_Set} and
+ \Ref{r_GMarray} are allowed.
+
+ Error kinds:
+ \begin{tabular}{lll}
+ r_Error_ClientUnknown && Client is not known by the server (earlier communication problems).\\
+ r_Error_DatabaseClosed && Database is not open. \\
+ r_Error_TransactionNotOpen && No transaction is active. \\
+ r_Error_ObjectUnknown && The object with {\tt oid} is not in the database.\\
+ r_Error_TransferFailed && Other communication problem. \\
+ \end{tabular}
+ */
+
+ r_Type* get_type_schema(const char* typeName, type_schema typetype) throw (r_Error);
+ /**
+ The method looks up the type structure with {\tt typeName} as its name. typetype is 1 for marray and 2 for collection.
+
+ Error kinds:
+ \begin{tabular}{lll}
+ r_Error_ClientUnknown && Client is not known by the server (earlier communication problems).\\
+ r_Error_DatabaseClosed && Database is not open. \\
+ r_Error_TransactionNotOpen && No transaction is active. \\
+ r_Error_ObjectUnknown && The object with {\tt typeName} is not in the database.\\
+ r_Error_TransferFailed && Other communication problem. \\
+ r_Error_TypeInvalid && The typetype is neither 1 nor 2. \\
+ r_Error_NameInvalid && The typeName is neither NULL or is a "\0". \\
+ \end{tabular}
+ */
+
+
+ /// set the transfer compression format, both for data sent from the server
+ /// to the client and the other way around.
+ void set_transfer_format( r_Data_Format format, const char *formatParams=NULL ) throw( r_Error );
+ /**
+ The method sets the transfer compression used for the communications of
+ this client with the server.
+
+ Error kinds:
+ \begin{tabular}{lll}
+ r_Error_ClientUnknown && Client is not known by the server\\
+ r_Error_DatabaseClosed && Database is not open\\
+ r_Error_FeatureNotSupported && Unsupported transfer format\\
+ \end{tabular}
+ */
+
+ /// set the storage format for newly created MDD for this client
+ void set_storage_format( r_Data_Format format, const char *formatParams=NULL) throw( r_Error );
+ /**
+ This method sets the storage format to use for MDD created by this client
+ in the RasDaMan database. The return values are identical to set_transfer_format()
+ */
+
+ /// stores a pointer to the actually opened database
+ static r_Database* actual_database;
+
+
+ //@Man: Methods for internal use only:
+ //@{
+ ///
+ const r_OId get_new_oid( unsigned short objType ) const throw(r_Error);
+ ///
+ //@}
+
+
+ // creates an empty MDD collection on the server
+ void insertColl( const char* collName, const char* typeName, const r_OId& oid ) throw( r_Error );
+
+ /// removes an object from a collection
+ void removeObjFromColl( const char* name, const r_OId& oid ) throw ( r_Error );
+
+ ClientComm* getComm();
+ private:
+ /// stores a pointer to a communication object, which is valid while a database is opened
+ ClientComm* communication;
+
+ /// database status
+ access_status db_status;
+
+ /// stores the RasMGR name
+ char* rasmgrName;
+
+ /// stores the RasMGR port
+ int rasmgrPort;
+
+ /// stores the user name
+ char* userName;
+
+ /// stores the user password (this will change!)
+ char* plainPass;
+};
+
+#include "rasodmg/database.icc"
+#include "rasodmg/ref.hh"
+
+#endif
diff --git a/rasodmg/database.icc b/rasodmg/database.icc
new file mode 100644
index 0000000..fb75479
--- /dev/null
+++ b/rasodmg/database.icc
@@ -0,0 +1,38 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INLINE SOURCE: database.icc
+ *
+ * MODULE: rasodmg
+ * CLASS: r_Database
+ *
+ * COMMENTS:
+ * None
+*/
+
+inline
+r_Database::access_status
+r_Database::get_status() const
+{
+ return db_status;
+}
diff --git a/rasodmg/dirdecompose.cc b/rasodmg/dirdecompose.cc
new file mode 100644
index 0000000..d00b9b4
--- /dev/null
+++ b/rasodmg/dirdecompose.cc
@@ -0,0 +1,147 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: dirdecomp.cc
+ *
+ * MODULE: rasodmg
+ * CLASS: r_DirDecomp
+ *
+ * COMMENTS:
+ * None
+ *
+*/
+
+#include "rasodmg/dirdecompose.hh"
+#include <string.h>
+
+// Default size of the interval buffer for holding intervals
+const r_Dimension r_Dir_Decompose::DEFAULT_INTERVALS = 5;
+
+r_Dir_Decompose::r_Dir_Decompose()
+: num_intervals(0), current_interval(0), intervals(NULL)
+{
+ num_intervals = r_Dir_Decompose::DEFAULT_INTERVALS;
+ intervals = new r_Range[num_intervals];
+}
+
+r_Dir_Decompose::~r_Dir_Decompose()
+{
+ if ( intervals )
+ {
+ delete [] intervals;
+ intervals = NULL;
+ }
+}
+
+r_Dir_Decompose::r_Dir_Decompose(const r_Dir_Decompose& other)
+: num_intervals(0), current_interval(0), intervals(NULL)
+{
+ num_intervals = other.num_intervals;
+ current_interval = other.current_interval;
+
+ if(other.intervals)
+ {
+ intervals = new r_Range[num_intervals];
+ memcpy(intervals, other.intervals, num_intervals*sizeof(r_Range));
+ }
+}
+
+const r_Dir_Decompose& r_Dir_Decompose::operator=(const r_Dir_Decompose& other)
+{
+ if (this != &other)
+ {
+ delete [] intervals;
+
+ num_intervals = other.num_intervals;
+ current_interval = other.current_interval;
+
+ if(other.intervals)
+ {
+ intervals = new r_Range[num_intervals];
+ memcpy(intervals, other.intervals, num_intervals*sizeof(r_Range));
+ }
+ }
+
+ return *this;
+}
+
+r_Dir_Decompose& r_Dir_Decompose::operator<<(r_Range limit)
+{
+ if (current_interval == num_intervals)
+ {
+ r_Range *aux = new r_Range[num_intervals*2];
+
+ for (int i=0; i<num_intervals; i++)
+ aux[i] = intervals[i];
+
+ delete [] intervals;
+ intervals = aux;
+
+ num_intervals*= 2;
+ }
+
+ intervals[current_interval++] = limit;
+
+ return *this;
+}
+
+int r_Dir_Decompose::get_num_intervals() const
+{
+ return current_interval;
+}
+
+r_Range r_Dir_Decompose::get_partition(int number) const
+ throw (r_Eindex_violation)
+{
+ if (number >= current_interval)
+ {
+ r_Eindex_violation err(0, current_interval, number);
+ throw err;
+ }
+
+ return intervals[number];
+}
+
+void r_Dir_Decompose::print_status(std::ostream& os) const
+{
+ os << "r_Dir_Decompose[ num intervals = " << num_intervals << " current interval = " << current_interval << " intervals = {";
+
+ for (int i=0; i<current_interval; i++)
+ os << intervals[i] << " ";
+
+ os << "} ]";
+}
+
+std::ostream& operator<<(std::ostream& os, const r_Dir_Decompose& d)
+{
+ d.print_status(os);
+
+ return os;
+}
+
+r_Sinterval
+r_Dir_Decompose::get_total_interval( )
+{
+ return r_Sinterval( intervals[0], intervals[current_interval - 1]);
+}
+
diff --git a/rasodmg/dirdecompose.hh b/rasodmg/dirdecompose.hh
new file mode 100644
index 0000000..c183fd0
--- /dev/null
+++ b/rasodmg/dirdecompose.hh
@@ -0,0 +1,114 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: dirdecomp.hh
+ *
+ * MODULE: rasodmg
+ * CLASS: r_Dir_Decompose
+ *
+ * COMMENTS:
+ * None
+*/
+
+#ifndef _R_DIRDECOMPOSE_HH_
+#define _R_DIRDECOMPOSE_HH_
+
+// Include statements
+
+#include <iostream>
+using std::cout;
+
+#include "raslib/error.hh"
+#include "raslib/sinterval.hh"
+
+//@ManMemo: Module {\bf rasodmg}
+
+/*@Doc:
+
+ The {\tt r_Dir_Decompose} class is used to specify a decomposition on
+ an n-dimensional cube (for use in {\tt r_Dir_Tiling}). For instance, to
+ specify a tiling restriction on a dimension with the form: [0, 2, 4, 5],
+ the following code would apply:
+
+ r_Dir_Decompose decomp;
+
+ decomp << 0 << 2 << 4 << 5;
+
+ Note that the first and the last elements input into the object must be
+ the origin and limit of that dimension or else a cross-section of the domain
+ will occur (as if the elements outside the specification wouldn't mind).
+
+ If one dimension is considered to be a prefered access direction, then
+ the r_Dir_Decompose should be empty, this is, no restriction should be
+ entered.
+*/
+
+class r_Dir_Decompose
+{
+ public:
+
+ r_Dir_Decompose();
+
+ virtual ~r_Dir_Decompose();
+
+ /// Copy constructor
+ r_Dir_Decompose(const r_Dir_Decompose& other);
+
+ /// Assigment operator
+ const r_Dir_Decompose& operator=(const r_Dir_Decompose& other);
+
+ /// Reads a new limit for the current dimension
+ r_Dir_Decompose& operator<<(r_Range limit);
+
+ /// Gets the number of intervals the dimension is to be split into
+ int get_num_intervals() const;
+
+ /// Gets a restriction
+ r_Range get_partition(int number) const throw (r_Eindex_violation);
+
+ /// Prints the current status of the object
+ virtual void print_status(std::ostream& os = cout ) const;
+
+protected:
+ r_Sinterval get_total_interval( );
+
+ /// Initial number of intervals of the buffer
+ const static r_Dimension DEFAULT_INTERVALS;
+
+ /// The number of intervals that this object can currently suport
+ r_Dimension num_intervals;
+
+ /// The current interval that is being used for input
+ r_Dimension current_interval;
+
+ /// The buffer that holds the information
+ r_Range* intervals;
+};
+
+//@ManMemo: Module: {\bf rasodmg}
+/**
+ Prints the status of an r_Dir_Decompose object to a stream
+*/
+extern std::ostream& operator<<(std::ostream& os, const r_Dir_Decompose& d);
+
+#endif
diff --git a/rasodmg/dirtiling.cc b/rasodmg/dirtiling.cc
new file mode 100644
index 0000000..f0bf682
--- /dev/null
+++ b/rasodmg/dirtiling.cc
@@ -0,0 +1,682 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: dirtiling.cc
+ *
+ * MODULE: rasodmg
+ * CLASS: r_DirTiling
+ *
+ * COMMENTS:
+ * None
+*/
+
+#ifdef __VISUALC__
+// Diable warning for signed/unsigned mismatch.
+#pragma warning( disable : 4018 )
+#endif
+
+#include "rasodmg/dirtiling.hh"
+#include "rasodmg/dirdecompose.hh"
+#include "rasodmg/alignedtiling.hh"
+#include "raslib/rminit.hh"
+
+#include <assert.h>
+#include <string.h>
+#include <math.h>
+#include <cstdlib>
+
+#ifdef AIX
+#include <strings.h>
+#endif
+
+// Uncoment the _VISUALIZE_2D_DECOMP_ line to generate ppm files the
+// visualization of the domain decomposition done by the algoritm
+// #define _VISUALIZE_2D_DECOMP_
+
+// Uncoment the folling line for some debug printfs on this class
+// #define _DEBUG_DIRTILING_
+
+#ifdef _DEBUG_DIRTILING_
+#define DEBUG_DIR(msg) cout << "[" << __LINE__ << "] " << msg;
+#else
+#define DEBUG_DIR(msg)
+#endif
+
+
+#ifdef _VISUALIZE_2D_DECOMP_
+#include "tools/visualtiling2d.hh"
+#endif
+
+const char*
+r_Dir_Tiling::description = "dimensions, decomposision patterns, tile size(in bytes) and subtiling [SUBTILING|NOSUBTILING] (ex: \"3;[0,2,4,5],[*],[0,10,15];100;NOSUBTILING\")";
+
+const char* r_Dir_Tiling::subtiling_name_withoutsubtiling = "NOSUBTILING";
+const char* r_Dir_Tiling::subtiling_name_withsubtiling = "SUBTILING";
+const char* r_Dir_Tiling::all_subtiling_names[r_Dir_Tiling::NUMBER]={
+ subtiling_name_withoutsubtiling,
+ subtiling_name_withsubtiling
+ };
+
+r_Dir_Tiling::SubTiling
+r_Dir_Tiling::get_subtiling_from_name(const char* name)
+{
+ if(!name) {
+ RMInit::logOut << "r_Dir_Tiling::get_subtiling_from_name(" << (name?name:"NULL") << ")." << endl;
+ return r_Dir_Tiling::NUMBER;
+ }
+
+ unsigned int i=r_Dir_Tiling::NUMBER;
+
+ for (i=0; i<(unsigned int)r_Dir_Tiling::NUMBER; i++)
+ {
+ if (strcasecmp(name, all_subtiling_names[i]) == 0)
+ break;
+ }
+
+ return (r_Dir_Tiling::SubTiling)i;
+}
+
+const char*
+r_Dir_Tiling::get_name_from_subtiling(SubTiling tsl)
+{
+ static const char* unknown="UNKNOWN";
+ unsigned int idx = (unsigned int)tsl;
+
+ if (idx >= (unsigned int)r_Dir_Tiling::NUMBER)
+ return unknown;
+
+ return all_subtiling_names[idx];
+}
+
+r_Dir_Tiling::r_Dir_Tiling(const char* encoded) throw (r_Error)
+ : r_Dimension_Tiling(0, 0)
+{
+ if(!encoded)
+ {
+ RMInit::logOut << "r_Dir_Tiling::r_Dir_Tiling(" << (encoded?encoded: "NULL") << ")." << endl;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+
+ r_Dimension tileD=0, dirIndex=0;
+ r_Range decomp=0;
+ std::vector<r_Dir_Decompose> vectDirDecomp;
+ r_Bytes tileS=0, lenToConvert=0, lenDirToConvert=0, lenDecomp=0;
+ r_Dir_Tiling::SubTiling subTiling;
+ const char *pStart=NULL, *pEnd=NULL, *pRes=NULL, *pTemp=NULL, *pToConvertEnd=NULL;
+ char* pToConvert=NULL;
+ const char *pDirRes=NULL, *pDirEnd=NULL, *pDirTemp=NULL, *pDirStart=NULL;
+ char* pDirToConvert=NULL;
+ char* pDecomp=NULL;
+
+ //initialisation
+ pStart=encoded;
+ pTemp=pStart;
+ pEnd=pTemp+strlen(pStart);
+
+ //deal with dimension
+ pRes=strstr(pTemp, COLON);
+ if(!pRes)
+ {
+ RMInit::logOut << "r_Dir_Tiling::r_Dir_Tiling(" << encoded << "): Error decoding tile dimension." << endl;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+
+ lenToConvert=pRes-pTemp;
+ pToConvert=new char[lenToConvert+1];
+ memcpy(pToConvert, pTemp, lenToConvert);
+ pToConvert[lenToConvert]='\0';
+
+ tileD=strtol(pToConvert, (char**)NULL, DefaultBase);
+ if(!tileD)
+ {
+ RMInit::logOut << "r_Dir_Tiling::r_Dir_Tiling(" << encoded << "): Error decoding tile dimension \"" << pToConvert << "\" is not a number." << endl;
+ delete[] pToConvert;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+ if(tileD<0)
+ {
+ RMInit::logOut << "r_Dir_Tiling::r_Dir_Tiling(" << encoded << "): Error decoding tile dimension \"" << pToConvert << "\" is negative." << endl;
+ delete[] pToConvert;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+
+ vectDirDecomp=std::vector<r_Dir_Decompose>(tileD);
+
+ delete[] pToConvert;
+ if(pRes==(pEnd-1))
+ {
+ RMInit::logOut << "r_Dir_Tiling::r_Dir_Tiling(" << encoded << "): Error decoding directional decompose, end of stream." << endl;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+ else
+ pRes++;
+ pTemp=pRes;
+
+ //deal with directional decompose
+ pRes=strstr(pTemp, COLON);
+ if(!pRes)
+ {
+ RMInit::logOut << "r_Dir_Tiling::r_Dir_Tiling(" << encoded << "): Error decoding directional decompose." << endl;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+
+ lenToConvert=pRes-pTemp;
+ pToConvert=new char[lenToConvert+1];
+ memcpy(pToConvert, pTemp, lenToConvert);
+ pToConvert[lenToConvert]='\0';
+ pToConvertEnd=pToConvert+strlen(pToConvert);
+ pDirTemp=pToConvert;
+
+ while(dirIndex < tileD)
+ {
+ pDirRes=strstr(pDirTemp, LSQRBRA);
+ if(!pDirRes)
+ {
+ RMInit::logOut << "r_Dir_Tiling::r_Dir_Tiling(" << encoded << "): Error decoding directional decompose for dimension " << dirIndex+1 << " from \"" << pToConvert << "\"." << endl;
+ delete[] pToConvert;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+ pDirStart=pDirRes;
+ pDirRes=strstr(pDirTemp, RSQRBRA);
+ if(!pDirRes)
+ {
+ RMInit::logOut << "r_Dir_Tiling::r_Dir_Tiling(" << encoded << "): Error decoding directional decompose for dimension " << dirIndex+1 << " from \"" << pToConvert << "\"." << endl;
+ delete[] pToConvert;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+ pDirEnd=pDirRes;
+
+ lenDirToConvert=pDirEnd-pDirStart;
+ if(lenDirToConvert == 1)
+ {
+ RMInit::logOut << "r_Dir_Tiling::r_Dir_Tiling(" << encoded << "): Error decoding directional decompose for dimension " << dirIndex+1 << " from \"" << pToConvert << "\"." << endl;
+ delete[] pToConvert;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+
+ pDirToConvert=new char[lenDirToConvert];
+ memcpy(pDirToConvert, pDirStart+1, lenDirToConvert-1);
+ pDirToConvert[lenDirToConvert-1]='\0';
+ pDirTemp=pDirToConvert;
+ pDirStart=pDirEnd;
+ pDirEnd=pDirToConvert+strlen(pDirToConvert);
+
+ if(*pDirToConvert != *ASTERIX)
+ {
+ pDirRes=strstr(pDirToConvert, COMMA);
+ if(!pDirRes)
+ {
+ RMInit::logOut << "r_Dir_Tiling::r_Dir_Tiling(" << encoded << "): Error decoding directional decompose for dimension " << dirIndex+1 << " from \"" << pToConvert << "\"." << endl;
+ delete[] pDirToConvert;
+ delete[] pToConvert;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+ while(pDirRes)
+ {
+ lenDecomp=pDirRes-pDirTemp;
+ pDecomp=new char[lenDecomp+1];
+ memcpy(pDecomp, pDirTemp, lenDecomp);
+ pDecomp[lenDecomp]='\0';
+
+ decomp=strtoul(pDecomp, (char**)&pDirTemp, DefaultBase);
+
+ if(*pDirTemp !='\0')
+ {
+ RMInit::logOut << "r_Dir_Tiling::r_Dir_Tiling(" << encoded << "): Error decoding decompose \"" << pDecomp << "\" from directional decompose \"" << pDirToConvert << "\", is not a number." << endl;
+ delete[] pDecomp;
+ delete[] pDirToConvert;
+ delete[] pToConvert;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+
+ vectDirDecomp[dirIndex] << decomp;
+
+ //skip COMMA & free buffer
+ delete[] pDecomp;
+ if(pDirRes==(pDirEnd-1))
+ {
+ RMInit::logOut << "r_Dir_Tiling::r_Dir_Tiling(" << encoded << "): Error decoding directional decompose \"" << pDirToConvert << "\", end of stream." << endl;
+ delete[] pDirToConvert;
+ delete[] pToConvert;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+ else
+ pDirRes++;
+ pDirTemp=pDirRes;
+
+ //next decomp
+ pDirRes=strstr(pDirTemp, COMMA);
+ if(!pDirRes)
+ {
+ decomp=strtoul(pDirTemp, (char**)&pDirRes, DefaultBase);
+ if(*pDirRes !='\0')
+ {
+ RMInit::logOut << "r_Dir_Tiling::r_Dir_Tiling(" << encoded << "): Error decoding decompose \"" << pDirTemp << "\" from directional decompose \"" << pDirToConvert << "\", is not a number." << endl;
+ delete[] pDirToConvert;
+ delete[] pToConvert;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+ vectDirDecomp[dirIndex]<<decomp;
+ break;
+ }//end if
+ }//end while
+ } //end if
+
+ delete[] pDirToConvert;
+ dirIndex++;
+ if(dirIndex < tileD)
+ {
+ if(pDirStart == (pToConvertEnd-1))
+ {
+ RMInit::logOut << "r_Dir_Tiling::r_Dir_Tiling(" << encoded << "): Error decoding directional decompose for dimension " << dirIndex << " from \"" << pToConvert << "\", end of stream." << endl;
+ delete[] pToConvert;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+ else
+ pDirStart++;
+
+ pDirRes=strstr(pDirStart, COMMA);
+ if(!pDirRes)
+ {
+ RMInit::logOut << "r_Dir_Tiling::r_Dir_Tiling(" << encoded << "): Error decoding directional decompose for dimension " << dirIndex+1 << " from \"" << pToConvert << "\", end of stream." << endl;
+ delete[] pToConvert;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+
+ if(pDirRes == (pToConvertEnd-1))
+ {
+ RMInit::logOut << "r_Dir_Tiling::r_Dir_Tiling(" << encoded << "): Error decoding directional decompose for dimension " << dirIndex << " from \"" << pToConvert << "\", end of stream." << endl;
+ delete[] pToConvert;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+ else
+ pDirRes++;
+
+ pDirTemp=pDirRes;
+ }//end if(dirIndex<tileD)
+ }//end while
+
+ //skip COLON & free buffer
+ delete[] pToConvert;
+ if(pRes==(pEnd-1))
+ {
+ RMInit::logOut << "r_Dir_Tiling::r_Dir_Tiling(" << encoded << "): Error decoding tile size from \"" << pStart << "\", end of stream." << endl;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+ else
+ pRes++;
+ pTemp=pRes;
+
+ //deal with tilesize
+ pRes=strstr(pTemp, COLON);
+ if(!pRes)
+ {
+ RMInit::logOut << "r_Dir_Tiling::r_Dir_Tiling(" << encoded << "): Error decoding tile size from \"" << pTemp << "\", end of stream." << endl;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+
+ lenToConvert=pRes-pTemp;
+ pToConvert=new char[lenToConvert+1];
+ memcpy(pToConvert, pTemp, lenToConvert);
+ pToConvert[lenToConvert]='\0';
+
+ tileS=strtol(pToConvert, (char**)NULL, DefaultBase);
+
+ if(!tileS)
+ {
+ RMInit::logOut << "r_Dir_Tiling::r_Dir_Tiling(" << encoded << "): Error decoding tile size from \"" << pToConvert << "\", is not a number." << endl;
+ delete[] pToConvert;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+ if(tileS<0)
+ {
+ RMInit::logOut << "r_Dir_Tiling::r_Dir_Tiling(" << encoded << "): Error decoding tile size from \"" << pToConvert << "\", is negative." << endl;
+ delete[] pToConvert;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+
+ //skip COLON & free buffer
+ delete[] pToConvert;
+ if(pRes==(pEnd-1))
+ {
+ RMInit::logOut << "r_Dir_Tiling::r_Dir_Tiling(" << encoded << "): Error decoding subtiling from \"" << pStart << "\", end of stream." << endl;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+ else
+ pRes++;
+ pTemp=pRes;
+ //deal with subtilig
+ subTiling=r_Dir_Tiling::get_subtiling_from_name(pTemp);
+ if(subTiling==r_Dir_Tiling::NUMBER)
+ {
+ RMInit::logOut << "r_Dir_Tiling::r_Dir_Tiling(" << encoded << "): Error decoding subtiling from \"" << pTemp << "\"." << endl;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+ dimension = tileD;
+ dim_decomp = vectDirDecomp;
+ sub_tile = subTiling;
+ tile_size = tileS;
+}
+
+r_Dir_Tiling::r_Dir_Tiling(r_Dimension dims, const std::vector<r_Dir_Decompose>& decomp, r_Bytes ts, SubTiling sub) throw (r_Error)
+ : r_Dimension_Tiling(dims, ts),
+ dim_decomp(decomp),
+ sub_tile(sub)
+{
+ if (dim_decomp.size() != dimension)
+ {
+ RMInit::logOut << "r_Dir_Tiling::r_Dir_Tiling(" << dims << ", " << decomp << ", " << ts << ", " << sub << ") number of dimensions (" << dimension << ") does not match number of decomposition entries (" << decomp.size() << ")" << endl;
+ throw r_Edim_mismatch(dimension, dim_decomp.size());
+ }
+}
+
+r_Dir_Tiling::~r_Dir_Tiling()
+{
+}
+
+r_Tiling_Scheme
+r_Dir_Tiling::get_tiling_scheme() const
+{
+ return r_DirectionalTiling;
+}
+
+r_Tiling* r_Dir_Tiling::clone() const
+{
+ r_Tiling* copy = new r_Dir_Tiling(dimension, dim_decomp, tile_size, sub_tile);
+ return copy;
+}
+
+void r_Dir_Tiling::print_status(std::ostream& os) const
+{
+ os << "r_Dir_Tiling[ ";
+ r_Dimension_Tiling::print_status(os);
+ os << " sub tiling = " << sub_tile << " decompose = { ";
+
+ for (r_Dimension i = 0; i < dim_decomp.size(); i++)
+ os << "dim #" << i << " : " << dim_decomp[i] << " ";
+ os << "} ";
+
+}
+
+std::vector<r_Minterval>*
+r_Dir_Tiling::compute_tiles(const r_Minterval& domain, r_Bytes typelen) const throw (r_Error)
+{
+ // Aux variable
+ r_Dimension i = 0;
+ // The result
+ std::vector<r_Minterval>* decomp_result = new std::vector<r_Minterval>();
+ // An alias to result
+ std::vector<r_Minterval>& result = *decomp_result;
+ std::vector<r_Dir_Decompose> temp_dim_decomp = dim_decomp;
+
+
+ // Check dims
+ if (dimension != domain.dimension())
+ {
+
+ delete decomp_result;
+
+ RMInit::logOut << "r_Dir_Tiling::compute_tiles(" << domain << ", " << typelen << ") dimensions of domain (" << domain.dimension() << ") do not match dimensions of tiling strategy (" << dimension << ")" << endl;
+ throw r_Edim_mismatch(dimension, domain.dimension());
+ }
+
+ // Undefined dims
+ bool* undef_dim = new bool[dimension];
+ // Count of undef dims
+ r_Dimension total_undef = 0;
+
+ // Check if limits ok
+ for (i = 0; i < dimension; i++)
+ {
+ // Restric defined
+ if (temp_dim_decomp[i].get_num_intervals() > 0)
+ {
+ undef_dim[i] = false;
+ r_Range lim1 = 0;
+ r_Range lim2 = 0;
+
+ lim1 = domain[i].high();
+ lim2 = temp_dim_decomp[i].get_partition(temp_dim_decomp[i].get_num_intervals() - 1);
+ if (lim1 != lim2)
+ {
+ delete[] undef_dim;
+ delete decomp_result;
+
+ RMInit::logOut << "r_Dir_Tiling::compute_tiles(" << domain << ", " << typelen << ") upper limit of domain (" << domain.dimension() << ") at dimension " << i << " (" << domain[i] << ") does not partition " << temp_dim_decomp[i].get_partition(temp_dim_decomp[i].get_num_intervals() - 1) << endl;
+ throw r_Elimits_mismatch(lim1, lim2);
+ }
+
+ lim1 = domain[i].low();
+ lim2 = temp_dim_decomp[i].get_partition(0);
+ if (lim1 != lim2)
+ {
+ delete[] undef_dim;
+ delete decomp_result;
+
+ RMInit::logOut << "r_Dir_Tiling::compute_tiles(" << domain << ", " << typelen << ") lower limit of domain (" << domain.dimension() << ") at dimension " << i << " (" << domain[i] << ") does not partition " << temp_dim_decomp[i].get_partition(0) << endl;
+ throw r_Elimits_mismatch(lim1, lim2);
+ }
+ }
+ else // Restric not defined
+ {
+ // Dim unspecified
+ undef_dim[i] = true;
+ total_undef++;
+ temp_dim_decomp[i] << domain[i].low() << domain[i].high();
+ }
+ }
+
+ // Create a counter for each dimension
+ r_Dimension* dim_counter = new r_Dimension[dimension];
+ memset(dim_counter, 0, sizeof(r_Dimension) * dimension);
+
+#ifdef _VISUALIZE_2D_DECOMP_
+ // User wants a visual of the 2D decomp.
+ // Number of times a decomp has been made
+ static int count;
+ ++count; // Update decomp count
+
+ Visual_Tiling_2D* vis;
+ if (dimension == 2)
+ {
+ // Create an object for visualization
+ char fname[80];
+ sprintf(fname, "2D_decomp_dir_%d.ppm", count);
+ vis = new Visual_Tiling_2D(domain, fname);
+ }
+#endif
+
+ // Iterate over the all space
+
+ bool done = false;
+ while (!done)
+ {
+ // Determine tile coordinates
+
+ r_Minterval tile(dimension);
+
+ for (i = 0; i < dimension; i++)
+ {
+ r_Range origin = temp_dim_decomp[i].get_partition(dim_counter[i]);
+ if (dim_counter[i] != 0)
+ origin++;
+
+ r_Range limit = temp_dim_decomp[i].get_partition(dim_counter[i]+1);
+
+ tile << r_Sinterval(origin, limit);
+ }
+
+ // Do something with tile coordinates (decompose big object)
+
+#ifdef _DEBUG_DIRTILING_
+ cout << "(DirTiling::compute_tiles(): Tile: " << tile << endl;
+#endif
+
+ // Check if sub-tiling should be done and calculate edgesize
+
+ if ((tile.cell_count() * typelen > tile_size) && (sub_tile == WITH_SUBTILING))
+ {
+ // Create a specification for the partition
+
+ r_Minterval partition(dimension);
+
+ if (total_undef == 0)
+ {
+ // No unspecified dimensions --- create block cross sections
+
+ for (i=0; i<dimension; i++)
+ partition << r_Sinterval((r_Range) 0, tile[i].high()-tile[i].low());
+ }
+ else
+ {
+ // Some unspecified dimensions
+
+ // Compute edgesize
+ r_Range edgesize = tile_size;
+
+ for (i = 0; i < dimension; i++)
+ {
+ if (!undef_dim[i])
+ edgesize/= (tile[i].high()-tile[i].low()+1) * typelen;
+ }
+
+ edgesize = floor(pow(((double)edgesize)/((double)typelen), (1.0/((double)total_undef))));
+
+ // Create specification
+
+ for (i = 0; i < dimension; i++)
+ {
+ if (undef_dim[i])
+ partition << r_Sinterval((r_Range) 0, (edgesize-1));
+ else
+ partition << r_Sinterval((r_Range) 0, tile[i].high()-tile[i].low());
+ }
+ }
+
+#ifdef _DEBUG_DIRTILING_
+ cout << "(DirTiling::compute_tiles(): Tile size = " << get_tile_size()
+ << " Specs = " << partition << endl;
+#endif
+
+ // Create subtiles and insert them in the result
+
+ r_Aligned_Tiling subtiling(partition, get_tile_size());
+ std::vector<r_Minterval>* subtiles = subtiling.compute_tiles(tile, typelen);
+ std::vector<r_Minterval>::iterator it = subtiles->begin();
+ for (; it != subtiles->end(); it++)
+ {
+ result.push_back(*it);
+
+#ifdef _VISUALIZE_2D_DECOMP_ // If we are visualizing
+ if (domain.dimension() == 2)
+ {
+ vis->set_pen(0, 255, 0);
+ if (dimension == 2)
+ (*vis) << (*it);
+ }
+#endif
+ }
+ delete subtiles;
+ }
+ else
+ result.push_back(tile);
+
+#ifdef _VISUALIZE_2D_DECOMP_ // If we are visualizing
+ if (domain.dimension() == 2)
+ {
+ vis->set_pen(255, 255, 0);
+ if (dimension == 2)
+ (*vis) << tile;
+ }
+#endif
+
+ // Update dimension counters
+
+ for (i=0; i < dimension; i++)
+ {
+ dim_counter[i]++;
+ if (dim_counter[i] == (temp_dim_decomp[i].get_num_intervals()-1))
+ dim_counter[i] = 0;
+ else
+ break;
+ }
+
+ // See if we are done
+ done = 1;
+ for (i=0; i<dimension; i++)
+ if (dim_counter[i] != 0)
+ {
+ done = 0;
+ break;
+ }
+ }
+
+ delete [] dim_counter;
+
+#ifdef _VISUALIZE_2D_DECOMP_
+ if (dimension == 2)
+ delete vis;
+#endif
+
+ delete [] undef_dim;
+ return &result;
+}
+
+bool
+r_Dir_Tiling::is_compatible(const r_Minterval& domain, r_Bytes type_len) const
+{
+ bool retval = true;
+ if (!r_Dimension_Tiling::is_compatible(domain, type_len))
+ retval = false;
+ else {
+
+ // Aux variable
+ r_Dimension i = 0;
+
+ for (i = 0; i < dimension; i++) // Check if limits ok
+ {
+ if (dim_decomp[i].get_num_intervals() > 0) // Restric defined
+ {
+ r_Range lim1, lim2;
+
+ lim1 = domain[i].high();
+ lim2 = dim_decomp[i].get_partition(dim_decomp[i].get_num_intervals()-1);
+ if (lim1 != lim2)
+ {
+ retval = false;
+ break;
+ }
+
+ lim1 = domain[i].low();
+ lim2 = dim_decomp[i].get_partition(0);
+ if (lim1 != lim2)
+ {
+ retval = false;
+ break;
+ }
+ }
+ }
+ }
+ return retval;
+}
+
diff --git a/rasodmg/dirtiling.hh b/rasodmg/dirtiling.hh
new file mode 100644
index 0000000..9495571
--- /dev/null
+++ b/rasodmg/dirtiling.hh
@@ -0,0 +1,133 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: dirtiling.hh
+ *
+ * MODULE: rasodmg
+ * CLASS: r_Dir_Tiling
+ *
+ * COMMENTS:
+ * None
+*/
+
+#ifndef _R_DIRTILING_HH_
+#define _R_DIRTILING_HH_
+
+// Include statements
+class r_Dir_Decompose;
+class r_Dir_Tiling;
+
+#include "rasodmg/tiling.hh"
+
+// Class definition
+
+//@ManMemo: Module: {\bf rasodmg}
+
+/*@Doc:
+ This class implements the "Directional Tiling" tiling method. In this
+ method the decomposition is done along certain directions of the
+ multi-dimensional cube. The user uses {\tt r_Dir_Decompose} to inform
+ the system on how the decomposition is done in each dimension.
+*/
+
+class r_Dir_Tiling : public r_Dimension_Tiling
+{
+ // ******************* PUBLIC SECTION *******************
+
+ public:
+
+ /// Constants that specify if subtiling will occur inside the blocks
+ enum SubTiling {
+ WITHOUT_SUBTILING = 0,
+ WITH_SUBTILING = 1,
+ NUMBER = 2
+ };
+ /// read everything from encoded string
+ /// e.g. "3;[0,2,4,5],[*],[0,10,15];100;NOSUBTILING"
+ r_Dir_Tiling(const char* encoded) throw (r_Error);
+
+ /// Class constructor
+ r_Dir_Tiling(r_Dimension dims,
+ const std::vector<r_Dir_Decompose>& decomp,
+ r_Bytes ts = RMInit::clientTileSize,
+ SubTiling sub = WITH_SUBTILING) throw (r_Error);
+ /**
+ The user has to give the number of dimensions of the space and the
+ decomposition wanted for that space. Note that the number of elements of
+ decomp must be the same as the number of dimensions of the space.
+ See {\tt r_Dir_Decompose} for details on how to indicate a decomposition.
+ SubTiling indicates if subtiling should occur inside the blocks specified
+ by the user.
+ Throws an exception when the decomp.size is not equal to the specified
+ dimension.
+ */
+
+ virtual ~r_Dir_Tiling();
+
+ virtual std::vector<r_Minterval>* compute_tiles(const r_Minterval& obj_domain, r_Bytes cell_size) const throw (r_Error);
+
+ virtual bool is_compatible(const r_Minterval& obj_domain, r_Bytes type_len) const;
+
+ virtual void print_status(std::ostream& os) const;
+
+ virtual r_Tiling* clone() const;
+
+ virtual r_Tiling_Scheme get_tiling_scheme() const;
+
+ //@ManMemo: Module: {\bf raslib}
+ /**
+ Get a tilesize limit for a tilisize limit name
+ */
+ static r_Dir_Tiling::SubTiling get_subtiling_from_name(const char* name);
+ //@ManMemo: Module: {\bf raslib}
+ /**
+ Get a tilisize limit name for a tilesize limit
+ */
+ static const char* get_name_from_subtiling(SubTiling st);
+
+ static const char* description;
+
+ protected: // data
+
+ /// The decomposition to be used
+ std::vector<r_Dir_Decompose> dim_decomp;
+
+ /// If sub-tiling should occour
+ SubTiling sub_tile;
+
+ //@ManMemo: Module: {\bf raslib}
+ /**
+ The names of all subtiling types, to avoid redundant storage and inconsistencies.
+ The variable name convention is the prefix subtiling_name_ followed by the name
+ of the data format in lower case, i.e. for WITH_SUBTILING subtiling_name_withsubtiling.
+ In addition there's an array of names all_subtiling_names where the subtiling
+ can be used as index to get the name.
+ */
+ static const char* subtiling_name_withoutsubtiling;
+ static const char* subtiling_name_withsubtiling;
+
+ static const char* all_subtiling_names[r_Dir_Tiling::NUMBER];
+};
+
+#endif
+
diff --git a/rasodmg/gmarray.cc b/rasodmg/gmarray.cc
new file mode 100644
index 0000000..89fa919
--- /dev/null
+++ b/rasodmg/gmarray.cc
@@ -0,0 +1,484 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: gmarray.cc
+ *
+ * MODULE: rasodmg
+ * CLASS: r_GMarray
+ *
+ * COMMENTS:
+ * None
+*/
+
+static const char rcsidgarray[] = "@(#)rasodmg, r_GMarray: $Id: gmarray.cc,v 1.45 2003/12/27 23:02:56 rasdev Exp $";
+
+#include <vector>
+
+#ifdef __VISUALC__
+#ifndef __EXECUTABLE__
+#define __EXECUTABLE__
+#define GMARRAY_NOT_SET
+#endif
+#endif
+
+#include "rasodmg/marray.hh"
+#include "rasodmg/database.hh"
+#include "rasodmg/storagelayout.hh"
+#include "rasodmg/alignedtiling.hh"
+#include "clientcomm/clientcomm.hh"
+
+#ifdef GMARRAY_NOT_SET
+#undef __EXECUTABLE__
+#endif
+
+#include "raslib/rmdebug.hh"
+#include "raslib/type.hh"
+#include "raslib/marraytype.hh"
+#include "raslib/structuretype.hh"
+
+#include <string.h> // for memcpy()
+#include <iostream>
+#include <iomanip>
+
+
+
+r_GMarray::r_GMarray() throw(r_Error)
+ : r_Object(1),
+ data(0),
+ data_size(0),
+ type_length(0),
+ current_format(r_Array),
+ storage_layout(0)
+{
+ storage_layout = new r_Storage_Layout();
+}
+
+
+
+r_GMarray::r_GMarray(const r_Minterval& initDomain, r_Bytes initLength, r_Storage_Layout* stl) throw (r_Error)
+ : r_Object(1),
+ data(0),
+ data_size(0),
+ domain(initDomain),
+ type_length(initLength),
+ current_format(r_Array),
+ storage_layout(stl)
+{
+ int error = 0;
+ if (domain.dimension() == 0)
+ {
+ error = 1;
+ }
+ else {
+ if (storage_layout == NULL)
+ {
+ storage_layout = new r_Storage_Layout(new r_Aligned_Tiling(initDomain.dimension()));
+ }
+ if (!storage_layout->is_compatible(initDomain, initLength))
+ {
+ error = 2;
+ }
+ }
+ if (error != 0)
+ {
+ RMInit::logOut << "r_GMarray::r_GMarray(" << initDomain << ", " << initLength << ", ";
+ if (storage_layout == NULL)
+ RMInit::logOut << "no storage layout";
+ else
+ RMInit::logOut << *storage_layout;
+ RMInit::logOut << ") ";
+ if (error == 1)
+ {
+ RMInit::logOut << "domain is not initialised";
+ throw r_Error(DOMAINUNINITIALISED);
+ }
+ else {
+ RMInit::logOut << "storage layout is not compatible";
+ throw r_Error(STORAGERLAYOUTINCOMPATIBLEWITHGMARRAY);
+ }
+ }
+ data_size = domain.cell_count() * initLength;
+ data = new char[ data_size ];
+ memset(data, 0, data_size);
+}
+
+
+
+r_GMarray::r_GMarray(const r_GMarray &obj) throw(r_Error)
+ : r_Object(obj, 1),
+ data(0),
+ data_size(0),
+ domain(obj.spatial_domain()),
+ type_length(obj.type_length),
+ current_format(obj.current_format),
+ storage_layout(0)
+{
+ RMDBCLASS("r_GMarray", "r_GMarray(const r_GMarray)", "rasodmg", __FILE__, __LINE__)
+
+ if (obj.data)
+ {
+ data_size = obj.data_size;
+ data = new char[ data_size ];
+
+ memcpy(data, obj.data, (unsigned int)data_size);
+ }
+
+ // clone the storage layout object
+ if (obj.storage_layout)
+ storage_layout = obj.storage_layout->clone();
+ else
+ RMInit::logOut << "copy constructor no storage layout" << endl;
+}
+
+
+
+r_GMarray::r_GMarray(r_GMarray &obj) throw(r_Error)
+ : r_Object(obj, 1),
+ data(obj.data),
+ data_size(obj.data_size),
+ domain(obj.spatial_domain()),
+ type_length(obj.type_length),
+ current_format(obj.current_format),
+ storage_layout(0)
+{
+ RMDBCLASS("r_GMarray", "r_GMarray(r_GMarray)", "rasodmg", __FILE__, __LINE__)
+
+ obj.data_size = 0;
+ obj.data = 0;
+ obj.domain = r_Minterval();
+ obj.type_length = 0;
+
+ // clone the storage layout object
+ if (obj.storage_layout)
+ storage_layout = obj.storage_layout->clone();
+ else
+ RMInit::logOut << "copy constructor (no data) no storage layout" << endl;
+}
+
+
+
+r_GMarray::~r_GMarray()
+{
+ r_deactivate();
+}
+
+
+
+void
+r_GMarray::r_deactivate()
+{
+ RMDBGENTER(2, RMDebug::module_rasodmg, "r_GMarray", "r_deactivate()");
+
+ if (data)
+ {
+ delete[] data;
+ data = 0;
+ }
+
+ // invoke deactivate of members with dynamic memory
+ domain.r_deactivate();
+
+ // delete dynamic members
+ if (storage_layout)
+ {
+ delete storage_layout;
+ storage_layout = 0;
+ }
+
+ RMDBGEXIT(2, RMDebug::module_rasodmg, "r_GMarray", "r_deactivate()");
+}
+
+
+
+const char*
+r_GMarray::operator[] (const r_Point& point) const
+ throw(r_Edim_mismatch, r_Eindex_violation)
+{
+ return &(data[ domain.cell_offset(point)*type_length ]);
+}
+
+
+
+const r_Storage_Layout*
+r_GMarray::get_storage_layout() const
+{
+ return storage_layout;
+}
+
+
+void
+r_GMarray::set_storage_layout(r_Storage_Layout *stl) throw(r_Error)
+{
+ if (!stl->is_compatible(domain, type_length))
+ {
+ RMInit::logOut << "r_GMarray::set_storage_layout(" << *stl << ") gmarray is not compatible with tiling" << endl;
+ RMInit::logOut << "\tgmarray domain : " << spatial_domain() << endl;
+ RMInit::logOut << "\tgmarray type size: " << get_type_length() << endl;
+ throw r_Error(STORAGERLAYOUTINCOMPATIBLEWITHGMARRAY);
+ }
+
+ if (storage_layout != NULL)
+ delete storage_layout;
+
+ storage_layout = stl;
+}
+
+
+
+const r_GMarray&
+r_GMarray::operator=(const r_GMarray& marray)
+{
+ if (this != &marray)
+ {
+ if (data)
+ {
+ delete[] data;
+ data = 0;
+ }
+
+ if (marray.data)
+ {
+ data_size = marray.data_size;
+ data = new char[ data_size ];
+
+ memcpy(data, marray.data, (unsigned int)data_size);
+ }
+
+ if (storage_layout)
+ {
+ delete storage_layout;
+ storage_layout = 0;
+ }
+
+ // this has to be changed to a clone() function in future
+ if (marray.storage_layout)
+ // storage_layout = new r_Storage_Layout(*marray.storage_layout);
+ storage_layout = marray.storage_layout->clone();
+
+ domain = marray.domain;
+ type_length = marray.type_length;
+ current_format = marray.current_format;
+ }
+
+ return *this;
+}
+
+
+
+void
+r_GMarray::insert_obj_into_db()
+{
+ // Nothing is done in that case. r_Marray objects can just be inserted as elements
+ // of a collection which invokes r_GMarray::insert_obj_into_db(const char* collName)
+ // of the r_Marray objects.
+
+ // r_Database::actual_database->communication->insertSingleMDDObj(this);
+ RMInit::logOut << " do nothing " << std::flush;
+}
+
+
+
+void
+r_GMarray::insert_obj_into_db(const char* collName)
+{
+ // Insert myself in database only if I have a type name, otherwise
+ // an exception is thrown.
+ if (!type_name)
+ {
+ r_Error err = r_Error(r_Error::r_Error_DatabaseClassUndefined);
+ throw err;
+ }
+
+ r_Database::actual_database->getComm()->insertMDD(collName, this);
+}
+
+
+
+
+void
+r_GMarray::print_status(std::ostream& s) const
+{
+ const r_Type* typeSchema = (r_Base_Type*)((r_GMarray*)this)->get_type_schema();
+ const r_Base_Type* baseTypeSchema = (r_Base_Type*)((r_GMarray*)this)->get_base_type_schema();
+
+ s << "GMarray" << endl;
+ s << " Oid...................: " << get_oid() << endl;
+ s << " Type Structure........: " << (get_type_structure() ? get_type_structure() : "<nn>") << endl;
+ s << " Type Schema...........: " << std::flush;
+ if (typeSchema)
+ typeSchema->print_status(s);
+ else
+ s << "<nn>" << std::flush;
+ s << endl;
+ s << " Domain................: " << domain << endl;
+ s << " Base Type Schema......: " << std::flush;
+ if (baseTypeSchema)
+ baseTypeSchema->print_status(s);
+ else
+ s << "<nn>" << std::flush;
+ s << endl;
+ s << " Base Type Length......: " << type_length << endl;
+ s << " Data format.......... : " << current_format << endl;
+ s << " Data size (bytes).... : " << data_size << endl;
+}
+
+
+
+void
+r_GMarray::print_status(std::ostream& s, int hexoutput) const
+{
+ print_status(s);
+
+ const r_Type* typeSchema = (r_Base_Type*)((r_GMarray*)this)->get_type_schema();
+ const r_Base_Type* baseTypeSchema = (r_Base_Type*)((r_GMarray*)this)->get_base_type_schema();
+
+ if (domain.dimension())
+ {
+ r_Point p(domain.dimension());
+ bool done = false;
+ r_Dimension i = 0;
+
+ // initialize point
+ for (i = 0; i < domain.dimension(); i++)
+ p << domain[i].low();
+
+ // iterate over all cells
+ while(!done)
+ {
+ //
+ // print cell
+ //
+
+ // get cell address
+ char* cell = data + domain.cell_offset(p) * type_length;
+
+ if (hexoutput)
+ {
+ for (r_Bytes j = 0; j < type_length; j++)
+ s << std::hex << (unsigned int)(unsigned char)(cell[j]);
+ }
+ else {
+ if(baseTypeSchema) baseTypeSchema->print_value(cell, s );
+ else s << "<nn>" << std::flush;
+ }
+
+ s << " ";
+
+ // increment coordinate
+ i = 0;
+ while(++p[i] > domain[i].high())
+ {
+ s << endl;
+ p[i] = domain[i].low();
+ i++;
+ if (i >= domain.dimension())
+ {
+ done = true;
+ break;
+ }
+ }
+ if (i > 1) s << endl;
+ }
+ }
+ else
+ {
+ s << "Cell value " << std::flush;
+
+ // print cell
+ if ((hexoutput) || (!baseTypeSchema))
+ {
+ for (unsigned int j=0; j<type_length; j++)
+ s << std::hex << (unsigned int)(unsigned char)(data[j]);
+ }
+ else {
+ if(baseTypeSchema) baseTypeSchema->print_value(data, s );
+ else s << "<nn>" << std::flush;
+ }
+ s << endl;
+ }
+
+ // turn off hex mode again
+ s << std::dec << std::flush;
+}
+
+
+
+
+r_GMarray* r_GMarray::intersect(r_Minterval where) const
+{
+ r_GMarray* tile = new r_GMarray();
+
+ r_Minterval obj_domain = spatial_domain();
+ r_Dimension num_dims = obj_domain.dimension();
+ r_Bytes tlength = get_type_length();
+
+ char* obj_data = new char[where.cell_count() * tlength];
+ tile->set_spatial_domain(where);
+ tile->set_type_length(tlength);
+ tile->set_array(obj_data);
+ tile->set_array_size(where.cell_count() * tlength);
+
+ r_Bytes block_length = where[num_dims-1].high() - where[num_dims-1].low() + 1;
+ r_Bytes total = where.cell_count()/block_length;
+
+ for (r_Area cell = 0; cell < total; cell++)
+ {
+ r_Point p = where.cell_point(cell*block_length);
+
+ char* dest_off = obj_data;
+ const char* source_off = get_array();
+
+ memcpy((void*) (dest_off + where.cell_offset(p)*tlength),
+ (void*) (source_off + obj_domain.cell_offset(p)*tlength),
+ (size_t) (block_length * tlength));
+ }
+
+ return tile;
+}
+
+
+
+const r_Base_Type*
+r_GMarray::get_base_type_schema()
+{
+ const r_Type* typePtr = r_Object::get_type_schema();
+ const r_Base_Type* baseTypePtr = 0;
+
+ if (typePtr)
+ {
+ if (typePtr->type_id() == r_Type::MARRAYTYPE)
+ {
+ const r_Marray_Type* marrayTypePtr = (const r_Marray_Type*)typePtr;
+ baseTypePtr = &(marrayTypePtr->base_type());
+ }
+ else
+ {
+ //whenever this module is done correctly, it should be checked first, what kind of type we are dealing with. therefore i do not declare a throw clause.
+ RMInit::logOut << "r_GMarray::get_base_type_schema() the type retrieved (" << typePtr->name() << ") was not a marray type" << endl;
+ throw r_Error(NOTANMARRAYTYPE);
+ }
+ }
+
+ return baseTypePtr;
+}
+
diff --git a/rasodmg/gmarray.hh b/rasodmg/gmarray.hh
new file mode 100644
index 0000000..2274e74
--- /dev/null
+++ b/rasodmg/gmarray.hh
@@ -0,0 +1,185 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: gmarray.hh
+ *
+ * MODULE: rasodmg
+ * CLASS: r_GMarray
+ *
+ * COMMENTS:
+ * None
+*/
+
+#ifndef _D_GMARRAY_
+#define _D_GMARRAY_
+
+#include "rasodmg/object.hh"
+
+#include "raslib/error.hh"
+#include "raslib/minterval.hh"
+#include "raslib/point.hh"
+#include "raslib/type.hh"
+#include "raslib/mddtypes.hh"
+
+#include <iostream>
+
+// forward declarations
+class r_Storage_Layout;
+
+
+//@ManMemo: Module: {\bf rasodmg}
+
+/*@Doc:
+
+ The class represents a generic MDD in the sense that it
+ is independent of the cell base type. The only information
+ available is the length in bytes of the base type.
+ More specific MDDs including base type information for more
+ type safety are represented by the template subclass \Ref{r_Marray}.
+ Class \Ref{r_Marray} provides a constructor to convert to the base
+ type specific class.
+*/
+
+class r_GMarray : public r_Object
+{
+ public:
+ /// default constructor (no memory is allocated!)
+ r_GMarray() throw(r_Error);
+
+ /// constructor for uninitialized MDD objects
+ r_GMarray(const r_Minterval& init_domain, r_Bytes type_length, r_Storage_Layout* stl = 0) throw (r_Error);
+ /**
+ If a storage layout pointer is provided, the object refered to is
+ taken and memory control moves to the \Ref{r_GMarray} class.
+ The user has to take care, that each creation of \Ref{r_GMarray}
+ objects get a new storage layout object.
+ r_Error is throw if the storage layout does not fit the type length or the dimension of the init domain and when the dimension of the domain is 0 (uninitialised).
+ */
+
+ /// copy constructor
+ r_GMarray(const r_GMarray&) throw(r_Error);
+
+ /// constructor which doesn't copy the data
+ r_GMarray(r_GMarray&) throw(r_Error);
+
+ /// destructor
+ virtual ~r_GMarray();
+
+ /// it is called when an object leaves transient memory (internal use only)
+ virtual void r_deactivate();
+
+ /// assignment: cleanup + copy
+ const r_GMarray& operator= (const r_GMarray&);
+
+ /// subscript operator for read access of a cell
+ const char* operator[](const r_Point&) const
+ throw(r_Edim_mismatch, r_Eindex_violation);
+
+ /// Returns a r_GMarray that is the intersection of the current domain with the specified interval
+ r_GMarray* intersect(r_Minterval where) const;
+
+ //@Man: Read methods
+ //@{
+ ///
+
+ /// gets a pointer to the storage layout object
+ const r_Storage_Layout* get_storage_layout() const;
+ /// getting the spatial domain
+ inline const r_Minterval& spatial_domain() const;
+ /// get the internal representation of the array
+ inline char* get_array();
+ /// get the internal representation of the array for reading
+ inline const char* get_array() const;
+ /// get size of internal array representation in byets
+ inline r_Bytes get_array_size() const;
+ /// get length of cell type in bytes
+ inline r_Bytes get_type_length() const;
+ /// get current data format
+ inline r_Data_Format get_current_format() const;
+
+ /// get base type schema
+ const r_Base_Type* get_base_type_schema();
+
+ ///
+ //@}
+
+ //@Man: Write methods
+ //@{
+ ///
+ /// sets the storage layout object and checks compatibility with the domain
+ void set_storage_layout(r_Storage_Layout *) throw (r_Error);
+ /// set spatial domain
+ inline void set_spatial_domain(const r_Minterval& domain);
+ /// set the internal representation of the array
+ inline void set_array(char*);
+ /// set size of internal memory representation in bytes
+ inline void set_array_size(r_Bytes);
+ /// set length of cell type in bytes
+ inline void set_type_length(r_Bytes);
+ /// set current data format
+ inline void set_current_format(r_Data_Format);
+
+ ///
+ //@}
+
+ //@Man: Methods for database communication (internal use only)
+ //@{
+ ///
+
+ /// inserts an object into the database
+ virtual void insert_obj_into_db();
+ /// insert myself into a specific collection in the database
+ void insert_obj_into_db(const char* collName);
+
+ ///
+ //@}
+
+ /// writes the state of the object to the specified stream
+ virtual void print_status(std::ostream& s = std::cout) const;
+
+ /// writes the state of the object to the specified stream
+ void print_status(std::ostream& s, int hexoutput) const;
+
+ protected:
+ /// spatial domain
+ r_Minterval domain;
+
+ /// pointer to the internal array representation
+ char* data;
+
+ /// size of internal array representation in bytes
+ r_Bytes data_size;
+
+ /// length of the cell base type in bytes
+ r_Bytes type_length;
+
+ /// store current data format
+ r_Data_Format current_format;
+
+ /// pointer to storage layout object
+ r_Storage_Layout* storage_layout;
+};
+
+#include "rasodmg/gmarray.icc"
+
+#endif
diff --git a/rasodmg/gmarray.icc b/rasodmg/gmarray.icc
new file mode 100644
index 0000000..f6453b2
--- /dev/null
+++ b/rasodmg/gmarray.icc
@@ -0,0 +1,119 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INLINE SOURCE: gmarray.icc
+ *
+ * MODULE: rasodmg
+ * CLASS: r_GMarray
+ *
+ * COMMENTS:
+ * None
+*/
+
+
+
+inline const r_Minterval&
+r_GMarray::spatial_domain() const
+{
+ return domain;
+};
+
+
+
+inline char*
+r_GMarray::get_array()
+{
+ return data;
+};
+
+
+inline const char*
+r_GMarray::get_array() const
+{
+ return data;
+}
+
+
+inline void
+r_GMarray::set_array( char* newData )
+{
+ // In case the array already has an array allocated, free it first.
+// if (data != NULL) delete [] data;
+ data = newData;
+};
+
+
+
+inline void
+r_GMarray::set_current_format( r_Data_Format newFormat )
+{
+ current_format = newFormat;
+};
+
+
+
+inline r_Bytes
+r_GMarray::get_type_length() const
+{
+ return type_length;
+};
+
+
+
+inline r_Bytes
+r_GMarray::get_array_size() const
+{
+ return data_size;
+};
+
+
+
+inline r_Data_Format
+r_GMarray::get_current_format() const
+{
+ return current_format;
+};
+
+
+
+inline void
+r_GMarray::set_spatial_domain( const r_Minterval& dom )
+{
+ domain = dom;
+};
+
+
+
+inline void
+r_GMarray::set_type_length( r_Bytes newValue )
+{
+ type_length = newValue;
+}
+
+
+
+inline void
+r_GMarray::set_array_size( r_Bytes newValue )
+{
+ data_size = newValue;
+}
diff --git a/rasodmg/interesttiling.cc b/rasodmg/interesttiling.cc
new file mode 100644
index 0000000..aad8841
--- /dev/null
+++ b/rasodmg/interesttiling.cc
@@ -0,0 +1,809 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: interesttiling.cc
+ *
+ * MODULE: rasodmg
+ * CLASS: r_Interest_Tiling
+ *
+ * COMMENTS:
+ * None
+*/
+
+#include "rasodmg/interesttiling.hh"
+#include "rasodmg/alignedtiling.hh"
+#include "rasodmg/dirdecompose.hh"
+#include "rasodmg/dirtiling.hh"
+#include "raslib/rminit.hh"
+
+#include <assert.h>
+#include <string.h>
+#include <math.h>
+#include <cstdlib>
+
+#ifdef AIX
+#include <strings.h>
+#endif
+
+// Uncoment the _VISUALIZE_2D_DECOMP_ line to generate ppm files the
+// visualization of the domain decomposition done by the algoritm
+// #define _VISUALIZE_2D_DECOMP_
+
+// Uncoment the folling line for some debug printfs on this class
+// #define _DEBUG_INTERESTTILING_
+
+#ifdef _VISUALIZE_2D_DECOMP_
+#include "tools/visualtiling2d.hh"
+#endif
+
+// This is a data structure for internal use within interesttiling.cc.
+// It is defined here because of problems with ptrepository.
+// -------------
+// This structure consists of a r_Minterval and a counter. Also, it has
+// some auxiliary constructors.
+
+class Classified_Block
+ {
+ public:
+ int intersection_count; // Intersection count
+ r_Minterval block; // The actual block
+
+ // Default constructor
+ Classified_Block(int count = 0);
+
+ // Constructor with the actual block and the counter
+ Classified_Block(const r_Minterval& b, int count = 0);
+
+ // Same data structure (this operator is needed because of dlist)
+ bool operator==(const Classified_Block& other) const;
+
+ // Different data structure (this operator is needed because of dlist)
+ bool operator!=(const Classified_Block& other) const;
+
+ // Friend of std::ostream (this operator is needed because of dlist)
+ friend std::ostream& operator<<(std::ostream& os, const Classified_Block& block);
+ };
+
+const char*
+r_Interest_Tiling::description = "dimensions, areas of interest, tile size (in bytes) and tile size limit [NOLIMIT|REGROUP|SUBTILING|REGROUPSUBTILING] (ex: \"2;[0:9,0:9];[100:109,0:9];100;REGROUPSUBTILING\")";
+
+const char* r_Interest_Tiling::tilesizelimit_name_nolimit ="NOLIMIT";
+const char* r_Interest_Tiling::tilesizelimit_name_regroup ="REGROUP";
+const char* r_Interest_Tiling::tilesizelimit_name_subtiling ="SUBTILING";
+const char* r_Interest_Tiling::tilesizelimit_name_regroupandsubtiling ="REGROUPSUBTILING";
+const char* r_Interest_Tiling::all_tilesizelimit_names[r_Interest_Tiling::NUMBER]={
+ tilesizelimit_name_nolimit,
+ tilesizelimit_name_regroup,
+ tilesizelimit_name_subtiling,
+ tilesizelimit_name_regroupandsubtiling
+ };
+
+r_Interest_Tiling::Tilesize_Limit
+r_Interest_Tiling::get_tilesize_limit_from_name(const char* name)
+{
+
+ if(!name) {
+ RMInit::logOut << "r_Interest_Tiling::get_tilesize_limit_from_name(" << (name?name: "NULL") << ")" << endl;
+ return r_Interest_Tiling::NUMBER;
+ }
+
+ unsigned int i=r_Interest_Tiling::NUMBER;
+
+ for (i=0; i<(unsigned int)r_Interest_Tiling::NUMBER; i++)
+ {
+ if (strcasecmp(name, all_tilesizelimit_names[i]) == 0)
+ break;
+ }
+ return (r_Interest_Tiling::Tilesize_Limit)i;
+}
+
+const char*
+r_Interest_Tiling::get_name_from_tilesize_limit(Tilesize_Limit tsl)
+{
+ static const char* unknown="UNKNOWN";
+ unsigned int idx = (unsigned int)tsl;
+
+ if (idx >= (unsigned int)r_Interest_Tiling::NUMBER)
+ return unknown;
+
+ return all_tilesizelimit_names[idx];
+}
+
+r_Interest_Tiling::r_Interest_Tiling(const char* encoded) throw (r_Error)
+ : r_Dimension_Tiling(0,0)
+{
+ if(!encoded)
+ {
+ RMInit::logOut << "r_Interest_Tiling::r_Interest_Tiling(" << (encoded?encoded: "NULL") << ")" << endl;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+
+ std::vector<r_Minterval> vectInterestAreas;
+ r_Interest_Tiling::Tilesize_Limit tileSizeLimit;
+ r_Dimension tileD=0;
+ r_Bytes tileS=0, lenToConvert=0;
+ const char *pStart=NULL, *pRes=NULL, *pTemp=NULL, *pEnd=NULL;
+ char *pToConvert=NULL;
+
+
+ pStart=encoded;
+ pEnd=pStart+strlen(pStart);
+ pTemp=pStart;
+ pRes=strstr(pTemp,COLON);
+
+ if(!pRes)
+ {
+ RMInit::logOut << "r_Interest_Tiling::r_Interest_Tiling(" << encoded << "): Error decoding tile dimension from \"" << pTemp << "\"." << endl;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+
+ //deal with dimension
+ lenToConvert=pRes-pTemp;
+ pToConvert=new char[lenToConvert+1];
+ memcpy(pToConvert,pTemp, lenToConvert);
+ pToConvert[lenToConvert]='\0';
+
+ tileD=strtol(pToConvert, (char**)NULL, DefaultBase);
+ if (!tileD)
+ {
+ RMInit::logOut << "r_Interest_Tiling::r_Interest_Tiling(" << encoded << "): Error decoding tile dimension from \"" << pToConvert << "\"." << endl;
+ delete[] pToConvert;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+ if (tileD < 0)
+ {
+ RMInit::logOut << "r_Interest_Tiling::r_Interest_Tiling(" << encoded << "): Error decoding tile dimension from \"" << pToConvert << "\", is negative." << endl;
+ delete[] pToConvert;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+
+ //skip COLON && free buffer
+ delete[] pToConvert;
+ if(pRes != (pEnd-1))
+ pRes++;
+ else
+ {
+ RMInit::logOut << "r_Interest_Tiling::r_Interest_Tiling(" << encoded << "): Error decoding interest areas, end of stream." << endl;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+
+ //parse interest areas
+ pTemp=pRes;
+ pRes=strstr(pTemp,COLON);
+
+ if(!pRes)
+ {
+ RMInit::logOut << "r_Interest_Tiling::r_Interest_Tiling(" << encoded << "): Error decoding interest areas." << endl;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+
+ while(pRes)
+ {
+ //is interest areas?
+ if(*pTemp != *LSQRBRA)
+ break;
+
+ //copy parsed interest area
+ lenToConvert=pRes-pTemp;
+ pToConvert=new char[lenToConvert+1];
+ memcpy(pToConvert, pTemp, lenToConvert);
+ pToConvert[lenToConvert]='\0';
+
+ //add to vector
+ try
+ {
+ r_Minterval a(pToConvert);
+ vectInterestAreas.push_back(a);
+ }
+ catch(r_Error& err)
+ {
+ RMInit::logOut << "r_Interest_Tiling::r_Interest_Tiling(" << encoded << "): Error decoding interest area from \"" << pToConvert << "\"." << endl;
+ RMInit::logOut << "Error " << err.get_errorno() << " : " << err.what() << endl;
+ delete [] pToConvert;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+
+ //skip COLON
+ delete[] pToConvert;
+ if(pRes != (pEnd-1))
+ pRes++;
+ else
+ {
+ RMInit::logOut << "r_Interest_Tiling::r_Interest_Tiling(" << encoded << "): Error decoding interest areas, end of stream." << endl;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+
+ //try next item
+ pTemp=pRes;
+ pRes=strstr(pTemp, COLON);
+ }
+
+ if(vectInterestAreas.empty())
+ {
+ RMInit::logOut << "r_Interest_Tiling::r_Interest_Tiling(" << encoded << "): Error decoding interest areas, no interest areas specified." << endl;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+
+ //deal with tile size
+ lenToConvert=pRes-pTemp;
+ pToConvert=new char[lenToConvert+1];
+ memcpy(pToConvert, pTemp, lenToConvert);
+ pToConvert[lenToConvert]='\0';
+
+ tileS=strtol(pToConvert, (char**)NULL, DefaultBase);
+ if (!tileS)
+ {
+ RMInit::logOut << "r_Interest_Tiling::r_Interest_Tiling(" << encoded << "): Error decoding tile size from \"" << pToConvert << "\"." << endl;
+ delete[] pToConvert;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+ if (tileS < 0)
+ {
+ RMInit::logOut << "r_Interest_Tiling::r_Interest_Tiling(" << encoded << "): Error decoding tile size from \"" << pToConvert << "\", is negative." << endl;
+ delete[] pToConvert;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+
+ //skip COLON && free buffer
+ delete[] pToConvert;
+ if(pRes != (pEnd-1))
+ pRes++;
+ else
+ {
+ RMInit::logOut << "r_Interest_Tiling::r_Interest_Tiling(" << encoded << "): Error decoding tile size limit, end of stream." << endl;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+
+ pTemp=pRes;
+
+ tileSizeLimit=r_Interest_Tiling::get_tilesize_limit_from_name(pTemp);
+ if(tileSizeLimit==r_Interest_Tiling::NUMBER)
+ {
+ RMInit::logOut << "r_Interest_Tiling::r_Interest_Tiling(" << encoded << "): Error decoding tile size limit from \"" << pTemp << "\"." << endl;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+
+ iareas = vectInterestAreas;
+ ts_strat = tileSizeLimit;
+ dimension = tileD;
+ tile_size = tileS;
+}
+
+r_Interest_Tiling::r_Interest_Tiling(r_Dimension dim, const std::vector<r_Minterval>& interest_areas, r_Bytes ts, Tilesize_Limit strat) throw (r_Error)
+ : r_Dimension_Tiling(dim, ts),
+ iareas(interest_areas),
+ ts_strat(strat)
+{
+ for (std::vector<r_Minterval>::iterator it = iareas.begin(); it != iareas.end(); it++)
+ if (it->dimension() != dimension)
+ {
+ RMInit::logOut << "r_Interest_Tiling::r_Interest_Tiling(" << dim << ", " << interest_areas << ", " << ts << ", " << strat << ") the interest area domain " << *it << " does not match the dimension of this tiling scheme (" << dimension << ")" << endl;
+ throw r_Edim_mismatch(dimension, it->dimension());
+ }
+}
+
+r_Interest_Tiling::~r_Interest_Tiling()
+{
+}
+
+r_Tiling* r_Interest_Tiling::clone() const
+{
+ r_Tiling* copy = new r_Interest_Tiling(dimension, iareas, tile_size, ts_strat);
+ return copy;
+}
+
+void r_Interest_Tiling::print_status(std::ostream& os) const
+{
+ os << "r_Interest_Tiling[ ";
+ r_Dimension_Tiling::print_status(os);
+ os << " interest areas = " << iareas << ", tiling strategy = " << ts_strat << " ]";
+}
+
+r_Tiling_Scheme
+r_Interest_Tiling::get_tiling_scheme() const
+ {
+ return r_InterestTiling;
+ }
+
+static int r_Range_comp(const void *elem1, const void *elem2)
+{
+ r_Range e1 = *((r_Range*) elem1);
+ r_Range e2 = *((r_Range*) elem2);
+
+ if (e1 == e2)
+ return 0;
+
+ if (e1 < e2)
+ return -1;
+ else
+ return +1;
+}
+
+std::vector<r_Dir_Decompose>*
+r_Interest_Tiling::make_partition(const r_Minterval& domain) const
+{
+ r_Dimension dim = domain.dimension();
+ int total = 2 * iareas.size();
+
+ // We need one decomp from each dimension
+ std::vector<r_Dir_Decompose>* part = new std::vector<r_Dir_Decompose>(dim);
+
+ // We have at most (number of interest areas + 2) intervals
+ r_Range* intervals = new r_Range[total + 2];
+
+ // Create iterator for interest areas
+ std::vector<r_Minterval>::const_iterator it = iareas.begin();
+ int total_iareas = iareas.size();
+
+
+ // For all dimensions
+ for (r_Dimension i = 0; i < dim; i++)
+ {
+ it = iareas.begin(); // Reset iterator
+ intervals[0] = domain[i].low(); // Input lower domain limit
+ intervals[total+1] = domain[i].high(); // Input higher domain limit
+
+
+ for (int j = 1; j < total + 1; j += 2, ++it) // For all possible intervals
+ {
+ if ((*it)[i].low()-1 <= domain[i].low()) // Input low iarea limit
+ intervals[j] = domain[i].low();
+ else
+ intervals[j] = (*it)[i].low()-1;
+
+ intervals[j+1] = (*it)[i].high(); // Input higher iarea limit
+ }
+
+ // Sort the table
+ qsort((void*) intervals, total+2, sizeof(r_Range), r_Range_comp);
+
+ // Create partition using the limits table
+ for (int k=0; k<total+2; k++) // all limits must be checked
+ {
+ if (k == total+1) // if on the last limit...
+ ((*part)[i]) << intervals[k]; // input it
+ else // else
+ if (intervals[k] != intervals[k+1]) // if it is unique
+ ((*part)[i]) << intervals[k]; // input it
+ }
+ }
+
+ // Free memory
+ delete [] intervals;
+
+ // Return result
+ return part;
+}
+
+std::vector<r_Minterval>*
+r_Interest_Tiling::group(std::vector<r_Minterval>& blocks, r_Bytes typelen, Blocks_Type btype) const
+{
+ r_Bytes tilesize = get_tile_size();
+ int joins = 0;
+ bool group_blocks = true;
+
+ // The list of threated blocks
+ std::vector<r_Minterval>* treated = new std::vector<r_Minterval>;
+
+ // An iterator for the blocks list
+ std::vector<r_Minterval>::iterator blocks_it = blocks.begin();
+
+ // The current block
+ r_Minterval current_block;
+
+ // For all the blocks in list
+ while (!blocks.empty())
+ {
+ // Get first block from list
+ current_block = blocks.back();
+ blocks.pop_back();
+
+ //this is neccessary when the compiler optimizes out the .end() check
+ unsigned int numberOfLevels = blocks.size();
+ for (blocks_it = blocks.begin(); blocks_it != blocks.end(); blocks_it++)
+ {
+ if (numberOfLevels == 0)
+ {
+ RMInit::logOut << "r_Interest_Tiling::group() the for loop was incorrectly optimized. breaking the loop." << endl;
+ break;
+ }
+ r_Minterval aux = *blocks_it;
+
+ // In principle two blocks can't be merged
+ group_blocks = false;
+
+ // If they can be merged
+ if (current_block.is_mergeable(aux))
+ {
+ std::vector<r_Minterval>::iterator ia_it = blocks.begin();
+
+ switch (btype)
+ {
+ case BLOCKS_A:
+
+ group_blocks = true;
+
+ // Check if the two blocks belong exaclty to the same iareas
+ for (; ia_it != blocks.end(); ia_it++)
+ {
+ if (aux.intersects_with(*ia_it) != current_block.intersects_with(*ia_it))
+ {
+ group_blocks = false;
+ break;
+ }
+ }
+
+ break;
+
+ case BLOCKS_B:
+
+ for (; ia_it != blocks.end(); ia_it++) // For all iareas
+ {
+ // Find the one this block intersects
+ if (current_block.intersects_with(*ia_it))
+ {
+ // Check if the other area intersects it
+ if (!aux.intersects_with(*ia_it))
+ group_blocks = false;
+ else
+ group_blocks = true;
+
+ break;
+ }
+ }
+
+ if (!group_blocks)
+ break;
+
+ group_blocks = false;
+
+ case BLOCKS_C: // Falls in (this is, also applies to B);
+
+ // Only on this two strategies, tilesize should be looked at
+ if ((ts_strat == REGROUP) || (ts_strat == REGROUP_AND_SUBTILING))
+ {
+ // If the resulting size isn't larger than tilesize
+ if ((current_block.cell_count()+aux.cell_count()) * typelen
+ < get_tile_size())
+ group_blocks = true;
+ }
+ else
+ group_blocks = true;
+
+ break;
+ }
+ }
+
+ // take care of the iterator advance, if is possible
+ if (group_blocks)
+ {
+ // Merge them
+ blocks.erase(blocks_it); // Automatically advances to next block
+ // take care of the size of the blocks
+ numberOfLevels--;
+ current_block.closure_with(aux);
+ ++joins;
+ }
+ else
+ numberOfLevels--;
+ }
+
+ // Update the treated list with the current block
+ treated->push_back(current_block);
+ }
+
+ std::vector<r_Minterval>* result = 0;
+
+ // If there was joins, the algoritm must be repeted
+ if (joins != 0)
+ {
+ result = group(*treated, typelen, btype);
+ delete treated;
+ }
+ else
+ {
+ result = treated;
+ }
+
+ // Return the result
+ return result;
+}
+
+std::vector<r_Minterval>*
+r_Interest_Tiling::compute_tiles(const r_Minterval& domain, r_Bytes typelen) const throw (r_Error)
+{
+ r_Dimension num_dims = domain.dimension(); // Dimensionality of dom
+if (domain.dimension() != dimension)
+ {
+ RMInit::logOut << "r_Interest_Tiling::compute_tiles(" << domain << ", " << typelen << ") dimension (" << dimension << ") does not match dimension of object to tile (" << num_dims << ")" << endl;
+ throw r_Edim_mismatch(dimension, num_dims);
+ }
+if (typelen > tile_size)
+ {
+ RMInit::logOut << "r_Interest_Tiling::compute_tiles(" << domain << ", " << typelen << ") tile size (" << tile_size << ") is smaller than type length (" << typelen << ")" << endl;
+ throw r_Error(TILESIZETOOSMALL);
+ }
+
+#ifdef _VISUALIZE_2D_DECOMP_ // User wants a visual
+ static int count; // Number of decomps
+ ++count; // Update num decomps
+ // of the 2D decomp.
+ Visual_Tiling_2D* vis;
+ if (domain.dimension() == 2)
+ {
+ // Create an object for visualization
+ char fname[80];
+ sprintf(fname, "2D_decomp_int_%d.ppm", count);
+ vis = new Visual_Tiling_2D(domain, fname);
+ }
+
+#endif
+
+
+ // *** Main algoritm ***
+
+ // The result
+ std::vector<r_Minterval>* result = new std::vector<r_Minterval>;
+
+ // Create a partition for dir tiling
+ std::vector<r_Dir_Decompose>* part = make_partition(domain);
+
+ // Perform dirtiling
+ r_Dir_Tiling *dir_tiling= NULL;
+ std::vector<r_Minterval>* dir_domain=NULL;
+
+ try
+ {
+ dir_tiling=new r_Dir_Tiling(num_dims, *part, tile_size, r_Dir_Tiling::WITHOUT_SUBTILING);
+
+ // Compute all tiles (directional tiles)
+ dir_domain = dir_tiling->compute_tiles(domain, typelen);
+
+ delete dir_tiling;
+ }
+ catch(r_Error& err)
+ {
+ delete result;
+ delete part;
+ if(dir_tiling)
+ delete dir_tiling;
+ throw;
+ }
+
+ // Get an interator for interest areas
+ //std::vector<r_Minterval>::iterator interest_area;
+
+ // Create a list for holding the classifed blocks
+ std::vector<Classified_Block> part_domain;
+
+ // Finds how many intersections exist between a block an the interest areas
+ for (std::vector<r_Minterval>::iterator dir_block = dir_domain->begin(); dir_block != dir_domain->end(); dir_block++)
+ {
+ Classified_Block b(*dir_block, 0);
+
+ for (std::vector<r_Minterval>::const_iterator interest_area = iareas.begin(); interest_area != iareas.end(); interest_area++)
+ {
+ if (b.block.intersects_with(*interest_area))
+ ++b.intersection_count;
+ }
+
+ part_domain.push_back(b);
+ }
+
+ // Lists used for grouping blocks
+ std::vector<r_Minterval> Out;
+ std::vector<r_Minterval> In_Unique;
+ std::vector<r_Minterval> In_Common;
+
+ // Divide blocks into lists according to their number of intersections
+ for (std::vector<Classified_Block>::iterator class_block = part_domain.begin(); class_block != part_domain.end(); class_block++)
+ {
+ switch ((*class_block).intersection_count)
+ {
+ case 0:
+ Out.push_back((*class_block).block);
+ break;
+ case 1:
+ In_Unique.push_back((*class_block).block);
+ break;
+ default:
+ In_Common.push_back((*class_block).block);
+ break;
+ }
+ }
+
+
+ // Group blocks
+ std::vector<r_Minterval>* Blocks_A = group(In_Common, typelen, BLOCKS_A);
+ std::vector<r_Minterval>* Blocks_B = group(In_Unique, typelen, BLOCKS_B);
+ std::vector<r_Minterval>* Blocks_C = group(Out, typelen, BLOCKS_C);
+
+
+ std::vector<r_Minterval>::iterator it_A = Blocks_A->begin();
+ std::vector<r_Minterval>::iterator it_B = Blocks_B->begin();
+ std::vector<r_Minterval>::iterator it_C = Blocks_C->begin();
+
+ // If may be necessary to perform sub-tiling
+ if ((ts_strat == SUB_TILING) || (ts_strat == REGROUP_AND_SUBTILING))
+ {
+ // Variable to hold result of sub-tiling
+ std::vector<r_Minterval>* subtiles = 0;
+
+ // We need an array to hold the 3 iterators of the resulting blocks
+ std::vector<r_Minterval>::iterator* blocks_it[3];
+ std::vector<r_Minterval>* blocks_vec[3];
+
+ // Put iterators on the list
+ blocks_it[0] = &it_A;
+ blocks_it[1] = &it_B;
+ blocks_it[2] = &it_C;
+
+ blocks_vec[0] = Blocks_A;
+ blocks_vec[1] = Blocks_B;
+ blocks_vec[2] = Blocks_C;
+
+ // For all the lists (Blocs_A, Blocks_B and Blocks_C)
+ for (int j=0; j<3; j++)
+ {
+ // Reset iterator to the begin
+ (*blocks_it[j]) = blocks_vec[j]->begin();
+
+ // Tile each block if necessary
+ for (; *blocks_it[j] != blocks_vec[j]->end(); (*blocks_it[j])++)
+ {
+ if ((**blocks_it[j]).cell_count()*typelen > get_tile_size())
+ {
+ // Create a specification of a regular n-dim cube grid
+ r_Minterval specs(num_dims);
+ for (r_Dimension i=0; i<num_dims; i++)
+ {
+ specs << r_Sinterval((r_Range)0, (**blocks_it[j])[i].high() - (**blocks_it[j])[i].low());
+ }
+
+ // Class for performing sub-tiling
+ r_Aligned_Tiling subtiling(specs, get_tile_size());
+
+ subtiles = subtiling.compute_tiles(**blocks_it[j], typelen);
+ for (std::vector<r_Minterval>::iterator it = subtiles->begin(); it != subtiles->end(); it++)
+ {
+ result->push_back(*it);
+
+#ifdef _VISUALIZE_2D_DECOMP_
+ if (domain.dimension() == 2)
+ (*vis) << (*it);
+#endif
+ }
+
+ delete subtiles;
+ }
+ else // No subtiling needed
+ {
+ // Insert block as it is
+ result->push_back(**blocks_it[j]);
+
+#ifdef _VISUALIZE_2D_DECOMP_
+ if (domain.dimension() == 2)
+ (*vis) << (**blocks_it[j]);
+#endif
+ }
+ }
+ }
+
+#ifdef _VISUALIZE_2D_DECOMP_
+ if (domain.dimension() == 2)
+ {
+ vis->set_pen(255, 255, 0);
+
+ interest_area.seek_begin();
+ while (interest_area.not_done())
+ {
+ (*vis) << (*interest_area);
+ ++interest_area;
+ }
+ }
+#endif
+
+ }
+ else
+ {
+ // The result is just the sum of all blocks
+
+ result->insert(result->end(), Blocks_A->begin(), Blocks_A->end());
+ result->insert(result->end(), Blocks_B->begin(), Blocks_B->end());
+ result->insert(result->end(), Blocks_C->begin(), Blocks_C->end());
+
+ // Visualization
+
+#ifdef _VISUALIZE_2D_DECOMP_
+ if (domain.dimension() == 2)
+ {
+ vis->set_pen(255, 255, 0);
+ for (it_A.seek_begin(); it_A.not_done(); it_A++)
+ (*vis) << *it_A;
+
+ vis->set_pen(0, 255, 0);
+ for (it_B.seek_begin(); it_B.not_done(); it_B++)
+ (*vis) << *it_B;
+
+ vis->set_pen(0, 0, 255);
+ for (it_C.seek_begin(); it_C.not_done(); it_C++)
+ (*vis) << *it_C;
+ }
+#endif
+ }
+
+ // *** End of the main algorithm ***
+
+ // *** Clean up ***
+
+ delete part;
+ delete dir_domain;
+ delete Blocks_A;
+ delete Blocks_B;
+ delete Blocks_C;
+
+#ifdef _VISUALIZE_2D_DECOMP_
+ if (domain.dimension() == 2)
+ delete vis;
+#endif
+
+ // Return result
+
+ return result;
+}
+
+
+
+std::ostream& operator<<(std::ostream& os, const Classified_Block block);
+
+
+Classified_Block::Classified_Block(int count)
+ : intersection_count(count)
+ {
+ }
+
+Classified_Block::Classified_Block(const r_Minterval& b, int count)
+ : intersection_count(count),
+ block(b)
+ {
+ }
+
+
+bool Classified_Block::operator==(const Classified_Block& other) const
+{
+ return (this->block == other.block)
+ && (this->intersection_count == other.intersection_count);
+}
+
+bool Classified_Block::operator!=(const Classified_Block& other) const
+{
+ return !(*this == other);
+}
+
+
+std::ostream& operator<<(std::ostream& os, const Classified_Block block)
+{
+ os << "CBlock(" << block.intersection_count << "x: " << block.block << ")";
+
+ return os;
+}
diff --git a/rasodmg/interesttiling.hh b/rasodmg/interesttiling.hh
new file mode 100644
index 0000000..944ada8
--- /dev/null
+++ b/rasodmg/interesttiling.hh
@@ -0,0 +1,183 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: dirtiling.hh
+ *
+ * MODULE: rasodmg
+ * CLASS: r_Interest_Tiling
+ *
+ * COMMENTS:
+ * None
+*/
+
+#ifndef _R_INTERESTTILING_HH_
+#define _R_INTERESTTILING_HH_
+
+class r_Dir_Decompose;
+class r_Interest_Tiling;
+#include "rasodmg/tiling.hh"
+
+//@ManMemo: Module: {\bf rasodmg}
+
+/*@Doc:
+ This class implements the "Interesting Areas" tiling algorithm.
+ The user specifies which areas are of interest to him and tiling is
+ performed accordingly.
+
+ Example of usage:
+ The user says that [10:20, 50:60] and [18:50, 65:70] are of interest
+ to him in the [0:1000, 0:1000] domain. Tiling should be done according
+ to this setting. To specify this with this class the following code
+ would work:
+
+ ...
+
+ r_Minterval domain(2);
+ domain << r_Sinterval(0L, 1000L) << r_Sinterval(0L, 1000L);
+
+ r_Minteval interest1(2);
+ interest1 << r_Sinterval(10L, 20L) << r_Sinterval(50L, 60L);
+
+ r_Minterval interest2(2);
+ interest2 << r_Sinterval(18L, 50L) << r_Sinterval(65L, 70L);
+
+ std::vector<r_Minterval> interest_areas;
+ interest_areas.insert_element(interest1);
+ interest_areas.insert_element(interest2);
+
+ r_Interest_Tiling(interest_areas);
+
+ ...
+*/
+
+class r_Interest_Tiling : public r_Dimension_Tiling
+{
+ public:
+
+ /// Possible strategies to limit the tilesize
+ enum Tilesize_Limit {NO_LIMIT, REGROUP, SUB_TILING, REGROUP_AND_SUBTILING, NUMBER};
+
+ /// read everything from an encoded string
+ /// e.g. "2;[0:9,0:9];[100:109,0:9];100;REGROUPSUBTILING"
+ r_Interest_Tiling(const char* encoded) throw (r_Error);
+
+ r_Interest_Tiling(r_Dimension dim,
+ const std::vector<r_Minterval>& interest_areas,
+ r_Bytes ts = RMInit::clientTileSize,
+ Tilesize_Limit strat = SUB_TILING) throw (r_Error);
+ /**
+ It takes as parameter a list containing the areas of interest to
+ the user and also the tilesize to be used.
+ The constructor also takes as parameter the tilesize limitation
+ strategy, that can be the following:
+
+ NO_LIMIT: The generated blocks can have any size.
+ REGROUP: Only when performing grouping/merging of blocks, the
+ size of the resulting block of two merges is checked
+ against tilesize. If it's bigger, they are not merged.
+ Blocks larger than tilesize may exist (for instance,
+ if the user specifies an interest area larger then
+ tilesize).
+ SUB_TILING: In this strategie, regrouping is done regardless of the
+ size of the generated blocks. After all the blocks are
+ created, sub-tiling is performed on those whose size is
+ larger than tilesize.
+ REGROUP_AND_SUBTILING: This combines the last two strategies. When
+ merging blocks, blocks larger than tilesize are never
+ created and, when the final blocks are all created,
+ sub-tiling is performed on those whose size is larger
+ then tilesize.
+ An exception is thrown when the dimensions of the domains does not match the
+ specified dimension.
+ */
+
+ virtual ~r_Interest_Tiling();
+
+ std::vector<r_Minterval>* compute_tiles(const r_Minterval& obj_domain, r_Bytes cell_size) const throw (r_Error);
+
+ virtual void print_status(std::ostream& os) const;
+
+ virtual r_Tiling* clone() const;
+
+ virtual r_Tiling_Scheme get_tiling_scheme() const;
+
+ //@ManMemo: Module: {\bf raslib}
+ /**
+ Get a tilesize limit for a tilisize limit name
+ */
+ static r_Interest_Tiling::Tilesize_Limit get_tilesize_limit_from_name(const char* name);
+ //@ManMemo: Module: {\bf raslib}
+ /**
+ Get a tilisize limit name for a tilesize limit
+ */
+ static const char* get_name_from_tilesize_limit(Tilesize_Limit tsl);
+
+ static const char* description;
+
+ protected: // methods.
+
+ /// Given a domain and a set of interest areas (internal) gener. partition
+ std::vector<r_Dir_Decompose>* make_partition(const r_Minterval& domain) const;
+
+ /// The Block types (A, B or C)
+ enum Blocks_Type {BLOCKS_A, BLOCKS_B, BLOCKS_C };
+ /**
+ A Blocks ---> Blocks that belong to two or more interest zones
+ (non-groupable)
+ B Blocks ---> Blocks within the same interest zone
+ (groupable by interest zone)
+ C Blocks ---> Blocks outside interest zones
+ (groupable)
+ */
+
+ /// Merge as many blocks together in a list as possible
+ std::vector<r_Minterval>* group(std::vector<r_Minterval>& blocks, r_Bytes typelen, Blocks_Type btype) const;
+ /**
+ Parameters: the block list, the lenght of the base cells and
+ the type of the block (A, B or C)
+ */
+
+ /// Tilesize limitation strategie
+ Tilesize_Limit ts_strat;
+
+ /// Interest areas
+ std::vector<r_Minterval> iareas;
+
+
+ //@ManMemo: Module: {\bf raslib}
+ /**
+ The names of all tilesizelimit types, to avoid redundant storage and inconsistencies.
+ The variable name convention is the prefix tilisizelimit_name_ followed by the name
+ of the data format in lower case, i.e. for NOLIMIT tilisizelimit_name_nolimit.
+ In addition there's an array of names all_tilesizelimit_names where the tilesize limit
+ can be used as index to get the name.
+ */
+ static const char* tilesizelimit_name_nolimit;
+ static const char* tilesizelimit_name_regroup;
+ static const char* tilesizelimit_name_subtiling;
+ static const char* tilesizelimit_name_regroupandsubtiling;
+
+ static const char* all_tilesizelimit_names[r_Interest_Tiling::NUMBER];
+};
+
+#endif
diff --git a/rasodmg/iterator.cc b/rasodmg/iterator.cc
new file mode 100644
index 0000000..cd9e167
--- /dev/null
+++ b/rasodmg/iterator.cc
@@ -0,0 +1,216 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: iterator.cc
+ *
+ * MODULE: rasodmg
+ * CLASS: r_Iterator
+ *
+ * COMMENTS:
+ * None
+*/
+
+static const char rcsiditerator[] = "@(#)rasodmg, r_Iterator: $Id: iterator.cc,v 1.18 2002/08/23 11:18:44 schatz Exp $";
+
+#include <iostream>
+using namespace std;
+
+#include "rasodmg/iterator.hh"
+
+#ifdef EARLY_TEMPLATE
+#ifndef __EXECUTABLE__
+#define __EXECUTABLE__
+#define ITERATOR_NOT_SET
+#endif
+#endif
+
+#include "rasodmg/collection.hh"
+
+#ifdef ITERATOR_NOT_SET
+#undef __EXECUTABLE__
+#endif
+
+template<class T>
+r_Iterator<T>::r_Iterator()
+{
+ // use default constructor only with assignment operator!
+ collection = 0;
+ ptr = 0;
+ ndone = 0;
+}
+
+template<class T>
+r_Iterator<T>::r_Iterator( const r_Iterator<T>& iter )
+{
+ collection = iter.collection;
+ ptr = iter.ptr;
+ ndone = iter.ndone;
+}
+
+template<class T>
+r_Iterator<T>::r_Iterator( r_Collection<T>& source, int removed_objects )
+{
+ collection = &source;
+ // sorry for this awful cast but there is
+ // no standard conversion of r_Collection<T>::CNode* to r_Collection::CNode*
+ if( removed_objects )
+ ptr = (typename r_Collection<T>::CNode*)source.removed_objects;
+ else
+ ptr = (typename r_Collection<T>::CNode*)source.coll;
+
+ ndone = (ptr->elem != 0);
+}
+
+template<class T>
+r_Iterator<T>::~r_Iterator()
+{
+}
+
+template<class T>
+r_Iterator<T>&
+r_Iterator<T>::operator=( const r_Iterator<T>& iter )
+{
+ if( this != &iter )
+ {
+ collection = iter.collection;
+ ptr = iter.ptr;
+ ndone = iter.ndone;
+ }
+
+ return *this;
+}
+
+template<class T>
+int
+r_Iterator<T>::is_equal(const r_Iterator<T>& iter) const
+{
+ if ( collection == iter.collection)
+ if ( ptr == iter.ptr )
+ return 1;
+ return 0;
+}
+
+
+template<class T>
+int
+operator==( const r_Iterator<T>& iter1, const r_Iterator<T>& iter2 )
+{
+ return iter1.is_equal(iter2);
+}
+
+template<class T>
+int
+operator!=( const r_Iterator<T>& iter1, const r_Iterator<T>& iter2 )
+{
+ return !iter1.is_equal(iter2);
+}
+
+template<class T>
+r_Iterator<T>&
+r_Iterator<T>::operator++()
+{
+ // ++prefix operator
+
+ if ( !ndone )
+ throw r_Error( r_Error::r_Error_IteratorExhausted );
+ if ( ptr->next != 0 )
+ ptr = ptr->next;
+ else
+ ndone = 0;
+
+ return *this;
+}
+
+template<class T>
+r_Iterator<T>
+r_Iterator<T>::operator++( int )
+{
+ // postfix++ operator
+ // create a copy of this, increment the original and return the copy
+ r_Iterator<T> result( *this );
+
+ operator++();
+
+ return result;
+}
+
+template<class T>
+T
+r_Iterator<T>::operator*()
+ throw( r_Error )
+{
+ if ( !ndone || ptr->elem == 0 )
+ {
+ r_Error err = r_Error( r_Error::r_Error_IteratorExhausted );
+ throw err;
+ }
+
+ // The following line was return *(ptr->elem) but the HP compiler had problems
+ // while instantiating the code. CNode::elem was of a different type than T.
+ return *((T*)ptr->elem);
+}
+
+template<class T>
+T
+r_Iterator<T>::get_element() const
+ throw( r_Error )
+{
+ if ( !ndone || ptr->elem == 0 )
+ throw r_Error( r_Error::r_Error_IteratorExhausted );
+ else
+ return *(ptr->elem);
+}
+
+template<class T>
+int
+r_Iterator<T>::next( T& element )
+{
+ if ( !ndone || ptr->elem == 0 ) return 0;
+ element = *(ptr->elem);
+ advance();
+ return 1;
+}
+
+template<class T>
+void
+r_Iterator<T>::reset( int removed_objects )
+{
+ if( removed_objects )
+ ptr = (typename r_Collection<T>::CNode*)collection->removed_objects;
+ else
+ ptr = (typename r_Collection<T>::CNode*)collection->coll;
+
+ ndone = (ptr->elem != 0);
+}
+
+template<class T>
+void
+r_Iterator<T>::advance()
+{
+ if ( !ndone )
+ throw r_Error( r_Error::r_Error_IteratorExhausted );
+ if ( ptr->next != 0 )
+ ptr = ptr->next;
+ else
+ ndone = 0;
+}
diff --git a/rasodmg/iterator.hh b/rasodmg/iterator.hh
new file mode 100644
index 0000000..995e7b6
--- /dev/null
+++ b/rasodmg/iterator.hh
@@ -0,0 +1,137 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: iterator.hh
+ *
+ * MODULE: rasodmg
+ * CLASS: r_Iterator
+ *
+ * COMMENTS:
+ * None
+*/
+
+#ifndef _D_ITERATOR_
+#define _D_ITERATOR_
+
+#include "raslib/error.hh"
+
+#ifdef __VISUALC__
+template <class T> class r_Collection;
+#else
+#include "rasodmg/collection.hh"
+#endif
+
+//@ManMemo: Module: {\bf rasodmg}
+
+
+
+/*@Doc:
+
+ The template class \Ref{r_Iterator} defines the generic
+ behavior for iteration. All iterators use a consistent protocol
+ for sequentially returning each element from the collection over
+ which the iteration is defined.
+ When an iterator is constructed, it is either initialized with
+ another iterator or is set to null. When an iterator is constructed
+ via the {\tt create_iterator()} method defined in \Ref{r_Collection},
+ the iterator is initailized to point to the first element, if there
+ is one.
+*/
+
+template <class T>
+class r_Iterator
+{
+ public:
+ /// default constructor
+ r_Iterator();
+ /// copy constructor
+ r_Iterator( const r_Iterator<T>& iter );
+ /// constructor getting the collection on which to iterate (used for {\tt r_Collection::create_iterator()})
+ r_Iterator( r_Collection<T>& source, int removed_objects=0 );
+ /**
+ Creates an iterator which points to the first element of the element collection. If
+ {\tt removed_objects} ist set to 1, the iterator points to the first element of
+ the list containing the removed objects (for internal use).
+ */
+
+ /// destructor
+ ~r_Iterator();
+
+ /// assignment operator
+ r_Iterator<T>& operator=( const r_Iterator<T>& iter );
+ /// comparisons: equal if they point to the same element in the same collection,
+ /// not equal if they point to different collections or elements
+ int is_equal( const r_Iterator<T>& iter ) const;
+
+ /// prefix incrementor
+ r_Iterator<T>& operator++();
+ /// postfix incrementor
+ r_Iterator<T> operator++( int );
+
+ /// re-initialize the iterator to the start of iteration for the same collection
+ void reset( int removed_objects=0 );
+ /**
+ Resets the iterator to point to the first element of the element collection. If
+ {\tt removed_objects} ist set to 1, the iterator points to the first element of
+ the list containing the removed objects (for internal use).
+ */
+
+ /// returns 1 if there are more elements to be visited in the iteration and 0 if iteration is complete
+ inline int not_done() const;
+ /// advances one element
+ void advance();
+
+ /// the dereference operator gets the actual element
+ T operator*() throw( r_Error );
+ /// gets the actual element
+ T get_element() const throw( r_Error );
+
+ /// gets the actual element, advances one element, and returns whether iteration is complete or not
+ int next( T& element );
+
+ /// replaces the actual element (can only be used with r_List)
+ void replace_element( const T& element );
+
+ private:
+ /// flag for end of iteration
+ int ndone;
+ /// pointer to the collection on which is iterated
+ r_Collection<T>* collection;
+ /// pointer to the actual element
+ typename r_Collection<T>::CNode* ptr;
+
+};
+
+#include "iterator.icc"
+
+#ifdef EARLY_TEMPLATE
+#ifdef __EXECUTABLE__
+#ifdef __VISUALC__
+#include "iterator.cpp"
+#else
+#include "iterator.cc"
+#endif
+#endif
+#endif
+
+#endif
diff --git a/rasodmg/iterator.icc b/rasodmg/iterator.icc
new file mode 100644
index 0000000..5bd4974
--- /dev/null
+++ b/rasodmg/iterator.icc
@@ -0,0 +1,39 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INLINE SOURCE: iterator.icc
+ *
+ * MODULE: rasodmg
+ * CLASS: r_Iterator
+ *
+ * COMMENTS:
+ * None
+*/
+
+
+template<class T>
+inline int
+r_Iterator<T>::not_done() const
+{
+ return ndone;
+}
diff --git a/rasodmg/marray.cc b/rasodmg/marray.cc
new file mode 100644
index 0000000..403c91f
--- /dev/null
+++ b/rasodmg/marray.cc
@@ -0,0 +1,354 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: marray.cc
+ *
+ * MODULE: rasodmg
+ * CLASS: r_Marray
+ *
+ * COMMENTS:
+ * None
+*/
+
+static const char rcsidmarray[] = "@(#)rasodmg, r_Marray: $Id: marray.cc,v 1.36 2002/08/23 11:18:44 schatz Exp $";
+
+#include "rasodmg/marray.hh"
+
+#ifdef __VISUALC__
+#ifndef __EXECUTABLE__
+#define __EXECUTABLE__
+#define MARRAY_NOT_SET
+#endif
+#endif
+
+#include "rasodmg/database.hh"
+#include "clientcomm/clientcomm.hh"
+
+#ifdef COLLECTION_NOT_SET
+#undef __EXECUTABLE__
+#endif
+
+#include "raslib/rmdebug.hh"
+
+#include <string.h> // for memcpy()
+#include <iostream>
+#include <iomanip>
+
+
+
+template<class T>
+r_Marray<T>::r_Marray() throw(r_Error)
+ : r_GMarray()
+{
+}
+
+
+
+template<class T>
+r_Marray<T>::r_Marray( const r_Minterval& initDomain, r_Storage_Layout* stl ) throw(r_Error)
+ : r_GMarray( initDomain, sizeof(T), stl )
+{
+}
+
+
+
+template<class T>
+r_Marray<T>::r_Marray( const r_Minterval& initDomain, const T& value, r_Storage_Layout* stl ) throw(r_Error)
+ : r_GMarray( initDomain, sizeof(T), stl )
+{
+ T* dataPtr = (T*)data;
+
+ for( unsigned long i=0; i<domain.cell_count(); i++ )
+ dataPtr[i] = value;
+}
+
+
+
+template<class T>
+r_Marray<T>::r_Marray( const r_Minterval& initDomain, r_InitFunction function, r_Storage_Layout* stl ) throw(r_Error)
+ : r_GMarray( initDomain, sizeof(T), stl )
+{
+ r_Dimension d;
+ int done = 0;
+ r_Point pt( domain.dimension() );
+
+ // memory pointer of type T
+ T* dataPtr = (T*)data;
+
+ // initialize the iterating point to the lowest values in each dimension
+ for( d=0; d<pt.dimension(); d++ )
+ pt[d] = domain[d].low();
+
+ // iterate point pt through the spatial domain and apply the
+ // initializing function for each point
+ while(!done)
+ {
+ // execute function on cell
+ dataPtr[domain.cell_offset( pt )] = (*function)( pt );
+
+ // increment coordinate
+ d = 0;
+ while( ++pt[d] > domain[d].high() )
+ {
+ pt[d] = domain[d].low();
+ d++;
+ if(d >= domain.dimension())
+ {
+ done = 1;
+ break;
+ }
+ }
+ }
+}
+
+
+
+template<class T>
+r_Marray<T>::r_Marray( const r_Marray<T> &obj ) throw(r_Error)
+ : r_GMarray( obj )
+{
+ RMDBCLASS( "r_Marray<T>", "r_Marray<T>( const r_Marray<T>& )", "rasodmg", __FILE__, __LINE__ )
+}
+
+
+
+template<class T>
+r_Marray<T>::r_Marray( r_GMarray &obj ) throw(r_Error)
+ : r_GMarray( obj )
+{
+}
+
+
+
+template<class T>
+r_Marray<T>::~r_Marray()
+{
+}
+
+
+
+template<class T>
+const r_Marray<T> &r_Marray<T>::operator=( const r_Marray<T> &marray )
+{
+ return (r_Marray<T> &) r_GMarray::operator=( marray );
+}
+
+
+
+template<class T>
+r_Marray<T>
+r_Marray<T>::operator[] ( long cordnt ) const
+ throw( r_Eindex_violation )
+{
+ // check if self does not just represent a cell
+ if( domain.dimension() == 0 )
+ throw( r_Eindex_violation( cordnt, 0, 0 ) );
+
+ // check if the index is valid
+ if( cordnt < domain[0].low() || cordnt > domain[0].high() )
+ throw( r_Eindex_violation( cordnt, domain[0].low(), domain[0].high() ) );
+
+ // build a new spatial domain
+ r_Minterval newDomain( domain.dimension()-1 );
+
+ // and initialize it
+ for( int i=0; i<newDomain.dimension(); i++ )
+ newDomain[i] = domain[i+1];
+
+ // build a new Marray
+ r_Marray<T> newMDD( newDomain );
+
+ // and fill it with data
+ unsigned long newCellCount = newDomain.cell_count();
+ unsigned long byteCount = ( newDomain.dimension() ? newDomain.cell_count() : 1 ) * type_length;
+ T* dataPtr = (T*)data; // typed pointer to the data
+
+ memcpy( newMDD.data, &(dataPtr[(cordnt-domain[0].low())*newCellCount]), (unsigned int)byteCount );
+
+ return newMDD;
+}
+
+
+
+template<class T>
+r_Marray<T>
+r_Marray<T>::operator[] ( const r_Minterval& mint ) const
+ throw( r_Edim_mismatch )
+{
+ unsigned long offset;
+ r_Point pt;
+ int pt_valid;
+
+ // first test dimensionality
+ if( domain.dimension() != mint.dimension() )
+ throw( r_Edim_mismatch( domain.dimension(), mint.dimension() ) );
+
+ // build a new Marray with undefined cells
+ r_Marray<T> newMDD( mint );
+ T* typedDataPtr = (T*)newMDD.data;
+
+ // iterate through the domain and fill the values where available
+ for( offset=0; offset<mint.cell_count(); offset++ )
+ {
+ pt = mint.cell_point(offset);
+
+ // Test if pt is a valid index in the spatial domain of the
+ // self object.
+ pt_valid = 1;
+ for( int dim=0; dim<domain.dimension() && pt_valid; dim++ )
+ pt_valid &= pt[dim] >= domain[dim].low() && pt[dim] <= domain[dim].high();
+
+ if( pt_valid )
+ typedDataPtr[offset] = operator[](pt);
+
+ // The points where pt_valid is not true are undefined, so nothing has to be
+ // done in the catch clause.
+ // Attention: Purify is reporting that unitialized memory is read when accessing
+ // these points.
+ }
+
+ return newMDD;
+}
+
+
+
+template<class T>
+const T&
+r_Marray<T>::operator[] ( const r_Point& point ) const
+ throw( r_Edim_mismatch, r_Eindex_violation )
+{
+ // first test dimensionality
+ if( point.dimension() != domain.dimension() )
+ throw( r_Edim_mismatch( point.dimension(), domain.dimension() ) );
+
+ T* typedDataPtr = (T*)data;
+
+ try
+ {
+ return typedDataPtr[ domain.cell_offset( point ) ];
+ }
+ catch( ... ) // exception can be r_Eindex_violation
+ {
+ throw; // rethrow it
+ }
+}
+
+
+
+template<class T>
+T&
+r_Marray<T>::operator[] ( const r_Point& point )
+ throw( r_Edim_mismatch, r_Eindex_violation )
+{
+ // first test dimensionality
+ if( point.dimension() != domain.dimension() )
+ throw( r_Edim_mismatch( point.dimension(), domain.dimension() ) );
+
+ T* typedDataPtr = (T*)data;
+
+ try
+ {
+ return typedDataPtr[ domain.cell_offset( point ) ];
+ }
+ catch( ... ) // exception can be r_Eindex_violation
+ {
+ throw; // rethrow it
+ }
+}
+
+
+
+template<class T>
+r_Marray<T>::operator T()
+ throw( r_Eno_cell )
+{
+ // check if the spatial domain of self is really zero
+ if( domain.dimension() > 0 || data == 0 )
+ throw r_Eno_cell();
+
+ return *((T*)data);
+}
+
+
+
+template<class T>
+void
+r_Marray<T>::print_status( std::ostream& s ) const
+{
+ r_GMarray::print_status( s );
+
+ /*
+
+ The following code part prints the content of the array by piping
+ each cell into the specified output stream. This implementation needs
+ the stream operator to be defined for each template type T.
+
+ if( domain.dimension() )
+ {
+ r_Point p(domain.dimension());
+ int done = 0;
+ r_Dimension i = 0;
+
+ // initialize point
+ for(i = 0; i < domain.dimension(); i++)
+ p << domain[i].low();
+
+ s << "Domain: " << domain << endl;
+
+ // iterate over all cells
+ while(!done)
+ {
+ // print cell
+ // if( hex_output )
+ // s << setw(8) << hex << (int)operator[]( p );
+ // else
+ s << setw(8) << operator[]( p );
+
+
+ // increment coordinate
+ i = 0;
+ while( ++p[i] > domain[i].high() )
+ {
+ s << endl;
+ p[i] = domain[i].low();
+ i++;
+ if(i >= domain.dimension())
+ {
+ done = 1;
+ break;
+ }
+ }
+ if(i > 1) s << endl;
+ }
+ }
+ else
+ // print cell
+ // if( hex_output )
+ // s << "Cell value " << setw(8) << hex << (int)*((T*)data) << endl;
+ // else
+ s << "Cell value " << setw(8) << *((T*)data) << endl;
+ */
+}
+
+
+
diff --git a/rasodmg/marray.hh b/rasodmg/marray.hh
new file mode 100644
index 0000000..8b5e5ea
--- /dev/null
+++ b/rasodmg/marray.hh
@@ -0,0 +1,145 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: marray.hh
+ *
+ * MODULE: rasodmg
+ * CLASS: r_Marray
+ *
+ * COMMENTS:
+ * None
+*/
+
+#ifndef _D_MARRAY_
+#define _D_MARRAY_
+
+#include "rasodmg/gmarray.hh"
+
+#include <iostream>
+
+using namespace std;
+
+
+//@ManMemo: Module: {\bf rasodmg}
+
+/*@Doc:
+
+ The central class of the library for representing an MDD
+ object is named r_Marray. Through overloading operators,
+ the handling of an MDD object is similar to the usage of
+ a normal C or C++ array from the programmers point of view.
+
+*/
+
+template<class T>
+class r_Marray : public r_GMarray
+{
+ public:
+ /// function type for initialization function
+ typedef T (*r_InitFunction)(const r_Point&);
+
+ /// default constructor (no memory is allocated!)
+ r_Marray() throw(r_Error);
+
+ /// constructor for uninitialized MDD objects
+ r_Marray( const r_Minterval&, r_Storage_Layout* stl = 0 ) throw(r_Error);
+ /**
+ If a storage layout pointer is provided, the object refered to is
+ taken and memory control moves to the \Ref{r_Marray} class.
+ The user has to take care, that each creation of \Ref{r_Marray}
+ objects get a new storage layout object.
+ */
+
+ /// constructor for constant MDD objects
+ r_Marray( const r_Minterval&, const T&, r_Storage_Layout* stl = 0 ) throw(r_Error);
+ /**
+ If a storage layout pointer is provided, the object refered to is
+ taken and memory control moves to the \Ref{r_Marray} class.
+ The user has to take care, that each creation of \Ref{r_Marray}
+ objects get a new storage layout object.
+ */
+
+ /// constructor with initializing function
+ r_Marray( const r_Minterval&, r_InitFunction, r_Storage_Layout* stl = 0 ) throw(r_Error);
+ /**
+ If a storage layout pointer is provided, the object refered to is
+ taken and memory control moves to the \Ref{r_Marray} class.
+ The user has to take care, that each creation of \Ref{r_Marray}
+ objects get a new storage layout object.
+ */
+
+ /// copy constructor
+ r_Marray( const r_Marray<T>& ) throw(r_Error);
+
+ /// constructor getting an object of type r_GMarray
+ r_Marray( r_GMarray& ) throw(r_Error);
+ /*
+ This constructor is used for converting general \Ref{r_GMarray} objects
+ to cell type safe \Ref{r_Marray} objects. Care has to be taken because
+ the memory of the \Ref{r_GMarray} can not be used anymore; it is passed
+ to the \Ref{r_Marray<T>} object.
+ */
+
+ /// destructor
+ virtual ~r_Marray();
+
+ /// assignment: cleanup + copy
+ const r_Marray& operator= ( const r_Marray& );
+
+ /// subscript operator for projection in the 1st dimension
+ r_Marray<T> operator[]( long ) const
+ throw(r_Eindex_violation);
+
+ /// subscript operator for restriction/extension combination
+ r_Marray<T> operator[]( const r_Minterval& ) const
+ throw( r_Edim_mismatch );
+
+ /// subscript operator for read access of a cell
+ const T& operator[]( const r_Point& ) const
+ throw(r_Edim_mismatch, r_Eindex_violation);
+
+ /// subscript operator for write access of a cell
+ T& operator[]( const r_Point& )
+ throw(r_Edim_mismatch, r_Eindex_violation);
+
+ /// cast operator for converting to base type for cell access
+ operator T()
+ throw( r_Eno_cell );
+
+ /// writes the state of the object to the specified stream
+ virtual void print_status( std::ostream& s = cout ) const;
+};
+
+#include "rasodmg/marray.icc"
+
+#ifdef EARLY_TEMPLATE
+#ifdef __EXECUTABLE__
+#ifdef __VISUALC__
+#include "rasodmg/marray.cpp"
+#else
+#include "rasodmg/marray.cc"
+#endif
+#endif
+#endif
+
+#endif
diff --git a/rasodmg/marray.icc b/rasodmg/marray.icc
new file mode 100644
index 0000000..98796a3
--- /dev/null
+++ b/rasodmg/marray.icc
@@ -0,0 +1,31 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INLINE SOURCE: marray.icc
+ *
+ * MODULE: rasodmg
+ * CLASS: r_Marray
+ *
+ * COMMENTS:
+ * None
+*/
diff --git a/rasodmg/object.cc b/rasodmg/object.cc
new file mode 100644
index 0000000..8b047dd
--- /dev/null
+++ b/rasodmg/object.cc
@@ -0,0 +1,603 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: object.cc
+ *
+ * MODULE: rasodmg
+ * CLASS: r_Object
+ *
+ * COMMENTS:
+ * None
+*/
+
+#include "mymalloc/mymalloc.h"
+
+static const char rcsid[] = "@(#)rasodmg, r_Object: $Id: object.cc,v 1.37 2002/08/19 14:09:32 schatz Exp $";
+
+#include "raslib/rmdebug.hh"
+#include "raslib/type.hh"
+#include "raslib/error.hh"
+
+#include "rasodmg/object.hh"
+
+#ifdef __VISUALC__
+#ifndef __EXECUTABLE__
+#define __EXECUTABLE__
+#define OBJECT_NOT_SET
+#endif
+#endif
+
+#include "rasodmg/transaction.hh"
+#include "rasodmg/database.hh"
+#include "clientcomm/clientcomm.hh"
+
+#ifdef OBJECT_NOT_SET
+#undef __EXECUTABLE__
+#endif
+
+#include <iostream>
+
+
+// At the beginning, next and last object types/status are not specified.
+r_Object::ObjectStatus r_Object::next_object_status = r_Object::no_status;
+r_Object::ObjectType r_Object::next_object_type = r_Object::no_object;
+char* r_Object::next_object_type_name = 0;
+r_OId r_Object::next_object_oid = r_OId();
+r_Object::ObjectType r_Object::last_object_type = r_Object::no_object;
+
+
+
+r_Object::r_Object()
+ : object_status( next_object_status ),
+ object_name(0),
+ type_name(0),
+ type_structure(0),
+ type_schema(0),
+ oid()
+{
+ RMDBCLASS( "r_Object", "r_Object()", "rasodmg", __FILE__, __LINE__ )
+
+ if( next_object_type_name ) type_name = strdup( next_object_type_name );
+
+ if( next_object_type == persistent_object )
+ RMInit::logOut << "Error: A peristent object is constructed with default constructor." << std::endl;
+ else
+ object_type = transient_object;
+
+ internal_obj_type = 0;
+
+ // reset next object type/status
+ r_Object::next_object_type = no_object;
+ r_Object::next_object_status = no_status;
+ r_Object::next_object_type_name = 0;
+ r_Object::next_object_oid = r_OId();
+}
+
+
+
+r_Object::r_Object( unsigned short objType ) throw(r_Error)
+ : object_status( next_object_status ),
+ object_name(0),
+ type_name(0),
+ type_structure(0),
+ type_schema(0),
+ oid()
+{
+ RMDBCLASS( "r_Object", "r_Object( unsigned short )", "rasodmg", __FILE__, __LINE__ )
+
+ if( next_object_type_name ) type_name = strdup( next_object_type_name );
+
+ if( next_object_type == persistent_object )
+ {
+ if( r_Transaction::actual_transaction == 0 )
+ {
+ RMInit::logOut << "Error: Tried to create a persistent object outside a transaction." << std::endl;
+ throw r_Error(r_Error::r_Error_TransactionNotOpen);
+ }
+
+ object_type = persistent_object;
+
+ switch( object_status )
+ {
+ case created:
+ // In case the object is newly created, get a new oid and assign it to the object.
+ oid = r_Database::actual_database->get_new_oid( objType );
+ break;
+ case read:
+ case transient:
+ // In case the object is read from db, use the oid stored in next_object_oid.
+ oid = next_object_oid;
+ break;
+ default:
+ RMDBGONCE(0, RMDebug::module_raslib, "r_Object", "r_Object(objType) bad object_status " << object_status);
+ break;
+ }
+
+ // Add the object to the list of persistent objects in the current transaction.
+ if( oid.is_valid() )
+ r_Transaction::actual_transaction->add_object_list( r_Ref<r_Object>( oid, this ) );
+ else
+ r_Transaction::actual_transaction->add_object_list( r_Ref<r_Object>( this ) );
+
+ }
+ else
+ object_type = transient_object;
+
+ internal_obj_type = objType;
+
+ // reset next object type/status
+ r_Object::next_object_type = no_object;
+ r_Object::next_object_status = no_status;
+ r_Object::next_object_type_name = 0;
+ r_Object::next_object_oid = r_OId();
+}
+
+
+
+/* OBSOLETE
+r_Object::r_Object( unsigned short objType, const char* name ) throw(r_Error)
+ : object_status( next_object_status ),
+ object_name( strdup(name) ),
+ type_name(0),
+ type_structure(0),
+ type_schema(0),
+ oid()
+{
+ RMANDEBUGOUT( "r_Object::r_Object( const char* name)" )
+
+ if( next_object_type_name ) type_name = strdup( next_object_type_name );
+
+ if( next_object_type == persistent_object )
+ {
+ if( r_Transaction::actual_transaction == 0 )
+ {
+ RMInit::logOut << "Error: Tried to create a persistent object outside a transaction." << std::endl;
+ throw r_Error(r_Error::r_Error_TransactionNotOpen);
+ }
+
+ object_type = persistent_object;
+
+ // get a new oid and assign it to the object
+ // oid = r_Database::actual_database->get_new_oid( objType );
+
+ // add the object to the list of persistent objects in the actual transaction
+ r_Transaction::actual_transaction->add_object_list( r_Ref<r_Object>( this ) );
+ }
+ else
+ object_type = transient_object;
+
+ // reset next object type/status
+ r_Object::next_object_type = no_object;
+ r_Object::next_object_status = no_status;
+ r_Object::next_object_type_name = 0;
+ r_Object::next_object_oid = r_OId();
+}
+*/
+
+
+r_Object::r_Object( const r_Object& obj, unsigned short objType ) throw(r_Error)
+ : object_status( next_object_status ),
+ object_name(0),
+ type_name(0),
+ type_structure(0),
+ type_schema(0),
+ oid()
+{
+ RMDBCLASS( "r_Object", "r_Object( const r_Object& )", "rasodmg", __FILE__, __LINE__ )
+
+ if( next_object_type_name ) type_name = strdup( next_object_type_name );
+
+ if( next_object_type == persistent_object )
+ {
+ if( r_Transaction::actual_transaction == 0 )
+ {
+ RMInit::logOut << "Error: Tried to create a persistent object outside a transaction." << std::endl;
+ throw r_Error(r_Error::r_Error_TransactionNotOpen);
+ }
+
+ object_type = persistent_object;
+
+ switch( object_status )
+ {
+ case created:
+ // In case the object is newly created, get a new oid and assign it to the object.
+ oid = r_Database::actual_database->get_new_oid( objType );
+ break;
+ case read:
+ case transient:
+ // In case the object is read from db, use the oid stored in next_object_oid.
+ oid = next_object_oid;
+ break;
+ default:
+ RMDBGONCE(0, RMDebug::module_raslib, "r_Object", "r_Object(obj, objType) bad object_status " << object_status);
+ break;
+ }
+
+ // Add the object to the list of persistent objects in the actual transaction.
+ if( oid.is_valid() )
+ r_Transaction::actual_transaction->add_object_list( r_Ref<r_Object>( oid, this ) );
+ else
+ r_Transaction::actual_transaction->add_object_list( r_Ref<r_Object>( this ) );
+ }
+ else
+ object_type = transient_object;
+
+ internal_obj_type = objType;
+
+ // reset next object type/status
+ r_Object::next_object_type = no_object;
+ r_Object::next_object_status = no_status;
+ r_Object::next_object_type_name = 0;
+ r_Object::next_object_oid = r_OId();
+
+ if( obj.object_name )
+ object_name = strdup( obj.object_name );
+
+ if( obj.type_name && !type_name )
+ type_name = strdup( obj.type_name );
+
+ if( obj.type_structure )
+ type_structure = strdup( obj.type_structure );
+}
+
+void
+r_Object::set_type_schema(const r_Type* tyy) throw (r_Error)
+ {
+ if (type_schema)
+ {
+ RMInit::logOut << "r_Object::set_type_schema(" << tyy->name() << ") this object has already a type" << std::endl;
+ throw r_Error(ILLEGALARGUMENT);
+ }
+ type_schema = tyy->clone();
+ }
+
+
+/*************************************************************
+ * Method name...: ~r_Object()
+ *
+ * Arguments.....:
+ * none
+ * Return value..:
+ * none
+ * Description...: Destructor.
+ ************************************************************/
+
+r_Object::~r_Object()
+{
+ RMDBCLASS( "r_Object", "~r_Object()", "rasodmg", __FILE__, __LINE__ )
+
+ // Free memory in the transient case. In the persistent case, r_deactivate()
+ // is invoked at the commit/abort point.
+ if( test_type( transient_object ) )
+ r_deactivate();
+
+ object_status = deleted;
+
+ // store the object type for the delete operator
+ r_Object::last_object_type = object_type;
+}
+
+
+
+/*************************************************************
+ * Method name...: r_deactivate()
+ *
+ * Arguments.....:
+ * none
+ * Return value..:
+ * none
+ * Description...: This method is called when the object leaves
+ * the application cache. It frees all dynamic
+ * memory allocated within the class.
+ ************************************************************/
+void
+r_Object::r_deactivate()
+{
+ RMDBCLASS( "r_Object", "r_deactivate()", "rasodmg", __FILE__, __LINE__ )
+
+ if( type_schema )
+ {
+ delete type_schema;
+ type_schema = 0;
+ }
+
+ if( object_name )
+ {
+ free( object_name );
+ object_name = 0;
+ }
+
+ if( type_name )
+ {
+ free( type_name );
+ type_name = 0;
+ }
+
+ if( type_structure )
+ {
+ delete [] type_structure;
+ type_structure = 0;
+ }
+
+ oid.r_deactivate();
+}
+
+
+
+/*************************************************************
+ * Method name...: operator new( size_t size )
+ *
+ * Arguments.....:
+ * none
+ * Return value..:
+ * none
+ * Description...: New operator set the next_object_type and
+ * allocates memory for the object.
+ ************************************************************/
+void*
+r_Object::operator new( size_t size )
+{
+ RMDBCLASS( "r_Object", "operator new( size_t )", "rasodmg", __FILE__, __LINE__ )
+
+ r_Object::next_object_type = transient_object;
+ r_Object::next_object_status = created;
+ r_Object::next_object_type_name = 0;
+ r_Object::next_object_oid = r_OId();
+
+ void* a = mymalloc( size );
+ return a;
+}
+
+
+
+/*************************************************************
+ * Method name...: operator new( size_t size,
+ * r_Database *database,
+ * const char* type_name )
+ *
+ * Arguments.....:
+ * none
+ * Return value..:
+ * none
+ * Description...: New operator set the next_object_type and
+ * allocates memory for the object.
+ ************************************************************/
+void*
+r_Object::operator new( size_t size, r_Database* /*database*/, const char* type_name )
+{
+ RMDBCLASS( "r_Object", "operator new( size_t, r_Database, const char* )", "rasodmg", __FILE__, __LINE__ )
+
+ r_Object::next_object_type = persistent_object;
+ r_Object::next_object_status = created;
+ r_Object::next_object_type_name = (char*)type_name;
+ r_Object::next_object_oid = r_OId();
+
+ void* a = mymalloc( size );
+ return a;
+}
+
+
+
+void*
+r_Object::operator new( size_t size, const char* type_name )
+{
+ RMDBCLASS( "r_Object", "operator new( size_t, const char* )", "rasodmg", __FILE__, __LINE__ )
+
+ r_Object::next_object_type = transient_object;
+ r_Object::next_object_status = created;
+ r_Object::next_object_type_name = (char*)type_name;
+ r_Object::next_object_oid = r_OId();
+
+ void* a = mymalloc( size );
+ return a;
+}
+
+
+
+/*************************************************************
+ * Method name...: operator delete( void* obj_ptr )
+ *
+ * Arguments.....:
+ * none
+ * Return value..:
+ * none
+ * Description...: Delete operator.
+ * Transient objects are deleted immediately from
+ * main memory.
+ * Persistent objects have been marked as deleted in
+ * the destructor. Further accesses through a r_Ref raise
+ * an exception. Main memory is freed after the transaction
+ * commits.
+ ************************************************************/
+void
+r_Object::operator delete( void* obj_ptr )
+{
+ RMDBCLASS( "r_Object", "operator delete()", "rasodmg", __FILE__, __LINE__ )
+
+ if( r_Object::last_object_type == transient_object )
+ free( obj_ptr );
+
+ r_Object::last_object_type = no_object;
+}
+
+
+
+/*************************************************************
+ * Method name...: test_status( ObjectStatus status )
+ *
+ * Arguments.....:
+ * none
+ * Return value..:
+ * none
+ * Description...: Tests if status matches the object status. If so
+ * in returns 1, otherwise 0.
+ ************************************************************/
+int
+r_Object::test_status( ObjectStatus status )
+{
+ return ( status == object_status );
+}
+
+
+
+/*************************************************************
+ * Method name...: test_type( ObjectType type )
+ *
+ * Arguments.....:
+ * none
+ * Return value..:
+ * none
+ * Description...: Tests if type matches the object type. If so
+ * in returns 1, otherwise 0.
+ ************************************************************/
+int
+r_Object::test_type( ObjectType type )
+{
+ return ( type == object_type );
+}
+
+
+
+/*************************************************************
+ * Method name...: operator new( size_t size,
+ * r_Database *database,
+ * ObjectStatus status )
+ *
+ * Arguments.....:
+ * none
+ * Return value..:
+ * none
+ * Description...: New operator set the next_object_type to
+ * persistent object and the next_object_status to the
+ * given status. Memory for the object is allocated.
+ ************************************************************/
+void*
+r_Object::operator new( size_t size, r_Database* /*database*/, ObjectStatus status, const r_OId& oid )
+{
+ RMDBCLASS( "r_Object", "operator new( size_t, r_Database, ObjectStatus )", "rasodmg", __FILE__, __LINE__ )
+
+ r_Object::next_object_type = persistent_object;
+ r_Object::next_object_status = status;
+ r_Object::next_object_type_name = 0;
+ r_Object::next_object_oid = oid;
+
+ void* a = mymalloc( size );
+ return a;
+}
+
+
+
+const r_Type*
+r_Object::get_type_schema()
+{
+ if( !type_schema )
+ {
+ // If type structure not known then try to get it from the server
+ if ( (type_structure == NULL) || (strlen(type_structure) == 0) )
+ {
+ ClientComm::r_Type_Type typeType = (ClientComm::r_Type_Type)0;
+
+ // we need an open database and an active transaction
+ if ( r_Database::actual_database == NULL ) return NULL;
+ else
+ {
+ if ( r_Database::actual_database->get_status() == r_Database::not_open )
+ return NULL;
+ }
+ if ( r_Transaction::actual_transaction == NULL) return NULL;
+ else
+ {
+ if ( r_Transaction::actual_transaction->get_status() != r_Transaction::active )
+ return NULL;
+ }
+
+ // set the object type and contact the database if the type name is defined.
+ if ( internal_obj_type == 1 ) typeType = ClientComm::r_MDDType_Type;
+ else if ( internal_obj_type == 2 ) typeType = ClientComm::r_SetType_Type;
+ if ( (type_name == NULL) || (strlen(type_name) == 0) || (typeType == 0) )
+ return NULL;
+
+ try {
+ type_structure = r_Database::actual_database->getComm()->getTypeStructure( type_name, typeType );
+ }
+ catch(r_Error& errObj) {
+ RMInit::logOut << "r_Object::get_type_schema() failed retriving typestructure" << std::endl;
+ RMInit::logOut << "Error " << errObj.get_errorno() << " : " << errObj.what() << std::endl;
+ return NULL;
+ }
+ }
+
+ type_schema = r_Type::get_any_type( type_structure );
+ }
+ return type_schema;
+}
+
+
+
+void
+r_Object::update_obj_in_db()
+{
+ RMInit::logOut << " dummy implementation " << std::flush;
+}
+
+
+
+void
+r_Object::load_obj_from_db()
+{
+ RMInit::logOut << " dummy implementation " << std::flush;
+}
+
+
+
+void
+r_Object::delete_obj_from_db()
+{
+ RMDBCLASS( "r_Object", "delete_obj_from_db()", "rasodmg", __FILE__, __LINE__ )
+
+ if( object_name && strlen( object_name ) )
+ {
+ RMInit::logOut << object_name << "... " << std::flush;
+
+ // delete myself from the database
+ r_Database::actual_database->getComm()->deleteCollByName( object_name );
+ }
+ else
+ {
+ RMInit::logOut << "no name - take oid ... " << std::flush;
+
+ if( oid.get_local_oid() )
+ // delete myself from the database
+ r_Database::actual_database->getComm()->deleteObjByOId( oid );
+ else
+ RMInit::logOut << " no oid ... FAILED" << std::flush;
+ }
+}
+
+
+void
+r_Object::initialize_oid( const r_OId& initOId )
+{
+ oid = initOId;
+}
+
diff --git a/rasodmg/object.hh b/rasodmg/object.hh
new file mode 100644
index 0000000..d5fcbeb
--- /dev/null
+++ b/rasodmg/object.hh
@@ -0,0 +1,240 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: object.hh
+ *
+ * MODULE: rasodmg
+ * CLASS: r_Object
+ *
+ * COMMENTS:
+ * None
+*/
+
+#ifndef _D_OBJECT_
+#define _D_OBJECT_
+
+#include "raslib/error.hh"
+#include "raslib/oid.hh"
+#include "raslib/rminit.hh"
+
+#include <stdlib.h>
+
+// forward declarations
+class r_Database;
+class r_Type;
+
+//@ManMemo: Module: {\bf rasodmg}
+
+/*@Doc:
+
+ Through inheritance of this class, the type definer specifies that
+ the subclass is capable of having persistent as well as transient
+ instances.
+
+ {\bf Attention: }Right now, just the classes \Ref{r_Set} and \Ref{r_Marray}
+ inherit from \Ref{r_Object} which, therefore, are the only persistent
+ capable classes. In fact, just objects of type {\tt r_Set<r_Ref<r_Marray<...>>>}
+ can be made persitent right now.
+
+*/
+
+class r_Object
+{
+ public:
+ /// default constructor
+ r_Object();
+
+ /// constructor getting objType
+ r_Object( unsigned short objType ) throw(r_Error);
+ /**
+ {\tt objType} specifies the type of the object (1=Marray, 2=Collection).
+ This is needed for oid allocation and propably dropped in future.
+ */
+
+ /// copy constructor
+ r_Object( const r_Object&, unsigned short objType=0 ) throw(r_Error);
+ /**
+ {\tt objType} specifies the type of the object (1=Marray, 2=Collection).
+ This is needed for oid allocation and propably dropped in future.
+ */
+
+ /// virtual destructor
+ virtual ~r_Object();
+
+ /// mark the object as modified
+ inline void mark_modified();
+
+ /// new operator for transient objects
+ void* operator new( size_t size );
+
+ /// new operator for persistent objects
+ void* operator new( size_t size, r_Database *database, const char* type_name = 0 );
+
+ /// new operator for transient objects carrying type information
+ void* operator new( size_t size, const char* type_name );
+
+ /// delete operator
+ void operator delete( void* obj_ptr );
+
+ /// set object type by name
+ inline void set_type_by_name( const char* name ) throw(r_Error);
+ /**
+ With this method a type name has to be given by the user for each
+ object which he wants to make persistent. The type name is the name
+ introduced in the RasDL file. If an object without a valid type
+ name is made persistent, an error occurs while committing the
+ transaction.
+
+ NOTE: This method is updated. Use {\tt void* operator new( size_t size,
+ r_Database *database, const char* type_name )} instead.
+ */
+
+ /// set object type by name
+ inline void set_type_structure( const char* name ) throw(r_Error);
+
+ /// get object type name
+ inline const char* get_type_name() const;
+
+ /// get object type structure
+ inline const char* get_type_structure() const;
+
+ /// get oid
+ inline const r_OId& get_oid() const;
+
+ /// get type schema
+ const r_Type* get_type_schema();
+
+ void set_type_schema(const r_Type* type) throw (r_Error);
+
+ //@Man: Methods and types for internal use only:
+ //@{
+ ///
+
+ /// object life status
+ enum ObjectStatus { no_status, deleted, created, modified, read, transient };
+ /**
+ created - The object was created in the current transaction and has to be stored in the database.
+ deleted - The object was deleted. It is still in main memory and in the database. It is going to
+ be removed at the end of the transaction.
+ modified - Object was modified and has to be updated in the database.
+ read - The object was read from the database without modifying it afterwards.
+ transient - The object belongs to a declarative query result. In most cases, it has no persistent
+ counterpart in the db. It is NOT considered in the update phase.
+ */
+
+ /// object types
+ enum ObjectType { no_object, persistent_object, transient_object };
+
+ ///
+ /// inserts an object into the database
+ virtual void insert_obj_into_db()=0;
+ /// inserts an object into a specific collection in the database
+ virtual void insert_obj_into_db( const char* )=0;
+ /// updates an object in database
+ virtual void update_obj_in_db();
+ /// load an object from the database
+ virtual void load_obj_from_db();
+ /// deletes an object from the database
+ void delete_obj_from_db();
+
+ ///
+ /// initialize oid of the object
+ void initialize_oid( const r_OId& initOId );
+
+ ///
+ /// it is called when an object comes into transient memory
+ virtual void r_activate() {;};
+ /// it is called when an object leaves transient memory
+ virtual void r_deactivate();
+
+ ///
+ /// test object status returns 1 if it matches
+ int test_status( ObjectStatus status );
+ /// gets the status of the object
+ inline ObjectStatus get_status() const;
+
+ ///
+ /// set object name. object name should contain only [a-zA-Z0-9_]
+ inline void set_object_name( const char* name ) throw(r_Error);
+ /// get object name
+ inline const char* get_object_name() const;
+
+ ///
+ /// new operator for activating an object (status = read)
+ void* operator new( size_t size, r_Database *database, ObjectStatus status, const r_OId& oid );
+
+ ///
+ //@}
+
+ protected:
+ /// test object type returns 1 if it matches
+ int test_type( ObjectType type );
+
+ /// stores object name if it has one
+ char* object_name;
+
+ /// stores object type name if it has one
+ char* type_name;
+
+ /// store type structure as string if it has one
+ char* type_structure;
+
+ /// pointer to type schema (built on request)
+ r_Type* type_schema;
+
+ /// internal object type (1 marray, 2 collection)
+ unsigned short internal_obj_type;
+
+ private:
+ /// right now, the object life status is either deleted, created, or read
+ ObjectStatus object_status;
+
+ /// persistent_object or transient_object
+ ObjectType object_type;
+
+ /// object identifier
+ r_OId oid;
+
+ /// holds the next object type between new operation and constructor
+ static ObjectType next_object_type;
+
+ /// holds the next object status between new operation and constructor
+ static ObjectStatus next_object_status;
+
+ /// holds the next object type name between new operation and constructor
+ static char* next_object_type_name;
+
+ /// holds the next object oid between new operation and constructor
+ static r_OId next_object_oid;
+
+ /// holds the last object type between destructor and delete operator
+ static ObjectType last_object_type;
+};
+
+#include "rasodmg/object.icc"
+
+#endif
+
+
+
+
diff --git a/rasodmg/object.icc b/rasodmg/object.icc
new file mode 100644
index 0000000..b210d95
--- /dev/null
+++ b/rasodmg/object.icc
@@ -0,0 +1,151 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INLINE SOURCE: object.icc
+ *
+ * MODULE: rasodmg
+ * CLASS: r_Object
+ *
+ * COMMENTS:
+ * None
+*/
+
+#include <string.h>
+
+
+inline void
+r_Object::mark_modified()
+{
+ if( object_status == no_status ||
+ object_status == read )
+ object_status = modified;
+};
+
+
+
+inline void
+r_Object::set_object_name( const char* name ) throw(r_Error)
+{
+ if(!name) {
+ //null pointer
+ RMInit::logOut << "r_Object::set_object_name(name) name is null!" << std::endl;
+ throw r_Error(INVALIDOBJECTNAME);
+ }
+
+ const char* cptr=name;
+
+ //check if the name contains only [a-zA-Z0-9_]
+ while(*cptr) {
+ if( ((*cptr >= 'a') && (*cptr <='z')) ||
+ ((*cptr >= 'A') && (*cptr <='Z')) ||
+ ((*cptr >= '0') && (*cptr <='9')) ||
+ (*cptr == '_') )
+ cptr++;
+ else
+ break;
+ }
+
+ if(*cptr) {
+ //invalid character in object name
+ RMInit::logOut << "r_Object::set_object_name(" << name << ") invalid name!" << std::endl;
+ throw r_Error(INVALIDOBJECTNAME);
+ }
+
+ if( object_name )
+ free( object_name );
+
+ object_name = strdup( name );
+};
+
+
+inline void
+r_Object::set_type_by_name( const char* name ) throw(r_Error)
+{
+ if(!name) {
+ //null pointer
+ RMInit::logOut << "r_Object::set_type_by_name(name) name is null!" << std::endl;
+ throw r_Error(r_Error:: r_Error_NameInvalid);
+ }
+
+ if( type_name )
+ free( type_name );
+
+ type_name = strdup( name );
+};
+
+
+inline void
+r_Object::set_type_structure( const char* name ) throw(r_Error)
+{
+ if(!name) {
+ //null pointer
+ RMInit::logOut << "r_Object::type_structure(name) name is null!" << std::endl;
+ throw r_Error(r_Error:: r_Error_NameInvalid);
+ }
+
+ if( type_structure )
+ delete [] type_structure;
+
+ type_structure = new char[strlen(name) + 1];
+ strcpy(type_structure, name);
+};
+
+
+inline const char*
+r_Object::get_type_name() const
+{
+ return type_name;
+};
+
+
+inline const char*
+r_Object::get_object_name() const
+{
+ return object_name;
+}
+
+
+inline const char*
+r_Object::get_type_structure() const
+{
+ if (type_structure != NULL)
+ return type_structure;
+ else
+ return "";
+};
+
+
+inline r_Object::ObjectStatus
+r_Object::get_status() const
+{
+ return object_status;
+};
+
+
+inline const r_OId&
+r_Object::get_oid() const
+{
+ return oid;
+}
+
+
diff --git a/rasodmg/oqlquery.cc b/rasodmg/oqlquery.cc
new file mode 100644
index 0000000..4b1a3f1
--- /dev/null
+++ b/rasodmg/oqlquery.cc
@@ -0,0 +1,628 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: oqlquery.cc
+ *
+ * MODULE: rasodmg
+ * CLASS: r_OQL_Query
+ * FUNCTION: r_oql_execute()
+ *
+ * COMMENTS:
+ * None
+*/
+
+static const char rcsid[] = "@(#)rasodmg, r_OQL_Query and r_oql_execute(): $Id: oqlquery.cc,v 1.25 2002/08/28 12:21:57 coman Exp $";
+
+#include "rasodmg/oqlquery.hh"
+
+#include <string.h>
+#include <ctype.h> // isdigit()
+#ifdef __VISUALC__
+#include <strstrea.h>
+#else
+#include <strstream>
+#endif
+
+#ifdef __VISUALC__
+#ifndef __EXECUTABLE__
+#define __EXECUTABLE__
+#define OQLQUERY_NOT_SET
+#endif
+#endif
+
+#include "rasodmg/database.hh"
+#include "rasodmg/transaction.hh"
+#include "rasodmg/set.hh"
+#include "rasodmg/gmarray.hh"
+
+#include "raslib/rmdebug.hh"
+#include "clientcomm/clientcomm.hh"
+
+#ifdef OQLQUERY_NOT_SET
+#undef __EXECUTABLE__
+#endif
+
+r_OQL_Query::r_OQL_Query()
+ : queryString(0),
+ parameterizedQueryString(0),
+ mddConstants(0)
+{
+}
+
+
+r_OQL_Query::r_OQL_Query( const char* s )
+ : queryString(0),
+ mddConstants(0)
+{
+ parameterizedQueryString = new char[strlen(s)+1];
+ strcpy( parameterizedQueryString, s );
+
+ reset_query();
+}
+
+
+r_OQL_Query::r_OQL_Query( const r_OQL_Query& q )
+ : queryString(0),
+ parameterizedQueryString(0),
+ mddConstants(0)
+{
+ // copy the query string
+ if(q.queryString) {
+ queryString = new char[strlen(q.queryString)+1];
+ strcpy( queryString, q.queryString);
+ }
+
+ // copy the parameterized query string
+ if(q.parameterizedQueryString) {
+ parameterizedQueryString = new char[strlen(q.parameterizedQueryString)+1];
+ strcpy( parameterizedQueryString, q.parameterizedQueryString );
+ }
+
+ if( q.mddConstants ) {
+ mddConstants = new r_Set< r_GMarray* >( *(q.mddConstants) );
+ }
+}
+
+
+r_OQL_Query::~r_OQL_Query()
+{
+ if( queryString )
+ delete[] queryString;
+ queryString = 0;
+
+ if( parameterizedQueryString )
+ delete[] parameterizedQueryString;
+ parameterizedQueryString = 0;
+
+ if( mddConstants )
+ delete mddConstants;
+ mddConstants = 0;
+}
+
+
+const r_OQL_Query&
+r_OQL_Query::operator=( const r_OQL_Query& q )
+{
+ if( this != &q )
+ {
+ // clean up and copy the query string
+
+ if( queryString )
+ {
+ delete[] queryString;
+ queryString = 0;
+ }
+
+ if( q.queryString )
+ {
+ queryString = new char[strlen(q.queryString)+1];
+ strcpy( queryString, q.queryString );
+ }
+
+ if( mddConstants )
+ {
+ delete mddConstants;
+ mddConstants = 0;
+ }
+
+ if( q.mddConstants )
+ {
+ mddConstants = new r_Set< r_GMarray* >( *(q.mddConstants) );
+ }
+
+ // clean up and copy the parameterized query string
+ if( parameterizedQueryString )
+ {
+ delete[] parameterizedQueryString;
+ parameterizedQueryString = 0;
+ }
+
+ if( q.parameterizedQueryString )
+ {
+ parameterizedQueryString = new char[strlen(q.parameterizedQueryString)+1];
+ strcpy( parameterizedQueryString, q.parameterizedQueryString );
+ }
+ }
+
+ return *this;
+}
+
+
+r_OQL_Query&
+r_OQL_Query::operator<<( const char* s ) throw( r_Error )
+{
+ try
+ {
+ replaceNextArgument( s );
+ }
+ catch( ... )
+ {
+ throw;
+ }
+
+ return *this;
+}
+
+
+r_OQL_Query&
+r_OQL_Query::operator<<( r_Char c ) throw( r_Error )
+{
+ char valueString[2];
+
+ valueString[0] = c;
+ valueString[1] = '\0';
+
+ try
+ {
+ replaceNextArgument( valueString );
+ }
+ catch( ... )
+ {
+ throw;
+ }
+
+ return *this;
+}
+
+
+r_OQL_Query&
+r_OQL_Query::operator<<( r_Short s ) throw( r_Error )
+{
+ char valueString[256];
+
+ std::ostrstream valueStream( valueString, 256 );
+
+ valueStream << s << std::ends;
+
+ try
+ {
+ replaceNextArgument( valueString );
+ }
+ catch( ... )
+ {
+ throw;
+ }
+
+ return *this;
+}
+
+
+r_OQL_Query&
+r_OQL_Query::operator<<( r_UShort us ) throw( r_Error )
+{
+ char valueString[256];
+
+ std::ostrstream valueStream( valueString, 256 );
+
+ valueStream << us << std::ends;
+
+ try
+ {
+ replaceNextArgument( valueString );
+ }
+ catch( ... )
+ {
+ throw;
+ }
+
+ return *this;
+}
+
+
+r_OQL_Query&
+r_OQL_Query::operator<<( r_Long l ) throw( r_Error )
+{
+ char valueString[256];
+
+ std::ostrstream valueStream( valueString, 256 );
+
+ valueStream << l << std::ends;
+
+ try
+ {
+ replaceNextArgument( valueString );
+ }
+ catch( ... )
+ {
+ throw;
+ }
+
+ return *this;
+}
+
+
+r_OQL_Query&
+r_OQL_Query::operator<<( r_ULong ul ) throw( r_Error )
+{
+ char valueString[256];
+
+ std::ostrstream valueStream( valueString, 256 );
+
+ valueStream << ul << std::ends;
+
+ try
+ {
+ replaceNextArgument( valueString );
+ }
+ catch( ... )
+ {
+ throw;
+ }
+
+ return *this;
+}
+
+
+r_OQL_Query&
+r_OQL_Query::operator<<( r_Point pt ) throw( r_Error )
+{
+ char valueString[256];
+
+ std::ostrstream valueStream( valueString, 256 );
+
+ valueStream << pt << std::ends;
+
+ try
+ {
+ replaceNextArgument( valueString );
+ }
+ catch( ... )
+ {
+ throw;
+ }
+
+ return *this;
+}
+
+
+r_OQL_Query&
+r_OQL_Query::operator<<( r_Sinterval in ) throw( r_Error )
+{
+ char valueString[256];
+
+ std::ostrstream valueStream( valueString, 256 );
+
+ valueStream << in << std::ends;
+
+ try
+ {
+ replaceNextArgument( valueString );
+ }
+ catch( ... )
+ {
+ throw;
+ }
+
+ return *this;
+}
+
+
+r_OQL_Query&
+r_OQL_Query::operator<<( r_Minterval in ) throw( r_Error )
+{
+ char valueString[256];
+
+ std::ostrstream valueStream( valueString, 256 );
+
+ valueStream << in << std::ends;
+
+ try
+ {
+ replaceNextArgument( valueString );
+ }
+ catch( ... )
+ {
+ throw;
+ }
+
+ return *this;
+}
+
+
+r_OQL_Query&
+r_OQL_Query::operator<<( r_GMarray& in ) throw( r_Error )
+{
+ // determine number of next mdd (starting with 0)
+ unsigned long mddNo = 0;
+ if( mddConstants )
+ mddNo = mddConstants->cardinality();
+
+ char valueString[256];
+ std::ostrstream valueStream( valueString, 256 );
+ valueStream << "#MDD" << mddNo << "#" << std::ends;
+
+ try
+ {
+ replaceNextArgument( valueString );
+ }
+ catch( ... )
+ {
+ throw;
+ }
+
+ // save reference to in
+ if( !mddConstants )
+ mddConstants = new r_Set< r_GMarray* >();
+
+ mddConstants->insert_element( &in );
+
+ return *this;
+}
+
+
+
+
+int
+r_OQL_Query::is_update_query() const
+{
+ return !is_retrieval_query();
+}
+
+
+
+int
+r_OQL_Query::is_retrieval_query() const
+{
+ int returnValue = 0;
+
+ if( parameterizedQueryString )
+ returnValue = strstr( parameterizedQueryString, "select" ) ||
+ strstr( parameterizedQueryString, "SELECT" );
+
+ return returnValue;
+}
+
+
+
+void
+r_OQL_Query::reset_query()
+{
+ if( queryString )
+ delete[] queryString;
+
+ queryString = new char[strlen(parameterizedQueryString)+1];
+ strcpy( queryString, parameterizedQueryString );
+
+ if( mddConstants )
+ {
+ delete mddConstants;
+ mddConstants = 0;
+ }
+}
+
+
+void
+r_OQL_Query::replaceNextArgument( const char* valueString )
+ throw( r_Error )
+{
+ char* argumentBegin=NULL;
+ char* argumentEnd=NULL;
+ char* argumentVal=NULL;
+ int argumentLength=0;
+ char* tmpString=NULL;
+ int length=0;
+
+ // locate the next argument in the query string
+
+ argumentBegin = argumentEnd = strchr( queryString, '$' );
+
+ if( !argumentBegin )
+ {
+ r_Error err = r_Error( r_Error::r_Error_QueryParameterCountInvalid );
+ throw err;
+ }
+
+ // while( *argumentEnd != ' ' && *argumentEnd != '\0' )
+ argumentEnd++;
+
+ //is digit or invalid argument format
+ if(!isdigit(*argumentEnd))
+ throw r_Error( QUERYPARAMETERINVALID );
+
+ while( isdigit(*argumentEnd) && *argumentEnd != ' ' && *argumentEnd != '\0' )
+ argumentEnd++;
+
+ argumentLength = argumentEnd - argumentBegin;
+ argumentVal = new char[ argumentLength + 1];
+ strncpy(argumentVal, argumentBegin, argumentLength);
+ argumentVal[argumentLength] = '\0';
+
+ while(true)
+ {
+ // allocate a new query string and fill it
+ tmpString = queryString;
+ length = strlen(queryString) - argumentLength + strlen(valueString);
+ queryString = new char[ length + 1 ];
+
+ *argumentBegin = '\0';
+ std::ostrstream queryStream( queryString, length + 1 );
+
+ queryStream << tmpString << valueString << argumentEnd << std::ends;
+
+ //update the reference
+ argumentEnd=queryString+strlen(tmpString)+strlen(valueString);
+
+ //remove buffer
+ delete[] tmpString;
+
+ //search again for this parameter
+ argumentEnd = argumentBegin = strstr( argumentEnd, argumentVal );
+
+ //end string?
+ if(argumentBegin == NULL)
+ break;
+
+ //skip $
+ argumentEnd++;
+
+ //is digit or invalid argument format
+ if(!isdigit(*argumentEnd))
+ {
+ delete [] argumentVal;
+ throw r_Error( QUERYPARAMETERINVALID );
+ }
+
+ //skip digits
+ while( isdigit(*argumentEnd) && *argumentEnd != ' ' && *argumentEnd != '\0' )
+ argumentEnd++;
+ }
+
+ delete[] argumentVal;
+}
+
+
+
+// HP COMPILER BUG
+// The iterator type needs a typedef because otherwise the compiler creates a duplicate
+// definition for each instance of the following template function.
+typedef r_Iterator<r_GMarray*> r_Iterator_r_GMarray;
+
+void r_oql_execute( r_OQL_Query& query, r_Set< r_Ref_Any > &result )
+ throw( r_Error )
+{
+ if( r_Database::actual_database == 0 || r_Database::actual_database->get_status() == r_Database::not_open )
+ {
+ r_Error err = r_Error( r_Error::r_Error_DatabaseClosed );
+ throw err;
+ }
+
+ if( r_Transaction::actual_transaction == 0 || r_Transaction::actual_transaction->get_status() != r_Transaction::active )
+ {
+ r_Error err = r_Error( r_Error::r_Error_TransactionNotOpen );
+ throw err;
+ }
+
+ try
+ {
+ r_Database::actual_database->getComm()->executeQuery( query, result );
+ }
+ catch( ... )
+ {
+ throw; // re-throw the exception
+ }
+
+ // reset the arguments of the query object
+ query.reset_query();
+}
+
+
+
+void r_oql_execute( r_OQL_Query& query, r_Set< r_Ref< r_GMarray > > &result )
+ throw( r_Error )
+{
+ if( r_Database::actual_database == 0 || r_Database::actual_database->get_status() == r_Database::not_open )
+ {
+ r_Error err = r_Error( r_Error::r_Error_DatabaseClosed );
+ throw err;
+ }
+
+ if( r_Transaction::actual_transaction == 0 || r_Transaction::actual_transaction->get_status() != r_Transaction::active )
+ {
+ r_Error err = r_Error( r_Error::r_Error_TransactionNotOpen );
+ throw err;
+ }
+
+ try
+ {
+ r_Set< r_Ref_Any > genericSet;
+
+
+ r_Database::actual_database->getComm()->executeQuery( query, genericSet );
+
+ const r_Type* typeSchema = genericSet.get_element_type_schema();
+
+ if( !typeSchema || typeSchema->type_id() != r_Type::MARRAYTYPE )
+ {
+ r_Error err( r_Error::r_Error_TypeInvalid );
+ throw err;
+ }
+
+ //
+ // iterate through the generic set and build a specific one
+ //
+ result.set_type_by_name( genericSet.get_type_name() );
+ result.set_type_structure( genericSet.get_type_structure() );
+
+ r_Iterator< r_Ref_Any > iter;
+ for( iter=genericSet.create_iterator(); iter.not_done(); iter++ )
+ result.insert_element( r_Ref<r_GMarray>(*iter) );
+ }
+ catch( ... )
+ {
+ throw; // re-throw the exception
+ }
+
+ // reset the arguments of the query object
+ query.reset_query();
+}
+
+
+
+void r_oql_execute( r_OQL_Query& query )
+ throw( r_Error )
+{
+ if( r_Database::actual_database == 0 || r_Database::actual_database->get_status() == r_Database::not_open )
+ {
+ r_Error err = r_Error( r_Error::r_Error_DatabaseClosed );
+ throw err;
+ }
+
+ if( r_Transaction::actual_transaction == 0 || r_Transaction::actual_transaction->get_status() != r_Transaction::active )
+ {
+ r_Error err = r_Error( r_Error::r_Error_TransactionNotOpen );
+ throw err;
+ }
+
+ try
+ {
+ r_Database::actual_database->getComm()->executeQuery( query );
+ }
+ catch( ... )
+ {
+ throw; // re-throw the exception
+ }
+
+ // reset the arguments of the query object
+ query.reset_query();
+}
+
diff --git a/rasodmg/oqlquery.hh b/rasodmg/oqlquery.hh
new file mode 100644
index 0000000..8da0935
--- /dev/null
+++ b/rasodmg/oqlquery.hh
@@ -0,0 +1,251 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: oqlquery.hh
+ *
+ * MODULE: rasodmg
+ * CLASS: r_OQL_Query
+ * FUNCTION: r_oql_execute()
+ *
+ * COMMENTS:
+ * None
+*/
+
+#ifndef _D_OQL_QUERY_
+#define _D_OQL_QUERY_
+
+#include "raslib/error.hh"
+
+#include "raslib/odmgtypes.hh"
+#include "rasodmg/marray.hh"
+#include "raslib/point.hh"
+#include "raslib/sinterval.hh"
+#include "raslib/minterval.hh"
+
+template <class T> class r_Set;
+template <class T> class r_Ref;
+class r_Ref_Any;
+
+//@ManMemo: Module: {\bf rasodmg}
+
+/*@Doc:
+
+ The global function \Ref{r_oql_execute} is used to invoke RasML
+ queries. The query statement is represented through an object
+ of class \Ref{r_OQL_Query} which is the first argument of the function.
+ The constructor gets a parameterized query string where #$i#
+ indicates the i-th parameter. The overloaded stream input
+ operators allows to insert the parameter values to the query, at
+ the same time preserving their respective types. If any of the
+ #$i# are not followed by a right operant construction argument at
+ the point \Ref{r_oql_execute} is called, a \Ref{r_Error} exception object
+ of kind {\tt r_Error_QueryParameterCountInvalid} is thrown.
+ Once a query has been executed via \Ref{r_oql_execute}, the arguments
+ associated with the #$i# parameters are cleared and new arguments
+ must be supplied.
+
+ The copy constructor and assignment operator copy all the underlying
+ data structures associated with the query, based upon the parameters
+ that have been passed to the query at the point the operation is
+ performed.
+
+ The stream operators raise a \Ref{r_Error} exception of type
+ {\tt r_Error_QueryParameterCountInvalid} if the number of arguments is
+ exceeded.
+
+*/
+
+class r_OQL_Query
+{
+ public:
+ /// default constructor
+ r_OQL_Query();
+
+ /// constructor getting the query string
+ r_OQL_Query( const char* s );
+
+ /// copy constructor
+ r_OQL_Query( const r_OQL_Query& q );
+
+ /// destructor
+ ~r_OQL_Query();
+
+ /// assignment operator
+ const r_OQL_Query& operator=( const r_OQL_Query& q );
+
+ //@Man: Stream input operators for every parameter type:
+ //@{
+ ///
+ r_OQL_Query& operator<<( const char* s ) throw( r_Error );
+ ///
+ r_OQL_Query& operator<<( r_Char c ) throw( r_Error );
+ ///
+ r_OQL_Query& operator<<( r_Short s ) throw( r_Error );
+ ///
+ r_OQL_Query& operator<<( r_UShort us ) throw( r_Error );
+ ///
+ r_OQL_Query& operator<<( r_Long l ) throw( r_Error );
+ ///
+ r_OQL_Query& operator<<( r_ULong ul ) throw( r_Error );
+ ///
+ r_OQL_Query& operator<<( r_Point pt ) throw( r_Error );
+ ///
+ r_OQL_Query& operator<<( r_Sinterval in ) throw( r_Error );
+ ///
+ r_OQL_Query& operator<<( r_Minterval in ) throw( r_Error );
+ ///
+ r_OQL_Query& operator<<( r_GMarray& in ) throw( r_Error );
+ ///
+ //@}
+
+ /// returns true if the current query is an update one
+ int is_update_query() const;
+
+ /// returns true if the current query is an update one
+ int is_retrieval_query() const;
+
+ //@Man: Methods for internal use:
+ //@{
+ /// resets the expandation of the query string
+ void reset_query();
+ /// gets the expanded query string
+ inline const char* get_query() const;
+ /// get mdd constants
+ inline const r_Set< r_GMarray* >* get_constants() const;
+ /// gets the parameterized query string
+ inline const char* get_parameterized_query() const;
+ ///
+ //@}
+
+ private:
+ /// method replaces the next argument with the delivered valueString
+ void replaceNextArgument( const char* valueString ) throw( r_Error );
+
+ /// storage for the expanded query string
+ char* queryString;
+
+ /// storage for the parameterized query string
+ char* parameterizedQueryString;
+
+ /// list for MDD constants
+ r_Set< r_GMarray* >* mddConstants;
+};
+
+
+
+
+//@ManMemo: Module: {\bf rasodmg}
+
+/*@Doc:
+ The free standing function \Ref{r_oql_execute} is called to execute a retrieval query.
+ The first parameter, {\tt query}, is a reference to a \Ref{r_OQL_Query} object specifying
+ the query to execute. The second parameter, {\tt result}, is used for returning the
+ result of the query. The query result is of type {\tt r_Set< r_Ref_Any >}.
+
+ If the function is not called within the scope of an opened database, a \Ref{r_Error}
+ exception of kind {\tt r_Error_DatabaseClosed} is raised. If it is called outside any
+ transaction, the exception is of kind {\tt r_Error_TransactionNotOpen}.
+
+ A complete list of all possible error kinds is given by the following table.
+
+ \begin{tabular}{lll}
+ r_Error_ClientUnknown && Client is not known by the server (earlier communication problems).\\
+ r_Error_DatabaseClosed && No database is not opened.\\
+ r_Error_TransactionNotOpen && Call is not within an active transaction.\\
+ r_Error_QueryParameterCountInvalid && At least one of the query parameters is not supplied with a value.\\
+ r_Error_TransferFailed && Other communication problem. \\
+ r_Error_QueryExecutionFailed && The execution of the query failed (further information is available
+ in an error object of type {\tt r_Equery_execution}).\\
+ r_Error_TypeInvalid && Result base type doesn't match the template type. \\
+ \end{tabular}
+*/
+
+void r_oql_execute( r_OQL_Query& query, r_Set< r_Ref_Any > &result )
+throw( r_Error );
+
+
+//@ManMemo: Module: {\bf rasodmg}
+
+/*@Doc:
+ The funcetion is used to execute retrieval queries with the result set being
+ of type {\tt r_Set< r_Ref< r_GMarray > >}. The function is supported for
+ compatibility reasons only. We suggest to use the general function
+ \Ref{r_oql_execute} able to maintain query results of any type.
+*/
+void r_oql_execute( r_OQL_Query& query, r_Set< r_Ref< r_GMarray > > &result )
+throw( r_Error );
+
+
+//@ManMemo: Module: {\bf rasodmg}
+
+/*@Doc:
+ The free standing function \Ref{r_oql_execute} is called to execute an update query.
+ The first parameter, {\tt query}, is a reference to a \Ref{r_OQL_Query} object specifying
+ the query to execute.
+
+ If the function is not called within the scope of an opened database, a \Ref{r_Error}
+ exception of kind {\tt r_Error_DatabaseClosed} is raised. If it is called outside any
+ transaction, the exception is of kind {\tt r_Error_TransactionNotOpen}.
+
+ A complete list of all possible error kinds is given by the following table.
+
+ \begin{tabular}{lll}
+ r_Error_ClientUnknown && Client is not known by the server (earlier communication problems).\\
+ r_Error_DatabaseClosed && No database is not opened.\\
+ r_Error_TransactionNotOpen && Call is not within an active transaction.\\
+ r_Error_QueryParameterCountInvalid && At least one of the query parameters is not supplied with a value.\\
+ r_Error_TransferFailed && Other communication problem. \\
+ r_Error_QueryExecutionFailed && The execution of the query failed (further information is available
+ in an error object of type {\tt r_Equery_execution}).\\
+ \end{tabular}
+*/
+
+void r_oql_execute( r_OQL_Query& query )
+throw( r_Error );
+
+#include "rasodmg/oqlquery.icc"
+
+#endif
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/rasodmg/oqlquery.icc b/rasodmg/oqlquery.icc
new file mode 100644
index 0000000..6d6b225
--- /dev/null
+++ b/rasodmg/oqlquery.icc
@@ -0,0 +1,52 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INLINE SOURCE: oqlquery.icc
+ *
+ * MODULE: rasodmg
+ * CLASS: r_OQL_Query
+ *
+ * COMMENTS:
+ *
+*/
+
+
+inline const char*
+r_OQL_Query::get_query() const
+{
+ return (const char*)queryString;
+};
+
+
+inline const r_Set< r_GMarray* >*
+r_OQL_Query::get_constants() const
+{
+ return mddConstants;
+};
+
+
+inline const char*
+r_OQL_Query::get_parameterized_query() const
+{
+ return (const char*)parameterizedQueryString;
+};
diff --git a/rasodmg/partinsert.cc b/rasodmg/partinsert.cc
new file mode 100644
index 0000000..566f287
--- /dev/null
+++ b/rasodmg/partinsert.cc
@@ -0,0 +1,199 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: partinsert.cc
+ *
+ * MODULE: rasodmg
+ * CLASS: r_Partial_Insert
+ *
+ * COMMENTS:
+ * None
+*/
+
+#include <string.h>
+#include <stdio.h>
+#include <vector>
+
+#include "raslib/rminit.hh"
+#include "raslib/rmdebug.hh"
+#include "raslib/minterval.hh"
+#include "raslib/error.hh"
+#include "rasodmg/storagelayout.hh"
+#include "rasodmg/alignedtiling.hh"
+#include "rasodmg/gmarray.hh"
+#include "rasodmg/database.hh"
+#include "rasodmg/oqlquery.hh"
+#include "rasodmg/partinsert.hh"
+
+
+
+// format string for creating collections; parameters: collection name, set type
+const char *r_Partial_Insert::format_create = "CREATE COLLECTION %s %s";
+// format string for updating the MDD; parameters: collection name, local oid
+const char *r_Partial_Insert::format_update = "UPDATE %s AS x SET x ASSIGN $1 WHERE OID(x) = %f";
+
+
+r_Partial_Insert::r_Partial_Insert( r_Database &usedb, const char *collname, const char *mddtype, const char *settype, const r_Storage_Layout &stl ) : mydb(usedb)
+{
+ init_share(collname, mddtype, settype);
+ mystl = stl.clone();
+}
+
+
+r_Partial_Insert::r_Partial_Insert( r_Database &usedb, const char *collname, const char *mddtype, const char *settype, const r_Minterval &dom, unsigned int tsize ) : mydb(usedb)
+{
+ init_share(collname, mddtype, settype);
+ r_Aligned_Tiling *tilingObj = new r_Aligned_Tiling(dom, tsize * dom.cell_count());
+ mystl = new r_Storage_Layout(tilingObj);
+}
+
+
+r_Partial_Insert::r_Partial_Insert( const r_Partial_Insert &src ) : mydb(src.mydb)
+{
+ init_share(src.collName, src.mddType, src.setType);
+ mystl = src.mystl->clone();
+}
+
+
+r_Partial_Insert::~r_Partial_Insert( void )
+{
+ if (collName != NULL)
+ delete [] collName;
+ if (mddType != NULL)
+ delete [] mddType;
+ if (setType != NULL)
+ delete [] setType;
+ if (mystl != NULL)
+ delete mystl;
+}
+
+
+void r_Partial_Insert::init_share( const char *collname, const char *mddtype, const char *settype )
+{
+ collName = new char[strlen(collname)+1];
+ strcpy(collName, collname);
+ mddType = new char[strlen(mddtype)+1];
+ strcpy(mddType, mddtype);
+ setType = new char[strlen(settype)+1];
+ strcpy(setType, settype);
+ doUpdate = 0;
+}
+
+int r_Partial_Insert::update( r_GMarray *mddPtr,
+ r_Data_Format transferFormat,
+ const char* transferFormatParams,
+ r_Data_Format storageFormat,
+ const char* storageFormatParams
+ )
+{
+ RMDBGENTER(0, RMDebug::module_rasodmg, "r_Partial_Insert", "update()");
+ try {
+ mddPtr->set_storage_layout(mystl->clone());
+ mddPtr->set_type_by_name(mddType);
+ }
+ catch (r_Error &err) {
+ RMInit::logOut << "r_Partial_Insert::update(): unable to set storage_layout for the currend MDD: "
+ << err.what() << endl;
+ return -1;
+ }
+
+ if (doUpdate == 0)
+ {
+ char *queryBuffer = new char[strlen(format_create) + strlen(collName) + strlen(setType)];
+ sprintf(queryBuffer, format_create, collName, setType);
+ // first try creating the collection
+ try
+ {
+ // this is basically 3 bytes to long, but that doesn't matter
+ myta.begin();
+ mydb.set_transfer_format(transferFormat, transferFormatParams);
+ mydb.set_storage_format(storageFormat, storageFormatParams);
+ r_OQL_Query query(queryBuffer);
+ r_oql_execute(query);
+ myta.commit();
+ RMDBGMIDDLE(0, RMDebug::module_rasodmg, "r_Partial_Insert", "update(): created new collection " << collName << " with type " << setType );
+ }
+ catch (r_Error &err)
+ {
+ RMDBGMIDDLE(0, RMDebug::module_rasodmg, "r_Partial_Insert", "update(): can't create collection: " << err.what() );
+ myta.abort();
+ // failure to create the collection is not an error
+ }
+ delete [] queryBuffer;
+
+ // now create the root object
+ try
+ {
+ myta.begin();
+ mydb.set_transfer_format(transferFormat, transferFormatParams);
+ mydb.set_storage_format(storageFormat, storageFormatParams);
+ r_Ref<r_GMarray> mddp = new (&mydb, mddType) r_GMarray(*mddPtr);
+ r_Ref<r_Set<r_Ref<r_GMarray> > > mddCollPtr;
+ mddCollPtr = (r_Ref<r_Set<r_Ref<r_GMarray> > >)(mydb.lookup_object(collName));
+ mddCollPtr->insert_element(mddp);
+ myOId = mddp->get_oid();
+ myta.commit();
+ RMDBGMIDDLE(0, RMDebug::module_rasodmg, "r_Partial_Insert", "update(): reated root object OK, oid = " << myOId );
+ doUpdate = 1;
+ }
+ catch (r_Error &err)
+ {
+ RMInit::logOut << "r_Partial_Insert::update(): unable to create root object: "
+ << err.what() << endl;
+ myta.abort();
+ return -1;
+ }
+ }
+ else
+ {
+ char *queryBuffer = new char[strlen(format_update) + strlen(collName) + 32];
+ sprintf(queryBuffer, format_update, collName, myOId.get_local_oid());
+
+ // try the update
+ try
+ {
+ myta.begin();
+ mydb.set_transfer_format(transferFormat, transferFormatParams);
+ mydb.set_storage_format(storageFormat, storageFormatParams);
+ RMDBGMIDDLE(1, RMDebug::module_rasodmg, "r_Partial_Insert", "update(): QUERY: " << queryBuffer );
+ r_OQL_Query query(queryBuffer);
+ query << (*mddPtr);
+ r_oql_execute(query);
+ myta.commit();
+ RMDBGMIDDLE(0, RMDebug::module_rasodmg, "r_Partial_Insert", "update(): update object OK" );
+ }
+ catch (r_Error &err)
+ {
+ RMInit::logOut << "r_Partial_Insert::update(): failed to update marray: "
+ << err.what() << endl;
+ myta.abort();
+ delete [] queryBuffer;
+ RMDBGEXIT(1, RMDebug::module_rasodmg, "r_Partial_Insert", "failed");
+ return -1;
+ }
+ delete [] queryBuffer;
+ }
+ RMDBGEXIT(1, RMDebug::module_rasodmg, "r_Partial_Insert", "update(): exiting OK" );
+
+ return 0;
+}
diff --git a/rasodmg/partinsert.hh b/rasodmg/partinsert.hh
new file mode 100644
index 0000000..013124c
--- /dev/null
+++ b/rasodmg/partinsert.hh
@@ -0,0 +1,109 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: partinsert.hh
+ *
+ * MODULE: rasodmg
+ * CLASS: r_Partial_Insert
+ *
+ * COMMENTS:
+ * None
+*/
+
+#ifndef _R_PARTIAL_INSERT_
+#define _R_PARTIAL_INSERT_
+
+
+#include "raslib/mddtypes.hh"
+#include "raslib/oid.hh"
+#include "rasodmg/transaction.hh"
+
+
+class r_Minterval;
+class r_Storage_Layout;
+class r_GMarray;
+class r_Database;
+
+
+//@ManMemo: {\bf rasodmg}
+
+/*@Doc:
+ Class for inserting an MDD into the database stripwise, as in most of
+ our insert tools.
+*/
+
+class r_Partial_Insert
+{
+ public:
+ /// constructor receiving all necessary parameters. The storage layout is copied
+ r_Partial_Insert( r_Database &usedb, const char *collname, const char *mddtype,
+ const char *settype, const r_Storage_Layout &stl );
+ /// alternative constructor for regular tiling
+ r_Partial_Insert( r_Database &usedb, const char *collname, const char *mddtype,
+ const char *settype, const r_Minterval &dom, unsigned int tsize );
+ /// copy constructor
+ r_Partial_Insert( const r_Partial_Insert &src );
+ /// destructor
+ ~r_Partial_Insert( void );
+
+ /// update the marray; no transaction should be activated, this is done internally.
+ int update( r_GMarray *mddPtr,
+ r_Data_Format transferFormat = r_Array,
+ const char* transferFormatParams = NULL,
+ r_Data_Format storageFormat = r_Array,
+ const char* storageFormatParams = NULL
+ );
+ /*
+ The marray may be modified in small aspects such as base type name and storage layout.
+ The "transferFormat, transferFormatParams" are used to set the transfer compression used
+ for the communications of client with the server.
+ The "storageFormat, storageFormatParams" are used to set the storage format used for
+ MDD created by the client in the RasDaMan database.
+ */
+
+ protected:
+ /// shared init code
+ void init_share( const char *collname, const char *mddtype, const char *settype );
+
+ /// the marray's OId
+ r_OId myOId;
+ /// the collection name
+ char *collName;
+ /// the MDD type name
+ char *mddType;
+ /// the set type name
+ char *setType;
+ /// the database
+ r_Database &mydb;
+ /// the storage layout
+ r_Storage_Layout *mystl;
+ /// the transaction object
+ r_Transaction myta;
+ /// do we have to do an insert or an update?
+ int doUpdate;
+ /// format strings for queries
+ static const char *format_create;
+ static const char *format_update;
+};
+
+#endif
diff --git a/rasodmg/polycutout.cc b/rasodmg/polycutout.cc
new file mode 100644
index 0000000..78f3d75
--- /dev/null
+++ b/rasodmg/polycutout.cc
@@ -0,0 +1,709 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: polycutout.cc
+ *
+ * MODULE: rasodmg
+ * CLASS: r_PolygonCutOut
+ *
+ * COMMENTS:
+ *
+ * This class is intended to perform the polygon cut out operation
+ * Except for the r_PolygonCutOut class, everything else is just
+ * for internal use
+ * Attention: this version works good (I hope :-) but has just a tiny geometrical problem:
+ * as usual in discrete space, lines are build up by little horiontal segments.
+ * Edges are considered to be inside, except the first little segment of a line.
+ * This is only for avoiding a bigger problem, I will develop a better algorythm
+*/
+
+/*
+This module is intended to perform polygon cut out operation. It supports the exact ESRI specifications
+regarding "clean" polygons, this means: not self intersecting, closed, if you walk from an point to the
+next of edge the inside is on the right. It also supports multiple rings, but the outer one has to have
+the "inside" inside.
+Don't forget that the rasdaman coordinates are with x left->right and y top->down, or at least
+I have considered them so because of the usual coordinates of tiffs
+*/
+
+static const char rcsid[] = "@(#)rasodmg, r_PolygonCutOut: $Id: polycutout.cc,v 1.11 2002/10/09 09:58:05 hoefner Exp $";
+
+#include "rasodmg/polycutout.hh"
+#include "rasodmg/marray.hh"
+#include "raslib/miter.hh"
+
+#include <math.h>
+
+r_SegmentIterator::r_SegmentIterator(r_Point &s,r_Point &e)
+ {
+ start = s;
+ end = e;
+ reset();
+ }
+
+void r_SegmentIterator::reset()
+ {
+ dx = end[0] - start[0];
+ dy = end[1] - start[1];
+
+ if( dx >= 0)
+ { if( dy >= 0 )
+ { if( dx >= dy ) { cadran = 0;}
+ else { cadran = 1; swap(dx,dy);}
+ }
+ else
+ { dy = -dy;
+ if( dx >= dy ) { cadran = 7;}
+ else { cadran = 6; swap(dx,dy);}
+ }
+ }
+ else
+ { dx = -dx;
+ if( dy >= 0 )
+ { if( dx >= dy ) { cadran = 3;}
+ else { cadran = 2; swap(dx,dy);}
+ }
+ else
+ { dy = -dy;
+ if( dx >= dy ) { cadran = 4;}
+ else { cadran = 5; swap(dx,dy);}
+ }
+ }
+ cx = 0;
+ cy = 0;
+ beta = 0;
+// std::cout<<"reset: ["<<start<<','<<end<<"] cadran="<<cadran<<" dx="<<dx<<" dy="<<dy<<std::endl;
+ }
+
+r_Point r_SegmentIterator::next()
+ {
+ r_Point resultat = createCurrentPoint();
+ //prepare next
+ cx++;
+ beta += dy;
+ if( (beta<<1) > dx ) { beta -= dx; cy++;}
+ return resultat;
+ }
+
+bool r_SegmentIterator::hasMore()
+ {
+// std::cout<<"hasMore: cx="<<cx<<" lim="<<dx+1<<std::endl;
+ return (cx <= dx ) ? true : false;
+ }
+
+int r_SegmentIterator::cosFunc() // limited use,1000 * cos(alfa)
+ { // use local variables
+ double ldx = end[0] - start[0];
+ double ldy = end[1] - start[1];
+
+ double num = ldx*ldx + ldy*ldy;
+ if(num == 0) return 0;
+
+ return (1000 * ldx)/sqrt(num);
+ }
+
+void r_SegmentIterator::swap(r_Range &x, r_Range &y)
+ {
+ r_Range temp = x;
+ x=y;
+ y=temp;
+ }
+
+r_Point r_SegmentIterator::createCurrentPoint()
+ {
+// std::cout<<" cCP: "<<cx<<':'<<cy<<std::endl;
+ r_Range rcx = cx;
+ r_Range rcy = cy;
+ switch(cadran)
+ { case 0: break;
+ case 1: swap(rcx,rcy); break;
+ case 2: swap(rcx,rcy); rcx=-rcx; break;
+ case 3: rcx=-rcx; break;
+ case 4: rcx=-rcx; rcy=-rcy; break;
+ case 5: swap(rcx,rcy); rcx=-rcx; rcy=-rcy; break;
+ case 6: swap(rcx,rcy); rcy=-rcy; break;
+ case 7: rcy=-rcy; break;
+ }
+ //std::cout<<"cCP: cx="<<cx<<" cy="<<cy<<" rx="<<rcx<<" ry="<<rcy<<" cadran="<<cadran<<std::endl;
+ return r_Point(start[0] + rcx, start[1] + rcy);
+ }
+
+
+
+r_Line::r_Line()
+ {
+ a = b = c = 0;
+ }
+
+r_Line::r_Line(double nA,double nB,double nC)
+ {
+ a = nA; b = nB; c = nC;
+ }
+
+r_Line::r_Line(r_Point &s,r_Point &e)
+ {
+ a = e[1] - s[1];
+ b = s[0] - e[0];
+ c = (double)e[0]*(double)s[1] - (double)s[0]*(double)e[1];
+ }
+
+double r_Line::getA() { return a; }
+double r_Line::getB() { return b; }
+double r_Line::getC() { return c; }
+
+float r_Line::ecuatia(r_Point &p)
+ {
+ return a * p[0] + b * p[1] + c;
+ }
+
+ostream& operator<<(ostream& os,r_Line &l)
+ {
+ return os<<"{L"<<l.a<<','<<l.b<<','<<l.c<<'}';
+ }
+
+
+
+
+r_PolygonCutOut::r_PolygonCutOut()
+ {
+ table = 0;
+ usedCount = 0;
+ mArray = 0;
+
+ imgWidth = 0;
+ imgHeight = 0;
+ imgX = 0;
+ imgY = 0;
+ tableWidth = 0;
+ tableHeight = 0;
+ }
+r_PolygonCutOut::~r_PolygonCutOut()
+ {
+ clearTables();
+ }
+
+void r_PolygonCutOut::setMArray(r_GMarray& myArray)
+ {
+ mArray = &myArray;
+
+ r_Minterval currDomain;
+ currDomain = mArray->spatial_domain();
+
+ imgX = currDomain[0].low();
+ imgY = currDomain[1].low();
+
+ imgWidth = currDomain[0].get_extent();
+ imgHeight = currDomain[1].get_extent();
+ }
+
+void r_PolygonCutOut::addPolygon(const r_Polygon &p)
+ {
+ polygons.push_back(p);
+ }
+
+bool r_PolygonCutOut::compute()
+ {
+//std::cout<<"PCO: compute in"<<std::endl;
+ if(!imgWidth || !imgHeight || polygons.size()==0) return false;
+
+//std::cout<<"PCO: initTable - in"<<std::endl;
+ initTable();
+//std::cout<<"PCO: initTable - out"<<std::endl;
+
+ list<r_Polygon>::iterator polyIter = polygons.begin();
+
+ for(int i = 0; i < polygons.size(); i++, polyIter++)
+ {
+ r_Polygon &currPolygon = *polyIter;
+
+ const std::vector<r_Edge>& edges = currPolygon.getEdges();
+ std::vector<r_Edge>::const_iterator edgeIterator = edges.begin();
+
+ for(int j = 0; j < edges.size(); j++,edgeIterator++)
+ {
+ r_Point start = edgeIterator->getStart();
+ r_Point end = edgeIterator->getEnd();
+
+ if(start == end) continue; //avoid such edges, causes problems
+
+ int inside = -computeInside(start,end); // minus because rasdaman coord are flipped
+ // we have to see if this is correct like this or not
+
+ //std::cout<<"compute edge "<<j<<" ["<<start<<"-"<<end<<"] inside="<<inside<<std::endl;
+ if(inside == 0 ) computeOneHorSegment(start,end);
+ else computeOneSegment(start,end,inside);
+ }
+ }
+ for(int line=0;line<tableHeight;line++)
+ { ordonateLine(line);
+ minimizeLine(line);
+ }
+//print();
+// std::cout<<"PCO: compute out"<<std::endl;
+ return true;
+ }
+
+bool r_PolygonCutOut::initTable()
+ {
+ clearTables();
+ tableWidth = computeTableWidth();
+ tableHeight= imgHeight;
+
+//std::cout<<"PCO: initTable: "<<tableWidth<<','<<tableHeight<<std::endl;
+ table = new TablePoint[tableWidth*tableHeight];
+ usedCount = new int[tableHeight];
+
+ // if(table==NULL || usedCount==NULL) std::cout<<"sunt nule"<<std::endl;
+
+ for(int i=0;i<tableWidth*tableHeight;i++)
+ {
+ table[i].x =-1;
+ table[i].inside= 0;
+ table[i].cosFunc= 0;
+ }
+
+ for(int j=0;j<tableHeight;j++)
+ usedCount[j]=0;
+
+ return true;
+ }
+
+void r_PolygonCutOut::clearTables()
+ {
+ if(table) delete[] table;
+ table = NULL;
+ if(usedCount) delete[] usedCount;
+ usedCount =NULL;
+ }
+int r_PolygonCutOut::computeTableWidth()
+ {
+ // once it was: tableWidth = poly->getCountNodes() + poly->countHorizontalEdges() + 2;
+
+ list<r_Polygon>::iterator iter=polygons.begin();
+
+ int nodes = 0;
+ int horizEdges = 0;
+
+ for(int i=0;i<polygons.size();i++, iter++)
+ {
+ r_Polygon &polygon = *iter;
+
+ nodes += polygon.countEdges();
+ horizEdges += polygon.countHorizontalEdges();
+ }
+ return nodes + horizEdges; // niet + 2;
+ }
+
+void r_PolygonCutOut::ordonateLine(int line)
+ {
+ int count=usedCount[line];
+ TablePoint *tLine = &getTP(line,0);
+ bool change=false;
+ do{
+ change=false;
+ for(int i=0;i<count-1;i++)
+ { bool swap=false;
+
+ if(tLine[i].x > tLine[i+1].x) swap=true;
+ if(tLine[i].x == tLine[i+1].x &&
+ tLine[i].inside != tLine[i+1].inside &&
+ tLine[i].cosFunc > tLine[i+1].cosFunc)
+ swap=true;
+ if(swap)
+ { TablePoint temp = tLine[i];
+ tLine[i] = tLine[i+1];
+ tLine[i+1] = temp;
+ change = true;
+ }
+ }
+ }while(change);
+
+ for(int j=0;j<count-1;j++)
+ { if(tLine[j] == tLine[j+1])
+ tLine[j].inside=0;
+ }
+
+ }
+
+void r_PolygonCutOut::minimizeLine(int line)
+ {
+ int count=usedCount[line];
+ if(count <= 2) return; //nothing to do
+
+ int inside = 0;
+ TablePoint *tLine = &getTP(line,0);
+
+ int level=0;
+ for(int i=0;i<count-1;i++)
+ {
+ if(level==0) { inside=tLine[i].inside;
+ level++;
+ continue;
+ }
+
+ if(tLine[i].inside==inside) level++;
+ else level--;
+
+ if(level!=0) tLine[i].inside=0; // means disabled
+ }
+
+ int s,d;
+ for(s=0,d=0;s<count;s++)
+ {
+ if(tLine[s].inside==0) continue;
+ if(s!=d) tLine[d]=tLine[s];
+ d++;
+ }
+ usedCount[line]=d;
+ }
+
+void r_PolygonCutOut::computeOneSegment(r_Point start, r_Point end, int inside)
+ {
+ int lastLine = -1;
+ int lastX = -1;
+ r_SegmentIterator segiter(start,end);
+
+ int cosFunc=segiter.cosFunc();
+ int cosNow = cosFunc; // first point: cosFunc, lastPoint -cosFunc, rest 0
+
+ bool firstLine = true;
+ bool lastPoint = false;
+ // this firstLine-lastPoint are here only top be sure that the first and the last point are in the table
+ // and not replaced by neighbours
+ while(segiter.hasMore())
+ { r_Point cp = segiter.next();
+ if(segiter.hasMore()==false) // last point
+ {
+ cosNow=-cosFunc;
+ lastPoint = true;
+ }
+
+ r_Range coordX = cp[0];
+ r_Range coordY = cp[1];
+
+ int tableLine = coordY - imgY;
+
+ if(tableLine>=0 && tableLine < tableHeight)
+ {
+ if(tableLine != lastLine)
+ { addPoint(tableLine,coordX,inside,cosNow);
+
+ if(lastLine != -1) firstLine = false;
+ }
+ else if(firstLine == false)
+ {
+ if(inside > 0 && coordX < lastX) replacePoint(tableLine,coordX,inside,cosNow);
+ else if(inside < 0 && coordX > lastX) replacePoint(tableLine,coordX,inside,cosNow);
+ else if(lastPoint) replacePoint(tableLine,coordX,inside,cosNow);
+ }
+ }
+
+ cosNow = 0;
+ lastLine = tableLine;
+ lastX = coordX;
+ }
+ }
+
+void r_PolygonCutOut::computeOneHorSegment(r_Point start, r_Point end)
+ {
+ r_SegmentIterator segiter(start,end);
+ int cosFunc=segiter.cosFunc();
+
+ r_Range startX = start[0];
+ r_Range endX = end[0];
+ r_Range commonY = start[1];
+
+ int tableLine = commonY - imgY;
+
+ if(tableLine>=0 && tableLine < tableHeight)
+ {
+ if(startX <= endX)
+ { addPoint(tableLine,startX, 1, cosFunc);
+ addPoint(tableLine,endX, -1,-cosFunc);
+ }
+ else { // in this case cosFunc < 0
+ addPoint(tableLine,endX, 1,-cosFunc);
+ addPoint(tableLine,startX,-1, cosFunc);
+ }
+ }
+ }
+
+int r_PolygonCutOut::computeInside(r_Point start, r_Point end)
+ {
+ r_Line line(start,end);
+ r_Point control(start[0]+1,start[1]);
+ float f = line.ecuatia(control);
+ if(f==0) return 0;
+ if(f<0 ) return -1;
+ return 1;
+ }
+
+
+r_PolygonCutOut::TablePoint& r_PolygonCutOut::getTP(int line, int column)
+ {
+ TablePoint *tp = table + (line * tableWidth + column);
+ return *tp;
+ }
+
+void r_PolygonCutOut::print(int onlyLine)
+ {
+ std::cout<<"r_PolygonCutOut::print: "<<tableWidth<<':'<<tableHeight<<std::endl;
+
+ if(onlyLine==-1) // print all
+ {
+ for(int i=0;i<tableHeight;i++)
+ printLine(i);
+ }
+ else
+ {
+ if(0<=onlyLine && onlyLine <tableHeight) printLine(onlyLine);
+ else std::cout<<"Line "<<onlyLine<<" doesn't exist"<<std::endl;
+ }
+ }
+
+void r_PolygonCutOut::printLine(r_Range line)
+ {
+ int count=usedCount[line];
+ TablePoint *tp = &getTP(line,0);
+
+ std::cout<<"line "<<line<<'('<<count<<") ";
+ for(int i=0;i<count;i++)
+ { char inside='0';
+ if(tp[i].inside==-1) inside='-';
+ if(tp[i].inside==1 ) inside='+';
+
+ std::cout<<'['<<tp[i].x<<','<<inside<<','<<tp[i].cosFunc<<']';
+ }
+ std::cout<<std::endl;
+ }
+
+void r_PolygonCutOut::addPoint(int tableLine,r_Range coordX, int inside,int cosFunc)
+ {
+ int which = usedCount[tableLine];
+ TablePoint *tp = &getTP(tableLine,which);
+
+ tp->x = coordX;
+ tp->inside = inside;
+ tp->cosFunc = cosFunc;
+ usedCount[tableLine]++;
+ }
+
+void r_PolygonCutOut::replacePoint(int tableLine,r_Range coordX,int inside, int cosFunc)
+ {
+ int which = usedCount[tableLine]-1;
+ TablePoint *tp = &getTP(tableLine,which);
+ tp->x = coordX;
+ tp->inside = inside;
+ tp->cosFunc = cosFunc;
+ }
+
+bool r_PolygonCutOut::TablePoint::operator==(r_PolygonCutOut::TablePoint &tp)
+ { return (x==tp.x && inside==tp.inside) ? true: false;
+ }
+
+
+// debug only int lastline = -1;
+void
+r_PolygonCutOut::eraseLine( r_Range x1, r_Range x2, r_Range y, const string& bgr ) throw(r_Error)
+{
+ // can heapen if we are outside the domain of the array
+ if(x2 < x1) return;
+
+ //if(lastline != y && x1 != 0)
+ // std::cout<<"Erasing line: y="<<y<<" ["<<x1<<","<<x2<<"]"<<std::endl;
+ //lastline = y;
+
+ r_Minterval eraseDom(2);
+ eraseDom << r_Sinterval(x1, x2) << r_Sinterval(y, y);
+ r_Minterval arrayDom = mArray->spatial_domain();
+ r_Bytes typeSize = mArray->get_type_length();
+ r_Bytes bgrSize = bgr.size();
+ const char *bgrContent=bgr.c_str();
+ char *currCell=NULL;
+
+
+ // Grrr. In RasDaMan the y are stored close together. So the whole fillPolygon
+ // should have been organised by x instead of y. Well, for now I just use an
+ // r_Miter here.
+
+ r_Miter eraseIter( &eraseDom, &arrayDom, typeSize, mArray->get_array() );
+ while( !eraseIter.isDone() ) {
+ currCell = eraseIter.nextCell();
+ // FIXME This potentially wont work for all types. I just set every byte to 0.
+ if(bgr.empty())
+ memset(currCell, 0, typeSize);
+ else
+ {
+ if( typeSize != bgrSize)
+ throw r_Error( r_Error::r_Error_TypeInvalid );
+ memmove(currCell, bgrContent, bgrSize);
+ }
+ }
+}
+
+
+bool
+r_PolygonCutOut::fillMArrayOutside(const string& bgr ) throw(r_Error)
+{
+ if( compute() == false ) return false;
+
+ r_Minterval currDomain = mArray->spatial_domain();
+
+ r_Range imgMinX = imgX;
+ r_Range imgMaxX = currDomain[0].high();
+
+ for(int lineY = 0; lineY < tableHeight ; lineY++)
+ {
+ r_Range coordY = imgY + lineY;
+
+ int countUsed = usedCount[lineY];
+
+ if(countUsed==0)
+ { // polygon didn't touch this line, so all line is outside
+ eraseLine(imgMinX, imgMaxX, coordY, bgr);
+ continue;
+ }
+
+ TablePoint *tp = &getTP(lineY, 0);
+
+ r_Range xLeft = imgMinX-1;
+ r_Range xRight = imgMaxX+1;
+ bool erase = false;
+
+ if( tp[countUsed-1].x < imgMinX)
+ { // the whole polygon is on the left of this line so we have to erase the whole line
+ eraseLine( imgMinX, imgMaxX, coordY, bgr);
+ continue;
+ }
+
+ if( tp[0].x > imgMaxX)
+ { // the whole polygon is on the right of this line so we have to erase the whole line
+ eraseLine( imgMinX, imgMaxX, coordY, bgr);
+ continue;
+ }
+
+ for(int i=0;i<countUsed; i++, tp++)
+ {
+ if(tp->x < imgMinX) continue;
+
+ if(tp->inside == -1)
+ { // inside is <-, so outside is ->
+ xLeft = tp->x;
+ if(xLeft > imgMaxX) break;
+
+ if(i == countUsed-1)
+ { xRight = imgMaxX+1; erase = true;
+ }
+ }
+
+ if(tp->inside == 1)
+ { // inside is ->, so outside is <-
+ xRight = tp->x > imgMaxX ? imgMaxX+1 : tp->x;
+ erase = true;
+ }
+
+ if(erase)
+ { eraseLine( xLeft+1, xRight-1, coordY, bgr);
+ erase = false;
+ }
+ }
+
+ }
+ clearTables();
+ return true;
+ }
+
+/*
+ Attention, this two functions look very similar, but with have significant differences
+ One of them is the absence of some -1 or +1 in the next function. This is important
+ because we consider the edges to be "inside", and the edges are in the table, so
+ erasing the inside is erase [start,end] and erasing the outside is erase [start+1,end-1]
+*/
+
+bool
+r_PolygonCutOut::fillMArrayInside(const string& bgr ) throw(r_Error)
+{
+ if( compute() == false ) return false;
+
+ r_Minterval currDomain = mArray->spatial_domain();
+
+ r_Range imgMinX = imgX;
+ r_Range imgMaxX = currDomain[0].high();
+
+ for(int lineY = 0; lineY < tableHeight ; lineY++)
+ {
+ r_Range coordY = imgY + lineY;
+
+ int countUsed = usedCount[lineY];
+
+ if(countUsed==0)
+ { // polygon didn't touch this line, so all line is outside
+ continue;
+ }
+
+ TablePoint *tp = &getTP(lineY, 0);
+
+ r_Range xLeft = imgMinX;
+ r_Range xRight = imgMaxX;
+ bool erase = false;
+
+ if( tp[countUsed-1].x < imgMinX)
+ { // the whole polygon is on the left of this line so we have to erase the whole line
+ continue;
+ }
+
+ if( tp[0].x > imgMaxX)
+ { // the whole polygon is on the right of this line so we have to erase the whole line
+ continue;
+ }
+
+ for(int i=0;i<countUsed; i++, tp++)
+ {
+ if(tp->x < imgMinX) continue;
+
+ if(tp->inside == 1)
+ { // inside is ->, so outside is <-
+ xLeft = tp->x;
+ if(xLeft > imgMaxX) break;
+
+ if(i == countUsed-1)
+ { xRight = imgMaxX; erase = true;
+ }
+ }
+
+ if(tp->inside == -1)
+ { // inside is <-, so outside is ->
+ xRight = tp->x > imgMaxX ? imgMaxX : tp->x;
+ erase = true;
+ }
+
+ if(erase)
+ { eraseLine( xLeft, xRight, coordY, bgr);
+ erase = false;
+ }
+ }
+
+ }
+ clearTables();
+ return true;
+ }
diff --git a/rasodmg/polycutout.hh b/rasodmg/polycutout.hh
new file mode 100644
index 0000000..fc2e258
--- /dev/null
+++ b/rasodmg/polycutout.hh
@@ -0,0 +1,162 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: polycutout.hh
+ *
+ * MODULE: rasodmg
+ * CLASS: r_PolygonCutOut
+ *
+ * COMMENTS:
+ *
+ * This class is intended to perform the polygon cut out operation
+ * Except for the r_PolygonCutOut class, everything else is just
+ * for internal use
+ * Attention: this version works good (I hope :-) but has just a tiny geometrical problem:
+ * as usual in discrete space, lines are build up by little horiontal segments.
+ * Edges are considered to be inside, except the first little segment of a line.
+ * This is only for avoiding a bigger problem, I will develop a better algorythm
+*/
+
+/*
+ This module is intended to perform polygon cut out operation. It supports the exact ESRI specifications
+ regarding "clean" polygons, this means: not self intersecting, closed, if you walk from an point to the
+ next of edge the inside is on the right. It also supports multiple rings, but the outer one has to have
+ the "inside" inside.
+ Don't forget that the rasdaman coordinates are with x left->right and y top->down, or at least
+ I have considered them so because of the usual coordinates of tiffs
+*/
+
+#ifndef _R_POLYGON_CUT_OUT_HH
+#define _R_POLYGON_CUT_OUT_HH
+
+#include <iosfwd>
+#include <vector>
+#include <list>
+#include <string>
+using std::string;
+using std::list;
+using std::vector;
+using std::ostream;
+
+#include "raslib/point.hh"
+#include "raslib/minterval.hh"
+#include "rasodmg/polygon.hh"
+
+
+//@ManMemo: Module: {\bf rasodmg}
+
+
+class r_SegmentIterator
+ {
+ public:
+ r_SegmentIterator(r_Point&,r_Point&);
+ void reset();
+ r_Point next();
+ bool hasMore();
+ int cosFunc(); // limited use,1000 * cos(alfa)
+ private:
+ void swap(r_Range&, r_Range&);
+ r_Point createCurrentPoint();
+
+ r_Point start;
+ r_Point end;
+ int cadran;
+
+ r_Range dx,dy;
+ r_Range cx,cy;
+ int beta;
+ };
+
+class r_Line
+ {
+ public:
+ r_Line();
+ r_Line(double,double,double);
+ r_Line(r_Point&,r_Point&);
+ double getA();
+ double getB();
+ double getC();
+ float ecuatia(r_Point&);
+ private:
+ double a,b,c;
+ friend ostream& operator<<(ostream&,r_Line&);
+ };
+
+
+class r_PolygonCutOut
+ {
+ public:
+ r_PolygonCutOut();
+ ~r_PolygonCutOut();
+ void setImageSize(r_Range width, r_Range height);
+
+ void setMArray(r_GMarray& myArray);
+ void addPolygon(const r_Polygon&);
+
+ bool fillMArrayInside(const string& bgr = "") throw(r_Error);
+ bool fillMArrayOutside(const string& bgr = "") throw(r_Error);
+
+ // just for debugging
+ void print(int onlyLine=-1);
+ void printLine(r_Range line);
+
+ private:
+ bool compute();
+ void eraseLine( r_Range, r_Range, r_Range y, const string& bgr ) throw(r_Error);
+
+ r_Range imgWidth,imgHeight;
+ r_Range imgX,imgY; // - the origin of the mdd domain
+
+ r_GMarray *mArray;
+
+ std::list<r_Polygon> polygons;
+
+ struct TablePoint
+ { r_Range x;
+ int inside; // where the inside is, -1 left, +1 right, 0 hor. line
+ int cosFunc;
+ bool operator==(TablePoint&);
+ };
+
+ r_Range tableWidth;
+ r_Range tableHeight;
+ TablePoint *table;
+ int *usedCount;
+ TablePoint& getTP(r_Range line, r_Range column);
+
+ bool initTable();
+ void clearTables();
+ int computeTableWidth();
+
+
+ int computeInside(r_Point start, r_Point end);
+ void computeOneSegment(r_Point start, r_Point end, int inside);
+ void computeOneHorSegment(r_Point start, r_Point end);
+ void ordonateLine(int line);
+ void minimizeLine(int line);
+ void replacePoint(r_Range line,r_Range col,int inside, int cosFunc);
+ void addPoint(r_Range line,r_Range col,int inside, int cosFunc);
+
+ };
+
+#endif
diff --git a/rasodmg/polygon.cc b/rasodmg/polygon.cc
new file mode 100644
index 0000000..755593f
--- /dev/null
+++ b/rasodmg/polygon.cc
@@ -0,0 +1,879 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: polygon.cc
+ *
+ * MODULE: rasodmg
+ * CLASS: r_Polygon
+ *
+ * PURPOSE:
+ * This class maintains 2-D polygon sequences.
+ * It knows about them being closed or not.
+ * Input syntax (see constructor) is:
+ * polygon ::= point+
+ * point ::= '[' int ',' int ']'
+ * int ::= ASCII-integer
+ *
+ * COMMENTS:
+ * - see comment in shrinkPoly() about a potential error source
+ * - r_Error::r_Error_General should be replaced with more specific exception
+ *
+*/
+
+#include "rasodmg/polygon.hh"
+
+#include <set>
+#include <algorithm>
+#include <math.h>
+
+#if defined(SOLARIS)
+#include <strings.h>
+#endif
+
+using std::sort;
+//causes problems compiling on old red hat
+//using std::iterator;
+
+#include "raslib/miter.hh"
+#include "rasodmg/marray.hh"
+
+#include "debug/debug.hh"
+
+static const char rcsid[] = "@(#)rasodmg, r_Polygon: $Header: /home/rasdev/CVS-repository/rasdaman/rasodmg/polygon.cc,v 1.28 2003/12/27 23:02:56 rasdev Exp $";
+
+#ifndef LONG_MAX
+const int LONG_MAX = (1<<31) - 1;
+#endif
+#ifndef LONG_MIN
+const int LONG_MIN = (1<<31); // due to overflow
+#endif
+
+// ------------------------------------------------------------------
+// r_Edge
+// ------------------------------------------------------------------
+
+r_Edge::r_Edge(const r_Point& newStart, const r_Point& newEnd) :
+ start(newStart), end(newEnd)
+{
+}
+
+const r_Point&
+r_Edge::getStart() const
+{
+ return start;
+}
+
+const r_Point&
+r_Edge::getEnd() const
+{
+ return end;
+}
+
+double
+r_Edge::getInvSlope() const
+{
+ return (((double)end[0] - start[0]) / (end[1] - start[1]));
+}
+
+double
+r_Edge::getSlope() const
+{
+ return (((double)end[1] - start[1]) / (end[0] - start[0]));
+}
+
+double
+r_Edge::getCurrX(r_Range y) const
+{
+ double currX=0.0;
+ if(end[1]==start[1])
+ currX=end[0];
+ else
+ currX=getInvSlope()*(y - start[1]) + start[0];
+ return currX;
+}
+
+double
+r_Edge::getCurrY(r_Range x) const
+{
+ double currY=0.0;
+ if(end[0]==start[0])
+ currY=end[1];
+ else
+ currY=getSlope()*(x - start[0]) + start[1];
+ return currY;
+}
+
+void
+r_Edge::print_status( std::ostream& s ) const
+{
+ start.print_status(s);
+ s << "->";
+ end.print_status(s);
+}
+
+
+bool
+r_Edge::isHorizontal() const
+{
+ return start[1] == end[1] ? true:false;
+}
+
+// ------------------------------------------------------------------
+// r_Polygon
+// ------------------------------------------------------------------
+
+const r_Dimension r_Polygon::polyPointDim=2;
+
+r_Polygon::r_Polygon(const char* init) throw (r_Error)
+ : closed(false),
+ firstPointSet(false)
+{
+ ENTER( "r_Polygon::r_Polygon, init=" << init );
+
+ if (init == NULL)
+ {
+ TALK( "r_Polygon::r_Polygon(" << (init?init: "NULL") << ")" );
+ RMInit::logOut << "r_Polygon::r_Polygon(" << (init?init: "NULL") << ")" << std::endl;
+ throw r_Error(POLYGONWRONGINITSTRING);
+ }
+ const int POINTBUFFERLEN=512;
+ const char* endPos = NULL;
+ size_t pointLen = 0;
+ char pointBuffer[POINTBUFFERLEN];
+ const char* startPos = index(init, '[');
+ if (startPos == NULL)
+ {
+ TALK( "r_Polygon::r_Polygon(" << init << ") the init string has to start with a '['" );
+ RMInit::logOut << "r_Polygon::r_Polygon(" << init << ") the init string has to start with a '['" << std::endl;
+ throw r_Error(POLYGONWRONGINITSTRING);
+ }
+
+ // while (true)
+ do
+ {
+ endPos = index(startPos, ']');
+ if (endPos == NULL)
+ {
+ TALK( "r_Polygon::r_Polygon(" << init << ") the init string has to contain valid r_Point definitions" );
+ RMInit::logOut << "r_Polygon::r_Polygon(" << init << ") the init string has to contain valid r_Point definitions" << std::endl;
+ throw r_Error(POLYGONWRONGINITSTRING);
+ }
+ pointLen = endPos - startPos;
+ if (pointLen >= POINTBUFFERLEN)
+ {
+ TALK( "r_Polygon::r_Polygon(" << init << ") the definition of one r_Point is too long, only 2 dimensions are allowed" );
+ RMInit::logOut << "r_Polygon::r_Polygon(" << init << ") the definition of one r_Point is too long, only 2 dimensions are allowed" << std::endl;
+ throw r_Error(POLYGONWRONGINITSTRING);
+ }
+ memset(pointBuffer, 0, POINTBUFFERLEN);
+ strncpy(pointBuffer, startPos, pointLen + 1);
+ addPoint(r_Point(pointBuffer));
+ startPos = index(endPos, '[');
+ // was an endless loop with break, changed it to a 'nice' loop -- PB 2003-sep-12
+ // if (startPos == NULL)
+ // break;
+ } while( startPos != NULL);
+
+ LEAVE( "r_Polygon::r_Polygon" );
+}
+
+r_Polygon::r_Polygon(r_Range x, r_Range y) : closed(false), firstPointSet(true)
+{
+ firstPoint = r_Point(x, y);
+ currPoint = firstPoint;
+}
+
+r_Polygon::r_Polygon() : closed(false), firstPointSet(false)
+{
+}
+
+r_Polygon::r_Polygon(const r_Polygon& old)
+{
+ closed=old.closed;
+ firstPointSet=old.firstPointSet;
+ firstPoint=old.firstPoint;
+ currPoint=old.currPoint;
+
+ edges=old.edges;
+}
+
+r_Polygon&
+r_Polygon::operator=(const r_Polygon& old)
+{
+ if(this!=&old)
+ {
+ closed=old.closed;
+ firstPointSet=old.firstPointSet;
+ firstPoint=old.firstPoint;
+ currPoint=old.currPoint;
+
+ edges=old.edges;
+ }
+ return *this;
+}
+
+void
+r_Polygon::addPoint(const r_Point& newPoint) throw(r_Error)
+{
+ if (newPoint.dimension() != polyPointDim)
+ {
+ RMInit::logOut << "r_Polygon::addPoint(" << newPoint << ") only " << polyPointDim << " dimensional r_Points allowed" << std::endl;
+ throw r_Error(POLYGONWRONGPOINTDIMENSION);
+ }
+
+ if(closed)
+ {
+ RMInit::logOut << "r_Polygon::addPoint(" << newPoint << ") polygon closed" << std::endl;
+ throw r_Error(r_Error::r_Error_General);
+ }
+
+ if(firstPointSet)
+ {
+ // add an edge from currentPoint to newPoint
+ edges.push_back(r_Edge(currPoint, newPoint));
+ currPoint = newPoint;
+
+ //check if we have the first point
+ checkFistPoint();
+ }
+ else
+ {
+ firstPoint = newPoint;
+ currPoint = newPoint;
+ firstPointSet = true;
+ }
+}
+
+void
+r_Polygon::addPointXY(r_Range x, r_Range y) throw(r_Error)
+{
+ r_Point newPoint(x, y);
+ addPoint(newPoint);
+}
+
+void
+r_Polygon::close()
+{
+ if (closed)
+ return;
+
+ // add the final edge from currentPoint to firstPoint
+ edges.push_back(r_Edge(currPoint, firstPoint));
+ closed = true;
+}
+
+const std::vector<r_Edge>&
+r_Polygon::getEdges() const throw(r_Error)
+{
+ // if the polygon is not closed we raise an exception.
+ if(!closed)
+ {
+ // TO DO: This should be an internal error sometimes.
+ RMInit::logOut << "r_Polygon::getEdges() polygon opened" << std::endl;
+ throw(r_Error(r_Error::r_Error_General));
+ }
+
+ return edges;
+}
+
+std::vector<r_Point>
+r_Polygon::getPoints() const throw(r_Error)
+{
+ if(!closed)
+ {
+ // TO DO: This should be an internal error sometimes.
+ RMInit::logOut << "r_Polygon::getPoints() polygon opened" << std::endl;
+ throw(r_Error(r_Error::r_Error_General));
+ }
+
+ std::vector<r_Point> retVal;
+ std::vector<r_Edge>::const_iterator iter, iterEnd;
+ for(iter = edges.begin(), iterEnd=edges.end(); iter != iterEnd; ++iter)
+ {
+ retVal.push_back((*iter).getStart());
+ }
+ return retVal;
+}
+
+r_Polygon::r_Polygon_Type
+r_Polygon::detectPolygonType() const throw(r_Error)
+{
+ const unsigned int minNoEdges=3;
+ std::vector<r_Point> points=getPoints();
+ unsigned int i=0,j=0, k=0, n=0;
+ unsigned int flag = 0;
+ double z;
+
+ n=points.size();
+
+ //check if is at least a triangle
+ if (n < minNoEdges)
+ return r_Polygon::UNKNOWN;
+
+ //check if is a polygon in 2D
+ for (i=0; i<n; i++)
+ if (points[i].dimension()!=polyPointDim)
+ return r_Polygon::UNKNOWN;
+
+ //check sign of vertice
+ for (i=0; i<n; i++)
+ {
+ j = (i + 1) % n;
+ k = (i + 2) % n;
+ z = (points[j][1] - points[i][1]) * (points[k][0] - points[j][0]);
+ z -= (points[j][0] - points[i][0]) * (points[k][1] - points[j][1]);
+ if (z < 0)
+ flag |= 1;
+ else if (z > 0)
+ flag |= 2;
+ if (flag == 3)
+ return r_Polygon::CONCAVE;
+ }
+
+ if (flag != 0)
+ return r_Polygon::CONVEX;
+ else
+ return r_Polygon::UNKNOWN;
+}
+
+void
+r_Polygon::checkFistPoint()
+ {
+ if (firstPoint == currPoint)
+ closed = true;
+ else
+ closed = false;
+ }
+
+void
+r_Polygon::print_status( std::ostream& s ) const
+{
+
+ std::vector<r_Edge>::const_iterator iter = edges.begin();
+ std::vector<r_Edge>::const_iterator iterEnd = edges.end();
+ s << "{";
+ while (iter!=iterEnd)
+ {
+ iter->print_status(s);
+ s << ", ";
+ ++iter;
+ }
+ s << "} ";
+ if (closed)
+ s << "closed";
+ else //does not matter, because open will crash ...
+ s << "opened";
+
+}
+
+std::ostream& operator<<( std::ostream& s, const r_Polygon& d )
+{
+ d.print_status( s );
+ return s;
+}
+
+void
+r_Polygon::fillMArray( r_GMarray& myArray, bool fillInside, const std::string& bgr ) const throw(r_Error)
+{
+ if(!closed)
+ {
+ // TO DO: This should be an internal error sometimes.
+ RMInit::logOut << "r_Polygon::fillMArray(...) polygon opened" << std::endl;
+ throw(r_Error(r_Error::r_Error_General));
+ }
+
+ // This code currently is not optimised. For every scanline all edges are checked.
+ // Normally you would keep a list of currently relevant edges and manage deletes
+ // and additions to this table by presorting. Anyway, focus was on correctnes
+ // for the time being and even that was not really easy.
+
+ // all edges of the poly except for horizontal ones.
+ std::set<r_Edge, EdgeSortCriterion> sortedEdges;
+ // the X values of the edges in the current scanline.
+ std::vector<double> currXVals;
+ // just to save some typing.
+ r_Minterval myDom = myArray.spatial_domain();
+ unsigned long typeSize = myArray.get_type_length();
+
+ // build sortedEdges (sorted after startPoint y, startPoint x).
+ std::vector<r_Edge>::const_iterator iter, iterEnd;
+ for(iter = edges.begin(), iterEnd=edges.end(); iter != iterEnd; ++iter)
+ sortedEdges.insert(*iter);
+
+ // now the actual filling is done. Remember that we only draw the outside!
+ // we iterate through the whole y range
+ for(r_Range y = myDom[1].low(); y <= myDom[1].high(); y++)
+ {
+ // update the currXVals by iterating through all edges.
+ for(std::multiset<r_Edge, EdgeSortCriterion>::const_iterator itera = sortedEdges.begin(); itera != sortedEdges.end(); itera++)
+ {
+ if( (*itera).getStart()[1] <= y && y <= (*itera).getEnd()[1] ||
+ (*itera).getEnd()[1] <= y && y <= (*itera).getStart()[1] )
+ {
+ currXVals.push_back((*itera).getCurrX(y));
+ }
+ }
+ // sort them.
+ sort(currXVals.begin(), currXVals.end());
+ // currently we can only draw concave polygons anyway (see below).
+ // So this is heavily simplified! Check version 1.3 for a
+ // blueprint of how it should look like.
+ if(fillInside)
+ {
+ if(currXVals.size() >= 1)
+ {
+ // currXVals is sorted, so just draw from the first to the last.
+ eraseLine(rint(currXVals.front()), rint(currXVals.back()), y, myArray, bgr);
+ }
+ }
+ else
+ {
+ // currXVals is sorted, so just draw from low to the first and
+ // from the last to high.
+ // This only works correctly if the polygon is clipped
+ // to the area of the image.
+ if(currXVals.size() >= 1)
+ {
+ eraseLine(myDom[0].low(), rint(currXVals.front())-1.0, y, myArray, bgr);
+ eraseLine(rint(currXVals.back())+1.0, myDom[0].high(), y, myArray, bgr);
+ }
+ else
+ {
+ eraseLine(myDom[0].low(), myDom[0].high(), y, myArray, bgr);
+ }
+ }
+ // Note:
+ // Couldn't get it working with an even/odd inside rule. Reason: If you
+ // want to do this correctly you have to classify two edges meeting into
+ // different categories to decide if they have to be put into currXVals
+ // once or twice. Otherwise you get problems. With this simplified version
+ // only convex polygons are filled correctly!
+
+ // delete the old currXVals
+ currXVals.clear();
+ }
+}
+
+r_Minterval
+r_Polygon::getBoundingBox() const throw(r_Error)
+{
+ if(!closed)
+ {
+ // TO DO: This should be an internal error sometimes.
+ TALK( "r_Polygon::getBoundingBox() polygon opened" );
+ RMInit::logOut << "r_Polygon::getBoundingBox() polygon opened" << std::endl;
+ throw(r_Error(r_Error::r_Error_General));
+ }
+
+ r_Minterval retVal(2);
+ r_Range minX = LONG_MAX;
+ r_Range maxX = LONG_MIN;
+ r_Range minY = LONG_MAX;
+ r_Range maxY = LONG_MIN;
+ r_Range currMinX=0, currMaxX=0, currMinY=0, currMaxY=0;
+ std::vector<r_Edge>::const_iterator iter, iterEnd;
+
+ for(iter = edges.begin(), iterEnd=edges.end(); iter != iterEnd; ++iter)
+ {
+ currMinX = (*iter).getStart()[0] < (*iter).getEnd()[0] ? (*iter).getStart()[0] : (*iter).getEnd()[0];
+ currMaxX = (*iter).getStart()[0] > (*iter).getEnd()[0] ? (*iter).getStart()[0] : (*iter).getEnd()[0];
+ currMinY = (*iter).getStart()[1] < (*iter).getEnd()[1] ? (*iter).getStart()[1] : (*iter).getEnd()[1];
+ currMaxY = (*iter).getStart()[1] > (*iter).getEnd()[1] ? (*iter).getStart()[1] : (*iter).getEnd()[1];
+ minX = currMinX < minX ? currMinX : minX;
+ maxX = currMaxX > maxX ? currMaxX : maxX;
+ minY = currMinY < minY ? currMinY : minY;
+ maxY = currMaxY > maxY ? currMaxY : maxY;
+ }
+ retVal << r_Sinterval(minX, maxX) << r_Sinterval(minY, maxY);
+ return retVal;
+}
+
+void
+r_Polygon::clip(const r_Minterval& clipDom) throw(r_Error)
+{
+ if(!closed)
+ {
+ // TO DO: This should be an internal error sometimes.
+ TALK( "r_Polygon::getBoundingBox() polygon opened" );
+ RMInit::logOut << "r_Polygon::getBoundingBox() polygon opened" << std::endl;
+ throw(r_Error(r_Error::r_Error_General));
+ }
+
+ std::vector<r_Point> pointList;
+
+ // Disjunct polygons used to crash the program.
+ // check if the bounding box of the polygon overlaps the clipDom
+ if(clipDom.intersects_with(getBoundingBox()))
+ {
+ // We just clip all 4 edges
+ for(int s = r_Polygon::top; s <= r_Polygon::right; ++s)
+ {
+ pointList=clip1Side(clipDom, (r_Polygon::Side)s);
+ if(pointList.empty()) // do we have intersection points?
+ {
+ // return a polygon with one line only. This should delete everything.
+ pointList.push_back(r_Point(clipDom[0].low(), clipDom[1].low()));
+ pointList.push_back(r_Point(clipDom[0].low(), clipDom[1].high()));
+ }
+ fromPoints(pointList);
+ pointList.clear();
+ }
+ }
+ else
+ {
+ // return a polygon with one line only. This should delete everything.
+ pointList.push_back(r_Point(clipDom[0].low(), clipDom[1].low()));
+ pointList.push_back(r_Point(clipDom[0].low(), clipDom[1].high()));
+ fromPoints(pointList);
+ }
+}
+
+
+void
+r_Polygon::scale(const r_Point& origin, const r_Minterval& mddDom,
+ const r_Minterval& clipDom, const double& scaleFactor) throw(r_Error)
+{
+ r_Dimension dim = origin.dimension();
+ std::vector<r_Point> oldPoints = getPoints();
+ std::vector<r_Point>::const_iterator iter = oldPoints.begin();
+ std::vector<r_Point>::const_iterator iterEnd = oldPoints.end();
+ std::vector<r_Point> newPoints;
+ r_Point tmpPoint(dim);
+ r_Range coord=0;
+
+ // iterate through all points
+ while( iter != iterEnd )
+ {
+ // currently only 2-D, but who knows
+ for (int i=0; i<dim; i++)
+ {
+ coord = (*iter)[i];
+ // This is yet another copy of the code in tile.cc (another one is
+ // in fastscale.cc). Hope it is exact enough if I do not do the
+ // correction for seamless tiling as done in Tile::getScaleDomain().
+ coord = (r_Range)(origin[i] + floor((coord - origin[i]) * scaleFactor));
+ // This domain thing is driving me crazy. Ok, now we still have to
+ // shift the domain so that it coincides with the origin of the
+ // MInterval used for clipping later (i.e. the domain of the MDD
+ // object which will be later filled using the polygon. See
+ // fastscale.cc, r_Fast_Scale<T>::get_scaled_image().
+ coord = coord + mddDom[i].high() - clipDom[i].high();
+ tmpPoint[i] = coord;
+ }
+ newPoints.push_back(tmpPoint);
+ ++iter;
+ }
+ fromPoints(newPoints);
+}
+
+
+void
+r_Polygon::scale(const r_Point& origin, const double& scaleFactor) throw(r_Error)
+{
+ r_Dimension dim = origin.dimension();
+ std::vector<r_Point> oldPoints = getPoints();
+ std::vector<r_Point>::const_iterator iter = oldPoints.begin();
+ std::vector<r_Point>::const_iterator iterEnd = oldPoints.end();
+ std::vector<r_Point> newPoints;
+ r_Point tmpPoint(dim);
+ r_Range coord=0;
+
+ //std::cout << "Polygon bounding box " << getBoundingBox() << std::endl;
+
+ // iterate through all points
+ while( iter != iterEnd )
+ {
+ // currently only 2-D, but who knows
+ for (int i=0; i<dim; i++)
+ {
+ coord = (*iter)[i];
+ // scaling is done in this way:
+ // translate to 0, scale and translate back
+ coord = origin[i]+(r_Range)floor((coord-origin[i]) * scaleFactor);
+ tmpPoint[i] = coord;
+ }
+ newPoints.push_back(tmpPoint);
+ ++iter;
+ }
+ fromPoints(newPoints);
+
+ //std::cout << "Polygon bounding box " << getBoundingBox() << std::endl;
+}
+
+void
+r_Polygon::mirror(const r_Minterval& mddDom) throw(r_Error)
+{
+ r_Dimension dim = mddDom.dimension();
+ std::vector<r_Point> oldPoints = getPoints();
+ std::vector<r_Point>::const_iterator iter = oldPoints.begin();
+ std::vector<r_Point>::const_iterator iterEnd = oldPoints.end();
+ std::vector<r_Point> newPoints;
+ r_Point tmpPoint(dim);
+ r_Range y=0;
+
+ // iterate through all points
+ while( iter != iterEnd )
+ {
+ y = mddDom[1].high() - (*iter)[1];
+ tmpPoint = (*iter);
+ tmpPoint[1] = y;
+ newPoints.push_back(tmpPoint);
+ ++iter;
+ }
+ fromPoints(newPoints);
+}
+
+void
+r_Polygon::fromPoints(const std::vector<r_Point>& newPoints) throw(r_Error)
+{
+ std::vector<r_Point>::const_iterator iter, iterEnd;
+
+ if(newPoints.empty())
+ {
+ TALK( "r_Polygon::fromPoinst(....) newPoints is empty" );
+ RMInit::logOut << "r_Polygon::fromPoinst(....) newPoints is empty" << std::endl;
+ throw r_Error(r_Error::r_Error_General);
+ }
+
+ iter = newPoints.begin();
+ iterEnd = newPoints.end();
+ edges.clear();
+
+ firstPoint = *iter;
+ currPoint = *iter;
+ while( ++iter != iterEnd )
+ {
+ edges.push_back(r_Edge(currPoint, *iter));
+ currPoint = *iter;
+ }
+ edges.push_back(r_Edge(currPoint, firstPoint));
+ closed = true;
+}
+
+void
+r_Polygon::eraseLine( r_Range x1, r_Range x2, r_Range y, r_GMarray& myArray, const std::string& bgr ) const throw(r_Error)
+{
+ // Do nothing in that case (may happen due to rounding problems)
+ if(x2 < x1)
+ return;
+
+ r_Minterval eraseDom(2);
+ eraseDom << r_Sinterval(x1, x2) << r_Sinterval(y, y);
+ r_Minterval arrayDom = myArray.spatial_domain();
+ r_Bytes typeSize = myArray.get_type_length();
+ r_Bytes bgrSize = bgr.size();
+ const char *bgrContent=bgr.c_str();
+ char *currCell=NULL;
+
+
+ // Grrr. In RasDaMan the y are stored close together. So the whole fillPolygon
+ // should have been organised by x instead of y. Well, for now I just use an
+ // r_Miter here.
+ r_Miter eraseIter( &eraseDom, &arrayDom, typeSize, myArray.get_array() );
+ while( !eraseIter.isDone() )
+ {
+ currCell = eraseIter.nextCell();
+ // FIXME This potentially wont work for all types. I just set every byte to 0.
+ if(bgr.empty())
+ memset(currCell, 0, typeSize);
+ else
+ {
+ if( typeSize != bgrSize)
+ throw r_Error( r_Error::r_Error_TypeInvalid );
+ memmove(currCell, bgrContent, bgrSize);
+ }
+ }
+}
+
+std::vector<r_Point>
+r_Polygon::clip1Side(const r_Minterval& b, r_Polygon::Side s)
+{
+ // This routine clips a polygon against one (endless) edge of a bounding box.
+ // It is an implementation of the Sutherland-Hodgman algorithm geared more
+ // towards readability than efficiency. The algorithm classifies edges into
+ // four cases:
+ // Case 1: both ends are inside. Then add the end point to the list of points.
+ // Case 2: start inside, end outside. And only the intersection of the
+ // bounding box edge and the polygon edge.
+ // Case 3: completely outside. Add no points.
+ // Case 4: start outside, end inside. Add end and the intersection of the
+ // bounding box edge and the polygon edge.
+
+ std::vector<r_Point> out;
+ std::vector<r_Edge>::const_iterator iter, iterEnd;
+
+ // iterate through all edges
+ for(iter = edges.begin(),iterEnd=edges.end(); iter != iterEnd; ++iter)
+ {
+ if(inside(b, (*iter).getEnd(), s))
+ {
+ if(inside(b, (*iter).getStart(), s))
+ {
+ // case 1
+ out.push_back((*iter).getEnd());
+ }
+ else
+ {
+ // case 4
+ out.push_back(intersect(b, *iter, s));
+ out.push_back((*iter).getEnd());
+ }
+ }
+ else
+ {
+ if(inside(b, (*iter).getStart(), s))
+ {
+ // case 2
+ out.push_back(intersect(b, *iter, s));
+ }
+ }
+ // do nothing for case 3
+ }
+ return out;
+}
+
+bool
+r_Polygon::inside(const r_Minterval& b, const r_Point& p, r_Polygon::Side s)
+{
+ switch(s)
+ {
+ case top:
+ return p[1] <= b[1].high();
+ case bottom:
+ return p[1] >= b[1].low();
+ case right:
+ return p[0] <= b[0].high();
+ case left:
+ return p[0] >= b[0].low();
+ default:
+ return false;
+ }
+}
+
+r_Point
+r_Polygon::intersect(const r_Minterval& b, const r_Edge& e, r_Polygon::Side s)
+{
+ switch(s)
+ {
+ case top:
+ return r_Point( e.getCurrX(b[1].high()), b[1].high() );
+ case bottom:
+ return r_Point( e.getCurrX(b[1].low()), b[1].low() );
+ case right:
+ return r_Point( b[0].high(), e.getCurrY(b[0].high()) );
+ default: //case left:
+ return r_Point( b[0].low(), e.getCurrY(b[0].low()) );
+ }
+}
+
+r_Point
+r_Polygon::getMiddle() const throw(r_Error)
+{
+ // Note that the summing up done here is a bit risky since overflows
+ // give incorrect results.
+
+ r_Point retVal(2);
+ double xSum = 0;
+ double ySum = 0;
+ int pointCount = 0;
+ std::vector<r_Point> myPoints = getPoints();
+ std::vector<r_Point>::const_iterator iter = myPoints.begin();
+ std::vector<r_Point>::const_iterator iterEnd = myPoints.end();
+
+ while( iter != iterEnd )
+ {
+ ySum += (*iter)[1];
+ xSum += (*iter)[0];
+ ++pointCount;
+ ++iter;
+ }
+ retVal[0] = rint((xSum / pointCount));
+ retVal[1] = rint((ySum / pointCount));
+
+ return retVal;
+}
+
+void
+r_Polygon::shrinkPoly(int pixelCount) throw(r_Error)
+{
+ // Ok now, we move all points towards the middle. Since we store edges we
+ // have to use this somewhat clumsy form with using points in between.
+ // Note that there is quite a bit of potential for error (e.g. points
+ // coinciding after moving them), Anyway, this was programmed as a quick
+ // hack for a problem at BLVA.
+ r_Point middle = getMiddle();
+ r_Dimension dim = middle.dimension();
+ std::vector<r_Point> oldPoints = getPoints();
+ std::vector<r_Point>::const_iterator iter = oldPoints.begin();
+ std::vector<r_Point>::const_iterator iterEnd = oldPoints.end();
+ std::vector<r_Point> newPoints;
+ r_Point tmpPoint(dim);
+ r_Range coord=0;
+
+ // iterate through all points
+ while( iter != iterEnd )
+ {
+ // currently only 2-D, but who knows
+ for (int i=0; i<dim; i++)
+ {
+ coord = (*iter)[i];
+ if(coord > middle[i])
+ {
+ coord = coord - pixelCount;
+ }
+ else
+ {
+ if(coord < middle[i])
+ {
+ coord = coord + pixelCount;
+ }
+ }
+ tmpPoint[i] = coord;
+ }
+ newPoints.push_back(tmpPoint);
+ ++iter;
+ }
+ fromPoints(newPoints);
+}
+
+
+int
+r_Polygon::countEdges() const
+{
+ return edges.size();
+}
+
+int
+r_Polygon::countHorizontalEdges() const
+{
+ int counter = 0;
+
+ std::vector<r_Edge>::const_iterator iter = edges.begin();
+
+ for(int i=0;i<edges.size();i++,iter++)
+ {
+ counter += iter->isHorizontal() ? 1:0;
+ }
+ return counter;
+}
+
diff --git a/rasodmg/polygon.hh b/rasodmg/polygon.hh
new file mode 100644
index 0000000..ebed9ea
--- /dev/null
+++ b/rasodmg/polygon.hh
@@ -0,0 +1,287 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: polygon.hh
+ *
+ * MODULE: rasodmg
+ * CLASS: r_Polygon
+ *
+ * COMMENTS:
+ * None
+*/
+
+#ifndef _R_POLYGON_
+#define _R_POLYGON_
+
+#include <iostream>
+#include <vector>
+#include <string>
+
+#include "raslib/point.hh"
+#include "raslib/minterval.hh"
+
+class r_GMarray;
+
+//@ManMemo: Module: {\bf rasodmg}
+
+/*@Doc:
+
+ The class r_Edge is used to represent edges of 2-D polygons
+ represented in class r_Polygon. Edges cannot be modified. This does
+ not make sense, as a polygon always has to consist out of connecting
+ edges. Modifications should always be done on the polygon.
+
+*/
+
+class r_Edge
+{
+public:
+ /// constructor getting a 2-D start and end point.
+ r_Edge(const r_Point& newStart, const r_Point& newEnd);
+
+ /// retrieve 2-D start point of edge.
+ const r_Point& getStart() const;
+
+ /// retrieve 2-D end point of edge.
+ const r_Point& getEnd() const;
+
+ /// calculate inverse slope of the edge. Note: may throw exception due to division by 0.
+ double getInvSlope() const;
+
+ /// calculate slope of the edge. Note: may throw exception due to division by 0.
+ double getSlope() const;
+
+ /// retrieve x for a given y on a line with the slope of the edge. Calls getInvSlope().
+ double getCurrX(r_Range y) const;
+
+ /// retrieve y for a given x on a line with the slope of the edge. Calls getSlope().
+ double getCurrY(r_Range x) const;
+
+ /// print start and end point of the edge.
+ void print_status( std::ostream& s = std::cout ) const;
+
+ /// returns true if the edge is parallel to the first axis
+ bool isHorizontal() const;
+
+private:
+ /// start point of the edge.
+ r_Point start;
+
+ /// end point of the edge.
+ r_Point end;
+};
+
+/*@Doc:
+
+ The class r_Polygon is used to represent 2-D polygons in
+ RasDaMan. Polygons are always constructed by specifying a set of
+ points. This class is mainly used for doing polygonal cutouts on
+ r_Marray objects, it offers the relevant methods for that purpose.
+
+ The construction of a r_Polygon with addPoint has to finish with a
+ call to close(). A open polygon is not a legal polygon! Currently no
+ exceptions are thrown if a polygon is open and methods besides
+ addPointXY or close are called. The results are undefined, if the
+ polygon is not closed.
+
+*/
+
+class r_Polygon
+{
+public:
+
+ /// FIXME current we support only 2 dimensional polygon
+ static const r_Dimension polyPointDim;
+
+ /// enum used to clasify one polygon
+ enum r_Polygon_Type{
+ UNKNOWN,
+ CONCAVE,
+ CONVEX
+ };
+
+ /// constructor to initialize polygon from a string
+ r_Polygon(const char* init) throw (r_Error);
+
+ /// constructor getting x and y of the first point in the polygon.
+ r_Polygon(r_Range x, r_Range y);
+
+ /// copy constructor
+ r_Polygon(const r_Polygon&);
+
+ /// default constructor.
+ r_Polygon();
+
+ /// asignment opertor
+ r_Polygon& operator=(const r_Polygon&);
+
+ /// add a point to the polygon.
+ void addPoint(const r_Point& newPoint) throw(r_Error);
+
+ /// add a point to the polygon specifying x and y.
+ void addPointXY(r_Range x, r_Range y) throw(r_Error);
+
+ /// close a polygon after creation with addPointXY.
+ void close();
+
+ /// retrieve the set of all edges of the polygon.
+ const std::vector<r_Edge>& getEdges() const throw(r_Error);
+
+ /// determine the polygon type for an polygon in 2D
+ r_Polygon::r_Polygon_Type detectPolygonType() const throw(r_Error);
+ /**
+ It is assumed that the polygon is simple (does not intersect itself or have holes)
+ Returns UNKNOWN for incomputables eg: polygon with colinear points, polygon with less then 3 points
+ */
+
+ /// retrieve a vector of all points in the polygon.
+ std::vector<r_Point> getPoints() const throw(r_Error);
+ /**
+ Each point is connected with its successor. The last point is connected to the first one.
+ */
+
+ /// print all edges of the polygon.
+ void print_status( std::ostream& s = std::cout ) const;
+
+ /// Fill the 2-D array myArray according to the polygon.
+ void fillMArray( r_GMarray& myArray, bool fillInside = false, const std::string& bgr = "") const throw(r_Error);
+ /** The polygon has to be completely in the domain of the array. Should this not be the case,
+ then the polygon must be clipped according to the domain of the array. Filling is done
+ so that the data in the array is overwritten byte by byte with 0 which is not inside
+ the polygon.
+ */
+
+ /// retrieve the bounding box of the polygon.
+ r_Minterval getBoundingBox() const throw(r_Error);
+
+ /// clip the polygon according to the bounding box specified in clipDom.
+ void clip(const r_Minterval& clipDom) throw(r_Error);
+ /** Note that the r_Polygon object is modified! So after calling clip you will generally
+ have a different polygon represented by your object. */
+
+ /// scale the points of the polygon according to scaleFactor.
+ void scale(const r_Point& origin, const r_Minterval& mddDom,
+ const r_Minterval& clipDom, const double& scaleFactor) throw(r_Error);
+ /** This function is used when using a polygon to extract part of an image retrieved
+ with r_Fast_Scale. The scaling is done like in r_Fast_Base_Scale::get_scaled_domain().
+ origin is the point of origin for the scaling. mddDom is the domain of the MDD which
+ will later be filled with the polygon. Problem is, that the domain of this MDD is
+ currently not created by simply scaling the domain of the original MDD. Instead it
+ is made sure that the origin of the scaled domain stays the same. clipDom is used
+ to do the same when scaling the polygon, it contains the scaled domain of the MDD
+ without shifting it to origin of the domain of the MDD before scaling. It is a
+ bit complicated, I know. scaleFactor is trivially the scaleFactor used. */
+
+ /// scale the points of the polygon according to scaleFactor.
+ void scale(const r_Point& origin, const double& scaleFactor) throw(r_Error);
+ /** This function is used used when we scale a polygon to extract part of an image retrieved
+ with r_Fast_Scale. The scaling is done like in r_Fast_Base_Scale::get_scaled_domain().
+ origin is the point of origin for the scaling. scaleFactor is the scale factor used. */
+
+ /// mirrors a polygon along the y-axes point by point.
+ void mirror(const r_Minterval& mddDom) throw(r_Error);
+ /** The mirroring is done along the middle of mddDom. It is done like that to be coherent
+ with the mirroring commonly done when inserting TIFF image, e.g. in insertlva.cc. */
+
+ /// get "middle" point by averaging all x and y values.
+ r_Point getMiddle() const throw(r_Error);
+
+ /// "shrink" polygon by moving all points towards the middle by pixelCount pixels.
+ void shrinkPoly(int pixelCount) throw(r_Error);
+
+ /// returns the number of edges
+ int countEdges() const;
+
+ /// returns the number of horizontal edges (used by polygon cut out)
+ int countHorizontalEdges() const;
+
+private:
+
+ /// check if the current point is the first point to close the polygon
+ void checkFistPoint();
+
+ /// clipping is done side by side. This enum is used to tell functions which side to clip.
+ enum Side {
+ top, bottom, left, right
+ };
+
+ /// overwrite this with a polygon create from a vector of points.
+ void fromPoints(const std::vector<r_Point>& newPoints) throw(r_Error);
+
+ /// erase the area in myArray outside of the polygon for one scanline.
+ void eraseLine( r_Range x1, r_Range x2, r_Range y, r_GMarray& myArray, const std::string& bgr ) const throw(r_Error);
+
+ /// return the polygon clipped on the specified side as a list of points.
+ std::vector<r_Point> clip1Side(const r_Minterval& b, r_Polygon::Side s);
+
+ /// determine if a point is inside a bounding line on a certain side.
+ bool inside(const r_Minterval& b, const r_Point& p, r_Polygon::Side s);
+
+ /// intersect an edge with a bounding line on a certain side.
+ r_Point intersect(const r_Minterval& b, const r_Edge& e, r_Polygon::Side s);
+
+ /// flag if the polygon is closed.
+ bool closed;
+
+ /// flag if firstPoint has been set.
+ bool firstPointSet;
+
+ /// vector of all edges of the polygon.
+ std::vector<r_Edge> edges;
+ /// remember first point. Used when constructing the polygon.
+
+ r_Point firstPoint;
+
+ /// remember last added point. Used when constructing the polygon.
+ r_Point currPoint;
+};
+
+extern std::ostream& operator<<( std::ostream& s, const r_Polygon& d );
+
+// The following classes are STL function objects which can be used to make
+// sorted collection of r_Edge. In the current implementation only the first
+// one is needed.
+
+class EdgeSortCriterion
+{
+public:
+ // This is needed for keeping a sorted set of edges (sorted by start coordinate y,
+ // then start coordinate x).
+ bool operator() (const r_Edge& e1, const r_Edge& e2) const {
+ return e1.getStart()[1] < e2.getStart()[1] ||
+ (!(e2.getStart()[1] < e1.getStart()[1]) && e1.getStart()[0] < e2.getStart()[0]);
+ }
+};
+
+class ActiveEdgeSortCriterion
+{
+public:
+ // This is needed for keeping a sorted set of active edges (sorted by start coordinate x,
+ // then start coordinate y).
+ bool operator() (const r_Edge& e1, const r_Edge& e2) const {
+ return e1.getStart()[0] < e2.getStart()[0] ||
+ (!(e2.getStart()[0] < e1.getStart()[0]) && e1.getStart()[1] < e2.getStart()[1]);
+ }
+};
+
+#endif
diff --git a/rasodmg/ref.cc b/rasodmg/ref.cc
new file mode 100644
index 0000000..b63be0e
--- /dev/null
+++ b/rasodmg/ref.cc
@@ -0,0 +1,656 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: ref.cc
+ *
+ * MODULE: rasodmg
+ * CLASS: r_Ref
+ *
+ * COMMENTS:
+ * None
+*/
+
+static const char rcsidref[] = "@(#)rasodmg, r_Ref: $Id: ref.cc,v 1.28 2002/08/28 12:10:18 coman Exp $";
+
+#include "rasodmg/database.hh"
+#include "rasodmg/ref.hh"
+
+#include "raslib/rmdebug.hh"
+
+#ifdef __VISUALC__
+#include <sstrea.h>
+#else
+#include <sstream>
+#endif
+
+#include "rasodmg/transaction.hh"
+#include "clientcomm/clientcomm.hh"
+
+// forward declaration needed because of EARLY_TEMPLATE
+class r_Transaction;
+
+// In case of early templates take care non-template code is only
+// compiled once.
+#ifndef __EXECUTABLE__
+
+r_Ref_Any::r_Ref_Any()
+ : memptr(0), oid()
+{
+ RMDBGONCE(4, RMDebug::module_rasodmg, "r_Ref_Any", "r_Ref_Any()")
+}
+
+
+
+r_Ref_Any::r_Ref_Any( const r_Ref_Any& obj )
+{
+ RMDBGONCE(4, RMDebug::module_rasodmg, "r_Ref_Any", "r_Ref_Any( const r_Ref_Any& )")
+ memptr = obj.memptr;
+ oid = obj.oid;
+}
+
+
+
+r_Ref_Any::r_Ref_Any( const r_OId& initOId )
+ : memptr(0)
+{
+ RMDBGONCE(4, RMDebug::module_rasodmg, "r_Ref_Any", "r_Ref_Any( const r_OId& )")
+ oid = initOId;
+}
+
+
+
+r_Ref_Any::r_Ref_Any( r_Object* ptr )
+ : oid(), memptr( ptr )
+{
+ RMDBGONCE(4, RMDebug::module_rasodmg, "r_Ref_Any", "r_Ref_Any( r_Object* )")
+}
+
+
+
+r_Ref_Any::r_Ref_Any( void* ptr )
+ : oid(), memptr( ptr )
+{
+ RMDBGONCE(4, RMDebug::module_rasodmg, "r_Ref_Any", "r_Ref_Any( void* )")
+}
+
+
+r_Ref_Any::r_Ref_Any( const r_OId &initOId, r_Object* ptr )
+ : oid( initOId ), memptr( ptr )
+{
+ RMDBGONCE(4, RMDebug::module_rasodmg, "r_Ref_Any", "r_Ref_Any( const r_OId &oid, const r_Object* )")
+}
+
+
+
+r_Ref_Any::~r_Ref_Any()
+{
+ RMDBGONCE(4, RMDebug::module_rasodmg, "r_Ref_Any", "~r_Ref_Any()")
+
+ // object should not be delete from databse when reference destructor is called
+ // if( memptr ){
+ // delete memptr;
+ // memptr = 0;
+ // }
+}
+
+
+
+r_Ref_Any&
+r_Ref_Any::operator=( const r_Ref_Any& objptr )
+{
+ memptr = objptr.memptr;
+ oid = objptr.oid;
+
+ return *this;
+}
+
+
+
+r_Ref_Any&
+r_Ref_Any::operator=( r_Object* ptr )
+{
+ memptr = ptr;
+ oid = r_OId();
+
+ return *this;
+}
+
+
+
+void
+r_Ref_Any::destroy()
+{
+ RMDBGONCE(4, RMDebug::module_rasodmg, "r_Ref_Any", "destroy()")
+
+ if( memptr && !oid.is_valid() ){
+ delete memptr;
+ memptr = 0;
+ }
+}
+
+
+void
+r_Ref_Any::delete_object()
+{
+ RMDBGONCE(4, RMDebug::module_rasodmg, "r_Ref_Any", "delete_object()")
+
+ if( memptr ){
+ delete memptr;
+ memptr = 0;
+ }
+}
+
+
+
+r_Ref_Any::operator const void*() const
+{
+ return memptr;
+}
+
+
+
+r_Ref_Any::operator void*()
+{
+ return memptr;
+}
+
+
+
+r_Ref_Any::operator r_Point*()
+{
+ return (r_Point*)memptr;
+}
+
+
+
+r_Ref_Any::operator r_Sinterval*()
+{
+ return (r_Sinterval*)memptr;
+}
+
+
+
+r_Ref_Any::operator r_Minterval*()
+{
+ return (r_Minterval*)memptr;
+}
+
+
+
+r_Ref_Any::operator r_OId*()
+{
+ return (r_OId*)memptr;
+}
+
+
+
+r_Ref_Any::operator r_Scalar*()
+{
+ return (r_Scalar*)memptr;
+}
+
+
+
+r_Ref_Any::operator r_Primitive*()
+{
+ return (r_Primitive*)memptr;
+}
+
+
+
+r_Ref_Any::operator r_Structure*()
+{
+ return (r_Structure*)memptr;
+}
+
+
+
+int
+r_Ref_Any::operator!() const
+{
+ return !is_null();
+}
+
+
+
+int
+r_Ref_Any::is_null() const
+{
+ return (memptr==0) && !oid.is_valid();
+}
+
+
+
+int
+r_Ref_Any::operator==( const r_Ref_Any& ref ) const
+{
+ RMDBGONCE(4, RMDebug::module_rasodmg, "r_Ref_Any", "operator==( const r_Ref_Any& )")
+ return // both refs are not valid or ...
+ ( is_null() && ref.is_null() ) ||
+ // both oids are valid and the same or ...
+ ( oid.is_valid() && oid == ref.oid ) ||
+ // both oids are not valid and memory pointers are the same
+ ( !oid.is_valid() && !ref.oid.is_valid() && memptr == ref.memptr );
+}
+
+
+
+int
+r_Ref_Any::operator!=( const r_Ref_Any& ref ) const
+{
+ RMDBGONCE(4, RMDebug::module_rasodmg, "r_Ref_Any", "operator!=( const r_Ref_Any& )")
+ return !operator==( ref );
+}
+
+
+
+int
+r_Ref_Any::operator==( const r_Object* ptr ) const
+{
+ RMDBGONCE(4, RMDebug::module_rasodmg, "r_Ref_Any", "operator==( const r_Object* )")
+ return memptr == (void*)ptr;
+}
+
+
+
+int
+r_Ref_Any::operator!=( const r_Object* ptr ) const
+{
+ RMDBGONCE(4, RMDebug::module_rasodmg, "r_Ref_Any", "operator!=( const r_Object* )")
+ return !operator==( ptr );
+}
+
+
+
+
+void*
+r_Ref_Any::get_memory_ptr() const
+{
+ return memptr;
+}
+
+#endif // __EXECUTABLE__
+
+
+
+template<class T>
+r_Ref<T>::r_Ref()
+ : memptr(0), oid()
+{
+ RMDBGONCE(4, RMDebug::module_rasodmg, "r_Ref", "r_Ref()")
+}
+
+
+
+template<class T>
+r_Ref<T>::r_Ref( const r_Ref<T>& obj )
+{
+ RMDBGONCE(4, RMDebug::module_rasodmg, "r_Ref", "r_Ref( const r_Ref<T>& )")
+ memptr = obj.memptr;
+ oid = obj.oid;
+}
+
+
+
+template<class T>
+r_Ref<T>::r_Ref( const r_OId& initOId )
+ : memptr(0)
+{
+ RMDBGONCE(4, RMDebug::module_rasodmg, "r_Ref", "r_Ref( const r_OId& )")
+ oid = initOId;
+}
+
+
+
+template<class T>
+r_Ref<T>::r_Ref( const r_Ref_Any& obj )
+{
+ RMDBGONCE(4, RMDebug::module_rasodmg, "r_Ref", "r_Ref( const r_Ref_Any& )")
+
+ memptr = (T*)obj.get_memory_ptr();
+ oid = obj.get_oid();
+}
+
+
+
+template<class T>
+r_Ref<T>::r_Ref( T* ptr )
+ : oid(), memptr( ptr )
+{
+ RMDBGONCE(4, RMDebug::module_rasodmg, "r_Ref", "r_Ref( const T* )")
+}
+
+
+
+template<class T>
+r_Ref<T>::r_Ref( const r_OId &initOId, T* ptr )
+ : oid( initOId ), memptr( ptr )
+{
+ RMDBGONCE(4, RMDebug::module_rasodmg, "r_Ref", "r_Ref( const r_OId &oid, const T* )")
+}
+
+
+
+template<class T>
+r_Ref<T>::~r_Ref()
+{
+ RMDBGONCE(4, RMDebug::module_rasodmg, "r_Ref", "~r_Ref()")
+
+ // object should not be delete from databse when reference destructor is called
+ // if( memptr ){
+ // delete memptr;
+ // memptr = 0;
+ // }
+}
+
+
+
+template<class T>
+r_Ref<T>::operator r_Ref_Any() const
+{
+ RMDBGONCE(4, RMDebug::module_rasodmg, "r_Ref", "operator r_Ref_Any()")
+ return r_Ref_Any( oid, (r_Object *)memptr );
+}
+
+
+/*
+template<class T>
+r_Ref<T>::operator const r_Ref_Any() const
+{
+ RMDBGONCE(4, RMDebug::module_rasodmg, "r_Ref", "operator const r_Ref_Any()")
+ return r_Ref_Any( oid, memptr );
+}
+*/
+
+template<class T>
+r_Ref<T>&
+r_Ref<T>::operator=( const r_Ref_Any& ptr )
+{
+ memptr = (T*)ptr.get_memory_ptr();
+ oid = ptr.get_oid();
+
+ return *this;
+}
+
+
+
+template<class T>
+r_Ref<T>&
+r_Ref<T>::operator=( T* ptr )
+{
+ memptr = ptr;
+ oid = r_OId();
+
+ return *this;
+}
+
+
+
+/*
+template<class T>
+r_Ref<T>&
+r_Ref<T>::operator=( r_Ref<T>& objptr )
+{
+ memptr = objptr.memptr;
+ oid = objptr.oid;
+
+ return *this;
+}
+*/
+
+
+template<class T>
+r_Ref<T>&
+r_Ref<T>::operator=( const r_Ref<T>& objptr )
+{
+ memptr = objptr.memptr;
+ oid = objptr.oid;
+
+ return *this;
+}
+
+
+
+template<class T>
+const T&
+r_Ref<T>::operator*() const throw( r_Error )
+{
+ RMDBGONCE(4, RMDebug::module_rasodmg, "r_Ref", "operator*()")
+ if( !memptr )
+ load_object();
+
+ if( !memptr )
+ {
+ r_Error err = r_Error( r_Error::r_Error_RefNull );
+ throw err;
+ }
+
+ return *memptr;
+}
+
+
+template<class T>
+T&
+r_Ref<T>::operator*() throw( r_Error )
+{
+ RMDBGONCE(4, RMDebug::module_rasodmg, "r_Ref", "operator*()")
+ if( !memptr )
+ load_object();
+
+ if( !memptr )
+ {
+ r_Error err = r_Error( r_Error::r_Error_RefNull );
+ throw err;
+ }
+
+ return *memptr;
+}
+
+
+
+template<class T>
+const T*
+r_Ref<T>::operator->() const throw( r_Error )
+{
+ RMDBGONCE(4, RMDebug::module_rasodmg, "r_Ref", "operator->()")
+ if( !memptr )
+ load_object();
+
+ if( !memptr )
+ {
+ r_Error err = r_Error( r_Error::r_Error_RefNull );
+ throw err;
+ }
+
+ return memptr;
+}
+
+template<class T>
+T*
+r_Ref<T>::operator->() throw( r_Error )
+{
+ RMDBGONCE(4, RMDebug::module_rasodmg, "r_Ref", "operator->()")
+ if( !memptr )
+ load_object();
+
+ if( !memptr )
+ {
+ r_Error err = r_Error( r_Error::r_Error_RefNull );
+ throw err;
+ }
+
+ return memptr;
+}
+
+
+
+template<class T>
+const T*
+r_Ref<T>::ptr() const throw( r_Error )
+{
+ RMDBGONCE(4, RMDebug::module_rasodmg, "r_Ref", "ptr()")
+ if( !memptr )
+ load_object();
+
+ return memptr;
+}
+
+
+template<class T>
+T*
+r_Ref<T>::ptr() throw( r_Error )
+{
+ RMDBGONCE(4, RMDebug::module_rasodmg, "r_Ref", "ptr()")
+ if( !memptr )
+ load_object();
+
+ return memptr;
+}
+
+
+
+template<class T>
+int
+r_Ref<T>::operator!() const
+{
+ return !is_null();
+}
+
+
+
+template<class T>
+int
+r_Ref<T>::is_null() const
+{
+ return (memptr==0) && !oid.is_valid();
+}
+
+
+
+template<class T>
+int
+r_Ref<T>::operator==( const r_Ref<T>& refR ) const
+{
+ RMDBGONCE(4, RMDebug::module_rasodmg, "r_Ref", "operator==( const r_Ref<T>& )")
+ return // both refs are not valid or ...
+ ( is_null() && refR.is_null() ) ||
+ // both oids are valid and the same or ...
+ ( oid.is_valid() && oid == refR.oid ) ||
+ // both oids are not valid and memory pointers are the same
+ ( !oid.is_valid() && !refR.oid.is_valid() && memptr == refR.memptr );
+}
+
+
+
+template<class T>
+int
+r_Ref<T>::operator!=( const r_Ref<T>& refR ) const
+{
+ RMDBGONCE(4, RMDebug::module_rasodmg, "r_Ref", "operator!=( const r_Ref<T>& )")
+ return !operator==( refR );
+}
+
+
+
+template<class T>
+int
+r_Ref<T>::operator==( const T* ptr ) const
+{
+ RMDBGONCE(4, RMDebug::module_rasodmg, "r_Ref", "operator==( const T* )")
+ return memptr == ptr;
+}
+
+
+
+template<class T>
+int
+r_Ref<T>::operator!=( const T* ptr ) const
+{
+ RMDBGONCE(4, RMDebug::module_rasodmg, "r_Ref", "operator!=( const T* )")
+ return !operator==( ptr );
+}
+
+
+template<class T>
+void
+r_Ref<T>::destroy()
+{
+ RMDBGONCE(4, RMDebug::module_rasodmg, "r_Ref", "destroy()")
+
+ if( memptr && !oid.is_valid() ){
+ delete memptr;
+ memptr = 0;
+ }
+}
+
+
+
+template<class T>
+void
+r_Ref<T>::delete_object()
+{
+ RMDBGONCE(4, RMDebug::module_rasodmg, "r_Ref", "delete_object()")
+
+ if( memptr ){
+ delete memptr;
+ memptr = 0;
+ }
+}
+
+
+
+template<class T>
+T*
+r_Ref<T>::get_memory_ptr() const
+{
+ return memptr;
+}
+
+#ifdef DEF_TRANSACTION
+
+template<class T>
+void
+r_Ref<T>::load_object() const
+{
+ if( oid.is_valid() )
+ {
+ if( r_Database::actual_database == 0 || r_Database::actual_database->get_status() == r_Database::not_open )
+ {
+ r_Error err = r_Error( r_Error::r_Error_DatabaseClosed );
+ throw err;
+ }
+
+ if( r_Transaction::actual_transaction == 0 ||
+ r_Transaction::actual_transaction->get_status() != r_Transaction::active )
+ {
+ r_Error err = r_Error( r_Error::r_Error_TransactionNotOpen );
+ throw err;
+ }
+
+ // load object and take its memory pointer
+ r_Ref<T> ref = r_Transaction::actual_transaction->load_object( oid );
+ memptr = ref.get_memory_ptr();
+ }
+}
+
+#endif
diff --git a/rasodmg/ref.hh b/rasodmg/ref.hh
new file mode 100644
index 0000000..2b5678e
--- /dev/null
+++ b/rasodmg/ref.hh
@@ -0,0 +1,323 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: ref.hh
+ *
+ * MODULE: rasodmg
+ * CLASS: r_Ref, r_Ref_Any
+ *
+ * COMMENTS:
+ * None
+*/
+
+#ifndef _D_REF_
+#define _D_REF_
+
+#include "raslib/error.hh"
+#include "raslib/oid.hh"
+
+class r_Object;
+class r_Point;
+class r_Sinterval;
+class r_Minterval;
+class r_Oid;
+class r_Scalar;
+class r_Primitive;
+class r_Structure;
+
+//@ManMemo: Module: {\bf rasodmg}
+
+/**
+ The class \Ref{r_Ref_Any} is defined to support a reference to any
+ type. Its primary purpose is to handle generic refernces and allow
+ conversions of \Ref{r_Ref}s in the type hierarchy. A \Ref{r_Ref_Any}
+ object can be used as an intermediary between any two types \Ref{r_Ref}<X>
+ and \Ref{r_Ref}<Y> where X and Y are different types. A \Ref{r_Ref}<T> can
+ always be converted to a \Ref{r_Ref_Any}; there is a function to perform
+ the conversion in the \Ref{r_Ref}<T> template. Each \Ref{r_Ref}<T> class
+ has a constructor and assignment operator that takes a reference to a
+ \Ref{r_Ref_Any}.
+*/
+
+class r_Ref_Any
+{
+ public:
+ /// default constructor
+ r_Ref_Any();
+
+ /// copy constructor
+ r_Ref_Any( const r_Ref_Any& );
+
+ /// constructor for creating a reference with an oid
+ r_Ref_Any( const r_OId& initOId );
+ /**
+ Dereferencing the self object results in loading the object with {\tt initOId}.
+ */
+
+ /// constructor getting a pointer to a persistent capable object
+ r_Ref_Any( r_Object* );
+
+ /// constructor getting a general pointer
+ r_Ref_Any( void* );
+
+ /// destructor deletes referenced object from main memory and database
+ ~r_Ref_Any();
+
+ /// assignment operator for assigning a \Ref{r_Ref_Any} pointer
+ r_Ref_Any& operator=( const r_Ref_Any& );
+
+ /// assignment operator for assigning a pointer to a persistent capable object
+ r_Ref_Any& operator=( r_Object* );
+
+ /// delete from main memory
+ void destroy();
+
+ /// deletes referenced object from main memory and database
+ void delete_object();
+
+ //@Man: Cast operators:
+ //@{
+ ///
+
+ ///
+ operator const void*() const;
+ ///
+ operator void*();
+ ///
+ operator r_Point*();
+ ///
+ operator r_Sinterval*();
+ ///
+ operator r_Minterval*();
+ ///
+ operator r_OId*();
+ ///
+ operator r_Scalar*();
+ ///
+ operator r_Structure*();
+ ///
+ operator r_Primitive*();
+
+ ///
+ //@}
+
+
+ /// operator for validity test
+ int operator!() const;
+
+ /// method for reference validity test
+ int is_null() const;
+ /**
+ The method delivers true iff the oid and/or the memory pointer are valid.
+ */
+
+ //@Man: Comparison operators:
+ //@{
+ ///
+
+ ///
+ int operator==( const r_Ref_Any& ) const;
+ ///
+ int operator!=( const r_Ref_Any& ) const;
+ /// compares the memory pointer (does not load the object)
+ int operator==( const r_Object* ) const;
+ /// compares the memory pointer (does not load the object)
+ int operator!=( const r_Object* ) const;
+
+ ///
+ //@}
+
+ /// get oid
+ inline const r_OId& get_oid() const;
+
+ //@Man: Methods for internal use only
+ //@{
+ ///
+ /// constructor getting oid and memory pointer
+ r_Ref_Any( const r_OId&, r_Object* );
+ ///
+ inline unsigned int is_oid_valid() const;
+ /// get memory pointer (without loading the object)
+ void* get_memory_ptr() const;
+ ///
+ //@}
+
+ private:
+ /// main memory pointer
+ void* memptr;
+
+ /// object identifier
+ r_OId oid;
+};
+
+
+
+
+//@ManMemo: Module: {\bf rasodmg}
+
+/**
+ References of type \Ref{r_Ref} in many respects behave like
+ C++ pointers but provide an additional mechanism that guarantees
+ integrity in references to persistent objects. \Ref{r_Ref}
+ implements a so called {\bf smart pointer} which behaves like
+ a C++ pointer but can do additional things in time of dereferencing
+ the pointer. In case that no valid memory pointer is available,
+ which means that the object is not present, and an oid is existing,
+ the object belonging to the oid is read from the db and the new
+ memory pointer is given back.
+*/
+
+template<class T>
+class r_Ref
+{
+ public:
+ /// default constructor
+ r_Ref();
+
+ /// constructor for r_Ref_Any objects
+ r_Ref( const r_Ref_Any& );
+
+ /// constructor for creating a reference with an oid
+ r_Ref( const r_OId& initOId );
+ /**
+ Dereferencing the self object results in loading the object with {\tt initOId}.
+ */
+
+ /// copy constructor
+ r_Ref( const r_Ref<T>& );
+
+ /// destructor deletes referenced object from main memory and database
+ ~r_Ref();
+
+ /// cast to \Ref{r_Ref_Any}
+ operator r_Ref_Any() const;
+
+ // cast to const \Ref{r_Ref_Any}
+ // operator const r_Ref_Any() const;
+
+ /// assignment operator for assigning a \Ref{r_Ref_Any}
+ r_Ref<T>& operator=( const r_Ref_Any& );
+
+ /// assignment operator for assigning a C pointer
+ r_Ref<T>& operator=( T* );
+
+ // assignment operator for assigning a r_Ref pointer
+ // r_Ref<T>& operator=( r_Ref<T>& );
+
+ /// assignment operator for assigning a r_Ref pointer
+ r_Ref<T>& operator=( const r_Ref<T>& );
+
+ /// dereference operator (error kinds: r_Error_RefNull, r_Error_RefInvalid)
+ const T& operator*() const throw (r_Error);
+
+ /// dereference operator (error kinds: r_Error_RefNull, r_Error_RefInvalid)
+ T& operator*() throw( r_Error );
+ /**
+ If the memory pointer is zero and the oid is valid, the object is loaded from the server
+ and a reference to the object in memory is returned.
+ */
+
+ const T* operator->() const throw (r_Error);
+
+ /// operator for dereferencing the reference (error kinds: r_Error_RefNull, r_Error_RefInvalid)
+ T* operator->() throw( r_Error );
+ /**
+ If the memory pointer is zero and the oid is valid, the object is loaded from the server
+ and the new memory location is returned.
+ */
+
+ const T* ptr() const throw (r_Error);
+
+ /// method for dereferencing the reference (error kinds: r_Error_RefNull, r_Error_RefInvalid)
+ T* ptr() throw( r_Error );
+ /**
+ If the memory pointer is zero and the oid is valid, the object is loaded from the server
+ and the new memory location is returned.
+ */
+
+ /// operator for validity test
+ int operator!() const;
+
+ /// method for reference validity test
+ int is_null() const;
+ /**
+ The method delivers true iff the oid and/or the memory pointer are valid.
+ */
+
+ //@Man: Comparison operators:
+ //@{
+ ///
+
+ ///
+ int operator==( const r_Ref<T>& refR ) const;
+ ///
+ int operator!=( const r_Ref<T>& refR ) const;
+ /// compares the memory pointer (does not load the object)
+ int operator==( const T* ) const;
+ /// compares the memory pointer (does not load the object)
+ int operator!=( const T* ) const;
+
+ ///
+ //@}
+
+ /// delete from main memory
+ void destroy();
+
+ /// deletes referenced object from main memory and database
+ void delete_object();
+
+ /// get oid
+ inline const r_OId& get_oid() const;
+
+ //@Man: Methods for internal use only
+ //@{
+ ///
+ /// constructor getting memory pointer
+ r_Ref( T* );
+
+ /// constructor getting oid and memory pointer
+ r_Ref( const r_OId&, T* );
+
+ /// get memory pointer (without loading the object)
+ T* get_memory_ptr() const;
+
+ ///
+ inline unsigned int is_oid_valid() const;
+
+ ///
+ //@}
+
+ private:
+ /// loads an object from database
+ void load_object() const;
+
+ /// main memory pointer
+ mutable T* memptr;
+
+ /// object identifier
+ r_OId oid;
+};
+
+#include "rasodmg/ref.icc"
+
+#endif
diff --git a/rasodmg/ref.icc b/rasodmg/ref.icc
new file mode 100644
index 0000000..8289b8f
--- /dev/null
+++ b/rasodmg/ref.icc
@@ -0,0 +1,64 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INLINE SOURCE: ref.icc
+ *
+ * MODULE: rasodmg
+ * CLASS: r_Ref
+ *
+ * COMMENTS:
+ * None
+*/
+
+
+inline const r_OId&
+r_Ref_Any::get_oid() const
+{
+ return oid;
+}
+
+
+
+inline unsigned int
+r_Ref_Any::is_oid_valid() const
+{
+ return oid.is_valid();
+}
+
+
+
+template<class T>
+inline const r_OId&
+r_Ref<T>::get_oid() const
+{
+ return oid;
+}
+
+
+
+template<class T>
+inline unsigned int
+r_Ref<T>::is_oid_valid() const
+{
+ return oid.is_valid();
+}
diff --git a/rasodmg/set.cc b/rasodmg/set.cc
new file mode 100644
index 0000000..b79fc4e
--- /dev/null
+++ b/rasodmg/set.cc
@@ -0,0 +1,92 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: set.cc
+ *
+ * MODULE: rasodmg
+ * CLASS: r_Set
+ *
+ * COMMENTS:
+ * None
+*/
+
+
+static const char rcsidset[] = "@(#)rasodmg, r_Set: $Id: set.cc,v 1.17 2002/08/23 11:18:44 schatz Exp $";
+
+#include "rasodmg/set.hh"
+
+class r_GMarray;
+
+#ifdef __VISUALC__
+ template class r_Set< r_GMarray *>;
+#endif
+
+#ifndef __GNUG__
+#define NULL 0
+#endif
+
+template<class T>
+r_Set<T>::r_Set() throw(r_Error)
+ : r_Collection<T>()
+{
+ this->allowsDuplicates = 0;
+ this->isOrdered = 0;
+ this->card = 0;
+}
+
+/* OBSOLETE
+template<class T>
+r_Set<T>::r_Set( const char* name )
+ : r_Collection<T>( name )
+{
+ allowsDuplicates = 0;
+ isOrdered = 0;
+ card = 0;
+}
+*/
+
+template<class T>
+r_Set<T>::r_Set( const r_Set<T>& set ) throw(r_Error)
+ : r_Collection<T>( set )
+{
+ this->allowsDuplicates = 0;
+ this->isOrdered = 0;
+}
+
+template<class T>
+r_Set<T>::~r_Set()
+{
+}
+
+template<class T>
+void
+r_Set<T>::insert_element( const T& element, int no_modification )
+{
+ typename r_Collection<T>::CNode* ptr = (typename r_Collection<T>::CNode*)this->coll;
+
+ while ( ptr->next != NULL && *((T*)(ptr->elem)) != element )
+ ptr = ptr->next;
+
+ if ( ptr->elem == NULL || *((T*)(ptr->elem)) != element )
+ r_Collection<T>::insert_element( element, no_modification );
+}
diff --git a/rasodmg/set.hh b/rasodmg/set.hh
new file mode 100644
index 0000000..b9f4915
--- /dev/null
+++ b/rasodmg/set.hh
@@ -0,0 +1,79 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: set.hh
+ *
+ * MODULE: rasodmg
+ * CLASS: r_Set
+ *
+ * COMMENTS:
+ * None
+*/
+
+#ifndef _D_SET_
+#define _D_SET_
+
+#include "rasodmg/collection.hh"
+
+//@ManMemo: Module: {\bf rasodmg}
+
+/*@Doc:
+
+ The class implements a set container. It inherits most of the
+ functionality from {\tt r_Collection}. The set can not have
+ any duplicates and it is not ordered.
+
+*/
+
+template <class T>
+class r_Set : public r_Collection<T>
+{
+ public:
+ /// default constructor
+ r_Set() throw(r_Error);
+ /// copy constructor
+ r_Set( const r_Set<T>& set ) throw(r_Error);
+ /// virtual destructor
+ virtual ~r_Set();
+
+ /// inserts an element at the beginning (no duplicates)
+ virtual void insert_element( const T& element, int no_modification = 0 );
+ /**
+ The method inserts an element into the collection. If {\tt no_modification}
+ is set, the {\tt mark_modified()} method of r_Object is not invoked and, therefore,
+ a modification will not be recognized at the commit point.
+ */
+
+};
+
+#ifdef EARLY_TEMPLATE
+#ifdef __EXECUTABLE__
+#ifdef __VISUALC__
+#include "rasodmg/set.cpp"
+#else
+#include "rasodmg/set.cc"
+#endif
+#endif
+#endif
+
+#endif
diff --git a/rasodmg/stattiling.cc b/rasodmg/stattiling.cc
new file mode 100644
index 0000000..d99df04
--- /dev/null
+++ b/rasodmg/stattiling.cc
@@ -0,0 +1,678 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: stattiling.cc
+ *
+ * MODULE: rasodmg
+ * CLASS: r_Stat_Tiling r_Access
+ *
+ * COMMENTS:
+ * None
+ */
+
+#ifdef __VISUALC__
+// Diable warning for signed/unsigned mismatch.
+#pragma warning( disable : 4018 )
+#endif
+
+#include "rasodmg/interesttiling.hh"
+#include "rasodmg/alignedtiling.hh"
+#include "rasodmg/stattiling.hh"
+#include "raslib/rminit.hh"
+#include "raslib/rmdebug.hh"
+
+#include <assert.h>
+#include <string.h>
+#include <math.h>
+#include <cstdlib>
+
+// Uncoment the _VISUALIZE_2D_DECOMP_ line to generate ppm files the
+// visualization of the domain decomposition done by the algoritm
+// #define _VISUALIZE_2D_DECOMP_
+
+// Uncomment the following line to have debug information (printfs)
+// #define _DEBUG_STATTILING_
+
+#ifdef _VISUALIZE_2D_DECOMP_
+#include "tools/visualtiling2d.hh"
+#endif
+
+const char*
+r_Stat_Tiling::description = "dimensions, access patterns, border threshold, interesting threshold, tile size (in bytes) (ex: \"2;[0:9,0:9],3;[100:109,0:9],2;2;0.3;100\")";
+
+const r_ULong
+r_Stat_Tiling::DEF_BORDER_THR = 50;
+const r_Double
+r_Stat_Tiling::DEF_INTERESTING_THR = 0.20;
+
+r_Stat_Tiling::r_Stat_Tiling(const char* encoded) throw (r_Error)
+ : r_Dimension_Tiling(0, 0)
+{
+ if(!encoded)
+ {
+ RMInit::logOut << "r_Stat_Tiling::r_Stat_Tiling(" << (encoded?encoded: "NULL") << ")" << endl;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+
+ r_Dimension tileD=0;
+ std::vector<r_Access> vectAccessInfo;
+ r_Access* accessInfo=NULL;
+ r_Minterval* accessInterv=NULL;
+ r_ULong accessTimes=0;
+ r_Bytes tileS=0, lenToConvert=0, lenInToConvert=0;
+ r_Area borderTH=0;
+ r_Double interestTH=0.;
+ const char *pStart=NULL, *pEnd=NULL, *pRes=NULL, *pTemp=NULL;
+ char *pToConvert=NULL;
+ const char *pInRes=NULL, *pInEnd=NULL;
+ char *pInToConvert=NULL;
+
+ pStart=encoded;
+ pEnd=pStart+strlen(pStart);
+ pTemp=pStart;
+
+ pRes=strstr(pTemp,COLON);
+ if(!pRes)
+ {
+ RMInit::logOut << "r_Stat_Tiling::r_Stat_Tiling(" << encoded << "): Error decoding tile dimension from \"" << pTemp << "\"." << endl;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+
+ //deal with dimension
+ lenToConvert=pRes-pTemp;
+ pToConvert=new char[lenToConvert+1];
+ memcpy(pToConvert,pTemp, lenToConvert);
+ pToConvert[lenToConvert]='\0';
+
+ tileD=strtol(pToConvert, (char**)NULL, DefaultBase);
+ if (!tileD)
+ {
+ RMInit::logOut << "r_Stat_Tiling::r_Stat_Tiling(" << encoded << "): Error decoding tile dimension from \"" << pToConvert << "\", is not a number." << endl;
+ delete[] pToConvert;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+ if (tileD < 0)
+ {
+ RMInit::logOut << "r_Stat_Tiling::r_Stat_Tiling(" << encoded << "): Error decoding tile dimension from \"" << pToConvert << "\", is negative." << endl;
+ delete[] pToConvert;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+
+ //skip COLON && free buffer
+ delete[] pToConvert;
+ if(pRes != (pEnd-1))
+ pRes++;
+ else
+ {
+ RMInit::logOut << "r_Stat_Tiling::r_Stat_Tiling(" << encoded << "): Error decoding access information from \"" << pStart << "\", end of stream." << endl;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+
+ //deal with access informations
+ pTemp=pRes;
+ pRes=strstr(pTemp, COLON);
+ if(!pRes)
+ {
+ RMInit::logOut << "r_Stat_Tiling::r_Stat_Tiling(" << encoded << "): Error decoding access information from \"" << pTemp << "\"." << endl;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+
+ while(pRes)
+ {
+ //is access info?
+ if(*pTemp!=*LSQRBRA)
+ break;
+
+ //copy substring in buffer
+ lenToConvert=pRes-pTemp;
+ pToConvert=new char[lenToConvert+1];
+ memcpy(pToConvert, pTemp, lenToConvert);
+ pToConvert[lenToConvert]='\0';
+
+ //deal with access Interval
+ pInEnd=pToConvert+strlen(pToConvert);
+ pInRes=strstr(pToConvert, RSQRBRA);
+ if(!pInRes)
+ {
+ RMInit::logOut << "r_Stat_Tiling::r_Stat_Tiling(" << encoded << "): Error decoding access information from \"" << pToConvert << "\"." << endl;
+ delete[] pToConvert;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+
+ lenInToConvert=pInRes-pToConvert+1; //1 for ]
+ pInToConvert=new char[lenInToConvert+1];
+ memcpy(pInToConvert, pToConvert, lenInToConvert);
+ pInToConvert[lenInToConvert]='\0';
+
+ try
+ {
+ accessInterv=new r_Minterval(pInToConvert);
+ delete [] pInToConvert;
+ }
+ catch(r_Error &err)
+ {
+ RMInit::logOut << "r_Stat_Tiling::r_Stat_Tiling(" << encoded << "): Error decoding access interval \"" << pInToConvert << "\" from \"" << pToConvert << "\"." << endl;
+ RMInit::logOut << "Error " << err.get_errorno() << " : " << err.what() << endl;
+ delete[] pInToConvert;
+ delete[] pToConvert;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+
+ //deal with access Times
+ pInRes=strstr(pInRes, COMMA);
+ if(!pInRes)
+ {
+ RMInit::logOut << "r_Stat_Tiling::r_Stat_Tiling(" << encoded << "): Error decoding access times \"" << pInRes << "\" from acess information \"" << pToConvert << "\", not specified." << endl;
+ delete[] pInToConvert;
+ delete[] pToConvert;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+ if(pInRes!=(pEnd-1))
+ pInRes++;
+ else
+ {
+ RMInit::logOut << "r_Stat_Tiling::r_Stat_Tiling(" << encoded << "): Error decoding access times \"" << pInRes << "\" from acess information \"" << pToConvert << "\", not specified." << endl;
+ delete[] pInToConvert;
+ delete[] pToConvert;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+ accessTimes=strtol(pInRes, (char**)NULL, DefaultBase);
+ if(!accessTimes)
+ {
+ RMInit::logOut << "r_Stat_Tiling::r_Stat_Tiling(" << encoded << "): Error decoding access times \"" << pInRes << "\" from acess information \"" << pToConvert << "\", not a number." << endl;
+ delete[] pInToConvert;
+ delete[] pToConvert;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+ if(accessTimes<0)
+ {
+ RMInit::logOut << "r_Stat_Tiling::r_Stat_Tiling(" << encoded << "): Error decoding access times \"" << pInRes << "\" from acess information \"" << pToConvert << "\", negative number." << endl;
+ delete[] pInToConvert;
+ delete[] pToConvert;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+
+ accessInfo=new r_Access(*accessInterv, accessTimes);
+ vectAccessInfo.push_back(*accessInfo);
+ delete accessInfo;
+ delete accessInterv;
+
+ //skip COLON && free buffer
+ delete[] pToConvert;
+
+ if(pRes != (pEnd-1))
+ pRes++;
+ else
+ {
+ RMInit::logOut << "r_Stat_Tiling::r_Stat_Tiling(" << encoded << "): Error decoding access informations, end of stream." << endl;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+
+ //deal with next item
+ pTemp=pRes;
+ pRes=strstr(pTemp, COLON);
+ }
+
+ if(vectAccessInfo.empty())
+ {
+ RMInit::logOut << "r_Stat_Tiling::r_Stat_Tiling(" << encoded << "): Error decoding access informations, no access informations specified." << endl;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+
+ //deal with borderTH
+ lenToConvert=pRes-pTemp;
+ pToConvert=new char[lenToConvert+1];
+ memcpy(pToConvert, pTemp, lenToConvert);
+ pToConvert[lenToConvert]='\0';
+
+ borderTH=strtol(pToConvert, (char**)NULL, DefaultBase);
+ if (!borderTH)
+ {
+ RMInit::logOut << "r_Stat_Tiling::r_Stat_Tiling(" << encoded << "): Error decoding border threshold \"" << pToConvert << "\"." << endl;
+ delete[] pToConvert;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+ if (borderTH < 0)
+ {
+ RMInit::logOut << "r_Stat_Tiling::r_Stat_Tiling(" << encoded << "): Error decoding border threshold \"" << pToConvert << "\"." << endl;
+ delete[] pToConvert;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+
+ //skip COLON && free buffer
+ delete[] pToConvert;
+ if(pRes != (pEnd-1))
+ pRes++;
+ else
+ {
+ RMInit::logOut << "r_Stat_Tiling::r_Stat_Tiling(" << encoded << "): Error decoding interesting threshold, end of stream." << endl;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+
+ //deal with interestTH
+ pTemp=pRes;
+ pRes=strstr(pTemp,COLON);
+ if(!pRes)
+ {
+ RMInit::logOut << "r_Stat_Tiling::r_Stat_Tiling(" << encoded << "): Error decoding interesting threshold." << endl;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+
+ //copy substring into buffer
+ lenToConvert=pRes-pTemp;
+ pToConvert=new char[lenToConvert+1];
+ memcpy(pToConvert, pTemp, lenToConvert);
+ pToConvert[lenToConvert]='\0';
+
+ interestTH=strtod(pToConvert, (char**)NULL);
+ if (!interestTH)
+ {
+ RMInit::logOut << "r_Stat_Tiling::r_Stat_Tiling(" << encoded << "): Error decoding interesting threshold \"" << pToConvert << "\"." << endl;
+ delete[] pToConvert;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+ if (interestTH < 0.)
+ {
+ RMInit::logOut << "r_Stat_Tiling::r_Stat_Tiling(" << encoded << "): Error decoding interesting threshold \"" << pToConvert << "\", negative number." << endl;
+ delete[] pToConvert;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+
+ if (interestTH > 1.)
+ {
+ RMInit::logOut << "r_Stat_Tiling::r_Stat_Tiling(" << encoded << "): Error decoding interesting threshold \"" << pToConvert << "\", not in [0,1] interval." << endl;
+ delete[] pToConvert;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+
+ //skip COLON && free buffer
+ delete[] pToConvert;
+ if(pRes != (pEnd-1))
+ pRes++;
+ else
+ {
+ RMInit::logOut << "r_Stat_Tiling::r_Stat_Tiling(" << encoded << "): Error decoding tile size, end of stream." << endl;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+
+ //deal with tilesize
+ pTemp=pRes;
+ tileS=strtol(pTemp, (char**)NULL, DefaultBase);
+ if (!tileS)
+ {
+ RMInit::logOut << "r_Stat_Tiling::r_Stat_Tiling(" << encoded << "): Error decoding tile size \"" << pToConvert << "\", not a number." << endl;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+ if (tileS < 0.)
+ {
+ RMInit::logOut << "r_Stat_Tiling::r_Stat_Tiling(" << encoded << "): Error decoding tile size \"" << pToConvert << "\", negative number." << endl;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+
+ border_thr = borderTH;
+ stat_info = vectAccessInfo;
+ interesting_thr = interestTH;
+ dimension = tileD;
+ tile_size = tileS;
+}
+
+
+r_Stat_Tiling::r_Stat_Tiling(r_Dimension dim, const std::vector<r_Access>& stat_info2, r_Bytes ts, r_ULong border_threshold, r_Double interesting_threshold) throw (r_Error)
+ : r_Dimension_Tiling(dim, ts),
+ border_thr(border_threshold),
+ stat_info(stat_info2),
+ interesting_thr(interesting_threshold)
+{
+ RMDBGENTER(1, RMDebug::module_rasodmg, "r_Stat_Tiling", "Filtering accesses... ");
+ // Filter accesses all areas have the same dimension if successfull else exception
+ filter(stat_info);
+ RMDBGMIDDLE(1, RMDebug::module_rasodmg, "r_Stat_Tiling", "done\n");
+ std::vector<r_Access>::iterator areas_it = stat_info.begin();
+ // Count total accesses
+ r_ULong total_accesses = 0;
+
+
+
+ for (;areas_it != stat_info.end(); areas_it++)
+ {
+ if ((*areas_it).get_pattern().dimension() != dim)
+ {
+ RMInit::logOut << "r_Stat_Tiling::r_Stat_Tiling(" << dim << ", " << &stat_info
+ << ", " << ts << ", " << border_threshold << ", " << interesting_threshold
+ << ") dimension (" << dim << ") does not match dimension of access patterns ("
+ << (*areas_it).get_pattern().dimension() << ")" << endl;
+ throw r_Edim_mismatch(dim, (*areas_it).get_pattern().dimension());
+ }
+ total_accesses += (*areas_it).get_times();
+ }
+
+ RMDBGMIDDLE(1, RMDebug::module_rasodmg, "r_Stat_Tiling", "Defining interest areas... ");
+
+ // Mininum number of accesses for being interesting
+ r_ULong critical_accesses = (r_ULong)(interesting_thr*total_accesses);
+
+ iareas.clear();
+ for (areas_it = stat_info.begin(); areas_it != stat_info.end(); areas_it++)
+ {
+ if ((*areas_it).get_times() >= critical_accesses) // Threshold exceeded or equal
+ {
+ iareas.push_back(areas_it->get_pattern()); // count this area in
+ }
+ }
+
+ RMDBGEXIT(1, RMDebug::module_rasodmg, "r_Stat_Tiling", "Defining interest areas... done\n");
+}
+
+r_Stat_Tiling::~r_Stat_Tiling()
+{
+}
+
+r_Tiling* r_Stat_Tiling::clone() const
+{
+ r_Tiling* copy = new r_Stat_Tiling(dimension, stat_info, tile_size, border_thr, interesting_thr);
+ return copy;
+}
+
+void r_Stat_Tiling::print_status(std::ostream& os) const
+{
+ os << "r_Stat_Tiling[ ";
+ r_Dimension_Tiling::print_status(os);
+ os << " border threshold = " << border_thr << ", interesting threshold = " << interesting_thr << " ]";
+}
+
+const std::vector<r_Minterval>&
+r_Stat_Tiling::get_interesting_areas() const
+ {
+ return iareas;
+ }
+
+r_Tiling_Scheme
+r_Stat_Tiling::get_tiling_scheme() const
+ {
+ return r_StatisticalTiling;
+ }
+
+r_Area
+r_Stat_Tiling::get_border_threshold() const
+{
+ return border_thr;
+}
+
+r_Double
+r_Stat_Tiling::get_interesting_threshold() const
+{
+ return interesting_thr;
+}
+
+r_Access
+r_Stat_Tiling::merge(const std::vector<r_Access>& patterns) const
+{
+ // Create an interator for list of patterns
+ std::vector<r_Access>::const_iterator it = patterns.begin();
+
+ // The result (initialy updated to the first element of patterns)
+ r_Access result = (*it);
+ it++;
+
+ // For all patterns
+ for (;it != patterns.end(); it++)
+ {
+ result.merge_with(*it); // Merge them
+ }
+ return result; // Return the result
+}
+
+void r_Stat_Tiling::filter(std::vector<r_Access>& patterns) const throw (r_Error)
+{
+ // List to hold the result
+ std::vector<r_Access> result;
+
+ // List to hold the clusters
+ std::vector<r_Access> cluster;
+
+ // Iterators for pattern and cluster list
+ std::vector<r_Access>::iterator pattern_it = patterns.begin();
+ std::vector<r_Access>::iterator cluster_it;
+
+ // For all elements in pattern table
+ while (!patterns.empty())
+ {
+ // Clean cluster
+ cluster.clear();
+ // Cluster with first element of pattern list
+ cluster.push_back(patterns.back());
+ patterns.pop_back();
+
+ // For all elements in the cluster
+ for (cluster_it = cluster.begin(); cluster_it != cluster.end(); cluster_it++)
+ {
+ // For all remaining patterns
+ for (pattern_it = patterns.begin(); pattern_it != patterns.end(); pattern_it++)
+ {
+ // Pattern near an element from the cluster
+ if ((*cluster_it).is_near(*pattern_it, border_thr))
+ {
+ // Add pattern to the cluster
+ cluster.push_back(*pattern_it);
+ // Remove pattern from list
+ patterns.erase(pattern_it);
+ }
+ }
+ }
+ // Merge cluster and add to result
+ result.push_back(merge(cluster));
+ }
+ // Filtered table
+ patterns = result;
+}
+
+std::vector<r_Minterval>*
+r_Stat_Tiling::compute_tiles(const r_Minterval& domain, r_Bytes typelen) const throw (r_Error)
+{
+ r_Dimension num_dims = domain.dimension(); // Dimensionality of dom
+if (domain.dimension() != dimension)
+ {
+ RMInit::logOut << "r_Stat_Tiling::compute_tiles(" << domain << ", " << typelen << ") dimension (" << dimension << ") does not match dimension of object to tile (" << num_dims << ")" << endl;
+ throw r_Edim_mismatch(dimension, num_dims);
+ }
+if (typelen > tile_size)
+ {
+ RMInit::logOut << "r_Stat_Tiling::compute_tiles(" << domain << ", " << typelen << ") tile size (" << tile_size << ") is smaller than type length (" << typelen << ")" << endl;
+ throw r_Error(TILESIZETOOSMALL);
+ }
+#ifdef _VISUALIZE_2D_DECOMP_ // User wants a visual
+ static int count; // Number of decomps
+ ++count; // Update num decomps
+ // of the 2D decomp.
+ Visual_Tiling_2D* vis;
+ if (domain.dimension() == 2)
+ {
+ // Create an object for visualization
+ char fname[80];
+ sprintf(fname, "2D_decomp_stat_%d.ppm", count);
+ vis = new Visual_Tiling_2D(domain, fname);
+ }
+#endif
+
+ // *** Main algoritm ***
+
+ std::vector<r_Minterval>* result; // Holds the result
+
+ if (iareas.empty()) // No interest areas
+ {
+ // Perform regular tiling
+
+ RMDBGENTER(1, RMDebug::module_rasodmg, "r_Stat_Tiling", "Regular tiling...");
+
+ result = r_Size_Tiling::compute_tiles(domain, typelen);
+
+ RMDBGEXIT(1, RMDebug::module_rasodmg, "r_Stat_Tiling", "done\n");
+ }
+ else // We have interest areas
+ {
+ // Use interest areas for tiling the domain
+
+ RMDBGENTER(1, RMDebug::module_rasodmg, "r_Stat_Tiling", "Statistic tiling...\n");
+ r_Interest_Tiling* tiling=NULL;
+
+ try
+ {
+ tiling=new r_Interest_Tiling(dimension, iareas, get_tile_size(), r_Interest_Tiling::SUB_TILING);
+ result = tiling->compute_tiles(domain, typelen);
+ delete tiling;
+ }
+ catch(r_Error& err)
+ {
+ if(tiling)
+ delete tiling;
+ throw;
+ }
+
+ RMDBGEXIT(1, RMDebug::module_rasodmg, "r_Stat_Tiling", "done\n");
+ }
+
+ // *** End of the main algorithm
+
+#ifdef _VISUALIZE_2D_DECOMP_
+ if (domain.dimension() == 2)
+ {
+ vis->set_pen(0, 255, 255);
+
+ std::vector<r_Minterval>::iterator it(*result);
+ it.seek_begin();
+ for (; it.not_done(); it++)
+ (*vis) << (*it);
+
+ vis->set_pen(255, 255, 0);
+
+ std::vector<r_Minterval>& ia = (std::vector<r_Minterval>) iareas; // Cast away constness
+
+ std::vector<r_Minterval>::iterator it2(ia);
+ it2.seek_begin();
+ for (; it2.not_done(); it2++)
+ (*vis) << (*it2);
+
+ delete vis;
+ }
+#endif
+
+ // Return result
+
+ return result;
+}
+
+
+
+//***************************************************************************
+
+r_Access::r_Access() :
+ times(0)
+{
+}
+
+r_Access::r_Access(const r_Minterval& pattern, r_ULong accesses) :
+ interval(pattern), times(accesses)
+{
+}
+
+const r_Minterval& r_Access::get_pattern() const
+{
+ return interval;
+}
+
+void r_Access::set_pattern(const r_Minterval& pattern)
+{
+ interval = pattern;
+}
+
+r_ULong r_Access::get_times() const
+{
+ return times;
+}
+
+void r_Access::set_times(r_ULong accesses)
+{
+ times = accesses;
+}
+
+bool r_Access::is_near(const r_Access& other, r_ULong border_threshold) const throw (r_Error)
+{
+ const r_Minterval& a = this->interval;
+ const r_Minterval& b = other.interval;
+
+ r_Dimension num_dims = interval.dimension();
+ if (num_dims != b.dimension())
+ {
+ RMInit::logOut << "r_Access::is_near(" << other << ", " << border_threshold << ") parameter 1 does not match my dimension (" << num_dims << ")" << endl;
+ throw r_Edim_mismatch(num_dims, b.dimension());
+ }
+ bool the_same = true;
+
+ // For all dimensions
+ for (r_Dimension i = 0; i < num_dims; i++)
+ {
+ // Higher limit does not exceed border threshold
+ if (labs(a[i].high() - b[i].high()) > border_threshold)
+ {
+ the_same = false;
+ break;
+ }
+
+ // Lower limit does not exceed border threshold
+ if (labs(a[i].low() - b[i].low()) > border_threshold)
+ {
+ the_same = false;
+ break;
+ }
+ }
+
+ return the_same;
+}
+
+void r_Access::merge_with(const r_Access& other)
+{
+ interval.closure_with(other.interval);
+ times+= other.times;
+}
+
+void r_Access::print_status(std::ostream& os) const
+{
+ os << "{" << times <<"x: " << interval << "}";
+}
+
+std::ostream& operator<<(std::ostream& os, const r_Access& access)
+{
+ access.print_status(os);
+
+ return os;
+}
+
+bool r_Access::operator==(const r_Access& other) const
+{
+ return ((this->interval == other.interval) && (this->times == other.times));
+}
+
+bool r_Access::operator!=(const r_Access& other) const
+{
+ return !(*this == other);
+}
diff --git a/rasodmg/stattiling.hh b/rasodmg/stattiling.hh
new file mode 100644
index 0000000..415b919
--- /dev/null
+++ b/rasodmg/stattiling.hh
@@ -0,0 +1,210 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: stattiling.hh
+ *
+ * MODULE: rasodmg
+ * CLASS: r_Stat_Tiling r_Access
+ *
+ * COMMENTS:
+ * None
+*/
+
+#ifndef _R_STATTILING_HH_
+#define _R_STATTILING_HH_
+
+// Include statements
+
+class r_Access;
+class r_Stat_Tiling;
+
+//@ManMemo: Module: {\bf rasodmg}
+
+/*@Doc:
+
+ This class represents an access pattern to a certain object.
+ {\tt r_Stat_Tiling} receives a list of this objects so that
+ an appropriate tiling can be defined.
+*/
+
+class r_Access
+{
+ public:
+
+ /// Class constructor
+ r_Access(const r_Minterval& pattern, r_ULong accesses = 1);
+ /**
+ It takes as parameter the interval and the number of times
+ that interval was accessed.
+ */
+
+ /// Gets the current interval (access pattern)
+ const r_Minterval& get_pattern() const;
+
+ /// Sets the current interval (access pattern)
+ void set_pattern(const r_Minterval& pattern);
+
+ /// Gets the number of times the pattern was accessed
+ r_ULong get_times() const;
+
+ /// Sets the number of times the pattern was accessed
+ void set_times(r_ULong accesses);
+
+ /// Checks if a certain access pattern is "close enough" of other
+ /// throws exception if the domains do not match
+ bool is_near(const r_Access& other, r_ULong border_threshold) const throw (r_Error);
+
+ /// Merge this access pattern with another
+ void merge_with(const r_Access& other);
+
+ /// Print object status
+ void print_status(std::ostream& os) const;
+
+ /// Operator equal
+ bool operator==(const r_Access& other) const;
+
+ /// Operator different
+ bool operator!=(const r_Access& other) const;
+
+ private:
+
+ /// The user can't use the default constructor
+ r_Access();
+
+ /// The actual stored pattern
+ r_Minterval interval;
+
+ /// The number of times it was accessed
+ r_ULong times;
+};
+
+//@ManMemo: Module: {\bf rasodmg}
+/**
+ Prints the status of a Access object to a stream
+*/
+extern std::ostream& operator<<(std::ostream& os, const r_Access& access);
+
+
+//@ManMemo: Module: {\bf rasodmg}
+
+/*@Doc:
+ This class implements the "statistic tiling" algorithm.
+
+ Three parameters are passed in the constructor of the class,
+ the border threshold for considering two access patterns to be the
+ same, the interesting threshold which specifies the percentage of
+ accesses that must take place so that an areas is considered of interest
+ when performing tiling and also the tilesize.
+
+ A call to {\tt update_stat_information} should be made prior to performing
+ tiling so that the static information about the accesses to the object
+ can be updated and the tiling operation prepared.
+*/
+
+class r_Stat_Tiling : public r_Dimension_Tiling
+{
+ // ******************* PUBLIC SECTION *******************
+
+ public: // constants
+
+ /// Default threshold for two borders being considered the same
+ const static r_Area DEF_BORDER_THR;
+
+ /// Default threshold for considering an area interesting when tiling
+ const static r_Double DEF_INTERESTING_THR;
+
+ /// read everything from an encoded string
+ /// e.g. "2;[0:9,0:9],3;[100:109,0:9],2;2;0.3;100"
+ r_Stat_Tiling(const char* encoded) throw (r_Error);
+
+ /// Class constructor
+ r_Stat_Tiling(r_Dimension dim,
+ const std::vector<r_Access>& stat_info,
+ r_Bytes ts = RMInit::clientTileSize,
+ r_Area border_threshold = DEF_BORDER_THR,
+ r_Double interesting_threshold = DEF_INTERESTING_THR) throw (r_Error);
+ /**
+ This is the "Statistic Tiling" class constructor.
+ It takes as parameters the threshold for, when performing filtering,
+ considering two borders the same, and also, the threshold at which
+ an area is considered interesting and should be taken in account when
+ performing tiling. Finally, the tilesize is considered as a parameter.
+ stat_info inputs the statistic information into the class and
+ calculates the new interest areas that will be used to perform tiling
+ on the object.
+ An exception is thrown when the statistical data does not fit the dimension.
+ */
+
+ virtual ~r_Stat_Tiling();
+
+ /// Gets the statistical information
+ virtual const std::vector<r_Minterval>& get_interesting_areas() const;
+
+ /// Gets the threshold at which to intervals are considered the same
+ r_Area get_border_threshold() const;
+ /**
+ This method gets the number of points (pixels/cells) at which two
+ intervals are considered to be the same, in the access patterns.
+ */
+
+ /// Gets the threshold at which an area is considered to be interesting
+ r_Double get_interesting_threshold() const;
+ /**
+ This method gets the threshold at which an area is considered to be
+ interesting. All the areas that are accessed above the specified
+ threshold, will be considered interest areas when performing tiling.
+ */
+
+ virtual void print_status(std::ostream& os) const;
+
+ virtual std::vector<r_Minterval>* compute_tiles(const r_Minterval& obj_domain, r_Bytes cell_size) const throw (r_Error);
+
+ virtual r_Tiling* clone() const;
+
+ virtual r_Tiling_Scheme get_tiling_scheme() const;
+
+ static const char* description;
+
+ protected: // methods
+
+ /// Filters and access pattern table (list)
+ /// throws exception if dimensions of access patterns are not the same
+ void filter(std::vector<r_Access>& patterns) const throw (r_Error);
+
+ /// Merges a list of access patterns
+ r_Access merge(const std::vector<r_Access>& patterns) const;
+
+ /// The "interesting area" threshold
+ r_Double interesting_thr;
+
+ /// The "same border" threshold
+ r_Area border_thr;
+
+ /// Current interest areas
+ std::vector<r_Minterval> iareas;
+
+ /// Statistical data
+ std::vector<r_Access> stat_info;
+};
+
+#endif
diff --git a/rasodmg/storagelayout.cc b/rasodmg/storagelayout.cc
new file mode 100644
index 0000000..847759d
--- /dev/null
+++ b/rasodmg/storagelayout.cc
@@ -0,0 +1,182 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: storagelayout.cc
+ *
+ * MODULE: rasodmg
+ * CLASS: r_StorageLayout, r_Domain_Storage_Layout
+ *
+ * COMMENTS:
+ * None
+ *
+*/
+
+// Because of NT port
+#include <string.h>
+#ifdef __VISUALC__
+#include <strstrea.h>
+#else
+#include <strstream>
+#endif
+#include <math.h>
+#include <vector>
+
+#include "rasodmg/storagelayout.hh"
+#include "rasodmg/iterator.hh"
+#include "rasodmg/tiling.hh"
+#include "rasodmg/alignedtiling.hh"
+#include "raslib/rmdebug.hh"
+#include "raslib/rminit.hh"
+#include "raslib/minterval.hh"
+#include "rasodmg/gmarray.hh"
+
+r_Storage_Layout::r_Storage_Layout(r_Data_Format init_format, const char* formatParams)
+ : til(0),
+ storage_format(init_format),
+ storage_params(0)
+{
+ til = new r_Size_Tiling();
+ if (formatParams != NULL)
+ storage_params = strdup(formatParams);
+}
+
+r_Storage_Layout::r_Storage_Layout(r_Tiling* ts, r_Data_Format init_format, const char* formatParams)
+ : til(ts),
+ storage_format(init_format),
+ storage_params(0)
+{
+ if (til == NULL)
+ til = new r_Size_Tiling();
+ if (formatParams != NULL)
+ storage_params = strdup(formatParams);
+}
+
+r_Storage_Layout::r_Storage_Layout(const r_Storage_Layout& sl)
+ : til(sl.get_tiling()->clone()),
+ storage_format(sl.get_storage_format()),
+ storage_params(0)
+{
+ if (sl.storage_params != NULL)
+ storage_params = strdup(sl.storage_params);
+}
+
+r_Storage_Layout*
+r_Storage_Layout::clone() const
+{
+ r_Storage_Layout* newSL = new r_Storage_Layout(til->clone(), storage_format, storage_params);
+ return newSL;
+}
+
+r_Storage_Layout::~r_Storage_Layout()
+{
+ if(til)
+ {
+ delete til;
+ til = NULL;
+ }
+ if (storage_params)
+ {
+ free(storage_params);
+ storage_params = NULL;
+ }
+}
+
+const r_Tiling*
+r_Storage_Layout::get_tiling() const
+{
+ return til;
+}
+
+r_Data_Format
+r_Storage_Layout::get_storage_format() const
+{
+ return storage_format;
+}
+
+const char*
+r_Storage_Layout::get_storage_format_params() const
+{
+ return storage_params;
+}
+
+r_Set< r_GMarray* >*
+r_Storage_Layout::decomposeMDD(const r_GMarray* mar) const throw (r_Error)
+{
+ r_Bytes cell_size = mar->get_type_length();
+ std::vector<r_Minterval>* tiles=NULL;
+ r_Set<r_GMarray*>* result=NULL;
+
+ if (!til->is_compatible(mar->spatial_domain(), cell_size))
+ {
+ RMInit::logOut << "r_Storage_Layout::decomposeMDD() gmarray is not compatible with tiling" << endl;
+ RMInit::logOut << "\tgmarray domain : " << mar->spatial_domain() << endl;
+ RMInit::logOut << "\tgmarray type size: " << mar->get_type_length() << endl;
+ RMInit::logOut << "\tstorage layout : " << *this << endl;
+ throw r_Error(STORAGERLAYOUTINCOMPATIBLEWITHGMARRAY);
+ }
+
+
+
+ try
+ {
+ tiles = til->compute_tiles(mar->spatial_domain(), cell_size);
+ }
+ catch(r_Error& err)
+ {
+ throw;
+ }
+
+ result = new r_Set<r_GMarray*>;
+
+ for (std::vector<r_Minterval>::iterator it = tiles->begin(); it != tiles->end(); it++)
+ result->insert_element(mar->intersect(*it));
+
+ delete tiles;
+ return result;
+}
+
+void
+r_Storage_Layout::print_status(std::ostream& os) const
+{
+ os << "r_Storage_Layout[ tiling = "<< *til << " storage format = " << storage_format << " storage parameters = ";
+ if (storage_params != NULL)
+ os << "upps, not here";
+ //os << storage_params;
+ else
+ os << "none defined";
+ os << " ]";
+}
+
+bool
+r_Storage_Layout::is_compatible(const r_Minterval& obj_domain, r_Bytes cellTypeSize) const
+{
+ return til->is_compatible(obj_domain, cellTypeSize);
+}
+
+std::ostream&
+operator<<(std::ostream& s, const r_Storage_Layout& sl)
+{
+ sl.print_status(s);
+ return s;
+}
+
diff --git a/rasodmg/storagelayout.hh b/rasodmg/storagelayout.hh
new file mode 100644
index 0000000..decb1a0
--- /dev/null
+++ b/rasodmg/storagelayout.hh
@@ -0,0 +1,132 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: storagelayout.hh
+ *
+ * MODULE: rasodmg
+ * CLASS: r_Storage_Layout, r_Domain_Storage_Layout
+ *
+ * COMMENTS:
+ * None
+*/
+
+#ifndef _R_STORAGELAYOUT_HH_
+#define _R_STORAGELAYOUT_HH_
+
+
+#include <iostream>
+using std::cout;
+
+#include "raslib/mddtypes.hh"
+#include "rasodmg/set.hh"
+
+// forward declarations
+class r_Storage_Layout;
+class r_GMarray;
+class ClientComm;
+class r_Tiling;
+class r_Minterval;
+
+//@ManMemo: Module: {\bf rasodmg}
+
+/*@Doc:
+
+ The {\tt r_Storage_Layout} class is used to express the storage options
+ for {\tt r_Marray} objects. This is the superclass of different storage
+ layout classes which may be used for different types of storage layout
+ schemes. It is also used directly by the rasdaman client for
+ default storage layout, i.e., for the storage layout for objects for
+ which absolutely none has been defined.
+
+ Notice: the tiling options are invalid if the rasdaman client is running
+ with the option notiling. In that case, no tiling is done,
+ independently of the storage layout chosen.
+ For the time being, compression does not work.
+*/
+
+class r_Storage_Layout
+{
+ public:
+
+ /// the dataformat is not used. please use the database methods for this purpose.
+ r_Storage_Layout(r_Data_Format init_format = r_Array, const char* formatParams = NULL);
+
+ /// the dataformat is not used. please use the database methods for this purpose.
+ r_Storage_Layout(r_Tiling* ts, r_Data_Format init_format = r_Array, const char* formatParams = NULL);
+
+ /// Copy constructor.
+ r_Storage_Layout(const r_Storage_Layout& sl);
+
+ ///
+ virtual r_Storage_Layout* clone() const;
+
+ /// virtual destructor
+ virtual ~r_Storage_Layout();
+
+ ///
+ const r_Tiling* get_tiling() const;
+
+ /// this does not do anything important. please use the database methods for this purpose.
+ r_Data_Format get_storage_format() const;
+
+ /// this does not do anything important. please use the database methods for this purpose.
+ const char* get_storage_format_params() const;
+
+ /// Function for decomposing large MDDs into a set of smaller tiles
+ virtual r_Set< r_GMarray* >* decomposeMDD(const r_GMarray* mar) const throw (r_Error);
+
+ /// writes the state of the object to the specified stream
+ void print_status(std::ostream& s = cout) const;
+
+ ///
+ virtual bool is_compatible(const r_Minterval& obj_domain, r_Bytes celltypesize) const;
+
+ protected:
+
+ friend class ClientComm;
+ friend class r_GMArray;
+
+ char* storage_params;
+
+ /// the dataformat is not used. please use the database methods for this purpose.
+ r_Data_Format storage_format;
+
+ /// Tiling scheme
+ r_Tiling* til;
+
+};
+
+//@ManMemo: Module: {\bf rasodmg }
+/**
+ Output stream operator for objects of type {\tt const} \Ref{r_Storage_Layout}.
+*/
+extern std::ostream& operator<<(std::ostream& s, const r_Storage_Layout& sl);
+
+#if (defined(__VISUALC__) && !defined(__EXECUTABLE__))
+ #define __EXECUTABLE__
+ #include "raslib/dlist.hh"
+ #undef __EXECUTABLE__
+#else
+ #include "raslib/dlist.hh"
+#endif
+#endif
diff --git a/rasodmg/storagelayout.icc b/rasodmg/storagelayout.icc
new file mode 100644
index 0000000..f31834d
--- /dev/null
+++ b/rasodmg/storagelayout.icc
@@ -0,0 +1,31 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INLINE SOURCE: storagelayout.icc
+ *
+ * MODULE: rasodmg
+ * CLASS: r_Storage_Layout
+ *
+ * COMMENTS:
+ * None
+*/
diff --git a/rasodmg/test/Makefile b/rasodmg/test/Makefile
new file mode 100644
index 0000000..07385a2
--- /dev/null
+++ b/rasodmg/test/Makefile
@@ -0,0 +1,372 @@
+# -*-Makefile-*-
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>. # Top Level makefile. This points to the various modules that have to be build
+# and/or deployed
+#
+# MAKEFILE FOR:
+# test programs of module rasodmg
+#
+# COMMENTS:
+# - the rasql situated here is obsolete, see applications/rasql
+#
+##################################################################
+#
+# This is just an example Makefile for a test program.
+# The dependency of the test program on the lib of the
+# corresponding module is in the Makefile of the module.
+#
+
+######################### Definitions ############################
+
+# standard include with general options
+include $(RMANBASE)/Makefile.inc
+
+DEFCLIENTLIBS = $(RASODMG) $(CLIENTCOMM) $(COMPRESSION) $(RASLIB) $(CONVERSION)
+
+# use client specific flags
+CXXFLAGS := $(CLIENTCXXFLAGS)
+LDFLAGS := $(CLIENTLDFLAGS)
+
+# add communication flags
+CXXFLAGS += $(COMMCXXFLAGS)
+LDFLAGS += $(COMMLDFLAGS)
+
+# COMPDATE must be made more general at the final destination
+COMPDATE = `date +\"%d.%m.%Y %H:%M:%S\"`
+CXXFLAGS += -DCOMPDATE="\"$(COMPDATE)\""
+
+## a symbol for not writing too much when linking
+QL = $(SUPPORT_BASE)/lib/lib
+SUPPORTLIBS= $(QL)tiff.a $(QL)jpeg.a $(QL)png.a $(QL)crypto.a $(QL)z.a \
+ $(QL)mfhdf.a $(QL)df.a $(QL)ppm.a $(QL)pgm.a $(QL)pbm.a $(LIBAKINSIDE) \
+ $(LIBAKNET)
+
+# all test programs
+ALLTESTS = test_oqlquery test_collection test_set test_iterator \
+ test_marray deletecollection \
+ test_ref test_insert test_lookup test_query test_insert3 \
+ test_breakdown test_benchmark test_storage test_alignedtiling \
+ test_dirtiling test_interesttiling test_stattiling test_bmark_dir \
+ gen_pattern test_bmark_int test_bmark_stat test_bmark_dir1 \
+ test_bmark_int1 test_gmarray test_transaction test_fastscale \
+ test_polygon exporttif defdiff defconv system_update system_compare \
+ system_insert system_query
+
+SRCCXX= defconv.cc system_compare.cc test_bmark_dir1.cc test_dirtiling.cc test_lookup.cc \
+ test_stattiling.cc defdiff.cc system_insert.cc test_bmark_int.cc test_fastscale.cc \
+ test_marray.cc test_storage.cc deletecollection.cc system_query.cc test_bmark_int1.cc \
+ test_gmarray.cc test_oqlquery.cc test_transaction.cc gen_pattern.cc system_update.cc \
+ test_bmark_pet.cc test_insert.cc test_polygon.cc rasql.cc test_alignedtiling.cc \
+ test_bmark_stat.cc test_insert3.cc test_query.cc readln.cc test_benchmark.cc \
+ test_breakdown.cc test_interesttiling.cc test_ref.cc system_basic.cc test_bmark_dir.cc \
+ test_collection.cc test_iterator.cc test_set.cc
+
+OBJS = ${SRCCXX:%.cc=%.o}
+
+ifeq ($(OSTYPE),$(OSTYPE_SOLARIS))
+LDFLAGS+= -lsocket
+endif
+
+MISCCLEAN = $(OBJS) $(ALLTESTS)
+
+########################### Targets ##############################
+# all tests
+tests: $(ALLTESTS)
+
+# test target for class r_Collection
+# test target for class r_OQL_Query
+.PHONY : oqlquery
+oqlquery: test_module test_oqlquery
+
+# test target for class r_Collection
+.PHONY : collection
+collection: test_module test_collection
+
+# test target for class r_Set
+.PHONY : set
+set: test_module test_set
+
+# test target for class r_Iterator
+.PHONY : iterator
+iterator: test_module test_iterator
+
+# test target for class r_Marray
+.PHONY : marray
+marray: test_module test_marray
+
+# test target for class r_GMarray
+.PHONY : gmarray
+gmarray: test_module test_gmarray
+
+# test target for class r_Ref, r_Transaction
+.PHONY : ref
+ref: test_module test_ref
+
+# test target for ODMG conformant insertion of r_Marrays
+.PHONY : insert
+insert: test_module test_insert
+
+# test target for ODMG conformant lookup of r_Marrays
+.PHONY : lookup
+lookup: test_module test_lookup
+
+# test target for RasQL queries
+.PHONY : query
+query: test_module test_query
+
+# test target for test_insert3
+.PHONY : insert3
+insert3: test_module test_insert3
+
+# test target for deletecollection
+.PHONY : deletecoll
+insert3: test_module deletecollection
+
+# test target for simulation of communication breakdown
+.PHONY : breakdown
+breakdown: test_module test_breakdown
+
+# test target for RasQL benchmark
+.PHONY : benchmark
+benchmark: test_module test_benchmark
+
+# test target for storage layout
+storage: test_module test_storage test_alignedtiling test_dirtiling
+
+# test target for transactions
+transaction: test_module test_transaction
+
+.PHONY : test_module
+test_module:
+ cd $(RMANBASE)/rasodmg; $(MAKE)
+ cd $(RMANBASE)/raslib; $(MAKE)
+
+test_oqlquery: test_oqlquery.o $(DEFCLIENTLIBS)
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^ -lm $(SUPPORTLIBS)
+
+test_collection: test_collection.o $(DEFCLIENTLIBS)
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^ -lm $(SUPPORTLIBS)
+
+test_set: test_set.o $(DEFCLIENTLIBS)
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^ -lm $(SUPPORTLIBS)
+
+test_iterator: test_iterator.o $(DEFCLIENTLIBS)
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^ -lm $(SUPPORTLIBS)
+
+test_marray: test_marray.o $(DEFCLIENTLIBS)
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^ -lm $(SUPPORTLIBS)
+
+test_gmarray: test_gmarray.o $(DEFCLIENTLIBS)
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^ -lm $(SUPPORTLIBS)
+
+test_ref: test_ref.o $(DEFCLIENTLIBS)
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^ -lm $(SUPPORTLIBS)
+
+test_insert: test_insert.o $(DEFCLIENTLIBS)
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^ -lm $(SUPPORTLIBS)
+
+test_lookup: test_lookup.o $(DEFCLIENTLIBS)
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^ -lm $(SUPPORTLIBS)
+
+test_fastscale: test_fastscale.o $(DEFCLIENTLIBS)
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^ -lm $(SUPPORTLIBS)
+
+ifeq ($(OSTYPE),$(OSTYPE_LINUX))
+exporttif_static: exporttif.o $(DEFCLIENTLIBS)
+ $(PURIFY) $(CXX) $(LDFLAGS) -o test_polygon -Xlinker -Bstatic $^ $(SUPPORTLIBS) -lstdc++
+endif
+
+ifeq ($(OSTYPE),$(OSTYPE_LINUX))
+exporttif: exporttif.o $(DEFCLIENTLIBS)
+ $(PURIFY) $(CXX) -nodefaultlibs $(LDFLAGS) -o $@ -Xlinker -Bstatic $^ \
+ $(SUPPORTLIBS) -lstdc++ -Xlinker -Bdynamic -lm -lgcc -lc -lgcc
+endif
+
+
+ifeq ($(OSTYPE),$(OSTYPE_LINUX))
+test_polygon_static: test_polygon.o $(DEFCLIENTLIBS)
+ $(PURIFY) $(CXX) $(LDFLAGS) -o test_polygon -Xlinker -Bstatic $^ \
+ $(SUPPORTLIBS) -lstdc++
+endif
+
+ifeq ($(OSTYPE),$(OSTYPE_LINUX))
+test_polygon: test_polygon.o $(DEFCLIENTLIBS)
+ $(PURIFY) $(CXX) -nodefaultlibs $(LDFLAGS) -o $@ -Xlinker -Bstatic $^ \
+ $(SUPPORTLIBS) -lstdc++ -Xlinker -Bdynamic -lm -lgcc -lc -lgcc
+endif
+
+ifeq ($(OSTYPE),$(OSTYPE_SOLARIS))
+test_polygon: test_polygon.o $(DEFCLIENTLIBS)
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^ $(SUPPORTLIBS)
+endif
+
+test_query: test_query.o $(DEFCLIENTLIBS)
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^ -lm $(SUPPORTLIBS)
+
+ifeq ($(OSTYPE),$(OSTYPE_LINUX))
+test_query_static: test_query.o $(DEFCLIENTLIBS)
+ $(PURIFY) $(CXX) -nodefaultlibs $(LDFLAGS) -o test_query $^ -Xlinker -Bstatic \
+ $(SUPPORTLIBS) -lstdc++ -Xlinker -Bdynamic -lgcc -lc -lgcc
+endif
+
+system_compare: system_basic.o system_compare.o $(DEFCLIENTLIBS)
+ifeq ($(OSTYPE),$(OSTYPE_SOLARIS))
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^ -lstdc++ -lm $(SUPPORTLIBS)
+else
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^ -Xlinker -Bstatic $(SUPPORTLIBS)
+endif
+
+system_update: system_update.o system_basic.o $(DEFCLIENTLIBS)
+ifeq ($(OSTYPE),$(OSTYPE_SOLARIS))
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^ -lm $(SUPPORTLIBS) -lNCSCNet -lNCSEcw -lNCSUtil -mt
+endif
+ifeq ($(OSTYPE),$(OSTYPE_LINUX))
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^ -Xlinker -Bstatic $(SUPPORTLIBS)
+endif
+ifeq ($(OSTYPE),$(OSTYPE_OSF1))
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^ $(SUPPORTLIBS)
+endif
+
+system_insert: system_insert.o system_basic.o $(DEFCLIENTLIBS)
+ifeq ($(OSTYPE),$(OSTYPE_SOLARIS))
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^ -lstdc++ -lm $(SUPPORTLIBS)
+else
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^ $(SUPPORTLIBS)
+endif
+
+system_query: system_query.o system_basic.o $(DEFCLIENTLIBS)
+ifeq ($(OSTYPE),$(OSTYPE_SOLARIS))
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^ $(SUPPORTLIBS) -lstdc++ -lm
+else
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^ -Xlinker -Bstatic $(SUPPORTLIBS)
+endif
+
+defdiff: defdiff.o $(DEFCLIENTLIBS)
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^ -Xlinker -Bstatic -lstdc++ -lm $(SUPPORTLIBS)
+
+defconv: defconv.o $(DEFCLIENTLIBS)
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^ -Xlinker -Bstatic -lstdc++ -lm $(SUPPORTLIBS)
+
+test_insert3: test_insert3.o $(DEFCLIENTLIBS)
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^ -lm $(SUPPORTLIBS)
+
+ifeq ($(OSTYPE),$(OSTYPE_LINUX))
+test_insert3_static: test_insert3.o $(DEFCLIENTLIBS)
+ $(PURIFY) $(CXX) -nodefaultlibs $(LDFLAGS) -o test_insert3 $^ -Xlinker -Bstatic \
+ $(SUPPORTLIBS) -lstdc++ -Xlinker -Bdynamic -lgcc -lc -lgcc
+endif
+
+deletecollection: deletecollection.o $(DEFCLIENTLIBS)
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^ -lm $(SUPPORTLIBS)
+
+test_breakdown: test_breakdown.o $(DEFCLIENTLIBS)
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^ -lm $(SUPPORTLIBS)
+
+test_benchmark: test_benchmark.o $(DEFCLIENTLIBS)
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^ -lm $(SUPPORTLIBS)
+
+test_storage: test_storage.o $(DEFCLIENTLIBS) $(TOOLS)
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^ -lm $(SUPPORTLIBS)
+
+test_alignedtiling: test_alignedtiling.o $(DEFCLIENTLIBS)
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^ -lm $(SUPPORTLIBS) $(TOOLS)
+
+test_dirtiling: test_dirtiling.o $(DEFCLIENTLIBS)
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^ -lm $(SUPPORTLIBS) $(TOOLS)
+
+test_interesttiling: test_interesttiling.o $(DEFCLIENTLIBS)
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^ -lm $(SUPPORTLIBS) $(TOOLS)
+
+test_stattiling: test_stattiling.o $(DEFCLIENTLIBS)
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^ -lm $(SUPPORTLIBS) $(TOOLS)
+
+test_bmark_dir: test_bmark_dir.o $(DEFCLIENTLIBS)
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^ -lm $(SUPPORTLIBS) $(TOOLS)
+
+test_bmark_dir1: test_bmark_dir1.o $(DEFCLIENTLIBS)
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^ -lm $(SUPPORTLIBS) $(TOOLS)
+
+test_bmark_int: test_bmark_int.o $(DEFCLIENTLIBS)
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^ -lm $(SUPPORTLIBS) $(TOOLS)
+
+test_bmark_int1: test_bmark_int1.o $(DEFCLIENTLIBS)
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^ -lm $(SUPPORTLIBS) $(TOOLS)
+
+test_bmark_pet: test_bmark_pet.o $(DEFCLIENTLIBS)
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^ -lm $(SUPPORTLIBS) $(TOOLS)
+
+test_bmark_stat: test_bmark_stat.o $(DEFCLIENTLIBS)
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^ -lm $(SUPPORTLIBS) $(TOOLS)
+
+gen_pattern: gen_pattern.o $(DEFCLIENTLIBS)
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^ -lm $(SUPPORTLIBS) $(TOOLS)
+
+test_transaction: test_transaction.o $(DEFCLIENTLIBS)
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^ -lm $(SUPPORTLIBS)
+
+test_db2blob: test_db2blob.o $(DEFCLIENTLIBS)
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ -mt $^ -lm $(DB2LDFLAGS) $(SUPPORTLIBS)
+
+test_db2blob.cc: test_db2blob.sqC
+ db2 connect to sample
+ db2 prep $< bindfile OUTPUT $@
+ db2 bind test_db2blob.bnd
+ db2 connect reset
+
+.PHONY : raslib
+raslib:
+ cd $(RMANBASE)/raslib; $(MAKE)
+
+.PHONY : rasodmg
+rasodmg:
+ cd $(RMANBASE)/rasodmg; $(MAKE)
+
+.PHONY : clientcomm
+clientcomm:
+ cd $(RMANBASE)/clientcomm; $(MAKE)
+
+
+rasql: readln.o rasql.o
+ $(CXX) -o rasql $^ -L$(SUPPORT_BASE)/lib -lreadline -lcurses
+ ln -s -f $(RMANHOME)/rasodmg/test/rasql $(RMANHOME)/bin/rasql
+
+
+updatemap: updatemap.o updatemap_util.o updatemap_error.o $(DEFCLIENTLIBS)
+ifeq ($(OSTYPE),$(OSTYPE_SOLARIS))
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^ -lm $(SUPPORTLIBS) -lNCSCNet -lNCSEcw -lNCSUtil -mt
+endif
+ifeq ($(OSTYPE),$(OSTYPE_LINUX))
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^ -Xlinker -Bstatic $(SUPPORTLIBS)
+endif
+ifeq ($(OSTYPE),$(OSTYPE_OSF1))
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^ $(SUPPORTLIBS)
+endif
+
+PHONY: clean
+clean:
+ -rm $(MISCCLEAN)
+
+######################## Dependencies ############################
+
+# automatically created dependencies
+include Makefile.dep
+
diff --git a/rasodmg/test/Makefile.dep b/rasodmg/test/Makefile.dep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/rasodmg/test/Makefile.dep
diff --git a/rasodmg/test/cmov_16.ql b/rasodmg/test/cmov_16.ql
new file mode 100644
index 0000000..47e4178
--- /dev/null
+++ b/rasodmg/test/cmov_16.ql
@@ -0,0 +1,425 @@
+// This query tests different selectivities with moving query boxes
+// on comp_cubed with 16kB tiles ([0:24,0:24,0:24]). Each selectivity
+// is repeated 20 times with query boxes of the same shape and size
+// starting at different origins.
+
+// [0.5]: [39:83, 43:87, 117:143]
+SELECT img[39:83, 43:87, 117:143]
+FROM comp_cubed_16 AS img
+// [0.5]: [146:190, 116:160, 35:61]
+SELECT img[146:190, 116:160, 35:61]
+FROM comp_cubed_16 AS img
+// [0.5]: [17:61, 42:86, 15:41]
+SELECT img[17:61, 42:86, 15:41]
+FROM comp_cubed_16 AS img
+// [0.5]: [112:156, 154:198, 108:134]
+SELECT img[112:156, 154:198, 108:134]
+FROM comp_cubed_16 AS img
+// [0.5]: [138:182, 26:70, 48:74]
+SELECT img[138:182, 26:70, 48:74]
+FROM comp_cubed_16 AS img
+// [0.5]: [53:97, 94:138, 22:48]
+SELECT img[53:97, 94:138, 22:48]
+FROM comp_cubed_16 AS img
+// [0.5]: [190:234, 59:103, 17:43]
+SELECT img[190:234, 59:103, 17:43]
+FROM comp_cubed_16 AS img
+// [0.5]: [118:162, 147:191, 30:56]
+SELECT img[118:162, 147:191, 30:56]
+FROM comp_cubed_16 AS img
+// [0.5]: [210:254, 179:223, 18:44]
+SELECT img[210:254, 179:223, 18:44]
+FROM comp_cubed_16 AS img
+// [0.5]: [129:173, 76:120, 102:128]
+SELECT img[129:173, 76:120, 102:128]
+FROM comp_cubed_16 AS img
+// [0.5]: [199:243, 119:163, 59:85]
+SELECT img[199:243, 119:163, 59:85]
+FROM comp_cubed_16 AS img
+// [0.5]: [47:91, 52:96, 108:134]
+SELECT img[47:91, 52:96, 108:134]
+FROM comp_cubed_16 AS img
+// [0.5]: [87:131, 103:147, 11:37]
+SELECT img[87:131, 103:147, 11:37]
+FROM comp_cubed_16 AS img
+// [0.5]: [32:76, 81:125, 87:113]
+SELECT img[32:76, 81:125, 87:113]
+FROM comp_cubed_16 AS img
+// [0.5]: [14:58, 77:121, 0:26]
+SELECT img[14:58, 77:121, 0:26]
+FROM comp_cubed_16 AS img
+// [0.5]: [128:172, 145:189, 21:47]
+SELECT img[128:172, 145:189, 21:47]
+FROM comp_cubed_16 AS img
+// [0.5]: [185:229, 102:146, 60:86]
+SELECT img[185:229, 102:146, 60:86]
+FROM comp_cubed_16 AS img
+// [0.5]: [40:84, 39:83, 106:132]
+SELECT img[40:84, 39:83, 106:132]
+FROM comp_cubed_16 AS img
+// [0.5]: [37:81, 10:54, 51:77]
+SELECT img[37:81, 10:54, 51:77]
+FROM comp_cubed_16 AS img
+// [0.5]: [46:90, 21:65, 102:128]
+SELECT img[46:90, 21:65, 102:128]
+FROM comp_cubed_16 AS img
+// [1]: [199:254, 50:105, 11:44]
+SELECT img[199:254, 50:105, 11:44]
+FROM comp_cubed_16 AS img
+// [1]: [180:235, 51:106, 91:124]
+SELECT img[180:235, 51:106, 91:124]
+FROM comp_cubed_16 AS img
+// [1]: [199:254, 43:98, 113:146]
+SELECT img[199:254, 43:98, 113:146]
+FROM comp_cubed_16 AS img
+// [1]: [78:133, 40:95, 37:70]
+SELECT img[78:133, 40:95, 37:70]
+FROM comp_cubed_16 AS img
+// [1]: [11:66, 98:153, 19:52]
+SELECT img[11:66, 98:153, 19:52]
+FROM comp_cubed_16 AS img
+// [1]: [90:145, 74:129, 83:116]
+SELECT img[90:145, 74:129, 83:116]
+FROM comp_cubed_16 AS img
+// [1]: [82:137, 103:158, 1:34]
+SELECT img[82:137, 103:158, 1:34]
+FROM comp_cubed_16 AS img
+// [1]: [186:241, 191:246, 47:80]
+SELECT img[186:241, 191:246, 47:80]
+FROM comp_cubed_16 AS img
+// [1]: [143:198, 68:123, 77:110]
+SELECT img[143:198, 68:123, 77:110]
+FROM comp_cubed_16 AS img
+// [1]: [188:243, 23:78, 94:127]
+SELECT img[188:243, 23:78, 94:127]
+FROM comp_cubed_16 AS img
+// [1]: [71:126, 11:66, 75:108]
+SELECT img[71:126, 11:66, 75:108]
+FROM comp_cubed_16 AS img
+// [1]: [89:144, 109:164, 12:45]
+SELECT img[89:144, 109:164, 12:45]
+FROM comp_cubed_16 AS img
+// [1]: [47:102, 56:111, 14:47]
+SELECT img[47:102, 56:111, 14:47]
+FROM comp_cubed_16 AS img
+// [1]: [24:79, 190:245, 77:110]
+SELECT img[24:79, 190:245, 77:110]
+FROM comp_cubed_16 AS img
+// [1]: [14:69, 189:244, 0:33]
+SELECT img[14:69, 189:244, 0:33]
+FROM comp_cubed_16 AS img
+// [1]: [198:253, 167:222, 117:150]
+SELECT img[198:253, 167:222, 117:150]
+FROM comp_cubed_16 AS img
+// [1]: [125:180, 1:56, 113:146]
+SELECT img[125:180, 1:56, 113:146]
+FROM comp_cubed_16 AS img
+// [1]: [90:145, 126:181, 109:142]
+SELECT img[90:145, 126:181, 109:142]
+FROM comp_cubed_16 AS img
+// [1]: [154:209, 9:64, 47:80]
+SELECT img[154:209, 9:64, 47:80]
+FROM comp_cubed_16 AS img
+// [1]: [81:136, 1:56, 87:120]
+SELECT img[81:136, 1:56, 87:120]
+FROM comp_cubed_16 AS img
+// [2]: [116:185, 1:70, 77:119]
+SELECT img[116:185, 1:70, 77:119]
+FROM comp_cubed_16 AS img
+// [2]: [99:168, 87:156, 20:62]
+SELECT img[99:168, 87:156, 20:62]
+FROM comp_cubed_16 AS img
+// [2]: [81:150, 74:143, 35:77]
+SELECT img[81:150, 74:143, 35:77]
+FROM comp_cubed_16 AS img
+// [2]: [16:85, 100:169, 56:98]
+SELECT img[16:85, 100:169, 56:98]
+FROM comp_cubed_16 AS img
+// [2]: [180:249, 47:116, 92:134]
+SELECT img[180:249, 47:116, 92:134]
+FROM comp_cubed_16 AS img
+// [2]: [78:147, 57:126, 9:51]
+SELECT img[78:147, 57:126, 9:51]
+FROM comp_cubed_16 AS img
+// [2]: [160:229, 76:145, 39:81]
+SELECT img[160:229, 76:145, 39:81]
+FROM comp_cubed_16 AS img
+// [2]: [95:164, 29:98, 26:68]
+SELECT img[95:164, 29:98, 26:68]
+FROM comp_cubed_16 AS img
+// [2]: [143:212, 120:189, 35:77]
+SELECT img[143:212, 120:189, 35:77]
+FROM comp_cubed_16 AS img
+// [2]: [163:232, 116:185, 78:120]
+SELECT img[163:232, 116:185, 78:120]
+FROM comp_cubed_16 AS img
+// [2]: [116:185, 58:127, 69:111]
+SELECT img[116:185, 58:127, 69:111]
+FROM comp_cubed_16 AS img
+// [2]: [38:107, 169:238, 0:42]
+SELECT img[38:107, 169:238, 0:42]
+FROM comp_cubed_16 AS img
+// [2]: [87:156, 112:181, 41:83]
+SELECT img[87:156, 112:181, 41:83]
+FROM comp_cubed_16 AS img
+// [2]: [14:83, 118:187, 37:79]
+SELECT img[14:83, 118:187, 37:79]
+FROM comp_cubed_16 AS img
+// [2]: [24:93, 172:241, 27:69]
+SELECT img[24:93, 172:241, 27:69]
+FROM comp_cubed_16 AS img
+// [2]: [105:174, 14:83, 21:63]
+SELECT img[105:174, 14:83, 21:63]
+FROM comp_cubed_16 AS img
+// [2]: [54:123, 92:161, 0:42]
+SELECT img[54:123, 92:161, 0:42]
+FROM comp_cubed_16 AS img
+// [2]: [151:220, 160:229, 58:100]
+SELECT img[151:220, 160:229, 58:100]
+FROM comp_cubed_16 AS img
+// [2]: [73:142, 42:111, 73:115]
+SELECT img[73:142, 42:111, 73:115]
+FROM comp_cubed_16 AS img
+// [2]: [38:107, 181:250, 25:67]
+SELECT img[38:107, 181:250, 25:67]
+FROM comp_cubed_16 AS img
+// [5]: [82:176, 43:137, 32:88]
+SELECT img[82:176, 43:137, 32:88]
+FROM comp_cubed_16 AS img
+// [5]: [114:208, 6:100, 52:108]
+SELECT img[114:208, 6:100, 52:108]
+FROM comp_cubed_16 AS img
+// [5]: [116:210, 132:226, 29:85]
+SELECT img[116:210, 132:226, 29:85]
+FROM comp_cubed_16 AS img
+// [5]: [29:123, 69:163, 53:109]
+SELECT img[29:123, 69:163, 53:109]
+FROM comp_cubed_16 AS img
+// [5]: [85:179, 1:95, 72:128]
+SELECT img[85:179, 1:95, 72:128]
+FROM comp_cubed_16 AS img
+// [5]: [80:174, 121:215, 27:83]
+SELECT img[80:174, 121:215, 27:83]
+FROM comp_cubed_16 AS img
+// [5]: [142:236, 129:223, 46:102]
+SELECT img[142:236, 129:223, 46:102]
+FROM comp_cubed_16 AS img
+// [5]: [130:224, 156:250, 82:138]
+SELECT img[130:224, 156:250, 82:138]
+FROM comp_cubed_16 AS img
+// [5]: [27:121, 111:205, 45:101]
+SELECT img[27:121, 111:205, 45:101]
+FROM comp_cubed_16 AS img
+// [5]: [139:233, 122:216, 49:105]
+SELECT img[139:233, 122:216, 49:105]
+FROM comp_cubed_16 AS img
+// [5]: [12:106, 3:97, 84:140]
+SELECT img[12:106, 3:97, 84:140]
+FROM comp_cubed_16 AS img
+// [5]: [73:167, 70:164, 1:57]
+SELECT img[73:167, 70:164, 1:57]
+FROM comp_cubed_16 AS img
+// [5]: [160:254, 1:95, 80:136]
+SELECT img[160:254, 1:95, 80:136]
+FROM comp_cubed_16 AS img
+// [5]: [152:246, 54:148, 72:128]
+SELECT img[152:246, 54:148, 72:128]
+FROM comp_cubed_16 AS img
+// [5]: [25:119, 50:144, 55:111]
+SELECT img[25:119, 50:144, 55:111]
+FROM comp_cubed_16 AS img
+// [5]: [151:245, 34:128, 92:148]
+SELECT img[151:245, 34:128, 92:148]
+FROM comp_cubed_16 AS img
+// [5]: [28:122, 68:162, 76:132]
+SELECT img[28:122, 68:162, 76:132]
+FROM comp_cubed_16 AS img
+// [5]: [145:239, 98:192, 44:100]
+SELECT img[145:239, 98:192, 44:100]
+FROM comp_cubed_16 AS img
+// [5]: [73:167, 122:216, 2:58]
+SELECT img[73:167, 122:216, 2:58]
+FROM comp_cubed_16 AS img
+// [5]: [1:95, 107:201, 68:124]
+SELECT img[1:95, 107:201, 68:124]
+FROM comp_cubed_16 AS img
+// [10]: [102:220, 43:161, 75:146]
+SELECT img[102:220, 43:161, 75:146]
+FROM comp_cubed_16 AS img
+// [10]: [106:224, 36:154, 79:150]
+SELECT img[106:224, 36:154, 79:150]
+FROM comp_cubed_16 AS img
+// [10]: [95:213, 56:174, 69:140]
+SELECT img[95:213, 56:174, 69:140]
+FROM comp_cubed_16 AS img
+// [10]: [62:180, 126:244, 74:145]
+SELECT img[62:180, 126:244, 74:145]
+FROM comp_cubed_16 AS img
+// [10]: [93:211, 63:181, 46:117]
+SELECT img[93:211, 63:181, 46:117]
+FROM comp_cubed_16 AS img
+// [10]: [129:247, 74:192, 67:138]
+SELECT img[129:247, 74:192, 67:138]
+FROM comp_cubed_16 AS img
+// [10]: [44:162, 84:202, 75:146]
+SELECT img[44:162, 84:202, 75:146]
+FROM comp_cubed_16 AS img
+// [10]: [52:170, 107:225, 19:90]
+SELECT img[52:170, 107:225, 19:90]
+FROM comp_cubed_16 AS img
+// [10]: [89:207, 94:212, 9:80]
+SELECT img[89:207, 94:212, 9:80]
+FROM comp_cubed_16 AS img
+// [10]: [52:170, 120:238, 67:138]
+SELECT img[52:170, 120:238, 67:138]
+FROM comp_cubed_16 AS img
+// [10]: [98:216, 51:169, 42:113]
+SELECT img[98:216, 51:169, 42:113]
+FROM comp_cubed_16 AS img
+// [10]: [30:148, 109:227, 51:122]
+SELECT img[30:148, 109:227, 51:122]
+FROM comp_cubed_16 AS img
+// [10]: [130:248, 118:236, 30:101]
+SELECT img[130:248, 118:236, 30:101]
+FROM comp_cubed_16 AS img
+// [10]: [25:143, 25:143, 46:117]
+SELECT img[25:143, 25:143, 46:117]
+FROM comp_cubed_16 AS img
+// [10]: [86:204, 119:237, 12:83]
+SELECT img[86:204, 119:237, 12:83]
+FROM comp_cubed_16 AS img
+// [10]: [116:234, 18:136, 11:82]
+SELECT img[116:234, 18:136, 11:82]
+FROM comp_cubed_16 AS img
+// [10]: [61:179, 24:142, 68:139]
+SELECT img[61:179, 24:142, 68:139]
+FROM comp_cubed_16 AS img
+// [10]: [53:171, 14:132, 72:143]
+SELECT img[53:171, 14:132, 72:143]
+FROM comp_cubed_16 AS img
+// [10]: [49:167, 84:202, 64:135]
+SELECT img[49:167, 84:202, 64:135]
+FROM comp_cubed_16 AS img
+// [10]: [85:203, 80:198, 13:84]
+SELECT img[85:203, 80:198, 13:84]
+FROM comp_cubed_16 AS img
+// [20]: [97:246, 85:234, 54:143]
+SELECT img[97:246, 85:234, 54:143]
+FROM comp_cubed_16 AS img
+// [20]: [63:212, 18:167, 43:132]
+SELECT img[63:212, 18:167, 43:132]
+FROM comp_cubed_16 AS img
+// [20]: [99:248, 28:177, 58:147]
+SELECT img[99:248, 28:177, 58:147]
+FROM comp_cubed_16 AS img
+// [20]: [57:206, 16:165, 46:135]
+SELECT img[57:206, 16:165, 46:135]
+FROM comp_cubed_16 AS img
+// [20]: [83:232, 93:242, 36:125]
+SELECT img[83:232, 93:242, 36:125]
+FROM comp_cubed_16 AS img
+// [20]: [57:206, 31:180, 48:137]
+SELECT img[57:206, 31:180, 48:137]
+FROM comp_cubed_16 AS img
+// [20]: [86:235, 70:219, 32:121]
+SELECT img[86:235, 70:219, 32:121]
+FROM comp_cubed_16 AS img
+// [20]: [39:188, 49:198, 50:139]
+SELECT img[39:188, 49:198, 50:139]
+FROM comp_cubed_16 AS img
+// [20]: [62:211, 104:253, 29:118]
+SELECT img[62:211, 104:253, 29:118]
+FROM comp_cubed_16 AS img
+// [20]: [103:252, 44:193, 13:102]
+SELECT img[103:252, 44:193, 13:102]
+FROM comp_cubed_16 AS img
+// [20]: [48:197, 14:163, 2:91]
+SELECT img[48:197, 14:163, 2:91]
+FROM comp_cubed_16 AS img
+// [20]: [0:149, 79:228, 13:102]
+SELECT img[0:149, 79:228, 13:102]
+FROM comp_cubed_16 AS img
+// [20]: [6:155, 103:252, 35:124]
+SELECT img[6:155, 103:252, 35:124]
+FROM comp_cubed_16 AS img
+// [20]: [0:149, 91:240, 46:135]
+SELECT img[0:149, 91:240, 46:135]
+FROM comp_cubed_16 AS img
+// [20]: [23:172, 50:199, 42:131]
+SELECT img[23:172, 50:199, 42:131]
+FROM comp_cubed_16 AS img
+// [20]: [80:229, 33:182, 17:106]
+SELECT img[80:229, 33:182, 17:106]
+FROM comp_cubed_16 AS img
+// [20]: [38:187, 41:190, 1:90]
+SELECT img[38:187, 41:190, 1:90]
+FROM comp_cubed_16 AS img
+// [20]: [42:191, 17:166, 39:128]
+SELECT img[42:191, 17:166, 39:128]
+FROM comp_cubed_16 AS img
+// [20]: [98:247, 95:244, 58:147]
+SELECT img[98:247, 95:244, 58:147]
+FROM comp_cubed_16 AS img
+// [20]: [10:159, 51:200, 21:110]
+SELECT img[10:159, 51:200, 21:110]
+FROM comp_cubed_16 AS img
+// [50]: [8:210, 13:215, 9:130]
+SELECT img[8:210, 13:215, 9:130]
+FROM comp_cubed_16 AS img
+// [50]: [48:250, 45:247, 24:145]
+SELECT img[48:250, 45:247, 24:145]
+FROM comp_cubed_16 AS img
+// [50]: [29:231, 6:208, 23:144]
+SELECT img[29:231, 6:208, 23:144]
+FROM comp_cubed_16 AS img
+// [50]: [12:214, 44:246, 23:144]
+SELECT img[12:214, 44:246, 23:144]
+FROM comp_cubed_16 AS img
+// [50]: [11:213, 27:229, 7:128]
+SELECT img[11:213, 27:229, 7:128]
+FROM comp_cubed_16 AS img
+// [50]: [1:203, 2:204, 14:135]
+SELECT img[1:203, 2:204, 14:135]
+FROM comp_cubed_16 AS img
+// [50]: [22:224, 50:252, 10:131]
+SELECT img[22:224, 50:252, 10:131]
+FROM comp_cubed_16 AS img
+// [50]: [15:217, 35:237, 9:130]
+SELECT img[15:217, 35:237, 9:130]
+FROM comp_cubed_16 AS img
+// [50]: [4:206, 51:253, 28:149]
+SELECT img[4:206, 51:253, 28:149]
+FROM comp_cubed_16 AS img
+// [50]: [22:224, 20:222, 31:152]
+SELECT img[22:224, 20:222, 31:152]
+FROM comp_cubed_16 AS img
+// [50]: [16:218, 42:244, 27:148]
+SELECT img[16:218, 42:244, 27:148]
+FROM comp_cubed_16 AS img
+// [50]: [21:223, 32:234, 22:143]
+SELECT img[21:223, 32:234, 22:143]
+FROM comp_cubed_16 AS img
+// [50]: [37:239, 44:246, 29:150]
+SELECT img[37:239, 44:246, 29:150]
+FROM comp_cubed_16 AS img
+// [50]: [17:219, 49:251, 14:135]
+SELECT img[17:219, 49:251, 14:135]
+FROM comp_cubed_16 AS img
+// [50]: [49:251, 50:252, 3:124]
+SELECT img[49:251, 50:252, 3:124]
+FROM comp_cubed_16 AS img
+// [50]: [17:219, 15:217, 1:122]
+SELECT img[17:219, 15:217, 1:122]
+FROM comp_cubed_16 AS img
+// [50]: [21:223, 51:253, 13:134]
+SELECT img[21:223, 51:253, 13:134]
+FROM comp_cubed_16 AS img
+// [50]: [7:209, 47:249, 11:132]
+SELECT img[7:209, 47:249, 11:132]
+FROM comp_cubed_16 AS img
+// [50]: [4:206, 22:224, 4:125]
+SELECT img[4:206, 22:224, 4:125]
+FROM comp_cubed_16 AS img
+// [50]: [16:218, 51:253, 21:142]
+SELECT img[16:218, 51:253, 21:142]
+FROM comp_cubed_16 AS img
diff --git a/rasodmg/test/cmov_32.ql b/rasodmg/test/cmov_32.ql
new file mode 100644
index 0000000..c6b31fe
--- /dev/null
+++ b/rasodmg/test/cmov_32.ql
@@ -0,0 +1,425 @@
+// This query tests different selectivities with moving query boxes
+// on comp_cubed with 32kB tiles ([0:31,0:31,0:31]). Each selectivity
+// is repeated 20 times with query boxes of the same shape and size
+// starting at different origins.
+
+// [0.5]: [46:90, 176:220, 60:86]
+SELECT img[46:90, 176:220, 60:86]
+FROM comp_cubed AS img
+// [0.5]: [143:187, 175:219, 106:132]
+SELECT img[143:187, 175:219, 106:132]
+FROM comp_cubed AS img
+// [0.5]: [169:213, 75:119, 66:92]
+SELECT img[169:213, 75:119, 66:92]
+FROM comp_cubed AS img
+// [0.5]: [90:134, 178:222, 48:74]
+SELECT img[90:134, 178:222, 48:74]
+FROM comp_cubed AS img
+// [0.5]: [76:120, 136:180, 31:57]
+SELECT img[76:120, 136:180, 31:57]
+FROM comp_cubed AS img
+// [0.5]: [7:51, 150:194, 89:115]
+SELECT img[7:51, 150:194, 89:115]
+FROM comp_cubed AS img
+// [0.5]: [133:177, 113:157, 0:26]
+SELECT img[133:177, 113:157, 0:26]
+FROM comp_cubed AS img
+// [0.5]: [114:158, 125:169, 108:134]
+SELECT img[114:158, 125:169, 108:134]
+FROM comp_cubed AS img
+// [0.5]: [210:254, 12:56, 56:82]
+SELECT img[210:254, 12:56, 56:82]
+FROM comp_cubed AS img
+// [0.5]: [176:220, 171:215, 83:109]
+SELECT img[176:220, 171:215, 83:109]
+FROM comp_cubed AS img
+// [0.5]: [102:146, 50:94, 34:60]
+SELECT img[102:146, 50:94, 34:60]
+FROM comp_cubed AS img
+// [0.5]: [134:178, 96:140, 97:123]
+SELECT img[134:178, 96:140, 97:123]
+FROM comp_cubed AS img
+// [0.5]: [200:244, 43:87, 123:149]
+SELECT img[200:244, 43:87, 123:149]
+FROM comp_cubed AS img
+// [0.5]: [155:199, 127:171, 48:74]
+SELECT img[155:199, 127:171, 48:74]
+FROM comp_cubed AS img
+// [0.5]: [111:155, 80:124, 11:37]
+SELECT img[111:155, 80:124, 11:37]
+FROM comp_cubed AS img
+// [0.5]: [164:208, 2:46, 64:90]
+SELECT img[164:208, 2:46, 64:90]
+FROM comp_cubed AS img
+// [0.5]: [137:181, 102:146, 17:43]
+SELECT img[137:181, 102:146, 17:43]
+FROM comp_cubed AS img
+// [0.5]: [100:144, 149:193, 121:147]
+SELECT img[100:144, 149:193, 121:147]
+FROM comp_cubed AS img
+// [0.5]: [186:230, 38:82, 108:134]
+SELECT img[186:230, 38:82, 108:134]
+FROM comp_cubed AS img
+// [0.5]: [48:92, 53:97, 14:40]
+SELECT img[48:92, 53:97, 14:40]
+FROM comp_cubed AS img
+// [1]: [64:119, 65:120, 57:90]
+SELECT img[64:119, 65:120, 57:90]
+FROM comp_cubed AS img
+// [1]: [13:68, 121:176, 20:53]
+SELECT img[13:68, 121:176, 20:53]
+FROM comp_cubed AS img
+// [1]: [3:58, 115:170, 59:92]
+SELECT img[3:58, 115:170, 59:92]
+FROM comp_cubed AS img
+// [1]: [174:229, 82:137, 93:126]
+SELECT img[174:229, 82:137, 93:126]
+FROM comp_cubed AS img
+// [1]: [40:95, 143:198, 43:76]
+SELECT img[40:95, 143:198, 43:76]
+FROM comp_cubed AS img
+// [1]: [126:181, 160:215, 86:119]
+SELECT img[126:181, 160:215, 86:119]
+FROM comp_cubed AS img
+// [1]: [20:75, 44:99, 89:122]
+SELECT img[20:75, 44:99, 89:122]
+FROM comp_cubed AS img
+// [1]: [15:70, 92:147, 23:56]
+SELECT img[15:70, 92:147, 23:56]
+FROM comp_cubed AS img
+// [1]: [122:177, 62:117, 75:108]
+SELECT img[122:177, 62:117, 75:108]
+FROM comp_cubed AS img
+// [1]: [183:238, 174:229, 70:103]
+SELECT img[183:238, 174:229, 70:103]
+FROM comp_cubed AS img
+// [1]: [13:68, 82:137, 97:130]
+SELECT img[13:68, 82:137, 97:130]
+FROM comp_cubed AS img
+// [1]: [174:229, 107:162, 91:124]
+SELECT img[174:229, 107:162, 91:124]
+FROM comp_cubed AS img
+// [1]: [79:134, 83:138, 88:121]
+SELECT img[79:134, 83:138, 88:121]
+FROM comp_cubed AS img
+// [1]: [3:58, 62:117, 39:72]
+SELECT img[3:58, 62:117, 39:72]
+FROM comp_cubed AS img
+// [1]: [96:151, 25:80, 93:126]
+SELECT img[96:151, 25:80, 93:126]
+FROM comp_cubed AS img
+// [1]: [124:179, 183:238, 21:54]
+SELECT img[124:179, 183:238, 21:54]
+FROM comp_cubed AS img
+// [1]: [106:161, 111:166, 89:122]
+SELECT img[106:161, 111:166, 89:122]
+FROM comp_cubed AS img
+// [1]: [66:121, 103:158, 74:107]
+SELECT img[66:121, 103:158, 74:107]
+FROM comp_cubed AS img
+// [1]: [180:235, 131:186, 80:113]
+SELECT img[180:235, 131:186, 80:113]
+FROM comp_cubed AS img
+// [1]: [4:59, 132:187, 59:92]
+SELECT img[4:59, 132:187, 59:92]
+FROM comp_cubed AS img
+// [2]: [69:138, 184:253, 75:117]
+SELECT img[69:138, 184:253, 75:117]
+FROM comp_cubed AS img
+// [2]: [58:127, 168:237, 87:129]
+SELECT img[58:127, 168:237, 87:129]
+FROM comp_cubed AS img
+// [2]: [162:231, 145:214, 58:100]
+SELECT img[162:231, 145:214, 58:100]
+FROM comp_cubed AS img
+// [2]: [129:198, 122:191, 7:49]
+SELECT img[129:198, 122:191, 7:49]
+FROM comp_cubed AS img
+// [2]: [86:155, 170:239, 54:96]
+SELECT img[86:155, 170:239, 54:96]
+FROM comp_cubed AS img
+// [2]: [0:69, 98:167, 70:112]
+SELECT img[0:69, 98:167, 70:112]
+FROM comp_cubed AS img
+// [2]: [41:110, 33:102, 58:100]
+SELECT img[41:110, 33:102, 58:100]
+FROM comp_cubed AS img
+// [2]: [37:106, 24:93, 65:107]
+SELECT img[37:106, 24:93, 65:107]
+FROM comp_cubed AS img
+// [2]: [39:108, 114:183, 26:68]
+SELECT img[39:108, 114:183, 26:68]
+FROM comp_cubed AS img
+// [2]: [166:235, 9:78, 38:80]
+SELECT img[166:235, 9:78, 38:80]
+FROM comp_cubed AS img
+// [2]: [147:216, 174:243, 45:87]
+SELECT img[147:216, 174:243, 45:87]
+FROM comp_cubed AS img
+// [2]: [121:190, 69:138, 58:100]
+SELECT img[121:190, 69:138, 58:100]
+FROM comp_cubed AS img
+// [2]: [87:156, 78:147, 73:115]
+SELECT img[87:156, 78:147, 73:115]
+FROM comp_cubed AS img
+// [2]: [31:100, 109:178, 75:117]
+SELECT img[31:100, 109:178, 75:117]
+FROM comp_cubed AS img
+// [2]: [54:123, 155:224, 26:68]
+SELECT img[54:123, 155:224, 26:68]
+FROM comp_cubed AS img
+// [2]: [150:219, 139:208, 25:67]
+SELECT img[150:219, 139:208, 25:67]
+FROM comp_cubed AS img
+// [2]: [65:134, 119:188, 87:129]
+SELECT img[65:134, 119:188, 87:129]
+FROM comp_cubed AS img
+// [2]: [159:228, 45:114, 47:89]
+SELECT img[159:228, 45:114, 47:89]
+FROM comp_cubed AS img
+// [2]: [77:146, 60:129, 87:129]
+SELECT img[77:146, 60:129, 87:129]
+FROM comp_cubed AS img
+// [2]: [169:238, 135:204, 4:46]
+SELECT img[169:238, 135:204, 4:46]
+FROM comp_cubed AS img
+// [5]: [24:118, 61:155, 77:133]
+SELECT img[24:118, 61:155, 77:133]
+FROM comp_cubed AS img
+// [5]: [137:231, 119:213, 11:67]
+SELECT img[137:231, 119:213, 11:67]
+FROM comp_cubed AS img
+// [5]: [140:234, 131:225, 56:112]
+SELECT img[140:234, 131:225, 56:112]
+FROM comp_cubed AS img
+// [5]: [154:248, 6:100, 54:110]
+SELECT img[154:248, 6:100, 54:110]
+FROM comp_cubed AS img
+// [5]: [146:240, 62:156, 60:116]
+SELECT img[146:240, 62:156, 60:116]
+FROM comp_cubed AS img
+// [5]: [78:172, 21:115, 3:59]
+SELECT img[78:172, 21:115, 3:59]
+FROM comp_cubed AS img
+// [5]: [80:174, 33:127, 84:140]
+SELECT img[80:174, 33:127, 84:140]
+FROM comp_cubed AS img
+// [5]: [138:232, 95:189, 52:108]
+SELECT img[138:232, 95:189, 52:108]
+FROM comp_cubed AS img
+// [5]: [60:154, 136:230, 70:126]
+SELECT img[60:154, 136:230, 70:126]
+FROM comp_cubed AS img
+// [5]: [79:173, 149:243, 65:121]
+SELECT img[79:173, 149:243, 65:121]
+FROM comp_cubed AS img
+// [5]: [13:107, 53:147, 57:113]
+SELECT img[13:107, 53:147, 57:113]
+FROM comp_cubed AS img
+// [5]: [13:107, 66:160, 44:100]
+SELECT img[13:107, 66:160, 44:100]
+FROM comp_cubed AS img
+// [5]: [137:231, 47:141, 38:94]
+SELECT img[137:231, 47:141, 38:94]
+FROM comp_cubed AS img
+// [5]: [11:105, 84:178, 42:98]
+SELECT img[11:105, 84:178, 42:98]
+FROM comp_cubed AS img
+// [5]: [19:113, 31:125, 51:107]
+SELECT img[19:113, 31:125, 51:107]
+FROM comp_cubed AS img
+// [5]: [27:121, 17:111, 29:85]
+SELECT img[27:121, 17:111, 29:85]
+FROM comp_cubed AS img
+// [5]: [142:236, 76:170, 94:150]
+SELECT img[142:236, 76:170, 94:150]
+FROM comp_cubed AS img
+// [5]: [153:247, 71:165, 83:139]
+SELECT img[153:247, 71:165, 83:139]
+FROM comp_cubed AS img
+// [5]: [12:106, 108:202, 79:135]
+SELECT img[12:106, 108:202, 79:135]
+FROM comp_cubed AS img
+// [5]: [146:240, 26:120, 59:115]
+SELECT img[146:240, 26:120, 59:115]
+FROM comp_cubed AS img
+// 1[0]: [3:121, 62:180, 39:110]
+SELECT img[3:121, 62:180, 39:110]
+FROM comp_cubed AS img
+// 1[0]: [11:129, 26:144, 19:90]
+SELECT img[11:129, 26:144, 19:90]
+FROM comp_cubed AS img
+// 1[0]: [49:167, 76:194, 77:148]
+SELECT img[49:167, 76:194, 77:148]
+FROM comp_cubed AS img
+// [10]: [55:173, 86:204, 21:92]
+SELECT img[55:173, 86:204, 21:92]
+FROM comp_cubed AS img
+// [10]: [110:228, 98:216, 80:151]
+SELECT img[110:228, 98:216, 80:151]
+FROM comp_cubed AS img
+// [10]: [123:241, 28:146, 59:130]
+SELECT img[123:241, 28:146, 59:130]
+FROM comp_cubed AS img
+// [10]: [89:207, 90:208, 34:105]
+SELECT img[89:207, 90:208, 34:105]
+FROM comp_cubed AS img
+// [10]: [111:229, 51:169, 5:76]
+SELECT img[111:229, 51:169, 5:76]
+FROM comp_cubed AS img
+// [10]: [15:133, 74:192, 12:83]
+SELECT img[15:133, 74:192, 12:83]
+FROM comp_cubed AS img
+// [10]: [103:221, 94:212, 74:145]
+SELECT img[103:221, 94:212, 74:145]
+FROM comp_cubed AS img
+// [10]: [107:225, 111:229, 16:87]
+SELECT img[107:225, 111:229, 16:87]
+FROM comp_cubed AS img
+// [10]: [14:132, 80:198, 58:129]
+SELECT img[14:132, 80:198, 58:129]
+FROM comp_cubed AS img
+// [10]: [2:120, 64:182, 25:96]
+SELECT img[2:120, 64:182, 25:96]
+FROM comp_cubed AS img
+// [10]: [74:192, 130:248, 3:74]
+SELECT img[74:192, 130:248, 3:74]
+FROM comp_cubed AS img
+// [10]: [96:214, 61:179, 14:85]
+SELECT img[96:214, 61:179, 14:85]
+FROM comp_cubed AS img
+// [10]: [73:191, 93:211, 6:77]
+SELECT img[73:191, 93:211, 6:77]
+FROM comp_cubed AS img
+// [10]: [55:173, 12:130, 54:125]
+SELECT img[55:173, 12:130, 54:125]
+FROM comp_cubed AS img
+// [10]: [1:119, 123:241, 51:122]
+SELECT img[1:119, 123:241, 51:122]
+FROM comp_cubed AS img
+// [10]: [117:235, 101:219, 55:126]
+SELECT img[117:235, 101:219, 55:126]
+FROM comp_cubed AS img
+// [10]: [24:142, 26:144, 33:104]
+SELECT img[24:142, 26:144, 33:104]
+FROM comp_cubed AS img
+// [20]: [36:185, 0:149, 39:128]
+SELECT img[36:185, 0:149, 39:128]
+FROM comp_cubed AS img
+// [20]: [85:234, 31:180, 54:143]
+SELECT img[85:234, 31:180, 54:143]
+FROM comp_cubed AS img
+// [20]: [55:204, 78:227, 20:109]
+SELECT img[55:204, 78:227, 20:109]
+FROM comp_cubed AS img
+// [20]: [28:177, 98:247, 26:115]
+SELECT img[28:177, 98:247, 26:115]
+FROM comp_cubed AS img
+// [20]: [53:202, 14:163, 15:104]
+SELECT img[53:202, 14:163, 15:104]
+FROM comp_cubed AS img
+// [20]: [84:233, 59:208, 28:117]
+SELECT img[84:233, 59:208, 28:117]
+FROM comp_cubed AS img
+// [20]: [24:173, 81:230, 21:110]
+SELECT img[24:173, 81:230, 21:110]
+FROM comp_cubed AS img
+// [20]: [70:219, 103:252, 59:148]
+SELECT img[70:219, 103:252, 59:148]
+FROM comp_cubed AS img
+// [20]: [75:224, 32:181, 36:125]
+SELECT img[75:224, 32:181, 36:125]
+FROM comp_cubed AS img
+// [20]: [80:229, 65:214, 22:111]
+SELECT img[80:229, 65:214, 22:111]
+FROM comp_cubed AS img
+// [20]: [5:154, 34:183, 20:109]
+SELECT img[5:154, 34:183, 20:109]
+FROM comp_cubed AS img
+// [20]: [16:165, 72:221, 57:146]
+SELECT img[16:165, 72:221, 57:146]
+FROM comp_cubed AS img
+// [20]: [90:239, 27:176, 55:144]
+SELECT img[90:239, 27:176, 55:144]
+FROM comp_cubed AS img
+// [20]: [81:230, 63:212, 61:150]
+SELECT img[81:230, 63:212, 61:150]
+FROM comp_cubed AS img
+// [20]: [87:236, 79:228, 61:150]
+SELECT img[87:236, 79:228, 61:150]
+FROM comp_cubed AS img
+// [20]: [100:249, 33:182, 35:124]
+SELECT img[100:249, 33:182, 35:124]
+FROM comp_cubed AS img
+// [20]: [14:163, 91:240, 38:127]
+SELECT img[14:163, 91:240, 38:127]
+FROM comp_cubed AS img
+// [20]: [60:209, 95:244, 11:100]
+SELECT img[60:209, 95:244, 11:100]
+FROM comp_cubed AS img
+// [20]: [99:248, 4:153, 29:118]
+SELECT img[99:248, 4:153, 29:118]
+FROM comp_cubed AS img
+// [20]: [10:159, 64:213, 32:121]
+SELECT img[10:159, 64:213, 32:121]
+FROM comp_cubed AS img
+// [50]: [8:210, 0:202, 1:122]
+SELECT img[8:210, 0:202, 1:122]
+FROM comp_cubed AS img
+// [50]: [17:219, 21:223, 6:127]
+SELECT img[17:219, 21:223, 6:127]
+FROM comp_cubed AS img
+// [50]: [49:251, 0:202, 4:125]
+SELECT img[49:251, 0:202, 4:125]
+FROM comp_cubed AS img
+// [50]: [11:213, 37:239, 15:136]
+SELECT img[11:213, 37:239, 15:136]
+FROM comp_cubed AS img
+// [50]: [29:231, 36:238, 18:139]
+SELECT img[29:231, 36:238, 18:139]
+FROM comp_cubed AS img
+// [50]: [38:240, 21:223, 2:123]
+SELECT img[38:240, 21:223, 2:123]
+FROM comp_cubed AS img
+// [50]: [26:228, 4:206, 9:130]
+SELECT img[26:228, 4:206, 9:130]
+FROM comp_cubed AS img
+// [50]: [1:203, 41:243, 21:142]
+SELECT img[1:203, 41:243, 21:142]
+FROM comp_cubed AS img
+// [50]: [39:241, 37:239, 10:131]
+SELECT img[39:241, 37:239, 10:131]
+FROM comp_cubed AS img
+// [50]: [6:208, 49:251, 2:123]
+SELECT img[6:208, 49:251, 2:123]
+FROM comp_cubed AS img
+// [50]: [2:204, 51:253, 8:129]
+SELECT img[2:204, 51:253, 8:129]
+FROM comp_cubed AS img
+// [50]: [23:225, 51:253, 9:130]
+SELECT img[23:225, 51:253, 9:130]
+FROM comp_cubed AS img
+// [50]: [32:234, 43:245, 10:131]
+SELECT img[32:234, 43:245, 10:131]
+FROM comp_cubed AS img
+// [50]: [33:235, 9:211, 31:152]
+SELECT img[33:235, 9:211, 31:152]
+FROM comp_cubed AS img
+// [50]: [28:230, 36:238, 4:125]
+SELECT img[28:230, 36:238, 4:125]
+FROM comp_cubed AS img
+// [50]: [25:227, 40:242, 3:124]
+SELECT img[25:227, 40:242, 3:124]
+FROM comp_cubed AS img
+// [50]: [33:235, 28:230, 25:146]
+SELECT img[33:235, 28:230, 25:146]
+FROM comp_cubed AS img
+// [50]: [42:244, 34:236, 1:122]
+SELECT img[42:244, 34:236, 1:122]
+FROM comp_cubed AS img
+// [50]: [34:236, 47:249, 6:127]
+SELECT img[34:236, 47:249, 6:127]
+FROM comp_cubed AS img
+// [50]: [35:237, 22:224, 31:152]
+SELECT img[35:237, 22:224, 31:152]
+FROM comp_cubed AS img
diff --git a/rasodmg/test/cmov_64.ql b/rasodmg/test/cmov_64.ql
new file mode 100644
index 0000000..4cb19ff
--- /dev/null
+++ b/rasodmg/test/cmov_64.ql
@@ -0,0 +1,425 @@
+// This query tests different selectivities with moving query boxes
+// on comp_cubed with 64kB tiles ([0:39,0:39,0:39]). Each selectivity
+// is repeated 20 times with query boxes of the same shape and size
+// starting at different origins.
+
+// [0.5]: [205:249, 154:198, 39:65]
+SELECT img[205:249, 154:198, 39:65]
+FROM comp_cubed_64 AS img
+// [0.5]: [125:169, 124:168, 15:41]
+SELECT img[125:169, 124:168, 15:41]
+FROM comp_cubed_64 AS img
+// [0.5]: [197:241, 71:115, 82:108]
+SELECT img[197:241, 71:115, 82:108]
+FROM comp_cubed_64 AS img
+// [0.5]: [53:97, 192:236, 122:148]
+SELECT img[53:97, 192:236, 122:148]
+FROM comp_cubed_64 AS img
+// [0.5]: [140:184, 93:137, 121:147]
+SELECT img[140:184, 93:137, 121:147]
+FROM comp_cubed_64 AS img
+// [0.5]: [154:198, 82:126, 120:146]
+SELECT img[154:198, 82:126, 120:146]
+FROM comp_cubed_64 AS img
+// [0.5]: [209:253, 51:95, 47:73]
+SELECT img[209:253, 51:95, 47:73]
+FROM comp_cubed_64 AS img
+// [0.5]: [57:101, 159:203, 113:139]
+SELECT img[57:101, 159:203, 113:139]
+FROM comp_cubed_64 AS img
+// [0.5]: [98:142, 166:210, 12:38]
+SELECT img[98:142, 166:210, 12:38]
+FROM comp_cubed_64 AS img
+// [0.5]: [194:238, 88:132, 52:78]
+SELECT img[194:238, 88:132, 52:78]
+FROM comp_cubed_64 AS img
+// [0.5]: [162:206, 101:145, 53:79]
+SELECT img[162:206, 101:145, 53:79]
+FROM comp_cubed_64 AS img
+// [0.5]: [166:210, 60:104, 126:152]
+SELECT img[166:210, 60:104, 126:152]
+FROM comp_cubed_64 AS img
+// [0.5]: [127:171, 157:201, 92:118]
+SELECT img[127:171, 157:201, 92:118]
+FROM comp_cubed_64 AS img
+// [0.5]: [46:90, 94:138, 53:79]
+SELECT img[46:90, 94:138, 53:79]
+FROM comp_cubed_64 AS img
+// [0.5]: [19:63, 42:86, 17:43]
+SELECT img[19:63, 42:86, 17:43]
+FROM comp_cubed_64 AS img
+// [0.5]: [182:226, 0:44, 97:123]
+SELECT img[182:226, 0:44, 97:123]
+FROM comp_cubed_64 AS img
+// [0.5]: [139:183, 98:142, 47:73]
+SELECT img[139:183, 98:142, 47:73]
+FROM comp_cubed_64 AS img
+// [0.5]: [106:150, 182:226, 11:37]
+SELECT img[106:150, 182:226, 11:37]
+FROM comp_cubed_64 AS img
+// [0.5]: [193:237, 200:244, 23:49]
+SELECT img[193:237, 200:244, 23:49]
+FROM comp_cubed_64 AS img
+// [0.5]: [40:84, 2:46, 5:31]
+SELECT img[40:84, 2:46, 5:31]
+FROM comp_cubed_64 AS img
+// [1]: [51:106, 169:224, 105:138]
+SELECT img[51:106, 169:224, 105:138]
+FROM comp_cubed_64 AS img
+// [1]: [72:127, 30:85, 113:146]
+SELECT img[72:127, 30:85, 113:146]
+FROM comp_cubed_64 AS img
+// [1]: [104:159, 82:137, 48:81]
+SELECT img[104:159, 82:137, 48:81]
+FROM comp_cubed_64 AS img
+// [1]: [91:146, 86:141, 40:73]
+SELECT img[91:146, 86:141, 40:73]
+FROM comp_cubed_64 AS img
+// [1]: [121:176, 19:74, 59:92]
+SELECT img[121:176, 19:74, 59:92]
+FROM comp_cubed_64 AS img
+// [1]: [69:124, 156:211, 27:60]
+SELECT img[69:124, 156:211, 27:60]
+FROM comp_cubed_64 AS img
+// [1]: [24:79, 64:119, 25:58]
+SELECT img[24:79, 64:119, 25:58]
+FROM comp_cubed_64 AS img
+// [1]: [70:125, 193:248, 90:123]
+SELECT img[70:125, 193:248, 90:123]
+FROM comp_cubed_64 AS img
+// [1]: [193:248, 1:56, 38:71]
+SELECT img[193:248, 1:56, 38:71]
+FROM comp_cubed_64 AS img
+// [1]: [118:173, 178:233, 56:89]
+SELECT img[118:173, 178:233, 56:89]
+FROM comp_cubed_64 AS img
+// [1]: [118:173, 23:78, 21:54]
+SELECT img[118:173, 23:78, 21:54]
+FROM comp_cubed_64 AS img
+// [1]: [9:64, 166:221, 44:77]
+SELECT img[9:64, 166:221, 44:77]
+FROM comp_cubed_64 AS img
+// [1]: [66:121, 65:120, 93:126]
+SELECT img[66:121, 65:120, 93:126]
+FROM comp_cubed_64 AS img
+// [1]: [63:118, 141:196, 31:64]
+SELECT img[63:118, 141:196, 31:64]
+FROM comp_cubed_64 AS img
+// [1]: [89:144, 58:113, 39:72]
+SELECT img[89:144, 58:113, 39:72]
+FROM comp_cubed_64 AS img
+// [1]: [72:127, 124:179, 93:126]
+SELECT img[72:127, 124:179, 93:126]
+FROM comp_cubed_64 AS img
+// [1]: [46:101, 178:233, 41:74]
+SELECT img[46:101, 178:233, 41:74]
+FROM comp_cubed_64 AS img
+// [1]: [52:107, 10:65, 49:82]
+SELECT img[52:107, 10:65, 49:82]
+FROM comp_cubed_64 AS img
+// [1]: [151:206, 5:60, 1:34]
+SELECT img[151:206, 5:60, 1:34]
+FROM comp_cubed_64 AS img
+// [1]: [95:150, 71:126, 85:118]
+SELECT img[95:150, 71:126, 85:118]
+FROM comp_cubed_64 AS img
+// [2]: [31:100, 166:235, 7:49]
+SELECT img[31:100, 166:235, 7:49]
+FROM comp_cubed_64 AS img
+// [2]: [109:178, 174:243, 31:73]
+SELECT img[109:178, 174:243, 31:73]
+FROM comp_cubed_64 AS img
+// [2]: [24:93, 32:101, 91:133]
+SELECT img[24:93, 32:101, 91:133]
+FROM comp_cubed_64 AS img
+// [2]: [76:145, 52:121, 33:75]
+SELECT img[76:145, 52:121, 33:75]
+FROM comp_cubed_64 AS img
+// [2]: [82:151, 5:74, 17:59]
+SELECT img[82:151, 5:74, 17:59]
+FROM comp_cubed_64 AS img
+// [2]: [48:117, 100:169, 72:114]
+SELECT img[48:117, 100:169, 72:114]
+FROM comp_cubed_64 AS img
+// [2]: [81:150, 183:252, 39:81]
+SELECT img[81:150, 183:252, 39:81]
+FROM comp_cubed_64 AS img
+// [2]: [8:77, 122:191, 5:47]
+SELECT img[8:77, 122:191, 5:47]
+FROM comp_cubed_64 AS img
+// [2]: [170:239, 145:214, 23:65]
+SELECT img[170:239, 145:214, 23:65]
+FROM comp_cubed_64 AS img
+// [2]: [84:153, 101:170, 86:128]
+SELECT img[84:153, 101:170, 86:128]
+FROM comp_cubed_64 AS img
+// [2]: [72:141, 147:216, 32:74]
+SELECT img[72:141, 147:216, 32:74]
+FROM comp_cubed_64 AS img
+// [2]: [12:81, 25:94, 108:150]
+SELECT img[12:81, 25:94, 108:150]
+FROM comp_cubed_64 AS img
+// [2]: [94:163, 125:194, 29:71]
+SELECT img[94:163, 125:194, 29:71]
+FROM comp_cubed_64 AS img
+// [2]: [4:73, 44:113, 0:42]
+SELECT img[4:73, 44:113, 0:42]
+FROM comp_cubed_64 AS img
+// [2]: [134:203, 7:76, 85:127]
+SELECT img[134:203, 7:76, 85:127]
+FROM comp_cubed_64 AS img
+// [2]: [84:153, 168:237, 3:45]
+SELECT img[84:153, 168:237, 3:45]
+FROM comp_cubed_64 AS img
+// [2]: [166:235, 140:209, 41:83]
+SELECT img[166:235, 140:209, 41:83]
+FROM comp_cubed_64 AS img
+// [2]: [98:167, 43:112, 81:123]
+SELECT img[98:167, 43:112, 81:123]
+FROM comp_cubed_64 AS img
+// [2]: [5:74, 137:206, 29:71]
+SELECT img[5:74, 137:206, 29:71]
+FROM comp_cubed_64 AS img
+// [2]: [177:246, 45:114, 28:70]
+SELECT img[177:246, 45:114, 28:70]
+FROM comp_cubed_64 AS img
+// [5]: [52:146, 5:99, 72:128]
+SELECT img[52:146, 5:99, 72:128]
+FROM comp_cubed_64 AS img
+// [5]: [147:241, 45:139, 90:146]
+SELECT img[147:241, 45:139, 90:146]
+FROM comp_cubed_64 AS img
+// [5]: [156:250, 145:239, 7:63]
+SELECT img[156:250, 145:239, 7:63]
+FROM comp_cubed_64 AS img
+// [5]: [30:124, 108:202, 74:130]
+SELECT img[30:124, 108:202, 74:130]
+FROM comp_cubed_64 AS img
+// [5]: [140:234, 44:138, 25:81]
+SELECT img[140:234, 44:138, 25:81]
+FROM comp_cubed_64 AS img
+// [5]: [48:142, 9:103, 8:64]
+SELECT img[48:142, 9:103, 8:64]
+FROM comp_cubed_64 AS img
+// [5]: [0:94, 157:251, 73:129]
+SELECT img[0:94, 157:251, 73:129]
+FROM comp_cubed_64 AS img
+// [5]: [125:219, 53:147, 7:63]
+SELECT img[125:219, 53:147, 7:63]
+FROM comp_cubed_64 AS img
+// [5]: [26:120, 133:227, 38:94]
+SELECT img[26:120, 133:227, 38:94]
+FROM comp_cubed_64 AS img
+// [5]: [157:251, 41:135, 74:130]
+SELECT img[157:251, 41:135, 74:130]
+FROM comp_cubed_64 AS img
+// [5]: [41:135, 120:214, 31:87]
+SELECT img[41:135, 120:214, 31:87]
+FROM comp_cubed_64 AS img
+// [5]: [33:127, 116:210, 71:127]
+SELECT img[33:127, 116:210, 71:127]
+FROM comp_cubed_64 AS img
+// [5]: [138:232, 127:221, 20:76]
+SELECT img[138:232, 127:221, 20:76]
+FROM comp_cubed_64 AS img
+// [5]: [13:107, 9:103, 60:116]
+SELECT img[13:107, 9:103, 60:116]
+FROM comp_cubed_64 AS img
+// [5]: [124:218, 139:233, 74:130]
+SELECT img[124:218, 139:233, 74:130]
+FROM comp_cubed_64 AS img
+// [5]: [117:211, 86:180, 91:147]
+SELECT img[117:211, 86:180, 91:147]
+FROM comp_cubed_64 AS img
+// [5]: [143:237, 52:146, 71:127]
+SELECT img[143:237, 52:146, 71:127]
+FROM comp_cubed_64 AS img
+// [5]: [10:104, 35:129, 19:75]
+SELECT img[10:104, 35:129, 19:75]
+FROM comp_cubed_64 AS img
+// [5]: [110:204, 64:158, 64:120]
+SELECT img[110:204, 64:158, 64:120]
+FROM comp_cubed_64 AS img
+// [5]: [12:106, 103:197, 96:152]
+SELECT img[12:106, 103:197, 96:152]
+FROM comp_cubed_64 AS img
+// [10]: [108:226, 53:171, 9:80]
+SELECT img[108:226, 53:171, 9:80]
+FROM comp_cubed_64 AS img
+// [10]: [46:164, 103:221, 10:81]
+SELECT img[46:164, 103:221, 10:81]
+FROM comp_cubed_64 AS img
+// [10]: [80:198, 73:191, 38:109]
+SELECT img[80:198, 73:191, 38:109]
+FROM comp_cubed_64 AS img
+// [10]: [38:156, 132:250, 26:97]
+SELECT img[38:156, 132:250, 26:97]
+FROM comp_cubed_64 AS img
+// [10]: [11:129, 86:204, 77:148]
+SELECT img[11:129, 86:204, 77:148]
+FROM comp_cubed_64 AS img
+// [10]: [46:164, 90:208, 17:88]
+SELECT img[46:164, 90:208, 17:88]
+FROM comp_cubed_64 AS img
+// [10]: [86:204, 125:243, 6:77]
+SELECT img[86:204, 125:243, 6:77]
+FROM comp_cubed_64 AS img
+// [10]: [54:172, 49:167, 69:140]
+SELECT img[54:172, 49:167, 69:140]
+FROM comp_cubed_64 AS img
+// [10]: [11:129, 111:229, 23:94]
+SELECT img[11:129, 111:229, 23:94]
+FROM comp_cubed_64 AS img
+// [10]: [46:164, 66:184, 2:73]
+SELECT img[46:164, 66:184, 2:73]
+FROM comp_cubed_64 AS img
+// [10]: [88:206, 88:206, 39:110]
+SELECT img[88:206, 88:206, 39:110]
+FROM comp_cubed_64 AS img
+// [10]: [46:164, 22:140, 43:114]
+SELECT img[46:164, 22:140, 43:114]
+FROM comp_cubed_64 AS img
+// [10]: [4:122, 59:177, 47:118]
+SELECT img[4:122, 59:177, 47:118]
+FROM comp_cubed_64 AS img
+// [10]: [22:140, 37:155, 31:102]
+SELECT img[22:140, 37:155, 31:102]
+FROM comp_cubed_64 AS img
+// [10]: [109:227, 71:189, 81:152]
+SELECT img[109:227, 71:189, 81:152]
+FROM comp_cubed_64 AS img
+// [10]: [96:214, 76:194, 67:138]
+SELECT img[96:214, 76:194, 67:138]
+FROM comp_cubed_64 AS img
+// [10]: [4:122, 126:244, 10:81]
+SELECT img[4:122, 126:244, 10:81]
+FROM comp_cubed_64 AS img
+// [10]: [38:156, 90:208, 31:102]
+SELECT img[38:156, 90:208, 31:102]
+FROM comp_cubed_64 AS img
+// [10]: [12:130, 67:185, 70:141]
+SELECT img[12:130, 67:185, 70:141]
+FROM comp_cubed_64 AS img
+// [10]: [108:226, 59:177, 70:141]
+SELECT img[108:226, 59:177, 70:141]
+FROM comp_cubed_64 AS img
+// [20]: [60:209, 12:161, 15:104]
+SELECT img[60:209, 12:161, 15:104]
+FROM comp_cubed_64 AS img
+// [20]: [36:185, 68:217, 31:120]
+SELECT img[36:185, 68:217, 31:120]
+FROM comp_cubed_64 AS img
+// [20]: [19:168, 96:245, 50:139]
+SELECT img[19:168, 96:245, 50:139]
+FROM comp_cubed_64 AS img
+// [20]: [68:217, 96:245, 4:93]
+SELECT img[68:217, 96:245, 4:93]
+FROM comp_cubed_64 AS img
+// [20]: [16:165, 44:193, 49:138]
+SELECT img[16:165, 44:193, 49:138]
+FROM comp_cubed_64 AS img
+// [20]: [71:220, 91:240, 11:100]
+SELECT img[71:220, 91:240, 11:100]
+FROM comp_cubed_64 AS img
+// [20]: [96:245, 58:207, 4:93]
+SELECT img[96:245, 58:207, 4:93]
+FROM comp_cubed_64 AS img
+// [20]: [40:189, 6:155, 11:100]
+SELECT img[40:189, 6:155, 11:100]
+FROM comp_cubed_64 AS img
+// [20]: [91:240, 22:171, 7:96]
+SELECT img[91:240, 22:171, 7:96]
+FROM comp_cubed_64 AS img
+// [20]: [79:228, 85:234, 39:128]
+SELECT img[79:228, 85:234, 39:128]
+FROM comp_cubed_64 AS img
+// [20]: [97:246, 104:253, 6:95]
+SELECT img[97:246, 104:253, 6:95]
+FROM comp_cubed_64 AS img
+// [20]: [62:211, 26:175, 7:96]
+SELECT img[62:211, 26:175, 7:96]
+FROM comp_cubed_64 AS img
+// [20]: [35:184, 5:154, 29:118]
+SELECT img[35:184, 5:154, 29:118]
+FROM comp_cubed_64 AS img
+// [20]: [20:169, 92:241, 5:94]
+SELECT img[20:169, 92:241, 5:94]
+FROM comp_cubed_64 AS img
+// [20]: [77:226, 33:182, 45:134]
+SELECT img[77:226, 33:182, 45:134]
+FROM comp_cubed_64 AS img
+// [20]: [6:155, 40:189, 55:144]
+SELECT img[6:155, 40:189, 55:144]
+FROM comp_cubed_64 AS img
+// [20]: [102:251, 25:174, 20:109]
+SELECT img[102:251, 25:174, 20:109]
+FROM comp_cubed_64 AS img
+// [20]: [35:184, 70:219, 31:120]
+SELECT img[35:184, 70:219, 31:120]
+FROM comp_cubed_64 AS img
+// [20]: [99:248, 88:237, 10:99]
+SELECT img[99:248, 88:237, 10:99]
+FROM comp_cubed_64 AS img
+// [20]: [67:216, 63:212, 60:149]
+SELECT img[67:216, 63:212, 60:149]
+FROM comp_cubed_64 AS img
+// [50]: [46:248, 7:209, 31:152]
+SELECT img[46:248, 7:209, 31:152]
+FROM comp_cubed_64 AS img
+// [50]: [45:247, 24:226, 17:138]
+SELECT img[45:247, 24:226, 17:138]
+FROM comp_cubed_64 AS img
+// [50]: [22:224, 30:232, 9:130]
+SELECT img[22:224, 30:232, 9:130]
+FROM comp_cubed_64 AS img
+// [50]: [29:231, 39:241, 4:125]
+SELECT img[29:231, 39:241, 4:125]
+FROM comp_cubed_64 AS img
+// [50]: [19:221, 51:253, 6:127]
+SELECT img[19:221, 51:253, 6:127]
+FROM comp_cubed_64 AS img
+// [50]: [27:229, 14:216, 10:131]
+SELECT img[27:229, 14:216, 10:131]
+FROM comp_cubed_64 AS img
+// [50]: [33:235, 15:217, 26:147]
+SELECT img[33:235, 15:217, 26:147]
+FROM comp_cubed_64 AS img
+// [50]: [48:250, 1:203, 18:139]
+SELECT img[48:250, 1:203, 18:139]
+FROM comp_cubed_64 AS img
+// [50]: [24:226, 23:225, 23:144]
+SELECT img[24:226, 23:225, 23:144]
+FROM comp_cubed_64 AS img
+// [50]: [31:233, 12:214, 8:129]
+SELECT img[31:233, 12:214, 8:129]
+FROM comp_cubed_64 AS img
+// [50]: [34:236, 1:203, 24:145]
+SELECT img[34:236, 1:203, 24:145]
+FROM comp_cubed_64 AS img
+// [50]: [27:229, 17:219, 22:143]
+SELECT img[27:229, 17:219, 22:143]
+FROM comp_cubed_64 AS img
+// [50]: [15:217, 50:252, 16:137]
+SELECT img[15:217, 50:252, 16:137]
+FROM comp_cubed_64 AS img
+// [50]: [49:251, 3:205, 29:150]
+SELECT img[49:251, 3:205, 29:150]
+FROM comp_cubed_64 AS img
+// [50]: [11:213, 33:235, 17:138]
+SELECT img[11:213, 33:235, 17:138]
+FROM comp_cubed_64 AS img
+// [50]: [15:217, 23:225, 29:150]
+SELECT img[15:217, 23:225, 29:150]
+FROM comp_cubed_64 AS img
+// [50]: [46:248, 28:230, 30:151]
+SELECT img[46:248, 28:230, 30:151]
+FROM comp_cubed_64 AS img
+// [50]: [11:213, 6:208, 1:122]
+SELECT img[11:213, 6:208, 1:122]
+FROM comp_cubed_64 AS img
+// [50]: [13:215, 16:218, 24:145]
+SELECT img[13:215, 16:218, 24:145]
+FROM comp_cubed_64 AS img
+// [50]: [44:246, 46:248, 28:149]
+SELECT img[44:246, 46:248, 28:149]
+FROM comp_cubed_64 AS img
diff --git a/rasodmg/test/croll_16.ql b/rasodmg/test/croll_16.ql
new file mode 100644
index 0000000..8e37740
--- /dev/null
+++ b/rasodmg/test/croll_16.ql
@@ -0,0 +1,180 @@
+// ["x"] comp_cubed_16 [232:238,*:*,*:*]
+SELECT img[232,*:*,*:*]+img[233,*:*,*:*]+img[234,*:*,*:*]+img[235,*:*,*:*]+img[236,*:*,*:*]+img[237,*:*,*:*]+img[238,*:*,*:*]
+FROM comp_cubed_16 as img
+// ["x"] comp_cubed_16 [179:185,*:*,*:*]
+SELECT img[179,*:*,*:*]+img[180,*:*,*:*]+img[181,*:*,*:*]+img[182,*:*,*:*]+img[183,*:*,*:*]+img[184,*:*,*:*]+img[185,*:*,*:*]
+FROM comp_cubed_16 as img
+// ["x"] comp_cubed_16 [24:30,*:*,*:*]
+SELECT img[24,*:*,*:*]+img[25,*:*,*:*]+img[26,*:*,*:*]+img[27,*:*,*:*]+img[28,*:*,*:*]+img[29,*:*,*:*]+img[30,*:*,*:*]
+FROM comp_cubed_16 as img
+// ["x"] comp_cubed_16 [188:194,*:*,*:*]
+SELECT img[188,*:*,*:*]+img[189,*:*,*:*]+img[190,*:*,*:*]+img[191,*:*,*:*]+img[192,*:*,*:*]+img[193,*:*,*:*]+img[194,*:*,*:*]
+FROM comp_cubed_16 as img
+// ["x"] comp_cubed_16 [238:244,*:*,*:*]
+SELECT img[238,*:*,*:*]+img[239,*:*,*:*]+img[240,*:*,*:*]+img[241,*:*,*:*]+img[242,*:*,*:*]+img[243,*:*,*:*]+img[244,*:*,*:*]
+FROM comp_cubed_16 as img
+// ["x"] comp_cubed_16 [76:82,*:*,*:*]
+SELECT img[76,*:*,*:*]+img[77,*:*,*:*]+img[78,*:*,*:*]+img[79,*:*,*:*]+img[80,*:*,*:*]+img[81,*:*,*:*]+img[82,*:*,*:*]
+FROM comp_cubed_16 as img
+// ["x"] comp_cubed_16 [239:245,*:*,*:*]
+SELECT img[239,*:*,*:*]+img[240,*:*,*:*]+img[241,*:*,*:*]+img[242,*:*,*:*]+img[243,*:*,*:*]+img[244,*:*,*:*]+img[245,*:*,*:*]
+FROM comp_cubed_16 as img
+// ["x"] comp_cubed_16 [119:125,*:*,*:*]
+SELECT img[119,*:*,*:*]+img[120,*:*,*:*]+img[121,*:*,*:*]+img[122,*:*,*:*]+img[123,*:*,*:*]+img[124,*:*,*:*]+img[125,*:*,*:*]
+FROM comp_cubed_16 as img
+// ["x"] comp_cubed_16 [176:182,*:*,*:*]
+SELECT img[176,*:*,*:*]+img[177,*:*,*:*]+img[178,*:*,*:*]+img[179,*:*,*:*]+img[180,*:*,*:*]+img[181,*:*,*:*]+img[182,*:*,*:*]
+FROM comp_cubed_16 as img
+// ["x"] comp_cubed_16 [51:57,*:*,*:*]
+SELECT img[51,*:*,*:*]+img[52,*:*,*:*]+img[53,*:*,*:*]+img[54,*:*,*:*]+img[55,*:*,*:*]+img[56,*:*,*:*]+img[57,*:*,*:*]
+FROM comp_cubed_16 as img
+// ["x"] comp_cubed_16 [8:14,*:*,*:*]
+SELECT img[8,*:*,*:*]+img[9,*:*,*:*]+img[10,*:*,*:*]+img[11,*:*,*:*]+img[12,*:*,*:*]+img[13,*:*,*:*]+img[14,*:*,*:*]
+FROM comp_cubed_16 as img
+// ["x"] comp_cubed_16 [173:179,*:*,*:*]
+SELECT img[173,*:*,*:*]+img[174,*:*,*:*]+img[175,*:*,*:*]+img[176,*:*,*:*]+img[177,*:*,*:*]+img[178,*:*,*:*]+img[179,*:*,*:*]
+FROM comp_cubed_16 as img
+// ["x"] comp_cubed_16 [237:243,*:*,*:*]
+SELECT img[237,*:*,*:*]+img[238,*:*,*:*]+img[239,*:*,*:*]+img[240,*:*,*:*]+img[241,*:*,*:*]+img[242,*:*,*:*]+img[243,*:*,*:*]
+FROM comp_cubed_16 as img
+// ["x"] comp_cubed_16 [84:90,*:*,*:*]
+SELECT img[84,*:*,*:*]+img[85,*:*,*:*]+img[86,*:*,*:*]+img[87,*:*,*:*]+img[88,*:*,*:*]+img[89,*:*,*:*]+img[90,*:*,*:*]
+FROM comp_cubed_16 as img
+// ["x"] comp_cubed_16 [14:20,*:*,*:*]
+SELECT img[14,*:*,*:*]+img[15,*:*,*:*]+img[16,*:*,*:*]+img[17,*:*,*:*]+img[18,*:*,*:*]+img[19,*:*,*:*]+img[20,*:*,*:*]
+FROM comp_cubed_16 as img
+// ["x"] comp_cubed_16 [144:150,*:*,*:*]
+SELECT img[144,*:*,*:*]+img[145,*:*,*:*]+img[146,*:*,*:*]+img[147,*:*,*:*]+img[148,*:*,*:*]+img[149,*:*,*:*]+img[150,*:*,*:*]
+FROM comp_cubed_16 as img
+// ["x"] comp_cubed_16 [215:221,*:*,*:*]
+SELECT img[215,*:*,*:*]+img[216,*:*,*:*]+img[217,*:*,*:*]+img[218,*:*,*:*]+img[219,*:*,*:*]+img[220,*:*,*:*]+img[221,*:*,*:*]
+FROM comp_cubed_16 as img
+// ["x"] comp_cubed_16 [86:92,*:*,*:*]
+SELECT img[86,*:*,*:*]+img[87,*:*,*:*]+img[88,*:*,*:*]+img[89,*:*,*:*]+img[90,*:*,*:*]+img[91,*:*,*:*]+img[92,*:*,*:*]
+FROM comp_cubed_16 as img
+// ["x"] comp_cubed_16 [136:142,*:*,*:*]
+SELECT img[136,*:*,*:*]+img[137,*:*,*:*]+img[138,*:*,*:*]+img[139,*:*,*:*]+img[140,*:*,*:*]+img[141,*:*,*:*]+img[142,*:*,*:*]
+FROM comp_cubed_16 as img
+// ["x"] comp_cubed_16 [135:141,*:*,*:*]
+SELECT img[135,*:*,*:*]+img[136,*:*,*:*]+img[137,*:*,*:*]+img[138,*:*,*:*]+img[139,*:*,*:*]+img[140,*:*,*:*]+img[141,*:*,*:*]
+FROM comp_cubed_16 as img
+// ["y"] comp_cubed_16 [*:*, 146:152, *:*]
+SELECT img[*:*,146,*:*]+img[*:*,147,*:*]+img[*:*,148,*:*]+img[*:*,149,*:*]+img[*:*,150,*:*]+img[*:*,151,*:*]+img[*:*,152,*:*]
+FROM comp_cubed_16 as img
+// ["y"] comp_cubed_16 [*:*, 15:21, *:*]
+SELECT img[*:*,15,*:*]+img[*:*,16,*:*]+img[*:*,17,*:*]+img[*:*,18,*:*]+img[*:*,19,*:*]+img[*:*,20,*:*]+img[*:*,21,*:*]
+FROM comp_cubed_16 as img
+// ["y"] comp_cubed_16 [*:*, 148:154, *:*]
+SELECT img[*:*,148,*:*]+img[*:*,149,*:*]+img[*:*,150,*:*]+img[*:*,151,*:*]+img[*:*,152,*:*]+img[*:*,153,*:*]+img[*:*,154,*:*]
+FROM comp_cubed_16 as img
+// ["y"] comp_cubed_16 [*:*, 82:88, *:*]
+SELECT img[*:*,82,*:*]+img[*:*,83,*:*]+img[*:*,84,*:*]+img[*:*,85,*:*]+img[*:*,86,*:*]+img[*:*,87,*:*]+img[*:*,88,*:*]
+FROM comp_cubed_16 as img
+// ["y"] comp_cubed_16 [*:*, 149:155, *:*]
+SELECT img[*:*,149,*:*]+img[*:*,150,*:*]+img[*:*,151,*:*]+img[*:*,152,*:*]+img[*:*,153,*:*]+img[*:*,154,*:*]+img[*:*,155,*:*]
+FROM comp_cubed_16 as img
+// ["y"] comp_cubed_16 [*:*, 154:160, *:*]
+SELECT img[*:*,154,*:*]+img[*:*,155,*:*]+img[*:*,156,*:*]+img[*:*,157,*:*]+img[*:*,158,*:*]+img[*:*,159,*:*]+img[*:*,160,*:*]
+FROM comp_cubed_16 as img
+// ["y"] comp_cubed_16 [*:*, 46:52, *:*]
+SELECT img[*:*,46,*:*]+img[*:*,47,*:*]+img[*:*,48,*:*]+img[*:*,49,*:*]+img[*:*,50,*:*]+img[*:*,51,*:*]+img[*:*,52,*:*]
+FROM comp_cubed_16 as img
+// ["y"] comp_cubed_16 [*:*, 3:9, *:*]
+SELECT img[*:*,3,*:*]+img[*:*,4,*:*]+img[*:*,5,*:*]+img[*:*,6,*:*]+img[*:*,7,*:*]+img[*:*,8,*:*]+img[*:*,9,*:*]
+FROM comp_cubed_16 as img
+// ["y"] comp_cubed_16 [*:*, 20:26, *:*]
+SELECT img[*:*,20,*:*]+img[*:*,21,*:*]+img[*:*,22,*:*]+img[*:*,23,*:*]+img[*:*,24,*:*]+img[*:*,25,*:*]+img[*:*,26,*:*]
+FROM comp_cubed_16 as img
+// ["y"] comp_cubed_16 [*:*, 17:23, *:*]
+SELECT img[*:*,17,*:*]+img[*:*,18,*:*]+img[*:*,19,*:*]+img[*:*,20,*:*]+img[*:*,21,*:*]+img[*:*,22,*:*]+img[*:*,23,*:*]
+FROM comp_cubed_16 as img
+// ["y"] comp_cubed_16 [*:*, 236:242, *:*]
+SELECT img[*:*,236,*:*]+img[*:*,237,*:*]+img[*:*,238,*:*]+img[*:*,239,*:*]+img[*:*,240,*:*]+img[*:*,241,*:*]+img[*:*,242,*:*]
+FROM comp_cubed_16 as img
+// ["y"] comp_cubed_16 [*:*, 98:104, *:*]
+SELECT img[*:*,98,*:*]+img[*:*,99,*:*]+img[*:*,100,*:*]+img[*:*,101,*:*]+img[*:*,102,*:*]+img[*:*,103,*:*]+img[*:*,104,*:*]
+FROM comp_cubed_16 as img
+// ["y"] comp_cubed_16 [*:*, 4:10, *:*]
+SELECT img[*:*,4,*:*]+img[*:*,5,*:*]+img[*:*,6,*:*]+img[*:*,7,*:*]+img[*:*,8,*:*]+img[*:*,9,*:*]+img[*:*,10,*:*]
+FROM comp_cubed_16 as img
+// ["y"] comp_cubed_16 [*:*, 199:205, *:*]
+SELECT img[*:*,199,*:*]+img[*:*,200,*:*]+img[*:*,201,*:*]+img[*:*,202,*:*]+img[*:*,203,*:*]+img[*:*,204,*:*]+img[*:*,205,*:*]
+FROM comp_cubed_16 as img
+// ["y"] comp_cubed_16 [*:*, 197:203, *:*]
+SELECT img[*:*,197,*:*]+img[*:*,198,*:*]+img[*:*,199,*:*]+img[*:*,200,*:*]+img[*:*,201,*:*]+img[*:*,202,*:*]+img[*:*,203,*:*]
+FROM comp_cubed_16 as img
+// ["y"] comp_cubed_16 [*:*, 19:25, *:*]
+SELECT img[*:*,19,*:*]+img[*:*,20,*:*]+img[*:*,21,*:*]+img[*:*,22,*:*]+img[*:*,23,*:*]+img[*:*,24,*:*]+img[*:*,25,*:*]
+FROM comp_cubed_16 as img
+// ["y"] comp_cubed_16 [*:*, 64:70, *:*]
+SELECT img[*:*,64,*:*]+img[*:*,65,*:*]+img[*:*,66,*:*]+img[*:*,67,*:*]+img[*:*,68,*:*]+img[*:*,69,*:*]+img[*:*,70,*:*]
+FROM comp_cubed_16 as img
+// ["y"] comp_cubed_16 [*:*, 169:175, *:*]
+SELECT img[*:*,169,*:*]+img[*:*,170,*:*]+img[*:*,171,*:*]+img[*:*,172,*:*]+img[*:*,173,*:*]+img[*:*,174,*:*]+img[*:*,175,*:*]
+FROM comp_cubed_16 as img
+// ["y"] comp_cubed_16 [*:*, 109:115, *:*]
+SELECT img[*:*,109,*:*]+img[*:*,110,*:*]+img[*:*,111,*:*]+img[*:*,112,*:*]+img[*:*,113,*:*]+img[*:*,114,*:*]+img[*:*,115,*:*]
+FROM comp_cubed_16 as img
+// ["y"] comp_cubed_16 [*:*, 148:154, *:*]
+SELECT img[*:*,148,*:*]+img[*:*,149,*:*]+img[*:*,150,*:*]+img[*:*,151,*:*]+img[*:*,152,*:*]+img[*:*,153,*:*]+img[*:*,154,*:*]
+FROM comp_cubed_16 as img
+// ["z"] comp_cubed_16 [*:*, *:*, 35:41]
+SELECT img[*:*,*:*,35]+img[*:*,*:*,36]+img[*:*,*:*,37]+img[*:*,*:*,38]+img[*:*,*:*,39]+img[*:*,*:*,40]+img[*:*,*:*,41]
+FROM comp_cubed_16 as img
+// ["z"] comp_cubed_16 [*:*, *:*, 24:30]
+SELECT img[*:*,*:*,24]+img[*:*,*:*,25]+img[*:*,*:*,26]+img[*:*,*:*,27]+img[*:*,*:*,28]+img[*:*,*:*,29]+img[*:*,*:*,30]
+FROM comp_cubed_16 as img
+// ["z"] comp_cubed_16 [*:*, *:*, 38:44]
+SELECT img[*:*,*:*,38]+img[*:*,*:*,39]+img[*:*,*:*,40]+img[*:*,*:*,41]+img[*:*,*:*,42]+img[*:*,*:*,43]+img[*:*,*:*,44]
+FROM comp_cubed_16 as img
+// ["z"] comp_cubed_16 [*:*, *:*, 129:135]
+SELECT img[*:*,*:*,129]+img[*:*,*:*,130]+img[*:*,*:*,131]+img[*:*,*:*,132]+img[*:*,*:*,133]+img[*:*,*:*,134]+img[*:*,*:*,135]
+FROM comp_cubed_16 as img
+// ["z"] comp_cubed_16 [*:*, *:*, 88:94]
+SELECT img[*:*,*:*,88]+img[*:*,*:*,89]+img[*:*,*:*,90]+img[*:*,*:*,91]+img[*:*,*:*,92]+img[*:*,*:*,93]+img[*:*,*:*,94]
+FROM comp_cubed_16 as img
+// ["z"] comp_cubed_16 [*:*, *:*, 49:55]
+SELECT img[*:*,*:*,49]+img[*:*,*:*,50]+img[*:*,*:*,51]+img[*:*,*:*,52]+img[*:*,*:*,53]+img[*:*,*:*,54]+img[*:*,*:*,55]
+FROM comp_cubed_16 as img
+// ["z"] comp_cubed_16 [*:*, *:*, 70:76]
+SELECT img[*:*,*:*,70]+img[*:*,*:*,71]+img[*:*,*:*,72]+img[*:*,*:*,73]+img[*:*,*:*,74]+img[*:*,*:*,75]+img[*:*,*:*,76]
+FROM comp_cubed_16 as img
+// ["z"] comp_cubed_16 [*:*, *:*, 76:82]
+SELECT img[*:*,*:*,76]+img[*:*,*:*,77]+img[*:*,*:*,78]+img[*:*,*:*,79]+img[*:*,*:*,80]+img[*:*,*:*,81]+img[*:*,*:*,82]
+FROM comp_cubed_16 as img
+// ["z"] comp_cubed_16 [*:*, *:*, 60:66]
+SELECT img[*:*,*:*,60]+img[*:*,*:*,61]+img[*:*,*:*,62]+img[*:*,*:*,63]+img[*:*,*:*,64]+img[*:*,*:*,65]+img[*:*,*:*,66]
+FROM comp_cubed_16 as img
+// ["z"] comp_cubed_16 [*:*, *:*, 9:15]
+SELECT img[*:*,*:*,9]+img[*:*,*:*,10]+img[*:*,*:*,11]+img[*:*,*:*,12]+img[*:*,*:*,13]+img[*:*,*:*,14]+img[*:*,*:*,15]
+FROM comp_cubed_16 as img
+// ["z"] comp_cubed_16 [*:*, *:*, 14:20]
+SELECT img[*:*,*:*,14]+img[*:*,*:*,15]+img[*:*,*:*,16]+img[*:*,*:*,17]+img[*:*,*:*,18]+img[*:*,*:*,19]+img[*:*,*:*,20]
+FROM comp_cubed_16 as img
+// ["z"] comp_cubed_16 [*:*, *:*, 2:8]
+SELECT img[*:*,*:*,2]+img[*:*,*:*,3]+img[*:*,*:*,4]+img[*:*,*:*,5]+img[*:*,*:*,6]+img[*:*,*:*,7]+img[*:*,*:*,8]
+FROM comp_cubed_16 as img
+// ["z"] comp_cubed_16 [*:*, *:*, 29:35]
+SELECT img[*:*,*:*,29]+img[*:*,*:*,30]+img[*:*,*:*,31]+img[*:*,*:*,32]+img[*:*,*:*,33]+img[*:*,*:*,34]+img[*:*,*:*,35]
+FROM comp_cubed_16 as img
+// ["z"] comp_cubed_16 [*:*, *:*, 48:54]
+SELECT img[*:*,*:*,48]+img[*:*,*:*,49]+img[*:*,*:*,50]+img[*:*,*:*,51]+img[*:*,*:*,52]+img[*:*,*:*,53]+img[*:*,*:*,54]
+FROM comp_cubed_16 as img
+// ["z"] comp_cubed_16 [*:*, *:*, 89:95]
+SELECT img[*:*,*:*,89]+img[*:*,*:*,90]+img[*:*,*:*,91]+img[*:*,*:*,92]+img[*:*,*:*,93]+img[*:*,*:*,94]+img[*:*,*:*,95]
+FROM comp_cubed_16 as img
+// ["z"] comp_cubed_16 [*:*, *:*, 75:81]
+SELECT img[*:*,*:*,75]+img[*:*,*:*,76]+img[*:*,*:*,77]+img[*:*,*:*,78]+img[*:*,*:*,79]+img[*:*,*:*,80]+img[*:*,*:*,81]
+FROM comp_cubed_16 as img
+// ["z"] comp_cubed_16 [*:*, *:*, 83:89]
+SELECT img[*:*,*:*,83]+img[*:*,*:*,84]+img[*:*,*:*,85]+img[*:*,*:*,86]+img[*:*,*:*,87]+img[*:*,*:*,88]+img[*:*,*:*,89]
+FROM comp_cubed_16 as img
+// ["z"] comp_cubed_16 [*:*, *:*, 125:131]
+SELECT img[*:*,*:*,125]+img[*:*,*:*,126]+img[*:*,*:*,127]+img[*:*,*:*,128]+img[*:*,*:*,129]+img[*:*,*:*,130]+img[*:*,*:*,131]
+FROM comp_cubed_16 as img
+// ["z"] comp_cubed_16 [*:*, *:*, 132:138]
+SELECT img[*:*,*:*,132]+img[*:*,*:*,133]+img[*:*,*:*,134]+img[*:*,*:*,135]+img[*:*,*:*,136]+img[*:*,*:*,137]+img[*:*,*:*,138]
+FROM comp_cubed_16 as img
+// ["z"] comp_cubed_16 [*:*, *:*, 32:38]
+SELECT img[*:*,*:*,32]+img[*:*,*:*,33]+img[*:*,*:*,34]+img[*:*,*:*,35]+img[*:*,*:*,36]+img[*:*,*:*,37]+img[*:*,*:*,38]
+FROM comp_cubed_16 as img
diff --git a/rasodmg/test/croll_32.ql b/rasodmg/test/croll_32.ql
new file mode 100644
index 0000000..b4b1790
--- /dev/null
+++ b/rasodmg/test/croll_32.ql
@@ -0,0 +1,180 @@
+// ["x"] comp_cubed [133:139,*:*,*:*]
+SELECT img[133,*:*,*:*]+img[134,*:*,*:*]+img[135,*:*,*:*]+img[136,*:*,*:*]+img[137,*:*,*:*]+img[138,*:*,*:*]+img[139,*:*,*:*]
+FROM comp_cubed as img
+// ["x"] comp_cubed [248:254,*:*,*:*]
+SELECT img[248,*:*,*:*]+img[249,*:*,*:*]+img[250,*:*,*:*]+img[251,*:*,*:*]+img[252,*:*,*:*]+img[253,*:*,*:*]+img[254,*:*,*:*]
+FROM comp_cubed as img
+// ["x"] comp_cubed [94:100,*:*,*:*]
+SELECT img[94,*:*,*:*]+img[95,*:*,*:*]+img[96,*:*,*:*]+img[97,*:*,*:*]+img[98,*:*,*:*]+img[99,*:*,*:*]+img[100,*:*,*:*]
+FROM comp_cubed as img
+// ["x"] comp_cubed [3:9,*:*,*:*]
+SELECT img[3,*:*,*:*]+img[4,*:*,*:*]+img[5,*:*,*:*]+img[6,*:*,*:*]+img[7,*:*,*:*]+img[8,*:*,*:*]+img[9,*:*,*:*]
+FROM comp_cubed as img
+// ["x"] comp_cubed [93:99,*:*,*:*]
+SELECT img[93,*:*,*:*]+img[94,*:*,*:*]+img[95,*:*,*:*]+img[96,*:*,*:*]+img[97,*:*,*:*]+img[98,*:*,*:*]+img[99,*:*,*:*]
+FROM comp_cubed as img
+// ["x"] comp_cubed [62:68,*:*,*:*]
+SELECT img[62,*:*,*:*]+img[63,*:*,*:*]+img[64,*:*,*:*]+img[65,*:*,*:*]+img[66,*:*,*:*]+img[67,*:*,*:*]+img[68,*:*,*:*]
+FROM comp_cubed as img
+// ["x"] comp_cubed [174:180,*:*,*:*]
+SELECT img[174,*:*,*:*]+img[175,*:*,*:*]+img[176,*:*,*:*]+img[177,*:*,*:*]+img[178,*:*,*:*]+img[179,*:*,*:*]+img[180,*:*,*:*]
+FROM comp_cubed as img
+// ["x"] comp_cubed [97:103,*:*,*:*]
+SELECT img[97,*:*,*:*]+img[98,*:*,*:*]+img[99,*:*,*:*]+img[100,*:*,*:*]+img[101,*:*,*:*]+img[102,*:*,*:*]+img[103,*:*,*:*]
+FROM comp_cubed as img
+// ["x"] comp_cubed [43:49,*:*,*:*]
+SELECT img[43,*:*,*:*]+img[44,*:*,*:*]+img[45,*:*,*:*]+img[46,*:*,*:*]+img[47,*:*,*:*]+img[48,*:*,*:*]+img[49,*:*,*:*]
+FROM comp_cubed as img
+// ["x"] comp_cubed [41:47,*:*,*:*]
+SELECT img[41,*:*,*:*]+img[42,*:*,*:*]+img[43,*:*,*:*]+img[44,*:*,*:*]+img[45,*:*,*:*]+img[46,*:*,*:*]+img[47,*:*,*:*]
+FROM comp_cubed as img
+// ["x"] comp_cubed [38:44,*:*,*:*]
+SELECT img[38,*:*,*:*]+img[39,*:*,*:*]+img[40,*:*,*:*]+img[41,*:*,*:*]+img[42,*:*,*:*]+img[43,*:*,*:*]+img[44,*:*,*:*]
+FROM comp_cubed as img
+// ["x"] comp_cubed [75:81,*:*,*:*]
+SELECT img[75,*:*,*:*]+img[76,*:*,*:*]+img[77,*:*,*:*]+img[78,*:*,*:*]+img[79,*:*,*:*]+img[80,*:*,*:*]+img[81,*:*,*:*]
+FROM comp_cubed as img
+// ["x"] comp_cubed [189:195,*:*,*:*]
+SELECT img[189,*:*,*:*]+img[190,*:*,*:*]+img[191,*:*,*:*]+img[192,*:*,*:*]+img[193,*:*,*:*]+img[194,*:*,*:*]+img[195,*:*,*:*]
+FROM comp_cubed as img
+// ["x"] comp_cubed [3:9,*:*,*:*]
+SELECT img[3,*:*,*:*]+img[4,*:*,*:*]+img[5,*:*,*:*]+img[6,*:*,*:*]+img[7,*:*,*:*]+img[8,*:*,*:*]+img[9,*:*,*:*]
+FROM comp_cubed as img
+// ["x"] comp_cubed [38:44,*:*,*:*]
+SELECT img[38,*:*,*:*]+img[39,*:*,*:*]+img[40,*:*,*:*]+img[41,*:*,*:*]+img[42,*:*,*:*]+img[43,*:*,*:*]+img[44,*:*,*:*]
+FROM comp_cubed as img
+// ["x"] comp_cubed [5:11,*:*,*:*]
+SELECT img[5,*:*,*:*]+img[6,*:*,*:*]+img[7,*:*,*:*]+img[8,*:*,*:*]+img[9,*:*,*:*]+img[10,*:*,*:*]+img[11,*:*,*:*]
+FROM comp_cubed as img
+// ["x"] comp_cubed [83:89,*:*,*:*]
+SELECT img[83,*:*,*:*]+img[84,*:*,*:*]+img[85,*:*,*:*]+img[86,*:*,*:*]+img[87,*:*,*:*]+img[88,*:*,*:*]+img[89,*:*,*:*]
+FROM comp_cubed as img
+// ["x"] comp_cubed [23:29,*:*,*:*]
+SELECT img[23,*:*,*:*]+img[24,*:*,*:*]+img[25,*:*,*:*]+img[26,*:*,*:*]+img[27,*:*,*:*]+img[28,*:*,*:*]+img[29,*:*,*:*]
+FROM comp_cubed as img
+// ["x"] comp_cubed [185:191,*:*,*:*]
+SELECT img[185,*:*,*:*]+img[186,*:*,*:*]+img[187,*:*,*:*]+img[188,*:*,*:*]+img[189,*:*,*:*]+img[190,*:*,*:*]+img[191,*:*,*:*]
+FROM comp_cubed as img
+// ["x"] comp_cubed [148:154,*:*,*:*]
+SELECT img[148,*:*,*:*]+img[149,*:*,*:*]+img[150,*:*,*:*]+img[151,*:*,*:*]+img[152,*:*,*:*]+img[153,*:*,*:*]+img[154,*:*,*:*]
+FROM comp_cubed as img
+// ["y"] comp_cubed [*:*, 100:106, *:*]
+SELECT img[*:*,100,*:*]+img[*:*,101,*:*]+img[*:*,102,*:*]+img[*:*,103,*:*]+img[*:*,104,*:*]+img[*:*,105,*:*]+img[*:*,106,*:*]
+FROM comp_cubed as img
+// ["y"] comp_cubed [*:*, 2:8, *:*]
+SELECT img[*:*,2,*:*]+img[*:*,3,*:*]+img[*:*,4,*:*]+img[*:*,5,*:*]+img[*:*,6,*:*]+img[*:*,7,*:*]+img[*:*,8,*:*]
+FROM comp_cubed as img
+// ["y"] comp_cubed [*:*, 166:172, *:*]
+SELECT img[*:*,166,*:*]+img[*:*,167,*:*]+img[*:*,168,*:*]+img[*:*,169,*:*]+img[*:*,170,*:*]+img[*:*,171,*:*]+img[*:*,172,*:*]
+FROM comp_cubed as img
+// ["y"] comp_cubed [*:*, 246:252, *:*]
+SELECT img[*:*,246,*:*]+img[*:*,247,*:*]+img[*:*,248,*:*]+img[*:*,249,*:*]+img[*:*,250,*:*]+img[*:*,251,*:*]+img[*:*,252,*:*]
+FROM comp_cubed as img
+// ["y"] comp_cubed [*:*, 78:84, *:*]
+SELECT img[*:*,78,*:*]+img[*:*,79,*:*]+img[*:*,80,*:*]+img[*:*,81,*:*]+img[*:*,82,*:*]+img[*:*,83,*:*]+img[*:*,84,*:*]
+FROM comp_cubed as img
+// ["y"] comp_cubed [*:*, 174:180, *:*]
+SELECT img[*:*,174,*:*]+img[*:*,175,*:*]+img[*:*,176,*:*]+img[*:*,177,*:*]+img[*:*,178,*:*]+img[*:*,179,*:*]+img[*:*,180,*:*]
+FROM comp_cubed as img
+// ["y"] comp_cubed [*:*, 233:239, *:*]
+SELECT img[*:*,233,*:*]+img[*:*,234,*:*]+img[*:*,235,*:*]+img[*:*,236,*:*]+img[*:*,237,*:*]+img[*:*,238,*:*]+img[*:*,239,*:*]
+FROM comp_cubed as img
+// ["y"] comp_cubed [*:*, 131:137, *:*]
+SELECT img[*:*,131,*:*]+img[*:*,132,*:*]+img[*:*,133,*:*]+img[*:*,134,*:*]+img[*:*,135,*:*]+img[*:*,136,*:*]+img[*:*,137,*:*]
+FROM comp_cubed as img
+// ["y"] comp_cubed [*:*, 25:31, *:*]
+SELECT img[*:*,25,*:*]+img[*:*,26,*:*]+img[*:*,27,*:*]+img[*:*,28,*:*]+img[*:*,29,*:*]+img[*:*,30,*:*]+img[*:*,31,*:*]
+FROM comp_cubed as img
+// ["y"] comp_cubed [*:*, 170:176, *:*]
+SELECT img[*:*,170,*:*]+img[*:*,171,*:*]+img[*:*,172,*:*]+img[*:*,173,*:*]+img[*:*,174,*:*]+img[*:*,175,*:*]+img[*:*,176,*:*]
+FROM comp_cubed as img
+// ["y"] comp_cubed [*:*, 85:91, *:*]
+SELECT img[*:*,85,*:*]+img[*:*,86,*:*]+img[*:*,87,*:*]+img[*:*,88,*:*]+img[*:*,89,*:*]+img[*:*,90,*:*]+img[*:*,91,*:*]
+FROM comp_cubed as img
+// ["y"] comp_cubed [*:*, 178:184, *:*]
+SELECT img[*:*,178,*:*]+img[*:*,179,*:*]+img[*:*,180,*:*]+img[*:*,181,*:*]+img[*:*,182,*:*]+img[*:*,183,*:*]+img[*:*,184,*:*]
+FROM comp_cubed as img
+// ["y"] comp_cubed [*:*, 198:204, *:*]
+SELECT img[*:*,198,*:*]+img[*:*,199,*:*]+img[*:*,200,*:*]+img[*:*,201,*:*]+img[*:*,202,*:*]+img[*:*,203,*:*]+img[*:*,204,*:*]
+FROM comp_cubed as img
+// ["y"] comp_cubed [*:*, 54:60, *:*]
+SELECT img[*:*,54,*:*]+img[*:*,55,*:*]+img[*:*,56,*:*]+img[*:*,57,*:*]+img[*:*,58,*:*]+img[*:*,59,*:*]+img[*:*,60,*:*]
+FROM comp_cubed as img
+// ["y"] comp_cubed [*:*, 227:233, *:*]
+SELECT img[*:*,227,*:*]+img[*:*,228,*:*]+img[*:*,229,*:*]+img[*:*,230,*:*]+img[*:*,231,*:*]+img[*:*,232,*:*]+img[*:*,233,*:*]
+FROM comp_cubed as img
+// ["y"] comp_cubed [*:*, 4:10, *:*]
+SELECT img[*:*,4,*:*]+img[*:*,5,*:*]+img[*:*,6,*:*]+img[*:*,7,*:*]+img[*:*,8,*:*]+img[*:*,9,*:*]+img[*:*,10,*:*]
+FROM comp_cubed as img
+// ["y"] comp_cubed [*:*, 7:13, *:*]
+SELECT img[*:*,7,*:*]+img[*:*,8,*:*]+img[*:*,9,*:*]+img[*:*,10,*:*]+img[*:*,11,*:*]+img[*:*,12,*:*]+img[*:*,13,*:*]
+FROM comp_cubed as img
+// ["y"] comp_cubed [*:*, 217:223, *:*]
+SELECT img[*:*,217,*:*]+img[*:*,218,*:*]+img[*:*,219,*:*]+img[*:*,220,*:*]+img[*:*,221,*:*]+img[*:*,222,*:*]+img[*:*,223,*:*]
+FROM comp_cubed as img
+// ["y"] comp_cubed [*:*, 200:206, *:*]
+SELECT img[*:*,200,*:*]+img[*:*,201,*:*]+img[*:*,202,*:*]+img[*:*,203,*:*]+img[*:*,204,*:*]+img[*:*,205,*:*]+img[*:*,206,*:*]
+FROM comp_cubed as img
+// ["y"] comp_cubed [*:*, 181:187, *:*]
+SELECT img[*:*,181,*:*]+img[*:*,182,*:*]+img[*:*,183,*:*]+img[*:*,184,*:*]+img[*:*,185,*:*]+img[*:*,186,*:*]+img[*:*,187,*:*]
+FROM comp_cubed as img
+// ["z"] comp_cubed [*:*, *:*, 4:10]
+SELECT img[*:*,*:*,4]+img[*:*,*:*,5]+img[*:*,*:*,6]+img[*:*,*:*,7]+img[*:*,*:*,8]+img[*:*,*:*,9]+img[*:*,*:*,10]
+FROM comp_cubed as img
+// ["z"] comp_cubed [*:*, *:*, 29:35]
+SELECT img[*:*,*:*,29]+img[*:*,*:*,30]+img[*:*,*:*,31]+img[*:*,*:*,32]+img[*:*,*:*,33]+img[*:*,*:*,34]+img[*:*,*:*,35]
+FROM comp_cubed as img
+// ["z"] comp_cubed [*:*, *:*, 74:80]
+SELECT img[*:*,*:*,74]+img[*:*,*:*,75]+img[*:*,*:*,76]+img[*:*,*:*,77]+img[*:*,*:*,78]+img[*:*,*:*,79]+img[*:*,*:*,80]
+FROM comp_cubed as img
+// ["z"] comp_cubed [*:*, *:*, 71:77]
+SELECT img[*:*,*:*,71]+img[*:*,*:*,72]+img[*:*,*:*,73]+img[*:*,*:*,74]+img[*:*,*:*,75]+img[*:*,*:*,76]+img[*:*,*:*,77]
+FROM comp_cubed as img
+// ["z"] comp_cubed [*:*, *:*, 125:131]
+SELECT img[*:*,*:*,125]+img[*:*,*:*,126]+img[*:*,*:*,127]+img[*:*,*:*,128]+img[*:*,*:*,129]+img[*:*,*:*,130]+img[*:*,*:*,131]
+FROM comp_cubed as img
+// ["z"] comp_cubed [*:*, *:*, 146:152]
+SELECT img[*:*,*:*,146]+img[*:*,*:*,147]+img[*:*,*:*,148]+img[*:*,*:*,149]+img[*:*,*:*,150]+img[*:*,*:*,151]+img[*:*,*:*,152]
+FROM comp_cubed as img
+// ["z"] comp_cubed [*:*, *:*, 138:144]
+SELECT img[*:*,*:*,138]+img[*:*,*:*,139]+img[*:*,*:*,140]+img[*:*,*:*,141]+img[*:*,*:*,142]+img[*:*,*:*,143]+img[*:*,*:*,144]
+FROM comp_cubed as img
+// ["z"] comp_cubed [*:*, *:*, 81:87]
+SELECT img[*:*,*:*,81]+img[*:*,*:*,82]+img[*:*,*:*,83]+img[*:*,*:*,84]+img[*:*,*:*,85]+img[*:*,*:*,86]+img[*:*,*:*,87]
+FROM comp_cubed as img
+// ["z"] comp_cubed [*:*, *:*, 133:139]
+SELECT img[*:*,*:*,133]+img[*:*,*:*,134]+img[*:*,*:*,135]+img[*:*,*:*,136]+img[*:*,*:*,137]+img[*:*,*:*,138]+img[*:*,*:*,139]
+FROM comp_cubed as img
+// ["z"] comp_cubed [*:*, *:*, 131:137]
+SELECT img[*:*,*:*,131]+img[*:*,*:*,132]+img[*:*,*:*,133]+img[*:*,*:*,134]+img[*:*,*:*,135]+img[*:*,*:*,136]+img[*:*,*:*,137]
+FROM comp_cubed as img
+// ["z"] comp_cubed [*:*, *:*, 52:58]
+SELECT img[*:*,*:*,52]+img[*:*,*:*,53]+img[*:*,*:*,54]+img[*:*,*:*,55]+img[*:*,*:*,56]+img[*:*,*:*,57]+img[*:*,*:*,58]
+FROM comp_cubed as img
+// ["z"] comp_cubed [*:*, *:*, 67:73]
+SELECT img[*:*,*:*,67]+img[*:*,*:*,68]+img[*:*,*:*,69]+img[*:*,*:*,70]+img[*:*,*:*,71]+img[*:*,*:*,72]+img[*:*,*:*,73]
+FROM comp_cubed as img
+// ["z"] comp_cubed [*:*, *:*, 104:110]
+SELECT img[*:*,*:*,104]+img[*:*,*:*,105]+img[*:*,*:*,106]+img[*:*,*:*,107]+img[*:*,*:*,108]+img[*:*,*:*,109]+img[*:*,*:*,110]
+FROM comp_cubed as img
+// ["z"] comp_cubed [*:*, *:*, 95:101]
+SELECT img[*:*,*:*,95]+img[*:*,*:*,96]+img[*:*,*:*,97]+img[*:*,*:*,98]+img[*:*,*:*,99]+img[*:*,*:*,100]+img[*:*,*:*,101]
+FROM comp_cubed as img
+// ["z"] comp_cubed [*:*, *:*, 71:77]
+SELECT img[*:*,*:*,71]+img[*:*,*:*,72]+img[*:*,*:*,73]+img[*:*,*:*,74]+img[*:*,*:*,75]+img[*:*,*:*,76]+img[*:*,*:*,77]
+FROM comp_cubed as img
+// ["z"] comp_cubed [*:*, *:*, 5:11]
+SELECT img[*:*,*:*,5]+img[*:*,*:*,6]+img[*:*,*:*,7]+img[*:*,*:*,8]+img[*:*,*:*,9]+img[*:*,*:*,10]+img[*:*,*:*,11]
+FROM comp_cubed as img
+// ["z"] comp_cubed [*:*, *:*, 127:133]
+SELECT img[*:*,*:*,127]+img[*:*,*:*,128]+img[*:*,*:*,129]+img[*:*,*:*,130]+img[*:*,*:*,131]+img[*:*,*:*,132]+img[*:*,*:*,133]
+FROM comp_cubed as img
+// ["z"] comp_cubed [*:*, *:*, 4:10]
+SELECT img[*:*,*:*,4]+img[*:*,*:*,5]+img[*:*,*:*,6]+img[*:*,*:*,7]+img[*:*,*:*,8]+img[*:*,*:*,9]+img[*:*,*:*,10]
+FROM comp_cubed as img
+// ["z"] comp_cubed [*:*, *:*, 141:147]
+SELECT img[*:*,*:*,141]+img[*:*,*:*,142]+img[*:*,*:*,143]+img[*:*,*:*,144]+img[*:*,*:*,145]+img[*:*,*:*,146]+img[*:*,*:*,147]
+FROM comp_cubed as img
+// ["z"] comp_cubed [*:*, *:*, 82:88]
+SELECT img[*:*,*:*,82]+img[*:*,*:*,83]+img[*:*,*:*,84]+img[*:*,*:*,85]+img[*:*,*:*,86]+img[*:*,*:*,87]+img[*:*,*:*,88]
+FROM comp_cubed as img
diff --git a/rasodmg/test/croll_64.ql b/rasodmg/test/croll_64.ql
new file mode 100644
index 0000000..5729a42
--- /dev/null
+++ b/rasodmg/test/croll_64.ql
@@ -0,0 +1,180 @@
+// ["x"] comp_cubed_64 [32:38,*:*,*:*]
+SELECT img[32,*:*,*:*]+img[33,*:*,*:*]+img[34,*:*,*:*]+img[35,*:*,*:*]+img[36,*:*,*:*]+img[37,*:*,*:*]+img[38,*:*,*:*]
+FROM comp_cubed_64 as img
+// ["x"] comp_cubed_64 [134:140,*:*,*:*]
+SELECT img[134,*:*,*:*]+img[135,*:*,*:*]+img[136,*:*,*:*]+img[137,*:*,*:*]+img[138,*:*,*:*]+img[139,*:*,*:*]+img[140,*:*,*:*]
+FROM comp_cubed_64 as img
+// ["x"] comp_cubed_64 [116:122,*:*,*:*]
+SELECT img[116,*:*,*:*]+img[117,*:*,*:*]+img[118,*:*,*:*]+img[119,*:*,*:*]+img[120,*:*,*:*]+img[121,*:*,*:*]+img[122,*:*,*:*]
+FROM comp_cubed_64 as img
+// ["x"] comp_cubed_64 [244:250,*:*,*:*]
+SELECT img[244,*:*,*:*]+img[245,*:*,*:*]+img[246,*:*,*:*]+img[247,*:*,*:*]+img[248,*:*,*:*]+img[249,*:*,*:*]+img[250,*:*,*:*]
+FROM comp_cubed_64 as img
+// ["x"] comp_cubed_64 [182:188,*:*,*:*]
+SELECT img[182,*:*,*:*]+img[183,*:*,*:*]+img[184,*:*,*:*]+img[185,*:*,*:*]+img[186,*:*,*:*]+img[187,*:*,*:*]+img[188,*:*,*:*]
+FROM comp_cubed_64 as img
+// ["x"] comp_cubed_64 [233:239,*:*,*:*]
+SELECT img[233,*:*,*:*]+img[234,*:*,*:*]+img[235,*:*,*:*]+img[236,*:*,*:*]+img[237,*:*,*:*]+img[238,*:*,*:*]+img[239,*:*,*:*]
+FROM comp_cubed_64 as img
+// ["x"] comp_cubed_64 [134:140,*:*,*:*]
+SELECT img[134,*:*,*:*]+img[135,*:*,*:*]+img[136,*:*,*:*]+img[137,*:*,*:*]+img[138,*:*,*:*]+img[139,*:*,*:*]+img[140,*:*,*:*]
+FROM comp_cubed_64 as img
+// ["x"] comp_cubed_64 [216:222,*:*,*:*]
+SELECT img[216,*:*,*:*]+img[217,*:*,*:*]+img[218,*:*,*:*]+img[219,*:*,*:*]+img[220,*:*,*:*]+img[221,*:*,*:*]+img[222,*:*,*:*]
+FROM comp_cubed_64 as img
+// ["x"] comp_cubed_64 [176:182,*:*,*:*]
+SELECT img[176,*:*,*:*]+img[177,*:*,*:*]+img[178,*:*,*:*]+img[179,*:*,*:*]+img[180,*:*,*:*]+img[181,*:*,*:*]+img[182,*:*,*:*]
+FROM comp_cubed_64 as img
+// ["x"] comp_cubed_64 [200:206,*:*,*:*]
+SELECT img[200,*:*,*:*]+img[201,*:*,*:*]+img[202,*:*,*:*]+img[203,*:*,*:*]+img[204,*:*,*:*]+img[205,*:*,*:*]+img[206,*:*,*:*]
+FROM comp_cubed_64 as img
+// ["x"] comp_cubed_64 [140:146,*:*,*:*]
+SELECT img[140,*:*,*:*]+img[141,*:*,*:*]+img[142,*:*,*:*]+img[143,*:*,*:*]+img[144,*:*,*:*]+img[145,*:*,*:*]+img[146,*:*,*:*]
+FROM comp_cubed_64 as img
+// ["x"] comp_cubed_64 [54:60,*:*,*:*]
+SELECT img[54,*:*,*:*]+img[55,*:*,*:*]+img[56,*:*,*:*]+img[57,*:*,*:*]+img[58,*:*,*:*]+img[59,*:*,*:*]+img[60,*:*,*:*]
+FROM comp_cubed_64 as img
+// ["x"] comp_cubed_64 [94:100,*:*,*:*]
+SELECT img[94,*:*,*:*]+img[95,*:*,*:*]+img[96,*:*,*:*]+img[97,*:*,*:*]+img[98,*:*,*:*]+img[99,*:*,*:*]+img[100,*:*,*:*]
+FROM comp_cubed_64 as img
+// ["x"] comp_cubed_64 [14:20,*:*,*:*]
+SELECT img[14,*:*,*:*]+img[15,*:*,*:*]+img[16,*:*,*:*]+img[17,*:*,*:*]+img[18,*:*,*:*]+img[19,*:*,*:*]+img[20,*:*,*:*]
+FROM comp_cubed_64 as img
+// ["x"] comp_cubed_64 [211:217,*:*,*:*]
+SELECT img[211,*:*,*:*]+img[212,*:*,*:*]+img[213,*:*,*:*]+img[214,*:*,*:*]+img[215,*:*,*:*]+img[216,*:*,*:*]+img[217,*:*,*:*]
+FROM comp_cubed_64 as img
+// ["x"] comp_cubed_64 [156:162,*:*,*:*]
+SELECT img[156,*:*,*:*]+img[157,*:*,*:*]+img[158,*:*,*:*]+img[159,*:*,*:*]+img[160,*:*,*:*]+img[161,*:*,*:*]+img[162,*:*,*:*]
+FROM comp_cubed_64 as img
+// ["x"] comp_cubed_64 [196:202,*:*,*:*]
+SELECT img[196,*:*,*:*]+img[197,*:*,*:*]+img[198,*:*,*:*]+img[199,*:*,*:*]+img[200,*:*,*:*]+img[201,*:*,*:*]+img[202,*:*,*:*]
+FROM comp_cubed_64 as img
+// ["x"] comp_cubed_64 [181:187,*:*,*:*]
+SELECT img[181,*:*,*:*]+img[182,*:*,*:*]+img[183,*:*,*:*]+img[184,*:*,*:*]+img[185,*:*,*:*]+img[186,*:*,*:*]+img[187,*:*,*:*]
+FROM comp_cubed_64 as img
+// ["x"] comp_cubed_64 [80:86,*:*,*:*]
+SELECT img[80,*:*,*:*]+img[81,*:*,*:*]+img[82,*:*,*:*]+img[83,*:*,*:*]+img[84,*:*,*:*]+img[85,*:*,*:*]+img[86,*:*,*:*]
+FROM comp_cubed_64 as img
+// ["x"] comp_cubed_64 [1:7,*:*,*:*]
+SELECT img[1,*:*,*:*]+img[2,*:*,*:*]+img[3,*:*,*:*]+img[4,*:*,*:*]+img[5,*:*,*:*]+img[6,*:*,*:*]+img[7,*:*,*:*]
+FROM comp_cubed_64 as img
+// ["y"] comp_cubed_64 [*:*, 72:78, *:*]
+SELECT img[*:*,72,*:*]+img[*:*,73,*:*]+img[*:*,74,*:*]+img[*:*,75,*:*]+img[*:*,76,*:*]+img[*:*,77,*:*]+img[*:*,78,*:*]
+FROM comp_cubed_64 as img
+// ["y"] comp_cubed_64 [*:*, 211:217, *:*]
+SELECT img[*:*,211,*:*]+img[*:*,212,*:*]+img[*:*,213,*:*]+img[*:*,214,*:*]+img[*:*,215,*:*]+img[*:*,216,*:*]+img[*:*,217,*:*]
+FROM comp_cubed_64 as img
+// ["y"] comp_cubed_64 [*:*, 199:205, *:*]
+SELECT img[*:*,199,*:*]+img[*:*,200,*:*]+img[*:*,201,*:*]+img[*:*,202,*:*]+img[*:*,203,*:*]+img[*:*,204,*:*]+img[*:*,205,*:*]
+FROM comp_cubed_64 as img
+// ["y"] comp_cubed_64 [*:*, 92:98, *:*]
+SELECT img[*:*,92,*:*]+img[*:*,93,*:*]+img[*:*,94,*:*]+img[*:*,95,*:*]+img[*:*,96,*:*]+img[*:*,97,*:*]+img[*:*,98,*:*]
+FROM comp_cubed_64 as img
+// ["y"] comp_cubed_64 [*:*, 233:239, *:*]
+SELECT img[*:*,233,*:*]+img[*:*,234,*:*]+img[*:*,235,*:*]+img[*:*,236,*:*]+img[*:*,237,*:*]+img[*:*,238,*:*]+img[*:*,239,*:*]
+FROM comp_cubed_64 as img
+// ["y"] comp_cubed_64 [*:*, 201:207, *:*]
+SELECT img[*:*,201,*:*]+img[*:*,202,*:*]+img[*:*,203,*:*]+img[*:*,204,*:*]+img[*:*,205,*:*]+img[*:*,206,*:*]+img[*:*,207,*:*]
+FROM comp_cubed_64 as img
+// ["y"] comp_cubed_64 [*:*, 59:65, *:*]
+SELECT img[*:*,59,*:*]+img[*:*,60,*:*]+img[*:*,61,*:*]+img[*:*,62,*:*]+img[*:*,63,*:*]+img[*:*,64,*:*]+img[*:*,65,*:*]
+FROM comp_cubed_64 as img
+// ["y"] comp_cubed_64 [*:*, 208:214, *:*]
+SELECT img[*:*,208,*:*]+img[*:*,209,*:*]+img[*:*,210,*:*]+img[*:*,211,*:*]+img[*:*,212,*:*]+img[*:*,213,*:*]+img[*:*,214,*:*]
+FROM comp_cubed_64 as img
+// ["y"] comp_cubed_64 [*:*, 1:7, *:*]
+SELECT img[*:*,1,*:*]+img[*:*,2,*:*]+img[*:*,3,*:*]+img[*:*,4,*:*]+img[*:*,5,*:*]+img[*:*,6,*:*]+img[*:*,7,*:*]
+FROM comp_cubed_64 as img
+// ["y"] comp_cubed_64 [*:*, 4:10, *:*]
+SELECT img[*:*,4,*:*]+img[*:*,5,*:*]+img[*:*,6,*:*]+img[*:*,7,*:*]+img[*:*,8,*:*]+img[*:*,9,*:*]+img[*:*,10,*:*]
+FROM comp_cubed_64 as img
+// ["y"] comp_cubed_64 [*:*, 5:11, *:*]
+SELECT img[*:*,5,*:*]+img[*:*,6,*:*]+img[*:*,7,*:*]+img[*:*,8,*:*]+img[*:*,9,*:*]+img[*:*,10,*:*]+img[*:*,11,*:*]
+FROM comp_cubed_64 as img
+// ["y"] comp_cubed_64 [*:*, 98:104, *:*]
+SELECT img[*:*,98,*:*]+img[*:*,99,*:*]+img[*:*,100,*:*]+img[*:*,101,*:*]+img[*:*,102,*:*]+img[*:*,103,*:*]+img[*:*,104,*:*]
+FROM comp_cubed_64 as img
+// ["y"] comp_cubed_64 [*:*, 74:80, *:*]
+SELECT img[*:*,74,*:*]+img[*:*,75,*:*]+img[*:*,76,*:*]+img[*:*,77,*:*]+img[*:*,78,*:*]+img[*:*,79,*:*]+img[*:*,80,*:*]
+FROM comp_cubed_64 as img
+// ["y"] comp_cubed_64 [*:*, 49:55, *:*]
+SELECT img[*:*,49,*:*]+img[*:*,50,*:*]+img[*:*,51,*:*]+img[*:*,52,*:*]+img[*:*,53,*:*]+img[*:*,54,*:*]+img[*:*,55,*:*]
+FROM comp_cubed_64 as img
+// ["y"] comp_cubed_64 [*:*, 177:183, *:*]
+SELECT img[*:*,177,*:*]+img[*:*,178,*:*]+img[*:*,179,*:*]+img[*:*,180,*:*]+img[*:*,181,*:*]+img[*:*,182,*:*]+img[*:*,183,*:*]
+FROM comp_cubed_64 as img
+// ["y"] comp_cubed_64 [*:*, 146:152, *:*]
+SELECT img[*:*,146,*:*]+img[*:*,147,*:*]+img[*:*,148,*:*]+img[*:*,149,*:*]+img[*:*,150,*:*]+img[*:*,151,*:*]+img[*:*,152,*:*]
+FROM comp_cubed_64 as img
+// ["y"] comp_cubed_64 [*:*, 105:111, *:*]
+SELECT img[*:*,105,*:*]+img[*:*,106,*:*]+img[*:*,107,*:*]+img[*:*,108,*:*]+img[*:*,109,*:*]+img[*:*,110,*:*]+img[*:*,111,*:*]
+FROM comp_cubed_64 as img
+// ["y"] comp_cubed_64 [*:*, 46:52, *:*]
+SELECT img[*:*,46,*:*]+img[*:*,47,*:*]+img[*:*,48,*:*]+img[*:*,49,*:*]+img[*:*,50,*:*]+img[*:*,51,*:*]+img[*:*,52,*:*]
+FROM comp_cubed_64 as img
+// ["y"] comp_cubed_64 [*:*, 56:62, *:*]
+SELECT img[*:*,56,*:*]+img[*:*,57,*:*]+img[*:*,58,*:*]+img[*:*,59,*:*]+img[*:*,60,*:*]+img[*:*,61,*:*]+img[*:*,62,*:*]
+FROM comp_cubed_64 as img
+// ["y"] comp_cubed_64 [*:*, 154:160, *:*]
+SELECT img[*:*,154,*:*]+img[*:*,155,*:*]+img[*:*,156,*:*]+img[*:*,157,*:*]+img[*:*,158,*:*]+img[*:*,159,*:*]+img[*:*,160,*:*]
+FROM comp_cubed_64 as img
+// ["z"] comp_cubed_64 [*:*, *:*, 127:133]
+SELECT img[*:*,*:*,127]+img[*:*,*:*,128]+img[*:*,*:*,129]+img[*:*,*:*,130]+img[*:*,*:*,131]+img[*:*,*:*,132]+img[*:*,*:*,133]
+FROM comp_cubed_64 as img
+// ["z"] comp_cubed_64 [*:*, *:*, 79:85]
+SELECT img[*:*,*:*,79]+img[*:*,*:*,80]+img[*:*,*:*,81]+img[*:*,*:*,82]+img[*:*,*:*,83]+img[*:*,*:*,84]+img[*:*,*:*,85]
+FROM comp_cubed_64 as img
+// ["z"] comp_cubed_64 [*:*, *:*, 134:140]
+SELECT img[*:*,*:*,134]+img[*:*,*:*,135]+img[*:*,*:*,136]+img[*:*,*:*,137]+img[*:*,*:*,138]+img[*:*,*:*,139]+img[*:*,*:*,140]
+FROM comp_cubed_64 as img
+// ["z"] comp_cubed_64 [*:*, *:*, 12:18]
+SELECT img[*:*,*:*,12]+img[*:*,*:*,13]+img[*:*,*:*,14]+img[*:*,*:*,15]+img[*:*,*:*,16]+img[*:*,*:*,17]+img[*:*,*:*,18]
+FROM comp_cubed_64 as img
+// ["z"] comp_cubed_64 [*:*, *:*, 142:148]
+SELECT img[*:*,*:*,142]+img[*:*,*:*,143]+img[*:*,*:*,144]+img[*:*,*:*,145]+img[*:*,*:*,146]+img[*:*,*:*,147]+img[*:*,*:*,148]
+FROM comp_cubed_64 as img
+// ["z"] comp_cubed_64 [*:*, *:*, 128:134]
+SELECT img[*:*,*:*,128]+img[*:*,*:*,129]+img[*:*,*:*,130]+img[*:*,*:*,131]+img[*:*,*:*,132]+img[*:*,*:*,133]+img[*:*,*:*,134]
+FROM comp_cubed_64 as img
+// ["z"] comp_cubed_64 [*:*, *:*, 75:81]
+SELECT img[*:*,*:*,75]+img[*:*,*:*,76]+img[*:*,*:*,77]+img[*:*,*:*,78]+img[*:*,*:*,79]+img[*:*,*:*,80]+img[*:*,*:*,81]
+FROM comp_cubed_64 as img
+// ["z"] comp_cubed_64 [*:*, *:*, 118:124]
+SELECT img[*:*,*:*,118]+img[*:*,*:*,119]+img[*:*,*:*,120]+img[*:*,*:*,121]+img[*:*,*:*,122]+img[*:*,*:*,123]+img[*:*,*:*,124]
+FROM comp_cubed_64 as img
+// ["z"] comp_cubed_64 [*:*, *:*, 87:93]
+SELECT img[*:*,*:*,87]+img[*:*,*:*,88]+img[*:*,*:*,89]+img[*:*,*:*,90]+img[*:*,*:*,91]+img[*:*,*:*,92]+img[*:*,*:*,93]
+FROM comp_cubed_64 as img
+// ["z"] comp_cubed_64 [*:*, *:*, 23:29]
+SELECT img[*:*,*:*,23]+img[*:*,*:*,24]+img[*:*,*:*,25]+img[*:*,*:*,26]+img[*:*,*:*,27]+img[*:*,*:*,28]+img[*:*,*:*,29]
+FROM comp_cubed_64 as img
+// ["z"] comp_cubed_64 [*:*, *:*, 69:75]
+SELECT img[*:*,*:*,69]+img[*:*,*:*,70]+img[*:*,*:*,71]+img[*:*,*:*,72]+img[*:*,*:*,73]+img[*:*,*:*,74]+img[*:*,*:*,75]
+FROM comp_cubed_64 as img
+// ["z"] comp_cubed_64 [*:*, *:*, 146:152]
+SELECT img[*:*,*:*,146]+img[*:*,*:*,147]+img[*:*,*:*,148]+img[*:*,*:*,149]+img[*:*,*:*,150]+img[*:*,*:*,151]+img[*:*,*:*,152]
+FROM comp_cubed_64 as img
+// ["z"] comp_cubed_64 [*:*, *:*, 99:105]
+SELECT img[*:*,*:*,99]+img[*:*,*:*,100]+img[*:*,*:*,101]+img[*:*,*:*,102]+img[*:*,*:*,103]+img[*:*,*:*,104]+img[*:*,*:*,105]
+FROM comp_cubed_64 as img
+// ["z"] comp_cubed_64 [*:*, *:*, 135:141]
+SELECT img[*:*,*:*,135]+img[*:*,*:*,136]+img[*:*,*:*,137]+img[*:*,*:*,138]+img[*:*,*:*,139]+img[*:*,*:*,140]+img[*:*,*:*,141]
+FROM comp_cubed_64 as img
+// ["z"] comp_cubed_64 [*:*, *:*, 76:82]
+SELECT img[*:*,*:*,76]+img[*:*,*:*,77]+img[*:*,*:*,78]+img[*:*,*:*,79]+img[*:*,*:*,80]+img[*:*,*:*,81]+img[*:*,*:*,82]
+FROM comp_cubed_64 as img
+// ["z"] comp_cubed_64 [*:*, *:*, 26:32]
+SELECT img[*:*,*:*,26]+img[*:*,*:*,27]+img[*:*,*:*,28]+img[*:*,*:*,29]+img[*:*,*:*,30]+img[*:*,*:*,31]+img[*:*,*:*,32]
+FROM comp_cubed_64 as img
+// ["z"] comp_cubed_64 [*:*, *:*, 56:62]
+SELECT img[*:*,*:*,56]+img[*:*,*:*,57]+img[*:*,*:*,58]+img[*:*,*:*,59]+img[*:*,*:*,60]+img[*:*,*:*,61]+img[*:*,*:*,62]
+FROM comp_cubed_64 as img
+// ["z"] comp_cubed_64 [*:*, *:*, 94:100]
+SELECT img[*:*,*:*,94]+img[*:*,*:*,95]+img[*:*,*:*,96]+img[*:*,*:*,97]+img[*:*,*:*,98]+img[*:*,*:*,99]+img[*:*,*:*,100]
+FROM comp_cubed_64 as img
+// ["z"] comp_cubed_64 [*:*, *:*, 13:19]
+SELECT img[*:*,*:*,13]+img[*:*,*:*,14]+img[*:*,*:*,15]+img[*:*,*:*,16]+img[*:*,*:*,17]+img[*:*,*:*,18]+img[*:*,*:*,19]
+FROM comp_cubed_64 as img
+// ["z"] comp_cubed_64 [*:*, *:*, 22:28]
+SELECT img[*:*,*:*,22]+img[*:*,*:*,23]+img[*:*,*:*,24]+img[*:*,*:*,25]+img[*:*,*:*,26]+img[*:*,*:*,27]+img[*:*,*:*,28]
+FROM comp_cubed_64 as img
diff --git a/rasodmg/test/croll_sliced.ql b/rasodmg/test/croll_sliced.ql
new file mode 100644
index 0000000..90ab35c
--- /dev/null
+++ b/rasodmg/test/croll_sliced.ql
@@ -0,0 +1,180 @@
+// ["x"] comp_sliced [2:8,*:*,*:*]
+SELECT img[2,*:*,*:*]+img[3,*:*,*:*]+img[4,*:*,*:*]+img[5,*:*,*:*]+img[6,*:*,*:*]+img[7,*:*,*:*]+img[8,*:*,*:*]
+FROM comp_sliced as img
+// ["x"] comp_sliced [86:92,*:*,*:*]
+SELECT img[86,*:*,*:*]+img[87,*:*,*:*]+img[88,*:*,*:*]+img[89,*:*,*:*]+img[90,*:*,*:*]+img[91,*:*,*:*]+img[92,*:*,*:*]
+FROM comp_sliced as img
+// ["x"] comp_sliced [2:8,*:*,*:*]
+SELECT img[2,*:*,*:*]+img[3,*:*,*:*]+img[4,*:*,*:*]+img[5,*:*,*:*]+img[6,*:*,*:*]+img[7,*:*,*:*]+img[8,*:*,*:*]
+FROM comp_sliced as img
+// ["x"] comp_sliced [104:110,*:*,*:*]
+SELECT img[104,*:*,*:*]+img[105,*:*,*:*]+img[106,*:*,*:*]+img[107,*:*,*:*]+img[108,*:*,*:*]+img[109,*:*,*:*]+img[110,*:*,*:*]
+FROM comp_sliced as img
+// ["x"] comp_sliced [236:242,*:*,*:*]
+SELECT img[236,*:*,*:*]+img[237,*:*,*:*]+img[238,*:*,*:*]+img[239,*:*,*:*]+img[240,*:*,*:*]+img[241,*:*,*:*]+img[242,*:*,*:*]
+FROM comp_sliced as img
+// ["x"] comp_sliced [145:151,*:*,*:*]
+SELECT img[145,*:*,*:*]+img[146,*:*,*:*]+img[147,*:*,*:*]+img[148,*:*,*:*]+img[149,*:*,*:*]+img[150,*:*,*:*]+img[151,*:*,*:*]
+FROM comp_sliced as img
+// ["x"] comp_sliced [242:248,*:*,*:*]
+SELECT img[242,*:*,*:*]+img[243,*:*,*:*]+img[244,*:*,*:*]+img[245,*:*,*:*]+img[246,*:*,*:*]+img[247,*:*,*:*]+img[248,*:*,*:*]
+FROM comp_sliced as img
+// ["x"] comp_sliced [236:242,*:*,*:*]
+SELECT img[236,*:*,*:*]+img[237,*:*,*:*]+img[238,*:*,*:*]+img[239,*:*,*:*]+img[240,*:*,*:*]+img[241,*:*,*:*]+img[242,*:*,*:*]
+FROM comp_sliced as img
+// ["x"] comp_sliced [246:252,*:*,*:*]
+SELECT img[246,*:*,*:*]+img[247,*:*,*:*]+img[248,*:*,*:*]+img[249,*:*,*:*]+img[250,*:*,*:*]+img[251,*:*,*:*]+img[252,*:*,*:*]
+FROM comp_sliced as img
+// ["x"] comp_sliced [189:195,*:*,*:*]
+SELECT img[189,*:*,*:*]+img[190,*:*,*:*]+img[191,*:*,*:*]+img[192,*:*,*:*]+img[193,*:*,*:*]+img[194,*:*,*:*]+img[195,*:*,*:*]
+FROM comp_sliced as img
+// ["x"] comp_sliced [136:142,*:*,*:*]
+SELECT img[136,*:*,*:*]+img[137,*:*,*:*]+img[138,*:*,*:*]+img[139,*:*,*:*]+img[140,*:*,*:*]+img[141,*:*,*:*]+img[142,*:*,*:*]
+FROM comp_sliced as img
+// ["x"] comp_sliced [100:106,*:*,*:*]
+SELECT img[100,*:*,*:*]+img[101,*:*,*:*]+img[102,*:*,*:*]+img[103,*:*,*:*]+img[104,*:*,*:*]+img[105,*:*,*:*]+img[106,*:*,*:*]
+FROM comp_sliced as img
+// ["x"] comp_sliced [49:55,*:*,*:*]
+SELECT img[49,*:*,*:*]+img[50,*:*,*:*]+img[51,*:*,*:*]+img[52,*:*,*:*]+img[53,*:*,*:*]+img[54,*:*,*:*]+img[55,*:*,*:*]
+FROM comp_sliced as img
+// ["x"] comp_sliced [101:107,*:*,*:*]
+SELECT img[101,*:*,*:*]+img[102,*:*,*:*]+img[103,*:*,*:*]+img[104,*:*,*:*]+img[105,*:*,*:*]+img[106,*:*,*:*]+img[107,*:*,*:*]
+FROM comp_sliced as img
+// ["x"] comp_sliced [238:244,*:*,*:*]
+SELECT img[238,*:*,*:*]+img[239,*:*,*:*]+img[240,*:*,*:*]+img[241,*:*,*:*]+img[242,*:*,*:*]+img[243,*:*,*:*]+img[244,*:*,*:*]
+FROM comp_sliced as img
+// ["x"] comp_sliced [56:62,*:*,*:*]
+SELECT img[56,*:*,*:*]+img[57,*:*,*:*]+img[58,*:*,*:*]+img[59,*:*,*:*]+img[60,*:*,*:*]+img[61,*:*,*:*]+img[62,*:*,*:*]
+FROM comp_sliced as img
+// ["x"] comp_sliced [57:63,*:*,*:*]
+SELECT img[57,*:*,*:*]+img[58,*:*,*:*]+img[59,*:*,*:*]+img[60,*:*,*:*]+img[61,*:*,*:*]+img[62,*:*,*:*]+img[63,*:*,*:*]
+FROM comp_sliced as img
+// ["x"] comp_sliced [146:152,*:*,*:*]
+SELECT img[146,*:*,*:*]+img[147,*:*,*:*]+img[148,*:*,*:*]+img[149,*:*,*:*]+img[150,*:*,*:*]+img[151,*:*,*:*]+img[152,*:*,*:*]
+FROM comp_sliced as img
+// ["x"] comp_sliced [212:218,*:*,*:*]
+SELECT img[212,*:*,*:*]+img[213,*:*,*:*]+img[214,*:*,*:*]+img[215,*:*,*:*]+img[216,*:*,*:*]+img[217,*:*,*:*]+img[218,*:*,*:*]
+FROM comp_sliced as img
+// ["x"] comp_sliced [172:178,*:*,*:*]
+SELECT img[172,*:*,*:*]+img[173,*:*,*:*]+img[174,*:*,*:*]+img[175,*:*,*:*]+img[176,*:*,*:*]+img[177,*:*,*:*]+img[178,*:*,*:*]
+FROM comp_sliced as img
+// ["y"] comp_sliced [*:*, 57:63, *:*]
+SELECT img[*:*,57,*:*]+img[*:*,58,*:*]+img[*:*,59,*:*]+img[*:*,60,*:*]+img[*:*,61,*:*]+img[*:*,62,*:*]+img[*:*,63,*:*]
+FROM comp_sliced as img
+// ["y"] comp_sliced [*:*, 225:231, *:*]
+SELECT img[*:*,225,*:*]+img[*:*,226,*:*]+img[*:*,227,*:*]+img[*:*,228,*:*]+img[*:*,229,*:*]+img[*:*,230,*:*]+img[*:*,231,*:*]
+FROM comp_sliced as img
+// ["y"] comp_sliced [*:*, 96:102, *:*]
+SELECT img[*:*,96,*:*]+img[*:*,97,*:*]+img[*:*,98,*:*]+img[*:*,99,*:*]+img[*:*,100,*:*]+img[*:*,101,*:*]+img[*:*,102,*:*]
+FROM comp_sliced as img
+// ["y"] comp_sliced [*:*, 3:9, *:*]
+SELECT img[*:*,3,*:*]+img[*:*,4,*:*]+img[*:*,5,*:*]+img[*:*,6,*:*]+img[*:*,7,*:*]+img[*:*,8,*:*]+img[*:*,9,*:*]
+FROM comp_sliced as img
+// ["y"] comp_sliced [*:*, 60:66, *:*]
+SELECT img[*:*,60,*:*]+img[*:*,61,*:*]+img[*:*,62,*:*]+img[*:*,63,*:*]+img[*:*,64,*:*]+img[*:*,65,*:*]+img[*:*,66,*:*]
+FROM comp_sliced as img
+// ["y"] comp_sliced [*:*, 133:139, *:*]
+SELECT img[*:*,133,*:*]+img[*:*,134,*:*]+img[*:*,135,*:*]+img[*:*,136,*:*]+img[*:*,137,*:*]+img[*:*,138,*:*]+img[*:*,139,*:*]
+FROM comp_sliced as img
+// ["y"] comp_sliced [*:*, 62:68, *:*]
+SELECT img[*:*,62,*:*]+img[*:*,63,*:*]+img[*:*,64,*:*]+img[*:*,65,*:*]+img[*:*,66,*:*]+img[*:*,67,*:*]+img[*:*,68,*:*]
+FROM comp_sliced as img
+// ["y"] comp_sliced [*:*, 112:118, *:*]
+SELECT img[*:*,112,*:*]+img[*:*,113,*:*]+img[*:*,114,*:*]+img[*:*,115,*:*]+img[*:*,116,*:*]+img[*:*,117,*:*]+img[*:*,118,*:*]
+FROM comp_sliced as img
+// ["y"] comp_sliced [*:*, 206:212, *:*]
+SELECT img[*:*,206,*:*]+img[*:*,207,*:*]+img[*:*,208,*:*]+img[*:*,209,*:*]+img[*:*,210,*:*]+img[*:*,211,*:*]+img[*:*,212,*:*]
+FROM comp_sliced as img
+// ["y"] comp_sliced [*:*, 136:142, *:*]
+SELECT img[*:*,136,*:*]+img[*:*,137,*:*]+img[*:*,138,*:*]+img[*:*,139,*:*]+img[*:*,140,*:*]+img[*:*,141,*:*]+img[*:*,142,*:*]
+FROM comp_sliced as img
+// ["y"] comp_sliced [*:*, 22:28, *:*]
+SELECT img[*:*,22,*:*]+img[*:*,23,*:*]+img[*:*,24,*:*]+img[*:*,25,*:*]+img[*:*,26,*:*]+img[*:*,27,*:*]+img[*:*,28,*:*]
+FROM comp_sliced as img
+// ["y"] comp_sliced [*:*, 121:127, *:*]
+SELECT img[*:*,121,*:*]+img[*:*,122,*:*]+img[*:*,123,*:*]+img[*:*,124,*:*]+img[*:*,125,*:*]+img[*:*,126,*:*]+img[*:*,127,*:*]
+FROM comp_sliced as img
+// ["y"] comp_sliced [*:*, 42:48, *:*]
+SELECT img[*:*,42,*:*]+img[*:*,43,*:*]+img[*:*,44,*:*]+img[*:*,45,*:*]+img[*:*,46,*:*]+img[*:*,47,*:*]+img[*:*,48,*:*]
+FROM comp_sliced as img
+// ["y"] comp_sliced [*:*, 110:116, *:*]
+SELECT img[*:*,110,*:*]+img[*:*,111,*:*]+img[*:*,112,*:*]+img[*:*,113,*:*]+img[*:*,114,*:*]+img[*:*,115,*:*]+img[*:*,116,*:*]
+FROM comp_sliced as img
+// ["y"] comp_sliced [*:*, 75:81, *:*]
+SELECT img[*:*,75,*:*]+img[*:*,76,*:*]+img[*:*,77,*:*]+img[*:*,78,*:*]+img[*:*,79,*:*]+img[*:*,80,*:*]+img[*:*,81,*:*]
+FROM comp_sliced as img
+// ["y"] comp_sliced [*:*, 162:168, *:*]
+SELECT img[*:*,162,*:*]+img[*:*,163,*:*]+img[*:*,164,*:*]+img[*:*,165,*:*]+img[*:*,166,*:*]+img[*:*,167,*:*]+img[*:*,168,*:*]
+FROM comp_sliced as img
+// ["y"] comp_sliced [*:*, 80:86, *:*]
+SELECT img[*:*,80,*:*]+img[*:*,81,*:*]+img[*:*,82,*:*]+img[*:*,83,*:*]+img[*:*,84,*:*]+img[*:*,85,*:*]+img[*:*,86,*:*]
+FROM comp_sliced as img
+// ["y"] comp_sliced [*:*, 50:56, *:*]
+SELECT img[*:*,50,*:*]+img[*:*,51,*:*]+img[*:*,52,*:*]+img[*:*,53,*:*]+img[*:*,54,*:*]+img[*:*,55,*:*]+img[*:*,56,*:*]
+FROM comp_sliced as img
+// ["y"] comp_sliced [*:*, 174:180, *:*]
+SELECT img[*:*,174,*:*]+img[*:*,175,*:*]+img[*:*,176,*:*]+img[*:*,177,*:*]+img[*:*,178,*:*]+img[*:*,179,*:*]+img[*:*,180,*:*]
+FROM comp_sliced as img
+// ["y"] comp_sliced [*:*, 33:39, *:*]
+SELECT img[*:*,33,*:*]+img[*:*,34,*:*]+img[*:*,35,*:*]+img[*:*,36,*:*]+img[*:*,37,*:*]+img[*:*,38,*:*]+img[*:*,39,*:*]
+FROM comp_sliced as img
+// ["z"] comp_sliced [*:*, *:*, 125:131]
+SELECT img[*:*,*:*,125]+img[*:*,*:*,126]+img[*:*,*:*,127]+img[*:*,*:*,128]+img[*:*,*:*,129]+img[*:*,*:*,130]+img[*:*,*:*,131]
+FROM comp_sliced as img
+// ["z"] comp_sliced [*:*, *:*, 99:105]
+SELECT img[*:*,*:*,99]+img[*:*,*:*,100]+img[*:*,*:*,101]+img[*:*,*:*,102]+img[*:*,*:*,103]+img[*:*,*:*,104]+img[*:*,*:*,105]
+FROM comp_sliced as img
+// ["z"] comp_sliced [*:*, *:*, 138:144]
+SELECT img[*:*,*:*,138]+img[*:*,*:*,139]+img[*:*,*:*,140]+img[*:*,*:*,141]+img[*:*,*:*,142]+img[*:*,*:*,143]+img[*:*,*:*,144]
+FROM comp_sliced as img
+// ["z"] comp_sliced [*:*, *:*, 102:108]
+SELECT img[*:*,*:*,102]+img[*:*,*:*,103]+img[*:*,*:*,104]+img[*:*,*:*,105]+img[*:*,*:*,106]+img[*:*,*:*,107]+img[*:*,*:*,108]
+FROM comp_sliced as img
+// ["z"] comp_sliced [*:*, *:*, 89:95]
+SELECT img[*:*,*:*,89]+img[*:*,*:*,90]+img[*:*,*:*,91]+img[*:*,*:*,92]+img[*:*,*:*,93]+img[*:*,*:*,94]+img[*:*,*:*,95]
+FROM comp_sliced as img
+// ["z"] comp_sliced [*:*, *:*, 106:112]
+SELECT img[*:*,*:*,106]+img[*:*,*:*,107]+img[*:*,*:*,108]+img[*:*,*:*,109]+img[*:*,*:*,110]+img[*:*,*:*,111]+img[*:*,*:*,112]
+FROM comp_sliced as img
+// ["z"] comp_sliced [*:*, *:*, 38:44]
+SELECT img[*:*,*:*,38]+img[*:*,*:*,39]+img[*:*,*:*,40]+img[*:*,*:*,41]+img[*:*,*:*,42]+img[*:*,*:*,43]+img[*:*,*:*,44]
+FROM comp_sliced as img
+// ["z"] comp_sliced [*:*, *:*, 11:17]
+SELECT img[*:*,*:*,11]+img[*:*,*:*,12]+img[*:*,*:*,13]+img[*:*,*:*,14]+img[*:*,*:*,15]+img[*:*,*:*,16]+img[*:*,*:*,17]
+FROM comp_sliced as img
+// ["z"] comp_sliced [*:*, *:*, 112:118]
+SELECT img[*:*,*:*,112]+img[*:*,*:*,113]+img[*:*,*:*,114]+img[*:*,*:*,115]+img[*:*,*:*,116]+img[*:*,*:*,117]+img[*:*,*:*,118]
+FROM comp_sliced as img
+// ["z"] comp_sliced [*:*, *:*, 127:133]
+SELECT img[*:*,*:*,127]+img[*:*,*:*,128]+img[*:*,*:*,129]+img[*:*,*:*,130]+img[*:*,*:*,131]+img[*:*,*:*,132]+img[*:*,*:*,133]
+FROM comp_sliced as img
+// ["z"] comp_sliced [*:*, *:*, 71:77]
+SELECT img[*:*,*:*,71]+img[*:*,*:*,72]+img[*:*,*:*,73]+img[*:*,*:*,74]+img[*:*,*:*,75]+img[*:*,*:*,76]+img[*:*,*:*,77]
+FROM comp_sliced as img
+// ["z"] comp_sliced [*:*, *:*, 57:63]
+SELECT img[*:*,*:*,57]+img[*:*,*:*,58]+img[*:*,*:*,59]+img[*:*,*:*,60]+img[*:*,*:*,61]+img[*:*,*:*,62]+img[*:*,*:*,63]
+FROM comp_sliced as img
+// ["z"] comp_sliced [*:*, *:*, 144:150]
+SELECT img[*:*,*:*,144]+img[*:*,*:*,145]+img[*:*,*:*,146]+img[*:*,*:*,147]+img[*:*,*:*,148]+img[*:*,*:*,149]+img[*:*,*:*,150]
+FROM comp_sliced as img
+// ["z"] comp_sliced [*:*, *:*, 130:136]
+SELECT img[*:*,*:*,130]+img[*:*,*:*,131]+img[*:*,*:*,132]+img[*:*,*:*,133]+img[*:*,*:*,134]+img[*:*,*:*,135]+img[*:*,*:*,136]
+FROM comp_sliced as img
+// ["z"] comp_sliced [*:*, *:*, 101:107]
+SELECT img[*:*,*:*,101]+img[*:*,*:*,102]+img[*:*,*:*,103]+img[*:*,*:*,104]+img[*:*,*:*,105]+img[*:*,*:*,106]+img[*:*,*:*,107]
+FROM comp_sliced as img
+// ["z"] comp_sliced [*:*, *:*, 104:110]
+SELECT img[*:*,*:*,104]+img[*:*,*:*,105]+img[*:*,*:*,106]+img[*:*,*:*,107]+img[*:*,*:*,108]+img[*:*,*:*,109]+img[*:*,*:*,110]
+FROM comp_sliced as img
+// ["z"] comp_sliced [*:*, *:*, 116:122]
+SELECT img[*:*,*:*,116]+img[*:*,*:*,117]+img[*:*,*:*,118]+img[*:*,*:*,119]+img[*:*,*:*,120]+img[*:*,*:*,121]+img[*:*,*:*,122]
+FROM comp_sliced as img
+// ["z"] comp_sliced [*:*, *:*, 12:18]
+SELECT img[*:*,*:*,12]+img[*:*,*:*,13]+img[*:*,*:*,14]+img[*:*,*:*,15]+img[*:*,*:*,16]+img[*:*,*:*,17]+img[*:*,*:*,18]
+FROM comp_sliced as img
+// ["z"] comp_sliced [*:*, *:*, 86:92]
+SELECT img[*:*,*:*,86]+img[*:*,*:*,87]+img[*:*,*:*,88]+img[*:*,*:*,89]+img[*:*,*:*,90]+img[*:*,*:*,91]+img[*:*,*:*,92]
+FROM comp_sliced as img
+// ["z"] comp_sliced [*:*, *:*, 44:50]
+SELECT img[*:*,*:*,44]+img[*:*,*:*,45]+img[*:*,*:*,46]+img[*:*,*:*,47]+img[*:*,*:*,48]+img[*:*,*:*,49]+img[*:*,*:*,50]
+FROM comp_sliced as img
diff --git a/rasodmg/test/csel_16.ql b/rasodmg/test/csel_16.ql
new file mode 100644
index 0000000..95399ed
--- /dev/null
+++ b/rasodmg/test/csel_16.ql
@@ -0,0 +1,43 @@
+// This query tests different selectivities a query box starting at
+// the origin on comp_cubed_16.
+
+// [0.5] cubed_16, selectivity 0,5%
+
+select img[0:44,0:44,0:26]
+from comp_cubed_16 as img
+
+// [1] cubed_16, selectivity 1%
+
+select img[0:55,0:55,0:33]
+from comp_cubed_16 as img
+
+// [2] cubed_16, selectivity 2%
+
+select img[0:69,0:69,0:42]
+from comp_cubed_16 as img
+
+// [5] cubed_16, selectivity 5%
+
+select img[0:94,0:94,0:56]
+from comp_cubed_16 as img
+
+// [10] cubed_16, selectivity 10%
+
+select img[0:118,0:118,0:71]
+from comp_cubed_16 as img
+
+// [20] cubed_16, selectivity 0%
+
+select img[0:149,0:149,0:89]
+from comp_cubed_16 as img
+
+// [50] cubed_16, selectivity 50%
+
+select img[0:202,0:202,0:121]
+from comp_cubed_16 as img
+
+// [100] cubed_16, selectivity 100%
+
+select img[0:255,0:255,0:153]
+from comp_cubed_16 as img
+
diff --git a/rasodmg/test/csel_32.ql b/rasodmg/test/csel_32.ql
new file mode 100644
index 0000000..aa3466c
--- /dev/null
+++ b/rasodmg/test/csel_32.ql
@@ -0,0 +1,43 @@
+// This query tests different selectivities a query box starting at
+// the origin on comp_cubed.
+
+// [0.5] cubed, selectivity 0,5%
+
+select img[0:44,0:44,0:26]
+from comp_cubed as img
+
+// [1] cubed, selectivity 1%
+
+select img[0:55,0:55,0:33]
+from comp_cubed as img
+
+// [2] cubed, selectivity 2%
+
+select img[0:69,0:69,0:42]
+from comp_cubed as img
+
+// [5] cubed, selectivity 5%
+
+select img[0:94,0:94,0:56]
+from comp_cubed as img
+
+// [10] cubed, selectivity 10%
+
+select img[0:118,0:118,0:71]
+from comp_cubed as img
+
+// [20] cubed, selectivity 0%
+
+select img[0:149,0:149,0:89]
+from comp_cubed as img
+
+// [50] cubed, selectivity 50%
+
+select img[0:202,0:202,0:121]
+from comp_cubed as img
+
+// [100] cubed, selectivity 100%
+
+select img[0:255,0:255,0:153]
+from comp_cubed as img
+
diff --git a/rasodmg/test/csel_64.ql b/rasodmg/test/csel_64.ql
new file mode 100644
index 0000000..c81079b
--- /dev/null
+++ b/rasodmg/test/csel_64.ql
@@ -0,0 +1,43 @@
+// This query tests different selectivities a query box starting at
+// the origin on comp_cubed_64.
+
+// [0.5] cubed_64, selectivity 0,5%
+
+select img[0:44,0:44,0:26]
+from comp_cubed_64 as img
+
+// [1] cubed_64, selectivity 1%
+
+select img[0:55,0:55,0:33]
+from comp_cubed_64 as img
+
+// [2] cubed_64, selectivity 2%
+
+select img[0:69,0:69,0:42]
+from comp_cubed_64 as img
+
+// [5] cubed_64, selectivity 5%
+
+select img[0:94,0:94,0:56]
+from comp_cubed_64 as img
+
+// [10] cubed_64, selectivity 10%
+
+select img[0:118,0:118,0:71]
+from comp_cubed_64 as img
+
+// [20] cubed_64, selectivity 0%
+
+select img[0:149,0:149,0:89]
+from comp_cubed_64 as img
+
+// [50] cubed_64, selectivity 50%
+
+select img[0:202,0:202,0:121]
+from comp_cubed_64 as img
+
+// [100] cubed_64, selectivity 100%
+
+select img[0:255,0:255,0:153]
+from comp_cubed_64 as img
+
diff --git a/rasodmg/test/csel_sliced.ql b/rasodmg/test/csel_sliced.ql
new file mode 100644
index 0000000..f3d9a0b
--- /dev/null
+++ b/rasodmg/test/csel_sliced.ql
@@ -0,0 +1,43 @@
+// This query tests different selectivities a query box starting at
+// the origin on comp_sliced.
+
+// [0.5] sliced, selectivity 0,5%
+
+select img[0:44,0:44,0:26]
+from comp_sliced as img
+
+// [1] sliced, selectivity 1%
+
+select img[0:55,0:55,0:33]
+from comp_sliced as img
+
+// [2] sliced, selectivity 2%
+
+select img[0:69,0:69,0:42]
+from comp_sliced as img
+
+// [5] sliced, selectivity 5%
+
+select img[0:94,0:94,0:56]
+from comp_sliced as img
+
+// [10] sliced, selectivity 10%
+
+select img[0:118,0:118,0:71]
+from comp_sliced as img
+
+// [20] sliced, selectivity 0%
+
+select img[0:149,0:149,0:89]
+from comp_sliced as img
+
+// [50] sliced, selectivity 50%
+
+select img[0:202,0:202,0:121]
+from comp_sliced as img
+
+// [100] sliced, selectivity 100%
+
+select img[0:255,0:255,0:153]
+from comp_sliced as img
+
diff --git a/rasodmg/test/defconv.cc b/rasodmg/test/defconv.cc
new file mode 100644
index 0000000..feee2dc
--- /dev/null
+++ b/rasodmg/test/defconv.cc
@@ -0,0 +1,598 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * defconv.cc
+ *
+ * Covert the DEF source file to another DEF destination file.
+ * Returns 0 for succes, otherwise 1.
+ *
+ * Parameters:
+ *
+ * --inputfilename <src-file>
+ * the filename of the src file, mandatory
+ * --outputfilename <dest-file>
+ * the filename of the dest file, mandatory
+ *
+ * --inputformat name
+ * name of DEF fromat(see data_foramat from mddtypes.hh)
+ * --inputformatparams params
+ * params used by convertFrom methods(see the heder file for you DEF from conversion)
+ * --outputformat name
+ * name of DEF fromat(see data_foramat from mddtypes.hh)
+ * --outputformatparams params
+ * params used by convertFrom methods(see the heder file for you DEF from conversion)
+ *
+ * --help
+ * print usage and exit
+ */
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#ifdef __GNUG__
+#include "raslib/template_inst.hh"
+#endif
+#endif
+
+#include "defutil.hh"
+#include "raslib/miter.hh"
+
+//program data
+const char* paramPrgHelp="--help";
+bool defPrgHelp=false;
+char* prgHelp=NULL;
+
+const char* paramSrcFileName="--srcfilename";
+bool defSrcFileName=false;
+char* srcFileName=NULL;
+
+const char* paramSrcFormat="--srcformat";
+bool defSrcFormat=false;
+char* srcFormatc=NULL;
+r_Data_Format srcFormat=r_Array;
+char *srcIvc=NULL, *srcTypec=NULL;
+r_Minterval srcIv;
+r_Type* srcType=NULL;
+
+const char* paramSrcFormatParams="--srcformatparams";
+bool defSrcFormatParams=false;
+char *srcFormatParams=NULL;
+
+const char* paramDestFileName="--destfilename";
+bool defDestFileName=false;
+char *destFileName=NULL;
+
+const char* paramDestFormat="--destformat";
+bool defDestFormat=false;
+char* destFormatc=NULL;
+r_Data_Format destFormat=r_Array;
+char *destIvc=NULL, *destTypec=NULL;
+r_Minterval destIv;
+r_Type* destType=NULL;
+
+const char* paramDestFormatParams="--destformatparams";
+bool defDestFormatParams=false;
+char *destFormatParams=NULL;
+
+//data used to parase formatparams for format Array
+const char* fpDomain="domain";
+const char* fpType="type";
+
+//structures used for parseParam
+const int paramsNo=7;
+
+const char *paramsName[paramsNo]={ paramPrgHelp, paramSrcFileName, paramSrcFormat, paramSrcFormatParams,
+ paramDestFileName, paramDestFormat, paramDestFormatParams};
+
+bool *paramsPresent[paramsNo]={ &defPrgHelp, &defSrcFileName, &defSrcFormat, &defSrcFormatParams,
+ &defDestFileName, &defDestFormat, &defDestFormatParams};
+
+char **paramsValue[paramsNo]={ &prgHelp, &srcFileName, &srcFormatc, &srcFormatParams,
+ &destFileName, &destFormatc, &destFormatParams};
+
+void printStatus()
+{
+ cout << "defdiff parameters list:" << endl;
+ for (int i=0; i<paramsNo; i++)
+ cout << "--Name='" << paramsName[i]
+ << "' Present=" << ((*paramsPresent[i])? "true": "false")
+ << " Value='" << *paramsValue[i] << "'" << endl;
+}
+
+void printUsage()
+{
+ char* fileNameSrc="test.bmp";
+ char* fileNameDest="test.tiff";
+
+ cout << "defconv v 0.1 - RasDaMan Data Exchange Format Convertor Utility" << endl;
+ cout << "Description: Returns " << EXIT_SUCCESS << " for succes, otherwise " << EXIT_FAILURE << endl;
+ cout << "For " << paramSrcFormat << "/" << paramDestFormat << " Array you have to specify the "
+ << paramSrcFormatParams << "/" << paramDestFormatParams << " as following:" << endl;
+ cout << "\"" << fpDomain << "=<domain_str>," << fpType << "=<type_str>\" (e.g. \""
+ << fpDomain << "=\"[0:477,0:464]\"," << fpType << "=char\")" << endl;
+ cout << "Usage options:" << endl;
+ cout << " " << paramSrcFileName << " <src-file> ... the filename used as src mandatory" << endl;
+ cout << " " << paramSrcFormat << " name ... name of DEF fromat(see data_foramat from mddtypes.hh)," << endl;
+ cout << " default Array" << endl;
+ cout << " " << paramSrcFormatParams << " params ... params used by convertFrom methods(see the header file" << endl;
+ cout << " for you DEF from conversion), default NULL" << endl;
+ cout << " " << paramDestFileName << " <dest-file> ... the filename used as dest mandatory" << endl;
+ cout << " " << paramDestFormat << " name ... name of DEF fromat(see data_foramat from mddtypes.hh)," << endl;
+ cout << " default Array" << endl;
+ cout << " " << paramDestFormatParams << " params ... params used by convertFrom methods(see the header file" << endl;
+ cout << " for you DEF from conversion), default NULL" << endl;
+ cout << " " << paramPrgHelp << " ... this help" << endl;
+ cout << "For example:" << endl;
+ cout << "defconv " << paramSrcFileName << " " << fileNameSrc << " " << paramSrcFormat << " " << format_name_bmp <<" "
+ << paramDestFileName << " " << fileNameDest << " " << paramDestFormat <<" " << format_name_tiff << endl;
+ cout << "Report bugs to liviu.coman@active­knowledge.com" << endl;
+
+}
+
+int checkParam(int& paramIndex, char** param)
+{
+ int i=0;
+ while(i<paramsNo)
+ {
+ if(!strcmp(param[paramIndex], paramsName[i]))
+ break;
+ i++;
+ }
+
+ if(i==paramsNo)
+ {
+ cout << "checkParam(...) error processing parameters: parameter "
+ << param[paramIndex] << " is unknown!" << endl;
+ return EXIT_FAILURE;
+ }
+ if(*paramsPresent[i])
+ {
+ cout << "checkParam(...) error processing parameters: parameter "
+ << param[paramIndex] << " is present more than once!" << endl;
+ return EXIT_FAILURE;
+ }
+
+ if(paramsName[i]!=paramPrgHelp)
+ {
+ *paramsPresent[i]=true;
+ paramIndex++;
+ *paramsValue[i]=param[paramIndex];
+ }
+ else
+ *paramsPresent[i]=true;
+
+ return EXIT_SUCCESS;
+}
+
+int parseParams(int argc, char** argv)
+{
+ int argIndex=0;
+ if (argc==1)
+ {
+ cout << "parseParams(...) parameters " << paramSrcFileName << " <src-file> and "
+ << paramDestFileName << " <dest-file> are mandatatory!" << endl;
+ return EXIT_FAILURE;
+ }
+ else
+ {
+ argIndex=1;
+ while(argIndex<argc)
+ {
+ if(checkParam(argIndex, argv)!=EXIT_SUCCESS)
+ break;
+ argIndex++;
+ }
+ if(argIndex<argc)
+ {
+ //error while parsing parameters
+ return EXIT_FAILURE;
+ }
+
+ //check rule
+ if((defSrcFileName && defDestFileName) || (defPrgHelp))
+ return EXIT_SUCCESS;
+ else
+ {
+ cout << "parseParams(...) parameters " << paramSrcFileName << " <src-file> and "
+ << paramDestFileName << " <dest-file> are mandatatory!" << endl;
+ return EXIT_FAILURE;
+ }
+ }
+}
+
+int validateParams()
+{
+
+ //check srcformat
+ if(defSrcFormat)
+ {
+ srcFormat = get_data_format_from_name(srcFormatc);
+ if((srcFormat!=r_Array) &&
+ (!r_Convertor_Factory::is_supported(srcFormat)))
+ {
+ cout << "convertDEFs(...) conversion " << srcFormatc << " not supported" << endl;
+ return EXIT_FAILURE;
+ }
+ }
+
+ //check destformat
+ if(defDestFormat)
+ {
+ destFormat = get_data_format_from_name(destFormatc);
+ if((destFormat!=r_Array) &&
+ (!r_Convertor_Factory::is_supported(destFormat)))
+ {
+ cout << "convertDEFs(...) conversion " << destFormatc << " not supported" << endl;
+ return EXIT_FAILURE;
+ }
+ }
+
+ //check srcFormatParams if srcFormat=r_Array
+ if(srcFormat == r_Array)
+ {
+ if(!defSrcFormatParams)
+ {
+ cout << "convertDEFs(...) for srcformat r_Array is necessary to provide the srcformatparams as described in help" << endl;
+ return EXIT_FAILURE;
+ }
+
+ if(parseArrayParams((const char*)srcFormatParams, fpDomain, fpType, srcIvc, srcTypec) != EXIT_SUCCESS)
+ return EXIT_FAILURE;
+
+ if(decodeMinterval(srcIvc, srcIv) != EXIT_SUCCESS)
+ return EXIT_FAILURE;
+
+ if(decodeType(srcTypec, srcType) != EXIT_SUCCESS)
+ return EXIT_FAILURE;
+ }
+
+ //check destFormatParams if destFormat=r_Array
+ if(destFormat == r_Array)
+ {
+ if(!defDestFormatParams)
+ {
+ cout << "convertDEFs(...) for destformat r_Array is necessary to provide the srcformatparams as described in help" << endl;
+ return EXIT_FAILURE;
+ }
+
+ if(parseArrayParams((const char*)destFormatParams, fpDomain, fpType, destIvc, destTypec) != EXIT_SUCCESS)
+ return EXIT_FAILURE;
+
+ if(decodeMinterval(destIvc, destIv) != EXIT_SUCCESS)
+ return EXIT_FAILURE;
+
+ if(decodeType(destTypec, destType) != EXIT_SUCCESS)
+ return EXIT_FAILURE;
+ }
+}
+
+int setCell(const char* srcCell,
+ const r_Type* srcType,
+ const r_Type* destType,
+ char* destCell,
+ bool rescale=false)
+{
+ r_Double srcTypeMin=0., srcTypeMax=0.;
+ r_Double destTypeMin=0., destTypeMax=0.;
+ r_Double srcVal=0., destVal=0.;
+
+ if(!srcCell)
+ {
+ cout << "setCell(...) srcCell is null" << endl;
+ return EXIT_FAILURE;
+ }
+ if(!srcType)
+ {
+ cout << "setCell(...) srcType is null" << endl;
+ return EXIT_FAILURE;
+ }
+ if(!destType)
+ {
+ cout << "setCell(...) destType is null" << endl;
+ return EXIT_FAILURE;
+ }
+ if(!destCell)
+ {
+ cout << "setCell(...) destCell is null" << endl;
+ return EXIT_FAILURE;
+ }
+
+ try
+ {
+ srcVal=((r_Primitive_Type*)srcType)->get_value(srcCell);
+ if(rescale)
+ {
+ ((r_Primitive_Type*)srcType)->get_limits(srcTypeMin, srcTypeMax);
+ ((r_Primitive_Type*)destType)->get_limits(destTypeMin, destTypeMax);
+ destVal=srcVal*destTypeMax/srcTypeMax;
+ }
+ else
+ destVal=srcVal;
+ ((r_Primitive_Type*)destType)->set_value(destCell,destVal);
+ }
+ catch(r_Error& err)
+ {
+ cout << "setCell(...) error while setting value to dest from src" << endl;
+ cout << "Error " << err.get_errorno() << " : " << err.what() << endl;
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+int convertData(const r_convDesc& descSrc, r_convDesc& descDest)
+{
+ r_Minterval srcIv, destIv, commonIv;
+
+ r_Bytes srcTypeSize=0, destTypeSize=0;
+ char *srcBuffer=NULL, *destBuffer=NULL;
+
+ if(!descSrc.dest)
+ {
+ cout << "convertData(...) descSrc.dest is null" << endl;
+ return EXIT_FAILURE;
+ }
+
+ if(!descSrc.destType)
+ {
+ cout << "convertData(...) descSrc.destType is null" << endl;
+ return EXIT_FAILURE;
+ }
+
+ if(descDest.dest)
+ {
+ cout << "convertData(...) descDest.dest is not null" << endl;
+ return EXIT_FAILURE;
+ }
+
+ if(!descDest.destType)
+ {
+ cout << "convertData(...) descDest.destType is null" << endl;
+ return EXIT_FAILURE;
+ }
+
+ //translate every interval to zero
+ try
+ {
+ srcIv=descSrc.destInterv.create_reverse_translation(descSrc.destInterv.get_origin());
+ destIv=descDest.destInterv.create_reverse_translation(descDest.destInterv.get_origin());
+ }
+ catch(r_Error& err)
+ {
+ cout << "convertData(...) error while translating to zero the following intervals:" << endl;
+ cout << "descSrc.destInterv=" << descSrc.destInterv << endl;
+ cout << "descDest.destInterv=" << descDest.destInterv << endl;
+ cout << "Error " << err.get_errorno() << ":" << err.what() << endl;
+ return EXIT_FAILURE;
+ }
+
+ //check intersection
+ try
+ {
+ commonIv.intersection_of(srcIv, destIv);
+ }
+ catch(r_Error& err)
+ {
+ cout << "convertData(...) error while doing the intersection of the following intervals:" << endl;
+ cout << "descSrc.destInterv=" << descSrc.destInterv << endl;
+ cout << "descDest.destInterv=" << descDest.destInterv << endl;
+ cout << "Error " << err.get_errorno() << ":" << err.what() << endl;
+ return EXIT_FAILURE;
+ }
+
+ //get type size
+ srcTypeSize=((r_Base_Type*)descSrc.destType)->size();
+ destTypeSize=((r_Base_Type*)descDest.destType)->size();
+
+ //allocate data
+ srcBuffer=new char[srcTypeSize];
+ if(!srcBuffer)
+ {
+ cout << "convertData(...) unable to claim memory for srcBuffer" << endl;
+ return EXIT_FAILURE;
+ }
+ destBuffer=new char[destTypeSize];
+ if(!destBuffer)
+ {
+ cout << "convertData(...) unable to claim memory for destBuffer" << endl;
+ delete[] srcBuffer;
+ srcBuffer=NULL;
+ return EXIT_FAILURE;
+ }
+ descDest.dest=new char[descDest.destInterv.cell_count()*destTypeSize];
+ if(!descDest.dest)
+ {
+ cout << "convertData(...) unable to claim memory for descDest.dest" << endl;
+ delete[] srcBuffer;
+ srcBuffer=NULL;
+ delete[] destBuffer;
+ destBuffer=NULL;
+ return EXIT_FAILURE;
+ }
+ memset(descDest.dest,0, descDest.destInterv.cell_count()*destTypeSize);
+
+ r_Miter srcIter( &commonIv, &srcIv, srcTypeSize, descSrc.dest );
+ r_Miter destIter( &commonIv, &destIv, destTypeSize, descDest.dest );
+ while(!srcIter.isDone() || !destIter.isDone())
+ {
+ memcpy(srcBuffer, srcIter.nextCell(), srcTypeSize);
+ if(setCell(srcBuffer, descSrc.destType, descDest.destType, destBuffer)!=EXIT_SUCCESS)
+ {
+ //abort algorithm
+ break;
+ }
+ memcpy(destIter.nextCell(), destBuffer, destTypeSize);
+ }
+
+ //clean up
+ delete[] srcBuffer;
+ srcBuffer=NULL;
+ delete[] destBuffer;
+ destBuffer=NULL;
+
+ //check algorithm
+ if(!srcIter.isDone() || !destIter.isDone())
+ {
+ cout << "convertData(...) error in algorithm" << endl;
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+
+
+int convertDEFs()
+{
+ char *dataSrc=NULL, *dataDest=NULL;
+ r_ULong dataSrcSize=0, dataDestSize=0;
+ r_convDesc descSrc, descDest;
+
+ initConvDesc(descSrc);
+ initConvDesc(descDest);
+
+ //read the source file
+ if(readFile(srcFileName, &dataSrc, dataSrcSize)!=EXIT_SUCCESS)
+ return EXIT_FAILURE;
+
+ if(!dataSrcSize)
+ {
+ cout << "convertDEFs() size of file " << srcFileName << " is zero" << endl;
+ //clean up
+ delete [] dataSrc;
+ dataSrc=NULL;
+ return EXIT_FAILURE;
+ }
+
+ //what is the input format?
+ if(srcFormat !=r_Array)
+ {
+ //it is safe to use srcType, srcIv because the srcFormat is not r_Array
+ srcType=r_Convertor::get_external_type(r_Convertor::ctype_char);
+ srcIv = r_Minterval(1);
+ srcIv << r_Sinterval((r_Long)0, (r_Long)(dataSrcSize - 1));
+
+ //did conversion work?
+ if(convertFrom(srcFormat, srcFormatParams, dataSrc,
+ srcIv, srcType, descSrc) != EXIT_SUCCESS)
+ {
+ //clean up
+ delete [] dataSrc;
+ dataSrc=NULL;
+ return EXIT_FAILURE;
+ }
+ }
+ else
+ {
+ descSrc.dest=dataSrc;
+ descSrc.destInterv=srcIv;
+ descSrc.destType=srcType;
+ }
+
+ //what is the output format?
+ if(destFormat !=r_Array)
+ {
+ if(convertTo(destFormat, destFormatParams, descSrc.dest, descSrc.destInterv, descSrc.destType, descDest) != EXIT_SUCCESS)
+ {
+ //clean up
+ cleanConvDesc(descSrc);
+ return EXIT_FAILURE;
+ }
+ //prepare the data for writing
+ dataDest=descDest.dest;
+ dataDestSize=descDest.destInterv.cell_count() * ((r_Base_Type*)descDest.destType)->size();
+ }
+ else
+ {
+ //prepare for conversion
+ descDest.destType=destType;
+ descDest.destInterv=destIv;
+ descDest.dest=NULL;
+
+ if(descSrc.destType->isPrimitiveType())
+ {
+ if(convertData(descSrc, descDest) != EXIT_SUCCESS)
+ {
+ //clean up
+ cleanConvDesc(descSrc);
+ cleanConvDesc(descDest);
+ return EXIT_FAILURE;
+ }
+
+ //prepare the data for writing
+ dataDest=descDest.dest;
+ dataDestSize=descDest.destInterv.cell_count() * ((r_Base_Type*)descDest.destType)->size();
+ }
+ else
+ {
+ //we store the data as it is
+ dataDest=descSrc.dest;
+ dataDestSize=descSrc.destInterv.cell_count() * ((r_Base_Type*)descSrc.destType)->size();
+ }
+
+ }
+
+
+
+ //write data into destFileName
+ if(writeFile(destFileName, (const char**)&dataDest, dataDestSize)!=EXIT_SUCCESS)
+ {
+ //clean up
+ cleanConvDesc(descSrc);
+ cleanConvDesc(descDest);
+ return EXIT_FAILURE;
+ }
+
+ //clean up
+ cleanConvDesc(descSrc);
+ cleanConvDesc(descDest);
+
+ return EXIT_SUCCESS;
+}
+
+int processRequest()
+{
+ if(validateParams() != EXIT_SUCCESS)
+ return EXIT_FAILURE;
+ return convertDEFs();
+}
+
+int main(int argc, char **argv)
+{
+ if(parseParams(argc, argv) != EXIT_SUCCESS)
+ {
+ printUsage();
+ return EXIT_FAILURE;
+ }
+ else
+ {
+ if(!defPrgHelp)
+ {
+ printStatus();
+ return processRequest();
+ }
+ else
+ {
+ printUsage();
+ return EXIT_SUCCESS;
+ }
+ }
+}
diff --git a/rasodmg/test/defdiff.cc b/rasodmg/test/defdiff.cc
new file mode 100644
index 0000000..953435a
--- /dev/null
+++ b/rasodmg/test/defdiff.cc
@@ -0,0 +1,537 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/*
+ * defdiff.cc
+ *
+ * Compare to DEF files and returns 0 for succes, otherwise 1
+ *
+ * Parameters:
+ *
+ * --inputfilename <src-file>
+ * the filename of the src file, mandatory
+ * --outputfilename <dest-file>
+ * the filename of the dest file, mandatory
+ *
+ * --inputformat name
+ * name of DEF fromat(see data_foramat from mddtypes.hh)
+ * --inputformatparams params
+ * params used by convertFrom methods(see the heder file for you DEF from conversion)
+ * --outputformat name
+ * name of DEF fromat(see data_foramat from mddtypes.hh)
+ * --outputformatparams params
+ * params used by convertFrom methods(see the heder file for you DEF from conversion)
+ *
+ * --help
+ * print usage and exit
+ */
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#ifdef __GNUG__
+#include "raslib/template_inst.hh"
+#endif
+#endif
+
+#include "defutil.hh"
+
+const char* diffFileName = "defdiff.tif";
+
+const char* paramPrgHelp="--help";
+bool defPrgHelp=false;
+char* prgHelp=NULL;
+
+const char* paramSrcFileName="--srcfilename";
+bool defSrcFileName=false;
+char* srcFileName=NULL;
+
+const char* paramSrcFormat="--srcformat";
+bool defSrcFormat=false;
+char* srcFormatc=NULL;
+r_Data_Format srcFormat=r_Array;
+
+const char* paramSrcFormatParams="--srcformatparams";
+bool defSrcFormatParams=false;
+char *srcFormatParams=NULL;
+
+const char* paramDestFileName="--destfilename";
+bool defDestFileName=false;
+char *destFileName=NULL;
+
+const char* paramDestFormat="--destformat";
+bool defDestFormat=false;
+char *destFormatc=NULL;
+r_Data_Format destFormat=r_Array;
+
+const char* paramDestFormatParams="--destformatparams";
+bool defDestFormatParams=false;
+char *destFormatParams=NULL;
+
+//structures used for parseParam
+const int paramsNo=7;
+
+const char *paramsName[paramsNo]={ paramPrgHelp, paramSrcFileName, paramSrcFormat, paramSrcFormatParams,
+ paramDestFileName, paramDestFormat, paramDestFormatParams};
+
+bool *paramsPresent[paramsNo]={ &defPrgHelp, &defSrcFileName, &defSrcFormat, &defSrcFormatParams,
+ &defDestFileName, &defDestFormat, &defDestFormatParams};
+
+char **paramsValue[paramsNo]={ &prgHelp, &srcFileName, &srcFormatc, &srcFormatParams,
+ &destFileName, &destFormatc, &destFormatParams};
+
+void printStatus()
+{
+ cout << "defdiff parameters list:" << endl;
+ for (int i=0; i<paramsNo; i++)
+ cout << "--Name='" << paramsName[i]
+ << "' Present=" << ((*paramsPresent[i])? "true": "false")
+ << " Value='" << (*paramsValue[i]?*paramsValue[i]: "null") << "'" << endl;
+}
+
+void printUsage()
+{
+ char* fileNameSrc="test.bmp";
+ char* fileNameDest="test.tiff";
+
+ cout << "defdiff v 0.1 - RasDaMan Data Exchange Format Difference Utility" << endl;
+ cout << "Description: Returns " << EXIT_SUCCESS << " for succes, otherwise " << EXIT_FAILURE << endl;
+ cout << "If it is possible it will create a tiff file with the difference, called " << diffFileName << endl;
+ cout << "Usage options:" << endl;
+ cout << " " << paramSrcFileName << " <src-file> ... the filename used as src mandatory" << endl;
+ cout << " " << paramSrcFormat << " name ... name of DEF fromat(see data_foramat from mddtypes.hh)," << endl;
+ cout << " default Array" << endl;
+ cout << " " << paramSrcFormatParams << " params ... params used by convertFrom methods(see the header file" << endl;
+ cout << " for you DEF from conversion), default NULL" << endl;
+ cout << " " << paramDestFileName << " <dest-file> ... the filename used as dest mandatory" << endl;
+ cout << " " << paramDestFormat << " name ... name of DEF fromat(see data_foramat from mddtypes.hh)," << endl;
+ cout << " default Array" << endl;
+ cout << " " << paramDestFormatParams << " params ... params used by convertFrom methods(see the header file" << endl;
+ cout << " for you DEF from conversion), default NULL" << endl;
+ cout << " " << paramPrgHelp << " ... this help" << endl;
+ cout << "For example:" << endl;
+ cout << "defdiff " << paramSrcFileName << " " << fileNameSrc << " " << paramSrcFormat << " " << format_name_bmp <<" "
+ << paramDestFileName << " " << fileNameDest << " " << paramDestFormat <<" " << format_name_tiff << endl;
+ cout << "Report bugs to liviu.coman@active­knowledge.com" << endl;
+
+}
+
+int checkParam(int& paramIndex, char** param)
+{
+ int i=0;
+ while(i<paramsNo)
+ {
+ if(!strcmp(param[paramIndex], paramsName[i]))
+ break;
+ i++;
+ }
+
+ if(i==paramsNo)
+ {
+ cout << "checkParam(...) error processing parameters: parameter "
+ << param[paramIndex] << " is unknown!" << endl;
+ return EXIT_FAILURE;
+ }
+ if(*paramsPresent[i])
+ {
+ cout << "checkParam(...) error processing parameters: parameter "
+ << param[paramIndex] << " is present more than once!" << endl;
+ return EXIT_FAILURE;
+ }
+
+ if(paramsName[i]!=paramPrgHelp)
+ {
+ *paramsPresent[i]=true;
+ paramIndex++;
+ *paramsValue[i]=param[paramIndex];
+ }
+ else
+ *paramsPresent[i]=true;
+
+ return EXIT_SUCCESS;
+}
+
+int parseParams(int argc, char** argv)
+{
+ int argIndex=0;
+ if (argc==1)
+ {
+ cout << "parseParams(...) parameters " << paramSrcFileName << " <src-file> and "
+ << paramDestFileName << " <dest-file> are mandatatory!" << endl;
+ return EXIT_FAILURE;
+ }
+ else
+ {
+ argIndex=1;
+ while(argIndex<argc)
+ {
+ if(checkParam(argIndex, argv)!=EXIT_SUCCESS)
+ break;
+ argIndex++;
+ }
+ if(argIndex<argc)
+ return EXIT_FAILURE;
+
+ //check rule
+ if((defSrcFileName && defDestFileName) || (defPrgHelp))
+ return EXIT_SUCCESS;
+ else
+ {
+ cout << "parseParams(...) parameters " << paramSrcFileName << " <src-file> and "
+ << paramDestFileName << " <dest-file> are mandatatory!" << endl;
+ return EXIT_FAILURE;
+ }
+ }
+}
+
+int validateParams()
+{
+ if(defSrcFormat)
+ {
+ srcFormat = get_data_format_from_name(srcFormatc);
+ if((srcFormat!=r_Array) &&
+ (!r_Convertor_Factory::is_supported(srcFormat)))
+ {
+ cout << "validateParams() conversion of " << srcFormatc << " not supported" << endl;
+ return EXIT_FAILURE;
+ }
+ }
+ if(defDestFormat)
+ {
+ destFormat = get_data_format_from_name(destFormatc);
+ if((destFormat!=r_Array) &&
+ (!r_Convertor_Factory::is_supported(destFormat)))
+ {
+ cout << "validateParams() conversion " << destFormatc << " not supported" << endl;
+ return EXIT_FAILURE;
+ }
+ }
+
+ return EXIT_SUCCESS;
+}
+
+int compareDEFs()
+{
+ char *dataSrc=NULL, *dataDest=NULL;
+ r_ULong dataSrcSize=0, dataDestSize=0;
+ r_ULong arraySrcSize=0, arrayDestSize=0;
+ r_Bytes basetypeSrcSize=0, basetypeDestSize=0;
+ r_convDesc descSrc, descDest;
+ r_Type::r_Type_Id basetypeSrcId=r_Type::UNKNOWNTYPE, basetypeDestId=r_Type::UNKNOWNTYPE;
+
+ //init conversion result data
+ initConvDesc(descSrc);
+ initConvDesc(descDest);
+
+ //read files
+ if(readFile(srcFileName, &dataSrc, dataSrcSize)!=EXIT_SUCCESS)
+ return EXIT_FAILURE;
+
+ if(readFile(destFileName, &dataDest, dataDestSize)!=EXIT_SUCCESS)
+ {
+ delete [] dataSrc;
+ dataSrc=NULL;
+ return EXIT_FAILURE;
+ }
+
+ //convert if necessary
+ if(srcFormat !=r_Array)
+ {
+ r_Minterval srcIv(1);
+ r_Type* srcType=NULL;
+
+ srcIv << r_Sinterval((r_Range)0, (r_Range)(dataSrcSize -1));
+ srcType=r_Convertor::get_external_type(r_Convertor::ctype_char);
+
+ if(convertFrom(srcFormat, srcFormatParams, dataSrc,
+ srcIv, srcType, descSrc) != EXIT_SUCCESS)
+ {
+ delete srcType;
+ srcType=NULL;
+ delete [] dataSrc;
+ dataSrc=NULL;
+ delete [] dataDest;
+ dataDest=NULL;
+ return EXIT_FAILURE;
+ }
+ else
+ {
+ //we don't need this anymore
+ delete [] dataSrc;
+ dataSrc=NULL;
+ delete srcType;
+ srcType=NULL;
+ }
+ }
+
+ if(destFormat !=r_Array)
+ {
+ r_Minterval destIv(1);
+ r_Type* destType=NULL;
+
+ destIv << r_Sinterval((r_Range)0, (r_Range)(dataDestSize -1));
+ destType=r_Convertor::get_external_type(r_Convertor::ctype_char);
+
+ if(convertFrom(destFormat, destFormatParams, dataDest,
+ destIv, destType, descDest) != EXIT_SUCCESS)
+ {
+ delete destType;
+ destType=NULL;
+ delete [] dataDest;
+ dataDest=NULL;
+ if(srcFormat==r_Array)
+ {
+ delete [] dataSrc;
+ dataSrc=NULL;
+ }
+ else
+ {
+ dataSrc=NULL;
+ cleanConvDesc(descSrc);
+ }
+
+ return EXIT_FAILURE;
+ }
+ else
+ {
+ //we don't need this anymore
+ delete [] dataDest;
+ dataDest=NULL;
+ delete destType;
+ destType=NULL;
+ }
+ }
+
+ //check domain
+ if((srcFormat!=r_Array) &&
+ (destFormat!=r_Array) &&
+ (descSrc.destInterv != descDest.destInterv))
+ {
+ cout << "compareDEFs() source domain " << descSrc.destInterv << " != destination domain " << descDest.destInterv << endl;
+ cleanConvDesc(descSrc);
+ cleanConvDesc(descDest);
+ return EXIT_FAILURE;
+ }
+
+ //check if celltype is a basetype
+ if((srcFormat!=r_Array) &&
+ (!descSrc.destType->isBaseType()))
+ {
+ cout << "compareDEFs() source type " << basetypeSrcId << " is not a base type" << endl;
+ if(destFormat==r_Array)
+ {
+ delete [] dataDest;
+ dataDest=NULL;
+ }
+ else
+ cleanConvDesc(descDest);
+ cleanConvDesc(descSrc);
+ return EXIT_FAILURE;
+ }
+
+ if((destFormat!=r_Array) &&
+ (!descDest.destType->isBaseType()))
+ {
+ cout << "compareDEFs() destination type " << basetypeDestId << " is not a base type" << endl;
+ if(srcFormat==r_Array)
+ {
+ delete [] dataSrc;
+ dataSrc=NULL;
+ }
+ else
+ cleanConvDesc(descSrc);
+ cleanConvDesc(descDest);
+ return EXIT_FAILURE;
+ }
+
+ //stoare info about types
+ if(srcFormat!=r_Array)
+ {
+ basetypeSrcId=descSrc.destType->type_id();
+ basetypeSrcSize=((r_Base_Type*)descSrc.destType)->size();
+ }
+ if(destFormat!=r_Array)
+ {
+ basetypeDestId=descDest.destType->type_id();
+ basetypeDestSize=((r_Base_Type*)descDest.destType)->size();
+ }
+
+ if((srcFormat!=r_Array) &&
+ (destFormat!=r_Array))
+ {
+ //FIXME basetypeSrcId!=basetypeDestId to powerfull
+ if(basetypeSrcId!=basetypeDestId)
+ cout << "compareDEFs() warning: source type " << basetypeSrcId
+ << " != destination type " << basetypeDestId << endl;
+
+ if(basetypeSrcSize!=basetypeDestSize)
+ {
+ cout << "comparetDEFs() source type " << descSrc.destType->name() << " != destination type " << descDest.destType->name() << endl;
+ cout << "source type size" << basetypeSrcSize << " != destination type size" << basetypeDestSize << endl;
+ cleanConvDesc(descSrc);
+ cleanConvDesc(descDest);
+ return EXIT_FAILURE;
+ }
+
+ if((basetypeSrcId == r_Type::STRUCTURETYPE) &&
+ (basetypeDestId == r_Type::STRUCTURETYPE) &&
+ (compareStructure((r_Structure_Type*)descSrc.destType, (r_Structure_Type*)descDest.destType) !=EXIT_SUCCESS))
+ {
+ cout << "compareDEFs() source structure type != destination structure type" << endl;
+ cout << "Source type is: " << (*(r_Structure_Type*)(descSrc.destType)) << endl;
+ cout << "Destination type is:" << (*(r_Structure_Type*)(descSrc.destType)) << endl;
+ cleanConvDesc(descSrc);
+ cleanConvDesc(descDest);
+ return EXIT_FAILURE;
+ }
+ }
+
+ if(srcFormat!=r_Array)
+ {
+ arraySrcSize=descSrc.destInterv.cell_count() * basetypeSrcSize;
+ dataSrc=descSrc.dest;
+ }
+ else
+ arraySrcSize=dataSrcSize;
+
+ if(destFormat!=r_Array)
+ {
+ arrayDestSize=descDest.destInterv.cell_count() * basetypeDestSize;
+ dataDest=descDest.dest;
+ }
+ else
+ arrayDestSize=dataDestSize;
+
+ if(arraySrcSize!=arrayDestSize)
+ {
+ cout << "compareDEFs() source data size " << arraySrcSize << " != " << " destination data size " << arrayDestSize << endl;
+ delete [] dataSrc;
+ dataSrc=NULL;
+ delete [] dataDest;
+ dataDest=NULL;
+ cleanConvDesc(descSrc);
+ cleanConvDesc(descDest);
+ return EXIT_FAILURE;
+ }
+
+ if(memcmp(dataSrc, dataDest, arraySrcSize))
+ {
+ cout << "compareDEFs() source and destination data are different" << endl;
+ r_convDesc descDiff;
+ r_ULong diffSize=0;
+ initConvDesc(descDiff);
+ //do diff
+ for(int i=0; i< arraySrcSize; i++)
+ dataDest[i]-=dataSrc[i];
+ if(convertTo(r_TIFF, NULL, dataDest, descDest.destInterv,
+ descDest.destType, descDiff) != EXIT_SUCCESS)
+ {
+ cout << "compareDEFs() error building the difference tiff file" << endl;;
+ }
+ else
+ {
+ diffSize=descDiff.destInterv.cell_count() * ((r_Base_Type*)descDiff.destType)->size();
+ if(writeFile(diffFileName, (const char**)&descDiff.dest, diffSize)!=EXIT_SUCCESS)
+ cout << "compareDEFs() error building the difference tiff file" << endl;;
+ cleanConvDesc(descDiff);
+ }
+
+ //clean up
+ if(srcFormat==r_Array)
+ {
+ delete [] dataSrc;
+ dataSrc=NULL;
+ }
+ else
+ {
+ dataSrc=NULL;
+ cleanConvDesc(descSrc);
+ }
+ if(destFormat==r_Array)
+ {
+ delete [] dataDest;
+ dataDest=NULL;
+ }
+ else
+ {
+ dataDest=NULL;
+ cleanConvDesc(descDest);
+ }
+ return EXIT_FAILURE;
+ }
+
+ cout << "compareDEFs() source and destination data are identic" << endl;
+
+ //clean up
+ if(srcFormat==r_Array)
+ {
+ delete [] dataSrc;
+ dataSrc=NULL;
+ }
+ else
+ {
+ dataSrc=NULL;
+ cleanConvDesc(descSrc);
+ }
+ if(destFormat==r_Array)
+ {
+ delete [] dataDest;
+ dataDest=NULL;
+ }
+ else
+ {
+ dataDest=NULL;
+ cleanConvDesc(descDest);
+ }
+
+ return EXIT_SUCCESS;
+}
+
+int processRequest()
+{
+ if(validateParams() != EXIT_SUCCESS)
+ return EXIT_FAILURE;
+ return compareDEFs();
+}
+
+int main(int argc, char **argv)
+{
+ if(parseParams(argc, argv)!=EXIT_SUCCESS)
+ {
+ printUsage();
+ return EXIT_FAILURE;
+ }
+ else
+ {
+ if(!defPrgHelp)
+ {
+#ifdef RMANDEBUG
+ printStatus();
+#endif
+ return processRequest();
+ }
+ else
+ {
+ printUsage();
+ return EXIT_SUCCESS;
+ }
+ }
+}
diff --git a/rasodmg/test/defutil.hh b/rasodmg/test/defutil.hh
new file mode 100644
index 0000000..b30a8a5
--- /dev/null
+++ b/rasodmg/test/defutil.hh
@@ -0,0 +1,412 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/*
+ * defutil.hh
+ *
+ * COMMENTS
+ * Common functions used by defxxx programs
+*/
+
+
+#include <cstdio>
+#include <cstdlib>
+#include <iostream>
+using std::cout;
+using std::endl;
+
+#include "raslib/mddtypes.hh"
+#include "raslib/structuretype.hh"
+#include "raslib/odmgtypes.hh"
+#include "raslib/minterval.hh"
+#include "raslib/parseparams.hh"
+#include "conversion/convertor.hh"
+#include "conversion/convfactory.hh"
+
+//--I/O file
+int readFile(const char* fileName, char **data, r_ULong& dataSize)
+{
+ FILE *pFile=NULL;
+
+ if(fileName==NULL)
+ {
+ cout << "readFile(...) fileName is null" << endl;
+ return EXIT_FAILURE;
+ }
+
+ if(*data!=NULL)
+ {
+ cout << "readFile(...) data is not null" << endl;
+ return EXIT_FAILURE;
+ }
+
+ pFile=fopen(fileName, "rb");
+ if(pFile==NULL)
+ {
+ cout << "readFile(...) unable to open file " << fileName << endl;
+ return EXIT_FAILURE;
+ }
+
+ fseek(pFile, 0, SEEK_END);
+ dataSize=ftell(pFile);
+
+ *data=new char[dataSize];
+ if(*data==NULL)
+ {
+ cout << "readFile(...) unable to claim memory for file " << fileName << endl;
+ fclose(pFile);
+ return EXIT_FAILURE;
+ }
+
+ fseek(pFile, 0, SEEK_SET);
+ fread(*data, 1, dataSize, pFile);
+
+ fclose(pFile);
+ return EXIT_SUCCESS;
+}
+
+int writeFile(const char* fileName, const char **data, r_ULong& dataSize)
+{
+ FILE *pFile=NULL;
+
+ if(fileName==NULL)
+ {
+ cout << "writeFile(...) fileName is null" << endl;
+ return EXIT_FAILURE;
+ }
+
+ if(*data==NULL)
+ {
+ cout << "writeFile(...) data is null" << endl;
+ return EXIT_FAILURE;
+ }
+
+ if(!dataSize)
+ {
+ cout << "writeFile(...) dataSize is zero" << endl;
+ return EXIT_FAILURE;
+ }
+
+ pFile=fopen(fileName, "wb");
+ if(pFile==NULL)
+ {
+ cout << "writeFile(...) unable to open file" << fileName << endl;
+ return EXIT_FAILURE;
+ }
+
+ fwrite(*data, 1, dataSize, pFile);
+
+ fclose(pFile);
+ pFile=NULL;
+
+ return EXIT_SUCCESS;
+}
+
+//ConvertFrom/To r_Array data
+int convertFrom(r_Data_Format fmt, const char* fmtParams,
+ const char* data, const r_Minterval& dataDom,
+ const r_Type* dataType, r_convDesc& desc)
+{
+ r_Storage_Man_CPP mySM;
+ r_Convertor *conv=NULL;
+
+ if(data==NULL)
+ {
+ cout << "convertFrom(...) data is null" << endl;
+ return EXIT_FAILURE;
+ }
+
+ if(dataType==NULL)
+ {
+ cout << "convertFrom(...) dataType is null" << endl;
+ return EXIT_FAILURE;
+ }
+
+ try
+ {
+ conv=r_Convertor_Factory::create(fmt, data, dataDom, dataType);
+ conv->set_storage_handler(mySM);
+ }
+ catch(r_Error& err)
+ {
+ cout << "convertFrom(...) request for convertor " << fmt << " failed" << endl
+ << "Error " << err.get_errorno() << " : " << err.what() << endl;
+ return EXIT_FAILURE;
+ }
+
+ try
+ {
+ desc = conv->convertFrom(fmtParams);
+ }
+ catch(r_Error &err)
+ {
+ cout << "convertFrom(...) conversion from " << fmt << " format to r_Array format failed! " << endl
+ << "Error " << err.get_errorno() << " : " << err.what() << endl;
+ if(conv)
+ {
+ delete conv;
+ conv=NULL;
+ }
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+int convertTo(r_Data_Format fmt, const char* fmtParams,
+ const char* data, const r_Minterval& dataDom,
+ const r_Type* dataType, r_convDesc& desc)
+{
+ r_Storage_Man_CPP mySM;
+ r_Convertor *conv=NULL;
+
+ if(data==NULL)
+ {
+ cout << "convertTo(...) data is null" << endl;
+ return EXIT_FAILURE;
+ }
+
+ if(dataType==NULL)
+ {
+ cout << "convertTo(...) dataType is null" << endl;
+ return EXIT_FAILURE;
+ }
+
+ try
+ {
+ conv=r_Convertor_Factory::create(fmt, data, dataDom, dataType);
+ conv->set_storage_handler(mySM);
+ }
+ catch(r_Error& err)
+ {
+ cout << "convertTo(...) request for convertor " << fmt << " failed! " << endl
+ << "Error " << err.get_errorno() << " : " << err.what() << endl;
+ return EXIT_FAILURE;
+ }
+
+ try
+ {
+ desc = conv->convertTo(fmtParams);
+ }
+ catch(r_Error &err)
+ {
+ cout << "convertTo(...) conversion from " << fmt << " format to r_Array format failed! " << endl
+ << "Error " << err.get_errorno() << " : " << err.what() << endl;
+ if(conv)
+ {
+ delete conv;
+ conv=NULL;
+ }
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+
+//init/deinit ConvDesc
+void cleanConvDesc(r_convDesc& desc)
+{
+ desc.src=NULL;
+ desc.srcType=NULL;
+ if(desc.dest!=NULL)
+ {
+ delete []desc.dest;
+ desc.dest=NULL;
+ }
+ if(desc.destType!=NULL)
+ {
+ delete desc.destType;
+ desc.destType=NULL;
+ }
+ desc.baseType = r_Convertor::ctype_void;
+}
+
+void initConvDesc(r_convDesc& desc)
+{
+ desc.dest=NULL;
+ desc.src=NULL;
+ desc.srcType=NULL;
+ desc.destType=NULL;
+ desc.baseType = r_Convertor::ctype_void;
+}
+
+//decode a minterval from a string
+int decodeMinterval(const char* src, r_Minterval& srcIv)
+{
+ if(!src)
+ {
+ cout << "decodeMinterval(...) src is null" << endl;
+ return EXIT_FAILURE;
+ }
+
+ try
+ {
+ srcIv=r_Minterval(src);
+ }
+ catch(r_Error& err)
+ {
+ cout << "decodeMinterval(...) error while constructing the minterval from " << src << endl;
+ cout << "Error " << err.get_errorno() << ":" << err.what() << endl;
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+//decode a type from a string
+int decodeType(const char* src, r_Type*& srcType)
+{
+ if(!src)
+ {
+ cout << "decodeType(...) src is null" << endl;
+ return EXIT_FAILURE;
+ }
+
+ if(srcType)
+ {
+ cout << "decodeType(...) src is not null" << endl;
+ return EXIT_FAILURE;
+ }
+
+ try
+ {
+ srcType=r_Type::get_any_type(src);
+ }
+ catch(r_Error& err)
+ {
+ cout << "decodeType(...) error while constructing the type from " << src << endl;
+ cout << "Error " << err.get_errorno() << ":" << err.what() << endl;
+ return EXIT_FAILURE;
+ }
+
+ if(!srcType)
+ {
+ cout << "decodeType(...) the type retrived with r_Type::get_any_type(...) is null" << endl;
+ return EXIT_FAILURE;
+ }
+
+ if(!srcType->isBaseType())
+ {
+ cout << "decodeType(...) the type retrived (" << srcType->type_id() << ") is not a base type" << endl;
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+//parse r_Array params 'domain=<domain_str>,type=<type_str>'
+int parseArrayParams(const char* formatparams,
+ const char* fpDomain,
+ const char* fpType,
+ char*& domain,
+ char*& type)
+{
+ const int fpNo=2;
+ r_Parse_Params params(fpNo);
+
+ //parameter validation
+ if(formatparams==NULL) {
+ cout << "parseArrayParams(...) formatparams is null" << endl;
+ return EXIT_FAILURE;
+ }
+ if(fpDomain==NULL){
+ cout << "parseArrayParams(...) fpDomain is null" << endl;
+ return EXIT_FAILURE;
+ }
+ if(fpType==NULL){
+ cout << "parseArrayParams(...) fpType is null" << endl;
+ return EXIT_FAILURE;
+ }
+ if(domain!=NULL){
+ cout << "parseArrayParams(...) domain is not null" << endl;
+ return EXIT_FAILURE;
+ }
+ if(type!=NULL){
+ cout << "parseArrayParams(...) type is not null" << endl;
+ return EXIT_FAILURE;
+ }
+
+ params.add(fpDomain, &domain, r_Parse_Params::param_type_string);
+ params.add(fpType, &type, r_Parse_Params::param_type_string);
+
+ if(params.process(formatparams) != fpNo)
+ {
+ cout << "parseArrayParams(...) error parsing " << formatparams << endl;
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+//compare 2 structure type
+int compareStructure(r_Structure_Type* src, r_Structure_Type* dest)
+{
+ r_Structure_Type::attribute_iterator iterSrc, iterDest;
+
+ if(src==NULL)
+ {
+ cout << "compareStructure(...) src is null !"<< endl;
+ return EXIT_FAILURE;
+ }
+
+ if(dest==NULL)
+ {
+ cout << "compareStructure(...) dest is null !"<< endl;
+ return EXIT_FAILURE;
+ }
+
+ iterSrc=src->defines_attribute_begin();
+ iterDest=dest->defines_attribute_begin();
+ while( iterSrc!=src->defines_attribute_end() || iterDest!=dest->defines_attribute_end())
+ {
+ r_Type::r_Type_Id typeSrcId=r_Type::UNKNOWNTYPE, typeDestId=r_Type::UNKNOWNTYPE;
+ typeSrcId=(*iterSrc).type_of().type_id();
+ typeDestId=(*iterDest).type_of().type_id();
+
+ if(typeSrcId!=typeDestId)
+ {
+ cout << "comparaStructure(...) typeSrcId(" << typeSrcId
+ << ") != typeDestId(" << typeDestId << ") !"<< endl;
+ return EXIT_FAILURE;
+ }
+
+ if((typeSrcId== r_Type::STRUCTURETYPE) &&
+ (compareStructure((r_Structure_Type*)(&((*iterSrc).type_of())),
+ (r_Structure_Type*)(&((*iterDest).type_of()))) != EXIT_SUCCESS))
+ return EXIT_FAILURE;
+
+ iterSrc++;
+ iterDest++;
+ }
+ if((iterSrc==src->defines_attribute_end()) &&
+ (iterDest==dest->defines_attribute_end()))
+ return EXIT_SUCCESS;
+ else
+ {
+ if(iterSrc!=src->defines_attribute_end())
+ cout << "compareStructure(...) src has more atributes then dest!" << endl;
+ else
+ cout << "compareStructure(...) dest has more atributes then src!" << endl;
+ return EXIT_FAILURE;
+ }
+}
diff --git a/rasodmg/test/deletecollection.cc b/rasodmg/test/deletecollection.cc
new file mode 100644
index 0000000..6cade1e
--- /dev/null
+++ b/rasodmg/test/deletecollection.cc
@@ -0,0 +1,720 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ * SOURCE: deletecollection.cc
+ *
+ * MODULE: rasodmg
+ *
+ * PURPOSE:
+ *
+ *
+ ************************************************************/
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#include "raslib/template_inst.hh"
+#endif
+
+#ifdef __VISUALC__
+#include <strstrea.h>
+#else
+#include <strstream.h>
+#endif
+
+#include <iostream>
+#include <iomanip.h>
+#include <string.h>
+#include <fstream.h>
+
+#include <math.h>
+
+#ifdef __VISUALC__
+ #define __EXECUTABLE__
+#endif
+
+#include "include/basictypes.hh"
+#include "raslib/type.hh"
+#include "rasodmg/storagelayout.hh"
+#include "rasodmg/alignedtiling.hh"
+
+#ifdef __VISUALC__
+ #undef __EXECUTABLE__
+#endif
+
+static int INIT = 0;
+
+static long minNo = 0;
+static long maxNo = 0;
+static ifstream fileStream;
+
+r_ULong initWithCounter( const r_Point& /*pt*/ )
+{
+ return INIT++;
+}
+
+
+r_Char initWithCounterChar( const r_Point& /*pt*/ )
+{
+ return (r_Char) INIT++;
+}
+
+
+r_UShort initWithCounterUShort( const r_Point& /*pt*/ )
+{
+ return (r_UShort) INIT++;
+}
+
+
+
+r_ULong initWithCrossfoot( const r_Point& pt )
+{
+ r_ULong value=0;
+
+ for( r_Dimension i=0; i< pt.dimension(); i++ )
+ value += (r_ULong)pt[i];
+
+ return value;
+}
+
+
+r_ULong initWithCoordinates( const r_Point& pt )
+{
+ r_ULong value=0;
+ r_ULong factor=1;
+
+ for( int i=pt.dimension()-1; i >= 0; i-- )
+ {
+ value += (r_ULong)(factor * pt[i]);
+ factor *= 100;
+ }
+
+ return value;
+}
+
+
+
+r_Char initWithCurve( const r_Point& pt )
+{
+ r_ULong value=0;
+
+ for( r_Dimension i=0; i < pt.dimension(); i++ )
+ value += (r_Char)( 255* sin( .25 * (float)pt[i] ) );
+
+ return (r_Char)value;
+}
+
+
+
+r_ULong initWithColorCube( const r_Point& pt )
+{
+ r_ULong value=0;
+
+ if( pt.dimension() == 3 )
+ value = ((unsigned long)(pt[0]) << 16) + ((unsigned long)(pt[1]) << 8) + (unsigned long)(pt[2]);
+
+ return value;
+}
+
+
+r_Char initWithRandomChar( const r_Point& /*pt*/ )
+{
+ // rand creates numbers between 0 and 32767
+ unsigned long number = rand();
+ double factor = (maxNo - minNo)/32767.0;
+
+ return (r_Char)(minNo + (number * factor));
+}
+
+r_ULong initWithRandomULong( const r_Point& /*pt*/ )
+{
+ // rand creates numbers between 0 and 32767
+ unsigned long number = rand();
+ double factor = (maxNo - minNo)/32767.0;
+
+ return (r_ULong)(minNo + (number * factor));
+}
+
+
+r_Char initFromFile( const r_Point& /*pt*/ )
+{
+ char ch;
+
+ if( fileStream.get(ch) )
+ return ch;
+ else
+ return 0;
+}
+
+/*
+r_Ref< r_Marray<r_ULong> > readFile( r_Database& db )
+{
+ r_Ref< r_Marray<r_ULong> > image;
+ r_Minterval domain(3);
+ long dx, dy, dz, depth, cx, cy, cz;
+ int i;
+
+ ifstream fileStream( "hw8.full.vol" );
+ if( !fileStream )
+ {
+ cout << "Error: File not found." << endl;
+ exit(-1);
+ }
+
+ // read the first 16 bytes
+ char charDummy;
+ for( i=0; i<16; i++ )
+ fileStream >> charDummy;
+
+ dx = 256;
+ dy = 256;
+ dz = 20;
+ depth = 8;
+
+ domain << r_Sinterval( 0l, (long)(dx-1) ) << r_Sinterval( 0l, (long)(dy-1) ) << r_Sinterval( 0l, (long)(dz-1) );
+
+ cout << domain << "... "; cout.flush();
+
+ image = new( &db ) r_Marray<r_ULong>( domain );
+
+ unsigned long* dataPtr = (unsigned long*)image->get_array();
+
+ r_Point pt(3);
+
+ // for( i=0; i<dx*dy*(221-dz); i++ )
+ // fileStream >> charDummy;
+
+ for( cz = 0; cz < dz; cz++ )
+ {
+ pt[2] = cz;
+ for( cy = 0; cy < dy; cy++ )
+ {
+ pt[1] = cy;
+ for( cx = 0; cx < dx; cx++ )
+ {
+ unsigned char ch;
+ fileStream.get(ch);
+
+ pt[0] = cx;
+ dataPtr[domain.cell_offset(pt)] = ((unsigned long)ch << 16) +
+ ((unsigned long)ch << 8) +
+ ((unsigned long)ch);
+ }
+ }
+ }
+
+ fileStream.close();
+
+ return image;
+}
+*/
+
+
+void printColl( r_Ref< r_Set< r_Ref< r_GMarray > > >& image_set, int output, int hexOutput )
+{
+ cout << "Collection" << endl;
+ cout << " Oid...................: " << image_set->get_oid() << endl;
+ cout << " Type Name.............: " << image_set->get_object_name() << endl;
+ cout << " Type Structure........: "
+ << ( image_set->get_type_structure() ? image_set->get_type_structure() : "<nn>" ) << endl;
+ cout << " Type Schema...........: " << flush;
+ if( image_set->get_type_schema() )
+ image_set->get_type_schema()->print_status( cout );
+ else
+ cout << "<nn>" << flush;
+ cout << endl;
+ cout << " Number of entries.....: " << image_set->cardinality() << endl;
+ cout << " Element Type Schema...: " << flush;
+ if( image_set->get_element_type_schema() )
+ image_set->get_element_type_schema()->print_status( cout );
+ else
+ cout << "<nn>" << flush;
+ cout << endl;
+
+ r_Iterator< r_Ref< r_GMarray > > iter = image_set->create_iterator();
+
+ cout << endl;
+ for ( int i=1 ; iter.not_done(); iter++, i++ )
+ {
+ // do not dereference the object
+ cout << "Image " << i << " oid: " << (*iter).get_oid() << endl;
+
+ if( output )
+ {
+ (*iter)->print_status( cout, hexOutput );
+ cout << endl;
+ }
+ }
+ cout << endl;
+}
+
+
+
+int checkArguments( int argc, char** argv, const char* searchText, int& optionValueIndex )
+{
+ int found = 0;
+ int i=1;
+
+ while( !found && i<argc )
+ found = !strcmp( searchText, argv[i++] );
+
+ if( found && i<argc && !strchr(argv[i],'-') )
+ optionValueIndex = i;
+ else
+ optionValueIndex = 0;
+
+ return found;
+}
+
+
+
+int main( int argc, char** argv )
+{
+ int optionValueIndex=0;
+ int testbed = 0;
+ unsigned long tileSize=0;
+ r_Minterval tileConfig;
+ int compressed=0;
+
+ char serverName[255];
+ char baseName[255];
+ char collName[255];
+ char setTypeName[255] = "";
+ char mddTypeName[255] = "";
+ char fileName[255]="";
+
+ if( argc < 4 || checkArguments( argc, argv, "-h", optionValueIndex ) )
+ {
+ cout << "Usage: test_insert3 server_name base_name collection_name [options]" << endl << endl;
+ cout << "Options: -h ... this help" << endl;
+ cout << " -settype <typename> ... type name used for creation of a new set." << endl;
+ cout << " -mddtype <typename> ... type name used for creation of a new mdd object." << endl;
+ cout << " -testbed ... turn on output for testbed" << endl;
+ cout << " -tileconf ... tile configuration" << endl;
+ cout << " -tilesize ... tile size" << endl;
+ cout << " -file <filename> ... file name used to read data from a file" << endl;
+ cout << " -compressed ... inserts MDD in compressed format" << endl;
+ cout << endl;
+ return 0;
+ }
+
+ strcpy( serverName, argv[1] );
+ strcpy( baseName, argv[2] );
+ strcpy( collName, argv[3] );
+
+ if( checkArguments( argc, argv, "-settype", optionValueIndex ) && optionValueIndex )
+ strcpy( setTypeName, argv[optionValueIndex] );
+
+ if( checkArguments( argc, argv, "-mddtype", optionValueIndex ) && optionValueIndex )
+ strcpy( mddTypeName, argv[optionValueIndex] );
+
+ testbed = checkArguments( argc, argv, "-testbed", optionValueIndex );
+
+ if( checkArguments( argc, argv, "-tileconf", optionValueIndex ) && optionValueIndex )
+ tileConfig = r_Minterval( argv[optionValueIndex] );
+
+ if( checkArguments( argc, argv, "-tilesize", optionValueIndex ) && optionValueIndex )
+ tileSize = strtoul( argv[optionValueIndex], (char **)NULL, 10 ) ;
+
+ if( checkArguments( argc, argv, "-file", optionValueIndex ) && optionValueIndex )
+ strcpy( fileName, argv[optionValueIndex] );
+
+ compressed = checkArguments( argc, argv, "-compressed", optionValueIndex );
+
+ cout << endl << endl;
+ cout << "Insertion of one MDD into the database" << endl;
+ cout << "======================================" << endl << endl;
+
+ r_Database db;
+ r_Transaction ta;
+ r_Ref< r_Set< r_Ref< r_GMarray > > > image_set;
+ r_Ref< r_GMarray > image;
+ r_Minterval domain;
+ r_Dimension dim;
+ r_Range low, high;
+ unsigned long initMode, initValue;
+
+ RGBPixel rgbValue = { 1, 2, 3 };
+
+ db.set_servername( serverName );
+
+ try
+ {
+ /*
+ cout << "MDD Initialization: 0 - Marray<r_ULong> with constant" << endl;
+ cout << " 1 - Marray<r_ULong> with counter" << endl;
+ cout << " 2 - Marray<r_ULong> with coordinates" << endl;
+ cout << " 3 - Marray<r_ULong> with crossfoot" << endl;
+ cout << " 4 - Marray<r_ULong> with color cube" << endl << endl;
+
+ cout << " 5 - Marray<r_Char> with constant" << endl;
+ cout << " 6 - insert RGBImage with constant" << endl;
+ cout << " 7 - Marray<r_Char> with 255*( sin(.25*x1) + ... + sin(.25*xn) )" << endl;
+
+ cout << " 8 - Marray<r_ULong> read a file (hw8.full.vol)" << endl;
+ cout << " 9 - Create just an empty collection of type Marray<r_ULong>" << endl;
+ cout << " 10 - Delete collection of type GMarray" << endl;
+ cout << " 11 - Delete an object of collection" << endl;
+
+ cout << " 13 - Marray<r_Char> with counter" << endl;
+ cout << " 14 - Marray<r_Char> with random numbers" << endl;
+ cout << " 15 - Marray<r_UShort> with counter" << endl;
+ cout << " 16 - Marray<r_ULong> with random numbers" << endl;
+ cout << " 17 - Marray<r_Boolean>" << endl;
+ cout << " 18 - Marray<r_Char> from file" << endl;
+
+ cin >> initMode;
+ cout << endl;
+ */
+ initMode = 10;
+
+ if( initMode == 18 )
+ {
+ fileStream.open( fileName );
+ if( !fileStream )
+ {
+ cout << "Error: File " << fileName << " not found." << endl;
+ exit(-1);
+ }
+ }
+
+ if( initMode == 0 || initMode == 5 || initMode == 17 )
+ {
+ cout << "Constant value : ";
+ cin >> initValue;
+ cout << endl;
+ }
+ if( initMode <= 7 || initMode >= 13 )
+ {
+ cout << "Number of dimensions : ";
+ cin >> dim;
+ cout << endl;
+
+ domain = r_Minterval(dim);
+
+ for( r_Dimension i = 1; i<=dim ; i++ )
+ {
+ cout << "Dimension " << setw(2) << i << " lower bound ";
+ cin >> low;
+ cout << " upper bound ";
+ cin >> high;
+
+ domain << r_Sinterval( low, high );
+ }
+
+ cout << endl;
+ }
+
+ if( initMode == 14 || initMode == 16 )
+ {
+ cout << "Minimum number : ";
+ cin >> minNo;
+ cout << endl;
+
+ cout << "Maximum number : ";
+ cin >> maxNo;
+ cout << endl;
+ }
+
+ cout << "Opening Database " << baseName << " on " << serverName << "... "; cout.flush();
+ db.open( baseName );
+ cout << "OK" << endl;
+
+ cout << "Starting Transaction ... " << flush;
+ ta.begin();
+ cout << "OK" << endl;
+
+ cout << "Opening the set ... " << flush;
+
+ if( initMode == 10 || initMode == 11 )
+ {
+ //
+ // get the set
+ //
+
+ try{
+ image_set = db.lookup_object( collName );
+ }
+ catch( r_Error &obj )
+ {
+ cout << "FAILED" << endl;
+ cout << obj.what() << endl;
+ return -1;
+ }
+
+ cout << "OK" << endl;
+
+ if( initMode == 10 )
+ {
+ // delete the set
+
+ if( !image_set.is_null() )
+ image_set.delete_object();
+ // delete image_set; (not implemented yet)
+ }
+ else
+ {
+ int imageNo=0;
+
+ printColl( image_set, 0, 0 );
+
+ cout << "Please enter the image number to delete: ";
+ cin >> imageNo;
+ cout << endl;
+
+ r_Iterator< r_Ref< r_GMarray > > iter = image_set->create_iterator();
+
+ for ( int i=1; iter.not_done() && i<imageNo; iter++, i++ );
+
+ if( imageNo && iter.not_done() )
+ {
+ image_set->remove_element( *iter );
+ cout << "MDD removed." << endl;
+ }
+ else
+ cout << "Number not valid." << endl << endl;
+ }
+ }
+ else
+ {
+ //
+ // get set
+ //
+
+ try{
+ image_set = db.lookup_object( collName );
+ }
+ catch( r_Error& /*obj*/ )
+ {
+ cout << "FAILED" << endl;
+ // cout << obj.what() << endl;
+
+ //
+ // set doesn't exist -> create the set
+ //
+
+ cout << "Create the set ... " << flush;
+
+ if( initMode == 5 || initMode == 7 || initMode == 13 || initMode == 14 || initMode == 18 )
+ {
+ if( !strlen( setTypeName ) )
+ strcpy( setTypeName, "GreySet" );
+
+ image_set = new( &db, setTypeName ) r_Set< r_Ref< r_Marray<r_Char> > >;
+ }
+ else if( initMode == 6 )
+ {
+ if( !strlen( setTypeName ) )
+ strcpy( setTypeName, "RGBSet" );
+
+ image_set = new( &db, setTypeName ) r_Set< r_Ref< r_Marray<RGBPixel> > >;
+ }
+ else if( initMode == 15 )
+ {
+ if( !strlen( setTypeName ) )
+ strcpy( setTypeName, "UShortSet" );
+
+ image_set = new( &db, setTypeName ) r_Set< r_Ref< r_Marray<r_UShort> > >;
+ }
+ else if( initMode == 17 )
+ {
+ if( !strlen( setTypeName ) )
+ strcpy( setTypeName, "BoolSet" );
+
+ image_set = new( &db, setTypeName ) r_Set< r_Ref< r_Marray<r_Boolean> > >;
+ }
+ else
+ {
+ if( !strlen( setTypeName ) )
+ strcpy( setTypeName, "ULongSet" );
+
+ image_set = new( &db, setTypeName ) r_Set< r_Ref< r_Marray<r_ULong> > >;
+ }
+
+ // create a name for the persistent set in order to be able to look it up again
+ db.set_object_name( *image_set, collName );
+ }
+
+ cout << " with type name " << setTypeName << " ... OK" << endl;
+
+ cout << "OId of the set is " << image_set->get_oid() << " ... " << endl;
+
+ if( initMode <= 9 || initMode >= 13 )
+ {
+ cout << "Creating an image ..." << flush;
+
+ // create storage layout object
+ r_Storage_Layout* stl = 0;
+ if( tileSize )
+ stl = new r_Storage_Layout( new r_Aligned_Tiling( tileConfig, tileSize ) );
+
+ if( compressed )
+ {
+ if( !stl )
+ stl = new r_Storage_Layout();
+
+ db.set_storage_format( r_ZLib );
+ }
+
+ // create the image
+ switch( initMode )
+ {
+ case 0:
+ if( !strlen( mddTypeName ) )
+ strcpy( mddTypeName, "ULongImage" );
+
+ image = new( &db, mddTypeName ) r_Marray<r_ULong>( domain, (r_ULong)initValue, stl );
+ break;
+ case 1:
+ if( !strlen( mddTypeName ) )
+ strcpy( mddTypeName, "ULongImage" );
+
+ image = new( &db, mddTypeName ) r_Marray<r_ULong>( domain, &initWithCounter, stl );
+ break;
+ case 2:
+ if( !strlen( mddTypeName ) )
+ strcpy( mddTypeName, "ULongImage" );
+
+ image = new( &db, mddTypeName ) r_Marray<r_ULong>( domain, &initWithCoordinates, stl );
+ break;
+ case 3:
+ if( !strlen( mddTypeName ) )
+ strcpy( mddTypeName, "ULongImage" );
+
+ image = new( &db, mddTypeName ) r_Marray<r_ULong>( domain, &initWithCrossfoot, stl );
+ break;
+ case 4:
+ if( !strlen( mddTypeName ) )
+ strcpy( mddTypeName, "ULongImage" );
+
+ image = new( &db, mddTypeName ) r_Marray<r_ULong>( domain, &initWithColorCube, stl );
+ break;
+ case 5:
+ if( !strlen( mddTypeName ) )
+ strcpy( mddTypeName, "GreyImage" );
+
+ image = new( &db, mddTypeName ) r_Marray<r_Char>( domain, (r_Char)initValue, stl );
+ break;
+ case 6:
+ if( !strlen( mddTypeName ) )
+ strcpy( mddTypeName, "RGBImage" );
+
+ image = new( &db, mddTypeName ) RGBImage( domain, rgbValue, stl );
+ break;
+ case 7:
+ if( !strlen( mddTypeName ) )
+ strcpy( mddTypeName, "GreyImage" );
+
+ image = new( &db, mddTypeName ) r_Marray<r_Char>( domain, &initWithCurve, stl );
+ break;
+ case 13:
+ if( !strlen( mddTypeName ) )
+ strcpy( mddTypeName, "GreyImage" );
+
+ image = new( &db, mddTypeName ) r_Marray<r_Char>( domain, &initWithCounterChar, stl );
+ break;
+ case 14:
+ if( !strlen( mddTypeName ) )
+ strcpy( mddTypeName, "GreyImage" );
+
+ image = new( &db, mddTypeName ) r_Marray<r_Char>( domain, &initWithRandomChar, stl );
+ break;
+ case 15:
+ if( !strlen( mddTypeName ) )
+ strcpy( mddTypeName, "UShortImage" );
+
+ image = new( &db, mddTypeName ) r_Marray<r_UShort>( domain, &initWithCounterUShort, stl );
+ break;
+ case 16:
+ if( !strlen( mddTypeName ) )
+ strcpy( mddTypeName, "ULongImage" );
+
+ image = new( &db, mddTypeName ) r_Marray<r_ULong>( domain, &initWithRandomULong, stl );
+ break;
+ case 17:
+ if( !strlen( mddTypeName ) )
+ strcpy( mddTypeName, "BoolImage" );
+
+ image = new( &db, mddTypeName ) r_Marray<r_Boolean>( domain, (r_Boolean)initValue, stl );
+ break;
+ case 18:
+ if( !strlen( mddTypeName ) )
+ strcpy( mddTypeName, "GreyImage" );
+
+ image = new( &db, mddTypeName ) r_Marray<r_Char>( domain, &initFromFile, stl );
+ break;
+ default:
+ if( !strlen( mddTypeName ) )
+ strcpy( mddTypeName, "ULongImage" );
+
+ image = new( &db, mddTypeName ) r_Marray<r_ULong>( domain, (r_ULong)0, stl );
+ }
+
+ cout << "OId of the new image is " << image->get_oid() << endl;
+
+ cout << "Inserting one image with domain " << domain << " into collection " << collName << "..." << flush;
+ // put in into the persistent list
+ image_set->insert_element( image );
+ cout << "OK" << endl << endl;
+
+ if( testbed )
+ {
+ cout << endl << "Testbed output:" << endl;
+ cout << "-- Testbed: set_oid=" << image_set->get_oid() << endl;
+ cout << "-- Testbed: image_oid=" << image->get_oid() << endl;
+ cout << endl;
+ }
+
+ }
+ }
+
+ try
+ {
+ cout << "Committing Transaction ... " << flush;
+ ta.commit();
+ cout << "OK" << endl;
+ }
+ catch( r_Error &obj )
+ {
+ cerr << obj.what() << endl;
+ return -1;
+ }
+
+ cout << "Closing Database ... " << flush;
+ db.close();
+ cout << "OK" << endl;
+
+ if( initMode == 18 )
+ fileStream.close();
+ }
+ catch( r_Error& errorObj )
+ {
+ cerr << errorObj.what() << endl;
+ return -1;
+ }
+
+ return 0;
+}
+
+
+
diff --git a/rasodmg/test/earth.ql b/rasodmg/test/earth.ql
new file mode 100644
index 0000000..5de6f1d
--- /dev/null
+++ b/rasodmg/test/earth.ql
@@ -0,0 +1,68 @@
+// This test evaluates the effort for internal operations.
+// Run on different servers with optimization of operations and
+// multidimensional operations turned on and off.
+
+// no operation
+
+select img[0:799,0:799]
+from earth1 as img
+
+// one MDD operation
+
+select img[0:799,0:799] + img[0:799,0:799]
+from earth1 as img
+
+// two MDD operations
+
+select img[0:799,0:799] + img[0:799,0:799] + img[0:799,0:799]
+from earth1 as img
+
+// three MDD operations
+
+select img[0:799,0:799] + img[0:799,0:799] + img[0:799,0:799] + img[0:799,0:799]
+from earth1 as img
+
+// four MDD operations
+
+select img[0:799,0:799] + img[0:799,0:799] + img[0:799,0:799] + img[0:799,0:799] + img[0:799,0:799]
+from earth1 as img
+
+// five MDD operations
+
+select img[0:799,0:799] + img[0:799,0:799] + img[0:799,0:799] + img[0:799,0:799] + img[0:799,0:799] + img[0:799,0:799]
+from earth1 as img
+
+// no operation
+
+select img[0:799,0:799]
+from earth1 as img
+
+// one unary operation
+
+select not(img[0:799,0:799])
+from earth1 as img
+
+// no operation
+
+select img[0:799,0:799]
+from earth1 as img
+
+// one binary operation with a constant (+)
+
+select img[0:799,0:799] + 10c
+from earth1 as img
+
+// two binary operations with a constant (+, *)
+
+select (img[0:799,0:799] + 10c) * 10c
+from earth1 as img
+
+// three binary operations with a constant (+, *, -)
+
+select ((img[0:799,0:799] + 10c) * 10c) - 10c
+from earth1 as img
+
+// four binary operations with a constant (+, *, -, /)
+
+select (((img[0:799,0:799] + 10c) * 10c) - 10c) / 10c
+from earth1 as img
diff --git a/rasodmg/test/earth_16.ql b/rasodmg/test/earth_16.ql
new file mode 100644
index 0000000..c53508a
--- /dev/null
+++ b/rasodmg/test/earth_16.ql
@@ -0,0 +1,41 @@
+// Selection of images out of a collection with 15 800x800x8bit
+// images. There is one image each with only 255, 254, 253 as a
+// value. And there is one image each with one value each out of
+// 250, 251, 252. No other image contains value greater than 249.
+
+// one img with some_cell
+
+SELECT img[0:252,0:252]
+FROM earth_16 as img
+WHERE some_cell ( img = 252c )
+
+// two imgs with some_cell
+
+SELECT img[0:252,0:252]
+FROM earth_16 as img
+WHERE some_cell ( img = 252c OR img = 251c )
+
+// three imgs with some_cell
+
+SELECT img[0:252,0:252]
+FROM earth_16 as img
+WHERE some_cell ( img = 252c OR img = 251c OR img = 250c )
+
+// one img with all_cell
+
+SELECT img[0:252,0:252]
+FROM earth_16 as img
+WHERE all_cell ( img >= 255c )
+
+// two imgs with all_cell
+
+SELECT img[0:252,0:252]
+FROM earth_16 as img
+WHERE all_cell ( img >= 254c )
+
+// three imgs with all_cell
+
+SELECT img[0:252,0:252]
+FROM earth_16 as img
+WHERE all_cell ( img >= 253c )
+
diff --git a/rasodmg/test/earth_32.ql b/rasodmg/test/earth_32.ql
new file mode 100644
index 0000000..67145be
--- /dev/null
+++ b/rasodmg/test/earth_32.ql
@@ -0,0 +1,41 @@
+// Selection of images out of a collection with 15 800x800x8bit
+// images. There is one image each with only 255, 254, 253 as a
+// value. And there is one image each with one value each out of
+// 250, 251, 252. No other image contains value greater than 249.
+
+// one img with some_cell
+
+SELECT img[0:252,0:252]
+FROM earth_32 as img
+WHERE some_cell ( img = 252c )
+
+// two imgs with some_cell
+
+SELECT img[0:252,0:252]
+FROM earth_32 as img
+WHERE some_cell ( img = 252c OR img = 251c )
+
+// three imgs with some_cell
+
+SELECT img[0:252,0:252]
+FROM earth_32 as img
+WHERE some_cell ( img = 252c OR img = 251c OR img = 250c )
+
+// one img with all_cell
+
+SELECT img[0:252,0:252]
+FROM earth_32 as img
+WHERE all_cell ( img >= 255c )
+
+// two imgs with all_cell
+
+SELECT img[0:252,0:252]
+FROM earth_32 as img
+WHERE all_cell ( img >= 254c )
+
+// three imgs with all_cell
+
+SELECT img[0:252,0:252]
+FROM earth_32 as img
+WHERE all_cell ( img >= 253c )
+
diff --git a/rasodmg/test/earth_64.ql b/rasodmg/test/earth_64.ql
new file mode 100644
index 0000000..31cec45
--- /dev/null
+++ b/rasodmg/test/earth_64.ql
@@ -0,0 +1,41 @@
+// Selection of images out of a collection with 15 800x800x8bit
+// images. There is one image each with only 255, 254, 253 as a
+// value. And there is one image each with one value each out of
+// 250, 251, 252. No other image contains value greater than 249.
+
+// one img with some_cell
+
+SELECT img[0:252,0:252]
+FROM earth_64 as img
+WHERE some_cell ( img = 252c )
+
+// two imgs with some_cell
+
+SELECT img[0:252,0:252]
+FROM earth_64 as img
+WHERE some_cell ( img = 252c OR img = 251c )
+
+// three imgs with some_cell
+
+SELECT img[0:252,0:252]
+FROM earth_64 as img
+WHERE some_cell ( img = 252c OR img = 251c OR img = 250c )
+
+// one img with all_cell
+
+SELECT img[0:252,0:252]
+FROM earth_64 as img
+WHERE all_cell ( img >= 255c )
+
+// two imgs with all_cell
+
+SELECT img[0:252,0:252]
+FROM earth_64 as img
+WHERE all_cell ( img >= 254c )
+
+// three imgs with all_cell
+
+SELECT img[0:252,0:252]
+FROM earth_64 as img
+WHERE all_cell ( img >= 253c )
+
diff --git a/rasodmg/test/gen_pattern.cc b/rasodmg/test/gen_pattern.cc
new file mode 100644
index 0000000..4ce3abc
--- /dev/null
+++ b/rasodmg/test/gen_pattern.cc
@@ -0,0 +1,248 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: gen_pattern.cc
+ *
+ * MODULE: rasodmg
+ *
+ * PURPOSE: generate patterns for r_StatTiling.
+ *
+ * COMMENTS:
+ * None
+*/
+
+/*
+ ATENTION: The format of the input file for using with this program is:
+
+ number_of_patterns minterval_domain
+ d_dim1 d_dim2 ... d_dimn
+ percentage minterval_pattern
+ ...
+
+ Example:
+
+ 1000 [1:800,1:600]
+ 10 10
+ 0.40 [10:600,30:300]
+ 0.60 [70:500,400:500]
+
+ Creates a file with 1000 patterns on a 800x600 domain.
+ The pixels are generated having borders with a maximum variation of
+ 10 pixels from the specified interest zones. And 2 interest zones
+ are specified, one for 40% of the patterns, another for 60%.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <iostream>
+#include <fstream.h>
+#include <time.h>
+#include "raslib/minterval.hh"
+#include "raslib/sinterval.hh"
+#include "raslib/dlist.hh"
+
+const int BUF_SIZE = 200;
+
+char* in_filename;
+char* out_filename;
+int total_patterns;
+int dim;
+int* delta;
+r_Minterval* domain;
+
+struct IArea
+{
+ r_Minterval iarea;
+ double percent;
+
+ IArea(r_Minterval& area, double percentage)
+ : iarea(area), percent(percentage)
+ {
+ }
+};
+
+DList<IArea*> IAreas;
+
+void parse(int argc, char** argv)
+{
+ if ((argc == 1) || ((argc == 2) && (strcmp(argv[1], "-h") == 0)))
+ {
+ cout << "Usage: " << argv[0] << " [input_filename] [output_filename]"
+ << endl;
+ exit(0);
+ }
+
+ if (argc != 3)
+ {
+ cout << "Usage: " << argv[0] << " [input_filename] [output_filename]"
+ << endl;
+ exit(0);
+ }
+
+ in_filename = argv[1];
+ out_filename = argv[2];
+}
+
+void get_specification()
+{
+ char buf[BUF_SIZE+1], buf2[BUF_SIZE+1];
+ double perc;
+
+ ifstream is(in_filename);
+ if (!is)
+ {
+ cout << "Could not open " << in_filename << "." << endl;
+ exit(0);
+ }
+
+ cout << "Reading parameters... " << endl;
+
+ is >> total_patterns;
+ is.getline(buf, BUF_SIZE);
+ domain = new r_Minterval(buf);
+ dim = domain->dimension();
+
+ if (total_patterns <= 0)
+ {
+ cout << "Invalid number of patterns: " << total_patterns << endl;
+ exit(0);
+ }
+
+ if (dim <= 0)
+ {
+ cout << "Invalid domain: " << *domain << endl;
+ delete domain;
+ exit(0);
+ }
+
+ cout << endl << "Patterns: " << total_patterns << endl;
+ cout << "Domain: " << *domain << endl;
+ cout << "Dimension: " << dim << " (";
+
+ delta = new int[dim];
+
+ for (int i=0; i<dim; i++)
+ {
+ is >> delta[i];
+ cout << "*";
+ }
+
+ cout << ")" << endl;
+ cout << "Reading patterns... (";
+
+ while (!is.eof())
+ {
+ is >> perc;
+ is.getline(buf, BUF_SIZE);
+ if (!is.bad() && sscanf(buf, "%s", buf2) == 1)
+ {
+ r_Minterval area(buf2);
+ IArea* ia = new IArea(area, perc);
+ IAreas += ia;
+
+ cout << "*";
+ }
+ else
+ break;
+ }
+
+ cout << ") -Done- " << endl;
+
+ is.close();
+}
+
+void generate_patterns()
+{
+ srand((unsigned int) time(NULL));
+
+
+ DListIterator<IArea*> it = IAreas.create_iterator();
+
+ ofstream os(out_filename);
+ if (!os)
+ {
+ cout << "Could not open " << out_filename << "." << endl;
+ exit(0);
+ }
+
+ while (it.not_done())
+ {
+ IArea* ia = *it;
+ ++it;
+
+ int total = (int)(ia->percent * total_patterns);
+
+ for (int i=0; i<total; i++)
+ {
+ os << "[";
+
+ for (int j=0; j<dim; j++)
+ {
+ long xmin = ia->iarea[j].low();
+ long xmax = ia->iarea[j].high();
+ long total = xmax-xmin;
+
+ if (delta[j] > total)
+ delta[j] = total;
+
+ long dxmin = (rand() % (2*delta[j] + 1)) - delta[j];
+ long dxmax = (rand() % (2*delta[j] + 1)) - delta[j];
+
+ xmin = xmin + dxmin;
+ if (xmin < (*domain)[j].low())
+ xmin = (*domain)[j].low() + ((*domain)[j].low() - xmin);
+
+ xmax = xmax + dxmax;
+ if (xmax > (*domain)[j].high())
+ xmax = (*domain)[j].high() - (xmax - (*domain)[j].high());
+
+ if (xmin > xmax)
+ {
+ long temp = xmin;
+ xmin = xmax;
+ xmax = temp;
+ }
+
+ os << xmin << ":" << xmax;
+
+ if (j != dim-1)
+ os << ",";
+ }
+
+ os << "]" << endl;
+ }
+ }
+
+ delete [] delta;
+ delete domain;
+}
+
+int main(int argc, char** argv)
+{
+ parse(argc, argv);
+ get_specification();
+ generate_patterns();
+
+ return 0;
+}
diff --git a/rasodmg/test/gen_query.pl b/rasodmg/test/gen_query.pl
new file mode 100644
index 0000000..aa5cf87
--- /dev/null
+++ b/rasodmg/test/gen_query.pl
@@ -0,0 +1,116 @@
+#!/usr/local/dist/bin/perl -w
+# use this one on Linux
+#!/usr/bin/perl -w
+
+# This program generates query files for use with test_benchmark. It
+# generates all files needed for executing the measurements specified
+# in the PhD thesis. It is not too generic, most of the things are
+# hardcoded.
+
+# each query is repeated 20 times
+$repeat = 20;
+# the collections which are used.
+@mdd = ( tomo_cubed, tomo_cubed_16, tomo_cubed_64, tomo_sliced );
+# the file name suffixes used for the collections
+@suffixes = ( _32, _16, _64, _s );
+# the selectivities tested for each collection
+@selectivity = ( .5, 1, 2, 5, 10, 20, 50 );
+# the filenames used to store the results
+
+sub calcQueryBox($$$$$$$$$);
+sub randNum($$);
+# initialize rand()
+srand();
+
+sub randNum($$)
+{
+ my ($l, $h) = @_;
+
+ return int ( $l + rand()*($h-$l) );
+}
+
+# this function calculates a random query box given the spatial
+#
+sub calcQueryBox($$$$$$$$$)
+{
+ my ( $xl, $xh, $yl, $yh, $zl, $zh, $xd, $yd, $zd ) = @_;
+
+ $x1 = randNum( $xl, $xh - $xd + 1);
+ $x2 = $x1 + ( $xd - 1 > 0 ? $xd - 1 : 0 );
+ $y1 = randNum( $yl, $yh - $yd + 1);
+ $y2 = $y1 + ( $yd - 1 > 0 ? $yd - 1 : 0 );
+ $z1 = randNum( $zl, $zh - $zd + 1);
+ $z2 = $z1 + ( $zd - 1 > 0 ? $zd - 1 : 0 );
+
+ return "[$x1:$x2, $y1:$y2, $z1:$z2]";
+}
+
+$headerStr = "
+// Testing acces to tomo_cubed with moving query box on different
+// selectivities.
+";
+
+foreach $tomo (@mdd)
+{
+ $suffix = shift @suffixes;
+ $fName1 = "tcubemov" . $suffix . ".ql";
+ $fName2 = "tcubeavg" . $suffix . ".ql";
+ open(QUERY1,">$fName1");
+ open(QUERY2,">$fName2");
+ print QUERY1 "$headerStr\n\n";
+ print QUERY2 "$headerStr\n\n";
+ foreach $sel (@selectivity)
+ {
+ $dx = $dy = int ( ($sel/100)**(1/3) * 256 );
+ $dz = int ( ($sel/100)**(1/3) * 154 );
+ # adapt query box for better fit
+ if(++$dx * $dy * $dz <= $sel/100*256*256*154) {
+ if($dx * ++$dy * $dz <= $sel/100*256*256*154) {
+ if($dx * $dy * ++$dz <= $sel/100*256*256*154) {
+ }
+ else {
+ $dz--;
+ }
+ }
+ else {
+ $dy--;
+ }
+ }
+ else {
+ $dx--;
+ }
+ for ($i = 1; $i <= $repeat; $i++) {
+ $qBox = calcQueryBox( 0, 255, 0, 255, 0, 153, $dx, $dy, $dz );
+ # print Query
+ print QUERY1 "// [$sel]: $qBox\n";
+ print QUERY2 "// [$sel]: $qBox\n";
+ print QUERY1 "SELECT img$qBox\nFROM $tomo AS img\n";
+ print QUERY2 "SELECT avg_cells(img$qBox)\nFROM $tomo AS img\n";
+ }
+ }
+}
+
+@suffixes = ( _32, _16, _64, _s );
+
+foreach $tomo (@mdd)
+{
+ $suffix = shift @suffixes;
+ $fName1 = "tslicemov" . $suffix . ".ql";
+ $fName2 = "tsliceavg" . $suffix . ".ql";
+ open(QUERY1,">$fName1");
+ open(QUERY2,">$fName2");
+ print QUERY1 "$headerStr\n\n";
+ print QUERY2 "$headerStr\n\n";
+ foreach $sel (@selectivity)
+ {
+ $dx = int ( ($sel/100) * 256 );
+ for ($i = 1; $i <= $repeat; $i++) {
+ $qBox = calcQueryBox( 0, 255, 0, 255, 0, 153, $dx, 256, 154 );
+ # print Query
+ print QUERY1 "// [$sel]: $qBox\n";
+ print QUERY2 "// [$sel]: $qBox\n";
+ print QUERY1 "SELECT img$qBox\nFROM $tomo AS img\n";
+ print QUERY2 "SELECT avg_cells(img$qBox)\nFROM $tomo AS img\n";
+ }
+ }
+}
diff --git a/rasodmg/test/gen_rollup.pl b/rasodmg/test/gen_rollup.pl
new file mode 100644
index 0000000..a3d60e0
--- /dev/null
+++ b/rasodmg/test/gen_rollup.pl
@@ -0,0 +1,209 @@
+#!/usr/local/dist/bin/perl
+
+$repeat = 20;
+
+sub randNum($$);
+# initialize rand()
+srand();
+
+sub randNum
+{
+ my ($l, $h) = @_;
+
+ return int ( $l + rand()*($h-$l) );
+}
+
+sub rollZ
+{
+ my $tomo = @_[0];
+ for ($i = 1; $i <= $repeat; $i++) {
+ $start = randNum(0, 153-6);
+ print "// [\"z\"] $tomo [*:*, *:*, $start:";
+ print $start + 6;
+ print "]\n";
+ print "SELECT img[*:*,*:*,$start]";
+ for ($j = $start + 1; $j <= $start + 6; $j++) {
+ print "+img[*:*,*:*,$j]";
+ }
+ print "\nFROM $tomo as img\n";
+ }
+}
+
+sub rollY
+{
+ my $tomo = @_[0];
+ for ($i = 1; $i <= $repeat; $i++) {
+ $start = randNum(0, 255-6);
+ print "// [\"y\"] $tomo [*:*, $start:";
+ print $start + 6;
+ print ", *:*]\n";
+ print "SELECT img[*:*,$start,*:*]";
+ for ($j = $start + 1; $j <= $start + 6; $j++) {
+ print "+img[*:*,$j,*:*]";
+ }
+ print "\nFROM $tomo as img\n";
+ }
+}
+
+sub rollX
+{
+ my $tomo = @_[0];
+ for ($i = 1; $i <= $repeat; $i++) {
+ $start = randNum(0, 255-6);
+ print "// [\"x\"] $tomo [$start:";
+ print $start + 6;
+ print ",*:*,*:*]\n";
+ print "SELECT img[$start,*:*,*:*]";
+ for ($j = $start + 1; $j <= $start + 6; $j++) {
+ print "+img[$j,*:*,*:*]";
+ }
+ print "\nFROM $tomo as img\n";
+ }
+}
+
+sub SQLrollX
+{
+ my $tomo = shift;
+
+ for($i = 1; $i <= $repeat; $i++)
+ {
+ $start = randNum(0, 153-6);
+ $end = $start + 6;
+ print "
+--#COMMENT BETWEEN $start AND $end
+
+SELECT y, z, sum(val)
+FROM $tomo
+WHERE x BETWEEN $start AND $end
+GROUP BY y, z
+;
+ ";
+
+
+ }
+}
+
+sub SQLrollY
+{
+ my $tomo = shift;
+
+ for($i = 1; $i <= $repeat; $i++)
+ {
+ $start = randNum(0, 255-6);
+ $end = $start + 6;
+ print "
+--#COMMENT BETWEEN $start AND $end
+
+SELECT x, z, sum(val)
+FROM $tomo
+WHERE y BETWEEN $start AND $end
+GROUP BY x, z
+;
+ ";
+
+
+ }
+}
+
+sub SQLrollZ
+{
+ my $tomo = shift;
+
+ for($i = 1; $i <= $repeat; $i++)
+ {
+ $start = randNum(0, 255-6);
+ $end = $start + 6;
+ print "
+--#COMMENT BETWEEN $start AND $end
+
+SELECT x, y, sum(val)
+FROM $tomo
+WHERE z BETWEEN $start AND $end
+GROUP BY x, y
+;
+ ";
+
+
+ }
+}
+
+sub genRollXYZ
+{
+ $headerStr = "
+// Testing roll up operations on different axes. It adds seven
+// consecutive slices along the corresponding Axis with a random
+// starting point on all four tomos..
+
+";
+
+ @mdd = ( tomo_sliced, tomo_cubed_16, tomo_cubed, tomo_cubed_64 );
+ foreach $tomo (@mdd)
+ {
+ rollX($tomo);
+ rollY($tomo);
+ rollZ($tomo);
+ };
+}
+
+sub genRollZ
+{
+ $headerStr = "
+// Testing roll up operations on different tomos. It adds seven
+// consecutive slices along the z-Axis with a random starting
+// point.
+
+";
+
+ @mdd = ( tomo_sliced, tomo_cubed, tomo_cubed_16, tomo_cubed_64 );
+ foreach $tomo (@mdd)
+ {
+ rollZ($tomo);
+ };
+}
+
+sub genSQLRollX
+{
+ $tomo = "tomo";
+
+ $headerStr = "
+-- tomo_rollX.sql
+-- tests rolling up tomo along x-axes.
+
+--#SET PERF_DETAIL 1 ROWS_FETCH -1 ROWS_OUT 0
+
+";
+ print $headerStr;
+ SQLrollX($tomo);
+}
+
+sub genSQLRollY
+{
+ $tomo = "tomo";
+
+ $headerStr = "
+-- tomo_rollY.sql
+-- tests rolling up tomo along y-axes.
+
+--#SET PERF_DETAIL 1 ROWS_FETCH -1 ROWS_OUT 0
+
+";
+ print $headerStr;
+ SQLrollY($tomo);
+}
+
+sub genSQLRollZ
+{
+ $tomo = "tomo";
+
+ $headerStr = "
+-- tomo_rollZ.sql
+-- tests rolling up tomo along z-axes.
+
+--#SET PERF_DETAIL 1 ROWS_FETCH -1 ROWS_OUT 0
+
+";
+ print $headerStr;
+ SQLrollZ($tomo);
+}
+
+genSQLRollX();
diff --git a/rasodmg/test/gen_s2k.pl b/rasodmg/test/gen_s2k.pl
new file mode 100644
index 0000000..6fd6fba
--- /dev/null
+++ b/rasodmg/test/gen_s2k.pl
@@ -0,0 +1,65 @@
+#!/usr/local/dist/bin/perl -w
+# use this one on Linux
+#!/usr/bin/perl -w
+
+# This program is an adaptation of gen_query for Sequoia 2000
+# queries.
+
+# IMPORTANT: At the moment this works only for collections
+# containing only one image. WHERE clauses on the OID have to
+# be added. Question: How do I get the OIDs? Probably have to
+# store them in the insertion program.
+
+# each query is repeated 40 times
+$repeat = 40;
+
+sub calcQueryBox($$$$$$);
+sub randNum($$);
+# initialize rand()
+srand();
+
+sub randNum($$)
+{
+ my ($l, $h) = @_;
+
+ return int ( $l + rand()*($h-$l) );
+}
+
+# this function calculates a random query box given the spatial
+# domain of the MDD and the extent of the query box
+sub calcQueryBox($$$$$$)
+{
+ my ( $xl, $xh, $yl, $yh, $xd, $yd ) = @_;
+
+ $x1 = randNum( $xl, $xh - $xd + 1);
+ $x2 = $x1 + ( $xd - 1 > 0 ? $xd - 1 : 0 );
+ $y1 = randNum( $yl, $yh - $yd + 1);
+ $y2 = $y1 + ( $yd - 1 > 0 ? $yd - 1 : 0 );
+
+ return "[$x1:$x2, $y1:$y2]";
+}
+
+$headerStr = "
+// Testing acces to s2k with a moving query box and a random band
+
+";
+
+open(QUERY1,">s2k.ql");
+
+print QUERY1 $headerStr;
+
+for ($i = 1; $i <= $repeat; $i++) {
+ $qBox = calcQueryBox( 0, 2599, 0, 1599, 200, 200 );
+ $band = randNum(1,5);
+ # print Query
+ print QUERY1 "// [Query 2]: $qBox\n";
+ print QUERY1 "SELECT img$qBox.band$band\nFROM s2k AS img\n";
+}
+
+for ($i = 1; $i <= $repeat; $i++) {
+ $qBox = calcQueryBox( 0, 2599, 0, 1599, 200, 200 );
+ $band = randNum(1,5);
+ # print Query
+ print QUERY1 "// [Query 3]: $qBox\n";
+ print QUERY1 "SELECT (1l*img$qBox.band1 + img$qBox.band2 +\n img$qBox.band3 + img$qBox.band4 +\n img$qBox.band5) / 5\nFROM s2k AS img\n";
+}
diff --git a/rasodmg/test/init_fast_collection.pl b/rasodmg/test/init_fast_collection.pl
new file mode 100644
index 0000000..63b29da
--- /dev/null
+++ b/rasodmg/test/init_fast_collection.pl
@@ -0,0 +1,111 @@
+#!/usr/bin/perl -w
+
+my $COLLECTION="orthorgb";
+my $SERVER="zombie";
+my $YMIN=0;
+my $YMAX=4999;
+my $XMIN=0;
+my $XMAX=4999;
+my $SCALELEVELS=8;
+my $IMGTYPE="RGB";#or "GREY"
+my $STORAGEFORMAT="Array";
+my $TRANSFERFORMAT="Array";
+my $transferWidth=2000;
+$transferWidth=int($transferWidth/(2**$SCALELEVELS))*(2**$SCALELEVELS);
+print "#transfer width $transferWidth\n";
+my $transferHeight=2000;
+$transferHeight=int($transferHeight/(2**$SCALELEVELS))*(2**$SCALELEVELS);
+print "#transfer height $transferHeight\n";
+my $i=0;
+my $currentCollection=$COLLECTION;
+my $currentXMin=$XMIN;
+my $currentYMin=$YMIN;
+my $currentXMax=$XMIN + $transferWidth;
+$currentXMax=min($XMAX, $currentXMax);
+my $currentYMax=$YMIN + $transferHeight;
+$currentYMax=min($YMAX, $currentYMax);
+my $colltype;
+my $mddtype;
+my $conversiontype;
+my $scaleLevel=2;
+my $command;
+my $scaleString;
+my $domain;
+
+sub max {
+ my $currentMax = shift;
+ my $next = shift;
+ if ($currentMax > $next)
+ {
+ return $currentMax;
+ }
+ else {
+ return $next;
+ }
+ };
+
+sub min {
+ my $currentMax = shift;
+ my $next = shift;
+ if ($currentMax > $next)
+ {
+ return $next;
+ }
+ else {
+ return $currentMax;
+ }
+ };
+
+if ($IMGTYPE eq "RGB")
+ {
+ $colltype="RGBSet";
+ $mddtype="RGBImage";
+ $conversiontype="RGBPixel";
+ }
+else {
+ if ($IMGTYPE eq "RGB")
+ {
+ $colltype="GreySet";
+ $mddtype="GreyImage";
+ $conversiontype="char";
+ }
+ else {
+ die "Unknown image type: $IMGTYPE\n";
+ }
+ }
+for ($i=1; $i < $SCALELEVELS + 1; $i++)
+ {
+ $currentCollection = $COLLECTION . "_" . int($i);
+ $scaleString .= "$currentCollection:$scaleLevel";
+ if ($i != $SCALELEVELS)
+ {
+ $scaleString .= ";";
+ }
+ $scaleLevel *= 2;
+ }
+while ($currentXMax <= $XMAX)
+ {
+ while ($currentYMax <= $YMAX)
+ {
+ $domain = "[$currentXMin:" . ($currentXMax - 1) . ",$currentYMin:" . ($currentYMax - 1) . "]";
+ $command = "system_update -s $SERVER --collection $COLLECTION -t --colltype $colltype --mddtype $mddtype --storageformat $STORAGEFORMAT --transferformat $TRANSFERFORMAT --scalelevels \"$scaleString\" --mdddomain \"$domain\"";
+ print "$command\n";
+ if ($currentYMax == $YMAX)
+ {
+ last;
+ }
+ $currentYMax += $transferHeight;
+ $currentYMax = min($currentYMax, $YMAX);
+ $currentYMin += $transferHeight;
+ };
+ if ($currentXMax == $XMAX)
+ {
+ last;
+ }
+ $currentXMin += $transferWidth;
+ $currentXMax += $transferWidth;
+ $currentXMax = min($currentXMax, $XMAX);
+ $currentYMin = $YMIN;
+ $currentYMax = $YMIN + $transferHeight;
+ $currentYMax = min($YMAX, $currentYMax);
+ };
diff --git a/rasodmg/test/polytest.poly b/rasodmg/test/polytest.poly
new file mode 100644
index 0000000..0d1c648
--- /dev/null
+++ b/rasodmg/test/polytest.poly
@@ -0,0 +1,3 @@
+[ 3430000, 5720000];
+[ 3460000, 5750000][ 3460000, 5750000][ 3460000, 5750000];
+
diff --git a/rasodmg/test/rasql.cc b/rasodmg/test/rasql.cc
new file mode 100644
index 0000000..c43eb63
--- /dev/null
+++ b/rasodmg/test/rasql.cc
@@ -0,0 +1,126 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: system_basic.cc
+ *
+ * MODULE: rasodmg/test
+ *
+ * COMMENTS:
+ * None
+*/
+
+static const char rcsid[] = "@(#)rasodmg/test,rasql: $Id: rasql.cc,v 1.5 2002/05/25 14:29:15 coman Exp $";
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <iostream>
+#include <fstream>
+#include <stdio.h>
+#include "readln.hh"
+#include "rasql.hh"
+
+static bool noMore = false;
+
+
+void logo() {
+ std::cout << "RasQL v0.1, (c) 2001 active knowledge GmbH." << std::endl;
+ if(noMore)
+ std::cout << "Option: no more" << std::endl;
+ std::cout << std::endl;
+}
+
+bool toFile(char *s) {
+ std::ofstream os(file_name);
+ if(!os)
+ return false;
+ os << s;
+ return true;
+}
+
+void filter(void) {
+ execlp(filter_prog, filter_prog, filter_params, 0);
+ perror("exec");
+ exit(1);
+}
+
+
+void query(void) {
+ execlp(query_prog, query_prog,
+ server_param, server_name,
+ base_param, base_name,
+ file_param, file_name,
+ 0);
+ perror("exec");
+ exit(1);
+}
+
+bool process(char* s) {
+ int p[2];
+ if(strcmp(s, "exit") == 0)
+ return false;
+ if(strcmp(s, "quit") == 0)
+ return false;
+
+ if(!toFile(s)) {
+ std::cerr << "toFile: error opening file " << file_name << std::endl;
+ return true;
+ }
+
+ if(noMore) {
+ if(!fork())
+ query();
+ }
+ else {
+ pipe(p);
+ if(!fork()) {
+ close(p[1]);
+ dup2(p[0], 0);
+ filter();
+ }
+ else if(!fork()) {
+ close(p[0]);
+ dup2(p[1], 1);
+ query();
+ }
+ else {
+ close(p[0]);
+ close(p[1]);
+ }
+ }
+
+ while(wait(0) > 0);
+ return true;
+}
+
+int main(int argc, char **argv) {
+ if(--argc && strcmp(*(++argv), "-nomore") == 0)
+ noMore = true;
+
+ logo();
+
+ ReadLn l(process, "RasQL> ");
+ l.loop();
+ std::cout << std::endl;
+ return 0;
+} \ No newline at end of file
diff --git a/rasodmg/test/rasql.hh b/rasodmg/test/rasql.hh
new file mode 100644
index 0000000..0f9c1a2
--- /dev/null
+++ b/rasodmg/test/rasql.hh
@@ -0,0 +1,38 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#ifndef __RASQL_HH__
+#define __RASQL_HH__
+
+const char* query_prog = "test_query";
+const char* server_param = "-server";
+const char* server_name = "localhost";
+const char* base_param = "-base";
+const char* base_name = "RASBASE";
+const char* file_param = "-file";
+const char* file_name = "/tmp/tmp.ql";
+
+const char* filter_prog = "less";
+const char* filter_params = "-Fn";
+
+#endif
diff --git a/rasodmg/test/readln.cc b/rasodmg/test/readln.cc
new file mode 100644
index 0000000..6d2d928
--- /dev/null
+++ b/rasodmg/test/readln.cc
@@ -0,0 +1,64 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#include "readln.hh"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <readline/readline.h>
+#include <readline/history.h>
+
+extern "C" int beep(int, int);
+
+ReadLn::ReadLn(bool (*f)(char*), char* p, bool useTab): worker(f), prompt(p), line(0) {
+ if(!useTab)
+ rl_bind_key((int)'\t', beep);
+}
+
+ReadLn::~ReadLn() {}
+
+void ReadLn::loop() {
+ do {
+ initLn();
+
+ if((line = readline(prompt)) != 0 && *line) {
+ add_history(line);
+ if(!worker(line))
+ break;
+ }
+
+ } while(line);
+}
+
+void ReadLn::initLn() {
+ if(line) {
+ free(line);
+ line = 0;
+ }
+}
+
+int beep(int, int) {
+ putchar( '\a');
+ return 1; // meaningless, just for prototype
+} \ No newline at end of file
diff --git a/rasodmg/test/readln.hh b/rasodmg/test/readln.hh
new file mode 100644
index 0000000..4f5a1bd
--- /dev/null
+++ b/rasodmg/test/readln.hh
@@ -0,0 +1,45 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#ifndef __READLN_HH__
+#define __READLN_HH__
+
+class ReadLn {
+public:
+// typedef void (* worker_t)(const char *);
+
+ ReadLn(bool (*f)(char*) = 0, char* p = "> ", bool useTab = false);
+ ~ReadLn();
+ void loop();
+
+protected:
+ void initLn();
+
+private:
+ char* prompt;
+ bool (*worker)(char*);
+ char *line;
+
+};
+
+#endif
diff --git a/rasodmg/test/runbm.sh b/rasodmg/test/runbm.sh
new file mode 100644
index 0000000..e0366fb
--- /dev/null
+++ b/rasodmg/test/runbm.sh
@@ -0,0 +1,94 @@
+#!/usr/bin/ksh
+
+echo "runbm started."
+
+# defaults if no parameters are given
+RUNS='-n 10'
+basename='NorbertBase'
+
+# parse command line
+while [[ 1 -eq 1 ]]; do
+ if [[ $1 = '-n' ]]; then
+ shift; RUNS="-n $1"; shift;
+ elif [[ $1 = '-e' ]]; then
+ shift; RUNS="-e $1"; shift;
+ elif [[ $1 = '-base' ]]; then
+ shift; basename=$1; shift;
+ else
+ break;
+ fi
+done
+
+QLFILES=${@}
+# optionally add different servers here
+RASSERVERS='rasserver'
+
+BMTIME=$(date +%d%b%y_%H-%M)
+
+mkdir bm_$BMTIME
+
+# shutdown server in case it is already running
+$RMANBASE/server/rascontrol $HOST down
+
+for servername in $RASSERVERS; do
+ for qlname in $QLFILES; do
+ echo "$servername $qlname:"
+ # take time when this test started
+ QLTIME=$(date +%d%b%y_%H-%M)
+
+ filename=$(pwd)/bm_$BMTIME/bm${servername#rasserver}_${qlname%\.ql}
+
+ # start server
+
+ # should be like the following line, but rasserver does not like long
+ # filenames :-(
+ # $RMANBASE/server/$servername -bl 4 -l $filename\_server.log -b $filename\_server.bm -d $filename\_server.dbg &
+
+ # workaround
+ $RMANBASE/server/$servername -bl 4 -notimeout &
+ # store PID
+ RMANPID=$!
+
+ # wait till it has finished
+ sleep 30
+
+ # write information file
+ touch $filename\.inf
+ echo "Filename of rasserver used: $servername" > $filename\.inf
+ echo "Host: $HOST" >> $filename\.inf
+ echo "Time: $QLTIME" >> $filename\.inf
+ echo "Output of what on rasserver:" >> $filename\.inf
+ what $RMANBASE/server/$servername >> $filename\.inf
+ echo "Output of what on test_benchmark:" >> $filename\.inf
+ what $RMANBASE/rasodmg/test/test_benchmark >> $filename\.inf
+
+ # run benchmark
+ $RMANBASE/rasodmg/test/test_benchmark $RUNS $HOST $basename $qlname
+
+ # save client information
+ mv client.bm $filename\_client.bm
+ mv client.log $filename\_client.log
+ mv client.dbg $filename\_client.dbg
+
+ # shutdown server
+ $RMANBASE/server/rascontrol $HOST down
+ # just to be sure
+ kill $RMANPID 1>/dev/null 2>&1
+
+ # workaround
+ mv server.log $filename\_server.log
+ mv server.bm $filename\_server.bm
+ mv server.dbg $filename\_server.dbg
+
+ # store queryfile
+ cp $qlname $filename\.ql
+
+ # create slk file for Excel
+ $RMANBASE/utilities/bm2sylk.pl $filename\_client.bm $filename\_server.bm > $filename.slk
+
+ done
+done
+
+echo "runbm finished."
+
+exit
diff --git a/rasodmg/test/small_16.ql b/rasodmg/test/small_16.ql
new file mode 100644
index 0000000..877c6e6
--- /dev/null
+++ b/rasodmg/test/small_16.ql
@@ -0,0 +1,42 @@
+// Selection of images out of a collection with 15 800x800x8bit
+// images. There is one image each with only 255, 254, 253 as a
+// value. And there is one image each with one value each out of
+// 250, 251, 252. No other image contains value greater than 249.
+
+// one img with some_cell
+
+SELECT img[0:252,0:252]
+FROM earth_16 as img
+WHERE some_cell ( img[700:799,300:399] = 252c )
+
+// two imgs with some_cell
+
+SELECT img[0:252,0:252]
+FROM earth_16 as img
+WHERE some_cell ( img[700:799,300:399] = 252c OR img[700:799,300:399] = 251c )
+
+// three imgs with some_cell
+
+SELECT img[0:252,0:252]
+FROM earth_16 as img
+WHERE some_cell ( img[700:799,300:399] = 252c OR img[700:799,300:399] = 251c
+ OR img[700:799,300:399] = 250c )
+
+// one img with all_cell
+
+SELECT img[0:252,0:252]
+FROM earth_16 as img
+WHERE all_cell ( img[700:799,300:399] >= 255c )
+
+// two imgs with all_cell
+
+SELECT img[0:252,0:252]
+FROM earth_16 as img
+WHERE all_cell ( img[700:799,300:399] >= 254c )
+
+// three imgs with all_cell
+
+SELECT img[0:252,0:252]
+FROM earth_16 as img
+WHERE all_cell ( img[700:799,300:399] >= 253c )
+
diff --git a/rasodmg/test/small_32.ql b/rasodmg/test/small_32.ql
new file mode 100644
index 0000000..ddf52b7
--- /dev/null
+++ b/rasodmg/test/small_32.ql
@@ -0,0 +1,42 @@
+// Selection of images out of a collection with 15 800x800x8bit
+// images. There is one image each with only 255, 254, 253 as a
+// value. And there is one image each with one value each out of
+// 250, 251, 252. No other image contains value greater than 249.
+
+// one img with some_cell
+
+SELECT img[0:252,0:252]
+FROM earth_32 as img
+WHERE some_cell ( img[700:799,300:399] = 252c )
+
+// two imgs with some_cell
+
+SELECT img[0:252,0:252]
+FROM earth_32 as img
+WHERE some_cell ( img[700:799,300:399] = 252c OR img[700:799,300:399] = 251c )
+
+// three imgs with some_cell
+
+SELECT img[0:252,0:252]
+FROM earth_32 as img
+WHERE some_cell ( img[700:799,300:399] = 252c OR img[700:799,300:399] = 251c
+ OR img[700:799,300:399] = 250c )
+
+// one img with all_cell
+
+SELECT img[0:252,0:252]
+FROM earth_32 as img
+WHERE all_cell ( img[700:799,300:399] >= 255c )
+
+// two imgs with all_cell
+
+SELECT img[0:252,0:252]
+FROM earth_32 as img
+WHERE all_cell ( img[700:799,300:399] >= 254c )
+
+// three imgs with all_cell
+
+SELECT img[0:252,0:252]
+FROM earth_32 as img
+WHERE all_cell ( img[700:799,300:399] >= 253c )
+
diff --git a/rasodmg/test/small_64.ql b/rasodmg/test/small_64.ql
new file mode 100644
index 0000000..dea4779
--- /dev/null
+++ b/rasodmg/test/small_64.ql
@@ -0,0 +1,42 @@
+// Selection of images out of a collection with 15 800x800x8bit
+// images. There is one image each with only 255, 254, 253 as a
+// value. And there is one image each with one value each out of
+// 250, 251, 252. No other image contains value greater than 249.
+
+// one img with some_cell
+
+SELECT img[0:252,0:252]
+FROM earth_64 as img
+WHERE some_cell ( img[700:799,300:399] = 252c )
+
+// two imgs with some_cell
+
+SELECT img[0:252,0:252]
+FROM earth_64 as img
+WHERE some_cell ( img[700:799,300:399] = 252c OR img[700:799,300:399] = 251c )
+
+// three imgs with some_cell
+
+SELECT img[0:252,0:252]
+FROM earth_64 as img
+WHERE some_cell ( img[700:799,300:399] = 252c OR img[700:799,300:399] = 251c
+ OR img[700:799,300:399] = 250c )
+
+// one img with all_cell
+
+SELECT img[0:252,0:252]
+FROM earth_64 as img
+WHERE all_cell ( img[700:799,300:399] >= 255c )
+
+// two imgs with all_cell
+
+SELECT img[0:252,0:252]
+FROM earth_64 as img
+WHERE all_cell ( img[700:799,300:399] >= 254c )
+
+// three imgs with all_cell
+
+SELECT img[0:252,0:252]
+FROM earth_64 as img
+WHERE all_cell ( img[700:799,300:399] >= 253c )
+
diff --git a/rasodmg/test/stat1.dat b/rasodmg/test/stat1.dat
new file mode 100644
index 0000000..520061f
--- /dev/null
+++ b/rasodmg/test/stat1.dat
@@ -0,0 +1,3 @@
+50 0.20 10000 [0:799, 0:599]
+[200:600, 200:400]
+[220:620, 190:440] \ No newline at end of file
diff --git a/rasodmg/test/stat2.dat b/rasodmg/test/stat2.dat
new file mode 100644
index 0000000..b288662
--- /dev/null
+++ b/rasodmg/test/stat2.dat
@@ -0,0 +1,7 @@
+50 0.20 50000 [0:799, 0:599]
+[200:600, 200:400]
+[220:620, 190:440]
+[100:400, 300:580]
+[120:410, 310:570]
+[120:410, 310:569]
+[0:600, 0:500] \ No newline at end of file
diff --git a/rasodmg/test/stat3.dat b/rasodmg/test/stat3.dat
new file mode 100644
index 0000000..8f447b5
--- /dev/null
+++ b/rasodmg/test/stat3.dat
@@ -0,0 +1,4 @@
+50 0.20 50000 [0:799, 0:599]
+[120:410, 310:570]
+[120:410, 310:569]
+[0:600, 0:500] \ No newline at end of file
diff --git a/rasodmg/test/system_basic.cc b/rasodmg/test/system_basic.cc
new file mode 100644
index 0000000..6ba9afb
--- /dev/null
+++ b/rasodmg/test/system_basic.cc
@@ -0,0 +1,1945 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: system_basic.cc
+ *
+ * MODULE: rasodmg/test
+ *
+ * COMMENTS:
+ * None
+*/
+
+static const char rcsid[] = "@(#)rasodmg/test,SystemBasic: $Id: system_basic.cc,v 1.37 2002/10/09 09:58:05 hoefner Exp $";
+
+#ifdef TESTBASIC
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#include "raslib/template_inst.hh"
+#endif
+#endif
+
+#include "system_basic.hh"
+
+#include <iostream>
+#include <iomanip>
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <math.h>
+#include <signal.h>
+#include <unistd.h>
+#ifdef SOLARIS
+#include <strings.h>
+#endif
+
+#include "raslib/rmdebug.hh"
+#include "raslib/rminit.hh"
+#include "raslib/type.hh"
+#include "raslib/complex.hh"
+#include "raslib/structure.hh"
+#include "raslib/basetype.hh"
+#include "raslib/structuretype.hh"
+#include "raslib/collectiontype.hh"
+#include "raslib/marraytype.hh"
+#include "raslib/dlist.hh"
+#include "raslib/primitivetype.hh"
+#include "raslib/miterd.hh"
+#include "raslib/storageman.hh"
+
+#include "rasodmg/marray.hh"
+#include "rasodmg/storagelayout.hh"
+#include "rasodmg/dirtiling.hh"
+#include "rasodmg/dirdecompose.hh"
+#include "rasodmg/interesttiling.hh"
+#include "rasodmg/alignedtiling.hh"
+#include "rasodmg/stattiling.hh"
+#include "rasodmg/oqlquery.hh"
+
+#include "conversion/convfactory.hh"
+#include "conversion/convertor.hh"
+
+#include "exportutils/hexcodec.cc"
+#include "exportutils/error.cc"
+
+void
+fast_scale_process_primitive_type(const r_Primitive_Type *primType, char *dest, const char *src, const r_Minterval &destIv, const r_Minterval &srcIv, const r_Minterval &iterDom, unsigned int type_len, unsigned int length, r_Scale_Function func);
+void
+fast_scale_process_structured_type(const r_Structure_Type *primType, char *dest, const char *src, const r_Minterval &destIv, const r_Minterval &srcIv, const r_Minterval &iterDom, unsigned int type_len, unsigned int length, r_Scale_Function func);
+template<class T>
+void
+fast_scale_resample_array(T *dest, const T *src, const r_Minterval &destIv, const r_Minterval &srcIv, const r_Minterval &iterDom, unsigned int type_len, unsigned int length, bool round);
+
+template<class T>
+void
+fast_scale_aggregate_array(T *dest, const T *src, const r_Minterval &destIv, const r_Minterval &srcIv, const r_Minterval &iterDom, unsigned int type_len, unsigned int length);
+
+void
+signalHandler(int sig)
+ {
+ cout << "**CLIENT** signal error " << sig << " ";
+ switch (sig)
+ {
+ case SIGHUP:
+ cout << "Hangup (POSIX). ";
+ break;
+ case SIGINT:
+ cout << "Interrupt (ANSI).";
+ break;
+ case SIGQUIT:
+ cout << "Quit (POSIX).";
+ break;
+ case SIGILL:
+ cout << "Illegal instruction (ANSI).";
+ break;
+ case SIGTRAP:
+ cout << "Trace trap (POSIX).";
+ break;
+ case SIGABRT:
+ cout << "Abort (ANSI) or IOT trap (4.2 BSD).";
+ break;
+ case SIGBUS:
+ cout << "BUS error (4.2 BSD).";
+ break;
+ case SIGFPE:
+ cout << "Floating-point exception (ANSI).";
+ break;
+ case SIGKILL:
+ cout << "Kill, unblockable (POSIX).";
+ break;
+ case SIGUSR1:
+ cout << "User-defined signal 1 (POSIX).";
+ break;
+ case SIGSEGV:
+ cout << "Segmentation violation (ANSI).";
+ break;
+ case SIGUSR2:
+ cout << "User-defined signal 2 (POSIX).";
+ break;
+ case SIGPIPE:
+ cout << "Broken pipe (POSIX).";
+ break;
+ case SIGALRM:
+ cout << "Alarm clock (POSIX).";
+ break;
+ case SIGTERM:
+ cout << "Termination (ANSI).";
+ break;
+#ifndef SOLARIS
+#ifndef DECALPHA
+ case SIGSTKFLT:
+ cout << "Stack fault.";
+ break;
+#endif
+#endif
+ case SIGCLD:
+ cout << "SIGCHLD (System V) or child status has changed (POSIX).";
+ break;
+ case SIGCONT:
+ cout << "Continue (POSIX).";
+ break;
+ case SIGSTOP:
+ cout << "Stop, unblockable (POSIX).";
+ break;
+ case SIGTSTP:
+ cout << "Keyboard stop (POSIX).";
+ break;
+ case SIGTTIN:
+ cout << "Background read from tty (POSIX).";
+ break;
+ case SIGTTOU:
+ cout << "Background write to tty (POSIX).";
+ break;
+ case SIGURG:
+ cout << "Urgent condition on socket (4.2 BSD).";
+ break;
+ case SIGXCPU:
+ cout << "CPU limit exceeded (4.2 BSD).";
+ break;
+ case SIGXFSZ:
+ cout << "File size limit exceeded (4.2 BSD).";
+ break;
+ case SIGVTALRM:
+ cout << "Virtual alarm clock (4.2 BSD).";
+ break;
+ case SIGPROF:
+ cout << "Profiling alarm clock (4.2 BSD).";
+ break;
+ case SIGWINCH:
+ cout << "Window size change (4.3 BSD, Sun).";
+ cout << "Continue with operation.";
+ return;
+ break;
+ case SIGPOLL:
+ cout << "Pollable event occurred (System V) or I/O now possible (4.2 BSD).";
+ break;
+ case SIGPWR:
+ cout << "Power failure restart (System V).";
+ break;
+ case SIGSYS:
+ cout << "Bad system call.";
+ break;
+ default:
+ cout << "Unknown signal.";
+ break;
+ }
+ cout << endl;
+ if (SystemBasic::handleSignal)
+ {
+ SystemBasic::handleSignal = false;
+ try {
+ cout << "Aborting transaction" << endl;;
+ SystemBasic::ta.abort();
+ cout << "Transaction aborted" << endl;
+ cout << "Closing database" << endl;
+ SystemBasic::db.close();
+ cout << "Database closed" << endl;
+ }
+ catch (r_Error& err)
+ {
+ cout << "Error while aborting transaction/closing database: " << err.get_errorno() << " : " << err.what() << endl;
+ }
+ }
+ else {
+ //not doing it
+ }
+ exit(sig);
+ }
+
+void
+installSignalHandlers()
+ {
+ signal(SIGINT, signalHandler);
+ signal(SIGTERM, signalHandler);
+ signal(SIGHUP, signalHandler);
+ signal(SIGPIPE, signalHandler);
+ signal(SIGHUP, signalHandler);
+ signal(SIGINT, signalHandler);
+ signal(SIGQUIT, signalHandler);
+ signal(SIGILL, signalHandler);
+ signal(SIGTRAP, signalHandler);
+ signal(SIGABRT, signalHandler);
+ signal(SIGIOT, signalHandler);
+ signal(SIGBUS, signalHandler);
+ signal(SIGFPE, signalHandler);
+ signal(SIGKILL, signalHandler);
+ signal(SIGUSR1, signalHandler);
+ signal(SIGSEGV, signalHandler);
+ signal(SIGUSR2, signalHandler);
+ signal(SIGPIPE, signalHandler);
+ signal(SIGALRM, signalHandler);
+ signal(SIGTERM, signalHandler);
+#ifndef SOLARIS
+#ifndef DECALPHA
+ signal(SIGSTKFLT, signalHandler);
+#endif
+#endif
+ signal(SIGCLD, signalHandler);
+ signal(SIGCHLD, signalHandler);
+ signal(SIGCONT, signalHandler);
+ signal(SIGSTOP, signalHandler);
+ signal(SIGTSTP, signalHandler);
+ signal(SIGTTIN, signalHandler);
+ signal(SIGTTOU, signalHandler);
+ signal(SIGURG, signalHandler);
+ signal(SIGXCPU, signalHandler);
+ signal(SIGXFSZ, signalHandler);
+ signal(SIGVTALRM, signalHandler);
+ signal(SIGPROF, signalHandler);
+ signal(SIGWINCH, signalHandler);
+ signal(SIGPOLL, signalHandler);
+ signal(SIGIO, signalHandler);
+ signal(SIGPWR, signalHandler);
+ signal(SIGSYS, signalHandler);
+#if !defined SOLARIS
+#if !defined DECALPHA
+ signal(SIGUNUSED, signalHandler);
+#endif
+#endif
+ }
+
+r_Tiling*
+SystemBasic::theTiling = 0;
+
+bool
+SystemBasic::testBed = false;
+
+const char*
+SystemBasic::serverName = "localhost";
+
+r_ULong
+SystemBasic::serverPort = 7001;
+
+const char*
+SystemBasic::baseName = "RASBASE";
+
+const char*
+SystemBasic::userName = "rasguest";
+
+const char*
+SystemBasic::passwd = "rasguest";
+
+bool
+SystemBasic::printText = false;
+
+const char*
+SystemBasic::outputFileName = NULL;
+
+r_Data_Format
+SystemBasic::outputFormat = r_Array;
+
+const char*
+SystemBasic::outputFormatParams = 0;
+
+const char*
+SystemBasic::conversionTypeName = "char";
+
+r_Data_Format
+SystemBasic::inputFormat = r_Array;
+
+const char*
+SystemBasic::inputFormatParams = 0;
+
+r_Data_Format
+SystemBasic::transferFormat = r_Array;
+
+const char*
+SystemBasic::transferFormatParams = 0;
+
+r_Data_Format
+SystemBasic::storageFormat = r_Array;
+
+const char*
+SystemBasic::storageFormatParams = 0;
+
+const char*
+SystemBasic::collName = NULL;
+
+const char*
+SystemBasic::setTypeName = NULL;
+
+const char*
+SystemBasic::mddTypeName = NULL;
+
+r_OId
+SystemBasic::mddOId;
+
+bool
+SystemBasic::mddOIdDef = false;
+
+r_OId
+SystemBasic::collOId;
+
+bool
+SystemBasic::collOIdDef = false;
+
+const char*
+SystemBasic::fileName = NULL;
+
+r_Database
+SystemBasic::db;
+
+r_Transaction
+SystemBasic::ta;
+
+r_Minterval
+SystemBasic::mddDomain;
+
+bool
+SystemBasic::mddDomainDef = false;
+
+bool
+SystemBasic::polygonDefined = false;
+
+r_PolygonCutOut
+SystemBasic::polygon;
+
+int
+SystemBasic::polygonShrinker;
+
+bool
+SystemBasic::transparent = false;
+
+string
+SystemBasic::outsidePatternSel;
+
+bool
+SystemBasic::outsidePatternSelDef = false;
+
+string
+SystemBasic::insidePatternSel;
+
+bool
+SystemBasic::insidePatternSelDef = false;
+
+string
+SystemBasic::outsidePattern;
+
+bool
+SystemBasic::outsidePatternDef = false;
+
+string
+SystemBasic::insidePattern;
+
+bool
+SystemBasic::insidePatternDef = false;
+
+const int
+SystemBasic::queryBufferLength = 512;
+
+std::list<std::pair<double, char*> >*
+SystemBasic::scaleLevels = NULL;
+
+int
+SystemBasic::wrongBytes = 0;
+
+r_Scale_Function
+SystemBasic::scaleFunction = r_SubSampling;
+
+size_t
+SystemBasic::updateBufferSize = 52428800;
+
+const char*
+SystemBasic::defaultUpdateBufferSize = "52428800";
+
+
+std::list<char*>
+SystemBasic:: layerList;
+
+std::list<unsigned int>
+SystemBasic::patternsTrue;
+
+std::list<unsigned int>
+SystemBasic::patternsFalse;
+
+const char*
+SystemBasic::noUsageHeader = "Please set SystemBasic::usageHeader to a meaningful value.\nThen you will help your users : )\n";
+
+const char*
+SystemBasic::usageHeader = SystemBasic::noUsageHeader;
+
+const char*
+SystemBasic::noUsageFooter = "Please set SystemBasic::usageFooter to a meaningful value.\nThen you will help your users : )\n";
+
+const char*
+SystemBasic::usageFooter = SystemBasic::noUsageFooter;
+
+r_Minterval
+SystemBasic::overlayDomain;
+
+bool
+SystemBasic::overlayDomainDef = false;
+
+r_Range
+SystemBasic::align = 0;
+
+bool
+SystemBasic::tiledUpdate = false;
+
+bool
+SystemBasic::force = false;
+
+//--tiling params description
+const string
+SystemBasic::tilingDesc= string("") +
+ "<tiling-name> tiling strategy, specified as:" + CommandLineParameter::descLineSep +
+ " " + tiling_name_notiling + "," + CommandLineParameter::descLineSep +
+ " " + tiling_name_sizetiling + "," + CommandLineParameter::descLineSep +
+ " " + tiling_name_alignedtiling + "," + CommandLineParameter::descLineSep +
+ " " + tiling_name_interesttiling + "," + CommandLineParameter::descLineSep +
+ " " + tiling_name_directionaltiling + "," + CommandLineParameter::descLineSep +
+ " " + tiling_name_statisticaltiling;
+
+const string
+SystemBasic::tilingParamsDesc = string("") +
+ "<params> parameters for tiling strategy, specified as:" + CommandLineParameter::descLineSep +
+ "... for " + tiling_name_notiling + CommandLineParameter::descLineSep +
+ r_No_Tiling::description + CommandLineParameter::descLineSep +
+ "... for " + tiling_name_sizetiling + CommandLineParameter::descLineSep +
+ r_Size_Tiling::description + CommandLineParameter::descLineSep +
+ "... for " + tiling_name_alignedtiling + CommandLineParameter::descLineSep +
+ r_Aligned_Tiling::description + CommandLineParameter::descLineSep +
+ "... for " + tiling_name_interesttiling + CommandLineParameter::descLineSep +
+ r_Interest_Tiling::description + CommandLineParameter::descLineSep +
+ "... for " + tiling_name_directionaltiling + CommandLineParameter::descLineSep +
+ r_Dir_Tiling::description + CommandLineParameter::descLineSep +
+ "... for " + tiling_name_statisticaltiling + CommandLineParameter::descLineSep +
+ r_Stat_Tiling::description;
+
+bool
+SystemBasic::handleSignal = true;
+
+int
+SystemBasic::parseParams(int argc, char** argv)
+ {
+ int retval = 0;
+ //program interface
+ CommandLineParser &cmlInter = CommandLineParser::getInstance();
+ CommandLineParameter &clp_help = cmlInter.addFlagParameter('h', "help", "show command line switches");
+ CommandLineParameter &clp_tiling = cmlInter.addStringParameter(CommandLineParser::noShortName, "tiling", tilingDesc.c_str(), tiling_name_sizetiling);
+ CommandLineParameter &tilingParams = cmlInter.addStringParameter(CommandLineParser::noShortName, "tilingparams", tilingParamsDesc.c_str(), "131072");
+ CommandLineParameter &clp_testbed = cmlInter.addFlagParameter(CommandLineParser::noShortName, "testbed", "testbed output flag.");
+ CommandLineParameter &clp_transparent = cmlInter.addFlagParameter('t', "transparent", "transparent update flag.\n\t\tIf it is specified black data will be treated as transparent");
+ CommandLineParameter &clp_printtext = cmlInter.addFlagParameter(CommandLineParser::noShortName, "printtext", "output of char data will be printed as text - not numbers.\n\t\tUseful for printing the names of all collections/or text stored in mdds");
+ CommandLineParameter &clp_server = cmlInter.addStringParameter('s', "server", "<host-name> host's name where rasmgr runs.", serverName);
+ CommandLineParameter &clp_port = cmlInter.addStringParameter('p', "port", "<nnnn> port number used by rasmgr.", "7001");
+ CommandLineParameter &clp_database = cmlInter.addStringParameter('d', "database", "<db-name> name of database.", baseName);
+ CommandLineParameter &clp_user = cmlInter.addStringParameter(CommandLineParser::noShortName, "user", "<user-name> name of user", userName);
+ CommandLineParameter &clp_passwd = cmlInter.addStringParameter(CommandLineParser::noShortName,"passwd", "<user-passwd> password of user", passwd);
+ CommandLineParameter &clp_storage = cmlInter.addStringParameter(CommandLineParser::noShortName, "storageformat", "<format> storage format.", format_name_array);
+ CommandLineParameter &clp_storageParams = cmlInter.addStringParameter(CommandLineParser::noShortName, "storageformatparams", "<params> parameters used for storing", NULL);
+ CommandLineParameter &clp_transfer = cmlInter.addStringParameter(CommandLineParser::noShortName, "transformat", "<format> transfer format.", format_name_array );
+ CommandLineParameter &clp_transferParams = cmlInter.addStringParameter(CommandLineParser::noShortName, "transformatparams", "<params> parameters used for transfer", NULL);
+ CommandLineParameter &clp_input = cmlInter.addStringParameter(CommandLineParser::noShortName, "inputformat", "<format> input format.", format_name_array );
+ CommandLineParameter &clp_inputParams = cmlInter.addStringParameter(CommandLineParser::noShortName, "inputformatparams", "<params> parameters used for input", NULL);
+ CommandLineParameter &clp_output = cmlInter.addStringParameter(CommandLineParser::noShortName, "outputformat", "<format> output format.", format_name_array );
+ CommandLineParameter &clp_outputParams = cmlInter.addStringParameter(CommandLineParser::noShortName, "outputformatparams", "<params> parameters used for output", NULL);
+ CommandLineParameter &clp_outputFileName = cmlInter.addStringParameter(CommandLineParser::noShortName, "outputfilename", "<name> file name of output file", NULL);
+ CommandLineParameter &clp_polygon = cmlInter.addStringParameter(CommandLineParser::noShortName, "polygon", "<polygon-path> polygon path used for delimiting the data. The polygon has to be given in counter clockwise direction. Do not forget to supply insidepattern and/or outsidepattern", NULL);
+ CommandLineParameter &clp_shrink = cmlInter.addStringParameter(CommandLineParser::noShortName, "shrink", "<number> pixels that will reduce the polygon.", "0");
+ CommandLineParameter &clp_fillinside = cmlInter.addStringParameter(CommandLineParser::noShortName, "outsidepattern", "<pattern> will be used to fill the outside of the polygon.", NULL);
+ CommandLineParameter &clp_filloutside = cmlInter.addStringParameter(CommandLineParser::noShortName, "insidepattern", "<pattern> will be used to fill the inside of the polygon.", NULL);
+ CommandLineParameter &clp_fillinsidesel = cmlInter.addStringParameter(CommandLineParser::noShortName, "outsidepatternbackdrop", "<pattern> will be used to fill the outside of the polygon in the backdrop mdd.", NULL);
+ CommandLineParameter &clp_filloutsidesel = cmlInter.addStringParameter(CommandLineParser::noShortName, "insidepatternbackdrop", "<pattern> will be used to fill the inside of the polygon in the backdrop mdd.", NULL);
+ CommandLineParameter &clp_collType = cmlInter.addStringParameter(CommandLineParser::noShortName, "colltype", "<coll-type> type of collection");
+ CommandLineParameter &clp_mddType = cmlInter.addStringParameter(CommandLineParser::noShortName, "mddtype", "<mdd-type> type of marray");
+ CommandLineParameter &clp_collName = cmlInter.addStringParameter('c', "collname", "<coll-name> name of collection");
+ CommandLineParameter &clp_mddoid = cmlInter.addStringParameter(CommandLineParser::noShortName, "mddoid","<mdd-oid> oid of the marray to work on");
+ CommandLineParameter &clp_colloid = cmlInter.addStringParameter(CommandLineParser::noShortName, "colloid","<coll-oid> oid of the set to work on");
+ CommandLineParameter &clp_mddDomain = cmlInter.addStringParameter(CommandLineParser::noShortName, "mdddomain","<mdd-domain> domain of marray");
+ CommandLineParameter &clp_overlayDomain = cmlInter.addStringParameter(CommandLineParser::noShortName, "overlaydomain","<overlay-domain> domain that is updated in the db in case of an overlay, default is the domain of the image");
+ CommandLineParameter &clp_align = cmlInter.addStringParameter(CommandLineParser::noShortName, "align","<pixels> number of pixels to align the domain to. May be used instead of overlaydomain.", "0");
+ CommandLineParameter &clp_tiledupdate = cmlInter.addFlagParameter(CommandLineParser::noShortName, "tiledupdate","do job in smaller pieces. Use update buffer size to compute the size of each update. May not be used with a file insertion!");
+ CommandLineParameter &clp_read = cmlInter.addStringParameter('r', "read", "<file-name> name of input file");
+ CommandLineParameter &clp_conversiontypename = cmlInter.addStringParameter(CommandLineParser::noShortName, "conversiontype","<type-name> name of type to be passed to the conversion module");
+ CommandLineParameter &clp_scalelevels = cmlInter.addStringParameter(CommandLineParser::noShortName, "scalelevels","<level-spec> list of scale levels: collection:1/scalefactor;...\n\t\te.g. coll:1;coll_1:2;coll_3:4;coll_4:8");
+ string t = string("") + "<function-name> name of the scaling algorithm.\n\t\teither " + scale_function_name_subsampling + " or " + scale_function_name_bitaggregation;
+ CommandLineParameter &clp_updatebuffer = cmlInter.addStringParameter(CommandLineParser::noShortName, "buffersize", "<buffer-size> number of cells that can be written in one go when using tiledupdate. If align is defined then the minimum update size is taken to be the value align in each dimension.", defaultUpdateBufferSize);
+ CommandLineParameter &cml_layerlist = cmlInter.addStringParameter(CommandLineParser::noShortName, "layerlist", "<list> list of files for merging: <\"layer[[;layer]...]\"> \n\t\tlayer: <filename:TruePattern:FalsePattern>\n\t\tTruePattern / FalsePattern:\n\t\tbinary pattern expressed as decimal number(e.g.: 01001 = 9)");
+ CommandLineParameter &clp_scalefunction = cmlInter.addStringParameter(CommandLineParser::noShortName, "scalefunction", t.c_str(), scale_function_name_subsampling);
+ CommandLineParameter &clientcommSleep = cmlInter.addStringParameter(CommandLineParser::noShortName, "clientcommsleep", "<seconds> number of seconds to wait till retry", "1");
+ CommandLineParameter &clientcommMaxRetry= cmlInter.addStringParameter(CommandLineParser::noShortName, "clientcommretry", "<tries> number of retries before giving up", "10");
+ CommandLineParameter &rpcMaxRetry = cmlInter.addStringParameter(CommandLineParser::noShortName, "rpcretry", "<tries> number of retries before giving up", "5");
+ CommandLineParameter &clp_Force = cmlInter.addFlagParameter(CommandLineParser::noShortName, "force", "force writing of files");
+ try {
+ cmlInter.processCommandLine(argc, argv);
+ }
+ catch(CmlException& err)
+ {
+ cout << usageHeader;
+ cmlInter.printHelp();
+ cout << usageFooter;
+ cout << "Error parsing command line:" << endl;
+ cout << err.what() << endl;
+ return ERRORPARSINGCOMMANDLINE;
+ }
+ try {
+ if (cmlInter.isPresent('h'))
+ {
+ cout << usageHeader;
+ cmlInter.printHelp();
+ cout << usageFooter;
+ return ALLDONE;
+ }
+ r_Tiling_Scheme ts = get_tiling_scheme_from_name(cmlInter.getValueAsString("tiling"));
+ switch (ts)
+ {
+ case r_NoTiling:
+ theTiling = new r_No_Tiling();
+ break;
+ case r_StatisticalTiling:
+ theTiling = new r_Stat_Tiling(cmlInter.getValueAsString("tilingparams"));
+ break;
+ case r_InterestTiling:
+ theTiling = new r_Interest_Tiling(cmlInter.getValueAsString("tilingparams"));
+ break;
+ case r_AlignedTiling:
+ theTiling = new r_Aligned_Tiling(cmlInter.getValueAsString("tilingparams"));
+ break;
+ case r_DirectionalTiling:
+ theTiling = new r_Dir_Tiling(cmlInter.getValueAsString("tilingparams"));
+ break;
+ case r_SizeTiling:
+ theTiling = new r_Size_Tiling(cmlInter.getValueAsString("tilingparams"));
+ break;
+ case r_RegularTiling:
+ return TILINGTYPENOTALLOWED;
+ default:
+ return UNKNOWNTILINGTYPE;
+ }
+ if (cmlInter.isPresent("scalelevels"))
+ {
+ retval = readScaleLevels(cmlInter.getValueAsString("scalelevels"));
+ if (retval != 0)
+ return retval;
+ }
+ testBed = cmlInter.isPresent("testbed");
+ force = cmlInter.isPresent("force");
+ transparent = cmlInter.isPresent("transparent");
+ printText = cmlInter.isPresent("printtext");
+ serverName = cmlInter.getValueAsString("server");
+ serverPort = cmlInter.getValueAsLong("port");
+ baseName = cmlInter.getValueAsString("database");
+ userName = cmlInter.getValueAsString("user");
+ passwd = cmlInter.getValueAsString("passwd");
+ storageFormat = get_data_format_from_name(cmlInter.getValueAsString("storageformat"));
+ storageFormatParams = cmlInter.getValueAsString("storageformatparams");
+ transferFormat = get_data_format_from_name(cmlInter.getValueAsString("transformat"));
+ transferFormatParams = cmlInter.getValueAsString("transformatparams");
+ inputFormat = get_data_format_from_name(cmlInter.getValueAsString("inputformat"));
+ inputFormatParams = cmlInter.getValueAsString("inputformatparams");
+ outputFormat = get_data_format_from_name(cmlInter.getValueAsString("outputformat"));
+ outputFormatParams = cmlInter.getValueAsString("outputformatparams");
+ outputFileName = cmlInter.getValueAsString("outputfilename");
+ RMInit::clientcommMaxRetry = clientcommMaxRetry.getValueAsLong();
+ RMInit::logOut << "Clientcomm retry set to " << RMInit::clientcommMaxRetry << endl;
+ RMInit::clientcommSleep = clientcommSleep.getValueAsLong();
+ RMInit::logOut << "Clientcomm sleep set to " << RMInit::clientcommSleep << endl;
+ RMInit::rpcMaxRetry = rpcMaxRetry.getValueAsLong();
+ RMInit::logOut << "RPC retry set to " << RMInit::rpcMaxRetry << endl;
+ if (cmlInter.isPresent("polygon"))
+ {
+ try {
+ r_Polygon p(cmlInter.getValueAsString("polygon"));
+ polygon.addPolygon(p);
+ polygonDefined = true;
+ }
+ catch (r_Error& err)
+ {
+ RMInit::logOut << "Error reading the polygon: " << err.get_errorno() << " " << err.what() << endl;
+ return POLYGONCREATIONFAILED;
+ }
+ }
+ polygonShrinker = cmlInter.getValueAsLong("shrink");
+ if (cmlInter.isPresent("outsidepattern"))
+ {
+ outsidePatternDef = true;
+ outsidePattern = HexCodec::convertTo(cmlInter.getValueAsString("outsidepattern"));
+ }
+ if (cmlInter.isPresent("insidepattern"))
+ {
+ insidePatternDef = true;
+ insidePattern = HexCodec::convertTo(cmlInter.getValueAsString("insidepattern"));
+ }
+ if (cmlInter.isPresent("outsidepatternbackdrop"))
+ {
+ outsidePatternSelDef = true;
+ outsidePatternSel = HexCodec::convertTo(cmlInter.getValueAsString("outsidepatternbackdrop"));
+ }
+ if (cmlInter.isPresent("insidepatternbackdrop"))
+ {
+ insidePatternSelDef = true;
+ insidePatternSel = HexCodec::convertTo(cmlInter.getValueAsString("insidepatternbackdrop"));
+ }
+ setTypeName = cmlInter.getValueAsString("colltype");
+ mddTypeName = cmlInter.getValueAsString("mddtype");
+ collName = cmlInter.getValueAsString("collname");
+ if (cmlInter.isPresent("mddoid"))
+ {
+ mddOIdDef = true;
+ mddOId = r_OId(cmlInter.getValueAsString("mddoid"));
+ }
+ if (cmlInter.isPresent("colloid"))
+ {
+ collOIdDef = true;
+ cmlInter.getValueAsString("colloid");
+ }
+ if (cmlInter.isPresent("mdddomain"))
+ {
+ mddDomainDef = true;
+ mddDomain = r_Minterval(cmlInter.getValueAsString("mdddomain"));
+ }
+ if (cmlInter.isPresent("overlaydomain"))
+ {
+ overlayDomainDef = true;
+ overlayDomain = r_Minterval(cmlInter.getValueAsString("overlaydomain"));
+ }
+ else {
+ overlayDomain = mddDomain;
+ }
+ align = cmlInter.getValueAsLong("align");
+ if (align > 0)
+ {
+ overlayDomainDef = true;
+ for (r_Dimension dim = 0; dim < overlayDomain.dimension(); dim++)
+ {
+ r_Range high = overlayDomain[dim].high();
+ r_Range low = overlayDomain[dim].low();
+
+ r_Range highd = high%align;
+ if (high < 0)
+ high = high - highd - 1;
+ else
+ high = high + align - highd - 1;
+
+ r_Range lowd = overlayDomain[dim].low()%align;
+ if (low < 0)
+ low = low - align - lowd;
+ else
+ low = low - lowd;
+ overlayDomain[dim].set_interval(low, high);
+ }
+ RMInit::logOut << "Alignment changed overlay domain to " << overlayDomain << endl;
+ }
+ fileName = cmlInter.getValueAsString("read");
+ tiledUpdate = cmlInter.isPresent("tiledupdate");
+ if (tiledUpdate && fileName)
+ {
+ return TILEDUPDATEANDFILE;
+ }
+ conversionTypeName = cmlInter.getValueAsString("conversiontype");
+ scaleFunction = get_scale_function_from_name(cmlInter.getValueAsString("scalefunction"));
+ updateBufferSize = cmlInter.getValueAsLong("buffersize");
+ if (cmlInter.isPresent("layerlist"))
+ {
+ const char* endPos = NULL;
+ char* layerName = NULL;
+ const char* patternTName = NULL;
+ unsigned int patternT = 0;
+ unsigned int patternF = 0;
+ bool found = false;
+ size_t length = 0;
+ const char* startPos = cmlInter.getValueAsString("layerlist");
+ while (true)
+ {
+ endPos = index(startPos, ':');
+ if (endPos == NULL)
+ {
+ return LAYERSNOTCORRECT;
+ }
+ length = endPos - startPos;
+ layerName = new char[length + 1];
+ memset(layerName, 0, length + 1);
+ strncpy(layerName, startPos, length);
+ startPos = endPos + 1;
+ endPos = index(startPos, ':');
+ patternT = (unsigned int)atol(startPos);
+ startPos = endPos + 1;
+ endPos = index(startPos, ';');
+ patternF = (unsigned int)atol(startPos);
+ layerList.push_back(layerName);
+ patternsTrue.push_back(patternT);
+ patternsFalse.push_back(patternF);
+ RMInit::logOut << "Layer level : " << layerName << " (" << patternT << "," << patternF << ")" << endl;
+ if (endPos == NULL)
+ {
+ break;
+ }
+ startPos = endPos + 1;
+ }
+ RMInit::logOut << "Layer list : ";
+ std::list<char*>::iterator iterL = layerList.begin();
+ std::list<unsigned int>::iterator iterT = patternsTrue.begin();
+ std::list<unsigned int>::iterator iterF = patternsFalse.begin();
+ while (iterL != layerList.end())
+ {
+ RMInit::logOut << *iterL << "(" << *iterT << "," << *iterF << ") ";
+ iterL++;
+ iterT++;
+ iterF++;
+ }
+ RMInit::logOut << std::endl;
+ if (layerList.size() > (sizeof(r_ULong) * 8))
+ {
+ std::list<char*>::iterator iterL = layerList.begin();
+ while (iterL != layerList.end())
+ {
+ delete[] *iterL;
+ ++iterL;
+ }
+ return TOOMANYLAYERS;
+ }
+ }
+ }
+ catch(CmlException& err)
+ {
+ cout << usageHeader;
+ cmlInter.printHelp();
+ cout << usageFooter;
+ cout << "Error evaluating command line:" << endl;
+ cout << err.what() << endl;
+ return ERRORPARSINGCOMMANDLINE;
+ }
+ return retval;
+ }
+
+int
+SystemBasic::saveData(const char* fileNamePat, const char* data, r_Bytes length, const r_Minterval& dom)
+ {
+ RMInit::logOut << "SystemBasic::saveData(" << fileNamePat << ", DATA, " << length << ", " << dom << ")" << std::endl;
+ r_Primitive_Type* tp = new r_Primitive_Type("Char", r_Type::CHAR);
+ r_Convertor* conv = r_Convertor_Factory::create(r_PNG, data, dom, tp);
+ r_convDesc desc = conv->convertTo(NULL);
+ size_t dtaSize=desc.destInterv.cell_count()*tp->size();
+ std::ofstream o;
+ o.open(fileNamePat);
+ if (!o.is_open())
+ {
+ RMInit::logOut << "unable to open file " << fileNamePat << " for writing" << std::endl;
+ return FILEINACCESSIBLE;
+ }
+ o.write(desc.dest, dtaSize);
+ //fwrite(desc.dest, 1, dtaSize, tfile);
+ o.flush();
+ o.close();
+ free(desc.dest);
+ delete desc.destType;
+ delete conv;
+ delete tp;
+ return 0;
+ }
+
+void
+SystemBasic::openTransaction(bool readwrite) throw (r_Error)
+ {
+ db.set_servername(serverName, serverPort);
+ db.set_useridentification(userName, passwd);
+ db.open(baseName);
+ if (readwrite)
+ ta.begin(r_Transaction::read_write);
+ else
+ ta.begin(r_Transaction::read_only);
+ db.set_transfer_format(transferFormat, transferFormatParams);
+ db.set_storage_format(storageFormat, storageFormatParams);
+ }
+
+void
+SystemBasic::printScalar(const r_Scalar& scalar)
+ {
+ switch (scalar.get_type()->type_id())
+ {
+ case r_Type::BOOL:
+ cout << (((r_Primitive*)&scalar)->get_boolean() ? "T" : "F") << std::flush;
+ break;
+
+ case r_Type::CHAR:
+ cout << (int)((r_Primitive*)&scalar)->get_char() << std::flush;
+ break;
+
+ case r_Type::OCTET:
+ cout << (int)((r_Primitive*)&scalar)->get_octet() << std::flush;
+ break;
+
+ case r_Type::SHORT:
+ cout << ((r_Primitive*)&scalar)->get_short() << std::flush;
+ break;
+
+ case r_Type::USHORT:
+ cout << ((r_Primitive*)&scalar)->get_ushort() << std::flush;
+ break;
+
+ case r_Type::LONG:
+ cout << ((r_Primitive*)&scalar)->get_long() << std::flush;
+ break;
+
+ case r_Type::ULONG:
+ cout << ((r_Primitive*)&scalar)->get_ulong() << std::flush;
+ break;
+
+ case r_Type::FLOAT:
+ cout << ((r_Primitive*)&scalar)->get_float() << std::flush;
+ break;
+
+ case r_Type::DOUBLE:
+ cout << ((r_Primitive*)&scalar)->get_double() << std::flush;
+ break;
+
+ case r_Type::COMPLEXTYPE1:
+ case r_Type::COMPLEXTYPE2:
+ cout << "(" << ((r_Complex*)&scalar)->get_re() << ", " << ((r_Complex*)&scalar)->get_im() << ")" << std::flush;
+ break;
+
+ case r_Type::STRUCTURETYPE:
+ {
+ r_Structure* structValue = (r_Structure*)&scalar;
+ cout << " { " << std::flush;
+ for(int i=0; i<structValue->count_elements(); i++)
+ {
+ printScalar((*structValue)[i]);
+ if (i < structValue->count_elements()-1) cout << ", " << std::flush;
+ }
+ cout << " }" << endl;
+ }
+ break;
+ }
+ }
+
+int
+SystemBasic::convertFrom(r_Data_Format fmt, char*& src, size_t& dtaSize, r_Minterval& interv, r_Base_Type*& tp, const char* options)
+ {
+ int retval = 0;
+
+ r_Minterval tmpInt(1);
+ tmpInt << r_Sinterval((r_Range)0, (r_Range)dtaSize - 1);
+
+ RMInit::logOut << "convertFrom(...) " << endl;
+ RMInit::logOut << "domain in : " << tmpInt << endl;
+ RMInit::logOut << "type in : ";
+ tp->print_status(RMInit::logOut);
+ RMInit::logOut << endl;
+
+ if (fmt != r_Array)
+ {
+ try {
+ r_Convertor* conv = r_Convertor_Factory::create(fmt, src, tmpInt, tp);
+ r_Storage_Man_CPP mySM;
+ conv->set_storage_handler(mySM);
+ r_convDesc desc = conv->convertFrom(options);
+
+ if (desc.destType->isBaseType())
+ {
+ delete tp;
+ tp = (r_Base_Type*)desc.destType;
+ tmpInt = desc.destInterv;
+ dtaSize=tmpInt.cell_count()*tp->size();
+ delete [] src;
+ src = desc.dest;
+ delete conv;
+ conv = 0;
+ if (interv.dimension() != 0)
+ {
+ if (tmpInt.cell_count() != interv.cell_count())
+ {
+ RMInit::logOut << "Domains do not have the same number of cells (mdd " << interv << ", data " << tmpInt << ")" << endl;
+ retval = DOMAINDATAMISMATCH;
+ }
+ else {
+ if (tmpInt.get_extent() != interv.get_extent())
+ {
+ RMInit::logOut << "Domains do not have the same extents (mdd " << interv << ", data " << tmpInt << ")" << endl;
+ retval = DOMAINDATAMISMATCH;
+ }
+ }
+ }
+ else {
+ interv = tmpInt;
+ }
+ }
+ else {
+ RMInit::logOut << "Error conversion type is not a base type" << endl;
+ retval = CONVERSIONRETURNEDWRONGTYPE;
+ }
+ }
+ catch (r_Error& obj)
+ {
+ RMInit::logOut << "Error (" << obj.get_errorno() << ") when converting from " << fmt << " : " << obj.what() << endl;
+ retval = CONVERSIONEXCEPTION;
+ }
+ }
+ else {
+ if (dtaSize != (tp->size() * interv.cell_count()))
+ {
+ RMInit::logOut << "base type size " << tp->size() << " cells " << interv.cell_count() << " does not match size " << dtaSize << endl;
+ retval = DOMAINDATAMISMATCH;
+ }
+ }
+
+ RMInit::logOut << "domain out : " << interv << endl;
+ RMInit::logOut << "type out : ";
+ tp->print_status(RMInit::logOut);
+ RMInit::logOut << endl;
+
+ return retval;
+ }
+
+int
+SystemBasic::convertTo(r_Data_Format fmt, char*& src, size_t& dtaSize, r_Minterval& interv, r_Base_Type*& tp, const char* options)
+ {
+ int retval = 0;
+
+ RMInit::logOut << "convertTo(...)" << endl;
+ RMInit::logOut << "domain in : " << interv << endl;
+ RMInit::logOut << "type in : " ;
+ tp->print_status(RMInit::logOut);
+ RMInit::logOut << endl;
+
+ if (fmt != r_Array)
+ {
+ try {
+ r_Convertor* conv = r_Convertor_Factory::create(fmt, src, interv, tp);
+ r_convDesc desc = conv->convertTo(options);
+ RMInit::logOut << "Conversion type : ";
+ desc.destType->print_status(RMInit::logOut);
+ RMInit::logOut << endl;
+ if (desc.destType->isBaseType())
+ {
+ delete tp;
+ tp = (r_Base_Type*)desc.destType;
+ }
+ else {
+ RMInit::logOut << "Error conversion type is not a base type" << endl;
+ throw r_Error();
+ }
+ dtaSize = desc.destInterv.cell_count() * tp->size(); // desc.destInterv[0].high() - desc.destInterv[0].low() + 1;
+ interv=desc.destInterv;
+ delete src;
+ src = desc.dest;
+ delete conv;
+ conv = 0;
+ }
+ catch (r_Error& obj)
+ {
+ RMInit::logOut << "Error (" << obj.get_errorno() << ") when converting to " << fmt << " : " << obj.what() << endl;
+ retval = CONVERSIONEXCEPTION;
+ }
+ }
+ else {
+ if (dtaSize != (tp->size() * interv.cell_count()))
+ {
+ RMInit::logOut << "base type size " << tp->size() << " cells " << interv.cell_count() << " does not match size " << dtaSize << endl;
+ retval = DOMAINDATAMISMATCH;
+ }
+ }
+
+ RMInit::logOut << "domain out : " << interv << endl;
+ RMInit::logOut << "type out : " ;
+ tp->print_status(RMInit::logOut);
+ RMInit::logOut << endl;
+
+ return retval;
+ }
+
+FILE*
+SystemBasic::checkFile(const char* fileN, int& retval)
+ {
+ FILE* fileD = NULL;
+ if ((fileD = fopen(fileN, "r")) == NULL)
+ retval = FILEINACCESSIBLE;
+ return fileD;
+ }
+
+char*
+SystemBasic::getData(FILE* file, size_t& dtaSize, int& retval)
+ {
+ char* dta = 0;
+ size_t size = 0;
+ fseek(file, 0, SEEK_END);
+ size = ftell(file);
+ RMInit::logOut << "getData(...)" << endl;
+ RMInit::logOut << "File size : " << size << endl;
+ try {
+ dta = new char[size];
+ }
+ catch(std::bad_alloc) {
+ RMInit::logOut << "Unable to claim memory(" << size << "B)!" << endl;
+ retval = UNABLETOCLAIMRESOURCEFORFILE;
+ return dta;
+ }
+
+ fseek(file, 0, SEEK_SET);
+ fread(dta, 1, size, file);
+ fclose(file);
+ dtaSize = size;
+ return dta;
+ }
+
+int
+SystemBasic::readScaleLevels(const char* startPos)
+ {
+ int retval = 0;
+ scaleLevels = new std::list<std::pair<double, char*> >();
+ const char* endPos = NULL;
+ char* levelName = NULL;
+ const char* factorName = NULL;
+ double factor = 0;
+ bool found = false;
+ size_t length = 0;
+ while (true)
+ {
+ endPos = index(startPos, ':');
+ if (endPos == NULL)
+ {
+ retval = SCALELEVELSINCORRECT;
+ delete scaleLevels;
+ scaleLevels = NULL;
+ break;
+ }
+ length = endPos - startPos;
+ levelName = new char[length + 1];
+ memset(levelName, 0, length + 1);
+ strncpy(levelName, startPos, length);
+ startPos = endPos + 1;
+ endPos = index(startPos, ';');
+ factor = atof(startPos);
+ factor = 1 / factor;
+ scaleLevels->push_back(std::pair<double, char*>(factor, levelName));
+ RMInit::logOut << "Scale level : " << levelName << " (" << factor << ")" << endl;
+ if (endPos == NULL)
+ {
+ break;
+ }
+ startPos = endPos + 1;
+ }
+ return retval;
+ }
+
+void
+SystemBasic::explainRetval(int retval)
+ {
+ switch (retval)
+ {
+ case EXCEPTIONEXECUTEQUERY:
+ cout << "An exception occured during execution of the query" << endl;
+ cout << "Check the RasDaMan exception." << endl;
+ break;
+ case TILINGPATAMETERSINCORRECT:
+ cout << "Tiling parameters incorrect" << endl;
+ cout << "Check the specification of the tiling parameters for the tiling strategy you chose." << endl;
+ break;
+ case UNKNOWNTILINGTYPE:
+ cout << "Unknown tiling type specified" << endl;
+ cout << "Please review your --tiling option." << endl;
+ break;
+ case TILINGPARAMETERSMISSING:
+ cout << "You specified a tiling option which requires additional parameters" << endl;
+ cout << "Please specify a --tilingparameter option. For information on the format consult the --help option. For information on the meaning of the parameters consult the RasDaMan c++ documentation of the apropriate tiling." << endl;
+ break;
+ case CONVERSIONEXCEPTION:
+ cout << "An exception occured during conversion" << endl;
+ break;
+ case CONVERSIONNOTSUPPORTED:
+ cout << "The specified conversion format is not supported" << endl;
+ break;
+ case NOQUERY:
+ cout << "Cannot read query from file" << endl;
+ break;
+ case ARGUMENTSMISSING:
+ cout << "There are arguments missing" << endl;
+ cout << "You must specify --arg1 in order to specify --arg2 ..." << endl;
+ break;
+ case ARGUMENTSINCOMPLETE:
+ cout << "There are arguments missing" << endl;
+ cout << "You must specify --arg? --arg?domain --arg?type, where ? can be 1, 2, 3 or 4" << endl;
+ break;
+ case CREATEANDNOCREATE:
+ cout << "You specified create and no create" << endl;
+ cout << "Please decide on one." << endl;
+ break;
+ case NOVALIDDOMAIN:
+ cout << "No valid domain" << endl;
+ cout << "Please use something like \"[0:*,-2:9]\"." << endl;
+ break;
+ case FILEINACCESSIBLE:
+ cout << "Cannot access one of the files" << endl;
+ break;
+ case FILENAMETOLONG:
+ cout << "File name too long" << endl;
+ break;
+ case NOCREATECREATECOLL:
+ cout << "You specified to not create a collection, but want to create one" << endl;
+ break;
+ case NOCOLLTYPE:
+ cout << "No collection type specified" << endl;
+ break;
+ case COLLOIDANDCOLLNAME:
+ cout << "Do not specify collection name and collection oid" << endl;
+ break;
+ case CREATECOLLWITHOID:
+ cout << "Cannot use user specified oid to create collection" << endl;
+ break;
+ case CREATEMDDWITHOID:
+ cout << "Cannot use user specified oid to create marray" << endl;
+ break;
+ case INVALIDTILESIZE:
+ cout << "Tile size is invalid" << endl;
+ break;
+ case DOMAINDATAMISMATCH:
+ cout << "Domain extent does not match size of data file" << endl;
+ break;
+ case MDDDOMAINNOTSPECIFIED:
+ cout << "Domain for marray not specified" << endl;
+ break;
+ case FILENAMENOTSPECIFIED:
+ cout << "File name not specified" << endl;
+ break;
+ case NOCOLLNAMENOCOLLOID:
+ cout << "Neither collection name nor collection oid specified" << endl;
+ break;
+ case MDDTYPEINVALID:
+ cout << "Marray type not valid" << endl;
+ break;
+ case NOBASETYPE:
+ cout << "No base type in marray type" << endl;
+ break;
+ case EXCEPTIONCREATECOLL:
+ cout << "Exception while creating collection" << endl;
+ break;
+ case EXCEPTIONADMIN:
+ cout << "Exception while performing administrativ action" << endl;
+ break;
+ case COLLECTIONINACCESSIBLE:
+ cout << "Collection not accessible" << endl;
+ break;
+ case OIDINVALID:
+ cout << "Specified oid is invalid" << endl;
+ cout << "Please use something like \"Oracle|RASBASE|1025\"." << endl;
+ break;
+ case MDDINACCESSIBLE:
+ cout << "Marray not accessible" << endl;
+ break;
+ case MDDOIDANDCOLL:
+ cout << "MDD oid and collection specified" << endl;
+ cout << "I can either update a whole collection or just one marray." << endl;
+ break;
+ case CONVERSIONTYPENOTABASETYPE:
+ cout << "Conversion type is not a base type." << endl;
+ cout << "Please supply a valid base type as a conversion type." << endl;
+ break;
+ case CONVERSIONRETURNEDWRONGTYPE:
+ cout << "The conversion module returned a type that was not a base type." << endl;
+ cout << "Please contact customer support." << endl;
+ break;
+ case POLYGONCREATIONFAILED:
+ cout << "The string passed to the polygon switch was wrong." << endl;
+ break;
+ case OVERLAYDOMAINSDONOTMATCH:
+ cout << "The domains of the MDD objects to overlay do not match." << endl;
+ break;
+ case OVERLAYTYPESIZESDONOTMATCH:
+ cout << "The type sizes of the MDD objects to overlay do not match." << endl;
+ break;
+ case POLYGONDOMAINTOOLARGE:
+ cout << "The domain of the MDD object does not cover the bounding box of the polygon." << endl;
+ break;
+ case NOCOLLNAMEDEFINED:
+ cout << "No collection name defined." << endl;
+ break;
+ case NOMDDTYPEDEFINED:
+ cout << "No mdd type defined." << endl;
+ break;
+ case MDDTYPEOFGMARRAYNOTINITIALISED:
+ cout << "MDD type of GMarray not initialised." << endl;
+ break;
+ case SCALEDOMAINISNOTCORRECT:
+ cout << "Scale domain is not correct." << endl;
+ break;
+ case SCALELEVELSINCORRECT:
+ cout << "Scale levels are not correct." << endl;
+ break;
+ case GMARRAYSARENOTEQUAL:
+ cout << "The GMarrays were not equal." << endl;
+ break;
+ case UNKNOWNSCALEFUNCTION:
+ cout << "The supplied scale function is unknown." << endl;
+ break;
+ case UNABLETOCLAIMRESOURCEFORFILE:
+ cout << "Unable to claim memory for the input files." << endl;
+ break;
+ case ERRORPARSINGCOMMANDLINE:
+ cout << "Error parsing the command line." << endl;
+ break;
+ case TILINGTYPENOTALLOWED:
+ cout << "The tiling type is not allowed." << endl;
+ break;
+ case LAYERSNOTCORRECT:
+ cout << "The layer parameter is not correct." << endl;
+ break;
+ case TOOMANYLAYERS:
+ cout << "There are too many layers defined for the merging." << endl;
+ break;
+ case OVERLAYDOMAINDOESNOTMATCH:
+ cout << "The overlay domain does not cover the domain of the input file." << endl;
+ break;
+ case TILEDUPDATEANDFILE:
+ cout << "Option tiledupdate and file specified." << endl;
+ break;
+ case NOCOMPAREDESTINATION:
+ cout << "Need either a file or a collection name to get the source data for the compare operation." << endl;
+ break;
+ case CONVERSIONTYPEMISSING:
+ cout << "Conversion type is missing." << endl;
+ break;
+ default :
+ cout << "Unknown execution code: " << retval << endl;
+ break;
+ case ALLDONE:
+ case 0:
+ cout << "No errors" << endl;
+ }
+ delete theTiling;
+ theTiling = NULL;
+ if (scaleLevels != NULL)
+ {
+ std::list<std::pair<double, char*> >::iterator iter = scaleLevels->begin();
+ std::list<std::pair<double, char*> >::iterator end = scaleLevels->end();
+ for (; iter != end; iter++)
+ {
+ delete [] (*iter).second;
+ (*iter).second = NULL;
+ }
+ delete scaleLevels;
+ scaleLevels = NULL;
+ }
+ }
+
+int
+SystemBasic::initGMarray(r_Ref<r_GMarray>& tempMDD, FILE* tempFile, r_Data_Format conversionFormat, r_Minterval& tempDataDomain, const char* conversionParams) throw (r_Error)
+ {
+ int retval = 0;
+ char* mddData = NULL;
+ size_t mddDataSize = 0;
+ r_Type* tempType = NULL;
+ r_Base_Type* conversionType = NULL;
+ const r_Base_Type* tempBaseType = (r_Base_Type*)tempMDD->get_base_type_schema();
+ if (tempBaseType != NULL)
+ {
+ mddData = getData(tempFile, mddDataSize, retval);
+ if (retval != 0)
+ return retval;
+ try {
+ tempType = r_Type::get_any_type(conversionTypeName);
+ }
+ catch (const r_Error& err)
+ {
+ RMInit::logOut << "Resolving conversion type: Exception in get_any_type: " << err.get_errorno() << " " << err.what() << endl;
+ delete tempType;
+ tempType = NULL;
+ retval = CONVERSIONTYPENOTABASETYPE;
+ }
+ if (!tempType->isBaseType())
+ {
+ retval = CONVERSIONTYPENOTABASETYPE;
+ delete tempType;
+ tempType = NULL;
+ }
+ else {
+ conversionType = (r_Base_Type*)tempType;
+ retval = convertFrom(conversionFormat, mddData, mddDataSize, tempDataDomain, conversionType, conversionParams);
+ if (retval == 0)
+ {
+ tempMDD->set_array_size(mddDataSize);
+ tempMDD->set_type_length(conversionType->size());
+ delete [] tempMDD->get_array();
+ tempMDD->set_array(mddData);
+ mddData = 0;
+ if (polygonDefined)
+ {
+/* should be done in r_PolygonCutOut
+ if (tempMDD->spatial_domain().covers(polygon.getBoundingBox()))
+ {
+*/
+ polygon.setMArray(*tempMDD);
+ if (insidePatternDef)
+ polygon.fillMArrayInside(insidePattern);
+ if (outsidePatternDef)
+ polygon.fillMArrayOutside(outsidePattern);
+/* should be done in r_PolygonCutOut
+ }
+ else {
+ RMInit::logOut << "Polygon Bounding Box " << polygon.getBoundingBox() << " GMarray Bounding Box " << tempMDD->spatial_domain() << std::endl;
+ retval = POLYGONDOMAINTOOLARGE;
+ }
+*/
+ }
+ }
+ else {
+ delete [] mddData;
+ mddData = 0;
+ }
+ delete conversionType;
+ conversionType = NULL;
+ }
+ }
+ else {
+ retval = MDDTYPEOFGMARRAYNOTINITIALISED;
+ }
+ return retval;
+ }
+
+int
+SystemBasic::compareGMarrays(const r_Ref<r_GMarray>& baseMDD, r_Ref<r_GMarray>& topMDD)
+ {
+ int retval = 0;
+ //r_GMarray* baseMDD = (r_GMarray*)&(*baseMDD2);
+ const r_Minterval& tempDomain = baseMDD->spatial_domain();
+ char* topMDDCells = topMDD->get_array();
+ const char* baseMDDCells = baseMDD->get_array();
+ wrongBytes = 0;
+
+ RMInit::logOut << "compareGMarrays: " << std::endl;
+ RMInit::logOut << "baseMDD domain: " << baseMDD->spatial_domain() << " type length: " << baseMDD->get_type_length() << std::endl;
+ RMInit::logOut << "topMDD domain: " << topMDD->spatial_domain() << " type length: " << topMDD->get_type_length() << std::endl;
+ if (tempDomain == topMDD->spatial_domain())
+ {
+ r_Bytes typeLen = baseMDD->get_type_length();
+ if (typeLen == topMDD->get_type_length())
+ {
+ r_Area numberCells = tempDomain.cell_count();
+
+ for (size_t elemNum = 0; elemNum < numberCells; elemNum++)
+ {
+ if (memcmp(&(baseMDDCells[elemNum * typeLen]), &(topMDDCells[elemNum * typeLen]), typeLen) != 0)
+ {
+ wrongBytes++;
+ }
+ }
+ wrongBytes*=typeLen;
+ }
+ else {
+ retval = OVERLAYTYPESIZESDONOTMATCH;
+ }
+ }
+ else {
+ retval = OVERLAYDOMAINSDONOTMATCH;
+ }
+ if (wrongBytes != 0)
+ {
+ retval = GMARRAYSARENOTEQUAL;
+ }
+ return retval;
+ }
+
+int
+SystemBasic::overlayGMarrays(r_Ref<r_GMarray>& targetMDD, const r_Ref<r_GMarray>& replaceBlackMDD, const r_Ref<r_GMarray>& backgroundMDD)
+ {
+ int retval = 0;
+
+ const r_Minterval& backgroundDomain = backgroundMDD->spatial_domain();
+ const r_Minterval& replaceBlackDomain = replaceBlackMDD->spatial_domain();
+ const r_Minterval& targetDomain = targetMDD->spatial_domain();
+
+ const char* replaceBlackMDDCells = replaceBlackMDD->get_array();
+ const char* backgroundMDDCells = backgroundMDD->get_array();
+ char* targetMDDCells = targetMDD->get_array();
+
+ RMInit::logOut << "overlayGMarrays: " << std::endl;
+ RMInit::logOut << "background MDD domain : " << backgroundMDD->spatial_domain() << " type length: " << backgroundMDD->get_type_length() << std::endl;
+ RMInit::logOut << "replace black MDD domain: " << replaceBlackMDD->spatial_domain() << " type length: " << replaceBlackMDD->get_type_length() << std::endl;
+ RMInit::logOut << "target MDD domain : " << targetMDD->spatial_domain() << " type length: " << replaceBlackMDD->get_type_length() << std::endl;
+
+ r_Bytes typeLen = backgroundMDD->get_type_length();
+ if ((typeLen == replaceBlackMDD->get_type_length()) && (typeLen == targetMDD->get_type_length()))
+ {
+ char* reference = new char[typeLen];
+ memset(reference, 0, typeLen);
+ if (backgroundDomain.get_extent() == targetDomain.get_extent())
+ //if ((backgroundDomain.get_extent() == replaceBlackDomain.get_extent()) && ((backgroundDomain.get_extent() == targetDomain.get_extent())))
+ {
+ if (backgroundDomain.get_extent() == replaceBlackDomain.get_extent())
+ {//background and target and transparent are equal
+ RMInit::logOut << "Overlay using fast method" << endl;
+ r_Area numberCells = backgroundDomain.cell_count();
+ for (size_t elemNum = 0; elemNum < numberCells; elemNum++)
+ {
+ if (memcmp(reference, &(replaceBlackMDDCells[elemNum * typeLen]), typeLen) == 0)
+ {
+ memcpy(&(targetMDDCells[elemNum * typeLen]), &(backgroundMDDCells[elemNum * typeLen]), typeLen);
+ }
+ else {
+ memcpy(&(targetMDDCells[elemNum * typeLen]), &(replaceBlackMDDCells[elemNum * typeLen]), typeLen);
+ }
+ }
+ }
+ else {//background and target are equal in size, but not equal to transparent
+ if (backgroundMDDCells == targetMDDCells)
+ {
+ RMInit::logOut << "Overlay background and target not neccessary" << endl;
+ }
+ else {
+ RMInit::logOut << "Overlay background and target using very fast method" << endl;
+ memcpy(targetMDDCells, backgroundMDDCells, backgroundDomain.cell_count() * typeLen);
+ }
+ //overlay target and transparent
+ r_Minterval overlayOn = replaceBlackDomain.create_intersection(backgroundDomain);
+ RMInit::logOut << "Overlay using slow method on " << overlayOn << endl;
+ r_Dimension dim = targetDomain.dimension();
+ r_Range width = overlayOn[dim - 1].get_extent();
+ r_MiterDirect replaceBlackIter((char*)replaceBlackMDDCells, replaceBlackDomain, overlayOn, typeLen);
+ r_MiterDirect targetIter((char*)targetMDDCells, targetDomain, overlayOn, typeLen);
+ while (!replaceBlackIter.isDone())
+ {
+ replaceBlackMDDCells = (const char*)replaceBlackIter.getData();
+ targetMDDCells = (char*)targetIter.getData();
+ for (size_t elemNum = 0; elemNum < width; elemNum++)
+ {
+ if (memcmp(reference, &(replaceBlackMDDCells[elemNum * typeLen]), typeLen) != 0)
+ {
+ memcpy(&(targetMDDCells[elemNum * typeLen]), &(replaceBlackMDDCells[elemNum * typeLen]), typeLen);
+ }
+ }
+ replaceBlackIter.id[dim-1].pos += width;
+ targetIter.id[dim-1].pos += width;
+ ++replaceBlackIter;
+ ++targetIter;
+ }
+ }
+ }
+ else {//background and target are not the same size. it does not matter if transparent is same as background
+ //need to use a miter, done as in Tile::copyTile, res is replaceBlack, op is background
+ r_Minterval overlayOn = replaceBlackDomain.create_intersection(backgroundDomain);
+ if (targetDomain.covers(overlayOn))
+ {//first copy background on top of target
+ RMInit::logOut << "Overlay using slow method on " << overlayOn << endl;
+ r_Minterval copyBackgroundDomain = targetDomain.create_intersection(backgroundDomain);
+ r_Dimension dim = copyBackgroundDomain.dimension();
+ r_Range backgroundWidth = copyBackgroundDomain[dim - 1].get_extent();
+ r_MiterDirect backgroundIter((char*)backgroundMDDCells, backgroundDomain, overlayOn, typeLen);
+ r_MiterDirect targetIter((char*)targetMDDCells, targetDomain, overlayOn, typeLen);
+ while (!targetIter.isDone())
+ {
+ backgroundMDDCells = (const char*)backgroundIter.getData();
+ targetMDDCells = (char*)targetIter.getData();
+
+ memcpy(targetMDDCells, backgroundMDDCells, typeLen * backgroundWidth);
+
+ backgroundIter.id[dim-1].pos += backgroundWidth;
+ targetIter.id[dim-1].pos += backgroundWidth;
+ ++backgroundIter;
+ ++targetIter;
+ }
+ targetMDDCells = targetMDD->get_array();
+
+ //overlay transparent over target
+ r_Range width = overlayOn[dim - 1].get_extent();
+ r_MiterDirect replaceBlackIter((char*)replaceBlackMDDCells, replaceBlackDomain, overlayOn, typeLen);
+ r_MiterDirect targetIter2((char*)targetMDDCells, targetDomain, overlayOn, typeLen);
+ while (!replaceBlackIter.isDone())
+ {
+ replaceBlackMDDCells = (const char*)replaceBlackIter.getData();
+ targetMDDCells = (char*)targetIter2.getData();
+ for (size_t elemNum = 0; elemNum < width; elemNum++)
+ {
+ if (memcmp(reference, &(replaceBlackMDDCells[elemNum * typeLen]), typeLen) != 0)
+ {
+ memcpy(&(targetMDDCells[elemNum * typeLen]), &(replaceBlackMDDCells[elemNum * typeLen]), typeLen);
+ }
+ }
+ replaceBlackIter.id[dim-1].pos += width;
+ targetIter2.id[dim-1].pos += width;
+ ++replaceBlackIter;
+ ++targetIter2;
+ }
+ }
+ else {
+ RMInit::logOut << "Target domain does not cover the overlay domain" << endl;
+ retval = OVERLAYDOMAINDOESNOTMATCH;
+ }
+ }
+ delete [] reference;
+ reference = NULL;
+ }
+ else {
+ retval = OVERLAYTYPESIZESDONOTMATCH;
+ }
+ return retval;
+ }
+
+int
+SystemBasic::scaleDomain(const r_Minterval& baseDomain, const r_Point& origin, double factor, r_Minterval& scaledDomain, r_Minterval& clipDomain, unsigned int& length)
+ {
+ int retval = 0;
+ r_Dimension dim = origin.dimension();
+ r_Dimension i = 0;
+ scaledDomain = r_Minterval(dim);
+ clipDomain = r_Minterval(dim);
+ r_Range low = 0;
+ r_Range high = 0;
+ r_Range baseSteps = 0;
+ r_Range scaleSteps = 0;
+ r_Range originVal = 0;
+ length = floor(1.0 / factor + 0.5);
+ if (baseDomain.dimension() == dim)
+ {
+ try {
+ for (; i < dim; i++)
+ {
+ const r_Sinterval& baseSinterval = baseDomain[i];
+ originVal = origin[i];
+ // simple trafo of low coordinate
+ low = (r_Range)(originVal + floor((baseSinterval.low() - originVal) * factor));
+ // for the high coordinate use the low coordinate of the _next_ tile
+ // ( = baseDomain[i].high() + 1 ) and subtract 1 ==> seamless tilingfactor
+ high = (r_Range)(originVal + floor((baseSinterval.high() + 1 - originVal) * factor) - 1);
+ // number of steps in base interval
+ baseSteps = floor((baseSinterval.high() - baseSinterval.low() + length) / length);
+ // number of steps in scaled interval
+ scaleSteps = high - low + 1;
+ if (baseSteps == scaleSteps)
+ {// everything is ok
+ scaledDomain << r_Sinterval(low, high);
+ clipDomain << baseSinterval;
+ }
+ else {
+ if (baseSteps < scaleSteps)
+ {// the base is too small -> shrink the scale interval
+ RMInit::logOut << "WARNING: " << baseDomain << " * " << factor << " : clipping the scale interval" << endl;
+ scaledDomain << r_Sinterval(low, low + baseSteps - 1);
+ clipDomain << baseSinterval;
+ }
+ else {// the scale is too small -> shrink the clip interval
+ RMInit::logOut << "WARNING: " << baseDomain << " * " << factor << " : clipping the base interval" << endl;
+ scaledDomain << r_Sinterval(low, high);
+ clipDomain << r_Sinterval(baseSinterval.low(), (r_Range)(baseSinterval.low() + scaleSteps * length - 1));
+ }
+ }
+ }
+ }
+ catch (r_Error& err)
+ {
+ RMInit::logOut << "SystemBasic::scaleDomain(" << baseDomain << ", " << scaleDomain << ", " << factor << ", " << origin << ") caught error : " << err.get_errorno() << " " << err.what() << endl;
+ retval = SCALEDOMAINISNOTCORRECT;
+ }
+ }
+ else {
+ retval = SCALEDOMAINISNOTCORRECT;
+ }
+ return retval;
+ }
+
+int
+SystemBasic::updateScaledMDD(const r_Ref<r_GMarray>& baseMDD, const r_Minterval& clipDomain, const r_Minterval& downScaleDomain, unsigned int length, const char* collectionName) throw (r_Error)
+ {
+ RMInit::logOut << "SystemBasic::updateScaledMDD(MDD, " << clipDomain << ", " << downScaleDomain << ", " << length << ", " << collectionName << ")" << endl;
+ int retval = 0;
+ const r_Minterval& baseDomain = baseMDD->spatial_domain();
+ if (retval == 0)
+ {
+ size_t tlen = baseMDD->get_type_length();
+ r_Ref<r_GMarray> scaledMDD = new (baseMDD->get_type_name())r_GMarray(downScaleDomain, tlen);
+ const r_Type* type = scaledMDD->get_base_type_schema();
+ if (type != NULL)
+ {
+ if (type->isPrimitiveType())
+ {
+ fast_scale_process_primitive_type((const r_Primitive_Type*)type, scaledMDD->get_array(), baseMDD->get_array(), downScaleDomain, baseDomain, clipDomain, tlen, length, scaleFunction);
+ }
+ else {
+ if (type->isStructType())
+ {
+ fast_scale_process_structured_type((const r_Structure_Type*)type, scaledMDD->get_array(), baseMDD->get_array(), downScaleDomain, baseDomain, clipDomain, tlen, length, scaleFunction);
+ }
+ else {
+ retval = NOBASETYPE;
+ }
+ }
+ }
+ else {
+ retval = NOBASETYPE;
+ }
+ if (retval == 0)
+ {//update the collection
+ std::ostringstream stream;
+ stream << "UPDATE " << collectionName << " AS A SET A" << downScaleDomain << " ASSIGN $1";
+ r_OQL_Query query(stream.str().c_str());
+ query << *scaledMDD;
+ RMDBGIF(20, RMDebug::module_tools, "WAITBEFOREQL", \
+ RMInit::dbgOut << "Waiting 10 sec before execute\n" << std::endl; \
+ sleep(10); \
+ RMInit::dbgOut << "Continue now\n" << std::endl; );
+ r_oql_execute(query);
+ RMDBGIF(20, RMDebug::module_tools, "WAITAFTERQL", \
+ RMInit::dbgOut << "Waiting 10 sec after execute\n" << std::endl; \
+ sleep(10); \
+ RMInit::dbgOut << "Continue now\n" << std::endl; );
+ }
+ scaledMDD.destroy();
+ }
+ return retval;
+ }
+
+int
+SystemBasic::compareScaledMDD(const r_Ref<r_GMarray>& baseMDD, const r_Minterval& clipDomain, const r_Minterval& downScaleDomain, unsigned int length, const char* collectionName) throw (r_Error)
+ {
+ RMInit::logOut << "SystemBasic::compareScaledMDD(MDD, " << clipDomain << ", " << downScaleDomain << ", " << length << ", " << collectionName << ")" << endl;
+ int retval = 0;
+ const r_Minterval& baseDomain = baseMDD->spatial_domain();
+ if (retval == 0)
+ {
+ size_t tlen = baseMDD->get_type_length();
+ r_Ref<r_GMarray> scaledMDD = new (baseMDD->get_type_name())r_GMarray(downScaleDomain, tlen);
+ const r_Type* type = ((r_GMarray*)&*baseMDD)->get_base_type_schema();
+ if (type != NULL)
+ {
+ if (type->isPrimitiveType())
+ {
+ fast_scale_process_primitive_type((const r_Primitive_Type*)type, scaledMDD->get_array(), baseMDD->get_array(), downScaleDomain, baseDomain, clipDomain, tlen, length, scaleFunction);
+ }
+ else {
+ if (type->isStructType())
+ {
+ fast_scale_process_structured_type((const r_Structure_Type*)type, scaledMDD->get_array(), baseMDD->get_array(), downScaleDomain, baseDomain, clipDomain, tlen, length, scaleFunction);
+ }
+ else {
+ RMInit::logOut << "scaledMDD returned a type (" << type->name() << ") which is neither primitive nor structured" << endl;
+ retval = NOBASETYPE;
+ }
+ }
+ }
+ else {
+ RMInit::logOut << "scaledMDD returned no base type schema" << endl;
+ retval = NOBASETYPE;
+ }
+ if (retval == 0)
+ {//update the collection
+ std::ostringstream stream;
+ stream << "SELECT A" << downScaleDomain << " FROM " << collectionName << " AS A";
+ r_OQL_Query query(stream.str().c_str());
+ r_Set< r_Ref_Any > result;
+ r_oql_execute(query, result);
+ r_Iterator< r_Ref_Any > iter = result.create_iterator();
+ r_Ref<r_GMarray> selectedMDD = r_Ref<r_GMarray>(*iter);
+ if (retval == 0)
+ {
+ retval = compareGMarrays(selectedMDD, scaledMDD);
+ if ((outputFileName != NULL) && ((retval != 0) || (force)))
+ {
+ char* tempName = new char[strlen(outputFileName) + strlen("image.png") + strlen(collectionName) + 1];
+ strcpy(tempName, outputFileName);
+ strcat(tempName, collectionName);
+ strcat(tempName, ".db.png");
+ saveData(tempName, selectedMDD->get_array(), selectedMDD->get_array_size(), selectedMDD->spatial_domain());
+ strcpy(tempName, outputFileName);
+ strcat(tempName, collectionName);
+ strcat(tempName, ".scaled.png");
+ saveData(tempName, scaledMDD->get_array(), scaledMDD->get_array_size(), scaledMDD->spatial_domain());
+ delete [] tempName;
+ tempName = NULL;
+ }
+ }
+ selectedMDD.destroy();
+ }
+ scaledMDD.destroy();
+ }
+ return retval;
+ }
+
+void
+fast_scale_process_primitive_type(const r_Primitive_Type *primType, char *dest, const char *src, const r_Minterval &destIv, const r_Minterval &srcIv, const r_Minterval &srcIter, unsigned int type_len, unsigned int length, r_Scale_Function func)
+ {
+ if (func == r_BitAggregation)
+ {
+ switch (primType->type_id())
+ {
+ case r_Primitive_Type::BOOL:
+ case r_Primitive_Type::CHAR:
+ case r_Primitive_Type::OCTET:
+ fast_scale_aggregate_array((char*)dest, (const char*)src, destIv, srcIv, srcIter, type_len, length);
+ break;
+ case r_Primitive_Type::SHORT:
+ case r_Primitive_Type::USHORT:
+ fast_scale_aggregate_array((short*)dest, (const short*)src, destIv, srcIv, srcIter, type_len, length);
+ break;
+ case r_Primitive_Type::LONG:
+ case r_Primitive_Type::ULONG:
+ case r_Primitive_Type::FLOAT:
+ fast_scale_aggregate_array((int*)dest, (const int*)src, destIv, srcIv, srcIter, type_len, length);
+ break;
+ case r_Primitive_Type::DOUBLE:
+ fast_scale_aggregate_array((long long*)dest, (const long long*)src, destIv, srcIv, srcIter, type_len, length);
+ break;
+ default:
+ RMInit::logOut << "Resample Array: unknown primitive type " << primType->type_id() << endl;
+ break;
+ }
+ }
+ else {
+ switch (primType->type_id())
+ {
+ case r_Primitive_Type::BOOL:
+ fast_scale_resample_array((r_Boolean*)dest, (const r_Boolean*)src, destIv, srcIv, srcIter, type_len, length, true);
+ break;
+ case r_Primitive_Type::CHAR:
+ fast_scale_resample_array((r_Char*)dest, (const r_Char*)src, destIv, srcIv, srcIter, type_len, length, true);
+ break;
+ case r_Primitive_Type::OCTET:
+ fast_scale_resample_array((r_Octet*)dest, (const r_Octet*)src, destIv, srcIv, srcIter, type_len, length, true);
+ break;
+ case r_Primitive_Type::SHORT:
+ fast_scale_resample_array((r_Short*)dest, (const r_Short*)src, destIv, srcIv, srcIter, type_len, length, true);
+ break;
+ case r_Primitive_Type::USHORT:
+ fast_scale_resample_array((r_UShort*)dest, (const r_UShort*)src, destIv, srcIv, srcIter, type_len, length, true);
+ break;
+ case r_Primitive_Type::LONG:
+ fast_scale_resample_array((r_Long*)dest, (const r_Long*)src, destIv, srcIv, srcIter, type_len, length, true);
+ break;
+ case r_Primitive_Type::ULONG:
+ fast_scale_resample_array((r_ULong*)dest, (const r_ULong*)src, destIv, srcIv, srcIter, type_len, length, true);
+ break;
+ case r_Primitive_Type::FLOAT:
+ fast_scale_resample_array((r_Float*)dest, (const r_Float*)src, destIv, srcIv, srcIter, type_len, length, false);
+ break;
+ case r_Primitive_Type::DOUBLE:
+ fast_scale_resample_array((r_Double*)dest, (const r_Double*)src, destIv, srcIv, srcIter, type_len, length, false);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+void
+fast_scale_process_structured_type(const r_Structure_Type *structType, char *dest, const char *src, const r_Minterval &destIv, const r_Minterval &srcIv, const r_Minterval &srcIter, unsigned int type_len, unsigned int length, r_Scale_Function func)
+ {
+ r_Structure_Type::attribute_iterator iter(structType->defines_attribute_begin());
+ while (iter != structType->defines_attribute_end())
+ {
+ r_Type *newType;
+ unsigned long offset;
+
+ newType = (*iter).type_of().clone();
+ offset = (*iter).offset();
+
+ if (newType->isStructType())
+ {
+ r_Structure_Type *newStructType = (r_Structure_Type*)newType;
+ fast_scale_process_structured_type(newStructType, dest + offset, src + offset, destIv, srcIv, srcIter, type_len, length, func);
+ }
+ else
+ {
+ r_Primitive_Type *newPrimType = (r_Primitive_Type*)newType;
+ fast_scale_process_primitive_type(newPrimType, dest + offset, src + offset, destIv, srcIv, srcIter, type_len, length, func);
+ }
+ delete newType;
+ iter++;
+ }
+ }
+
+
+// always iterate over the full dest domain, but not over the full src domain.
+template<class T>
+void fast_scale_resample_array(T *dest, const T *src, const r_Minterval &destIv, const r_Minterval &srcIv, const r_Minterval &iterDom, unsigned int type_len, unsigned int length, bool round)
+ {
+ //cout << "here " << destIv << srcIv << iterDom << ", " << type_len << " " << length << endl;
+ r_MiterDirect destIter((void*)dest, destIv, destIv, type_len, 1);
+ r_MiterDirect subIter((void*)src, srcIv, iterDom, type_len, 1);
+ r_MiterDirect srcIter((void*)src, srcIv, iterDom, type_len, length);
+ unsigned int dim = (unsigned int)srcIv.dimension();
+ unsigned int i;
+
+ for (i=0; i<dim; i++)
+ {
+ subIter.id[i].low = 0;
+ }
+ while (srcIter.done == 0)
+ {
+ double sum = 0;
+ unsigned int count = 1;
+
+ // init sub iterator
+ subIter.done = 0;
+ for (i=0; i<dim; i++)
+ {
+ long rest;
+
+ subIter.id[i].pos = 0;
+ subIter.id[i].data = srcIter.getData();
+ rest = srcIter.id[i].high - srcIter.id[i].pos;
+ if (rest >= (long)length)
+ rest = (long)length-1;
+ subIter.id[i].high = rest;
+ count *= rest+1;
+ }
+ while (subIter.done == 0)
+ {
+ sum += *((const T*)(subIter.getData()));
+ ++subIter;
+ }
+ // use round to nearest
+ if (round)
+ *((T*)(destIter.getData())) = (T)(sum / count + 0.5);
+ else
+ *((T*)(destIter.getData())) = (T)(sum / count);
+ //cout << (long)(((const T*)(srcIter.getData())) - src) << " , " << (long)(((T*)(destIter.getData())) - dest) << endl;
+ ++srcIter;
+ ++destIter;
+ }
+ }
+
+// always iterate over the full dest domain, but not over the full src domain.
+template<class T>
+void fast_scale_aggregate_array(T *dest, const T *src, const r_Minterval &destIv, const r_Minterval &srcIv, const r_Minterval &iterDom, unsigned int type_len, unsigned int length)
+ {
+ //cout << "here " << destIv << srcIv << iterDom << ", " << type_len << " " << length << endl;
+ r_MiterDirect destIter((void*)dest, destIv, destIv, type_len, 1);
+ r_MiterDirect subIter((void*)src, srcIv, iterDom, type_len, 1);
+ r_MiterDirect srcIter((void*)src, srcIv, iterDom, type_len, length);
+ unsigned int dim = (unsigned int)srcIv.dimension();
+ unsigned int i;
+
+ for (i=0; i<dim; i++)
+ {
+ subIter.id[i].low = 0;
+ }
+ while (srcIter.done == 0)
+ {
+ T sum = 0;
+ unsigned int count = 1;
+
+ // init sub iterator
+ subIter.done = 0;
+ for (i=0; i<dim; i++)
+ {
+ long rest;
+
+ subIter.id[i].pos = 0;
+ subIter.id[i].data = srcIter.getData();
+ rest = srcIter.id[i].high - srcIter.id[i].pos;
+ if (rest >= (long)length)
+ rest = (long)length-1;
+ subIter.id[i].high = rest;
+ count *= rest+1;
+ }
+ while (subIter.done == 0)
+ {
+ sum |= *((const T*)(subIter.getData()));
+ ++subIter;
+ }
+ *((T*)(destIter.getData())) = sum;
+ //cout << (long)(((const T*)(srcIter.getData())) - src) << " , " << (long)(((T*)(destIter.getData())) - dest) << endl;
+ ++srcIter;
+ ++destIter;
+ }
+ }
+
+#ifdef TESTBASIC
+int
+main(int argc, const char** argv)
+ {
+ r_Minterval baseDomain("[0:1024]");
+ r_Point origin("[0]");
+ r_Point translation("[256]");
+ double factor = 0.5;
+ r_Minterval scaledDomain;
+ r_Minterval clipDomain;
+ unsigned int length = 0;
+ for (int o = 0; o < 1024; o++)
+ {
+ for (int i = 0; i < 1024; i++)
+ {
+ for (int a = 0; a < 8; a++)
+ {
+ SystemBasic::scaleDomain(baseDomain, origin, factor, scaledDomain, clipDomain, length);
+ if (clipDomain != baseDomain)
+ {
+ cout << "ERROR clip != base (" << factor << "): " << clipDomain << " " << baseDomain << endl;
+ }
+ factor = factor /2;
+ }
+ factor = 0.5;
+ baseDomain.translate(translation);
+ }
+ baseDomain = r_Minterval("[256:511]");
+ baseDomain[0].set_high(256 * (o + 2) - 1);
+ }
+ }
+#endif
diff --git a/rasodmg/test/system_basic.hh b/rasodmg/test/system_basic.hh
new file mode 100644
index 0000000..ef7d083
--- /dev/null
+++ b/rasodmg/test/system_basic.hh
@@ -0,0 +1,210 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#ifndef _SYSTEMBASIC_HH_
+#define _SYSTEMBASIC_HH_
+
+class r_Tiling;
+
+// fopen, getc
+#include <stdio.h>
+#include <list>
+#include "raslib/mddtypes.hh"
+#include "raslib/minterval.hh"
+#include "raslib/scalar.hh"
+#include "raslib/odmgtypes.hh"
+#include "raslib/oid.hh"
+#include "rasodmg/transaction.hh"
+#include "rasodmg/database.hh"
+#include "rasodmg/ref.hh"
+#include "rasodmg/set.hh"
+#include "rasodmg/gmarray.hh"
+#include "rasodmg/polycutout.hh"
+#include "cmlparser.hh"
+
+class SystemBasic
+ {
+ public:
+ static char* getData(FILE* file, size_t& dtaSize, int& retval);
+
+ static void printScalar(const r_Scalar& scalar);
+
+ static int checkArguments(int argc, const char** argv, const char* searchText, int& optionValueIndex);
+
+ static void explainRetval(int retval);
+
+ static void printOptions();
+
+ static int parseParams(int argc, char** argv);
+
+ static FILE* checkFile(const char* fileArg, int& retval);
+
+ static int convertTo(r_Data_Format fmt, char*& src, size_t& size, r_Minterval& interv, r_Base_Type*& tp, const char* options);
+
+ static int convertFrom(r_Data_Format fmt, char*& src, size_t& size, r_Minterval& interv, r_Base_Type*& tp, const char* options);
+
+ static int readScaleLevels(const char* argv);
+
+ static int initGMarray(r_Ref<r_GMarray>& tempMDD, FILE* tempFile, r_Data_Format conversionFormat, r_Minterval& tempDataDomain, const char* conversionParams) throw (r_Error);
+
+ static int overlayGMarrays(r_Ref<r_GMarray>& target, const r_Ref<r_GMarray>& replaceBlackMDD, const r_Ref<r_GMarray>& backgroundMDD);
+
+ static int compareGMarrays(const r_Ref<r_GMarray>& baseMDD, r_Ref<r_GMarray>& topMDD);
+
+ static void openTransaction(bool readwrite = true) throw (r_Error);
+
+ static int compareScaledMDD(const r_Ref<r_GMarray>& baseMDD, const r_Minterval& clipDom, const r_Minterval& downScaledDomain, unsigned int length, const char* collectionName) throw (r_Error);
+
+ static int updateScaledMDD(const r_Ref<r_GMarray>& baseMDD, const r_Minterval& clipDom, const r_Minterval& downScaledDomain, unsigned int length, const char* collectionName) throw (r_Error);
+
+ static int scaleDomain(const r_Minterval& baseDomain, const r_Point& origin, double factor, r_Minterval& scaledDomain, r_Minterval& clipDomain, unsigned int& length);
+
+ static int saveData(const char* fileNamePat, const char* data, r_Bytes length, const r_Minterval& mddDomain);
+
+ static const char* serverName;
+ static r_ULong serverPort;
+ static const char* baseName;
+ static const char* userName;
+ static const char* passwd;
+ static bool printText;
+ static const char* outputFileName;
+ static const char* conversionTypeName;
+ static r_Data_Format inputFormat;
+ static const char* inputFormatParams;
+ static r_Data_Format outputFormat;
+ static const char* outputFormatParams;
+ static r_Data_Format transferFormat;
+ static const char* transferFormatParams;
+ static r_Data_Format storageFormat;
+ static const char* storageFormatParams;
+ static const char* collName;
+ static const char* setTypeName;
+ static const char* mddTypeName;
+ static r_OId mddOId;
+ static bool mddOIdDef;
+ static r_OId collOId;
+ static bool collOIdDef;
+ static const char* fileName;
+ static r_Database db;
+ static r_Transaction ta;
+ static r_Minterval mddDomain;
+ static bool mddDomainDef;
+ static bool testBed;
+ static r_Tiling* theTiling;
+ static bool polygonDefined;
+ static r_PolygonCutOut polygon;
+ static int polygonShrinker;
+ static bool transparent;
+ static string outsidePatternSel;
+ static bool outsidePatternSelDef;
+ static string insidePatternSel;
+ static bool insidePatternSelDef;
+ static string outsidePattern;
+ static bool outsidePatternDef;
+ static string insidePattern;
+ static bool insidePatternDef;
+ static const int queryBufferLength;
+ static std::list<std::pair<double, char*> >* scaleLevels;
+ static int wrongBytes;
+ static r_Scale_Function scaleFunction;
+ static const string tilingDesc;
+ static const string tilingParamsDesc;
+ static const char* noUsageHeader;
+ static const char* usageHeader;
+ static const char* noUsageFooter;
+ static const char* usageFooter;
+ static size_t updateBufferSize;
+ static const char* defaultUpdateBufferSize;
+ static std::list<char*> layerList;
+ static std::list<unsigned int> patternsTrue;
+ static std::list<unsigned int> patternsFalse;
+ static r_Minterval overlayDomain;
+ static bool overlayDomainDef;
+ static r_Range align;
+ static bool tiledUpdate;
+ static bool handleSignal;
+ static bool force;
+ };
+
+void signalHandler(int sig);
+
+void installSignalHandlers();
+
+#define QUERYBUFFERLENGTH 512
+
+#define ALLDONE -1
+#define OK 0
+#define CREATEANDNOCREATE 1
+#define NOVALIDDOMAIN 2
+#define FILEINACCESSIBLE 3
+#define FILENAMETOLONG 4
+#define NOCREATECREATECOLL 5
+#define NOCOLLTYPE 6
+#define COLLOIDANDCOLLNAME 7
+#define CREATECOLLWITHOID 8
+#define CREATEMDDWITHOID 9
+#define INVALIDTILESIZE 10
+#define DOMAINDATAMISMATCH 11
+#define MDDDOMAINNOTSPECIFIED 12
+#define FILENAMENOTSPECIFIED 13
+#define NOCOLLNAMENOCOLLOID 14
+#define MDDTYPEINVALID 15
+#define NOBASETYPE 16
+#define EXCEPTIONCREATECOLL 17
+#define EXCEPTIONADMIN 18
+#define COLLECTIONINACCESSIBLE 19
+#define MDDINACCESSIBLE 20
+#define OIDINVALID 21
+#define MDDOIDANDCOLL 22
+#define ARGUMENTSMISSING 23
+#define ARGUMENTSINCOMPLETE 24
+#define EXCEPTIONEXECUTEQUERY 25
+#define NOQUERY 26
+#define CONVERSIONNOTSUPPORTED 27
+#define CONVERSIONEXCEPTION 28
+#define UNKNOWNTILINGTYPE 29
+#define TILINGPARAMETERSMISSING 30
+#define TILINGPATAMETERSINCORRECT 31
+#define CONVERSIONTYPENOTABASETYPE 32
+#define CONVERSIONRETURNEDWRONGTYPE 33
+#define POLYGONCREATIONFAILED 34
+#define OVERLAYDOMAINSDONOTMATCH 35
+#define OVERLAYTYPESIZESDONOTMATCH 36
+#define POLYGONDOMAINTOOLARGE 37
+#define NOCOLLNAMEDEFINED 38
+#define NOMDDTYPEDEFINED 39
+#define MDDTYPEOFGMARRAYNOTINITIALISED 40
+#define SCALEDOMAINISNOTCORRECT 41
+#define SCALELEVELSINCORRECT 42
+#define GMARRAYSARENOTEQUAL 43
+#define UNKNOWNSCALEFUNCTION 44
+#define UNABLETOCLAIMRESOURCEFORFILE 45
+#define ERRORPARSINGCOMMANDLINE 46
+#define TILINGTYPENOTALLOWED 47
+#define LAYERSNOTCORRECT 48
+#define TOOMANYLAYERS 49
+#define OVERLAYDOMAINDOESNOTMATCH 50
+#define TILEDUPDATEANDFILE 51
+#define NOCOMPAREDESTINATION 52
+#define CONVERSIONTYPEMISSING 53
+#endif
diff --git a/rasodmg/test/system_compare.cc b/rasodmg/test/system_compare.cc
new file mode 100644
index 0000000..1dbc507
--- /dev/null
+++ b/rasodmg/test/system_compare.cc
@@ -0,0 +1,273 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: system_compare.cc
+ *
+ * MODULE: rasodmg/test
+ *
+ * COMMENTS:
+ * None
+*/
+
+static const char rcsid[] = "@(#)rasodmg/test,SystemCompare: $Id: system_compare.cc,v 1.3 2002/07/16 07:42:36 hoefner Exp $";
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#include "raslib/template_inst.hh"
+#endif
+
+#include "system_compare.hh"
+#include "raslib/rminit.hh"
+#include "raslib/rmdebug.hh"
+#include "raslib/primitivetype.hh"
+#include "raslib/marraytype.hh"
+#include "rasodmg/tiling.hh"
+#include "rasodmg/stattiling.hh"
+#include "rasodmg/storagelayout.hh"
+#include "rasodmg/oqlquery.hh"
+#include "clientcomm/clientcomm.hh"
+
+int main(int argc, const char** argv)
+ {
+ SystemBasic::usageHeader = "system_compare version 0.9\n\t\tProgram for checking data in RasDaMan\n";
+ SystemBasic::usageFooter = "Required information:\n\t\tMDD type\n\t\tCollection name\n\t\tMDD domain\n\t\tScale levels or file name\n";
+ int retval = 0;
+ try {
+ retval = SystemCompare::doStuff(argc, argv);
+ }
+ catch (r_Error& e)
+ {
+ cout << "Caught Exception at top level: " << e.get_errorno() << " " << e.what() << endl;
+ }
+ }
+
+int
+SystemCompare::doStuff(int argc, const char** argv)
+ {
+ installSignalHandlers();
+ int retval = 0;
+ retval = parseParams(argc, (char**)argv);
+ if (retval == 0)
+ {
+ if (mddTypeName)
+ {
+ if (mddDomainDef)
+ {
+ if (collName)
+ {
+ if (fileName)
+ {//compare given file with database
+ retval = doCompare();
+ }
+ else {
+ if (scaleLevels != NULL)
+ {//compare scalelevels
+ retval = doCompare();
+ }
+ else {
+ retval = NOCOMPAREDESTINATION;
+ }
+ }
+ }
+ else {
+ retval = NOCOLLNAMEDEFINED;
+ }
+ }
+ else {
+ retval = MDDDOMAINNOTSPECIFIED;
+ }
+ }
+ else {
+ retval = NOMDDTYPEDEFINED;
+ }
+ }
+ explainRetval(retval);
+ return retval;
+ }
+
+//SystemUpdate::doUpdate(const char* queryString, const char* queryStringS, const char* mddTypeName, const r_Marray_Type mddType, const r_Minterval& mddDomain, const char* inputFormatParams, )
+int
+SystemCompare::doCompare()
+ {
+ int retval = 0;
+ char queryBufferS[QUERYBUFFERLENGTH];
+ memset(queryBufferS, 0, QUERYBUFFERLENGTH * sizeof(char));
+ if (mddOIdDef)
+ {
+ std::ostrstream stream(queryBufferS, QUERYBUFFERLENGTH);
+ stream << "SELECT A" << mddDomain << " FROM " << collName << " AS A WHERE oid(A) = " << mddOId;
+ }
+ else {
+ std::ostrstream stream(queryBufferS, QUERYBUFFERLENGTH);
+ stream << "SELECT A" << mddDomain << " FROM " << collName << " AS A";
+ }
+ r_Storage_Layout* stl = new r_Storage_Layout(theTiling->clone());
+ char* typeStructure = NULL;
+ r_Ref<r_GMarray> selectedMDD;
+ r_Set< r_Ref_Any > result;
+ r_Marray_Type* mddType = NULL;
+ try {
+ openTransaction(false);
+ typeStructure = db.communication->getTypeStructure(mddTypeName, ClientComm::r_MDDType_Type);
+ ta.abort();
+ db.close();
+ }
+ catch (r_Error& err)
+ {
+ RMInit::logOut << "Error during type retrieval from database: " << err.get_errorno() << " " << err.what() << endl;
+ typeStructure = new char[strlen(mddTypeName) + 1];
+ strcpy(typeStructure, mddTypeName);
+ }
+ try {
+ r_Type* tempType = r_Type::get_any_type(typeStructure);
+ if (tempType->isMarrayType())
+ {
+ mddType = (r_Marray_Type*)tempType;
+ }
+ else {
+ RMInit::logOut << "The type (" << typeStructure << ") is not an marray type." << endl;
+ retval = MDDTYPEINVALID;
+ }
+ }
+ catch (r_Error& err)
+ {
+ RMInit::logOut << "Error during type retrieval from type structure (" << typeStructure << "): " << err.get_errorno() << " " << err.what() << endl;
+ retval = MDDTYPEINVALID;
+ }
+ if (retval == 0)
+ {
+ size_t baseTypeLength = mddType->base_type().size();
+ if (fileName)
+ {//check if file corresponds to collection
+ r_Storage_Layout* stl = new r_Storage_Layout(theTiling->clone());
+ r_Ref<r_GMarray> tempMDD = new (mddTypeName)r_GMarray(mddDomain, baseTypeLength, stl);
+ tempMDD->set_type_schema(mddType);
+ FILE* filePointer = checkFile(fileName, retval);
+ if (retval != 0)
+ {
+ tempMDD.destroy();
+ return retval;
+ }
+ retval = initGMarray(tempMDD, filePointer, inputFormat, mddDomain, inputFormatParams);
+ fclose(filePointer);
+ if (retval == 0)
+ {
+ try {
+ r_OQL_Query query(queryBufferS);
+ openTransaction(false);
+ r_oql_execute(query, result);
+ r_Iterator< r_Ref_Any > iter = result.create_iterator();
+ selectedMDD = r_Ref<r_GMarray>(*iter);
+ if (polygonDefined)
+ {
+ polygon.setMArray(*selectedMDD);
+ if (foreGroundDef)
+ polygon.fillMArrayInside(foreGround);
+ if (backGroundDef)
+ polygon.fillMArrayOutside(backGround);
+ }
+ if (retval == 0)
+ {
+ retval = compareGMarrays(selectedMDD, tempMDD);
+ if (((retval != 0) || (force)) && (outputFileName != NULL))
+ {
+ char* tempName = new char[strlen(outputFileName) + strlen("image.png") + 1];
+ strcpy(tempName, outputFileName);
+ strcat(tempName, ".db.png");
+ saveData(tempName, selectedMDD->get_array(), selectedMDD->get_array_size(), selectedMDD->spatial_domain());
+ strcpy(tempName, outputFileName);
+ strcat(tempName, ".image.png");
+ saveData(tempName, tempMDD->get_array(), tempMDD->get_array_size(), tempMDD->spatial_domain());
+ delete [] tempName;
+ tempName = NULL;
+ }
+ }
+ ta.abort();
+ db.close();
+ }
+ catch (r_Error& err)
+ {
+ RMInit::logOut << "Error during administrative action: " << err.get_errorno() << " " << err.what() << endl;
+ retval = EXCEPTIONADMIN;
+ ta.abort();
+ }
+ if (db.get_status() != r_Database::not_open)
+ db.close();
+ }
+ }
+ if (scaleLevels != NULL)
+ {
+ try {
+ //initialise selectedMDD
+ r_OQL_Query query(queryBufferS);
+ openTransaction(false);
+ r_oql_execute(query, result);
+ r_Iterator< r_Ref_Any > iter = result.create_iterator();
+ selectedMDD = r_Ref<r_GMarray>(*iter);
+ if (polygonDefined)
+ {
+ polygon.setMArray(*selectedMDD);
+ if (foreGroundDef)
+ polygon.fillMArrayInside(foreGround);
+ if (backGroundDef)
+ polygon.fillMArrayOutside(backGround);
+ }
+ if (retval == 0)
+ {//read the scaled mdds from db and scale down the selected MDD and compare
+ std::list<std::pair<double, char*> >::iterator iter = scaleLevels->begin();
+ std::list<std::pair<double, char*> >::iterator end = scaleLevels->end();
+ r_Minterval scaledDomain;
+ r_Minterval clipDomain;
+ unsigned int length = 0;
+ r_Dimension maxDim = mddDomain.dimension();
+ r_Point origin(maxDim);
+ double factor = 0;
+ for (r_Dimension i = 0; i < maxDim; i++)
+ origin[i] = 0;
+ while ((iter != end) && (retval == 0))
+ {
+ factor = iter->first;
+ retval = scaleDomain(overlayDomain, origin, factor, scaledDomain, clipDomain, length);
+ RMInit::logOut << "scaled: " << iter->second << " scaled domain " << scaledDomain << " clip domain " << clipDomain << " result=" << retval << endl;
+ const r_Type* type = selectedMDD->get_base_type_schema();
+ size_t tlen = selectedMDD->get_type_length();
+ retval = compareScaledMDD(selectedMDD, clipDomain, scaledDomain, length, iter->second);
+ iter++;
+ }
+ }
+ ta.abort();
+ db.close();
+ }
+ catch (r_Error& err)
+ {
+ RMInit::logOut << "Error during administrative action: " << err.get_errorno() << " " << err.what() << endl;
+ retval = EXCEPTIONADMIN;
+ ta.abort();
+ }
+ if (db.get_status() != r_Database::not_open)
+ db.close();
+ }
+ }
+ return retval;
+ }
+
diff --git a/rasodmg/test/system_compare.hh b/rasodmg/test/system_compare.hh
new file mode 100644
index 0000000..f2d0136
--- /dev/null
+++ b/rasodmg/test/system_compare.hh
@@ -0,0 +1,40 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#ifndef _SYSTEMCOMPARE_HH_
+#define _SYSTEMCOMPARE_HH_
+
+#include "system_basic.hh"
+
+class SystemCompare : public SystemBasic
+ {
+ public:
+ static int doStuff(int argc, const char** argv);
+
+ static void printUsage();
+
+ static int doCompare();
+
+ };
+
+#endif
diff --git a/rasodmg/test/system_insert.cc b/rasodmg/test/system_insert.cc
new file mode 100644
index 0000000..f290778
--- /dev/null
+++ b/rasodmg/test/system_insert.cc
@@ -0,0 +1,384 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: system_insert.cc
+ *
+ * MODULE: rasodmg/test
+ *
+ * COMMENTS:
+ * None
+*/
+
+static const char rcsid[] = "@(#)rasodmg/test,SystemInsert: $Id: system_insert.cc,v 1.10 2002/03/13 13:48:17 coman Exp $";
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#include "raslib/template_inst.hh"
+#endif
+
+#include "system_insert.hh"
+#include "raslib/rminit.hh"
+#include "raslib/rmdebug.hh"
+#include "raslib/primitivetype.hh"
+#include "rasodmg/tiling.hh"
+#include "rasodmg/stattiling.hh"
+#include "rasodmg/storagelayout.hh"
+
+int main(int argc, const char** argv)
+ {
+ return SystemInsert::doStuff(argc, argv);
+ }
+
+int
+SystemInsert::doStuff(int argc, const char** argv)
+ {
+ RMInit::logOut.rdbuf(cout.rdbuf());
+ RMInit::dbgOut.rdbuf(cout.rdbuf());
+ RMDebug::level = 10;
+ r_Base_Type* conversionType = 0;
+ int retval = 0;
+
+ if ((argc == 1) || checkArguments(argc, argv, "-h", optionValueIndex) || checkArguments(argc, argv, "--help", optionValueIndex))
+ {
+ printUsage();
+ }
+ else {
+ retval = readArgs(argc, argv);
+ /*
+ what can we do:
+ create mdd:
+ requires
+ mddType
+ optional
+ collName ok
+ collOId ok
+ create coll:
+ requires
+ settype ok
+ optional
+ collName ok
+ insert existing mdd into coll:
+ requires
+ mddOId
+ collName/collOId
+ */
+ if (retval == 0)
+ {
+ if (mddTypeDef)
+ {//create mdd
+ if (mddOIdDef)
+ {//cannot create mdd with a user specified oid
+ retval = CREATEMDDWITHOID;
+ }
+ else {
+ if (fileNameDef)
+ {
+ if (mddDomainDef)
+ {
+ if (collNameDef)
+ {//create mdd, lookup coll by name, insert mdd into coll
+ //open stuff
+ try {
+ openTransaction();
+ //get collection
+ try {
+ collection = db.lookup_object(collName);
+ }
+ catch (r_Error& obj)
+ {
+ RMInit::logOut << "Error (" << obj.get_errorno() << ") accessing collection " << collName << ": " << obj.what() << endl;
+ retval = COLLECTIONINACCESSIBLE;
+ }
+ //create mddObject
+ if (retval == 0)
+ {
+ r_Storage_Layout* stl = new r_Storage_Layout(theTiling->clone());
+ //stl->set_storage_format(storageFormat, storageFormatParams);
+ mddObject = new (&db, mddTypeName) r_GMarray(mddDomain, 0, stl);
+ retval = initGMarray(mddObject, filePointer, inputFormat, mddDomain, inputFormatParams);
+ if (retval == 0)
+ {
+ collection->insert_element(mddObject);
+ ta.commit();
+ }
+ else
+ ta.abort();
+ }
+ else {
+ ta.abort();
+ }
+ db.close();
+ }
+ catch (r_Error& obj)
+ {
+ cout << "Exception (" << obj.get_errorno() << ") at administrative action: " << obj.what() << endl;
+ retval = EXCEPTIONADMIN;
+ ta.abort();
+ db.close();
+ }
+ }
+ else {//no collname
+ if (collOIdDef)
+ {//create mdd, lookup coll by oid, insert mdd into coll
+ try {
+ openTransaction();
+ //get collection
+ try {
+ collection = db.lookup_object(collOId);
+ }
+ catch (r_Error& obj)
+ {
+ RMInit::logOut << "Error (" << obj.get_errorno() << ") accessing collection " << collOId << ": " << obj.what() << endl;
+ retval = COLLECTIONINACCESSIBLE;
+ }
+ //create mddObject
+ if (retval == 0)
+ {
+ r_Storage_Layout* stl = new r_Storage_Layout(theTiling->clone());
+ //stl->set_storage_format(dataFormat, dataFormatParams);
+ mddObject = new (&db, mddTypeName) r_GMarray(mddDomain, 0, stl);
+ retval = initGMarray(mddObject, filePointer, inputFormat, mddDomain, inputFormatParams);
+ if (retval == 0)
+ {
+ collection->insert_element(mddObject);
+ ta.commit();
+ }
+ else
+ ta.abort();
+ }
+ else {
+ ta.abort();
+ }
+ db.close();
+ }
+ catch (r_Error& obj)
+ {
+ cout << "Exception (" << obj.get_errorno() << ") at administrative action: " << obj.what() << endl;
+ retval = EXCEPTIONADMIN;
+ ta.abort();
+ db.close();
+ }
+ }
+ else {//no collname, no collOId, create mdd
+ try {
+ openTransaction();
+ r_Storage_Layout* stl = new r_Storage_Layout(theTiling->clone());
+ //stl->set_storage_format(storageFormat, storageFormatParams);
+ mddObject = new (&db, mddTypeName) r_GMarray(mddDomain, 0, stl);
+ retval = initGMarray(mddObject, filePointer, inputFormat, mddDomain, inputFormatParams);
+ if (retval == 0)
+ {
+ collection->insert_element(mddObject);
+ ta.commit();
+ }
+ else
+ ta.abort();
+ db.close();
+ }
+ catch (r_Error& obj)
+ {
+ cout << "Exception (" << obj.get_errorno() << ") at administrative action: " << obj.what() << endl;
+ retval = EXCEPTIONADMIN;
+ ta.abort();
+ db.close();
+ }
+ }
+ }
+ }
+ else {
+ retval = MDDDOMAINNOTSPECIFIED;
+ }
+ }
+ else {
+ retval = FILENAMENOTSPECIFIED;
+ }
+ }
+ }
+ else {//create coll or insert existing mdd into existing coll
+ if (mddOIdDef)
+ {//insert existing mdd into existing coll
+ if (collOIdDef)
+ {//lookup mdd by oid, lookup coll by oid, insert mdd into coll
+ try {
+ openTransaction();
+ //get collection
+ try {
+ collection = db.lookup_object(collOId);
+ }
+ catch (r_Error& obj)
+ {
+ RMInit::logOut << "Error (" << obj.get_errorno() << ") accessing collection " << collOId << ": " << obj.what() << endl;
+ retval = COLLECTIONINACCESSIBLE;
+ }
+ if (retval == 0)
+ {
+ //lookup mddObject
+ try {
+ mddObject = db.lookup_object(mddOId);
+ }
+ catch (r_Error& obj)
+ {
+ RMInit::logOut << "Error (" << obj.get_errorno() << ") accessing mdd " << mddOId << ": " << obj.what() << endl;
+ retval = MDDINACCESSIBLE;
+ }
+ if (retval == 0)
+ {
+ collection->insert_element(mddObject);
+ ta.commit();
+ }
+ else {
+ ta.abort();
+ }
+ }
+ else {
+ ta.abort();
+ }
+ db.close();
+ }
+ catch (r_Error& obj)
+ {
+ cout << "Exception (" << obj.get_errorno() << ") at administrative action: " << obj.what() << endl;
+ retval = EXCEPTIONADMIN;
+ ta.abort();
+ db.close();
+ }
+ }
+ else {
+ if (collNameDef)
+ {//lookup mdd by oid, lookup coll by name
+ try {
+ openTransaction();
+ //get collection
+ try {
+ collection = db.lookup_object(collName);
+ }
+ catch (r_Error& obj)
+ {
+ RMInit::logOut << "Error (" << obj.get_errorno() << ") accessing collection " << collName << ": " << obj.what() << endl;
+ retval = COLLECTIONINACCESSIBLE;
+ }
+ if (retval == 0)
+ {
+ //lookup mddObject
+ try {
+ mddObject = db.lookup_object(mddOId);
+ }
+ catch (r_Error& obj)
+ {
+ RMInit::logOut << "Error (" << obj.get_errorno() << ") accessing mdd " << mddOId << ": " << obj.what() << endl;
+ retval = MDDINACCESSIBLE;
+ }
+ if (retval == 0)
+ {
+ collection->insert_element(mddObject);
+ ta.commit();
+ }
+ else {
+ ta.abort();
+ }
+ }
+ else {
+ ta.abort();
+ }
+ db.close();
+ }
+ catch (r_Error& obj)
+ {
+ cout << "Exception (" << obj.get_errorno() << ") at administrative action: " << obj.what() << endl;
+ retval = EXCEPTIONADMIN;
+ ta.abort();
+ db.close();
+ }
+ }
+ else {//no coll name, no coll oid, error
+ retval = NOCOLLNAMENOCOLLOID;
+ }
+ }
+ }
+ else {//do not create mdd, do not insert mdd into coll
+ if (setTypeDef)
+ {//create coll
+ //open stuff
+ try {
+ openTransaction();
+ try {
+ collection = new (&db, setTypeName) r_Set< r_Ref< r_GMarray > >;
+ if (collNameDef)
+ {//object.cc insert in db will throw r_error without name
+ db.set_object_name(*collection, collName);
+ }
+ ta.commit();
+ }
+ catch (r_Error& obj)
+ {
+ cout << "Exception (" << obj.get_errorno() << ") at creating collection: " << obj.what() << endl;
+ retval = EXCEPTIONCREATECOLL;
+ ta.abort();
+ }
+ //create mddObject
+ db.close();
+ }
+ catch (r_Error& obj)
+ {
+ cout << "Exception (" << obj.get_errorno() << ") at administrative action: " << obj.what() << endl;
+ retval = EXCEPTIONADMIN;
+ ta.abort();
+ db.close();
+ }
+ }
+ else {
+ retval = NOCOLLTYPE;
+ }
+ }
+ }
+ }
+ else {
+ //errors occured in check arguments
+ }
+ }
+ explainRetval(retval);
+ return retval;
+ }
+
+void
+SystemInsert::printUsage()
+ {
+ cout << "Insert program for extended systemtest" << endl << endl;
+ SystemBasic::printOptions();
+ cout << "Actions: Create and insert MDD object" << endl;
+ cout << " required information: MDD type" << endl;
+ cout << " Collection name or oid" << endl;
+ cout << " MDD domain" << endl;
+ cout << " File name with data" << endl;
+ cout << " Create MDD object (is not supported by rasdaman)" << endl;
+ cout << " required information: MDD type" << endl;
+ cout << " MDD domain" << endl;
+ cout << " File name with data" << endl;
+ cout << " Create Collection object" << endl;
+ cout << " required information: Collection type" << endl;
+ cout << " optional information: Collection name" << endl;
+ cout << " Insert existing MDD in existing Collection (is not supported by rasdaman)" << endl;
+ cout << " required information: MDD oid" << endl;
+ cout << " Collection name or oid" << endl;
+ cout << endl;
+ }
diff --git a/rasodmg/test/system_insert.hh b/rasodmg/test/system_insert.hh
new file mode 100644
index 0000000..97b5a17
--- /dev/null
+++ b/rasodmg/test/system_insert.hh
@@ -0,0 +1,43 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#ifndef _SYSTEMINSERT_HH_
+#define _SYSTEMINSERT_HH_
+
+#include "system_basic.hh"
+
+class SystemInsert : public SystemBasic
+ {
+ public:
+ static int doStuff(int argc, const char** argv);
+
+ static void printUsage();
+
+ static void createMDD();
+
+ static void createColl();
+
+ static void insertMDDIntoColl();
+ };
+
+#endif
diff --git a/rasodmg/test/system_query.cc b/rasodmg/test/system_query.cc
new file mode 100644
index 0000000..d04c658
--- /dev/null
+++ b/rasodmg/test/system_query.cc
@@ -0,0 +1,400 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: system_query.cc
+ *
+ * MODULE: rasodmg/test
+ *
+ * COMMENTS:
+ * None
+*/
+
+static const char rcsid[] = "@(#)rasodmg/test,SystemQuery: $Id: system_query.cc,v 1.11 2002/07/30 07:16:23 hoefner Exp $";
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#include "raslib/template_inst.hh"
+#endif
+
+#include <unistd.h>
+#include "system_query.hh"
+#include "raslib/complex.hh"
+#include "raslib/structure.hh"
+#include "raslib/primitive.hh"
+#include "raslib/primitivetype.hh"
+#include "rasodmg/oqlquery.hh"
+#include "rasodmg/storagelayout.hh"
+
+int
+main(int argc, char** argv)
+ {
+ SystemBasic::usageHeader = "system_compare version 0.9\n\t\tProgram for executing queries against RasDaMan\n";
+ SystemBasic::usageFooter = "Required information:\n\t\tQuery file\n";
+ int retval = 0;
+ try {
+ retval = SystemQuery::doStuff(argc, argv);
+ }
+ catch (r_Error& e)
+ {
+ cout << "Caught Exception at top level: " << e.get_errorno() << " " << e.what() << endl;
+ }
+ }
+
+int
+SystemQuery::doStuff(int argc, char** argv)
+ {
+ installSignalHandlers();
+ int retval = 0;
+ retval = parseParams(argc, argv);
+ if (retval == 0)
+ {
+ if (fileName)
+ {
+ r_Storage_Layout* stl = 0;
+ db.set_servername(serverName);
+ db.set_useridentification(userName, passwd);
+ try {
+ db.open(baseName);
+ FILE* filePointer = checkFile(fileName, retval);
+ if (retval != 0)
+ return retval;
+ size_t dataSize = 0;
+ char* data = getData(filePointer, dataSize, retval);
+ if(retval != 0)
+ return retval;
+ char* myQuery = new char[dataSize + 1];
+ memcpy(myQuery, data, dataSize);
+ delete data;
+ data = 0;
+ myQuery[dataSize - 1] = '\0';
+ RMInit::logOut << "Query " << myQuery << endl;
+ r_OQL_Query q1(myQuery);
+ RMInit::logOut << "OQL " << q1.get_query() << endl;
+ if (q1.is_update_query())
+ {
+ cout << "Starting Update Transaction" << endl;
+ ta.begin();
+ db.set_storage_format(storageFormat, storageFormatParams);
+ db.set_transfer_format(transferFormat, transferFormatParams);
+ if (retval == 0)
+ {
+ try {
+ RMDBGIF(20, RMDebug::module_tools, "WAITBEFOREQL", \
+ RMInit::dbgOut << "Waiting 100 sec before query\n" << std::endl; \
+ sleep(100); \
+ RMInit::dbgOut << "Continue now\n" << std::endl; );
+ r_oql_execute(q1);
+ RMDBGIF(20, RMDebug::module_tools, "WAITAFTERQL", \
+ RMInit::dbgOut << "Waiting 100 sec before query\n" << std::endl; \
+ sleep(100); \
+ RMInit::dbgOut << "Continue now\n" << std::endl; );
+ }
+ catch (r_Error& errorObj)
+ {
+ cout << "FAILED" << endl << errorObj.what() << endl;
+ ta.abort();
+ retval = EXCEPTIONEXECUTEQUERY;
+ }
+ }
+ if (retval == 0)
+ ta.commit();
+ }
+ else {
+ cout << "Starting Read Only Transaction ... "; cout.flush();
+ ta.begin(r_Transaction::read_only);
+ db.set_storage_format(storageFormat, storageFormatParams);
+ db.set_transfer_format(transferFormat, transferFormatParams);
+ cout << "OK" << endl;
+ r_Set< r_Ref_Any > result_set;
+ cout << "Executing query ... "; cout.flush();
+ try {
+ RMDBGIF(20, RMDebug::module_tools, "WAITBEFOREQL", \
+ RMInit::dbgOut << "Waiting 100 sec before query\n" << std::endl; \
+ sleep(100); \
+ RMInit::dbgOut << "Continue now\n" << std::endl; );
+ r_oql_execute(q1, result_set);
+ RMDBGIF(20, RMDebug::module_tools, "WAITAFTERQL", \
+ RMInit::dbgOut << "Waiting 100 sec before query\n" << std::endl; \
+ sleep(100); \
+ RMInit::dbgOut << "Continue now\n" << std::endl; );
+ }
+ catch(r_Error& errorObj)
+ {
+ cout << "FAILED" << endl << errorObj.what() << endl;
+ ta.abort();
+ retval = EXCEPTIONEXECUTEQUERY;
+ }
+ if (retval == 0)
+ {
+ cout << "OK" << endl;
+ cout << "Collection" << endl;
+ cout << " Oid...................: " << result_set.get_oid() << endl;
+ cout << " Type Structure........: " << (result_set.get_type_structure() ? result_set.get_type_structure() : "<nn>") << endl;
+ cout << " Type Schema...........: " << flush;
+ if (result_set.get_type_schema())
+ result_set.get_type_schema()->print_status(cout);
+ else
+ cout << "<nn>" << flush;
+ cout << endl;
+ cout << " Number of entries.....: " << result_set.cardinality() << endl;
+ cout << " Element Type Schema...: " << flush;
+ if (result_set.get_element_type_schema())
+ result_set.get_element_type_schema()->print_status(cout);
+ else
+ cout << "<nn>" << flush;
+ cout << endl;
+ if (testBed)
+ {
+ cout << "-- Testbed line: result_type=" << result_set.get_type_structure() << endl;
+ cout << "-- Testbed line: result_elements=" << result_set.cardinality() << endl;
+ cout << endl;
+ }
+
+ r_Iterator< r_Ref_Any > iter = result_set.create_iterator();
+ cout << endl;
+ if (testBed)
+ cout << "-- Testbed start block:" << endl;
+ for (int i=1 ; iter.not_done(); iter++, i++)
+ {
+ switch (result_set.get_element_type_schema()->type_id())
+ {
+ case r_Type::MARRAYTYPE:
+ {
+ const char *defExt=NULL;
+ r_Data_Format mafmt = r_Ref<r_GMarray>(*iter)->get_current_format();
+ r_Data_Format tmpfmt = r_Data_Format_NUMBER;
+ if(outputFormat)
+ tmpfmt = outputFormat;
+ else
+ tmpfmt = mafmt;
+ // special treatment only for DEFs
+ switch (tmpfmt)
+ {
+ case r_TOR:
+ defExt = "tor"; break;
+ case r_DEM:
+ defExt = "dem"; break;
+ case r_VFF:
+ defExt = "vff"; break;
+ case r_TIFF:
+ defExt = "tif"; break;
+ case r_JPEG:
+ defExt = "jpg"; break;
+ case r_HDF:
+ defExt = "hdf"; break;
+ case r_PNG:
+ defExt = "png"; break;
+ case r_BMP:
+ defExt = "bmp"; break;
+ default:
+ defExt = NULL;
+ }
+ if (outputFormat && (defExt == NULL))
+ defExt = "raw";
+ if (defExt == NULL)
+ {
+ if (printText)
+ {
+ int numCells = r_Ref<r_GMarray>(*iter)->get_array_size();
+ const char* theStuff = r_Ref<r_GMarray>(*iter)->get_array();
+ for (int cnt = 0; cnt < numCells; cnt++)
+ cout << theStuff[cnt];
+ }
+ else {
+ cout << "Image " << i << endl;
+ r_Ref<r_GMarray>(*iter)->print_status(cout, 0);
+ }
+ cout << endl;
+ }
+ else{
+
+ if(outputFormat && mafmt!=outputFormat)
+ {
+ r_Base_Type* conversionType=NULL;
+ r_Minterval* mddDomain=NULL;
+ if(mafmt!=r_Array)
+ {
+ data=r_Ref<r_GMarray>(*iter)->get_array();
+ dataSize=r_Ref<r_GMarray>(*iter)->get_array_size();
+ mddDomain=(r_Minterval*)&(r_Ref<r_GMarray>(*iter)->spatial_domain());
+ conversionType=(r_Base_Type*)r_Ref<r_GMarray>(*iter)->get_base_type_schema();
+ //convert this from currentformat(DEF) to r_Array
+ if (convertFrom(mafmt, data, dataSize, *mddDomain, conversionType, NULL) == 0)
+ {
+ r_Ref<r_GMarray>(*iter)->set_array_size(dataSize);
+ r_Ref<r_GMarray>(*iter)->set_type_length(conversionType->size());
+ r_Ref<r_GMarray>(*iter)->set_array(data);
+ r_Ref<r_GMarray>(*iter)->set_current_format(r_Array);
+ r_Ref<r_GMarray>(*iter)->set_spatial_domain(*mddDomain);
+ data = 0;
+ }
+ else
+ {
+ cout << "Error while converting to " << r_Array << " from " << mafmt << endl;
+ retval=CONVERSIONEXCEPTION;
+ }
+ }
+ //convert this from r_Array to outputFormat
+ data=r_Ref<r_GMarray>(*iter)->get_array();
+ dataSize=r_Ref<r_GMarray>(*iter)->get_array_size();
+ mddDomain=(r_Minterval*)&(r_Ref<r_GMarray>(*iter)->spatial_domain());
+ conversionType=(r_Base_Type*)r_Ref<r_GMarray>(*iter)->get_base_type_schema();
+ if (convertTo(outputFormat, data, dataSize, *mddDomain, conversionType, outputFormatParams) == 0)
+ {
+ r_Ref<r_GMarray>(*iter)->set_array_size(dataSize);
+ r_Ref<r_GMarray>(*iter)->set_type_length(conversionType->size());
+ r_Ref<r_GMarray>(*iter)->set_array(data);
+ r_Ref<r_GMarray>(*iter)->set_current_format(outputFormat);
+ r_Ref<r_GMarray>(*iter)->set_spatial_domain(*mddDomain);
+ data = 0;
+ }
+ else
+ {
+ cout << "Error while converting to " << outputFormat << " from " << r_Array << endl;
+ retval=CONVERSIONEXCEPTION;
+ }
+ }
+
+ char defFileName[256];
+ sprintf(defFileName, "%s%d.%s", outputFileName, i, defExt);
+ cout << "Marray " << i << " will write " << r_Ref<r_GMarray>(*iter)->get_array_size() << " bytes to " << defFileName << endl;
+
+ FILE *tfile = fopen(defFileName, "wb");
+ fwrite((void*)r_Ref<r_GMarray>(*iter)->get_array(), 1, r_Ref<r_GMarray>(*iter)->get_array_size(), tfile);
+ fclose(tfile);
+ }
+ }
+ break;
+
+ case r_Type::POINTTYPE:
+ cout << "Element " << i << ": " << *(r_Ref<r_Point>(*iter)) << endl;
+ break;
+
+ case r_Type::SINTERVALTYPE:
+ cout << "Element " << i << ": " << *(r_Ref<r_Sinterval>(*iter)) << endl;
+ break;
+
+ case r_Type::MINTERVALTYPE:
+ cout << "Element " << i << ": " << *(r_Ref<r_Minterval>(*iter)) << endl;
+ break;
+
+ case r_Type::OIDTYPE:
+ cout << "Element " << i << ": " << *(r_Ref<r_OId>(*iter)) << endl;
+ break;
+
+ default:
+ cout << "Element " << i << ": " << flush;
+ printScalar( *(r_Ref<r_Scalar>(*iter)) );
+ cout << endl;
+ }
+ }
+ }
+ if (testBed)
+ cout << "-- Testbed end block:" << endl;
+ if (retval == 0)
+ ta.commit();
+ else
+ ta.abort();
+ }
+ delete myQuery;
+ myQuery = 0;
+ db.close();
+ }
+ catch (r_Error& obj)
+ {
+ cout << "Exception (" << obj.get_errorno() << ") : " << obj.what() << endl;
+ ta.abort();
+ db.close();
+ retval = EXCEPTIONADMIN;
+ }
+ }
+ else {
+ retval = FILENAMENOTSPECIFIED;
+ }
+ }
+ explainRetval(retval);
+ return retval;
+ }
+
+void SystemQuery::printScalar( const r_Scalar& scalar )
+{
+ switch( scalar.get_type()->type_id() )
+ {
+ case r_Type::BOOL:
+ cout << ( ((r_Primitive*)&scalar)->get_boolean() ? "T" : "F" ) << flush;
+ break;
+
+ case r_Type::CHAR:
+ cout << (int)((r_Primitive*)&scalar)->get_char() << flush;
+ break;
+
+ case r_Type::OCTET:
+ cout << (int)((r_Primitive*)&scalar)->get_octet() << flush;
+ break;
+
+ case r_Type::SHORT:
+ cout << ((r_Primitive*)&scalar)->get_short() << flush;
+ break;
+
+ case r_Type::USHORT:
+ cout << ((r_Primitive*)&scalar)->get_ushort() << flush;
+ break;
+
+ case r_Type::LONG:
+ cout << ((r_Primitive*)&scalar)->get_long() << flush;
+ break;
+
+ case r_Type::ULONG:
+ cout << ((r_Primitive*)&scalar)->get_ulong() << flush;
+ break;
+
+ case r_Type::FLOAT:
+ cout << ((r_Primitive*)&scalar)->get_float() << flush;
+ break;
+
+ case r_Type::DOUBLE:
+ cout << ((r_Primitive*)&scalar)->get_double() << flush;
+ break;
+
+ case r_Type::COMPLEXTYPE1:
+ case r_Type::COMPLEXTYPE2:
+ cout << "(" << ((r_Complex*)&scalar)->get_re() << ", " << ((r_Complex*)&scalar)->get_im() << ")" << flush;
+ break;
+
+ case r_Type::STRUCTURETYPE:
+ {
+ r_Structure* structValue = (r_Structure*)&scalar;
+
+ cout << "{ " << flush;
+
+ for( int i=0; i<structValue->count_elements(); i++ )
+ {
+ printScalar( (*structValue)[i] );
+
+ if( i < structValue->count_elements()-1 ) cout << ", " << flush;
+ }
+ cout << " }" << endl;
+ }
+ break;
+ }
+}
diff --git a/rasodmg/test/system_query.hh b/rasodmg/test/system_query.hh
new file mode 100644
index 0000000..b5cafdb
--- /dev/null
+++ b/rasodmg/test/system_query.hh
@@ -0,0 +1,37 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#ifndef _SYSTEMQUERY_HH_
+#define _SYSTEMQUERY_HH_
+
+#include "system_basic.hh"
+
+class SystemQuery : public SystemBasic
+ {
+ public:
+ static int doStuff(int argc, char** argv);
+
+ static void printScalar(const r_Scalar& scalar);
+ };
+
+#endif
diff --git a/rasodmg/test/system_update.cc b/rasodmg/test/system_update.cc
new file mode 100644
index 0000000..daf6a06
--- /dev/null
+++ b/rasodmg/test/system_update.cc
@@ -0,0 +1,399 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: system_update.cc
+ *
+ * MODULE: rasodmg/test
+ *
+ * COMMENTS:
+ * None
+*/
+
+static const char rcsid[] = "@(#)rasodmg/test,SystemUpdate: $Id: system_update.cc,v 1.21 2003/12/27 23:02:58 rasdev Exp $";
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#include "raslib/template_inst.hh"
+#endif
+
+#include <unistd.h>
+#include <math.h>
+
+#include "system_update.hh"
+#include "raslib/rminit.hh"
+#include "raslib/rmdebug.hh"
+#include "raslib/primitivetype.hh"
+#include "raslib/marraytype.hh"
+#include "raslib/mitera.hh"
+#include "rasodmg/tiling.hh"
+#include "rasodmg/stattiling.hh"
+#include "rasodmg/storagelayout.hh"
+#include "rasodmg/oqlquery.hh"
+#include "clientcomm/clientcomm.hh"
+
+
+
+int main(int argc, char** argv)
+ {
+ SystemBasic::usageHeader = "system_update version 0.9.4\n\t\tProgram for writing data into RasDaMan\n";
+ SystemBasic::usageFooter = "Required information:\n\t\t MDD type\n\t\tCollection name\n\t\tMDD domain\n\t\tFile name with data\n";
+ int retval = 0;
+ try {
+ retval = SystemUpdate::doStuff(argc, argv);
+ }
+ catch (const r_Error& e)
+ {
+ cout << "Caught Exception at top level: " << e.get_errorno() << " " << e.what() << endl;
+ retval = -1;
+ }
+ catch (const std::exception& e2)
+ {
+ cout << "Caught Exception at top level: " << e2.what() << endl;
+ retval = -1;
+ }
+ catch (...)
+ {
+ cout << "Caught Unknown Exception at top level!" << endl;
+ retval = -1;
+ }
+ return retval;
+ }
+
+int
+SystemUpdate::doStuff(int argc, char** argv)
+ {
+#ifndef RMANDEBUG
+ installSignalHandlers();
+#endif
+ int retval = 0;
+ retval = parseParams(argc, argv);
+ if (retval == 0)
+ {
+ if (mddTypeName)
+ {
+ if (mddDomainDef)
+ {
+ if (fileName && (conversionTypeName == NULL))
+ {
+ retval = CONVERSIONTYPEMISSING;
+ }
+ else {
+ if (fileName || (!fileName && transparent))
+ {
+ if (collName)
+ {
+ r_MiterArea* iter = NULL;
+ r_Minterval tempDom;
+ r_Minterval tileDom;
+ if (tiledUpdate)
+ {
+ tempDom = overlayDomain;
+ //taken from tiling.cc r_Size_Tiling
+ r_Dimension dim = tempDom.dimension();
+ r_Range edgeLength = (r_Range)std::max((r_Range)floor(pow(updateBufferSize, 1/(double)dim)), 1);
+ if (align)
+ {
+ edgeLength = edgeLength - edgeLength%align;
+ if (edgeLength < align)
+ edgeLength = align;
+ }
+ tileDom = r_Minterval(dim);
+ for (r_Dimension dimcnt = 0; dimcnt < dim; dimcnt++)
+ tileDom << r_Sinterval(0, edgeLength - 1);
+ iter = new r_MiterArea(&tileDom, &tempDom);
+ RMInit::logOut << "Tiling domain " << tileDom << " complete domain " << tempDom << endl;
+ //nextArea()
+ //isDone()
+ }
+ do {
+ std::ostringstream selstream;
+ std::ostringstream updstream;
+ if (tiledUpdate)
+ {
+ mddDomain = iter->nextArea();
+ overlayDomain = mddDomain;
+ tiledUpdate = !iter->isDone();
+ RMInit::logOut << "Doing now " << mddDomain << " " << overlayDomain << " done " << tiledUpdate << endl;
+ }
+ if (mddOIdDef)
+ {
+ updstream << "UPDATE " << collName << " AS a SET a" << overlayDomain << " ASSIGN $1 WHERE oid(a)=" << mddOId;
+ }
+ else {
+ updstream << "UPDATE " << collName << " AS a SET a" << overlayDomain << " ASSIGN $1";
+ }
+ if (transparent || !fileName)
+ {
+ if (overlayDomainDef)
+ {
+ if (overlayDomain.covers(mddDomain))
+ {
+ selstream << "SELECT A" << overlayDomain << " FROM " << collName << " AS A";
+ }
+ else {
+ RMInit::logOut << "Overlay domain " << overlayDomain << " does not cover MDD domain " << mddDomain << endl;
+ retval = OVERLAYDOMAINDOESNOTMATCH;
+ }
+ }
+ else {
+ selstream << "SELECT A" << mddDomain << " FROM " << collName << " AS A";
+ }
+ }
+ if (retval == 0)
+ {
+ retval = doUpdate(updstream.str().c_str(), selstream.str().c_str());
+ }
+ }
+ while (tiledUpdate && (retval == 0));
+ delete iter;
+ iter = NULL;
+ }
+ else {
+ retval = NOCOLLNAMEDEFINED;
+ }
+ }
+ else {
+ retval = FILENAMENOTSPECIFIED;
+ }
+ }
+ }
+ else {
+ retval = MDDDOMAINNOTSPECIFIED;
+ }
+ }
+ else {
+ retval = NOMDDTYPEDEFINED;
+ }
+ }
+ explainRetval(retval);
+ return retval;
+ }
+
+//SystemUpdate::doUpdate(const char* queryString, const char* queryStringS, const char* mddTypeName, const r_Marray_Type mddType, const r_Minterval& mddDomain, const char* inputFormatParams, )
+int
+SystemUpdate::doUpdate(const char* queryString, const char* queryStringS)
+ {
+ int retval = 0;
+ char* typeStructure = NULL;
+ r_Ref<r_GMarray> selectedMDD;
+ r_Set< r_Ref_Any > result;
+ r_Marray_Type* mddType = NULL;
+ try {
+ openTransaction(false);
+ typeStructure = db.getComm()->getTypeStructure(mddTypeName, ClientComm::r_MDDType_Type);
+ ta.abort();
+ db.close();
+ }
+ catch (r_Error& err)
+ {
+ if (err.get_kind() == r_Error::r_Error_DatabaseClassUndefined)
+ {
+ RMInit::logOut << "Type is not a well known type" << endl;
+ typeStructure = new char[strlen(mddTypeName) + 1];
+ strcpy(typeStructure, mddTypeName);
+ }
+ else {
+ RMInit::logOut << "Error during type retrieval from database: " << err.get_errorno() << " " << err.what() << endl;
+ throw;
+ }
+ }
+ try {
+ r_Type* tempType = r_Type::get_any_type(typeStructure);
+ if (tempType->isMarrayType())
+ {
+ mddType = (r_Marray_Type*)tempType;
+ tempType = NULL;
+ }
+ else {
+ RMInit::logOut << "The type (" << typeStructure << ") is not an marray type." << endl;
+ delete tempType;
+ tempType = NULL;
+ retval = MDDTYPEINVALID;
+ }
+ }
+ catch (r_Error& err)
+ {
+ RMInit::logOut << "Error during type retrieval from type structure (" << typeStructure << "): " << err.get_errorno() << " " << err.what() << endl;
+ retval = MDDTYPEINVALID;
+ }
+ delete [] typeStructure;
+ typeStructure = NULL;
+ if (retval == 0)
+ {
+ size_t baseTypeLength = mddType->base_type().size();
+ r_Storage_Layout* stl = new r_Storage_Layout(theTiling->clone());
+ r_Ref<r_GMarray> fileMDD = new (mddTypeName)r_GMarray(mddDomain, baseTypeLength, stl);
+ fileMDD->set_type_schema(mddType);
+ stl = new r_Storage_Layout(theTiling->clone());
+ r_Ref<r_GMarray> targetMDD = new (mddTypeName)r_GMarray(overlayDomain, baseTypeLength, stl);
+ targetMDD->set_type_schema(mddType);
+ if (fileName)
+ {
+ FILE* filePointer = checkFile(fileName, retval);
+ if (retval != 0)
+ {
+ fileMDD.destroy();
+ targetMDD.destroy();
+ delete mddType;
+ mddType = NULL;
+ return retval;
+ }
+ retval = initGMarray(fileMDD, filePointer, inputFormat, mddDomain, inputFormatParams);
+ }
+ else {
+ RMInit::logOut << "Will not read from file" << endl;
+ }
+ if (retval == 0)
+ {
+ try {
+ openTransaction();
+ if (strlen(queryStringS))
+ {//do transparent update
+ r_OQL_Query query(queryStringS);
+ RMDBGIF(20, RMDebug::module_tools, "WAITBEFOREQL", \
+ RMInit::dbgOut << "Waiting 100 sec before execute\n" << std::endl; \
+ sleep(100); \
+ RMInit::dbgOut << "Continue now\n" << std::endl; );
+ bool dataFound = true;
+ try {
+ r_oql_execute(query, result);
+ }
+ catch (r_Error& err)
+ {
+ dataFound = false;
+ if (err.get_kind() != r_Error::r_Error_TransferFailed)
+ {
+ throw;
+ }
+ }
+ RMDBGIF(20, RMDebug::module_tools, "WAITAFTERQL", \
+ RMInit::dbgOut << "Waiting 100 sec after execute\n" << std::endl; \
+ sleep(100); \
+ RMInit::dbgOut << "Continue now\n" << std::endl; );
+ if (dataFound)
+ {
+ r_Iterator< r_Ref_Any > iter = result.create_iterator();
+ selectedMDD = r_Ref<r_GMarray>(*iter);
+ if (polygonDefined)
+ {
+ polygon.setMArray(*selectedMDD);
+ if (insidePatternSelDef)
+ polygon.fillMArrayInside(insidePatternSel);
+ if (outsidePatternSelDef)
+ polygon.fillMArrayOutside(outsidePatternSel);
+ }
+ if (fileName)
+ {
+ retval = overlayGMarrays(targetMDD, fileMDD, selectedMDD);
+ }
+ else {//just copy selected over target
+ retval = overlayGMarrays(targetMDD, selectedMDD, targetMDD);
+ }
+ }
+ else {
+ retval = overlayGMarrays(targetMDD, fileMDD, targetMDD);
+ }
+ }
+ else {
+ retval = overlayGMarrays(targetMDD, fileMDD, targetMDD);
+ }
+ if (retval == 0)
+ {
+ if (scaleLevels == NULL)
+ {
+ r_OQL_Query query(queryString);
+ query << *targetMDD;
+ RMDBGIF(20, RMDebug::module_tools, "WAITBEFOREQL", \
+ RMInit::dbgOut << "Waiting 100 sec before execute\n" << std::endl; \
+ sleep(100); \
+ RMInit::dbgOut << "Continue now\n" << std::endl; );
+ r_oql_execute(query);
+ RMDBGIF(20, RMDebug::module_tools, "WAITAFTERQL", \
+ RMInit::dbgOut << "Waiting 100 sec after execute\n" << std::endl; \
+ sleep(100); \
+ RMInit::dbgOut << "Continue now\n" << std::endl; );
+ }
+ else {
+ std::list<std::pair<double, char*> >::iterator iter = scaleLevels->begin();
+ std::list<std::pair<double, char*> >::iterator end = scaleLevels->end();
+ r_Minterval scaledDomain;
+ r_Minterval clipDomain;
+ unsigned int length = 0;
+ r_Dimension maxDim = mddDomain.dimension();
+ r_Point origin(maxDim);
+ double factor = 0;
+ for (r_Dimension i = 0; i < maxDim; i++)
+ origin[i] = 0;
+ while ((iter != end) && (retval == 0))
+ {
+ factor = iter->first;
+ if (factor == 1)
+ {
+ r_OQL_Query query(queryString);
+ query << *targetMDD;
+ RMDBGIF(20, RMDebug::module_tools, "WAITBEFOREQL", \
+ RMInit::dbgOut << "Waiting 100 sec before execute\n" << std::endl; \
+ sleep(100); \
+ RMInit::dbgOut << "Continue now\n" << std::endl; );
+ r_oql_execute(query);
+ RMDBGIF(20, RMDebug::module_tools, "WAITAFTERQL", \
+ RMInit::dbgOut << "Waiting 100 sec after execute\n" << std::endl; \
+ sleep(100); \
+ RMInit::dbgOut << "Continue now\n" << std::endl; );
+ }
+ else {
+ retval = scaleDomain(overlayDomain, origin, factor, scaledDomain, clipDomain, length);
+ RMInit::logOut << "scaled: " << iter->second << " scaled domain " << scaledDomain << " clip domain " << clipDomain << " result=" << retval << endl;
+ if (retval == 0)
+ retval = updateScaledMDD(targetMDD, clipDomain, scaledDomain, length, iter->second);
+ }
+ iter++;
+ }
+ }
+ RMDBGIF(20, RMDebug::module_tools, "WAITCOMMIT", \
+ RMInit::dbgOut << "Waiting 100 sec before commit\n" << std::endl; \
+ sleep(100); \
+ RMInit::dbgOut << "Continue now\n" << std::endl; );
+ }
+ if (retval == 0)
+ ta.commit();
+ else
+ ta.abort();
+ }
+ catch (r_Error& err)
+ {
+ RMInit::logOut << "Error during administrative action: " << err.get_errorno() << " " << err.what() << endl;
+ retval = EXCEPTIONADMIN;
+ ta.abort();
+ }
+ if (db.get_status() != r_Database::not_open)
+ db.close();
+ }
+ fileMDD.destroy();
+ targetMDD.destroy();
+ }
+ delete mddType;
+ mddType = NULL;
+ return retval;
+ }
+
diff --git a/rasodmg/test/system_update.hh b/rasodmg/test/system_update.hh
new file mode 100644
index 0000000..74d1fc6
--- /dev/null
+++ b/rasodmg/test/system_update.hh
@@ -0,0 +1,40 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#ifndef _SYSTEMUPDATE_HH_
+#define _SYSTEMUPDATE_HH_
+
+#include "system_basic.hh"
+
+class SystemUpdate : public SystemBasic
+ {
+ public:
+ static int doStuff(int argc, char** argv);
+
+ static void printUsage();
+
+ static int doUpdate(const char* Query, const char* TransparentSelectQuery);
+
+ };
+
+#endif
diff --git a/rasodmg/test/test_alignedtiling.cc b/rasodmg/test/test_alignedtiling.cc
new file mode 100644
index 0000000..636a3c1
--- /dev/null
+++ b/rasodmg/test/test_alignedtiling.cc
@@ -0,0 +1,126 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_alignedtiling.cc
+ *
+ * MODULE: rasodmg
+ *
+ * COMMENTS:
+ * None
+*/
+
+#include <iostream>
+#include <string.h>
+
+#ifdef __VISUALC__
+ #define __EXECUTABLE__
+#endif
+// #include "clientcomm/clientcomm.hh"
+#include "rasodmg/ref.hh"
+#include "rasodmg/transaction.hh"
+#include "rasodmg/database.hh"
+#include "rasodmg/set.hh"
+#include "rasodmg/marray.hh"
+#include "rasodmg/odmgtypes.hh"
+#include "raslib/minterval.hh"
+#include "rasodmg/alignedtiling.hh"
+#ifdef __VISUALC__
+ #undef __EXECUTABLE__
+#endif
+
+
+int checkArguments( int argc, char** argv, const char* searchText, int& optionValueIndex )
+{
+ int found = 0;
+ int i=1;
+
+ while( !found && i<argc )
+ found = !strcmp( searchText, argv[i++] );
+
+ if( found && i<argc && !strchr(argv[i],'-') )
+ optionValueIndex = i;
+ else
+ optionValueIndex = 0;
+
+ return found;
+}
+
+
+int main( int argc, char** argv )
+{
+
+ int optionValueIndex;
+ if( argc < 5 || checkArguments( argc, argv, "-h", optionValueIndex ) )
+ {
+ cout << "Usage: test_alignedtiling tile_config tile_size cell_size domain" << endl << endl;
+ cout << "Options: -h ... this help" << endl;
+ cout << endl;
+ return 0;
+ }
+
+ r_Minterval* tile_config = 0;
+ r_Minterval* domain = 0;
+
+ try {
+ tile_config = new r_Minterval( argv[1] );
+ domain = new r_Minterval( argv[4] );
+ }
+ catch (...)
+ {
+ return -1;
+ }
+
+ unsigned cell_size = strtoul( argv[3], (char **)NULL, 10 );
+ unsigned long tile_size = strtoul( argv[2], (char **)NULL, 10 );
+
+ cout << "Tile Config " << *tile_config << endl;
+ r_Aligned_Tiling storeOptions( *tile_config, tile_size );
+
+ cout << endl;
+
+ cout << "Tiling Options : ts - " << storeOptions.get_tile_size( )
+ << ", tc - " << storeOptions.get_tile_config( ) << endl;
+
+ cout << "Object domain : " << *domain << ", cell size " << cell_size << endl;
+
+
+ r_Aligned_Tiling newSL(storeOptions);
+
+ cout << "Testing copy constructor. Newly constructed object..." << endl;
+ cout << "Tiling Options : ts - " << storeOptions.get_tile_size( )
+ << ", tc - " << storeOptions.get_tile_config( ) << endl;
+
+ cout << "Object domain : " << *domain << ", cell size " << cell_size << endl;
+
+ r_Minterval result_tile =
+ storeOptions.compute_tile_domain(cell_size, *domain);
+
+ cout << "Tiling Options resulting tile :" << result_tile << endl;
+
+
+ delete domain;
+ delete tile_config;
+
+ return 0;
+}
+
diff --git a/rasodmg/test/test_all.sh b/rasodmg/test/test_all.sh
new file mode 100644
index 0000000..dfff5fd
--- /dev/null
+++ b/rasodmg/test/test_all.sh
@@ -0,0 +1,9 @@
+#!/usr/bin/ksh
+
+runbm.sh -e 20 tmov_16.ql tmov_32.ql tmov_64.ql
+runbm.sh -n 10 tsel_sliced.ql tsel_16.ql tsel_32.ql tsel_64.ql
+runbm.sh -e 20 troll_sliced.ql troll_16.ql troll_32.ql troll_64.ql
+runbm.sh -e 20 cmov_16.ql cmov_32.ql cmov_64.ql
+runbm.sh -n 10 csel_sliced.ql csel_16.ql csel_32.ql csel_64.ql
+runbm.sh -e 20 croll_sliced.ql croll_16.ql croll_32.ql croll_64.ql
+runbm.sh -n 5 earth_16.ql earth_32.ql earth_64.ql small_16.ql small_32.ql small_64.ql
diff --git a/rasodmg/test/test_benchmark.cc b/rasodmg/test/test_benchmark.cc
new file mode 100644
index 0000000..2997d68
--- /dev/null
+++ b/rasodmg/test/test_benchmark.cc
@@ -0,0 +1,273 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_benchmark.cc
+ *
+ * MODULE: rasodmg
+ *
+ * COMMENTS:
+ * None
+*/
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#include "raslib/template_inst.hh"
+#endif
+
+#ifdef __VISUALC__
+#include <strstrea.h>
+#else
+#include <strstream.h>
+#endif
+
+#include <iostream>
+#include <fstream.h>
+#include <string.h>
+
+#include "rasodmg/transaction.hh"
+#include "rasodmg/database.hh"
+#include "rasodmg/ref.hh"
+#include "rasodmg/set.hh"
+#include "rasodmg/marray.hh"
+#include "rasodmg/iterator.hh"
+#include "rasodmg/oqlquery.hh"
+
+#include "raslib/type.hh"
+#include "raslib/shhopt.h"
+#include "raslib/rmdebug.hh"
+
+#include <sys/time.h>
+
+static int numExec = 1; // number of repetitions for each query
+static int readEach = 0; // number of repeated queries in query file
+static int qNum = 0; // counter for current query
+
+RMTimer execTimer("test_benchmark", "r_oql_execute()");
+RMTimer wholeTimer("test_benchmark", "execQuery()");
+
+int checkArguments( int argc, char** argv, const char* searchText,
+ int& optionValueIndex )
+{
+ int found = 0;
+ int i=1;
+
+ while( !found && i<argc )
+ found = !strcmp( searchText, argv[i++] );
+
+ if( found && i<argc && !strchr(argv[i],'-') )
+ optionValueIndex = i;
+ else
+ optionValueIndex = 0;
+
+ return found;
+}
+
+void execQuery( char* serverName, char* baseName, char* queryBuffer )
+{
+}
+
+static void
+printUsage(void)
+{
+ cout << "Usage: test_benchmark [options] server_name base_name file_name"
+ << endl;
+ cout << " -h, --help Print this message and exit." << endl;
+ cout << " -n, --nrepeat Followed by number of repeated" << endl
+ << " executions for each query in file_name."
+ << endl;
+ cout << " -e, --readeach Followed by number of queries read from"
+ << endl
+ << " the query file treated as variations of"
+ << endl
+ << " the same query." << endl;
+ exit(0);
+}
+
+void execQuery(char* serverName, char* baseName, char* comment, char* query)
+{
+ int i;
+ r_Database db;
+ r_Transaction ta;
+
+ RMInit::bmOut << comment;
+ RMInit::bmOut << "Query " << (qNum/numExec)+1 << "." << (qNum%numExec)+1
+ << ": " << query;
+ qNum++;
+
+ wholeTimer.start();
+
+ r_Set< r_Ref_Any > image_set;
+ db.set_servername( serverName );
+
+ try
+ {
+ r_OQL_Query q1( query );
+
+ db.open( baseName );
+
+ if( q1.is_update_query() )
+ ta.begin();
+ else
+ ta.begin( r_Transaction::read_only );
+
+ // here the query is executed and times are taken
+
+ try
+ {
+ execTimer.start();
+ if( q1.is_update_query() )
+ r_oql_execute( q1 );
+ else
+ r_oql_execute( q1, image_set );
+ execTimer.stop();
+ }
+
+ catch( r_Error& errorObj )
+ {
+ execTimer.stop();
+ cerr << endl << "QUERY FAILED" << endl << errorObj.what() << endl;
+ ta.commit();
+ db.close();
+ }
+
+ ta.commit();
+ db.close();
+
+ wholeTimer.stop();
+ }
+ catch( r_Error& errorObj )
+ {
+ wholeTimer.stop();
+ cerr << endl << "FAILED" << endl << errorObj.what() << endl;
+ }
+}
+
+void execQueries(char* serverName, char* baseName, char* comment, char* query)
+{
+ if(!readEach) {
+ for(int i = 0; i < numExec; i++)
+ execQuery(serverName, baseName, comment, query);
+ }
+ else {
+ execQuery(serverName, baseName, comment, query);
+ }
+}
+
+void parseFile(ifstream& fileStream, char* serverName, char* baseName)
+{
+ enum legalStates { FIRSTCOMMENT, COMMENT, QUERY };
+ legalStates parseState = FIRSTCOMMENT;
+ ostrstream commentStream;
+ ostrstream queryStream;
+ char buf[256];
+ char dummy;
+
+ while( fileStream.get( buf, 255, '\n' ) ) {
+ // read end of line
+ fileStream.get(dummy);
+ // checking for empty line
+ if(buf[0] == 0) {
+ if(parseState == FIRSTCOMMENT) {
+ // end of first comment, print it and switch to normal comment
+ commentStream << ends;
+ RMInit::bmOut << commentStream.str() << endl;
+ commentStream.rdbuf()->freeze(0);
+ commentStream.seekp(0, ios::beg);
+ parseState = COMMENT;
+ }
+ }
+ // checking for comment
+ else if(buf[0] == '/' && buf[1] == '/') {
+ if(parseState == QUERY) {
+ // execute the query, reset buffers
+ queryStream << endl << ends;
+ commentStream << ends;
+ execQueries(serverName, baseName, commentStream.str(),
+ queryStream.str());
+ queryStream.rdbuf()->freeze(0);
+ queryStream.seekp(0, ios::beg);
+ commentStream.rdbuf()->freeze(0);
+ commentStream.seekp(0, ios::beg);
+ parseState = COMMENT;
+ }
+ commentStream << buf << endl;
+ }
+ // must be a query
+ else {
+ parseState = QUERY;
+ queryStream << buf;
+ queryStream << " ";
+ }
+ }
+ // last query
+ if(parseState == QUERY) {
+ // execute the query, reset buffers
+ queryStream << endl << ends;
+ commentStream << ends;
+ execQueries(serverName, baseName, commentStream.str(),
+ queryStream.str());
+ queryStream.rdbuf()->freeze(0);
+ queryStream.seekp(0, ios::beg);
+ commentStream.rdbuf()->freeze(0);
+ commentStream.seekp(0, ios::beg);
+ }
+}
+
+int main( int argc, char** argv )
+{
+ int optionValueIndex;
+ char serverName[255];
+ char baseName[255];
+ char fileName[255];
+
+ optStruct testBenchmarkOpt[] = {
+ /* short long type var/func special */
+ { 'h', "help", OPT_FLAG, printUsage, OPT_CALLFUNC },
+ { 'n', "nrepeat", OPT_INT, &numExec, 0 },
+ { 'e', "readeach", OPT_INT, &readEach, 0 },
+ { 0, 0, OPT_END, 0, 0 } /* no more options */
+ };
+
+ /* parse all options */
+ optParseOptions(&argc, argv, testBenchmarkOpt, 0);
+
+ if( argc < 4 )
+ printUsage();
+
+ if(readEach)
+ numExec = readEach;
+
+ strcpy( serverName, argv[argc-3] );
+ strcpy( baseName, argv[argc-2] );
+ strcpy( fileName, argv[argc-1] );
+
+ ifstream fileStream( fileName );
+ if( !fileStream )
+ {
+ cout << "Error: File not found." << endl;
+ return -1;
+ }
+
+ parseFile(fileStream, serverName, baseName);
+ return 0;
+}
diff --git a/rasodmg/test/test_bmark_dir.cc b/rasodmg/test/test_bmark_dir.cc
new file mode 100644
index 0000000..04535c8
--- /dev/null
+++ b/rasodmg/test/test_bmark_dir.cc
@@ -0,0 +1,257 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_bmark_dir.cc
+ *
+ * MODULE: rasodmg
+ *
+ * PURPOSE: benchmark dirtiling
+ *
+ * COMMENTS:
+ * This program creates a 3D datacube for benchmarking
+ * the directional tiling method
+ *
+*/
+
+#include <iostream>
+#include <stdio.h>
+#include <stdlib.h>
+#include "rasodmg/ref.hh"
+#include "rasodmg/transaction.hh"
+#include "rasodmg/database.hh"
+#include "rasodmg/set.hh"
+#include "rasodmg/marray.hh"
+#include "rasodmg/odmgtypes.hh"
+#include "rasodmg/storagelayout.hh"
+#include "rasodmg/tiling.hh"
+#include "rasodmg/dirtiling.hh"
+#include "rasodmg/dirdecompose.hh"
+#include "rasodmg/storagelayout.hh"
+#include "raslib/oid.hh"
+
+#define TOTAL_DAYS (365L * 2L)
+#define TOTAL_PRODUCTS (60L)
+#define TOTAL_STORES (100L)
+
+#define MAX_SALES 500
+
+#define S_32K (32 * 1024L)
+#define S_64K (64 * 1024L)
+#define S_128K (128 * 1024L)
+#define S_256K (256 * 1024L)
+
+#define TOTAL_CUBES 9
+
+
+char* server_name;
+char* dbase_name;
+char* colect_name;
+
+void parse(int argc, char* argv[])
+{
+ if (argc != 4)
+ {
+ cout << "Usage: " << argv[0] << " [server name] [db name] [colection name]"
+ << endl;
+
+ exit(0);
+ }
+
+ server_name = argv[1];
+ dbase_name = argv[2];
+ colect_name = argv[3];
+}
+
+r_ULong init(const r_Point&)
+{
+ return (long)(rand() % MAX_SALES);
+}
+
+void insert_datacube()
+{
+
+ r_Ref< r_Set< r_Ref< r_Marray<r_ULong> > > > cube_set;
+ // r_Ref< r_Marray<r_ULong> > cube[TOTAL_CUBES];
+ r_Minterval domain, block_config;
+ r_Domain_Storage_Layout* dsl[TOTAL_CUBES];
+ r_OId oid[TOTAL_CUBES];
+
+ domain = r_Minterval(3);
+ domain << r_Sinterval(1L, TOTAL_DAYS)
+ << r_Sinterval(1L, TOTAL_PRODUCTS)
+ << r_Sinterval(1L, TOTAL_STORES);
+
+
+ // For alligned tiling (Regular tiling)
+
+ block_config = r_Minterval(3);
+ block_config << r_Sinterval(0L, TOTAL_DAYS)
+ << r_Sinterval(0L, TOTAL_PRODUCTS)
+ << r_Sinterval(0L, TOTAL_STORES);
+
+ r_Aligned_Tiling* til_reg_32k = new r_Aligned_Tiling(block_config, S_32K);
+ r_Aligned_Tiling* til_reg_64k = new r_Aligned_Tiling(block_config, S_64K);
+ r_Aligned_Tiling* til_reg_128k = new r_Aligned_Tiling(block_config, S_128K);
+ r_Aligned_Tiling* til_reg_256k = new r_Aligned_Tiling(block_config, S_256K);
+
+
+ // For directional tiling
+
+ r_Dir_Decompose decomp[3];
+ decomp[0] << 1 << 365 << 730;
+ decomp[1] << 1 << 27 << 42 << 60;
+ decomp[2] << 1 << 27 << 35 << 41 << 59 << 73 << 89 << 97 << 100;
+
+ r_Dir_Tiling* til_dir_32k = new r_Dir_Tiling(3, decomp, S_32K);
+ r_Dir_Tiling* til_dir_64k = new r_Dir_Tiling(3, decomp, S_64K);
+ r_Dir_Tiling* til_dir_128k = new r_Dir_Tiling(3, decomp, S_128K);
+ r_Dir_Tiling* til_dir_256k = new r_Dir_Tiling(3, decomp, S_256K);
+ r_Dir_Tiling* til_dir_Unlk = new r_Dir_Tiling(3, decomp, S_256K, r_Dir_Tiling::WITHOUT_SUBTILING);
+
+
+ // Domain storage layouts
+
+ dsl[0] = new r_Domain_Storage_Layout(domain, til_reg_32k);
+ dsl[1] = new r_Domain_Storage_Layout(domain, til_reg_64k);
+ dsl[2] = new r_Domain_Storage_Layout(domain, til_reg_128k);
+ dsl[3] = new r_Domain_Storage_Layout(domain, til_reg_256k);
+
+ dsl[4] = new r_Domain_Storage_Layout(domain, til_dir_32k);
+ dsl[5] = new r_Domain_Storage_Layout(domain, til_dir_64k);
+ dsl[6] = new r_Domain_Storage_Layout(domain, til_dir_128k);
+ dsl[7] = new r_Domain_Storage_Layout(domain, til_dir_256k);
+ dsl[8] = new r_Domain_Storage_Layout(domain, til_dir_Unlk);
+
+
+for (int i=0; i< TOTAL_CUBES ; i++)
+{
+ r_Database db;
+ r_Transaction trans;
+ // The main phase of the database creation
+ r_Ref< r_Marray<r_ULong> > cube1;
+
+ db.set_servername(server_name);
+
+ try
+ {
+ cout << "Opening database " << dbase_name << " on " << server_name
+ << "... " << flush;
+
+ db.open(dbase_name);
+
+ cout << "Ok" << endl;
+ cout << "Starting transaction... " << flush;
+
+ trans.begin();
+
+
+ cout << "Ok" << endl;
+ cout << "Opening the set... " << flush;
+
+ try
+ {
+ cube_set = db.lookup_object(colect_name);
+ }
+ catch (...)
+ {
+ cout << "*Failed*" << endl;
+ cout << "Creating the set... " << flush;
+
+ cube_set = new(&db, "ULong_3D_Set") r_Set< r_Ref< r_Marray<r_ULong> > >;
+ db.set_object_name(*cube_set, colect_name);
+ }
+
+ cout << "Ok" << endl;
+ cout << "Creating the datacube... " << flush;
+
+ // for (int i=0; i<TOTAL_CUBES; i++)
+ // {
+ // cube[i] =
+ cube1 =
+ new(&db, "ULong_3D_Cube") r_Marray<r_ULong>(domain, 1L /* &init */, dsl[i]);
+
+ // cube_set->insert_element(cube[i]);
+ // oid[i] = cube[i].get_oid();
+ cube_set->insert_element(cube1);
+ oid[i] = cube1->get_oid();
+
+ cout << "*" << flush;
+
+
+ cout << " ... Ok" << endl;
+
+ cout << " Cube[" << i << "]: " << oid[i] << endl;
+
+ cout << "Commiting transaction... " << flush;
+
+ trans.commit();
+
+ cout << "Ok" << endl;
+
+ cout << "Closing database... " << flush;
+
+ db.close();
+
+ }
+ catch (r_Error& e)
+ {
+ cout << e.what() << endl;
+ exit(0);
+ }
+ catch (...)
+ {
+ cout << "Undefined error..." << endl;
+ exit(0);
+ }
+}
+
+ cout << "Ok [******************]" << endl << flush;
+
+// Wrong - management of memory for storage layouts passes
+// to the marray, after being given to it.
+// for (int j=0; j<TOTAL_CUBES; j++)
+// delete dsl[j];
+
+ cout << endl;
+ cout << "Inserted data resume" << endl;
+ cout << "====================" << endl;
+
+ // for (int k=0; k<TOTAL_CUBES; k++)
+ // cout << " Cube[" << k << "]: " << oid[k] << endl;
+}
+
+int main(int argc, char* argv[])
+{
+ parse(argc, argv);
+ insert_datacube();
+
+ return 0;
+}
+
+
+
+
+
+
+
+
diff --git a/rasodmg/test/test_bmark_dir1.cc b/rasodmg/test/test_bmark_dir1.cc
new file mode 100644
index 0000000..c185858
--- /dev/null
+++ b/rasodmg/test/test_bmark_dir1.cc
@@ -0,0 +1,318 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_bmark_dir1.cc
+ *
+ * MODULE: rasodmg
+ *
+ * PURPOSE: benchmark dirtiling
+ *
+ * COMMENTS:
+ * This program creates 3D and 5D datacubes for benchmarking
+ * the directional tiling method
+ *
+*/
+
+#include <iostream>
+#include <stdio.h>
+#include <stdlib.h>
+#include "rasodmg/ref.hh"
+#include "rasodmg/transaction.hh"
+#include "rasodmg/database.hh"
+#include "rasodmg/set.hh"
+#include "rasodmg/marray.hh"
+#include "raslib/odmgtypes.hh"
+#include "rasodmg/tiling.hh"
+#include "rasodmg/dirtiling.hh"
+#include "rasodmg/dirdecompose.hh"
+#include "rasodmg/storagelayout.hh"
+#include "raslib/oid.hh"
+
+#define YEARS (2L)
+
+#define TOTAL_DAYS (365L * 2L)
+#define TOTAL_PRODUCTS (60L)
+#define TOTAL_STORES (100L)
+
+
+#define MAX_SALES 500
+
+#define S_32K (32 * 1024L)
+#define S_64K (64 * 1024L)
+#define S_128K (128 * 1024L)
+#define S_256K (256 * 1024L)
+
+#define TOTAL_CUBES 10
+
+
+char* server_name;
+char* dbase_name;
+char* colect_name;
+
+void parse(int argc, char* argv[])
+{
+ if (argc != 4)
+ {
+ cout << "Usage: " << argv[0] << " [server name] [db name] [colection name]"
+ << endl;
+
+ exit(0);
+ }
+
+ server_name = argv[1];
+ dbase_name = argv[2];
+ colect_name = argv[3];
+}
+
+r_ULong init(const r_Point& pnt )
+{
+ return (long)(rand() % MAX_SALES);
+}
+
+void insert_datacube()
+{
+
+ r_Ref< r_Set< r_Ref< r_Marray<r_ULong> > > > cube_set;
+ // r_Ref< r_Marray<r_ULong> > cube[TOTAL_CUBES];
+ r_Minterval domain, block_config;
+ r_Domain_Storage_Layout* dsl[TOTAL_CUBES];
+ r_OId oid[TOTAL_CUBES];
+
+ domain = r_Minterval(3);
+ domain << r_Sinterval(1L, TOTAL_DAYS)
+ << r_Sinterval(1L, TOTAL_PRODUCTS)
+ << r_Sinterval(1L, TOTAL_STORES);
+
+
+ block_config = r_Minterval(3);
+ block_config << r_Sinterval(0L, TOTAL_DAYS)
+ << r_Sinterval(0L, TOTAL_PRODUCTS)
+ << r_Sinterval(0L, TOTAL_STORES);
+
+ // Each storage object must have an own dynamic tiling obj or else the client
+ // ( and server ) crashes because memory is released for a non heap memory free
+ // r_Marray become responsible for managing the memory allocated for the
+ // tiling object.
+ r_Aligned_Tiling* til_reg_32k = new r_Aligned_Tiling(block_config, S_32K);
+ r_Aligned_Tiling* til_reg_64k = new r_Aligned_Tiling(block_config, S_64K);
+ r_Aligned_Tiling* til_reg_128k = new r_Aligned_Tiling(block_config, S_128K);
+ r_Aligned_Tiling* til_reg_256k = new r_Aligned_Tiling(block_config, S_256K);
+
+
+ // For directional tiling
+
+ r_Dir_Decompose decomp[3];
+
+ // Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dez
+ unsigned int daysMonth[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+ int ix = 0;
+ int year;
+ int month;
+ decomp[0] << 1;
+ for ( year = 0; year < YEARS ; year++)
+ {
+ for (month = 0; month < 12; month++ )
+ {
+ decomp[0] << ix + daysMonth[month];
+ ix += daysMonth[month];
+ }
+ }
+
+ decomp[1] << 1 << 60;
+
+ // << 1 << 1 + 26 << 27 + 8 << 35 + 6 << 41 + 18 << 59 + 14 << 73 + 16 << 89 + 8 << 97 + 3;
+ decomp[2] << 1 << 27 << 35 << 41 << 59 << 73 << 89 << 97 << 100;
+
+
+ r_Dir_Tiling* til_dir_32k = new r_Dir_Tiling(3, decomp, S_32K);
+ r_Dir_Tiling* til_dir_64k = new r_Dir_Tiling(3, decomp, S_64K);
+ r_Dir_Tiling* til_dir_128k = new r_Dir_Tiling(3, decomp, S_128K);
+ r_Dir_Tiling* til_dir_256k = new r_Dir_Tiling(3, decomp, S_256K);
+
+
+ r_Dir_Decompose decomp1[3];
+
+ ix = 0;
+ decomp1[0] << 1;
+ for ( year = 0; year < YEARS ; year++)
+ {
+ for (month = 0; month < 12; month++ )
+ {
+ decomp1[0] << ix + daysMonth[month];
+ ix += daysMonth[month];
+ }
+ }
+
+ // Products
+ // << 1<< 1+ 26 << 27 + 15 << 42 + 28
+ decomp1[1] << 1 << 27 << 42 << 60;
+
+ // Stores
+ // << 1 << 1 + 26 << 27 + 8 << 35 + 6 << 41 + 18 << 59 + 14 << 73 + 16 << 89 + 8 << 97 + 3;
+ decomp1[2] << 1 << 27 << 35 << 41 << 59 << 73 << 89 << 97 << 100;
+
+ r_Dir_Tiling* til_dir1_32k = new r_Dir_Tiling(3, decomp1, S_32K);
+ r_Dir_Tiling* til_dir1_64k = new r_Dir_Tiling(3, decomp1, S_64K);
+
+ // Domain storage layouts
+
+ dsl[0] = new r_Domain_Storage_Layout(domain, til_reg_32k);
+ dsl[1] = new r_Domain_Storage_Layout(domain, til_reg_64k);
+ dsl[2] = new r_Domain_Storage_Layout(domain, til_reg_128k);
+ dsl[3] = new r_Domain_Storage_Layout(domain, til_reg_256k);
+
+ dsl[4] = new r_Domain_Storage_Layout(domain, til_dir_32k);
+ dsl[5] = new r_Domain_Storage_Layout(domain, til_dir_64k);
+ dsl[6] = new r_Domain_Storage_Layout(domain, til_dir_128k);
+ dsl[7] = new r_Domain_Storage_Layout(domain, til_dir_256k);
+
+ dsl[8] = new r_Domain_Storage_Layout(domain, til_dir1_32k);
+ dsl[9] = new r_Domain_Storage_Layout(domain, til_dir1_64k);
+
+
+for (int i= 0 ; i< TOTAL_CUBES ; i++)
+{
+ r_Database db;
+ r_Transaction trans;
+ // The main phase of the database creation
+ r_Ref< r_Marray<r_ULong> > cube1;
+
+ db.set_servername(server_name);
+
+ try
+ {
+ cout << "Opening database " << dbase_name << " on " << server_name
+ << "... " << flush;
+
+ db.open(dbase_name);
+
+ cout << "Ok" << endl;
+ cout << "Starting transaction... " << flush;
+
+ trans.begin();
+
+
+ cout << "Ok" << endl;
+ cout << "Opening the set... " << flush;
+
+ try
+ {
+ cube_set = db.lookup_object(colect_name);
+ }
+ catch (...)
+ {
+ cout << "*Failed*" << endl;
+ cout << "Creating the set... " << flush;
+
+ cube_set = new(&db, "ULong_3D_Set") r_Set< r_Ref< r_Marray<r_ULong> > >;
+ db.set_object_name(*cube_set, colect_name);
+ }
+
+ cout << "Ok" << endl;
+ cout << "Creating the datacube... " << flush;
+
+ // for (int i=0; i<TOTAL_CUBES; i++)
+ // {
+ // cube[i] =
+ cout << "domain == " << domain << endl;
+ cube1 =
+ new(&db, "ULong_3D_Cube") r_Marray<r_ULong>(domain, 1L/* &init */, dsl[i]);
+
+ // cube_set->insert_element(cube[i]);
+ // oid[i] = cube[i].get_oid();
+ cube_set->insert_element(cube1);
+ oid[i] = cube1->get_oid();
+
+ cout << "*" << flush;
+
+
+ cout << " ... Ok" << endl;
+
+ cout << " Cube[" << i+1 << "]: " << oid[i] << endl;
+ cout << " Spatial domain: " << cube1->spatial_domain( ) << endl;
+ cout << " Type length: " << cube1->get_type_length( ) << endl;
+ cout << " Storage Layout: ";
+ if( i < 4 )
+ cout << "regular; tile size " << dsl[i]->get_tile_size( ) << endl;
+ else
+ {
+ cout << "directional; tile size " << dsl[i]->get_tile_size( ) << endl;
+ cout << "Dir decompose: ";
+ for ( int j = 0; j < 3 ; j++ )
+ {
+ for ( int k = 0; k < 3 ; k++)
+ {
+ if ( i < 8 )
+ decomp[k].print_status(cout );
+ else
+ decomp1[k].print_status( cout );
+ }
+ }
+ cout << endl;
+ }
+
+ cout << "Commiting transaction... " << flush;
+
+ trans.commit();
+
+ cout << "Ok" << endl;
+
+ cout << "Closing database... " << flush;
+
+ db.close();
+
+ }
+ catch (r_Error& e)
+ {
+ cout << e.what() << endl;
+ exit(0);
+ }
+ catch (...)
+ {
+ cout << "Undefined error..." << endl;
+ exit(0);
+ }
+}
+
+ cout << "Ok [******************]" << endl << flush;
+
+ cout << endl;
+ cout << "Inserted data resume" << endl;
+ cout << "====================" << endl;
+}
+
+int main(int argc, char* argv[])
+{
+ parse(argc, argv);
+ insert_datacube();
+
+ return 0;
+}
+
+
+
+
+
+
+
+
diff --git a/rasodmg/test/test_bmark_int.cc b/rasodmg/test/test_bmark_int.cc
new file mode 100644
index 0000000..ddd8610
--- /dev/null
+++ b/rasodmg/test/test_bmark_int.cc
@@ -0,0 +1,241 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_bmark_dir.cc
+ *
+ * MODULE: rasodmg
+ *
+ * PURPOSE: benchmark interest tiling
+ *
+ * COMMENTS:
+ * This program is used to load the database with information
+ * for benchmarking interesting tiling
+ *
+*/
+
+#include <iostream>
+#include <stdio.h>
+#include <stdlib.h>
+#include "rasodmg/ref.hh"
+#include "rasodmg/transaction.hh"
+#include "rasodmg/database.hh"
+#include "rasodmg/set.hh"
+#include "rasodmg/marray.hh"
+#include "raslib/odmgtypes.hh"
+#include "rasodmg/tiling.hh"
+#include "rasodmg/dirtiling.hh"
+#include "rasodmg/dirdecompose.hh"
+#include "rasodmg/storagelayout.hh"
+#include "raslib/oid.hh"
+#include "RGBCube.hh"
+
+#define S_32K (32 * 1024L)
+#define S_64K (64 * 1024L)
+#define S_128K (128 * 1024L)
+#define S_256K (256 * 1024L)
+
+#define TOTAL_CUBES 8
+#define SIZE_X 120L
+#define SIZE_Y 159L
+#define SIZE_Z 119L
+
+char* server_name;
+char* dbase_name;
+char* colect_name;
+
+void parse(int argc, char* argv[])
+{
+ if (argc != 4)
+ {
+ cout << "Usage: " << argv[0] << " [server name] [db name] [colection name]"
+ << endl;
+
+ exit(0);
+ }
+
+ server_name = argv[1];
+ dbase_name = argv[2];
+ colect_name = argv[3];
+}
+
+void insert_datacube()
+{
+
+ r_Ref< r_Set< r_Ref< r_Marray<r_ULong> > > > cube_set;
+ r_Minterval domain;
+ r_Domain_Storage_Layout* dsl[TOTAL_CUBES];
+ r_OId oid[TOTAL_CUBES];
+
+ domain = r_Minterval(3);
+ domain << r_Sinterval(0L, SIZE_X)
+ << r_Sinterval(0L, SIZE_Y)
+ << r_Sinterval(0L, SIZE_Z);
+
+
+ // For alligned tiling (Regular tiling)
+
+ r_Minterval block_config(3);
+ block_config << r_Sinterval(0L, SIZE_X)
+ << r_Sinterval(0L, SIZE_Y)
+ << r_Sinterval(0L, SIZE_Z);
+
+ r_Aligned_Tiling* til_reg_32k = new r_Aligned_Tiling(block_config, S_32K);
+ r_Aligned_Tiling* til_reg_64k = new r_Aligned_Tiling(block_config, S_64K);
+ r_Aligned_Tiling* til_reg_128k = new r_Aligned_Tiling(block_config, S_128K);
+ r_Aligned_Tiling* til_reg_256k = new r_Aligned_Tiling(block_config, S_256K);
+
+
+ // For directional tiling
+
+ r_Minterval interest1(3);
+ interest1 << r_Sinterval(0L, SIZE_X)
+ << r_Sinterval(65L, 110L)
+ << r_Sinterval(35L, 75L);
+
+ r_Minterval interest2(3);
+ interest2 << r_Sinterval(0L, SIZE_X)
+ << r_Sinterval(90L, 150L)
+ << r_Sinterval(45L, 105L);
+
+ r_Minterval interest3(3);
+ interest3 << r_Sinterval(60L, 120L)
+ << r_Sinterval(0L, SIZE_Y)
+ << r_Sinterval(0L, SIZE_Z);
+
+ DList<r_Minterval> areas;
+ areas += interest1;
+ areas += interest2;
+ areas += interest3;
+
+ r_Interest_Tiling* til_int_32k =
+ new r_Interest_Tiling(areas, r_Interest_Tiling::SUB_TILING, S_32K);
+ r_Interest_Tiling* til_int_64k =
+ new r_Interest_Tiling(areas, r_Interest_Tiling::SUB_TILING, S_64K);
+ r_Interest_Tiling* til_int_128k =
+ new r_Interest_Tiling(areas, r_Interest_Tiling::SUB_TILING, S_128K);
+ r_Interest_Tiling* til_int_256k =
+ new r_Interest_Tiling(areas, r_Interest_Tiling::SUB_TILING, S_256K);
+
+ // Domain storage layouts
+
+ dsl[0] = new r_Domain_Storage_Layout(domain, til_reg_32k);
+ dsl[1] = new r_Domain_Storage_Layout(domain, til_reg_64k);
+ dsl[2] = new r_Domain_Storage_Layout(domain, til_reg_128k);
+ dsl[3] = new r_Domain_Storage_Layout(domain, til_reg_256k);
+
+ dsl[4] = new r_Domain_Storage_Layout(domain, til_int_32k);
+ dsl[5] = new r_Domain_Storage_Layout(domain, til_int_64k);
+ dsl[6] = new r_Domain_Storage_Layout(domain, til_int_128k);
+ dsl[7] = new r_Domain_Storage_Layout(domain, til_int_256k);
+
+
+ // Create cubes
+
+ r_Database db;
+ db.set_servername(server_name);
+
+ for (int i=0; i< TOTAL_CUBES ; i++)
+ {
+ r_Transaction trans;
+
+ r_Ref< r_Marray<r_ULong> > cube;
+
+ try
+ {
+ cout << "Opening database " << dbase_name << " on " << server_name
+ << "... " << flush;
+
+ db.open(dbase_name);
+
+ cout << "Ok" << endl;
+ cout << "Starting transaction... " << flush;
+
+ trans.begin();
+
+ cout << "Ok" << endl;
+ cout << "Opening the set... " << flush;
+
+ try
+ {
+ cube_set = db.lookup_object(colect_name);
+ }
+ catch (...)
+ {
+ cout << "*Failed*" << endl;
+ cout << "Creating the set... " << flush;
+
+ cube_set =
+ new(&db, "RGB_3D_Set") r_Set< r_Ref< r_Marray<RGBPixel> > >;
+
+ db.set_object_name(*cube_set, colect_name);
+ }
+
+ cout << "Ok" << endl;
+ cout << "Creating the datacube... " << flush;
+
+ cube =
+ new(&db, "RGB_3D_Cube") r_Marray<RGBPixel>(domain, dsl[i]);
+
+ cube_set->insert_element(cube);
+
+ cout << " Cube[" << i << "]: " << cube->get_oid() << endl;
+
+ cout << "*" << flush;
+ cout << " ... Ok" << endl;
+ cout << "Commiting transaction... " << flush;
+
+ trans.commit();
+
+ cout << "Ok" << endl;
+ cout << "Closing database... " << flush;
+
+ db.close();
+ }
+ catch (r_Error& e)
+ {
+ cout << e.what() << endl;
+ exit(0);
+ }
+ catch (...)
+ {
+ cout << "Undefined error..." << endl;
+ exit(0);
+ }
+ }
+}
+
+int main(int argc, char* argv[])
+{
+ parse(argc, argv);
+ insert_datacube();
+
+ return 0;
+}
+
+
+
+
+
+
+
+
diff --git a/rasodmg/test/test_bmark_int1.cc b/rasodmg/test/test_bmark_int1.cc
new file mode 100644
index 0000000..dce1311
--- /dev/null
+++ b/rasodmg/test/test_bmark_int1.cc
@@ -0,0 +1,242 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_bmark_int1.cc
+ *
+ * MODULE: rasodmg
+ *
+ * PURPOSE: benchmark interest tiling
+ *
+ * COMMENTS:
+ * This program is used to load the database with information
+ * for benchmarking interesting tiling
+ *
+*/
+
+#include <iostream>
+#include <stdio.h>
+#include <stdlib.h>
+#include "rasodmg/ref.hh"
+#include "rasodmg/transaction.hh"
+#include "rasodmg/database.hh"
+#include "rasodmg/set.hh"
+#include "rasodmg/marray.hh"
+#include "rasodmg/odmgtypes.hh"
+#include "rasodmg/storagelayout.hh"
+#include "rasodmg/tiling.hh"
+#include "rasodmg/dirtiling.hh"
+#include "rasodmg/dirdecompose.hh"
+#include "rasodmg/storagelayout.hh"
+#include "raslib/oid.hh"
+#include "RGBCube.hh"
+
+#define S_32K (32 * 1024L)
+#define S_64K (64 * 1024L)
+#define S_128K (128 * 1024L)
+#define S_256K (256 * 1024L)
+
+#define TOTAL_CUBES 8
+#define SIZE_X 120L // 12L //
+#define SIZE_Y 159L // 16L //
+#define SIZE_Z 119L // 12L //
+
+char* server_name;
+char* dbase_name;
+char* colect_name;
+
+void parse(int argc, char* argv[])
+{
+ if (argc != 4)
+ {
+ cout << "Usage: " << argv[0] << " [server name] [db name] [colection name]"
+ << endl;
+
+ exit(0);
+ }
+
+ server_name = argv[1];
+ dbase_name = argv[2];
+ colect_name = argv[3];
+}
+
+void insert_datacube( )
+{
+
+ r_Ref< r_Set< r_Ref< r_Marray<r_ULong> > > > cube_set;
+ r_Minterval domain[TOTAL_CUBES];
+ r_Domain_Storage_Layout* dsl[TOTAL_CUBES];
+ r_OId oid[TOTAL_CUBES];
+
+ for (int i = 0; i < TOTAL_CUBES; i++)
+ {
+ domain[i] = r_Minterval(3);
+ domain[i] << r_Sinterval(0L, SIZE_X)
+ << r_Sinterval(0L, SIZE_Y)
+ << r_Sinterval(0L, SIZE_Z);
+ }
+
+ // For alligned tiling (Regular tiling)
+
+ r_Minterval block_config(3);
+ block_config << r_Sinterval(0L, SIZE_X)
+ << r_Sinterval(0L, SIZE_Y)
+ << r_Sinterval(0L, SIZE_Z);
+
+ r_Aligned_Tiling* til_reg_32k = new r_Aligned_Tiling(block_config, S_32K);
+ r_Aligned_Tiling* til_reg_64k = new r_Aligned_Tiling(block_config, S_64K);
+ r_Aligned_Tiling* til_reg_128k = new r_Aligned_Tiling(block_config, S_128K);
+ r_Aligned_Tiling* til_reg_256k = new r_Aligned_Tiling(block_config, S_256K);
+
+
+ // For directional tiling
+
+ r_Minterval interest1(3);
+ interest1 << r_Sinterval(0L, SIZE_X)
+ << r_Sinterval(80L, 120L) // r_Sinterval(8L, 12L) //
+ << r_Sinterval(25L, 60L); // r_Sinterval(2L, 6L); //
+
+ r_Minterval interest2(3);
+ interest2 << r_Sinterval(0L, SIZE_X)
+ << r_Sinterval(70L, 159L) // r_Sinterval(7L, 16L) //
+ << r_Sinterval(25L, 105L); //r_Sinterval(2L, 10L); //
+
+
+ DList<r_Minterval> areas;
+ areas += interest1;
+ areas += interest2;
+
+ r_Interest_Tiling* til_int_32k =
+ new r_Interest_Tiling(areas, r_Interest_Tiling::SUB_TILING, S_32K);
+ r_Interest_Tiling* til_int_64k =
+ new r_Interest_Tiling(areas, r_Interest_Tiling::SUB_TILING, S_64K);
+ r_Interest_Tiling* til_int_128k =
+ new r_Interest_Tiling(areas, r_Interest_Tiling::SUB_TILING, S_128K);
+ r_Interest_Tiling* til_int_256k =
+ new r_Interest_Tiling(areas, r_Interest_Tiling::SUB_TILING, S_256K);
+
+ // Domain storage layouts
+
+ dsl[0] = new r_Domain_Storage_Layout(domain[0], til_reg_32k);
+ dsl[1] = new r_Domain_Storage_Layout(domain[1], til_reg_64k);
+ dsl[2] = new r_Domain_Storage_Layout(domain[2], til_reg_128k);
+ dsl[3] = new r_Domain_Storage_Layout(domain[3], til_reg_256k);
+
+ dsl[4] = new r_Domain_Storage_Layout(domain[4], til_int_32k);
+ dsl[5] = new r_Domain_Storage_Layout(domain[5], til_int_64k);
+ dsl[6] = new r_Domain_Storage_Layout(domain[6], til_int_128k);
+ dsl[7] = new r_Domain_Storage_Layout(domain[7], til_int_256k);
+
+
+ // Create cubes
+
+ r_Database db;
+ db.set_servername(server_name);
+
+ for ( i=0; i< TOTAL_CUBES ; i++)
+ {
+ r_Transaction trans;
+
+ r_Ref< r_Marray<r_ULong> > cube;
+
+ try
+ {
+ cout << "Opening database " << dbase_name << " on " << server_name
+ << "... " << flush;
+
+ db.open(dbase_name);
+
+ cout << "Ok" << endl;
+ cout << "Starting transaction... " << flush;
+
+ trans.begin();
+
+ cout << "Ok" << endl;
+ cout << "Opening the set... " << flush;
+
+ try
+ {
+ cube_set = db.lookup_object(colect_name);
+ }
+ catch (...)
+ {
+ cout << "*Failed*" << endl;
+ cout << "Creating the set... " << flush;
+
+ cube_set =
+ new(&db, "RGB_3D_Set") r_Set< r_Ref< r_Marray<RGBPixel> > >;
+
+ db.set_object_name(*cube_set, colect_name);
+ }
+
+ cout << "Ok" << endl;
+ cout << "Creating the datacube... " << flush;
+ r_Minterval newDomain( domain[i]);
+ cube =
+ new(&db, "RGB_3D_Cube") r_Marray<RGBPixel>(newDomain, dsl[i]);
+
+ cube_set->insert_element(cube);
+
+ cout << "Cube[" << i+1 << "]: " << cube->get_oid() << endl;
+ cout << "Spatial domain: " << cube->spatial_domain( ) <<endl;
+ cout << "Storage Layout " << endl;
+ dsl[i]->print_status( );
+
+ cout << "*" << flush;
+ cout << " ... Ok" << endl;
+ cout << "Commiting transaction... " << flush;
+
+ trans.commit();
+
+ cout << "Ok" << endl;
+ // cout << "Destroying cube... " <<flush;
+ // cube.destroy( );
+ cout << "Closing database... " << flush;
+ db.close();
+ }
+ catch (r_Error& e)
+ {
+ cout << e.what() << endl;
+ exit(0);
+ }
+ catch (...)
+ {
+ cout << "Undefined error..." << endl;
+ exit(0);
+ }
+ }
+}
+
+int main(int argc, char* argv[])
+{
+ parse(argc, argv);
+ insert_datacube( );
+ return 0;
+}
+
+
+
+
+
+
+
+
diff --git a/rasodmg/test/test_bmark_pet.cc b/rasodmg/test/test_bmark_pet.cc
new file mode 100644
index 0000000..8fa94fb
--- /dev/null
+++ b/rasodmg/test/test_bmark_pet.cc
@@ -0,0 +1,235 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_bmark_pet.cc
+ *
+ * MODULE: rasodmg
+ *
+ * PURPOSE: benchmark interest tiling
+ *
+ * COMMENTS:
+ * This program is used to load the database with information
+ * for benchmarking interesting tiling
+ *
+*/
+
+#include <iostream>
+#include <stdio.h>
+#include <stdlib.h>
+#include "rasodmg/ref.hh"
+#include "rasodmg/transaction.hh"
+#include "rasodmg/database.hh"
+#include "rasodmg/set.hh"
+#include "rasodmg/marray.hh"
+#include "rasodmg/odmgtypes.hh"
+#include "rasodmg/storagelayout.hh"
+#include "rasodmg/tiling.hh"
+#include "rasodmg/dirtiling.hh"
+#include "rasodmg/dirdecompose.hh"
+#include "rasodmg/storagelayout.hh"
+#include "raslib/oid.hh"
+#include "include/basictypes.hh"
+
+#define S_32K (32 * 1024L)
+#define S_64K (64 * 1024L)
+#define S_128K (128 * 1024L)
+#define S_256K (256 * 1024L)
+
+#define TOTAL_CUBES 7
+#define SIZE_X 185L
+#define SIZE_Y 150L
+#define SIZE_Z 141L
+
+char* server_name;
+char* dbase_name;
+char* colect_name;
+
+void parse(int argc, char* argv[])
+{
+ if (argc != 4)
+ {
+ cout << "Usage: " << argv[0] << " [server name] [db name] [colection name]"
+ << endl;
+
+ exit(0);
+ }
+
+ server_name = argv[1];
+ dbase_name = argv[2];
+ colect_name = argv[3];
+}
+
+void insert_datacube( )
+{
+
+ r_Ref< r_Set< r_Ref< r_Marray<r_Short> > > > cube_set;
+ r_Minterval domain[TOTAL_CUBES];
+ r_Domain_Storage_Layout* dsl[TOTAL_CUBES];
+ r_OId oid[TOTAL_CUBES];
+
+ for (int i = 0; i < TOTAL_CUBES; i++)
+ {
+ domain[i] = r_Minterval(3);
+ domain[i] << r_Sinterval(0L, SIZE_X - 1 )
+ << r_Sinterval(0L, SIZE_Y - 1)
+ << r_Sinterval(0L, SIZE_Z - 1);
+ }
+
+ // For aligned tiling (Regular tiling)
+
+ r_Minterval block_config(3);
+ block_config << r_Sinterval(0L, SIZE_X)
+ << r_Sinterval(0L, SIZE_Y)
+ << r_Sinterval(0L, SIZE_Z);
+
+ r_Aligned_Tiling* til_reg_32k = new r_Aligned_Tiling(block_config, S_32K);
+ r_Aligned_Tiling* til_reg_64k = new r_Aligned_Tiling(block_config, S_64K);
+ r_Aligned_Tiling* til_reg_128k = new r_Aligned_Tiling(block_config, S_128K);
+ r_Aligned_Tiling* til_reg_256k = new r_Aligned_Tiling(block_config, S_256K);
+ r_Aligned_Tiling* til_reg_64k1 = new r_Aligned_Tiling(block_config, S_64K);
+
+
+ // For areas of interest tiling
+ r_Minterval interest1_1("[23:170,4:75,12:138]");
+ r_Minterval interest1_2("[61:149,70:135,8:130]");
+ r_Minterval interest2_1("[28:175,2:73,8:134]");
+ r_Minterval interest2_2("[63:151,75:140,11:133]");
+
+
+ DList<r_Minterval> areas1;
+ areas1 += interest1_1;
+ areas1 += interest1_2;
+ DList<r_Minterval> areas2;
+ areas2 += interest2_1;
+ areas2 += interest2_2;
+
+ r_Interest_Tiling* til_int1 =
+ new r_Interest_Tiling(areas1, r_Interest_Tiling::NO_LIMIT);
+ r_Interest_Tiling* til_int2 =
+ new r_Interest_Tiling(areas2, r_Interest_Tiling::NO_LIMIT);
+
+ // Domain storage layouts
+
+ dsl[0] = new r_Domain_Storage_Layout(domain[0], til_reg_32k);
+ dsl[1] = new r_Domain_Storage_Layout(domain[1], til_reg_64k);
+ dsl[2] = new r_Domain_Storage_Layout(domain[2], til_reg_128k);
+ dsl[3] = new r_Domain_Storage_Layout(domain[3], til_reg_256k);
+
+ dsl[4] = new r_Domain_Storage_Layout(domain[4], til_int1);
+ dsl[5] = new r_Domain_Storage_Layout(domain[5], til_int2);
+ dsl[6] = new r_Domain_Storage_Layout(domain[6], til_reg_64k1);
+
+
+ // Create cubes
+
+ r_Database db;
+ db.set_servername(server_name);
+
+ for ( i=0; i< TOTAL_CUBES ; i++)
+ {
+ r_Transaction trans;
+
+ r_Ref< r_Marray<r_Short> > cube;
+
+ try
+ {
+ cout << "Opening database " << dbase_name << " on " << server_name
+ << "... " << flush;
+
+ db.open(dbase_name);
+
+ cout << "Ok" << endl;
+ cout << "Starting transaction... " << flush;
+
+ trans.begin();
+
+ cout << "Ok" << endl;
+ cout << "Opening the set... " << flush;
+
+ try
+ {
+ cube_set = db.lookup_object(colect_name);
+ }
+ catch (...)
+ {
+ cout << "*Failed*" << endl;
+ cout << "Creating the set... " << flush;
+
+ cube_set =
+ new(&db, "ShortSet3") r_Set< r_Ref< r_Marray<r_Short> > >;
+
+ db.set_object_name(*cube_set, colect_name);
+ }
+
+ cout << "Ok" << endl;
+ cout << "Creating the datacube... " << flush;
+ r_Minterval newDomain( domain[i]);
+ cube =
+ new(&db, "ShortCube") r_Marray<r_Short>(newDomain, dsl[i]);
+
+ cube_set->insert_element(cube);
+
+ cout << "Cube[" << i+1 << "]: " << cube->get_oid() << endl;
+ cout << "Spatial domain: " << cube->spatial_domain( ) <<endl;
+ cout << "Storage Layout " << endl;
+ dsl[i]->print_status( );
+
+ cout << "*" << flush;
+ cout << " ... Ok" << endl;
+ cout << "Commiting transaction... " << flush;
+
+ trans.commit();
+
+ cout << "Ok" << endl;
+ // cout << "Destroying cube... " <<flush;
+ // cube.destroy( );
+ cout << "Closing database... " << flush;
+ db.close();
+ }
+ catch (r_Error& e)
+ {
+ cout << e.what() << endl;
+ exit(0);
+ }
+ catch (...)
+ {
+ cout << "Undefined error..." << endl;
+ exit(0);
+ }
+ }
+}
+
+int main(int argc, char* argv[])
+{
+ parse(argc, argv);
+ insert_datacube( );
+ return 0;
+}
+
+
+
+
+
+
+
+
diff --git a/rasodmg/test/test_bmark_stat.cc b/rasodmg/test/test_bmark_stat.cc
new file mode 100644
index 0000000..2c5b776
--- /dev/null
+++ b/rasodmg/test/test_bmark_stat.cc
@@ -0,0 +1,331 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_bmark_stat.cc
+ *
+ * MODULE: rasodmg
+ *
+ * PURPOSE: Load database for statistic tiling benchmark
+ *
+ * COMMENTS:
+ * None
+*/
+
+/*
+ ATENTION: The format of the input file for using with this program is:
+
+ border_threshold accesses_threshold tilesize domain
+ access1
+ access2
+ accessXXX
+ ...
+
+ Example:
+
+ 50 0.20 1000 [0:799, 0:599]
+ [10:20, 30:40]
+ [12:20, 35:39]
+ [100:300, 300:400]
+ [120:300, 310:410]
+ [200:500, 350:500]
+ [200:510, 350:500]
+*/
+
+
+#include <iostream>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "raslib/oid.hh"
+#include "raslib/dlist.hh"
+#include "raslib/minterval.hh"
+#include "raslib/sinterval.hh"
+#include "rasodmg/ref.hh"
+#include "rasodmg/set.hh"
+#include "rasodmg/marray.hh"
+#include "rasodmg/tiling.hh"
+#include "rasodmg/database.hh"
+#include "rasodmg/odmgtypes.hh"
+#include "rasodmg/stattiling.hh"
+#include "rasodmg/transaction.hh"
+#include "rasodmg/storagelayout.hh"
+#include "RGBCube.hh"
+
+#define S_32K (32 * 1024L)
+#define S_64K (64 * 1024L)
+#define S_128K (128 * 1024L)
+#define S_256K (256 * 1024L)
+
+#define TOTAL_CUBES 8
+#define SIZE_X 120L
+#define SIZE_Y 159L
+#define SIZE_Z 119L
+
+char* filename;
+char* server_name;
+char* dbase_name;
+char* colect_name;
+int cube_i;
+
+DList<r_Access> stat_info;
+unsigned int border_threshold;
+double interesting_threshold;
+unsigned long tile_size;
+r_Minterval* domain;
+
+void parse(int argc, char* argv[])
+{
+ if (argc != 6)
+ {
+ cout << "Usage: " << argv[0] << " server db collec ptfile cube" << endl;
+ cout << endl;
+ cout << " server ............. server to use" << endl;
+ cout << " db ................. database" << endl;
+ cout << " collec ............. collection" << endl;
+ cout << " ptfile ............. pattern file" << endl;
+ cout << " cube ............... datacube to create" << endl;
+
+ exit(1);
+ }
+
+ server_name = argv[1];
+ dbase_name = argv[2];
+ colect_name = argv[3];
+ filename = argv[4];
+ cube_i = atoi(argv[5]);
+
+ if ((cube_i<0) || (cube_i>7))
+ {
+ cout << "Invalid datacube. Must be in 0..7" << endl;
+ exit(0);
+ }
+}
+
+void read_data()
+{
+ const unsigned int BUF_SIZE = 256;
+ char buf[BUF_SIZE], buf2[BUF_SIZE];
+
+ cout << "Opening " << filename << " for reading... ";
+
+ ifstream is(filename, ios::in);
+ if (!is)
+ {
+ cout << "Couldn't open!!!" << endl;
+ exit(1);
+ }
+ else
+ cout << "done." << endl;
+
+ cout << "Reading parameters... ";
+
+ is >> border_threshold;
+ is >> interesting_threshold;
+ is >> tile_size;
+
+ is.getline(buf, BUF_SIZE);
+ domain = new r_Minterval(buf);
+
+ cout << "done." << endl;
+ cout << "Geting the accesses... ";
+
+ unsigned long count = 0;
+
+ while (!is.eof())
+ {
+ is.getline(buf, BUF_SIZE);
+ if (sscanf(buf, "%s", buf2) == 1)
+ {
+ r_Minterval inter(buf);
+ stat_info += inter;
+ ++count;
+
+ cout << "*";
+ }
+ }
+
+ is.close();
+
+ cout << endl;
+ cout << "Geting the accesses... done." << endl << endl;
+
+ cout << "Border threshold = " << border_threshold << endl;
+ cout << "Interesting threshold = " << interesting_threshold << endl;
+ cout << "Tile size = " << tile_size << endl;
+ cout << "Domain = " << *domain << endl;
+ cout << "Number of accesses = " << count << endl << endl;
+}
+
+
+void insert_datacube()
+{
+
+ r_Ref< r_Set< r_Ref< r_Marray<r_ULong> > > > cube_set;
+ r_Minterval domain;
+
+ domain = r_Minterval(3);
+ domain << r_Sinterval(0L, SIZE_X)
+ << r_Sinterval(0L, SIZE_Y)
+ << r_Sinterval(0L, SIZE_Z);
+
+
+ // For alligned tiling (Regular tiling)
+
+ r_Minterval block_config(3);
+ block_config << r_Sinterval(0L, SIZE_X)
+ << r_Sinterval(0L, SIZE_Y)
+ << r_Sinterval(0L, SIZE_Z);
+
+ unsigned long ts;
+ switch (cube_i)
+ {
+ case 0:
+ ts = S_32K;
+ break;
+ case 1:
+ ts = S_64K;
+ break;
+ case 2:
+ ts = S_128K;
+ break;
+ case 3:
+ ts = S_256K;
+ break;
+ default: // Irrelevant, not used.
+ ts = S_32K;
+ break;
+ }
+
+ r_Aligned_Tiling til_reg(block_config, ts);
+ r_Stat_Tiling til_stat(border_threshold, interesting_threshold, tile_size);
+
+ if (cube_i > 3)
+ {
+ til_stat.update_stat_information(stat_info);
+ }
+
+
+ // Domain storage layout
+
+ // This is a hack due to problems with the pointers
+ r_Domain_Storage_Layout* dsl[2];
+ r_Domain_Storage_Layout* use;
+
+ dsl[0] = new r_Domain_Storage_Layout(domain, &til_reg);
+ dsl[1] = new r_Domain_Storage_Layout(domain, &til_stat);
+
+ if (cube_i<4)
+ use = dsl[0];
+ else
+ use = dsl[1];
+
+ // Create cube
+
+ r_Database db;
+ db.set_servername(server_name);
+ r_Transaction trans;
+ r_Ref< r_Marray<r_ULong> > cube;
+
+ try
+ {
+ cout << "Opening database " << dbase_name << " on " << server_name
+ << "... " << flush;
+
+ db.open(dbase_name);
+
+ cout << "Ok" << endl;
+ cout << "Starting transaction... " << flush;
+
+ trans.begin();
+
+ cout << "Ok" << endl;
+ cout << "Opening the set... " << flush;
+
+ try
+ {
+ cube_set = db.lookup_object(colect_name);
+ }
+ catch (...)
+ {
+ cout << "*Failed*" << endl;
+ cout << "Creating the set... " << flush;
+
+ cube_set =
+ new(&db, "RGB_3D_Set") r_Set< r_Ref< r_Marray<RGBPixel> > >;
+
+ db.set_object_name(*cube_set, colect_name);
+ }
+
+ cout << "Ok" << endl;
+ cout << "Creating the datacube... " << flush;
+
+ cube =
+ new(&db, "RGB_3D_Cube") r_Marray<RGBPixel>(domain, use);
+
+ cube_set->insert_element(cube);
+
+ cout << "*" << flush;
+ cout << " ... Ok" << endl;
+ cout << "Commiting transaction... " << flush;
+
+ trans.commit();
+
+ cout << "Ok" << endl;
+ cout << "Closing database... " << flush;
+
+ db.close();
+
+ cout << " Ok" << endl << flush;
+ }
+ catch (r_Error& e)
+ {
+ cout << e.what() << endl;
+ exit(0);
+ }
+ catch (...)
+ {
+ cout << "Undefined error..." << endl;
+ exit(0);
+ }
+}
+
+
+int main(int argc, char* argv[])
+{
+ parse(argc, argv);
+ read_data();
+ insert_datacube();
+
+ return 0;
+}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/rasodmg/test/test_breakdown.cc b/rasodmg/test/test_breakdown.cc
new file mode 100644
index 0000000..41f4f65
--- /dev/null
+++ b/rasodmg/test/test_breakdown.cc
@@ -0,0 +1,112 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_breakdown.cc
+ *
+ * MODULE: rasodmg
+ *
+ * PURPOSE: Simulates a connection breakdown with an open database and a
+ * unfinished transaction.
+ *
+ * COMMENTS:
+ * None
+*/
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#include "raslib/template_inst.hh"
+#endif
+
+#include <iostream>
+#include <string.h>
+#include <stdlib.h> // for exit()
+
+#include "rasodmg/ref.hh"
+#include "rasodmg/transaction.hh"
+#include "rasodmg/database.hh"
+#include "rasodmg/set.hh"
+#include "rasodmg/marray.hh"
+
+int main( int ac, char** av )
+{
+ char servername[255];
+ char baseName[255];
+ char collName[255];
+
+ if( ac>1 )
+ strcpy( servername, av[1] );
+ else
+ strcpy( servername, "hpwibas5" );
+
+ if( ac > 2 )
+ strcpy( baseName, av[2] );
+ else
+ strcpy( baseName, "RasDaBase" );
+
+ if( ac > 3 )
+ strcpy( collName, av[3] );
+ else
+ strcpy( collName, "Images" );
+
+ cout << endl << endl;
+ cout << "ODMG conformant insertion of Marrays" << endl;
+ cout << "====================================" << endl << endl;
+
+ r_Database db;
+ r_Transaction ta;
+ r_Ref< r_Set< r_Ref< r_Marray<int> > > > image_set;
+ r_Ref< r_Marray<int> > image;
+ r_Minterval domain;
+
+ domain = r_Minterval(2) << r_Sinterval( 0, 10 ) << r_Sinterval( 0, 10 );
+
+ db.set_servername( servername );
+
+ cout << "Opening Database on " << servername << "... "; cout.flush();
+ db.open( baseName );
+ cout << "OK" << endl;
+
+ cout << "Starting Transaction ... "; cout.flush();
+ ta.begin();
+ cout << "OK" << endl;
+
+ cout << "Creating a persistent set with two images ..."; cout.flush();
+
+ // create the set
+ image_set = new( &db ) r_Set< r_Ref< r_Marray<int> > >;
+
+ // create a name for the set
+ db.set_object_name( *image_set, collName );
+
+ // create first image
+ image = new( &db ) r_Marray<int>( domain, 0 );
+
+ // put in into the persistent list
+ image_set->insert_element( image );
+
+ //
+ // *** POW! CONNECTION BREAKDOWN! ***
+ //
+ cout << endl << "*** POW! CONNECTION BREAKDOWN! ***" << endl;
+ exit( 0 );
+}
diff --git a/rasodmg/test/test_collection.cc b/rasodmg/test/test_collection.cc
new file mode 100644
index 0000000..d668a89
--- /dev/null
+++ b/rasodmg/test/test_collection.cc
@@ -0,0 +1,116 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_collection.cc
+ *
+ * MODULE: rasodmg
+ *
+ * COMMENTS:
+ * None
+*/
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#include "raslib/template_inst.hh"
+#endif
+
+#include <iostream>
+#include "rasodmg/collection.hh"
+#include "rasodmg/iterator.hh"
+#include "rasodmg/ref.hh"
+
+int main()
+{
+ int v,x,y,z,d;
+
+ v = 100;
+ x = 200;
+ y = 100;
+ z = 300;
+ d = 500;
+
+ cout << endl << endl;
+ cout << "Collection Examples" << endl;
+ cout << "====================" << endl << endl;
+
+ cout << "Creating r_Collection of type int." <<endl;
+ r_Collection< r_Ref_Any > a;
+ r_Iterator< r_Ref_Any > iter;
+
+ cout << "Cardinality of empty collection 'a': " << a.cardinality() << endl << endl;
+
+ cout << "Now inserting four elements:" << endl << "v = 100" << endl;
+ a.insert_element( &v );
+
+ cout << "x = 200" << endl;
+ a.insert_element( &x );
+
+ cout << "y = 100 (should work in collections)" << endl;
+ a.insert_element( &y );
+
+ cout << "z = 300" << endl;
+ a.insert_element( &z );
+
+ cout << "Cardinality of collection 'a' after four inserts: " << a.cardinality() << endl << endl;
+
+ cout << "Elements: " << flush;
+ for( iter = a.create_iterator(); iter.not_done(); iter++ )
+ cout << (*iter) << ", " << flush;
+ cout << endl;
+
+ cout << "Does 'a' contain element '100' (1=TRUE/0=FALSE)? " << a.contains_element(&y) << endl;
+
+ cout << "Does 'a' contain element '500' (1=TRUE/0=FALSE)? " << a.contains_element(&d) << endl << endl;
+
+ cout << "Now removing element 'x=200' from 'a'." << endl;
+ a.remove_element(&x);
+ cout << "Cardinality of 'a' now: " << a.cardinality() << endl << endl;
+
+ cout << "Now removing element '100' from 'a'." << endl;
+ a.remove_element(&y);
+ cout << "Cardinality of 'a' now: " << a.cardinality() << endl << endl;
+
+ cout << "Now removing (non-existing) element '500' from 'a'." << endl;
+ a.remove_element(&d);
+ cout << "Cardinality of 'a' now: " << a.cardinality() << endl << endl;
+
+ cout << "Elements: " << flush;
+ for( iter = a.create_iterator(); iter.not_done(); iter++ )
+ cout << (*iter) << ", " << flush;
+ cout << endl;
+
+ cout << "Testing assignment operator on r_Collections." << endl << "(creating r_Collection 'b' that is equal to 'a'.)" <<endl;
+ r_Collection< r_Ref_Any > b;
+ b = a;
+ cout << "Cardinality of 'b': " << b.cardinality() << endl << endl;
+
+ cout << "Testing copy constructor of r_Collection." << endl << "(creating r_Collection 'c' that is equal to 'a'.)" <<endl;
+ r_Collection< r_Ref_Any > c(a);
+ cout << "Cardinality of 'c': " << c.cardinality() << endl << endl;
+
+ cout << "Now removing all elements from 'a'." << endl;
+ a.remove_all();
+ cout << "Cardinality of 'a' now: " << a.cardinality() << endl;
+ cout << "Cardinality of 'b' is still: " << b.cardinality() << endl;
+ cout << "Cardinality of 'c' is still: " << c.cardinality() << endl << endl;
+}
diff --git a/rasodmg/test/test_comp_conv.sh b/rasodmg/test/test_comp_conv.sh
new file mode 100644
index 0000000..5f6e2c6
--- /dev/null
+++ b/rasodmg/test/test_comp_conv.sh
@@ -0,0 +1,325 @@
+#!/bin/ksh
+#constants sections
+TEST_TIME=$(date +%d.%b.%Y_%H:%M)
+TEST_DIR=$RMANHOME/rasodmg/test
+SYSTEM_INSERT=$TEST_DIR/system_insert
+SYSTEM_QUERY=$TEST_DIR/system_query
+DEFDIFF=$TEST_DIR/defdiff
+QUERYFILE=/tmp/query.ql
+LOGFILE=$PWD/$0_log
+IMG_DIR=$TEST_DIR/images
+INIMGFILE=$IMG_DIR/x1
+OUTIMGFILE=$IMG_DIR/out
+FAILIMGFILE=$IMG_DIR/fails/out
+REALIMGFILE="$OUTIMGFILE"1
+set -A CONVERSION Array TIFF JPEG HDF PNG BMP VFF
+set -A CONVERSIONEXT raw tif jpg hdf png bmp vff
+#AutoCompression not implemented ask Andeas?
+COMPRESSION="Array ZLib RLE HaarWavelet DaubechiesWavelet SepZLib \
+ SepRLE Daubechies6Wavelet Daubechies8Wavelet Daubechies10Wavelet Daubechies12Wavelet \
+ Daubechies14Wavelet Daubechies16Wavelet Daubechies18Wavelet Daubechies20Wavelet \
+ LeastAsym8Wavelet LeastAsym10Wavelet LeastAsym12Wavelet LeastAsym14Wavelet \
+ LeastAsym16Wavelet LeastAsym18Wavelet LeastAsym20Wavelet Coiflet6Wavelet \
+ Coiflet12Wavelet Coiflet18Wavelet Coiflet24Wavelet Coiflet30Wavelet QHaarWavelet"
+DEBUG=0
+SERVER=$HOSTNAME
+DATABASE=RASBASE
+USER=rasguest
+PASSWD=rasguest
+COLLNAME=pipi
+SETTYPE=BoolSet
+MDDTYPE=BoolImage
+MDDDOMAIN=[0:624,0:899]
+
+#function used
+error() {
+ echo "$1 !"
+ exit 1
+}
+
+log() {
+ echo "$1" >>$LOGFILE
+}
+
+print_options() {
+echo "RasDaMan (s)erver host ..... $SERVER"
+echo "RasDaMan (d)atabase ..... $DATABASE"
+echo "RasDaMan (u)ser ..... $USER"
+echo "Test Colle(c)tion ..... $COLLNAME"
+echo "Test Set T(y)pe ..... $SETTYPE"
+echo "Test MDD (T)ype ..... $MDDTYPE"
+echo "Test MDD D(o)main ..... $MDDDOMAIN"
+echo "Start Con(v)ersion Test"
+echo "Start Com(p)ression Test"
+echo "(E)xit Test"
+}
+
+check_options() {
+ option=""
+ if(test "$1" = "s"); then
+ while(test -z "$option"); do
+ echo "RasDaMan Server Host: \c"
+ read option
+ done
+ SERVER=$option
+ elif (test "$1" = "d"); then
+ while(test -z "$option"); do
+ echo "RasDaMan Database: \c"
+ read option
+ done
+ DATABASE=$option
+ elif (test "$1" = "u"); then
+ while(test -z "$option"); do
+ echo "RasDaMan User: \c"
+ read option
+ done
+ USER=$option
+ option=""
+ while(test -z "$option"); do
+ echo "Password: \c"
+ read option
+ done
+ PASSWD=$option
+ elif (test "$1" = "c"); then
+ while(test -z "$option"); do
+ echo "Test Collection: \c"
+ read option
+ done
+ COLLNAME=$option
+ elif (test "$1" = "y"); then
+ while(test -z "$option"); do
+ echo "Test SetType: \c"
+ read option
+ done
+ SETTYPE=$option
+ elif (test "$1" = "t"); then
+ while(test -z "$option"); do
+ echo "MDD Type: \c"
+ read option
+ done
+ MDDTYPE=$option
+ elif (test "$1" = "o"); then
+ while(test -z "$option"); do
+ echo "MDD Domain: \c"
+ read option
+ done
+ MDDDOMAIN=$option
+ elif (test "$1" = "p"); then
+ echo "All set, get ready for compression test, go!"
+ execute_compression_test
+ elif (test "$1" = "v"); then
+ echo "All set, get ready for conversion test, go!"
+ execute_conversion_test
+ else
+ echo "Please choose a valid option!"
+ fi
+}
+
+
+
+
+execute_compression_test() {
+SELECTQUERY="select a from $COLLNAME as a"
+CREATEQUERY="create collection $COLLNAME $SETTYPE"
+DELETEQUERY="delete from $COLLNAME where true"
+
+SYSTEM_INSERT_ARGS="-s $SERVER -u $USER -p $PASSWD --dbname $DATABASE --collection $COLLNAME --mddtype $MDDTYPE --mdddomain $MDDDOMAIN"
+SYSTEM_QUERY_ARGS="-s $SERVER -u $USER -p $PASSWD --dbname $DATABASE"
+
+#creates collection
+rm -rf $LOGFILE
+log "Compression Test stated on $TEST_TIME"
+log "-creating collection $COLLNAME SETTYPE"
+echo "$CREATEQUERY" > $QUERYFILE
+if (test $DEBUG -ne 0); then
+ log "$SYSTEM_QUERY $SYSTEM_QUERY_ARGS -r $QUERYFILE"
+fi
+$SYSTEM_QUERY $SYSTEM_QUERY_ARGS -r $QUERYFILE 1>>$LOGFILE 2>&1
+if ( test $? -ne 0 ); then
+ #deletes all mdd from collection from current collection
+ log "-deleting all image from $COLLNAME collection"
+ echo "$DELETEQUERY" > $QUERYFILE
+ if (test $DEBUG -ne 0); then
+ log "$SYSTEM_QUERY $SYSTEM_QUERY_ARGS -r $QUERYFILE"
+ fi
+ $SYSTEM_QUERY $SYSTEM_QUERY_ARGS -r $QUERYFILE 1>>$LOGFILE 2>&1
+ if ( test $? -ne 0 ); then
+ error "An Error occured please check the log file $LOGFILE"
+ fi
+fi
+
+k=1
+informat=${CONVERSION[0]}
+informatext=${CONVERSIONEXT[0]}
+
+for storage in $COMPRESSION; do
+ for transfer in $COMPRESSION; do
+ #insert the data in db
+ log "--inserting $INIMGFILE.$informatext with tranfer $transfer mode and storage $storage mode in $COLLNAME"
+ if (test $DEBUG -ne 0); then
+ log "$SYSTEM_INSERT $SYSTEM_INSERT_ARGS \n--storageformat $storage --transformat $transfer \
+ --inputformat $informat -r $INIMGFILE.$informatext"
+ fi
+ $SYSTEM_INSERT $SYSTEM_INSERT_ARGS --storageformat $storage --transformat $transfer \
+ --inputformat $informat -r $INIMGFILE.$informatext 1>>$LOGFILE 2>&1
+ if ( test $? -eq 0 ); then
+ #checks if what is in db is correct compared with DEF input
+ outformat=$informat
+ outformatext=$informatext
+ log "---retriving data for tranfer $transfer mode in output $outformat mode"
+ echo "$SELECTQUERY" > $QUERYFILE
+ if (test $DEBUG -ne 0); then
+ log "$SYSTEM_QUERY $SYSTEM_QUERY_ARGS --transformat $transfer --outputformat $outformat \
+ --outputfilename $OUTIMGFILE -r $QUERYFILE"
+ fi
+ $SYSTEM_QUERY $SYSTEM_QUERY_ARGS --transformat $transfer --outputformat $outformat \
+ --outputfilename $OUTIMGFILE -r $QUERYFILE 1>>$LOGFILE 2>&1
+ if ( test $? -ne 0 ); then
+ error "An Error occured please check the log file $LOGFILE"
+ fi
+
+ #comparing files src.outformatext with realfile.outformatext
+ $DEFDIFF --srcfilename $INIMGFILE.$informatext --srcformat $informat \
+ --destfilename $REALIMGFILE.$outformatext --destformat $outformat 1>>$LOGFILE 2>&1
+ if (test $? -eq 0); then
+ echo "$k-DEFIN=$informat TRANSFER=$transfer STORAGE=$storage DEFOUT=$outformat OK"
+ log "---$k-DEFIN=$informat TRANSFER=$transfer STORAGE=$storage DEFOUT=$outformat OK"
+ else
+ echo "$k-DEFIN=$informat TRANSFER=$transfer STORAGE=$storage DEFOUT=$outformat FAILED"
+ log "---$k-DEFIN=$informat TRANSFER=$transfer STORAGE=$storage DEFOUT=$outformat FAILED"
+ #keep the file for futher analysis
+ mv $REALIMGFILE.$outformatext $FAILIMGFILE$k.$outformatext
+ fi
+
+ #deletes all mdd from collection
+ log "--deleting current image"
+ echo "$DELETEQUERY" > $QUERYFILE
+ if (test $DEBUG -ne 0); then
+ log "$SYSTEM_QUERY $SYSTEM_QUERY_ARGS --transformat $transfer -r $QUERYFILE"
+ fi
+ $SYSTEM_QUERY $SYSTEM_QUERY_ARGS --transformat $transfer -r $QUERYFILE 1>>$LOGFILE 2>&1
+ if ( test $? -ne 0 ); then
+ error "An Error occured please check the log file $LOGFILE"
+ fi
+ else
+ error "An Error occured please check the log file $LOGFILE"
+ fi
+ k=$(($k+1))
+ done
+done
+}
+
+execute_conversion_test() {
+SELECTQUERY="select a from $COLLNAME as a"
+CREATEQUERY="create collection $COLLNAME $SETTYPE"
+DELETEQUERY="delete from $COLLNAME where true"
+
+SYSTEM_INSERT_ARGS="-s $SERVER -u $USER -p $PASSWD --dbname $DATABASE --collection $COLLNAME --mddtype $MDDTYPE --mdddomain $MDDDOMAIN"
+SYSTEM_QUERY_ARGS="-s $SERVER -u $USER -p $PASSWD --dbname $DATABASE"
+
+#creates collection
+rm -rf $LOGFILE
+log "Conversion Test stated on $TEST_TIME"
+log "-creating collection $COLLNAME SETTYPE"
+echo "$CREATEQUERY" > $QUERYFILE
+if (test $DEBUG -ne 0); then
+ log "$SYSTEM_QUERY $SYSTEM_QUERY_ARGS -r $QUERYFILE"
+fi
+$SYSTEM_QUERY $SYSTEM_QUERY_ARGS -r $QUERYFILE 1>>$LOGFILE 2>&1
+if ( test $? -ne 0 ); then
+ #deletes all mdd from collection from current collection
+ log "-deleting all image from $COLLNAME collection"
+ echo "$DELETEQUERY" > $QUERYFILE
+ if (test $DEBUG -ne 0); then
+ log "$SYSTEM_QUERY $SYSTEM_QUERY_ARGS -r $QUERYFILE"
+ fi
+ $SYSTEM_QUERY $SYSTEM_QUERY_ARGS -r $QUERYFILE 1>>$LOGFILE 2>&1
+ if ( test $? -ne 0 ); then
+ error "An Error occured please check the log file $LOGFILE"
+ fi
+fi
+
+i=0
+k=1
+n=${#CONVERSION[*]}
+transfer=Array
+storage=Array
+
+while (test i -lt n); do
+ informat=${CONVERSION[$i]}
+ informatext=${CONVERSIONEXT[$i]}
+ #insert the data in db
+ log "--inserting $INIMGFILE.$informatext with tranfer $transfer mode and storage $storage mode in $COLLNAME"
+ if (test $DEBUG -ne 0); then
+ log "$SYSTEM_INSERT $SYSTEM_INSERT_ARGS \n--storageformat $storage --transformat $transfer \
+ --inputformat $informat -r $INIMGFILE.$informatext"
+ fi
+ $SYSTEM_INSERT $SYSTEM_INSERT_ARGS --storageformat $storage --transformat $transfer \
+ --inputformat $informat -r $INIMGFILE.$informatext 1>>$LOGFILE 2>&1
+ if ( test $? -eq 0 ); then
+ #checks if what is in db is correct compared with DEF input
+ j=0
+ while (test j -lt n); do
+ outformat=${CONVERSION[$j]}
+ outformatext=${CONVERSIONEXT[$j]}
+ log "---retriving data for tranfer $transfer mode in output $outformat mode"
+ echo "$SELECTQUERY" > $QUERYFILE
+ if (test $DEBUG -ne 0); then
+ log "$SYSTEM_QUERY $SYSTEM_QUERY_ARGS --transformat $transfer --outputformat $outformat \
+ --outputfilename $OUTIMGFILE -r $QUERYFILE"
+ fi
+ $SYSTEM_QUERY $SYSTEM_QUERY_ARGS --transformat $transfer --outputformat $outformat \
+ --outputfilename $OUTIMGFILE -r $QUERYFILE 1>>$LOGFILE 2>&1
+ if ( test $? -ne 0 ); then
+ error "An Error occured please check the log file $LOGFILE"
+ fi
+ #comparing files src.outformatext with realfile.outformatext
+ $DEFDIFF --srcfilename $INIMGFILE.$informatext --srcformat $informat \
+ --destfilename $REALIMGFILE.$outformatext --destformat $outformat 1>>$LOGFILE 2>&1
+ if (test $? -eq 0); then
+ echo "$k-DEFIN=$informat TRANSFER=$transfer STORAGE=$storage DEFOUT=$outformat OK"
+ log "---$k-DEFIN=$informat TRANSFER=$transfer STORAGE=$storage DEFOUT=$outformat OK"
+ else
+ echo "$k-DEFIN=$informat TRANSFER=$transfer STORAGE=$storage DEFOUT=$outformat FAILED"
+ log "---$k-DEFIN=$informat TRANSFER=$transfer STORAGE=$storage DEFOUT=$outformat FAILED"
+ #keep the file for futher analysis
+ mv $REALIMGFILE.$outformatext $FAILIMGFILE$k.$outformatext
+ fi
+ j=$(($j+1))
+ k=$(($k+1))
+ done
+ #deletes all mdd from collection
+ log "--deleting current image"
+ echo "$DELETEQUERY" > $QUERYFILE
+ if (test $DEBUG -ne 0); then
+ log "$SYSTEM_QUERY $SYSTEM_QUERY_ARGS --transformat $transfer -r $QUERYFILE"
+ fi
+ $SYSTEM_QUERY $SYSTEM_QUERY_ARGS --transformat $transfer -r $QUERYFILE 1>>$LOGFILE 2>&1
+ if ( test $? -ne 0 ); then
+ error "An Error occured please check the log file $LOGFILE"
+ fi
+ else
+ error "An Error occured please check the log file $LOGFILE"
+ fi
+ i=$(($i+1))
+done
+}
+
+echo "Conversion & Compression Test - Main Menu"
+
+opt="s"
+while ( test "$opt" != "e"); do
+ print_options
+ echo "Change settings/Start Test/Exit?\c"
+ read opt
+ if (test "$opt" = "E"); then
+ opt="e"
+ fi
+ if (test "$opt" = "e"); then
+ echo "Exiting ..."
+ exit 0
+ else
+ check_options $opt
+ fi
+done
+
diff --git a/rasodmg/test/test_db2blob.sqC b/rasodmg/test/test_db2blob.sqC
new file mode 100644
index 0000000..a77a168
--- /dev/null
+++ b/rasodmg/test/test_db2blob.sqC
@@ -0,0 +1,399 @@
+// -*-C++-*- (for Emacs)
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ * SOURCE: test_db2blob.cc
+ *
+ * MODULE: rasodmg
+ *
+ * PURPOSE:
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#ifdef LINUX
+#define __EXECUTABLE__
+#include "raslib/template_inst.hh"
+#endif
+
+#ifdef __VISUALC__
+#include <strstrea.h>
+#else
+#include <strstream.h>
+#endif
+
+#include <iostream.h>
+#include <fstream.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h> // for drand48()
+
+#include "rasodmg/marray.hh"
+#include "raslib/shhopt.h"
+
+#include <sys/time.h>
+
+#include "sql.h"
+
+// number of repetitions for each query
+unsigned long repeat = 20;
+
+static int printFlag = 0;
+
+EXEC SQL INCLUDE SQLCA;
+
+#define CHECKERR(CE_STR) if (check_error (CE_STR, &sqlca) != 0)
+
+// copied from DB2 example program
+int check_error (char eString[], struct sqlca *caPointer) {
+ char eBuffer[1024];
+ char sBuffer[1024];
+ short rc, Erc;
+
+ if (caPointer->sqlcode != 0) {
+ printf ("--- error report ---\n");
+ printf ("ERROR occured : %s.\nSQLCODE : %ld\n", eString,
+ caPointer->sqlcode);
+
+ /**********************\
+ * GET SQLSTATE MESSAGE *
+ \**********************/
+ rc = sqlogstt (sBuffer, 1024, 80, caPointer->sqlstate);
+
+ /******************************\
+ * GET ERROR MESSAGE API called *
+ \******************************/
+ Erc = sqlaintp (eBuffer, 1024, 80, caPointer);
+
+ /* return code is the length of the eBuffer string */
+ if (Erc > 0) printf ("%s", eBuffer);
+
+ if (caPointer->sqlcode < 0) {
+ if (rc == 0) {
+ printf ("\n%s", sBuffer);
+ }
+ printf ("--- end error report ---\n");
+ return 1;
+ } else {
+ /* errorCode is just a Warning message */
+ if (rc == 0) {
+ printf ("\n%s", sBuffer);
+ }
+ printf ("--- end error report ---\n");
+ printf ("WARNING - CONTINUING PROGRAM WITH WARNINGS!\n");
+ return 0;
+ } /* endif */
+ } /* endif */
+ return 0;
+}
+
+class BMTimer
+{
+public:
+ /// constructor, initializes members
+ inline BMTimer();
+
+ inline void start();
+ inline void stop();
+
+private:
+ /// reference parameter for gettimeofday().
+ timeval acttime;
+ // reference parameter for gettimeofday, not used.
+ static struct timezone dummy;
+ /// used to calculate time spent in function.
+ static long oldsec;
+ /// used to calculate time spent in function.
+ static long oldusec;
+};
+
+struct timezone BMTimer::dummy;
+long BMTimer::oldsec;
+long BMTimer::oldusec;
+
+inline
+BMTimer::BMTimer()
+{
+ oldsec = 0;
+ oldusec = 0;
+}
+
+inline void
+BMTimer::start()
+{
+ gettimeofday(&acttime, &dummy);
+}
+
+inline void
+BMTimer::stop()
+{
+ oldsec = acttime.tv_sec;
+ oldusec = acttime.tv_usec;
+ gettimeofday(&acttime, &dummy);
+ cout << (acttime.tv_sec-oldsec)*1000000 + acttime.tv_usec
+ - oldusec << "us";
+}
+
+BMTimer myTimer;
+
+r_Marray<char>*
+blobRead(r_Minterval& sd)
+{
+ EXEC SQL BEGIN DECLARE SECTION;
+ long beginLoc;
+ long endLoc;
+ SQL TYPE IS BLOB_LOCATOR tomoLoc;
+ short tomo_ind;
+ // buf will be a structure with a char[] element called data and
+ // an unsigned long called length
+ SQL TYPE IS BLOB(256) blobBuf;
+ EXEC SQL END DECLARE SECTION;
+
+ int i,j;
+ // storing result
+ r_Marray<char>* result = new r_Marray<char>(sd);
+ char* resBuf = result->get_array();
+
+ EXEC SQL CONNECT TO sample;
+
+ myTimer.start();
+
+ EXEC SQL DECLARE curs1 CURSOR FOR
+ SELECT blob_col
+ FROM tomo_blob;
+
+ EXEC SQL OPEN curs1;
+
+ EXEC SQL FETCH curs1 INTO :tomoLoc :tomo_ind;
+ if (SQLCODE != 0) {
+ cout << "FETCH curs1: " << SQLCODE << endl;
+ }
+
+ if(tomo_ind < 0)
+ cout << "No BLOB there!" << endl;
+
+ // iterating through the Minterval
+ for(i=sd[0].low(); i<=sd[0].high(); i++) {
+ for(j=sd[1].low(); j<=sd[1].high(); j++) {
+ beginLoc = sd[2].low() + j*256 + i*256*256;
+ endLoc = sd[2].high() + j*256 + i*256*256;
+ unsigned long rowSize = endLoc - beginLoc + 1;
+ EXEC SQL VALUES (SUBSTR( :tomoLoc, :beginLoc, :endLoc - :beginLoc + 1))
+ INTO :blobBuf;
+ memcpy(resBuf, blobBuf.data, rowSize);
+ resBuf += rowSize;
+ }
+ }
+
+ EXEC SQL CLOSE curs1;
+
+ myTimer.stop();
+
+ EXEC SQL CONNECT RESET;
+
+ return result;
+}
+
+r_Marray<char>*
+blob1DRead(float sel)
+{
+ EXEC SQL BEGIN DECLARE SECTION;
+ long beginLoc2;
+ long endLoc2;
+ SQL TYPE IS BLOB_LOCATOR tomoLoc2;
+ short tomo_ind2;
+ // buf will be a structure with a char[] element called data and
+ // an unsigned long called length
+ SQL TYPE IS BLOB(4000000) blobBuf2;
+ EXEC SQL END DECLARE SECTION;
+
+ int i,j;
+ // storing result
+ r_Minterval* sd_res;
+ sd_res = new r_Minterval("[0:255,0:255,0:153]");
+ r_Marray<char>* result = new r_Marray<char>(*sd_res);
+ char* resBuf = result->get_array();
+
+ EXEC SQL CONNECT TO sample;
+
+ EXEC SQL DECLARE curs2 CURSOR FOR
+ SELECT blob_col
+ FROM tomo_blob;
+
+ EXEC SQL OPEN curs2;
+
+ EXEC SQL FETCH curs2 INTO :tomoLoc2 :tomo_ind2;
+ if (SQLCODE != 0) {
+ cout << "FETCH curs2: " << SQLCODE << endl;
+ }
+ if(tomo_ind2 < 0)
+ cout << "No BLOB there!" << endl;
+
+ unsigned long rowSize = (int)(sel/100 * 10092544);
+ beginLoc2 = (int)(drand48() * (10092544 - rowSize));
+ endLoc2 = beginLoc2 + rowSize;
+
+ EXEC SQL VALUES (SUBSTR( :tomoLoc2, :beginLoc2, :endLoc2 - :beginLoc2 + 1))
+ INTO :blobBuf2;
+
+ memcpy(resBuf, blobBuf2.data, rowSize);
+ resBuf += rowSize;
+
+ EXEC SQL CLOSE curs2;
+
+ EXEC SQL CONNECT RESET;
+
+ delete sd_res;
+ return result;
+}
+
+void
+blobInsert( char *fileName )
+{
+ EXEC SQL BEGIN DECLARE SECTION;
+ SQL TYPE IS BLOB_FILE tomoFile;
+ EXEC SQL END DECLARE SECTION;
+
+ EXEC SQL CONNECT TO sample;
+ CHECKERR ("CONNECT TO") exit(1);
+
+ strcpy(tomoFile.name, fileName);
+ tomoFile.name_length = strlen(fileName);
+ tomoFile.file_options = SQL_FILE_READ;
+
+ EXEC SQL INSERT INTO tomo_blob
+ VALUES(:tomoFile);
+ CHECKERR ("INSERT INTO") exit(1);
+
+ EXEC SQL CONNECT RESET;
+}
+
+void
+blob1DExec(int queryNum, float sel)
+{
+ int i;
+ // storing the result
+ r_Marray<char>* res;
+
+ for(i=1; i<=repeat; i++) {
+ myTimer.start();
+ res = blob1DRead(sel);
+ cout << queryNum << "." << i << ": ";
+ myTimer.stop();
+ cout << endl;
+ delete res;
+ }
+
+ // optionally printing the result
+ if( printFlag )
+ ((r_GMarray*)(res))->r_GMarray::print_status();
+}
+
+void
+execQuery(char* myRectStr, int queryNum, int i)
+{
+ // storing the result
+ r_Marray<char>* res;
+ // the query rectangle
+ r_Minterval* sd_res;
+
+ sd_res = new r_Minterval(myRectStr);
+
+ cout << queryNum << "." << i << ": ";
+ res = blobRead(*sd_res);
+ cout << endl;
+ delete res;
+
+ delete sd_res;
+
+ // optionally printing the result
+ if( printFlag )
+ ((r_GMarray*)(res))->r_GMarray::print_status();
+}
+
+static void
+printUsage(void)
+{
+ cout << "Usage: test_db2blob [options] aFileName"
+ << endl;
+ cout << " aFileName Name of file with query rectangles "
+ << endl
+ << " or BLOB data when inserting." << endl;
+ cout << " -h, --help Print this message and exit." << endl;
+ cout << " -i, --insert Insert BLOB instead of querying"
+ << endl;
+ cout << " -p, --print Print data queried."
+ << endl;
+ exit(0);
+}
+
+int
+main( int argc, char** argv )
+{
+ int iFlag = 0;
+ int queryNum = 0;
+ char fName[1024] = "";
+ float selArray[] = { 0.5, 1, 2, 5, 10, 20, 50, 100 };
+
+ optStruct testDB2BLOBOpt[] = {
+ /* short long type var/func special */
+ { 'h', "help", OPT_FLAG, printUsage, OPT_CALLFUNC },
+ { 'i', "insert", OPT_FLAG, &iFlag, 0 },
+ { 'p', "print", OPT_FLAG, &printFlag, 0 },
+ { 0, 0, OPT_END, 0, 0 } /* no more options */
+ };
+
+ /* parse all options */
+ optParseOptions(&argc, argv, testDB2BLOBOpt, 0);
+
+ strcpy(fName, argv[argc-1]);
+
+ if( iFlag ) {
+ blobInsert( fName );
+ exit(1);
+ }
+
+ ifstream fileStream( fName );
+ char buf[256];
+ char dummy;
+
+ int j = 0;
+ while( fileStream.get( buf, 255, '\n' ) ) {
+ fileStream.get(dummy);
+ if((buf[0] == '/' && buf[1] == '/') || buf[0] == 0) {
+ queryNum++;
+ cout << "Query " << queryNum << ": " << buf << endl;
+ j=0;
+ } else if(buf[0] != 0) {
+ execQuery(buf, queryNum, ++j);
+ }
+ }
+
+// // Selectivity 50% and 100% does not work
+// for(int i=0; i<6; i++) {
+// cout << "BLOB selectivity " << selArray[i] << endl;
+// blob1DExec(++queryNum, selArray[i]);
+// }
+}
diff --git a/rasodmg/test/test_dirtiling.cc b/rasodmg/test/test_dirtiling.cc
new file mode 100644
index 0000000..3cc57dc
--- /dev/null
+++ b/rasodmg/test/test_dirtiling.cc
@@ -0,0 +1,93 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_dirtiling.cc
+ *
+ * MODULE: rasodmg
+ *
+ * PURPOSE: test class r_Dir_Tiling.
+ *
+ * COMMENTS:
+ * None
+*/
+
+
+#include <iostream>
+#include <stdio.h>
+#include "rasodmg/marray.hh"
+#include "rasodmg/tiling.hh"
+#include "rasodmg/dirtiling.hh"
+#include "rasodmg/dirdecompose.hh"
+#include "raslib/dlist.hh"
+
+int main(int argc, char* argv[])
+{
+ int tilesize = 10000;
+
+ // Get tile size
+ if (argc == 2)
+ tilesize = atoi(argv[1]);
+
+ // Create a domain decomposition
+
+ r_Dir_Decompose decomp[2];
+ decomp[0] << 0 << 50 << 200 << 600 << 700 << 950 << 999;
+
+ r_Dir_Tiling tiling(2, decomp, tilesize);
+ tiling.print_status(cout);
+
+ cout << endl << "----- Domain decomposition -----" << endl;
+
+ // Create a domain and an image
+
+ r_Minterval domain(2);
+ domain << r_Sinterval(0L, 999L) << r_Sinterval(0L, 99L);
+
+ r_Marray<char> image(domain);
+
+ // Compute tiles
+
+ DList<r_Minterval>* tiles = tiling.compute_tiles(domain, sizeof(char));
+
+ // Output the information
+
+ cout << "Domain: " << domain << endl << endl;
+ cout << "Tiles: " << endl;
+
+ DListIterator<r_Minterval> it = tiles->create_iterator();
+ for (; it.not_done(); it++)
+ {
+ r_Minterval inter = *it;
+ cout << " " << inter << endl;
+ }
+
+ delete tiles;
+}
+
+
+
+
+
+
+
+
diff --git a/rasodmg/test/test_fastscale.cc b/rasodmg/test/test_fastscale.cc
new file mode 100644
index 0000000..1911855
--- /dev/null
+++ b/rasodmg/test/test_fastscale.cc
@@ -0,0 +1,293 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_fastscale.cc
+ *
+ * MODULE: rasodmg
+ *
+ * COMMENTS:
+ * None
+*/
+
+
+#include <iostream>
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#include "raslib/template_inst.hh"
+#endif
+
+#include "rasodmg/fastscale.hh"
+#include "rasodmg/transaction.hh"
+#include "rasodmg/database.hh"
+#include "rasodmg/marray.hh"
+#include "raslib/odmgtypes.hh"
+
+
+
+template class r_Fast_Scale<r_Char>;
+
+template<class T>
+void fast_scale_resample_array(T *dest, const T *src, const r_Minterval &destIv, const r_Minterval &srcIv, const r_Minterval &srcIter, unsigned int type_len, unsigned int length);
+
+static void test_resample(unsigned int extent, unsigned int shrink)
+{
+ r_Minterval siv(2);
+ r_Minterval div(2);
+ unsigned int shrunken;
+ r_Char *srcData;
+ r_Char *destData;
+
+ cout << "Test resampling, size " << extent
+ << ", shrink factor " << shrink << endl;
+
+ shrunken = (extent / shrink);
+ if (shrunken * shrink < extent) shrunken++;
+
+ siv << r_Sinterval((r_Range)0, (r_Range)extent-1)
+ << r_Sinterval((r_Range)0, (r_Range)extent-1);
+
+ div << r_Sinterval((r_Range)0, (r_Range)shrunken-1)
+ << r_Sinterval((r_Range)0, (r_Range)shrunken-1);
+
+ srcData = new r_Char[extent*extent];
+ destData = new r_Char[shrunken*shrunken];
+
+ unsigned int i, j;
+
+ for (i=0; i<extent; i++)
+ for (j=0; j<extent; j++)
+ srcData[i*extent + j] = (r_Char)(i+j);
+
+ cout << "go... " << flush;
+ fast_scale_resample_array(destData, srcData, div, siv, siv, 1, shrink);
+ cout << "OK... " << flush;
+
+ delete [] srcData;
+ delete [] destData;
+
+ cout << "done." << endl;
+}
+
+
+int main(int argc, char *argv[])
+{
+ char servername[256] = "sunwibas0";
+ char collname[256] = "nopscale";
+ char database[256] = "NorbertBase";
+ r_Range imgSize = 1000;
+ r_Range updtSize = 100;
+ int dostuff=3;
+
+#if 0
+ // test the actual resampling code...
+ unsigned int shrink;
+ for (shrink=2; shrink<50; shrink++)
+ {
+ test_resample(1000, shrink);
+ }
+ exit(0);
+#endif
+
+ int i;
+
+ i = 1;
+ while (i < argc)
+ {
+ if (argv[i][0] == '-')
+ {
+ switch (argv[i][1])
+ {
+ case 's':
+ strcpy(servername, argv[++i]);
+ break;
+ case 'd':
+ strcpy(database, argv[++i]);
+ break;
+ case 'c':
+ strcpy(collname, argv[++i]);
+ break;
+ case 'i':
+ imgSize = atoi(argv[++i]);
+ break;
+ case 'n': // no create
+ dostuff &= ~1;
+ break;
+ case 'N': // no update
+ dostuff &= ~2;
+ break;
+ case 'h':
+ cout << argv[0] << " [-s servername -d dbname -c collname -i imgsize -n -N -h]" << endl;
+ exit(0);
+ default:
+ cerr << "Bad switch " << argv[i] << endl;
+ exit(-1);
+ }
+ }
+ else
+ {
+ cerr << "unknown option " << argv[i] << endl;
+ exit(-1);
+ }
+ i++;
+ }
+
+ r_Database db;
+ r_Transaction ta;
+ r_Minterval tileDom(2);
+ r_Domain_Storage_Layout *myStorageLayout;
+ r_Aligned_Tiling *myAlignedTiling;
+ tileDom << r_Sinterval((r_Range)0, (r_Range)100)
+ << r_Sinterval((r_Range)0, (r_Range)100);
+ myAlignedTiling = new r_Aligned_Tiling( tileDom, tileDom.cell_count() );
+ myStorageLayout = new r_Domain_Storage_Layout( tileDom, myAlignedTiling );
+ r_Minterval imgDom(2);
+ imgDom << r_Sinterval((r_Range)0, (r_Range)imgSize)
+ << r_Sinterval((r_Range)0, (r_Range)imgSize);
+
+ r_Fast_Scale<r_Char>* myScale;
+
+ cout << "Server = " << servername << ", Database = " << database << ", collection = " << collname << ", Image size = " << imgSize << endl;
+
+ try
+ {
+ db.set_servername(servername);
+ db.open(database);
+ }
+ catch(r_Error &err)
+ {
+ cerr << err.what() << endl;
+ exit(-1);
+ }
+
+ if ((dostuff & 1) != 0)
+ {
+ try
+ {
+ ta.begin();
+ myScale = new r_Fast_Scale<r_Char>(collname, imgDom, "GreySet", "GreyImage", myStorageLayout);
+ ta.commit();
+ delete myScale;
+ cout << "created OK" << endl;
+ }
+ catch(r_Error &err)
+ {
+ ta.abort();
+ cerr << err.what() << endl;
+ }
+ }
+
+ delete myStorageLayout;
+
+ // read a small object for identification
+ try
+ {
+ ta.begin(r_Transaction::read_only);
+ r_Ref<r_GMarray> mddObj = r_Fast_Base_Scale::get_minimal_array(collname);
+ ta.commit();
+ cout << "Object read: ";
+ mddObj->print_status();
+ mddObj.destroy();
+ }
+ catch(r_Error &err)
+ {
+ ta.abort();
+ cerr << err.what() << endl;
+ }
+
+ try
+ {
+ ta.begin(r_Transaction::read_only);
+ myScale = new r_Fast_Scale<r_Char>(collname);
+ cout << "Read domain: " << myScale->get_full_domain() << endl;
+ ta.commit();
+ cout << "domain OK" << endl;
+ }
+ catch(r_Error &err)
+ {
+ ta.abort();
+ cerr << err.what() << endl;
+ }
+
+ if ((dostuff & 2) != 0)
+ {
+ // update a diagonal strip
+ for (i=0; i<=imgSize-updtSize; i+=updtSize/2)
+ {
+ try
+ {
+ r_Minterval uiv(2);
+
+ uiv << r_Sinterval((r_Range)i, (r_Range)i+updtSize-1)
+ << r_Sinterval((r_Range)i, (r_Range)i+updtSize-1);
+
+ cout << "Update " << uiv << endl;
+ r_Marray<r_Char> *updtArray = new ("GreyImage") r_Marray<r_Char>(uiv);
+ memset(updtArray->get_array(), 255, updtSize * updtSize);
+ cout << "Start insert... " << flush;
+ ta.begin();
+ myScale->insert_array(*updtArray);
+ ta.commit();
+ delete updtArray;
+ cout << "OK" << endl;
+ }
+ catch (r_Error &err)
+ {
+ ta.abort();
+ cerr << err.what();
+ }
+ }
+ }
+
+ double scaleFactor;
+
+ for (scaleFactor=1.0; scaleFactor>1e-6; scaleFactor-=0.05)
+ {
+ try
+ {
+ r_Minterval scaledIv;
+
+ if (myScale->get_scaled_domain(myScale->get_full_domain(), scaledIv, scaleFactor) != 0)
+ {
+ cout << "Read " << scaledIv << ", scaled " << scaleFactor << "..." << flush;
+ ta.begin(r_Transaction::read_only);
+ r_Ref<r_Marray<r_Char> > result;
+ result = myScale->get_scaled_image(scaledIv, scaleFactor);
+ ta.commit();
+ cout << "OK" << endl;
+ result.destroy();
+ }
+ }
+ catch(r_Error &err)
+ {
+ ta.abort();
+ cerr << err.what() << endl;
+ }
+ }
+
+ delete myScale;
+
+ db.close();
+
+ return 0;
+}
diff --git a/rasodmg/test/test_gmarray.cc b/rasodmg/test/test_gmarray.cc
new file mode 100644
index 0000000..dbd95a4
--- /dev/null
+++ b/rasodmg/test/test_gmarray.cc
@@ -0,0 +1,229 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_marray.cc
+ *
+ * MODULE: raslib
+ *
+ * COMMENTS:
+ * None
+*/
+
+#include <iostream>
+
+#include "rasodmg/marray.hh"
+
+#include "raslib/minterval.hh"
+#include "raslib/sinterval.hh"
+#include "raslib/point.hh"
+#include "raslib/error.hh"
+#include "raslib/type.hh"
+#include "raslib/basetype.hh"
+#include "raslib/attribute.hh"
+#include "raslib/structuretype.hh"
+#include "raslib/primitivetype.hh"
+
+
+struct myStructType {
+ char red;
+ char green;
+ short east;
+ float middle;
+};
+
+struct myStructType3 {
+ double feature_1 ;
+ double feature_2 ;
+ double feature_3 ;
+};
+
+struct myStructTypeCom {
+ long greyvalue;
+ long greyvalue2;
+ myStructType3 features;
+};
+
+static int INIT = 0;
+static float FINIT = 0;
+static char CINIT = 0;
+static double DINIT = 0;
+static long LINIT = 0;
+
+int initFunction( const r_Point& /*pt*/ )
+{
+ /*
+ int value=0;
+
+ for( int i=0; i< pt.dimension(); i++ )
+ value += pt[i];
+
+ return value;
+ */
+ return 3*(INIT++)/2;
+}
+
+float initFunctionFloat( const r_Point& /*pt*/ )
+{
+ return 3*(FINIT++)/2;
+}
+
+
+char initFunctionChar( const r_Point& /*pt*/ )
+{
+ return 3*(CINIT++)/2;
+}
+
+double initFunctionDouble( const r_Point& /*pt*/ )
+{
+ return 3*(DINIT++)/2;
+}
+
+long initFunctionLong( const r_Point& /*pt*/ )
+{
+ return (LINIT++);
+}
+
+
+myStructType initFunctionStruct( const r_Point& /*pt*/ )
+{
+ myStructType myStruct;
+
+ myStruct.red = 3;
+ myStruct.green = 4;
+ myStruct.east = 123;
+ myStruct.middle = 7.4;
+
+ return myStruct;
+}
+
+
+myStructType3 initFunctionStruct3( const r_Point& pt)
+{
+ myStructType3 myStruct;
+
+ myStruct.feature_1 = 0.5* initFunctionDouble( pt );
+ DINIT--;
+ myStruct.feature_2 = 3* initFunctionDouble( pt );
+ DINIT--;
+ myStruct.feature_3 = initFunctionDouble( pt );
+
+ return myStruct;
+}
+
+
+myStructTypeCom initFunctionStructCom( const r_Point& pt)
+{
+ myStructTypeCom myStructCom;
+
+ myStructCom.greyvalue = initFunctionLong( pt );
+ LINIT--;
+ myStructCom.greyvalue2 = 3*initFunctionLong( pt );
+
+ //myStructCom.features = initFunctionStruct3( pt );
+
+ myStructCom.features.feature_1 = 0.5* initFunctionDouble( pt );
+ DINIT--;
+ myStructCom.features.feature_2 = 3* initFunctionDouble( pt );
+ DINIT--;
+ myStructCom.features.feature_3 = initFunctionDouble( pt );
+
+
+ return myStructCom;
+}
+
+
+
+int main()
+{
+ cout << endl << endl;
+ cout << "Marray Examples" << endl;
+ cout << "===============" << endl << endl;
+
+ cout << "Initialization of Marray<int, [3:5,6:8]> with init function:" << endl;
+ r_Marray<int> a( r_Minterval("[3:5,6:8]"), &initFunction );
+ a.set_type_structure("marray<long>");
+ cout << "OK" << endl;
+ a.print_status( cout );
+
+
+ cout << "Initialization of Marray<float, [3:5,6:8]> with init function float:" << endl;
+ r_Marray<float> b( r_Minterval("[3:5,6:8]"), &initFunctionFloat );
+ b.set_type_structure("marray<float>");
+ cout << "OK" << endl;
+ b.print_status( cout );
+
+
+ cout << "Initialization of Marray<char, [3:5,6:8]> with init function char:" << endl;
+ r_Marray<char> c( r_Minterval("[3:5,6:8]"), &initFunctionChar );
+ c.set_type_structure("marray<char>");
+ cout << "OK" << endl;
+ c.print_status( cout );
+
+
+ cout << "Initialization of Marray<double, [3:5,6:8]> with init function double:" << endl;
+ r_Marray<double> d( r_Minterval("[3:5,6:8]"), &initFunctionDouble );
+ d.set_type_structure("marray<double>");
+ cout << "OK" << endl;
+ d.print_status( cout );
+
+ FINIT = 0;
+ CINIT = 0;
+ cout << "Initialization of Marray<struct{char, char, short, float}, [3:5,6:8]> with init function struct:" << endl;
+ r_Marray<myStructType> st( r_Minterval("[3:5,6:8]"), &initFunctionStruct );
+ st.set_type_structure("marray<struct{char,char,short,float}>");
+ cout << "OK" << endl;
+ st.print_status( cout );
+
+ DINIT = 0;
+ cout << "Initialization of Marray<struct{double, double, double}, [3:5,6:8]> with init function struct3:" << endl;
+ r_Marray<myStructType3> st3( r_Minterval("[3:5,6:8]"), &initFunctionStruct3 );
+ st3.set_type_structure("marray<struct{double,double,double}>");
+ cout << "OK" << endl;
+ st3.print_status( cout );
+
+ DINIT = 0;
+ cout << "Initialization of Marray<struct{ long, long, struct{double, double, double} }, [3:5,6:8]> with init function structCom:" << endl;
+ r_Marray<myStructTypeCom> stCom( r_Minterval("[3:5,6:8]"), &initFunctionStructCom );
+ stCom.set_type_structure("marray<struct{long,long,struct{double,double,double}}>");
+ cout << "OK" << endl;
+ stCom.print_status( cout );
+ cout << endl;
+
+ // print single cell
+ r_GMarray& gstCom = (r_GMarray&)stCom;
+
+ const r_Base_Type& baseType = *(gstCom.get_base_type_schema());
+ cout << "gmarray_stCom[4,6] = " << flush;
+ baseType.print_value( gstCom[r_Point(4,6)] );
+ cout << endl;
+
+ cout << "access second double of inner struct: " << flush;
+ const r_Structure_Type& outerStruct = (const r_Structure_Type&)baseType;
+ // const r_Attribute& innerAttribute = outerStruct[2];
+ // const r_Structure_Type& innerStruct = (const r_Structure_Type&)innerAttribute.type_of();
+ // const r_Attribute& doubleAttribute = innerStruct[1];
+ // cout << doubleAttribute.get_double( gstCom[r_Point(4,6)] ) << endl;
+ cout << outerStruct[2][1].get_double( gstCom[r_Point(4,6)] ) << endl;
+
+ return 0;
+}
diff --git a/rasodmg/test/test_insert.cc b/rasodmg/test/test_insert.cc
new file mode 100644
index 0000000..dea9147
--- /dev/null
+++ b/rasodmg/test/test_insert.cc
@@ -0,0 +1,235 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_insert.cc
+ *
+ * MODULE: rasodmg
+ *
+ * COMMENTS:
+ * None
+*/
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#include "raslib/template_inst.hh"
+#endif
+
+#include <iostream>
+#include <string.h>
+
+#ifdef __VISUALC__
+ #define __EXECUTABLE__
+#endif
+
+#include "include/basictypes.hh"
+
+#ifdef __VISUALC__
+ #undef __EXECUTABLE__
+#endif
+
+static int INIT = 0;
+
+r_ULong initWithCounter( const r_Point& /*pt*/ )
+{
+ return INIT++;
+}
+
+
+r_ULong initWithCrossfoot( const r_Point& pt )
+{
+ r_ULong value=0;
+
+ for( r_Dimension i=0; i< pt.dimension(); i++ )
+ value += pt[i];
+
+ return value;
+}
+
+
+r_ULong initWithCoordinates( const r_Point& pt )
+{
+ r_ULong value=0;
+ int factor=1;
+
+ for( int i=pt.dimension()-1; i >= 0; i-- )
+ {
+ value += factor * pt[i];
+ factor *= 100;
+ }
+
+ return value;
+}
+
+
+
+int checkArguments( int argc, char** argv, const char* searchText, int& optionValueIndex )
+{
+ int found = 0;
+ int i=1;
+
+ while( !found && i<argc )
+ found = !strcmp( searchText, argv[i++] );
+
+ if( found && i<argc && !strchr(argv[i],'-') )
+ optionValueIndex = i;
+ else
+ optionValueIndex = 0;
+
+ return found;
+}
+
+
+
+int main( int argc, char** argv )
+{
+ char serverName[255];
+ char baseName[255];
+ char collName[255];
+ int optionValueIndex;
+
+ if( argc < 4 || checkArguments( argc, argv, "-h", optionValueIndex ) )
+ {
+ cout << "Usage: test_insert server_name base_name collection_name [options]" << endl << endl;
+ cout << "Options: -h ... this help" << endl;
+ // cout << " -nooutput ... no output of MDD content" << endl;
+ // cout << " -hex ... output in hex" << endl;
+ cout << endl;
+ return 0;
+ }
+
+ strcpy( serverName, argv[1] );
+ strcpy( baseName, argv[2] );
+ strcpy( collName, argv[3] );
+
+ cout << endl << endl;
+ cout << "ODMG conformant insertion of Marrays" << endl;
+ cout << "====================================" << endl << endl;
+
+ r_Database db;
+ r_Transaction ta;
+ r_Ref< r_Set< r_Ref< r_Marray<r_ULong> > > > image_set;
+ r_Ref< r_Marray<r_ULong> > image1, image2, image3, image4,
+ image5, image6, transImage;
+ r_Minterval domain, domain2;
+
+ domain = r_Minterval(2) << r_Sinterval( 0, 10 ) << r_Sinterval( 0, 10 );
+
+ db.set_servername( serverName );
+
+ try
+ {
+ cout << "Opening Database " << baseName << " on " << serverName << "... " << flush;
+ db.open( baseName );
+ cout << "OK" << endl;
+
+ cout << "Starting Transaction ... " << flush;
+ ta.begin();
+ cout << "OK" << endl;
+
+ cout << "Opening the set ... " << flush;
+
+ try{
+ image_set = db.lookup_object( collName );
+ }
+ catch( r_Error& /*obj*/ )
+ {
+ cout << "FAILED" << endl;
+ // cout << obj.what() << endl;
+
+ //
+ // set doesn't exist -> create the set
+ //
+
+ cout << "Create the set ... " << flush;
+
+ // create the set
+ image_set = new( &db, "ULongSet" ) r_Set< r_Ref< r_Marray<r_ULong> > >;
+
+ // create a name for the persistent set in order to be able to look it up again
+ db.set_object_name( *image_set, collName );
+ }
+
+ cout << "OK" << endl;
+
+ cout << "Create image1 with constant 0 ... " << flush;
+ image1 = new( &db, "ULongImage" ) ULongImage( domain, (r_ULong)0 );
+ cout << "OK" << endl;
+
+ cout << "Create image2 with copy constructor from image1 ... " << flush;
+ image2 = new( &db, "ULongImage" ) ULongImage( (const ULongImage&) *image1 );
+ cout << "OK" << endl;
+
+ cout << "Create transient image with constant 1 ... " << flush;
+ transImage = new ULongImage( domain, 1ul );
+ cout << "OK" << endl;
+
+ cout << "Create image3 with copy constructor from transient image ... " << flush;
+ image3 = new( &db, "ULongImage" ) ULongImage( (const ULongImage&) *transImage );
+ cout << "OK" << endl;
+
+ transImage.destroy();
+
+ // image2->initialize_oid( db.get_new_oid(1) );
+
+ cout << "Create image4 with cross foot ... " << flush;
+ image4 = new( &db, "ULongImage" ) r_Marray<r_ULong>( domain, &initWithCrossfoot );
+ cout << "OK" << endl;
+
+ cout << "Create image5 with counter ... " << flush;
+ image5 = new( &db, "ULongImage" ) r_Marray<r_ULong>( domain, &initWithCounter );
+ cout << "OK" << endl;
+
+ cout << "Create image6 with coordinates ... " << flush;
+ image6 = new( &db, "ULongImage" ) r_Marray<r_ULong>( domain, &initWithCoordinates );
+ cout << "OK" << endl;
+
+ cout << "Insert images into the set " << collName << " ... " << flush;
+
+ // insert the images
+ image_set->insert_element( image1 );
+ image_set->insert_element( image2 );
+ image_set->insert_element( image3 );
+ image_set->insert_element( image4 );
+ image_set->insert_element( image5 );
+ image_set->insert_element( image6 );
+
+ cout << "OK" << endl;
+
+ cout << "Commiting Transaction ... " << flush;
+ ta.commit();
+ cout << "OK" << endl;
+
+ cout << "Closing Database ... " << flush;
+ db.close();
+ cout << "OK" << endl;
+ }
+ catch( r_Error& errorObj )
+ {
+ ta.abort();
+ db.close();
+ cerr << "Error " << errorObj.get_errorno() << " : " << errorObj.what() << endl;
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/rasodmg/test/test_insert3.cc b/rasodmg/test/test_insert3.cc
new file mode 100644
index 0000000..8d620e7
--- /dev/null
+++ b/rasodmg/test/test_insert3.cc
@@ -0,0 +1,843 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_insert3.cc
+ *
+ * MODULE: rasodmg
+ *
+ * COMMENTS:
+ * None
+ */
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#include "raslib/template_inst.hh"
+#endif
+
+#ifdef __VISUALC__
+#include <strstrea.h>
+#else
+#include <strstream>
+#endif
+
+#include <iostream>
+#include <iomanip>
+#include <string>
+#include <fstream>
+
+#include <math.h>
+
+#ifdef __VISUALC__
+ #define __EXECUTABLE__
+#endif
+#include "include/basictypes.hh"
+#include "raslib/type.hh"
+
+#include "rasodmg/storagelayout.hh"
+
+#include "rasodmg/alignedtiling.hh"
+#include "rasodmg/dirtiling.hh"
+#include "rasodmg/dirdecompose.hh"
+#include "rasodmg/interesttiling.hh"
+#include "rasodmg/stattiling.hh"
+
+
+const int MAX_STR_LEN = 255;
+
+static int INIT = 0;
+static r_Long minNo = 0;
+static r_Long maxNo = 0;
+static ifstream fileStream;
+
+using namespace std;
+
+r_ULong initWithCounter( const r_Point& /*pt*/ )
+{
+ return INIT++;
+}
+
+
+r_Char initWithCounterChar( const r_Point& /*pt*/ )
+{
+ return (r_Char) INIT++;
+}
+
+
+r_UShort initWithCounterUShort( const r_Point& /*pt*/ )
+{
+ return (r_UShort) INIT++;
+}
+
+
+
+r_ULong initWithCrossfoot( const r_Point& pt )
+{
+ r_ULong value=0;
+
+ for( r_Dimension i=0; i< pt.dimension(); i++ )
+ value += (r_ULong)pt[i];
+
+ return value;
+}
+
+
+r_ULong initWithCoordinates( const r_Point& pt )
+{
+ r_ULong value=0;
+ r_ULong factor=1;
+
+ for( int i=pt.dimension()-1; i >= 0; i-- )
+ {
+ value += (r_ULong)(factor * pt[i]);
+ factor *= 100;
+ }
+
+ return value;
+}
+
+
+
+r_Char initWithCurve( const r_Point& pt )
+{
+ r_ULong value=0;
+
+ for( r_Dimension i=0; i < pt.dimension(); i++ )
+ value += (r_Char)( 255* sin( .25 * (float)pt[i] ) );
+
+ return (r_Char)value;
+}
+
+
+
+r_ULong initWithColorCube( const r_Point& pt )
+{
+ r_ULong value=0;
+
+ if( pt.dimension() == 3 )
+ value = ((r_ULong)(pt[0]) << 16) + ((r_ULong)(pt[1]) << 8) + (r_ULong)(pt[2]);
+
+ return value;
+}
+
+
+r_Char initWithRandomChar( const r_Point& /*pt*/ )
+{
+ // rand creates numbers between 0 and 32767
+ r_ULong number = rand();
+ double factor = (maxNo - minNo)/32767.0;
+
+ return (r_Char)(minNo + (number * factor));
+}
+
+r_ULong initWithRandomULong( const r_Point& /*pt*/ )
+{
+ // rand creates numbers between 0 and 32767
+ r_ULong number = rand();
+ double factor = (maxNo - minNo)/32767.0;
+
+ return (r_ULong)(minNo + (number * factor));
+}
+
+
+r_Char initFromFile( const r_Point& /*pt*/ )
+{
+ char ch;
+
+ if( fileStream.get(ch) )
+ return ch;
+ else
+ return 0;
+}
+
+#ifdef QUERY_TEST
+r_Ref< r_Marray<r_ULong> > readFile( r_Database& db )
+{
+ r_Ref< r_Marray<r_ULong> > image;
+ r_Minterval domain(3);
+ long dx, dy, dz, depth, cx, cy, cz;
+ int i;
+
+ ifstream fileStream( "hw8.full.vol" );
+ if( !fileStream )
+ {
+ std::cout << "Error: File not found." << std::endl;
+ exit(-1);
+ }
+
+ // read the first 16 bytes
+ char charDummy;
+ for( i=0; i<16; i++ )
+ fileStream >> charDummy;
+
+ dx = 256;
+ dy = 256;
+ dz = 20;
+ depth = 8;
+
+ domain << r_Sinterval( (r_Long)0, (r_Long)(dx-1) ) << r_Sinterval( (r_Long)0, (r_Long)(dy-1) ) << r_Sinterval( (r_Long)0, (r_Long)(dz-1) );
+
+ std::cout << domain << "... "<< std::flush;
+
+ image = new( &db ) r_Marray<r_ULong>( domain );
+
+ r_ULong* dataPtr = (r_ULong*)image->get_array();
+
+ r_Point pt(3);
+
+ // for( i=0; i<dx*dy*(221-dz); i++ )
+ // fileStream >> charDummy;
+
+ for( cz = 0; cz < dz; cz++ )
+ {
+ pt[2] = cz;
+ for( cy = 0; cy < dy; cy++ )
+ {
+ pt[1] = cy;
+ for( cx = 0; cx < dx; cx++ )
+ {
+ unsigned char ch;
+ fileStream.get(ch);
+
+ pt[0] = cx;
+ dataPtr[domain.cell_offset(pt)] = ((r_ULong)ch << 16) +
+ ((r_ULong)ch << 8) +
+ ((r_ULong)ch);
+ }
+ }
+ }
+
+ fileStream.close();
+
+ return image;
+}
+#endif
+
+
+void printColl( r_Ref< r_Set< r_Ref< r_GMarray > > >& image_set, int output, int hexOutput )
+{
+ std::cout << "Collection" << std::endl;
+ std::cout << " Oid...................: " << image_set->get_oid() << std::endl;
+ std::cout << " Type Name.............: " << image_set->get_object_name() << std::endl;
+ std::cout << " Type Structure........: "
+ << ( image_set->get_type_structure() ? image_set->get_type_structure() : "<nn>" ) << std::endl;
+ std::cout << " Type Schema...........: " << std::flush;
+ if( image_set->get_type_schema() )
+ image_set->get_type_schema()->print_status( std::cout );
+ else
+ std::cout << "<nn>" << std::flush;
+ std::cout << std::endl;
+ std::cout << " Number of entries.....: " << image_set->cardinality() << std::endl;
+ std::cout << " Element Type Schema...: " << std::flush;
+ if( image_set->get_element_type_schema() )
+ image_set->get_element_type_schema()->print_status( std::cout );
+ else
+ std::cout << "<nn>" << std::flush;
+ std::cout << std::endl;
+
+ r_Iterator< r_Ref< r_GMarray > > iter = image_set->create_iterator();
+
+ std::cout << std::endl;
+ for ( int i=1 ; iter.not_done(); iter++, i++ )
+ {
+ // do not dereference the object
+ std::cout << "Image " << i << " oid: " << (*iter).get_oid() << std::endl;
+
+ if( output )
+ {
+ (*iter)->print_status( std::cout, hexOutput );
+ std::cout << std::endl;
+ }
+ }
+ std::cout << std::endl;
+}
+
+
+
+int checkArguments( int argc, char** argv, const char* searchText, int& optionValueIndex )
+{
+ int found = 0;
+ int i=1;
+
+ while( !found && i<argc )
+ found = !strcmp( searchText, argv[i++] );
+
+ if( found && i<argc && (argv[i][0] != '-') )
+ optionValueIndex = i;
+ else
+ optionValueIndex = 0;
+
+ return found;
+}
+
+void printUsage(char* name){
+ std::cout << name << " v1.1 systemtest insert utility" << std::endl;
+ std::cout << "Description: Systemtest insert utility for creation and update of sets in RasDaMan" << std::endl;
+ std::cout << "Usage: " << name << " [options]" << std::endl << std::endl;
+ std::cout << "Options: -h ... this help" << std::endl;
+ std::cout << " -server <srvname> ... name of server.(mandatory)" << std::endl;
+ std::cout << " -port <nnnn> ... port of server.(default 7001)" << std::endl;
+ std::cout << " -base <dbname> ... name of database.(madatory)" << std::endl;
+ std::cout << " -setname <setname> ... name of collection.(madatory)" << std::endl;
+ std::cout << " -settype <typename> ... type name used for creation of a new set." << std::endl;
+ std::cout << " -mddtype <typename> ... type name used for creation of a new mdd object." << std::endl;
+ std::cout << " -user <usrname> ... user name.(default rasguest)" << std::endl;
+ std::cout << " -passwd <usrpasswd> ... user password.(default rasquest)" << std::endl;
+ std::cout << " -transferformat <format> ... transfer format.(default Array)" << std::endl;
+ std::cout << " -transferformatparams <formatparams> ... transfer format parameters.(default NULL)" << std::endl;
+ std::cout << " -storageformat <format> ... storage format.(default Array)" << std::endl;
+ std::cout << " -storageformatparams <formatparams> ... storage format parameters.(default NULL)" << std::endl;
+ std::cout << " -tiling <tiling> ... tiling strategy.(default SizeTiling)" << std::endl;
+ std::cout << " -tilingparams <tilingparams> ... tiling strategy params.(default 131072)" << std::endl;
+ std::cout << " -file <filename> ... file name used to read data from a file" << std::endl;
+ std::cout << " -testbed ... turn on output for testbed.default(default off)" << std::endl;
+ std::cout << std::endl << std::endl;
+
+ std::cout << "Report bugs to <support@active­knowledge.com>" << std::endl;
+}
+
+r_Tiling*
+getTilingScheme(r_Tiling_Scheme& tilingS, char* tilingP){
+ r_Tiling* retval=NULL;
+
+ try {
+ std::cout << " Creating tiling strategy ..." << std::flush;
+ switch(tilingS) {
+ case r_NoTiling:
+ retval = new r_No_Tiling(tilingP);
+ break;
+ case r_AlignedTiling:
+ retval = new r_Aligned_Tiling(tilingP);
+ break;
+ case r_InterestTiling:
+ retval = new r_Interest_Tiling(tilingP);
+ break;
+ case r_DirectionalTiling:
+ retval = new r_Dir_Tiling(tilingP);
+ break;
+ case r_StatisticalTiling:
+ retval = new r_Stat_Tiling(tilingP);
+ break;
+ default:
+ retval = new r_Size_Tiling(tilingP);
+ break;
+ }
+ std::cout << "OK" << std::flush;
+ }
+ catch(r_Error& err){
+ std::cout << "FAILED" << std::endl;
+ std::cout << "Error " << err.get_errorno() << " : " << err.what() << std::endl;
+ }
+
+ return retval;
+}
+
+int main( int argc, char** argv ) {
+ int optionValueIndex=0;
+ int testbed = 0;
+
+ r_Tiling_Scheme tilingScheme = r_SizeTiling;
+ char* tilingSchemeParams = "131072";
+
+ r_Data_Format transferFormat=r_Array;
+ char *transferFormatParams = NULL;
+ r_Data_Format storageFormat=r_Array;
+ char *storageFormatParams = NULL;
+
+ char serverName[MAX_STR_LEN]="";
+ r_ULong serverPort=7001;
+ char baseName[MAX_STR_LEN]="";
+
+ char userName[MAX_STR_LEN]="rasguest";
+ char userPasswd[MAX_STR_LEN]="rasguest";
+
+ char collName[MAX_STR_LEN]="";
+ char setTypeName[MAX_STR_LEN] = "";
+ char mddTypeName[MAX_STR_LEN] = "";
+ char fileName[MAX_STR_LEN]="";
+
+
+ if( checkArguments( argc, argv, "-h", optionValueIndex ) ) {
+ printUsage(argv[0]);
+ return EXIT_SUCCESS;
+ }
+
+ if( checkArguments( argc, argv, "-server", optionValueIndex ) && optionValueIndex )
+ strcpy( serverName, argv[optionValueIndex] );
+
+ if( checkArguments( argc, argv, "-base", optionValueIndex ) && optionValueIndex )
+ strcpy( baseName, argv[optionValueIndex] );
+
+ if( checkArguments( argc, argv, "-setname", optionValueIndex ) && optionValueIndex )
+ strcpy( collName, argv[optionValueIndex] );
+
+ if(!strcmp(serverName, "") ||
+ !strcmp(baseName, "") ||
+ !strcmp(collName, "") ) {
+ std::cerr << "Mandatory parameters are missing!" << std::endl;
+ printUsage(argv[0]);
+ return EXIT_SUCCESS;
+ }
+
+ if( checkArguments( argc, argv, "-port", optionValueIndex ) && optionValueIndex )
+ serverPort = strtoul( argv[optionValueIndex], (char **)NULL, 10 ) ;
+
+ if( checkArguments( argc, argv, "-user", optionValueIndex ) && optionValueIndex )
+ strcpy( userName, argv[optionValueIndex] );
+
+ if( checkArguments( argc, argv, "-passwd", optionValueIndex ) && optionValueIndex )
+ strcpy( userPasswd, argv[optionValueIndex] );
+
+ if( checkArguments( argc, argv, "-transferformat", optionValueIndex ) && optionValueIndex ) {
+ transferFormat = get_data_format_from_name( argv[optionValueIndex] );
+ if(transferFormat == r_Data_Format_NUMBER) {
+ std::cerr << "Invalid transfer format '" << argv[optionValueIndex] << "' switched to " << r_Array << std::endl;
+ transferFormat = r_Array;
+ }
+ }
+
+ if( checkArguments( argc, argv, "-transferformatparams", optionValueIndex ) && optionValueIndex )
+ transferFormatParams = argv[optionValueIndex] ;
+
+ if( checkArguments( argc, argv, "-storageformat", optionValueIndex ) && optionValueIndex ) {
+ storageFormat = get_data_format_from_name(argv[optionValueIndex] );
+ if(storageFormat == r_Data_Format_NUMBER) {
+ std::cerr << "Invalid storage format '" << argv[optionValueIndex] << "' switched to " << r_Array << std::endl;
+ storageFormat = r_Array;
+ }
+ }
+
+ if( checkArguments( argc, argv, "-storageformatparams", optionValueIndex ) && optionValueIndex )
+ storageFormatParams = argv[optionValueIndex] ;
+
+ if( checkArguments( argc, argv, "-settype", optionValueIndex ) && optionValueIndex )
+ strcpy( setTypeName, argv[optionValueIndex] );
+
+ if( checkArguments( argc, argv, "-mddtype", optionValueIndex ) && optionValueIndex )
+ strcpy( mddTypeName, argv[optionValueIndex] );
+
+ testbed = checkArguments( argc, argv, "-testbed", optionValueIndex );
+
+ if( checkArguments( argc, argv, "-tiling", optionValueIndex ) && optionValueIndex ) {
+ tilingScheme = get_tiling_scheme_from_name( argv[optionValueIndex] );
+ if(tilingScheme == r_Tiling_Scheme_NUMBER) {
+ std::cerr << "Invalid tiling scheme '" << argv[optionValueIndex] << "' switched to " << r_SizeTiling << std::endl;
+ tilingScheme = r_SizeTiling;
+ }
+ if(tilingScheme == r_RegularTiling) {
+ std::cerr << "Tiling scheme '" << argv[optionValueIndex] << "' not supported, switched to " << r_SizeTiling << std::endl;
+ tilingScheme = r_SizeTiling;
+ }
+ }
+
+ if( checkArguments( argc, argv, "-tilingparams", optionValueIndex ) && optionValueIndex )
+ tilingSchemeParams = argv[optionValueIndex] ;
+
+ if( checkArguments( argc, argv, "-file", optionValueIndex ) && optionValueIndex )
+ strcpy( fileName, argv[optionValueIndex] );
+
+ std::cout << std::endl << std::endl;
+ std::cout << "Insertion of one MDD into the database" << std::endl;
+ std::cout << "======================================" << std::endl << std::endl;
+
+ r_Database db;
+ r_Transaction ta;
+ r_Ref< r_Set< r_Ref< r_GMarray > > > image_set;
+ r_Ref< r_GMarray > image;
+ r_Minterval domain;
+ r_Dimension dim;
+ r_Range low, high;
+ r_ULong initMode, initValue;
+
+ RGBPixel rgbValue = { 1, 2, 3 };
+
+ db.set_servername( serverName, serverPort );
+ db.set_useridentification( userName, userPasswd );
+
+
+ try
+ {
+ std::cout << "MDD Initialization: 0 - Marray<r_ULong> with constant" << std::endl;
+ std::cout << " 1 - Marray<r_ULong> with counter" << std::endl;
+ std::cout << " 2 - Marray<r_ULong> with coordinates" << std::endl;
+ std::cout << " 3 - Marray<r_ULong> with crossfoot" << std::endl;
+ std::cout << " 4 - Marray<r_ULong> with color cube" << std::endl << std::endl;
+
+ std::cout << " 5 - Marray<r_Char> with constant" << std::endl;
+ std::cout << " 6 - insert RGBImage with constant" << std::endl;
+ std::cout << " 7 - Marray<r_Char> with 255*( sin(.25*x1) + ... + sin(.25*xn) )" << std::endl;
+
+ std::cout << " 8 - Marray<r_ULong> read a file (hw8.full.vol)" << std::endl;
+ std::cout << " 9 - Create just an empty collection of type Marray<r_ULong>" << std::endl;
+ std::cout << " 10 - Delete collection of type GMarray" << std::endl;
+ std::cout << " 11 - Delete an object of collection" << std::endl;
+
+ std::cout << " 13 - Marray<r_Char> with counter" << std::endl;
+ std::cout << " 14 - Marray<r_Char> with random numbers" << std::endl;
+ std::cout << " 15 - Marray<r_UShort> with counter" << std::endl;
+ std::cout << " 16 - Marray<r_ULong> with random numbers" << std::endl;
+ std::cout << " 17 - Marray<r_Boolean>" << std::endl;
+ std::cout << " 18 - Marray<r_Char> from file" << std::endl;
+
+ cin >> initMode;
+ std::cout << "Selected mode : " << initMode << std::endl;
+
+ if( initMode == 18 )
+ {
+ fileStream.open( fileName );
+ if( !fileStream )
+ {
+ std::cout << "Error: File " << fileName << " not found." << std::endl;
+ exit(-1);
+ }
+ }
+
+ if( initMode == 0 || initMode == 5 || initMode == 17 )
+ {
+ std::cout << "Constant value : ";
+ cin >> initValue;
+ std::cout << initValue << std::endl;
+ }
+ if( initMode <= 7 || initMode >= 13 )
+ {
+ std::cout << "Number of dimensions : ";
+ cin >> dim;
+ std::cout << dim << std::endl;
+
+ domain = r_Minterval(dim);
+
+ for( r_Dimension i = 1; i<=dim ; i++ )
+ {
+ std::cout << setw(2) << i << " Dimension( lower bound : ";
+ cin >> low;
+ std::cout << low << " upper bound : ";
+ cin >> high;
+ std::cout << high << " ); " ;
+
+ domain << r_Sinterval( low, high );
+ }
+
+ std::cout << std::endl;
+ }
+
+ if( initMode == 14 || initMode == 16 )
+ {
+ std::cout << "Minimum number : ";
+ cin >> minNo;
+ std::cout << minNo << std::endl;
+
+ std::cout << "Maximum number : ";
+ cin >> maxNo;
+ std::cout << maxNo << std::endl;
+ }
+
+ try{
+ std::cout << "Opening Database " << baseName << " on " << serverName << "... "<< std::flush;
+ db.open( baseName );
+ std::cout << "OK" << std::endl;
+
+ std::cout << "Starting Transaction ... " << std::flush;
+ ta.begin();
+ std::cout << "OK" << std::endl;
+
+ std::cout << "Setting transfer and storage formats ... " << std::flush;
+ db.set_transfer_format( transferFormat, transferFormatParams );
+ db.set_storage_format( storageFormat, storageFormatParams );
+ std::cout << "OK" << std::endl;
+ }
+ catch(r_Error& obj){
+ std::cout << "FAILED" << std::endl;
+ std::cout << "Error " << obj.get_errorno() << " : " << obj.what() << std::endl;
+ ta.abort();
+ db.close();
+ return EXIT_FAILURE;
+ }
+
+ std::cout << "Opening the set " << collName << "... " << std::flush;
+
+ if( initMode == 10 || initMode == 11 )
+ {
+ //
+ // get the set
+ //
+
+ try{
+ image_set = db.lookup_object( collName );
+ }
+ catch( r_Error &obj )
+ {
+ std::cout << "FAILED" << std::endl;
+ std::cout << "Error " << obj.get_errorno() << " : " << obj.what() << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ std::cout << "OK" << std::endl;
+
+ if( initMode == 10 )
+ {
+ // delete the set
+
+ if( !image_set.is_null() )
+ image_set.delete_object();
+ // delete image_set; (not implemented yet)
+ }
+ else
+ {
+ int imageNo=0;
+
+ printColl( image_set, 0, 0 );
+
+ std::cout << "Please enter the image number to delete: ";
+ cin >> imageNo;
+ std::cout << imageNo << std::endl;
+
+ r_Iterator< r_Ref< r_GMarray > > iter = image_set->create_iterator();
+
+ for ( int i=1; iter.not_done() && i<imageNo; iter++, i++ );
+
+ if( imageNo && iter.not_done() )
+ {
+ image_set->remove_element( *iter );
+ std::cout << "MDD " << imageNo << " removed." << std::endl;
+ }
+ else
+ std::cout << "Number not valid." << std::endl << std::endl;
+ }
+ }
+ else
+ {
+ //
+ // get set
+ //
+
+ try{
+ image_set = db.lookup_object( collName );
+ }
+ catch( r_Error& /*obj*/ )
+ {
+ std::cout << "FAILED" << std::endl;
+ //std::cout << "Error " << obj.get_errorno() << " : " << obj.what() << std::endl;
+
+ //
+ // set doesn't exist -> create the set
+ //
+
+ std::cout << "Create the set " << collName << " ... " << std::flush;
+
+ if( initMode == 5 || initMode == 7 || initMode == 13 || initMode == 14 || initMode == 18 )
+ {
+ if( !strlen( setTypeName ) )
+ strcpy( setTypeName, "GreySet" );
+
+ image_set = new( &db, setTypeName ) r_Set< r_Ref< r_Marray<r_Char> > >;
+ }
+ else if( initMode == 6 )
+ {
+ if( !strlen( setTypeName ) )
+ strcpy( setTypeName, "RGBSet" );
+
+ image_set = new( &db, setTypeName ) r_Set< r_Ref< r_Marray<RGBPixel> > >;
+ }
+ else if( initMode == 15 )
+ {
+ if( !strlen( setTypeName ) )
+ strcpy( setTypeName, "UShortSet" );
+
+ image_set = new( &db, setTypeName ) r_Set< r_Ref< r_Marray<r_UShort> > >;
+ }
+ else if( initMode == 17 )
+ {
+ if( !strlen( setTypeName ) )
+ strcpy( setTypeName, "BoolSet" );
+
+ image_set = new( &db, setTypeName ) r_Set< r_Ref< r_Marray<r_Boolean> > >;
+ }
+ else
+ {
+ if( !strlen( setTypeName ) )
+ strcpy( setTypeName, "ULongSet" );
+
+ image_set = new( &db, setTypeName ) r_Set< r_Ref< r_Marray<r_ULong> > >;
+ }
+
+ // create a name for the persistent set in order to be able to look it up again
+ db.set_object_name( *image_set, collName );
+ }
+
+ std::cout << " with type name " << setTypeName << " ... OK" << std::endl;
+
+ std::cout << "OId of the set is " << image_set->get_oid() << " ... " << std::endl;
+
+ if( initMode <= 9 || initMode >= 13 )
+ {
+ std::cout << "Creating the marray ..." << std::flush;
+
+ // create storage layout object
+ r_Tiling* tilingObj = getTilingScheme(tilingScheme, tilingSchemeParams);
+
+ if(tilingObj == NULL) return EXIT_FAILURE;
+
+ r_Storage_Layout* stl = new r_Storage_Layout( tilingObj );
+
+ // create the image
+ switch( initMode )
+ {
+ case 0:
+ if( !strlen( mddTypeName ) )
+ strcpy( mddTypeName, "ULongImage" );
+
+ image = new( &db, mddTypeName ) r_Marray<r_ULong>( domain, (r_ULong)initValue, stl );
+ break;
+ case 1:
+ if( !strlen( mddTypeName ) )
+ strcpy( mddTypeName, "ULongImage" );
+
+ image = new( &db, mddTypeName ) r_Marray<r_ULong>( domain, &initWithCounter, stl );
+ break;
+ case 2:
+ if( !strlen( mddTypeName ) )
+ strcpy( mddTypeName, "ULongImage" );
+
+ image = new( &db, mddTypeName ) r_Marray<r_ULong>( domain, &initWithCoordinates, stl );
+ break;
+ case 3:
+ if( !strlen( mddTypeName ) )
+ strcpy( mddTypeName, "ULongImage" );
+
+ image = new( &db, mddTypeName ) r_Marray<r_ULong>( domain, &initWithCrossfoot, stl );
+ break;
+ case 4:
+ if( !strlen( mddTypeName ) )
+ strcpy( mddTypeName, "ULongImage" );
+
+ image = new( &db, mddTypeName ) r_Marray<r_ULong>( domain, &initWithColorCube, stl );
+ break;
+ case 5:
+ if( !strlen( mddTypeName ) )
+ strcpy( mddTypeName, "GreyImage" );
+
+ image = new( &db, mddTypeName ) r_Marray<r_Char>( domain, (r_Char)initValue, stl );
+ break;
+ case 6:
+ if( !strlen( mddTypeName ) )
+ strcpy( mddTypeName, "RGBImage" );
+
+ image = new( &db, mddTypeName ) RGBImage( domain, rgbValue, stl );
+ break;
+ case 7:
+ if( !strlen( mddTypeName ) )
+ strcpy( mddTypeName, "GreyImage" );
+
+ image = new( &db, mddTypeName ) r_Marray<r_Char>( domain, &initWithCurve, stl );
+ break;
+ case 13:
+ if( !strlen( mddTypeName ) )
+ strcpy( mddTypeName, "GreyImage" );
+
+ image = new( &db, mddTypeName ) r_Marray<r_Char>( domain, &initWithCounterChar, stl );
+ break;
+ case 14:
+ if( !strlen( mddTypeName ) )
+ strcpy( mddTypeName, "GreyImage" );
+
+ image = new( &db, mddTypeName ) r_Marray<r_Char>( domain, &initWithRandomChar, stl );
+ break;
+ case 15:
+ if( !strlen( mddTypeName ) )
+ strcpy( mddTypeName, "UShortImage" );
+
+ image = new( &db, mddTypeName ) r_Marray<r_UShort>( domain, &initWithCounterUShort, stl );
+ break;
+ case 16:
+ if( !strlen( mddTypeName ) )
+ strcpy( mddTypeName, "ULongImage" );
+
+ image = new( &db, mddTypeName ) r_Marray<r_ULong>( domain, &initWithRandomULong, stl );
+ break;
+ case 17:
+ if( !strlen( mddTypeName ) )
+ strcpy( mddTypeName, "BoolImage" );
+
+ image = new( &db, mddTypeName ) r_Marray<r_Boolean>( domain, (r_Boolean)initValue, stl );
+ break;
+ case 18:
+ if( !strlen( mddTypeName ) )
+ strcpy( mddTypeName, "GreyImage" );
+
+ image = new( &db, mddTypeName ) r_Marray<r_Char>( domain, &initFromFile, stl );
+ break;
+ default:
+ if( !strlen( mddTypeName ) )
+ strcpy( mddTypeName, "ULongImage" );
+
+ image = new( &db, mddTypeName ) r_Marray<r_ULong>( domain, (r_ULong)0, stl );
+ }
+
+ std::cout << " Marray type " << mddTypeName << " ... OK" << std::endl;
+ std::cout << "OId of the new image is " << image->get_oid() << std::endl;
+
+ std::cout << "Inserting one image with domain " << domain << " into collection " << collName << "..." << std::flush;
+ // put in into the persistent list
+ image_set->insert_element( image );
+ std::cout << "OK" << std::endl << std::endl;
+
+ if( testbed )
+ {
+ std::cout << std::endl << "Testbed output:" << std::endl;
+ std::cout << "-- Testbed: set_oid=" << image_set->get_oid() << std::endl;
+ std::cout << "-- Testbed: image_oid=" << image->get_oid() << std::endl;
+ std::cout << std::endl;
+ }
+
+ }
+ }
+
+ try
+ {
+ std::cout << "Committing Transaction ... " << std::flush;
+ ta.commit();
+ std::cout << "OK" << std::endl;
+ }
+ catch( r_Error &obj )
+ {
+ std::cerr << "Error " << obj.get_errorno() << " : " << obj.what() << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ std::cout << "Closing Database ... " << std::flush;
+ db.close();
+ std::cout << "OK" << std::endl;
+
+ if( initMode == 18 )
+ fileStream.close();
+ }
+ catch( r_Error& obj )
+ {
+ std::cerr << "Error " << obj.get_errorno() << " : " << obj.what() << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+
+
diff --git a/rasodmg/test/test_interesttiling.cc b/rasodmg/test/test_interesttiling.cc
new file mode 100644
index 0000000..3c5ee45
--- /dev/null
+++ b/rasodmg/test/test_interesttiling.cc
@@ -0,0 +1,97 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_interestrtiling.cc
+ *
+ * MODULE: rasodmg
+ *
+ * PURPOSE: test class r_Interest_Tiling.
+ *
+ * COMMENTS:
+ * None
+*/
+
+
+#include <iostream>
+#include <stdio.h>
+#include "rasodmg/marray.hh"
+#include "rasodmg/tiling.hh"
+#include "rasodmg/dirtiling.hh"
+#include "rasodmg/dirdecompose.hh"
+#include "rasodmg/interesttiling.hh"
+#include "raslib/minterval.hh"
+#include "raslib/sinterval.hh"
+#include "raslib/dlist.hh"
+
+int main()
+{
+ r_Minterval domain(2);
+ domain << r_Sinterval(0L, 500L) << r_Sinterval(0L, 600L);
+
+ r_Minterval int1(2);
+ int1 << r_Sinterval(0L, 100L) << r_Sinterval(0L, 500L);
+
+ r_Minterval int2(2);
+ int2 << r_Sinterval(200L, 400L) << r_Sinterval(100L, 200L);
+
+ r_Minterval int3(2);
+ int3 << r_Sinterval(250L, 450L) << r_Sinterval(150L, 250L);
+
+ r_Minterval int4(2);
+ int4 << r_Sinterval(300L, 500L) << r_Sinterval(400L, 550L);
+
+ DList<r_Minterval> iareas;
+ iareas += int1;
+ iareas += int2;
+ iareas += int3;
+ iareas += int4;
+
+ r_Interest_Tiling tiling(iareas, r_Interest_Tiling::REGROUP_AND_SUBTILING,
+ 50000);
+
+ DList<r_Minterval>* tiles = tiling.compute_tiles(domain, 1);
+
+ cout << "Domain: " << domain << endl << endl;
+ cout << "Interest Areas: " << endl;
+ DListIterator<r_Minterval> it_areas = iareas.create_iterator();
+ for (; it_areas.not_done(); it_areas++)
+ {
+ r_Minterval inter = *it_areas;
+ cout << " " << inter << endl;
+ }
+
+ cout << "Tiles: " << endl;
+
+ DListIterator<r_Minterval> it = tiles->create_iterator();
+ for (; it.not_done(); it++)
+ {
+ r_Minterval inter = *it;
+ cout << " " << inter << endl;
+ }
+
+ delete tiles;
+
+ return 0;
+}
+
+
diff --git a/rasodmg/test/test_iterator.cc b/rasodmg/test/test_iterator.cc
new file mode 100644
index 0000000..24feea6
--- /dev/null
+++ b/rasodmg/test/test_iterator.cc
@@ -0,0 +1,135 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_iterator.cc
+ *
+ * MODULE: rasodmg
+ *
+ * COMMENTS:
+ * None
+*/
+
+#include <iostream>
+#include "rasodmg/collection.hh"
+#include "rasodmg/iterator.hh"
+
+int main()
+{
+ int i,v,x,y,z,status;
+
+ i = 0;
+ v = 100;
+ x = 200;
+ y = 300;
+ z = 400;
+ status = 5;
+
+ cout << endl << endl;
+ cout << "Iterator Examples" << endl;
+ cout << "===================" << endl << endl;
+
+ cout << "Creating r_Collection of type int." <<endl;
+ r_Collection<int> a;
+
+ cout << "Creating an iterator of an empty collection." <<endl;
+ r_Iterator<int> iterEmpty = a.create_iterator();
+ if( iterEmpty.not_done() )
+ cout << "Iterator says that iteration is not done." << endl << endl;
+ else
+ cout << "Iterator says that iteration is done." << endl << endl;
+
+ cout << "Now inserting four elements:" << endl << "v = 100" << endl;
+ a.insert_element(v);
+ r_Iterator<int> iterTest = a.create_iterator();
+ if( iterTest.not_done() )
+ cout << "Iterator says that iteration is not done." << endl << endl;
+ else
+ cout << "Iterator says that iteration is done." << endl << endl;
+
+ cout << "x = 200" << endl;
+ a.insert_element(x);
+
+ cout << "y = 300" << endl;
+ a.insert_element(y);
+
+ cout << "z = 400" << endl;
+ a.insert_element(z);
+
+ cout << "Cardinality of collection 'a' after four inserts: " << a.cardinality() << endl << endl;
+
+ cout << "Now creating an iterator for 'a'." << endl;
+
+ // ODMG wants an iterator to be created this way...
+ r_Iterator<int> iter = a.create_iterator();
+
+ // ...but this is an equally valid version that doesn't require
+ // r_Collection to have a member function create_iterator:
+ //r_Iterator<int> iter( a );
+
+ cout << "Iterator points to element: " << iter.get_element() << endl << endl
+ << "Advancing iterator two times." << endl;
+ iter.advance();
+ iter.advance();
+ cout << "Iterator points to element: " << iter.get_element() << endl << endl
+ << "Regetting this element and advancing iterator (next function)." << endl;
+ status = iter.next( i );
+ cout << "Element is " << i << "." << endl;
+ cout << "Iterator points to element: " << iter.get_element() << endl << endl
+ << "Resetting iterator." << endl;
+ iter.reset();
+ cout << "Iterator points to element: " << iter.get_element() << endl << endl;
+
+ cout << "Testing prefix and postfix incrementors." << endl;
+ r_Iterator<int> iter2 = a.create_iterator();
+ //r_Iterator<int> iter2( a );
+ iter.reset();
+ cout << "Postfix incrementor returns: " << iter++.get_element() << endl;
+ iter.reset();
+ iter2 = ++iter;
+ cout << "Prefix incrementor returns: " << iter2.get_element() << endl << endl;
+
+ cout << "Resetting both iterators." << endl;
+ iter.reset();
+ iter2.reset();
+ cout << "iter1 == iter2 ? (1=TRUE/0=FALSE) " << iter.is_equal(iter2) << endl;
+ cout << "iter1 != iter2 ? (1=TRUE/0=FALSE) " << (!iter.is_equal(iter2)) << endl << endl;
+
+ cout << "Computing all permutatios of the four numbers:" << endl;
+
+ r_Iterator<int> iter3 = a.create_iterator();
+ //r_Iterator<int> iter3( a );
+ r_Iterator<int> iter4 = a.create_iterator();
+ //r_Iterator<int> iter4( a );
+
+ for ( ; iter.not_done(); iter++ )
+ for ( iter2.reset(); iter2.not_done(); iter2++ )
+ for ( iter3.reset(); iter3.not_done(); iter3++ )
+ for ( iter4.reset(); iter4.not_done(); iter4++ )
+ if ( !(iter4.is_equal(iter3) ||
+ iter4.is_equal(iter2) ||
+ iter4.is_equal(iter) ||
+ iter3.is_equal(iter2) ||
+ iter3.is_equal(iter) ||
+ iter2.is_equal(iter) ) )
+ cout << *iter << " " << *iter2 << " " << *iter3 << " " << *iter4 << endl;
+}
diff --git a/rasodmg/test/test_lookup.cc b/rasodmg/test/test_lookup.cc
new file mode 100644
index 0000000..c18c7fa
--- /dev/null
+++ b/rasodmg/test/test_lookup.cc
@@ -0,0 +1,378 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_lookup.cc
+ *
+ * MODULE: rasodmg
+ *
+ * COMMENTS:
+ * None
+ */
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#include "raslib/template_inst.hh"
+#endif
+
+#include <iostream>
+#include <string.h>
+
+#include "raslib/type.hh"
+
+#ifdef __VISUALC__
+ #define __EXECUTABLE__
+ #include "include/basictypes.hh"
+ #undef __EXECUTABLE__
+#else
+ #include "include/basictypes.hh"
+#endif
+
+const int MAX_STR_LEN = 255;
+enum prg_mode {
+ USE_INVALID = 0,
+ USE_COLLNAME,
+ USE_OIDSTR
+ };
+
+using namespace std;
+
+int checkArguments( int argc, char** argv, const char* searchText, int& optionValueIndex )
+{
+ int found = 0;
+ int i=1;
+
+ while( !found && i<argc )
+ found = !strcmp( searchText, argv[i++] );
+
+ if( found && i<argc && (argv[i][0] != '-') )
+ optionValueIndex = i;
+ else
+ optionValueIndex = 0;
+
+ return found;
+}
+
+
+
+void printColl( r_Ref< r_Set< r_Ref< r_GMarray > > >& image_set, int output, int rgbOutput, int hexOutput )
+{
+ std::cout << "Collection" << std::endl;
+ std::cout << " Oid...................: " << image_set->get_oid() << std::endl;
+ std::cout << " Type Name.............: " << image_set->get_object_name() << std::endl;
+ std::cout << " Type Structure........: "
+ << ( image_set->get_type_structure() ? image_set->get_type_structure() : "<nn>" ) << std::endl;
+ std::cout << " Type Schema...........: " << std::flush;
+ if( image_set->get_type_schema() )
+ image_set->get_type_schema()->print_status( std::cout );
+ else
+ std::cout << "<nn>" << std::flush;
+ std::cout << std::endl;
+ std::cout << " Number of entries.....: " << image_set->cardinality() << std::endl;
+ std::cout << " Element Type Schema...: " << std::flush;
+ if( image_set->get_element_type_schema() )
+ image_set->get_element_type_schema()->print_status( std::cout );
+ else
+ std::cout << "<nn>" << std::flush;
+ std::cout << std::endl;
+
+ if( output )
+ {
+ r_Iterator< r_Ref< r_GMarray > > iter = image_set->create_iterator();
+
+ std::cout << std::endl;
+
+ for ( int i=1 ; iter.not_done(); iter++, i++ )
+ {
+ std::cout << "Image " << i << std::endl;
+
+ if( !rgbOutput )
+ (*iter)->print_status( std::cout, hexOutput );
+ else
+ {
+ RGBImage image( **iter );
+ r_Point pt(0,0);
+
+ std::cout << "[0,0] = {" << (int)image[pt].red << ","
+ << (int)image[pt].green << ","
+ << (int)image[pt].blue << "}" << std::endl;
+ }
+ std::cout << std::endl;
+ }
+
+ std::cout << std::endl;
+ }
+}
+
+void
+printUsage(char* name) {
+ std::cout << name << "v1.1 systemtest lookup utility " << std::endl << std::endl;
+ std::cout << "Description: Systemtest lookup utility for retrival of set / marray from RasDaMan " << std::endl << std::endl;
+ std::cout << "Usage: " << name << " [options]" << std::endl << std::endl;
+ std::cout << "Options: -h ... this help" << std::endl;
+ std::cout << " -server <srvname> ... name of server.(mandatory)" << std::endl;
+ std::cout << " -port <nnnn> ... port of server.(default 7001)" << std::endl;
+ std::cout << " -base <dbname> ... name of database.(madatory)" << std::endl;
+ std::cout << " -setname <setname> ... name of collection for retrival by name.(madatory)" << std::endl;
+ std::cout << " -oid <oidset> ... oid of marray or set as string for retrival by oid.(mandatory)" << std::endl;
+ std::cout << " -user <usrname> ... user name.(default rasguest)" << std::endl;
+ std::cout << " -passwd <usrpasswd> ... user password.(default rasguest)" << std::endl;
+ std::cout << " -transferformat <format> ... transfer format.(default Array)" << std::endl;
+ std::cout << " -transferformatparams <formatparams> ... transfer format parameters.(default NULL)" << std::endl;
+ std::cout << " -storageformat <format> ... storage format.(default Array)" << std::endl;
+ std::cout << " -storageformatparams <formatparams> ... storage format parameters.(default NULL)" << std::endl;
+ std::cout << " -ia ... interactive control for multiple collection retrieval.(default off)" << std::endl;
+ std::cout << " -hex ... output in hex.(default off)" << std::endl;
+ std::cout << " -rgb ... output is rgb struct.(default off)" << std::endl;
+ std::cout << " -nooutput ... no output of MDD content.(default on)" << std::endl;
+ std::cout << " -testbed ... turn on output for testbed.(default off)" << std::endl;
+
+ std::cout << std::endl << std::endl;
+
+ std::cout << "Report bugs to <support@active­knowledge.com>" << std::endl;
+}
+
+int main( int argc, char** argv )
+{
+ int interactive=0;
+ int output=0;
+ int optionValueIndex=0;
+ char key = 'a';
+ int hexOutput = 0;
+ int rgbOutput = 0;
+ prg_mode mode=USE_INVALID;
+ int testbed = 0;
+
+ r_Data_Format transferFormat=r_Array;
+ char *transferFormatParams = NULL;
+ r_Data_Format storageFormat=r_Array;
+ char *storageFormatParams = NULL;
+
+ char *serverName="";
+ r_ULong serverPort = 7001;
+ char *baseName="";
+
+ char *collName="";
+ char *oidString="";
+
+ char *userName="rasguest";
+ char *userPasswd="rasguest";
+
+#ifdef TEST_LOOKUP
+ r_GMarray* transImage = 0;
+ r_Ref<r_GMarray> transImageRef = 0;
+#endif
+
+ if( checkArguments( argc, argv, "-h", optionValueIndex ) ) {
+ printUsage(argv[0]);
+ return EXIT_SUCCESS;
+ }
+
+ if( checkArguments( argc, argv, "-server", optionValueIndex ) && optionValueIndex )
+ serverName=argv[optionValueIndex];
+
+ if( checkArguments( argc, argv, "-base", optionValueIndex ) && optionValueIndex )
+ baseName=argv[optionValueIndex];
+
+ if( checkArguments( argc, argv, "-setname", optionValueIndex ) && optionValueIndex ) {
+ collName=argv[optionValueIndex];
+ mode=USE_COLLNAME;
+ }
+
+ if( checkArguments( argc, argv, "-oid", optionValueIndex ) && optionValueIndex ) {
+ oidString=argv[optionValueIndex];
+ if(mode != USE_INVALID) {
+ std::cerr << "Use -setname or -oid, not both in the same time" << std::endl;
+ printUsage(argv[0]);
+ return EXIT_FAILURE;
+ }
+ mode=USE_OIDSTR;
+ }
+
+ if(!strcmp(serverName, "") ||
+ !strcmp(baseName, "") ||
+ (mode == USE_INVALID) ) {
+ std::cerr << "Mandatory parameters are missing!" << std::endl;
+ printUsage(argv[0]);
+ return EXIT_SUCCESS;
+ }
+
+ if( checkArguments( argc, argv, "-port", optionValueIndex ) && optionValueIndex )
+ serverPort = strtoul( argv[optionValueIndex], (char **)NULL, 10 ) ;
+
+ if( checkArguments( argc, argv, "-user", optionValueIndex ) && optionValueIndex )
+ strcpy( userName, argv[optionValueIndex] );
+
+ if( checkArguments( argc, argv, "-passwd", optionValueIndex ) && optionValueIndex )
+ strcpy( userPasswd, argv[optionValueIndex] );
+
+ if( checkArguments( argc, argv, "-transferformat", optionValueIndex ) && optionValueIndex ) {
+ transferFormat = get_data_format_from_name( argv[optionValueIndex] );
+ if(transferFormat == r_Data_Format_NUMBER) {
+ std::cerr << "Invalid transfer format '" << argv[optionValueIndex] << "' switched to " << r_Array << std::endl;
+ transferFormat = r_Array;
+ }
+ }
+
+ if( checkArguments( argc, argv, "-transferformatparams", optionValueIndex ) && optionValueIndex )
+ transferFormatParams = argv[optionValueIndex] ;
+
+ if( checkArguments( argc, argv, "-storageformat", optionValueIndex ) && optionValueIndex ) {
+ storageFormat = get_data_format_from_name(argv[optionValueIndex] );
+ if(storageFormat == r_Data_Format_NUMBER) {
+ std::cerr << "Invalid storage format '" << argv[optionValueIndex] << "' switched to " << r_Array << std::endl;
+ storageFormat = r_Array;
+ }
+ }
+
+ if( checkArguments( argc, argv, "-storageformatparams", optionValueIndex ) && optionValueIndex )
+ storageFormatParams = argv[optionValueIndex] ;
+
+ interactive = checkArguments( argc, argv, "-ia", optionValueIndex );
+ output = !checkArguments( argc, argv, "-nooutput", optionValueIndex );
+ hexOutput = checkArguments( argc, argv, "-hex", optionValueIndex );
+ rgbOutput = checkArguments( argc, argv, "-rgb", optionValueIndex );
+ testbed = checkArguments( argc, argv, "-testbed", optionValueIndex );
+
+ std::cout << std::endl << std::endl;
+ std::cout << "ODMG conformant lookup of Marrays" << std::endl;
+ std::cout << "=================================" << std::endl << std::endl;
+
+ r_Database db;
+ r_Transaction ta;
+
+
+
+ try
+ {
+ std::cout << "Opening database '" << baseName << "' on server '" << serverName << "':" << serverPort
+ << " using user '" << userName << "':'" << userPasswd << "' ... " << std::flush;
+ db.set_servername( serverName, serverPort );
+ db.set_useridentification( userName, userPasswd );
+ db.open( baseName );
+ std::cout << "OK" << std::endl;
+
+ while( key != 'q' )
+ {
+ std::cout << "Starting Read Only Transaction ... " << std::flush;
+ ta.begin( r_Transaction::read_only );
+ std::cout << "OK" << std::endl;
+
+ if( mode == USE_COLLNAME )
+ {
+ r_Ref< r_Set< r_Ref< r_GMarray > > > image_set;
+
+ std::cout << "Looking up collection by name " << collName << " ..." << std::flush;
+ image_set = db.lookup_object( collName );
+ std::cout << "OK" << std::endl;
+
+ printColl( image_set, output, rgbOutput, hexOutput );
+ }
+ else
+ {
+ r_Ref<r_Object> persObject;
+ r_OId oid( oidString );
+
+ std::cout << "Looking up object by oid " << oid << " ..." << std::flush;
+ persObject = db.lookup_object( oid );
+ std::cout << "OK" << std::endl;
+
+ std::cout << "Object type: " << persObject->get_type_structure() << std::endl;
+
+ if( strstr( persObject->get_type_structure(), "set" ) )
+ {
+ r_Ref< r_Set< r_Ref< r_GMarray > > > image_set = (r_Ref_Any) persObject;
+
+ printColl( image_set, output, rgbOutput, hexOutput );
+ }
+ else
+ {
+ r_Ref<r_GMarray> marray = (r_Ref_Any) persObject;
+
+ std::cout << "MDD object with domain " << marray->spatial_domain()
+ << " and type " << marray->get_type_name() << std::endl;
+
+ if( output )
+ marray->print_status( std::cout );
+
+#ifdef TEST_LOOKUP
+ // make a copy for use after ta
+ transImage = new r_GMarray( (const r_GMarray&)*marray );
+ transImageRef = new("type") r_GMarray( (const r_GMarray&)*marray );
+#endif
+ }
+
+ std::cout << std::endl;
+ }
+
+ std::cout << "Commiting Transaction ... " << std::flush;
+ ta.commit();
+ std::cout << "OK" << std::endl;
+
+ if( interactive )
+ {
+ std::cout << "Command (q=quit, a=again): ";
+ cin >> key;
+ }
+ else
+ key = 'q';
+
+ }
+
+ std::cout << "Closing Database ... " << std::flush;
+ db.close();
+ std::cout << "OK" << std::endl;
+
+ }
+ catch( r_Error& errorObj )
+ {
+ ta.abort();
+ db.close();
+ std::cout << "Error " << errorObj.get_errorno() << " : " << errorObj.what() << std::endl;
+ return EXIT_FAILURE;
+ }
+
+#ifdef TEST_LOOKUP
+ if( transImage )
+ {
+ std::cout << "Transient MDD object with domain " << transImage->spatial_domain()
+ << " and type " << transImage->get_type_name() << std::endl;
+
+ transImage->print_status( std::cout, hexOutput );
+
+ delete transImage;
+ }
+
+ if( transImageRef != 0 )
+ {
+ std::cout << "Transient MDD object with domain " << transImageRef->spatial_domain()
+ << " and type " << transImageRef->get_type_name() << std::endl;
+
+ transImageRef->print_status( std::cout, hexOutput );
+
+ transImageRef.destroy();
+ }
+#endif
+
+ return EXIT_SUCCESS;
+}
+
diff --git a/rasodmg/test/test_marray.cc b/rasodmg/test/test_marray.cc
new file mode 100644
index 0000000..210db3f
--- /dev/null
+++ b/rasodmg/test/test_marray.cc
@@ -0,0 +1,110 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_marray.cc
+ *
+ * MODULE: raslib
+ *
+ * COMMENTS:
+ * None
+*/
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#include "raslib/template_inst.hh"
+#endif
+
+#include <iostream>
+
+#include "rasodmg/marray.hh"
+
+#include "raslib/minterval.hh"
+#include "raslib/sinterval.hh"
+#include "raslib/point.hh"
+#include "raslib/error.hh"
+
+static int INIT = 0;
+
+int initFunction( const r_Point& /*pt*/ )
+{
+ /*
+ int value=0;
+
+ for( int i=0; i< pt.dimension(); i++ )
+ value += pt[i];
+
+ return value;
+ */
+ return INIT++;
+}
+
+
+int main()
+{
+ cout << endl << endl;
+ cout << "Marray Examples" << endl;
+ cout << "===============" << endl << endl;
+
+ cout << "Initialization of Marray<int, [0:2,3:5,6:8]> with init function:" << endl;
+ r_Minterval domain(3);
+ domain << r_Sinterval(0,2) << r_Sinterval(3,5) << r_Sinterval(6,8);
+ r_Marray<int> a( domain, &initFunction );
+ cout << "OK" << endl;
+ a.print_status( cout );
+
+ cout << "Value [0,3,6] = " << a[r_Point(0,3,6)] << endl;
+ cout << "Changing to 99" << endl;
+ a[r_Point(0,3,6)] = 99;
+ cout << "New value [0,3,6] = " << a[r_Point(0,3,6)] << endl;
+
+ cout << endl << "Projection operator:" << endl;
+ cout << "project a[1]" << endl;
+ r_Marray<int> b = a[1];
+ b.print_status( cout );
+
+ cout << endl << "Projection and cast operator a[r_Point(1,4,7)] :" << endl;
+ cout << "a[1][4][7] = " << (int)(a[ r_Point(1,4,7) ]) << endl;
+
+ cout << endl << "Projection and cast operator a[1][4][7] :" << endl;
+ cout << "a[1][4][7] = " << (int)(a[1][4][7]) << endl;
+
+ cout << endl << "Triming operator:" << endl;
+ cout << "trim a[1:3, 4:6, 7:9]" << endl;
+ r_Marray<int> c = a[ r_Minterval(3) << r_Sinterval(1,3) << r_Sinterval(4,6) << r_Sinterval(7,9) ];
+ c.print_status( cout );
+
+ cout << "Initialization of Marray<char, [0:2,0:2,0:2]> with 'A'" << endl;
+ r_Minterval domain2(3);
+ domain2 << r_Sinterval(0,2) << r_Sinterval(0,2) << r_Sinterval(0,2);
+ r_Marray<char> a_char( domain2, 'A' );
+ cout << "OK" << endl;
+ a_char.print_status( cout );
+
+ cout << "Transforming the object GMarray( [0:2,0:2,0:2], 4 ) to Marray<int>( [...] )" << endl;
+ r_GMarray genMDD( domain2, 4 );
+ r_Marray<int> specMDD( genMDD );
+
+ cout << specMDD.spatial_domain() << endl;
+
+ return 0;
+}
diff --git a/rasodmg/test/test_oqlquery.cc b/rasodmg/test/test_oqlquery.cc
new file mode 100644
index 0000000..1fe0839
--- /dev/null
+++ b/rasodmg/test/test_oqlquery.cc
@@ -0,0 +1,157 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_sinterval.cc
+ *
+ * MODULE: rasodmg
+ *
+ * COMMENTS:
+ * None
+*/
+
+#include <iostream>
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#include "raslib/template_inst.hh"
+#endif
+
+#include <iostream>
+#include "rasodmg/oqlquery.hh"
+
+int main()
+{
+ cout << endl << endl;
+ cout << "r_OQL_Query Examples" << endl;
+ cout << "====================" << endl << endl;
+
+
+ // 1. Example
+
+ cout << "1. Initializing with two string arguments." << endl;
+ r_OQL_Query q1("select d from $1 where d.id = $2");
+
+ try
+ {
+ q1 << "Images d" << "<id>";
+ }
+ catch( r_Error& err )
+ {
+ cout << err.what() << endl;
+ }
+
+ cout << "Parameterized query string : " << q1.get_parameterized_query() << endl;
+ cout << "Query string : " << q1.get_query() << endl << endl;
+
+
+ // 2. Example
+
+ cout << "2. Initializing with too many arguments." << endl;
+ r_OQL_Query q2("select d from $1 where d.id = $2");
+
+ try
+ {
+ q2 << "Images d" << "<id>" << "too many";
+ }
+ catch( r_Error& err )
+ {
+ cout << err.what() << endl;
+ }
+
+ cout << "Parameterized query string : " << q2.get_parameterized_query() << endl;
+ cout << "Query string : " << q2.get_query() << endl << endl;
+
+
+ // 3. Example
+
+ cout << "3. Initializing with different arguments." << endl;
+ r_OQL_Query q3("select $1 from $2 $3 where d.id1 = $4 and d.id2 = $5");
+
+ try
+ {
+ q3 << (unsigned char)'d' << "Images" << (unsigned char)'d' << (r_Long)100l << (r_Long)20l;
+ }
+ catch( r_Error& err )
+ {
+ cout << err.what() << endl;
+ }
+
+ cout << "Parameterized query string : " << q3.get_parameterized_query() << endl;
+ cout << "Query string : " << q3.get_query() << endl << endl;
+
+ // 4. Example
+
+ cout << "4. Initializing with different arguments." << endl;
+ r_OQL_Query q4("select d$1 from $2 as d where some( d$3 > $4 )");
+
+ try
+ {
+ q4 << ( r_Minterval(2) << r_Sinterval((r_Long)100l,(r_Long)199l) << r_Sinterval((r_Long)200l,(r_Long)299l) )
+ << "Images"
+ << ( r_Minterval(2) << r_Sinterval((r_Long)300l,(r_Long)399l) << r_Sinterval((r_Long)400l,(r_Long)499l) )
+ << (r_Long)127l;
+ }
+ catch( r_Error& err )
+ {
+ cout << err.what() << endl;
+ }
+
+ cout << "Parameterized query string : " << q4.get_parameterized_query() << endl;
+ cout << "Query string : " << q4.get_query() << endl << endl;
+
+ // 5. Example
+
+ cout << "4. Initializing with different arguments." << endl;
+ r_OQL_Query q5("update upd1 as a set a assign $1 *$2*3");
+
+ try
+ {
+ r_GMarray mdd;
+
+ cout << "Parameterized query string : " << q5.get_parameterized_query() << endl;
+ cout << "Query string : " << q5.get_query() << endl << endl;
+ q5 << mdd;
+ cout << "Parameterized query string : " << q5.get_parameterized_query() << endl;
+ cout << "Query string : " << q5.get_query() << endl << endl;
+ q5 << mdd;
+ cout << "Parameterized query string : " << q5.get_parameterized_query() << endl;
+ cout << "Query string : " << q5.get_query() << endl << endl;
+ }
+ catch( r_Error& err )
+ {
+ cout << err.what() << endl;
+ }
+
+ cout << "Parameterized query string : " << q5.get_parameterized_query() << endl;
+ cout << "Query string : " << q5.get_query() << endl << endl;
+}
+
+
+
+
+
+
+
+
+
+
diff --git a/rasodmg/test/test_polygon.cc b/rasodmg/test/test_polygon.cc
new file mode 100644
index 0000000..bee92bc
--- /dev/null
+++ b/rasodmg/test/test_polygon.cc
@@ -0,0 +1,951 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_polygon.cc
+ *
+ * MODULE: rasodmg
+ *
+ * COMMENTS:
+ * None
+ */
+
+#include "mymalloc/mymalloc.h"
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#include "raslib/template_inst.hh"
+#endif
+
+extern "C" {
+ #include "tiffio.h"
+}
+
+#include <iostream>
+#include <vector>
+
+using std::vector;
+using std::iterator;
+
+#include <stdio.h>
+#include <math.h>
+#include <ctype.h>
+#if defined(SOLARIS)
+#include <strings.h>
+#else
+#include <string.h>
+#endif
+
+#include "rasodmg/polygon.hh"
+#include "rasodmg/transaction.hh"
+#include "rasodmg/database.hh"
+#include "rasodmg/marray.hh"
+#include "rasodmg/oqlquery.hh"
+#include "rasodmg/fastscale.hh"
+#include "raslib/basetype.hh"
+#include "raslib/mitera.hh"
+#include "raslib/shhopt.h"
+#include "rasodmg/ref.hh"
+#include "conversion/tiff.hh"
+
+#include "cmlinterpreter.hh"
+#include "cmloption.hh"
+#include "cmlerror.hh"
+
+// global limits
+static const int MYSTRINGSIZE = 256;
+static const int SUCCES = 0;
+static const int FAILED = 1;
+
+// global variable used in this program
+r_Database db;
+r_Transaction ta;
+r_Float rScale;
+char* rBgr=NULL;
+r_Polygon poly;
+
+// default values & constants
+static const char* DefaultSrv = "localhost";
+static const char* DefaultPort = "7001";
+static const char* DefaultDb = "RASBASE";
+static const char* DefaultUsr = "rasguest";
+static const char* DefaultPasswd = "rasguest";
+static const r_Float DefaultScale = 1.;
+
+
+
+
+// parameters of this program
+CmlInterpreter cmlInter;
+CmlStringOption cmlSrv('s',"server", "srv-name", "name of machine running RasDaMan manager. Default: localhost");
+CmlStringOption cmlPort(0,"port", "nnnn", "port number used by RasDaMan manager. Default: 7001");
+CmlStringOption cmlDb('d',"database", "db-name", "name of database. Default: RASBASE).");
+CmlStringOption cmlUsr(0, "user", "user-name", "name of user. Default rasguest");
+CmlStringOption cmlPasswd(0,"passwd", "user-passwd", "password of user. Default rasguest");
+CmlStringOption cmlColl('c',"collname", "coll-name", "name of collection. Mandatory");
+CmlStringOption cmlDomain('r',"domain", "domain", "domain to be retrieved (e.g. \"[1000:8000,5000:10000]\"). Mandatory");
+CmlStringOption cmlScale('f',"scale", "factor", "scale factor applied to domain. Default 1");
+CmlStringOption cmlFile('t',"tiffile", "file-name", "name of TIFF file written. Mandatory");
+CmlStringOption cmlPolygon('p',"polygon", "pol-desc","polygon for clipping (e.g. \"[1010,8200] [4000,8200] [3000,9800]\").");
+CmlStringOption cmlBgr('b',"background", "bgr-desc", "background of TIFF file (e.g. 0x1f).");
+CmlBoolOption cmlHelp('h',"help","print this message.");
+
+
+
+// This is a quick first try at a class for creating TIFFs stripe by stripe. It copies
+// a lot of code from class r_Conv_TIFF in conversion/tiff.cc. Ideally this at some
+// point should make use of Andreas' conversion framework.
+
+class r_TIFFStripe
+{
+public:
+ r_TIFFStripe(const char* newFileName, const r_Minterval& tiffDom);
+ void openTiff(); //open the tiff file
+ bool addArray(const r_GMarray& myArray); //write myArray to tiff file
+ void closeTiff(); //close the tiff file
+ ~r_TIFFStripe();
+private:
+ char* fileName; //filename of the tiff image
+ TIFF* tiffFile; //handler of the tiff image
+ uint16 bpp; // bits per pixel (24 for RGB)
+ uint16 bps; // bits per sample (8 for RGB)
+ unsigned long typeSize; // size of base type, will be retrieved with r_Base_Type::size()
+ uint32 width; // image width
+ uint32 height; //image height
+ char* scanLine; // buffer for scanLine to be written to file
+ uint32 tiffRow; // row's no of tiff image
+};
+
+r_TIFFStripe::r_TIFFStripe(const char* newFileName, const r_Minterval& tiffDom)
+ : bpp(8), bps(8), typeSize(1), tiffRow(0), fileName(NULL), tiffFile(NULL), scanLine(NULL)
+{
+ fileName = strdup(newFileName);
+ width = (uint32)(tiffDom.get_extent()[0]);
+ height = (uint32)(tiffDom.get_extent()[1]);
+ // copied this formula from Andreas, do not fully get it. 31 seems to be an internal
+ // buffer for tifflib and >> 5 together with uint32 instead of char seems to be used
+ // to get the correct number of chars as oppose to bits.
+
+ //allocate the buffer
+ scanLine = (char*)mymalloc(width*typeSize);
+}
+
+void
+r_TIFFStripe::openTiff()
+{
+ uint16 cmap[256]; // Colour map (for greyscale images)
+
+ tiffFile = TIFFOpen(fileName, "w");
+
+ // These fields are written to the file by TIFFWriteDirectory, which is automatically
+ // called by TIFFClose and TIFFFlush
+
+ TIFFSetField(tiffFile, TIFFTAG_ARTIST, "RasDaMan");
+ TIFFSetField(tiffFile, TIFFTAG_DOCUMENTNAME, "Image");
+ TIFFSetField(tiffFile, TIFFTAG_SOFTWARE, "RasDaMan");
+ //TIFFSetField(tiffFile, TIFFTAG_SUBFILETYPE, (uint32)0);
+ TIFFSetField(tiffFile, TIFFTAG_IMAGEWIDTH, width);
+ TIFFSetField(tiffFile, TIFFTAG_IMAGELENGTH, height);
+ TIFFSetField(tiffFile, TIFFTAG_BITSPERSAMPLE, bps);
+ // UNIX doesn't mind which fill-order. NT only understands this one.
+ TIFFSetField(tiffFile, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB);
+ // problem: LZW is no longer supported in current versions of libtiff.
+ TIFFSetField(tiffFile, TIFFTAG_COMPRESSION, (uint16)COMPRESSION_NONE);
+ TIFFSetField(tiffFile, TIFFTAG_ORIENTATION, (uint16)ORIENTATION_TOPLEFT);
+
+ // Format-dependent tags, currently support only 8bit grey images
+ TIFFSetField(tiffFile, TIFFTAG_PHOTOMETRIC, (uint16)PHOTOMETRIC_PALETTE);
+ TIFFSetField(tiffFile, TIFFTAG_SAMPLESPERPIXEL, (uint16)1);
+ TIFFSetField(tiffFile, TIFFTAG_PLANARCONFIG, (uint16)PLANARCONFIG_CONTIG);
+ // TIFFSetField(tiffFile, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tiffFile, (uint32)-1));
+ TIFFSetField(tiffFile, TIFFTAG_ROWSPERSTRIP, (uint32)1);
+ //TIFFSetField(tiffFile, TIFFTAG_MINSAMPLEVALUE, (uint16)0);
+ //TIFFSetField(tiffFile, TIFFTAG_MAXSAMPLEVALUE, (uint16)255);
+ TIFFSetField(tiffFile, TIFFTAG_RESOLUTIONUNIT, (uint16)RESUNIT_INCH);
+
+ // This will have to be adapted!
+ TIFFSetField(tiffFile, TIFFTAG_XRESOLUTION, (float)90.0);
+ TIFFSetField(tiffFile, TIFFTAG_YRESOLUTION, (float)90.0);
+ TIFFSetField(tiffFile, TIFFTAG_XPOSITION, (float)0.0);
+ TIFFSetField(tiffFile, TIFFTAG_YPOSITION, (float)0.0);
+
+ // build the colour-map (greyscale, i.e. all 3 components identical)
+ // TIFF needs 16 bit values for this (--> tools/tiffdither.c)
+ for (int i=0; i<256; i++) cmap[i] = (uint16)(i*((1L << 16) - 1)/255);
+ TIFFSetField(tiffFile, TIFFTAG_COLORMAP, cmap, cmap, cmap);
+}
+
+bool
+r_TIFFStripe::addArray(const r_GMarray& myArray)
+{
+ // here we write the r_GMarray we get line by line into the TIFF. We
+ // assume that the width of myArray (width = [0] r_Sinterval)
+ // corresponds to the width of the whole TIFF.
+
+ unsigned long imageHeight = myArray.spatial_domain().get_extent()[1];
+ unsigned long imageWidth = myArray.spatial_domain().get_extent()[0];
+
+ if(imageWidth != width)
+ {
+ cout << "Error Tiff file \"" << fileName << "\" initialised for "
+ << width << ", not for " << imageWidth << " !" << endl;
+ return false;
+ }
+
+ const char* linePtr = myArray.get_array(); // points to myArray's data
+ char* scanLinePtr = (char*)scanLine;
+
+
+ for (int row = 0; row < imageHeight; row++) {
+ // copy data (and transpose)
+ for (int col=0; col < imageWidth; col++) {
+ for(int i=0; i<typeSize; i++) {
+ *scanLinePtr++ = *(linePtr + col*imageHeight*typeSize + row*typeSize + i);
+ }
+ // not really fast and does not work for all types! Good enough for now.
+ }
+ if(TIFFWriteScanline(tiffFile, (tdata_t)scanLine, tiffRow++, 0) < 0)
+ {
+ // error
+ cerr << "Error writing line into file " << fileName << "." << endl;
+ return false;
+ }
+ memset(scanLine, 0, imageWidth*typeSize);
+ scanLinePtr = (char*)scanLine;
+ }
+
+ return true;
+}
+
+void
+r_TIFFStripe::closeTiff()
+{
+ TIFFClose(tiffFile);
+}
+
+r_TIFFStripe::~r_TIFFStripe()
+{
+ if(fileName)
+ free(fileName);
+ if(scanLine)
+ free(scanLine);
+}
+
+void
+printUsage(char* name)
+{
+ static const char* ExColl="lva";
+ static const char* ExDomain="[0:100,0:100]";
+ static const char* ExFile="lva.tif";
+
+ cout << name << " v1.0 - RasDaMan Export Utility for 2D marrays" << endl;
+ cout << "Description: Exports data with background, from RasDaMan database from a fastscale collection" << endl;
+ cout << " for a domain with a scale." << endl;
+ cout << " Returns " << SUCCES << " for succes, otherwise " << FAILED << endl;
+ cout << "Notes: If a polygon is specified, the result is a image which has data inside the polygon and"<< endl;
+ cout << " the rest is filled with background color." << endl;
+
+ cout << "Usage options:" << endl;
+ cmlInter.printHelp();
+
+ cout << "For example:" << endl;
+ cout << name << "\t" << cmlSrv.getLongFormTag() << " " << DefaultSrv << " ";
+ cout << cmlPort.getLongFormTag() << " " << DefaultPort << " ";
+ cout << cmlDb.getLongFormTag() << " " << DefaultDb << " ";
+ cout << cmlColl.getLongFormTag() << " " << ExColl << " ";
+ cout << endl << "\t\t" << cmlDomain.getLongFormTag() << " " << ExDomain << " ";
+ cout << cmlScale.getLongFormTag() << " " << DefaultScale << " ";
+ cout << cmlFile.getLongFormTag() << " " << ExFile << " ";
+ cout << endl << "\t\t" << cmlUsr.getLongFormTag() << " " << DefaultUsr << " ";
+ cout << cmlPasswd.getLongFormTag() << " " << DefaultPasswd << " ";
+ cout << endl;
+
+ cout << "Report bugs to <support@active­knowledge.com>" << endl;
+}
+
+void
+printStatus(char* name)
+{
+ cout << name << "'s parameters list:" << endl;
+ cmlInter.printStatus();
+}
+
+void
+defineParams()
+{
+ cmlInter.defineOption(&cmlSrv);
+ cmlInter.defineOption(&cmlPort);
+ cmlInter.defineOption(&cmlDb);
+ cmlInter.defineOption(&cmlUsr);
+ cmlInter.defineOption(&cmlPasswd);
+ cmlInter.defineOption(&cmlColl);
+ cmlInter.defineOption(&cmlDomain);
+ cmlInter.defineOption(&cmlScale);
+ cmlInter.defineOption(&cmlFile);
+ cmlInter.defineOption(&cmlPolygon);
+ cmlInter.defineOption(&cmlBgr);
+ cmlInter.defineOption(&cmlHelp);
+}
+
+void
+getParams()
+{
+ CmlOption* ptr=NULL;
+
+ ptr=cmlInter.getOption(&cmlSrv);
+ cmlSrv=*((CmlStringOption*)ptr);
+
+ ptr=cmlInter.getOption(&cmlPort);
+ cmlPort=*((CmlStringOption*)ptr);
+
+ ptr=cmlInter.getOption(&cmlDb);
+ cmlDb=*((CmlStringOption*)ptr);
+
+ ptr=cmlInter.getOption(&cmlUsr);
+ cmlUsr=*((CmlStringOption*)ptr);
+
+ ptr=cmlInter.getOption(&cmlPasswd);
+ cmlPasswd=*((CmlStringOption*)ptr);
+
+ ptr=cmlInter.getOption(&cmlColl);
+ cmlColl=*((CmlStringOption*)ptr);
+
+ ptr=cmlInter.getOption(&cmlDomain);
+ cmlDomain=*((CmlStringOption*)ptr);
+
+ ptr=cmlInter.getOption(&cmlScale);
+ cmlScale=*((CmlStringOption*)ptr);
+
+ ptr=cmlInter.getOption(&cmlFile);
+ cmlFile=*((CmlStringOption*)ptr);
+
+ ptr=cmlInter.getOption(&cmlPolygon);
+ cmlPolygon=*((CmlStringOption*)ptr);
+
+ ptr=cmlInter.getOption(&cmlBgr);
+ cmlBgr=*((CmlStringOption*)ptr);
+
+ ptr=cmlInter.getOption(&cmlHelp);
+ cmlHelp=*((CmlBoolOption*)ptr);
+
+ ptr=NULL;
+}
+
+bool
+parseParams(int argc, char** argv)
+{
+ try
+ {
+ defineParams();
+ cmlInter.interpretArguments(argc, argv);
+ getParams();
+ }
+ catch(CmlError& err)
+ {
+ cout << "Command Line Parsing Error:" << endl << err.getText() << endl;
+ return false;
+ }
+
+ //check rule
+ if(cmlColl.isPresent() &&
+ cmlDomain.isPresent() &&
+ cmlFile.isPresent()
+ )
+ return true;
+ else
+ {
+ cout << "Error some of mandatory arguments are missing!" << endl;
+ cout << "Please check your command line!" << endl;
+ return false;
+ }
+}
+
+bool
+fillPolygon(r_Polygon& myPoly)
+{
+
+ char* startPos = (char*)cmlPolygon.getString();
+ char* endPos=NULL;
+ int pointStrLen=0, pointNo=0;
+ char currPoint[MYSTRINGSIZE];
+ r_Point myPoint;
+
+
+ //cout << "start decoding polygon string"<< endl;
+
+ while(true)
+ {
+ strcpy(currPoint, "");
+ startPos = index(startPos, '[');
+ if(!startPos) {
+ // Did not find a closing [, that's it.
+ break;
+ }
+
+ endPos = index(startPos, ']');
+ if(!endPos) {
+ // Did not find a closing ], that's it.
+ break;
+ }
+
+ // try to add point
+ pointStrLen = endPos - startPos + 1;
+ strncpy(currPoint, startPos, pointStrLen);
+ currPoint[pointStrLen+1] = '\0';
+
+ try
+ {
+ myPoint=r_Point(currPoint);
+ myPoly.addPoint( myPoint );
+ pointNo++;
+ //cout << "-point " << pointNo << " : " << currPoint << endl;
+ }
+ catch(r_Error& err)
+ {
+ cout << "Error decoding point \"" << currPoint << "\" from polygon string \""
+ << cmlPolygon.getString() << " !" << endl;
+ return false;
+ }
+ startPos += pointStrLen;
+ }
+
+ if(!pointNo)
+ {
+ cout << "Error no points found, while decoding polygon string \"" << cmlPolygon.getString() << "\" !" << endl;
+ return false;
+ }
+
+ //cout << "end decoding"<< endl;
+
+ myPoly.close();
+
+ return true;
+}
+
+bool
+parseBgr()
+{
+ static char hexval[]= { 0x00, 0x01, 0x02, 0x03,
+ 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b,
+ 0x0c, 0x0d, 0x0e, 0x0f,
+ };
+ static char hexfig[]= { '0', '1', '2', '3',
+ '4', '5', '6', '7',
+ '8', '9', 'a', 'b',
+ 'c', 'd', 'e', 'f',
+ '\0'};
+
+ static r_Bytes sizeBgrMin=2, sizeHexFig=strlen(hexfig);
+ char* pBgr=(char*)cmlBgr.getString();
+ r_Bytes sizeBgr=strlen(pBgr), sizerBgr=0, indexFigure=0, indexHexFig=0;
+
+ if(sizeBgr <= sizeBgrMin)
+ {
+ cout << "Error decoding background \"" << pBgr << "\", is not a hex string !" << endl;
+ return false;
+ }
+
+ if (pBgr[0] !='0' || (pBgr[1] != 'x' && pBgr[1]!='X'))
+ {
+ cout << "Error decoding background \"" << pBgr << "\", 0x or 0X is missing !" << endl;
+ return false;
+ }
+
+ if(sizeBgr%sizeBgrMin)
+ {
+ sizerBgr=(sizeBgr-sizeBgrMin+1)/sizeBgrMin;
+ }
+ else
+ sizerBgr=(sizeBgr-sizeBgrMin)/sizeBgrMin;
+
+ rBgr=new char [sizeBgr+1];
+ memset(rBgr,'\0', sizeBgr+1);
+
+ //skip tag 0x/0X
+ pBgr+=sizeBgrMin;
+
+ while (*pBgr)
+ {
+ //check figure
+ indexHexFig=0;
+ while(indexHexFig<sizeHexFig)
+ {
+ if (tolower(*pBgr) == hexfig[indexHexFig])
+ break;
+ indexHexFig++;
+ }
+
+ if(indexHexFig>=sizeHexFig)
+ {
+ cout << "Error decoding background \"" << pBgr << "\", \"" << *pBgr << "\" is no a hex value !" << endl;
+ delete[] rBgr;
+ return false;
+ }
+
+ //set value figure
+ if(indexFigure%sizeBgrMin)
+ {
+#if defined(LITTLE_ENDIAN)
+ rBgr[indexFigure/sizeBgrMin]=rBgr[indexFigure/sizeBgrMin] * 16 + hexval[indexHexFig];
+#else
+ rBgr[indexFigure/sizeBgrMin]=rBgr[indexFigure/sizeBgrMin]+ hexval[indexHexFig] * 16;
+#endif
+ }
+ else
+ rBgr[indexFigure/sizeBgrMin]=hexval[indexHexFig];
+
+ //advance
+ pBgr++;
+ indexFigure++;
+ }
+
+ return true;
+}
+
+
+bool
+detectParams()
+{
+ r_Long rPort=0;
+
+ // server name
+ if(!cmlSrv.isPresent())
+ cmlSrv.setValue(DefaultSrv);
+
+ // server port
+ if(!cmlPort.isPresent())
+ cmlPort.setValue(DefaultPort);
+ else
+ {
+ try
+ {
+ rPort=cmlPort.getLong();
+ }
+ catch(CmlError& err)
+ {
+ cout << "Error decoding " << cmlPort.getLongForm() << " \"" << cmlPort.getString()
+ << "\" isn't a number!" << endl;
+ return false;
+ }
+ if (rPort <= 0.)
+ {
+ cout << "Error decoding " << cmlPort.getLongForm() << " \"" << cmlPort.getString()
+ << "\" is negative or zero !" << endl;
+ return false;
+ }
+ }
+
+ // database name
+ if(!cmlDb.isPresent())
+ cmlDb.setValue(DefaultDb);
+
+ // user name
+ if(!cmlUsr.isPresent())
+ cmlUsr.setValue(DefaultUsr);
+
+ // user passord
+ if(!cmlPasswd.isPresent())
+ cmlPasswd.setValue(DefaultPasswd);
+
+ // scale factor
+ if(!cmlScale.isPresent())
+ rScale=DefaultScale;
+ else
+ {
+ try
+ {
+ rScale=cmlScale.getDouble();
+ }
+ catch(CmlError& err)
+ {
+ cout << "Error decoding " << cmlScale.getLongForm() << " \"" << cmlScale.getString()
+ << "\" isn't a number!" << endl;
+ return false;
+ }
+ if (rScale <= 0.)
+ {
+ cout << "Error decoding " << cmlScale.getLongForm() << " \"" << cmlScale.getString()
+ << "\" is negative or zero !" << endl;
+ return false;
+ }
+ }
+
+ // collection name
+ // nothing to check here
+
+ // collection domain
+ try
+ {
+ r_Minterval test(cmlDomain.getString());
+ }
+ catch(r_Error& err)
+ {
+ cout << "Error while decoding " << cmlDomain.getLongForm() << " \"" << cmlDomain.getString() << "\" !" << endl;
+ cout << "Error " << err.get_errorno() << " : " << err.what() << endl;
+ return false;
+ }
+
+ // filename
+ //nothing to be checked here
+
+ // polygon
+ if(cmlPolygon.isPresent())
+ {
+ if(!fillPolygon(poly))
+ return false;
+
+ //FIXME
+ //is convex?
+ if(poly.detectPolygonType()!=r_Polygon::CONVEX)
+ {
+ cout << "We support only simple convex polygon now. Please check your polygon !" << endl;
+ return false;
+ }
+ }
+
+ // background
+ if(cmlBgr.isPresent())
+ return parseBgr();
+
+ return true;
+}
+
+
+
+bool
+exportData()
+{
+
+ // At the moment we do just a quick check for the TIFF writing using r_Conversion.
+ // Now we do a query and store the result as a TIFF using r_Conversion.
+
+ // Ok, the whole TIFF conversion thing is done below. Now let's get an
+ // array from RasDaMan here.
+ r_Ref<r_GMarray> mddObj;
+ r_Fast_Base_Scale *scaler=NULL;
+ r_Minterval trimDom(cmlDomain.getString());
+ r_Minterval tiffDom, currDom, insertionUnit(2), clipDom(2);
+ r_Minterval collDom;
+ r_Point trimExtent;
+ r_Polygon myPoly;
+
+ // 5 MB buffer for spooling images
+ r_ULong bufSize = 5 * 1024 * 1024;
+ //size of base type
+ r_Bytes typeSize = 1;
+ // no of scan lines in buffer
+ r_ULong numScanLineInBuf=0;
+ //tiff strip object
+ r_TIFFStripe* myTiff=NULL;
+
+ try
+ {
+ db.set_servername(cmlSrv.getString(), cmlPort.getLong());
+ db.set_useridentification(cmlUsr.getString(), cmlPasswd.getString());
+ db.open(cmlDb.getString());
+
+ try
+ {
+ ta.begin( r_Transaction::read_only );
+ scaler = new r_Fast_Scale<r_Char>(cmlColl.getString());
+ collDom = scaler->get_full_domain();
+ }
+ catch( r_Error& errorObj )
+ {
+ cout << "Error while initializing collection " << cmlColl.getString() << " !" << endl;
+ cout << "Error " << errorObj.get_errorno() << " : " << errorObj.what() << endl;
+ ta.abort();
+ db.close();
+ if(rBgr)
+ {
+ delete[] rBgr;
+ rBgr=NULL;
+ }
+ return false;
+ }
+
+ if (!collDom.covers(trimDom))
+ {
+ cout << "Error, the requested domain " << trimDom << " is not in the collection domain " << collDom << " !" << endl;
+
+ if(scaler)
+ {
+ delete scaler;
+ scaler=NULL;
+ }
+
+ ta.abort();
+ db.close();
+
+ if(rBgr)
+ {
+ delete[] rBgr;
+ rBgr=NULL;
+ }
+
+ return false;
+ }
+
+ // Ok, now here we split the domain in stripes. We take a roughly 5 MB buffer. It
+ // is calculated using the original domain of the area to be retrieved and scale^2
+ // to calculate the memory used without calculating the domains back and forth.
+
+ insertionUnit[0] = trimDom[0]; // we take the whole width of the image.
+
+ trimExtent=trimDom.get_extent();
+ numScanLineInBuf = bufSize / ( typeSize * trimExtent[0] * rScale * rScale);
+ numScanLineInBuf = numScanLineInBuf > trimExtent[1] ? trimExtent[1] : numScanLineInBuf;
+
+ if(numScanLineInBuf < 1) //if numScanLine is 0 as result of division
+ numScanLineInBuf=1;
+
+ insertionUnit[1] = r_Sinterval((r_Range)0, (r_Range)(numScanLineInBuf - 1));
+
+ try {
+ scaler->get_scaled_domain(trimDom, tiffDom, rScale);
+ }
+ catch( r_Error& errorObj ){
+ cout << "Error while getting the scaled domain !" << endl;
+ cout << "Error " << errorObj.get_errorno() << " : " << errorObj.what() << endl;
+ if(scaler)
+ {
+ delete scaler;
+ scaler=NULL;
+ }
+
+ ta.abort();
+ db.close();
+
+ if(rBgr)
+ {
+ delete[] rBgr;
+ rBgr=NULL;
+ }
+ return false;
+ }
+
+
+ if(cmlPolygon.isPresent())
+ {
+ // we scale the polygon according to the scale factor
+ cout << "Defined Polygon: " << poly << endl;
+ poly.scale(collDom.get_origin(), rScale);
+ cout << "Scaled Polygon: " << poly << endl;
+ }
+
+ myTiff = new r_TIFFStripe(cmlFile.getString(), tiffDom);
+ myTiff->openTiff();
+
+ cout << "Retrieving area " << trimDom << " of object " << cmlColl.getString()
+ << " with scale factor " << rScale << "." << endl;
+ cout << "Retrieving units of shape " << insertionUnit << "." << endl;
+ cout << "Tiff Image area " << tiffDom << endl;
+
+ r_MiterArea myIter(&insertionUnit, &trimDom);
+ while( !myIter.isDone() ) {
+ currDom = myIter.nextArea();
+ cout << " Getting " << currDom << " with scale factor " << rScale << "." << endl;
+ try {
+ mddObj = scaler->get_scaled_object(currDom, rScale, 1);
+ }
+ catch( r_Error& errorObj )
+ {
+ cout << "Error while getting the scaled domain !" << endl;
+ cout << "Error " << errorObj.get_errorno() << " : " << errorObj.what() << endl;
+ if(myTiff)
+ {
+ myTiff->closeTiff();
+ delete myTiff;
+ myTiff=NULL;
+ }
+ if(scaler)
+ {
+ delete scaler;
+ scaler=NULL;
+ }
+
+ ta.abort();
+ db.close();
+
+ if(rBgr)
+ {
+ delete[] rBgr;
+ rBgr=NULL;
+ }
+ return false;
+ }
+
+ // The polygonal cutout is currently not done. We will need a scale function with the
+ // same semantics as fastscale for it to work. Then the polygon can be specified in
+ // original pixel coordinates and will be scaled according to the scaling factor.
+
+ if(cmlPolygon.isPresent()) {
+ // we clip the polygon it according to the scaled domain retrieved by r_Fast_Scale
+
+ // original polygon is modified by clip function
+ myPoly=poly;
+
+ scaler->get_scaled_domain(currDom, clipDom, rScale);
+ cout << "Domain for clipping: " << clipDom << endl;
+
+ //FIXME
+ //quick hack for test_polygon because get_scaled_image
+ //returns the clipDom translated in currDom.get_origin()
+ mddObj->set_spatial_domain(clipDom);
+
+ myPoly.clip(clipDom);
+ cout << "Clipped polygon: " << myPoly << endl;
+
+
+ // we would have to transpose it here. This is done by the TIFF conversion.
+
+ // REALLY IMPORTANT: The TA has to be open here! Otherwise neither
+ // type info nor domain can be read.
+ try
+ {
+ myPoly.fillMArray(*mddObj, false, rBgr);
+ }
+ catch(r_Error& err)
+ {
+ cout << "Error size of background " << strlen(rBgr) << " bytes "
+ << " is different from mdd base type size " << mddObj->get_type_length()
+ << " bytes !" << endl;
+ mddObj.destroy();
+ throw err;
+ }
+ }//end if(usePolygon)
+
+ // Ok, now we use our r_TIFFStripe class here
+ if(!myTiff->addArray(*mddObj))
+ {
+ if(myTiff)
+ {
+ myTiff->closeTiff();
+ delete myTiff;
+ myTiff=NULL;
+ }
+
+ if(rBgr)
+ {
+ delete[] rBgr;
+ rBgr=NULL;
+ }
+
+ if(scaler)
+ {
+ delete scaler;
+ scaler=NULL;
+ }
+
+ mddObj.destroy();
+
+ ta.abort();
+ db.close();
+
+ return false;
+ }
+ mddObj.destroy();
+ }//end while
+
+ delete scaler;
+ scaler=NULL;
+
+ myTiff->closeTiff();
+ delete myTiff;
+ myTiff=NULL;
+
+ delete[] rBgr;
+ rBgr=NULL;
+
+ ta.commit();
+ db.close();
+ }
+ catch(r_Error & errObj)
+ {
+ cout << "Error while exporting the data !" << endl;
+ cout << "Error " << errObj.get_errorno() << " : " << errObj.what() << endl;
+ if(scaler)
+ {
+ delete scaler;
+ scaler=NULL;
+ }
+
+ ta.abort();
+ db.close();
+
+ if(rBgr)
+ {
+ delete[] rBgr;
+ rBgr = NULL;
+ }
+ if(myTiff)
+ {
+ myTiff->closeTiff();
+ delete myTiff;
+ myTiff = NULL;
+ }
+ return false;
+ }
+
+ return true;
+}
+
+bool
+processRequest(char* name)
+{
+ bool result=false;
+
+ if(detectParams())
+ {
+#if defined(RMANDEBUG)
+ printStatus(name);
+#endif
+ result=exportData();
+ }
+
+ return result;
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ int result=FAILED;
+
+ if(!parseParams(argc, argv))
+ printUsage(argv[0]);
+ else
+ if(cmlHelp.isPresent())
+ {
+ printUsage(argv[0]);
+ result=SUCCES;
+ }
+ else
+ if(processRequest(argv[0]))
+ result=SUCCES;
+ else
+ printUsage(argv[0]);
+ return result;
+
+}
+
diff --git a/rasodmg/test/test_query.cc b/rasodmg/test/test_query.cc
new file mode 100644
index 0000000..b8b8faf
--- /dev/null
+++ b/rasodmg/test/test_query.cc
@@ -0,0 +1,693 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_query.cc
+ *
+ * MODULE: rasodmg
+ *
+ * COMMENTS:
+ * None
+ */
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#include "raslib/template_inst.hh"
+#endif
+
+#ifdef __VISUALC__
+#include <strstrea.h>
+#else
+#include <strstream>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <sstream>
+#include <fstream>
+
+using namespace std;
+
+#ifdef __VISUALC__
+ #define __EXECUTABLE__
+#endif
+
+#include "rasodmg/transaction.hh"
+#include "rasodmg/database.hh"
+
+#include "rasodmg/ref.hh"
+
+#include "rasodmg/set.hh"
+#include "rasodmg/marray.hh"
+#include "rasodmg/iterator.hh"
+#include "rasodmg/oqlquery.hh"
+
+#include "raslib/type.hh"
+
+#include "raslib/minterval.hh"
+
+#include "raslib/primitive.hh"
+#include "raslib/complex.hh"
+#include "raslib/structure.hh"
+
+#include "raslib/structuretype.hh"
+#include "raslib/primitivetype.hh"
+
+#include "rasodmg/storagelayout.hh"
+
+#include "rasodmg/alignedtiling.hh"
+#include "rasodmg/dirtiling.hh"
+#include "rasodmg/dirdecompose.hh"
+#include "rasodmg/interesttiling.hh"
+#include "rasodmg/stattiling.hh"
+
+#ifdef __VISUALC__
+ #undef __EXECUTABLE__
+#endif
+
+const int MAX_STR_LEN = 255;
+const int MAX_QUERY_LEN = 10240;
+
+bool printText = false;
+
+int checkArguments( int argc, char** argv, const char* searchText, int& optionValueIndex )
+{
+ int found = 0;
+ int i=1;
+
+ while( !found && i<argc )
+ found = !strcmp( searchText, argv[i++] );
+
+ if( found && i<argc && (argv[i][0] != '-') )
+ optionValueIndex = i;
+ else
+ optionValueIndex = 0;
+
+ return found;
+}
+
+
+void printScalar( const r_Scalar& scalar )
+{
+ switch( scalar.get_type()->type_id() )
+ {
+ case r_Type::BOOL:
+ std::cout << ( ((r_Primitive*)&scalar)->get_boolean() ? "T" : "F" ) << std::flush;
+ break;
+
+ case r_Type::CHAR:
+ std::cout << (int)((r_Primitive*)&scalar)->get_char() << std::flush;
+ break;
+
+ case r_Type::OCTET:
+ std::cout << (int)((r_Primitive*)&scalar)->get_octet() << std::flush;
+ break;
+
+ case r_Type::SHORT:
+ std::cout << ((r_Primitive*)&scalar)->get_short() << std::flush;
+ break;
+
+ case r_Type::USHORT:
+ std::cout << ((r_Primitive*)&scalar)->get_ushort() << std::flush;
+ break;
+
+ case r_Type::LONG:
+ std::cout << ((r_Primitive*)&scalar)->get_long() << std::flush;
+ break;
+
+ case r_Type::ULONG:
+ std::cout << ((r_Primitive*)&scalar)->get_ulong() << std::flush;
+ break;
+
+ case r_Type::FLOAT:
+ std::cout << ((r_Primitive*)&scalar)->get_float() << std::flush;
+ break;
+
+ case r_Type::DOUBLE:
+ std::cout << ((r_Primitive*)&scalar)->get_double() << std::flush;
+ break;
+
+ case r_Type::COMPLEXTYPE1:
+ case r_Type::COMPLEXTYPE2:
+ std::cout << "(" << ((r_Complex*)&scalar)->get_re() << ", " << ((r_Complex*)&scalar)->get_im() << ")" << std::flush;
+ break;
+
+ case r_Type::STRUCTURETYPE:
+ {
+ r_Structure* structValue = (r_Structure*)&scalar;
+
+ std::cout << "{ " << std::flush;
+
+ for( int i=0; i<structValue->count_elements(); i++ )
+ {
+ printScalar( (*structValue)[i] );
+
+ if( i < structValue->count_elements()-1 ) std::cout << ", " << std::flush;
+ }
+
+ std::cout << " }" << std::endl;
+ }
+ break;
+ default:
+ std::cout << "scalar type " << scalar.get_type()->type_id() << " not supported!" << std::endl;
+ break;
+ }
+}
+
+void printUsage(char* name){
+ std::cout << name << "v1.1 systemtest query utility " << std::endl;
+ std::cout << "Description: Systemtest query utility for query execution in RasDaMan" << std::endl;
+ std::cout << "Usage: " << name << " [options]" << std::endl << std::endl;
+ std::cout << "Options: -h ... this help" << std::endl;
+ std::cout << " -server <srvname> ... name of server.(mandatory)" << std::endl;
+ std::cout << " -port <nnnn> ... port of server.(default 7001)" << std::endl;
+ std::cout << " -base <dbname> ... name of database.(madatory)" << std::endl;
+ std::cout << " -file <filename> ... file name used to read query from a file" << std::endl;
+ std::cout << " -user <usrname> ... user name.(default rasguest)" << std::endl;
+ std::cout << " -passwd <usrpasswd> ... user password.(default rasguest)" << std::endl;
+ std::cout << " -transferformat <format> ... transfer format.(default Array)" << std::endl;
+ std::cout << " -transferformatparams <formatparams> ... transfer format parameters.(default NULL)" << std::endl;
+ std::cout << " -storageformat <format> ... storage format.(default Array)" << std::endl;
+ std::cout << " -storageformatparams <formatparams> ... storage format parameters.(default NULL)" << std::endl;
+ std::cout << " -mdddomain <domain> ... MDD domain." << std::endl;
+ std::cout << " -tiling <tiling> ... tiling strategy, only for update query.(default SizeTiling)" << std::endl;
+ std::cout << " -tilingparams <tilingparams> ... tiling strategy params, only for update query.(default 131072)" << std::endl;
+ std::cout << " -hex ... output in hex.(default off)" << std::endl;
+ std::cout << " -nooutput ... no output of MDD content.(default on)" << std::endl;
+ std::cout << " -testbed ... turn on output for testbed.(default off)" << std::endl;
+ std::cout << " -text ... print textual output.(default off)" << std::endl;
+ std::cout << std::endl << std::endl;
+
+ std::cout << "Report bugs to <support@active-knowledge.com>" << std::endl;
+}
+
+r_Tiling*
+getTilingScheme(r_Tiling_Scheme& tilingS, char* tilingP){
+ r_Tiling* retval=NULL;
+
+ try {
+ std::cout << "Creating tiling strategy ..." << std::flush;
+ switch(tilingS) {
+ case r_NoTiling:
+ retval = new r_No_Tiling(tilingP);
+ break;
+ case r_AlignedTiling:
+ retval = new r_Aligned_Tiling(tilingP);
+ break;
+ case r_InterestTiling:
+ retval = new r_Interest_Tiling(tilingP);
+ break;
+ case r_DirectionalTiling:
+ retval = new r_Dir_Tiling(tilingP);
+ break;
+ case r_StatisticalTiling:
+ retval = new r_Stat_Tiling(tilingP);
+ break;
+ default:
+ retval = new r_Size_Tiling(tilingP);
+ break;
+ }
+ std::cout << "OK" << std::flush;
+ }
+ catch(r_Error& err){
+ std::cout << "FAILED" << std::endl;
+ std::cout << "Error " << err.get_errorno() << " : " << err.what() << std::endl;
+ }
+
+ return retval;
+}
+
+int main( int argc, char** argv )
+{
+ int optionValueIndex=0;
+
+ char serverName[MAX_STR_LEN] = "";
+ r_ULong serverPort = 7001;
+ char baseName[MAX_STR_LEN] = "";
+
+ char userName[MAX_STR_LEN] = "rasguest";
+ char userPasswd[MAX_STR_LEN] = "rasguest";
+
+ char fileName[MAX_STR_LEN] = "";
+
+ r_Data_Format transferFormat = r_Array;
+ char *transferFormatParams = NULL;
+ r_Data_Format storageFormat = r_Array;
+ char *storageFormatParams = NULL;
+
+ r_Tiling_Scheme tilingScheme = r_SizeTiling;
+ char* tilingSchemeParams = "131072";
+
+
+ int output = 0;
+ int hexOutput = 0;
+ int testbed = 0;
+
+ r_ULong tileSize=0;
+ r_Minterval tileConfig;
+ r_Minterval mddDomain;
+
+ if( checkArguments( argc, argv, "-h", optionValueIndex ) ) {
+ printUsage(argv[0]);
+ return EXIT_SUCCESS;
+ }
+
+ if( checkArguments( argc, argv, "-server", optionValueIndex ) && optionValueIndex )
+ strcpy( serverName, argv[optionValueIndex] );
+
+ if( checkArguments( argc, argv, "-base", optionValueIndex ) && optionValueIndex )
+ strcpy( baseName, argv[optionValueIndex] );
+
+ if( checkArguments( argc, argv, "-file", optionValueIndex ) && optionValueIndex )
+ strcpy( fileName, argv[optionValueIndex] );
+
+ if(!strcmp(serverName, "") ||
+ !strcmp(baseName, "") ||
+ !strcmp(fileName, "") ) {
+ std::cerr << "Mandatory parameters are missing!" << std::endl;
+ printUsage(argv[0]);
+ return EXIT_SUCCESS;
+ }
+
+ hexOutput = checkArguments( argc, argv, "-hex", optionValueIndex );
+ printText = checkArguments( argc, argv, "-text", optionValueIndex );
+ output = !checkArguments( argc, argv, "-nooutput", optionValueIndex );
+ testbed = checkArguments( argc, argv, "-testbed", optionValueIndex );
+
+ if( checkArguments( argc, argv, "-mdddomain", optionValueIndex ) && optionValueIndex )
+ mddDomain = r_Minterval( argv[optionValueIndex] );
+
+ if( checkArguments( argc, argv, "-tileconf", optionValueIndex ) && optionValueIndex )
+ tileConfig = r_Minterval( argv[optionValueIndex] );
+
+ if( checkArguments( argc, argv, "-tilesize", optionValueIndex ) && optionValueIndex )
+ tileSize = strtoul( argv[optionValueIndex], (char **)NULL, 10 ) ;
+
+ if( checkArguments( argc, argv, "-port", optionValueIndex ) && optionValueIndex )
+ serverPort = strtoul( argv[optionValueIndex], (char **)NULL, 10 ) ;
+
+ if( checkArguments( argc, argv, "-user", optionValueIndex ) && optionValueIndex )
+ strcpy( userName, argv[optionValueIndex] );
+
+ if( checkArguments( argc, argv, "-passwd", optionValueIndex ) && optionValueIndex )
+ strcpy( userPasswd, argv[optionValueIndex] );
+
+ if( checkArguments( argc, argv, "-transferformat", optionValueIndex ) && optionValueIndex ) {
+ transferFormat = get_data_format_from_name( argv[optionValueIndex] );
+ if(transferFormat == r_Data_Format_NUMBER) {
+ std::cerr << "Invalid transfer format '" << argv[optionValueIndex] << "' switched to " << r_Array << std::endl;
+ transferFormat = r_Array;
+ }
+ }
+
+ if( checkArguments( argc, argv, "-transferformatparams", optionValueIndex ) && optionValueIndex )
+ transferFormatParams = argv[optionValueIndex] ;
+
+ if( checkArguments( argc, argv, "-storageformat", optionValueIndex ) && optionValueIndex ) {
+ storageFormat = get_data_format_from_name(argv[optionValueIndex] );
+ if(storageFormat == r_Data_Format_NUMBER) {
+ std::cerr << "Invalid storage format '" << argv[optionValueIndex] << "' switched to " << r_Array << std::endl;
+ storageFormat = r_Array;
+ }
+ }
+
+ if( checkArguments( argc, argv, "-storageformatparams", optionValueIndex ) && optionValueIndex )
+ storageFormatParams = argv[optionValueIndex] ;
+
+ if( checkArguments( argc, argv, "-tiling", optionValueIndex ) && optionValueIndex ) {
+ tilingScheme = get_tiling_scheme_from_name( argv[optionValueIndex] );
+ if(tilingScheme == r_Tiling_Scheme_NUMBER) {
+ std::cerr << "Invalid tiling scheme '" << argv[optionValueIndex] << "' switched to " << r_SizeTiling << std::endl;
+ tilingScheme = r_SizeTiling;
+ }
+ if(tilingScheme == r_RegularTiling) {
+ std::cerr << "Tiling scheme '" << argv[optionValueIndex] << "' not supported, switched to " << r_SizeTiling << std::endl;
+ tilingScheme = r_SizeTiling;
+ }
+ }
+
+ if( checkArguments( argc, argv, "-tilingparams", optionValueIndex ) && optionValueIndex )
+ tilingSchemeParams = argv[optionValueIndex] ;
+
+
+#ifdef __VISUALC__
+ std::ifstream fileStream( fileName, ios::nocreate );
+ if( !fileStream.is_open() )
+#else
+ std::ifstream fileStream( fileName );
+ if( !fileStream )
+#endif
+ {
+ std::cout << "Error: File not found." << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ std::ostringstream queryStream;
+
+ queryStream << "-- " << fileName << std::endl;
+
+ char ch;
+ while( fileStream.get(ch) ) queryStream.put(ch);
+
+ queryStream << std::ends;
+
+ std::cout << std::endl << std::endl;
+
+ r_Database db;
+ r_Transaction ta;
+
+ db.set_servername( serverName, serverPort );
+ db.set_useridentification( userName, userPasswd );
+
+ try
+ {
+ std::cout << "Creating query string ..."<< std::flush;
+ r_OQL_Query q1( queryStream.str().c_str() );
+ std::cout << "OK" << std::endl;
+ std::cout << "The query is: " << std::endl;
+
+ std::cout << q1.get_query() << std::endl;
+
+ std::cout << "Opening Database " << baseName << " on " << serverName << "... "<< std::flush;
+ db.open( baseName );
+ std::cout << "OK" << std::endl;
+
+ if( q1.is_update_query() )
+ {
+ std::cout << "Starting Update Transaction ... "<< std::flush;
+ ta.begin();
+ std::cout << "OK" << std::endl;
+
+ std::cout << "Setting transfer and storage formats ... " << std::flush;
+ db.set_transfer_format( transferFormat, transferFormatParams );
+ db.set_storage_format( storageFormat, storageFormatParams );
+ std::cout << "OK" << std::endl;
+
+ r_Marray<r_ULong>* mddConst = NULL;
+ r_Tiling* tilingObj = NULL;
+ r_Storage_Layout* stl = NULL;
+
+
+ std::cout << "Executing the update query ..."<< std::flush;
+
+ if( strstr( queryStream.str().c_str(), "$" ) )
+ {
+ r_Minterval domain;
+ if( mddDomain.dimension() )
+ domain = mddDomain;
+ else
+ domain = r_Minterval("[0:10,0:10]");
+
+ // create storage layout object
+
+ try {
+ tilingObj = getTilingScheme(tilingScheme, tilingSchemeParams);
+
+ stl = new r_Storage_Layout( tilingObj );
+
+ // mddConst = new( "GreyCube" ) r_Marray<r_Char>( domain, (unsigned char)0, stl );
+ mddConst = new( "ULongImage" ) r_Marray<r_ULong>( domain, (r_ULong)9, stl );
+ // mddConst = new( "FloatCube4" ) r_Marray<r_Float>( domain, 9ul, stl );
+
+ q1 << *mddConst;
+ }
+ catch(r_Error& errorObj) {
+ std::cout << "FAILED" << std::endl;
+ std::cout << "Error " << errorObj.get_errorno() << " : " << errorObj.what() << std::endl;
+
+ if( testbed )
+ {
+ std::cout << "-- Testbed line: error_no=" << errorObj.get_errorno() << std::endl;
+ std::cout << std::endl;
+ }
+
+ std::cout << "Aborting Transaction ... "<< std::flush;
+ ta.abort();
+ std::cout << "OK" << std::endl;
+
+ std::cout << "Closing Database ... "<< std::flush;
+ db.close();
+
+ std::cout << "OK" << std::endl;
+
+ if( mddConst ) delete mddConst;
+ else
+ if( stl ) delete stl;
+ else if(tilingObj) delete tilingObj;
+
+ return EXIT_FAILURE;
+ }
+ }
+
+ try
+ {
+ r_oql_execute( q1 );
+ }
+ catch( r_Error& errorObj )
+ {
+ std::cout << "FAILED" << std::endl;
+ std::cout << "Error " << errorObj.get_errorno() << " : " << errorObj.what() << std::endl;
+
+ if( testbed )
+ {
+ std::cout << "-- Testbed line: error_no=" << errorObj.get_errorno() << std::endl;
+ std::cout << std::endl;
+ }
+
+ std::cout << "Aborting Transaction ... " << std::flush;
+ ta.abort();
+ std::cout << "OK" << std::endl;
+
+ std::cout << "Closing Database ... " << std::flush;
+ db.close();
+
+ std::cout << "OK" << std::endl;
+
+ if( mddConst ) delete mddConst;
+
+ return EXIT_FAILURE;
+ }
+ std::cout << "OK" << std::endl;
+
+ if( mddConst ) delete mddConst;
+ }
+ else
+ {
+ std::cout << "Starting Read Only Transaction ... " << std::flush;
+ ta.begin( r_Transaction::read_only );
+ std::cout << "OK" << std::endl;
+
+ std::cout << "Setting transfer and storage formats ... " << std::flush;
+ db.set_transfer_format( transferFormat, transferFormatParams );
+ db.set_storage_format( storageFormat, storageFormatParams );
+ std::cout << "OK" << std::endl;
+
+ r_Set< r_Ref_Any > result_set;
+
+ std::cout << "Executing the retrieval query ..." << std::flush;
+
+ try
+ {
+ r_oql_execute( q1, result_set );
+ }
+ catch( r_Error& errorObj )
+ {
+ std::cout << "FAILED" << std::endl;
+ std::cout << "Error " << errorObj.get_errorno() << " : " << errorObj.what() << std::endl;
+
+ if( testbed )
+ {
+ std::cout << "-- Testbed line: error_no=" << errorObj.get_errorno() << std::endl;
+ std::cout << std::endl;
+ }
+
+ std::cout << "Aborting Transaction ... " << std::flush;
+ ta.abort();
+ std::cout << "OK" << std::endl;
+
+ std::cout << "Closing Database ... " << std::flush;
+ db.close();
+ std::cout << "OK" << std::endl;
+
+ return EXIT_FAILURE;
+ }
+
+ std::cout << "OK" << std::endl;
+ std::cout << "Collection" << std::endl;
+ std::cout << " Oid...................: " << result_set.get_oid() << std::endl;
+ std::cout << " Type Structure........: "
+ << ( result_set.get_type_structure() ? result_set.get_type_structure() : "<nn>" ) << std::endl;
+ std::cout << " Type Schema...........: " << std::flush;
+ if( result_set.get_type_schema() )
+ result_set.get_type_schema()->print_status( std::cout );
+ else
+ std::cout << "<nn>" << std::flush;
+ std::cout << std::endl;
+ std::cout << " Number of entries.....: " << result_set.cardinality() << std::endl;
+ std::cout << " Element Type Schema...: " << std::flush;
+ if( result_set.get_element_type_schema() )
+ result_set.get_element_type_schema()->print_status( std::cout );
+ else
+ std::cout << "<nn>" << std::flush;
+ std::cout << std::endl;
+
+ if( testbed )
+ {
+ std::cout << "-- Testbed line: result_type=" << result_set.get_type_structure() << std::endl;
+ std::cout << "-- Testbed line: result_elements=" << result_set.cardinality() << std::endl;
+ std::cout << std::endl;
+ }
+
+ /* The following can be used, if the type is known and the element type is not atomic.
+
+ r_Set< r_Ref< r_Point > >* set2 = (r_Set< r_Ref< r_Point > >*)&result_set;
+ r_Iterator< r_Ref<r_Point> > iter2 = set2->create_iterator();
+ for( iter2.reset(); iter2.not_done(); iter2++ )
+ std::cout << **iter2 << std::endl;
+ */
+
+ if( output || testbed )
+ {
+ r_Iterator< r_Ref_Any > iter = result_set.create_iterator();
+
+ std::cout << std::endl;
+
+ if( testbed )
+ std::cout << "-- Testbed start block:" << std::endl;
+
+ for ( int i=1 ; iter.not_done(); iter++, i++ )
+ {
+ switch( result_set.get_element_type_schema()->type_id() )
+ {
+ case r_Type::MARRAYTYPE:
+ {
+ const char *defExt;
+ r_Data_Format mafmt = r_Ref<r_GMarray>(*iter)->get_current_format();
+
+ // special treatment only for DEFs
+ switch (mafmt)
+ {
+ case r_TIFF:
+ defExt = "tif"; break;
+ case r_JPEG:
+ defExt = "jpg"; break;
+ case r_HDF:
+ defExt = "hdf"; break;
+ case r_PNG:
+ defExt = "png"; break;
+ case r_BMP:
+ defExt = "bmp"; break;
+ case r_VFF:
+ defExt = "vff"; break;
+ default:
+ defExt = NULL;
+ }
+
+ if( defExt == NULL )
+ {
+ std::cout << "Image " << i << std::endl;
+ if (printText)
+ {
+ int numCells = r_Ref<r_GMarray>(*iter)->get_array_size();
+ const char* theStuff = r_Ref<r_GMarray>(*iter)->get_array();
+ for (int cnt = 0; cnt < numCells; cnt++)
+ std::cout << theStuff[cnt];
+ std::cout << std::endl;
+ }
+ else {
+ r_Ref<r_GMarray>(*iter)->print_status( std::cout, hexOutput );
+ }
+ std::cout << std::endl;
+ }
+ else
+ {
+ char defFileName[256];
+
+ sprintf( defFileName, "image%d.%s", i, defExt );
+ std::cout << "Image " << i << " written to " << defFileName << std::endl;
+
+ FILE *tfile = fopen( defFileName, "wb" );
+ fwrite((void*)r_Ref<r_GMarray>(*iter)->get_array(), 1,
+ r_Ref<r_GMarray>(*iter)->get_array_size(), tfile );
+ fclose(tfile);
+ }
+ }
+ break;
+
+ case r_Type::POINTTYPE:
+ std::cout << "Element " << i << ": " << *(r_Ref<r_Point>(*iter)) << std::endl;
+ break;
+
+ case r_Type::SINTERVALTYPE:
+ std::cout << "Element " << i << ": " << *(r_Ref<r_Sinterval>(*iter)) << std::endl;
+ break;
+
+ case r_Type::MINTERVALTYPE:
+ std::cout << "Element " << i << ": " << *(r_Ref<r_Minterval>(*iter)) << std::endl;
+ break;
+
+ case r_Type::OIDTYPE:
+ std::cout << "Element " << i << ": " << *(r_Ref<r_OId>(*iter)) << std::endl;
+ break;
+
+ default:
+ std::cout << "Element " << i << ": " << std::flush;
+ printScalar( *(r_Ref<r_Scalar>(*iter)) );
+ std::cout << std::endl;
+ // or simply
+ // r_Ref<r_Scalar>(*iter)->print_status( std::cout );
+ }
+ }
+
+ if( testbed )
+ std::cout << "-- Testbed end block:" << std::endl;
+
+ std::cout << std::endl;
+ }
+
+ } // retrieval query
+
+ std::cout << "Commiting Transaction ... " << std::endl;
+ ta.commit();
+ std::cout << "OK" << std::endl;
+
+ std::cout << "Closing Database ... " << std::flush;
+ db.close();
+ std::cout << "OK" << std::endl;
+ }
+ catch( r_Error& errorObj )
+ {
+ std::cout << "FAILED" << std::endl;
+ std::cout << "Error " << errorObj.get_errorno() << " : " << errorObj.what() << std::endl;
+ ta.abort();
+ db.close();
+ if( testbed )
+ {
+ std::cout << "-- Testbed line: error_no=" << errorObj.get_errorno() << std::endl;
+ std::cout << std::endl;
+ }
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
diff --git a/rasodmg/test/test_ref.cc b/rasodmg/test/test_ref.cc
new file mode 100644
index 0000000..1da5d68
--- /dev/null
+++ b/rasodmg/test/test_ref.cc
@@ -0,0 +1,69 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_ref.cc
+ *
+ * MODULE: rasodmg
+ *
+ * COMMENTS:
+ * None
+*/
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#include "raslib/template_inst.hh"
+#endif
+
+#include <iostream>
+#include "rasodmg/ref.hh"
+
+class X
+{
+ public:
+ int a;
+};
+
+int main()
+{
+ cout << endl << endl;
+ cout << "r_Ref tests" << endl;
+ cout << "===========" << endl << endl;
+
+ r_Ref<X> ptr;
+ r_Ref<int> ptr2;
+
+ cout << "r_Ref created. is_null() ? " << ptr.is_null() << endl;
+
+ ptr = new X;
+
+ cout << "r_Ref assigned to pointer of base type. is_null() ? " << ptr.is_null() << endl;
+
+ (*ptr).a = 1;
+ cout << "assignment *ptr.a = 1. Current value ? " << (*ptr).a << endl;
+ ptr->a = 2;
+ cout << "assignment ptr->a = 2. Current value ? " << ptr->a << endl;
+
+ ptr.destroy(); // delete from memory
+
+ return 0;
+}
diff --git a/rasodmg/test/test_set.cc b/rasodmg/test/test_set.cc
new file mode 100644
index 0000000..a6bbc0f
--- /dev/null
+++ b/rasodmg/test/test_set.cc
@@ -0,0 +1,104 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_set.cc
+ *
+ * MODULE: rasodmg
+ *
+ * COMMENTS:
+ *
+*/
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#include "raslib/template_inst.hh"
+#endif
+
+#include <iostream>
+#include "rasodmg/set.hh"
+
+int main()
+{
+ int v,x,y,z;
+
+ v = 100;
+ x = 200;
+ y = 100;
+ z = 300;
+
+ cout << endl << endl;
+ cout << "Set Examples" << endl;
+ cout << "=============" << endl << endl;
+
+ cout << "Creating r_Set of type int." << endl;
+ r_Set<int> a;
+
+ cout << "Cardinality of empty set 'a': " << a.cardinality() << endl << endl;
+
+ cout << "Now inserting four elements:" << endl << "v = 100" << endl;
+ a.insert_element(v);
+
+ cout << "x = 200" << endl;
+ a.insert_element(x);
+
+ cout << "y = 100 (should fail in sets)" << endl;
+ a.insert_element(y);
+
+ cout << "z = 300" << endl;
+ a.insert_element(z);
+
+ cout << "Cardinality of collection 'a' after four inserts: " << a.cardinality() << endl << endl;
+
+ cout << "Does 'a' contain element '100' (1=TRUE/0=FALSE)? " << a.contains_element(100) << endl;
+
+ cout << "Does 'a' contain element '500' (1=TRUE/0=FALSE)? " << a.contains_element(500) << endl << endl;
+
+ cout << "Now removing element 'x=200' from 'a'." << endl;
+ a.remove_element(x);
+ cout << "Cardinality of 'a' now: " << a.cardinality() << endl << endl;
+
+ cout << "Now removing element '100' from 'a'." << endl;
+ a.remove_element(100);
+ cout << "Cardinality of 'a' now: " << a.cardinality() << endl << endl;
+
+ cout << "Now removing (non-existing) element '500' from 'a'." << endl;
+ a.remove_element(500);
+ cout << "Cardinality of 'a' now: " << a.cardinality() << endl << endl;
+
+ cout << "Testing assignment operator on r_Sets." << endl << "(creating r_Set 'b' that is equal to 'a'.)" <<endl;
+ r_Set<int> b;
+ b = a;
+ cout << "Cardinality of 'b': " << b.cardinality() << endl << endl;
+
+ cout << "Testing copy constructor of r_Set." << endl << "(creating r_Set 'c' that is equal to 'a'.)" <<endl;
+ r_Set<int> c(a);
+ cout << "Cardinality of 'c': " << c.cardinality() << endl << endl;
+
+ cout << "Now removing all elements from 'a'." << endl;
+ a.remove_all();
+ cout << "Cardinality of 'a' now: " << a.cardinality() << endl;
+ cout << "Cardinality of 'b' is still: " << b.cardinality() << endl;
+ cout << "Cardinality of 'c' is still: " << c.cardinality() << endl << endl;
+
+ return 0;
+}
diff --git a/rasodmg/test/test_stattiling.cc b/rasodmg/test/test_stattiling.cc
new file mode 100644
index 0000000..a1a1f44
--- /dev/null
+++ b/rasodmg/test/test_stattiling.cc
@@ -0,0 +1,173 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_interestrtiling.cc
+ *
+ * MODULE: rasodmg
+ *
+ * PURPOSE: test class r_StatTiling.
+ *
+ * COMMENTS:
+ * None
+*/
+
+/*
+ ATENTION: The format of the input file for using with this program is:
+
+ border_threshold accesses_threshold tilesize domain
+ access1
+ access2
+ accessXXX
+ ...
+
+ Example:
+
+ 50 0.20 1000 [0:799, 0:599]
+ [10:20, 30:40]
+ [12:20, 35:39]
+ [100:300, 300:400]
+ [120:300, 310:410]
+ [200:500, 350:500]
+ [200:510, 350:500]
+*/
+
+
+#include <iostream>
+#include <stdio.h>
+#include "rasodmg/marray.hh"
+#include "rasodmg/tiling.hh"
+#include "raslib/dlist.hh"
+#include "rasodmg/stattiling.hh"
+#include "raslib/minterval.hh"
+#include "raslib/sinterval.hh"
+
+char* filename;
+DList<r_Access> stat_info;
+unsigned int border_threshold;
+double interesting_threshold;
+unsigned long tile_size;
+r_Minterval* domain;
+
+void parse(int argc, char* argv[])
+{
+ if (argc != 2)
+ {
+ cout << "Usage: test_stattiling <filename>" << endl << endl;
+ exit(1);
+ }
+
+ filename = argv[1];
+}
+
+void read_data()
+{
+ const unsigned int BUF_SIZE = 256;
+ char buf[BUF_SIZE], buf2[BUF_SIZE];
+
+ cout << "Opening " << filename << " for reading... ";
+
+ ifstream is(filename, ios::in);
+ if (!is)
+ {
+ cout << "Couldn't open!!!" << endl;
+ exit(1);
+ }
+ else
+ cout << "done." << endl;
+
+ cout << "Reading parameters... ";
+
+ is >> border_threshold;
+ is >> interesting_threshold;
+ is >> tile_size;
+
+ is.getline(buf, BUF_SIZE);
+ domain = new r_Minterval(buf);
+
+ cout << "done." << endl;
+ cout << "Geting the accesses... ";
+
+ unsigned long count = 0;
+
+ while (!is.eof())
+ {
+ is.getline(buf, BUF_SIZE);
+ if (sscanf(buf, "%s", buf2) == 1)
+ {
+ r_Minterval inter(buf);
+ stat_info += inter;
+ ++count;
+
+ cout << "*";
+ }
+ }
+
+ is.close();
+
+ cout << endl;
+ cout << "Geting the accesses... done." << endl << endl;
+
+ cout << "Border threshold = " << border_threshold << endl;
+ cout << "Interesting threshold = " << interesting_threshold << endl;
+ cout << "Tile size = " << tile_size << endl;
+ cout << "Domain = " << *domain << endl;
+ cout << "Number of accesses = " << count << endl << endl;
+}
+
+void test_tiling()
+{
+ r_Stat_Tiling tiling(border_threshold, interesting_threshold, tile_size);
+ tiling.update_stat_information(stat_info);
+
+ DList<r_Minterval>* tiles = tiling.compute_tiles(*domain, 1);
+
+ cout << endl << "Tiles: " << endl;
+ while (!tiles->is_empty())
+ {
+ r_Minterval inter = tiles->get_first(TRUE);
+ cout << " " << inter << endl;
+ }
+
+ delete tiles;
+ delete domain;
+}
+
+int main(int argc, char* argv[])
+{
+ parse(argc, argv);
+ read_data();
+ test_tiling();
+
+ return 0;
+}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/rasodmg/test/test_storage.cc b/rasodmg/test/test_storage.cc
new file mode 100644
index 0000000..81c1261
--- /dev/null
+++ b/rasodmg/test/test_storage.cc
@@ -0,0 +1,282 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_storage.cc
+ *
+ * MODULE: rasodmg
+ *
+ * COMMENTS:
+ * None
+*/
+
+#include <iostream>
+#include <string.h>
+
+#ifdef __VISUALC__
+ #define __EXECUTABLE__
+#endif
+#include "rasodmg/ref.hh"
+#include "rasodmg/transaction.hh"
+#include "rasodmg/database.hh"
+#include "rasodmg/set.hh"
+#include "rasodmg/marray.hh"
+#include "raslib/odmgtypes.hh"
+#include "rasodmg/storagelayout.hh"
+#include "rasodmg/alignedtiling.hh"
+#include "rasodmg/dirdecompose.hh"
+#include "rasodmg/dirtiling.hh"
+
+#ifdef __VISUALC__
+ #undef __EXECUTABLE__
+#endif
+
+static int INIT = 0;
+
+r_ULong initWithCounter( const r_Point& /*pt*/ )
+{
+ return INIT++;
+}
+
+
+r_ULong initWithCrossfoot( const r_Point& pt )
+{
+ r_ULong value=0;
+
+ for( r_Dimension i=0; i< pt.dimension(); i++ )
+ value += pt[i];
+
+ return value;
+}
+
+
+r_ULong initWithCoordinates( const r_Point& pt )
+{
+ r_ULong value=0;
+ int factor=1;
+
+ for( int i=pt.dimension()-1; i >= 0; i-- )
+ {
+ value += factor * pt[i];
+ factor *= 100;
+ }
+
+ return value;
+}
+
+
+
+int checkArguments( int argc, char** argv, const char* searchText, int& optionValueIndex )
+{
+ int found = 0;
+ int i=1;
+
+ while( !found && i<argc )
+ found = !strcmp( searchText, argv[i++] );
+
+ if( found && i<argc && !strchr(argv[i],'-') )
+ optionValueIndex = i;
+ else
+ optionValueIndex = 0;
+
+ return found;
+}
+
+
+
+
+int main( int argc, char** argv )
+{
+ char serverName[255];
+ char baseName[255];
+ char collName[255];
+ int optionValueIndex;
+
+ if( argc < 4 || checkArguments( argc, argv, "-h", optionValueIndex ) )
+ {
+ cout << "Usage: test_storage server_name base_name collection_name [options]" << endl << endl;
+ cout << "Options: -h ... this help" << endl;
+ // cout << " -nooutput ... no output of MDD content" << endl;
+ // cout << " -hex ... output in hex" << endl;
+ cout << endl;
+ return 0;
+ }
+
+ strcpy( serverName, argv[1] );
+ strcpy( baseName, argv[2] );
+ strcpy( collName, argv[3] );
+
+ cout << endl << endl;
+ cout << "ODMG conformant insertion of Marrays" << endl;
+ cout << "====================================" << endl << endl;
+
+ r_Database db;
+ r_Transaction ta;
+ r_Ref< r_Set< r_Ref< r_Marray<r_ULong> > > > image_set;
+ r_Ref< r_Marray<r_ULong> > image1, image2, image3, image4;
+ r_Minterval domain, domain2;
+
+ domain = r_Minterval(2) << r_Sinterval( 0, 100 ) << r_Sinterval( 0, 100 );
+
+ // Default storage layout
+ r_Storage_Layout* sl1 = new r_Storage_Layout;
+ cout << "sl1 " << *sl1 <<endl;
+
+ // Default tiling with a different tile size than the previous one:
+ r_Size_Tiling* til2 = new r_Size_Tiling( 40000 );
+ r_Storage_Layout* sl2 = new r_Storage_Layout( til2 );
+ //, r_Storage_Layout::No_Compression );
+ cout << "sl2 " << *sl2 <<endl;
+
+ // Aligned Tiling
+ r_Aligned_Tiling* til3 = new r_Aligned_Tiling( r_Minterval("[0:1,0:2]"), 3200 );
+ // cout << *til3;
+ r_Storage_Layout* sl3 = new r_Storage_Layout( til3 );
+ cout << "sl3 " << *sl3 <<endl;
+
+ // Directional Tiling
+ vector<r_Dir_Decompose> decompVec;
+ r_Dir_Decompose decompI, decompII;
+ decompI << 0 << 10 << 20 << 40 << 60 << 70 << 100;
+ decompII << 0 << 10 << 20 << 40 << 60 << 70 << 100;
+ decompVec.push_back(decompI);
+ decompVec.push_back(decompII);
+ r_Dir_Tiling* til4 = new r_Dir_Tiling( 2, decompVec );
+ r_Storage_Layout* sl4 = new r_Storage_Layout( til4 );
+ cout << "sl4 " << *sl4 <<endl;
+
+ // FIXME adapt this to test also statistical, interest and no tiling
+/*
+ // Interest Tiling
+ vector<r_Dir_Decompose> decompVec;
+ r_Dir_Decompose decompI, decompII;
+ decompI << 0 << 10 << 20 << 40 << 60 << 70 << 100;
+ decompII << 0 << 10 << 20 << 40 << 60 << 70 << 100;
+ decompVec.push_back(decompI);
+ decompVec.push_back(decompII);
+ r_Dir_Tiling* til4 = new r_Dir_Tiling( 2, decompVec );
+ r_Storage_Layout* sl4 = new r_Storage_Layout( til4 );
+ cout << "sl4 " << *sl4 <<endl;
+
+ // Statistic Tiling
+ vector<r_Dir_Decompose> decompVec;
+ r_Dir_Decompose decompI, decompII;
+ decompI << 0 << 10 << 20 << 40 << 60 << 70 << 100;
+ decompII << 0 << 10 << 20 << 40 << 60 << 70 << 100;
+ decompVec.push_back(decompI);
+ decompVec.push_back(decompII);
+ r_Dir_Tiling* til4 = new r_Dir_Tiling( 2, decompVec );
+ r_Storage_Layout* sl4 = new r_Storage_Layout( til4 );
+ cout << "sl4 " << *sl4 <<endl;
+
+ // No Tiling
+ vector<r_Dir_Decompose> decompVec;
+ r_Dir_Decompose decompI, decompII;
+ decompI << 0 << 10 << 20 << 40 << 60 << 70 << 100;
+ decompII << 0 << 10 << 20 << 40 << 60 << 70 << 100;
+ decompVec.push_back(decompI);
+ decompVec.push_back(decompII);
+ r_Dir_Tiling* til4 = new r_Dir_Tiling( 2, decompVec );
+ r_Storage_Layout* sl4 = new r_Storage_Layout( til4 );
+ cout << "sl4 " << *sl4 <<endl;
+*/
+
+
+ db.set_servername( serverName );
+
+ try
+ {
+ cout << "Opening Database " << baseName << " on " << serverName << "... " << flush;
+ db.open( baseName );
+ cout << "OK" << endl;
+
+ cout << "Starting Transaction ... " << flush;
+ ta.begin();
+ cout << "OK" << endl;
+
+ cout << "Opening the set ... " << flush;
+
+ try{
+ image_set = db.lookup_object( collName );
+ }
+ catch( r_Error &obj )
+ {
+ cout << "FAILED" << endl;
+ // cout << obj.what() << endl;
+
+ //
+ // set doesn't exist -> create the set
+ //
+
+ cout << "Create the set ... " << flush;
+
+ // create the set
+ image_set = new( &db, "ULongSet" ) r_Set< r_Ref< r_Marray<r_ULong> > >;
+
+ // create a name for the persistent set in order to be able to look it up again
+ db.set_object_name( *image_set, collName );
+ }
+
+ cout << "OK" << endl;
+
+ cout << "Creating four images ... " << flush;
+
+ // create first image
+ image1 = new( &db, "ULongImage" ) r_Marray<r_ULong>( domain, (r_ULong)0, sl1 );
+
+ // create second image
+ image2 = new( &db, "ULongImage" ) r_Marray<r_ULong>( domain, &initWithCrossfoot, sl2 );
+
+ // create third image
+ image3 = new( &db, "ULongImage" ) r_Marray<r_ULong>( domain, &initWithCounter, sl3 );
+
+ // create fourth image
+ image4 = new( &db, "ULongImage" ) r_Marray<r_ULong>( domain, &initWithCoordinates, sl4 );
+
+ cout << "OK" << endl;
+
+ cout << "Inserting them into the set " << collName << " ... " << flush;
+
+ // insert the images
+ image_set->insert_element( image1 );
+ image_set->insert_element( image2 );
+ image_set->insert_element( image3 );
+ image_set->insert_element( image4 );
+
+ cout << "OK" << endl;
+
+ cout << "Commiting Transaction ... " << flush;
+ ta.commit();
+ cout << "OK" << endl;
+
+ cout << "Closing Database ... " << flush;
+ db.close();
+ cout << "OK" << endl;
+ }
+ catch( r_Error& errorObj )
+ {
+ cerr << errorObj.what() << endl;
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/rasodmg/test/test_transaction.cc b/rasodmg/test/test_transaction.cc
new file mode 100644
index 0000000..faa12b3
--- /dev/null
+++ b/rasodmg/test/test_transaction.cc
@@ -0,0 +1,152 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#include <iostream>
+#include <stdio.h>
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#endif
+
+#include "rasodmg/database.hh"
+#include "rasodmg/transaction.hh"
+#include "rasodmg/marray.hh"
+#include "rasodmg/ref.hh"
+#include "rasodmg/set.hh"
+#include "rasodmg/oqlquery.hh"
+
+
+#define STRINGSIZE 256
+
+
+int main(int argc, char *argv[])
+{
+ char dbname[STRINGSIZE] = "";
+ char servername[STRINGSIZE] = "";
+ char collname[STRINGSIZE] = "tTAcoll";
+ r_Range range_low = 0;
+ r_Range range_high = 15;
+
+ int i;
+
+ i = 1;
+ while (i < argc)
+ {
+ if (argv[i][0] == '-')
+ {
+ switch (argv[i][1])
+ {
+ case 's':
+ strcpy(servername, argv[++i]);
+ break;
+ case 'd':
+ strcpy(dbname, argv[++i]);
+ break;
+ case 'c':
+ strcpy(collname, argv[++i]);
+ break;
+ case 'h':
+ cout << "Usage: " << argv[0] << " -s servername -d dbname" << endl;
+ exit(0);
+ }
+ }
+ i++;
+ }
+
+ if ((strlen(servername) == 0) || (strlen(dbname) == 0))
+ {
+ cerr << "Must specify servername and databasename!" << endl;
+ exit(-1);
+ }
+
+ r_Database db;
+
+ try
+ {
+ cout << "Trying to open " << dbname << " on " << servername << "... ";
+ cout << flush;
+ db.set_servername(servername);
+ db.open(dbname);
+ cout << "OK" << endl;
+ }
+ catch (r_Error &err)
+ {
+ cout << "failed." << endl;
+ cerr << err.what();
+ return -1;
+ }
+
+ r_Transaction ta;
+ char queryString[STRINGSIZE];
+
+ try
+ {
+ ta.begin();
+ sprintf(queryString, "CREATE COLLECTION %s GreySet", collname);
+ cout << "Collection " << collname << flush;
+ r_OQL_Query query(queryString);
+ r_oql_execute(query);
+ ta.commit();
+ cout << " created." << endl;
+ }
+ catch (r_Error &err)
+ {
+ ta.abort();
+ cout << " not created: " << err.what() << endl;
+ }
+
+ try
+ {
+ r_Sinterval siv = r_Sinterval(range_low, range_high);
+ r_Minterval interv(2);
+ interv << siv << siv;
+ r_Ref<r_Marray<char> > mddPtr = new ("GreyImage") r_Marray<char>(interv);
+ memset(mddPtr->get_array(), 0, interv.cell_count());
+
+ ta.begin();
+
+ cout << "Starting write transaction, press return to commit..." << flush;
+
+ sprintf(queryString, "INSERT INTO %s VALUES $1", collname);
+ r_OQL_Query query(queryString);
+ query << (*mddPtr);
+ r_oql_execute(query);
+
+ while (fgetc(stdin) == EOF) ;
+
+ ta.commit();
+
+ cout << "Write transaction successful." << endl;
+ }
+ catch(r_Error &err)
+ {
+ cerr << "Write transaction failed: " << err.what() << endl;
+ ta.abort();
+ db.close();
+ exit(0);
+ }
+
+ db.close();
+
+ return 0;
+}
diff --git a/rasodmg/test/tmov_16.ql b/rasodmg/test/tmov_16.ql
new file mode 100644
index 0000000..2742c4d
--- /dev/null
+++ b/rasodmg/test/tmov_16.ql
@@ -0,0 +1,425 @@
+// This query tests different selectivities with moving query boxes
+// on tomo_cubed with 16kB tiles ([0:24,0:24,0:24]). Each selectivity
+// is repeated 20 times with query boxes of the same shape and size
+// starting at different origins.
+
+// [0.5]: [39:83, 43:87, 117:143]
+SELECT img[39:83, 43:87, 117:143]
+FROM tomo_cubed_16 AS img
+// [0.5]: [146:190, 116:160, 35:61]
+SELECT img[146:190, 116:160, 35:61]
+FROM tomo_cubed_16 AS img
+// [0.5]: [17:61, 42:86, 15:41]
+SELECT img[17:61, 42:86, 15:41]
+FROM tomo_cubed_16 AS img
+// [0.5]: [112:156, 154:198, 108:134]
+SELECT img[112:156, 154:198, 108:134]
+FROM tomo_cubed_16 AS img
+// [0.5]: [138:182, 26:70, 48:74]
+SELECT img[138:182, 26:70, 48:74]
+FROM tomo_cubed_16 AS img
+// [0.5]: [53:97, 94:138, 22:48]
+SELECT img[53:97, 94:138, 22:48]
+FROM tomo_cubed_16 AS img
+// [0.5]: [190:234, 59:103, 17:43]
+SELECT img[190:234, 59:103, 17:43]
+FROM tomo_cubed_16 AS img
+// [0.5]: [118:162, 147:191, 30:56]
+SELECT img[118:162, 147:191, 30:56]
+FROM tomo_cubed_16 AS img
+// [0.5]: [210:254, 179:223, 18:44]
+SELECT img[210:254, 179:223, 18:44]
+FROM tomo_cubed_16 AS img
+// [0.5]: [129:173, 76:120, 102:128]
+SELECT img[129:173, 76:120, 102:128]
+FROM tomo_cubed_16 AS img
+// [0.5]: [199:243, 119:163, 59:85]
+SELECT img[199:243, 119:163, 59:85]
+FROM tomo_cubed_16 AS img
+// [0.5]: [47:91, 52:96, 108:134]
+SELECT img[47:91, 52:96, 108:134]
+FROM tomo_cubed_16 AS img
+// [0.5]: [87:131, 103:147, 11:37]
+SELECT img[87:131, 103:147, 11:37]
+FROM tomo_cubed_16 AS img
+// [0.5]: [32:76, 81:125, 87:113]
+SELECT img[32:76, 81:125, 87:113]
+FROM tomo_cubed_16 AS img
+// [0.5]: [14:58, 77:121, 0:26]
+SELECT img[14:58, 77:121, 0:26]
+FROM tomo_cubed_16 AS img
+// [0.5]: [128:172, 145:189, 21:47]
+SELECT img[128:172, 145:189, 21:47]
+FROM tomo_cubed_16 AS img
+// [0.5]: [185:229, 102:146, 60:86]
+SELECT img[185:229, 102:146, 60:86]
+FROM tomo_cubed_16 AS img
+// [0.5]: [40:84, 39:83, 106:132]
+SELECT img[40:84, 39:83, 106:132]
+FROM tomo_cubed_16 AS img
+// [0.5]: [37:81, 10:54, 51:77]
+SELECT img[37:81, 10:54, 51:77]
+FROM tomo_cubed_16 AS img
+// [0.5]: [46:90, 21:65, 102:128]
+SELECT img[46:90, 21:65, 102:128]
+FROM tomo_cubed_16 AS img
+// [1]: [199:254, 50:105, 11:44]
+SELECT img[199:254, 50:105, 11:44]
+FROM tomo_cubed_16 AS img
+// [1]: [180:235, 51:106, 91:124]
+SELECT img[180:235, 51:106, 91:124]
+FROM tomo_cubed_16 AS img
+// [1]: [199:254, 43:98, 113:146]
+SELECT img[199:254, 43:98, 113:146]
+FROM tomo_cubed_16 AS img
+// [1]: [78:133, 40:95, 37:70]
+SELECT img[78:133, 40:95, 37:70]
+FROM tomo_cubed_16 AS img
+// [1]: [11:66, 98:153, 19:52]
+SELECT img[11:66, 98:153, 19:52]
+FROM tomo_cubed_16 AS img
+// [1]: [90:145, 74:129, 83:116]
+SELECT img[90:145, 74:129, 83:116]
+FROM tomo_cubed_16 AS img
+// [1]: [82:137, 103:158, 1:34]
+SELECT img[82:137, 103:158, 1:34]
+FROM tomo_cubed_16 AS img
+// [1]: [186:241, 191:246, 47:80]
+SELECT img[186:241, 191:246, 47:80]
+FROM tomo_cubed_16 AS img
+// [1]: [143:198, 68:123, 77:110]
+SELECT img[143:198, 68:123, 77:110]
+FROM tomo_cubed_16 AS img
+// [1]: [188:243, 23:78, 94:127]
+SELECT img[188:243, 23:78, 94:127]
+FROM tomo_cubed_16 AS img
+// [1]: [71:126, 11:66, 75:108]
+SELECT img[71:126, 11:66, 75:108]
+FROM tomo_cubed_16 AS img
+// [1]: [89:144, 109:164, 12:45]
+SELECT img[89:144, 109:164, 12:45]
+FROM tomo_cubed_16 AS img
+// [1]: [47:102, 56:111, 14:47]
+SELECT img[47:102, 56:111, 14:47]
+FROM tomo_cubed_16 AS img
+// [1]: [24:79, 190:245, 77:110]
+SELECT img[24:79, 190:245, 77:110]
+FROM tomo_cubed_16 AS img
+// [1]: [14:69, 189:244, 0:33]
+SELECT img[14:69, 189:244, 0:33]
+FROM tomo_cubed_16 AS img
+// [1]: [198:253, 167:222, 117:150]
+SELECT img[198:253, 167:222, 117:150]
+FROM tomo_cubed_16 AS img
+// [1]: [125:180, 1:56, 113:146]
+SELECT img[125:180, 1:56, 113:146]
+FROM tomo_cubed_16 AS img
+// [1]: [90:145, 126:181, 109:142]
+SELECT img[90:145, 126:181, 109:142]
+FROM tomo_cubed_16 AS img
+// [1]: [154:209, 9:64, 47:80]
+SELECT img[154:209, 9:64, 47:80]
+FROM tomo_cubed_16 AS img
+// [1]: [81:136, 1:56, 87:120]
+SELECT img[81:136, 1:56, 87:120]
+FROM tomo_cubed_16 AS img
+// [2]: [116:185, 1:70, 77:119]
+SELECT img[116:185, 1:70, 77:119]
+FROM tomo_cubed_16 AS img
+// [2]: [99:168, 87:156, 20:62]
+SELECT img[99:168, 87:156, 20:62]
+FROM tomo_cubed_16 AS img
+// [2]: [81:150, 74:143, 35:77]
+SELECT img[81:150, 74:143, 35:77]
+FROM tomo_cubed_16 AS img
+// [2]: [16:85, 100:169, 56:98]
+SELECT img[16:85, 100:169, 56:98]
+FROM tomo_cubed_16 AS img
+// [2]: [180:249, 47:116, 92:134]
+SELECT img[180:249, 47:116, 92:134]
+FROM tomo_cubed_16 AS img
+// [2]: [78:147, 57:126, 9:51]
+SELECT img[78:147, 57:126, 9:51]
+FROM tomo_cubed_16 AS img
+// [2]: [160:229, 76:145, 39:81]
+SELECT img[160:229, 76:145, 39:81]
+FROM tomo_cubed_16 AS img
+// [2]: [95:164, 29:98, 26:68]
+SELECT img[95:164, 29:98, 26:68]
+FROM tomo_cubed_16 AS img
+// [2]: [143:212, 120:189, 35:77]
+SELECT img[143:212, 120:189, 35:77]
+FROM tomo_cubed_16 AS img
+// [2]: [163:232, 116:185, 78:120]
+SELECT img[163:232, 116:185, 78:120]
+FROM tomo_cubed_16 AS img
+// [2]: [116:185, 58:127, 69:111]
+SELECT img[116:185, 58:127, 69:111]
+FROM tomo_cubed_16 AS img
+// [2]: [38:107, 169:238, 0:42]
+SELECT img[38:107, 169:238, 0:42]
+FROM tomo_cubed_16 AS img
+// [2]: [87:156, 112:181, 41:83]
+SELECT img[87:156, 112:181, 41:83]
+FROM tomo_cubed_16 AS img
+// [2]: [14:83, 118:187, 37:79]
+SELECT img[14:83, 118:187, 37:79]
+FROM tomo_cubed_16 AS img
+// [2]: [24:93, 172:241, 27:69]
+SELECT img[24:93, 172:241, 27:69]
+FROM tomo_cubed_16 AS img
+// [2]: [105:174, 14:83, 21:63]
+SELECT img[105:174, 14:83, 21:63]
+FROM tomo_cubed_16 AS img
+// [2]: [54:123, 92:161, 0:42]
+SELECT img[54:123, 92:161, 0:42]
+FROM tomo_cubed_16 AS img
+// [2]: [151:220, 160:229, 58:100]
+SELECT img[151:220, 160:229, 58:100]
+FROM tomo_cubed_16 AS img
+// [2]: [73:142, 42:111, 73:115]
+SELECT img[73:142, 42:111, 73:115]
+FROM tomo_cubed_16 AS img
+// [2]: [38:107, 181:250, 25:67]
+SELECT img[38:107, 181:250, 25:67]
+FROM tomo_cubed_16 AS img
+// [5]: [82:176, 43:137, 32:88]
+SELECT img[82:176, 43:137, 32:88]
+FROM tomo_cubed_16 AS img
+// [5]: [114:208, 6:100, 52:108]
+SELECT img[114:208, 6:100, 52:108]
+FROM tomo_cubed_16 AS img
+// [5]: [116:210, 132:226, 29:85]
+SELECT img[116:210, 132:226, 29:85]
+FROM tomo_cubed_16 AS img
+// [5]: [29:123, 69:163, 53:109]
+SELECT img[29:123, 69:163, 53:109]
+FROM tomo_cubed_16 AS img
+// [5]: [85:179, 1:95, 72:128]
+SELECT img[85:179, 1:95, 72:128]
+FROM tomo_cubed_16 AS img
+// [5]: [80:174, 121:215, 27:83]
+SELECT img[80:174, 121:215, 27:83]
+FROM tomo_cubed_16 AS img
+// [5]: [142:236, 129:223, 46:102]
+SELECT img[142:236, 129:223, 46:102]
+FROM tomo_cubed_16 AS img
+// [5]: [130:224, 156:250, 82:138]
+SELECT img[130:224, 156:250, 82:138]
+FROM tomo_cubed_16 AS img
+// [5]: [27:121, 111:205, 45:101]
+SELECT img[27:121, 111:205, 45:101]
+FROM tomo_cubed_16 AS img
+// [5]: [139:233, 122:216, 49:105]
+SELECT img[139:233, 122:216, 49:105]
+FROM tomo_cubed_16 AS img
+// [5]: [12:106, 3:97, 84:140]
+SELECT img[12:106, 3:97, 84:140]
+FROM tomo_cubed_16 AS img
+// [5]: [73:167, 70:164, 1:57]
+SELECT img[73:167, 70:164, 1:57]
+FROM tomo_cubed_16 AS img
+// [5]: [160:254, 1:95, 80:136]
+SELECT img[160:254, 1:95, 80:136]
+FROM tomo_cubed_16 AS img
+// [5]: [152:246, 54:148, 72:128]
+SELECT img[152:246, 54:148, 72:128]
+FROM tomo_cubed_16 AS img
+// [5]: [25:119, 50:144, 55:111]
+SELECT img[25:119, 50:144, 55:111]
+FROM tomo_cubed_16 AS img
+// [5]: [151:245, 34:128, 92:148]
+SELECT img[151:245, 34:128, 92:148]
+FROM tomo_cubed_16 AS img
+// [5]: [28:122, 68:162, 76:132]
+SELECT img[28:122, 68:162, 76:132]
+FROM tomo_cubed_16 AS img
+// [5]: [145:239, 98:192, 44:100]
+SELECT img[145:239, 98:192, 44:100]
+FROM tomo_cubed_16 AS img
+// [5]: [73:167, 122:216, 2:58]
+SELECT img[73:167, 122:216, 2:58]
+FROM tomo_cubed_16 AS img
+// [5]: [1:95, 107:201, 68:124]
+SELECT img[1:95, 107:201, 68:124]
+FROM tomo_cubed_16 AS img
+// [10]: [102:220, 43:161, 75:146]
+SELECT img[102:220, 43:161, 75:146]
+FROM tomo_cubed_16 AS img
+// [10]: [106:224, 36:154, 79:150]
+SELECT img[106:224, 36:154, 79:150]
+FROM tomo_cubed_16 AS img
+// [10]: [95:213, 56:174, 69:140]
+SELECT img[95:213, 56:174, 69:140]
+FROM tomo_cubed_16 AS img
+// [10]: [62:180, 126:244, 74:145]
+SELECT img[62:180, 126:244, 74:145]
+FROM tomo_cubed_16 AS img
+// [10]: [93:211, 63:181, 46:117]
+SELECT img[93:211, 63:181, 46:117]
+FROM tomo_cubed_16 AS img
+// [10]: [129:247, 74:192, 67:138]
+SELECT img[129:247, 74:192, 67:138]
+FROM tomo_cubed_16 AS img
+// [10]: [44:162, 84:202, 75:146]
+SELECT img[44:162, 84:202, 75:146]
+FROM tomo_cubed_16 AS img
+// [10]: [52:170, 107:225, 19:90]
+SELECT img[52:170, 107:225, 19:90]
+FROM tomo_cubed_16 AS img
+// [10]: [89:207, 94:212, 9:80]
+SELECT img[89:207, 94:212, 9:80]
+FROM tomo_cubed_16 AS img
+// [10]: [52:170, 120:238, 67:138]
+SELECT img[52:170, 120:238, 67:138]
+FROM tomo_cubed_16 AS img
+// [10]: [98:216, 51:169, 42:113]
+SELECT img[98:216, 51:169, 42:113]
+FROM tomo_cubed_16 AS img
+// [10]: [30:148, 109:227, 51:122]
+SELECT img[30:148, 109:227, 51:122]
+FROM tomo_cubed_16 AS img
+// [10]: [130:248, 118:236, 30:101]
+SELECT img[130:248, 118:236, 30:101]
+FROM tomo_cubed_16 AS img
+// [10]: [25:143, 25:143, 46:117]
+SELECT img[25:143, 25:143, 46:117]
+FROM tomo_cubed_16 AS img
+// [10]: [86:204, 119:237, 12:83]
+SELECT img[86:204, 119:237, 12:83]
+FROM tomo_cubed_16 AS img
+// [10]: [116:234, 18:136, 11:82]
+SELECT img[116:234, 18:136, 11:82]
+FROM tomo_cubed_16 AS img
+// [10]: [61:179, 24:142, 68:139]
+SELECT img[61:179, 24:142, 68:139]
+FROM tomo_cubed_16 AS img
+// [10]: [53:171, 14:132, 72:143]
+SELECT img[53:171, 14:132, 72:143]
+FROM tomo_cubed_16 AS img
+// [10]: [49:167, 84:202, 64:135]
+SELECT img[49:167, 84:202, 64:135]
+FROM tomo_cubed_16 AS img
+// [10]: [85:203, 80:198, 13:84]
+SELECT img[85:203, 80:198, 13:84]
+FROM tomo_cubed_16 AS img
+// [20]: [97:246, 85:234, 54:143]
+SELECT img[97:246, 85:234, 54:143]
+FROM tomo_cubed_16 AS img
+// [20]: [63:212, 18:167, 43:132]
+SELECT img[63:212, 18:167, 43:132]
+FROM tomo_cubed_16 AS img
+// [20]: [99:248, 28:177, 58:147]
+SELECT img[99:248, 28:177, 58:147]
+FROM tomo_cubed_16 AS img
+// [20]: [57:206, 16:165, 46:135]
+SELECT img[57:206, 16:165, 46:135]
+FROM tomo_cubed_16 AS img
+// [20]: [83:232, 93:242, 36:125]
+SELECT img[83:232, 93:242, 36:125]
+FROM tomo_cubed_16 AS img
+// [20]: [57:206, 31:180, 48:137]
+SELECT img[57:206, 31:180, 48:137]
+FROM tomo_cubed_16 AS img
+// [20]: [86:235, 70:219, 32:121]
+SELECT img[86:235, 70:219, 32:121]
+FROM tomo_cubed_16 AS img
+// [20]: [39:188, 49:198, 50:139]
+SELECT img[39:188, 49:198, 50:139]
+FROM tomo_cubed_16 AS img
+// [20]: [62:211, 104:253, 29:118]
+SELECT img[62:211, 104:253, 29:118]
+FROM tomo_cubed_16 AS img
+// [20]: [103:252, 44:193, 13:102]
+SELECT img[103:252, 44:193, 13:102]
+FROM tomo_cubed_16 AS img
+// [20]: [48:197, 14:163, 2:91]
+SELECT img[48:197, 14:163, 2:91]
+FROM tomo_cubed_16 AS img
+// [20]: [0:149, 79:228, 13:102]
+SELECT img[0:149, 79:228, 13:102]
+FROM tomo_cubed_16 AS img
+// [20]: [6:155, 103:252, 35:124]
+SELECT img[6:155, 103:252, 35:124]
+FROM tomo_cubed_16 AS img
+// [20]: [0:149, 91:240, 46:135]
+SELECT img[0:149, 91:240, 46:135]
+FROM tomo_cubed_16 AS img
+// [20]: [23:172, 50:199, 42:131]
+SELECT img[23:172, 50:199, 42:131]
+FROM tomo_cubed_16 AS img
+// [20]: [80:229, 33:182, 17:106]
+SELECT img[80:229, 33:182, 17:106]
+FROM tomo_cubed_16 AS img
+// [20]: [38:187, 41:190, 1:90]
+SELECT img[38:187, 41:190, 1:90]
+FROM tomo_cubed_16 AS img
+// [20]: [42:191, 17:166, 39:128]
+SELECT img[42:191, 17:166, 39:128]
+FROM tomo_cubed_16 AS img
+// [20]: [98:247, 95:244, 58:147]
+SELECT img[98:247, 95:244, 58:147]
+FROM tomo_cubed_16 AS img
+// [20]: [10:159, 51:200, 21:110]
+SELECT img[10:159, 51:200, 21:110]
+FROM tomo_cubed_16 AS img
+// [50]: [8:210, 13:215, 9:130]
+SELECT img[8:210, 13:215, 9:130]
+FROM tomo_cubed_16 AS img
+// [50]: [48:250, 45:247, 24:145]
+SELECT img[48:250, 45:247, 24:145]
+FROM tomo_cubed_16 AS img
+// [50]: [29:231, 6:208, 23:144]
+SELECT img[29:231, 6:208, 23:144]
+FROM tomo_cubed_16 AS img
+// [50]: [12:214, 44:246, 23:144]
+SELECT img[12:214, 44:246, 23:144]
+FROM tomo_cubed_16 AS img
+// [50]: [11:213, 27:229, 7:128]
+SELECT img[11:213, 27:229, 7:128]
+FROM tomo_cubed_16 AS img
+// [50]: [1:203, 2:204, 14:135]
+SELECT img[1:203, 2:204, 14:135]
+FROM tomo_cubed_16 AS img
+// [50]: [22:224, 50:252, 10:131]
+SELECT img[22:224, 50:252, 10:131]
+FROM tomo_cubed_16 AS img
+// [50]: [15:217, 35:237, 9:130]
+SELECT img[15:217, 35:237, 9:130]
+FROM tomo_cubed_16 AS img
+// [50]: [4:206, 51:253, 28:149]
+SELECT img[4:206, 51:253, 28:149]
+FROM tomo_cubed_16 AS img
+// [50]: [22:224, 20:222, 31:152]
+SELECT img[22:224, 20:222, 31:152]
+FROM tomo_cubed_16 AS img
+// [50]: [16:218, 42:244, 27:148]
+SELECT img[16:218, 42:244, 27:148]
+FROM tomo_cubed_16 AS img
+// [50]: [21:223, 32:234, 22:143]
+SELECT img[21:223, 32:234, 22:143]
+FROM tomo_cubed_16 AS img
+// [50]: [37:239, 44:246, 29:150]
+SELECT img[37:239, 44:246, 29:150]
+FROM tomo_cubed_16 AS img
+// [50]: [17:219, 49:251, 14:135]
+SELECT img[17:219, 49:251, 14:135]
+FROM tomo_cubed_16 AS img
+// [50]: [49:251, 50:252, 3:124]
+SELECT img[49:251, 50:252, 3:124]
+FROM tomo_cubed_16 AS img
+// [50]: [17:219, 15:217, 1:122]
+SELECT img[17:219, 15:217, 1:122]
+FROM tomo_cubed_16 AS img
+// [50]: [21:223, 51:253, 13:134]
+SELECT img[21:223, 51:253, 13:134]
+FROM tomo_cubed_16 AS img
+// [50]: [7:209, 47:249, 11:132]
+SELECT img[7:209, 47:249, 11:132]
+FROM tomo_cubed_16 AS img
+// [50]: [4:206, 22:224, 4:125]
+SELECT img[4:206, 22:224, 4:125]
+FROM tomo_cubed_16 AS img
+// [50]: [16:218, 51:253, 21:142]
+SELECT img[16:218, 51:253, 21:142]
+FROM tomo_cubed_16 AS img
diff --git a/rasodmg/test/tmov_32.ql b/rasodmg/test/tmov_32.ql
new file mode 100644
index 0000000..db9eb7d
--- /dev/null
+++ b/rasodmg/test/tmov_32.ql
@@ -0,0 +1,425 @@
+// This query tests different selectivities with moving query boxes
+// on tomo_cubed with 32kB tiles ([0:31,0:31,0:31]). Each selectivity
+// is repeated 20 times with query boxes of the same shape and size
+// starting at different origins.
+
+// [0.5]: [46:90, 176:220, 60:86]
+SELECT img[46:90, 176:220, 60:86]
+FROM tomo_cubed AS img
+// [0.5]: [143:187, 175:219, 106:132]
+SELECT img[143:187, 175:219, 106:132]
+FROM tomo_cubed AS img
+// [0.5]: [169:213, 75:119, 66:92]
+SELECT img[169:213, 75:119, 66:92]
+FROM tomo_cubed AS img
+// [0.5]: [90:134, 178:222, 48:74]
+SELECT img[90:134, 178:222, 48:74]
+FROM tomo_cubed AS img
+// [0.5]: [76:120, 136:180, 31:57]
+SELECT img[76:120, 136:180, 31:57]
+FROM tomo_cubed AS img
+// [0.5]: [7:51, 150:194, 89:115]
+SELECT img[7:51, 150:194, 89:115]
+FROM tomo_cubed AS img
+// [0.5]: [133:177, 113:157, 0:26]
+SELECT img[133:177, 113:157, 0:26]
+FROM tomo_cubed AS img
+// [0.5]: [114:158, 125:169, 108:134]
+SELECT img[114:158, 125:169, 108:134]
+FROM tomo_cubed AS img
+// [0.5]: [210:254, 12:56, 56:82]
+SELECT img[210:254, 12:56, 56:82]
+FROM tomo_cubed AS img
+// [0.5]: [176:220, 171:215, 83:109]
+SELECT img[176:220, 171:215, 83:109]
+FROM tomo_cubed AS img
+// [0.5]: [102:146, 50:94, 34:60]
+SELECT img[102:146, 50:94, 34:60]
+FROM tomo_cubed AS img
+// [0.5]: [134:178, 96:140, 97:123]
+SELECT img[134:178, 96:140, 97:123]
+FROM tomo_cubed AS img
+// [0.5]: [200:244, 43:87, 123:149]
+SELECT img[200:244, 43:87, 123:149]
+FROM tomo_cubed AS img
+// [0.5]: [155:199, 127:171, 48:74]
+SELECT img[155:199, 127:171, 48:74]
+FROM tomo_cubed AS img
+// [0.5]: [111:155, 80:124, 11:37]
+SELECT img[111:155, 80:124, 11:37]
+FROM tomo_cubed AS img
+// [0.5]: [164:208, 2:46, 64:90]
+SELECT img[164:208, 2:46, 64:90]
+FROM tomo_cubed AS img
+// [0.5]: [137:181, 102:146, 17:43]
+SELECT img[137:181, 102:146, 17:43]
+FROM tomo_cubed AS img
+// [0.5]: [100:144, 149:193, 121:147]
+SELECT img[100:144, 149:193, 121:147]
+FROM tomo_cubed AS img
+// [0.5]: [186:230, 38:82, 108:134]
+SELECT img[186:230, 38:82, 108:134]
+FROM tomo_cubed AS img
+// [0.5]: [48:92, 53:97, 14:40]
+SELECT img[48:92, 53:97, 14:40]
+FROM tomo_cubed AS img
+// [1]: [64:119, 65:120, 57:90]
+SELECT img[64:119, 65:120, 57:90]
+FROM tomo_cubed AS img
+// [1]: [13:68, 121:176, 20:53]
+SELECT img[13:68, 121:176, 20:53]
+FROM tomo_cubed AS img
+// [1]: [3:58, 115:170, 59:92]
+SELECT img[3:58, 115:170, 59:92]
+FROM tomo_cubed AS img
+// [1]: [174:229, 82:137, 93:126]
+SELECT img[174:229, 82:137, 93:126]
+FROM tomo_cubed AS img
+// [1]: [40:95, 143:198, 43:76]
+SELECT img[40:95, 143:198, 43:76]
+FROM tomo_cubed AS img
+// [1]: [126:181, 160:215, 86:119]
+SELECT img[126:181, 160:215, 86:119]
+FROM tomo_cubed AS img
+// [1]: [20:75, 44:99, 89:122]
+SELECT img[20:75, 44:99, 89:122]
+FROM tomo_cubed AS img
+// [1]: [15:70, 92:147, 23:56]
+SELECT img[15:70, 92:147, 23:56]
+FROM tomo_cubed AS img
+// [1]: [122:177, 62:117, 75:108]
+SELECT img[122:177, 62:117, 75:108]
+FROM tomo_cubed AS img
+// [1]: [183:238, 174:229, 70:103]
+SELECT img[183:238, 174:229, 70:103]
+FROM tomo_cubed AS img
+// [1]: [13:68, 82:137, 97:130]
+SELECT img[13:68, 82:137, 97:130]
+FROM tomo_cubed AS img
+// [1]: [174:229, 107:162, 91:124]
+SELECT img[174:229, 107:162, 91:124]
+FROM tomo_cubed AS img
+// [1]: [79:134, 83:138, 88:121]
+SELECT img[79:134, 83:138, 88:121]
+FROM tomo_cubed AS img
+// [1]: [3:58, 62:117, 39:72]
+SELECT img[3:58, 62:117, 39:72]
+FROM tomo_cubed AS img
+// [1]: [96:151, 25:80, 93:126]
+SELECT img[96:151, 25:80, 93:126]
+FROM tomo_cubed AS img
+// [1]: [124:179, 183:238, 21:54]
+SELECT img[124:179, 183:238, 21:54]
+FROM tomo_cubed AS img
+// [1]: [106:161, 111:166, 89:122]
+SELECT img[106:161, 111:166, 89:122]
+FROM tomo_cubed AS img
+// [1]: [66:121, 103:158, 74:107]
+SELECT img[66:121, 103:158, 74:107]
+FROM tomo_cubed AS img
+// [1]: [180:235, 131:186, 80:113]
+SELECT img[180:235, 131:186, 80:113]
+FROM tomo_cubed AS img
+// [1]: [4:59, 132:187, 59:92]
+SELECT img[4:59, 132:187, 59:92]
+FROM tomo_cubed AS img
+// [2]: [69:138, 184:253, 75:117]
+SELECT img[69:138, 184:253, 75:117]
+FROM tomo_cubed AS img
+// [2]: [58:127, 168:237, 87:129]
+SELECT img[58:127, 168:237, 87:129]
+FROM tomo_cubed AS img
+// [2]: [162:231, 145:214, 58:100]
+SELECT img[162:231, 145:214, 58:100]
+FROM tomo_cubed AS img
+// [2]: [129:198, 122:191, 7:49]
+SELECT img[129:198, 122:191, 7:49]
+FROM tomo_cubed AS img
+// [2]: [86:155, 170:239, 54:96]
+SELECT img[86:155, 170:239, 54:96]
+FROM tomo_cubed AS img
+// [2]: [0:69, 98:167, 70:112]
+SELECT img[0:69, 98:167, 70:112]
+FROM tomo_cubed AS img
+// [2]: [41:110, 33:102, 58:100]
+SELECT img[41:110, 33:102, 58:100]
+FROM tomo_cubed AS img
+// [2]: [37:106, 24:93, 65:107]
+SELECT img[37:106, 24:93, 65:107]
+FROM tomo_cubed AS img
+// [2]: [39:108, 114:183, 26:68]
+SELECT img[39:108, 114:183, 26:68]
+FROM tomo_cubed AS img
+// [2]: [166:235, 9:78, 38:80]
+SELECT img[166:235, 9:78, 38:80]
+FROM tomo_cubed AS img
+// [2]: [147:216, 174:243, 45:87]
+SELECT img[147:216, 174:243, 45:87]
+FROM tomo_cubed AS img
+// [2]: [121:190, 69:138, 58:100]
+SELECT img[121:190, 69:138, 58:100]
+FROM tomo_cubed AS img
+// [2]: [87:156, 78:147, 73:115]
+SELECT img[87:156, 78:147, 73:115]
+FROM tomo_cubed AS img
+// [2]: [31:100, 109:178, 75:117]
+SELECT img[31:100, 109:178, 75:117]
+FROM tomo_cubed AS img
+// [2]: [54:123, 155:224, 26:68]
+SELECT img[54:123, 155:224, 26:68]
+FROM tomo_cubed AS img
+// [2]: [150:219, 139:208, 25:67]
+SELECT img[150:219, 139:208, 25:67]
+FROM tomo_cubed AS img
+// [2]: [65:134, 119:188, 87:129]
+SELECT img[65:134, 119:188, 87:129]
+FROM tomo_cubed AS img
+// [2]: [159:228, 45:114, 47:89]
+SELECT img[159:228, 45:114, 47:89]
+FROM tomo_cubed AS img
+// [2]: [77:146, 60:129, 87:129]
+SELECT img[77:146, 60:129, 87:129]
+FROM tomo_cubed AS img
+// [2]: [169:238, 135:204, 4:46]
+SELECT img[169:238, 135:204, 4:46]
+FROM tomo_cubed AS img
+// [5]: [24:118, 61:155, 77:133]
+SELECT img[24:118, 61:155, 77:133]
+FROM tomo_cubed AS img
+// [5]: [137:231, 119:213, 11:67]
+SELECT img[137:231, 119:213, 11:67]
+FROM tomo_cubed AS img
+// [5]: [140:234, 131:225, 56:112]
+SELECT img[140:234, 131:225, 56:112]
+FROM tomo_cubed AS img
+// [5]: [154:248, 6:100, 54:110]
+SELECT img[154:248, 6:100, 54:110]
+FROM tomo_cubed AS img
+// [5]: [146:240, 62:156, 60:116]
+SELECT img[146:240, 62:156, 60:116]
+FROM tomo_cubed AS img
+// [5]: [78:172, 21:115, 3:59]
+SELECT img[78:172, 21:115, 3:59]
+FROM tomo_cubed AS img
+// [5]: [80:174, 33:127, 84:140]
+SELECT img[80:174, 33:127, 84:140]
+FROM tomo_cubed AS img
+// [5]: [138:232, 95:189, 52:108]
+SELECT img[138:232, 95:189, 52:108]
+FROM tomo_cubed AS img
+// [5]: [60:154, 136:230, 70:126]
+SELECT img[60:154, 136:230, 70:126]
+FROM tomo_cubed AS img
+// [5]: [79:173, 149:243, 65:121]
+SELECT img[79:173, 149:243, 65:121]
+FROM tomo_cubed AS img
+// [5]: [13:107, 53:147, 57:113]
+SELECT img[13:107, 53:147, 57:113]
+FROM tomo_cubed AS img
+// [5]: [13:107, 66:160, 44:100]
+SELECT img[13:107, 66:160, 44:100]
+FROM tomo_cubed AS img
+// [5]: [137:231, 47:141, 38:94]
+SELECT img[137:231, 47:141, 38:94]
+FROM tomo_cubed AS img
+// [5]: [11:105, 84:178, 42:98]
+SELECT img[11:105, 84:178, 42:98]
+FROM tomo_cubed AS img
+// [5]: [19:113, 31:125, 51:107]
+SELECT img[19:113, 31:125, 51:107]
+FROM tomo_cubed AS img
+// [5]: [27:121, 17:111, 29:85]
+SELECT img[27:121, 17:111, 29:85]
+FROM tomo_cubed AS img
+// [5]: [142:236, 76:170, 94:150]
+SELECT img[142:236, 76:170, 94:150]
+FROM tomo_cubed AS img
+// [5]: [153:247, 71:165, 83:139]
+SELECT img[153:247, 71:165, 83:139]
+FROM tomo_cubed AS img
+// [5]: [12:106, 108:202, 79:135]
+SELECT img[12:106, 108:202, 79:135]
+FROM tomo_cubed AS img
+// [5]: [146:240, 26:120, 59:115]
+SELECT img[146:240, 26:120, 59:115]
+FROM tomo_cubed AS img
+// 1[0]: [3:121, 62:180, 39:110]
+SELECT img[3:121, 62:180, 39:110]
+FROM tomo_cubed AS img
+// 1[0]: [11:129, 26:144, 19:90]
+SELECT img[11:129, 26:144, 19:90]
+FROM tomo_cubed AS img
+// 1[0]: [49:167, 76:194, 77:148]
+SELECT img[49:167, 76:194, 77:148]
+FROM tomo_cubed AS img
+// [10]: [55:173, 86:204, 21:92]
+SELECT img[55:173, 86:204, 21:92]
+FROM tomo_cubed AS img
+// [10]: [110:228, 98:216, 80:151]
+SELECT img[110:228, 98:216, 80:151]
+FROM tomo_cubed AS img
+// [10]: [123:241, 28:146, 59:130]
+SELECT img[123:241, 28:146, 59:130]
+FROM tomo_cubed AS img
+// [10]: [89:207, 90:208, 34:105]
+SELECT img[89:207, 90:208, 34:105]
+FROM tomo_cubed AS img
+// [10]: [111:229, 51:169, 5:76]
+SELECT img[111:229, 51:169, 5:76]
+FROM tomo_cubed AS img
+// [10]: [15:133, 74:192, 12:83]
+SELECT img[15:133, 74:192, 12:83]
+FROM tomo_cubed AS img
+// [10]: [103:221, 94:212, 74:145]
+SELECT img[103:221, 94:212, 74:145]
+FROM tomo_cubed AS img
+// [10]: [107:225, 111:229, 16:87]
+SELECT img[107:225, 111:229, 16:87]
+FROM tomo_cubed AS img
+// [10]: [14:132, 80:198, 58:129]
+SELECT img[14:132, 80:198, 58:129]
+FROM tomo_cubed AS img
+// [10]: [2:120, 64:182, 25:96]
+SELECT img[2:120, 64:182, 25:96]
+FROM tomo_cubed AS img
+// [10]: [74:192, 130:248, 3:74]
+SELECT img[74:192, 130:248, 3:74]
+FROM tomo_cubed AS img
+// [10]: [96:214, 61:179, 14:85]
+SELECT img[96:214, 61:179, 14:85]
+FROM tomo_cubed AS img
+// [10]: [73:191, 93:211, 6:77]
+SELECT img[73:191, 93:211, 6:77]
+FROM tomo_cubed AS img
+// [10]: [55:173, 12:130, 54:125]
+SELECT img[55:173, 12:130, 54:125]
+FROM tomo_cubed AS img
+// [10]: [1:119, 123:241, 51:122]
+SELECT img[1:119, 123:241, 51:122]
+FROM tomo_cubed AS img
+// [10]: [117:235, 101:219, 55:126]
+SELECT img[117:235, 101:219, 55:126]
+FROM tomo_cubed AS img
+// [10]: [24:142, 26:144, 33:104]
+SELECT img[24:142, 26:144, 33:104]
+FROM tomo_cubed AS img
+// [20]: [36:185, 0:149, 39:128]
+SELECT img[36:185, 0:149, 39:128]
+FROM tomo_cubed AS img
+// [20]: [85:234, 31:180, 54:143]
+SELECT img[85:234, 31:180, 54:143]
+FROM tomo_cubed AS img
+// [20]: [55:204, 78:227, 20:109]
+SELECT img[55:204, 78:227, 20:109]
+FROM tomo_cubed AS img
+// [20]: [28:177, 98:247, 26:115]
+SELECT img[28:177, 98:247, 26:115]
+FROM tomo_cubed AS img
+// [20]: [53:202, 14:163, 15:104]
+SELECT img[53:202, 14:163, 15:104]
+FROM tomo_cubed AS img
+// [20]: [84:233, 59:208, 28:117]
+SELECT img[84:233, 59:208, 28:117]
+FROM tomo_cubed AS img
+// [20]: [24:173, 81:230, 21:110]
+SELECT img[24:173, 81:230, 21:110]
+FROM tomo_cubed AS img
+// [20]: [70:219, 103:252, 59:148]
+SELECT img[70:219, 103:252, 59:148]
+FROM tomo_cubed AS img
+// [20]: [75:224, 32:181, 36:125]
+SELECT img[75:224, 32:181, 36:125]
+FROM tomo_cubed AS img
+// [20]: [80:229, 65:214, 22:111]
+SELECT img[80:229, 65:214, 22:111]
+FROM tomo_cubed AS img
+// [20]: [5:154, 34:183, 20:109]
+SELECT img[5:154, 34:183, 20:109]
+FROM tomo_cubed AS img
+// [20]: [16:165, 72:221, 57:146]
+SELECT img[16:165, 72:221, 57:146]
+FROM tomo_cubed AS img
+// [20]: [90:239, 27:176, 55:144]
+SELECT img[90:239, 27:176, 55:144]
+FROM tomo_cubed AS img
+// [20]: [81:230, 63:212, 61:150]
+SELECT img[81:230, 63:212, 61:150]
+FROM tomo_cubed AS img
+// [20]: [87:236, 79:228, 61:150]
+SELECT img[87:236, 79:228, 61:150]
+FROM tomo_cubed AS img
+// [20]: [100:249, 33:182, 35:124]
+SELECT img[100:249, 33:182, 35:124]
+FROM tomo_cubed AS img
+// [20]: [14:163, 91:240, 38:127]
+SELECT img[14:163, 91:240, 38:127]
+FROM tomo_cubed AS img
+// [20]: [60:209, 95:244, 11:100]
+SELECT img[60:209, 95:244, 11:100]
+FROM tomo_cubed AS img
+// [20]: [99:248, 4:153, 29:118]
+SELECT img[99:248, 4:153, 29:118]
+FROM tomo_cubed AS img
+// [20]: [10:159, 64:213, 32:121]
+SELECT img[10:159, 64:213, 32:121]
+FROM tomo_cubed AS img
+// [50]: [8:210, 0:202, 1:122]
+SELECT img[8:210, 0:202, 1:122]
+FROM tomo_cubed AS img
+// [50]: [17:219, 21:223, 6:127]
+SELECT img[17:219, 21:223, 6:127]
+FROM tomo_cubed AS img
+// [50]: [49:251, 0:202, 4:125]
+SELECT img[49:251, 0:202, 4:125]
+FROM tomo_cubed AS img
+// [50]: [11:213, 37:239, 15:136]
+SELECT img[11:213, 37:239, 15:136]
+FROM tomo_cubed AS img
+// [50]: [29:231, 36:238, 18:139]
+SELECT img[29:231, 36:238, 18:139]
+FROM tomo_cubed AS img
+// [50]: [38:240, 21:223, 2:123]
+SELECT img[38:240, 21:223, 2:123]
+FROM tomo_cubed AS img
+// [50]: [26:228, 4:206, 9:130]
+SELECT img[26:228, 4:206, 9:130]
+FROM tomo_cubed AS img
+// [50]: [1:203, 41:243, 21:142]
+SELECT img[1:203, 41:243, 21:142]
+FROM tomo_cubed AS img
+// [50]: [39:241, 37:239, 10:131]
+SELECT img[39:241, 37:239, 10:131]
+FROM tomo_cubed AS img
+// [50]: [6:208, 49:251, 2:123]
+SELECT img[6:208, 49:251, 2:123]
+FROM tomo_cubed AS img
+// [50]: [2:204, 51:253, 8:129]
+SELECT img[2:204, 51:253, 8:129]
+FROM tomo_cubed AS img
+// [50]: [23:225, 51:253, 9:130]
+SELECT img[23:225, 51:253, 9:130]
+FROM tomo_cubed AS img
+// [50]: [32:234, 43:245, 10:131]
+SELECT img[32:234, 43:245, 10:131]
+FROM tomo_cubed AS img
+// [50]: [33:235, 9:211, 31:152]
+SELECT img[33:235, 9:211, 31:152]
+FROM tomo_cubed AS img
+// [50]: [28:230, 36:238, 4:125]
+SELECT img[28:230, 36:238, 4:125]
+FROM tomo_cubed AS img
+// [50]: [25:227, 40:242, 3:124]
+SELECT img[25:227, 40:242, 3:124]
+FROM tomo_cubed AS img
+// [50]: [33:235, 28:230, 25:146]
+SELECT img[33:235, 28:230, 25:146]
+FROM tomo_cubed AS img
+// [50]: [42:244, 34:236, 1:122]
+SELECT img[42:244, 34:236, 1:122]
+FROM tomo_cubed AS img
+// [50]: [34:236, 47:249, 6:127]
+SELECT img[34:236, 47:249, 6:127]
+FROM tomo_cubed AS img
+// [50]: [35:237, 22:224, 31:152]
+SELECT img[35:237, 22:224, 31:152]
+FROM tomo_cubed AS img
diff --git a/rasodmg/test/tmov_64.ql b/rasodmg/test/tmov_64.ql
new file mode 100644
index 0000000..1ca53e6
--- /dev/null
+++ b/rasodmg/test/tmov_64.ql
@@ -0,0 +1,425 @@
+// This query tests different selectivities with moving query boxes
+// on tomo_cubed with 64kB tiles ([0:39,0:39,0:39]). Each selectivity
+// is repeated 20 times with query boxes of the same shape and size
+// starting at different origins.
+
+// [0.5]: [205:249, 154:198, 39:65]
+SELECT img[205:249, 154:198, 39:65]
+FROM tomo_cubed_64 AS img
+// [0.5]: [125:169, 124:168, 15:41]
+SELECT img[125:169, 124:168, 15:41]
+FROM tomo_cubed_64 AS img
+// [0.5]: [197:241, 71:115, 82:108]
+SELECT img[197:241, 71:115, 82:108]
+FROM tomo_cubed_64 AS img
+// [0.5]: [53:97, 192:236, 122:148]
+SELECT img[53:97, 192:236, 122:148]
+FROM tomo_cubed_64 AS img
+// [0.5]: [140:184, 93:137, 121:147]
+SELECT img[140:184, 93:137, 121:147]
+FROM tomo_cubed_64 AS img
+// [0.5]: [154:198, 82:126, 120:146]
+SELECT img[154:198, 82:126, 120:146]
+FROM tomo_cubed_64 AS img
+// [0.5]: [209:253, 51:95, 47:73]
+SELECT img[209:253, 51:95, 47:73]
+FROM tomo_cubed_64 AS img
+// [0.5]: [57:101, 159:203, 113:139]
+SELECT img[57:101, 159:203, 113:139]
+FROM tomo_cubed_64 AS img
+// [0.5]: [98:142, 166:210, 12:38]
+SELECT img[98:142, 166:210, 12:38]
+FROM tomo_cubed_64 AS img
+// [0.5]: [194:238, 88:132, 52:78]
+SELECT img[194:238, 88:132, 52:78]
+FROM tomo_cubed_64 AS img
+// [0.5]: [162:206, 101:145, 53:79]
+SELECT img[162:206, 101:145, 53:79]
+FROM tomo_cubed_64 AS img
+// [0.5]: [166:210, 60:104, 126:152]
+SELECT img[166:210, 60:104, 126:152]
+FROM tomo_cubed_64 AS img
+// [0.5]: [127:171, 157:201, 92:118]
+SELECT img[127:171, 157:201, 92:118]
+FROM tomo_cubed_64 AS img
+// [0.5]: [46:90, 94:138, 53:79]
+SELECT img[46:90, 94:138, 53:79]
+FROM tomo_cubed_64 AS img
+// [0.5]: [19:63, 42:86, 17:43]
+SELECT img[19:63, 42:86, 17:43]
+FROM tomo_cubed_64 AS img
+// [0.5]: [182:226, 0:44, 97:123]
+SELECT img[182:226, 0:44, 97:123]
+FROM tomo_cubed_64 AS img
+// [0.5]: [139:183, 98:142, 47:73]
+SELECT img[139:183, 98:142, 47:73]
+FROM tomo_cubed_64 AS img
+// [0.5]: [106:150, 182:226, 11:37]
+SELECT img[106:150, 182:226, 11:37]
+FROM tomo_cubed_64 AS img
+// [0.5]: [193:237, 200:244, 23:49]
+SELECT img[193:237, 200:244, 23:49]
+FROM tomo_cubed_64 AS img
+// [0.5]: [40:84, 2:46, 5:31]
+SELECT img[40:84, 2:46, 5:31]
+FROM tomo_cubed_64 AS img
+// [1]: [51:106, 169:224, 105:138]
+SELECT img[51:106, 169:224, 105:138]
+FROM tomo_cubed_64 AS img
+// [1]: [72:127, 30:85, 113:146]
+SELECT img[72:127, 30:85, 113:146]
+FROM tomo_cubed_64 AS img
+// [1]: [104:159, 82:137, 48:81]
+SELECT img[104:159, 82:137, 48:81]
+FROM tomo_cubed_64 AS img
+// [1]: [91:146, 86:141, 40:73]
+SELECT img[91:146, 86:141, 40:73]
+FROM tomo_cubed_64 AS img
+// [1]: [121:176, 19:74, 59:92]
+SELECT img[121:176, 19:74, 59:92]
+FROM tomo_cubed_64 AS img
+// [1]: [69:124, 156:211, 27:60]
+SELECT img[69:124, 156:211, 27:60]
+FROM tomo_cubed_64 AS img
+// [1]: [24:79, 64:119, 25:58]
+SELECT img[24:79, 64:119, 25:58]
+FROM tomo_cubed_64 AS img
+// [1]: [70:125, 193:248, 90:123]
+SELECT img[70:125, 193:248, 90:123]
+FROM tomo_cubed_64 AS img
+// [1]: [193:248, 1:56, 38:71]
+SELECT img[193:248, 1:56, 38:71]
+FROM tomo_cubed_64 AS img
+// [1]: [118:173, 178:233, 56:89]
+SELECT img[118:173, 178:233, 56:89]
+FROM tomo_cubed_64 AS img
+// [1]: [118:173, 23:78, 21:54]
+SELECT img[118:173, 23:78, 21:54]
+FROM tomo_cubed_64 AS img
+// [1]: [9:64, 166:221, 44:77]
+SELECT img[9:64, 166:221, 44:77]
+FROM tomo_cubed_64 AS img
+// [1]: [66:121, 65:120, 93:126]
+SELECT img[66:121, 65:120, 93:126]
+FROM tomo_cubed_64 AS img
+// [1]: [63:118, 141:196, 31:64]
+SELECT img[63:118, 141:196, 31:64]
+FROM tomo_cubed_64 AS img
+// [1]: [89:144, 58:113, 39:72]
+SELECT img[89:144, 58:113, 39:72]
+FROM tomo_cubed_64 AS img
+// [1]: [72:127, 124:179, 93:126]
+SELECT img[72:127, 124:179, 93:126]
+FROM tomo_cubed_64 AS img
+// [1]: [46:101, 178:233, 41:74]
+SELECT img[46:101, 178:233, 41:74]
+FROM tomo_cubed_64 AS img
+// [1]: [52:107, 10:65, 49:82]
+SELECT img[52:107, 10:65, 49:82]
+FROM tomo_cubed_64 AS img
+// [1]: [151:206, 5:60, 1:34]
+SELECT img[151:206, 5:60, 1:34]
+FROM tomo_cubed_64 AS img
+// [1]: [95:150, 71:126, 85:118]
+SELECT img[95:150, 71:126, 85:118]
+FROM tomo_cubed_64 AS img
+// [2]: [31:100, 166:235, 7:49]
+SELECT img[31:100, 166:235, 7:49]
+FROM tomo_cubed_64 AS img
+// [2]: [109:178, 174:243, 31:73]
+SELECT img[109:178, 174:243, 31:73]
+FROM tomo_cubed_64 AS img
+// [2]: [24:93, 32:101, 91:133]
+SELECT img[24:93, 32:101, 91:133]
+FROM tomo_cubed_64 AS img
+// [2]: [76:145, 52:121, 33:75]
+SELECT img[76:145, 52:121, 33:75]
+FROM tomo_cubed_64 AS img
+// [2]: [82:151, 5:74, 17:59]
+SELECT img[82:151, 5:74, 17:59]
+FROM tomo_cubed_64 AS img
+// [2]: [48:117, 100:169, 72:114]
+SELECT img[48:117, 100:169, 72:114]
+FROM tomo_cubed_64 AS img
+// [2]: [81:150, 183:252, 39:81]
+SELECT img[81:150, 183:252, 39:81]
+FROM tomo_cubed_64 AS img
+// [2]: [8:77, 122:191, 5:47]
+SELECT img[8:77, 122:191, 5:47]
+FROM tomo_cubed_64 AS img
+// [2]: [170:239, 145:214, 23:65]
+SELECT img[170:239, 145:214, 23:65]
+FROM tomo_cubed_64 AS img
+// [2]: [84:153, 101:170, 86:128]
+SELECT img[84:153, 101:170, 86:128]
+FROM tomo_cubed_64 AS img
+// [2]: [72:141, 147:216, 32:74]
+SELECT img[72:141, 147:216, 32:74]
+FROM tomo_cubed_64 AS img
+// [2]: [12:81, 25:94, 108:150]
+SELECT img[12:81, 25:94, 108:150]
+FROM tomo_cubed_64 AS img
+// [2]: [94:163, 125:194, 29:71]
+SELECT img[94:163, 125:194, 29:71]
+FROM tomo_cubed_64 AS img
+// [2]: [4:73, 44:113, 0:42]
+SELECT img[4:73, 44:113, 0:42]
+FROM tomo_cubed_64 AS img
+// [2]: [134:203, 7:76, 85:127]
+SELECT img[134:203, 7:76, 85:127]
+FROM tomo_cubed_64 AS img
+// [2]: [84:153, 168:237, 3:45]
+SELECT img[84:153, 168:237, 3:45]
+FROM tomo_cubed_64 AS img
+// [2]: [166:235, 140:209, 41:83]
+SELECT img[166:235, 140:209, 41:83]
+FROM tomo_cubed_64 AS img
+// [2]: [98:167, 43:112, 81:123]
+SELECT img[98:167, 43:112, 81:123]
+FROM tomo_cubed_64 AS img
+// [2]: [5:74, 137:206, 29:71]
+SELECT img[5:74, 137:206, 29:71]
+FROM tomo_cubed_64 AS img
+// [2]: [177:246, 45:114, 28:70]
+SELECT img[177:246, 45:114, 28:70]
+FROM tomo_cubed_64 AS img
+// [5]: [52:146, 5:99, 72:128]
+SELECT img[52:146, 5:99, 72:128]
+FROM tomo_cubed_64 AS img
+// [5]: [147:241, 45:139, 90:146]
+SELECT img[147:241, 45:139, 90:146]
+FROM tomo_cubed_64 AS img
+// [5]: [156:250, 145:239, 7:63]
+SELECT img[156:250, 145:239, 7:63]
+FROM tomo_cubed_64 AS img
+// [5]: [30:124, 108:202, 74:130]
+SELECT img[30:124, 108:202, 74:130]
+FROM tomo_cubed_64 AS img
+// [5]: [140:234, 44:138, 25:81]
+SELECT img[140:234, 44:138, 25:81]
+FROM tomo_cubed_64 AS img
+// [5]: [48:142, 9:103, 8:64]
+SELECT img[48:142, 9:103, 8:64]
+FROM tomo_cubed_64 AS img
+// [5]: [0:94, 157:251, 73:129]
+SELECT img[0:94, 157:251, 73:129]
+FROM tomo_cubed_64 AS img
+// [5]: [125:219, 53:147, 7:63]
+SELECT img[125:219, 53:147, 7:63]
+FROM tomo_cubed_64 AS img
+// [5]: [26:120, 133:227, 38:94]
+SELECT img[26:120, 133:227, 38:94]
+FROM tomo_cubed_64 AS img
+// [5]: [157:251, 41:135, 74:130]
+SELECT img[157:251, 41:135, 74:130]
+FROM tomo_cubed_64 AS img
+// [5]: [41:135, 120:214, 31:87]
+SELECT img[41:135, 120:214, 31:87]
+FROM tomo_cubed_64 AS img
+// [5]: [33:127, 116:210, 71:127]
+SELECT img[33:127, 116:210, 71:127]
+FROM tomo_cubed_64 AS img
+// [5]: [138:232, 127:221, 20:76]
+SELECT img[138:232, 127:221, 20:76]
+FROM tomo_cubed_64 AS img
+// [5]: [13:107, 9:103, 60:116]
+SELECT img[13:107, 9:103, 60:116]
+FROM tomo_cubed_64 AS img
+// [5]: [124:218, 139:233, 74:130]
+SELECT img[124:218, 139:233, 74:130]
+FROM tomo_cubed_64 AS img
+// [5]: [117:211, 86:180, 91:147]
+SELECT img[117:211, 86:180, 91:147]
+FROM tomo_cubed_64 AS img
+// [5]: [143:237, 52:146, 71:127]
+SELECT img[143:237, 52:146, 71:127]
+FROM tomo_cubed_64 AS img
+// [5]: [10:104, 35:129, 19:75]
+SELECT img[10:104, 35:129, 19:75]
+FROM tomo_cubed_64 AS img
+// [5]: [110:204, 64:158, 64:120]
+SELECT img[110:204, 64:158, 64:120]
+FROM tomo_cubed_64 AS img
+// [5]: [12:106, 103:197, 96:152]
+SELECT img[12:106, 103:197, 96:152]
+FROM tomo_cubed_64 AS img
+// [10]: [108:226, 53:171, 9:80]
+SELECT img[108:226, 53:171, 9:80]
+FROM tomo_cubed_64 AS img
+// [10]: [46:164, 103:221, 10:81]
+SELECT img[46:164, 103:221, 10:81]
+FROM tomo_cubed_64 AS img
+// [10]: [80:198, 73:191, 38:109]
+SELECT img[80:198, 73:191, 38:109]
+FROM tomo_cubed_64 AS img
+// [10]: [38:156, 132:250, 26:97]
+SELECT img[38:156, 132:250, 26:97]
+FROM tomo_cubed_64 AS img
+// [10]: [11:129, 86:204, 77:148]
+SELECT img[11:129, 86:204, 77:148]
+FROM tomo_cubed_64 AS img
+// [10]: [46:164, 90:208, 17:88]
+SELECT img[46:164, 90:208, 17:88]
+FROM tomo_cubed_64 AS img
+// [10]: [86:204, 125:243, 6:77]
+SELECT img[86:204, 125:243, 6:77]
+FROM tomo_cubed_64 AS img
+// [10]: [54:172, 49:167, 69:140]
+SELECT img[54:172, 49:167, 69:140]
+FROM tomo_cubed_64 AS img
+// [10]: [11:129, 111:229, 23:94]
+SELECT img[11:129, 111:229, 23:94]
+FROM tomo_cubed_64 AS img
+// [10]: [46:164, 66:184, 2:73]
+SELECT img[46:164, 66:184, 2:73]
+FROM tomo_cubed_64 AS img
+// [10]: [88:206, 88:206, 39:110]
+SELECT img[88:206, 88:206, 39:110]
+FROM tomo_cubed_64 AS img
+// [10]: [46:164, 22:140, 43:114]
+SELECT img[46:164, 22:140, 43:114]
+FROM tomo_cubed_64 AS img
+// [10]: [4:122, 59:177, 47:118]
+SELECT img[4:122, 59:177, 47:118]
+FROM tomo_cubed_64 AS img
+// [10]: [22:140, 37:155, 31:102]
+SELECT img[22:140, 37:155, 31:102]
+FROM tomo_cubed_64 AS img
+// [10]: [109:227, 71:189, 81:152]
+SELECT img[109:227, 71:189, 81:152]
+FROM tomo_cubed_64 AS img
+// [10]: [96:214, 76:194, 67:138]
+SELECT img[96:214, 76:194, 67:138]
+FROM tomo_cubed_64 AS img
+// [10]: [4:122, 126:244, 10:81]
+SELECT img[4:122, 126:244, 10:81]
+FROM tomo_cubed_64 AS img
+// [10]: [38:156, 90:208, 31:102]
+SELECT img[38:156, 90:208, 31:102]
+FROM tomo_cubed_64 AS img
+// [10]: [12:130, 67:185, 70:141]
+SELECT img[12:130, 67:185, 70:141]
+FROM tomo_cubed_64 AS img
+// [10]: [108:226, 59:177, 70:141]
+SELECT img[108:226, 59:177, 70:141]
+FROM tomo_cubed_64 AS img
+// [20]: [60:209, 12:161, 15:104]
+SELECT img[60:209, 12:161, 15:104]
+FROM tomo_cubed_64 AS img
+// [20]: [36:185, 68:217, 31:120]
+SELECT img[36:185, 68:217, 31:120]
+FROM tomo_cubed_64 AS img
+// [20]: [19:168, 96:245, 50:139]
+SELECT img[19:168, 96:245, 50:139]
+FROM tomo_cubed_64 AS img
+// [20]: [68:217, 96:245, 4:93]
+SELECT img[68:217, 96:245, 4:93]
+FROM tomo_cubed_64 AS img
+// [20]: [16:165, 44:193, 49:138]
+SELECT img[16:165, 44:193, 49:138]
+FROM tomo_cubed_64 AS img
+// [20]: [71:220, 91:240, 11:100]
+SELECT img[71:220, 91:240, 11:100]
+FROM tomo_cubed_64 AS img
+// [20]: [96:245, 58:207, 4:93]
+SELECT img[96:245, 58:207, 4:93]
+FROM tomo_cubed_64 AS img
+// [20]: [40:189, 6:155, 11:100]
+SELECT img[40:189, 6:155, 11:100]
+FROM tomo_cubed_64 AS img
+// [20]: [91:240, 22:171, 7:96]
+SELECT img[91:240, 22:171, 7:96]
+FROM tomo_cubed_64 AS img
+// [20]: [79:228, 85:234, 39:128]
+SELECT img[79:228, 85:234, 39:128]
+FROM tomo_cubed_64 AS img
+// [20]: [97:246, 104:253, 6:95]
+SELECT img[97:246, 104:253, 6:95]
+FROM tomo_cubed_64 AS img
+// [20]: [62:211, 26:175, 7:96]
+SELECT img[62:211, 26:175, 7:96]
+FROM tomo_cubed_64 AS img
+// [20]: [35:184, 5:154, 29:118]
+SELECT img[35:184, 5:154, 29:118]
+FROM tomo_cubed_64 AS img
+// [20]: [20:169, 92:241, 5:94]
+SELECT img[20:169, 92:241, 5:94]
+FROM tomo_cubed_64 AS img
+// [20]: [77:226, 33:182, 45:134]
+SELECT img[77:226, 33:182, 45:134]
+FROM tomo_cubed_64 AS img
+// [20]: [6:155, 40:189, 55:144]
+SELECT img[6:155, 40:189, 55:144]
+FROM tomo_cubed_64 AS img
+// [20]: [102:251, 25:174, 20:109]
+SELECT img[102:251, 25:174, 20:109]
+FROM tomo_cubed_64 AS img
+// [20]: [35:184, 70:219, 31:120]
+SELECT img[35:184, 70:219, 31:120]
+FROM tomo_cubed_64 AS img
+// [20]: [99:248, 88:237, 10:99]
+SELECT img[99:248, 88:237, 10:99]
+FROM tomo_cubed_64 AS img
+// [20]: [67:216, 63:212, 60:149]
+SELECT img[67:216, 63:212, 60:149]
+FROM tomo_cubed_64 AS img
+// [50]: [46:248, 7:209, 31:152]
+SELECT img[46:248, 7:209, 31:152]
+FROM tomo_cubed_64 AS img
+// [50]: [45:247, 24:226, 17:138]
+SELECT img[45:247, 24:226, 17:138]
+FROM tomo_cubed_64 AS img
+// [50]: [22:224, 30:232, 9:130]
+SELECT img[22:224, 30:232, 9:130]
+FROM tomo_cubed_64 AS img
+// [50]: [29:231, 39:241, 4:125]
+SELECT img[29:231, 39:241, 4:125]
+FROM tomo_cubed_64 AS img
+// [50]: [19:221, 51:253, 6:127]
+SELECT img[19:221, 51:253, 6:127]
+FROM tomo_cubed_64 AS img
+// [50]: [27:229, 14:216, 10:131]
+SELECT img[27:229, 14:216, 10:131]
+FROM tomo_cubed_64 AS img
+// [50]: [33:235, 15:217, 26:147]
+SELECT img[33:235, 15:217, 26:147]
+FROM tomo_cubed_64 AS img
+// [50]: [48:250, 1:203, 18:139]
+SELECT img[48:250, 1:203, 18:139]
+FROM tomo_cubed_64 AS img
+// [50]: [24:226, 23:225, 23:144]
+SELECT img[24:226, 23:225, 23:144]
+FROM tomo_cubed_64 AS img
+// [50]: [31:233, 12:214, 8:129]
+SELECT img[31:233, 12:214, 8:129]
+FROM tomo_cubed_64 AS img
+// [50]: [34:236, 1:203, 24:145]
+SELECT img[34:236, 1:203, 24:145]
+FROM tomo_cubed_64 AS img
+// [50]: [27:229, 17:219, 22:143]
+SELECT img[27:229, 17:219, 22:143]
+FROM tomo_cubed_64 AS img
+// [50]: [15:217, 50:252, 16:137]
+SELECT img[15:217, 50:252, 16:137]
+FROM tomo_cubed_64 AS img
+// [50]: [49:251, 3:205, 29:150]
+SELECT img[49:251, 3:205, 29:150]
+FROM tomo_cubed_64 AS img
+// [50]: [11:213, 33:235, 17:138]
+SELECT img[11:213, 33:235, 17:138]
+FROM tomo_cubed_64 AS img
+// [50]: [15:217, 23:225, 29:150]
+SELECT img[15:217, 23:225, 29:150]
+FROM tomo_cubed_64 AS img
+// [50]: [46:248, 28:230, 30:151]
+SELECT img[46:248, 28:230, 30:151]
+FROM tomo_cubed_64 AS img
+// [50]: [11:213, 6:208, 1:122]
+SELECT img[11:213, 6:208, 1:122]
+FROM tomo_cubed_64 AS img
+// [50]: [13:215, 16:218, 24:145]
+SELECT img[13:215, 16:218, 24:145]
+FROM tomo_cubed_64 AS img
+// [50]: [44:246, 46:248, 28:149]
+SELECT img[44:246, 46:248, 28:149]
+FROM tomo_cubed_64 AS img
diff --git a/rasodmg/test/tomo_ops.ql b/rasodmg/test/tomo_ops.ql
new file mode 100644
index 0000000..fce9bf5
--- /dev/null
+++ b/rasodmg/test/tomo_ops.ql
@@ -0,0 +1,27 @@
+// This test evaluates performance of binary operations on parts
+// of tomo. Selectivity fixed at 10%
+
+// cubed, no operation
+
+select img[0:117,0:117,0:69]
+from tomo_cubed as img
+
+// cubed, one MDD operation
+
+select img[0:117,0:117,0:69] + img[0:117,0:117,0:69]
+from tomo_cubed as img
+
+// cubed, two MDD operations
+
+select img[0:117,0:117,0:69] + img[0:117,0:117,0:69] + img[0:117,0:117,0:69]
+from tomo_cubed as img
+
+// cubed, three MDD operations
+
+select img[0:117,0:117,0:69] + img[0:117,0:117,0:69] + img[0:117,0:117,0:69] + img[0:117,0:117,0:69]
+from tomo_cubed as img
+
+// cubed, four MDD operations
+
+select img[0:117,0:117,0:69] + img[0:117,0:117,0:69] + img[0:117,0:117,0:69] + img[0:117,0:117,0:69] + img[0:117,0:117,0:69]
+from tomo_cubed as img
diff --git a/rasodmg/test/tomo_select.ql b/rasodmg/test/tomo_select.ql
new file mode 100644
index 0000000..7584f12
--- /dev/null
+++ b/rasodmg/test/tomo_select.ql
@@ -0,0 +1,72 @@
+// This test evaluates different selectivities in tomo stored both
+// in slices and cubes.
+
+// sliced, selectivity 0,5%
+
+select img[0:43,0:43,0:25]
+from tomo_sliced as img
+
+// sliced, selectivity 1%
+
+select img[0:55,0:55,0:32]
+from tomo_sliced as img
+
+// sliced, selectivity 2%
+
+select img[0:68,0:68,0:41]
+from tomo_sliced as img
+
+// sliced, selectivity 5%
+
+select img[0:91,0:91,0:54]
+from tomo_sliced as img
+
+// sliced, selectivity 10%
+
+select img[0:117,0:117,0:69]
+from tomo_sliced as img
+
+// sliced, selectivity 50%
+
+select img[0:201,0:201,0:121]
+from tomo_sliced as img
+
+// sliced, selectivity 100%
+
+select img[0:255,0:255,0:153]
+from tomo_sliced as img
+
+// cubed, selectivity 0,5%
+
+select img[0:43,0:43,0:25]
+from tomo_cubed as img
+
+// cubed, selectivity 1%
+
+select img[0:55,0:55,0:32]
+from tomo_cubed as img
+
+// cubed, selectivity 2%
+
+select img[0:68,0:68,0:41]
+from tomo_cubed as img
+
+// cubed, selectivity 5%
+
+select img[0:91,0:91,0:54]
+from tomo_cubed as img
+
+// cubed, selectivity 10%
+
+select img[0:117,0:117,0:69]
+from tomo_cubed as img
+
+// cubed, selectivity 50%
+
+select img[0:201,0:201,0:121]
+from tomo_cubed as img
+
+// cubed, selectivity 100%
+
+select img[0:255,0:255,0:153]
+from tomo_cubed as img
diff --git a/rasodmg/test/troll_16.ql b/rasodmg/test/troll_16.ql
new file mode 100644
index 0000000..e15110e
--- /dev/null
+++ b/rasodmg/test/troll_16.ql
@@ -0,0 +1,180 @@
+// ["x"] tomo_cubed_16 [232:238,*:*,*:*]
+SELECT img[232,*:*,*:*]+img[233,*:*,*:*]+img[234,*:*,*:*]+img[235,*:*,*:*]+img[236,*:*,*:*]+img[237,*:*,*:*]+img[238,*:*,*:*]
+FROM tomo_cubed_16 as img
+// ["x"] tomo_cubed_16 [179:185,*:*,*:*]
+SELECT img[179,*:*,*:*]+img[180,*:*,*:*]+img[181,*:*,*:*]+img[182,*:*,*:*]+img[183,*:*,*:*]+img[184,*:*,*:*]+img[185,*:*,*:*]
+FROM tomo_cubed_16 as img
+// ["x"] tomo_cubed_16 [24:30,*:*,*:*]
+SELECT img[24,*:*,*:*]+img[25,*:*,*:*]+img[26,*:*,*:*]+img[27,*:*,*:*]+img[28,*:*,*:*]+img[29,*:*,*:*]+img[30,*:*,*:*]
+FROM tomo_cubed_16 as img
+// ["x"] tomo_cubed_16 [188:194,*:*,*:*]
+SELECT img[188,*:*,*:*]+img[189,*:*,*:*]+img[190,*:*,*:*]+img[191,*:*,*:*]+img[192,*:*,*:*]+img[193,*:*,*:*]+img[194,*:*,*:*]
+FROM tomo_cubed_16 as img
+// ["x"] tomo_cubed_16 [238:244,*:*,*:*]
+SELECT img[238,*:*,*:*]+img[239,*:*,*:*]+img[240,*:*,*:*]+img[241,*:*,*:*]+img[242,*:*,*:*]+img[243,*:*,*:*]+img[244,*:*,*:*]
+FROM tomo_cubed_16 as img
+// ["x"] tomo_cubed_16 [76:82,*:*,*:*]
+SELECT img[76,*:*,*:*]+img[77,*:*,*:*]+img[78,*:*,*:*]+img[79,*:*,*:*]+img[80,*:*,*:*]+img[81,*:*,*:*]+img[82,*:*,*:*]
+FROM tomo_cubed_16 as img
+// ["x"] tomo_cubed_16 [239:245,*:*,*:*]
+SELECT img[239,*:*,*:*]+img[240,*:*,*:*]+img[241,*:*,*:*]+img[242,*:*,*:*]+img[243,*:*,*:*]+img[244,*:*,*:*]+img[245,*:*,*:*]
+FROM tomo_cubed_16 as img
+// ["x"] tomo_cubed_16 [119:125,*:*,*:*]
+SELECT img[119,*:*,*:*]+img[120,*:*,*:*]+img[121,*:*,*:*]+img[122,*:*,*:*]+img[123,*:*,*:*]+img[124,*:*,*:*]+img[125,*:*,*:*]
+FROM tomo_cubed_16 as img
+// ["x"] tomo_cubed_16 [176:182,*:*,*:*]
+SELECT img[176,*:*,*:*]+img[177,*:*,*:*]+img[178,*:*,*:*]+img[179,*:*,*:*]+img[180,*:*,*:*]+img[181,*:*,*:*]+img[182,*:*,*:*]
+FROM tomo_cubed_16 as img
+// ["x"] tomo_cubed_16 [51:57,*:*,*:*]
+SELECT img[51,*:*,*:*]+img[52,*:*,*:*]+img[53,*:*,*:*]+img[54,*:*,*:*]+img[55,*:*,*:*]+img[56,*:*,*:*]+img[57,*:*,*:*]
+FROM tomo_cubed_16 as img
+// ["x"] tomo_cubed_16 [8:14,*:*,*:*]
+SELECT img[8,*:*,*:*]+img[9,*:*,*:*]+img[10,*:*,*:*]+img[11,*:*,*:*]+img[12,*:*,*:*]+img[13,*:*,*:*]+img[14,*:*,*:*]
+FROM tomo_cubed_16 as img
+// ["x"] tomo_cubed_16 [173:179,*:*,*:*]
+SELECT img[173,*:*,*:*]+img[174,*:*,*:*]+img[175,*:*,*:*]+img[176,*:*,*:*]+img[177,*:*,*:*]+img[178,*:*,*:*]+img[179,*:*,*:*]
+FROM tomo_cubed_16 as img
+// ["x"] tomo_cubed_16 [237:243,*:*,*:*]
+SELECT img[237,*:*,*:*]+img[238,*:*,*:*]+img[239,*:*,*:*]+img[240,*:*,*:*]+img[241,*:*,*:*]+img[242,*:*,*:*]+img[243,*:*,*:*]
+FROM tomo_cubed_16 as img
+// ["x"] tomo_cubed_16 [84:90,*:*,*:*]
+SELECT img[84,*:*,*:*]+img[85,*:*,*:*]+img[86,*:*,*:*]+img[87,*:*,*:*]+img[88,*:*,*:*]+img[89,*:*,*:*]+img[90,*:*,*:*]
+FROM tomo_cubed_16 as img
+// ["x"] tomo_cubed_16 [14:20,*:*,*:*]
+SELECT img[14,*:*,*:*]+img[15,*:*,*:*]+img[16,*:*,*:*]+img[17,*:*,*:*]+img[18,*:*,*:*]+img[19,*:*,*:*]+img[20,*:*,*:*]
+FROM tomo_cubed_16 as img
+// ["x"] tomo_cubed_16 [144:150,*:*,*:*]
+SELECT img[144,*:*,*:*]+img[145,*:*,*:*]+img[146,*:*,*:*]+img[147,*:*,*:*]+img[148,*:*,*:*]+img[149,*:*,*:*]+img[150,*:*,*:*]
+FROM tomo_cubed_16 as img
+// ["x"] tomo_cubed_16 [215:221,*:*,*:*]
+SELECT img[215,*:*,*:*]+img[216,*:*,*:*]+img[217,*:*,*:*]+img[218,*:*,*:*]+img[219,*:*,*:*]+img[220,*:*,*:*]+img[221,*:*,*:*]
+FROM tomo_cubed_16 as img
+// ["x"] tomo_cubed_16 [86:92,*:*,*:*]
+SELECT img[86,*:*,*:*]+img[87,*:*,*:*]+img[88,*:*,*:*]+img[89,*:*,*:*]+img[90,*:*,*:*]+img[91,*:*,*:*]+img[92,*:*,*:*]
+FROM tomo_cubed_16 as img
+// ["x"] tomo_cubed_16 [136:142,*:*,*:*]
+SELECT img[136,*:*,*:*]+img[137,*:*,*:*]+img[138,*:*,*:*]+img[139,*:*,*:*]+img[140,*:*,*:*]+img[141,*:*,*:*]+img[142,*:*,*:*]
+FROM tomo_cubed_16 as img
+// ["x"] tomo_cubed_16 [135:141,*:*,*:*]
+SELECT img[135,*:*,*:*]+img[136,*:*,*:*]+img[137,*:*,*:*]+img[138,*:*,*:*]+img[139,*:*,*:*]+img[140,*:*,*:*]+img[141,*:*,*:*]
+FROM tomo_cubed_16 as img
+// ["y"] tomo_cubed_16 [*:*, 146:152, *:*]
+SELECT img[*:*,146,*:*]+img[*:*,147,*:*]+img[*:*,148,*:*]+img[*:*,149,*:*]+img[*:*,150,*:*]+img[*:*,151,*:*]+img[*:*,152,*:*]
+FROM tomo_cubed_16 as img
+// ["y"] tomo_cubed_16 [*:*, 15:21, *:*]
+SELECT img[*:*,15,*:*]+img[*:*,16,*:*]+img[*:*,17,*:*]+img[*:*,18,*:*]+img[*:*,19,*:*]+img[*:*,20,*:*]+img[*:*,21,*:*]
+FROM tomo_cubed_16 as img
+// ["y"] tomo_cubed_16 [*:*, 148:154, *:*]
+SELECT img[*:*,148,*:*]+img[*:*,149,*:*]+img[*:*,150,*:*]+img[*:*,151,*:*]+img[*:*,152,*:*]+img[*:*,153,*:*]+img[*:*,154,*:*]
+FROM tomo_cubed_16 as img
+// ["y"] tomo_cubed_16 [*:*, 82:88, *:*]
+SELECT img[*:*,82,*:*]+img[*:*,83,*:*]+img[*:*,84,*:*]+img[*:*,85,*:*]+img[*:*,86,*:*]+img[*:*,87,*:*]+img[*:*,88,*:*]
+FROM tomo_cubed_16 as img
+// ["y"] tomo_cubed_16 [*:*, 149:155, *:*]
+SELECT img[*:*,149,*:*]+img[*:*,150,*:*]+img[*:*,151,*:*]+img[*:*,152,*:*]+img[*:*,153,*:*]+img[*:*,154,*:*]+img[*:*,155,*:*]
+FROM tomo_cubed_16 as img
+// ["y"] tomo_cubed_16 [*:*, 154:160, *:*]
+SELECT img[*:*,154,*:*]+img[*:*,155,*:*]+img[*:*,156,*:*]+img[*:*,157,*:*]+img[*:*,158,*:*]+img[*:*,159,*:*]+img[*:*,160,*:*]
+FROM tomo_cubed_16 as img
+// ["y"] tomo_cubed_16 [*:*, 46:52, *:*]
+SELECT img[*:*,46,*:*]+img[*:*,47,*:*]+img[*:*,48,*:*]+img[*:*,49,*:*]+img[*:*,50,*:*]+img[*:*,51,*:*]+img[*:*,52,*:*]
+FROM tomo_cubed_16 as img
+// ["y"] tomo_cubed_16 [*:*, 3:9, *:*]
+SELECT img[*:*,3,*:*]+img[*:*,4,*:*]+img[*:*,5,*:*]+img[*:*,6,*:*]+img[*:*,7,*:*]+img[*:*,8,*:*]+img[*:*,9,*:*]
+FROM tomo_cubed_16 as img
+// ["y"] tomo_cubed_16 [*:*, 20:26, *:*]
+SELECT img[*:*,20,*:*]+img[*:*,21,*:*]+img[*:*,22,*:*]+img[*:*,23,*:*]+img[*:*,24,*:*]+img[*:*,25,*:*]+img[*:*,26,*:*]
+FROM tomo_cubed_16 as img
+// ["y"] tomo_cubed_16 [*:*, 17:23, *:*]
+SELECT img[*:*,17,*:*]+img[*:*,18,*:*]+img[*:*,19,*:*]+img[*:*,20,*:*]+img[*:*,21,*:*]+img[*:*,22,*:*]+img[*:*,23,*:*]
+FROM tomo_cubed_16 as img
+// ["y"] tomo_cubed_16 [*:*, 236:242, *:*]
+SELECT img[*:*,236,*:*]+img[*:*,237,*:*]+img[*:*,238,*:*]+img[*:*,239,*:*]+img[*:*,240,*:*]+img[*:*,241,*:*]+img[*:*,242,*:*]
+FROM tomo_cubed_16 as img
+// ["y"] tomo_cubed_16 [*:*, 98:104, *:*]
+SELECT img[*:*,98,*:*]+img[*:*,99,*:*]+img[*:*,100,*:*]+img[*:*,101,*:*]+img[*:*,102,*:*]+img[*:*,103,*:*]+img[*:*,104,*:*]
+FROM tomo_cubed_16 as img
+// ["y"] tomo_cubed_16 [*:*, 4:10, *:*]
+SELECT img[*:*,4,*:*]+img[*:*,5,*:*]+img[*:*,6,*:*]+img[*:*,7,*:*]+img[*:*,8,*:*]+img[*:*,9,*:*]+img[*:*,10,*:*]
+FROM tomo_cubed_16 as img
+// ["y"] tomo_cubed_16 [*:*, 199:205, *:*]
+SELECT img[*:*,199,*:*]+img[*:*,200,*:*]+img[*:*,201,*:*]+img[*:*,202,*:*]+img[*:*,203,*:*]+img[*:*,204,*:*]+img[*:*,205,*:*]
+FROM tomo_cubed_16 as img
+// ["y"] tomo_cubed_16 [*:*, 197:203, *:*]
+SELECT img[*:*,197,*:*]+img[*:*,198,*:*]+img[*:*,199,*:*]+img[*:*,200,*:*]+img[*:*,201,*:*]+img[*:*,202,*:*]+img[*:*,203,*:*]
+FROM tomo_cubed_16 as img
+// ["y"] tomo_cubed_16 [*:*, 19:25, *:*]
+SELECT img[*:*,19,*:*]+img[*:*,20,*:*]+img[*:*,21,*:*]+img[*:*,22,*:*]+img[*:*,23,*:*]+img[*:*,24,*:*]+img[*:*,25,*:*]
+FROM tomo_cubed_16 as img
+// ["y"] tomo_cubed_16 [*:*, 64:70, *:*]
+SELECT img[*:*,64,*:*]+img[*:*,65,*:*]+img[*:*,66,*:*]+img[*:*,67,*:*]+img[*:*,68,*:*]+img[*:*,69,*:*]+img[*:*,70,*:*]
+FROM tomo_cubed_16 as img
+// ["y"] tomo_cubed_16 [*:*, 169:175, *:*]
+SELECT img[*:*,169,*:*]+img[*:*,170,*:*]+img[*:*,171,*:*]+img[*:*,172,*:*]+img[*:*,173,*:*]+img[*:*,174,*:*]+img[*:*,175,*:*]
+FROM tomo_cubed_16 as img
+// ["y"] tomo_cubed_16 [*:*, 109:115, *:*]
+SELECT img[*:*,109,*:*]+img[*:*,110,*:*]+img[*:*,111,*:*]+img[*:*,112,*:*]+img[*:*,113,*:*]+img[*:*,114,*:*]+img[*:*,115,*:*]
+FROM tomo_cubed_16 as img
+// ["y"] tomo_cubed_16 [*:*, 148:154, *:*]
+SELECT img[*:*,148,*:*]+img[*:*,149,*:*]+img[*:*,150,*:*]+img[*:*,151,*:*]+img[*:*,152,*:*]+img[*:*,153,*:*]+img[*:*,154,*:*]
+FROM tomo_cubed_16 as img
+// ["z"] tomo_cubed_16 [*:*, *:*, 35:41]
+SELECT img[*:*,*:*,35]+img[*:*,*:*,36]+img[*:*,*:*,37]+img[*:*,*:*,38]+img[*:*,*:*,39]+img[*:*,*:*,40]+img[*:*,*:*,41]
+FROM tomo_cubed_16 as img
+// ["z"] tomo_cubed_16 [*:*, *:*, 24:30]
+SELECT img[*:*,*:*,24]+img[*:*,*:*,25]+img[*:*,*:*,26]+img[*:*,*:*,27]+img[*:*,*:*,28]+img[*:*,*:*,29]+img[*:*,*:*,30]
+FROM tomo_cubed_16 as img
+// ["z"] tomo_cubed_16 [*:*, *:*, 38:44]
+SELECT img[*:*,*:*,38]+img[*:*,*:*,39]+img[*:*,*:*,40]+img[*:*,*:*,41]+img[*:*,*:*,42]+img[*:*,*:*,43]+img[*:*,*:*,44]
+FROM tomo_cubed_16 as img
+// ["z"] tomo_cubed_16 [*:*, *:*, 129:135]
+SELECT img[*:*,*:*,129]+img[*:*,*:*,130]+img[*:*,*:*,131]+img[*:*,*:*,132]+img[*:*,*:*,133]+img[*:*,*:*,134]+img[*:*,*:*,135]
+FROM tomo_cubed_16 as img
+// ["z"] tomo_cubed_16 [*:*, *:*, 88:94]
+SELECT img[*:*,*:*,88]+img[*:*,*:*,89]+img[*:*,*:*,90]+img[*:*,*:*,91]+img[*:*,*:*,92]+img[*:*,*:*,93]+img[*:*,*:*,94]
+FROM tomo_cubed_16 as img
+// ["z"] tomo_cubed_16 [*:*, *:*, 49:55]
+SELECT img[*:*,*:*,49]+img[*:*,*:*,50]+img[*:*,*:*,51]+img[*:*,*:*,52]+img[*:*,*:*,53]+img[*:*,*:*,54]+img[*:*,*:*,55]
+FROM tomo_cubed_16 as img
+// ["z"] tomo_cubed_16 [*:*, *:*, 70:76]
+SELECT img[*:*,*:*,70]+img[*:*,*:*,71]+img[*:*,*:*,72]+img[*:*,*:*,73]+img[*:*,*:*,74]+img[*:*,*:*,75]+img[*:*,*:*,76]
+FROM tomo_cubed_16 as img
+// ["z"] tomo_cubed_16 [*:*, *:*, 76:82]
+SELECT img[*:*,*:*,76]+img[*:*,*:*,77]+img[*:*,*:*,78]+img[*:*,*:*,79]+img[*:*,*:*,80]+img[*:*,*:*,81]+img[*:*,*:*,82]
+FROM tomo_cubed_16 as img
+// ["z"] tomo_cubed_16 [*:*, *:*, 60:66]
+SELECT img[*:*,*:*,60]+img[*:*,*:*,61]+img[*:*,*:*,62]+img[*:*,*:*,63]+img[*:*,*:*,64]+img[*:*,*:*,65]+img[*:*,*:*,66]
+FROM tomo_cubed_16 as img
+// ["z"] tomo_cubed_16 [*:*, *:*, 9:15]
+SELECT img[*:*,*:*,9]+img[*:*,*:*,10]+img[*:*,*:*,11]+img[*:*,*:*,12]+img[*:*,*:*,13]+img[*:*,*:*,14]+img[*:*,*:*,15]
+FROM tomo_cubed_16 as img
+// ["z"] tomo_cubed_16 [*:*, *:*, 14:20]
+SELECT img[*:*,*:*,14]+img[*:*,*:*,15]+img[*:*,*:*,16]+img[*:*,*:*,17]+img[*:*,*:*,18]+img[*:*,*:*,19]+img[*:*,*:*,20]
+FROM tomo_cubed_16 as img
+// ["z"] tomo_cubed_16 [*:*, *:*, 2:8]
+SELECT img[*:*,*:*,2]+img[*:*,*:*,3]+img[*:*,*:*,4]+img[*:*,*:*,5]+img[*:*,*:*,6]+img[*:*,*:*,7]+img[*:*,*:*,8]
+FROM tomo_cubed_16 as img
+// ["z"] tomo_cubed_16 [*:*, *:*, 29:35]
+SELECT img[*:*,*:*,29]+img[*:*,*:*,30]+img[*:*,*:*,31]+img[*:*,*:*,32]+img[*:*,*:*,33]+img[*:*,*:*,34]+img[*:*,*:*,35]
+FROM tomo_cubed_16 as img
+// ["z"] tomo_cubed_16 [*:*, *:*, 48:54]
+SELECT img[*:*,*:*,48]+img[*:*,*:*,49]+img[*:*,*:*,50]+img[*:*,*:*,51]+img[*:*,*:*,52]+img[*:*,*:*,53]+img[*:*,*:*,54]
+FROM tomo_cubed_16 as img
+// ["z"] tomo_cubed_16 [*:*, *:*, 89:95]
+SELECT img[*:*,*:*,89]+img[*:*,*:*,90]+img[*:*,*:*,91]+img[*:*,*:*,92]+img[*:*,*:*,93]+img[*:*,*:*,94]+img[*:*,*:*,95]
+FROM tomo_cubed_16 as img
+// ["z"] tomo_cubed_16 [*:*, *:*, 75:81]
+SELECT img[*:*,*:*,75]+img[*:*,*:*,76]+img[*:*,*:*,77]+img[*:*,*:*,78]+img[*:*,*:*,79]+img[*:*,*:*,80]+img[*:*,*:*,81]
+FROM tomo_cubed_16 as img
+// ["z"] tomo_cubed_16 [*:*, *:*, 83:89]
+SELECT img[*:*,*:*,83]+img[*:*,*:*,84]+img[*:*,*:*,85]+img[*:*,*:*,86]+img[*:*,*:*,87]+img[*:*,*:*,88]+img[*:*,*:*,89]
+FROM tomo_cubed_16 as img
+// ["z"] tomo_cubed_16 [*:*, *:*, 125:131]
+SELECT img[*:*,*:*,125]+img[*:*,*:*,126]+img[*:*,*:*,127]+img[*:*,*:*,128]+img[*:*,*:*,129]+img[*:*,*:*,130]+img[*:*,*:*,131]
+FROM tomo_cubed_16 as img
+// ["z"] tomo_cubed_16 [*:*, *:*, 132:138]
+SELECT img[*:*,*:*,132]+img[*:*,*:*,133]+img[*:*,*:*,134]+img[*:*,*:*,135]+img[*:*,*:*,136]+img[*:*,*:*,137]+img[*:*,*:*,138]
+FROM tomo_cubed_16 as img
+// ["z"] tomo_cubed_16 [*:*, *:*, 32:38]
+SELECT img[*:*,*:*,32]+img[*:*,*:*,33]+img[*:*,*:*,34]+img[*:*,*:*,35]+img[*:*,*:*,36]+img[*:*,*:*,37]+img[*:*,*:*,38]
+FROM tomo_cubed_16 as img
diff --git a/rasodmg/test/troll_32.ql b/rasodmg/test/troll_32.ql
new file mode 100644
index 0000000..cb407ee
--- /dev/null
+++ b/rasodmg/test/troll_32.ql
@@ -0,0 +1,180 @@
+// ["x"] tomo_cubed [133:139,*:*,*:*]
+SELECT img[133,*:*,*:*]+img[134,*:*,*:*]+img[135,*:*,*:*]+img[136,*:*,*:*]+img[137,*:*,*:*]+img[138,*:*,*:*]+img[139,*:*,*:*]
+FROM tomo_cubed as img
+// ["x"] tomo_cubed [248:254,*:*,*:*]
+SELECT img[248,*:*,*:*]+img[249,*:*,*:*]+img[250,*:*,*:*]+img[251,*:*,*:*]+img[252,*:*,*:*]+img[253,*:*,*:*]+img[254,*:*,*:*]
+FROM tomo_cubed as img
+// ["x"] tomo_cubed [94:100,*:*,*:*]
+SELECT img[94,*:*,*:*]+img[95,*:*,*:*]+img[96,*:*,*:*]+img[97,*:*,*:*]+img[98,*:*,*:*]+img[99,*:*,*:*]+img[100,*:*,*:*]
+FROM tomo_cubed as img
+// ["x"] tomo_cubed [3:9,*:*,*:*]
+SELECT img[3,*:*,*:*]+img[4,*:*,*:*]+img[5,*:*,*:*]+img[6,*:*,*:*]+img[7,*:*,*:*]+img[8,*:*,*:*]+img[9,*:*,*:*]
+FROM tomo_cubed as img
+// ["x"] tomo_cubed [93:99,*:*,*:*]
+SELECT img[93,*:*,*:*]+img[94,*:*,*:*]+img[95,*:*,*:*]+img[96,*:*,*:*]+img[97,*:*,*:*]+img[98,*:*,*:*]+img[99,*:*,*:*]
+FROM tomo_cubed as img
+// ["x"] tomo_cubed [62:68,*:*,*:*]
+SELECT img[62,*:*,*:*]+img[63,*:*,*:*]+img[64,*:*,*:*]+img[65,*:*,*:*]+img[66,*:*,*:*]+img[67,*:*,*:*]+img[68,*:*,*:*]
+FROM tomo_cubed as img
+// ["x"] tomo_cubed [174:180,*:*,*:*]
+SELECT img[174,*:*,*:*]+img[175,*:*,*:*]+img[176,*:*,*:*]+img[177,*:*,*:*]+img[178,*:*,*:*]+img[179,*:*,*:*]+img[180,*:*,*:*]
+FROM tomo_cubed as img
+// ["x"] tomo_cubed [97:103,*:*,*:*]
+SELECT img[97,*:*,*:*]+img[98,*:*,*:*]+img[99,*:*,*:*]+img[100,*:*,*:*]+img[101,*:*,*:*]+img[102,*:*,*:*]+img[103,*:*,*:*]
+FROM tomo_cubed as img
+// ["x"] tomo_cubed [43:49,*:*,*:*]
+SELECT img[43,*:*,*:*]+img[44,*:*,*:*]+img[45,*:*,*:*]+img[46,*:*,*:*]+img[47,*:*,*:*]+img[48,*:*,*:*]+img[49,*:*,*:*]
+FROM tomo_cubed as img
+// ["x"] tomo_cubed [41:47,*:*,*:*]
+SELECT img[41,*:*,*:*]+img[42,*:*,*:*]+img[43,*:*,*:*]+img[44,*:*,*:*]+img[45,*:*,*:*]+img[46,*:*,*:*]+img[47,*:*,*:*]
+FROM tomo_cubed as img
+// ["x"] tomo_cubed [38:44,*:*,*:*]
+SELECT img[38,*:*,*:*]+img[39,*:*,*:*]+img[40,*:*,*:*]+img[41,*:*,*:*]+img[42,*:*,*:*]+img[43,*:*,*:*]+img[44,*:*,*:*]
+FROM tomo_cubed as img
+// ["x"] tomo_cubed [75:81,*:*,*:*]
+SELECT img[75,*:*,*:*]+img[76,*:*,*:*]+img[77,*:*,*:*]+img[78,*:*,*:*]+img[79,*:*,*:*]+img[80,*:*,*:*]+img[81,*:*,*:*]
+FROM tomo_cubed as img
+// ["x"] tomo_cubed [189:195,*:*,*:*]
+SELECT img[189,*:*,*:*]+img[190,*:*,*:*]+img[191,*:*,*:*]+img[192,*:*,*:*]+img[193,*:*,*:*]+img[194,*:*,*:*]+img[195,*:*,*:*]
+FROM tomo_cubed as img
+// ["x"] tomo_cubed [3:9,*:*,*:*]
+SELECT img[3,*:*,*:*]+img[4,*:*,*:*]+img[5,*:*,*:*]+img[6,*:*,*:*]+img[7,*:*,*:*]+img[8,*:*,*:*]+img[9,*:*,*:*]
+FROM tomo_cubed as img
+// ["x"] tomo_cubed [38:44,*:*,*:*]
+SELECT img[38,*:*,*:*]+img[39,*:*,*:*]+img[40,*:*,*:*]+img[41,*:*,*:*]+img[42,*:*,*:*]+img[43,*:*,*:*]+img[44,*:*,*:*]
+FROM tomo_cubed as img
+// ["x"] tomo_cubed [5:11,*:*,*:*]
+SELECT img[5,*:*,*:*]+img[6,*:*,*:*]+img[7,*:*,*:*]+img[8,*:*,*:*]+img[9,*:*,*:*]+img[10,*:*,*:*]+img[11,*:*,*:*]
+FROM tomo_cubed as img
+// ["x"] tomo_cubed [83:89,*:*,*:*]
+SELECT img[83,*:*,*:*]+img[84,*:*,*:*]+img[85,*:*,*:*]+img[86,*:*,*:*]+img[87,*:*,*:*]+img[88,*:*,*:*]+img[89,*:*,*:*]
+FROM tomo_cubed as img
+// ["x"] tomo_cubed [23:29,*:*,*:*]
+SELECT img[23,*:*,*:*]+img[24,*:*,*:*]+img[25,*:*,*:*]+img[26,*:*,*:*]+img[27,*:*,*:*]+img[28,*:*,*:*]+img[29,*:*,*:*]
+FROM tomo_cubed as img
+// ["x"] tomo_cubed [185:191,*:*,*:*]
+SELECT img[185,*:*,*:*]+img[186,*:*,*:*]+img[187,*:*,*:*]+img[188,*:*,*:*]+img[189,*:*,*:*]+img[190,*:*,*:*]+img[191,*:*,*:*]
+FROM tomo_cubed as img
+// ["x"] tomo_cubed [148:154,*:*,*:*]
+SELECT img[148,*:*,*:*]+img[149,*:*,*:*]+img[150,*:*,*:*]+img[151,*:*,*:*]+img[152,*:*,*:*]+img[153,*:*,*:*]+img[154,*:*,*:*]
+FROM tomo_cubed as img
+// ["y"] tomo_cubed [*:*, 100:106, *:*]
+SELECT img[*:*,100,*:*]+img[*:*,101,*:*]+img[*:*,102,*:*]+img[*:*,103,*:*]+img[*:*,104,*:*]+img[*:*,105,*:*]+img[*:*,106,*:*]
+FROM tomo_cubed as img
+// ["y"] tomo_cubed [*:*, 2:8, *:*]
+SELECT img[*:*,2,*:*]+img[*:*,3,*:*]+img[*:*,4,*:*]+img[*:*,5,*:*]+img[*:*,6,*:*]+img[*:*,7,*:*]+img[*:*,8,*:*]
+FROM tomo_cubed as img
+// ["y"] tomo_cubed [*:*, 166:172, *:*]
+SELECT img[*:*,166,*:*]+img[*:*,167,*:*]+img[*:*,168,*:*]+img[*:*,169,*:*]+img[*:*,170,*:*]+img[*:*,171,*:*]+img[*:*,172,*:*]
+FROM tomo_cubed as img
+// ["y"] tomo_cubed [*:*, 246:252, *:*]
+SELECT img[*:*,246,*:*]+img[*:*,247,*:*]+img[*:*,248,*:*]+img[*:*,249,*:*]+img[*:*,250,*:*]+img[*:*,251,*:*]+img[*:*,252,*:*]
+FROM tomo_cubed as img
+// ["y"] tomo_cubed [*:*, 78:84, *:*]
+SELECT img[*:*,78,*:*]+img[*:*,79,*:*]+img[*:*,80,*:*]+img[*:*,81,*:*]+img[*:*,82,*:*]+img[*:*,83,*:*]+img[*:*,84,*:*]
+FROM tomo_cubed as img
+// ["y"] tomo_cubed [*:*, 174:180, *:*]
+SELECT img[*:*,174,*:*]+img[*:*,175,*:*]+img[*:*,176,*:*]+img[*:*,177,*:*]+img[*:*,178,*:*]+img[*:*,179,*:*]+img[*:*,180,*:*]
+FROM tomo_cubed as img
+// ["y"] tomo_cubed [*:*, 233:239, *:*]
+SELECT img[*:*,233,*:*]+img[*:*,234,*:*]+img[*:*,235,*:*]+img[*:*,236,*:*]+img[*:*,237,*:*]+img[*:*,238,*:*]+img[*:*,239,*:*]
+FROM tomo_cubed as img
+// ["y"] tomo_cubed [*:*, 131:137, *:*]
+SELECT img[*:*,131,*:*]+img[*:*,132,*:*]+img[*:*,133,*:*]+img[*:*,134,*:*]+img[*:*,135,*:*]+img[*:*,136,*:*]+img[*:*,137,*:*]
+FROM tomo_cubed as img
+// ["y"] tomo_cubed [*:*, 25:31, *:*]
+SELECT img[*:*,25,*:*]+img[*:*,26,*:*]+img[*:*,27,*:*]+img[*:*,28,*:*]+img[*:*,29,*:*]+img[*:*,30,*:*]+img[*:*,31,*:*]
+FROM tomo_cubed as img
+// ["y"] tomo_cubed [*:*, 170:176, *:*]
+SELECT img[*:*,170,*:*]+img[*:*,171,*:*]+img[*:*,172,*:*]+img[*:*,173,*:*]+img[*:*,174,*:*]+img[*:*,175,*:*]+img[*:*,176,*:*]
+FROM tomo_cubed as img
+// ["y"] tomo_cubed [*:*, 85:91, *:*]
+SELECT img[*:*,85,*:*]+img[*:*,86,*:*]+img[*:*,87,*:*]+img[*:*,88,*:*]+img[*:*,89,*:*]+img[*:*,90,*:*]+img[*:*,91,*:*]
+FROM tomo_cubed as img
+// ["y"] tomo_cubed [*:*, 178:184, *:*]
+SELECT img[*:*,178,*:*]+img[*:*,179,*:*]+img[*:*,180,*:*]+img[*:*,181,*:*]+img[*:*,182,*:*]+img[*:*,183,*:*]+img[*:*,184,*:*]
+FROM tomo_cubed as img
+// ["y"] tomo_cubed [*:*, 198:204, *:*]
+SELECT img[*:*,198,*:*]+img[*:*,199,*:*]+img[*:*,200,*:*]+img[*:*,201,*:*]+img[*:*,202,*:*]+img[*:*,203,*:*]+img[*:*,204,*:*]
+FROM tomo_cubed as img
+// ["y"] tomo_cubed [*:*, 54:60, *:*]
+SELECT img[*:*,54,*:*]+img[*:*,55,*:*]+img[*:*,56,*:*]+img[*:*,57,*:*]+img[*:*,58,*:*]+img[*:*,59,*:*]+img[*:*,60,*:*]
+FROM tomo_cubed as img
+// ["y"] tomo_cubed [*:*, 227:233, *:*]
+SELECT img[*:*,227,*:*]+img[*:*,228,*:*]+img[*:*,229,*:*]+img[*:*,230,*:*]+img[*:*,231,*:*]+img[*:*,232,*:*]+img[*:*,233,*:*]
+FROM tomo_cubed as img
+// ["y"] tomo_cubed [*:*, 4:10, *:*]
+SELECT img[*:*,4,*:*]+img[*:*,5,*:*]+img[*:*,6,*:*]+img[*:*,7,*:*]+img[*:*,8,*:*]+img[*:*,9,*:*]+img[*:*,10,*:*]
+FROM tomo_cubed as img
+// ["y"] tomo_cubed [*:*, 7:13, *:*]
+SELECT img[*:*,7,*:*]+img[*:*,8,*:*]+img[*:*,9,*:*]+img[*:*,10,*:*]+img[*:*,11,*:*]+img[*:*,12,*:*]+img[*:*,13,*:*]
+FROM tomo_cubed as img
+// ["y"] tomo_cubed [*:*, 217:223, *:*]
+SELECT img[*:*,217,*:*]+img[*:*,218,*:*]+img[*:*,219,*:*]+img[*:*,220,*:*]+img[*:*,221,*:*]+img[*:*,222,*:*]+img[*:*,223,*:*]
+FROM tomo_cubed as img
+// ["y"] tomo_cubed [*:*, 200:206, *:*]
+SELECT img[*:*,200,*:*]+img[*:*,201,*:*]+img[*:*,202,*:*]+img[*:*,203,*:*]+img[*:*,204,*:*]+img[*:*,205,*:*]+img[*:*,206,*:*]
+FROM tomo_cubed as img
+// ["y"] tomo_cubed [*:*, 181:187, *:*]
+SELECT img[*:*,181,*:*]+img[*:*,182,*:*]+img[*:*,183,*:*]+img[*:*,184,*:*]+img[*:*,185,*:*]+img[*:*,186,*:*]+img[*:*,187,*:*]
+FROM tomo_cubed as img
+// ["z"] tomo_cubed [*:*, *:*, 4:10]
+SELECT img[*:*,*:*,4]+img[*:*,*:*,5]+img[*:*,*:*,6]+img[*:*,*:*,7]+img[*:*,*:*,8]+img[*:*,*:*,9]+img[*:*,*:*,10]
+FROM tomo_cubed as img
+// ["z"] tomo_cubed [*:*, *:*, 29:35]
+SELECT img[*:*,*:*,29]+img[*:*,*:*,30]+img[*:*,*:*,31]+img[*:*,*:*,32]+img[*:*,*:*,33]+img[*:*,*:*,34]+img[*:*,*:*,35]
+FROM tomo_cubed as img
+// ["z"] tomo_cubed [*:*, *:*, 74:80]
+SELECT img[*:*,*:*,74]+img[*:*,*:*,75]+img[*:*,*:*,76]+img[*:*,*:*,77]+img[*:*,*:*,78]+img[*:*,*:*,79]+img[*:*,*:*,80]
+FROM tomo_cubed as img
+// ["z"] tomo_cubed [*:*, *:*, 71:77]
+SELECT img[*:*,*:*,71]+img[*:*,*:*,72]+img[*:*,*:*,73]+img[*:*,*:*,74]+img[*:*,*:*,75]+img[*:*,*:*,76]+img[*:*,*:*,77]
+FROM tomo_cubed as img
+// ["z"] tomo_cubed [*:*, *:*, 125:131]
+SELECT img[*:*,*:*,125]+img[*:*,*:*,126]+img[*:*,*:*,127]+img[*:*,*:*,128]+img[*:*,*:*,129]+img[*:*,*:*,130]+img[*:*,*:*,131]
+FROM tomo_cubed as img
+// ["z"] tomo_cubed [*:*, *:*, 146:152]
+SELECT img[*:*,*:*,146]+img[*:*,*:*,147]+img[*:*,*:*,148]+img[*:*,*:*,149]+img[*:*,*:*,150]+img[*:*,*:*,151]+img[*:*,*:*,152]
+FROM tomo_cubed as img
+// ["z"] tomo_cubed [*:*, *:*, 138:144]
+SELECT img[*:*,*:*,138]+img[*:*,*:*,139]+img[*:*,*:*,140]+img[*:*,*:*,141]+img[*:*,*:*,142]+img[*:*,*:*,143]+img[*:*,*:*,144]
+FROM tomo_cubed as img
+// ["z"] tomo_cubed [*:*, *:*, 81:87]
+SELECT img[*:*,*:*,81]+img[*:*,*:*,82]+img[*:*,*:*,83]+img[*:*,*:*,84]+img[*:*,*:*,85]+img[*:*,*:*,86]+img[*:*,*:*,87]
+FROM tomo_cubed as img
+// ["z"] tomo_cubed [*:*, *:*, 133:139]
+SELECT img[*:*,*:*,133]+img[*:*,*:*,134]+img[*:*,*:*,135]+img[*:*,*:*,136]+img[*:*,*:*,137]+img[*:*,*:*,138]+img[*:*,*:*,139]
+FROM tomo_cubed as img
+// ["z"] tomo_cubed [*:*, *:*, 131:137]
+SELECT img[*:*,*:*,131]+img[*:*,*:*,132]+img[*:*,*:*,133]+img[*:*,*:*,134]+img[*:*,*:*,135]+img[*:*,*:*,136]+img[*:*,*:*,137]
+FROM tomo_cubed as img
+// ["z"] tomo_cubed [*:*, *:*, 52:58]
+SELECT img[*:*,*:*,52]+img[*:*,*:*,53]+img[*:*,*:*,54]+img[*:*,*:*,55]+img[*:*,*:*,56]+img[*:*,*:*,57]+img[*:*,*:*,58]
+FROM tomo_cubed as img
+// ["z"] tomo_cubed [*:*, *:*, 67:73]
+SELECT img[*:*,*:*,67]+img[*:*,*:*,68]+img[*:*,*:*,69]+img[*:*,*:*,70]+img[*:*,*:*,71]+img[*:*,*:*,72]+img[*:*,*:*,73]
+FROM tomo_cubed as img
+// ["z"] tomo_cubed [*:*, *:*, 104:110]
+SELECT img[*:*,*:*,104]+img[*:*,*:*,105]+img[*:*,*:*,106]+img[*:*,*:*,107]+img[*:*,*:*,108]+img[*:*,*:*,109]+img[*:*,*:*,110]
+FROM tomo_cubed as img
+// ["z"] tomo_cubed [*:*, *:*, 95:101]
+SELECT img[*:*,*:*,95]+img[*:*,*:*,96]+img[*:*,*:*,97]+img[*:*,*:*,98]+img[*:*,*:*,99]+img[*:*,*:*,100]+img[*:*,*:*,101]
+FROM tomo_cubed as img
+// ["z"] tomo_cubed [*:*, *:*, 71:77]
+SELECT img[*:*,*:*,71]+img[*:*,*:*,72]+img[*:*,*:*,73]+img[*:*,*:*,74]+img[*:*,*:*,75]+img[*:*,*:*,76]+img[*:*,*:*,77]
+FROM tomo_cubed as img
+// ["z"] tomo_cubed [*:*, *:*, 5:11]
+SELECT img[*:*,*:*,5]+img[*:*,*:*,6]+img[*:*,*:*,7]+img[*:*,*:*,8]+img[*:*,*:*,9]+img[*:*,*:*,10]+img[*:*,*:*,11]
+FROM tomo_cubed as img
+// ["z"] tomo_cubed [*:*, *:*, 127:133]
+SELECT img[*:*,*:*,127]+img[*:*,*:*,128]+img[*:*,*:*,129]+img[*:*,*:*,130]+img[*:*,*:*,131]+img[*:*,*:*,132]+img[*:*,*:*,133]
+FROM tomo_cubed as img
+// ["z"] tomo_cubed [*:*, *:*, 4:10]
+SELECT img[*:*,*:*,4]+img[*:*,*:*,5]+img[*:*,*:*,6]+img[*:*,*:*,7]+img[*:*,*:*,8]+img[*:*,*:*,9]+img[*:*,*:*,10]
+FROM tomo_cubed as img
+// ["z"] tomo_cubed [*:*, *:*, 141:147]
+SELECT img[*:*,*:*,141]+img[*:*,*:*,142]+img[*:*,*:*,143]+img[*:*,*:*,144]+img[*:*,*:*,145]+img[*:*,*:*,146]+img[*:*,*:*,147]
+FROM tomo_cubed as img
+// ["z"] tomo_cubed [*:*, *:*, 82:88]
+SELECT img[*:*,*:*,82]+img[*:*,*:*,83]+img[*:*,*:*,84]+img[*:*,*:*,85]+img[*:*,*:*,86]+img[*:*,*:*,87]+img[*:*,*:*,88]
+FROM tomo_cubed as img
diff --git a/rasodmg/test/troll_64.ql b/rasodmg/test/troll_64.ql
new file mode 100644
index 0000000..c74f21e
--- /dev/null
+++ b/rasodmg/test/troll_64.ql
@@ -0,0 +1,180 @@
+// ["x"] tomo_cubed_64 [32:38,*:*,*:*]
+SELECT img[32,*:*,*:*]+img[33,*:*,*:*]+img[34,*:*,*:*]+img[35,*:*,*:*]+img[36,*:*,*:*]+img[37,*:*,*:*]+img[38,*:*,*:*]
+FROM tomo_cubed_64 as img
+// ["x"] tomo_cubed_64 [134:140,*:*,*:*]
+SELECT img[134,*:*,*:*]+img[135,*:*,*:*]+img[136,*:*,*:*]+img[137,*:*,*:*]+img[138,*:*,*:*]+img[139,*:*,*:*]+img[140,*:*,*:*]
+FROM tomo_cubed_64 as img
+// ["x"] tomo_cubed_64 [116:122,*:*,*:*]
+SELECT img[116,*:*,*:*]+img[117,*:*,*:*]+img[118,*:*,*:*]+img[119,*:*,*:*]+img[120,*:*,*:*]+img[121,*:*,*:*]+img[122,*:*,*:*]
+FROM tomo_cubed_64 as img
+// ["x"] tomo_cubed_64 [244:250,*:*,*:*]
+SELECT img[244,*:*,*:*]+img[245,*:*,*:*]+img[246,*:*,*:*]+img[247,*:*,*:*]+img[248,*:*,*:*]+img[249,*:*,*:*]+img[250,*:*,*:*]
+FROM tomo_cubed_64 as img
+// ["x"] tomo_cubed_64 [182:188,*:*,*:*]
+SELECT img[182,*:*,*:*]+img[183,*:*,*:*]+img[184,*:*,*:*]+img[185,*:*,*:*]+img[186,*:*,*:*]+img[187,*:*,*:*]+img[188,*:*,*:*]
+FROM tomo_cubed_64 as img
+// ["x"] tomo_cubed_64 [233:239,*:*,*:*]
+SELECT img[233,*:*,*:*]+img[234,*:*,*:*]+img[235,*:*,*:*]+img[236,*:*,*:*]+img[237,*:*,*:*]+img[238,*:*,*:*]+img[239,*:*,*:*]
+FROM tomo_cubed_64 as img
+// ["x"] tomo_cubed_64 [134:140,*:*,*:*]
+SELECT img[134,*:*,*:*]+img[135,*:*,*:*]+img[136,*:*,*:*]+img[137,*:*,*:*]+img[138,*:*,*:*]+img[139,*:*,*:*]+img[140,*:*,*:*]
+FROM tomo_cubed_64 as img
+// ["x"] tomo_cubed_64 [216:222,*:*,*:*]
+SELECT img[216,*:*,*:*]+img[217,*:*,*:*]+img[218,*:*,*:*]+img[219,*:*,*:*]+img[220,*:*,*:*]+img[221,*:*,*:*]+img[222,*:*,*:*]
+FROM tomo_cubed_64 as img
+// ["x"] tomo_cubed_64 [176:182,*:*,*:*]
+SELECT img[176,*:*,*:*]+img[177,*:*,*:*]+img[178,*:*,*:*]+img[179,*:*,*:*]+img[180,*:*,*:*]+img[181,*:*,*:*]+img[182,*:*,*:*]
+FROM tomo_cubed_64 as img
+// ["x"] tomo_cubed_64 [200:206,*:*,*:*]
+SELECT img[200,*:*,*:*]+img[201,*:*,*:*]+img[202,*:*,*:*]+img[203,*:*,*:*]+img[204,*:*,*:*]+img[205,*:*,*:*]+img[206,*:*,*:*]
+FROM tomo_cubed_64 as img
+// ["x"] tomo_cubed_64 [140:146,*:*,*:*]
+SELECT img[140,*:*,*:*]+img[141,*:*,*:*]+img[142,*:*,*:*]+img[143,*:*,*:*]+img[144,*:*,*:*]+img[145,*:*,*:*]+img[146,*:*,*:*]
+FROM tomo_cubed_64 as img
+// ["x"] tomo_cubed_64 [54:60,*:*,*:*]
+SELECT img[54,*:*,*:*]+img[55,*:*,*:*]+img[56,*:*,*:*]+img[57,*:*,*:*]+img[58,*:*,*:*]+img[59,*:*,*:*]+img[60,*:*,*:*]
+FROM tomo_cubed_64 as img
+// ["x"] tomo_cubed_64 [94:100,*:*,*:*]
+SELECT img[94,*:*,*:*]+img[95,*:*,*:*]+img[96,*:*,*:*]+img[97,*:*,*:*]+img[98,*:*,*:*]+img[99,*:*,*:*]+img[100,*:*,*:*]
+FROM tomo_cubed_64 as img
+// ["x"] tomo_cubed_64 [14:20,*:*,*:*]
+SELECT img[14,*:*,*:*]+img[15,*:*,*:*]+img[16,*:*,*:*]+img[17,*:*,*:*]+img[18,*:*,*:*]+img[19,*:*,*:*]+img[20,*:*,*:*]
+FROM tomo_cubed_64 as img
+// ["x"] tomo_cubed_64 [211:217,*:*,*:*]
+SELECT img[211,*:*,*:*]+img[212,*:*,*:*]+img[213,*:*,*:*]+img[214,*:*,*:*]+img[215,*:*,*:*]+img[216,*:*,*:*]+img[217,*:*,*:*]
+FROM tomo_cubed_64 as img
+// ["x"] tomo_cubed_64 [156:162,*:*,*:*]
+SELECT img[156,*:*,*:*]+img[157,*:*,*:*]+img[158,*:*,*:*]+img[159,*:*,*:*]+img[160,*:*,*:*]+img[161,*:*,*:*]+img[162,*:*,*:*]
+FROM tomo_cubed_64 as img
+// ["x"] tomo_cubed_64 [196:202,*:*,*:*]
+SELECT img[196,*:*,*:*]+img[197,*:*,*:*]+img[198,*:*,*:*]+img[199,*:*,*:*]+img[200,*:*,*:*]+img[201,*:*,*:*]+img[202,*:*,*:*]
+FROM tomo_cubed_64 as img
+// ["x"] tomo_cubed_64 [181:187,*:*,*:*]
+SELECT img[181,*:*,*:*]+img[182,*:*,*:*]+img[183,*:*,*:*]+img[184,*:*,*:*]+img[185,*:*,*:*]+img[186,*:*,*:*]+img[187,*:*,*:*]
+FROM tomo_cubed_64 as img
+// ["x"] tomo_cubed_64 [80:86,*:*,*:*]
+SELECT img[80,*:*,*:*]+img[81,*:*,*:*]+img[82,*:*,*:*]+img[83,*:*,*:*]+img[84,*:*,*:*]+img[85,*:*,*:*]+img[86,*:*,*:*]
+FROM tomo_cubed_64 as img
+// ["x"] tomo_cubed_64 [1:7,*:*,*:*]
+SELECT img[1,*:*,*:*]+img[2,*:*,*:*]+img[3,*:*,*:*]+img[4,*:*,*:*]+img[5,*:*,*:*]+img[6,*:*,*:*]+img[7,*:*,*:*]
+FROM tomo_cubed_64 as img
+// ["y"] tomo_cubed_64 [*:*, 72:78, *:*]
+SELECT img[*:*,72,*:*]+img[*:*,73,*:*]+img[*:*,74,*:*]+img[*:*,75,*:*]+img[*:*,76,*:*]+img[*:*,77,*:*]+img[*:*,78,*:*]
+FROM tomo_cubed_64 as img
+// ["y"] tomo_cubed_64 [*:*, 211:217, *:*]
+SELECT img[*:*,211,*:*]+img[*:*,212,*:*]+img[*:*,213,*:*]+img[*:*,214,*:*]+img[*:*,215,*:*]+img[*:*,216,*:*]+img[*:*,217,*:*]
+FROM tomo_cubed_64 as img
+// ["y"] tomo_cubed_64 [*:*, 199:205, *:*]
+SELECT img[*:*,199,*:*]+img[*:*,200,*:*]+img[*:*,201,*:*]+img[*:*,202,*:*]+img[*:*,203,*:*]+img[*:*,204,*:*]+img[*:*,205,*:*]
+FROM tomo_cubed_64 as img
+// ["y"] tomo_cubed_64 [*:*, 92:98, *:*]
+SELECT img[*:*,92,*:*]+img[*:*,93,*:*]+img[*:*,94,*:*]+img[*:*,95,*:*]+img[*:*,96,*:*]+img[*:*,97,*:*]+img[*:*,98,*:*]
+FROM tomo_cubed_64 as img
+// ["y"] tomo_cubed_64 [*:*, 233:239, *:*]
+SELECT img[*:*,233,*:*]+img[*:*,234,*:*]+img[*:*,235,*:*]+img[*:*,236,*:*]+img[*:*,237,*:*]+img[*:*,238,*:*]+img[*:*,239,*:*]
+FROM tomo_cubed_64 as img
+// ["y"] tomo_cubed_64 [*:*, 201:207, *:*]
+SELECT img[*:*,201,*:*]+img[*:*,202,*:*]+img[*:*,203,*:*]+img[*:*,204,*:*]+img[*:*,205,*:*]+img[*:*,206,*:*]+img[*:*,207,*:*]
+FROM tomo_cubed_64 as img
+// ["y"] tomo_cubed_64 [*:*, 59:65, *:*]
+SELECT img[*:*,59,*:*]+img[*:*,60,*:*]+img[*:*,61,*:*]+img[*:*,62,*:*]+img[*:*,63,*:*]+img[*:*,64,*:*]+img[*:*,65,*:*]
+FROM tomo_cubed_64 as img
+// ["y"] tomo_cubed_64 [*:*, 208:214, *:*]
+SELECT img[*:*,208,*:*]+img[*:*,209,*:*]+img[*:*,210,*:*]+img[*:*,211,*:*]+img[*:*,212,*:*]+img[*:*,213,*:*]+img[*:*,214,*:*]
+FROM tomo_cubed_64 as img
+// ["y"] tomo_cubed_64 [*:*, 1:7, *:*]
+SELECT img[*:*,1,*:*]+img[*:*,2,*:*]+img[*:*,3,*:*]+img[*:*,4,*:*]+img[*:*,5,*:*]+img[*:*,6,*:*]+img[*:*,7,*:*]
+FROM tomo_cubed_64 as img
+// ["y"] tomo_cubed_64 [*:*, 4:10, *:*]
+SELECT img[*:*,4,*:*]+img[*:*,5,*:*]+img[*:*,6,*:*]+img[*:*,7,*:*]+img[*:*,8,*:*]+img[*:*,9,*:*]+img[*:*,10,*:*]
+FROM tomo_cubed_64 as img
+// ["y"] tomo_cubed_64 [*:*, 5:11, *:*]
+SELECT img[*:*,5,*:*]+img[*:*,6,*:*]+img[*:*,7,*:*]+img[*:*,8,*:*]+img[*:*,9,*:*]+img[*:*,10,*:*]+img[*:*,11,*:*]
+FROM tomo_cubed_64 as img
+// ["y"] tomo_cubed_64 [*:*, 98:104, *:*]
+SELECT img[*:*,98,*:*]+img[*:*,99,*:*]+img[*:*,100,*:*]+img[*:*,101,*:*]+img[*:*,102,*:*]+img[*:*,103,*:*]+img[*:*,104,*:*]
+FROM tomo_cubed_64 as img
+// ["y"] tomo_cubed_64 [*:*, 74:80, *:*]
+SELECT img[*:*,74,*:*]+img[*:*,75,*:*]+img[*:*,76,*:*]+img[*:*,77,*:*]+img[*:*,78,*:*]+img[*:*,79,*:*]+img[*:*,80,*:*]
+FROM tomo_cubed_64 as img
+// ["y"] tomo_cubed_64 [*:*, 49:55, *:*]
+SELECT img[*:*,49,*:*]+img[*:*,50,*:*]+img[*:*,51,*:*]+img[*:*,52,*:*]+img[*:*,53,*:*]+img[*:*,54,*:*]+img[*:*,55,*:*]
+FROM tomo_cubed_64 as img
+// ["y"] tomo_cubed_64 [*:*, 177:183, *:*]
+SELECT img[*:*,177,*:*]+img[*:*,178,*:*]+img[*:*,179,*:*]+img[*:*,180,*:*]+img[*:*,181,*:*]+img[*:*,182,*:*]+img[*:*,183,*:*]
+FROM tomo_cubed_64 as img
+// ["y"] tomo_cubed_64 [*:*, 146:152, *:*]
+SELECT img[*:*,146,*:*]+img[*:*,147,*:*]+img[*:*,148,*:*]+img[*:*,149,*:*]+img[*:*,150,*:*]+img[*:*,151,*:*]+img[*:*,152,*:*]
+FROM tomo_cubed_64 as img
+// ["y"] tomo_cubed_64 [*:*, 105:111, *:*]
+SELECT img[*:*,105,*:*]+img[*:*,106,*:*]+img[*:*,107,*:*]+img[*:*,108,*:*]+img[*:*,109,*:*]+img[*:*,110,*:*]+img[*:*,111,*:*]
+FROM tomo_cubed_64 as img
+// ["y"] tomo_cubed_64 [*:*, 46:52, *:*]
+SELECT img[*:*,46,*:*]+img[*:*,47,*:*]+img[*:*,48,*:*]+img[*:*,49,*:*]+img[*:*,50,*:*]+img[*:*,51,*:*]+img[*:*,52,*:*]
+FROM tomo_cubed_64 as img
+// ["y"] tomo_cubed_64 [*:*, 56:62, *:*]
+SELECT img[*:*,56,*:*]+img[*:*,57,*:*]+img[*:*,58,*:*]+img[*:*,59,*:*]+img[*:*,60,*:*]+img[*:*,61,*:*]+img[*:*,62,*:*]
+FROM tomo_cubed_64 as img
+// ["y"] tomo_cubed_64 [*:*, 154:160, *:*]
+SELECT img[*:*,154,*:*]+img[*:*,155,*:*]+img[*:*,156,*:*]+img[*:*,157,*:*]+img[*:*,158,*:*]+img[*:*,159,*:*]+img[*:*,160,*:*]
+FROM tomo_cubed_64 as img
+// ["z"] tomo_cubed_64 [*:*, *:*, 127:133]
+SELECT img[*:*,*:*,127]+img[*:*,*:*,128]+img[*:*,*:*,129]+img[*:*,*:*,130]+img[*:*,*:*,131]+img[*:*,*:*,132]+img[*:*,*:*,133]
+FROM tomo_cubed_64 as img
+// ["z"] tomo_cubed_64 [*:*, *:*, 79:85]
+SELECT img[*:*,*:*,79]+img[*:*,*:*,80]+img[*:*,*:*,81]+img[*:*,*:*,82]+img[*:*,*:*,83]+img[*:*,*:*,84]+img[*:*,*:*,85]
+FROM tomo_cubed_64 as img
+// ["z"] tomo_cubed_64 [*:*, *:*, 134:140]
+SELECT img[*:*,*:*,134]+img[*:*,*:*,135]+img[*:*,*:*,136]+img[*:*,*:*,137]+img[*:*,*:*,138]+img[*:*,*:*,139]+img[*:*,*:*,140]
+FROM tomo_cubed_64 as img
+// ["z"] tomo_cubed_64 [*:*, *:*, 12:18]
+SELECT img[*:*,*:*,12]+img[*:*,*:*,13]+img[*:*,*:*,14]+img[*:*,*:*,15]+img[*:*,*:*,16]+img[*:*,*:*,17]+img[*:*,*:*,18]
+FROM tomo_cubed_64 as img
+// ["z"] tomo_cubed_64 [*:*, *:*, 142:148]
+SELECT img[*:*,*:*,142]+img[*:*,*:*,143]+img[*:*,*:*,144]+img[*:*,*:*,145]+img[*:*,*:*,146]+img[*:*,*:*,147]+img[*:*,*:*,148]
+FROM tomo_cubed_64 as img
+// ["z"] tomo_cubed_64 [*:*, *:*, 128:134]
+SELECT img[*:*,*:*,128]+img[*:*,*:*,129]+img[*:*,*:*,130]+img[*:*,*:*,131]+img[*:*,*:*,132]+img[*:*,*:*,133]+img[*:*,*:*,134]
+FROM tomo_cubed_64 as img
+// ["z"] tomo_cubed_64 [*:*, *:*, 75:81]
+SELECT img[*:*,*:*,75]+img[*:*,*:*,76]+img[*:*,*:*,77]+img[*:*,*:*,78]+img[*:*,*:*,79]+img[*:*,*:*,80]+img[*:*,*:*,81]
+FROM tomo_cubed_64 as img
+// ["z"] tomo_cubed_64 [*:*, *:*, 118:124]
+SELECT img[*:*,*:*,118]+img[*:*,*:*,119]+img[*:*,*:*,120]+img[*:*,*:*,121]+img[*:*,*:*,122]+img[*:*,*:*,123]+img[*:*,*:*,124]
+FROM tomo_cubed_64 as img
+// ["z"] tomo_cubed_64 [*:*, *:*, 87:93]
+SELECT img[*:*,*:*,87]+img[*:*,*:*,88]+img[*:*,*:*,89]+img[*:*,*:*,90]+img[*:*,*:*,91]+img[*:*,*:*,92]+img[*:*,*:*,93]
+FROM tomo_cubed_64 as img
+// ["z"] tomo_cubed_64 [*:*, *:*, 23:29]
+SELECT img[*:*,*:*,23]+img[*:*,*:*,24]+img[*:*,*:*,25]+img[*:*,*:*,26]+img[*:*,*:*,27]+img[*:*,*:*,28]+img[*:*,*:*,29]
+FROM tomo_cubed_64 as img
+// ["z"] tomo_cubed_64 [*:*, *:*, 69:75]
+SELECT img[*:*,*:*,69]+img[*:*,*:*,70]+img[*:*,*:*,71]+img[*:*,*:*,72]+img[*:*,*:*,73]+img[*:*,*:*,74]+img[*:*,*:*,75]
+FROM tomo_cubed_64 as img
+// ["z"] tomo_cubed_64 [*:*, *:*, 146:152]
+SELECT img[*:*,*:*,146]+img[*:*,*:*,147]+img[*:*,*:*,148]+img[*:*,*:*,149]+img[*:*,*:*,150]+img[*:*,*:*,151]+img[*:*,*:*,152]
+FROM tomo_cubed_64 as img
+// ["z"] tomo_cubed_64 [*:*, *:*, 99:105]
+SELECT img[*:*,*:*,99]+img[*:*,*:*,100]+img[*:*,*:*,101]+img[*:*,*:*,102]+img[*:*,*:*,103]+img[*:*,*:*,104]+img[*:*,*:*,105]
+FROM tomo_cubed_64 as img
+// ["z"] tomo_cubed_64 [*:*, *:*, 135:141]
+SELECT img[*:*,*:*,135]+img[*:*,*:*,136]+img[*:*,*:*,137]+img[*:*,*:*,138]+img[*:*,*:*,139]+img[*:*,*:*,140]+img[*:*,*:*,141]
+FROM tomo_cubed_64 as img
+// ["z"] tomo_cubed_64 [*:*, *:*, 76:82]
+SELECT img[*:*,*:*,76]+img[*:*,*:*,77]+img[*:*,*:*,78]+img[*:*,*:*,79]+img[*:*,*:*,80]+img[*:*,*:*,81]+img[*:*,*:*,82]
+FROM tomo_cubed_64 as img
+// ["z"] tomo_cubed_64 [*:*, *:*, 26:32]
+SELECT img[*:*,*:*,26]+img[*:*,*:*,27]+img[*:*,*:*,28]+img[*:*,*:*,29]+img[*:*,*:*,30]+img[*:*,*:*,31]+img[*:*,*:*,32]
+FROM tomo_cubed_64 as img
+// ["z"] tomo_cubed_64 [*:*, *:*, 56:62]
+SELECT img[*:*,*:*,56]+img[*:*,*:*,57]+img[*:*,*:*,58]+img[*:*,*:*,59]+img[*:*,*:*,60]+img[*:*,*:*,61]+img[*:*,*:*,62]
+FROM tomo_cubed_64 as img
+// ["z"] tomo_cubed_64 [*:*, *:*, 94:100]
+SELECT img[*:*,*:*,94]+img[*:*,*:*,95]+img[*:*,*:*,96]+img[*:*,*:*,97]+img[*:*,*:*,98]+img[*:*,*:*,99]+img[*:*,*:*,100]
+FROM tomo_cubed_64 as img
+// ["z"] tomo_cubed_64 [*:*, *:*, 13:19]
+SELECT img[*:*,*:*,13]+img[*:*,*:*,14]+img[*:*,*:*,15]+img[*:*,*:*,16]+img[*:*,*:*,17]+img[*:*,*:*,18]+img[*:*,*:*,19]
+FROM tomo_cubed_64 as img
+// ["z"] tomo_cubed_64 [*:*, *:*, 22:28]
+SELECT img[*:*,*:*,22]+img[*:*,*:*,23]+img[*:*,*:*,24]+img[*:*,*:*,25]+img[*:*,*:*,26]+img[*:*,*:*,27]+img[*:*,*:*,28]
+FROM tomo_cubed_64 as img
diff --git a/rasodmg/test/troll_sliced.ql b/rasodmg/test/troll_sliced.ql
new file mode 100644
index 0000000..5b6ae0f
--- /dev/null
+++ b/rasodmg/test/troll_sliced.ql
@@ -0,0 +1,180 @@
+// ["x"] tomo_sliced [2:8,*:*,*:*]
+SELECT img[2,*:*,*:*]+img[3,*:*,*:*]+img[4,*:*,*:*]+img[5,*:*,*:*]+img[6,*:*,*:*]+img[7,*:*,*:*]+img[8,*:*,*:*]
+FROM tomo_sliced as img
+// ["x"] tomo_sliced [86:92,*:*,*:*]
+SELECT img[86,*:*,*:*]+img[87,*:*,*:*]+img[88,*:*,*:*]+img[89,*:*,*:*]+img[90,*:*,*:*]+img[91,*:*,*:*]+img[92,*:*,*:*]
+FROM tomo_sliced as img
+// ["x"] tomo_sliced [2:8,*:*,*:*]
+SELECT img[2,*:*,*:*]+img[3,*:*,*:*]+img[4,*:*,*:*]+img[5,*:*,*:*]+img[6,*:*,*:*]+img[7,*:*,*:*]+img[8,*:*,*:*]
+FROM tomo_sliced as img
+// ["x"] tomo_sliced [104:110,*:*,*:*]
+SELECT img[104,*:*,*:*]+img[105,*:*,*:*]+img[106,*:*,*:*]+img[107,*:*,*:*]+img[108,*:*,*:*]+img[109,*:*,*:*]+img[110,*:*,*:*]
+FROM tomo_sliced as img
+// ["x"] tomo_sliced [236:242,*:*,*:*]
+SELECT img[236,*:*,*:*]+img[237,*:*,*:*]+img[238,*:*,*:*]+img[239,*:*,*:*]+img[240,*:*,*:*]+img[241,*:*,*:*]+img[242,*:*,*:*]
+FROM tomo_sliced as img
+// ["x"] tomo_sliced [145:151,*:*,*:*]
+SELECT img[145,*:*,*:*]+img[146,*:*,*:*]+img[147,*:*,*:*]+img[148,*:*,*:*]+img[149,*:*,*:*]+img[150,*:*,*:*]+img[151,*:*,*:*]
+FROM tomo_sliced as img
+// ["x"] tomo_sliced [242:248,*:*,*:*]
+SELECT img[242,*:*,*:*]+img[243,*:*,*:*]+img[244,*:*,*:*]+img[245,*:*,*:*]+img[246,*:*,*:*]+img[247,*:*,*:*]+img[248,*:*,*:*]
+FROM tomo_sliced as img
+// ["x"] tomo_sliced [236:242,*:*,*:*]
+SELECT img[236,*:*,*:*]+img[237,*:*,*:*]+img[238,*:*,*:*]+img[239,*:*,*:*]+img[240,*:*,*:*]+img[241,*:*,*:*]+img[242,*:*,*:*]
+FROM tomo_sliced as img
+// ["x"] tomo_sliced [246:252,*:*,*:*]
+SELECT img[246,*:*,*:*]+img[247,*:*,*:*]+img[248,*:*,*:*]+img[249,*:*,*:*]+img[250,*:*,*:*]+img[251,*:*,*:*]+img[252,*:*,*:*]
+FROM tomo_sliced as img
+// ["x"] tomo_sliced [189:195,*:*,*:*]
+SELECT img[189,*:*,*:*]+img[190,*:*,*:*]+img[191,*:*,*:*]+img[192,*:*,*:*]+img[193,*:*,*:*]+img[194,*:*,*:*]+img[195,*:*,*:*]
+FROM tomo_sliced as img
+// ["x"] tomo_sliced [136:142,*:*,*:*]
+SELECT img[136,*:*,*:*]+img[137,*:*,*:*]+img[138,*:*,*:*]+img[139,*:*,*:*]+img[140,*:*,*:*]+img[141,*:*,*:*]+img[142,*:*,*:*]
+FROM tomo_sliced as img
+// ["x"] tomo_sliced [100:106,*:*,*:*]
+SELECT img[100,*:*,*:*]+img[101,*:*,*:*]+img[102,*:*,*:*]+img[103,*:*,*:*]+img[104,*:*,*:*]+img[105,*:*,*:*]+img[106,*:*,*:*]
+FROM tomo_sliced as img
+// ["x"] tomo_sliced [49:55,*:*,*:*]
+SELECT img[49,*:*,*:*]+img[50,*:*,*:*]+img[51,*:*,*:*]+img[52,*:*,*:*]+img[53,*:*,*:*]+img[54,*:*,*:*]+img[55,*:*,*:*]
+FROM tomo_sliced as img
+// ["x"] tomo_sliced [101:107,*:*,*:*]
+SELECT img[101,*:*,*:*]+img[102,*:*,*:*]+img[103,*:*,*:*]+img[104,*:*,*:*]+img[105,*:*,*:*]+img[106,*:*,*:*]+img[107,*:*,*:*]
+FROM tomo_sliced as img
+// ["x"] tomo_sliced [238:244,*:*,*:*]
+SELECT img[238,*:*,*:*]+img[239,*:*,*:*]+img[240,*:*,*:*]+img[241,*:*,*:*]+img[242,*:*,*:*]+img[243,*:*,*:*]+img[244,*:*,*:*]
+FROM tomo_sliced as img
+// ["x"] tomo_sliced [56:62,*:*,*:*]
+SELECT img[56,*:*,*:*]+img[57,*:*,*:*]+img[58,*:*,*:*]+img[59,*:*,*:*]+img[60,*:*,*:*]+img[61,*:*,*:*]+img[62,*:*,*:*]
+FROM tomo_sliced as img
+// ["x"] tomo_sliced [57:63,*:*,*:*]
+SELECT img[57,*:*,*:*]+img[58,*:*,*:*]+img[59,*:*,*:*]+img[60,*:*,*:*]+img[61,*:*,*:*]+img[62,*:*,*:*]+img[63,*:*,*:*]
+FROM tomo_sliced as img
+// ["x"] tomo_sliced [146:152,*:*,*:*]
+SELECT img[146,*:*,*:*]+img[147,*:*,*:*]+img[148,*:*,*:*]+img[149,*:*,*:*]+img[150,*:*,*:*]+img[151,*:*,*:*]+img[152,*:*,*:*]
+FROM tomo_sliced as img
+// ["x"] tomo_sliced [212:218,*:*,*:*]
+SELECT img[212,*:*,*:*]+img[213,*:*,*:*]+img[214,*:*,*:*]+img[215,*:*,*:*]+img[216,*:*,*:*]+img[217,*:*,*:*]+img[218,*:*,*:*]
+FROM tomo_sliced as img
+// ["x"] tomo_sliced [172:178,*:*,*:*]
+SELECT img[172,*:*,*:*]+img[173,*:*,*:*]+img[174,*:*,*:*]+img[175,*:*,*:*]+img[176,*:*,*:*]+img[177,*:*,*:*]+img[178,*:*,*:*]
+FROM tomo_sliced as img
+// ["y"] tomo_sliced [*:*, 57:63, *:*]
+SELECT img[*:*,57,*:*]+img[*:*,58,*:*]+img[*:*,59,*:*]+img[*:*,60,*:*]+img[*:*,61,*:*]+img[*:*,62,*:*]+img[*:*,63,*:*]
+FROM tomo_sliced as img
+// ["y"] tomo_sliced [*:*, 225:231, *:*]
+SELECT img[*:*,225,*:*]+img[*:*,226,*:*]+img[*:*,227,*:*]+img[*:*,228,*:*]+img[*:*,229,*:*]+img[*:*,230,*:*]+img[*:*,231,*:*]
+FROM tomo_sliced as img
+// ["y"] tomo_sliced [*:*, 96:102, *:*]
+SELECT img[*:*,96,*:*]+img[*:*,97,*:*]+img[*:*,98,*:*]+img[*:*,99,*:*]+img[*:*,100,*:*]+img[*:*,101,*:*]+img[*:*,102,*:*]
+FROM tomo_sliced as img
+// ["y"] tomo_sliced [*:*, 3:9, *:*]
+SELECT img[*:*,3,*:*]+img[*:*,4,*:*]+img[*:*,5,*:*]+img[*:*,6,*:*]+img[*:*,7,*:*]+img[*:*,8,*:*]+img[*:*,9,*:*]
+FROM tomo_sliced as img
+// ["y"] tomo_sliced [*:*, 60:66, *:*]
+SELECT img[*:*,60,*:*]+img[*:*,61,*:*]+img[*:*,62,*:*]+img[*:*,63,*:*]+img[*:*,64,*:*]+img[*:*,65,*:*]+img[*:*,66,*:*]
+FROM tomo_sliced as img
+// ["y"] tomo_sliced [*:*, 133:139, *:*]
+SELECT img[*:*,133,*:*]+img[*:*,134,*:*]+img[*:*,135,*:*]+img[*:*,136,*:*]+img[*:*,137,*:*]+img[*:*,138,*:*]+img[*:*,139,*:*]
+FROM tomo_sliced as img
+// ["y"] tomo_sliced [*:*, 62:68, *:*]
+SELECT img[*:*,62,*:*]+img[*:*,63,*:*]+img[*:*,64,*:*]+img[*:*,65,*:*]+img[*:*,66,*:*]+img[*:*,67,*:*]+img[*:*,68,*:*]
+FROM tomo_sliced as img
+// ["y"] tomo_sliced [*:*, 112:118, *:*]
+SELECT img[*:*,112,*:*]+img[*:*,113,*:*]+img[*:*,114,*:*]+img[*:*,115,*:*]+img[*:*,116,*:*]+img[*:*,117,*:*]+img[*:*,118,*:*]
+FROM tomo_sliced as img
+// ["y"] tomo_sliced [*:*, 206:212, *:*]
+SELECT img[*:*,206,*:*]+img[*:*,207,*:*]+img[*:*,208,*:*]+img[*:*,209,*:*]+img[*:*,210,*:*]+img[*:*,211,*:*]+img[*:*,212,*:*]
+FROM tomo_sliced as img
+// ["y"] tomo_sliced [*:*, 136:142, *:*]
+SELECT img[*:*,136,*:*]+img[*:*,137,*:*]+img[*:*,138,*:*]+img[*:*,139,*:*]+img[*:*,140,*:*]+img[*:*,141,*:*]+img[*:*,142,*:*]
+FROM tomo_sliced as img
+// ["y"] tomo_sliced [*:*, 22:28, *:*]
+SELECT img[*:*,22,*:*]+img[*:*,23,*:*]+img[*:*,24,*:*]+img[*:*,25,*:*]+img[*:*,26,*:*]+img[*:*,27,*:*]+img[*:*,28,*:*]
+FROM tomo_sliced as img
+// ["y"] tomo_sliced [*:*, 121:127, *:*]
+SELECT img[*:*,121,*:*]+img[*:*,122,*:*]+img[*:*,123,*:*]+img[*:*,124,*:*]+img[*:*,125,*:*]+img[*:*,126,*:*]+img[*:*,127,*:*]
+FROM tomo_sliced as img
+// ["y"] tomo_sliced [*:*, 42:48, *:*]
+SELECT img[*:*,42,*:*]+img[*:*,43,*:*]+img[*:*,44,*:*]+img[*:*,45,*:*]+img[*:*,46,*:*]+img[*:*,47,*:*]+img[*:*,48,*:*]
+FROM tomo_sliced as img
+// ["y"] tomo_sliced [*:*, 110:116, *:*]
+SELECT img[*:*,110,*:*]+img[*:*,111,*:*]+img[*:*,112,*:*]+img[*:*,113,*:*]+img[*:*,114,*:*]+img[*:*,115,*:*]+img[*:*,116,*:*]
+FROM tomo_sliced as img
+// ["y"] tomo_sliced [*:*, 75:81, *:*]
+SELECT img[*:*,75,*:*]+img[*:*,76,*:*]+img[*:*,77,*:*]+img[*:*,78,*:*]+img[*:*,79,*:*]+img[*:*,80,*:*]+img[*:*,81,*:*]
+FROM tomo_sliced as img
+// ["y"] tomo_sliced [*:*, 162:168, *:*]
+SELECT img[*:*,162,*:*]+img[*:*,163,*:*]+img[*:*,164,*:*]+img[*:*,165,*:*]+img[*:*,166,*:*]+img[*:*,167,*:*]+img[*:*,168,*:*]
+FROM tomo_sliced as img
+// ["y"] tomo_sliced [*:*, 80:86, *:*]
+SELECT img[*:*,80,*:*]+img[*:*,81,*:*]+img[*:*,82,*:*]+img[*:*,83,*:*]+img[*:*,84,*:*]+img[*:*,85,*:*]+img[*:*,86,*:*]
+FROM tomo_sliced as img
+// ["y"] tomo_sliced [*:*, 50:56, *:*]
+SELECT img[*:*,50,*:*]+img[*:*,51,*:*]+img[*:*,52,*:*]+img[*:*,53,*:*]+img[*:*,54,*:*]+img[*:*,55,*:*]+img[*:*,56,*:*]
+FROM tomo_sliced as img
+// ["y"] tomo_sliced [*:*, 174:180, *:*]
+SELECT img[*:*,174,*:*]+img[*:*,175,*:*]+img[*:*,176,*:*]+img[*:*,177,*:*]+img[*:*,178,*:*]+img[*:*,179,*:*]+img[*:*,180,*:*]
+FROM tomo_sliced as img
+// ["y"] tomo_sliced [*:*, 33:39, *:*]
+SELECT img[*:*,33,*:*]+img[*:*,34,*:*]+img[*:*,35,*:*]+img[*:*,36,*:*]+img[*:*,37,*:*]+img[*:*,38,*:*]+img[*:*,39,*:*]
+FROM tomo_sliced as img
+// ["z"] tomo_sliced [*:*, *:*, 125:131]
+SELECT img[*:*,*:*,125]+img[*:*,*:*,126]+img[*:*,*:*,127]+img[*:*,*:*,128]+img[*:*,*:*,129]+img[*:*,*:*,130]+img[*:*,*:*,131]
+FROM tomo_sliced as img
+// ["z"] tomo_sliced [*:*, *:*, 99:105]
+SELECT img[*:*,*:*,99]+img[*:*,*:*,100]+img[*:*,*:*,101]+img[*:*,*:*,102]+img[*:*,*:*,103]+img[*:*,*:*,104]+img[*:*,*:*,105]
+FROM tomo_sliced as img
+// ["z"] tomo_sliced [*:*, *:*, 138:144]
+SELECT img[*:*,*:*,138]+img[*:*,*:*,139]+img[*:*,*:*,140]+img[*:*,*:*,141]+img[*:*,*:*,142]+img[*:*,*:*,143]+img[*:*,*:*,144]
+FROM tomo_sliced as img
+// ["z"] tomo_sliced [*:*, *:*, 102:108]
+SELECT img[*:*,*:*,102]+img[*:*,*:*,103]+img[*:*,*:*,104]+img[*:*,*:*,105]+img[*:*,*:*,106]+img[*:*,*:*,107]+img[*:*,*:*,108]
+FROM tomo_sliced as img
+// ["z"] tomo_sliced [*:*, *:*, 89:95]
+SELECT img[*:*,*:*,89]+img[*:*,*:*,90]+img[*:*,*:*,91]+img[*:*,*:*,92]+img[*:*,*:*,93]+img[*:*,*:*,94]+img[*:*,*:*,95]
+FROM tomo_sliced as img
+// ["z"] tomo_sliced [*:*, *:*, 106:112]
+SELECT img[*:*,*:*,106]+img[*:*,*:*,107]+img[*:*,*:*,108]+img[*:*,*:*,109]+img[*:*,*:*,110]+img[*:*,*:*,111]+img[*:*,*:*,112]
+FROM tomo_sliced as img
+// ["z"] tomo_sliced [*:*, *:*, 38:44]
+SELECT img[*:*,*:*,38]+img[*:*,*:*,39]+img[*:*,*:*,40]+img[*:*,*:*,41]+img[*:*,*:*,42]+img[*:*,*:*,43]+img[*:*,*:*,44]
+FROM tomo_sliced as img
+// ["z"] tomo_sliced [*:*, *:*, 11:17]
+SELECT img[*:*,*:*,11]+img[*:*,*:*,12]+img[*:*,*:*,13]+img[*:*,*:*,14]+img[*:*,*:*,15]+img[*:*,*:*,16]+img[*:*,*:*,17]
+FROM tomo_sliced as img
+// ["z"] tomo_sliced [*:*, *:*, 112:118]
+SELECT img[*:*,*:*,112]+img[*:*,*:*,113]+img[*:*,*:*,114]+img[*:*,*:*,115]+img[*:*,*:*,116]+img[*:*,*:*,117]+img[*:*,*:*,118]
+FROM tomo_sliced as img
+// ["z"] tomo_sliced [*:*, *:*, 127:133]
+SELECT img[*:*,*:*,127]+img[*:*,*:*,128]+img[*:*,*:*,129]+img[*:*,*:*,130]+img[*:*,*:*,131]+img[*:*,*:*,132]+img[*:*,*:*,133]
+FROM tomo_sliced as img
+// ["z"] tomo_sliced [*:*, *:*, 71:77]
+SELECT img[*:*,*:*,71]+img[*:*,*:*,72]+img[*:*,*:*,73]+img[*:*,*:*,74]+img[*:*,*:*,75]+img[*:*,*:*,76]+img[*:*,*:*,77]
+FROM tomo_sliced as img
+// ["z"] tomo_sliced [*:*, *:*, 57:63]
+SELECT img[*:*,*:*,57]+img[*:*,*:*,58]+img[*:*,*:*,59]+img[*:*,*:*,60]+img[*:*,*:*,61]+img[*:*,*:*,62]+img[*:*,*:*,63]
+FROM tomo_sliced as img
+// ["z"] tomo_sliced [*:*, *:*, 144:150]
+SELECT img[*:*,*:*,144]+img[*:*,*:*,145]+img[*:*,*:*,146]+img[*:*,*:*,147]+img[*:*,*:*,148]+img[*:*,*:*,149]+img[*:*,*:*,150]
+FROM tomo_sliced as img
+// ["z"] tomo_sliced [*:*, *:*, 130:136]
+SELECT img[*:*,*:*,130]+img[*:*,*:*,131]+img[*:*,*:*,132]+img[*:*,*:*,133]+img[*:*,*:*,134]+img[*:*,*:*,135]+img[*:*,*:*,136]
+FROM tomo_sliced as img
+// ["z"] tomo_sliced [*:*, *:*, 101:107]
+SELECT img[*:*,*:*,101]+img[*:*,*:*,102]+img[*:*,*:*,103]+img[*:*,*:*,104]+img[*:*,*:*,105]+img[*:*,*:*,106]+img[*:*,*:*,107]
+FROM tomo_sliced as img
+// ["z"] tomo_sliced [*:*, *:*, 104:110]
+SELECT img[*:*,*:*,104]+img[*:*,*:*,105]+img[*:*,*:*,106]+img[*:*,*:*,107]+img[*:*,*:*,108]+img[*:*,*:*,109]+img[*:*,*:*,110]
+FROM tomo_sliced as img
+// ["z"] tomo_sliced [*:*, *:*, 116:122]
+SELECT img[*:*,*:*,116]+img[*:*,*:*,117]+img[*:*,*:*,118]+img[*:*,*:*,119]+img[*:*,*:*,120]+img[*:*,*:*,121]+img[*:*,*:*,122]
+FROM tomo_sliced as img
+// ["z"] tomo_sliced [*:*, *:*, 12:18]
+SELECT img[*:*,*:*,12]+img[*:*,*:*,13]+img[*:*,*:*,14]+img[*:*,*:*,15]+img[*:*,*:*,16]+img[*:*,*:*,17]+img[*:*,*:*,18]
+FROM tomo_sliced as img
+// ["z"] tomo_sliced [*:*, *:*, 86:92]
+SELECT img[*:*,*:*,86]+img[*:*,*:*,87]+img[*:*,*:*,88]+img[*:*,*:*,89]+img[*:*,*:*,90]+img[*:*,*:*,91]+img[*:*,*:*,92]
+FROM tomo_sliced as img
+// ["z"] tomo_sliced [*:*, *:*, 44:50]
+SELECT img[*:*,*:*,44]+img[*:*,*:*,45]+img[*:*,*:*,46]+img[*:*,*:*,47]+img[*:*,*:*,48]+img[*:*,*:*,49]+img[*:*,*:*,50]
+FROM tomo_sliced as img
diff --git a/rasodmg/test/tsel_16.ql b/rasodmg/test/tsel_16.ql
new file mode 100644
index 0000000..defdca1
--- /dev/null
+++ b/rasodmg/test/tsel_16.ql
@@ -0,0 +1,43 @@
+// This query tests different selectivities a query box starting at
+// the origin on tomo_cubed_16.
+
+// [0.5] cubed_16, selectivity 0,5%
+
+select img[0:44,0:44,0:26]
+from tomo_cubed_16 as img
+
+// [1] cubed_16, selectivity 1%
+
+select img[0:55,0:55,0:33]
+from tomo_cubed_16 as img
+
+// [2] cubed_16, selectivity 2%
+
+select img[0:69,0:69,0:42]
+from tomo_cubed_16 as img
+
+// [5] cubed_16, selectivity 5%
+
+select img[0:94,0:94,0:56]
+from tomo_cubed_16 as img
+
+// [10] cubed_16, selectivity 10%
+
+select img[0:118,0:118,0:71]
+from tomo_cubed_16 as img
+
+// [20] cubed_16, selectivity 0%
+
+select img[0:149,0:149,0:89]
+from tomo_cubed_16 as img
+
+// [50] cubed_16, selectivity 50%
+
+select img[0:202,0:202,0:121]
+from tomo_cubed_16 as img
+
+// [100] cubed_16, selectivity 100%
+
+select img[0:255,0:255,0:153]
+from tomo_cubed_16 as img
+
diff --git a/rasodmg/test/tsel_32.ql b/rasodmg/test/tsel_32.ql
new file mode 100644
index 0000000..e2360a5
--- /dev/null
+++ b/rasodmg/test/tsel_32.ql
@@ -0,0 +1,43 @@
+// This query tests different selectivities a query box starting at
+// the origin on tomo_cubed.
+
+// [0.5] cubed, selectivity 0,5%
+
+select img[0:44,0:44,0:26]
+from tomo_cubed as img
+
+// [1] cubed, selectivity 1%
+
+select img[0:55,0:55,0:33]
+from tomo_cubed as img
+
+// [2] cubed, selectivity 2%
+
+select img[0:69,0:69,0:42]
+from tomo_cubed as img
+
+// [5] cubed, selectivity 5%
+
+select img[0:94,0:94,0:56]
+from tomo_cubed as img
+
+// [10] cubed, selectivity 10%
+
+select img[0:118,0:118,0:71]
+from tomo_cubed as img
+
+// [20] cubed, selectivity 0%
+
+select img[0:149,0:149,0:89]
+from tomo_cubed as img
+
+// [50] cubed, selectivity 50%
+
+select img[0:202,0:202,0:121]
+from tomo_cubed as img
+
+// [100] cubed, selectivity 100%
+
+select img[0:255,0:255,0:153]
+from tomo_cubed as img
+
diff --git a/rasodmg/test/tsel_64.ql b/rasodmg/test/tsel_64.ql
new file mode 100644
index 0000000..da24627
--- /dev/null
+++ b/rasodmg/test/tsel_64.ql
@@ -0,0 +1,43 @@
+// This query tests different selectivities a query box starting at
+// the origin on tomo_cubed_64.
+
+// [0.5] cubed_64, selectivity 0,5%
+
+select img[0:44,0:44,0:26]
+from tomo_cubed_64 as img
+
+// [1] cubed_64, selectivity 1%
+
+select img[0:55,0:55,0:33]
+from tomo_cubed_64 as img
+
+// [2] cubed_64, selectivity 2%
+
+select img[0:69,0:69,0:42]
+from tomo_cubed_64 as img
+
+// [5] cubed_64, selectivity 5%
+
+select img[0:94,0:94,0:56]
+from tomo_cubed_64 as img
+
+// [10] cubed_64, selectivity 10%
+
+select img[0:118,0:118,0:71]
+from tomo_cubed_64 as img
+
+// [20] cubed_64, selectivity 0%
+
+select img[0:149,0:149,0:89]
+from tomo_cubed_64 as img
+
+// [50] cubed_64, selectivity 50%
+
+select img[0:202,0:202,0:121]
+from tomo_cubed_64 as img
+
+// [100] cubed_64, selectivity 100%
+
+select img[0:255,0:255,0:153]
+from tomo_cubed_64 as img
+
diff --git a/rasodmg/test/tsel_sliced.ql b/rasodmg/test/tsel_sliced.ql
new file mode 100644
index 0000000..4755357
--- /dev/null
+++ b/rasodmg/test/tsel_sliced.ql
@@ -0,0 +1,43 @@
+// This query tests different selectivities a query box starting at
+// the origin on tomo_sliced.
+
+// [0.5] sliced, selectivity 0,5%
+
+select img[0:44,0:44,0:26]
+from tomo_sliced as img
+
+// [1] sliced, selectivity 1%
+
+select img[0:55,0:55,0:33]
+from tomo_sliced as img
+
+// [2] sliced, selectivity 2%
+
+select img[0:69,0:69,0:42]
+from tomo_sliced as img
+
+// [5] sliced, selectivity 5%
+
+select img[0:94,0:94,0:56]
+from tomo_sliced as img
+
+// [10] sliced, selectivity 10%
+
+select img[0:118,0:118,0:71]
+from tomo_sliced as img
+
+// [20] sliced, selectivity 0%
+
+select img[0:149,0:149,0:89]
+from tomo_sliced as img
+
+// [50] sliced, selectivity 50%
+
+select img[0:202,0:202,0:121]
+from tomo_sliced as img
+
+// [100] sliced, selectivity 100%
+
+select img[0:255,0:255,0:153]
+from tomo_sliced as img
+
diff --git a/rasodmg/tiling.cc b/rasodmg/tiling.cc
new file mode 100644
index 0000000..89801c3
--- /dev/null
+++ b/rasodmg/tiling.cc
@@ -0,0 +1,309 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: tiling.cc
+ *
+ * MODULE: rasodmg
+ * CLASS: r_Tiling
+ *
+ * COMMENTS:
+ * None
+ *
+*/
+
+//for max min
+#include <algorithm>
+
+//for pow
+#include <math.h>
+#include <iostream>
+#include "rasodmg/tiling.hh"
+#include "raslib/rmdebug.hh"
+#include "raslib/minterval.hh"
+#include "rasodmg/gmarray.hh"
+#include "raslib/dlist.hh"
+
+const char*
+r_Tiling::ASTERIX = "*";
+const char*
+r_Tiling::COLON = ";";
+const char*
+r_Tiling::COMMA = ",";
+const char*
+r_Tiling::LSQRBRA = "[";
+const char*
+r_Tiling::RSQRBRA = "]";
+const long
+r_Tiling::DefaultBase = 10;
+
+r_Tiling::~r_Tiling()
+ {
+ }
+
+const char*
+r_No_Tiling::description = "no parameters";
+
+r_No_Tiling::r_No_Tiling(const char* encoded) throw(r_Error)
+ {
+ //we don't use encoded string, it is present in order to have
+ //uniform interface "char* constructor" for every tiling strategy
+ }
+
+r_No_Tiling::r_No_Tiling()
+ {
+ }
+
+r_No_Tiling::~r_No_Tiling()
+ {
+ }
+
+void
+r_No_Tiling::print_status(std::ostream& os) const
+ {
+ os << "r_No_Tiling[ ]";
+ }
+
+bool
+r_No_Tiling::is_compatible(const r_Minterval& obj_domain, r_Bytes cellTypeSize) const
+ {
+ return true;
+ }
+
+std::vector<r_Minterval>*
+r_No_Tiling::compute_tiles(const r_Minterval& obj_domain, r_Bytes cellTypeSize) const throw (r_Error)
+ {
+ RMDBGENTER(4, RMDebug::module_rasodmg, "r_No_Tiling", "compute_tiles(" << obj_domain << ", " << cellTypeSize << ")")
+ std::vector<r_Minterval>* result = new std::vector<r_Minterval>;
+ result->push_back(obj_domain);
+ RMDBGEXIT(4, RMDebug::module_rasodmg, "r_No_Tiling", "compute_tiles() " << *result)
+ return result;
+ }
+
+r_Tiling*
+r_No_Tiling::clone() const
+ {
+ r_Tiling* clo = new r_No_Tiling();
+ return clo;
+ }
+
+r_Tiling_Scheme
+r_No_Tiling::get_tiling_scheme() const
+ {
+ return r_NoTiling;
+ }
+
+std::ostream&
+operator<<(std::ostream& os, const r_Tiling& t)
+ {
+ t.print_status(os);
+ return os;
+ }
+
+const char*
+r_Size_Tiling::description = "tile configuration or tile dimension and tile size (in bytes) (ex: \"[0:9,0:9];100\" or \"2;100\")";
+
+r_Size_Tiling::r_Size_Tiling(const char* encoded) throw (r_Error)
+ : tile_size(0)
+{
+ if(!encoded) {
+ RMInit::logOut << "r_Size_Tiling::r_Size_Tiling(" << (encoded?encoded:"NULL") << ")" << endl;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+
+ r_Bytes tileS=strtol(encoded, (char**)NULL, DefaultBase);
+ if(tileS<=0) {
+ RMInit::logOut << "r_Size_Tiling::r_Size_Tiling(" << encoded << "): Error decoding tile size." << endl;
+ throw r_Error(TILINGPARAMETERNOTCORRECT);
+ }
+ tile_size = tileS;
+}
+
+r_Size_Tiling::r_Size_Tiling(r_Bytes ts) :
+ tile_size(ts)
+ {
+ }
+
+r_Size_Tiling::~r_Size_Tiling()
+ {
+ }
+
+r_Bytes
+r_Size_Tiling::get_tile_size() const
+ {
+ return tile_size;
+ }
+
+void
+r_Size_Tiling::print_status(std::ostream& os) const
+ {
+ os << "r_Size_Tiling[ tile size = " << tile_size << " ]";
+ }
+
+bool
+r_Size_Tiling::is_compatible(const r_Minterval& obj_domain, r_Bytes cellTypeSize) const
+ {
+ return ((cellTypeSize <= tile_size) && (obj_domain.dimension() != 0));
+ }
+
+std::vector<r_Minterval>*
+r_Size_Tiling::compute_tiles(const r_Minterval& obj_domain, r_Bytes cellTypeSize) const throw (r_Error)
+ {
+ RMDBGENTER(4, RMDebug::module_rasodmg, "r_Size_Tiling", "compute_tiles(" << obj_domain << ", " << cellTypeSize << ")")
+ if (cellTypeSize > tile_size)
+ {
+ RMInit::logOut << "r_Size_Tiling::compute_tiles(" << obj_domain << ", " << cellTypeSize << ") tile size (" << tile_size << ") is smaller than type length (" << cellTypeSize << ")" << endl;
+ throw r_Error(TILESIZETOOSMALL);
+ }
+ std::vector<r_Minterval>* result = new std::vector<r_Minterval>;
+ r_Minterval bigDom = obj_domain;
+ r_Dimension dim = bigDom.dimension();
+ r_Minterval tileDom(dim);
+ // compute the domain of the small tiles
+ // tiles are n-dimensional cubes with edge length n-th root of max tile size
+ RMDBGMIDDLE(4, RMDebug::module_rasodmg, "r_Size_Tiling", "tile size " << get_tile_size())
+ r_Range edgeLength = (r_Range)std::max((r_Range)floor(pow(get_tile_size()/cellTypeSize, 1/(double)dim)), 1);
+ r_Dimension dimcnt = 0;
+ for (dimcnt = 0; dimcnt < dim; dimcnt++)
+ tileDom << r_Sinterval((r_Range)0, edgeLength - 1);
+
+ r_Minterval currDom(dim);
+ r_Point cursor(dim);
+ r_Point tileSize;
+ r_Point origin;
+ bool done = 0;
+
+ // initialize cursor
+ for (dimcnt = 0; dimcnt < dim; dimcnt++)
+ cursor[dimcnt] = 0;
+
+ // calculate size of Tiles
+ tileSize = tileDom.get_extent();
+
+ // origin of bigTile
+ origin = bigDom.get_origin();
+
+ // initialize currDom
+ for (dimcnt=0; dimcnt < dim; dimcnt++)
+ currDom << r_Sinterval((r_Range)origin[dimcnt], (r_Range)(origin[dimcnt] + tileSize[dimcnt] - 1));
+ // resets tileDom to lower left side of bigTile
+ tileDom = currDom;
+
+ // intersect with bigTile
+ currDom.intersection_with(bigDom);
+
+ // iterate with smallTile over bigTile
+ while (!done)
+ {
+ currDom.intersection_with(bigDom);
+ // create new smallTile
+ r_Minterval smallTile(dim);
+
+ smallTile = currDom;
+ // insert tile in set
+ result->push_back(smallTile);
+
+ // increment cursor, start with highest dimension
+ r_Dimension i = cursor.dimension() - 1;
+ cursor[i] += tileSize[i];
+ // move cursor
+ currDom = tileDom.create_translation(cursor);
+ while (!(currDom.intersects_with( bigDom )))
+ {
+ cursor[i] = 0;
+ if (i == 0)
+ {
+ done = true;
+ break;
+ }
+ i--;
+ cursor[i] += tileSize[i];
+ // move cursor
+ currDom = tileDom.create_translation(cursor);
+ }
+ }
+ RMDBGEXIT(4, RMDebug::module_rasodmg, "r_Size_Tiling", "compute_tiles() " << *result)
+ return result;
+ }
+
+r_Tiling*
+r_Size_Tiling::clone() const
+ {
+ r_Tiling* clo = new r_Size_Tiling(tile_size);
+ return clo;
+ }
+
+r_Tiling_Scheme
+r_Size_Tiling::get_tiling_scheme() const
+ {
+ return r_SizeTiling;
+ }
+
+/*
+std::ostream&
+operator<<(std::ostream& os, const r_Size_Tiling& t)
+ {
+ t.print_status(os);
+ return os;
+ }
+*/
+
+r_Dimension_Tiling::r_Dimension_Tiling(r_Dimension dim, r_Bytes ts)
+ : r_Size_Tiling(ts),
+ dimension(dim)
+ {
+ }
+
+r_Dimension_Tiling::~r_Dimension_Tiling()
+ {
+ }
+
+r_Dimension
+r_Dimension_Tiling::get_dimension() const
+ {
+ return dimension;
+ }
+
+void
+r_Dimension_Tiling::print_status(std::ostream& os) const
+ {
+ os << "r_Dimension_Tiling[ ";
+ r_Size_Tiling::print_status(os);
+ os << " dimension = " << dimension << " ]";
+ }
+
+bool
+r_Dimension_Tiling::is_compatible(const r_Minterval& obj_domain, r_Bytes cellTypeSize) const
+ {
+ return ((obj_domain.dimension() == dimension) && r_Size_Tiling::is_compatible(obj_domain, cellTypeSize));
+ }
+
+/*
+std::ostream&
+operator<<(std::ostream& os, const r_Dimension_Tiling& t)
+ {
+ t.print_status(os);
+ return os;
+ }
+*/
+
+
diff --git a/rasodmg/tiling.hh b/rasodmg/tiling.hh
new file mode 100644
index 0000000..e178e0a
--- /dev/null
+++ b/rasodmg/tiling.hh
@@ -0,0 +1,228 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: tiling.hh
+ *
+ * MODULE: rasodmg
+ * CLASS: r_Tiling
+ *
+ * COMMENTS:
+ * None
+*/
+
+#ifndef _R_TILING_HH_
+#define _R_TILING_HH_
+
+class r_Tiling;
+class r_No_Tiling;
+class r_Size_Tiling;
+class r_Dimension_Tiling;
+class r_Minterval;
+
+// Include statements
+
+#include <vector>
+#include <iostream>
+using std::cout;
+
+#include "raslib/rminit.hh"
+#include "raslib/odmgtypes.hh"
+#include "raslib/mddtypes.hh"
+#include "raslib/error.hh"
+
+//@ManMemo: Module {\bf rasodmg}
+
+/*@Doc:
+
+ The {\tt r_Tiling} class is used to specify in which way the tiling is done
+ by the system. The core method that does that is called {\tt decomposeMDD()}
+ and must be implemented by all derived classes. It takes an object that
+ hasn't yet been split and divides it into tiles. Each derived class
+ implements a diferent decomposition method.
+*/
+
+class r_Tiling
+ {
+ public:
+
+ /// does not do anything
+ virtual ~r_Tiling();
+
+ /// Prints the current status of the object
+ virtual void print_status(std::ostream& os) const = 0;
+
+ /// Check compatibility of object domain with this tiling
+ virtual bool is_compatible(const r_Minterval& obj_domain, r_Bytes cellTypeSize) const = 0;
+
+ /// Decompose an object in tiles
+ virtual std::vector<r_Minterval>* compute_tiles(const r_Minterval& obj_domain, r_Bytes cell_size) const throw (r_Error) = 0;
+ /**
+ This method provides the core funcionality of this class. All derived
+ classes must implement it. As input parameters it takes the big object to
+ be decomposed and returns a set of tiles that compose the big object.
+ This method throws an exeception when the dimension specified, extend or
+ the cell_size are incompatible with the current tiling. You can check
+ compatibility by invoking is_compatible.
+ */
+
+ /// Clones this object
+ virtual r_Tiling* clone() const = 0;
+ /**
+ This method is similar to a copy constructor, this is, is returns a copy of
+ the current object. Derived classes must explicitly implement this method.
+ */
+
+ virtual r_Tiling_Scheme get_tiling_scheme() const = 0;
+ /**
+ return the type of tiling scheme
+ */
+
+ static const char* ASTERIX;
+ static const char* COLON;
+ static const char* COMMA;
+ static const char* LSQRBRA;
+ static const char* RSQRBRA;
+ static const long DefaultBase;
+ };
+
+class r_Size_Tiling : public r_Tiling
+ {
+ public:
+ /// Constructor that reads everything from a string
+ /// e.g."100"
+ r_Size_Tiling(const char* encoded) throw (r_Error);
+
+ /// Constructor for this object (Takes tile size as parameter)
+ r_Size_Tiling(r_Bytes ts = RMInit::clientTileSize);
+
+ /// does not do anything
+ virtual ~r_Size_Tiling();
+
+ /// Gets the current tile size
+ r_Bytes get_tile_size() const;
+
+ virtual void print_status(std::ostream& os) const;
+
+ /// returns true if the cellTypeSize is smaller or equal to the tile size and obj_domain has more than 0 dimensions
+ virtual bool is_compatible(const r_Minterval& obj_domain, r_Bytes cellTypeSize) const;
+
+ virtual std::vector<r_Minterval>* compute_tiles(const r_Minterval& obj_domain, r_Bytes cellTypeSize) const throw (r_Error);
+
+ virtual r_Tiling* clone() const;
+
+ virtual r_Tiling_Scheme get_tiling_scheme() const;
+
+ static const char* description;
+
+ protected:
+
+ /// Tile size
+ r_Bytes tile_size;
+ };
+
+
+class r_Dimension_Tiling : public r_Size_Tiling
+ {
+ public:
+ /// Constructor for this object (Takes dim (no of dimension) and tile size as parameter)
+ r_Dimension_Tiling(r_Dimension dim, r_Bytes ts = RMInit::clientTileSize);
+
+ /// does not do anything
+ virtual ~r_Dimension_Tiling();
+
+ /// Gets the current dimension
+ r_Dimension get_dimension() const;
+
+ virtual void print_status(std::ostream& os) const;
+
+ virtual bool is_compatible(const r_Minterval& obj_domain, r_Bytes cellTypeSize) const;
+ /// returns true if the cellTypeSize is smaller or equal to the tile size and the dimension fits the obj_domain
+
+ virtual std::vector<r_Minterval>* compute_tiles(const r_Minterval& obj_domain, r_Bytes cellTypeSize) const throw (r_Error) = 0;
+
+ virtual r_Tiling* clone() const = 0;
+
+ protected:
+
+ /// dimension the mdd must have
+ r_Dimension dimension;
+ };
+
+
+class r_No_Tiling : public r_Tiling
+ {
+ public:
+ /// Constructor that reads everything from a string e.g."100"
+ /// This string is ignored in the constructor, it is present
+ /// in order to have an uniform interface
+ r_No_Tiling(const char* encoded) throw (r_Error);
+ /// Constructor for this object
+ r_No_Tiling();
+
+ /// does not do anything
+ virtual ~r_No_Tiling();
+
+ /// Prints the current status of the object
+ virtual void print_status(std::ostream& os) const;
+
+ /// Check compatibility of object domain with this tiling
+ virtual bool is_compatible(const r_Minterval& obj_domain, r_Bytes cellTypeSize) const;
+ /// returns true
+
+ /// Decompose an object in tiles
+ virtual std::vector<r_Minterval>* compute_tiles(const r_Minterval& obj_domain, r_Bytes cellTypeSize) const throw (r_Error);
+ /// returns obj_domain
+
+ virtual r_Tiling* clone() const;
+
+ virtual r_Tiling_Scheme get_tiling_scheme() const;
+
+ static const char* description;
+ };
+
+
+/*@Doc:
+ Prints the status of a Tiling object to a stream
+*/
+//extern std::ostream& operator<<(std::ostream& os, const r_Size_Tiling& t);
+
+/*@Doc:
+ Prints the status of a Tiling object to a stream
+*/
+//extern std::ostream& operator<<(std::ostream& os, const r_No_Tiling& t);
+
+/*@Doc:
+ Prints the status of a Tiling object to a stream
+*/
+extern std::ostream& operator<<(std::ostream& os, const r_Tiling& t);
+
+#include "rasodmg/tiling.hh"
+#if (defined(__VISUALC__) && !defined(__EXECUTABLE__))
+ #define __EXECUTABLE__
+ #include "raslib/dlist.hh"
+ #undef __EXECUTABLE__
+#else
+ #include "raslib/dlist.hh"
+#endif
+
+#endif
diff --git a/rasodmg/transaction.cc b/rasodmg/transaction.cc
new file mode 100644
index 0000000..792b8d9
--- /dev/null
+++ b/rasodmg/transaction.cc
@@ -0,0 +1,377 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: transaction.cc
+ *
+ * MODULE: rasodmg
+ * CLASS: r_Transaction
+ *
+ * COMMENTS:
+ * None
+*/
+
+static const char rcsid[] = "@(#)rasodmg, r_Transaction: $Id: transaction.cc,v 1.38 2005/09/03 20:39:35 rasdev Exp $";
+
+
+#ifdef __VISUALC__
+ #ifndef __EXECUTABLE__
+ #define __EXECUTABLE__
+ #define TRANSACTION_NOT_SET
+ #endif
+#endif
+
+#include "rasodmg/transaction.hh"
+#include "rasodmg/database.hh"
+
+#include "raslib/rmdebug.hh"
+#include "raslib/scalar.hh"
+#include "clientcomm/clientcomm.hh"
+
+#ifdef __VISUALC__
+ #ifdef TRANSACTION_NOT_SET
+ #undef __EXECUTABLE__
+ #endif
+
+ template class r_Set< r_Ref<r_Object> >;
+#endif
+
+#include <iostream>
+
+// Initially there is no transaction active.
+r_Transaction* r_Transaction::actual_transaction = 0;
+
+
+
+r_Transaction::r_Transaction()
+ : ta_state( inactive ), ta_mode( read_write )
+{
+}
+
+
+
+r_Transaction::~r_Transaction()
+{
+ if( ta_state == active )
+ abort();
+}
+
+
+
+void
+r_Transaction::begin( r_Transaction::r_TAMode mode ) throw( r_Error )
+{
+ // check if no other transaction is running
+ if( ta_state != inactive || actual_transaction )
+ {
+ r_Error err = r_Error( r_Error::r_Error_TransactionOpen );
+ throw err;
+ }
+
+ // check if a database is opened
+ if( r_Database::actual_database == 0 )
+ {
+ r_Error err = r_Error( r_Error::r_Error_DatabaseClosed );
+ throw err;
+ }
+
+ ta_state = active;
+
+ // if a database is opened, a communication object is existing
+ //r_Database::actual_database->communication->openTA( mode == read_only ? 1 : 0 );
+ r_Database::actual_database->getComm()->openTA( mode == read_only ? 1 : 0 );
+
+ actual_transaction = this;
+ ta_mode = mode;
+}
+
+
+
+void
+r_Transaction::commit() throw( r_Error )
+{
+ if( ta_state != active )
+ {
+ throw( new r_Error( r_Error::r_Error_TransactionNotOpen ) );
+ }
+ else
+ {
+ RMInit::logOut << std::endl << "Commit Log:" << std::endl;
+
+ //
+ // Commit list of r_Object references.
+ //
+
+ r_Iterator< r_Ref<r_Object> > iter = object_list.create_iterator();
+
+ for( iter.reset(); iter.not_done(); iter++ )
+ {
+ if( (*iter)->get_oid().is_valid() )
+ {
+ RMInit::logOut << " Object " << (*iter)->get_oid() << " " << std::flush;
+
+ switch( (*iter)->get_status() )
+ {
+ case r_Object::deleted:
+ RMInit::logOut << "state DELETED, deleting ... " << std::flush;
+ (*iter)->r_Object::delete_obj_from_db();
+ RMInit::logOut << "OK" << std::endl;
+ break;
+
+ case r_Object::created:
+ RMInit::logOut << "state CREATED, writing ... " << std::flush;
+ (*iter)->insert_obj_into_db();
+ RMInit::logOut << "OK" << std::endl;
+ break;
+
+ case r_Object::modified:
+ RMInit::logOut << "state MODIFIED, modifying ... " << std::endl;
+ (*iter)->update_obj_in_db();
+ break;
+
+ case r_Object::read:
+ RMInit::logOut << "state READ, OK" << std::endl;
+ break;
+
+ case r_Object::transient:
+ RMInit::logOut << "state TRANSIENT, OK" << std::endl;
+ break;
+
+ default:
+ RMInit::logOut << "state UNKNOWN" << std::endl;
+ break;
+ }
+ }
+ else
+ RMInit::logOut << " Object with no oid, state TRANSIENT query result" << std::endl;
+ }
+
+ // Don't do the r_deactivate() in the first loop because if a collection is not
+ // before its elements in the list, it tries to save non existing objects.
+
+ for( iter.reset(); iter.not_done(); iter++ )
+ {
+ if( !(*iter)->test_status( r_Object::deleted ) )
+ (*iter)->r_deactivate();
+
+ (*iter)->r_Object::r_deactivate();
+
+ free( (*iter).get_memory_ptr() );
+ }
+
+ object_list.remove_all();
+
+ //
+ // Commit list of non-r_Object references.
+ //
+
+ r_Iterator< GenRefElement* > iter2 = non_object_list.create_iterator();
+
+ for( iter2.reset(); iter2.not_done(); iter2++ )
+ {
+ RMInit::logOut << " Value " << std::flush;
+
+ switch( (*iter2)->type )
+ {
+ case POINT:
+ RMInit::logOut << "transient Point DELETED" << std::endl;
+ delete ((r_Point*)(*iter2)->ref);
+ break;
+
+ case SINTERVAL:
+ RMInit::logOut << "transient Sinterval DELETED" << std::endl;
+ delete ((r_Sinterval*)(*iter2)->ref);
+ break;
+
+ case MINTERVAL:
+ RMInit::logOut << "transient Minterval DELETED" << std::endl;
+ delete ((r_Minterval*)(*iter2)->ref);
+ break;
+
+ case OID:
+ RMInit::logOut << "transient OId DELETED" << std::endl;
+ delete ((r_OId*)(*iter2)->ref);
+ break;
+
+ default:
+ RMInit::logOut << "transient Scalar DELETED" << std::endl;
+ delete ((r_Scalar*)(*iter2)->ref);
+ break;
+ }
+
+ delete *iter2;
+ }
+
+ non_object_list.remove_all();
+
+
+ //
+ // commit transaction on the server
+ //
+
+// r_Database::actual_database->communication->commitTA();
+ r_Database::actual_database->getComm()->commitTA();
+
+ ta_state = inactive;
+ actual_transaction = 0;
+ }
+}
+
+
+
+void
+r_Transaction::abort()
+{
+ if( ta_state != active )
+ {
+ throw( r_Error( r_Error::r_Error_TransactionNotOpen ) );
+ }
+ else
+ {
+ RMInit::logOut << std::endl << "Abort Log:" << std::endl;
+
+ //
+ // Abort list of r_Object references.
+ //
+
+ r_Iterator< r_Ref<r_Object> > iter = object_list.create_iterator();
+
+ for( iter.reset(); iter.not_done(); iter++ )
+ {
+ RMInit::logOut << " Object DELETED" << std::endl;
+
+ if( !(*iter)->test_status( r_Object::deleted ) )
+ (*iter)->r_deactivate();
+
+ (*iter)->r_Object::r_deactivate();
+
+ free( (*iter).get_memory_ptr() );
+ }
+
+ object_list.remove_all();
+
+ //
+ // Abort list of non-r_Object references.
+ //
+
+ r_Iterator< GenRefElement* > iter2 = non_object_list.create_iterator();
+
+ for( iter2.reset(); iter2.not_done(); iter2++ )
+ {
+ switch( (*iter2)->type )
+ {
+ case POINT:
+ RMInit::logOut << " Transient Point DELETED" << std::endl;
+ delete ((r_Point*)(*iter2)->ref);
+ break;
+
+ case SINTERVAL:
+ RMInit::logOut << " Transient Sinterval DELETED" << std::endl;
+ delete ((r_Sinterval*)(*iter2)->ref);
+ break;
+
+ case MINTERVAL:
+ RMInit::logOut << " Transient Minterval DELETED" << std::endl;
+ delete ((r_Minterval*)(*iter2)->ref);
+ break;
+
+ case OID:
+ RMInit::logOut << " Transient OId DELETED" << std::endl;
+ delete ((r_OId*)(*iter2)->ref);
+ break;
+
+ default:
+ RMInit::logOut << " Transient Scalar DELETED" << std::endl;
+ delete ((r_Scalar*)(*iter2)->ref);
+ break;
+ }
+
+ delete *iter2;
+ }
+
+ non_object_list.remove_all();
+
+ //
+ // Abort transaction on the server.
+ //
+ if (r_Database::actual_database)
+// r_Database::actual_database->communication->abortTA();
+ r_Database::actual_database->getComm()->abortTA();
+ else
+ RMInit::logOut << " Database was already closed. Please abort every transaction before closing the database. Please also check for any try/catches with a close database but without transaction abort." << std::endl;
+
+ ta_state = inactive;
+ actual_transaction = 0;
+ }
+}
+
+
+
+r_Ref_Any
+r_Transaction::load_object( const r_OId& oid )
+{
+ // check, if object is already loaded
+ unsigned int found = 0;
+ r_Iterator< r_Ref<r_Object> > iter = object_list.create_iterator();
+
+ iter.reset();
+ while( iter.not_done() && !found )
+ {
+ found = ( (*iter)->get_oid() == oid );
+ if( !found ) iter++;
+ }
+
+ if( found )
+ {
+ // return reference of loaded object
+ RMDBGONCE(4, RMDebug::module_rasodmg, "r_Transaction", "load_object( oid ) - object already loaded")
+ return *iter;
+ }
+ else
+ {
+ // load object and return reference
+ RMDBGONCE(4, RMDebug::module_rasodmg, "r_Transaction", "load_object( oid ) - load object")
+ return r_Database::actual_database->lookup_object( oid );
+ }
+}
+
+
+
+void
+r_Transaction::add_object_list( const r_Ref<r_Object> &obj )
+{
+ object_list.insert_element( obj );
+}
+
+
+
+void
+r_Transaction::add_object_list( GenRefType type, void* ref )
+{
+ GenRefElement* element = new GenRefElement;
+
+ element->type = type;
+ element->ref = ref;
+
+ non_object_list.insert_element( element );
+}
+
diff --git a/rasodmg/transaction.hh b/rasodmg/transaction.hh
new file mode 100644
index 0000000..443855a
--- /dev/null
+++ b/rasodmg/transaction.hh
@@ -0,0 +1,167 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: transaction.hh
+ *
+ * MODULE: rasodmg
+ * CLASS: r_Transaction
+ *
+ * COMMENTS:
+ * None
+*/
+
+//@ManMemo: Module: {\bf rasodmg}
+
+#ifndef _D_TRANSACTION_
+#define _D_TRANSACTION_
+
+#include "raslib/error.hh"
+#include "raslib/oid.hh"
+
+class r_Object;
+
+#include "rasodmg/set.hh"
+#include "rasodmg/ref.hh"
+
+/*@Doc:
+
+ Transactions can be started, committed, aborted, and checkpointed.
+ It is important to note that all access, creation, modification,
+ and deletion of persistent objects must be done within a transaction.
+ Right now, only one transaction can be active at a time.
+
+*/
+
+class r_Transaction
+{
+ public:
+ /// possible states of the transaction
+ enum r_TAStatus { active, inactive, comiting, aborting };
+
+ /// possible transaction modes
+ enum r_TAMode { read_write, read_only };
+
+ /// default constructor
+ r_Transaction();
+
+ /// destructor, an active transaction is aborted
+ ~r_Transaction();
+
+ /// start the transaction
+ void begin( r_TAMode mode = read_write ) throw( r_Error );
+ /**
+ By default, a transaction is started in write mode. If the read_only
+ mode is specified, no write operations are allowed within the transaction
+ anymore.
+ If any write operation occurs in read_only mode, the exception r_Error with
+ kind {\tt r_Error_TransactionReadOnly} will be raised and the transaction will
+ be aborted.
+ In order to achieve maximal performance, read-only transactions should be used
+ whenever posssible, i.e., when no update operations occur within this transaction.
+ */
+
+ /// commit transaction and make changes persistent
+ void commit() throw( r_Error );
+ /**
+ The transaction is committed and changes are made persistent
+ in the database.
+ While committing, the following errors can occur:
+
+ \begin{tabular}{lll}
+ r_Error_TransferFailed && Server communication problem.\\
+ r_Error_ObjectUnknown && Name of object is unknown.\\
+ r_Error_DatabaseClassUndefined && Type name of object not known by the database.\\
+ r_Error_CollectionElementTypeMismatch && Collection and MDD type mismatch.\\
+ \end{tabular}
+ */
+
+ /// abort transaction and forget changes within transaction
+ void abort();
+
+ /// returns the current state
+ inline r_TAStatus get_status() const;
+
+ /// returns current mode
+ inline r_TAMode get_mode() const;
+
+ //@Man: Methods and types for internal use only:
+ //@{
+ ///
+
+ /// store a pointer to the actual transaction
+ static r_Transaction* actual_transaction;
+
+ /// load an object (internal use only)
+ r_Ref_Any load_object( const r_OId& oid );
+
+ /// possible non-r_Object values maintained by the transaction
+ enum GenRefType { MINTERVAL, SINTERVAL, POINT, OID, SCALAR };
+
+ /// adds a non-r_Object to the list of persistent objects
+ void add_object_list( GenRefType type, void* ref );
+
+ ///
+ //@}
+
+ private:
+ /// adds an object of type \Ref{r_Object} to the list of persistent objects
+ void add_object_list( const r_Ref<r_Object>& );
+
+ /// current transaction state
+ r_TAStatus ta_state;
+
+ /// current transaction mode (just valid if transaction is active)
+ r_TAMode ta_mode;
+
+ /// list of \Ref{r_Object} references which have been created within the transaction
+ r_Set< r_Ref<r_Object> > object_list;
+
+ // element type of non \Ref{r_Object} list maintained by the transaction
+ typedef struct{ GenRefType type; void* ref; } GenRefElement;
+
+ /// list of non \Ref{r_Object} references which have been created within the transaction
+ r_Set< GenRefElement* > non_object_list;
+
+ friend class r_Object;
+};
+
+#define DEF_TRANSACTION
+
+#include "rasodmg/iterator.hh"
+// For HP cfront compiler each template instantiation used in a library
+// must be defined in an included header.
+typedef r_Iterator<r_Object*> r_Iterator_r_Object_dummy;
+#include "rasodmg/transaction.icc"
+
+#ifdef EARLY_TEMPLATE
+#ifdef __EXECUTABLE__
+#ifdef __VISUALC__
+#include "rasodmg/ref.cpp"
+#else
+#include "rasodmg/ref.cc"
+#endif
+#endif
+#endif
+
+
+#endif
diff --git a/rasodmg/transaction.icc b/rasodmg/transaction.icc
new file mode 100644
index 0000000..58e662f
--- /dev/null
+++ b/rasodmg/transaction.icc
@@ -0,0 +1,46 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INLINE SOURCE: transaction.icc
+ *
+ * MODULE: rasodmg
+ * CLASS: r_Transaction
+ *
+ * COMMENTS:
+ * None
+*/
+
+inline
+r_Transaction::r_TAStatus
+r_Transaction::get_status() const
+{
+ return ta_state;
+}
+
+
+inline
+r_Transaction::r_TAMode
+r_Transaction::get_mode() const
+{
+ return ta_mode;
+}
diff --git a/reladminif/Makefile.am b/reladminif/Makefile.am
new file mode 100644
index 0000000..07a6e99
--- /dev/null
+++ b/reladminif/Makefile.am
@@ -0,0 +1,68 @@
+# -*-Makefile-*- (for Emacs)
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+#
+# MAKEFILE FOR:
+# reladminif
+#
+#
+# COMMENTS:
+# - stagerif not used
+#
+##################################################################
+
+AM_CXXFLAGS=@BASEDBCXXFLAGS@
+AM_LDFLAGS=@BASEDBLDFLAGS@
+
+.SUFFIXES= .@EMBEDDEDSQLEXT@ .@EMBEDDEDSQLOUT@
+.@EMBEDDEDSQLEXT@.@EMBEDDEDSQLOUT@:
+ $(EMBEDDEDSQLPRECOMPILER) $@ $<
+
+
+noinst_LIBRARIES=libreladminif.a
+libreladminif_a_SOURCES=adminifcommon.cc adminif.hh databaseifcommon.cc databaseif.hh \
+ transactionifcommon.cc transactionif.hh sqlerror.hh \
+ oidifcommon.cc oidif.hh dbobject.cc dbobject.hh \
+ dbnamedobject.cc dbnamedobject.hh eoid.cc eoid.hh \
+ dbref.cc dbref.hh objectbrokercommon.cc objectbroker.hh \
+ dbobjectiterator.cc dbobjectiterator.hh \
+ externs.h lists.h binaryrepresentation.hh destroyable.hh \
+ sqlglobals.h dbobjectiditerator.hh
+EXTRA_libreladminif_a_SOURCES=adminif.pgc databaseif.pgc transactionif.pgc \
+ sqlerror.pgc oidif.pgc objectbroker.pgc \
+ dbobjectiditerator.cc
+
+libreladminif_a_LIBADD= adminif.$(OBJEXT) databaseif.$(OBJEXT) transactionif.$(OBJEXT) \
+ sqlerror.$(OBJEXT) oidif.$(OBJEXT) objectbroker.$(OBJEXT)
+libreladminif_a_DEPENDENCIES= adminif.$(OBJEXT) databaseif.$(OBJEXT) transactionif.$(OBJEXT) \
+ sqlerror.$(OBJEXT) oidif.$(OBJEXT) objectbroker.$(OBJEXT)
+
+
+BUILT_SOURCES= adminif.@EMBEDDEDSQLOUT@ databaseif.@EMBEDDEDSQLOUT@ transactionif.@EMBEDDEDSQLOUT@ \
+ sqlerror.@EMBEDDEDSQLOUT@ oidif.@EMBEDDEDSQLOUT@ objectbroker.@EMBEDDEDSQLOUT@
+
+
+CLEANFILES= adminif.@EMBEDDEDSQLOUT@ databaseif.@EMBEDDEDSQLOUT@ transactionif.@EMBEDDEDSQLOUT@ \
+ sqlerror.@EMBEDDEDSQLOUT@ oidif.@EMBEDDEDSQLOUT@ objectbroker.@EMBEDDEDSQLOUT@ \
+ client.bm client.dbg client.log ir.out
+
+
diff --git a/reladminif/adminif.hh b/reladminif/adminif.hh
new file mode 100644
index 0000000..6d4024b
--- /dev/null
+++ b/reladminif/adminif.hh
@@ -0,0 +1,174 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#ifndef _ADMINIF_HH_
+#define _ADMINIF_HH_
+
+/************************************************************************
+ *
+= *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ***********************************************************************/
+
+class AdminIf;
+class DatabaseIf;
+
+class r_Error;
+
+#include <iostream>
+#include "lists.h"
+
+class AdminIf;
+
+//@ManMemo: Module: {\bf reladminif}.
+
+/*@Doc:
+An AdminIf instance has to be obtained, before any work with the base
+DBMS can be done. Only one instance can exist at any time. The class
+follows the singleton design pattern (Gamma et. al. p. 127ff.).
+
+{\bf Functionality}
+
+At the moment, AdminIf is responsible for the state of a transaction.
+persistent objects rely on this class to decide if they should write
+changes back into the db. It also carries a list of compressed tiles.
+Before a session is opened, no persistence capable classes can be used (e.g.
+\Ref{BLOBTile})! Remember to also create a \Ref{DatabaseIf} instance
+before using a persistence capable class.
+
+{\bf Example}
+
+{\tt AdminIf* myAdmin = AdminIf::instance();}
+
+...
+
+{\tt delete myAdmin;}
+
+*/
+
+const int SYSTEMNAME_MAXLEN=256;
+
+class AdminIf
+ {
+ public:
+ static AdminIf* instance();
+ /*@Doc:
+ satic function used to access instance of AdminIf and start session.
+ */
+
+ static DatabaseIf* getCurrentDatabaseIf();
+ /*@Doc:
+ static function used to access the current databaseif object
+ */
+
+ static void setCurrentDatabaseIf(DatabaseIf* db);
+ /*@Doc:
+ static function used to store the current databaseif object in AdminIf
+ this function should only be called by DatabaseIf, DatabasIf
+ is responsible for setting the databaseif object to
+ NULL at destruction time.
+ */
+
+ ~AdminIf();
+ /*@Doc:
+ issues a ROLLBACK WORK RELEASE
+ deinitializes the ObjectBroker
+ deinitializes benchmark timers
+ */
+
+ static char* getSystemName();
+ /*@Doc:
+ returns Oracle on oracle
+ */
+
+ static void setReadOnlyTA(bool newReadOnlyTA);
+ /*@Doc:
+ sets readOnlyTA, should only be used by \Ref{TransactionIf}
+ */
+
+ static bool isReadOnlyTA();
+ /*@Doc:
+ checks for read only TA.
+ */
+
+ static bool isAborted();
+ /*@Doc:
+ used by DBObject::validate() to determine if it should execute the persistency functions
+ */
+
+ static void setAborted(bool newAborted);
+ /*@Doc:
+ used by transactionif to set the aborted status of the transaction
+ */
+
+ protected:
+ AdminIf() throw (r_Error);
+ /*@Doc:
+ constructor, can not be used from outside.
+ initializes the objectbroker
+ does a CONNECT, when successful sets validConnection to true else false,
+ then a ROLLBACK WORK RELEASE
+ throws exception if connection fails
+ */
+
+ private:
+ static AdminIf* myInstance;
+ /*@Doc:
+ pointer to instance (just needed for Singleton pattern).
+ */
+
+ static DatabaseIf* myDatabaseIf;
+ /*@Doc:
+ pointer to the current DatabaseIf object
+ */
+
+ static bool validConnection;
+ /*@Doc:
+ flag for error when opening session: false if error.
+ */
+
+ static bool readOnlyTA;
+ /*@Doc:
+ flag for read only transactions
+ */
+
+ static const char dbmsName[SYSTEMNAME_MAXLEN];
+ /*@Doc:
+ holds the specific name of dbms
+ */
+
+ static char systemName[SYSTEMNAME_MAXLEN];
+ /*@Doc:
+ Store the dbms name using dbmsName
+ */
+
+ static bool _isAborted;
+ /*@Doc:
+ flag for aborted transactions
+ */
+ };
+
+#endif
diff --git a/reladminif/adminif.pgc b/reladminif/adminif.pgc
new file mode 100644
index 0000000..5e1a03d
--- /dev/null
+++ b/reladminif/adminif.pgc
@@ -0,0 +1,90 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************************
+ *
+ *
+ * PURPOSE:
+ * implements adminif interface using the PostgreSQL DBMS.
+ *
+ *
+ * COMMENTS:
+ * none
+ *
+ ***********************************************************************/
+
+static const char rcsid[] = "@(#)reladminif,AdminIf: $Id: adminif.ec,v 1.6 2003/12/27 23:11:43 rasdev Exp $";
+
+#include "debug-srv.hh"
+#include "sqlerror.hh"
+
+// general embedded SQL related definitions
+EXEC SQL include sqlglobals.h;
+
+#include "adminif.hh"
+#include "raslib/rmdebug.hh"
+#include "objectbroker.hh"
+
+extern char globalConnectId[256];
+const char AdminIf::dbmsName[SYSTEMNAME_MAXLEN]="PostgreSQL";
+
+AdminIf::AdminIf() throw (r_Error)
+{
+ RMDBGENTER(4, RMDebug::module_adminif, "Adminif", "AdminIf()");
+ ENTER( "AdminIf::AdminIf" );
+
+ EXEC SQL BEGIN DECLARE SECTION;
+ char id[STRING_MAXLEN];
+ EXEC SQL END DECLARE SECTION;
+
+ strncpy((char *)&id, globalConnectId, sizeof(id)-1);
+
+ TALK( "EXEC SQL CONNECT TO " << id );
+ EXEC SQL CONNECT TO :id;
+
+ if (check("AdminIf Connect\0"))
+ {
+ validConnection = false;
+ TALK( "connect unsuccessful; wrong connect string?" );
+ cout << "Error: connect unsuccessful; wrong connect string '" << globalConnectId << "' ?" << endl;
+ throw r_Error( 830 );
+ }
+ else
+ {
+ validConnection = true;
+ TALK( "connect ok" );
+ }
+
+ TALK( "EXEC SQL ROLLBACK WORK" );
+ EXEC SQL ROLLBACK WORK;
+
+#ifndef FASTCONNECT
+ TALK( "EXEC SQL DISCONNECT CURRENT" );
+ EXEC SQL DISCONNECT CURRENT;
+#endif
+
+ ObjectBroker::init();
+
+ LEAVE( "AdminIf::AdminIf, SQLCODE=" << SQLCODE );
+ RMDBGEXIT(4, RMDebug::module_adminif, "Adminif", "AdminIf() " << validConnection);
+}
+
diff --git a/reladminif/adminifcommon.cc b/reladminif/adminifcommon.cc
new file mode 100644
index 0000000..f4409e3
--- /dev/null
+++ b/reladminif/adminifcommon.cc
@@ -0,0 +1,163 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************************
+ *
+ *
+ * PURPOSE:
+ * Code with embedded SQL for relational DBMS
+ *
+ *
+ * COMMENTS:
+ * none
+ *
+ ***********************************************************************/
+
+#include <string.h>
+#if defined(DECALPHA) || defined(LINUX) || defined(AIX) || defined(SOLARIS)
+//#include <algorith.h>
+//#elif defined(LINUX) || defined(AIX) || defined(SOLARIS)
+#include <algorithm>
+#endif
+
+#include "raslib/error.hh"
+#include "adminif.hh"
+
+#include "raslib/rmdebug.hh"
+#include "sqlerror.hh"
+#include "objectbroker.hh"
+
+#include "externs.h"
+
+// defined in rasserver.cc
+extern char globalConnectId[256];
+
+AdminIf* AdminIf::myInstance = NULL;
+
+bool AdminIf::validConnection = false;
+
+bool AdminIf::readOnlyTA = false;
+
+DatabaseIf* AdminIf::myDatabaseIf = NULL;
+
+char AdminIf::systemName[SYSTEMNAME_MAXLEN];
+
+bool AdminIf::_isAborted = false;
+
+bool
+AdminIf::isAborted()
+ {
+ RMDBGENTER(4, RMDebug::module_adminif, "Adminif", "isAborted()");
+ bool retval=false;
+
+#ifdef READ_ONLY_RMAN
+ retval=true;
+#else
+ retval=_isAborted;
+#endif
+ RMDBGEXIT(4, RMDebug::module_adminif, "AdminIf", "isAborted() " << retval);
+ return retval;
+ }
+
+void
+AdminIf::setAborted(bool newAborted)
+ {
+ RMDBGONCE(4, RMDebug::module_adminif, "AdminIf", "setAborted(" << newAborted << ") " << _isAborted);
+ _isAborted = newAborted;
+ }
+
+DatabaseIf*
+AdminIf::getCurrentDatabaseIf()
+ {
+ RMDBGONCE(4, RMDebug::module_adminif, "Adminif", "getCurrentDatabaseIf() " << myDatabaseIf);
+ return myDatabaseIf;
+ }
+
+void
+AdminIf::setCurrentDatabaseIf(DatabaseIf* db)
+ {
+ RMDBGONCE(4, RMDebug::module_adminif, "Adminif", "setCurrentDatabaseIf(" << db << ") " << myDatabaseIf);
+ myDatabaseIf = db;
+ }
+
+AdminIf*
+AdminIf::instance()
+ {
+ RMDBGENTER(4, RMDebug::module_adminif, "Adminif", "instance() " << myInstance);
+ AdminIf* retval=NULL;
+
+ strcpy((char*)&systemName, dbmsName);
+ if(!myInstance)
+ {
+ myInstance = new AdminIf();
+ }
+ if(validConnection)
+ retval=myInstance;
+
+ RMDBGEXIT(4, RMDebug::module_adminif, "Adminif", "instance() " << retval);
+ return retval;
+ }
+
+AdminIf::~AdminIf()
+ {
+ RMDBGENTER(4, RMDebug::module_adminif, "Adminif", "~AdminIf()");
+
+ myInstance = NULL;
+ ObjectBroker::deinit();
+
+#ifdef RMANBENCHMARK
+ DBObject::readTimer.setOutput(0);
+
+ DBObject::updateTimer.setOutput(0);
+
+ DBObject::deleteTimer.setOutput(0);
+
+ DBObject::insertTimer.setOutput(0);
+
+ OId::oidAlloc.setOutput(0);
+
+ OId::oidResolve.setOutput(0);
+#endif
+ RMDBGEXIT(4, RMDebug::module_adminif, "Adminif", "~AdminIf()");
+ }
+
+void
+AdminIf::setReadOnlyTA(bool newReadOnlyTA)
+ {
+ RMDBGONCE(4, RMDebug::module_adminif, "Adminif", "setReadOnlyTA(" << newReadOnlyTA << ")" << readOnlyTA);
+ readOnlyTA = newReadOnlyTA;
+ }
+
+bool
+AdminIf::isReadOnlyTA()
+ {
+ RMDBGONCE(4, RMDebug::module_adminif, "Adminif", "isReadOnlyTA()" << readOnlyTA);
+ return readOnlyTA;
+ }
+
+char*
+AdminIf::getSystemName()
+ {
+ RMDBGONCE(4, RMDebug::module_adminif, "Adminif", "getSystemName()" <<systemName);
+ return systemName;
+ }
+
diff --git a/reladminif/binaryrepresentation.hh b/reladminif/binaryrepresentation.hh
new file mode 100644
index 0000000..d2e3f0f
--- /dev/null
+++ b/reladminif/binaryrepresentation.hh
@@ -0,0 +1,31 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+class BinaryRepresentation
+ {
+ public:
+ char* binaryName;
+ char* binaryData;
+ size_t binaryLength;
+ static const char* fileTag;
+ };
+
diff --git a/reladminif/databaseif.hh b/reladminif/databaseif.hh
new file mode 100644
index 0000000..f8b8954
--- /dev/null
+++ b/reladminif/databaseif.hh
@@ -0,0 +1,222 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#ifndef _DATABASEIF_HH_
+#define _DATABASEIF_HH_
+
+/************************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ***********************************************************************/
+
+//@ManMemo: Module: {\bf reladminif}.
+/*@Doc:
+With a DatabaseIf instance a database can be opened or closed. There
+is also functionality for creating and deleting DBs. A
+database has to be open, before persistence capable classes can be
+used (see also \Ref{AdminIf}).
+
+{\bf Example}
+
+{\tt DatabaseIf database;}
+
+{\tt database.open( "myDatabase" )}
+
+...
+
+{\tt database.close();}
+*/
+
+class DatabaseIf;
+class TransactionIf;
+
+#include <iostream>
+using std::cout;
+using std::endl;
+using std::ostream;
+
+#include "raslib/error.hh"
+
+class DatabaseIf
+ {
+ public:
+ friend std::ostream& operator<< (std::ostream& stream, DatabaseIf& db);
+ /*@Doc:
+ prints the status of the database (connected, online, offline, name)
+ */
+
+ /// opens database with name {\tt dbName}.
+ void open( const char* dbName ) throw(r_Error);
+ /*@Doc:
+ Precondition: not opened, not connected, db exists
+ Postcondition: open, not connected, db exists
+ If last opened database was not closed (throw r_Error::r_Error_DatabaseOpen)),
+ If database does not exist (throw r_Error::r_Error_DatabaseUnknown).
+ In the current implementation this value is returned, when dbName is not RASBASE,
+ regardles if the db exists or not.
+ */
+
+ void close();
+ /*@Doc:
+ Precondition: open, not connected, db exists
+ Postcondition: not open, not connected, db exists
+ closes currently opened database. only frees name and sets connected/opened to false.
+ */
+
+ static void createDB( const char* dbName, const char* schemaName, const char* volumeName=0 ) throw(r_Error);
+ /*@Doc:
+ Precondition: not open, not connected, db does not exist
+ Postcondition: not open, not connected, db exists
+ creates a new database. schemaName and volumeName are ignored.
+ only successful if dbName is RASBASE
+ */
+
+ static void destroyDB(const char* dbName) throw(r_Error);
+ /*@Doc:
+ Precondition: not open, not connected, db exists
+ Postcondition: not open, not connected, db does not exist
+ destroys an existing database with name {\tt dbName}.
+ Database must not be open in order to be destroyed.
+ A transaction must not be opened.
+ Returns -1 if database does not exist.
+ */
+
+
+ void garbage();
+ /*@Doc:
+ this method does not do anything
+ */
+
+ const char* getName() const;
+ /*@Doc:
+ returns a pointer to the name of the db.
+ */
+
+ DatabaseIf();
+ /*@Doc:
+ constructor. Initializes opened, myName and connected to 0
+ */
+
+ bool isConnected() const;
+ /*@Doc:
+ true when there has been an EXEC SQL CONNECT
+ */
+
+ bool isOpen() const;
+ /*@Doc:
+ true when it was opened by a transaction
+ */
+
+ ~DatabaseIf();
+ /*@Doc:
+ executes a baseDBMSClose() if it is still connected.
+ */
+
+ static bool databaseExists(const char* dbname) throw (r_Error);
+ /*@Doc:
+ Precondition: none checked. db must be open and connected.
+ Postcondition: none
+ basedbms error thrown.
+ checks if a database has been created.
+ */
+
+ static bool isConsistent() throw (r_Error);
+ /*@Doc:
+ Precondition: none checked. db must be open and connected.
+ Postcondition: none
+ basedbms error thrown if something really bad happens.
+ checks if counters are ok.
+ */
+
+ protected:
+ friend class TransactionIf;
+
+ void baseDBMSOpen() throw (r_Error);
+ /*@Doc:
+ Precondition: current database = 0
+ Postcondition: current database = this
+ issues a CONNECT.
+ sets the DatabaseIf object in AdminIf to this.
+ */
+
+ void baseDBMSClose();
+ /*@Doc:
+ Precondition: current database = this
+ Postcondition: current database = 0
+ issues a ROLLBACK WORK RELEASE in oracle.
+ issues a DISCONNECT in db2.
+ sets the DatabaseIf object in AdminIf to 0, if it was the same.
+ */
+
+ static void connect() throw (r_Error);
+ /*@Doc:
+ Precondition: none checked.
+ Postcondition: none.
+ issues a CONNECT.
+ throws r_Error if there is a problem during connection.
+ */
+
+ static void disconnect() throw (r_Error);
+ /*@Doc:
+ Precondition: none checked.
+ Postcondition: none.
+ issues a CONNECT.
+ throws r_Error if there is a problem during disconnection.
+ */
+
+ void checkCompatibility() throw (r_Error);
+ /*@Doc:
+ Precondition: none checked.
+ Postcondition: none.
+ throws r_Error if the current rasdaman system does not match the database.
+ */
+
+ private:
+ bool opened;
+ /*@Doc:
+ TRUE only if database is open.
+ */
+
+ char* myName;
+ /*@Doc:
+ Valid only if opened.
+ */
+
+ bool connected;
+ /*@Doc:
+ TRUE only if database connection exists ; )
+ */
+
+ static const char* DefaultDatabaseName;
+ /*@Doc:
+ only one database is supported. any database name given is compared to this string.
+ access to the db is only granted if the name of the database is the same as this string.
+ */
+
+ };
+
+#endif
diff --git a/reladminif/databaseif.pgc b/reladminif/databaseif.pgc
new file mode 100644
index 0000000..cec18c5
--- /dev/null
+++ b/reladminif/databaseif.pgc
@@ -0,0 +1,1382 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+// This is -*- C++ -*-
+/*************************************************************************
+ *
+ *
+ * PURPOSE:
+ * Code with embedded SQL for PostgreSQL DBMS
+ *
+ *
+ * COMMENTS:
+ * - need connection via ECPG and libqg, use non-public interface to
+ * obtain libpq style connection ptr from ECPG structure
+ * - global variable globalConnectId used for DB server identification, maybe better as constructor parameter
+ * - dbName parameter not evaluated
+ * - PG: no CLUSTER index available
+ * - PG: index always in same schema as table
+ * - replaced "if ((SQLCODE != SQLOK) && (SQLCODE != SQLNULLFETCHED))"
+ * by "if (SQLCODE < 0 || SQLCODE == SQLNODATAFOUND)"
+ * - databaseExists() not used
+ * - attribute name 'OId' -> 'UOId' (for UDFs), 'OId' -> 'Id' (for IXs)
+ * to avoid PG name clash with attr type
+ * - except for RAS_COUNTERS, "no data" means no error, but that we need to initialize the empty table
+ *
+ ***********************************************************************/
+
+static const char rcsid[] = "@(#)reladminif,DatabaseIf: $Id: databaseif.ec,v 1.9 2003/12/27 23:11:43 rasdev Exp $";
+
+#include "debug/debug.hh"
+
+// general embedded SQL related definitions
+EXEC SQL include sqlglobals.h;
+
+// SQL error codes:
+EXEC SQL include "externs.h"
+
+// PG stuff
+#include "libpq-fe.h" // C interface to PgSQL
+// libq-style connection ptr taken from ECPG connect (needed for libq functions):
+// (currently used by relblobif/blobtile.pgc)
+PGconn *pgConn = NULL;
+
+// we use a non-public interface to obtain the connection ptr
+// defs are taken from PG's /src/interfaces/ecpg/ecpglib/extern.h
+// --- START non-public PG
+struct ECPGtype_information_cache
+{
+ struct ECPGtype_information_cache *next;
+ int oid;
+ bool isarray;
+};
+
+struct connection
+{
+ char *name;
+ PGconn *conn; // changed name to avoid component name clash of gcc3 -- PB 2005-feb-08
+ bool committed;
+ int autocommit;
+ struct ECPGtype_information_cache *cache_head;
+ struct connection *next;
+};
+
+
+// need to safeguard this from C++ name mangling -- PB 2005-feb-09
+//#ifdef __cplusplus
+//extern "C" {
+//#endif
+// struct connection *ECPGget_connection(const char *);
+//#ifdef __cplusplus
+//}
+//#endif
+
+// --- END non-public PG
+
+#include "databaseif.hh"
+#include "raslib/rmdebug.hh"
+#include "sqlerror.hh"
+#include "oidif.hh"
+#include "adminif.hh"
+
+extern char globalConnectId[256];
+// size of ARCHITECTURE attribute in RAS_ADMIN:
+#define SIZE_ARCH_RASADMIN 20
+
+
+void
+DatabaseIf::disconnect() throw (r_Error)
+{
+ RMDBGENTER(4, RMDebug::module_adminif, "DatabaseIf", "disconnect()");
+ ENTER( "DatabaseIf::disconnect" );
+
+ TALK( "EXEC SQL ROLLBACK WORK" );
+ EXEC SQL ROLLBACK WORK;
+ // 'ok' or 'no begin work issued' (which happens at a close database)
+ if (SQLCODE != SQLOK && SQLCODE != -255)
+ {
+ check("DatabaseIf::disconnect() ROLLBACK\0");
+ TALK( "Error while issuing ROLLBACK");
+ RMDBGMIDDLE(4, RMDebug::module_adminif, "DatabaseIf", "error occured while issuing a ROLLBACK");
+ }
+
+#ifndef FASTCONNECT
+ TALK( "EXEC SQL DISCONNECT CURRENT" );
+ EXEC SQL DISCONNECT CURRENT;
+ if (SQLCODE != SQLOK)
+ {
+ check("DatabaseIf::disconnect() DISCONNECT\0");
+ TALK( "Error while issuing DISCONNECT");
+ RMDBGMIDDLE(4, RMDebug::module_adminif, "DatabaseIf", "error occured while issuing a DISCONNECT");
+ }
+ pgConn = NULL;
+#endif
+
+ LEAVE( "DatabaseIf::disconnect, SQLCODE=" << SQLCODE );
+ RMDBGEXIT(4, RMDebug::module_adminif, "DatabaseIf", "disconnect() SQLCODE=" << SQLCODE);
+}
+
+void
+DatabaseIf::connect() throw (r_Error)
+{
+ RMDBGENTER(4, RMDebug::module_adminif, "DatabaseIf", "connect()");
+ ENTER( "DatabaseIf::connect" );
+
+#ifndef FASTCONNECT
+
+ EXEC SQL BEGIN DECLARE SECTION;
+ char id[STRING_MAXLEN];
+ EXEC SQL END DECLARE SECTION;
+
+
+ strcpy((char *)&id, globalConnectId);
+ TALK( "EXEC SQL CONNECT TO " << id );
+ EXEC SQL CONNECT TO :id AS rasdaConn; // "AS" param must be same as down in ECPGget_connection()
+ if (SQLCODE != SQLOK)
+ {
+ check("DatabaseIf::connect() CONNECT");
+ RMDBGMIDDLE(4, RMDebug::module_adminif, "DatabaseIf", "connect() SQLCODE=" << SQLCODE);
+ TALK( "error in connect, SQLCODE=" << SQLCODE );
+ generateException();
+ }
+ char newConnectId[256];
+ sprintf(newConnectId, "dbname='%s'", id);
+ pgConn = PQconnectdb(newConnectId);
+ if (pgConn == NULL || PQstatus(pgConn) == CONNECTION_BAD) {
+ RMDBGMIDDLE(4, RMDebug::module_adminif, "DatabaseIf", "Error: cannot obtain libpq connection" );
+ TALK( "Error: cannot obtain libpq connection" );
+ generateException();
+ }
+
+ /*
+
+ // get connection ptr for libpq based access
+ struct connection *interimConn = NULL;
+ interimConn = ECPGget_connection( "rasdaConn" ); // param must be same as up in CONNECT ... AS
+ if (interimConn == NULL || interimConn->conn == NULL)
+ {
+ }
+ pgConn = interimConn->conn;*/
+
+#endif
+
+ LEAVE( "DatabaseIf::connect, SQLCODE=" << SQLCODE );
+ RMDBGEXIT(4, RMDebug::module_adminif, "DatabaseIf", "connect()");
+}
+
+void
+DatabaseIf::checkCompatibility() throw (r_Error)
+{
+ RMDBGENTER(4, RMDebug::module_adminif, "DatabaseIf", "checkCompatibility()");
+ ENTER( "DatabaseIf::checkCompatibility" );
+
+ EXEC SQL BEGIN DECLARE SECTION;
+ long rasver1; // rasdaman version as stored in db
+ long schemaver1; // schema version as stored in db
+ char* arch1[SIZE_ARCH_RASADMIN]; // used for reading architecture from db
+ char *myArchitecture = RASARCHITECTURE; // used for architecture selection
+ EXEC SQL END DECLARE SECTION;
+
+ TALK( "EXEC SQL SELECT ServerVersion, IFVersion INTO :rasver1, :schemaver1 FROM RAS_ADMIN WHERE Architecture = " << myArchitecture );
+ EXEC SQL SELECT
+ ServerVersion, IFVersion
+ INTO
+ :rasver1, :schemaver1
+ FROM
+ RAS_ADMIN
+ WHERE
+ Architecture = :myArchitecture;
+ TALK( "-> rasver1=" << rasver1 << ", schemaver1=" << schemaver1 );
+ if (SQLCODE != SQLOK)
+ {
+ check("DatabaseIf::baseDBMSOpen() check schema\0");
+ // this error is not supported by PG -- PB 2005-jan-07
+ // if (SQLCODE == SQLTABLEUNKNOWN)...
+
+ if (SQLCODE == SQLNODATAFOUND)
+ {
+ RMInit::logOut << "The Database is incompatible with the current RasServer." << std::endl \
+ << "Database has no entry for the current platform." << std::endl \
+ << "You are using rasserver:" << std::endl \
+ << "\tversion " << RMANVERSION << std::endl \
+ << "\tschema " << RASSCHEMAVERSION << std::endl \
+ << "\tplatform " << RASARCHITECTURE << std::endl;
+ EXEC SQL DECLARE admincursor CURSOR FOR
+ SELECT
+ ServerVersion, IFVersion, Architecture
+ FROM
+ RAS_ADMIN;
+ EXEC SQL OPEN admincursor;
+ do
+ {
+ (void) memset( arch1, '\0', (size_t) sizeof(arch1) ); // just to make sure string is terminated
+ EXEC SQL FETCH admincursor INTO :rasver1, :schemaver1, :arch1;
+ if (SQLCODE != SQLOK)
+ {
+ if (SQLCODE != SQLNODATAFOUND)
+ {
+ check("DatabaseIf::checkCompatibility()\0");
+ RMInit::logOut << "DBMS Error occured during compatibility check." << std::endl \
+ << "Please see Debug Log for additional information." << std::endl;
+ EXEC SQL CLOSE admincursor;
+ generateException();
+ }
+ break;
+ }
+ RMInit::logOut << "Found database entries for rasserver:" << std::endl \
+ << "\tversion " << rasver1 << std::endl \
+ << "\tschema " << schemaver1 << std::endl \
+ << "\tplatform " << arch1 << std::endl << std::endl \
+ << "Please see Migration Documentation." << std::endl;
+ } while (true);
+
+ EXEC SQL CLOSE admincursor;
+ throw r_Error(DATABASE_INCOMPATIBLE);
+ }
+ else
+ {
+ RMInit::logOut << "DBMS Error occured during compatibility check." << std::endl \
+ << "Please see Debug Log for additional information." << std::endl;
+ generateException();
+ }
+ }
+ else
+ {
+ if (schemaver1 != RASSCHEMAVERSION)
+ {
+ RMInit::logOut << "The Database is incompatible with the current RasServer." << std::endl \
+ << "The database was generated with:" << std::endl \
+ << "\tversion " << rasver1 << std::endl \
+ << "\tschema " << schemaver1 << std::endl \
+ << "\tplatform " << arch1 << std::endl << std::endl \
+ << "You are using rasserver:" << std::endl \
+ << "\tversion " << RMANVERSION << std::endl \
+ << "\tschema " << RASSCHEMAVERSION << std::endl \
+ << "\tplatform " << RASARCHITECTURE << std::endl \
+ << "Please see Migration Documentation." << std::endl;
+ throw r_Error(DATABASE_INCOMPATIBLE);
+ }
+#if 0 // do not check against release, v6 has same schema as v5! -- PB 2005-sep-18
+ // check only against major release number -- PB 2003-sep-08
+ if (rasver1/1000 != RMANVERSION/1000)
+ {
+ RMInit::logOut << "The Database is incompatible with the current RasServer." << std::endl \
+ << "The database was generated with:" << std::endl \
+ << "\tversion " << rasver1 << std::endl \
+ << "\tschema " << schemaver1 << std::endl \
+ << "\tplatform " << arch1 << std::endl << std::endl \
+ << "You are using rasserver:" << std::endl \
+ << "\tversion " << RMANVERSION << std::endl \
+ << "\tschema " << RASSCHEMAVERSION << std::endl \
+ << "\tplatform " << RASARCHITECTURE << std::endl \
+ << "Please see Migration Documentation." << std::endl;
+ throw r_Error(DATABASE_INCOMPATIBLE);
+ }
+#endif // 0
+ }
+
+ LEAVE( "DatabaseIf::checkCompatibility" );
+ RMDBGEXIT(4, RMDebug::module_adminif, "DatabaseIf", "checkComptatibility()");
+}
+
+bool
+DatabaseIf::isConsistent() throw (r_Error)
+{
+ RMDBGENTER(4, RMDebug::module_adminif, "DatabaseIf", "isConsistent()");
+ ENTER( "DatabaseIf::isConsistent" );
+
+ bool retval=true;
+
+ EXEC SQL BEGIN DECLARE SECTION;
+ long nextoid;
+ long checkoid; // was: double -- PB 2005-jul-12
+ short oidind;
+ char name2[255]; // must be able to hold counterNames elements, see oidif.cc
+ EXEC SQL END DECLARE SECTION;
+ nextoid = 0;
+ checkoid = 0;
+ oidind = 0;
+
+ (void) strncpy( name2, (char*) OId::counterNames[OId::DBMINTERVALOID], (size_t) sizeof(name2) );
+ TALK( "EXEC SQL SELECT NextValue INTO :nextoid FROM RAS_COUNTERS WHERE CounterName = " << name2 );
+ EXEC SQL SELECT NextValue INTO :nextoid
+ FROM
+ RAS_COUNTERS
+ WHERE
+ CounterName = :name2;
+ TALK( "-> nextoid=" << nextoid );
+ if (check("DatabaseIf::isConsistent() SELECT DBMINTERVALOID"))
+ generateException();
+
+ // replaced MAX() (which ignores index) by ORDER BY variant -- PB 2005-jul-12
+ // EXEC SQL SELECT MAX(DomainId) INTO :checkoid INDICATOR :oidind
+ // FROM RAS_DOMAINS;
+ checkoid = 0;
+ TALK( "SELECT DomainId..." );
+ EXEC SQL SELECT DomainId INTO :checkoid INDICATOR :oidind
+ FROM RAS_DOMAINS
+ ORDER BY DomainId DESC LIMIT 1;
+ TALK( "-> SQLCODE=" << SQLCODE );
+ // now "no data" means no error, but that we need to initialize the empty table
+ if (SQLCODE < 0)
+ {
+ check("DatabaseIf::isConsistent() SELECT MAX(DomainId)");
+ generateException();
+ }
+ if ((checkoid > nextoid) && (oidind == 0))
+ {
+ RMInit::logOut << "The administrative tables for Domain Data is inconsistent. Please call support." << std::endl;
+ RMInit::dbgOut << std::endl << "Counter in RAS_DOMAINS : " << checkoid << std::endl << "Counter in RAS_COUNTERS : " << nextoid << std::endl;
+ retval=false;
+ }
+ checkoid = 0;
+ nextoid=0;
+ oidind=0;
+
+ if(retval)
+ {
+ (void) strncpy( name2, (char*) OId::counterNames[OId::MDDOID], (size_t) sizeof(name2) );
+ TALK( "SELECT NextValue FROM RAS_COUNTERS..." );
+ EXEC SQL SELECT NextValue INTO :nextoid
+ FROM RAS_COUNTERS
+ WHERE CounterName = :name2;
+ if (check("DatabaseIf::isConsistent() SELECT MDDOID"))
+ generateException();
+ // replaced MAX() (which ignores index) by ORDER BY variant -- PB 2005-jul-12
+ // EXEC SQL SELECT MAX(MDDId) INTO :checkoid INDICATOR :oidind
+ // FROM RAS_MDDOBJECTS;
+ checkoid = 0;
+ TALK( "SELECT MDDId FROM RAS_MDDOBJECTS..." );
+ EXEC SQL SELECT MDDId INTO :checkoid INDICATOR :oidind
+ FROM RAS_MDDOBJECTS
+ ORDER BY MDDId DESC LIMIT 1;
+ // now "no data" means no error, but that we need to initialize the empty table
+ if (SQLCODE < 0)
+ {
+ check("DatabaseIf::isConsistent() SELECT MAX(MDDId)");
+ generateException();
+ }
+
+ if ((checkoid > nextoid) && (oidind == 0))
+ {
+ RMInit::logOut << "The administrative tables for MDD Objects is inconsistent. Please call support." << std::endl;
+ RMInit::dbgOut << std::endl << "Counter in RAS_MDDOBJECTS : " << checkoid << std::endl << "Counter in RAS_COUNTERS : " << nextoid << std::endl;
+ retval=false;
+ }
+ checkoid = 0;
+ nextoid=0;
+ oidind=0;
+ }
+
+ if(retval)
+ {
+ (void) strncpy( name2, (char*) OId::counterNames[OId::MDDCOLLOID], (size_t) sizeof(name2) );
+ EXEC SQL SELECT NextValue INTO :nextoid
+ FROM RAS_COUNTERS
+ WHERE CounterName = :name2;
+ if (check("DatabaseIf::isConsistent() SELECT MDDCollOId"))
+ generateException();
+ // replaced MAX() (which ignores index) by ORDER BY variant -- PB 2005-jul-12
+ // EXEC SQL SELECT MAX(MDDCollId) INTO :checkoid INDICATOR :oidind
+ // FROM RAS_MDDCOLLNAMES;
+ checkoid = 0;
+ TALK( "SELECT MDDCollId FROM RAS_MDDCOLLNAMES..." );
+ EXEC SQL SELECT MDDCollId INTO :checkoid INDICATOR :oidind
+ FROM RAS_MDDCOLLNAMES
+ ORDER BY MDDCollId DESC LIMIT 1;
+ // now "no data" means no error, but that we need to initialize the empty table
+ if (SQLCODE < 0)
+ {
+ check("DatabaseIf::isConsistent() SELECT MAX(MDDCollId)");
+ generateException();
+ }
+
+ if ((checkoid > nextoid) && (oidind == 0))
+ {
+ RMInit::logOut << "The administrative tables for MDD Collections is inconsistent. Please call support." << std::endl;
+ RMInit::dbgOut << std::endl << "Counter in RAS_MDDCOLLNAMES : " << checkoid << std::endl << "Counter in RAS_COUNTERS : " << nextoid << std::endl;
+ retval=false;
+ }
+ checkoid = 0;
+ nextoid=0;
+ oidind=0;
+ }
+
+ if(retval)
+ {
+ (void) strncpy( name2, (char*) OId::counterNames[OId::MDDTYPEOID], (size_t) sizeof(name2) );
+ EXEC SQL SELECT NextValue INTO :nextoid
+ FROM RAS_COUNTERS
+ WHERE CounterName = :name2;
+ if (check("DatabaseIf::isConsistent() SELECT MDDTYPEOID"))
+ generateException();
+ // replaced MAX() (which ignores index) by ORDER BY variant -- PB 2005-jul-12
+ // EXEC SQL SELECT MAX(MDDTypeOId) INTO :checkoid INDICATOR :oidind
+ // FROM RAS_MDDTYPES;
+ checkoid = 0;
+ TALK( "SELECT MDDTypeOId FROM RAS_MDDTYPES..." );
+ EXEC SQL SELECT MDDTypeOId INTO :checkoid INDICATOR :oidind
+ FROM RAS_MDDTYPES
+ ORDER BY MDDTypeOId DESC LIMIT 1;
+ TALK( "SELECT MDDTypeOId FROM RAS_MDDTYPES..." );
+ // now "no data" means no error, but that we need to initialize the empty table
+ if (SQLCODE < 0)
+ {
+ check("DatabaseIf::isConsistent() SELECT MAX(MDDTypeOId)");
+ generateException();
+ }
+
+ if (checkoid > nextoid)
+ {
+ RMInit::logOut << "The administrative tables for MDDTypes is inconsistent. Please call support." << std::endl;
+ RMInit::dbgOut << std::endl << "Counter in RAS_MDDTYPES : " << checkoid << std::endl << "Counter in RAS_COUNTERS : " << nextoid << " real " << nextoid << std::endl;
+ retval=false;
+ }
+ checkoid = 0;
+ nextoid=0;
+ oidind=0;
+ }
+
+ if(retval)
+ {
+ (void) strncpy( name2, (char*) OId::counterNames[OId::MDDBASETYPEOID], (size_t) sizeof(name2) );
+ EXEC SQL SELECT NextValue INTO :nextoid
+ FROM RAS_COUNTERS
+ WHERE CounterName = :name2;
+ if (check("DatabaseIf::isConsistent() SELECT MDDBASETYPEOID"))
+ generateException();
+ // replaced MAX() (which ignores index) by ORDER BY variant -- PB 2005-jul-12
+ // EXEC SQL SELECT MAX(MDDBaseTypeOId) INTO :checkoid INDICATOR :oidind
+ // FROM RAS_MDDBASETYPES;
+ checkoid = 0;
+ TALK( "SELECT MDDBaseTypeOId FROM RAS_MDDBASETYPES..." );
+ EXEC SQL SELECT MDDBaseTypeOId INTO :checkoid INDICATOR :oidind
+ FROM RAS_MDDBASETYPES
+ ORDER BY MDDBaseTypeOId DESC LIMIT 1;
+ // now "no data" means no error, but that we need to initialize the empty table
+ if (SQLCODE < 0)
+ {
+ check("DatabaseIf::isConsistent() SELECT MAX(MDDBaseTypeOId)");
+ generateException();
+ }
+
+ if (checkoid > nextoid)
+ {
+ RMInit::logOut << "The administrative tables for MDDBaseTypes is inconsistent. Please call support." << std::endl;
+ RMInit::dbgOut << std::endl << "Counter in RAS_MDDBASETYPES : " << checkoid << std::endl << "Counter in RAS_COUNTERS : " << nextoid << " real " << nextoid << std::endl;
+ retval=false;
+ }
+ checkoid = 0;
+ nextoid=0;
+ oidind=0;
+ }
+
+ if(retval)
+ {
+ (void) strncpy( name2, (char*) OId::counterNames[OId::MDDDIMTYPEOID], (size_t) sizeof(name2) );
+ EXEC SQL SELECT NextValue INTO :nextoid
+ FROM RAS_COUNTERS
+ WHERE CounterName = :name2;
+ if (check("DatabaseIf::isConsistent() SELECT MDDDIMTYPEOID"))
+ generateException();
+ // replaced MAX() (which ignores index) by ORDER BY variant -- PB 2005-jul-12
+ // EXEC SQL SELECT MAX(MDDDimTypeOId) INTO :checkoid INDICATOR :oidind
+ // FROM RAS_MDDDIMTYPES;
+ checkoid = 0;
+ TALK( "SELECT MDDDimTypeOId FROM RAS_MDDDIMTYPES..." );
+ EXEC SQL SELECT MDDDimTypeOId INTO :checkoid INDICATOR :oidind
+ FROM RAS_MDDDIMTYPES
+ ORDER BY MDDDimTypeOId DESC LIMIT 1;
+ // now "no data" means no error, but that we need to initialize the empty table
+ if (SQLCODE < 0)
+ {
+ check("DatabaseIf::isConsistent() SELECT MAX(MDDDimTypeOId)");
+ generateException();
+ }
+
+ if (checkoid > nextoid)
+ {
+ RMInit::logOut << "The administrative tables for MDDDimensionTypes is inconsistent. Please call support." << std::endl;
+ RMInit::dbgOut << std::endl << "Counter in RAS_MDDDIMTYPES : " << checkoid << std::endl << "Counter in RAS_COUNTERS : " << nextoid << " real " << nextoid << std::endl;
+ retval=false;
+ }
+ checkoid = 0;
+ nextoid=0;
+ oidind=0;
+ }
+
+ if(retval)
+ {
+ (void) strncpy( name2, (char*) OId::counterNames[OId::MDDDOMTYPEOID], (size_t) sizeof(name2) );
+ EXEC SQL SELECT NextValue INTO :nextoid
+ FROM RAS_COUNTERS
+ WHERE CounterName = :name2;
+ if (check("DatabaseIf::isConsistent() SELECT MDDDOMTYPEOID"))
+ generateException();
+ // replaced MAX() (which ignores index) by ORDER BY variant -- PB 2005-jul-12
+ // EXEC SQL SELECT MAX(MDDDomTypeOId) INTO :checkoid INDICATOR :oidind
+ // FROM RAS_MDDDOMTYPES;
+ checkoid = 0;
+ TALK( "SELECT MDDDomTypeOId FROM RAS_MDDDOMTYPES..." );
+ EXEC SQL SELECT MDDDomTypeOId INTO :checkoid INDICATOR :oidind
+ FROM RAS_MDDDOMTYPES
+ ORDER BY MDDDomTypeOId DESC LIMIT 1;
+ // now "no data" means no error, but that we need to initialize the empty table
+ if (SQLCODE < 0)
+ {
+ check("DatabaseIf::isConsistent() SELECT MAX(MDDDomTypeId)");
+ generateException();
+ }
+
+ if (checkoid > nextoid)
+ {
+ RMInit::logOut << "The administrative tables for MDDDomainTypes is inconsistent. Please call support." << std::endl;
+ RMInit::dbgOut << std::endl << "Counter in RAS_MDDDOMTYPES : " << checkoid << std::endl << "Counter in RAS_COUNTERS : " << nextoid << " real " << nextoid << std::endl;
+ retval=false;
+ }
+ checkoid = 0;
+ nextoid=0;
+ oidind=0;
+ }
+
+ if(retval)
+ {
+ (void) strncpy( name2, (char*) OId::counterNames[OId::STRUCTTYPEOID], (size_t) sizeof(name2) );
+ EXEC SQL SELECT NextValue INTO :nextoid
+ FROM RAS_COUNTERS
+ WHERE CounterName = :name2;
+ if (check("DatabaseIf::isConsistent() SELECT STRUCTTYPEOID"))
+ generateException();
+ // replaced MAX() (which ignores index) by ORDER BY variant -- PB 2005-jul-12
+ // EXEC SQL SELECT MAX(BaseTypeId) INTO :checkoid INDICATOR :oidind
+ // FROM RAS_BASETYPENAMES;
+ checkoid = 0;
+ TALK( "SELECT BaseTypeId FROM RAS_BASETYPENAMES..." );
+ EXEC SQL SELECT BaseTypeId INTO :checkoid INDICATOR :oidind
+ FROM RAS_BASETYPENAMES
+ ORDER BY BaseTypeId DESC LIMIT 1;
+ // now "no data" means no error, but that we need to initialize the empty table
+ if (SQLCODE < 0)
+ {
+ check("DatabaseIf::isConsistent() SELECT MAX(BaseTypeId)");
+ generateException();
+ }
+
+ if ((checkoid > nextoid) && (oidind == 0))
+ {
+ RMInit::logOut << "The administrative tables for StructTypes is inconsistent. Please call support." << std::endl;
+ RMInit::dbgOut << std::endl << "Counter in RAS_BASETYPENAMES : " << checkoid << std::endl << "Counter in RAS_COUNTERS : " << nextoid << std::endl;
+ retval=false;
+ }
+ checkoid = 0;
+ nextoid=0;
+ oidind=0;
+ }
+
+ if(retval)
+ {
+ (void) strncpy( name2, (char*) OId::counterNames[OId::SETTYPEOID], (size_t) sizeof(name2) );
+ EXEC SQL SELECT NextValue INTO :nextoid
+ FROM RAS_COUNTERS
+ WHERE CounterName = :name2;
+ if (check("DatabaseIf::isConsistent() SELECT SETTYPEOID"))
+ generateException();
+ // replaced MAX() (which ignores index) by ORDER BY variant -- PB 2005-jul-12
+ // EXEC SQL SELECT MAX(SetTypeId) INTO :checkoid INDICATOR :oidind
+ // FROM RAS_SETTYPES;
+ checkoid = 0;
+ TALK( "SELECT SetTypeId FROM RAS_SETTYPES..." );
+ EXEC SQL SELECT SetTypeId INTO :checkoid INDICATOR :oidind
+ FROM RAS_SETTYPES
+ ORDER BY SetTypeId DESC LIMIT 1;
+ // now "no data" means no error, but that we need to initialize the empty table
+ if (SQLCODE < 0)
+ {
+ check("DatabaseIf::isConsistent() SELECT MAX(SetTypeId)");
+ generateException();
+ }
+
+ if ((checkoid > nextoid) && (oidind == 0))
+ {
+ RMInit::logOut << "The administrative tables for MDDTypes is inconsistent. Please call support." << std::endl;
+ RMInit::dbgOut << std::endl << "Counter in RAS_SETTYPES : " << checkoid << std::endl << "Counter in RAS_COUNTERS : " << nextoid << std::endl;
+ retval=false;
+ }
+ checkoid = 0;
+ nextoid=0;
+ oidind=0;
+ }
+
+ if(retval)
+ {
+ (void) strncpy( name2, (char*) OId::counterNames[OId::BLOBOID], (size_t) sizeof(name2) );
+ EXEC SQL SELECT NextValue INTO :nextoid
+ FROM RAS_COUNTERS
+ WHERE CounterName = :name2;
+ if (check("DatabaseIf::isConsistent() SELECT BLOBOID"))
+ generateException();
+ // replaced MAX() (which ignores index) by ORDER BY variant -- PB 2005-jul-12
+ // EXEC SQL SELECT MAX(BlobId) INTO :checkoid INDICATOR :oidind
+ // FROM RAS_TILES;
+ checkoid = 0;
+ TALK( "SELECT BlobId FROM RAS_TILES..." );
+ EXEC SQL SELECT BlobId INTO :checkoid INDICATOR :oidind
+ FROM RAS_TILES
+ ORDER BY BlobId DESC LIMIT 1;
+ // now "no data" means no error, but that we need to initialize the empty table
+ if (SQLCODE < 0)
+ {
+ check("DatabaseIf::isConsistent() SELECT MAX(BlobId)");
+ generateException();
+ }
+
+ if ((checkoid > nextoid) && (oidind == 0))
+ {
+ RMInit::logOut << "The administrative tables for BLOB Data is inconsistent. Please call support." << std::endl;
+ RMInit::dbgOut << std::endl << "Counter in RAS_TILES : " << checkoid << std::endl << "Counter in RAS_COUNTERS : " << nextoid << std::endl;
+ retval=false;
+ }
+ checkoid = 0;
+ nextoid=0;
+ oidind=0;
+ }
+
+ if(retval)
+ {
+ (void) strncpy( name2, (char*) OId::counterNames[OId::MDDHIERIXOID], (size_t) sizeof(name2) );
+ EXEC SQL SELECT NextValue INTO :nextoid
+ FROM RAS_COUNTERS
+ WHERE CounterName = :name2;
+ if (check("DatabaseIf::isConsistent() SELECT MDDHIERIXOID"))
+ generateException();
+ // replaced MAX() (which ignores index) by ORDER BY variant -- PB 2005-jul-12
+ // EXEC SQL SELECT MAX(MDDObjIxOId) INTO :checkoid INDICATOR :oidind
+ // FROM RAS_HIERIX;
+ checkoid = 0;
+ TALK( "SELECT MDDObjIxOId FROM RAS_HIERIX..." );
+ EXEC SQL SELECT MDDObjIxOId INTO :checkoid INDICATOR :oidind
+ FROM RAS_HIERIX
+ ORDER BY MDDObjIxOId DESC LIMIT 1;
+ // now "no data" means no error, but that we need to initialize the empty table
+ if (SQLCODE < 0)
+ {
+ check("DatabaseIf::isConsistent() SELECT MAX(MDDObjIxOId)");
+ generateException();
+ }
+
+ if (checkoid > (nextoid * 512 + OId::MDDHIERIXOID))
+ {
+ RMInit::logOut << "The administrative tables for hierarchical MDD indexes is inconsistent. Please call support." << std::endl;
+ RMInit::dbgOut << std::endl << "Counter in RAS_HIERIX : " << checkoid << std::endl << "Counter in RAS_COUNTERS : " << nextoid << " real " << (nextoid * 512 + OId::MDDHIERIXOID) << std::endl;
+ retval=false;
+ }
+ checkoid = 0;
+ nextoid=0;
+ oidind=0;
+ }
+
+ if(retval)
+ {
+ (void) strncpy( name2, (char*) OId::counterNames[OId::STORAGEOID], (size_t) sizeof(name2) );
+ EXEC SQL SELECT NextValue INTO :nextoid
+ FROM RAS_COUNTERS
+ WHERE CounterName = :name2;
+ if (check("DatabaseIf::isConsistent() SELECT STORAGEOID"))
+ generateException();
+ // replaced MAX() (which ignores index) by ORDER BY variant -- PB 2005-jul-12
+ // EXEC SQL SELECT MAX(StorageId) INTO :checkoid INDICATOR :oidind
+ // FROM RAS_STORAGE;
+ checkoid=0;
+ TALK( "SELECT StorageId FROM RAS_STORAGE..." );
+ EXEC SQL SELECT StorageId INTO :checkoid INDICATOR :oidind
+ FROM RAS_STORAGE
+ ORDER BY StorageId DESC LIMIT 1;
+ // now "no data" means no error, but that we need to initialize the empty table
+ if (SQLCODE < 0)
+ {
+ check("DatabaseIf::isConsistent() SELECT MAX(StorageId)");
+ generateException();
+ }
+
+ if ((checkoid > nextoid) && (oidind == 0))
+ {
+ RMInit::logOut << "Fatal error: administrative tables for MDD storage structures are inconsistent. Please call support." << std::endl;
+ RMInit::dbgOut << std::endl << "Counter in RAS_STORAGE : " << checkoid << std::endl << "Counter in RAS_COUNTERS : " << nextoid << std::endl;
+ retval=false;
+ }
+ checkoid=0;
+ nextoid=0;
+ oidind=0;
+ }
+
+ LEAVE( "DatabaseIf::isConsistent, retval=" << retval );
+ RMDBGEXIT(4, RMDebug::module_adminif, "DatabaseIf", "isConsistent() " << retval);
+ return retval;
+}
+
+void
+DatabaseIf::createDB(const char* dbName, const char* schemaName, const char* volumeName) throw(r_Error)
+{
+ RMDBGENTER(4, RMDebug::module_adminif, "DatabaseIf", "create(" << dbName << ", " << schemaName << ", " << volumeName << ")");
+ ENTER( "DatabaseIf::createDB, dbName=" << dbName << ", schemaName=" << schemaName << ", volumeName=" << volumeName );
+
+ int i=0;
+ EXEC SQL BEGIN DECLARE SECTION;
+ long id;
+ long idd;
+ char name[255];
+ EXEC SQL END DECLARE SECTION;
+
+ name[0] = '\0'; // initialize to empty string
+
+ try
+ {
+ if (AdminIf::getCurrentDatabaseIf() != 0)
+ {
+ RMDBGMIDDLE(5, RMDebug::module_adminif, "DatabaseIf", "another database is open");
+ TALK( "Error: another database is open" );
+ throw r_Error(r_Error::r_Error_DatabaseOpen);
+ }
+ connect();
+ TALK( "EXEC SQL BEGIN WORK;");
+ EXEC SQL BEGIN WORK;
+ if(check("DatabaseIf::create() BEGIN WORK\0"))
+ generateException();
+
+/* not used, see comment with databaseExists()
+ // does database exist already?
+ if (databaseExists(dbName))
+ {
+ RMDBGMIDDLE(5, RMDebug::module_adminif, "DatabaseIf", "database already exists");
+ RMInit::logOut << "Database creation failed: database exists already." << std::endl;
+ TALK( "Error: database exists." );
+ throw r_Error(DATABASE_EXISTS);
+ }
+*/
+
+ // --- start table/index creation ------------------------------
+
+ // no index here because there is only one entry in the table
+ TALK( "EXEC SQL CREATE TABLE RAS_ADMIN ( IFVersion INTEGER NOT NULL, Architecture VARCHAR(20) NOT NULL, ServerVersion INTEGER NOT NULL) " );
+ EXEC SQL CREATE TABLE RAS_ADMIN (
+ IFVersion INTEGER NOT NULL,
+ Architecture VARCHAR(20) NOT NULL,
+ ServerVersion INTEGER NOT NULL
+ );
+ if(check("DatabaseIf::create() CREATE TABLE RAS_ADMIN\0"))
+ generateException();
+
+ id = RASSCHEMAVERSION;
+ idd = RMANVERSION;
+ (void) strncpy( name, RASARCHITECTURE, (size_t) sizeof(name) );
+
+ TALK( "EXEC SQL INSERT INTO RAS_ADMIN (IFVersion, Architecture, ServerVersion) VALUES (" << id << ", " << name << ", " << idd << ")" );
+ EXEC SQL INSERT INTO RAS_ADMIN (IFVersion, Architecture, ServerVersion) VALUES (:id, :name, :idd);
+ if(check("DatabaseIf::create() INSERT INTO RAS_ADMIN\0"))
+ generateException();
+
+ // no index here because there is only 20 entries in the table
+ TALK( "EXEC SQL CREATE TABLE RAS_COUNTERS ( NextValue INTEGER NOT NULL, CounterName VARCHAR(20) NOT NULL)" );
+ EXEC SQL CREATE TABLE RAS_COUNTERS (
+ NextValue INTEGER NOT NULL,
+ CounterName VARCHAR(20) NOT NULL
+ );
+ if(check("DatabaseIf::create() CREATE TABLE RAS_COUNTERS\0"))
+ generateException();
+
+ // initialising RAS_COUNTERS
+ for(i = 1; i < OId::maxCounter; i++)
+ {
+ (void) strncpy( name, (char*) OId::counterNames[i], (size_t) sizeof(name) );
+ id = 1;
+ TALK( "EXEC SQL INSERT INTO RAS_COUNTERS (CounterName, NextValue) VALUES (" << name << "," << id << ")" );
+ EXEC SQL INSERT INTO RAS_COUNTERS (CounterName, NextValue) VALUES (:name, :id);
+ if(check("DatabaseIf::create() INSERT INTO RAS_COUNTERS\0"))
+ generateException();
+ }
+
+ TALK( "...and several more tables..." );
+
+ // relblobif
+ EXEC SQL CREATE TABLE RAS_TILES (
+ BlobId INTEGER NOT NULL,
+ DataFormat INTEGER,
+ Tile oid
+ );
+ if(check("DatabaseIf::create() CREATE TABLE RAS_TILES\0"))
+ generateException();
+
+ EXEC SQL CREATE UNIQUE INDEX RAS_TILES_IX
+ ON RAS_TILES (BlobId);
+ if(check("DatabaseIf::create() CREATE UNIQUE INDEX RAS_TILES_IX\0"))
+ generateException();
+
+ //ras_itiles
+ EXEC SQL CREATE TABLE RAS_ITILES (
+ ITileId INTEGER NOT NULL,
+ ITile oid
+ );
+ if (check("DatabaseIf::create() CREATE TABLE RAS_ITILES\0"))
+ generateException();
+
+ EXEC SQL CREATE UNIQUE INDEX RAS_ITILES_IX
+ ON RAS_ITILES (ITileId);
+ if(check("DatabaseIf::create() CREATE UNIQUE INDEX RAS_ITILES_IX\0"))
+ generateException();
+
+ // relcatalogif
+ EXEC SQL CREATE TABLE RAS_MDDTYPES (
+ MDDTypeOId DEC(15,0) NOT NULL,
+ MDDTypeName VARCHAR(254) NOT NULL
+ );
+ if(check("DatabaseIf::create() CREATE TABLE RAS_MDDTYPES\0"))
+ generateException();
+
+ EXEC SQL CREATE UNIQUE INDEX RAS_MDDTYPES_IX
+ ON RAS_MDDTYPES (MDDTypeOId);
+ if(check("DatabaseIf::create() CREATE UNIQUE INDEX RAS_MDDTYPES_IX\0"))
+ generateException();
+
+ EXEC SQL CREATE TABLE RAS_ITMAP (
+ TileId INTEGER NOT NULL,
+ IndexId INTEGER NOT NULL
+ );
+ if(check("DatabaseIf::create() CREATE TABLE RAS_ITMAP\0"))
+ generateException();
+
+ EXEC SQL CREATE UNIQUE INDEX RAS_ITMAP_IX
+ ON RAS_ITMAP (TileId);
+ if(check("DatabaseIf::create() CREATE UNIQUE INDEX RAS_ITMAP_IX\0"))
+ generateException();
+
+ EXEC SQL CREATE TABLE RAS_MDDBASETYPES (
+ MDDBaseTypeOId DEC(15,0) NOT NULL,
+ BaseTypeId DEC(15,0) NOT NULL,
+ MDDTypeName VARCHAR(254) NOT NULL
+ );
+ if(check("DatabaseIf::create() CREATE TABLE RAS_MDDBASETYPES\0"))
+ generateException();
+
+ EXEC SQL CREATE UNIQUE INDEX RAS_MDDBASETYPES_IX
+ ON RAS_MDDBASETYPES (MDDBaseTypeOId);
+ if(check("DatabaseIf::create() CREATE UNIQUE INDEX RAS_MDDBASETYPES_IX\0"))
+ generateException();
+
+ EXEC SQL CREATE TABLE RAS_MDDDIMTYPES (
+ MDDDimTypeOId DEC(15,0) NOT NULL,
+ BaseTypeId DEC(15,0) NOT NULL,
+ Dimension INTEGER NOT NULL,
+ MDDTypeName VARCHAR(254) NOT NULL
+ );
+ if(check("DatabaseIf::create() CREATE TABLE RAS_MDDDIMTYPES\0"))
+ generateException();
+
+ EXEC SQL CREATE UNIQUE INDEX RAS_MDDDIMTYPES_IX
+ ON RAS_MDDDIMTYPES (MDDDimTypeOId);
+ if(check("DatabaseIf::create() CREATE UNIQUE INDEX RAS_MDDDIMTYPES_IX\0"))
+ generateException();
+
+ EXEC SQL CREATE TABLE RAS_MDDDOMTYPES (
+ MDDDomTypeOId DEC(15,0) NOT NULL,
+ BaseTypeId DEC(15,0) NOT NULL,
+ DomainId INTEGER NOT NULL,
+ MDDTypeName VARCHAR(254) NOT NULL
+ );
+ if(check("DatabaseIf::create() CREATE TABLE RAS_MDDDOMAINTYPES\0"))
+ generateException();
+
+ EXEC SQL CREATE UNIQUE INDEX RAS_MDDDOMTYPES_IX
+ ON RAS_MDDDOMTYPES (MDDDomTypeOId);
+ if(check("DatabaseIf::create() CREATE UNIQUE INDEX RAS_MDDDOMTYPES_IX\0"))
+ generateException();
+
+ EXEC SQL CREATE TABLE RAS_SETTYPES (
+ SetTypeId INTEGER NOT NULL,
+ MDDTypeOId DEC(15,0) NOT NULL,
+ SetTypeName VARCHAR(254) NOT NULL
+ );
+ if(check("DatabaseIf::create() CREATE TABLE RAS_SETTYPES\0"))
+ generateException();
+
+ EXEC SQL CREATE UNIQUE INDEX RAS_SETTYPES_IX
+ ON RAS_SETTYPES (SetTypeId);
+ if(check("DatabaseIf::create() CREATE UNIQUE INDEX RAS_SETTYPES_IX\0"))
+ generateException();
+
+ EXEC SQL CREATE TABLE RAS_BASETYPENAMES (
+ BaseTypeId SMALLINT NOT NULL,
+ BaseTypeName VARCHAR (254) NOT NULL
+ );
+ if(check("DatabaseIf::create() CREATE TABLE RAS_BASETYPENAMES\0"))
+ generateException();
+
+ EXEC SQL CREATE UNIQUE INDEX RAS_BASETYPENAMES_IX
+ ON RAS_BASETYPENAMES (BaseTypeId);
+ if(check("DatabaseIf::create() CREATE UNIQUE INDEX RAS_BASETYPENAMES_IX\0"))
+ generateException();
+
+ EXEC SQL CREATE TABLE RAS_BASETYPES (
+ BaseTypeId INTEGER NOT NULL,
+ Count SMALLINT NOT NULL,
+ ContentType DEC(15,0) NOT NULL,
+ ContentTypeName VARCHAR (254) NOT NULL
+ );
+ if(check("DatabaseIf::create() CREATE TABLE RAS_BASETYPES\0"))
+ generateException();
+
+ EXEC SQL CREATE INDEX RAS_BASETYPESC_IX
+ ON RAS_BASETYPES (BaseTypeId);
+ if(check("DatabaseIf::create() CREATE INDEX RAS_BASETYPES_IX\0"))
+ generateException();
+
+ EXEC SQL CREATE UNIQUE INDEX RAS_BASETYPES_IX
+ ON RAS_BASETYPES (BaseTypeId, Count);
+ if(check("DatabaseIf::create() CREATE UNIQUE INDEX RAS_BASETYPES_IX\0"))
+ generateException();
+
+ EXEC SQL CREATE TABLE RAS_DOMAINS (
+ DomainId INTEGER NOT NULL,
+ Dimension INTEGER NOT NULL
+ );
+ if(check("DatabaseIf::create() CREATE TABLE RAS_DOMAINS\0"))
+ generateException();
+
+ EXEC SQL CREATE UNIQUE INDEX RAS_DOMAINS_IX
+ ON RAS_DOMAINS (DomainId);
+ if(check("DatabaseIf::create() CREATE UNIQUE INDEX RAS_DOMAINS_IX\0"))
+ generateException();
+
+ EXEC SQL CREATE TABLE RAS_DOMAINVALUES (
+ DomainId INTEGER NOT NULL,
+ DimensionCount INTEGER NOT NULL,
+ Low INTEGER,
+ High INTEGER
+ );
+ if(check("DatabaseIf::create() CREATE TABLE RAS_DOMAINVALUES\0"))
+ generateException();
+
+ EXEC SQL CREATE INDEX RAS_DOMAINVALUESC_IX
+ ON RAS_DOMAINVALUES (DomainId);
+ if(check("DatabaseIf::create() CREATE INDEX RAS_DOMAINVALUESC_IX\0"))
+ generateException();
+
+ EXEC SQL CREATE UNIQUE INDEX RAS_DOMAINVALUES_IX
+ ON RAS_DOMAINVALUES (DomainId, DimensionCount);
+ if(check("DatabaseIf::create() CREATE UNIQUE INDEX RAS_DOMAINVALUES_IX\0"))
+ generateException();
+
+ // relmddif
+ EXEC SQL CREATE TABLE RAS_MDDCOLLECTIONS (
+ MDDId INTEGER NOT NULL,
+ MDDCollId INTEGER NOT NULL
+ );
+ if(check("DatabaseIf::create() CREATE TABLE RAS_MDDCOLLECTIONS\0"))
+ generateException();
+
+ EXEC SQL CREATE INDEX RAS_COLLECTIONSC_IX
+ ON RAS_MDDCOLLECTIONS (MDDCOllId);
+ if(check("DatabaseIf::create() CREATE INDEX RAS_COLLECTIONSC_IX\0"))
+ generateException();
+
+ EXEC SQL CREATE UNIQUE INDEX RAS_COLLECTIONS_IX
+ ON RAS_MDDCOLLECTIONS (MDDCOllId, MDDId);
+ if(check("DatabaseIf::create() CREATE UNIQUE INDEX RAS_COLLECTIONS_IX\0"))
+ generateException();
+
+ // referes to MDDSet
+ EXEC SQL CREATE TABLE RAS_MDDCOLLNAMES (
+ MDDCollId INTEGER NOT NULL,
+ SetTypeId INTEGER NOT NULL,
+ MDDCollName VARCHAR(254)
+ );
+ if(check("DatabaseIf::create() CREATE TABLE RAS_MDDCOLLNAMES\0"))
+ generateException();
+
+ EXEC SQL CREATE UNIQUE INDEX RAS_MDDCOLLNAMES_IX
+ ON RAS_MDDCOLLNAMES (MDDCollId);
+ if(check("DatabaseIf::create() CREATE UNIQUE INDEX RAS_MDDCOLLNAMES_IX\0"))
+ generateException();
+
+ EXEC SQL CREATE TABLE RAS_MDDOBJECTS (
+ MDDId INTEGER NOT NULL,
+ BaseTypeOId DEC(15,0) NOT NULL,
+ DomainId INTEGER NOT NULL,
+ PersRefCount INTEGER NOT NULL,
+ StorageOId DEC(15,0) NOT NULL,
+ NodeOId DEC(15,0)
+ );
+ if(check("DatabaseIf::create() CREATE TABLE RAS_MDDOBJECTS\0"))
+ generateException();
+
+ EXEC SQL CREATE UNIQUE INDEX RAS_MDDOBJECTS_IX
+ ON RAS_MDDOBJECTS (MDDId);
+ if(check("DatabaseIf::create() CREATE UNIQUE INDEX RAS_MDDOBJECTS_IX\0"))
+ generateException();
+
+ //relstorageif
+ EXEC SQL CREATE TABLE RAS_STORAGE (
+ StorageId INTEGER NOT NULL,
+ DomainId INTEGER,
+ TileSize INTEGER,
+ PCTMin INTEGER,
+ PCTMax INTEGER,
+ IndexSize INTEGER,
+ IndexType SMALLINT,
+ TilingScheme SMALLINT,
+ DataFormat SMALLINT
+ );
+ if(check("DatabaseIf::create() CREATE TABLE RAS_MDDOBJECTS\0"))
+ generateException();
+
+ EXEC SQL CREATE UNIQUE INDEX RAS_STORAGE_IX
+ ON RAS_STORAGE (StorageId);
+ if(check("DatabaseIf::create() CREATE UNIQUE INDEX RAS_STORAGE_IX\0"))
+ generateException();
+
+ // relindexif
+ // may not be needed
+ EXEC SQL CREATE TABLE RAS_HIERIX (
+ MDDObjIxOId DEC(15,0) NOT NULL,
+ NumEntries SMALLINT NOT NULL,
+ Dimension SMALLINT NOT NULL,
+ ParentOId DEC(15,0) NOT NULL,
+ IndexSubType SMALLINT NOT NULL,
+ DynData OID
+ );
+ if(check("DatabaseIf::create() CREATE TABLE RAS_HIERIX\0"))
+ generateException();
+
+ // Note: table RAS_HIERIXDYN is not needed, we put each index node into the above DynData blob
+
+ EXEC SQL CREATE TABLE RAS_UDFBODY (
+ UOId DEC(15,0) NOT NULL,
+ Name VARCHAR(254) NOT NULL,
+ Body CHAR(3700) NOT NULL
+ );
+ if(check("DatabaseIf::create() CREATE TABLE RAS_UDFBODY\0"))
+ generateException();
+
+ EXEC SQL CREATE UNIQUE INDEX RAS_UDFBODY_IX
+ ON RAS_UDFBODY (UOId);
+ if(check("DatabaseIf::create() CREATE UNIQUE INDEX RAS_UDFBODY_IX\0"))
+ generateException();
+
+ EXEC SQL CREATE TABLE RAS_UDFARGS (
+ UOId DEC(15,0) NOT NULL,
+ ArgNum SMALLINT NOT NULL,
+ ArgName VARCHAR(254) NOT NULL
+ );
+ if(check("DatabaseIf::create() CREATE TABLE RAS_UDFARGS\0"))
+ generateException();
+
+ EXEC SQL CREATE INDEX RAS_UDFARGSC_IX
+ ON RAS_UDFARGS(UOId);
+ if(check("DatabaseIf::create() CREATE INDEX RAS_UDFARGSC_IX\0"))
+ generateException();
+
+ EXEC SQL CREATE UNIQUE INDEX RAS_UDFARGS_IX
+ ON RAS_UDFARGS(UOId, ArgNum);
+ if(check("DatabaseIf::create() CREATE UNIQUE INDEX RAS_UDFARGS_IX\0"))
+ generateException();
+
+ EXEC SQL CREATE TABLE RAS_UDFPACKAGE (
+ UOId DEC(15,0) NOT NULL,
+ Name VARCHAR(254) NOT NULL
+ );
+ if(check("DatabaseIf::create() CREATE TABLE RAS_UDFPACKAGE\0"))
+ generateException();
+
+ EXEC SQL CREATE UNIQUE INDEX RAS_UDFPACKAGEN_IX
+ ON RAS_UDFPACKAGE (Name);
+ if(check("DatabaseIf::create() CREATE UNIQUE INDEX RAS_UDFPACKAGEN_IX\0"))
+ generateException();
+
+ EXEC SQL CREATE UNIQUE INDEX RAS_UDFPACKAGEO_IX
+ ON RAS_UDFPACKAGE (UOId);
+ if(check("DatabaseIf::create() CREATE UNIQUE INDEX RAS_UDFPACKAGEO_IX\0"))
+ generateException();
+
+ EXEC SQL CREATE TABLE RAS_UDFNSCONTENT (
+ UOId DEC(15,0) NOT NULL,
+ UDFOId DEC(15,0) NOT NULL
+ );
+ if(check("DatabaseIf::create() CREATE TABLE RAS_UDFNSCONTENT\0"))
+ generateException();
+
+ EXEC SQL CREATE INDEX RAS_UDFNSCONTENTC_IX
+ ON RAS_UDFNSCONTENT(UOId);
+ if(check("DatabaseIf::create() CREATE INDEX RAS_UDFNSCONTENTC_IX\0"))
+ generateException();
+
+ EXEC SQL CREATE UNIQUE INDEX RAS_UDFNSCONTENT_IX
+ ON RAS_UDFNSCONTENT(UOId, UDFOId);
+ if(check("DatabaseIf::create() CREATE UNIQUE INDEX RAS_UDFNSCONTENT_IX\0"))
+ generateException();
+
+ // We need 1 byte more because the first character may not be a \0 -> the first byte is always 13
+ // note: this does not hold for PG, but we keep it to remain cross-platform consistent in data
+ // note2: we use blob instead of varchar because the latter can hold only ascii data in PG
+ EXEC SQL CREATE TABLE RAS_RCINDEXDYN (
+ Id DEC(15,0) NOT NULL,
+ Count DEC(3,0) NOT NULL,
+ DynData oid
+ );
+ if(check("DatabaseIf::create() CREATE TABLE RAS_RCINDEXDYN\0"))
+ generateException();
+
+ EXEC SQL CREATE INDEX RAS_RCINDEXDYNC_IX
+ ON RAS_RCINDEXDYN (Id);
+ if(check("DatabaseIf::create() CREATE INDEX RAS_RCINDEXDYNC_IX\0"))
+ generateException();
+
+ EXEC SQL CREATE UNIQUE INDEX RAS_RCINDEXDYN_IX
+ ON RAS_RCINDEXDYN (Id, Count);
+ if(check("DatabaseIf::create() CREATE UNIQUE INDEX RAS_RCINDEXDYN_IX\0"))
+ generateException();
+
+ EXEC SQL CREATE VIEW RAS_MDDTYPES_VIEW
+ (MDDTypeOId, MDDTypeName)
+ AS
+ SELECT
+ MDDTypeOId * 512 + 3, MDDTypeName
+ FROM
+ RAS_MDDTYPES
+ UNION
+ SELECT
+ MDDBaseTypeOId * 512 + 4, MDDTypeName
+ FROM
+ RAS_MDDBASETYPES
+ UNION
+ SELECT
+ MDDDimTypeOId * 512 + 5, MDDTypeName
+ FROM
+ RAS_MDDDIMTYPES
+ UNION
+ SELECT
+ MDDDomTypeOId * 512 + 6, MDDTypeName
+ FROM
+ RAS_MDDDOMTYPES;
+ if(check("DatabaseIf::create() CREATE VIEW"))
+ generateException();
+
+ TALK( "EXEC SQL COMMIT WORK" );
+ EXEC SQL COMMIT WORK;
+ if(check("DatabaseIf::create() COMMIT WORK"))
+ generateException();
+
+ disconnect();
+ }
+ catch (r_Error& err)
+ {
+ // abort TA, ignore any error there
+ TALK( "EXEC SQL ABORT WORK;");
+ EXEC SQL ABORT WORK;
+
+ RMDBGMIDDLE(0, RMDebug::module_adminif, "DatabaseIf", "create(" << dbName << ", " << schemaName << ", " << volumeName << ") error caught " << err.what() << " " << err.get_errorno());
+ throw; // rethrow exception
+ }
+
+ LEAVE( "DatabaseIf::createDB, SQLCODE=" << SQLCODE );
+ RMDBGEXIT(4, RMDebug::module_adminif, "DatabaseIf", "create(" << dbName << ", " << schemaName << ", " << volumeName << ")");
+}
+
+void
+DatabaseIf::destroyDB(const char* dbName) throw(r_Error)
+{
+ RMDBGENTER(4, RMDebug::module_adminif, "DatabaseIf", "destroyDB(" << dbName << ")");
+ ENTER( "DatabaseIf::destroyDB, dbName=" << dbName );
+
+ if (AdminIf::getCurrentDatabaseIf() != 0)
+ {
+ RMDBGMIDDLE(5, RMDebug::module_adminif, "DatabaseIf", "another database is already open");
+ LEAVE( "Error: another database is already open" );
+ RMInit::logOut << "Another database is already open." << std::endl << "Cannot destroy database " << dbName << "." << std::endl;
+ throw r_Error(r_Error::r_Error_DatabaseOpen);
+ }
+ connect();
+
+/* this check is omitted, see databaseExists() comment
+ // terminate processing of database was not found -- PB 2003-sep-05
+ // try
+ // {
+ if (!databaseExists(dbName))
+ {
+ RMDBGMIDDLE(5, RMDebug::module_adminif, "DatabaseIf", "unknown database");
+ LEAVE( "Error: Database unknown" );
+ RMInit::logOut << "Database " << dbName << " not found." << std::endl << "Cannot destroy database " << dbName << "." << std::endl;
+ throw r_Error(r_Error::r_Error_DatabaseUnknown);
+ }
+ // }
+ // catch (r_Error& err)
+ // {
+ // RMInit::logOut << "Caught exception while trying to check for existence of database: " << err.what() << " " << err.get_errorno() << " " << err.get_kind() << endl;
+ // RMInit::logOut << "Continuing with destruction of the database" << endl;
+ // TALK( "Continuing destruction of the database after error " << err.get_errorno() << " " << err.get_kind() );
+ // }
+*/
+
+ EXEC SQL BEGIN WORK;
+ check("DatabaseIf::destroyDB() BEGIN WORK\0");
+
+ EXEC SQL DROP VIEW RAS_MDDTYPES_VIEW;
+ check("DatabaseIf::destroyDB() DROP VIEW RAS_MDDTYPES_VIEW\0");
+
+ // relblobif
+ EXEC SQL DROP TABLE RAS_TILES;
+ check("DatabaseIf::destroyDB() DROP TABLE RAS_TILES\0");
+
+ EXEC SQL DROP TABLE RAS_ITILES;
+ check("DatabaseIf::destroyDB() DROP TABLE RAS_ITILES\0");
+
+ // relcatalogif
+ EXEC SQL DROP TABLE RAS_MDDTYPES;
+ check("DatabaseIf::destroyDB() DROP TABLE RAS_MDDTYPES\0");
+
+ EXEC SQL DROP TABLE RAS_ITMAP;
+ check("DatabaseIf::destroyDB() DROP TABLE RAS_ITMAP\0");
+
+ EXEC SQL DROP TABLE RAS_MDDBASETYPES;
+ check("DatabaseIf::destroyDB() DROP TABLE RAS_MDDBASETYPES\0");
+
+ EXEC SQL DROP TABLE RAS_MDDDIMTYPES;
+ check("DatabaseIf::destroyDB() DROP TABLE RAS_MDDDIMENSIONTYPES\0");
+
+ EXEC SQL DROP TABLE RAS_MDDDOMTYPES;
+ check("DatabaseIf::destroyDB() DROP TABLE RAS_MDDDOMAINTYPES\0");
+
+ EXEC SQL DROP TABLE RAS_SETTYPES;
+ check("DatabaseIf::destroyDB() DROP TABLE RAS_SETTYPES\0");
+
+ EXEC SQL DROP TABLE RAS_BASETYPENAMES;
+ check("DatabaseIf::destroyDB() DROP TABLE RAS_BASETYPENAMES\0");
+
+ EXEC SQL DROP INDEX RAS_BASETYPES_IX;
+ check("DatabaseIf::destroyDB() DROP INDEX RAS_BASETYPES_IX\0");
+
+ EXEC SQL DROP TABLE RAS_BASETYPES;
+ check("DatabaseIf::destroyDB() DROP TABLE RAS_BASETYPES\0");
+
+ EXEC SQL DROP TABLE RAS_DOMAINS;
+ check("DatabaseIf::destroyDB() DROP TABLE RAS_DOMAINS\0");
+
+ EXEC SQL DROP TABLE RAS_DOMAINVALUES;
+ check("DatabaseIf::destroyDB() DROP TABLE RAS_DOMAINVALUES\0");
+
+ // relmddif
+ // referes to DBMDDCollOIdEntry
+ EXEC SQL DROP TABLE RAS_MDDCOLLECTIONS;
+ check("DatabaseIf::destroyDB() DROP TABLE RAS_MDDCOLLECTIONS\0");
+
+ // referes to MDDSet
+ EXEC SQL DROP TABLE RAS_MDDCOLLNAMES;
+ check("DatabaseIf::destroyDB() DROP TABLE RAS_MDDCOLLNAMES\0");
+
+ EXEC SQL DROP TABLE RAS_MDDOBJECTS;
+ check("DatabaseIf::destroyDB() DROP TABLE RAS_MDDOBJECTS\0");
+
+ // relindexif
+ // may not be needed
+ EXEC SQL DROP TABLE RAS_HIERIX;
+ check("DatabaseIf::destroyDB() DROP TABLE RAS_HIERIX\0");
+
+ EXEC SQL DROP INDEX RAS_HIERIXDYN_IX;
+ check("DatabaseIf::destroyDB() DROP INDEX RAS_HIERIXDYN_IX\0");
+
+ EXEC SQL DROP TABLE RAS_HIERIXDYN;
+ check("DatabaseIf::destroyDB() DROP TABLE RAS_HIERIXDYN\0");
+
+ EXEC SQL DROP TABLE RAS_STORAGE;
+ check("DatabaseIf::destroyDB() DROP TABLE RAS_STORAGE\0");
+
+ EXEC SQL DROP TABLE RAS_COUNTERS;
+ check("DatabaseIf::destroyDB() DROP TABLE RAS_COUNTERS\0");
+
+ EXEC SQL DROP TABLE RAS_UDFBODY;
+ check("DatabaseIf::destroyDB() DROP TABLE RAS_UDFBODY");
+
+ EXEC SQL DROP TABLE RAS_UDFARGS;
+ check("DatabaseIf::destroyDB() DROP TABLE RAS_UDFARGS");
+
+ EXEC SQL DROP TABLE RAS_UDFPACKAGE;
+ check("DatabaseIf::destroyDB() DROP TABLE RAS_UDFPACKAGE");
+
+ EXEC SQL DROP TABLE RAS_UDFNSCONTENT;
+ check("DatabaseIf::destroyDB() DROP TABLE RAS_UDFNSCONTENT");
+
+ EXEC SQL DROP INDEX RAS_RCINDEXDYN_IX;
+ check("DatabaseIf::destroyDB() DROP INDEX RAS_RCINDEXDYN_IX\0");
+
+ EXEC SQL DROP TABLE RAS_RCINDEXDYN;
+ check("DatabaseIf::destroyDB() DROP TABLE RAS_RCINDEXDYN\0");
+
+ EXEC SQL DROP TABLE RAS_ADMIN;
+ check("DatabaseIf::destroyDB() DROP TABLE RAS_ADMIN\0");
+
+ EXEC SQL COMMIT WORK;
+ check("DatabaseIf::destroyDB() COMMIT\0");
+
+ disconnect();
+
+ LEAVE( "DatabaseIf::destroyDB" );
+ RMDBGEXIT(4, RMDebug::module_adminif, "DatabaseIf", "destroyDB(" << dbName << ")");
+}
+
+/**
+This test is omitted because in PG it would fail the transaction,
+hence making continuation impossible.
+On the other hand, if the database really doesn't exist
+/ exists already (whatever is the erroneous situation)
+the transaction will fail for the very same reason.
+And here we can't decide what situation is good / not good!
+The only thing we lose is an appropriate error message
+on the top-level situation of the whole database.
+
+To make sure that no invocation of this function leads to erroneous results, we disable it.
+**/
+
+#if 0 // disable function to avoid invocation -- PB 2005-feb05
+bool
+DatabaseIf::databaseExists(const char* dbname) throw (r_Error)
+{
+ RMDBGENTER(4, RMDebug::module_adminif, "DatabaseIf", "databaseExists(" << dbname << ")");
+ ENTER( "DatabaseIf::databaseExists, dbName(ignored)=" << dbname );
+
+ EXEC SQL BEGIN DECLARE SECTION;
+ long nextoid;
+ short oidind;
+ char name1[255]; // must be large enough to hold counterNames, see oidif.cc
+ EXEC SQL END DECLARE SECTION;
+ bool retval = true;
+
+ (void) strncpy( name1, (char*) OId::counterNames[OId::DBMINTERVALOID], (size_t) sizeof(name1) );
+ TALK( "EXEC SQL SELECT NextValue INTO :nextoid FROM RAS_COUNTERS WHERE CounterName = " << name1 << ";" )
+ EXEC SQL SELECT NextValue INTO :nextoid
+ FROM RAS_COUNTERS
+ WHERE CounterName = :name1;
+ retval = (SQLCODE == SQLOK) ? true : false;
+
+ LEAVE( "DatabaseIf::databaseExists, SQLCODE=" << SQLCODE << ", retval=" << retval );
+ RMDBGEXIT(4, RMDebug::module_adminif, "DatabaseIf", "databaseExists(" << dbname << ") retval " << retval);
+
+ return retval;
+}
+#endif // 0
diff --git a/reladminif/databaseifcommon.cc b/reladminif/databaseifcommon.cc
new file mode 100644
index 0000000..b3e3097
--- /dev/null
+++ b/reladminif/databaseifcommon.cc
@@ -0,0 +1,242 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+// This is -*- C++ -*-
+/*************************************************************************
+ *
+ *
+ * PURPOSE:
+ * Contains all code that is shared by the database interface implementations
+ *
+ *
+ * COMMENTS:
+ * - schema version depending on release doesn't make sense; rather change
+ * it when the schema _really_ changes!
+ *
+ ***********************************************************************/
+
+
+#include <string.h>
+#include <malloc.h>
+
+#include "globals.hh" // DEFAULT_DBNAME
+
+#include "databaseif.hh"
+#include "adminif.hh"
+#include "raslib/rminit.hh"
+#include "raslib/rmdebug.hh"
+#include "externs.h"
+#include "sqlerror.hh"
+#include "raslib/error.hh"
+#include "relcatalogif/alltypes.hh"
+
+// defined in rasserver.cc
+extern char globalConnectId[256];
+
+const char* DatabaseIf::DefaultDatabaseName = DEFAULT_DBNAME;
+
+DatabaseIf::~DatabaseIf()
+{
+ RMDBGENTER(4, RMDebug::module_adminif, "DatabaseIf", "~DatabaseIf()");
+ if (isConnected())
+ {
+ baseDBMSClose();
+ }
+ if (myName)
+ {
+ free(myName);
+ myName = NULL;
+ }
+
+ connected = false;
+ opened = false;
+ RMDBGEXIT(4, RMDebug::module_adminif, "DatabaseIf", "~DatabaseIf()");
+}
+
+bool
+DatabaseIf::isConnected() const
+{
+ RMDBGONCE(4, RMDebug::module_adminif, "DatabaseIf", "isConnected() " << connected);
+ return connected;
+}
+
+bool
+DatabaseIf::isOpen() const
+{
+ RMDBGONCE(4, RMDebug::module_adminif, "DatabaseIf", "isOpen() " << opened);
+ return opened;
+}
+
+void
+DatabaseIf::open(const char* dbName) throw(r_Error)
+{
+ RMDBGENTER(4, RMDebug::module_adminif, "DatabaseIf", "open(" << dbName << ")");
+
+ if (opened)
+ {
+ RMDBGMIDDLE(4, RMDebug::module_adminif, "DatabaseIf", "another database is already open");
+ throw r_Error(r_Error::r_Error_DatabaseOpen);
+ }
+ else
+ {
+ //cannot do any further error checking
+ if ( 0 ) // we allow any other database name -- strcmp(dbName, DefaultDatabaseName))
+ {
+ RMDBGMIDDLE(4, RMDebug::module_adminif, "DatabaseIf", "database name unknown");
+ RMInit::logOut << "b_DatabaseIf::open(" << dbName << ") dbName=" << dbName << std::endl;
+ throw r_Error(r_Error::r_Error_DatabaseUnknown);
+ }
+ else
+ {
+ opened = true;
+ myName = strdup(dbName);
+ }
+ }
+ RMDBGEXIT(4, RMDebug::module_adminif, "DatabaseIf", "open(" << dbName << ")");
+}
+
+void
+DatabaseIf::baseDBMSOpen() throw (r_Error)
+{
+ RMDBGENTER(4, RMDebug::module_adminif, "DatabaseIf", "baseDBMSOpen() " << ((myName)? myName:"NULL"));
+ if (connected)
+ {
+ RMDBGMIDDLE(4, RMDebug::module_adminif, "DatabaseIf", "databasename is already connected");
+ throw r_Error(r_Error::r_Error_TransactionOpen);
+ }
+#ifdef RMANDEBUG
+ if (AdminIf::getCurrentDatabaseIf())
+ {
+ RMDBGMIDDLE(0, RMDebug::module_adminif, "DatabaseIf", "baseDBMSOpen() CurrentDatabaseIf != 0");
+ RMInit::logOut << "Transaction begin:" << std::endl \
+ << "There seems to be another database connection active (Internal State 1)." << std::endl \
+ << "Please contact Customer support." << std::endl;
+ throw r_Error(DATABASE_OPEN);
+ }
+#endif
+ AdminIf::setCurrentDatabaseIf(this);
+ connect();
+ connected = true;
+
+#ifdef DBMS_PGSQL // cannot have this check in PostgreSQL -- PB 2005-jan-09
+ if (!databaseExists(myName))
+ {
+ RMInit::logOut << "Database " << ((myName)? myName: "NULL") << " unknown" << std::endl;
+ throw r_Error(r_Error::r_Error_DatabaseUnknown);
+ }
+#endif // DBMS_PGSQL
+
+#ifndef FASTCONNECT
+ checkCompatibility();
+ if (!isConsistent())
+ {
+ RMInit::logOut << "Database " << ((myName)? myName: "NULL") << " inconsistent" << std::endl;
+ throw r_Error(DATABASE_INCONSISTENT);
+ }
+#endif
+ RMDBGEXIT(4, RMDebug::module_adminif, "DatabaseIf", "baseDBMSOpen()");
+}
+
+void
+DatabaseIf::close()
+{
+ RMDBGENTER(4, RMDebug::module_adminif, "DatabaseIf", "close()");
+ opened = false;
+ if (myName)
+ {
+ free(myName);
+ myName = NULL;
+ }
+ if (connected)
+ {
+ disconnect();
+ connected = false;
+ }
+ RMDBGEXIT(4, RMDebug::module_adminif, "DatabaseIf", "close()");
+}
+
+void
+DatabaseIf::baseDBMSClose()
+{
+ RMDBGENTER(4, RMDebug::module_adminif, "DatabaseIf", "baseDBMSClose()");
+#ifdef RMANDEBUG
+ if (AdminIf::getCurrentDatabaseIf() == this)
+ {
+#endif
+ AdminIf::setCurrentDatabaseIf(0);
+#ifdef RMANDEBUG
+ }
+ else
+ {
+ //this happens when a transaction is killed by the server
+ RMDBGONCE(0, RMDebug::module_adminif, "DatabaseIf", "baseDBMSClose() current DatabaseIf != this");
+ }
+#endif
+ disconnect();
+ connected = false;
+ RMDBGEXIT(4, RMDebug::module_adminif, "DatabaseIf", "baseDBMSClose()");
+}
+
+DatabaseIf::DatabaseIf()
+ : opened(false),
+ connected(false),
+ myName(NULL)
+{
+ RMDBGONCE(4, RMDebug::module_adminif, "DatabaseIf", "DatabaseIf()");
+}
+
+const char*
+DatabaseIf::getName() const
+{
+ RMDBGONCE(4, RMDebug::module_adminif, "DatabaseIf", "getName() " << ((myName)? myName:"NULL"));
+ return myName;
+}
+
+ostream&
+operator << (ostream& stream, DatabaseIf& db)
+{
+ stream << "DatabaseIf" << std::endl;
+ stream << "\tConnected To\t: " << ((db.getName())? db.getName():" ") << std::endl;
+ if (db.opened)
+ {
+ if (db.connected)
+ {
+ stream << "\tDatabase is really ONLINE" << std::endl;
+ }
+ else
+ {
+ stream << "\tDatabase is only FAKE ONLINE" << std::endl;
+ }
+ }
+ else
+ {
+ stream << "\tDatabase is OFFLINE" << std::endl;
+ }
+ return stream;
+}
+
+void
+DatabaseIf::garbage( )
+{
+ RMDBGONCE(0, RMDebug::module_adminif, "DatabaseIf", "garbage() NOT IMPLEMENTED");
+}
+
diff --git a/reladminif/dbnamedobject.cc b/reladminif/dbnamedobject.cc
new file mode 100644
index 0000000..1ad2472
--- /dev/null
+++ b/reladminif/dbnamedobject.cc
@@ -0,0 +1,179 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include "mymalloc/mymalloc.h"
+
+/*****************************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ *
+ * COMMENTS:
+ * uses embedded SQL
+ *
+ *****************************************************************************/
+
+#include <string.h>
+#include <stdlib.h>
+#include "dbnamedobject.hh"
+#include "dbobject.hh"
+#include "raslib/rmdebug.hh"
+
+// Beware: keep this value less or equal to STRING_MAXLEN in externs.h!
+#define MAXNAMELENGTH_CONST 200
+short DBNamedObject::MAXNAMELENGTH = MAXNAMELENGTH_CONST;
+
+const char* DBNamedObject::defaultName="unamed object\0";
+
+void
+DBNamedObject::printStatus(unsigned int level, std::ostream& stream) const
+{
+ DBObject::printStatus(level, stream);
+ stream << " Name: " << myName;
+}
+
+DBNamedObject::DBNamedObject(const OId& id) throw (r_Error)
+ : DBObject(id),
+ myName(NULL),
+ myNameSize(0)
+{
+ RMDBGONCE(9, RMDebug::module_adminif, "DBNamedObject", "DBNamedObject(" << myOId << ")");
+}
+
+DBNamedObject::DBNamedObject()
+ : DBObject(),
+ myNameSize(0),
+ myName(NULL)
+{
+ RMDBGONCE(9, RMDebug::module_adminif, "DBNamedObject", "DBNamedObject()");
+ setName(defaultName);
+}
+
+DBNamedObject::DBNamedObject(const DBNamedObject& old)
+ : DBObject(old),
+ myNameSize(0),
+ myName(NULL)
+{
+ RMDBGONCE(9, RMDebug::module_adminif, "DBNamedObject", "DBNamedObject(const DBNamedObject& old)");
+ setName(old.getName());
+}
+
+DBNamedObject::DBNamedObject(const char* name)
+ : DBObject(),
+ myNameSize(0),
+ myName(NULL)
+{
+ RMDBGONCE(9, RMDebug::module_adminif, "DBNamedObject", "DBNamedObject(" << name << ")");
+ setName(name);
+}
+
+DBNamedObject::DBNamedObject(const OId& id, const char* name)
+ : DBObject(id),
+ myNameSize(0),
+ myName(NULL)
+{
+ RMDBGONCE(9, RMDebug::module_adminif, "DBNamedObject", "DBNamedObject(" << myOId << ", " << name << ")");
+ setName(name);
+}
+
+DBNamedObject::~DBNamedObject()
+{
+ RMDBGENTER(9, RMDebug::module_adminif, "DBNamedObject", "~DBNamedObject() " << myOId);
+ if (myName)
+ {
+ free(myName);
+ myName = NULL;
+ }
+ myNameSize = 0;
+ RMDBGEXIT(9, RMDebug::module_adminif, "DBNamedObject", "~DBNamedObject() " << myOId);
+}
+
+DBNamedObject&
+DBNamedObject::operator=(const DBNamedObject& old)
+{
+ RMDBGONCE(9, RMDebug::module_adminif, "DBNamedObject", "operator=(" << old.getName() << ") " << myName);
+ if (this != &old)
+ {
+ DBObject::operator=(old);
+ setName(old.getName());
+ }
+ return *this;
+}
+
+const char*
+DBNamedObject::getName() const
+{
+ RMDBGONCE(9, RMDebug::module_adminif, "DBNamedObject", "getName() " << myName);
+ return myName;
+}
+
+void
+DBNamedObject::setName(const char* newname)
+{
+ RMDBGENTER(9, RMDebug::module_adminif, "DBNamedObject", "setName(" << newname << ")");
+ if (myName)
+ {
+ RMDBGMIDDLE(10, RMDebug::module_adminif, "DBNamedObject", "myName\t:" << myName);
+ free(myName);
+ myName=NULL;
+ }
+ int len = strlen(newname);
+ if (len > MAXNAMELENGTH)
+ len = MAXNAMELENGTH;
+ myName = (char*)mymalloc((len + 1) * sizeof(char));
+ myNameSize = (len + 1) * sizeof(char);
+ strncpy(myName, newname, len);
+ *(myName + len) = 0;
+ RMDBGEXIT(9, RMDebug::module_adminif, "DBNamedObject", "setName(" << myName << ")");
+}
+
+void
+DBNamedObject::setName(const short length, const char* data)
+{
+ RMDBGENTER(9, RMDebug::module_adminif, "DBNamedObject", "setName(" << length << ", data ) " << myOId);
+ if (myName)
+ {
+ RMDBGMIDDLE(10,RMDebug::module_adminif, "DBNamedObject", "myName\t:" << myName);
+ free(myName);
+ myName=NULL;
+ }
+ int len = 0;
+ if (length > MAXNAMELENGTH)
+ len = MAXNAMELENGTH;
+ else
+ len = length;
+ myName = (char*)mymalloc((len + 1) * sizeof(char));
+ myNameSize = (len + 1) * sizeof(char);
+ strncpy(myName, data, len);
+ *(myName + len) = 0;
+ RMDBGMIDDLE(10,RMDebug::module_adminif, "DBNamedObject", "myName\t:" << myName);
+ RMDBGEXIT(9, RMDebug::module_adminif, "DBNamedObject", "setName(" << length << ", data ) " << myOId);
+}
+
+r_Bytes
+DBNamedObject::getMemorySize() const
+{
+ return sizeof(char) * myNameSize + DBObject::getMemorySize() + sizeof(unsigned short);
+}
+
diff --git a/reladminif/dbnamedobject.hh b/reladminif/dbnamedobject.hh
new file mode 100644
index 0000000..654547c
--- /dev/null
+++ b/reladminif/dbnamedobject.hh
@@ -0,0 +1,121 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#ifndef _DBNAMEDOBJECT_HH_
+#define _DBNAMEDOBJECT_HH_
+
+class DBObject;
+class DBNamedObject;
+
+#include "dbobject.hh"
+
+//@ManMemo: Module: {\bf reladminif}.
+/*@Doc:
+Has functionality for setting the name of itsself from VARCHAR structures.
+Takes care of too long names.
+Implements set/getName functionality.
+*/
+
+class DBNamedObject : public DBObject
+ {
+ public:
+ DBNamedObject();
+ /*@Doc:
+ sets Name to defaultName
+ */
+
+ DBNamedObject(const OId& id) throw (r_Error);
+ /*@Doc:
+ only initializes itself
+ */
+
+ DBNamedObject(const DBNamedObject& old);
+ /*@Doc:
+ sets myName to the name of the old object
+ */
+
+ DBNamedObject(const char* name);
+ /*@Doc:
+ sets myName to name
+ */
+
+ DBNamedObject(const OId& id, const char* name);
+ /*@Doc:
+ sets myName to name and calls DBObject(OId). this is needed by MDDSet.
+ */
+
+ virtual ~DBNamedObject();
+ /*@Doc:
+ frees myName
+ */
+
+ const char* getName() const;
+ /*@Doc:
+ returns a pointer to myName.
+ */
+
+ static short MAXNAMELENGTH;
+ /*@Doc:
+ the maximum length of a name.
+ */
+
+ DBNamedObject& operator=(const DBNamedObject& old);
+ /*@Doc:
+ takes care of the name
+ */
+
+ virtual r_Bytes getMemorySize() const;
+ /*@Doc:
+ Should be revised not to include attribute sizes
+ */
+
+ virtual void printStatus(unsigned int level = 0, std::ostream& stream = std::cout) const;
+ /*@Doc:
+ prints the status of DBObject + Name: myName
+ */
+
+ protected:
+
+ void setName(const char* newname);
+ /*@Doc:
+ renames the object
+ */
+
+ void setName(const short length, const char* data);
+ /*@Doc:
+ sets the name from a VARCHAR structure
+ */
+
+ char* myName;
+ /*@Doc:
+ the name of the object
+ */
+
+ unsigned short myNameSize;
+ /*@Doc:
+ the size of the name
+ */
+
+ static const char* defaultName;
+ };
+
+#endif
diff --git a/reladminif/dbobject.cc b/reladminif/dbobject.cc
new file mode 100644
index 0000000..eabe794
--- /dev/null
+++ b/reladminif/dbobject.cc
@@ -0,0 +1,459 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************************
+ *
+ *
+ * PURPOSE:
+ * Code with embedded SQL for relational DBMS
+ *
+ *
+ * COMMENTS:
+ * none
+ *
+ ***********************************************************************/
+
+// mainly for ostringstream:
+#include <iostream>
+#include <string>
+#include <sstream>
+#include <fstream>
+#include <cstring>
+
+using namespace std;
+
+#include "objectbroker.hh"
+#include "dbobject.hh"
+#include "adminif.hh"
+#include "externs.h"
+#include "raslib/rmdebug.hh"
+#include "raslib/error.hh"
+#include "eoid.hh"
+
+#ifdef RMANBENCHMARK
+RMTimer DBObject::readTimer = RMTimer("DBObject","read");
+RMTimer DBObject::updateTimer = RMTimer("DBObject","update");
+RMTimer DBObject::insertTimer = RMTimer("DBObject","insert");
+RMTimer DBObject::deleteTimer = RMTimer("DBObject","delete");
+#endif
+
+const char*
+BinaryRepresentation::fileTag = "RMAN";
+
+void
+DBObject::printStatus(unsigned int level, std::ostream& stream) const
+ {
+ char* indent = new char[level*2 +1];
+ for (int j = 0; j < level*2 ; j++)
+ indent[j] = ' ';
+ indent[level*2] = '\0';
+
+ stream << indent;
+ stream << myOId;
+ delete[] indent;
+ indent=0;
+ }
+
+r_Bytes
+DBObject::getTotalStorageSize() const
+ {
+ return 0;
+ }
+
+r_Bytes
+DBObject::getMemorySize() const
+ {
+ return sizeof(DBObject);
+ }
+
+void
+DBObject::setCached(bool newCached)
+ {
+ RMDBGONCE(10, RMDebug::module_adminif, "DBObject", "setCached(" << (int)newCached << ") " << myOId);
+ _isCached = newCached;
+ }
+
+bool
+DBObject::isCached() const
+ {
+ RMDBGONCE(10, RMDebug::module_adminif, "DBObject", "isCached()" << (int) _isCached)
+ return _isCached;
+ }
+
+void
+DBObject::destroy()
+ {
+ RMDBGENTER(10, RMDebug::module_adminif, "DBObject", "destroy() " << myOId);
+#ifdef RMANDEBUG
+ OId tempid(myOId);
+#endif
+ if (referenceCount == 0)
+ {
+ if (!_isCached)
+ {
+ //exception may be possible when !isModified()
+ if (!AdminIf::isReadOnlyTA())
+ {
+ RMDBGMIDDLE(10, RMDebug::module_adminif, "DBObject", "deleting object " << myOId);
+ delete this;//is dynamic and may be deleted
+ }
+ else {
+ if (!_isPersistent)
+ {
+ RMDBGMIDDLE(10, RMDebug::module_adminif, "DBObject", "deleting object " << myOId);
+ //is dynamic and may be deleted
+ delete this;
+ }
+ }
+ }
+ }
+#ifdef RMANDEBUG
+ RMDBGEXIT(10, RMDebug::module_adminif, "DBObject", "destroy() " << tempid);
+#else
+ RMDBGEXIT(10, RMDebug::module_adminif, "DBObject", "destroy()");
+#endif
+ }
+
+void
+DBObject::release()
+ {
+ RMDBGONCE(10, RMDebug::module_adminif, "DBObject", "release() ");
+ //no dynamic memory
+ }
+
+void DBObject::incrementReferenceCount(void)
+ {
+ RMDBGONCE(10, RMDebug::module_adminif, "DBObject", "incrementReferenceCount() " << referenceCount);
+ referenceCount++;
+ }
+
+void DBObject::decrementReferenceCount(void)
+ {
+ RMDBGONCE(10, RMDebug::module_adminif, "DBObject", "decrementReferenceCount() " <<referenceCount);
+ referenceCount--;
+ if (referenceCount == 0)
+ destroy();
+ }
+
+int
+DBObject::getReferenceCount(void) const
+ {
+ RMDBGONCE(10, RMDebug::module_adminif, "DBObject", "getReferenceCount() " <<referenceCount);
+ return referenceCount;
+ }
+
+//public:
+DBObject::DBObject()
+ : _isInDatabase(false),
+ _isPersistent(false),
+ _isModified(true),
+ _isCached(false),
+ referenceCount(0),
+ objecttype(OId::INVALID),
+ myOId(0)
+ {
+ RMDBGONCE(10, RMDebug::module_adminif, "DBObject", "DBObject() " << myOId);
+ }
+
+DBObject::DBObject(const DBObject& old)
+ : _isInDatabase(old._isInDatabase),
+ _isPersistent(old._isPersistent),
+ _isModified(old._isModified),
+ _isCached(old._isCached),
+ referenceCount(old.referenceCount),
+ objecttype(old.objecttype),
+ myOId(old.myOId)
+ {
+ RMDBGONCE(10, RMDebug::module_adminif, "DBObject", "DBObject(const DBObject& old)" << myOId);
+ }
+
+//constructs an object and reads it from the database. the oid must match the type of the object.
+//a r_Error::r_Error_ObjectUnknown is thrown when the oid is not in the database.
+DBObject::DBObject(const OId& id) throw (r_Error)
+ : referenceCount(0),
+ _isCached(false),
+ myOId(id),
+ objecttype(id.getType())
+ {
+ //flags must be set by readFromDb()
+ RMDBGONCE(10, RMDebug::module_adminif, "DBObject", "DBObject(" << myOId << ")");
+ }
+
+DBObject&
+DBObject::operator=(const DBObject& old)
+ {
+ RMDBGONCE(10, RMDebug::module_adminif, "DBObject", "operator=(" << old.myOId << ")");
+ if (this != &old)
+ {
+ _isPersistent = old._isPersistent;
+ _isInDatabase = old._isInDatabase;
+ _isModified = old._isModified;
+ _isCached = old._isCached;
+ objecttype = old.objecttype;
+ myOId = old.myOId;
+ }
+ return *this;
+ }
+
+//setPersistent(true) makes the object persistent as soon as validate is called.
+//a r_Error::r_Error_TransactionReadOnly is thrown when the transaction is readonly.
+void
+DBObject::setPersistent(bool newPersistent) throw (r_Error)
+ {
+ RMDBGENTER(6, RMDebug::module_adminif, "DBObject", "setPersistent(" << (int)newPersistent << ") " << myOId);
+ if (newPersistent)
+ {//make object persistent
+ if (!_isPersistent)
+ {//object is not persistent
+ if (!AdminIf::isReadOnlyTA())
+ {//may be written to database
+ OId::allocateOId(myOId, objecttype);
+ _isPersistent = true;
+ _isModified = true;
+ ObjectBroker::registerDBObject(this);
+ RMDBGMIDDLE(6, RMDebug::module_adminif, "DBObject", "persistent\t: yes, was not persistent");
+ }
+ else {//read only transaction
+ RMDBGEXIT(6, RMDebug::module_adminif, "DBObject", "ReadOnlyTransaction");
+ RMInit::logOut << "DBObject::setPersistent() read only transaction" << endl;
+ throw r_Error(r_Error::r_Error_TransactionReadOnly);
+ }
+ }
+ else {//is already persitent
+ RMDBGMIDDLE(6, RMDebug::module_adminif, "DBObject", "persistent\t: yes, was already persistent");
+ }
+ }
+ else {//delete the object from database
+ if (_isPersistent)
+ {
+ if (!AdminIf::isReadOnlyTA())
+ {//may be deleted to database
+ RMDBGMIDDLE(6, RMDebug::module_adminif, "DBObject", "persistent\t: no, was persistent");
+ _isPersistent = false;
+ _isModified = true;
+ }
+ else {//read only transaction
+ RMDBGEXIT(6, RMDebug::module_adminif, "DBObject", "ReadOnlyTransaction");
+ RMInit::logOut << "DBObject::setPersistent() read only transaction" << endl;
+ throw r_Error(r_Error::r_Error_TransactionReadOnly);
+ }
+ }
+ else {
+ RMDBGMIDDLE(6, RMDebug::module_adminif, "DBObject", "persistent\t: no, was not persistent");
+ }
+ }
+ RMDBGEXIT(6, RMDebug::module_adminif, "DBObject", "setPersistent(" << (int)newPersistent << ") " << myOId);
+ }
+
+//tells if an object is persistent.
+bool
+DBObject::isPersistent() const
+ {
+ RMDBGONCE(6, RMDebug::module_adminif, "DBObject", "isPersistent()" << (int)_isPersistent);
+ return _isPersistent;
+ }
+
+//writes the object to database/deletes it or updates it.
+//a r_Error::r_Error_TransactionReadOnly is thrown when the transaction is readonly.
+void
+DBObject::validate() throw (r_Error)
+ {
+ RMDBGENTER(9, RMDebug::module_adminif, "DBObject", "validate() " << myOId);
+ if (_isModified)
+ {
+ if (!AdminIf::isReadOnlyTA())
+ {
+ if (!AdminIf::isAborted())
+ {
+ if (_isInDatabase)
+ {
+ if (_isPersistent)
+ {
+ RMDBGMIDDLE(11, RMDebug::module_adminif, "DBObject", "is persistent and modified and in database");
+#ifdef RMANBENCHMARK
+ updateTimer.resume();
+#endif
+ this->updateInDb();
+#ifdef RMANBENCHMARK
+ updateTimer.pause();
+#endif
+ }
+ else {
+ RMDBGMIDDLE(11, RMDebug::module_adminif, "DBObject", "is not persistent and in database");
+#ifdef RMANBENCHMARK
+ deleteTimer.resume();
+#endif
+ this->deleteFromDb();
+#ifdef RMANBENCHMARK
+ deleteTimer.pause();
+#endif
+ }
+ }
+ else {
+ if (_isPersistent)
+ {
+ RMDBGMIDDLE(11, RMDebug::module_adminif, "DBObject", "is persistent and modified and not in database");
+
+#ifdef RMANBENCHMARK
+ insertTimer.resume();
+#endif
+ this->insertInDb();
+#ifdef RMANBENCHMARK
+ insertTimer.pause();
+#endif
+ }
+ else {
+ //don´t do anything: not in db and not persistent
+ }
+ }
+ }
+ else {
+ //don´t do anything: is aborted
+ }
+ }
+ else {
+ //don´t do anything: is read only
+ }
+ }
+ else {
+ //don´t do anything: not modified
+ }
+ RMDBGEXIT(9, RMDebug::module_adminif, "DBObject", "validate() " << myOId);
+ }
+
+void
+DBObject::setModified() throw (r_Error)
+ {
+ RMDBGENTER(8, RMDebug::module_adminif, "DBObject", "setModified() " << myOId);
+ if (!AdminIf::isReadOnlyTA())
+ _isModified = true;
+ else {
+ RMDBGMIDDLE(5, RMDebug::module_adminif, "DBObject", "readonly transaction " << myOId);
+ //this happens really a lot.
+ //RMInit::logOut << "DBObject::setModified() read only transaction" << endl;
+ //throw r_Error(r_Error::r_Error_TransactionReadOnly);
+ _isModified = true;
+ }
+ RMDBGEXIT(8, RMDebug::module_adminif, "DBObject", "setModified() " << myOId);
+ }
+
+bool
+DBObject::isModified() const
+ {
+ RMDBGONCE(8, RMDebug::module_adminif, "DBObject", "isModified() " << (int)_isModified);
+ return _isModified;
+ }
+
+OId
+DBObject::getOId() const
+ {
+ RMDBGONCE(8, RMDebug::module_adminif, "DBObject", "getOId() " << myOId);
+ return myOId;
+ }
+
+EOId
+DBObject::getEOId() const
+ {
+ RMDBGONCE(8, RMDebug::module_adminif, "DBObject", "getEOId() " << myOId);
+ return EOId(myOId);
+ }
+
+OId::OIdType
+DBObject::getObjectType() const
+ {
+ RMDBGONCE(8, RMDebug::module_adminif, "DBObject", "getObjectType() " << objecttype);
+ return objecttype;
+ }
+
+DBObject::~DBObject()
+ {
+ RMDBGENTER(10, RMDebug::module_adminif, "DBObject", "~DBObject() " << myOId);
+ ObjectBroker::deregisterDBObject(myOId);
+ RMDBGEXIT(10, RMDebug::module_adminif, "DBObject", "~DBObject() " << myOId);
+ }
+
+void
+DBObject::updateInDb() throw (r_Error)
+ {
+ RMDBGENTER(10, RMDebug::module_adminif, "DBObject", "updateInDb() " << myOId);
+ _isModified = false;
+ _isInDatabase = true;
+ _isPersistent = true;
+ RMDBGEXIT(10, RMDebug::module_adminif, "DBObject", "updateInDb() " << myOId);
+ }
+
+//writes the object into the database. the object must not be in the database.
+void
+DBObject::insertInDb() throw (r_Error)
+ {
+ RMDBGENTER(10, RMDebug::module_adminif, "DBObject", "insertInDb() " << myOId);
+ _isModified = false;
+ _isInDatabase = true;
+ _isPersistent = true;
+ RMDBGEXIT(10, RMDebug::module_adminif, "DBObject", "insertInDb() " << myOId);
+ }
+
+void
+DBObject::deleteFromDb() throw (r_Error)
+ {
+ RMDBGENTER(10, RMDebug::module_adminif, "DBObject", "deleteFromDb() " << myOId);
+ _isModified = false;
+ _isInDatabase = false;
+ _isPersistent = false;
+ RMDBGEXIT(10, RMDebug::module_adminif, "DBObject", "deleteFromDb() " << myOId);
+ }
+
+void
+DBObject::readFromDb() throw (r_Error)
+ {
+ RMDBGENTER(10, RMDebug::module_adminif, "DBObject", "readFromDb() " << myOId);
+ _isPersistent = true;
+ _isModified = false;
+ _isInDatabase = true;
+ RMDBGEXIT(10, RMDebug::module_adminif, "DBObject", "readFromDb() " << myOId);
+ }
+
+BinaryRepresentation
+DBObject::getBinaryRepresentation() const throw (r_Error)
+ {
+ RMInit::logOut << "getBinaryRepresentation() for " << objecttype << " not implemented" << endl;
+ throw r_Error(BINARYEXPORTNOTSUPPORTEDFOROBJECT);
+ }
+
+void
+DBObject::setBinaryRepresentation(const BinaryRepresentation& br) throw (r_Error)
+ {
+ RMInit::logOut << "setBinaryRepresentation() for " << objecttype << " not implemented" << endl;
+ throw r_Error(BINARYIMPORTNOTSUPPORTEDFOROBJECT);
+ }
+
+char*
+DBObject::getBinaryName() const
+ {
+ //if we use 64bit oids we have at most 20 digits + "_" + type
+ ostringstream o;
+ o << (int)objecttype << '_' << myOId.getCounter() << ".raw";
+ const char* temp = o.str().c_str();
+ char* retval = new char[strlen(temp) + 1];
+ memcpy(retval, temp, strlen(temp) + 1);
+ return retval;
+ }
diff --git a/reladminif/dbobject.hh b/reladminif/dbobject.hh
new file mode 100644
index 0000000..80e3360
--- /dev/null
+++ b/reladminif/dbobject.hh
@@ -0,0 +1,291 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#ifndef _DBOBJECT_HH_
+#define _DBOBJECT_HH_
+
+class DBObject;
+class EOId;
+
+template <class T> class DBRef;
+
+#include <iosfwd>
+
+#include "oidif.hh"
+#include "raslib/mddtypes.hh"
+#include "raslib/error.hh"
+#include "binaryrepresentation.hh"
+
+#ifdef RMANBENCHMARK
+#include "raslib/rmdebug.hh"
+#endif
+
+typedef DBRef<DBObject> DBObjectId;
+
+//@ManMemo: Module: {\bf reladminif}.
+/*@Doc:
+Base class for all persistent classes. it supplies functionality for reference counting,
+management by ObjectBroker, modification management, cache size.
+
+a persistent DBObject has a unique OId. this oid identifies it in the database.
+*/
+
+class DBObject
+ {
+ public:
+ virtual void destroy(void);
+ /*@Doc:
+ deletes the object if and only if
+ the refence count is zero and
+ the object is not cached and
+ the transaction is not readonly.
+ */
+
+ int getReferenceCount(void) const;
+ /*@Doc:
+ Returns the number of references that exist for this object
+ */
+
+ void incrementReferenceCount(void);
+ /*@Doc:
+ Reference counting functions. These should be private with friend DBRef, but the compiler
+ doesn't allow friend template classes, only instances. Don't call directly, only DBRef
+ is allowed to.
+ */
+
+ void decrementReferenceCount(void);
+ /*@Doc:
+ Reference counting functions. These should be private with friend DBRef, but the compiler
+ doesn't allow friend template classes, only instances. Don't call directly, only DBRef
+ is allowed to.
+ */
+
+ virtual ~DBObject();
+ /*@Doc:
+ deregisters this object with the ObjectBroker.
+ the oid is not invalidated to allow the ObjectBroker to kill it.
+ */
+
+ DBObject();
+ /*@Doc:
+ initializes all attributes. the oid is set to 0. the objecttype is set to OId::INVALID.
+ */
+
+ DBObject(const DBObject& old);
+ /*@Doc:
+ clones all attributes.
+ */
+
+ DBObject(const OId& id) throw (r_Error);
+ /*@Doc:
+ initializes only referenceCount, myOId, objecttype. _isCached is set to 0.
+ Subclasses may contain a call to readFromDb which can throw a r_Error_ObjectUnknown
+ or database related exception.
+ */
+
+ virtual void setPersistent(bool newPersistent) throw (r_Error);
+ /*@Doc:
+ setPersistent(true) makes the object persistent as soon as validate is called.
+ a r_Error_TransactionReadOnly is thrown when the transaction is readonly.
+ setPersistent(false) deletes the object from the database as soon as validate is called.
+ if the state of the object changes in a read only transaction
+ (e.g. persistent->non persistent) a r_Error_TransactionReadOnly is thrown.
+ */
+
+ bool isPersistent() const;
+ /*@Doc:
+ tells if an object is persistent.
+ */
+
+ void validate() throw (r_Error);
+ /*@Doc:
+ writes the object to database/deletes it or updates it.
+ any r_Errors from insertInDb, updateInDb, deleteFromDb, readFromDb are passed to the
+ caller.
+ */
+
+ virtual void setModified() throw (r_Error);
+ /*@Doc:
+ marks this object dirty.
+ a r_Error_TransactionReadOnly should be thrown when the transaction is readonly.
+ this is because of o2 related stuff in dbmddobject. should be taken care of.
+ */
+
+ bool isModified() const;
+ /*@Doc:
+ tells if this object is dirty.
+ */
+
+ OId getOId() const;
+ /*@Doc:
+ returns the oid of this object
+ */
+
+ EOId getEOId() const;
+ /*@Doc:
+ returns the EOId of this object.
+ */
+
+ OId::OIdType getObjectType() const;
+ /*@Doc:
+ returns the type of this object (MDDSet, ...). objects which are not
+ yet persistent also return their object type.
+ */
+
+ DBObject& operator=(const DBObject& old);
+ /*@Doc:
+ clones all DBObject attributes except reference count.
+ */
+
+ bool isCached() const;
+ /*@Doc:
+ tells if this object is cached.
+ */
+
+ virtual void setCached(bool newCached);
+ /*@Doc:
+
+ */
+
+ virtual r_Bytes getMemorySize() const;
+ /*@Doc:
+ returns the memory space used by this object.
+ */
+
+ virtual void printStatus(unsigned int level = 0, std::ostream& stream = std::cout) const;
+ /*@Doc:
+ prints the indent, OIdType, myOId as long and myOId as double.
+ */
+
+ virtual r_Bytes getTotalStorageSize() const;
+ /*@Doc:
+ returns the space taken up by this object in the database.
+ as dbobject has no persistent attributes it returns 0.
+ */
+
+ virtual BinaryRepresentation getBinaryRepresentation() const throw (r_Error);
+ /*@Doc:
+ returns the binary representation fit for storage in the database
+ */
+
+ virtual void setBinaryRepresentation(const BinaryRepresentation&) throw (r_Error);
+ /*@Doc:
+ set the objects state from the binary represenation
+ */
+
+ virtual char* getBinaryName() const;
+ /*Doc:
+ create the name for binary represenation from the oid
+ */
+
+#ifdef RMANBENCHMARK
+ static RMTimer readTimer;
+
+ static RMTimer updateTimer;
+
+ static RMTimer insertTimer;
+
+ static RMTimer deleteTimer;
+#endif
+
+ protected:
+ virtual void release();
+ /*@Doc:
+ releases all dynamic memory (references to other persistent obkjects).
+ this is needed for cross transactional caches.
+ dbobject does not have any dynamic memory.
+ */
+
+ virtual void readFromDb() throw (r_Error);
+ /*@Doc:
+ reads the object from database. myOId must be set!!!
+ a r_Error_ObjectUnknown is thrown when the oid is not in the database.
+ */
+
+ virtual void insertInDb() throw (r_Error);
+ /*@Doc:
+ writes the object into the database. the object must not be in the database.
+ a r_Error_TransactionReadOnly is thrown when the transaction is readonly.
+ this implementation checks for readOnlyTA
+ */
+
+ virtual void deleteFromDb() throw (r_Error);
+ /*@Doc:
+ deletes an object in the database.
+ a r_Error_TransactionReadOnly is thrown when the transaction is readonly.
+ this implementation checks for readOnlyTA
+ */
+
+ virtual void updateInDb() throw (r_Error);
+ /*@Doc:
+ updates an existing object in the database
+ a r_Error_TransactionReadOnly is thrown when the transaction is readonly.
+ this implementation checks for readOnlyTA
+ */
+
+ bool _isPersistent;
+ /*@Doc:
+ tells, if this object should be in the database or not.
+ */
+
+ bool _isInDatabase;
+ /*@Doc:
+ tells, if this object is already in the database.
+ */
+
+ bool _isModified;
+ /*@Doc:
+ tells, if this object has changed an should be updated in the database.
+ */
+
+ bool _isCached;
+ /*@Doc:
+ tells , if this objects is cached or not
+ */
+
+ OId myOId;
+ /*@Doc:
+ the oid of this object. is set by setPersistent(1) or by the constructor
+ of optional persistent objects (types).
+ */
+
+ OId::OIdType objecttype;
+ /*@Doc:
+ the type of this object. needed by setPersistent(1) to allocate the correct oid.
+ */
+
+ int referenceCount;
+ /*@Doc:
+ The number of references that exist for this file. Use get_reference() for reading
+ its value from derived classes. Modified by incr_reference and decr_reference.
+ */
+
+ private:
+
+ void sharedObjectInit(void);
+ /*@Doc:
+ Initialization code shared by all constructors.
+ does not do anything.
+ */
+ };
+
+#endif
diff --git a/reladminif/dbobjectiditerator.cc b/reladminif/dbobjectiditerator.cc
new file mode 100644
index 0000000..17889be
--- /dev/null
+++ b/reladminif/dbobjectiditerator.cc
@@ -0,0 +1,103 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include "dbobjectiditerator.hh"
+#include "objectbroker.hh"
+#include "dbref.hh"
+#include "raslib/rmdebug.hh"
+
+template<class T>
+DBObjectIdIterator<T>::DBObjectIdIterator(const DBObjectIdIterator<T>& oidlist)
+ : mySet(NULL),
+ counter(0)
+ {
+ RMDBGONCE(7, RMDebug::module_adminif, "DBObjectIdIterator", "DBObjectIdIterator(const DBObjectIdIterator<T>&)");
+ mySet = oidlist.mySet;
+ myIter = mySet->begin();
+ }
+
+template<class T>
+DBObjectIdIterator<T>::DBObjectIdIterator(const std::set<DBRef<T>, std::less<DBRef<T> > >& oidlist)
+ : mySet(NULL),
+ counter(0)
+ {
+ RMDBGONCE(7, RMDebug::module_adminif, "DBObjectIdIterator", "DBObjectIdIterator(OIdSet)");
+ mySet = (std::set<DBRef<T>, std::less<DBRef<T> > >*)&oidlist;
+ myIter = mySet->begin();
+ }
+
+template<class T> void
+DBObjectIdIterator<T>::reset()
+ {
+ RMDBGONCE(7, RMDebug::module_adminif, "DBObjectIdIterator","reset()");
+ myIter = mySet->begin();
+ counter = 0;
+ }
+
+template<class T> bool
+DBObjectIdIterator<T>::not_done() const
+ {
+ RMDBGENTER(7, RMDebug::module_adminif, "DBObjectIdIterator","not_done()");
+ bool retval = false;
+ if (myIter == mySet->end())
+ {
+ retval = false;
+ }
+ else {
+ if (mySet->empty())
+ {
+ retval = false;
+ }
+ else {
+ if (counter == mySet->size())
+ retval = false;
+ else
+ retval = true;
+ }
+ }
+ RMDBGEXIT(7, RMDebug::module_adminif, "DBObjectIdIterator","not_done() " << retval);
+ return retval;
+ }
+
+template<class T> void
+DBObjectIdIterator<T>::advance()
+ {
+ RMDBGONCE(7, RMDebug::module_adminif, "DBObjectIdIterator","advance() " << counter);
+ myIter++;
+ counter++;
+ }
+
+template<class T> DBRef<T>
+DBObjectIdIterator<T>::get_element() const
+ {
+ RMDBGONCE(7, RMDebug::module_adminif, "DBObjectIdIterator", "get_element() " << (*myIter).getOId());
+ return (*myIter);
+ }
+
+template<class T>
+DBObjectIdIterator<T>::~DBObjectIdIterator()
+ {
+ RMDBGONCE(7, RMDebug::module_adminif, "DBObjectIdIterator", "~DBObjectIdIterator()");
+ mySet = NULL;
+ counter = 0;
+ }
+
diff --git a/reladminif/dbobjectiditerator.hh b/reladminif/dbobjectiditerator.hh
new file mode 100644
index 0000000..bb6ba78
--- /dev/null
+++ b/reladminif/dbobjectiditerator.hh
@@ -0,0 +1,108 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*
+ * 2007-may-10 CJ fixed compilation errors (gcc 4.1)
+*/
+
+#ifndef _DBOBJECtIdIterATOR_HH_
+#define _DBOBJECtIdIterATOR_HH_
+
+template <class T> class DBObjectIdIterator;
+template <class T> class DBRef;
+class ObjectBroker;
+
+#include "lists.h"
+//@ManMemo: Module: {\bf reladminif}.
+/*@Doc:
+
+this object gets a set of oids. when an oid is accessed the iterator returns a DBRef to the oid.
+
+*/
+
+
+template<class T>
+class DBObjectIdIterator
+ {
+ public:
+ DBObjectIdIterator(const std::set<DBRef<T>, std::less<DBRef<T> > >& oidlist);
+ /*@Doc:
+ constructs a new Iterator. the OIdSet will be deleted by the DBOBjectIdIterator.
+ there may be oids of objects with other classes present. you should be carefull
+ when using this feature - as in mddtypes/mddbasetypes/mdddim/domtypes
+ */
+
+ DBObjectIdIterator(const DBObjectIdIterator<T>& it);
+ /*@Doc:
+ */
+
+ ~DBObjectIdIterator();
+ /*@Doc:
+ deletes the OIdSet passed to it in the constructor
+ */
+
+ void reset();
+ /*@Doc:
+ resets the iterator to the beginning
+ */
+
+ bool not_done() const;
+ /*@Doc:
+ checks if there are more elements
+ */
+
+ void advance();
+ /*@Doc:
+ advances the iterator one entry
+ */
+
+ DBRef<T> get_element() const;
+ /*@Doc:
+ returns an dbref<object>
+ */
+
+ private:
+ typename std::set<DBRef<T>, std::less<DBRef<T> > >::iterator myIter;
+ /*@Doc:
+ internal pointer where the iterator is
+ */
+
+ std::set<DBRef<T>, std::less<DBRef<T> > >* mySet;
+ /*@Doc:
+ the actual list which is used to lookup objects by the objectbroker
+ */
+
+ unsigned int counter;
+ /*@Doc:
+ holds the actual position in set
+ */
+ };
+
+#ifdef EARLY_TEMPLATE
+#ifdef __EXECUTABLE__
+#include "dbobjectiditerator.cc"
+#endif
+#endif
+
+#endif
+
+
diff --git a/reladminif/dbobjectiterator.cc b/reladminif/dbobjectiterator.cc
new file mode 100644
index 0000000..69517b5
--- /dev/null
+++ b/reladminif/dbobjectiterator.cc
@@ -0,0 +1,104 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include "dbobjectiterator.hh"
+#include "objectbroker.hh"
+#include "dbref.hh"
+#include "raslib/rmdebug.hh"
+
+template<class T>
+DBObjectIterator<T>::DBObjectIterator(const DBObjectIterator<T>& oidlist)
+ : mySet(NULL),
+ counter(0)
+ {
+ RMDBGONCE(7, RMDebug::module_adminif, "DBObjectIterator", "DBObjectIterator(const DBObjectIterator<T>&)");
+ mySet = new OIdSet(*(oidlist.mySet));
+ myIter = mySet->begin();
+ }
+
+template<class T>
+DBObjectIterator<T>::DBObjectIterator(const OIdSet& oidlist)
+ : mySet(NULL),
+ counter(0)
+ {
+ RMDBGONCE(7, RMDebug::module_adminif, "DBObjectIterator", "DBObjectIterator(OIdSet)");
+ mySet = new OIdSet(oidlist);
+ myIter = mySet->begin();
+ }
+
+template<class T> void
+DBObjectIterator<T>::reset()
+ {
+ RMDBGONCE(7, RMDebug::module_adminif, "DBObjectIterator","reset()");
+ myIter = mySet->begin();
+ counter = 0;
+ }
+
+template<class T> bool
+DBObjectIterator<T>::not_done() const
+ {
+ RMDBGENTER(7, RMDebug::module_adminif, "DBObjectIterator","not_done()");
+ bool retval = false;
+ if (myIter == mySet->end())
+ {
+ retval = false;
+ }
+ else {
+ if (mySet->empty())
+ {
+ retval = false;
+ }
+ else {
+ if (counter == mySet->size())
+ retval = false;
+ else
+ retval = true;
+ }
+ }
+ RMDBGEXIT(7, RMDebug::module_adminif, "DBObjectIterator","not_done() " << retval);
+ return retval;
+ }
+
+template<class T> void
+DBObjectIterator<T>::advance()
+ {
+ RMDBGONCE(7, RMDebug::module_adminif, "DBObjectIterator","advance() " << counter);
+ myIter++;
+ counter++;
+ }
+
+template<class T> DBRef<T>
+DBObjectIterator<T>::get_element() const
+ {
+ RMDBGONCE(7, RMDebug::module_adminif, "DBObjectIterator", "get_element() " << *myIter << " " << (*myIter).getType());
+ return DBRef<T>(*myIter);
+ }
+
+template<class T>
+DBObjectIterator<T>::~DBObjectIterator()
+ {
+ RMDBGONCE(7, RMDebug::module_adminif, "DBObjectIterator", "~DBObjectIterator()");
+ delete mySet;
+ mySet = NULL;
+ counter = 0;
+ }
+
diff --git a/reladminif/dbobjectiterator.hh b/reladminif/dbobjectiterator.hh
new file mode 100644
index 0000000..4f04370
--- /dev/null
+++ b/reladminif/dbobjectiterator.hh
@@ -0,0 +1,104 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#ifndef _DBOBJECTITERATOR_HH_
+#define _DBOBJECTITERATOR_HH_
+
+template <class T> class DBObjectIterator;
+template <class T> class DBRef;
+class ObjectBroker;
+
+#include "lists.h"
+//@ManMemo: Module: {\bf reladminif}.
+/*@Doc:
+
+this object gets a set of oids. when an oid is accessed the iterator returns a DBRef to the oid.
+
+*/
+
+
+template<class T>
+class DBObjectIterator
+ {
+ public:
+ DBObjectIterator(const OIdSet& oidlist);
+ /*@Doc:
+ constructs a new Iterator. the OIdSet will be deleted by the DBOBjectIterator.
+ there may be oids of objects with other classes present. you should be carefull
+ when using this feature - as in mddtypes/mddbasetypes/mdddim/domtypes
+ */
+
+ DBObjectIterator(const DBObjectIterator<T>& it);
+ /*@Doc:
+ */
+
+ ~DBObjectIterator();
+ /*@Doc:
+ deletes the OIdSet passed to it in the constructor
+ */
+
+ void reset();
+ /*@Doc:
+ resets the iterator to the beginning
+ */
+
+ bool not_done() const;
+ /*@Doc:
+ checks if there are more elements
+ */
+
+ void advance();
+ /*@Doc:
+ advances the iterator one entry
+ */
+
+ DBRef<T> get_element() const;
+ /*@Doc:
+ returns an dbref<object>
+ */
+
+ private:
+ OIdSet::iterator myIter;
+ /*@Doc:
+ internal pointer where the iterator is
+ */
+
+ OIdSet* mySet;
+ /*@Doc:
+ the actual list which is used to lookup objects by the objectbroker
+ */
+
+ unsigned int counter;
+ /*@Doc:
+ holds the actual position in set
+ */
+ };
+
+#ifdef EARLY_TEMPLATE
+#ifdef __EXECUTABLE__
+#include "dbobjectiterator.cc"
+#endif
+#endif
+
+#endif
+
+
diff --git a/reladminif/dbref.cc b/reladminif/dbref.cc
new file mode 100644
index 0000000..1012371
--- /dev/null
+++ b/reladminif/dbref.cc
@@ -0,0 +1,874 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * DBRef is a smart pointer for managing objects derived from
+ * the DbObject class.
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+
+#include "dbref.hh"
+#include <iostream>
+#include <stdio.h>
+#include "raslib/rmdebug.hh"
+#include "objectbroker.hh"
+#include "indexmgr/indexds.hh"
+#include "relindexif/dbrcindexds.hh"
+#include "relindexif/dbtcindex.hh"
+#include "indexmgr/hierindexds.hh"
+#include "debug/debug.hh"
+
+template <class T> bool
+DBRef<T>::pointerCaching = true;
+
+/*for testing
+bool
+DBRef<BLOBTile>::pointerCaching = false;
+
+bool
+DBRef<InlineTile>::pointerCaching = false;
+
+bool
+DBRef<DBTile>::pointerCaching = false;
+*/
+
+template <class T> void
+DBRef<T>::setPointerCaching(bool useIt)
+ {
+ RMDBGONCE(10, RMDebug::module_adminif, "DBRef", "setPointerCaching(" << useIt << ") " << pointerCaching );
+ pointerCaching = useIt;
+ }
+
+template <class T> bool
+DBRef<T>::getPointerCaching()
+ {
+ RMDBGONCE(10, RMDebug::module_adminif, "DBRef", "getPointerCaching() " << pointerCaching );
+ return pointerCaching;
+ }
+
+template <class T>
+DBRef<T>::DBRef(void)
+ : object(0),
+ objId(DBOBJID_NONE),
+ pointerValid(false)
+ {
+ RMDBGONCE(11, RMDebug::module_adminif, "DBRef", "DBRef()");
+ }
+
+
+template <class T>
+DBRef<T>::DBRef(const OId &id)
+ : object(0),
+ pointerValid(false),
+ objId(id)
+ {
+ RMDBGONCE(11, RMDebug::module_adminif, "DBRef", "DBRef(" << id << ")");
+ }
+
+
+template <class T>
+DBRef<T>::DBRef(double id)
+ : object(0),
+ pointerValid(false),
+ objId(id)
+ {
+ RMDBGONCE(11, RMDebug::module_adminif, "DBRef", "DBRef(double " << id << ")");
+ }
+
+
+template <class T>
+DBRef<T>::DBRef(const DBRef<T> &src)
+ : object(0),
+ pointerValid(src.pointerValid),
+ objId(src.objId)
+ {
+ RMDBGENTER(11, RMDebug::module_adminif, "DBRef", "DBRef(const DBRef) src.OId=" << src.objId);
+ if (pointerCaching)
+ {
+ if (src.object)
+ {
+ object = src.object;
+ objId = object->getOId();
+ object->incrementReferenceCount();
+ }
+ }
+ else {
+ if (pointerValid && src.object)
+ {
+ object = src.object;
+ }
+ }
+
+ RMDBGEXIT(11, RMDebug::module_adminif, "DBRef", "DBRef(const DBRef) " << objId);
+ }
+
+
+template <class T>
+DBRef<T>::DBRef(T *ptr)
+ : object(ptr),
+ pointerValid(true),
+ objId(DBOBJID_NONE)
+ {
+ RMDBGENTER(11, RMDebug::module_adminif, "DBRef", "DBRef(const T* " << ptr << ")");
+
+ if (object != 0)
+ {
+ objId = object->getOId();
+ object->incrementReferenceCount();
+ RMDBGMIDDLE(11, RMDebug::module_adminif, "DBRef", "DBRef(T* " << ptr->getOId() << ")");
+ }
+ else {
+ pointerValid = false;
+ RMDBGMIDDLE(11, RMDebug::module_adminif, "DBRef", "DBRef(T* 0) " << objId);
+ }
+ }
+
+
+template <class T>
+DBRef<T>::~DBRef(void)
+ {
+ RMDBGENTER(11, RMDebug::module_adminif, "DBRef", "~DBRef() " << objId);
+ if ((object != 0) && pointerCaching)
+ object->decrementReferenceCount();
+ object = 0;
+ RMDBGEXIT(11, RMDebug::module_adminif, "DBRef", "~DBRef() " << objId);
+ }
+
+template <class T>
+bool DBRef<T>::operator<(const DBRef<T>& other) const
+ {
+ RMDBGENTER(3, RMDebug::module_adminif, "DBRef", "DBRef<T>::operator<(" << other.objId << ", " << (r_Ptr)other.object << ") " << objId << ", " << (r_Ptr)object);
+ int ret = operator==(other);
+ return (ret == -1);
+ }
+
+template <class T>
+bool operator< (const DBRef<T> &me, const DBRef<T> &him)
+ {
+ RMDBGENTER(3, RMDebug::module_adminif, "DBRef", "operator<({" << me.getOId() << "}, {" << him.getOId() << "})");
+ return me.operator<(him);
+ }
+
+template <class T>
+int DBRef<T>::operator==(const DBRef<T> &src) const
+ {
+ RMDBGENTER(3, RMDebug::module_adminif, "DBRef", "operator==(" << src.objId << ", " << (r_Ptr)src.object << ") " << objId << ", " << (r_Ptr)object);
+ int retval = 0;
+ if (isInitialised())
+ {
+ if (src.isInitialised())
+ {
+ if (object)
+ {
+ if (object->isPersistent())
+ {//this persistent
+ if (src.object)
+ {
+ if (src.object->isPersistent())
+ {
+ if (object->getOId() < src.object->getOId())
+ retval = -1;
+ else
+ if (object->getOId() > src.object->getOId())
+ retval = +1;
+ //else == -> 0
+ }
+ else {//src is transient
+ retval = +1;
+ }
+ }
+ else {//src is persistent
+ if (object->getOId() < src.objId)
+ {
+ retval = -1;
+ }
+ else {
+ if (object->getOId() > src.objId)
+ retval = +1;
+ //else == -> 0
+ }
+ }
+ }
+ else {//this transient
+ if (src.object)
+ {
+ if (src.object->isPersistent())
+ {
+ retval = -1;
+ }
+ else {//src is transient
+ if (object < src.object)
+ retval = -1;
+ else
+ if (object > src.object)
+ retval = +1;
+ //else == -> 0
+ }
+ }
+ else {//src is persistent
+ retval = -1;
+ }
+ }
+ }
+ else {//this is persistent
+ if (src.object)
+ {
+ if (src.object->isPersistent())
+ {
+ if (objId < src.object->getOId())
+ {
+ retval = -1;
+ }
+ else {
+ if (objId > src.object->getOId())
+ retval = +1;
+ //else == -> 0
+ }
+
+ }
+ else {//src not persistent
+ retval = +1;
+ }
+ }
+ else {//src is persistent
+ if (objId < src.objId)
+ {
+ retval = -1;
+ }
+ else {
+ if (objId > src.objId)
+ retval = +1;
+ //else == -> 0
+ }
+ }
+ }
+ }
+ else {
+ retval = +1;
+ }
+ }
+ else {
+ if (src.isInitialised())
+ {
+ retval = -1;
+ }
+ //else is 0
+ }
+ RMDBGEXIT(11, RMDebug::module_adminif, "DBRef", "operator==(" << src.objId << ") " << retval);
+ return retval;
+ }
+
+
+template <class T>
+DBRef<T> &DBRef<T>::operator=(const DBRef<T> &src)
+ {
+ RMDBGENTER(11, RMDebug::module_adminif, "DBRef", "operator=(" << src.objId << ") " << objId);
+ if ((object != 0) && pointerCaching)
+ {
+ object->decrementReferenceCount();
+ }
+ object = src.object;
+ pointerValid = src.pointerValid;
+ objId = src.objId;
+ if (pointerCaching)
+ {
+ if (object)
+ {
+ objId = object->getOId();
+ object->incrementReferenceCount();
+ }
+ }
+ else {
+ if (object && pointerValid)
+ objId = object->getOId();
+ }
+
+ RMDBGEXIT(11, RMDebug::module_adminif, "DBRef", "operator=(" << src.objId << ") " << objId);
+ return *this;
+ }
+
+
+template<class T>
+DBRef<T> &DBRef<T>::operator=(T *ptr)
+ {
+ RMDBGENTER(11, RMDebug::module_adminif, "DBRef", "operator=( at " << ptr << " ) " << objId);
+ if ((object != 0) && pointerCaching)
+ object->decrementReferenceCount();
+
+ object = ptr;
+ if (object == 0)
+ {
+ objId = DBOBJID_NONE;
+ pointerValid = false;
+ }
+ else {
+ objId = object->getOId();
+ object->incrementReferenceCount();
+ pointerValid = true;
+ }
+ RMDBGEXIT(11, RMDebug::module_adminif, "DBRef", "operator=( at " << ptr << " ) " << objId);
+ return *this;
+ }
+
+
+template <class T>
+T &DBRef<T>::operator *(void) throw ( r_Error )
+ {
+ RMDBGENTER(11, RMDebug::module_adminif, "DBRef", "operator*() " << objId);
+
+ if (is_null())
+ {
+ TALK( "DBRef::operator*(): object not found " << objId);
+ RMDBGMIDDLE(2, RMDebug::module_adminif, "DBRef", "object was not found " << objId);
+ r_Error err = r_Error(r_Error::r_Error_RefNull);
+ throw err;
+ }
+
+ RMDBGEXIT(11, RMDebug::module_adminif, "DBRef", "operator*() " << objId);
+ return *object;
+ }
+
+
+template <class T>
+const T &DBRef<T>::operator *(void) const throw ( r_Error )
+ {
+ RMDBGENTER(11, RMDebug::module_adminif, "DBRef", "operator*() const " << objId);
+
+ if (is_null())
+ {
+ TALK( "DBRef::operator*(): object not found " << objId);
+ RMDBGMIDDLE(2, RMDebug::module_adminif, "DBRef", "object was not found " << objId);
+ r_Error err = r_Error(r_Error::r_Error_RefNull);
+ throw err;
+ }
+
+ RMDBGEXIT(11, RMDebug::module_adminif, "DBRef", "operator*() " << objId);
+ return *object;
+ }
+
+
+#ifndef __GNUG__
+
+template <class T>
+T &DBRef<T>::operator[](int idx) const throw(r_Error)
+ {
+ RMDBGENTER(11, RMDebug::module_adminif, "DBRef", "operator[](" << idx << ") " << objId);
+
+ if (is_null())
+ {
+ TALK( "DBRef::operator[](): object not found " << objId);
+ RMDBGMIDDLE(2, RMDebug::module_adminif, "DBRef", "object was not found " << objId);
+ r_Error err = r_Error(r_Error::r_Error_RefNull);
+ throw err;
+ }
+
+ RMDBGEXIT(11, RMDebug::module_adminif, "DBRef", "operator[](" << idx << ") " << objId);
+ return *((this + idx).object);
+ }
+
+#endif
+
+template <class T>
+T *DBRef<T>::operator->(void) throw(r_Error)
+ {
+ RMDBGENTER(11, RMDebug::module_adminif, "DBRef", "operator->() " << objId);
+
+ if (is_null())
+ {
+ TALK( "DBRef::operator->(): object not found " << objId);
+ RMDBGMIDDLE(2, RMDebug::module_adminif, "DBRef", "object was not found " << objId);
+ r_Error err = r_Error(r_Error::r_Error_RefNull);
+ throw err;
+ }
+
+ RMDBGEXIT(11, RMDebug::module_adminif, "DBRef", "operator->() " << objId);
+ return object;
+ }
+
+
+template <class T>
+const T *DBRef<T>::operator->(void) const throw(r_Error)
+ {
+ RMDBGENTER(11, RMDebug::module_adminif, "DBRef", "operator->() const " << objId);
+
+ if (is_null())
+ {
+ TALK( "DBRef::operator->(): object not found " << objId);
+ RMDBGMIDDLE(2, RMDebug::module_adminif, "DBRef", "object was not found " << objId);
+ r_Error err = r_Error(r_Error::r_Error_RefNull);
+ throw err;
+ }
+
+ RMDBGEXIT(11, RMDebug::module_adminif, "DBRef", "operator->() const " << objId);
+ return object;
+ }
+
+
+template <class T>
+T *DBRef<T>::ptr(void) throw(r_Error)
+ {
+ RMDBGENTER(11, RMDebug::module_adminif, "DBRef", "ptr() " << objId);
+
+ if (is_null())
+ {
+ TALK( "DBRef::ptr(): object not found " << objId);
+ RMDBGMIDDLE(2, RMDebug::module_adminif, "DBRef", "object was not found " << objId);
+ r_Error err = r_Error(r_Error::r_Error_RefNull);
+ throw err;
+ }
+
+ RMDBGEXIT(11, RMDebug::module_adminif, "DBRef", "ptr() " << objId);
+ return object;
+ }
+
+
+template <class T>
+const T *DBRef<T>::ptr(void) const throw(r_Error)
+ {
+ RMDBGENTER(11, RMDebug::module_adminif, "DBRef", "ptr() " << objId);
+
+ if (is_null())
+ {
+ TALK( "DBRef::ptr(): object not found " << objId);
+ RMDBGMIDDLE(2, RMDebug::module_adminif, "DBRef", "object was not found " << objId);
+ r_Error err = r_Error(r_Error::r_Error_RefNull);
+ throw err;
+ }
+
+ RMDBGEXIT(11, RMDebug::module_adminif, "DBRef", "ptr() " << objId);
+ return object;
+ }
+
+
+template <class T>
+DBRef<T>::operator T*() throw (r_Error)
+ {
+ RMDBGENTER(11, RMDebug::module_adminif, "DBRef", "operator T*() " << objId);
+
+ if (is_null())
+ {
+ TALK( "DBRef::T*(): object not found " << objId);
+ RMDBGMIDDLE(2, RMDebug::module_adminif, "DBRef", "object was not found " << objId);
+ r_Error err = r_Error(r_Error::r_Error_RefNull);
+ throw err;
+ }
+
+ RMDBGEXIT(11, RMDebug::module_adminif, "DBRef", "operator T*() " << objId);
+ return object;
+ }
+
+
+template <class T>
+DBRef<T>::operator const T*() const throw (r_Error)
+ {
+ RMDBGENTER(11, RMDebug::module_adminif, "DBRef", "operator const T*() const" << objId);
+
+ if (is_null())
+ {
+ TALK( "DBRef::T*(): object not found " << objId);
+ RMDBGMIDDLE(2, RMDebug::module_adminif, "DBRef", "object was not found " << objId);
+ r_Error err = r_Error(r_Error::r_Error_RefNull);
+ throw err;
+ }
+
+ RMDBGEXIT(11, RMDebug::module_adminif, "DBRef", "operator const T*() " << objId);
+ return object;
+ }
+
+
+template <class T>
+OId DBRef<T>::getOId(void) const
+ {
+ if (object && pointerCaching)
+ ((DBRef<T>)*this).objId = object->getOId();
+ return objId;
+ }
+
+template <class T>
+void DBRef<T>::delete_object(void)
+ {
+ if (!is_null())
+ {
+ object->setPersistent(false);
+ object->decrementReferenceCount();
+ object = 0;
+ objId = DBOBJID_NONE;
+ }
+ else {
+ r_Error err;
+ if (objId.getType() == OId::INVALID)
+ {
+ err = r_Error(r_Error::r_Error_OIdInvalid);
+ }
+ else {
+ err = r_Error(r_Error::r_Error_ObjectUnknown);
+ }
+ RMDBGONCE(0, RMDebug::module_adminif, "DBRef", "delete_object() " << objId << " not ok")
+ throw err;
+ }
+ }
+
+template <class T>
+bool DBRef<T>::isInitialised() const
+ {
+ bool retval=false;
+ if (object)
+ retval=true;
+ else {
+ if (objId.getType() != OId::INVALID)
+ retval=true;
+ }
+ return retval;
+ }
+
+template <class T>
+bool DBRef<T>::is_valid(void) const
+ {
+ bool retval=false;
+ if (!is_null())
+ retval=true;
+ return retval;
+ }
+
+
+template <class T>
+void DBRef<T>::release()
+ {
+ RMDBGENTER(11, RMDebug::module_adminif, "DBRef", "release() " << objId);
+ if ((object != 0) && pointerCaching)
+ {
+ object->decrementReferenceCount();
+ }
+ object = 0;
+ RMDBGEXIT(11, RMDebug::module_adminif, "DBRef", "release() " << objId);
+ }
+
+
+template <class T>
+DBRef<T>::operator DBRef<DBObject>() const
+ {
+ RMDBGENTER(11, RMDebug::module_adminif, "DBRef", "operator DBRef<DBObject>() " << objId);
+ if (object && pointerCaching)
+ {
+ RMDBGEXIT(11, RMDebug::module_adminif, "DBRef", "operator DBRef<DBObject>(" << object << ") " << objId);
+ return DBRef<DBObject>(object);
+ }
+ else {
+ RMDBGEXIT(11, RMDebug::module_adminif, "DBRef", "operator DBRef<DBObject>(" << objId << ") " << objId);
+ return DBRef<DBObject>(objId);
+ }
+ }
+
+template <class T>
+DBRef<T>::operator DBRef<InlineTile>() const throw (r_Error)
+ {
+ RMDBGENTER(11, RMDebug::module_adminif, "DBRef", "operator DBRef<InlineTile>() " << objId);
+ if (object && pointerCaching)
+ {
+ if (object->getObjectType() == OId::INLINETILEOID)
+ {
+ RMDBGEXIT(11, RMDebug::module_adminif, "DBRef", "operator DBRef<InlineTile>() " << objId);
+ return DBRef<InlineTile>((InlineTile*)object);
+ }
+ }
+ else {
+ if (objId.getType() == OId::INLINETILEOID)
+ {
+ RMDBGEXIT(11, RMDebug::module_adminif, "DBRef", "operator DBRef<InlineTile>() " << objId);
+ return DBRef<InlineTile>(objId);
+ }
+ }
+ TALK( "DBRef::<InlineTile>(): operator mismatch" << objId);
+ RMDBGEXIT(0, RMDebug::module_adminif, "DBRef", "operator DBRef<InlineTile>() mismatch " << objId);
+ throw r_Error(r_Error::r_Error_DatabaseClassMismatch);
+ }
+
+template <class T>
+DBRef<T>::operator DBRef<DBTile>() const throw (r_Error)
+ {
+ RMDBGENTER(11, RMDebug::module_adminif, "DBRef", "operator DBRef<DBTile>() " << objId << "; object=" << (long) object );
+ TALK( "DBRef::DBRef<DBTile>(): object=" << (long) object );
+ if (object && pointerCaching)
+ {
+ if ((object->getObjectType() == OId::BLOBOID) || (object->getObjectType() == OId::INLINETILEOID))
+ {
+ RMDBGEXIT(11, RMDebug::module_adminif, "DBRef", "operator DBRef<DBTile>() " << objId);
+ return DBRef<DBTile>((DBTile*)object);
+ }
+ }
+ else {
+ if ((objId.getType() == OId::BLOBOID) || (objId.getType() == OId::INLINETILEOID))
+ {
+ RMDBGEXIT(11, RMDebug::module_adminif, "DBRef", "operator DBRef<DBTile>() " << objId);
+ return DBRef<DBTile>(objId);
+ }
+ }
+ if (object) { TALK( "DBRef::DBRef<DBTile>(): object->getObjectType()=" << object->getObjectType() ); }
+ TALK( "DBRef::DBRef<DBTile>(): objId->getObjectType()=" << objId.getType() );
+ TALK( "DBRef::DBRef<DBTile>(): operator mismatch" << objId );
+ if (object) { RMDBGMIDDLE(0, RMDebug::module_adminif, "DBRef", "object->getObjectType()=" << object->getObjectType() ); }
+ RMDBGMIDDLE(0, RMDebug::module_adminif, "DBRef", "objId->getObjectType()=" << objId.getType() );
+ RMDBGEXIT(0, RMDebug::module_adminif, "DBRef", "operator DBRef<DBTile>() mismatch " << objId);
+ throw r_Error(r_Error::r_Error_DatabaseClassMismatch);
+ }
+
+template <class T>
+DBRef<T>::operator DBRef<BLOBTile>() const throw (r_Error)
+ {
+ RMDBGENTER(11, RMDebug::module_adminif, "DBRef", "operator DBRef<BLOBTile>() " << objId);
+ if (object && pointerCaching)
+ {
+ if (object->getObjectType() == OId::BLOBOID || (object->getObjectType() == OId::INLINETILEOID))
+ {
+ RMDBGEXIT(11, RMDebug::module_adminif, "DBRef", "operator DBRef<BLOBTile>() " << objId);
+ return DBRef<BLOBTile>((BLOBTile*)object);
+ }
+ }
+ else {
+ if ((objId.getType() == OId::BLOBOID) || (objId.getType() == OId::INLINETILEOID))
+ {
+ RMDBGEXIT(11, RMDebug::module_adminif, "DBRef", "operator DBRef<BLOBTile>() " << objId);
+ return DBRef<BLOBTile>(objId);
+ }
+ }
+ TALK( "DBRef::DBRef<BLOBTile>(): operator mismatch" << objId);
+ RMDBGEXIT(0, RMDebug::module_adminif, "DBRef", "operator DBRef<BLOBTile>() mismatch " << objId);
+ throw r_Error(r_Error::r_Error_DatabaseClassMismatch);
+ }
+
+template <class T>
+DBRef<T>::operator DBRef<DBTCIndex>() const throw (r_Error)
+ {
+ RMDBGENTER(11, RMDebug::module_adminif, "DBRef", "operator DBRef<DBTCIndex>() " << objId);
+ if (object && pointerCaching)
+ {
+ if (object->getObjectType() == OId::DBTCINDEXOID)
+ {
+ RMDBGEXIT(11, RMDebug::module_adminif, "DBRef", "operator DBRef<DBTCIndex>() " << objId);
+ return DBRef<DBTCIndex>((DBTCIndex*)object);
+ }
+ }
+ else {
+ if (objId.getType() == OId::DBTCINDEXOID)
+ {
+ RMDBGEXIT(11, RMDebug::module_adminif, "DBRef", "operator DBRef<DBTCIndex>() " << objId);
+ return DBRef<DBTCIndex>(objId);
+ }
+ }
+ TALK( "DBRef::DBRef<DBTCIndex>(): operator mismatch" << objId);
+ RMDBGEXIT(0, RMDebug::module_adminif, "DBRef", "operator DBRef<DBTCIndex>() mismatch " << objId);
+ throw r_Error(r_Error::r_Error_DatabaseClassMismatch);
+ }
+
+template <class T>
+DBRef<T>::operator DBRef<DBHierIndex>() const throw (r_Error)
+ {
+ RMDBGENTER(11, RMDebug::module_adminif, "DBRef", "operator DBRef<DBHierIndex>() " << objId);
+ if (object && pointerCaching)
+ {
+ if ((object->getObjectType() == OId::MDDHIERIXOID) || (object->getObjectType() == OId::DBTCINDEXOID))
+ {
+ RMDBGEXIT(11, RMDebug::module_adminif, "DBRef", "operator DBRef<DBHierIndex>() " << objId);
+ return DBRef<DBHierIndex>((DBHierIndex*)object);
+ }
+ }
+ else {
+ if ((objId.getType() == OId::MDDHIERIXOID) || (objId.getType() == OId::DBTCINDEXOID))
+ {
+ RMDBGEXIT(11, RMDebug::module_adminif, "DBRef", "operator DBRef<DBHierIndex>() " << objId);
+ return DBRef<DBHierIndex>(objId);
+ }
+ }
+ TALK( "DBRef::DBRef<DBHierIndex>(): operator mismatch" << objId);
+ RMDBGEXIT(0, RMDebug::module_adminif, "DBRef", "operator DBRef<DBHierIndex>() mismatch " << objId);
+ throw r_Error(r_Error::r_Error_DatabaseClassMismatch);
+ }
+
+
+template <class T>
+DBRef<T>::operator DBRef<DBRCIndexDS>() const throw (r_Error)
+ {
+ RMDBGENTER(11, RMDebug::module_adminif, "DBRef", "operator DBRef<DBRCIndexDS>() " << objId);
+ if (object && pointerCaching)
+ {
+ if (object->getObjectType() == OId::MDDRCIXOID)
+ {
+ RMDBGEXIT(11, RMDebug::module_adminif, "DBRef", "operator DBRef<DBRCIndexDS>() " << objId);
+ return DBRef<DBRCIndexDS>((DBRCIndexDS*)object);
+ }
+ }
+ else {
+ if (objId.getType() == OId::MDDRCIXOID)
+ {
+ RMDBGEXIT(11, RMDebug::module_adminif, "DBRef", "operator DBRef<DBRCIndexDS>() " << objId);
+ return DBRef<DBRCIndexDS>(objId);
+ }
+ }
+ TALK( "DBRef::DBRef<DBRCIndexDS>(): operator mismatch" << objId);
+ RMDBGEXIT(0, RMDebug::module_adminif, "DBRef", "operator DBRef<DBRCIndexDS>() mismatch " << objId);
+ throw r_Error(r_Error::r_Error_DatabaseClassMismatch);
+ }
+
+
+template <class T>
+DBRef<T>::operator HierIndexDS*() const throw (r_Error)
+ {
+ RMDBGENTER(11, RMDebug::module_adminif, "DBRef", "operator HierIndexDS*() " << objId);
+ if (object && pointerCaching)
+ {
+ if ((object->getObjectType() == OId::MDDHIERIXOID) || (object->getObjectType() == OId::DBTCINDEXOID))
+ {
+ RMDBGEXIT(11, RMDebug::module_adminif, "DBRef", "operator HierIndexDS*() " << objId);
+ return (HierIndexDS*)object;
+ }
+ }
+ else {
+ if (objId.getType() == OId::MDDHIERIXOID)
+ {
+ RMDBGEXIT(11, RMDebug::module_adminif, "DBRef", "operator IndexDS*() DBHierIndexId" << objId);
+ DBRef<DBHierIndex> t(objId);
+ return (HierIndexDS*)t.ptr();
+ }
+ else {
+ if (objId.getType() == OId::DBTCINDEXOID)
+ {
+ RMDBGEXIT(11, RMDebug::module_adminif, "DBRef", "operator IndexDS*() DBTCIndexId" << objId);
+ DBRef<DBTCIndex> t(objId);
+ return (HierIndexDS*)t.ptr();
+ }
+ }
+ }
+ TALK( "DBRef::HierIndexDS*(): operator mismatch" << objId);
+ RMDBGEXIT(0, RMDebug::module_adminif, "DBRef", "operator HierIndexDS*() mismatch " << objId);
+ throw r_Error(r_Error::r_Error_DatabaseClassMismatch);
+ }
+
+
+template <class T>
+DBRef<T>::operator IndexDS*() const throw (r_Error)
+ {
+ RMDBGENTER(11, RMDebug::module_adminif, "DBRef", "operator IndexDS*() " << objId);
+ if (object && pointerCaching)
+ {
+ if ((object->getObjectType() == OId::MDDHIERIXOID) || (object->getObjectType() == OId::DBTCINDEXOID) || (object->getObjectType() == OId::MDDRCIXOID))
+ {
+ RMDBGEXIT(11, RMDebug::module_adminif, "DBRef", "operator IndexDS*() " << objId);
+ return (IndexDS*)object;
+ }
+ }
+ else {
+ if (objId.getType() == OId::MDDHIERIXOID)
+ {
+ RMDBGEXIT(11, RMDebug::module_adminif, "DBRef", "operator IndexDS*() DBHierIndexId" << objId);
+ DBRef<DBHierIndex> t(objId);
+ return (IndexDS*)t.ptr();
+ }
+ else {
+ if (objId.getType() == OId::DBTCINDEXOID)
+ {
+ RMDBGEXIT(11, RMDebug::module_adminif, "DBRef", "operator IndexDS*() DBTCIndexId" << objId);
+ DBRef<DBTCIndex> t(objId);
+ return (IndexDS*)t.ptr();
+ }
+ else {
+ if (objId.getType() == OId::MDDRCIXOID)
+ {
+ RMDBGEXIT(11, RMDebug::module_adminif, "DBRef", "operator IndexDS*() DBRCIndexId" << objId);
+ DBRef<DBRCIndexDS> t(objId);
+ return (IndexDS*)t.ptr();
+ }
+ }
+ }
+ }
+ TALK( "DBRef::IndexDS*(): operator mismatch" << objId);
+ RMDBGEXIT(0, RMDebug::module_adminif, "DBRef", "operator IndexDS*() mismatch " << objId);
+ throw r_Error(r_Error::r_Error_DatabaseClassMismatch);
+ }
+
+
+template <class T>
+bool DBRef<T>::is_null(void) const
+ {
+ RMDBGENTER(11, RMDebug::module_adminif, "DBRef", "is_null() " << objId);
+ bool retval = false;
+ T* t = 0;
+ if (object == 0)
+ {
+ if (objId.getType() == OId::INVALID)
+ {
+ throw r_Error(r_Error::r_Error_OIdInvalid);
+ }
+ else {
+ try {
+ t = (T*)ObjectBroker::getObjectByOId(objId);
+ RMDBGMIDDLE(11, RMDebug::module_adminif, "DBRef", "found object");
+ t->incrementReferenceCount();
+ ((DBRef<T>*)this)->object = t;
+ RMDBGMIDDLE(11, RMDebug::module_adminif, "DBRef", "object is at: " << object << " found object was at: " << t);
+ }
+ catch (r_Error& err)
+ {
+ if (err.get_kind() == r_Error::r_Error_ObjectUnknown)
+ retval = true;
+ else
+ throw;
+ }
+ }
+ }
+ else {
+ if (pointerCaching == false)
+ {
+ if (pointerValid == false)
+ {
+ try {
+ t = (T*)ObjectBroker::getObjectByOId(objId);
+ RMDBGMIDDLE(11, RMDebug::module_adminif, "DBRef", "found object");
+ t->incrementReferenceCount();
+ ((DBRef<T>*)this)->object = t;
+ RMDBGMIDDLE(11, RMDebug::module_adminif, "DBRef", "object is at: " << object << " found object was at: " << t);
+ }
+ catch (r_Error& err)
+ {
+ if (err.get_kind() == r_Error::r_Error_ObjectUnknown)
+ retval = true;
+ else
+ throw;
+ }
+ }
+ else {
+ //retval = false; is done in initialize
+ }
+ }
+ else {
+ //retval = false; is done in initialize
+ }
+ }
+ RMDBGEXIT(11, RMDebug::module_adminif, "DBRef", "is_null() " << objId << " " << retval);
+ return retval;
+ }
diff --git a/reladminif/dbref.hh b/reladminif/dbref.hh
new file mode 100644
index 0000000..35065a9
--- /dev/null
+++ b/reladminif/dbref.hh
@@ -0,0 +1,301 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * DBRef is a smart pointer for managing objects derived from
+ * the DbObject class.
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+
+#ifndef _DBREF_HH_
+#define _DBREF_HH_
+
+class DBHierIndex;
+class DBRCIndexDS;
+class DBTCIndex;
+class BLOBTile;
+class InlineTile;
+class DBTile;
+class OId;
+class DBObject;
+class r_Error;
+class IndexDS;
+class HierIndexDS;
+class DBMDDObj;
+
+template <class T> class DBRef;
+
+#include "oidif.hh"
+
+//@ManMemo: Module: {\bf reladminif}.
+/*@Doc:
+DBRef is a smart pointer class operating on classes derived from DbObject. A smart
+pointer to an object with a known id is created using DBRef<T>(id). The object
+managed by a given smart pointer can be changed (rebinding) by using the assignment
+operator.
+All access methods may throw database related r_Errors.
+*/
+
+#define DBOBJID_NONE OId()
+
+template <class T>
+class DBRef
+ {
+ public:
+
+ DBRef(void);
+ /*@Doc:
+ Default constructor. Object must be assigned a value before the first dereferencing.
+ */
+
+ DBRef(const OId &id);
+ /*@Doc:
+ Id-constructor, binds smart pointer to object with the given id (must only be unique
+ within class T, not within all classes derived from DbObject).
+ */
+
+ DBRef(OId::OIdPrimitive id);
+ /*@Doc:
+ Id-constructor, binds smart pointer to object with the given id (must only be unique
+ within class T, not within all classes derived from DbObject).
+ */
+
+ DBRef(const DBRef<T> &src);
+ /*@Doc:
+ Copy-constructor, binds smart pointer to the same object src is bound to.
+ */
+
+ DBRef(T *ptr);
+ /*@Doc:
+ Object-constructor, binds smart pointer explicitly to the object ptr.
+ */
+
+ ~DBRef(void);
+ /*@Doc:
+ Destructor: decrements reference count for the object that was managed by this
+ smart pointer.
+ */
+
+ bool operator<(const DBRef<T>& other) const;
+ /*@Doc:
+ Returns true if me.operator==(other) returns -1
+ */
+
+ int operator==(const DBRef<T> &src) const;
+ /*@Doc:
+ Comparison operator:
+ Returns:
+ -1 if this is not initialised and src is initialised
+ -1 if persistent and objId < src.objId
+ -1 if transient and src is persistent
+ -1 if transient and object < src.object
+ 0 if persistent and src persistent and myOId == src.myOId
+ 0 if transient and src transient and object == src.object
+ 0 if this is not initialised and src is not initialised
+ +1 if persistent and objId > src.objId
+ +1 if persistent and src is transient
+ +1 if transient and object > src.object
+ -1 if this is initialised and src is not initialised
+ */
+
+ DBRef<T> &operator=(const DBRef<T> &src);
+ /*@Doc:
+ Assignment operator: removes old binding and rebinds to the same object managed by src.
+ */
+
+ DBRef<T> &operator=(T *ptr);
+ /*@Doc:
+ Assignment operator: removes old binding and rebinds to object ptr.
+ */
+
+ T *operator->(void) throw (r_Error);
+ /*@Doc:
+ Dereferencing operator -> for accessing the managed object's members.
+ */
+
+ const T *operator->(void) const throw (r_Error);
+ /*@Doc:
+ Dereferencing operator -> for accessing the managed object's members.
+ */
+
+ T &operator*(void) throw (r_Error);
+ /*@Doc:
+ Dereferencing operator * for accessing the managed object.
+ */
+
+ const T &operator*(void) const throw (r_Error);
+ /*@Doc:
+ Dereferencing operator * for accessing the managed object.
+ */
+
+#ifndef __GNUG__
+ T &operator[](int idx) const throw (r_Error);
+ /*@Doc:
+ Dereferencing operator [] for accessing array objects.
+ */
+#endif
+
+ T *ptr(void) throw (r_Error);
+ /*@Doc:
+ Returns pointer to managed object.
+ */
+
+ const T *ptr(void) const throw (r_Error);
+ /*@Doc:
+ Returns pointer to managed object.
+ */
+
+ OId getOId(void) const;
+ /*@Doc:
+ Returns id of managed object
+ */
+
+ void delete_object(void);
+ /*@Doc:
+ deletes the object from database if it is valid else throws an exception.
+ */
+
+ bool is_null(void) const;
+ /*@Doc:
+ Returns false if valid binding exists, true otherwise.
+ this method may instantiate an object from the database
+ */
+
+ bool is_valid(void) const;
+ /*@Doc:
+ Returns true if valid binding exists, false otherwise
+ */
+
+ bool isInitialised() const;
+ /*@Doc:
+ Returns true if OId is valid or the pointer is valid, false otherwise
+ */
+
+ void release();
+ /*@Doc:
+ releases this DBRef pointer and refcount to its object
+ */
+
+ operator DBRef<DBObject>() const;
+ /*@Doc:
+ cast operator. works allways.
+ */
+
+ operator DBRef<BLOBTile>() const throw (r_Error);
+ /*@Doc:
+ cast operator. checks it the objects type is of OId::BLOBOID.
+ */
+
+ operator DBRef<DBTile>() const throw (r_Error);
+ /*@Doc:
+ cast operator. checks it the objects type is of OId::BLOBOID or OId::INLINETILEOID.
+ */
+
+ operator DBRef<InlineTile>() const throw (r_Error);
+ /*@Doc:
+ cast operator. checks it the objects type is of OId::INLINETILEOID.
+ */
+
+ operator DBRef<DBHierIndex>() const throw (r_Error);
+ /*@Doc:
+ cast operator. checks it the objects type is of OId::MDDHIERIXOID.
+ */
+
+ operator DBRef<DBTCIndex>() const throw (r_Error);
+ /*@Doc:
+ cast operator. checks it the objects type is of OId::INLINEIXOID.
+ */
+
+ operator DBRef<DBRCIndexDS>() const throw (r_Error);
+ /*@Doc:
+ cast operator. checks it the objects type is of OId::MDDRCIXOID.
+ */
+
+ operator IndexDS*() const throw (r_Error);
+ /*@Doc:
+ cast operator. checks it the objects type is of any valid index.
+ */
+
+ operator HierIndexDS*() const throw (r_Error);
+ /*@Doc:
+ cast operator. checks it the objects type is of any valid hierarchical index.
+ */
+
+ operator T*() throw (r_Error);
+ /*@Doc:
+ */
+
+ operator const T*() const throw (r_Error);
+ /*@Doc:
+ */
+
+ static void setPointerCaching(bool useIt);
+ /*@Doc:
+ Make the dbref store and use pointers.
+ If set to false the DBRef will always ask the objectbroker.
+ May be set at any time to false.
+ Only between transactions may it be set to true.
+ */
+
+ static bool getPointerCaching();
+ /*@Doc:
+ returns pointerCaching
+ */
+
+ private:
+
+
+ mutable T *object;
+ /*@Doc:
+ Pointer to the managed object or 0 if no binding exists.
+ */
+
+ OId objId;
+ /*@Doc:
+ id of managed object.
+ */
+
+ bool pointerValid;
+ /*@Doc:
+ whenever a smartpointer is initiaised by a pointer, this attribute is set to true.
+ this is neccessary for disabled pointer caching.
+ */
+
+ static bool pointerCaching;
+ };
+
+template <class T> bool operator< (const DBRef<T> &me, const DBRef<T> &him);
+
+#ifdef EARLY_TEMPLATE
+#ifdef __EXECUTABLE__
+#include "dbref.cc"
+#endif
+#endif
+
+#endif
diff --git a/reladminif/destroyable.hh b/reladminif/destroyable.hh
new file mode 100644
index 0000000..316cfeb
--- /dev/null
+++ b/reladminif/destroyable.hh
@@ -0,0 +1,52 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#ifndef _DESTROYABLE_HH_
+#define _DESTROYABLE_HH_
+
+/****************************************************************************
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ ****************************************************************************/
+
+//@ManMemo: Module: {\bf reladminif}
+/*@Doc:
+
+This is an interface class. It is abstract. It supplies the signature that
+is required to allow other interfaces to be defined without a virtual destructor.
+*/
+
+class Destroyable
+ {
+ public:
+ virtual void destroy() = 0;
+ /*@Doc:
+ delete the object.
+ object may not be deleted when reference counting is enabled.
+ */
+
+ };
+
+#endif
diff --git a/reladminif/eoid.cc b/reladminif/eoid.cc
new file mode 100644
index 0000000..f07497e
--- /dev/null
+++ b/reladminif/eoid.cc
@@ -0,0 +1,231 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * EOId is optimized for maps that contain only EOId of one system/database.
+ *
+ *
+ * COMMENTS:
+ *
+ **********************************************************************/
+
+#include "eoid.hh"
+#include "externs.h"
+#include "adminif.hh"
+#include "databaseif.hh"
+#include "raslib/rmdebug.hh"
+#include "raslib/error.hh"
+
+void
+EOId::print_status(std::ostream& s) const
+ {
+ s << systemName.c_str() << "|" << databaseName.c_str() << "|";
+ OId::print_status(s);
+ }
+
+std::ostream&
+operator<<(std::ostream& s, const EOId& d )
+ {
+ s << "EOId(" << d.getSystemName() << "|" << d.getBaseName() << "|" << d.getOId() << ")";
+ return s;
+ }
+
+std::ostream&
+operator<<(std::ostream& s, EOId& d )
+ {
+ s << "EOId(" << d.getSystemName() << "|" << d.getBaseName() << "|" << d.getOId() << ")";
+ return s;
+ }
+
+EOId::EOId(const char* systemname, const char* dbname, OId::OIdCounter id, OId::OIdType type)
+ : OId(id, type),
+ systemName(systemname),
+ databaseName(dbname)
+ {
+ RMDBGONCE(10, RMDebug::module_adminif, "EOId", "EOId(" << systemname << "," << dbname << "," << id << "," << type << ")");
+ }
+
+EOId::EOId(const OId& id)
+ : OId(id)
+ {
+ RMDBGENTER(10, RMDebug::module_adminif, "EOId", "EOId(" << id << ")");
+ if (AdminIf::getCurrentDatabaseIf())
+ {
+ systemName = (AdminIf::getSystemName());
+ databaseName = (AdminIf::getCurrentDatabaseIf()->getName());
+ }
+ else {
+ RMDBGMIDDLE(10, RMDebug::module_adminif, "EOId", "EOId(" << id << ") no current databaseif");
+ throw r_Error(r_Error::r_Error_TransactionNotOpen);
+ }
+ RMDBGEXIT(10, RMDebug::module_adminif, "EOId", "EOId(" << id << ")");
+ }
+
+EOId::EOId()
+ : OId()
+ {
+ RMDBGENTER(10, RMDebug::module_adminif, "EOId", "EOId()");
+ if (AdminIf::getCurrentDatabaseIf())
+ {
+ systemName = (AdminIf::getSystemName());
+ databaseName = (AdminIf::getCurrentDatabaseIf()->getName());
+ }
+ else {
+ RMDBGMIDDLE(10, RMDebug::module_adminif, "EOId", "EOId() no current databaseif");
+ throw r_Error(r_Error::r_Error_TransactionNotOpen);
+ }
+ RMDBGEXIT(10, RMDebug::module_adminif, "EOId", "EOId()");
+ }
+
+EOId::~EOId()
+ {
+ RMDBGONCE(10, RMDebug::module_adminif, "EOId", "~EOId()");
+ }
+
+const char*
+EOId::getSystemName() const
+ {
+ RMDBGONCE(10, RMDebug::module_adminif, "EOId", "getSystemName() " << systemName.c_str());
+ return systemName.c_str();
+ }
+
+
+const char*
+EOId::getBaseName() const
+ {
+ RMDBGONCE(10, RMDebug::module_adminif, "EOId", "getBaseName() " << databaseName.c_str());
+ return databaseName.c_str();
+ }
+
+
+OId
+EOId::getOId() const
+ {
+ RMDBGONCE(10, RMDebug::module_adminif, "EOId", "getOId() " << (OId)*this);
+ return(OId)*this;
+ }
+
+
+void
+EOId::allocateEOId(EOId& eoid, OId::OIdType t) throw (r_Error)
+ {
+ RMDBGENTER(10, RMDebug::module_adminif, "EOId", "allocateEOId(" << eoid << "," << t << ")");
+ if (AdminIf::getCurrentDatabaseIf())
+ {
+ eoid.systemName = AdminIf::getSystemName();
+ eoid.databaseName = AdminIf::getCurrentDatabaseIf()->getName();
+ }
+ else {
+ RMDBGMIDDLE(10, RMDebug::module_adminif, "EOId", "allocateEOId(" << eoid << ") no current databaseif");
+ throw r_Error(r_Error::r_Error_TransactionNotOpen);
+ }
+ allocateOId(eoid, t);
+ RMDBGEXIT(10, RMDebug::module_adminif, "EOId", "allocateEOId(" << eoid << "," << t << ")");
+ }
+
+bool
+EOId::operator==(const EOId& one) const
+ {
+ RMDBGONCE(10, RMDebug::module_adminif, "EOId", "operator==(" << one << ")");
+ bool retval=false;
+ if(OId::operator==(one))
+ if(systemName == one.systemName)
+ if(databaseName == one.databaseName)
+ retval=true;
+ return retval;
+ }
+
+bool
+EOId::operator!=(const EOId& one) const
+ {
+ RMDBGONCE(10, RMDebug::module_adminif, "EOId", "operator!=(" << one << ")");
+ return !EOId::operator==(one);
+ }
+
+EOId&
+EOId::operator=(const EOId& old)
+ {
+ RMDBGONCE(10, RMDebug::module_adminif, "EOId", "operator=(" << old << ")");
+ if(this != &old)
+ {
+ OId::operator=(old);
+ systemName = old.systemName;
+ databaseName = old.databaseName;
+ }
+ return *this;
+ }
+
+bool
+EOId::operator<(const EOId& old) const
+ {
+ RMDBGONCE(10, RMDebug::module_adminif, "EOId", "operator<(" << old << ")");
+ bool retval=false;
+ if (OId::operator<(old))
+ retval=true;
+ if (!retval && (databaseName < old.databaseName))
+ retval=true;
+ if (!retval && (systemName < old.systemName))
+ retval=true;
+ return retval;
+ }
+
+bool
+EOId::operator>(const EOId& old) const
+ {
+ RMDBGONCE(10, RMDebug::module_adminif, "EOId", "operator>(" << old << ")");
+ bool retval=false;
+ if (OId::operator>(old))
+ retval=true;
+ if (!retval && (databaseName > old.databaseName))
+ retval=true;
+ if (!retval && (systemName > old.systemName))
+ retval=true;
+ return retval;
+ }
+
+bool
+EOId::operator<=(const EOId& old) const
+ {
+ RMDBGONCE(10, RMDebug::module_adminif, "EOId", "operator<=(" << old << ")");
+ bool retval=false;
+ if (operator<(old))
+ retval=true;
+ if (!retval && (operator==(old)))
+ retval=true;
+ return retval;
+ }
+
+bool
+EOId::operator>=(const EOId& old) const
+ {
+ RMDBGONCE(10, RMDebug::module_adminif, "EOId", "operator<=(" << old << ")");
+ bool retval=false;
+ if (operator>(old))
+ retval=true;
+ if (!retval && (operator==(old)))
+ retval=true;
+ return retval;
+ }
+
diff --git a/reladminif/eoid.hh b/reladminif/eoid.hh
new file mode 100644
index 0000000..968dcb5
--- /dev/null
+++ b/reladminif/eoid.hh
@@ -0,0 +1,146 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#ifndef _EOIDIF_HH_
+#define _EOIDIF_HH_
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * EOId is optimized for maps that contain only EOId of one system/database.
+ *
+ *
+ * COMMENTS:
+ * When true multiple connections are implemented the order of compare
+ * statements in the operator"<" and ">" must be changed.
+ ***************************************************************************/
+
+class EOId;
+class r_Error;
+
+#include "oidif.hh"
+#include <string>
+
+//@ManMemo: Module: {\bf reladminif}.
+/*@Doc:
+EOId is optimized for maps that contain only EOId of one system/database.
+when true multiple connections are implemented the order of compare
+statements in the operator"<" and ">" must be changed.
+*/
+
+class EOId : public OId
+ {
+ public:
+ EOId(const char* systemname, const char* dbname, OId::OIdCounter id, OIdType type);
+ /*@Doc:
+ constructs a complete EOId.
+ */
+
+ EOId(const OId& id);
+ /*@Doc:
+ uses the currently open database to get system and db name
+ systemname and database name will be null string when the
+ database is not really open.
+ */
+
+ EOId();
+ /*@Doc:
+ uses the currently open database to get system and db name
+ systemname and database name will be null string when the
+ database is not really open.
+ */
+
+
+ ~EOId();
+ /*@Doc:
+ does not do anything.
+ */
+
+ EOId& operator=(const EOId& old);
+ /*@Doc:
+ assignes all atributes.
+ */
+
+
+ const char* getSystemName() const;
+ /*@Doc:
+ returns the system name, which is the same as the
+ one returned by databaseif.
+ */
+
+
+ const char* getBaseName() const;
+ /*@Doc:
+ returns the database name, which is the same as the
+ one returned by databaseif
+ */
+
+
+ OId getOId() const;
+ /*@Doc:
+ returns the oid of this eoid
+ */
+
+
+ void print_status(std::ostream& o) const;
+ /*@Doc:
+ returns the systemname|databasename|oid
+ */
+
+ static void allocateEOId(EOId& eoid, OId::OIdType t) throw (r_Error);
+ /*@Doc:
+ Allocates a new logical MDD EOid in the currently opened base.
+ throws an r_Error_DatabaseClosed when the database is not really open.
+ */
+
+ bool operator<(const EOId& old) const;
+
+ bool operator>(const EOId& old) const;
+
+ bool operator<=(const EOId& old) const;
+
+ bool operator>=(const EOId& old) const;
+
+ bool operator== (const EOId& one) const;
+
+ bool operator!= (const EOId& one) const;
+
+ private:
+
+ std::string databaseName;
+ /*@Doc:
+ the name of the database the oid of this eoid is valid for.
+ stl std::string was used because of the compare functionality.
+ */
+
+ std::string systemName;
+ /*@Doc:
+ the name of the system above mentioned database runs on
+ stl std::string was used because of the compare functionality.
+ */
+ };
+
+extern std::ostream& operator<<(std::ostream& s, EOId& d);
+
+extern std::ostream& operator<<(std::ostream& s, const EOId& d);
+
+#endif
diff --git a/reladminif/externs.h b/reladminif/externs.h
new file mode 100644
index 0000000..d947c7e
--- /dev/null
+++ b/reladminif/externs.h
@@ -0,0 +1,81 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*****************************************************************************
+ *
+ *
+ * PURPOSE:
+ * provide global definitions for embedded SQL usage (any base DBMS)
+ *
+ *
+ * COMMENTS:
+ * - uses embedded SQL
+ * - FIXME: should also contain stuff from sqlglobals.h, merge some time
+ *
+ *****************************************************************************/
+
+#ifndef _EXTERNS_H_
+#define _EXTERNS_H_
+
+const int SQLOK = 0;
+const short INDNULL = -1;
+
+#ifdef BASEDB_INFORMIX
+ const int SQLNULLFETCHED = -245;
+ const int SQLTABLEUNKNOWN = -206;
+ const int SQLNODATAFOUND = 100;
+
+ //SQLCODE and SQLSTATE are defined in the sqlca.h file
+#endif // informix
+
+#ifdef BASEDB_DB2
+ const int SQLNULLFETCHED = -1405;
+ const int SQLTABLEUNKNOWN = -942;
+ const int SQLNODATAFOUND = 100;
+
+ //declared in sqlerror.sqC
+ extern long SQLCODE;
+ extern char SQLSTATE[6];
+
+#endif // db2
+
+#ifdef BASEDB_ORACLE
+ const int SQLNULLFETCHED = -1405;
+ const int SQLTABLEUNKNOWN = -942;
+ const int SQLNODATAFOUND = 100;
+
+ #include <sqlca.h>
+ #define SQLCODE sqlca.sqlcode
+
+ //declared in sqlerror.pc
+ extern struct sqlca sqlca;
+#endif // oracle
+
+#ifdef BASEDB_PGSQL
+ #include "ecpgerrno.h" // PgSQL error codes
+ // const int SQLNULLFETCHED = -1405; unused
+ // const int SQLTABLEUNKNOWN = -942; not supported by PG
+ const int SQLNODATAFOUND = ECPG_NOT_FOUND;
+ //SQLCODE and SQLSTATE are defined in the sqlca.h file
+#endif // pgsql
+
+#endif // _EXTERNS_H_
diff --git a/reladminif/lists.h b/reladminif/lists.h
new file mode 100644
index 0000000..783c2af
--- /dev/null
+++ b/reladminif/lists.h
@@ -0,0 +1,106 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#ifndef _LISTS_H_
+#define _LISTS_H_
+
+#include <vector>
+#include <set>
+#include <map>
+#include "relmddif/mddid.hh"
+
+class DBObject;
+class OId;
+class InlineMinterval;
+class r_Minterval;
+class KeyObject;
+class IndexDS;
+class HierIndexDS;
+class Tile;
+
+#include "raslib/mddtypes.hh"
+
+//used to hold oids for indexes, blobs, and dbmintervals. no double entries
+typedef std::set< OId, std::less< double > > OIdSet;
+
+//used to hold oids for indexes, blobs, and dbmintervals. no double entries
+typedef std::set< const OId, std::less< double > > OIdConstSet;
+
+typedef std::vector<HierIndexDS*> HierIndexDSPVector;
+
+//used to hold DBObject*. e.g. in objectbroker to temporarily store them before deletion
+typedef std::vector<DBObject*> DBObjectPVector;
+
+//used to hold DBObject*. e.g. in objectbroker to temporarily store them before deletion
+typedef std::vector<const DBObject*> DBObjectPConstVector;
+
+//used to hold oids for indexes, blobs, and dbmintervals
+typedef std::vector<OId> OIdVector;
+
+//used to hold oids for indexes, blobs, and dbmintervals
+typedef std::vector<const OId> OIdConstVector;
+
+//holds type information on specific blobs which are stored in above oidlists
+typedef std::vector<r_Data_Format> CompTypeVector;
+
+typedef std::vector<const InlineMinterval*> IntervalPConstVector;
+
+typedef std::vector<InlineMinterval*> IntervalPVector;
+
+typedef std::vector<const InlineMinterval> IntervalConstVector;
+
+typedef std::vector<InlineMinterval> IntervalVector;
+
+typedef std::vector<const KeyObject*> KeyObjectPConstVector;
+
+typedef std::vector<KeyObject*> KeyObjectPVector;
+
+typedef std::vector<const KeyObject> KeyObjectConstVector;
+
+typedef std::vector<KeyObject> KeyObjectVector;
+
+typedef std::vector<r_Minterval> DomainVector;
+
+typedef std::vector<r_Minterval*> DomainPVector;
+
+typedef std::vector<const r_Minterval*> DomainPConstVector;
+
+typedef std::vector<IndexDS*> IndexPVector;
+
+typedef std::vector<Tile*> TilePVector;
+
+typedef std::map< double, DBObject*, std::less<double> > DBObjectPMap;
+typedef std::pair< double, DBObject* > DBObjectPPair;
+typedef std::pair< const double, DBObject* > ConstDBObjectPPair;
+
+typedef std::map< double, const DBObject*, std::less<double> > DBObjectPConstMap;
+typedef std::pair< double, const DBObject* > DBObjectPConstPair;
+typedef std::pair< const double, const DBObject* > ConstDBObjectPConstPair;
+
+typedef std::map< double, OId, std::less<double> > OIdMap;
+typedef std::pair< const double, OId > OIdPair;
+typedef std::pair< const double, const OId > OIdConstPair;
+
+typedef std::map< double, r_Minterval, std::less<double> > DomainMap;
+typedef std::pair< const double, r_Minterval > DomainPair;
+typedef std::pair< const double, const r_Minterval > DomainConstPair;
+#endif
diff --git a/reladminif/objectbroker.hh b/reladminif/objectbroker.hh
new file mode 100644
index 0000000..bb8d429
--- /dev/null
+++ b/reladminif/objectbroker.hh
@@ -0,0 +1,506 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#ifndef _OBJECTBROKER_HH_
+#define _OBJECTBROKER_HH_
+
+class ObjectBroker;
+class ULongType;
+class LongType;
+class CharType;
+class BoolType;
+class UShortType;
+class ShortType;
+class OctetType;
+class DoubleType;
+class FloatType;
+class ComplexType1;
+class ComplexType2;
+class StructType;
+class BaseType;
+class SetType;
+class MDDType;
+class Type;
+class DBObject;
+
+#include "oidif.hh"
+#include "raslib/error.hh"
+#include "lists.h"
+
+#ifdef RMANBENCHMARK
+#include "raslib/rmdebug.hh"
+#endif
+
+//@ManMemo: Module: {\bf reladminif}.
+/*@Doc:
+the ObjectBroker is one of the three columns one which the persistence layer rests:
+ObjectBroker, DBRef, DBObject.
+the ObjectBroker keeps track of all persistent objects which are loaded into memory.
+objects register themselves at this facility and deregister themselves when they are
+deleted.
+
+The ObjectBroker supplies functionality for accessing persistent objects by oid and by
+name.
+The ObjectBroker can be configured to serve as a cross transaction cache.
+The ObejctBroker can retrieve the oids of all objects of a specific type which are stored
+in the database.
+The list of objects which are kept by the ObjectBroker are cleared by TransactionIf.
+*/
+
+class ObjectBroker
+ {
+ public:
+ static bool freeMemory() throw (r_Error);
+ /*@Doc:
+ this will handle the memory issue.
+ returns true if memory was freed, false otherwise.
+ if false is returned there is really to much memory allocated and the transaction should be stopped.
+ */
+
+ static void deregisterTileIndexMapping(const OId& tileoid, const OId& indexoid);
+ /*@Doc:
+ deletes the object in the correct list
+ */
+
+ static void registerTileIndexMapping(const OId& tileoid, const OId& indexoid);
+ /*@Doc:
+ inserts the object in the correct list
+ */
+
+ static void registerDBObject(DBObject* object);
+ /*@Doc:
+ inserts the object in the correct list
+ */
+
+ static void deregisterDBObject(const OId& id);
+ /*@Doc:
+ removes the object with the specified oid from the list
+ */
+
+ static DBObject* getObjectByOId(const OId& id) throw (r_Error);
+ /*@Doc:
+ retrieve a dbobject from db. passes (r_Error)s from DBObject up.
+ */
+
+ static DBObject* isInMemory(const OId& id) throw (r_Error);
+ /*@Doc:
+ does not retrieve the object from db. only retrieves from memory.
+ if there is no matching object a 0 pointer is returned.
+ throws an (r_Error) if the OId has a invalid type
+ */
+
+ static OIdSet* getAllObjects(OId::OIdType type);
+ /*@Doc:
+ generates a list of all objects in the db and in memory with the
+ specified type. the vector must be deleted by the calling function
+ */
+
+ static MDDType* getMDDTypeByName(const char* name) throw (r_Error);
+ /*@Doc:
+ retrieves an object with that name and that type from the db.
+ this method was introduced to remove the spurious sqlwarnings.
+ passes (r_Error)s from DBObject up or ObjectNotFound when there is
+ no matching object
+ */
+
+ static DBObject* getObjectByName(OId::OIdType type, const char* name) throw (r_Error);
+ /*@Doc:
+ retrieves an object with that name and that type from the db.
+ passes (r_Error)s from DBObject up or ObjectNotFound when there is
+ no matching object
+ */
+
+ static void clearBroker() throw (r_Error);
+ /*@Doc:
+ deletes persistent objects from memory, depending on cache ofcourse.
+ any (r_Error)s thrown during the deletion/update/insert process are
+ handed up. the objects are removed before errors can occur. multiple
+ calls to clearBroker until the method completes are possible. memory
+ leaks may occur in this event.
+ */
+
+ static void clearCache() throw (r_Error);
+ /*@Doc:
+ deletes _all_ persistent objects from memory.
+ any (r_Error)s thrown during the deletion/update/insert process are
+ handed up. the objects are removed before errors can occur. multiple
+ calls to clearBroker until the method completes are possible. memory
+ leaks may occur in this event.
+ */
+
+ static void init();
+ /*@Doc:
+ initialize the atomic types and maps
+ */
+
+ static void deinit();
+ /*@Doc:
+ delete the atomic types and maps
+ */
+
+ static DBObjectPMap& getMap(OId::OIdType type) throw (r_Error);
+ /*@Doc:
+ returns a pointer to the store of objects of that particular type.
+ (r_Error) is thrown if there is no map for that type
+ */
+
+ protected:
+ static DBObject* loadDBMDDObj(const OId& id) throw (r_Error);
+ /*@Doc:
+ retrieves MDDObjects from memory and from database
+ */
+
+ static DBObject* loadMDDSet(const OId& id) throw (r_Error);
+ /*@Doc:
+ retrieves MDDSets from memory and from database
+ */
+
+ static DBObject* loadMDDType(const OId& id) throw (r_Error);
+ /*@Doc:
+ retrieves MDDTypes from memory and from database
+ */
+
+ static DBObject* loadMDDBaseType(const OId& id) throw (r_Error);
+ /*@Doc:
+ retrieves MDDBaseTypes from memory and from database
+ */
+
+ static DBObject* loadMDDDimensionType(const OId& id) throw (r_Error);
+ /*@Doc:
+ retrieves MDDDimTypes from memory and from database
+ */
+
+ static DBObject* loadMDDDomainType(const OId& id) throw (r_Error);
+ /*@Doc:
+ retrieves MDDDomTypes from memory and from database
+ */
+
+ static DBObject* loadStructType(const OId& id) throw (r_Error);
+ /*@Doc:
+ retrieves StructTypes from memory and from database
+ */
+
+ static DBObject* loadSetType(const OId& id) throw (r_Error);
+ /*@Doc:
+ retrieves SetTypes from memory and from database
+ */
+
+ static DBObject* loadBLOBTile(const OId& id) throw (r_Error);
+ /*@Doc:
+ retrieves BLOBTiles from memory and from database.
+ knows how to get a inlinetile from a dbtcindex.
+ */
+
+ static DBObject* loadDBMinterval(const OId& id) throw (r_Error);
+ /*@Doc:
+ retrieves DBMintervals from memory and from database
+ */
+
+ static DBObject* loadDBStorage(const OId& id) throw (r_Error);
+ /*@Doc:
+ retrieves DBStorageLayout from memory and from database
+ */
+
+ static DBObject* loadDBHierIndex(const OId& id) throw (r_Error);
+ /*@Doc:
+ retrieves HierIxs from memory and from database
+ */
+
+ static DBObject* loadDBTCIndex(const OId& id) throw (r_Error);
+ /*@Doc:
+ retrieves DBTCIndex from memory and from database
+ */
+
+ static DBObject* loadInlineTile(const OId& id) throw (r_Error);
+ /*@Doc:
+ retrieves InlineTiles from memory and from database
+ */
+
+ static DBObject* loadDBRCIndexDS(const OId& id) throw (r_Error);
+ /*@Doc:
+ retrieves DBRCIndexDS from memory and from database
+ */
+
+ static OId getOIdByName(OId::OIdType type, const char* name) throw (r_Error);
+ /*@Doc:
+ finds the oid of an object with the given type and name
+ */
+
+ static void clearMap(DBObjectPMap& theMap) throw (r_Error);
+ /*@Doc:
+ deletes entries in this map as long as they are not cached
+ (r_Error) is thrown when there is a problem in ~DBObject.
+ the object is removed from the map though.
+ */
+
+ static void completelyClearMap(DBObjectPMap& theMap) throw (r_Error);
+ /*@Doc:
+ deletes entries in this map
+ (r_Error) is thrown when there is a problem in ~DBObject.
+ the object is removed from the map though.
+ */
+
+
+ static OId getOIdOfMDDSet(const char* name) throw (r_Error);
+ /*@Doc:
+ retrieves MDDSets from memory and from database
+ */
+
+ static OId getOIdOfMDDType(const char* name) throw (r_Error);
+ /*@Doc:
+ retrieves MDDTypes from memory and from database
+ */
+
+ static OId getOIdOfMDDBaseType(const char* name) throw (r_Error);
+ /*@Doc:
+ retrieves MDDBaseTypes from memory and from database
+ */
+
+ static OId getOIdOfMDDDimensionType(const char* name) throw (r_Error);
+ /*@Doc:
+ retrieves MDDDimTypes from memory and from database
+ */
+
+ static OId getOIdOfMDDDomainType(const char* name) throw (r_Error);
+ /*@Doc:
+ retrieves MDDDomTypes from memory and from database
+ */
+
+ static OId getOIdOfStructType(const char* name) throw (r_Error);
+ /*@Doc:
+ retrieves StructTypes from memory and from database
+ */
+
+ static OId getOIdOfSetType(const char* name) throw (r_Error);
+ /*@Doc:
+ retrieves SetTypes from memory and from database
+ */
+
+ static OIdSet* getAllMDDObjects() throw (r_Error);
+ /*@Doc:
+ retrieves the oids of all MDD Objects from memory and from database
+ oidlist must be deallocated by the caller
+ (r_Error) occures in a database failure
+ */
+
+ static OIdSet* getAllMDDSets() throw (r_Error);
+ /*@Doc:
+ retrieves the oids of all MDDSets from memory and from database
+ oidlist must be deallocated by the caller
+ (r_Error) occures in a database failure
+ */
+
+ static OIdSet* getAllMDDTypes() throw (r_Error);
+ /*@Doc:
+ retrieves the oids of all MDDTypes from memory and from database
+ oidlist must be deallocated by the caller
+ (r_Error) occures in a database failure
+ */
+
+ static OIdSet* getAllMDDBaseTypes() throw (r_Error);
+ /*@Doc:
+ retrieves the oids of all MDDBaseTypes from memory and from database
+ oidlist must be deallocated by the caller
+ (r_Error) occures in a database failure
+ */
+
+ static OIdSet* getAllMDDDimensionTypes() throw (r_Error);
+ /*@Doc:
+ retrieves the oids of all MDDDimTypes from memory and from database
+ oidlist must be deallocated by the caller
+ (r_Error) occures in a database failure
+ */
+
+ static OIdSet* getAllMDDDomainTypes() throw (r_Error);
+ /*@Doc:
+ retrieves the oids of all MDDDomTypes from memory and from database
+ oidlist must be deallocated by the caller
+ (r_Error) occures in a database failure
+ */
+
+ static OIdSet* getAllStructTypes() throw (r_Error);
+ /*@Doc:
+ retrieves the oids of all StructTypes from memory and from database
+ oidlist must be deallocated by the caller
+ (r_Error) occures in a database failure
+ */
+
+ static OIdSet* getAllSetTypes() throw (r_Error);
+ /*@Doc:
+ retrieves the oids of all SetTypes from memory and from database
+ oidlist must be deallocated by the caller
+ (r_Error) occures in a database failure
+ */
+
+ static OIdSet* getAllAtomicTypes() throw (r_Error);
+ /*@Doc:
+ retrieves the oids of all AtomicTypes from memory
+ oidlist must be deallocated by the caller
+ (r_Error) should never occur
+ */
+
+ private:
+ ///the types have to be in fornt of* the maps because of static destructor!
+ static ULongType* theULong;
+ /*@Doc:
+ a pointer to this member is returned by getObjectByOId().
+ */
+
+ static CharType* theChar;
+ /*@Doc:
+ a pointer to this member is returned by getObjectByOId().
+ */
+
+ static BoolType* theBool;
+ /*@Doc:
+ a pointer to this member is returned by getObjectByOId().
+ */
+
+ static UShortType* theUShort;
+ /*@Doc:
+ a pointer to this member is returned by getObjectByOId().
+ */
+
+ static LongType* theLong;
+ /*@Doc:
+ a pointer to this member is returned by getObjectByOId().
+ */
+
+ static ShortType* theShort;
+ /*@Doc:
+ a pointer to this member is returned by getObjectByOId().
+ */
+
+ static OctetType* theOctet;
+ /*@Doc:
+ a pointer to this member is returned by getObjectByOId().
+ */
+
+ static DoubleType* theDouble;
+ /*@Doc:
+ a pointer to this member is returned by getObjectByOId().
+ */
+
+ static FloatType* theFloat;
+ /*@Doc:
+ a pointer to this member is returned by getObjectByOId().
+ */
+
+ static ComplexType1* theComplex1;
+ /*@Doc:
+ a pointer to this member is returned by getObjectByOId().
+ */
+
+ static ComplexType2* theComplex2;
+ /*@Doc:
+ a pointer to this member is returned by getObjectByOId().
+ */
+
+ static DBObjectPMap theDBMDDObjs;
+ /*@Doc:
+ holds all MDDObjects in memory
+ */
+
+ static DBObjectPMap theMDDSets;
+ /*@Doc:
+ holds all MDDSets in memory
+ */
+
+ static DBObjectPMap theMDDTypes;
+ /*@Doc:
+ holds all MDDTypes in memory
+ */
+
+ static DBObjectPMap theMDDBaseTypes;
+ /*@Doc:
+ holds all MDDBaseTypes in memory
+ */
+
+ static DBObjectPMap theMDDDimensionTypes;
+ /*@Doc:
+ holds all MDDDimTypes in memory
+ */
+
+ static DBObjectPMap theMDDDomainTypes;
+ /*@Doc:
+ holds all MDDDomTypes in memory
+ */
+
+ static DBObjectPMap theStructTypes;
+ /*@Doc:
+ holds all StructTypes in memory
+ */
+
+ static DBObjectPMap theSetTypes;
+ /*@Doc:
+ holds all SetTypes in memory
+ */
+
+ static DBObjectPMap theBLOBTiles;
+ /*@Doc:
+ holds all BLOBTiles in memory
+ */
+
+ static DBObjectPMap theDBMintervals;
+ /*@Doc:
+ holds all DBMintervals in memory
+ */
+
+ static DBObjectPMap theDBStorages;
+ /*@Doc:
+ holds all MDDEntries in memory
+ */
+
+ static DBObjectPMap theDBHierIndexs;
+ /*@Doc:
+ holds all HierIxs in memory
+ */
+
+ static DBObjectPMap theDBTCIndexs;
+ /*@Doc:
+ holds all HierIxs in memory
+ */
+
+ static DBObjectPMap theInlineTiles;
+ /*@Doc:
+ holds all InlineTiles in memory
+ */
+
+ static DBObjectPMap theAtomicTypes;
+ /*@Doc:
+ holds all SetTypes in memory
+ */
+
+ static DBObjectPMap theRCIndexes;
+ /*@Doc:
+ holds all RC Indexes in memory
+ */
+
+ static OIdMap theTileIndexMappings;
+ /*@Doc:
+ key (first/double) is oid of tile, value (second/oid) is oid of index.
+ */
+
+ };
+
+#endif
+
diff --git a/reladminif/objectbroker.pgc b/reladminif/objectbroker.pgc
new file mode 100644
index 0000000..9313d9c
--- /dev/null
+++ b/reladminif/objectbroker.pgc
@@ -0,0 +1,1029 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+// This is -*- C++ -*-
+
+/*************************************************************************
+ *
+ *
+ * PURPOSE:
+ * Code with embedded SQL for PostgreSQL DBMS
+ *
+ *
+ * COMMENTS:
+ * none
+ *
+ ***********************************************************************/
+
+static const char rcsid[] = "@(#)reladminif,ObjectBroker: $Id: objectbroker.ec,v 1.4 2003/12/27 23:11:43 rasdev Exp $";
+
+#include "debug-srv.hh"
+
+// general embedded SQL related definitions
+EXEC SQL include "sqlglobals.h";
+
+#include "objectbroker.hh"
+#include "raslib/rmdebug.hh"
+#include "sqlerror.hh"
+#include "relindexif/dbtcindex.hh"
+#include "relindexif/indexid.hh"
+#include "adminif.hh"
+#include "relindexif/dbrcindexds.hh"
+#include "relblobif/inlinetile.hh"
+#include "dbref.hh"
+#include "dbnamedobject.hh"
+#include "externs.h"
+#include "catalogmgr/typefactory.hh"
+
+DBObject*
+ObjectBroker::loadInlineTile(const OId& id) throw (r_Error)
+{
+ RMDBGENTER(11, RMDebug::module_adminif, "ObjectBroker", "loadInlineTile(" << id << ")");
+ ENTER( "ObjectBroker::loadInlineTile, oid=" << id );
+
+ DBObject* retval = 0;
+ OIdMap::iterator i = theTileIndexMappings.find(id);
+ if (i != theTileIndexMappings.end())
+ {
+ DBTCIndexId dbtc((*i).second);
+ retval = (DBObject*)dbtc->getInlineTile(id);
+ }
+ else
+ {
+ try
+ {
+ retval = new InlineTile(id);
+ RMDBGMIDDLE(11, RMDebug::module_adminif, "ObjectBroker", "found in db");
+ }
+ catch (r_Error& error)
+ {
+ RMDBGMIDDLE(11, RMDebug::module_adminif, "ObjectBroker", "not found in db");
+ if(retval)
+ {
+ delete retval;
+ retval=0;
+ }
+ }
+ if (retval == 0)
+ {
+ EXEC SQL BEGIN DECLARE SECTION;
+ long indexid;
+ long inlineid;
+ EXEC SQL END DECLARE SECTION;
+
+ indexid = 0;
+ inlineid = id.getCounter();
+
+ EXEC SQL SELECT
+ IndexId
+ INTO
+ :indexid
+ FROM
+ RAS_ITMAP
+ WHERE
+ TileId = :inlineid;
+ if (SQLCODE == SQLOK)
+ {
+ DBTCIndexId dbtc(OId(indexid, OId::DBTCINDEXOID));
+ retval = (DBObject*)dbtc->getInlineTile(id);
+ }
+ else
+ {
+ if (SQLCODE == SQLNODATAFOUND)
+ {
+ RMDBGEXIT(11, RMDebug::module_adminif, "ObjectBroker", "db error not found in db");
+ throw r_Error(r_Error::r_Error_ObjectUnknown);
+ }
+ else
+ {
+ check("ObjectBroker::loadInlineTile SELECT FROM RAS_ITMAP");
+ generateException();
+ }
+ }
+ }
+ DBObjectPPair myPair(retval->getOId(), retval);
+ theInlineTiles.insert(myPair);
+ }
+
+ LEAVE( "ObjectBroker::loadInlineTile, retval=" << retval );
+ RMDBGEXIT(11, RMDebug::module_adminif, "ObjectBroker", "loadInlineTile(" << id << ")");
+ return retval;
+}
+
+
+OId
+ObjectBroker::getOIdOfSetType(const char* name) throw (r_Error)
+{
+ ENTER( "ObjectBroker::getOIdOfSetType, name=" << name );
+
+ EXEC SQL BEGIN DECLARE SECTION;
+ char setname[STRING_MAXLEN];
+ long setoid;
+ EXEC SQL END DECLARE SECTION;
+
+ OId retval;
+ int len = strlen(name);
+ if (len > DBNamedObject::MAXNAMELENGTH)
+ {
+ throw r_Error(TYPENAMEISTOOLONG);
+ }
+ (void) strncpy( setname, (char*) name, (size_t) sizeof(setname) );
+
+ EXEC SQL SELECT
+ SetTypeId
+ INTO
+ :setoid
+ FROM
+ RAS_SETTYPES
+ WHERE
+ SetTypeName = :setname;
+
+ if (SQLCODE != SQLOK)
+ {
+ if (SQLCODE == SQLNODATAFOUND)
+ {
+ RMDBGONCE(11, RMDebug::module_adminif, "ObjectBroker", "is not in db");
+ throw r_Error(r_Error::r_Error_ObjectUnknown);
+ }
+ else
+ {
+ check("ObjectBroker::getOIdOfSetType()\0");
+ generateException();
+ }
+ }
+ else
+ {
+ retval = OId(setoid, OId::SETTYPEOID);
+ RMDBGONCE(11, RMDebug::module_adminif, "ObjectBroker", "is in db with " << retval);
+ }
+
+ LEAVE( "ObjectBroker::getOIdOfSetType, retval=" << retval );
+ return retval;
+}
+
+MDDType*
+ObjectBroker::getMDDTypeByName(const char* name) throw (r_Error)
+{
+ ENTER( "ObjectBroker::getMDDTypeByName, name=" << name );
+
+ EXEC SQL BEGIN DECLARE SECTION;
+ char mddtnamev[STRING_MAXLEN];
+ double mddtoidv;
+ EXEC SQL END DECLARE SECTION;
+
+ MDDType* retval = 0;
+ DBObjectPMap* theMaps[] = {&theMDDTypes, &theMDDBaseTypes, &theMDDDimensionTypes, &theMDDDomainTypes};
+
+ // FIXME: why do we iterate 5 times?
+ for (int a = 0; a < 4; a++)
+ {
+ DBObjectPMap& theMap = *theMaps[a];
+ //check if there is an object with that name already in memory
+ for (DBObjectPMap::iterator iter = theMap.begin(); iter != theMap.end(); iter++)
+ {
+ if (strcmp(((DBNamedObject*)(*iter).second)->getName(), name) == 0)
+ {
+ //RMDBGMIDDLE(11, RMDebug::module_adminif, "ObjectBroker", name << " equals " << ((DBNamedObject*)(*iter).second)->getName());
+ retval = (MDDType*)(*iter).second;
+ break;
+ }
+ else
+ {
+ //RMDBGMIDDLE(11, RMDebug::module_adminif, "ObjectBroker", name << " equals NOT " << ((DBNamedObject*)(*iter).second)->getName());
+ }
+ }
+ if (retval != 0)
+ break;
+ }
+
+ if (retval == 0)
+ {
+ int len = strlen(name);
+ if (len > DBNamedObject::MAXNAMELENGTH)
+ {
+ LEAVE( "ObjectBroker::getMDDTypeByName(): type name exceeding max length: " << name );
+ throw r_Error(TYPENAMEISTOOLONG);
+ }
+ (void) strncpy( mddtnamev, (char*) name, (size_t) sizeof(mddtnamev) );
+
+ TALK( "EXEC SQL SELECT MDDTypeOId INTO :mddtoidv FROM RAS_MDDTYPES_VIEW WHERE MDDTypeName = " << mddtnamev );
+ EXEC SQL SELECT MDDTypeOId
+ INTO :mddtoidv
+ FROM RAS_MDDTYPES_VIEW
+ WHERE MDDTypeName = :mddtnamev;
+
+ if (SQLCODE != SQLOK)
+ {
+ if (SQLCODE == SQLNODATAFOUND)
+ {
+ RMDBGONCE(11, RMDebug::module_adminif, "ObjectBroker", "is not in db");
+ LEAVE( "ObjectBroker::getMDDTypeByName(): object not found" );
+ throw r_Error(r_Error::r_Error_ObjectUnknown);
+ }
+ else
+ {
+ check("ObjectBroker::getMDDTypeByName()\0");
+ LEAVE( "ObjectBroker::getMDDTypeByName(): database access error: " << SQLCODE );
+ generateException();
+ }
+ }
+ else
+ {
+ retval = (MDDType*)getObjectByOId(OId(mddtoidv));
+ }
+ }
+
+ LEAVE( "ObjectBroker::getMDDTypeByName, retval=" << retval );
+ return retval;
+}
+
+OId
+ObjectBroker::getOIdOfMDDType(const char* name) throw (r_Error)
+{
+ ENTER( "ObjectBroker::getOIdOfMDDType, name=" << name );
+
+ EXEC SQL BEGIN DECLARE SECTION;
+ char mddtname[STRING_MAXLEN];
+ long mddtoid;
+ EXEC SQL END DECLARE SECTION;
+
+ OId retval;
+ int len = strlen(name);
+ if (len > DBNamedObject::MAXNAMELENGTH)
+ {
+ LEAVE( "ObjectBroker::getOIdOfMDDType(): name exceeds max length:" << name );
+ throw r_Error(TYPENAMEISTOOLONG);
+ }
+ (void) strncpy( mddtname, (char*) name, (size_t) sizeof(mddtname) );
+
+ TALK( "EXEC SQL SELECT MDDTypeOId INTO :mddtoid FROM RAS_MDDTYPES WHERE MDDTypeName = " << mddtname );
+ EXEC SQL SELECT MDDTypeOId
+ INTO :mddtoid
+ FROM RAS_MDDTYPES
+ WHERE MDDTypeName = :mddtname;
+
+ if (SQLCODE != SQLOK)
+ {
+ if (SQLCODE == SQLNODATAFOUND)
+ {
+ RMDBGONCE(11, RMDebug::module_adminif, "ObjectBroker", "is not in db");
+ LEAVE( "ObjectBroker::getOIdOfMDDType(): object not in db" );
+ throw r_Error(r_Error::r_Error_ObjectUnknown);
+ }
+ else
+ {
+ check("ObjectBroker::getOIdOfMDDType()\0");
+ LEAVE( "ObjectBroker::getOIdOfMDDType(): db access error: " << SQLCODE );
+ generateException();
+ }
+ }
+ else
+ {
+ retval = OId(mddtoid,OId::MDDTYPEOID);
+ }
+
+ LEAVE( "ObjectBroker::getOIdOfMDDType, retval=" << retval );
+ return retval;
+}
+
+OId
+ObjectBroker::getOIdOfMDDBaseType(const char* name) throw (r_Error)
+{
+ ENTER( "ObjectBroker::getOIdOfMDDBaseType, name=" << name );
+
+ EXEC SQL BEGIN DECLARE SECTION;
+ char mddbname[STRING_MAXLEN];
+ long mddboid;
+ EXEC SQL END DECLARE SECTION;
+
+ OId retval;
+ int len = strlen(name);
+ if (len > DBNamedObject::MAXNAMELENGTH)
+ {
+ LEAVE( "ObjectBroker::getOIdOfMDDBaseType(): name exceeds max length:" << name );
+ throw r_Error(TYPENAMEISTOOLONG);
+ }
+ (void) strncpy( mddbname, (char*) name, (size_t) sizeof(mddbname) );
+
+ TALK( "EXEC SQL SELECT MDDBaseTypeOId INTO :mddboid FROM RAS_MDDBASETYPES WHERE MDDTypeName = " << mddbname );
+ EXEC SQL SELECT MDDBaseTypeOId
+ INTO :mddboid
+ FROM RAS_MDDBASETYPES
+ WHERE MDDTypeName = :mddbname;
+
+ if (SQLCODE != SQLOK)
+ {
+ if (SQLCODE == SQLNODATAFOUND)
+ {
+ RMDBGONCE(11, RMDebug::module_adminif, "ObjectBroker", "is not in db");
+ LEAVE( "ObjectBroker::getOIdOfMDDBaseType(): object not in db" );
+ throw r_Error(r_Error::r_Error_ObjectUnknown);
+ }
+ else
+ {
+ check("ObjectBroker::getOIdOfMDDBaseType()\0");
+ LEAVE( "ObjectBroker::getOIdOfMDDBaseType(): db access error: " << SQLCODE );
+ generateException();
+ }
+ }
+ else
+ {
+ retval = OId(mddboid,OId::MDDBASETYPEOID);
+ }
+
+ LEAVE( "ObjectBroker::getOIdOfMDDBaseType, retval=" << retval );
+ return retval;
+}
+
+OId
+ObjectBroker::getOIdOfMDDDimensionType(const char* name) throw (r_Error)
+{
+ ENTER( "ObjectBroker::getOIdOfMDDDimensionType, name=" << name );
+
+ EXEC SQL BEGIN DECLARE SECTION;
+ char mdddiname[STRING_MAXLEN];
+ long mdddioid;
+ EXEC SQL END DECLARE SECTION;
+
+ OId retval;
+ int len = strlen(name);
+ if (len > DBNamedObject::MAXNAMELENGTH)
+ {
+ LEAVE( "ObjectBroker::getOIdOfMDDDimensionType(): name exceeds max length:" << name );
+ throw r_Error(TYPENAMEISTOOLONG);
+ }
+ (void) strncpy( mdddiname, (char*) name, (size_t) sizeof(mdddiname) );
+
+ TALK( "EXEC SQL SELECT MDDDimTypeOId INTO :mdddioid FROM RAS_MDDDIMTYPES WHERE MDDTypeName = " << mdddiname );
+ EXEC SQL SELECT MDDDimTypeOId
+ INTO :mdddioid
+ FROM RAS_MDDDIMTYPES
+ WHERE MDDTypeName = :mdddiname;
+
+ if (SQLCODE != SQLOK)
+ {
+ if (SQLCODE == SQLNODATAFOUND)
+ {
+ RMDBGONCE(11, RMDebug::module_adminif, "ObjectBroker", "is not in db");
+ LEAVE( "ObjectBroker::getOIdOfMDDDimensionType(): object not in db" );
+ throw r_Error(r_Error::r_Error_ObjectUnknown);
+ }
+ else
+ {
+ check("ObjectBroker::getOIdOfMDDDimensionType()\0");
+ LEAVE( "ObjectBroker::getOIdOfMDDDimensionType(): db access error: " << SQLCODE );
+ generateException();
+ }
+ }
+ else
+ {
+ retval = OId(mdddioid,OId::MDDDIMTYPEOID);
+ }
+
+ LEAVE( "ObjectBroker::getOIdOfMDDDimensionType, retval=" << retval );
+ return retval;
+}
+
+OId
+ObjectBroker::getOIdOfMDDDomainType(const char* name) throw (r_Error)
+{
+ ENTER( "ObjectBroker::getOIdOfMDDDomainType, name=" << name );
+
+ EXEC SQL BEGIN DECLARE SECTION;
+ char mdddoname[STRING_MAXLEN];
+ long mdddooid;
+ EXEC SQL END DECLARE SECTION;
+
+ OId retval;
+ int len = strlen(name);
+ if (len > DBNamedObject::MAXNAMELENGTH)
+ {
+ LEAVE( "ObjectBroker::getOIdOfMDDDomainType(): name exceeds max length:" << name );
+ throw r_Error(TYPENAMEISTOOLONG);
+ }
+ (void) strncpy( mdddoname, (char*) name, (size_t) sizeof(mdddoname) );
+
+ TALK( "EXEC SQL SELECT MDDDomTypeOId INTO :mdddooid FROM RAS_MDDDOMTYPES WHERE MDDTypeName = " << mdddoname );
+ EXEC SQL SELECT MDDDomTypeOId
+ INTO :mdddooid
+ FROM RAS_MDDDOMTYPES
+ WHERE MDDTypeName = :mdddoname;
+
+ if (SQLCODE != SQLOK)
+ {
+ if (SQLCODE == SQLNODATAFOUND)
+ {
+ RMDBGONCE(11, RMDebug::module_adminif, "ObjectBroker", "is not in db");
+ LEAVE( "ObjectBroker::getOIdOfMDDDomainType(): object not in db" );
+ throw r_Error(r_Error::r_Error_ObjectUnknown);
+ }
+ else
+ {
+ check("ObjectBroker::getOIdOfMDDDomainType()\0");
+ LEAVE( "ObjectBroker::getOIdOfMDDDomainType(): db access error: " << SQLCODE );
+ generateException();
+ }
+ }
+ else
+ {
+ retval = OId(mdddooid,OId::MDDDOMTYPEOID);
+ }
+
+ LEAVE( "ObjectBroker::getOIdOfMDDDomainType, retval=" << retval );
+ return retval;
+}
+
+OId
+ObjectBroker::getOIdOfStructType(const char* name) throw (r_Error)
+{
+ ENTER( "ObjectBroker::getOIdOfStructType, name=" << name );
+
+ EXEC SQL BEGIN DECLARE SECTION;
+ char structname[STRING_MAXLEN];
+ long structoid;
+ EXEC SQL END DECLARE SECTION;
+
+ OId retval;
+ int len = strlen(name);
+ if (len > DBNamedObject::MAXNAMELENGTH)
+ {
+ LEAVE( "ObjectBroker::getOIdOfStructType(): name exceeds max length:" << name );
+ throw r_Error(TYPENAMEISTOOLONG);
+ }
+ (void) strncpy( structname, (char*) name, (size_t) sizeof(structname) );
+
+ TALK( "EXEC SQL SELECT BaseTypeId INTO :structoid FROM RAS_BASETYPENAMES WHERE BaseTypeName = " << structname );
+ EXEC SQL SELECT BaseTypeId
+ INTO :structoid
+ FROM RAS_BASETYPENAMES
+ WHERE BaseTypeName = :structname;
+
+ if (SQLCODE != SQLOK)
+ {
+ RMDBGONCE(11, RMDebug::module_adminif, "ObjectBroker", "is not in db");
+ if (SQLCODE == SQLNODATAFOUND)
+ {
+ RMDBGONCE(11, RMDebug::module_adminif, "ObjectBroker", "is not in db");
+ LEAVE( "ObjectBroker::getOIdOfStructType(): object not in db" );
+ throw r_Error(r_Error::r_Error_ObjectUnknown);
+ }
+ else
+ {
+ check("ObjectBroker::getOIdOfStructType()\0");
+ LEAVE( "ObjectBroker::getOIdOfStructType(): db access error: " << SQLCODE );
+ generateException();
+ }
+ }
+ else
+ {
+ retval = OId(structoid, OId::STRUCTTYPEOID);
+ RMDBGONCE(11, RMDebug::module_adminif, "ObjectBroker", "is in db with " << retval);
+ }
+
+ LEAVE( "ObjectBroker::getOIdOfStructType, retval=" << retval );
+ return retval;
+}
+
+OId
+ObjectBroker::getOIdOfMDDSet(const char* name) throw (r_Error)
+{
+ ENTER( "ObjectBroker::getOIdOfMDDSet, name=" << name );
+
+ EXEC SQL BEGIN DECLARE SECTION;
+ char collname[STRING_MAXLEN];
+ long colloid;
+ EXEC SQL END DECLARE SECTION;
+
+ OId retval;
+ int len = strlen(name);
+ if (len > DBNamedObject::MAXNAMELENGTH)
+ {
+ LEAVE( "ObjectBroker::getOIdOfMDDSet(): name exceeds max length:" << name );
+ throw r_Error(TYPENAMEISTOOLONG);
+ }
+ (void) strncpy( collname, (char*) name, (size_t) sizeof(collname) );
+
+ TALK( "EXEC SQL SELECT MDDCollId INTO :colloid FROM RAS_MDDCOLLNAMES WHERE MDDCollName = " << collname );
+ EXEC SQL SELECT MDDCollId
+ INTO :colloid
+ FROM RAS_MDDCOLLNAMES
+ WHERE MDDCollName = :collname;
+
+ if (SQLCODE != SQLOK)
+ {
+ if (SQLCODE == SQLNODATAFOUND)
+ {
+ RMDBGONCE(11, RMDebug::module_adminif, "ObjectBroker", "is not in db");
+ LEAVE( "ObjectBroker::getOIdOfMDDSet(): object not in db" );
+ throw r_Error(r_Error::r_Error_ObjectUnknown);
+ }
+ else
+ {
+ check("ObjectBroker::getOIdOfMDDSet()\0");
+ LEAVE( "ObjectBroker::getOIdOfMDDSet(): db access error: " << SQLCODE );
+ generateException();
+ }
+ }
+ else
+ {
+ retval = OId(colloid, OId::MDDCOLLOID);
+ RMDBGONCE(11, RMDebug::module_adminif, "ObjectBroker", "is in db with " << retval);
+ }
+
+ LEAVE( "ObjectBroker::getOIdOfMDDSet, retval=" << retval );
+ return retval;
+}
+
+OIdSet*
+ObjectBroker::getAllSetTypes() throw (r_Error)
+{
+ RMDBGENTER(11, RMDebug::module_adminif, "ObjectBroker", "getAllSetTypes()");
+ ENTER( "ObjectBroker::getAllSetTypes" );
+
+ OIdSet* retval = new OIdSet();
+ DBObjectPMap& theMap = ObjectBroker::getMap(OId::SETTYPEOID);
+ for (DBObjectPMap::iterator i = theMap.begin(); i != theMap.end(); i++)
+ {
+ RMDBGMIDDLE(11, RMDebug::module_adminif, "ObjectBroker", "inserted from memory " << (*i).first);
+ retval->insert((*i).first);
+ }
+ OId id;
+
+ EXEC SQL BEGIN DECLARE SECTION;
+ long settoid1;
+ EXEC SQL END DECLARE SECTION;
+
+ TALK( "EXEC SQL DECLARE setcursor CURSOR FOR SELECT SetTypeId FROM RAS_SETTYPES ORDER BY SetTypeId" );
+ EXEC SQL DECLARE setcursor CURSOR FOR
+ SELECT SetTypeId
+ FROM RAS_SETTYPES
+ ORDER BY SetTypeId;
+
+ TALK( "EXEC SQL OPEN setcursor" );
+ EXEC SQL OPEN setcursor;
+
+ do
+ {
+ TALK( "EXEC SQL FETCH setcursor INTO :settoid1" );
+ EXEC SQL FETCH setcursor INTO :settoid1;
+ if (SQLCODE != SQLOK)
+ {
+ if (SQLCODE != SQLNODATAFOUND)
+ {
+ check("ObjectBroker::getAllSetTypes\0");
+ TALK( "EXEC SQL CLOSE setcursor" );
+ EXEC SQL CLOSE setcursor;
+ delete retval;
+ retval = 0;
+ LEAVE( "ObjectBroker::getAllSetTypes(): db access error: " << SQLCODE );
+ generateException();
+ }
+ break;
+ }
+ id = OId(settoid1, OId::SETTYPEOID);
+ RMDBGMIDDLE(11, RMDebug::module_adminif, "ObjectBroker", "read " << id << " " << id.getType());
+ TALK( "got object " << id << " " << id.getType());
+ retval->insert(id);
+ } while (1);
+
+ TALK( "EXEC SQL CLOSE setcursor" );
+ EXEC SQL CLOSE setcursor;
+
+ LEAVE( "ObjectBroker::getAllSetTypes, SQLCODE=" << SQLCODE );
+ RMDBGEXIT(11, RMDebug::module_adminif, "ObjectBroker", "getAllSetTypes() ");
+ return retval;
+}
+
+OIdSet*
+ObjectBroker::getAllMDDTypes() throw (r_Error)
+{
+ RMDBGENTER(11, RMDebug::module_adminif, "ObjectBroker", "getAllMDDTypes()");
+ ENTER( "ObjectBroker::getAllMDDTypes" );
+
+ OIdSet* retval = new OIdSet();
+ DBObjectPMap& theMap = ObjectBroker::getMap(OId::MDDTYPEOID);
+ for (DBObjectPMap::iterator i = theMap.begin(); i != theMap.end(); i++)
+ {
+ RMDBGMIDDLE(11, RMDebug::module_adminif, "ObjectBroker", "inserted from memory " << (*i).first);
+ retval->insert((*i).first);
+ }
+ OId id;
+
+ EXEC SQL BEGIN DECLARE SECTION;
+ long mddtoid1;
+ EXEC SQL END DECLARE SECTION;
+
+ TALK( "EXEC SQL DECLARE mddtcursor CURSOR FOR SELECT MDDTypeOId FROM RAS_MDDTYPES ORDER BY MDDTypeOId" );
+ EXEC SQL DECLARE mddtcursor CURSOR FOR
+ SELECT MDDTypeOId
+ FROM RAS_MDDTYPES
+ ORDER BY MDDTypeOId;
+
+ TALK( "EXEC SQL OPEN mddtcursor" );
+ EXEC SQL OPEN mddtcursor;
+
+ do
+ {
+ TALK( "EXEC SQL FETCH mddtcursor INTO :mddtoid1" ) ;
+ EXEC SQL FETCH mddtcursor INTO :mddtoid1;
+ if (SQLCODE != SQLOK)
+ {
+ if (SQLCODE != SQLNODATAFOUND)
+ {
+ check("ObjectBroker::getAllMDDTypes()\0");
+ EXEC SQL CLOSE mddtcursor;
+ delete retval;
+ retval = 0;
+ LEAVE( "ObjectBroker::getAllMDDTypes(): db access error: " << SQLCODE );
+ generateException();
+ }
+ break;
+ }
+ id = OId(mddtoid1, OId::MDDTYPEOID);
+ RMDBGMIDDLE(11, RMDebug::module_adminif, "ObjectBroker", "read " << id << " " << id.getType());
+ TALK( "got object " << id << " " << id.getType() );
+ retval->insert(id);
+ } while (1);
+
+ TALK( "EXEC SQL CLOSE mddtcursor" );
+ EXEC SQL CLOSE mddtcursor;
+
+ LEAVE( "ObjectBroker::getAllMDDTypes, retval=" << retval );
+ RMDBGEXIT(11, RMDebug::module_adminif, "ObjectBroker", "getAllMDDTypes() ");
+ return retval;
+}
+
+OIdSet*
+ObjectBroker::getAllMDDBaseTypes() throw (r_Error)
+{
+ RMDBGENTER(11, RMDebug::module_adminif, "ObjectBroker", "getAllMDDBaseTypes()");
+ ENTER( "ObjectBroker::getAllMDDBaseTypes" );
+
+ OIdSet* retval = new OIdSet();
+ DBObjectPMap& theMap = ObjectBroker::getMap(OId::MDDBASETYPEOID);
+ for (DBObjectPMap::iterator i = theMap.begin(); i != theMap.end(); i++)
+ {
+ RMDBGMIDDLE(11, RMDebug::module_adminif, "ObjectBroker", "inserted from memory " << (*i).first);
+ retval->insert((*i).first);
+ }
+ OId id;
+
+ EXEC SQL BEGIN DECLARE SECTION;
+ long mddboid1;
+ EXEC SQL END DECLARE SECTION;
+
+ TALK( "EXEC SQL DECLARE mddbcursor CURSOR FOR SELECT MDDBaseTypeOId FROM RAS_MDDBASETYPES ORDER BY MDDBaseTypeOId" );
+ EXEC SQL DECLARE mddbcursor CURSOR FOR
+ SELECT MDDBaseTypeOId
+ FROM RAS_MDDBASETYPES
+ ORDER BY MDDBaseTypeOId;
+
+ TALK( "EXEC SQL OPEN mddbcursor" );
+ EXEC SQL OPEN mddbcursor;
+
+ do
+ {
+ TALK( "EXEC SQL FETCH mddbcursor INTO :mddboid1" );
+ EXEC SQL FETCH mddbcursor INTO :mddboid1;
+ if (SQLCODE != SQLOK)
+ {
+ if (SQLCODE != SQLNODATAFOUND)
+ {
+ check("ObjectBroker::getAllMDDBaseTypes()\0");
+ EXEC SQL CLOSE mddbcursor;
+ delete retval;
+ retval = 0;
+ LEAVE( "ObjectBroker::getAllMDDBaseTypes(): db access error: " << SQLCODE );
+ generateException();
+ }
+ break;
+ }
+ id = OId(mddboid1, OId::MDDBASETYPEOID);
+ RMDBGMIDDLE(11, RMDebug::module_adminif, "ObjectBroker", "read " << id << " " << id.getType());
+ TALK( "got object " << id << " " << id.getType() );
+ retval->insert(id);
+ } while (1);
+
+ TALK( "EXEC SQL CLOSE mddbcursor" );
+ EXEC SQL CLOSE mddbcursor;
+
+ LEAVE( "ObjectBroker::getAllMDDBaseTypes, retval=" << retval );
+ RMDBGEXIT(11, RMDebug::module_adminif, "ObjectBroker", "getAllMDDBaseTypes() ");
+ return retval;
+}
+
+OIdSet*
+ObjectBroker::getAllMDDDimensionTypes() throw (r_Error)
+{
+ RMDBGENTER(11, RMDebug::module_adminif, "ObjectBroker", "getAllMDDDimensionTypes()");
+ ENTER( "ObjectBroker::getAllMDDDimensionTypes" );
+
+ OIdSet* retval = new OIdSet();
+ DBObjectPMap& theMap = ObjectBroker::getMap(OId::MDDDIMTYPEOID);
+ for (DBObjectPMap::iterator i = theMap.begin(); i != theMap.end(); i++)
+ {
+ RMDBGMIDDLE(11, RMDebug::module_adminif, "ObjectBroker", "inserted from memory " << (*i).first);
+ retval->insert((*i).first);
+ }
+ OId id;
+
+ EXEC SQL BEGIN DECLARE SECTION;
+ long mdddioid1;
+ EXEC SQL END DECLARE SECTION;
+
+ TALK( "EXEC SQL DECLARE mdddicursor CURSOR FOR SELECT MDDDimTypeOId FROM RAS_MDDDIMTYPES ORDER BY MDDDimTypeOId" );
+ EXEC SQL DECLARE mdddicursor CURSOR FOR
+ SELECT MDDDimTypeOId
+ FROM RAS_MDDDIMTYPES
+ ORDER BY MDDDimTypeOId;
+
+ TALK( "EXEC SQL OPEN mdddicursor" );
+ EXEC SQL OPEN mdddicursor;
+
+ do
+ {
+ TALK( "EXEC SQL FETCH mdddicursor INTO :mdddioid1" );
+ EXEC SQL FETCH mdddicursor INTO :mdddioid1;
+ if (SQLCODE != SQLOK)
+ {
+ if (SQLCODE != SQLNODATAFOUND)
+ {
+ check("ObjectBroker::getAllMDDDimensionTypes()\0");
+ EXEC SQL CLOSE mdddicursor;
+ delete retval;
+ retval = 0;
+ LEAVE( "ObjectBroker::getAllMDDDimensionTypes(): db access error: " << SQLCODE );
+ generateException();
+ }
+ break;
+ }
+ id = OId(mdddioid1, OId::MDDDIMTYPEOID);
+ RMDBGMIDDLE(11, RMDebug::module_adminif, "ObjectBroker", "read " << id << " " << id.getType());
+ TALK( "got object " << id << " " << id.getType() );
+ retval->insert(id);
+ } while (1);
+
+ TALK( "EXEC SQL CLOSE mdddicursor" );
+ EXEC SQL CLOSE mdddicursor;
+
+ LEAVE( "ObjectBroker::getAllMDDDimensionTypes, retval=" << retval );
+ RMDBGEXIT(11, RMDebug::module_adminif, "ObjectBroker", "getAllMDDDimensionTypes() ");
+ return retval;
+}
+
+OIdSet*
+ObjectBroker::getAllMDDDomainTypes() throw (r_Error)
+{
+ RMDBGENTER(11, RMDebug::module_adminif, "ObjectBroker", "getAllMDDDomainTypes()");
+ ENTER( "ObjectBroker::getAllMDDDomainTypes" );
+
+ OIdSet* retval = new OIdSet();
+ DBObjectPMap& theMap = ObjectBroker::getMap(OId::MDDDOMTYPEOID);
+ for (DBObjectPMap::iterator i = theMap.begin(); i != theMap.end(); i++)
+ {
+ RMDBGMIDDLE(11, RMDebug::module_adminif, "ObjectBroker", "inserted from memory " << (*i).first);
+ retval->insert((*i).first);
+ }
+ OId id;
+
+ EXEC SQL BEGIN DECLARE SECTION;
+ long mdddooid1;
+ EXEC SQL END DECLARE SECTION;
+
+ TALK( "EXEC SQL DECLARE mdddocursor CURSOR FOR SELECT MDDDomTypeOId FROM RAS_MDDDOMTYPES ORDER BY MDDDomTypeOId" );
+ EXEC SQL DECLARE mdddocursor CURSOR FOR
+ SELECT MDDDomTypeOId
+ FROM RAS_MDDDOMTYPES
+ ORDER BY MDDDomTypeOId;
+
+ TALK( "EXEC SQL OPEN mdddocursor" );
+ EXEC SQL OPEN mdddocursor;
+
+ do
+ {
+ TALK( "EXEC SQL FETCH mdddocursor INTO :mdddooid1" );
+ EXEC SQL FETCH mdddocursor INTO :mdddooid1;
+ if (SQLCODE != SQLOK)
+ {
+ if (SQLCODE != SQLNODATAFOUND)
+ {
+ check("ObjectBroker::getAllMDDDomainTypes()\0");
+ EXEC SQL CLOSE mdddocursor;
+ delete retval;
+ retval = 0;
+ LEAVE( "ObjectBroker::getAllMDDDomainTypes(): db access error: " << SQLCODE );
+ generateException();
+ }
+ break;
+ }
+ id = OId(mdddooid1, OId::MDDDOMTYPEOID);
+ RMDBGMIDDLE(11, RMDebug::module_adminif, "ObjectBroker", "read " << id << " " << id.getType());
+ TALK( "got object " << id << " " << id.getType() );
+ retval->insert(id);
+ } while (1);
+ TALK( "EXEC SQL CLOSE mdddocursor" );
+ EXEC SQL CLOSE mdddocursor;
+
+ LEAVE( "ObjectBroker::getAllMDDDomainTypes" );
+ RMDBGEXIT(11, RMDebug::module_adminif, "ObjectBroker", "getAllMDDDomainTypes() ");
+ return retval;
+}
+
+OIdSet*
+ObjectBroker::getAllStructTypes() throw (r_Error)
+{
+ RMDBGENTER(11, RMDebug::module_adminif, "ObjectBroker", "getAllStructTypes()");
+ ENTER( "ObjectBroker::getAllStructTypes" );
+
+ OIdSet* retval = new OIdSet();
+ DBObjectPMap& theMap = ObjectBroker::getMap(OId::STRUCTTYPEOID);
+ for (DBObjectPMap::iterator i = theMap.begin(); i != theMap.end(); i++)
+ {
+ RMDBGMIDDLE(11, RMDebug::module_adminif, "ObjectBroker", "inserted from memory " << (*i).first);
+ retval->insert((*i).first);
+ }
+ OId id;
+
+ EXEC SQL BEGIN DECLARE SECTION;
+ long structoid1;
+ short maxbuiltin;
+ EXEC SQL END DECLARE SECTION;
+
+ maxbuiltin = TypeFactory::MaxBuiltInId;
+
+ TALK( "EXEC SQL DECLARE structcursor CURSOR FOR SELECT BaseTypeId FROM RAS_BASETYPENAMES ORDER BY BaseTypeId" );
+ EXEC SQL DECLARE structcursor CURSOR FOR
+ SELECT BaseTypeId
+ FROM RAS_BASETYPENAMES
+ ORDER BY BaseTypeId;
+
+ TALK( "EXEC SQL OPEN structcursor" );
+ EXEC SQL OPEN structcursor;
+
+ do
+ {
+ TALK( "EXEC SQL FETCH structcursor INTO :structoid1" );
+ EXEC SQL FETCH structcursor INTO :structoid1;
+ if (SQLCODE != SQLOK)
+ {
+ if (SQLCODE != SQLNODATAFOUND)
+ {
+ check("ObjectBroker::getAllStructTypes()\0");
+ EXEC SQL CLOSE structcursor;
+ delete retval;
+ retval = 0;
+ LEAVE( "ObjectBroker::getAllStructTypes(): db access error: " << SQLCODE );
+ generateException();
+ }
+ break;
+ }
+ id = OId(structoid1, OId::STRUCTTYPEOID);
+ RMDBGMIDDLE(11, RMDebug::module_adminif, "ObjectBroker", "read " << id << " " << id.getType());
+ TALK( "got object " << id << " " << id.getType() );
+ retval->insert(id);
+ } while (1);
+ TALK( "EXEC SQL CLOSE structcursor" );
+ EXEC SQL CLOSE structcursor;
+
+ LEAVE( "ObjectBroker::getAllStructTypes, retval=" << retval );
+ RMDBGEXIT(11, RMDebug::module_adminif, "ObjectBroker", "getAllStructTypes() ");
+ return retval;
+}
+
+OIdSet*
+ObjectBroker::getAllMDDObjects() throw (r_Error)
+{
+ RMDBGENTER(11, RMDebug::module_adminif, "ObjectBroker", "getAllMDDObjects()");
+ ENTER( "ObjectBroker::getAllMDDObjects" );
+
+ OIdSet* retval = new OIdSet();
+ DBObjectPMap& theMap = ObjectBroker::getMap(OId::MDDOID);
+ for (DBObjectPMap::iterator i = theMap.begin(); i != theMap.end(); i++)
+ {
+ RMDBGMIDDLE(11, RMDebug::module_adminif, "ObjectBroker", "inserted from memory " << (*i).first);
+ retval->insert((*i).first);
+ }
+ OId id;
+
+ EXEC SQL BEGIN DECLARE SECTION;
+ long mddobjoid1;
+ EXEC SQL END DECLARE SECTION;
+
+ TALK(" EXEC SQL DECLARE mddobjcursor CURSOR FOR SELECT MDDId FROM RAS_MDDOBJECTS ORDER BY MDDId" );
+ EXEC SQL DECLARE mddobjcursor CURSOR FOR
+ SELECT MDDId
+ FROM RAS_MDDOBJECTS
+ ORDER BY MDDId;
+
+ TALK( "EXEC SQL OPEN mddobjcursor" );
+ EXEC SQL OPEN mddobjcursor;
+
+ do
+ {
+ TALK( "EXEC SQL FETCH mddobjcursor INTO :mddobjoid1" );
+ EXEC SQL FETCH mddobjcursor INTO :mddobjoid1;
+ if (SQLCODE != SQLOK)
+ {
+ if (SQLCODE != SQLNODATAFOUND)
+ {
+ check("ObjectBroker::getAllMDDObjects()\0");
+ EXEC SQL CLOSE mddobjcursor;
+ delete retval;
+ retval = 0;
+ RMDBGEXIT(11, RMDebug::module_adminif, "ObjectBroker", "Database Failed");
+ LEAVE( "ObjectBroker::getAllMDDObjects(): db access error: " << SQLCODE );
+ generateException();
+ }
+ break;
+ }
+ id = OId(mddobjoid1, OId::MDDOID);
+ RMDBGMIDDLE(11, RMDebug::module_adminif, "ObjectBroker", "read " << id << " " << id.getType());
+ TALK( "got object " << id << " " << id.getType() );
+ retval->insert(id);
+ } while (1);
+ TALK( "EXEC SQL CLOSE mddobjcursor" );
+ EXEC SQL CLOSE mddobjcursor;
+
+ LEAVE( "ObjectBroker::getAllMDDObjects, retval=" << retval );
+ RMDBGEXIT(11, RMDebug::module_adminif, "ObjectBroker", "getAllMDDObjects() ");
+ return retval;
+}
+
+OIdSet*
+ObjectBroker::getAllMDDSets() throw (r_Error)
+{
+ RMDBGENTER(11, RMDebug::module_adminif, "ObjectBroker", "getAllMDDSets()");
+ ENTER( "ObjectBroker::getAllMDDSets" );
+
+ OIdSet* retval = new OIdSet();
+ DBObjectPMap& theMap = ObjectBroker::getMap(OId::MDDCOLLOID);
+ for (DBObjectPMap::iterator i = theMap.begin(); i != theMap.end(); i++)
+ {
+ RMDBGMIDDLE(11, RMDebug::module_adminif, "ObjectBroker", "inserted from memory " << (*i).first);
+ retval->insert((*i).first);
+ }
+ OId id;
+
+ EXEC SQL BEGIN DECLARE SECTION;
+ long colloid1;
+ EXEC SQL END DECLARE SECTION;
+
+ TALK( "EXEC SQL DECLARE collcursor CURSOR FOR SELECT MDDCollId FROM RAS_MDDCOLLNAMES ORDER BY MDDCollId" );
+ EXEC SQL DECLARE collcursor CURSOR FOR
+ SELECT MDDCollId
+ FROM RAS_MDDCOLLNAMES
+ ORDER BY MDDCollId;
+
+ TALK(" EXEC SQL OPEN collcursor" );
+ EXEC SQL OPEN collcursor;
+
+ do
+ {
+ TALK( "EXEC SQL FETCH collcursor INTO :colloid1" );
+ EXEC SQL FETCH collcursor INTO :colloid1;
+ if (SQLCODE != SQLOK)
+ {
+ if (SQLCODE != SQLNODATAFOUND)
+ {
+ check("ObjectBroker::getAllMDDSets()\0");
+ EXEC SQL CLOSE collcursor;
+ delete retval;
+ retval = 0;
+ RMDBGEXIT(11, RMDebug::module_adminif, "ObjectBroker", "Database Failed");
+ LEAVE( "ObjectBroker::getAllMDDSets(): db access error: " << SQLCODE );
+ generateException();
+ }
+ break;
+ }
+ id = OId(colloid1, OId::MDDCOLLOID);
+ RMDBGMIDDLE(11, RMDebug::module_adminif, "ObjectBroker", "read " << id << " " << id.getType());
+ TALK( "got object " << id << " " << id.getType() );
+ retval->insert(id);
+ } while (1);
+ TALK( "EXEC SQL CLOSE collcursor" );
+ EXEC SQL CLOSE collcursor;
+
+ LEAVE( "ObjectBroker::getAllMDDSets, retval=" << retval );
+ RMDBGEXIT(11, RMDebug::module_adminif, "ObjectBroker", "getAllMDDSets() ");
+ return retval;
+}
+
diff --git a/reladminif/objectbrokercommon.cc b/reladminif/objectbrokercommon.cc
new file mode 100644
index 0000000..648f3c6
--- /dev/null
+++ b/reladminif/objectbrokercommon.cc
@@ -0,0 +1,1144 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include <map>
+#include <set>
+#include <cstring>
+#include <cstdlib>
+
+#include "raslib/rmdebug.hh"
+#include "raslib/minterval.hh"
+#include "objectbroker.hh"
+#include "dbnamedobject.hh"
+#include "relstorageif/dbstoragelayout.hh"
+#include "adminif.hh"
+#include "relcatalogif/alltypes.hh"
+#include "relindexif/hierindex.hh"
+#include "relblobif/blobtile.hh"
+#include "relcatalogif/dbminterval.hh"
+#include "relblobif/inlinetile.hh"
+#include "relindexif/dbtcindex.hh"
+#include "sqlerror.hh"
+#include "relindexif/indexid.hh"
+#include "relmddif/mddid.hh"
+#include "dbref.hh"
+#include "relmddif/dbmddobj.hh"
+#include "catalogmgr/typefactory.hh"
+#include "relmddif/dbmddset.hh"
+#include "relindexif/dbrcindexds.hh"
+#include "debug.hh"
+
+#ifdef LINUX
+template class DBRef<BLOBTile>;
+template class DBRef<DBTile>;
+template class DBRef<InlineTile>;
+#endif
+
+using namespace std;
+
+LongType*
+ObjectBroker::theLong = 0;
+
+ShortType*
+ObjectBroker::theShort = 0;
+
+OctetType*
+ObjectBroker::theOctet = 0;
+
+ULongType*
+ObjectBroker::theULong = 0;
+
+UShortType*
+ObjectBroker::theUShort = 0;
+
+CharType*
+ObjectBroker::theChar = 0;
+
+BoolType*
+ObjectBroker::theBool = 0;
+
+DoubleType*
+ObjectBroker::theDouble = 0;
+
+FloatType*
+ObjectBroker::theFloat = 0;
+
+ComplexType1*
+ObjectBroker::theComplex1 = 0;
+
+ComplexType2*
+ObjectBroker::theComplex2 = 0;
+
+DBObjectPMap
+ObjectBroker::theAtomicTypes;
+
+DBObjectPMap
+ObjectBroker::theSetTypes;
+
+DBObjectPMap
+ObjectBroker::theMDDTypes;
+
+DBObjectPMap
+ObjectBroker::theMDDBaseTypes;
+
+DBObjectPMap
+ObjectBroker::theMDDDimensionTypes;
+
+DBObjectPMap
+ObjectBroker::theMDDDomainTypes;
+
+DBObjectPMap
+ObjectBroker::theStructTypes;
+
+DBObjectPMap
+ObjectBroker::theDBMintervals;
+
+DBObjectPMap
+ObjectBroker::theDBMDDObjs;
+
+DBObjectPMap
+ObjectBroker::theMDDSets;
+
+DBObjectPMap
+ObjectBroker::theDBStorages;
+
+DBObjectPMap
+ObjectBroker::theDBHierIndexs;
+
+DBObjectPMap
+ObjectBroker::theDBTCIndexs;
+
+DBObjectPMap
+ObjectBroker::theBLOBTiles;
+
+DBObjectPMap
+ObjectBroker::theInlineTiles;
+
+DBObjectPMap
+ObjectBroker::theRCIndexes;
+
+OIdMap
+ObjectBroker::theTileIndexMappings;
+
+bool
+ObjectBroker::freeMemory() throw (r_Error)
+ {
+ RMDBGONCE(0, RMDebug::module_adminif, "ObjectBroker", "memoryOverFlow()");
+ bool retval = false;
+ DBRef<BLOBTile>::setPointerCaching(false);
+ DBRef<DBTile>::setPointerCaching(false);
+ DBRef<InlineTile>::setPointerCaching(false);
+ if (!ObjectBroker::theBLOBTiles.empty())
+ {
+ int theLucky = ObjectBroker::theBLOBTiles.size() / 2;
+ DBObjectPMap::iterator it = ObjectBroker::theBLOBTiles.begin();
+ for (int i = 0; i < theLucky; i++, it++);
+ delete (*it).second;
+ retval = true;
+ }
+ return retval;
+ }
+
+void
+ObjectBroker::init()
+ {
+ RMDBGENTER(2, RMDebug::module_adminif, "ObjectBroker", "init()");
+ ObjectBroker::theLong = new LongType();
+
+ ObjectBroker::theShort = new ShortType();
+
+ ObjectBroker::theOctet = new OctetType();
+
+ ObjectBroker::theULong = new ULongType();
+
+ ObjectBroker::theUShort = new UShortType();
+
+ ObjectBroker::theChar = new CharType();
+
+ ObjectBroker::theBool = new BoolType();
+
+ ObjectBroker::theDouble = new DoubleType();
+
+ ObjectBroker::theFloat = new FloatType();
+
+ ObjectBroker::theComplex1 = new ComplexType1();
+
+ ObjectBroker::theComplex2 = new ComplexType2();
+
+ DBObject* atomicTypes[] = {theComplex2, theComplex1, theFloat, theDouble, theOctet, theShort, theLong, theUShort, theBool, theChar, theULong};
+ RMDBGIF(0, RMDebug::module_adminif, "ObjectBroker", \
+ if (sizeof(atomicTypes)/sizeof(DBObject*) != TypeFactory::MaxBuiltInId) \
+ { \
+ RMInit::logOut << "ObjectBroker::init() not all atomic types were added!" << endl; \
+ exit(1); \
+ } )
+ for (unsigned int a = 0; a < sizeof(atomicTypes)/sizeof(DBObject*); a++)
+ {
+ DBObjectPPair myPair(atomicTypes[a]->getOId(), atomicTypes[a]);
+ theAtomicTypes.insert(myPair);
+ }
+ RMDBGEXIT(2, RMDebug::module_adminif, "ObjectBroker", "init()");
+ }
+
+void
+ObjectBroker::deinit()
+ {
+ RMDBGONCE(2, RMDebug::module_adminif, "ObjectBroker", "deinit()");
+ if (ObjectBroker::theLong != 0)
+ {
+ delete ObjectBroker::theLong;
+ ObjectBroker::theLong = 0;
+ }
+
+ if (ObjectBroker::theShort != 0)
+ {
+ delete ObjectBroker::theShort;
+ ObjectBroker::theShort = 0;
+ }
+
+ if (ObjectBroker::theOctet != 0)
+ {
+ delete ObjectBroker::theOctet;
+ ObjectBroker::theOctet = 0;
+ }
+
+ if (ObjectBroker::theULong != 0)
+ {
+ delete ObjectBroker::theULong;
+ ObjectBroker::theULong = 0;
+ }
+
+ if (ObjectBroker::theUShort != 0)
+ {
+ delete ObjectBroker::theUShort;
+ ObjectBroker::theUShort = 0;
+ }
+
+ if (ObjectBroker::theChar != 0)
+ {
+ delete ObjectBroker::theChar;
+ ObjectBroker::theChar = 0;
+ }
+
+ if (ObjectBroker::theBool != 0)
+ {
+ delete ObjectBroker::theBool;
+ ObjectBroker::theBool = 0;
+ }
+
+ if (ObjectBroker::theDouble != 0)
+ {
+ delete ObjectBroker::theDouble;
+ ObjectBroker::theDouble = 0;
+ }
+
+ if (ObjectBroker::theFloat != 0)
+ {
+ delete ObjectBroker::theFloat;
+ ObjectBroker::theFloat = 0;
+ }
+
+ if (ObjectBroker::theComplex1 != 0)
+ {
+ delete ObjectBroker::theComplex1;
+ ObjectBroker::theComplex1 = 0;
+ }
+
+ if (ObjectBroker::theComplex2 != 0)
+ {
+ delete ObjectBroker::theComplex2;
+ ObjectBroker::theComplex2 = 0;
+ }
+
+ theAtomicTypes.clear();
+
+ theSetTypes.clear();
+
+ theMDDTypes.clear();
+
+ theMDDBaseTypes.clear();
+
+ theMDDDimensionTypes.clear();
+
+ theMDDDomainTypes.clear();
+
+ theStructTypes.clear();
+
+ theDBMintervals.clear();
+
+ theDBMDDObjs.clear();
+
+ theMDDSets.clear();
+
+ theDBStorages.clear();
+
+ theDBHierIndexs.clear();
+
+ theDBTCIndexs.clear();
+
+ theBLOBTiles.clear();
+
+ theInlineTiles.clear();
+
+ theRCIndexes.clear();
+
+ theTileIndexMappings.clear();
+ }
+
+DBObject*
+ObjectBroker::getObjectByOId(const OId& id) throw (r_Error)
+ {
+ RMDBGENTER(11, RMDebug::module_adminif, "ObjectBroker", "getObjectByOId(" << id << " " << id.getType() << ")");
+ DBObject* retval = 0;
+ if (id.getType() == OId::INVALID)
+ retval = 0;
+ else {
+ retval = ObjectBroker::isInMemory(id);
+ if (retval == 0)
+ {
+ switch (id.getType())
+ {
+ case OId::MDDOID:
+ retval = loadDBMDDObj(id);
+ break;
+ case OId::MDDCOLLOID:
+ retval = loadMDDSet(id);
+ break;
+ case OId::MDDTYPEOID:
+ retval = loadMDDType(id);
+ break;
+ case OId::MDDBASETYPEOID:
+ retval = loadMDDBaseType(id);
+ break;
+ case OId::MDDDIMTYPEOID:
+ retval = loadMDDDimensionType(id);
+ break;
+ case OId::MDDDOMTYPEOID:
+ retval = loadMDDDomainType(id);
+ break;
+ case OId::STRUCTTYPEOID:
+ retval = loadStructType(id);
+ break;
+ case OId::SETTYPEOID:
+ retval = loadSetType(id);
+ break;
+ case OId::BLOBOID:
+ retval = loadBLOBTile(id);
+ break;
+ case OId::DBMINTERVALOID:
+ retval = loadDBMinterval(id);
+ break;
+ case OId::STORAGEOID:
+ retval = loadDBStorage(id);
+ break;
+ case OId::MDDHIERIXOID:
+ retval = loadDBHierIndex(id);
+ break;
+ case OId::DBTCINDEXOID:
+ retval = loadDBTCIndex(id);
+ break;
+ case OId::INLINETILEOID:
+ retval = loadInlineTile(id);
+ break;
+ case OId::MDDRCIXOID:
+ retval = loadDBRCIndexDS(id);
+ break;
+ case OId::ATOMICTYPEOID:
+ RMInit::logOut << "Atomic type not found in memory." << endl;
+ default:
+ RMDBGEXIT(11, RMDebug::module_adminif, "ObjectBroker", "getObjectByOId(" << id << " " << id.getType() << ")");
+ RMInit::logOut << "Retrival of Object Failed (Internal State 3)." << endl << "Please contact Customer Support." << endl;
+ throw r_Error(INVALID_OIDTYPE);
+ break;
+ }
+ }
+ }
+ RMDBGEXIT(11, RMDebug::module_adminif, "ObjectBroker", "getObjectByOId(" << id << " " << id.getType() << ") " << retval);
+ return retval;
+ }
+
+
+DBObject*
+ObjectBroker::isInMemory(const OId& id) throw (r_Error)
+ {
+ RMDBGENTER(11, RMDebug::module_adminif, "ObjectBroker", "isInMemory(" << id << " " << id.getType() << ")");
+ DBObject* retval = 0;
+ DBObjectPMap& theMap = ObjectBroker::getMap(id.getType());
+ DBObjectPMap::iterator i = theMap.find(id);
+ if (i != theMap.end())
+ {
+ retval = (*i).second;
+ RMDBGMIDDLE(11, RMDebug::module_adminif, "ObjectBroker", "found object with that id in map at " << (unsigned long)retval << " with id " << retval->getOId());
+ }
+ else {
+ RMDBGMIDDLE(11, RMDebug::module_adminif, "ObjectBroker", "did not find object with that id in map");
+ }
+ RMDBGEXIT(11, RMDebug::module_adminif, "ObjectBroker", "isInMemory(" << id << " ( " << id.getCounter() << " "<< id.getType() << " ) ) " << retval);
+ return retval;
+ }
+
+void
+ObjectBroker::registerDBObject(DBObject* obj)
+ {
+ DBObjectPPair myPair(obj->getOId(), obj);
+ ObjectBroker::getMap(obj->getOId().getType()).insert(myPair);
+ }
+
+void
+ObjectBroker::deregisterDBObject(const OId& id)
+ {
+ RMDBGENTER(11, RMDebug::module_adminif, "ObjectBroker", "deregisterDBObject(" << id << ")");
+ if (id.getType() != OId::INVALID)
+ {
+ RMDBGMIDDLE(11, RMDebug::module_adminif, "ObjectBroker", "size of map before\t: " << ObjectBroker::getMap(id.getType()).size());
+ DBObjectPMap& t = ObjectBroker::getMap(id.getType());
+ DBObjectPMap::iterator i = t.find(id);
+ if (i != t.end())
+ {
+ (*i).second = 0;
+ t.erase(i);
+ }
+ RMDBGMIDDLE(11, RMDebug::module_adminif, "ObjectBroker", "size of map after \t: " << ObjectBroker::getMap(id.getType()).size());
+ }
+ RMDBGEXIT(11, RMDebug::module_adminif, "ObjectBroker", "deregisterDBObject(" << id << ")");
+ }
+
+OIdSet*
+ObjectBroker::getAllObjects(OId::OIdType type)
+ {
+ OIdSet* retval = 0;
+ switch (type)
+ {
+ case OId::MDDCOLLOID:
+ retval = getAllMDDSets();
+ break;
+ case OId::MDDOID:
+ retval = getAllMDDObjects();
+ break;
+ case OId::MDDTYPEOID:
+ retval = getAllMDDTypes();
+ break;
+ case OId::MDDBASETYPEOID:
+ retval = getAllMDDBaseTypes();
+ break;
+ case OId::MDDDIMTYPEOID:
+ retval = getAllMDDDimensionTypes();
+ break;
+ case OId::MDDDOMTYPEOID:
+ retval = getAllMDDDomainTypes();
+ break;
+ case OId::STRUCTTYPEOID:
+ retval = getAllStructTypes();
+ break;
+ case OId::SETTYPEOID:
+ retval = getAllSetTypes();
+ break;
+ case OId::ATOMICTYPEOID:
+ retval = getAllAtomicTypes();
+ break;
+
+ default:
+ RMDBGONCE(11, RMDebug::module_adminif, "ObjectBroker", "getAllObjects(" << type << ")");
+ RMInit::logOut << "Retrival of Object Failed (Internal State 4)." << endl << "Please contact Customer Support." << endl;
+ throw r_Error(INVALID_OIDTYPE);
+ break;
+ }
+ return retval;
+ }
+
+
+OId
+ObjectBroker::getOIdByName(OId::OIdType type, const char* name) throw (r_Error)
+ {
+ RMDBGENTER(11, RMDebug::module_adminif, "ObjectBroker", "getOIdByName(" << type << ", " << name << ")");
+ OId id;
+ switch (type)
+ {
+ case OId::MDDCOLLOID:
+ id = getOIdOfMDDSet(name);
+ break;
+ case OId::MDDTYPEOID:
+ id = getOIdOfMDDType(name);
+ break;
+ case OId::MDDBASETYPEOID:
+ id = getOIdOfMDDBaseType(name);
+ break;
+ case OId::MDDDIMTYPEOID:
+ id = getOIdOfMDDDimensionType(name);
+ break;
+ case OId::MDDDOMTYPEOID:
+ id = getOIdOfMDDDomainType(name);
+ break;
+ case OId::STRUCTTYPEOID:
+ id = getOIdOfStructType(name);
+ break;
+ case OId::SETTYPEOID:
+ id = getOIdOfSetType(name);
+ break;
+ case OId::ATOMICTYPEOID:
+ if(strcmp(name, ULongType::Name) == 0)
+ id = theULong->getOId();
+ else if(strcmp(name, BoolType::Name) == 0)
+ id = theBool->getOId();
+ else if(strcmp(name, CharType::Name) == 0)
+ id = theChar->getOId();
+ else if(strcmp(name, UShortType::Name) == 0)
+ id = theUShort->getOId();
+ else if(strcmp(name, LongType::Name) == 0)
+ id = theLong->getOId();
+ else if(strcmp(name, ShortType::Name) == 0)
+ id = theShort->getOId();
+ else if(strcmp(name, OctetType::Name) == 0)
+ id = theOctet->getOId();
+ else if(strcmp(name, DoubleType::Name) == 0)
+ id = theDouble->getOId();
+ else if(strcmp(name, FloatType::Name) == 0)
+ id = theFloat->getOId();
+ else if(strcmp(name, ComplexType1::Name) == 0)
+ id = theComplex1->getOId();
+ else if(strcmp(name, ComplexType2::Name) == 0)
+ id = theComplex2->getOId();
+ break;
+
+ default:
+ RMDBGEXIT(11, RMDebug::module_adminif, "ObjectBroker", "getOIdByName(" << type << ", " << name << ")");
+ RMInit::logOut << "Retrival of Object Failed (Internal State 5)." << endl << "Please contact Customer Support." << endl;
+ throw r_Error(INVALID_OIDTYPE);
+ break;
+ }
+ RMDBGEXIT(11, RMDebug::module_adminif, "ObjectBroker", "getOIdByName(" << type << ", " << name << ") " << id << " " << id.getType());
+ return id;
+ }
+
+
+DBObject*
+ObjectBroker::getObjectByName(OId::OIdType type, const char* name) throw (r_Error)
+ {
+ RMDBGENTER(11, RMDebug::module_adminif, "ObjectBroker", "getObjectByName(" << type << ", " << name << ")");
+ DBObject* retval = 0;
+ DBObjectPMap* theMap = 0;
+ switch (type)
+ {
+ case OId::MDDCOLLOID:
+ theMap = &theMDDSets;
+ break;
+ case OId::MDDTYPEOID:
+ theMap = &theMDDTypes;
+ break;
+ case OId::MDDBASETYPEOID:
+ theMap = &theMDDBaseTypes;
+ break;
+ case OId::MDDDIMTYPEOID:
+ theMap = &theMDDDimensionTypes;
+ break;
+ case OId::MDDDOMTYPEOID:
+ theMap = &theMDDDomainTypes;
+ break;
+ case OId::STRUCTTYPEOID:
+ theMap = &theStructTypes;
+ break;
+ case OId::SETTYPEOID:
+ theMap = &theSetTypes;
+ break;
+ case OId::ATOMICTYPEOID:
+ theMap = &theAtomicTypes;
+ break;
+ default:
+ RMDBGEXIT(11, RMDebug::module_adminif, "ObjectBroker", "getObjectByName(" << type << ", " << name << ")");
+ RMInit::logOut << "Retrival of Object Failed (Internal State 6)." << endl << "Please contact Customer Support." << endl;
+ throw r_Error(INVALID_OIDTYPE);
+ break;
+ }
+
+ //check if there is an object with that name already in memory
+ for (DBObjectPMap::iterator iter = theMap->begin(); iter != theMap->end(); iter++)
+ {
+ if (strcmp(((DBNamedObject*)(*iter).second)->getName(), name) == 0)
+ {
+ RMDBGMIDDLE(11, RMDebug::module_adminif, "ObjectBroker", name << " equals " << ((DBNamedObject*)(*iter).second)->getName());
+ retval = (*iter).second;
+ break;
+ }
+ else {
+ RMDBGMIDDLE(11, RMDebug::module_adminif, "ObjectBroker", name << " equals NOT " << ((DBNamedObject*)(*iter).second)->getName());
+ }
+ }
+
+ //no - no matching object. try loading from db
+ if (!retval)
+ {
+ retval = ObjectBroker::getObjectByOId(ObjectBroker::getOIdByName(type,name));
+ }
+ RMDBGEXIT(11, RMDebug::module_adminif, "ObjectBroker", "getObjectByName(" << type << ", " << name << ") " << retval);
+ return retval;
+ }
+
+void
+ObjectBroker::clearMap(DBObjectPMap& theMap) throw (r_Error)
+ {
+ RMDBGENTER(11, RMDebug::module_adminif, "ObjectBroker", "clearMap()");
+ DBObjectPVector test;
+ test.reserve(theMap.size());
+ if (AdminIf::isAborted() || AdminIf::isReadOnlyTA())
+ {
+ //only delete objects that are modifed/not cached
+ for (DBObjectPMap::iterator i = theMap.begin(); i != theMap.end(); i++ )
+ {
+ if ((*i).second->isModified() || !(*i).second->isCached())
+ {
+ RMDBGMIDDLE(117, RMDebug::module_adminif, "ObjectBroker", "preparing to delete " << (*i).second->getOId() << " " << (*i).second->getOId().getType());
+ test.push_back((*i).second);
+ //(*i).second = 0; not good because of circular dependencies in the destructors
+ }
+ else {
+ RMDBGMIDDLE(11, RMDebug::module_adminif, "ObjectBroker", "leaving alone " << (*i).second->getOId() << " " << (*i).second->getOId().getType());
+ }
+ }
+ }
+ else {
+ //only delete objects that are not cached. validate the cached objects.
+ RMDBGMIDDLE(11, RMDebug::module_adminif, "ObjectBroker", "theMap are validated");
+ for (DBObjectPMap::iterator i = theMap.begin(); i != theMap.end(); i++ )
+ {
+ if ((*i).second->isCached())
+ {
+ RMDBGMIDDLE(117, RMDebug::module_adminif, "ObjectBroker", "leaving alone because of cache " << (*i).second->getOId() << " " << (*i).second->getOId().getType());
+ (*i).second->validate();
+ }
+ else {
+ RMDBGMIDDLE(11, RMDebug::module_adminif, "ObjectBroker", "preparing to delete " << (*i).second->getOId() << " " << (*i).second->getOId().getType());
+ test.push_back((*i).second);
+ //(*i).second = 0; not good because of circular dependencies in the destructors
+ }
+ }
+ }
+ for (DBObjectPVector::iterator i2 = test.begin(); i2 != test.end(); i2++)
+ {
+ RMDBGMIDDLE(11, RMDebug::module_adminif, "ObjectBroker", "deleting " << (*i2)->getOId() << " " << (*i2)->getOId().getType() << " size " << (*i2)->getMemorySize());
+ delete (*i2);
+ }
+ test.clear();
+ RMDBGEXIT(11, RMDebug::module_adminif, "ObjectBroker", "clearMap() ");
+ }
+
+void
+ObjectBroker::completelyClearMap(DBObjectPMap& theMap) throw (r_Error)
+ {
+ RMDBGENTER(11, RMDebug::module_adminif, "ObjectBroker", "completelyClearMap()");
+ DBObjectPVector test;
+ test.reserve(theMap.size());
+ for (DBObjectPMap::iterator i = theMap.begin(); i != theMap.end(); i++ )
+ {
+ RMDBGMIDDLE(11, RMDebug::module_adminif, "ObjectBroker", "preparing to delete " << (*i).second->getOId() << " " << (*i).second->getOId().getType());
+ (*i).second->validate();
+ test.push_back((*i).second);
+ //(*i).second = 0; not good because of circular dependencies in the destructors
+ }
+ for (DBObjectPVector::iterator i2 = test.begin(); i2 != test.end(); i2++)
+ {
+ RMDBGMIDDLE(11, RMDebug::module_adminif, "ObjectBroker", "deleting " << (*i2)->getOId() << " " << (*i2)->getOId().getType());
+ delete (*i2);
+ }
+ test.clear();
+ RMDBGEXIT(11, RMDebug::module_adminif, "ObjectBroker", "completelyClearMap() ");
+ }
+
+void
+ObjectBroker::clearBroker() throw (r_Error)
+ {
+ //do not ever clear the ATOMICTYPEOID map! those are on the stack, not heap!
+// ObjectBroker::completelyClearMap(ObjectBroker::getMap(OId::UDFOID));
+// ObjectBroker::completelyClearMap(ObjectBroker::getMap(OId::UDFPACKAGEOID));
+ ObjectBroker::completelyClearMap(ObjectBroker::getMap(OId::MDDCOLLOID));
+ ObjectBroker::completelyClearMap(ObjectBroker::getMap(OId::MDDOID));
+ ObjectBroker::completelyClearMap(ObjectBroker::getMap(OId::MDDHIERIXOID));
+ ObjectBroker::completelyClearMap(ObjectBroker::getMap(OId::MDDRCIXOID));
+ ObjectBroker::completelyClearMap(ObjectBroker::getMap(OId::DBTCINDEXOID));
+ ObjectBroker::completelyClearMap(ObjectBroker::getMap(OId::INLINETILEOID));
+ ObjectBroker::completelyClearMap(ObjectBroker::getMap(OId::STORAGEOID));
+ ObjectBroker::completelyClearMap(ObjectBroker::getMap(OId::SETTYPEOID));
+ ObjectBroker::completelyClearMap(ObjectBroker::getMap(OId::MDDDOMTYPEOID));
+ ObjectBroker::completelyClearMap(ObjectBroker::getMap(OId::MDDDIMTYPEOID));
+ ObjectBroker::completelyClearMap(ObjectBroker::getMap(OId::MDDBASETYPEOID));
+ ObjectBroker::completelyClearMap(ObjectBroker::getMap(OId::MDDTYPEOID));
+ ObjectBroker::completelyClearMap(ObjectBroker::getMap(OId::STRUCTTYPEOID));
+ ObjectBroker::completelyClearMap(ObjectBroker::getMap(OId::DBMINTERVALOID));
+ ObjectBroker::completelyClearMap(ObjectBroker::getMap(OId::BLOBOID));
+ theTileIndexMappings.clear();
+ }
+
+void
+ObjectBroker::clearCache() throw (r_Error)
+ {
+ //do not ever clear the ATOMICTYPEOID map! those are on the stack, not heap!
+// ObjectBroker::completelyClearMap(ObjectBroker::getMap(OId::UDFOID));
+// ObjectBroker::completelyClearMap(ObjectBroker::getMap(OId::UDFPACKAGEOID));
+ ObjectBroker::completelyClearMap(ObjectBroker::getMap(OId::MDDCOLLOID));
+ ObjectBroker::completelyClearMap(ObjectBroker::getMap(OId::MDDOID));
+ ObjectBroker::completelyClearMap(ObjectBroker::getMap(OId::MDDHIERIXOID));
+ ObjectBroker::completelyClearMap(ObjectBroker::getMap(OId::MDDRCIXOID));
+ ObjectBroker::completelyClearMap(ObjectBroker::getMap(OId::DBTCINDEXOID));
+ ObjectBroker::completelyClearMap(ObjectBroker::getMap(OId::INLINETILEOID));
+ ObjectBroker::completelyClearMap(ObjectBroker::getMap(OId::STORAGEOID));
+ ObjectBroker::completelyClearMap(ObjectBroker::getMap(OId::SETTYPEOID));
+ ObjectBroker::completelyClearMap(ObjectBroker::getMap(OId::MDDDOMTYPEOID));
+ ObjectBroker::completelyClearMap(ObjectBroker::getMap(OId::MDDDIMTYPEOID));
+ ObjectBroker::completelyClearMap(ObjectBroker::getMap(OId::MDDBASETYPEOID));
+ ObjectBroker::completelyClearMap(ObjectBroker::getMap(OId::MDDTYPEOID));
+ ObjectBroker::completelyClearMap(ObjectBroker::getMap(OId::STRUCTTYPEOID));
+ ObjectBroker::completelyClearMap(ObjectBroker::getMap(OId::DBMINTERVALOID));
+ ObjectBroker::completelyClearMap(ObjectBroker::getMap(OId::BLOBOID));
+ theTileIndexMappings.clear();
+ }
+
+DBObjectPMap&
+ObjectBroker::getMap(OId::OIdType type) throw (r_Error)
+ {
+ DBObjectPMap* theMap = 0;
+ switch (type)
+ {
+ case OId::MDDOID:
+ theMap = &theDBMDDObjs;
+ break;
+ case OId::MDDCOLLOID:
+ theMap = &theMDDSets;
+ break;
+ case OId::MDDTYPEOID:
+ theMap = &theMDDTypes;
+ break;
+ case OId::MDDBASETYPEOID:
+ theMap = &theMDDBaseTypes;
+ break;
+ case OId::MDDDIMTYPEOID:
+ theMap = &theMDDDimensionTypes;
+ break;
+ case OId::MDDDOMTYPEOID:
+ theMap = &theMDDDomainTypes;
+ break;
+ case OId::STRUCTTYPEOID:
+ theMap = &theStructTypes;
+ break;
+ case OId::SETTYPEOID:
+ theMap = &theSetTypes;
+ break;
+ case OId::BLOBOID:
+ theMap = &theBLOBTiles;
+ break;
+ case OId::INLINETILEOID:
+ theMap = &theInlineTiles;
+ break;
+ case OId::DBMINTERVALOID:
+ theMap = &theDBMintervals;
+ break;
+ case OId::STORAGEOID:
+ theMap = &theDBStorages;
+ break;
+ case OId::DBTCINDEXOID:
+ theMap = &theDBTCIndexs;
+ break;
+ case OId::MDDHIERIXOID:
+ theMap = &theDBHierIndexs;
+ break;
+ case OId::ATOMICTYPEOID:
+ theMap = &theAtomicTypes;
+ break;
+ case OId::MDDRCIXOID:
+ theMap = &theRCIndexes;
+ break;
+ default:
+ RMDBGONCE(11, RMDebug::module_adminif, "ObjectBroker", "getMap(" << type << ")");
+ RMInit::logOut << "Retrival of Object Failed (Internal State 7)." << endl << "Please contact Customer Support." << endl;
+ throw r_Error(INVALID_OIDTYPE);
+ break;
+ }
+ return *theMap;
+ }
+
+DBObject*
+ObjectBroker::loadDBStorage(const OId& id) throw (r_Error)
+ {
+ DBObject* retval = 0;
+ try {
+ retval = new DBStorageLayout(id);
+ RMDBGONCE(11, RMDebug::module_adminif, "ObjectBroker", "found in db");
+ DBObjectPPair myPair(retval->getOId(), retval);
+ theDBStorages.insert(myPair);
+ }
+ catch (r_Error& error)
+ {
+ RMDBGONCE(11, RMDebug::module_adminif, "ObjectBroker", "not found in db");
+ if(retval)
+ {
+ delete retval;
+ retval=0;
+ }
+ throw error;
+ }
+ return retval;
+ }
+
+DBObject*
+ObjectBroker::loadSetType(const OId& id) throw (r_Error)
+ {
+ DBObject* retval = 0;
+ try {
+ retval = new SetType(id);
+ RMDBGONCE(11, RMDebug::module_adminif, "ObjectBroker", "found in db");
+ DBObjectPPair myPair(retval->getOId(), retval);
+ theSetTypes.insert(myPair);
+ }
+ catch (r_Error& error)
+ {
+ RMDBGONCE(11, RMDebug::module_adminif, "ObjectBroker", "not found in db");
+ if(retval)
+ {
+ delete retval;
+ retval=0;
+ }
+ throw error;
+ }
+ return retval;
+ }
+
+DBObject*
+ObjectBroker::loadMDDType(const OId& id) throw (r_Error)
+ {
+ DBObject* retval = 0;
+ try {
+ retval = new MDDType(id);
+ RMDBGONCE(11, RMDebug::module_adminif, "ObjectBroker", "found in db");
+ DBObjectPPair myPair(retval->getOId(),retval);
+ theMDDTypes.insert(myPair);
+ }
+ catch (r_Error& error)
+ {
+ RMDBGONCE(11, RMDebug::module_adminif, "ObjectBroker", "not found in db");
+ if(retval)
+ {
+ delete retval;
+ retval=0;
+ }
+ throw error;
+ }
+ return retval;
+ }
+
+
+DBObject*
+ObjectBroker::loadMDDBaseType(const OId& id) throw (r_Error)
+ {
+ DBObject* retval = 0;
+ try {
+ retval = new MDDBaseType(id);
+ RMDBGONCE(11, RMDebug::module_adminif, "ObjectBroker", "found in db");
+ DBObjectPPair myPair(retval->getOId(), retval);
+ theMDDBaseTypes.insert(myPair);
+ }
+ catch (r_Error& error)
+ {
+ RMDBGONCE(11, RMDebug::module_adminif, "ObjectBroker", "not found in db");
+ if(retval)
+ {
+ delete retval;
+ retval=0;
+ }
+ throw error;
+ }
+ return retval;
+ }
+
+
+DBObject*
+ObjectBroker::loadMDDDimensionType(const OId& id) throw (r_Error)
+ {
+ DBObject* retval = 0;
+ try {
+ retval = new MDDDimensionType(id);
+ RMDBGONCE(11, RMDebug::module_adminif, "ObjectBroker", "found in db");
+ DBObjectPPair myPair(retval->getOId(), retval);
+ theMDDDimensionTypes.insert(myPair);
+ }
+ catch (r_Error& error)
+ {
+ RMDBGONCE(11, RMDebug::module_adminif, "ObjectBroker", "not found in db");
+ if(retval)
+ {
+ delete retval;
+ retval=0;
+ }
+ throw error;
+ }
+ return retval;
+ }
+
+
+DBObject*
+ObjectBroker::loadMDDDomainType(const OId& id) throw (r_Error)
+ {
+ DBObject* retval = 0;
+ try {
+ retval = new MDDDomainType(id);
+ RMDBGONCE(11, RMDebug::module_adminif, "ObjectBroker", "found in db");
+ DBObjectPPair myPair(retval->getOId(), retval);
+ theMDDDomainTypes.insert(myPair);
+ }
+ catch (r_Error& error)
+ {
+ RMDBGONCE(11, RMDebug::module_adminif, "ObjectBroker", "not found in db");
+ if(retval)
+ {
+ delete retval;
+ retval=0;
+ }
+ throw error;
+ }
+ return retval;
+ }
+
+
+DBObject*
+ObjectBroker::loadStructType(const OId& id) throw (r_Error)
+ {
+ DBObject* retval = 0;
+ try {
+ retval = new StructType(id);
+ RMDBGONCE(11, RMDebug::module_adminif, "ObjectBroker", "found in db");
+ DBObjectPPair myPair(retval->getOId(), retval);
+ theStructTypes.insert(myPair);
+ }
+ catch (r_Error& error)
+ {
+ RMDBGONCE(11, RMDebug::module_adminif, "ObjectBroker", "not found in db");
+ if(retval)
+ {
+ delete retval;
+ retval=0;
+ }
+ throw error;
+ }
+ return retval;
+ }
+
+
+DBObject*
+ObjectBroker::loadDBMinterval(const OId& id) throw (r_Error)
+ {
+ DBObject* retval = 0;
+ try {
+ retval = new DBMinterval(id);
+ RMDBGONCE(11, RMDebug::module_adminif, "ObjectBroker", "found in db");
+ DBObjectPPair myPair( retval->getOId(), retval);
+ theDBMintervals.insert(myPair);
+ }
+ catch (r_Error& error)
+ {
+ RMDBGONCE(11, RMDebug::module_adminif, "ObjectBroker", "not found in db");
+ if(retval)
+ {
+ delete retval;
+ retval=0;
+ }
+ throw error;
+ }
+ return retval;
+ }
+
+
+DBObject*
+ObjectBroker::loadDBMDDObj(const OId& id) throw (r_Error)
+{
+ ENTER( "ObjectBroker::loadDBMDDObj, id=" << id );
+
+ DBObject* retval = 0;
+ try
+ {
+ retval = new DBMDDObj(id);
+ RMDBGONCE(11, RMDebug::module_adminif, "ObjectBroker", "found in db");
+ DBObjectPPair myPair(retval->getOId(), retval);
+ TALK( "found object, inserting " << retval->getOId() << " into result list" );
+ theDBMDDObjs.insert(myPair);
+ }
+ catch (r_Error& error)
+ {
+ RMDBGONCE(11, RMDebug::module_adminif, "ObjectBroker", "not found in db");
+ if(retval)
+ {
+ delete retval;
+ retval=0;
+ }
+ LEAVE( "ObjectBroker::loadDBMDDObj, object not found in db, throwing error " << error.what() );
+ throw error;
+ }
+
+ LEAVE( "ObjectBroker::loadDBMDDObj, retval=" << retval );
+ return retval;
+}
+
+
+DBObject*
+ObjectBroker::loadMDDSet(const OId& id) throw (r_Error)
+ {
+ DBObject* retval = 0;
+ try {
+ retval = new DBMDDSet(id);
+ RMDBGONCE(11, RMDebug::module_adminif, "ObjectBroker", "found in db");
+ DBObjectPPair myPair(retval->getOId(),retval);
+ theMDDSets.insert(myPair);
+ }
+ catch (r_Error& error)
+ {
+ RMDBGONCE(11, RMDebug::module_adminif, "ObjectBroker", "not found in db");
+ if(retval)
+ {
+ delete retval;
+ retval=0;
+ }
+ throw error;
+ }
+ return retval;
+ }
+
+DBObject*
+ObjectBroker::loadDBTCIndex(const OId& id) throw (r_Error)
+ {
+ DBObject* retval = 0;
+ try {
+ retval = new DBTCIndex(id);
+ RMDBGONCE(11, RMDebug::module_adminif, "ObjectBroker", "found in db");
+ DBObjectPPair myPair(retval->getOId(), retval);
+ retval->setCached(true);
+ theDBTCIndexs.insert(myPair);
+ }
+ catch (r_Error& error)
+ {
+ RMDBGONCE(11, RMDebug::module_adminif, "ObjectBroker", "not found in db");
+ if(retval)
+ {
+ delete retval;
+ retval=0;
+ }
+ throw error;
+ }
+ return retval;
+ }
+
+DBObject*
+ObjectBroker::loadDBHierIndex(const OId& id) throw (r_Error)
+ {
+ DBObject* retval = 0;
+ try {
+ retval = new DBHierIndex(id);
+ RMDBGONCE(11, RMDebug::module_adminif, "ObjectBroker", "found in db");
+ DBObjectPPair myPair(retval->getOId(),retval);
+ retval->setCached(true);
+ theDBHierIndexs.insert(myPair);
+ }
+ catch (r_Error& error)
+ {
+ RMDBGONCE(11, RMDebug::module_adminif, "ObjectBroker", "not found in db");
+ if(retval)
+ {
+ delete retval;
+ retval=0;
+ }
+ throw error;
+ }
+ return retval;
+ }
+
+
+DBObject*
+ObjectBroker::loadBLOBTile(const OId& id) throw (r_Error)
+ {
+ DBObject* retval = 0;
+ try {
+ retval = new BLOBTile(id);
+ RMDBGONCE(11, RMDebug::module_adminif, "ObjectBroker", "found in db");
+ DBObjectPPair myPair( retval->getOId(),retval);
+ theBLOBTiles.insert(myPair);
+ }
+ catch (r_Error& error)
+ {
+ RMDBGONCE(11, RMDebug::module_adminif, "ObjectBroker", "not found in db");
+ if(retval)
+ {
+ delete retval;
+ retval=0;
+ }
+ throw error;
+ }
+ return retval;
+ }
+
+DBObject*
+ObjectBroker::loadDBRCIndexDS(const OId& id) throw (r_Error)
+ {
+ DBObject* retval = 0;
+ try {
+ retval = new DBRCIndexDS(id);
+ retval->setCached(true);
+ RMDBGONCE(11, RMDebug::module_adminif, "ObjectBroker", "found in db");
+ DBObjectPPair myPair( retval->getOId(),retval);
+ theRCIndexes.insert(myPair);
+ }
+ catch (r_Error& error)
+ {
+ RMDBGONCE(11, RMDebug::module_adminif, "ObjectBroker", "not found in db");
+ delete retval;
+ throw error;
+ }
+ return retval;
+ }
+
+void
+ObjectBroker::registerTileIndexMapping(const OId& tileoid, const OId& indexoid)
+ {
+ OIdPair p(tileoid, indexoid);
+ theTileIndexMappings.insert(p);
+ }
+
+void
+ObjectBroker::deregisterTileIndexMapping(const OId& tileoid, const OId& indexoid)
+ {
+ OIdPair p(tileoid, indexoid);
+ OIdMap::iterator i = theTileIndexMappings.find(tileoid);
+ if (i != theTileIndexMappings.end())
+ theTileIndexMappings.erase(i);
+ else
+ RMDBGONCE(0, RMDebug::module_adminif, "ObjectBroker", "deregisterIndexTileMapping(" << indexoid << ", " << tileoid << ") NOT FOUND");
+ }
+
+OIdSet*
+ObjectBroker::getAllAtomicTypes() throw (r_Error)
+ {
+ RMDBGENTER(11, RMDebug::module_adminif, "ObjectBroker", "getAllAtomicTypes()");
+ OIdSet* retval = new OIdSet();
+ DBObjectPMap& theMap = ObjectBroker::getMap(OId::ATOMICTYPEOID);
+ for (DBObjectPMap::iterator i = theMap.begin(); i != theMap.end(); i++)
+ {
+ RMDBGMIDDLE(11, RMDebug::module_adminif, "ObjectBroker", "inserted from memory " << (*i).first);
+ retval->insert((*i).first);
+ }
+ RMDBGEXIT(11, RMDebug::module_adminif, "ObjectBroker", "getAllAtomicTypes() ");
+ return retval;
+ }
+
diff --git a/reladminif/oidif.hh b/reladminif/oidif.hh
new file mode 100644
index 0000000..33ce760
--- /dev/null
+++ b/reladminif/oidif.hh
@@ -0,0 +1,307 @@
+#ifndef _OIDIF_HH_
+#define _OIDIF_HH_
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/************************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ***********************************************************************/
+
+ //@ManMemo: Module: {\bf adminif}.
+
+class OId;
+
+#include <iostream>
+
+#include "raslib/error.hh"
+
+#ifdef RMANBENCHMARK
+#include "raslib/rmdebug.hh"
+#endif
+
+//@ManMemo: Module: {\bf reladminif}.
+/*@Doc:
+the oid is a structure containing a counter and a type field. based on the type
+it is possible to determine the type of the object the oid is refering to.
+the counter is used to pinpoint the exact instance of the object.
+
+currently there are 19 different persistent classes.
+
+the counter and type information is encoded into a double:
+ID_MULTIPLIER * counter + type;
+the counters for each oid type are stored in the database. their exact value is read
+when the transaction starts. the values are updated in the database at the end of a
+transaction. this can be a problem with multiple concurrent open read/write
+transactions.
+*/
+
+
+class OId
+ {
+ public:
+ enum OIdType { INVALID = 0,
+ MDDOID,
+ MDDCOLLOID,
+ MDDTYPEOID,
+ MDDBASETYPEOID,
+ MDDDIMTYPEOID,
+ MDDDOMTYPEOID,
+ STRUCTTYPEOID,
+ SETTYPEOID,
+ BLOBOID,
+ DBMINTERVALOID,
+ STORAGEOID,
+ MDDHIERIXOID,
+ DBTCINDEXOID,
+ INLINETILEOID,
+ INNEROID,
+ ATOMICTYPEOID,
+ UDFOID,
+ UDFPACKAGEOID,
+ MDDRCIXOID};
+ /*@Doc:
+ every persistent class needs a unique OIdType.
+ There is as always an exception: INNEROID is only used by DBTCIndex internally
+ */
+
+ typedef int OIdCounter;
+ /*@Doc:
+ every persistent object needs a unique OIdCounter within all persistent objects
+ with the same OIdType.
+ */
+
+ typedef double OIdPrimitive;
+ /*@Doc:
+ an oid can be converted from and to a primitive of this type.
+ */
+
+ static OIdPrimitive ID_MULTIPLIER;
+ /*@Doc:
+ is used to calculate the actual id and type from a given double
+ */
+
+ static void allocateOId(OId& id, OIdType type, OIdCounter howMany = 1);
+ /*@Doc:
+ allocates a OId for an object of the specified type or a whole bunch of them.
+ */
+
+ static void deinitialize();
+ /*@Doc:
+ writes the current state of the oid counters back
+ into the database.
+ */
+
+ static void initialize();
+ /*@Doc:
+ reads the state of the oid counters from the database.
+ */
+
+ OId::OIdType getType() const;
+ /*@Doc:
+ Returns type of the object with this OId.
+ */
+
+ OId(const OId& oldOId);
+ /*@Doc:
+ Copy constructor
+ */
+
+ OId(OIdCounter newId, OIdType type);
+ /*@Doc:
+ New OId with counter = newId, oidtype = type
+ */
+
+ OId(OIdPrimitive oidd);
+ /*@Doc:
+ generate a oid from a double.
+ */
+
+ OId();
+ /*@Doc:
+ invalid oid
+ */
+
+ OIdCounter getCounter() const;
+ /*@Doc:
+ returns the counter part of the oid.
+ */
+
+ void print_status(std::ostream& s = std::cout) const;
+ /*@Doc:
+ prints a double
+ */
+
+ operator double() const;
+ /*@Doc:
+ converts the oid to a double:
+ oid * OId::ID_MULTIPLIER + oidtype;
+ */
+
+ static const char* counterNames[];
+ /*@Doc:
+ holds the names of the counters in RAS_ADMIN, to go with counterIds
+ */
+
+ static unsigned int maxCounter;
+
+ OId& operator=(const OId& old);
+
+ bool operator== (const OId& one) const;
+
+ bool operator!= (const OId& one) const;
+
+ bool operator< (const OId& old) const;
+
+ bool operator> (const OId& old) const;
+
+ bool operator<= (const OId& old) const;
+
+ bool operator>= (const OId& old) const;
+
+ protected:
+ // protection agains writing back unloaded counters => inconsistent DB!!
+ static bool loadedOk;
+
+
+ OIdCounter oid;
+ /*@Doc:
+ the counter inside the oid
+ */
+
+ OIdType oidtype;
+ /*@Doc:
+ the type of object
+ */
+
+ static OIdCounter nextMDDOID;
+ /*@Doc:
+ counter which holds the next oid
+ */
+
+ static OIdCounter nextMDDCOLLOID;
+ /*@Doc:
+ counter which holds the next oid
+ */
+
+ static OIdCounter nextMDDTYPEOID;
+ /*@Doc:
+ counter which holds the next oid
+ */
+
+ static OIdCounter nextMDDBASETYPEOID;
+ /*@Doc:
+ counter which holds the next oid
+ */
+
+ static OIdCounter nextMDDDIMTYPEOID;
+ /*@Doc:
+ counter which holds the next oid
+ */
+
+ static OIdCounter nextMDDDOMTYPEOID;
+ /*@Doc:
+ counter which holds the next oid
+ */
+
+ static OIdCounter nextSTRUCTTYPEOID;
+ /*@Doc:
+ counter which holds the next oid
+ */
+
+ static OIdCounter nextSETTYPEOID;
+ /*@Doc:
+ counter which holds the next oid
+ */
+
+ static OIdCounter nextBLOBOID;
+ /*@Doc:
+ counter which holds the next oid
+ */
+
+ static OIdCounter nextDBMINTERVALOID;
+ /*@Doc:
+ counter which holds the next oid
+ */
+
+ static OIdCounter nextSTORAGEOID;
+ /*@Doc:
+ counter which holds the next oid
+ */
+
+ static OIdCounter nextMDDHIERIXOID;
+ /*@Doc:
+ counter which holds the next oid
+ */
+
+ //static OIdCounter nextDBTCINDEXOID;
+ /*@Doc:
+ this counter is not used because mddhierix takes care of that
+ */
+
+ //static OIdCounter nextINLINETILEOID;
+ /*@Doc:
+ not used because they are the same as bloboid counter
+ */
+
+ static OIdCounter nextATOMICTYPEOID;
+ /*@Doc:
+ not used now because they are hard coded
+ */
+
+ static OIdCounter nextMDDRCIXOID;
+ /*@Doc:
+ counter which holds the next oid
+ */
+
+ static OIdCounter nextUDFOID;
+ /*@Doc:
+ counter which holds the next oid
+ */
+
+ static OIdCounter nextUDFPACKAGEOID;
+ /*@Doc:
+ counter which holds the next oid
+ */
+
+ static OIdCounter* counterIds[];
+ /*@Doc:
+ holds all OIdCounters of next* sort, to go with the counterNames.
+ */
+
+ };
+
+extern std::ostream& operator<<(std::ostream& in, const OId& d);
+
+extern std::ostream& operator<<(std::ostream& in, OId::OIdType d);
+
+extern bool operator== (const OId::OIdPrimitive one, const OId& two);
+
+extern bool operator== (const OId& two, const OId::OIdPrimitive one);
+
+#endif
diff --git a/reladminif/oidif.pgc b/reladminif/oidif.pgc
new file mode 100644
index 0000000..9f19254
--- /dev/null
+++ b/reladminif/oidif.pgc
@@ -0,0 +1,135 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+// This is -*- C++ -*-
+/*****************************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ * uses embedded SQL
+ *
+ *****************************************************************************/
+
+static const char rcsid[] = "@(#)reladminif,OIdIf: $Id: oidif.ec,v 1.5 2003/12/27 23:11:43 rasdev Exp $";
+
+#include "debug-srv.hh"
+
+// general embedded SQL related definitions
+EXEC SQL include "sqlglobals.h";
+
+#include "oidif.hh"
+#include "raslib/rmdebug.hh"
+#include "sqlerror.hh"
+#include "adminif.hh"
+
+void
+OId::initialize()
+{
+ RMDBGENTER(4, RMDebug::module_adminif, "OId", "initialize()");
+ ENTER( "OId::initialize" );
+
+ loadedOk = false;
+
+ EXEC SQL BEGIN DECLARE SECTION;
+ long nextoid;
+ char name[STRING_MAXLEN];
+ EXEC SQL END DECLARE SECTION;
+ nextoid = 0;
+ for (int i = 1; i < maxCounter; i++)
+ {
+ (void) strncpy( name, (char*) counterNames[i], (size_t) sizeof(name) );
+
+ TALK( "EXEC SQL SELECT NextValue INTO :nextoid FROM RAS_COUNTERS WHERE CounterName = " << name );
+ EXEC SQL SELECT NextValue INTO :nextoid
+ FROM RAS_COUNTERS
+ WHERE CounterName = :name;
+ TALK( "-> nextoid=" << nextoid );
+ if (check("OId::initialize() SELECT OId"))
+ {
+ RMInit::logOut << "OId::initialize() error reading " << name << endl;
+ generateException();
+ }
+ *counterIds[i] = nextoid;
+ RMDBGMIDDLE(4, RMDebug::module_adminif, "OIdIf", "read " << counterNames[i] << " " << *counterIds[i]);
+ }
+
+ loadedOk = true;
+
+ LEAVE( "OId::initialize" );
+ RMDBGEXIT(4, RMDebug::module_adminif, "OId", "initialize()");
+}
+
+void
+OId::deinitialize()
+{
+ RMDBGENTER(4, RMDebug::module_adminif, "OId", "deinitialize()");
+ ENTER( "OId::deinitialize" );
+
+ if (AdminIf::isReadOnlyTA())
+ {
+ RMDBGMIDDLE(4, RMDebug::module_adminif, "OIdIf", "do nothing is read only");
+ }
+ else
+ {
+ if (AdminIf::isAborted())
+ {
+ RMDBGMIDDLE(4, RMDebug::module_adminif, "OIdIf", "do nothing is aborted");
+ }
+
+ else if(loadedOk==false)
+ {
+ RMDBGMIDDLE(4, RMDebug::module_adminif, "OIdIf", "avoiding to write uninitialized counters into DB");
+ }
+
+ else
+ {
+ EXEC SQL BEGIN DECLARE SECTION;
+ long nextoid1;
+ char name2[STRING_MAXLEN];
+ EXEC SQL END DECLARE SECTION;
+
+ for (int i = 1; i < maxCounter; i++)
+ {
+ nextoid1 = *counterIds[i];
+ (void) strncpy( name2, (char*) counterNames[i], (size_t) sizeof(name2) );
+
+ RMDBGMIDDLE(4, RMDebug::module_adminif, "OIdIf", "setting " << name2 << " to " << nextoid1)
+ TALK( "EXEC SQL UPDATE RAS_COUNTERS SET NextValue = " << nextoid1 << " WHERE CounterName = " << name2 );
+ EXEC SQL UPDATE RAS_COUNTERS SET NextValue = :nextoid1
+ WHERE CounterName = :name2;
+ if (check("OId::deinitialize() UPDATE OId"))
+ {
+ RMInit::logOut << "OId::deinitialize() error writing " << name2 << endl;
+ }
+ }
+ }
+ }
+
+ loadedOk = false;
+
+ LEAVE( "OId::deinitialize" );
+ RMDBGEXIT(4, RMDebug::module_adminif, "OId", "deinitialize()");
+}
+
diff --git a/reladminif/oidifcommon.cc b/reladminif/oidifcommon.cc
new file mode 100644
index 0000000..ed75ef3
--- /dev/null
+++ b/reladminif/oidifcommon.cc
@@ -0,0 +1,414 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+// This is -*- C++ -*-
+/*****************************************************************************
+ *
+ *
+ * PURPOSE:
+ * code common to all database interface implementations
+ *
+ *
+ * COMMENTS:
+ * uses embedded SQL
+ *
+ *****************************************************************************/
+#include <string.h>
+#include "oidif.hh"
+#include "adminif.hh"
+#include "databaseif.hh"
+#include <stdlib.h>
+#include "externs.h"
+#include "sqlerror.hh"
+#include "raslib/error.hh"
+#include "raslib/rmdebug.hh"
+
+#ifdef RMANBENCHMARK
+RMTimer
+OId::oidAlloc("OId","allocateOId");
+#endif
+
+#ifdef RMANBENCHMARK
+RMTimer
+OId::oidResolve("OId","resolveOId");
+#endif
+
+double OId::ID_MULTIPLIER = 512;
+
+OId::OIdCounter OId::nextMDDOID = 0;
+
+OId::OIdCounter OId::nextMDDCOLLOID = 0;
+
+OId::OIdCounter OId::nextMDDTYPEOID = 0;
+
+OId::OIdCounter OId::nextMDDBASETYPEOID = 0;
+
+OId::OIdCounter OId::nextMDDDIMTYPEOID = 0;
+
+OId::OIdCounter OId::nextMDDDOMTYPEOID = 0;
+
+OId::OIdCounter OId::nextSTRUCTTYPEOID = 0;
+
+OId::OIdCounter OId::nextSETTYPEOID = 0;
+
+OId::OIdCounter OId::nextBLOBOID = 0;
+
+OId::OIdCounter OId::nextDBMINTERVALOID = 0;
+
+OId::OIdCounter OId::nextSTORAGEOID = 0;
+
+OId::OIdCounter OId::nextMDDHIERIXOID = 0;
+
+OId::OIdCounter OId::nextATOMICTYPEOID = 0;
+
+OId::OIdCounter OId::nextMDDRCIXOID = 0;
+
+OId::OIdCounter OId::nextUDFOID = 0;
+
+OId::OIdCounter OId::nextUDFPACKAGEOID = 0;
+
+unsigned int
+OId::maxCounter = 20;
+
+const char*
+OId::counterNames[] = { "INVALID",
+ "MDDOID",
+ "MDDCOLLOID",
+ "MDDTYPEOID",
+ "MDDBASETYPEOID",
+ "MDDDIMTYPEOID",
+ "MDDDOMTYPEOID",
+ "STRUCTTYPEOID",
+ "SETTYPEOID",
+ "BLOBOID",
+ "DBMINTERVALOID",
+ "STORAGEOID",
+ "MDDHIERIXOID",
+ "INLINEINDEXOID",
+ "INLINETILEOID",
+ "INNEROID",
+ "ATOMICTYPEOID",
+ "UDFOID",
+ "UDFPACKAGEOID",
+ "MDDRCIXOID"
+ };
+
+OId::OIdCounter*
+OId::counterIds[] = {
+ NULL,
+ &nextMDDOID,
+ &nextMDDCOLLOID,
+ &nextMDDTYPEOID,
+ &nextMDDBASETYPEOID,
+ &nextMDDDIMTYPEOID,
+ &nextMDDDOMTYPEOID,
+ &nextSTRUCTTYPEOID,
+ &nextSETTYPEOID,
+ &nextBLOBOID,
+ &nextDBMINTERVALOID,
+ &nextSTORAGEOID,
+ &nextMDDHIERIXOID,
+ &nextMDDHIERIXOID,
+ &nextBLOBOID,
+ &nextBLOBOID,
+ &nextATOMICTYPEOID,
+ &nextUDFOID,
+ &nextUDFPACKAGEOID,
+ &nextMDDRCIXOID
+ };
+
+bool OId::loadedOk = false;
+
+void
+OId::allocateOId(OId& id, OIdType type, OIdCounter howMany)
+ {
+ RMDBGENTER(4, RMDebug::module_adminif, "OId", "allocateOId(" << id << ", " << (OIdType)type << ")");
+ if (howMany == 0)
+ {
+ RMInit::logOut << "OId::allocateOId(" << id << ", " << type << ", " << howMany << ") allocation of zero oids not supported" << endl;
+ throw r_Error(r_Error::r_Error_CreatingOIdFailed);
+ }
+ if (type == INVALID || type == INNEROID || type == ATOMICTYPEOID || type > maxCounter)
+ {
+ RMInit::logOut << "OIDs of the specified type (" << type << " cannot be allocated." << endl;
+ throw r_Error(r_Error::r_Error_CreatingOIdFailed);
+ }
+ else {
+ id.oid = *counterIds[type];
+ *counterIds[type] = *counterIds[type] + howMany;
+ }
+ id.oidtype = type;
+ RMDBGEXIT(4, RMDebug::module_adminif, "OId", "allocateOId(" << id << ", " << type << ") ");
+ }
+
+OId::OId(const OId& oldOId)
+ {
+ RMDBGENTER(4, RMDebug::module_adminif, "OId", "OId(" << oldOId << ")");
+ oid = oldOId.oid;
+ oidtype = oldOId.oidtype;
+ RMDBGEXIT(4, RMDebug::module_adminif, "OId", "OId(" << oldOId << ")");
+ }
+
+OId::OId()
+ {
+ RMDBGENTER(4, RMDebug::module_adminif, "OId", "OId()");
+ oidtype = INVALID;
+ oid = 0;
+ RMDBGEXIT(4, RMDebug::module_adminif, "OId", "OId()");
+ }
+
+OId::OId(OIdPrimitive newId)
+ {
+ RMDBGENTER(4, RMDebug::module_adminif, "OId", "OId(OIdPrimitive " << newId << ")");
+ oid = newId / OId::ID_MULTIPLIER;
+ oidtype = (OId::OIdType)(newId - (OIdPrimitive)((OIdPrimitive)oid * OId::ID_MULTIPLIER));
+ RMDBGEXIT(4, RMDebug::module_adminif, "OId", "OId(OIdPrimitive " << newId << ") ID " << oid << " TYPE " << oidtype);
+ }
+
+OId::OId(OIdCounter newId, OIdType type)
+ {
+ RMDBGENTER(4, RMDebug::module_adminif, "OId", "OId(" << newId << "," << type << ")");
+ oidtype = type;
+ oid = newId;
+ RMDBGEXIT(4, RMDebug::module_adminif, "OId", "OId(" << newId << "," << type << ")");
+ }
+
+OId::OIdType
+OId::getType() const
+ {
+ RMDBGONCE(4, RMDebug::module_adminif, "OId", "getType() " << oidtype);
+ return oidtype;
+ }
+
+void
+OId::print_status(ostream& s) const
+ {
+ s << this;
+ }
+
+OId::OIdCounter
+OId::getCounter() const
+ {
+ RMDBGONCE(4, RMDebug::module_adminif, "OId", "getCounter() " << oid);
+ return oid;
+ }
+
+OId::operator double() const
+ {
+ RMDBGONCE(4, RMDebug::module_adminif, "OId", "operator() " << oid);
+ return oid * OId::ID_MULTIPLIER + oidtype;
+ }
+
+bool
+OId::operator!= (const OId& one) const
+ {
+ RMDBGONCE(4, RMDebug::module_adminif, "OId", "operator!=(" << one << ") " << *this);
+ return !(OId::operator==(one));
+ }
+
+bool
+OId::operator== (const OId& one) const
+ {
+ bool retval = false;
+ if (oidtype == one.oidtype)
+ {
+ retval = (oid == one.oid);
+ }
+ else {
+ retval = false;
+ }
+ RMDBGONCE(4, RMDebug::module_adminif, "OId", "operator==(" << one << ") " << *this << " retval=" << retval);
+ return retval;
+ }
+
+OId&
+OId::operator=(const OId& old)
+ {
+ RMDBGONCE(4, RMDebug::module_adminif, "OId", "operator=(" << old << ") "<< *this);
+ if (this != &old)
+ {
+ oid = old.oid;
+ oidtype = old.oidtype;
+ }
+ return *this;
+ }
+
+bool
+OId::operator<(const OId& old) const
+ {
+ bool retval = false;
+ if (oidtype == old.oidtype)
+ {
+ retval = (oid < old.oid);
+ }
+ else {
+ retval = (oidtype < old.oidtype);
+ }
+ RMDBGONCE(4, RMDebug::module_adminif, "OId", "operator<(" << old << ") " << *this << " retval=" << retval);
+ return retval;
+ }
+
+bool
+OId::operator>(const OId& old) const
+ {
+ bool retval = false;
+ if (oidtype == old.oidtype)
+ {
+ retval = (oid > old.oid);
+ }
+ else {
+ retval = (oidtype > old.oidtype);
+ }
+ RMDBGONCE(4, RMDebug::module_adminif, "OId", "operator>(" << old << ") " << *this << " retval=" << retval);
+ return retval;
+ }
+
+bool
+OId::operator<=(const OId& old) const
+ {
+ bool retval = false;
+ if (oidtype == old.oidtype)
+ {
+ retval = (oid <= old.oid);
+ }
+ else {
+ retval = (oidtype < old.oidtype);
+ }
+ RMDBGONCE(4, RMDebug::module_adminif, "OId", "operator<=(" << old << ") " << *this << " retval=" << retval);
+ return retval;
+ }
+
+bool
+OId::operator>=(const OId& old) const
+ {
+ bool retval = false;
+ if (oidtype == old.oidtype)
+ {
+ retval = (oid >= old.oid);
+ }
+ else {
+ retval = (oidtype > old.oidtype);
+ }
+ RMDBGONCE(4, RMDebug::module_adminif, "OId", "operator>=(" << old << ") " << *this << " retval=" << retval);
+ return retval;
+ }
+
+bool
+operator== (const double one, const OId& two)
+ {
+ RMDBGONCE(4, RMDebug::module_adminif, "OId", "operator==(" << one << "," << two << ")");
+ bool retval=false;
+ if (((double)two) == one)
+ retval=true;
+ return retval;
+ }
+
+bool
+operator== (const OId& two, const double one)
+ {
+ RMDBGONCE(4, RMDebug::module_adminif, "OId", "operator==(" << two << "," << one << ")");
+ bool retval=false;
+ if (((double)two) == one)
+ retval=true;
+ return retval;
+ }
+
+std::ostream&
+operator<<(std::ostream& s, const OId& d)
+ {
+ s << "OId(" << d.getCounter() << ":" << d.getType() << ")";
+ return s;
+ }
+
+std::ostream&
+operator<<(std::ostream& s, OId::OIdType d)
+ {
+ switch (d)
+ {
+ case OId::INVALID:
+ s << "INVALID";
+ break;
+ case OId::MDDOID:
+ s << "MDDOID";
+ break;
+ case OId::MDDCOLLOID:
+ s << "MDDCOLLOID";
+ break;
+ case OId::MDDTYPEOID:
+ s << "MDDTYPEOID";
+ break;
+ case OId::MDDBASETYPEOID:
+ s << "MDDBASETYPEOID";
+ break;
+ case OId::MDDDIMTYPEOID:
+ s << "MDDDIMTYPEOID";
+ break;
+ case OId::MDDDOMTYPEOID:
+ s << "MDDDOMTYPEOID";
+ break;
+ case OId::STRUCTTYPEOID:
+ s << "STRUCTTYPEOID";
+ break;
+ case OId::SETTYPEOID:
+ s << "SETTYPEOID";
+ break;
+ case OId::BLOBOID:
+ s << "BLOBOID";
+ break;
+ case OId::DBMINTERVALOID:
+ s << "DBMINTERVALOID";
+ break;
+ case OId::STORAGEOID:
+ s << "STORAGEOID";
+ break;
+ case OId::MDDHIERIXOID:
+ s << "MDDHIERIXOID";
+ break;
+ case OId::DBTCINDEXOID:
+ s << "DBTCINDEXOID";
+ break;
+ case OId::INLINETILEOID:
+ s << "INLINETILEOID";
+ break;
+ case OId::INNEROID:
+ s << "INNEROIDOID";
+ break;
+ case OId::ATOMICTYPEOID:
+ s << "ATOMICTYPEOID";
+ break;
+ case OId::UDFOID:
+ s << "UDFOID";
+ break;
+ case OId::UDFPACKAGEOID:
+ s << "UDFPACKAGEOID";
+ break;
+ case OId::MDDRCIXOID:
+ s << "MDDRCIXOID";
+ break;
+ default:
+ s << "UNKNOWN: " << (int)d;
+ break;
+ }
+ return s;
+ }
+
+
diff --git a/reladminif/sqlerror.hh b/reladminif/sqlerror.hh
new file mode 100644
index 0000000..869fb86
--- /dev/null
+++ b/reladminif/sqlerror.hh
@@ -0,0 +1,118 @@
+#ifndef _SQLERROR_HH_
+#define _SQLERROR_HH_
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/************************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ***********************************************************************/
+
+//@ManMemo: Module: {\bf reladminif}.
+
+/*@Doc:
+
+ SQL Errors Handling
+
+*/
+#include <iostream>
+using std::cout;
+using std::endl;
+
+#include "raslib/error.hh"
+
+#ifdef BASEDB_DB2
+#define generateException() generateExceptionn(sqlca)
+
+void generateExceptionn(struct sqlca&) throw (r_Error);
+
+/*@Doc:
+generates a new r_Ebase_dbms exception and throws it.
+*/
+
+#define check(msg) checkk(msg, sqlca)
+int checkk(const char* msg, struct sqlca& mysql) throw( r_Error );
+ /*@Doc:
+ returns sqlcode, prints error messages when appropriate.
+ the msg is inserted in the error message.
+ changes are not rolledback, nothing is done to the connection.
+ */
+
+#endif
+
+#ifdef BASEDB_ORACLE
+void generateException() throw (r_Error);
+/*@Doc:
+generates a new r_Ebase_dbms exception and throws it.
+*/
+
+int check(const char* msg) throw (r_Error);
+/*@Doc:
+returns sqlcode, prints error messages when appropriate.
+the msg is inserted in the error message.
+changes are not rolledback, nothing is done to the connection.
+*/
+
+void printSQLError(void* err, int status);
+void printSQLError(void* err) throw (r_Error);
+/*@Doc:
+This diplays cli errors.
+*/
+#endif
+
+#ifdef BASEDB_INFORMIX
+void generateException() throw (r_Error);
+/*@Doc:
+This generates exceptions.
+*/
+
+int check(const char* msg, bool displayWarning = false) throw (r_Error);
+/*@Doc:
+This diplays esql errors.
+*/
+
+void printSQLError(int error, const char*);
+/*@Doc:
+This diplays cli errors.
+*/
+#endif
+
+#ifdef BASEDB_PGSQL
+void generateException() throw (r_Error);
+/*@Doc:
+This generates exceptions.
+*/
+
+int check(const char* msg) throw (r_Error);
+/*@Doc:
+Display error message if SQL errors have occurred.
+*/
+#endif
+
+#endif
+
diff --git a/reladminif/sqlerror.pgc b/reladminif/sqlerror.pgc
new file mode 100644
index 0000000..94d41a3
--- /dev/null
+++ b/reladminif/sqlerror.pgc
@@ -0,0 +1,198 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+// This is -*- C++ -*-
+/*************************************************************************
+ *
+ *
+ * PURPOSE:
+ * process base DBMS errors (PostgreSQL) by printing messages and throwing exceptions.
+ *
+ *
+ * COMMENTS:
+ * - different from other implementations in that no distinction between
+ * error and warning
+ * - the whole module should be redesigned for all DBMSs - very unconcise
+ * - no function printSQLError() as eg in Informix
+ * - FIXME: generateException() should be declared r_Ebase_dbms instead of r_Error
+ *
+ ***********************************************************************/
+
+static const char rcsid[] = "@(#)reladminif,SQLError: $Id: sqlerror.ec,v 1.4 2003/12/27 23:11:43 rasdev Exp $";
+
+// #define SQLCA_STORAGE_CLASS extern
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "sqlerror.hh"
+#include "externs.h"
+
+#include "raslib/rmdebug.hh"
+#include "raslib/error.hh"
+#include "debug-srv.hh"
+
+// general embedded SQL related definitions
+EXEC SQL include "sqlglobals.h";
+
+// SQLSTATE not available in PGSQL (SQLCODE is, funny enough)
+#define SQLSTATE sqlca.sqlstate
+
+// error codes
+EXEC SQL define SUCCESS 0;
+EXEC SQL define WARNING 1;
+EXEC SQL define NODATA 100;
+EXEC SQL define RTERROR -1;
+
+// general message buffer size
+#define BUFFER_SIZE 4000
+
+// SQL error message max size
+// FIXME: is this really enough?
+const int MSG_MAXLEN=BUFFER_SIZE;
+
+// length of buffer for remembering last message
+#define LASTERRORMSGLEN BUFFER_SIZE
+char lastErrorMsg[LASTERRORMSGLEN];
+
+/*
+ * The sqlstate_err() function checks the SQLSTATE status variable to see
+ * if an error or warning has occurred following an SQL statement.
+ */
+int sqlstate_err()
+{
+ int err_code = RTERROR;
+
+ if (SQLSTATE[0] == '0') /* trap '00', '01', '02' */
+ {
+ switch(SQLSTATE[1])
+ {
+ case '0': /* success - return 0 */
+ err_code = SUCCESS;
+ break;
+ case '1': /* warning - return 1 */
+ err_code = WARNING;
+ break;
+ case '2': /* end of data - return 100 */
+ err_code = NODATA;
+ break;
+ default: /* error - return SQLCODE */
+ break;
+ }
+ }
+ return err_code;
+} // sqlstate_err()
+
+
+/*
+ * The disp_sqlstate_err() function prints details into msgbuf.
+ */
+void disp_sqlstate_err(char* msgbuf, size_t length)
+{
+ char error_buffer[BUFFER_SIZE];
+ size_t characters_written = 0;
+
+ snprintf(error_buffer, BUFFER_SIZE, "SQLSTATE: %5s SQLCODE: %d\n", SQLSTATE, SQLCODE);
+ characters_written = strlen(error_buffer);
+ if (characters_written > length)
+ {
+ RMInit::logOut << "error message didn't fit into buffer: " << error_buffer << endl;
+ }
+ else
+ {
+ strcat(msgbuf, error_buffer);
+ }
+} // disp_sqlstate_err()
+
+/*
+ * disp_error(): print statement and error/warning text into buffer
+ */
+void disp_error(const char* stmt, char* msgbuf, size_t length)
+{
+ char error_buffer[BUFFER_SIZE];
+ snprintf(error_buffer, BUFFER_SIZE, "Warning/error in %s:\n", stmt);
+
+ size_t error_len = strlen(error_buffer);
+
+ if (error_len > length)
+ RMInit::logOut << "error message didn't fit into buffer: " << error_buffer << endl;
+ else
+ {
+ strcat(msgbuf, error_buffer);
+ length = length - error_len;
+ }
+ disp_sqlstate_err(msgbuf, length);
+} // disp_error()
+
+/*
+ * disp_exception(): if sql_errcode says there was an error,
+ * allocate msg buffer and copy error msg
+ */
+char* disp_exception(const char* stmt, int sqlerr_code)
+{
+ char* msgbuf = NULL;
+ switch (sqlerr_code)
+ {
+ case SUCCESS:
+ case NODATA:
+ break;
+ case WARNING:
+ case RTERROR:
+ msgbuf = new char[BUFFER_SIZE];
+ memset(msgbuf, 0, BUFFER_SIZE);
+ disp_error(stmt, msgbuf, BUFFER_SIZE);
+ break;
+ default:
+ RMInit::logOut << "Invalid exception state for " << stmt << " " << sqlerr_code << endl;
+ break;
+ }
+ return msgbuf;
+} // disp_exception()
+
+/*
+ * check(): check base DBMS for any error occurred during last
+ * database access and print message into log if so.
+ */
+int
+check(const char* stmt) throw (r_Error)
+{
+ char* msg = disp_exception(stmt, sqlstate_err());
+ if (msg != NULL)
+ {
+ RMInit::logOut << msg << endl;
+ snprintf(lastErrorMsg, LASTERRORMSGLEN, msg);
+ delete [] msg;
+ msg = NULL;
+ }
+ return SQLCODE;
+}
+
+// generate r_Ebase_dbms exception using SQL error code and message
+void
+generateException() throw (r_Error)
+{
+ TALK( "Throwing Exception (SQLCODE=" << SQLCODE << "): " << lastErrorMsg );
+ RMInit::dbgOut << "Throwing Exception (SQLCODE=" << SQLCODE << "): " << lastErrorMsg << endl;
+ throw r_Ebase_dbms( SQLCODE, lastErrorMsg );
+} // generateException()
+
diff --git a/reladminif/sqlglobals.h b/reladminif/sqlglobals.h
new file mode 100644
index 0000000..5ac83cf
--- /dev/null
+++ b/reladminif/sqlglobals.h
@@ -0,0 +1,50 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*****************************************************************************
+ *
+ *
+ * PURPOSE:
+ * provide global definitions for embedded SQL usage (any base DBMS)
+ *
+ *
+ * COMMENTS:
+ * - further SQL-relevant constants for C++ usage can be found in externs.h
+ *
+ *****************************************************************************/
+
+#ifndef _SQLGLOBALS_H_
+#define _SQLGLOBALS_H_
+
+// this syntax should be the same for all embedded SQL versions
+// right now only tested & used with Informix, though
+
+// max length of varchar attributes and other string buffers; incl padding zero
+// see $(INFORMIXDIR)/incl/esql/varchar.h
+// unfortunately there it is not made known to ESQL, so we must use a literal here
+EXEC SQL define VARCHAR_MAXLEN 255;
+EXEC SQL define STRING_MAXLEN 255;
+
+// SQL query string buffer size
+#define SQL_QUERY_BUFFER_SIZE 400
+
+#endif // _SQLGLOBALS_H_
diff --git a/reladminif/test/Makefile b/reladminif/test/Makefile
new file mode 100644
index 0000000..40097a2
--- /dev/null
+++ b/reladminif/test/Makefile
@@ -0,0 +1,90 @@
+# -*-Makefile-*-
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>. # Top Level makefile. This points to the various modules that have to be build
+# and/or deployed
+#
+# MAKEFILE FOR:
+# reladminif tests.
+#
+# COMMENTS:
+# - List environment dependencies, known bugs, specialities etc.
+#
+##################################################################
+######################### Definitions ############################
+
+# all test programs
+ALLTESTS = test_databaseif dbreftest admintest perstest eoidtest dbnamedobjtest testindex testconnect test_databaseif
+
+# Needed rasdaman libraries for linking. To be completed.
+NEEDEDLIBS = $(CACHETAMGR) $(QLPARSER) $(INDEXMGR) $(RELADMINIF) $(RELMDDIF) $(RELBLOBIF) $(RELINDEXIF) $(CACHETAMGR) $(RELCATALOGIF) $(RASLIB) $(RELADMINIF) $(RELMDDIF)
+
+# insert names of source files which need STL<TOOLKIT>
+# also insert names of source files which include .hh files which need stl
+NEEDSTL := dbreftest.C eoidtest.C admintest.C perstest.C dbnamedobjtest.C testindex.c
+
+# insert any files that are not object, bind or generated .c/.C files
+# e.g.: libs
+MISCCLEAN := client.bm client.dbg client.log ir.out core
+
+# insert object files here. makes only sense if oracle and db2 files are the same
+OBJS := dbreftest.o admintest.o perstest.o eoidtest.o dbnamedobjtest.o testindex.o testconnect.o test_databaseif.o
+
+# add to compile flag set
+CXXFLAGS += $(I_SYM)$(RMANBASE)/raslib
+
+########################### Targets ##############################
+
+# make all tests
+.PHONY: test
+test: $(ALLTESTS)
+
+indextest.o: indextest.cc
+ $(CXX) -c $(BASEDBCXXFLAGS) $(STLCXXFLAGS) $(CXXFLAGS) $<
+
+######################## Dependencies ############################
+
+admintest: admintest.o $(NEEDEDLIBS)
+admintest.o: admintest.C
+
+dbreftest: dbreftest.o
+dbreftest.o: dbreftest.C
+
+eoidtest: eoidtest.o
+eoidtest.o: eoidtest.C
+
+dbnamedobjtest: dbnamedobjtest.o
+dbnamedobjtest.o: dbnamedobjtest.C
+
+perstest: perstest.o
+perstest.o: perstest.C
+
+dbcheck.o: dbcheck.c
+dbcheck.c: dbcheck.pc
+dbcheck: dbcheck.o
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^ -L/home/proj/rasdaman/3rdParty/linux/lib -L$(RMANHOME)/lib -Xlinker -Bstatic $(LIBAKINSIDE) -lmddmgr -ltilemgr -lindexmgr -lcatalogmgr -lstoragemgr -lreladminif -lrelmddif -lrelstorageif -lrelindexif -lrelcatalogif -lrelblobif -lcompression -lconversion -lraslib $(RMANHOME)/mymalloc/mymalloc_svc.o -lpng -ltiff -ljpeg -lmfhdf -ldf -lz $(REL_STATIC_LIBS)
+
+check: check.o
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^ -L$(RMANHOME)/lib -Xlinker -Bstatic $(LIBAKINSIDE) -lmddmgr -ltilemgr -lindexmgr -lcatalogmgr -lstoragemgr -lreladminif -lrelmddif -lrelstorageif -lrelindexif -lrelcatalogif -lrelblobif -lcompression -lconversion -lraslib $(RMANHOME)/mymalloc/mymalloc_svc.o -lpng -ltiff -ljpeg -lmfhdf -ldf -lz $(REL_STATIC_LIBS)
+
+test_databaseif: test_databaseif.o ../databaseif.o
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ $^ $(RMANBASE)/mymalloc/mymalloc_svc.o ../sqlerror.o ../oidif.o ../adminif.o -L$(RMANBASE)/lib -lraslib -lrasodmg $(BASEDBLDFLAGS)
+
diff --git a/reladminif/test/admintest.C b/reladminif/test/admintest.C
new file mode 100644
index 0000000..adf0d94
--- /dev/null
+++ b/reladminif/test/admintest.C
@@ -0,0 +1,92 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include "raslib/rmdebug.hh"
+#include <iostream.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "adminif.hh"
+#include "databaseif.hh"
+#include "transactionif.hh"
+#include "raslib/rmdebug.hh"
+#include "externs.h"
+
+RMINITGLOBALS('C')
+
+
+int
+main(int argc, char *argv[])
+ {
+ int RManDebug2 = 5;
+ int RManModule = 1;
+ DatabaseIf database;
+ TransactionIf ta;
+ char* name = 0;
+
+ if (argc == 2)
+ name = argv[1];
+ else
+ name = "RASBASE";
+
+ cout << "OPENING DATABASEIF" << endl;
+ if (database.open(name))
+ {
+ cout << "ERROR OPENING DATABASE" << endl;
+ return -1;
+ }
+ cout << "OPENED DATABASEIF" << endl;
+
+ if (!database.databaseExists())
+ {
+ cout << "DATABASE EXISTS NOT" << endl;
+ cout << "CREATEING DATABASE" << endl;
+ database.create(name, 0, 0);
+ cout << "DATABASE CREATED" << endl;
+ }
+ else {
+ cout << "DATABASE EXISTS" << endl;
+ cout << "BEGINNING TRANSACTIONIF" << endl;
+ ta.begin(&database);
+ cout << "TRANSACTIONIF BEGUN" << endl;
+ cout << "DESTROYING DATABASE" << endl;
+ database.destroyDB(&ta, name);
+ cout << "DATABASE DESTROYED" << endl;
+ }
+ cout << "CLOSING DATABASEIF" << endl;
+ database.close();
+ cout << "CLOSED DATABASEIF" << endl;
+
+ cout << "OPENING DATABASEIF" << endl;
+ if (database.open(name))
+ {
+ cout << "ERROR OPENING DATABASE" << endl;
+ return -1;
+ }
+ cout << "OPENED DATABASEIF" << endl;
+ if (database.databaseExists())
+ cout << "DATABASE EXISTS" << endl;
+ else
+ cout << "DATABASE EXISTS NOT" << endl;
+ database.close();
+ cout << "CLOSED DATABASEIF" << endl;
+ }
diff --git a/reladminif/test/check.cc b/reladminif/test/check.cc
new file mode 100644
index 0000000..44e5892
--- /dev/null
+++ b/reladminif/test/check.cc
@@ -0,0 +1,301 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*
+get mddoid, iterate domain, dataformat
+
+select mdd
+get domain
+ {
+ begin ta
+ iterate over domain
+ retrieve tiles
+ alter tiles
+ commit ta
+ }
+*/
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#include "server/template_inst.hh"
+#endif
+
+#include "reladminif/adminif.hh"
+#include "reladminif/databaseif.hh"
+#include "reladminif/transactionif.hh"
+#include "reladminif/oidif.hh"
+#include "mddmgr/mddobj.hh"
+#include "tilemgr/tile.hh"
+#include "cmlparser.hh"
+#include "raslib/mitera.hh"
+
+#define ALLDONE 0
+#define ERRORPARSINGCOMMANDLINE 1
+#define DOMAINMISSING 2
+#define OIDMISSING 3
+#define OIDINVALID 4
+#define DOMAINMISMATCH 5
+#define FAILED 6
+#define DOMAININVALID 7
+#define UNKNOWNDATAFORMAT 8
+
+char globalConnectId[256];
+
+RMINITGLOBALS('S')
+
+r_Minterval domain;
+OId oid;
+
+int
+main(int argc, char** argv)
+ {
+ RMInit::logOut.rdbuf(cout.rdbuf());
+ RMInit::dbgOut.rdbuf(cout.rdbuf());
+ int retval = 0;
+ CommandLineParser &cmlInter = CommandLineParser::getInstance();
+ CommandLineParameter &clp_help = cmlInter.addFlagParameter('h', "help", "show command line switches");
+ CommandLineParameter &clp_connect = cmlInter.addStringParameter(CommandLineParser::noShortName, "connect", "database connect string", "/");
+ CommandLineParameter &clp_mdddomain = cmlInter.addStringParameter(CommandLineParser::noShortName, "mdddomain", "the domain to do the changes in.");
+ CommandLineParameter &clp_domain = cmlInter.addStringParameter(CommandLineParser::noShortName, "domain", "the extent to be used when selecting data from the mdd.");
+ CommandLineParameter &clp_oid = cmlInter.addStringParameter(CommandLineParser::noShortName, "oid", "the oid of the mdd to operate on");
+ CommandLineParameter &clp_comptype = cmlInter.addStringParameter(CommandLineParser::noShortName, "storageformat", "name of storage format", "Array");
+ CommandLineParameter &clp_readonly = cmlInter.addFlagParameter('r', "readonly", "read only check");
+ try {
+ cmlInter.processCommandLine(argc, argv);
+ }
+ catch(CmlException& err)
+ {
+ cmlInter.printHelp();
+ cout << "Error parsing command line:" << endl;
+ cout << err.what() << endl;
+ return ERRORPARSINGCOMMANDLINE;
+ }
+ if (cmlInter.isPresent('h'))
+ {
+ cmlInter.printHelp();
+ return ALLDONE;
+ }
+ r_Data_Format storageFormat = r_Array;
+ if (cmlInter.isPresent("storageformat"))
+ {
+ storageFormat = get_data_format_from_name(cmlInter.getValueAsString("storageformat"));
+ if (storageFormat == r_Data_Format_NUMBER)
+ {
+ cout << "unknown data format " << cmlInter.getValueAsString("storageformat") << endl;
+ return UNKNOWNDATAFORMAT;
+ }
+ }
+ if (!cmlInter.isPresent("domain"))
+ {
+ cout << "domain is missing" << endl;
+ return DOMAINMISSING;
+ }
+ if (!cmlInter.isPresent("oid"))
+ {
+ cout << "oid is missing" << endl;
+ return OIDMISSING;
+ }
+ strcpy((char*)globalConnectId, cmlInter.getValueAsString("connect"));
+ cout << "connect " << globalConnectId << endl;
+ try {
+ domain = r_Minterval(cmlInter.getValueAsString("domain"));
+ }
+ catch (const r_Error& e)
+ {
+ cout << "domain is not valid: " << e.what() << " " << e.get_errorno() << endl;
+ return DOMAININVALID;
+ }
+ oid = OId(atol(cmlInter.getValueAsString("oid")));
+ if (oid.getType() != OId::MDDOID)
+ {
+ cout << "oid is not a mdd oid" << endl;
+ return OIDINVALID;
+ }
+ bool readonly = cmlInter.isPresent("readonly");
+ if (readonly)
+ {
+ cout << "performing read only check" << std::endl;
+ }
+ else {
+ cout << "performing recompression" << std::endl;
+ }
+ cout << "set up done" << endl;
+ AdminIf::instance();
+ DatabaseIf d;
+ TransactionIf t;
+ MDDObj* mdd = NULL;
+ r_Minterval completeDomain;
+ r_MiterArea* miter = NULL;
+ try {
+ d.open("RASBASE");
+ t.begin(&d, true);
+ mdd = new MDDObj(oid);
+ if (mdd->getCurrentDomain().dimension() == domain.dimension())
+ {
+ completeDomain = mdd->getCurrentDomain();
+ if (cmlInter.isPresent("mdddomain"))
+ {
+ try {
+ r_Minterval temp(cmlInter.getValueAsString("mdddomain"));
+ if (temp.dimension() == completeDomain.dimension())
+ {
+ cout << "Not using complete mdd domain (" << completeDomain << ") but " << temp << endl;
+ completeDomain = temp;
+ }
+ else {
+ cout << "Domains do not have same number of dimensions" << endl;
+ delete mdd;
+ mdd = NULL;
+ t.commit();
+ d.close();
+ return DOMAINMISMATCH;
+ }
+ }
+ catch (const r_Error& e2)
+ {
+ cout << "mdddomain parameter is not correct: " << e2.get_errorno() << " " << e2.what() << endl;
+ delete mdd;
+ mdd = NULL;
+ t.commit();
+ d.close();
+ return DOMAININVALID;
+ }
+ }
+ miter = new r_MiterArea(&domain, &completeDomain);
+ }
+ else {
+ t.commit();
+ d.close();
+ return DOMAINMISMATCH;
+ }
+ delete mdd;
+ mdd = NULL;
+ t.commit();
+ d.close();
+ }
+ catch (const r_Error& e)
+ {
+ delete miter;
+ miter = NULL;
+ cout << "Caught exception " << e.get_errorno() << " " << e.what() << endl;
+ try {
+ t.abort();
+ }
+ catch (const r_Error& ee)
+ {
+ cout << "Caugh exception while aborting " << ee.get_errorno() << " " << ee.what() << endl;
+ try {
+ t.abort();
+ }
+ catch (const r_Error& eee)
+ {
+ cout << "Caugh exception while 2nd aborting " << eee.get_errorno() << " " << eee.what() << endl;
+ }
+ }
+ try {
+ d.close();
+ }
+ catch (const r_Error& eeee)
+ {
+ cout << "Caugh exception while closing " << eeee.get_errorno() << " " << eeee.what() << endl;
+ }
+ return FAILED;
+ }
+ std::vector<Tile*>* tiles = NULL;
+ std::vector<Tile*>::iterator here;
+ std::vector<Tile*>::iterator end;
+ r_Minterval currentDomain;
+ while (!miter->isDone())
+ {
+ currentDomain = miter->nextArea();
+ try {
+ d.open("RASBASE");
+ t.begin(&d, readonly);
+ mdd = new MDDObj(oid);
+ tiles = mdd->intersect(currentDomain);
+ end = tiles->end();
+ if (tiles)
+ {
+ cout << "working on " << currentDomain << " with " << tiles->size() << " tiles" << endl;
+ for (here = tiles->begin(); here < end; here++)
+ {
+ cout << " tile " << (*here)->getDomain() << " " << (*here)->getDBTile()->getOId() << " " << (*here)->getDataFormat() << " " << (*here)->getCompressedSize();
+ if (!(*here)->decompress())
+ {
+ cout << " decompress failed";
+ }
+ if (((*here)->getDataFormat() != storageFormat) && (!readonly))
+ {
+ cout << " changing storage format";
+ (*here)->setCompressionFormat(storageFormat);
+ cout << " compressed size " << (*here)->getCompressedSize();
+ }
+ cout << endl;
+ }
+ }
+ else {
+ cout << currentDomain << " no tiles" << endl;
+ }
+ delete mdd;
+ mdd = NULL;
+ delete tiles;
+ tiles = NULL;
+ t.commit();
+ d.close();
+ }
+ catch (const r_Error& e)
+ {
+ delete miter;
+ miter = NULL;
+ delete tiles;
+ tiles = NULL;
+ cout << "Caught exception " << e.get_errorno() << " " << e.what() << endl;
+ try {
+ t.abort();
+ }
+ catch (const r_Error& ee)
+ {
+ cout << "Caugh exception while aborting " << ee.get_errorno() << " " << ee.what() << endl;
+ try {
+ t.abort();
+ }
+ catch (const r_Error& eee)
+ {
+ cout << "Caugh exception while 2nd aborting " << eee.get_errorno() << " " << eee.what() << endl;
+ }
+ }
+ try {
+ d.close();
+ }
+ catch (const r_Error& eeee)
+ {
+ cout << "Caugh exception while closing " << eeee.get_errorno() << " " << eeee.what() << endl;
+ }
+ return FAILED;
+ }
+ }
+ delete tiles;
+ tiles = NULL;
+ delete miter;
+ miter = NULL;
+ return retval;
+ }
diff --git a/reladminif/test/dbnamedobjtest.C b/reladminif/test/dbnamedobjtest.C
new file mode 100644
index 0000000..e0c47f4
--- /dev/null
+++ b/reladminif/test/dbnamedobjtest.C
@@ -0,0 +1,88 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include "mymalloc/mymalloc.h"
+#include "raslib/rmdebug.hh"
+#include <iostream.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "dbnamedobject.hh"
+
+RMINITGLOBALS('C')
+
+int RManDebug2 = 6;
+int RManModule = 4;
+
+int
+main(int argc, char *argv[])
+ {
+ if (argc == 1)
+ {
+ cout << "Usage:" << endl;
+ cout << "\t1\t: " << endl << "\t\t" << endl;
+ }
+ else {
+ cout << "arg 1: " << argv[0] << " arg 2: " << argv[1] << " arg 3: " << argv[2] << endl;
+ OId* id = 0;
+ DBNamedObject* obj = 0;
+ char* text = (char*)mymalloc(sizeof(char) * 300);
+ struct {
+ short length;
+ char data[200];
+ } VARCHAR;
+
+ cout << "DATADUMP\t:" << VARCHAR.data << endl;
+ strcpy(VARCHAR.data, "aslkjfdhaskldjfjsd\0askdjfhdkjsladf\0laksjddf\0");
+ cout << "DATADUMP\t:" << VARCHAR.data << endl;
+ switch (atoi(argv[1]))
+ {
+ case 1:
+ strcpy(text, "maxidaxi\0waxitaxi");
+// id = new OId(1,1);
+ DBNamedObject::MAXNAMELENGTH = atoi(argv[2]);
+ cout << "Name: " << text << endl;
+ obj = new DBNamedObject(text);//*id, text);
+ cout << "Get Name: " << obj->getName() << endl;
+ break;
+ case 2:
+ DBNamedObject::MAXNAMELENGTH = atoi(argv[2]);
+ obj = new DBNamedObject(text);//*id, text);
+ cout << "Get Name: " << obj->getName() << endl;
+ VARCHAR.length = atoi(argv[3]);
+ obj->setName(VARCHAR.length, (char*)VARCHAR.data);
+ cout << "Get Name: " << obj->getName() << endl;
+ break;
+ case 3:
+ DBNamedObject::MAXNAMELENGTH = atoi(argv[2]);
+ obj = new DBNamedObject();
+ cout << "Get Name: " << obj->getName() << endl;
+ VARCHAR.length = atoi(argv[3]);
+ obj->setName(VARCHAR.length, (char*)VARCHAR.data);
+ cout << "Get Name: " << obj->getName() << endl;
+ break;
+ default:
+ cout << "DONT KNOW WHAT TO DO" << endl;
+ break;
+ }
+ }
+ }
diff --git a/reladminif/test/dbreftest.C b/reladminif/test/dbreftest.C
new file mode 100644
index 0000000..5c62b64
--- /dev/null
+++ b/reladminif/test/dbreftest.C
@@ -0,0 +1,70 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include "raslib/rmdebug.hh"
+#include <iostream.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "dbnamedobject.hh"
+#include "dbref.hh"
+#include "dbobject.hh"
+#include "oidif.hh"
+#include "adminif.hh"
+#include "databaseif.hh"
+#include "oidif.hh"
+#include "transactionif.hh"
+
+#include "alltypes.hh"
+#include "typefactory.hh"
+
+#include "dbmddcoll.hh"
+#include "dbmddcolloidentry.hh"
+#include "dbmddobj.hh"
+
+#include "raslib/rmdebug.hh"
+
+RMINITGLOBALS('C')
+
+int RManDebug2 = 8;
+int RManModule = 3;
+
+int
+main(int argc, char *argv[])
+ {
+ OId t(10, OId::BASETYPEOID);
+
+ AdminIf* myAdmin;
+ DatabaseIf database;
+ TransactionIf ta;
+ RManDebug = 6;
+
+ myAdmin = AdminIf::instance();
+ database.open("RMAN");
+ ta.begin(&database);
+
+ DbRef<BaseType> p(t);
+ cout << "Type " << p->getName() << endl;
+
+ ta.abort();
+ database.close();
+ }
diff --git a/reladminif/test/demobld.sql b/reladminif/test/demobld.sql
new file mode 100644
index 0000000..0895e87
--- /dev/null
+++ b/reladminif/test/demobld.sql
@@ -0,0 +1,125 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+--
+-- $Header: /home/rasdev/CVS-repository/rasdaman/reladminif/test/demobld.sql,v 1.3 2003/12/27 23:11:46 rasdev Exp $
+-- Copyright (c) Oracle Corporation 1988, 1993. All Rights Reserved.
+--
+--
+-- This script creates the SQL*Plus demonstration tables.
+--
+-- It should be STARTed by each user wishing to access the tables.
+--
+
+set termout on
+prompt Building demonstration tables. Please wait.
+set termout off
+set feedback off
+
+ALTER SESSION SET NLS_LANGUAGE = AMERICAN;
+ALTER SESSION SET NLS_TERRITORY = AMERICA;
+
+DROP TABLE EMP;
+DROP TABLE DEPT;
+DROP TABLE BONUS;
+DROP TABLE SALGRADE;
+DROP TABLE DUMMY;
+
+CREATE TABLE EMP
+ (EMPNO NUMBER(4) NOT NULL,
+ ENAME VARCHAR2(10),
+ JOB VARCHAR2(9),
+ MGR NUMBER(4),
+ HIREDATE DATE,
+ SAL NUMBER(7,2),
+ COMM NUMBER(7,2),
+ DEPTNO NUMBER(2));
+
+INSERT INTO EMP VALUES
+ (7369,'SMITH','CLERK',7902,'17-DEC-80',800,NULL,20);
+INSERT INTO EMP VALUES
+ (7499,'ALLEN','SALESMAN',7698,'20-FEB-81',1600,300,30);
+INSERT INTO EMP VALUES
+ (7521,'WARD','SALESMAN',7698,'22-FEB-81',1250,500,30);
+INSERT INTO EMP VALUES
+ (7566,'JONES','MANAGER',7839,'2-APR-81',2975,NULL,20);
+INSERT INTO EMP VALUES
+ (7654,'MARTIN','SALESMAN',7698,'28-SEP-81',1250,1400,30);
+INSERT INTO EMP VALUES
+ (7698,'BLAKE','MANAGER',7839,'1-MAY-81',2850,NULL,30);
+INSERT INTO EMP VALUES
+ (7782,'CLARK','MANAGER',7839,'9-JUN-81',2450,NULL,10);
+INSERT INTO EMP VALUES
+ (7788,'SCOTT','ANALYST',7566,'09-DEC-82',3000,NULL,20);
+INSERT INTO EMP VALUES
+ (7839,'KING','PRESIDENT',NULL,'17-NOV-81',5000,NULL,10);
+INSERT INTO EMP VALUES
+ (7844,'TURNER','SALESMAN',7698,'8-SEP-81',1500,0,30);
+INSERT INTO EMP VALUES
+ (7876,'ADAMS','CLERK',7788,'12-JAN-83',1100,NULL,20);
+INSERT INTO EMP VALUES
+ (7900,'JAMES','CLERK',7698,'3-DEC-81',950,NULL,30);
+INSERT INTO EMP VALUES
+ (7902,'FORD','ANALYST',7566,'3-DEC-81',3000,NULL,20);
+INSERT INTO EMP VALUES
+ (7934,'MILLER','CLERK',7782,'23-JAN-82',1300,NULL,10);
+
+CREATE TABLE DEPT
+ (DEPTNO NUMBER(2),
+ DNAME VARCHAR2(14),
+ LOC VARCHAR2(13) );
+
+INSERT INTO DEPT VALUES
+ (10,'ACCOUNTING','NEW YORK');
+INSERT INTO DEPT VALUES (20,'RESEARCH','DALLAS');
+INSERT INTO DEPT VALUES
+ (30,'SALES','CHICAGO');
+INSERT INTO DEPT VALUES
+ (40,'OPERATIONS','BOSTON');
+
+CREATE TABLE BONUS
+ (
+ ENAME VARCHAR2(10),
+ JOB VARCHAR2(9),
+ SAL NUMBER,
+ COMM NUMBER
+ );
+
+CREATE TABLE SALGRADE
+ ( GRADE NUMBER,
+ LOSAL NUMBER,
+ HISAL NUMBER );
+
+INSERT INTO SALGRADE VALUES (1,700,1200);
+INSERT INTO SALGRADE VALUES (2,1201,1400);
+INSERT INTO SALGRADE VALUES (3,1401,2000);
+INSERT INTO SALGRADE VALUES (4,2001,3000);
+INSERT INTO SALGRADE VALUES (5,3001,9999);
+
+CREATE TABLE DUMMY
+ ( DUMMY NUMBER );
+
+INSERT INTO DUMMY VALUES (0);
+
+COMMIT;
+
+EXIT;
diff --git a/reladminif/test/demodrop.sql b/reladminif/test/demodrop.sql
new file mode 100644
index 0000000..282bf6d
--- /dev/null
+++ b/reladminif/test/demodrop.sql
@@ -0,0 +1,42 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+--
+-- $Header: /home/rasdev/CVS-repository/rasdaman/reladminif/test/demodrop.sql,v 1.3 2003/12/27 23:11:46 rasdev Exp $
+-- Copyright (c) Oracle Corporation 1988, 1993. All Rights Reserved.
+--
+--
+-- This script drops the SQL*Plus demonstration tables.
+--
+-- It should be STARTed by each owner of the tables.
+
+set termout on
+prompt Dropping demonstration tables. Please wait.
+set termout off
+
+DROP TABLE EMP;
+DROP TABLE DEPT;
+DROP TABLE BONUS;
+DROP TABLE SALGRADE;
+DROP TABLE DUMMY;
+
+EXIT;
diff --git a/reladminif/test/eoidtest.C b/reladminif/test/eoidtest.C
new file mode 100644
index 0000000..66aa0ee
--- /dev/null
+++ b/reladminif/test/eoidtest.C
@@ -0,0 +1,128 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include "raslib/rmdebug.hh"
+#include <iostream.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "dbnamedobject.hh"
+#include "dbref.hh"
+#include "dbobject.hh"
+#include "oidif.hh"
+#include "adminif.hh"
+#include "databaseif.hh"
+#include "oidif.hh"
+#include "eoid.hh"
+#include "transactionif.hh"
+
+#include "alltypes.hh"
+#include "typefactory.hh"
+
+#include "dbmddcoll.hh"
+#include "dbmddcolloidentry.hh"
+#include "dbmddobj.hh"
+
+#include "raslib/rmdebug.hh"
+
+RMINITGLOBALS('C')
+
+int RManDebug2 = 8;
+int RManModule = 3;
+
+int
+main(int argc, char *argv[])
+ {
+ typedef map< EOId, string, less<EOId> > ap;
+ typedef pair< EOId, string > air;
+ ap* myMap = new ap();
+ AdminIf* myAdmin;
+ DatabaseIf database;
+ myAdmin = AdminIf::instance();
+ database.open("RMAN");
+ TransactionIf ta;
+ ta.begin(&database);
+
+ cout << "DBName " << database.getName() << endl;
+ cout << " or " << AdminIf::getCurrentDatabaseIf()->getName() << endl;;
+
+ OId* o = new OId(1, OId::BASETYPEOID);
+ EOId* e = new EOId("asys", "abase", 0L, 3);
+ string* s = new string("aa0");
+ myMap->insert(air(*e, *s));
+
+ e = new EOId("asys", "abase", 5L, 3);
+ s = new string("aa5");
+ myMap->insert(air(*e, *s));
+
+ e = new EOId("asys", "abase", 10L, 3);
+ s = new string("aa10");
+ myMap->insert(air(*e, *s));
+
+ e = new EOId("bsys", "abase", 0L, 3);
+ s = new string("ba0");
+ myMap->insert(air(*e, *s));
+
+ e = new EOId("bsys", "abase", 5L, 3);
+ s = new string("ba5");
+ myMap->insert(air(*e, *s));
+
+ e = new EOId("bsys", "abase", 10L, 3);
+ s = new string("ba10");
+ myMap->insert(air(*e, *s));
+
+ e = new EOId("asys", "bbase", 0L, 3);
+ s = new string("ab0");
+ myMap->insert(air(*e, *s));
+
+ e = new EOId("asys", "bbase", 5L, 3);
+ s = new string("ab5");
+ myMap->insert(air(*e, *s));
+
+ e = new EOId("asys", "bbase", 10L, 3);
+ s = new string("ab10");
+ myMap->insert(air(*e, *s));
+
+ e = new EOId("bsys", "bbase", 0L, 3);
+ s = new string("bb0");
+ myMap->insert(air(*e, *s));
+
+ e = new EOId("bsys", "bbase", 10L, 3);
+ s = new string("bb10");
+ myMap->insert(air(*e, *s));
+
+ e = new EOId("bsys", "bbase", 15L, 3);
+ s = new string("bb15");
+ myMap->insert(air(*e, *s));
+
+ e = new EOId("asys", "abase", 5L, 3);
+ s = new string("fuenf b");
+ myMap->insert(air(*e, *s));
+
+ int i = 0;
+ ap::iterator iter = myMap->begin();
+ for (; iter != myMap->end(); iter++)
+ {
+ i++;
+ cout << "Nummer " << i << " key " << (*iter).first << " value " << (*iter).second.c_str() << endl;
+ }
+ }
diff --git a/reladminif/test/indextest.cc b/reladminif/test/indextest.cc
new file mode 100644
index 0000000..fdcdfa9
--- /dev/null
+++ b/reladminif/test/indextest.cc
@@ -0,0 +1,227 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include "mymalloc/mymalloc.h"
+#include <stdlib.h>
+#include <iostream>
+
+#include "chartype.hh"
+#include "cachetamgr/persmddcoll.hh"
+#include "cachetamgr/persmddobj.hh"
+#include "cachetamgr/perstile.hh"
+#include "cachetamgr/persmddcolliter.hh"
+
+#include "adminif.hh"
+#include "databaseif.hh"
+#include "transactionif.hh"
+#include "oidif.hh"
+
+#include "raslib/rminit.hh"
+#include "typefactory.hh"
+
+#include "dbmddobj.hh"
+#include "dbmddcoll.hh"
+
+#include "mddbasetype.hh"
+#include "mdddimensiontype.hh"
+#include "settype.hh"
+
+#ifndef BASEDB_O2
+#include "externs.h"
+#endif
+
+RMINITGLOBALS('C')
+#ifndef BASEDB_O2
+char* O2DBName = "RASBASE";
+#else
+char* O2DBName = "NorbertBase";
+#endif
+char *collName = "testColl";
+char defaultCollName[]= "ObjsContainer";
+
+#ifdef BASEDB_O2
+extern char* myExecArgv0 = "";
+#endif
+
+int
+main( int argc, char** argv)
+ {
+#ifdef BASEDB_O2
+ myExecArgv0 = argv[0];
+#endif
+ RManDebug = 3;
+#ifndef BASEDB_O2
+ RManModule = 0;
+#endif
+ RMInit::logOut = cout.rdbuf();
+ RMInit::dbgOut = cout.rdbuf();
+ RMInit::tileSize = 12;
+ MDDStorage::DefaultIxType = MDDStorage::RPlusTreeNode;
+
+ // variables representing O2 database, ta and session
+ DatabaseIf db;
+
+ // don't forget to initialize before using AdminIf!
+ AdminIf* myAdmin = AdminIf::instance();
+ TransactionIf ta;
+ // connect to the database
+ cout << "Connecting to database " << O2DBName << "..." << endl;
+ int errorDBOpen;
+ try {
+ errorDBOpen = db.open(O2DBName);
+ }
+ catch(...)
+ {
+ cout << "Caught Exception " << endl;
+ exit(-1);
+ }
+ ta.begin(&db);
+ int i = PersMDDColl::destroyRoot(collName, &db);
+ ta.commit();
+ ta.begin(&db);
+ const CollectionType* greyset = TypeFactory::mapSetType("GreySet");
+ MDDDimensionType* mddtype = (MDDDimensionType*)TypeFactory::mapMDDType("GreyCube");
+ if (!mddtype || !greyset)
+ {
+ cout << "didnt find types" << endl;
+ exit(-1);
+ }
+ OId oColl;
+ if (OId::allocateMDDCollOId(&oColl) == 0)
+ {
+ }
+ else
+ cout <<"Error allocating OId for collection " << endl;
+ PersMDDColl* col;
+ try {
+ // CollectionType* ct = TypeFactory::mapSetType("ObjsContainerType");
+ col = PersMDDColl::createRoot(collName, oColl, greyset, &db);
+ }
+ catch (...)
+ {
+ cout << "Error creating PersMDDColl" << endl;
+ exit(-1);
+ }
+
+ greyset = TypeFactory::mapSetType("GreySet3");
+ mddtype = (MDDDimensionType*)TypeFactory::mapMDDType("GreyCube");
+
+ OId oid1;
+ if (OId::allocateMDDOId(&oid1) == 0)
+ {
+
+ }
+ else
+ {
+ cout << "Error by allocation of OId" <<endl;
+ exit(1);
+ }
+
+ // read root object
+
+ PersMDDColl objsSet(collName);
+
+
+ // create MDD Object 1
+
+ r_Sinterval limits1Obj1(0l,100l);
+ r_Sinterval limits2Obj1(0l,100l);
+ r_Sinterval limits3Obj1(0l,100l);
+ r_Minterval dom(3);
+ dom << limits1Obj1 << limits2Obj1 << limits3Obj1;
+
+ PersMDDObj* MDDObj1 = new PersMDDObj(mddtype, dom, O2DBName, oid1);
+ cout << "created new persmddobj" << endl;
+
+ char* test = (char*)mymalloc((dom.cell_count() + 1) * mddtype->getBaseType()->getSize());
+ for (i = 0; i < 1000; i++)
+ test[i] = i%255;
+
+ dom[0].set_interval(0l,1l);
+ dom[1].set_interval(0l,1l);
+ dom[2].set_interval(0l,1l);
+ PersTile* tile1Obj1 = new PersTile(dom, mddtype->getBaseType(), test);
+ MDDObj1->insertTile(tile1Obj1);
+ cout << "1--------------" << endl;
+
+ dom[0].set_interval(2l,3l);
+ dom[1].set_interval(0l,1l);
+ dom[2].set_interval(0l,1l);
+ tile1Obj1 = new PersTile(dom, mddtype->getBaseType(), test);
+ MDDObj1->insertTile(tile1Obj1);
+ cout << "2--------------" << endl;
+
+ dom[0].set_interval(4l,5l);
+ dom[1].set_interval(0l,1l);
+ dom[2].set_interval(0l,1l);
+ tile1Obj1 = new PersTile(dom, mddtype->getBaseType(), test);
+ MDDObj1->insertTile(tile1Obj1);
+ cout << "3--------------" << endl;
+
+ dom[1].set_interval(0l,1l);
+ dom[0].set_interval(20l,21l);
+ dom[2].set_interval(0l,1l);
+ tile1Obj1 = new PersTile(dom, mddtype->getBaseType(), test);
+ MDDObj1->insertTile(tile1Obj1);
+ cout << "4--------------" << endl;
+
+ dom[1].set_interval(0l,1l);
+ dom[0].set_interval(22l,23l);
+ dom[2].set_interval(0l,1l);
+ tile1Obj1 = new PersTile(dom, mddtype->getBaseType(), test);
+ MDDObj1->insertTile(tile1Obj1);
+ cout << "5--------------" << endl;
+
+ dom[1].set_interval(0l,1l);
+ dom[0].set_interval(24l,25l);
+ dom[2].set_interval(0l,1l);
+ tile1Obj1 = new PersTile(dom, mddtype->getBaseType(), test);
+ MDDObj1->insertTile(tile1Obj1);
+ cout << "6--------------" << endl;
+
+ dom[1].set_interval(0l,1l);
+ dom[0].set_interval(10l,11l);
+ dom[2].set_interval(0l,1l);
+ tile1Obj1 = new PersTile(dom, mddtype->getBaseType(), test);
+ MDDObj1->insertTile(tile1Obj1);
+ cout << "7--------------" << endl;
+
+ dom[1].set_interval(0l,1l);
+ dom[0].set_interval(26l,27l);
+ dom[2].set_interval(0l,1l);
+ tile1Obj1 = new PersTile(dom, mddtype->getBaseType(), test);
+ MDDObj1->insertTile(tile1Obj1);
+ cout << "8--------------" << endl;
+
+ objsSet.insert(MDDObj1);
+
+ r_Point po("[10,0,1]");
+ char* utest = MDDObj1->pointQuery(po);
+ if (utest)
+ cout << "works" << endl;
+ else
+ cout << "failure" << endl;
+ ta.commit();
+ db.close();
+ }
+
+
diff --git a/reladminif/test/perstest.C b/reladminif/test/perstest.C
new file mode 100644
index 0000000..118fcf4
--- /dev/null
+++ b/reladminif/test/perstest.C
@@ -0,0 +1,1155 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include "mymalloc/mymalloc.h"
+#define TEST_PROTECTED
+#define TEST_PRIVATE
+
+#include <stdlib.h>
+#include <iostream.h>
+
+#include "ulongtype.hh"
+#include "cachetamgr/persmddcoll.hh"
+#include "cachetamgr/persmddobj.hh"
+#include "cachetamgr/perstile.hh"
+#include "cachetamgr/persmddcolliter.hh"
+
+#include "adminif.hh"
+#include "databaseif.hh"
+#include "transactionif.hh"
+#include "oidif.hh"
+
+#include "raslib/rminit.hh"
+#include "typefactory.hh"
+
+#include "dbmddobj.hh"
+#include "dbmddcoll.hh"
+
+#include "mddbasetype.hh"
+#include "mdddomaintype.hh"
+#include "settype.hh"
+
+#include "externs.h"
+
+
+
+/*
+ Global Variables
+*/
+
+RMINITGLOBALS('C')
+
+static char* O2DBName;
+char *collName;
+char defaultCollName[]= "ObjsContainer";
+OId globalOId1, globalOId2;
+OId globalCollOId;
+EOId globalEOId[4];
+int numObjsCreated;
+TransactionIf ta;
+int ExitNo;
+
+/*
+ Functions
+*/
+
+int
+getOption( )
+{
+ unsigned int result;
+ cout << endl;
+ cout << "Choose Option : " << endl;
+ cout << "-----------------------------------------------------------------"<<endl;
+ cout << " 1 - Create MDD collection with name .. " << collName << endl;
+ cout << " 2 - Populate collection with MDD objects (testConstructors) " << endl;
+ cout << " 3 - Access MDD collection given name (testAccessing) " << endl;
+ cout << " 4 - Access MDD collection given OId (testAccessing)" << endl;
+ cout << " 5 - Access MDD object given OId (testAccessingMDDObj) " << endl;
+ cout << " 6 - Remove MDD object from the collection given OId (testRemove) "<<endl;
+ cout << " 7 - Test PersMDDObj::intersect( ) (testSearch) " <<endl;
+ cout << " 8 - Test PersMDDColl::getCardinality( ) "<<endl;
+ cout << " 9 - Test PersMDDObj get functions "<< endl;
+ cout << " 10 - Remove MDD Collection given OId " << endl;
+ cout << " 11 - Insert MDD given OId in a second collection "<< endl;
+ cout << " 12 - Insert tile in MDD given OId "<< globalOId1 <<endl;
+ cout << " 13 - Test removeTile from MDD "<< globalOId1 << endl;
+ ExitNo = 14;
+ cout << " " << ExitNo << " - Exit " << endl;
+ cout << "------------------------------------------------------------------"<<endl;
+ cout << "Enter option: ";
+ cin >> result;
+ switch (result)
+ {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ return result;
+ break;
+ default:
+ return getOption();
+ }
+}
+
+// 1 - Create MDD collection
+static int createMDDColl( const char* collName, DatabaseIf* db );
+
+// 2 - Populate collection with MDD objects
+static void testConstructors( char* cn );
+
+// 3 - Retrieves an MDD collection with name cn and prints contents:
+static void testAccessing( char* cn );
+
+// 4 - Retrieves an MDD collection with OId o and prints contents:
+static void testAccessing( OId o );
+
+// 5 - Retrieves an MDD object with OId o and prints contents:
+static void testAccessingMDDObj( OId o );
+
+// Removes one of the MDD objects in the collection
+static void testRemove( );
+
+// 6 - Removes MDD object with OId o in the collection
+static void testRemove( OId o );
+
+// 7 - Test PersMDDObj::intersect( ) objects of the collection
+static void testSearch( );
+
+// 8 - Test PersMDDColl::getCardinality( )
+static void testGetCardinality( char* cn);
+
+// 9 - Scans collection and tests PersMDDObj get functions
+static void testGetFunctions( );
+
+//10 - Remove MDD collection given OId
+
+//11 - Insert MDD given OId in a second collection
+static void testInsertMDDObjColl( OId o, char* cn );
+
+//12 - Test later insertion of tile in PersMDDObj
+static void testLaterInsert( OId o );
+
+//13 - Test removeTile from an MDD obj
+static void testRemoveTile( OId o );
+
+// Tries accessing several OIds, including ilegal ones, to test
+// several error conditions.
+static void testAccessingOId( );
+
+
+/*************************************************************
+ * Function name.: int main( int argc, char** argv)
+ *
+ * Arguments.....:
+ * argc: number of arguments given to program
+ * argv: array of char* with arguments
+ * Return value..: exit status
+ * Description...: none
+ ************************************************************/
+int
+main( int argc, char** argv)
+{
+RManDebug = 10;
+RManModule = 0;
+RMInit::logOut = cout.rdbuf();
+RMInit::dbgOut = cout.rdbuf();
+RMInit::tileSize = 12;
+MDDStorage::DefaultIxType = MDDStorage::RPlusTreeNode;
+
+ // variables representing O2 database, ta and session
+ DatabaseIf database;
+
+ if( argc < 2 ) {
+ cout << "Usage: test_persmddcoll <database> [collName]" << endl;
+ return -1;
+ }
+ O2DBName = strdup( argv[1] );
+ if ( argc == 3 ) collName = strdup( argv[2] );
+ else
+ collName = defaultCollName;
+
+ // don't forget to initialize before using AdminIf!
+ AdminIf* myAdmin = AdminIf::instance();
+
+
+ // connect to the database
+ cout << "Connecting to database " << O2DBName
+ << "..." << endl;
+ int errorDBOpen;
+ try{
+ errorDBOpen = database.open( O2DBName );
+ }
+ catch( ...)
+ {
+ cout << "Caught Exception " << endl;
+ errorDBOpen = -6;
+ }
+ if ( errorDBOpen < 0 )
+ {
+ cout << "Database doesn't exist. Create it new ... " << endl;
+ cout << "Creating new database " << O2DBName
+ << "..." << endl;
+ database.create( O2DBName, "TestSMSchema" );
+ cout << "Connecting to database " << O2DBName
+ << "..." << endl;
+ try{
+ errorDBOpen = database.open( O2DBName );
+ }
+ catch(...)
+ {
+ errorDBOpen = -6;
+ }
+ }
+ if ( errorDBOpen < 0 )
+ {
+ cout << "Failed at opening newly created database " << errorDBOpen << endl;
+ cout << "Exiting " << endl;
+ return errorDBOpen;
+ }
+
+ ta.begin( &database );
+ cout << endl << "Deleting root object from the database ..." <<endl;
+ int i = PersMDDColl::destroyRoot( collName, &database );
+ cout << " i == " << i << endl;
+ // cout << " &database = " << long( &database) << endl;
+ ta.commit( );
+
+ char c;
+ int error;
+
+ for( unsigned opt = getOption( ); opt != ExitNo ; opt = getOption( ) )
+ {
+ cout <<"Transaction begin ... " << endl;
+ ta.begin( &database );
+ switch ( opt )
+ {
+ case 1: // 1 - Create MDD collection with name
+ // create root collection
+ cout << endl << "Creating mdd types and root collection..." << endl;
+ if ( createMDDColl( collName, &database ) != 0 )
+ {
+ cout <<"Error caught ................."<< endl;
+ cout << endl << "Ending O2 session..." << endl;
+ ta.commit( );
+ database.close( );
+ delete myAdmin;
+ exit( 1 );
+ }
+ break;
+
+ case 2: // 2 - Populate collection with MDD objects (testConstructors)
+ // create objects and put them in the collection
+ cout << endl << "Populate collection ..." << endl;
+ testConstructors( collName );
+ break;
+
+ case 3: // 3 - Access MDD collection given name (testAccessing)
+ // read coll and print contents
+ cout << endl << "Read collection " << collName << " and print contents..." << endl;
+ testAccessing( collName );
+ break;
+
+ case 4: // 4 - Access MDD collection given OId (testAccessing)
+ cout << endl << "Read collection " << globalCollOId << " and print contents..." << endl;
+ testAccessing( globalCollOId );
+ break;
+
+ case 5: // 5 - Access MDD object given OId (testAccessingMDDObj)
+ cout << endl << "Test Accessing MDD with OId " << globalOId1 << " ... " << endl;
+ testAccessingMDDObj( globalOId1 );
+ break;
+
+ case 6: // 6 - Remove MDD object from the collection given OId (testRemove)
+ cout<< endl << "Remove MDD with OId " << globalOId1 << " ..." << endl;
+ testRemove( globalOId1 );
+ break;
+
+ case 7: // 7 - Test PersMDDObj::intersect( ) (testSearch)
+ cout << endl << "Test region search ..." << endl;
+ testSearch( );
+ break;
+
+ case 8: // 8 - Test PersMDDColl::getCardinality( )
+ cout << endl << "Get cardinality of collection" << collName <<" ..." << endl;
+ testGetCardinality( collName );
+ break;
+
+ case 9: // 9 - Test PersMDDObj get functions
+ cout << endl <<"Test PersMDDObj get functions " << endl;
+ testGetFunctions( );
+ break;
+
+ case 10: // 10 - Remove MDD Collection given OId
+ cout << endl << "Remove MDD collection with OId ";
+ cout << globalCollOId << " ..." << endl;
+ error = PersMDDColl::destroyRoot( globalCollOId, &database );
+ if (error )
+ cout << " Error destroying root " << endl;
+ break;
+
+ case 11: // 11 - Insert MDD given OId in a second collection
+ cout << endl << "Insert Object with OId " << globalOId1;
+ cout << " in collection Coleccao1 " << endl;
+ cout << "First, create collection" << endl;
+ if ( createMDDColl( "Coleccao1", &database ) != 0 )
+ {
+ cout <<"Error caught ................."<< endl;
+ cout << endl << "Ending O2 session..." << endl;
+ ta.commit( );
+ database.close( );
+ delete myAdmin;
+ exit( 1 );
+ }
+ cout << "Then insert object with OId "<< globalOId1 << endl;
+ testInsertMDDObjColl( globalOId1 , "Coleccao1");
+ cout << endl;
+ break;
+
+ case 12: // 12 - Insert new tiles in the MDD object
+ cout << endl << "Insert Tile in object with OId " << globalOId1;
+ testLaterInsert( globalOId1 );
+ cout << endl;
+ break;
+
+ case 13: // 13 - Remove a tile from the MDD object
+ cout << endl << "Remove Tile from object with OId " << globalOId1;
+ testRemoveTile( globalOId1 );
+ cout << endl;
+ break;
+
+ default:
+ break;
+ }
+ cout <<"Transaction abort (A/a) or commit (default)? ";
+ cin >> c;
+ if ( c == 'A' || c == 'a' )
+ {
+ ta.abort( );
+ cout <<"End of Transaction Abort..."<<endl;
+ }
+ else
+ {
+ ta.commit( );
+ cout <<"End of Transaction Commit..."<<endl;
+ }
+ if ( opt == 6 )
+ {
+ cout<<"Garbage ? ( y /n ) ";
+ cin >> c;
+ if (c =='y' || c == 'Y' )
+ {
+ cout <<"Garbaging ..."<< endl;
+ ta.begin( &database );
+ database.garbage( );
+ ta.commit( );
+ }
+ }
+ cout <<"End of transaction commit... "<<endl;
+ } // for opt
+
+
+ cout << endl << "Ending O2 session..." << endl;
+ database.close( );
+ delete myAdmin;
+
+ free( O2DBName );
+ if ( collName != defaultCollName ) free( collName );
+ return 0;
+
+}
+
+/*************************************************************
+ * Functions......:
+ *
+ * static void
+ * testInsertMDDObjColl( OId o, char* cn )
+ *
+ * static void
+ * testConstructors( char* collName )
+ *
+ ************************************************************/
+static void
+testInsertMDDObjColl( OId o, char* cn )
+{
+ cout << "....testInsertMDDObjColl "<< o <<","<< cn << endl;
+ PersMDDObj* obj = new PersMDDObj( O2DBName,o );
+ PersMDDColl objsSet( cn );
+ objsSet.insert( obj );
+ delete obj;
+
+}
+
+static void testConstructors( char* collName )
+{
+
+ const BaseType* ulongTypeObj = TypeFactory::mapType("ULong");
+ const BaseType* boolTypeObj = TypeFactory::mapType("Bool");
+ const MDDBaseType* mType1 = (const MDDBaseType* ) TypeFactory::mapMDDType("TestSMDomainType2D");
+ const MDDBaseType* mType2 = (const MDDBaseType* ) TypeFactory::mapMDDType("TestSMDomainType3D");
+
+ cout << "....testConstructors"<< endl;
+
+ OId oid1;
+ if ( OId::allocateMDDOId( &oid1 ) == 0)
+ cout << "Successfull allocation of OId " << oid1 <<endl;
+ else
+ {
+ cout << "Error by allocation of OId" <<endl;
+ exit(1);
+ }
+ OId oid2;
+ if ( OId::allocateMDDOId( &oid2 ) == 0)
+ cout << "Successfull allocation of OId " << oid2 <<endl;
+ else
+ {
+ cout << "Error by allocation of OId" <<endl;
+ exit(1);
+ }
+
+ globalOId1 = oid1;
+ globalOId2 = oid2;
+
+ // read root object
+
+ PersMDDColl objsSet(collName);
+
+
+ // create MDD Object 1
+
+ cout << "Creating mddObj1" << endl;
+ cout << "tile 1 = nil, 10-12, 20-24 "<< endl;
+ r_Sinterval limits1Obj1(10l,12l);
+ r_Sinterval limits2Obj1(20l,24l);
+ r_Minterval dom(2);
+ dom << limits1Obj1 << limits2Obj1;
+
+ r_Minterval tmpInt = *( ( MDDDomainType* ) mType1 )->getDomain( );
+ PersMDDObj* MDDObj1 = new PersMDDObj( mType1, tmpInt, O2DBName, oid1 );
+
+ char* test = (char*)mymalloc((dom.cell_count() + 1) * 4);
+ memset(test, 0, (dom.cell_count() + 1) * 4);
+ cout << "created new persmddobj" << endl;
+ PersTile* tile1Obj1 = new PersTile( dom, ulongTypeObj, test );
+ cout << "created new perstile" << endl;
+ MDDObj1->insertTile(tile1Obj1);
+ cout << "inserted tile" << endl;
+
+ cout << "tile 2 = nil, 0-400, 22-24 "<< endl;
+ dom[0].set_interval(0l,400l);
+ dom[1].set_interval(22l,24l);
+ test = (char*)mymalloc((dom.cell_count() + 1) * 4);
+ memset(test, 0, (dom.cell_count() + 1) * 4);
+ cout << "created new perstile" << endl;
+ PersTile* tile2Obj1 = new PersTile( dom, ulongTypeObj, test );
+ cout << "insert tile" << endl;
+ MDDObj1->insertTile(tile2Obj1);
+ cout << "inserted tile" << endl;
+
+ cout << "tile 3 = nil, 0-600, 10-1000 "<< endl;
+ dom[0].set_interval(0l,600l);
+ dom[1].set_interval(10l,1000l);
+ test = (char*)mymalloc((dom.cell_count() + 1) * 4);
+ memset(test, 0, (dom.cell_count() + 1) * 4);
+ cout << "created new perstile" << endl;
+ PersTile* tile3Obj1 = new PersTile( dom, ulongTypeObj, test );
+ cout << "insert tile" << endl;
+ MDDObj1->insertTile(tile3Obj1);
+ cout << "inserted tile" << endl;
+
+ cout << "MDDObj1 == isPersistent:" << MDDObj1->isPersistent( )<< ";" <<endl;
+ MDDObj1->printStatus( );
+ cout << endl;
+
+ objsSet.insert(MDDObj1);
+
+ // create MDD Object
+ cout << "Creating mddObj2 "<< endl;
+ cout << "tile 1 = nil, 0-19, 20-59, 30-59 "<< endl;
+ r_Sinterval limits1Obj2(0l,19l);
+ r_Sinterval limits2Obj2(20l,59l);
+ r_Sinterval limits3Obj2(30l,59l);
+ r_Minterval dom2(3);
+ dom2 << limits1Obj2 << limits2Obj2 << limits3Obj2;
+
+ tmpInt = *( ( MDDDomainType* ) mType2 )->getDomain( );
+ PersMDDObj* MDDObj2 = new PersMDDObj( mType2, tmpInt, O2DBName, oid2 );
+
+ test = (char*)mymalloc((dom.cell_count() + 1) * 1);
+ memset(test, 0, (dom.cell_count() + 1) * 1);
+ PersTile* tile1Obj2 = new PersTile( dom2, boolTypeObj, test);
+ MDDObj2->insertTile( tile1Obj2 );
+
+ cout << "tile 2 = nil, 20-39, 60-79, 60-89 "<< endl;
+ dom2[0].set_interval(20l,39l);
+ dom2[1].set_interval(60l,79l);
+ dom2[2].set_interval(60l,89l);
+ test = (char*)mymalloc((dom.cell_count() + 1) * 1);
+ memset(test, 0, (dom.cell_count() + 1) * 1);
+ PersTile* tile2Obj2 = new PersTile( dom2, boolTypeObj, test);
+
+ MDDObj2->insertTile(tile2Obj2);
+
+
+ cout << "MDDObj2 == isPersistent:" << MDDObj2->isPersistent( )<< ";" <<endl;
+ MDDObj2->printStatus( );
+ cout << endl;
+
+/*
+ // This program doesn't work if the TA is aborted when OIds are
+ // allocated, even if all allocated OIds are binded. Question: is it
+ // because of dangling handles? This little test was done to
+ // check that.
+ // This without oids works with ta.abort
+ // conclusion: the problem with abort is not due to the handles
+ Handle hd;
+ d_Ref<DBMDDObj> refObj = MDDObj2->getDBMDDObjId();
+ hd = refObj.o2_get_handle();
+*/
+
+
+ objsSet.insert(MDDObj2);
+ numObjsCreated = 2;
+
+ cout << "Release all " << endl;
+
+ //( ( PersMDDColl ) objsSet ).releaseAll( );
+
+ cout << "Release all END" << endl;
+}
+
+
+/*************************************************************
+ * Function......: testAccessing( char* cn )
+ * testAccessing( OId o )
+ ************************************************************/
+
+static void testAccessing( char* cn )
+{
+ PersMDDObj* accessedObj;
+
+ cout << "....testAccessing collection "<< cn << endl;
+
+ try{
+ PersMDDColl objsSet( cn );
+
+ // To test PersMDDColl::printStatus( )
+ // objsSet.printStatus( );
+
+ // To test PersMDDObj::printStatus( ), MDDCollIter::createIterator( ) and
+ // MDDCollIter methods :
+
+ cout << "Iterating through the collection with PersMDDCollIter " << endl;
+ MDDCollIter* objsIt = objsSet.createIterator( );
+
+ for( int i = 1 ; objsIt->notDone( ); i++, objsIt->advance( ))
+ {
+ cout << i<<". MDD object in set:" << endl;
+ accessedObj = (PersMDDObj*) objsIt->getElement();
+ accessedObj->printStatus();
+ EOId eoid;
+ if ( accessedObj->getEOId( &eoid ) ==0 )
+ cout <<"EOId: " << eoid;
+ // old version cout <<"EOId: " << eoid.getSystemName( ) << eoid.getBaseName( ) << eoid.getOId( );
+ cout << endl << endl;
+ accessedObj->getEOId( &globalEOId[i-1] );
+ }
+ delete objsIt;
+ objsSet.releaseAll( );
+ }
+ catch ( r_Error& errObj)
+ {
+ cout <<"Error caught ................."<< endl;
+ }
+}
+
+static void testAccessing( OId o )
+{
+ PersMDDObj* accessedObj;
+
+ cout << "....testAccessing collection "<< o << endl;
+
+ try {
+ PersMDDColl objsSet( o, O2DBName );
+
+ OId o;
+ if ( objsSet.getOId( &o ) == 0 )
+ cout <<"getOId " << o << endl;
+ else
+ cout <<"Error getOId " << endl;
+
+ EOId eo;
+ if ( objsSet.getEOId( &eo ) == 0 )
+ cout << "getEOId " << eo <<endl;
+ // cout << "getEOId " << eo.getSystemName( ) <<":"<<eo.getBaseName( )<<":"<<eo.getOId( ) << endl;
+ else
+ cout <<"Error getEOId " << endl;
+
+ // To test PersMDDColl::printStatus( )
+ objsSet.printStatus( );
+
+ // To test PersMDDObj::printStatus( ), MDDCollIter::createIterator( ) and
+ // MDDCollIter methods :
+
+ cout << "Iterating through the collection with PersMDDCollIter " << endl;
+ MDDCollIter* objsIt = objsSet.createIterator( );
+
+ for( int i = 1 ; objsIt->notDone( ); i++, objsIt->advance( ))
+ {
+ cout << i<<". MDD object in set:" << endl;
+ accessedObj = (PersMDDObj*) objsIt->getElement();
+ accessedObj->printStatus();
+ EOId eoid;
+ if ( accessedObj->getEOId( &eoid ) ==0 )
+ cout <<"EOId: " << eoid ;
+ // cout <<"EOId: " << eoid.getSystemName( ) << eoid.getBaseName() << eoid.getOId( );
+ cout << endl << endl;
+ accessedObj->getEOId( &globalEOId[i-1] );
+ }
+ delete objsIt;
+ objsSet.releaseAll( );
+ }
+ catch ( r_Error& errObj)
+ {
+ cout <<"Error caught ................."<< endl;
+ }
+
+}
+
+/*************************************************************
+ * Function......: testAccessingMDDObj(OId o )
+ * testAccessingOId( )
+ *
+ ************************************************************/
+static void testAccessingMDDObj(OId o)
+{
+ PersMDDObj *mObj;
+
+ cout << "....testAccessingMDDObj"<<endl;
+
+ try{
+ mObj = new PersMDDObj( O2DBName, o);
+ mObj->printStatus( );
+ delete mObj;
+ }
+ catch (...)
+ {
+ cout <<" Object not found..." << endl;
+
+ }
+}
+
+static void testAccessingOId()
+{
+ PersMDDObj *mObj1, *mObj2, *mObj;
+ int result;
+ OId o(70000);
+ OId o1(5010);
+ OId o2(0);
+ OId o3(5);
+
+ cout << "....testAccessingOId"<<endl;
+
+
+ cout << "Test OIdIf::getType( )..."<<endl;
+ cout << "1.st MDDObj " << endl;
+ cout << "getType " << globalOId1.getType( O2DBName ) << endl;
+
+ cout << "2.nd MDDObj " << endl;
+ cout << "getType " << globalOId2.getType( O2DBName ) << endl;
+
+ // This crashes
+ // cout << "OId == 0 " << endl;
+ // cout << "getType " << o2.getType( O2DBName ) << endl;
+
+ cout << "OId == 5 " << endl;
+ cout << "getType " << o3.getType( O2DBName ) << endl;
+
+ cout << "MDDCollection " << endl;
+ cout << "getType " << globalCollOId.getType( O2DBName ) << endl;
+ // mObj2 = new PersMDDObj( O2DBName, globalOId2);
+ // mObj2->printStatus( );
+
+ cout << "Not used OId " << endl;
+ cout << "getType " << o1.getType( O2DBName ) << endl;
+
+ cout << "Nonexistent OId " << endl;
+ cout << "getType " << o.getType( O2DBName ) << endl;
+ // mObj2 = new PersMDDObj( O2DBName, globalOId2);
+ // mObj2->printStatus( );
+
+ cout <<"Loading PersMDDObjs from OIds " << endl;
+ mObj1 = new PersMDDObj( O2DBName, globalOId1);
+ mObj1->printStatus( );
+ mObj2 = new PersMDDObj( O2DBName, globalOId2);
+ mObj2->printStatus( );
+
+ delete mObj1;
+ delete mObj2;
+
+
+ for ( int i = 0; i < numObjsCreated; i++ )
+ {
+ cout << "Reading with " << i+1<< ".th EOId " ;
+ cout << globalEOId[i];
+ // cout << globalEOId[i].getSystemName( );
+ // cout << " ; "<< globalEOId[i].getBaseName( ) << ";" << globalEOId[i].getOId( );
+ cout << endl;
+
+
+ // result = o2_externalNameGetObject( &globalEOId[i], &hdObj );
+/*
+ result = globalEOId[i].getObject( &hdObj );
+ if ( result == 0 )
+ {
+ DBMDDObjId obj1(hdObj);
+ mObj = new PersMDDObj(obj1);
+ mObj->printStatus( );
+ }
+ else
+ cout << "No such object!!" << endl;
+ // o2_unref_handle( );
+ delete mObj;
+*/
+ }
+
+}
+
+/*************************************************************
+ * Function......: testLaterInsert()
+ *
+ ************************************************************/
+
+static void testLaterInsert( OId o )
+{
+ PersMDDObj* accessedObj;
+
+ cout << "....testLaterInsert"<<endl;
+
+ try{
+ accessedObj = new PersMDDObj( O2DBName, o);
+ }
+ catch (...)
+ {
+ cout <<" Object not found..." << endl;
+ return;
+ }
+
+ cout << "Current status of MDD object : " << endl;
+ accessedObj->printStatus( );
+ cout << endl << "Inserting new Tile ..."<< endl;
+
+ PersTile *t, *t2, *t3;
+ switch( accessedObj->getDimension( ) )
+ {
+ case 2 :
+ t2 = new PersTile( r_Minterval("[40:60,80:1200]"),
+ accessedObj->getCellType( ) );
+ t = t2;
+ break;
+ case 3 :
+ t3 = new PersTile(r_Minterval("[40:60,80:100,0:20]"),
+ accessedObj->getCellType( ) );
+ t = t3;
+ break;
+ default:
+ cout << "Error Dimensionality not expected" << endl;
+ break;
+ }
+ accessedObj->insertTile(t);
+ cout << " New status after insertion:" << endl;
+ accessedObj->printStatus();
+ cout << endl << endl;
+
+ delete accessedObj;
+}
+
+
+/*************************************************************
+ * Function......: testSearch()
+ *
+ ************************************************************/
+static void testSearch()
+{
+
+ MDDObj* accessedObj;
+
+ cout << "....testSearch"<<endl;
+
+ PersMDDColl objsSet(collName);
+
+ MDDCollIter* objsIt = objsSet.createIterator( );
+
+ for( int i = 1 ; objsIt->notDone( ); i++, objsIt->advance( ))
+ {
+ accessedObj = objsIt->getElement();
+
+ cout << "Accessed Object " << endl;
+ accessedObj->printStatus( );
+ cout << endl;
+
+ if (i == 1 || i == 2)
+ {
+ r_Minterval searchInt1(2);
+ r_Minterval searchInt2(3);
+ vector< Tile* >* entriesList;
+
+ cout << " -- " << i << ". MDD object in list. Search for:";
+ switch (i) {
+ case 1: searchInt1[0].set_interval(10l,20l);
+ searchInt1[1].set_interval(10l,30l);
+ cout << " 10-20, 10-30" << endl;
+ entriesList = accessedObj->intersect(searchInt1);
+ break;
+ case 2: searchInt2[0].set_interval(10l,20l);
+ searchInt2[1].set_interval(10l,30l);
+ searchInt2[2].set_interval(40l,50l);
+ cout << " 10-20, 10-30, 40-50" <<endl;
+ entriesList = accessedObj->intersect(searchInt2);
+ break;
+ default: break;
+ }
+ cout << " -- Search result: " << endl;
+ vector<Tile*>::iterator entryIt = entriesList->begin();
+
+ while (entryIt != entriesList->end())
+ {
+ // (*entryIt)->printStatus();
+ r_Minterval tileInterval = (*entryIt)->getDomain();
+ int dimensionality = tileInterval.dimension();
+
+ cout << " PersTile printStatus";
+ cout << " domain == " << dimensionality << ": ";
+ for (int i = 0; i <dimensionality; i++)
+ cout << tileInterval[i].low() << "-"
+ << tileInterval[i].high() <<", ";
+ cout << endl;
+
+ entryIt++;
+ }
+ delete entriesList;
+ }
+ }
+ delete objsIt;
+ // objsSet.releaseAll( );
+}
+
+/*************************************************************
+ * Function......: testRemoveTile(OId o )
+ *
+ ************************************************************/
+static void testRemoveTile(OId o)
+{
+ PersMDDObj *mObj;
+
+ cout << "....testRemoveTile from MDD Obj "<< o << endl;
+
+ try{
+ mObj = new PersMDDObj( O2DBName, o);
+ mObj->printStatus( );
+ }
+ catch (...)
+ {
+ cout <<" Object not found..." << endl;
+ return;
+ }
+
+ vector<Tile*>* tiles = mObj->getTiles( );
+
+ if ( tiles->size( ) == 0 )
+ {
+ cout <<"MDD object has no tiles !! "<< endl;
+ return;
+ }
+ else
+ {
+ int ix = tiles->size( )/2;
+
+ cout << "Removing "<< ix <<". tile from MDD Obj "<< endl;
+ cout << "Tile Description: " << (*tiles)[ix]->getDomain( ) << endl;
+
+ PersTile* t = (PersTile*) (*tiles)[ix];
+
+ mObj->removeTile( (*tiles)[ix] );
+
+ delete tiles;
+ delete mObj;
+ }
+}
+
+/*************************************************************
+ * Function......: testGetCardinality( const char* cn )
+ * testGetFunctions()
+ *
+ ************************************************************/
+static void testGetCardinality( char* cn )
+{
+ cout << "....testGetCardinality( "<< cn << " )" << endl;
+
+ try{
+ PersMDDColl objsSet( cn );
+ cout<< "Cardinality of collection " << objsSet.getCardinality( ) <<endl;
+ }
+ catch( r_Error& errObj)
+ {
+ cout <<"Error caught ................."<< endl;
+ }
+}
+
+static void testGetFunctions()
+{
+ PersMDDObj* accessedObj;
+
+ cout << "....testGetFunctions"<<endl;
+
+ PersMDDColl objsSet(collName);
+
+ MDDCollIter* objsIt = objsSet.createIterator( );
+
+ vector< Tile* >* entriesList;
+
+ for( int i = 1 ; objsIt->notDone( ); i++, objsIt->advance( ))
+ {
+ r_Minterval currDom;
+ r_Minterval defDom;
+
+ cout << " " << i << ". Object" << endl;
+ accessedObj = (PersMDDObj*) objsIt->getElement();
+
+
+ defDom = accessedObj->getDefinitionDomain( );
+ cout << " GetDefinitionDomain result: ";
+ defDom.print_status( );
+ cout << endl;
+
+ currDom = accessedObj->getCurrentDomain( );
+ cout << " GetCurrentDomain result: ";
+ currDom.print_status( );
+ cout << endl;
+
+ entriesList = accessedObj->getTiles( );
+ cout << " -- GetTiles result: " << endl;
+ vector<Tile*>::iterator entryIt = entriesList->begin();
+
+ while (entryIt != entriesList->end())
+ {
+ // (*entryIt)->printStatus();
+ r_Minterval tileInterval = (*entryIt)->getDomain();
+ int dimensionality = tileInterval.dimension();
+
+ cout << " PersTile ";
+ cout << " domain == " << dimensionality << ": ";
+ for (int i = 0; i <dimensionality; i++)
+ cout << tileInterval[i].low() << "-" << tileInterval[i].high() <<", ";
+ cout << endl;
+ entryIt++;
+ }
+ delete entriesList;
+ }
+ delete objsIt;
+ objsSet.releaseAll( );
+}
+
+/*************************************************************
+ * Function......: testRemove()
+ * testRemove( OId o )
+ *
+ ************************************************************/
+
+static void testRemove()
+{
+ PersMDDObj* accessedObj;
+
+ cout << "....testRemove"<<endl;
+
+ PersMDDColl objsSet(collName);
+ // PersMDDColl objsSet("Qualquercoisa");
+ // To test PersMDDColl::printStatus and PersMDDColl::remove
+
+
+ MDDCollIter* objsIt = objsSet.createIterator( );
+
+ cout << "-- Remove second element from collection " << endl;
+
+ for( int i = 1 ; objsIt->notDone( ) && i < 2; i++, objsIt->advance( ))
+ {
+ accessedObj = (PersMDDObj*) objsIt->getElement();
+ }
+ cout << "Delete of objsIt:" << endl;
+ delete objsIt;
+ cout << "Finished Delete of objsIt." << endl;
+ cout << "Remove accessedObj:" << endl;
+ objsSet.remove( accessedObj );
+ cout << "Finished Remove accessedObj." << endl;
+}
+
+static void testRemove( OId o )
+{
+
+ cout << "....testRemove( OId == " << o <<" ) "<< endl;
+
+ PersMDDColl objsSet(collName);
+ objsSet.remove( o, O2DBName );
+}
+
+
+/*************************************************************
+ * Function......: createMDDColl( )
+ ************************************************************/
+static int
+createMDDColl( const char* collName, DatabaseIf* db )
+{
+cout << "createMDDColl(" << collName << ", " << db->getName() << ")" << endl;
+ MDDDomainType* mType1 = 0;
+ MDDDomainType* mType2 = 0;
+ MDDType* mt = 0;
+ CollectionType* collType1 = 0;
+
+ const BaseType* ulongTypeObj = TypeFactory::mapType("ULong");
+
+ const MDDDomainType* cmType1 =
+ ( MDDDomainType* ) TypeFactory::mapMDDType( "TestSMDomainType2D" );
+ if (cmType1)
+ cout << "cmType1 " << cmType1->getName() << endl;
+ const MDDDomainType* cmType2 =
+ ( MDDDomainType* ) TypeFactory::mapMDDType( "TestSMDomainType3D" );
+ if (cmType2)
+ cout << "cmType1 " << cmType2->getName() << endl;
+
+ const CollectionType* collType =
+ (CollectionType*)TypeFactory::mapSetType( "ObjsContainerType" );
+ if (collType)
+ cout << "collType " << collType->getName() << endl;
+
+
+ if( !cmType1 || !cmType2 || !collType )
+ {
+ cout << "types not found!" << endl;
+ char name1[] = "TestSMDomainType2D";
+ char name2[] = "TestSMDomainType3D";
+
+ r_Sinterval limits1Obj1(0l,1000l);
+ r_Sinterval limits2Obj1(0l,800l);
+ r_Minterval dom1(2);
+ dom1 << limits1Obj1 << limits2Obj1;
+ cout << "MDD Type 1 , domain "<< dom1 << endl;
+
+ cout << " tile 1 = nil, 0-19, 20-59, 30-59 "<< endl;
+ r_Sinterval limits1Obj2(0l,19l);
+ r_Sinterval limits2Obj2(20l,59l);
+ r_Sinterval limits3Obj2(30l,59l);
+ r_Minterval dom2(3);
+ dom2 << limits1Obj2 << limits2Obj2 << limits3Obj2;
+ cout << "MDD Type 2 , domain "<< dom2 << endl;
+
+ // MDDDomainType* mType1 =
+ mType1 =
+ new MDDDomainType((char*) name1, ( BaseType* ) ulongTypeObj, dom1 );
+ // MDDDomainType* mType2 =
+ mType2 =
+ new MDDDomainType((char*) name2, ( BaseType* ) ulongTypeObj, dom2 );
+
+ cout << "MDD Type1 == ";
+ mType1->print_status( cout );
+ cout << endl;
+ cout << "MDD Type2 == ";
+ mType2->print_status( cout );
+ cout << endl;
+
+ TypeFactory::addMDDType( mType1 );
+ TypeFactory::addMDDType( mType2 );
+
+ if ( !collType )
+ {
+ cout << "Collection type newly created " << endl;
+ // MDDType* mt = new MDDType( );
+ mt = new MDDType( );
+ cout << "MDDtype created "<< endl;
+ collType1 = new SetType( "ObjsContainerType", mType1 );
+ cout << "Set Type created ... ";
+ collType = collType1;
+ TypeFactory::addSetType( (SetType*) collType );
+ cout <<" and added "<< endl;
+
+ }
+
+ }
+ else
+ cout << "types were found!" << endl;
+ //ta.commit( );
+
+ //ta.begin( );
+
+ cout << "Creating root collection" << endl;
+
+ // cout << " &database = " << long( db ) << endl;
+
+ OId oColl;
+ if( OId::allocateMDDCollOId( &oColl ) == 0 )
+ cout <<"Successfully allocated OId for collection " << oColl << endl;
+ else
+ cout <<"Error allocating OId for collection " << endl;
+ globalCollOId = oColl;
+
+ PersMDDColl* col;
+ try {
+ // CollectionType* ct = TypeFactory::mapSetType( "ObjsContainerType" );
+ col = PersMDDColl::createRoot( collName, oColl, collType, db );
+ }
+ catch (...)
+ {
+ cout <<"Error caught ................."<< endl;
+ return -1;
+ }
+
+ cout << "Committing TA ..."<< endl;
+ ta.commit( );
+
+ /*
+
+ cout <<"Freeing types ... "<< endl;
+
+ // if ( mType1 ) delete mType1;
+ cout << "Type 1 freed . "<< endl;
+ // if ( mType2 ) delete mType2;
+ cout << "Type 2 freed . "<< endl;
+ // if ( mt ) delete mt;
+ cout << "Type mt freed . "<< endl;
+ // if ( collType1 ) delete collType1;
+ cout << "Types collType1 freed . "<< endl;
+ */
+ if ( col ) delete col;
+ cout << "Col freed . "<< endl;
+
+
+ ta.begin( db );
+ return 0;
+}
diff --git a/reladminif/test/test_databaseif.cc b/reladminif/test/test_databaseif.cc
new file mode 100644
index 0000000..46caa5f
--- /dev/null
+++ b/reladminif/test/test_databaseif.cc
@@ -0,0 +1,203 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************************
+ *
+ *
+ * PURPOSE:
+ * test class DatabaseIf.
+ *
+ *
+ * PREREQUISITES:
+ * - needs COMPDATE (compilation date) defined, eg. cc -DCOMPDATE=\"`date`\"
+ *
+ * COMMENTS:
+ *
+ ***********************************************************************/
+
+static const char rcsid[] = "@(#)reladminif,DatabaseIf: $Id: databaseif.ec,v 1.9 2003/12/27 23:11:43 rasdev Exp $";
+
+using namespace std;
+
+#include <iostream.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "error.hh"
+#include "adminif.hh"
+#include "databaseif.hh"
+#include "externs.h"
+
+#include "raslib/rmdebug.hh"
+#define DEBUG_MAIN
+#include "debug.hh"
+
+
+RMINITGLOBALS('C')
+
+
+// test environment:
+#include "testcenter.h"
+
+#define ELLIPSIS "..."
+/// test macro for checking error condition, printing result, and aborting on error
+#define CHECK(p) { cout << "CHECKING " << "p"; \
+ if (!(p)) \
+ { cout << TEST_ERROR << endl; \
+ return false; \
+ } \
+ else \
+ { \
+ cout << TEST_OK << endl; \
+ } \
+ }
+
+/// ObjectBroker: dummy class to satisfy linker; real ObjectBroker functionality never used here.
+class ObjectBroker
+{
+ public:
+ void init();
+ void deinit();
+ bool freeMemory();
+};
+
+void ObjectBroker::init()
+{
+}
+void ObjectBroker::deinit()
+{
+}
+bool ObjectBroker::freeMemory()
+{
+ return true;
+}
+
+/// from server/rasserver_main.cc:
+char globalConnectId[256];
+
+/// doTest(): run the test cases
+/// preconditions:
+/// database does NOT yet exist
+/// @params:
+/// dbname name of database
+/// @returns:
+/// true if all tests succeeded
+/// false if some test failed
+
+bool doTest( const char *dbname )
+{
+ bool result = false; // overall test result
+ DatabaseIf *db = NULL; // our test candidate
+
+ try // capture eny eventual exception for reporting
+ {
+ // --- (1) good scenario
+
+ cout << "DatabaseIf constructor" << ELLIPSIS << flush;
+ db = new DatabaseIf();
+ cout << "new state is: " << *db;
+ CHECK( db != NULL );
+
+ cout << "create" << ELLIPSIS << endl;
+ db->createDB( dbname, NULL, NULL );
+ CHECK( db->isConnected() );
+ CHECK( db->isOpen() );
+
+ cout << "db open" << ELLIPSIS << endl;
+ db->open( dbname );
+ CHECK( db->isConnected() );
+ CHECK( db->isOpen() );
+
+ cout << "db close" << ELLIPSIS << endl;
+ db->close();
+ CHECK( db->isConnected() );
+ CHECK( db->isOpen() );
+
+ cout << "db destroy" << ELLIPSIS << endl;
+ db->destroyDB( dbname );
+ CHECK( db->isConnected() );
+ CHECK( db->isOpen() );
+
+ result = true;
+ }
+ // FIXME: what else should be caught explicitly?
+ catch(r_Error& myErr)
+ {
+ cout << "caught r_Error exception #" << myErr.get_errorno() << ": " << myErr.what() << endl;
+ result = false;
+ }
+ catch(bad_alloc)
+ {
+ cout << "caught bad_alloc exception" << endl;
+ result = false;
+ }
+ catch(...)
+ {
+ cout << "caught unknown exception" << endl;
+ result = false;
+ }
+
+ return result;
+}
+
+int
+main(int argc, char *argv[])
+{
+ const char *progName = argv[0]; // name of this test program
+
+ int RManDebug2 = 5; // debug trace settings
+ int RManModule = 1; // dito
+
+ char* dbName = "RASBASE"; // default database name
+ int result = RC_ERROR; // overall test exit code
+ char *resultText = NULL; // overall test status string
+
+ // --- parameter evaluation, launch msg
+ if (argc == 2)
+ dbName = argv[1];
+ else if (argc > 2)
+ {
+ cout << "usage: " << progName << " [dbname]" << endl;
+ return( RC_USAGE );
+ }
+ cout << progName << ", generated on " << COMPDATE << " for rasdaman version " << RMANVERSION << " and base DBMS " << BASEDBSTRING << "; using database '" << dbName << "'" << endl;
+
+ // --- all is fine, let's do the test
+ bool allFine = doTest( dbName );
+
+ if (allFine)
+ {
+ resultText = TEST_OK;
+ result = RC_OK;
+ }
+ else
+ {
+ resultText = TEST_ERROR;
+ result = RC_ERROR;
+ }
+
+ // --- done, epilogue
+ cout << progName << ": overall test result is " << resultText << endl;
+
+ return( result );
+}
+
diff --git a/reladminif/test/testcenter.h b/reladminif/test/testcenter.h
new file mode 100644
index 0000000..c17d94f
--- /dev/null
+++ b/reladminif/test/testcenter.h
@@ -0,0 +1,47 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************************
+ *
+ *
+ * PURPOSE:
+ * provide global settings for running system tests.
+ *
+ *
+ * COMMENTS:
+ *
+ ***********************************************************************/
+
+#ifndef _TESTCENTER_H_
+
+/// program exit codes
+#define RC_OK 0
+#define RC_USAGE 2
+#define RC_ERROR -1
+
+/// protocol output, must be canonical for automatic & regression testing
+#define TEST_OK "OK"
+#define TEST_ERROR "ERROR"
+
+#define _TESTCENTER_H_
+#endif _TESTCENTER_H_
+
diff --git a/reladminif/test/testconnect.c b/reladminif/test/testconnect.c
new file mode 100644
index 0000000..70215b7
--- /dev/null
+++ b/reladminif/test/testconnect.c
@@ -0,0 +1,395 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include <sqlhdr.h>
+#include <sqliapi.h>
+#line 1 "testconnect.ec"
+/* testconnect.ec
+test connection to Informix database
+*/
+
+#include <iostream>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <minmax.h>
+
+/*
+ * EXEC SQL INCLUDE SQLCA;
+ */
+#line 11 "testconnect.ec"
+
+#line 11 "testconnect.ec"
+#line 1 "/opt/informix/incl/esql/sqlca.h"
+/****************************************************************************
+ *
+ * IBM INC.
+ *
+ * PROPRIETARY DATA
+ *
+ * Licensed Material - Property Of IBM
+ *
+ * "Restricted Materails of IBM"
+ *
+ * IBM Informix Client SDK
+ *
+ * (c) Copyright IBM Corporation 2002. All rights reserved.
+ *
+ *
+ * Title: sqlca.h
+ * Sccsid: @(#)sqlca.h 9.4 1/18/93 11:09:48
+ * Description:
+ * SQL Control Area
+ *
+ ***************************************************************************
+ */
+
+#ifndef SQLCA_INCL
+#define SQLCA_INCL
+
+#include "ifxtypes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct sqlca_s
+ {
+ int4 sqlcode;
+ char sqlerrm[72]; /* error message parameters */
+ char sqlerrp[8];
+ int4 sqlerrd[6];
+ /* 0 - estimated number of rows returned */
+ /* 1 - serial value after insert or ISAM error code */
+ /* 2 - number of rows processed */
+ /* 3 - estimated cost */
+ /* 4 - offset of the error into the SQL statement */
+ /* 5 - rowid after insert */
+#ifdef _FGL_
+ char sqlawarn[8];
+#else
+ struct sqlcaw_s
+ {
+ char sqlwarn0; /* = W if any of sqlwarn[1-7] = W */
+ char sqlwarn1; /* = W if any truncation occurred or
+ database has transactions or
+ no privileges revoked */
+ char sqlwarn2; /* = W if a null value returned or
+ ANSI database */
+ char sqlwarn3; /* = W if no. in select list != no. in into list or
+ turbo backend or no privileges granted */
+ char sqlwarn4; /* = W if no where clause on prepared update, delete or
+ incompatible float format */
+ char sqlwarn5; /* = W if non-ANSI statement */
+ char sqlwarn6; /* = W if server is in data replication secondary mode */
+ char sqlwarn7; /* = W if database locale is different from proc_locale
+ */
+ } sqlwarn;
+#endif
+ } ifx_sqlca_t;
+
+/* NOTE: 4gl assumes that the sqlwarn structure can be defined as
+ * sqlawarn -- an 8 character string, because single-char
+ * variables are not recognized in 4gl.
+ *
+ * If this structure should change, the code generated by 4gl compiler
+ * must also change
+ */
+
+#ifdef VMS
+noshare
+#endif /* VMS */
+
+#define SQLNOTFOUND 100
+
+#ifndef IFX_THREAD
+extern struct sqlca_s sqlca;
+
+extern int4 SQLCODE;
+
+extern char SQLSTATE[];
+#else /* IFX_THREAD */
+extern int4 * ifx_sqlcode();
+extern struct sqlca_s * ifx_sqlca();
+#define SQLCODE (*(ifx_sqlcode()))
+#define SQLSTATE ((char *)(ifx_sqlstate()))
+#define sqlca (*(ifx_sqlca()))
+#endif /* IFX_THREAD */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SQLCA_INCL */
+
+#line 101 "/opt/informix/incl/esql/sqlca.h"
+/*
+ * EXEC SQL define SUCCESS 0;
+ */
+#line 12 "testconnect.ec"
+
+/*
+ * EXEC SQL define WARNING 1;
+ */
+#line 13 "testconnect.ec"
+
+/*
+ * EXEC SQL define NODATA 100;
+ */
+#line 14 "testconnect.ec"
+
+/*
+ * EXEC SQL define RTERROR -1;
+ */
+#line 15 "testconnect.ec"
+
+#line 16 "testconnect.ec"
+
+/*
+ * The sqlstate_err() function checks the SQLSTATE status variable to see
+ * if an error or warning has occurred following an SQL statement.
+ */
+int4 sqlstate_err()
+{
+ int4 err_code = -1;
+
+ if(SQLSTATE[0] == '0') /* trap '00', '01', '02' */
+ {
+ switch(SQLSTATE[1])
+ {
+ case '0': /* success - return 0 */
+ err_code = 0;
+ break;
+ case '1': /* warning - return 1 */
+ err_code = 1;
+ break;
+ case '2': /* end of data - return 100 */
+ err_code = 100;
+ break;
+ default: /* error - return SQLCODE */
+ break;
+ }
+ }
+ return(err_code);
+}
+
+/*
+ * The disp_sqlstate_err() function executes the GET DIAGNOSTICS
+ * statement and prints the detail for each exception that is returned.
+ */
+void disp_sqlstate_err()
+{
+ mint j;
+
+/*
+ * EXEC SQL BEGIN DECLARE SECTION;
+ */
+#line 53 "testconnect.ec"
+#line 54 "testconnect.ec"
+#line 54 "testconnect.ec"
+mint exception_count;
+#line 55 "testconnect.ec"
+ char overflow[2];
+#line 56 "testconnect.ec"
+mint exception_num = 1;
+#line 57 "testconnect.ec"
+ char class_id[255];
+#line 58 "testconnect.ec"
+ char subclass_id[255];
+#line 59 "testconnect.ec"
+ char message[255];
+#line 60 "testconnect.ec"
+mint messlen;
+#line 61 "testconnect.ec"
+ char sqlstate_code[6];
+#line 62 "testconnect.ec"
+mint i;
+/*
+ * EXEC SQL END DECLARE SECTION;
+ */
+#line 63 "testconnect.ec"
+
+
+ printf("SQLSTATE: %s\n",SQLSTATE);
+ printf("SQLCODE: %d\n", SQLCODE);
+
+/*
+ * EXEC SQL get diagnostics :exception_count = NUMBER, :overflow = MORE;
+ */
+#line 68 "testconnect.ec"
+ {
+#line 68 "testconnect.ec"
+ static ifx_hostvar_t _SQhtab[] =
+ {
+ { 0, 1, 102, sizeof(exception_count), 0, 0, 0, 0 },
+ { 0, 2, 100, 2, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0 }
+#line 68 "testconnect.ec"
+ };
+ _SQhtab[0].hostaddr = (char *)&exception_count;
+ _SQhtab[1].hostaddr = (overflow);
+#line 68 "testconnect.ec"
+ sqli_diag_get(ESQLINTVERSION, _SQhtab, -1);
+#line 68 "testconnect.ec"
+ }
+
+ printf("EXCEPTIONS: Number=%d\t", exception_count);
+ printf("More? %s\n", overflow);
+
+ for (i = 1; i <= exception_count; i++)
+ {
+/*
+ * EXEC SQL get diagnostics exception :i
+ * :sqlstate_code = RETURNED_SQLSTATE,
+ * :class_id = CLASS_ORIGIN, :subclass_id = SUBCLASS_ORIGIN,
+ * :message = MESSAGE_TEXT, :messlen = MESSAGE_LENGTH;
+ */
+#line 75 "testconnect.ec"
+ {
+#line 78 "testconnect.ec"
+ static ifx_hostvar_t _SQhtab[] =
+ {
+ { 0, 3, 100, 6, 0, 0, 0, 0 },
+ { 0, 4, 100, 255, 0, 0, 0, 0 },
+ { 0, 5, 100, 255, 0, 0, 0, 0 },
+ { 0, 6, 100, 255, 0, 0, 0, 0 },
+ { 0, 7, 102, sizeof(messlen), 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0 }
+#line 78 "testconnect.ec"
+ };
+ _SQhtab[0].hostaddr = (sqlstate_code);
+ _SQhtab[1].hostaddr = (class_id);
+ _SQhtab[2].hostaddr = (subclass_id);
+ _SQhtab[3].hostaddr = (message);
+ _SQhtab[4].hostaddr = (char *)&messlen;
+#line 78 "testconnect.ec"
+ sqli_diag_get(ESQLINTVERSION, _SQhtab, i);
+#line 78 "testconnect.ec"
+ }
+
+ printf("EXCEPTION %d: SQLSTATE=%s\n", i, sqlstate_code);
+ message[messlen-1] = '\0';
+ printf("MESSAGE TEXT: %s\n", message);
+ j = byleng(class_id, stleng(class_id));
+ class_id[j] = '\0';
+ printf("CLASS ORIGIN: %s\n",class_id);
+ j = byleng(subclass_id, stleng(subclass_id));
+ subclass_id[j] = '\0';
+ printf("SUBCLASS ORIGIN: %s\n",subclass_id);
+ }
+}
+
+void disp_error(char* stmt)
+{
+}
+
+void disp_exception(char* stmt, int4 sqlerr_code, mint warn_flg)
+{
+ switch (sqlerr_code)
+ {
+ case 0:
+ case 100:
+ break;
+ case 1:
+ if(warn_flg)
+ {
+ printf("Warning encountered in %s\n", stmt);
+ disp_sqlstate_err();
+ }
+ break;
+ case -1:
+ printf("Error encountered in %s\n", stmt);
+ disp_sqlstate_err();
+ break;
+ default:
+ printf("INVALID EXCEPTION STATE for %s\n", stmt);
+ break;
+ }
+}
+
+int
+check()
+{
+ mint warn_flg = 1;
+ int4 sqlerr_code = 0;
+
+ sqlerr_code = sqlstate_err();
+ disp_exception((char*)"error", sqlerr_code, warn_flg);
+
+ return SQLCODE;
+}
+
+
+int
+main(int argc, char** argv)
+{
+ cout << argv[0] << " Informix database access test" << endl;
+ if (argc != 2)
+ {
+ cout << "Usage: " << argv[0] << " connectstring" << endl;
+ return 2;
+ }
+
+/*
+ * EXEC SQL BEGIN DECLARE SECTION;
+ */
+#line 143 "testconnect.ec"
+#line 144 "testconnect.ec"
+#line 144 "testconnect.ec"
+ char id[256];
+/*
+ * EXEC SQL END DECLARE SECTION;
+ */
+#line 145 "testconnect.ec"
+
+
+ strcpy( id, argv[1] );
+ cout << "using connect string: " << id << endl;
+
+/*
+ * EXEC SQL CONNECT TO :id;
+ */
+#line 150 "testconnect.ec"
+ {
+#line 150 "testconnect.ec"
+ sqli_connect_open(ESQLINTVERSION, 0, id, (char *) 0, (ifx_conn_t *) 0, 0);
+#line 150 "testconnect.ec"
+ }
+ check();
+
+/*
+ * EXEC SQL DISCONNECT CURRENT;
+ */
+#line 153 "testconnect.ec"
+ {
+#line 153 "testconnect.ec"
+ sqli_connect_close(3, (char *) 0, 0, 0);
+#line 153 "testconnect.ec"
+ }
+ check();
+
+ cout << argv[0] << ": done." << endl;
+ return 0;
+}
+
+
+#line 159 "testconnect.ec"
diff --git a/reladminif/test/testta.pgc b/reladminif/test/testta.pgc
new file mode 100644
index 0000000..38a994c
--- /dev/null
+++ b/reladminif/test/testta.pgc
@@ -0,0 +1,281 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************************
+ *
+ *
+ * PURPOSE:
+ * test class TransactionIF.
+ *
+ *
+ * COMMENTS:
+ * none
+ *
+ * PRECONDITIONS:
+ * - database exists and is accessible (PG & rasdaman server running)
+ * - reladminif/DatabaseIF works
+ *
+ ***********************************************************************/
+
+static const char rcsid[] = "@(#)reladminif,TransactionIf: $Id: testta.pgc,v 1.6 2003/12/27 23:11:43 rasdev Exp $";
+
+#define DEBUG_MAIN
+#include "debug.hh"
+
+// constants:
+#define DATABASE "RASBASE"
+
+// pointers representing O2, database, ta and session
+AdminIf* admin = NULL;
+DatabaseIf* db = NULL;
+TransactionIf* ta = NULL;
+
+int main()
+{
+ const char *prog = argv[0]; // this program's name
+
+ cout << prog << ": test for transactionif, generated on " << COMPDATE << endl;
+
+ // --- outmost exception catcher ------------------------
+ try
+ {
+
+ // --- (1) preparation: open connection
+ admin = AdminIf::instance();
+ if( !admin )
+ {
+ cout << prog << ": cannot create adminIf instance" << endl;
+ throw r_Error();
+ }
+ // connect to the database
+ db = new DatabaseIf();
+ if( !admin )
+ {
+ cout << prog << ": cannot create DatabaseIf instance" << endl;
+ throw r_Error();
+ }
+ db->open( DATABASE );
+
+ ta = new TransactionIf();
+ if( !admin )
+ {
+ cout << prog << ": cannot create TransactionIf instance" << endl;
+ throw r_Error();
+ }
+ ta->begin( db );
+ ta->abort( db );
+ ta->commit( db );
+
+ db->close();
+ }
+ catch(...)
+ {
+ cout << prog << ": error abort." << endl;
+ }
+
+ cout << prog << ": test for transactionif done." << endl;
+}
+
+
+void
+TransactionIf::begin( bool readOnly ) throw ( r_Error )
+{
+ RMDBGENTER(2, RMDebug::module_adminif, "TransactionIf", "begin(" << readOnly << ")");
+ ENTER( "TransactionIf::begin, readOnly=" << readOnly );
+
+ isReadOnly = readOnly;
+ AdminIf::setAborted(false);
+ AdminIf::setReadOnlyTA(readOnly);
+
+ TALK( "EXEC SQL BEGIN WORK" );
+ EXEC SQL BEGIN WORK;
+ if (sqlca.sqlwarn[2] == 'W') // real error, not just a warning
+ {
+ SQLCODE = 0; // FIXME: bad hack, as PG can't reset error state and SQLCODE is queried in many places -- PB 2005-jan-09
+ }
+ else
+ {
+ RMDBGMIDDLE(4, RMDebug::module_adminif, "TransactionIf", "error occured while issuing BEGIN");
+ LEAVE( "TransactionIf::begin(): error during BEGIN: " << SQLCODE );
+ generateException();
+ }
+
+ if (readOnly)
+ {
+ TALK( "EXEC SQL SET TRANSACTION READ ONLY" );
+ EXEC SQL SET TRANSACTION READ ONLY;
+ // no error check, as this doesn't inhibit work
+ }
+
+ // prelim.:have additional libpq TA -- PB 2005-jan-09
+ TALK( "PQexec( pgConn, BEGIN )" );
+ PGresult *pgResult = PQexec( pgConn, "BEGIN" );
+ if (PQresultStatus(pgResult) != PGRES_COMMAND_OK)
+ {
+ LEAVE( "TransactionIf::begin() Error: cannot open libpq TA: " << PQerrorMessage(pgConn) );
+ generateException();
+ }
+
+#ifdef RMANBENCHMARK
+ DBObject::readTimer.start();
+ DBObject::readTimer.pause();
+
+ DBObject::updateTimer.start();
+ DBObject::updateTimer.pause();
+
+ DBObject::deleteTimer.start();
+ DBObject::deleteTimer.pause();
+
+ DBObject::insertTimer.start();
+ DBObject::insertTimer.pause();
+
+ OId::oidAlloc.start();
+ OId::oidAlloc.pause();
+
+ OId::oidResolve.start();
+ OId::oidResolve.pause();
+#endif
+
+ OId::initialize();
+ TypeFactory::initialize();
+
+ LEAVE( "TransactionIf::begin, SQLCODE=" << SQLCODE );
+ RMDBGEXIT(2, RMDebug::module_adminif, "TransactionIf", "begin(" << readOnly << ") ");
+}
+
+void
+TransactionIf::commit() throw ( r_Error )
+{
+ RMDBGENTER(2, RMDebug::module_adminif, "TransactionIf", "commit()");
+ ENTER( "TransactionIf::commit" );
+
+ if (isReadOnly)
+ {
+ RMDBGMIDDLE(9, RMDebug::module_adminif, "TransactionIf", "read only: aborting");
+ TALK( "TA is readonly: aborting" );
+ abort();
+ }
+ else
+ {
+ AdminIf::setAborted(false);
+ RMDBGMIDDLE(9, RMDebug::module_adminif, "TransactionIf", "set aborted false");
+ TypeFactory::freeTempTypes();
+ RMDBGMIDDLE(9, RMDebug::module_adminif, "TransactionIf", "freed temp types");
+ ObjectBroker::clearBroker();
+ RMDBGMIDDLE(9, RMDebug::module_adminif, "TransactionIf", "cleared broker");
+ OId::deinitialize();
+ RMDBGMIDDLE(9, RMDebug::module_adminif, "TransactionIf", "wrote oid counters");
+ AdminIf::setReadOnlyTA(false);
+ RMDBGMIDDLE(9, RMDebug::module_adminif, "TransactionIf", "committing");
+
+ TALK( "EXEC SQL COMMIT WORK" );
+ EXEC SQL COMMIT WORK;
+ if (check("TransactionIf::begin() COMMIT\0"))
+ {
+ RMDBGMIDDLE(4, RMDebug::module_adminif, "TransactionIf", "error occured while issuing COMMIT");
+ LEAVE( "TransactionIf::commit(): error during COMMIT:" << SQLCODE );
+ generateException();
+ }
+
+ // prelim.:have additional libpq TA -- PB 2005-jan-09
+ TALK( "PQexec( pgConn, END )" );
+ PGresult *pgResult = PQexec( pgConn, "END" );
+ if (PQresultStatus(pgResult) != PGRES_COMMAND_OK)
+ {
+ LEAVE( "TransactionIf::commit() Error: cannot commit libpq TA: " << PQerrorMessage(pgConn) );
+ generateException();
+ }
+
+ if (lastBase)
+ {
+ RMDBGMIDDLE(9, RMDebug::module_adminif, "TransactionIf", "closing dbms");
+ lastBase->baseDBMSClose();
+ }
+ }
+
+#ifdef RMANBENCHMARK
+ DBObject::readTimer.stop();
+
+ DBObject::updateTimer.stop();
+
+ DBObject::deleteTimer.stop();
+
+ DBObject::insertTimer.stop();
+
+ OId::oidAlloc.stop();
+
+ OId::oidResolve.stop();
+#endif
+
+ LEAVE( "TransactionIf::commit" );
+ RMDBGEXIT(2, RMDebug::module_adminif, "TransactionIf", "commit() " << endl << endl);
+}
+
+void
+TransactionIf::abort()
+{
+ RMDBGENTER(2, RMDebug::module_adminif, "TransactionIf", "abort()");
+ ENTER( "TransactionIf::abort" );
+
+ // prelim.:have additional libpq TA -- PB 2005-jan-09
+ TALK( "PQexec( pgConn, ABORT )" );
+ PGresult *pgResult = PQexec( pgConn, "ABORT" );
+ if (PQresultStatus(pgResult) != PGRES_COMMAND_OK)
+ {
+ LEAVE( "TransactionIf::abort() Error: cannot abort libpq TA: " << PQerrorMessage(pgConn) );
+ generateException();
+ }
+
+ AdminIf::setAborted(true);
+ TypeFactory::freeTempTypes();
+ ObjectBroker::clearBroker();
+ OId::deinitialize();
+ AdminIf::setReadOnlyTA(false);
+
+ TALK( "EXEC SQL ROLLBACK WORK" );
+ EXEC SQL ROLLBACK WORK;
+ if (check("TransactionIf::abort() ROLLBACK\0"))
+ {
+ RMDBGMIDDLE(4, RMDebug::module_adminif, "TransactionIf", "error occured while issuing ROLLBACK");
+ TALK( "TransactionIf::abort(): error during ROLLBACK, still continuing: " << SQLCODE );
+ }
+ if(lastBase)
+ lastBase->baseDBMSClose();
+
+#ifdef RMANBENCHMARK
+ DBObject::readTimer.stop();
+
+ DBObject::updateTimer.stop();
+
+ DBObject::deleteTimer.stop();
+
+ DBObject::insertTimer.stop();
+
+ OId::oidAlloc.stop();
+
+ OId::oidResolve.stop();
+#endif
+
+ LEAVE( "TransactionIf::abort, SQLCODE=" << SQLCODE );
+ RMDBGEXIT(2, RMDebug::module_adminif, "TransactionIf", "abort() " << endl << endl);
+}
+
diff --git a/reladminif/transactionif.hh b/reladminif/transactionif.hh
new file mode 100644
index 0000000..757325d
--- /dev/null
+++ b/reladminif/transactionif.hh
@@ -0,0 +1,107 @@
+#ifndef _TRANSACTIONIF_HH_
+#define _TRANSACTIONIF_HH_
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/************************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ***********************************************************************/
+
+//@ManMemo: Module: {\bf transactionif}.
+
+/*@Doc:
+TransactionIf has the functionality to begin, commit and abort a base
+DBMS transaction.
+*/
+
+class TransactionIf;
+class DatabaseIf;
+
+#include <iostream>
+
+#include "raslib/error.hh"
+
+class TransactionIf
+ {
+ public:
+ void begin(DatabaseIf* currBase, bool readOnly = false) throw ( r_Error );
+ /*@Doc:
+ begin a TA.
+ By default, the TA started is a write TA. If {\tt readOnly} is set to 1,
+ the TA will be read only.
+ */
+
+ void commit() throw ( r_Error );
+ /*@Doc:
+ commit a transaction. make all changes permanent.
+ r_Error is thrown when any objects have problems
+ writting themselves to the database.
+ AdminIf::compCompTiles(), TypeFactory::freeTempTypes,
+ ObjectBroker::clearBroker, OId::deinitialize are called.
+ COMMIT is issued. the database is closed.
+ the benchmark timers are stopped.
+ */
+
+ void abort();
+ /*@Doc:
+ abort a TA. don't make changes permanent.
+ AdminIf::compCompTiles(), TypeFactory::freeTempTypes,
+ ObjectBroker::clearBroker, OId::deinitialize are called.
+ ROLLBACK is issued. the database is closed.
+ the benchmark timers are stopped.
+ */
+
+ DatabaseIf* getDatabaseIf();
+ /*@Doc:
+ returns the DatabaseIf object associated with this transaction.
+ */
+
+ private:
+ void begin( bool readOnly = false ) throw ( r_Error );
+ /*@Doc:
+ begin a TA. Internal usage only.
+ This function does not work if the appropriate initializations have'nt
+ been done. For that reason, it is only appropriate for internal usage.
+ By default, the TA started is a write TA. If {\tt readOnly} is set to 1,
+ the TA will be read only.
+ benchmark timers are started.
+ */
+
+ bool isReadOnly;
+ /*@Doc:
+ keeps track if the current TA is read only or not
+ */
+
+ static DatabaseIf* lastBase;
+ /*@Doc:
+ stores the last base used in begin();
+ */
+ };
+
+#endif
diff --git a/reladminif/transactionif.pgc b/reladminif/transactionif.pgc
new file mode 100644
index 0000000..6bd16f7
--- /dev/null
+++ b/reladminif/transactionif.pgc
@@ -0,0 +1,242 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************************
+ *
+ *
+ * PURPOSE:
+ * Code with embedded SQL for relational DBMS
+ *
+ *
+ * COMMENTS:
+ * - reconsider this 604 ignorance!
+ *
+ ***********************************************************************/
+
+static const char rcsid[] = "@(#)reladminif,TransactionIf: $Id: transactionif.ec,v 1.6 2003/12/27 23:11:43 rasdev Exp $";
+
+#include "debug.hh"
+
+// general embedded SQL related definitions
+EXEC SQL include sqlglobals.h;
+
+#include "transactionif.hh"
+#include "raslib/rmdebug.hh"
+#include "adminif.hh"
+#include "oidif.hh"
+#include "catalogmgr/typefactory.hh"
+#include "sqlerror.hh"
+#include "objectbroker.hh"
+#include "databaseif.hh"
+
+// PG stuff for libpg connection maintenance
+#include "libpq-fe.h"
+extern PGconn *pgConn;
+
+
+void
+TransactionIf::begin( bool readOnly ) throw ( r_Error )
+{
+ RMDBGENTER(2, RMDebug::module_adminif, "TransactionIf", "begin(" << readOnly << ")");
+ ENTER( "TransactionIf::begin, readOnly=" << readOnly );
+
+ isReadOnly = readOnly;
+ AdminIf::setAborted(false);
+ AdminIf::setReadOnlyTA(readOnly);
+
+ TALK( "EXEC SQL BEGIN WORK" );
+ EXEC SQL BEGIN WORK;
+ if (sqlca.sqlwarn[2] == 'W') // real error, not just a warning
+ {
+ SQLCODE = 0; // FIXME: bad hack, as PG can't reset error state and SQLCODE is queried in many places -- PB 2005-jan-09
+ }
+ else
+ {
+ RMDBGMIDDLE(4, RMDebug::module_adminif, "TransactionIf", "error occured while issuing BEGIN");
+ LEAVE( "TransactionIf::begin(): error during BEGIN: " << SQLCODE );
+ generateException();
+ }
+
+ if (readOnly)
+ {
+ TALK( "EXEC SQL SET TRANSACTION READ ONLY" );
+ EXEC SQL SET TRANSACTION READ ONLY;
+ // no error check, as this doesn't inhibit work
+ }
+
+ // prelim.:have additional libpq TA -- PB 2005-jan-09
+ TALK( "PQexec( pgConn, BEGIN )" );
+ PGresult *pgResult = PQexec( pgConn, "BEGIN" );
+ if (PQresultStatus(pgResult) != PGRES_COMMAND_OK)
+ {
+ LEAVE( "TransactionIf::begin() Error: cannot open libpq TA: " << PQerrorMessage(pgConn) );
+ generateException();
+ }
+
+#ifdef RMANBENCHMARK
+ DBObject::readTimer.start();
+ DBObject::readTimer.pause();
+
+ DBObject::updateTimer.start();
+ DBObject::updateTimer.pause();
+
+ DBObject::deleteTimer.start();
+ DBObject::deleteTimer.pause();
+
+ DBObject::insertTimer.start();
+ DBObject::insertTimer.pause();
+
+ OId::oidAlloc.start();
+ OId::oidAlloc.pause();
+
+ OId::oidResolve.start();
+ OId::oidResolve.pause();
+#endif
+
+ OId::initialize();
+ TypeFactory::initialize();
+
+ LEAVE( "TransactionIf::begin, SQLCODE=" << SQLCODE );
+ RMDBGEXIT(2, RMDebug::module_adminif, "TransactionIf", "begin(" << readOnly << ") ");
+}
+
+void
+TransactionIf::commit() throw ( r_Error )
+{
+ RMDBGENTER(2, RMDebug::module_adminif, "TransactionIf", "commit()");
+ ENTER( "TransactionIf::commit" );
+
+ if (isReadOnly)
+ {
+ RMDBGMIDDLE(9, RMDebug::module_adminif, "TransactionIf", "read only: aborting");
+ TALK( "TA is readonly: aborting" );
+ abort();
+ }
+ else
+ {
+ AdminIf::setAborted(false);
+ RMDBGMIDDLE(9, RMDebug::module_adminif, "TransactionIf", "set aborted false");
+ TypeFactory::freeTempTypes();
+ RMDBGMIDDLE(9, RMDebug::module_adminif, "TransactionIf", "freed temp types");
+ ObjectBroker::clearBroker();
+ RMDBGMIDDLE(9, RMDebug::module_adminif, "TransactionIf", "cleared broker");
+ OId::deinitialize();
+ RMDBGMIDDLE(9, RMDebug::module_adminif, "TransactionIf", "wrote oid counters");
+ AdminIf::setReadOnlyTA(false);
+ RMDBGMIDDLE(9, RMDebug::module_adminif, "TransactionIf", "committing");
+
+ // prelim.:have additional libpq TA -- PB 2005-jan-09
+ TALK( "PQexec( pgConn, END )" );
+ PGresult *pgResult = PQexec( pgConn, "END" );
+ if (PQresultStatus(pgResult) != PGRES_COMMAND_OK)
+ {
+ LEAVE( "TransactionIf::commit() Error: cannot commit libpq TA: " << PQerrorMessage(pgConn) );
+ generateException();
+ }
+
+ TALK( "EXEC SQL COMMIT WORK" );
+ EXEC SQL COMMIT WORK;
+ if (SQLCODE == -604) // = "no TA open" - seems to be a hickup from our double transaction
+ // so we ignore it; FIXME: reinvestigate! -- PB 25-aug-2005
+ {
+ TALK( "TransactionIf::commit(): ignoring 'no TA open' error (SQLCODE -604) during COMMIT." );
+ }
+ else if (check("TransactionIf::begin() COMMIT\0"))
+ {
+ RMDBGMIDDLE(4, RMDebug::module_adminif, "TransactionIf", "error occured while issuing COMMIT");
+ LEAVE( "TransactionIf::commit(): error during COMMIT:" << SQLCODE );
+ generateException();
+ }
+ if (lastBase)
+ {
+ RMDBGMIDDLE(9, RMDebug::module_adminif, "TransactionIf", "closing dbms");
+ lastBase->baseDBMSClose();
+ }
+ }
+
+#ifdef RMANBENCHMARK
+ DBObject::readTimer.stop();
+
+ DBObject::updateTimer.stop();
+
+ DBObject::deleteTimer.stop();
+
+ DBObject::insertTimer.stop();
+
+ OId::oidAlloc.stop();
+
+ OId::oidResolve.stop();
+#endif
+
+ LEAVE( "TransactionIf::commit" );
+ RMDBGEXIT(2, RMDebug::module_adminif, "TransactionIf", "commit() " << endl << endl);
+}
+
+void
+TransactionIf::abort()
+{
+ RMDBGENTER(2, RMDebug::module_adminif, "TransactionIf", "abort()");
+ ENTER( "TransactionIf::abort" );
+
+ // prelim.:have additional libpq TA -- PB 2005-jan-09
+ TALK( "PQexec( pgConn, ABORT )" );
+ PGresult *pgResult = PQexec( pgConn, "ABORT" );
+ if (PQresultStatus(pgResult) != PGRES_COMMAND_OK)
+ {
+ LEAVE( "TransactionIf::abort() Error: cannot abort libpq TA: " << PQerrorMessage(pgConn) );
+ generateException();
+ }
+
+ AdminIf::setAborted(true);
+ TypeFactory::freeTempTypes();
+ ObjectBroker::clearBroker();
+ OId::deinitialize();
+ AdminIf::setReadOnlyTA(false);
+
+ TALK( "EXEC SQL ROLLBACK WORK" );
+ EXEC SQL ROLLBACK WORK;
+ if (check("TransactionIf::abort() ROLLBACK\0"))
+ {
+ RMDBGMIDDLE(4, RMDebug::module_adminif, "TransactionIf", "error occured while issuing ROLLBACK");
+ TALK( "TransactionIf::abort(): error during ROLLBACK, still continuing: " << SQLCODE );
+ }
+ if(lastBase)
+ lastBase->baseDBMSClose();
+
+#ifdef RMANBENCHMARK
+ DBObject::readTimer.stop();
+
+ DBObject::updateTimer.stop();
+
+ DBObject::deleteTimer.stop();
+
+ DBObject::insertTimer.stop();
+
+ OId::oidAlloc.stop();
+
+ OId::oidResolve.stop();
+#endif
+
+ LEAVE( "TransactionIf::abort, SQLCODE=" << SQLCODE );
+ RMDBGEXIT(2, RMDebug::module_adminif, "TransactionIf", "abort() " << endl << endl);
+}
+
diff --git a/reladminif/transactionifcommon.cc b/reladminif/transactionifcommon.cc
new file mode 100644
index 0000000..730b5b7
--- /dev/null
+++ b/reladminif/transactionifcommon.cc
@@ -0,0 +1,69 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************************
+ *
+ *
+ * PURPOSE:
+ * Code common to all DBMS interface implementations
+ */
+
+#include <iostream>
+
+#include "transactionif.hh"
+#include "adminif.hh"
+#include "catalogmgr/typefactory.hh"
+#include "oidif.hh"
+#include "raslib/rmdebug.hh"
+#include "databaseif.hh"
+#include "externs.h"
+#include "objectbroker.hh"
+#include "raslib/error.hh"
+#include "dbobject.hh"
+#include "sqlerror.hh"
+
+DatabaseIf* TransactionIf::lastBase = NULL;
+
+DatabaseIf*
+TransactionIf::getDatabaseIf()
+ {
+ RMDBGONCE(2, RMDebug::module_adminif, "TransactionIf", "getDatabaseIf() " << lastBase << endl);
+ return lastBase;
+ }
+
+void
+TransactionIf::begin( DatabaseIf* currBase, bool readOnly ) throw ( r_Error )
+ {
+ RMDBGENTER(4, RMDebug::module_adminif, "TransactionIf", "begin(" << currBase->getName() << ", " << readOnly << ")");
+ try {
+ currBase->baseDBMSOpen();
+ }
+ catch(r_Error& err) {
+ currBase->baseDBMSClose();
+ throw err;
+ }
+ lastBase = currBase;
+ begin(readOnly);
+ RMDBGEXIT(4, RMDebug::module_adminif, "TransactionIf", "begin(" << currBase->getName() << ", " << readOnly << ") ");
+ }
+
+
diff --git a/relblobif/Makefile.am b/relblobif/Makefile.am
new file mode 100644
index 0000000..36b7bf8
--- /dev/null
+++ b/relblobif/Makefile.am
@@ -0,0 +1,52 @@
+# -*-Makefile-*- (for Emacs)
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+#
+# MAKEFILE FOR:
+# relblobif
+#
+# COMMENTS:
+# uses Oracle precompiler
+#
+##################################################################
+
+AM_CXXFLAGS=@BASEDBCXXFLAGS@
+AM_LDFLAGS=@BASEDBLDFLAGS@
+
+.SUFFIXES= .@EMBEDDEDSQLEXT@ .@EMBEDDEDSQLOUT@
+.@EMBEDDEDSQLEXT@.@EMBEDDEDSQLOUT@:
+ $(EMBEDDEDSQLPRECOMPILER) $@ $<
+
+
+noinst_LIBRARIES=librelblobif.a
+librelblobif_a_SOURCES= blobtile.hh \
+ dbtile.cc dbtile.hh inlinetile.cc inlinetile.hh \
+ blobtilecommon.cc tileid.hh
+EXTRA_librelblobif_a_SOURCES=blobtile.pgc
+librelblobif_a_LIBADD=blobtile.$(OBJEXT)
+librelblobif_a_DEPENDENCIES=blobtile.$(OBJEXT)
+
+BUILT_SOURCES=blobtile.@EMBEDDEDSQLOUT@
+
+CLEANFILES=blobtile.@EMBEDDEDSQLOUT@ client.bm client.dbg client.log ir.out \
+ blobtile.$(OBJEXT)
+
diff --git a/relblobif/blobtile.file.pgc b/relblobif/blobtile.file.pgc
new file mode 100644
index 0000000..0547fdf
--- /dev/null
+++ b/relblobif/blobtile.file.pgc
@@ -0,0 +1,402 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include "mymalloc/mymalloc.h"
+// This is -*- C++ -*-
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * implements blobtile interface using the PostgreSQL DBMS.
+ *
+ *
+ * COMMENTS:
+ * - uses LO blob method, this has been tested to be faster than bytea
+ * - RMDBG macros generate so weird output that I added DEBUG macros
+ * although this is very ugly (2 trace facilities in parallel)
+ * - exceptions thrown are r_Error, either directly or through common
+ * function generateException() (reladminif) which throws r_Ebase_dbms
+ *
+ ************************************************************/
+
+using namespace std;
+
+static const char rcsid[] = "@(#)blobif,BLOBTile: $Id: blobtile.ec,v 1.8 2003/12/27 23:19:03 rasdev Exp $";
+
+#include <stdio.h>
+#include <stdlib.h> /* atoi */
+
+// PG stuff:
+#include "libpq-fe.h" /* C interface to PgSQL */
+#include "libpq/libpq-fs.h" /* large object (lo) api */
+
+// simple trace facility
+// trace macros are activated through externally defined compile variable DEBUG
+#include "debug-srv.hh"
+
+// general embedded SQL related definitions
+EXEC SQL include "../reladminif/sqlglobals.h";
+
+// libpg connection maintenance
+// must have been initiated before use (see databasif.pgc)
+extern PGconn *pgConn;
+
+// all the DBMS independent code is factored out and
+// will be included in the resulting .c file
+#include "blobtile.hh"
+#include "simplefilestorage.hh"
+#include "raslib/error.hh"
+#include "externs.h"
+#include "raslib/rmdebug.hh"
+#include "sqlerror.hh"
+#include "tileid.hh"
+#include "inlinetile.hh"
+#include "objectbroker.hh"
+#include "dbref.hh"
+
+
+IFileStorage* initFileStorage() {
+ SimpleFileStorage *fileStorage;
+ char *path = getenv("RASDATA");
+ if (path == NULL)
+ path="/tmp";
+ fileStorage = new SimpleFileStorage(path);
+ return fileStorage;
+}
+
+// update blob in ras_tiles table, identified by variable myOId (from blobtile.cc), update map ref
+void
+BLOBTile::updateInDb() throw (r_Error)
+{
+ RMDBGENTER(3, RMDebug::module_blobif, "BLOBTile", "updateInDb() " << myOId);
+ ENTER( "BLOBTile::updateInDb" );
+ if (fileStorage == NULL)
+ fileStorage = initFileStorage();
+
+ Oid tile;
+ long indbmyoId = 0;
+ long indbmyoid = 0;
+ short dataformat = 0;
+ char pgQuery[SQL_QUERY_BUFFER_SIZE];
+ PGresult *pgResult = NULL;
+
+ // (1) --- get tuple
+ dataformat = dataFormat;
+ indbmyoid = myOId.getCounter();
+
+ fileStorage->update(cells, size, indbmyoid);
+
+ // alternative solution for now:
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "UPDATE RAS_TILES SET DataFormat = %d WHERE BlobId = %d", dataformat, indbmyoid );
+ TALK( pgQuery );
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_COMMAND_OK)
+ {
+ LEAVE( "BLOBTile::updateInDb() libpq 'update dataformat' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+
+ // (4) --- update map ref
+ DBObject::updateInDb();
+
+ LEAVE( "BLOBTile::updateInDb, myOId=" << myOId );
+ RMDBGEXIT(3, RMDebug::module_blobif, "BLOBTile", "updateInDb() " << myOId);
+} // updateInDb()
+
+// insert new blob into ras_tiles table, update map ref
+// tuple is identified by blobtile.cc var myOId
+// data is taken from buffer 'cells' containing 'size' bytes
+void
+BLOBTile::insertInDb() throw (r_Error)
+{
+ RMDBGENTER(3, RMDebug::module_blobif, "BLOBTile", "insertInDb() " << myOId);
+ ENTER( "BLOBTile::insertInDb" );
+
+ if (fileStorage == NULL)
+ fileStorage = initFileStorage();
+
+ Oid blobOid;
+ long indbmyOId2;
+ short dataformat2;
+ Oid tile2;
+ dataformat2 = dataFormat;
+
+ // prelim:
+ char pgQuery[SQL_QUERY_BUFFER_SIZE];
+ PGresult *pgResult = NULL;
+
+ indbmyOId2 = myOId.getCounter();
+ TALK( "myOId.getCounter = " << indbmyOId2 );
+
+ fileStorage->insert(cells, size, indbmyOId2);
+
+ // (2) --- insert tuple into db
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "INSERT INTO RAS_TILES ( BlobId, DataFormat, Tile) VALUES ( %d, %d, %d )", indbmyOId2, dataformat2, indbmyOId2 );
+ TALK( pgQuery );
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_COMMAND_OK)
+ {
+ LEAVE( "BLOBTile::insertInDb() libpq 'insert' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+ PQclear( pgResult );
+
+ // FIXME: other sources have here an updateInDb();
+
+ // (3) --- update map ref
+ DBObject::insertInDb();
+
+ LEAVE( "BLOBTile::insertInDb(), myOId=" << myOId );
+ RMDBGEXIT(3, RMDebug::module_blobif, "BLOBTile", "insertInDb() " << myOId);
+} // insertInDb()
+
+// delete one tuple from ras_tiles table, update map ref
+// tuple is identified by blobtile.cc var myOId
+void
+BLOBTile::deleteFromDb() throw (r_Error)
+{
+ RMDBGENTER(3, RMDebug::module_blobif, "BLOBTile", "deleteFromDb() " << myOId);
+ ENTER( "BLOBTile::deleteFromDb" );
+ if (fileStorage == NULL)
+ fileStorage = initFileStorage();
+
+ long blobId; // blob tuple primary key
+ Oid blobOid; // blob oid "ptr"
+
+ // get counter value (primary key) from oid
+ blobId = myOId.getCounter();
+
+ fileStorage->remove(blobId);
+ PGresult *pgResult = NULL;
+ char pgQuery[SQL_QUERY_BUFFER_SIZE];
+
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "DELETE FROM RAS_TILES WHERE BlobId = ", blobOid );
+ TALK( pgQuery );
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_COMMAND_OK)
+ {
+ LEAVE( "BLOBTile::deleteFromDb() libpq 'delete tuple' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+ PQclear( pgResult );
+
+ // FIXME: other sources have here an updateInDb();
+
+ // update map ref
+ DBObject::deleteFromDb();
+
+ LEAVE( "BLOBTile::deleteFromDb, myOId=" << myOId );
+ RMDBGEXIT(3, RMDebug::module_blobif, "BLOBTile", "deleteFromDb() " << myOId);
+}
+
+// delete a range of tuple(s) from ras_tiles table, update map ref
+// tuples are identified by target and a range
+void
+BLOBTile::kill(const OId& target, unsigned int range)
+{
+ RMDBGENTER(0, RMDebug::module_blobif, "BLOBTile", "kill(" << target << ", " << range <<")");
+ ENTER( "BLOBTile::kill, target=" << target << ", range=" << range );
+
+ long indbmyOId5;
+ long indbmyOId6;
+ long blobId; // blob tuple primary key
+ Oid blobOid; // blob oid "ptr"
+ char pgQuery[SQL_QUERY_BUFFER_SIZE];
+ PGresult *pgResult = NULL; // query result
+
+ DBObject* targetobj = NULL;
+ IFileStorage *fileStorage = initFileStorage();
+
+ if (range == 0) // single tuple
+ {
+ // (1) --- delete form cache
+ targetobj = ObjectBroker::isInMemory(target);
+ if (targetobj)
+ {
+ targetobj->setPersistent(false);
+ }
+
+ // (2) --- free blob
+ indbmyOId5 = target.getCounter();
+ fileStorage->remove(indbmyOId5);
+
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "DELETE FROM RAS_TILES WHERE BlobId = %d", indbmyOId5 );
+ TALK( pgQuery );
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_COMMAND_OK)
+ {
+ LEAVE( "BLOBTile::kill() libpq 'delete single' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+ else if (PQntuples(pgResult) == 0)
+ {
+ if (target.getType() == OId::INLINETILEOID)
+ {
+ InlineTileId t(target);
+ if (!t.is_null())
+ t->setPersistent(false);
+ }
+ //else: this tile has been deleted before
+ }
+ PQclear( pgResult );
+ }
+ else
+ {
+ // (1) --- iterate over cache and remove
+ DBObjectPMap& mapRef = ObjectBroker::getMap(target.getType());
+ DBObjectPMap::iterator it = mapRef.begin();
+ DBObjectPMap::iterator theEnd = mapRef.end();
+ OId end(target.getCounter() + range, target.getType());
+ while (it != theEnd)
+ {
+ if (target <= (const OId&)(*it).first && (*it).first <= (const OId&)end)
+ {
+ (*it).second->setPersistent(false);
+ }
+ }
+
+ // (2) --- iterate over db and remove
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "DECLARE DeleteLoop CURSOR FOR SELECT Tile FROM RAS_TILES WHERE %d <= BlobId AND BlobId <= %d", indbmyOId5, indbmyOId6 );
+ TALK( pgQuery );
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_TUPLES_OK)
+ {
+ LEAVE( "BLOBTile::kill() libpq 'select for deleteLoop' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+
+ // loop over elements & delete each one
+ do
+ {
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "FETCH NEXT FROM DeleteLoop" );
+ TALK( pgQuery );
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_TUPLES_OK)
+ {
+ LEAVE( "BLOBTile::kill() libpq 'fetch next' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+ else if (PQntuples(pgResult) != 1)
+ {
+ LEAVE( "BLOBTile::kill() libpq 'fetch' did not yield 1 result but " << PQntuples(pgResult) );
+ PQclear( pgResult );
+ generateException();
+ }
+ blobOid = atoi( PQgetvalue( pgResult, 0, 0 ) ); // extract value from result
+
+ // delete blob identified by blobOid
+ fileStorage->remove(blobOid);
+ // FIXME: what about errors? continue??
+ } while (PQresultStatus(pgResult) != PGRES_TUPLES_OK);
+ PQclear( pgResult );
+
+ // (3) --- delete tuples in db
+ indbmyOId5 = target.getCounter();
+ indbmyOId6 = end.getCounter();
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "DELETE FROM RAS_TILES WHERE %d <= BlobId AND BlobId <= %d", indbmyOId5, indbmyOId6 );
+ TALK( pgQuery );
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_COMMAND_OK)
+ {
+ LEAVE( "BLOBTile::kill() libpq 'delete range' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+ PQclear( pgResult );
+
+ }
+
+ LEAVE( "BLOBTile::kill" );
+ RMDBGEXIT(0, RMDebug::module_blobif, "BLOBTile", "kill(" << target << " " << target.getType() << ")");
+}
+
+// read tuple from ras_tiles, identified by blobtile.cc var myOId
+// allocates necessary mem into ptr 'cells' and fills it; must be freed elsewhere
+// external var 'size' is set to the number of bytes read
+void
+BLOBTile::readFromDb() throw (r_Error)
+{
+ RMDBGENTER(3, RMDebug::module_blobif, "BLOBTile", "readFromDb() " << myOId);
+ ENTER( "BLOBTile::readFromDb" );
+ if (fileStorage == NULL)
+ fileStorage = initFileStorage();
+
+#ifdef RMANBENCHMARK
+ DBObject::readTimer.resume();
+#endif
+
+ Oid blobOid;
+ long indbmyOId3;
+ short dataformat3;
+ short indicatorr3;
+ PGresult *pgResult = NULL; // PostgreSQL call return values
+
+ indbmyOId3 = myOId.getCounter();
+
+ // (1) --- access tuple
+ char pgQuery[SQL_QUERY_BUFFER_SIZE];
+
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "SELECT Tile, DataFormat FROM RAS_TILES WHERE BlobId = %d", indbmyOId3 );
+ TALK( pgQuery );
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_TUPLES_OK)
+ {
+ LEAVE( "BLOBTile::readFromDb() libpq 'select' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+ else if (PQntuples(pgResult) != 1)
+ {
+ LEAVE( "BLOBTile::readFromDb() libpq 'select' did not yield 1 result but " << PQntuples(pgResult) );
+ PQclear( pgResult );
+ throw r_Error(r_Error::r_Error_ObjectUnknown);
+ }
+ blobOid = atoi( PQgetvalue( pgResult, 0, 0 ) ); // extract 1st value from result
+ dataformat3 = atoi( PQgetvalue( pgResult, 0, 1 ) ); // extract 2nd value from result
+ PQclear( pgResult );
+
+ // we have a tuple, extract data format
+ dataFormat = (r_Data_Format)dataformat3;
+ currentFormat = (r_Data_Format)dataformat3;
+ TALK( "got dataFormat " << dataFormat );
+
+ fileStorage->retrieve(indbmyOId3, &cells, &size);
+
+ RMDBGIF(20, RMDebug::module_blobif, "BLOBTileOutput", for (int a = 0; a < size; a++)\
+ RMInit::dbgOut << " " << hex << (int)(cells[a]); RMInit::dbgOut << dec << endl;)
+
+ DBObject::readFromDb();
+
+#ifdef RMANBENCHMARK
+ DBObject::readTimer.pause();
+#endif
+
+ LEAVE( "BLOBTile::readFromDb" );
+ RMDBGEXIT(3, RMDebug::module_blobif, "BLOBTile", "readFromDb() " << myOId);
+}
+
diff --git a/relblobif/blobtile.hh b/relblobif/blobtile.hh
new file mode 100644
index 0000000..227ea1e
--- /dev/null
+++ b/relblobif/blobtile.hh
@@ -0,0 +1,160 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+// -*-C++-*- (for Emacs)
+
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * The Blobtile class is used to store the tiles in the database.
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#ifndef _BLOBTILE_HH_
+#define _BLOBTILE_HH_
+
+class OId;
+class r_Error;
+
+#include "dbtile.hh"
+#include "raslib/mddtypes.hh"
+
+//@ManMemo: Module: {\bf relblobif}.
+
+/*@Doc:
+
+BLOBTile is the persistent class for storing the contents of MDD tiles
+in the database. Each instance represents the contents of a tile of a MDD Object
+from the database. BLOBTiles are just arrays of unsigned characters.
+In main memory they are encapsulated in the class \Ref{PersTile}.
+
+At the moment a BLOBTile is loaded into main memory, when it is
+accessed the first time. This usually happens, when the RasDaMan DBMS
+accesses the contents of a \Ref{PersTile}.
+
+{\bf Interdependencies}
+
+BLOBTile is an interface class with the base DBMS. It is, therefore,
+highly dependent on the base DBMS used.
+*/
+
+class BLOBTile : public DBTile
+ {
+ public:
+ //@Man: constructors
+ //@{
+ BLOBTile(r_Data_Format dataformat = r_Array);
+ /*@Doc:
+ constructs a new empty BLOBTile and gets an id for it.
+ */
+
+ BLOBTile(const OId& BlobId) throw (r_Error);
+ /*@Doc:
+ constructs a BlobTile out of the database
+ */
+
+ BLOBTile(r_Bytes newSize, char c = 0, r_Data_Format dataformat = r_Array);
+ /*@Doc:
+ constructs a new BLOBTile of size newSize filled with c.
+ */
+
+ BLOBTile(r_Bytes newSize, r_Bytes patSize, const char* pat, r_Data_Format dataformat = r_Array);
+ /*@Doc:
+ Constructs a new BLOB Tile of size newSize filled with the repeated
+ char array pat of size patSize. If after filling some chars are
+ left, they are filled with 0
+ */
+ /*@ManMemo: constructs a new BLOB Tile with the char array newCells
+ with newSize elements as contents. */
+
+ BLOBTile(r_Bytes newSize, const char* newCells, r_Data_Format dataformat = r_Array);
+ /*@Doc:
+ constructs a new BLOBTile of size newSize filled with the contents of newCells.
+ */
+
+ BLOBTile(r_Bytes newSize, const char* newCells, r_Data_Format dataformat, const OId& myOId);
+ /*@Doc:
+ constructs a new BLOBTile of size newSize filled with the contents of newCells.
+ the oid will be assigned to this blob. used by regular computed index.
+ */
+
+ BLOBTile(const OId& BlobId, r_Bytes newSize, r_Data_Format newFmt);
+ /*@Doc:
+ constructs a new BLOBTile of size newSize filled with zeros.
+ the tile will think it is not modified and also not in the db but persistent.
+ this is used by the rc index.
+ */
+
+ //@}
+
+ virtual ~BLOBTile();
+ /*@Doc:
+ validates the object. deletes it cells.
+ */
+
+ static void kill(const OId& target, unsigned int range = 0);
+ /*@Doc:
+ delete a blobtile without loading it first into memory.
+ is used by the indexes.
+ delete the blobtile and range consecutive tiles.
+ */
+
+ static r_Bytes BLOBBufferLength;
+ /*@Doc:
+ info on the length of the BLOBBuffer
+ */
+
+ protected:
+
+ virtual void updateInDb() throw (r_Error);
+ /*@Doc:
+ update the contents of a Tile in the db
+ */
+
+ virtual void insertInDb() throw (r_Error);
+ /*@Doc:
+ inserts the Blob into the db.
+ */
+
+ virtual void readFromDb() throw (r_Error);
+ /*@Doc:
+ read blob from db into blobtile
+ */
+
+ virtual void deleteFromDb() throw (r_Error);
+ /*@Doc:
+ deletes a blob from TILES, sets size to 0 and flags to -1
+ */
+
+ private:
+ static char* BLOBBuffer;
+ /*@Doc:
+ for writing into the DB. currently not needed by oracle.
+ */
+
+ };
+
+#endif
diff --git a/relblobif/blobtile.pgc b/relblobif/blobtile.pgc
new file mode 100644
index 0000000..7f3aef4
--- /dev/null
+++ b/relblobif/blobtile.pgc
@@ -0,0 +1,765 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include "mymalloc/mymalloc.h"
+// This is -*- C++ -*-
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * implements blobtile interface using the PostgreSQL DBMS.
+ *
+ *
+ * COMMENTS:
+ * - uses LO blob method, this has been tested to be faster than bytea
+ * - RMDBG macros generate so weird output that I added DEBUG macros
+ * although this is very ugly (2 trace facilities in parallel)
+ * - exceptions thrown are r_Error, either directly or through common
+ * function generateException() (reladminif) which throws r_Ebase_dbms
+ *
+ ************************************************************/
+
+using namespace std;
+
+static const char rcsid[] = "@(#)blobif,BLOBTile: $Id: blobtile.ec,v 1.8 2003/12/27 23:19:03 rasdev Exp $";
+
+#include <stdio.h>
+#include <stdlib.h> /* atoi */
+
+// PG stuff:
+#include "libpq-fe.h" /* C interface to PgSQL */
+#include "libpq/libpq-fs.h" /* large object (lo) api */
+
+// simple trace facility
+// trace macros are activated through externally defined compile variable DEBUG
+#include "debug-srv.hh"
+
+// general embedded SQL related definitions
+EXEC SQL include "../reladminif/sqlglobals.h";
+
+// libpg connection maintenance
+// must have been initiated before use (see databasif.pgc)
+extern PGconn *pgConn;
+
+// all the DBMS independent code is factored out and
+// will be included in the resulting .c file
+//#include "blobtile.cc"
+#include "blobtile.hh"
+#include "raslib/rmdebug.hh"
+#include "reladminif/objectbroker.hh"
+#include "reladminif/dbref.hh"
+#include "reladminif/sqlerror.hh"
+#include "inlinetile.hh"
+
+// update blob in ras_tiles table, identified by variable myOId (from blobtile.cc), update map ref
+void
+BLOBTile::updateInDb() throw (r_Error)
+{
+ RMDBGENTER(3, RMDebug::module_blobif, "BLOBTile", "updateInDb() " << myOId);
+ ENTER( "BLOBTile::updateInDb" );
+
+#ifdef NOTYET // should be in future
+/*
+ EXEC SQL BEGIN DECLARE SECTION;
+ Oid tile;
+ long indbmyoId;
+ long indbmyoid = 0;
+ short dataformat = 0;
+ EXEC SQL END DECLARE SECTION;
+
+ dataformat = dataFormat;
+ indbmyoid = myOId.getCounter();
+
+ // (1) --- get tuple
+ TALK( "EXEC SQL SELECT Tile INTO :tile FROM RAS_TILES WHERE BlobId = " << indbmyoid );
+ EXEC SQL SELECT TILE
+ INTO :tile
+ FROM RAS_TILES
+ WHERE BlobId = :indbmyoid;
+ if (SQLCODE < 0)
+ {
+ RMInit::logOut << "BLOBTile::updateInDb(): error: cannot get blob, SQLCODE " << SQLCODE << endl;
+ LEAVE( "BLOBTile::updateInDb(): error: cannot get blob, SQLCODE " << SQLCODE );
+ check("Select blob oid");
+ generateException();
+ }
+ else if (SQLCODE == SQLNODATAFOUND)
+ {
+ RMInit::logOut << "BLOBTile::updateInDb(): error: object not in database" << endl;
+ LEAVE( "BLOBTile::updateInDb(): error: object not in database" );
+ throw r_Error(r_Error::r_Error_ObjectUnknown);
+ }
+*/
+#endif //NOTYET
+ // alternative solution for now:
+ Oid tile;
+ long indbmyoId = 0;
+ long indbmyoid = 0;
+ short dataformat = 0;
+ char pgQuery[SQL_QUERY_BUFFER_SIZE];
+ PGresult *pgResult = NULL;
+
+ // (1) --- get tuple
+ dataformat = dataFormat;
+ indbmyoid = myOId.getCounter();
+
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "SELECT Tile FROM RAS_TILES WHERE BlobId = %d", indbmyoid );
+ TALK( pgQuery );
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_TUPLES_OK)
+ {
+ LEAVE( "BLOBTile::updateInDb() libpq 'select tile' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+ else if (PQntuples(pgResult) != 1)
+ {
+ LEAVE( "BLOBTile::updateInDb() libpq 'select' did not yield 1 result but " << PQntuples(pgResult) );
+ PQclear( pgResult );
+ generateException();
+ }
+ tile = atoi( PQgetvalue( pgResult, 0, 0 ) ); // extract value from result
+ PQclear( pgResult );
+
+ // (2) --- open, write, close blob
+ TALK( "lo_open()" );
+ int fd = lo_open( pgConn, tile, INV_WRITE ); // no error code mentioned in manual
+ TALK( "lo_write() for fd " << fd << " and " << size << " bytes" );
+ int loResult = lo_write( pgConn, fd, cells, size );
+ if (loResult < 0)
+ {
+ RMInit::logOut << "BLOBTile::updateInDb() cannot write blob, error: " << loResult << endl;
+ LEAVE( "BLOBTile::updateInDb: cannot write blob, error " << loResult );
+ generateException();
+ }
+ else if (loResult != size) // did not get all
+ {
+ RMInit::dbgOut << "BLOB (" << myOId << ") insert: wrote " << loResult << " instead of " << size << " bytes" << endl;
+ LEAVE( "BLOBTile::updateInDb: wrote " << loResult << " instead of " << size << " bytes" );
+ generateException();
+ }
+ TALK( "lo_close()" );
+ loResult = lo_close( pgConn, fd );
+ if (loResult < 0) // can't close, don't know if data are written
+ {
+ RMInit::logOut << "BLOBTile::updateInDb() ignoring lo_close() error: " << PQerrorMessage(pgConn) << endl;
+ LEAVE( "BLOBTile::updateInDb: cannot lo_close(): " << PQerrorMessage(pgConn) );
+ generateException();
+ }
+
+#ifdef NOTYET // should be in future
+/*
+ // (3) --- update data format
+ // NOTE: we assume the blob already exists and do not change the oid
+ TALK( "EXEC SQL UPDATE RAS_TILES SET DataFormat = " << dataformat << " WHERE BlobId = " << indbmyoid );
+ EXEC SQL UPDATE RAS_TILES
+ SET DataFormat = :dataformat
+ WHERE BlobId = :indbmyoid;
+ if (check("Update Dataformat"))
+ generateException();
+*/
+#endif //NOTYET
+ // alternative solution for now:
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "UPDATE RAS_TILES SET DataFormat = %d WHERE BlobId = %d", dataformat, indbmyoid );
+ TALK( pgQuery );
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_COMMAND_OK)
+ {
+ LEAVE( "BLOBTile::updateInDb() libpq 'update dataformat' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+
+ // (4) --- update map ref
+ DBObject::updateInDb();
+
+ LEAVE( "BLOBTile::updateInDb, myOId=" << myOId );
+ RMDBGEXIT(3, RMDebug::module_blobif, "BLOBTile", "updateInDb() " << myOId);
+} // updateInDb()
+
+// insert new blob into ras_tiles table, update map ref
+// tuple is identified by blobtile.cc var myOId
+// data is taken from buffer 'cells' containing 'size' bytes
+void
+BLOBTile::insertInDb() throw (r_Error)
+{
+ RMDBGENTER(3, RMDebug::module_blobif, "BLOBTile", "insertInDb() " << myOId);
+ ENTER( "BLOBTile::insertInDb" );
+
+/*
+#ifdef NOTYET
+ EXEC SQL BEGIN DECLARE SECTION;
+#endif NOTYET
+*/
+ Oid blobOid;
+ long indbmyOId2;
+ short dataformat2;
+ Oid tile2;
+/*
+#ifdef NOTYET
+ EXEC SQL END DECLARE SECTION;
+#endif NOTYET
+*/
+ dataformat2 = dataFormat;
+
+ // prelim:
+ char pgQuery[SQL_QUERY_BUFFER_SIZE];
+ PGresult *pgResult = NULL;
+
+ indbmyOId2 = myOId.getCounter();
+ TALK( "myOId.getCounter = " << indbmyOId2 );
+
+ // (1) --- open, write, close blob; generates new 'oid' for subsequent storage in tuple
+ TALK( "lo_creat()" );
+ blobOid = lo_creat( pgConn, INV_READ|INV_WRITE ); // create -- not clear what INV_* here means so indicate all
+ if (blobOid == 0)
+ {
+ RMInit::logOut << "BLOBTile::insertInDb() cannot create blob, error: " << PQerrorMessage(pgConn) << endl;
+ LEAVE( "BLOBTile::insertInDb(): cannot create blob, error " << PQerrorMessage(pgConn) );
+ generateException();
+ }
+ TALK( "lo_open() for oid " << blobOid );
+ int fd = lo_open( pgConn, blobOid, INV_WRITE ); // no error code indicated, 0 seems to be no error
+ TALK( "lo_write() for fd " << fd << " and " << size << " bytes" );
+ int loResult = lo_write( pgConn, fd, cells, size );
+ if (loResult < 0)
+ {
+ RMInit::logOut << "BLOBTile::insertInDb() cannot write blob, error: " << PQerrorMessage(pgConn) << endl;
+ LEAVE( "BLOBTile::insertInDb(): cannot write blob, error " << PQerrorMessage(pgConn) );
+ generateException();
+ }
+ else if (loResult != size) // did not get all
+ {
+ RMInit::dbgOut << "BLOB (" << myOId << ") insert: wrote " << loResult << " instead of " << size << " bytes" << endl;
+ LEAVE( "BLOBTile::insertInDb(): wrote " << loResult << " instead of " << size << " bytes" );
+ generateException();
+ }
+ TALK( "lo_close()" );
+ loResult = lo_close( pgConn, fd );
+ if (loResult < 0) // cannot close, don't know if data are there
+ {
+ RMInit::logOut << "BLOBTile::insertInDb() ignoring lo_close() error: " << PQerrorMessage(pgConn) << endl;
+ LEAVE( "BLOBTile::insertInDb(): ignoring lo_close() error: " << PQerrorMessage(pgConn) );
+ generateException();
+ }
+
+/*
+#ifdef NOTYET
+ // (2) --- insert tuple into db
+ TALK( "EXEC SQL INSERT INTO RAS_TILES ( BlobId, DataFormat, Tile ) VALUES (" << indbmyOId2 << "," << dataformat2 << ", " << blobOid << ")" );
+ EXEC SQL INSERT INTO RAS_TILES ( BlobId, DataFormat, Tile)
+ VALUES ( :indbmyOId2, :dataformat2, :blobOid );
+#endif NOTYET
+*/
+ // alternative solution for now:
+ // (2) --- insert tuple into db
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "INSERT INTO RAS_TILES ( BlobId, DataFormat, Tile) VALUES ( %d, %d, %d )", indbmyOId2, dataformat2, blobOid );
+ TALK( pgQuery );
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_COMMAND_OK)
+ {
+ LEAVE( "BLOBTile::insertInDb() libpq 'insert' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+ PQclear( pgResult );
+
+ // FIXME: other sources have here an updateInDb();
+
+ // (3) --- update map ref
+ DBObject::insertInDb();
+
+ LEAVE( "BLOBTile::insertInDb(), myOId=" << myOId );
+ RMDBGEXIT(3, RMDebug::module_blobif, "BLOBTile", "insertInDb() " << myOId);
+} // insertInDb()
+
+// delete one tuple from ras_tiles table, update map ref
+// tuple is identified by blobtile.cc var myOId
+void
+BLOBTile::deleteFromDb() throw (r_Error)
+{
+ RMDBGENTER(3, RMDebug::module_blobif, "BLOBTile", "deleteFromDb() " << myOId);
+ ENTER( "BLOBTile::deleteFromDb" );
+
+/*
+#ifdef NOTYET
+ EXEC SQL BEGIN DECLARE SECTION;
+#endif NOTYET
+*/
+ long blobId; // blob tuple primary key
+ Oid blobOid; // blob oid "ptr"
+/*
+#ifdef NOTYET
+ EXEC SQL END DECLARE SECTION;
+#endif NOTYET
+*/
+
+ // get counter value (primary key) from oid
+ blobId = myOId.getCounter();
+
+/*
+#ifdef NOTYET
+ // (1) --- get tile tuple
+ TALK( "EXEC SQL SELECT Tile INTO :blobOid FROM RAS_TILES WHERE BlobId = " << blobId );
+ EXEC SQL SELECT Tile INTO :blobOid FROM RAS_TILES WHERE BlobId = :blobId;
+ if (SQLCODE < 0)
+ {
+ LEAVE( "BLOBTile::deleteFromDb(): Fatal error: cannot find tuple for oid " << blobId );
+ check("BLOBTile::deleteFromDb() - find tuple\0");
+ generateException();
+ }
+#endif NOTYET
+*/
+ char pgQuery[SQL_QUERY_BUFFER_SIZE];
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "SELECT Tile FROM RAS_TILES WHERE BlobId = %d", blobId );
+ TALK( pgQuery );
+ PGresult *pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult))
+ {
+ LEAVE( "BLOBTile::deleteFromDb() libpq 'select tile' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+ else if (PQntuples(pgResult) != 1)
+ {
+ LEAVE( "BLOBTile::deleteFromDb() libpq 'select' did not yield 1 result but " << PQntuples(pgResult) );
+ PQclear( pgResult );
+ generateException();
+ }
+ blobOid = atoi( PQgetvalue( pgResult, 0, 0 ) ); // extract value from result
+ PQclear( pgResult );
+
+ // FIXME: other sources have here an updateInDb();
+
+ // (2) --- delete blob identified by blobOid
+ TALK( "lo_unlink()" );
+ int loResult = lo_unlink( pgConn, blobOid );
+ if (loResult < 0)
+ {
+ LEAVE( "BLOBTile::deleteFromDb(): cannot unlink blob with id '" << blobOid << "' for oid " << blobId << PQerrorMessage(pgConn) );
+ generateException();
+ }
+
+/*
+#ifdef NOTYET
+ // (3) --- delete tuple from table
+ TALK( "EXEC SQL DELETE FROM RAS_TILES WHERE BlobId = " << blobId );
+ EXEC SQL DELETE FROM RAS_TILES WHERE BlobId = :blobId;
+ if (SQLCODE < 0)
+ {
+ LEAVE( "BLOBTile::deleteFromDb: Fatal error: cannot delete tuple for oid " << blobId << ", error: " << SQLCODE );
+ check("BLOBTile::deleteFromDb() - delete tuple\0");
+ generateException();
+ }
+#endif NOTYET
+*/
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "DELETE FROM RAS_TILES WHERE BlobId = ", blobOid );
+ TALK( pgQuery );
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_COMMAND_OK)
+ {
+ LEAVE( "BLOBTile::deleteFromDb() libpq 'delete tuple' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+ PQclear( pgResult );
+
+ // FIXME: other sources have here an updateInDb();
+
+ // update map ref
+ DBObject::deleteFromDb();
+
+ LEAVE( "BLOBTile::deleteFromDb, myOId=" << myOId );
+ RMDBGEXIT(3, RMDebug::module_blobif, "BLOBTile", "deleteFromDb() " << myOId);
+}
+
+// delete a range of tuple(s) from ras_tiles table, update map ref
+// tuples are identified by target and a range
+void
+BLOBTile::kill(const OId& target, unsigned int range)
+{
+ RMDBGENTER(0, RMDebug::module_blobif, "BLOBTile", "kill(" << target << ", " << range <<")");
+ ENTER( "BLOBTile::kill, target=" << target << ", range=" << range );
+
+/*
+#ifdef NOTYET
+ EXEC SQL BEGIN DECLARE SECTION;
+#endif NOTYET
+*/
+ long indbmyOId5;
+ long indbmyOId6;
+ long blobId; // blob tuple primary key
+ Oid blobOid; // blob oid "ptr"
+/*
+#ifdef NOTYET
+ EXEC SQL END DECLARE SECTION;
+#endif NOTYET
+*/
+ char pgQuery[SQL_QUERY_BUFFER_SIZE];
+ PGresult *pgResult = NULL; // query result
+
+ DBObject* targetobj = NULL;
+
+ if (range == 0) // single tuple
+ {
+ // (1) --- delete form cache
+ targetobj = ObjectBroker::isInMemory(target);
+ if (targetobj)
+ {
+ targetobj->setPersistent(false);
+ }
+
+ // (2) --- free blob
+ indbmyOId5 = target.getCounter();
+/*
+#ifdef NOTYET
+ TALK( "EXEC SQL SELECT Tile INTO :blobOid FROM RAS_TILES WHERE BlobId = " << indbmyOId5 );
+ EXEC SQL SELECT Tile INTO :blobOid FROM RAS_TILES WHERE BlobId = :indbmyOId5;
+ if (SQLCODE < 0)
+ {
+ LEAVE( "BLOBTile::kill(): Fatal error: cannot find tuple for oid " << blobId );
+ check("BLOBTile::kill() - find tuple\0");
+ generateException();
+ }
+ else if (SQLCODE != SQLNODATAFOUND) // we've got a tuple
+ {
+ // delete blob identified by blobOid
+ }
+ // else there is no tuple - this is inconsistent, but nothing to delete
+#endif NOTYET
+*/
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "SELECT Tile FROM RAS_TILES WHERE BlobId = %d", indbmyOId5 );
+ TALK( pgQuery );
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_TUPLES_OK)
+ {
+ LEAVE( "BLOBTile::kill() libpq 'select tile' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+ else if (PQntuples(pgResult) != 1)
+ {
+ LEAVE( "BLOBTile::kill() libpq 'select' did not yield 1 result but " << PQntuples(pgResult) );
+ PQclear( pgResult );
+ generateException();
+ }
+ blobOid = atoi( PQgetvalue( pgResult, 0, 0 ) ); // extract value from result
+ PQclear( pgResult );
+
+ // delete blob identified by blobOid
+ int loResult = lo_unlink( pgConn, blobOid );
+ if (loResult < 0)
+ {
+ LEAVE( "BLOBTile::kill(): cannot unlink blob with id '" << blobOid << "' for oid " << blobId << ": " << PQerrorMessage(pgConn) );
+ check("BLOBTile::kill() - unlink blob\0");
+ generateException();
+ }
+
+/*
+#ifdef NOTYET
+ // (3) --- delete tuple
+ TALK( "EXEC SQL DELETE FROM RAS_TILES WHERE BlobId = " << indbmyOId5 );
+ EXEC SQL DELETE FROM RAS_TILES WHERE BlobId = :indbmyOId5;
+ if (SQLCODE != SQLOK)
+ {
+ if (SQLCODE == SQLNODATAFOUND) // was: NODATA -- PB 2005-feb-13
+ {
+ if (target.getType() == OId::INLINETILEOID)
+ {
+ InlineTileId t(target);
+ if (!t.is_null())
+ t->setPersistent(false);
+ }
+ //else: this tile has been deleted before
+ }
+ else
+ {
+ check("BLOBTile::kill()\0");
+ generateException();
+ }
+ }
+#endif NOTYET
+*/
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "DELETE FROM RAS_TILES WHERE BlobId = %d", indbmyOId5 );
+ TALK( pgQuery );
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_COMMAND_OK)
+ {
+ LEAVE( "BLOBTile::kill() libpq 'delete single' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+ else if (PQntuples(pgResult) == 0)
+ {
+ if (target.getType() == OId::INLINETILEOID)
+ {
+ InlineTileId t(target);
+ if (!t.is_null())
+ t->setPersistent(false);
+ }
+ //else: this tile has been deleted before
+ }
+ PQclear( pgResult );
+ }
+ else
+ {
+ // (1) --- iterate over cache and remove
+ DBObjectPMap& mapRef = ObjectBroker::getMap(target.getType());
+ DBObjectPMap::iterator it = mapRef.begin();
+ DBObjectPMap::iterator theEnd = mapRef.end();
+ OId end(target.getCounter() + range, target.getType());
+ while (it != theEnd)
+ {
+ if (target <= (const OId&)(*it).first && (*it).first <= (const OId&)end)
+ {
+ (*it).second->setPersistent(false);
+ }
+ }
+
+ // (2) --- iterate over db and remove
+/*
+#ifdef NOTYET
+ TALK( "EXEC SQL DECLARE DeleteLoop CURSOR FOR SELECT Tile FROM RAS_TILES WHERE " << indbmyOId5 << " <= BlobId AND BlobId <= " << indbmyOId6 );
+ EXEC SQL DECLARE DeleteLoop CURSOR FOR SELECT Tile FROM RAS_TILES WHERE :indbmyOId5 <= BlobId AND BlobId <= :indbmyOId6;
+ if (SQLCODE < 0)
+ {
+ LEAVE( "BLOBTile::kill: Fatal error: cannot prepare cursor for oid " << blobId << " to " << indbmyOId6 );
+ check("BLOBTile::kill() - prepare cursor\0");
+ generateException();
+ }
+#endif NOTYET
+*/
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "DECLARE DeleteLoop CURSOR FOR SELECT Tile FROM RAS_TILES WHERE %d <= BlobId AND BlobId <= %d", indbmyOId5, indbmyOId6 );
+ TALK( pgQuery );
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_TUPLES_OK)
+ {
+ LEAVE( "BLOBTile::kill() libpq 'select for deleteLoop' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+
+ // loop over elements & delete each one
+ do
+ {
+/*
+#ifdef NOTYET
+ TALK( "EXEC SQL FETCH NEXT FROM DeleteLoop INTO :blobOid" );
+ EXEC SQL FETCH NEXT FROM DeleteLoop INTO :blobOid;
+ if (SQLCODE < 0)
+ {
+ LEAVE( "BLOBTile::kill: Fatal error: cannot fetch next tuple" );
+ check("BLOBTile::kill() - fetch next tuple\0");
+ generateException();
+ }
+#endif NOTYET
+*/
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "FETCH NEXT FROM DeleteLoop" );
+ TALK( pgQuery );
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_TUPLES_OK)
+ {
+ LEAVE( "BLOBTile::kill() libpq 'fetch next' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+ else if (PQntuples(pgResult) != 1)
+ {
+ LEAVE( "BLOBTile::kill() libpq 'fetch' did not yield 1 result but " << PQntuples(pgResult) );
+ PQclear( pgResult );
+ generateException();
+ }
+ blobOid = atoi( PQgetvalue( pgResult, 0, 0 ) ); // extract value from result
+
+ // delete blob identified by blobOid
+ int loResult = lo_unlink( pgConn, blobOid );
+ if (loResult < 0)
+ {
+ LEAVE( "BLOBTile::kill: Fatal error: cannot unlink blob with id '" << blobOid << "' for oid " << blobId );
+ check("BLOBTile::kill() - unlink blob\0");
+ generateException();
+ }
+/*
+#ifdef NOTYET
+ } while (SQLCODE == SQLOK || SQLCODE < 0);
+#endif NOTYET
+*/
+ // FIXME: what about errors? continue??
+ } while (PQresultStatus(pgResult) != PGRES_TUPLES_OK);
+ PQclear( pgResult );
+
+ // (3) --- delete tuples in db
+ indbmyOId5 = target.getCounter();
+ indbmyOId6 = end.getCounter();
+/*
+#ifdef NOTYET
+ TALK( "EXEC SQL DELETE FROM RAS_TILES WHERE " << indbmyOId5 << " <= BlobId AND BlobId <= " << indbmyOId6 );
+ EXEC SQL DELETE FROM RAS_TILES WHERE :indbmyOId5 <= BlobId AND BlobId <= :indbmyOId6;
+ if ((SQLCODE != SQLOK) && (SQLCODE != SQLNODATAFOUND))
+ {
+ check("BLOBTile::kill()\0");
+ generateException();
+ }
+#endif NOTYET
+*/
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "DELETE FROM RAS_TILES WHERE %d <= BlobId AND BlobId <= %d", indbmyOId5, indbmyOId6 );
+ TALK( pgQuery );
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_COMMAND_OK)
+ {
+ LEAVE( "BLOBTile::kill() libpq 'delete range' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+ PQclear( pgResult );
+
+ }
+
+ LEAVE( "BLOBTile::kill" );
+ RMDBGEXIT(0, RMDebug::module_blobif, "BLOBTile", "kill(" << target << " " << target.getType() << ")");
+}
+
+// read tuple from ras_tiles, identified by blobtile.cc var myOId
+// allocates necessary mem into ptr 'cells' and fills it; must be freed elsewhere
+// external var 'size' is set to the number of bytes read
+void
+BLOBTile::readFromDb() throw (r_Error)
+{
+ RMDBGENTER(3, RMDebug::module_blobif, "BLOBTile", "readFromDb() " << myOId);
+ ENTER( "BLOBTile::readFromDb" );
+
+#ifdef RMANBENCHMARK
+ DBObject::readTimer.resume();
+#endif
+
+/*
+#ifdef NOTYET
+ EXEC SQL BEGIN DECLARE SECTION;
+#endif NOTYET
+*/
+ Oid blobOid;
+ long indbmyOId3;
+ short dataformat3;
+ short indicatorr3;
+/*
+#ifdef NOTYET
+ EXEC SQL END DECLARE SECTION;
+#endif NOTYET
+*/
+ PGresult *pgResult = NULL; // PostgreSQL call return values
+
+ indbmyOId3 = myOId.getCounter();
+
+ // (1) --- access tuple
+/*
+#ifdef NOTYET
+ TALK( "EXEC SQL SELECT Tile, DataFormat INTO :blobOid, :dataformat3 FROM RAS_TILES WHERE BlobId = " << indbmyOId3 );
+ EXEC SQL SELECT Tile, DataFormat INTO :blobOid, :dataformat3 FROM RAS_TILES WHERE BlobId = :indbmyOId3;
+ if (SQLCODE < 0)
+ {
+ RMInit::logOut << "BLOBTile::readFromDb() Fatal error during RAS_TILES read: got SQLCODE " << SQLCODE << " for oid " << indbmyOId3 << endl;
+ LEAVE( "BLOBTile::readFromDb: Fatal error during RAS_TILES read: got SQLCODE " << SQLCODE << " for oid " << indbmyOId3 );
+ check("BLOBTile::readFromDb() - find tuple\0");
+ generateException();
+ }
+ else if (SQLCODE == SQLNODATAFOUND) // we've got no tuple
+ {
+ RMInit::logOut << "BLOBTile::readFromDb() error: object unknown for oid " << indbmyOId3 << endl;
+ LEAVE( "BLOBTile::readFromDb: Error: object unknown for oid " << indbmyOId3 );
+ throw r_Error(r_Error::r_Error_ObjectUnknown);
+ }
+#endif NOTYET
+*/
+ char pgQuery[SQL_QUERY_BUFFER_SIZE];
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "SELECT Tile, DataFormat FROM RAS_TILES WHERE BlobId = %d", indbmyOId3 );
+ TALK( pgQuery );
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_TUPLES_OK)
+ {
+ LEAVE( "BLOBTile::readFromDb() libpq 'select' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+ else if (PQntuples(pgResult) != 1)
+ {
+ LEAVE( "BLOBTile::readFromDb() libpq 'select' did not yield 1 result but " << PQntuples(pgResult) );
+ PQclear( pgResult );
+ throw r_Error(r_Error::r_Error_ObjectUnknown);
+ }
+ blobOid = atoi( PQgetvalue( pgResult, 0, 0 ) ); // extract 1st value from result
+ dataformat3 = atoi( PQgetvalue( pgResult, 0, 1 ) ); // extract 2nd value from result
+ PQclear( pgResult );
+
+ // we have a tuple, extract data format
+ dataFormat = (r_Data_Format)dataformat3;
+ currentFormat = (r_Data_Format)dataformat3;
+ TALK( "got dataFormat " << dataFormat );
+
+ // (2) --- open, read, close blob
+ TALK( "lo_open()" );
+ int fd = lo_open( pgConn, blobOid, INV_READ ); // open; manual tells no error indication
+ TALK( "lo_lseek() end" );
+ size = lo_lseek( pgConn, fd, 0, SEEK_END ); // determine blob size; FIXME: more efficient method??
+ TALK( "lo_lseek() start" );
+ (void) lo_lseek( pgConn, fd, 0, SEEK_SET ); // rewind for reading
+ cells = (char*) mymalloc( size * sizeof(char) ); // allocate buffer for blob
+ if (cells == NULL)
+ {
+ RMInit::logOut << "BLOBTile::readFromDb() error: cannot allocate " << size << " bytes " << endl;
+ LEAVE( "BLOBTile::readFromDb: error: cannot allocate " << size << " bytes" );
+ generateException();
+ }
+
+ TALK( "lo_read()" ); // read blob
+ int loResult = lo_read( pgConn, fd, cells, size );
+ if (loResult < 0)
+ {
+ RMInit::logOut << "BLOBTile::readFromDb() cannot read blob, error: " << PQerrorMessage(pgConn) << endl;
+ LEAVE( "BLOBTile::readFromDb: cannot read blob, error " << PQerrorMessage(pgConn) );
+ generateException();
+ }
+ else if (loResult != size) // did not get all
+ {
+ RMInit::dbgOut << "BLOB (" << myOId << ") read: want to read (" << size << " bytes, but got " << loResult << " bytes" << endl;
+ LEAVE( "BLOBTile::readFromDb: want to read " << size << " bytes, but got " << loResult << " bytes" );
+ generateException();
+ }
+ TALK( "lo_close()" );
+ int ignoredPgResult = lo_close( pgConn, fd ); // close blob
+ if (ignoredPgResult < 0) // we note, but ignore errors, as we have the data
+ {
+ RMInit::logOut << "BLOBTile::readFromDb() ignoring lo_close() error: " << ignoredPgResult << endl;
+ TALK( "BLOBTile::readFromDb: ignoring lo_close() error: " << ignoredPgResult );
+ }
+ RMDBGIF(20, RMDebug::module_blobif, "BLOBTileOutput", for (int a = 0; a < size; a++)\
+ RMInit::dbgOut << " " << hex << (int)(cells[a]); RMInit::dbgOut << dec << endl;)
+
+ DBObject::readFromDb();
+
+#ifdef RMANBENCHMARK
+ DBObject::readTimer.pause();
+#endif
+
+ LEAVE( "BLOBTile::readFromDb" );
+ RMDBGEXIT(3, RMDebug::module_blobif, "BLOBTile", "readFromDb() " << myOId);
+}
+
diff --git a/relblobif/blobtilecommon.cc b/relblobif/blobtilecommon.cc
new file mode 100644
index 0000000..d134687
--- /dev/null
+++ b/relblobif/blobtilecommon.cc
@@ -0,0 +1,172 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include "mymalloc/mymalloc.h"
+
+// This is -*- C++ -*-
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ * uses embedded SQL
+ *
+ * PURPOSE
+ * has common code for all database interface implementations
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <vector>
+#include <iostream>
+#include <cstring>
+
+#include "blobtile.hh"
+
+#include "raslib/error.hh"
+#include "reladminif/externs.h"
+#include "raslib/rmdebug.hh"
+#include "reladminif/sqlerror.hh"
+#include "tileid.hh"
+#include "inlinetile.hh"
+#include "reladminif/objectbroker.hh"
+#include "reladminif/dbref.hh"
+
+// defined in rasserver.cc
+extern char globalConnectId[256];
+
+BLOBTile::BLOBTile(r_Data_Format dataformat)
+ : DBTile(dataformat)
+ {
+ RMDBGONCE(3, RMDebug::module_blobif, "BLOBTile", "BLOBTile(" << dataformat << ")");
+ objecttype = OId::BLOBOID;
+ }
+
+/*************************************************************
+ * Method name...: BLOBTile(r_Bytes newSize, char c)
+ *
+ * Arguments.....:
+ * newSize: size in number of chars
+ * c: value for all cells
+ * Return value..: none
+ * Description...: creates a new BLOBTile containing with all
+ * cells set to c.
+ ************************************************************/
+
+BLOBTile::BLOBTile(r_Bytes newSize, char c, r_Data_Format dataformat)
+ : DBTile(newSize, c, dataformat)
+ {
+ RMDBGONCE(3, RMDebug::module_blobif, "BLOBTile", "BLOBTile(" << newSize << ", data, " << dataformat << ")");
+ objecttype = OId::BLOBOID;
+ }
+
+
+/*************************************************************
+ * Method name...: BLOBTile(r_Bytes newSize,
+ * int patSize, char* pat);
+ *
+ * Arguments.....:
+ * newSize: size in number of chars
+ * patSize: number of chars in pattern
+ * pat: char array with the pattern
+ * Return value..: none
+ * Description...: creates a new BLOBTile containing the
+ * repeated pattern pat. newSize shoud be
+ * a multiply of patSize, otherwise the
+ * cells are filled up with 0.
+ ************************************************************/
+
+BLOBTile::BLOBTile(r_Bytes newSize, r_Bytes patSize, const char* pat, r_Data_Format dataformat)
+ : DBTile(newSize, patSize, pat, dataformat)
+ {
+ RMDBGONCE(3, RMDebug::module_blobif, "BLOBTile", "BLOBTile(" << newSize << ", " << patSize << ", pattern, " << dataformat << ")");
+ objecttype = OId::BLOBOID;
+ }
+
+/*************************************************************
+ * Method name...: BLOBTile(r_Bytes newSize,
+ * char* newCells)
+ *
+ * Arguments.....:
+ * newSize: size in number of chars
+ * newCells: char array with the new cells (must
+ * have at least newSize elements)
+ * Return value..: none
+ * Description...: creates a new BLOBTile. The elements of
+ * the char array are copied!
+ ************************************************************/
+
+BLOBTile::BLOBTile(r_Bytes newSize, const char* newCells, r_Data_Format dataformat)
+ : DBTile(newSize, newCells, dataformat)
+ {
+ RMDBGONCE(3, RMDebug::module_blobif, "BLOBTile", "BLOBTile(" << size << ", data, " << dataformat << ")");
+ objecttype = OId::BLOBOID;
+ }
+
+BLOBTile::BLOBTile(r_Bytes newSize, const char* newCells, r_Data_Format dataformat, const OId& id)
+ : DBTile(newSize, newCells, dataformat)
+ {
+ RMDBGONCE(3, RMDebug::module_blobif, "BLOBTile", "BLOBTile(" << size << ", data, " << dataformat << ", " << id << ")");
+ objecttype = OId::BLOBOID;
+ myOId = id;
+ // copied from DBObject::setPersistent()
+ // if we don't do this the blob will get a new oid
+ _isPersistent = true;
+ _isModified = true;
+ ObjectBroker::registerDBObject(this);
+ }
+
+BLOBTile::BLOBTile(const OId& id) throw (r_Error)
+ : DBTile(id)
+ {
+ RMDBGENTER(3, RMDebug::module_blobif, "BLOBTile", "BLOBTile(" << id <<")");
+ readFromDb();
+ RMDBGEXIT(3, RMDebug::module_blobif, "BLOBTile", "BLOBTile(" << id << ")");
+ }
+
+BLOBTile::BLOBTile(const OId& id, r_Bytes newSize, r_Data_Format newFmt)
+ : DBTile(id)
+ {
+ _isInDatabase = false;
+ _isPersistent = true;
+ _isModified = false;
+ _isCached = false;
+ dataFormat = newFmt;
+ currentFormat = r_Array;
+ size = newSize;
+ cells = (char*)mymalloc(size * sizeof(char));
+ memset(cells, 0, size);
+ ObjectBroker::registerDBObject(this);
+ }
+
+BLOBTile::~BLOBTile()
+ {
+ RMDBGENTER(3, RMDebug::module_blobif, "BLOBTile", "~BLOBTile() " << myOId);
+ validate();
+ RMDBGEXIT(3, RMDebug::module_blobif, "BLOBTile", "~BLOBTile() " << myOId << ")");
+ }
+
+char* BLOBTile::BLOBBuffer = NULL;
+r_Bytes BLOBTile::BLOBBufferLength = 131072;
+
diff --git a/relblobif/dbtile.cc b/relblobif/dbtile.cc
new file mode 100644
index 0000000..4c9d928
--- /dev/null
+++ b/relblobif/dbtile.cc
@@ -0,0 +1,329 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include "mymalloc/mymalloc.h"
+// This is -*- C++ -*-
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ * uses embedded SQL
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)blobif,DBTile: $Id: dbtile.cc,v 1.12 2005/09/03 20:41:40 rasdev Exp $";
+
+#include "dbtile.hh"
+#include "raslib/rmdebug.hh"
+#include "reladminif/externs.h"
+#include "reladminif/sqlerror.hh"
+#include "raslib/error.hh"
+#include "reladminif/objectbroker.hh"
+#include "blobtile.hh"
+#include "inlinetile.hh"
+#include "reladminif/dbref.hh"
+#include "debug.hh" // for ENTER/LEAVE/TALK macros
+
+#include "unistd.h"
+#include <iostream>
+#include <cstring>
+#include <vector>
+
+#ifdef BASEDB_ORACLE
+ #include <oratypes.h>
+ #include <oci.h>
+ #include <sqlca.h>
+#endif
+
+
+r_Data_Format
+DBTile::getDataFormat() const
+ {
+ RMDBGONCE(3, RMDebug::module_blobif, "DBTile", "getDataFormat() const " << myOId << " " << dataFormat);
+ return dataFormat;
+ }
+
+r_Data_Format
+DBTile::getCurrentFormat() const
+ {
+ return currentFormat;
+ }
+
+void
+DBTile::setCurrentFormat(const r_Data_Format& dataformat) const
+ {
+ currentFormat = dataformat;
+ }
+
+void
+DBTile::setDataFormat(const r_Data_Format& dataformat)
+ {
+ dataFormat = dataformat;
+ setModified();
+ }
+
+r_Bytes
+DBTile::getMemorySize() const
+ {
+ return size * sizeof(char) + sizeof(char*) + sizeof(r_Data_Format) + DBObject::getMemorySize() + sizeof(r_Bytes);
+ }
+
+void
+DBTile::setCells(char* newCells)
+ {
+ if(cells != newCells) {
+ if(cells != NULL) {
+ TALK( "DBTile::setCells() freeing blob cells" );
+ free(cells);
+ // cells = NULL; // added PB 2005-jan-10
+ }
+ cells = newCells;
+ setModified();
+ }
+ }
+
+void
+DBTile::setNoModificationData(char* newCells) const
+ {
+ if(cells != newCells) {
+ if(cells != NULL) {
+ TALK( "DBTile::setNoModificationData() freeing blob cells" );
+ free(cells);
+ // cells = NULL; // added PB 2005-jan-10
+ }
+ cells = newCells;
+ }
+ }
+
+void
+DBTile::setNoModificationSize(r_Bytes newSize) const
+ {
+ size = newSize;
+ }
+
+char*
+DBTile::getCells()
+ {
+ RMDBGONCE(3, RMDebug::module_blobif, "DBTile", "getCells() " << myOId);
+ setModified();
+ return cells;
+ }
+
+const char*
+DBTile::getCells() const
+ {
+ RMDBGONCE(3, RMDebug::module_blobif, "DBTile", "getCells() const " << myOId);
+ return cells;
+ }
+
+char
+DBTile::getCell(r_Bytes index) const
+ {
+ RMDBGONCE(3, RMDebug::module_blobif, "DBTile", "getCell(" << index << ") const " << myOId);
+ return cells[index];
+ }
+
+r_Bytes
+DBTile::getSize() const
+ {
+ RMDBGONCE(3, RMDebug::module_blobif, "DBTile", "getSize() const " << myOId << " " << size);
+ return size;
+ }
+
+void
+DBTile::setCell(r_Bytes index, char newCell)
+ {
+ RMDBGONCE(3, RMDebug::module_blobif, "DBTile", "setCell(" << index << ", " << (int)newCell << ") " << myOId);
+ setModified();
+ cells[index] = newCell;
+ }
+
+DBTile::DBTile(r_Data_Format dataformat)
+ : DBObject(),
+ size(0),
+ cells(NULL),
+ dataFormat(dataformat),
+ currentFormat(r_Array)
+ {
+ RMDBGONCE(3, RMDebug::module_blobif, "DBTile", "DBTile(" << dataFormat << ")");
+ objecttype = OId::INVALID;
+ }
+
+DBTile::DBTile(r_Bytes newSize, char c, r_Data_Format dataformat)
+ : DBObject(),
+ size(newSize),
+ cells(NULL),
+ currentFormat(r_Array),
+ dataFormat(dataformat)
+ {
+ RMDBGENTER(3, RMDebug::module_blobif, "DBTile", "DBTile(" << newSize << ", '(int)" << (int) c << "', " << dataFormat << ")");
+
+ TALK( "DBTile::DBTile() allocating " << newSize << " bytes for blob cells, previous ptr was " << (long) cells );
+ cells = (char*)mymalloc(newSize * sizeof(char));
+ objecttype = OId::INVALID;
+ memset(cells, c, size);
+
+ RMDBGEXIT(3, RMDebug::module_blobif, "DBTile", "DBTile(" << newSize << ", '(int)" << (int) c << "', " << dataFormat << ") " << myOId);
+ }
+
+DBTile::DBTile(r_Bytes newSize, r_Bytes patSize, const char* pat, r_Data_Format dataformat)
+ : DBObject(),
+ size(newSize),
+ cells(NULL),
+ currentFormat(r_Array),
+ dataFormat(dataformat)
+ {
+ RMDBGENTER(3, RMDebug::module_blobif, "DBTile", "DBTile(" << newSize << ", " << patSize << ", pattern, " << dataFormat << ")");
+ objecttype = OId::INVALID;
+
+ TALK( "DBTile::DBTile() allocating " << newSize << " bytes for blob cells, previous ptr was " << (long) cells );
+ cells = (char*)mymalloc(newSize * sizeof(char));
+
+ r_Bytes i = 0;
+ r_Bytes j = 0;
+
+ if (patSize >= size)
+ {
+ // fill cells with pattern
+ for (j = 0; j < size; j++)
+ {
+ cells[j] = pat[j];
+ }
+ }
+ else {
+ if (patSize >= 0)
+ {
+ // fill cells with repeated pattern
+ for (i = 0; i < size; i += patSize)
+ {
+ for (j = 0; j < patSize; j++)
+ {
+ cells[(i+j)]= pat[j];
+ }
+ }
+ // pad end with 0
+ if (i != size)
+ {
+ // no padding necessary
+ i -= patSize;
+ for (; i < size; i++)
+ {
+ cells[i]=0;
+ }
+ }
+ }
+ else {
+ // fill cells with 0
+ for (i = 0; i < size; i++)
+ {
+ cells[i] = 0;
+ }
+ }
+ }
+
+ RMDBGEXIT(3, RMDebug::module_blobif, "DBTile", "DBTile(" << newSize << ", " << patSize << ", pattern, " << dataFormat << ") " << myOId);
+ }
+
+DBTile::DBTile(r_Bytes newSize, const char* newCells, r_Data_Format dataformat)
+ : DBObject(),
+ size(newSize),
+ cells(0),
+ dataFormat(dataformat),
+ currentFormat(r_Array)
+ {
+ RMDBGENTER(3, RMDebug::module_blobif, "DBTile", "DBTile(" << size << ", data, " << dataFormat << ")");
+
+ TALK( "DBTile::DBTile() allocating " << newSize << " bytes for blob cells, previous ptr was " << (long) cells );
+
+ cells = (char*)mymalloc(size * sizeof(char));
+ objecttype = OId::INVALID;
+ memcpy(cells, newCells, newSize);
+
+ RMDBGEXIT(3, RMDebug::module_blobif, "DBTile", "DBTile(" << size << ", data, " << dataFormat << ") " << myOId);
+ }
+
+DBTile::DBTile(const OId& id) throw (r_Error)
+ : DBObject(id),
+ size(0),
+ cells(NULL),
+ currentFormat(r_Array)
+ {
+ RMDBGONCE(3, RMDebug::module_blobif, "DBTile", "DBTile(" << id <<")");
+ }
+
+DBTile::~DBTile()
+ {
+ RMDBGENTER(3, RMDebug::module_blobif, "DBTile", "~DBTile() " << myOId);
+ if (cells)
+ {
+ TALK( "DBTile::~DBTile() freeing blob cells" );
+ free(cells);
+ }
+ cells = NULL;
+ RMDBGEXIT(3, RMDebug::module_blobif, "DBTile", "~DBTile() " << myOId);
+ }
+
+void
+DBTile::resize(r_Bytes newSize)
+ {
+ RMDBGONCE(3, RMDebug::module_blobif, "DBTile", "resize(" << newSize << ") " << myOId);
+ if (size != newSize)
+ {
+ setModified();
+ if (cells)
+ {
+ TALK( "DBTile::resize() freeing blob cells" );
+ free(cells);
+ // cells = NULL; // added PB 2005-jan-10
+ }
+ TALK( "DBTile::resize() allocating " << newSize << " bytes for blob cells, previous ptr was " << (long) cells );
+ cells = (char*)mymalloc(newSize * sizeof(char));
+ size = newSize;
+ }
+ }
+
+void
+DBTile::printStatus(unsigned int level, std::ostream& stream) const
+ {
+ DBObject::printStatus(level, stream);
+ stream << " r_Data_Format " << dataFormat << " size " << size << " ";
+ RMDBGIF(20, RMDebug::module_blobif, "DBTile", for (int a = 0; a < size; a++)\
+ stream << " " << (int)(cells[a]); stream << endl;)
+ }
+
+std::ostream&
+operator << (std::ostream& stream, DBTile& b)
+ {
+ stream << "\tDBTile at " << &b << endl;
+ stream << "\t\tOId\t\t:" << b.myOId << endl;
+ stream << "\t\tId\t\t:" << b.myOId.getCounter() << endl;
+ stream << "\t\tSize\t\t:" << b.size << endl;
+ stream << "\t\tModified\t:" << (int)b._isModified << endl;
+ stream << "\t\tCells\t\t:";
+ RMDBGIF(20, RMDebug::module_blobif, "DBTile", for (int a = 0; a < b.size; a++)\
+ stream << " " << (int)(b.cells[a]); stream << endl;)
+ return stream;
+ }
+
diff --git a/relblobif/dbtile.hh b/relblobif/dbtile.hh
new file mode 100644
index 0000000..d95d86b
--- /dev/null
+++ b/relblobif/dbtile.hh
@@ -0,0 +1,222 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#ifndef _DBTILE_HH_
+#define _DBTILE_HH_
+
+// -*-C++-*- (for Emacs)
+
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+class OId;
+class r_Error;
+#include "reladminif/dbobject.hh"
+#include "raslib/mddtypes.hh"
+#include "tileid.hh"
+#include "relindexif/indexid.hh"
+
+//@ManMemo: Module: {\bf reldbif}.
+
+/*@Doc:
+This class is used in tilemgr as an interface to the persistent tiles. There are subclasses of dbtile which store themselves differently. This class can also be used to get rid of tilemgr/TransTile. When no persistent tile is needed then a dbtile and not a blobtile/inlinetile can be used.
+*/
+
+
+class DBTile : public DBObject
+ {
+ public:
+ friend std::ostream& operator << (std::ostream& stream, DBTile& b);
+ /*@Doc:
+ prints info about the dbtile (flags, id, dbdata, size, modified)
+ */
+ //@Man: read methods
+ //@{
+ /// get contents as array of chars for read access.
+ char* getCells();
+ /*@Doc:
+ Returns a pointer to the contents of the DBTile. This pointer
+ can be used as a char array with getSize() elements.
+ Retriving the contents with this method will mark this object dirty.
+ */
+
+ /// get contents as array of chars for read access.
+ const char* getCells() const;
+ /*@Doc:
+ Returns a pointer to the contents of the DBTile. This pointer
+ can be used as a char array with getSize() elements.
+ */
+
+ /// get one char in the contents of the DBTile.
+ char getCell(r_Bytes index) const;
+ /*@Doc:
+ Returns a copy of the char. This functions function should usually
+ not be used because of performance considerations.
+ */
+
+ r_Data_Format getDataFormat() const;
+ /*@Doc:
+ Returns the Data Format of this tile (r_Tiff, r_Array, ...)
+ */
+
+ r_Data_Format getCurrentFormat() const;
+ /*@Doc:
+ Returns the Data Format of the tiles contents (r_Tiff, r_Array, ...)
+ */
+
+ void setDataFormat(const r_Data_Format& dataformat);
+ /*@Doc:
+ Sets the Data Format of this tile (r_Tiff, r_Array, ...)
+ This method will mark this object dirty.
+ */
+
+ void setCurrentFormat(const r_Data_Format& dataformat) const;
+ /*@Doc:
+ Sets the Data Format of the contents of this tile (r_Array, or the compressed stuff)
+ This method will _not_ mark this object dirty.
+ */
+
+ /// get size of contents of DBTile in chars.
+ r_Bytes getSize() const;
+ /*@Doc:
+ Returns the size of this Tile in bytes.
+ */
+ //@}
+
+ //@Man: write methods
+ //@{
+ /// change one char in the contents of the DBTile.
+ void setCell(r_Bytes index, char newCell);
+ /*@Doc:
+ Usually modifications should be done directly on the char array
+ returned by getCells() because of much better performance.
+ This method will mark this object dirty.
+ */
+
+ void setCells(char* newCells);
+ /*@Doc:
+ Completely replaces the character array of this tile.
+ The old arry is deleted.
+ Modification is set to dirty.
+ */
+
+ //@}
+
+ //@Man: constructors
+ //@{
+ DBTile(r_Data_Format dataformat = r_Array);
+ /*@Doc:
+ constructs a new empty DBTile. Length is 0.
+ */
+
+ DBTile(const OId& BlobId) throw (r_Error);
+ /*@Doc:
+ Passes to DBObject.
+ */
+
+ DBTile(r_Bytes newSize, char c = 0, r_Data_Format dataformat = r_Array);
+ /*@Doc:
+ constructs a new DBTile of size newSize filled with c.
+ */
+
+ DBTile(r_Bytes newSize, r_Bytes patSize, const char* pat, r_Data_Format dataformat = r_Array);
+ /*@Doc:
+ Constructs a new DB Tile of size newSize filled with the repeated
+ char array pat of size patSize. If after filling some chars are
+ left, they are filled with 0
+ */
+ /*@ManMemo: constructs a new DB Tile with the char array newCells
+ with newSize elements as contents. */
+
+ DBTile(r_Bytes newSize, const char* newCells, r_Data_Format dataformat = r_Array);
+ /*@Doc:
+ constructs a new DBTile of size newSize filled with the contents of newCells.
+ the newCells are copied.
+ */
+ //@}
+
+ virtual ~DBTile();
+ /*@Doc:
+ validates the object. deletes it cells.
+ */
+
+ void resize(r_Bytes newSize);
+ /*@Doc:
+ resize DBTile. previous contents are lost.
+ */
+
+ virtual r_Bytes getMemorySize() const;
+ /*@Doc:
+ returns the space taken up by this object in memory:
+ size * sizeof(char) + sizeof(char*) +
+ DBObject::getMemorySize() + sizeof(r_Data_Format) + sizeof(r_Bytes)
+ */
+
+ virtual void printStatus(unsigned int level = 0, std::ostream& stream = std::cout) const;
+ /*@Doc:
+ prints the status of DBObject, the dataformat, the size and the contents as (int)
+ */
+
+ void setNoModificationData(char* data) const;
+ /*@Doc:
+ Completely replaces the array.
+ The object will not be marked dirty.
+ This is used for transparent compression/decompression.
+ */
+
+ void setNoModificationSize(r_Bytes newSize) const;
+ /*@Doc:
+ Sets the size of this tile.
+ The object will not be marked dirty.
+ This is used for transparent compression/decompression.
+ */
+
+ protected:
+ mutable r_Bytes size;
+ /*@Doc:
+ total size of the contents of DBTile in number of chars.
+ */
+
+ mutable char* cells;
+ /*@Doc:
+ the data is allocated by malloc
+ */
+
+ r_Data_Format dataFormat;
+ /*@Doc:
+ data format to construct a PersTile
+ */
+
+ mutable r_Data_Format currentFormat;
+ /*@Doc:
+ the current format of the contents. This is neccessary to know when getting mixed up compressed contents.
+ */
+ };
+
+#endif
diff --git a/relblobif/filestorageexception.hh b/relblobif/filestorageexception.hh
new file mode 100644
index 0000000..b39cb69
--- /dev/null
+++ b/relblobif/filestorageexception.hh
@@ -0,0 +1,42 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * The interface used by the file storage modules.
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#ifndef _FILESTORAGEEXCEPTION_HH_
+#define _FILESTORAGEEXCEPTION_HH_
+
+class FileStorageException
+{
+
+}; // class FileStorageException
+
+#endif // _FILESTORAGEEXCEPTION_HH_
diff --git a/relblobif/ifilestorage.hh b/relblobif/ifilestorage.hh
new file mode 100644
index 0000000..1a3cb69
--- /dev/null
+++ b/relblobif/ifilestorage.hh
@@ -0,0 +1,56 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * The interface used by the file storage modules.
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#ifndef _IFILESTORAGE_H__
+#define _IFILESTORAGE_H__
+
+#include "raslib/error.hh"
+class OId;
+
+// The class is the interface for the file storage modules.
+class IFileStorage
+{
+ public:
+ // Update the content of a blob. The blob should exist already.
+ virtual void update(const char* data, r_Bytes size, int BlobId) throw (r_Error) = 0;
+ // Store the content of a new blob.
+ virtual void insert(const char* data, r_Bytes size, int BlobId) throw (r_Error) = 0;
+ // Retrive the content of a previously stored blob
+ virtual void retrieve(int BlobId, char** data, r_Bytes *size) throw (r_Error) = 0;
+ // Delete a previously stored blob.
+ virtual void remove(int BlobId) throw (r_Error) = 0;
+
+ //virtual ~IFileStorage() = 0;
+}; // class IFileStorage
+
+#endif // _IFILESTORAGE_H__
diff --git a/relblobif/inlinetile.cc b/relblobif/inlinetile.cc
new file mode 100644
index 0000000..bfff1ca
--- /dev/null
+++ b/relblobif/inlinetile.cc
@@ -0,0 +1,259 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include "mymalloc/mymalloc.h"
+// This is -*- C++ -*-
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+
+ *
+ * COMMENTS:
+ * uses embedded SQL
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)blobif,BLOBTile: $Id: inlinetile.cc,v 1.5 2002/06/15 16:47:29 coman Exp $";
+
+#include <iostream>
+
+#include "inlinetile.hh"
+#include "raslib/rmdebug.hh"
+#include "reladminif/externs.h"
+#include "raslib/error.hh"
+#include "reladminif/objectbroker.hh"
+#include "blobtile.hh"
+#include "relindexif/dbtcindex.hh"
+#include "reladminif/dbref.hh"
+#include "storagemgr/sstoragelayout.hh"
+
+#include <cstring>
+
+InlineTile::InlineTile(r_Data_Format dataformat)
+ : BLOBTile(dataformat)
+ {
+ RMDBGONCE(3, RMDebug::module_blobif, "InlineTile", "InlineTile()");
+ objecttype = OId::INLINETILEOID;
+ }
+
+InlineTile::InlineTile(r_Bytes newSize, char c, r_Data_Format dataformat)
+ : BLOBTile(newSize, c, dataformat)
+ {
+ RMDBGONCE(3, RMDebug::module_blobif, "InlineTile", "InlineTile(" << newSize << ", data)");
+ objecttype = OId::INLINETILEOID;
+ }
+
+InlineTile::InlineTile(r_Bytes newSize, r_Bytes patSize, const char* pat, r_Data_Format dataformat)
+ : BLOBTile(newSize, patSize, pat, dataformat)
+ {
+ RMDBGONCE(3, RMDebug::module_blobif, "InlineTile", "InlineTile(" << newSize << ", " << patSize << ", pattern)");
+ objecttype = OId::INLINETILEOID;
+ }
+
+InlineTile::InlineTile(r_Bytes newSize, const char* newCells, r_Data_Format dataformat)
+ : BLOBTile(newSize, newCells, dataformat)
+ {
+ RMDBGONCE(3, RMDebug::module_blobif, "InlineTile", "InlineTile(" << size << ", data)");
+ objecttype = OId::INLINETILEOID;
+ }
+
+InlineTile::InlineTile(const OId& id) throw (r_Error)
+ : BLOBTile(id)
+ {
+ RMDBGONCE(5, RMDebug::module_blobif, "InlineTile", "InlineTile(" << id <<")");
+ objecttype = OId::INLINETILEOID;
+ }
+
+InlineTile::InlineTile(const OId& id, char*& thecells)
+ : BLOBTile(r_Array)
+ {
+ RMDBGENTER(5, RMDebug::module_blobif, "InlineTile", "InlineTile(" << id << ", cells " << (r_Ptr)thecells << ")");
+ objecttype = OId::INLINETILEOID;
+ myIndexOId = id;
+
+ //restore the size of the blob
+ memcpy(&size, thecells, sizeof(r_Bytes));
+ thecells = thecells + sizeof(r_Bytes);
+
+ //restore the dataformat
+ memcpy(&dataFormat, thecells, sizeof(r_Data_Format));
+ thecells = thecells + sizeof(r_Data_Format);
+
+ //restore my own oid
+ memcpy(&myOId, thecells, sizeof(OId));
+ thecells = thecells + sizeof(OId);
+
+ //restore the cells
+ cells = (char*)mymalloc(size * sizeof(char));
+ memcpy(cells, thecells, size);
+ thecells = thecells + size;
+ RMDBGMIDDLE(5, RMDebug::module_blobif, "InlineTile", "OId " << myOId << " size " << size << " DataFormat " << dataFormat);
+
+ DBObject::readFromDb();
+ _isInDatabase = false;
+ ObjectBroker::registerDBObject(this);
+ RMDBGEXIT(5, RMDebug::module_blobif, "InlineTile", "InlineTile(" << id << ", cells " << (r_Ptr)thecells << ") " << myOId);
+ }
+
+void
+InlineTile::printStatus(unsigned int level, std::ostream& stream) const
+ {
+ char* indent = new char[level*2 +1];
+ for (unsigned int j = 0; j < level*2 ; j++)
+ indent[j] = ' ';
+ indent[level*2] = '\0';
+
+ stream << indent << "InlineTile ";
+ if (isInlined())
+ stream << "is Inlined at " << myIndexOId << endl;
+ else
+ stream << "is not Inlined " << endl;
+ BLOBTile::printStatus(level + 1, stream);
+ delete[] indent;
+ }
+
+void
+InlineTile::destroy()
+ {
+ if (isCached())
+ return;
+ else
+ DBObject::destroy();
+ }
+
+bool
+InlineTile::isCached() const
+ {
+ char retval = true;
+ //not previously cached
+ if (!_isCached)
+ if (!isInlined())
+ {//outlined
+ if (getSize() > StorageLayout::DefaultMinimalTileSize)//size is ok
+ retval = false;
+ }
+ else {//inlined
+ if (getSize() < StorageLayout::DefaultPCTMax)//size is ok
+ retval = false;
+ }
+ return retval;
+ }
+
+void
+InlineTile::setModified() throw(r_Error)
+ {
+ RMDBGENTER(4, RMDebug::module_blobif, "InlineTile", "setModified() " << myOId);
+ DBObject::setModified();
+ if (isInlined())
+ {
+ RMDBGMIDDLE(4, RMDebug::module_blobif, "InlineTile", " index will be modified");
+ DBTCIndexId t(myIndexOId);
+ t->setInlineTileHasChanged();
+ }
+ else {
+ RMDBGMIDDLE(4, RMDebug::module_blobif, "InlineTile", "index will not be modified");
+ }
+ RMDBGEXIT(4, RMDebug::module_blobif, "InlineTile", "setModified() " << myOId);
+ }
+
+const OId&
+InlineTile::getIndexOId() const
+ {
+ return myIndexOId;
+ }
+
+void
+InlineTile::setIndexOId(const OId& oid)
+ {
+ myIndexOId = oid;
+ }
+
+r_Bytes
+InlineTile::getStorageSize() const
+ {
+ return size + sizeof(r_Bytes) + sizeof(r_Data_Format) + sizeof(OId);
+ }
+
+void
+InlineTile::outlineTile()
+ {
+ DBTCIndexId t(myIndexOId);
+ t->removeInlineTile(this);
+ setIndexOId(OId(0, OId::INVALID));
+ _isInDatabase = false;
+ _isModified = true;
+ }
+
+void
+InlineTile::inlineTile(const OId& ixId)
+ {
+ setIndexOId(ixId);
+ DBTCIndexId t(myIndexOId);
+ t->addInlineTile(this);
+ if (_isInDatabase)
+ {
+ bool pers = _isPersistent;
+ bool modi = _isModified;
+ BLOBTile::deleteFromDb();
+ _isPersistent = pers;
+ _isModified = modi;
+ }
+ }
+
+bool
+InlineTile::isInlined() const
+ {
+ return (myIndexOId.getType() == OId::DBTCINDEXOID);
+ }
+
+char*
+InlineTile::insertInMemBlock(char* thecontents)
+ {
+ RMDBGENTER(5, RMDebug::module_blobif, "InlineTile", "insertInMemBlock(" << (void*)thecontents << ")");
+ //store size of blob
+ memcpy(thecontents, &size, sizeof(r_Bytes));
+ thecontents = thecontents + sizeof(r_Bytes);
+
+ //store the dataformat
+ memcpy(thecontents, &dataFormat, sizeof(r_Data_Format));
+ thecontents = thecontents + sizeof(r_Data_Format);
+
+ //store my own oid
+ memcpy(thecontents, &myOId, sizeof(OId));
+ thecontents = thecontents + sizeof(OId);
+
+ //store the blob
+ memcpy(thecontents, cells, size * sizeof(char));
+ thecontents = thecontents + size * sizeof(char);
+ RMDBGMIDDLE(5, RMDebug::module_blobif, "InlineTile", "OId " << myOId << " size " << size << " DataFormat " << dataFormat);
+ RMDBGIF(20, RMDebug::module_blobif, "InlineTile", for (int i = 0; i < size; i++) RMInit::dbgOut << (unsigned int)(cells[i]) << " "; RMInit::dbgOut << endl;)
+ DBObject::updateInDb();
+ RMDBGEXIT(5, RMDebug::module_blobif, "InlineTile", "insertInMemBlock(" << (void*)thecontents << ")");
+ return thecontents;
+ }
+
+InlineTile::~InlineTile()
+ {
+ }
+
diff --git a/relblobif/inlinetile.hh b/relblobif/inlinetile.hh
new file mode 100644
index 0000000..0e833f2
--- /dev/null
+++ b/relblobif/inlinetile.hh
@@ -0,0 +1,176 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#ifndef _INLINETILE_HH_
+#define _INLINETILE_HH_
+// -*-C++-*- (for Emacs)
+
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * The inlinetile class is used to store small tiles efficiently.
+ * Potentially many inlinetiles are grouped together in a blob and
+ * stored in the database. highly dependend on DBTCIndex.
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+class OId;
+class r_Error;
+
+#include "raslib/mddtypes.hh"
+#include "tileid.hh"
+#include "blobtile.hh"
+
+//@ManMemo: Module: {\bf relblobif}.
+
+/*@Doc:
+
+InlineTile is the persistent class for storing the contents of MDD tiles
+in the database. it can be stored as a blobtile or inlined:
+in inlined mode multiple inlinetiles are stored as one blob in the database.
+memory management and modification management is critical.
+there are special functions in objectbroker to retrieve inlinetiles.
+they can only be inlined by a dbtcindex.
+
+*/
+
+
+class InlineTile : public BLOBTile
+ {
+ public:
+
+ //@Man: constructors
+ //@{
+ InlineTile(const OId& id, char*& thecells);
+ /*@Doc:
+ construct a new inline tile with the oid of
+ the dbtilecontainerindex and the array which
+ holds the contents of the tile.
+ thecells will be automagically forwarded to the beginning of the next inline tile.
+ */
+
+ InlineTile(r_Data_Format dataformat = r_Array);
+ /*@Doc:
+ constructs a new empty InlineTile and gets an id for it.
+ */
+
+ InlineTile(const OId& BlobId) throw (r_Error);
+ /*@Doc:
+ constructs a InlineTile out of the database
+ */
+
+ InlineTile(r_Bytes newSize, char c = 0, r_Data_Format dataformat = r_Array);
+ /*@Doc:
+ constructs a new InlineTile of size newSize filled with c.
+ */
+
+ InlineTile(r_Bytes newSize, r_Bytes patSize, const char* pat, r_Data_Format dataformat = r_Array);
+ /*@Doc:
+ Constructs a new InlineTile of size newSize filled with the repeated
+ char array pat of size patSize. If after filling some chars are
+ left, they are filled with 0
+ */
+ /*@ManMemo: constructs a new InlineTile with the char array newCells
+ with newSize elements as contents. */
+
+ InlineTile(r_Bytes newSize, const char* newCells, r_Data_Format dataformat = r_Array);
+ /*@Doc:
+ constructs a new InlineTile of size newSize filled with the contents of newCells.
+ */
+
+ //@}
+ virtual void destroy();
+ /*@Doc:
+ may not destroy the object because it is inlined and therefore depending on its parent index.
+ */
+
+ const OId& getIndexOId() const;
+ /*@Doc:
+ returns the oid of the index which contains the inlined tile. if the tile is outlined then this oid is invalid.
+ */
+
+ void setIndexOId(const OId& oid);
+ /*@Doc:
+ make the inlinetile use this index as its parent and storage structure.
+ */
+
+ r_Bytes getStorageSize() const;
+ /*@Doc:
+ returns the size this tile will consume in as an inlined array.
+ */
+
+ virtual char* insertInMemBlock(char* test);
+ /*@Doc:
+ inserts the Blob into the char.
+ the returned pointer is after the end of this tiles data.
+ */
+
+ virtual void setModified() throw(r_Error);
+ /*@Doc:
+ does not only set itself modified but also informs its parent of changes.
+ */
+
+ virtual bool isCached() const;
+ /*@Doc:
+ returns true if it is inlined.
+ */
+
+ virtual void inlineTile(const OId& ixOId);
+ /*@Doc:
+ do everything so that this tile is inlined and uses ixOId as its index parent.
+ it will not check if this tile is already inlined.
+ */
+
+ virtual void outlineTile();
+ /*@Doc:
+ does everything necessary to act as a blobtile:
+ remove it from the index parent.
+ */
+
+ virtual bool isInlined() const;
+ /*@Doc:
+ checks if it has a valid index parent.
+ */
+
+ virtual ~InlineTile();
+ /*@Doc:
+ no functionality. if it is inlined the dbtcindex will take care of storing it.
+ if it is not inlined the blobtile functionality will take over.
+ */
+
+ virtual void printStatus(unsigned int level = 0, std::ostream& stream = std::cout) const;
+
+ protected:
+
+ OId myIndexOId;
+ /*@Doc:
+ when this inlinetile is in inlined mode the myIndexOId points to the parent index.
+ if this oid is invalid the inlinetile is not in inline mode.
+ */
+
+ };
+
+#endif
diff --git a/relblobif/simplefilestorage.cc b/relblobif/simplefilestorage.cc
new file mode 100644
index 0000000..02548bc
--- /dev/null
+++ b/relblobif/simplefilestorage.cc
@@ -0,0 +1,178 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * The interface used by the file storage modules.
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include "raslib/rminit.hh"
+#include "../reladminif/oidif.hh"
+#include "simplefilestorage.hh"
+#include "debug-srv.hh"
+
+using namespace std;
+
+SimpleFileStorage::~SimpleFileStorage()
+{
+}
+
+SimpleFileStorage::SimpleFileStorage(const string& path) throw (r_Error) : root_path(path)
+{
+ // Check if the path exist is readable/writable etc.
+ struct stat status;
+ if (stat(path.c_str(), &status)<0 || !S_ISDIR(status.st_mode)) {
+ throw 1; // Root directory not found
+ }
+ TALK("SimpleFileStorage initialized on root path" << path);
+}
+
+void SimpleFileStorage::insert(const char* data, r_Bytes size, int BlobId) throw (r_Error)
+{
+ ENTER("SimpleFileStorage::insert with BlobID="<<BlobId);
+ vector<string> path;
+ getPath(BlobId, &path);
+ string file_path = path[0]; // Root path
+ // Iterate trough the levels and create all directories needed.
+ for (int i = 1; i < path.size() - 1; ++i)
+ {
+ file_path += '/' + path[i];
+ struct stat status;
+ if (!stat(file_path.c_str(), &status))
+ if (!mkdir(file_path.c_str(), 0770))
+ throw 2; // Cannot create directory
+ }
+ file_path += '/' + path[path.size() - 1];
+ int fd = open(file_path.c_str(), O_CREAT | O_WRONLY, 0770);
+ if (fd < 0)
+ throw 3; // Cannot create file
+ int offset = 0;
+ // Send the data to the disk
+ while (offset < size) {
+ int count = write(fd, data + offset, size - offset);
+ if (count == -1)
+ throw 4; // Error while writing data to the disk
+ offset += count;
+ }
+ if (close(fd)<0)
+ throw 4; // Error while writing data to the disk
+ LEAVE("SimpleFileStorage::insert");
+}
+
+void SimpleFileStorage::update(const char* data, r_Bytes size, int BlobId) throw (r_Error)
+{
+ ENTER("SimpleFileStorage::update");
+ vector<string> path;
+ getPath(BlobId, &path);
+ string file_path = path[0]; // Root path
+ // Iterate trough the levels and create all directories needed.
+ for (int i = 1; i < path.size() - 1; ++i)
+ {
+ file_path += '/' + path[i];
+ struct stat status;
+ if (!stat(file_path.c_str(), &status))
+ if (!mkdir(file_path.c_str(), 0770))
+ throw 2; // Cannot create directory
+ }
+ file_path += '/' + path[path.size() - 1];
+
+ int fd = open(file_path.c_str(), O_WRONLY | O_CREAT | O_TRUNC);
+ if (fd < 0)
+ throw 6; // Cannot open file
+ int offset = 0;
+ // Send the data to the disk
+ while (offset < size) {
+ int count = write(fd, data + offset, size - offset);
+ if (count == -1)
+ throw 4; // Error while writing data to the disk
+ offset += count;
+ }
+ if (close(fd)<0)
+ throw 4; // Error while writing data to the disk
+ LEAVE("SimpleFileStorage::update");
+}
+
+void SimpleFileStorage::retrieve(int BlobId, char** data, r_Bytes* size) throw (r_Error)
+{
+ ENTER("SimpleFileStorage::read");
+ string path;
+ getPath(BlobId, &path);
+ struct stat status;
+ if (stat(path.c_str(), &status) < 0)
+ throw 5; // File does not exist, the blob does not exist.
+
+ *size = status.st_size;
+ *data = (char*)malloc(status.st_size);
+
+ int fd = open(path.c_str(), O_RDONLY);
+ if (fd < 0)
+ throw 6; // Cannot open file
+ int offset = 0;
+ // Send the data to the disk
+ while (offset < *size) {
+ int count = read(fd, *data + offset, *size - offset);
+ if (count == -1)
+ throw 7; // Error while reading data from the disk
+ offset += count;
+ }
+ if (close(fd) < 0)
+ throw 7; // Error while reading data from the disk
+ LEAVE("SimpleFileStorage::read");
+}
+
+void SimpleFileStorage::remove(int BlobId) throw (r_Error)
+{
+ ENTER("SimpleFileStorage::remove");
+ string path;
+ getPath(BlobId, &path);
+ if (unlink(path.c_str()) < 0)
+ throw 8; // Error while removing the file
+ LEAVE("SimpleFileStorage::remove");
+}
+
+void SimpleFileStorage::getPath(int BlobId, vector<string> *path) {
+ ENTER("SimpleFileStorage::getPath");
+ path->clear();
+ path->push_back(root_path);
+ stringstream aux;
+ aux << BlobId;
+ path->push_back(aux.str());
+ LEAVE("SimpleFileStorage::getPath");
+}
+
+void SimpleFileStorage::getPath(int BlobId, string *path) {
+ vector<string> segments;
+ getPath(BlobId, &segments);
+ *path = segments[0];
+ for (int i = 1; i < segments.size(); ++i)
+ *path += '/' + segments[i];
+}
diff --git a/relblobif/simplefilestorage.hh b/relblobif/simplefilestorage.hh
new file mode 100644
index 0000000..7978486
--- /dev/null
+++ b/relblobif/simplefilestorage.hh
@@ -0,0 +1,66 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * The interface used by the file storage modules.
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#ifndef _SIMPLEFILESTORAGE_HH_
+#define _SIMPLEFILESTORAGE_HH_
+
+#include <vector>
+#include <string>
+#include "ifilestorage.hh"
+
+class SimpleFileStorage : public IFileStorage
+{
+ public:
+ SimpleFileStorage(const std::string& storage_path) throw (r_Error);
+ // Update the content of a blob. The blob should exist already.
+ void update(const char* data, r_Bytes size, int BlobId) throw (r_Error);
+ // Store the content of a new blob.
+ virtual void insert(const char* data, r_Bytes size, int BlobId) throw (r_Error);
+ // Retrive the content of a previously stored blob
+ virtual void retrieve(int BlobId, char** data, r_Bytes* size) throw (r_Error);
+ // Delete a previously stored blob.
+ virtual void remove(int BlobId) throw (r_Error);
+
+ virtual ~SimpleFileStorage();
+ private:
+ // Given on BlobId will return the path where the blob should be stored.
+ // It's returned as a vector so that other functions can iterate trough it and check
+ // or create the directories on each level.
+ void getPath(int BlobId, std::vector<std::string>* path);
+ // Similar to the one above but returns the agregated path
+ void getPath(int BlobId, std::string* path);
+ std::string root_path;
+
+}; // class SimpleFileStorage
+
+#endif // _SIMPLEFILESTORAGE_HH_
diff --git a/relblobif/test/Makefile b/relblobif/test/Makefile
new file mode 100644
index 0000000..fe98b32
--- /dev/null
+++ b/relblobif/test/Makefile
@@ -0,0 +1,65 @@
+# -*-Makefile-*-
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>. # Top Level makefile. This points to the various modules that have to be build
+# and/or deployed
+#
+#
+# MAKEFILE FOR:
+# test programs of module relblobif
+#
+# COMMENTS:
+# List environment dependencies, known bugs, specialities etc.
+#
+##################################################################
+######################### Definitions ############################
+
+LDFLAGS += $(L_SYM)$(RMANHOME)/lib $(LIBAKINSIDE) $(RMANBASE)/mymalloc/mymalloc_cln.o -lcrypt
+
+# source files
+CPPSOURCES = updateblob.c deleteblob.c createtable.c droptable.c insertblob.c readblob.c r.c r2.c # copytile.c
+
+# all test programs
+ALLTESTS = ${CPPSOURCES:%.c=%}
+
+# object files
+OBJS = ${CPPSOURCES:%.c=%.o}
+
+NEEDSTL =
+
+# Needed rasdaman libraries for linking. To be completed.
+#NEEDEDLIBS = $(QLPARSER) $(RELBLOBIF) $(RELADMINIF) $(RASLIB) $(RELCATALOGIF) $(RELMDDIF) $(RASLIB) $(CACHETAMGR) $(RELINDEXIF) $(CACHETAMGR) $(RASQL) $(QLPARSER)
+
+MISCCLEAN = core client.bm client.dbg client.log ir.out
+
+########################### Targets ##############################
+
+# make all tests
+.PHONY: test
+test: $(ALLTESTS)
+
+########################### Dependencies #########################
+
+blobdump: blobdump.o
+ $(CXX) -o $@ $^ $(LDFLAGS) $(BASEDBLDFLAGS) $(L_SYM)$(PGSQL_ROOT)/lib $(l_SYM)ecpg
+blobdump.o: blobdump.c
+blobdump.c: blobdump.pgc
+
diff --git a/relblobif/test/README.txt b/relblobif/test/README.txt
new file mode 100644
index 0000000..ea20ca4
--- /dev/null
+++ b/relblobif/test/README.txt
@@ -0,0 +1,5 @@
+relblobif/test:
+
+Strictly speaking these are not rasdaman tests, they do not contribute to systemtest.
+Rather they allow to test a DBMS for how it behaves wrt. long fields (char, varchar, blobs) if attacked with binary contents.
+
diff --git a/relblobif/test/blobdump.c b/relblobif/test/blobdump.c
new file mode 100644
index 0000000..bc2f44f
--- /dev/null
+++ b/relblobif/test/blobdump.c
@@ -0,0 +1,323 @@
+#include "mymalloc/mymalloc.h"
+/* Processed by ecpg (3.1.1) */
+/* These include files are added by the preprocessor */
+#include <ecpgtype.h>
+#include <ecpglib.h>
+#include <ecpgerrno.h>
+#include <sqlca.h>
+#line 1 "blobdump.pgc"
+/* End of automatic include section */
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * dump RAS_TILES blob table.
+ * Depending on parameters, either a particular tuple is printed
+ * or the whole table. Optionally also the blob is dumped in hex.
+ * Parameters: see usage().
+ *
+ *
+ * COMMENTS:
+ * - assumes RAS_TILES
+ *
+ ************************************************************/
+
+using namespace std;
+
+#include <iostream>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h> /* getopt */
+
+#include <sqlca.h>
+
+// SQL error codes:
+#include "externs.h"
+
+// PG stuff
+#include "libpq-fe.h" // C interface to PgSQL
+#include "libpq/libpq-fs.h" /* large object (lo) api */
+// libq-style connection ptr taken from ECPG connect (needed for libq functions):
+// (currently used by relblobif/blobtile.pgc)
+PGconn *pgConn = NULL;
+PGresult *pgResult = NULL;
+
+#define RC_OK 0
+#define RC_ERROR -1
+
+#define QUERYSIZE 2000
+static char pgQuery[QUERYSIZE];
+
+void exitNicely()
+{
+ PQclear( pgResult );
+ (void) PQexec( pgConn, "ROLLBACK WORK" );
+ PQfinish( pgConn );
+ exit( RC_ERROR );
+}
+
+
+void
+disconnect()
+{
+ pgResult = PQexec( pgConn, "ROLLBACK WORK" );
+ if (PQresultStatus(pgResult) != PGRES_COMMAND_OK)
+ {
+ cerr << "error during disconnect: " << PQerrorMessage(pgConn) << endl << flush;
+ PQclear( pgResult );
+ exit( RC_ERROR );
+ }
+ PQclear( pgResult );
+
+ PQfinish( pgConn );
+ pgConn = NULL;
+}
+
+void
+connect( const char * db )
+{
+ char pgConnInfo[200];
+
+ (void) snprintf( pgConnInfo, (size_t) sizeof(pgConnInfo), "dbname = %s", db );
+ pgConn = PQconnectdb( pgConnInfo );
+ if (PQstatus(pgConn) != CONNECTION_OK)
+ {
+ cerr << "error during connect: " << PQerrorMessage(pgConn) << endl << flush;
+ exitNicely();
+ }
+
+ pgResult = PQexec( pgConn, "BEGIN TRANSACTION" );
+ if (PQresultStatus(pgResult) != PGRES_COMMAND_OK)
+ {
+ cerr << "error during being ta: " << PQerrorMessage(pgConn) << endl << flush;
+ PQclear( pgResult );
+ exit( RC_ERROR );
+ }
+ PQclear( pgResult );
+
+}
+
+// read one tuple from ras_tiles, identified by myOId, and display it (with contents if withDump==true)
+void
+readFromDb( long myOId, bool withDump )
+{
+ unsigned int blobOid = 0;
+ short dataFormat = 0;
+ unsigned long size = 0;
+ char *cells = NULL;
+
+ // (1) --- access tuple
+ int result = snprintf( pgQuery, (size_t) sizeof(pgQuery), "SELECT Tile, DataFormat FROM RAS_TILES WHERE BlobId = %d", myOId );
+
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_TUPLES_OK)
+ {
+ cerr << "error during 'select': " << PQerrorMessage(pgConn) << endl << flush;
+ exitNicely();
+ }
+ else if (PQntuples(pgResult) < 1)
+ {
+ cerr << "no tuple with id " << myOId << endl << flush;
+ exitNicely();
+ }
+
+ blobOid = atoi( PQgetvalue( pgResult, 0, 0 ) );
+ dataFormat = atoi( PQgetvalue( pgResult, 0, 1 ) );
+ PQclear( pgResult );
+
+ // (2) --- open, read, close blob
+ int fd = lo_open( pgConn, blobOid, INV_READ ); // open; manual tells no error indication
+ size = lo_lseek( pgConn, fd, 0, SEEK_END ); // determine blob size; FIXME: more efficient method??
+ (void) lo_lseek( pgConn, fd, 0, SEEK_SET ); // rewind for reading
+ cells = (char*) mymalloc( size * sizeof(char) ); // allocate buffer for blob
+ if (cells == NULL)
+ {
+ cerr << "error during malloc()" << endl << flush;
+ exitNicely();
+ }
+ int loResult = lo_read( pgConn, fd, cells, size );
+ if (loResult < 0)
+ {
+ cerr << "error during lo_read(): " << PQerrorMessage(pgConn) << endl << flush;
+ exitNicely();
+ }
+ else if (loResult != size) // did not get all
+ {
+ cerr << "error (did not get all bytes): " << PQerrorMessage(pgConn) << endl << flush;
+ exitNicely();
+ }
+ int ignoredPgResult = lo_close( pgConn, fd ); // close blob
+
+ if (withDump)
+ {
+ cout << " id = " << myOId << ", dataFormat = " << dataFormat << ", bloboid = " << blobOid << ", blob length = " << size << ", contents = ";
+ for (int a = 0; a < size; a++)
+ cout << " " << hex << (0xff & (unsigned int)(cells[a])) << dec;
+ cout << dec << endl;
+ }
+ else
+ {
+ cout << " id = " << myOId << ", dataFormat = " << dataFormat << ", bloboid = " << blobOid << ", blob length = " << size << endl;
+ }
+
+ free( cells );
+}
+
+// read all tuples from ras_tiles and display them (with contents if withDump==true)
+void
+readAllFromDb( bool withDump )
+{
+ unsigned int blobOid;
+ long myId;
+ short dataFormat;
+ unsigned long size = 0;
+ char *cells = NULL;
+ int rowNumber = 0;
+
+ // (1) --- declare cursor
+ pgResult = PQexec( pgConn, "SELECT BlobId, Tile, DataFormat FROM RAS_TILES" );
+ if (PQresultStatus(pgResult) != PGRES_TUPLES_OK && PQresultStatus(pgResult) != PGRES_COMMAND_OK)
+ {
+ cerr << "error during 'declare cursor': " << PQerrorMessage(pgConn) << endl << flush;
+ exitNicely();
+ }
+
+ do
+ {
+ myId = atoi( PQgetvalue( pgResult, rowNumber, 0 ) );
+ blobOid = atoi( PQgetvalue( pgResult, rowNumber, 1 ) );
+ dataFormat = atoi( PQgetvalue( pgResult, rowNumber, 2 ) );
+
+ // (2) --- open, read, close blob
+ int fd = lo_open( pgConn, blobOid, INV_READ ); // open; manual tells no error indication
+ size = lo_lseek( pgConn, fd, 0, SEEK_END ); // determine blob size; FIXME: more efficient method??
+ (void) lo_lseek( pgConn, fd, 0, SEEK_SET ); // rewind for reading
+ cells = (char*) mymalloc( size * sizeof(char) ); // allocate buffer for blob
+ if (cells == NULL)
+ {
+ cerr << "error: readFromDb() - no tuples found " << endl;
+ return;
+ }
+ int loResult = lo_read( pgConn, fd, cells, size );
+ if (loResult < 0)
+ {
+ cerr << "error: readFromDb() - no tuples found " << endl;
+ return;
+ }
+ else if (loResult != size) // did not get all
+ {
+ cerr << "error: readFromDb() - no tuples found " << endl;
+ return;
+ }
+ int ignoredPgResult = lo_close( pgConn, fd ); // close blob
+
+ if (withDump)
+ {
+ cout << " id = " << myId << ", dataFormat = " << dataFormat << ", bloboid = " << blobOid << ", blob length = " << size << ", contents = ";
+ for (int a = 0; a < size; a++)
+ cout << " " << hex << (0xff & (unsigned int)(cells[a])) << dec;
+ cout << endl;
+ }
+ else
+ {
+ cout << " id = " << myId << ", dataFormat = " << dataFormat << ", bloboid = " << blobOid << ", blob length = " << size << endl;
+ }
+
+ rowNumber++;
+ } while (PQresultStatus(pgResult) == PGRES_TUPLES_OK || PQresultStatus(pgResult) == PGRES_COMMAND_OK);
+
+ (void) PQexec( pgConn, "CLOSE TileLoop" );
+ PQclear( pgResult );
+ free( cells );
+}
+
+void usage(const char *prog)
+{
+ cout << "Usage: " << prog << " -d db [-i id] [-c]" << endl;
+ cout << "where:" << endl;
+ cout << " -d db log into PG server using PG database name db (mandatory)" << endl;
+ cout << " -i id dump blob with identifier id (default: dump whole table)" << endl;
+ cout << " -c dump blob contents too (default: descriptor data only)" << endl;
+ cout << " -h (help) print this overview" << endl;
+}
+
+int
+main(int argc, char* argv[])
+{
+ char *prog = argv[0]; // prog name
+ char db[100]; // DB connect string
+ int blobOid = 0; // tuple to be dumped
+ bool withDump = false; // by default, don't dump blob contents
+ char c; // getop var
+ int result; // for sscanf()
+
+ cout << prog << ": dump rasdaman blob table." << endl;
+
+ opterr = 0;
+ while ((c = getopt(argc, argv, "d:i:c")) != -1)
+ {
+ switch (c)
+ {
+ case 'd':
+ (void) strncpy( db, optarg, sizeof(db) );
+ break;
+ case 'i':
+ result = sscanf( optarg, "%d", &blobOid );
+ if (result != 1)
+ {
+ cerr << prog << ": positive integer expected: " << optarg << endl;
+ exit( RC_ERROR );
+ }
+ break;
+ case 'c':
+ withDump = true;
+ break;
+ case 'h':
+ case '?':
+ case ':':
+ usage(prog);
+ exit( RC_OK );
+ break;
+ }
+ }
+ if (optind < argc || argc == 1)
+ {
+ usage( prog );
+ exit( RC_ERROR );
+ }
+
+ connect( db );
+
+ if (blobOid > 0)
+ readFromDb( blobOid, withDump );
+ else
+ readAllFromDb( withDump );
+
+ disconnect();
+
+ cout << prog << ": done." << endl;
+}
+
diff --git a/relblobif/test/blobdump.pgc b/relblobif/test/blobdump.pgc
new file mode 100644
index 0000000..69b35b7
--- /dev/null
+++ b/relblobif/test/blobdump.pgc
@@ -0,0 +1,315 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include "mymalloc/mymalloc.h"
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * dump RAS_TILES blob table.
+ * Depending on parameters, either a particular tuple is printed
+ * or the whole table. Optionally also the blob is dumped in hex.
+ * Parameters: see usage().
+ *
+ *
+ * COMMENTS:
+ * - assumes RAS_TILES
+ *
+ ************************************************************/
+
+using namespace std;
+
+#include <iostream>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h> /* getopt */
+
+#include <sqlca.h>
+
+// SQL error codes:
+#include "externs.h"
+
+// PG stuff
+#include "libpq-fe.h" // C interface to PgSQL
+#include "libpq/libpq-fs.h" /* large object (lo) api */
+// libq-style connection ptr taken from ECPG connect (needed for libq functions):
+// (currently used by relblobif/blobtile.pgc)
+PGconn *pgConn = NULL;
+PGresult *pgResult = NULL;
+
+#define RC_OK 0
+#define RC_ERROR -1
+
+#define QUERYSIZE 2000
+static char pgQuery[QUERYSIZE];
+
+void exitNicely()
+{
+ PQclear( pgResult );
+ (void) PQexec( pgConn, "ROLLBACK WORK" );
+ PQfinish( pgConn );
+ exit( RC_ERROR );
+}
+
+
+void
+disconnect()
+{
+ pgResult = PQexec( pgConn, "ROLLBACK WORK" );
+ if (PQresultStatus(pgResult) != PGRES_COMMAND_OK)
+ {
+ cerr << "error during disconnect: " << PQerrorMessage(pgConn) << endl << flush;
+ PQclear( pgResult );
+ exit( RC_ERROR );
+ }
+ PQclear( pgResult );
+
+ PQfinish( pgConn );
+ pgConn = NULL;
+}
+
+void
+connect( const char * db )
+{
+ char pgConnInfo[200];
+
+ (void) snprintf( pgConnInfo, (size_t) sizeof(pgConnInfo), "dbname = %s", db );
+ pgConn = PQconnectdb( pgConnInfo );
+ if (PQstatus(pgConn) != CONNECTION_OK)
+ {
+ cerr << "error during connect: " << PQerrorMessage(pgConn) << endl << flush;
+ exitNicely();
+ }
+
+ pgResult = PQexec( pgConn, "BEGIN TRANSACTION" );
+ if (PQresultStatus(pgResult) != PGRES_COMMAND_OK)
+ {
+ cerr << "error during being ta: " << PQerrorMessage(pgConn) << endl << flush;
+ PQclear( pgResult );
+ exit( RC_ERROR );
+ }
+ PQclear( pgResult );
+
+}
+
+// read one tuple from ras_tiles, identified by myOId, and display it (with contents if withDump==true)
+void
+readFromDb( long myOId, bool withDump )
+{
+ unsigned int blobOid = 0;
+ short dataFormat = 0;
+ unsigned long size = 0;
+ char *cells = NULL;
+
+ // (1) --- access tuple
+ int result = snprintf( pgQuery, (size_t) sizeof(pgQuery), "SELECT Tile, DataFormat FROM RAS_TILES WHERE BlobId = %d", myOId );
+
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_TUPLES_OK)
+ {
+ cerr << "error during 'select': " << PQerrorMessage(pgConn) << endl << flush;
+ exitNicely();
+ }
+ else if (PQntuples(pgResult) < 1)
+ {
+ cerr << "no tuple with id " << myOId << endl << flush;
+ exitNicely();
+ }
+
+ blobOid = atoi( PQgetvalue( pgResult, 0, 0 ) );
+ dataFormat = atoi( PQgetvalue( pgResult, 0, 1 ) );
+ PQclear( pgResult );
+
+ // (2) --- open, read, close blob
+ int fd = lo_open( pgConn, blobOid, INV_READ ); // open; manual tells no error indication
+ size = lo_lseek( pgConn, fd, 0, SEEK_END ); // determine blob size; FIXME: more efficient method??
+ (void) lo_lseek( pgConn, fd, 0, SEEK_SET ); // rewind for reading
+ cells = (char*) mymalloc( size * sizeof(char) ); // allocate buffer for blob
+ if (cells == NULL)
+ {
+ cerr << "error during malloc()" << endl << flush;
+ exitNicely();
+ }
+ int loResult = lo_read( pgConn, fd, cells, size );
+ if (loResult < 0)
+ {
+ cerr << "error during lo_read(): " << PQerrorMessage(pgConn) << endl << flush;
+ exitNicely();
+ }
+ else if (loResult != size) // did not get all
+ {
+ cerr << "error (did not get all bytes): " << PQerrorMessage(pgConn) << endl << flush;
+ exitNicely();
+ }
+ int ignoredPgResult = lo_close( pgConn, fd ); // close blob
+
+ if (withDump)
+ {
+ cout << " id = " << myOId << ", dataFormat = " << dataFormat << ", bloboid = " << blobOid << ", blob length = " << size << ", contents = ";
+ for (int a = 0; a < size; a++)
+ cout << " " << hex << (0xff & (unsigned int)(cells[a])) << dec;
+ cout << dec << endl;
+ }
+ else
+ {
+ cout << " id = " << myOId << ", dataFormat = " << dataFormat << ", bloboid = " << blobOid << ", blob length = " << size << endl;
+ }
+
+ free( cells );
+}
+
+// read all tuples from ras_tiles and display them (with contents if withDump==true)
+void
+readAllFromDb( bool withDump )
+{
+ unsigned int blobOid;
+ long myId;
+ short dataFormat;
+ unsigned long size = 0;
+ char *cells = NULL;
+ int rowNumber = 0;
+
+ // (1) --- declare cursor
+ pgResult = PQexec( pgConn, "SELECT BlobId, Tile, DataFormat FROM RAS_TILES" );
+ if (PQresultStatus(pgResult) != PGRES_TUPLES_OK && PQresultStatus(pgResult) != PGRES_COMMAND_OK)
+ {
+ cerr << "error during 'declare cursor': " << PQerrorMessage(pgConn) << endl << flush;
+ exitNicely();
+ }
+
+ do
+ {
+ myId = atoi( PQgetvalue( pgResult, rowNumber, 0 ) );
+ blobOid = atoi( PQgetvalue( pgResult, rowNumber, 1 ) );
+ dataFormat = atoi( PQgetvalue( pgResult, rowNumber, 2 ) );
+
+ // (2) --- open, read, close blob
+ int fd = lo_open( pgConn, blobOid, INV_READ ); // open; manual tells no error indication
+ size = lo_lseek( pgConn, fd, 0, SEEK_END ); // determine blob size; FIXME: more efficient method??
+ (void) lo_lseek( pgConn, fd, 0, SEEK_SET ); // rewind for reading
+ cells = (char*) mymalloc( size * sizeof(char) ); // allocate buffer for blob
+ if (cells == NULL)
+ {
+ cerr << "error: readFromDb() - no tuples found " << endl;
+ return;
+ }
+ int loResult = lo_read( pgConn, fd, cells, size );
+ if (loResult < 0)
+ {
+ cerr << "error: readFromDb() - no tuples found " << endl;
+ return;
+ }
+ else if (loResult != size) // did not get all
+ {
+ cerr << "error: readFromDb() - no tuples found " << endl;
+ return;
+ }
+ int ignoredPgResult = lo_close( pgConn, fd ); // close blob
+
+ if (withDump)
+ {
+ cout << " id = " << myId << ", dataFormat = " << dataFormat << ", bloboid = " << blobOid << ", blob length = " << size << ", contents = ";
+ for (int a = 0; a < size; a++)
+ cout << " " << hex << (0xff & (unsigned int)(cells[a])) << dec;
+ cout << endl;
+ }
+ else
+ {
+ cout << " id = " << myId << ", dataFormat = " << dataFormat << ", bloboid = " << blobOid << ", blob length = " << size << endl;
+ }
+
+ rowNumber++;
+ } while (PQresultStatus(pgResult) == PGRES_TUPLES_OK || PQresultStatus(pgResult) == PGRES_COMMAND_OK);
+
+ (void) PQexec( pgConn, "CLOSE TileLoop" );
+ PQclear( pgResult );
+ free( cells );
+}
+
+void usage(const char *prog)
+{
+ cout << "Usage: " << prog << " -d db [-i id] [-c]" << endl;
+ cout << "where:" << endl;
+ cout << " -d db log into PG server using PG database name db (mandatory)" << endl;
+ cout << " -i id dump blob with identifier id (default: dump whole table)" << endl;
+ cout << " -c dump blob contents too (default: descriptor data only)" << endl;
+ cout << " -h (help) print this overview" << endl;
+}
+
+int
+main(int argc, char* argv[])
+{
+ char *prog = argv[0]; // prog name
+ char db[100]; // DB connect string
+ int blobOid = 0; // tuple to be dumped
+ bool withDump = false; // by default, don't dump blob contents
+ char c; // getop var
+ int result; // for sscanf()
+
+ cout << prog << ": dump rasdaman blob table." << endl;
+
+ opterr = 0;
+ while ((c = getopt(argc, argv, "d:i:c")) != -1)
+ {
+ switch (c)
+ {
+ case 'd':
+ (void) strncpy( db, optarg, sizeof(db) );
+ break;
+ case 'i':
+ result = sscanf( optarg, "%d", &blobOid );
+ if (result != 1)
+ {
+ cerr << prog << ": positive integer expected: " << optarg << endl;
+ exit( RC_ERROR );
+ }
+ break;
+ case 'c':
+ withDump = true;
+ break;
+ case 'h':
+ case '?':
+ case ':':
+ usage(prog);
+ exit( RC_OK );
+ break;
+ }
+ }
+ if (optind < argc || argc == 1)
+ {
+ usage( prog );
+ exit( RC_ERROR );
+ }
+
+ connect( db );
+
+ if (blobOid > 0)
+ readFromDb( blobOid, withDump );
+ else
+ readAllFromDb( withDump );
+
+ disconnect();
+
+ cout << prog << ": done." << endl;
+}
+
diff --git a/relblobif/test/dblob.C b/relblobif/test/dblob.C
new file mode 100644
index 0000000..c9e2f3d
--- /dev/null
+++ b/relblobif/test/dblob.C
@@ -0,0 +1,242 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include "databaseif.hh"
+#include "transactionif.hh"
+#include "adminif.hh"
+#include "typefactory.hh"
+#include "blobtile.hh"
+#include "raslib/rmdebug.hh"
+#include <iostream.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "externs.h"
+#include "dbref.hh"
+
+RMINITGLOBALS('C')
+
+
+int
+main(int argc, char *argv[])
+ {
+ try {
+ RManDebug = 12;
+ RMInit::dbgOut = cout.rdbuf();
+ if (argc == 1)
+ {
+ printf("Usage:\n");
+ printf("\t%s DBNAME TEST ARGS\n", argv[0]);
+ printf("\twith DBNAME the name of the Database\n");
+ printf("\tand TEST of:\n");
+ printf("\t\t1 : Read BLOBTile ARGS=BlobId\n");
+ printf("\t\t2 : Insert new BLOBTile ARGS=Blobdata\n");
+ printf("\t\t3 : same as above with commit\n");
+ printf("\t\t4 : Update BLOBTile ARGS=BlobId Blobdata\n");
+ printf("\t\t5 : Delete BLOBTile ARGS=BlobId\n");
+ printf("\t\t6 : Insert new BLOBTile ARGS=Blobdatalength\n");
+ }
+ else {
+ if (argc >= 3)
+ {
+ AdminIf* myAdmin;
+ DatabaseIf database;
+ TransactionIf ta;
+ OId* id1 = 0;
+ BLOBTile* b = 0;
+ DbRef<BLOBTile> d;
+
+ short test = atoi(argv[2]);
+ RManDebug = 12;
+ switch (test)
+ {
+ case 1:
+ if (argc == 4)
+ {
+ cout << "Connect to Database: " << argv[1] << endl;
+ myAdmin = AdminIf::instance();
+ database.open(argv[1]);
+ ta.begin(&database);
+
+ id1 = new OId(atof(argv[3]));
+ cout << "Reading BLOBTile with Id " << *id1 << endl;
+ cout << "scop1" << endl;
+ {
+ d = DbRef<BLOBTile>(*id1);
+ cout << "Got BLOBTile" << endl;
+ cout << *d;
+ cout << "Refcount\t:" << d->getReferenceCount() << endl;
+ }
+ cout << "scop1" << endl;
+ ta.abort();
+ database.close();
+ delete myAdmin;
+ }
+ else {
+ printf("YOU DIRTY ASHOLE! NOT THE RIGHT COUNT OF ARGS!\n");
+ }
+ break;
+ case 2:
+ if (argc == 4)
+ {
+ cout << "Connect to Database: " << argv[1] << endl;
+ myAdmin = AdminIf::instance();
+ database.open(argv[1]);
+ ta.begin(&database);
+
+ b = new BLOBTile(strlen(argv[3]), argv[3]);
+ cout << *b;
+ //unneeded b->setPersistent(1);
+ b->validate();
+
+ cout << "Aborting Transaction" << endl;
+ ta.abort();
+ database.close();
+ delete myAdmin;
+ }
+ else {
+ printf("YOU DIRTY ASHOLE! NOT THE RIGHT COUNT OF ARGS!\n");
+ }
+ break;
+
+ case 3:
+ if (argc == 4)
+ {
+ cout << "Connect to Database: " << argv[1] << endl;
+ myAdmin = AdminIf::instance();
+ database.open(argv[1]);
+ ta.begin(&database);
+
+ b = new BLOBTile(strlen(argv[3]), argv[3]);
+ //unneeded b->setPersistent(1);
+ cout << *b;
+ b->validate();
+
+ cout << "Commiting Transaction" << endl;
+ ta.commit();
+ database.close();
+ delete myAdmin;
+ }
+ else {
+ printf("YOU DIRTY ASHOLE! NOT THE RIGHT COUNT OF ARGS!\n");
+ }
+ break;
+
+ case 4:
+ if (argc == 5)
+ {
+ cout << "Connect to Database: " << argv[1] << endl;
+ myAdmin = AdminIf::instance();
+ database.open(argv[1]);
+ ta.begin(&database);
+
+ id1 = new OId(atof(argv[3]));
+ cout << "Reading BLOBTile with Id " << *id1 << endl;
+ d = DbRef<BLOBTile>(*id1);
+ cout << *d;
+
+ cout << "Resizing BLOBTile to " << strlen(argv[4]) << endl;
+ d->resize(strlen(argv[4]));
+ cout << *d;
+
+ cout << "Overwriting BLOBTile data" << endl;
+ memcpy(d->getCells(), argv[4], d->getSize());
+ cout << *d;
+
+ cout << "Updating Database" << endl;
+ d->setModified();
+
+ cout << "Commiting Transaction" << endl;
+ ta.commit();
+ database.close();
+ delete myAdmin;
+ }
+ else {
+ printf("YOU DIRTY ASHOLE! NOT THE RIGHT COUNT OF ARGS!\n");
+ }
+
+
+ case 5:
+ if (argc == 4)
+ {
+ cout << "Connect to Database: " << argv[1] << endl;
+ myAdmin = AdminIf::instance();
+ database.open(argv[1]);
+ ta.begin(&database);
+
+ id1 = new OId(atof(argv[3]));
+ cout << "Reading BLOBTile with Id " << *id1 << endl;
+ d = DbRef<BLOBTile>(*id1);
+ cout << *d;
+
+ cout << "Deleting BLOBTile from Database" << endl;
+ d->setPersistent(0);
+ cout << *d;
+
+ cout << "Commiting Transaction" << endl;
+ ta.commit();
+ database.close();
+ delete myAdmin;
+ }
+ else {
+ printf("YOU DIRTY ASHOLE! NOT THE RIGHT COUNT OF ARGS!\n");
+ }
+ case 6:
+ if (argc == 4)
+ {
+ cout << "Connect to Database: " << argv[1] << endl;
+ myAdmin = AdminIf::instance();
+ database.open(argv[1]);
+ ta.begin(&database);
+
+ b = new BLOBTile(atol(argv[3]), 'c');
+ cout << *b;
+ //unneeded b->setPersistent(1);
+ b->validate();
+
+ cout << "Commiting Transaction" << endl;
+ ta.commit();
+ database.close();
+ delete myAdmin;
+ }
+ else {
+ printf("YOU DIRTY ASHOLE! NOT THE RIGHT COUNT OF ARGS!\n");
+ }
+ break;
+
+ }
+ }
+ else {
+ printf("TOO FEW ARGS\n");
+ if (argc == 0)
+ {
+ TypeFactory type_();
+ }
+ }
+ }
+ }
+ catch (r_Error e)
+ {
+ cout << "caught " << e.what() << " kind " << e.get_kind() << " #" << e.get_errorno() << endl;
+ }
+ return 0;
+ }
diff --git a/relblobif/tileid.hh b/relblobif/tileid.hh
new file mode 100644
index 0000000..da63043
--- /dev/null
+++ b/relblobif/tileid.hh
@@ -0,0 +1,36 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#ifndef _TILEID_HH_
+#define _TILEID_HH_
+
+class DBTile;
+class BLOBTile;
+class InlineTile;
+
+template <class T> class DBRef;
+
+typedef DBRef<BLOBTile> BLOBTileId;
+typedef DBRef<InlineTile> InlineTileId;
+typedef DBRef<DBTile> DBTileId;
+
+#endif
diff --git a/relcatalogif/Makefile.am b/relcatalogif/Makefile.am
new file mode 100644
index 0000000..19ebca8
--- /dev/null
+++ b/relcatalogif/Makefile.am
@@ -0,0 +1,69 @@
+# -*-Makefile-*- (for Emacs)
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+#
+# MAKEFILE FOR:
+# relcatalogif
+#
+# COMMENTS:
+#
+##################################################################
+
+#
+# This Makefile only works with GNU Make!
+#
+
+######################### Definitions ############################
+
+AM_CXXFLAGS=@BASEDBCXXFLAGS@
+AM_LDFLAGS=@BASEDBLDFLAGS@
+
+.SUFFIXES= .@EMBEDDEDSQLEXT@ .@EMBEDDEDSQLOUT@
+.@EMBEDDEDSQLEXT@.@EMBEDDEDSQLOUT@:
+ $(EMBEDDEDSQLPRECOMPILER) $@ $<
+
+noinst_LIBRARIES=librelcatalogif.a
+librelcatalogif_a_SOURCES= type.C type.hh basetype.C basetype.hh atomictype.C ulongtype.C ulongtype.hh ushorttype.C ushorttype.hh \
+ booltype.C booltype.hh compositetype.C compositetype.hh structtypecommon.cc structtype.hh structtype.icc \
+ longtype.C longtype.hh shorttype.C shorttype.hh octettype.C octettype.hh doubletype.C doubletype.hh\
+ floattype.C floattype.hh chartype.C chartype.hh collectiontype.C collectiontype.hh settypecommon.cc settype.hh\
+ mddtypecommon.cc mddtype.hh mddbasetypecommon.cc mddbasetype.hh mdddomaintypecommon.cc mdddomaintype.hh\
+ mdddimensiontypecommon.cc mdddimensiontype.hh dbminterval.hh inlineminterval.cc inlineminterval.hh \
+ typeiterator.hh atomictype.hh uintegraltype.hh uintegraltype.icc integraltype.hh \
+ integraltype.icc realtype.hh realtype.icc alltypes.hh complextype.hh complextype.icc
+EXTRA_librelcatalogif_a_SOURCES= settype.pgc mddtype.pgc mddbasetype.pgc mdddomaintype.pgc mdddimensiontype.pgc structtype.pgc dbminterval.pgc
+librelcatalogif_a_LIBADD= settype.$(OBJEXT) mddtype.$(OBJEXT) mddbasetype.$(OBJEXT) mdddimensiontype.$(OBJEXT) \
+ structtype.$(OBJEXT) dbminterval.$(OBJEXT) mdddomaintype.$(OBJEXT)
+librelcatalogif_a_DEPENDENCIES= settype.$(OBJEXT) mddtype.$(OBJEXT) mddbasetype.$(OBJEXT) mdddimensiontype.$(OBJEXT) \
+ structtype.$(OBJEXT) dbminterval.$(OBJEXT) mdddomaintype.$(OBJEXT)
+
+BUILT_SOURCES= settype.@EMBEDDEDSQLOUT@ mddtype.@EMBEDDEDSQLOUT@ mddbasetype.@EMBEDDEDSQLOUT@ \
+ mdddimensiontype.@EMBEDDEDSQLOUT@ structtype.@EMBEDDEDSQLOUT@ dbminterval.@EMBEDDEDSQLOUT@ \
+ mdddomaintype.@EMBEDDEDSQLOUT@
+
+
+CLEANFILES=settype.@EMBEDDEDSQLOUT@ mddtype.@EMBEDDEDSQLOUT@ mddbasetype.@EMBEDDEDSQLOUT@ \
+ mdddimensiontype.@EMBEDDEDSQLOUT@ structtype.@EMBEDDEDSQLOUT@ dbminterval.@EMBEDDEDSQLOUT@ \
+ mdddomaintype.@EMBEDDEDSQLOUT@ \
+ client.bm client.dbg client.log ir.out core
+
+
+
diff --git a/relcatalogif/alltypes.hh b/relcatalogif/alltypes.hh
new file mode 100644
index 0000000..6ecadff
--- /dev/null
+++ b/relcatalogif/alltypes.hh
@@ -0,0 +1,38 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include "ulongtype.hh"
+#include "longtype.hh"
+#include "chartype.hh"
+#include "booltype.hh"
+#include "octettype.hh"
+#include "ushorttype.hh"
+#include "shorttype.hh"
+#include "floattype.hh"
+#include "doubletype.hh"
+#include "structtype.hh"
+#include "settype.hh"
+#include "mddtype.hh"
+#include "mddbasetype.hh"
+#include "mdddomaintype.hh"
+#include "mdddimensiontype.hh"
+#include "complextype.hh"
diff --git a/relcatalogif/atomictype.C b/relcatalogif/atomictype.C
new file mode 100644
index 0000000..a7b4b65
--- /dev/null
+++ b/relcatalogif/atomictype.C
@@ -0,0 +1,113 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * uses ODMG-conformant O2 classes
+ *
+ *
+ * COMMENTS:
+ * none
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)catalogif,AtomicType: $Id: atomictype.C,v 1.4 2001/06/20 08:06:37 hoefner Exp $";
+
+#include "atomictype.hh"
+#include "reladminif/externs.h"
+
+/*************************************************************
+ * Method name...: AtomicType();
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: initializes member variables for an
+ * AtomicType.
+ ************************************************************/
+
+AtomicType::AtomicType(unsigned int newSize)
+ : BaseType("unnamed atomictype"),
+ size(newSize)
+ {
+ objecttype = OId::ATOMICTYPEOID;
+ _isPersistent = 1;
+ _isInDatabase = 1;
+ _isModified = 0;
+ }
+
+AtomicType::AtomicType(const char* name, unsigned int newSize)
+ : BaseType(name),
+ size(newSize)
+ {
+ objecttype = OId::ATOMICTYPEOID;
+ _isPersistent = 1;
+ _isInDatabase = 1;
+ _isModified = 0;
+ }
+
+AtomicType::AtomicType(const AtomicType& old)
+ : BaseType(old),
+ size(old.size)
+ {
+ objecttype = OId::ATOMICTYPEOID;
+ _isPersistent = 1;
+ _isInDatabase = 1;
+ _isModified = 0;
+ }
+
+AtomicType::AtomicType(const OId& id) throw (r_Error)
+ : BaseType(id)
+ {
+ objecttype = OId::ATOMICTYPEOID;
+ _isPersistent = 1;
+ _isInDatabase = 1;
+ _isModified = 0;
+ }
+
+AtomicType::~AtomicType()
+ {
+ }
+
+AtomicType&
+AtomicType::operator=(const AtomicType& old)
+ {
+ BaseType::operator=(old);
+ size = old.size;
+ return *this;
+ }
+
+/*************************************************************
+ * Method name...: unsigned int getSize() const
+ *
+ * Arguments.....: none
+ * Return value..: size in d_Octets
+ * Description...: returns size of AtomicType in chars
+ ************************************************************/
+
+unsigned int
+AtomicType::getSize() const
+{
+ return size;
+}
+
diff --git a/relcatalogif/atomictype.hh b/relcatalogif/atomictype.hh
new file mode 100644
index 0000000..3a7523b
--- /dev/null
+++ b/relcatalogif/atomictype.hh
@@ -0,0 +1,93 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+// -*-C++-*- (for Emacs)
+
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * The AtomicType class is the superclass for all for
+ * atomic types (e.g. Octet, ULong) describing the type of a
+ * cell
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#ifndef _ATOMICTYPE_HH_
+#define _ATOMICTYPE_HH_
+
+#include <iostream>
+#include "basetype.hh"
+
+//@ManMemo: Module: {\bf relcatalogif}.
+
+/*@Doc:
+AtomicType is the abstract base class for all non-structured
+\Ref{BaseType} subclasses, i.e. base types like \Ref{ULongType} or
+\Ref{BoolType}.
+*/
+
+class AtomicType : public BaseType
+ {
+ public:
+ virtual unsigned int getSize() const;
+ /*@Doc:
+ get size of cells of this base type.
+ */
+
+ AtomicType(unsigned int newSize);
+ /*@Doc:
+ constructor.
+ */
+
+ AtomicType(const AtomicType& old);
+ /*@Doc:
+ copy constructor.
+ */
+
+ AtomicType(const OId& id) throw (r_Error);
+ /*@Doc:
+ */
+
+ AtomicType& operator=(const AtomicType& old);
+ /*@Doc:
+ */
+
+ virtual ~AtomicType();
+ /*@Doc:
+ */
+
+ protected:
+ unsigned int size;
+ /*@Doc:
+ size of one cell of this base type in number of chars.
+ */
+
+ AtomicType(const char* name, unsigned int newSize);
+ /*@Doc:
+ */
+ };
+
+#endif
diff --git a/relcatalogif/basetype.C b/relcatalogif/basetype.C
new file mode 100644
index 0000000..a01f208
--- /dev/null
+++ b/relcatalogif/basetype.C
@@ -0,0 +1,130 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * uses ODMG-conformant O2 classes
+ *
+ *
+ * COMMENTS:
+ * none
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)catalogif,BaseType: $Id: basetype.C,v 1.11 2001/06/20 08:06:37 hoefner Exp $";
+
+#include "basetype.hh"
+#include "raslib/rmdebug.hh"
+#include "reladminif/externs.h"
+
+BaseType::BaseType(const char* name)
+ : Type(name)
+ {
+ RMDBGONCE(7, RMDebug::module_catalogif, "BaseType", "BaseType(" << getName() << ")");
+ }
+
+/*************************************************************
+ * Method name...: BaseType()
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: constructor
+ ************************************************************/
+
+BaseType::BaseType()
+ : Type("unnamed basetype")
+ {
+ RMDBGONCE(7, RMDebug::module_catalogif, "BaseType", "BaseType()");
+ }
+
+BaseType::BaseType(const OId& id) throw (r_Error)
+ : Type(id)
+ {
+ RMDBGONCE(7, RMDebug::module_catalogif, "BaseType", "BaseType(" << myOId << ")");
+ }
+
+BaseType::BaseType(const BaseType& old)
+ : Type(old)
+ {
+ }
+
+/*************************************************************
+ * Method name...: ~BaseType()
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: virtual destructor
+ ************************************************************/
+
+BaseType::~BaseType()
+ {
+ }
+
+BaseType&
+BaseType::operator=(const BaseType& old)
+ {
+ Type::operator=(old);
+ return *this;
+ }
+
+/*************************************************************
+ * Method name...: UnaryOp* getUnaryOp( Ops::OpType optype )
+ *
+ * Arguments.....:
+ * optype: operation to return
+ * Return value..:
+ * pointer to ther UnaryOp requested
+ * Description...: return requested UnaryOp for ULongType
+ ************************************************************/
+
+UnaryOp*
+BaseType::getUnaryOp( Ops::OpType op, const BaseType* optype ) const
+{
+ return Ops::getUnaryOp(op, (const BaseType*)this, optype);
+}
+
+BinaryOp*
+BaseType::getBinaryOp( Ops::OpType op, const BaseType* op1type,
+ const BaseType* op2type ) const
+{
+ return Ops::getBinaryOp(op, (const BaseType*)this, op1type, op2type);
+}
+
+
+CondenseOp*
+BaseType::getCondenseOp( Ops::OpType op ) const
+{
+ return Ops::getCondenseOp(op, (const BaseType*)this);
+}
+
+
+int
+BaseType::compatibleWith(const Type* aType) const
+ {
+ RMDBGENTER(7, RMDebug::module_catalogif, "BaseType", "compatibleWith(" << aType->getName() << ") " << getName());
+ int retval = (myType == aType->getType());
+ RMDBGEXIT(7, RMDebug::module_catalogif, "BaseType", "compatibleWith(" << aType->getName() << ") " << getName() << " " << retval);
+ return retval;
+ }
+
diff --git a/relcatalogif/basetype.hh b/relcatalogif/basetype.hh
new file mode 100644
index 0000000..f01bd60
--- /dev/null
+++ b/relcatalogif/basetype.hh
@@ -0,0 +1,161 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+// -*-C++-*- (for Emacs)
+
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * The BaseType class is the superclass for all classes
+ * describing the type of a cell
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#ifndef _BASETYPE_HH_
+#define _BASETYPE_HH_
+
+#include <iostream>
+#include "catalogmgr/ops.hh"
+#include "type.hh"
+#include "raslib/odmgtypes.hh"
+
+//@ManMemo: Module: {\bf relcatalogif}.
+
+/*@Doc:
+BaseType is the abstract base class for all types usable as basetypes
+for an MDD. At the moment, only atomic types are supported. Later
+structured types will also be supported.
+
+Common to each basetype is the ability to get size information,to
+print a cell and to provide means to carry out operations on cells of
+this type. This functionality is defined as pure virtual functions
+here.
+
+{\bf Interdependencies}
+
+Each \Ref{Tile} has a pointer to its BaseType. Pointers to BaseType
+are also used in subclasses of \Ref{MDDObject}.
+*/
+
+class BaseType : public Type
+ {
+ public:
+ virtual unsigned int getSize() const = 0;
+ /*@Doc:
+ returns the size of one cell of the type in chars.
+ */
+
+ virtual r_ULong* convertToCULong(const char* cell, r_ULong* value) const = 0;
+
+ /*@Doc:
+ returns value of the cell as a C #unsigned long#.
+ */
+
+ virtual char* makeFromCULong(char* cell, const r_ULong* value) const = 0;
+ /*@Doc:
+ returns C #unsigned long# in cell #cell#.
+ */
+
+ virtual r_Long* convertToCLong(const char* cell, r_Long* value) const = 0;
+ /*@Doc:
+ returns value of the cell as a C #long#.
+ */
+
+ virtual char* makeFromCLong(char* cell, const r_Long* value) const = 0;
+ /*@Doc:
+ returns C #long# in cell #cell#.
+ */
+
+ virtual double* convertToCDouble(const char* cell, double* value) const = 0;
+ /*@Doc:
+ returns value of the cell as a C #double#.
+ */
+
+ virtual char* makeFromCDouble(char* cell, const double* value) const = 0;
+ /*@Doc:
+ returns C #double# in cell #cell#.
+ */
+
+ virtual void printCell(ostream& stream, const char* cell) const = 0;
+ /*@Doc:
+ print contents of a cell to stream.
+ */
+
+ //@Man: methods for getting functions (used by \Ref{Tile})
+ //@{
+ /// get function object for condense operation.
+ virtual CondenseOp* getCondenseOp( Ops::OpType op ) const;
+ /*@Doc:
+ \Ref{CondenseOp} carrying out the operation op on a cell of this
+ type. The type of the result depends on the operation carried out,
+ but is usually of type self. See \Ref{Ops} for details.
+ */
+
+ /// get function object for unary operation.
+ virtual UnaryOp* getUnaryOp( Ops::OpType op, const BaseType* optype ) const;
+ /*@Doc:
+ Returns a pointer to a function object of a subclass of class
+ \Ref{UnaryOp} carrying out the operation {\tt op} on a cell of
+ type {\tt optype}. The result type has the type self. See
+ \Ref{Ops} for details.
+ */
+
+ /// get function object for binary operation.
+ virtual BinaryOp* getBinaryOp( Ops::OpType op, const BaseType* op1type, const BaseType* op2type) const;
+ /*@Doc:
+ Returns a pointer to a function object of a subclass of class
+ \Ref{BinaryOp} carrying out the operation {\tt op} on two cells of
+ type {\tt op1type} respective {\tt op2type}. The result type has
+ the type self. See \Ref{Ops} for details.
+ */
+ //@}
+
+ BaseType();
+ /*@Doc:
+ default constructor, cannot be used.
+ */
+
+ BaseType(const OId& id) throw (r_Error);
+
+ BaseType(const BaseType& old);
+
+ BaseType& operator=(const BaseType& old);
+
+ virtual ~BaseType();
+ /*@Doc:
+ virtual destructor.
+ */
+
+ virtual int compatibleWith(const Type* aType) const;
+ /*@Doc:
+ returns true if my TypeEnum == aType->getType()
+ */
+
+ protected:
+ BaseType(const char* name);
+ };
+
+#endif
diff --git a/relcatalogif/booltype.C b/relcatalogif/booltype.C
new file mode 100644
index 0000000..b6025b4
--- /dev/null
+++ b/relcatalogif/booltype.C
@@ -0,0 +1,157 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * uses ODMG-conformant O2 classes
+ *
+ *
+ * COMMENTS:
+ * none
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)catalogif,BoolType: $Header: /home/rasdev/CVS-repository/rasdaman/relcatalogif/booltype.C,v 1.8 2003/12/27 23:23:04 rasdev Exp $";
+
+#include "booltype.hh"
+#include <string.h>
+
+/*************************************************************
+ * Method name...: BoolType();
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: initializes member variables for an
+ * BoolType.
+ ************************************************************/
+
+BoolType::BoolType(const OId& id) throw (r_Error)
+ : UIntegralType(id)
+ {
+ readFromDb();
+ }
+
+BoolType::BoolType()
+ : UIntegralType(BoolType::Name, 1)
+ {
+ myType = BOOLTYPE;
+ myOId = OId(BOOLTYPE, OId::ATOMICTYPEOID);
+ }
+
+/*************************************************************
+ * Method name...: BoolType(const BoolType& old);
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: copy constructor
+ ************************************************************/
+
+BoolType::BoolType(const BoolType& old)
+ : UIntegralType(old)
+ {
+ }
+
+/*************************************************************
+ * Method name...: operator=(const BoolType&);
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: copy constructor
+ ************************************************************/
+
+BoolType&
+BoolType::operator=(const BoolType& old)
+ {
+ // Gracefully handle self assignment
+ if (this == &old)
+ return *this;
+ AtomicType::operator=(old);
+ return *this;
+ }
+
+/*************************************************************
+ * Method name...: ~BoolType();
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: virtual destructor
+ ************************************************************/
+
+BoolType::~BoolType()
+ {
+ }
+
+/*************************************************************
+ * Method name...: void printCell( ostream& stream,
+ * const char* cell )
+ *
+ * Arguments.....:
+ * stream: stream to print on
+ * cell: pointer to cell to print
+ * Return value..: none
+ * Description...: prints a cell cell in hex on stream
+ * followed by a space.
+ * Assumes that Bool is stored MSB..LSB
+ * on HP.
+ ************************************************************/
+
+void
+BoolType::printCell( ostream& stream, const char* cell ) const
+{
+ if(*cell == 0)
+ stream << "FALSE ";
+ else
+ stream << "TRUE ";
+}
+
+r_ULong*
+BoolType::convertToCULong(const char* cell, r_ULong* value) const
+{
+ // !!!! HP specific, assumes 4 Byte long and MSB..LSB
+ // byte order
+ //*value = *(unsigned char*)cell;
+
+ *value = *(unsigned char*)cell ? 1: 0;
+ return value;
+}
+
+
+char*
+BoolType::makeFromCULong(char* cell, const r_ULong* value) const
+{
+ // !!!! HP specific, assumes 4 Byte long and MSB..LSB
+ // byte order
+ *(unsigned char*)(cell) = (unsigned char)(*value);
+ return cell;
+}
+
+void
+BoolType::readFromDb() throw (r_Error)
+ {
+ setName(BoolType::Name);
+ size = 1;
+ myType = BOOLTYPE;
+ myOId = OId(BOOLTYPE, OId::ATOMICTYPEOID);
+ }
+
diff --git a/relcatalogif/booltype.hh b/relcatalogif/booltype.hh
new file mode 100644
index 0000000..9810055
--- /dev/null
+++ b/relcatalogif/booltype.hh
@@ -0,0 +1,104 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+// -*-C++-*- (for Emacs)
+
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * The ULongType class is the superclass for all classes
+ * describing the type of a cell
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#ifndef _BOOLTYPE_HH_
+#define _BOOLTYPE_HH_
+
+#include <iostream>
+#include "uintegraltype.hh"
+#include "catalogmgr/ops.hh"
+
+class OId;
+
+//@ManMemo: Module: {\bf relcatalogif}.
+
+/*@Doc:
+
+BoolType is the base type used for boolean cell values (e.g. result
+of comparison operations, see \Ref{Ops}). The value of a Bool is
+stored in one char. BoolType is a persistence capable class.
+*/
+
+class BoolType : public UIntegralType
+ {
+ public:
+ BoolType(const OId& id) throw (r_Error);
+
+ BoolType();
+ /*@Doc:
+ default constructor, no initialization needed for BoolType.
+ */
+
+ BoolType(const BoolType& old);
+ /*@Doc:
+ copy constructor.
+ */
+
+ BoolType& operator=(const BoolType& old);
+ /*@Doc:
+ assignment operator.
+ */
+
+ virtual ~BoolType();
+ /*@Doc:
+ virtual destructor.
+ */
+
+ virtual void printCell(ostream& stream, const char* cell) const;
+ /*@Doc:
+ */
+
+ virtual r_ULong* convertToCULong(const char* cell, r_ULong* value) const;
+ /*@Doc:
+ */
+
+ virtual char* makeFromCULong(char* cell, const r_ULong* value) const;
+ /*@Doc:
+ */
+
+ static const char* Name;
+
+ protected:
+
+ virtual void readFromDb() throw (r_Error);
+ /*@Doc:
+ initializes the attributes of this type.
+ there is no database activity. this is hard coded.
+ */
+
+ };
+
+#endif
diff --git a/relcatalogif/chartype.C b/relcatalogif/chartype.C
new file mode 100644
index 0000000..3ac3f6a
--- /dev/null
+++ b/relcatalogif/chartype.C
@@ -0,0 +1,158 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * uses ODMG-conformant O2 classes
+ *
+ *
+ * COMMENTS:
+ * none
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)catalogif,CharType: $Header: /home/rasdev/CVS-repository/rasdaman/relcatalogif/chartype.C,v 1.10 2003/12/27 23:23:04 rasdev Exp $";
+
+#include "chartype.hh"
+#include <iomanip>
+#include <string.h>
+#include <limits.h>
+
+/*************************************************************
+ * Method name...: CharType();
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: initializes member variables for an
+ * CharType.
+ ************************************************************/
+
+CharType::CharType()
+ : UIntegralType(CharType::Name, 1)
+ {
+ myType = CHAR;
+ myOId = OId(CHAR, OId::ATOMICTYPEOID);
+ }
+
+/*************************************************************
+ * Method name...: CharType(const CharType& old);
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: copy constructor
+ ************************************************************/
+
+CharType::CharType(const CharType& old)
+ : UIntegralType(CharType::Name, old.size)
+ {
+ }
+
+CharType::CharType(const OId& id) throw (r_Error)
+ : UIntegralType(OId(CHAR, OId::ATOMICTYPEOID))
+ {
+ readFromDb();
+ }
+
+/*************************************************************
+ * Method name...: operator=(const CharType&);
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: copy constructor
+ ************************************************************/
+
+CharType&
+CharType::operator=(const CharType& old)
+ {
+ // Gracefully handle self assignment
+ if (this == &old)
+ return *this;
+ AtomicType::operator=(old);
+ return *this;
+ }
+
+void
+CharType::readFromDb() throw (r_Error)
+ {
+ setName(CharType::Name);
+ myType = CHAR;
+ myOId = OId(CHAR, OId::ATOMICTYPEOID);
+ size = 1;
+ }
+
+/*************************************************************
+ * Method name...: ~CharType();
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: virtual destructor
+ ************************************************************/
+
+CharType::~CharType()
+ {
+ }
+
+/*************************************************************
+ * Method name...: void printCell( ostream& stream,
+ * const char* cell )
+ *
+ * Arguments.....:
+ * stream: stream to print on
+ * cell: pointer to cell to print
+ * Return value..: none
+ * Description...: prints a cell cell in hex on stream
+ * followed by a space.
+ * Assumes that Char is stored MSB..LSB
+ * on HP.
+ ************************************************************/
+
+void
+CharType::printCell( ostream& stream, const char* cell ) const
+{
+ // !!!! HP specific, assumes 1 Byte char
+ stream << std::setw(4) << (r_Long)(*(unsigned char*)cell);
+}
+
+r_ULong*
+CharType::convertToCULong(const char* cell, r_ULong* value) const
+{
+ // !!!! HP specific, assumes 4 Byte long and MSB..LSB
+ // byte order
+ *value = *(unsigned char*)cell;
+ return value;
+}
+
+
+char*
+CharType::makeFromCULong(char* cell, const r_ULong* value) const
+ {
+ r_ULong myLong = *value;
+ //restricting long to value range of short
+ myLong = myLong > UCHAR_MAX ? UCHAR_MAX : myLong;
+ myLong = myLong < 0 ? 0 : myLong;
+ // !!!! HP specific, assumes 4 Byte long and MSB..LSB
+ // byte order
+ *(unsigned char*)(cell)=(unsigned char)myLong;
+ return cell;
+ }
diff --git a/relcatalogif/chartype.hh b/relcatalogif/chartype.hh
new file mode 100644
index 0000000..2a8fd8c
--- /dev/null
+++ b/relcatalogif/chartype.hh
@@ -0,0 +1,106 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+// -*-C++-*- (for Emacs)
+
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * The CharType class represents unsigned char.
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#ifndef _CHARTYPE_HH_
+#define _CHARTYPE_HH_
+
+#include <iostream>
+#include "raslib/odmgtypes.hh"
+#include "uintegraltype.hh"
+#include "catalogmgr/ops.hh"
+
+class OId;
+
+//@ManMemo: Module: {\bf relcatalogif}.
+
+/*@Doc:
+
+CharType is the base type used for unsigned char cell values (e.g.
+result of comparison operations, see \Ref{Ops}). The value of a Char
+is stored in one char. CharType is a persistence capable class.
+*/
+
+class CharType : public UIntegralType
+ {
+ public:
+ CharType();
+ /*@Doc:
+ default constructor, no initialization needed for CharType.
+ */
+
+ CharType(const OId& id) throw (r_Error);
+ /*@Doc:
+ */
+
+ CharType(const CharType& old);
+ /*@Doc:
+ copy constructor.
+ */
+
+ CharType& operator=(const CharType& old);
+ /*@Doc:
+ assignment operator.
+ */
+
+ virtual ~CharType();
+ /*@Doc:
+ virtual destructor.
+ */
+
+ virtual void printCell(ostream& stream, const char* cell) const;
+ /*@Doc:
+ */
+
+ virtual r_ULong* convertToCULong(const char* cell, r_ULong* value) const;
+ /*@Doc:
+ */
+
+ virtual char* makeFromCULong(char* cell, const r_ULong* value) const;
+ /*@Doc:
+ */
+
+ static const char* Name;
+
+ protected:
+
+ virtual void readFromDb() throw (r_Error);
+ /*@Doc:
+ initializes the attributes of this type.
+ there is no database activity. this is hard coded.
+ */
+
+ };
+
+#endif
diff --git a/relcatalogif/collectiontype.C b/relcatalogif/collectiontype.C
new file mode 100644
index 0000000..26e9f1d
--- /dev/null
+++ b/relcatalogif/collectiontype.C
@@ -0,0 +1,98 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include "collectiontype.hh"
+#include "mddtype.hh"
+
+r_Bytes
+CollectionType::getMemorySize() const
+ {
+ return DBNamedObject::getMemorySize() + myMDDType->getMemorySize() + sizeof(MDDType*);
+ }
+
+CollectionType::CollectionType(const MDDType* newMDDType)
+ : Type("unnamed collectiontype")
+ {
+ myMDDType = newMDDType;
+ }
+
+CollectionType::CollectionType()
+ : Type("unnamed collectiontype")
+ {
+ myMDDType = 0;
+ }
+
+CollectionType::CollectionType(const char* name)
+ : Type(name)
+ {
+ myMDDType = 0;
+ }
+
+
+CollectionType::CollectionType(const char* name, const MDDType* newMDDType)
+ : Type(name)
+ {
+ myMDDType = newMDDType;
+ }
+
+CollectionType::CollectionType(const OId& id) throw (r_Error)
+ : Type(id)
+ {
+ }
+
+CollectionType::CollectionType(const CollectionType& old)
+ : Type(old)
+ {
+ myMDDType = old.myMDDType;
+ }
+
+CollectionType&
+CollectionType::operator=(const CollectionType& old)
+ {
+ Type::operator=(old);
+ myMDDType = old.myMDDType;
+ return *this;
+ }
+
+CollectionType::~CollectionType()
+ {
+ }
+
+const MDDType*
+CollectionType::getMDDType() const
+ {
+ return myMDDType;
+ }
+
+void
+CollectionType::print_status( ostream& s ) const
+{
+ s << "d_" << getName() << "<";
+ myMDDType->print_status(s);
+ s << " >";
+}
+
+int
+CollectionType::compatibleWith(const Type* aType) const
+{
+ return myMDDType->compatibleWith(aType);
+}
diff --git a/relcatalogif/collectiontype.hh b/relcatalogif/collectiontype.hh
new file mode 100644
index 0000000..591d715
--- /dev/null
+++ b/relcatalogif/collectiontype.hh
@@ -0,0 +1,129 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+// -*-C++-*- (for Emacs)
+
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * The CollectionType class is the superclass for the class
+ * SetType.
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#ifndef _COLLECTIONTYPE_HH_
+#define _COLLECTIONTYPE_HH_
+
+class CollectionType;
+
+#include <iostream>
+#include "catalogmgr/ops.hh"
+#include "type.hh"
+#include "reladminif/externs.h"
+
+class MDDType;
+
+//@ManMemo: Module: {\bf relcatalogif}.
+
+/*@Doc:
+ CollectionType is the base class for classes that deal with
+ collections of MDDs (the only subclass at the moment is SetType).
+*/
+
+class CollectionType : public Type
+ {
+ public:
+ const MDDType* getMDDType() const;
+ /*@Doc:
+ returns MDDType of collection.
+ */
+ /*
+ MDDType* getMDDType() const;
+ */
+
+
+ void print_status( ostream& s ) const;
+ /*@Doc:
+ writes the state of the object to the specified stream:
+ d_MYNAME <MYMDDTYPE->printStatus >
+ */
+
+ CollectionType(const MDDType* newMDDType);
+ /*@Doc:
+ constructor receiving pointer to an MDDType (or subclass).
+ */
+
+ CollectionType();
+ /*@Doc:
+ default constructor, cannot be used.
+ */
+
+ CollectionType(const OId& id) throw (r_Error);
+ /*@Doc:
+ */
+
+ CollectionType(const CollectionType& old);
+ /*@Doc:
+ */
+
+ CollectionType& operator=(const CollectionType& old);
+ /*@Doc:
+ */
+
+ virtual ~CollectionType();
+ /*@Doc:
+ virtual destructor.
+ */
+
+ virtual int compatibleWith(const Type* aType) const;
+ /*@Doc:
+ overloaded from Type.
+ returns true if myMDDType is compatible with the type.
+ */
+
+ virtual r_Bytes getMemorySize() const;
+ /*@Doc:
+ returns DBNamedObject::getMemorySize() +
+ myMDDType->getMemorySize() + sizeof(MDDType*);
+ */
+
+ protected:
+ const MDDType* myMDDType;
+ /*@Doc:
+ persistent pointer to MDDType of collection.
+ */
+
+ CollectionType(const char* name);
+ /*@Doc:
+ */
+
+ CollectionType(const char* name,const MDDType* newMDDType);
+ /*@Doc:
+ */
+ };
+
+#endif
+
diff --git a/relcatalogif/complextype.hh b/relcatalogif/complextype.hh
new file mode 100644
index 0000000..9d18e32
--- /dev/null
+++ b/relcatalogif/complextype.hh
@@ -0,0 +1,131 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+// -*-C++-*- (for Emacs)
+
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#ifndef _COMPLEXTYPE_HH_
+#define _COMPLEXTYPE_HH_
+
+#include <iostream>
+#include <values.h>
+#include "realtype.hh"
+#include "catalogmgr/ops.hh"
+
+class OId;
+
+
+
+class GenericComplexType : public AtomicType {
+
+public:
+ GenericComplexType(const char *name, unsigned int size): AtomicType(name, size) {}
+ GenericComplexType(const OId& id) throw (r_Error): AtomicType(id) {}
+ virtual ~GenericComplexType() {}
+ virtual unsigned int getReOffset() const = 0;
+ virtual unsigned int getImOffset() const = 0;
+
+protected:
+ virtual void readFromDb() throw (r_Error) = 0;
+};
+
+
+class ComplexType1 : public GenericComplexType {
+
+public:
+ ComplexType1();
+ ComplexType1(const OId& id) throw (r_Error);
+ ComplexType1(const ComplexType1& old);
+ ComplexType1& operator=(const ComplexType1& old);
+ virtual ~ComplexType1();
+ virtual void printCell(ostream& stream, const char* cell) const;
+ unsigned int getReOffset() const;
+ unsigned int getImOffset() const;
+ virtual const char* getTypeName() const;
+ static const char* Name;
+
+
+protected:
+ virtual void readFromDb() throw (r_Error);
+
+private:
+ unsigned int reOffset, imOffset;
+
+// static const char* complexTypeName;
+
+ r_ULong* convertToCULong(const char*, r_ULong*) const;
+ char* makeFromCULong(char*, const r_ULong*) const;
+ r_Long* convertToCLong(const char*, r_Long*) const;
+ char* makeFromCLong(char*, const r_Long*) const;
+ double* convertToCDouble(const char* cell, double* value) const;
+ char* makeFromCDouble(char* cell, const double* value) const;
+
+};
+
+class ComplexType2 : public GenericComplexType {
+
+public:
+ ComplexType2();
+ ComplexType2(const OId& id) throw (r_Error);
+ ComplexType2(const ComplexType2& old);
+ ComplexType2& operator=(const ComplexType2& old);
+ virtual ~ComplexType2();
+ virtual void printCell(ostream& stream, const char* cell) const;
+ unsigned int getReOffset() const;
+ unsigned int getImOffset() const;
+ virtual const char* getTypeName() const;
+ static const char* Name;
+
+protected:
+ virtual void readFromDb() throw (r_Error);
+
+private:
+ unsigned int reOffset, imOffset;
+
+// static const char* complexTypeName;
+
+ r_ULong* convertToCULong(const char*, r_ULong*) const;
+ char* makeFromCULong(char*, const r_ULong*) const;
+ r_Long* convertToCLong(const char*, r_Long*) const;
+ char* makeFromCLong(char*, const r_Long*) const;
+ double* convertToCDouble(const char* cell, double* value) const;
+ char* makeFromCDouble(char* cell, const double* value) const;
+
+};
+
+
+#include "complextype.icc"
+
+
+
+#endif
diff --git a/relcatalogif/complextype.icc b/relcatalogif/complextype.icc
new file mode 100644
index 0000000..a6ca72c
--- /dev/null
+++ b/relcatalogif/complextype.icc
@@ -0,0 +1,159 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+///////////////////////////////////////////////////////////////
+// implementation - ComplexType1
+///////////////////////////////////////////////////////////////
+
+
+inline ComplexType1::ComplexType1()
+ : GenericComplexType(ComplexType1::Name, 2 * sizeof(float)), reOffset(0), imOffset(sizeof(float)) {
+ myType = COMPLEXTYPE1;
+ myOId = OId(COMPLEXTYPE1, OId::ATOMICTYPEOID);
+}
+
+inline ComplexType1::ComplexType1(const OId& id) throw (r_Error)
+ : GenericComplexType(id), reOffset(0), imOffset(sizeof(float)) {
+ readFromDb();
+}
+
+inline ComplexType1::ComplexType1(const ComplexType1& old) : GenericComplexType(old) {
+ reOffset = old.reOffset;
+ imOffset = old.imOffset;
+}
+
+inline ComplexType1& ComplexType1::operator =(const ComplexType1& old) {
+ if(this == &old)
+ return *this;
+ AtomicType::operator =(old);
+ reOffset = old.reOffset;
+ imOffset = old.imOffset;
+ return *this;
+}
+
+inline ComplexType1::~ComplexType1() {}
+
+inline void ComplexType1::printCell( ostream& stream, const char* cell ) const {
+ stream << "( Re: " << *(float *)(cell + reOffset) << "\t";
+ stream << "Im: " << *(float *)(cell + imOffset) << " )\n";
+}
+
+inline void ComplexType1::readFromDb() throw (r_Error) {
+ size = 2 * sizeof(float);
+ setName(ComplexType1::Name);
+ myType = COMPLEXTYPE1;
+ myOId = OId(COMPLEXTYPE1, OId::ATOMICTYPEOID);
+}
+
+inline unsigned int ComplexType1::getReOffset() const { return reOffset; }
+inline unsigned int ComplexType1::getImOffset() const { return imOffset; }
+
+// those would better throw an exception
+inline r_ULong* ComplexType1::convertToCULong(const char*, r_ULong*) const { return 0; }
+inline char* ComplexType1::makeFromCULong(char*, const r_ULong*) const { return 0; }
+inline r_Long* ComplexType1::convertToCLong(const char*, r_Long*) const { return 0; }
+inline char* ComplexType1::makeFromCLong(char*, const r_Long*) const { return 0; }
+
+inline double* ComplexType1::convertToCDouble(const char* cell, double* value) const {
+ *value = *(float*)cell;
+ return value;
+}
+
+inline char* ComplexType1::makeFromCDouble(char* cell, const double* value) const {
+ double dummy = *value;
+ if(dummy > FLT_MAX)
+ dummy = FLT_MAX;
+ if(dummy < -1.0f * FLT_MAX)
+ dummy = -1.0f * FLT_MAX;
+ *(float*)(cell) = dummy;
+ return cell;
+}
+
+inline const char* ComplexType1::getTypeName() const {
+ return "complex";
+}
+
+///////////////////////////////////////////////////////////////
+// implementation - ComplexType2
+///////////////////////////////////////////////////////////////
+
+inline ComplexType2::ComplexType2()
+ : GenericComplexType(ComplexType2::Name, 2 * sizeof(double)), reOffset(0), imOffset(sizeof(double)) {
+ myType = COMPLEXTYPE2;
+ myOId = OId(COMPLEXTYPE2, OId::ATOMICTYPEOID);
+}
+
+inline ComplexType2::ComplexType2(const OId& id) throw (r_Error)
+ : GenericComplexType(id), reOffset(0), imOffset(sizeof(double)) {
+ readFromDb();
+}
+
+inline ComplexType2::ComplexType2(const ComplexType2& old) : GenericComplexType(old) {
+ reOffset = old.reOffset;
+ imOffset = old.imOffset;
+}
+
+inline ComplexType2& ComplexType2::operator =(const ComplexType2& old) {
+ if(this == &old)
+ return *this;
+ AtomicType::operator =(old);
+ reOffset = old.reOffset;
+ imOffset = old.imOffset;
+ return *this;
+}
+
+inline ComplexType2::~ComplexType2() {}
+
+inline void ComplexType2::printCell( ostream& stream, const char* cell ) const {
+ stream << "( Re: " << *(double *)(cell + reOffset) << "\t";
+ stream << "Im: " << *(double *)(cell + imOffset) << " )\n";
+}
+
+inline void ComplexType2::readFromDb() throw (r_Error) {
+ size = 2 * sizeof(double);
+ setName(ComplexType2::Name);
+ myType = COMPLEXTYPE2;
+ myOId = OId(COMPLEXTYPE2, OId::ATOMICTYPEOID);
+}
+
+inline unsigned int ComplexType2::getReOffset() const { return reOffset; }
+inline unsigned int ComplexType2::getImOffset() const { return imOffset; }
+
+// those would better throw an exception
+inline r_ULong* ComplexType2::convertToCULong(const char*, r_ULong*) const { return 0; }
+inline char* ComplexType2::makeFromCULong(char*, const r_ULong*) const { return 0; }
+inline r_Long* ComplexType2::convertToCLong(const char*, r_Long*) const { return 0; }
+inline char* ComplexType2::makeFromCLong(char*, const r_Long*) const { return 0; }
+
+inline double* ComplexType2::convertToCDouble(const char* cell, double* value) const {
+ *value = *(double*)cell;
+ return value;
+}
+
+inline char* ComplexType2::makeFromCDouble(char* cell, const double* value) const {
+ *(double*)(cell) = *value;
+ return cell;
+}
+
+inline const char* ComplexType2::getTypeName() const {
+ return "complexd";
+}
diff --git a/relcatalogif/compositetype.C b/relcatalogif/compositetype.C
new file mode 100644
index 0000000..aefead7
--- /dev/null
+++ b/relcatalogif/compositetype.C
@@ -0,0 +1,104 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * uses ODMG-conformant O2 classes
+ *
+ *
+ * COMMENTS:
+ * none
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)catalogif,CompositeType: $Header: /home/rasdev/CVS-repository/rasdaman/relcatalogif/compositetype.C,v 1.6 2003/12/27 23:23:04 rasdev Exp $";
+
+#include "compositetype.hh"
+#include "reladminif/externs.h"
+
+/*************************************************************
+ * Method name...: unsigned int getSize() const
+ *
+ * Arguments.....: none
+ * Return value..: size in d_Octets
+ * Description...: returns size of CompositeType in chars
+ ************************************************************/
+
+unsigned int
+CompositeType::getSize() const
+ {
+ return size;
+ }
+
+/*************************************************************
+ * Method name...: CompositeType();
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: initializes member variables for an
+ * CompositeType.
+ ************************************************************/
+
+CompositeType::CompositeType()
+ : BaseType("unnamed compositetype"),
+ size(0)
+ {
+ }
+
+CompositeType::CompositeType(unsigned int newSize)
+ : BaseType("unnamed compositetype"),
+ size(newSize)
+ {
+ }
+
+CompositeType::CompositeType(const char* name, unsigned int newSize)
+ : BaseType(name),
+ size(newSize)
+ {
+ }
+
+CompositeType::CompositeType(const CompositeType& old)
+ : BaseType(old),
+ size(old.size)
+ {
+ }
+
+CompositeType::CompositeType(const OId& id) throw (r_Error)
+ : BaseType(id)
+ {
+ }
+
+CompositeType::~CompositeType()
+ {
+ }
+
+CompositeType&
+CompositeType::operator=(const CompositeType& old)
+ {
+ BaseType::operator=(old);
+ size = old.size;
+ return *this;
+ }
+
+
diff --git a/relcatalogif/compositetype.hh b/relcatalogif/compositetype.hh
new file mode 100644
index 0000000..9e07106
--- /dev/null
+++ b/relcatalogif/compositetype.hh
@@ -0,0 +1,99 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+// -*-C++-*- (for Emacs)
+
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * The CompositeType class is the superclass for all for
+ * composite types (e.g. Octet, ULong) describing the type of a
+ * cell
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#ifndef _COMPOSITETYPE_HH_
+#define _COMPOSITETYPE_HH_
+
+#include <iostream>
+#include "basetype.hh"
+
+//@ManMemo: Module: {\bf relcatalogif}.
+
+/*@Doc:
+CompositeType is the abstract base class for all structured
+\Ref{BaseType} subclasses, at the moment only \Ref{StructType}.
+*/
+
+class CompositeType : public BaseType
+{
+public:
+ virtual unsigned int getSize() const;
+ /*@Doc:
+ get size of cells of this base type.
+ */
+
+ CompositeType();
+ /*@Doc:
+ constructor.
+ */
+
+ CompositeType(const OId& id) throw (r_Error);
+ /*@Doc:
+ constructor.
+ */
+
+ CompositeType(const CompositeType& old);
+ /*@Doc:
+ constructor.
+ */
+
+ CompositeType(unsigned int newSize);
+ /*@Doc:
+ constructor.
+ */
+
+ virtual ~CompositeType();
+ /*@Doc:
+ virtual destructor needed because of subclasses
+ */
+
+ CompositeType& operator=(const CompositeType& old);
+ /*@Doc:
+ */
+
+protected:
+ unsigned int size;
+ /*@Doc:
+ size of one cell of this base type in number of chars.
+ */
+
+ CompositeType(const char* name, unsigned int newSize);
+ /*@Doc:
+ */
+};
+
+#endif
diff --git a/relcatalogif/dbminterval.hh b/relcatalogif/dbminterval.hh
new file mode 100644
index 0000000..c871cef
--- /dev/null
+++ b/relcatalogif/dbminterval.hh
@@ -0,0 +1,103 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#ifndef _DBMINTERVAL_HH_
+#define _DBMINTERVAL_HH_
+
+class DBMinterval;
+
+template<class T> class DBRef;
+typedef DBRef<DBMinterval> DBMintervalId;
+
+#include "reladminif/dbobject.hh"
+#include "raslib/minterval.hh"
+
+
+//@ManMemo: Module: {\bf relcatalogif}.
+
+/*@Doc:
+Persistent version of r_Minterval. it stores its attributes not very efficient.
+it is used by DBMDDObj and MDDDomainType because the performance impact is neglectabel.
+
+for a more efficient storage system refere to InlineMInterval
+*/
+
+class DBMinterval : public DBObject, public r_Minterval
+ {
+ public:
+ DBMinterval();
+
+ DBMinterval(const OId& id) throw (r_Error);
+
+ DBMinterval(r_Dimension dim);
+
+ DBMinterval(const char* dom);
+
+ DBMinterval(const r_Minterval& old);
+
+ DBMinterval(const DBMinterval& old);
+
+ ~DBMinterval();
+ /*@Doc:
+ validates the object in the database.
+ */
+
+ virtual DBMinterval& operator=(const DBMinterval& old);
+ /*@Doc:
+ replaces only the r_Minterval part of the object
+ */
+
+ virtual DBMinterval& operator=(const r_Minterval& old);
+ /*@Doc:
+ replaces only the r_Minterval part of the object
+ */
+
+ virtual r_Bytes getMemorySize() const;
+ /*@Doc:
+ esimates the space taken up by this object with:
+ DBObject::getMemorySize() + sizeof(r_Minterval)
+ + dimensionality * (4 + 4 + 1 + 1)
+ */
+
+ protected:
+
+ virtual void insertInDb() throw (r_Error);
+ /*@Doc:
+ inserts the object into the database. it uses one table
+ for the fixed length attributes (oid, size, dimension) and
+ another for dynamic data (lower/upper bounds/fixed ranges)
+ */
+
+ virtual void updateInDb() throw (r_Error);
+ /*@Doc:
+ */
+
+ virtual void deleteFromDb() throw (r_Error);
+ /*@Doc:
+ */
+
+ virtual void readFromDb() throw (r_Error);
+ /*@Doc:
+ */
+ };
+
+#endif
diff --git a/relcatalogif/dbminterval.lis b/relcatalogif/dbminterval.lis
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/relcatalogif/dbminterval.lis
diff --git a/relcatalogif/dbminterval.pgc b/relcatalogif/dbminterval.pgc
new file mode 100644
index 0000000..eaddf10
--- /dev/null
+++ b/relcatalogif/dbminterval.pgc
@@ -0,0 +1,381 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+// This is -*- C++ -*-
+
+/*************************************************************************
+ *
+ *
+ * PURPOSE:
+ * Code with embedded SQL for PostgreSQL DBMS
+ *
+ *
+ * COMMENTS:
+ * none
+ *
+ ***********************************************************************/
+
+#include "reladminif/sqlerror.hh"
+#include "reladminif/externs.h"
+#include "dbminterval.hh"
+#include "raslib/rmdebug.hh"
+
+EXEC SQL include "../reladminif/sqlglobals.h";
+
+DBMinterval::DBMinterval()
+ : r_Minterval(),
+ DBObject()
+{
+ objecttype = OId::DBMINTERVALOID;
+}
+
+DBMinterval::DBMinterval(const OId& id) throw (r_Error)
+ : r_Minterval(),
+ DBObject(id)
+{
+ objecttype = OId::DBMINTERVALOID;
+ readFromDb();
+}
+
+DBMinterval::DBMinterval(r_Dimension dim)
+ : r_Minterval(dim),
+ DBObject()
+{
+ objecttype = OId::DBMINTERVALOID;
+}
+
+DBMinterval::DBMinterval(const char* dom)
+ : r_Minterval((char*)dom),
+ DBObject()
+{
+ objecttype = OId::DBMINTERVALOID;
+}
+
+DBMinterval::DBMinterval(const DBMinterval& old)
+ : r_Minterval(old),
+ DBObject(old)
+{
+ objecttype = OId::DBMINTERVALOID;
+}
+
+DBMinterval::DBMinterval(const r_Minterval& old)
+ : r_Minterval(old),
+ DBObject()
+{
+ objecttype = OId::DBMINTERVALOID;
+}
+
+DBMinterval::~DBMinterval()
+{
+ RMDBGENTER(4, RMDebug::module_catalogif, "DBMinterval", "~DBMinterval() " << myOId);
+ validate();
+ RMDBGEXIT(4, RMDebug::module_catalogif, "DBMinterval", "~DBMinterval() " << myOId);
+}
+
+DBMinterval&
+DBMinterval::operator=(const DBMinterval& old)
+{
+ RMDBGENTER(11, RMDebug::module_catalogif, "DBMinterval", "operator=(" << old.getOId() << ") with me " << myOId);
+ if (this == &old)
+ return *this;
+ r_Minterval::operator=(old);
+ setModified();
+ RMDBGEXIT(11, RMDebug::module_catalogif, "DBMinterval", "operator=(" << old.getOId() << ") with me " << myOId);
+ return *this;
+}
+
+DBMinterval&
+DBMinterval::operator=(const r_Minterval& old)
+{
+ if (this == &old)
+ return *this;
+ r_Minterval::operator=(old);
+ setModified();
+ return *this;
+}
+
+r_Bytes
+DBMinterval::getMemorySize() const
+{
+ return DBObject::getMemorySize() + sizeof(r_Minterval) + dimensionality * (4 + 4 + 1 + 1);
+}
+
+void
+DBMinterval::insertInDb() throw (r_Error)
+{
+ EXEC SQL BEGIN DECLARE SECTION;
+ long domainid;
+ long count;
+ long low;
+ short lowind;
+ long high;
+ short highind;
+ long dimension;
+ EXEC SQL END DECLARE SECTION;
+
+ domainid = myOId.getCounter();
+ dimension = dimensionality;
+
+ EXEC SQL INSERT INTO RAS_DOMAINS ( DomainId, Dimension)
+ VALUES ( :domainid, :dimension);
+ if (SQLCODE != SQLOK)
+ {
+ check("DBMinterval::insertInDb() INSERT INTO RAS_DOMAINS");
+ generateException();
+ }
+
+ for (count = 0; count < dimensionality; count++)
+ {
+ if (intervals[count].is_low_fixed())
+ {
+ low = intervals[count].low();
+ lowind = 0;
+ }
+ else
+ {
+ lowind = -1;
+ }
+ if (intervals[count].is_high_fixed())
+ {
+ high = intervals[count].high();
+ highind = 0;
+ }
+ else
+ {
+ highind = -1;
+ }
+
+ EXEC SQL INSERT INTO RAS_DOMAINVALUES ( DomainId, DimensionCount, Low, High)
+ VALUES ( :domainid, :count, :low INDICATOR :lowind, :high INDICATOR :highind);
+ if (SQLCODE != SQLOK)
+ {
+ check("DBMinterval::insertInDb() INSERT INTO RAS_DOMAINVALUES");
+ generateException();
+ }
+ }
+
+ DBObject::insertInDb();
+}
+
+void
+DBMinterval::updateInDb() throw (r_Error)
+{
+ EXEC SQL BEGIN DECLARE SECTION;
+ long domainid1;
+ long count1;
+ long low1;
+ short lowind1;
+ long high1;
+ short highind1;
+ long dimension1;
+ EXEC SQL END DECLARE SECTION;
+
+ domainid1 = myOId.getCounter();
+
+ EXEC SQL SELECT Dimension
+ INTO :dimension1
+ FROM RAS_DOMAINS
+ WHERE DomainId = :domainid1;
+
+ if (dimension1 < dimensionality)
+ { //insert more rows in RAS_DOMAINVALUES
+ for (count1 = dimension1; count1 < dimensionality; count1++)
+ {
+ EXEC SQL INSERT INTO RAS_DOMAINVALUES ( DomainId, DimensionCount)
+ VALUES ( :domainid1, :count1);
+ if (SQLCODE != SQLOK)
+ {
+ check("DBMinterval::updateInDb() INSERT INTO RAS_DOMAINVALUES");
+ generateException();
+ }
+ }
+ dimension1 = dimensionality;
+ EXEC SQL UPDATE RAS_DOMAINS SET Dimension = :dimension1
+ WHERE DomainId = :domainid1;
+
+ if (check("DBMinterval::updateInDb() UPDATE RAS_DOMAINS"))
+ generateException();
+ }
+ else
+ {
+ if (dimension1 > dimensionality)
+ { //delete superfluous dimensions
+ for (count1 = dimension1; count1 > dimensionality; count1--)
+ {
+ EXEC SQL DELETE
+ FROM RAS_DOMAINVALUES
+ WHERE DomainId = :domainid1 AND DimensionCount = :count1;
+ if (SQLCODE != SQLOK)
+ {
+ check("DBMinterval::updateInDb() DELETE FROM RAS_DOMAINVALUES");
+ generateException();
+ }
+ }
+ dimension1 = dimensionality;
+ EXEC SQL UPDATE RAS_DOMAINS
+ SET Dimension = :dimension1
+ WHERE DomainId = :domainid1;
+ if (SQLCODE != SQLOK)
+ {
+ check("DBMinterval::updateInDb() UPDATE RAS_DOMAINS");
+ generateException();
+ }
+ }
+ else
+ { //only update dimension boundaries
+ }
+ }
+
+ for (count1 = 0; count1 < dimensionality; count1++)
+ {
+ if (intervals[count1].is_low_fixed())
+ {
+ low1 = intervals[count1].low();
+ lowind1 = 0;
+ }
+ else
+ {
+ lowind1 = -1;
+ }
+ if (intervals[count1].is_high_fixed())
+ {
+ high1 = intervals[count1].high();
+ highind1 = 0;
+ }
+ else
+ {
+ highind1 = -1;
+ }
+
+ EXEC SQL UPDATE RAS_DOMAINVALUES
+ SET Low = :low1 INDICATOR :lowind1, High = :high1 INDICATOR :highind1
+ WHERE DomainId = :domainid1 AND DimensionCount = :count1;
+ if (SQLCODE != SQLOK)
+ {
+ check("DBMinterval::updateInDb() UPDATE RAS_DOMAINVALUES");
+ generateException();
+ }
+ }
+
+ DBObject::updateInDb();
+}
+
+void
+DBMinterval::deleteFromDb() throw (r_Error)
+{
+ EXEC SQL BEGIN DECLARE SECTION;
+ long domainid2;
+ EXEC SQL END DECLARE SECTION;
+
+ domainid2 = myOId.getCounter();
+
+ EXEC SQL DELETE FROM RAS_DOMAINS
+ WHERE DomainId = :domainid2;
+ if (SQLCODE != SQLOK)
+ {
+ check("DBMinterval::deleteFromDb() DELETE FROM RAS_DOMAINS");
+ generateException();
+ }
+
+ EXEC SQL DELETE FROM RAS_DOMAINVALUES
+ WHERE DomainId = :domainid2;
+ if (SQLCODE != SQLOK)
+ {
+ check("DBMinterval::deleteFromDb() DELETE FROM RAS_DOMAINVALUES");
+ generateException();
+ }
+
+ DBObject::deleteFromDb();
+}
+
+void
+DBMinterval::readFromDb() throw (r_Error)
+{
+ char undefined = '*';
+ EXEC SQL BEGIN DECLARE SECTION;
+ long domainid3;
+ long count3;
+ long low3;
+ short lowind3;
+ long high3;
+ short highind3;
+ long dimension3;
+ EXEC SQL END DECLARE SECTION;
+
+ domainid3 = myOId.getCounter();
+
+ EXEC SQL SELECT Dimension
+ INTO :dimension3
+ FROM RAS_DOMAINS
+ WHERE DomainId = :domainid3;
+ if (SQLCODE != SQLOK)
+ {
+ check("DBMinterval::readFromDb() SELECT FROM RAS_DOMAINS");
+ if (SQLCODE == 100)
+ {
+ throw r_Error(r_Error::r_Error_ObjectUnknown);
+ }
+ else
+ {
+ generateException();
+ }
+ }
+
+ dimensionality = dimension3;
+ delete[] intervals;
+ intervals = new r_Sinterval[dimensionality];
+ streamInitCnt = 0;
+
+ for (count3 = 0; count3 < dimension3; count3++)
+ {
+ EXEC SQL SELECT Low, High
+ INTO :low3 INDICATOR :lowind3, :high3 INDICATOR :highind3
+ FROM RAS_DOMAINVALUES
+ WHERE DimensionCount = :count3 AND DomainId = :domainid3;
+ if (SQLCODE != SQLOK)
+ {
+ check("DBMinterval::readFromDb() SELECT FROM RAS_DOMAINVALUES");
+ generateException();
+ }
+
+ if (!lowind3)
+ {
+ intervals[count3].set_low((r_Range)low3);
+ }
+ else
+ {
+ intervals[count3].set_low(undefined);
+ }
+ if (!highind3)
+ {
+ intervals[count3].set_high((r_Range)high3);
+ }
+ else
+ {
+ intervals[count3].set_high(undefined);
+ }
+ streamInitCnt++;
+ }
+
+ DBObject::readFromDb();
+}
+
diff --git a/relcatalogif/doubletype.C b/relcatalogif/doubletype.C
new file mode 100644
index 0000000..0258c1a
--- /dev/null
+++ b/relcatalogif/doubletype.C
@@ -0,0 +1,154 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * uses ODMG-conformant O2 classes
+ *
+ *
+ * COMMENTS:
+ * none
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)catalogif,DoubleType: $Header: /home/rasdev/CVS-repository/rasdaman/relcatalogif/doubletype.C,v 1.8 2003/12/27 23:23:04 rasdev Exp $";
+
+#include "doubletype.hh"
+#include <iomanip>
+#include <string.h>
+
+DoubleType::DoubleType(const OId& id) throw (r_Error)
+ : RealType(id)
+ {
+ readFromDb();
+ }
+
+/*************************************************************
+ * Method name...: DoubleType();
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: initializes member variables for an
+ * DoubleType.
+ ************************************************************/
+
+DoubleType::DoubleType()
+ : RealType(DoubleType::Name, 8)
+ {
+ myType = DOUBLE;
+ myOId = OId(DOUBLE, OId::ATOMICTYPEOID);
+ }
+
+/*************************************************************
+ * Method name...: DoubleType(const DoubleType& old);
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: copy constructor
+ ************************************************************/
+
+DoubleType::DoubleType(const DoubleType& old) :
+ RealType(old)
+{
+}
+
+/*************************************************************
+ * Method name...: operator=(const DoubleType&);
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: copy constructor
+ ************************************************************/
+
+DoubleType&
+DoubleType::operator=(const DoubleType& old)
+ {
+ // Gracefully handle self assignment
+ if (this == &old)
+ return *this;
+ AtomicType::operator=(old);
+ return *this;
+ }
+
+/*************************************************************
+ * Method name...: ~DoubleType();
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: virtual destructor
+ ************************************************************/
+
+DoubleType::~DoubleType()
+{
+}
+
+void
+DoubleType::readFromDb() throw (r_Error)
+ {
+ size = 8;
+ setName(DoubleType::Name);
+ myType = DOUBLE;
+ myOId = OId(DOUBLE, OId::ATOMICTYPEOID);
+ }
+
+/*************************************************************
+ * Method name...: void printCell( ostream& stream,
+ * const char* cell )
+ *
+ * Arguments.....:
+ * stream: stream to print on
+ * cell: pointer to cell to print
+ * Return value..: none
+ * Description...: prints a cell cell in hex on stream
+ * followed by a space.
+ * Assumes that Double is stored MSB..LSB
+ * on HP.
+ ************************************************************/
+
+void
+DoubleType::printCell( ostream& stream, const char* cell ) const
+{
+ // !!!! HP specific, assumes 4 Byte double and MSB..LSB
+ // byte order
+ stream << *(double*)cell << " ";
+}
+
+double*
+DoubleType::convertToCDouble(const char* cell, double* value) const
+{
+ // !!!! HP specific, assumes 8 Byte double
+ // byte order
+ *value = *(double*)cell;
+ return value;
+}
+
+
+char*
+DoubleType::makeFromCDouble(char* cell, const double* value) const
+{
+ // !!!! HP specific, assumes 4 Byte double and MSB..LSB
+ // byte order
+ *(double*)(cell) = *value;
+ return cell;
+}
diff --git a/relcatalogif/doubletype.hh b/relcatalogif/doubletype.hh
new file mode 100644
index 0000000..74dcfa2
--- /dev/null
+++ b/relcatalogif/doubletype.hh
@@ -0,0 +1,103 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+// -*-C++-*- (for Emacs)
+
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * The DoubleType class is the superclass for all classes
+ * describing the type of a cell
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#ifndef _DOUBLETYPE_HH_
+#define _DOUBLETYPE_HH_
+
+#include <iostream>
+#include "realtype.hh"
+#include "catalogmgr/ops.hh"
+
+class OId;
+
+//@ManMemo: Module: {\bf relcatalogif}.
+
+/*@Doc:
+DoubleType is the base type used for 32bit integer cell
+values. The value of a Double is stored in four chars.
+*/
+
+class DoubleType : public RealType
+ {
+ public:
+ DoubleType();
+ /*@Doc:
+ default constructor, sets type name to "Double".
+ */
+
+ DoubleType(const OId& id) throw (r_Error);
+ /*@Doc:
+ */
+
+ DoubleType(const DoubleType& old);
+ /*@Doc:
+ copy constructor.
+ */
+
+ DoubleType& operator=(const DoubleType& old);
+ /*@Doc:
+ assignment operator.
+ */
+
+ virtual ~DoubleType();
+ /*@Doc:
+ virtual destructor.
+ */
+
+ virtual void printCell(ostream& stream, const char* cell) const;
+ /*@Doc:
+ */
+
+ virtual double* convertToCDouble(const char* cell, double* value) const;
+ /*@Doc:
+ */
+
+ virtual char* makeFromCDouble(char* cell, const double* value) const;
+ /*@Doc:
+ */
+
+ static const char* Name;
+
+ protected:
+
+ virtual void readFromDb() throw (r_Error);
+ /*@Doc:
+ initializes the attributes of this type.
+ there is no database activity. this is hard coded.
+ */
+ };
+
+#endif
diff --git a/relcatalogif/floattype.C b/relcatalogif/floattype.C
new file mode 100644
index 0000000..f043dd9
--- /dev/null
+++ b/relcatalogif/floattype.C
@@ -0,0 +1,159 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * uses ODMG-conformant O2 classes
+ *
+ *
+ * COMMENTS:
+ * none
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)catalogif,FloatType: $Header: /home/rasdev/CVS-repository/rasdaman/relcatalogif/floattype.C,v 1.10 2003/12/27 23:23:04 rasdev Exp $";
+
+#include "floattype.hh"
+#include <iomanip>
+#include <string.h>
+#include "reladminif/oidif.hh"
+#include <values.h>
+
+FloatType::FloatType(const OId& id) throw (r_Error)
+ : RealType(id)
+ {
+ readFromDb();
+ }
+
+/*************************************************************
+ * Method name...: FloatType();
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: initializes member variables for an
+ * FloatType.
+ ************************************************************/
+
+FloatType::FloatType()
+ : RealType(FloatType::Name, 4)
+ {
+ myType = FLOAT;
+ myOId = OId(FLOAT, OId::ATOMICTYPEOID);
+ }
+
+/*************************************************************
+ * Method name...: FloatType(const FloatType& old);
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: copy constructor
+ ************************************************************/
+
+FloatType::FloatType(const FloatType& old)
+ : RealType(old)
+ {
+ }
+
+/*************************************************************
+ * Method name...: operator=(const FloatType&);
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: copy constructor
+ ************************************************************/
+
+FloatType& FloatType::operator=(const FloatType& old)
+ {
+ // Gracefully handle self assignment
+ if (this == &old)
+ return *this;
+ AtomicType::operator=(old);
+ return *this;
+ }
+
+/*************************************************************
+ * Method name...: ~FloatType();
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: virtual destructor
+ ************************************************************/
+
+FloatType::~FloatType()
+{
+}
+
+void
+FloatType::readFromDb() throw (r_Error)
+ {
+ setName(FloatType::Name);
+ size = 4;
+ myType = FLOAT;
+ myOId = OId(FLOAT, OId::ATOMICTYPEOID);
+ }
+
+/*************************************************************
+ * Method name...: void printCell( ostream& stream,
+ * const char* cell )
+ *
+ * Arguments.....:
+ * stream: stream to print on
+ * cell: pointer to cell to print
+ * Return value..: none
+ * Description...: prints a cell cell in hex on stream
+ * followed by a space.
+ * Assumes that Float is stored MSB..LSB
+ * on HP.
+ ************************************************************/
+
+void
+FloatType::printCell( ostream& stream, const char* cell ) const
+{
+ // !!!! HP specific, assumes 4 Byte float and MSB..LSB
+ // byte order
+ stream << std::setw(8) << *(float*)cell;
+}
+
+double*
+FloatType::convertToCDouble(const char* cell, double* value) const
+{
+ // !!!! HP specific, assumes 4 Byte float and MSB..LSB
+ // byte order
+ *value = *(float*)cell;
+ return value;
+}
+
+
+char*
+FloatType::makeFromCDouble(char* cell, const double* value) const
+{
+ // make sure that a float is not assigned a double (DEC Alpha correctly dumps core)
+ double dummy = *value;
+ if(dummy > FLT_MAX)
+ dummy = FLT_MAX;
+ if(dummy < -1.0f * FLT_MAX)
+ dummy = -1.0f * FLT_MAX;
+ *(float*)(cell) = dummy;
+ return cell;
+}
diff --git a/relcatalogif/floattype.hh b/relcatalogif/floattype.hh
new file mode 100644
index 0000000..299fe11
--- /dev/null
+++ b/relcatalogif/floattype.hh
@@ -0,0 +1,95 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+// -*-C++-*- (for Emacs)
+
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * The FloatType class is the superclass for all classes
+ * describing the type of a cell
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#ifndef _FLOATTYPE_HH_
+#define _FLOATTYPE_HH_
+
+#include <iostream>
+#include "realtype.hh"
+#include "catalogmgr/ops.hh"
+
+class OId;
+
+//@ManMemo: Module: {\bf relcatalogif}.
+
+/*@Doc:
+FloatType is the base type used for 32bit integer cell
+values. The value of a Float is stored in four chars.
+*/
+
+class FloatType : public RealType
+ {
+ public:
+ FloatType(const OId& id) throw (r_Error);
+
+ FloatType();
+ /*@Doc:
+ default constructor, sets type name to "Float".
+ */
+
+ FloatType(const FloatType& old);
+ /*@Doc:
+ copy constructor.
+ */
+
+ FloatType& operator=(const FloatType& old);
+ /*@Doc:
+ assignment operator.
+ */
+
+ virtual ~FloatType();
+ /*@Doc:
+ virtual destructor.
+ */
+
+ virtual void printCell(ostream& stream, const char* cell) const;
+
+ virtual double* convertToCDouble(const char* cell, double* value) const;
+
+ virtual char* makeFromCDouble(char* cell, const double* value) const;
+
+ static const char* Name;
+
+ protected:
+
+ virtual void readFromDb() throw (r_Error);
+ /*@Doc:
+ initializes the attributes of this type.
+ there is no database activity. this is hard coded.
+ */
+ };
+
+#endif
diff --git a/relcatalogif/inlineminterval.cc b/relcatalogif/inlineminterval.cc
new file mode 100644
index 0000000..05d14d3
--- /dev/null
+++ b/relcatalogif/inlineminterval.cc
@@ -0,0 +1,139 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+// This is -*- C++ -*-
+/*
+ * dbminterval.pc
+ *
+ * 17-May-99 hoefner First created.
+ * 27-May-99 webbasan Added prefix "RAS_" to tablenames.
+ */
+
+#include "inlineminterval.hh"
+#include "raslib/rmdebug.hh"
+
+InlineMinterval::InlineMinterval()
+ : r_Minterval((r_Dimension)0)
+ {
+ RMDBGONCE(10, RMDebug::module_catalogif, "InlineMinterval", "InlineMinterval()");
+ }
+
+InlineMinterval::~InlineMinterval()
+ {
+ RMDBGONCE(10, RMDebug::module_catalogif, "InlineMinterval", "~InlineMinterval()");
+ }
+
+InlineMinterval::InlineMinterval(r_Dimension dim)
+ : r_Minterval(dim)
+ {
+ RMDBGONCE(10, RMDebug::module_catalogif, "InlineMinterval", "InlineMinterval(" << dim << ")");
+ }
+
+InlineMinterval::InlineMinterval(r_Dimension dim, r_Range* lowerbound, r_Range* upperbound, char* lowerfixed, char* upperfixed)
+ : r_Minterval(dim)
+ {
+ RMDBGENTER(10, RMDebug::module_catalogif, "InlineMinterval", "InlineMinterval(" << dim << ", lb, ub, lf, uf)");
+ char undefined = '*';
+ streamInitCnt = dim;
+
+ for (r_Dimension count = 0; count < dimensionality; count++)
+ {
+ if (!lowerfixed[count])
+ {
+ intervals[count].set_high(undefined);
+ intervals[count].set_low(lowerbound[count]);
+ }
+ else {
+ intervals[count].set_low(undefined);
+ }
+ if (!upperfixed[count])
+ {
+ intervals[count].set_high(upperbound[count]);
+ }
+ else {
+ intervals[count].set_high(undefined);
+ }
+ }
+ RMDBGEXIT(10, RMDebug::module_catalogif, "InlineMinterval", "InlineMinterval(" << dim << ", lb, ub, lf, uf)");
+ }
+
+InlineMinterval::InlineMinterval(const InlineMinterval& old)
+ : r_Minterval(old)
+ {
+ RMDBGONCE(10, RMDebug::module_catalogif, "InlineMinterval", "InlineMinterval(InlineMinterval)");
+ }
+
+InlineMinterval::InlineMinterval(const r_Minterval& old)
+ : r_Minterval(old)
+ {
+ RMDBGONCE(10, RMDebug::module_catalogif, "InlineMinterval", "InlineMinterval(r_Minterval)");
+ }
+
+InlineMinterval&
+InlineMinterval::operator=(const InlineMinterval& old)
+ {
+ RMDBGENTER(10, RMDebug::module_catalogif, "InlineMinterval", "operator=()");
+ if (this == &old)
+ return *this;
+ r_Minterval::operator=(old);
+ RMDBGEXIT(10, RMDebug::module_catalogif, "InlineMinterval", "operator=()");
+ return *this;
+ }
+
+InlineMinterval&
+InlineMinterval::operator=(const r_Minterval& old)
+ {
+ RMDBGENTER(10, RMDebug::module_catalogif, "InlineMinterval", "operator=()");
+ if (this == &old)
+ return *this;
+ r_Minterval::operator=(old);
+ RMDBGEXIT(10, RMDebug::module_catalogif, "InlineMinterval", "operator=()");
+ return *this;
+ }
+
+void
+InlineMinterval::insertInDb(r_Range* lowerbound, r_Range* upperbound, char* lowerfixed, char* upperfixed) const
+ {
+ RMDBGENTER(10, RMDebug::module_catalogif, "InlineMinterval", "insertInDb(lb, ub, lf, uf)");
+ char undefined = '*';
+ for (int count = 0; count < dimensionality; count++)
+ {
+ if (intervals[count].is_low_fixed())
+ {
+ lowerbound[count] = intervals[count].low();
+ lowerfixed[count] = 0;
+ }
+ else {
+ lowerfixed[count] = undefined;
+ }
+ if (intervals[count].is_high_fixed())
+ {
+ upperbound[count] = intervals[count].high();
+ upperfixed[count] = 0;
+ }
+ else {
+ upperfixed[count] = undefined;
+ }
+ }
+ RMDBGEXIT(10, RMDebug::module_catalogif, "InlineMinterval", "insertInDb(lb, ub, lf, uf)");
+ }
+
diff --git a/relcatalogif/inlineminterval.hh b/relcatalogif/inlineminterval.hh
new file mode 100644
index 0000000..c3f1daa
--- /dev/null
+++ b/relcatalogif/inlineminterval.hh
@@ -0,0 +1,73 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#ifndef _INLINEMINTERVAL_HH_
+#define _INLINEMINTERVAL_HH_
+
+class InlineMinterval;
+
+template<class T> class DBRef;
+
+#include "raslib/minterval.hh"
+
+//@ManMemo: Module: {\bf relcatalogif}.
+
+/*@Doc:
+InlineMinterval is a subclass of r_Minterval which stores and
+instantiates itself in char[].
+This class is used by the index data structures to store their
+domain data fast and efficiently.
+*/
+
+class InlineMinterval : public r_Minterval
+ {
+ public:
+ InlineMinterval();
+
+ InlineMinterval(r_Dimension dim);
+
+ InlineMinterval(r_Dimension dim, r_Range* lowerbound, r_Range* upperbound, char* lowerfixed, char* upperfixed);
+ /*@Doc:
+ construct a InlineMinterval with dimension dim from the
+ arrays lowerbound, upperbound, lowerfixed, upperfixed.
+ */
+
+ InlineMinterval(const r_Minterval& old);
+
+ InlineMinterval(const InlineMinterval& old);
+
+ virtual ~InlineMinterval();
+
+ //replaces only the r_Minterval part of the object
+ virtual InlineMinterval& operator=(const InlineMinterval& old);
+
+ //replaces only the r_Minterval part of the object
+ virtual InlineMinterval& operator=(const r_Minterval& old);
+
+ virtual void insertInDb(r_Range* lowerbound, r_Range* upperbound, char* lowerfixed, char* upperfixed) const;
+ /*@Doc:
+ stores the attributes of the InlineMinterval into the four
+ supplied arrays. the arrays must be large enough.
+ */
+ };
+
+#endif
diff --git a/relcatalogif/integraltype.hh b/relcatalogif/integraltype.hh
new file mode 100644
index 0000000..118056e
--- /dev/null
+++ b/relcatalogif/integraltype.hh
@@ -0,0 +1,89 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * The IntegralType class is the superclass for all signed integral
+ * types (e.g. Char, Long) describing the type of a
+ * cell
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#ifndef _INTEGRALTYPE_HH_
+#define _INTEGRALTYPE_HH_
+
+#include "atomictype.hh"
+
+//@ManMemo: Module: {\bf relcatalogif}.
+
+/*@Doc:
+IntegralType is the abstract base class for all integral signed
+\Ref{BaseType} subclasses, i.e. base types like \Ref{LongType} or
+\Ref{ShortType}. It provides conversions to/from unsigned and
+double. It's subclasses must implement conversions to/from long.
+*/
+
+class IntegralType : public AtomicType {
+public:
+ IntegralType(unsigned int newSize):
+ AtomicType(newSize) {}
+ /*@Doc:
+ constructor.
+ */
+
+ IntegralType(const IntegralType& old):
+ AtomicType(old) {}
+ /*@Doc:
+ copy constructor.
+ */
+
+ IntegralType(const OId& id) throw (r_Error):
+ AtomicType(id) {}
+ /*@Doc:
+ */
+
+ virtual ~IntegralType() {}
+ /*@Doc:
+ */
+
+ virtual r_ULong* convertToCULong(const char*, r_ULong*) const;
+ virtual char* makeFromCULong(char*, const r_ULong*) const;
+
+ virtual double* convertToCDouble(const char*, double*) const;
+ virtual char* makeFromCDouble(char*, const double*) const;
+
+protected:
+ IntegralType(const char* name, unsigned int newSize):
+ AtomicType(name, newSize) {}
+ /*@Doc:
+ */
+
+};
+
+#include "integraltype.icc"
+
+#endif
diff --git a/relcatalogif/integraltype.icc b/relcatalogif/integraltype.icc
new file mode 100644
index 0000000..f74cfa6
--- /dev/null
+++ b/relcatalogif/integraltype.icc
@@ -0,0 +1,53 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+*
+*
+* COMMENTS:
+*
+************************************************************/
+
+
+
+inline r_ULong*
+IntegralType::convertToCULong(const char* cell, r_ULong* value) const {
+ return (r_ULong*)(this->convertToCLong(cell, (r_Long *)value));
+}
+
+inline double*
+IntegralType::convertToCDouble(const char* cell, double* value) const {
+ r_Long tmp;
+ *value = *this->convertToCLong(cell, &tmp);
+ return value;
+}
+
+inline char*
+IntegralType::makeFromCULong(char* cell, const r_ULong* value) const {
+ return this->makeFromCLong(cell, (r_Long *)value);
+}
+
+inline char*
+IntegralType::makeFromCDouble(char* cell, const double* value) const {
+ r_Long tmp = *value;
+ return this->makeFromCLong(cell, &tmp);
+}
diff --git a/relcatalogif/longtype.C b/relcatalogif/longtype.C
new file mode 100644
index 0000000..765ea65
--- /dev/null
+++ b/relcatalogif/longtype.C
@@ -0,0 +1,147 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * uses ODMG-conformant O2 classes
+ *
+ *
+ * COMMENTS:
+ * none
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)catalogif,LongType: $Header: /home/rasdev/CVS-repository/rasdaman/relcatalogif/longtype.C,v 1.9 2003/12/27 23:23:04 rasdev Exp $";
+
+#include "longtype.hh"
+#include <iomanip>
+#include <string.h>
+
+LongType::LongType(const OId& id) throw (r_Error)
+ : IntegralType(id)
+ {
+ readFromDb();
+ }
+
+/*************************************************************
+ * Method name...: LongType();
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: initializes member variables for an
+ * LongType.
+ ************************************************************/
+
+LongType::LongType()
+ : IntegralType(LongType::Name, 4)
+ {
+ myType = LONG;
+ myOId = OId(LONG, OId::ATOMICTYPEOID);
+ }
+
+void
+LongType::readFromDb() throw (r_Error)
+ {
+ setName(LongType::Name);
+ size = 4;
+ myType = LONG;
+ myOId = OId(LONG, OId::ATOMICTYPEOID);
+ }
+
+/*************************************************************
+ * Method name...: LongType(const LongType& old);
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: copy constructor
+ ************************************************************/
+
+LongType::LongType(const LongType& old)
+ : IntegralType(old)
+ {
+ }
+
+/*************************************************************
+ * Method name...: operator=(const LongType&);
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: copy constructor
+ ************************************************************/
+
+LongType& LongType::operator=(const LongType& old)
+ {
+ // Gracefully handle self assignment
+ if (this == &old)
+ return *this;
+ AtomicType::operator=(old);
+ return *this;
+ }
+
+/*************************************************************
+ * Method name...: ~LongType();
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: virtual destructor
+ ************************************************************/
+
+LongType::~LongType()
+{
+}
+
+/*************************************************************
+ * Method name...: void printCell( ostream& stream,
+ * const char* cell )
+ *
+ * Arguments.....:
+ * stream: stream to print on
+ * cell: pointer to cell to print
+ * Return value..: none
+ * Description...: prints a cell cell in hex on stream
+ * followed by a space.
+ * Assumes that Long is stored MSB..LSB
+ * on HP.
+ ************************************************************/
+
+void
+LongType::printCell( ostream& stream, const char* cell ) const
+{
+ stream << std::setw(8) << *(r_Long*)cell;
+}
+
+r_Long*
+LongType::convertToCLong(const char* cell, r_Long* value) const
+{
+ *value = *(r_Long*)cell;
+ return value;
+}
+
+
+char*
+LongType::makeFromCLong(char* cell, const r_Long* value) const
+{
+ *(r_Long*)(cell) = *value;
+ return cell;
+}
diff --git a/relcatalogif/longtype.hh b/relcatalogif/longtype.hh
new file mode 100644
index 0000000..4aa5573
--- /dev/null
+++ b/relcatalogif/longtype.hh
@@ -0,0 +1,106 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+// -*-C++-*- (for Emacs)
+
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * The LongType class is the superclass for all classes
+ * describing the type of a cell
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#ifndef _LONGTYPE_HH_
+#define _LONGTYPE_HH_
+
+#include <iostream>
+#include "integraltype.hh"
+#include "catalogmgr/ops.hh"
+
+class OId;
+
+//@ManMemo: Module: {\bf relcatalogif}.
+
+/*@Doc:
+LongType is the base type used for 32bit integer cell
+values. The value of a Long is stored in four chars.
+
+*/
+
+class LongType : public IntegralType
+ {
+ public:
+ LongType(const OId& id) throw (r_Error);
+ /*@Doc:
+ */
+
+ LongType();
+ /*@Doc:
+ default constructor, sets type name to "Long".
+ */
+
+ LongType(const LongType& old);
+ /*@Doc:
+ copy constructor.
+ */
+
+ LongType& operator=(const LongType& old);
+ /*@Doc:
+ assignment operator.
+ */
+
+ virtual ~LongType();
+ /*@Doc:
+ virtual destructor.
+ */
+
+ virtual void printCell(ostream& stream, const char* cell) const;
+ /*@Doc:
+ there is concern about the MSB..LSB problem in the source code.
+ */
+
+ virtual r_Long* convertToCLong(const char* cell, r_Long* value) const;
+ /*@Doc:
+ */
+
+ virtual char* makeFromCLong(char* cell, const r_Long* value) const;
+ /*@Doc:
+ */
+
+ static const char* Name;
+
+ protected:
+
+ virtual void readFromDb() throw (r_Error);
+ /*@Doc:
+ initializes the attributes of this type.
+ there is no database activity. this is hard coded.
+ */
+
+ };
+
+#endif
diff --git a/relcatalogif/mddbasetype.hh b/relcatalogif/mddbasetype.hh
new file mode 100644
index 0000000..1e1642f
--- /dev/null
+++ b/relcatalogif/mddbasetype.hh
@@ -0,0 +1,142 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+// -*-C++-*- (for Emacs)
+
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * The MDDBaseType class is used as a type for MDDs where
+ * only the base type is specified.
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#ifndef _MDDBASETYPE_HH_
+#define _MDDBASETYPE_HH_
+
+class MDDBaseType;
+
+#include "catalogmgr/ops.hh"
+#include "mddtype.hh"
+
+class OId;
+
+//@ManMemo: Module: {\bf relcatalogif}.
+
+/*@Doc:
+ The MDDBaseType class is used as a type for MDDs when
+ only the base type is specified.
+*/
+
+class MDDBaseType : public MDDType
+ {
+ public:
+ virtual char* getTypeStructure() const;
+ /*@Doc:
+ returns a string: marray < myBaseType->getTypeStructure >
+ */
+
+ MDDBaseType(const OId& id) throw (r_Error);
+ /*@Doc:
+ constructs a MDDBaseType out of the database.
+ */
+
+ MDDBaseType(const char* newTypeName, const BaseType* newBaseType);
+ /*@Doc:
+ constructor.
+ */
+
+ MDDBaseType();
+ /*@Doc:
+ default constructor, cannot be used.
+ */
+
+
+ MDDBaseType(const char* newtypename);
+ /*@Doc:
+ */
+
+ MDDBaseType(const MDDBaseType& old);
+ /*@Doc:
+ copy constructor.
+ */
+
+ MDDBaseType& operator=(const MDDBaseType& old);
+ /*@Doc:
+ assignment operator.
+ */
+
+ const BaseType* getBaseType() const;
+ /*@Doc:
+ returns base type.
+ */
+
+ virtual void print_status( ostream& s ) const;
+ /*@Doc:
+ writes the state of the object to the specified stream:
+ \tr_Marray < myBaseType->getTypeName() \t>
+ */
+
+ virtual ~MDDBaseType();
+ /*@Doc:
+ virtual destructor.
+ validates the object.
+ */
+
+ virtual int compatibleWith(const Type* aType) const;
+ /*@Doc:
+ to be compatible the following must be true:
+ aType must be MDDBASETYPE or subclass and
+ myBaseType must be compatible with aType->myBaseType
+ */
+
+ virtual int compatibleWithDomain(const r_Minterval* aDomain) const;
+ /*@Doc:
+ create a new MDDDomainType with itself and aDomain, then it
+ checks compatibility with self.
+ */
+
+ virtual r_Bytes getMemorySize() const;
+ /*@Doc:
+ computes memory size by:
+ MDDType::getMemorySize() + myBaseType->getMemorySize() + sizeof(BaseType*);
+ */
+
+ protected:
+
+ virtual void insertInDb() throw (r_Error);
+
+ virtual void readFromDb() throw (r_Error);
+
+ virtual void deleteFromDb() throw (r_Error);
+
+ const BaseType* myBaseType;
+ /*@Doc:
+ reference to the basetype
+ */
+ };
+
+#endif
diff --git a/relcatalogif/mddbasetype.lis b/relcatalogif/mddbasetype.lis
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/relcatalogif/mddbasetype.lis
diff --git a/relcatalogif/mddbasetype.pgc b/relcatalogif/mddbasetype.pgc
new file mode 100644
index 0000000..6b4f11d
--- /dev/null
+++ b/relcatalogif/mddbasetype.pgc
@@ -0,0 +1,125 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+// This is -*- C++ -*-
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * Code with embedded SQL for PostgreSQL DBMS
+ *
+ *
+ * COMMENTS:
+ * uses embedded SQL
+ *
+ ************************************************************/
+
+// general embedded SQL related definitions
+EXEC SQL include "../reladminif/sqlglobals.h";
+
+#include "debug-srv.hh"
+#include "mddbasetype.hh"
+#include "raslib/rmdebug.hh"
+#include "reladminif/sqlerror.hh"
+#include "reladminif/externs.h"
+#include "reladminif/objectbroker.hh"
+
+void
+MDDBaseType::insertInDb() throw (r_Error)
+{
+ RMDBGENTER(6, RMDebug::module_catalogif, "MDDBaseType", "insertInDb() " << myOId << " " << getTypeName());
+ EXEC SQL BEGIN DECLARE SECTION;
+ long mddtypeid;
+ double mddbasetypeid;
+ char mddtypename[STRING_MAXLEN];
+ EXEC SQL END DECLARE SECTION;
+
+ (void) strncpy( mddtypename, (char*) getName(), (size_t) sizeof(mddtypename) );
+ DBObject* obj = (DBObject*)getBaseType();
+ mddbasetypeid = obj->getOId();
+ mddtypeid = myOId.getCounter();
+ TALK( "EXEC SQL INSERT INTO RAS_MDDBASETYPES ( MDDBaseTypeOId, MDDTypeName, BaseTypeId)"
+ << " VALUES ( " << mddtypeid << ", " << mddtypename << ", " << mddbasetypeid << ")" );
+ EXEC SQL INSERT INTO RAS_MDDBASETYPES ( MDDBaseTypeOId, MDDTypeName, BaseTypeId)
+ VALUES ( :mddtypeid, :mddtypename, :mddbasetypeid);
+ if (check("MDDBaseType::insertInDb()\0"))
+ generateException();
+ DBObject::insertInDb();
+ RMDBGEXIT(5, RMDebug::module_catalogif, "MDDBaseType", "insertInDb() " << myOId);
+}
+
+void
+MDDBaseType::readFromDb() throw (r_Error)
+{
+ RMDBGENTER(5, RMDebug::module_catalogif, "MDDBaseType", "readFromDb() " << myOId);
+#ifdef RMANBENCHMARK
+ DBObject::readTimer.resume();
+#endif
+ EXEC SQL BEGIN DECLARE SECTION;
+ long mddtypeid1;
+ char mddtypename1[STRING_MAXLEN];
+ double mddbasetypeid1;
+ EXEC SQL END DECLARE SECTION;
+
+ mddtypeid1 = myOId.getCounter();
+ mddbasetypeid1 = 0;
+
+ TALK( "EXEC SQL SELECT BaseTypeId, MDDTypeName INTO :mddbasetypeid1, :mddtypename1 "
+ << "FROM RAS_MDDBASETYPES "
+ << "WHERE MDDBaseTypeOId = " << mddtypeid1 );
+ EXEC SQL SELECT BaseTypeId, MDDTypeName INTO :mddbasetypeid1, :mddtypename1
+ FROM RAS_MDDBASETYPES
+ WHERE MDDBaseTypeOId = :mddtypeid1;
+ if (check("MDDBaseType::readFromDb() SELECT FROM RAS_MDDBASETYPES\0") != 0)
+ if (SQLCODE == 100)
+ throw r_Error(r_Error::r_Error_ObjectUnknown);
+ else
+ generateException();
+
+ setName(mddtypename1);
+ myBaseType = (BaseType*)ObjectBroker::getObjectByOId(OId(mddbasetypeid1));
+#ifdef RMANBENCHMARK
+ DBObject::readTimer.pause();
+#endif
+ DBObject::readFromDb();
+ RMDBGEXIT(5, RMDebug::module_catalogif, "MDDBaseType", "readFromDb() " << myOId);
+}
+
+void
+MDDBaseType::deleteFromDb() throw (r_Error)
+{
+ RMDBGENTER(5, RMDebug::module_catalogif, "MDDBaseType", "deleteFromDb() " << myOId << " " << getTypeName());
+ EXEC SQL BEGIN DECLARE SECTION;
+ long mddtypeid2;
+ EXEC SQL END DECLARE SECTION;
+
+ mddtypeid2 = myOId.getCounter();
+
+ TALK( "EXEC SQL DELETE FROM RAS_MDDBASETYPES WHERE MDDBaseTypeOId = " << mddtypeid2 );
+ EXEC SQL DELETE FROM RAS_MDDBASETYPES
+ WHERE MDDBaseTypeOId = :mddtypeid2;
+ if (check("MDDBaseType::deleteFromDb()\0"))
+ generateException();
+ DBObject::deleteFromDb();
+ RMDBGEXIT(5, RMDebug::module_catalogif, "MDDBaseType", "deleteFromDb() " << myOId);
+}
+
diff --git a/relcatalogif/mddbasetypecommon.cc b/relcatalogif/mddbasetypecommon.cc
new file mode 100644
index 0000000..036abe8
--- /dev/null
+++ b/relcatalogif/mddbasetypecommon.cc
@@ -0,0 +1,174 @@
+#include "mymalloc/mymalloc.h"
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+// This is -*- C++ -*-
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * code common to all database interface implementations
+ *
+ * CHANGE HISTORY (append further entries):
+ */
+
+#include <malloc.h>
+#include "raslib/rmdebug.hh"
+#include "mddbasetype.hh"
+#include "mdddomaintype.hh"
+#include "basetype.hh"
+#include <iostream>
+#include "reladminif/sqlerror.hh"
+#include "reladminif/externs.h"
+#include "reladminif/objectbroker.hh"
+#include <cstring>
+
+r_Bytes
+MDDBaseType::getMemorySize() const
+ {
+ return MDDType::getMemorySize() + myBaseType->getMemorySize() + sizeof(BaseType*);
+ }
+
+MDDBaseType::MDDBaseType(const OId& id) throw (r_Error)
+ : MDDType(id)
+ {
+ RMDBGENTER(5, RMDebug::module_catalogif, "MDDBaseType", "MDDBaseType(" << myOId << ")");
+ if (objecttype == OId::MDDBASETYPEOID)
+ {
+ mySubclass = MDDBASETYPE;
+ readFromDb();
+ }
+ RMDBGEXIT(5, RMDebug::module_catalogif, "MDDBaseType", "MDDBaseType(" << myOId << ")");
+ }
+
+MDDBaseType::MDDBaseType(const char* newTypeName, const BaseType* newBaseType)
+ : MDDType(newTypeName)
+ {
+ objecttype = OId::MDDBASETYPEOID;
+ myBaseType = newBaseType;
+ mySubclass = MDDBASETYPE;
+ }
+
+MDDBaseType::MDDBaseType()
+ : MDDType("unnamed mddbasetype")
+ {
+ objecttype = OId::MDDBASETYPEOID;
+ myBaseType = 0;
+ mySubclass = MDDBASETYPE;
+ }
+
+MDDBaseType::MDDBaseType(const char* tname)
+ : MDDType(tname)
+ {
+ objecttype = OId::MDDBASETYPEOID;
+ myBaseType = 0;
+ mySubclass = MDDBASETYPE;
+ }
+
+MDDBaseType::MDDBaseType(const MDDBaseType& old)
+ : MDDType(old)
+ {
+ myBaseType = old.myBaseType;
+ }
+
+MDDBaseType& MDDBaseType::operator=(const MDDBaseType& old)
+ {
+ // Gracefully handle self assignment
+ if (this == &old)
+ return *this;
+ MDDType::operator=(old);
+ myBaseType = old.myBaseType;
+ return *this;
+ }
+
+char*
+MDDBaseType::getTypeStructure() const
+ {
+ char* baseType = myBaseType->getTypeStructure();
+ char* result = (char*)mymalloc(10 + strlen(baseType));
+
+ strcpy(result, "marray <");
+ strcat(result, baseType);
+ strcat(result, ">");
+
+ free(baseType);
+ return result;
+ }
+
+void
+MDDBaseType::print_status( ostream& s ) const
+ {
+ s << "\tr_Marray" << "<" << myBaseType->getTypeName() << "\t>";
+ }
+
+const BaseType*
+MDDBaseType::getBaseType() const
+ {
+ return myBaseType;
+ }
+
+MDDBaseType::~MDDBaseType()
+ {
+ RMDBGENTER(5, RMDebug::module_catalogif, "MDDBaseType", "~MDDBaseType() " << myOId);
+ validate();
+ RMDBGEXIT(5, RMDebug::module_catalogif, "MDDBaseType", "~MDDBaseType() " << myOId);
+ }
+
+int
+MDDBaseType::compatibleWith(const Type* aType) const
+ {
+ RMDBGENTER(11, RMDebug::module_catalogif, "MDDBaseType", "compatibleWith(" << aType->getName() << ") " << getName());
+ int retval;
+ if( ((MDDType*)aType)->getSubtype() != MDDBASETYPE && ((MDDType*)aType)->getSubtype() != MDDDOMAINTYPE && ((MDDType*)aType)->getSubtype() != MDDDIMENSIONTYPE )
+ {
+ RMDBGMIDDLE(11, RMDebug::module_catalogif, "MDDBaseType", "not mddbasetype or subclass");
+ retval = 0;
+ }
+ else {
+ // myBaseType has to be specified
+ if( myBaseType->compatibleWith(((MDDBaseType*)aType)->getBaseType()) )
+ {
+ retval = 1;
+ }
+ else {
+ RMDBGMIDDLE(11, RMDebug::module_catalogif, "MDDBaseType", "basetypes not compatible");
+ retval = 0;
+ }
+ }
+ RMDBGEXIT(11, RMDebug::module_catalogif, "MDDBaseType", "compatibleWith(" << aType->getName() << ") " << getName() << " retval " << retval);
+ return retval;
+ }
+
+int
+MDDBaseType::compatibleWithDomain(const r_Minterval* aDomain ) const
+ {
+ RMDBGENTER(11, RMDebug::module_catalogif, "MDDBaseType", "compatibleWithDomain(" << *aDomain << ") " << getName());
+ int retval;
+
+ // create an MDDDomainType with aDomain and myBaseType
+ MDDDomainType tempType( "tempType", myBaseType, *aDomain );
+ // use normal compatibleWith
+ retval = this->compatibleWith( &tempType );
+ RMDBGEXIT(11, RMDebug::module_catalogif, "MDDBaseType", "compatibleWithDomain(" << aDomain << ") " << getName() << " retval " << retval);
+ return retval;
+ }
+
diff --git a/relcatalogif/mdddimensiontype.hh b/relcatalogif/mdddimensiontype.hh
new file mode 100644
index 0000000..293812d
--- /dev/null
+++ b/relcatalogif/mdddimensiontype.hh
@@ -0,0 +1,128 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+// -*-C++-*- (for Emacs)
+
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * The MDDBaseType class is used as a type for MDDs where
+ * the base type and the dimensionality is specified.
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#ifndef _MDDDIMENSIONTYPE_HH_
+#define _MDDDIMENSIONTYPE_HH_
+
+#include <iostream>
+#include "raslib/mddtypes.hh"
+#include "catalogmgr/ops.hh"
+#include "mddbasetype.hh"
+
+class OId;
+
+//@ManMemo: Module: {\bf relcatalogif}.
+
+/*@Doc:
+ The MDDBaseType class is used as a type for MDDs where
+ the base type and the dimensionality is specified.
+*/
+
+class MDDDimensionType : public MDDBaseType
+ {
+ public:
+ virtual char* getTypeStructure() const;
+ /*@Doc:
+ */
+
+ virtual r_Bytes getMemorySize() const;
+ /*@Doc:
+ the memory size is computed by:
+ MDDBaseType::getMemorySize() + sizeof(r_Dimension);
+ */
+
+ MDDDimensionType(const OId& id) throw (r_Error);
+ /*@Doc:
+ */
+
+ MDDDimensionType(const char* newTypeName, const BaseType* newBaseType, r_Dimension newDimension);
+ /*@Doc:
+ constructor.
+ */
+
+ MDDDimensionType();
+ /*@Doc:
+ default constructor, cannot be used.
+ */
+
+ MDDDimensionType(const MDDDimensionType& old);
+ /*@Doc:
+ copy constructor.
+ */
+
+ MDDDimensionType& operator=(const MDDDimensionType& old);
+ /*@Doc:
+ assignment operator.
+ */
+
+ virtual void print_status( ostream& s ) const;
+ /*@Doc:
+ writes the state of the object to the specified stream
+ */
+
+ r_Dimension getDimension() const;
+ /*@Doc:
+ return dimensionality
+ */
+
+ virtual ~MDDDimensionType();
+ /*@Doc:
+ virtual destructor.
+ */
+
+ virtual int compatibleWith(const Type* aType) const;
+ /*@Doc:
+ is compatible if:
+ aType is MDDDimType or MDDDomType and
+ the basetypes are compatible
+ and dimensionality is the same
+ */
+
+ protected:
+
+ virtual void insertInDb() throw (r_Error);
+
+ virtual void readFromDb() throw (r_Error);
+
+ virtual void deleteFromDb() throw (r_Error);
+
+ r_Dimension myDimension;
+ /*@Doc:
+ dimensionality.
+ */
+ };
+
+#endif
diff --git a/relcatalogif/mdddimensiontype.lis b/relcatalogif/mdddimensiontype.lis
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/relcatalogif/mdddimensiontype.lis
diff --git a/relcatalogif/mdddimensiontype.pgc b/relcatalogif/mdddimensiontype.pgc
new file mode 100644
index 0000000..c8b631c
--- /dev/null
+++ b/relcatalogif/mdddimensiontype.pgc
@@ -0,0 +1,148 @@
+#include "mymalloc/mymalloc.h"
+// This is -*- C++ -*-
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************************
+ *
+ *
+ * PURPOSE:
+ * Code with embedded SQL for PostgreSQL DBMS
+ *
+ *
+ * COMMENTS:
+ * none
+ *
+ ***********************************************************************/
+
+// general embedded SQL related definitions
+EXEC SQL include "../reladminif/sqlglobals.h";
+
+#include "mdddimensiontype.hh"
+#include "raslib/rmdebug.hh"
+#include "reladminif/objectbroker.hh"
+#include "reladminif/sqlerror.hh"
+
+void
+MDDDimensionType::insertInDb() throw (r_Error)
+{
+ RMDBGENTER(5, RMDebug::module_catalogif, "MDDDimensionType", "insertInDb() " << myOId << " " << getTypeName());
+ EXEC SQL BEGIN DECLARE SECTION;
+ long mddtypeid;
+ short dimension;
+ double mddbasetypeid;
+ char mddtypename[STRING_MAXLEN];
+ EXEC SQL END DECLARE SECTION;
+
+ dimension = myDimension;
+ mddtypeid = myOId.getCounter();
+ (void) strncpy( mddtypename, (char*) getName(), (size_t) sizeof(mddtypename) );
+ DBObject* obj = (DBObject*)getBaseType();
+ mddbasetypeid = obj->getOId();
+ RMDBGMIDDLE(5, RMDebug::module_catalogif, "MDDDimensionType", " typeid " << mddtypeid << " name " << mddtypename << " basetypeoid " << mddbasetypeid << "dimension " << dimension)
+
+ EXEC SQL INSERT INTO RAS_MDDDIMTYPES (
+ MDDDimTypeOId,
+ MDDTypeName,
+ BaseTypeId,
+ Dimension
+ )
+ VALUES (
+ :mddtypeid,
+ :mddtypename,
+ :mddbasetypeid,
+ :dimension
+ );
+ if (check("MDDDimensionType::insertInDb()\0"))
+ generateException();
+ DBObject::insertInDb();
+ RMDBGEXIT(5, RMDebug::module_catalogif, "MDDDimensionType", "insertInDb() " << myOId);
+}
+
+void
+MDDDimensionType::readFromDb() throw (r_Error)
+{
+ RMDBGENTER(5, RMDebug::module_catalogif, "MDDDimensionType", "readFromDb() " << myOId);
+#ifdef RMANBENCHMARK
+ DBObject::readTimer.resume();
+#endif
+ EXEC SQL BEGIN DECLARE SECTION;
+ long mddtypeid1;
+ char mddtypename1[STRING_MAXLEN];
+ double mddbasetypeid1;
+ short dimension1;
+ EXEC SQL END DECLARE SECTION;
+
+ mddtypeid1 = myOId.getCounter();
+ mddbasetypeid1 = 0;
+ dimension1 = 0;
+
+ EXEC SQL SELECT
+ Dimension,
+ BaseTypeId,
+ MDDTypeName
+ INTO
+ :dimension1,
+ :mddbasetypeid1,
+ :mddtypename1
+ FROM
+ RAS_MDDDIMTYPES
+ WHERE
+ MDDDimTypeOId = :mddtypeid1;
+ if (check("MDDDimensionType::MDDDimensionType() SELECT FROM RAS_MDDDIMTYPES\0") != 0)
+ if (SQLCODE == 100)
+ throw r_Error(r_Error::r_Error_ObjectUnknown);
+ else
+ generateException();
+
+ myDimension = dimension1;
+ setName(mddtypename1);
+ myBaseType = (BaseType*)ObjectBroker::getObjectByOId(OId(mddbasetypeid1));
+#ifdef RMANBENCHMARK
+ DBObject::readTimer.pause();
+#endif
+ RMDBGMIDDLE(6, RMDebug::module_catalogif, "MDDDimensionType", "myBaseType at " << myBaseType);
+ DBObject::readFromDb();
+ RMDBGEXIT(5, RMDebug::module_catalogif, "MDDDimensionType", "readFromDb() " << myOId);
+}
+
+void
+MDDDimensionType::deleteFromDb() throw (r_Error)
+{
+ RMDBGENTER(5, RMDebug::module_catalogif, "MDDDimensionType", "deleteFromDb() " << myOId << " " << getTypeName());
+ EXEC SQL BEGIN DECLARE SECTION;
+ long mddtypeid3;
+ EXEC SQL END DECLARE SECTION;
+
+ mddtypeid3 = myOId.getCounter();
+
+ EXEC SQL DELETE FROM
+ RAS_MDDDIMTYPES
+ WHERE
+ MDDDimTypeOId = :mddtypeid3;
+ if (check("MDDDimensionType::deleteFromDb()\0"))
+ generateException();
+ DBObject::deleteFromDb();
+ RMDBGEXIT(5, RMDebug::module_catalogif, "MDDDimensionType", "deleteFromDb() " << myOId);
+}
+
diff --git a/relcatalogif/mdddimensiontypecommon.cc b/relcatalogif/mdddimensiontypecommon.cc
new file mode 100644
index 0000000..dc71b06
--- /dev/null
+++ b/relcatalogif/mdddimensiontypecommon.cc
@@ -0,0 +1,166 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include "mymalloc/mymalloc.h"
+#include "raslib/rmdebug.hh"
+#include "mdddimensiontype.hh"
+#include <malloc.h>
+#include "basetype.hh"
+#include "mdddomaintype.hh"
+#include <iostream>
+#include "reladminif/sqlerror.hh"
+#include "reladminif/externs.h"
+#include "reladminif/objectbroker.hh"
+#include <stdio.h>
+#include <cstring>
+
+r_Bytes
+MDDDimensionType::getMemorySize() const
+ {
+ return MDDBaseType::getMemorySize() + sizeof(r_Dimension);
+ }
+
+MDDDimensionType::MDDDimensionType(const OId& id) throw (r_Error)
+ : MDDBaseType(id),
+ myDimension(0)
+ {
+ RMDBGENTER(4, RMDebug::module_catalogif, "MDDDimensionType", "MDDDimensionType(" << myOId << ")");
+ if (objecttype == OId::MDDDIMTYPEOID)
+ {
+ mySubclass = MDDDIMENSIONTYPE;
+ readFromDb();
+ }
+ RMDBGEXIT(4, RMDebug::module_catalogif, "MDDDimensionType", "MDDDimensionType(" << myOId << ")");
+ }
+
+MDDDimensionType::MDDDimensionType(const char* newTypeName, const BaseType* newBaseType, r_Dimension newDimension)
+ : MDDBaseType(newTypeName, newBaseType),
+ myDimension(newDimension)
+ {
+ objecttype = OId::MDDDIMTYPEOID;
+ mySubclass = MDDDIMENSIONTYPE;
+ }
+
+MDDDimensionType::MDDDimensionType()
+ : MDDBaseType("unnamed mdddimensiontype"),
+ myDimension(0)
+ {
+ objecttype = OId::MDDDIMTYPEOID;
+ mySubclass = MDDDIMENSIONTYPE;
+ }
+
+MDDDimensionType::MDDDimensionType(const MDDDimensionType& old)
+ : MDDBaseType(old)
+ {
+ objecttype = OId::MDDDIMTYPEOID;
+ myDimension = old.myDimension;
+ }
+
+MDDDimensionType&
+MDDDimensionType::operator=(const MDDDimensionType& old)
+ {
+ // Gracefully handle self assignment
+ if (this == &old)
+ return *this;
+ MDDBaseType::operator=(old);
+ myDimension = old.myDimension;
+ return *this;
+ }
+
+char*
+MDDDimensionType::getTypeStructure() const
+ {
+ char dimBuf[255];
+ sprintf(dimBuf, "%d", myDimension);
+ RMDBGENTER(10, RMDebug::module_catalogif, "MDDDimensionType", "getTypeStructure()");
+ RMDBGMIDDLE(10, RMDebug::module_catalogif, "MDDDimensionType", "myBaseType at " << myBaseType);
+ char* baseType = myBaseType->getTypeStructure();
+ RMDBGMIDDLE(10, RMDebug::module_catalogif, "MDDDimensionType", "basetype at " << baseType);
+ char* result = (char*)mymalloc(12 + strlen(baseType) + strlen(dimBuf));
+
+ strcpy(result, "marray <");
+ strcat(result, baseType);
+ strcat(result, ", ");
+ strcat(result, dimBuf);
+ strcat(result, ">");
+
+ free(baseType);
+ RMDBGEXIT(10, RMDebug::module_catalogif, "MDDDimensionType", "getTypeStructure() " << result);
+ return result;
+ }
+
+void
+MDDDimensionType::print_status( ostream& s ) const
+ {
+ s << "\tr_Marray" << "<" << myBaseType->getTypeName() << "\t, " << myDimension << ">";
+ }
+
+r_Dimension
+MDDDimensionType::getDimension() const
+ {
+ return myDimension;
+ }
+
+MDDDimensionType::~MDDDimensionType()
+ {
+ RMDBGENTER(4, RMDebug::module_catalogif, "MDDDimensionType", "~MDDDimensionType() " << myOId);
+ validate();
+ RMDBGEXIT(4, RMDebug::module_catalogif, "MDDDimensionType", "~MDDDimensionType() " << myOId);
+ }
+
+int
+MDDDimensionType::compatibleWith(const Type* aType) const
+ {
+ RMDBGENTER(5, RMDebug::module_catalogif, "MDDDimensionType", "compatibleWith(" << aType->getName() << ") " << getName());
+ int retval;
+ if( ((MDDType*)aType)->getSubtype() != MDDDOMAINTYPE && ((MDDType*)aType)->getSubtype() != MDDDIMENSIONTYPE )
+ {
+ RMDBGMIDDLE(6, RMDebug::module_catalogif, "MDDDimensionType", "not a domain- or dimensiontype");
+ retval = 0;
+ }
+ else {
+ // check BaseType first
+ if( ! (myBaseType->compatibleWith(((MDDBaseType*)aType)->getBaseType())) )
+ {
+ RMDBGMIDDLE(6, RMDebug::module_catalogif, "MDDDimensionType", "basetypes are not compatible");
+ retval = 0;
+ }
+ else {
+ // check dimensionality
+ if( ((MDDType*)aType)->getSubtype() == MDDDIMENSIONTYPE )
+ {
+ RMDBGMIDDLE(6, RMDebug::module_catalogif, "MDDDimensionType", "check for dimension equality");
+ retval = (myDimension == ((MDDDimensionType*)aType)->getDimension());
+ }
+ else {
+ if( ((MDDType*)aType)->getSubtype() == MDDDOMAINTYPE )
+ {
+ RMDBGMIDDLE(6, RMDebug::module_catalogif, "MDDDimensionType", "check for dimension equality");
+ retval = ( ((MDDDimensionType*)this)->myDimension == ((MDDDomainType*)aType)->getDomain()->dimension() );
+ }
+ }
+ }
+ }
+ RMDBGEXIT(5, RMDebug::module_catalogif, "MDDDimensionType", "compatibleWith(" << aType->getName() << ") " << getName() << " " << retval);
+ return retval;
+ }
+
diff --git a/relcatalogif/mdddomaintype.hh b/relcatalogif/mdddomaintype.hh
new file mode 100644
index 0000000..22d5352
--- /dev/null
+++ b/relcatalogif/mdddomaintype.hh
@@ -0,0 +1,137 @@
+// -*-C++-*- (for Emacs)
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * The MDDBaseType class is used as a type for MDDs where
+ * the base type and the domain is specified.
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#ifndef _MDDDOMAINTYPE_HH_
+#define _MDDDOMAINTYPE_HH_
+
+class MDDDomainType;
+
+#include <iostream>
+#include "raslib/minterval.hh"
+#include "catalogmgr/ops.hh"
+#include "mddbasetype.hh"
+#include "raslib/mddtypes.hh" //for r_Range
+
+class DBMinterval;
+class OId;
+
+//@ManMemo: Module: {\bf relcatalogif}.
+
+/*@Doc:
+ The MDDBaseType class is used as a type for MDDs where
+ the base type and the domain is specified.
+*/
+
+class MDDDomainType : public MDDBaseType
+ {
+ public:
+ virtual char* getTypeStructure() const;
+ /*@Doc:
+ looks like:
+ marray <myBaseType->getTypeStructure(), myDomain->get_string_representation()>
+ */
+
+ MDDDomainType(const OId& id) throw (r_Error);
+
+ MDDDomainType(const char* newTypeName, const BaseType* newBaseType, const r_Minterval& newDomain);
+
+ MDDDomainType();
+ /*@Doc:
+ default constructor, cannot be used.
+ */
+
+ MDDDomainType(const MDDDomainType& old);
+ /*@Doc:
+ copy constructor.
+ */
+
+ MDDDomainType& operator=(const MDDDomainType& old);
+ /*@Doc:
+ assignment operator.
+ */
+
+ const r_Minterval* getDomain() const;
+ /*@Doc:
+ returns domain.
+ */
+
+ virtual void print_status( ostream& s ) const;
+ /*@Doc:
+ writes the state of the object to the specified stream.
+ looks like: \tr_Marray<myBaseType->getTypeName(), myDomain->print_status()\t>
+ */
+
+ virtual ~MDDDomainType();
+ /*@Doc:
+ virtual destructor.
+ calls validate and deletes myDomain
+ */
+
+ virtual void setPersistent(bool t) throw (r_Error);
+ /*@Doc:
+ this method from DBObject is overridden to make sure that
+ the dbminterval is also made persistent/deleted from db.
+ */
+
+ virtual int compatibleWith(const Type* aType) const;
+ /*@Doc:
+ aType is compatible if:
+ aType is a MDDDomainType and
+ the basetypes are compatible
+ */
+
+ virtual r_Bytes getMemorySize() const;
+ /*@Doc:
+ memory space is computed by
+ MDDBaseType::getMemorySize() + sizeof(DBMinterval*)
+ + myDomain->getMemorySize();
+ */
+
+ protected:
+
+ DBMinterval* myDomain;
+ /*@Doc:
+ persistent domain.
+ */
+
+ virtual void insertInDb() throw (r_Error);
+
+ virtual void readFromDb() throw (r_Error);
+
+ virtual void deleteFromDb() throw (r_Error);
+ };
+
+#endif
diff --git a/relcatalogif/mdddomaintype.lis b/relcatalogif/mdddomaintype.lis
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/relcatalogif/mdddomaintype.lis
diff --git a/relcatalogif/mdddomaintype.pgc b/relcatalogif/mdddomaintype.pgc
new file mode 100644
index 0000000..ec2cd80
--- /dev/null
+++ b/relcatalogif/mdddomaintype.pgc
@@ -0,0 +1,143 @@
+#include "mymalloc/mymalloc.h"
+// This is -*- C++ -*-
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * Code with embedded SQL for PostgreSQL DBMS
+ *
+ *
+ * COMMENTS:
+ * uses embedded SQL
+ *
+ ************************************************************/
+
+// general embedded SQL related definitions
+EXEC SQL include "../reladminif/sqlglobals.h";
+
+#include "mdddomaintype.hh"
+#include "raslib/rmdebug.hh"
+#include "reladminif/objectbroker.hh"
+#include "reladminif/sqlerror.hh"
+#include "dbminterval.hh"
+
+
+void
+MDDDomainType::insertInDb() throw (r_Error)
+{
+ RMDBGENTER(5, RMDebug::module_catalogif, "MDDDomainType", "insertInDb() " << myOId << " " << getTypeName());
+
+ char* domstr = 0;
+ EXEC SQL BEGIN DECLARE SECTION;
+ long mddtypeid;
+ double mddbasetypeid;
+ char mddtypename[VARCHAR_MAXLEN];
+ long domainid;
+ EXEC SQL END DECLARE SECTION;
+
+ (void) strncpy( mddtypename, (char*) getName(), (size_t) sizeof(mddtypename) );
+ DBObject* obj = (DBObject*)getBaseType();
+ mddbasetypeid = obj->getOId();
+ mddtypeid = myOId.getCounter();
+ domainid = myDomain->getOId().getCounter();
+
+ EXEC SQL INSERT INTO RAS_MDDDOMTYPES ( MDDDomTypeOId, MDDTypeName, BaseTypeId, DomainId)
+ VALUES ( :mddtypeid, :mddtypename, :mddbasetypeid, :domainid);
+ if (check("MDDDomainType::insertInDb()\0"))
+ generateException();
+
+ DBObject::insertInDb();
+
+ RMDBGEXIT(5, RMDebug::module_catalogif, "MDDDomainType", "insertInDb() " << myOId);
+}
+
+void
+MDDDomainType::readFromDb() throw (r_Error)
+{
+ RMDBGENTER(5, RMDebug::module_catalogif, "MDDDomainType", "readFromDb() " << myOId);
+
+ EXEC SQL BEGIN DECLARE SECTION;
+ long mddtypeid1;
+ struct {
+ short length;
+ char data[STRING_MAXLEN];
+ } mddtypename1;
+ double mddbasetypeid1;
+ long domainid1;
+ EXEC SQL END DECLARE SECTION;
+
+ mddtypeid1 = myOId.getCounter();
+ mddbasetypeid1 = 0;
+
+ EXEC SQL SELECT BaseTypeId, MDDTypeName, DomainId
+ INTO :mddbasetypeid1, :mddtypename1, :domainid1
+ FROM RAS_MDDDOMTYPES
+ WHERE MDDDomTypeOId = :mddtypeid1;
+ if (check("MDDDomainType::MDDDomainType() SELECT FROM RAS_MDDDOMTYPES\0") != 0)
+ {
+ if (SQLCODE == 100)
+ throw r_Error(r_Error::r_Error_ObjectUnknown);
+ else
+ generateException();
+ }
+
+ setName(mddtypename1.length, mddtypename1.data);
+ myBaseType = (BaseType*)ObjectBroker::getObjectByOId(OId(mddbasetypeid1));
+ myDomain = (DBMinterval*)ObjectBroker::getObjectByOId(OId(domainid1, OId::DBMINTERVALOID));
+ myDomain->setCached(true);
+
+#ifdef RMANBENCHMARK
+ DBObject::readTimer.pause();
+#endif
+
+ DBObject::readFromDb();
+
+ RMDBGEXIT(5, RMDebug::module_catalogif, "MDDDomainType", "readFromDb() " << myOId);
+}
+
+void
+MDDDomainType::deleteFromDb() throw (r_Error)
+{
+ RMDBGENTER(5, RMDebug::module_catalogif, "MDDDomainType", "deleteFromDb() " << myOId << " " << getTypeName());
+
+ EXEC SQL BEGIN DECLARE SECTION;
+ long mddtypeid2;
+ EXEC SQL END DECLARE SECTION;
+
+ mddtypeid2 = myOId.getCounter();
+
+ EXEC SQL DELETE FROM RAS_MDDDOMTYPES
+ WHERE MDDDomTypeOId = :mddtypeid2;
+ if (check("MDDDomainType::deleteFromDb()\0"))
+ generateException();
+
+ myDomain->setPersistent(false);
+ myDomain->setCached(false);
+
+ DBObject::deleteFromDb();
+
+ RMDBGEXIT(5, RMDebug::module_catalogif, "MDDDomainType", "deleteFromDb() " << myOId);
+}
diff --git a/relcatalogif/mdddomaintypecommon.cc b/relcatalogif/mdddomaintypecommon.cc
new file mode 100644
index 0000000..0f64848
--- /dev/null
+++ b/relcatalogif/mdddomaintypecommon.cc
@@ -0,0 +1,204 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include "mymalloc/mymalloc.h"
+#include "raslib/rmdebug.hh"
+#include "mdddomaintype.hh"
+#include "mdddimensiontype.hh"
+#include "malloc.h"
+#include "basetype.hh"
+#include <iostream>
+#include "reladminif/sqlerror.hh"
+#include "reladminif/externs.h"
+#include "reladminif/objectbroker.hh"
+#include "dbminterval.hh"
+#include <cstring>
+
+r_Bytes
+MDDDomainType::getMemorySize() const
+ {
+ return MDDBaseType::getMemorySize() + sizeof(DBMinterval*) + myDomain->getMemorySize();
+ }
+
+MDDDomainType::MDDDomainType(const OId& id) throw (r_Error)
+ : MDDBaseType(id),
+ myDomain(0)
+ {
+ RMDBGENTER(4, RMDebug::module_catalogif, "MDDDomainType", "MDDDomainType(" << id <<")");
+ if (objecttype == OId::MDDDOMTYPEOID)
+ {
+ mySubclass = MDDDOMAINTYPE;
+ readFromDb();
+ }
+ RMDBGMIDDLE(8, RMDebug::module_catalogif, "MDDDomainType", "Domain\t:" << *myDomain);
+ RMDBGEXIT(4, RMDebug::module_catalogif, "MDDDomainType", "MDDDomainType(" << id <<")");
+ }
+
+MDDDomainType::MDDDomainType(const char* newTypeName, const BaseType* newBaseType, const r_Minterval& newDomain)
+ : MDDBaseType(newTypeName, newBaseType)
+ {
+ objecttype = OId::MDDDOMTYPEOID;
+ myDomain = new DBMinterval(newDomain);
+ myDomain->setCached(true);
+ mySubclass = MDDDOMAINTYPE;
+ }
+
+MDDDomainType::MDDDomainType()
+ : MDDBaseType("unnamed mdddomaintype"),
+ myDomain(0)
+ {
+ objecttype = OId::MDDDOMTYPEOID;
+ mySubclass = MDDDOMAINTYPE;
+ }
+
+MDDDomainType::MDDDomainType(const MDDDomainType& old)
+ : MDDBaseType(old)
+ {
+ throw r_Error(r_Error::r_Error_FeatureNotSupported);
+ }
+
+MDDDomainType&
+MDDDomainType::operator=(const MDDDomainType& old)
+ {
+ // Gracefully handle self assignment
+ if (this == &old)
+ return *this;
+ MDDBaseType::operator=(old);
+ if (myDomain)
+ {
+ myDomain->setPersistent(false);
+ myDomain->setCached(false);
+ delete myDomain;
+ }
+ myDomain = new DBMinterval(*old.myDomain);
+ myDomain->setCached(true);
+ return *this;
+ }
+
+char*
+MDDDomainType::getTypeStructure() const
+ {
+ char* baseType = myBaseType->getTypeStructure();
+ char* mdom = myDomain->get_string_representation();
+ char* result = (char*)mymalloc(12 + strlen(baseType) + strlen(mdom));
+
+ strcpy(result, "marray <");
+ strcat(result, baseType);
+ strcat(result, ", ");
+ strcat(result, mdom);
+ strcat(result, ">");
+ free(mdom);
+ free(baseType);
+ return result;
+ }
+
+const r_Minterval*
+MDDDomainType::getDomain() const
+ {
+ return myDomain;
+ }
+
+void
+MDDDomainType::print_status( ostream& s ) const
+ {
+ s << "\tr_Marray" << "<" << myBaseType->getTypeName() << ", ";
+ myDomain->print_status(s);
+ s << "\t>";
+ }
+
+MDDDomainType::~MDDDomainType()
+ {
+ RMDBGENTER(4, RMDebug::module_catalogif, "MDDDomainType", "~MDDDomainType() " << myOId << " " << getTypeName());
+
+ validate();
+ if (myDomain)
+ delete myDomain;
+ myDomain = 0;
+ RMDBGEXIT(4, RMDebug::module_catalogif, "MDDDomainType", "~MDDDomainType() " << myOId << " " << getTypeName());
+ }
+
+int
+MDDDomainType::compatibleWith(const Type* aType) const
+ {
+ RMDBGENTER(11, RMDebug::module_catalogif, "MDDDomainType", "compatibleWith(" << aType->getName() << ") " << getName());
+ bool retval = false;
+ if (aType->getType() == MDDTYPE)
+ {
+ MDDTypeEnum ttype = ((const MDDType*)aType)->getSubtype();
+ if (ttype == MDDDOMAINTYPE)
+ {
+ if (myBaseType->compatibleWith(((const MDDBaseType*)aType)->getBaseType()))
+ {
+ if (((const MDDDomainType*)aType)->getDomain()->dimension() == myDomain->dimension())
+ {
+ if (myDomain->covers(*((const MDDDomainType*)aType)->getDomain()))
+ {
+ retval = true;
+ }
+ else {
+ RMDBGMIDDLE(6, RMDebug::module_catalogif, "MDDDomainType", "domain marray types have incompatible domains");
+ }
+ }
+ else {
+ RMDBGMIDDLE(6, RMDebug::module_catalogif, "MDDDomainType", "domain marray types have different dimensions");
+ }
+ }
+ else {
+ RMDBGMIDDLE(6, RMDebug::module_catalogif, "MDDDomainType", "basetypes are not equal");
+ }
+ }
+ else {
+ if (ttype == MDDDIMENSIONTYPE)
+ {
+ if (myBaseType->compatibleWith(((const MDDBaseType*)aType)->getBaseType()))
+ {
+ if (myDomain->dimension() == ((const MDDDimensionType*)aType)->getDimension())
+ {
+ retval = true;
+ }
+ else {
+ RMDBGMIDDLE(6, RMDebug::module_catalogif, "MDDDomainType", "dimension marray type has wrong dimension")
+ }
+ }
+ else {
+ RMDBGMIDDLE(6, RMDebug::module_catalogif, "MDDDomainType", "basetypes are not equal");
+ }
+ }
+ else {
+ RMDBGMIDDLE(6, RMDebug::module_catalogif, "MDDDomainType", "not a dimension/domain type");
+ }
+ }
+ }
+ else {
+ RMInit::logOut << "MDDDomainType::compatibleWith() was passed a type that is not an marray type (" << aType->getName() << endl;
+ }
+ RMDBGEXIT(11, RMDebug::module_catalogif, "MDDDomainType", "compatibleWith(" << aType->getName() << ") " << getName() << " retval " << retval);
+ return retval;
+ }
+
+void
+MDDDomainType::setPersistent(bool t) throw (r_Error)
+ {
+ MDDBaseType::setPersistent(t);
+ myDomain->setPersistent(t);
+ }
+
diff --git a/relcatalogif/mddtype.hh b/relcatalogif/mddtype.hh
new file mode 100644
index 0000000..3508d7a
--- /dev/null
+++ b/relcatalogif/mddtype.hh
@@ -0,0 +1,140 @@
+// -*-C++-*- (for Emacs)
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * The MDDType class is used as a type for MDDs where nothing
+ * is specified. It also is a superclass for types for MDDs
+ * specifying more.
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#ifndef _MDDTYPE_HH_
+#define _MDDTYPE_HH_
+
+#include "catalogmgr/ops.hh"
+#include "type.hh"
+#include "raslib/minterval.hh"
+
+class OId;
+
+//@ManMemo: Module: {\bf relcatalogif}.
+
+/*@Doc:
+ The MDDType class is used as a type for MDDs where nothing
+ is specified. It also is a superclass for types for MDDs
+ specifying more.
+*/
+
+class MDDType : public Type
+ {
+ public:
+ enum MDDTypeEnum { MDDONLYTYPE, MDDBASETYPE, MDDDOMAINTYPE, MDDDIMENSIONTYPE };
+ /*@Doc:
+ enum used for runtime typing.
+ could be superceded by OId::OIdType
+ */
+
+ virtual char* getTypeStructure() const;
+ /*@Doc:
+ returns type as string:
+ marray <>
+ */
+
+ MDDType(const OId& id) throw (r_Error);
+
+ MDDType();
+ /*@Doc:
+ constructor.
+ */
+
+ MDDType(const char* newTypeName);
+ /*@Doc:
+ constructor using type name.
+ */
+
+ MDDType(const MDDType& old);
+ /*@Doc:
+ copy constructor.
+ */
+
+ MDDType& operator=(const MDDType& old);
+ /*@Doc:
+ assignment operator.
+ */
+
+ virtual void print_status( ostream& s ) const;
+ /*@Doc:
+ writes the state of the object to the specified stream:
+ \tr_Marray<>
+ */
+
+ MDDType::MDDTypeEnum getSubtype() const;
+ /*@Doc:
+ return subclass of MDDType (runtime typing)
+ */
+
+ virtual ~MDDType();
+ /*@Doc:
+ virtual destructor.
+ */
+
+ virtual int compatibleWith(const Type* aType) const;
+ /*@Doc:
+ check for compatibility of MDDTypes:
+ if aType is a MDDTYPE Type (don't confuse with MDDType!!)
+ */
+
+ virtual int compatibleWithDomain(const r_Minterval* aDomain) const;
+ /*@Doc:
+ check for compatibility with a certain domain.
+ always returns 1.
+ */
+
+ virtual r_Bytes getMemorySize() const;
+ /*@Doc:
+ the memory space is computed by:
+ sizeof(MDDType::MDDTypeEnum) + DBNamedObject::getMemorySize();
+ */
+
+ protected:
+
+ virtual void insertInDb() throw (r_Error);
+
+ virtual void readFromDb() throw (r_Error);
+
+ virtual void deleteFromDb() throw (r_Error);
+
+ MDDTypeEnum mySubclass;
+ /*@Doc:
+ used for runtime typing and comparison operation.
+ */
+ };
+
+#endif
diff --git a/relcatalogif/mddtype.lis b/relcatalogif/mddtype.lis
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/relcatalogif/mddtype.lis
diff --git a/relcatalogif/mddtype.pgc b/relcatalogif/mddtype.pgc
new file mode 100644
index 0000000..052aba6
--- /dev/null
+++ b/relcatalogif/mddtype.pgc
@@ -0,0 +1,128 @@
+// This is -*- C++ -*-
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * Code with embedded SQL for PostgreSQL DBMS
+ *
+ *
+ * COMMENTS:
+ * uses embedded SQL
+ *
+ ************************************************************/
+
+
+// general embedded SQL related definitions
+EXEC SQL include "../reladminif/sqlglobals.h";
+
+#include "mddtype.hh"
+#include "raslib/rmdebug.hh"
+#include "reladminif/sqlerror.hh"
+#include "reladminif/externs.h"
+
+
+void
+MDDType::deleteFromDb() throw (r_Error)
+{
+ RMDBGENTER(7, RMDebug::module_catalogif, "MDDType", "deleteFromDb() " << myOId << " " << getTypeName());
+ EXEC SQL BEGIN DECLARE SECTION;
+ long mddtypeid3;
+ EXEC SQL END DECLARE SECTION;
+
+ mddtypeid3 = myOId.getCounter();
+
+ EXEC SQL DELETE FROM RAS_MDDTYPES
+ WHERE RAS_MDDTYPES.MDDTypeOId = :mddtypeid3;
+ if (check("MDDType::deleteFromDb()\0"))
+ generateException();
+
+ DBObject::deleteFromDb();
+
+ RMDBGEXIT(7, RMDebug::module_catalogif, "MDDType", "deleteFromDb() " << myOId);
+}
+
+void
+MDDType::insertInDb() throw (r_Error)
+{
+ RMDBGENTER(7, RMDebug::module_catalogif, "MDDType", "insertInDb() " << myOId << " " << getTypeName());
+ EXEC SQL BEGIN DECLARE SECTION;
+ long mddtypeid;
+ char mddtypename[VARCHAR_MAXLEN];
+ EXEC SQL END DECLARE SECTION;
+
+ mddtypeid = 0;
+ (void) strncpy( mddtypename, (char*) getName(), (size_t) sizeof(mddtypename) );
+ mddtypeid = myOId.getCounter();
+ EXEC SQL INSERT INTO RAS_MDDTYPES ( MDDTypeOId, MDDTypeName)
+ VALUES ( :mddtypeid, :mddtypename);
+ if (check("MDDType::insertInDb()\0"))
+ generateException();
+
+ DBObject::insertInDb();
+
+ RMDBGEXIT(7, RMDebug::module_catalogif, "MDDType", "insertInDb() " << myOId);
+}
+
+void
+MDDType::readFromDb() throw (r_Error)
+{
+ RMDBGENTER(7, RMDebug::module_catalogif, "MDDType", "readFromDb() " << myOId);
+#ifdef RMANBENCHMARK
+ DBObject::readTimer.resume();
+#endif
+ EXEC SQL BEGIN DECLARE SECTION;
+ long mddtypeid1;
+ char mddtypename1[VARCHAR_MAXLEN];
+ EXEC SQL END DECLARE SECTION;
+
+ mddtypeid1 = myOId.getCounter();
+
+ EXEC SQL SELECT
+ MDDTypeName
+ INTO
+ :mddtypename1
+ FROM
+ RAS_MDDTYPES
+ WHERE
+ MDDTypeOId = :mddtypeid1;
+ if (check("MDDType::readFromDb()\0") != 0)
+ {
+ if (SQLCODE == SQLNODATAFOUND) // was: 100 -- PB 2005-feb-13
+ throw r_Error(r_Error::r_Error_ObjectUnknown);
+ else
+ generateException();
+ }
+
+ setName(mddtypename1);
+
+#ifdef RMANBENCHMARK
+ DBObject::readTimer.pause();
+#endif
+
+ DBObject::readFromDb();
+
+ RMDBGEXIT(7, RMDebug::module_catalogif, "MDDType", "readFromDb() " << myOId);
+}
diff --git a/relcatalogif/mddtypecommon.cc b/relcatalogif/mddtypecommon.cc
new file mode 100644
index 0000000..e1ed1dd
--- /dev/null
+++ b/relcatalogif/mddtypecommon.cc
@@ -0,0 +1,128 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include "mymalloc/mymalloc.h"
+#include <malloc.h>
+#include <iostream>
+#include <string.h>
+#include "raslib/minterval.hh"
+#include "raslib/rmdebug.hh"
+#include "reladminif/sqlerror.hh"
+#include "mddtype.hh"
+#include "reladminif/externs.h"
+
+r_Bytes
+MDDType::getMemorySize() const
+ {
+ return sizeof(MDDType::MDDTypeEnum) + DBNamedObject::getMemorySize();
+ }
+
+MDDType::MDDType(const OId& id) throw (r_Error)
+ : Type(id)
+ {
+ if (objecttype == OId::MDDTYPEOID)
+ {
+ readFromDb();
+ mySubclass = MDDONLYTYPE;
+ }
+ myType = MDDTYPE;
+ }
+
+MDDType::MDDType()
+ : Type("unnamed mddtype")
+ {
+ myType = MDDTYPE;
+ mySubclass = MDDONLYTYPE;
+ objecttype = OId::MDDTYPEOID;
+ }
+
+MDDType::MDDType(const char* newTypeName)
+ : Type(newTypeName)
+ {
+ myType = MDDTYPE;
+ mySubclass = MDDONLYTYPE;
+ objecttype = OId::MDDTYPEOID;
+ }
+
+MDDType::MDDType(const MDDType& old)
+ : Type(old)
+ {
+ myType = old.myType;
+ mySubclass = old.mySubclass;
+ }
+
+MDDType& MDDType::operator=(const MDDType& old)
+ {
+ // Gracefully handle self assignment
+ if (this == &old)
+ return *this;
+ Type::operator=(old);
+ myType = old.myType;
+ mySubclass = old.mySubclass;
+ return *this;
+ }
+
+MDDType::~MDDType()
+ {
+ RMDBGENTER(6, RMDebug::module_catalogif, "MDDType", "~MDDType() " << myOId);
+ validate();
+ RMDBGEXIT(6, RMDebug::module_catalogif, "MDDType", "~MDDType() " << myOId);
+ }
+
+char*
+MDDType::getTypeStructure() const
+ {
+ char* result = (char*)mymalloc(10);
+
+ strcpy(result, "marray <>");
+ return result;
+ }
+
+void
+MDDType::print_status( ostream& s ) const
+ {
+ s << "\tr_Marray" << "<" << ">";
+ }
+
+int
+MDDType::compatibleWith(const Type* aType) const
+ {
+ RMDBGONCE(11, RMDebug::module_catalogif, "MDDType", "compatibleWith(" << aType->getName() << ") " << (aType->getType() != MDDTYPE));
+ if(aType->getType() != MDDTYPE)
+ return 0;
+ else
+ return 1;
+ }
+
+int
+MDDType::compatibleWithDomain(const r_Minterval* aDomain ) const
+ {
+ RMDBGONCE(11, RMDebug::module_catalogif, "MDDType", "compatibleWithDomain(" << *aDomain << ") " << 1);
+ return 1;
+ }
+
+MDDType::MDDTypeEnum
+MDDType::getSubtype() const
+ {
+ return mySubclass;
+ }
+
diff --git a/relcatalogif/octettype.C b/relcatalogif/octettype.C
new file mode 100644
index 0000000..f650574
--- /dev/null
+++ b/relcatalogif/octettype.C
@@ -0,0 +1,158 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * uses ODMG-conformant O2 classes
+ *
+ *
+ * COMMENTS:
+ * none
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)catalogif,OctetType: $Header: /home/rasdev/CVS-repository/rasdaman/relcatalogif/octettype.C,v 1.9 2003/12/27 23:23:04 rasdev Exp $";
+
+#include "octettype.hh"
+#include <iomanip>
+#include <string.h>
+#include <limits.h>
+
+OctetType::OctetType(const OId& id)
+ : IntegralType(id)
+ {
+ readFromDb();
+ }
+
+/*************************************************************
+ * Method name...: OctetType();
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: initializes member variables for an
+ * OctetType.
+ ************************************************************/
+
+OctetType::OctetType()
+ : IntegralType(OctetType::Name, 1)
+ {
+ myType = OCTET;
+ myOId = OId(OCTET, OId::ATOMICTYPEOID);
+ }
+
+/*************************************************************
+ * Method name...: OctetType(const OctetType& old);
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: copy constructor
+ ************************************************************/
+
+OctetType::OctetType(const OctetType& old)
+ : IntegralType(old)
+ {
+ }
+
+/*************************************************************
+ * Method name...: operator=(const OctetType&);
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: copy constructor
+ ************************************************************/
+
+OctetType& OctetType::operator=(const OctetType& old)
+ {
+ // Gracefully handle self assignment
+ if (this == &old)
+ return *this;
+ AtomicType::operator=(old);
+ return *this;
+ }
+
+/*************************************************************
+ * Method name...: ~OctetType();
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: virtual destructor
+ ************************************************************/
+
+OctetType::~OctetType()
+{
+}
+
+/*************************************************************
+ * Method name...: void printCell( ostream& stream,
+ * const char* cell )
+ *
+ * Arguments.....:
+ * stream: stream to print on
+ * cell: pointer to cell to print
+ * Return value..: none
+ * Description...: prints a cell cell in hex on stream
+ * followed by a space.
+ * Assumes that Octet is stored MSB..LSB
+ * on HP.
+ ************************************************************/
+
+void
+OctetType::printCell( ostream& stream, const char* cell ) const
+{
+ // !!!! HP specific, assumes 1 Byte char
+ stream << std::setw(4) << (r_Long)(*(char*)cell);
+}
+
+r_Long*
+OctetType::convertToCLong(const char* cell, r_Long* value) const
+{
+ // !!!! HP specific, assumes 4 Byte long and MSB..LSB
+ // byte order
+ *value = *(char*)cell;
+ return value;
+}
+
+
+char*
+OctetType::makeFromCLong(char* cell, const r_Long* value) const
+{
+ r_Long myLong = *value;
+ // restricting long to value range of short
+ myLong = myLong > SCHAR_MAX ? SCHAR_MAX : myLong;
+ myLong = myLong < SCHAR_MIN ? SCHAR_MIN : myLong;
+ // !!!! HP specific, assumes 4 Byte long and MSB..LSB
+ // byte order
+ *(char*)(cell) = (char)myLong;
+ return cell;
+}
+
+void
+OctetType::readFromDb() throw (r_Error)
+ {
+ setName(OctetType::Name);
+ size = 1;
+ myType = OCTET;
+ myOId = OId(OCTET, OId::ATOMICTYPEOID);
+ }
+
diff --git a/relcatalogif/octettype.hh b/relcatalogif/octettype.hh
new file mode 100644
index 0000000..8a5107c
--- /dev/null
+++ b/relcatalogif/octettype.hh
@@ -0,0 +1,103 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+// -*-C++-*- (for Emacs)
+
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * The ULongType class is the superclass for all classes
+ * describing the type of a cell
+ *
+ *
+ * COMMENTS:
+ * This file is patched by O2!
+ *
+ ************************************************************/
+
+#ifndef _OCTETTYPE_HH_
+#define _OCTETTYPE_HH_
+
+#include <iostream>
+#include "integraltype.hh"
+#include "catalogmgr/ops.hh"
+
+class OId;
+
+//@ManMemo: Module: {\bf relcatalogif}.
+
+/*@Doc:
+
+OctetType is the base type used for boolean cell values (e.g. result
+of comparison operations, see \Ref{Ops}). The value of a Octet is
+stored in one char. OctetType is a persistence capable class.
+*/
+
+class OctetType : public IntegralType
+ {
+ public:
+ OctetType(const OId& id);
+
+ OctetType();
+ /*@Doc:
+ default constructor, no initialization needed for OctetType.
+ */
+
+ OctetType(const OctetType& old);
+ /*@Doc:
+ copy constructor.
+ */
+
+ OctetType& operator=(const OctetType& old);
+ /*@Doc:
+ assignment operator.
+ */
+
+ virtual ~OctetType();
+ /*@Doc:
+ virtual destructor.
+ */
+
+ virtual void printCell(ostream& stream, const char* cell) const;
+ /*@Doc:
+ */
+
+ virtual r_Long* convertToCLong(const char* cell, r_Long* value) const;
+ /*@Doc:
+ */
+
+ virtual char* makeFromCLong(char* cell, const r_Long* value) const;
+
+ static const char* Name;
+
+ protected:
+
+ virtual void readFromDb() throw (r_Error);
+ /*@Doc:
+ initializes the attributes of this type.
+ there is no database activity. this is hard coded.
+ */
+
+ };
+
+#endif
diff --git a/relcatalogif/realtype.hh b/relcatalogif/realtype.hh
new file mode 100644
index 0000000..08c9752
--- /dev/null
+++ b/relcatalogif/realtype.hh
@@ -0,0 +1,90 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * The RealType class is the superclass for floating point
+ * types (Float, Double) describing the type of a
+ * cell
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#ifndef _REALTYPE_HH_
+#define _REALTYPE_HH_
+
+#include "atomictype.hh"
+
+//@ManMemo: Module: {\bf relcatalogif}.
+
+/*@Doc:
+RealType is the abstract base class for floating point
+\Ref{BaseType} subclasses, \Ref{Float} or \Ref{Double}.
+It provides conversions to/from long and unsigned long
+It's subclasses must implement conversions to/from double
+*/
+
+class RealType : public AtomicType {
+public:
+ RealType(unsigned int newSize):
+ AtomicType(newSize) {}
+ /*@Doc:
+ constructor.
+ */
+
+ RealType(const RealType& old):
+ AtomicType(old) {}
+ /*@Doc:
+ copy constructor.
+ */
+
+ RealType(const OId& id) throw (r_Error):
+ AtomicType(id) {}
+ /*@Doc:
+ */
+
+ virtual ~RealType() {}
+ /*@Doc:
+ */
+
+ virtual r_ULong* convertToCULong(const char*, r_ULong*) const;
+ virtual char* makeFromCULong(char*, const r_ULong*) const;
+
+ virtual r_Long* convertToCLong(const char*, r_Long*) const;
+ virtual char* makeFromCLong(char*, const r_Long*) const;
+
+protected:
+ RealType(const char* name, unsigned int newSize):
+ AtomicType(name, newSize) {}
+ /*@Doc:
+ */
+};
+
+#include "realtype.icc"
+
+#endif
+
+
diff --git a/relcatalogif/realtype.icc b/relcatalogif/realtype.icc
new file mode 100644
index 0000000..6460e24
--- /dev/null
+++ b/relcatalogif/realtype.icc
@@ -0,0 +1,52 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+*
+*
+* COMMENTS:
+*
+************************************************************/
+
+inline r_ULong*
+RealType::convertToCULong(const char* cell, r_ULong* value) const {
+ double tmp;
+ *value = (r_ULong) *this->convertToCDouble(cell, &tmp);
+ return value;
+}
+
+inline r_Long*
+RealType::convertToCLong(const char* cell, r_Long* value) const {
+ return (r_Long*)(this->convertToCULong(cell, (r_ULong *)value));
+}
+
+inline char*
+RealType::makeFromCULong(char* cell, const r_ULong* value) const {
+ double tmp = *value;
+ return this->makeFromCDouble(cell, &tmp);
+}
+
+inline char*
+RealType::makeFromCLong(char* cell, const r_Long* value) const {
+ return this->makeFromCULong(cell, (r_ULong *)value);
+}
+
diff --git a/relcatalogif/settype.hh b/relcatalogif/settype.hh
new file mode 100644
index 0000000..7c62200
--- /dev/null
+++ b/relcatalogif/settype.hh
@@ -0,0 +1,82 @@
+// -*-C++-*- (for Emacs)
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * The SetType class represents the type for sets of MDD
+ * objects.
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#ifndef _SETTYPE_HH_
+#define _SETTYPE_HH_
+
+class SetType;
+
+#include <iostream>
+#include "collectiontype.hh"
+#include "catalogmgr/ops.hh"
+class OId;
+
+//@ManMemo: Module: {\bf relcatalogif}.
+
+/*@Doc:
+ The SetType class represents the type for sets of MDD
+ objects.
+*/
+
+class SetType : public CollectionType
+{
+public:
+ SetType(const OId& id) throw (r_Error);
+
+ virtual char* getTypeStructure() const;
+
+ /// constructor receiving pointer to an MDDType (or subclass).
+ SetType(const char* newTypeName, const MDDType* newMDDType);
+ /// default constructor, cannot be used.
+ SetType();
+ /// copy constructor.
+ SetType(const SetType& old);
+ /// assignment operator.
+ SetType& operator=(const SetType& old);
+
+ /// virtual destructor.
+ virtual ~SetType();
+
+protected:
+
+ virtual void deleteFromDb() throw (r_Error);
+
+ virtual void insertInDb() throw (r_Error);
+
+ virtual void readFromDb() throw (r_Error);
+};
+
+#endif
diff --git a/relcatalogif/settype.lis b/relcatalogif/settype.lis
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/relcatalogif/settype.lis
diff --git a/relcatalogif/settype.pgc b/relcatalogif/settype.pgc
new file mode 100644
index 0000000..4d8ba82
--- /dev/null
+++ b/relcatalogif/settype.pgc
@@ -0,0 +1,140 @@
+// This is -*- C++ -*-
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * Code with embedded SQL for PostgreSQL DBMS
+ *
+ *
+ * COMMENTS:
+ * uses embedded SQL
+ *
+ ************************************************************/
+
+#include "debug-srv.hh"
+
+// general embedded SQL related definitions
+EXEC SQL include "../reladminif/sqlglobals.h";
+
+#include "settype.hh"
+#include "mddtype.hh"
+#include "reladminif/sqlerror.hh"
+#include "raslib/rmdebug.hh"
+#include "reladminif/objectbroker.hh"
+
+void
+SetType::insertInDb() throw (r_Error)
+{
+ RMDBGENTER(5, RMDebug::module_catalogif, "SetType", "insertInDb() " << myOId << " " << getTypeName());
+
+ EXEC SQL BEGIN DECLARE SECTION;
+ double mddtypeid;
+ char settypename[VARCHAR_MAXLEN];
+ long settypeid;
+ EXEC SQL END DECLARE SECTION;
+
+ (void) strncpy( settypename, (char*) getTypeName(), (size_t) sizeof(settypename) );
+ settypeid = myOId.getCounter();
+ mddtypeid = getMDDType()->getOId();
+
+ // TALK( "EXEC SQL INSERT INTO RAS_SETTYPES ( SetTypeId, SetTypeName, MDDTypeOId) VALUES( " << settypeid << ", " << settypename << ", " << mddtypeid << " )" );
+ EXEC SQL INSERT INTO RAS_SETTYPES ( SetTypeId, SetTypeName, MDDTypeOId)
+ VALUES ( :settypeid, :settypename, :mddtypeid);
+ if (SQLCODE != SQLOK)
+ {
+ check("SetType::insertInDb()");
+ LEAVE("SetType::insertInDb() error: " << SQLCODE );
+ generateException();
+ }
+
+ DBObject::insertInDb();
+
+ RMDBGEXIT(5, RMDebug::module_catalogif, "SetType", "insertInDb() " << myOId);
+}
+
+void
+SetType::deleteFromDb() throw (r_Error)
+{
+ RMDBGENTER(5, RMDebug::module_catalogif, "SetType", "deleteFromDb() " << myOId << " " << getTypeName());
+ EXEC SQL BEGIN DECLARE SECTION;
+ long settypeid3;
+ EXEC SQL END DECLARE SECTION;
+
+ settypeid3 = myOId.getCounter();
+
+ TALK( "EXEC SQL DELETE FROM RAS_SETTYPES WHERE RAS_SETTYPES.SetTypeId = " << settypeid3 );
+ EXEC SQL DELETE FROM RAS_SETTYPES WHERE RAS_SETTYPES.SetTypeId = :settypeid3;
+ if (SQLCODE != SQLOK)
+ {
+ check("SetType::deleteFromDb()");
+ LEAVE("SetType::deleteFromDb() error: " << SQLCODE );
+ generateException();
+ }
+ DBObject::deleteFromDb();
+ RMDBGEXIT(5, RMDebug::module_catalogif, "SetType", "deleteFromDb() " << myOId);
+}
+
+void
+SetType::readFromDb() throw (r_Error)
+{
+ RMDBGENTER(5, RMDebug::module_catalogif, "SetType", "readFromDb() " << myOId);
+#ifdef RMANBENCHMARK
+ DBObject::readTimer.resume();
+#endif
+ EXEC SQL BEGIN DECLARE SECTION;
+ double mddtypeid1;
+ char settypename1[VARCHAR_MAXLEN];
+ long settypeid1;
+ EXEC SQL END DECLARE SECTION;
+
+ settypeid1 = myOId.getCounter();
+ mddtypeid1 = 0;
+
+ TALK( "EXEC SQL SELECT SetTypeName, MDDTypeOId INTO :settypename1, :mddtypeid1 FROM RAS_SETTYPES WHERE SetTypeId = " << settypeid1 );
+ EXEC SQL SELECT SetTypeName, MDDTypeOId
+ INTO :settypename1, :mddtypeid1
+ FROM RAS_SETTYPES
+ WHERE SetTypeId = :settypeid1;
+ if (check("SetType::readFromDb()") != 0)
+ {
+ if (SQLCODE == SQLNODATAFOUND) // was: 100 -- PB 2005-feb-13
+ throw r_Error(r_Error::r_Error_ObjectUnknown);
+ else
+ generateException();
+ }
+
+ setName(settypename1);
+ myType = SETTYPE;
+ myMDDType = (MDDType*)ObjectBroker::getObjectByOId(OId(mddtypeid1));
+ DBObject::readFromDb();
+
+#ifdef RMANBENCHMARK
+ DBObject::readTimer.pause();
+#endif
+
+ RMDBGEXIT(5, RMDebug::module_catalogif, "SetType", "readFromDb() " << myOId);
+}
+
diff --git a/relcatalogif/settypecommon.cc b/relcatalogif/settypecommon.cc
new file mode 100644
index 0000000..c05e74c
--- /dev/null
+++ b/relcatalogif/settypecommon.cc
@@ -0,0 +1,89 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include "mymalloc/mymalloc.h"
+#include <malloc.h>
+#include "settype.hh"
+#include <stdlib.h>
+#include <string.h>
+#include "reladminif/sqlerror.hh"
+#include "reladminif/externs.h"
+#include "raslib/rmdebug.hh"
+#include "reladminif/objectbroker.hh"
+#include "mddtype.hh"
+
+
+SetType::SetType(const OId& id) throw (r_Error)
+ : CollectionType(id)
+ {
+ objecttype = OId::SETTYPEOID;
+ readFromDb();
+ }
+
+char*
+SetType::getTypeStructure() const
+ {
+ char* dummy = myMDDType->getTypeStructure();
+ char* result = (char*)mymalloc(5 + strlen(dummy) + 2);
+
+ strcpy(result, "set <");
+ strcat(result, dummy);
+ strcat(result, ">");
+
+ free(dummy);
+ return result;
+ }
+
+SetType::SetType(const char* newTypeName, const MDDType* newMDDType)
+ : CollectionType(newTypeName, newMDDType)
+ {
+ myType = SETTYPE;
+ objecttype = OId::SETTYPEOID;
+ }
+
+SetType::SetType(const SetType& old)
+ : CollectionType(old)
+ {
+ }
+
+SetType& SetType::operator=(const SetType& old)
+ {
+ // Gracefully handle self assignment
+ if (this == &old)
+ return *this;
+ CollectionType::operator=(old);
+ return *this;
+ }
+
+SetType::SetType()
+ : CollectionType("unnamed settype")
+ {
+ myType = SETTYPE;
+ objecttype = OId::SETTYPEOID;
+ }
+
+SetType::~SetType()
+ {
+ RMDBGENTER(4, RMDebug::module_catalogif, "SetType", "~SetType() " << myOId);
+ validate();
+ RMDBGEXIT(4, RMDebug::module_catalogif, "SetType", "~SetType() " << myOId);
+ }
diff --git a/relcatalogif/shorttype.C b/relcatalogif/shorttype.C
new file mode 100644
index 0000000..4827243
--- /dev/null
+++ b/relcatalogif/shorttype.C
@@ -0,0 +1,153 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * uses ODMG-conformant O2 classes
+ *
+ *
+ * COMMENTS:
+ * none
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)catalogif,ShortType: $Header: /home/rasdev/CVS-repository/rasdaman/relcatalogif/shorttype.C,v 1.11 2003/12/27 23:23:04 rasdev Exp $";
+
+#include "shorttype.hh"
+#include <iomanip>
+#include <limits.h>
+#include <string.h>
+
+ShortType::ShortType(const OId& id) throw (r_Error)
+ :IntegralType(id)
+ {
+ readFromDb();
+ }
+
+/*************************************************************
+ * Method name...: ShortType();
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: initializes member variables for an
+ * ShortType.
+ ************************************************************/
+
+ShortType::ShortType()
+ : IntegralType(ShortType::Name, 2)
+ {
+ myType = SHORT;
+ myOId = OId(SHORT, OId::ATOMICTYPEOID);
+ }
+
+/*************************************************************
+ * Method name...: ShortType(const ShortType& old);
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: copy constructor
+ ************************************************************/
+
+ShortType::ShortType(const ShortType& old)
+ : IntegralType(old)
+ {
+ }
+
+/*************************************************************
+ * Method name...: operator=(const ShortType&);
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: copy constructor
+ ************************************************************/
+
+ShortType& ShortType::operator=(const ShortType& old)
+ {
+ // Gracefully handle self assignment
+ if (this == &old)
+ return *this;
+ AtomicType::operator=(old);
+ return *this;
+ }
+
+/*************************************************************
+ * Method name...: ~ShortType();
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: virtual destructor
+ ************************************************************/
+
+ShortType::~ShortType()
+{
+}
+
+/*************************************************************
+ * Method name...: void printCell( ostream& stream,
+ * const char* cell )
+ *
+ * Arguments.....:
+ * stream: stream to print on
+ * cell: pointer to cell to print
+ * Return value..: none
+ * Description...: prints a cell cell in hex on stream
+ * followed by a space.
+ * Assumes that Short is stored MSB..LSB
+ * on HP.
+ ************************************************************/
+
+void
+ShortType::printCell( ostream& stream, const char* cell ) const
+{
+ stream << std::setw(5) << *(short*)cell;
+}
+
+r_Long*
+ShortType::convertToCLong(const char* cell, r_Long* value) const
+{
+ *value = *(short*)cell;
+ return value;
+}
+
+
+char*
+ShortType::makeFromCLong(char* cell, const r_Long* value) const
+{
+ r_Long myLong = *value;
+ // restricting long to value range of short
+ myLong = myLong > SHRT_MAX ? SHRT_MAX : myLong;
+ myLong = myLong < SHRT_MIN ? SHRT_MIN : myLong;
+ // !!!! HP specific, assumes 2 Byte short
+ *(short*)(cell) = (short)myLong;
+ return cell;
+}
+
+void
+ShortType::readFromDb() throw (r_Error)
+ {
+ setName(ShortType::Name);
+ myType = SHORT;
+ size = 2;
+ myOId = OId(SHORT, OId::ATOMICTYPEOID);
+ }
diff --git a/relcatalogif/shorttype.hh b/relcatalogif/shorttype.hh
new file mode 100644
index 0000000..75b701e
--- /dev/null
+++ b/relcatalogif/shorttype.hh
@@ -0,0 +1,104 @@
+// -*-C++-*- (for Emacs)
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * The ShortType class is the superclass for all classes
+ * describing the type of a cell
+ *
+ *
+ * COMMENTS:
+ * This file is patched by O2!
+ *
+ ************************************************************/
+
+#ifndef _SHORTTYPE_HH_
+#define _SHORTTYPE_HH_
+
+#include <iostream>
+#include "integraltype.hh"
+#include "catalogmgr/ops.hh"
+
+class OId;
+
+//@ManMemo: Module: {\bf relcatalogif}.
+
+/*@Doc:
+ShortType is the base type used for 16bit integer cell
+values. The value of a Short is stored in four chars.
+
+*/
+
+class ShortType : public IntegralType
+ {
+ public:
+ ShortType(const OId& id) throw (r_Error);
+
+ ShortType();
+ /*@Doc:
+ default constructor, sets type name to "Short".
+ */
+
+ ShortType(const ShortType& old);
+ /*@Doc:
+ copy constructor.
+ */
+
+ ShortType& operator=(const ShortType& old);
+ /*@Doc:
+ assignment operator.
+ */
+
+ virtual ~ShortType();
+ /*@Doc:
+ virtual destructor.
+ */
+
+ virtual void printCell(ostream& stream, const char* cell) const;
+ /*@Doc:
+ */
+
+ virtual r_Long* convertToCLong(const char* cell, r_Long* value) const;
+ /*@Doc:
+ */
+
+ virtual char* makeFromCLong(char* cell, const r_Long* value) const;
+ /*@Doc:
+ */
+
+ static const char* Name;
+
+ protected:
+
+ virtual void readFromDb() throw (r_Error);
+ /*@Doc:
+ initializes the attributes of this type.
+ there is no database activity. this is hard coded.
+ */
+
+ };
+
+#endif
diff --git a/relcatalogif/structtype.hh b/relcatalogif/structtype.hh
new file mode 100644
index 0000000..7adbfc2
--- /dev/null
+++ b/relcatalogif/structtype.hh
@@ -0,0 +1,173 @@
+// -*-C++-*- (for Emacs)
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * The StructType class is the superclass for all classes
+ * describing the type of a cell
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#ifndef _STRUCTTYPE_HH_
+#define _STRUCTTYPE_HH_
+
+#include <iostream>
+#include <vector>
+
+#include "compositetype.hh"
+#include "catalogmgr/ops.hh"
+
+class BaseType;
+
+//@ManMemo: Module: {\bf relcatalogif}.
+
+/*@Doc:
+StructType is the base type used for user defined structures. It
+stores the names and BaseTypes of the elements. The size of a
+StructType in chars depends on the elements.
+
+StructType now uses alignment for structures with elements of
+different sizes. One byte types are aligned to one byte, two byte
+types to two, all other types to four. The Size is padded to 4 byte
+alignment except for types with only chars (one byte alignment) or
+type with only shorts (two byte alignment). Structs as elements of
+structs are aligned with the minimum byte alignment needed for the
+struct.
+
+*/
+
+class StructType : public CompositeType
+ {
+ // friend ostream& operator << (ostream& stream, StructType& b);
+
+ public:
+ virtual void printCell(ostream& stream, const char* cell) const;
+
+ virtual char* getTypeStructure() const;
+
+ /// add new element to struct
+ unsigned int addElement(const char* elemName, const char* elemType);
+
+ /// add new element to struct using pointer to BaseType
+ unsigned int addElement(const char* elemName, const BaseType* elemType);
+
+ /// get offset for an element by name of element.
+ unsigned int getOffset(const char* elemName) const;
+
+ /// get offset for an element by number of element (0 based).
+ unsigned int getOffset(unsigned int num) const;
+
+ /// get type of an element by name of element.
+ const BaseType* getElemType(const char* elemName) const;
+
+ /// get name of an element by number of element (0 based).
+ const char* const getElemName(unsigned int num) const;
+
+ /// get type of an element by number of element (0 based).
+ const BaseType* getElemType(unsigned int num) const;
+
+ /// get number of elements.
+ unsigned int getNumElems() const;
+
+ /// get alignment needed for structure to be embedded in another structure.
+ unsigned int getAlignment() const;
+
+ /// checks if a certain StructType is contained in this StructType
+ int contains(const StructType* aStruct) const;
+
+ StructType(const OId& structtypeid) throw (r_Error);
+
+ /// default constructor, sets type name to "".
+ StructType();
+
+ /// constructor getting type name and number of elements.
+ StructType(const char* newTypeName, unsigned int numElem );
+
+ /// copy constructor.
+ StructType( const StructType& old );
+
+ /// assignment operator.
+ StructType& operator=( const StructType& old );
+
+ /// virtual destructor.
+ virtual ~StructType();
+
+ virtual int compatibleWith(const Type* aType) const;
+
+ virtual r_Bytes getMemorySize() const;
+
+private:
+ // those inherited from BaseType aren't useful at all for StructType
+ // made them private to preven calling them
+ virtual r_ULong* convertToCULong(const char* cell, r_ULong* value) const;
+ virtual char* makeFromCULong(char* cell, const r_ULong* value) const;
+ virtual r_Long* convertToCLong(const char* cell, r_Long* value) const;
+ virtual char* makeFromCLong(char* cell, const r_Long* value) const;
+ virtual double* convertToCDouble(const char* cell, double* value) const;
+ virtual char* makeFromCDouble(char* cell, const double* value) const;
+
+
+ protected:
+
+ virtual void insertInDb() throw (r_Error);
+
+ virtual void deleteFromDb() throw (r_Error);
+
+ virtual void readFromDb() throw (r_Error);
+
+ // moves back one step all elements all elements behind pos
+ void moveBack(int pos);
+
+ // calculates and sets current size of type with alignment
+ void calcSize();
+
+ /// Array containing references to base types of elements.
+ std::vector< const BaseType* > elements;
+
+ /// Array containing names of elements.
+ std::vector< char* > elementNames;
+
+ /// Array containing offsets to elements
+ std::vector< unsigned int > elementOffsets;
+
+ /// The number of elements.
+ unsigned int numElems;
+
+ /// Alignment needed for structure if embedded in other structures.
+ unsigned int align;
+
+ /// add new element to struct using pointer to BaseType
+ /// does the actuall adding. the public method will not let a persitent type
+ /// be changed
+ unsigned int addElementPriv(const char* elemName, const BaseType* elemType);
+ };
+
+#include "structtype.icc"
+
+#endif
diff --git a/relcatalogif/structtype.icc b/relcatalogif/structtype.icc
new file mode 100644
index 0000000..788d996
--- /dev/null
+++ b/relcatalogif/structtype.icc
@@ -0,0 +1,54 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+*
+*
+* COMMENTS:
+*
+************************************************************/
+
+// those would better throw an exception
+
+inline r_ULong* StructType::convertToCULong(const char* cell, r_ULong* value) const {
+ return 0;
+}
+
+inline char* StructType::makeFromCULong(char* cell, const r_ULong* value) const {
+ return 0;
+}
+
+inline r_Long* StructType::convertToCLong(const char* cell, r_Long* value) const {
+ return 0;
+}
+
+inline char* StructType::makeFromCLong(char* cell, const r_Long* value) const {
+ return 0;
+}
+
+inline double* StructType::convertToCDouble(const char* cell, double* value) const {
+ return 0;
+}
+
+inline char* StructType::makeFromCDouble(char* cell, const double* value) const {
+ return 0;
+}
diff --git a/relcatalogif/structtype.lis b/relcatalogif/structtype.lis
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/relcatalogif/structtype.lis
diff --git a/relcatalogif/structtype.pgc b/relcatalogif/structtype.pgc
new file mode 100644
index 0000000..d1d1e24
--- /dev/null
+++ b/relcatalogif/structtype.pgc
@@ -0,0 +1,214 @@
+#include "mymalloc/mymalloc.h"
+// This is -*- C++ -*-
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * Code with embedded SQL for PostgreSQL DBMS
+ *
+ *
+ * COMMENTS:
+ * uses embedded SQL
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)catalogif,StructType: $Header: /home/rasdev/CVS-repository/rasdaman/relcatalogif/structtype.ec,v 1.4 2003/12/27 23:23:04 rasdev Exp $";
+
+// general embedded SQL related definitions
+EXEC SQL include "../reladminif/sqlglobals.h";
+
+#include "debug-srv.hh"
+#include "structtype.hh"
+#include "raslib/rmdebug.hh"
+#include "reladminif/sqlerror.hh"
+#include "reladminif/externs.h"
+#include "reladminif/objectbroker.hh"
+
+
+void
+StructType::insertInDb() throw (r_Error)
+{
+ RMDBGENTER(5, RMDebug::module_catalogif, "StructType", "insertInDb() " << myOId);
+ EXEC SQL BEGIN DECLARE SECTION;
+ long structtypeid;
+ char structtypename[VARCHAR_MAXLEN];
+ double elementtype;
+ char elementname[VARCHAR_MAXLEN];
+ short count;
+ EXEC SQL END DECLARE SECTION;
+
+ (void) strncpy( structtypename, (char*) getTypeName(), (size_t) sizeof(structtypename) );
+ structtypeid = myOId.getCounter();
+
+ TALK( "EXEC SQL INSERT INTO RAS_BASETYPENAMES ( BaseTypeId, BaseTypeName) VALUES ( " << structtypeid << ", " << structtypename << ")" );
+ EXEC SQL INSERT INTO RAS_BASETYPENAMES ( BaseTypeId, BaseTypeName)
+ VALUES ( :structtypeid, :structtypename);
+ if (SQLCODE != SQLOK)
+ {
+ check("StructType::insertInDb() INSERT INTO RAS_BASETYPENAMES");
+ LEAVE("StructType::insertInDb() INSERT INTO RAS_BASETYPENAMES error: " << SQLCODE );
+ generateException();
+ }
+
+ for (count = 0; count < getNumElems(); count++)
+ {
+ (void) strncpy( elementname, (char*) getElemName(count), (size_t) sizeof(elementname) );
+ //should not be necessary because of TypeFactory::addType()
+ DBObject* obj = (DBObject*)getElemType(count);
+
+ elementtype = obj->getOId();
+ RMDBGMIDDLE(6, RMDebug::module_catalogif, "StructType", "element " << count << ". id\t:" << elementtype);
+
+ TALK( "EXEC SQL INSERT INTO RAS_BASETYPES ( BaseTypeId, ContentType, Count, ContentTypeName) VALUES ( " << structtypeid << ", " << elementtype << ", " << count << ", " << elementname << ")" );
+ EXEC SQL INSERT INTO RAS_BASETYPES ( BaseTypeId, ContentType, Count, ContentTypeName )
+ VALUES ( :structtypeid, :elementtype, :count, :elementname);
+ if (SQLCODE != SQLOK)
+ {
+ check("StructType::insertInDb() INSERT INTO RAS_BASETYPES");
+ LEAVE("StructType::insertInDb() INSERT INTO RAS_BASETYPES error: " << SQLCODE );
+ generateException();
+ }
+ }
+ DBObject::insertInDb();
+ RMDBGEXIT(5, RMDebug::module_catalogif, "StructType", "insertInDb()");
+}
+
+void
+StructType::deleteFromDb() throw (r_Error)
+{
+ RMDBGENTER(5, RMDebug::module_catalogif, "StructType", "deleteFromDb() " << myOId);
+ EXEC SQL BEGIN DECLARE SECTION;
+ long basetypeid3;
+ EXEC SQL END DECLARE SECTION;
+
+ basetypeid3 = myOId.getCounter();
+
+ TALK( "EXEC SQL DELETE FROM RAS_BASETYPENAMES WHERE BaseTypeId = " << basetypeid3 );
+ EXEC SQL DELETE FROM RAS_BASETYPENAMES
+ WHERE BaseTypeId = :basetypeid3;
+ if (SQLCODE != SQLOK)
+ {
+ check("StructType::deleteFromDb() DELETE FROM RAS_BASETYPENAMES");
+ LEAVE("StructType::deleteFromDb() DELETE FROM RAS_BASETYPENAMES error: " << SQLCODE );
+ generateException();
+ }
+
+ TALK( "EXEC SQL DELETE FROM RAS_BASETYPES WHERE BaseTypeId = " << basetypeid3 );
+ EXEC SQL DELETE FROM RAS_BASETYPES
+ WHERE BaseTypeId = :basetypeid3;
+ if (SQLCODE != SQLOK)
+ {
+ check("StructType::deleteFromDb() DELETE FROM RAS_BASETYPES");
+ LEAVE("StructType::deleteFromDb() DELETE FROM RAS_BASETYPES error: " << SQLCODE );
+ generateException();
+ }
+
+ DBObject::deleteFromDb();
+ RMDBGEXIT(5, RMDebug::module_catalogif, "StructType", "deleteFromDb() " << myOId);
+}
+
+void
+StructType::readFromDb() throw (r_Error)
+{
+ RMDBGENTER(5, RMDebug::module_catalogif, "StructType", "readFromDb() " << myOId);
+ short count = 0;
+
+ EXEC SQL BEGIN DECLARE SECTION;
+ long basetypeid1;
+ double elementtypeid1;
+ char basetypename1[VARCHAR_MAXLEN];
+ char elementname1[VARCHAR_MAXLEN];
+ long count1; // added PB 2005­jan-09
+ EXEC SQL END DECLARE SECTION;
+
+ basetypeid1 = myOId.getCounter();
+
+ TALK( "EXEC SQL SELECT BaseTypeName INTO :basetypename1 FROM RAS_BASETYPENAMES WHERE BaseTypeId = " << basetypeid1 );
+ EXEC SQL SELECT BaseTypeName
+ INTO :basetypename1
+ FROM RAS_BASETYPENAMES
+ WHERE BaseTypeId = :basetypeid1;
+ if (SQLCODE != SQLOK)
+ {
+ check("StructType::readFromDb() SELECT FROM RAS_BASETYPENAMES");
+ LEAVE("StructType::readFromDb() SELECT FROM RAS_BASETYPENAMES error: " << SQLCODE );
+ if (SQLCODE == SQLNODATAFOUND) // was: 100 -- PB 2005-feb-13
+ throw r_Error(r_Error::r_Error_ObjectUnknown);
+ else
+ generateException();
+ }
+
+ setName(basetypename1);
+
+ TALK( "EXEC SQL DECLARE c CURSOR FOR SELECT ContentTypeName, ContentType, Count FROM RAS_BASETYPES WHERE BaseTypeId = " << basetypeid1 << " ORDER BY Count" );
+ EXEC SQL DECLARE c CURSOR FOR
+ SELECT ContentTypeName, ContentType, Count
+ FROM RAS_BASETYPES
+ WHERE BaseTypeId = :basetypeid1
+ ORDER BY Count;
+ if (SQLCODE != SQLOK)
+ {
+ check("StructType::readFromDb() DECLARE");
+ LEAVE("StructType::readFromDb() DECLARE error: " << SQLCODE );
+ }
+
+ TALK( "EXEC SQL OPEN c" );
+ EXEC SQL OPEN c;
+ check("StructType::readFromDb() OPEN");
+
+ do
+ {
+ memset(elementname1, 0, VARCHAR_MAXLEN);
+ // bug fix (FIXME: what about other DBMSs?), was this: -- PB 2005-jan-09
+ // EXEC SQL FETCH c INTO :elementname1, :elementtypeid1;
+ TALK( "EXEC SQL FETCH c INTO :elementname1, :elementtypeid1, :count1;" )
+ EXEC SQL FETCH c INTO :elementname1, :elementtypeid1, :count1;
+ if (SQLCODE != SQLOK)
+ {
+ if (SQLCODE != SQLNODATAFOUND) // was: 100 -- PB 2005-feb-13
+ {
+ check("StructType::readFromDb() FETCH");
+ cout << "FETCHED " << count << endl;
+ TALK( "EXEC SQL CLOSE c" );
+ EXEC SQL CLOSE c;
+ TALK( "EXEC SQL FREE c" );
+ EXEC SQL FREE c;
+ generateException();
+ }
+ break;
+ }
+ RMDBGMIDDLE(7, RMDebug::module_catalogif, "StructType", count << ". contenttypeid is " << elementtypeid1 << " elementname is " << elementname1);
+ addElementPriv((char*)elementname1, (BaseType*)ObjectBroker::getObjectByOId(OId(elementtypeid1)));
+ count++;
+ } while (1); // FIXME: make it (SQLCODE == SQLOK)
+
+ TALK( "EXEC SQL CLOSE c" );
+ EXEC SQL CLOSE c;
+
+ DBObject::readFromDb();
+
+ RMDBGEXIT(5, RMDebug::module_catalogif, "StructType", "readFromDb() " << myOId);
+}
+
diff --git a/relcatalogif/structtypecommon.cc b/relcatalogif/structtypecommon.cc
new file mode 100644
index 0000000..8c6acaa
--- /dev/null
+++ b/relcatalogif/structtypecommon.cc
@@ -0,0 +1,511 @@
+#include "mymalloc/mymalloc.h"
+// This is -*- C++ -*-
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ * code common to all database interface implementations
+ */
+#include "structtype.hh"
+#include "catalogmgr/typefactory.hh"
+#include <iomanip>
+#include <stdlib.h>
+#include "reladminif/sqlerror.hh"
+#include "reladminif/externs.h"
+#include "raslib/rmdebug.hh"
+#include "reladminif/objectbroker.hh"
+#include "raslib/error.hh"
+
+#include <cstring>
+
+/*************************************************************
+ * Method name...: StructType();
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: initializes member variables for an
+ * StructType.
+ ************************************************************/
+
+r_Bytes
+StructType::getMemorySize() const
+ {
+ r_Bytes retval = DBNamedObject::getMemorySize() + sizeof(int) + sizeof(int) + sizeof(std::vector< BaseType* >) + sizeof(std::vector< unsigned int >) + sizeof(std::vector< char* >) + sizeof(int) * numElems + sizeof(BaseType*) * numElems;
+ for (int i = 0; i < numElems; i++)
+ retval = retval + 1 + strlen(elementNames[i]);
+ return retval;
+ }
+
+StructType::StructType()
+ : CompositeType("unnamed structtype", 0),
+ numElems(0),
+ elements(0),
+ elementNames(0),
+ elementOffsets(0),
+ align(1)
+ {
+ myType = STRUCT;
+ objecttype = OId::STRUCTTYPEOID;
+ }
+
+StructType::StructType(const char* newTypeName, unsigned int numElem )
+ : CompositeType(newTypeName, 0),
+ elements(numElem),
+ elementNames(numElem),
+ elementOffsets(numElem),
+ numElems(0),
+ align(1)
+ {
+ myType = STRUCT;
+ objecttype = OId::STRUCTTYPEOID;
+ }
+
+/*************************************************************
+ * Method name...: StructType(const StructType& old);
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: copy constructor
+ ************************************************************/
+
+StructType::StructType(const StructType& old)
+ : CompositeType(old)
+ {
+ elements = old.elements;
+ elementNames = old.elementNames;
+ elementOffsets = old.elementOffsets;
+ numElems = old.numElems;
+ align = old.align;
+ }
+
+StructType::StructType(const OId& structtypeid) throw (r_Error)
+ : CompositeType(structtypeid),
+ elements(0),
+ elementNames(0),
+ elementOffsets(0),
+ numElems(0),
+ align(1)
+ {
+ RMDBGENTER(4, RMDebug::module_catalogif, "StructType", "StructType(" << myOId << ")");
+ myType = STRUCT;
+ objecttype = OId::STRUCTTYPEOID;
+ readFromDb();
+ RMDBGEXIT(4, RMDebug::module_catalogif, "StructType", "StructType(" << myOId << ")");
+ }
+
+/*************************************************************
+ * Method name...: operator=(const StructType&);
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: copy constructor
+ ************************************************************/
+
+StructType&
+StructType::operator=(const StructType& old)
+ {
+ // Gracefully handle self assignment
+ //FIXME memory leak with char* in elementNames and elements
+ if (this == &old)
+ return *this;
+ CompositeType::operator=(old);
+ elements = old.elements;
+ elementNames = old.elementNames;
+ elementOffsets = old.elementOffsets;
+ numElems = old.numElems;
+ align = old.align;
+ return *this;
+ }
+
+StructType::~StructType()
+ {
+ ObjectBroker::deregisterDBObject(myOId);
+ validate();
+ for (int i = 0; i < getNumElems(); i++)
+ free((void*)elementNames[i]);//is ok because noone is using it
+ }
+
+/*************************************************************
+ * Method name...: void printCell( ostream& stream,
+ * const char* cell )
+ *
+ * Arguments.....:
+ * stream: stream to print on
+ * cell: pointer to cell to print
+ * Return value..: none
+ * Description...: prints a cell cell in hex on stream
+ * followed by a space.
+ * Assumes that Struct is stored MSB..LSB
+ * on HP.
+ ************************************************************/
+
+void
+StructType::printCell( ostream& stream, const char* cell ) const
+ {
+ int i;
+
+ stream << "\t|";
+ for(i=0; i<numElems; i++)
+ {
+ stream << elementNames[i] << "\t: ";
+ elements[i]->printCell(stream, cell + elementOffsets[i]);
+ stream << "\t ";
+ }
+ stream << "\t| ";
+ }
+
+char*
+StructType::getTypeStructure() const
+ {
+ // this implementation is not very clever, perhaps should use
+ // an intelligent string class
+ char* result = (char*)mymalloc(10);
+ char* newResult;
+ int i;
+
+ strcpy(result, "struct { ");
+ if(numElems == 0)
+ {
+ newResult = (char*)mymalloc(strlen(result) + 1 + 2);
+ strcpy(newResult, result);
+ strcat(newResult, " }");
+ free(result);
+ return newResult;
+ }
+ for(i = 0; i < numElems; i++)
+ {
+ char* dummy = elements[i]->getTypeStructure();
+ newResult = (char*)mymalloc(strlen(result) +
+ strlen(elementNames[i]) +
+ strlen(dummy) + 1 + 3 );
+ strcpy(newResult, result);
+ strcat(newResult, dummy);
+ strcat(newResult, " ");
+ strcat(newResult, elementNames[i]);
+ strcat(newResult, ", ");
+ free(result);
+ free(dummy);
+ result = newResult;
+ }
+ newResult = (char*)mymalloc(strlen(result) + 1 );
+ strcpy(newResult, result);
+ newResult[strlen(newResult) - 2] = ' ';
+ newResult[strlen(newResult) - 1] = '}';
+ free(result);
+ result = newResult;
+ return result;
+ }
+
+unsigned int
+StructType::addElement(const char* elemName, const char* elemType)
+ {
+ BaseType* stuff = 0;
+ stuff = (BaseType*)ObjectBroker::getObjectByName(OId::ATOMICTYPEOID, elemType);
+ if (stuff == 0)
+ stuff = (BaseType*)ObjectBroker::getObjectByName(OId::STRUCTTYPEOID, elemType);
+ return addElement(elemName, stuff);
+ }
+
+unsigned int
+StructType::addElement(const char* elemName, const BaseType* newType)
+ {
+ if (newType)
+ {
+ if (!_isPersistent)
+ {
+ addElementPriv(elemName, newType);
+ }
+ }
+ return numElems;
+ }
+
+unsigned int
+StructType::addElementPriv(const char* elemName, const BaseType* newType)
+ {
+ int currPos = 0;
+ int i, j;
+ char* myElemName = 0;
+
+ myElemName = (char*)mymalloc(strlen(elemName) + 1);
+ strcpy(myElemName, elemName);
+
+ if(numElems+1 > elements.size())
+ {
+ BaseType* dummyB = 0;
+ char* dummyN = 0;
+ unsigned int dummyO = 0;
+ elements.push_back(dummyB);
+ elementNames.push_back(dummyN);
+ elementOffsets.push_back(dummyO);
+ }
+ if(numElems == 0)
+ {
+ // first element
+ elementOffsets[currPos] = 0;
+ ++numElems;
+ }
+ else {
+ // All cases have to set currPos and numElems correctly!
+ // The array has to be ordered by offsets.
+ if(newType->getType() == STRUCT)
+ {
+ unsigned int myAlign = ((StructType*)(newType))->getAlignment();
+ if( align < myAlign )
+ align = myAlign;
+ // append at the end, align offset to 4 bytes.
+ currPos = numElems;
+ ++numElems;
+ elementOffsets[currPos] = ((elementOffsets[currPos-1] +
+ elements[currPos-1]->getSize()-1)/myAlign+1)*myAlign;
+ }
+ else {
+ if(newType->getSize() >= 4)
+ {
+ if(align < 4)
+ align = 4;
+ // append at the end, align offset to 4 bytes.
+ currPos = numElems;
+ ++numElems;
+ elementOffsets[currPos] = ((elementOffsets[currPos-1] +
+ elements[currPos-1]->getSize()-1)/4+1)*4;
+ }
+ else {
+ if(newType->getSize() == 2)
+ {
+ if(align < 2)
+ align = 2;
+ currPos = numElems;
+ numElems++;
+ elementOffsets[currPos] = ((elementOffsets[currPos-1] +
+ elements[currPos-1]->getSize()-1)/2+1)*2;
+ }
+ else {
+ if(newType->getSize() == 1)
+ {
+ currPos = numElems;
+ numElems++;
+ elementOffsets[currPos] = elementOffsets[currPos-1] +
+ elements[currPos-1]->getSize();
+ }
+ else {
+ RMDBGONCE(0, RMDebug::module_catalogif,"StructType", "addType() ERROR!");
+ // for debugging purposes only, shouldn't happen.
+ }
+ }
+ }
+ }
+ }
+ // actually insert type and name of element
+ elements[currPos] = newType;
+ elementNames[currPos] = myElemName;
+ // calculate current size
+ calcSize();
+ return numElems;
+ }
+
+unsigned int
+StructType::getOffset(const char* elemName) const
+ {
+ RMDBGENTER(6, RMDebug::module_catalogif, "StructType", "getOffset(" << elemName << ") " << getName() << " " << myOId);
+ int i;
+ unsigned int retval = 0;
+ bool found = false;
+ for(i=0; i<numElems; i++)
+ {
+ if(strcmp(elementNames[i], elemName) == 0)
+ {
+ retval = elementOffsets[i];
+ found = true;
+ break;
+ }
+ }
+RMDBGIF(0, RMDebug::module_catalogif, "StructType", \
+ if (found == false) \
+ { \
+ RMDBGONCE(0, RMDebug::module_catalogif, "StructType", "ERROR in StructType::getOffset(" << elemName << ") name not found " << getName() << " " << myOId << " retval " << retval); \
+ throw r_Error(STRUCTTYPE_ELEMENT_UNKNOWN); \
+ } )
+ RMDBGEXIT(6, RMDebug::module_catalogif, "StructType", "getOffset(" << elemName << ") " << getName() << " " << myOId << " retval " << retval);
+ return retval;
+ // should raise exception!
+ }
+
+unsigned int
+StructType::getOffset(unsigned int num) const
+ {
+ if (num >= numElems)
+ {
+ RMDBGONCE(0, RMDebug::module_catalogif, "StructType", "ERROR in StructType::getOffset(" << num << ") offset out of bounds " << getName() << " retval " << 0);
+ RMDBGIF(0, RMDebug::module_catalogif, "StructType", throw r_Error(STRUCTTYPE_ELEMENT_OUT_OF_BOUNDS); )
+ return 0;
+ }
+ return elementOffsets[num];
+ }
+
+const BaseType*
+StructType::getElemType(const char* elemName) const
+ {
+ RMDBGENTER(6, RMDebug::module_catalogif, "StructType", "getElemType(" << elemName << ") " << getName() << " " << myOId);
+ const BaseType* retval = 0;
+ int i;
+
+ for(i=0; i<numElems; i++)
+ {
+ if(strcmp(elementNames[i], elemName) == 0)
+ {
+ retval = elements[i];
+ break;
+ }
+ }
+ RMDBGIF(0, RMDebug::module_catalogif, "StructType", \
+ if (retval == 0) \
+ { \
+ RMDBGMIDDLE(0, RMDebug::module_catalogif, "StructType", "ERROR in StructType::getElemType(" << elemName << ") name not found " << getName() << " " << myOId << " retval " << retval); \
+ throw r_Error(STRUCTTYPE_ELEMENT_UNKNOWN); \
+ } )
+ RMDBGEXIT(6, RMDebug::module_catalogif, "StructType", "getElemType(" << elemName << ") " << getName() << " " << myOId << " retval " << retval);
+ return retval;
+ }
+
+const BaseType*
+StructType::getElemType(unsigned int num) const
+ {
+ if(!(num < numElems))
+ {
+ RMDBGONCE(0, RMDebug::module_catalogif, "StructType", "ERROR in StructType::getElemType(" << num << ") offset out of bounds " << getName() << " retval " << 0);
+ RMDBGIF(0, RMDebug::module_catalogif, "StructType", throw r_Error(STRUCTTYPE_ELEMENT_OUT_OF_BOUNDS); )
+ return 0;
+ }
+ return elements[num];
+ }
+
+const char* const
+StructType::getElemName(unsigned int num) const
+ {
+ if(!(num < numElems))
+ {
+ RMDBGONCE(0, RMDebug::module_catalogif, "StructType", "ERROR in StructType::getElemName(" << num << ") offset out of bounds " << getName() << " retval " << 0);
+ RMDBGIF(0, RMDebug::module_catalogif, "StructType", throw r_Error(STRUCTTYPE_ELEMENT_OUT_OF_BOUNDS); )
+ return 0;
+ }
+ return elementNames[num];
+ }
+
+unsigned int
+StructType::getNumElems() const
+ {
+ return numElems;
+ }
+
+unsigned int
+StructType::getAlignment() const
+ {
+ return align;
+ }
+
+int
+StructType::contains(const StructType* aStruct) const
+ {
+ int i;
+
+ for(i=0; i<numElems; i++)
+ {
+ if(elements[i] == aStruct)
+ return 1;
+ else
+ if(elements[i]->getType() == STRUCT)
+ if(((StructType*)elements[i])->contains(aStruct))
+ return 1;
+ }
+ return 0;
+ }
+
+int
+StructType::compatibleWith(const Type* aType) const
+ {
+ RMDBGENTER(7, RMDebug::module_catalogif, "StructType", "compatibleWith(" << aType->getName() << ") " << getName());
+ int retval;
+ if(aType->getType() != STRUCT)
+ {
+ RMDBGMIDDLE(8, RMDebug::module_catalogif, "StructType", "no structtype");
+ retval = 0;
+ }
+ else {
+ if(elements.size() != ((StructType*)aType)->elements.size())
+ {
+ RMDBGMIDDLE(8, RMDebug::module_catalogif, "StructType", "not the same size");
+ retval = 0;
+ }
+ else {
+ const BaseType* myBaseType;
+ const BaseType* otherBaseType;
+
+ int i;
+
+ retval = 1;
+ for( i = 0; i < elements.size(); i++ )
+ {
+ myBaseType = elements[i];
+ otherBaseType = ((StructType*)aType)->elements[i];
+ if(!myBaseType->compatibleWith(otherBaseType))
+ {
+ RMDBGMIDDLE(8, RMDebug::module_catalogif, "StructType", i << ". element " << otherBaseType->getName() << " does not match " << myBaseType);
+ retval = 0;
+ break;
+ }
+ }
+ }
+ }
+ RMDBGEXIT(7, RMDebug::module_catalogif, "StructType", "compatibleWith(" << aType->getName() << ") " << getName() << " retval " << retval);
+ return retval;
+ }
+
+void
+StructType::calcSize()
+ {
+ int alignSize = 1;
+
+ // check for alignment of size
+ for(int i=0; i<numElems; i++)
+ {
+ if( elements[i]->getSize() == 4 || elements[i]->getType() == STRUCT )
+ {
+ alignSize = 4;
+ break;
+ }
+ else {
+ if( elements[i]->getSize() == 2 )
+ {
+ alignSize = 2;
+ }
+ }
+ }
+ // align size to alignSize bytes (there may be unused bytes at the end!)
+ size = ((elementOffsets[numElems-1]+elements[numElems-1]->getSize()-1)/alignSize+1)*alignSize;
+ }
+
diff --git a/relcatalogif/type.C b/relcatalogif/type.C
new file mode 100644
index 0000000..5b496b2
--- /dev/null
+++ b/relcatalogif/type.C
@@ -0,0 +1,138 @@
+#include "mymalloc/mymalloc.h"
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * uses ODMG-conformant O2 classes
+ *
+ *
+ * COMMENTS:
+ * none
+ *
+ ************************************************************/
+
+#include <stdlib.h>
+#include <cstring>
+#include <ctype.h>
+#include "type.hh"
+#include "raslib/rmdebug.hh"
+#include "reladminif/externs.h"
+
+/************************************************************
+ * Method name...: Type()
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: constructor
+ ************************************************************/
+
+Type::Type()
+ : DBNamedObject("unnamed type")
+ {
+ RMDBGONCE(4, RMDebug::module_catalogif, "Type", "Type()");
+ }
+
+Type::Type(const OId& id) throw (r_Error)
+ : DBNamedObject(id)
+ {
+ RMDBGONCE(4, RMDebug::module_catalogif, "Type", "Type(" << myOId << ")");
+ }
+
+Type::Type(const char* name)
+ : DBNamedObject(name)
+ {
+ RMDBGONCE(4, RMDebug::module_catalogif, "Type", "Type(" << name << ")");
+ }
+
+Type::Type(const Type& old)
+ : DBNamedObject(old)
+ {
+ myType = old.myType;
+ }
+
+Type&
+Type::operator=(const Type& old)
+ {
+ DBNamedObject::operator=(old);
+ myType = old.myType;
+ return *this;
+ }
+
+void
+Type::destroy()
+ {
+ //does nothing to prevent types from being deleted because of reference counts
+ }
+
+/*************************************************************
+ * Method name...: getTypeName()
+ *
+ * Arguments.....: none
+ * Return value..:
+ * name of the type as a C string.
+ * Description...: returns name of the type.
+ ************************************************************/
+
+const char*
+Type::getTypeName() const
+{
+ return getName();
+}
+
+char*
+Type::getTypeStructure() const
+{
+ // default implementation for all non-structured base types.
+ char* dummy = (char*)getTypeName();
+ char* result = (char*)mymalloc(strlen(dummy) + 1);
+ strcpy(result, dummy);
+ for(int i = 0; i < strlen(dummy); i++)
+ result[i] = tolower(result[i]);
+ return result;
+}
+
+const TypeEnum
+Type::getType() const
+{
+ return myType;
+}
+
+int
+Type::compatibleWith(const Type* /* aType */) const
+{
+ return 0;
+}
+
+/*************************************************************
+ * Method name...: ~Type()
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: virtual destructor
+ ************************************************************/
+
+Type::~Type()
+ {
+ }
diff --git a/relcatalogif/type.hh b/relcatalogif/type.hh
new file mode 100644
index 0000000..f119f09
--- /dev/null
+++ b/relcatalogif/type.hh
@@ -0,0 +1,137 @@
+// -*-C++-*- (for Emacs)
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * The Type class is the superclass for the classes
+ * CollectionType, BaseType, and MDDType.
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#ifndef _TYPE_HH_
+#define _TYPE_HH_
+
+class Type;
+class OId;
+
+#include <iostream>
+using std::ostream;
+using std::cout;
+using std::endl;
+
+#include "catalogmgr/ops.hh"
+#include "reladminif/dbnamedobject.hh"
+
+//@ManMemo: Module: {\bf relcatalogif}.
+
+/*@Doc:
+Type is the abstract base class for CollectionType, BaseType, and MDDType.
+
+Common to each type is the ability to get its name.
+This functionality is defined as a pure virtual function here.
+
+{\bf Interdependencies}
+
+Each \Ref{Tile} has a pointer to its BaseType. Pointers to BaseType
+are also used in subclasses of \Ref{MDDObject}.
+*/
+
+class Type : public DBNamedObject
+ {
+ public:
+ virtual void destroy();
+ /*@Doc:
+ does nothing. is neccessary to stop types from being deleted by ~DBRef<Type>
+ */
+
+ /// returns the name of the type as a C string.
+ virtual const char* getTypeName() const;
+ /*@Doc:
+ The name of the type is the class name without the Type suffix.
+ e.g. "Bool" for \Ref{BoolType}, or "ULong" for \Ref{ULongType},
+ or "Set" for \Ref{SetType}, or "Dimension" for \Ref{DimensionType}.
+ */
+
+ /// returns the structure of the type as a C string.
+ virtual char* getTypeStructure() const;
+ /*@Doc:
+ Returns a copy of getTypeName() for non-structured base types. For
+ structured types a list of the elements in the form of #struct {
+ ulong elemName1, ushort elemName2 }# is returned. MDDTypes are
+ printed in the form #marray< RGBPixel, [10:20]# (less information,
+ if domain is not specified). Sets are printed in the form
+ #set<setName>#. The char* has to be freed by the caller!
+ */
+
+ const TypeEnum getType() const;
+ /*@Doc:
+ returns the type as a TypeEnum.
+ */
+
+ virtual int compatibleWith(const Type* aType) const;
+ /*@Doc:
+ checks, if two types are compatible (see also \Ref{MDDType}).
+ */
+
+ Type();
+ /*@Doc:
+ default constructor, cannot be used.
+ */
+
+ Type(const OId& id) throw (r_Error);
+ /*@Doc:
+ */
+
+ Type(const Type& old);
+ /*@Doc:
+ */
+
+ Type& operator=(const Type& old);
+ /*@Doc:
+ */
+
+ virtual ~Type();
+ /*@Doc:
+ virtual destructor.
+ */
+
+ protected:
+ TypeEnum myType;
+ /*@Doc:
+ enum for type. this can be ULONG, USHORT, CHAR,
+ BOOLTYPE, LONG, SHORT, OCTET, DOUBLE,
+ FLOAT, STRUCT, CLASSTYPE, SETTYPE, MDDTYPE
+ */
+
+ Type(const char* name);
+ /*@Doc:
+ */
+ };
+
+#endif
diff --git a/relcatalogif/typeiterator.C b/relcatalogif/typeiterator.C
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/relcatalogif/typeiterator.C
diff --git a/relcatalogif/typeiterator.hh b/relcatalogif/typeiterator.hh
new file mode 100644
index 0000000..a1a3e63
--- /dev/null
+++ b/relcatalogif/typeiterator.hh
@@ -0,0 +1,30 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#ifndef _TYPEITERATOR_HH_
+#define _TYPEITERATOR_HH_
+
+#include "reladminif/dbobjectiterator.hh"
+#define TypeIterator DBObjectIterator
+
+#endif
+
diff --git a/relcatalogif/uintegraltype.hh b/relcatalogif/uintegraltype.hh
new file mode 100644
index 0000000..89a4362
--- /dev/null
+++ b/relcatalogif/uintegraltype.hh
@@ -0,0 +1,90 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * The UIntegralType class is the superclass for all unsigned
+ * integral types (Char, Short, Long) describing the type of a
+ * cell
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#ifndef _UINTEGRALTYPE_HH_
+#define _UINTEGRALTYPE_HH_
+
+#include "atomictype.hh"
+
+//@ManMemo: Module: {\bf relcatalogif}.
+
+/*@Doc:
+UIntegralType is the abstract base class for all integral
+\Ref{BaseType} subclasses, i.e. base types like \Ref{ULongType} or
+\Ref{BoolType}. It provides conversions to/from long and
+double. It's subclasses must implement conversions to/from unsigned
+long.
+*/
+
+class UIntegralType : public AtomicType {
+public:
+ UIntegralType(unsigned int newSize):
+ AtomicType(newSize) {}
+ /*@Doc:
+ constructor.
+ */
+
+ UIntegralType(const UIntegralType& old):
+ AtomicType(old) {}
+ /*@Doc:
+ copy constructor.
+ */
+
+ UIntegralType(const OId& id) throw (r_Error):
+ AtomicType(id) {}
+ /*@Doc:
+ */
+
+ virtual ~UIntegralType() {}
+ /*@Doc:
+ */
+
+ virtual r_Long* convertToCLong(const char*, r_Long*) const;
+ virtual char* makeFromCLong(char*, const r_Long*) const;
+
+ virtual double* convertToCDouble(const char*, double*) const;
+ virtual char* makeFromCDouble(char*, const double*) const;
+
+protected:
+ UIntegralType(const char* name, unsigned int newSize):
+ AtomicType(name, newSize) {}
+ /*@Doc:
+ */
+
+};
+
+#include "uintegraltype.icc"
+
+#endif
diff --git a/relcatalogif/uintegraltype.icc b/relcatalogif/uintegraltype.icc
new file mode 100644
index 0000000..3bd0a96
--- /dev/null
+++ b/relcatalogif/uintegraltype.icc
@@ -0,0 +1,51 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+*
+*
+* COMMENTS:
+*
+************************************************************/
+
+inline r_Long*
+UIntegralType::convertToCLong(const char* cell, r_Long* value) const {
+ return (r_Long*)(this->convertToCULong(cell, (r_ULong *)value));
+}
+
+inline double*
+UIntegralType::convertToCDouble(const char* cell, double* value) const {
+ r_Long tmp;
+ *value = *this->convertToCLong(cell, &tmp);
+ return value;
+}
+
+inline char*
+UIntegralType::makeFromCLong(char* cell, const r_Long* value) const {
+ return this->makeFromCULong(cell, (r_ULong *)value);
+}
+
+inline char*
+UIntegralType::makeFromCDouble(char* cell, const double* value) const {
+ r_Long tmp = *value;
+ return this->makeFromCLong(cell, &tmp);
+}
diff --git a/relcatalogif/ulongtype.C b/relcatalogif/ulongtype.C
new file mode 100644
index 0000000..7f4c91c
--- /dev/null
+++ b/relcatalogif/ulongtype.C
@@ -0,0 +1,149 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * uses ODMG-conformant O2 classes
+ *
+ *
+ * COMMENTS:
+ * none
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)catalogif,ULongType: $Header: /home/rasdev/CVS-repository/rasdaman/relcatalogif/ulongtype.C,v 1.10 2003/12/27 23:23:04 rasdev Exp $";
+
+#include "ulongtype.hh"
+#include <iomanip>
+#include <string.h>
+#include "reladminif/externs.h"
+
+ULongType::ULongType(const OId& id) throw (r_Error)
+ : UIntegralType(id)
+ {
+ readFromDb();
+ }
+
+/*************************************************************
+ * Method name...: ULongType();
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: initializes member variables for an
+ * ULongType.
+ ************************************************************/
+
+ULongType::ULongType()
+ : UIntegralType(ULongType::Name, 4)
+ {
+ myOId = OId(ULONG, OId::ATOMICTYPEOID);
+ myType = ULONG;
+ }
+
+/*************************************************************
+ * Method name...: ULongType(const ULongType& old);
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: copy constructor
+ ************************************************************/
+
+ULongType::ULongType(const ULongType& old)
+ : UIntegralType(old)
+ {
+ }
+
+/*************************************************************
+ * Method name...: operator=(const ULongType&);
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: copy constructor
+ ************************************************************/
+
+ULongType& ULongType::operator=(const ULongType& old)
+ {
+ // Gracefully handle self assignment
+ if (this == &old)
+ return *this;
+ AtomicType::operator=(old);
+ return *this;
+ }
+
+/*************************************************************
+ * Method name...: ~ULongType();
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: virtual destructor
+ ************************************************************/
+
+ULongType::~ULongType()
+{
+}
+
+/*************************************************************
+ * Method name...: void printCell( ostream& stream,
+ * const char* cell )
+ *
+ * Arguments.....:
+ * stream: stream to print on
+ * cell: pointer to cell to print
+ * Return value..: none
+ * Description...: prints a cell cell in hex on stream
+ * followed by a space.
+ * Assumes that ULong is stored MSB..LSB
+ * on HP.
+ ************************************************************/
+
+void
+ULongType::printCell( ostream& stream, const char* cell ) const
+{
+ stream << std::setw(8) << *(r_ULong*)cell;
+}
+
+r_ULong*
+ULongType::convertToCULong(const char* cell, r_ULong* value) const
+{
+ *value = *(r_ULong*)cell;
+ return value;
+}
+
+
+char*
+ULongType::makeFromCULong(char* cell, const r_ULong* value) const
+{
+ *(r_ULong*)(cell) = *value;
+ return cell;
+}
+
+void
+ULongType::readFromDb() throw (r_Error)
+ {
+ setName(ULongType::Name);
+ size = 4;
+ myOId = OId(ULONG, OId::ATOMICTYPEOID);
+ myType = ULONG;
+ }
+
diff --git a/relcatalogif/ulongtype.hh b/relcatalogif/ulongtype.hh
new file mode 100644
index 0000000..5e0b369
--- /dev/null
+++ b/relcatalogif/ulongtype.hh
@@ -0,0 +1,101 @@
+// -*-C++-*- (for Emacs)
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * The ULongType class is the superclass for all classes
+ * describing the type of a cell
+ *
+ *
+ * COMMENTS:
+ * This file is patched by O2!
+ *
+ ************************************************************/
+
+#ifndef _ULONGTYPE_HH_
+#define _ULONGTYPE_HH_
+
+#include <iostream>
+#include "uintegraltype.hh"
+#include "catalogmgr/ops.hh"
+#include "reladminif/oidif.hh"
+
+//@ManMemo: Module: {\bf relcatalogif}.
+
+/*@Doc:
+ULongType is the base type used for 32bit unsigned integer cell
+values. The value of a ULong is stored in four chars.
+*/
+
+class ULongType : public UIntegralType
+ {
+ public:
+ ULongType(const OId& id) throw (r_Error);
+
+ ULongType();
+ /*@Doc:
+ default constructor, sets type name to "ULong".
+ */
+
+ ULongType(const ULongType& old);
+ /*@Doc:
+ copy constructor.
+ */
+
+ ULongType& operator=(const ULongType& old);
+ /*@Doc:
+ assignment operator.
+ */
+
+ virtual ~ULongType();
+ /*@Doc:
+ virtual destructor.
+ */
+
+ virtual void printCell(ostream& stream, const char* cell) const;
+ /*@Doc:
+ */
+
+ virtual r_ULong* convertToCULong(const char* cell, r_ULong* value) const;
+ /*@Doc:
+ */
+
+ virtual char* makeFromCULong(char* cell, const r_ULong* value) const;
+ /*@Doc:
+ */
+
+ static const char* Name;
+
+ protected:
+
+ virtual void readFromDb() throw (r_Error);
+ /*@Doc:
+ initializes the attributes of this type.
+ there is no database activity. this is hard coded.
+ */
+ };
+
+#endif
diff --git a/relcatalogif/ushorttype.C b/relcatalogif/ushorttype.C
new file mode 100644
index 0000000..f5e068f
--- /dev/null
+++ b/relcatalogif/ushorttype.C
@@ -0,0 +1,155 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * uses ODMG-conformant O2 classes
+ *
+ *
+ * COMMENTS:
+ * none
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)catalogif,UShortType: $Header: /home/rasdev/CVS-repository/rasdaman/relcatalogif/ushorttype.C,v 1.9 2003/12/27 23:23:04 rasdev Exp $";
+
+#include "ushorttype.hh"
+#include <iomanip>
+#include <string.h>
+
+/*************************************************************
+ * Method name...: UShortType();
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: initializes member variables for an
+ * UShortType.
+ ************************************************************/
+
+UShortType::UShortType()
+ : UIntegralType(UShortType::Name, 2)
+ {
+ myType = USHORT;
+ myOId = OId(USHORT, OId::ATOMICTYPEOID);
+ }
+
+/*************************************************************
+ * Method name...: UShortType(const UShortType& old);
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: copy constructor
+ ************************************************************/
+
+UShortType::UShortType(const UShortType& old)
+ : UIntegralType(old)
+ {
+ }
+
+UShortType::UShortType(const OId& id) throw (r_Error)
+ : UIntegralType(id)
+ {
+ readFromDb();
+ }
+
+/*************************************************************
+ * Method name...: operator=(const UShortType&);
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: copy constructor
+ ************************************************************/
+
+UShortType& UShortType::operator=(const UShortType& old)
+ {
+ // Gracefully handle self assignment
+ if (this == &old)
+ return *this;
+ AtomicType::operator=(old);
+ return *this;
+ }
+
+/*************************************************************
+ * Method name...: ~UShortType();
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: virtual destructor
+ ************************************************************/
+
+UShortType::~UShortType()
+{
+}
+
+/*************************************************************
+ * Method name...: void printCell( ostream& stream,
+ * const char* cell )
+ *
+ * Arguments.....:
+ * stream: stream to print on
+ * cell: pointer to cell to print
+ * Return value..: none
+ * Description...: prints a cell cell in hex on stream
+ * followed by a space.
+ * Assumes that UShort is stored MSB..LSB
+ * on HP.
+ ************************************************************/
+
+void
+UShortType::printCell( ostream& stream, const char* cell ) const
+{
+ // !!!! HP specific, assumes 4 Byte long and MSB..LSB
+ // byte order
+ stream << std::setw(5) << *(unsigned short*)cell;
+}
+
+r_ULong*
+UShortType::convertToCULong(const char* cell, r_ULong* value) const
+{
+ // !!!! HP specific, assumes 2 Byte short
+ *value = *(unsigned short*)cell;
+ return value;
+}
+
+
+char*
+UShortType::makeFromCULong(char* cell, const r_ULong* value) const
+{
+ r_ULong myLong = *value;
+ // restricting long to value range of short
+ myLong = myLong > USHRT_MAX ? USHRT_MAX : myLong;
+ myLong = myLong < 0 ? 0 : myLong;
+ // !!!! HP specific, assumes 2 Byte short
+ *(unsigned short*)(cell) = (unsigned short)myLong;
+ return cell;
+}
+
+void
+UShortType::readFromDb() throw (r_Error)
+ {
+ size = 2;
+ setName(UShortType::Name);
+ myType = USHORT;
+ myOId = OId(USHORT, OId::ATOMICTYPEOID);
+ }
diff --git a/relcatalogif/ushorttype.hh b/relcatalogif/ushorttype.hh
new file mode 100644
index 0000000..39f614f
--- /dev/null
+++ b/relcatalogif/ushorttype.hh
@@ -0,0 +1,100 @@
+// -*-C++-*- (for Emacs)
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * The UShortType class is the superclass for all classes
+ * describing the type of a cell
+ *
+ *
+ * COMMENTS:
+ * This file is patched by O2!
+ *
+ ************************************************************/
+
+#ifndef _USHORTTYPE_HH_
+#define _USHORTTYPE_HH_
+
+#include <iostream>
+#include "uintegraltype.hh"
+#include "catalogmgr/ops.hh"
+
+//@ManMemo: Module: {\bf relcatalogif}.
+
+/*@Doc:
+UShortType is the base type used for 16bit unsigned integer cell
+values. The value of a UShort is stored in four chars.
+*/
+
+class UShortType : public UIntegralType
+ {
+ public:
+ UShortType(const OId& id) throw (r_Error);
+
+ UShortType();
+ /*@Doc:
+ default constructor, sets type name to "UShort".
+ */
+
+ UShortType(const UShortType& old);
+ /*@Doc:
+ copy constructor.
+ */
+
+ UShortType& operator=(const UShortType& old);
+ /*@Doc:
+ assignment operator.
+ */
+
+ virtual ~UShortType();
+ /*@Doc:
+ virtual destructor.
+ */
+
+ virtual void printCell(ostream& stream, const char* cell) const;
+ /*@Doc:
+ */
+
+ virtual r_ULong* convertToCULong(const char* cell, r_ULong* value) const;
+ /*@Doc:
+ */
+
+ virtual char* makeFromCULong(char* cell, const r_ULong* value) const;
+ /*@Doc:
+ */
+
+ static const char* Name;
+
+ protected:
+
+ virtual void readFromDb() throw (r_Error);
+ /*@Doc:
+ initializes the attributes of this type.
+ there is no database activity. this is hard coded.
+ */
+ };
+
+#endif
diff --git a/relindexif/Makefile.am b/relindexif/Makefile.am
new file mode 100644
index 0000000..d7ab48d
--- /dev/null
+++ b/relindexif/Makefile.am
@@ -0,0 +1,49 @@
+# -*-Makefile-*- (for Emacs)
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+#
+# MAKEFILE FOR:
+# indexif
+#
+##################################################################
+
+AM_CXXFLAGS=@BASEDBCXXFLAGS@
+AM_LDFLAGS=@BASEDBLDFLAGS@
+
+.SUFFIXES= .@EMBEDDEDSQLEXT@ .@EMBEDDEDSQLOUT@
+.@EMBEDDEDSQLEXT@.@EMBEDDEDSQLOUT@:
+ $(EMBEDDEDSQLPRECOMPILER) $@ $<
+
+noinst_LIBRARIES=librelindexif.a
+librelindexif_a_SOURCES=dbrcindexdscommon.cc dbrcindexds.hh \
+ dbtcindexcommon.cc dbtcindex.hh \
+ hierindexcommon.cc hierindex.hh \
+ indexid.hh
+EXTRA_librelindexif_a_SOURCES=dbrcindexds.pgc dbtcindex.pgc hierindex.pgc
+
+librelindexif_a_LIBADD=dbrcindexds.$(OBJEXT) dbtcindex.$(OBJEXT) hierindex.$(OBJEXT)
+librelindexif_a_DEPENDENCIES=dbrcindexds.$(OBJEXT) dbtcindex.$(OBJEXT) hierindex.$(OBJEXT)
+
+BUILT_SOURCES=dbrcindexds.@EMBEDDEDSQLOUT@ dbtcindex.@EMBEDDEDSQLOUT@ hierindex.@EMBEDDEDSQLOUT@
+
+CLEANFILES=dbrcindexds.@EMBEDDEDSQLOUT@ dbtcindex.@EMBEDDEDSQLOUT@ hierindex.@EMBEDDEDSQLOUT@
+
diff --git a/relindexif/dbrcindexds.hh b/relindexif/dbrcindexds.hh
new file mode 100644
index 0000000..ee74061
--- /dev/null
+++ b/relindexif/dbrcindexds.hh
@@ -0,0 +1,210 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * RC index RDBMS adaptor include file.
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#ifndef _DBRCINDEXDS_HH_
+#define _DBRCINDEXDS_HH_
+
+#include "reladminif/dbobject.hh"
+#include "indexmgr/indexds.hh"
+#include "relcatalogif/inlineminterval.hh"
+
+//@ManMemo: Module: {\bf relindexif}
+/*@Doc:
+Can't have DBRCIndex and DBHierIndex under a common father class because the compiler has problems resolving the DBRef<> functions correctly.
+
+Persistent class for storing data on regular computed indexes.
+
+Beware of the cache when droping the IndexDS classes!
+
+See indexmgr/indexds.hh for documentation.
+
+Data to store:
+RAS_RCINDEXDYN
+ OId NUMBER(15,0),
+ Count NUMBER(3,0),
+ DynData VARCHAR(3990)
+NB: under Oracle 9i, Dyndata is defined as:
+ DynData BLOB NOT NULL
+This should be done for the other systems too,
+as VARCHAR usually is subject to charset translation
+which we don't want on our binary data.
+
+DynData holds: r_Dimension, OId::OIdType, OId::OIdCounter, InlineMinterval, InlineMinterval
+As:
+ r_Dimension dimension 4
+ OId::OIdType myBaseOIdType 2
+ OId::OIdCounter myBaseCounter 4
+ unsigned int mySize 4
+ InlineMinterval myDomain 10 * dim
+
+*/
+class DBRCIndexDS : public IndexDS
+ {
+ public:
+ DBRCIndexDS(const r_Minterval& definedDomain, unsigned int numberTiles, OId::OIdType theEntryType = OId::BLOBOID);
+ /*@Doc:
+ Create a new index which handles the domain definedDomain, with tiles of domain
+ tileConfig. As soon as you create this index it will check if the tileConfig fits
+ the definedDomain (the tileConfig must completely cover the definedDomain) and then
+ allocate as many oids as are neccessary to fill the definedDomain.
+ */
+
+ virtual r_Minterval getCoveredDomain() const;
+ /// return defined domain
+
+ virtual r_Minterval getAssignedDomain() const;
+ /// return defined domain
+
+ virtual r_Minterval getObjectDomain(unsigned int pos) const;
+ /// throw r_Error_FeatureNotSupported
+
+ virtual r_Dimension getDimension() const;
+
+ virtual void setAssignedDomain(const r_Minterval& domain);
+ /// throw r_Error_FeatureNotSupported
+
+ virtual unsigned int getSize() const;
+ /// this will return the maximum number of tiles that can be stored in the definedDomain.
+
+ virtual r_Bytes getTotalStorageSize() const;
+
+ virtual bool isValid() const;
+ /// returns true
+
+ virtual bool isUnderFull() const;
+ /// returns false
+
+ virtual bool isOverFull() const;
+ /// returns false
+
+ virtual bool isSameAs(const IndexDS* pix) const;
+
+ virtual bool removeObject(unsigned int pos);
+ /// throw r_Error_FeatureNotSupported
+
+ virtual bool removeObject(const KeyObject& theKey);
+ /// throw r_Error_FeatureNotSupported
+
+ virtual void insertObject(const KeyObject& theKey, unsigned int pos);
+ /// throw r_Error_FeatureNotSupported
+
+ virtual void setObject(const KeyObject& theKey, unsigned int pos);
+ /// throw r_Error_FeatureNotSupported
+
+ virtual void setObjectDomain(const r_Minterval& dom, unsigned int pos);
+ /// throw r_Error_FeatureNotSupported
+
+ virtual const KeyObject& getObject(unsigned int pos) const;
+ /// throw r_Error_FeatureNotSupported
+
+ virtual void getObjects(KeyObjectVector& objs) const;
+ /// throw r_Error_FeatureNotSupported
+
+ virtual unsigned int getOptimalSize() const;
+ /// returns the maximum number of entries that can be stored in this index
+
+ virtual void freeDS();
+
+ virtual OId::OIdPrimitive getIdentifier() const;
+
+ static r_Bytes BytesPerTupel;
+ /*@Doc:
+ tuning parameter. used to calculate the optimal size of
+ an index. this is also the number of bytes written to the
+ database.
+ */
+
+ virtual void printStatus(unsigned int level = 0, std::ostream& stream = std::cout) const;
+
+ virtual ~DBRCIndexDS();
+
+ virtual void destroy();
+
+ virtual IndexDS* getNewInstance() const;
+ /// throw r_Error_FeatureNotSupported
+
+ virtual OId::OIdType getBaseOIdType() const;
+
+ virtual OId::OIdCounter getBaseCounter() const;
+
+ protected:
+ friend class ObjectBroker;
+ /*@Doc:
+ ObjectBroker needs to access OId constructor
+ */
+
+ DBRCIndexDS(const OId& id);
+ /*@Doc:
+ */
+
+ virtual void readFromDb() throw (r_Error);
+ /*@Doc:
+ */
+
+ virtual void updateInDb() throw (r_Error);
+ /*@Doc:
+ */
+
+ virtual void deleteFromDb() throw (r_Error);
+ /*@Doc:
+ */
+
+ virtual void insertInDb() throw (r_Error);
+ /*@Doc:
+ */
+
+ OId::OIdCounter myBaseCounter;
+ /*@Doc:
+ The first oid that will be used to store entries.
+ */
+
+ OId::OIdType myBaseOIdType;
+ /*@Doc:
+ The type of objects to store in this index (most of the time this will be OId::BLOBOID).
+ */
+
+ OId::OIdCounter mySize;
+
+ InlineMinterval myDomain;
+ /*@Doc:
+ Defined domain of this index.
+ */
+
+ short currentDbRows;
+ /*@Doc:
+ is needed to support update of index in database
+ keeps the number of rows currently taken up in the db by
+ this instance
+ */
+ };
+#endif
diff --git a/relindexif/dbrcindexds.pgc b/relindexif/dbrcindexds.pgc
new file mode 100644
index 0000000..a476920
--- /dev/null
+++ b/relindexif/dbrcindexds.pgc
@@ -0,0 +1,495 @@
+#include "mymalloc/mymalloc.h"
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * Code with embedded SQL for PostgreSQL DBMS
+ *
+ *
+ * COMMENTS:
+ * - attribute name 'OId' -> 'UOId' (for UDFs), 'OId' -> 'Id' (for IXs)
+ * to avoid PG name clash with attr type
+ *
+ ************************************************************/
+
+// PG stuff:
+#include "libpq-fe.h" /* C interface to PgSQL */
+#include "libpq/libpq-fs.h" /* large object (lo) api */
+
+#include "debug-srv.hh"
+
+#include "dbrcindexds.hh"
+#include "reladminif/sqlerror.hh"
+#include "raslib/rmdebug.hh"
+
+// general embedded SQL related definitions
+EXEC SQL include "../reladminif/sqlglobals.h";
+
+// container size for index node
+// BEWARE: keep these parameters always consistent!
+#define BYTES_PER_TUPLE 3990
+EXEC SQL define SQL_BYTES_PER_TUPLE 3991;
+
+// libpg connection maintenance
+extern PGconn *pgConn;
+
+r_Bytes
+DBRCIndexDS::BytesPerTupel = BYTES_PER_TUPLE;
+
+void
+DBRCIndexDS::insertInDb() throw (r_Error)
+{
+ RMDBGENTER(5, RMDebug::module_indexif, "DBRCIndexDS", "insertInDb() " << myOId);
+ ENTER( "DBRCIndexDS::insertInDb" );
+
+#ifdef NOTYET // should be in future
+/*
+ EXEC SQL BEGIN DECLARE SECTION;
+*/
+#endif //NOTYET
+ double id2;
+ short count2;
+ Oid blobOid;
+ char pgQuery[SQL_QUERY_BUFFER_SIZE]; // prelim
+ PGresult *pgResult = NULL; // prelim
+#ifdef NOTYET // should be in future
+/*
+ EXEC SQL END DECLARE SECTION;
+*/
+#endif //NOTYET
+
+ // alternative solution for now:
+
+ // (1) --- prepare buffer
+ id2 = myOId;
+ r_Dimension dimension = myDomain.dimension();
+
+ //number of bytes for bounds in 1 minterval
+ r_Bytes boundssize = sizeof(r_Range) * dimension;
+ //number of bytes for fixes in 1 minterval
+ r_Bytes fixessize = sizeof(char) * dimension;
+ //number of bytes for the dynamic data
+ r_Bytes completesize = sizeof(r_Dimension) + sizeof(short) + sizeof(OId::OIdCounter) + sizeof(unsigned int) + boundssize * 2 + fixessize * 2;
+
+ char* completebuffer = (char*)mymalloc(completesize);
+ r_Range* upperboundsbuf = (r_Range*)mymalloc(boundssize);
+ r_Range* lowerboundsbuf = (r_Range*)mymalloc(boundssize);
+ char* upperfixedbuf = (char*)mymalloc(fixessize);
+ char* lowerfixedbuf = (char*)mymalloc(fixessize);
+
+ RMDBGMIDDLE(8, RMDebug::module_indexif, "DBRCIndexDS", "complete " << completesize << " bounds " << boundssize << " fixes " << fixessize);
+ TALK( "DBRCIndexDS: complete " << completesize << " bounds " << boundssize << " fixes " << fixessize);
+
+ // insert myDomain in buffers
+ myDomain.insertInDb(&(lowerboundsbuf[0]), &(upperboundsbuf[0]), &(lowerfixedbuf[0]), &(upperfixedbuf[0]));
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBRCIndexDS", "domain " << myDomain << " stored as " << InlineMinterval(dimension, &(lowerboundsbuf[0]), &(upperboundsbuf[0]), &(lowerfixedbuf[0]), &(upperfixedbuf[0])));
+ TALK( "DBRCIndexDS: domain " << myDomain << " stored as " << InlineMinterval(dimension, &(lowerboundsbuf[0]), &(upperboundsbuf[0]), &(lowerfixedbuf[0]), &(upperfixedbuf[0])) );
+
+ char* insertionpointer = completebuffer;
+ // write the buffers in the complete buffer
+ // this indirection is neccessary because of memory alignment of longs...
+ // insert dimension
+ memcpy(insertionpointer, &dimension, sizeof(r_Dimension));
+ insertionpointer = insertionpointer + sizeof(r_Dimension);
+
+ // insert oid type
+ memcpy(insertionpointer, &myBaseOIdType, sizeof(short));
+ insertionpointer = insertionpointer + sizeof(short);
+
+ // insert oid counter
+ memcpy(insertionpointer, &myBaseCounter, sizeof(OId::OIdCounter));
+ insertionpointer = insertionpointer + sizeof(OId::OIdCounter);
+
+ // insert oid counter
+ memcpy(insertionpointer, &mySize, sizeof(unsigned int));
+ insertionpointer = insertionpointer + sizeof(unsigned int);
+
+ // insert domains
+ memcpy(insertionpointer, lowerboundsbuf, boundssize);
+ insertionpointer = insertionpointer + boundssize;
+ free(lowerboundsbuf);
+
+ memcpy(insertionpointer, upperboundsbuf, boundssize);
+ insertionpointer = insertionpointer + boundssize;
+ free(upperboundsbuf);
+
+ memcpy(insertionpointer, lowerfixedbuf, fixessize);
+ insertionpointer = insertionpointer + fixessize;
+ free(lowerfixedbuf);
+
+ memcpy(insertionpointer, upperfixedbuf, fixessize);
+ free(upperfixedbuf);
+
+#ifdef RMANDEBUG // dump low-level blob byte string
+{
+ char printbuf[10000];
+ (void) sprintf( printbuf, "DBRCIndexDS::insertInDb(): [%d]", completesize );
+#if 0 // extra verbose output: dump buffer
+ char bytebuf[3];
+ for (unsigned int i = 0; i < completesize; i++)
+ {
+ (void) sprintf( bytebuf, " %2X", (unsigned char) completebuffer[i] );
+ strcat( printbuf, bytebuf );
+ }
+#endif // 0
+ TALK( printbuf );
+}
+#endif //RMANDEBUG
+
+ // (2) --- create, open, write, close blob; generates new 'oid' for subsequent storage in tuple
+ TALK( "lo_creat()" );
+ blobOid = lo_creat( pgConn, INV_READ|INV_WRITE ); // create -- not clear what INV_* here means so indicate all
+ if (blobOid == 0)
+ {
+ free(completebuffer);
+ completebuffer = NULL;
+ RMInit::logOut << "DBRCIndexDS::insertInDb() cannot create blob, error: " << PQerrorMessage(pgConn) << endl;
+ LEAVE( "DBRCIndexDS::insertInDb(pgConn)" );
+ generateException();
+ }
+ TALK( "lo_open() for oid " << blobOid );
+ int fd = lo_open( pgConn, blobOid, INV_WRITE ); // no error code indicated, 0 seems to be no error
+ TALK( "lo_write() for fd " << fd << " with " << completesize << " bytes" );
+ int loResult = lo_write( pgConn, fd, completebuffer, completesize );
+ if (loResult < 0)
+ {
+ free(completebuffer);
+ completebuffer = NULL;
+ RMInit::logOut << "DBRCIndexDS::insertInDb() cannot write blob, error: " << PQerrorMessage(pgConn) << endl;
+ LEAVE( "DBRCIndexDS::insertInDb() cannot write blob, error " << PQerrorMessage(pgConn) );
+ generateException();
+ }
+ else if (loResult != completesize) // did not get all
+ {
+ free(completebuffer);
+ completebuffer = NULL;
+ RMInit::dbgOut << "BLOB (" << myOId << ") insert: wrote " << loResult << " instead of " << completesize << " bytes" << endl;
+ LEAVE( "DBRCIndexDS::insertInDb() wrote " << loResult << " instead of " << completesize << " bytes" );
+ generateException();
+ }
+ TALK( "lo_close(), " << completesize << " bytes written" );
+ loResult = lo_close( pgConn, fd );
+ if (loResult < 0) // can't close, don't know if data are written
+ {
+ free(completebuffer);
+ completebuffer = NULL;
+ RMInit::logOut << "DBRCIndexDS::insertInDb() ignoring lo_close() error: " << PQerrorMessage(pgConn) << endl;
+ LEAVE( "DBRCIndexDS::insertInDb() cannot lo_close(): " << PQerrorMessage(pgConn) );
+ generateException();
+ }
+ free(completebuffer);
+
+ // (3) --- insert HIERIX tuple into db
+ count2 = 0; // we only have one entry
+#ifdef NOTYET // should be in future
+/*
+ TALK( "EXEC SQL INSERT INTO RAS_RCINDEXDYN ( Id, Count, DynData ) VALUES ( " << id2 << "," << count2 << "," << blobOid << " )" );
+ EXEC SQL INSERT INTO RAS_RCINDEXDYN ( Id, Count, DynData )
+ VALUES ( :id2, :count2, :blobOid );
+ if (SQLCODE != SQLOK)
+ {
+ check("DBRCIndexDS::insertInDb() insert into RAS_HIERIXDYN\0");
+ LEAVE( "DBRCIndexDS::insertInDb(): db access error: " << SQLCODE );
+ generateException();
+ }
+*/
+#endif // NOTYET
+ // alternative solution for now:
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "INSERT INTO RAS_RCINDEXDYN ( Id, Count, DynData ) VALUES ( %f, %d, %d )", id2, count2, blobOid );
+ TALK( pgQuery );
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_COMMAND_OK)
+ {
+ LEAVE( "DBRCIndexDS::insertInDb() libpq 'insert RAS_HIERIX' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+ PQclear( pgResult );
+
+ // (4) --- dbobject insert
+ DBObject::insertInDb();
+
+ LEAVE( "DBRCIndexDS::insertInDb" );
+ RMDBGEXIT(5, RMDebug::module_indexif, "DBRCIndexDS", "insertInDb() " << myOId);
+}
+
+void
+DBRCIndexDS::readFromDb() throw (r_Error)
+{
+ RMDBGENTER(5, RMDebug::module_indexif, "DBRCIndexDS", "readFromDb() " << myOId);
+ ENTER( "DBRCIndexDS::readFromDb" );
+
+#ifdef RMANBENCHMARK
+ DBObject::readTimer.resume();
+#endif
+
+#ifdef NOTYET // should be in future
+/*
+ EXEC SQL BEGIN DECLARE SECTION;
+*/
+#endif //NOTYET
+ double id1;
+ Oid blobOid;
+ char pgQuery[SQL_QUERY_BUFFER_SIZE]; // prelim
+ PGresult *pgResult = NULL; // prelim
+#ifdef NOTYET // should be in future
+/*
+ EXEC SQL END DECLARE SECTION;
+*/
+#endif //NOTYET
+
+ // (1) --- prepare variables
+ id1 = myOId;
+
+ // (2) --- get tuple
+#ifdef NOTYET // should be in future
+/*
+ TALK( "EXEC SQL SELECT DynData FROM RAS_RCINDEXDYN WHERE Id = " << id1 );
+ EXEC SQL SELECT DynData FROM RAS_RCINDEXDYN WHERE Id = :id1;
+ if (SQLCODE != SQLOK)
+ {
+ check("DBRCIndexDS::readFromDb() select from RAS_RCINDEXDYN");
+ LEAVE("DBRCIndexDS::readFromDb() 'select from RAS_RCINDEXDYN' error: " << SQLCODE );
+ generateException();
+ }
+*/
+#endif // NOTYET
+ // alternative solution for now:
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "SELECT DynData FROM RAS_RCINDEXDYN WHERE Id = %f", id1 );
+ TALK( pgQuery );
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_TUPLES_OK)
+ {
+ LEAVE( "DBRCIndexDS::readFromDb() libpq 'insert RAS_HIERIX' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+ blobOid = atoi( PQgetvalue( pgResult, 0, 0 ) ); // extract value from result
+ PQclear( pgResult );
+
+ // (3) --- open, read, close blob
+ TALK( "lo_open()" );
+ int fd = lo_open( pgConn, blobOid, INV_READ ); // open; manual tells no error indication
+ TALK( "lo_lseek() end" );
+ int blobSize = lo_lseek( pgConn, fd, 0, SEEK_END ); // determine blob size; FIXME: more efficient method??
+ TALK( "lo_lseek() start" );
+ (void) lo_lseek( pgConn, fd, 0, SEEK_SET ); // rewind for reading
+ char* completebuffer = (char*)mymalloc(blobSize); // receives blob contents
+ if (completebuffer == NULL)
+ {
+ RMInit::logOut << "DBRCIndexDS::readFromDb() cannot allocate blob buffer" << endl;
+ LEAVE( "DBRCIndexDS::readFromDb: cannot allocate blob buffer" );
+ throw r_Error( r_Error::r_Error_MemoryAllocation );
+ }
+ TALK( "lo_read() for " << blobSize << " bytes" ); // read blob
+ int loResult = lo_read( pgConn, fd, completebuffer, blobSize );
+ if (loResult < 0)
+ {
+ RMInit::logOut << "DBRCIndexDS::readFromDb() cannot read blob, error: " << loResult << endl;
+ LEAVE( "DBRCIndexDS::readFromDb: cannot read blob, error " << loResult );
+ throw r_Error( r_Error::r_Error_BaseDBMSFailed );
+ }
+ else if (loResult != blobSize) // did not get all
+ {
+ RMInit::dbgOut << "BLOB (" << myOId << ") read: want to read (" << blobSize << " bytes, but got " << loResult << " bytes" << endl;
+ LEAVE( "DBRCIndexDS::readFromDb: want to read " << blobSize << " bytes, but got " << loResult << " bytes" );
+ throw r_Error( r_Error::r_Error_LimitsMismatch );
+ }
+ TALK( "lo_close()" );
+ int ignoredPgResult = lo_close( pgConn, fd ); // close blob
+ if (ignoredPgResult < 0) // we note, but ignore errors, as we have the data
+ {
+ RMInit::logOut << "DBRCIndexDS::readFromDb() ignoring lo_close() error: " << ignoredPgResult << endl;
+ TALK( "DBRCIndexDS::readFromDb: ignoring lo_close() error: " << ignoredPgResult );
+ }
+
+#ifdef RMANDEBUG // dump low-level blob byte string
+{
+ char printbuf[10000];
+ (void) sprintf( printbuf, "XXX DBRCIndexDS::readFromDb(): [%d]", blobSize );
+ char bytebuf[3];
+ for (unsigned int i = 0; i < blobSize; i++)
+ {
+ (void) sprintf( bytebuf, " %2X", (unsigned char) completebuffer[i] );
+ strcat( printbuf, bytebuf );
+ }
+ TALK( printbuf );
+}
+#endif // RMANDEBUG
+
+ // (4) --- fill variables and buffers
+ r_Dimension dimension = 0;
+ (void) memcpy(&dimension, completebuffer, sizeof(r_Dimension));
+ unsigned int bytesdone = sizeof(r_Dimension);
+
+ (void) memcpy(&myBaseOIdType, &(completebuffer[bytesdone]), sizeof(short));
+ bytesdone += sizeof(short);
+ (void) memcpy(&myBaseCounter, &(completebuffer[bytesdone]), sizeof(OId::OIdCounter));
+ bytesdone += sizeof(OId::OIdCounter);
+ (void) memcpy(&mySize, &(completebuffer[bytesdone]), sizeof(unsigned int));
+ bytesdone += sizeof(unsigned int);
+
+ r_Bytes boundssize = sizeof(r_Range) * dimension; //number of bytes for bounds in 2 domains
+ r_Bytes fixessize = sizeof(char) * dimension; //number of bytes for fixes in 2 domains
+ r_Bytes completesize = boundssize * 2 + fixessize * 2; //number of bytes for the dynamic data
+ char *dynamicBuffer = &completebuffer[bytesdone]; // ptr to start of dynamic part of buffer
+
+ // additional plausi check
+ if (blobSize != bytesdone + completesize)
+ {
+ RMInit::logOut << "DBRCIndexDS::readFromDb() blob size inconsistency: blobSize (" << blobSize << " != bytesdone (" << bytesdone << ") + completesize (" << completesize << ")";
+ TALK( "DBRCIndexDS::readFromDb() blob size inconsistency: blobSize (" << blobSize << " != bytesdone (" << bytesdone << ") + completesize (" << completesize << ")" );
+ throw r_Error( r_Error::r_Error_LimitsMismatch );
+ }
+
+ RMDBGMIDDLE(7, RMDebug::module_indexif, "DBRCIndexDS", "dimension " << dimension << ", base oid type " << myBaseOIdType << ", base counter " << myBaseCounter << ", size " << mySize << ", complete data size " << completesize );
+
+ r_Range* upperboundsbuf = (r_Range*)mymalloc(boundssize);
+ r_Range* lowerboundsbuf = (r_Range*)mymalloc(boundssize);
+ char* upperfixedbuf = (char*)mymalloc(fixessize);
+ char* lowerfixedbuf = (char*)mymalloc(fixessize);
+
+ // all dynamic data is in dynamicBuffer
+ // put that stuff in the correct buffers
+ memcpy(lowerboundsbuf, dynamicBuffer, boundssize);
+ memcpy(upperboundsbuf, &dynamicBuffer[boundssize], boundssize);
+ memcpy(lowerfixedbuf, &dynamicBuffer[boundssize * 2], fixessize);
+ memcpy(upperfixedbuf, &dynamicBuffer[boundssize * 2 + fixessize], fixessize);
+
+ // all dynamic data is in its buffer
+ free (completebuffer);
+ dynamicBuffer = completebuffer = NULL;
+
+ // rebuild attributes from buffers
+ myDomain = InlineMinterval(dimension, &(lowerboundsbuf[0]), &(upperboundsbuf[0]), &(lowerfixedbuf[0]), &(upperfixedbuf[0]));
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBRCIndexDS", "domain " << myDomain << " constructed from " << InlineMinterval(dimension, &(lowerboundsbuf[0]), &(upperboundsbuf[0]), &(lowerfixedbuf[0]), &(upperfixedbuf[0])));
+
+ free(upperboundsbuf);
+ upperboundsbuf = NULL;
+ free(lowerboundsbuf);
+ lowerboundsbuf = NULL;
+ free(upperfixedbuf);
+ upperfixedbuf = NULL;
+ free(lowerfixedbuf);
+ lowerfixedbuf = NULL;
+
+#ifdef RMANBENCHMARK
+ DBObject::readTimer.pause();
+#endif
+
+ // (5) --- dbobject read
+ DBObject::readFromDb();
+
+ LEAVE( "DBRCIndexDS::readFromDb, myOId=" << myOId );
+ RMDBGEXIT(5, RMDebug::module_indexif, "DBRCIndexDS", "readFromDb() " << myOId);
+}
+
+void
+DBRCIndexDS::deleteFromDb() throw (r_Error)
+{
+ RMDBGENTER(8, RMDebug::module_indexif, "DBRCIndexDS", "deleteFromDb() " << myOId);
+ ENTER( "DBRCIndexDS::deleteFromDb" );
+
+#ifdef NOTYET // should be in future
+/*
+ EXEC SQL BEGIN DECLARE SECTION;
+*/
+#endif // NOTYET
+ double id3;
+ Oid blobOid;
+ char pgQuery[SQL_QUERY_BUFFER_SIZE]; // prelim
+ PGresult *pgResult = NULL; // prelim
+#ifdef NOTYET // should be in future
+/*
+ EXEC SQL END DECLARE SECTION;
+*/
+#endif // NOTYET
+
+ // (1) --- set variables
+ id3 = myOId;
+
+ // (2) --- fetch blob oid
+#ifdef NOTYET // should be in future
+/*
+ TALK( "EXEC SQL SELECT DynData FROM RAS_RCINDEXDYN WHERE Id = " << id3 );
+ EXEC SQL SELECT DynData FROM RAS_RCINDEXDYN
+ WHERE Id = :id3;
+ if (check("DBRCIndexDS::deleteFromDb() RAS_RCINDEX") != 0)
+ generateException();
+*/
+#endif // NOTYET
+ // alternative solution for now:
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "SELECT DynData FROM RAS_RCINDEXDYN WHERE Id = %f", id3 );
+ TALK( pgQuery );
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_TUPLES_OK)
+ {
+ LEAVE( "DBRCIndexDS::deleteFromDb() libpq 'select RAS_RCINDEXDYN' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+ blobOid = atoi( PQgetvalue( pgResult, 0, 0 ) ); // extract value from result
+ PQclear( pgResult );
+
+ // (3) --- delete blob
+ int loResult = lo_unlink( pgConn, blobOid );
+ if (loResult < 0) // no disaster if we can't so no exception
+ {
+ TALK( "DBRCIndexDS::deleteFromDb() warning: libpq 'unlink blob' error: " << PQerrorMessage(pgConn) );
+ }
+
+ // (3) --- delete tuple
+#ifdef NOTYET // should be in future
+/*
+ TALK( "EXEC SQL DELETE FROM RAS_RCINDEXDYN WHERE Id = " << id3 );
+ EXEC SQL DELETE FROM RAS_RCINDEXDYN
+ WHERE Id = :id3;
+ if (SQLCODE != SQLOK)
+ {
+ check("DBRCIndexDS::deleteFromDb() delete from RAS_RCINDEX");
+ LEAVE("DBRCIndexDS::deleteFromDb() 'delete from RAS_RCINDEX' error: " << SQLCODE );
+ generateException();
+ }
+*/
+#endif // NOTYET
+ // alternative solution for now:
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "DELETE FROM RAS_RCINDEXDYN WHERE Id = %f", id3 );
+ TALK( pgQuery );
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_COMMAND_OK)
+ {
+ LEAVE( "DBRCIndexDS::deleteFromDb() libpq 'select RAS_RCINDEXDYN' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+
+ // (4) --- dbobject delete
+ DBObject::deleteFromDb();
+
+ LEAVE( "DBRCIndexDS::deleteFromDb" );
+ RMDBGEXIT(8, RMDebug::module_indexif, "DBRCIndexDS", "deleteFromDb() " << myOId);
+}
+
diff --git a/relindexif/dbrcindexdscommon.cc b/relindexif/dbrcindexdscommon.cc
new file mode 100644
index 0000000..e8ede17
--- /dev/null
+++ b/relindexif/dbrcindexdscommon.cc
@@ -0,0 +1,286 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * C++ part (i.e., RDBMS independent) of the RC index adaptor.
+ *
+ *
+ * COMMENTS:
+ * uses embedded SQL
+ *
+ ************************************************************/
+
+#include "mymalloc/mymalloc.h"
+#include "dbrcindexds.hh"
+#include "reladminif/objectbroker.hh"
+#include "reladminif/dbref.hh"
+#include "raslib/rmdebug.hh"
+#include "reladminif/lists.h"
+#include "reladminif/sqlerror.hh"
+#include "reladminif/externs.h"
+#include "relblobif/blobtile.hh"
+#include "indexmgr/keyobject.hh"
+#include "storagemgr/sstoragelayout.hh"
+
+DBRCIndexDS::DBRCIndexDS(const OId& id)
+ : IndexDS(id),
+ currentDbRows(0),
+ myDomain(0),
+ myBaseCounter(0),
+ myBaseOIdType(OId::INVALID),
+ mySize(0)
+{
+ RMDBGENTER(7, RMDebug::module_indexif, "DBRCIndexDS", "DBRCIndexDS(" << myOId << ")");
+ objecttype = OId::MDDRCIXOID;
+ readFromDb();
+ RMDBGEXIT(7, RMDebug::module_indexif, "DBRCIndexDS", "DBRCIndexDS(" << myOId << ")");
+}
+
+DBRCIndexDS::DBRCIndexDS(const r_Minterval& definedDomain, unsigned int size, OId::OIdType theEntryType)
+ : IndexDS(),
+ myDomain(definedDomain),
+ currentDbRows(-1),
+ myBaseCounter(0),
+ myBaseOIdType(theEntryType),
+ mySize(size)
+{
+ RMDBGENTER(7, RMDebug::module_indexif, "DBRCIndexDS", "DBRCIndexDS(" << definedDomain << ", " << size << ", " << theEntryType << ") " << myOId);
+ objecttype = OId::MDDRCIXOID;
+ OId t;
+ OId::allocateOId(t, myBaseOIdType, mySize);
+ myBaseCounter = t.getCounter();
+ RMDBGMIDDLE(7, RMDebug::module_indexif, "DBRCIndexDS", "base counter " << myBaseCounter);
+ setPersistent(true);
+ setCached(true);
+ RMDBGEXIT(7, RMDebug::module_indexif, "DBRCIndexDS", "DBRCIndexDS(" << definedDomain << ", " << size << ", " << theEntryType << ") " << myOId);
+}
+
+IndexDS*
+DBRCIndexDS::getNewInstance() const
+{
+ RMInit::logOut << "DBRCIndexDS::getNewInstance() not suported" << std::endl;
+ throw r_Error(r_Error::r_Error_FeatureNotSupported);
+}
+
+OId::OIdPrimitive
+DBRCIndexDS::getIdentifier() const
+{
+ return myOId;
+}
+
+bool
+DBRCIndexDS::removeObject(const KeyObject& entry)
+{
+ RMInit::logOut << "DBRCIndexDS::removeObject(" << entry << ") not suported" << std::endl;
+ throw r_Error(r_Error::r_Error_FeatureNotSupported);
+}
+
+bool
+DBRCIndexDS::removeObject(unsigned int pos)
+{
+ RMInit::logOut << "DBRCIndexDS::removeObject(" << pos << ") not suported" << std::endl;
+ throw r_Error(r_Error::r_Error_FeatureNotSupported);
+}
+
+
+void
+DBRCIndexDS::insertObject(const KeyObject& theKey, unsigned int pos)
+{
+ RMInit::logOut << "DBRCIndexDS::insertObject(" << theKey << ", " << pos << ") not suported" << std::endl;
+ throw r_Error(r_Error::r_Error_FeatureNotSupported);
+}
+
+void
+DBRCIndexDS::setObjectDomain(const r_Minterval& dom, unsigned int pos)
+{
+ RMInit::logOut << "DBRCIndexDS::setObjectDomain(" << dom << ", " << pos << ") not suported" << std::endl;
+ throw r_Error(r_Error::r_Error_FeatureNotSupported);
+}
+
+void
+DBRCIndexDS::setObject(const KeyObject& theKey, unsigned int pos)
+{
+ RMInit::logOut << "DBRCIndexDS::setObject(" << theKey << ", " << pos << ") not suported" << std::endl;
+ throw r_Error(r_Error::r_Error_FeatureNotSupported);
+}
+
+r_Minterval
+DBRCIndexDS::getCoveredDomain() const
+{
+ RMDBGONCE(7, RMDebug::module_indexif, "DBRCIndexDS", "getCoveredDomain() const " << myOId << " " << myDomain);
+ return myDomain;
+}
+
+r_Dimension
+DBRCIndexDS::getDimension() const
+{
+ RMDBGONCE(7, RMDebug::module_indexif, "DBDDObjIx", "getDimension() const " << myOId << " " << myDomain.dimension());
+ return myDomain.dimension();
+}
+
+r_Bytes
+DBRCIndexDS::getTotalStorageSize() const
+{
+ RMDBGENTER(4, RMDebug::module_indexif, "DBRCIndexDS", "getTotalStorageSize() " << myOId);
+ r_Bytes sz = 0;
+
+ RMDBGEXIT(4, RMDebug::module_indexif, "DBRCIndexDS", "getTotalStorageSize() " << myOId << " " << sz);
+ return sz;
+}
+
+bool
+DBRCIndexDS::isValid() const
+{
+ return true;
+}
+
+void
+DBRCIndexDS::printStatus(unsigned int level, std::ostream& stream) const
+{
+ char* indent = new char[level*2 +1];
+ for (unsigned int j = 0; j < level*2 ; j++)
+ indent[j] = ' ';
+ indent[level*2] = '\0';
+
+ stream << indent << "DBRCIndexDS" << std::endl;
+ stream << indent << " current db rows " << currentDbRows << std::endl;
+ stream << indent << " domain " << myDomain << std::endl;
+ stream << indent << " base oid counter " << myBaseCounter << std::endl;
+ stream << indent << " base oid type " << myBaseOIdType << std::endl;
+ stream << indent << " size " << mySize << std::endl;
+ DBObject::printStatus(level, stream);
+ delete[] indent;
+}
+
+OId::OIdCounter
+DBRCIndexDS::getBaseCounter() const
+{
+ return myBaseCounter;
+}
+
+OId::OIdType
+DBRCIndexDS::getBaseOIdType() const
+{
+ return myBaseOIdType;
+}
+
+unsigned int
+DBRCIndexDS::getSize() const
+{
+ return mySize;
+}
+
+bool
+DBRCIndexDS::isUnderFull() const
+{
+ //redistribute in srptindexlogic has to be checked first before any other return value may be assigned
+ return false;
+}
+
+bool
+DBRCIndexDS::isOverFull() const
+{
+ return false;
+}
+
+unsigned int
+DBRCIndexDS::getOptimalSize() const
+{
+ return getSize();
+}
+
+r_Minterval
+DBRCIndexDS::getAssignedDomain() const
+{
+ return myDomain;
+}
+
+void
+DBRCIndexDS::setAssignedDomain(const r_Minterval& newDomain)
+{
+ RMInit::logOut << "DBRCIndexDS::setAssignedDomain(" << newDomain << ") not suported" << std::endl;
+ throw r_Error(r_Error::r_Error_FeatureNotSupported);
+}
+
+void
+DBRCIndexDS::freeDS()
+{
+ setPersistent(false);
+}
+
+bool
+DBRCIndexDS::isSameAs(const IndexDS* other) const
+{
+ if (other->isPersistent())
+ if (myOId == other->getIdentifier())
+ return true;
+ return false;
+}
+
+const KeyObject&
+DBRCIndexDS::getObject(unsigned int pos) const
+{
+ RMInit::logOut << "DBRCIndexDS::getObject(" << pos << ") not suported" << std::endl;
+ throw r_Error(r_Error::r_Error_FeatureNotSupported);
+}
+
+void
+DBRCIndexDS::getObjects(KeyObjectVector& objs) const
+{
+ RMInit::logOut << "DBRCIndexDS::getObjects(vec) not suported" << std::endl;
+ throw r_Error(r_Error::r_Error_FeatureNotSupported);
+}
+
+r_Minterval
+DBRCIndexDS::getObjectDomain(unsigned int pos) const
+{
+ RMInit::logOut << "DBRCIndexDS::getObjectDomain(" << pos << ") not suported" << std::endl;
+ throw r_Error(r_Error::r_Error_FeatureNotSupported);
+}
+
+void
+DBRCIndexDS::destroy()
+{
+ DBObject::destroy();
+}
+
+DBRCIndexDS::~DBRCIndexDS()
+{
+ RMDBGENTER(7, RMDebug::module_indexif, "DBRCIndexDS", "~DBRCIndexDS() " << myOId);
+ validate();
+ currentDbRows = 0;
+ RMDBGEXIT(7, RMDebug::module_indexif, "DBRCIndexDS", "~DBRCIndexDS() " << myOId);
+}
+
+void
+DBRCIndexDS::updateInDb() throw (r_Error)
+{
+ RMDBGENTER(5, RMDebug::module_indexif, "DBRCIndexDS", "updateInDb() " << myOId);
+ // this operation is illegal
+ RMInit::logOut << "DBRCIndexDS::updateInDb() update is not possible" << std::endl;
+ throw r_Error(r_Error::r_Error_FeatureNotSupported);
+ RMDBGEXIT(5, RMDebug::module_indexif, "DBRCIndexDS", "updateInDb() " << myOId);
+}
+
diff --git a/relindexif/dbtcindex.hh b/relindexif/dbtcindex.hh
new file mode 100644
index 0000000..e1f9688
--- /dev/null
+++ b/relindexif/dbtcindex.hh
@@ -0,0 +1,192 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#ifndef _DBTCINDEX_HH_
+#define _DBTCINDEX_HH_
+
+#include "hierindex.hh"
+#include "relblobif/tileid.hh"
+
+//@ManMemo: Module: {\bf relindexif}
+/*@Doc:
+This class stores data of hierarchical indexes in the database. It is extended to store tiles _inline_. this means it is possible for this class to concatenate several tiles into one large blob and store this blob in the database. the tiles must be inlinetiles. it is only interessting if the size of the tiles is very small (smaller than a disc page).
+
+for further information on the methods of this class see hierindexds and indexds interface classes in indexmgr.
+*/
+class DBTCIndex : public DBHierIndex
+ {
+ public:
+ DBTCIndex(r_Dimension dim, bool isNode);
+ /*@Doc:
+ constructs a new index with dimension dim.
+ instance is imediately persistent
+ */
+
+ virtual void printStatus(unsigned int level = 0, std::ostream& stream = std::cout) const;
+ /*@Doc:
+ Prints current status of index, in hierarchical format.
+ */
+
+ ~DBTCIndex();
+ /*@Doc:
+ */
+
+ virtual bool removeObject(const KeyObject& entry);
+ /*@Doc:
+ will take care of inlined tiles when they are removed.
+ */
+
+ virtual bool removeObject(unsigned int pos);
+ /*@Doc:
+ will take care of inlined tiles when they are removed.
+ */
+
+ virtual void removeInlineTile(InlineTile*);
+ /*@Doc:
+ this method is called by inlinetile to removeitselve from the index when it is outlined. the oid of this tile is still stored in the index. do not confuse with removeObejct!
+ */
+
+ virtual void addInlineTile(InlineTile*);
+ /*@Doc:
+ this method is called by inlinetile when it is told to inline itself into this index.
+ */
+
+ void setInlineTileHasChanged();
+ /*@Doc:
+ called by an inlined inlinetile when it is modified. the index must know about this in order to update the inlinetile in the database.
+ */
+
+ virtual IndexDS* getNewInstance() const;
+ /*@Doc:
+ used by indexmgr index logic classes to generate new nodes/leaves without knowing what kind of index structure it is operating with. in essence a clone() pattern.
+ */
+
+ protected:
+ friend class ObjectBroker;
+ /*@Doc:
+ ObjectBroker needs to access OId constructor and getInlineTile
+ */
+
+ InlineTile* getInlineTile(const OId& itid);
+ /*@Doc:
+ returns the specified inline tile.
+ memory management is done by the DBTCIndex object.
+ */
+
+
+ void changeIOIdToBOId();
+ /*@Doc:
+ changes all inlineoids to bloboids. needed in order to be able to use dbhierindex database functionality.
+ */
+
+
+ void readyForRemoval(const OId& id);
+ /*@Doc:
+ inlined inlinetiles must be loaded previous to removing them in order to get them outlined.
+ */
+
+ void changeBOIdToIOId();
+ /*@Doc:
+ changes the bloboids of the inlinetiles which are stored in this index into inlineoids. also neccessary to be able to use dbhierindex functionality.
+ */
+
+ void registerIOIds();
+ /*@Doc:
+ registers all inline oids with the objectbroker. changeIOIdToBOId is supposed to be called afterwards.
+ */
+
+ void readInlineTiles() throw (r_Error);
+ /*
+ loads the tiles from the blob tablespace.
+ errors are database errors.
+ */
+
+ void decideForInlining();
+ /*
+ makes blobtiles to inlinetiles and vice versa.
+ */
+
+ void insertBlob();
+ /*@Doc:
+ insert empty blob into db
+ */
+
+ void storeTiles();
+ /*@Doc:
+ write the tiles into the blob space if neccessary.
+ */
+
+ void writeInlineTiles(char* cells, r_Bytes blobSize) throw (r_Error);
+ /*
+ writes the tiles into the blob tablespace.
+ errors are database errors.
+ */
+
+ void updateTileIndexMappings() throw (r_Error);
+ /*
+ writes the mappings among dbtcindex and inlinetiles into the database for objectbroker to see.
+ errors are database errors.
+ */
+
+ DBTCIndex(const OId& id);
+
+ void setMappingHasChanged();
+ /*@Doc:
+ tells the index that it has to update the table for mapping inlined inlinetile oids to dbtcindexes.
+ */
+
+ virtual void readFromDb() throw (r_Error);
+
+ virtual void updateInDb() throw (r_Error);
+
+ virtual void deleteFromDb() throw (r_Error);
+
+ virtual void insertInDb() throw (r_Error);
+
+ bool mappingHasChanged;
+ /*@Doc:
+ is true when an inlinetile has been added or removed.
+ */
+
+ bool inlineTileHasChanged;
+ /*@Doc:
+ is true when the inlined tiles need to be updated.
+ */
+
+ bool _isLoaded;
+ /*@Doc:
+ transient, tells if the object has loaded its inlined tiles.
+ */
+
+ bool hasBlob;
+ /*@Doc:
+ transient, tells if the object has already a blob in the database or not.
+ */
+
+ DBObjectPMap inlineTiles;
+ /*@Doc:
+ transient, contains pointers to materialised inlinetiles.
+ is filled on demand by loadInlineTiles.
+ */
+
+ };
+#endif
diff --git a/relindexif/dbtcindex.pgc b/relindexif/dbtcindex.pgc
new file mode 100644
index 0000000..10e8318
--- /dev/null
+++ b/relindexif/dbtcindex.pgc
@@ -0,0 +1,338 @@
+#include "mymalloc/mymalloc.h"
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * Code with embedded SQL for PostgreSQL DBMS
+ *
+ *
+ * COMMENTS:
+ * - not yet implemented.
+ *
+ ************************************************************/
+
+// PG stuff:
+#include "libpq-fe.h" /* C interface to PgSQL */
+#include "libpq/libpq-fs.h" /* large object (lo) api */
+
+#include "debug-srv.hh"
+
+// general embedded SQL related definitions
+EXEC SQL include "../reladminif/sqlglobals.h";
+
+#include "dbtcindex.hh"
+#include "raslib/rmdebug.hh"
+#include "reladminif/sqlerror.hh"
+
+void
+DBTCIndex::deleteFromDb() throw (r_Error)
+{
+ RMDBGENTER(5, RMDebug::module_indexif, "DBTCIndex", "deleteFromDb() " << myOId);
+ throw r_Error( r_Error::r_Error_BaseDBMSFailed );
+
+/*
+ EXEC SQL BEGIN DECLARE SECTION;
+ long id3;
+ Oid blobOid;
+ char pgQuery[SQL_QUERY_BUFFER_SIZE]; // prelim
+ PGresult *pgResult = NULL; // prelim
+ EXEC SQL END DECLARE SECTION;
+
+ if (!_isLoaded)
+ readInlineTiles();
+
+ DBHierIndex::deleteFromDb();
+
+ id3 = myOId.getCounter();
+
+ TALK( "EXEC SQL DELETE FROM RAS_ITILES WHERE ITileId = " << id3 );
+ EXEC SQL DELETE FROM RAS_ITILES
+ WHERE ITileId = :id3;
+ if (SQLCODE != 0)
+ {
+ if (SQLCODE != 100)
+ {
+ check("DBTCIndex::deleteFromDb() RAS_ITILES");
+ generateException();
+ }
+ }
+
+ TALK( "EXEC SQL DELETE FROM RAS_ITMAP WHERE IndexId = " << id3 );
+ EXEC SQL DELETE FROM
+ RAS_ITMAP
+ WHERE
+ IndexId = :id3;
+ if (SQLCODE != 0)
+ {
+ if (SQLCODE != 100)
+ {
+ check("DBTCIndex::deleteFromDb() RAS_ITMAP");
+ generateException();
+ }
+ }
+
+ RMDBGEXIT(5, RMDebug::module_indexif, "DBTCIndex", "deleteFromDb() " << myOId);
+*/
+}
+
+void
+DBTCIndex::storeTiles()
+{
+ RMDBGENTER(5, RMDebug::module_indexif, "DBTCIndex", "storeTiles() " << myOId);
+ throw r_Error( r_Error::r_Error_BaseDBMSFailed );
+
+ /*
+ char* cells = NULL;
+ r_Bytes blobSize = 0;
+ r_Bytes currinlinesize = 0;
+ char* from = NULL;
+ DBObjectPMap::iterator itit;
+
+ for (itit = inlineTiles.begin(); inlineTiles.end() != itit; itit++)
+ {
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBTCIndex", "InlineTile " << (*itit).second->getOId() << " has size " << ((InlineTile*)(*itit).second)->getStorageSize());
+ blobSize = ((InlineTile*)(*itit).second)->getStorageSize() + blobSize;
+ }
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBTCIndex", "blobSize " << blobSize << " hasBlob " << (int)hasBlob);
+ if (hasBlob && (blobSize == 0))
+ {
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBTCIndex", "dropping blob");
+ //drop blob
+ EXEC SQL BEGIN DECLARE SECTION;
+ long blspcoid4;
+ EXEC SQL END DECLARE SECTION;
+ blspcoid4 = myOId.getCounter();
+
+ TALK( "EXEC SQL DELETE FROM RAS_ITILES WHERE ITileId = " << blspcoid4 );
+ EXEC SQL DELETE FROM RAS_ITILES WHERE ITileId = :blspcoid4;
+ if (SQLCODE != 0)
+ {
+ if (SQLCODE != 100)
+ {
+ check("DBTCIndex::storeTiles drop blob()");
+ generateException();
+ }
+ else
+ {
+ RMInit::logOut << "Tile container index: error in BLOB Space." << endl << "Please contact Customer support." << endl;
+ RMInit::dbgOut << "Tile container index: store tiles, but can't find my blob!" << endl;
+ throw r_Error(TILE_CONTAINER_NOT_FOUND);
+ }
+ }
+ hasBlob = false;
+ }
+ else
+ {
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBTCIndex", "not dropping blob");
+ if (blobSize == 0)
+ {
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBTCIndex", "nothing to insert");
+ }
+ else
+ {
+ if (!hasBlob)
+ {
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBTCIndex", "but inserting blob");
+ insertBlob();
+ }
+ hasBlob = true;
+ cells = (char*)mymalloc(blobSize * sizeof(char));
+ from = cells;
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBTCIndex", "inserting " << blobSize << " bytes");
+ for (itit = inlineTiles.begin(); inlineTiles.end() != itit; itit++)
+ {
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBTCIndex", "inserting " << (*itit).second->getOId() << " from " << (r_Bytes)(from - cells));
+ from = ((InlineTile*)((*itit).second))->insertInMemBlock(from);
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBTCIndex", "inserted to " << (r_Bytes)(from - cells));
+ }
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBTCIndex", "will write " << (r_Bytes)(from - cells) << " bytes");
+ writeInlineTiles(cells, blobSize);
+ for (itit = inlineTiles.begin(); itit != inlineTiles.end(); itit++)
+ {
+ delete (*(inlineTiles.begin())).second;
+ (*(inlineTiles.begin())).second = NULL;
+ }
+ }
+ }
+ RMDBGEXIT(5, RMDebug::module_indexif, "DBTCIndex", "storeTiles() " << myOId);
+ */
+}
+
+void
+DBTCIndex::insertBlob()
+{
+ RMDBGENTER(5, RMDebug::module_indexif, "DBTCIndex", "insertBlob() " << myOId);
+
+ throw r_Error( r_Error::r_Error_BaseDBMSFailed );
+
+ EXEC SQL BEGIN DECLARE SECTION;
+ long blspcoid3;
+ EXEC SQL END DECLARE SECTION;
+ blspcoid3 = myOId.getCounter();
+
+/*
+ EXEC SQL INSERT INTO RAS_ITILES (
+ ITileId,
+ ITile
+ )
+ VALUES (
+ :blspcoid3,
+ EMPTY_BLOB()
+ );
+ if (check("DBTCIndex::insertBlob()") != 0)
+ {
+ if (SQLCODE == -1)
+ RMInit::logOut << "Counter for DBTCIndexs corrupted." << endl << "Please increment Rows in RAS_COUNTERS manually." << endl;
+ generateException();
+ }
+*/
+ hasBlob = true;
+ RMDBGEXIT(5, RMDebug::module_indexif, "DBTCIndex", "insertBlob() " << myOId);
+}
+
+void
+DBTCIndex::writeInlineTiles(char* theblob, r_Bytes blobSize) throw (r_Error)
+{
+ RMDBGENTER(3, RMDebug::module_indexif, "DBTCIndex", "writeInlineTiles() " << myOId);
+ throw r_Error( r_Error::r_Error_BaseDBMSFailed );
+
+ /*
+ EXEC SQL BEGIN DECLARE SECTION;
+ long blspcoid2;
+ EXEC SQL END DECLARE SECTION;
+
+ if (blobSize == 0)
+ {
+ RMInit::logOut << "DBTCIndex encountered an internal Error: blobSize is zero." << endl;
+ RMInit::logOut << "Please check your Oracle Instance and contact Customer Support." << endl;
+ RMDBGONCE(0, RMDebug::module_indexif, "DBTCIndex", "writeInlineTiles blobSize = 0!");
+ throw r_Error(r_Error::r_Error_BaseDBMSFailed);
+ }
+ do
+ {
+
+ //EXEC SQL SELECT ITile INTO :loc1 FROM RAS_ITILES WHERE ITileId = :blspcoid2;
+ if (check("Select Loblocator") != 0)
+ generateException();
+
+ } while ((retries < 5) && (tnserror));
+
+ _isLoaded = false;
+ inlineTileHasChanged = false;
+
+ RMDBGEXIT(3, RMDebug::module_indexif, "DBTCIndex", "writeInlineTiles() " << myOId << " " << myOId.getType());
+*/
+}
+
+void
+DBTCIndex::readInlineTiles() throw (r_Error)
+{
+ RMDBGENTER(3, RMDebug::module_indexif, "DBTCIndex", "readInlineTiles() " << myOId);
+ throw r_Error( r_Error::r_Error_BaseDBMSFailed );
+
+/*
+ EXEC SQL BEGIN DECLARE SECTION;
+ long blspcoid1;
+ EXEC SQL END DECLARE SECTION;
+ blspcoid1 = myOId.getCounter();
+
+ long from = 0;
+ long newsize = 0;
+ char* theblob = NULL;
+
+
+ //EXEC SQL SELECT ITile INTO :loc FROM RAS_ITILES WHERE ITileId = :blspcoid1;
+ if (check("DBTCIndex::loadInlineTiles() SELECT LOBLOCATOR"))
+ throw r_Error(r_Error::r_Error_ObjectUnknown);
+
+ if (loblength != 0)
+ {
+ theblob = (char*)mymalloc(loblength * sizeof(char));
+ }
+ inlineTiles = DBObjectPMap();
+ InlineTile* t = NULL;
+ char* end = (theblob + loblength);
+ RMDBGMIDDLE(3, RMDebug::module_indexif, "DBTCIndex", "end is at " << (r_Bytes)end);
+ while (theblob != end)
+ {
+ RMDBGMIDDLE(3, RMDebug::module_indexif, "DBTCIndex", "reading from " << (r_Bytes)theblob);
+ t = new InlineTile(myOId, theblob);
+ t->setCached(true);
+ DBObjectPPair p(t->getOId(), t);
+ inlineTiles.insert(p);
+ }
+
+#ifdef RMANBENCHMARK
+ DBObject::readTimer.pause();
+#endif
+ _isLoaded = true;
+ inlineTileHasChanged = false;
+ mappingHasChanged = false;
+ RMDBGEXIT(3, RMDebug::module_indexif, "DBTCIndex", "readInlineTiles() " << myOId);
+ */
+}
+
+void
+DBTCIndex::updateTileIndexMappings() throw (r_Error)
+{
+ RMDBGENTER(5, RMDebug::module_indexif, "DBTCIndex", "updateTileIndexMappings() " << myOId);
+ throw r_Error( r_Error::r_Error_BaseDBMSFailed );
+
+ EXEC SQL BEGIN DECLARE SECTION;
+ long indexid;
+ long inlineid;
+ EXEC SQL END DECLARE SECTION;
+
+ indexid = myOId.getCounter();
+
+ TALK( "EXEC SQL DELETE FROM RAS_ITMAP WHERE IndexId = " << indexid );
+ EXEC SQL DELETE FROM
+ RAS_ITMAP
+ WHERE
+ IndexId = :indexid;
+
+ DBObjectPMap::iterator itit;
+ for (itit = inlineTiles.begin(); itit != inlineTiles.end(); itit++)
+ {
+ inlineid = OId((*itit).first).getCounter();
+
+ TALK( "EXEC SQL INSERT INTO RAS_ITMAP ( TileId, IndexId) VALUES ( " << inlineid << "," << indexid << ")" );
+ EXEC SQL INSERT INTO RAS_ITMAP (
+ TileId,
+ IndexId
+ )
+ VALUES (
+ :inlineid,
+ :indexid
+ );
+ RMDBGMIDDLE(6, RMDebug::module_indexif, "DBTCIndex", "TileId: " << inlineid << " IndexId: " << indexid);
+ if (check("DBTCIndex::updateTileIndexMappings() insert in RAS_ITMAP") != 0)
+ generateException();
+ }
+ mappingHasChanged = false;
+ RMDBGEXIT(5, RMDebug::module_indexif, "DBTCIndex", "updateTileIndexMappings() " << myOId);
+}
+
diff --git a/relindexif/dbtcindexcommon.cc b/relindexif/dbtcindexcommon.cc
new file mode 100644
index 0000000..fb44354
--- /dev/null
+++ b/relindexif/dbtcindexcommon.cc
@@ -0,0 +1,357 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include <unistd.h>
+
+#include "dbtcindex.hh"
+#include "raslib/rmdebug.hh"
+#include "reladminif/lists.h"
+#include "reladminif/sqlerror.hh"
+#include "reladminif/externs.h"
+#include "relblobif/blobtile.hh"
+#include "relblobif/inlinetile.hh"
+#include "relblobif/tileid.hh"
+#include "reladminif/objectbroker.hh"
+#include "reladminif/adminif.hh"
+#include "reladminif/dbref.hh"
+#include "storagemgr/sstoragelayout.hh"
+#include "indexmgr/keyobject.hh"
+
+void
+DBTCIndex::setMappingHasChanged()
+ {
+ mappingHasChanged = true;
+ }
+
+void
+DBTCIndex::setInlineTileHasChanged()
+ {
+ inlineTileHasChanged = true;
+ }
+
+DBTCIndex::DBTCIndex(const OId& id)
+ : DBHierIndex(id),
+ _isLoaded(false),
+ inlineTileHasChanged(false),
+ mappingHasChanged(false),
+ hasBlob(false)
+ {
+ RMDBGENTER(7, RMDebug::module_indexif, "DBTCIndex", "DBTCIndex(" << myOId << ")");
+ throw r_Error(r_Error::r_Error_FeatureNotSupported);
+ readFromDb();
+ _isLoaded = !hasBlob;
+ RMDBGEXIT(7, RMDebug::module_indexif, "DBTCIndex", "DBTCIndex(" << myOId << ")");
+ }
+
+IndexDS*
+DBTCIndex::getNewInstance() const
+ {
+ return (HierIndexDS*)new DBTCIndex(getDimension(), !isLeaf());
+ }
+
+DBTCIndex::DBTCIndex(r_Dimension dim, bool isNode)
+ : DBHierIndex(dim, isNode, false),
+ _isLoaded(true),
+ inlineTileHasChanged(false),
+ mappingHasChanged(false),
+ hasBlob(false)
+ {
+ RMDBGENTER(7, RMDebug::module_indexif, "DBTCIndex", "DBTCIndex(" << dim << ", " << (int)_isLoaded << ") " << myOId);
+ throw r_Error(r_Error::r_Error_FeatureNotSupported);
+ objecttype = OId::DBTCINDEXOID;
+ setPersistent(true);
+ setCached(true);
+ RMDBGEXIT(7, RMDebug::module_indexif, "DBTCIndex", "DBTCIndex(" << dim << ") " << myOId);
+ }
+
+void
+DBTCIndex::printStatus(unsigned int level, std::ostream& stream) const
+ {
+ char* indent = new char[level*2 +1];
+ for (unsigned int j = 0; j < level*2 ; j++)
+ indent[j] = ' ';
+ indent[level*2] = '\0';
+
+ stream << indent << "DBTCIndex ";
+ DBHierIndex::printStatus(level + 1, stream);
+ delete[] indent;
+ }
+
+
+DBTCIndex::~DBTCIndex()
+ {
+ RMDBGENTER(7, RMDebug::module_indexif, "DBTCIndex", "~DBTCIndex() " << myOId);
+ if (!isModified())
+ {
+ if (!AdminIf::isReadOnlyTA())
+ {
+ if (isLeaf())
+ decideForInlining();
+ if (mappingHasChanged)
+ updateTileIndexMappings();
+ if (inlineTileHasChanged)
+ {
+ storeTiles();
+ changeBOIdToIOId();
+ }
+ if (isModified())
+ DBHierIndex::updateInDb();
+ if (isLeaf())
+ changeIOIdToBOId();
+ }
+ }
+ else
+ validate();
+ currentDbRows = 0;
+ parent = OId(0);
+ RMDBGEXIT(7, RMDebug::module_indexif, "DBTCIndex", "~DBTCIndex() " << myOId);
+ }
+
+void
+DBTCIndex::registerIOIds()
+ {
+ RMDBGENTER(7, RMDebug::module_indexif, "DBTCIndex", "registerIOIds() " << myOId);
+ for (KeyObjectVector::iterator i = myKeyObjects.begin(); i != myKeyObjects.end(); i++)
+ if ((*i).getObject().getOId().getType() == OId::INNEROID)
+ {
+ RMDBGMIDDLE(7, RMDebug::module_indexif, "DBTCIndex", "registering tileoid " << OId((*i).getObject().getOId().getCounter(), OId::INLINETILEOID) << " indexoid " << myOId);
+ ObjectBroker::registerTileIndexMapping(OId((*i).getObject().getOId().getCounter(), OId::INLINETILEOID), myOId);
+ hasBlob = true;
+ }
+ RMDBGEXIT(7, RMDebug::module_indexif, "DBTCIndex", "registerIOIds() " << myOId);
+ }
+
+void
+DBTCIndex::changeIOIdToBOId()
+ {
+ for (KeyObjectVector::iterator it = myKeyObjects.begin(); it != myKeyObjects.end(); it++)
+ if ((*it).getObject().getOId().getType() == OId::INNEROID)
+ {
+ OId o((*it).getObject().getOId().getCounter(), OId::INLINETILEOID);
+ DBObjectPPair p(o, 0);
+ inlineTiles.insert(p);
+ (*it).setObject(o);
+ }
+ }
+
+void
+DBTCIndex::changeBOIdToIOId()
+ {
+ for (KeyObjectVector::iterator it = myKeyObjects.begin(); it != myKeyObjects.end(); it++)
+ {
+ DBObjectPMap::iterator itit = inlineTiles.find((*it).getObject().getOId());
+ if (itit != inlineTiles.end())
+ {
+ (*it).setObject(OId((*it).getObject().getOId().getCounter(), OId::INNEROID));
+ }
+ }
+ }
+
+void
+DBTCIndex::removeInlineTile(InlineTile* it)
+ {
+ DBObjectPMap::iterator itit = inlineTiles.find(it->getOId());
+ if (itit != inlineTiles.end())
+ {
+ inlineTiles.erase(itit);
+ setMappingHasChanged();
+ setInlineTileHasChanged();
+ ObjectBroker::deregisterTileIndexMapping(it->getOId(), myOId);
+ }
+ else {
+ RMDBGONCE(0, RMDebug::module_indexif, "DBTCIndex", "deregisterInlineTile(" << it->getOId() << ") it not found")
+ }
+ }
+
+void
+DBTCIndex::addInlineTile(InlineTile* it)
+ {
+ if (!_isLoaded)
+ readInlineTiles();
+ DBObjectPPair p(it->getOId(), it);
+ inlineTiles.insert(p);
+ ObjectBroker::registerTileIndexMapping(it->getOId(), myOId);
+ setMappingHasChanged();
+ setInlineTileHasChanged();
+ }
+
+void
+DBTCIndex::insertInDb() throw (r_Error)
+ {
+ RMDBGENTER(5, RMDebug::module_indexif, "DBTCIndex", "insertInDb() " << myOId);
+ if (isLeaf())
+ {
+ decideForInlining();
+ if (inlineTileHasChanged || mappingHasChanged)
+ {
+ updateTileIndexMappings();
+ insertBlob();
+ storeTiles();
+ changeBOIdToIOId();
+ }
+ }
+ DBHierIndex::insertInDb();
+ if (isLeaf())
+ changeIOIdToBOId();
+ RMDBGEXIT(5, RMDebug::module_indexif, "DBTCIndex", "insertInDb() " << myOId);
+ }
+
+void
+DBTCIndex::readFromDb() throw (r_Error)
+ {
+ RMDBGENTER(5, RMDebug::module_indexif, "DBTCIndex", "readFromDb() " << myOId);
+ DBHierIndex::readFromDb();
+ if (isLeaf())
+ {
+ registerIOIds();
+ changeIOIdToBOId();
+ }
+ inlineTileHasChanged = false;
+ mappingHasChanged = false;
+ RMDBGEXIT(5, RMDebug::module_indexif, "DBTCIndex", "readFromDb() " << myOId);
+ }
+
+void
+DBTCIndex::updateInDb() throw (r_Error)
+ {
+ RMDBGENTER(5, RMDebug::module_indexif, "DBTCIndex", "updateInDb() " << myOId);
+ if (isLeaf())
+ decideForInlining();
+ if (mappingHasChanged)
+ updateTileIndexMappings();
+ if (inlineTileHasChanged)
+ storeTiles();
+ if (inlineTiles.size() != 0)
+ changeBOIdToIOId();
+ DBHierIndex::updateInDb();
+ if (isLeaf())
+ changeIOIdToBOId();
+ RMDBGEXIT(5, RMDebug::module_indexif, "DBTCIndex", "updateInDb() " << myOId);
+ }
+
+InlineTile*
+DBTCIndex::getInlineTile(const OId& itid)
+ {
+ InlineTile* retval = 0;
+ DBObjectPMap::iterator itit;
+ if (!_isLoaded)
+ {
+ readInlineTiles();
+ }
+ itit = inlineTiles.find(itid);
+ if (itit != inlineTiles.end())
+ {
+ retval = (InlineTile*)(*itit).second;
+ }
+ return retval;
+ }
+
+void
+DBTCIndex::readyForRemoval(const OId& id)
+ {
+ if (id.getType() == OId::INLINETILEOID)
+ {
+ DBObjectPMap::iterator itit;
+
+ itit = inlineTiles.find(id);
+ if (inlineTiles.end() != itit)
+ {
+ if (!_isLoaded)
+ {
+ readInlineTiles();
+ itit = inlineTiles.find(id);
+ ((*itit).second)->setCached(false);
+ ((InlineTile*)(*itit).second)->outlineTile();
+ }
+ else {
+ ((*itit).second)->setCached(false);
+ ((InlineTile*)(*itit).second)->outlineTile();
+ }
+ }
+ }
+ }
+
+bool
+DBTCIndex::removeObject(const KeyObject& entry)
+ {
+ RMDBGENTER(4, RMDebug::module_indexif, "DBTCIndex", "removeObject(" << entry << ") " << myOId);
+ if (isLeaf())
+ readyForRemoval(entry.getObject().getOId());
+ bool found = DBHierIndex::removeObject(entry);
+ RMDBGEXIT(4, RMDebug::module_indexif, "DBTCIndex", "removeEntry(" << entry << ") " << myOId << " " << found);
+ return found;
+ }
+
+bool
+DBTCIndex::removeObject(unsigned int pos)
+ {
+ RMDBGENTER(4, RMDebug::module_indexif, "DBTCIndex", "removeObject(" << pos << ") " << myOId);
+ if (isLeaf())
+ if (pos <= myKeyObjects.size())
+ readyForRemoval(myKeyObjects[pos].getObject().getOId());
+ bool found = DBHierIndex::removeObject((unsigned int)pos);
+ RMDBGEXIT(4, RMDebug::module_indexif, "DBTCIndex", "removeEntry(" << pos << ") " << myOId << " " << found);
+ return found;
+ }
+
+void
+DBTCIndex::decideForInlining()
+ {
+ RMDBGENTER(5, RMDebug::module_indexif, "DBTCIndex", "decideForInlining() " << myOId);
+ if (isLeaf())
+ {
+ InlineTile* itile = NULL;
+ KeyObjectVector::iterator it;
+ for (it = myKeyObjects.begin(); it != myKeyObjects.end(); it++)
+ {
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBTCIndex", " we do oid " << (*it));
+ if ((*it).getObject().getOId().getType() == OId::INLINETILEOID)
+ if ((itile = (InlineTile*)ObjectBroker::isInMemory((*it).getObject().getOId())) != 0)
+ {
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBTCIndex", "in memory");
+ //decide for inlineing
+ if (itile->isInlined())
+ {
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBTCIndex", "inlined");
+ if (itile->getSize() > StorageLayout::DefaultPCTMax)
+ {
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBTCIndex", "needs to be outlined");
+ itile->outlineTile();
+ }
+ }
+ else {
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBTCIndex", "outlined");
+ if (itile->getSize() < StorageLayout::DefaultMinimalTileSize)
+ {
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBTCIndex", "needs to be inlined");
+ itile->inlineTile(myOId);
+ }
+ }
+ }
+ else {
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBTCIndex", "not in memory");
+ }
+ }
+ }
+ RMDBGEXIT(5, RMDebug::module_indexif, "DBTCIndex", "decideForInlining() " << myOId);
+ }
+
diff --git a/relindexif/hierindex.hh b/relindexif/hierindex.hh
new file mode 100644
index 0000000..89b2043
--- /dev/null
+++ b/relindexif/hierindex.hh
@@ -0,0 +1,219 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#ifndef _DBHIERINDEX_HH_
+#define _DBHIERINDEX_HH_
+
+#include "reladminif/dbobject.hh"
+#include "indexmgr/hierindexds.hh"
+#include "relcatalogif/inlineminterval.hh"
+
+//@ManMemo: Module: {\bf relindexif}
+/*@Doc:
+This class stores data of hierarchical indexes in the database.
+
+There should be another interface to include the isLeaf/isRoot/...
+functionality.
+
+Beware of the cache when droping the IndexDS classes!
+
+See indexmgr/hierindexds.hh and indexmgr/indexds.hh for documentation.
+*/
+class DBHierIndex : public HierIndexDS
+ {
+ public:
+ DBHierIndex(r_Dimension dim, bool isNode, bool makePersistent);
+ /*@Doc:
+ constructs a new index with type ixType, dimension dim.
+ if isNode is true the index behaves as a node, else as
+ a leaf instance is imediately persistent
+ */
+
+ virtual double getOccupancy() const;
+
+ HierIndexDS* getParent() const;
+
+ void setParent(const HierIndexDS* newPa);
+
+ virtual void setIsNode(bool beNode);
+
+ virtual bool isLeaf() const;
+
+ virtual bool isRoot() const;
+ /*@Doc:
+ is a check for a valid myParent OId
+ */
+
+ virtual unsigned int getHeight() const;
+
+ virtual unsigned int getHeightOfTree() const;
+ /*@Doc:
+ Recursive function to get height of the tree.
+ */
+
+ virtual unsigned int getHeightToRoot() const;
+ /*@Doc:
+ Recursive function to get the number of levels to the root.
+ */
+
+ virtual unsigned int getHeightToLeaf() const;
+ /*@Doc:
+ Recursive function to get the number of levels to the
+ leafs.
+ */
+
+ virtual unsigned int getTotalEntryCount() const;
+
+ virtual unsigned int getTotalNodeCount() const;
+
+ virtual unsigned int getTotalLeafCount() const;
+
+ virtual r_Minterval getCoveredDomain() const;
+
+ virtual r_Minterval getAssignedDomain() const;
+
+ virtual r_Minterval getObjectDomain(unsigned int pos) const;
+
+ virtual r_Dimension getDimension() const;
+
+ virtual void setAssignedDomain(const r_Minterval& domain);
+
+ virtual unsigned int getSize() const;
+
+ virtual r_Bytes getTotalStorageSize() const;
+
+ virtual bool isValid() const;
+
+ virtual bool isUnderFull() const;
+
+ virtual bool isOverFull() const;
+
+ virtual bool isSameAs(const IndexDS* pix) const;
+
+ virtual bool removeObject(unsigned int pos);
+
+ virtual bool removeObject(const KeyObject& theKey);
+
+ virtual void insertObject(const KeyObject& theKey, unsigned int pos);
+
+ virtual void setObject(const KeyObject& theKey, unsigned int pos);
+
+ virtual void setObjectDomain(const r_Minterval& dom, unsigned int pos);
+
+ virtual const KeyObject& getObject(unsigned int pos) const;
+
+ virtual void getObjects(KeyObjectVector& objs) const;
+
+ virtual unsigned int getOptimalSize() const;
+
+ static unsigned int getOptimalSize(r_Dimension dim);
+ /*@Doc:
+ Used to calculate the optimal number of entries for
+ that dimension
+ */
+
+ virtual void freeDS();
+
+ virtual OId::OIdPrimitive getIdentifier() const;
+
+ static r_Bytes BytesPerTupel;
+ /*@Doc:
+ tuning parameter. used to calculate the optimal size of
+ an index. this is also the number of bytes written to the
+ database.
+ */
+
+ virtual void printStatus(unsigned int level = 0, std::ostream& stream = std::cout) const;
+
+ virtual ~DBHierIndex();
+
+ virtual void destroy();
+
+ virtual IndexDS* getNewInstance() const;
+
+ virtual BinaryRepresentation getBinaryRepresentation() const throw (r_Error);
+
+ virtual void setBinaryRepresentation(const BinaryRepresentation&) throw (r_Error);
+
+ protected:
+ friend class ObjectBroker;
+ /*@Doc:
+ ObjectBroker needs to access OId constructor
+ */
+
+ DBHierIndex(const OId& id);
+ /*@Doc:
+ */
+
+ virtual void readFromDb() throw (r_Error);
+ /*@Doc:
+ */
+
+ virtual void updateInDb() throw (r_Error);
+ /*@Doc:
+ */
+
+ virtual void deleteFromDb() throw (r_Error);
+ /*@Doc:
+ */
+
+ virtual void insertInDb() throw (r_Error);
+ /*@Doc:
+ */
+
+ void extendCoveredDomain(const r_Minterval& newTilesExtents) throw (r_Edim_mismatch, r_Eno_interval);
+ /*@Doc:
+ Recalculates the current domain of this index to
+ include newTilesExtents.
+ */
+
+ OId parent;
+ /*@Doc:
+ persistent, identifies the parent
+ */
+
+ bool _isNode;
+ /*@Doc:
+ persistent, tells the object what it is.
+ */
+
+
+ unsigned int maxSize;
+ /*@Doc:
+ Non persistent attribute. a cache so the maxSize does not have to be calculated all the time.
+ */
+
+ KeyObjectVector myKeyObjects;
+
+ InlineMinterval myDomain;
+ /*@Doc:
+ Defined domain of this index.
+ */
+
+ short currentDbRows;
+ /*@Doc:
+ is needed to support update of index in database
+ keeps the number of rows currently taken up in the db by
+ this instance
+ */
+ };
+#endif
diff --git a/relindexif/hierindex.pgc b/relindexif/hierindex.pgc
new file mode 100644
index 0000000..fa56b8b
--- /dev/null
+++ b/relindexif/hierindex.pgc
@@ -0,0 +1,745 @@
+#include "mymalloc/mymalloc.h"
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * Code with embedded SQL for PostgreSQL DBMS
+ *
+ *
+ * COMMENTS:
+ * - blobs contain 13c as first byte; this is not required here,
+ * but kept for data compatibility with other base DBMSs.
+ *
+ ************************************************************/
+
+// PG stuff:
+#include "libpq-fe.h" /* C interface to PgSQL */
+#include "libpq/libpq-fs.h" /* large object (lo) api */
+
+#include "debug-srv.hh"
+
+// general embedded SQL related definitions
+EXEC SQL include "../reladminif/sqlglobals.h";
+
+#include "hierindex.hh"
+#include "raslib/rmdebug.hh"
+#include "reladminif/sqlerror.hh"
+#include "relblobif/blobtile.hh"
+#include "indexmgr/keyobject.hh"
+
+// libpg connection maintenance
+extern PGconn *pgConn;
+
+void
+DBHierIndex::insertInDb() throw (r_Error)
+{
+ RMDBGENTER(5, RMDebug::module_indexif, "DBHierIndex", "insertInDb() " << myOId);
+ ENTER( "DBHierIndex::insertInDb(), myOId=" << myOId );
+
+#ifdef NOTYET // should be in future
+/*
+ EXEC SQL BEGIN DECLARE SECTION;
+*/
+#endif // NOTYET
+ double id2;
+ long dimension2;
+ long size2;
+ double parentid2;
+ short indexsubtype2;
+ Oid blobOid;
+ char pgQuery[SQL_QUERY_BUFFER_SIZE]; // prelim
+ PGresult *pgResult = NULL; // prelim
+#ifdef NOTYET // should be in future
+/*
+ EXEC SQL END DECLARE SECTION;
+*/
+#endif // NOTYET
+
+ // (0) --- prepare variables
+ id2 = myOId;
+ dimension2 = myDomain.dimension();
+ // size2 = myKeyObjects.size();
+ size2 = getSize();
+ indexsubtype2 = _isNode;
+
+ if (parent.getType() == OId::INVALID)
+ parentid2 = 0;
+ else
+ parentid2 = parent;
+
+ // (1) -­- set all buffers
+ //number of bytes for bounds for "size" entries and mydomain
+ r_Bytes boundssize = sizeof(r_Range) * (size2 + 1) * dimension2;
+ //number of bytes for fixes for "size" entries and mydomain
+ r_Bytes fixessize = sizeof(char) * (size2 + 1) * dimension2;
+ //number of bytes for ids of entries
+ r_Bytes idssize = sizeof(OId::OIdCounter) * size2;
+ //number of bytes for types of entries
+ r_Bytes typessize = sizeof(char) * size2;
+ //number of bytes for the dynamic data, plus 1 starter byte (see below)
+ r_Bytes completesize = 1 + boundssize * 2 + fixessize * 2 + idssize + typessize;
+
+ char* completebuffer = (char*)mymalloc(completesize);
+ if (completebuffer == NULL)
+ {
+ RMInit::logOut << "DBHierIndex::insertInDb() cannot malloc buffer" << endl;
+ LEAVE( "DBHierIndex::insertInDb() cannot malloc buffer" );
+ throw r_Error( r_Error::r_Error_MemoryAllocation );
+ }
+ r_Range* upperboundsbuf = (r_Range*)mymalloc(boundssize);
+ if (upperboundsbuf == NULL)
+ {
+ RMInit::logOut << "DBHierIndex::insertInDb() cannot malloc buffer" << endl;
+ LEAVE( "DBHierIndex::insertInDb() cannot malloc buffer" );
+ throw r_Error( r_Error::r_Error_MemoryAllocation );
+ }
+ r_Range* lowerboundsbuf = (r_Range*)mymalloc(boundssize);
+ if (lowerboundsbuf == NULL)
+ {
+ RMInit::logOut << "DBHierIndex::insertInDb() cannot malloc buffer" << endl;
+ LEAVE( "DBHierIndex::insertInDb() cannot malloc buffer" );
+ throw r_Error( r_Error::r_Error_MemoryAllocation );
+ }
+ char* upperfixedbuf = (char*)mymalloc(fixessize);
+ if (upperfixedbuf == NULL)
+ {
+ RMInit::logOut << "DBHierIndex::insertInDb() cannot malloc buffer" << endl;
+ LEAVE( "DBHierIndex::insertInDb() cannot malloc buffer" );
+ throw r_Error( r_Error::r_Error_MemoryAllocation );
+ }
+ char* lowerfixedbuf = (char*)mymalloc(fixessize);
+ if (lowerfixedbuf == NULL)
+ {
+ RMInit::logOut << "DBHierIndex::insertInDb() cannot malloc buffer" << endl;
+ LEAVE( "DBHierIndex::insertInDb() cannot malloc buffer" );
+ throw r_Error( r_Error::r_Error_MemoryAllocation );
+ }
+ OId::OIdCounter* entryidsbuf = (OId::OIdCounter*)mymalloc(idssize);
+ if (entryidsbuf == NULL)
+ {
+ RMInit::logOut << "DBHierIndex::insertInDb() cannot malloc buffer" << endl;
+ LEAVE( "DBHierIndex::insertInDb() cannot malloc buffer" );
+ throw r_Error( r_Error::r_Error_MemoryAllocation );
+ }
+ char* entrytypesbuf = (char*)mymalloc(typessize);
+ if (entrytypesbuf == NULL)
+ {
+ RMInit::logOut << "DBHierIndex::insertInDb() cannot malloc buffer" << endl;
+ LEAVE( "DBHierIndex::insertInDb() cannot malloc buffer" );
+ throw r_Error( r_Error::r_Error_MemoryAllocation );
+ }
+
+ RMDBGMIDDLE(8, RMDebug::module_indexif, "DBHierIndex", "complete=" << completesize << " bounds=" << boundssize << " fixes=" << fixessize << " ids=" << idssize << " types=" << typessize << ", size=" << size2 << " dimension=" << dimension2 );
+
+ myDomain.insertInDb(&(lowerboundsbuf[0]), &(upperboundsbuf[0]), &(lowerfixedbuf[0]), &(upperfixedbuf[0]));
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBHierIndex", "domain " << myDomain << " stored as " << InlineMinterval(dimension2, &(lowerboundsbuf[0]), &(upperboundsbuf[0]), &(lowerfixedbuf[0]), &(upperfixedbuf[0])));
+ //populate the buffers with data
+ KeyObjectVector::iterator it = myKeyObjects.begin();
+ InlineMinterval indom;
+ for (unsigned int i = 0; i < size2; i++, it++)
+ {
+ indom = (*it).getDomain();
+ indom.insertInDb(&(lowerboundsbuf[(i+1)*dimension2]), &(upperboundsbuf[(i+1)*dimension2]), &(lowerfixedbuf[(i+1)*dimension2]), &(upperfixedbuf[(i+1)*dimension2]));
+ entryidsbuf[i] = (*it).getObject().getOId().getCounter();
+ entrytypesbuf[i] = (char)(*it).getObject().getOId().getType();
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBHierIndex", "entry " << entryidsbuf[i] << " " << (OId::OIdType)entrytypesbuf[i] << " at " << InlineMinterval(dimension2, &(lowerboundsbuf[(i+1)*dimension2]), &(upperboundsbuf[(i+1)*dimension2]), &(lowerfixedbuf[(i+1)*dimension2]), &(upperfixedbuf[(i+1)*dimension2])));
+ }
+
+ // write the buffers in the complete buffer, free all unnecessary buffers
+ // this indirection is neccessary because of memory alignement of longs...
+ completebuffer[0] = 13; //the first char must not be a \0
+ (void) memcpy( &completebuffer[1], lowerboundsbuf, boundssize);
+ free(lowerboundsbuf);
+ (void) memcpy( &completebuffer[boundssize + 1], upperboundsbuf, boundssize);
+ free(upperboundsbuf);
+ (void) memcpy( &completebuffer[boundssize * 2 + 1], lowerfixedbuf, fixessize);
+ free(lowerfixedbuf);
+ (void) memcpy( &completebuffer[boundssize * 2 + fixessize + 1], upperfixedbuf, fixessize);
+ free(upperfixedbuf);
+ (void) memcpy( &completebuffer[boundssize * 2 + fixessize * 2 + 1], entryidsbuf, idssize);
+ free(entryidsbuf);
+ (void) memcpy( &completebuffer[boundssize * 2 + fixessize * 2 + idssize + 1], entrytypesbuf, typessize);
+ free(entrytypesbuf);
+
+#ifdef RMANDEBUG // dump low-level blob byte string
+{
+ char printbuf[10000];
+ (void) sprintf( printbuf, "XXX DBHierIndex::insertInDb(): [%d]", completesize );
+ char bytebuf[3];
+ for (unsigned int i = 0; i < completesize; i++)
+ {
+ (void) sprintf( bytebuf, " %2X", (unsigned char) completebuffer[i] );
+ strcat( printbuf, bytebuf );
+ }
+ TALK( printbuf );
+}
+#endif // RMANDEBUG
+
+ // (2) --- create, open, write, close blob; generates new 'oid' for subsequent storage in tuple
+ TALK( "lo_creat()" );
+ blobOid = lo_creat( pgConn, INV_READ|INV_WRITE ); // create -- not clear what INV_* here means so indicate all
+ if (blobOid == 0)
+ {
+ RMInit::logOut << "DBHierIndex::insertInDb() cannot create blob, error: " << PQerrorMessage(pgConn) << endl;
+ LEAVE( "DBHierIndex::insertInDb(pgConn)" );
+ generateException();
+ }
+ TALK( "lo_open() for oid " << blobOid );
+ int fd = lo_open( pgConn, blobOid, INV_WRITE ); // no error code indicated, 0 seems to be no error
+ TALK( "lo_write() for fd " << fd << " with " << completesize << " bytes" );
+ int loResult = lo_write( pgConn, fd, completebuffer, completesize );
+ if (loResult < 0)
+ {
+ RMInit::logOut << "DBHierIndex::insertInDb() cannot write blob, error: " << PQerrorMessage(pgConn) << endl;
+ LEAVE( "DBHierIndex::insertInDb() cannot write blob, error " << PQerrorMessage(pgConn) );
+ generateException();
+ }
+ else if (loResult != completesize) // did not get all
+ {
+ RMInit::dbgOut << "BLOB (" << myOId << ") insert: wrote " << loResult << " instead of " << completesize << " bytes" << endl;
+ LEAVE( "DBHierIndex::insertInDb() wrote " << loResult << " instead of " << completesize << " bytes" );
+ generateException();
+ }
+ TALK( "lo_close()" );
+ loResult = lo_close( pgConn, fd );
+ if (loResult < 0) // can't close, don't know if data are written
+ {
+ RMInit::logOut << "DBHierIndex::insertInDb() ignoring lo_close() error: " << PQerrorMessage(pgConn) << endl;
+ LEAVE( "DBHierIndex::insertInDb() cannot lo_close(): " << PQerrorMessage(pgConn) );
+ generateException();
+ }
+
+ free(completebuffer); // free main buffer
+
+ // (3) --- insert HIERIX tuple into db
+#ifdef NOTYET // should be in future
+/*
+ TALK( "EXEC SQL INSERT INTO RAS_HIERIX ( MDDObjIxOId, NumEntries, Dimension, ParentOId, IndexSubType, DynData ) VALUES ( " << id2 << "," << size2 << "," << dimension2 << "," << parentid2 << "," << indexsubtype2 << ", " << blobOid << " )" );
+ EXEC SQL INSERT INTO RAS_HIERIX ( MDDObjIxOId, NumEntries, Dimension, ParentOId, IndexSubType, DynData)
+ VALUES ( :id2, :size2, :dimension2, :parentid2, :indexsubtype2, :blobOid);
+ if (SQLCODE != SQLOK)
+ {
+ check("DBHierIndex::insertInDb() insert into RAS_HIERIX\0");
+ LEAVE( "DBHierIndex::insertInDb(): db access error: " << SQLCODE );
+ generateException();
+ }
+*/
+#endif // NOTYET
+ // alternative solution for now:
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "INSERT INTO RAS_HIERIX ( MDDObjIxOId, NumEntries, Dimension, ParentOId, IndexSubType, DynData ) VALUES ( %f, %d, %d, %f, %d, %d )", id2, size2, dimension2, parentid2, indexsubtype2, blobOid );
+ TALK( pgQuery );
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_COMMAND_OK)
+ {
+ LEAVE( "DBHierIndex::insertInDb() libpq 'insert RAS_HIERIX' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+ PQclear( pgResult );
+
+ // (4) --- dbobject insert
+ DBObject::insertInDb();
+
+ RMDBGEXIT(5, RMDebug::module_indexif, "DBHierIndex", "insertInDb() " << myOId);
+ LEAVE( "DBHierIndex::insertInDb(), myOId=" << myOId );
+} // insertInDb()
+
+void
+DBHierIndex::readFromDb() throw (r_Error)
+{
+ RMDBGENTER(5, RMDebug::module_indexif, "DBHierIndex", "readFromDb() " << myOId);
+ ENTER( "DBHierIndex::readFromDb(), myOId=" << myOId );
+
+#ifdef RMANBENCHMARK
+ DBObject::readTimer.resume();
+#endif
+#ifdef NOTYET // should be in future
+/*
+ EXEC SQL BEGIN DECLARE SECTION;
+*/
+#endif // NOTYET
+ double id1;
+ double parentid1;
+ long dimension1;
+ long size1;
+ short indexsubtype1;
+ short lowerfind;
+ Oid blobOid;
+ char pgQuery[SQL_QUERY_BUFFER_SIZE]; // prelim
+ PGresult *pgResult = NULL; // prelim
+#ifdef NOTYET // should be in future
+/*
+ EXEC SQL END DECLARE SECTION;
+*/
+#endif // NOTYET
+
+ // (0) --- prepare variables
+ id1 = myOId;
+
+ // (1) --- fetch tuple from database
+#ifdef NOTYET // should be in future
+/*
+ TALK( "EXEC SQL SELECT NumEntries, Dimension, ParentOId, IndexSubType, DynData INTO :size1, :dimension1, :parentid1, :indexsubtype1, blobOid FROM RAS_HIERIX WHERE MDDObjIxOId = " << id1 );
+ EXEC SQL SELECT NumEntries, Dimension, ParentOId, IndexSubType, DynData
+ INTO :size1, :dimension1, :parentid1, :indexsubtype1, :blobOid
+ FROM RAS_HIERIX
+ WHERE MDDObjIxOId = :id1;
+ if (SQLCODE != SQLOK)
+ {
+ check("DBHierIndex::readFromDb() select from RAS_HIERIX");
+ LEAVE( "DBHierIndex::insertInDb() 'select from RAS_HIERIX' error: " << SQLCODE );
+ generateException();
+ }
+*/
+#endif // NOTYET
+ // alternative solution for now:
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "SELECT NumEntries, Dimension, ParentOId, IndexSubType, DynData FROM RAS_HIERIX WHERE MDDObjIxOId = %f", id1 );
+ TALK( pgQuery );
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_TUPLES_OK)
+ {
+ LEAVE( "DBHierIndex::insertInDb() libpq 'select RAS_HIERIX' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+ size1 = atoi( PQgetvalue( pgResult, 0, 0 ) ); // extract value #1 from result
+ dimension1 = atoi( PQgetvalue( pgResult, 0, 1 ) ); // extract value #2 from result
+ parentid1 = atoi( PQgetvalue( pgResult, 0, 2 ) ); // extract value #3 from result
+ indexsubtype1 = atoi( PQgetvalue( pgResult, 0, 3 ) ); // extract value #4 from result
+ blobOid = atoi( PQgetvalue( pgResult, 0, 4 ) ); // extract value #5 from result
+ PQclear( pgResult );
+
+ // (2) --- fill variables and buffers
+
+ _isNode = indexsubtype1;
+
+ if (parentid1)
+ parent = OId(parentid1);
+ else
+ parent = OId(0, OId::INVALID);
+
+ //number of bytes for bounds for "size" entries and mydomain
+ r_Bytes boundssize = sizeof(r_Range) * (size1 + 1) * dimension1;
+ //number of bytes for fixes for "size" entries and mydomain
+ r_Bytes fixessize = sizeof(char) * (size1 + 1) * dimension1;
+ //number of bytes for ids of entries
+ r_Bytes idssize = sizeof(OId::OIdCounter) * size1;
+ //number of bytes for types of entries
+ r_Bytes typessize = sizeof(char) * size1;
+ //number of bytes for the dynamic data (1 starter byte!)
+ r_Bytes completesize = 1 + boundssize * 2 + fixessize * 2 + idssize + typessize;
+
+ RMDBGMIDDLE(8, RMDebug::module_indexif, "DBHierIndex", "complete=" << completesize << " bounds=" << boundssize << " fixes=" << fixessize << " ids=" << idssize << " types=" << typessize << ", size=" << size1 << " dimension=" << dimension1 );
+
+ char* completebuffer = (char*)mymalloc(completesize);
+ r_Range* upperboundsbuf = (r_Range*)mymalloc(boundssize);
+ r_Range* lowerboundsbuf = (r_Range*)mymalloc(boundssize);
+ char* upperfixedbuf = (char*)mymalloc(fixessize);
+ char* lowerfixedbuf = (char*)mymalloc(fixessize);
+ OId::OIdCounter* entryidsbuf = (OId::OIdCounter*)mymalloc(idssize);
+ char* entrytypesbuf = (char*)mymalloc(typessize);
+
+ // (3) --- open, read, close blob
+ TALK( "lo_open()" );
+ int fd = lo_open( pgConn, blobOid, INV_READ ); // open; manual tells no error indication
+ TALK( "lo_lseek() end" );
+ int bytesToDo = lo_lseek( pgConn, fd, 0, SEEK_END ); // determine blob size; FIXME: more efficient method??
+ TALK( "lo_lseek() start" );
+ (void) lo_lseek( pgConn, fd, 0, SEEK_SET ); // rewind for reading
+ TALK( "lo_read() for " << completesize << " bytes" ); // read blob
+ int loResult = lo_read( pgConn, fd, completebuffer, completesize );
+ if (loResult < 0)
+ {
+ RMInit::logOut << "DBHierIndex::readFromDb() cannot read blob, error: " << pgResult << endl;
+ LEAVE( "DBHierIndex::readFromDb: cannot read blob, error " << pgResult );
+ throw r_Error( r_Error::r_Error_BaseDBMSFailed );
+ }
+ else if (loResult != bytesToDo) // did not get all
+ {
+ RMInit::dbgOut << "BLOB (" << myOId << ") read: want to read (" << bytesToDo << " bytes, but got " << loResult << " bytes" << endl;
+ LEAVE( "DBHierIndex::readFromDb: want to read " << bytesToDo << " bytes, but got " << loResult << " bytes" );
+ throw r_Error( r_Error::r_Error_LimitsMismatch );
+ }
+ else if (completesize != bytesToDo) // this because I don't trust computations
+ {
+ RMInit::dbgOut << "BLOB (" << myOId << ") read: completesize=" << completesize << ", but bytesToDo=" << bytesToDo << endl;
+ LEAVE( "DBHierIndex::readFromDb: completesize=" << completesize << ", but bytesToDo=" << bytesToDo );
+ throw r_Error( r_Error::r_Error_LimitsMismatch );
+ }
+ TALK( "lo_close()" );
+ int ignoredPgResult = lo_close( pgConn, fd ); // close blob
+ if (ignoredPgResult < 0) // we note, but ignore errors, as we have the data
+ {
+ RMInit::logOut << "DBHierIndex::readFromDb() ignoring lo_close() error: " << ignoredPgResult << endl;
+ TALK( "DBHierIndex::readFromDb: ignoring lo_close() error: " << ignoredPgResult );
+ }
+
+#ifdef RMANDEBUG // dump low-level blob byte string
+{
+ char printbuf[10000];
+ (void) sprintf( printbuf, "XXX DBHierIndex::readFromDb(): [%d]", completesize );
+ char bytebuf[3];
+ for (unsigned int i = 0; i < completesize; i++)
+ {
+ (void) sprintf( bytebuf, " %2X", (unsigned char) completebuffer[i] );
+ strcat( printbuf, bytebuf );
+ }
+ TALK( printbuf );
+}
+#endif // RMANDEBUG
+
+ // (4) --- copy data into buffers
+ // all dynamic data ( plus starter byte) is in completebuffer, put that stuff in the correct buffers
+ memcpy(lowerboundsbuf, &completebuffer[1], boundssize);
+ memcpy(upperboundsbuf, &completebuffer[boundssize + 1], boundssize);
+ memcpy(lowerfixedbuf, &completebuffer[boundssize * 2 + 1], fixessize);
+ memcpy(upperfixedbuf, &completebuffer[boundssize * 2 + fixessize + 1], fixessize);
+ memcpy(entryidsbuf, &completebuffer[boundssize * 2 + fixessize * 2 + 1], idssize);
+ memcpy(entrytypesbuf, &completebuffer[boundssize * 2 + fixessize * 2 + idssize + 1], typessize);
+ // now all dynamic data is in its private buffer
+ free (completebuffer);
+ completebuffer = NULL;
+
+ // rebuild the attributes from the buffers
+ int i = 0;
+ myDomain = InlineMinterval(dimension1, &(lowerboundsbuf[0]), &(upperboundsbuf[0]), &(lowerfixedbuf[0]), &(upperfixedbuf[i*dimension1]));
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBHierIndex", "domain " << myDomain << " constructed from " << InlineMinterval(dimension1, &(lowerboundsbuf[0]), &(upperboundsbuf[0]), &(lowerfixedbuf[0]), &(upperfixedbuf[0])));
+ KeyObject theKey = KeyObject(DBObjectId(), myDomain);
+ for (i = 0; i < size1; i++)
+ {
+ theKey.setDomain(InlineMinterval(dimension1, &(lowerboundsbuf[(i+1)*dimension1]), &(upperboundsbuf[(i+1)*dimension1]), &(lowerfixedbuf[(i+1)*dimension1]), &(upperfixedbuf[(i+1)*dimension1])));
+ theKey.setObject(OId(entryidsbuf[i], (OId::OIdType)entrytypesbuf[i]));
+ myKeyObjects.push_back(theKey);
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBHierIndex", "entry " << entryidsbuf[i] << " " << (OId::OIdType)entrytypesbuf[i] << " at " << InlineMinterval(dimension1, &(lowerboundsbuf[(i+1)*dimension1]), &(upperboundsbuf[(i+1)*dimension1]), &(lowerfixedbuf[(i+1)*dimension1]), &(upperfixedbuf[(i+1)*dimension1])));
+ }
+
+ free(upperboundsbuf);
+ free(lowerboundsbuf);
+ free(upperfixedbuf);
+ free(lowerfixedbuf);
+ free(entryidsbuf);
+ free(entrytypesbuf);
+
+#ifdef RMANBENCHMARK
+ DBObject::readTimer.pause();
+#endif
+
+ // (5) --- fill dbobject
+ DBObject::readFromDb();
+
+ RMDBGEXIT(5, RMDebug::module_indexif, "DBHierIndex", "readFromDb() " << myOId);
+ LEAVE( "DBHierIndex::readFromDb(), myOId=" << myOId );
+} // readFromDb()
+
+void
+DBHierIndex::updateInDb() throw (r_Error)
+{
+ RMDBGENTER(5, RMDebug::module_indexif, "DBHierIndex", "updateInDb() " << myOId);
+ ENTER( "DBHierIndex::updateInDb(), myOId=" << myOId );
+
+#ifdef NOTYET // should be in future
+/*
+ EXEC SQL BEGIN DECLARE SECTION;
+*/
+#endif // NOTYET
+ double id4;
+ long dimension4;
+ long size4;
+ double parentid4;
+ short count4;
+ short indexsubtype4;
+ Oid blobOid;
+ char pgQuery[SQL_QUERY_BUFFER_SIZE]; // prelim
+ PGresult *pgResult = NULL; // prelim
+#ifdef NOTYET // should be in future
+/*
+ EXEC SQL END DECLARE SECTION;
+*/
+#endif // NOTYET
+
+ // (0) --- prepare variables
+ id4 = myOId;
+ indexsubtype4 = _isNode;
+ dimension4 = myDomain.dimension();
+ size4 = myKeyObjects.size();
+ if (parent.getType() == OId::INVALID)
+ parentid4 = 0;
+ else
+ parentid4 = parent;
+
+ // (1) --- prepare buffer
+ //number of bytes for bounds for "size" entries and mydomain
+ r_Bytes boundssize = sizeof(r_Range) * (size4 + 1) * dimension4;
+ //number of bytes for fixes for "size" entries and mydomain
+ r_Bytes fixessize = sizeof(char) * (size4 + 1) * dimension4;
+ //number of bytes for ids of entries
+ r_Bytes idssize = sizeof(OId::OIdCounter) * size4;
+ //number of bytes for types of entries
+ r_Bytes typessize = sizeof(char) * size4;
+ //number of bytes for the dynamic data; 1 starter byte!
+ r_Bytes completesize = 1 + boundssize * 2 + fixessize * 2 + idssize + typessize;
+
+ char* completebuffer = (char*)mymalloc(completesize);
+ r_Range* upperboundsbuf = (r_Range*)mymalloc(boundssize);
+ r_Range* lowerboundsbuf = (r_Range*)mymalloc(boundssize);
+ char* upperfixedbuf = (char*)mymalloc(fixessize);
+ char* lowerfixedbuf = (char*)mymalloc(fixessize);
+ OId::OIdCounter* entryidsbuf = (OId::OIdCounter*)mymalloc(idssize);
+ char* entrytypesbuf = (char*)mymalloc(typessize);
+
+ // populate the buffers with data
+ myDomain.insertInDb(&(lowerboundsbuf[0]), &(upperboundsbuf[0]), &(lowerfixedbuf[0]), &(upperfixedbuf[0]));
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBHierIndex", "domain " << myDomain << " stored as " << InlineMinterval(dimension4, &(lowerboundsbuf[0]), &(upperboundsbuf[0]), &(lowerfixedbuf[0]), &(upperfixedbuf[0])));
+
+ KeyObjectVector::iterator it = myKeyObjects.begin();
+ InlineMinterval indom;
+ for (unsigned int i = 0; i < size4; i++, it++)
+ {
+ indom = (*it).getDomain();
+ indom.insertInDb(&(lowerboundsbuf[(i+1)*dimension4]), &(upperboundsbuf[(i+1)*dimension4]), &(lowerfixedbuf[(i+1)*dimension4]), &(upperfixedbuf[(i+1)*dimension4]));
+ entryidsbuf[i] = (*it).getObject().getOId().getCounter();
+ entrytypesbuf[i] = (char)(*it).getObject().getOId().getType();
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBHierIndex", "entry " << entryidsbuf[i] << " " << (OId::OIdType)entrytypesbuf[i] << " at " << InlineMinterval(dimension4, &(lowerboundsbuf[(i+1)*dimension4]), &(upperboundsbuf[(i+1)*dimension4]), &(lowerfixedbuf[(i+1)*dimension4]), &(upperfixedbuf[(i+1)*dimension4])));
+ }
+
+ RMDBGMIDDLE(8, RMDebug::module_indexif, "DBHierIndex", "complete=" << completesize << " bounds=" << boundssize << " fixes=" << fixessize << " ids=" << idssize << " types=" << typessize << ", size=" << size4 << " dimension=" << dimension4 );
+
+ // write the buffers in the complete buffer, plus starter byte
+ // this indirection is neccessary because of memory alignement of longs...
+ completebuffer[0] = 13; // write dummy starter byte
+ memcpy( &completebuffer[1], lowerboundsbuf, boundssize);
+ free(lowerboundsbuf);
+ memcpy( &completebuffer[boundssize + 1], upperboundsbuf, boundssize);
+ free(upperboundsbuf);
+ memcpy( &completebuffer[boundssize * 2 + 1], lowerfixedbuf, fixessize);
+ free(lowerfixedbuf);
+ memcpy( &completebuffer[boundssize * 2 + fixessize + 1], upperfixedbuf, fixessize);
+ free(upperfixedbuf);
+ memcpy( &completebuffer[boundssize * 2 + fixessize * 2 + 1], entryidsbuf, idssize);
+ free(entryidsbuf);
+ memcpy( &completebuffer[boundssize * 2 + fixessize * 2 + idssize + 1], entrytypesbuf, typessize);
+ free(entrytypesbuf);
+
+#ifdef RMANDEBUG // dump low-level blob byte string
+{
+ char printbuf[10000];
+ (void) sprintf( printbuf, "XXX DBHierIndex::updateInDb(): [%d]", completesize );
+ char bytebuf[3];
+ for (unsigned int i = 0; i < completesize; i++)
+ {
+ (void) sprintf( bytebuf, " %2X", (unsigned char) completebuffer[i] );
+ strcat( printbuf, bytebuf );
+ }
+ TALK( printbuf );
+}
+#endif // RMANDEBUG
+
+ // (2) --- write complete buffer to new database blob
+ // create, open, write, close blob; generates new 'oid' for subsequent storage in tuple
+ TALK( "lo_creat()" );
+ blobOid = lo_creat( pgConn, INV_READ|INV_WRITE ); // create -- not clear what INV_* here means so indicate all
+ if (blobOid == 0)
+ {
+ RMInit::logOut << "DBHierIndex::updateInDb() cannot create blob, error: " << PQerrorMessage(pgConn) << endl;
+ LEAVE( "DBHierIndex::updateInDb(pgConn)" );
+ generateException();
+ }
+ TALK( "lo_open() for oid " << blobOid );
+ int fd = lo_open( pgConn, blobOid, INV_WRITE ); // no error code indicated, 0 seems to be no error
+ TALK( "lo_write() for fd " << fd << " for " << completesize << " bytes" );
+ int loResult = lo_write( pgConn, fd, completebuffer, completesize );
+ if (loResult < 0)
+ {
+ RMInit::logOut << "DBHierIndex::updateInDb() cannot write blob, error: " << PQerrorMessage(pgConn) << endl;
+ LEAVE( "DBHierIndex::updateInDb() cannot write blob, error " << PQerrorMessage(pgConn) );
+ generateException();
+ }
+ else if (loResult != completesize) // did not get all
+ {
+ RMInit::dbgOut << "BLOB (" << myOId << ") update: wrote " << loResult << " instead of " << completesize << " bytes" << endl;
+ LEAVE( "DBHierIndex::updateInDb() wrote " << loResult << " instead of " << completesize << " bytes" );
+ generateException();
+ }
+ TALK( "lo_close()" );
+ loResult = lo_close( pgConn, fd );
+ if (loResult < 0) // can't close, don't know if data are written
+ {
+ RMInit::logOut << "DBHierIndex::updateInDb() ignoring lo_close() error: " << PQerrorMessage(pgConn) << endl;
+ LEAVE( "DBHierIndex::updateInDb() cannot lo_close(): " << PQerrorMessage(pgConn) );
+ generateException();
+ }
+ free(completebuffer);
+ completebuffer = NULL;
+
+ // (3) -- update HierIx entry
+#ifdef NOTYET // should be in future
+/*
+ TALK( "EXEC SQL UPDATE RAS_HIERIX SET NumEntries = " << size4 << ", Dimension = " << dimension4 << ", ParentOId = " << parentid4 << ", IndexSubType = " << indexsubtype4 << ", DynData = " << blobOid );
+ EXEC SQL UPDATE RAS_HIERIX
+ SET NumEntries = :size4, Dimension = :dimension4, ParentOId = :parentid4, IndexSubType = :indexsubtype4, DynData = :blobOid
+ WHERE MDDObjIxOId = :id4;
+ if (SQLCODE != SQLOK)
+ {
+ check("DBHierIndex::updateInDb() update RAS_HIERIX");
+ LEAVE( "DBHierIndex::updateInDb(): db access error: " << SQLCODE );
+ generateException();
+ }
+*/
+#endif // NOTYET
+ // alternative solution for now:
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "UPDATE RAS_HIERIX SET NumEntries = %d, Dimension = %d, ParentOId = %f, IndexSubType = %d, DynData = %d WHERE MDDObjIxOId = %f", size4, dimension4, parentid4, indexsubtype4, blobOid, id4 );
+ TALK( pgQuery );
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_COMMAND_OK)
+ {
+ LEAVE( "DBHierIndex::updateInDb() libpq 'UPDATE HierIx' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+ PQclear( pgResult );
+
+ // (4) --- dbobject update
+ DBObject::updateInDb();
+
+ RMDBGEXIT(5, RMDebug::module_indexif, "DBHierIndex", "updateInDb() " << myOId);
+ LEAVE( "DBHierIndex::updateInDb(), myOId=" << myOId );
+} // updateInDb()
+
+void
+DBHierIndex::deleteFromDb() throw (r_Error)
+{
+ RMDBGENTER(8, RMDebug::module_indexif, "DBHierIndex", "deleteFromDb() " << myOId);
+ ENTER( "DBHierIndex::deleteFromDb(), myOId=" << myOId );
+
+#ifdef NOTYET // should be in future
+/*
+ EXEC SQL BEGIN DECLARE SECTION;
+*/
+#endif // NOTYET
+ double id3;
+ Oid blobOid;
+ char pgQuery[SQL_QUERY_BUFFER_SIZE]; // prelim
+ PGresult *pgResult = NULL; // prelim
+#ifdef NOTYET // should be in future
+/*
+ EXEC SQL END DECLARE SECTION;
+*/
+#endif // NOTYET
+
+ OId oi;
+ DBObjectId dbo;
+ while (!myKeyObjects.empty())
+ {
+ oi = myKeyObjects.begin()->getObject().getOId();
+ DBObjectId dbo;
+ if ((oi.getType() == OId::BLOBOID) || (oi.getType() == OId::INLINETILEOID))
+ {
+ BLOBTile::kill(oi);
+ }
+ else
+ {
+ dbo = DBObjectId(oi);
+ if (!dbo.is_null())
+ {
+ dbo->setCached(false);
+ dbo->setPersistent(false);
+ dbo = (unsigned int)0;
+ }
+ }
+ myKeyObjects.erase(myKeyObjects.begin());
+ }
+
+ id3 = myOId;
+
+ // (1) --- get blob oid
+#ifdef NOTYET // should be in future
+/*
+ TALK( "EXEC SQL SELECT DynData INTO :blobOid FROM RAS_HIERIX WHERE MDDObjIxOId = " << id3 );
+ EXEC SQL SELECT DynData
+ INTO :blobOid
+ FROM RAS_HIERIX
+ WHERE MDDObjIxOId = :id3;
+ if (SQLCODE != SQLOK)
+ {
+ check("DBHierIndex::deleteFromDb() select from RAS_HIERIX");
+ LEAVE( "DBHierIndex::deleteFromDb() select from RAS_HIERIX: error: " << SQLCODE );
+ generateException();
+ }
+*/
+#endif // NOTYET
+ // alternative solution for now:
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "SELECT DynData FROM RAS_HIERIX WHERE MDDObjIxOId = %f", id3 );
+ TALK( pgQuery );
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_TUPLES_OK)
+ {
+ LEAVE( "DBHierIndex::deleteFromDb() libpq 'select RAS_HIERIX' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+ blobOid = atoi( PQgetvalue( pgResult, 0, 0 ) ); // extract value from result
+ PQclear( pgResult );
+
+ // (2) --- delete blob
+ int loResult = lo_unlink( pgConn, blobOid );
+ if (loResult < 0) // no disaster if we can't so no exception
+ {
+ TALK( "DBHierIndex::deleteFromDb() warning: libpq 'unlink blob' error: " << PQerrorMessage(pgConn) );
+ }
+
+ // (3) --- delete tuple
+#ifdef NOTYET // should be in future
+/*
+ TALK( "EXEC SQL DELETE FROM RAS_HIERIX WHERE MDDObjIxOId = " << id3 );
+ EXEC SQL DELETE FROM RAS_HIERIX
+ WHERE MDDObjIxOId = :id3;
+ if (SQLCODE != SQLOK)
+ {
+ check("DBHierIndex::deleteFromDb() RAS_HIERIX");
+ LEAVE( "DBHierIndex::deleteFromDb(): db access error: " << SQLCODE );
+ generateException();
+ }
+*/
+#endif // NOTYET
+ // alternative solution for now:
+ (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "DELETE FROM RAS_HIERIX WHERE MDDObjIxOId = %f", id3 );
+ TALK( pgQuery );
+ pgResult = PQexec( pgConn, pgQuery );
+ if (PQresultStatus(pgResult) != PGRES_COMMAND_OK)
+ {
+ LEAVE( "DBHierIndex::updateInDb() libpq 'DELETE HierIx' error: " << PQerrorMessage(pgConn) );
+ PQclear( pgResult );
+ generateException();
+ }
+ PQclear( pgResult );
+
+ // (4) --- dbobject delete
+ DBObject::deleteFromDb();
+
+ RMDBGEXIT(8, RMDebug::module_indexif, "DBHierIndex", "deleteFromDb() " << myOId);
+ LEAVE( "DBHierIndex::deleteFromDb(), myOId=" << myOId );
+} // deleteFromDb()
+
diff --git a/relindexif/hierindexcommon.cc b/relindexif/hierindexcommon.cc
new file mode 100644
index 0000000..61ce20c
--- /dev/null
+++ b/relindexif/hierindexcommon.cc
@@ -0,0 +1,1033 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * maintain the hierarchical index in the DBMS.
+ *
+ *
+ * COMMENTS:
+ * - relies on the same-name DBMS preprocessor sources for the
+ * various DBMSs supported.
+ *
+ ************************************************************/
+
+#include <cstring>
+
+#include "mymalloc/mymalloc.h"
+#include "hierindex.hh"
+#include "reladminif/objectbroker.hh"
+#include "reladminif/dbref.hh"
+#include "raslib/rmdebug.hh"
+#include "reladminif/lists.h"
+#include "reladminif/sqlerror.hh"
+#include "reladminif/externs.h"
+#include "relblobif/blobtile.hh"
+#include "indexmgr/keyobject.hh"
+#include "storagemgr/sstoragelayout.hh"
+#include "raslib/endian.hh"
+#include "debug.hh"
+
+DBHierIndex::DBHierIndex(const OId& id)
+ : HierIndexDS(id),
+ currentDbRows(0),
+ myDomain((r_Dimension)0),
+ maxSize(0),
+ parent(0),
+ _isNode(false)
+ {
+ RMDBGENTER(7, RMDebug::module_indexif, "DBHierIndex", "DBHierIndex(" << myOId << ")");
+ ENTER( "DBHierIndex::DBHierIndex(" << myOId << ")" );
+
+ if (id.getType() == OId::MDDHIERIXOID)
+ readFromDb();
+ maxSize = DBHierIndex::getOptimalSize(getDimension());
+ myKeyObjects.reserve(maxSize);
+
+ LEAVE( "DBHierIndex::DBHierIndex(" << myOId << ")" );
+ RMDBGEXIT(7, RMDebug::module_indexif, "DBHierIndex", "DBHierIndex(" << myOId << ")");
+ }
+
+DBHierIndex::DBHierIndex(r_Dimension dim, bool isNODE, bool makePersistent)
+ : HierIndexDS(),
+ maxSize(0),
+ myDomain(dim),
+ currentDbRows(-1),
+ parent(0),
+ _isNode(isNODE)
+ {
+ RMDBGENTER(7, RMDebug::module_indexif, "DBHierIndex", "DBHierIndex(" << dim << ", " << (int)isNODE << ", " << makePersistent << ") " << myOId);
+ ENTER( "DBHierIndex::DBHierIndex( dim=" << dim << ", isNODE=" << (int) isNODE << ", makePersistent=" << makePersistent << " ) - myOId=" << myOId );
+
+ objecttype = OId::MDDHIERIXOID;
+ if (makePersistent)
+ setPersistent(true);
+
+ maxSize = getOptimalSize(dim);
+ myKeyObjects.reserve(maxSize);
+ setCached(true);
+
+ LEAVE( "DBHierIndex::DBHierIndex( dim=" << dim << ", isNODE=" << (int) isNODE << ", makePersistent=" << makePersistent << " ) - myOId=" << myOId );
+ RMDBGEXIT(7, RMDebug::module_indexif, "DBHierIndex", "DBHierIndex(" << dim << ", " << (int)isNODE << ", " << makePersistent << ") " << myOId);
+ }
+
+IndexDS*
+DBHierIndex::getNewInstance() const
+ {
+ ENTER( "DBHierIndex::getNewInstance()" );
+ LEAVE( "DBHierIndex::getNewInstance() - dim=" << getDimension() << ", !isLeaf=" << (!isLeaf()) );
+ return new DBHierIndex(getDimension(), !isLeaf(), true);
+ }
+
+OId::OIdPrimitive
+DBHierIndex::getIdentifier() const
+ {
+ ENTER( "DBHierIndex::getIdentifier()" );
+ LEAVE( "DBHierIndex::getIdentifier() - myOId=" << myOId );
+ return myOId;
+ }
+
+bool
+DBHierIndex::removeObject(const KeyObject& entry)
+ {
+ RMDBGENTER(4, RMDebug::module_indexif, "DBHierIndex", "removeObject(" << entry << ") " << myOId);
+ ENTER( "DBHierIndex::removeObject() - entry=" << entry << ", myOId=" << myOId );
+
+ bool found = false;
+ unsigned int pos = 0;
+ OId oid(entry.getObject().getOId());
+ for (KeyObjectVector::iterator i = myKeyObjects.begin(); i != myKeyObjects.end(); i++)
+ {
+ RMDBGMIDDLE(9, RMDebug::module_indexif, "DBHierIndex", "at pos " << pos << " of " << myKeyObjects.size());
+ TALK( "DBHierIndex::removeObject() touching object in vector at pos " << pos << " of " << myKeyObjects.size());
+ if (oid == (*i).getObject().getOId())
+ {
+ found = true;
+ myKeyObjects.erase(i);
+ setModified();
+ break;
+ }
+ else {
+ RMDBGMIDDLE(9, RMDebug::module_indexif, "DBHierIndex", "did not match " << oid << " with " << *i);
+ }
+ }
+
+ LEAVE( "DBHierIndex::removeObject() - entry=" << entry << ", myOId=" << myOId << ", found=" << found );
+ RMDBGEXIT(4, RMDebug::module_indexif, "DBHierIndex", "removeObject(" << entry << ") " << myOId << " " << found);
+ return found;
+ }
+
+bool
+DBHierIndex::removeObject(unsigned int pos)
+ {
+ RMDBGENTER(4, RMDebug::module_indexif, "DBHierIndex", "removeObject(" << pos << ") " << myOId);
+ ENTER( "DBHierIndex::removeObject() - pos=" << pos << ", myOId=" << myOId );
+
+ bool found = false;
+ if (pos <= myKeyObjects.size())
+ {
+ found = true;
+ myKeyObjects.erase(myKeyObjects.begin() + pos);
+ setModified();
+ }
+
+ LEAVE( "DBHierIndex::removeObject() - pos=" << pos << ", myOId=" << myOId << ", found=" << found );
+ RMDBGEXIT(4, RMDebug::module_indexif, "DBHierIndex", "removeObject(" << pos << ") " << myOId << " " << found);
+ return found;
+ }
+
+
+void
+DBHierIndex::insertObject(const KeyObject& theKey, unsigned int pos)
+ {
+ RMDBGENTER(8, RMDebug::module_indexif, "DBHierIndex", "insertObject(" << theKey << ", " << pos << ") " << myOId);
+ ENTER( "DBHierIndex::insertObject() - theKey=" << theKey << ", pos=" << pos << ", myOId=" << myOId );
+
+ if (!isLeaf())
+ DBHierIndexId(theKey.getObject())->setParent(this);
+ if (myKeyObjects.size() == 0)
+ {
+ // first tile to be inserted in the index, initialize domain
+ myDomain = theKey.getDomain();
+ }
+ else
+ extendCoveredDomain(theKey.getDomain());
+ myKeyObjects.insert(myKeyObjects.begin() + pos, theKey);
+ TALK( "now have " << myKeyObjects.size() << " objects in key object vector." );
+ setModified();
+
+ LEAVE( "DBHierIndex::insertObject() - theKey=" << theKey << ", pos=" << pos << ", myOId=" << myOId << ", CoveredDomain " << getCoveredDomain() << std::endl << std::endl );
+ TALK( " CoveredDomain=" << getCoveredDomain() << std::endl << std::endl );
+ RMDBGEXIT(8, RMDebug::module_indexif, "DBHierIndex", "insertObject(" << theKey << ", " << pos << ") " << myOId << " CoveredDomain " << getCoveredDomain());
+ }
+
+void
+DBHierIndex::setObjectDomain(const r_Minterval& dom, unsigned int pos)
+ {
+ RMDBGENTER(7, RMDebug::module_indexif, "DBHierIndex", "setObjectDomain(" << dom << ", " << pos << ") " << myOId);
+ ENTER( "DBHierIndex::setObjectDomain() - dom=" << dom << ", pos=" << pos << ", myOId=" << myOId );
+
+ myKeyObjects[pos].setDomain(dom);
+ //might be unneccessary/harmfull, check later
+ extendCoveredDomain(dom);
+
+ //setModified(); done in domain extension
+ if (!isLeaf())
+ {
+ DBHierIndexId t(myKeyObjects[pos].getObject());
+ t->setAssignedDomain(dom);
+ }
+
+ LEAVE( "DBHierIndex::setObjectDomain() - dom=" << dom << ", pos=" << pos << ", myOId=" << myOId );
+ RMDBGEXIT(7, RMDebug::module_indexif, "DBHierIndex", "setObjectDomain(" << dom << ", " << pos << ") " << myOId);
+ }
+
+void
+DBHierIndex::setObject(const KeyObject& theKey, unsigned int pos)
+ {
+ RMDBGENTER(7, RMDebug::module_indexif, "DBHierIndex", "setObject(" << theKey << ", " << pos << ") " << myOId);
+ ENTER( "DBHierIndex::setObject() - theKey=" << theKey << ", pos=" << pos << ", myOId=" << myOId );
+
+ myKeyObjects[pos] = theKey;
+ setModified();
+ if (!isLeaf())
+ {
+ DBHierIndexId(theKey.getObject())->setParent(this);
+ }
+
+ LEAVE( "DBHierIndex::setObject() - theKey=" << theKey << ", pos=" << pos << ", myOId=" << myOId );
+ RMDBGEXIT(7, RMDebug::module_indexif, "DBHierIndex", "setObject(" << theKey << ", " << pos << ") " << myOId);
+ }
+
+r_Minterval
+DBHierIndex::getCoveredDomain() const
+ {
+ RMDBGONCE(7, RMDebug::module_indexif, "DBHierIndex", "getCoveredDomain() const " << myOId << " " << myDomain);
+ TALK( "DBHierIndex::getCoveredDomain( " << myOId << ") -> " << myDomain );
+ return myDomain;
+ }
+
+r_Dimension
+DBHierIndex::getDimension() const
+ {
+ RMDBGONCE(7, RMDebug::module_indexif, "DBDDObjIx", "getDimension() const " << myOId << " " << myDomain.dimension());
+ TALK( "DBHierIndex::getDimension( " << myOId << ") -> " << myDomain.dimension() );
+ return myDomain.dimension();
+ }
+
+r_Bytes
+DBHierIndex::getTotalStorageSize() const
+ {
+ RMDBGENTER(4, RMDebug::module_indexif, "DBHierIndex", "getTotalStorageSize() " << myOId);
+ ENTER( "DBHierIndex::getTotalStorageSize() - myOId=" << myOId );
+
+ r_Bytes sz = 0;
+
+ for (KeyObjectVector::const_iterator i = myKeyObjects.begin(); i != myKeyObjects.end(); i++)
+ {
+ sz = sz + ((DBObject*)ObjectBroker::getObjectByOId(i->getObject().getOId()))->getTotalStorageSize();
+ }
+
+ LEAVE( "DBHierIndex::getTotalStorageSize( " << myOId << " ) for " << myKeyObjects.size() << " objects -> sz=" << sz );
+ RMDBGEXIT(4, RMDebug::module_indexif, "DBHierIndex", "getTotalStorageSize() " << myOId << " " << sz);
+ return sz;
+ }
+
+bool
+DBHierIndex::isValid() const
+ {
+ ENTER( "DBHierIndex::isValid()" );
+
+ bool valid = true;
+ //may not be unsigned int (r_Area) because of error check
+ int area = 0;
+ if (!isLeaf())
+ {
+ area = myDomain.cell_count();
+ DBHierIndexId tempIx;
+ TALK( "inspecting " << myKeyObjects.size() << " objects in key object vector." );
+ for (KeyObjectVector::const_iterator i = myKeyObjects.begin(); i != myKeyObjects.end(); i++)
+ {
+ if (myDomain.covers((*i).getDomain()))
+ {
+ //ok
+ area = area - (*i).getDomain().cell_count();
+ }
+ else {
+ if (myDomain == (*i).getDomain())
+ {
+ //ok
+ area = area - (*i).getDomain().cell_count();
+ tempIx = DBHierIndexId((*i).getObject());
+ if (!tempIx->isValid())
+ {
+ valid = false;
+ break;
+ }
+ }
+ else {
+ RMDBGONCE(0, RMDebug::module_indexif, "DBHierIndex", "isValid() " << myOId << " key does not cover domain: myDomain " << myDomain << " key " << *i);
+ valid = false;
+ break;
+ }
+ }
+ }
+ if (valid)
+ {
+ if (area < 0)
+ {
+ RMDBGONCE(0, RMDebug::module_indexif, "DBHierIndex", "isValid() " << myOId << " there are double entries");
+ valid = false;
+ }
+ }
+ }
+ else {
+ area = myDomain.cell_count();
+ valid = true;
+ for (KeyObjectVector::const_iterator i = myKeyObjects.begin(); i != myKeyObjects.end(); i++)
+ {
+ if (myDomain.intersects_with((*i).getDomain()))
+ {
+ //ok
+ area = area - (*i).getDomain().create_intersection(myDomain).cell_count();
+ }
+ else {
+ RMDBGONCE(0, RMDebug::module_indexif, "DBHierIndex", "isValid() " << myOId << " key does not intersect domain: myDomain " << myDomain << " key " << *i);
+ valid = false;
+ break;
+ }
+ }
+ if (!valid)
+ {
+ if (area < 0)
+ {
+ RMDBGONCE(0, RMDebug::module_indexif, "DBHierIndex", "isValid() " << myOId << " there are double entries");
+ valid = false;
+ }
+ }
+ }
+
+ ENTER( "DBHierIndex::isValid() -> valid=" << valid );
+ return valid;
+ }
+
+void
+DBHierIndex::printStatus(unsigned int level, std::ostream& stream) const
+ {
+ ENTER( "DBHierIndex::printStatus() - level=" << level );
+
+ DBObjectId t;
+ char* indent = new char[level*2 +1];
+ for (unsigned int j = 0; j < level*2 ; j++)
+ indent[j] = ' ';
+ indent[level*2] = '\0';
+
+ stream << indent << "DBHierIndex ";
+ if (isRoot())
+ stream << "is Root ";
+ else
+ stream << "Parent " << parent << " ";
+ if (isLeaf())
+ stream << "Leaf ";
+ else
+ stream << "Node ";
+ DBObject::printStatus(level, stream);
+ stream << " size " << myKeyObjects.size() << " domain " << myDomain << std::endl;
+ int count = 0;
+ TALK( "inspecting " << myKeyObjects.size() << " objects in key object vector." );
+ for (KeyObjectVector::const_iterator i = myKeyObjects.begin(); i != myKeyObjects.end(); i++)
+ {
+ stream << indent << " entry #" << count << " is " << *i << std::endl;
+ if (!isLeaf())
+ {
+ t = DBObjectId((*i).getObject());
+ if (t.is_null())
+ stream << indent << " entry is null";
+ else
+ t->printStatus(level + 1, stream);
+ }
+ stream << std::endl;
+ count++;
+ }
+ delete[] indent;
+
+ LEAVE( "DBHierIndex::printStatus()" );
+ }
+
+unsigned int
+DBHierIndex::getSize() const
+ {
+ RMDBGONCE(4, RMDebug::module_indexif, "DBHierIndex", "getSize() " << myOId << " " << myKeyObjects.size());
+ TALK( "DBHierIndex::getSize() - myOId=" << myOId << ", size=" << myKeyObjects.size() );
+ return myKeyObjects.size();
+ }
+
+bool
+DBHierIndex::isUnderFull() const
+ {
+ //redistribute in srptindexlogic has to be checked first before any other return value may be assigned
+ TALK( "DBHierIndex::isUnderFull() -> false" );
+ return false;
+ }
+
+bool
+DBHierIndex::isOverFull() const
+ {
+ ENTER( "DBHierIndex::isOverFull()" );
+
+ bool retval = false;
+ if (getSize() >= maxSize)
+ retval = true;
+
+ RMDBGONCE(4, RMDebug::module_indexif, "DBHierIndex", "isOverFull() " << myOId << " maxSize " << maxSize << " size " << getSize() << " retval " << retval)
+ ENTER( "DBHierIndex::isOverFull() -> " << retval );
+ return retval;
+ }
+
+unsigned int
+DBHierIndex::getOptimalSize(r_Dimension dim)
+ {
+ ENTER( "DBHierIndex::getOptimalSize() - dim=" << dim );
+
+ unsigned int retval = 0;
+ //BLOCKSIZE
+ unsigned int blocksize = 0;
+ unsigned int useablespace = 0;
+ //dimension * (upperbound + upperfixed + lowerbound + lowerfixed) + entryid + entryoidtype
+ unsigned int oneentry = dim * (sizeof(r_Range) * 2 + sizeof(char) * 2) + sizeof(OId::OIdCounter) + sizeof(char);
+
+#ifdef BASEDB_ORACLE
+ blocksize = 2048;
+ //BLOCKSIZE - (BLOCK OVERHEAD + ROW OVERHEAD + 1 * largerow + number(15,0) + short)
+ useablespace = blocksize - (130 + 3 + 1 * 3 + 12 + 2);
+#else
+#ifdef BASEDB_DB2
+ blocksize = 4096;
+ //from the manual
+ useablespace = 3990;
+#else
+#ifdef BASEDB_INFORMIX
+ blocksize = 4096;
+ //from the manual
+ useablespace = 3990;
+#else
+#ifdef BASEDB_PGSQL
+ blocksize = 8192; // default only!!!;
+ useablespace = 7000; // no indication for any less space available, but to be sure we go a little lower -- PB 2005-jan-10
+#else
+#error "BASEDB not defined! please check for BASEDB_XXX define in Makefile.inc!"
+#endif // pgsql
+#endif // informix
+#endif // db2
+#endif // oracle
+
+ //remove mydomain size
+ useablespace = useablespace - dim * (sizeof(r_Range) * 2 + sizeof(char) * 2);
+ //minimum size is 8-lucky guess(good for 1,2,3,4 dimensions)
+ retval = std::max((unsigned int)8, useablespace / oneentry);
+ if (StorageLayout::DefaultIndexSize != 0)
+ retval = StorageLayout::DefaultIndexSize;
+
+ LEAVE( "DBHierIndex::getOptimalSize() - maxSize=" << retval );
+ RMDBGONCE(4, RMDebug::module_indexif, "DBHierIndex", "getOptimalSize(" << dim << ") maxSize " << retval)
+ return retval;
+ }
+
+unsigned int
+DBHierIndex::getOptimalSize() const
+ {
+ TALK( "DBHierIndex::getOptimalSize() -> " << maxSize );
+ return maxSize;
+ }
+
+r_Minterval
+DBHierIndex::getAssignedDomain() const
+ {
+ TALK( "DBHierIndex::getAssignedDomain() -> " << myDomain );
+ return myDomain;
+ }
+
+void
+DBHierIndex::setAssignedDomain(const r_Minterval& newDomain)
+ {
+ RMDBGENTER(7, RMDebug::module_indexif, "DBHierIndex", "setAssignedDomain(" << newDomain << ") " << myOId);
+ ENTER( "DBHierIndex::setAssignedDomain() - newDomain=" << newDomain << ", myOId=" << myOId );
+
+ myDomain = newDomain;
+ setModified();
+
+ LEAVE( "DBHierIndex::setAssignedDomain()" );
+ RMDBGEXIT(7, RMDebug::module_indexif, "DBHierIndex", "setAssignedDomain(" << newDomain << ") " << myOId);
+ }
+
+void
+DBHierIndex::extendCoveredDomain(const r_Minterval& newTilesExtents) throw (r_Edim_mismatch, r_Eno_interval)
+ {
+ RMDBGENTER(7, RMDebug::module_indexif, "DBHierIndex", "extendCoveredDomain(" << newTilesExtents << ") " << myOId);
+ ENTER( "DBHierIndex::extendCoveredDomain() - newTilesExtents=" << newTilesExtents << ", myOId=" << myOId );
+
+ myDomain.closure_with(newTilesExtents);
+ setModified();
+
+ LEAVE( "DBHierIndex::extendCoveredDomain()" );
+ RMDBGEXIT(7, RMDebug::module_indexif, "DBHierIndex", "extendCoveredDomain(" << newTilesExtents << ") " << myOId);
+ }
+
+void
+DBHierIndex::setParent(const HierIndexDS* newPa)
+ {
+ RMDBGENTER(7, RMDebug::module_indexif, "DBHierIndex", "setParent(" << OId(newPa->getIdentifier()) << ") " << myOId);
+ ENTER( "DBHierIndex::setParent() - newPa=" << newPa << ", myOId=" << myOId );
+
+ if ((OId::OIdPrimitive)parent != newPa->getIdentifier())
+ {
+ parent = newPa->getIdentifier();
+ setModified();
+ }
+
+ LEAVE( "DBHierIndex::setParent()" );
+ RMDBGEXIT(7, RMDebug::module_indexif, "DBHierIndex", "setParent(" << OId(newPa->getIdentifier()) << ") " << myOId);
+ }
+
+HierIndexDS*
+DBHierIndex::getParent() const
+ {
+ RMDBGONCE(7, RMDebug::module_indexif, "DBHierIndex", "getParent() const " << myOId << " " << parent << " " << parent);
+ ENTER( "DBHierIndex::getParent() - myOId=" << myOId << ", parent=" << parent );
+
+ DBHierIndexId t(parent);
+
+ LEAVE( "DBHierIndex::getParent() - t=" << t );
+ return (HierIndexDS*)t;
+ }
+
+bool
+DBHierIndex::isRoot() const
+ {
+ RMDBGONCE(7, RMDebug::module_indexif, "DBHierIndex", "isRoot() const " << myOId << " " << (int)(parent.getType() == OId::INVALID));
+ TALK( "DBHierIndex::isRoot() -> " << (parent.getType() == OId::INVALID) );
+ return (parent.getType() == OId::INVALID);
+ }
+
+bool
+DBHierIndex::isLeaf() const
+ {
+ RMDBGONCE(7, RMDebug::module_indexif, "DBHierIndex", "isLeaf() const " << myOId << " " << (int)(!_isNode));
+ TALK( "DBHierIndex::isLeaf() -> " << !_isNode );
+ return !_isNode;
+ }
+
+void
+DBHierIndex::setIsNode(bool isNodea)
+ {
+ RMDBGONCE(7, RMDebug::module_indexif, "DBHierIndex", "setIsNode(" << isNodea << ") " << myOId << " was " << _isNode);
+ TALK( "DBHierIndex::setIsNode() - isNodea=" << isNodea );
+ _isNode = isNodea;
+ }
+
+void
+DBHierIndex::freeDS()
+ {
+ TALK( "DBHierIndex::freeDS()" );
+ setPersistent(false);
+ }
+bool
+DBHierIndex::isSameAs(const IndexDS* other) const
+ {
+ ENTER( "DBHierIndex::isSameAs() - other=" << other );
+
+ bool result = false;
+ if (other->isPersistent())
+ if (myOId == other->getIdentifier())
+ result = true;
+
+ LEAVE( "DBHierIndex::isSameAs() -> " << result );
+ return result;
+ }
+
+
+double
+DBHierIndex::getOccupancy() const
+ {
+ cout << "DBHierIndex::getOccupancy() const NOT IMPLEMENTED" << std::endl;
+ TALK( "DBHierIndex::getOccupancy() NOT IMPLEMENTED" );
+ return 0;
+ }
+
+const KeyObject&
+DBHierIndex::getObject(unsigned int pos) const
+ {
+ RMDBGONCE(4, RMDebug::module_indexif, "DBHierIndex", "getObject(" << pos << ") " << myOId << " " << myKeyObjects[pos]);
+ TALK( "DBHierIndex::getObject() - pos=" << pos << ", myOId=" << myOId << " -> " << myKeyObjects[pos] );
+
+ return myKeyObjects[pos];
+ }
+
+void
+DBHierIndex::getObjects(KeyObjectVector& objs) const
+ {
+ RMDBGENTER(4, RMDebug::module_indexif, "DBHierIndex", "getObjects() " << myOId);
+ ENTER( "DBHierIndex::getObjects() - myOId=" << myOId );
+
+ for (KeyObjectVector::const_iterator keyIt = myKeyObjects.begin(); keyIt != myKeyObjects.end(); keyIt++)
+ {
+ objs.push_back(*keyIt);
+ }
+
+ LEAVE( "DBHierIndex::getObjects() - size=" << objs.size() );
+ RMDBGEXIT(4, RMDebug::module_indexif, "DBHierIndex", "getObjects() " << myOId << " vec.size " << objs.size());
+ }
+
+r_Minterval
+DBHierIndex::getObjectDomain(unsigned int pos) const
+ {
+ RMDBGONCE(4, RMDebug::module_indexif, "DBHierIndex", "getObjectDomain(" << pos << ") " << myOId << " " << myKeyObjects[pos]);
+ TALK( "DBHierIndex::getObjectDomain() - pos=" << pos << ", myOId=" << myOId << " -> " << myKeyObjects[pos] );
+ return myKeyObjects[pos].getDomain();
+ }
+
+unsigned int
+DBHierIndex::getHeight() const
+ {
+ TALK( "DBHierIndex::getHeight() -> " << getHeightToLeaf() );
+ return getHeightToLeaf();
+ }
+
+unsigned int
+DBHierIndex::getHeightOfTree() const
+ {
+ ENTER( "DBHierIndex::getHeightOfTree() - myOId=" << myOId );
+
+ unsigned int retval = getHeightToLeaf() + getHeightToRoot();
+
+ LEAVE( "DBHierIndex::getHeightOfTree() -> " << retval );
+ RMDBGONCE(7, RMDebug::module_indexif, "DBHierIndex", "getHeightOfTree() const " << myOId << " " << retval);
+ return retval;
+ }
+
+unsigned int
+DBHierIndex::getHeightToRoot() const
+ {
+ ENTER( "DBHierIndex::getHeightToRoot() - myOId=" << myOId );
+
+ unsigned int retval = 0;
+ if (isRoot())
+ retval = 0;
+ else {
+ DBHierIndexId t(parent);
+ const DBHierIndex* tp = (DBHierIndex*)t.ptr();
+ retval = tp->getHeightToRoot() + 1;
+ }
+
+ LEAVE( "DBHierIndex::getHeightToRoot() -> " << retval );
+ RMDBGONCE(7, RMDebug::module_indexif, "DBHierIndex", "getHeightToRoot() const " << myOId << " " << retval);
+ return retval;
+ }
+
+unsigned int
+DBHierIndex::getHeightToLeaf() const
+ {
+ ENTER( "DBHierIndex::getHeightToLeaf() - myOId=" << myOId );
+
+ unsigned int retval = 0;
+ if (isLeaf())
+ retval = 0;
+ else {
+ DBHierIndexId t(parent);
+ const DBHierIndex* tp = (DBHierIndex*)t.ptr();
+ retval = tp->getHeightToLeaf() + 1;
+ }
+
+ LEAVE( "DBHierIndex::getHeightToLeaf() -> " << retval );
+ RMDBGONCE(7, RMDebug::module_indexif, "DBHierIndex", "getHeightToLeaf() const " << myOId << " " << retval);
+ return retval;
+ }
+
+unsigned int
+DBHierIndex::getTotalLeafCount() const
+ {
+ RMDBGENTER(7, RMDebug::module_indexif, "DBHierIndex", "getTotalLeafCount() const " << myOId);
+ ENTER( "DBHierIndex::getTotalLeafCount() - myOId=" << myOId );
+
+ unsigned int retval = 0;
+ if (!isLeaf())
+ {
+ //i am not a leaf
+ if (DBHierIndexId(myKeyObjects.begin()->getObject())->isLeaf())
+ {
+ //i contain only leafs, so i return the number of entries i contain
+ retval = getSize();
+ }
+ else {
+ //i contain only nodes, so i ask my children how many leafs there are
+ for (KeyObjectVector::const_iterator keyIt = myKeyObjects.begin(); keyIt != myKeyObjects.end(); keyIt++)
+ {
+ DBHierIndexId accessedIx((*keyIt).getObject());
+ retval = retval + accessedIx->getTotalLeafCount();
+ }
+ }
+ }
+ else {
+ retval = 1;
+ }
+
+ LEAVE( "DBHierIndex::getTotalLeafCount() -> " << retval );
+ RMDBGEXIT(7, RMDebug::module_indexif, "DBHierIndex", "getTotalLeafCount() const " << myOId << " " << retval);
+ return retval;
+ }
+
+unsigned int
+DBHierIndex::getTotalNodeCount() const
+ {
+ RMDBGENTER(7, RMDebug::module_indexif, "DBHierIndex", "getTotalNodeCount() const " << myOId);
+ ENTER( "DBHierIndex::getTotalNodeCount() - myOId=" << myOId );
+
+ unsigned int retval = 0;
+ if (!isLeaf())
+ {
+ //i am not a leaf
+ if (DBHierIndexId(myKeyObjects.begin()->getObject())->isLeaf())
+ {
+ //i contain only nodes
+ //i add the nodes i contain
+ retval = getSize();
+ //i add the nodes my children contain
+ for (KeyObjectVector::const_iterator keyIt = myKeyObjects.begin(); keyIt != myKeyObjects.end(); keyIt++)
+ {
+ DBHierIndexId accessedIx((*keyIt).getObject());
+ retval = retval + accessedIx->getTotalNodeCount();
+ }
+ }
+ }
+ //else : a leaf does not contain nodes
+
+ LEAVE( "DBHierIndex::getTotalNodeCount() -> " << retval );
+ RMDBGEXIT(7, RMDebug::module_indexif, "DBHierIndex", "getTotalNodeCount() const " << myOId << " " << retval);
+ return retval;
+ }
+
+unsigned int
+DBHierIndex::getTotalEntryCount() const
+ {
+ RMDBGENTER(7, RMDebug::module_indexif, "DBHierIndex", "getTotoalEntryCount() const " << myOId);
+ ENTER( "DBHierIndex::getTotalEntryCount() - myOId=" << myOId );
+
+ unsigned int retval = 0;
+ if (isLeaf())
+ {
+ //i contain only entries
+ //i return the number of entries i contain
+ retval = getSize();
+ }
+ else {
+ //i contain only nodes, no entries
+ //i ask my children how many entries they contain
+ for (KeyObjectVector::const_iterator keyIt = myKeyObjects.begin(); keyIt != myKeyObjects.end(); keyIt++)
+ {
+ DBHierIndexId accessedIx((*keyIt).getObject());
+ retval = retval + accessedIx->getTotalEntryCount();
+ }
+ }
+
+ LEAVE( "DBHierIndex::getTotalEntryCount() -> " << retval );
+ RMDBGEXIT(7, RMDebug::module_indexif, "DBHierIndex", "getTotoalEntryCount() const " << myOId << " " << retval);
+ return retval;
+ }
+
+void
+DBHierIndex::destroy()
+ {
+ TALK( "DBObject::destroy()" );
+ DBObject::destroy();
+ }
+
+DBHierIndex::~DBHierIndex()
+ {
+ RMDBGENTER(7, RMDebug::module_indexif, "DBHierIndex", "~DBHierIndex() " << myOId);
+ ENTER( "DBHierIndex::~DBHierIndex() - myOId=" << myOId );
+
+ validate();
+ currentDbRows = 0;
+ parent = OId(0);
+ myKeyObjects.clear();
+ myDomain = (InlineMinterval) NULL;
+ maxSize = 0;
+ _isNode = true;
+
+ LEAVE( "DBHierIndex::~DBHierIndex()" );
+ RMDBGEXIT(7, RMDebug::module_indexif, "DBHierIndex", "~DBHierIndex() " << myOId);
+ }
+
+/*
+Encoding:
+name :
+ type_oid.raw
+value :
+ common
+ 1 byte version
+ 1 byte endianness
+ 2 bytes type
+ 4 bytes oid
+ 1 byte flags
+ 2 byte reserved
+ special
+ 4 bytes size
+ 2 bytes dimension
+ 8 bytes parent oid
+ 1 byte subtype
+ x bytes database layout
+*/
+
+BinaryRepresentation
+DBHierIndex::getBinaryRepresentation() const throw (r_Error)
+ {
+ ENTER( "DBHierIndex::getBinaryRepresentation()" );
+
+ BinaryRepresentation brp;
+ brp.binaryName = getBinaryName();
+ brp.binaryData = NULL;
+ brp.binaryLength = 0;
+ short dimension2 = myDomain.dimension();
+ size_t size2 = myKeyObjects.size();
+ short subtype = _isNode;
+ double parentid2 = 0;
+
+ if (parent.getType() == OId::INVALID)
+ parentid2 = 0;
+ else
+ parentid2 = parent;
+
+ //INSERTINTO
+
+ //number of bytes for bounds for "size" entries and mydomain
+ r_Bytes boundssize = sizeof(r_Range) * (size2 + 1) * dimension2;
+ //number of bytes for fixes for "size" entries and mydomain
+ r_Bytes fixessize = sizeof(char) * (size2 + 1) * dimension2;
+ //number of bytes for ids of entries
+ r_Bytes idssize = sizeof(OId::OIdCounter) * size2;
+ //number of bytes for types of entries
+ r_Bytes typessize = sizeof(char) * size2;
+ //number of bytes for the dynamic data
+ r_Bytes completesize = boundssize * 2 + fixessize * 2 + idssize + typessize;
+
+ char* completebuffer = new char[completesize];
+ r_Range* upperboundsbuf = new r_Range[boundssize];
+ r_Range* lowerboundsbuf = new r_Range[boundssize];
+ char* upperfixedbuf = new char[fixessize];
+ char* lowerfixedbuf = new char[fixessize];
+ OId::OIdCounter* entryidsbuf = new OId::OIdCounter[idssize];
+ char* entrytypesbuf = new char[typessize];
+
+ RMDBGMIDDLE(8, RMDebug::module_indexif, "DBHierIndex", "complete " << completesize << " bounds " << boundssize << " fixes " << fixessize << " ids " << idssize << " types " << typessize);
+
+ //counter which keeps track of the bytes that have been written to the db
+ r_Bytes byteswritten = 0;
+ //counter which keeps track of the bytes that have to be written to the db
+ r_Bytes bytestowrite = 0;
+
+ myDomain.insertInDb(&(lowerboundsbuf[0]), &(upperboundsbuf[0]), &(lowerfixedbuf[0]), &(upperfixedbuf[0]));
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBHierIndex", "domain " << myDomain << " stored as " << InlineMinterval(dimension2, &(lowerboundsbuf[0]), &(upperboundsbuf[0]), &(lowerfixedbuf[0]), &(upperfixedbuf[0])));
+ //populate the buffers with data
+ KeyObjectVector::const_iterator it = myKeyObjects.begin();
+ InlineMinterval indom;
+ for (unsigned int i = 0; i < size2; i++, it++)
+ {
+ indom = (*it).getDomain();
+ indom.insertInDb(&(lowerboundsbuf[(i+1)*dimension2]), &(upperboundsbuf[(i+1)*dimension2]), &(lowerfixedbuf[(i+1)*dimension2]), &(upperfixedbuf[(i+1)*dimension2]));
+ entryidsbuf[i] = (*it).getObject().getOId().getCounter();
+ entrytypesbuf[i] = (char)(*it).getObject().getOId().getType();
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBHierIndex", "entry " << entryidsbuf[i] << " " << (OId::OIdType)entrytypesbuf[i] << " at " << InlineMinterval(dimension2, &(lowerboundsbuf[(i+1)*dimension2]), &(upperboundsbuf[(i+1)*dimension2]), &(lowerfixedbuf[(i+1)*dimension2]), &(upperfixedbuf[(i+1)*dimension2])));
+ }
+
+ //write the buffers in the complete buffer
+ //this indirection is neccessary because of memory alignement of longs...
+ memcpy(completebuffer, lowerboundsbuf, boundssize);
+ delete [] lowerboundsbuf;
+ memcpy(&completebuffer[boundssize], upperboundsbuf, boundssize);
+ delete [] upperboundsbuf;
+ memcpy(&completebuffer[boundssize * 2], lowerfixedbuf, fixessize);
+ delete [] lowerfixedbuf;
+ memcpy(&completebuffer[boundssize * 2 + fixessize], upperfixedbuf, fixessize);
+ delete [] upperfixedbuf;
+ memcpy(&completebuffer[boundssize * 2 + fixessize * 2], entryidsbuf, idssize);
+ delete [] entryidsbuf;
+ memcpy(&completebuffer[boundssize * 2 + fixessize * 2 + idssize], entrytypesbuf, typessize);
+ delete [] entrytypesbuf;
+
+/*
+ 5 bytes tag
+ 1 byte version
+ 1 byte endianness
+ 8 bytes oid
+*/
+ //version + endianness + oid + size + dimension + parentoid + subtype
+ brp.binaryLength = 7 + sizeof(double) + sizeof(int) + sizeof(short) + sizeof(double) + sizeof(char) + completesize;
+ brp.binaryData = new char[brp.binaryLength];
+ memcpy(brp.binaryData, BinaryRepresentation::fileTag, 5);
+ memset(&brp.binaryData[5], 1, 1);
+ if (r_Endian::get_endianness() == r_Endian::r_Endian_Little)
+ {
+ memset(&brp.binaryData[6], 1, 1);
+ }
+ else {
+ memset(&brp.binaryData[6], 0, 1);
+ }
+ double tempd = myOId;
+ memcpy(&brp.binaryData[7], &tempd, sizeof(double));
+/*
+ special
+ 4 bytes size
+ 2 bytes dimension
+ 8 bytes parent oid
+ 1 byte subtype
+ x bytes database layout
+*/
+ int tempi = size2;
+ memcpy(&brp.binaryData[7 + sizeof(double)], &tempi, sizeof(int));
+ short temps = dimension2;
+ memcpy(&brp.binaryData[7 + sizeof(double) + sizeof(int)], &temps, sizeof(short));
+ memcpy(&brp.binaryData[7 + sizeof(double) + sizeof(int) + sizeof(short)], &parentid2, sizeof(double));
+ char tempc = subtype;
+ memcpy(&brp.binaryData[7 + sizeof(double) + sizeof(int) + sizeof(short) + sizeof(double)], &tempc, sizeof(char));
+ memcpy(&brp.binaryData[7 + sizeof(double) + sizeof(int) + sizeof(short) + sizeof(double) + sizeof(char)], completebuffer, completesize);
+
+ delete [] completebuffer;
+
+ LEAVE( "DBHierIndex::getBinaryRepresentation()" );
+ return brp;
+ }
+
+void
+DBHierIndex::setBinaryRepresentation(const BinaryRepresentation& brp) throw (r_Error)
+ {
+ ENTER( "DBHierIndex::setBinaryRepresentation()" );
+
+ if (memcmp(brp.binaryData, BinaryRepresentation::fileTag, 5) != 0)
+ {
+ RMInit::logOut << "DBHierIndex::setBinaryRepresentation(brp:" << brp.binaryName << ") not a correct data set " << brp.binaryData << endl;
+ throw r_Error();
+ }
+ if (brp.binaryData[5] != 1)
+ {
+ RMInit::logOut << "DBHierIndex::setBinaryRepresentation(brp:" << brp.binaryName << ") not unknown export version " << (int)brp.binaryData[5] << endl;
+ throw r_Error();
+ }
+ if (brp.binaryData[6] != (r_Endian::get_endianness() == r_Endian::r_Endian_Little))
+ {
+ RMInit::logOut << "DBHierIndex::setBinaryRepresentation(brp:" << brp.binaryName << ") endianess conversion not supported" << endl;
+ throw r_Error();
+ }
+ size_t size1;
+ short dimension1;
+ double parentid1;
+ int tempi;
+ short temps;
+ char tempc;
+ double tempd;
+
+ memcpy((char*)&tempd, &brp.binaryData[7], sizeof(double));
+ myOId = tempd;
+ char* temp = getBinaryName();
+ if (strcmp(temp, brp.binaryName) != 0)
+ {
+ RMInit::logOut << "DBHierIndex::setBinaryRepresentation(brp:" << brp.binaryName << ") my name should be " << temp << endl;
+ delete [] temp;
+ throw r_Error();
+ }
+ delete [] temp;
+ temp = NULL;
+ memcpy(&tempi, &brp.binaryData[7 + sizeof(double)], sizeof(int));
+ size1 = tempi;
+ memcpy(&temps, &brp.binaryData[7 + sizeof(double) + sizeof(int)], sizeof(short));
+ dimension1 = temps;
+ memcpy(&parentid1, &brp.binaryData[7 + sizeof(double) + sizeof(int) + sizeof(short)], sizeof(double));
+ memcpy(&tempc, &brp.binaryData[7 + sizeof(double) + sizeof(int) + sizeof(short) + sizeof(double)], sizeof(char));
+ _isNode = tempc;
+
+ if (parentid1)
+ parent = OId(parentid1);
+ else
+ parent = OId(0, OId::INVALID);
+
+ //number of bytes for bounds for "size" entries and mydomain
+ r_Bytes boundssize = sizeof(r_Range) * (size1 + 1) * dimension1;
+ //number of bytes for fixes for "size" entries and mydomain
+ r_Bytes fixessize = sizeof(char) * (size1 + 1) * dimension1;
+ //number of bytes for ids of entries
+ r_Bytes idssize = sizeof(OId::OIdCounter) * size1;
+ //number of bytes for types of entries
+ r_Bytes typessize = sizeof(char) * size1;
+ //number of bytes for the dynamic data
+ r_Bytes completesize = boundssize * 2 + fixessize * 2 + idssize + typessize;
+
+ RMDBGMIDDLE(8, RMDebug::module_indexif, "DBHierIndex", "size " << size1 << " dimension " << dimension1 << " fixes " << fixessize << " ids " << idssize << " types " << typessize);
+ TALK( "DBHierIndex::setBinaryRepresentation(): size=" << size1 << ", dimension=" << dimension1 << ", fixes=" << fixessize << ", ids=" << idssize << ", types=" << typessize );
+
+ char* completebuffer = new char[completesize];
+ r_Range* upperboundsbuf = new r_Range[boundssize];
+ r_Range* lowerboundsbuf = new r_Range[boundssize];
+ char* upperfixedbuf = new char[fixessize];
+ char* lowerfixedbuf = new char[fixessize];
+ OId::OIdCounter* entryidsbuf = new OId::OIdCounter[idssize];
+ char* entrytypesbuf = new char[typessize];
+ memcpy(completebuffer, &brp.binaryData[7 + sizeof(double) + sizeof(int) + sizeof(short) + sizeof(double) + sizeof(char)], completesize);
+
+ //all dynamic data is in completebuffer
+ //put that stuff in the correct buffers
+ memcpy(lowerboundsbuf, completebuffer, boundssize);
+ memcpy(upperboundsbuf, &completebuffer[boundssize], boundssize);
+ memcpy(lowerfixedbuf, &completebuffer[boundssize * 2], fixessize);
+ memcpy(upperfixedbuf, &completebuffer[boundssize * 2 + fixessize], fixessize);
+ memcpy(entryidsbuf, &completebuffer[boundssize * 2 + fixessize * 2], idssize);
+ memcpy(entrytypesbuf, &completebuffer[boundssize * 2 + fixessize * 2 + idssize], typessize);
+ //all dynamic data is in its buffer
+ delete [] completebuffer;
+ completebuffer = NULL;
+ int i = 0;
+ //rebuild the attributes from the buffers
+ myDomain = InlineMinterval(dimension1, &(lowerboundsbuf[0]), &(upperboundsbuf[0]), &(lowerfixedbuf[0]), &(upperfixedbuf[i*dimension1]));
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBHierIndex", "domain " << myDomain << " constructed from " << InlineMinterval(dimension1, &(lowerboundsbuf[0]), &(upperboundsbuf[0]), &(lowerfixedbuf[0]), &(upperfixedbuf[0])));
+ KeyObject theKey = KeyObject(DBObjectId(), myDomain);
+ for (i = 0; i < size1; i++)
+ {
+ theKey.setDomain(InlineMinterval(dimension1, &(lowerboundsbuf[(i+1)*dimension1]), &(upperboundsbuf[(i+1)*dimension1]), &(lowerfixedbuf[(i+1)*dimension1]), &(upperfixedbuf[(i+1)*dimension1])));
+ theKey.setObject(OId(entryidsbuf[i], (OId::OIdType)entrytypesbuf[i]));
+ myKeyObjects.push_back(theKey);
+ RMDBGMIDDLE(5, RMDebug::module_indexif, "DBHierIndex", "entry " << entryidsbuf[i] << " " << (OId::OIdType)entrytypesbuf[i] << " at " << InlineMinterval(dimension1, &(lowerboundsbuf[(i+1)*dimension1]), &(upperboundsbuf[(i+1)*dimension1]), &(lowerfixedbuf[(i+1)*dimension1]), &(upperfixedbuf[(i+1)*dimension1])));
+ }
+
+ delete [] upperboundsbuf;
+ delete [] lowerboundsbuf;
+ delete [] upperfixedbuf;
+ delete [] lowerfixedbuf;
+ delete [] entryidsbuf;
+ delete [] entrytypesbuf;
+ _isInDatabase = true;
+ _isPersistent = true;
+ _isModified = true;
+ currentDbRows = 1;
+
+ LEAVE( "DBHierIndex::setBinaryRepresentation()" );
+ }
+
diff --git a/relindexif/indexid.hh b/relindexif/indexid.hh
new file mode 100644
index 0000000..be9b0b5
--- /dev/null
+++ b/relindexif/indexid.hh
@@ -0,0 +1,37 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#ifndef _INDEXID_HH_
+#define _INDEXID_HH_
+
+class DBHierIndex;
+class DBTCIndex;
+//class DBIndexDS;
+class DBRCIndexDS;
+
+template <class T> class DBRef;
+
+typedef DBRef<DBHierIndex> DBHierIndexId;
+typedef DBRef<DBTCIndex> DBTCIndexId;
+typedef DBRef<DBRCIndexDS> DBRCIndexDSId;
+//typedef DBRef<DBIndexDS> DBIndexDSId;
+#endif
diff --git a/relindexif/test/Makefile b/relindexif/test/Makefile
new file mode 100644
index 0000000..b21e636
--- /dev/null
+++ b/relindexif/test/Makefile
@@ -0,0 +1,97 @@
+# -*-Makefile-*-
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>. # Top Level makefile. This points to the various modules that have to be build
+# and/or deployed
+#
+
+# MAKEFILE FOR:
+# test programs of module relindexif
+#
+#
+# COMMENTS:
+# List environment dependencies, known bugs, specialities etc.
+#
+########################################################################
+
+# standard include with general options
+include $(RMANBASE)/Makefile.inc
+
+CPPSOURCES = testindex.c
+
+# Not needed if BASEDB flag correctly set
+INDEXIF = $(RELINDEXIF)
+
+# all test programs
+ALLTESTS = testindex
+
+# Needed RasDaMan libraries for linking. To be copmpleted.
+#NEEDEDLIBS = $(CACHETAMGR) $(QLPARSER) $(INDEXMGR) $(RELADMINIF) $(RELMDDIF) $(RELBLOBIF) $(RELINDEXIF) $(CACHETAMGR) $(RELCATALOGIF) $(RASLIB) $(RELADMINIF) $(RELMDDIF)
+NEEDEDLIBS = $(RASLIB) $(CLIENTCOMM)
+
+MISCCLEAN := client.bm client.dbg client.log ir.out core
+OBJS := testindex.o miteratest.o
+# some additional flags for compiling and linking
+
+
+############################## Targets #################################
+
+# make all tests
+.PHONY: test
+test: $(ALLTESTS)
+
+# delete object and test programs
+.PHONY: clean
+clean:
+ -rm $(ALLTESTS)
+ -rm *.c
+ -rm *.o
+
+# deletes all non modified, but checked out files
+.PHONY: rcsclean
+rcsclean:
+ -rcsclean
+
+########################### Dependencies ###############################
+
+
+# make all tests
+.PHONY: test
+test: $(ALLTESTS)
+
+# See reladminif/test/Makefile for an example of how to add
+# here test files.
+
+testindex : testindex.o
+testindex.o : testindex.c
+testindex.c : testindex.pc
+
+miteratest : miteratest.o
+ $(PURIFY) $(CXX) $(LDFLAGS) -o miteratest miteratest.o $(RASLIB) ../../mymalloc/mymalloc_cln.o
+miteratest.o : miteratest.cc
+ $(CXX) -c $(CPPFLAGS) $(CXXFLAGS) $<
+
+computeindex : computedindex.o
+ $(PURIFY) $(CXX) $(LDFLAGS) -o $@ wurzelprungt
+computeindex.o : computedindex.cc
+ $(CXX) -c $(CPPFLAGS) -mt $(CXXFLAGS) $< asdlfkajsd
+
+
diff --git a/relindexif/test/computedindex.cc b/relindexif/test/computedindex.cc
new file mode 100644
index 0000000..0a63254
--- /dev/null
+++ b/relindexif/test/computedindex.cc
@@ -0,0 +1,109 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include <iostream>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "raslib/rmdebug.hh"
+#include "raslib/rminit.hh"
+#include "raslib/minterval.hh"
+
+RMINITGLOBALS('C')
+
+/*
+ You need to know the defined domain:
+ check if the tile config fits the defined domain
+ check if the requested/inserted tile fits into the defined domain
+ You need to know the tile config:
+ check if the inserted tile has the proper domain
+ You need to know the normalized domain:
+ it is translated to the origin
+ its extent is divided by the extent of the tile config
+ You request a point in the index:
+ the point is translated to the normalized domain
+ the point is normalized (divided by the tile config extent)
+ you get the cell offset of this point from the normalized domain
+ you add the base counter to the cell offset
+ You request a domain in the index
+ the domain is translated to the normalized domain
+ the domain is normalized (divided by the tile config extent)
+ for each point in the resulting domain you do a point query
+*/
+
+r_Minterval
+createNormalizedDomain(const r_Point& mddDomainExtent, const r_Point& tileConfigExtent)
+ {
+ r_Dimension theDim = mddDomainExtent.dimension();
+ r_Minterval normalizedDomain(theDim);
+ r_Range normalized = 0;
+
+ for (r_Dimension dim = 0; dim < theDim; dim++)
+ {
+ normalized = (r_Range)(mddDomainExtent[dim]/tileConfigExtent[dim]) - 1;
+ cout << "mdd domain extent [" << dim << "] " << mddDomainExtent[dim] << endl;
+ cout << "tile config extent [" << dim << "] " << tileConfigExtent[dim] << endl;
+ cout << "division " << mddDomainExtent[dim]/tileConfigExtent[dim] << endl;
+ if ((normalized + 1)* tileConfigExtent[dim] != mddDomainExtent[dim])
+ {
+ cout << "got you" << endl;
+ }
+ normalizedDomain[dim] = r_Sinterval(0, normalized);
+ }
+ return normalizedDomain;
+ }
+
+r_Point
+createNormalizedPoint(const r_Point& toNormalize, const r_Point& tileConfigExtent, const r_Point& mddDomainOrigin)
+ {
+ r_Dimension theDim = mddDomainOrigin.dimension();
+ r_Point normalizedPoint(theDim);
+
+ for (r_Dimension dim = 0; dim < theDim; dim++)
+ {
+ normalizedPoint[dim] = (r_Range)((toNormalize[dim] - mddDomainOrigin[dim])/tileConfigExtent[dim]);
+ }
+ return normalizedPoint;
+ }
+
+void
+main(unsigned int argc, const char** argv)
+ {
+ unsigned int baseCounter = 0;
+ unsigned int entryType = 0;
+ r_Area index = 0;
+
+ r_Minterval tileConfig("[0:1,0:2]");
+
+ r_Minterval mddDomain("[10:21,0:11]");
+
+ r_Point whereToSearch("[11,9]");
+
+ r_Minterval normalizedDomain = createNormalizedDomain(mddDomain.get_extent(), tileConfig.get_extent());
+ cout << "normalized domain " << normalizedDomain << endl;
+
+ r_Point normalizedSearch = createNormalizedPoint(whereToSearch, tileConfig.get_extent(), mddDomain.get_origin());
+ cout << "normalized search " << normalizedSearch << endl;
+ cout << "index of search point " << normalizedDomain.cell_offset(normalizedSearch) << endl;
+
+ }
+
diff --git a/relindexif/test/exportindex.cc b/relindexif/test/exportindex.cc
new file mode 100644
index 0000000..1e4e45b
--- /dev/null
+++ b/relindexif/test/exportindex.cc
@@ -0,0 +1,234 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*
+get mddoid, iterate domain, dataformat
+
+select mdd
+get domain
+ {
+ begin ta
+ iterate over domain
+ retrieve tiles
+ alter tiles
+ commit ta
+ }
+*/
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#include "server/template_inst.hh"
+#endif
+
+#include "reladminif/adminif.hh"
+#include "reladminif/databaseif.hh"
+#include "reladminif/transactionif.hh"
+#include "reladminif/oidif.hh"
+#include "cmlparser.hh"
+#include "relindexif/indexid.hh"
+
+#define ALLDONE 0
+#define ERRORPARSINGCOMMANDLINE 1
+#define DOMAINMISSING 2
+#define OIDMISSING 3
+#define OIDINVALID 4
+#define DOMAINMISMATCH 5
+#define FAILED 6
+#define DOMAININVALID 7
+#define UNKNOWNDATAFORMAT 8
+
+char globalConnectId[256];
+
+RMINITGLOBALS('S')
+
+r_Minterval domain;
+OId oid;
+
+int
+main(int argc, char** argv)
+ {
+ RMInit::logOut.rdbuf(cout.rdbuf());
+ RMInit::dbgOut.rdbuf(cout.rdbuf());
+ int retval = 0;
+ bool import = false;
+ const char* fileName = NULL;
+ CommandLineParser &cmlInter = CommandLineParser::getInstance();
+ CommandLineParameter &clp_help = cmlInter.addFlagParameter('h', "help", "show command line switches");
+ CommandLineParameter &clp_import = cmlInter.addStringParameter('i', "import", "import data");
+
+ CommandLineParameter &clp_connect = cmlInter.addStringParameter(CommandLineParser::noShortName, "connect", "database connect string", "/");
+ CommandLineParameter &clp_oid = cmlInter.addStringParameter(CommandLineParser::noShortName, "oid", "the oid of the mdd to operate on");
+ try {
+ cmlInter.processCommandLine(argc, argv);
+ }
+ catch(CmlException& err)
+ {
+ cmlInter.printHelp();
+ cout << "Error parsing command line:" << endl;
+ cout << err.what() << endl;
+ return ERRORPARSINGCOMMANDLINE;
+ }
+ if (cmlInter.isPresent('h'))
+ {
+ cmlInter.printHelp();
+ return ALLDONE;
+ }
+ if (cmlInter.isPresent("oid"))
+ {
+ oid = OId(atol(cmlInter.getValueAsString("oid")));
+ if (oid.getType() != OId::MDDHIERIXOID)
+ {
+ cout << "oid is not a mdd oid" << endl;
+ return OIDINVALID;
+ }
+ }
+ else {
+ if (cmlInter.isPresent('i'))
+ {
+ import = true;
+ fileName = cmlInter.getValueAsString('i');
+ }
+ else {
+ cout << "oid is missing" << endl;
+ return OIDMISSING;
+ }
+ }
+ strcpy((char*)globalConnectId, cmlInter.getValueAsString("connect"));
+ cout << "connect " << globalConnectId << endl;
+ cout << "set up done" << endl;
+ AdminIf::instance();
+ DatabaseIf d;
+ TransactionIf t;
+ if (import)
+ {
+ std::ifstream i;
+ i.open(fileName);
+ if (i.is_open())
+ {
+ i.seekg(0, std::ios::end);
+ std::streampos end = i.tellg();
+ size_t length = end;
+ BinaryRepresentation brp;
+ brp.binaryLength = length;
+ brp.binaryName = new char[strlen(fileName) + 1];
+ memcpy(brp.binaryName, fileName, strlen(fileName) + 1);
+ brp.binaryData = new char[length];
+ i.seekg(0, std::ios::beg);
+ i.read(brp.binaryData, end);
+ i.close();
+ DBHierIndex* p = new DBHierIndex(0, false, false);
+ p->setBinaryRepresentation(brp);
+ delete [] brp.binaryData;
+ brp.binaryData = NULL;
+ delete [] brp.binaryName;
+ brp.binaryName = NULL;
+ p->printStatus();
+ try {
+ d.open("RASBASE");
+ t.begin(&d, false);
+ ObjectBroker::registerDBObject(p);
+ t.commit();
+ d.close();
+ }
+ catch (const r_Error& e)
+ {
+ cout << "Caught exception " << e.get_errorno() << " " << e.what() << endl;
+ try {
+ t.abort();
+ }
+ catch (const r_Error& ee)
+ {
+ cout << "Caugh exception while aborting " << ee.get_errorno() << " " << ee.what() << endl;
+ try {
+ t.abort();
+ }
+ catch (const r_Error& eee)
+ {
+ cout << "Caugh exception while 2nd aborting " << eee.get_errorno() << " " << eee.what() << endl;
+ }
+ }
+ try {
+ d.close();
+ }
+ catch (const r_Error& eeee)
+ {
+ cout << "Caugh exception while closing " << eeee.get_errorno() << " " << eeee.what() << endl;
+ }
+ return FAILED;
+ }
+ }
+ else {
+ cout << "Unable to open file " << fileName << endl;
+ }
+ }
+ else {
+ try {
+ d.open("RASBASE");
+ t.begin(&d, true);
+ DBHierIndexId index(oid);
+ BinaryRepresentation bin = index->getBinaryRepresentation();
+ index->printStatus();
+ std::ofstream o;
+ o.open(bin.binaryName);
+ if (o.is_open())
+ {
+ o.write(bin.binaryData, bin.binaryLength);
+ o.flush();
+ o.close();
+ }
+ else {
+ cout << "Unable to open file " << bin.binaryName << endl;
+ }
+ delete [] bin.binaryName;
+ delete [] bin.binaryData;
+ t.commit();
+ d.close();
+ }
+ catch (const r_Error& e)
+ {
+ cout << "Caught exception " << e.get_errorno() << " " << e.what() << endl;
+ try {
+ t.abort();
+ }
+ catch (const r_Error& ee)
+ {
+ cout << "Caugh exception while aborting " << ee.get_errorno() << " " << ee.what() << endl;
+ try {
+ t.abort();
+ }
+ catch (const r_Error& eee)
+ {
+ cout << "Caugh exception while 2nd aborting " << eee.get_errorno() << " " << eee.what() << endl;
+ }
+ }
+ try {
+ d.close();
+ }
+ catch (const r_Error& eeee)
+ {
+ cout << "Caugh exception while closing " << eeee.get_errorno() << " " << eeee.what() << endl;
+ }
+ return FAILED;
+ }
+ }
+ return retval;
+ }
diff --git a/relindexif/test/miteratest.cc b/relindexif/test/miteratest.cc
new file mode 100644
index 0000000..f76f461
--- /dev/null
+++ b/relindexif/test/miteratest.cc
@@ -0,0 +1,53 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include <iostream>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "raslib/rmdebug.hh"
+#include "raslib/rminit.hh"
+#include "raslib/minterval.hh"
+#include "raslib/mitera.hh"
+
+RMINITGLOBALS('C')
+
+
+void
+main(unsigned int argc, const char** argv)
+ {
+ r_Minterval indexDomain("[0:99,0:99]");
+ cout << "index " << indexDomain << endl;
+ r_Minterval iterationDomain("[0:0,0:0]");
+ cout << "iterd " << iterationDomain << endl;
+ r_Minterval iterationResult(2);
+ //r_MiterArea iter(&indexDomain, &iterationDomain);
+ r_MiterArea iter(&iterationDomain, &indexDomain);
+ unsigned int i = 0;
+ while (!iter.isDone())
+ {
+ i++;
+ cout << iter.nextArea() << endl;
+ }
+ cout << " i is " << i << endl;
+ }
+
diff --git a/relindexif/test/testindex.pc b/relindexif/test/testindex.pc
new file mode 100644
index 0000000..df867aa
--- /dev/null
+++ b/relindexif/test/testindex.pc
@@ -0,0 +1,262 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include "mymalloc/mymalloc.h"
+#include <iostream>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "adminif.hh"
+#include "transactionif.hh"
+#include "databaseif.hh"
+#include "raslib/rmdebug.hh"
+#include "indexmgr/mddstorage.hh"
+#include "raslib/mddtypes.hh"
+#include "oidif.hh"
+#include "inlineminterval.hh"
+#include "externs.h"
+
+
+
+RMINITGLOBALS('C')
+
+unsigned int size = 0;
+r_Dimension dimension = 0;
+MDDStorage::IndexType myType = 0;
+int _isNode = 0;
+OId myOId = (double)0;
+OId parent = (double)0;
+
+void
+readFromDb()
+ {
+ RMDBGOUT(8, "(relindexif)" << "\tDBHierIndex::readFromDb() " << myOId);
+ EXEC SQL BEGIN DECLARE SECTION;
+ double id1;
+ double parentid1;
+ short indextype1;
+ long dimension1;
+ long size1;
+ short indexsubtype1;
+ short lowerfind;
+ struct {
+ short length;
+ char data[3990];
+ } dyndata1;
+ short dyndataind1;
+ EXEC SQL END DECLARE SECTION;
+
+ id1 = myOId;
+
+ EXEC SQL SELECT
+ IndexType,
+ NumEntries,
+ Dimension,
+ ParentOId,
+ IndexSubType
+ INTO
+ :indextype1,
+ :size1,
+ :dimension1,
+ :parentid1,
+ :indexsubtype1
+ FROM
+ RAS_HIERIX
+ WHERE
+ MDDObjIxOId = :id1;
+ if (SQLCODE != 0)
+ {
+ check("DBHierIndex::readFromDb() RAS_HIERIX\0");
+ if (SQLCODE == 100)
+ throw r_Error(r_Error::r_Error_ObjectUnknown);
+ else
+ throw r_Error(r_Error::r_Error_BaseDBMSFailed);
+ }
+
+ switch (indextype1)
+ {
+ case 0:
+ myType = MDDStorage::AutoIx;
+ break;
+ case 1:
+ myType = MDDStorage::DirTilesIx;
+ break;
+ case 2:
+ myType = MDDStorage::RegDirIx;
+ break;
+ case 3:
+ myType = MDDStorage::RPlusTreeNode;
+ break;
+ case 4:
+ myType = MDDStorage::RegRPlusTreeNode;
+ break;
+ default:
+ RMDBGOUT(0, "DBHierIndex::readFromDb() UNKNOWN INDEXTYPE " << indextype1 << "\t " << myOId << " " << myOId.getType());
+ break;
+ }
+ cout << "myType\t\t" << myType << endl;
+
+ size = size1;
+
+ cout << "size\t\t" << size << endl;
+
+ _isNode = indexsubtype1;
+
+ cout << "node\t\t" << _isNode << endl;
+
+ dimension = dimension1;
+
+ cout << "dimension\t\t" << dimension << endl;
+
+ if (parentid1)
+ parent = OId(parentid1);
+ else
+ parent = OId(0, OId::INVALID);
+
+ cout << "parent\t\t" << parent << " " << parent.getIdAsLong() << " " << parent.getType() << endl;
+
+ //number of bytes for bounds for "size" entries and mydomain
+ unsigned long boundssize = sizeof(r_Range) * (size + 1) * dimension;
+ //number of bytes for fixes for "size" entries and mydomain
+ unsigned long fixessize = sizeof(char) * (size + 1) * dimension;
+ //number of bytes for ids of entries
+ unsigned long idssize = sizeof(OId::Id) * size;
+ //number of bytes for types of entries
+ unsigned long typessize = sizeof(char) * size;
+ //number of bytes for the dynamic data
+ unsigned long completesize = boundssize * 2 + fixessize * 2 + idssize + typessize;
+
+ char* completebuffer = (char*)mymalloc(completesize);
+ r_Range* upperboundsbuf = (r_Range*)mymalloc(boundssize);
+ r_Range* lowerboundsbuf = (r_Range*)mymalloc(boundssize);
+ char* upperfixedbuf = (char*)mymalloc(fixessize);
+ char* lowerfixedbuf = (char*)mymalloc(fixessize);
+ OId::Id* entryidsbuf = (OId::Id*)mymalloc(idssize);
+ char* entrytypesbuf = (char*)mymalloc(typessize);
+
+ RMDBGOUT(8, "(relindexif)" << "\t\tcomplete " << completesize << " bounds " << boundssize << " fixes " << fixessize << " ids " << idssize << " types " << typessize);
+ //counter which keeps track of the bytes that have been read from the db
+ unsigned long bytesdone = 0;
+ //counter which keeps track of the bytes that have to be read from the db
+ unsigned long bytestogo = 0;
+
+ int i = 0;
+ currentDbRows = 0;
+
+ EXEC SQL DECLARE C CURSOR FOR
+ SELECT
+ DynData
+ FROM
+ RAS_HIERIXDYN
+ WHERE
+ MDDObjIxOId = :id1
+ ORDER BY
+ Count;
+
+ EXEC SQL OPEN C;
+
+ do {
+ EXEC SQL FETCH C INTO :dyndata1 :dyndataind1;
+ if (SQLCODE != 0)
+ {
+ if (SQLCODE != 100)
+ {
+ check("DBHierIndex::readFromDb() FETCH\0");
+ RMDBGOUT(7, "(relindexif)" << "\t\tSQLCODE " << SQLCODE);
+ free(upperboundsbuf);
+ free(lowerboundsbuf);
+ free(upperfixedbuf);
+ free(lowerfixedbuf);
+ free(entryidsbuf);
+ free(entrytypesbuf);
+ free(completebuffer);
+
+ throw r_Error(r_Error::r_Error_BaseDBMSFailed);
+ }
+ break;
+ }
+ RMDBGOUT(7, "(relindexif)" << "\t\tbytes allready read " << bytesdone << " bytes read now " << dyndata1.length);
+ memcpy(&completebuffer[bytesdone], dyndata1.data, dyndata1.length);
+ bytesdone = dyndata1.length + bytesdone;
+ currentDbRows = currentDbRows + 1;
+ }
+ while (1);
+
+ //all dynamic data is in completebuffer
+ //put that stuff in the correct buffers
+ memcpy(lowerboundsbuf, completebuffer, boundssize);
+ memcpy(upperboundsbuf, &completebuffer[boundssize], boundssize);
+ memcpy(lowerfixedbuf, &completebuffer[boundssize * 2], fixessize);
+ memcpy(upperfixedbuf, &completebuffer[boundssize * 2 + fixessize], fixessize);
+ memcpy(entryidsbuf, &completebuffer[boundssize * 2 + fixessize * 2], idssize);
+ memcpy(entrytypesbuf, &completebuffer[boundssize * 2 + fixessize * 2 + idssize], typessize);
+ //all dynamic data is in its buffer
+ free (completebuffer);
+
+ //rebuild the attributes from the buffers
+ myDomain = InlineMinterval(dimension, &(lowerboundsbuf[0]), &(upperboundsbuf[0]), &(lowerfixedbuf[0]), &(upperfixedbuf[i*dimension]));
+ cout << "myDomain\t\t" << myDomain << endl;
+
+ for (i = 0; i < size; i++)
+ {
+ domainList.push_back(InlineMinterval(dimension, &(lowerboundsbuf[(i+1)*dimension]), &(upperboundsbuf[(i+1)*dimension]), &(lowerfixedbuf[(i+1)*dimension]), &(upperfixedbuf[(i+1)*dimension])));
+ entryOIdList.push_back(OId(entryidsbuf[i], (OId::OIdType)entrytypesbuf[i]));
+ RMDBGOUT(8, "(relindexif)" << "\t\tentry " << entryidsbuf[i] << " " << (OId::OIdType)entrytypesbuf[i] << " at " << InlineMinterval(dimension, &(lowerboundsbuf[(i+1)*dimension]), &(upperboundsbuf[(i+1)*dimension]), &(lowerfixedbuf[(i+1)*dimension]), &(upperfixedbuf[(i+1)*dimension])));
+ }
+
+ free(upperboundsbuf);
+ free(lowerboundsbuf);
+ free(upperfixedbuf);
+ free(lowerfixedbuf);
+ free(entryidsbuf);
+ free(entrytypesbuf);
+ EXEC SQL CLOSE C;
+ RMDBGOUT(8, "(relindexif)" << "\t\tDBHierIndex::readFromDb() END " << myOId);
+ }
+
+int
+main(int argc, char** argv)
+ {
+ AdminIf* myAdmin = AdminIf::instance();
+ DatabaseIf database;
+ TransactionIf ta;
+
+ if (!myAdmin)
+ {
+ cout << "Error at connecting " << endl;
+ cout << "Goodbye "<< endl;
+ exit (-1);
+ }
+
+ if (!database.open("RASBASE"))
+ {
+ cout << "could not open database" << endl;
+ }
+ if (argc == 2)
+ {
+ myOId = (double)a2l(argv[1]);
+ cout << "myOId " << myOId << endl;
+ readFromDb();
+ }
+ }
+
+
diff --git a/relmddif/Makefile.am b/relmddif/Makefile.am
new file mode 100644
index 0000000..d225fc4
--- /dev/null
+++ b/relmddif/Makefile.am
@@ -0,0 +1,49 @@
+# -*-Makefile-*- (for Emacs)
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+#
+#
+# MAKEFILE FOR:
+# mddif
+#
+# COMMENTS:
+# uses O2
+#
+##################################################################
+
+AM_CXXFLAGS=@BASEDBCXXFLAGS@
+AM_LDFLAGS=@BASEDBLDFLAGS@
+
+.SUFFIXES= .@EMBEDDEDSQLEXT@ .@EMBEDDEDSQLOUT@
+.@EMBEDDEDSQLEXT@.@EMBEDDEDSQLOUT@:
+ $(EMBEDDEDSQLPRECOMPILER) $@ $<
+
+noinst_LIBRARIES=librelmddif.a
+librelmddif_a_SOURCES=dbmddsetcommon.cc dbmddobj.hh dbmddset.hh dbiterid.hh mddid.hh
+EXTRA_librelmddif_a_SOURCES= dbmddobj.pgc dbmddset.pgc
+librelmddif_a_LIBADD=dbmddobj.$(OBJEXT) dbmddset.$(OBJEXT)
+librelmddif_a_DEPENDENCIES=dbmddobj.$(OBJEXT) dbmddset.$(OBJEXT)
+
+BUILT_SOURCES=dbmddobj.@EMBEDDEDSQLOUT@ dbmddset.@EMBEDDEDSQLOUT@
+
+CLEANFILES=dbmddobj.@EMBEDDEDSQLOUT@ dbmddset.@EMBEDDEDSQLOUT@ \
+ client.bm client.dbg client.log ir.out core
+
diff --git a/relmddif/dbiterid.hh b/relmddif/dbiterid.hh
new file mode 100644
index 0000000..b41583b
--- /dev/null
+++ b/relmddif/dbiterid.hh
@@ -0,0 +1,33 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#ifndef _DBITERID_HH_
+#define _DBITERID_HH_
+
+class DBMDDObj;
+#include "dbobjectiterator.hh"
+
+typedef DBObjectIterator<DBMDDObj> DBIter;
+typedef DBIter* DBIterId;
+
+#endif
+
diff --git a/relmddif/dbmddobj.hh b/relmddif/dbmddobj.hh
new file mode 100644
index 0000000..4497373
--- /dev/null
+++ b/relmddif/dbmddobj.hh
@@ -0,0 +1,254 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#ifndef _DBMDDOBJ_HH_
+#define _DBMDDOBJ_HH_
+
+#include <iostream>
+class ObjectBroker;
+class BaseType;
+class MDDBaseType;
+class OIdIf;
+class r_Minterval;
+class r_Error;
+class DBMinterval;
+
+#include "mddid.hh"
+#include "relindexif/indexid.hh"
+#include "reladminif/dbobject.hh"
+#include "raslib/mddtypes.hh"
+#include "relstorageif/storageid.hh"
+#include "relstorageif/dbstoragelayout.hh"
+
+//@ManMemo: Module: {\bf relmddif}
+/*@Doc:
+A {\tt DBMDDObj} object links all neccessary persistent data for an MDD
+object. One DBMDDObj can be inserted in multiple MDD Collections. It will
+only be deleted from the database when there are no more references in MDD
+Collections. This is done through persistent reference counting.
+
+The DBMDDObj stores the following data:
+-MDDBaseType: type information on the data that is stored in it.
+-Definition domain: the spatial domain this object may extend to. This
+ domain may have open boundaries.
+-Index: a refernce to the index which holds the actual data.
+-Storagelayout: has asorted methods for modifying how the data is stored in the database.
+The definition domain is stored in an extensible but inefficient way.
+*/
+
+class DBMDDObj : public DBObject
+ {
+ public:
+ DBMDDObj( const MDDBaseType* type,
+ const r_Minterval& domain,
+ const DBObjectId& i,
+ const DBStorageLayoutId& s,
+ const OId& theMDDObj) throw (r_Error);
+ /*@Doc:
+ type: it contains the basetype which will be used to create perstiles.
+ domain: the definition domain. the extend to which the mdd object may grow.
+ i: the index structure which should be used. there has to be some way to use DBRef<IndexDS>.
+ s: the storage layout object.
+ theMDDObj: this oid may not be assigned to an mdd object yet!
+ */
+
+ DBMDDObj( const MDDBaseType* newMDDType,
+ const r_Minterval& domain,
+ const DBObjectId& newObjIx,
+ const DBStorageLayoutId& newSL);
+ /*@Doc:
+ newMDDType: it contains the basetype which will be used to create perstiles.
+ domain: the definition domain. the extend to which the mdd object may grow.
+ newObjIx: the index structure which should be used. there has to be some way to use DBRef<IndexDS>.
+ s: the storage layout object.
+ The oid is generated by the object itself.
+ */
+
+ const MDDBaseType* getMDDBaseType() const;
+ /*@Doc:
+ return the mddbasetype for this object.
+ */
+
+ DBStorageLayoutId getDBStorageLayout() const;
+ /*@Doc:
+ return the storage layout object for this mdd object.
+ */
+
+ const char* getCellTypeName() const;
+ /*@Doc:
+ Returns the name of the base type of this MDD object cells.
+ */
+
+ const BaseType* getCellType() const;
+ /*@Doc:
+ Returns the base type of this MDD object cells.
+ */
+
+ r_Dimension dimensionality() const;
+ /*@Doc:
+ Returns dimensionality of the object.
+ */
+
+ r_Minterval getDefinitionDomain() const;
+ /*@Doc:
+ Returns the definition domain of the object.
+ */
+
+ r_Bytes getHeaderSize() const;
+ /*@Doc:
+ Returns the size of the header for an MDD object.
+ The size returned by this funtion is an approximation to
+ the size of the actual physical storage space used by the
+ base DBMS. In the current implementation:
+ HeaderSize = MDDBaseType*Size + r_Minterval*Size +
+ DBMDDObjIxSize + DBObjectSize
+ This should be reviewed and renamed to
+ getPhysicalStorageSize
+ */
+
+ virtual void printStatus(unsigned int level = 0, std::ostream& stream = cout) const;
+ /*@Doc:
+ Prints the status of the object:
+ the name of the cell type
+ the definition domain
+ the index contents
+ */
+
+ void setIx(const DBObjectId& newObjIx);
+ /*@Doc:
+ make the mdd object use newObjIx instead of its old index structure.
+ the old index structure is not deleted from the database!
+ */
+
+ DBObjectId getDBIndexDS() const;
+ /*@Doc:
+ Returns the reference to the index.
+ */
+
+ DBMDDObj(const DBMDDObj& old);
+ /*@Doc:
+ Copy constructor should never be used.
+ Should raise a r_Error.
+ */
+
+ virtual ~DBMDDObj();
+ /*@Doc:
+ Validates the object and deletes the definition domain.
+ */
+
+ virtual void setPersistent(bool t = true) throw (r_Error);
+ /*@Doc:
+ Was overridden to pass changes to definition domain, storage layout and
+ to the index.
+ */
+
+ virtual void setCached(bool ic);
+ /*@Doc:
+ overrides DBObject to handle the DBMinterval
+ */
+
+ void incrementPersRefCount();
+ /*@Doc:
+ used by mddset to tell the mddobj that there is an
+ additional mddset ref to it
+ */
+
+ void decrementPersRefCount();
+ /*@Doc:
+ used by mddset to tell the mddobj that there is an mddset
+ ref less to it
+ */
+
+ int getPersRefCount() const;
+ /*@Doc:
+ returns the number of persistent references to this object.
+ when zero, the object may be deleted
+ */
+
+ virtual r_Bytes getMemorySize() const;
+ /*@Doc:
+ Calculates the size of this object in main memory.
+ */
+
+ protected:
+ friend class ObjectBroker;
+
+ DBMDDObj(const OId& id) throw (r_Error);
+ /*@Doc:
+ Constructs a DBMDDObj from the database.
+ */
+
+ virtual void insertInDb() throw (r_Error);
+ /*@Doc:
+
+ */
+
+ virtual void deleteFromDb() throw (r_Error);
+ /*@Doc:
+
+ */
+
+ virtual void readFromDb() throw (r_Error);
+ /*@Doc:
+
+ */
+
+ virtual void updateInDb() throw (r_Error);
+ /*@Doc:
+
+ */
+
+ private:
+
+ int persistentRefCount;
+ /*@Doc:
+ number of persistent references (by mddsets) to this object
+ */
+
+ DBMDDObj();
+ /*@Doc:
+ creates an empty object and does NOT register it
+ with ObjectBroker.
+ */
+
+ const MDDBaseType* mddType;
+ /*@Doc:
+ Type of this object.
+ */
+
+ DBMinterval* myDomain;
+ /*@Doc:
+ Definition domain for the object.
+ */
+
+ DBStorageLayoutId storageLayoutId;
+ /*@Doc:
+ StorageLayout OId
+ */
+
+ DBObjectId objIxId;
+ /*@Doc:
+ Index OId
+ */
+ };
+
+#endif
diff --git a/relmddif/dbmddobj.pgc b/relmddif/dbmddobj.pgc
new file mode 100644
index 0000000..58f41d0
--- /dev/null
+++ b/relmddif/dbmddobj.pgc
@@ -0,0 +1,546 @@
+// This is -*- C++ -*-
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+
+#include "reladminif/oidif.hh"
+#include "reladminif/dbref.hh"
+#include "reladminif/sqlerror.hh"
+#include "reladminif/externs.h"
+#include "raslib/rmdebug.hh"
+#include "catalogmgr/typefactory.hh"
+#include "relcatalogif/mddbasetype.hh"
+#include "relcatalogif/basetype.hh"
+#include "reladminif/objectbroker.hh"
+#include "relcatalogif/dbminterval.hh"
+#include "relstorageif/dbstoragelayout.hh"
+#include "dbmddobj.hh"
+#include "relindexif/indexid.hh"
+#include "indexmgr/indexds.hh"
+
+#include "debug-srv.hh"
+
+
+DBMDDObj::DBMDDObj()
+ : DBObject(),
+ myDomain(NULL),
+ objIxId(),
+ mddType(NULL),
+ persistentRefCount(0),
+ storageLayoutId(new DBStorageLayout())
+{
+ RMDBGENTER(7, RMDebug::module_mddif, "DBMDDObj", "DBMDDObj()");
+ ENTER( "DBMDDObj::DBMDDObj" );
+
+ objecttype = OId::MDDOID;
+ myDomain = new DBMinterval();
+ myDomain->setPersistent(true);
+ storageLayoutId->setPersistent(true);
+
+ LEAVE( "DBMDDObj::DBMDDObj" );
+ RMDBGEXIT(7, RMDebug::module_mddif, "DBMDDObj", "DBMDDObj()");
+}
+
+DBMDDObj::DBMDDObj(const OId& id) throw (r_Error)
+ : DBObject(id),
+ myDomain(NULL),
+ objIxId(),
+ persistentRefCount(0),
+ mddType(NULL),
+ storageLayoutId((double)0)
+{
+ RMDBGENTER(7, RMDebug::module_mddif, "DBMDDObj", "DBMDDObj(" << myOId << ")");
+ ENTER( "DBMDDObj::DBMDDObj, id=" << id );
+
+ objecttype = OId::MDDOID;
+ readFromDb();
+
+ LEAVE( "DBMDDObj::DBMDDObj" );
+ RMDBGEXIT(7, RMDebug::module_mddif, "DBMDDObj", "DBMDDObj(" << myOId << ")");
+}
+
+DBMDDObj::DBMDDObj( const MDDBaseType* newMDDType,
+ const r_Minterval& domain,
+ const DBObjectId& newObjIx,
+ const DBStorageLayoutId& newSL,
+ const OId& newOId) throw (r_Error)
+ : DBObject(),
+ objIxId(newObjIx.getOId()),
+ mddType(newMDDType),
+ persistentRefCount(0),
+ storageLayoutId(newSL),
+ myDomain(NULL)
+{
+ RMDBGENTER(7, RMDebug::module_mddif, "DBMDDObj", "DBMDDObj(" << newMDDType->getName() << ", " << domain << ", Ix " << newObjIx.getOId() << ", Sl " << newSL.getOId() << ", " << newOId << ")");
+ ENTER( "DBMDDObj::DBMDDObj" );
+
+ objecttype = OId::MDDOID;
+ EXEC SQL BEGIN DECLARE SECTION;
+ long testoid1;
+ EXEC SQL END DECLARE SECTION;
+
+ testoid1 = newOId.getCounter();
+
+ TALK( "EXEC SQL SELECT MDDId INTO :testoid1 FROM RAS_MDDOBJECTS WHERE MDDId = " << testoid1 );
+ EXEC SQL SELECT
+ MDDId
+ INTO
+ :testoid1
+ FROM
+ RAS_MDDOBJECTS
+ WHERE
+ MDDId = :testoid1;
+ if (SQLCODE != SQLNODATAFOUND)
+ {
+ ((DBObjectId)newObjIx)->setPersistent(false);
+ ((DBObject*)newSL.ptr())->setPersistent(false);
+ if (SQLCODE == SQLOK)
+ {
+ RMDBGMIDDLE(1, RMDebug::module_mddif, "DBMDDObj", "OId is already there");
+ RMInit::logOut << "DBMDDObj::DBMDDObj(...) OId already exists" << endl;
+ throw r_Error(r_Error::r_Error_OIdNotUnique);
+ }
+ else
+ {
+ check("DBMDDObj(type, domain, index, layout, oid)");
+ generateException();
+ }
+ }
+ if (newMDDType->isPersistent())
+ mddType = newMDDType;
+ else
+ mddType = (const MDDBaseType*)TypeFactory::addMDDType(newMDDType);
+ myDomain = new DBMinterval(domain);
+ _isPersistent = true;
+ _isModified = true;
+ myOId = newOId;
+ setPersistent(true);
+
+ LEAVE( "DBMDDObj::DBMDDObj, " << newMDDType->getName() << ", " << domain << ", Ix " << newObjIx.getOId() << ", " << myOId << ") " << myOId );
+ RMDBGEXIT(7, RMDebug::module_mddif, "DBMDDObj", "DBMDDObj(" << newMDDType->getName() << ", " << domain << ", Ix " << newObjIx.getOId() << ", " << myOId << ") " << myOId);
+}
+
+
+DBMDDObj::DBMDDObj(const DBMDDObj& old)
+ : DBObject(old),
+ objIxId(),
+ mddType(NULL),
+ persistentRefCount(0),
+ storageLayoutId(),
+ myDomain(NULL)
+{
+ RMDBGENTER(7, RMDebug::module_mddif, "DBMDDObj", "DBMDDObj(const DBMDDObj&" << old.getOId() << ")");
+ ENTER( "DBMDDObj::DBMDDObj" );
+
+ if (old.myDomain)
+ {
+ if (old.myDomain->isPersistent())
+ {
+ myDomain = (DBMinterval*)ObjectBroker::getObjectByOId(old.myDomain->getOId());
+ }
+ else
+ {
+ myDomain = new DBMinterval(*old.myDomain);
+ myDomain->setPersistent(true);
+ }
+ }
+ else
+ {
+ myDomain = NULL;
+ }
+
+ objIxId = old.objIxId;
+ storageLayoutId = old.storageLayoutId;
+ persistentRefCount = old.persistentRefCount;
+ mddType = old.mddType;
+
+ LEAVE( "DBMDDObj::DBMDDObj" );
+ RMDBGEXIT(7, RMDebug::module_mddif, "DBMDDObj", "DBMDDObj(const DBMDDObj& " << old.getOId() << ")");
+}
+
+DBMDDObj::DBMDDObj(const MDDBaseType* newMDDType, const r_Minterval& domain, const DBObjectId& newObjIx, const DBStorageLayoutId& newSL)
+ : DBObject(),
+ objIxId(newObjIx),
+ mddType(NULL),
+ persistentRefCount(0),
+ storageLayoutId(newSL),
+ myDomain(NULL)
+{
+ RMDBGENTER(7, RMDebug::module_mddif, "DBMDDObj", "DBMDDObj(" << newMDDType->getName() << ", " << domain << ", Ix " << newObjIx.getOId() << ", Sl " << newSL.getOId() << ")");
+ ENTER( "DBMDDObj::DBMDDObj" );
+
+ objecttype = OId::MDDOID;
+ myDomain = new DBMinterval(domain);
+ mddType = newMDDType;
+/*only if it is a persistent mdd
+ if (newMDDType->isPersistent())
+ mddType = (MDDBaseType*)newMDDType;
+ else
+ mddType = (MDDBaseType*)TypeFactory::addMDDType(newMDDType);
+ setPersistent(true);
+*/
+
+ LEAVE( "DBMDDObj::DBMDDObj" );
+ RMDBGEXIT(7, RMDebug::module_mddif, "DBMDDObj", "DBMDDObj(" << newMDDType->getName() << ", " << domain << ", Ix " << newObjIx.getOId() << ") " << myOId);
+}
+
+DBMDDObj::~DBMDDObj()
+{
+ RMDBGENTER(7, RMDebug::module_mddif, "DBMDDObj", "~DBMDDObj() " << myOId);
+ ENTER( "DBMDDObj::~DBMDDObj" );
+
+ validate();
+ if (myDomain)
+ delete myDomain;
+ myDomain = NULL;
+
+ LEAVE( "DBMDDObj::~DBMDDObj" );
+ RMDBGEXIT(7, RMDebug::module_mddif, "DBMDDObj", "~DBMDDObj() " << myOId);
+}
+
+DBStorageLayoutId
+DBMDDObj::getDBStorageLayout() const
+{
+ return storageLayoutId;
+}
+
+r_Bytes
+DBMDDObj::getMemorySize() const
+{
+ return DBObject::getMemorySize() + sizeof(long) + sizeof(MDDBaseType*) + sizeof(DBMinterval*) + sizeof(OId) + myDomain->getMemorySize() + mddType->getMemorySize() + sizeof(OId);
+}
+
+const MDDBaseType*
+DBMDDObj::getMDDBaseType() const
+{
+ return mddType;
+}
+
+const BaseType*
+DBMDDObj::getCellType() const
+{
+ return mddType->getBaseType();
+}
+
+r_Dimension
+DBMDDObj::dimensionality() const
+{
+ return myDomain->dimension();
+}
+
+void
+DBMDDObj::setCached(bool ic)
+{
+ DBObject::setCached(ic);
+ if (myDomain)
+ myDomain->setCached(ic);
+}
+
+//this should only receive an setPersistent(false)
+void
+DBMDDObj::setPersistent(bool o) throw (r_Error)
+{
+ RMDBGENTER(7, RMDebug::module_mddif, "DBMDDObj", "setPersistent(" << (int)o << ") " << myOId);
+ ENTER( "DBMDDObj::setPersistent, o=" << o );
+
+ DBObject::setPersistent(o);
+ if (!o)
+ setCached(false);
+ if (myDomain)
+ myDomain->setPersistent(o);
+ DBObjectId testIx(objIxId);
+ if (testIx.is_null())
+ {
+ RMDBGMIDDLE(0, RMDebug::module_mddif, "DBMDDObj", "index object is not valid " << myOId << " index " << objIxId.getOId());
+ throw r_Error(INDEX_OF_MDD_IS_NULL);
+ }
+ else
+ {
+ testIx->setPersistent(o);
+ if (o)
+ {
+ objIxId.release();
+ }
+ }
+
+ if (storageLayoutId.is_null())
+ {
+ RMDBGMIDDLE(0, RMDebug::module_mddif, "DBMDDObj", "layout object is not valid " << myOId << " layout " << storageLayoutId.getOId());
+ RMInit::logOut << "DBMDDObj::setPersistent() layout object is not valid" << endl;
+ throw r_Error(STORAGE_OF_MDD_IS_NULL);
+ }
+ else
+ {
+ storageLayoutId->setPersistent(o);
+ }
+ if (o && !mddType->isPersistent())
+ mddType = (const MDDBaseType*)TypeFactory::addMDDType(mddType);
+
+ LEAVE( "DBMDDObj::setPersistent, o=" << o );
+ RMDBGEXIT(7, RMDebug::module_mddif, "DBMDDObj", "setPersistent(" << (int)o << ") " << myOId);
+}
+
+const char*
+DBMDDObj::getCellTypeName() const
+{
+ return mddType->getBaseType()->getTypeName();
+}
+
+r_Minterval
+DBMDDObj::getDefinitionDomain() const
+{
+ return *myDomain;
+}
+
+r_Bytes
+DBMDDObj::getHeaderSize() const
+{
+ r_Bytes sz = sizeof(MDDBaseType*) + sizeof(r_Minterval*) + sizeof(DBObjectId) + sizeof(DBObject) + sizeof(DBStorageLayoutId);
+ return sz;
+}
+
+void
+DBMDDObj::printStatus(unsigned int level, ostream& stream) const
+{
+ DBObject::printStatus(level, stream);
+ stream << *myDomain << endl;
+ mddType->printStatus(level + 1, stream);
+ DBObjectId testIx(objIxId);
+ if (!testIx.is_null())
+ testIx->printStatus(level + 1, stream);
+ else
+ stream << "index is invalid " << objIxId.getOId();
+ if (storageLayoutId.is_null())
+ stream << "storagelayout is invalid " << storageLayoutId.getOId();
+ else
+ storageLayoutId->printStatus(level + 1, stream);
+}
+
+void
+DBMDDObj::setIx(const DBObjectId& newIx)
+{
+ ENTER( "DBMDDObj::setIx" );
+
+ if (isPersistent())
+ {
+ if (objIxId.getOId() != newIx.getOId())
+ {
+ objIxId = newIx.getOId();
+ setModified();
+ }
+ }
+ else
+ {
+ objIxId = newIx;
+ }
+
+ LEAVE( "DBMDDObj::setIx" );
+}
+
+void
+DBMDDObj::updateInDb() throw (r_Error)
+{
+ RMDBGENTER(7, RMDebug::module_mddif, "DBMDDObj", "updateInDb() " << myOId);
+ ENTER( "DBMDDObj::updateInDb" );
+
+ EXEC SQL BEGIN DECLARE SECTION;
+ long mddoid3;
+ double objindex3;
+ long persRefCount3;
+ EXEC SQL END DECLARE SECTION;
+
+ objindex3 = objIxId.getOId();
+ mddoid3 = myOId.getCounter();
+ persRefCount3 = persistentRefCount;
+
+ TALK( "EXEC SQL UPDATE RAS_MDDOBJECTS SET PersRefCount = " << persRefCount3 << ", NodeOId = " << objindex3 << " WHERE MDDId = " << mddoid3 );
+ EXEC SQL UPDATE RAS_MDDOBJECTS SET PersRefCount = :persRefCount3, NodeOId = :objindex3
+ WHERE MDDId = :mddoid3;
+ if (SQLCODE != SQLOK)
+ {
+ check("DBMDDObj::updateInDb()\0");
+ generateException();
+ }
+
+ DBObject::updateInDb();
+
+ LEAVE( "DBMDDObj::updateInDb" );
+ RMDBGEXIT(7, RMDebug::module_mddif, "DBMDDObj", "updateInDb() " << myOId);
+}
+
+void
+DBMDDObj::insertInDb() throw (r_Error)
+{
+ RMDBGENTER(7, RMDebug::module_mddif, "DBMDDObj", "insertInDb() " << myOId);
+ ENTER( "DBMDDObj::insertInDb" );
+
+ EXEC SQL BEGIN DECLARE SECTION;
+ long mddoid;
+ double basetypeid;
+ double storage;
+ long domainid;
+ double objindex;
+ long persRefCount;
+ EXEC SQL END DECLARE SECTION;
+
+ storage = storageLayoutId->getOId();
+ objindex = objIxId.getOId();
+ mddoid = myOId.getCounter();
+ basetypeid = mddType->getOId();
+ domainid = myDomain->getOId().getCounter();
+ persRefCount = persistentRefCount;
+
+ TALK( "EXEC SQL INSERT INTO RAS_MDDOBJECTS ( MDDId, BaseTypeOId, DomainId, PersRefCount, NodeOId, StorageOId) VALUES ( " << mddoid << "," << basetypeid<< "," << domainid<< "," << persRefCount << "," << objindex << "," << storage << ")" );
+ EXEC SQL INSERT INTO RAS_MDDOBJECTS ( MDDId, BaseTypeOId, DomainId, PersRefCount, NodeOId, StorageOId)
+ VALUES ( :mddoid, :basetypeid, :domainid, :persRefCount, :objindex, :storage);
+ if (SQLCODE != SQLOK)
+ {
+ check("DBMDDObj::insertInDb()");
+ generateException();
+ }
+
+ DBObject::insertInDb();
+
+ LEAVE( "DBMDDObj::insertInDb" );
+ RMDBGEXIT(7, RMDebug::module_mddif, "DBMDDObj", "insertInDb() " << myOId);
+}
+
+void
+DBMDDObj::deleteFromDb() throw (r_Error)
+{
+ RMDBGENTER(7, RMDebug::module_mddif, "DBMDDObj", "deleteFromDb() " << myOId);
+ ENTER( "DBMDDObj::deleteFromDb" );
+
+ EXEC SQL BEGIN DECLARE SECTION;
+ long mddoid1;
+ EXEC SQL END DECLARE SECTION;
+
+ mddoid1 = myOId.getCounter();
+
+ TALK( "EXEC SQL DELETE FROM RAS_MDDOBJECTS WHERE MDDId = " << mddoid1 );
+ EXEC SQL DELETE FROM RAS_MDDOBJECTS WHERE MDDId = :mddoid1;
+ if (SQLCODE != SQLOK)
+ {
+ check("DBMDDObj::deleteFromDb()\0");
+ generateException();
+ }
+ DBObject::deleteFromDb();
+
+ LEAVE( "DBMDDObj::deleteFromDb" );
+ RMDBGEXIT(7, RMDebug::module_mddif, "DBMDDObj", "deleteFromDb() " << myOId);
+}
+
+void
+DBMDDObj::readFromDb() throw (r_Error)
+{
+ RMDBGENTER(7, RMDebug::module_mddif, "DBMDDObj", "readFromDb() " << myOId);
+ ENTER( "DBMDDObj::readFromDb" );
+
+#ifdef RMANBENCHMARK
+ DBObject::readTimer.resume();
+#endif
+ EXEC SQL BEGIN DECLARE SECTION;
+ long mddoid2;
+ double basetypeid2;
+ long domainid2;
+ double objindex2;
+ long persRefCount2;
+ double storage2;
+ EXEC SQL END DECLARE SECTION;
+
+ mddoid2 = myOId.getCounter();
+
+ TALK( "EXEC SQL SELECT BaseTypeOId, DomainId, PersRefCount, NodeOId, StorageOId INTO :basetypeid2, :domainid2, :persRefCount2, :objindex2, :storage2 FROM RAS_MDDOBJECTS WHERE MDDId = " << mddoid2 );
+
+ EXEC SQL SELECT BaseTypeOId, DomainId, PersRefCount, NodeOId, StorageOId
+ INTO :basetypeid2, :domainid2, :persRefCount2, :objindex2, :storage2
+ FROM RAS_MDDOBJECTS
+ WHERE MDDId = :mddoid2;
+ if (SQLCODE != SQLOK)
+ {
+ if (SQLCODE == SQLNODATAFOUND)
+ {
+ RMDBGMIDDLE(7, RMDebug::module_mddif, "DBMDDObj", "object not found");
+ throw r_Error(r_Error::r_Error_ObjectUnknown);
+ }
+ else
+ {
+ check("DBMDDObj::readFromDb()\0");
+ generateException();
+ }
+ }
+
+ objIxId = OId(objindex2);
+ storageLayoutId = OId(storage2);
+ persistentRefCount = persRefCount2;
+ mddType = (MDDBaseType*)ObjectBroker::getObjectByOId(OId(basetypeid2));
+ myDomain = (DBMinterval*)ObjectBroker::getObjectByOId(OId(domainid2, OId::DBMINTERVALOID));
+ myDomain->setCached(true);
+
+ DBObject::readFromDb();
+#ifdef RMANBENCHMARK
+ DBObject::readTimer.pause();
+#endif
+
+ LEAVE( "DBMDDObj::readFromDb" );
+ RMDBGEXIT(7, RMDebug::module_mddif, "DBMDDObj", "readFromDb() " << myOId);
+}
+
+
+DBObjectId
+DBMDDObj::getDBIndexDS() const
+{
+ return objIxId;
+}
+
+int
+DBMDDObj::getPersRefCount() const
+{
+ return persistentRefCount;
+}
+
+void
+DBMDDObj::incrementPersRefCount()
+{
+ persistentRefCount++;
+ setModified();
+}
+
+void
+DBMDDObj::decrementPersRefCount()
+{
+ persistentRefCount--;
+ if (persistentRefCount == 0)
+ setPersistent(false);
+ setModified();
+}
diff --git a/relmddif/dbmddset.hh b/relmddif/dbmddset.hh
new file mode 100644
index 0000000..7df6cd4
--- /dev/null
+++ b/relmddif/dbmddset.hh
@@ -0,0 +1,176 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#ifndef _MDDSET_HH_
+#define _MDDSET_HH_
+
+class MDDSet;
+class OId;
+class EOId;
+class r_Error;
+class DBMDDObj;
+class CollectionType;
+
+#include "reladminif/lists.h"
+#include "mddid.hh"
+#include "reladminif/dbnamedobject.hh"
+#include "reladminif/dbref.hh"
+
+//@ManMemo: Module: {\bf mddif}
+/*@Doc:
+ MDDSet is the persistent class for collections of MDD objects.
+
+ Each instance of MDDSet represents a collection stored in the base
+ DBMS.
+
+ This class should only be used by DBMDDColl.
+*/
+
+class DBMDDSet : public DBNamedObject
+ {
+ public:
+ DBMDDSet(const char* name, const CollectionType* type) throw (r_Error);
+ /*@Doc:
+ creates a new set
+ */
+
+ DBMDDSet(const char* name, const OId& id, const CollectionType* type) throw (r_Error);
+ /*@Doc:
+ creates a new set
+ */
+
+ static DBMDDSetId getDBMDDSet(const char* name) throw (r_Error);
+
+ static DBMDDSetId getDBMDDSet(const OId& id) throw (r_Error);
+
+ static bool deleteDBMDDSet(const OId& id);
+ /*@Doc:
+ returns succes
+ */
+
+ static bool deleteDBMDDSet(const char* name);
+ /*@Doc:
+ returns succes
+ */
+
+ virtual void printStatus(unsigned int level = 0, std::ostream& stream = std::cout) const;
+
+ virtual void setPersistent(bool state) throw (r_Error);
+ /*@Doc:
+ throws r_Error when the mdd set may not be made persistent.
+ */
+
+ void insert(DBMDDObjId newObj);
+ /*@Doc:
+ Inserts an object into the MDD Collection.
+ The persistent reference count of this DBMDDObj is updated.
+ */
+
+ DBMDDObjIdIter* newIterator() const;
+ /*@Doc:
+ Returns a new iterator for this collection.
+ */
+
+ unsigned int getCardinality() const;
+ /*@Doc:
+ Returns the number of elements in the collection.
+ */
+
+ void remove(DBMDDObjId& obj);
+ /*@Doc:
+ Removes an object from the MDD Collection.
+ The persistent reference count of this DBMDDObj is updated.
+ */
+
+ void removeAll();
+ /*@Doc:
+ Removes all objects from the MDD Collection.
+ The persistent reference count of the DBMDDObjs is updated.
+ */
+
+ void releaseAll();
+ /*@Doc:
+ Releases all dynamic memory used by this collection.
+ */
+
+ bool contains_element(const DBMDDObjId& elem) const;
+ /*@Doc:
+ */
+
+ virtual ~DBMDDSet( );
+ /*@Doc:
+ */
+
+ void deleteName();
+ /*@Doc:
+ sets the name of this object to a null string.
+ used by DatabaseIf::destroyRoot
+ */
+
+ virtual r_Bytes getMemorySize() const;
+ /*@Doc:
+ */
+
+ const CollectionType* getCollType() const;
+ /*@Doc:
+ Returns the collectiontype of this entry.
+ */
+
+ protected:
+ friend class ObjectBroker;
+
+ typedef std::set<DBMDDObjId, std::less<DBMDDObjId> > DBMDDObjIdSet;
+
+ DBMDDSet(const OId& id) throw (r_Error);
+ /*@Doc:
+ gets an existing coll from the db
+ */
+
+ virtual void updateInDb() throw(r_Error);
+ /*@Doc:
+ */
+
+ virtual void insertInDb() throw(r_Error);
+ /*@Doc:
+ */
+
+ virtual void readFromDb() throw(r_Error);
+ /*@Doc:
+ */
+
+ virtual void deleteFromDb() throw(r_Error);
+ /*@Doc:
+ */
+
+ private:
+ DBMDDObjIdSet mySet;
+ /*@Doc:
+ Memory representation of the list of oids of DBMDDObjs.
+ */
+
+ const CollectionType* collType;
+ /*@Doc:
+ Pointer to the collectiontype.
+ */
+ };
+
+#endif
diff --git a/relmddif/dbmddset.pgc b/relmddif/dbmddset.pgc
new file mode 100644
index 0000000..b92a884
--- /dev/null
+++ b/relmddif/dbmddset.pgc
@@ -0,0 +1,314 @@
+// This is -*- C++ -*-
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * Code with embedded SQL for PostgreSQL DBMS
+ *
+ *
+ * COMMENTS:
+ * uses embedded SQL
+ *
+ ************************************************************/
+
+#include "debug-srv.hh"
+
+// general embedded SQL related definitions
+EXEC SQL include "../reladminif/sqlglobals.h";
+
+#include "dbmddset.hh"
+#include "raslib/rmdebug.hh"
+#include "reladminif/sqlerror.hh"
+#include "reladminif/objectbroker.hh"
+#include "relcatalogif/collectiontype.hh"
+
+DBMDDSet::DBMDDSet(const char* name, const OId& id, const CollectionType* type) throw (r_Error)
+ : DBNamedObject(id, name),
+ collType(type)
+{
+ RMDBGENTER(4, RMDebug::module_mddif, "DBMDDSet", "DBMDDSet(" << getName() << ", " << myOId << ", " << collType->getName() << ")");
+ ENTER( "DBMDDSet::DBMDDSet, name=" << name << ", oid=" << id );
+
+ if (name == NULL)
+ setName("unnamed collection");
+ if (type == NULL)
+ {
+ RMDBGONCE(0, RMDebug::module_mddif, "DBMDDSet", "DBMDDSet(" << name << ", NULL)")
+ throw r_Error(r_Error::r_Error_General);
+ }
+ if (!type->isPersistent())
+ {
+ r_Error t(RASTYPEUNKNOWN);
+ t.setTextParameter("type", type->getName());
+ RMDBGONCE(0, RMDebug::module_mddif, "DBMDDSet", "DBMDDSet(" << name << ", " << type->getName() << " not persistent)")
+ throw t;
+ }
+ DBMDDSet* set = NULL;
+ try
+ {
+ set = (DBMDDSet*)ObjectBroker::getObjectByName(OId::MDDCOLLOID, getName());
+ }
+ catch (r_Error& err)
+ {
+ if (err.get_kind() == r_Error::r_Error_ObjectUnknown)
+ set = NULL;
+ else
+ throw;
+ }
+ if (set)
+ {
+ RMDBGMIDDLE(5, RMDebug::module_mddif, "DBMDDSet", "already have a set with name " << getName());
+ RMInit::logOut << "DBMDDSet::DBMDDSet() mdd collection with name \"" << getName() << "\" exists already" << endl;
+ throw r_Error(r_Error::r_Error_NameNotUnique);
+ }
+ EXEC SQL BEGIN DECLARE SECTION;
+ long testoid1;
+ EXEC SQL END DECLARE SECTION;
+
+ testoid1 = id.getCounter();
+ TALK( "EXEC SQL SELECT MDDCollId INTO :testoid1 FROM RAS_MDDCOLLNAMES WHERE MDDCollId = " << testoid1 );
+ EXEC SQL SELECT MDDCollId INTO :testoid1 FROM RAS_MDDCOLLNAMES WHERE MDDCollId = :testoid1;
+ if (SQLCODE == SQLNODATAFOUND)
+ { //the code is most of the time 100
+ _isInDatabase = false;
+ _isPersistent = true;
+ _isModified = true;
+ objecttype = OId::MDDCOLLOID;
+ myOId = id;
+ ObjectBroker::registerDBObject(this);
+ }
+ else
+ {
+ if (SQLCODE == SQLOK)
+ {
+ RMDBGMIDDLE(2, RMDebug::module_mddif, "DBMDDSet", "already have a DBMDDSet with this OId " << id);
+ RMInit::logOut << "DBMDDSet::DBMDDSet() mdd collection with oid \"" << id << "\" exists already" << endl;
+ throw r_Error(r_Error::r_Error_OIdNotUnique);
+ }
+ else
+ {
+ check("DBMDDSet::DBMDDSet(name, oid, settype)");
+ generateException();
+ }
+ }
+
+ LEAVE( "DBMDDSet::DBMDDSet" );
+ RMDBGEXIT(4, RMDebug::module_mddif, "DBMDDSet", "DBMDDSet(" << name << ", " << id << ") " << myOId);
+}
+
+void
+DBMDDSet::insertInDb() throw (r_Error)
+{
+ RMDBGENTER(4, RMDebug::module_mddif, "DBMDDSet", "insertInDb() " << myOId);
+ ENTER( "DBMDDSet::insertInDb" );
+
+ EXEC SQL BEGIN DECLARE SECTION;
+ long mddoid;
+ long mddcolloid;
+ long colltypeoid;
+ char collname[VARCHAR_MAXLEN];
+ EXEC SQL END DECLARE SECTION;
+
+ mddcolloid = myOId.getCounter();
+ colltypeoid = collType->getOId().getCounter();
+
+ (void) strncpy( collname, (char*) getName(), (size_t) sizeof(collname) );
+
+ TALK( "EXEC SQL INSERT INTO RAS_MDDCOLLNAMES ( MDDCollName, MDDCollId, SetTypeId) VALUES( " << collname << "," << mddcolloid << "," << colltypeoid << ")" );
+
+ EXEC SQL INSERT INTO RAS_MDDCOLLNAMES ( MDDCollName, MDDCollId, SetTypeId)
+ VALUES ( :collname, :mddcolloid, :colltypeoid);
+ if (SQLCODE != SQLOK)
+ {
+ check("DBMDDSet::insertInDb() INSERT INTO RAS_MDDCOLLNAMES\0");
+ generateException();
+ }
+
+ for (DBMDDObjIdSet::iterator i = mySet.begin(); i != mySet.end(); i++)
+ {
+ mddoid = (*i).getOId().getCounter();
+ RMDBGMIDDLE(5, RMDebug::module_mddif, "DBMDDSet", "mddobject with id " << mddoid);
+ TALK( "EXEC SQL INSERT INTO RAS_MDDCOLLECTIONS ( MDDId, MDDCollId) VALUES( " << mddoid << "," << mddcolloid << ")" );
+ EXEC SQL INSERT INTO RAS_MDDCOLLECTIONS ( MDDId, MDDCollId)
+ VALUES ( :mddoid, :mddcolloid);
+ if (SQLCODE != SQLOK)
+ {
+ check("DBMDDSet::insertInDb() INSERT INTO RAS_MDDCOLLECTIONS\0");
+ generateException();
+ }
+ else
+ {
+ RMDBGMIDDLE(5, RMDebug::module_mddif, "DBMDDSet", "wrote mddobjoid\t: " << (*i).getOId());
+ }
+ }
+
+ DBObject::insertInDb();
+
+ LEAVE( "DBMDDSet::insertInDb" );
+ RMDBGEXIT(4, RMDebug::module_mddif, "DBMDDSet", "insertInDb() " << myOId);
+}
+
+void
+DBMDDSet::deleteFromDb() throw (r_Error)
+{
+ RMDBGENTER(4, RMDebug::module_mddif, "DBMDDSet", "deleteFromDb() " << myOId);
+ ENTER( "DBMDDSet::deleteFromDb" );
+
+ EXEC SQL BEGIN DECLARE SECTION;
+ long mddcolloid1;
+ EXEC SQL END DECLARE SECTION;
+
+ mddcolloid1 = myOId.getCounter();
+ TALK( "EXEC SQL DELETE FROM RAS_MDDCOLLNAMES WHERE MDDCollId = " << mddcolloid1 );
+ EXEC SQL DELETE FROM RAS_MDDCOLLNAMES WHERE MDDCollId = :mddcolloid1;
+ if (SQLCODE != SQLOK)
+ {
+ check("DBMDDSet::deleteFromDb() DELETE FROM RAS_MDDCOLLNAMES\0");
+ generateException();
+ }
+
+ TALK( "EXEC SQL DELETE FROM RAS_MDDCOLLECTIONS WHERE MDDCollId = " << mddcolloid1 );
+ EXEC SQL DELETE FROM RAS_MDDCOLLECTIONS WHERE MDDCollId = :mddcolloid1;
+ if (SQLCODE != SQLOK)
+ {
+ if (SQLCODE != SQLNODATAFOUND)
+ {
+ check("DBMDDSet::deleteFromDb() DELETE FROM RAS_MDDCOLLECTIONS\0");
+ generateException();
+ }
+ else
+ {
+ //there may be empty collections
+ }
+ }
+
+ DBObject::deleteFromDb();
+
+ LEAVE( "DBMDDSet::deleteFromDb" );
+ RMDBGEXIT(4, RMDebug::module_mddif, "DBMDDSet", "deleteFromDb() " << myOId);
+}
+
+void
+DBMDDSet::readFromDb() throw (r_Error)
+{
+ RMDBGENTER(4, RMDebug::module_mddif, "DBMDDSet", "readFromDb() " << myOId);
+ ENTER( "DBMDDSet::readFromDb" );
+
+#ifdef RMANBENCHMARK
+ DBObject::readTimer.resume();
+#endif
+ EXEC SQL BEGIN DECLARE SECTION;
+ long mddoid2;
+ long mddcolloid2;
+ long colltypeoid2;
+ char collname2[VARCHAR_MAXLEN];
+ EXEC SQL END DECLARE SECTION;
+
+ mddcolloid2 = myOId.getCounter();
+
+ TALK( "EXEC SQL SELECT MDDCollName, SetTypeId INTO :collname2, :colltypeoid2 FROM RAS_MDDCOLLNAMES WHERE MDDCollId = " << mddcolloid2 );
+
+ EXEC SQL SELECT MDDCollName, SetTypeId
+ INTO :collname2, :colltypeoid2
+ FROM RAS_MDDCOLLNAMES
+ WHERE MDDCollId = :mddcolloid2;
+ if (SQLCODE != SQLOK)
+ {
+ if (SQLCODE == SQLNODATAFOUND)
+ {
+ RMDBGMIDDLE(7, RMDebug::module_mddif, "DBMDDSet", "object not found");
+ LEAVE( "DBMDDSet::readFromDb(): object not found" );
+ throw r_Error(r_Error::r_Error_ObjectUnknown);
+ }
+ else
+ {
+ LEAVE( "DBMDDSet::readFromDb(): db access error: " << SQLCODE );
+ check("DBMDDSet::readFromDb() SELECT FROM RAS_MDDCOLLNAMES\0");
+ generateException();
+ }
+ }
+
+ setName(collname2);
+ collType = (const CollectionType*)ObjectBroker::getObjectByOId(OId(colltypeoid2, OId::SETTYPEOID));
+
+ TALK( "EXEC SQL DECLARE c CURSOR FOR SELECT MDDId FROM RAS_MDDCOLLECTIONS WHERE MDDCollId = " << mddcolloid2 << " ORDER BY MDDId" );
+ EXEC SQL DECLARE c CURSOR FOR
+ SELECT MDDId
+ FROM RAS_MDDCOLLECTIONS
+ WHERE MDDCollId = :mddcolloid2
+ ORDER BY MDDId;
+ if (SQLCODE != SQLOK)
+ {
+ LEAVE( "DBMDDSet::readFromDb(): db access error: " << SQLCODE );
+ check("DBMDDSet::readFromDb() DECLARE CURSOR");
+ generateException();
+ }
+
+ TALK( "EXEC SQL OPEN c" );
+ EXEC SQL OPEN c;
+ if (SQLCODE != SQLOK)
+ {
+ LEAVE( "DBMDDSet::readFromDb(): db access error: " << SQLCODE );
+ check("DBMDDSet::readFromDb() OPEN CURSOR");
+ generateException();
+ }
+
+ do
+ {
+ TALK( "EXEC SQL FETCH c INTO :mddoid2" );
+ EXEC SQL FETCH c INTO :mddoid2;
+ if (SQLCODE == SQLOK)
+ {
+ RMDBGMIDDLE(7, RMDebug::module_mddif, "DBMDDSet", "fetched mddobjectoid " << mddoid2);
+ mySet.insert(OId(mddoid2, OId::MDDOID));
+ }
+ else
+ {
+ if (SQLCODE == SQLNODATAFOUND)
+ {
+ //no more data to read
+ break;
+ }
+ else
+ {
+ LEAVE( "DBMDDSet::readFromDb(): db access error: " << SQLCODE );
+ check("DBMDDSet::readFromDb() FETCHING\0");
+ generateException();
+ }
+ }
+ } while (true);
+ TALK( "EXEC SQL CLOSE c" );
+ EXEC SQL CLOSE c;
+
+ DBObject::readFromDb();
+#ifdef RMANBENCHMARK
+ DBObject::readTimer.pause();
+#endif
+
+ LEAVE( "DBMDDSet::readFromDb" );
+ RMDBGEXIT(4, RMDebug::module_mddif, "DBMDDSet", "readFromDb() " << myOId);
+}
+
diff --git a/relmddif/dbmddsetcommon.cc b/relmddif/dbmddsetcommon.cc
new file mode 100644
index 0000000..4bd4dd7
--- /dev/null
+++ b/relmddif/dbmddsetcommon.cc
@@ -0,0 +1,281 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include <iostream>
+#include <set>
+#include "dbmddset.hh"
+#include "raslib/rmdebug.hh"
+#include "reladminif/sqlerror.hh"
+#include "reladminif/externs.h"
+#include "dbmddobj.hh"
+#include "reladminif/objectbroker.hh"
+#include "reladminif/dbref.hh"
+#include "relcatalogif/collectiontype.hh"
+#include "reladminif/dbobjectiditerator.hh"
+#include "raslib/error.hh"
+
+void
+DBMDDSet::printStatus(unsigned int level, std::ostream& stream) const
+ {
+ char* indent = new char[level*2 +1];
+ for (int j = 0; j < level*2 ; j++)
+ indent[j] = ' ';
+ indent[level*2] = '\0';
+ DBObject::printStatus(level, stream);
+ stream << indent;
+ stream << "Collection Entries ";
+ for (DBMDDObjIdSet::const_iterator i = mySet.begin(); i != mySet.end(); i++)
+ {
+ if (isPersistent())
+ stream << (*i).getOId() << " ";
+ else
+ stream << (r_Ptr)(*i).ptr() << " ";
+ }
+ stream << endl;
+ delete[] indent;
+ indent=0;
+ }
+
+bool
+DBMDDSet::contains_element(const DBMDDObjId& elem) const
+ {
+ RMDBGENTER(4, RMDebug::module_mddif, "DBMDDSet", "contains_element(" << elem.getOId() << ") " << myOId);
+ bool retval = false;
+ DBMDDObjIdSet::const_iterator i = mySet.find(elem);
+ if (i != mySet.end())
+ {
+ retval = true;
+ }
+ RMDBGEXIT(4, RMDebug::module_mddif, "DBMDDSet", "contains_element(" << elem.getOId() << ") " << myOId << " " << retval);
+ return retval;
+ }
+
+void
+DBMDDSet::remove(DBMDDObjId& elem)
+ {
+ RMDBGENTER(4, RMDebug::module_mddif, "DBMDDSet", "remove(" << elem.getOId() << ")");
+ DBMDDObjIdSet::iterator i = mySet.find(elem);
+ if (i != mySet.end())
+ {
+ elem->decrementPersRefCount();
+ mySet.erase(i);
+ setModified();
+ }
+ RMDBGEXIT(4, RMDebug::module_mddif, "DBMDDSet", "remove(" << elem.getOId() << ")");
+ }
+
+void
+DBMDDSet::removeAll()
+ {
+ DBMDDObjId t;
+ while (!mySet.empty())
+ {
+ ((DBMDDObj*)(*(mySet.begin())).ptr())->decrementPersRefCount();
+ mySet.erase(mySet.begin());
+ }
+ setModified();
+ }
+
+DBMDDSet::~DBMDDSet()
+ {
+ RMDBGENTER(4, RMDebug::module_mddif, "DBMDDSet", "~DBMDDSet() " << myOId);
+ validate();
+ collType = NULL;
+ mySet.clear();
+ RMDBGEXIT(4, RMDebug::module_mddif, "DBMDDSet", "~DBMDDSet() " << myOId);
+ }
+
+const CollectionType*
+DBMDDSet::getCollType() const
+ {
+ RMDBGONCE(4, RMDebug::module_mddif, "DBMDDSet", "getCollType() " << myOId << "\t" << collType->getName());
+ return collType;
+ }
+
+
+r_Bytes
+DBMDDSet::getMemorySize() const
+ {
+ return DBNamedObject::getMemorySize() + sizeof(OIdSet) + mySet.size() * sizeof(OId);
+ }
+
+void
+DBMDDSet::insert(DBMDDObjId elem)
+ {
+ if (!contains_element(elem))
+ {
+ setModified();
+ elem->incrementPersRefCount();
+ mySet.insert(elem);
+ }
+ }
+
+DBMDDObjIdIter*
+DBMDDSet::newIterator() const
+ {
+ return new DBMDDObjIdIter(mySet);
+ }
+
+unsigned int
+DBMDDSet::getCardinality() const
+ {
+ return mySet.size();
+ }
+
+void
+DBMDDSet::deleteName()
+ {
+ setName("\0");
+ setModified();
+ }
+
+void
+DBMDDSet::releaseAll()
+ {
+ RMDBGONCE(1, RMDebug::module_mddif, "DBMDDSet", "releaseAll() " << myOId << "\tdoes not do anything");
+ }
+
+DBMDDSetId
+DBMDDSet::getDBMDDSet(const char* name) throw (r_Error)
+ {
+ RMDBGENTER(4, RMDebug::module_mddif, "DBMDDSet", "getDBMDDSet(" << name << ")");
+ DBMDDSetId set((DBMDDSet*)ObjectBroker::getObjectByName(OId::MDDCOLLOID, name));
+ RMDBGEXIT(4, RMDebug::module_mddif, "DBMDDSet", "getDBMDDSet(" << name << ")");
+ return set;
+ }
+
+DBMDDSetId
+DBMDDSet::getDBMDDSet(const OId& o) throw (r_Error)
+ {
+ RMDBGENTER(4, RMDebug::module_mddif, "DBMDDSet", "getDBMDDSet(" << o << ")");
+ DBMDDSetId set((DBMDDSet*)ObjectBroker::getObjectByOId(o));
+ RMDBGEXIT(4, RMDebug::module_mddif, "DBMDDSet", "getDBMDDSet(" << o << ")");
+ return set;
+ }
+
+bool
+DBMDDSet::deleteDBMDDSet(const OId& oid)
+ {
+ bool retval = true;
+ try {
+ DBObject* set = ObjectBroker::getObjectByOId(oid);
+ set->setPersistent(false);
+ }
+ catch (r_Error& e)
+ {
+ if (e.get_kind() == r_Error::r_Error_ObjectUnknown)
+ retval = false;
+ else
+ throw;
+ }
+ return retval;
+ }
+
+bool
+DBMDDSet::deleteDBMDDSet(const char* name)
+ {
+ bool retval = true;
+ try {
+ DBObject* set = ObjectBroker::getObjectByName(OId::MDDCOLLOID, name);
+ set->setPersistent(false);
+ }
+ catch (r_Error& e)
+ {
+ if (e.get_kind() == r_Error::r_Error_ObjectUnknown)
+ retval = false;
+ else
+ throw;
+ }
+ return retval;
+ }
+
+DBMDDSet::DBMDDSet(const char* name, const CollectionType* type) throw (r_Error)
+ : DBNamedObject(name),
+ collType(type)
+ {
+ if (name == NULL)
+ setName("unnamed collection");
+ if (type == NULL)
+ {
+ RMDBGONCE(0, RMDebug::module_mddif, "DBMDDSet", "DBMDDSet(" << name << ", NULL)")
+ RMInit::logOut << "DBMDDSet::DBMDDSet() the collection type is NULL" << endl;
+ throw r_Error(COLLECTIONTYPEISNULL);
+ }
+ objecttype = OId::MDDCOLLOID;
+ }
+
+void
+DBMDDSet::setPersistent(bool state) throw (r_Error)
+ {
+ DBMDDSet* set = NULL;
+ if (state)
+ {
+ if (!collType->isPersistent())
+ {
+ r_Error t(RASTYPEUNKNOWN);
+ t.setTextParameter("type", collType->getName());
+ RMDBGONCE(0, RMDebug::module_mddif, "DBMDDSet", "setPersistent(" << state << ") " << getName() << ", " << collType->getName() << " not persistent");
+ throw t;
+ }
+ try {
+ set = (DBMDDSet*)ObjectBroker::getObjectByName(OId::MDDCOLLOID, getName());
+ }
+ catch (r_Error& err)
+ {
+ if (err.get_kind() == r_Error::r_Error_ObjectUnknown)
+ set = NULL;
+ else
+ throw;
+ }
+ if (set)
+ {
+ RMDBGMIDDLE(6, RMDebug::module_mddif, "DBMDDSet", "already have a set with name " << getName());
+ RMInit::logOut << "DBMDDSet::DBMDDSet() mdd collection with name \"" << getName() << "\" exists already" << endl;
+ throw r_Error(r_Error::r_Error_NameNotUnique);
+ }
+ }
+ else {
+ removeAll();
+ }
+ DBNamedObject::setPersistent(state);
+ }
+
+DBMDDSet::DBMDDSet(const OId& id) throw (r_Error)
+ : DBNamedObject(id),
+ collType(0)
+ {
+ RMDBGENTER(4, RMDebug::module_mddif, "DBMDDSet", "DBMDDSet(" << myOId << ")");
+ objecttype = OId::MDDCOLLOID;
+ readFromDb();
+ RMDBGEXIT(4, RMDebug::module_mddif, "DBMDDSet", "DBMDDSet(" << myOId << ")");
+ }
+
+void
+DBMDDSet::updateInDb() throw (r_Error)
+ {
+ RMDBGENTER(4, RMDebug::module_mddif, "DBMDDSet", "updateInDb() " << myOId);
+ deleteFromDb();
+ insertInDb();
+ DBObject::updateInDb();
+ RMDBGEXIT(4, RMDebug::module_mddif, "DBMDDSet", "updateInDb() " << myOId);
+ }
+
diff --git a/relmddif/mddid.hh b/relmddif/mddid.hh
new file mode 100644
index 0000000..de721cf
--- /dev/null
+++ b/relmddif/mddid.hh
@@ -0,0 +1,36 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#ifndef _MDDID_HH_
+#define _MDDID_HH_
+
+class DBMDDObj;
+class DBMDDSet;
+
+template <class T> class DBRef;
+template <class T> class DBObjectIdIterator;
+
+typedef DBRef<DBMDDObj> DBMDDObjId;
+typedef DBRef<DBMDDSet> DBMDDSetId;
+typedef DBObjectIdIterator<DBMDDObj> DBMDDObjIdIter;
+
+#endif
diff --git a/relmddif/test/Makefile b/relmddif/test/Makefile
new file mode 100644
index 0000000..b5df243
--- /dev/null
+++ b/relmddif/test/Makefile
@@ -0,0 +1,77 @@
+# -*-Makefile-*-
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>. # Top Level makefile. This points to the various modules that have to be build
+# and/or deployed
+#
+# MAKEFILE FOR:
+# test programs of module relblobif
+#
+# COMMENTS:
+# List environment dependencies, known bugs, specialities etc.
+#
+##################################################################
+######################### Definitions ############################
+
+# standard include with general options
+include $(RMANBASE)/Makefile.inc
+
+# all test programs
+ALLTESTS = dbmddcollidt dbmddcolloidentryt mdditest dbiteritest dbobjtest intervaltest
+
+# source files
+CPPSOURCES =
+
+# object files
+OBJS = dbmddcollidt.o dbmddcolloidentryt.o mdditest.o dbobjtest.o dbiteritest.o intervaltest.o
+
+NEEDSTL = dbmddcollidt.C dbmddcolloidentryt.C mdditest.C dbiteritest.C intervaltest.C dbobjtest.C
+
+MISCCLEAN = client.bm client.dbg client.log ir.out core
+
+NEEDEDLIBS = $(RELBLOBIF) $(RELADMINIF) $(RASLIB) $(RELCATALOGIF) $(RELMDDIF) $(RASLIB) $(CACHETAMGR) $(RELINDEXIF) $(RELBLOBIF) $(RELADMINIF)
+
+########################### Targets ##############################
+
+# make all tests
+.PHONY: test
+test: $(ALLTESTS)
+
+########################### Dependencies #########################
+
+dbmddcollidt : dbmddcollidt.o $(NEEDEDLIBS)
+dbmddcollidt.o : dbmddcollidt.C
+
+dbmddcolloidentryt : dbmddcolloidentryt.o $(NEEDEDLIBS)
+dbmddcolloidentryt.o : dbmddcolloidentryt.C
+
+mdditest: mdditest.o $(NEEDEDLIBS)
+mdditest.o: mdditest.C
+
+intervaltest: intervaltest.o $(NEEDEDLIBS)
+intervaltest.o: intervaltest.C
+
+dbobjtest: dbobjtest.o $(NEEDEDLIBS)
+dbobjtest.o: dbobjtest.C
+
+dbitertest: dbitertest.o $(NEEDEDLIBS)
+dbitertest.o: dbitertest.C
+
diff --git a/relmddif/test/dbiteritest.C b/relmddif/test/dbiteritest.C
new file mode 100644
index 0000000..dc19894
--- /dev/null
+++ b/relmddif/test/dbiteritest.C
@@ -0,0 +1,67 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include <stdlib.h>
+#include <iostream.h>
+#include <string.h>
+
+#include "adminif.hh"
+#include "databaseif.hh"
+#include "oidif.hh"
+#include "transactionif.hh"
+
+#include "alltypes.hh"
+#include "typefactory.hh"
+
+#include "dbmddcoll.hh"
+#include "dbmddcolloidentry.hh"
+#include "dbmddobj.hh"
+
+#include "raslib/rmdebug.hh"
+
+RMINITGLOBALS('C')
+int RManDebug2 = 0;
+int RManModule = 0;
+
+int
+main(int argc, char* argv[])
+ {
+ AdminIf* myAdmin;
+ DatabaseIf database;
+ TransactionIf ta;
+ RManDebug = 6;
+
+ myAdmin = AdminIf::instance();
+ database.open("RMAN");
+ ta.begin(&database);
+
+ MDDIterator<DBMDDCollOId>* mdditercoll = &MDDInit::createMDDCollOIdIterator();
+ for (i = 0; mdditercoll->not_done(); mdditercoll->advance(), i++)
+ {
+ cout << "Iter returned for " << i << ". " << mdditercoll->get_element()->getOId() << " " << mdditercoll->get_element()->getName() << " " << mdditercoll->get_element()->getCardinality() << endl;
+ for (DBIterId iter = mdditercoll->get_element()->createIterator(); iter->not_done(); iter->advance())
+ {
+ cout << "\tIter returned for MDDObject " << iter->get_element()->getOId() << endl;
+ cout << "\t\t"; iter->get_element()->printStatus();
+ }
+ }
+ }
diff --git a/relmddif/test/dbmddcollidt.C b/relmddif/test/dbmddcollidt.C
new file mode 100644
index 0000000..1dd4267
--- /dev/null
+++ b/relmddif/test/dbmddcollidt.C
@@ -0,0 +1,111 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include <stdlib.h>
+#include <iostream.h>
+#include <string.h>
+
+#include "adminif.hh"
+#include "databaseif.hh"
+#include "oidif.hh"
+#include "transactionif.hh"
+
+#include "alltypes.hh"
+#include "typefactory.hh"
+
+#include "dbmddobj.hh"
+
+#include "raslib/rmdebug.hh"
+
+RMINITGLOBALS('C')
+
+int
+main(int argc, char* argv[])
+ {
+ if (argc >= 2)
+ {
+ AdminIf* myAdmin;
+ DatabaseIf database;
+ TransactionIf ta;
+ DBMDDObj* obj = 0;
+ DBMDDColl* dbColl = 0;
+ OId* id = 0;
+ DBIterId* iter = 0;
+
+ myAdmin = AdminIf::instance();
+ database.open("RMAN");
+ ta.begin(&database);
+
+
+ switch (atoi(argv[1]))
+ {
+ default:
+ cout << "DEFAULT" << argv[0] << argv[1] << argv[2] << endl;
+ break;
+ case 1:
+ cout << "Case 1" << endl;
+ dbColl = new DBMDDCollId(argv[2]);
+ obj = new DBMDDObj();
+ dbColl->insert_element(obj);
+
+ obj = new DBMDDObj();
+ dbColl->insert_element(obj);
+
+ obj = new DBMDDObj();
+ dbColl->insert_element(obj);
+
+ for (iter = &dbColl->create_iterator(); iter->not_done(); iter->advance())
+ cout << "Iter returned: " << iter->get_element()->getOId() << endl;
+ cout << "Name of Collection: " << dbColl->getName() << endl;
+ cout << "Size of Collection: " << dbColl->cardinality() << endl;
+ cout << "OId of Collection: " << dbColl->getOId() << endl;
+ cout << "Writing DBMDDCollId" << endl;
+ dbColl->writeToDb();
+ ta.commit();
+ break;
+ case 2:
+ cout << "Case 2" << endl;
+ id = new OId(atol(argv[2]), OId::MDDCOLLOID);
+ cout << "Reading DBMDDCollId " << *id << endl;
+ dbColl = new DBMDDCollId(*id);
+ for (iter = &dbColl->create_iterator(); iter->not_done(); iter->advance())
+ cout << "Iter returned: " << iter->get_element()->getOId() << endl;
+ cout << "Name of Collection: " << dbColl->getName() << endl;
+ cout << "Size of Collection: " << dbColl->cardinality() << endl;
+ cout << "OId of Collection: " << dbColl->getOId() << endl;
+ ta.commit();
+ break;
+ case 3:
+ cout << "Case 3" << endl;
+ id = new OId(atol(argv[2]), OId::MDDCOLLOID);
+ cout << "Deleteing DBMDDCollId " << *id << endl;
+ dbColl = new DBMDDCollId(*id);
+ dbColl->deleteFromDb();
+ ta.commit();
+ break;
+ }
+ database.close();
+ }
+ else {
+ cout << "Usage: 1 write, 2 read, 3 delete" << endl << "\t1: collname" << endl << "\t2: collid" << endl << "\t3: collid" << endl;
+ }
+ }
diff --git a/relmddif/test/dbmddcolloidentryt.C b/relmddif/test/dbmddcolloidentryt.C
new file mode 100644
index 0000000..3e36de6
--- /dev/null
+++ b/relmddif/test/dbmddcolloidentryt.C
@@ -0,0 +1,101 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include "relcatalogif/alltypes.hh"
+#include "relcatalogif/typefactory.hh"
+#include "raslib/rmdebug.hh"
+#include "raslib/minterval.hh"
+
+#include <string.h>
+#include <stdlib.h>
+#include <iostream.h>
+
+#include "relblobif/blobtile.hh"
+
+#include "reladminif/adminif.hh"
+#include "reladminif/transactionif.hh"
+#include "reladminif/databaseif.hh"
+#include "reladminif/oidif.hh"
+
+#include "relmddif/dbmddcolloidentry.hh"
+#include "relmddif/dbmddcollentry.hh"
+#include "relmddif/dbmddcolloid.hh"
+#include "relmddif/dbmddcoll.hh"
+#include "relmddif/dbmddobj.hh"
+
+RMINITGLOBALS('C')
+
+int
+main(int argc, char* argv[])
+ {
+ if (argc == 0)
+ {
+ OId* t = new OId();
+ BLOBTile b(*t);
+ r_Minterval c();
+ TypeFactory::instance();
+ }
+ AdminIf* myAdmin;
+ DatabaseIf database;
+ TransactionIf ta;
+
+ myAdmin = AdminIf::instance();
+ database.open("RMAN");
+ ta.begin(&database);
+
+ if (argc >= 2)
+ {
+ DBMDDCollOIdEntry* mycoll1 = 0;
+ OId* id = 0;
+ switch(atoi(argv[1]))
+ {
+ case 1:
+ cout << "Creating Entry: " << argv[2] << endl;
+ DBMDDCollEntry::newDBMDDCollEntry(argv[2], TypeFactory::mapSetType("MySet2"));
+ cout << "aborting" << endl;
+ ta.abort();
+ break;
+ case 2:
+ cout << "Creating Entry: " << argv[2] << endl;
+ DBMDDCollEntry::newDBMDDCollEntry(argv[2], TypeFactory::mapSetType("MySet2"));
+ cout << "commiting" << endl;
+ ta.commit();
+ break;
+ case 3:
+ cout << "Reading Entry with OId: " << argv[2] << endl;
+ id = new OId(atol(argv[2]), OId::MDDCOLLOID);
+ mycoll1 = MDDInit::mapMDDCollOIdEntry(*id);
+
+ cout << "Collection Name\t:" << mycoll1->getCollName() << endl;
+ cout << "Collection OId\t:" << mycoll1->getOId() << endl;
+ cout << "Collection SetType\t:" << mycoll1->getCollType()->getTypeName() << endl;
+ cout << "aborting" << endl;
+ ta.abort();
+ break;
+ default:
+ cout << "DONT KNOW WHAT TO DO!" << endl;
+ }
+ }
+ else {
+ cout << "Usage: 1 write abort, 2 write commit, 3 read" << endl << "\t1: name" << endl << "\t2: name" << endl << "\t3: id" << endl;
+ }
+ }
diff --git a/relmddif/test/dbobjtest.C b/relmddif/test/dbobjtest.C
new file mode 100644
index 0000000..441580a
--- /dev/null
+++ b/relmddif/test/dbobjtest.C
@@ -0,0 +1,150 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include <stdlib.h>
+#include <iostream.h>
+#include <string.h>
+
+#include "adminif.hh"
+#include "databaseif.hh"
+#include "oidif.hh"
+#include "transactionif.hh"
+
+#include "alltypes.hh"
+#include "typefactory.hh"
+
+#include "dbmddcoll.hh"
+#include "dbmddcolloidentry.hh"
+#include "dbmddobj.hh"
+
+#include "raslib/rmdebug.hh"
+
+RMINITGLOBALS('C')
+int RManDebug2 = 8;
+int RManModule = 4;
+
+int
+main(int argc, char* argv[])
+ {
+ if (argc >= 2)
+ {
+ AdminIf* myAdmin;
+ DatabaseIf database;
+ TransactionIf ta;
+ RManDebug = 6;
+
+ myAdmin = AdminIf::instance();
+ database.open("RMAN");
+ ta.begin(&database);
+
+ DBIterId* iter = 0;
+ DBMDDColl* coll = 0;
+ DBMDDCollOIdEntry* entry = 0;
+ DBMDDObj* obj = 0;
+ MDDIterator<DBMDDObj>* mdditerobj = 0;
+ OId* id1 = 0;
+ OId* id2 = 0;
+ OId* id3 = 0;
+ int i = 0;
+ MDDBaseType* type = 0;
+ DBMinterval* dom = 0;
+
+ switch (atoi(argv[1]))
+ {
+ case 1:
+ cout << "Create Object with mdddtype " << atol(argv[2]) << " domainid " << atol(argv[3]) << " objIx " << atol(argv[4]) << endl;
+ id1 = new OId(atol(argv[2]), OId::MDDTYPEOID);
+ id2 = new OId(atol(argv[3]), OId::DBMINTERVALOID);
+ id3 = new OId();
+ cout << *id1 << " " << *id2 << endl;
+ type = (const MDDBaseType*)TypeFactory::mapMDDType(*id1);
+ cout << "MDDType\t: " << type->getName() << endl;
+ dom = TypeFactory::mapDBMinterval(*id2);
+ cout << "Domain\t: " << *dom << endl;
+ OId::allocateOId(*id3, OId::MDDOID);
+ cout << "MDDOId " << *id3 << endl;
+ obj = DBMDDObj::getNonInitializedMDD((char*)0, *id3);
+ cout << "Got Noninitialized at" << obj << endl;
+ obj->initialize((const MDDBaseType*)type, *dom, atol(argv[4]));
+ break;
+ case 2:
+ cout << "Creating Object Iterator" << endl;
+ mdditerobj = &MDDInit::createMDDObjectIterator();
+ for (i = 0; mdditerobj->not_done(); mdditerobj->advance(), i++)
+ {
+ cout << "Iter returned for " << i << ". " << mdditerobj->get_element()->getOId() << " with domain " << mdditerobj->get_element()->getDefinitionDomain() << endl;
+ }
+ break;
+ case 3:
+ id1 = new OId(atol(argv[2]), OId::MDDOID);
+ cout << "Delete Object with id: " << *id1 << endl;
+ MDDInit::deleteMDDObject(*id1);
+ cout << "Deleted" << endl;
+ mdditerobj = &MDDInit::createMDDObjectIterator();
+ for (i = 0; mdditerobj->not_done(); mdditerobj->advance(), i++)
+ {
+ cout << "Iter returned for " << i << ". " << mdditerobj->get_element()->getOId() << " with domain " << mdditerobj->get_element()->getDefinitionDomain() << endl;
+ }
+ cout << "DONE " << endl;
+ break;
+ case 4:
+ id1 = new OId(atol(argv[2]), OId::MDDOID);
+ id2 = new OId(atol(argv[3]), OId::MDDCOLLOID);
+ cout << "Insert Object with id: " << *id1 << " into collection with id: " << *id2 << endl;
+ coll = MDDInit::mapMDDCollection(*id2);
+ coll->insert(MDDInit::mapMDDObject(*id1));
+ for (iter = &coll->createIterator(); iter->not_done(); iter->advance(), i++)
+ cout << "Iter returned for " << i << ". " << iter->get_element()->getOId() << endl;
+ break;
+ case 5:
+ id1 = new OId(atol(argv[2]), OId::MDDOID);
+ id2 = new OId(atol(argv[3]), OId::MDDCOLLOID);
+ cout << "Remove Object with id " << *id1 << " from collection with id: " << *id2 << endl;
+ coll = MDDInit::mapMDDCollection(*id2);
+ coll->remove(MDDInit::mapMDDObject(*id1));
+ for (iter = &coll->createIterator(); iter->not_done(); iter->advance(), i++)
+ cout << "Iter returned for " << i << ". " << iter->get_element()->getOId() << endl;
+ }
+
+ if (argv[5])
+ {
+ if ((strcmp(argv[5],"commit") == 0))
+ {
+ cout << "commiting" << endl;
+ ta.commit();
+ }
+ }
+ cout << "aborting" << endl;
+ ta.abort();
+ database.close();
+ }
+ else {
+ cout << "USAGE:" << endl;
+ cout << "\t1: create object" << endl << "\t\tmddtypeid domainid objix" << endl;
+ cout << "\t2: object iterator" << endl << "\t\t" << endl;
+ cout << "\t3: delete object" << endl << "\t\tobjectid" << endl;
+ cout << "\t4: insert object in collection" << endl << "\t\tobjectid collectionid" << endl;
+ cout << "\t5: remove object from collection" << endl << "\t\tobjectid collectionid" << endl;
+ cout << "5th argument must be abort/commit" << endl;
+ }
+ }
+
diff --git a/relmddif/test/intervaltest.C b/relmddif/test/intervaltest.C
new file mode 100644
index 0000000..333b681
--- /dev/null
+++ b/relmddif/test/intervaltest.C
@@ -0,0 +1,120 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include <stdlib.h>
+#include <iostream.h>
+#include <string.h>
+
+#include "adminif.hh"
+#include "databaseif.hh"
+#include "oidif.hh"
+#include "transactionif.hh"
+
+#include "alltypes.hh"
+#include "typefactory.hh"
+
+#include "dbmddcoll.hh"
+#include "dbmddcolloidentry.hh"
+#include "dbmddobj.hh"
+
+#include "dbminterval.hh"
+#include "raslib/rmdebug.hh"
+int RManDebug2 = 8;
+int RManModule = 3;
+RMINITGLOBALS('C')
+
+int
+main(int argc, char* argv[])
+ {
+ if (argc >= 2)
+ {
+
+ AdminIf* myAdmin;
+ DatabaseIf database;
+ TransactionIf ta;
+
+ myAdmin = AdminIf::instance();
+ database.open("RMAN");
+ ta.begin(&database);
+
+ cout << endl << endl << endl;
+
+ DBMinterval* in = 0;
+ OId* oi = 0;
+ switch (atoi(argv[1]))
+ {
+ case 1://insert
+ in = new DBMinterval(argv[2]);
+ cout << "built interval with:" << argv[2] << endl;
+ in->setPersistent(1);
+ cout << "OId of interval:" << in->getOId() << endl;
+ cout << "Minterval:" << in->get_string_representation() << endl;
+ delete in;
+ cout << "Domain deleted" << endl;
+ break;
+ case 2://update
+ oi = new OId(atol(argv[2]),OId::DBMINTERVALOID);
+ cout << "OId of interval:" << *oi << endl;
+ in = new DBMinterval(*oi);
+ cout << "Minterval:" << in->get_string_representation() << endl;
+ (*in)[in->dimension() - 2].set_low(1L);
+ (*in)[in->dimension() - 2].set_high(3L);
+ cout << "Minterval:" << in->get_string_representation() << endl;
+ in->setModified();
+ delete in;
+ cout << "Minterval deleted" << endl;
+ break;
+ case 3://delete
+ oi = new OId(atol(argv[2]),OId::DBMINTERVALOID);
+ cout << "OId of interval:" << *oi << endl;
+ in = new DBMinterval(*oi);
+ cout << "Minterval:" << in->get_string_representation() << endl;
+ in->setPersistent(0);
+ delete in;
+ cout << "Minterval deleted" << endl;
+ break;
+ case 4://read
+ oi = new OId(atol(argv[2]),OId::DBMINTERVALOID);
+ cout << "OId of interval:" << *oi << endl;
+ in = new DBMinterval(*oi);
+ cout << "Minterval:" << in->get_string_representation() << endl;
+ delete in;
+ cout << "Minterval deleted" << endl;
+ break;
+ default:
+ cout << "Don´t know what to do!" << endl;
+ break;
+ }
+ cout << endl << endl << endl;
+
+ if (argv[3])
+ {
+ if (strcmp(argv[3], "commit") == 0)
+ ta.commit();
+ }
+ ta.abort();
+ database.close();
+ }
+ else {
+ cout << "Usage:\n\t1 insert domain\n\t2 update oid\n\t3 delete oid\n\t4 read oid\n\t\tcommit/abort" << endl;
+ }
+ }
diff --git a/relmddif/test/mdditest.C b/relmddif/test/mdditest.C
new file mode 100644
index 0000000..c72252b
--- /dev/null
+++ b/relmddif/test/mdditest.C
@@ -0,0 +1,312 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include <stdlib.h>
+#include <iostream.h>
+#include <string.h>
+
+#include "adminif.hh"
+#include "databaseif.hh"
+#include "oidif.hh"
+#include "transactionif.hh"
+
+#include "alltypes.hh"
+#include "typefactory.hh"
+
+#include "dbmddcoll.hh"
+#include "dbmddcolloidentry.hh"
+#include "dbmddobj.hh"
+
+#include "dbdirix.hh"
+
+#include "raslib/rmdebug.hh"
+
+RMINITGLOBALS('C')
+int RManDebug2 = 8;
+int RManModule = 5;
+
+int
+main(int argc, char* argv[])
+ {
+ if (argc >= 2)
+ {
+ AdminIf* myAdmin;
+ DatabaseIf database;
+ TransactionIf ta;
+ RManDebug = 6;
+
+ myAdmin = AdminIf::instance();
+ database.open("RASBASE");
+ ta.begin(&database);
+
+ DBMDDColl* coll = 0;
+ MDDSet* set = 0;
+ DBMDDCollOIdEntry* entry = 0;
+ DBMDDObjId obj = 0;
+ DBIterId iter = 0;
+ MDDIterator<DBMDDCollOIdEntry>* mdditer = 0;
+ MDDIterator<DBMDDObj>* mdditerobj = 0;
+ MDDIterator<MDDSet>* mdditercoll = 0;
+ DBMDDObjIxId ix1 = 0;
+ DBMDDObjIxId ix2 = 0;
+ DBMDDObjIxId ix3 = 0;
+ DBMDDObjIxId ix4 = 0;
+ DBDirIx* dirix = 0;
+ OId* id2 = 0;
+ OId* id = 0;
+ int i = 0;
+ OId o;
+ StructType st((char*)"StructType6", 2);
+ st.addElement("_ase6", "Bool");
+ st.addElement("_ase7", "Octet");
+ st.addElement("_ase8", "Float");
+ SetType settype((char*)"MySet3", &MDDDomainType("MyMDDDomainType", &st, r_Minterval("[1:200,*:300,20:*,*:*,20:133]")));;
+ SetType* s = 0;
+ cout << endl << endl << endl;
+
+ switch (atoi(argv[1]))
+ {
+ case 1:
+ cout << "Creating Root:" << argv[2] << endl;
+ coll = DBMDDColl::createRoot(argv[2], &database);
+ cout << "Creating Entry:" << argv[3] << endl;
+ s = TypeFactory::mapSetType("MySet3");
+ if (!s)
+ {
+
+ s = TypeFactory::addSetType(&settype);
+ }
+ DBMDDCollOIdEntry::newDBMDDCollEntry(argv[3], TypeFactory::mapSetType("MySet3"));
+ cout << "Getting Entry " << argv[3] << endl;
+ entry = MDDInit::mapMDDCollOIdEntry(argv[3]);
+ cout << "EntryName: " << entry->getCollName() << endl;
+ cout << "Inserting Objects" << endl;
+ id = new OId();
+ cout << endl;
+
+ OId::allocateOId(*id, OId::MDDOID);
+ dirix = new DBDirIx(1, DBMDDObjIx::DIRIX);
+ cout << "DBDIRIX AT " << dirix << endl;
+ ix1 = dirix;
+ cout << "DBREF IS_NULL " << ix1.is_null() << endl;
+ cout << "ALLOCATED OID " << *id << endl;
+ obj = DBMDDObj::getNonInitializedMDD(0, *id);
+ cout << "INITIALIZING" << endl;
+ obj->initialize((const MDDBaseType*)TypeFactory::mapMDDType("MyMDDDomainType"), *((MDDDomainType*)TypeFactory::mapMDDType("MyMDDDomainType"))->getDomain(), ix1);
+ cout << "INSERTING" << endl;
+ coll->insert(obj);
+ cout << endl << endl;
+
+ OId::allocateOId(*id, OId::MDDOID);
+ ix2 = new DBDirIx(1, DBMDDObjIx::DIRIX);
+ cout << "ALLOCATED OID " << *id << endl;
+ obj = DBMDDObj::getNonInitializedMDD(0, *id);
+ cout << "INITIALIZING" << endl;
+ obj->initialize((const MDDBaseType*)TypeFactory::mapMDDType("MyMDDDomainType"), *((MDDDomainType*)TypeFactory::mapMDDType("MyMDDDomainType"))->getDomain(), ix2);
+ cout << "INSERTING" << endl;
+ coll->insert(obj);
+ cout << endl << endl;
+
+ OId::allocateOId(*id, OId::MDDOID);
+ ix3 = new DBDirIx(1, DBMDDObjIx::DIRIX);
+ cout << "ALLOCATED OID " << *id << endl;
+ obj = DBMDDObj::getNonInitializedMDD(0, *id);
+ cout << "INITIALIZING" << endl;
+ obj->initialize((const MDDBaseType*)TypeFactory::mapMDDType("MyMDDDomainType"), *((MDDDomainType*)TypeFactory::mapMDDType("MyMDDDomainType"))->getDomain(), ix3);
+ cout << "INSERTING" << endl;
+ coll->insert(obj);
+ cout << endl << endl;
+
+ for (iter = coll->createNewIterator(); iter->not_done(); iter->advance())
+ {
+ cout << "Iter returned for oid " << iter->get_element()->getOId() << " domain at " << &(iter->get_element()->getDefinitionDomain());
+ iter->get_element()->printStatus();
+ }
+ cout << "Size of Collection: " << coll->getCardinality() << endl;
+ coll->getOId(&o);
+ cout << "OId of Collection: " << o << endl;
+ break;
+ case 2:
+ cout << "Getting Root:" << argv[2] << endl;
+ coll = DBMDDColl::getRoot(argv[2]);
+ i = 0;
+ for (iter = coll->createNewIterator(); iter->not_done(); iter->advance(), i++)
+ cout << "Iter returned for " << i << ". " << iter->get_element()->getOId() << endl;
+ cout << "Size of Collection: " << coll->getCardinality() << endl;
+ coll->getOId(&o);
+ cout << "OId of Collection: " << o << endl;
+ break;
+ case 3:
+ cout << "Creating Object Iterator" << endl;
+ mdditerobj = &MDDInit::createMDDObjectIterator();
+ for (i = 0; mdditerobj->not_done(); mdditerobj->advance(), i++)
+ {
+ cout << "Iter returned for " << i << ". " << mdditerobj->get_element()->getOId() << endl;
+ }
+ break;
+ case 4:
+ cout << "Creating Entry Iterator" << endl;
+ mdditer = &MDDInit::createMDDCollOIdEntryIterator();
+ for (i = 0; mdditer->not_done(); mdditer->advance(), i++)
+ {
+ cout << "Iter returned for " << i << ". " << mdditer->get_element()->getOId() << " " << mdditer->get_element()->getCollName() << " " << mdditer->get_element()->getCollType()->getTypeName() << endl;
+ }
+ break;
+ case 5:
+ cout << "Creating Coll Iterator" << endl;
+ mdditercoll = &MDDInit::createMDDSetIterator();
+ for (i = 0; mdditercoll->not_done(); mdditercoll->advance(), i++)
+ {
+ mdditercoll->get_element()->getOId(&o);
+ cout << "Iter returned for " << i << ". " << o << " " << mdditercoll->get_element()->getName() << " " << mdditercoll->get_element()->getCardinality() << endl;
+ }
+ break;
+ case 6:
+ id = new OId(atol(argv[2]), OId::MDDCOLLOID);
+ cout << "Delete Coll with id: " << *id << endl;
+ MDDInit::deleteMDDSet(*id);
+ cout << "Deleted" << endl;
+ mdditercoll = &MDDInit::createMDDSetIterator();
+ for (i = 0; mdditercoll->not_done(); mdditercoll->advance(), i++)
+ {
+ cout << "Iter returned for " << i << ". " << mdditercoll->get_element()->getOId() << " " << mdditercoll->get_element()->getName() << " " << mdditercoll->get_element()->getCardinality() << endl;
+ }
+ break;
+ case 7:
+ id = new OId(atol(argv[2]), OId::MDDCOLLOID);
+ cout << "Delete Coll Entry with id: " << *id << endl;
+ MDDInit::deleteMDDCollOIdEntry(*id);
+ cout << "Deleted" << endl;
+ mdditer = &MDDInit::createMDDCollOIdEntryIterator();
+ for (i = 0; mdditer->not_done(); mdditer->advance(), i++)
+ {
+ cout << "Iter returned for " << i << ":" << endl;
+ cout << "\t" << mdditer->get_element()->getOId() << endl;
+ cout << "\t" << mdditer->get_element()->getCollName() << endl;
+ cout << "\t" << mdditer->get_element()->getCollType()->getTypeName() << endl;
+ }
+ cout << "Done!" << endl;
+ break;
+ case 8:
+ id = new OId(atol(argv[2]), OId::MDDOID);
+ cout << "Delete Object with id: " << *id << endl;
+ MDDInit::deleteMDDObject(*id);
+ cout << "Deleted" << endl;
+ mdditerobj = &MDDInit::createMDDObjectIterator();
+ for (i = 0; mdditerobj->not_done(); mdditerobj->advance(), i++)
+ {
+ cout << "Iter returned for " << i << ". " << mdditerobj->get_element()->getOId() << endl;
+ }
+ cout << "DONE! " << endl;
+ break;
+ case 9:
+ id = new OId(atol(argv[2]), OId::MDDOID);
+ id2 = new OId(atol(argv[3]), OId::MDDCOLLOID);
+ cout << "Insert Object with id: " << *id << " into collection with id: " << *id2 << endl;
+ set = MDDInit::mapMDDSet(*id2);
+ set->insert(MDDInit::mapMDDObject(*id));
+ for (iter = set->createNewIterator(); iter->not_done(); iter->advance(), i++)
+ cout << "Iter returned for " << i << ". " << iter->get_element()->getOId() << endl;
+ break;
+ case 10:
+ cout << "Creating Root:" << argv[2] << endl;
+ coll = DBMDDColl::createRoot(argv[2], &database);
+ break;
+ case 11:
+ cout << "Creating Entry:" << argv[2] << endl;
+ DBMDDCollOIdEntry::newDBMDDCollEntry(argv[2], TypeFactory::mapSetType("MySet3"));
+ cout << "Getting Entry " << argv[2] << endl;
+ entry = MDDInit::mapMDDCollOIdEntry(argv[2]);
+ cout << "EntryName: " << entry->getCollName() << endl;
+ break;
+ case 12:
+ id = new OId(atol(argv[2]), OId::MDDOID);
+ id2 = new OId(atol(argv[3]), OId::MDDCOLLOID);
+ cout << "Remove Object with id " << *id << " from collection with id: " << *id2 << endl;
+ set = MDDInit::mapMDDSet(*id2);
+ set->remove(MDDInit::mapMDDObject(*id));
+ for (iter = set->createNewIterator(); iter->not_done(); iter->advance(), i++)
+ cout << "Iter returned for " << i << ". " << iter->get_element()->getOId() << endl;
+ break;
+ case 13:
+ cout << "Create new MDDObject" << endl;
+ id = new OId();
+ ix1 = new DBDirIx(1, DBDirIx::DIRIX);
+ cout << endl;
+
+ OId::allocateOId(*id, OId::MDDOID);
+ cout << "ALLOCATED OID " << *id << endl;
+ obj = DBMDDObj::getNonInitializedMDD(0, *id);
+ cout << "INITIALIZING" << endl;
+ obj->initialize((const MDDBaseType*)TypeFactory::mapMDDType("MyMDDDomainType"), *((MDDDomainType*)TypeFactory::mapMDDType("MyMDDDomainType"))->getDomain(), ix1);
+ cout << endl << endl;
+ break;
+ }
+ if (argv[4])
+ if ((strcmp(argv[4],"dbiter") == 0))
+ {
+ cout << "DIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII" << endl;
+ MDDIterator<MDDSet>* mdditercoll = &MDDInit::createMDDSetIterator();
+ for (i = 0; mdditercoll->not_done(); mdditercoll->advance(), i++)
+ {
+ mdditercoll->get_element()->getOId(&o);
+ cout << "Iter returned for " << i << ". " << o << " " << " " << mdditercoll->get_element()->getCardinality() << endl;
+ for (DBIter* iter = mdditercoll->get_element()->createNewIterator(); iter->not_done(); iter->advance())
+ {
+ cout << "\tIter returned for MDDObject " << iter->get_element()->getOId() << endl;
+ cout << "\t\t"; iter->get_element()->printStatus();
+ }
+ }
+ }
+ cout << endl << endl << endl;
+
+ if (argv[4])
+ {
+ if ((strcmp(argv[4],"commit") == 0))
+ {
+ cout << "commiting" << endl;
+ ta.commit();
+ }
+ }
+ else {
+ cout << "aborting" << endl;
+ ta.abort();
+ }
+ database.close();
+ }
+ else {
+ cout << "USAGE:" << endl;
+ cout << "\t1: create Coll and Entry" << endl << "\t\t collectionname entryname" << endl;
+ cout << "\t2: getRoot" << endl << "\t\trootname" << endl;
+ cout << "\t3: mddobject iterator" << endl << "\t\t" << endl;
+ cout << "\t4: entry iterator" << endl << "\t\t" << endl;
+ cout << "\t5: collection iterator" << endl << "\t\t" << endl;
+ cout << "\t6: delete collection" << endl << "\t\tcollectionoid" << endl;
+ cout << "\t7: delete entry" << endl << "\t\tentryoid" << endl;
+ cout << "\t8: delete mddobject" << endl << "\t\tmddobjectoid" << endl;
+ cout << "\t9: insert mddobject into collection" << endl << "\t\tmddobjectoid collectionoid" << endl;
+ cout << "\t10: create collection" << endl << "\t\tcollectionname" << endl;
+ cout << "\t11: create entry" << endl << "\t\tentryname" << endl;
+ cout << "\t12: remove mddobject from collection" << endl << "\t\tmddobjectoid collectionoid" << endl;
+ cout << "\t13: create mddobject" << endl << "\t\t" << endl;
+ }
+ }
diff --git a/relstorageif/Makefile.am b/relstorageif/Makefile.am
new file mode 100644
index 0000000..0ed7565
--- /dev/null
+++ b/relstorageif/Makefile.am
@@ -0,0 +1,50 @@
+# -*-Makefile-*- (for Emacs)
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+#
+# MAKEFILE FOR:
+# indexif
+#
+# COMMENTS:
+#
+##################################################################
+
+AM_CXXFLAGS=@BASEDBCXXFLAGS@
+AM_LDFLAGS=@BASEDBLDFLAGS@
+
+.SUFFIXES= .@EMBEDDEDSQLEXT@
+.@EMBEDDEDSQLEXT@.@EMBEDDEDSQLOUT@:
+ $(EMBEDDEDSQLPRECOMPILER) $@ $<
+
+
+noinst_LIBRARIES=librelstorageif.a
+librelstorageif_a_SOURCES= dbstoragelayout.hh storageid.hh empty.cc
+EXTRA_librelstorageif_a_SOURCES= dbstoragelayout.pgc
+librelstorageif_a_LIBADD= dbstoragelayout.$(OBJEXT)
+librelstorageif_a_DEPENDENCIES= dbstoragelayout.$(OBJEXT)
+
+BUILT_SOURCES= dbstoragelayout.@EMBEDDEDSQLOUT@
+
+
+CLEANFILES= dbstoragelayout.@EMBEDDEDSQLOUT@ \
+ client.bm client.dbg client.log ir.out
+
diff --git a/relstorageif/dbstoragelayout.hh b/relstorageif/dbstoragelayout.hh
new file mode 100644
index 0000000..c18beed
--- /dev/null
+++ b/relstorageif/dbstoragelayout.hh
@@ -0,0 +1,214 @@
+#ifndef _DBSTORAGELAYOUT_HH_
+#define _DBSTORAGELAYOUT_HH_
+
+#include <string>
+#include <vector>
+#include "relcatalogif/dbminterval.hh"
+#include "reladminif/dbobject.hh"
+#include "reladminif/dbref.hh"
+
+class DBStorageLayout;
+template<class T> class DBRef;
+typedef DBRef<DBStorageLayout> DBStorageLayoutId;
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+/****************************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ****************************************************************************/
+
+//@ManMemo: Module: {\bf relstorageif}
+/*@Doc:
+ Each instance of the {\tt DBStorageLayout} class describes a physical
+ storage layout for an MDD object or collection.
+ Every storage parameter which is not defined using the proper set* methods will result in a default value to be returned. the supports* methods will tell if the value is a default value defined at instantiation time through the static storagemgr/StorageLayout attributes or an explicitly defined value.
+ For information on the meaning of these attributes refere to storagemgr/storagelayout
+*/
+
+class DBStorageLayout : public DBObject
+ {
+ public:
+ //@Man: Creation
+ //@{
+
+ /// Construct object that uses system defaults.
+ DBStorageLayout();
+
+ //@}
+
+ void printStatus(unsigned int level = 0,std::ostream& stream = std::cout) const;
+
+ //@Man: check operations
+ //@{
+ bool supportsTileSize() const;
+
+ bool supportsPCTMin() const;
+
+ bool supportsPCTMax() const;
+
+ bool supportsIndexSize() const;
+
+ bool supportsIndexType() const;
+
+ bool supportsTilingScheme() const;
+
+ //is checked by OId::INVALID on tilingConfiguration
+ bool supportsTileConfiguration() const;
+
+ bool supportsDataFormat() const;
+ //@}
+
+ //@Man: Get operations
+ //@{
+
+ r_Bytes getPCTMin() const;
+
+ r_Bytes getPCTMax() const;
+
+ unsigned int getIndexSize() const;
+
+ r_Index_Type getIndexType() const;
+
+ r_Tiling_Scheme getTilingScheme() const;
+
+ r_Bytes getTileSize() const;
+
+ r_Minterval getTileConfiguration() const;
+
+ r_Data_Format getDataFormat() const;
+
+ //@}
+
+ //@Man: Set operations
+ //@{
+
+ void setPCTMin(r_Bytes bytes);
+
+ void setPCTMax(r_Bytes bytes);
+
+ void setIndexSize(unsigned int entries);
+
+ void setIndexType(r_Index_Type it);
+
+ void setTilingScheme(r_Tiling_Scheme ts);
+
+ void setTileSize(r_Bytes ts);
+
+ void setTileConfiguration(const r_Minterval& tc);
+
+ void setDataFormat(r_Data_Format df);
+
+ //@}
+
+
+ //@Man: Destruction
+ //@{
+ ///
+ ~DBStorageLayout();
+ //@}
+
+ protected:
+ DBStorageLayout(const OId& id) throw (r_Error);
+
+ friend class ObjectBroker;
+
+ //@Man: Operations
+ //@{
+
+ virtual void readFromDb() throw (r_Error);
+
+ virtual void insertInDb() throw (r_Error);
+
+ virtual void deleteFromDb() throw (r_Error);
+
+ virtual void updateInDb() throw (r_Error);
+
+
+ //@}
+
+ private:
+
+ //@Man: Actual Parameters:
+ //@{
+
+ /// Name of the storage layout represented by this object
+ // char* stName;
+
+ //@Man: Index Structure:
+ //@{
+ /// Which type of index should be used
+ r_Index_Type indexType;
+
+ unsigned int indexSize;
+ //@}
+
+ //@Man: Tiling:
+ //@{
+ /// How the object should be tiled
+ r_Tiling_Scheme tilingScheme;
+
+ r_Bytes pctMin;
+
+ r_Bytes pctMax;
+
+ /// Tile size in bytes.
+ r_Bytes tileSize;
+
+ /// Default configuration of the tiles.
+ DBMintervalId tileConfiguration;
+ /**
+ Describe the shape of the tiles. For instance, [2:4,0:1,0:2].
+ The tiling will start at the point [2,0,0].
+ Tiles will be appended from there according to the tileConfig.
+ */
+ //@}
+
+ //@Man: DataFormat
+ //@{
+ /// How the tiles of the object should be compressed
+ r_Data_Format dataFormat;
+ //@}
+
+ //@}
+ bool _supportsTileSize;
+
+ bool _supportsPCTMin;
+
+ bool _supportsPCTMax;
+
+ bool _supportsIndexSize;
+
+ bool _supportsIndexType;
+
+ bool _supportsTiling;
+
+ bool _supportsDataFormat;
+
+ bool _supportsTileConfiguration;
+ };
+
+#endif
diff --git a/relstorageif/dbstoragelayout.pgc b/relstorageif/dbstoragelayout.pgc
new file mode 100644
index 0000000..f7b8910
--- /dev/null
+++ b/relstorageif/dbstoragelayout.pgc
@@ -0,0 +1,646 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/****************************************************************************
+ *
+ *
+ * PURPOSE:
+ * Code with embedded SQL for PostgreSQL DBMS
+ *
+ *
+ * COMMENTS:
+ * none
+ *
+ ****************************************************************************/
+
+#include "reladminif/sqlerror.hh"
+#include "raslib/rmdebug.hh"
+#include "reladminif/externs.h"
+#include "dbstoragelayout.hh"
+#include "storagemgr/sstoragelayout.hh"
+#include "reladminif/objectbroker.hh"
+
+DBStorageLayout::DBStorageLayout()
+ : DBObject(),
+ indexType(StorageLayout::DefaultIndexType),
+ indexSize(StorageLayout::DefaultIndexSize),
+ tilingScheme(StorageLayout::DefaultTilingScheme),
+ tileSize(StorageLayout::DefaultTileSize),
+ tileConfiguration(new DBMinterval()),
+ dataFormat(StorageLayout::DefaultDataFormat),
+ pctMin(StorageLayout::DefaultMinimalTileSize),
+ pctMax(StorageLayout::DefaultPCTMax),
+ _supportsTileSize(false),
+ _supportsPCTMin(false),
+ _supportsPCTMax(false),
+ _supportsIndexSize(false),
+ _supportsIndexType(false),
+ _supportsTiling(false),
+ _supportsTileConfiguration(false),
+ _supportsDataFormat(false)
+{
+ objecttype = OId::STORAGEOID;
+}
+
+DBStorageLayout::DBStorageLayout(const OId& id) throw(r_Error)
+ : DBObject(id),
+ indexType(StorageLayout::DefaultIndexType),
+ indexSize(StorageLayout::DefaultIndexSize),
+ tilingScheme(StorageLayout::DefaultTilingScheme),
+ tileSize(StorageLayout::DefaultTileSize),
+ tileConfiguration(new DBMinterval()),
+ dataFormat(StorageLayout::DefaultDataFormat),
+ pctMin(StorageLayout::DefaultMinimalTileSize),
+ pctMax(StorageLayout::DefaultPCTMax),
+ _supportsTileSize(false),
+ _supportsPCTMin(false),
+ _supportsPCTMax(false),
+ _supportsIndexSize(false),
+ _supportsIndexType(false),
+ _supportsTiling(false),
+ _supportsTileConfiguration(false),
+ _supportsDataFormat(false)
+{
+ objecttype = OId::STORAGEOID;
+ readFromDb();
+}
+
+void
+DBStorageLayout::printStatus(unsigned int level, std::ostream& stream) const
+{
+ char* indent = new char[level*2 +1];
+ for (int j = 0; j < level*2 ; j++)
+ indent[j] = ' ';
+ indent[level*2] = '\0';
+
+ stream << indent;
+ stream << "DBStorageLayout:" << endl;
+ if (supportsTileSize())
+ stream << "\tTileSize\t\t\t:";
+ else
+ stream << "\tTileSize (Def.)\t\t\t:";
+ stream << getTileSize() << endl;
+ stream << indent;
+ if (supportsPCTMin())
+ stream << "\tPCTMin\t\t:";
+ else
+ stream << "\tPCTMin (Def.)\t\t\t:";
+ stream << getPCTMin() << endl;
+ stream << indent;
+ if (supportsPCTMax())
+ stream << "\tPCTMax\t\t:";
+ else
+ stream << "\tPCTMax (Def.)\t\t\t:";
+ stream << getPCTMax() << endl;
+ stream << indent;
+ if (supportsIndexSize())
+ stream << "\tIndexSize\t\t:";
+ else
+ stream << "\tIndexSize (Def.)\t\t:";
+ stream << getIndexSize() << endl;
+ stream << indent;
+ if (supportsIndexType())
+ stream << "\tIndexType\t\t\t:";
+ else
+ stream << "\tIndexType (Def.)\t\t:";
+ stream << getIndexType() << endl;
+ stream << indent;
+ if (supportsTilingScheme())
+ stream << "\tTilingScheme\t\t\t:";
+ else
+ stream << "\tTilingScheme (Def.)\t\t:";
+ stream << getTilingScheme() << endl;
+ stream << indent;
+ if (supportsTileConfiguration())
+ stream << "\tTileConfiguration\t\t:";
+ else
+ stream << "\tTileConfiguration (Def.)\t:";
+ stream << getTileConfiguration() << endl;
+ stream << indent;
+ if (supportsDataFormat())
+ stream << "\tDataFormat\t\t\t:";
+ else
+ stream << "\tDataFormat (Def.)\t\t:";
+ stream << getDataFormat() << endl;
+ stream << indent;
+
+ delete[] indent;
+}
+
+bool
+DBStorageLayout::supportsIndexType() const
+{
+ return _supportsIndexType;
+}
+
+bool
+DBStorageLayout::supportsDataFormat() const
+{
+ return _supportsDataFormat;
+}
+
+bool
+DBStorageLayout::supportsTilingScheme() const
+{
+ return _supportsTiling;
+}
+
+bool
+DBStorageLayout::supportsTileSize() const
+{
+ return _supportsTileSize;
+}
+
+bool
+DBStorageLayout::supportsIndexSize() const
+{
+ return _supportsIndexSize;
+}
+
+bool
+DBStorageLayout::supportsPCTMin() const
+{
+ return _supportsPCTMin;
+}
+
+bool
+DBStorageLayout::supportsPCTMax() const
+{
+ return _supportsPCTMax;
+}
+
+bool
+DBStorageLayout::supportsTileConfiguration() const
+{
+ return _supportsTileConfiguration;
+}
+
+r_Index_Type
+DBStorageLayout::getIndexType() const
+{
+ return indexType;
+}
+
+r_Data_Format
+DBStorageLayout::getDataFormat() const
+{
+ return dataFormat;
+}
+
+r_Tiling_Scheme
+DBStorageLayout::getTilingScheme() const
+{
+ return tilingScheme;
+}
+
+r_Bytes
+DBStorageLayout::getTileSize() const
+{
+ return tileSize;
+}
+
+unsigned int
+DBStorageLayout::getIndexSize() const
+{
+ return indexSize;
+}
+
+r_Bytes
+DBStorageLayout::getPCTMin() const
+{
+ return pctMin;
+}
+
+r_Bytes
+DBStorageLayout::getPCTMax() const
+{
+ return pctMax;
+}
+
+r_Minterval
+DBStorageLayout::getTileConfiguration() const
+{
+ return *tileConfiguration;
+}
+
+void
+DBStorageLayout::setIndexType(r_Index_Type it)
+{
+ _supportsIndexType = true;
+ indexType = it;
+ setModified();
+}
+
+void
+DBStorageLayout::setDataFormat(r_Data_Format cs)
+{
+ _supportsDataFormat = true;
+ dataFormat = cs;
+ setModified();
+}
+
+void
+DBStorageLayout::setTilingScheme(r_Tiling_Scheme ts)
+{
+ _supportsTiling = true;
+ tilingScheme = ts;
+ setModified();
+}
+
+void
+DBStorageLayout::setTileSize(r_Bytes tsize)
+{
+ _supportsTileSize = true;
+ tileSize = tsize;
+ setModified();
+}
+
+void
+DBStorageLayout::setTileConfiguration(const r_Minterval& tc)
+{
+ _supportsTileConfiguration = true;
+ *tileConfiguration = tc;
+ setModified();
+}
+
+void
+DBStorageLayout::setIndexSize(unsigned int newindexSize)
+{
+ _supportsIndexSize = true;
+ indexSize = newindexSize;
+ setModified();
+}
+
+void
+DBStorageLayout::setPCTMin(r_Bytes newpctMin)
+{
+ _supportsPCTMin = true;
+ pctMin = newpctMin;
+ setModified();
+}
+
+void
+DBStorageLayout::setPCTMax(r_Bytes newpctMax)
+{
+ _supportsPCTMax = true;
+ pctMax = newpctMax;
+ setModified();
+}
+
+DBStorageLayout::~DBStorageLayout()
+{
+ validate();
+}
+
+/*
+TABLE RAS_STORAGE (
+ StorageId INTEGER NOT NULL UNIQUE,
+ DomainId INTEGER,
+ TileSize INTEGER,
+ PCTMin INTEGER,
+ PCTMax INTEGER,
+ IndexSize INTEGER,
+ IndexType SMALLINT,
+ TilingScheme SMALLINT,
+ DataFormat SMALLINT
+ )
+*/
+
+void
+DBStorageLayout::readFromDb() throw(r_Error)
+{
+ RMDBGENTER(5, RMDebug::module_storageif, "DBStorageLayout", "readFromDb() " << myOId);
+ EXEC SQL BEGIN DECLARE SECTION;
+ long storageid1;
+ long domainid1;
+ short domainid1ind;
+ long tilesize1;
+ short tilesize1ind;
+ long pctmin1;
+ short pctmin1ind;
+ long pctmax1;
+ short pctmax1ind;
+ long indexsize1;
+ short indexsize1ind;
+ short indextype1;
+ short indextype1ind;
+ short tilingscheme1;
+ short tilingscheme1ind;
+ short dataformat1;
+ short dataformat1ind;
+ EXEC SQL END DECLARE SECTION;
+
+ storageid1 = myOId.getCounter();
+ EXEC SQL SELECT
+ DomainId,
+ TileSize,
+ PCTMin,
+ PCTMax,
+ IndexType,
+ TilingScheme,
+ DataFormat,
+ IndexSize
+ INTO
+ :domainid1 INDICATOR :domainid1ind,
+ :tilesize1 INDICATOR :tilesize1ind,
+ :pctmin1 INDICATOR :pctmin1ind,
+ :pctmax1 INDICATOR :pctmax1ind,
+ :indextype1 INDICATOR :indextype1ind,
+ :tilingscheme1 INDICATOR :tilingscheme1ind,
+ :dataformat1 INDICATOR :dataformat1ind,
+ :indexsize1 INDICATOR :indexsize1ind
+ FROM
+ RAS_STORAGE
+ WHERE
+ StorageId = :storageid1;
+ if (SQLCODE != SQLOK)
+ {
+ check("DBStorageLayout::readFromDb() SELECT FROM RAS_STORAGE");
+ generateException();
+ }
+
+ if (domainid1ind)
+ {
+ _supportsTileConfiguration = false;
+ //((DBMinterval)*tileConfiguration) = StorageLayout::DefaultTileConfiguration;
+ *tileConfiguration = StorageLayout::DefaultTileConfiguration;
+ }
+ else
+ {
+ _supportsTileConfiguration = true;
+ tileConfiguration = OId(domainid1, OId::DBMINTERVALOID);
+ }
+
+ if (indexsize1ind)
+ {
+ _supportsIndexSize = false;
+ indexSize = StorageLayout::DefaultIndexSize;
+ }
+ else
+ {
+ _supportsIndexSize = true;
+ indexSize = indexsize1;
+ }
+
+ if (tilesize1ind)
+ {
+ _supportsTileSize = false;
+ tileSize = StorageLayout::DefaultTileSize;
+ }
+ else
+ {
+ _supportsTileSize = true;
+ tileSize = tilesize1;
+ }
+
+ if (pctmin1ind)
+ {
+ _supportsPCTMin = false;
+ pctMin = StorageLayout::DefaultMinimalTileSize;
+ }
+ else
+ {
+ _supportsPCTMin = true;
+ pctMin = pctmin1;
+ }
+
+ if (pctmax1ind)
+ {
+ _supportsPCTMax = false;
+ pctMax = StorageLayout::DefaultPCTMax;
+ }
+ else
+ {
+ _supportsPCTMax = true;
+ pctMax = pctmax1;
+ }
+
+ if (indextype1ind)
+ {
+ _supportsIndexType = false;
+ indexType = StorageLayout::DefaultIndexType;
+ }
+ else
+ {
+ _supportsIndexType = true;
+ indexType = (r_Index_Type)indextype1;
+ }
+
+ if (tilingscheme1ind)
+ {
+ _supportsTiling = false;
+ tilingScheme = StorageLayout::DefaultTilingScheme;
+ }
+ else
+ {
+ _supportsTiling = true;
+ tilingScheme = (r_Tiling_Scheme)tilingscheme1;
+ }
+
+ if (dataformat1ind)
+ {
+ _supportsDataFormat = false;
+ dataFormat = StorageLayout::DefaultDataFormat;
+ }
+ else
+ {
+ _supportsDataFormat = true;
+ dataFormat = (r_Data_Format)dataformat1;
+ }
+
+ DBObject::readFromDb();
+ RMDBGEXIT(5, RMDebug::module_storageif, "DBStorageLayout", "readFromDb() " << myOId);
+}
+
+void
+DBStorageLayout::updateInDb() throw(r_Error)
+{
+ deleteFromDb();
+ insertInDb();
+ DBObject::updateInDb();
+}
+
+void
+DBStorageLayout::insertInDb() throw(r_Error)
+{
+ RMDBGENTER(5, RMDebug::module_storageif, "DBStorageLayout", "insertInDb() " << myOId);
+ EXEC SQL BEGIN DECLARE SECTION;
+ long storageid2;
+ long domainid2;
+ short domainid2ind;
+ long tilesize2;
+ short tilesize2ind;
+ long pctmin2;
+ short pctmin2ind;
+ long pctmax2;
+ short pctmax2ind;
+ long indexsize2;
+ short indexsize2ind;
+ short indextype2;
+ short indextype2ind;
+ short tilingscheme2;
+ short tilingscheme2ind;
+ short dataformat2;
+ short dataformat2ind;
+ EXEC SQL END DECLARE SECTION;
+
+ storageid2 = myOId.getCounter();
+
+ if (supportsTileConfiguration())
+ {
+ domainid2ind = 0;
+ tileConfiguration->setPersistent(true);
+ domainid2 = tileConfiguration->getOId().getCounter();
+ }
+ else
+ {
+ domainid2ind = -1;
+ }
+
+ if (supportsTileSize())
+ {
+ tilesize2ind = 0;
+ tilesize2 = tileSize;
+ }
+ else
+ {
+ tilesize2ind = -1;
+ }
+
+ if (supportsIndexSize())
+ {
+ indexsize2ind = 0;
+ indexsize2 = indexSize;
+ }
+ else
+ {
+ indexsize2ind = -1;
+ }
+
+ if (supportsPCTMin())
+ {
+ pctmin2ind = 0;
+ pctmin2 = pctMin;
+ }
+ else
+ {
+ pctmin2ind = -1;
+ }
+
+ if (supportsPCTMax())
+ {
+ pctmax2ind = 0;
+ pctmax2 = pctMax;
+ }
+ else
+ {
+ pctmax2ind = -1;
+ }
+
+ if (supportsIndexType())
+ {
+ indextype2ind = 0;
+ indextype2 = indexType;
+ }
+ else
+ {
+ indextype2ind = -1;
+ }
+
+ if (supportsTilingScheme())
+ {
+ tilingscheme2ind = 0;
+ tilingscheme2 = tilingScheme;
+ }
+ else
+ {
+ tilingscheme2ind = -1;
+ }
+
+ if (supportsDataFormat())
+ {
+ dataformat2ind = 0;
+ dataformat2 = dataFormat;
+ }
+ else
+ {
+ dataformat2ind = -1;
+ }
+
+ EXEC SQL INSERT
+ INTO
+ RAS_STORAGE
+ (
+ StorageId,
+ DomainId,
+ TileSize,
+ PCTMin,
+ PCTMax,
+ IndexType,
+ TilingScheme,
+ DataFormat,
+ IndexSize
+ )
+ VALUES (
+ :storageid2,
+ :domainid2 INDICATOR :domainid2ind,
+ :tilesize2 INDICATOR :tilesize2ind,
+ :pctmin2 INDICATOR :pctmin2ind,
+ :pctmax2 INDICATOR :pctmax2ind,
+ :indextype2 INDICATOR :indextype2ind,
+ :tilingscheme2 INDICATOR :tilingscheme2ind,
+ :dataformat2 INDICATOR :dataformat2ind,
+ :indexsize2 INDICATOR :indexsize2ind
+ );
+ if (SQLCODE != SQLOK)
+ {
+ check("DBStorageLayout::insertInDb() INSERT INTO RAS_STORAGE");
+ generateException();
+ }
+
+ DBObject::insertInDb();
+
+ RMDBGEXIT(5, RMDebug::module_storageif, "DBStorageLayout", "insertInDb() " << myOId);
+}
+
+void
+DBStorageLayout::deleteFromDb() throw(r_Error)
+{
+ RMDBGENTER(5, RMDebug::module_storageif, "DBStorageLayout", "deleteFrom() " << myOId);
+ EXEC SQL BEGIN DECLARE SECTION;
+ long storageid3;
+ EXEC SQL END DECLARE SECTION;
+
+ storageid3 = myOId.getCounter();
+
+ EXEC SQL DELETE FROM RAS_STORAGE WHERE StorageId = :storageid3;
+ if (SQLCODE != SQLOK)
+ {
+ check("DBStorageLayout::deleteFrom() DELETE FROM RAS_STORAGE");
+ generateException();
+ }
+
+ tileConfiguration->setPersistent(false);
+ DBObject::deleteFromDb();
+
+ RMDBGEXIT(5, RMDebug::module_storageif, "DBStorageLayout", "deleteFrom() " << myOId);
+}
diff --git a/relstorageif/empty.cc b/relstorageif/empty.cc
new file mode 100644
index 0000000..8246d58
--- /dev/null
+++ b/relstorageif/empty.cc
@@ -0,0 +1 @@
+/* This file helps automake to include a .cc.o rule. It's not supposed to contain anything except this comment. */
diff --git a/relstorageif/storageid.hh b/relstorageif/storageid.hh
new file mode 100644
index 0000000..ec70b2c
--- /dev/null
+++ b/relstorageif/storageid.hh
@@ -0,0 +1,32 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#ifndef _STORAGEID_HH_
+#define _STORAGEID_HH_
+
+class DBStorageLayout;
+
+template <class T> class DBRef;
+
+typedef DBRef<DBStorageLayout> DBStorageLayoutId;
+
+#endif
diff --git a/rnprotocol/Makefile.am b/rnprotocol/Makefile.am
new file mode 100644
index 0000000..d6a021d
--- /dev/null
+++ b/rnprotocol/Makefile.am
@@ -0,0 +1,47 @@
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+#
+# MAKEFILE FOR:
+# module rnprotocol
+#
+# COMMENTS:
+#
+##################################################################
+
+noinst_LIBRARIES=libservercomm.a libclientcomm.a
+
+libservercomm_a_SOURCES=rnprotocol.cc rnprotocol.hh \
+ rnpembedded.cc rnpembedded.hh \
+ rnpcommunication.cc rnpcommunication.hh \
+ rnpserver.cc rnpserver.hh \
+ srvrasmgrcomm.cc srvrasmgrcomm.hh \
+ rnprasserver.cc rnprasserver.hh \
+ rnpservercomm.cc rnpservercomm.hh
+
+libclientcomm_a_SOURCES=rnprotocol.cc rnprotocol.hh \
+ rnpembedded.cc rnpembedded.hh \
+ rnpcommunication.cc rnpcommunication.hh \
+ rnprasserver.cc \
+ rnpclientcomm.cc rnpclientcomm2.cc rnpclientcomm.hh
+
+CLEANFILES=core
+
diff --git a/rnprotocol/rnpclientcomm.cc b/rnprotocol/rnpclientcomm.cc
new file mode 100644
index 0000000..fc58f4b
--- /dev/null
+++ b/rnprotocol/rnpclientcomm.cc
@@ -0,0 +1,1712 @@
+#include "mymalloc/mymalloc.h"
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ * Contains the upper level functions, everything related to communication
+ * is in rnpclientcomm2
+ *
+ ************************************************************/
+
+#include <openssl/evp.h>
+
+#include "rnpclientcomm.hh"
+#include "rasdaman.hh"
+#include "debug.hh"
+
+
+// waiting time increment upon subsecuqnet connect tries in RNP [msecs] -- PB 2005-sep-09
+const unsigned int RNP_PAUSE_INCREMENT = 100;
+
+
+RnpClientComm::RnpClientComm( const char* nRasmgrHost, int nRasmgrPort) throw( r_Error )
+:RnpBaseClientComm(RnpRasserver::serverID, RnpTransport::crp_Rnp)
+{
+ ENTER( "RpcClientComm::RnpClientComm( " << nRasmgrHost << "," << nRasmgrPort << " )" );
+ RMDBGENTER( 2, RMDebug::module_clientcomm, "RpcClientComm", "RnpClientComm(" << nRasmgrHost << "," << nRasmgrPort << ")" );
+
+ clientID = -1;
+
+ clientParams = new r_Parse_Params();
+ clientParams->add("compserver", &serverCompresses, r_Parse_Params::param_type_int);
+ clientParams->add("exactformat", &exactFormat, r_Parse_Params::param_type_int);
+
+ endianClient = (int)r_Endian::get_endianness();
+
+ rasmgrHost=(char*)nRasmgrHost;
+ rasmgrPort=nRasmgrPort;
+ serverHost[0]=0;
+ capability[0]=0;
+ strcpy(identificationString,"rasguest:8e70a429be359b6dace8b5b2500dedb0"); // this is MD5("rasguest");
+
+ transferFormatParams = 0;
+ storageFormatParams = 0;
+
+ // experimentally disabled -- PB 2005-sep-01
+ // useTurbo = true;
+ useTurbo = true;
+ TALK( "useTurbo=" << useTurbo );
+
+ akg::NbJob::setTimeoutInterval(3600);
+
+ RMDBGEXIT( 2, RMDebug::module_clientcomm, "RpcClientComm", "RnpClientComm()" );
+ LEAVE( "RpcClientComm::RnpClientComm()" );
+}
+
+RnpClientComm::~RnpClientComm() throw ()
+{
+ ENTER( "RpcClientComm::~RnpClientComm()" );
+ RMDBGENTER( 2, RMDebug::module_clientcomm, "RpcClientComm", "~RnpClientComm()" );
+ RMDBGEXIT( 2, RMDebug::module_clientcomm, "RpcClientComm", "~RnpClientComm()" );
+ LEAVE( "RpcClientComm::~RnpClientComm()" );
+}
+
+bool RnpClientComm::effectivTypeIsRNP() throw()
+{
+ bool retval = true;
+ ENTER( "RpcClientComm::effectivTypeIsRNP()" );
+ RMDBGENTER( 2, RMDebug::module_clientcomm, "RpcClientComm", "effectivTypeIsRNP()" );
+ RMDBGEXIT( 2, RMDebug::module_clientcomm, "RpcClientComm", "effectivTypeIsRNP() -> " << retval );
+ LEAVE( "RpcClientComm::effectivTypeIsRNP() -> " << retval );
+ return retval;
+}
+
+int RnpClientComm::openDB( const char* database )
+{
+ int retval = 0;
+
+ ENTER( "RpcClientComm::openDB(" << database << ")" );
+ RMDBGENTER( 2, RMDebug::module_clientcomm, "RpcClientComm", "openDB(" << database << ")" );
+
+ strcpy(databaseName,database);
+
+ getFreeServer(false, true); // read only, openDB
+
+ TALK( "openDB: Connected to server: "<<serverHost<<":"<<serverPort );
+ setConnectionParameters(serverHost,serverPort);
+
+/* was commented out, trying it... -- PB 2005-aug-31
+*/
+ if(useTurbo)
+ {
+ turboOpenDB(databaseName);
+ }
+ else
+ {
+ executeConnect();
+ executeOpenDB(database);
+ executeCloseDB();
+ executeDisconnect();
+ }
+/* */
+
+ RMDBGEXIT( 2, RMDebug::module_clientcomm, "RpcClientComm", "openDB() -> " << retval );
+ LEAVE( "RpcClientComm::openDB() -> " << retval );
+ return retval;
+}
+
+int RnpClientComm::closeDB()
+{
+ int retval = 0;
+ ENTER( "RpcClientComm::closeDB()" );
+ RMDBGENTER( 2, RMDebug::module_clientcomm, "RpcClientComm", "closeDB()" );
+ RMDBGEXIT( 2, RMDebug::module_clientcomm, "RpcClientComm", "closeDB() -> " << retval );
+ LEAVE( "RpcClientComm::closeDB() -> " << retval );
+ return retval;
+}
+
+int RnpClientComm::createDB( const char* name ) throw(r_Error)
+{
+ int retval = -1;
+ ENTER( "RpcClientComm::createDB( " << (name?name:"(null)") << " )" );
+ RMDBGENTER( 2, RMDebug::module_clientcomm, "RpcClientComm", "createDB()" );
+ RMDBGEXIT( 2, RMDebug::module_clientcomm, "RpcClientComm", "createDB() -> " << retval );
+ LEAVE( "RpcClientComm::createDB() -> " << retval );
+ return retval;
+}
+
+int RnpClientComm::destroyDB( const char* name ) throw(r_Error)
+{
+ int retval = -1;
+ ENTER( "RpcClientComm::destroyDB( " << (name?name:"(null)") << " )" );
+ RMDBGENTER( 2, RMDebug::module_clientcomm, "RpcClientComm", "destroyDB()" );
+ RMDBGEXIT( 2, RMDebug::module_clientcomm, "RpcClientComm", "destroyDB() -> " << retval );
+ LEAVE( "RpcClientComm::destroyDB() -> " << retval );
+ return retval;
+}
+
+int RnpClientComm::openTA( unsigned short readOnly ) throw(r_Error)
+{
+ int retval = 1;
+ ENTER( "RpcClientComm::openTA(" << readOnly << ")" );
+ RMDBGENTER( 2, RMDebug::module_clientcomm, "RpcClientComm", "openTA(" << readOnly << ")" );
+
+ bool rw = (readOnly == 0 ? true : false);
+
+ getFreeServer(rw, false); // readwrite?, not openDB
+ TALK( "openTA: connected to server "<<serverHost<<":"<<serverPort );
+ setConnectionParameters(serverHost,serverPort);
+
+ if(useTurbo)
+ {
+ turboBeginTA(rw);
+ }
+ else
+ {
+ executeConnect();
+ executeOpenDB(databaseName);
+ executeBeginTA(rw);
+ }
+
+ RMDBGEXIT( 2, RMDebug::module_clientcomm, "RpcClientComm", "openTA() -> " << retval );
+ LEAVE( "RpcClientComm::openTA() -> " << retval );
+ return retval;
+}
+
+int RnpClientComm::commitTA() throw(r_Error)
+{
+ int retval = 1;
+
+ ENTER( "RpcClientComm::commitTA()" );
+ RMDBGENTER( 2, RMDebug::module_clientcomm, "RpcClientComm", "commitTA()" );
+
+ if(useTurbo)
+ {
+ turboCommitTA();
+ }
+ else
+ {
+ executeCommitTA();
+ executeCloseDB();
+ executeDisconnect();
+ }
+
+ RMDBGEXIT( 2, RMDebug::module_clientcomm, "RpcClientComm", "commitTA() -> " << retval );
+ LEAVE( "RpcClientComm::commitTA() -> " << retval );
+ return retval;
+}
+
+int RnpClientComm::abortTA()
+{
+ int retval = 1;
+
+ ENTER( "RpcClientComm::abortTA()" );
+ RMDBGENTER( 2, RMDebug::module_clientcomm, "RpcClientComm", "abortTA()" );
+
+ try
+ {
+ if(useTurbo)
+ {
+ turboAbortTA();
+ }
+ else
+ {
+ executeAbortTA();
+ executeCloseDB();
+ executeDisconnect();
+ }
+ }
+ // make it nicer, but we are not allowed to throw anything! Later will change the declaration of the function
+ catch(...)
+ {
+ TALK( "RpcClientComm::abortTA(): caught & ignored exception." );
+ }
+
+ RMDBGEXIT( 2, RMDebug::module_clientcomm, "RpcClientComm", "abortTA() -> " << retval );
+ LEAVE( "RpcClientComm::abortTA() -> " << retval );
+ return retval;
+}
+
+void RnpClientComm::insertMDD( const char* collName, r_GMarray* mar ) throw( r_Error )
+{
+ ENTER( "RpcClientComm::insertMDD(" << (collName?collName:"(null)") << "," << (long) mar << ")" );
+ RMDBGENTER( 2, RMDebug::module_clientcomm, "RpcClientComm", "insertMDD(" << collName << "," << (long) mar << ")" );
+
+ checkForRwTransaction();
+
+ r_Minterval spatdom;
+ r_Bytes marBytes;
+ RPCMarray* rpcMarray;
+ r_Bytes tileSize = 0;
+
+ // get the spatial domain of the r_GMarray
+ spatdom = mar->spatial_domain();
+
+ // determine the amount of data to be transferred
+ marBytes = mar->get_array_size();
+
+ const r_Base_Type* baseType = mar->get_base_type_schema();
+
+ // if the MDD is too large for being transfered as one block, it has to be
+ // divided in tiles
+ const r_Tiling* til = mar->get_storage_layout()->get_tiling();
+ r_Tiling_Scheme scheme = til->get_tiling_scheme();
+ if (scheme == r_NoTiling)
+ tileSize = RMInit::RMInit::clientTileSize;
+ else
+ //allowed because the only subclass of tiling without size is no tiling
+ tileSize = ((const r_Size_Tiling*)til)->get_tile_size();
+
+ if( RMInit::tiling && marBytes > tileSize )
+ {
+ // initiate composition of MDD at server side
+ int status = executeStartInsertPersMDD(collName, mar); //rpcStatusPtr = rpcstartinsertpersmdd_1( params, binding_h );
+
+ switch( status )
+ {
+ case 0:
+ break; // OK
+ case 2:
+ LEAVE( "RpcClientComm::insertMDD() Error: database class undefined." );
+ throw r_Error( r_Error::r_Error_DatabaseClassUndefined );
+ break;
+ case 3:
+ LEAVE( "RpcClientComm::insertMDD() Error: collection element type mismatch." );
+ throw r_Error( r_Error::r_Error_CollectionElementTypeMismatch );
+ break;
+ case 4:
+ LEAVE( "RpcClientComm::insertMDD() Error: type invalid." );
+ throw r_Error( r_Error::r_Error_TypeInvalid );
+ break;
+ default:
+ LEAVE( "RpcClientComm::insertMDD() Error: transfer invalid." );
+ throw r_Error( r_Error::r_Error_TransferFailed );
+ break;
+ }
+
+ r_Set< r_GMarray* >* bagOfTiles;
+
+ bagOfTiles = mar->get_storage_layout()->decomposeMDD( mar );
+
+ RMDBGMIDDLE(2, RMDebug::module_clientcomm, "RpcClientComm", "decomposing into " << bagOfTiles->cardinality() << " tiles")
+
+ r_Iterator< r_GMarray* > iter = bagOfTiles->create_iterator();
+ r_GMarray *origTile;
+
+ for(iter.reset(); iter.not_done(); iter.advance() )
+ {
+ origTile = *iter;
+
+ RMDBGMIDDLE(2, RMDebug::module_clientcomm, "RpcClientComm", "inserting Tile with domain " << origTile->spatial_domain() << ", " << origTile->spatial_domain().cell_count() * origTile->get_type_length() << " bytes")
+
+ getMarRpcRepresentation( origTile, rpcMarray, mar->get_storage_layout()->get_storage_format(), baseType );
+
+ status = executeInsertTile(true, rpcMarray);
+
+ // free rpcMarray structure (rpcMarray->data.confarray_val is freed somewhere else)
+ freeMarRpcRepresentation( origTile, rpcMarray );
+
+ // delete current tile (including data block)
+ delete origTile;
+
+ if( status > 0 )
+ {
+ throw r_Error( r_Error::r_Error_TransferFailed );
+ }
+ }
+
+ executeEndInsertMDD(true); //rpcendinsertmdd_1( params3, binding_h );
+
+ // delete transient data
+ bagOfTiles->remove_all();
+ delete bagOfTiles;
+ }
+ else // begin: MDD is transferred in one piece
+ {
+ RMDBGMIDDLE(2, RMDebug::module_clientcomm, "RpcClientComm", ", one tile" )
+
+ getMarRpcRepresentation( mar, rpcMarray, mar->get_storage_layout()->get_storage_format(), baseType );
+
+ int status = executeInsertMDD(collName, mar, rpcMarray); // rpcStatusPtr = rpcinsertmdd_1( params, binding_h );
+
+ freeMarRpcRepresentation( mar, rpcMarray );
+
+ RMDBGMIDDLE(2, RMDebug::module_clientcomm, "RpcClientComm", "ok" )
+
+ switch( status )
+ {
+ case 0:
+ break; // OK
+ case 2:
+ LEAVE( "RpcClientComm::insertMDD(): exception, status = " << status );
+ throw r_Error( r_Error::r_Error_DatabaseClassUndefined );
+ break;
+ case 3:
+ LEAVE( "RpcClientComm::insertMDD(): exception, status = " << status );
+ throw r_Error( r_Error::r_Error_CollectionElementTypeMismatch );
+ break;
+ case 4:
+ LEAVE( "RpcClientComm::insertMDD(): exception, status = " << status );
+ throw r_Error( r_Error::r_Error_TypeInvalid );
+ break;
+ default:
+ LEAVE( "RpcClientComm::insertMDD(): exception, status = " << status );
+ throw r_Error( r_Error::r_Error_TransferFailed );
+ break;
+ }
+
+ } // end: MDD i transferred in one piece
+
+ RMDBGEXIT( 2, RMDebug::module_clientcomm, "RpcClientComm", "insertMDD()" );
+ LEAVE( "RpcClientComm::insertMDD()" );
+}
+
+
+//################################################################
+
+r_Ref_Any RnpClientComm::getMDDByOId( const r_OId& oid ) throw( r_Error )
+{
+ ENTER( "RpcClientComm::getMDDByOId(" << oid << ")" );
+ RMDBGENTER( 2, RMDebug::module_clientcomm, "RpcClientComm", "getMDDByOId(" << oid << ")" );
+
+ RMInit::logOut << "Internal error: RnpClientComm::getMDDByOId() not implemented, returning empty r_Ref_Any()." << endl;
+
+ RMDBGEXIT( 2, RMDebug::module_clientcomm, "RpcClientComm", "getMDDByOId()" );
+ LEAVE( "RpcClientComm::getMDDByOId()" );
+ return r_Ref_Any();
+}
+
+void RnpClientComm::insertColl( const char* collName, const char* typeName, const r_OId& oid ) throw( r_Error )
+{
+ ENTER( "RpcClientComm::insertColl(" << collName << "," << typeName << "," << oid << ")" );
+ RMDBGENTER( 2, RMDebug::module_clientcomm, "RpcClientComm", "insertColl(" << collName << "," << typeName << "," << oid << ")" );
+
+ checkForRwTransaction();
+
+ int status = executeInsertCollection(collName, typeName, oid);
+
+ switch( status )
+ {
+ case 0:
+ break; //OK
+ case 1:
+ LEAVE( "RpcClientComm::insertColl(): exception, status = " << status );
+ throw r_Error( r_Error::r_Error_ClientUnknown ); break;
+ case 2:
+ LEAVE( "RpcClientComm::insertColl(): exception, status = " << status );
+ throw r_Error( r_Error::r_Error_DatabaseClassUndefined ); break;
+ case 3:
+ LEAVE( "RpcClientComm::insertColl(): exception, status = " << status );
+ throw r_Error( r_Error::r_Error_NameNotUnique ); break;
+ default:
+ LEAVE( "RpcClientComm::insertColl(): exception, status = " << status );
+ throw r_Error( r_Error::r_Error_General );break;
+ }
+
+ RMDBGEXIT( 2, RMDebug::module_clientcomm, "RpcClientComm", "insertColl()" );
+ LEAVE( "RpcClientComm::insertColl()" );
+}
+
+
+void RnpClientComm::deleteCollByName( const char* collName ) throw( r_Error )
+{
+ ENTER( "RpcClientComm::deleteCollByName(" << (collName?collName:"(null)") << ")" );
+ RMDBGENTER( 2, RMDebug::module_clientcomm, "RpcClientComm", "deleteCollByName(" << collName << ")" );
+
+ checkForRwTransaction();
+
+ startRequest(RnpRasserver::cmd_delcollbyname);
+ encoder.addInt32Parameter(RnpRasserver::pmt_clientid, clientID);
+ TALK( "adding clientID 0x" << hex << clientID << dec );
+ encoder.addStringParameter(RnpRasserver::pmt_collname, collName);
+
+ helper012d("removeObjFromColl");
+
+ RMDBGEXIT( 2, RMDebug::module_clientcomm, "RpcClientComm", "deleteCollByName()" );
+ LEAVE( "RpcClientComm::deleteCollByName()" );
+}
+
+void RnpClientComm::deleteObjByOId( const r_OId& oid ) throw( r_Error )
+{
+ ENTER( "RpcClientComm::deleteObjByOId(" << oid << ")" );
+ RMDBGENTER( 2, RMDebug::module_clientcomm, "RpcClientComm", "deleteObjByOId(" << oid << ")" );
+
+ checkForRwTransaction();
+
+ startRequest(RnpRasserver::cmd_delobjbyoid);
+ encoder.addInt32Parameter(RnpRasserver::pmt_clientid, clientID);
+ TALK( "adding clientID 0x" << hex << clientID << dec );
+ encoder.addStringParameter(RnpRasserver::pmt_oidstring, oid.get_string_representation());
+
+ helper012d("deleteObjByOId");
+
+ RMDBGEXIT( 2, RMDebug::module_clientcomm, "RpcClientComm", "deleteObjByOId()" );
+ LEAVE( "RpcClientComm::deleteObjByOId()" );
+}
+
+void RnpClientComm::removeObjFromColl( const char* collName, const r_OId& oid ) throw ( r_Error )
+{
+ ENTER( "RpcClientComm::removeObjFromColl(" << (collName?collName:"(null)") << "," << oid << ")" );
+ RMDBGENTER( 2, RMDebug::module_clientcomm, "RpcClientComm", "removeObjFromColl(" << collName << "," << oid << ")" );
+
+ checkForRwTransaction();
+
+ startRequest(RnpRasserver::cmd_remobjfromcoll);
+ encoder.addInt32Parameter(RnpRasserver::pmt_clientid, clientID);
+ TALK( "adding clientID 0x" << hex << clientID << dec );
+ encoder.addStringParameter(RnpRasserver::pmt_collname, collName);
+ encoder.addStringParameter(RnpRasserver::pmt_oidstring, oid.get_string_representation());
+
+ helper012d("removeObjFromColl");
+
+ RMDBGEXIT( 2, RMDebug::module_clientcomm, "RpcClientComm", "removeObjFromColl()" );
+ LEAVE( "RpcClientComm::removeObjFromColl()" );
+}
+
+
+r_Ref_Any RnpClientComm::getCollByName( const char* collName ) throw( r_Error )
+{
+ ENTER( "RpcClientComm::getCollByName(" << (collName?collName:"(null)") << ")" );
+ RMDBGENTER( 2, RMDebug::module_clientcomm, "RpcClientComm", "getCollByName(" << collName << ")" );
+
+ r_Ref_Any result = executeGetCollByNameOrOId ( collName, r_OId() );
+
+ RMDBGEXIT( 2, RMDebug::module_clientcomm, "RpcClientComm", "getCollByName()" );
+ LEAVE( "RpcClientComm::getCollByName()" );
+ return result;
+}
+
+r_Ref_Any RnpClientComm::getCollByOId ( const r_OId& oid ) throw( r_Error )
+{
+ ENTER( "RpcClientComm::getCollByOId(" << oid << ")" );
+ RMDBGENTER( 2, RMDebug::module_clientcomm, "RpcClientComm", "getCollByOId(" << oid << ")" );
+
+ r_Ref_Any result = executeGetCollByNameOrOId ( NULL, oid );
+
+ RMDBGEXIT( 2, RMDebug::module_clientcomm, "RpcClientComm", "getCollByOId()" );
+ LEAVE( "RpcClientComm::getCollByOId()" );
+ return result;
+}
+
+r_Ref_Any RnpClientComm::getCollOIdsByName( const char* name ) throw( r_Error )
+{
+ ENTER( "RpcClientComm::getCollOIdsByName(" << (name?name:"(null)") << ")" );
+ RMDBGENTER( 2, RMDebug::module_clientcomm, "RpcClientComm", "getCollOIdsByName(" << name << ")" );
+
+ r_Ref_Any result = executeGetCollOIdsByNameOrOId ( name, r_OId() );
+
+ RMDBGEXIT( 2, RMDebug::module_clientcomm, "RpcClientComm", "getCollOIdsByName()" );
+ LEAVE( "RpcClientComm::getCollOIdsByName()" );
+ return result;
+}
+
+r_Ref_Any RnpClientComm::getCollOIdsByOId ( const r_OId& oid ) throw( r_Error )
+{
+ ENTER( "RpcClientComm::getCollOIdsByOId(" << oid << ")" );
+ RMDBGENTER( 2, RMDebug::module_clientcomm, "RpcClientComm", "getCollOIdsByOId(" << oid << ")" );
+
+ r_Ref_Any result = executeGetCollOIdsByNameOrOId ( NULL, oid );
+
+ RMDBGEXIT( 2, RMDebug::module_clientcomm, "RpcClientComm", "getCollOIdsByOId()" );
+ LEAVE( "RpcClientComm::getCollOIdsByOId()" );
+ return result;
+}
+
+
+//------------------------------
+void RnpClientComm::executeQuery( const r_OQL_Query& query, r_Set< r_Ref_Any >& result ) throw( r_Error )
+{
+ ENTER( "RpcClientComm::executeQuery(_,_)" );
+ RMDBGENTER( 2, RMDebug::module_clientcomm, "RpcClientComm", "executeQuery(_,_)" );
+
+ int status = executeExecuteQuery( query.get_query(), result );
+
+ switch(status)
+ {
+ case 0:
+ getMDDCollection( result, 1 );
+ break; // 1== isQuery
+ case 1:
+ getElementCollection( result );
+ break;
+ //case 2: nothing
+ default:
+ RMInit::logOut << "Internal error: RpcClientComm::executeQuery(): illegal status value " << status << endl;
+ }
+
+ RMDBGEXIT( 2, RMDebug::module_clientcomm, "RpcClientComm", "executeQuery()" );
+ LEAVE( "RpcClientComm::executeQuery()" );
+}
+
+void RnpClientComm::getMDDCollection( r_Set< r_Ref_Any >& mddColl, unsigned int isQuery ) throw(r_Error)
+{
+ ENTER( "RpcClientComm::getMDDCollection(_," << isQuery << ")" );
+ RMDBGENTER( 2, RMDebug::module_clientcomm, "RpcClientComm", "getMDDCollection(_," << isQuery << ")" );
+
+ unsigned short tileStatus=0;
+ unsigned short mddStatus = 0;
+
+ while( mddStatus == 0 ) // repeat until all MDDs are transferred
+ {
+ r_Ref<r_GMarray> mddResult;
+
+ // Get spatial domain of next MDD
+ GetMDDRes* thisResult = executeGetNextMDD();
+
+ mddStatus = thisResult->status;
+
+ if( mddStatus == 2 )
+ {
+ RMInit::logOut << "Error: getMDDCollection(...) - no transfer collection or empty transfer collection" << endl;
+ LEAVE( "RpcClientComm::getMDDCollection(): exception, status = " << mddStatus );
+ throw r_Error( r_Error::r_Error_TransferFailed );
+ }
+
+ tileStatus = getMDDCore(mddResult, thisResult, isQuery);
+
+ // finally, insert the r_Marray into the set
+
+ mddColl.insert_element( mddResult, 1 );
+
+ free(thisResult->domain);
+ free(thisResult->typeName);
+ free(thisResult->typeStructure);
+ free(thisResult->oid);
+ delete thisResult;
+
+ if( tileStatus == 0 ) // if this is true, we're done with this collection
+ break;
+
+ } // end while( mddStatus == 0 )
+
+ executeEndTransfer();
+
+ RMDBGEXIT( 2, RMDebug::module_clientcomm, "RpcClientComm", "getMDDCollection()" );
+ LEAVE( "RpcClientComm::getMDDCollection()" );
+}
+
+
+// small helper for ...
+void freeGetTileRes(GetTileRes *ptr)
+{
+ ENTER( "RpcClientComm::freeGetTileRes(_)" );
+ RMDBGENTER( 2, RMDebug::module_clientcomm, "RpcClientComm", "freeGetTileRes(_)" );
+
+ if(ptr->marray->domain)
+ free(ptr->marray->domain);
+ if(ptr->marray->data.confarray_val)
+ free(ptr->marray->data.confarray_val);
+ delete ptr->marray;
+ delete ptr;
+
+ RMDBGEXIT( 2, RMDebug::module_clientcomm, "RpcClientComm", "freeGetTileRes()" );
+ LEAVE( "RpcClientComm::freeGetTileRes(_)" );
+}
+
+unsigned short
+RnpClientComm::getMDDCore( r_Ref< r_GMarray > &mdd, GetMDDRes *thisResult, unsigned int isQuery ) throw( r_Error )
+{
+ ENTER( "RpcClientComm::getMDDCore(_,_," << isQuery << ")" );
+ RMDBGENTER( 2, RMDebug::module_clientcomm, "RpcClientComm", "getMDDCore(_,_," << isQuery << ")" );
+
+ // create r_Minterval and oid
+ r_Minterval mddDomain( thisResult->domain );
+ r_OId rOId ( thisResult->oid );
+ r_GMarray *marray;
+
+ if( isQuery )
+ marray = new( r_Database::actual_database, r_Object::transient, rOId ) r_GMarray();
+ else
+ marray = new( r_Database::actual_database, r_Object::read , rOId ) r_GMarray();
+
+ marray->set_spatial_domain( mddDomain );
+ marray->set_type_by_name ( thisResult->typeName );
+ marray->set_type_structure( thisResult->typeStructure );
+
+ r_Data_Format currentFormat = (r_Data_Format)(thisResult->currentFormat);
+ if (r_Tile_Compression::check_data_format(currentFormat) == 1)
+ currentFormat = r_Array;
+ marray->set_current_format( currentFormat );
+
+ r_Data_Format decompFormat;
+
+ const r_Base_Type *baseType = marray->get_base_type_schema();
+
+ // Variables needed for tile transfer
+ GetTileRes* tileRes=0;
+ unsigned short mddDim = mddDomain.dimension(); // we assume that each tile has the same dimensionality as the MDD
+ r_Minterval tileDomain;
+ r_GMarray* tile; // for temporary tile
+ char* memCopy;
+ unsigned long memCopyLen;
+ int tileCntr = 0;
+ unsigned short tileStatus = 0;
+
+ tileStatus = 2; // call rpcgetnexttile_1 at least once
+
+ while( tileStatus == 2 || tileStatus == 3 ) // while( for all tiles of the current MDD )
+ {
+ tileRes = executeGetNextTile();
+
+ tileStatus = tileRes->status;
+
+ if( tileStatus == 4 )
+ {
+ freeGetTileRes(tileRes);
+ RMInit::logOut << "Error: rpcGetNextTile(...) - no tile to transfer or empty transfer collection" << endl;
+ LEAVE( "RpcClientComm::getMDDCore(): exception, status = " << tileStatus );
+ throw r_Error( r_Error::r_Error_TransferFailed );
+ }
+
+ // take cellTypeLength for current MDD of the first tile
+ if( tileCntr == 0 )
+ marray->set_type_length( tileRes->marray->cellTypeLength );
+
+ tileDomain = r_Minterval( tileRes->marray->domain );
+ memCopyLen = tileDomain.cell_count() * marray->get_type_length(); // cell type length of the tile must be the same
+ if (memCopyLen < tileRes->marray->data.confarray_len)
+ memCopyLen = tileRes->marray->data.confarray_len; // may happen when compression expands
+ memCopy = new char[ memCopyLen ];
+
+ // create temporary tile
+ tile = new r_GMarray();
+ tile->set_spatial_domain( tileDomain );
+ tile->set_array( memCopy );
+ tile->set_array_size( memCopyLen );
+ tile->set_type_length( tileRes->marray->cellTypeLength );
+ tileCntr++;
+
+ // Variables needed for block transfer of a tile
+ unsigned long blockOffset = 0;
+ unsigned short subStatus = 3;
+ currentFormat = (r_Data_Format)(tileRes->marray->currentFormat);
+
+ switch( tileStatus )
+ {
+ case 3: // at least one block of the tile is left
+
+ // Tile arrives in several blocks -> put them together
+ concatArrayData(tileRes->marray->data.confarray_val, tileRes->marray->data.confarray_len, memCopy, memCopyLen, blockOffset);
+ freeGetTileRes(tileRes);
+
+ tileRes = executeGetNextTile();//rpcgetnexttile_1( &clientID, binding_h );
+
+ subStatus = tileRes->status;
+
+ if( subStatus == 4 )
+ {
+ freeGetTileRes(tileRes);
+ LEAVE( "RpcClientComm::getMDDCore(): exception, status = " << tileStatus << ", subStatus = " << subStatus );
+ throw r_Error( r_Error::r_Error_TransferFailed );
+ }
+
+ concatArrayData(tileRes->marray->data.confarray_val, tileRes->marray->data.confarray_len, memCopy, memCopyLen, blockOffset);
+ freeGetTileRes(tileRes);
+
+ tileStatus = subStatus;
+ break;
+
+ default: // tileStatus = 0,3 last block of the current tile
+
+ // Tile arrives as one block.
+ concatArrayData(tileRes->marray->data.confarray_val, tileRes->marray->data.confarray_len, memCopy, memCopyLen, blockOffset);
+ freeGetTileRes(tileRes);
+
+ break;
+ }
+
+ // uncompress the tile if necessary
+ decompFormat = doTransferDecompression( tile, baseType, currentFormat, blockOffset );
+
+ char* marrayData = NULL;
+ // Now the tile is transferred completely, insert it into current MDD
+ if( tileStatus < 2 && tileCntr == 1 && (tile->spatial_domain() == marray->spatial_domain()))
+ {
+ // MDD consists of just one tile that is the same size of the mdd
+
+ // simply take the data memory of the tile
+ marray->set_array( tile->get_array() );
+ marray->set_array_size( tile->get_array_size() );
+ tile->set_array( 0 );
+ }
+ else
+ {
+ // MDD consists of more than one tile or the tile does not cover the whole domain
+
+ r_Bytes size = mddDomain.cell_count() * marray->get_type_length();
+
+ if( tileCntr == 1 )
+ {
+ // allocate memory for the MDD
+ marrayData = new char[ size ];
+ memset(marrayData, 0, size);
+
+ marray->set_array( marrayData );
+ }
+ else
+ marrayData = marray->get_array();
+
+
+ // copy tile data into MDD data space (optimized, relying on the internal representation of an MDD )
+ char* mddBlockPtr;
+ char* tileBlockPtr = tile->get_array();
+ unsigned long blockCells = tileDomain[tileDomain.dimension()-1].high()-tileDomain[tileDomain.dimension()-1].low()+1;
+ unsigned long blockSize = blockCells * marray->get_type_length();
+ unsigned long blockNo = tileDomain.cell_count() / blockCells;
+
+ for( unsigned long blockCtr = 0; blockCtr < blockNo; blockCtr++ )
+ {
+ mddBlockPtr = marrayData + marray->get_type_length()*mddDomain.cell_offset( tileDomain.cell_point( blockCtr * blockCells ) );
+ memcpy( (void*)mddBlockPtr, (void*)tileBlockPtr, (size_t)blockSize );
+ tileBlockPtr += blockSize;
+ }
+
+ // former non-optimized version
+ // for( i=0; i<tileDomain->cell_count(); i++ )
+ // (*marray)[tileDomain->cell_point( i )] = (*tile)[tileDomain->cell_point( i )];
+
+ marray->set_array_size( size );
+ }
+
+ // delete temporary tile
+ delete tile;
+
+ } // end while( MDD is not transferred completely )
+
+
+ mdd = r_Ref<r_GMarray>( marray->get_oid(), marray );
+
+ RMDBGEXIT( 2, RMDebug::module_clientcomm, "RpcClientComm", "getMDDCore() -> " << tileStatus );
+ LEAVE( "RpcClientComm::getMDDCore() -> " << tileStatus );
+ return tileStatus;
+}
+
+
+int RnpClientComm::concatArrayData( const char *source, unsigned long srcSize, char *&dest, unsigned long &destSize, unsigned long &destLevel )
+{
+ ENTER( "RpcClientComm::concatArrayData( 0x" << hex << (unsigned long) source << dec << "," << srcSize << ",_,_,_ )" );
+ RMDBGENTER( 2, RMDebug::module_clientcomm, "RpcClientComm", "concatArrayData(" << source << "," << srcSize << ",_,_,_)" );
+
+ if (destLevel + srcSize > destSize)
+ {
+ // need to extend dest
+ unsigned long newSize = destLevel + srcSize;
+ char *newArray;
+
+ // allocate a little extra if we have to extend
+ newSize = newSize + newSize / 16;
+
+ // RMDBGOUT( 1, "RpcClientComm::concatArrayData(): need to extend from " << destSize << " to " << newSize );
+
+ if ((newArray = new char[newSize]) == NULL)
+ {
+ RMDBGEXIT( 2, RMDebug::module_clientcomm, "RpcClientComm", "concatArrayData() -> " << -1 );
+ LEAVE( "RpcClientComm::concatArrayData() -> -1" );
+ return -1;
+ }
+
+ memcpy(newArray, dest, destLevel);
+ delete [] dest;
+ dest = newArray;
+ destSize = newSize;
+ }
+
+ memcpy(dest + destLevel, source, srcSize);
+ destLevel += srcSize;
+
+ RMDBGEXIT( 2, RMDebug::module_clientcomm, "RpcClientComm", "concatArrayData() -> " << 0 );
+ LEAVE( "RpcClientComm::concatArrayData() -> 0" );
+ return 0;
+}
+
+r_Data_Format
+RnpClientComm::doTransferDecompression( r_GMarray* tile, const r_Base_Type *type, r_Data_Format fmt, unsigned long size )
+{
+ ENTER( "RpcClientComm::doTransferDecompression(...) tile dom:" << tile->spatial_domain() << " array size:" << tile->get_array_size() << " type size:" << tile->get_type_length());
+ RMDBGENTER( 2, RMDebug::module_clientcomm, "RpcClientComm", "doTransferDecompression(...) tile dom:"
+ << tile->spatial_domain() << " array size:" << tile->get_array_size()
+ << " type size:" << tile->get_type_length());
+
+ if (fmt != r_Array)
+ {
+ r_Tile_Compression *engine = NULL;
+ char *newTileData = NULL;
+ r_Data_Format newFormat;
+
+ RMDBGMIDDLE( 2, RMDebug::module_clientcomm, "RpcClientComm", "doTransferDecompression(...) decompressing from "
+ << fmt << ", " << size << "bytes");
+
+ try
+ {
+ r_Storage_Man_CPP sman;
+ engine = r_Tile_Compression::create( fmt, tile->spatial_domain(), type );
+ engine->set_storage_handler(sman);
+ newTileData = (char*)(engine->decompress(tile->get_array(), size));
+ RMDBGMIDDLE( 2, RMDebug::module_clientcomm, "RpcClientComm",
+ "doTransferDecompression(...) decompression to " << engine->get_decomp_format() << " OK");
+ }
+ catch (r_Error &err)
+ {
+ RMDBGMIDDLE( 2, RMDebug::module_clientcomm, "RpcClientComm",
+ "doTransferDecompression(...) decompression to " << engine->get_decomp_format() << " FAILED");
+ RMInit::logOut << "RpcClientComm::doTransferDecompression() Error decompressing data, assuming raw" << endl;
+ }
+
+ newFormat = engine->get_decomp_format();
+
+ if (newTileData != NULL)
+ {
+ delete [] tile->get_array();
+ tile->set_array(newTileData);
+ tile->set_array_size(tile->spatial_domain().cell_count()*tile->get_type_length());
+ }
+ else
+ newFormat = fmt;
+
+ RMDBGMIDDLE( 2, RMDebug::module_clientcomm, "RpcClientComm", "doTransferDecompression(...) tile newFmt:"
+ << newFormat << " dom:" << tile->spatial_domain()
+ << " array size:" << tile->get_array_size()
+ << " type size:" << tile->get_type_length());
+
+ // ... also make sure the decoded format is really raw array data (r_Array)
+ if ((endianClient != endianServer) && (newFormat == r_Array))
+ {
+ // if compression engine already handles endianness we mustn't change again
+ if (!engine->converts_endianness()) {
+ RMDBGMIDDLE( 2, RMDebug::module_clientcomm, "RpcClientComm", "doTransferDecompression(...) for "
+ << fmt << " endianness changed from "
+ << (r_Endian::r_Endianness)endianServer << " to " << (r_Endian::r_Endianness) endianClient);
+ changeEndianness(tile, type);
+ }
+ }
+
+ if (engine != NULL)
+ delete engine;
+
+ RMDBGEXIT( 2, RMDebug::module_clientcomm, "RpcClientComm", "doTransferDecompression(...) tile fmt:" << newFormat);
+ LEAVE( "RpcClientComm::doTransferDecompression() -> " << newFormat );
+ return newFormat;
+ }
+
+ if (endianClient != endianServer)
+ {
+ RMDBGMIDDLE( 2, RMDebug::module_clientcomm, "RpcClientComm", "doTransferDecompression(...) for "
+ << fmt << " endianness changed from "
+ << (r_Endian::r_Endianness)endianServer << " to " << (r_Endian::r_Endianness) endianClient);
+ changeEndianness(tile, type);
+ }
+
+ RMDBGEXIT( 2, RMDebug::module_clientcomm, "RpcClientComm", "doTransferDecompression(...) tile fmt:" << r_Array);
+ LEAVE( "RpcClientComm::doTransferDecompression() -> " << r_Array );
+ return r_Array;
+}
+
+
+void RnpClientComm::getElementCollection( r_Set< r_Ref_Any >& resultColl ) throw(r_Error)
+{
+ ENTER( "RpcClientComm::getElementCollection()" );
+ RMDBGENTER( 2, RMDebug::module_clientcomm, "RpcClientComm", "getElementCollection(_)" );
+
+ unsigned short rpcStatus = 0;
+
+ TALK( "got set of type " << resultColl.get_type_structure() );
+
+ while( rpcStatus == 0 ) // repeat until all elements are transferred
+ {
+ GetElementRes* thisResult = executeGetNextElement();
+
+ rpcStatus = thisResult->status;
+
+ if( rpcStatus == 2 )
+ {
+ RMInit::logOut << "Error: getElementCollection(...) - no transfer collection or empty transfer collection" << endl;
+ LEAVE( "RpcClientComm::getElementCollection(): exception: rpcStatus = " << rpcStatus );
+ throw r_Error( r_Error::r_Error_TransferFailed );
+ }
+ // create new collection element, use type of collection resultColl
+ r_Ref_Any element;
+ const r_Type* elementType = resultColl.get_element_type_schema();
+
+ // convert the endianness before creating the new element!
+ if (endianClient != endianServer)
+ {
+
+ if (endianClient == 0)
+ elementType->convertToBigEndian(thisResult->data.confarray_val, 1);
+ else
+ elementType->convertToLittleEndian(thisResult->data.confarray_val, 1);
+ }
+
+ switch( elementType->type_id() )
+ {
+ case r_Type::BOOL:
+ case r_Type::CHAR:
+ case r_Type::OCTET:
+ case r_Type::SHORT:
+ case r_Type::USHORT:
+ case r_Type::LONG:
+ case r_Type::ULONG:
+ case r_Type::FLOAT:
+ case r_Type::DOUBLE:
+ element = new r_Primitive( thisResult->data.confarray_val, (r_Primitive_Type*) elementType );
+ r_Transaction::actual_transaction->add_object_list( r_Transaction::SCALAR, (void*) element );
+ break;
+
+ case r_Type::COMPLEXTYPE1:
+ case r_Type::COMPLEXTYPE2:
+ element = new r_Complex(thisResult->data.confarray_val, (r_Complex_Type *)elementType);
+ r_Transaction::actual_transaction->add_object_list(r_Transaction::SCALAR, (void *)element);
+ break;
+
+ case r_Type::STRUCTURETYPE:
+ element = new r_Structure( thisResult->data.confarray_val, (r_Structure_Type*) elementType );
+ r_Transaction::actual_transaction->add_object_list( r_Transaction::SCALAR, (void*) element );
+ break;
+
+ case r_Type::POINTTYPE:
+ {
+ char* stringRep = new char[thisResult->data.confarray_len+1];
+ strncpy( stringRep, thisResult->data.confarray_val, thisResult->data.confarray_len );
+ stringRep[thisResult->data.confarray_len] = '\0';
+
+ r_Point* typedElement = new r_Point( stringRep );
+ element = typedElement;
+ r_Transaction::actual_transaction->add_object_list( r_Transaction::POINT, (void*) typedElement );
+ delete [] stringRep;
+ }
+ break;
+
+ case r_Type::SINTERVALTYPE:
+ {
+ char* stringRep = new char[thisResult->data.confarray_len+1];
+ strncpy( stringRep, thisResult->data.confarray_val, thisResult->data.confarray_len );
+ stringRep[thisResult->data.confarray_len] = '\0';
+
+ r_Sinterval* typedElement = new r_Sinterval( stringRep );
+ element = typedElement;
+ r_Transaction::actual_transaction->add_object_list( r_Transaction::SINTERVAL, (void*) typedElement );
+ delete [] stringRep;
+ }
+ break;
+
+ case r_Type::MINTERVALTYPE:
+ {
+ char* stringRep = new char[thisResult->data.confarray_len+1];
+ strncpy( stringRep, thisResult->data.confarray_val, thisResult->data.confarray_len );
+ stringRep[thisResult->data.confarray_len] = '\0';
+
+ r_Minterval* typedElement = new r_Minterval( stringRep );
+ element = typedElement;
+ r_Transaction::actual_transaction->add_object_list( r_Transaction::MINTERVAL, (void*) typedElement );
+ delete [] stringRep;
+ }
+ break;
+
+ case r_Type::OIDTYPE:
+ {
+ char* stringRep = new char[thisResult->data.confarray_len+1];
+ strncpy( stringRep, thisResult->data.confarray_val, thisResult->data.confarray_len );
+ stringRep[thisResult->data.confarray_len] = '\0';
+
+ r_OId* typedElement = new r_OId( stringRep );
+ element = typedElement;
+ r_Transaction::actual_transaction->add_object_list( r_Transaction::OID, (void*) typedElement );
+ delete [] stringRep;
+ }
+ break;
+ default:
+ RMDBGENTER(2, RMDebug::module_clientcomm, "RpcClientComm", "getElementCollection(...) bad element typeId" << elementType->type_id())
+ break;
+ }
+
+ TALK( "got an element" );
+
+ // insert element into result set
+ resultColl.insert_element( element, 1 );
+
+ delete[] thisResult->data.confarray_val;
+ delete thisResult;
+ }
+
+ executeEndTransfer();
+
+ RMDBGEXIT( 2, RMDebug::module_clientcomm, "RpcClientComm", "getElementCollection()" );
+ LEAVE( "RpcClientComm::getElementCollection()" );
+}
+
+//##################################################################################
+void RnpClientComm::executeQuery( const r_OQL_Query& query ) throw( r_Error )
+{
+ ENTER( "RnpClientComm::executeQuery(_)" );
+
+ checkForRwTransaction();
+
+ unsigned short status;
+
+ //
+ // Send MDD constants to the server.
+ //
+ if( query.get_constants() )
+ {
+ r_Set< r_GMarray* >* mddConstants = (r_Set< r_GMarray* >*)query.get_constants();
+
+ if(executeInitUpdate() < 0) // error would be nicer
+ {
+ LEAVE( "Error: RnpClientComm::executeQuery(): update query initialization failed." );
+ return;
+ }
+
+ r_Iterator<r_GMarray*> iter = mddConstants->create_iterator();
+
+ for( iter.reset(); iter.not_done(); iter++ )
+ {
+ r_GMarray* mdd = *iter;
+
+ const r_Base_Type* baseType = mdd->get_base_type_schema();
+
+ if( mdd )
+ {
+ status = executeStartInsertTransMDD(mdd);
+ switch( status )
+ {
+ case 0:
+ break; // OK
+ case 2:
+ LEAVE( "RnpClientComm::executeQuery(): exception, status = " << status );
+ throw r_Error( r_Error::r_Error_DatabaseClassUndefined );
+ break;
+ case 3:
+ LEAVE( "RnpClientComm::executeQuery(): exception, status = " << status );
+ throw r_Error( r_Error::r_Error_TypeInvalid );
+ break;
+ default:
+ LEAVE( "RnpClientComm::executeQuery(): exception, status = " << status );
+ throw r_Error( r_Error::r_Error_TransferFailed );
+ break;
+ }
+
+ r_Set< r_GMarray* >* bagOfTiles;
+
+ bagOfTiles = mdd->get_storage_layout()->decomposeMDD( mdd );
+
+ r_Iterator< r_GMarray* > iter2 = bagOfTiles->create_iterator();
+
+ for(iter2.reset(); iter2.not_done();iter2.advance())
+ {
+ RPCMarray* rpcMarray;
+
+ r_GMarray *origTile = *iter2;
+
+ getMarRpcRepresentation( origTile, rpcMarray, mdd->get_storage_layout()->get_storage_format(), baseType );
+
+ status = executeInsertTile(false, rpcMarray);
+
+ // free rpcMarray structure (rpcMarray->data.confarray_val is freed somewhere else)
+ freeMarRpcRepresentation( origTile, rpcMarray );
+
+ // delete current tile (including data block)
+ delete origTile;
+
+ if( status > 0 )
+ {
+ LEAVE( "RnpClientComm::executeQuery(): exception, status = " << status );
+ throw r_Error( r_Error::r_Error_TransferFailed );
+ }
+ }
+
+ bagOfTiles->remove_all();
+ delete bagOfTiles;
+
+ executeEndInsertMDD(false);
+ }
+ }
+ }
+
+ executeExecuteUpdateQuery(query.get_query());
+ LEAVE( "RnpClientComm::executeQuery(_)" );
+}
+
+
+// helper functions
+void
+RnpClientComm::getMarRpcRepresentation( const r_GMarray* mar, RPCMarray*& rpcMarray,
+ r_Data_Format initStorageFormat,
+ const r_Base_Type *baseType)
+{
+ ENTER( "RpcClientComm::getMarRpcRepresentation(...)");
+ RMDBGENTER(2, RMDebug::module_clientcomm, "RpcClientComm", "getMarRpcRepresentation(...)");
+
+ // allocate memory for the RPCMarray data structure and assign its fields
+ rpcMarray = (RPCMarray*)mymalloc( sizeof(RPCMarray) );
+ rpcMarray->domain = mar->spatial_domain().get_string_representation();
+ rpcMarray->cellTypeLength = mar->get_type_length();
+
+ void* arrayData = NULL;
+ r_ULong arraySize=0;
+
+ if (initStorageFormat == r_Array)
+ {
+ if (transferFormat != r_Array)
+ {
+ r_Tile_Compression *engine = NULL;
+
+ try
+ {
+ r_Storage_Man_CPP sman;
+ engine = r_Tile_Compression::create(transferFormat, mar->spatial_domain(), baseType);
+ engine->set_storage_handler(sman);
+ RMDBGMIDDLE(2, RMDebug::module_clientcomm, "RpcClientComm", "getMarRpcRepresentation(...) compress with " << engine->get_name())
+ if ((endianClient != endianServer) && (!engine->converts_endianness()))
+ {
+ RMDBGMIDDLE( 2, RMDebug::module_clientcomm, "RpcClientComm", "getMarRpcRepresentation(...) for "
+ << transferFormat << " endianness changed before compression from " << (r_Endian::r_Endianness)endianClient
+ << " to " << (r_Endian::r_Endianness) endianServer);
+ char *endianData = new char[mar->get_array_size()];
+ changeEndianness(mar, endianData, baseType);
+ arrayData = engine->compress(endianData, arraySize, transferFormatParams);
+ delete [] endianData;
+ endianData=NULL;
+ }
+ else
+ {
+ arrayData = engine->compress(mar->get_array(), arraySize, transferFormatParams);
+ }
+ RMDBGMIDDLE(2, RMDebug::module_clientcomm, "RpcClientComm", "compression returned " << arrayData << " (" << arraySize << " bytes)")
+/* void *testData = engine->decompress(arrayData, arraySize);
+ cout << "Decompression worked " << ((memcmp(mar->get_array(), testData, (mar->get_type_length()) * (mar->spatial_domain().cell_count())) == 0) ? "OK" : "!NOT!") << endl;
+ delete [] testData;
+*/
+
+ // ForWiss: revert to uncompressed data if the compressed data is larger
+ // coman: and introduced a bug of endianess ...
+ if (arraySize > mar->get_array_size())
+ {
+ RMInit::logOut << "RpcClientComm::getMarRpcRepresentation(...) Warning: overriding compression setting("
+ << transferFormat << ") to " << r_Array
+ << " because compressed size( " << arraySize
+ << " bytes) > uncompressed size( " << mar->get_array_size() << " bytes)" << endl;
+ delete [] arrayData;
+ arrayData = NULL;
+ }
+ }
+ catch (r_Error &err)
+ {
+ RMInit::logOut << "RpcClientComm::getMarRpcRepresentation() Error: Unsupported data format " << transferFormat << endl;
+ }
+ if (engine != NULL)
+ delete engine;
+ }
+ else
+ {
+ if (endianClient != endianServer)
+ {
+ RMDBGMIDDLE( 2, RMDebug::module_clientcomm, "RpcClientComm", "getMarRpcRepresentation(...) for "
+ << transferFormat << " endianness changed from "
+ << (r_Endian::r_Endianness)endianClient << " to " << (r_Endian::r_Endianness) endianServer);
+ arraySize = mar->get_array_size();
+ arrayData = new char[arraySize];
+ changeEndianness(mar, arrayData, baseType);
+ }
+ }
+ }
+
+ if (arrayData == NULL)
+ {
+ //error in compression or compression inefficient
+ rpcMarray->currentFormat = initStorageFormat;
+ rpcMarray->data.confarray_len = mar->get_array_size();
+ if (endianClient != endianServer)
+ {
+ RMDBGMIDDLE( 2, RMDebug::module_clientcomm, "RpcClientComm", "getMarRpcRepresentation(...) for "
+ << transferFormat << "endianness changed from "
+ << (r_Endian::r_Endianness)endianClient << " to " << (r_Endian::r_Endianness) endianServer
+ << " because compression " << transferFormat << " failed" );
+ arrayData = new char[arraySize];
+ changeEndianness(mar, arrayData, baseType);
+ rpcMarray->data.confarray_val = (char*)(arrayData);
+ }
+ else
+ {
+ rpcMarray->data.confarray_val = (char*)(mar->get_array());
+ }
+ }
+ else
+ {
+ if (arraySize != mar->get_array_size())
+ {
+ RMDBGMIDDLE(2, RMDebug::module_clientcomm, "RpcClientComm", "compressed to " << (100.0*arraySize) / mar->get_array_size() << "%")
+ }
+ rpcMarray->currentFormat = transferFormat;
+ rpcMarray->data.confarray_len = arraySize;
+ rpcMarray->data.confarray_val = (char*)arrayData;
+ }
+ rpcMarray->storageFormat = storageFormat;
+
+ RMDBGEXIT(2, RMDebug::module_clientcomm, "RpcClientComm", "getMarRpcRepresentation(...)");
+ LEAVE( "RpcClientComm::getMarRpcRepresentation()");
+}
+
+
+void
+RnpClientComm::freeMarRpcRepresentation( const r_GMarray* mar, RPCMarray* rpcMarray )
+{
+ ENTER( "RnpClientComm::freeMarRpcRepresentation(_,_)" );
+
+ if (rpcMarray->data.confarray_val != ((r_GMarray*)mar)->get_array())
+ {
+ delete[] rpcMarray->data.confarray_val;
+ }
+ free( rpcMarray->domain );
+ free( rpcMarray );
+
+ LEAVE( "RnpClientComm::freeMarRpcRepresentation()" );
+}
+
+
+//#########################################################################
+r_OId RnpClientComm::getNewOId( unsigned short objType ) throw(r_Error)
+{
+ return executeGetNewOId(objType);
+}
+
+unsigned short RnpClientComm::getObjectType( const r_OId& oid ) throw(r_Error)
+{
+ return executeGetObjectType(oid);
+}
+
+char* RnpClientComm::getTypeStructure( const char* typeName, r_Type_Type typeType ) throw(r_Error)
+{
+ return executeGetTypeStructure( typeName, typeType );
+}
+
+int RnpClientComm::setStorageFormat( r_Data_Format format, const char *formatParams)
+{
+ ENTER( "RnpClientComm::setStorageFormat( format=" << format << ", formatParams=" << (formatParams?formatParams:"(null)") << " )" );
+
+ storageFormat = format;
+
+ if (storageFormatParams != NULL)
+ {
+ free(storageFormatParams);
+ storageFormatParams = NULL;
+ }
+ if (formatParams != NULL)
+ {
+ storageFormatParams = (char*)mymalloc(strlen(formatParams) + 1);
+ strcpy(storageFormatParams, formatParams);
+ // extract ``compserver'' if present
+ clientParams->process(storageFormatParams);
+ }
+
+ int result = executeSetFormat( false, format, formatParams);
+
+ LEAVE( "RnpClientComm::setStorageFormat() -> " << result );
+ return result;
+}
+
+int RnpClientComm::setTransferFormat( r_Data_Format format, const char* formatParams)
+{
+ ENTER( "RnpClientComm::setTransferFormat( format=" << format << ", formatParams=" << (formatParams?formatParams:"(null)") << " )" );
+
+ transferFormat = format;
+
+ if (transferFormatParams != NULL)
+ {
+ free(transferFormatParams);
+ transferFormatParams = NULL;
+ }
+ if (formatParams != NULL)
+ {
+ transferFormatParams = (char*)mymalloc(strlen(formatParams)+1);
+ strcpy(transferFormatParams, formatParams);
+ // extract ``exactformat'' if present
+ clientParams->process(transferFormatParams);
+ }
+
+ int result = executeSetFormat( true, format, formatParams);
+ LEAVE( "RnpClientComm::setTransferFormat() -> " << result );
+ return result;
+}
+
+const char* RnpClientComm::getExtendedErrorInfo() throw(r_Error)
+{
+ // This function shouldn't be called for RNP protocol
+ static char *errorInfo = new char[30];
+ strcpy(errorInfo,"No info");
+
+ return errorInfo;
+}
+
+const char* RnpClientComm::getServerName()
+{
+ return serverHost;
+}
+
+void RnpClientComm::setUserIdentification(const char *userName, const char *plainTextPassword)
+{
+ ENTER( "RnpClientComm::setUserIdentification( userName=" << (userName?userName:"(null)") << ", plainTextPassword=" << (plainTextPassword?plainTextPassword:"(null)") << " )" );
+
+ char digest[33]="";
+ messageDigest(plainTextPassword,digest,"MD5");
+ sprintf(identificationString,"%s:%s",userName,digest);
+
+ LEAVE( "RnpClientComm::setUserIdentification()" );
+}
+
+unsigned long RnpClientComm::getClientID() const
+{
+ return clientID;
+}
+
+void RnpClientComm::triggerAliveSignal(){}
+
+void RnpClientComm::sendAliveSignal(){}
+
+//############# helper functions ###################
+int RnpClientComm::messageDigest(const char *input,char *output,const char *mdName)
+{
+
+ EVP_MD_CTX mdctx;
+ const EVP_MD *md;
+ unsigned int md_len, i;
+ unsigned char md_value[100];
+
+ OpenSSL_add_all_digests();
+
+ md = EVP_get_digestbyname(mdName);
+
+ if(!md)
+ return 0;
+
+ EVP_DigestInit(&mdctx, md);
+ EVP_DigestUpdate(&mdctx,input, strlen(input));
+ EVP_DigestFinal(&mdctx, md_value, &md_len);
+
+ for(i = 0; i < md_len; i++)
+ sprintf(output+i+i,"%02x", md_value[i]);
+
+ return strlen(output);
+}
+
+
+void RnpClientComm::setMaxRetry(unsigned int newMaxRetry)
+{
+ RMInit::clientcommMaxRetry = newMaxRetry;
+}
+
+unsigned int RnpClientComm::getMaxRetry()
+{
+ return RMInit::clientcommMaxRetry;
+}
+
+// aux function: sleep incrementally, with subsecond precision
+static void pause(int retryCount)
+{
+ // changed PB 2005-sep-09
+ // was: unsigned int millisec = 50 + retryCount * 50;
+ unsigned int millisec = RNP_PAUSE_INCREMENT * (retryCount + 1);
+ // if(millisec > 1000)
+ // millisec = 1000;
+
+ timeval tv;
+ tv.tv_sec = millisec / 1000;
+ tv.tv_usec = millisec * 1000;
+ select(0,NULL,NULL,NULL,&tv);
+}
+
+int RnpClientComm::getFreeServer(bool readwrite, bool openDB)
+{
+ ENTER( "RnpClientComm::getFreeServer( readwrite=" << readwrite << ", openDB=" << openDB << " )" );
+
+ // to avoid nested retries, only this loop is kept,
+ // the one in executeGetFreeServer() has been removed -- PB 2005-aug-31
+ for ( int retryCount=0; ; retryCount++ )
+ {
+ try
+ {
+ executeGetFreeServer(readwrite, openDB);
+
+ // if no error, we have the server, so break
+ break;
+ }
+ catch(r_Error &e)
+ {
+ int errorno = e.get_errorno();
+ RMInit::logOut << "Error: Connection to rasdaman server failed with " << errorno << ": " << e.what() << endl;
+ // for these errors a retry makes sense, as long as we haven't reached the retry limit:
+ if ( ( errorno==801 || errorno==805 || errorno==806 ) && retryCount < RMInit::clientcommMaxRetry )
+ {
+ TALK( " retry="<<retryCount );
+ pause(retryCount); // waiting with incremental delays
+ }
+ else
+ {
+ LEAVE( "RnpClientComm::getFreeServer(): exception " << errorno << ": " << e.what() );
+ throw;
+ }
+ }
+ }
+
+ LEAVE( "RnpClientComm::getFreeServer() -> 1" );
+ return 1;
+}
+
+#define MAXMSG 512
+int RnpClientComm::executeGetFreeServer(bool readwrite, bool openDB)
+{
+ ENTER( "RnpClientComm::executeGetFreeServer( readwrite=" << readwrite << ", openDB=" << openDB << " )" );
+
+ static char myRasmgrID[100]="";
+ if(myRasmgrID[0]==0)
+ {
+ unsigned int hostid = gethostid();
+ unsigned int pid = getpid();
+ sprintf(myRasmgrID,"%u:%u",hostid,pid);
+ }
+ char message[MAXMSG];
+ char header[MAXMSG];
+ char body[MAXMSG];
+
+ if (openDB)
+ sprintf(header,"POST getfreeserver2 HTTP/1.1\r\nAccept: text/plain\r\nUserAgent: RasClient/1.0\r\nAuthorization: ras %s\r\nContent-length:",identificationString);
+ else
+ sprintf(header,"POST getfreeserver HTTP/1.1\r\nAccept: text/plain\r\nUserAgent: RasClient/1.0\r\nAuthorization: ras %s\r\nContent-length:",identificationString);
+ sprintf(body,"%s RNP %s %s",databaseName,(readwrite ? "rw":"ro"), myRasmgrID);
+ sprintf(message,"%s %d\r\n\r\n%s",header,strlen(body)+1,body);
+
+ struct protoent* getprotoptr = getprotobyname("tcp");
+
+ struct hostent *hostinfo = gethostbyname(rasmgrHost);
+ if(hostinfo==NULL)
+ {
+ RMInit::logOut << "Error locating rasmgr on host " << rasmgrHost <<" ("<<strerror(errno)<<')'<<endl;
+ LEAVE( "RnpClientComm::executeGetFreeServer(): exception, unable to contact rasmgr." );
+ throw r_Error( r_Error::r_Error_ServerInvalid );
+ }
+
+ sockaddr_in internetSocketAddress;
+
+ internetSocketAddress.sin_family=AF_INET;
+ internetSocketAddress.sin_port=htons(rasmgrPort);
+ internetSocketAddress.sin_addr=*(struct in_addr*)hostinfo->h_addr;
+
+ int sock;
+ bool ok = false;
+ // old comment by Walter Schatz: "this has to be 5000 or so, now that counter is 120 default (later we'll make this better)"
+ // new comment by PB 2005-aug-31:
+ // - these retries + the ones in getFreeServer lead to max*max*40 = 400,000 retries! one loop should be enough.
+ // - there are unmotivated factors at every step (cf pause()), let's do just one wait loop;
+ // all loop code is commented out with prefix "NOLOOP"
+ // X: int retry;
+ // X: for(retry=0;retry<RMInit::clientcommMaxRetry * 40;retry++)
+ // X: {
+ sock=socket(PF_INET,SOCK_STREAM,getprotoptr->p_proto);
+ if(sock<0)
+ {
+ // X: if(retry==0)
+ RMInit::logOut << "Error: cannot open socket to rasmgr (" << strerror(errno) << ")." << endl;
+ // X: sleep(RMInit::clientcommSleep);
+ // X: continue;
+ }
+
+ else if(connect(sock,(struct sockaddr*)&internetSocketAddress,sizeof(internetSocketAddress)) < 0)
+ {
+ // X: if(retry==0)
+ // X: RMInit::logOut <<"getFreeServer: Connection to rasmgr failed: "<<strerror(errno)<<endl;
+ close(sock);
+ // X: sleep(RMInit::clientcommSleep);
+ // X: continue;
+ }
+
+ TALK( "Socket="<<sock<<" protocol(tcp)="<<getprotoptr->p_proto );
+ ok = true;
+ // X: break;
+ // X:}
+ // X:if(retry)
+ // X: RMInit::logOut << "Warning: tried connecting " << retry+1 << " times " <<endl;
+
+ if( !ok )
+ {
+ // X: RMInit::logOut << "Error: Giving up on connecting, sorry, after this number of tries: " << retry+1 <<endl;
+ close(sock);
+ LEAVE( "RnpClientComm::executeGetFreeServer(): exception, giving up on getting a free server." );
+ throw r_Error( r_Error::r_Error_ServerInvalid );
+ }
+
+ // --- from here on we have a connection ---
+
+ //write_to_server
+ // TALK( "want to write this message to rasmgr: " << message ); // message is said to be 0-terminated
+ int nbytes=writeWholeMessage(sock,message,strlen(message)+1);
+
+ if(nbytes<0)
+ {
+ RMInit::logOut << "Error: cannot send message to rasmgr on host " << rasmgrHost << " ("<<strerror(errno)<<')' << endl;
+ LEAVE( "RnpClientComm::executeGetFreeServer(): exception, error writing message to rasmgr." );
+ close(sock);
+ throw r_Error( r_Error::r_Error_ServerInvalid );
+ }
+
+ //wait and read answer
+ nbytes=readWholeMessage(sock,message,MAXMSG);
+ close(sock);
+
+ if(nbytes<0)
+ {
+ RMInit::logOut << "Error reading answer from rasmgr on host " << rasmgrHost <<" ("<<strerror(errno)<<')'<<endl;
+ LEAVE( "RnpClientComm::executeGetFreeServer(): exception, error reading answer from rasmgr." );
+ throw r_Error( r_Error::r_Error_ServerInvalid );
+ }
+ // TALK( "received this message: " << message ); // quite verbose!
+
+ // and now, analyze answer
+ // first line is: HTTP/1.1 code answertext(CRLF)
+ char *p=strstr(message," "); //looks for the first white space to locate status-code
+
+ int statusCode=strtoul( p, (char **)NULL, 10);
+
+ char *pEOL=strstr(p,"\r\n"); // locate CRLF
+ if(!pEOL)
+ {
+ RMInit::logOut << "Error: Invalid answer from rasmgr." << endl;
+ LEAVE( "RnpClientComm::executeGetFreeServer(): exception, invalid answer from rasmgr." );
+ throw r_Error( r_Error::r_Error_ServerInvalid );
+ }
+
+ if(statusCode==200)
+ { // It's OK
+ char *addr = strstr(message,"\r\n\r\n")+4; //looks for the address of server
+
+ addr = strtok(addr," \r\n\t"); //isolates the RasMGR host name
+
+ char *portString = strtok(NULL," \r\n\t"); //looks for the port, sended as string
+
+ char *capab = strtok(NULL," \r\n\t");
+
+ if(portString && addr && capab)
+ {
+ strcpy(serverHost,addr);
+ serverPort = strtoul( portString, (char **)NULL, 0);
+ strcpy(capability,capab);
+ TALK( "RnpClientComm::executeGetFreeServer(): got server " << serverHost << ":" << serverPort << ", capability: " << capability );
+ }
+ else
+ {
+ RMInit::logOut << "Error: Invalid answer from rasmgr." << endl;
+ LEAVE( "RnpClientComm::executeGetFreeServer(): exception, server invalid." );
+ throw r_Error( r_Error::r_Error_ServerInvalid );
+ }
+
+ }
+ else
+ {
+ char *errText = strstr(message,"\r\n\r\n")+4;
+ RMInit::logOut << "Communication error: "<<errText<< endl;
+
+ int errorCode = strtoul(errText, (char **)NULL, 0);
+
+ switch(errorCode)
+ {
+ case 802:
+ case 803:
+ case 804:
+ LEAVE( "RnpClientComm::executeGetFreeServer(): exception, errorCode = " << errorCode );
+ throw r_Error( r_Error::r_Error_AccesDenied,errorCode);
+ break;
+ case 801:
+ case 805:
+ case 806:
+ LEAVE( "RnpClientComm::executeGetFreeServer(): exception, errorCode = " << errorCode );
+ throw r_Error( r_Error::r_Error_SystemOverloaded,errorCode);
+ break;
+ case 807:
+ LEAVE( "RnpClientComm::executeGetFreeServer(): exception, errorCode = " << errorCode );
+ throw r_Error( r_Error::r_Error_DatabaseUnknown,errorCode);
+ break;
+ default :
+ LEAVE( "RnpClientComm::executeGetFreeServer(): exception, errorCode = " << errorCode );
+ throw r_Error( r_Error::r_Error_General,808 );
+ break;
+ }
+ }
+
+ LEAVE( "RnpClientComm::executeGetFreeServer() -> 1" );
+ return 1;
+}
+
+int RnpClientComm::readWholeMessage(int socket,char *destBuffer,int buffSize)
+{
+ // we read what is comming in until we encounter a '\0'
+ // this is our end-sign.
+ int totalLength=0;
+ int redNow;
+ while(1)
+ {
+ redNow = read(socket,destBuffer+totalLength,buffSize-totalLength);
+ if(redNow == -1)
+ {
+ if(errno == EINTR)
+ continue; // read was interrupted by signal
+ return -1; // another error
+ }
+ totalLength+=redNow;
+
+ if(destBuffer[totalLength-1]==0)
+ break; // THE END
+ }
+
+ TALK( "RnpClientComm::readWholeMessage(): read " << totalLength << " bytes, buffer is: " << destBuffer );
+ return totalLength;
+}
+
+int RnpClientComm::writeWholeMessage(int socket,char *destBuffer,int buffSize)
+{
+ // we write the whole message, including the ending '\0', which is already in
+ // the buffSize provided by the caller
+ int totalLength=0;
+ int writeNow;
+ while(1)
+ {
+ writeNow = write(socket,destBuffer+totalLength,buffSize-totalLength);
+ if(writeNow == -1)
+ {
+ if(errno == EINTR)
+ continue; // read was interrupted by signal
+ return -1; // another error
+ }
+ totalLength+=writeNow;
+
+ if( totalLength==buffSize )
+ break; // THE END
+ }
+
+ TALK( "RnpClientComm::writeWholeMessage(): wrote " << totalLength << " bytes, buffer is: " << destBuffer );
+ return totalLength;
+}
+
+
+void RnpClientComm::checkForRwTransaction() throw (r_Error)
+{
+ r_Transaction *trans = r_Transaction::actual_transaction;
+ if( trans == 0 || trans->get_mode() == r_Transaction::read_only )
+ {
+ TALK( "RnpClientComm::checkForRwTransaction(): throwing exception from failed TA rw check." );
+ throw r_Error( r_Error::r_Error_TransactionReadOnly );
+ }
+}
diff --git a/rnprotocol/rnpclientcomm.hh b/rnprotocol/rnpclientcomm.hh
new file mode 100644
index 0000000..cd81edd
--- /dev/null
+++ b/rnprotocol/rnpclientcomm.hh
@@ -0,0 +1,346 @@
+#ifndef RNPCLIENTCOMM_HH
+#define RNPCLIENTCOMM_HH
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#include "clientcomm/clientcomm.hh"
+#include "rnprotocol/rnpcommunication.hh"
+#include "rnprotocol/rnprasserver.hh"
+#include "clientcomm/rpcif.h"
+
+using namespace rnp;
+
+class RnpClientComm : public ClientComm, RnpBaseClientComm
+ {
+ public:
+ /// constructor getting the host name of the rasmgr host and it's listening port (default 7001).
+ RnpClientComm( const char* rasmgrHost, int rasmgrPort = RASMGRPORT ) throw( r_Error );
+
+ ~RnpClientComm() throw ();
+
+ bool effectivTypeIsRNP() throw();
+
+ //@Man: Database methods
+ //@{
+ ///
+
+ /// open database
+ int openDB( const char* database );
+ /// close current database
+ int closeDB();
+ /// create a database
+ int createDB( const char* name ) throw(r_Error);
+ /// destroy a database
+ int destroyDB( const char* name ) throw(r_Error);
+
+ ///
+ //@}
+
+ //@Man: Transaction methods
+ //@{
+ ///
+
+ /// begin transaction
+ int openTA( unsigned short readOnly = 0 ) throw(r_Error);
+ /// commit current transaction
+ int commitTA() throw(r_Error);
+ /// abort current transaction
+ int abortTA();
+
+ ///
+ //@}
+
+ //@Man: MDD methods
+ //@{
+ ///
+
+ /// inserts a MDD object in an existing MDD collection on the server
+ void insertMDD( const char* collName, r_GMarray* mar ) throw( r_Error );
+ /// gets MDD object by oid
+ r_Ref_Any getMDDByOId( const r_OId& oid ) throw( r_Error );
+
+ ///
+ //@}
+
+ //@Man: Collection methods
+ //@{
+ ///
+
+ /// creates an empty MDD collection on the server
+ void insertColl( const char* collName, const char* typeName, const r_OId& oid ) throw( r_Error );
+ /// deletes an MDD collection by name
+ void deleteCollByName( const char* collName ) throw( r_Error );
+ /// deletes an object by oid (right now, objects are collection only)
+ void deleteObjByOId( const r_OId& oid ) throw( r_Error );
+ /// removes an object from a collection
+ void removeObjFromColl( const char* name, const r_OId& oid ) throw ( r_Error );
+ /// gets collection by name
+ r_Ref_Any getCollByName( const char* name ) throw( r_Error );
+ /// gets collection by oid
+ r_Ref_Any getCollByOId ( const r_OId& oid ) throw( r_Error );
+ /// gets collection references by name
+ r_Ref_Any getCollOIdsByName( const char* name ) throw( r_Error );
+ /// gets collection references by oid
+ r_Ref_Any getCollOIdsByOId ( const r_OId& oid ) throw( r_Error );
+
+ ///
+ //@}
+
+ //@Man: Query methods
+ //@{
+ ///
+
+ /// query execution
+ void executeQuery( const r_OQL_Query& query, r_Set< r_Ref_Any >& result ) throw( r_Error );
+ /*@Doc:
+ Executes a retrieval query of type \Ref{r_OQL_Query} and returns the result. Every
+ MDD object of the MDD collection is fetched from the server and inserted
+ in the resulting \Ref{r_Set}.
+ */
+
+ /// update execution
+ void executeQuery( const r_OQL_Query& query ) throw( r_Error );
+ /*@Doc:
+ Executes an update query of type \Ref{r_OQL_Query}.
+ */
+
+ ///
+ //@}
+
+
+ //@Man: System methods
+ //@{
+ ///
+
+ /// get new oid
+ r_OId getNewOId( unsigned short objType ) throw(r_Error);
+
+ /// get oid type
+ unsigned short getObjectType( const r_OId& oid ) throw(r_Error);
+
+ /// get type structure
+ /// dallocate using delete []
+ char* getTypeStructure( const char* typeName, r_Type_Type typeType ) throw(r_Error);
+
+ ///
+ //@}
+
+ /// provides read access to my clientID
+ unsigned long getClientID() const;
+
+ /// set the preferred transfer format
+ int setTransferFormat( r_Data_Format format, const char* formatParams=NULL );
+
+ /// set the preferred storage format
+ int setStorageFormat( r_Data_Format format, const char *formatParams=NULL );
+
+
+ /// get real server name (the dinamic one, assigned by the RasMGR)
+ const char* getServerName();
+
+ /// user identification for RasMGR
+ void setUserIdentification(const char *userName, const char *plainTextPassword);
+
+ /// set maximum retry to get a server
+ void setMaxRetry(unsigned int newMaxRetry);
+
+ /// get maximum retry to get a server
+ unsigned int getMaxRetry();
+
+ void setTurbo(bool turbo);
+
+ ///
+ //@}
+
+ // obsolete, but kept because of virtual functions in base class
+ void triggerAliveSignal();
+ void sendAliveSignal();
+ const char *getExtendedErrorInfo() throw(r_Error);
+
+ void setTimeoutInterval(int seconds);
+ int getTimeoutInterval();
+
+//#### secret, unofficial functions ###########
+
+ r_OId createCollection(const char *collName, const char *collTypeName) throw(r_Error);
+
+ r_OId createMDD(const char* collName, const char* mddTypeName, const char* definitionDomain, const char *tileDomain, bool rcindex = false) throw(r_Error);
+
+ void extendMDD(r_OId mddOId, const char *stripeDomain, const char* tileDomain) throw(r_Error);
+
+ vector<r_OId> getOIdsFromCollection( const char* name ) throw( r_Error );
+
+ vector<r_OId> getOIdsFromCollection( const r_OId& oid ) throw( r_Error );
+
+ vector<r_Minterval> getTileDomains(r_OId mddOId, const char *stripeDomain) throw( r_Error );
+
+
+ void preloadTiles(r_OId mddOId, const char *tileDomain) throw(r_Error);
+
+ int getTileData(r_OId mddOId, const char *tileDomain, char *&data, bool preallocated = false) throw(r_Error);
+
+ void replaceTileData(r_OId mddOId, const char *tileDomain, const char *newData, int dataLength, const char *alfaData, int alfaLength) throw(r_Error);
+
+//#############################################
+ private:
+ /// client ID assigned to me by the server
+ int clientID;
+
+ /// the name of the rasmgr host
+ char *rasmgrHost;
+
+ /// the listening port of the rasmgr
+ int rasmgrPort;
+
+ /// the name of the server host
+ char serverHost[100]; //can't be just a pointer, it's never stored elsewhere
+
+ int serverPort;
+
+ // the name of the opened database, needed because it will be opened again and again, in a hidden operation
+ char databaseName[100];
+
+ // the capability
+ char capability[100];
+
+ /// user identification string
+ char identificationString[100];
+
+ /// requests a free server from the rasmgr, retrying maxRetry times
+ int getFreeServer(bool readwrite, bool openDB);
+
+ /// requests a free server from the rasmgr
+ int executeGetFreeServer(bool readwrite, bool openDB);
+
+ int readWholeMessage(int socket,char *destBuffer,int buffSize);
+
+ int writeWholeMessage(int socket,char *destBuffer,int buffSize);
+
+ // MD5 of password
+ int messageDigest(const char *input,char *output,const char *mdName);
+
+ /// internal function for client/server protocol handling of non-MDD collection transfer
+ void getElementCollection( r_Set< r_Ref_Any >& result ) throw(r_Error);
+
+ /// internal function for client/server protocol handling of MDD collection transfer
+ void getMDDCollection( r_Set< r_Ref_Any >& result, unsigned int isQuery ) throw(r_Error);
+
+ /// internal function for reading an MDD from the database
+ unsigned short getMDDCore( r_Ref<r_GMarray> &mdd, GetMDDRes *thisResult, unsigned int isQuery ) throw( r_Error );
+
+ /// concatenate data to an array, making sure there are no overflows (used by getMDDCore())
+ int concatArrayData( const char *source, unsigned long srcSize, char *&dest,
+ unsigned long &destSize, unsigned long &destLevel );
+
+ /// do transfer decompression
+ r_Data_Format doTransferDecompression( r_GMarray *tile, const r_Base_Type *type,
+ r_Data_Format fmt, unsigned long size );
+
+ /// internal function for converting a \Ref{r_GMarray} into its RPC representation
+ void getMarRpcRepresentation( const r_GMarray* mar, RPCMarray*& rpcMarray,
+ r_Data_Format initStorageFormat = r_Array,
+ const r_Base_Type *bt = NULL);
+
+ /// internal function for freeing data allocated by getMarRpcRepresentation()
+ void freeMarRpcRepresentation( const r_GMarray* mar, RPCMarray* rpcMarray );
+
+ /// endianness of client and server (0 means big endian)
+ int endianServer;
+ int endianClient;
+
+ /// data format for transfer compression
+ r_Data_Format transferFormat;
+ /// storage format for inserting new tiles
+ r_Data_Format storageFormat;
+ /// transfer format parameters
+ char* transferFormatParams;
+ /// storage format parameters
+ char *storageFormatParams;
+ /// parameter object for configuration
+ r_Parse_Params *clientParams;
+
+ /// policy is compress-on-server
+ int serverCompresses;
+ /// policy is exact
+ int exactFormat;
+
+ // functions which really do the connection stuff
+ void executeConnect();
+ void executeDisconnect();
+ void executeOpenDB(const char*);
+ void executeCloseDB();
+ void executeBeginTA(bool rw);
+ void executeCommitTA();
+ void executeAbortTA();
+ int executeExecuteQuery( const char* query, r_Set< r_Ref_Any >& result ) throw( r_Error );
+ GetElementRes* executeGetNextElement();
+ int executeEndTransfer();
+ GetMDDRes* executeGetNextMDD();
+ GetTileRes* executeGetNextTile();
+ void executeExecuteUpdateQuery(const char *query) throw(r_Error);
+ int executeStartInsertTransMDD(r_GMarray* mdd);
+ int executeInsertTile(bool persistent, RPCMarray* tile);
+ void executeEndInsertMDD(bool persistent);
+ int executeInitUpdate();
+ int executeStartInsertPersMDD( const char* collName, r_GMarray* mar );
+ int executeInsertMDD(const char* collName, r_GMarray* mar, RPCMarray *rpcMarray);
+ int executeInsertCollection( const char* collName, const char* typeName, const r_OId& oid );
+ r_Ref_Any executeGetCollByNameOrOId ( const char* collName, const r_OId& oid ) throw( r_Error );
+ r_Ref_Any executeGetCollOIdsByNameOrOId ( const char* collName, const r_OId& oid ) throw( r_Error );
+ int executeSetFormat( bool transferFormat, r_Data_Format format, const char* formatParams);
+ r_OId executeGetNewOId( unsigned short objType ) throw(r_Error);
+ unsigned short executeGetObjectType( const r_OId& oid ) throw(r_Error);
+ char* executeGetTypeStructure( const char* typeName, r_Type_Type typeType ) throw(r_Error);
+
+ vector<r_OId> executeGetOIdsFromCollection ( const char* collName, const r_OId& oid ) throw( r_Error );
+
+ void turboOpenDB(const char*);
+ void turboBeginTA(bool rw);
+ void turboCommitTA();
+ void turboAbortTA();
+
+ bool useTurbo;
+
+ // returns only if transaction is open and rw, otherwise throws
+ void checkForRwTransaction() throw (r_Error);
+
+ // varianta locala
+ void sendRequestGetAnswer() throw (r_Error);
+
+ int sendAndReturnStatus() throw (r_Error);
+
+ bool detectErrors();
+ // doesn't return if there is an error
+ void reassemble_r_Error() throw (r_Error);
+
+ // a very internal helper for some functions
+ void helper012d(const char* caller) throw (r_Error);
+ };
+
+#endif
diff --git a/rnprotocol/rnpclientcomm2.cc b/rnprotocol/rnpclientcomm2.cc
new file mode 100644
index 0000000..3974bd5
--- /dev/null
+++ b/rnprotocol/rnpclientcomm2.cc
@@ -0,0 +1,1226 @@
+#include "mymalloc/mymalloc.h"
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE
+ * Contains the functions which really communicate with the server
+ *
+ *
+ * COMMENTS:
+ * - return values & their meaning see servercomm.hh
+ *
+ ************************************************************/
+
+#include <openssl/evp.h>
+
+#include "rnpclientcomm.hh"
+
+#include "rasodmg/transaction.hh"
+#include "rasodmg/database.hh"
+#include "rasodmg/iterator.hh"
+#include "rasodmg/set.hh"
+#include "rasodmg/ref.hh"
+#include "rasodmg/storagelayout.hh"
+#include "rasodmg/tiling.hh"
+
+#include "raslib/minterval.hh"
+#include "raslib/rmdebug.hh"
+#include "raslib/rminit.hh"
+#include "raslib/primitivetype.hh"
+#include "raslib/complextype.hh"
+#include "raslib/structuretype.hh"
+#include "raslib/primitive.hh"
+#include "raslib/complex.hh"
+#include "raslib/structure.hh"
+#include "raslib/endian.hh"
+#include "raslib/parseparams.hh"
+// for transfer compression
+#include "compression/tilecompression.hh"
+
+#include "debug.hh"
+
+void RnpClientComm::setTurbo(bool turbo)
+{
+ ENTER( "RpcClientComm::setTurbo(" << turbo << ")" );
+ RMDBGENTER( 2, RMDebug::module_clientcomm, "RpcClientComm", "setTurbo(" << turbo << ")" );
+
+ useTurbo = turbo;
+
+ RMDBGEXIT( 2, RMDebug::module_clientcomm, "RpcClientComm", "setTurbo()" );
+ LEAVE( "RpcClientComm::setTurbo()" );
+}
+
+void RnpClientComm::executeConnect()
+{
+ ENTER( "RnpClientComm::executeConnect()" );
+
+ startRequest(RnpRasserver::cmd_connect);
+ encoder.addInt32Parameter(RnpRasserver::pmt_clientid, 0);
+ encoder.addStringParameter(RnpRasserver::pmt_capability, capability);
+ TALK( "request RnpRasserver::cmd_connect with clientID 0x" << hex << clientID << dec );
+
+ sendRequestGetAnswer();
+
+ clientID = decoder.getDataAsInteger();
+ TALK( "executeConnect: Connected, clientID 0x" << hex << clientID << dec << endl );
+
+ endianServer = decoder.getDesiredEndianness() == Rnp::bigEndian ? 0: 1;
+ endianClient = Rnp::detectHostEndianness() == Rnp::bigEndian ? 0: 1;
+
+ clearAnswer();
+
+ LEAVE( "RnpClientComm::executeConnect()" );
+}
+
+void RnpClientComm::executeDisconnect()
+{
+ ENTER( "RnpClientComm::executeDisconnect()" );
+
+ startRequest(RnpRasserver::cmd_disconnect);
+ encoder.addInt32Parameter(RnpRasserver::pmt_clientid, clientID);
+ TALK( "request RnpRasserver::cmd_disconnect with clientID 0x" << hex << clientID << dec );
+
+ clientID = -1;
+ TALK( "clientID now set to 0x" << hex << clientID << dec );
+
+ sendRequestGetAnswer();
+ clearAnswer();
+
+ LEAVE( "RnpClientComm::executeDisconnect()" );
+}
+
+void RnpClientComm::executeOpenDB(const char* lDatabaseName)
+{
+ ENTER( "RnpClientComm::executeOpenDB( lDatabaseName=" << (lDatabaseName?lDatabaseName:"(null)") << " )" );
+
+ startRequest(RnpRasserver::cmd_opendb);
+ encoder.addInt32Parameter(RnpRasserver::pmt_clientid, clientID);
+ encoder.addStringParameter(RnpRasserver::pmt_dbname, lDatabaseName);
+ TALK( "request RnpRasserver::cmd_opendb '" << lDatabaseName << "', with clientID 0x" << hex << clientID << dec );
+
+ sendRequestGetAnswer();
+ clearAnswer();
+
+ LEAVE( "RnpClientComm::executeOpenDB()" );
+}
+
+void RnpClientComm::executeCloseDB()
+{
+ ENTER( "RnpClientComm::executeCloseDB()" );
+
+ startRequest(RnpRasserver::cmd_closedb);
+ encoder.addInt32Parameter(RnpRasserver::pmt_clientid, clientID);
+ TALK( "request RnpRasserver::cmd_closedb with clientID 0x" << hex << clientID << dec );
+
+ sendRequestGetAnswer();
+ clearAnswer();
+
+ LEAVE( "RnpClientComm::executeCloseDB()" );
+}
+
+void RnpClientComm::executeBeginTA(bool rw)
+{
+ ENTER( "RnpClientComm::executeBeginTA( rw=" << rw << " )" );
+
+ startRequest(RnpRasserver::cmd_beginta);
+ encoder.addInt32Parameter(RnpRasserver::pmt_clientid, clientID);
+ encoder.addInt32Parameter(RnpRasserver::pmt_accesmode, rw);
+ TALK( "request RnpRasserver::cmd_beginta with rw=" << rw << ", clientID 0x" << hex << clientID << dec );
+
+ sendRequestGetAnswer();
+ clearAnswer();
+
+ LEAVE( "RnpClientComm::executeBeginTA()" );
+}
+
+void RnpClientComm::executeCommitTA()
+{
+ ENTER( "RnpClientComm::executeCommitTA()" );
+
+ startRequest(RnpRasserver::cmd_committa);
+ encoder.addInt32Parameter(RnpRasserver::pmt_clientid, clientID);
+ TALK( "request RnpRasserver::cmd_committa with clientID 0x" << hex << clientID << dec );
+
+ sendRequestGetAnswer();
+ clearAnswer();
+
+ LEAVE( "RnpClientComm::executeCommitTA()" );
+}
+
+void RnpClientComm::executeAbortTA()
+{
+ ENTER( "RnpClientComm::executeAbortTA()" );
+
+ startRequest(RnpRasserver::cmd_abortta);
+ encoder.addInt32Parameter(RnpRasserver::pmt_clientid, clientID);
+ TALK( "request RnpRasserver::cmd_abortta with clientID 0x" << hex << clientID << dec );
+
+ sendRequestGetAnswer();
+ clearAnswer();
+
+ LEAVE( "RnpClientComm::executeAbortTA()" );
+}
+
+void RnpClientComm::turboOpenDB(const char *lDatabaseName)
+{
+ ENTER( "RnpClientComm::turboOpenDB( lDatabaseName=" << (lDatabaseName?lDatabaseName:"(null)") << " )" );
+
+ clientID = 0;
+
+ startRequest(RnpRasserver::cmd_connect);
+ encoder.addInt32Parameter(RnpRasserver::pmt_clientid, 0); // = always clientID -- PB
+ encoder.addStringParameter(RnpRasserver::pmt_capability, capability);
+ encoder.endFragment();
+ TALK( "request RnpRasserver::cmd_connect with clientID 0x0, capability '" << capability << "'" );
+
+ encoder.startFragment(Rnp::fgt_Command,RnpRasserver::cmd_opendb);
+ encoder.addInt32Parameter(RnpRasserver::pmt_clientid, clientID);
+ encoder.addStringParameter(RnpRasserver::pmt_dbname, lDatabaseName);
+ encoder.endFragment();
+ TALK( "adding fragment RnpRasserver::cmd_opendb with db '" << lDatabaseName << "', clientID 0x" << hex << clientID << dec );
+
+ encoder.startFragment(Rnp::fgt_Command,RnpRasserver::cmd_closedb);
+ encoder.addInt32Parameter(RnpRasserver::pmt_clientid, clientID);
+ encoder.endFragment();
+ TALK( "adding fragment RnpRasserver::cmd_closedb with clientID 0x" << hex << clientID << dec );
+
+ encoder.startFragment(Rnp::fgt_Command,RnpRasserver::cmd_disconnect);
+ encoder.addInt32Parameter(RnpRasserver::pmt_clientid, clientID);
+ TALK( "adding fragment RnpRasserver::cmd_disconnect with clientID 0x" << hex << clientID << dec );
+
+ sendRequestGetAnswer();
+
+ //clientID = decoder.getDataAsInteger();
+
+ clientID = -1; // we will disconnect so we force it here
+ TALK( "RnpClientComm::turboOpenDB(): clientID set to 0x" << hex << clientID << dec );
+
+ endianServer = decoder.getDesiredEndianness() == Rnp::bigEndian ? 0: 1;
+ endianClient = Rnp::detectHostEndianness() == Rnp::bigEndian ? 0: 1;
+
+ // open
+ decoder.getNextFragment();
+ detectErrors();
+ // close
+ decoder.getNextFragment();
+ detectErrors();
+ // disconnect
+ decoder.getNextFragment();
+ detectErrors();
+
+ clearAnswer();
+
+ LEAVE( "RnpClientComm::turboOpenDB()" );
+}
+
+void RnpClientComm::turboBeginTA(bool rw)
+{
+ ENTER( "RnpClientComm::turboBeginTA( rw=" << rw << " )" );
+
+ clientID = 0;
+
+ startRequest(RnpRasserver::cmd_connect);
+ encoder.addInt32Parameter(RnpRasserver::pmt_clientid, 0);
+ encoder.addStringParameter(RnpRasserver::pmt_capability, capability);
+ encoder.endFragment();
+ TALK( "request RnpRasserver::cmd_connect with clientID 0x" << hex << clientID << dec << ", capability '" << capability << "'" );
+
+ encoder.startFragment(Rnp::fgt_Command,RnpRasserver::cmd_opendb);
+ encoder.addInt32Parameter(RnpRasserver::pmt_clientid, clientID);
+ encoder.addStringParameter(RnpRasserver::pmt_dbname, databaseName);
+ encoder.endFragment();
+ TALK( "adding fragment RnpRasserver::cmd_opendb '" << databaseName << "', with clientID 0x" << hex << clientID << dec );
+
+ encoder.startFragment(Rnp::fgt_Command,RnpRasserver::cmd_beginta);
+ encoder.addInt32Parameter(RnpRasserver::pmt_clientid, clientID);
+ encoder.addInt32Parameter(RnpRasserver::pmt_accesmode, rw);
+ TALK( "adding fragment RnpRasserver::cmd_beginta with rw=" << rw << ", clientID 0x" << hex << clientID << dec );
+
+ sendRequestGetAnswer();
+
+ clientID = decoder.getDataAsInteger();
+ TALK( "rceived clientID 0x" << hex << clientID << dec );
+ endianServer = decoder.getDesiredEndianness() == Rnp::bigEndian ? 0: 1;
+ endianClient = Rnp::detectHostEndianness() == Rnp::bigEndian ? 0: 1;
+
+ // open
+ decoder.getNextFragment();
+ detectErrors();
+
+ // beginTA
+ decoder.getNextFragment();
+ detectErrors();
+
+ clearAnswer();
+
+ LEAVE( "RnpClientComm::turboBeginTA()" );
+}
+
+void RnpClientComm::turboCommitTA()
+{
+ ENTER( "RnpClientComm::turboCommitTA()" );
+
+ startRequest(RnpRasserver::cmd_committa);
+ encoder.addInt32Parameter(RnpRasserver::pmt_clientid, clientID);
+ encoder.endFragment();
+ TALK( "request RnpRasserver::cmd_committa with clientID 0x" << hex << clientID << dec );
+
+ encoder.startFragment(Rnp::fgt_Command,RnpRasserver::cmd_closedb);
+ encoder.addInt32Parameter(RnpRasserver::pmt_clientid, clientID);
+ encoder.endFragment();
+ TALK( "adding fragment RnpRasserver::cmd_closedb with clientID 0x" << hex << clientID << dec );
+
+ encoder.startFragment(Rnp::fgt_Command,RnpRasserver::cmd_disconnect);
+ encoder.addInt32Parameter(RnpRasserver::pmt_clientid, clientID);
+ TALK( "adding fragment RnpRasserver::cmd_disconnect with clientID 0x" << hex << clientID << dec );
+
+ sendRequestGetAnswer();
+
+ // close
+ decoder.getNextFragment();
+ detectErrors();
+
+ // disconnect
+ decoder.getNextFragment();
+ detectErrors();
+
+ clientID = -1;
+ TALK( "resetting: clientID 0x" << hex << clientID << dec );
+ clearAnswer();
+
+ LEAVE( "RnpClientComm::turboCommitTA()" );
+}
+void RnpClientComm::turboAbortTA()
+{
+ ENTER( "RnpClientComm::turboAbortTA()" );
+
+ startRequest(RnpRasserver::cmd_abortta);
+ encoder.addInt32Parameter(RnpRasserver::pmt_clientid, clientID);
+ encoder.endFragment();
+ TALK( "request RnpRasserver::cmd_abortta with clientID 0x" << hex << clientID << dec );
+
+ encoder.startFragment(Rnp::fgt_Command,RnpRasserver::cmd_closedb);
+ encoder.addInt32Parameter(RnpRasserver::pmt_clientid, clientID);
+ encoder.endFragment();
+ TALK( "adding fragment RnpRasserver::cmd_closedb with clientID 0x" << hex << clientID << dec );
+
+ encoder.startFragment(Rnp::fgt_Command,RnpRasserver::cmd_disconnect);
+ encoder.addInt32Parameter(RnpRasserver::pmt_clientid, clientID);
+ TALK( "adding fragment RnpRasserver::cmd_disconnect with clientID 0x" << hex << clientID << dec );
+
+ sendRequestGetAnswer();
+
+ // close
+ decoder.getNextFragment();
+ detectErrors();
+
+ // disconnect
+ decoder.getNextFragment();
+ detectErrors();
+
+ clientID = -1;
+ TALK( "resetting: clientID 0x" << hex << clientID << dec );
+
+ clearAnswer();
+
+ LEAVE( "RnpClientComm::turboAbortTA()" );
+}
+
+//---------------------------------------------------------------------------------
+int RnpClientComm::executeStartInsertPersMDD( const char* collName, r_GMarray* mar )
+{
+ ENTER( "RnpClientComm::executeStartInsertPersMDD( collName=" << (collName?collName:"(null)") << ", mar=" << ((unsigned long) mar) << " )" );
+
+ startRequest(RnpRasserver::cmd_startinsPmdd);
+ encoder.addInt32Parameter(RnpRasserver::pmt_clientid, clientID);
+ encoder.addStringParameter(RnpRasserver::pmt_collname, collName);
+
+ char *domain = mar->spatial_domain().get_string_representation();
+ encoder.addStringParameter(RnpRasserver::pmt_domain, domain);
+
+ encoder.addInt32Parameter(RnpRasserver::pmt_typelength, mar->get_type_length());
+ encoder.addStringParameter(RnpRasserver::pmt_typename, mar->get_type_name());
+ encoder.addStringParameter(RnpRasserver::pmt_oidstring, mar->get_oid().get_string_representation());
+
+ TALK( "request RnpRasserver::cmd_startinsPmdd with collname '" << collName << "', domain " << domain << ", typelength " << mar->get_type_length() << ", typename '" << mar->get_type_name() << ", oid " << mar->get_oid().get_string_representation() << ", clientID 0x" << hex << clientID << dec );
+
+ free(domain);
+
+ int result = sendAndReturnStatus();
+
+ ENTER( "RnpClientComm::executeStartInsertPersMDD() -> " << result );
+ return result;
+}
+
+int RnpClientComm::executeExecuteQuery( const char* query, r_Set< r_Ref_Any >& result ) throw( r_Error )
+{
+ ENTER( "RnpClientComm::executeExecuteQuery( query=" << (query?query:"(null)") << ", result=" << ((unsigned long) &result) << " )" );
+
+ startRequest(RnpRasserver::cmd_queryrpc);
+ encoder.adjustBufferSize(strlen(query));
+
+ encoder.addInt32Parameter(RnpRasserver::pmt_clientid, clientID);
+ encoder.addStringParameter(RnpRasserver::pmt_querystring, query);
+ TALK( "request RnpRasserver::cmd_queryrpc with query '" << query << ", clientID 0x" << hex << clientID << dec );
+
+ sendRequestGetAnswer();
+
+ int status = decoder.getDataAsInteger();
+ decoder.getNextParameter();
+ int errNo = decoder.getDataAsInteger();
+ decoder.getNextParameter();
+ int lineNo = decoder.getDataAsInteger();
+ decoder.getNextParameter();
+ int colNo = decoder.getDataAsInteger();
+ decoder.getNextParameter();
+ const char* token = decoder.getDataAsString();
+ decoder.getNextParameter();
+ const char* typeName = decoder.getDataAsString();
+ decoder.getNextParameter();
+ const char* typeStructure = decoder.getDataAsString();
+
+ if(status == 0 || status == 1)
+ {
+ result.set_type_by_name( typeName );
+ result.set_type_structure( typeStructure );
+ }
+ // status == 2 - empty result
+
+ if( status == 4 || status == 5 )
+ {
+ r_Equery_execution_failed err( errNo, lineNo, colNo, token );
+ clearAnswer();
+ LEAVE( "RnpClientComm::executeExecuteQuery() exception: status=" << status );
+ throw err;
+ }
+ clearAnswer();
+
+ LEAVE( "RnpClientComm::executeExecuteQuery() -> " << status );
+ return status;
+}
+
+int RnpClientComm::executeEndTransfer()
+{
+ ENTER( "RnpClientComm::executeEndTransfer()" );
+
+ startRequest(RnpRasserver::cmd_endtransfer);
+ encoder.addInt32Parameter(RnpRasserver::pmt_clientid, clientID);
+ TALK( "request RnpRasserver::cmd_endtransfer with clientID 0x" << hex << clientID << dec );
+
+ int result = sendAndReturnStatus();
+
+ LEAVE( "RnpClientComm::executeEndTransfer() -> " << result );
+ return result;
+}
+
+GetElementRes* RnpClientComm::executeGetNextElement()
+{
+ ENTER( "RnpClientComm::executeGetNextElement()" );
+
+ startRequest(RnpRasserver::cmd_getnextelem);
+ encoder.addInt32Parameter(RnpRasserver::pmt_clientid, clientID);
+ TALK( "request RnpRasserver::cmd_getnextelem with clientID 0x" << hex << clientID << dec );
+
+ sendRequestGetAnswer();
+
+ GetElementRes *result = new GetElementRes;
+ result->data.confarray_val = NULL;
+
+ result->status = decoder.getDataAsInteger();
+
+ if(decoder.countParameters() == 2)
+ {
+ decoder.getNextParameter();
+ result->data.confarray_len = decoder.getDataLength();
+ result->data.confarray_val = new char[decoder.getDataLength()];
+
+ memcpy(result->data.confarray_val, decoder.getData(), decoder.getDataLength());
+
+ }
+
+ clearAnswer();
+
+ LEAVE( "RnpClientComm::executeGetNextElement() -> " << result );
+ return result;
+}
+
+
+int RnpClientComm::executeInsertMDD(const char* collName, r_GMarray* mar, RPCMarray *rpcMarray)
+{
+ ENTER( "RnpClientComm::executeInsertMDD( collName=" << (collName?collName:"(null)") << ", mar=" << ((unsigned long) mar) << ", rpcMarray=" << ((unsigned long) rpcMarray) << " )" );
+
+ int size = rpcMarray->data.confarray_len;
+ startRequest(RnpRasserver::cmd_insertmdd, RNP_DEFAULTBUFFERSIZE + size);
+ encoder.addInt32Parameter( RnpRasserver::pmt_clientid, clientID);
+ encoder.addStringParameter( RnpRasserver::pmt_collname, collName);
+ encoder.addStringParameter( RnpRasserver::pmt_typename, mar->get_type_name());
+ encoder.addStringParameter( RnpRasserver::pmt_oidstring, mar->get_oid().get_string_representation());
+ encoder.addStringParameter( RnpRasserver::pmt_domain, rpcMarray->domain);
+ encoder.addInt32Parameter( RnpRasserver::pmt_typelength, rpcMarray->cellTypeLength);
+ encoder.addInt32Parameter( RnpRasserver::pmt_currentformat, rpcMarray->currentFormat);
+ encoder.addInt32Parameter( RnpRasserver::pmt_storageformat, rpcMarray->storageFormat);
+ encoder.addOpaqueParameter( RnpRasserver::pmt_tiledata, rpcMarray->data.confarray_val, size);
+ TALK( "request RnpRasserver::cmd_insertmdd with collection '" << collName << ", ..., clientID 0x" << hex << clientID << dec );
+
+ int result = sendAndReturnStatus();
+
+ LEAVE( "RnpClientComm::executeInsertMDD() -> " << result );
+ return result;
+}
+
+int RnpClientComm::executeInsertCollection( const char* collName, const char* typeName, const r_OId& oid )
+{
+ ENTER( "RnpClientComm::executeInsertCollection( collName=" << (collName?collName:"(null)") << ", typeName=" << (typeName?typeName:"(null)") << ", oid=" << oid << " )" );
+
+ startRequest(RnpRasserver::cmd_insertcoll);
+ encoder.addInt32Parameter(RnpRasserver::pmt_clientid, clientID);
+ encoder.addStringParameter(RnpRasserver::pmt_collname, collName);
+ encoder.addStringParameter(RnpRasserver::pmt_typename, typeName);
+ encoder.addStringParameter(RnpRasserver::pmt_oidstring, oid.get_string_representation());
+ TALK( "request RnpRasserver::cmd_insertcoll collection '" << collName << ", ..., with clientID 0x" << hex << clientID << dec );
+
+ int result = sendAndReturnStatus();
+ LEAVE( "RnpClientComm::executeInsertCollection() -> " << result );
+ return result;
+}
+
+// common function using the dynamic parameter facility of RNP
+r_Ref_Any RnpClientComm::executeGetCollByNameOrOId ( const char* collName, const r_OId& oid ) throw( r_Error )
+{
+ ENTER( "RnpClientComm::executeGetCollByNameOrOId( collName=" << (collName?collName:"(null)") << ", oid=" << oid << " )" );
+
+ startRequest(RnpRasserver::cmd_getcoll);
+ encoder.addInt32Parameter(RnpRasserver::pmt_clientid, clientID);
+ if( collName != NULL)
+ encoder.addStringParameter(RnpRasserver::pmt_collname, collName);
+ else
+ encoder.addStringParameter(RnpRasserver::pmt_oidstring, oid.get_string_representation());
+ TALK( "request RnpRasserver::cmd_getcoll with ..., clientID 0x" << hex << clientID << dec );
+
+ sendRequestGetAnswer();
+
+ int status = decoder.getDataAsInteger();
+ decoder.getNextParameter(); const char *typeName = decoder.getDataAsString();
+ decoder.getNextParameter(); const char *typeStructure = decoder.getDataAsString();
+ decoder.getNextParameter(); const char *oidstring = decoder.getDataAsString();
+ decoder.getNextParameter(); const char *collectionName= decoder.getDataAsString();
+
+ r_Set< r_Ref_Any >* set = 0;
+
+ if( status != 0 && status != 1 )
+ {
+ r_Error err;
+ switch( status )
+ {
+ case 2:
+ err = r_Error( r_Error::r_Error_ObjectUnknown );
+ break;
+ case 3:
+ err = r_Error( r_Error::r_Error_ClientUnknown );
+ break;
+ default:
+ err = r_Error( r_Error::r_Error_TransferFailed );
+ break;
+ }
+ clearAnswer();
+ LEAVE( "RnpClientComm::executeGetCollByNameOrOId(): exception, status = " << status );
+ throw err;
+ }
+
+ // create the set
+ r_OId rOId( oidstring );
+ set = new ( r_Database::actual_database, r_Object::read, rOId ) r_Set< r_Ref_Any >;
+
+ // initialize data elements
+ set->set_type_by_name ( typeName );
+ set->set_type_structure( typeStructure );
+ set->set_object_name ( collectionName );
+
+ clearAnswer();
+
+ // get collection elements
+ if( status == 0 )
+ getMDDCollection( *set, 0 );
+ // else rpcStatus == 1 -> Result collection is empty and nothing has to be got.
+
+ r_Ref_Any result = r_Ref_Any( set->get_oid(), set );
+ LEAVE( "RnpClientComm::executeGetCollByNameOrOId() -> (result set not displayed)" );
+ return result;
+}
+
+
+// common function using the dynamic parameter facility of RNP
+r_Ref_Any RnpClientComm::executeGetCollOIdsByNameOrOId ( const char* collName, const r_OId& oid ) throw( r_Error )
+{
+ ENTER( "RnpClientComm::executeGetCollOIdsByNameOrOId( collName=" << (collName?collName:"(null)") << ", oid=" << oid << " )" );
+
+ startRequest(RnpRasserver::cmd_getcolloids);
+ encoder.addInt32Parameter(RnpRasserver::pmt_clientid, clientID);
+ if( collName != NULL)
+ encoder.addStringParameter(RnpRasserver::pmt_collname, collName);
+ else
+ encoder.addStringParameter(RnpRasserver::pmt_oidstring, oid.get_string_representation());
+ TALK( "request RnpRasserver::cmd_getcolloids with ..., clientID 0x" << hex << clientID << dec );
+
+ sendRequestGetAnswer();
+
+ int status = decoder.getDataAsInteger();
+ decoder.getNextParameter(); const char *typeName = decoder.getDataAsString();
+ decoder.getNextParameter(); const char *typeStructure = decoder.getDataAsString();
+ decoder.getNextParameter(); const char *oidstring = decoder.getDataAsString();
+ decoder.getNextParameter(); const char *collectionName= decoder.getDataAsString();
+
+ r_Set< r_Ref<r_GMarray> >* set = 0;
+
+ if( status != 0 && status != 1 )
+ {
+ r_Error err;
+ switch( status )
+ {
+ case 2:
+ err = r_Error( r_Error::r_Error_ObjectUnknown );
+ break;
+ case 3:
+ err = r_Error( r_Error::r_Error_ClientUnknown );
+ break;
+ default:
+ err = r_Error( r_Error::r_Error_TransferFailed );
+ break;
+ }
+ clearAnswer();
+ LEAVE( "RnpClientComm::executeGetCollOIdsByNameOrOId(): exception, status = " << status );
+ throw err;
+ }
+
+ // create the set
+ r_OId rOId( oidstring );
+ set = new ( r_Database::actual_database, r_Object::read, rOId ) r_Set< r_Ref< r_GMarray > >;
+
+ set->set_type_by_name ( typeName );
+ set->set_type_structure( typeStructure );
+ set->set_object_name ( collName );
+
+ // fill set with oids
+ if( status == 0 )
+ {
+ while(decoder.getNextParameter() != 0)
+ {
+ r_OId roid( decoder.getDataAsString() );
+ set->insert_element( r_Ref<r_GMarray>(roid), 1 );
+ }
+ }
+
+ clearAnswer();
+
+ r_Ref_Any result = r_Ref_Any( set->get_oid(), set );
+ LEAVE( "RnpClientComm::executeGetCollOIdsByNameOrOId() -> (result not displayed)" );
+ return result;
+ }
+
+
+GetMDDRes* RnpClientComm::executeGetNextMDD()
+{
+ ENTER( "RnpClientComm::executeGetNextMDD()" );
+
+ startRequest(RnpRasserver::cmd_getnextmdd);
+ encoder.addInt32Parameter(RnpRasserver::pmt_clientid, clientID);
+ TALK( "request RnpRasserver::cmd_getnextmdd with clientID 0x" << hex << clientID << dec );
+
+ sendRequestGetAnswer();
+
+ GetMDDRes* result = new GetMDDRes;
+
+ result->status = decoder.getDataAsInteger();
+ decoder.getNextParameter(); result->domain = strdup(decoder.getDataAsString());
+ decoder.getNextParameter(); result->typeName = strdup(decoder.getDataAsString());
+ decoder.getNextParameter(); result->typeStructure = strdup(decoder.getDataAsString());
+ decoder.getNextParameter(); result->oid = strdup(decoder.getDataAsString());
+ decoder.getNextParameter(); result->currentFormat = decoder.getDataAsInteger();
+
+ clearAnswer();
+
+ LEAVE( "RnpClientComm::executeGetNextMDD() -> " << result );
+ return result;
+}
+
+GetTileRes* RnpClientComm::executeGetNextTile()
+{
+ ENTER( "RnpClientComm::executeGetNextTile()" );
+
+ startRequest(RnpRasserver::cmd_getnexttile);
+ encoder.addInt32Parameter(RnpRasserver::pmt_clientid, clientID);
+ TALK( "request RnpRasserver::cmd_getnexttile with clientID 0x" << hex << clientID << dec );
+
+ sendRequestGetAnswer();
+
+ GetTileRes* result = new GetTileRes;
+ result->marray = new RPCMarray;
+
+ result->status = decoder.getDataAsInteger();
+ if(decoder.getNextParameter() != 0)
+ {
+ result->marray->domain = strdup(decoder.getDataAsString());
+ decoder.getNextParameter(); result->marray->cellTypeLength = decoder.getDataAsInteger();
+ decoder.getNextParameter(); result->marray->currentFormat = decoder.getDataAsInteger();
+ decoder.getNextParameter(); result->marray->storageFormat = decoder.getDataAsInteger();
+ decoder.getNextParameter();
+ int length = decoder.getDataLength();
+ result->marray->data.confarray_len = length;
+ result->marray->data.confarray_val = (char*)mymalloc(length);
+ memcpy(result->marray->data.confarray_val, decoder.getData(), length);
+ }
+ else
+ {
+ result->marray->domain = 0;
+ result->marray->data.confarray_val = 0;
+ }
+ clearAnswer();
+
+ LEAVE( "RnpClientComm::executeGetNextTile() -> " << result );
+ return result;
+}
+
+int RnpClientComm::executeInitUpdate()
+{
+ ENTER( "RnpClientComm::executeInitUpdate()" );
+
+ startRequest(RnpRasserver::cmd_initupdate);
+ encoder.addInt32Parameter(RnpRasserver::pmt_clientid, clientID);
+ TALK( "adding fragment XXX with clientID 0x" << hex << clientID << dec );
+
+ int result = sendAndReturnStatus();
+ LEAVE( "RnpClientComm::executeInitUpdate() -> " << result );
+ return result;
+}
+
+int RnpClientComm::executeStartInsertTransMDD(r_GMarray* mdd)
+{
+ ENTER( "RnpClientComm::executeStartInsertTransMDD( mdd=" << ((unsigned long) mdd) << " )" );
+
+ startRequest(RnpRasserver::cmd_startinsTmdd);
+ encoder.addInt32Parameter( RnpRasserver::pmt_clientid, clientID);
+ encoder.addStringParameter( RnpRasserver::pmt_domain, mdd->spatial_domain().get_string_representation());
+ encoder.addInt32Parameter( RnpRasserver::pmt_typelength, mdd->get_type_length());
+ encoder.addStringParameter( RnpRasserver::pmt_typename, mdd->get_type_name());
+ TALK( "request RnpRasserver::cmd_startinsTmdd with ..., clientID 0x" << hex << clientID << dec );
+
+ int result = sendAndReturnStatus();
+ LEAVE( "RnpClientComm::executeStartInsertTransMDD() -> " << result );
+ return result;
+}
+
+int RnpClientComm::executeInsertTile(bool persistent, RPCMarray *tile)
+{
+ ENTER( "RnpClientComm::executeInsertTile( persistent=" << persistent << ", tile=" << ((unsigned long) tile) << " )" );
+
+ int size = tile->data.confarray_len;
+ startRequest(RnpRasserver::cmd_inserttile, RNP_DEFAULTBUFFERSIZE + size);
+ encoder.addInt32Parameter( RnpRasserver::pmt_clientid, clientID);
+ encoder.addInt32Parameter( RnpRasserver::pmt_ispersistent, persistent ? 1:0);
+ encoder.addStringParameter( RnpRasserver::pmt_domain, tile->domain);
+ encoder.addInt32Parameter( RnpRasserver::pmt_typelength, tile->cellTypeLength);
+ encoder.addInt32Parameter( RnpRasserver::pmt_currentformat, tile->currentFormat);
+ encoder.addInt32Parameter( RnpRasserver::pmt_storageformat, tile->storageFormat);
+ encoder.addOpaqueParameter( RnpRasserver::pmt_tiledata, tile->data.confarray_val, size);
+ TALK( "request RnpRasserver::cmd_inserttile with ..., clientID 0x" << hex << clientID << dec );
+
+ int result = sendAndReturnStatus();
+
+ LEAVE( "RnpClientComm::executeInsertTile() -> " << result );
+ return result;
+}
+
+void RnpClientComm::executeEndInsertMDD(bool persistent)
+{
+ ENTER( "RnpClientComm::executeEndInsertMDD( persistent=" << persistent << " )" );
+
+ startRequest(RnpRasserver::cmd_endinsmdd);
+ encoder.addInt32Parameter(RnpRasserver::pmt_clientid, clientID);
+ encoder.addInt32Parameter(RnpRasserver::pmt_ispersistent, persistent ? 1:0);
+ TALK( "request RnpRasserver::cmd_endinsmdd with persistent " << persistent << ", clientID 0x" << hex << clientID << dec );
+
+ sendRequestGetAnswer();
+ clearAnswer();
+
+ LEAVE( "RnpClientComm::executeEndInsertMDD()" );
+}
+
+void RnpClientComm::executeExecuteUpdateQuery(const char *query) throw(r_Error)
+ {
+ ENTER( "RnpClientComm::executeExecuteUpdateQuery( query=" << (query?query:"(null)") << " )" );
+
+ startRequest(RnpRasserver::cmd_updaterpc);
+ encoder.adjustBufferSize(strlen(query));
+ encoder.addInt32Parameter(RnpRasserver::pmt_clientid, clientID);
+ encoder.addStringParameter(RnpRasserver::pmt_querystring, query);
+ TALK( "request RnpRasserver::cmd_updaterpc with query '" << query << "', clientID 0x" << hex << clientID << dec );
+
+ sendRequestGetAnswer();
+ int status = decoder.getDataAsInteger();
+ decoder.getNextParameter();
+ int errNo = decoder.getDataAsInteger();
+ decoder.getNextParameter();
+ int lineNo = decoder.getDataAsInteger();
+ decoder.getNextParameter();
+ int colNo = decoder.getDataAsInteger();
+ decoder.getNextParameter();
+ const char* token = decoder.getDataAsString();
+
+ clearAnswer();
+
+ if( status == 2 || status == 3 )
+ {
+ LEAVE( "RnpClientComm::executeExecuteUpdateQuery(): exception, status = " << status );
+ throw r_Equery_execution_failed( errNo, lineNo, colNo, token );
+ }
+
+ if( status == 1 )
+ {
+ LEAVE( "RnpClientComm::executeExecuteUpdateQuery(): exception, status = " << status );
+ throw r_Error( r_Error::r_Error_ClientUnknown );
+ }
+
+ if( status > 3 )
+ {
+ LEAVE( "RnpClientComm::executeExecuteUpdateQuery(): exception, status = " << status );
+ throw r_Error( r_Error::r_Error_TransferFailed );
+ }
+
+ LEAVE( "RnpClientComm::executeExecuteUpdateQuery()" );
+}
+
+r_OId RnpClientComm::executeGetNewOId( unsigned short objType ) throw(r_Error)
+{
+ //cout<<" RnpClientComm::getNewOId: not implemented"<<endl;
+
+ ENTER( "RnpClientComm::executeGetNewOId( objType=" << objType << " )" );
+
+ startRequest(RnpRasserver::cmd_getnewoid);
+ encoder.addInt32Parameter(RnpRasserver::pmt_clientid, clientID);
+ encoder.addInt32Parameter(RnpRasserver::pmt_objecttype, objType);
+ TALK( "request RnpRasserver::cmd_getnewoid with ..., clientID 0x" << hex << clientID << dec );
+
+ sendRequestGetAnswer();
+
+ r_OId oid( decoder.getDataAsString() );
+
+ clearAnswer();
+
+ LEAVE( "RnpClientComm::executeGetNewOId() -> " << oid );
+ return oid;
+}
+
+unsigned short RnpClientComm::executeGetObjectType( const r_OId& oid ) throw(r_Error)
+{
+ ENTER( "RnpClientComm::executeGetObjectType( oid=" << oid << " )" );
+
+ startRequest(RnpRasserver::cmd_getobjecttype);
+ encoder.addInt32Parameter(RnpRasserver::pmt_clientid, clientID);
+ encoder.addStringParameter(RnpRasserver::pmt_oidstring, oid.get_string_representation());
+ TALK( "request RnpRasserver::cmd_getobjecttype with ..., clientID 0x" << hex << clientID << dec );
+
+ sendRequestGetAnswer();
+
+ int status = decoder.getDataAsInteger();
+ switch( status )
+ {
+ case 0:
+ break; //OK
+ case 1:
+ clearAnswer();
+ LEAVE( "RnpClientComm::executeGetObjectType(): exception, status = " << status );
+ throw r_Error( r_Error::r_Error_ClientUnknown );
+ break;
+ case 2:
+ clearAnswer();
+ LEAVE( "RnpClientComm::executeGetObjectType(): exception, status = " << status );
+ throw r_Error( r_Error::r_Error_ObjectUnknown );
+ break;
+ default:
+ clearAnswer();
+ LEAVE( "RnpClientComm::executeGetObjectType(): exception, status = " << status );
+ throw r_Error( r_Error::r_Error_TransferFailed );
+ break;
+ }
+
+ decoder.getNextParameter(); unsigned short objType = decoder.getDataAsInteger();
+
+ clearAnswer();
+
+ LEAVE( "RnpClientComm::executeGetObjectType() -> " << objType );
+ return objType;
+}
+
+char* RnpClientComm::executeGetTypeStructure( const char* typeName, r_Type_Type typeType ) throw(r_Error)
+{
+ ENTER( "RnpClientComm::executeGetTypeStructure( typeName=" << (typeName?typeName:"(null)") << ", typeType=" << typeType << " )" );
+
+ startRequest(RnpRasserver::cmd_gettypestruct);
+ encoder.addInt32Parameter(RnpRasserver::pmt_clientid, clientID);
+ encoder.addStringParameter(RnpRasserver::pmt_typename, typeName);
+ encoder.addInt32Parameter(RnpRasserver::pmt_typetype, typeType);
+ TALK( "request RnpRasserver::cmd_gettypestruct with ..., clientID 0x" << hex << clientID << dec );
+
+ sendRequestGetAnswer();
+
+ int status = decoder.getDataAsInteger();
+ switch(status)
+ {
+ case 0:
+ break; //OK
+ case 1:
+ clearAnswer();
+ LEAVE( "RnpClientComm::executeGetTypeStructure(): exception, status = " << status );
+ throw r_Error( r_Error::r_Error_TransactionNotOpen );
+ break;
+ case 2:
+ clearAnswer();
+ LEAVE( "RnpClientComm::executeGetTypeStructure(): exception, status = " << status );
+ throw r_Error( r_Error::r_Error_DatabaseClassUndefined );
+ break;
+ default:
+ clearAnswer();
+ LEAVE( "RnpClientComm::executeGetTypeStructure(): exception, status = " << status );
+ throw r_Error( r_Error::r_Error_TransferFailed );
+ break;
+ }
+
+ decoder.getNextParameter();
+ char* typeStructure = new char [decoder.getDataLength() + 1];
+ strcpy(typeStructure, decoder.getDataAsString());
+
+ clearAnswer();
+
+ LEAVE( "RnpClientComm::executeGetTypeStructure() -> " << typeStructure );
+ return typeStructure;
+}
+
+int RnpClientComm::executeSetFormat( bool lTransferFormat, r_Data_Format format, const char* formatParams)
+{
+ ENTER( "RnpClientComm::executeSetFormat( lTransferFormat=" << lTransferFormat << ", format=" << format << ", formatParams=" << (formatParams?formatParams:"(null)") << " )" );
+
+ startRequest(RnpRasserver::cmd_setformat);
+ encoder.addInt32Parameter( RnpRasserver::pmt_clientid, clientID);
+ encoder.addInt32Parameter( RnpRasserver::pmt_whichformat, lTransferFormat);
+ encoder.addInt32Parameter( RnpRasserver::pmt_format, format);
+ encoder.addStringParameter(RnpRasserver::pmt_formatparams, formatParams);
+ TALK( "request RnpRasserver::cmd_setformat with ..., clientID 0x" << hex << clientID << dec );
+
+ sendRequestGetAnswer();
+
+ int status = decoder.getDataAsInteger();
+
+ clearAnswer();
+
+ LEAVE( "RnpClientComm::executeSetFormat() -> " << status );
+ return status;
+}
+
+//----------------------------------------------------------
+int RnpClientComm::sendAndReturnStatus() throw (r_Error)
+{
+ ENTER( "RnpClientComm::sendAndReturnStatus()" );
+
+ sendRequestGetAnswer();
+
+ int status = decoder.getDataAsInteger();
+
+ clearAnswer();
+
+ LEAVE( "RnpClientComm::sendAndReturnStatus() -> " << status );
+ return status;
+}
+
+void RnpClientComm::sendRequestGetAnswer() throw (r_Error)
+{
+ ENTER( "RnpClientComm::sendRequestGetAnswer()" );
+
+ RnpBaseClientComm::setMaxRetry(RNP_MAX_RETRY); // defined in raslib/rminit.hh -- PB 2005-sep-01
+ if(RnpBaseClientComm::sendRequestGetAnswer() == false)
+ {
+ clearAnswer();
+ LEAVE( "RnpClientComm::sendRequestGetAnswer(): exception, sendRequestGetAnswer() == false" );
+ throw r_Error( r_Error::r_Error_TransferFailed);
+ }
+
+ detectErrors();
+ if(decoder.countParameters() > 0) decoder.getFirstParameter();
+
+ LEAVE( "RnpClientComm::sendRequestGetAnswer()" );
+}
+
+void RnpClientComm::helper012d(const char* caller) throw (r_Error)
+{
+ int status = sendAndReturnStatus();
+
+ switch( status )
+ {
+ case 0:
+ break;
+ case 1:
+ TALK( "RnpClientComm::helper012d( " << (caller?caller:"(null)") << " ): error: status = " << status );
+ throw r_Error( r_Error::r_Error_ClientUnknown );
+ break;
+ case 2:
+ TALK( "RnpClientComm::helper012d( " << (caller?caller:"(null)") << " ): error: status = " << status );
+ throw r_Error( r_Error::r_Error_ObjectUnknown );
+ break;
+ default:
+ TALK( "RnpClientComm::helper012d( " << (caller?caller:"(null)") << " ): error: status = " << status );
+ throw r_Error( r_Error::r_Error_General );
+ break;
+ }
+}
+
+bool RnpClientComm::detectErrors()
+{
+ if(decoder.getFragmentType() != Rnp::fgt_Error)
+ return false;
+
+ reassemble_r_Error() ;
+
+ return true;
+}
+
+void RnpClientComm::reassemble_r_Error() throw (r_Error)
+{
+ decoder.getFirstParameter();
+ if(decoder.getParameterType() != Rnp::ert_Other)
+ return;
+
+ decoder.getNextParameter();
+
+ r_Error *temp = r_Error::getAnyError((char*)decoder.getDataAsString());
+
+ r_Error err = *temp;
+
+ delete temp;
+
+ TALK( "npClientComm::reassemble_r_Error() throwing exception: " << (char*)decoder.getDataAsString() );
+ throw err;
+}
+
+void RnpClientComm::setTimeoutInterval(int seconds)
+{
+ akg::NbJob::setTimeoutInterval(seconds);
+}
+
+int RnpClientComm::getTimeoutInterval()
+{
+ return akg::NbJob::getTimeoutInterval();
+}
+
+//## unofficial functions
+
+r_OId RnpClientComm::createCollection(const char *collName, const char *collTypeName) throw(r_Error)
+{
+ ENTER( "RnpClientComm::createCollection( collName=" << (collName?collName:"(null)") << ", collTypeName=" << (collTypeName?collTypeName:"(null)") << " )" );
+
+ checkForRwTransaction();
+ startRequest(RnpRasserver::cmd_createcollection);
+ encoder.addInt32Parameter( RnpRasserver::pmt_clientid, clientID);
+ encoder.addStringParameter(RnpRasserver::pmt_collname, collName);
+ encoder.addStringParameter(RnpRasserver::pmt_typename, collTypeName);
+ TALK( "request RnpRasserver::cmd_createcollection with ..., clientID 0x" << hex << clientID << dec );
+
+ sendRequestGetAnswer();
+
+ r_OId oid(decoder.getDataAsString());
+
+ clearAnswer();
+
+ LEAVE( "RnpClientComm::createCollection() -> " << oid );
+ return oid;
+}
+
+r_OId RnpClientComm::createMDD(const char* collName, const char* mddTypeName, const char* definitionDomain, const char *tileDomain, bool rcindex) throw(r_Error)
+{
+ ENTER( "RnpClientComm::createMDD( collName=" << (collName?collName:"(null)") << "; mddTypeName=" << (mddTypeName?mddTypeName:"(null)") << ", definitionDomain=" << (definitionDomain?definitionDomain:"(null)") << ", tileDomain=" << (tileDomain?tileDomain:"(null)") << ", rcindex=" << rcindex << " )" );
+
+ checkForRwTransaction();
+ startRequest(RnpRasserver::cmd_createmdd);
+ encoder.addInt32Parameter( RnpRasserver::pmt_clientid, clientID);
+ encoder.addStringParameter(RnpRasserver::pmt_collname, collName);
+ encoder.addStringParameter(RnpRasserver::pmt_typename, mddTypeName);
+ encoder.addStringParameter(RnpRasserver::pmt_domain, definitionDomain);
+ encoder.addInt32Parameter( RnpRasserver::pmt_indextype, rcindex);
+ encoder.addStringParameter(RnpRasserver::pmt_domain, tileDomain);
+ TALK( "request RnpRasserver::cmd_createmdd with collName " << collName << ", mddTypeName " << mddTypeName << ", definitionDomain " << definitionDomain << ", rcindex " << rcindex << ", tileDomain " << tileDomain << ", clientID 0x" << hex << clientID << dec );
+
+ sendRequestGetAnswer();
+
+ r_OId oid(decoder.getDataAsString());
+ TALK( "RnpClientComm::createMDD() receiving oid " << oid );
+
+ clearAnswer();
+
+ LEAVE( "RnpClientComm::createMDD() -> " << oid );
+ return oid;
+}
+
+void RnpClientComm::extendMDD(r_OId mddOId, const char *stripeDomain, const char* tileDomain) throw(r_Error)
+{
+ ENTER( "RnpClientComm::extendMDD( mddOId=" << mddOId << ", stripeDomain=" << (stripeDomain?stripeDomain:"(null)") << ", tileDomain=" << (tileDomain?tileDomain:"(null)") << " )" );
+
+ checkForRwTransaction();
+ startRequest(RnpRasserver::cmd_extendmdd);
+ encoder.addInt32Parameter( RnpRasserver::pmt_clientid, clientID);
+ encoder.addStringParameter(RnpRasserver::pmt_oidstring, mddOId.get_string_representation());
+ encoder.addStringParameter(RnpRasserver::pmt_domain, stripeDomain);
+ encoder.addStringParameter(RnpRasserver::pmt_domain, tileDomain);
+ TALK( "request RnpRasserver::cmd_extendmdd with oid " << mddOId.get_string_representation() << ", stripeDomain " << stripeDomain << ", tileDomain " << tileDomain << ", clientID 0x" << hex << clientID << dec );
+
+ sendRequestGetAnswer();
+
+ clearAnswer();
+
+ LEAVE( "RnpClientComm::extendMDD()" );
+}
+
+vector<r_OId> RnpClientComm::getOIdsFromCollection( const char* collName ) throw( r_Error )
+{
+ ENTER( "RnpClientComm::getOIdsFromCollection( collName=" << (collName?collName:"(null)") << " )" );
+
+ vector<r_OId> result = executeGetOIdsFromCollection ( collName, r_OId());
+
+ LEAVE( "RnpClientComm::getOIdsFromCollection()" );
+ return result;
+}
+
+vector<r_OId> RnpClientComm::getOIdsFromCollection( const r_OId& oid ) throw( r_Error )
+{
+ ENTER( "RnpClientComm::getOIdsFromCollection( oid=" << oid << " )" );
+
+ vector<r_OId> result = executeGetOIdsFromCollection ( 0, oid );
+
+ LEAVE( "RnpClientComm::getOIdsFromCollection()" );
+ return result;
+}
+
+vector<r_OId> RnpClientComm::executeGetOIdsFromCollection ( const char* collName, const r_OId& oid ) throw( r_Error )
+{
+ ENTER( "RnpClientComm::executeGetOIdsFromCollection( collName=" << (collName?collName:"(null)") << ", oid=" << oid << " )" );
+
+ startRequest(RnpRasserver::cmd_getcolloids);
+ encoder.addInt32Parameter(RnpRasserver::pmt_clientid, clientID);
+ TALK( "request RnpRasserver::cmd_getcolloids with clientID 0x" << hex << clientID << dec );
+ if( collName != NULL)
+ {
+ encoder.addStringParameter(RnpRasserver::pmt_collname, collName);
+ TALK( "RnpClientComm::executeGetOIdsFromCollection() adding collName " << collName );
+ }
+ else
+ {
+ encoder.addStringParameter(RnpRasserver::pmt_oidstring, oid.get_string_representation());
+ TALK( "RnpClientComm::executeGetOIdsFromCollection() adding oid " << oid.get_string_representation() );
+ }
+
+ sendRequestGetAnswer();
+
+ int status = decoder.getDataAsInteger();
+ // we have to read all this, but we don't use them here
+ decoder.getNextParameter(); const char *typeName = decoder.getDataAsString();
+ TALK( "RnpClientComm::executeGetOIdsFromCollection() received typeName " << typeName );
+ decoder.getNextParameter(); const char *typeStructure = decoder.getDataAsString();
+ TALK( "RnpClientComm::executeGetOIdsFromCollection() received typeStructure " << typeStructure );
+ decoder.getNextParameter(); const char *oidstring = decoder.getDataAsString();
+ TALK( "RnpClientComm::executeGetOIdsFromCollection() received oid " << oidstring );
+ decoder.getNextParameter(); const char *collectionName= decoder.getDataAsString();
+ TALK( "RnpClientComm::executeGetOIdsFromCollection() received collectionName " << collectionName );
+
+ if( status != 0 && status != 1 )
+ {
+ r_Error err;
+ switch( status )
+ {
+ case 2:
+ LEAVE( "RnpClientComm::executeGetOIdsFromCollection(): exception, status = " << status );
+ err = r_Error( r_Error::r_Error_ObjectUnknown );
+ break;
+ case 3:
+ LEAVE( "RnpClientComm::executeGetOIdsFromCollection(): exception, status = " << status );
+ err = r_Error( r_Error::r_Error_ClientUnknown );
+ break;
+ default:
+ LEAVE( "RnpClientComm::executeGetOIdsFromCollection(): exception, status = " << status );
+ err = r_Error( r_Error::r_Error_TransferFailed );
+ break;
+ }
+ clearAnswer();
+ throw err;
+ }
+
+ // create the set
+ vector<r_OId> result;
+ // fill set with oids
+ if( status == 0 )
+ {
+ while(decoder.getNextParameter() != 0)
+ {
+ r_OId roid( decoder.getDataAsString() );
+ TALK( "RnpClientComm::executeGetOIdsFromCollection() received oid set component " << roid );
+
+ result.push_back(roid);
+ }
+ }
+
+ clearAnswer();
+
+ LEAVE( "RnpClientComm::executeGetOIdsFromCollection()" );
+ return result;
+ }
+
+vector<r_Minterval> RnpClientComm::getTileDomains(r_OId mddOId, const char *stripeDomain) throw( r_Error )
+{
+ ENTER( "RnpClientComm::getTileDomains( mddOId=" << mddOId << ", stripeDomain=" << (stripeDomain?stripeDomain:"(null)") << " )" );
+
+ startRequest(RnpRasserver::cmd_gettiledomains);
+ encoder.addInt32Parameter(RnpRasserver::pmt_clientid, clientID);
+ encoder.addStringParameter(RnpRasserver::pmt_oidstring, mddOId.get_string_representation());
+ encoder.addStringParameter(RnpRasserver::pmt_domain, stripeDomain);
+ TALK( "request RnpRasserver::cmd_gettiledomains with oid " << mddOId.get_string_representation() << ", stripeDomain " << stripeDomain << ", clientID 0x" << hex << clientID << dec );
+
+ sendRequestGetAnswer();
+
+ vector<r_Minterval> result;
+
+ const RnpParameter *currParam = decoder.getFirstParameter();
+
+ while(currParam)
+ {
+ r_Minterval interval(decoder.getDataAsString());
+ TALK( "RnpClientComm::getTileDomains() received minterval " << interval );
+
+ result.push_back(interval);
+
+ currParam = decoder.getNextParameter();
+ }
+
+ clearAnswer();
+
+ LEAVE( "RnpClientComm::getTileDomains() -> " << result );
+ return result;
+}
+
diff --git a/rnprotocol/rnpcommunication.cc b/rnprotocol/rnpcommunication.cc
new file mode 100644
index 0000000..65c5ed8
--- /dev/null
+++ b/rnprotocol/rnpcommunication.cc
@@ -0,0 +1,702 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/****************************************************************************
+ *
+ *
+ * COMMENTS:
+ * - FIXME: uses assert() !!! -- PB 2003-nov-22
+ *
+ ****************************************************************************/
+
+#include <assert.h>
+#include <rnpcommunication.hh>
+
+#ifdef AFTERV52
+#include <rnpexception.hh>
+#endif
+
+#include "debug.hh"
+#include "raslib/rminit.hh" // for RNP_COMM_TIMEOUT
+
+using namespace rnp;
+
+RnpClientJob::RnpClientJob() throw()
+ {
+ }
+
+void RnpClientJob::init(CommBuffer* transmitterBuffer, RnpBaseClientComm* newClientComm) throw()
+ {
+ ENTER( "RnpClientJob::init" );
+
+ if ( ! ( transmitterBuffer != 0 ) )
+ {
+ TALK( "RnpClientJob::init(): warning: assert will fire." );
+ }
+ assert(transmitterBuffer != 0);
+ if ( ! ( newClientComm != 0 ) )
+ {
+ TALK( "RnpClientJob::init(): warning: assert will fire." );
+ }
+ assert(newClientComm != 0);
+
+ rnpReceiver.reset();
+ answerOk = false;
+ currentBufferPtr = transmitterBuffer;
+ clientCommPtr = newClientComm;
+ invalidFormat = false;
+
+ status=wks_notdefined;
+
+ LEAVE( "RnpClientJob::init" );
+ }
+
+void RnpClientJob::clearAnswerBuffer() throw()
+ {
+ rnpReceiver.reset();
+ }
+
+void RnpClientJob::resetState() throw()
+ {
+ ENTER( "RnpClientJob::resetState" );
+
+ clearConnection();
+
+ clientCommPtr->jobIsReady();
+
+ status = wks_notdefined;
+
+ LEAVE( "RnpClientJob::resetState" );
+ }
+void RnpClientJob::processRequest() throw()
+ {
+ ENTER( "RnpClientJob::processRequest" );
+
+ answerOk = true;
+
+ invalidFormat = false;
+
+ resetState();
+
+ LEAVE( "RnpClientJob::processRequest" );
+ }
+
+bool RnpClientJob::validateMessage() throw()
+ {
+ ENTER( "RnpClientJob::validateMessage()" );
+
+ bool validated = rnpReceiver.validateMessage();
+
+ currentBufferPtr = rnpReceiver.getCurrentBuffer();
+
+ if( validated == true)
+ {
+ status=wks_processing;
+ LEAVE( "RnpClientJob::validateMessage() -> true" );
+ return true;
+ }
+
+ if(rnpReceiver.isDiscarding())
+ {
+ TALK( "RnpClientJob::validateMessage - discarding message" );
+ resetState();
+ answerOk = false;
+ invalidFormat = true;
+ }
+ answerOk = false;
+
+ LEAVE( "RnpClientJob::validateMessage() -> false" );
+ return false;
+ }
+
+void RnpClientJob::executeOnWriteReady() throw()
+ {
+ ENTER( "RnpClientJob::executeOnWriteReady()" );
+
+ rnpReceiver.reset();
+
+ currentBufferPtr->freeBuffer();
+
+ currentBufferPtr = rnpReceiver.getCurrentBuffer();
+
+ readyToReadAnswer();
+
+ LEAVE( "RnpClientJob::executeOnWriteReady()" );
+ }
+
+void RnpClientJob::specificCleanUpOnTimeout() throw()
+ {
+ ENTER( "RnpClientJob::specificCleanUpOnTimeout()" );
+
+ answerOk = false;
+ resetState();
+
+ LEAVE( "RnpClientJob::specificCleanUpOnTimeout()" );
+ }
+
+void RnpClientJob::executeOnReadError() throw()
+ {
+ ENTER( "RnpClientJob::executeOnReadError()" );
+
+ answerOk = false;
+ resetState();
+
+ LEAVE( "RnpClientJob::executeOnReadError()" );
+ }
+
+void RnpClientJob::executeOnWriteError() throw()
+ {
+ ENTER( "RnpClientJob::executeOnWriteError()" );
+
+ answerOk = false;
+ resetState();
+
+ LEAVE( "RnpClientJob::executeOnWriteError()" );
+ }
+
+CommBuffer* RnpClientJob::getAnswerBuffer() throw()
+ {
+ return rnpReceiver.getMessageBuffer();
+ }
+
+bool RnpClientJob::isAnswerOk() throw()
+ {
+ return answerOk;
+ }
+
+bool RnpClientJob::isInvalidFormat() throw()
+ {
+ return invalidFormat;
+ }
+
+
+//###################################################
+
+RnpBaseClientComm::RnpBaseClientComm(RnpQuark theServerType, RnpTransport::CarrierProtocol theProtocol) throw()
+ {
+ ENTER( "RnpBaseClientComm::RnpBaseClientComm( serverType="<<theServerType<<" protocol="<<theProtocol << " )" );
+
+ serverHost = NULL;
+ serverPort = 0;
+ serverType = theServerType;
+ carrierProtocol = theProtocol;
+
+ initDefaultCommunication();
+ maxRetry = 0; // # of RE-tries -- PB 2005-aug-31
+
+ LEAVE( "RnpBaseClientComm::RnpBaseClientComm()" );
+ }
+
+RnpBaseClientComm::RnpBaseClientComm(const char* theServerHost, int theServerPort, RnpQuark theServerType, RnpTransport::CarrierProtocol theProtocol) throw()
+ {
+ ENTER( "RnpBaseClientComm::RnpBaseClientComm( server="<<theServerHost<<" port="<<theServerPort<<" serverType="<<theServerType<<" protocol="<<theProtocol << " )" );
+
+ if ( ! ( theServerHost != 0 ) )
+ {
+ TALK( "RnpBaseClientComm::RnpBaseClientComm(): warning: assert will fire." );
+ }
+ assert(theServerHost != 0);
+ if ( ! ( theServerPort > 0 ) )
+ {
+ TALK( "RnpBaseClientComm::RnpBaseClientComm(): warning: assert will fire." );
+ }
+ assert(theServerPort > 0);
+
+ serverHost = theServerHost;
+ serverPort = theServerPort;
+ serverType = theServerType;
+ carrierProtocol = theProtocol;
+
+ initDefaultCommunication();
+
+ maxRetry = 0; // # of RE-tries -- PB 2005-aug-31
+
+ LEAVE( "RnpBaseClientComm::RnpBaseClientComm()" );
+ }
+RnpBaseClientComm::~RnpBaseClientComm() throw()
+ {
+ }
+
+void RnpBaseClientComm::setConnectionParameters(const char* theServerHost, int theServerPort) throw()
+ {
+ ENTER( "RnpBaseClientComm::setConnectionParameters( server="<<theServerHost<<" port="<<theServerPort << " )" );
+
+ if ( ! ( theServerHost != 0 ) )
+ {
+ TALK( "RnpBaseClientComm::setConnectionParameters(): warning: assert will fire." );
+ }
+ assert(theServerHost != 0);
+ if ( ! ( theServerPort > 0 ) )
+ {
+ TALK( "RnpBaseClientComm::setConnectionParameters(): warning: assert will fire." );
+ }
+ assert(theServerPort > 0);
+
+ serverHost = theServerHost;
+ serverPort = theServerPort;
+
+ LEAVE( "RnpBaseClientComm::setConnectionParameters()" );
+ }
+
+void RnpBaseClientComm::setCarrierProtocol(RnpTransport::CarrierProtocol theProtocol) throw()
+ {
+ carrierProtocol = theProtocol;
+ }
+
+RnpTransport::CarrierProtocol RnpBaseClientComm::getCarrierProtocol() throw()
+ {
+ return carrierProtocol;
+ }
+
+void RnpBaseClientComm::initDefaultCommunication() throw()
+ {
+ ENTER( "RnpBaseClientComm::initDefaultCommunication()" );
+
+ communicatorPtr = &internalCommunicator;
+
+ communicatorPtr->initJobs(1);
+ communicatorPtr->setTimeout(RNP_COMM_TIMEOUT,0); // defined in raslib/rminit.hh -- PB 2005-sep-09
+
+ communicatorPtr->attachJob(clientJob);
+
+ // not necessary? transmitterBuffer.allocate(RNP_DEFAULTBUFFERSIZE);
+
+ LEAVE( "RnpBaseClientComm::initDefaultCommunication()" );
+ }
+
+
+void RnpBaseClientComm::jobIsReady() throw()
+ {
+ ENTER( "RnpBaseClientComm::jobIsReady()" );
+
+ communicatorPtr->shouldExit();
+
+ LEAVE( "RnpBaseClientComm::jobIsReady()" );
+ }
+
+void RnpBaseClientComm::startRequest(RnpQuark command, int transmitterBufferSize)
+ {
+ ENTER( "RnpBaseClientComm::startRequest( command="<<command<<" transmitterBufferSize="<<transmitterBufferSize << " )" );
+
+ transmitterBuffer.allocate(transmitterBufferSize);
+
+ clientJob.init(&transmitterBuffer,this);
+
+ encoder.setBuffer(&transmitterBuffer);
+
+ encoder.startRequest(serverType, carrierProtocol);
+ encoder.startFragment(Rnp::fgt_Command, command);
+
+ LEAVE( "RnpBaseClientComm::startRequest()" );
+ }
+
+bool RnpBaseClientComm::sendRequestGetAnswer()
+ {
+ ENTER( "RnpBaseClientComm::sendMessageGetAnswer()" );
+
+ if ( ! ( serverHost != NULL ) )
+ {
+ TALK( "RnpBaseClientComm::sendRequestGetAnswer(): warning: assert will fire." );
+ }
+ assert(serverHost != NULL);
+ if ( ! ( serverPort > 0 ) )
+ {
+ TALK( "RnpBaseClientComm::sendRequestGetAnswer(): warning: assert will fire." );
+ }
+ assert(serverPort > 0);
+
+ encoder.endFragment();
+ encoder.endMessage();
+
+ bool connected = false;
+ for (int retry = 0; retry < maxRetry+1 && !connected; retry++) // NB: first attempt + RE-tries! -- PB 2005-aug-31
+ {
+ connected = clientJob.connectToServer(serverHost,serverPort);
+ }
+
+ if(connected == false)
+ {
+#ifdef AFTERV52
+ LEAVE( "RnpBaseClientComm::sendMessageGetAnswer(): exception - cannot connect to server "<<serverHost<<":"<<serverPort );
+ throw RnpIOException(clientJob.getErrno());
+#endif
+ LEAVE( "RnpBaseClientComm::sendMessageGetAnswer(): -> false" );
+ return false;
+ }
+
+ communicatorPtr->runClient();
+
+ if(clientJob.isAnswerOk()== false)
+ {
+#ifdef AFTERV52
+ LEAVE( "RnpBaseClientComm::sendMessageGetAnswer(): exception - answer not OK" );
+ if(clientJob.isInvalidFormat()) throw RnpInvalidFormatException();
+ else throw RnpIOException(clientJob.getErrno());
+#endif
+ LEAVE( "RnpBaseClientComm::sendMessageGetAnswer(): -> false" );
+ return false;
+ }
+
+ CommBuffer* receiverBuffer = clientJob.getAnswerBuffer();
+ decoder.decode(receiverBuffer);
+ decoder.getFirstFragment();
+
+ LEAVE( "RnpBaseClientComm::sendMessageGetAnswer() -> true");
+ return true;
+ }
+
+bool RnpBaseClientComm::checkForExceptions()
+ {
+ if(decoder.getFragmentType() != Rnp::fgt_Error) return false;
+ return true;
+ }
+
+void RnpBaseClientComm::clearAnswer() throw()
+ {
+ clientJob.clearAnswerBuffer();
+ }
+
+void RnpBaseClientComm::setMaxRetry(unsigned int newMaxRetry)
+ {
+ maxRetry = newMaxRetry;
+ }
+
+unsigned int RnpBaseClientComm::getMaxRetry()
+ {
+ return maxRetry;
+ }
+//############# Server side ################################################
+//#######################################################################
+//#######################################################################
+
+RnpServerJob::RnpServerJob() throw()
+ {
+ }
+
+void RnpServerJob::init(RnpBaseServerComm* theServerComm) throw()
+ {
+ if ( ! ( theServerComm != 0 ) )
+ {
+ TALK( "RnpServerJob::init(): warning: assert will fire." );
+ }
+ assert(theServerComm != 0);
+
+ rnpReceiver.reset();
+ currentBufferPtr = rnpReceiver.getCurrentBuffer();
+ serverCommPtr = theServerComm;
+
+ status=wks_accepting;
+ }
+
+void RnpServerJob::processRequest() throw()
+ {
+ serverCommPtr->processRequest(currentBufferPtr, &transmiterBuffer, rnpReceiver.getCarrierProtocol(), this);
+
+ rnpReceiver.reset();
+
+ currentBufferPtr = &transmiterBuffer;
+
+ readyToWriteAnswer();
+ }
+
+bool RnpServerJob::validateMessage() throw()
+ {
+
+ bool validated = false;
+
+ if(rnpReceiver.validateMessage() == true)
+ {
+ status=wks_processing;
+ validated = true;
+ }
+
+ if(rnpReceiver.isDiscarding())
+ {
+ resetJob();
+ validated = false;
+ }
+
+ currentBufferPtr = rnpReceiver.getCurrentBuffer();
+
+ return validated;
+ }
+
+void RnpServerJob::executeOnWriteReady() throw()
+ {
+ resetJob();
+ }
+
+void RnpServerJob::executeOnAccept() throw()
+ {
+ }
+
+void RnpServerJob::specificCleanUpOnTimeout() throw()
+ {
+ // initial era gol, dar...
+ // clearConnection face cine apeleaza: NbJob::cleanUpIfTimeout()
+ rnpReceiver.reset();
+
+ transmiterBuffer.freeBuffer();
+
+ currentBufferPtr = rnpReceiver.getCurrentBuffer();
+
+ currentBufferPtr->clearToRead();
+
+ status=wks_accepting;
+ }
+
+void RnpServerJob::executeOnReadError() throw()
+ {
+ resetJob();
+ }
+
+void RnpServerJob::executeOnWriteError() throw()
+ {
+ resetJob();
+ }
+
+void RnpServerJob::resetJob() throw()
+ {
+ clearConnection();
+
+ rnpReceiver.reset();
+
+ transmiterBuffer.freeBuffer();
+
+ currentBufferPtr = rnpReceiver.getCurrentBuffer();
+
+ currentBufferPtr->clearToRead();
+
+ status=wks_accepting;
+ }
+
+//###################################################
+RnpBaseServerComm::RnpBaseServerComm() throw()
+ {
+ nrServerJobs = 1;
+
+ transmitterBufferSize = RNP_DEFAULTBUFFERSIZE;
+
+ communicator = NULL;
+ }
+
+RnpBaseServerComm::~RnpBaseServerComm() throw()
+ {
+ disconnectFromCommunicator();
+ }
+
+bool RnpBaseServerComm::setServerJobs(int nrOfServerJobs) throw()
+ {
+ if(communicator != 0 ) return false;
+
+ nrServerJobs = nrOfServerJobs;
+
+ return true;
+ }
+
+int RnpBaseServerComm::countServerJobs() throw()
+ {
+ return nrServerJobs;
+ }
+
+void RnpBaseServerComm::connectToCommunicator(NbCommunicator &theCommunicator)
+ { // throws whatever 'new' throws
+ if ( ! ( communicator == NULL ) )
+ {
+ TALK( "RnpServerJob::init(): warning: assert will fire." );
+ }
+ assert(communicator == NULL);
+
+ communicator = &theCommunicator;
+
+ for(int i=0; i<nrServerJobs;i++)
+ {
+ RnpServerJob* job = createJob();
+
+ job->init(this);
+
+ communicator->attachJob(*job);
+
+ serverJob.push_back(job);
+ }
+ }
+
+bool RnpBaseServerComm::disconnectFromCommunicator() throw()
+ {
+ if(communicator == NULL) return false;
+
+ for(int i=0; i<nrServerJobs;i++)
+ {
+ communicator->deattachJob(*(serverJob[i]));
+
+ delete serverJob[i];
+ }
+
+ serverJob.clear();
+
+ communicator = NULL;
+
+ return true;
+ }
+
+RnpServerJob* RnpBaseServerComm::createJob()
+ {
+ return new RnpServerJob;
+ }
+
+
+void RnpBaseServerComm::setTransmitterBufferSize(int nSize) throw()
+ {
+ transmitterBufferSize = nSize;
+ }
+
+int RnpBaseServerComm::getTransmitterBufferSize() throw()
+ {
+ return transmitterBufferSize;
+ }
+
+
+void RnpBaseServerComm::processRequest(CommBuffer *receiverBuffer, CommBuffer *transmiterBuffer, RnpTransport::CarrierProtocol protocol, RnpServerJob *callingJob) throw()
+ {
+ // use 'callingJob' to get info about the client (hostaddress, etc)
+
+ decoder.decode(receiverBuffer);
+ RnpQuark destServerType = decoder.getDestinationServerType();
+ Rnp::Endianness desEndianness = decoder.getDesiredEndianness();
+
+ // test if servertype matches!
+
+ transmiterBuffer->allocate(transmitterBufferSize);
+ transmiterBuffer->clearToRead();
+
+ encoder.setBuffer(transmiterBuffer);
+ encoder.setFinalEndianness(desEndianness);
+ encoder.startAnswer(destServerType, protocol);
+
+ decoder.getFirstFragment();
+ bool wasError = false;
+ for(int fragment=0; fragment < decoder.countFragments(); fragment++)
+ {
+ if(wasError == false)
+ {
+ try
+ {
+ decodeFragment();
+ }
+ catch(...)
+ {
+ wasError = true;
+ answerUnknownError();
+ }
+ }
+ else
+ {
+ discardFragment();
+ }
+ decoder.getNextFragment();
+ }
+ encoder.endMessage();
+ }
+
+const char* RnpBaseServerComm::getNextAsString(RnpQuark parameterType) const
+ {
+ decoder.getNextParameter();
+ //if(decoder.getParameterType != parameterType) throw something
+ return decoder.getDataAsString();
+ }
+
+int RnpBaseServerComm::getNextAsInteger(RnpQuark parameterType) const
+ {
+ decoder.getNextParameter();
+ //if(decoder.getParameterType != parameterType) throw something
+ return decoder.getDataAsInteger();
+ }
+
+float RnpBaseServerComm::getNextAsFloat(RnpQuark parameterType) const
+ {
+ decoder.getNextParameter();
+ //if(decoder.getParameterType != parameterType) throw something
+ return decoder.getDataAsFloat();
+ }
+
+double RnpBaseServerComm::getNextAsDouble(RnpQuark parameterType) const
+ {
+ decoder.getNextParameter();
+ //if(decoder.getParameterType != parameterType) throw something
+ return decoder.getDataAsDouble();
+ }
+
+const void* RnpBaseServerComm::getNextAsOpaque(RnpQuark parameterType) const
+ {
+ decoder.getNextParameter();
+ //if(decoder.getParameterType != parameterType) throw something
+ return decoder.getDataAsOpaque();
+ }
+
+int RnpBaseServerComm::getCurrentParameterLength() const throw()
+ {
+ return decoder.getDataLength();
+ }
+
+void RnpBaseServerComm::answerSTLException(exception &ex) throw()
+ {
+ encoder.startFragment(Rnp::fgt_Error, decoder.getCommand());
+ encoder.addInt32Parameter(Rnp::ert_StlException, 0);
+ encoder.addStringParameter(Rnp::erp_whatValue, ex.what());
+ encoder.endFragment();
+ }
+
+void RnpBaseServerComm::answerUnknownError() throw()
+ {
+ encoder.startFragment(Rnp::fgt_Error, decoder.getCommand());
+ encoder.addInt32Parameter(Rnp::ert_Unknown, 0);
+ encoder.endFragment();
+ }
+
+void RnpBaseServerComm::discardFragment() throw()
+ {
+ encoder.startFragment(Rnp::fgt_DiscardedRequest, decoder.getCommand());
+
+ encoder.endFragment();
+ }
+
+void RnpBaseServerComm::startOkAnswer() throw()
+ {
+ encoder.startFragment(Rnp::fgt_OkAnswer, decoder.getCommand());
+ }
+
+void RnpBaseServerComm::endOkAnswer() throw()
+ {
+ encoder.endFragment();
+ }
+
+void RnpBaseServerComm::communicatorShouldExit() throw()
+ {
+ if ( ! ( communicator != NULL ) )
+ {
+ TALK( "RnpServerJob::init(): warning: assert will fire." );
+ }
+ assert(communicator != NULL);
+
+ communicator->shouldExit();
+ }
+
diff --git a/rnprotocol/rnpcommunication.hh b/rnprotocol/rnpcommunication.hh
new file mode 100644
index 0000000..56aca81
--- /dev/null
+++ b/rnprotocol/rnpcommunication.hh
@@ -0,0 +1,345 @@
+#ifndef RNPCOMMUNICATION_HH
+#define RNPCOMMUNICATION_HH
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/****************************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ *
+ ****************************************************************************/
+
+#include "network/akgnetwork.hh"
+#include "rnprotocol/rnpembedded.hh"
+#include <vector>
+
+#ifdef AFTERV52
+ #include <akglogging.hh>
+ #include <akg_exception.hh>
+#else
+ #include <exception>
+#endif
+
+namespace rnp
+ {
+using namespace akg;
+using namespace std;
+
+class RnpBaseClientComm;
+
+/** This class represents the RNP client job. It taker a CommBuffer, sends its data
+ and receives the answer. Is directy owned and used by 'RnpBaseClientComm',
+ so you don't have to worry about it
+ Be aware that the transmitter buffer is freed after transmission! */
+class RnpClientJob : public NbClientJob
+ {
+ public:
+ /// Default constructor
+ RnpClientJob() throw();
+
+ /** Initialization: takes the tarnsmitter buffer containing data to be send
+ and a pointer to a Communicator object, which will coordinate the transmission
+ Assert: transmitterBuffer!=0, newClientComm !=0 */
+ void init(CommBuffer *transmitterBuffer, RnpBaseClientComm *newClientComm) throw();
+
+ /// Call-back function for the Communicator.
+ void processRequest() throw();
+
+ /** Returns a pointer to the buffer containing the answer. The buffer
+ holds only the RNP message, without carrier header */
+ CommBuffer* getAnswerBuffer() throw();
+
+ /// Returns 'true' if the answer was correctly received
+ bool isAnswerOk() throw();
+
+ /// Returns true if the format of the received message is not valid RNP and was discarded
+ bool isInvalidFormat() throw();
+
+ /** Clears the answer buffer. Important if huge amount of data where received.
+ The buffer is cleared by the next transmission, also. */
+ void clearAnswerBuffer() throw();
+ protected:
+ /// (See the explanations from NbJob)
+ bool validateMessage() throw();
+ void executeOnWriteReady() throw();
+ void specificCleanUpOnTimeout() throw();
+ void executeOnReadError() throw();
+ void executeOnWriteError() throw();
+
+ /// Resets the object: clears the connection and marks the job as ready
+ void resetState() throw();
+ private:
+ RnpBaseClientComm *clientCommPtr;
+
+ RnpReceiver rnpReceiver;
+ bool answerOk;
+ bool invalidFormat;
+ };
+
+/**
+ RnpBaseClientComm is the base class for the client communication. It offers
+ the necessary elements for creating the request, send it, receive the answer
+ and decode it. Every specific client comm will inherit from this and will
+ implement the various functions using the functions provided by this class.
+
+ It has a private NbCommunicator object, but if you need a shared one
+ be my guest. The RnpClientJob is its own also and this stays like that!
+*/
+class RnpBaseClientComm
+ {
+ public:
+ /// Constructor taking the server type and the carrier protocol
+ RnpBaseClientComm(RnpQuark serverType, RnpTransport::CarrierProtocol = RnpTransport::crp_Rnp) throw();
+
+ /** Constructor taking also the connection info for the server
+ Assert: serverHost != 0, serverPort > 0 */
+ RnpBaseClientComm(const char* serverHost, int serverPort, RnpQuark serverType, RnpTransport::CarrierProtocol = RnpTransport::crp_Rnp) throw();
+
+ /// Destructor
+ virtual ~RnpBaseClientComm() throw();
+
+ /** Set the connection parameter
+ Assert: serverHost != 0, serverPort > 0 */
+ void setConnectionParameters(const char* serverHost, int serverPort) throw();
+
+ /// Set the carrier protocol
+ void setCarrierProtocol(RnpTransport::CarrierProtocol) throw();
+ /// Returns the used carrier protocol
+ RnpTransport::CarrierProtocol getCarrierProtocol() throw();
+
+ // callback from RnpClientJob
+ void jobIsReady() throw();
+
+ // Set the maximal retry count (retries to connect to the server)
+ void setMaxRetry(unsigned int newMaxRetry);
+
+ /// Returns the maximal retry count
+ unsigned int getMaxRetry();
+
+ protected:
+ // stuff for helping creating the function calls
+ RnpQuark serverType;
+ RnpTransport::CarrierProtocol carrierProtocol;
+
+ /// Start building the request, might throw whatever new throws
+ void startRequest(RnpQuark command, int transmitterBufferSize = RNP_DEFAULTBUFFERSIZE);
+
+ /** Does the dirty work: sends the request and brings the answer
+ Later it will throw various exceptions, but for now it only
+ returns 'true' if everything is OK
+ Assert: serverHost != 0, serverPort > 0 */
+ bool sendRequestGetAnswer();
+
+ /** detects an exception as answer and throws it. this version only Akg and STL
+ returns true if there is an exception, but can't reassemble it
+ returns false if there is a correct answer, no exception
+ doesn't return, but throws, if there is an exception and it can reassemble it*/
+ virtual bool checkForExceptions();
+
+#ifdef AFTERV52
+ // reassembles and throws an AkgSerializableException. Returns if it isn't an Akg...
+ void reassembleAkgSerializable() throw(AkgSerializableException);
+
+ // reassembles and throws a STL-exception. Returns only if it isn't a stl-exception
+ void reassembleStlException() throw(RnpStlException);
+#endif
+ /// Clear the answer when you don't need it any more, memory is released
+ void clearAnswer() throw();
+
+ /** Default communication init, build another init() if you don't like this
+ This sets 1 job, 60sec as timeout, attaches the internal job.
+ Be aware that this timeout is not the timeout of the client job,
+ but the one of the communicator */
+ void initDefaultCommunication() throw();
+
+ // encoding and decoding
+ RnpProtocolDecoder decoder;
+ RnpTransmitter encoder;
+ CommBuffer transmitterBuffer; // to go, use internal of encoder
+
+ // stuff for non blocking communication
+ RnpClientJob clientJob; // the client job
+ NbCommunicator *communicatorPtr; // the communicator to be used
+ NbCommunicator internalCommunicator; // an internal communicator, if you dont like that you put another one
+
+ // connection parameters
+ const char* serverHost;
+ unsigned int serverPort;
+ unsigned int maxRetry;
+
+ /// Helper function for ptinting the current parameter
+ void printCurrentParameter() throw();
+ };
+
+
+//############ Server side ###################################
+
+class RnpBaseServerComm;
+
+/** This class represents the RNP server job. It receives the request, sends it to 'RnpBaseServerComm'
+ for processing and gets from there the answer which it transmittes to the client
+*/
+class RnpServerJob : public NbServerJob
+ {
+ public:
+ /// Default constructor
+ RnpServerJob() throw();
+
+ /** Initialization: it connects to the given 'RnpBaseServerComm'
+ Assert: theServerComm != 0 */
+ void init(RnpBaseServerComm*) throw();
+
+ /// Calls the 'RnpBaseServerComm->processRequest()' and than initiates the transmission
+ void processRequest() throw();
+
+ protected:
+ /// (See explanations from NbJob)
+ bool validateMessage() throw();
+ void executeOnAccept() throw();
+ void executeOnWriteReady() throw();
+ void specificCleanUpOnTimeout() throw();
+ void executeOnReadError() throw();
+ void executeOnWriteError() throw();
+
+ void resetJob() throw();
+
+ RnpBaseServerComm *serverCommPtr;
+
+ RnpReceiver rnpReceiver;
+
+ CommBuffer transmiterBuffer;
+ };
+
+/**
+ RnpBaseServerComm is the base class for the server communication. It offers
+ the necessary elements for decoding the request, and for creating and transmitting
+ the answer. Every specific server comm will inherit from this and will
+ implement the various functions, most important the 'processRequest()',
+ using the elements provided by this class.
+
+ It has a pool of 'RnpServerJob's which deal with the communication. Whichever has
+ a valid request calls 'processRequest()'. The communicator object is external
+*/
+
+class RnpBaseServerComm
+ {
+ public:
+ /// Default constructor - 1 server job
+ RnpBaseServerComm() throw();
+
+ /// Destructor
+ virtual ~RnpBaseServerComm() throw();
+
+ /** Sets the number of server jobs, only if there is no connection to a communicator
+ Otherwise it changes nothing and returns 'false' */
+ bool setServerJobs(int nrOfServerJobs) throw();
+
+ /// Returns the number of server jobs
+ int countServerJobs() throw();
+
+ /// Connect to the communicator. It also creates the jobs. Throws whatever new throws. Assert: no other connection!
+ void connectToCommunicator(NbCommunicator&);
+
+ /** Disconnect the jobs from the communicator and destroys them.
+ Returns 'false' if there wasn't any connection to a communicator */
+ bool disconnectFromCommunicator() throw();
+
+ /// Set the transmitter buffer size
+ void setTransmitterBufferSize(int) throw();
+
+ /// Returns the transmitter buffer size
+ int getTransmitterBufferSize() throw();
+
+ /** The heart of the class. It takes the request, decodes it, sends every fragment
+ to the 'decodeFragment()', which has to dispatch the commands to the specific
+ functions. These functions have to use 'decoder' and 'encoder' to do their job and
+ might throw whatever is appropriate. 'processRequest()' catches 'AkgException',
+ 'exception' and (...) and converts them for transmission.
+ If you don't like this version, make another one */
+ virtual void processRequest(CommBuffer *receiverBuffer, CommBuffer *transmiterBuffer, RnpTransport::CarrierProtocol, RnpServerJob *callingJob) throw();
+
+ /** Instructs the communicator that it should exit. Usefull to implement
+ 'down server' commands */
+ void communicatorShouldExit() throw();
+
+ protected:
+ /** Called by 'processRequest' to dispatch to the specific functions
+ Might throw whatever appropriate */
+ virtual void decodeFragment() = 0;
+
+ /// Returns next parameter as string(can be NULL), verifying the parameter type.
+ const char* getNextAsString(RnpQuark parameterType) const;
+
+ /// Returns next parameter as integer, verifying the parameter type.
+ int getNextAsInteger(RnpQuark parameterType) const;
+
+ /// Returns next parameter as float, verifying the parameter type.
+ float getNextAsFloat(RnpQuark parameterType) const;
+
+ /// Returns next parameter as double, verifying the parameter type.
+ double getNextAsDouble(RnpQuark parameterType) const;
+
+ /// Returns next parameter as const void* (can be NULL), verifying the parameter type.
+ const void* getNextAsOpaque(RnpQuark parameterType) const;
+
+ /// Returns the length of the data of the current parameter
+ int getCurrentParameterLength() const throw();
+#ifdef AFTERV52
+ /// Helper function to serialize an 'AkgException'
+ void answerAkgSerializable(AkgSerializableException&) throw();
+#endif
+ /// Helper function to serialize an 'exception' (based on it's 'what()'-member
+ void answerSTLException(exception&) throw();
+
+ /// Helper function to serialize an unknown exception
+ void answerUnknownError() throw();
+
+ /// Helper function to discard a fragment
+ void discardFragment() throw();
+
+ /// Start building an OK-answer
+ void startOkAnswer() throw();
+
+ /// Just for completeness, it's only an 'encoder.endFragment()'
+ void endOkAnswer() throw();
+
+ RnpProtocolDecoder decoder;
+ RnpTransmitter encoder;
+
+ private:
+ /** Creates a server jobs. Default is a RnpServerJob, but you might want
+ some other kind of job */
+ virtual RnpServerJob* createJob();
+
+ vector<RnpServerJob*> serverJob;
+
+ int nrServerJobs;
+
+ NbCommunicator *communicator;
+
+ int transmitterBufferSize;
+ };
+
+} // namespace
+#endif
diff --git a/rnprotocol/rnpembedded.cc b/rnprotocol/rnpembedded.cc
new file mode 100644
index 0000000..c0362bb
--- /dev/null
+++ b/rnprotocol/rnpembedded.cc
@@ -0,0 +1,467 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/****************************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ****************************************************************************/
+
+#include <rnpembedded.hh>
+#include <assert.h>
+
+#include "debug.hh"
+
+
+using namespace rnp;
+
+const char* RnpTransport::carrierNames[] =
+ {
+ "(unknown)","RNP","HTTP","(bad)"
+ };
+
+const char* RnpTransport::getCarrierName(RnpTransport::CarrierProtocol x) throw()
+ {
+ if(x < crp_Unknown || x >= crp_HowMany) return carrierNames[0];
+ return carrierNames[x];
+ }
+
+
+const int RnpReceiver::headerBufferLength = 1000;
+
+RnpReceiver::RnpReceiver() throw()
+ {
+ headerBuffer.allocate(headerBufferLength);
+
+ reset();
+ }
+
+RnpReceiver::~RnpReceiver() throw()
+ {
+ }
+
+void RnpReceiver::reset() throw()
+ {
+ rnpMessageBuffer.freeBuffer();
+ headerBuffer.clearToRead();
+ status = waitingHeader;
+ carrier = RnpTransport::crp_Unknown;
+ }
+
+akg::CommBuffer* RnpReceiver::getCurrentBuffer() throw()
+ {
+ return status == readingMessage ? &rnpMessageBuffer : &headerBuffer;
+ }
+
+akg::CommBuffer* RnpReceiver::getMessageBuffer() throw()
+ {
+ return &rnpMessageBuffer;
+ }
+
+RnpTransport::CarrierProtocol
+RnpReceiver::getCarrierProtocol() const throw()
+ {
+ return carrier;
+ }
+
+int RnpReceiver::getCarrierHeaderSize() const throw()
+ {
+ return carrierHeaderLength;
+ }
+
+const void* RnpReceiver::getCarrierHeader() throw()
+ {
+ return headerBuffer.getData();
+ }
+
+bool RnpReceiver::isDiscarding() const throw()
+ {
+ return status == discarding ? true:false;
+ }
+
+bool RnpReceiver::validateMessage() throw()
+ {
+ ENTER( "RnpReceiver::validateMessage()");
+
+ if(status == waitingHeader)
+ { rnpHeader = NULL;
+
+ if(isHttpCarrier() || isRnpCarrier())
+ { // a valid carrier header was detected
+ if(rnpHeader != NULL)
+ { // we can switch to reading the message
+ if(prepareMessageBuffer())
+ {
+ status = readingMessage;
+ }
+ else {
+ status = discarding;
+ LEAVE( "RnpReceiver::validateMessage() -> false - discarding message: not enough memory for message buffer.");
+ return false;
+ }
+ }
+ else
+ {
+ // status == readingHeader, but rnpHeader == NULL
+ // so we wait for some more message
+ LEAVE( "RnpReceiver::validateMessage - wait for more message(s)");
+ return false;
+ }
+ }
+ else
+ { status = discarding;
+ LEAVE( "RnpReceiver::validateMessage() -> false - discarding message: no valid carrier header.");
+ return false;
+ }
+ }
+
+ if(status == readingMessage)
+ {
+ if(rnpMessageBuffer.getNotFilledSize() != 0)
+ {
+ LEAVE( "RnpReceiver::validateMessage() -> false");
+ return false;
+ }
+ }
+ if(status == discarding)
+ {
+ TALK( "RnpReceiver::validateMessage - discarding(3)." );
+ headerBuffer.clearToRead();
+ LEAVE( "RnpReceiver::validateMessage() -> false");
+ return false;
+ }
+ LEAVE( "RnpReceiver::validateMessage() -> true");
+ return true;
+ }
+
+/* the isXXXCarrier() functions have to:
+ - return true if the message is or might be an XXX embedded RnpMessage
+ - set rnpHeader only if there is a valid carrier header
+ - set carrierHeaderLength in this case
+
+ so:
+ - invalid carrier returns false / rnpHeader == NULL
+ - valid carrier but not rnp - false /rnpHeader != NULL
+ - valid carrier but not enough data to be sure it's also valid rnp - true/rnpHeader == NULL
+ - valid carrier & valid rnp header =>true/rnpHeader != NULL carrierHeaderLength set
+*/
+
+bool RnpReceiver::isHttpCarrier() throw()
+ {
+ ENTER( "RnpReceiver::isHttpCarrier()" );
+
+ char *data = (char*)headerBuffer.getData();
+
+ rnpHeader = NULL;
+ carrierHeaderLength = -1;
+
+ bool isHttpReqHeader = strncmp(data,"POST RnpMessage HTTP/1.1",24) ? false : true;
+ bool isHttpAnsHeader = strncmp(data,"HTTP/1.1 200 OK" ,15) ? false : true;
+
+ if(isHttpReqHeader == false && isHttpAnsHeader == false)
+ {
+ LEAVE( "RnpReceiver::isHttpCarrier() -> false" );
+ return false;
+ }
+
+ char *eoHttp = strstr(data,"\r\n\r\n");
+
+ if(eoHttp == NULL)
+ {
+ LEAVE( "RnpReceiver::isHttpCarrier() -> false" );
+ return false;
+ }
+
+ carrierHeaderLength = eoHttp - data + 4;
+
+ if( carrierHeaderLength == -1)
+ {
+ LEAVE( "RnpReceiver::isHttpCarrier() -> false" );
+ return false;
+ }
+
+ if(carrierHeaderLength + sizeof(RnpHeader) > headerBuffer.getDataSize())
+ { // is HTTP carrier, but we need more data to say if it's an embedded RnpMessage
+ LEAVE( "RnpReceiver::isHttpCarrier() -> true" );
+ return true;
+ }
+
+ rnpHeader = (RnpHeader*)(data + carrierHeaderLength);
+
+ bool isRnp = rnpHeader->isRnpMessage();
+
+ if(isRnp)
+ { carrier = RnpTransport::crp_Http;
+ TALK( "RnpReceiver::isHttpCarrier - valid HTTP carrier detected.");
+ }
+
+ LEAVE( "RnpReceiver::isHttpCarrier() -> " << isRnp);
+ return isRnp;
+ }
+
+bool RnpReceiver::isRnpCarrier() throw()
+ {
+ ENTER( "RnpReceiver::isRnpCarrier()" );
+
+ char *data = (char*)headerBuffer.getData();
+
+ rnpHeader = NULL;
+ carrierHeaderLength = -1;
+
+ if(sizeof(RnpHeader) > headerBuffer.getDataSize())
+ { // we need more data to say if it's an RnpMessage
+ LEAVE( "RnpReceiver::isRnpCarrier() -> true" );
+ return true;
+ }
+
+ rnpHeader = (RnpHeader*)data;
+ carrierHeaderLength = 0;
+
+ bool isRnp = rnpHeader->isRnpMessage();
+
+ if(isRnp)
+ { carrier = RnpTransport::crp_Rnp;
+ TALK( "RnpReceiver::isRnpCarrier - valid RNP carrier detected!");
+ }
+
+ LEAVE( "RnpReceiver::isRnpCarrier() -> " << isRnp );
+ return isRnp;
+ }
+
+bool RnpReceiver::prepareMessageBuffer() throw()
+ {
+ if(rnpMessageBuffer.allocate(rnpHeader->getTotalLength()) == false)
+ return false;
+
+ char *data = (char*)headerBuffer.getData();
+
+ rnpMessageBuffer.read(data + carrierHeaderLength, headerBuffer.getDataSize() - carrierHeaderLength);
+
+ RnpHeader *nRnpHeader = (RnpHeader*)rnpMessageBuffer.getData();
+
+ return true;
+ }
+
+//########################################################################################################
+
+RnpTransmitter::RnpTransmitter() throw()
+ {
+ carrier = NULL;
+ carrierType = RnpTransport::crp_Http;
+ }
+
+RnpTransmitter::~RnpTransmitter() throw()
+ {
+ if(carrier != NULL) delete carrier;
+ }
+
+bool RnpTransmitter::startRequest(RnpQuark serverType, RnpTransport::CarrierProtocol desiredProtocol) throw()
+ {
+ getCarrierObject(desiredProtocol);
+
+ if(carrier == NULL) return false;
+
+ startMessage(serverType, carrier->getRequestHeaderLength());
+
+ return true;
+ }
+
+bool RnpTransmitter::startAnswer(RnpQuark serverType, RnpTransport::CarrierProtocol desiredProtocol) throw()
+ {
+ getCarrierObject(desiredProtocol);
+
+ if(carrier == NULL) return false;
+
+ startMessage(serverType, carrier->getAnswerHeaderLength());
+
+ return true;
+ }
+
+akg::CommBuffer* RnpTransmitter::endMessage() throw()
+ {
+ if(carrier == NULL) return NULL;
+
+ akg::CommBuffer *theBuffer = RnpProtocolEncoder::endMessage();
+ carrier->putHeader(theBuffer);
+
+ return theBuffer;
+ }
+
+RnpTransport::CarrierProtocol
+RnpTransmitter::getCarrierProtocol() throw()
+ {
+ return carrierType;
+ }
+
+RnpCarrier* RnpTransmitter::getCarrierObject(RnpTransport::CarrierProtocol desiredProtocol) throw()
+ {
+ carrierType = desiredProtocol;
+
+ if(carrier != NULL) delete carrier;
+
+ switch(carrierType)
+ {
+ case RnpTransport::crp_Rnp : carrier = new RnpCarrier;break;
+ case RnpTransport::crp_Http: carrier = new HttpRnpCarrier;break;
+
+ case RnpTransport::crp_BadCarrier:
+ carrier = new BadRnpCarrier;break;
+
+ default : carrier = NULL;break;
+ }
+
+ return carrier;
+ }
+
+int RnpTransmitter::getBufferSize() const throw()
+ {
+ if ( ! ( commBuffer != 0 ) )
+ {
+ TALK( "RnpTransmitter::getBufferSize(): warning: assert will fire." );
+ }
+ assert(commBuffer != 0);
+ return commBuffer->getBufferSize();
+ }
+
+int RnpTransmitter::getNotFilledSize() const throw()
+ {
+ if ( ! ( commBuffer != 0 ) )
+ {
+ TALK( "RnpTransmitter::getNotFilledSize(): warning: assert will fire." );
+ }
+ assert(commBuffer != 0);
+ return commBuffer->getNotFilledSize();
+ }
+
+int RnpTransmitter::getDataSize() const throw()
+ {
+ if ( ! ( commBuffer != 0 ) )
+ {
+ TALK( "RnpTransmitter::getDataSize(): warning: assert will fire." );
+ }
+ assert(commBuffer != 0);
+ return commBuffer->getDataSize();
+ }
+
+//################################################
+
+RnpCarrier::RnpCarrier() throw()
+ {
+ type = RnpTransport::crp_Rnp;
+ }
+
+RnpCarrier::~RnpCarrier() throw()
+ {
+ }
+
+RnpTransport::CarrierProtocol RnpCarrier::getType() throw()
+ {
+ return type;
+ }
+
+int RnpCarrier::getRequestHeaderLength() throw()
+ {
+ requestHeader = true;
+ return 0;
+ }
+
+int RnpCarrier::getAnswerHeaderLength() throw()
+ {
+ requestHeader = false;
+ return 0;
+ }
+
+void RnpCarrier::putHeader(akg::CommBuffer*) throw()
+ { // nothing!!
+ }
+
+
+HttpRnpCarrier::HttpRnpCarrier() throw()
+ {
+ type = RnpTransport::crp_Http;
+ }
+
+
+int HttpRnpCarrier::getRequestHeaderLength() throw()
+ {
+ requestHeader = true;
+ return strlen(theRequestHeader);
+ }
+
+int HttpRnpCarrier::getAnswerHeaderLength() throw()
+ {
+ requestHeader = false;
+ return strlen(theAnswerHeader);
+ }
+
+void HttpRnpCarrier::putHeader(akg::CommBuffer *messageBuffer) throw()
+ {
+ char *data = (char*)messageBuffer->getData();
+
+ const char *header = requestHeader ? theRequestHeader : theAnswerHeader;
+ int headerLength = strlen(header);
+ int posOfLength = headerLength - 14;
+
+ strncpy(data,header,posOfLength);
+
+ sprintf(data + posOfLength, "%10d",messageBuffer->getDataSize() - headerLength);
+
+ strncpy(data + headerLength - 4,"\r\n\r\n",4); // it shouldn't be null terminated!
+ }
+
+const char HttpRnpCarrier::theRequestHeader[]=
+ "POST RnpMessage HTTP/1.1\r\nAccept: bin/rnp\r\nUserAgent: RnpClient/1.0\r\nContent-length: uxxxyyyzzz\r\n\r\n";
+ // ^10 digits
+
+const char HttpRnpCarrier::theAnswerHeader[]=
+ "HTTP/1.1 200 OK\r\nContent-type: bin/rnp\r\nContent-length: uxxxyyyzzz\r\n\r\n";
+
+
+
+BadRnpCarrier::BadRnpCarrier() throw()
+ {
+ type = RnpTransport::crp_BadCarrier;
+ }
+
+int BadRnpCarrier::getRequestHeaderLength() throw()
+ {
+ requestHeader = true;
+ return strlen(theHeader);
+ }
+
+int BadRnpCarrier::getAnswerHeaderLength() throw()
+ {
+ requestHeader = false;
+ return strlen(theHeader);
+ }
+
+void BadRnpCarrier::putHeader(akg::CommBuffer *messageBuffer) throw()
+ {
+ char *data = (char*)messageBuffer->getData();
+
+ strncpy(data,theHeader,strlen(theHeader));
+ }
+
+const char BadRnpCarrier::theHeader[]="BadCarrier";
+
+
diff --git a/rnprotocol/rnpembedded.hh b/rnprotocol/rnpembedded.hh
new file mode 100644
index 0000000..2e7c454
--- /dev/null
+++ b/rnprotocol/rnpembedded.hh
@@ -0,0 +1,256 @@
+#ifndef RNPEMBEDDED_HH
+#define RNPEMBEDDED_HH
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/****************************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ *
+ ****************************************************************************/
+#include "rnprotocol/rnprotocol.hh"
+
+namespace rnp
+ {
+
+/** RNP messages may be embedded in messages of the carrier protocol
+ We will use for now only HTTP carrier or none at all
+ But we define a BadCarrier for testing purposes
+*/
+
+
+/** Class containing definitions and some helper functions
+*/
+class RnpTransport
+ {
+ public:
+ enum CarrierProtocol
+ {
+ crp_Unknown,
+ crp_Rnp,
+ crp_Http,
+ crp_BadCarrier,
+ //....
+ crp_HowMany
+ };
+
+ static const char* getCarrierName(CarrierProtocol) throw();
+ private:
+ static const char* carrierNames[];
+ };
+
+/**
+ RnpReceiver is a class that is able to receive an message in a CommBuffer and decide if it is a
+ valid Rnp message, embedded or not.
+
+ It is designed to be used by a NbJob for receiving the message and cooperate with it.
+
+ If it is an invalid message or the message buffer can't be allocated,
+ the rest of the message is discarded and the NbJob has to close the connection and do appropriate cleaning
+
+ The receiver has two buffers, a fixed length one, for header and a dynamic one for the RNP message
+*/
+
+class RnpReceiver
+ {
+ public:
+ /// Default constructor
+ RnpReceiver() throw();
+
+ /// Destructor
+ ~RnpReceiver() throw();
+
+ /// Resets the receiver, preparing for a new message
+ void reset() throw();
+
+ /// Returns a pointer to the current buffer (the header one or the message one)
+ akg::CommBuffer* getCurrentBuffer() throw();
+
+ /** Returns a pointer to the message buffer, which contains the RNP message,
+ whitout any carrier header */
+ akg::CommBuffer* getMessageBuffer() throw();
+
+ /// Returns 'true' if the whole message was received, 'false' if more data is expected
+ bool validateMessage() throw();
+
+ /** Returns 'true' if an error occured and the message has to be discarded
+ If validate()==false and isDiscarding()==true => NbJob has to reset receiver and close connection*/
+ bool isDiscarding() const throw();
+
+ /// Returns the type of the carrier protocol
+ RnpTransport::CarrierProtocol getCarrierProtocol() const throw();
+
+ /// Returns the size of the carrier header
+ int getCarrierHeaderSize() const throw();
+
+ /// Returns a pointer to the carrier header
+ const void* getCarrierHeader() throw();
+
+ private:
+
+ enum Status
+ {
+ waitingHeader,
+ readingMessage,
+ discarding
+ };
+
+
+ Status status;
+
+ akg::CommBuffer headerBuffer;
+ akg::CommBuffer rnpMessageBuffer;
+
+ RnpHeader *rnpHeader;
+
+ RnpTransport::CarrierProtocol carrier;
+ int carrierHeaderLength;
+
+ static const int headerBufferLength;
+
+ bool isHttpCarrier() throw();
+ bool isRnpCarrier() throw();
+ bool prepareMessageBuffer() throw();
+
+ };
+
+class RnpCarrier;
+
+/** Class for creating an embedded RNP message. Most methods are inherited
+ from RnpProtocolEncoder, it offers just convenient methods for
+ dealing with carriers
+*/
+class RnpTransmitter : public RnpProtocolEncoder
+ {
+ public:
+ /// Default constructor
+ RnpTransmitter() throw();
+
+ /// Destructor
+ ~RnpTransmitter() throw();
+
+ /// Starts a new message, as a request, embedded in a specified protocol
+ bool startRequest(RnpQuark serverType, RnpTransport::CarrierProtocol) throw();
+
+ /// Starts a new message, as an answer, embedded in a specified protocol
+ bool startAnswer(RnpQuark serverType, RnpTransport::CarrierProtocol) throw();
+
+ /// ends the message, puts the carrier headers and, if requested, changes endianness
+ akg::CommBuffer* endMessage() throw();
+
+ /// Returns the carrier protocol
+ RnpTransport::CarrierProtocol getCarrierProtocol() throw();
+
+ /// Returns the total size of the buffer
+ int getBufferSize() const throw();
+
+ /// Return the space left in the buffer
+ int getNotFilledSize() const throw();
+
+ /// Returns the data size in the buffer
+ int getDataSize() const throw();
+ private:
+
+ RnpTransport::CarrierProtocol carrierType;
+
+ /** Creates and returns a RnpCarrier object, based on the type got as parameter
+ It assignes the object to 'carrier' and it also destroys the previous
+ assigned object
+ */
+ RnpCarrier* getCarrierObject(RnpTransport::CarrierProtocol) throw();
+ RnpCarrier* carrier;
+ };
+
+/** Base class for the various carriers, is itself the RNP carrier
+*/
+class RnpCarrier
+ {
+ public:
+ /// Default constructor
+ RnpCarrier() throw();
+
+ /// Virtual destructor
+ virtual ~RnpCarrier() throw();
+
+ /// Returns the type of the object
+ RnpTransport::CarrierProtocol getType() throw();
+
+ /// Returns the length of the request header
+ virtual int getRequestHeaderLength() throw();
+
+ /// Returns the length of the answer header
+ virtual int getAnswerHeaderLength() throw();
+
+ /** Write the header directly into the reserved space of the buffer,
+ since the rest of the message is already there*/
+ virtual void putHeader(akg::CommBuffer*) throw();
+
+ protected:
+ /// The type of the carrier
+ RnpTransport::CarrierProtocol type;
+
+ /// Flag for 'putHeader' to know which header to write
+ bool requestHeader;
+
+ };
+
+/** The HTTP-carrier
+*/
+class HttpRnpCarrier : public RnpCarrier
+ {
+ public:
+ /// Default constructor
+ HttpRnpCarrier() throw();
+
+ /// Returns the length of the request header
+ int getRequestHeaderLength() throw();
+
+ /// Returns the length of the answer header
+ int getAnswerHeaderLength() throw();
+
+ /// Writes the header into the buffer
+ void putHeader(akg::CommBuffer*) throw();
+
+ private:
+ static const char theRequestHeader[];
+ static const char theAnswerHeader[];
+ };
+
+/** A 'bad carrier', just for testing purposes
+*/
+class BadRnpCarrier : public RnpCarrier
+ {
+ public:
+ BadRnpCarrier() throw();
+
+ int getRequestHeaderLength() throw();
+ int getAnswerHeaderLength() throw();
+ void putHeader(akg::CommBuffer*) throw();
+
+ private:
+ static const char theHeader[];
+ };
+
+} //namespace
+#endif
diff --git a/rnprotocol/rnprasserver.cc b/rnprotocol/rnprasserver.cc
new file mode 100644
index 0000000..f877403
--- /dev/null
+++ b/rnprotocol/rnprasserver.cc
@@ -0,0 +1,72 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#include "debug.hh"
+
+#include "rnprasserver.hh"
+
+// forever and ever
+const RnpQuark RnpRasserver::serverID = 3072002;
+
+
+const char* RnpRasserver::parameterTypeNames[pmt_HowMany] =
+ {
+ "(pmt_none)", "pmt_clientid"
+ };
+
+const char* RnpRasserver::commandNames[cmd_HowMany] =
+ {
+ "(cmd_none)", "cmd_connect", "cmd_disconnect",
+ "cmd_opendb", "cmd_closedb", "cmd_beginta",
+ "cmd_committa", "cmd_abortta", "cmd_istaopen",
+ "cmd_queryhttp", "cmd_getnewoid", "cmd_queryrpc",
+ "cmd_getnextelem", "cmd_endtransfer", "cmd_getnextmdd",
+ "cmd_getnexttile", "cmd_updaterpc", "cmd_startinsTmdd",
+ "cmd_inserttile", "cmd_endinsmdd", "cmd_initupdate",
+ "cmd_gettypestruct", "cmd_startinsPmdd", "cmd_insertmdd",
+ "cmd_insertcoll", "cmd_removeobjfromcoll", "cmd_delobjbyoid",
+ "cmd_delcollbyname", "cmd_getcoll", "cmd_getcolloids",
+ "cmd_getobjecttype", "cmd_setformat",
+
+ "cmd_createcollection", "cmd_createmdd", "cmd_extendmdd",
+ "cmd_gettiledomains"
+ };
+
+const char* RnpRasserver::getParameterTypeName(RnpQuark pType) const throw()
+ {
+ if(0<= pType && pType < pmt_HowMany) return parameterTypeNames[pType];
+ return undefValue;
+ }
+
+const char* RnpRasserver::getCommandName(RnpQuark cmd) const throw()
+ {
+ const char *result = NULL;
+
+ if(0<= cmd && cmd < cmd_HowMany)
+ result = commandNames[cmd];
+ else
+ result = undefValue;
+
+ TALK( "RnpRasserver::getCommandName( " << cmd << " ) -> " << result );
+ return result;
+ }
+
diff --git a/rnprotocol/rnprasserver.hh b/rnprotocol/rnprasserver.hh
new file mode 100644
index 0000000..44b6473
--- /dev/null
+++ b/rnprotocol/rnprasserver.hh
@@ -0,0 +1,124 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#ifndef RNPRASSERVER_HH
+#define RNPRASSERVER_HH
+
+#include "rnprotocol/rnprotocol.hh"
+
+using namespace rnp;
+
+class RnpRasserver : public Rnp
+ {
+ public:
+
+ static const RnpQuark serverID; // 3072002
+ enum ParameterType
+ {
+ pmt_none,
+ pmt_clientid = 1,
+ pmt_rErrorString = 2,
+ pmt_dbname = 3,
+ pmt_accesmode = 4,
+ pmt_querystring = 5,
+ pmt_httpqanswer = 6,
+ pmt_oidstring = 7,
+ pmt_capability = 8,
+ pmt_transstatus = 9,
+ pmt_objecttype =10,
+ pmt_returnstatus =11,
+ pmt_skalarobject =12,
+ pmt_tiledata =13,
+ pmt_domain =14,
+ pmt_typename =15,
+ pmt_typelength =16,
+ pmt_typetype =17,
+ pmt_typestructure = 18,
+ pmt_collname = 19,
+ pmt_whichformat = 20,
+ pmt_format = 21,
+ pmt_formatparams = 22,
+ pmt_currentformat = 23,
+ pmt_storageformat = 24,
+ pmt_ispersistent = 25,
+ pmt_errorno = 26,
+ pmt_lineno = 27,
+ pmt_columnno = 28,
+ pmt_errortoken = 29,
+ pmt_indextype = 30,
+ //.......
+ pmt_HowMany
+ };
+
+ enum Command
+ {
+ cmd_none,
+ cmd_connect = 1,
+ cmd_disconnect = 2,
+ cmd_opendb = 3,
+ cmd_closedb = 4,
+ cmd_beginta = 5,
+ cmd_committa = 6,
+ cmd_abortta = 7,
+ cmd_istaopen = 8,
+ cmd_queryhttp = 9,
+ cmd_getnewoid = 10,
+ cmd_queryrpc = 11,
+ cmd_getnextelem = 12,
+ cmd_endtransfer = 13,
+ cmd_getnextmdd = 14,
+ cmd_getnexttile = 15,
+ cmd_updaterpc = 16,
+ cmd_startinsTmdd = 17,
+ cmd_inserttile = 18,
+ cmd_endinsmdd = 19,
+ cmd_initupdate = 20,
+ cmd_gettypestruct = 21,
+ cmd_startinsPmdd = 22,
+ cmd_insertmdd = 23,
+ cmd_insertcoll = 24,
+ cmd_remobjfromcoll = 25,
+ cmd_delobjbyoid = 26,
+ cmd_delcollbyname = 27,
+ cmd_getcoll = 28,
+ cmd_getcolloids = 29,
+ cmd_getobjecttype = 30,
+ cmd_setformat = 31,
+ //-- until here the compatibility functions --
+
+ cmd_createcollection = 32,
+ cmd_createmdd = 33,
+ cmd_extendmdd = 34,
+ cmd_gettiledomains = 35,
+ cmd_HowMany
+ };
+
+ const char* getParameterTypeName(RnpQuark) const throw();
+ const char* getCommandName(RnpQuark) const throw();
+
+ protected:
+ /// Arrays containing the names of the various elements
+ static const char* parameterTypeNames[pmt_HowMany];
+ static const char* commandNames[cmd_HowMany];
+
+ };
+#endif
diff --git a/rnprotocol/rnprotocol.cc b/rnprotocol/rnprotocol.cc
new file mode 100644
index 0000000..ce0deec
--- /dev/null
+++ b/rnprotocol/rnprotocol.cc
@@ -0,0 +1,819 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/****************************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ****************************************************************************/
+
+#include <rnprotocol.hh>
+#include <assert.h>
+
+using namespace rnp;
+using namespace std;
+
+#include "raslib/rminit.hh"
+#include "debug.hh"
+
+
+const RnpQuark Rnp::rnpProtocolId = 25112001;
+
+
+const char* Rnp::endiannessNames[2]=
+ {
+ "big endian", "little endian"
+ };
+
+const char* Rnp::fragmentTypeNames[Rnp::fgt_HowMany]=
+ {
+ "(fgt_none)", "Command", "OkAnswer", "ErrorAnswer"
+ };
+
+const char* Rnp::dataTypeNames[Rnp::dtt_HowMany] =
+ {
+ "(dtt_none)", "Asciiz", "Int32","Float","Double","Opaque","NullPtr"
+ };
+
+const char* Rnp::errorTypeNames[Rnp::ert_HowMany] =
+ {
+ "(ert_unknown)", "StlException", "OtherException"
+ };
+
+const char* Rnp::errorParamNames[Rnp::erp_HowMany] =
+ {
+ "(erp_none)", "StlWhatValue"
+ };
+
+const char* Rnp::undefValue = "(undef)";
+
+const char* Rnp::getFragmentTypeName(RnpQuark fType) throw()
+ {
+ if(0<= fType && fType < fgt_HowMany) return fragmentTypeNames[fType];
+ return undefValue;
+ }
+
+const char* Rnp::getDataTypeName(RnpQuark dType) throw()
+ {
+ if(0<= dType && dType < dtt_HowMany) return dataTypeNames[dType];
+ return undefValue;
+ }
+
+const char* Rnp::getErrorTypeName(RnpQuark eType) throw()
+ {
+ if(0<= eType && eType < ert_HowMany) return errorTypeNames[eType];
+ return undefValue;
+ }
+
+const char* Rnp::getErrorParamName(RnpQuark eName) throw()
+ {
+ if(0<= eName && eName < erp_HowMany) return errorParamNames[eName];
+ return undefValue;
+ }
+
+const char* Rnp::getEndiannessName(Rnp::Endianness endianness) throw()
+ {
+ return endiannessNames[endianness];
+ }
+
+Rnp::Endianness Rnp::detectHostEndianness() throw()
+ {
+ unsigned int uInteger = 1;
+
+ char* ptr = (char*)&uInteger;
+
+ return *ptr==1 ? littleEndian : bigEndian;
+ }
+
+RnpQuark Rnp::swapBytes(RnpQuark orig) throw()
+ {
+ RnpQuark result = orig;
+
+ char *buf = (char*)&result;
+
+ char tmp = buf[0];
+ buf[0] = buf[3];
+ buf[3] = tmp;
+
+ tmp = buf[1];
+ buf[1] = buf[2];
+ buf[2] = tmp;
+
+ return result;
+ }
+
+//############## RNP Header #################################
+
+bool RnpHeader::isRnpMessage() const throw()
+ {
+ Rnp::Endianness hostEndianness = Rnp::detectHostEndianness();
+
+ RnpQuark cProtocolId = hostEndianness == Rnp::littleEndian ? protocolId : Rnp::swapBytes(protocolId);
+
+ return cProtocolId == Rnp::rnpProtocolId ? true:false;
+ }
+
+Rnp::Endianness RnpHeader::getEndianness() const throw()
+ {
+ return (Rnp::Endianness)messageEndianness;
+ }
+
+RnpQuark RnpHeader::getTotalLength() const throw()
+ {
+ Rnp::Endianness endianness = (Rnp::Endianness)messageEndianness;
+ return endianness == Rnp::detectHostEndianness() ? totalMessageLength : Rnp::swapBytes(totalMessageLength);
+ }
+
+bool RnpHeader::changeEndianness(Rnp::Endianness newEndianness) throw()
+ {
+ Rnp::Endianness endianness = (Rnp::Endianness)messageEndianness;
+
+ if(newEndianness == endianness) return false; // no change necessary
+
+ messageEndianness = newEndianness;
+
+ totalMessageLength = Rnp::swapBytes(totalMessageLength);
+ nrFragments = Rnp::swapBytes(nrFragments);
+ serverType = Rnp::swapBytes(serverType);
+ authInfoStart = Rnp::swapBytes(authInfoStart);
+ authInfoLength = Rnp::swapBytes(authInfoLength);
+ comprInfoStart = Rnp::swapBytes(comprInfoStart);
+ comprInfoLength = Rnp::swapBytes(comprInfoLength);
+ dataStart = Rnp::swapBytes(dataStart);
+ dataLength = Rnp::swapBytes(dataLength);
+
+ return true;
+ }
+
+RnpFragmentHeader* RnpHeader::getFirstFragment() const throw()
+ {
+ return (RnpFragmentHeader*)((char*)this + dataStart);
+ }
+
+//############ RNP Fragment ##################################
+
+RnpFragmentHeader* RnpFragmentHeader::getNextFragment() const throw()
+ {
+ char *ptr = (char*)this;
+
+ return (RnpFragmentHeader*)(ptr + totalLength);
+ }
+
+RnpParameter* RnpFragmentHeader::getFirstParameter() const throw()
+ {
+ return (RnpParameter*)(this+1);
+ }
+
+void RnpFragmentHeader::changeEndianness() throw()
+ {
+ // there is no info about the initial endianness so be carefull
+ fragmType = Rnp::swapBytes(fragmType);
+ command = Rnp::swapBytes(command);
+ nrParams = Rnp::swapBytes(nrParams);
+ totalLength = Rnp::swapBytes(totalLength);
+ }
+
+//############ RNP Parameter ##################################
+RnpParameter* RnpParameter::getNextParameter() const throw()
+ {
+ char *ptr = (char*)this;
+ return (RnpParameter*)(ptr + totalLength);
+ }
+
+void* RnpParameter::getData() const throw()
+ {
+ return (void*)(this+1);
+ }
+
+RnpQuark RnpParameter::getDataLength() const throw()
+ {
+ return dataLength;
+ }
+
+RnpQuark RnpParameter::computeTotalAlignedLength() throw()
+ {
+ totalLength = (sizeof(RnpParameter) + dataLength + 3) & 0xFFFFFFFC;
+ return totalLength;
+ }
+
+RnpQuark RnpParameter::getPaddLength() const throw()
+ {
+ return totalLength - (sizeof(RnpParameter) + dataLength);
+ }
+
+void RnpParameter::changeToHostEndianness() throw()
+ {
+ // there is no info about the initial endianness so be carefull
+ paramType = Rnp::swapBytes(paramType);
+ dataType = Rnp::swapBytes(dataType);
+ dataLength = Rnp::swapBytes(dataLength);
+ totalLength = Rnp::swapBytes(totalLength);
+
+ RnpQuark *valPtr = (RnpQuark*)getData();
+ switch(dataType)
+ {
+ case Rnp::dtt_Int32:
+ case Rnp::dtt_Float32: *valPtr = Rnp::swapBytes(*valPtr);
+ break;
+
+ case Rnp::dtt_Double64: RnpQuark temp = Rnp::swapBytes(*valPtr);
+ *valPtr = Rnp::swapBytes(*(valPtr +1));
+ *(valPtr+1) = temp;
+ break;
+ }
+ }
+
+void RnpParameter::changeToPartnerEndianness() throw()
+ {
+ // there is no info about the initial endianness so be careful
+
+ RnpQuark *valPtr = (RnpQuark*)getData();
+ switch(dataType)
+ {
+ case Rnp::dtt_Int32:
+ case Rnp::dtt_Float32: *valPtr = Rnp::swapBytes(*valPtr);
+ break;
+
+ case Rnp::dtt_Double64: RnpQuark temp = Rnp::swapBytes(*valPtr);
+ *valPtr = Rnp::swapBytes(*(valPtr +1));
+ *(valPtr+1) = temp;
+ break;
+ }
+ paramType = Rnp::swapBytes(paramType);
+ dataType = Rnp::swapBytes(dataType);
+ dataLength = Rnp::swapBytes(dataLength);
+ totalLength = Rnp::swapBytes(totalLength);
+ }
+
+//###########################################################
+
+RnpProtocolEncoder::RnpProtocolEncoder() throw()
+ {
+ commBuffer = NULL;
+
+ rnpHeader = NULL;
+ currFragment = NULL;
+ currParameter = NULL;
+ allocated = false;
+ carrierHeaderSize = 0;
+ finalEndianness = Rnp::detectHostEndianness();
+ }
+
+RnpProtocolEncoder::~RnpProtocolEncoder() throw()
+ {
+ if(commBuffer != NULL && allocated == true) delete commBuffer;
+ // the other pointers are not pointing to allocated memory!!
+ }
+
+void RnpProtocolEncoder::setBuffer(akg::CommBuffer* buffer) throw()
+ {
+ if(commBuffer != NULL && allocated == true) delete commBuffer;
+
+ commBuffer = buffer;
+ allocated = false;
+ }
+
+bool RnpProtocolEncoder::allocateBuffer(int maxMessageLength) throw()
+ {
+ if(commBuffer != NULL && allocated ==true) delete commBuffer;
+
+ commBuffer = new akg::CommBuffer(maxMessageLength);
+ allocated = true;
+ return true;
+ }
+
+bool RnpProtocolEncoder::adjustBufferSize(int differenceSize) throw()
+ {
+ ENTER( "RnpProtocolEncoder::adjustBufferSize( differenceSize=" << differenceSize << " )" );
+
+ if (commBuffer == 0)
+ {
+ TALK( "RnpProtocolEncoder::adjustBufferSize(): warning: null commBuffer, assert would fire." );
+ return false;
+ }
+ assert(commBuffer != 0);
+
+ if (differenceSize <= 0)
+ {
+ TALK( "RnpProtocolEncoder::adjustBufferSize(): warning: nonpositive differenceSize, assert would fire." );
+ return false;
+ }
+ assert(differenceSize > 0);
+
+ // we need to adjust the pointers to the new location
+ char *orig = (char*)(commBuffer->getData());
+ char *head = (char*)rnpHeader;
+ char *frag = (char*)currFragment;
+ char *para = (char*)currParameter;
+
+ if(commBuffer->resize(commBuffer->getDataSize() + differenceSize + RNP_DEFAULTBUFFERSIZE) == true)
+ {
+ char *final = (char*)(commBuffer->getData());
+ rnpHeader = (RnpHeader*)(final + (head - orig));
+ currFragment = (RnpFragmentHeader*)(final + (frag - orig));
+ currParameter= (RnpParameter*)(final + (para - orig));
+ LEAVE( "RnpProtocolEncoder::adjustBufferSize() -> true" );
+ return true;
+ }
+
+ LEAVE( "RnpProtocolEncoder::adjustBufferSize() -> false" );
+ return false;
+ }
+
+int RnpProtocolEncoder::getBufferSize() throw()
+ {
+ if (commBuffer == 0)
+ {
+ TALK( "RnpProtocolEncoder::getBufferSize(): warning: null commBuffer, assert will fire." );
+ }
+ assert(commBuffer != 0);
+
+ return commBuffer->getBufferSize();
+ }
+
+void RnpProtocolEncoder::startMessage(RnpQuark serverType, int nCarrierHeaderSize) throw()
+ {
+ if (commBuffer == 0)
+ {
+ TALK( "RnpProtocolEncoder::startMessage(): warning: null commBuffer, assert will fire." );
+ }
+ assert(commBuffer != NULL);
+
+ carrierHeaderSize = nCarrierHeaderSize;
+
+ commBuffer->clearToRead();
+
+ commBuffer->reserve(sizeof(RnpHeader) + carrierHeaderSize);
+
+ rnpHeader = (RnpHeader*)((char*)commBuffer->getData() + carrierHeaderSize);
+
+ Rnp::Endianness hostEndianness = Rnp::detectHostEndianness();
+
+ // the protocolID is always 25112001 little endian!!
+ rnpHeader->protocolId = hostEndianness == Rnp::littleEndian ? Rnp::rnpProtocolId : Rnp::swapBytes(Rnp::rnpProtocolId);
+
+ rnpHeader->messageEndianness = hostEndianness;
+ rnpHeader->desiredEndianness = hostEndianness;
+ rnpHeader->majorVersion = 1;
+ rnpHeader->minorVersion = 0;
+ rnpHeader->totalMessageLength = sizeof(RnpHeader);
+ rnpHeader->nrFragments = 0;
+ rnpHeader->serverType = serverType;
+ rnpHeader->authInfoStart = 0;
+ rnpHeader->authInfoLength = 0;
+ rnpHeader->comprInfoStart = 0;
+ rnpHeader->comprInfoLength = 0;
+ rnpHeader->dataStart = sizeof(RnpHeader);
+ rnpHeader->dataLength = 0;
+
+ currFragment = (RnpFragmentHeader*)(rnpHeader+1);
+
+ }
+
+int RnpProtocolEncoder::getCarrierHeaderSize() throw()
+ {
+ return carrierHeaderSize;
+ }
+
+void RnpProtocolEncoder::setDesiredEndianness(Rnp::Endianness desiredEndianness) throw()
+ {
+ rnpHeader->desiredEndianness = desiredEndianness;
+ }
+void RnpProtocolEncoder::setFinalEndianness(Rnp::Endianness endianness) throw()
+ {
+ finalEndianness = endianness;
+ }
+
+void RnpProtocolEncoder::startFragment(Rnp::FragmentType fType,RnpQuark command) throw()
+ {
+ commBuffer->reserve(sizeof(RnpFragmentHeader));
+
+ currFragment->fragmType = fType;
+ currFragment->command = command;
+ currFragment->nrParams = 0;
+ currFragment->totalLength = sizeof(RnpFragmentHeader);
+
+ currParameter = currFragment->getFirstParameter();
+ rnpHeader->nrFragments++;
+
+ }
+
+void RnpProtocolEncoder::addStringParameter(RnpQuark parameterType,const char* str) throw()
+ {
+ if(str != 0) addParameter(parameterType, Rnp::dtt_Asciiz, str, strlen(str)+1);
+ else addParameter(parameterType, Rnp::dtt_NullPtr, str, 0);
+ }
+
+void RnpProtocolEncoder::addInt32Parameter(RnpQuark parameterType, int par) throw()
+ {
+ addParameter(parameterType, Rnp::dtt_Int32, &par, sizeof(par));
+ }
+
+void RnpProtocolEncoder::addFloat32Parameter(RnpQuark parameterType, float par) throw()
+ {
+ addParameter(parameterType, Rnp::dtt_Float32, &par, sizeof(par));
+ }
+void RnpProtocolEncoder::addDouble64Parameter(RnpQuark parameterType, double par) throw()
+ {
+ addParameter(parameterType, Rnp::dtt_Double64, &par, sizeof(par));
+ }
+
+void RnpProtocolEncoder::addOpaqueParameter(RnpQuark parameterType, const void *buf, int size) throw()
+ {
+ if(buf != 0) addParameter(parameterType, Rnp::dtt_Opaque, buf, size);
+ else addParameter(parameterType, Rnp::dtt_NullPtr, buf, 0);
+ }
+
+void RnpProtocolEncoder::addParameter(RnpQuark parameterType, Rnp::DataType dtt, const void *data, int length) throw()
+ {
+ commBuffer->reserve(sizeof(RnpParameter));
+
+ currParameter->paramType = parameterType;
+ currParameter->dataType = dtt;
+ currParameter->dataLength = length;
+ currParameter->totalLength = currParameter->computeTotalAlignedLength();
+
+ int paddlen = currParameter->getPaddLength();
+
+ if(data != 0 ) commBuffer->read(data,length);
+ if(paddlen) commBuffer->reserve(paddlen);
+
+ currFragment->nrParams++;
+ currFragment->totalLength += currParameter->totalLength;
+ currParameter = currParameter->getNextParameter();
+ }
+
+void RnpProtocolEncoder::endFragment() throw()
+ {
+ rnpHeader->totalMessageLength += currFragment->totalLength;
+ rnpHeader->dataLength += currFragment->totalLength;
+ currFragment = currFragment->getNextFragment();
+ }
+
+akg::CommBuffer* RnpProtocolEncoder::endMessage() throw()
+ {
+ changeToPartnerEndianness(finalEndianness);
+ return commBuffer;
+ }
+
+bool RnpProtocolEncoder::changeToPartnerEndianness(Rnp::Endianness newEndianness) throw()
+ {
+ if(newEndianness == rnpHeader->getEndianness()) return false;
+ // so newEndianness is the same as the message endiannes, no change necessary
+
+ // don't forget that the endianness is now the host endianness so,
+ // after changed, the data can't be used correctly any more!!
+
+ RnpFragmentHeader* lCurrFragment = rnpHeader->getFirstFragment();
+
+ for(int fragment=0; fragment < rnpHeader->nrFragments; fragment++)
+ {
+
+ RnpParameter* lCurrParameter = lCurrFragment->getFirstParameter();
+ for(int parameter = 0; parameter < lCurrFragment->nrParams; parameter++)
+ {
+ RnpParameter* nextParameter = lCurrParameter->getNextParameter();
+ lCurrParameter->changeToPartnerEndianness();
+ lCurrParameter = nextParameter;
+ }
+
+ RnpFragmentHeader* nextFragment = lCurrFragment->getNextFragment();
+ lCurrFragment->changeEndianness();
+ lCurrFragment = nextFragment;
+ }
+
+ rnpHeader->changeEndianness(newEndianness);
+
+ return true;
+ }
+
+//###### DECODER #######################
+
+RnpProtocolDecoder::RnpProtocolDecoder() throw()
+ {
+ // this memory doesn't belong to us, so do not deallocate!!
+ commBuffer = NULL;
+ rnpHeader = NULL;
+ currFragment = NULL;
+ currParameter = NULL;
+ }
+
+bool RnpProtocolDecoder::decode(akg::CommBuffer *buffer) throw()
+ {
+ // Later, throw something intelligible!
+ commBuffer = buffer;
+
+ rnpHeader = (RnpHeader*)commBuffer->getData();
+
+ if(rnpHeader->isRnpMessage() == false) return false;
+
+ originalEndianness = rnpHeader->getEndianness();
+
+ if(originalEndianness == Rnp::detectHostEndianness())
+ {
+ // -- test validity of message --
+ if(testIntegrity() == false) return false;
+ }
+ else
+ { // -- endianess of message --
+ changeToHostEndianness();
+ }
+ return true;
+ }
+
+bool RnpProtocolDecoder::testIntegrity() const throw()
+ {
+ // could be done better...
+ ENTER( "RnpProtocolDecoder::testIntegrity()" );
+
+ if(rnpHeader->isRnpMessage() == false)
+ {
+ RMInit::logOut << "Communication error: received invalid RNP header." << endl;
+ return false;
+ }
+
+ bool ok = true;
+ char *endOfMessage = (char*)rnpHeader + rnpHeader->getTotalLength();
+ char *endOfHeader = (char*)rnpHeader + sizeof(RnpHeader);
+ int maxLength = commBuffer->getDataSize() - sizeof(RnpHeader);
+ // max of every length
+
+ RnpFragmentHeader* lCurrFragment = (RnpFragmentHeader*)getFirstFragment();
+ for(int fragment=0; fragment < countFragments(); fragment++)
+ {
+ if( endOfHeader <= (char*)lCurrFragment && (char*)lCurrFragment < endOfMessage)
+ ;
+ else
+ {
+ ok = false;
+ RMInit::logOut << "Communication error: RNP message corrupt: short header." << endl;
+ break;
+ }
+
+ if(lCurrFragment->totalLength > maxLength)
+ {
+ ok = false;
+ RMInit::logOut << "Communication error: RNP message corrupt: actual length (" << lCurrFragment->totalLength << ") larger than foreseen (" << maxLength << ")." << endl;
+ break;
+ }
+
+ char *startOfParameters = (char*)lCurrFragment + sizeof(RnpFragmentHeader);
+ char *endOfParameters = (char*)lCurrFragment + lCurrFragment->totalLength;
+
+ RnpParameter* lCurrParameter = (RnpParameter*)getFirstParameter();
+ for(int parameter = 0; parameter < countParameters(); parameter++)
+ {
+ if( startOfParameters <= (char*)lCurrParameter && (char*)lCurrParameter < endOfParameters)
+ ;
+ else
+ {
+ ok = false;
+ RMInit::logOut << "Communication error: RNP message corrupt: current parameter location outside parameter area." << endl;
+ break;
+ }
+
+ if(lCurrParameter->totalLength > lCurrFragment->totalLength)
+ {
+ ok = false;
+ RMInit::logOut << "Communication error: RNP message corrupt: current parameter length (" << lCurrParameter->totalLength << ") larger than total fragment size (" << lCurrFragment->totalLength << ")." << endl;
+ break;
+ }
+
+ lCurrParameter = (RnpParameter*)getNextParameter();
+ }
+
+ if( (char*)lCurrParameter != endOfParameters)
+ {
+ ok = false;
+// the counting seems to differ from the protocol specs;
+// to avoid log flooding we disable it for the moment being -- PB 2005-aug-28
+#ifdef RMANDEBUG
+ RMInit::logOut << "Communication warning: puzzled by message: parameter count too small, found extra parameter(s). (this message can be ignored)" << endl;
+#endif
+ }
+
+ if(ok == false)
+ break;
+
+ // we found a valid fragment, proceed to next one
+ lCurrFragment = (RnpFragmentHeader*)getNextFragment();
+ }
+
+ LEAVE( "RnpProtocolDecoder::testIntegrity() -> " << ok );
+ return ok;
+ }
+
+bool RnpProtocolDecoder::changeToHostEndianness() throw()
+ {
+ if(rnpHeader->changeEndianness(Rnp::detectHostEndianness()) == false ) return false;
+ // so host endianness is the same as the message endiannes, no change necessary
+
+ currFragment = (RnpFragmentHeader*)getFirstFragment();
+
+ for(int fragment=0; fragment < countFragments(); fragment++)
+ {
+ currFragment->changeEndianness();
+
+ currParameter = (RnpParameter*)getFirstParameter();
+ for(int parameter = 0; parameter < countParameters(); parameter++)
+ {
+ currParameter->changeToHostEndianness();
+
+ currParameter = (RnpParameter*)getNextParameter();
+ }
+
+ currFragment = (RnpFragmentHeader*)getNextFragment();
+ }
+ return true;
+ }
+
+RnpQuark RnpProtocolDecoder::getDestinationServerType() const throw()
+ {
+ return rnpHeader->serverType;
+ }
+
+Rnp::Endianness RnpProtocolDecoder::getDesiredEndianness() const throw()
+ {
+ return (Rnp::Endianness)rnpHeader->desiredEndianness;
+ }
+
+Rnp::Endianness RnpProtocolDecoder::getOriginalEndianness() const throw()
+ {
+ return originalEndianness;
+ }
+
+int RnpProtocolDecoder::getMessageLength() const throw()
+ {
+ return rnpHeader->totalMessageLength;
+ }
+
+int RnpProtocolDecoder::getMessageVersion() const throw()
+ {
+ return 1000*rnpHeader->majorVersion + rnpHeader->minorVersion;
+ }
+
+RnpQuark RnpProtocolDecoder::countFragments() const throw()
+ {
+ return rnpHeader->nrFragments;
+ }
+
+const RnpFragmentHeader* RnpProtocolDecoder::getFirstFragment() const throw()
+ {
+ currFragmentIdx = 0;
+
+ return currFragment = (currFragmentIdx < rnpHeader->nrFragments ? rnpHeader->getFirstFragment() : 0);
+ }
+
+const RnpFragmentHeader* RnpProtocolDecoder::getNextFragment() const throw()
+ {
+ currFragmentIdx++;
+
+ return currFragment = (currFragmentIdx < rnpHeader->nrFragments ? currFragment->getNextFragment() : 0);
+ }
+
+RnpQuark RnpProtocolDecoder::getFragmentType() const throw()
+ {
+ return currFragment->fragmType;
+ }
+
+const char* RnpProtocolDecoder::getFragmentTypeName() const throw()
+ {
+ return Rnp::getFragmentTypeName(currFragment->fragmType);
+ }
+RnpQuark RnpProtocolDecoder::getCommand() const throw()
+ {
+ return currFragment->command;
+ }
+
+int RnpProtocolDecoder::countParameters() const throw()
+ {
+ return currFragment->nrParams;
+ }
+
+RnpQuark RnpProtocolDecoder::getFragmentLength() const throw()
+ {
+ return currFragment->totalLength;
+ }
+
+const RnpParameter* RnpProtocolDecoder::getFirstParameter() const throw()
+ {
+ currParameterIdx = 0;
+
+ return currParameter = ( currParameterIdx < currFragment->nrParams ? currFragment->getFirstParameter() : 0);
+ }
+
+const RnpParameter* RnpProtocolDecoder::getNextParameter() const throw()
+ {
+ currParameterIdx++;
+
+ return currParameter = ( currParameterIdx < currFragment->nrParams ? currParameter->getNextParameter() : 0);
+ }
+
+RnpQuark RnpProtocolDecoder::getParameterType() const throw()
+ {
+ return currParameter->paramType;
+ }
+
+RnpQuark RnpProtocolDecoder::getDataType() const throw()
+ {
+ return currParameter->dataType;
+ }
+
+const void* RnpProtocolDecoder::getData() const throw()
+ {
+ return currParameter->getData();
+ }
+
+const char* RnpProtocolDecoder::getDataAsString() const throw()
+ {
+ if ( !( currParameter->dataType == Rnp::dtt_Asciiz || currParameter->dataType == Rnp::dtt_NullPtr) )
+ {
+ TALK( "RnpProtocolEncoder::getDataAsString(): warning: assert will fire." );
+ }
+ assert(currParameter->dataType == Rnp::dtt_Asciiz || currParameter->dataType == Rnp::dtt_NullPtr);
+
+ return currParameter->dataType == Rnp::dtt_Asciiz ? (const char*)currParameter->getData() : (const char*)0;
+ }
+
+int RnpProtocolDecoder::getDataAsInteger() const throw()
+ {
+ if ( !( currParameter->dataType == Rnp::dtt_Int32 ) )
+ {
+ TALK( "RnpProtocolEncoder::getDataAsInteger(): warning: assert will fire." );
+ }
+ assert(currParameter->dataType == Rnp::dtt_Int32);
+
+ return *(int*)currParameter->getData();
+ }
+
+float RnpProtocolDecoder::getDataAsFloat() const throw()
+ {
+ if ( !( currParameter->dataType == Rnp::dtt_Float32 ) )
+ {
+ TALK( "RnpProtocolEncoder::getDataAsFloat(): warning: assert will fire." );
+ }
+ assert(currParameter->dataType == Rnp::dtt_Float32);
+
+ return *(float*)currParameter->getData();
+ }
+
+double RnpProtocolDecoder::getDataAsDouble() const throw()
+ {
+ if ( !( currParameter->dataType == Rnp::dtt_Double64 ) )
+ {
+ TALK( "RnpProtocolEncoder::getDataAsDouble(): warning: assert will fire." );
+ }
+ assert(currParameter->dataType == Rnp::dtt_Double64);
+
+ return *(double*)currParameter->getData();
+ }
+
+const void* RnpProtocolDecoder::getDataAsOpaque() const throw()
+ {
+ if ( !( currParameter->dataType == Rnp::dtt_Opaque || currParameter->dataType == Rnp::dtt_NullPtr) )
+ {
+ TALK( "RnpProtocolEncoder::getDataAsOpaque(): warning: assert will fire." );
+ }
+ assert(currParameter->dataType == Rnp::dtt_Opaque || currParameter->dataType == Rnp::dtt_NullPtr);
+
+ return currParameter->dataType == Rnp::dtt_Opaque ? (const void*)currParameter->getData() : (const void*)0;
+ }
+
+int RnpProtocolDecoder::getDataLength() const throw()
+ {
+ return currParameter->getDataLength();
+ }
+
+void RnpProtocolDecoder::printRnpHeader(RnpHeader *lRnpHeader) const throw()
+ {
+ cout<<"RnpHeader ID="<<lRnpHeader->protocolId<<endl;
+ cout<<" total fragments="<<lRnpHeader->nrFragments<<endl;
+ cout<<" sizeof header="<<sizeof(RnpHeader)<<endl;
+ cout<<endl;
+ }
+
+bool RnpProtocolDecoder::isRnpMessage() const throw()
+ {
+ return rnpHeader->isRnpMessage();
+ }
+
diff --git a/rnprotocol/rnprotocol.hh b/rnprotocol/rnprotocol.hh
new file mode 100644
index 0000000..dfa7885
--- /dev/null
+++ b/rnprotocol/rnprotocol.hh
@@ -0,0 +1,462 @@
+#ifndef RNPROTOCOL_HH
+#define RNPROTOCOL_HH
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/****************************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ *
+ ****************************************************************************/
+
+#include "network/akgnetwork.hh"
+#ifdef AFTERV52
+ #include "akglogging.hh"
+ #include "rnpexception.hh"
+#else
+ #define AKGLOGLN(a,b,c)
+#endif
+
+namespace rnp
+ {
+
+//using namespace akg;
+
+/** If nothing else is specified, this is the size of the RNP buffers
+ It is enough as long as you dont send large opaque data */
+#define RNP_DEFAULTBUFFERSIZE 1024
+
+/// The basic type used in RNP. It is always 32-bit long
+typedef int RnpQuark;
+
+/** Class Rnp contains definitions and general helper functions for RNP
+*/
+class Rnp
+ {
+ public:
+ /** The 32-bit protocol ID. value 25112001, stored always little endian.
+ In big endian this is 0xc12d7f01.
+ */
+ static const RnpQuark rnpProtocolId;//always little endian!!!
+
+ enum Endianness
+ {
+ bigEndian = 0,
+ littleEndian = 1
+ };
+
+ enum FragmentType
+ {
+ fgt_None = 0,
+ fgt_Command,
+ fgt_OkAnswer,
+ fgt_Error,
+ fgt_DiscardedRequest,
+ //...
+ // to know how many where defined
+ fgt_HowMany
+ };
+ enum DataType
+ {
+ dtt_None = 0,
+ dtt_Asciiz = 1,
+ dtt_Int32 = 2,
+ dtt_Float32 = 3,
+ dtt_Double64 = 4,
+ dtt_Opaque = 5,
+ dtt_NullPtr = 6, // NULL pointer
+ //...
+ // to know how many where defined
+ dtt_HowMany
+ };
+
+ // the type of the error, so the receiver can rebuild it
+ enum ErrorType
+ {
+ ert_Unknown = 0, // unknown error type, no exception, something else
+ ert_StlException, // ... has a "what()" - member
+ ert_AkgSerializable, // akg serializable exception, we don't carry usual exceptions!
+ ert_Other, // other exceptions
+
+ ert_HowMany
+ };
+
+ enum ErrorParam
+ {
+ erp_None = 0,
+ erp_whatValue = 1, // used by "exception"
+ erp_Key = 2, // key of "akgexception"
+ erp_Value = 3, // value of "akgexception"
+
+ erp_HowMany
+ };
+
+ /// Functions to get the names of the various elements
+ static const char* getFragmentTypeName(RnpQuark) throw();
+ static const char* getDataTypeName(RnpQuark) throw();
+ static const char* getEndiannessName(Endianness) throw();
+ static const char* getErrorTypeName(RnpQuark) throw();
+ static const char* getErrorParamName(RnpQuark) throw();
+
+ /** Every server has his own command set, each with parameters
+ Define your own functions to get names for this elements */
+ virtual const char* getParameterTypeName(RnpQuark) const throw() =0;
+ virtual const char* getCommandName(RnpQuark) const throw() =0;
+
+ /// Helper functions for endianness
+ static RnpQuark swapBytes(RnpQuark) throw();
+ static Endianness detectHostEndianness() throw();
+
+#ifdef AFTERV52
+ /// Log connection for the whole RNP module
+ static AkgLogConnection logConn;
+#endif
+ protected:
+ /// Arrays containing the names of the various elements
+ static const char* undefValue;
+ static const char* endiannessNames[2];
+ static const char* fragmentTypeNames[fgt_HowMany];
+ static const char* dataTypeNames[dtt_HowMany];
+ static const char* errorTypeNames[ert_HowMany];
+ static const char* errorParamNames[erp_HowMany];
+ };
+
+struct RnpFragmentHeader;
+
+/** The header of the RNP message. Always 64 bytes long
+*/
+struct RnpHeader
+ {
+ RnpQuark protocolId;
+ char messageEndianness;
+ char desiredEndianness;
+ char majorVersion;
+ char minorVersion;
+ RnpQuark totalMessageLength;
+ RnpQuark nrFragments;
+ RnpQuark serverType;
+ RnpQuark authInfoStart;
+ RnpQuark authInfoLength;
+ RnpQuark comprInfoStart;
+ RnpQuark comprInfoLength;
+ RnpQuark dataStart;
+ RnpQuark dataLength;
+ RnpQuark _unused[5];
+ // sizeof = 64
+
+ /// Returns 'true' if this is a valid RNP header
+ bool isRnpMessage() const throw();
+
+ /// Returns the message endianness
+ Rnp::Endianness getEndianness() const throw();
+
+ /// Returns the total length of the message, regardless of endianness
+ RnpQuark getTotalLength() const throw();
+
+ /** Changes the endianness of the header to the specified one
+ Returns 'true' if a change was necessary */
+ bool changeEndianness(Rnp::Endianness) throw();
+
+ /// Returns a pointer to the first fragment. Header has to be in host endianness
+ RnpFragmentHeader* getFirstFragment() const throw();
+ };
+
+/** The header of parameters. Size is 16.
+ The parameter has a header like this and then the data
+*/
+struct RnpParameter
+ {
+ /// The logical type of the parameter. Server dependent
+ RnpQuark paramType;
+
+ /// The data type of the parameter. One of Rnp::DataType
+ RnpQuark dataType;
+
+ /// The length of the data
+ RnpQuark dataLength;
+
+ /// Total length of teh parameter, header + data + alignment bytes
+ // (Length is always 4bytes aligned!, at least Sun requires it)
+ RnpQuark totalLength;
+
+ /// Returns a pointer to the next parameter
+ RnpParameter* getNextParameter() const throw();
+
+ /// Returns a pointer to the parameter data
+ void* getData() const throw();
+
+ /// Returns the length of the parameter data
+ RnpQuark getDataLength() const throw();
+
+ /** Changes the endianness of the parameter. Since there is no info
+ about the current endianness, be carefull when you use it.
+ It also changes the endianness of the data, except when it is
+ opaque data.*/
+ void changeToHostEndianness() throw();
+ void changeToPartnerEndianness() throw();
+
+ RnpQuark computeTotalAlignedLength() throw();
+ RnpQuark getPaddLength() const throw();
+ };
+
+/** The header of fragments. Size is 16.
+ Every fragment has a header like this and a number of parameters
+*/
+struct RnpFragmentHeader
+ {
+ /// The type of the fragment. One of Rnp::FragmentType
+ RnpQuark fragmType;
+
+ /// The command. Server dependent
+ RnpQuark command;
+
+ /// Number of parameters
+ RnpQuark nrParams;
+
+ /// Total length of the fragment, this header + all parameters
+ RnpQuark totalLength;
+
+ /// Returns a pointer to the next fragment
+ RnpFragmentHeader* getNextFragment() const throw();
+
+ /// Returns a pointer to the first parameter of this fragment
+ RnpParameter* getFirstParameter() const throw();
+
+ /** Changes the endianness of the fragment. Since there is no info
+ about the current endianness, be carefull when you use it */
+ void changeEndianness() throw();
+ };
+
+/** Class for encoding a RNP message. It has support for the header of the
+ embedding protocol and for the endianness of the partner. The rest is for
+ creating the message into a akg::CommBuffer, which can be internal or external.
+ The buffer has to be big enough, the size is not adapted
+*/
+class RnpProtocolEncoder
+ {
+ public:
+ /// Default constructor
+ RnpProtocolEncoder() throw();
+ /// Destructor
+ ~RnpProtocolEncoder() throw();
+
+ /// Sets an external buffer as work buffer.
+ void setBuffer(akg::CommBuffer*) throw();
+
+ /// Allocates an internal buffer as work buffer
+ bool allocateBuffer(int maxMessageLength) throw();
+
+ /** resizes the internal buffer, so the new buffer can hold the actual data plus
+ the requested difference. Additionally we allocate also RNP_DEFAULTBUFFERSIZE bytes
+ Assert: commBuffer != 0 , differenceSize >= 0*/
+ bool adjustBufferSize(int differenceSize) throw();
+
+ int getBufferSize() throw();
+
+ /** Makes the necessary initializations for a new message.
+ Takes as parameter the type of the destination server and allocates
+ space for an embedding protocol header
+ Assert: commBuffer != NULL, meaning there is a valid working buffer
+
+ IMPORTANT: Be aware that all this functions for creating the
+ message have to be called in the correct order, otherwise undefined
+ results may occur!
+ */
+ void startMessage(RnpQuark serverType, int carrierHeaderSize = 0) throw();
+
+ /** Sets the desired endianness for the answer. Servers have to use
+ this endianness when they answer, clients might use it for the next
+ requests
+ */
+ void setDesiredEndianness(Rnp::Endianness) throw();
+
+ /** Sets the final endianness for the message. 'endMessage()' is the one
+ who changes the endianness to the final one
+ */
+ void setFinalEndianness(Rnp::Endianness) throw();
+
+ /// Starts a new fragment.
+ void startFragment(Rnp::FragmentType, RnpQuark command) throw();
+
+ /// Adds a string parameter to the current fragment
+ void addStringParameter(RnpQuark parameterType, const char*) throw();
+
+ /// Adds an int parameter to the current fragment
+ void addInt32Parameter(RnpQuark parameterType, int) throw();
+
+ /// Adds a float parameter to the current fragment
+ void addFloat32Parameter(RnpQuark parameterType, float) throw();
+
+ /// Adds a double parameter to the current fragment
+ void addDouble64Parameter(RnpQuark parameterType, double) throw();
+
+ /// Adds an opaque parameter to the current fragment
+ void addOpaqueParameter(RnpQuark parameterType, const void*, int size) throw();
+
+ /// Ends the current fragment
+ void endFragment() throw();
+
+ /// Ends the message and, if necessary, changes the endianness
+ akg::CommBuffer* endMessage() throw();
+
+ /// Returns the size of the reserved space for the embedding carrier header
+ int getCarrierHeaderSize() throw();
+
+ protected:
+
+ akg::CommBuffer *commBuffer;
+
+ private:
+
+ /// Helper function to add a parameter to the current fragment
+ void addParameter(RnpQuark parameterType, Rnp::DataType, const void *data, int length) throw();
+
+ /// The function which does the endianness change
+ bool changeToPartnerEndianness(Rnp::Endianness) throw();
+
+ bool allocated;
+ int carrierHeaderSize;
+ Rnp::Endianness finalEndianness;
+
+ RnpHeader *rnpHeader;
+ RnpFragmentHeader *currFragment;
+ RnpParameter *currParameter;
+ };
+
+/** Class for decoding a RNP message. The buffer is always an external one
+ Decoding the messsage means also changing the endianness to the host endianness
+*/
+class RnpProtocolDecoder
+ {
+ public:
+ /// Default constructor
+ RnpProtocolDecoder() throw();
+
+ /** Takes the buffer and decodes it, provided it is a RNP message
+ Returns 'false' if it is not a RNP message, or the message is corrupt
+ (for now, if the endianness is not the one of the host, no integrity
+ verification is done. In this case endianness is changes, but if the
+ message is corrupt...bang!!). Later this will have to throw something
+ */
+ bool decode(akg::CommBuffer*) throw();
+
+ /// Returns the code of the destination server
+ RnpQuark getDestinationServerType() const throw();
+
+ /// Returns the desired endianness
+ Rnp::Endianness getDesiredEndianness() const throw();
+
+ /// Returns the original endianness of the message
+ Rnp::Endianness getOriginalEndianness() const throw();
+
+ /// Returns the total message length
+ int getMessageLength() const throw();
+
+ /// Returns the version of the message
+ int getMessageVersion() const throw();
+
+ /// Returns the number of fragments contained in the message
+ RnpQuark countFragments() const throw();
+
+ /// Returns a pointer to the first fragment
+ const RnpFragmentHeader* getFirstFragment() const throw();
+
+ /// Returns a pointer to the next fragment
+ const RnpFragmentHeader* getNextFragment() const throw();
+
+ /// Returns the type of the current fragment
+ RnpQuark getFragmentType() const throw();
+
+ /// Returns the name of type of the current fragment
+ const char* getFragmentTypeName() const throw();
+
+ /// Returns the command of the current fragment
+ RnpQuark getCommand() const throw();
+
+ /// Returns the number of parameters of the current fragment
+ int countParameters() const throw();
+
+ /// Returns the length of the current fragment
+ RnpQuark getFragmentLength() const throw();
+
+ /// Returns a pointer to the first parameter of the current fragment
+ const RnpParameter* getFirstParameter() const throw();
+
+ /// Returns a pointer to the next parameter of the current fragment
+ const RnpParameter* getNextParameter() const throw();
+
+ /// Returns the logical type of the current parameter
+ RnpQuark getParameterType() const throw();
+
+ /// Returns the data type of the current parameter
+ RnpQuark getDataType() const throw();
+
+ /// Returns a pointer to the data of the current parameter, can't be NULL
+ const void* getData() const throw();
+
+ /// Returns a pointer to the data of the current parameter, as string-asciiz (assert!) (can be NULL)
+ const char* getDataAsString() const throw();
+
+ /// Returns a pointer to the data of the current parameter, as integer (assert!)
+ int getDataAsInteger() const throw();
+
+ /// Returns a pointer to the data of the current parameter, as float (assert!)
+ float getDataAsFloat() const throw();
+
+ /// Returns a pointer to the data of the current parameter, as double (assert!)
+ double getDataAsDouble() const throw();
+
+ /// Returns a pointer to the data of the current parameter, as const void* (assert!) (can be NULL)
+ const void* getDataAsOpaque() const throw();
+
+ /// Returns the length of the data of the current parameter
+ int getDataLength() const throw();
+
+ private:
+ akg::CommBuffer *commBuffer;
+ Rnp::Endianness originalEndianness;
+ mutable RnpHeader *rnpHeader;
+ mutable RnpFragmentHeader *currFragment;
+ mutable int currFragmentIdx;
+
+ mutable RnpParameter *currParameter;
+ mutable int currParameterIdx;
+
+ /// Helper function to print a RNP header
+ void printRnpHeader(RnpHeader*) const throw();
+
+ /// Tests the integrity of the message
+ bool testIntegrity() const throw();
+
+
+ /// Returns 'true' if the message is a RNP message
+ bool isRnpMessage() const throw();
+
+ /// Changes the endianness of the message to the message of the host
+ bool changeToHostEndianness() throw();
+ };
+
+
+} //namespace
+#endif
diff --git a/rnprotocol/rnpserver.cc b/rnprotocol/rnpserver.cc
new file mode 100644
index 0000000..cac982c
--- /dev/null
+++ b/rnprotocol/rnpserver.cc
@@ -0,0 +1,134 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ * - called from rasserver_main.cc
+ * - startRnpServer() is twin to startRpcServer and startHttpServer()
+ *
+ ************************************************************/
+
+#include <iostream>
+#include <signal.h>
+#include "rnpserver.hh"
+#include "srvrasmgrcomm.hh"
+#include "server/rasserver_config.hh"
+#include "rnpservercomm.hh"
+
+#include "raslib/rminit.hh"
+#include "debug-srv.hh"
+
+// only for access control
+#include "servercomm/servercomm.hh"
+
+#include "server/rasserver_entry.hh"
+
+RnpRasDaManComm rnpServerComm;
+RasserverCommunicator communicator(&rnpServerComm);
+
+extern "C"
+{
+void rnpSignalHandler(int sig);
+}
+
+void startRnpServer()
+{
+ ENTER( "startRnpServer" );
+
+ signal (SIGTERM, rnpSignalHandler);
+
+ RMInit::logOut << "Initializing control connections..." << flush;
+ rasmgrComm.init(configuration.getTimeout(), configuration.getServerName(), configuration.getRasmgrHost(), configuration.getRasmgrPort());
+
+ accessControl.setServerName(configuration.getServerName());
+
+ RMInit::logOut << "informing rasmgr: server available..." << flush;
+ rasmgrComm.informRasmgrServerAvailable();
+ RMInit::logOut << "ok" << endl;
+
+ //##################
+
+ RMInit::logOut << "Initializing job control..." << flush;
+ communicator.initJobs(1);
+ communicator.setTimeout(RNP_TIMEOUT_LISTEN,0); // the select loop!
+
+ communicator.setListenPort(configuration.getListenPort());
+
+ rnpServerComm.setServerJobs(1);
+ rnpServerComm.connectToCommunicator(communicator);
+ rnpServerComm.setTransmitterBufferSize(configuration.getMaxTransferBufferSize());
+
+ RMInit::logOut<<"setting timeout to "<<configuration.getTimeout()<< " secs..." << flush;
+
+ rnpServerComm.setTimeoutInterval(configuration.getTimeout());
+ NbJob::setTimeoutInterval(configuration.getTimeout());
+
+ RMInit::logOut << "connecting to base DBMS..." << flush;
+ RasServerEntry &rasserver = RasServerEntry::getInstance();
+ rasserver.compat_connectToDBMS();
+
+ RMInit::logOut<<"ok, waiting for clients."<<endl<<endl;
+ communicator.runServer();
+
+ RMInit::logOut<<"RNP server shutdown in progress..."<<flush;
+ rnpServerComm.disconnectFromCommunicator();
+
+ //##################
+
+ RMInit::logOut<<"informing rasmgr..."<<flush;
+ rasmgrComm.informRasmgrServerDown();
+
+ RMInit::logOut<<"server stopped."<<endl;
+ LEAVE( "startRnpServer" );
+}
+
+void stopRnpServer()
+{
+ ENTER( "stopRnpServer" );
+
+ communicator.shouldExit();
+
+ LEAVE( "stopRnpServer" );
+}
+
+
+void rnpSignalHandler(int sig)
+{
+ static int in_progress=0; // sema for signal-in-signal
+
+ if (in_progress) // routine already active?
+ return; // ...then don't interfere
+
+ in_progress = 1; // block further signals
+
+ for(long j=0;j<1000000;j++) // make sure server notices shutdown
+ ; // NB: why this large number? doesn't seem to be thought over carefully -- PB 2003-nov-23
+
+ stopRnpServer(); // send shutdown request
+}
+
+
diff --git a/rnprotocol/rnpserver.hh b/rnprotocol/rnpserver.hh
new file mode 100644
index 0000000..9d7162f
--- /dev/null
+++ b/rnprotocol/rnpserver.hh
@@ -0,0 +1,33 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#ifndef RNPSERVER_HH
+#define RNPSERVER_HH
+
+
+// This header contains only a function for starting the RNP server
+// It is done like this to keep the rest of the server as separate as possible from the rnp part
+
+void startRnpServer();
+
+
+#endif
diff --git a/rnprotocol/rnpservercomm.cc b/rnprotocol/rnpservercomm.cc
new file mode 100644
index 0000000..677cf4e
--- /dev/null
+++ b/rnprotocol/rnpservercomm.cc
@@ -0,0 +1,1344 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ * - CLIENTID: | 0|.counter.|....timestamp ......|
+ * |31,30.....24|23...16|15...8|7...0|
+ * - requests count from 1..n between connect and disconnect
+ * - fragments count from 1..n between ???
+ *
+ ************************************************************/
+
+#ifndef RMANVERSION
+#error "Please specify RMANVERSION variable!"
+#endif
+
+#ifndef COMPDATE
+#error "Please specify the COMPDATE variable!"
+/*
+COMPDATE=`date +"%d.%m.%Y %H:%M:%S"`
+
+and -DCOMPDATE="\"$(COMPDATE)\"" when compiling
+*/
+#endif
+
+#include "mymalloc/mymalloc.h"
+#include <time.h>
+#include "rnprasserver.hh"
+#include "rnpservercomm.hh"
+#include "srvrasmgrcomm.hh"
+
+#include "server/rasserver_entry.hh"
+#include "time/akgtime.hh"
+
+#include "debug-srv.hh"
+
+
+
+// aux function to avoid a compiler warning (see 'man strftime')
+size_t my_strftime(char *s, size_t max, const char *fmt, const struct tm *tm)
+{
+ return strftime(s, max, fmt, tm);
+}
+
+// now(): aux function returning, as a static string, the current time
+// keep in sync with same function in rasmgr/rasmgr_localsrv.cc!
+const char* now()
+{
+ size_t strfResult = 0; // return value of strftime()
+ static char timestring[50]; // must hold 20+1 chars
+
+ time_t t = time(NULL); // get time
+ struct tm* tm = localtime(&t); // break down time
+ strfResult = my_strftime( timestring, sizeof(timestring), "[%F %T]", tm ); // format time
+ if (strfResult == 0) // bad luck? then take fallback message
+ (void) strncpy( timestring, "[-no time available-]", sizeof(timestring) );
+ return( timestring );
+}
+
+const int RnpRasDaManComm::NoClient = -1;
+
+RnpRasDaManComm::RnpRasDaManComm() throw()
+{
+ ENTER( "RnpRasDaManComm::RnpRasDaManComm" );
+ requestCounter = 0;
+ fragmentCounter = 0;
+ clientID = NoClient;
+ LEAVE( "RnpRasDaManComm::RnpRasDaManComm" );
+}
+
+RnpRasDaManComm::~RnpRasDaManComm() throw()
+{
+ TALK( "RnpRasDaManComm::~RnpRasDaManComm" );
+}
+
+// we need our implementation because of r_Error, but we will go for the default when r_Error is AkgException
+void RnpRasDaManComm::processRequest(CommBuffer *receiverBuffer, CommBuffer *transmiterBuffer, RnpTransport::CarrierProtocol protocol, RnpServerJob *callingJob) throw()
+{
+ ENTER( "RnpRasDaManComm::processRequest, at " << now() << ", client=" << callingJob->getClientHostAddress().getStringAddress() );
+ RMInit::logOut << now() << " request from " << callingJob->getClientHostAddress().getStringAddress() << endl;
+
+ BenchmarkTimer bmt("request time");
+ bmt.start();
+
+ decoder.decode(receiverBuffer);
+ RnpQuark destServerType = decoder.getDestinationServerType();
+ Rnp::Endianness desEndianness = decoder.getDesiredEndianness();
+
+ // test if servertype matches!
+
+ transmiterBuffer->allocate(getTransmitterBufferSize());
+ transmiterBuffer->clearToWrite();
+
+ encoder.setBuffer(transmiterBuffer);
+ encoder.setFinalEndianness(desEndianness);
+ encoder.startAnswer(destServerType, protocol);
+
+ requestCounter++;
+
+ decoder.getFirstFragment();
+ bool wasError = false;
+ for(int fragment=0; fragment < decoder.countFragments(); fragment++)
+ {
+ if(wasError == false)
+ {
+ try
+ {
+ decodeFragment();
+ }
+ // DBMS connection lost? then need to disconnect client to allow to resync
+ catch(r_Ebase_dbms &edb)
+ {
+ RMInit::logOut << "Error: base DBMS reports: " << edb.what() << endl;
+ wasError = true;
+ answerr_Error(edb);
+#if 0 // seems too hard -- PB 2005-jul-25
+ try
+ {
+ RMInit::logOut << "detaching client..." ;
+ executeDisconnect();
+ RMInit::logOut << "ok" << endl;
+ }
+ catch (...) // ignore any further error, just log it
+ {
+ RMInit::logOut << "failed" << endl;
+ }
+#endif // 0
+ }
+ catch(r_Error &ex)
+ {
+ RMInit::logOut << "Error: request terminated: " << ex.what() << endl;
+ TALK( "rasdaman exception kind=" << ex.get_kind() << ", errorno=" << ex.get_errorno() );
+ wasError = true;
+ answerr_Error(ex);
+
+#if 0 // seems too hard -- PB 2005-jul-25
+ // a base DBMS error we treat just like above
+ // -- PB 2003-nov-24
+ if (ex.get_kind() == r_Error::r_Error_BaseDBMSFailed
+ || ex.get_errorno() == 206) // serializable error, see errtxts
+ {
+ try
+ {
+ RMInit::logOut << "detaching client...";
+ executeDisconnect();
+ RMInit::logOut << "ok" << endl;
+ }
+ catch (...) // ignore any further error, just log it
+ {
+ RMInit::logOut << "failed" << endl;
+ }
+ }
+#endif // 0
+ }
+ catch(exception &ex)
+ {
+ RMInit::logOut << "Error: request terminated with general exception: " << ex.what() << endl;
+ wasError = true;
+ answerSTLException(ex);
+ }
+ catch(...)
+ {
+ RMInit::logOut << "Error: request terminated with generic exception." << endl;
+ wasError = true;
+ answerUnknownError();
+ }
+ }
+ else
+ {
+ discardFragment();
+ }
+ decoder.getNextFragment();
+ }
+ encoder.endMessage();
+
+ bmt.stop();
+
+ RMInit::logOut << now() << " request completed; " << bmt << endl << endl;
+ LEAVE( "RnpRasDaManComm::processRequest" );
+}
+
+RnpServerJob* RnpRasDaManComm::createJobs(int howMany)
+{
+ TALK( "RNP: creating "<<howMany<<" RnpRasserverJob's" );
+ return new RnpRasserverJob[howMany];
+}
+
+void RnpRasDaManComm::setTimeoutInterval(int seconds)
+{
+ clientTimer.setTimeoutInterval(seconds);
+}
+
+void RnpRasDaManComm::checkForTimeout()
+{
+ ENTER( "RnpRasDaManComm::checkForTimeout" );
+ if(clientID != NoClient)
+ {
+ if(clientTimer.checkForTimeout())
+ {
+ TALK( "Client 0x" << hex << clientID << dec << " has timed out." );
+ RMInit::logOut << "Client has timed out, connection being freed." << endl;
+ disconnectClient();
+ }
+ }
+ else
+ rasmgrComm.informRasmgrServerStillAvailable();
+ LEAVE( "RnpRasDaManComm::checkForTimeout" );
+}
+
+
+void RnpRasDaManComm::decodeFragment() throw( r_Error )
+{
+ ENTER( "RnpRasDaManComm::decodeFragment" );
+
+ try // somewhere during cmd execution there can be exceptions; we pass them thru
+ {
+ fragmentCounter++;
+
+ RnpQuark command = decoder.getCommand();
+
+ RnpRasserver *hook = new RnpRasserver;
+ TALK( "fragmentCounter=" << fragmentCounter << ", command is " << hook->getCommandName( command ) );
+
+ // first parameter has to be the clientID
+ verifyClientID( command );
+
+ switch(command)
+ {
+ case RnpRasserver::cmd_connect: executeConnect(); break;
+ case RnpRasserver::cmd_disconnect: executeDisconnect(); break;
+ case RnpRasserver::cmd_opendb: executeOpenDB(); break;
+ case RnpRasserver::cmd_closedb: executeCloseDB(); break;
+ case RnpRasserver::cmd_beginta: executeBeginTA(); break;
+ case RnpRasserver::cmd_committa: executeCommitTA(); break;
+ case RnpRasserver::cmd_abortta: executeAbortTA(); break;
+ case RnpRasserver::cmd_istaopen: executeIsTAOpen(); break;
+ case RnpRasserver::cmd_queryhttp: executeQueryHttp(); break;
+ case RnpRasserver::cmd_getnewoid: executeGetNewOId(); break;
+ case RnpRasserver::cmd_queryrpc: executeQueryRpc(); break;
+ case RnpRasserver::cmd_getnextelem: executeGetNextElement(); break;
+ case RnpRasserver::cmd_endtransfer: executeEndTransfer(); break;
+ case RnpRasserver::cmd_getnextmdd: executeGetNextMDD(); break;
+ case RnpRasserver::cmd_getnexttile: executeGetNextTile(); break;
+ case RnpRasserver::cmd_updaterpc : executeUpdateQuery(); break;
+ case RnpRasserver::cmd_startinsTmdd: executeStartInsertTransMDD(); break;
+ case RnpRasserver::cmd_inserttile : executeInsertTile(); break;
+ case RnpRasserver::cmd_endinsmdd : executeEndInsertMDD(); break;
+ case RnpRasserver::cmd_initupdate : executeInitUpdate(); break;
+ case RnpRasserver::cmd_gettypestruct: executeGetTypeStructure(); break;
+ case RnpRasserver::cmd_startinsPmdd: executeStartInsertPersMDD(); break;
+ case RnpRasserver::cmd_insertmdd: executeInsertMDD(); break;
+ case RnpRasserver::cmd_insertcoll: executeInsertCollection(); break;
+ case RnpRasserver::cmd_remobjfromcoll: executeRemoveObjFromColl(); break;
+ case RnpRasserver::cmd_delobjbyoid: executeDeleteObjByOId(); break;
+ case RnpRasserver::cmd_delcollbyname: executeDeleteCollByName(); break;
+ case RnpRasserver::cmd_getcoll: executeGetCollection(); break;
+ case RnpRasserver::cmd_getcolloids: executeGetCollectionOIds(); break;
+ case RnpRasserver::cmd_getobjecttype: executeGetObjectType(); break;
+ case RnpRasserver::cmd_setformat: executeSetFormat(); break;
+ // --- until here the compatible ones ---
+
+ // -- the secret, unofficial ones --
+ case RnpRasserver::cmd_createcollection: executeCreateCollection(); break;
+ case RnpRasserver::cmd_createmdd: executeCreateMDD(); break;
+ case RnpRasserver::cmd_extendmdd: executeExtendMDD(); break;
+ case RnpRasserver::cmd_gettiledomains: executeGetTileDomains(); break;
+
+ default:
+ RMInit::logOut << "Protocol error: Unknown command: " << command << endl;
+ LEAVE( "RnpRasDaManComm::decodeFragment: Unknown command: "<<command );
+ throw r_Error(822);
+ break;
+ }
+
+ clientTimer.markAction();
+ }
+ catch (r_Error &e) // any rasdaman error is passed through
+ {
+ LEAVE( "RnpRasDaManComm::decodeFragment, rasdaman exception caught: " << e.what() );
+ throw; // pass on
+ }
+
+ catch (...) // any other error is "unexpected", by def
+ {
+ LEAVE( "RnpRasDaManComm::decodeFragment, general exception caught." );
+ throw( r_Error( 10000 ) ); // unexpected internal error - FIXME: can we be more precise?
+ }
+
+ LEAVE( "RnpRasDaManComm::decodeFragment" );
+}
+
+//######## here the executing functions ################
+void RnpRasDaManComm::executeConnect()
+{
+ ENTER( "RnpRasDaManComm::executeConnect" );
+
+ RasServerEntry& rasserver = RasServerEntry::getInstance();
+
+ decoder.getNextParameter();
+ const char *capability = decoder.getDataAsString();
+
+ TALK("capability: "<<capability);
+
+ // a new connect requires to drop any eventually preexisting connection first -- PB 2005-sep-02
+ // if (clientID != NoClient) // any previous un-disconnected activity?
+ if (fragmentCounter > 1 || requestCounter > 1) // any previous un-disconnected activity?
+ {
+ RMInit::logOut << "Preparing request for new connect by resetting old connection; ";
+ RnpRasDaManComm::disconnectInternally();
+ // FIXME: the entry in CltTable still remains (see compat_*())
+ // - although this doesn't harm in any way it should be removed
+ }
+
+ rasserver.compat_connectNewClient(capability);
+ connectClient();
+
+ encoder.startFragment(Rnp::fgt_OkAnswer, decoder.getCommand());
+ encoder.addInt32Parameter(RnpRasserver::pmt_clientid, clientID);
+ encoder.endFragment();
+ TALK( "adding clientID 0x" << hex << clientID << dec );
+
+ LEAVE( "RnpRasDaManComm::executeConnect, assigned clientID=0x"<<hex<<clientID<<dec);
+}
+
+void RnpRasDaManComm::executeDisconnect()
+{
+ ENTER("RnpRasDaManComm::executeDisconnect, clientID=0x"<<hex<<clientID<<dec);
+ RasServerEntry& rasserver = RasServerEntry::getInstance();
+
+ rasserver.compat_disconnectClient();
+ TALK( "rasserver.compat_disconnectClient() done, now disconnectClient()." );
+ disconnectClient();
+
+ encoder.startFragment(Rnp::fgt_OkAnswer, decoder.getCommand());
+ encoder.endFragment();
+
+ LEAVE("RnpRasDaManComm::executeDisconnect");
+}
+
+void RnpRasDaManComm::executeOpenDB()
+{
+ ENTER("RnpRasDaManComm::executeOpenDB");
+
+ RasServerEntry& rasserver = RasServerEntry::getInstance();
+
+ decoder.getNextParameter();
+ const char* databaseName = decoder.getDataAsString();
+
+ TALK( "Execute open DB, database="<< databaseName );
+
+ rasserver.compat_openDB(databaseName);
+
+ encoder.startFragment(Rnp::fgt_OkAnswer, decoder.getCommand());
+ encoder.endFragment();
+
+ LEAVE("RnpRasDaManComm::executeOpenDB");
+}
+
+void RnpRasDaManComm::executeCloseDB()
+{
+ ENTER("RnpRasDaManComm::executeCloseDB");
+
+ RasServerEntry& rasserver = RasServerEntry::getInstance();
+
+ rasserver.compat_closeDB();
+
+ encoder.startFragment(Rnp::fgt_OkAnswer, decoder.getCommand());
+ encoder.endFragment();
+
+ LEAVE("RnpRasDaManComm::executeCloseDB");
+}
+
+void RnpRasDaManComm::executeBeginTA()
+{
+ ENTER( "RnpRasDaManComm::executeBeginTA" );
+
+ RasServerEntry& rasserver = RasServerEntry::getInstance();
+
+ decoder.getNextParameter();
+ bool rw = decoder.getDataAsInteger() ? true:false;
+
+ TALK( "executeBeginTA transaction: "<<(rw ? "rw":"ro") );
+
+ rasserver.compat_beginTA(rw);
+
+ encoder.startFragment(Rnp::fgt_OkAnswer, decoder.getCommand());
+ encoder.endFragment();
+
+ LEAVE( "RnpRasDaManComm::executeBeginTA" );
+}
+
+void RnpRasDaManComm::executeCommitTA()
+{
+ ENTER("executeCommitTA - in");
+ RasServerEntry& rasserver = RasServerEntry::getInstance();
+
+ rasserver.compat_commitTA();
+
+ encoder.startFragment(Rnp::fgt_OkAnswer, decoder.getCommand());
+ encoder.endFragment();
+ LEAVE("executeCommitTA - out");
+}
+
+void RnpRasDaManComm::executeAbortTA()
+ {
+ ENTER("executeAbortTA - in");
+ RasServerEntry& rasserver = RasServerEntry::getInstance();
+
+ rasserver.compat_abortTA();
+
+ encoder.startFragment(Rnp::fgt_OkAnswer, decoder.getCommand());
+ encoder.endFragment();
+ LEAVE("executeAbortTA - out");
+ }
+
+void RnpRasDaManComm::executeIsTAOpen()
+ {
+ ENTER("executeIsTAOpen - in");
+ RasServerEntry& rasserver = RasServerEntry::getInstance();
+
+ bool isOpen = rasserver.compat_isOpenTA();
+
+ encoder.startFragment(Rnp::fgt_OkAnswer, decoder.getCommand());
+ encoder.addInt32Parameter(RnpRasserver::pmt_transstatus, isOpen);
+ encoder.endFragment();
+ LEAVE("executeIsTAOpen - out; isOpen=" << isOpen);
+ }
+
+void RnpRasDaManComm::executeQueryHttp()
+{
+ ENTER("executeQueryHttp - in");
+
+ RasServerEntry& rasserver = RasServerEntry::getInstance();
+ // TALK("have inst" );
+ decoder.getNextParameter();
+
+ const void* httpParams = decoder.getData();
+ int httpParamsLen = decoder.getDataLength();
+ // TALK( "httpParamsLen=" << httpParamsLen );
+ char *resultBuffer = 0;
+ int resultLen = rasserver.compat_executeQueryHttp((const char*)httpParams, httpParamsLen, resultBuffer);
+ // TALK( "resultLen=" << resultLen );
+
+ encoder.startFragment(Rnp::fgt_OkAnswer, decoder.getCommand());
+
+ if(resultLen && resultBuffer)
+ {
+ encoder.adjustBufferSize(resultLen);
+ encoder.addOpaqueParameter(RnpRasserver::pmt_httpqanswer, resultBuffer, resultLen);
+ delete[] resultBuffer;
+ resultBuffer = 0;
+ }
+ encoder.endFragment();
+
+ LEAVE("executeQueryHttp - out; resultLen=" << resultLen );
+}
+
+void RnpRasDaManComm::executeGetNewOId()
+ {
+ ENTER("executeGetNewOId - in");
+ RasServerEntry& rasserver = RasServerEntry::getInstance();
+
+ decoder.getNextParameter();
+
+ int objType = decoder.getDataAsInteger();
+
+ r_OId oid = rasserver.compat_getNewOId( (unsigned short)objType );
+ const char* cOId = oid.get_string_representation();
+
+ TALK("executeGetNewOId objType = "<<objType<<" oid="<<cOId);
+
+ encoder.startFragment(Rnp::fgt_OkAnswer, decoder.getCommand());
+ encoder.addStringParameter(RnpRasserver::pmt_oidstring, cOId);
+ encoder.endFragment();
+
+ LEAVE("executeGetNewOId - out");
+ }
+
+#define INITPTR(a) a = 0
+#define SECUREPTR(a) if(a == 0) a = strdup("")
+#define FREEPTR(a) free(a)
+
+void RnpRasDaManComm::executeQueryRpc()
+ {
+ ENTER("executeQueryRpc() - in");
+
+ RasServerEntry& rasserver = RasServerEntry::getInstance();
+
+ decoder.getNextParameter();
+
+ const char *query = decoder.getDataAsString();
+ TALK("query="<<query);
+
+ ExecuteQueryRes queryResult;
+ INITPTR(queryResult.token);
+ INITPTR(queryResult.typeName);
+ INITPTR(queryResult.typeStructure);
+
+ int status = rasserver.compat_executeQueryRpc(query, queryResult);
+ SECUREPTR(queryResult.token);
+ SECUREPTR(queryResult.typeName);
+ SECUREPTR(queryResult.typeStructure);
+
+ encoder.startFragment(Rnp::fgt_OkAnswer, decoder.getCommand());
+ encoder.addInt32Parameter( RnpRasserver::pmt_returnstatus,status);
+ TALK( "adding return status " << status );
+ encoder.addInt32Parameter( RnpRasserver::pmt_errorno, queryResult.errorNo);
+ encoder.addInt32Parameter( RnpRasserver::pmt_lineno, queryResult.lineNo);
+ encoder.addInt32Parameter( RnpRasserver::pmt_columnno, queryResult.columnNo);
+ encoder.addStringParameter(RnpRasserver::pmt_errortoken,queryResult.token);
+ encoder.addStringParameter(RnpRasserver::pmt_typename, queryResult.typeName);
+ encoder.addStringParameter(RnpRasserver::pmt_typestructure,queryResult.typeStructure);
+ encoder.endFragment();
+
+ FREEPTR(queryResult.token);
+ FREEPTR(queryResult.typeName);
+ FREEPTR(queryResult.typeStructure);
+
+ LEAVE("executeQueryRpc - out");
+ }
+
+void RnpRasDaManComm::executeGetNextElement()
+ {
+ ENTER("executeGetNextElement - in");
+ RasServerEntry& rasserver = RasServerEntry::getInstance();
+
+ char *buffer = NULL;
+ unsigned int bufferSize;
+
+ int status = rasserver.compat_getNextElement(buffer,bufferSize);
+
+ encoder.startFragment(Rnp::fgt_OkAnswer, decoder.getCommand());
+ encoder.addInt32Parameter(RnpRasserver::pmt_returnstatus,status);
+ TALK( "adding return status " << status );
+ if(buffer != NULL)
+ encoder.addOpaqueParameter(RnpRasserver::pmt_skalarobject, buffer, bufferSize);
+
+ encoder.endFragment();
+
+ free(buffer);
+
+ LEAVE("executeGetNextElement - out");
+ }
+
+void RnpRasDaManComm::executeEndTransfer()
+ {
+ ENTER("executeEndTransfer - in");
+ RasServerEntry& rasserver = RasServerEntry::getInstance();
+
+ int status = rasserver.compat_endTransfer();
+
+ encoder.startFragment(Rnp::fgt_OkAnswer, decoder.getCommand());
+ encoder.addInt32Parameter(RnpRasserver::pmt_returnstatus,status);
+ TALK( "adding return status " << status );
+ encoder.endFragment();
+
+ LEAVE("executeEndTransfer - out");
+ }
+
+
+void RnpRasDaManComm::executeGetNextMDD()
+ {
+ ENTER("executeGetNextMDD - in");
+ RasServerEntry& rasserver = RasServerEntry::getInstance();
+
+
+ r_Minterval mddDomain;
+ char* typeName;
+ char* typeStructure;
+ r_OId oid;
+ unsigned short currentFormat;
+
+
+ int status = rasserver.compat_getNextMDD(mddDomain, typeName, typeStructure, oid, currentFormat);
+
+ encoder.startFragment(Rnp::fgt_OkAnswer, decoder.getCommand());
+ encoder.addInt32Parameter(RnpRasserver::pmt_returnstatus,status);
+ TALK( "adding return status " << status );
+ encoder.addStringParameter(RnpRasserver::pmt_oidstring, mddDomain.get_string_representation());
+ encoder.addStringParameter(RnpRasserver::pmt_typename, typeName);
+ encoder.addStringParameter(RnpRasserver::pmt_typestructure, typeStructure);
+ encoder.addStringParameter(RnpRasserver::pmt_oidstring, oid.get_string_representation() ? oid.get_string_representation() : "");
+ encoder.addInt32Parameter(RnpRasserver::pmt_currentformat, currentFormat);
+ encoder.endFragment();
+
+ free(typeName);
+ free(typeStructure);
+
+ LEAVE("executeGetNextMDD - out");
+ }
+
+void RnpRasDaManComm::executeGetNextTile()
+ {
+ ENTER("executeGetNextTile - in");
+ RasServerEntry& rasserver = RasServerEntry::getInstance();
+
+ RPCMarray *tempRpcMarray;
+
+ int status = rasserver.compat_getNextTile(&tempRpcMarray);
+
+ encoder.startFragment(Rnp::fgt_OkAnswer, decoder.getCommand());
+ encoder.addInt32Parameter(RnpRasserver::pmt_returnstatus,status);
+ TALK( "adding return status " << status );
+
+ if(tempRpcMarray != 0)
+ {
+ encoder.addStringParameter(RnpRasserver::pmt_domain, tempRpcMarray->domain);
+ encoder.addInt32Parameter( RnpRasserver::pmt_typelength, tempRpcMarray->cellTypeLength);
+ encoder.addInt32Parameter( RnpRasserver::pmt_currentformat, tempRpcMarray->currentFormat);
+ encoder.addInt32Parameter( RnpRasserver::pmt_storageformat, tempRpcMarray->storageFormat);
+
+ encoder.adjustBufferSize(tempRpcMarray->data.confarray_len);
+ encoder.addOpaqueParameter(RnpRasserver::pmt_tiledata, tempRpcMarray->data.confarray_val, tempRpcMarray->data.confarray_len);
+
+ // Do not free this! "tempRpcMarray->data.confarray_val";
+ free(tempRpcMarray->domain);
+ free(tempRpcMarray);
+
+ }
+ encoder.endFragment();
+
+ /* Notez aici ca n-am unde: e adevarat ca tilele trebuie transferate si pe bucati, fiindca
+ un tiff mare creat cu select e o tila!
+ */
+
+
+ LEAVE("executeGetNextTile - out");
+ }
+
+//----------
+
+void RnpRasDaManComm::executeUpdateQuery()
+ {
+ ENTER("executeUpdateQuery - in");
+ RasServerEntry& rasserver = RasServerEntry::getInstance();
+
+ decoder.getNextParameter(); const char* query = decoder.getDataAsString();
+
+ ExecuteUpdateRes returnStructure;
+ returnStructure.token = NULL;
+
+ int status = rasserver.compat_ExecuteUpdateQuery(query, returnStructure);
+
+ const char *token = returnStructure.token != NULL ? returnStructure.token : "";
+
+ encoder.startFragment(Rnp::fgt_OkAnswer, decoder.getCommand());
+ encoder.addInt32Parameter( RnpRasserver::pmt_returnstatus, status);
+ TALK( "adding return status " << status );
+ encoder.addInt32Parameter( RnpRasserver::pmt_errorno, returnStructure.errorNo);
+ encoder.addInt32Parameter( RnpRasserver::pmt_lineno, returnStructure.lineNo);
+ encoder.addInt32Parameter( RnpRasserver::pmt_columnno, returnStructure.columnNo);
+ encoder.addStringParameter(RnpRasserver::pmt_errortoken, token );
+ encoder.endFragment();
+
+ if(returnStructure.token) free(returnStructure.token);
+
+ LEAVE("executeUpdateQuery - out");
+ }
+
+void RnpRasDaManComm::executeInitUpdate()
+ {
+ ENTER("executeInitUpdate - in");
+
+ RasServerEntry& rasserver = RasServerEntry::getInstance();
+
+ int status = rasserver.compat_InitUpdate();
+
+ encoder.startFragment(Rnp::fgt_OkAnswer, decoder.getCommand());
+ encoder.addInt32Parameter(RnpRasserver::pmt_returnstatus, status);
+ TALK( "adding return status " << status );
+ encoder.endFragment();
+ LEAVE("executeInitUpdate - out");
+ }
+
+void RnpRasDaManComm::executeStartInsertTransMDD()
+ {
+ ENTER("executeStartInsertTransMDD - in");
+
+ RasServerEntry& rasserver = RasServerEntry::getInstance();
+
+ decoder.getNextParameter(); const char* domain = decoder.getDataAsString();
+ decoder.getNextParameter(); int typeLength = decoder.getDataAsInteger();
+ decoder.getNextParameter(); const char* typeName = decoder.getDataAsString();
+
+ int status = rasserver.compat_StartInsertTransMDD(domain, typeLength, typeName);
+
+ encoder.startFragment(Rnp::fgt_OkAnswer, decoder.getCommand());
+ encoder.addInt32Parameter(RnpRasserver::pmt_returnstatus, status);
+ TALK( "adding return status " << status );
+ encoder.endFragment();
+
+ LEAVE("executeStartInsertTransMDD - out");
+ }
+
+void RnpRasDaManComm::executeInsertTile()
+ {
+ ENTER("executeInsertTile - in");
+
+ RasServerEntry& rasserver = RasServerEntry::getInstance();
+
+ RPCMarray *rpcMarray = new RPCMarray;
+
+ decoder.getNextParameter(); int persistent = decoder.getDataAsInteger();
+ decoder.getNextParameter(); rpcMarray->domain = (char*)decoder.getDataAsString();
+ decoder.getNextParameter(); rpcMarray->cellTypeLength = decoder.getDataAsInteger();
+ decoder.getNextParameter(); rpcMarray->currentFormat = decoder.getDataAsInteger();
+ decoder.getNextParameter(); rpcMarray->storageFormat = decoder.getDataAsInteger();
+
+ decoder.getNextParameter();
+ const void* buffer = decoder.getData();
+ int length = decoder.getDataLength();
+
+ rpcMarray->data.confarray_val = (char*)mymalloc(length); memcpy(rpcMarray->data.confarray_val, buffer, length);
+ rpcMarray->data.confarray_len = length;
+
+ int status = rasserver.compat_InsertTile(persistent, rpcMarray);
+
+ encoder.startFragment(Rnp::fgt_OkAnswer, decoder.getCommand());
+ encoder.addInt32Parameter(RnpRasserver::pmt_returnstatus, status);
+ TALK( "adding return status " << status );
+ encoder.endFragment();
+
+ // rpcMarray->data.confarray_val is freed by Tile::Tile(...), which is stupid, but...
+ delete rpcMarray;
+
+ LEAVE("executeInsertTile - out");
+ }
+
+void RnpRasDaManComm::executeEndInsertMDD()
+ {
+ ENTER("executeEndInsertMDD - in");
+
+ RasServerEntry& rasserver = RasServerEntry::getInstance();
+
+ decoder.getNextParameter(); int persistent = decoder.getDataAsInteger();
+
+ int status = rasserver.compat_EndInsertMDD(persistent);
+
+ encoder.startFragment(Rnp::fgt_OkAnswer, decoder.getCommand());
+ encoder.addInt32Parameter(RnpRasserver::pmt_returnstatus, status);
+ TALK( "adding return status " << status );
+ encoder.endFragment();
+
+ LEAVE("executeEndInsertMDD - out");
+ }
+
+void RnpRasDaManComm::executeGetTypeStructure()
+ {
+ ENTER("executeGetTypeStructure - in");
+
+ RasServerEntry& rasserver = RasServerEntry::getInstance();
+
+ decoder.getNextParameter(); const char *typeName = decoder.getDataAsString();
+ decoder.getNextParameter(); int typeType = decoder.getDataAsInteger();
+
+ char *typeStructure=NULL;
+
+ int status = rasserver.compat_GetTypeStructure(typeName, typeType, typeStructure);
+
+ encoder.startFragment(Rnp::fgt_OkAnswer, decoder.getCommand());
+ encoder.addInt32Parameter(RnpRasserver::pmt_returnstatus, status);
+ TALK( "adding return status " << status );
+ encoder.addStringParameter(RnpRasserver::pmt_typestructure, typeStructure ? typeStructure : "");
+ encoder.endFragment();
+
+ if(typeStructure)
+ {
+ free(typeStructure);
+ }
+ LEAVE("executeGetTypeStructure - out");
+ }
+
+void RnpRasDaManComm::executeStartInsertPersMDD()
+ {
+ ENTER("executeStartInsertPersMDD - in");
+ RasServerEntry& rasserver = RasServerEntry::getInstance();
+
+ decoder.getNextParameter(); const char* collName = decoder.getDataAsString();
+ decoder.getNextParameter(); r_Minterval mddDomain( decoder.getDataAsString() );
+ decoder.getNextParameter(); int typeLength = decoder.getDataAsInteger();
+ decoder.getNextParameter(); const char* typeName = decoder.getDataAsString();
+ decoder.getNextParameter(); r_OId oid( decoder.getDataAsString() );
+
+ int status = rasserver.compat_StartInsertPersMDD(collName, mddDomain, typeLength, typeName, oid);
+
+ encoder.startFragment(Rnp::fgt_OkAnswer, decoder.getCommand());
+ encoder.addInt32Parameter(RnpRasserver::pmt_returnstatus, status);
+ TALK( "adding return status " << status );
+ encoder.endFragment();
+ LEAVE("executeStartInsertPersMDD - out");
+ }
+
+void RnpRasDaManComm::executeInsertMDD()
+ {
+ ENTER("executeInsertMDD - in");
+
+ RasServerEntry& rasserver = RasServerEntry::getInstance();
+
+ decoder.getNextParameter(); const char* collName = decoder.getDataAsString();
+ decoder.getNextParameter(); const char* typeName = decoder.getDataAsString();
+ decoder.getNextParameter(); r_OId oid( decoder.getDataAsString() );
+
+ RPCMarray *rpcMarray = new RPCMarray;
+
+ decoder.getNextParameter(); rpcMarray->domain = (char*)decoder.getDataAsString();
+ decoder.getNextParameter(); rpcMarray->cellTypeLength = decoder.getDataAsInteger();
+ decoder.getNextParameter(); rpcMarray->currentFormat = decoder.getDataAsInteger();
+ decoder.getNextParameter(); rpcMarray->storageFormat = decoder.getDataAsInteger();
+
+ decoder.getNextParameter();
+ const void* buffer = decoder.getData();
+ int length = decoder.getDataLength();
+
+ rpcMarray->data.confarray_val = (char*)mymalloc(length); memcpy(rpcMarray->data.confarray_val, buffer, length);
+ rpcMarray->data.confarray_len = length;
+
+ int status = rasserver.compat_InsertMDD(collName, rpcMarray, typeName, oid);
+
+ encoder.startFragment(Rnp::fgt_OkAnswer, decoder.getCommand());
+ encoder.addInt32Parameter(RnpRasserver::pmt_returnstatus, status);
+ TALK( "adding return status " << status );
+ encoder.endFragment();
+
+ LEAVE("executeInsertMDD - out");
+ }
+
+void RnpRasDaManComm::executeInsertCollection()
+ {
+ ENTER("executeInsertCollection - in");
+ RasServerEntry& rasserver = RasServerEntry::getInstance();
+
+ decoder.getNextParameter(); const char* collName = decoder.getDataAsString();
+ decoder.getNextParameter(); const char* typeName = decoder.getDataAsString();
+ decoder.getNextParameter(); r_OId oid( decoder.getDataAsString() );
+
+ int status = rasserver.compat_InsertCollection(collName, typeName, oid);
+
+ encoder.startFragment(Rnp::fgt_OkAnswer, decoder.getCommand());
+ encoder.addInt32Parameter(RnpRasserver::pmt_returnstatus, status);
+ TALK( "adding return status " << status );
+ encoder.endFragment();
+
+ LEAVE("executeInsertCollection - out");
+ }
+
+void RnpRasDaManComm::executeDeleteCollByName()
+ {
+ ENTER("executeDeleteCollByName - in");
+ RasServerEntry& rasserver = RasServerEntry::getInstance();
+
+ decoder.getNextParameter(); const char* collName = decoder.getDataAsString();
+
+ int status = rasserver.compat_DeleteCollByName(collName);
+
+ encoder.startFragment(Rnp::fgt_OkAnswer, decoder.getCommand());
+ encoder.addInt32Parameter(RnpRasserver::pmt_returnstatus, status);
+ TALK( "adding return status " << status );
+ encoder.endFragment();
+
+ LEAVE("executeDeleteCollByName - out");
+ }
+
+void RnpRasDaManComm::executeDeleteObjByOId()
+ {
+ ENTER("executeDeleteObjByOId - in");
+ RasServerEntry& rasserver = RasServerEntry::getInstance();
+
+ decoder.getNextParameter(); r_OId oid( decoder.getDataAsString() );
+
+ int status = rasserver.compat_DeleteObjByOId(oid);
+
+ encoder.startFragment(Rnp::fgt_OkAnswer, decoder.getCommand());
+ encoder.addInt32Parameter(RnpRasserver::pmt_returnstatus, status);
+ TALK( "adding return status " << status );
+ encoder.endFragment();
+
+ LEAVE("executeDeleteObjByOId - out");
+ }
+
+void RnpRasDaManComm::executeRemoveObjFromColl()
+ {
+ ENTER("executeRemoveObjFromColl - in");
+ RasServerEntry& rasserver = RasServerEntry::getInstance();
+
+ decoder.getNextParameter(); const char* collName = decoder.getDataAsString();
+ decoder.getNextParameter(); r_OId oid( decoder.getDataAsString() );
+
+ int status = rasserver.compat_RemoveObjFromColl(collName, oid);
+
+ encoder.startFragment(Rnp::fgt_OkAnswer, decoder.getCommand());
+ encoder.addInt32Parameter(RnpRasserver::pmt_returnstatus, status);
+ TALK( "adding return status " << status );
+ encoder.endFragment();
+
+ LEAVE("executeRemoveObjFromColl - out");
+ }
+
+void RnpRasDaManComm::executeGetCollection()
+ {
+ ENTER("executeGetCollection - in");
+ RasServerEntry& rasserver = RasServerEntry::getInstance();
+
+ char* typeName = NULL;
+ char* typeStructure = NULL;
+ char* collName = NULL;
+ r_OId oid;
+ int status = 0;
+
+ decoder.getNextParameter();
+ if(decoder.getParameterType() == RnpRasserver::pmt_collname)
+ {
+ collName = strdup(decoder.getDataAsString());
+ status = rasserver.compat_GetCollectionByName(collName, typeName, typeStructure, oid);
+ }
+ else
+ {
+ const char* oidstring = decoder.getDataAsString();
+ oid = r_OId(oidstring);
+ status = rasserver.compat_GetCollectionByName(oid, typeName, typeStructure, collName);
+ }
+
+ encoder.startFragment(Rnp::fgt_OkAnswer, decoder.getCommand());
+ encoder.addInt32Parameter(RnpRasserver::pmt_returnstatus, status);
+ TALK( "adding return status " << status );
+ encoder.addStringParameter(RnpRasserver::pmt_typename, typeName);
+ encoder.addStringParameter(RnpRasserver::pmt_typestructure, typeStructure);
+ encoder.addStringParameter(RnpRasserver::pmt_oidstring, oid.get_string_representation());
+ encoder.addStringParameter(RnpRasserver::pmt_collname, collName);
+ encoder.endFragment();
+
+ free((void*)typeName);
+ free((void*)typeStructure);
+ free((void*)collName);
+
+ LEAVE("executeGetCollection - out");
+ }
+
+void RnpRasDaManComm::executeGetCollectionOIds()
+ {
+ ENTER("executeGetCollectionOIds - in");
+ RasServerEntry& rasserver = RasServerEntry::getInstance();
+
+ char* typeName = NULL;
+ char* typeStructure = NULL;
+ char* collName = NULL;
+ r_OId oid;
+ RPCOIdEntry* oidTable = NULL;
+ unsigned int oidTableSize = 0;
+ int status = 0;
+
+ decoder.getNextParameter();
+ if(decoder.getParameterType() == RnpRasserver::pmt_collname)
+ {
+ collName = strdup(decoder.getDataAsString());
+ status = rasserver.compat_GetCollectionOidsByName(collName, typeName, typeStructure, oid, oidTable, oidTableSize);
+ }
+ else
+ { oid = r_OId(decoder.getDataAsString());
+ status = rasserver.compat_GetCollectionOidsByOId(oid, typeName, typeStructure, oidTable, oidTableSize, collName);
+ }
+ encoder.startFragment(Rnp::fgt_OkAnswer, decoder.getCommand());
+ encoder.addInt32Parameter(RnpRasserver::pmt_returnstatus, status);
+ TALK( "adding return status " << status );
+ encoder.addStringParameter(RnpRasserver::pmt_typename, typeName);
+ encoder.addStringParameter(RnpRasserver::pmt_typestructure, typeStructure);
+ encoder.addStringParameter(RnpRasserver::pmt_oidstring, oid.get_string_representation());
+ encoder.addStringParameter(RnpRasserver::pmt_collname, collName);
+
+ if(oidTable)
+ for(int i=0;i<oidTableSize; i++)
+ {
+ encoder.adjustBufferSize(strlen(oidTable[i].oid));
+ encoder.addStringParameter(RnpRasserver::pmt_oidstring, oidTable[i].oid);
+ free(oidTable[i].oid);
+ }
+ encoder.endFragment();
+
+ free((void*)typeName);
+ free((void*)typeStructure);
+ free((void*)collName);
+ free(oidTable);
+
+ LEAVE("executeGetCollectionOIds - out");
+ }
+
+void RnpRasDaManComm::executeGetObjectType()
+ {
+ ENTER("executeGetObjectType - in");
+ RasServerEntry& rasserver = RasServerEntry::getInstance();
+
+ decoder.getNextParameter(); const char* oidstring = decoder.getDataAsString();
+
+ r_OId oid(oidstring);
+ unsigned short objType;
+
+ int status=rasserver.compat_GetObjectType(oid, objType);
+
+ encoder.startFragment(Rnp::fgt_OkAnswer, decoder.getCommand());
+ encoder.addInt32Parameter(RnpRasserver::pmt_returnstatus, status);
+ TALK( "adding return status " << status );
+ encoder.addInt32Parameter(RnpRasserver::pmt_objecttype, objType);
+ encoder.endFragment();
+
+
+ LEAVE("executeGetObjectType - out");
+ }
+
+void RnpRasDaManComm::executeSetFormat()
+ {
+ ENTER("executeSetFormat - in");
+ RasServerEntry& rasserver = RasServerEntry::getInstance();
+
+ decoder.getNextParameter(); int whichFormat = decoder.getDataAsInteger();
+ decoder.getNextParameter(); int format = decoder.getDataAsInteger();
+ decoder.getNextParameter(); const char* params = decoder.getDataAsString();
+
+ int status = 0;
+
+ if(whichFormat == 1)
+ status = rasserver.compat_SetTransferFormat(format, params);
+ else
+ status = rasserver.compat_SetStorageFormat(format, params);
+
+ encoder.startFragment(Rnp::fgt_OkAnswer, decoder.getCommand());
+ encoder.addInt32Parameter(RnpRasserver::pmt_returnstatus, status);
+ TALK( "adding return status " << status );
+ encoder.endFragment();
+
+ LEAVE("executeSetFormat - out");
+ }
+
+//########### until here the compatible ones ###############
+
+void RnpRasDaManComm::executeCreateCollection()
+ {
+ ENTER("executeCreateCollection - in");
+ RasServerEntry& rasserver = RasServerEntry::getInstance();
+
+ const char* collName = getNextAsString(RnpRasserver::pmt_collname);
+ const char* collTypeName = getNextAsString(RnpRasserver::pmt_typename);
+
+ TALK("rasserver.createCollection( " << collName << ", " << collTypeName << " )" );
+ r_OId roid = rasserver.createCollection(collName, collTypeName);
+
+ encoder.startFragment(Rnp::fgt_OkAnswer, decoder.getCommand());
+ encoder.addStringParameter(RnpRasserver::pmt_oidstring, roid.get_string_representation());
+ encoder.endFragment();
+
+ LEAVE("executeCreateCollection - out");
+ }
+
+void RnpRasDaManComm::executeCreateMDD()
+{
+ ENTER( "RnpRasDaManComm::executeCreateMDD" );
+ RasServerEntry& rasserver = RasServerEntry::getInstance();
+
+ const char *collName = getNextAsString(RnpRasserver::pmt_collname);
+ const char *mddTypeName = getNextAsString(RnpRasserver::pmt_typename);
+ const char *definitionDomain = getNextAsString(RnpRasserver::pmt_domain);
+ bool rcindex = false;
+ const char *tileDomain = 0;
+
+ if(decoder.getNextParameter())
+ {
+ rcindex = decoder.getDataAsInteger() ? true : false;
+ tileDomain = getNextAsString(RnpRasserver::pmt_domain);
+ }
+ TALK( "collName=" << collName << ", mddTypeName=" << mddTypeName << ", definitionDomain=" << definitionDomain << ", tileDomain=" << tileDomain << ", rcindex=" << rcindex );
+ r_OId roid = rasserver.createMDD(collName, mddTypeName, definitionDomain, tileDomain, rcindex);
+
+ encoder.startFragment(Rnp::fgt_OkAnswer, decoder.getCommand());
+ encoder.addStringParameter(RnpRasserver::pmt_oidstring, roid.get_string_representation());
+ encoder.endFragment();
+
+ LEAVE( "RnpRasDaManComm::executeCreateMDD, oid=" << roid.get_string_representation() );
+}
+
+void RnpRasDaManComm::executeExtendMDD()
+{
+ ENTER( "RnpRasDaManComm::executeExtendMDD" );
+
+ RasServerEntry& rasserver = RasServerEntry::getInstance();
+
+ const char *oidstring = getNextAsString(RnpRasserver::pmt_oidstring);
+ const char *stripeDomain = getNextAsString(RnpRasserver::pmt_domain);
+ const char *tileDomain = getNextAsString(RnpRasserver::pmt_domain);
+
+ r_OId mddOId = r_OId(oidstring);
+
+ TALK( "mddOId=" << oidstring << ", stripeDomain=" << stripeDomain << ", tileDomain=" << tileDomain );
+ rasserver.extendMDD(mddOId, stripeDomain, tileDomain);
+
+ encoder.startFragment(Rnp::fgt_OkAnswer, decoder.getCommand());
+ encoder.endFragment();
+
+ LEAVE( "RnpRasDaManComm::executeExtendMDD" );
+}
+
+void RnpRasDaManComm::executeGetTileDomains()
+{
+ ENTER( "RnpRasDaManComm::executeGetTileDomains" );
+
+ RasServerEntry& rasserver = RasServerEntry::getInstance();
+
+ const char *oidstring = getNextAsString(RnpRasserver::pmt_oidstring);
+ const char *stripeDomain = getNextAsString(RnpRasserver::pmt_domain);
+
+ r_OId mddOId = r_OId(oidstring);
+
+ vector<r_Minterval> result = rasserver.getTileDomains(mddOId, stripeDomain);
+
+ encoder.startFragment(Rnp::fgt_OkAnswer, decoder.getCommand());
+
+ for(int i=0;i < result.size(); i++)
+ {
+ const char *domain = result[i].get_string_representation();
+ encoder.addStringParameter(RnpRasserver::pmt_domain, domain);
+
+ free((void*)domain);
+ }
+
+ encoder.endFragment();
+
+ LEAVE( "RnpRasDaManComm::executeGetTileDomains" );
+}
+
+//######### helper functions ###########################
+
+void RnpRasDaManComm::connectClient()
+ {
+ clientID = makeNewClientID();
+ TALK( "RnpRasDaManComm::connectClient(): assigned new client id 0x" << hex << clientID << dec );
+ }
+
+void RnpRasDaManComm::disconnectInternally()
+{
+ clientID = NoClient;
+ requestCounter = 1; // because pre-increment before request processing will not be reached when this is called
+ fragmentCounter = 1; // same phenomenon, different reason: verify needs this counter for OK'ing connect
+}
+
+void RnpRasDaManComm::disconnectClient()
+ {
+ clientID = NoClient;
+ requestCounter = 0;
+ fragmentCounter = 0;
+ rasmgrComm.informRasmgrServerAvailable();
+ }
+
+
+void RnpRasDaManComm::verifyClientID( RnpQuark command ) throw (r_Error)
+ {
+ ENTER( "RnpRasDaManComm::verifyClientID( command=" << command << " ), fragmentCounter=" << fragmentCounter << ", requestCounter=" << requestCounter );
+
+ decoder.getFirstParameter();
+
+ if(decoder.getParameterType() != RnpRasserver::pmt_clientid)
+ {
+ RMInit::logOut << "Error: unidentified client." << endl;
+ LEAVE( "RnpRasDaManComm::verifyClientID() - exception, unknown client id." );
+ throw r_Error(820); // sorry, I know, symbolic constants
+ }
+
+ int verClientID = decoder.getDataAsInteger();
+ TALK( "RnpRasDaManComm::verifyClientID: clientID 0x" << hex << clientID << dec << ", verClientID 0x" << hex << verClientID << dec );
+
+ // it's our client, it's OK
+ if(clientID == verClientID)
+ {
+ LEAVE( "RnpRasDaManComm::verifyClientID() - it's our client, it's OK" );
+ return;
+ }
+
+ // connect cmd is OK too
+ if(command == RnpRasserver::cmd_connect)
+ {
+ LEAVE( "RnpRasDaManComm::verifyClientID() - connect requested, OK" );
+ return;
+ }
+
+ // new client, first request, it's probably connect, so OK
+ if(clientID == NoClient && fragmentCounter == 1)
+ {
+ LEAVE( "RnpRasDaManComm::verifyClientID() - new client, first request, it's probably connect, so OK" );
+ return;
+ }
+
+ // new client, same message, a new request, it's also OK (he is allowed to put more fragments in a request!)
+ if(clientID != NoClient && fragmentCounter > 1 && requestCounter == 1 && verClientID == 0)
+ {
+ LEAVE( "RnpRasDaManComm::verifyClientID() - new client, same message, a new request (multi-fragment), so OK" );
+ return;
+ }
+
+ RMInit::logOut << "Error: unregistered client." << endl;
+ LEAVE("RnpRasDaManComm::verifyClientID(): stored clientID is 0x" << hex << clientID << dec << ", but client identified as 0x" << hex << verClientID << dec << ", fragmentCounter=" << fragmentCounter << ", requestCounter=" << requestCounter);
+ throw r_Error(821); // invalid sequence number
+ }
+
+int RnpRasDaManComm::makeNewClientID()
+ {
+
+ // CLIENTID: | 0|.counter.|....timestamp ......|
+ // |31,30.....24|23...16|15...8|7...0|
+ static int counter = 0;
+
+ int timeNow = time(NULL);
+
+ int result = (timeNow & 0xFFFFFF) + (counter << 24);
+
+ counter = (counter+1) & 0x7F;
+
+ TALK( "RnpRasDaManComm::makeNewClientID() -> 0x" << hex << result << " (counter now: " << counter << ")" );
+ return result;
+ }
+
+void RnpRasDaManComm::answerr_Error(r_Error &err)
+{
+ const char *errText = err.serialiseError();
+
+ RMInit::logOut << "Error in response: (" << errText << ") " << err.what() << endl;
+
+ encoder.startFragment(Rnp::fgt_Error, decoder.getCommand());
+ encoder.addInt32Parameter(Rnp::ert_Other, 0);
+ encoder.addStringParameter(RnpRasserver::pmt_rErrorString, errText);
+
+ // add descriptive text -- PB 2003-nov-24
+ encoder.addStringParameter(RnpRasserver::pmt_rErrorString, err.what() );
+
+ encoder.endFragment();
+
+ delete[] errText;
+}
+
+//######################################################
+RnpRasserverJob::RnpRasserverJob() throw()
+ {
+ TALK( "RNP: RnpRasserverJob created" );
+ }
+
+bool RnpRasserverJob::validateMessage() throw()
+ {
+ TALK( "RNP: validateMessage()" );
+ return RnpServerJob::validateMessage();
+ }
+
+void RnpRasserverJob::executeOnAccept() throw()
+ {
+ TALK( "RNP: executeOnAccept()" );
+ RnpServerJob::executeOnAccept();
+ }
+
+void RnpRasserverJob::executeOnWriteReady() throw()
+ {
+ TALK( "RNP: executeOnWriteReady()" );
+ RnpServerJob::executeOnWriteReady();
+ }
+
+void RnpRasserverJob::specificCleanUpOnTimeout() throw()
+ {
+ TALK( "RNP: specificCleanUpOnTimeout()" );
+ RnpServerJob::specificCleanUpOnTimeout();
+ }
+
+void RnpRasserverJob::executeOnReadError() throw()
+ {
+ RMInit::logOut << "Error while executing read operation." << endl;
+ RnpServerJob::executeOnReadError();
+ }
+
+void RnpRasserverJob::executeOnWriteError() throw()
+ {
+ RMInit::logOut << "Error while executing write operation." << endl;
+ RnpServerJob::executeOnWriteError();
+ }
+
+//#########################################################
+RasserverCommunicator::RasserverCommunicator(RnpRasDaManComm* cmm) throw()
+ {
+ commPtr = cmm;
+ }
+
+bool RasserverCommunicator::executeOnTimeout() throw()
+ {
+ TALK( "RasserverCommunicator::executeOnTimeout()" );
+
+ commPtr->checkForTimeout();
+
+ return true;
+ }
+
+//#########################################################
+ClientTimer::ClientTimer()
+ {
+ interval = 0;
+ lastAction = 0;
+ enabled = false;
+ }
+
+void ClientTimer::setTimeoutInterval(int seconds)
+ {
+ interval = seconds;
+ enabled = true;
+ markAction();
+ }
+
+void ClientTimer::markAction()
+ {
+ lastAction = time(NULL);
+ }
+
+bool ClientTimer::checkForTimeout()
+ {
+ if(enabled == false) return false;
+
+ time_t now = time(NULL);
+
+ return now >= lastAction + interval;
+ }
+
diff --git a/rnprotocol/rnpservercomm.hh b/rnprotocol/rnpservercomm.hh
new file mode 100644
index 0000000..9a173f4
--- /dev/null
+++ b/rnprotocol/rnpservercomm.hh
@@ -0,0 +1,157 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#ifndef RNPSERVERCOMM_HH
+#define RNPSERVERCOMM_HH
+
+//#include <rnprotocol.hh>
+//#include <rnpembedded.hh>
+#include "rnpcommunication.hh"
+#include "raslib/error.hh"
+
+using namespace rnp;
+
+class ClientTimer
+ {
+ public:
+ ClientTimer();
+ void setTimeoutInterval(int seconds);
+ void markAction();
+ bool checkForTimeout();
+ private:
+ time_t interval;
+ time_t lastAction;
+ bool enabled;
+ };
+
+class RnpRasserverJob : public RnpServerJob
+ {
+ public:
+ RnpRasserverJob() throw();
+
+ private:
+ bool validateMessage() throw();
+ void executeOnAccept() throw();
+ void executeOnWriteReady() throw();
+ void specificCleanUpOnTimeout() throw();
+ void executeOnReadError() throw();
+ void executeOnWriteError() throw();
+ };
+
+class RnpRasDaManComm : public RnpBaseServerComm
+ {
+ public:
+ RnpRasDaManComm() throw();
+
+ ~RnpRasDaManComm() throw();
+
+ void processRequest(CommBuffer *receiverBuffer, CommBuffer *transmiterBuffer, RnpTransport::CarrierProtocol, RnpServerJob *callingJob) throw();
+
+ void setTimeoutInterval(int seconds);
+ void checkForTimeout();
+
+ private: // inherited from RnpBaseServerComm
+ RnpServerJob* createJobs(int howMany);
+
+ void decodeFragment() throw( r_Error );
+
+ ClientTimer clientTimer;
+ private: // the execution functions:
+ void executeConnect();
+ void executeDisconnect();
+ void executeOpenDB();
+ void executeCloseDB();
+ void executeBeginTA();
+ void executeCommitTA();
+ void executeAbortTA();
+ void executeIsTAOpen();
+ void executeQueryHttp();
+ void executeGetNewOId();
+ void executeQueryRpc();
+ void executeGetNextElement();
+ void executeEndTransfer();
+ void executeGetNextMDD();
+ void executeGetNextTile();
+
+ void executeUpdateQuery();
+ void executeStartInsertTransMDD();
+ void executeInsertTile();
+ void executeEndInsertMDD();
+ void executeInitUpdate();
+ void executeGetTypeStructure();
+ void executeStartInsertPersMDD();
+ void executeInsertMDD();
+ void executeInsertCollection();
+ void executeRemoveObjFromColl();
+ void executeDeleteObjByOId();
+ void executeDeleteCollByName();
+ void executeGetCollection();
+ void executeGetCollectionOIds();
+ void executeGetObjectType();
+ void executeSetFormat();
+
+
+ void executeCreateCollection();
+ void executeCreateMDD();
+ void executeExtendMDD();
+ void executeGetTileDomains();
+
+ void answerr_Error(r_Error&);
+ private: // helper functions
+ void connectClient();
+ // reset connection, without reporting availability to rasmgr
+ void disconnectInternally();
+ // reset connection, with reporting availability to rasmgr
+ void disconnectClient();
+ void verifyClientID( RnpQuark command ) throw (r_Error);
+ int makeNewClientID();
+
+ int clientID; // un timestamp, de fapt!
+ int requestCounter; // numara pachetele trimise de un client
+ int fragmentCounter; // numara fragmentele trimise de un client
+
+ static const int NoClient;
+ };
+
+class RasserverCommunicator : public NbCommunicator
+ {
+ public:
+ RasserverCommunicator(RnpRasDaManComm*) throw();
+
+ protected:
+ bool executeOnTimeout() throw();
+
+ RnpRasDaManComm *commPtr;
+ };
+
+#endif // RNPSERVERCOMM_HH
+
diff --git a/rnprotocol/srvrasmgrcomm.cc b/rnprotocol/srvrasmgrcomm.cc
new file mode 100644
index 0000000..d977045
--- /dev/null
+++ b/rnprotocol/srvrasmgrcomm.cc
@@ -0,0 +1,213 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ * - why sometimes exit() and sometimes return on error?
+ * should be return or exception, always.
+ *
+ ************************************************************/
+
+#include "srvrasmgrcomm.hh"
+#include<stdio.h>
+#include<errno.h>
+#include<stdlib.h>
+#include<unistd.h>
+#include<sys/types.h>
+#include<sys/socket.h>
+#include<netinet/in.h>
+#include<netdb.h>
+#include<iostream>
+#include<string.h>
+#include "raslib/rminit.hh"
+
+
+#include "debug.hh"
+
+
+// exit code of the server when communication is impossible
+// PB: Why 10 ? Anyway, should not use exit in a server, how often did I tell you, Walter Schatz!!!
+const unsigned int EXIT_CODE = 10;
+
+// max number of retries to connect to rasmgr in informRasMgr()
+const unsigned int SRV_MAX_RETRY = 10000000;
+
+// how many retries are attempted before a message is issued informRasMgr()
+const unsigned int SRV_TALK_INTERVAL = 100000;
+
+
+SrvRasmgrComm rasmgrComm;
+
+SrvRasmgrComm::SrvRasmgrComm()
+{
+ timeout = 0;
+ serverName = 0;
+ rasmgrHost = 0;
+ rasmgrPort = -1;
+}
+
+// note: should make use of timeout as defined in cmd line,
+// but that's a major undertaking -- PB 2005-sep-02
+
+void SrvRasmgrComm::init(unsigned int timeOut, const char* instanceName, const char* nRasmgrHost, int nRasmgrPort)
+{
+ timeout = timeOut;
+ serverName = instanceName;
+ rasmgrHost = nRasmgrHost;
+ rasmgrPort = nRasmgrPort;
+}
+
+unsigned int SrvRasmgrComm::getTimeout()
+{
+ return timeout;
+}
+
+void SrvRasmgrComm::informRasmgrServerAvailable()
+{
+ informRasMGR(SERVER_AVAILABLE);
+}
+
+void SrvRasmgrComm::informRasmgrServerDown()
+{
+ informRasMGR(SERVER_DOWN);
+}
+
+void SrvRasmgrComm::informRasmgrServerStillAvailable()
+{
+ // too verbose, blows up log file
+ // RMInit::logOut << "informing rasmgr: server still available." << endl;
+ informRasMGR(SERVER_REGULARSIG);
+}
+
+void SrvRasmgrComm::informRasMGR(int what)
+{ //what: 0 - going down
+ // 1 - available
+ // 2 - regular signal
+
+// cout<<"servername ="<<serverName<<" rasmgrhost="<<rasmgrHost<<" port="<<rasmgrPort<<endl;
+
+// if(what == SERVER_AVAILABLE) accessControl.resetForNewClient();
+
+ struct protoent* getprotoptr = getprotobyname("tcp");
+
+ struct hostent *hostinfo = gethostbyname(rasmgrHost);
+ if(hostinfo==NULL)
+ {
+ RMInit::logOut << "Error: cannot locate rasmgr host '" << rasmgrHost << "': " << strerror(errno) << std::endl;
+ return;
+ }
+
+ sockaddr_in internetSocketAddress;
+ internetSocketAddress.sin_family = AF_INET;
+ internetSocketAddress.sin_port=htons(rasmgrPort);
+ internetSocketAddress.sin_addr=*(struct in_addr*)hostinfo->h_addr;
+
+ int sock;
+
+ bool ok=false;
+ long talkInterval=SRV_TALK_INTERVAL;
+ long maxRetry=SRV_MAX_RETRY;
+ long retry =0;
+ // creating socket
+ for(retry=0;retry<maxRetry;retry++)
+ {
+ sock=socket(PF_INET,SOCK_STREAM,getprotoptr->p_proto);
+ //std::cout<<"Socket="<<sock<<" protocol(tcp)="<<getprotoptr->p_proto<<std::endl;
+
+ if(sock<0)
+ {
+ if( (retry%talkInterval) == 0)
+ {
+ std::cerr<< "Error: server '" << serverName << " cannot open socket to rasmgr (" << retry << " attempts, still retrying): " << strerror(errno) << std::endl;
+ RMInit::logOut << "Error: server '" << serverName << " cannot open socket to rasmgr (" << retry << " attempts, still retrying): " << strerror(errno) << std::endl;
+ }
+ continue;
+ }
+
+ if(connect(sock,(struct sockaddr*)&internetSocketAddress,sizeof(internetSocketAddress)) < 0)
+ {
+ if( (retry%talkInterval) == 0)
+ {
+ std::cerr << "Error: server '" << serverName << " cannot connect to rasmgr (" << retry << " attempts, still retrying): " << strerror(errno) << std::endl;
+ RMInit::logOut << "Error: server '" << serverName << " cannot connect to rasmgr (" << retry << " attempts, still retrying): " << strerror(errno) << std::endl;
+ }
+ close(sock); //yes, some SO requieres this, like DEC from BLVA
+ continue;
+ }
+ ok = true;
+ break;
+ }
+
+ if( !ok )
+ {
+ std::cerr << "Error: unable to contact rasmgr, server '" << serverName << "' herewith giving up." <<std::endl;
+ RMInit::logOut << "Error: unable to contact rasmgr, server '" << serverName << "' herewith giving up." <<std::endl;
+ if(sock)
+ close(sock);
+ exit( EXIT_CODE );
+ }
+
+ // creating the HTTP message
+ char message[200];
+ sprintf(message,"%s%d\r\n\r\n%s %d %ld ","POST rasservernewstatus HTTP/1.1\r\nUserAgent: RasServer/1.0\r\nContent-length: ",strlen(serverName)+3,serverName,what,0);
+
+ // writing message;
+ if(writeWholeMessage(sock,message,strlen(message)+1)<0)
+ {
+ std::cerr << "Error: cannot send message to rasmgr: " << strerror(errno) << std::endl;
+ RMInit::logOut << "Error: cannot send message to rasmgr: " << strerror(errno) << std::endl;
+ close(sock);
+ exit( EXIT_CODE );
+ }
+ close(sock);
+}
+
+
+int SrvRasmgrComm::writeWholeMessage(int socket,char *destBuffer,int buffSize)
+{
+ // we write the whole message, including the ending '\0', which is already in
+ // the buffSize provided by the caller
+ int totalLength=0;
+ int writeNow;
+ while(1)
+ {
+ writeNow = write(socket,destBuffer+totalLength,buffSize-totalLength);
+ if(writeNow == -1)
+ {
+ if(errno == EINTR)
+ continue; // read was interrupted by signal (on bad SO's)
+ return -1; // another error
+ }
+ totalLength+=writeNow;
+
+ if( totalLength==buffSize )
+ break; // THE END
+ }
+
+ return totalLength;
+}
+
diff --git a/rnprotocol/srvrasmgrcomm.hh b/rnprotocol/srvrasmgrcomm.hh
new file mode 100644
index 0000000..0d15c4c
--- /dev/null
+++ b/rnprotocol/srvrasmgrcomm.hh
@@ -0,0 +1,67 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#ifndef SRVRASMGR_HH
+#define SRVRASMGR_HH
+
+#define SERVER_DOWN 0
+#define SERVER_AVAILABLE 1
+ // 2 is server crushed, but it's generated by rasmgr!
+ // regularly signal the rasmgr that we are available
+#define SERVER_REGULARSIG 3
+
+class SrvRasmgrComm
+ {
+ public:
+ SrvRasmgrComm();
+
+ void init(unsigned int timeOut, const char* instanceName, const char* rasmgrHost, int rasmgrPort);
+
+ void informRasmgrServerAvailable();
+ void informRasmgrServerDown();
+ void informRasmgrServerStillAvailable();
+
+ unsigned int getTimeout();
+
+ private:
+ void informRasMGR(int what);
+ int writeWholeMessage(int socket,char *destBuffer,int buffSize);
+
+ const char* serverName;
+ const char* rasmgrHost;
+ int rasmgrPort;
+ unsigned int timeout;
+ };
+
+extern SrvRasmgrComm rasmgrComm;
+
+#endif
diff --git a/server/Makefile.am b/server/Makefile.am
new file mode 100644
index 0000000..5a36db5
--- /dev/null
+++ b/server/Makefile.am
@@ -0,0 +1,58 @@
+# -*-Makefile-*-
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+#
+# MAKEFILE FOR:
+# rasdaman server binaries, raslic
+#
+# COMMENTS:
+# - For static link you have to do: setenv STATIC_LIBS=TRUE
+#
+##################################################################
+
+AM_CXXFLAGS=@BASEDBCXXFLAGS@
+AM_LDFLAGS=@BASEDBLDFLAGS@
+
+bin_PROGRAMS=rasserver
+rasserver_SOURCES=rasserver_main.cc rasserver_config.cc rasserver_entry.cc \
+ createinitmdd.cc rasserver_config.hh rasserver_entry.hh \
+ createinitmdd.hh template_inst.hh\
+ ../debug/debug-clt.hh ../debug/debug.hh ../debug/debug-srv.hh \
+ ../include/bool.h ../include/globals.hh ../include/rasdaman.hh \
+ ../include/stdexcept.h
+rasserver_LDADD=../rnprotocol/libservercomm.a ../servercomm/libservercomm.a ../qlparser/libqlparser.a ../conversion/libconversion.a \
+ ../raslib/libraslib.a ../storagemgr/libstoragemgr.a ../reladminif/libreladminif.a \
+ ../tilemgr/libtilemgr.a ../mddmgr/libmddmgr.a \
+ ../catalogmgr/libcatalogmgr.a ../relmddif/librelmddif.a ../relstorageif/librelstorageif.a \
+ ../relcatalogif/librelcatalogif.a ../indexmgr/libindexmgr.a ../relblobif/librelblobif.a \
+ ../relindexif/librelindexif.a ../httpserver/libhttpserver.a \
+ ../network/libnetwork.a ../commline/libcommline.a \
+ ../time/libtime.a ../compression/libcompression.a \
+ ../relcatalogif/librelcatalogif.a ../raslib/libraslib.a
+
+SUBDIRS = ../relblobif ../relindexif ../relmddif ../relcatalogif ../reladminif ../relstorageif \
+ ../indexmgr ../catalogmgr ../tilemgr ../storagemgr ../commline ../network \
+ ../raslib ../servercomm ../rnprotocol ../rasodmg ../qlparser ../conversion \
+ ../mddmgr ../httpserver ../mymalloc ../time
+
+$(RECURSIVE_CLEAN_TARGETS):
+ @$(MAKE) $(AM_MAKEFLAGS) `echo $@ | sed s/-recursive/-am/`
diff --git a/server/createinitmdd.cc b/server/createinitmdd.cc
new file mode 100644
index 0000000..13098af
--- /dev/null
+++ b/server/createinitmdd.cc
@@ -0,0 +1,397 @@
+#include "mymalloc/mymalloc.h"
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+using namespace std;
+
+#include "server/createinitmdd.hh"
+#include <iomanip>
+#include "reladminif/objectbroker.hh"
+#include "raslib/mitera.hh"
+
+// #undef DEBUG_HH
+// #include "debug.hh"
+#define ENTER(a) cout << "ENTER " << a << endl << flush;
+#define LEAVE(a) cout << "LEAVE " << a << endl << flush;
+
+//#include <akgtime.hh>
+
+
+
+FastCollectionCreator::FastCollectionCreator(const char *collName, const char *collTypeName)
+ {
+ ENTER( "FastCollectionCreator::FastCollectionCreator(" << collName << "," << collTypeName << ")" );
+ collectionName = collName;
+
+ collectionTypeName = collTypeName;
+ LEAVE( "FastCollectionCreator::FastCollectionCreator()" );
+ }
+
+r_OId FastCollectionCreator::createCollection()
+ {
+ ENTER( "FastCollectionCreator::createCollection()" );
+
+ verifyName(collectionName);
+
+ // allocate a new OId
+ EOId eOId; EOId::allocateEOId( eOId, OId::MDDCOLLOID );
+ r_OId oid = r_OId( eOId.getSystemName(), eOId.getBaseName(), eOId.getOId() );
+
+ CollectionType* collType = (CollectionType*)TypeFactory::mapSetType( collectionTypeName );
+
+ RMInit::logOut<<"Creating collection "<<collectionName<<" with type "<<collectionTypeName<<"...";
+ if( collType )
+ {
+ try
+ {
+ MDDColl* coll = MDDColl::createMDDCollection(collectionName, OId(oid.get_local_oid()), collType);
+ delete coll;
+ RMInit::logOut << "OK" << std::endl;
+ }
+ catch( r_Error& obj )
+ {
+ if (obj.get_kind() == r_Error::r_Error_NameNotUnique)
+ {
+ RMInit::logOut << "collection name exists already... FAILED" << std::endl;
+ }
+ else
+ {
+ RMInit::logOut << obj.get_errorno() << " " << obj.what() << std::endl;
+ }
+ throw;
+ }
+ }
+ else
+ {
+ RMInit::logOut << "collection type not found... FAILED" << std::endl;
+ throw r_Error(COLLTYPE_NULL);
+ }
+
+ ENTER( "FastCollectionCreator::createCollection()" );
+ return oid;
+ }
+
+void FastCollectionCreator::verifyName( const char* name ) throw(r_Error)
+ {
+ ENTER( "FastCollectionCreator::verifyName(" << (long) name << ")" );
+
+ if(!name)
+ {
+ RMInit::logOut << "FastCollectionCreator::verifyName() name is null!" << std::endl;
+ throw r_Error(INVALIDOBJECTNAME);
+ }
+
+ const char* cptr=name;
+
+ //check if the name contains only [a-zA-Z0-9_]
+ while(*cptr) {
+ if( ((*cptr >= 'a') && (*cptr <='z')) ||
+ ((*cptr >= 'A') && (*cptr <='Z')) ||
+ ((*cptr >= '0') && (*cptr <='9')) ||
+ (*cptr == '_') )
+ cptr++;
+ else
+ break;
+ }
+
+ if(*cptr) {
+ //invalid character in object name
+ RMInit::logOut << "FastCollectionCreator::verifyName(" << name << ") invalid name!" << std::endl;
+ throw r_Error(INVALIDOBJECTNAME);
+ }
+
+ LEAVE( "FastCollectionCreator::verifyName(" << name << ") -> ok" );
+ }
+
+
+//###################################################################################################
+
+FastMDDCreator::FastMDDCreator()
+ {
+ ENTER( "FastMDDCreator::FastMDDCreator()" );
+
+ comprData = 0;
+
+ storageFormat = r_TMC;
+ formatParams = NULL;
+
+ LEAVE( "FastMDDCreator::FastMDDCreator()" );
+ }
+
+FastMDDCreator::~FastMDDCreator()
+ {
+ ENTER( "FastMDDCreator::~FastMDDCreator()" );
+
+ if(comprData) free(comprData);
+
+ LEAVE( "FastMDDCreator::~FastMDDCreator()" );
+ }
+
+void FastMDDCreator::setCollectionName(const char* collName)
+ {
+ ENTER( "FastMDDCreator::setCollectionName(" << collName << ")" );
+
+ collectionName = collName;
+
+ LEAVE( "FastMDDCreator::setCollectionName()" );
+ }
+
+void FastMDDCreator::setMDDTypeName(const char* _mddTypeName)
+ {
+ ENTER( "FastMDDCreator::setMDDTypeName(" << _mddTypeName << ")" );
+
+ mddTypeName = _mddTypeName;
+
+ LEAVE( "FastMDDCreator::setMDDTypeName()" );
+ }
+
+void FastMDDCreator::verifyCompatibility(MDDColl* collection) throw (r_Error)
+ {
+ ENTER( "FastMDDCreator::verifyCompatibility(_)" );
+
+ if (collection->isPersistent())
+ {
+ //cout<<"OK, colection exists and is persistent"<<endl;
+ }
+ else
+ {
+ throw r_Error(SYSTEM_COLLECTION_NOT_WRITABLE);
+ }
+
+ char* collTypeStructure = collection->getCollectionType()->getTypeStructure();
+ //cout<<"collTypeStructure="<<collTypeStructure<<endl;
+
+ const MDDType* mddType = TypeFactory::mapMDDType( mddTypeName.c_str() );
+ if(mddType == NULL) throw r_Error(MDDTYPE_NULL);
+
+ char* mddTypeStructure = mddType->getTypeStructure();
+ //cout<<"mddTypeStructure="<<mddTypeStructure<<endl;
+
+
+ if(mddType->compatibleWithDomain( &definitionInterval ))
+ {
+ //cout<<"compatibil with domain: "<<definitionInterval<<endl;
+ }
+ else throw r_Error(r_Error::r_Error_CollectionElementTypeMismatch);
+ //cout<<"incompatibil with domain"<<endl;
+
+ if(collection->getCollectionType()->compatibleWith( mddType ))
+ {
+ //cout<<"compatibil with collection"<<endl;
+ }
+ else
+ throw r_Error(r_Error::r_Error_CollectionElementTypeMismatch);
+ //cout<<"incompatibil with collection"<<endl;
+
+ free( collTypeStructure );
+ free( mddTypeStructure );
+
+ LEAVE( "FastMDDCreator::verifyCompatibility()" );
+ }
+
+r_OId FastMDDCreator::createMDD(const char *domain)
+ {
+ ENTER( "FastMDDCreator::createMDD(" << domain << ")" );
+
+ definitionInterval = r_Minterval(domain);
+
+ MDDColl* collection = MDDColl::getMDDCollection( collectionName.c_str() );
+
+ verifyCompatibility(collection);
+
+ const MDDType* mddType = TypeFactory::mapMDDType( mddTypeName.c_str() );
+ MDDBaseType* mddBaseType = (MDDBaseType*)mddType;
+
+ //allocate oid-ul;
+ EOId eOId; EOId::allocateEOId( eOId, OId::MDDOID );
+
+ mddOId = r_OId( eOId.getSystemName(), eOId.getBaseName(), eOId.getOId() );
+
+ StorageLayout ms;
+ ms.setTileSize(StorageLayout::DefaultTileSize);
+ ms.setIndexType(StorageLayout::DefaultIndexType);
+ ms.setTilingScheme(StorageLayout::DefaultTilingScheme);
+ if (definitionInterval.dimension() == StorageLayout::DefaultTileConfiguration.dimension())
+ ms.setTileConfiguration(StorageLayout::DefaultTileConfiguration);
+
+ mymdd = new MDDObj(mddBaseType, definitionInterval, eOId.getOId(), ms);
+
+ cellSize = mymdd->getCellType()->getSize();
+
+ collection->insert( mymdd );
+
+ collection->releaseAll();
+
+ delete collection;
+
+ LEAVE( "FastMDDCreator::createMDD() -> " << mddOId );
+ return mddOId;
+ }
+
+r_OId FastMDDCreator::createRCxMDD(const char *domain, const char *tileDomain)
+ {
+ ENTER( "FastMDDCreator::createRCxMDD(" << domain << "," << tileDomain << ")" );
+
+ definitionInterval = r_Minterval(domain);
+ r_Minterval tileInterval = r_Minterval(tileDomain);
+
+ MDDColl* collection = MDDColl::getMDDCollection( collectionName.c_str() );
+
+ verifyCompatibility(collection);
+
+ const MDDType* mddType = TypeFactory::mapMDDType( mddTypeName.c_str() );
+ MDDBaseType* mddBaseType = (MDDBaseType*)mddType;
+
+ //allocate oid-ul;
+ EOId eOId; EOId::allocateEOId( eOId, OId::MDDOID );
+
+ mddOId = r_OId( eOId.getSystemName(), eOId.getBaseName(), eOId.getOId() );
+
+ StorageLayout ms;
+ ms.setTileSize(tileInterval.cell_count() * mddBaseType->getBaseType()->getSize());
+ ms.setDataFormat(r_ZLib);
+ ms.setIndexType(r_Reg_Computed_Index);
+ ms.setTilingScheme(r_RegularTiling);
+ ms.setTileConfiguration(tileInterval);
+ mymdd = new MDDObj(mddBaseType, definitionInterval, eOId.getOId(), ms);
+
+
+ cellSize = mymdd->getCellType()->getSize();
+
+ collection->insert( mymdd );
+
+ collection->releaseAll();
+
+ delete collection;
+
+ LEAVE( "FastMDDCreator::createRCxMDD() -> " << mddOId );
+ return mddOId;
+ }
+
+vector<r_Minterval> FastMDDCreator::getTileDomains(r_OId mddOId, const char *stripeDomain)
+ {
+ ENTER( "FastMDDCreator::getTileDomains(" << mddOId << "," << stripeDomain << ")" );
+
+ mymdd = new MDDObj( OId(mddOId.get_local_oid()) );
+
+ r_Minterval stripeInterval(stripeDomain);
+
+ vector< Tile* >* tiles = mymdd->intersect(stripeInterval);
+
+ vector<r_Minterval> result;
+
+ for(int i=0; i < tiles->size(); i++)
+ {
+ result.push_back( (*tiles)[i]->getDomain());
+ }
+ delete mymdd;
+
+ LEAVE( "FastMDDCreator::getTileDomains()" );
+ return result;
+ }
+
+void FastMDDCreator::addStripe(r_OId _mddOId, const char *stripeDomain, const char *tileDomain)
+ {
+ ENTER( "FastMDDCreator::addStripe(" << _mddOId << "," << stripeDomain << "," << tileDomain << ")" );
+
+ mddOId = _mddOId;
+
+ r_Minterval stripeInterval(stripeDomain);
+ r_Minterval tileInterval(tileDomain);
+
+
+ mymdd = new MDDObj( OId(mddOId.get_local_oid()) );
+ cellSize = mymdd->getCellType()->getSize();
+ const BaseType* baseType = mymdd->getMDDBaseType()->getBaseType();
+
+
+ r_MiterArea iter(&tileInterval, &stripeInterval);
+
+ while (!iter.isDone())
+ {//iterate through the partitions in the search domain
+ r_Minterval currentSlInterval = iter.nextArea();
+ //cout<<"inserting tile: "<< currentSlInterval<<endl;
+
+ createCompressedTileData(currentSlInterval, baseType);
+
+ Tile* tile = new Tile( currentSlInterval, baseType, comprData, true, comprDataSize, storageFormat);
+ tile->setParameters(formatParams);
+ tile->setPersistent(true);
+
+ mymdd->insertTile( tile );
+ }
+
+ delete mymdd;
+
+ LEAVE( "FastMDDCreator::addStripe()" );
+ }
+
+
+void FastMDDCreator::createCompressedTileData(r_Minterval& tileInterval, const BaseType* baseType)
+ {
+ ENTER( "FastMDDCreator::createCompressedTileData(" << tileInterval << "," << baseType << ")" );
+
+ static int lastSize = 0;
+ int uncompressedSize = tileInterval.cell_count() * cellSize;
+
+ if(comprData)
+ {
+ if(lastSize == uncompressedSize)
+ {
+ return;
+ }
+ else { free(comprData); comprData = 0; }
+ }
+
+
+ r_Data_Format comprMode = storageFormat; ;
+
+ char* dataPtr = (char*)mymalloc(uncompressedSize); memset(dataPtr,0,uncompressedSize);
+
+ r_Base_Type *compType = (r_Base_Type*)(r_Type::get_any_type(baseType->getTypeStructure()));
+
+ r_Tile_Compression *engine = r_Tile_Compression::create(comprMode, tileInterval, compType);
+
+ r_ULong newSize = uncompressedSize;
+ comprData = (char*)(engine->compress(dataPtr, newSize, formatParams));
+ comprDataSize = newSize;
+ delete engine;
+ //cout<<"Compression of "<<uncompressedSize<<" of zeroes resulted in "<<comprDataSize<<" bytes"<<endl;
+
+ free(dataPtr);
+ delete compType;
+
+ lastSize= uncompressedSize;
+
+ LEAVE( "FastMDDCreator::createCompressedTileData()" );
+ }
+
diff --git a/server/createinitmdd.hh b/server/createinitmdd.hh
new file mode 100644
index 0000000..5165c6f
--- /dev/null
+++ b/server/createinitmdd.hh
@@ -0,0 +1,105 @@
+#ifndef CREATE_INIT_MDD_HH
+#define CREATE_INIT_MDD_HH
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ * These are tools for fast, low level acces to MDD and Colelctions
+ * The main purpose is speeding up initialization and import operations
+ *
+ ************************************************************/
+
+
+#include "mddmgr/mddcoll.hh"
+#include "mddmgr/mddobj.hh"
+#include "mddmgr/mddcolliter.hh"
+#include "tilemgr/tile.hh"
+#include "catalogmgr/typefactory.hh"
+#include "relcatalogif/mddtype.hh"
+#include "relcatalogif/mdddomaintype.hh"
+#include "relcatalogif/settype.hh"
+#include "reladminif/eoid.hh"
+#include "raslib/basetype.hh"
+#include "compression/tilecompression.hh"
+#include "raslib/oid.hh"
+#include "servercomm/servercomm.hh"
+
+
+class FastCollectionCreator
+ {
+ public:
+ FastCollectionCreator(const char *collName, const char* collTypeName);
+
+ r_OId createCollection();
+
+ private:
+ // allow only [A-Z,a-z,_]
+ void verifyName( const char* name ) throw(r_Error);
+
+ const char *collectionName;
+ const char *collectionTypeName;
+
+ };
+
+
+class FastMDDCreator
+ {
+ public:
+ FastMDDCreator();
+ ~FastMDDCreator();
+
+ void setCollectionName(const char *collName);
+ void setMDDTypeName(const char* mddTypeName);
+
+ r_OId createMDD(const char *domain);
+ r_OId createRCxMDD(const char *domain, const char *tileDomain);
+
+ void addStripe(r_OId mddOId, const char *stripeDomain, const char *tileDomain);
+
+ vector<r_Minterval> getTileDomains(r_OId mddOId, const char *stripeDomain);
+ private:
+ void verifyCompatibility(MDDColl *collection) throw(r_Error);
+
+ void createCompressedTileData(r_Minterval&, const BaseType* baseType);
+
+ std::string collectionName;
+ std::string mddTypeName;
+
+ r_Minterval definitionInterval;
+
+ r_Data_Format storageFormat;
+ const char *formatParams;
+
+ r_OId mddOId;
+ int cellSize;
+
+ char *comprData;
+ int comprDataSize;
+
+ MDDObj *mymdd;
+ };
+
+#endif
diff --git a/server/rasserver_config.cc b/server/rasserver_config.cc
new file mode 100644
index 0000000..94c2963
--- /dev/null
+++ b/server/rasserver_config.cc
@@ -0,0 +1,297 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*
+ * 2003-nov-05 PB makeLogFileName: use constants, use /tmp if RMANHOME env var not defined
+ * 2005-sep-05 PB parseCommandLine(): exit -2 on help
+ * 2006-apr-21 PB added debug output
+ */
+
+using namespace std;
+
+#include <unistd.h>
+#include <netdb.h>
+#include <sys/stat.h>
+#include <iostream>
+#include <string>
+#include <sstream>
+
+#include "debug.hh" // ENTER, LEAVE, TALK
+#include "globals.hh" // DEFAULT_PORT, LOGDIR, ALT_LOGDIR, LOG_SUFFIX
+#include "rasserver_config.hh"
+
+#include "storagemgr/sstoragelayout.hh"
+#include "servercomm/httpserver.hh"
+
+Configuration configuration;
+
+Configuration::Configuration()
+ {
+ logToStdOut = true;
+ logFileName = 0;
+ }
+
+
+bool Configuration::parseCommandLine(int argc, char** argv)
+ {
+ CommandLineParser &cmlInter = CommandLineParser::getInstance();
+ initParameters();
+
+ try
+ {
+ myExecutable = argv[0];
+ cmlInter.processCommandLine(argc, argv);
+
+ if(cmlHelp->isPresent())
+ {
+ printHelp();
+ exit( -2 ); // Unix code for 'help' -- PB 2005-sep-18
+ }
+ checkParameters();
+ }
+
+ catch(CmlException &ex)
+ {
+ cout<<"Error: " << ex.what()<<endl;
+
+ if(!logToStdOut)
+ {
+ RMInit::logOut<<"Error: " << ex.what()<<endl;
+ }
+ return false;
+ }
+ return true;
+ }
+
+// just for shorter lines...
+#define NSN CommandLineParser::noShortName
+
+void Configuration::initParameters()
+ {
+ CommandLineParser &cmlInter = CommandLineParser::getInstance();
+
+ cmlHelp = &cmlInter.addFlagParameter('h', "help", "print this help");
+
+ //connection
+ cmlRsn = &cmlInter.addStringParameter(NSN, "rsn", "<srv-name> rasserver instance name");
+ cmlPort = &cmlInter.addStringParameter(NSN, "lport", "<nnnn> rasserver listen port (RPC or HTTP)");
+ cmlMgr = &cmlInter.addStringParameter(NSN, "mgr", "<mgr-host> name of RasMGR host", DEFAULT_HOSTNAME);
+ cmlMgrPort = &cmlInter.addLongParameter(NSN, "mgrport", "<nnnn> port of RasMGR", DEFAULT_PORT );
+ cmlMgrSync = &cmlInter.addStringParameter(NSN, "sync", NULL); // deprecated
+
+ cmlTransBuffer = &cmlInter.addLongParameter(NSN, "transbuffer", "<nnnn> maximal size of the transfer buffer in bytes", MAX_BUFFER_SIZE);
+ cmlTimeOut = &cmlInter.addLongParameter(NSN, "timeout", "<nnn> client time out in seconds.\n\t\tif it is set to 0 server doesn't check for client timeouts", CLIENT_TIMEOUT);
+ cmlMgmntInt = &cmlInter.addStringParameter(NSN, "mgmntint", NULL); // deprecated
+ cmlHttp = &cmlInter.addFlagParameter(NSN, "http", "start HTTP version of rasserver");
+ cmlRnp = &cmlInter.addFlagParameter(NSN, "rnp", "start RNP version of rasserver");
+
+ cmlOptLevel = &cmlInter.addLongParameter(NSN, "opt", "<nn> optimization level(0-4)\n\t\t 0 = no / 4 = maximal optimization", 4L);
+ cmlConnectStr = &cmlInter.addStringParameter(NSN, "connect", "<connect-str> connect string for underlying database(e.g. test/test@julep)", "/");
+ cmlLog = &cmlInter.addStringParameter('l', "log", "<log-file> log is printed to <log-file>\n\t\tif <log-file> is stdout , log output is printed to standard out", "$RMANHOME/log/<srv-name>.<pid>.log");
+
+#ifdef RMANDEBUG
+ cmlTileSize = &cmlInter.addLongParameter(NSN, "tilesize", "<nnnn> specifies maximal size of tiles in bytes\n\t\t-regular tiles with equal edge lengthes", 2097152);
+ cmlPctMin = &cmlInter.addLongParameter(NSN, "pctmin", "<nnnn> specifies minimal size of blobtiles in bytes", 2048);
+ cmlPctMax = &cmlInter.addLongParameter(NSN, "pctmax", "<nnnn> specifies maximal size of inlinetiles in bytes", 4096);
+ cmlUseTC = &cmlInter.addFlagParameter(NSN, "usetc", "use TileContainerIndex");
+ cmlTileConf = &cmlInter.addStringParameter(NSN, "tileconf", "<dom> default tile configuration (e.g. [0:1,0:2])", "[0:511,0:511]");
+
+ string tilingDesc = string("<tiling-name> retiling strategy, specified as:") + CommandLineParameter::descLineSep +
+ " " + tiling_name_notiling + "," + CommandLineParameter::descLineSep +
+ " " + tiling_name_regulartiling;
+ cmlTiling = &cmlInter.addStringParameter(NSN, "tiling", tilingDesc.c_str(), tiling_name_notiling);
+
+ string indexDesc = string("<index-name> index for created objects, specified as:") + CommandLineParameter::descLineSep +
+ " " + index_name_auto + "," + CommandLineParameter::descLineSep +
+ " " + index_name_directory + "," + CommandLineParameter::descLineSep +
+ " " + index_name_regdirectory + "," + CommandLineParameter::descLineSep +
+ " " + index_name_rplustree + "," + CommandLineParameter::descLineSep +
+ " " + index_name_regrplustree + "," + CommandLineParameter::descLineSep +
+ " " + index_name_tilecontainer + "," + CommandLineParameter::descLineSep +
+ " " + index_name_regcomputed;
+ cmlIndex = &cmlInter.addStringParameter(NSN, "index", indexDesc.c_str(), index_name_rplustree);
+
+ // for systemtest use e.g.3 together with tileSize 12
+ string indexsizeDesc = string("<nnnn> make the index use n nodes");
+ cmlIndexSize = &cmlInter.addLongParameter(NSN, "indexsize", indexsizeDesc.c_str(),0L);
+ cmlDbg = &cmlInter.addStringParameter('d', "debug", "<dgb-file> debug output is printed to <dbg-file>; if <dbg-file> is stdout, debug output is printed to standard out","<srv-name>.log");
+ cmlDbgLevel = &cmlInter.addLongParameter(NSN, "dl", "<nn> debug level (0-4; 0 = no / 4 = maximal debug information)", 0L);
+#endif // RMANDEBUG
+
+ }
+#undef NSN
+
+void Configuration::checkParameters()
+ {
+ ENTER( "Configuration::checkParameters()" );
+
+ serverName = cmlRsn->getValueAsString();
+
+ initLogFiles();
+
+ listenPort = cmlPort->getValueAsLong();
+
+ rasmgrHost = cmlMgr->getValueAsString();
+ rasmgrPort = cmlMgrPort->getValueAsLong();
+ TALK( "rasmgrHost = " << rasmgrHost << ", rasmgrPort = " << rasmgrPort );
+
+ deprecated(cmlMgrSync);
+
+ maxTransferBufferSize = cmlTransBuffer->getValueAsLong();
+ timeout = cmlTimeOut->getValueAsLong();
+ deprecated(cmlMgmntInt);
+ httpServ = cmlHttp->isPresent();
+ rnpServ = cmlRnp->isPresent();
+
+ optLevel = cmlOptLevel->getValueAsLong();
+ dbConnection = cmlConnectStr->getValueAsString();
+
+#ifdef RMANDEBUG
+ tileSize = cmlTileSize->getValueAsLong();
+ pctMin = cmlPctMin->getValueAsLong();
+ pctMax = cmlPctMax->getValueAsLong();
+ useTC = cmlUseTC->isPresent();
+
+
+ tileConf = cmlTileConf->getValueAsString();//(r_Minterval..)
+ tilingName = cmlTiling->getValueAsString();
+ indexType = cmlIndex->getValueAsString();
+ indexSize = cmlIndexSize->getValueAsLong();
+ deprecated(cmlDbg);
+ dbgLevel = cmlDbgLevel->getValueAsLong();
+#endif
+
+ LEAVE( "Configuration::checkParameters()" );
+ }
+
+void Configuration::printHelp()
+ {
+ CommandLineParser &cmlInter = CommandLineParser::getInstance();
+
+ cout << "Usage: rasserver [options]" << endl;
+ cout << "Options:" << endl;
+ cmlInter.printHelp();
+
+ cout << endl;
+
+ }
+
+void
+Configuration::initLogFiles()
+ {
+ if( cmlLog->isPresent())
+ {
+ if( strcasecmp(cmlLog->getValueAsString(), "stdout") != 0)
+ { logFileName = cmlLog->getValueAsString();
+ logToStdOut = false;
+ }
+ else
+ {
+ logFileName = "stdout";
+ logToStdOut = true;
+ }
+ }
+ else
+ { // default
+ logFileName = makeLogFileName( serverName, LOG_SUFFIX );
+ logToStdOut = false;
+ }
+
+ if( logToStdOut == true)
+ {
+ RMInit::logOut.rdbuf(cout.rdbuf());
+ RMInit::dbgOut.rdbuf(cout.rdbuf());
+ RMInit::bmOut.rdbuf(cout.rdbuf());
+ }
+ else
+ {
+ if (RMInit::logFileOut.is_open())
+ RMInit::logFileOut.close();
+ RMInit::logFileOut.open(logFileName, ios::out | ios::ate);
+ RMInit::logOut.rdbuf(RMInit::logFileOut.rdbuf());
+ RMInit::dbgOut.rdbuf(RMInit::logFileOut.rdbuf());
+ RMInit::bmOut.rdbuf(RMInit::logFileOut.rdbuf());
+ }
+ cout<<"This server's log file is: " << logFileName << endl;
+ }
+
+const char *
+Configuration::makeLogFileName(const char *srvName,const char *desExt)
+ {
+ static char buffer[ FILENAME_MAX ];
+ int pid =getpid();
+ char *dir = getenv( RMANHOME_VAR );
+ if (dir == NULL)
+ {
+ cout << "Error: environment variable " << RMANHOME_VAR << " not set. Using " << ALT_LOGDIR << " for the moment being." << endl;
+ strcpy( buffer, ALT_LOGDIR );
+ }
+ else
+ {
+ strcpy( buffer, dir );
+ strcat( buffer, LOGDIR );
+ }
+ mkdir(buffer,S_IRWXU + S_IRGRP+S_IXGRP + S_IROTH+S_IXOTH); // create if not exist, rwxr-xr-x
+ sprintf(buffer+strlen(buffer),"/%s.%06d.%s",srvName,pid,desExt);
+ return buffer;
+ }
+
+void
+Configuration::deprecated(CommandLineParameter *cml)
+ {
+ if(cml->isPresent())
+ {
+ cout<<"WARNING: parameter '"<<cml->calledName()<<"' is deprecated, will be removed in next version!"<<endl;
+ }
+ }
+
+const char* Configuration::getServerName() { return serverName; }
+int Configuration::getListenPort() { return listenPort; }
+bool Configuration::isHttpServer() { return httpServ; }
+bool Configuration::isRnpServer() { return rnpServ; }
+
+const char* Configuration::getRasmgrHost() { return rasmgrHost; }
+int Configuration::getRasmgrPort() { return rasmgrPort; }
+
+bool Configuration::isLogToStdOut() { return logToStdOut; }
+
+int Configuration::getDefaultOptimizationLevel() { return optLevel; }
+int Configuration::getMaxTransferBufferSize() { return maxTransferBufferSize; }
+int Configuration::getTimeout() { return timeout; }
+const char* Configuration::getDbConnectionID() { return dbConnection; }
+
+#ifdef RMANDEBUG
+int Configuration::getDefaultTileSize() { return tileSize; }
+int Configuration::getDefaultPCTMin() { return pctMin; }
+int Configuration::getDefaultPCTMax() { return pctMax; }
+
+int Configuration::getDefaultIndexSize(){ return indexSize; }
+
+int Configuration::getDebugLevel() { return dbgLevel; }
+
+const char* Configuration::getDefaultTileConfig() { return tileConf; }
+const char* Configuration::getTilingScheme() { return tilingName; }
+const char* Configuration::getIndexType() { return indexType; }
+bool Configuration::useTileContainer() { return useTC; }
+
+#endif
+
diff --git a/server/rasserver_config.hh b/server/rasserver_config.hh
new file mode 100644
index 0000000..dcb777d
--- /dev/null
+++ b/server/rasserver_config.hh
@@ -0,0 +1,138 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#ifndef RASSERVER_CONFIG_HH
+#define RASSERVER_CONFIG_HH
+
+
+#include "commline/cmlparser.hh"
+
+class Configuration
+ {
+ public:
+ Configuration();
+
+ bool parseCommandLine(int argc, char** argv);
+
+ const char* getServerName();
+ int getListenPort();
+ bool isHttpServer();
+ bool isRnpServer();
+
+ const char* getRasmgrHost();
+ int getRasmgrPort();
+ bool isLogToStdOut();
+
+ int getDefaultOptimizationLevel();
+ int getMaxTransferBufferSize();
+ int getTimeout();
+ const char* getDbConnectionID();
+
+#ifdef RMANDEBUG
+ int getDefaultTileSize();
+ int getDefaultPCTMin();
+ int getDefaultPCTMax();
+
+ int getDefaultIndexSize();
+
+ int getDebugLevel();
+
+ const char* getDefaultTileConfig();
+ const char* getTilingScheme();
+ const char* getIndexType();
+ bool useTileContainer();
+
+#endif
+ private:
+ void printHelp();
+
+ void initParameters();
+ void checkParameters();
+ void initLogFiles();
+ void deprecated(CommandLineParameter*);
+
+ const char* makeLogFileName(const char *srvName,const char *desExt);
+
+ // Parameters
+ CommandLineParameter *cmlHelp;
+ CommandLineParameter *cmlRsn;
+ CommandLineParameter *cmlPort;
+ CommandLineParameter *cmlMgr;
+ CommandLineParameter *cmlMgrPort;
+ CommandLineParameter *cmlMgrSync;
+
+ CommandLineParameter *cmlTransBuffer;
+ CommandLineParameter *cmlTimeOut;
+ CommandLineParameter *cmlMgmntInt;
+ CommandLineParameter *cmlHttp;
+ CommandLineParameter *cmlRnp;
+
+ CommandLineParameter *cmlOptLevel;
+ CommandLineParameter *cmlConnectStr;
+ CommandLineParameter *cmlLog;
+
+#ifdef RMANDEBUG
+ CommandLineParameter *cmlTileSize;
+ CommandLineParameter *cmlPctMin;
+ CommandLineParameter *cmlPctMax;
+ CommandLineParameter *cmlUseTC;
+ CommandLineParameter *cmlTileConf;
+ CommandLineParameter *cmlTiling;
+ CommandLineParameter *cmlIndex;
+ CommandLineParameter *cmlIndexSize;
+ CommandLineParameter *cmlDbg;
+ CommandLineParameter *cmlDbgLevel;
+#endif
+ const char* myExecutable;
+
+ const char* serverName;
+ int listenPort;
+
+ const char* rasmgrHost;
+ int rasmgrPort;
+
+ bool logToStdOut;
+ const char* logFileName; // == 0 if stdout
+
+ int maxTransferBufferSize;
+ int timeout;
+ bool httpServ;
+ bool rnpServ;
+ int optLevel;
+ const char* dbConnection;
+
+#ifdef RMANDEBUG
+ int tileSize;
+ int pctMin;
+ int pctMax;
+ bool useTC;
+ const char* tileConf;
+ const char* tilingName;
+ const char* indexType;
+ int indexSize;
+ int dbgLevel;
+#endif
+ };
+
+extern Configuration configuration;
+
+#endif
diff --git a/server/rasserver_entry.cc b/server/rasserver_entry.cc
new file mode 100644
index 0000000..2296ec8
--- /dev/null
+++ b/server/rasserver_entry.cc
@@ -0,0 +1,528 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+using namespace std;
+
+#include "mymalloc/mymalloc.h"
+
+#include "rasserver_entry.hh"
+
+#include "debug-srv.hh"
+
+// console output describing successful/unsuccessful actions (cf. servercomm/servercomm.cc)
+#define MSG_OK "ok"
+#define MSG_FAILED "failed"
+
+
+struct HTTPRequest
+{
+ char *Database;
+ int Command;
+ char *QueryString;
+ int ClientType;
+ char *ClientID;
+ int Endianess;
+ int NumberOfQueryParams;
+ char *BinData;
+ int BinDataSize;
+ char *Capability;
+};
+
+
+RasServerEntry* RasServerEntry::myself = 0;
+
+RasServerEntry& RasServerEntry::getInstance()
+{
+ if(myself == 0)
+ myself = new RasServerEntry;
+ return *myself;
+}
+
+RasServerEntry::RasServerEntry()
+{
+}
+
+RasServerEntry::~RasServerEntry()
+{
+}
+
+void RasServerEntry::compat_connectToDBMS() throw( r_Error )
+{
+ // here no log output, this is a server startup function!
+
+ admin = AdminIf::instance();
+ if( !admin )
+ throw r_Error( r_Error::r_Error_BaseDBMSFailed );
+}
+
+void RasServerEntry::compat_connectNewClient(const char *capability)
+{
+ // we need to add the log information which otherwise is provided in ServerComm (servercomm/servercomm2.cc)
+ RMInit::logOut << "Request: connectNewClient..." << flush;
+
+ char client[256]; strcpy( client, "unknown" );
+
+#if 0 // client table is a relict from 1-process, multi-user rasdaman;
+ // now it conflicts with rasmgr dispatcher mimics, so we disable -- PB 2005-sep-01
+ currentClientContext = new ClientTblElt( client, ++(clientCount) );
+ currentClientIdx = clientCount;
+#else
+// this id must be !=0 because otherwise in ServerComm::getClientContext() it will not be recognized as valid id, and then the "last action" time will not be updated (timeout!)
+#define SINGLETON_CLIENTID 42
+
+ // disable client list by using only 1 element (fixed id), initialize only once
+ currentClientIdx = SINGLETON_CLIENTID;
+ // if (currentClientContext==NULL)
+ currentClientContext = new ClientTblElt( client, currentClientIdx );
+ TALK( "using constant Client id " << currentClientIdx );
+
+ // make sure any old element is deleted; currently inhibited, crashes :( -- PB 2005-sep-02
+ // RMInit::logOut << "client table has " << clientTbl.size() << " elements before cleanup, ";
+ // ServerComm::deleteClientTblEntry( currentClientIdx );
+ // RMInit::logOut << " and " << clientTbl.size() << " after.";
+#endif // 0
+
+ // Put the context information in the static control list
+ ServerComm::addClientTblEntry( currentClientContext );
+
+ TALK( "assigned Client id " << currentClientIdx );
+
+ if(accessControl.crunchCapability(capability) == CAPABILITY_REFUSED)
+ throw r_Ecapability_refused();
+
+ RMInit::logOut << MSG_OK << endl;
+}
+
+void RasServerEntry::compat_disconnectClient()
+{
+ // we need to add the log information which otherwise is provided in ServerComm (servercomm/servercomm2.cc)
+ RMInit::logOut << "Request: disconnect..." << flush;
+
+#if 0 //
+ deleteClientTblEntry( currentClientIdx );
+ currentClientIdx = -1;
+#else
+ // disable client list, use 1 constant element (see above) -- PB 2005-sep-01
+ currentClientIdx = SINGLETON_CLIENTID;
+ ServerComm::deleteClientTblEntry( currentClientIdx );
+
+ // delete currentClientContext;
+ // currentClientContext = NULL;
+
+ // clientTbl.resize( 0 );
+
+ RMInit::logOut << MSG_OK << endl;
+#endif // 0
+
+// in a disconnect following an abortta, the client can't be found any more in the table.
+// the delete op below then doesn't decrease table size -> endless loop.
+// Therefore let us take the original approach: delete only the requested client. -- PB 2003-nov-24
+#if 0
+ // THIS IS PARANOIA, ONCE WE HAD SOME PROBLEMS, SO WE KILL ALL
+ while(!clientTbl.empty())
+ {
+ ClientTblElt *temp = clientTbl.front();
+
+ temp->currentUsers = 0; // forced!
+
+ deleteClientTblEntry(temp->clientId);
+ }
+#endif // 0
+}
+
+// we want the ServerComm version, we'll drop this client management anyway
+ServerComm::ClientTblElt* RasServerEntry::getClientContext( unsigned long ClientId )
+{
+#if 0 // see above -- we just have 1 single context -- PB 2005-sep-01
+ ClientId = SINGLETON_CLIENTID;
+#endif // 0
+
+ return ServerComm::getClientContext( ClientId );
+}
+
+
+void RasServerEntry::compat_openDB(const char* databaseName)
+{
+ // we use "ServercComm::" just to show that it's that function
+ ServerComm::openDB( currentClientIdx, databaseName, "" );
+}
+
+void RasServerEntry::compat_closeDB()
+{
+ ServerComm::closeDB( currentClientIdx);
+}
+
+void RasServerEntry::compat_beginTA(bool rw)
+{
+ ServerComm::beginTA( currentClientIdx, rw ? 0 : 1);
+}
+
+void RasServerEntry::compat_commitTA()
+{
+ ServerComm::commitTA( currentClientIdx);
+}
+
+void RasServerEntry::compat_abortTA()
+{
+ ServerComm::abortTA( currentClientIdx);
+}
+
+bool RasServerEntry::compat_isOpenTA()
+{
+ return ServerComm::isTAOpen( currentClientIdx );
+}
+
+int GetHTTPRequestTemp( char *Source, int SourceLen, struct HTTPRequest *RequestInfo);
+
+int RasServerEntry::compat_executeQueryHttp(const char* httpParams, int httpParamsLen, char*& resultBuffer)
+{
+ strcpy(currentClientContext->clientIdText, ServerComm::HTTPCLIENT);
+
+ HTTPRequest RequestInfo;
+ /* Initialize RequestInfo */
+ RequestInfo.Database = NULL;
+ RequestInfo.QueryString = NULL;
+ RequestInfo.ClientType = 0;
+ RequestInfo.ClientID = NULL;
+ RequestInfo.Command = 0;
+ RequestInfo.Endianess = 0;
+ RequestInfo.NumberOfQueryParams = 0;
+ RequestInfo.BinDataSize = 0;
+ RequestInfo.BinData = NULL;
+ RequestInfo.Capability = NULL;
+
+ int resultLen = 0;
+ if(GetHTTPRequestTemp( (char*)httpParams, httpParamsLen, &RequestInfo) == 0)
+ {
+ // we need to add the log information which otherwise is provided in ServerComm (servercomm/servercomm2.cc)
+ // logged now in rnprotocol modules -- PB 2005-sep-05
+ // RMInit::logOut << "Request: http query '" << RequestInfo.QueryString << "'..." << flush;
+ char* queryResult;
+
+ resultLen = HttpServer::processRequest(currentClientIdx, RequestInfo.Database, RequestInfo.Command,
+ RequestInfo.QueryString, RequestInfo.BinDataSize,
+ RequestInfo.BinData, RequestInfo.Endianess,
+ queryResult,RequestInfo.Capability);
+
+ resultBuffer = queryResult;
+ RMInit::logOut << MSG_OK << endl;
+ }
+ else
+ RMInit::logOut << "Error: Internal HTTP protocol mismatch." << endl;
+
+ // free RequestInfo
+ free(RequestInfo.Database);
+ free(RequestInfo.QueryString);
+ free(RequestInfo.Capability);
+ free(RequestInfo.BinData);
+ free(RequestInfo.ClientID);
+
+ return resultLen;
+}
+
+r_OId RasServerEntry::compat_getNewOId(unsigned short objType)
+{
+ r_OId result;
+
+ ServerComm::getNewOId(currentClientIdx, objType, result);
+
+ return result;
+}
+
+
+int RasServerEntry::compat_executeQueryRpc(const char* query, ExecuteQueryRes &queryResult)
+{
+ queryResult.token=NULL;
+ queryResult.typeName=NULL;
+ queryResult.typeStructure=NULL;
+
+ return ServerComm::executeQuery(currentClientIdx, query, queryResult);
+}
+
+int RasServerEntry::compat_getNextElement(char* &buffer, unsigned int &bufferSize )
+{
+ return ServerComm::getNextElement(currentClientIdx, buffer, bufferSize);
+}
+
+int RasServerEntry::compat_endTransfer()
+{
+ return ServerComm::endTransfer(currentClientIdx);
+}
+
+int RasServerEntry::compat_getNextMDD(r_Minterval &mddDomain, char* &typeName, char* &typeStructure, r_OId &oid,unsigned short &currentFormat)
+{
+ return ServerComm::getNextMDD( currentClientIdx, mddDomain, typeName, typeStructure, oid, currentFormat);
+}
+int RasServerEntry::compat_getNextTile(RPCMarray** rpcMarray)
+{
+ return ServerComm::getNextTile( currentClientIdx, rpcMarray);
+}
+
+int RasServerEntry::compat_ExecuteUpdateQuery(const char *query, ExecuteUpdateRes& returnStructure)
+{
+ return ServerComm::executeUpdate(currentClientIdx, query, returnStructure);
+}
+
+int RasServerEntry::compat_InitUpdate()
+{
+ return ServerComm::initExecuteUpdate(currentClientIdx);
+}
+
+int RasServerEntry::compat_StartInsertTransMDD(const char *domain, int typeLength, const char *typeName)
+{
+ r_Minterval mddDomain(domain);
+ return ServerComm::startInsertTransMDD(currentClientIdx, mddDomain, typeLength, typeName);
+}
+
+int RasServerEntry::compat_InsertTile(int persistent, RPCMarray *rpcMarray)
+{
+ return ServerComm::insertTile( currentClientIdx, persistent, rpcMarray );
+}
+
+int RasServerEntry::compat_EndInsertMDD(int persistent)
+{
+ return ServerComm::endInsertMDD( currentClientIdx, persistent );
+}
+
+int RasServerEntry::compat_GetTypeStructure(const char *typeName, int typeType, char* &typeStructure)
+{
+ return ServerComm::getTypeStructure( currentClientIdx, typeName, typeType, typeStructure );
+}
+
+int RasServerEntry::compat_StartInsertPersMDD(const char *collName, r_Minterval &mddDomain, int typeLength, const char *typeName, r_OId &oid)
+{
+ return ServerComm::startInsertPersMDD( currentClientIdx, collName, mddDomain, typeLength, typeName, oid );
+}
+
+int RasServerEntry::compat_InsertMDD(const char *collName, RPCMarray *rpcMarray, const char *typeName, r_OId &oid)
+{
+ return ServerComm::insertMDD( currentClientIdx, collName, rpcMarray, typeName, oid );
+}
+
+int RasServerEntry::compat_InsertCollection(const char *collName, const char *typeName, r_OId &oid)
+{
+ return ServerComm::insertColl( currentClientIdx, collName, typeName, oid );
+}
+
+int RasServerEntry::compat_DeleteCollByName(const char *collName)
+{
+ return ServerComm::deleteCollByName( currentClientIdx, collName );
+}
+
+int RasServerEntry::compat_DeleteObjByOId(r_OId &oid)
+{
+ return ServerComm::deleteObjByOId( currentClientIdx, oid );
+}
+
+int RasServerEntry::compat_RemoveObjFromColl(const char *collName, r_OId &oid)
+{
+ return ServerComm::removeObjFromColl( currentClientIdx, collName, oid );
+}
+
+int RasServerEntry::compat_GetCollectionByName(const char* collName, char* &typeName, char* &typeStructure, r_OId &oid)
+{
+ return ServerComm::getCollByName( currentClientIdx, collName, typeName, typeStructure, oid );
+}
+
+int RasServerEntry::compat_GetCollectionByName(r_OId oid, char* &typeName, char* &typeStructure, char* &collName)
+{
+ return ServerComm::getCollByOId( currentClientIdx, oid, typeName,typeStructure, collName );
+}
+
+int RasServerEntry::compat_GetCollectionOidsByName(const char* collName, char* &typeName, char* &typeStructure, r_OId &oid, RPCOIdEntry* &oidTable, unsigned int &oidTableSize)
+{
+ return ServerComm::getCollOIdsByName( currentClientIdx, collName, typeName, typeStructure, oid, oidTable, oidTableSize);
+}
+
+int RasServerEntry::compat_GetCollectionOidsByOId(r_OId oid, char* &typeName, char* &typeStructure, RPCOIdEntry* &oidTable, unsigned int &oidTableSize, char* &collName)
+{
+ return ServerComm::getCollOIdsByOId( currentClientIdx, oid, typeName, typeStructure, oidTable, oidTableSize, collName);
+}
+
+int RasServerEntry::compat_GetObjectType(r_OId &oid, unsigned short &objType)
+{
+ return ServerComm::getObjectType( currentClientIdx, oid, objType );
+}
+
+int RasServerEntry::compat_SetTransferFormat(int format, const char* params)
+{
+ return ServerComm::setTransferMode( currentClientIdx, format, params );
+}
+
+int RasServerEntry::compat_SetStorageFormat(int format, const char* params)
+{
+ return ServerComm::setStorageMode( currentClientIdx, format, params );
+}
+
+//### stupid inherited stuff, we'll lose them later #####
+void RasServerEntry::startRpcServer() throw( r_Error ){}
+void RasServerEntry::stopRpcServer(){}
+//#######################################################
+
+// local version of this function, with small adaptations to compile here.
+int GetHTTPRequestTemp( char *Source, int SourceLen, struct HTTPRequest *RequestInfo)
+{
+ ENTER( "GetHTTPRequestTemp, source=" << Source << ", SourceLen=" << SourceLen );
+
+ int result = 0; // function return value
+ char *Buffer = NULL; // ptr to current analysis point in Input
+ char *Input = NULL; // local copy of Source
+
+ Input = new char[ SourceLen + 1 ];
+ memcpy( Input, Source, SourceLen );
+ Input[SourceLen] = '\0';
+ // Read the message body and check for the post parameters
+ Buffer = strtok( Input, "=" );
+ while( Buffer != NULL )
+ {
+ if( strcmp(Buffer,"Database") == 0 )
+ {
+ RequestInfo->Database = strdup(strtok( NULL, "&" ));
+ TALK( "Parameter Database is " << RequestInfo->Database );
+ Buffer = strtok( NULL, "=" );
+ }
+ else if( strcmp(Buffer,"QueryString") == 0 )
+ {
+ RequestInfo->QueryString = strdup(strtok( NULL, "&" ));
+ TALK( "Parameter QueryString is " << RequestInfo->QueryString );
+ Buffer = strtok( NULL, "=" );
+ }
+ else if( strcmp(Buffer,"Capability") == 0 )
+ {
+ RequestInfo->Capability = strdup(strtok( NULL, "&\0" ));
+ TALK( "Parameter Capability is " << RequestInfo->Capability );
+ Buffer = strtok( NULL, "=" );
+ }
+ else if( strcmp(Buffer,"ClientID") == 0 )
+ {
+ RequestInfo->ClientID = strdup(strtok( NULL, "&" ));
+ TALK( "Parameter ClientID is " << RequestInfo->ClientID );
+ Buffer = strtok( NULL, "=" );
+ }
+ else if( strcmp(Buffer,"Command") == 0 )
+ {
+ RequestInfo->Command = atoi( strtok( NULL, "&" ) );
+ TALK( "Parameter Command is " << RequestInfo->Command );
+ Buffer = strtok( NULL, "=" );
+ }
+ else if( strcmp(Buffer,"Endianess") == 0 )
+ {
+ RequestInfo->Endianess = atoi( strtok( NULL, "&" ) );
+ TALK( "Parameter Endianess is " << RequestInfo->Endianess );
+ Buffer = strtok( NULL, "=" );
+ }
+ else if( strcmp(Buffer,"NumberOfQueryParameters") == 0 )
+ {
+ RequestInfo->NumberOfQueryParams = atoi( strtok( NULL, "&" ) );
+ TALK( "Parameter NumberOfQueryParams is " << RequestInfo->NumberOfQueryParams );
+ Buffer = strtok( NULL, "=" );
+ }
+ else if( strcmp(Buffer,"BinDataSize") == 0 )
+ {
+ RequestInfo->BinDataSize = atoi( strtok( NULL, "&" ) );
+ TALK( "Parameter BinDataSize is " << RequestInfo->BinDataSize );
+ Buffer = strtok( NULL, "=" );
+ }
+ else if( strcmp(Buffer,"BinData") == 0 )
+ {
+ // This parameter has to be the last one!
+ RequestInfo->BinData = new char[RequestInfo->BinDataSize ];
+ memcpy(RequestInfo->BinData, Source + (SourceLen-RequestInfo->BinDataSize), RequestInfo->BinDataSize );
+ //set Buffer to NULL => exit this while block
+ Buffer = NULL;
+ }
+ else if( strcmp(Buffer,"ClientType") == 0 )
+ {
+ Buffer = strtok( NULL, "&" );
+ TALK( "Parameter Type is " << Buffer );
+ /* BROWSER? */
+ if( strcmp(Buffer,"BROWSER") == 0 )
+ RequestInfo->ClientType = 1;
+ /* Rasclient? */
+ else if( strcmp(Buffer,"RASCLIENT") == 0 )
+ RequestInfo->ClientType = 2;
+ /* Sonstiges */
+ else
+ {
+ TALK( "Error: Unknown Parameter: " << Buffer );
+ result = 2;
+ }
+ Buffer = strtok( NULL, "=" );
+ }
+ else
+ result = 1;
+ }
+
+ if (result == 0)
+ delete[] Input;
+
+ LEAVE( "GetHTTPRequestTemp, result=" << result );
+ return result;
+}
+
+//#####################################################################################################
+#include "server/createinitmdd.hh"
+
+r_OId RasServerEntry::createCollection(const char* collName, const char* collTypeName)
+{
+ FastCollectionCreator fcc(collName, collTypeName);
+
+ return fcc.createCollection();
+}
+
+r_OId RasServerEntry::createMDD(const char* collName, const char* mddTypeName, const char* definitionDomain, const char* tileDomain, bool rcindex)
+{
+ FastMDDCreator fc;
+
+ fc.setCollectionName(collName);
+ fc.setMDDTypeName(mddTypeName);
+
+ if(rcindex)
+ return fc.createRCxMDD(definitionDomain, tileDomain);
+
+ return fc.createMDD(definitionDomain);
+}
+
+void RasServerEntry::extendMDD(r_OId mddOId, const char *stripeDomain, const char* tileDomain)
+{
+ FastMDDCreator fc;
+
+ fc.addStripe(mddOId, stripeDomain, tileDomain);
+}
+
+vector<r_Minterval> RasServerEntry::getTileDomains(r_OId mddOId, const char *stripeDomain)
+{
+ FastMDDCreator fc;
+
+ return fc.getTileDomains(mddOId, stripeDomain);
+}
+
diff --git a/server/rasserver_entry.hh b/server/rasserver_entry.hh
new file mode 100644
index 0000000..64dbbfc
--- /dev/null
+++ b/server/rasserver_entry.hh
@@ -0,0 +1,140 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+#ifndef RASSERVER_ENTRY_HH
+#define RASSERVER_ENTRY_HH
+
+/*
+ This class is the entry point of the rasdaman server. It's the interface of the server to the outside world
+ It's functions are called by the communication level.
+
+ For now the class inherites HttpServer which inherites ServerComm, but only to have nice acces to the stuff
+ found there. Later we will drop both of them and make the life easier.
+*/
+
+#include "servercomm/httpserver.hh"
+
+
+class RasServerEntry : public HttpServer
+ {
+ private:
+ RasServerEntry();
+ static RasServerEntry* myself;
+ public:
+ static RasServerEntry& getInstance();
+
+ ~RasServerEntry();
+
+ //### inherited stuff - we have to keep them for now
+ void startRpcServer() throw( r_Error );
+ void stopRpcServer();
+ //###
+
+ void compat_connectToDBMS() throw( r_Error );
+
+ // All "compat_" functions use old ServerComm and HttpServer stuff to do their job
+ // Later, the new functions will do the job proper and this old functions will be dropped!
+ void compat_connectNewClient(const char *capability);
+ unsigned long currentClientIdx;
+ ClientTblElt* getClientContext( unsigned long ClientId ); // inherited...
+ ClientTblElt* currentClientContext;
+
+ void compat_disconnectClient();
+
+ void compat_openDB(const char* databaseName);
+
+ void compat_closeDB();
+
+ void compat_beginTA(bool rw);
+
+ void compat_commitTA();
+
+ void compat_abortTA();
+
+ bool compat_isOpenTA();
+
+ // provided for temporary compatibility with the encoding of the java interface
+ // resultBuffer will be allocated and it's address stored in the given pointer
+ // result is the length of the result
+ int compat_executeQueryHttp(const char* httpParams, int httpParamsLen, char*& resultBuffer);
+
+ r_OId compat_getNewOId(unsigned short objType); // 1 - mddType, 2 -collType
+
+ int compat_executeQueryRpc(const char* query, ExecuteQueryRes &queryResult);
+
+ int compat_getNextElement(char* &buffer, unsigned int &bufferSize );
+
+ int compat_endTransfer();
+
+ int compat_getNextMDD(r_Minterval &mddDomain, char* &typeName, char* &typeStructure, r_OId &oid,unsigned short &currentFormat);
+
+ int compat_getNextTile(RPCMarray** rpcMarray);
+
+ int compat_ExecuteUpdateQuery(const char *query, ExecuteUpdateRes &returnStructure);
+
+ int compat_InitUpdate();
+
+ int compat_StartInsertTransMDD(const char *domain, int typeLength, const char *typeName);
+
+ int compat_InsertTile(int persistent, RPCMarray*);
+
+ int compat_EndInsertMDD(int persistent);
+
+ int compat_GetTypeStructure(const char *typeName, int typeType, char* &typeStructure);
+
+ int compat_StartInsertPersMDD(const char *collName, r_Minterval &mddDomain, int typeLength, const char *typeName, r_OId &oid);
+
+ int compat_InsertMDD(const char *collName, RPCMarray *rpcMarray, const char *typeName, r_OId &oid);
+
+ int compat_InsertCollection(const char *collName, const char *typeName, r_OId &oid);
+
+ int compat_DeleteCollByName(const char *collName);
+
+ int compat_DeleteObjByOId(r_OId &oid);
+
+ int compat_RemoveObjFromColl(const char *collName, r_OId &oid);
+
+ int compat_GetCollectionByName(const char* collName, char* &typeName, char* &typeStructure, r_OId &oid);
+
+ int compat_GetCollectionByName(r_OId oid, char* &typeName, char* &typeStructure, char* &collName);
+
+ int compat_GetCollectionOidsByName(const char* collName, char* &typeName, char* &typeStructure, r_OId &oid, RPCOIdEntry* &oidTable, unsigned int &oidTableSize);
+
+ int compat_GetCollectionOidsByOId(r_OId oid, char* &typeName, char* &typeStructure, RPCOIdEntry* &oidTable, unsigned int &oidTableSize, char* &collName);
+
+ int compat_GetObjectType(r_OId &oid, unsigned short &objType);
+
+ int compat_SetTransferFormat(int format, const char* params);
+
+ int compat_SetStorageFormat(int format, const char* params);
+
+
+ r_OId createCollection(const char* collName, const char* collTypeName);
+
+ r_OId createMDD(const char* collName, const char* mddTypeName, const char* definitionDomain, const char* tileDomain, bool rcindex);
+
+ void extendMDD(r_OId mddOId, const char *stripeDomain, const char* tileDomain);
+
+ vector<r_Minterval> getTileDomains(r_OId mddOId, const char *stripeDomain);
+
+ };
+#endif
diff --git a/server/rasserver_main.cc b/server/rasserver_main.cc
new file mode 100644
index 0000000..adaaa8c
--- /dev/null
+++ b/server/rasserver_main.cc
@@ -0,0 +1,360 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+using namespace std;
+
+#ifndef RMANVERSION
+#error "Please specify RMANVERSION variable!"
+#endif
+
+#ifndef COMPDATE
+#error "Please specify the COMPDATE variable!"
+/*
+COMPDATE=`date +"%d.%m.%Y %H:%M:%S"`
+
+and -DCOMPDATE="\"$(COMPDATE)\"" when compiling
+*/
+#endif
+
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#ifdef __GNUG__
+#include "template_inst.hh"
+#endif
+#endif
+
+#include <iostream>
+#include <netdb.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string>
+
+#include "globals.hh" // DEFAULT_PORT
+#include "raslib/rmdebug.hh"
+#include "servercomm/httpserver.hh"
+#include "storagemgr/sstoragelayout.hh"
+#include <signal.h>
+
+RMINITGLOBALS('C');
+
+#include "rasserver_config.hh"
+#include "rnprotocol/rnpserver.hh"
+
+// from some unknown location the debug-srv.hh guard seems to be defined already, so get rid of it -- PB 2005-jan-10
+#undef DEBUG_HH
+#define DEBUG_MAIN debug_main
+#include "debug-srv.hh"
+
+
+bool initialization();
+
+extern int globalOptimizationLevel = 4;
+extern unsigned long maxTransferBufferSize = 4000000;
+extern char* dbSchema = 0;
+extern int noTimeOut = 0;
+
+// here the id string for connecting to the RDBMS is stored (used by rel* modules).
+// FIXME: bad hack -- PB 2003-oct-12
+char globalConnectId[256];
+int globalHTTPPort;
+// do we allow for User-Defined Functions? (aka rasql routines)
+bool udfEnabled = true;
+
+// drop client after 5 minutes of no alive signal
+// can be changed via cmd line parameter
+unsigned long clientTimeOut = CLIENT_TIMEOUT;
+
+// server management every 2 minutes
+unsigned long managementInterval = 120;
+
+const char* rasmgrHost = 0;
+int rasmgrPort = DEFAULT_PORT;
+const char* serverName = 0;
+int serverListenPort = 0;
+
+int main ( int argc, char** argv )
+{
+ SET_OUTPUT( true ); // enable debug output, if compiled so
+ ENTER( "rasserver.main()" );
+
+ //print startup text (this line will still go into forking rasmgr's log!)
+ cout << "Spawned rasserver v" << RMANVERSION / 1000. << " on base DBMS " << BASEDBSTRING << " -- generated on " << COMPDATE << "." << endl;
+
+ if(configuration.parseCommandLine(argc, argv) == false)
+ {
+ RMInit::logOut << "Error: cannot parse command line." << endl;
+ LEAVE( "rasserver.main(): Error parsing command line." );
+ return -1;
+ }
+
+ RMInit::logOut << "rasserver: rasdaman server v" << RMANVERSION / 1000. << " on base DBMS " << BASEDBSTRING << " -- generated on " << COMPDATE << "." << endl;
+ std::cout << " Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann rasdaman GmbH." << std::endl
+ << "Rasdaman community is free software: you can redistribute it and/or modify "
+ "it under the terms of the GNU General Public License as published by "
+ "the Free Software Foundation, either version 3 of the License, or "
+ "(at your option) any later version. \n"
+ "Rasdaman community is distributed in the hope that it will be useful, "
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of "
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the "
+ "GNU General Public License for more details. \n\n";
+
+ RMInit::logOut << "This program contains software which is in the public domain:" << endl;
+ RMInit::logOut << " zlib 1.1.4 (C) 1995-1998 Jean-loup Gailly and Mark Adler" << endl;
+ RMInit::logOut << " libpng 1.2.1 (C) 2002 Glenn Randers-Pehrson" << endl;
+ RMInit::logOut << " libtiff 3.8.0 (C) 1988-1997 Sam Leffler, (C) 1991-1997 Silicon Graphics, Inc." << endl;
+ RMInit::logOut << " libjpeg 6b (C) 1991-1998, Thomas G. Lane." << endl;
+ RMInit::logOut << " openssl 0.96c (C) 1998-2002 The OpenSSL Project, (C) 1995-1998 Eric A. Young, Tim J. Hudson" << endl;
+
+ if(initialization() == false )
+ {
+ RMInit::logOut << "Error during initialization. aborted." << endl;
+ LEAVE( "rasserver.main(): Error during initialization." );
+ return -1;
+ }
+
+ //
+ // body rasserver
+ //
+
+ RMInit::logOut << "Installing signal handler for ignoring broken pipe signal..." << flush;
+ signal( SIGPIPE, SIG_IGN );
+ RMInit::logOut << "ok" << endl;
+
+ int returnCode = 0;
+ ServerComm* server = NULL;
+
+ try
+ {
+ TALK( "selecting server type..." );
+
+ if(configuration.isRnpServer())
+ {
+ TALK( "startRnpServer()..." );
+ startRnpServer();
+ TALK( "startRnpServer() done." );
+ }
+ else if(configuration.isHttpServer())
+ {
+ TALK( "initializing HttpServer()..." );
+ server = new HttpServer( clientTimeOut, managementInterval, serverListenPort, (char*)rasmgrHost, rasmgrPort,(char*)serverName);
+ }
+ else
+ {
+ TALK( "initializing ServerComm() (ie: RPC)..." );
+ server = new ServerComm( clientTimeOut, managementInterval, serverListenPort, (char*)rasmgrHost, rasmgrPort,(char*)serverName);
+ }
+
+ // in case of HTTP or RPC server: launch previously generated object
+ if(server)
+ {
+ TALK( "server->startRpcServer()..." );
+ server->startRpcServer();
+ TALK( "server->startRpcServer() done." );
+ }
+ }
+ catch ( r_Error& errorObj )
+ {
+ TALK( "Error: encountered " << errorObj.get_errorno() << ": " << errorObj.what() );
+ RMInit::logOut << "Error: encountered " << errorObj.get_errorno() << ": " << errorObj.what() << endl;
+// we never write to stdout (= rasmgr log file), so we don't need this -- PB 2003-nov-24
+#if 0
+ if(!configuration.isLogToStdOut())
+ {
+ RMInit::logOut << "Error: encountered " << errorObj.get_errorno() << ": " << errorObj.what() << endl;
+ }
+#endif // 0
+ returnCode = -1;
+ }
+ catch(...)
+ {
+ TALK( "rasserver: general exception" );
+ RMInit::logOut << "rasserver: general exception" << endl;
+// we never write to stdout (= rasmgr log file), so we don't need this -- PB 2003-nov-24
+#if 0
+ if(!configuration.isLogToStdOut())
+ {
+ RMInit::logOut << "rasserver: general exception" << endl;
+ }
+#endif
+ returnCode = -1;
+ }
+
+ if(server)
+ delete server;
+ server = NULL;
+
+ if( dbSchema )
+ free( dbSchema );
+ dbSchema = NULL;
+
+ LEAVE( "rasserver.main(): -> " << returnCode );
+ return returnCode;
+}
+
+bool initialization()
+{
+ serverName = configuration.getServerName();
+ accessControl.setServerName(serverName);
+
+ serverListenPort = globalHTTPPort = configuration.getListenPort();
+
+ RMInit::logOut<<"Server "<< serverName << " of type ";
+
+ if(configuration.isRnpServer())
+ RMInit::logOut << "RNP, listening on port " << serverListenPort << flush;
+ else if(configuration.isHttpServer())
+ RMInit::logOut << "HTTP, listening on port " << serverListenPort << flush;
+ else
+ RMInit::logOut << "RPC, registered with prognum 0x" << hex <<serverListenPort << dec << flush;
+
+ // globalConnectId = configuration.getDbConnectionID();
+ strcpy(globalConnectId,configuration.getDbConnectionID());
+ RMInit::logOut << ", connecting to " << BASEDBSTRING << " as '" << globalConnectId << "'." << endl;
+
+// we never write to stdout (= rasmgr log file), so we don't need this -- PB 2003-nov-24
+#if 0
+ if(!configuration.isLogToStdOut())
+ {
+ RMInit::logOut<<"Server "<< serverName << " of type ";
+ if(configuration.isRnpServer())
+ RMInit::logOut << "RNP, listening on port " << serverListenPort << endl;
+ else if(configuration.isHttpServer())
+ RMInit::logOut << "HTTP, listening on port " << serverListenPort << endl;
+ else
+ RMInit::logOut << "RPC, registered with prognum 0x" << hex <<serverListenPort << dec << endl;
+ }
+#endif // 0
+
+ rasmgrHost = configuration.getRasmgrHost();
+ rasmgrPort = configuration.getRasmgrPort();
+
+ RMInit::logOut << "Verifying rasmgr host name: " << rasmgrHost << "...";
+// we don't write to stdout (=rasmgr log), so no need to duplicate -- PB 2003-nov-24
+#if 0
+ if(!configuration.isLogToStdOut())
+ RMInit::logOut << "Verifying RasMGR host name: " << rasmgrHost << "...";
+#endif // 0
+ if(!gethostbyname(rasmgrHost))
+ {
+ RMInit::logOut << "failed" << endl;
+ if(!configuration.isLogToStdOut()) RMInit::logOut << "failed" << endl;
+ return false;
+ }
+ RMInit::logOut << "ok" << endl;
+// we don't write to stdout (=rasmgr log), so no need to duplicate -- PB 2003-nov-24
+#if 0
+ if(!configuration.isLogToStdOut())
+ RMInit::logOut << " ok" << endl;
+#endif // 0
+
+ globalOptimizationLevel = configuration.getDefaultOptimizationLevel();
+
+ maxTransferBufferSize = configuration.getMaxTransferBufferSize();
+
+ clientTimeOut = configuration.getTimeout();
+ if(clientTimeOut == 0)
+ noTimeOut = 1;
+
+ managementInterval = clientTimeOut/4;
+
+#ifdef RMANDEBUG
+ //tilesize
+ StorageLayout::DefaultTileSize = configuration.getDefaultTileSize();
+ RMInit::logOut << "Tile size set to : " << StorageLayout::DefaultTileSize << endl;
+
+ //pctmin
+ StorageLayout::DefaultMinimalTileSize = configuration.getDefaultPCTMin();
+ RMInit::logOut << "PCTMin set to : " << StorageLayout::DefaultMinimalTileSize << endl;
+
+ //pctmax
+ StorageLayout::DefaultPCTMax = configuration.getDefaultPCTMax();
+ RMInit::logOut << "PCTMax set to : " << StorageLayout::DefaultPCTMax << endl;
+
+ //indexsize
+ StorageLayout::DefaultIndexSize = configuration.getDefaultIndexSize();
+ RMInit::logOut << "IndexSize set to : " << StorageLayout::DefaultIndexSize << endl;
+
+ RManDebug = configuration.getDebugLevel();
+ RMInit::logOut<<"Debug level: " << RManDebug << endl;
+
+ try
+ {
+ StorageLayout::DefaultTileConfiguration = r_Minterval(configuration.getDefaultTileConfig());
+ }
+ catch(r_Error& err)
+ {
+ RMInit::logOut << "Error converting " << configuration.getDefaultTileConfig() << " to r_Minterval" << endl;
+ RMInit::logOut << "Error " << err.get_errorno() << " : " << err.what() << endl;
+ if(!configuration.isLogToStdOut())
+ {
+ RMInit::logOut << "Error converting " << configuration.getDefaultTileConfig() << " to r_Minterval" << endl;
+ RMInit::logOut << "Error " << err.get_errorno() << " : " << err.what() << endl;
+ }
+ return false;
+ }
+ RMInit::logOut << "Default Tile Conf: " << StorageLayout::DefaultTileConfiguration << endl;
+
+ // Tiling
+ r_Tiling_Scheme tmpTS=get_tiling_scheme_from_name(configuration.getTilingScheme());
+
+ if(tmpTS != r_Tiling_Scheme_NUMBER)
+ StorageLayout::DefaultTilingScheme = tmpTS;
+
+ if((tmpTS != r_NoTiling) && (tmpTS != r_RegularTiling))
+ {
+ RMInit::logOut << "Error: unsupported tiling strategy: " << configuration.getTilingScheme() << endl;
+ if(configuration.isLogToStdOut())
+ {
+ RMInit::logOut << "Error: unsupported tiling strategy: " << configuration.getTilingScheme() << endl;
+ }
+ return false;
+ }
+
+ //retiling enabled only if tiling scheme is regular tiling
+ RMInit::tiling = (tmpTS == r_RegularTiling);
+ RMInit::logOut << "Default Tiling : " << StorageLayout::DefaultTilingScheme << endl;
+
+ // Index
+ r_Index_Type tmpIT = get_index_type_from_name(configuration.getIndexType());
+ if ( tmpIT != r_Index_Type_NUMBER)
+ StorageLayout::DefaultIndexType = tmpIT;
+ RMInit::logOut << "Default Index : " << StorageLayout::DefaultIndexType << endl;
+
+ //use tilecontainer
+ RMInit::useTileContainer = configuration.useTileContainer();
+ RMInit::logOut << "Use Tile Container: " << RMInit::useTileContainer << endl;
+#endif
+
+ return true;
+}
+
diff --git a/server/template_inst.hh b/server/template_inst.hh
new file mode 100644
index 0000000..7c5a2b8
--- /dev/null
+++ b/server/template_inst.hh
@@ -0,0 +1,132 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+//for rb_tree, select1st
+#include <ext/functional>
+#include <ext/rb_tree>
+#include <vector>
+#include <utility>
+#include <memory>
+
+#if(__GNUC__==2 &&__GNUC_MINOR__==95)
+using std::rb_tree;
+using std::select1st;
+#else
+using __gnu_cxx::rb_tree;
+using __gnu_cxx::select1st;
+#endif
+
+using std::vector;
+using std::pair;
+
+// commented by Constantin Jucovschi (gcc 3.4+ no longer supports __default_alloc_template)
+//using std::__default_alloc_template;
+using std::fill_n;
+
+#include "qlparser/symtab.hh"
+
+#include "raslib/attribute.hh"
+#include "raslib/itertype.hh"
+#include "raslib/dlist.hh"
+
+#include "tilemgr/tile.hh"
+
+#include "indexmgr/keyobject.hh"
+
+#include "reladminif/dbref.hh"
+#include "reladminif/dbobjectiditerator.hh"
+
+#include "relblobif/blobtile.hh"
+#include "relblobif/dbtile.hh"
+#include "relblobif/inlinetile.hh"
+
+#include "relcatalogif/typeiterator.hh"
+#include "relcatalogif/settype.hh"
+#include "relcatalogif/structtype.hh"
+#include "relcatalogif/mddtype.hh"
+#include "relcatalogif/inlineminterval.hh"
+#include "relcatalogif/dbminterval.hh"
+
+#include "relindexif/dbtcindex.hh"
+#include "relindexif/hierindex.hh"
+#include "relindexif/dbrcindexds.hh"
+
+#include "relmddif/dbmddobj.hh"
+#include "relmddif/dbmddset.hh"
+
+#include "relstorageif/dbstoragelayout.hh"
+
+template class SymbolTable<int>;
+
+template class r_IterType<r_Attribute>;
+
+template class DBRef<DBHierIndex>;
+template class DBRef<DBRCIndexDS>;
+template class DBRef<DBTCIndex>;
+template class DBRef<BLOBTile>;
+template class DBRef<DBTile>;
+template class DBRef<InlineTile>;
+template class DBRef<DBMDDSet>;
+template class DBRef<DBMinterval>;
+template class DBRef<DBStorageLayout>;
+template bool operator< (const DBRef<DBMDDObj>&, const DBRef<DBMDDObj>&);
+
+//template TypeIterator<StructType>;
+//template TypeIterator<SetType>;
+template class TypeIterator<MDDType>;
+template class DBRef<DBMDDObj>;
+template class DBRef<DBObject>;
+
+template class DBObjectIdIterator<DBMDDObj>;
+template class DBObjectIterator<DBMDDObj>;
+template class DBObjectIterator<DBMDDSet>;
+template class DBObjectIterator<StructType>;
+template class DBObjectIterator<SetType>;
+template class DBRef<StructType>;
+template class DBRef<SetType>;
+template class DBRef<MDDType>;
+
+template std::ostream& operator<< (const vector<KeyObject>&, std::ostream&);
+template std::ostream& operator<< (std::ostream &, const vector<KeyObject>&);
+template std::ostream& operator << (std::ostream& os, const std::vector<double>& list);
+template std::ostream& operator << (std::ostream& os, const std::vector<r_Minterval>& list);
+
+template class rb_tree<OId, pair<OId const, DBMDDObj *>, select1st<pair<OId const, DBMDDObj *> >, less<OId> >;
+template class rb_tree<OId, pair<OId const, DBMinterval *>, select1st<pair<OId const, DBMinterval *> >, less<OId> >;
+template class rb_tree<OId, pair<OId const, DBRef<DBMDDObj> >, select1st<pair<OId const, DBRef<DBMDDObj> > >, less<OId> >;
+template class rb_tree<OId, pair<OId const, DBMDDSet *>, select1st<pair<OId const, DBMDDSet *> >, less<OId> >;
+template class rb_tree<OId, pair<OId const, MDDType *>, select1st<pair<OId const, MDDType *> >, less<OId> >;
+template class rb_tree<OId, pair<OId const, SetType *>, select1st<pair<OId const, SetType *> >, less<OId> >;
+template class rb_tree<OId, pair<OId const, StructType *>, select1st<pair<OId const, StructType *> >, less<OId> >;
+template class rb_tree<long, pair<long const, BLOBTile *>, select1st<pair<long const, BLOBTile *> >, less<long> >;
+template class rb_tree<long, pair<long const, InlineTile *>, select1st<pair<long const, InlineTile *> >, less<long> >;
+template class vector<BaseType const * >;
+template class vector<OId >;
+template class vector<Tile * >;
+template class vector<Type * >;
+template class vector<char * >;
+template class vector<char >;
+template class vector<r_Data_Format >;
+template class vector<unsigned int >;
+
+template class Tile ** fill_n<Tile **, unsigned int, Tile *>(Tile **, unsigned int, Tile * const &);
+
diff --git a/server/test/Makefile b/server/test/Makefile
new file mode 100644
index 0000000..f86365f
--- /dev/null
+++ b/server/test/Makefile
@@ -0,0 +1,59 @@
+# -*-Makefile-*-
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>. # Top Level makefile. This points to the various modules that have to be build
+# and/or deployed
+#
+# MAKEFILE FOR:
+# testing rasserver
+#
+# COMMENTS:
+# List environment dependencies, known bugs, specialities etc.
+#
+##################################################################
+#
+# This is just an example Makefile for a test program.
+# The dependency of the test program on the lib of the
+# corresponding module is in the Makefile of the module.
+#
+
+######################### Definitions ############################
+
+# standard include with general options
+include $(RMANBASE)/Makefile.inc
+
+# object files for test program
+TESTOBJS =
+# name of test program
+TESTPRG =
+
+########################### Targets ##############################
+
+$(TESTPRG): $(TESTOBJS) $(OBJS)
+ $(CXX) $(LDFLAGS) -o $@ $^
+
+.PHONY : clean
+clean:
+ -rm $(TESTOBJS)
+ -rm $(TESTPRG)
+
+######################## Dependencies ############################
+
diff --git a/server/test/test_mult-db-open.cc b/server/test/test_mult-db-open.cc
new file mode 100644
index 0000000..b803026
--- /dev/null
+++ b/server/test/test_mult-db-open.cc
@@ -0,0 +1,165 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)exportutils,ExportData: $Id: exporttif.cc,v 1.1 2003/12/27 21:44:18 rasdev Exp $";
+
+#ifndef RMANVERSION
+#error "Please specify RMANVERSION variable!"
+#endif
+
+#ifndef COMPDATE
+#error "Please specify the COMPDATE variable!"
+/*
+COMPDATE=`date +"%d.%m.%Y %H:%M:%S"`
+
+and -DCOMPDATE="\"$(COMPDATE)\"" when compiling
+*/
+#endif
+
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#ifdef __GNUG__
+#include "raslib/template_inst.hh"
+#endif
+#endif
+
+#include <iostream>
+#include <cstdio>
+#include <cctype>
+
+using std::vector;
+using std::iterator;
+
+#if defined(SOLARIS)
+# include <strings.h>
+#else
+# include <cstring>
+#endif
+
+#include "mymalloc/mymalloc.h"
+
+// here is the main prog for allocating debug macro vars
+#define DEBUG_MAIN
+#include "debug.hh"
+
+#include "rasodmg/transaction.hh"
+#include "rasodmg/database.hh"
+
+
+// global variables and default settings
+// -------------------------------------
+
+r_Database db;
+r_Transaction ta;
+
+const char* server = DEFAULT_SERV;
+unsigned int port = DEFAULT_PORT;
+const char* database = DEFAULT_DB;
+const char* user = DEFAULT_USER;
+const char* passwd = DEFAULT_PASSWD;
+
+
+void
+openDatabase() throw (r_Error)
+{
+ ENTER( "openDatabase" );
+
+ if (! dbIsOpen)
+ {
+ cout << "Opening database " << database << " at " << server << ":" << port << "..." << flush;
+ db.set_servername(server, port);
+ db.set_useridentification( user, passwd);
+ TALK( "database was closed, opening database=" << database << ", server=" << server << ", port=" << port << ", user=" << user << ", passwd=" << passwd << "..." );
+ db.open( database );
+ TALK( "done" );
+ dbIsOpen = true;
+ cout << "ok" << endl << flush;
+ }
+
+ LEAVE( "openDatabase" );
+}
+
+void
+closeDatabase() throw (r_Error)
+{
+ ENTER( "closeDatabase" );
+
+ if (dbIsOpen)
+ {
+ TALK( "database was open, closing it" );
+ db.close();
+ dbIsOpen = false;
+ }
+
+ LEAVE( "closeDatabase" );
+ return;
+}
+
+
+int main(int argc, char** argv)
+{
+ SET_OUTPUT( false ); // inhibit unconditional debug output, await cmd line evaluation
+
+ int retval = EXIT_FAILURE;
+
+ cout << argv[0] << ": rasdaman test 'failure upon multiple db open' for rasdaman v" << RMANVERSION/1000 << " -- generated on " << COMPDATE << endl;
+
+ try
+ {
+ openDatabase();
+
+ closeDatabase();
+
+ retval = EXIT_SUCCESS;
+ }
+ catch (ExportError& e)
+ {
+ cout << argv[0] << ": " << e.what() << endl;
+ retval = EXIT_FAILURE;
+ }
+ catch (const r_Error& e)
+ {
+ cout << argv[0] << ": rasdaman error " << e.get_errorno() << ": " << e.what() << endl;
+ retval = EXIT_FAILURE;
+ }
+ catch (...)
+ {
+ cout << argv[0] << ": panic: unexpected internal exception." << endl;
+ retval = EXIT_FAILURE;
+ }
+
+ cout << argv[0] << " done." << endl;
+
+ return retval;
+}
+
diff --git a/servercomm/Makefile.am b/servercomm/Makefile.am
new file mode 100644
index 0000000..07e962f
--- /dev/null
+++ b/servercomm/Makefile.am
@@ -0,0 +1,50 @@
+# -*-Makefile-*- (for Emacs)
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+#
+# MAKEFILE FOR:
+# module servercomm
+#
+# COMMENTS:
+#
+##################################################################
+
+AM_CXXFLAGS=@BASEDBCXXFLAGS@
+AM_LDFLAGS=@BASEDBLDFLAGS@
+
+noinst_LIBRARIES=libservercomm.a
+libservercomm_a_SOURCES=../clientcomm/rpcif_xdr.c ../clientcomm/rpcif_svc.cc servercomm.cc \
+ servercomm2.cc manager.cc callbackmgr.cc httpserver.cc \
+ ../mymalloc/mymalloc_svc.cc ../mymalloc/mymalloc.h \
+ ../clientcomm/rpcif.h callbackmgr.hh httpserver.hh httpserver.icc \
+ servercomm.hh servercomm.icc
+BUILT_SOURCES=../clientcomm/rpcif_xdr.c ../clientcomm/rpcif.h ../clientcomm/rpcif_svc.cc
+
+.PHONY: ../clientcomm/rpcif_xdr.c ../clientcomm/rpcif.h ../clientcomm/rpcif_svc.cc
+../clientcomm/rpcif_xdr.c:
+ cd ../clientcomm ; $(MAKE) rpcif_xdr.c
+
+../clientcomm/rpcif.h:
+ cd ../clientcomm ; $(MAKE) rpcif.h
+
+../clientcomm/rpcif_svc.cc:
+ cd ../clientcomm ; $(MAKE) rpcif_svc.cc
diff --git a/servercomm/callbackmgr.cc b/servercomm/callbackmgr.cc
new file mode 100644
index 0000000..ff5cb08
--- /dev/null
+++ b/servercomm/callbackmgr.cc
@@ -0,0 +1,172 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: callbackmgr.hh
+ *
+ * MODULE: servercomm
+ * CLASS: CallBackManager
+ *
+ * COMMENTS:
+ * No Comments
+*/
+
+
+#include <malloc.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "raslib/rmdebug.hh"
+#include "debug.hh"
+
+#include "servercomm/callbackmgr.hh"
+
+
+CallBackManager::CallBackManager(unsigned int size)
+{
+ RMDBGONCE(1, RMDebug::module_servercomm, "CallBackManager", "CallBackManager(" << size << ")" )
+
+ callbacks = new callback_desc_t[size];
+ maxCallbacks = size;
+ numPending = 0;
+ overflowDetected = 0;
+}
+
+
+CallBackManager::~CallBackManager(void)
+{
+ RMDBGONCE(1, RMDebug::module_servercomm, "CallBackManager", "~CallBackManager()" )
+
+ delete [] callbacks;
+}
+
+
+void CallBackManager::setMaximumSize(unsigned int size)
+{
+ RMDBGONCE(1, RMDebug::module_servercomm, "CallBackManager", "setMaximumSize(" << size << ")" )
+
+ callback_desc_t *newcb = new callback_desc_t[size];
+
+ if (callbacks != NULL)
+ {
+ if (numPending != 0)
+ {
+ unsigned int copysize = (numPending > size) ? size : numPending;
+ memcpy(newcb, callbacks, copysize * sizeof(callback_desc_t));
+ if (copysize < numPending)
+ overflowDetected = 1;
+ }
+ delete [] callbacks;
+ }
+ callbacks = newcb;
+ maxCallbacks = size;
+}
+
+
+int CallBackManager::findCallback(callback_f function, void *context) const
+{
+ unsigned int i;
+
+ // No system calls from this function!
+ for (i=0; i<numPending; i++)
+ {
+ if ((callbacks[i].function == function) && (callbacks[i].context == context))
+ return (int)i;
+ }
+ return -1;
+}
+
+
+int CallBackManager::registerCallback(callback_f function, void *context)
+{
+ // No mallocs, debug output, system calls, ... in this function!!!
+ if (numPending >= maxCallbacks)
+ {
+ overflowDetected = 1;
+ return -1;
+ }
+
+ callbacks[numPending].function = function;
+ callbacks[numPending].context = context;
+
+ numPending++;
+
+ return 0;
+}
+
+
+int CallBackManager::registerUniqueCallback(callback_f function, void *context)
+{
+ if (findCallback(function, context) == -1)
+ return registerCallback(function, context);
+ else
+ return -1;
+}
+
+
+int CallBackManager::removeCallback(callback_f function, void *context)
+{
+ int i;
+
+ // restrictive environment here too, no system calls!
+ i = findCallback(function, context);
+ if (i != -1)
+ {
+ if (i < (int)numPending-1)
+ memmove(callbacks+i, callbacks+(i+1), (numPending-i-1)*sizeof(callback_desc_t));
+ numPending--;
+ return 0;
+ }
+ return -1;
+}
+
+
+unsigned int CallBackManager::getNumCallbacks(void) const
+{
+ return numPending;
+}
+
+
+int CallBackManager::executePending(void)
+{
+ unsigned int i;
+
+ RMDBGENTER(2, RMDebug::module_servercomm, "CallBackManager", "executePending()" )
+
+ for (i=0; i<numPending; i++)
+ {
+ RMDBGMIDDLE(3, RMDebug::module_servercomm, "CallBackManager", "callback function " << i << "..." );
+ callbacks[i].function(callbacks[i].context);
+ }
+
+ if (overflowDetected)
+ {
+ TALK( "CallBackManager::executePending(): overflow detected, number of pending calls: " << numPending );
+ RMInit::logOut << "Internal error: callback overflow." << endl;
+ overflowDetected = 0;
+ }
+
+ i = numPending;
+ numPending = 0;
+
+ return i;
+}
diff --git a/servercomm/callbackmgr.hh b/servercomm/callbackmgr.hh
new file mode 100644
index 0000000..81effcb
--- /dev/null
+++ b/servercomm/callbackmgr.hh
@@ -0,0 +1,136 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: callbackmgr.hh
+ *
+ * MODULE: servercomm
+ * CLASS: CallBackManager
+ *
+ * COMMENTS:
+ * No Comments
+*/
+
+
+#ifndef _CALLBACK_MANAGER_
+#define _CALLBACK_MANAGER_
+
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The class CallBackManager stores function- and context pointers
+ that are executed in the order they were registered in when
+ calling executePending(). This system replaces the alarm handler
+ approach formerly used which suffered from a restrictive
+ environment where mallocs and printfs were not legal. Since
+ neither call must happen when a callback function is registered
+ the maximum number of callbacks must be fixed in the constructor.
+*/
+
+class CallBackManager
+{
+ public:
+ /// constructor
+ CallBackManager(unsigned int size=1024);
+ /**
+ Constructor; size is the maximum number of callback slots to
+ reserve.
+ */
+
+ /// destructor
+ ~CallBackManager(void);
+
+ /// Resizes the number of callback slots at run-time
+ void setMaximumSize(unsigned int size);
+
+ /// callback function type
+ typedef void (*callback_f)(void*);
+ /**
+ The type of a callback function is void f(void *context). The
+ value of context is the one specified when registering. It's
+ up to the function to cast the value.
+ */
+
+ /// register new callback
+ int registerCallback(callback_f function, void *context);
+ /**
+ Register a new callback function. Returns 0 for OK, -1 if
+ the callback table had an overflow. Since it must be possible
+ to call this function from an alarm handler there may not be
+ any mallocs or prints here.
+ */
+
+ /// register new callback, ensuring uniqueness
+ int registerUniqueCallback(callback_f function, void *context);
+ /**
+ Same as registerCallback, but makes sure this callback isn't
+ pending already in which case it does nothing.
+ */
+
+ /// remove callback
+ int removeCallback(callback_f function, void *context);
+ /**
+ Deregister a callback function. Returns 0 for OK, -1 for
+ not found.
+ */
+
+ /// Get the number of callback functions registered.
+ unsigned int getNumCallbacks(void) const;
+
+ /// execute pending callbacks
+ int executePending(void);
+ /**
+ Execute all pending callback functions and clear the list
+ afterwards. Returns the number of callback functions executed.
+ */
+
+
+ private:
+
+ /// find a matching function/context pair
+ int findCallback(callback_f function, void *context) const;
+ /**
+ Searches the pending callbacks for the one specified by the
+ function parameters and returns its index if found, -1 otherwise.
+ */
+
+ //@{ Internal storage structure for callbacks.
+ typedef struct callback_desc_s {
+ callback_f function;
+ void *context;
+ } callback_desc_t;
+ //@}
+
+ callback_desc_t *callbacks;
+
+ /// Maximum size of callback list
+ unsigned int maxCallbacks;
+
+ /// Currently occupied callback slots
+ unsigned int numPending;
+
+ /// Flag that's set to 1 if the callback table overflowed.
+ int overflowDetected;
+};
+
+#endif
diff --git a/servercomm/httpserver.cc b/servercomm/httpserver.cc
new file mode 100644
index 0000000..514f6b8
--- /dev/null
+++ b/servercomm/httpserver.cc
@@ -0,0 +1,1371 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: httpserver.cc
+ *
+ * MODULE: httpserver
+ * CLASS: HttpServer
+ *
+ * COMMENTS:
+ * No Comments
+*/
+
+#include "mymalloc/mymalloc.h"
+
+static const char rcsid[] = "@(#)servercomm, HttpServer: $Id: httpserver.cc,v 1.54 2005/09/03 21:05:14 rasdev Exp $";
+
+#include <iostream>
+#include <malloc.h>
+#include <time.h> // for time()
+#include <string.h>
+
+#include <signal.h> // for signal()
+#include <unistd.h> // for alarm(), gethostname()
+#include <iomanip>
+
+#include "raslib/rmdebug.hh"
+#include "raslib/rminit.hh"
+#include "raslib/error.hh"
+#include "raslib/minterval.hh"
+#include "raslib/endian.hh"
+#include "raslib/basetype.hh"
+
+#include "servercomm/httpserver.hh"
+#include "qlparser/qtnode.hh"
+#include "qlparser/qtdata.hh"
+#include "catalogmgr/typefactory.hh"
+
+#include "mddmgr/mddcoll.hh"
+#include "tilemgr/tile.hh"
+
+#include "relcatalogif/mddtype.hh"
+#include "relcatalogif/mdddomaintype.hh"
+#include "relcatalogif/settype.hh"
+
+#ifdef PURIFY
+#include <purify.h>
+#endif
+
+#ifdef RMANBENCHMARK
+ // to control ZLibCompression::decompTimer and ZLibCompression::compTimer
+ #include "zlibcompression.hh"
+#endif
+
+#include "httpserver/httpserver.h"
+
+#include "qlparser/qtmdd.hh"
+#include "qlparser/qtatomicdata.hh"
+#include "qlparser/qtcomplexdata.hh"
+#include "qlparser/qtintervaldata.hh"
+#include "qlparser/qtmintervaldata.hh"
+#include "qlparser/qtpointdata.hh"
+#include "qlparser/qtstringdata.hh"
+
+#define UNEXPECTED_INTERNAL_ERROR 10000
+
+// ok message for log output; should go into a central file
+#define MSG_OK "ok"
+
+// include and extern declarations for the query parsing
+#include "qlparser/querytree.hh"
+extern int yyparse();
+extern void yyreset();
+extern QueryTree* parseQueryTree;
+extern ParseInfo* parseError;
+extern char* beginParseString;
+extern char* iterParseString;
+extern unsigned long maxTransferBufferSize;
+extern char* dbSchema;
+extern MDDColl* mddConstants;
+
+// this is a temporary thing
+extern int globalOptimizationLevel;
+
+#ifdef RMANBENCHMARK
+#if BASEDB == 1
+static o2_ClientStat newO2Stats;
+static o2_ClientStat oldO2Stats;
+#endif
+#endif
+
+// defined in servercomm2.cc
+extern char globalHTTPSetTypeStructure[];
+
+// This currently represents the one and only client active at one time.
+static HttpServer::ClientTblElt globalClientContext(ServerComm::HTTPCLIENT, 1);
+
+// At the beginning, no servercomm object exists.
+HttpServer* HttpServer::actual_httpserver = 0;
+
+// This is a local inline function to enable encoding of longs into chars
+static inline void encodeLong(char* res, const r_Long* val)
+{
+ *res = *(char*)val;
+ *(res+1) = *((char*)val+1);
+ *(res+2) = *((char*)val+2);
+ *(res+3) = *((char*)val+3);
+}
+
+static inline void encodeULong(char* res, const r_ULong* val)
+{
+ *res = *(char*)val;
+ *(res+1) = *((char*)val+1);
+ *(res+2) = *((char*)val+2);
+ *(res+3) = *((char*)val+3);
+}
+
+// This function takes a binary data block and returns a vector of mddTransferEncodings
+void
+getMDDs(int binDataSize, char *binData, int Endianess, vector<HttpServer::MDDEncoding*> &resultVector)
+{
+ char *currentPos;
+ char *stringBuffer;
+ char *binDataBuffer = NULL;
+ r_Long intValue;
+ HttpServer::MDDEncoding *currentMDD;
+ r_Endian::r_Endianness myEndianess = r_Endian::get_endianness();
+
+ //RMInit::logOut << "Starting getMDDs , binDataSize is " << binDataSize << endl;
+
+ stringBuffer = (char*)mymalloc(1024);
+ currentPos = binData;
+ // Examine the whole array...
+ while(currentPos < (binData+binDataSize))
+ {
+ // Create new MDDEncoding object
+ currentMDD = new HttpServer::MDDEncoding();
+ // get objectType
+ memcpy(&intValue, currentPos, sizeof(r_Long));
+ // intValue = *(int *)intValue;
+ if(myEndianess != Endianess)
+ {
+ intValue = r_Endian::swap(intValue);
+ }
+ currentMDD->setObjectType(intValue);
+ currentPos+=4;
+ //RMInit::logOut << "object type is " << intValue << endl;
+
+ // get objectTypeName
+ strcpy(stringBuffer,currentPos);
+ if(strcmp(stringBuffer,"null") != 0)
+ currentMDD->setObjectTypeName(strdup(stringBuffer));
+ currentPos += strlen(stringBuffer) + 1;
+ //RMInit::logOut << "objectTypeName is " << stringBuffer << endl;
+
+ // get typeStructure
+ strcpy(stringBuffer,currentPos);
+ if(strcmp(stringBuffer,"null") != 0)
+ currentMDD->setTypeStructure(strdup(stringBuffer));
+ currentPos += strlen(stringBuffer) + 1;
+ //RMInit::logOut << "typeStructure is " << stringBuffer << endl;
+
+ // get typeLength
+ memcpy(&intValue, currentPos, sizeof(r_Long));
+ //intValue = *(int *)currentPos;
+ if(myEndianess != Endianess)
+ {
+ intValue = r_Endian::swap(intValue);
+ }
+ currentMDD->setTypeLength(intValue);
+ currentPos+=sizeof(r_Long);
+ //RMInit::logOut << "type length is " << intValue << endl;
+
+ // get domain
+ strcpy(stringBuffer,currentPos);
+ if(strcmp(stringBuffer,"null") != 0)
+ currentMDD->setDomain(strdup(stringBuffer));
+ currentPos += strlen(stringBuffer) + 1;
+ //RMInit::logOut << "domain is " << stringBuffer << endl;
+
+ // get tileSize - later this will be the storage_layout
+ strcpy(stringBuffer,currentPos);
+ if(strcmp(stringBuffer,"null") != 0)
+ currentMDD->setTileSize(strdup(stringBuffer));
+ currentPos += strlen(stringBuffer) + 1;
+ //RMInit::logOut << "tileSize is " << stringBuffer << endl;
+ // get oid
+ strcpy(stringBuffer,currentPos);
+ if(strcmp(stringBuffer,"null") != 0)
+ currentMDD->setOID(strdup(stringBuffer));
+ currentPos += strlen(stringBuffer) + 1;
+ //RMInit::logOut << "OID is " << stringBuffer << endl;
+ // get dataSize
+ /* RMInit::logOut << "Byte1: " << (short)*currentPos << endl;
+ RMInit::logOut << "Byte2: " << (short)*(currentPos+1) << endl;
+ RMInit::logOut << "Byte3: " << (short)*(currentPos+2) << endl;
+ RMInit::logOut << "Byte4: " << (short)*(currentPos+3) << endl;*/
+ memcpy(&intValue, currentPos, sizeof(r_Long));
+ //intValue = *(int *)currentPos;
+ if(myEndianess != Endianess)
+ {
+ intValue = r_Endian::swap(intValue);
+ }
+ currentMDD->setDataSize(intValue);
+ currentPos+=sizeof(r_Long);
+ //RMInit::logOut << "Data size is " << intValue << endl;
+
+ // get binData
+ binDataBuffer = (char*)mymalloc(intValue+1);
+ memcpy(binDataBuffer,currentPos,intValue);
+ currentMDD->setBinData(binDataBuffer);
+ currentPos += intValue;
+
+ // Put object into result vector
+ resultVector.insert(resultVector.begin(),currentMDD);
+ }
+ // free Buffer
+ free(stringBuffer);
+
+ //RMInit::logOut << "vector has " << resultVector.size() << " entries." << endl;
+
+}
+
+
+/**********************************************************************
+ * Class MDDEncoding
+ *
+ * IMPORTANT: This class does not copy its parameters for performance reasons!
+ * So the memory allocated for the parameters must not be freed in
+ * the calling functions or methods, this is done by the destructor
+ * of this class!
+ *
+ *********************************************************************/
+HttpServer::MDDEncoding::MDDEncoding()
+{
+ objectType = 0;
+ objectTypeName = NULL;
+ typeStructure = NULL;
+ typeLength = 0;
+ domain = NULL;
+ tileSize = NULL;
+ oidString = NULL;
+ dataSize = 0;
+ binData = NULL;
+ stringRepresentation = (char*)mymalloc(4096);
+};
+
+HttpServer::MDDEncoding::~MDDEncoding()
+{
+ if (objectTypeName != NULL)
+ free(objectTypeName);
+ if (typeStructure != NULL)
+ free(typeStructure);
+ if (domain != NULL)
+ free(domain);
+ if (tileSize != NULL)
+ free(tileSize);
+ if (oidString != NULL)
+ free(oidString);
+ // binData is freed elsewhere!
+ free(stringRepresentation);
+}
+
+void HttpServer::MDDEncoding::setObjectType(int type)
+{
+ objectType = type;
+}
+
+void HttpServer::MDDEncoding::setObjectTypeName(char *name)
+{
+ if(objectTypeName)
+ free(objectTypeName);
+ objectTypeName = name;
+}
+
+void HttpServer::MDDEncoding::setTypeStructure(char *type)
+{
+ if(typeStructure)
+ free(typeStructure);
+ typeStructure = type;
+}
+
+void HttpServer::MDDEncoding::setTypeLength(int len)
+{
+ typeLength = len;
+}
+
+void HttpServer::MDDEncoding::setDomain(char *dom)
+{
+ if(domain)
+ free(domain);
+ domain = dom;
+}
+
+void HttpServer::MDDEncoding::setTileSize(char *size)
+{
+ if(tileSize)
+ free(tileSize);
+ tileSize = size;
+}
+
+void HttpServer::MDDEncoding::setOID(char *o)
+{
+ if(oidString)
+ free(oidString);
+ oidString = o;
+}
+
+void HttpServer::MDDEncoding::setDataSize(int size)
+{
+ dataSize = size;
+}
+
+void HttpServer::MDDEncoding::setBinData(char *data)
+{
+ if(binData)
+ free(binData);
+ binData = data;
+}
+
+const char* HttpServer::MDDEncoding::toString()
+{
+ char *intBuffer = (char*)mymalloc(128);
+
+ strcpy(stringRepresentation,"\n\n MDD information: \n ObjectTypeName: ");
+ strcat(stringRepresentation,objectTypeName);
+ strcat(stringRepresentation,"\n ObjectType: ");
+ sprintf(intBuffer,"%d",objectType);
+ strcat(stringRepresentation,intBuffer);
+ strcat(stringRepresentation,"\n OID: ");
+ strcat(stringRepresentation,oidString);
+ strcat(stringRepresentation,"\n Domain: ");
+ strcat(stringRepresentation,domain);
+ strcat(stringRepresentation,"\n TypeStructure: ");
+ strcat(stringRepresentation,typeStructure);
+ strcat(stringRepresentation,"\n tileSize: ");
+ strcat(stringRepresentation,tileSize);
+ strcat(stringRepresentation,"\n DataSize: ");
+ sprintf(intBuffer,"%d",dataSize);
+ strcat(stringRepresentation,intBuffer);
+
+ free(intBuffer);
+ return stringRepresentation;
+}
+
+
+/*************************************************************************
+ * Method name...: HttpServer() (constructor)
+ ************************************************************************/
+HttpServer::HttpServer()
+{
+ if( actual_httpserver )
+ {
+ std::cerr << "Internal Error: Tried to instantiate more than one HttpServer object." << endl;
+ exit(1);
+ }
+
+ // So that it should be never freed
+ globalClientContext.currentUsers++;
+ actual_httpserver = this;
+ flagInformRasMgr = false;
+ isHttpServer = true;
+}
+
+HttpServer::HttpServer( unsigned long timeOut, unsigned long managementInterval , unsigned long listenPort, char* rasmgrHost, unsigned int rasmgrPort,char* serverName)
+:ServerComm( timeOut, managementInterval, listenPort, rasmgrHost, rasmgrPort,serverName)
+{
+ if( actual_httpserver )
+ {
+ std::cerr << "Internal Error: Tried to instantiate more than one HTTPServer object." << endl;
+ exit(1);
+ }
+
+ actual_httpserver = this;
+
+ flagInformRasMgr = false;
+
+ // So that it should be never freed
+ globalClientContext.currentUsers++;
+
+ isHttpServer = true;
+}
+
+/*************************************************************************
+ * Method name...: ~HttpServer() (destructor)
+ ************************************************************************/
+HttpServer::~HttpServer()
+{
+ // delete communication object
+ if( admin ) delete admin;
+
+ actual_httpserver = 0;
+}
+
+
+
+/*************************************************************************
+ * Method name...: startHttpServer()
+ ************************************************************************/
+void termSignalHandler(int sig);
+
+
+void
+HttpServer::startRpcServer()
+ throw( r_Error )
+{
+ // create administraion object (O2 session is initialized)
+ admin = AdminIf::instance();
+ if( !admin )
+ throw r_Error( r_Error::r_Error_BaseDBMSFailed );
+
+ // simulating command line arguments
+ const char* dummy[] = { "rasserver", "-c", "httpserver.conf" };
+
+ signal (SIGTERM, termSignalHandler);
+ cout << "RasDaMan server "<<serverName<<" is up." << endl;
+ RMInit::logOut << "RasDaMan server "<<serverName<<" is up." << endl;
+
+ doIt_httpserver( 3, const_cast<char**>(dummy));
+
+}
+
+void termSignalHandler(int sig)
+ {
+ static int in_progress=0;
+
+ if (in_progress) return;
+
+ in_progress = 1;
+
+ if(HttpServer::actual_httpserver)
+ {
+ HttpServer::actual_httpserver->stopRpcServer();
+ }
+
+ }
+
+void clearLastClient(); // is down at end of file
+
+
+void
+HttpServer::stopRpcServer()
+{
+ RMInit::logOut << " Shutdown request received." << endl;
+ // RMInit::logOut << "Unregistering interface...";
+ // has to be adapted for HTTP server
+ // svc_unregister( RPCIF, RPCIFVERS );
+ // RMInit::logOut << "ok" << endl;
+
+ RMInit::logOut << "Clearing clients..." << endl;
+
+ clearLastClient();
+ RMInit::logOut << "informing rasmgr..." << endl;
+ informRasMGR(SERVER_DOWN);
+ cout << "rasdaman server " << serverName << " is down." << endl;
+
+ exit(0);
+ // svc_exit();
+}
+
+HttpServer::ClientTblElt*
+HttpServer::getClientContext( unsigned long clientId )
+{
+ // this is a simplification and only works for one client
+ globalClientContext.currentUsers++;
+ return &globalClientContext;
+}
+
+/*************************************************************************
+ * Method name...: printServerStatus( )
+ ************************************************************************/
+void
+HttpServer::printServerStatus( ostream& s )
+{
+ unsigned long currentTime = time(NULL);
+
+ s << endl;
+ s << "HTTP Server state information at " << endl; // << ctime((time_t*)&currentTime) << endl;
+ s << " Transaction active.............: " << ( transactionActive ? "yes" : "no" ) << endl;
+ s << " Max. transfer buffer size......: " << maxTransferBufferSize << " bytes" << endl;
+ s << endl;
+
+ // Purify?
+ /*
+ s << "memory map----------------------------------------------------" << endl;
+
+ // memorymap(1);
+
+ struct mallinfo meminfo = mallinfo();
+
+ s << "space in arena : " << meminfo.arena << endl;
+ s << "number of small blocks : " << meminfo.smblks << endl;
+ s << "number of ordinary blocks : " << meminfo.ordblks << endl;
+ s << "space in free ordinary blocks : " << meminfo.fordblks << endl;
+ s << "space in used ordinary blocks : " << meminfo.uordblks << endl;
+
+ s << "additional space from last call: " << meminfo.uordblks - memUsed << endl;
+
+ memUsed = meminfo.uordblks;
+
+ s << "end memory map------------------------------------------------" << endl << endl;
+ */
+}
+
+//For future, to make this shit nicer
+
+#ifdef LITTLE_ENDIAN
+ const int systemEndianess = 1;
+#else
+ const int systemEndianess = 0;
+#endif
+
+int encodeAckn(char*&result, int ackCode = 99) // 99 is the 'OK', but we have other ack to
+ {
+ result = (char*)mymalloc(1);
+ *result = ackCode;
+ return 1;
+ }
+
+void cleanExecuteQueryRes(ExecuteQueryRes& res) {
+ if(res.typeStructure){
+ free(res.typeStructure);
+ res.typeStructure=NULL;
+ }
+ if(res.token){
+ free(res.token);
+ res.token=NULL;
+ }
+ if(res.typeName){
+ free(res.typeName);
+ res.typeName=NULL;
+ }
+}
+
+int encodeError(char*&result, const r_ULong errorNo, const r_ULong lineNo,const r_ULong columnNo, const char *text)
+ {
+ int totalLength = 14 + strlen(text) + 1;
+ result = (char*)mymalloc(totalLength);
+ char *currentPos = result;
+ // fill it with data
+ *currentPos = 0; // result is error
+ currentPos++;
+ *currentPos = systemEndianess;
+ currentPos++;
+ encodeULong(currentPos, &errorNo);
+ currentPos += sizeof(r_ULong);
+ encodeULong(currentPos, &lineNo);
+ currentPos += sizeof(r_ULong);
+ encodeULong(currentPos, &columnNo);
+ currentPos += sizeof(r_ULong);
+ strcpy(currentPos, text);
+
+ return totalLength;
+ }
+
+//a dirty hack:
+static long lastCallingClientId=-1;
+// this is needed to get a died client lost. Who designed this should do it better
+
+
+long
+HttpServer::processRequest( unsigned long callingClientId, char* baseName, int rascommand,
+ char* query, int binDataSize, char* binData, int Endianess, char*& result, char *capability )
+{
+
+lastCallingClientId=callingClientId;
+
+ //RMInit::logOut << "Start Method Processrequest ... " << endl;
+try
+ { // put to catch all errors which come up here, so HTTP-Server doesn't crush because of them
+
+ long returnValue=0;
+ unsigned short execResult=0;
+ unsigned short dummy=0;
+ ExecuteQueryRes resultError;
+ // needed for result type MDD collection
+ r_Minterval resultDom;
+ char* typeName;
+ char* typeStructure;
+ char* currentPos;
+ r_OId oid;
+ bool valid;
+ unsigned short currentFormat;
+ // vector with mdds in transfer encoding
+ vector<HttpServer::MDDEncoding*> transferredMDDs;
+ Tile* resultTile; // temporary tile with the whole MDD
+ int i;
+ unsigned short objType;
+ r_OId *roid;
+ int totalLength;
+ long l;
+ ClientTblElt* context;
+ // server endianess
+ r_Endian::r_Endianness serverEndian;
+ if(capability)
+ { unsigned long resultCode;
+ resultCode=accessControl.crunchCapability(capability);
+
+ if(resultCode)
+ {
+ flagInformRasMgr = true; // Used in doIt_http...
+
+ return encodeError(result, resultCode,0,0, "");
+ }
+ }
+
+
+ switch (rascommand)
+ {
+ case 1:
+ // commOpenDB
+ // call openDB (userName initialized with "")
+ openDB(callingClientId, baseName, "");
+ return encodeAckn(result);
+ break;
+
+ case 2:
+ // commCloseDB
+ // call closeDB
+ flagInformRasMgr = true; // Used in doIt_http...
+ closeDB(callingClientId);
+ return encodeAckn(result);
+ break;
+
+ case 3:
+ // commBTreadOnly
+ // call beginTA
+ beginTA(callingClientId, 1);
+ return encodeAckn(result);
+ break;
+
+ case 4:
+ // commBTreadWrite
+ // call beginTA
+ beginTA(callingClientId, 0);
+ return encodeAckn(result);
+ break;
+
+ case 5:
+ // commCT
+ // call commitTA
+ commitTA(callingClientId);
+ return encodeAckn(result);
+ break;
+
+ case 6:
+ // commAT
+ // call abortTA
+ abortTA(callingClientId);
+ return encodeAckn(result);
+ break;
+
+ case 7:
+ // commIsOpenTA
+ return encodeAckn(result, (transactionActive==callingClientId) ? 99 : 98);
+ break;
+
+ case 8:
+ // commQueryExec
+ // call executeQuery (result contains error information)
+ resultError.token=NULL;
+ resultError.typeName=NULL;
+ resultError.typeStructure=NULL;
+ execResult = executeQuery(callingClientId, query, resultError);
+ // now we distinguish between different result types
+ if(execResult == 0) {
+ // MDD results
+ int totalLength = 6; // total length of result in bytes
+ r_Long numMDD = 0; // number of MDD objects in the result
+ ClientTblElt* context;
+ vector<Tile*> resultTiles; // contains all TransTiles representing the resulting MDDs
+ resultTiles.reserve(20);
+ vector<char*> resultTypes;
+ resultTypes.reserve(20);
+ vector<char*> resultDomains;
+ resultDomains.reserve(20);
+ vector<r_OId> resultOIDs;
+ resultOIDs.reserve(20);
+ // Here should be something like the following. Unfortunately,
+ // context->transferColl seems to be 0 here. I don't know why.
+ // Thats why a global variable was introduced in
+ // servercomm2.cc.
+ // CollectionType* collectionType =
+ // (CollectionType*) context->transferColl->getMDDCollType();
+ // char* collTypeStructure = collectionType->getTypeStructure();
+
+ while(getNextMDD(callingClientId, resultDom, typeName, typeStructure, oid,
+ currentFormat) == 0) {
+ numMDD++;
+ // create TransTile for whole data from the tiles stored in context->transTiles
+ context = getClientContext( callingClientId );
+ // that should be enough, just transfer the whole thing ;-)
+ resultTile = new Tile( context->transTiles );
+
+ // server endianess
+ r_Endian::r_Endianness serverEndian = r_Endian::get_endianness();
+
+ // This currently represents the one and only client active at one time.
+ // stupid!!! if((context->clientId == 1) && (strcmp(context->clientIdText, ServerComm::HTTPCLIENT) == 0) && (serverEndian != r_Endian::r_Endian_Big))
+ if(serverEndian != r_Endian::r_Endian_Big)
+ {
+ // RMInit::logOut << "Changing endianness..." << flush;
+ // calling client is a http-client(java -> always BigEndian) and server has LittleEndian
+ char *tpstruct;
+ r_Base_Type *useType;
+ tpstruct = resultTile->getType()->getTypeStructure();
+ useType = (r_Base_Type*)(r_Type::get_any_type(tpstruct));
+
+ char* tempT = (char*)mymalloc(sizeof(char) * resultTile->getSize());
+
+ // change the endianness of the entire tile for identical domains for src and dest
+ r_Endian::swap_array(useType, resultDom, resultDom, resultTile->getContents(), tempT);
+ resultTile->setContents(tempT);
+
+ delete useType;
+ free(tpstruct);
+
+ // RMInit::logOut << MSG_OK << endl;
+ }
+
+ resultTiles.push_back(resultTile);
+ resultTypes.push_back(typeStructure);
+ resultDomains.push_back(resultDom.get_string_representation());
+ resultOIDs.push_back(oid);
+ //oid.print_status(RMInit::logOut);
+
+ // this is normally done in getNextTile(). But this is not called, so we do it here.
+ (*(context->transferDataIter))++;
+ if( *(context->transferDataIter) != context->transferData->end() ) {
+ // clean context->transtile if necessary
+ if( context->transTiles ){
+ delete context->transTiles;
+ context->transTiles = 0;
+ }
+ // clean context->tileIter if necessary
+ if( context->tileIter ){
+ delete context->tileIter;
+ context->tileIter = 0;
+ }
+ }
+
+ // clean typeName if necessary
+ if( typeName ){
+ free(typeName);
+ typeName = 0;
+ }
+ }
+
+ // clean typeName if necessary
+ if( typeName ){
+ free(typeName);
+ typeName = 0;
+ }
+
+ // prepare for transfer
+ // calculate total length of the result array
+ for(i = 0; i < numMDD; i++) {
+ totalLength += strlen(resultTypes[i]) + 1;
+ totalLength += strlen(resultDomains[i]) + 1;
+ // OID might be NULL
+ if(resultOIDs[i].get_string_representation() != NULL)
+ totalLength += strlen(resultOIDs[i].get_string_representation()) + 1;
+ else
+ totalLength++;
+ totalLength += resultTiles[i]->getSize();
+ totalLength += 4;
+ }
+ // for the type of the collection
+ totalLength += strlen(globalHTTPSetTypeStructure) + 1;
+
+ // allocate the result
+ result = (char*)mymalloc(totalLength);
+ currentPos = result;
+ // fill it with data
+ *currentPos = 1; // result is MDD collection
+ currentPos++;
+ *currentPos = systemEndianess;
+ currentPos++;
+ // type of the collection
+ strcpy(currentPos, globalHTTPSetTypeStructure);
+ currentPos += strlen(globalHTTPSetTypeStructure) + 1;
+ encodeLong(currentPos, &numMDD);
+ currentPos += sizeof(r_Long);
+ // encode MDDs
+ for(i = 0; i < numMDD; i++) {
+ r_Long dummy = resultTiles[i]->getSize();
+ strcpy(currentPos, resultTypes[i]);
+ currentPos += strlen(resultTypes[i]) + 1;
+ strcpy(currentPos, resultDomains[i]);
+ currentPos += strlen(resultDomains[i]) + 1;
+ // OID might be NULL
+ if(resultOIDs[i].get_string_representation() != NULL)
+ {
+ strcpy(currentPos, resultOIDs[i].get_string_representation());
+ currentPos += strlen(resultOIDs[i].get_string_representation()) + 1;
+ }
+ else
+ {
+ *currentPos = '\0';
+ currentPos++;
+ }
+ encodeLong(currentPos, &dummy);
+ currentPos += sizeof(r_Long);
+ memcpy(currentPos, resultTiles[i]->getContents(), dummy);
+ currentPos += dummy;
+ }
+
+ // delete all the temporary storage
+ for(i = 0; i < numMDD; i++) {
+ delete resultTiles[i];
+ free(resultTypes[i]);
+ free(resultDomains[i]);
+ }
+
+ returnValue = totalLength;
+
+ } else if(execResult == 1) {
+ // the result is a collection of scalars.
+ int totalLength = 6; // total length of result in bytes
+ r_Long numElem = 0; // number of MDD objects in the result
+ ClientTblElt* context;
+ vector<char*> resultElems; // contains all TransTiles representing the resulting MDDs
+ resultElems.reserve(20);
+ vector<unsigned int> resultLengths;
+ resultLengths.reserve(20);
+
+ // we have to get the type of the collection
+ totalLength += strlen(resultError.typeStructure) + 1;
+
+ // then we have to get all elements in the collection
+ unsigned short dummyRes;
+ char* buffer;
+ unsigned int bufferSize;
+ // This will probably not work for empty collections. Only if getNextElement
+ // returns 2 in this case. I really don't get it.
+ unsigned short moreElems = 0;
+
+ while( moreElems == 0 ) {
+ moreElems = getNextElement(callingClientId, buffer, bufferSize);
+
+ //RMInit::logOut << "More elems is " << moreElems << endl;
+ numElem++;
+ resultElems.push_back(buffer);
+ resultLengths.push_back(bufferSize);
+ // length of data
+ totalLength += bufferSize;
+ // this will be length of type
+ totalLength += 1;
+ // size of each element
+ totalLength += sizeof(r_Long);
+ }
+
+ // allocate the result
+ result = (char*)mymalloc(totalLength);
+ currentPos = result;
+ // fill it with data
+ *currentPos = 2; // result is collection of other types
+ currentPos++;
+ *currentPos = systemEndianess;
+ currentPos++;
+ // type of the collection
+ strcpy(currentPos, resultError.typeStructure);
+ currentPos += strlen(resultError.typeStructure) + 1;
+ // number of elements
+ encodeLong(currentPos, &numElem);
+ currentPos += sizeof(r_Long);
+
+ // and finally copy them together
+ for(i = 0; i < numElem; i++) {
+ // This should be the type of the element
+ *currentPos = '\0';
+ currentPos++;
+ // length in bytes of the element
+ r_ULong convDummy = resultLengths[i];
+ encodeULong(currentPos, &convDummy);
+ currentPos += sizeof(r_ULong);
+ // actual data
+ memcpy(currentPos, resultElems[i], resultLengths[i]);
+ currentPos += resultLengths[i];
+ }
+
+ // delete all the temporary storage
+ for(i = 0; i < numElem; i++) {
+ free(resultElems[i]);
+ }
+
+ returnValue = totalLength;
+
+ } else if(execResult == 2) {
+ int totalLength = 7; // total length of result in bytes
+ // the result collection is empty. It is returned as an empty MDD collection.
+ // allocate the result
+ result = (char*)mymalloc(totalLength);
+ currentPos = result;
+ // fill it with data
+ *currentPos = 1; // result is MDD collection
+ currentPos++;
+ *currentPos = systemEndianess;
+ currentPos++;
+ // here the type of the collection should be added, currently empty string!
+ *currentPos = '\0';
+ currentPos++;
+ // now set the number of results to zero
+ r_Long dummy=0;
+ encodeLong(currentPos, &dummy);
+
+ returnValue = totalLength;
+
+ } else if(execResult == 4 || execResult == 5) {
+ // parse error or execution error
+ returnValue = encodeError(result, resultError.errorNo,resultError.lineNo, resultError.columnNo, resultError.token);
+
+ } else {
+ // unknow error
+ returnValue = -10;
+ }
+
+ cleanExecuteQueryRes(resultError);
+
+ // insert error handling here
+ return returnValue;
+ break;
+
+ case 9:
+ // commUpdateExec
+ // empty transfer structures (only to be sure, this case probably cannot occur :-)
+ returnValue = 0;
+ valid = false;
+ while(!transferredMDDs.empty())
+ {
+ RMInit::logOut << "Freeing old transfer structures..." << std::flush;
+ free(transferredMDDs.back()->binData);
+ delete(transferredMDDs.back());
+ transferredMDDs.pop_back();
+ RMInit::logOut << MSG_OK << endl;
+ }
+
+ // do we have an insert statement?
+ if(binDataSize > 0)
+ {
+ // yes, it is an insert statement => analyze and prepare the MDDs
+ // create an empty MDD-Set in the client context
+ initExecuteUpdate(callingClientId);
+
+ // Analyze the binData array (the uploaded mdds)
+ getMDDs(binDataSize,binData,Endianess,transferredMDDs);
+
+ // Store all MDDs
+ //RMInit::logOut << "vector has " << transferredMDDs.size() << " entries." << endl;
+ returnValue = 0;
+ while(!transferredMDDs.empty() && (returnValue == 0))
+ {
+ //RMInit::logOut << "Element:" << transferredMDDs.back()->toString() << endl;
+ // insert MDD into MDD-Set of client context
+ r_Minterval tempStorage(transferredMDDs.back()->domain);
+
+ roid = new r_OId(transferredMDDs.back()->oidString);
+ // OID valid
+ valid = roid->is_valid();
+ if(valid)
+ {
+ // parse the query string to get the collection name
+ char* collection;
+ char* startPtr;
+ char* endPtr;
+ startPtr = endPtr = query;
+ collection = new char[ endPtr - startPtr + 1 ];
+ // one for insert, one for into and one for the collection name
+ for(int i = 0; i<3; i++)
+ {
+ // delete spaces, tabs ...
+ while((*endPtr == ' ' || *endPtr == '\t' || *endPtr == '\r' || *endPtr == '\n') && *endPtr != '\0') endPtr++;
+ startPtr = endPtr;
+ // parse next word
+ while(*endPtr != ' ' && *endPtr != '\t' && *endPtr != '\r' && *endPtr != '\n' && *endPtr != '\0') endPtr++;
+ if(endPtr - startPtr >= 1)
+ {
+ collection = new char[endPtr - startPtr + 1];
+ strncpy(collection, startPtr, endPtr - startPtr);
+ collection[endPtr - startPtr] = '\0';
+ }
+ }
+ //RMInit::logOut << "collection: " << collection << endl;
+
+ //RMInit::logOut << "OID is valid: " << endl;
+ //roid->print_status(RMInit::logOut);
+ execResult = startInsertPersMDD( callingClientId, collection, tempStorage,
+ transferredMDDs.back()->typeLength,
+ transferredMDDs.back()->objectTypeName, *roid);
+ }
+ // OID not valid
+ else
+ {
+ //RMInit::logOut << "OID is NOT valid" << endl;
+
+ execResult = startInsertTransMDD( callingClientId, tempStorage,
+ transferredMDDs.back()->typeLength,
+ transferredMDDs.back()->objectTypeName );
+ }
+
+ //clean roid, we don't needed anymore
+ if(roid) {
+ delete roid;
+ roid = NULL;
+ }
+
+ if(execResult != 0)
+ {
+ // no or wrong mdd type - return error message
+ unsigned long errNo;
+ if(strlen(transferredMDDs.back()->objectTypeName) < 1)
+ errNo=966;
+ else
+ {
+ switch(execResult)
+ {
+ case 2:
+ errNo = 965;
+ break;
+ case 3:
+ errNo = 959;
+ break;
+ case 4:
+ errNo = 952;
+ break;
+ case 5:
+ errNo = 957;
+ break;
+ default:
+ errNo = 350;
+ }
+ RMInit::logOut << "Error: while inserting MDD" << endl;
+ }
+
+ returnValue = encodeError(result, errNo, 0, 0, transferredMDDs.back()->objectTypeName);
+
+ //clean up
+ while(!transferredMDDs.empty())
+ {
+ RMInit::logOut << "Freeing old transfer structures..." << std::flush;
+ free(transferredMDDs.back()->binData);
+ delete(transferredMDDs.back());
+ transferredMDDs.pop_back();
+ RMInit::logOut << MSG_OK << endl;
+ }
+
+
+
+ return returnValue;
+ }
+ else
+ {
+ // create RPCMarray data structure - formats are currently hardcoded (r_Array)
+ RPCMarray *rpcMarray = (RPCMarray*)mymalloc( sizeof(RPCMarray) );
+ rpcMarray->domain = strdup(transferredMDDs.back()->domain);
+ rpcMarray->cellTypeLength = transferredMDDs.back()->typeLength;
+ rpcMarray->currentFormat = r_Array;
+ rpcMarray->storageFormat = r_Array;
+ rpcMarray->data.confarray_len = transferredMDDs.back()->dataSize;
+ rpcMarray->data.confarray_val = transferredMDDs.back()->binData;
+
+ /*
+ RMInit::logOut << "Creating RPCMarray with domain " << rpcMarray->domain << ", size " <<
+ rpcMarray->data.confarray_len << ", typeLength " << rpcMarray->cellTypeLength << " ..."
+ << flush;
+ */
+
+ // split tile if a tileSize (an MInterval) has been specified
+ r_Minterval* splitInterval = NULL;
+ if(transferredMDDs.back()->tileSize != NULL)
+ {
+ splitInterval = new r_Minterval(transferredMDDs.back()->tileSize);
+ RMInit::logOut << "Splitinterval is " << splitInterval << endl;
+ }
+ // now insert the tile(s)
+ if(valid)
+ {
+ insertTileSplitted( callingClientId, 1, rpcMarray, splitInterval );
+ }
+ else
+ {
+ insertTileSplitted( callingClientId, 0, rpcMarray, splitInterval );
+ }
+
+ // free the stuff
+ free(rpcMarray->domain);
+ free(rpcMarray);
+ delete(transferredMDDs.back());
+ transferredMDDs.pop_back();
+ delete(splitInterval);
+ }
+ }
+
+ // end insertion into client structure
+ if(valid)
+ endInsertMDD(callingClientId, 1);
+ else
+ endInsertMDD( callingClientId, 0 );
+ }
+
+ if(returnValue == 0)
+ {
+ //RMInit::logOut << "Executing query: " << query << flush;
+ // until now now error has occurred => execute the query
+ ExecuteUpdateRes returnStructure;
+ returnStructure.token=NULL;
+ if(!valid)
+ execResult = executeUpdate( callingClientId, (const char*)query , returnStructure );
+ // query was executed successfully
+ if (execResult == 0) {
+ // allocate the result
+ result = (char*)mymalloc(1);
+ currentPos = result;
+ *currentPos = 99; // result is an acknowledgement
+ returnValue = 1;
+ }
+ // parsing or execution error
+ else if( execResult == 2 || execResult == 3 ) {
+ returnValue = encodeError(result, returnStructure.errorNo,returnStructure.lineNo, returnStructure.columnNo, returnStructure.token);
+ }
+ else {
+ // unknow error
+ returnValue = -10;
+ }
+
+ if(returnStructure.token) {
+ free(returnStructure.token);
+ returnStructure.token=NULL;
+ }
+ }
+ return returnValue;
+ break;
+ case 10:
+ // getnewoid
+ accessControl.wantToWrite();
+ objType = 1;
+ roid = new r_OId();
+ ServerComm::getNewOId(lastCallingClientId, objType, *roid);
+ //roid->print_status(RMInit::logOut);
+
+ // prepare returnValue
+ totalLength = 9; // total length of result in bytes
+ totalLength += strlen(roid->get_system_name()) + 1;
+ totalLength += strlen(roid->get_base_name()) + 1;
+ // allocate the result
+ result = (char*)mymalloc(totalLength);
+ currentPos = result;
+ // fill it with data
+ *currentPos = 4; // result is a OID
+ currentPos++;
+
+ // system
+ strcpy(currentPos, roid->get_system_name());
+ currentPos += strlen(roid->get_system_name()) + 1;
+
+ // base
+ strcpy(currentPos, roid->get_base_name());
+ currentPos += strlen(roid->get_base_name()) + 1;
+
+
+ context = getClientContext( callingClientId );
+ // server endianess
+ serverEndian = r_Endian::get_endianness();
+ // This currently represents the one and only client active at one time.
+ if((context->clientId == 1) &&
+ (strcmp(context->clientIdText, ServerComm::HTTPCLIENT) == 0) &&
+ (serverEndian != r_Endian::r_Endian_Big))
+ {
+ // calling client is a http-client(java -> always BigEndian) and server has LittleEndian
+ double tmp = roid->get_local_oid();
+ *(double*)currentPos = r_Endian::swap(tmp);
+ }
+ else
+ *(double*)currentPos = roid->get_local_oid();
+ //currentPos += 8;
+ returnValue = totalLength;
+
+ //clean up we don't need roid anymore
+ if(roid) {
+ delete roid;
+ roid=NULL;
+ }
+
+ return returnValue;
+ break;
+ default:
+ return -10;
+ break;
+ }
+ }
+ catch(r_Eno_permission &e) // this shouldn't be here, but ...
+ {
+ return encodeError(result, e.get_errorno(),0,0, "");
+ }
+ catch(...)
+ {
+ // really? flagInformRasMgr = true; // client should ask for a new server
+
+ return encodeError(result, UNEXPECTED_INTERNAL_ERROR,0,0, "");
+ }
+
+}
+
+//**********************************************************************
+
+#include "raslib/error.hh"
+#include "raslib/rminit.hh"
+
+#include "httpserver/defs.h"
+#include "httpserver/protos.h"
+#include "httpserver/types.h"
+#include "httpserver/server.h"
+
+
+extern struct ServerBase Server;
+
+extern struct Logging *LogBase;
+
+void Select(int socket); // wrap around to put timeout in it
+
+int HttpServer::doIt_httpserver( int argc, char *argv[] )
+{
+ pid_t ChildPId; /* -> Server.ChildInfo */
+
+ RMInit::logOut << "Initialising parameters for HTTP server... " << endl;
+ RMInit::logOut.flush();
+ Initialize( argc, argv, &Server );
+
+ RMInit::logOut << "Initialising server socket for HTTP server... " << endl;
+ RMInit::logOut.flush();
+ listen( Server.SockFD, 5 );
+ RMInit::logOut << "Waiting for client calls... " << endl;
+ RMInit::logOut.flush();
+
+ informRasMGR(SERVER_AVAILABLE);
+
+ for(;;)
+ {
+ Select( Server.SockFD);
+ Accept( Server.SockFD, &Server.Client );
+ strcpy( Server.Client.Host.IPAddrString, inet_ntoa( Server.Client.Socket.sin_addr ) );
+
+ if( Server.Client.Host.IPAddrString == NULL )
+ strcpy( Server.Client.Host.IPAddrString, "0.0.0.0" );
+
+ Server.Client.Host.IPAddress = inet_addr( Server.Client.Host.IPAddrString );
+ Server.Client.Comm.ConnStatus = CONN_UNDEFINED;
+ InitHTTPMsg( &Server.Client.Response );
+ InitReqInfo( &Server.Client.Request );
+ LogMsg( LG_SERVER, INFO, "INFO: ====== Connection from %s accepted...",
+ Server.Client.Host.IPAddrString );
+
+ HandleRequest( &Server.Client );
+ LogMsg( LG_SERVER, INFO, "INFO: ====== EOT. Disconnecting." );
+
+ close( Server.Client.SockFD );
+
+ if(flagInformRasMgr == true)
+ { informRasMGR(SERVER_AVAILABLE);
+ flagInformRasMgr = false;
+ }
+
+#ifdef PURIFY
+ purify_printf( "Request finished." );
+ purify_new_leaks();
+#endif
+
+ }
+ // otherwise Exit(OK) should have been called
+ return -1;
+}
+
+extern int noTimeOut;
+void Select(int socket)
+ {
+ static time_t lastEntry =0; // last time we entered here
+
+ fd_set read_fd_set, http_fd_set;
+
+ FD_ZERO(&http_fd_set);
+ FD_SET(socket,&http_fd_set);
+
+ const int checkTimeOutInterval=30;
+
+ struct timeval timeout;
+ timeout.tv_sec=checkTimeOutInterval;
+ timeout.tv_usec=0 ;
+
+ lastEntry = time(NULL);
+ while(1)
+ { read_fd_set=http_fd_set;
+ //cout<<"HTTP Server is waiting..."<<endl;
+ timeout.tv_sec=checkTimeOutInterval;
+ timeout.tv_usec=0;
+
+ int rasp=select(FD_SETSIZE,&read_fd_set,NULL,NULL,&timeout);
+ //cout<<"rasp="<<rasp<<endl;
+ if(rasp>0)
+ {
+ break; // means client call
+ }
+
+ if(rasp<=0)
+ {
+ if(accessControl.isClient()==false)
+ { // regularly tell the rasmgr that we are available. There is a scenario for DoS-attack (or bug, or firewall-problem)
+ // when a client allocates itself a server and never calls, so the server is not usable any more.
+ // but we have to find a smarter way of doing this, we need rasmgr-rasserver communication!
+ ServerComm::actual_servercomm->informRasMGR(SERVER_REGULARSIG);
+ }
+
+ //cout<<"Timeout...noTimeout="<<noTimeOut<<endl; // or a signal
+ //unsigned long clientTimeout=(ServerComm::actual_servercomm)->clientTimeout;
+ //cout<<"clientTimeout="<<clientTimeout<<" have Client="<<accessControl.isClient()<<endl;
+
+ if(!noTimeOut && lastCallingClientId !=-1)
+ {
+ time_t now=time(NULL);
+ unsigned long clientTimeOut=(ServerComm::actual_servercomm)->clientTimeout;
+ if((now - lastEntry) > clientTimeOut && accessControl.isClient())
+ {
+ RMInit::logOut <<"Timeout: after " << clientTimeOut << ", freeing client "<<lastCallingClientId<< "..." << std::flush;
+ ServerComm *sc=ServerComm::actual_servercomm;
+ ServerComm::ClientTblElt *clnt= sc-> getClientContext( lastCallingClientId );
+ clnt->transaction.abort();
+ clnt->database.close();
+ sc->informRasMGR(SERVER_AVAILABLE);
+ // cout<<"Http server, client timeout, available again..."<<endl;
+
+ RMInit::logOut << MSG_OK << endl;
+ }
+ }
+
+ }
+ }
+
+ }
+
+// used at exit, but put here for some compiling reason
+void clearLastClient()
+ {
+ if(accessControl.isClient())
+ {
+ RMInit::logOut << "Freeing client " << lastCallingClientId << "..." << std::flush;
+ ServerComm *sc=ServerComm::actual_servercomm;
+ ServerComm::ClientTblElt *clnt= sc-> getClientContext( lastCallingClientId );
+ clnt->transaction.abort();
+ clnt->database.close();
+ RMInit::logOut << MSG_OK << endl;
+ }
+ }
+
diff --git a/servercomm/httpserver.hh b/servercomm/httpserver.hh
new file mode 100644
index 0000000..47d64ba
--- /dev/null
+++ b/servercomm/httpserver.hh
@@ -0,0 +1,173 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: httpserver.hh
+ *
+ * MODULE: servercomm
+ * CLASS: HttpServer
+ *
+ * COMMENTS:
+ * No Comments
+*/
+
+#ifndef _HTTPSERVER_
+#define _HTTPSERVER_
+
+#include "servercomm/servercomm.hh"
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The class HttpServer describes the one and only server communication object
+ that can exist in a RasDaMan server. It manages listening for clients and
+ maps incoming calls to the respective procedures (which reside in the
+ file manager.cc).
+
+ This class implements the functions useful for HTTP communication
+ and is based on a copy of servercomm.hh (Version 1.48).
+*/
+
+
+class HttpServer : public ServerComm
+{
+public:
+
+ /// the class represents an MDD in HTTP transfer encoding
+ class MDDEncoding
+ {
+ public:
+
+ int objectType;
+ char *objectTypeName;
+ char *typeStructure;
+ int typeLength;
+ char *domain;
+ char *tileSize;
+ char *oidString;
+ int dataSize;
+ char *binData;
+ char *stringRepresentation;
+
+ /// default constructor
+ MDDEncoding();
+
+ /// destructor
+ ~MDDEncoding();
+
+ // set objectType
+ void setObjectType(int type);
+
+ // set objectTypeName
+ void setObjectTypeName(char *name);
+
+ // set typeStructure
+ void setTypeStructure(char* type);
+
+ // set typeLength
+ void setTypeLength(int len);
+
+ // set domain
+ void setDomain(char *dom);
+
+ // set oid
+ void setOID(char *o);
+
+ // set tile size
+ void setTileSize(char *size);
+
+ // set dataSize
+ void setDataSize(int size);
+
+ // set binData
+ void setBinData(char *data);
+
+ // print Values
+ const char* toString();
+ };
+
+
+ /// stores a pointer to the actual servercomm object, only one can exist at a time
+ static HttpServer* actual_httpserver;
+
+ // the class uses the class ClientTblElt from ServerComm because it is used
+ // in some other files of the server, e.g., qlparser/qtmddaccess.cc or
+ // qlparser/qtcommand.cc or qlparser/qtinsert.cc all include servercomm.hh
+
+ /// default constructor
+ HttpServer();
+
+ // the acual constructor
+ HttpServer( unsigned long timeOut, unsigned long managementInterval , unsigned long listenPort, char* rasmgrHost, unsigned int rasmgrPort,char* serverName);
+
+ /// destructor
+ virtual ~HttpServer();
+
+ /// forces the server to listen for client calls
+ virtual void startRpcServer() throw( r_Error );
+
+ /// stops the server
+ virtual void stopRpcServer();
+
+ /// print server status to {\tt s}
+ virtual void printServerStatus( ostream& s=cout );
+
+ /// Executes a retrieval query and prepare the result for HTTP transer.
+ virtual long processRequest( unsigned long callingClientId, char* baseName,
+ int rascommand, char* query, int binDataSize, char *binData,
+ int Endianess, char* &result, char *capability );
+ /**
+ Executes a query and prepares the complete result for transfer via
+ HTTP. The length of the result is returned. The first parameter is
+ the unique client id for which the query should be executed. The
+ second parameter The third parameter is the query itself represented
+ as a string. {\tt result} will contain a pointer to the result as
+ needed for HTTP transfer. This pointer has to be freed by the caller
+ using free.
+
+ Return values on Error:
+ \begin{tabular}{lll}
+ -1 && parse errror\\
+ -2 && execution error\\
+ -3 && unknown error\\
+ \end{tabular}
+
+ Question: How to transfer the result?
+ */
+
+ /// returns a pointer to the context of the calling client, 0 it there is no context
+ virtual ClientTblElt* getClientContext( unsigned long ClientId );
+ /**
+ Returns a pointer to the context of the calling client. Currently always
+ the same global context is returned.
+ */
+ private:
+ int doIt_httpserver( int argc, char *argv[] );
+
+
+ bool flagInformRasMgr; // used to trigger informRasMGR(SERVERAVAILABLE)
+
+};
+
+#include "httpserver.icc"
+
+#endif
diff --git a/servercomm/httpserver.icc b/servercomm/httpserver.icc
new file mode 100644
index 0000000..d1b00bd
--- /dev/null
+++ b/servercomm/httpserver.icc
@@ -0,0 +1,31 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INLINE SOURCE: httpserver.icc
+ *
+ * MODULE: servercomm
+ * CLASS: ServerComm
+ *
+ * COMMENTS:
+ * No Comments
+*/
diff --git a/servercomm/manager.cc b/servercomm/manager.cc
new file mode 100644
index 0000000..8177919
--- /dev/null
+++ b/servercomm/manager.cc
@@ -0,0 +1,1885 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: manager.cc
+ *
+ * MODULE: servercomm
+ * CLASS: -
+ *
+ * COMMENTS:
+ * No Comments
+*/
+
+#include "mymalloc/mymalloc.h"
+static const char rcsid[] = "@(#)manager, ServerComm: $Id: manager.cc,v 1.92 2005/09/03 21:05:14 rasdev Exp $";
+
+#include <iostream>
+using namespace std;
+
+#include <string.h> // for strcat()
+#include <time.h> // for time()
+#include <malloc.h>
+
+// server option for switching off garbageCollection (Formerly there were problems
+// because of illegal functions called in signal handler, see man 5 attributes;
+// these are no longer relevant since the introduction of the CallBackManager)
+extern int noTimeOut;
+
+
+// Put it in front of any typedef bool ... because o2 is using bool as a variable.
+// #include "o2template_CC.hxx"
+
+#include <signal.h> // for signal()
+#include <unistd.h> // for alarm()
+
+#ifndef SOLARIS
+ #define PORTMAP // define to use function declarations for old interfaces
+ #include <rpc/rpc.h>
+#else // HPUX
+ #include <rpc/rpc.h>
+#endif
+
+#ifndef _RPCIF_
+ #define _RPCIF_
+ #include "clientcomm/rpcif.h"
+#endif
+
+#include "raslib/rmdebug.hh"
+#include "raslib/minterval.hh"
+#include "raslib/oid.hh"
+#include "raslib/endian.hh"
+
+#include "servercomm/servercomm.hh"
+
+
+extern "C" {
+void garbageCollection( int );
+void garbageCollectionDummy ( int );
+}
+
+
+//
+// Section for global variables pointing to RPC return data.
+//
+static GetExtendedErrorInfo rpcExtendedErrorInfo = { 0, 0};
+static ServerVersionRes rpcServerVersionRes = { 0, 0};
+static u_short rpcDummy = 0;
+static OpenDBRes rpcOpenDBRes = { 0, 0};
+
+static ServerStatRes rpcServerStatRes = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, { 0, 0 } };
+static ExecuteQueryRes rpcExecuteQueryRes = { 0, 0, 0, 0, 0, 0, 0 };
+static GetMDDRes rpcGetMDDRes = { 0, 0, 0, 0, 0 };
+static GetElementRes rpcGetElementRes = { 0, { 0, 0 } };
+static GetTileRes rpcGetTileRes = { 0, 0 };
+static ExecuteUpdateRes rpcExecuteUpdateRes = { 0, 0, 0, 0, 0 };
+static GetCollRes rpcGetCollRes = { 0, 0, 0, 0, 0 };
+static GetCollOIdsRes rpcGetCollOidsRes = { 0, 0, 0, 0, 0, { 0, 0 } };
+static OIdRes rpcOidRes = { 0, 0 };
+static GetTypeStructureRes rpcGetTypeStructureRes = { 0, 0 };
+static ObjectTypeRes procResult = { 0, 0 };
+
+extern char *secureResultBufferForRPC;
+
+void freeDynamicRPCData()
+{
+ // rpcserverstat
+ if( rpcServerStatRes.clientTable.clientTable_len )
+ {
+ for( int i=0; i<rpcServerStatRes.clientTable.clientTable_len; i++ )
+ {
+ free( rpcServerStatRes.clientTable.clientTable_val[i].clientIdText );
+ free( rpcServerStatRes.clientTable.clientTable_val[i].userName );
+ free( rpcServerStatRes.clientTable.clientTable_val[i].baseName );
+ }
+
+ free( rpcServerStatRes.clientTable.clientTable_val );
+
+ rpcServerStatRes.clientTable.clientTable_len = 0;
+ rpcServerStatRes.clientTable.clientTable_val = 0;
+ }
+
+ // rpcexecutequery
+ if( rpcExecuteQueryRes.token ) free( rpcExecuteQueryRes.token );
+ if( rpcExecuteQueryRes.typeName ) free( rpcExecuteQueryRes.typeName );
+ if( rpcExecuteQueryRes.typeStructure ) free( rpcExecuteQueryRes.typeStructure );
+ rpcExecuteQueryRes.token = 0;
+ rpcExecuteQueryRes.status = 0;
+ rpcExecuteQueryRes.errorNo = 0;
+ rpcExecuteQueryRes.lineNo = 0;
+ rpcExecuteQueryRes.columnNo = 0;
+ rpcExecuteQueryRes.typeName = 0;
+ rpcExecuteQueryRes.typeStructure = 0;
+
+ // rpcgetnextmdd, rpcgetmddbyoid
+ if( rpcGetMDDRes.domain ) free( rpcGetMDDRes.domain );
+ if( rpcGetMDDRes.typeName ) free( rpcGetMDDRes.typeName );
+ if( rpcGetMDDRes.typeStructure ) free( rpcGetMDDRes.typeStructure );
+ if( rpcGetMDDRes.oid ) free( rpcGetMDDRes.oid );
+ rpcGetMDDRes.typeStructure = 0;
+ rpcGetMDDRes.typeName = 0;
+ rpcGetMDDRes.domain = 0;
+ rpcGetMDDRes.oid = 0;
+
+ // rpcgetnextelement
+ if( rpcGetElementRes.data.confarray_val ) free( rpcGetElementRes.data.confarray_val );
+ rpcGetElementRes.data.confarray_val = 0;
+
+ // rpcgetnexttile
+ if( rpcGetTileRes.marray )
+ {
+ if( rpcGetTileRes.marray->domain ) free( rpcGetTileRes.marray->domain );
+ // if( rpcGetTileRes.marray->data ) free( rpcGetTileRes.marray->data );
+ free( rpcGetTileRes.marray );
+ rpcGetTileRes.marray = 0;
+ }
+
+ // rpcexecuteupdate
+ if( rpcExecuteUpdateRes.token ) free( rpcExecuteUpdateRes.token );
+ rpcExecuteUpdateRes.token = 0;
+ rpcExecuteUpdateRes.status = 0;
+ rpcExecuteUpdateRes.errorNo = 0;
+ rpcExecuteUpdateRes.lineNo = 0;
+ rpcExecuteUpdateRes.columnNo = 0;
+
+ // rpcgetcollbyname, rpcgetcollbyoid
+ if( rpcGetCollRes.typeName ) free( rpcGetCollRes.typeName );
+ if( rpcGetCollRes.typeStructure ) free( rpcGetCollRes.typeStructure );
+ if( rpcGetCollRes.oid ) free( rpcGetCollRes.oid );
+ if( rpcGetCollRes.collName ) free( rpcGetCollRes.collName );
+ rpcGetCollRes.oid = 0;
+ rpcGetCollRes.typeStructure = 0;
+ rpcGetCollRes.typeName = 0;
+ rpcGetCollRes.collName = 0;
+
+ // rpcgetcolloidsbyname, rpcgetcolloidsbyoid
+ if( rpcGetCollOidsRes.typeName ) free( rpcGetCollOidsRes.typeName );
+ if( rpcGetCollOidsRes.typeStructure ) free( rpcGetCollOidsRes.typeStructure );
+ if( rpcGetCollOidsRes.oid ) free( rpcGetCollOidsRes.oid );
+ if( rpcGetCollOidsRes.collName ) free( rpcGetCollOidsRes.collName );
+ rpcGetCollOidsRes.oid = 0;
+ rpcGetCollOidsRes.typeStructure = 0;
+ rpcGetCollOidsRes.typeName = 0;
+ rpcGetCollOidsRes.collName = 0;
+
+ if( rpcGetCollOidsRes.oidTable.oidTable_len )
+ {
+ for( int i=0; i<rpcGetCollOidsRes.oidTable.oidTable_len; i++ )
+ free( rpcGetCollOidsRes.oidTable.oidTable_val[i].oid );
+
+ free( rpcGetCollOidsRes.oidTable.oidTable_val );
+
+ rpcGetCollOidsRes.oidTable.oidTable_len = 0;
+ rpcGetCollOidsRes.oidTable.oidTable_val = 0;
+ }
+
+ // rpcgetnewoid
+ if( rpcOidRes.oid ) free( rpcOidRes.oid );
+ rpcOidRes.oid = 0;
+
+ // rpcgettypestructure
+ if( rpcGetTypeStructureRes.typeStructure ) free( rpcGetTypeStructureRes.typeStructure );
+ rpcGetTypeStructureRes.typeStructure = 0;
+
+ // execute all pending callbacks. Redirect alarm signal first to make sure no
+ // reentrancy is possible!
+ signal( SIGALRM, garbageCollectionDummy );
+ ServerComm::actual_servercomm->callback_mgr.executePending();
+ signal( SIGALRM, garbageCollection );
+}
+
+
+/*************************************************************
+ *
+ *
+ * SOURCE: manager.cc
+ *
+ * MODULE: servercomm
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#ifdef LINUX
+#define RPCFUNCTIONDEF(name, param) name##_svc( param, struct svc_req* )
+#define RPCFUNCTIONDEFP(name, param) *name##_svc( param, struct svc_req* )
+#else
+#define RPCFUNCTIONDEF(name, param) name##_svc( param, struct svc_req* )
+#define RPCFUNCTIONDEFP(name, param) *name##_svc( param, struct svc_req* )
+#endif
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/**
+ The global remote procedure \Ref{rpcgetserverversion_1} is called by a client to determine
+ version numbers of the server.
+*/
+
+ServerVersionRes*
+RPCFUNCTIONDEF( rpcgetserverversion_1, int* )
+{
+ freeDynamicRPCData();
+
+ rpcServerVersionRes.serverVersionNo = RMANVERSION / 1000.0;
+ rpcServerVersionRes.rpcInterfaceVersionNo = RPCVERSION / 1000.0;
+
+ return &rpcServerVersionRes;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/**
+ The global remote procedure \Ref{rpcshutdown_1} is called by a client to shut
+ down the server.
+*/
+
+unsigned short*
+RPCFUNCTIONDEF( rpcshutdown_1, int* )
+{
+ rpcDummy = 0;
+ freeDynamicRPCData();
+ // we don't allow the client to shut down the server. This is done thru rasmgr
+ // may be is would be better to redesign this server interface and drop several
+ // functions
+ return &rpcDummy;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/**
+ The global remote procedure \Ref{rpcServerStat_1} is called by a clientcomm
+ object on the client system to display server statistics.
+*/
+
+ServerStatRes*
+RPCFUNCTIONDEF( rpcserverstat_1, int* )
+{
+ secureResultBufferForRPC = (char*)&rpcServerStatRes;
+
+ freeDynamicRPCData();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // log server status
+#ifdef RMANDEBUG
+ sc->printServerStatus( RMInit::dbgOut );
+#endif
+
+ // get server status
+ sc->getServerStatus( rpcServerStatRes );
+
+ return &rpcServerStatRes;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/**
+ The global remote procedure \Ref{rpckilltableentry_1} is called by a clientcomm
+ object on the client system to kill a specific client table entry on the server.
+*/
+
+unsigned short*
+RPCFUNCTIONDEF( rpckilltableentry_1, unsigned long* killId )
+{
+ secureResultBufferForRPC = (char*)&rpcDummy;
+ rpcDummy = 0;
+ unsigned long kId = *killId;
+
+ freeDynamicRPCData();
+
+ accessControl.wantToWrite();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ RMInit::logOut << " Kill specific table entry request received for client ID " << kId << "." << endl;
+
+ if( sc && !sc->clientTbl.empty() )
+ {
+
+ list<ServerComm::ClientTblElt*>::iterator iter;
+ iter = sc->clientTbl.begin();
+
+ while ( *iter != NULL )
+ {
+ if( (*iter)->clientId == kId )
+ {
+ RMInit::logOut << "ID " << (*iter)->clientId << " found, deleting..." << endl;
+
+ sc->deleteClientTblEntry( (*iter)->clientId );
+
+ // if this dead client has locked the transaction semaphor, unlock it
+ if( sc->transactionActive == kId )
+ sc->transactionActive = 0;
+
+ // client IDs are unique, so this was the only one...
+ break;
+ }
+ else
+ iter++;
+ }
+ // The following is a necessary dummy command for ONC RPC for not
+ // misinterpreting the above break command as a return
+ iter = sc->clientTbl.begin();
+ }
+return &rpcDummy;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/**
+*/
+
+unsigned short*
+RPCFUNCTIONDEF( rpcalive_1, unsigned long* callingClientId )
+{
+ secureResultBufferForRPC = (char*)&rpcDummy;
+ rpcDummy = 0;
+ unsigned long cci = *callingClientId;
+
+ freeDynamicRPCData();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ rpcDummy = sc->aliveSignal( cci );
+
+ // Return the result
+ return &rpcDummy;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The global remote procedure {\tt rpcopendb_1()} is called by a clientcomm
+ object on the client system to open a database on a RasDaMan server.
+*/
+
+OpenDBRes*
+RPCFUNCTIONDEF( rpcopendb_1, OpenDBParams* params )
+{
+ secureResultBufferForRPC = (char*)&rpcOpenDBRes;
+
+ unsigned long* clientId = new unsigned long;
+
+ freeDynamicRPCData();
+
+ char client[256];
+ client[0] = '\0';
+ strcat( client, "unknown" );
+
+ const char* dbName = params->dbName;
+ const char* userName = params->userName;
+
+ RMInit::logOut << "Client called ... ";
+
+ //
+ // Create a new entry in the client table (should be moved to ServerComm):
+ //
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Create a new client table element and initialize it.
+ ServerComm::ClientTblElt* contextStore;
+ contextStore = new ServerComm::ClientTblElt( client, ++(sc->clientCount) );
+
+ // give the client id back to to client via the pointer variable
+ *clientId = sc->clientCount;
+ // Put the context information in the static control list
+ sc->clientTbl.push_back( contextStore );
+
+ // RMInit::logOut << "assigned id " << *clientId << endl;
+
+ // check acces permission
+
+ rpcOpenDBRes.status=accessControl.crunchCapability(params->capability);
+ //
+ // Open the database: (only if acces control is OK)
+ //
+ if(rpcOpenDBRes.status==0)
+ rpcOpenDBRes.status = sc->openDB( *clientId, dbName, userName );
+
+ rpcOpenDBRes.clientID = *clientId;
+ delete clientId;
+
+ // If database is not successfully opened, the client table entry is deleted again.
+ if( rpcOpenDBRes.status != 0 )
+ sc->deleteClientTblEntry( rpcOpenDBRes.clientID );
+
+ return &rpcOpenDBRes;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The global remote procedure {\tt rpcclosedb_1()} is called by a clientcomm
+ object on the client system to close a database on a RasDaMan server.
+*/
+
+unsigned short*
+RPCFUNCTIONDEF( rpcclosedb_1, unsigned long* callingClientId )
+{
+ secureResultBufferForRPC = (char*)&rpcDummy;
+
+ unsigned long cci;
+ cci = *callingClientId;
+
+ freeDynamicRPCData();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ rpcDummy = sc->closeDB( cci );
+
+ if( rpcDummy == 0 )
+ sc->deleteClientTblEntry( cci );
+
+ return &rpcDummy;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The global remote procedure {\tt rpccreatedb_1()} is called by a clientcomm
+ object on the client system to create a database on a RasDaMan server.
+*/
+unsigned short*
+RPCFUNCTIONDEF( rpccreatedb_1, char** name )
+{
+ secureResultBufferForRPC = (char*)&rpcDummy;
+
+ char* dbname = *name;
+
+ freeDynamicRPCData();
+
+ accessControl.wantToWrite();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method. (createDB doesn't actually return something
+ // other than 0, so this can be used in later extensions)
+ rpcDummy = sc->createDB( dbname );
+
+ // Return the result
+ return &rpcDummy;
+}
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The global remote procedure {\tt rpcdestroydb_1()} is called by a clientcomm
+ object on the client system to destroy a database on a RasDaMan server.
+*/
+unsigned short*
+RPCFUNCTIONDEF( rpcdestroydb_1, char** name )
+{
+ secureResultBufferForRPC = (char*)&rpcDummy;
+
+ char* dbname = *name;
+
+ freeDynamicRPCData();
+
+ accessControl.wantToWrite();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method. (createDB doesn't actually return something
+ // other than 0, so this can be used in later extensions)
+ rpcDummy = sc->destroyDB( dbname );
+
+ // Return the result
+ return &rpcDummy;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The global remote procedure {\tt rpcBeginTA()} is called by a clientcomm
+ object on the client system to begin a new transaction in a session with
+ a RasDaMan server.
+*/
+
+unsigned short*
+RPCFUNCTIONDEF( rpcbeginta_1, BeginTAParams* params )
+{
+ secureResultBufferForRPC = (char*)&rpcDummy;
+
+ freeDynamicRPCData();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // check acces permission
+ rpcDummy = accessControl.crunchCapability(params->capability);
+
+ // Call the corresponding method. (only if acces control is OK)
+ if(rpcDummy==0)
+ rpcDummy = sc->beginTA( params->clientID, params->readOnly );
+
+ // Return the result
+ return &rpcDummy;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The global remote procedure {\tt rpcCommitTA()} is called by a clientcomm
+ object on the client system to commit the current transaction in a session with
+ a RasDaMan server.
+*/
+
+unsigned short*
+RPCFUNCTIONDEF( rpccommitta_1, unsigned long* callingClientId )
+{
+ secureResultBufferForRPC = (char*)&rpcDummy;
+
+ unsigned long cci;
+ cci = *callingClientId;
+
+ freeDynamicRPCData();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ rpcDummy = sc->commitTA( cci );
+
+ // Return the result
+ return &rpcDummy;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The global remote procedure {\tt rpcAbortTA()} is called by a clientcomm
+ object on the client system to abort the current transaction in a session with
+ a RasDaMan server.
+*/
+
+unsigned short*
+RPCFUNCTIONDEF( rpcabortta_1, unsigned long* callingClientId )
+{
+ secureResultBufferForRPC = (char*)&rpcDummy;
+
+ unsigned long cci;
+ cci = *callingClientId;
+
+ freeDynamicRPCData();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ rpcDummy = sc->abortTA( cci );
+
+ // Return the result
+ return &rpcDummy;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The global remote procedure {\tt rpcexecutequery_1()} is called by a clientcomm
+ object on the client system to initiate a retrieval query execution on a RasDaMan
+ server.
+*/
+
+ExecuteQueryRes*
+RPCFUNCTIONDEF( rpcexecutequery_1, ExecuteQueryParams* params )
+{
+ secureResultBufferForRPC = (char*)&rpcExecuteQueryRes;
+
+ unsigned short returnValue;
+ unsigned long callingClientId = params->clientID;
+ const char* query = params->query;
+
+ freeDynamicRPCData();
+
+ // prevent RPC from NULL pointers in case of exceptions
+ char *prev1 = strdup("");
+ char *prev2 = strdup("");
+ char *prev3 = strdup("");
+ rpcExecuteQueryRes.token = prev1;
+ rpcExecuteQueryRes.typeName = prev2;
+ rpcExecuteQueryRes.typeStructure = prev3;
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ returnValue = sc->executeQuery( callingClientId, (const char*) query, rpcExecuteQueryRes );
+
+ // if no exception was thrown we are here, first check if the pointers have changed
+ if( rpcExecuteQueryRes.token != prev1 ) free(prev1);
+ if( rpcExecuteQueryRes.typeName != prev2 ) free(prev2);
+ if( rpcExecuteQueryRes.typeStructure != prev3 ) free(prev3);
+
+ // than check if the pointers are NULL
+ if( !rpcExecuteQueryRes.token ) rpcExecuteQueryRes.token = strdup("");
+ if( !rpcExecuteQueryRes.typeName ) rpcExecuteQueryRes.typeName = strdup("");
+ if( !rpcExecuteQueryRes.typeStructure ) rpcExecuteQueryRes.typeStructure = strdup("");
+
+ // set missing parts of return structure
+ rpcExecuteQueryRes.status = returnValue;
+
+
+ return &rpcExecuteQueryRes;
+}
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The global remote procedure {\tt rpcgetnextmdd_1()} is called by a clientcomm
+ object on the client system to transmit the next element of a MDD collection
+ from a RasDaMan server.
+*/
+
+GetMDDRes*
+RPCFUNCTIONDEF( rpcgetnextmdd_1, unsigned long* callingClientId )
+{
+ RMDBGENTER(2, RMDebug::module_servercomm, "Manager", "rpcgetnextmdd_1" )
+
+ secureResultBufferForRPC = (char*)&rpcGetMDDRes;
+
+ r_Minterval mddDomain;
+ r_OId oid;
+
+ freeDynamicRPCData();
+
+ // prevent RPC from NULL pointers
+ char *prev1 = strdup("");
+ char *prev2 = strdup("");
+ char *prev3 = strdup("");
+ char *prev4 = strdup("");
+
+ rpcGetMDDRes.typeName = prev1;
+ rpcGetMDDRes.typeStructure = prev2;
+ rpcGetMDDRes.domain = prev3;
+ rpcGetMDDRes.oid = prev4;
+
+ accessControl.wantToRead();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method and return the result
+ rpcGetMDDRes.status = sc->getNextMDD( *callingClientId, mddDomain,
+ rpcGetMDDRes.typeName,
+ rpcGetMDDRes.typeStructure, oid,
+ rpcGetMDDRes.currentFormat );
+ rpcGetMDDRes.domain = mddDomain.get_string_representation();
+ rpcGetMDDRes.oid = oid.get_string_representation() ? strdup( oid.get_string_representation() ) : strdup("");
+
+ // if no exceptions...
+ if( rpcGetMDDRes.typeName != prev1 ) free(prev1);
+ if( rpcGetMDDRes.typeStructure != prev2 ) free(prev2);
+ if( rpcGetMDDRes.domain != prev3 ) free(prev3);
+ if( rpcGetMDDRes.oid != prev4 ) free(prev4);
+
+ // prevent RPC from NULL pointers
+ if( !rpcGetMDDRes.typeName ) rpcGetMDDRes.typeName = strdup("");
+ if( !rpcGetMDDRes.typeStructure ) rpcGetMDDRes.typeStructure = strdup("");
+ // the other 2 are not null
+
+ RMDBGEXIT(2, RMDebug::module_servercomm, "Manager", "rpcgetnextmdd_1" )
+ return &rpcGetMDDRes;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The global remote procedure {\tt rpcgetnextelement_1()} is called by a clientcomm
+ object on the client system to transmit the next element of a non-MDD collection
+ from a RasDaMan server.
+*/
+
+GetElementRes*
+RPCFUNCTIONDEF( rpcgetnextelement_1, unsigned long* callingClientId )
+{
+ RMDBGENTER(2, RMDebug::module_servercomm, "Manager", "rpcgetnextelement_1" )
+
+ secureResultBufferForRPC = (char*)&rpcGetElementRes;
+
+ freeDynamicRPCData();
+
+ accessControl.wantToRead();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method and return the result
+ rpcGetElementRes.status = sc->getNextElement( *callingClientId, rpcGetElementRes.data.confarray_val,
+ rpcGetElementRes.data.confarray_len );
+
+ RMDBGEXIT(2, RMDebug::module_servercomm, "Manager", "rpcgetnextelement_1" )
+ return &rpcGetElementRes;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The global remote procedure \Ref{rpcgetmddbyoid_1} is called by a clientcomm
+ object on the client system to receive an MDD by its oid.
+*/
+
+GetMDDRes*
+RPCFUNCTIONDEF( rpcgetmddbyoid_1, OIdSpecParams* params )
+{
+ RMDBGENTER(2, RMDebug::module_servercomm, "Manager", "rpcgetmddbyoid_1" )
+
+ secureResultBufferForRPC = (char*)&rpcGetMDDRes;
+
+ r_Minterval mddDomain;
+ r_OId oid( params->oid );
+
+ freeDynamicRPCData();
+ // prevent RPC from NULL pointers if exception occur
+ char *prev1 = strdup("");
+ char *prev2 = strdup("");
+ char *prev3 = strdup("");
+ char *prev4 = strdup("");
+
+ rpcGetMDDRes.typeName = prev1;
+ rpcGetMDDRes.typeStructure = prev2;
+ rpcGetMDDRes.domain = prev3;
+ rpcGetMDDRes.oid = prev4;
+
+ accessControl.wantToRead();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method and return the result
+ rpcGetMDDRes.status = sc->getMDDByOId( params->clientID, oid, mddDomain,
+ rpcGetMDDRes.typeName,
+ rpcGetMDDRes.typeStructure,
+ rpcGetMDDRes.currentFormat );
+ rpcGetMDDRes.domain = mddDomain.get_string_representation();
+ rpcGetMDDRes.oid = oid.get_string_representation() ? strdup( oid.get_string_representation() ) : strdup("");
+
+ // prevent RPC from NULL pointers
+ if( rpcGetMDDRes.typeName != prev1) free(prev1);
+ if( rpcGetMDDRes.typeStructure != prev2) free(prev2);
+ if( rpcGetMDDRes.domain != prev3 ) free(prev3);
+ if( rpcGetMDDRes.oid != prev4 ) free(prev4);
+
+ if( !rpcGetMDDRes.typeName ) rpcGetMDDRes.typeName = strdup("");
+ if( !rpcGetMDDRes.typeStructure ) rpcGetMDDRes.typeStructure = strdup("");
+ // the other 2 are not null
+
+ RMDBGEXIT(2, RMDebug::module_servercomm, "Manager", "rpcgetmddbyoid_1" )
+ return &rpcGetMDDRes;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The global remote procedure {\tt rpcgetnexttile_1()} is called by a clientcomm
+ object on the client system to transmit the next element of a MDD collection
+ from a RasDaMan server.
+*/
+
+GetTileRes*
+RPCFUNCTIONDEF( rpcgetnexttile_1, unsigned long* callingClientId )
+{
+ RMDBGENTER(2, RMDebug::module_servercomm, "Manager", "rpcgetnexttile_1" )
+
+ secureResultBufferForRPC = (char*)&rpcGetTileRes;
+
+ freeDynamicRPCData();
+
+ // fake data for security
+ RPCMarray *secureRpcMarray = (RPCMarray*)mymalloc(sizeof(RPCMarray));
+ secureRpcMarray->domain = strdup("");
+ secureRpcMarray->cellTypeLength = 1;
+ secureRpcMarray->currentFormat = 1;
+ secureRpcMarray->storageFormat = 1;
+ secureRpcMarray->data.confarray_len = 1;
+ secureRpcMarray->data.confarray_val = strdup("");
+
+ rpcGetTileRes.marray = secureRpcMarray;
+
+ RPCMarray *tempRpcMarray;
+
+ accessControl.wantToRead();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method and return the result
+ rpcGetTileRes.status = sc->getNextTile( *callingClientId, &tempRpcMarray); //&rpcGetTileRes.marray );
+ // if this throws, secure... is nice initialized
+
+ rpcGetTileRes.marray = tempRpcMarray;
+
+ free(secureRpcMarray->data.confarray_val);
+ free(secureRpcMarray->domain);
+ free(secureRpcMarray);
+
+ RMDBGEXIT(2, RMDebug::module_servercomm, "Manager", "rpcgetnexttile_1" )
+ return &rpcGetTileRes;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+//@ManMemo: Module: {\bf servercomm}
+
+/**
+*/
+unsigned short*
+RPCFUNCTIONDEF( rpcendtransfer_1, unsigned long* callingClientId )
+{
+ unsigned long cci = *callingClientId;
+
+ secureResultBufferForRPC = (char*)&rpcDummy;
+
+ freeDynamicRPCData();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ rpcDummy = sc->endTransfer( cci );
+
+ // Return the result
+ return &rpcDummy;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+//@ManMemo: Module: {\bf servercomm}
+
+/**
+*/
+unsigned short*
+RPCFUNCTIONDEF( rpcinitexecuteupdate_1, unsigned long* callingClientId )
+{
+ secureResultBufferForRPC = (char*)&rpcDummy;
+
+ unsigned long cci;
+ cci = *callingClientId;
+
+ freeDynamicRPCData();
+
+ accessControl.wantToWrite();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ rpcDummy = sc->initExecuteUpdate( cci );
+
+ // Return the result
+ return &rpcDummy;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The global remote procedure {\tt rpcexecuteupdate_1()} is called by a clientcomm
+ object on the client system to initiate an update query execution on a RasDaMan
+ server.
+*/
+
+ExecuteUpdateRes*
+RPCFUNCTIONDEF( rpcexecuteupdate_1, ExecuteQueryParams* params )
+{
+ secureResultBufferForRPC = (char*)&rpcExecuteUpdateRes;
+
+ unsigned short returnValue;
+ unsigned long callingClientId = params->clientID;
+ const char* query = params->query;
+
+ freeDynamicRPCData();
+
+ // prevent RPC from NULL pointers
+ char *prev1 = strdup("");
+ rpcExecuteUpdateRes.token = prev1;
+
+ accessControl.wantToWrite();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ returnValue = sc->executeUpdate( callingClientId, (const char*) query, rpcExecuteUpdateRes );
+
+ // set missing parts of return structure
+ rpcExecuteUpdateRes.status = returnValue;
+
+ // prevent RPC from NULL pointers
+ if( rpcExecuteUpdateRes.token != prev1 ) free(prev1);
+
+ if( !rpcExecuteUpdateRes.token ) rpcExecuteUpdateRes.token = strdup("");
+
+ return &rpcExecuteUpdateRes;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+//@ManMemo: Module: {\bf servercomm}
+
+/**
+*/
+unsigned short*
+RPCFUNCTIONDEF( rpcstartinserttransmdd_1, InsertTransMDDParams* params )
+{
+ secureResultBufferForRPC = (char*)&rpcDummy;
+
+ unsigned long callingClientId = params->clientID;
+ // const char* collName = params->collName; // not used
+ const char* typeName = params->typeName;
+ unsigned long typeLength = params->typeLength;
+ r_Minterval mddDomain( params->domain );
+
+ freeDynamicRPCData();
+
+ accessControl.wantToWrite();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ rpcDummy = sc->startInsertTransMDD( callingClientId, mddDomain, typeLength, typeName );
+
+ // Return the result
+ return &rpcDummy;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+//@ManMemo: Module: {\bf servercomm}
+
+/**
+*/
+unsigned short*
+RPCFUNCTIONDEF( rpcstartinsertpersmdd_1, InsertPersMDDParams* params )
+{
+ secureResultBufferForRPC = (char*)&rpcDummy;
+
+ unsigned long callingClientId = params->clientID;
+ const char* collName = params->collName;
+ const char* typeName = params->typeName;
+ unsigned long typeLength = params->typeLength;
+ r_Minterval mddDomain( params->domain );
+ r_OId oid( params->oid );
+
+ freeDynamicRPCData();
+
+ accessControl.wantToWrite();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ rpcDummy = sc->startInsertPersMDD( callingClientId, (const char*) collName, mddDomain, typeLength, typeName, oid );
+
+ // Return the result
+ return &rpcDummy;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+//@ManMemo: Module: {\bf servercomm}
+
+/**
+*/
+unsigned short*
+RPCFUNCTIONDEF( rpcinserttile_1, InsertTileParams* params )
+{
+ secureResultBufferForRPC = (char*)&rpcDummy;
+
+ freeDynamicRPCData();
+
+ accessControl.wantToWrite();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ rpcDummy = sc->insertTile( params->clientID, params->isPersistent, params->marray );
+
+ // Return the result
+ return &rpcDummy;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/**
+*/
+unsigned short*
+RPCFUNCTIONDEF( rpcendinsertmdd_1, EndInsertMDDParams* params )
+{
+ secureResultBufferForRPC = (char*)&rpcDummy;
+
+ freeDynamicRPCData();
+
+ accessControl.wantToWrite();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ rpcDummy = sc->endInsertMDD( params->clientID, params->isPersistent );
+
+ // Return the result
+ return &rpcDummy;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The global remote procedure {\tt rpcInsertMDD()} is called by a clientcomm
+ object on the client system to insert a MDD object in an existing MDD
+ collection on a RasDaMan server.
+*/
+
+unsigned short*
+RPCFUNCTIONDEF( rpcinsertmdd_1, InsertMDDParams* params )
+{
+ secureResultBufferForRPC = (char*)&rpcDummy;
+
+ unsigned long callingClientId = params->clientID;
+ const char* collName = params->collName;
+ const char* typeName = params->typeName;
+ RPCMarray* rpcMarray = params->marray;
+
+ r_OId oid( params->oid );
+
+ freeDynamicRPCData();
+
+ accessControl.wantToWrite();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ rpcDummy = sc->insertMDD( callingClientId, collName, rpcMarray, typeName, oid );
+
+ return &rpcDummy;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The global remote procedure {\tt rpcgetcollbyname_1()} is called by a clientcomm
+ object on the client system to initiate the lookup of a MDD collection by its name
+ on a RasDaMan server.
+*/
+
+GetCollRes*
+RPCFUNCTIONDEF( rpcgetcollbyname_1, NameSpecParams* params )
+{
+ RMDBGENTER(2, RMDebug::module_servercomm, "Manager", "rpcgetcollbyname_1" )
+
+ secureResultBufferForRPC = (char*)&rpcGetCollRes;
+
+ r_OId oid;
+
+ freeDynamicRPCData();
+
+ char *prev1 = strdup("");
+ char *prev2 = strdup("");
+ char *prev3 = strdup("");
+ char *prev4 = strdup("");
+ rpcGetCollRes.typeName = prev1;
+ rpcGetCollRes.typeStructure = prev2;
+ rpcGetCollRes.oid = prev3;
+ rpcGetCollRes.collName = prev4;
+
+ accessControl.wantToRead();
+
+ unsigned long callingClientId = params->clientID;
+ const char* collName = params->name;
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ rpcGetCollRes.status = sc->getCollByName( callingClientId, collName,
+ rpcGetCollRes.typeName,
+ rpcGetCollRes.typeStructure, oid );
+
+ rpcGetCollRes.oid = oid.get_string_representation() ? strdup( oid.get_string_representation() ) : strdup("");
+ rpcGetCollRes.collName = params->name ? strdup( params->name ) : strdup("");
+
+ // prevent RPC from NULL pointers
+ if( rpcGetCollRes.typeName != prev1) free(prev1);
+ if( rpcGetCollRes.typeStructure != prev2) free(prev2);
+ if( rpcGetCollRes.oid != prev3) free(prev3);
+ if( rpcGetCollRes.collName != prev4) free(prev4);
+
+ if( !rpcGetCollRes.typeName ) rpcGetCollRes.typeName = strdup("");
+ if( !rpcGetCollRes.typeStructure ) rpcGetCollRes.typeStructure = strdup("");
+
+ // Return the result
+ RMDBGEXIT(2, RMDebug::module_servercomm, "Manager", "rpcgetcollbyname_1" )
+ return &rpcGetCollRes;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The global remote procedure {\tt rpcgetcollbyoid_1()} is called by a clientcomm
+ object on the client system to initiate the lookup of a MDD collection by its oid
+ on a RasDaMan server.
+*/
+
+GetCollRes*
+RPCFUNCTIONDEF( rpcgetcollbyoid_1, OIdSpecParams* params )
+{
+ RMDBGENTER(2, RMDebug::module_servercomm, "Manager", "rpcgetcollbyoid_1" )
+
+ secureResultBufferForRPC = (char*)&rpcGetCollRes;
+
+ r_OId oid( params->oid );
+
+ freeDynamicRPCData();
+ // prevent RPC from NULL pointers
+ char *prev1 = strdup("");
+ char *prev2 = strdup("");
+ char *prev3 = strdup("");
+ char *prev4 = strdup("");
+ rpcGetCollRes.typeName = prev1;
+ rpcGetCollRes.typeStructure = prev2;
+ rpcGetCollRes.collName = prev3;
+ rpcGetCollRes.oid = prev4;
+
+ accessControl.wantToRead();
+
+ unsigned long callingClientId = params->clientID;
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ rpcGetCollRes.status = sc->getCollByOId( callingClientId, oid, rpcGetCollRes.typeName,
+ rpcGetCollRes.typeStructure, rpcGetCollRes.collName );
+
+ rpcGetCollRes.oid = oid.get_string_representation() ? strdup( oid.get_string_representation() ) : strdup("");
+
+ // prevent RPC from NULL pointers
+ if( rpcGetCollRes.typeName != prev1) free(prev1);
+ if( rpcGetCollRes.typeStructure != prev2) free(prev2);
+ if( rpcGetCollRes.collName != prev3) free(prev3);
+ if( rpcGetCollRes.oid != prev4) free(prev4);
+
+ if( !rpcGetCollRes.typeName ) rpcGetCollRes.typeName = strdup("");
+ if( !rpcGetCollRes.typeStructure ) rpcGetCollRes.typeStructure = strdup("");
+ if( !rpcGetCollRes.collName ) rpcGetCollRes.collName = strdup("");
+ // oid is not null,
+
+ // Return the result
+ RMDBGEXIT(2, RMDebug::module_servercomm, "Manager", "rpcgetcollbyoid_1" )
+ return &rpcGetCollRes;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The global remote procedure {\tt rpcgetcolloidsbyname_1()} is called by a clientcomm
+ object on the client system to retrieve the collection of oids by the collection's name.
+*/
+
+GetCollOIdsRes*
+RPCFUNCTIONDEF( rpcgetcolloidsbyname_1, NameSpecParams* params )
+{
+ RMDBGENTER(2, RMDebug::module_servercomm, "Manager", "rpcgetcolloidsbyname_1" )
+
+ secureResultBufferForRPC = (char*)&rpcGetCollOidsRes;
+
+ r_OId oid;
+
+ freeDynamicRPCData();
+
+ char *prev1 = strdup("");
+ char *prev2 = strdup("");
+ char *prev3 = strdup("");
+ char *prev4 = strdup("");
+ rpcGetCollOidsRes.typeName = prev1;
+ rpcGetCollOidsRes.typeStructure = prev2;
+ rpcGetCollOidsRes.collName = prev3;
+ rpcGetCollRes.oid = prev4;
+
+ accessControl.wantToRead();
+
+ unsigned long callingClientId = params->clientID;
+ const char* collName = params->name;
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ rpcGetCollOidsRes.status = sc->getCollOIdsByName( callingClientId, collName, rpcGetCollOidsRes.typeName,
+ rpcGetCollOidsRes.typeStructure, oid,
+ rpcGetCollOidsRes.oidTable.oidTable_val, rpcGetCollOidsRes.oidTable.oidTable_len );
+
+ rpcGetCollOidsRes.oid = oid.get_string_representation() ? strdup( oid.get_string_representation() ) : strdup("");
+ rpcGetCollOidsRes.collName = params->name ? strdup( params->name ) : strdup("");
+
+ // prevent RPC from NULL pointers
+ if( rpcGetCollOidsRes.typeName != prev1 ) free(prev1);
+ if( rpcGetCollOidsRes.typeStructure != prev2 ) free(prev2);
+ if( rpcGetCollOidsRes.collName != prev3 ) free(prev3);
+ if( rpcGetCollRes.oid != prev4) free(prev4);
+
+ if( !rpcGetCollOidsRes.typeName ) rpcGetCollOidsRes.typeName = strdup("");
+ if( !rpcGetCollOidsRes.typeStructure ) rpcGetCollOidsRes.typeStructure = strdup("");
+ if( !rpcGetCollOidsRes.collName ) rpcGetCollOidsRes.collName = strdup("");
+ // oid is not null
+
+ // Return the result
+ RMDBGEXIT(2, RMDebug::module_servercomm, "Manager", "rpcgetcolloidsbyname_1" )
+ return &rpcGetCollOidsRes;
+}
+
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The global remote procedure {\tt rpcgetcolloidsbyoid_1()} is called by a clientcomm
+ object on the client system to retrieve the collection of oids by the collection's oid.
+*/
+
+GetCollOIdsRes*
+RPCFUNCTIONDEF( rpcgetcolloidsbyoid_1, OIdSpecParams* params )
+{
+ RMDBGENTER(2, RMDebug::module_servercomm, "Manager", "rpcgetcolloidsbyname_1" )
+
+ secureResultBufferForRPC = (char*)&rpcGetCollOidsRes;
+
+ r_OId oid( params->oid );
+
+ freeDynamicRPCData();
+
+ char *prev1 = strdup("");
+ char *prev2 = strdup("");
+ char *prev3 = strdup("");
+ char *prev4 = strdup("");
+ rpcGetCollOidsRes.typeName = prev1;
+ rpcGetCollOidsRes.typeStructure = prev2;
+ rpcGetCollOidsRes.collName = prev3;
+ rpcGetCollRes.oid = prev4;
+
+ accessControl.wantToRead();
+
+ unsigned long callingClientId = params->clientID;
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ rpcGetCollOidsRes.status = sc->getCollOIdsByOId( callingClientId, oid,
+ rpcGetCollOidsRes.typeName,
+ rpcGetCollOidsRes.typeStructure,
+ rpcGetCollOidsRes.oidTable.oidTable_val,
+ rpcGetCollOidsRes.oidTable.oidTable_len,
+ rpcGetCollOidsRes.collName );
+
+ rpcGetCollOidsRes.oid = oid.get_string_representation() ? strdup( oid.get_string_representation() ) : strdup("");
+
+ // prevent RPC from NULL pointers
+ if( rpcGetCollOidsRes.typeName != prev1 ) free(prev1);
+ if( rpcGetCollOidsRes.typeStructure != prev2 ) free(prev2);
+ if( rpcGetCollOidsRes.collName != prev3 ) free(prev3);
+ if( rpcGetCollRes.oid != prev4) free(prev4);
+
+ if( !rpcGetCollOidsRes.typeName ) rpcGetCollOidsRes.typeName = strdup("");
+ if( !rpcGetCollOidsRes.typeStructure ) rpcGetCollOidsRes.typeStructure = strdup("");
+ if( !rpcGetCollOidsRes.collName ) rpcGetCollOidsRes.collName = strdup("");
+
+ // Return the result
+ RMDBGEXIT(2, RMDebug::module_servercomm, "Manager", "rpcgetcolloidsbyname_1" )
+ return &rpcGetCollOidsRes;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The global remote procedure {\tt rpcinsertcoll_1()} is called by a clientcomm
+ object on the client system to create a MDD collection for further use on
+ a RasDaMan server.
+*/
+
+unsigned short*
+RPCFUNCTIONDEF( rpcinsertcoll_1, InsertCollParams* params )
+{
+ secureResultBufferForRPC = (char*)&rpcDummy;
+
+ unsigned long callingClientId = params->clientID;
+ const char* collName = params->collName;
+ const char* typeName = params->typeName;
+
+ freeDynamicRPCData();
+
+ accessControl.wantToWrite();
+
+ r_OId oid( params->oid );
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ rpcDummy = sc->insertColl( callingClientId, collName, typeName, oid );
+
+ // Return the result
+ return &rpcDummy;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The global remote procedure {\tt rpcdeletecollbyname_1()} is called by a clientcomm
+ object on the client system to delete a existing MDD collection.
+*/
+
+unsigned short*
+RPCFUNCTIONDEF( rpcdeletecollbyname_1, NameSpecParams* params )
+{
+ secureResultBufferForRPC = (char*)&rpcDummy;
+
+ unsigned long callingClientId = params->clientID;
+ const char* collName = params->name;
+
+ freeDynamicRPCData();
+
+ accessControl.wantToWrite();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ rpcDummy = sc->deleteCollByName( callingClientId, collName );
+
+ // Return the result
+ return &rpcDummy;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The global remote procedure {\tt rpcdeleteobjbyoid_1()} is called by a clientcomm
+ object on the client system to delete an object specified by oid.
+*/
+
+unsigned short*
+RPCFUNCTIONDEF( rpcdeleteobjbyoid_1, OIdSpecParams* params )
+{
+ secureResultBufferForRPC = (char*)&rpcDummy;
+
+ unsigned long callingClientId = params->clientID;
+ r_OId oid( params->oid );
+
+ freeDynamicRPCData();
+
+ accessControl.wantToWrite();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ rpcDummy = sc->deleteObjByOId( callingClientId, oid );
+
+ // Return the result
+ return &rpcDummy;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The global remote procedure {\tt rpcremoveobjfromcoll_1()} is called by a clientcomm
+ object on the client system to delete an object from a collection.
+*/
+
+unsigned short*
+RPCFUNCTIONDEF( rpcremoveobjfromcoll_1, RemoveObjFromCollParams* params )
+{
+ secureResultBufferForRPC = (char*)&rpcDummy;
+
+ unsigned long callingClientId = params->clientID;
+ const char* collName = params->collName;
+ r_OId oid( params->oid );
+
+ freeDynamicRPCData();
+
+ accessControl.wantToWrite();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ rpcDummy = sc->removeObjFromColl( callingClientId, collName, oid );
+
+ // Return the result
+ return &rpcDummy;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+*/
+
+ObjectTypeRes*
+RPCFUNCTIONDEF( rpcgetobjecttype_1, OIdSpecParams* params )
+{
+ secureResultBufferForRPC = (char*)&procResult;
+
+ freeDynamicRPCData();
+
+ accessControl.wantToRead();
+
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ r_OId oid( params->oid );
+
+ procResult.status = sc->getObjectType( params->clientID, oid, procResult.objType );
+
+ // Return the result
+ return &procResult;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+*/
+
+OIdRes*
+RPCFUNCTIONDEF( rpcgetnewoid_1, NewOIdParams* params )
+{
+ secureResultBufferForRPC = (char*)&rpcOidRes;
+
+ freeDynamicRPCData();
+
+ char *prev1 = strdup("");
+ rpcOidRes.oid = prev1;
+
+ accessControl.wantToWrite();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ r_OId oid;
+
+ rpcOidRes.status = sc->getNewOId( params->clientID, params->objType, oid );
+ rpcOidRes.oid = oid.get_string_representation() ? strdup( oid.get_string_representation() ) : strdup("");
+ free(prev1);
+
+ // Return the result
+ return &rpcOidRes;
+}
+
+
+// Callback for callback manager, performs actual garbage collection.
+// The context points to the ServerComm object (see registering call in
+// garbageCollection() )
+static void callback_garbage_collection(void *context)
+{
+ ServerComm *sc = (ServerComm*)context;
+
+ if( sc && !sc->clientTbl.empty() )
+ {
+ RMInit::dbgOut << "Garbage Collection ... " << flush;
+
+#ifdef RMANDEBUG
+ sc->printServerStatus( RMInit::dbgOut );
+#endif
+
+ if (!noTimeOut)
+ {
+ list<ServerComm::ClientTblElt*>::iterator iter;
+ iter = sc->clientTbl.begin();
+ unsigned long now = time( NULL );
+
+ RMDBGONCE(2, RMDebug::module_servercomm, "Manager", "checking " << sc->clientTbl.size() << " clients..." );
+ while ( iter != sc->clientTbl.end() )
+ {
+ if( now - (*iter)->lastActionTime >= sc->clientTimeout )
+ {
+ RMInit::logOut << "Message: Found timed-out client with id " << (*iter)->clientId
+ << " (" << (*iter)->clientIdText << ", "
+ << now - (*iter)->lastActionTime << "s)..." << flush;
+
+ if( sc->deleteClientTblEntry( (*iter)->clientId ) == 0 )
+ {
+ RMInit::logOut << "deleted." << endl;
+
+ sc->informRasMGR(SERVER_AVAILABLE);
+ // reset the iterator (otherwise, it would skip one object
+ // because one was deleted)
+ iter = sc->clientTbl.begin();
+ }
+ else
+ {
+ RMInit::logOut << "deletion postponed." << endl;
+ iter++;
+ }
+ }
+ else
+ iter++;
+ }
+ }
+ RMInit::dbgOut << "garbage collection done." << endl;
+ }
+}
+
+
+#ifdef LINUX
+extern "C"
+#endif
+void
+garbageCollection( int )
+{
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ /*
+ * Just register the callbacks because we're not allowed to do any
+ * mallocs or prints in the alarm handler environment. The pending
+ * callbacks will be executed whenever there's RPC activity.
+ */
+ sc->callback_mgr.registerUniqueCallback(callback_garbage_collection, (void*)sc);
+
+ // Re-initialize the signal handler to point to this function
+ signal( SIGALRM, garbageCollection);
+
+ // Reset the alarm
+ alarm( (unsigned int)sc->garbageCollectionInterval );
+}
+
+
+#ifdef LINUX
+extern "C"
+#endif
+void
+garbageCollectionDummy( int )
+{
+ /* Dummy garbage collection function for avoiding reentrance of the callback manager.
+ Does nothing but reinstall the signal. */
+ signal( SIGALRM, garbageCollection);
+ alarm( (unsigned int)(ServerComm::actual_servercomm->garbageCollectionInterval) );
+}
+
+
+#ifdef LINUX
+extern "C"
+#endif
+GetTypeStructureRes*
+RPCFUNCTIONDEF( rpcgettypestructure_1, GetTypeStructureParams* params )
+{
+ secureResultBufferForRPC = (char*)&rpcGetTypeStructureRes;
+
+ freeDynamicRPCData();
+
+ char *prev1 = strdup("");
+ rpcGetTypeStructureRes.typeStructure = prev1;
+
+ accessControl.wantToRead();
+
+ // Get a pointer to the actual servercomm object.
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ // Call the corresponding method.
+ rpcGetTypeStructureRes.status = sc->getTypeStructure( params->clientID, params->typeName,
+ params->typeType, rpcGetTypeStructureRes.typeStructure );
+
+ // prevent RPC from NULL pointers
+ if( rpcGetTypeStructureRes.typeStructure != prev1 ) free(prev1);
+
+ if( !rpcGetTypeStructureRes.typeStructure ) rpcGetTypeStructureRes.typeStructure = strdup("");
+
+ // Return the result
+ return &rpcGetTypeStructureRes;
+}
+
+
+
+#ifdef LINUX
+extern "C"
+#endif
+int*
+RPCFUNCTIONDEF( rpcgetserverendian_1, int * )
+{
+ freeDynamicRPCData();
+
+ static int result;
+
+#ifdef LITTLE_ENDIAN
+ result = 1;
+#else
+ result = 0;
+#endif
+
+ return &result;
+}
+
+
+#ifdef LINUX
+extern "C"
+#endif
+unsigned short*
+RPCFUNCTIONDEF( rpcsetservertransfer_1, SetServerTransferParams* params )
+{
+ freeDynamicRPCData();
+ secureResultBufferForRPC = (char*)&rpcDummy;
+
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ rpcDummy = (unsigned short)(sc->setTransferMode( params->clientID, params->format, params->formatParams ));
+
+ return &rpcDummy;
+}
+
+
+#ifdef LINUX
+extern "C"
+#endif
+GetExtendedErrorInfo *
+RPCFUNCTIONDEF( rpcgeterrorinfo_1, void * params )
+{
+ freeDynamicRPCData();
+
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ rpcExtendedErrorInfo.errorText = (char*) sc->getExtendedErrorInfo();
+
+ return &rpcExtendedErrorInfo;
+}
+
+#ifdef LINUX
+extern "C"
+#endif
+unsigned short*
+RPCFUNCTIONDEF( rpcsetserverstorage_1, SetServerTransferParams* params )
+{
+ secureResultBufferForRPC = (char*)&rpcDummy;
+
+ freeDynamicRPCData();
+
+ ServerComm* sc = ServerComm::actual_servercomm;
+
+ rpcDummy = (unsigned short)(sc->setStorageMode(params->clientID, params->format, params->formatParams ));
+
+ return &rpcDummy;
+}
+
diff --git a/servercomm/servercomm.cc b/servercomm/servercomm.cc
new file mode 100644
index 0000000..5982453
--- /dev/null
+++ b/servercomm/servercomm.cc
@@ -0,0 +1,1399 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: servercomm.cc
+ *
+ * MODULE: servercomm
+ * CLASS: ServerComm
+ *
+ * COMMENTS:
+ * None
+*/
+
+#include "mymalloc/mymalloc.h"
+
+// --- these defs should go into a central constant definition section,
+// as they define externally observable behavior -- PB 2003-nov-15
+
+// waiting period until client is considered dead [secs]
+#define CLIENT_TIMEOUT 3600
+
+// timeout for select() call at server startup [secs]
+#define TIMEOUT_SELECT 30
+
+// period after which the next garbage collection is scheduled [secs]
+#define GARBCOLL_INTERVAL 600
+
+// console output describing successful/unsuccessful actions
+#define MSG_OK "ok"
+#define MSG_FAILED "failed"
+
+// rasserver exit codes (selection of value sometimes unclear :-(
+#define EXITCODE_ZERO 0
+#define EXITCODE_ONE 1
+#define EXITCODE_RASMGR_FAILED 10 // Why 10 ?
+// ---
+
+static const char rcsid[] = "@(#)servercomm, ServerComm: $Id: servercomm.cc,v 1.146 2006/01/03 00:23:53 rasdev Exp $";
+
+#include<openssl/evp.h>
+
+#include <iostream>
+#include <malloc.h>
+#include <time.h> // for time()
+#include <string.h>
+
+#include <signal.h> // for signal()
+#include <unistd.h> // for alarm(), gethostname()
+#include <iomanip>
+
+#ifdef SOLARIS
+ #define PORTMAP // define to use function declarations for old interfaces
+ #include <rpc/rpc.h>
+
+ int _rpcpmstart = 0;
+
+ // function prototype with C linkage
+ extern "C" int gethostname(char *name, int namelen);
+#else // HPUX
+ #include <rpc/rpc.h>
+#endif
+
+#include <rpc/pmap_clnt.h>
+
+#include "raslib/rmdebug.hh"
+#include "raslib/rminit.hh"
+#include "raslib/error.hh"
+#include "raslib/minterval.hh"
+#include "raslib/parseparams.hh"
+#include "compression/tilecompression.hh"
+
+#include "servercomm/servercomm.hh"
+#include "qlparser/qtnode.hh"
+#include "qlparser/qtdata.hh"
+#include "catalogmgr/typefactory.hh"
+
+#include "tilemgr/tile.hh"
+
+#include "relcatalogif/mddtype.hh"
+#include "relcatalogif/mdddomaintype.hh"
+#include "relcatalogif/settype.hh"
+#include "mddmgr/mddcoll.hh"
+#include "mddmgr/mddcolliter.hh"
+#include "mddmgr/mddobj.hh"
+
+#include "debug.hh"
+
+#ifdef PURIFY
+#include <purify.h>
+#endif
+#include<stdio.h>
+#include<stdlib.h>
+#include<sys/types.h>
+#include<sys/socket.h>
+#include<netinet/in.h>
+#include<netdb.h>
+#include<iostream>
+
+using namespace std;
+// init globals for server initialization
+// RMINITGLOBALS('S')
+
+// Once again a function prototype. The first one is for the RPC dispatcher
+// function located in the server stub file rpcif_svc.c and the second one
+// is for the garbage collection function pointed to by the signal handler.
+extern "C"
+{
+ // void rpcif_1( struct svc_req*, register SVCXPRT* );
+ void garbageCollection( int );
+}
+extern char* rpcif_1( struct svc_req*, register SVCXPRT* );
+extern bool bMemFailed;
+
+// this is a temporary thing
+extern int globalOptimizationLevel;
+extern unsigned long maxTransferBufferSize;
+
+// At the beginning, no servercomm object exists.
+ServerComm* ServerComm::actual_servercomm = 0;
+
+list<ServerComm::ClientTblElt*> ServerComm::clientTbl;
+unsigned long ServerComm::clientCount = 0;
+
+#include "rnprotocol/srvrasmgrcomm.hh"
+
+extern SrvRasmgrComm rasmgrComm;
+
+/*************************************************************************
+ * Method name...: ServerComm() (constructor)
+ ************************************************************************/
+ServerComm::ServerComm()
+ : clientTimeout( rasmgrComm.getTimeout() ),
+ garbageCollectionInterval( GARBCOLL_INTERVAL ),
+ transactionActive( 0 ),
+ memUsed( 0 ),
+ admin( 0 ),
+ errorText( 0 )
+{
+ if( actual_servercomm )
+ {
+ RMInit::logOut << "Internal Error: Tried to instantiate more than one ServerComm object." << endl;
+ exit( EXITCODE_ONE );
+ }
+
+ // uniqueClientContext = NULL;
+ isHttpServer = false;
+
+ actual_servercomm = this;
+}
+
+ServerComm::ServerComm( unsigned long timeOut, unsigned long managementInterval , unsigned long listenPort, char* rasmgrHost, unsigned int rasmgrPort,char* serverName)
+ : clientTimeout( timeOut ),
+ garbageCollectionInterval( managementInterval ),
+ transactionActive( 0 ),
+ memUsed( 0 ),
+ admin( 0 ),
+ errorText( 0 )
+{
+ if( actual_servercomm )
+ {
+ RMInit::logOut << "Internal Error: Tried to instantiate more than one ServerComm object." << endl;
+ exit( EXITCODE_ONE );
+ }
+
+ actual_servercomm = this;
+ this->listenPort = listenPort;
+ this->rasmgrHost = rasmgrHost;
+ this->rasmgrPort = rasmgrPort;
+ this->serverName = serverName;
+
+ isHttpServer = false;
+ //uniqueClientContext = NULL;
+}
+
+
+
+/*************************************************************************
+ * Method name...: ~ServerComm() (destructor)
+ ************************************************************************/
+ServerComm::~ServerComm()
+{
+ // delete communication object
+ if( admin ) delete admin;
+
+ actual_servercomm = 0;
+}
+
+/*************************************************************************
+ * Method name...: startRpcServer()
+ ************************************************************************/
+void rpcSignalHandler(int sig);
+void our_svc_run();
+
+void
+ServerComm::startRpcServer()
+ throw( r_Error )
+{
+ // create administraion object (O2 session is initialized)
+ admin = AdminIf::instance();
+ if( !admin )
+ throw r_Error( r_Error::r_Error_BaseDBMSFailed );
+
+ register SVCXPRT *transp;
+
+ // install a signal handler to catch alarm signals for garbage collection
+ signal( SIGALRM, garbageCollection );
+
+ RMInit::logOut << "Testing if no other rasdaman RPC server with my listenPort (0x"<< hex << listenPort << dec <<") is already running on this CPU..." << flush;
+
+
+ char* myName = new char[256];
+
+ if( gethostname( myName, 256 ) )
+ RMInit::logOut << endl << "Unable to determine my own hostname. Skipping this test." << endl;
+ else
+ if( clnt_create( myName, listenPort, RPCIFVERS, "tcp" ) )
+ {
+ RMInit::logOut << MSG_FAILED << endl;
+ exit( EXITCODE_ZERO );
+ }
+ else
+ RMInit::logOut << MSG_OK << endl;
+
+ delete[] myName;
+
+ (void) pmap_unset(listenPort, RPCIFVERS);
+
+ RMInit::logOut << "Creating UDP services..." << flush;
+ transp = svcudp_create(RPC_ANYSOCK);
+ if (transp == NULL)
+ {
+ RMInit::logOut << MSG_FAILED << endl;
+ throw r_Error( r_Error::r_Error_General );
+ }
+
+ RMInit::logOut << "registering UDP interface..." << flush;
+ if (!svc_register(transp, listenPort, RPCIFVERS, rpcif_1_caller, IPPROTO_UDP))
+ {
+ RMInit::logOut << MSG_FAILED << endl;
+ throw r_Error( r_Error::r_Error_General );
+ }
+ RMInit::logOut << MSG_OK << endl;
+
+ RMInit::logOut << "Creating TCP services..." << flush;
+ transp = svctcp_create(RPC_ANYSOCK, 0, 0);
+ if (transp == NULL)
+ {
+ RMInit::logOut << MSG_FAILED << endl;
+ throw r_Error( r_Error::r_Error_General );
+ }
+
+ RMInit::logOut << "registering TCP interface..." << flush;
+ if (!svc_register(transp, listenPort, RPCIFVERS, rpcif_1_caller, IPPROTO_TCP))
+ {
+ RMInit::logOut << MSG_FAILED << endl;
+ throw r_Error( r_Error::r_Error_General );
+ }
+ RMInit::logOut << MSG_OK << endl;
+
+ RMInit::logOut << "Setting alarm clock for next garbage collection to " << garbageCollectionInterval
+ << " secs..."; RMInit::logOut.flush();
+ alarm( (unsigned int)garbageCollectionInterval );
+ RMInit::logOut << MSG_OK << endl;
+
+ RMInit::logOut << "Global query optimization level is " << globalOptimizationLevel << "." << endl;
+
+ signal (SIGTERM, rpcSignalHandler);
+ informRasMGR(SERVER_AVAILABLE);
+ RMInit::logOut << "rasdaman server "<<serverName<<" is up." << endl;
+
+ // now wait for client calls (exception guarded)
+#ifdef PURIFY
+ purify_printf( "Server startup finished." );
+ purify_new_leaks();
+#endif
+ // svc_run();
+ our_svc_run();
+}
+
+extern "C" {
+ void garbageCollection( int );
+ void garbageCollectionDummy ( int );
+}
+
+void our_svc_run()
+{
+ ENTER( "our_svc_run" );
+
+ fd_set read_fd_set;
+
+ // TALK( "tcp_socket="<<get_socket(&svc_fdset,0) );
+
+ struct timeval timeout;
+ timeout.tv_sec= TIMEOUT_SELECT;
+ timeout.tv_usec=0;
+
+ while(1)
+ {
+ read_fd_set=svc_fdset;
+ TALK( "RPC Server is waiting..." );
+
+ int rasp=select(FD_SETSIZE,&read_fd_set,NULL,NULL,&timeout);
+ TALK( "RPC select returns: " << rasp );
+ if(rasp>0)
+ {
+ svc_getreqset(&read_fd_set);
+ TALK( "RPC Request executed." );
+ }
+
+ if(rasp<=0)
+ {
+ TALK( "our_svc_run(): Error: Timeout." ); // or a signal
+ // execute all pending callbacks. Redirect alarm signal first to make sure no
+ // reentrance is possible!
+
+ // these should abort any pending transaction
+ signal( SIGALRM, garbageCollectionDummy );
+ ServerComm::actual_servercomm->callback_mgr.executePending();
+ signal( SIGALRM, garbageCollection );
+ timeout.tv_sec= TIMEOUT_SELECT;
+ timeout.tv_usec=0;
+
+ if(accessControl.isClient()==false)
+ {
+ // regularly tell the rasmgr that we are available. There is a scenario for DoS-attack (or bug, or firewall-problem)
+ // when a client allocates itself a server and never calls, so the server is not usable any more.
+ // but we have to find a smarter way of doing this, we need rasmgr-rasserver communication!
+ ServerComm::actual_servercomm->informRasMGR(SERVER_REGULARSIG);
+ }
+ if(bMemFailed)
+ {
+ // no reason to continue
+ RMInit::logOut << "Internal error: rasserver: memory exhausted." << endl << flush;
+ exit( EXITCODE_ONE );
+ }
+ }
+ }
+
+ LEAVE( "our_svc_run" );
+}
+
+
+void rpcSignalHandler(int sig)
+{
+ static int in_progress=0; // our sema to prevent signal-in-signal
+
+ if (in_progress)
+ return;
+
+ in_progress = 1;
+
+ // busy wait
+#define SIGNAL_WAIT_CYCLES 1000000
+ for(long j=0;j<SIGNAL_WAIT_CYCLES;j++)
+ ;
+
+ // if we have a valid server, stop it
+ if(ServerComm::actual_servercomm)
+ {
+ ServerComm::actual_servercomm->stopRpcServer();
+ }
+} // rpcSignalHandler()
+
+void
+ServerComm::stopRpcServer()
+{
+ RMInit::logOut << "Shutdown request received." << endl;
+
+ // Determine when next garbage collection would have occured
+ unsigned long nextGarbColl = time( NULL );
+ struct itimerval rttimer;
+ getitimer( ITIMER_REAL, &rttimer );
+ nextGarbColl += rttimer.it_value.tv_sec;
+ RMInit::logOut << "Next garbage collection would have been in " << rttimer.it_value.tv_sec << " sec, at "
+ << ctime((time_t*)&nextGarbColl);
+
+ RMInit::logOut << "Unregistering interface...";
+ svc_unregister( listenPort, RPCIFVERS );
+
+ RMInit::logOut << "shutting down services...";
+ abortEveryThingNow();
+
+ RMInit::logOut << "informing rasmgr...";
+ informRasMGR(SERVER_DOWN);
+ RMInit::logOut << MSG_OK << endl;
+
+ RMInit::logOut << "rasdaman server " << serverName <<" is down." << endl;
+
+ exit(0);
+ // svc_exit();
+}
+
+// quick hack function used when stopping server to abort transaction and close db
+void
+ServerComm::abortEveryThingNow()
+{
+ ENTER( "ServerComm::abortEveryThingNow()" );
+
+ list<ServerComm::ClientTblElt*>::iterator iter;
+ ServerComm *sc=ServerComm::actual_servercomm;
+ iter = sc->clientTbl.begin();
+
+ while ( iter != sc->clientTbl.end() )
+ {
+ ServerComm::ClientTblElt *clnt = *iter;
+
+ clnt->transaction.abort();
+ clnt->database.close();
+
+ iter++;
+ }
+
+ LEAVE( "ServerComm::abortEveryThingNow()" );
+}
+
+/*************************************************************************
+ * rpcif_1_caller(struct svc_req *rqstp, SVCXPRT *transp)
+ * indirect caller for rpcif_1, which is automaticaly generated and can't
+ * be hand-edited. It provides services for parallel-processing
+ *************************************************************************/
+void rpcif_1_caller(struct svc_req *rqstp, SVCXPRT *transp)
+{
+ ENTER( "rpcif_1_caller(_,_)" );
+
+ bool flagTransactionReady=false;
+
+ bool isGetExtendedError=false;
+
+ switch (rqstp->rq_proc)
+ {
+ //case RPCCOMMITTA: no, closeDB only, because abortTA and commitTA
+ //case RPCABORTTA: do automatically a closeDB and both reporting to RasMGR "available" brings problems
+
+ case RPCCLOSEDB: flagTransactionReady=true; break;
+
+ case RPCGETERRORINFO: isGetExtendedError = true; break;
+ }
+
+ if(isGetExtendedError == false) ServerComm::actual_servercomm->clearExtendedErrorInfo();
+
+ char* errTxt = rpcif_1(rqstp,transp);
+
+ if(isGetExtendedError && bMemFailed) {
+ // the client got the message
+ // no reason to continue
+
+ signal( SIGALRM, garbageCollectionDummy );
+ ServerComm::actual_servercomm->callback_mgr.executePending();
+ RMInit::logOut << "Internal error: rasserver panic: memory exhausted, terminating forcefully." << endl << flush;
+ exit(1);
+ }
+
+ if (errTxt)
+ {
+ // this is not necessary, since the client gets an error code '42'
+ //RMInit::logOut << "rasserver: general exception from server caught by rpcif_1_caller!" << endl << errTxt << endl;
+ //RMInit::logOut.flush();
+ //cerr << "rasserver: general exception from server caught by rpcif_1_caller!" << endl << errTxt << endl;
+ ServerComm::actual_servercomm->setExtendedErrorInfo(errTxt);
+ free(errTxt);
+ errTxt = 0;
+
+ //Answer "Remote system error " to the client
+ //svcerr_systemerr (transp); don't think that's necessary any more, for the same reason
+ }
+
+ ServerComm::actual_servercomm->clientEndRequest();
+
+ if(flagTransactionReady)
+ ServerComm::actual_servercomm->informRasMGR(SERVER_AVAILABLE);
+
+ LEAVE( "rpcif_1_caller()" );
+}
+
+
+/*************************************************************************
+ * Method name...: informRasMGR( int what ) with a helper function
+ ************************************************************************/
+#include <errno.h>
+
+// writeWholeMessage:
+// send message via (open, connected) socket to rasmgr
+// called by informRasMGR.
+// return values:
+// -1 error
+// >0 success
+
+int writeWholeMessage(int socket,char *destBuffer,int buffSize)
+{
+ ENTER( "writeWholeMessage( socket=" << socket << ", destBuffer=" << (destBuffer?destBuffer:"(null)") << ", buffSize=" << buffSize << " )" );
+
+ // we write the whole message, including the ending '\0', which is already in
+ // the buffSize provided by the caller
+ int totalLength=0;
+ int writeNow;
+ while(1)
+ {
+ writeNow = write(socket,destBuffer+totalLength,buffSize-totalLength);
+ if(writeNow == -1)
+ {
+ TALK( "writeWholeMessage: bad socket write returned " << writeNow << ", errno=" << errno );
+ if(errno == EINTR)
+ continue; // read was interrupted by signal (on bad SO's)
+ LEAVE( "writeWholeMessage(): error, errno=" << errno );
+ return -1; // another error
+ }
+ totalLength+=writeNow;
+
+ if( totalLength==buffSize )
+ break; // THE END
+ }
+
+ LEAVE( "writeWholeMessage() -> " << totalLength );
+ return totalLength;
+}
+
+
+long infCount=0; // for debug only
+
+// ServerComm::informRasMGR:
+// send message code to rasmgr (e.g., "still alive"), incl socket management
+// return code:
+// none, but function does exit() on error 8-()
+void ServerComm::informRasMGR( int what )
+{
+ ENTER( "ServerComm::informRasMGR, what=" << what );
+ TALK( "Informing dispatcher " << rasmgrHost << " port=" << rasmgrPort << " that server is available" );
+ //what: 0 - going down
+ // 1 - available
+ // 2 - regular signal
+
+ if (what == SERVER_AVAILABLE)
+ accessControl.resetForNewClient();
+
+ struct protoent* getprotoptr = getprotobyname("tcp");
+ struct hostent *hostinfo = gethostbyname(rasmgrHost);
+ if (hostinfo==NULL)
+ {
+ cerr<< serverName<<": informRasMGR: cannot locate RasMGR host "<<rasmgrHost<<" ("<<strerror(errno)<<')'<<endl;
+ RMInit::logOut << "informRasMGR: cannot locate RasMGR host "<<rasmgrHost<<" ("<<strerror(errno)<<')'<<endl;
+ LEAVE( "ServerComm::informRasMGR: cannot locate RasMGR host "<<rasmgrHost << ": " << strerror(errno) );
+ return;
+ }
+
+ sockaddr_in internetSocketAddress;
+ internetSocketAddress.sin_family = AF_INET;
+ internetSocketAddress.sin_port=htons(rasmgrPort);
+ internetSocketAddress.sin_addr=*(struct in_addr*)hostinfo->h_addr;
+
+ int sock; // socket for rasmgr communication
+ bool ok=false; // did we get a socket?
+
+ // FIXME: This is _extremely_ ugly. Should be something like
+ // 10 retries, with exponentially growing waits, such as 0, 1ms, 2ms, 4ms, ...
+ // have prepared defs, but code is the original one. -- PB 2003-nov-15
+ // long maxRetry = NUM_RETRIES_SERVER_ALIVE;
+ // #define NUM_RETRIES_SERVER_ALIVE 10
+
+ long retry =0;
+ long maxRetry=10000000; // ten millions!
+ long talkInterval=100000;
+ // creating socket
+ for(retry=0;retry<maxRetry;retry++)
+ {
+ int result;
+
+ // BEWARE, is this relevant? -- PB 2003-nov-15
+ // man 7 socket says:
+ // "Under some circumstances (e.g. multiple processes
+ // accessing a single socket), the condition that caused
+ // the SIGIO may have already disappeared when the process
+ // reacts to the signal. If this happens, the process
+ // should wait again because Linux will resend the signal later."
+
+ sock=socket(PF_INET,SOCK_STREAM,getprotoptr->p_proto);
+ TALK( "Socket=" << sock << " protocol(tcp)=" << getprotoptr->p_proto );
+
+ if(sock<0)
+ {
+ // if ( (retry%talkInterval) == 0)
+ {
+ cerr << "Error in server '" << serverName << "': cannot open socket to rasmgr, (" << strerror(errno) << ')' << " still retrying..." << endl;
+ TALK( "ServerComm::informRasMGR: cannot open socket to RasMGR: " << strerror(errno) << "; retry " << retry << " of " << maxRetry );
+ RMInit::logOut << "Error: cannot open socket to rasmgr, (" << strerror(errno) << ')'<<endl;
+ }
+ continue;
+ }
+ result = connect(sock,(struct sockaddr*)&internetSocketAddress,sizeof(internetSocketAddress));
+ TALK( "connect(socket=" << sock << ",htons(" << rasmgrPort << ")=" << internetSocketAddress.sin_port << ",in_addr=" << internetSocketAddress.sin_addr.s_addr << ")->" << result );
+ if (result < 0)
+ {
+ // if( (retry%talkInterval) == 0)
+ {
+ cerr << "Error in server '" << serverName << "': Connection to rasmgr failed (still retrying): "<<strerror(errno);
+ cerr << ". retry #" << retry << " of " << maxRetry << endl;
+ TALK( "ServerComm::informRasMGR: cannot connect to RasMGR: " << strerror(errno) << "; retry " << retry << " of " << maxRetry );
+ RMInit::logOut <<"Error: Cannot connect to rasmgr ("<<strerror(errno)<<')';
+ RMInit::logOut << " retry #" << retry << " of " << maxRetry << endl;
+ }
+ close(sock); //yes, some SO require this, like Tru64
+ continue;
+ }
+ ok = true;
+ break;
+ } // for
+
+ if ( !ok )
+ {
+ cerr << "Error in server '" << serverName << "': Giving up on connecting, terminating." << endl;
+ RMInit::logOut << "Error: Giving up on connecting, terminating." << endl;
+ if (sock)
+ close(sock);
+
+ // FIXME: see below
+ exit( EXITCODE_RASMGR_FAILED );
+ }
+
+ // create HTTP message
+ char message[200];
+ sprintf(message,"%s%d\r\n\r\n%s %d %ld ","POST rasservernewstatus HTTP/1.1\r\nUserAgent: RasServer/1.0\r\nContent-length: ",strlen(serverName)+3,serverName,what,infCount++);
+
+ // writing message;
+ if(writeWholeMessage(sock,message,strlen(message)+1)<0)
+ {
+ RMInit::logOut <<"Error: Connection to rasmgr failed. ("<<strerror(errno)<<')'<<endl;
+ close(sock);
+
+ // FIXME: extremely ugly. replace by retcode which
+ // prevents rasserver from going into svc_run loop
+ // -- PB 2003-nov-15
+ exit( EXITCODE_RASMGR_FAILED );
+ }
+ close(sock);
+
+ LEAVE( "ServerComm::informRasMGR, ok=" << ok << ", retries=" << retry );
+} // ServerComm::informRasMGR()
+
+
+/*************************************************************************
+ * Method name...: getClientContext( unsigned long clientId )
+ ************************************************************************/
+ServerComm::ClientTblElt*
+ServerComm::getClientContext( unsigned long clientId )
+{
+ ENTER( "ServerComm::getClientContext( " << clientId << " )" );
+
+ ClientTblElt* returnValue=0;
+
+ if( !clientTbl.empty() )
+ {
+ list<ClientTblElt*>::iterator iter;
+
+ iter = clientTbl.begin();
+ while( iter != clientTbl.end() && (*iter)->clientId != clientId )
+ {
+ TALK( " inspecting entry with clientID " << (*iter)->clientId );
+ iter++;
+ }
+
+ if( iter != clientTbl.end() && clientId && (*iter)->clientId == clientId )
+ {
+ returnValue = *iter;
+
+ // Valid entry was found, so increase the number of current users and
+ // reset the client's lastActionTime to now.
+
+ (*iter)->currentUsers++;
+ (*iter)->lastActionTime = time( NULL );
+ TALK( "valid entry found, current users now: " << (*iter)->currentUsers );
+ }
+ }
+
+ // this output will be done lateron, in the caller:
+ // if( returnValue == 0 )
+ // RMInit::logOut << "Error: client not registered." << endl;
+
+ // this trick did not work, broke the HTTP server
+ // if(isHttpServer==false ) uniqueClientContext = returnValue;
+
+#ifdef RMANDEBUG
+ ServerComm::printServerStatus( RMInit::logOut ); // pretty verbose
+#endif
+
+ LEAVE( "ServerComm::getClientContext()" );
+ return returnValue;
+}
+
+void
+ServerComm::clientEndRequest()
+{
+ ENTER( "ServerComm::clientEndRequest()" );
+
+#ifdef RMANDEBUG
+ printServerStatus( RMInit::dbgOut ); // pretty verbose
+#endif
+
+ // this trick did not work, broke the HTTp server
+
+ // if(isHttpServer==false && uniqueClientContext != NULL)
+ // uniqueClientContext->endRequest();
+
+ LEAVE( "ServerComm::clientEndRequest()" );
+}
+
+/*************************************************************************
+ * Method name...: printServerStatus( )
+ ************************************************************************/
+void
+ServerComm::printServerStatus( ostream& s )
+{
+ unsigned long currentTime = time(NULL);
+
+ s << "Server state information at " << endl; // << ctime((time_t*)&currentTime) << endl;
+ s << " Inactivity time out of clients.: " << clientTimeout << " sec" << endl;
+ s << " Server management interval.....: " << garbageCollectionInterval << " sec" << endl;
+ s << " Transaction active.............: " << ( transactionActive ? "yes" : "no" ) << endl;
+ s << " Max. transfer buffer size......: " << maxTransferBufferSize << " bytes" << endl;
+ s << " Next available cliend id.......: " << clientCount+1 << endl;
+ s << " No. of client table entries....: " << clientTbl.size() << endl << endl;
+
+ if( !clientTbl.empty() )
+ {
+ list<ClientTblElt*>::iterator iter;
+
+ // display contents of client table
+ s << "client table dump---------------------------------------------" << endl;
+ for( iter = clientTbl.begin(); iter != clientTbl.end(); iter++ )
+ {
+ if (*iter==NULL)
+ {
+ s << "Error: null context found." << endl;
+ RMInit::logOut << "Error: null context found." << endl;
+ continue;
+ }
+
+ s << "Client ID : " << (*iter)->clientId << endl
+ << "Current Users : " << (*iter)->currentUsers << endl
+ << "Client location: " << (*iter)->clientIdText << endl
+ << "User name : " << (*iter)->userName << endl
+ << "Database in use: " << (*iter)->baseName << endl
+ << "Creation time : " << endl // ctime((time_t*)&(*iter)->creationTime)
+ << "Last action at : " << endl // ctime((time_t*)&(*iter)->lastActionTime)
+ << "MDD collection : " << (*iter)->transferColl << endl
+ << "MDD iterator : " << (*iter)->transferCollIter << endl
+ << "Current PersMDD: " << (*iter)->assembleMDD << endl
+ << "Current MDD : " << (*iter)->transferMDD << endl
+ << "Tile vector : " << (*iter)->transTiles << endl
+ << "Tile iterator : " << (*iter)->tileIter << endl
+ << "Block byte cntr: " << (*iter)->bytesToTransfer << endl << endl;
+ }
+ s << "end client table dump-----------------------------------------" << endl;
+
+ }
+
+ /*
+ s << "memory map----------------------------------------------------" << endl;
+
+ // memorymap(1);
+
+ struct mallinfo meminfo = mallinfo();
+
+ s << "space in arena : " << meminfo.arena << endl;
+ s << "number of small blocks : " << meminfo.smblks << endl;
+ s << "number of ordinary blocks : " << meminfo.ordblks << endl;
+ s << "space in free ordinary blocks : " << meminfo.fordblks << endl;
+ s << "space in used ordinary blocks : " << meminfo.uordblks << endl;
+
+ s << "additional space from last call: " << meminfo.uordblks - memUsed << endl;
+
+ memUsed = meminfo.uordblks;
+
+ s << "end memory map------------------------------------------------" << endl << endl;
+*/
+}
+
+
+
+/*************************************************************************
+ * Method name...: getServerStatus( )
+ ************************************************************************/
+void
+ServerComm::getServerStatus( ServerStatRes& returnStruct )
+{
+ returnStruct.inactivityTimeout = clientTimeout;
+ returnStruct.managementInterval = garbageCollectionInterval;
+ returnStruct.transactionActive = transactionActive;
+ returnStruct.maxTransferBufferSize = maxTransferBufferSize;
+ returnStruct.nextClientId = clientCount+1;
+ returnStruct.clientNumber = clientTbl.size();
+
+ if( !clientTbl.empty() )
+ {
+ list<ClientTblElt*>::iterator iter;
+ int i;
+
+ returnStruct.clientTable.clientTable_len = clientTbl.size();
+ returnStruct.clientTable.clientTable_val = (RPCClientEntry*) mymalloc( sizeof(RPCClientEntry) * clientTbl.size() );
+
+ for( iter = clientTbl.begin(), i=0; iter != clientTbl.end(); iter++, i++ )
+ {
+ returnStruct.clientTable.clientTable_val[i].clientId = (*iter)->clientId;
+ returnStruct.clientTable.clientTable_val[i].clientIdText = strdup( (*iter)->clientIdText );
+ returnStruct.clientTable.clientTable_val[i].userName = strdup( (*iter)->userName );
+ returnStruct.clientTable.clientTable_val[i].baseName = strdup( (*iter)->baseName );
+ returnStruct.clientTable.clientTable_val[i].creationTime = (*iter)->creationTime;
+ returnStruct.clientTable.clientTable_val[i].lastActionTime = (*iter)->lastActionTime;
+ returnStruct.clientTable.clientTable_val[i].transferColl = (unsigned long)((*iter)->transferColl);
+ returnStruct.clientTable.clientTable_val[i].transferIter = (unsigned long)((*iter)->transferCollIter);
+ returnStruct.clientTable.clientTable_val[i].assembleMDD = (unsigned long)((*iter)->assembleMDD);
+ returnStruct.clientTable.clientTable_val[i].transferMDD = (unsigned long)((*iter)->transferMDD);
+ returnStruct.clientTable.clientTable_val[i].transTiles = (unsigned long)((*iter)->transTiles);
+ returnStruct.clientTable.clientTable_val[i].tileIter = (unsigned long)((*iter)->tileIter);
+ returnStruct.clientTable.clientTable_val[i].bytesToTransfer = (*iter)->bytesToTransfer;
+ }
+ }
+
+ struct mallinfo meminfo = mallinfo();
+
+ returnStruct.memArena = meminfo.arena;
+ returnStruct.memSmblks = meminfo.smblks;
+ returnStruct.memOrdblks = meminfo.ordblks;
+ returnStruct.memFordblks = meminfo.fordblks;
+ returnStruct.memUordblks = meminfo.uordblks;
+}
+
+
+/*************************************************************************
+ * Method name...: addClientTblEntry( ClientTblElt *context )
+ ************************************************************************/
+void
+ServerComm::addClientTblEntry( ClientTblElt *context ) throw ( r_Error )
+{
+ ENTER( "addClientTblEntry()" );
+
+ if (context==NULL)
+ {
+ RMInit::logOut << "Error: ServerComm::addClientTblEntry(): client context is NULL." << endl;
+ throw r_Error( r_Error::r_Error_RefNull );
+ }
+
+ clientTbl.push_back( context );
+
+#ifdef RMANDEBUG
+ ServerComm::printServerStatus( RMInit::logOut ); // quite verbose
+#endif
+
+ LEAVE( "addClientTblEntry()" );
+}
+
+
+/*************************************************************************
+ * Method name...: deleteClientTblEntry( unsigned long clientId )
+ ************************************************************************/
+unsigned short
+ServerComm::deleteClientTblEntry( unsigned long clientId )
+{
+ ENTER( "deleteClientTblEntry( " << clientId << " )" );
+
+ unsigned short returnValue = 0;
+
+ ClientTblElt* context = getClientContext( clientId );
+
+ if( !context )
+ {
+ TALK( "Warning: in ServerComm::deleteClientTblEntry(): null context, " << "client " << clientId << " not found." );
+ return 1; // desired client id was not found in the client table
+ }
+
+ if( context->currentUsers > 1 )
+ {
+ // In this case, the client table entry was under use before our getClientContext() call.
+ context->release();
+ TALK( "Client context of user "<<clientId<<" has current users ="<<context->currentUsers );
+ return 2;
+ }
+
+ // The transaction contained in the client table element is aborted here.
+ // This is reasonable because at this point, the transaction is either
+ // already committed (This is the case if an rpcCloseDB call arrives.
+ // In this case, abort doesn't do anything harmful.) or the communication
+ // has broken down before a rpcCommitTA or a rpcAbortTA (In this case this
+ // function is called by the garbage collection and aborting the transaction
+ // is advisable.).
+
+ context->releaseTransferStructures();
+
+ // If the current transaction belongs to this client, abort it.
+ if( transactionActive == clientId )
+ {
+ RMInit::logOut << "aborting transaction..." << RMInit::logOut.flush();
+ context->transaction.abort();
+ transactionActive = 0;
+ }
+
+ // close the database if it isn't already closed
+ // (e.g. after connection breakdowns)
+ if( strcmp( context->baseName, "none" ) != 0 )
+ {
+ RMInit::logOut << "closing database..." << RMInit::logOut.flush();
+
+ context->database.close();
+
+ // reset database name
+ delete[] context->baseName;
+ context->baseName = new char[5];
+ strcpy( context->baseName, "none" );
+ }
+
+#ifdef RMANDEBUG
+ ServerComm::printServerStatus( RMInit::logOut ); // can be pretty verbose
+#endif
+
+ // remove the entry from the client table
+ list<ClientTblElt*>::iterator iter;
+ for( iter=clientTbl.begin(); iter != clientTbl.end() && (*iter)->clientId != clientId; iter++ )
+ ;
+ if ( iter != clientTbl.end() )
+ clientTbl.erase( iter );
+
+ // delete the client table entry data itself
+ // (delete is controlled by the destructor of the ClientTblElt object)
+ delete context;
+
+ TALK( "client table now has " << clientTbl.size() << " entries." );
+
+ LEAVE( "deleteClientTblEntry()" );
+ return returnValue;
+}
+
+/*************************************************************************
+ * Method name...: ServerComm::getExtendedErrorInfo()
+ ************************************************************************/
+
+const char *
+ServerComm::getExtendedErrorInfo()
+{
+ if(errorText == NULL)
+ return "(no error info)";
+
+ return errorText;
+}
+
+/*************************************************************************
+ * Method name...: ServerComm::getExtendedErrorInfo()
+ ************************************************************************/
+
+void ServerComm::setExtendedErrorInfo(const char *newErrorText)
+{
+ clearExtendedErrorInfo();
+
+ errorText = new char [strlen(newErrorText)+1];
+ strcpy(errorText,newErrorText);
+}
+
+
+/*************************************************************************
+ * Method name...: ServerComm::getExtendedErrorInfo()
+ ************************************************************************/
+
+void ServerComm::clearExtendedErrorInfo()
+{
+ if(errorText) delete[] errorText;
+
+ errorText = NULL;
+}
+
+/*************************************************************************
+ * Method name...: ClientTblElt( const char* clientText,
+ * unsigned long client ) (constructor)
+ ************************************************************************/
+ServerComm::ClientTblElt::ClientTblElt( const char* clientText, unsigned long client )
+ : clientId( client ),
+ currentUsers(0),
+ clientIdText(0),
+ userName(0),
+ baseName(0),
+ creationTime(0),
+ lastActionTime(0),
+ transferFormat(r_Array),
+ transferFormatParams(0),
+ exactFormat(1),
+ storageFormat(r_Array),
+ storageFormatParams(0),
+ encodedData(0),
+ encodedSize(0),
+ totalRawSize(0),
+ totalTransferedSize(0),
+ transferColl(0),
+ transferCollIter(0),
+ transferData(0),
+ transferDataIter(0),
+ assembleMDD(0),
+ transferMDD(0),
+ transTiles(0),
+ tileIter(0),
+ deletableTiles(0),
+ bytesToTransfer(0),
+ persMDDCollections(0),
+ taTimer(0),
+ transferTimer(0),
+ evaluationTimer(0),
+ clientParams(0)
+{
+ ENTER( "ServerComm::ClientTblElt::ClientTblElt( clientText=" << (clientText?clientText:"(null)") << ", client=0x" << hex << client << dec << " )" );
+
+ creationTime = time( NULL );
+
+ clientIdText = new char[strlen(clientText)+1];
+ strcpy( clientIdText, clientText );
+
+ baseName = new char[5];
+ strcpy( baseName, "none" );
+
+ userName = new char[8];
+ strcpy( userName, "unknown" );
+
+ clientParams = new r_Parse_Params();
+ clientParams->add("exactformat", &exactFormat, r_Parse_Params::param_type_int);
+
+ LEAVE( "ServerComm::ClientTblElt::ClientTblElt()" );
+}
+
+
+ServerComm::ClientTblElt::~ClientTblElt()
+{
+ releaseTransferStructures();
+
+ // delete the clientIdText member
+ delete[] clientIdText;
+ // delete the baseName member
+ delete[] baseName;
+ // delete user name
+ delete[] userName;
+ // delete transfer format parameters
+ if (transferFormatParams != NULL)
+ delete [] transferFormatParams;
+
+ if (storageFormatParams != NULL)
+ delete [] storageFormatParams;
+
+ if(clientParams)
+ delete clientParams;
+}
+
+
+void
+ServerComm::ClientTblElt::release()
+{
+ if( currentUsers == 0 )
+ RMInit::logOut << "Warning: releasing a non-active client." << endl;
+
+ currentUsers--;
+ lastActionTime = time( NULL );
+}
+
+void
+ServerComm::ClientTblElt::endRequest()
+{
+ if(currentUsers != 0)
+ RMInit::logOut << "Warning: Client ended request without releasing context. Forcing release now." << endl;
+
+ currentUsers=0;
+ lastActionTime = time( NULL );
+}
+
+void
+ServerComm::ClientTblElt::releaseTransferStructures()
+{
+ ENTER( "ServerComm::ClientTblElt::releaseTransferStructures()" );
+ RMDBGENTER(2, RMDebug::module_servercomm, "ServerComm::ClientTblElt", "releaseTransferStructures()")
+ // delete the transfer iterator
+
+ if( transferCollIter )
+ {
+ RMDBGMIDDLE(2, RMDebug::module_servercomm, "ServerComm::ClientTblElt", "release transferCollIter" )
+ delete transferCollIter;
+ transferCollIter = 0;
+ }
+
+ // delete transfer data
+ if( transferData )
+ {
+ RMDBGMIDDLE(2, RMDebug::module_servercomm, "ServerComm::ClientTblElt", "release transferData" )
+
+ QtNode::QtDataList::iterator dataIter;
+
+ // delete list elements
+ for( dataIter=transferData->begin(); dataIter!=transferData->end(); dataIter++ )
+ if( *dataIter )
+ {
+ // Note: The following consistency check does not hold for the case when data objects occur
+ // more than once in the result set (e.g., constants).
+
+ // Consistency Check: should be the last reference.
+ // if( (*dataIter)->getRefNo() > 1 )
+ // {
+ // RMInit::logOut << endl << "Internal error in releaseTransferStructures: references left, object " << RMInit::logOut.flush();
+ // (*dataIter)->printStatus( RMInit::logOut );
+ // RMInit::logOut << endl;
+ // }
+
+ // Just tupel elements which are not further referenced are deleted.
+ if (*dataIter)
+ {
+ (*dataIter)->deleteRef();
+ (*dataIter) = 0;
+ }
+ }
+ delete transferData;
+ transferData = 0;
+ }
+
+ // delete the transfer collection
+ // the transferData will check objects because of the bugfix. therefore the objects may deleted only after the check.
+ if( transferColl )
+ {
+ RMDBGMIDDLE(2, RMDebug::module_servercomm, "ServerComm::ClientTblElt", "release transferColl" )
+ transferColl->releaseAll();
+ delete transferColl;
+ transferColl = 0;
+ }
+
+ // delete transfer data iterator
+ if( transferDataIter )
+ {
+ RMDBGMIDDLE(2, RMDebug::module_servercomm, "ServerComm::ClientTblElt", "release transferDataIter" )
+ delete transferDataIter;
+ transferDataIter = 0;
+ }
+
+ // delete the temporary PersMDDObj
+ if( assembleMDD )
+ {
+ RMDBGMIDDLE(2, RMDebug::module_servercomm, "ServerComm::ClientTblElt", "release assembleMDD" )
+ delete assembleMDD;
+ assembleMDD = 0;
+ }
+
+ // delete the transfer MDDobj
+ if( transferMDD )
+ {
+ RMDBGMIDDLE(2, RMDebug::module_servercomm, "ServerComm::ClientTblElt", "release transferMDD" )
+ delete transferMDD;
+ transferMDD = 0;
+ }
+
+ // vector< Tile* >* transTiles;
+ if( transTiles )
+ {
+ RMDBGMIDDLE(2, RMDebug::module_servercomm, "ServerComm::ClientTblElt", "release transTiles" )
+ // Tiles are deleted by the MDDObject owing them.
+ // release( transTiles->begin(), transTiles->end() );
+ delete transTiles;
+ transTiles = 0;
+ }
+
+ // vector< Tile* >::iterator* tileIter;
+ if( tileIter )
+ {
+ RMDBGMIDDLE(2, RMDebug::module_servercomm, "ServerComm::ClientTblElt", "release tileIter" )
+ delete tileIter;
+ tileIter = 0;
+ }
+
+ // delete deletable tiles
+ if( deletableTiles )
+ {
+ RMDBGMIDDLE(2, RMDebug::module_servercomm, "ServerComm::ClientTblElt", "release deletableTiles" )
+
+ vector<Tile*>::iterator iter;
+
+ for( iter=deletableTiles->begin(); iter!=deletableTiles->end(); iter++ )
+ if( *iter )
+ delete *iter;
+
+ delete deletableTiles;
+ deletableTiles = 0;
+ }
+
+ // delete persistent MDD collections
+ if( persMDDCollections )
+ {
+ RMDBGMIDDLE(2, RMDebug::module_servercomm, "ServerComm::ClientTblElt", "release persMDDCollections" )
+
+ vector<MDDColl*>::iterator collIter;
+
+ for( collIter=persMDDCollections->begin(); collIter!=persMDDCollections->end(); collIter++ )
+ if( *collIter )
+ {
+ RMDBGMIDDLE(2, RMDebug::module_servercomm, "ServerComm::ClientTblElt", "before PersMDDColl::releaseAll()" )
+ (*collIter)->releaseAll();
+ RMDBGMIDDLE(2, RMDebug::module_servercomm, "ServerComm::ClientTblElt", "after PersMDDColl::releaseAll()" )
+ delete *collIter;
+ }
+
+ delete persMDDCollections;
+ persMDDCollections = 0;
+ }
+
+ // transfer compression
+ if (encodedData != NULL)
+ {
+ free(encodedData);
+ encodedData = NULL; encodedSize = 0;
+ }
+
+#ifdef RMANBENCHMARK
+ // Attention: taTimer is deleted in either commitTA() or abortTA().
+
+ if( evaluationTimer ) delete evaluationTimer;
+ evaluationTimer = 0;
+
+ if( transferTimer ) delete transferTimer;
+ transferTimer = 0;
+#endif
+ RMDBGEXIT(2, RMDebug::module_servercomm, "ServerComm::ClientTblElt", "releaseTransferStructures()")
+ LEAVE( "ServerComm::ClientTblElt::releaseTransferStructures()" );
+}
+
+
+/******************************************************************************************
+*** This class shouldn't be here, later it will be put in its own file
+******************************************************************************************/
+
+// learned from license.cc
+#ifdef LINUX
+extern "C" {
+ extern char *strptime __P ((__const char *__s, __const char *__fmt, struct tm *__tp));
+}
+#endif
+
+AccessControl accessControl;
+
+
+AccessControl::AccessControl()
+{
+ initDeltaT=0;
+ resetForNewClient();
+}
+
+AccessControl::~AccessControl()
+{
+}
+
+void AccessControl::setServerName(const char *serverName)
+{
+ strcpy(this->serverName,serverName);
+}
+
+void AccessControl::initSyncro(const char *syncroString)
+{
+ struct tm brokentime;
+ strptime(syncroString,"%d:%m:%Y:%H:%M:%S",&brokentime);
+ initDeltaT= difftime (time(NULL) ,mktime(&brokentime) );
+ // cout<<"DeltaT="<<initDeltaT<<endl;
+}
+
+void AccessControl::resetForNewClient()
+{
+ okToRead=false;
+ okToWrite=false;
+ weHaveClient=false;
+}
+
+bool AccessControl::isClient()
+{
+ return weHaveClient;
+}
+
+int AccessControl::crunchCapability(const char *capability)
+{
+ ENTER( "AccessControl::crunchCapability( capability=" << (capability?capability:"(null)") << " )" );
+
+ // verify capability is original
+ char capaQ[200];
+ strcpy(capaQ,"$Canci"); strcat(capaQ,capability);
+
+ char *digest=strstr(capaQ,"$D");
+ if(digest==NULL)
+ {
+ LEAVE( "AccessControl::crunchCapability(): error: digest not found -> " << CAPABILITY_REFUSED );
+ return CAPABILITY_REFUSED;
+ }
+
+ *digest=0;
+ digest++;digest++;
+ digest[32]=0;
+ TALK( "Digest="<<digest );
+
+ char testdigest[50];
+ messageDigest(capaQ,testdigest,"MD5");
+ TALK( "testdg="<<testdigest );
+ if(strcmp(testdigest,digest)!=0)
+ {
+ LEAVE( "AccessControl::crunchCapability() digest error on '" << digest << "' -> " << CAPABILITY_REFUSED );
+ return CAPABILITY_REFUSED;
+ }
+
+ char *rights=strstr(capaQ,"$E")+2;
+ char *timeout=strstr(capaQ,"$T")+2;
+ char *cServerName=strstr(capaQ,"$N")+2;
+ // end of cServername is $D, $->0 by digest
+
+ struct tm brokentime;
+ strptime(timeout,"%d:%m:%Y:%H:%M:%S",&brokentime);
+ double DeltaT= difftime (mktime(&brokentime),time(NULL) );
+
+ //for the moment, DEC makes trouble
+ // if(DeltaT < initDeltaT) return CAPABILITY_REFUSED; //!!! Capability too old
+ // cout<<"DeltaT="<<DeltaT<<" initDeltaT="<<initDeltaT<<(DeltaT >= initDeltaT ? " ok":" fail")<<endl;
+
+ if(strcmp(serverName,cServerName)!=0)
+ {
+ LEAVE( "AccessControl::crunchCapability() -> server name doesn't match, got: " << cServerName << ", need: " << serverName << " -> " << CAPABILITY_REFUSED );
+ return CAPABILITY_REFUSED; //!!! Call is not for me
+ }
+
+ okToRead = false; // looks like a 'true' never gets reset: -- PB 2006-jan-02
+ okToWrite = false; // -dito-
+ for(int i=0;*rights!='$' && *rights && i<2; rights++,i++)
+ {
+ //We only have 2 rights defined now
+ if(*rights=='R')
+ okToRead = true;
+ if(*rights=='W')
+ okToWrite= true;
+ }
+
+ weHaveClient=true;
+
+ TALK( "capability crunched: digest=" << digest << ", rights=" << rights << ", timeout=" << timeout << "(remaining time: " << DeltaT << "), cServerName=" << cServerName << ", okToRead=" << okToRead << ", okToWrite=" << okToWrite << "" );
+
+ LEAVE( "AccessControl::crunchCapability() -> 0 (ok)" );
+ return 0; // OK for now
+}
+
+int AccessControl::messageDigest(const char *input,char *output,const char *mdName)
+{
+ EVP_MD_CTX mdctx;
+ const EVP_MD *md;
+ unsigned int md_len, i;
+ unsigned char md_value[100];
+
+ OpenSSL_add_all_digests();
+
+ md = EVP_get_digestbyname(mdName);
+
+ if(!md)
+ return 0;
+
+ EVP_DigestInit(&mdctx, md);
+ EVP_DigestUpdate(&mdctx,input, strlen(input));
+ EVP_DigestFinal(&mdctx, md_value, &md_len);
+
+ for(i = 0; i < md_len; i++)
+ sprintf(output+i+i,"%02x", md_value[i]);
+
+ return strlen(output);
+}
+
+void AccessControl::wantToRead()
+{
+ if(okToRead==false)
+ {
+ TALK( "AccessControl::wantToRead(): error: no permission for read operation." );
+ throw r_Eno_permission(); //r_Error(NO_PERMISSION_FOR_OPERATION);
+ }
+}
+
+void AccessControl::wantToWrite()
+{
+ if(okToWrite==false)
+ {
+ TALK( "AccessControl::wantToWrite(): error: no permission for write operation." );
+ throw r_Eno_permission(); //r_Error(NO_PERMISSION_FOR_OPERATION);
+ }
+
+}
+
+
diff --git a/servercomm/servercomm.hh b/servercomm/servercomm.hh
new file mode 100644
index 0000000..2d34e69
--- /dev/null
+++ b/servercomm/servercomm.hh
@@ -0,0 +1,1120 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INCLUDE: servercomm.hh
+ *
+ * MODULE: servercomm
+ * CLASS: ServerComm
+ *
+ * COMMENTS:
+ * None
+*/
+
+#ifndef _SERVERCOMM_
+#define _SERVERCOMM_
+
+// Put it in front of any typedef bool ... because o2 is using bool as a variable.
+// #include "o2template_CC.hxx"
+
+#include <list>
+
+#include <rpc/rpc.h>
+#include "raslib/error.hh"
+#include "raslib/oid.hh"
+#include "raslib/minterval.hh"
+
+#include "reladminif/adminif.hh"
+#include "reladminif/databaseif.hh"
+#include "reladminif/transactionif.hh"
+#include "relcatalogif/basetype.hh"
+
+#include "servercomm/callbackmgr.hh"
+
+#ifndef _RPCIF_
+ #define _RPCIF_
+ #include "clientcomm/rpcif.h"
+#endif
+
+#ifdef DECALPHA
+#include <rpc/svc.h>
+#endif
+
+// forward declarations
+class QtData;
+class MDDObj;
+class MDDCollIter;
+class MDDColl;
+class RMTimer;
+class r_Parse_Params;
+
+//@ManMemo: Module: {\bf servercomm}
+
+/*@Doc:
+ The class servercomm describes the one and only server communication object
+ that can exist in a RasDaMan RPC server. It manages listening for client and
+ maps incoming calls to the respective remote procedures (which reside in the
+ file manager.cc). These remote procedures are global functions
+ which mainly concern with RPC call processing and finally call the methods
+ of this servercomm class to forward client requests.
+*/
+
+class ServerComm
+{
+ public:
+
+ /// the class defines an entry of the client table
+ class ClientTblElt
+ {
+ public:
+ /// default constructor
+ ClientTblElt( const char* clientIdText, unsigned long clientId );
+ /**
+ Default constructor that takes the information to be placed in the
+ clientIdText field of the client table entry and the unique ID to
+ be placed in the clientId field.
+ */
+
+ /// destructor
+ ~ClientTblElt();
+
+ /// release client context
+ void release();
+ /**
+ Releasing the client context means to decrease the currentUsers counter
+ and to update lastActionTime.
+ */
+
+ void endRequest();
+
+ /// releases transfer collection/iterator
+ void releaseTransferStructures();
+ /**
+ The method releases transfer collection and iterator. As the collection is a
+ persistent one, care has to be taken that creation and deletion is done
+ within the same transaction.
+ */
+
+ /// unique client identification assigned by the server
+ unsigned long clientId;
+
+ /// counter indicating the number of current users
+ unsigned int currentUsers;
+
+ /// binding information about the client (IP address and TCP port number)
+ char* clientIdText;
+
+ /// Name of the client user name (if available)
+ char* userName;
+
+ /// Name of the actual database (if one is open)
+ char* baseName;
+
+ /// time when the database was opened (for curiosity purposes)
+ unsigned long creationTime;
+
+ /// time of the client's last action (for garbage collection purposes)
+ unsigned long lastActionTime;
+
+ /// convert raw array data to this data format before transfer
+ r_Data_Format transferFormat;
+ char* transferFormatParams;
+ /// send data to client in the exact transfer format
+ int exactFormat;
+ /// store array data in this data format in the database
+ r_Data_Format storageFormat;
+ char* storageFormatParams;
+
+ /// the tile data converted into the transfer format, if required
+ void* encodedData;
+ unsigned long encodedSize;
+ /// for establishing the compression ratio
+ unsigned long totalRawSize;
+ unsigned long totalTransferedSize;
+
+ /// pointer to an MDD collection
+ MDDColl* transferColl;
+ /**
+ For collection of MDD constants with an update query.
+ */
+
+ /// pointer to an iterator for collection transferColl
+ MDDCollIter* transferCollIter;
+
+ /// pointer to the query result which is currently in transfer
+ std::vector<QtData*>* transferData;
+ /**
+ For the result of the last query (NULL if the result is completely delivered to the client).
+ */
+
+ /// point to an iterator for transfer data
+ std::vector<QtData*>::iterator* transferDataIter;
+
+ /// pointer to a persistent MDD object for tile based transfers
+ MDDObj* assembleMDD;
+
+ /// pointer to an MDD object for tile base transfer
+ MDDObj* transferMDD;
+
+ /// std::vector storing tiles of actual MDD for transfer
+ std::vector< Tile* >* transTiles;
+
+ /// iterator for the std::vector above
+ std::vector< Tile* >::iterator* tileIter;
+
+ /// std::vector storing pointers to transient tiles
+ std::vector< Tile* >* deletableTiles;
+ /**
+ The tiles referenced by these pointers are border tiles dynamically created in getNextMDD().
+ They do not belong to any MDD object, and, therefore, they have to be deleted explicitly.
+ */
+
+ /// bytes to transfer in actual tile (valid only if tile is larger than {\tt MAXTRANSBYTES})
+ unsigned long bytesToTransfer;
+
+ /// std::vector of persistent MDD collections in use
+ std::vector< MDDColl* >* persMDDCollections;
+
+ /// object representing the actual database
+ DatabaseIf database;
+
+ /// object representing the actual transaction (only one at a time possible)
+ TransactionIf transaction;
+
+ /// pointer to a timer for recording transaction time
+ RMTimer* taTimer;
+
+ /// pointer to a timer for recording transfer time
+ RMTimer* transferTimer;
+
+ /// pointer to a timer for recording evaluation time
+ RMTimer* evaluationTimer;
+
+ /// parameter object
+ r_Parse_Params *clientParams;
+
+ private:
+ /// empty private definition prevents of using the copy constructor
+ ClientTblElt( const ClientTblElt& ){};
+ };
+
+ /// default constructor
+ ServerComm();
+
+ /// constructor getting the client time out and the time interval for management routines, together with listen port, rasmgr host and port and the server name
+ ServerComm( unsigned long timeOut, unsigned long managementInterval , unsigned long listenPort, char* rasmgrHost, unsigned int rasmgrPort, char* serverName);
+
+ /// destructor
+ virtual ~ServerComm();
+
+ /// forces the server to listen for client calls
+ virtual void startRpcServer() throw( r_Error );
+
+ /// stops the server
+ virtual void stopRpcServer();
+
+ // informs RasMGR:
+ void informRasMGR(int);
+ #define SERVER_DOWN 0
+ #define SERVER_AVAILABLE 1
+ // 2 is server crushed, but it's generated by rasmgr!
+ // regularly signal the rasmgr that we are available
+ #define SERVER_REGULARSIG 3
+
+ /// adds an entry to the client table (used in RasServerEntry)
+ void addClientTblEntry( ClientTblElt *context ) throw ( r_Error );
+ /**
+ Adds the context entry passed to the client table.
+ Throws an exception if context==NULL.
+ */
+
+ /// deletes an entry of the client table (must be public because it is used in the global garbage collection function)
+ unsigned short deleteClientTblEntry( unsigned long ClientId );
+ /**
+ Deletes the entry of the client table corresponding to the given client id.
+ If no corresponding id is found, false is returned.
+ */
+
+ // quick hack function used when stopping server to abort transaction and close db
+ void abortEveryThingNow();
+
+ /// print server status with client table content to {\tt s}
+ virtual void printServerStatus( ostream& s=cout );
+
+ /// get server status
+ virtual void getServerStatus( ServerStatRes &returnStruct );
+
+ /// the client table which holds information about the calling clients
+ static std::list<ClientTblElt*> clientTbl;
+
+ /// last used client ID (this is increased by one to get the clientId for the next client)
+ static unsigned long clientCount;
+
+ /// inactivity timeout in seconds after which pending client data is deleted
+ const unsigned long clientTimeout;
+
+ /// do a garbage collection every {\tt garbageCollectionInterval} seconds (ONC RPC only)
+ const unsigned long garbageCollectionInterval;
+
+ /// flag for active o2 transaction (stores the clientID of the owner of the active transaction, or 0 if none open)
+ unsigned long transactionActive;
+
+ /// memory used by malloc in ordinary blocks (set in dumpClientTable)
+ long memUsed;
+
+ /// stores a pointer to the actual servercomm object, only one can exist at a time
+ static ServerComm* actual_servercomm;
+
+ /**
+ the callback manager object for garbage collection, license check, ...
+ Always instantiated with default size, resized on startup if required.
+ */
+ CallBackManager callback_mgr;
+
+ //@Man: Communication methods
+ //@{
+ ///
+
+ /// process the client's alive signal
+ virtual unsigned short aliveSignal( unsigned long client );
+ /**
+ The method take the alive signal of a client and updates the last action time.
+
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successfull\\
+ 1 && client context not found\\
+ \end{tabular}
+ */
+
+ ///
+ /// open database
+ virtual unsigned short openDB( unsigned long callingClientId, const char* dbName, const char* userName );
+ /**
+ The method opens the database with {\tt dbName}. The return value means the following:
+
+ \begin{tabular}{lll}
+ 0 && database successfully opened\\
+ 1 && client context not found\\
+ 2 && database does not exist\\
+ 3 && database is already open\\
+ \end{tabular}
+ */
+
+ /// close current database
+ virtual unsigned short closeDB( unsigned long callingClientId );
+ /**
+ The return value has the following meaning:
+ \begin{tabular}{lll}
+ 0 && operation was successful\\
+ 1 && client context not found\\
+ \end{tabular}
+ */
+
+ /// create a database
+ virtual unsigned short createDB( char* name );
+
+ /// destroy a database
+ virtual unsigned short destroyDB( char* name );
+
+ ///
+ /// open transaction
+ virtual unsigned short beginTA( unsigned long callingClientId, unsigned short readOnly=0 );
+ /**
+ The return value has the following meaning:
+ \begin{tabular}{lll}
+ 0 && operation was successful\\
+ 1 && client context not found\\
+ 2 && other transaction already active\\
+ \end{tabular}
+ */
+
+
+ /// commit current transaction
+ virtual unsigned short commitTA( unsigned long callingClientId );
+ /**
+ The return value has the following meaning:
+ \begin{tabular}{lll}
+ 0 && operation was successful\\
+ 1 && client context not found\\
+ \end{tabular}
+ */
+
+
+ /// abort current transaction
+ virtual unsigned short abortTA( unsigned long callingClientId );
+ /**
+ The return value has the following meaning:
+ \begin{tabular}{lll}
+ 0 && operation was successful\\
+ 1 && client context not found\\
+ \end{tabular}
+ */
+
+ /// is transaction open currently?
+ /**
+ The return value has the following meaning:
+ \begin{tabular}{lll}
+ true && a transaction is open\\
+ false && no transaction is open\\
+ \end{tabular}
+ */
+
+ virtual bool isTAOpen( unsigned long callingClientId );
+
+ ///
+ /// executes a retrieval query and prepares the result for transfer with \Ref{getNextMDD}.
+ virtual unsigned short executeQuery( unsigned long callingClientId, const char* query, ExecuteQueryRes &returnStructure );
+ /**
+ Executes a query and puts the result in the actual transfer collection.
+ The first parameter is the unique client id
+ for which the query should be executed. The second parameter is the
+ query itself represented as a string.
+
+ Return values
+ \begin{tabular}{lll}
+ 0 && operation was successful - result collection holds MDD elements\\
+ 1 && operation was successful - result collection holds non-MDD elements\\
+ 2 && operation was successful - result collection has no elements\\
+ 3 && client context not found\\
+ 4 && parse errror\\
+ 5 && execution error\\
+ \end{tabular}
+
+ Communication protocol (return value = 0)
+ \begin{tabular}{lll}
+ \Ref{executeQuery} && \\
+ -> && \Ref{getNextMDD} \\
+ && -> && \Ref{getNextTile} \\
+ && && : \\
+ && :\\
+ \Ref{endTransfer} \\
+ \end{tabular}
+
+ Communication protocol (return value = 1)
+ \begin{tabular}{lll}
+ \Ref{executeQuery} && \\
+ -> && \Ref{getNextElement} \\
+ && :\\
+ \Ref{endTransfer} \\
+ \end{tabular}
+ */
+
+ ///
+ /// get the domain of the next MDD of the actual transfer collection
+ virtual unsigned short getNextMDD( unsigned long callingClientId,
+ r_Minterval &mddDomain,
+ char* &typeName,
+ char* &typeStructure,
+ r_OId &oid,
+ unsigned short &currentFormat );
+ /**
+ The Method gets the domain of the next MDD of the actual transfer collection.
+ The first parameter is the unique client id. The second parameter returns the
+ domain of the MDD to be transfered. {\tt typeName} returns the name of the
+ MDD type and its structure.
+ Transfer of MDD data is tile-based using the method \Ref{getNextTile}.
+
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successful, at least one MDD is left in the transfer collection\\
+ 1 && nothing left in the transfer collection\\
+ 2 && client context not found, no tiles in the MDD object, no actual transfer collection \\
+ \end{tabular}
+ */
+
+ /// get the next scalar element in the actual transfer collection.
+ virtual unsigned short getNextElement( unsigned long callingClientId,
+ char* &buffer,
+ unsigned int &bufferSize );
+ /**
+ The Method gets the next non-MDD element in the actual transfer collection.
+ The first parameter is the unique client id. The second parameter returns a
+ pointer to the memory occupied by the next element and the third one delivers
+ the size of the buffer.
+
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successful, at least one element is left in the transfer collection\\
+ 1 && operation succesful, nothing left in the transfer collection\\
+ 2 && client context not found, no tiles in the MDD object, no actual transfer collection \\
+ \end{tabular}
+ */
+
+ /// get an MDD by OId
+ virtual unsigned short getMDDByOId( unsigned long callingClientId,
+ r_OId &oid,
+ r_Minterval &mddDomain,
+ char* &typeName,
+ char* &typeStructure,
+ unsigned short &currentFormat );
+ /**
+ The Method gets an MDD by OId {\tt oid}. If the MDD is found, it is initialized as transfer
+ object and can be picked up by \Ref{getNextTile} calls (tile-based transfer).
+
+ Additionally, the method returns domain, type name, and type structure of the found MDD
+ object by reference parameters.
+
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successful\\
+ 1 && client context not found\\
+ 2 && object with this oid not found\\
+ 3 && object has no tiles
+ \end{tabular}
+
+ Communication protocol
+ \begin{tabular}{lll}
+ \Ref{getMDDByOId} \\
+ -> && \Ref{getNextTile} \\
+ && : \\
+ \Ref{endTransfer} \\
+ \end{tabular}
+ */
+
+ /// get next tile of the actual MDD of the actual transfer collection
+ virtual unsigned short getNextTile( unsigned long callingClientId,
+ RPCMarray** rpcMarray );
+ /**
+ The Method gets the next tile of the actual MDD of the actual transfer collection.
+ The first parameter is the unique client id. The second parameter is the
+ RPC representation of the Marray representing the tile. If a tile is too large to be
+ transferred in one piece, the data is split. To get the rest of the data, consecutively
+ use this method.
+
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successful, no further MDDs are left\\
+ 1 && operation was successful, at least one MDD is left in the transfer collection\\
+ 2 && operation was successful, at least one tile is left in the actual MDD\\
+ 3 && operation was successful, at least one block is left in the actual tile\\
+ 4 && client context not found, no tiles in the MDD object, no actual transfer collection \\
+ && or nothing left in the collection\\
+ \end{tabular}
+
+ Examples of valid return value chains:
+ \begin{itemize}
+ \item To be transferred: 1 MDD consisting of 1 tile (which is too large)\\
+ \begin{verbatim}
+ 3 ->...-> 3 -> 0
+ \end{verbatim}
+ \item To be transferred: 1 MDD consisting of 2 tiles (the first is too large)\\
+ \begin{verbatim}
+ 3 ->...-> 3 -> 2 -> 0
+ |--------------| |
+ 1st tile 2nd tile
+ \end{verbatim}
+ \item To be transferred: 2 MDDs, each consisting of 1 tile (none too large)\\
+ \begin{verbatim}
+ 1 -> 0
+ \end{verbatim}
+ \item To be transferred: 3 MDDs, the first (A) consisting of 1 tile (not too large),\\
+ the second (B) consisting of 2 tiles (B1, B2, of which the first is too large),
+ the third (C) consisting of 2 tiles (C1, C2, of which the second is too large),
+ \begin{verbatim}
+ 1 -> 3 ->...-> 3 -> 2 -> 1 -> 2 -> 3 ->...-> 3 -> 0
+ | |--------------| | | |--------------|
+ | B1 B2 C1 C2
+ | |-------------------| |-------------------|
+ A B C
+ \end{verbatim}
+ \end{itemize}
+ */
+
+ /// process the client's alive signal
+ virtual unsigned short endTransfer( unsigned long client );
+ /**
+ The method terminates a transfer session and releases all transfer structures.
+
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successfull\\
+ 1 && client context not found\\
+ \end{tabular}
+ */
+
+ ///
+ /// prepares transfer of MDD constants and execution of update query
+ virtual unsigned short initExecuteUpdate( unsigned long callingClientId );
+ /**
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successful\\
+ 1 && client context not found\\
+ \end{tabular}
+
+ Communication protocol
+ \begin{tabular}{lll}
+ \Ref{initExecuteUpdate} && \\
+ -> && \Ref{startInsertTransMDD} \\
+ && -> && \Ref{insertTile} \\
+ && && :\\
+ && \Ref{endInsertMDD}\\
+ && :\\
+ \Ref{executeUpdate} && \\
+ \end{tabular}
+
+ Note: Method \Ref{executeUpdate} can be invoked without the \Ref{initExecuteUpdate}
+ prolog in case of no constant MDD objects.
+ */
+
+ /// executes an update query
+ virtual unsigned short executeUpdate( unsigned long callingClientId, const char* query, ExecuteUpdateRes &returnStructure );
+ /**
+ Executes an update query.
+ The first parameter is the unique client id
+ for which the query should be executed. The second parameter is the
+ query itself represented as a string.
+
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successful\\
+ 1 && client context not found\\
+ 2 && parse errror\\
+ 3 && execution error\\
+ \end{tabular}
+ */
+
+ ///
+ /// prepares an MDD (transient) for transfer of tiles
+ virtual unsigned short startInsertTransMDD( unsigned long callingClientId,
+ r_Minterval &domain,
+ unsigned long typeLength,
+ const char* typeName );
+ /**
+ Creates an object for tile based transfer with method \Ref{insertTile}.
+
+ The first parameter is the unique client id for which the MDD should be created.
+ The second parameter is the
+ name of the collection to insert the MDD object. The third parameter holds the
+ spatial domain of the following MDD object and {\tt typeLength} specifies the size of
+ the base type in bytes. The last one gives the type structure as string representation.
+
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successful\\
+ 1 && client context not found\\
+ 2 && MDD type name not found\\
+ 3 && MDD and its type are incompatible\\
+ \end{tabular}
+ */
+
+ /// create a new persistent MDD object for tile based transfers
+ virtual unsigned short startInsertPersMDD( unsigned long callingClientId,
+ const char* collName,
+ r_Minterval& domain,
+ unsigned long typeLength,
+ const char* typeName,
+ r_OId& oid );
+ /**
+ Creates an object for tile based transfer with method \Ref{insertTile} to be
+ inserted into the specified MDD collection.
+
+ Parameters
+ \begin{tabular}{lll}
+ {\tt callingClientId} && unique client id of the calling client\\
+ {\tt collName} && name of the collection to insert the MDD object\\
+ {\tt domain} && spatial domain\\
+ {\tt typeLength} && size of base type in bytes\\
+ {\tt typeName} && type structure as string representation\\
+ {\tt oid} && object identifier\\
+ \end{tabular}
+
+ Return values
+ \begin{tabular}{lll}
+ 0 && operation was successful\\
+ 1 && client context not found\\
+ 2 && MDD type name not found\\
+ 3 && types of MDD and collection are incompatible\\
+ 4 && MDD and its type are incompatible\\
+ 5 && collection does not exist\\
+ 6 && creation of persistent object failed\\
+ \end{tabular}
+
+ Communication protocol
+ \begin{tabular}{lll}
+ \Ref{startInsertPersMDD} && \\
+ -> && \Ref{insertTile} \\
+ && :\\
+ \Ref{endInsertMDD} && \\
+ \end{tabular}
+ */
+
+ /// insert a tile into a persistent MDD object
+ virtual unsigned short insertTile( unsigned long callingClientId,
+ int isPersistent,
+ RPCMarray* rpcMarray );
+ /**
+ Inserts a tile into the current MDD object.
+
+ Parameters
+ \begin{tabular}{lll}
+ {\tt callingClientId} && unique client id of the calling client\\
+ {\tt isPersistent} && determines wheather it is a persistent or a transient tile\\
+ {\tt rpcMarray} && RPC representation of the tile\\
+ \end{tabular}
+
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successful\\
+ 1 && client context not found\\
+ 2 && base type name of inserting tile is not supported\\
+ \end{tabular}
+ */
+
+
+
+ // inserts a tile into a persistent MDD object splitting it up according to
+ // parameter tileSize
+ virtual unsigned short insertTileSplitted( unsigned long callingClientId,
+ int isPersistent,
+ RPCMarray* rpcMarray,
+ r_Minterval* tileSize );
+ /**
+ Splits and inserts a tile into the current MDD object.
+
+ Parameters
+ \begin{tabular}{lll}
+ {\tt callingClientId} && unique client id of the calling client\\
+ {\tt isPersistent} && determines wheather it is a persistent or a transient tile\\
+ {\tt rpcMarray} && RPC representation of the tile\\
+ {\tt tileSize} && r_Minterval specifying the tile-size\\
+ \end{tabular}
+
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successful\\
+ 1 && client context not found\\
+ 2 && base type name of inserting tile is not supported\\
+ \end{tabular}
+ */
+
+ /// finnishes the MDD creation and inserts the MDD into the collection
+ virtual unsigned short endInsertMDD( unsigned long callingClientId,
+ int isPersistent );
+ /**
+ Parameters
+ \begin{tabular}{lll}
+ {\tt callingClientId} && unique client id of the calling client\\
+ {\tt isPersistent} && determines wheather it is a persistent or a transient MDD\\
+ \end{tabular}
+ */
+
+ ///
+ /// insert object into collection
+ virtual unsigned short insertMDD( unsigned long callingClientId,
+ const char* collName,
+ RPCMarray *rpcMarray,
+ const char* typeName, r_OId& oid );
+ /**
+ Inserts an object into an MDD collection. It is transfered in one piece.
+
+ Parameters
+ \begin{tabular}{lll}
+ {\tt callingClientId} && unique client id of the calling client\\
+ {\tt collName} && name of the collection to insert the MDD object\\
+ {\tt rpcMarray} && RPC representation of the MDD object\\
+ {\tt typeName} && type structure as string representation\\
+ {\tt oid} && object identifier\\
+ \end{tabular}
+
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successful\\
+ 1 && client context not found\\
+ 2 && MDD type name not found\\
+ 3 && types of MDD and collection are incompatible\\
+ 4 && MDD and its type are incompatible\\
+ 5 && collection does not exist\\
+ 6 && creation of persistent object failed\\
+ \end{tabular}
+ */
+
+ ///
+ /// prepare an MDD collection for transfer with getNextMDD()
+ virtual unsigned short getCollByName( unsigned long callingClientId,
+ const char* collName,
+ char* &typeName,
+ char* &typeStructure,
+ r_OId &oid );
+ /**
+ ATTENTION: This function is not used at the moment. It hast
+ to be adapted to transferData.
+
+ Prepares an MDD collection for transfer with getNextMDD().
+
+ Parameters
+ \begin{tabular}{lll}
+ {\tt callingClientId} && unique client id of the calling client\\
+ {\tt collName} && name of the collection to be got\\
+ {\tt typeName} && returns name of the collection type\\
+ {\tt typeStructure} && returns structure of the collection type\\
+ {\tt oid} && returns oid of the collection\\
+ \end{tabular}
+
+ The first parameter is the unique client id. The second parameter is the
+ name of the collection to get. {\tt typeName} returns the name of the
+ collection type and {\tt typeStructure} its type structure.
+
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successful - collection has some elements\\
+ 1 && operation was successful - collection has no elements\\
+ 2 && collection is not known\\
+ 3 && client context not found\\
+ \end{tabular}
+ */
+
+ /// prepare an MDD collection for transfer with getNextMDD()
+ virtual unsigned short getCollByOId( unsigned long callingClientId,
+ r_OId &oid,
+ char* &typeName,
+ char* &typeStructure,
+ char* &collName );
+ /**
+ ATTENTION: This function is not used at the moment. It hast
+ to be adapted to transferData.
+
+ Prepares an MDD collection for transfer with \Ref{getNextMDD}.
+
+ Parameters
+ \begin{tabular}{lll}
+ {\tt callingClientId} && unique client id of the calling client\\
+ {\tt oid} && oid of the collection to be got\\
+ {\tt typeName} && returns name of the collection type\\
+ {\tt typeStructure} && returns structure of the collection type\\
+ {\tt collName} && returns name of collection\\
+ \end{tabular}
+
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successful - collection has some elements\\
+ 1 && operation was successful - collection has no elements\\
+ 2 && collection is not known\\
+ 3 && client context not found\\
+ \end{tabular}
+ */
+
+ /// gets oids of the collection specified by name
+ virtual unsigned short getCollOIdsByName( unsigned long callingClientId,
+ const char* collName,
+ char* &typeName,
+ char* &typeStructure,
+ r_OId &oid,
+ RPCOIdEntry* &oidTable,
+ unsigned int &oidTableSize );
+ /**
+ Gets the collection of oids of the collection with {\tt collName}.
+
+ Parameters
+ \begin{tabular}{lll}
+ {\tt callingClientId} && unique client id of the calling client\\
+ {\tt collName} && name of the collection to be got\\
+ {\tt typeName} && returns name of the collection type\\
+ {\tt typeStructure} && returns structure of the collection type\\
+ {\tt oid} && returns object identifier\\
+ {\tt oidTable} && returns an array of pointers to oids\\
+ {\tt oidTableSize} && returns the no of elements in the table\\
+ \end{tabular}
+
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successful - collection has some elements\\
+ 1 && operation was successful - collection has no elements\\
+ 2 && collection is not known\\
+ 3 && client context not found\\
+ \end{tabular}
+ */
+
+ /// gets oids of the collection specified by name
+ virtual unsigned short getCollOIdsByOId( unsigned long callingClientId,
+ r_OId &oid,
+ char* &typeName,
+ char* &typeStructure,
+ RPCOIdEntry* &oidTable,
+ unsigned int &oidTableSize,
+ char* &collName );
+ /**
+ Gets the collection of oids of the collection with {\tt collName}.
+
+ Parameters
+ \begin{tabular}{lll}
+ {\tt callingClientId} && unique client id of the calling client\\
+ {\tt oid} && oid of the collection to be got\\
+ {\tt typeName} && returns name of the collection type\\
+ {\tt typeStructure} && returns structure of the collection type\\
+ {\tt oidTable} && returns an array of pointers to oids\\
+ {\tt oidTableSize} && returns the no of elements in the table\\
+ {\tt collName} && returns name of collection\\
+ \end{tabular}
+
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successful - collection has some elements\\
+ 1 && operation was successful - collection has no elements\\
+ 2 && collection is not known\\
+ 3 && client context not found\\
+ \end{tabular}
+ */
+
+ ///
+ /// create new MDD collection
+ virtual unsigned short insertColl( unsigned long callingClientId,
+ const char* collName,
+ const char* typeName,
+ r_OId& oid );
+ /**
+ Creates a new MDD collection.
+
+ Parameters
+ \begin{tabular}{lll}
+ {\tt callingClientId} && unique client id of the calling client\\
+ {\tt collName} && name of the collection to be created\\
+ {\tt typeName} && name of the collection type\\
+ {\tt oid} && object identifier\\
+ \end{tabular}
+
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successful\\
+ 1 && client context not found\\
+ 2 && collection type name not found\\
+ 3 && collection name exists already in the db
+ \end{tabular}
+ */
+
+ ///
+ /// delete MDD collection
+ virtual unsigned short deleteCollByName( unsigned long callingClientId,
+ const char* collName );
+ /**
+ Deletes an MDD collection. The first parameter is the unique client id
+ for which the collection should be deleted. The second parameter is the
+ name for the collection to be deleted.
+
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successful\\
+ 1 && client context not found\\
+ 2 && collection with name does not exist\\
+ \end{tabular}
+ */
+
+ /// delete object by oid
+ virtual unsigned short deleteObjByOId( unsigned long callingClientId, r_OId& oid );
+ /**
+ Deletes the object with {\tt oid}.
+ The first parameter is the unique client id for which the object should be
+ deleted.
+
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successful\\
+ 1 && client context not found\\
+ 2 && object with oid does not exist\\
+ \end{tabular}
+ */
+
+ ///
+ /// remove object specified by oid from collection specified by name
+ virtual unsigned short removeObjFromColl( unsigned long callingClientId,
+ const char* collName, r_OId& oid );
+ /**
+ The method removes the object with {\\t oid} from collection with {\tt collName}.
+ The first parameter is the unique client id for which the object should be removed.
+
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successful\\
+ 1 && client context not found\\
+ 2 && specified collection does not exist\\
+ 3 && specified object does not exist in the collection\\
+ \end{tabular}
+ */
+
+ ///
+ /// get new object identifier
+ virtual unsigned short getNewOId( unsigned long callingClientId,
+ unsigned short objType, r_OId& oid );
+ /**
+ Creates a new oid and gives it back by the refernce parameter {\tt oid}.
+ {\tt objType} determines the type of object for which that oid is allocated. The folowing
+ values are supported: 1 = MDD, 2 = Collection.
+
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successful\\
+ 1 && client context not found\\
+ 2 && error while creating oid\\
+ \end{tabular}
+ */
+
+ /// get type of object by oid
+ virtual unsigned short getObjectType( unsigned long callingClientId,
+ r_OId& oid, unsigned short &objType );
+ /**
+ Determines the type of the object indicated by {\tt oid}. The type is returned by the
+ reference parameter {\tt objType}. The folowing types are supported: 1 = MDD, 2 = Collection.
+
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successful\\
+ 1 && client context not found\\
+ 2 && oid not found\\
+ \end{tabular}
+ */
+
+ /// get type structure of a type name
+ virtual unsigned short getTypeStructure( unsigned long callingClientId,
+ const char* typeName,
+ unsigned short typeType,
+ char* &typeStructure);
+ /**
+ Determines the type structure of the type specified by {\tt typeName}. The type
+ either can be a set type (typeType=1), an mdd type (typeType=2), or a base type
+ (typeType = 3).
+
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successful\\
+ 1 && client context not found\\
+ 2 && type name not found\\
+ \end{tabular}
+ */
+
+ /// set the data format used for transferring data to the client
+ virtual unsigned short setTransferMode( unsigned long callingClientId,
+ unsigned short format, const char* formatParams );
+ /**
+ Sets the data format used by the server to transfer data to the client to
+ format which is of type r_Data_Format.
+
+ Return values:
+ \begin{tabular}{lll}
+ 0 && operation was successful\\
+ 1 && client context not found\\
+ 2 && unknown or unsupported data format\\
+ \end{tabular}
+ */
+
+ /// set the data format for storing data into the database
+ virtual unsigned short setStorageMode( unsigned long callingClientId,
+ unsigned short format, const char *formatParams );
+ /**
+ return values exactly like setTransferMode()
+ */
+ ///
+ //@}
+
+ /// returns a pointer to the context of the calling client, 0 it there is no context
+ virtual ClientTblElt* getClientContext( unsigned long ClientId );
+ /**
+ Returns a pointer to the context of the calling client. This is done by
+ searching the client table maintained by the server for the given client id.
+ If there is no context corresponding to the client id, 0 is returned.
+
+ Attention: After a client context was successfully received it has to be
+ released using its member function release();
+ */
+
+ // get, set and clear extended error info.
+ const char *getExtendedErrorInfo();
+
+ void setExtendedErrorInfo(const char*);
+
+ void clearExtendedErrorInfo();
+
+ void clientEndRequest();
+
+ // constant for clientID
+ static const char* HTTPCLIENT;
+
+ private:
+ /// copy constructor is private and therefore can not be used
+ ServerComm( const ServerComm& );//and then why this? : clientTimeout(3600), garbageCollectionInterval(600){;};
+
+ protected:
+ /// make sure a tile has the correct data format, converting if necessary
+ static int ensureTileFormat( r_Data_Format &hasFmt, r_Data_Format needFmt,
+ const r_Minterval &dom, const BaseType *type,
+ char *&data, unsigned long &size, int repack,
+ int owner, const char *params = NULL);
+ ///returns the following:
+ static const int ENSURE_TILE_FORMAT_OK;
+ static const int ENSURE_TILE_FORMAT_BAD;
+
+ /// pointer to the actual administration interface object
+ AdminIf* admin;
+
+ char *errorText;
+
+ unsigned long listenPort;
+ char* rasmgrHost;
+ unsigned int rasmgrPort;
+ char* serverName;
+
+ bool isHttpServer;
+ //this trick didn't work and we are out of time
+ // ClientTblElt *uniqueClientContext;
+};
+
+
+/// indirect caller for rpcif_1
+void rpcif_1_caller(struct svc_req *rqstp,SVCXPRT *transp);
+
+
+/******************************************************************************************
+*** This class shouldn't be here, later it will be put in its own file
+******************************************************************************************/
+
+
+class AccessControl
+ {
+ public:
+ AccessControl();
+ ~AccessControl();
+ void initSyncro(const char *);
+ void setServerName(const char *serverName);
+
+ void resetForNewClient();
+ int crunchCapability(const char*);
+ /* 0 - ok
+ 804 - capability refused
+ */
+
+ void wantToRead(); // both throw
+ void wantToWrite();
+ bool isClient();
+ private:
+ int messageDigest(const char *input,char *output,const char *mdName);
+ double initDeltaT;
+ char serverName[100];
+
+ bool okToRead;
+ bool okToWrite;
+ bool weHaveClient;
+ };
+extern AccessControl accessControl;
+
+#include "servercomm.icc"
+
+#endif
diff --git a/servercomm/servercomm.icc b/servercomm/servercomm.icc
new file mode 100644
index 0000000..ebc1d6c
--- /dev/null
+++ b/servercomm/servercomm.icc
@@ -0,0 +1,31 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * INLINE SOURCE: servercomm.icc
+ *
+ * MODULE: servercomm
+ * CLASS: ServerComm
+ *
+ * COMMENTS:
+ * None
+*/
diff --git a/servercomm/servercomm2.cc b/servercomm/servercomm2.cc
new file mode 100644
index 0000000..7fcbef2
--- /dev/null
+++ b/servercomm/servercomm2.cc
@@ -0,0 +1,4051 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: servercomm2.cc
+ *
+ * MODULE: servercomm
+ * CLASS: ServerComm
+ *
+ * PURPOSE:
+ *
+ * COMMENTS:
+ * - FIXME: catch exceptions in all operations
+ * - return values & their meaning see servercomm.hh
+ * - FIXME: "client not registered" delivers sometimes 1, sometimes 3
+ *
+*/
+
+#include "mymalloc/mymalloc.h"
+
+static const char rcsid[] = "@(#)servercomm2, ServerComm: $Id: servercomm2.cc,v 1.121 2005/09/07 23:23:31 rasdev Exp $";
+
+// after some time please take this and everything related to it out (26.06.2001)
+#define ANDREAS_2306
+
+#include <iostream>
+#include <malloc.h>
+#include <string.h>
+#include <math.h> // for log(), exp(), floor()
+#include <ctime> // time
+#include <iomanip>
+
+#ifdef PURIFY
+#include <purify.h>
+#endif
+
+#ifdef RMANBENCHMARK
+ // to control GenericCompression::decompTimer and GenericCompression::compTimer
+ #include "gencompression.hh"
+ #include "zlibcompression.hh"
+#endif
+
+#ifdef SOLARIS
+ #define PORTMAP // define to use function declarations for old interfaces
+ #include <rpc/rpc.h>
+
+ extern int _rpcpmstart;
+
+ // function prototype with C linkage
+ extern "C" int gethostname(char *name, int namelen);
+#else // HPUX
+ #include <rpc/rpc.h>
+#endif
+
+#include <rpc/pmap_clnt.h>
+
+#include "raslib/rmdebug.hh"
+#include "debug.hh"
+#include "raslib/rminit.hh"
+#include "raslib/error.hh"
+#include "raslib/minterval.hh"
+#include "raslib/mddtypes.hh"
+#include "raslib/basetype.hh"
+#include "raslib/endian.hh"
+#include "raslib/odmgtypes.hh"
+#include "raslib/parseparams.hh"
+// for transfer compression
+#include "compression/tilecompression.hh"
+
+#include "servercomm/servercomm.hh"
+#include "catalogmgr/typefactory.hh"
+
+#include "mddmgr/mddcoll.hh"
+#include "mddmgr/mddobj.hh"
+#include "mddmgr/mddcolliter.hh"
+#include "tilemgr/tile.hh"
+
+#include "relcatalogif/mddtype.hh"
+#include "relcatalogif/mdddomaintype.hh"
+#include "relcatalogif/settype.hh"
+#include "reladminif/eoid.hh"
+
+#include "qlparser/qtmdd.hh"
+#include "qlparser/qtatomicdata.hh"
+#include "qlparser/qtcomplexdata.hh"
+#include "qlparser/qtintervaldata.hh"
+#include "qlparser/qtmintervaldata.hh"
+#include "qlparser/qtpointdata.hh"
+#include "qlparser/qtstringdata.hh"
+
+// console output describing successful/unsuccessful actions
+#define MSG_OK "ok"
+#define MSG_FAILED "failed"
+
+// include and extern declarations for the query parsing
+#include "qlparser/querytree.hh"
+extern int yyparse(void *);
+extern void yyreset();
+#ifdef NOPRE
+char* ppInBuf = 0;
+char* ppOutBuf = 0;
+void ppreset()
+{
+ RMInit::logOut << "Error: Preprocessor not compiled in." << std::endl;
+ RMInit::dbgOut << "Error: Preprocessor not compiled in." << std::endl;
+ throw r_Error(ILLEGALSTATEREACHED);
+}
+
+int ppparse()
+{
+ RMInit::logOut << "Error: Preprocessor not compiled in." << std::endl;
+ RMInit::dbgOut << "Error: Preprocessor not compiled in." << std::endl;
+ throw r_Error(ILLEGALSTATEREACHED);
+}
+#else
+extern char* ppInBuf;
+extern char* ppOutBuf;
+extern void ppreset();
+extern int ppparse();
+#endif
+extern bool udfEnabled;
+
+extern QueryTree* parseQueryTree;
+extern ParseInfo* parseError;
+extern char* beginParseString;
+extern char* iterParseString;
+extern unsigned long maxTransferBufferSize;
+extern char* dbSchema;
+
+MDDColl* mddConstants=0;
+
+ServerComm::ClientTblElt* currentClientTblElt=0;
+
+// Once again a function prototype. The first one is for the RPC dispatcher
+// function located in the server stub file rpcif_svc.c and the second one
+// is for the garbage collection function pointed to by the signal handler.
+extern "C"
+{
+ // static void rpcif_1( struct svc_req*, register SVCXPRT* );
+ char* rpcif_1( struct svc_req*, register SVCXPRT* );
+ void garbageCollection( int );
+}
+
+// this is a temporary thing
+extern int globalOptimizationLevel;
+
+// This is needed in httpserver.cc
+char globalHTTPSetTypeStructure[4096];
+
+// constant for clientID
+const char* ServerComm::HTTPCLIENT = "HTTPClient";
+
+///ensureTileFormat returns the following:
+const int ServerComm::ENSURE_TILE_FORMAT_OK=0;
+const int ServerComm::ENSURE_TILE_FORMAT_BAD=-1;
+
+/*************************************************************************
+ * Method name...: openDB( unsigned long callingClientId,
+ * const char* dbName ,
+ * const char* userName )
+ ************************************************************************/
+unsigned short
+ServerComm::openDB( unsigned long callingClientId,
+ const char* dbName,
+ const char* userName )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "openDB" )
+
+ unsigned short returnValue=0;
+
+ RMInit::logOut << "Request: openDB '" << dbName << "'..." << std::flush;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+ // release transfer collection/iterator
+ context->releaseTransferStructures();
+
+ // open the database
+ try
+ {
+ context->database.open( dbName );
+ }
+ catch(r_Error& err)
+ {
+ if(err.get_kind() == r_Error::r_Error_DatabaseUnknown)
+ {
+ RMInit::logOut << "Error: database does not exist." << endl;
+ returnValue = 2;
+ }
+ else if(err.get_kind() == r_Error::r_Error_DatabaseOpen)
+ {
+ // ignore re-open to be fault tolerant -- PB 2004-dec-16
+ // RMInit::logOut << "Error: database is already open." << endl;
+ returnValue = 3;
+ }
+ else
+ {
+ RMInit::logOut << "Error: exception " << err.get_errorno() << ": " << err.what() << endl;
+ //should be something else. but better than no message about the problem at all
+ returnValue = 2;
+ }
+ }
+
+ if( returnValue == 0 )
+ {
+ // database was successfully opened, so assign db and user name
+ delete[] context->baseName;
+ context->baseName = new char[strlen( dbName )+1];
+ strcpy( context->baseName, dbName );
+
+ delete[] context->userName;
+ context->userName = new char[strlen( userName )+1];
+ strcpy( context->userName, userName );
+
+ RMInit::logOut << MSG_OK << std::endl;
+ }
+
+ context->release();
+
+ // ignore "already open" error to be more fault tolerant -- PB 2004-dec-16
+ if( returnValue == 3 )
+ {
+ RMInit::logOut << "Warning: database already open for user '" << userName << "', ignoring command." << endl;
+ returnValue = 0;
+ }
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 1;
+ }
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "openDB" )
+ return returnValue;
+}
+
+
+
+/*************************************************************************
+ * Method name...: closeDB( unsigned long callingClientId )
+ ************************************************************************/
+unsigned short
+ServerComm::closeDB( unsigned long callingClientId )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "closeDB" )
+ unsigned short returnValue;
+
+ RMInit::logOut << "Request: closeDB..." << std::flush;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+ // release transfer collection/iterator
+ context->releaseTransferStructures();
+
+ // If the current transaction belongs to this client, abort it.
+ if( transactionActive == callingClientId )
+ {
+ RMInit::logOut << "Warning: transaction is open; aborting this transaction..." << std::flush;
+
+ context->transaction.abort();
+ transactionActive = 0;
+ }
+
+ // close the database
+ context->database.close();
+
+ // reset database name
+ delete[] context->baseName;
+ context->baseName = new char[5];
+ strcpy( context->baseName, "none" );
+
+ returnValue = 0;
+
+ context->release();
+
+#ifdef PURIFY
+ purify_new_leaks();
+#endif
+
+ RMInit::logOut << MSG_OK << endl;
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 1;
+ }
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "closeDB" )
+ return returnValue;
+}
+
+
+
+/*************************************************************************
+ * Method name...: createDB( char* name )
+ ************************************************************************/
+unsigned short
+ServerComm::createDB( char* name )
+{
+ unsigned short returnValue;
+
+ // FIXME: what about client id? -- PB 2005-aug-27
+
+ RMInit::logOut << "Request: createDB '" << name << "'..." << std::flush;
+
+ DatabaseIf* tempDbIf = new DatabaseIf;
+
+ // create the database
+ try
+ {
+ tempDbIf->createDB( name, dbSchema );
+ RMInit::logOut << MSG_OK << endl;
+ }
+ catch(r_Error& myErr)
+ {
+ RMInit::logOut << "Error: exception " << myErr.get_errorno() << ": " << myErr.what() << std::endl;
+ }
+ catch(std::bad_alloc)
+ {
+ RMInit::logOut << "Error: cannot allocate memory." << std::endl;
+ throw;
+ }
+ catch(...)
+ {
+ RMInit::logOut << std::endl << "Error: Unspecified exception." << std::endl;
+ }
+
+ delete tempDbIf;
+
+ // FIXME: set proper return value on failure (update .hh!) -- PB 2005-aug-27
+ returnValue = 0;
+
+ return returnValue;
+}
+
+
+
+/*************************************************************************
+ * Method name...: destroyDB( char* name )
+ ************************************************************************/
+unsigned short
+ServerComm::destroyDB( char* name )
+{
+ // Note: why no check for client id here? -- PB 2005-aug-25
+
+ unsigned short returnValue = 0;
+
+ RMInit::logOut << "Request: destroyDB '" << name << "'..." << std::flush;
+
+ DatabaseIf* tempDbIf = new DatabaseIf;
+
+ // begin a temporary transaction because persistent data (as databases)
+ // can only be manipulated within active transactions.
+ // tempTaIf->begin(tempDbIf);
+
+ // destroy the database
+ tempDbIf->destroyDB( name );
+
+ // commit the temporary transaction
+ // tempTaIf->commit();
+
+ delete tempDbIf;
+
+ RMInit::logOut << MSG_OK << std::endl;
+
+ return returnValue;
+}
+
+
+
+/*************************************************************************
+ * Method name...: beginTA( unsigned long callingClientId )
+ ************************************************************************/
+unsigned short
+ServerComm::beginTA( unsigned long callingClientId,
+ unsigned short readOnly )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "beginTA" )
+ unsigned short returnValue;
+
+ RMInit::logOut << "Request: beginTA (" << ( readOnly ? "read" : "write" ) << ")..." << std::flush;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context == 0 )
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 1;
+ }
+ else if ( transactionActive )
+ {
+ RMInit::logOut << "Error: transaction already active." << std::endl;
+ returnValue = 2;
+ context->release();
+ }
+ else
+ {
+ // release transfer collection/iterator
+ context->releaseTransferStructures();
+
+#ifdef RMANBENCHMARK
+ if( RManBenchmark > 0 )
+ context->taTimer = new RMTimer("ServerComm", "transaction time ");
+#endif
+ try
+ {
+ // start the transaction
+ context->transaction.begin( &(context->database), readOnly );
+ RMInit::logOut << MSG_OK << endl;
+ }
+ catch(r_Error& err)
+ {
+ RMInit::logOut << "Error: exception " << err.get_errorno() << ": " << err.what() << std::endl;
+ context->release();
+ throw;
+ }
+
+ // lock the semaphor
+ transactionActive = callingClientId;
+ returnValue = 0;
+
+ context->release();
+ }
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "beginTA" )
+ return returnValue;
+}
+
+
+
+/*************************************************************************
+ * Method name...: commitTA( unsigned long callingClientId )
+ ************************************************************************/
+unsigned short
+ServerComm::commitTA( unsigned long callingClientId )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "commitTA" )
+ unsigned short returnValue;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ RMInit::logOut << "Request: commitTA..." << std::flush;
+
+ if( context != 0 )
+ {
+#ifdef RMANBENCHMARK
+ RMTimer* commitTimer = 0;
+
+ if( RManBenchmark > 0 )
+ commitTimer = new RMTimer("ServerComm", "commit time ");
+#endif
+
+ // release transfer collection/iterator within the transaction they are created
+ context->releaseTransferStructures();
+
+ // commit the transaction
+ context->transaction.commit();
+
+ // unlock the semaphor
+ transactionActive = 0;
+
+ returnValue = 0;
+
+#ifdef RMANBENCHMARK
+ if( commitTimer ) delete commitTimer;
+#endif
+
+ context->release();
+
+ RMInit::logOut << MSG_OK << endl;
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 1;
+ }
+
+#ifdef RMANBENCHMARK
+ if( context->taTimer )
+ delete context->taTimer;
+ context->taTimer = 0;
+#endif
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "commitTA" )
+ return returnValue;
+}
+
+
+
+/*************************************************************************
+ * Method name...: abortTA( unsigned long callingClientId )
+ ************************************************************************/
+unsigned short
+ServerComm::abortTA( unsigned long callingClientId )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "abortTA" )
+ unsigned short returnValue;
+
+ RMInit::logOut << "Request: abortTA..." << std::flush;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+ // release transfer collection/iterator within the transaction they are created
+ context->releaseTransferStructures();
+
+ // abort the transaction
+ context->transaction.abort();
+
+ // unlock the semaphor
+ transactionActive = 0;
+
+ returnValue = 0;
+
+ context->release();
+
+ RMInit::logOut << MSG_OK << endl;
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 1;
+ }
+
+#ifdef RMANBENCHMARK
+ if( context->taTimer ) delete context->taTimer;
+ context->taTimer = 0;
+#endif
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "abortTA" )
+ return returnValue;
+}
+
+
+/*************************************************************************
+ * Method name...: isTAOpen()
+ * as right now only one transaction can be active per server,
+ * we only have to check the sema.
+ * returns:
+ * true iff a transaction is open
+ ************************************************************************/
+bool
+ServerComm::isTAOpen( unsigned long callingClientId )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "isTAOpen" )
+
+ RMInit::logOut << "Request: isTAOpen..." << std::flush;
+
+ bool returnValue = transactionActive;
+
+ RMInit::logOut << MSG_OK << (transactionActive?", is active.":", is not active.") << endl;
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "isTAOpen" )
+ return returnValue;
+}
+
+
+
+unsigned short
+ServerComm::insertColl( unsigned long callingClientId,
+ const char* collName,
+ const char* typeName,
+ r_OId& oid )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "insertColl" )
+ unsigned short returnValue = 0;
+
+ RMInit::logOut << "Request: insertColl '" << collName << "' with type '" << typeName << "'..." << std::flush;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+ // delete old transfer structures
+ context->releaseTransferStructures();
+
+ //
+ // create the collenction
+ //
+
+ // get collection type
+ CollectionType* collType = (CollectionType*)TypeFactory::mapSetType( typeName );
+
+ if( collType )
+ {
+ try
+ {
+ MDDColl* coll = MDDColl::createMDDCollection(collName, OId(oid.get_local_oid()), collType);
+ delete coll;
+ RMInit::logOut << MSG_OK << endl;
+ }
+ catch( r_Error& obj )
+ {
+ if (obj.get_kind() == r_Error::r_Error_NameNotUnique)
+ {
+ RMInit::logOut << "Error: collection exists already." << std::endl;
+ returnValue = 3;
+ }
+ else
+ {
+ RMInit::logOut << "Error: cannot create collection: " << obj.get_errorno() << " " << obj.what() << std::endl;
+ //this should be another code...
+ returnValue = 3;
+ }
+ }
+
+ }
+ else
+ {
+ RMInit::logOut << "Error: unknown collection type: '" << typeName << "'." << std::endl;
+ returnValue = 2;
+ }
+
+ //
+ // done
+ //
+
+ context->release();
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 1;
+ }
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "insertColl" )
+ return returnValue;
+}
+
+
+
+/*************************************************************************
+ * Method name...: deleteCollByName( unsigned long callingClientId,
+ * const char* collName )
+ ************************************************************************/
+unsigned short
+ServerComm::deleteCollByName( unsigned long callingClientId,
+ const char* collName )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "deleteCollByName(" << callingClientId << ", " << collName << ")")
+ unsigned short returnValue;
+
+ RMInit::logOut << "Request: deleteCollByName '" << collName << "'..." << std::flush;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+ // delete old transfer structures
+ context->releaseTransferStructures();
+
+ //
+ // delete collenction
+ //
+
+ // delete root object with collection name
+ if (MDDColl::dropMDDCollection(collName))
+ {
+ RMDBGMIDDLE( 4, RMDebug::module_servercomm, "ServerComm", "collection dropped")
+ RMInit::logOut << MSG_OK << std::endl;
+ returnValue = 0;
+ }
+ else
+ {
+ RMDBGMIDDLE( 4, RMDebug::module_servercomm, "ServerComm", "did not drop collection")
+ RMInit::logOut << "Error: collection does not exist." << std::endl;
+ returnValue = 2;
+ }
+
+ //
+ // done
+ //
+
+ context->release();
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 1;
+ }
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "deleteCollByName(" << callingClientId << ", " << collName << ") " << returnValue)
+ return returnValue;
+}
+
+
+
+unsigned short
+ServerComm::deleteObjByOId( unsigned long callingClientId,
+ r_OId& oid )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "deleteObjByOId(" << callingClientId << ", " << oid << ")");
+ unsigned short returnValue;
+
+ RMInit::logOut << "Request: deleteObjByOId " << oid << "..." << std::flush;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+ // delete old transfer structures
+ context->releaseTransferStructures();
+
+ // determine type of object
+ OId oidIf( oid.get_local_oid() );
+
+ RMDBGMIDDLE( 4, RMDebug::module_servercomm, "ServerComm", "OId of object " << oidIf)
+ OId::OIdType objType = oidIf.getType();
+
+ switch( objType )
+ {
+ case OId::MDDOID:
+ // FIXME: why not deleted?? -- PB 2005-aug-27
+ RMInit::logOut << "found MDD object; NOT deleted yet..." << MSG_OK << std::endl;
+ RMDBGMIDDLE( 4, RMDebug::module_servercomm, "ServerComm", "not deleting mdd object")
+ returnValue = 0;
+ break;
+ case OId::MDDCOLLOID:
+ RMInit::logOut << "deleting collection..." << std::flush;
+ // delete root object with collection name
+ if (MDDColl::dropMDDCollection(oidIf))
+ {
+ RMInit::logOut << MSG_OK << std::endl;
+ RMDBGMIDDLE( 4, RMDebug::module_servercomm, "ServerComm", "deleted mdd coll")
+ returnValue = 0;
+ }
+ else
+ {
+ RMInit::logOut << "Error: Collection does not exist." << std::endl;
+ RMDBGMIDDLE( 4, RMDebug::module_servercomm, "ServerComm", "did not delete mdd coll")
+ returnValue = 2;
+ }
+ break;
+ default:
+ RMInit::logOut << "Error: object has unknown type: " << objType << std::endl;
+ returnValue = 2;
+ }
+
+ //
+ // done
+ //
+
+ context->release();
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 1;
+ }
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "deleteObjByOId(" << callingClientId << ", " << oid << ")" << returnValue)
+ return returnValue;
+}
+
+
+
+unsigned short
+ServerComm::removeObjFromColl( unsigned long callingClientId,
+ const char* collName,
+ r_OId& oid )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "removeObjFromColl(" << callingClientId << ", " << collName << ", " << oid << ")")
+ unsigned short returnValue;
+
+ RMInit::logOut << "Request: removeObjFromColl '" << collName << "', oid " << oid << "..." << std::flush;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+ // delete old transfer structures
+ context->releaseTransferStructures();
+
+ OId oidIf( oid.get_local_oid() );
+
+ RMDBGMIDDLE( 4, RMDebug::module_servercomm, "ServerComm", "mdd object oid " << oidIf)
+
+ // open collection
+ MDDColl* coll = 0;
+
+ try
+ {
+ coll = MDDColl::getMDDCollection(collName);
+ RMDBGMIDDLE( 4, RMDebug::module_servercomm, "ServerComm", "retrieved mdd coll")
+ }
+ catch(r_Error& obj)
+ {
+ // collection name invalid
+ if (obj.get_kind() == r_Error::r_Error_ObjectUnknown)
+ {
+ RMInit::logOut << "Error: collection not found." << std::endl;
+ returnValue = 2;
+ }
+ else
+ {
+ RMInit::logOut << "Error " << obj.get_errorno() << ": " << obj.what() << std::endl;
+ // there should be another return code
+ returnValue = 2;
+ }
+ coll = NULL;
+ }
+ catch(std::bad_alloc)
+ {
+ RMInit::logOut << "Error: cannot allocate memory." << std::endl;
+ throw;
+ }
+ catch(...)
+ {
+ // collection name invalid
+ RMInit::logOut << "Error: unspecified exception." << std::endl;
+ returnValue = 2;
+ }
+
+ if( coll )
+ {
+ if (coll->isPersistent())
+ {
+ RMDBGMIDDLE( 4, RMDebug::module_servercomm, "ServerComm", "retrieved persistent mdd coll")
+
+ OId collId;
+ coll->getOId(collId);
+ RMDBGMIDDLE( 4, RMDebug::module_servercomm, "ServerComm", "mdd coll oid " << collId)
+ MDDColl::removeMDDObject(collId, oidIf);
+
+ // no error management yet -> returnValue = 3
+
+ RMInit::logOut << MSG_OK << std::endl;
+ returnValue = 0;
+
+ delete coll;
+ }
+ }
+
+ //
+ // done
+ //
+
+ context->release();
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 1;
+ }
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "removeObjFromColl(" << callingClientId << ", " << collName << ", " << oid << ") " << returnValue)
+ return returnValue;
+}
+
+
+unsigned short
+ServerComm::insertMDD( unsigned long callingClientId,
+ const char* collName,
+ RPCMarray* rpcMarray,
+ const char* typeName,
+ r_OId& oid )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "insertMDD" )
+ unsigned short returnValue = 0;
+
+ RMInit::logOut << "Request: insertMDD type='" << typeName << "' into collection '" << collName << "'..." << std::flush;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+ r_Data_Format myDataFmt = r_Array;
+ r_Data_Format myCurrentFmt = r_Array;
+
+ if( context != 0 )
+ {
+ // delete old transfer structures
+ context->releaseTransferStructures();
+
+ //
+ // insert the object into the collection
+ //
+
+ // Determine the type of the MDD to be inserted.
+ const MDDType* mddType = TypeFactory::mapMDDType( typeName );
+ if( mddType )
+ {
+ if( mddType->getSubtype() != MDDType::MDDONLYTYPE )
+ {
+ //
+ // open the collection
+ //
+
+ MDDColl* collection=0;
+ MDDColl* almost = 0;
+
+ try
+ {
+ almost = MDDColl::getMDDCollection( collName );
+ if (almost->isPersistent())
+ collection = (MDDColl*)almost;
+ else
+ {
+ RMInit::logOut << "Error: inserting into system collection is illegal." << std::endl;
+ context->release(); //!!!
+ throw r_Error(SYSTEM_COLLECTION_NOT_WRITABLE);
+ }
+ }
+ catch(std::bad_alloc)
+ {
+ RMInit::logOut << "Error: cannot allocate memory." << std::endl;
+ context->release(); //!!!
+ throw;
+ }
+ catch (r_Error& err)
+ {
+ RMInit::logOut << "Error " << err.get_errorno() << ": " << err.what() << std::endl;
+ returnValue = 5;
+ context->release(); //!!!
+ throw;
+ }
+ catch(...)
+ {
+ returnValue = 5;
+ RMInit::logOut << "Error: unspecific exception during collection read." << std::endl;
+ context->release();
+ return returnValue;
+ }
+
+ //
+ // check MDD and collection type for compatibility
+ //
+
+ r_Minterval domain( rpcMarray->domain );
+
+ RMDBGIF(4, RMDebug::module_servercomm, "ServerComm", \
+ char* collTypeStructure = collection->getCollectionType()->getTypeStructure(); \
+ char* mddTypeStructure = mddType->getTypeStructure(); \
+ RMInit::dbgOut << std::endl << "Collection type structure.: " << collTypeStructure << std::endl \
+ << "MDD type structure........: " << mddTypeStructure << std::endl \
+ << "MDD domain................: " << domain << std::endl; \
+ free( collTypeStructure ); \
+ free( mddTypeStructure ); )
+
+ if( !mddType->compatibleWithDomain( &domain ) )
+ {
+ // free resources
+ collection->releaseAll();
+ delete collection;
+
+ // return error
+ returnValue = 4;
+ RMInit::logOut << "Error: MDD type is not compatible wrt. its domain: " << domain << std::endl;
+
+ context->release();
+
+ return returnValue;
+ }
+
+ if( !collection->getCollectionType()->compatibleWith( mddType ) )
+ {
+ // free resources
+ collection->releaseAll();
+ delete collection;
+
+ // return error
+ returnValue = 3;
+ RMInit::logOut << "Error: MDD and collection types are incompatible." << std::endl;
+
+ context->release();
+
+ return returnValue;
+ }
+
+ //
+ // create persistent MDD object
+ //
+
+ MDDBaseType* mddBaseType = (MDDBaseType*)mddType;
+ char* dataPtr = rpcMarray->data.confarray_val;
+ unsigned long dataSize = rpcMarray->data.confarray_len;
+ // reset data area from rpc structure so that it is not deleted
+ // deletion is done by TransTile resp. Tile
+ rpcMarray->data.confarray_len = 0;
+ rpcMarray->data.confarray_val = 0;
+ int getMDDData=0;
+ const BaseType* baseType = mddBaseType->getBaseType();
+ unsigned long byteCount = domain.cell_count() * rpcMarray->cellTypeLength;
+ //r_Data_Format storageFormat = (r_Data_Format)(rpcMarray->storageFormat);
+
+ MDDObj* mddObj=0;
+ StorageLayout ms;
+ ms.setTileSize(StorageLayout::DefaultTileSize);
+ ms.setIndexType(StorageLayout::DefaultIndexType);
+ ms.setTilingScheme(StorageLayout::DefaultTilingScheme);
+ if (domain.dimension() == StorageLayout::DefaultTileConfiguration.dimension())
+ ms.setTileConfiguration(StorageLayout::DefaultTileConfiguration);
+
+ try
+ {
+ mddObj = new MDDObj(mddBaseType, domain, OId(oid.get_local_oid()), ms);
+ }
+ catch(std::bad_alloc)
+ {
+ RMInit::logOut << "Error: cannot allocate memory." << std::endl;
+ context->release(); //!!!
+ throw;
+ }
+ catch (r_Error& obj)
+ {
+ RMInit::logOut << "Error " << obj.get_errorno() << ": " << obj.what() << std::endl;
+ context->release(); //!!!
+ throw;
+ }
+ catch(...)
+ {
+ returnValue = 6;
+ RMInit::logOut << "Error: unspecific exception during creation of persistent object." << std::endl;
+
+ context->release();
+
+ return returnValue;
+ }
+
+ myDataFmt = (r_Data_Format)(rpcMarray->storageFormat);
+ myCurrentFmt = (r_Data_Format)(rpcMarray->currentFormat);
+ RMInit::dbgOut << "oid " << oid
+ << ", domain " << domain
+ << ", cell length " << rpcMarray->cellTypeLength
+ << ", data size " << dataSize
+ << ", rpc storage " << myDataFmt
+ << ", rpc transfer " << myCurrentFmt << " " << std::flush;
+
+ // store in the specified storage format; the current tile format afterwards will be the
+ // requested format if all went well, but use the (new) current format to be sure.
+ // Don't repack here, however, because it might be retiled before storage.
+ if(ensureTileFormat(myCurrentFmt, myDataFmt, domain,
+ baseType, dataPtr, dataSize, 0, 1, context->storageFormatParams) != ENSURE_TILE_FORMAT_OK)
+ {
+ //FIXME returnValue
+ returnValue = 6;
+ RMInit::logOut << "Error: illegal tile format for creating object." << std::endl;
+
+ context->release();
+
+ return returnValue;
+ }
+
+ // if compressed, getMDDData is != 0
+ if (myCurrentFmt != r_Array)
+ getMDDData = dataSize;
+
+ // This should check the compressed size rather than the raw data size
+ if( RMInit::tiling && dataSize > StorageLayout::DefaultTileSize )
+ {
+ r_Range edgeLength = (r_Range)floor(exp((1/(r_Double)domain.dimension())*
+ log((r_Double)StorageLayout::DefaultTileSize/rpcMarray->cellTypeLength)));
+
+ if (edgeLength <1)
+ edgeLength=1;
+
+ r_Minterval tileDom( domain.dimension() );
+ for( int i=0; i<tileDom.dimension(); i++ )
+ tileDom << r_Sinterval( (r_Range)0, (r_Range)(edgeLength-1) );
+
+ Tile* entireTile = 0;
+
+ // compression intelligence moved somewhere else, but creation of
+ // compression object in tile constructor might throw an error.
+
+ if (r_Tile_Compression::check_data_format(myDataFmt) == r_Tile_Compression::COMPRESSION)
+ {
+ RMInit::dbgOut << "insertTile created new TransTile (" << myDataFmt << "), ";
+ }
+ else
+ {
+ RMInit::logOut << "Warning: unsupported data format '" << myCurrentFmt << "', falling back to 'r_Array'..." << std::flush;
+ myCurrentFmt = r_Array;
+ }
+ entireTile = new Tile( domain, baseType, dataPtr, getMDDData, myDataFmt );
+
+ entireTile->setParameters(context->storageFormatParams);
+ vector< Tile *>* tileSet = entireTile->splitTile( tileDom );
+ if (entireTile->isPersistent())
+ entireTile->setPersistent(0);
+ delete entireTile;
+
+ RMInit::logOut << "creating " << tileSet->size() << " tile(s)..." << std::flush;
+
+ for( vector<Tile*>::iterator iter = tileSet->begin(); iter != tileSet->end(); iter++ )
+ mddObj->insertTile( *iter );
+
+ // delete the vector again
+ delete tileSet;
+ }
+ else
+ {
+ Tile* tile = 0;
+
+ if (r_Tile_Compression::check_data_format(myDataFmt) == r_Tile_Compression::COMPRESSION)
+ {
+ tile = new Tile( domain, baseType, dataPtr, getMDDData, myDataFmt );
+ RMInit::dbgOut << "insertTile created new TransTile (" << myDataFmt << "), ";
+ }
+ else
+ {
+ RMInit::logOut << "Error: Unsupported data format '" << myCurrentFmt << "', will ingore it..." << std::flush;
+ tile = new Tile( domain, baseType, dataPtr, getMDDData );
+ }
+
+ tile->setParameters(context->storageFormatParams);
+ RMInit::dbgOut << "one tile..." << std::flush;
+ mddObj->insertTile( tile );
+ }
+
+ collection->insert( mddObj );
+
+ // free transient memory
+ collection->releaseAll();
+
+ delete collection;
+
+ //
+ // done
+ //
+
+ RMInit::logOut << MSG_OK << std::endl;
+ }
+ else
+ {
+ RMInit::logOut << "Error: MDD type name '" << typeName << "' has no base type." << std::endl;
+ returnValue = 2;
+ }
+ }
+ else
+ {
+ RMInit::logOut << "Error: MDD type name '" << typeName << "' not found." << std::endl;
+ returnValue = 2;
+ }
+
+ context->release();
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 1;
+ }
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "insertMDD " << returnValue)
+ return returnValue;
+}
+
+
+unsigned short
+ServerComm::insertTileSplitted( unsigned long callingClientId,
+ int isPersistent,
+ RPCMarray* rpcMarray,
+ r_Minterval* tileSize)
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "insertTileSplitted" )
+ unsigned short returnValue = 0;
+
+ RMInit::logOut << "Request: insertTile..." << std::flush;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+ BaseType* baseType = NULL;
+
+ if( isPersistent )
+ baseType = (BaseType*)context->assembleMDD->getCellType();
+ else
+ baseType = (BaseType*)context->transferMDD->getCellType();
+
+ // The type of the tile has to be the one of the MDD.
+ // type check missing
+
+ if( baseType != NULL )
+ {
+ r_Minterval domain( rpcMarray->domain );
+ char* dataPtr = rpcMarray->data.confarray_val;
+ unsigned long dataSize = rpcMarray->data.confarray_len;
+ // reset data area from rpc structure so that it is not deleted
+ // deletion is done by TransTile resp. Tile
+ rpcMarray->data.confarray_len = 0;
+ rpcMarray->data.confarray_val = 0;
+ int getMDDData = 0;
+ r_Data_Format myDataFmt = (r_Data_Format)(rpcMarray->storageFormat);
+ r_Data_Format myCurrentFmt = (r_Data_Format)(rpcMarray->currentFormat);
+ RMDBGMIDDLE( 2, RMDebug::module_server, "ServerComm", "insertTileSplitted - rpc storage format : " << myDataFmt)
+ RMDBGMIDDLE( 2, RMDebug::module_server, "ServerComm", "insertTileSplitted - rpc transfer format : " << myCurrentFmt)
+ // store in specified storage format; use (new) current format afterwards
+ // Don't repack here because of possible retiling.
+ if(ensureTileFormat(myCurrentFmt, myDataFmt, domain,
+ baseType, dataPtr, dataSize, 0, 1, context->storageFormatParams) != ENSURE_TILE_FORMAT_OK)
+ {
+ //FIXME returnValue
+ returnValue = 1;
+
+ context->release();
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "insertTileSplitted - ensureTileFormat Failed" )
+
+ return returnValue;
+ }
+
+ if (myCurrentFmt != r_Array)
+ getMDDData = dataSize;
+
+ Tile* tile = 0;
+
+ if (r_Tile_Compression::check_data_format(myDataFmt) == r_Tile_Compression::COMPRESSION)
+ {
+ RMInit::dbgOut << "insertTile created new TransTile (" << myDataFmt << "), ";
+ }
+ else
+ {
+ RMInit::logOut << "Warning: Unsupported data format '" << myCurrentFmt << "', will be ignored..." << std::flush;
+ myDataFmt = r_Array;
+ }
+ tile = new Tile( domain, baseType, dataPtr, getMDDData, myDataFmt );
+
+ // for java clients only: check endianness and split tile if necessary
+ if(strcmp(context->clientIdText, ServerComm::HTTPCLIENT) == 0)
+ {
+ // check endianess
+ r_Endian::r_Endianness serverEndian = r_Endian::get_endianness();
+ if(serverEndian != r_Endian::r_Endian_Big)
+ {
+ RMInit::dbgOut << "changing endianness..." << std::flush;
+
+ // we have to swap the endianess
+ char *tpstruct;
+ r_Base_Type *useType;
+ tpstruct = baseType->getTypeStructure();
+ useType = (r_Base_Type*)(r_Type::get_any_type(tpstruct));
+
+ char* tempT = (char*)mymalloc(sizeof(char) * tile->getSize());
+
+ // change the endianness of the entire tile for identical domains for src and dest
+ r_Endian::swap_array(useType, domain, domain, tile->getContents(), tempT);
+ tile->setContents(tempT);
+
+ delete useType;
+ free(tpstruct);
+ }
+
+ // Split the tile!
+ vector< Tile *>* tileSet = tile->splitTile( *tileSize );
+ RMInit::dbgOut << "Now inserting splitted tile...";
+ for( vector<Tile*>::iterator iter = tileSet->begin(); iter != tileSet->end(); iter++ )
+ {
+ (*iter)->setParameters(context->storageFormatParams);
+ if( isPersistent )
+ context->assembleMDD->insertTile( *iter );
+ else
+ context->transferMDD->insertTile( *iter );
+ }
+ // delete the vector again
+ delete tile;
+ delete tileSet;
+ }
+ // for c++ clients: insert tile
+ else
+ {
+ //insert one single tile
+ // later, we should take into consideration the default server tile-size!
+ RMInit::logOut << "Now inserting single tile...";
+ tile->setParameters(context->storageFormatParams);
+ if( isPersistent )
+ context->assembleMDD->insertTile( tile );
+ else
+ context->transferMDD->insertTile( tile );
+ //do not access tile again, because it was already deleted in insertTile
+ }
+ //
+ // done
+ //
+
+ RMInit::logOut << MSG_OK << std::endl;
+ }
+ else
+ RMInit::logOut << "Error: tile and MDD base type do not match." << std::endl;
+
+ context->release();
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 1;
+ }
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "insertTileSplitted" )
+ return returnValue;
+}
+
+
+unsigned short
+ServerComm::insertTile( unsigned long callingClientId,
+ int isPersistent,
+ RPCMarray* rpcMarray )
+{
+ // no log here, is done in RNP comm.
+
+ unsigned short returnValue = insertTileSplitted(callingClientId, isPersistent, rpcMarray, NULL);
+
+ return returnValue;
+}
+
+
+unsigned short
+ServerComm::startInsertPersMDD( unsigned long callingClientId,
+ const char* collName,
+ r_Minterval &domain,
+ unsigned long typeLength,
+ const char* typeName,
+ r_OId& oid )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "startInsertPersMDD" )
+ unsigned short returnValue = 0;
+
+ RMInit::logOut << "Request: startInsertPersMDD type '" << typeName
+ << "', collection '" << collName << "', domain " << domain << ", cell length " << typeLength
+ << ", " << domain.cell_count()*typeLength << " bytes..." << std::flush;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+ // delete old transfer structures
+ context->releaseTransferStructures();
+
+ // Determine the type of the MDD to be inserted.
+ const MDDType* mddType = TypeFactory::mapMDDType( typeName );
+
+ if( mddType )
+ {
+ if( mddType->getSubtype() != MDDType::MDDONLYTYPE )
+ {
+ MDDBaseType* mddBaseType = (MDDBaseType*)mddType;
+
+ try
+ {
+ // store PersMDDColl for insert operation at the end of the transfer
+ context->transferColl = MDDColl::getMDDCollection( collName );
+ if (!context->transferColl->isPersistent())
+ {
+ RMInit::logOut << "Error: inserting into system collection is illegal." << std::endl;
+ context->release(); //!!!
+ throw r_Error(SYSTEM_COLLECTION_NOT_WRITABLE);
+ }
+ }
+ catch (r_Error& obj)
+ {
+ RMInit::logOut << "Error " << obj.get_errorno() << ": " << obj.what() << std::endl;
+ context->release(); //!!!
+ throw;
+ }
+ catch(std::bad_alloc)
+ {
+ RMInit::logOut << "Error: cannot allocate memory." << std::endl;
+ context->release(); //!!!
+ throw;
+ }
+ catch(...)
+ {
+ returnValue = 5;
+ RMInit::logOut << "Error: unspecific exception while opening collection." << std::endl;
+
+ context->release();
+
+ return returnValue;
+ }
+
+ //
+ // check MDD and collection type for compatibility
+ //
+
+ RMDBGIF(4, RMDebug::module_servercomm, "ServerComm", \
+ char* collTypeStructure = context->transferColl->getCollectionType()->getTypeStructure(); \
+ char* mddTypeStructure = mddType->getTypeStructure(); \
+ RMInit::dbgOut << std::endl << "Collection type structure.: " << collTypeStructure << std::endl \
+ << "MDD type structure........: " << mddTypeStructure << std::endl \
+ << "MDD domain................: " << domain << std::endl; \
+ free( collTypeStructure ); \
+ free( mddTypeStructure ); )
+
+ if( !mddType->compatibleWithDomain( &domain ) )
+ {
+ // free resources
+ context->transferColl->releaseAll();
+ delete context->transferColl;
+ context->transferColl = 0;
+
+ // return error
+ returnValue = 4;
+ RMInit::logOut << "Error: MDD type not compatible wrt. its domain: " << domain << MSG_FAILED << std::endl;
+
+ context->release();
+
+ return returnValue;
+ }
+
+ if( !context->transferColl->getCollectionType()->compatibleWith( mddType ) )
+ {
+ // free resources
+ context->transferColl->releaseAll();
+ delete context->transferColl;
+ context->transferColl = 0;
+
+ // return error
+ returnValue = 3;
+ RMInit::logOut << "Error: incompatible MDD and collection types." << std::endl;
+
+ context->release();
+
+ return returnValue;
+ }
+
+ //
+ // Create persistent MDD for further tile insertions
+ //
+
+ StorageLayout ms;
+ ms.setTileSize(StorageLayout::DefaultTileSize);
+ ms.setIndexType(StorageLayout::DefaultIndexType);
+ ms.setTilingScheme(StorageLayout::DefaultTilingScheme);
+ if (domain.dimension() == StorageLayout::DefaultTileConfiguration.dimension())
+ ms.setTileConfiguration(StorageLayout::DefaultTileConfiguration);
+ try
+ {
+ context->assembleMDD = new MDDObj( mddBaseType, domain, OId( oid.get_local_oid() ), ms );
+ }
+ catch (r_Error& err)
+ {
+ RMInit::logOut << "Error: while creating persistent tile: " << err.get_errorno() << ": " << err.what() << std::endl;
+ context->release(); //!!!
+ throw;
+ }
+ catch(std::bad_alloc)
+ {
+ RMInit::logOut << "Error: cannot allocate memory." << std::endl;
+ context->release(); //!!!
+ throw;
+ }
+ catch(...)
+ {
+ returnValue = 6;
+ RMInit::logOut << "Error: unspecific exception during creation of persistent object." << std::endl;
+
+ context->release();
+
+ return returnValue;
+ }
+
+ RMInit::logOut << MSG_OK << std::endl;
+ }
+ else
+ {
+ RMInit::logOut << "Error: MDD type '" << typeName << "' has no base type..." << std::endl;
+ returnValue = 2;
+ }
+ }
+ else
+ {
+ RMInit::logOut << "Error: MDD type name '" << typeName << "' not found." << std::endl;
+ returnValue = 2;
+ }
+
+ context->release();
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 1;
+ }
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "startInsertPersMDD" )
+ return returnValue;
+}
+
+
+/*************************************************************************
+ * Method name...: executeQuery( unsigned long callingClientId,
+ * const char* query
+ * ExecuteQueryRes &returnStructure )
+ ************************************************************************/
+unsigned short
+ServerComm::executeQuery( unsigned long callingClientId,
+ const char* query,
+ ExecuteQueryRes &returnStructure )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "executeQuery" )
+ unsigned short returnValue=0;
+
+ // set all to zero as default. They are not really applicable here.
+ returnStructure.errorNo = 0;
+ returnStructure.lineNo = 0;
+ returnStructure.columnNo = 0;
+
+ RMInit::logOut << "Request: executeQquery '" << query << "'..." << std::flush;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+#ifdef RMANBENCHMARK
+ RMTimer* queryOptimizationTimer = 0;
+
+ Tile::relTimer.start();
+ Tile::relTimer.pause();
+ Tile::opTimer.start();
+ Tile::opTimer.pause();
+ ZLibCompression::decompTimer.start();
+ ZLibCompression::decompTimer.pause();
+ ZLibCompression::compTimer.start();
+ ZLibCompression::compTimer.pause();
+
+ if( RManBenchmark > 0 )
+ RMInit::bmOut << "Query: " << query << std::endl;
+#endif
+
+#ifdef PURIFY
+ purify_printf( "%s\n", query );
+#endif
+
+ // delete old transfer collection/iterator
+ context->releaseTransferStructures();
+
+ //
+ // execute the query
+ //
+
+#ifdef RMANBENCHMARK
+ if( RManBenchmark > 0 )
+ queryOptimizationTimer = new RMTimer("ServerComm", "optimization time");
+#endif
+
+
+
+ QueryTree* qtree = new QueryTree(); // create a query tree object...
+ parseQueryTree = qtree; // ...and assign it to the global parse query tree pointer;
+
+ currentClientTblElt = context; // assign current client table element (temporary)
+
+ int ppRet = 0;
+ int parserRet = 0;
+
+ udfEnabled = 0; // Forced for RNP, but only temporary...
+ if(udfEnabled)
+ {
+ //
+ // preprocess
+ //
+ RMInit::logOut << "preprocessing..." << std::flush;
+ ppInBuf = (char *)query;
+ ppreset();
+ ppRet = ppparse();
+
+ RMInit::dbgOut << "new query: '" << ppOutBuf << "'..." << std::flush;
+
+ // initialize the input string parameters
+ beginParseString = ppOutBuf;
+ iterParseString = ppOutBuf;
+ }
+ else
+ {
+ beginParseString = (char*)query;
+ iterParseString = (char*)query;
+ }
+
+ yyreset();
+
+ RMInit::logOut << "parsing..." << std::flush;
+
+ parserRet=yyparse(0);
+ if((ppRet == 0) && (parserRet == 0))
+ {
+ try
+ {
+ RMDBGIF(1, RMDebug::module_servercomm, "ServerComm::executeQuery", \
+ qtree->printTree( 2, RMInit::logOut);
+ );
+
+ RMInit::logOut << "checking semantics..." << std::flush;
+ qtree->checkSemantics();
+
+ unsigned int localOptimizationLevel = globalOptimizationLevel < qtree->getOptimizationLevel() ?
+ globalOptimizationLevel : qtree->getOptimizationLevel();
+
+ RMInit::logOut << "optimizing (level " << localOptimizationLevel << ")..." << std::flush;
+ qtree->optimize( localOptimizationLevel );
+
+ RMDBGIF(1, RMDebug::module_servercomm, "ServerComm::executeQuery", \
+ qtree->printTree( 2, RMInit::logOut );
+ );
+
+#ifdef RMANBENCHMARK
+ if( queryOptimizationTimer )
+ {
+ delete queryOptimizationTimer;
+ queryOptimizationTimer = 0;
+ }
+
+ if( RManBenchmark > 0 )
+ context->evaluationTimer = new RMTimer("ServerComm", "evaluation time ");
+#endif
+ qtree->printTree( 2, std::cout );
+ //qtree->checkSemantics();
+ //qtree->printTree( 2, std::cout );
+ RMInit::logOut << "evaluating..." << std::flush;
+ context->transferData = qtree->evaluateRetrieval();
+ }
+ catch( ParseInfo& info )
+ {
+ // this is the old error handling which has been here for quite some time
+ // dealing with errors when release data
+ context->releaseTransferStructures();
+
+ returnValue = 5; // execution error
+
+ // set the error values of the return structure
+ returnStructure.errorNo = info.getErrorNo();
+ returnStructure.lineNo = info.getLineNo();
+ returnStructure.columnNo = info.getColumnNo();
+ returnStructure.token = strdup( info.getToken().c_str() );
+
+ RMInit::logOut << "Error: cannot parse query (1)." << std::endl;
+ info.printStatus( RMInit::logOut );
+ }
+ catch( r_Ebase_dbms& myErr )
+ {
+ RMInit::logOut << "Error: base DBMS exception: " << myErr.what() << std::endl;
+
+ // release data
+ context->releaseTransferStructures();
+ context->release(); //!!!
+
+ //delete parser data
+ parseQueryTree = 0;
+ currentClientTblElt = 0;
+ delete qtree;
+
+ returnValue = 42; // general serialisable exception
+
+ throw;
+ }
+ catch( r_Error& myErr )
+ {
+ RMInit::logOut << "Error: " << myErr.get_errorno() << " " << myErr.what() << std::endl;
+
+ // release data
+ context->releaseTransferStructures();
+ context->release(); //!!!
+
+ //delete parser data
+ parseQueryTree = 0;
+ currentClientTblElt = 0;
+ delete qtree;
+
+ returnValue = 5;
+
+ throw;
+ }
+ catch(std::bad_alloc)
+ {
+ RMInit::logOut << "Error: cannot allocate memory." << std::endl;
+
+ // release data
+ context->releaseTransferStructures();
+ context->release(); //!!!
+
+ //delete parser data
+ parseQueryTree = 0;
+ currentClientTblElt = 0;
+ delete qtree;
+
+ throw;
+ }
+ catch(...)
+ {
+ RMInit::logOut << "Error: unspecific exception." << std::endl;
+
+ context->releaseTransferStructures();
+ context->release(); //!!!
+
+ //delete parser data
+ parseQueryTree = 0;
+ currentClientTblElt = 0;
+ delete qtree;
+
+ returnValue = 5;
+
+ throw;
+ }
+
+ if( returnValue == 0 )
+ {
+ if( context->transferData != 0 )
+ {
+ // create the transfer iterator
+ context->transferDataIter = new vector<QtData*>::iterator;
+ *(context->transferDataIter) = context->transferData->begin();
+
+ //
+ // set typeName and typeStructure
+ //
+
+ // The type of first result object is used to determine the type of the result
+ // collection.
+ if( *(context->transferDataIter) != context->transferData->end() )
+ {
+ QtData* firstElement = (**(context->transferDataIter));
+
+ if( firstElement->getDataType() == QT_MDD )
+ {
+ QtMDD* mddObj = (QtMDD*)firstElement;
+ const BaseType* baseType = mddObj->getMDDObject()->getCellType();
+ r_Minterval domain = mddObj->getLoadDomain();
+
+ MDDType* mddType = new MDDDomainType( "tmp", (BaseType*)baseType, domain );
+ SetType* setType = new SetType( "tmp", mddType );
+
+ returnStructure.typeName = strdup( setType->getTypeName() );
+ returnStructure.typeStructure = setType->getTypeStructure(); // no copy
+
+ TypeFactory::addTempType( setType );
+ TypeFactory::addTempType( mddType );
+ }
+ else
+ {
+ returnValue = 1; // evaluation ok, non-MDD elements
+
+ returnStructure.typeName = strdup("");
+
+ // hack set type
+ char* elementType = firstElement->getTypeStructure();
+ returnStructure.typeStructure = (char*)mymalloc( strlen(elementType) + 6 );
+ sprintf( returnStructure.typeStructure, "set<%s>", elementType );
+ free( elementType );
+ }
+
+ strcpy(globalHTTPSetTypeStructure, returnStructure.typeStructure);
+
+ RMInit::logOut << MSG_OK << ", result type '" << returnStructure.typeStructure << "', " << context->transferData->size() << " element(s)." << std::endl;
+ }
+ else
+ {
+ RMInit::logOut << MSG_OK << ", result is empty." << std::endl;
+ returnValue = 2; // evaluation ok, no elements
+
+ returnStructure.typeName = strdup("");
+ returnStructure.typeStructure = strdup("");
+ }
+ }
+ else
+ {
+ RMInit::logOut << MSG_OK << ", result is empty." << std::endl;
+ returnValue = 2; // evaluation ok, no elements
+ }
+ }
+ }
+ else
+ {
+ if(ppRet)
+ {
+ RMInit::logOut << MSG_OK << ",result is empty." << std::endl;
+ returnValue = 2; // evaluation ok, no elements
+ }
+ else // parse error
+ {
+ if( parseError )
+ {
+ returnStructure.errorNo = parseError->getErrorNo();
+ returnStructure.lineNo = parseError->getLineNo();
+ returnStructure.columnNo = parseError->getColumnNo();
+ returnStructure.token = strdup( parseError->getToken().c_str() );
+
+ delete parseError;
+ parseError = 0;
+ }
+ else
+ {
+ returnStructure.errorNo = 309;
+ RMInit::logOut << "Internal Error: Unknown parse error.";
+ }
+
+ yyreset(); // reset the input buffer of the scanner
+
+ RMInit::logOut << "Error: cannot parse query (2)." << std::endl;
+ returnValue = 4;
+ }
+ }
+
+ parseQueryTree = 0;
+ currentClientTblElt = 0;
+ delete qtree;
+
+ //
+ // done
+ //
+
+#ifdef RMANBENCHMARK
+ if( queryOptimizationTimer )
+ delete queryOptimizationTimer;
+
+ // Evaluation timer can not be stopped because some time spent in the transfer
+ // module is added to this phase.
+ if( context->evaluationTimer )
+ context->evaluationTimer->pause();
+
+ if( RManBenchmark > 0 )
+ context->transferTimer = new RMTimer("ServerComm", "transfer time ");
+#endif
+
+ // In case of an error or the result set is empty, no endTransfer()
+ // is called by the client.
+ // Therefore, some things have to be release here.
+ if( returnValue >= 2)
+ {
+#ifdef RMANBENCHMARK
+ Tile::o2Timer.stop();
+ Tile::opTimer.stop();
+ Tile::relTimer.stop();
+ Tile::opTimer.stop();
+ ZLibCompression::decompTimer.stop();
+ ZLibCompression::compTimer.stop();
+ if( context->evaluationTimer )
+ delete context->evaluationTimer;
+ context->evaluationTimer = 0;
+
+ if( context->transferTimer )
+ delete context->transferTimer;
+ context->transferTimer = 0;
+
+ RMTimer* releaseTimer = 0;
+
+ if( RManBenchmark > 0 )
+ releaseTimer = new RMTimer("ServerComm", "release time ");
+#endif
+
+ // release transfer collection/iterator
+ context->releaseTransferStructures();
+
+#ifdef RMANBENCHMARK
+ if( releaseTimer )
+ delete releaseTimer;
+#endif
+ }
+ context->release();
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 3;
+ }
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "executeQuery" )
+ return returnValue;
+}
+
+
+
+unsigned short
+ServerComm::initExecuteUpdate( unsigned long callingClientId )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "initExecuteUpdate" )
+ unsigned short returnValue = 0;
+
+ RMInit::logOut << "Request: initExecuteUpdate..." << std::flush;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+ // delete old transfer structures
+ context->releaseTransferStructures();
+
+ MDDType* mddType = new MDDType( "tmp" );
+ SetType* setType = new SetType( "tmp", mddType );
+
+ TypeFactory::addTempType( mddType );
+ TypeFactory::addTempType( setType );
+
+ // create a transient collection for storing MDD constants
+ context->transferColl = new MDDColl( setType );
+
+ context->release();
+
+ RMInit::logOut << MSG_OK << std::endl;
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 1;
+ }
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "initExecuteUpdate" )
+ return returnValue;
+}
+
+
+
+unsigned short
+ServerComm::startInsertTransMDD( unsigned long callingClientId,
+ r_Minterval &domain, unsigned long typeLength,
+ const char* typeName )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "startInsertTransMDD" )
+ unsigned short returnValue = 0;
+
+ RMInit::logOut << "Request: startInsertTransMDD type '"
+ << typeName <<"', domain " << domain << ", cell length " << typeLength << ", "
+ << domain.cell_count()*typeLength << " bytes..." << std::flush;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+
+ RMDBGMIDDLE(1, RMDebug::module_servercomm, "ServerComm", "startInsertTransMDD(...) TRANSFER " << context->transferFormat << ", EXACT " << (bool)context->exactFormat);
+
+ // Determine the type of the MDD to be inserted.
+ const MDDType* mddType = TypeFactory::mapMDDType( typeName );
+
+ if( mddType )
+ {
+ if( mddType->getSubtype() != MDDType::MDDONLYTYPE )
+ {
+ MDDBaseType* mddBaseType = (MDDBaseType*)mddType;
+
+ if( !mddType->compatibleWithDomain( &domain ) )
+ {
+ // return error
+ returnValue = 3;
+ RMInit::logOut << "Error: MDD type incompatible wrt. domain: " << domain << std::endl;
+
+ context->release();
+
+ return returnValue;
+ }
+
+ // create for further insertions
+ context->transferMDD = new MDDObj( mddBaseType, domain );
+
+ RMInit::logOut << MSG_OK << std::endl;
+ }
+ else
+ {
+ RMInit::logOut << "Error: MDD type has no base type." << std::endl;
+ returnValue = 2;
+ }
+ }
+ else
+ {
+ RMInit::logOut << "Error: MDD type not found." << std::endl;
+ returnValue = 2;
+ }
+
+ context->release();
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 1;
+ }
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "startInsertTransMDD" )
+ return returnValue;
+}
+
+
+
+unsigned short
+ServerComm::endInsertMDD( unsigned long callingClientId,
+ int isPersistent )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "endInsertMDD" )
+ unsigned short returnValue = 0;
+
+ RMInit::logOut << "Request: endInsertMDD..." << std::flush;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+ if( isPersistent )
+ {
+ // we are finished with this MDD Object, so insert it into the collection
+ context->transferColl->insert( context->assembleMDD );
+
+ // reset assembleMDD, because otherwise it is tried to be freed
+ context->assembleMDD = 0;
+
+ // free transfer structure
+ context->releaseTransferStructures();
+
+ // old: context->transferColl->releaseAll(); caused a crash because releaseAll() is not idempotent
+ }
+ else
+ {
+ // we are finished with this MDD Object, so insert it into the collection
+ context->transferColl->insert( context->transferMDD );
+
+ // reset transferMDD
+ context->transferMDD = 0;
+
+ // Do not delete the transfer structure because the transient set
+ // of MDD objects will be used as constants for executeUpdate().
+ }
+
+ RMInit::logOut << MSG_OK << std::endl;
+
+ context->release();
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 1;
+ }
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "endInsertMDD" )
+ return returnValue;
+}
+
+
+
+unsigned short
+ServerComm::executeUpdate( unsigned long callingClientId,
+ const char* query,
+ ExecuteUpdateRes &returnStructure )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "executeUpdate" )
+
+ RMInit::logOut << "Request: executeUpdate query '" << query << "'..." << std::flush;
+
+#ifdef RMANBENCHMARK
+ RMTimer* queryOptimizationTimer = 0;
+ Tile::relTimer.start();
+ Tile::relTimer.pause();
+ Tile::opTimer.start();
+ Tile::opTimer.pause();
+ ZLibCompression::decompTimer.start();
+ ZLibCompression::decompTimer.pause();
+ ZLibCompression::compTimer.start();
+ ZLibCompression::compTimer.pause();
+
+ if( RManBenchmark > 0 )
+ RMInit::bmOut << "Query (update): " << query << std::endl;
+#endif
+
+ unsigned short returnValue = 0;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+#ifdef PURIFY
+ purify_printf( "%s\n", query );
+#endif
+
+ //
+ // execute the query
+ //
+
+#ifdef RMANBENCHMARK
+ if( RManBenchmark > 0 )
+ queryOptimizationTimer = new RMTimer("ServerComm", "optimization time");
+#endif
+
+ QueryTree* qtree = new QueryTree(); // create a query tree object...
+ parseQueryTree = qtree; // ...and assign it to the global parse query tree pointer;
+
+ mddConstants = context->transferColl; // assign the mdd constants collection to the global pointer (temporary)
+ currentClientTblElt = context; // assign current client table element (temporary)
+
+ int ppRet = 0;
+ udfEnabled = false; // forced for RNP tests
+ if(udfEnabled)
+ {
+ //
+ // preprocess
+ //
+ RMInit::logOut << "preprocessing..." << std::flush;
+ ppInBuf = (char *)query;
+ ppreset();
+ ppRet = ppparse();
+
+ if(ppOutBuf)
+ RMInit::dbgOut << "new query: '" << ppOutBuf << "'" << std::endl;
+ else
+ RMInit::dbgOut << "new query: empty." << std::endl;
+
+ // initialize the input string parameters
+ beginParseString = ppOutBuf;
+ iterParseString = ppOutBuf;
+ }
+ else
+ {
+ beginParseString = (char*)query;
+ iterParseString = (char*)query;
+ }
+
+ yyreset();
+
+ RMInit::logOut << "parsing..." << std::flush;
+
+ if( ppRet == 0 && yyparse(0) == 0 )
+ {
+ try
+ {
+ RMDBGIF(1, RMDebug::module_servercomm, "ServerComm::executeUpdate", \
+ qtree->printTree( 2, RMInit::logOut );
+ );
+
+ RMInit::logOut << "checking semantics..." << std::flush;
+
+ qtree->checkSemantics();
+
+ // coman: Why is disabled optimization for update query?
+ // unsigned int localOptimizationLevel = globalOptimizationLevel < qtree->getOptimizationLevel() ?
+ // globalOptimizationLevel : qtree->getOptimizationLevel();
+
+ unsigned int localOptimizationLevel = 0;
+
+ RMInit::logOut << "optimizing (level " << localOptimizationLevel << ")..." << std::flush;
+ qtree->optimize( localOptimizationLevel );
+
+ RMDBGIF(1, RMDebug::module_servercomm, "ServerComm::executeUpdate", \
+ qtree->printTree( 2, RMInit::logOut );
+ );
+
+#ifdef RMANBENCHMARK
+ if( queryOptimizationTimer )
+ {
+ delete queryOptimizationTimer;
+ queryOptimizationTimer = 0;
+ }
+
+ if( RManBenchmark > 0 )
+ context->evaluationTimer = new RMTimer("ServerComm", "evaluation time ");
+#endif
+
+ RMInit::logOut << "evaluating..." << std::flush;
+ qtree->evaluateUpdate();
+
+ // release data
+ context->releaseTransferStructures();
+
+ RMInit::logOut << MSG_OK << std::endl;
+ }
+ catch( ParseInfo& info )
+ {
+ // release data
+ context->releaseTransferStructures();
+
+ returnValue = 3; // evaluation error
+
+ // set the error values of the return structure
+ returnStructure.errorNo = info.getErrorNo();
+ returnStructure.lineNo = info.getLineNo();
+ returnStructure.columnNo = info.getColumnNo();
+ returnStructure.token = strdup( info.getToken().c_str() );
+
+ RMInit::logOut << "Error: cannot parse query (1)." << std::endl;
+ info.printStatus( RMInit::logOut );
+ }
+ catch(r_Error &err)
+ {
+ context->releaseTransferStructures();
+ context->release();
+ RMInit::logOut << "Error: " << err.get_errorno() << " " << err.what() << std::endl;
+ throw;
+ }
+ }
+ else
+ {
+ if(ppRet)
+ {
+ RMInit::logOut << MSG_OK << std::endl;
+ returnValue = 0;
+ }
+ else // parse error
+ {
+ if( parseError )
+ {
+ returnStructure.errorNo = parseError->getErrorNo();
+ returnStructure.lineNo = parseError->getLineNo();
+ returnStructure.columnNo = parseError->getColumnNo();
+ returnStructure.token = strdup( parseError->getToken().c_str() );
+
+ delete parseError;
+
+ RMInit::logOut << "Error: cannot parse query (2)." << std::endl;
+ parseError = 0;
+ }
+ else
+ {
+ returnStructure.errorNo = 309;
+ RMInit::logOut << "Error: unspecific internal parser error." << endl;
+ }
+
+ yyreset(); // reset the input buffer of the scanner
+
+ returnValue = 2;
+ }
+ }
+
+ parseQueryTree = 0;
+ mddConstants = 0;
+ currentClientTblElt = 0;
+ delete qtree;
+
+ // delete set of mdd constants
+ context->releaseTransferStructures();
+
+ //
+ // done
+ //
+
+ context->release();
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 1;
+ }
+
+
+#ifdef RMANBENCHMARK
+ if( queryOptimizationTimer )
+ delete queryOptimizationTimer;
+
+ // stop evaluation timer
+ if( context->evaluationTimer )
+ {
+ delete context->evaluationTimer;
+ context->evaluationTimer = 0;
+ }
+
+ Tile::opTimer.stop();
+ Tile::relTimer.stop();
+ ZLibCompression::decompTimer.stop();
+ ZLibCompression::compTimer.stop();
+#endif
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "executeUpdate" )
+ return returnValue;
+}
+
+
+
+unsigned short
+ServerComm::getCollByName( unsigned long callingClientId,
+ const char* collName,
+ char* &typeName,
+ char* &typeStructure,
+ r_OId &oid )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "ServerComm::getCollByName" )
+
+ RMInit::logOut << "Request: getCollByName '" << collName << "'..." << std::flush;
+
+ unsigned short returnValue=0;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+ //
+ // create the actual transfer collenction
+ //
+
+ // delete old transfer collection/iterator
+ context->releaseTransferStructures();
+
+ // create the transfer collection
+ try
+ {
+ context->transferColl = MDDColl::getMDDCollection( collName );
+ RMDBGMIDDLE( 4, RMDebug::module_server, "ServerComm", "retrieved mdd collection" )
+ }
+ catch(std::bad_alloc)
+ {
+ RMInit::logOut << "Error: cannot allocate memory." << std::endl;
+ context->release(); //!!!
+ throw;
+ }
+ catch (r_Error& err)
+ {
+ RMInit::logOut << "Error " << err.get_errorno() << " " << err.what() << std::endl;
+ context->release(); //!!!
+ throw;
+ }
+ catch(...)
+ {
+ returnValue = 2; // collection name invalid
+ RMInit::logOut << "Error: unspecific exception." << std::endl;
+ }
+
+ if( returnValue == 0 )
+ {
+ // create the transfer iterator
+ context->transferCollIter = context->transferColl->createIterator();
+ context->transferCollIter->reset();
+
+ // set typeName and typeStructure
+ CollectionType* collectionType = (CollectionType*) context->transferColl->getCollectionType();
+
+ if( collectionType )
+ {
+ typeName = strdup( collectionType->getTypeName() );
+ typeStructure = collectionType->getTypeStructure(); // no copy !!!
+
+ // set oid in case of a persistent collection
+ if( context->transferColl->isPersistent() )
+ {
+ EOId eOId;
+ if (context->transferColl->isPersistent())
+ {
+ if (context->transferColl->getEOId(eOId) == true)
+ oid = r_OId( eOId.getSystemName(), eOId.getBaseName(), eOId.getOId() );
+ }
+ }
+ RMInit::logOut << MSG_OK << std::endl;
+ }
+ else
+ {
+ RMInit::logOut << "Warning: cannot obtain collection type information." << endl;
+ typeName = strdup("");
+ typeStructure = strdup("");
+ }
+
+ if( !context->transferCollIter->notDone() )
+ {
+ RMInit::logOut << MSG_OK << ", result empty.";
+ returnValue = 1;
+
+ // delete transfer collection/iterator
+ context->releaseTransferStructures();
+ }
+ }
+
+ //
+ // done
+ //
+
+ context->release();
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 3;
+ }
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", " ServerComm::getCollByName" )
+
+ return returnValue;
+}
+
+
+
+unsigned short
+ServerComm::getCollByOId( unsigned long callingClientId,
+ r_OId &oid,
+ char* &typeName,
+ char* &typeStructure,
+ char* &collName )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", " ServerComm::getCollByOId" )
+
+ RMInit::logOut << "Request: getCollByOId " << oid << "..." << std::flush;
+
+ unsigned short returnValue=0;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+ // delete old transfer collection/iterator
+ context->releaseTransferStructures();
+
+ // check type and existence of oid
+ OId oidIf( oid.get_local_oid() );
+ OId::OIdType objType = oidIf.getType();
+
+ if( objType == OId::MDDCOLLOID )
+ {
+ //
+ // get collection
+ //
+
+ try
+ {
+ RMDBGMIDDLE( 4, RMDebug::module_server, "ServerComm",
+ std::endl << " execute new PersMDDColl(" << oid << ")" )
+ context->transferColl = MDDColl::getMDDCollection(oidIf);
+ RMDBGMIDDLE( 4, RMDebug::module_server, "ServerComm", " ok" )
+ }
+ catch(std::bad_alloc)
+ {
+ RMInit::logOut << "Error: cannot allocate memory." << std::endl;
+ throw;
+ }
+ catch (r_Error& err)
+ {
+ RMInit::logOut << "Error " << err.get_errorno() << " " << err.what() << std::endl;
+ throw;
+ }
+ catch(...) // not found (?)
+ {
+ returnValue = 2;
+ RMInit::logOut << "Error: unspecific exception." << endl;
+ }
+
+ //
+ // create the actual transfer collenction
+ //
+
+ if( returnValue == 0 )
+ {
+ // get collection name
+ collName = strdup(context->transferColl->getName());
+
+ // create the transfer iterator
+ context->transferCollIter = context->transferColl->createIterator();
+ context->transferCollIter->reset();
+
+ // set typeName and typeStructure
+ CollectionType* collectionType = (CollectionType*) context->transferColl->getCollectionType();
+
+ if( collectionType )
+ {
+ typeName = strdup( collectionType->getTypeName() );
+ typeStructure = collectionType->getTypeStructure(); // no copy !!!
+
+ // set oid in case of a persistent collection
+ if( context->transferColl->isPersistent() )
+ {
+ EOId eOId;
+
+ if (context->transferColl->getEOId(eOId) == true)
+ oid = r_OId( eOId.getSystemName(), eOId.getBaseName(), eOId.getOId() );
+ }
+ RMInit::logOut << MSG_OK << std::endl;
+ }
+ else
+ {
+ RMInit::logOut << MSG_OK << ", but warning: cannot obtain type information." << endl;
+ typeName = strdup("");
+ typeStructure = strdup("");
+ }
+
+ if( !context->transferCollIter->notDone() )
+ {
+ RMInit::logOut << MSG_OK << ", result empty." << endl;
+ returnValue = 1;
+
+ // delete transfer collection/iterator
+ context->releaseTransferStructures();
+ }
+ }
+
+ }
+ else
+ {
+ returnValue = 2; // oid does not belong to a collection object
+ RMInit::logOut << "Error: oid does not belong to a collection object." << std::endl;
+ }
+
+ //
+ // done
+ //
+
+ context->release();
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 3;
+ }
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", " ServerComm::getCollByOId" )
+
+ return returnValue;
+}
+
+
+
+unsigned short
+ServerComm::getCollOIdsByName( unsigned long callingClientId,
+ const char* collName,
+ char* &typeName,
+ char* &typeStructure,
+ r_OId &oid,
+ RPCOIdEntry* &oidTable,
+ unsigned int &oidTableSize )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "getCollOIdsByName" )
+
+ RMInit::logOut << "Request: getCollOIdsByName '" << collName << "'..." << std::flush;
+
+ unsigned short returnValue=0;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+ //
+ // get collection
+ //
+
+ MDDColl* coll = 0;
+ MDDColl* almost = 0;
+
+ try
+ {
+ RMDBGMIDDLE( 4, RMDebug::module_server, "ServerComm", "retrieving collection " << collName)
+ almost = MDDColl::getMDDCollection( collName );
+ RMDBGMIDDLE( 4, RMDebug::module_server, "ServerComm", "retrieved collection " << collName)
+ if (!almost->isPersistent())
+ {
+ RMDBGMIDDLE( 4, RMDebug::module_server, "ServerComm", "retrieved system collection")
+ RMInit::logOut << "Error: trying to get oid of system collection: " << collName << std::endl;
+ throw r_Error(SYSTEM_COLLECTION_HAS_NO_OID);
+ }
+ else
+ {
+ RMDBGMIDDLE( 4, RMDebug::module_server, "ServerComm", "retrieved persistent collection")
+ coll = (MDDColl*)almost;
+ }
+ }
+ catch(std::bad_alloc)
+ {
+ RMInit::logOut << "Error: cannot allocate memory." << std::endl;
+ throw;
+ }
+ catch (r_Error& err)
+ {
+ RMDBGMIDDLE( 4, RMDebug::module_server, "ServerComm", "caught exception")
+ RMInit::logOut << "Error " << err.get_errorno() << ": " << err.what() << std::endl;
+ returnValue = 2; // collection name invalid
+ }
+ catch(...)
+ {
+ RMDBGMIDDLE( 4, RMDebug::module_server, "ServerComm", "caught exception")
+ returnValue = 2; // collection name invalid
+ RMInit::logOut << "Error: unspecific exception." << std::endl;
+ }
+ RMDBGMIDDLE( 4, RMDebug::module_server, "ServerComm", "after exception catching")
+
+ if( returnValue == 0 )
+ {
+ // set typeName and typeStructure
+ CollectionType* collectionType = (CollectionType*) coll->getCollectionType();
+
+ if( collectionType )
+ {
+ typeName = strdup( collectionType->getTypeName() );
+ typeStructure = collectionType->getTypeStructure(); // no copy !!!
+
+ // set oid
+ EOId eOId;
+
+ if (coll->getEOId(eOId) == true)
+ oid = r_OId( eOId.getSystemName(), eOId.getBaseName(), eOId.getOId() );
+ }
+ else
+ {
+ RMInit::logOut << "Warning: no type information available..." << std::flush;
+ typeName = strdup("");
+ typeStructure = strdup("");
+ }
+
+ if( coll->getCardinality() )
+ {
+ // create iterator
+ MDDCollIter* collIter = coll->createIterator();
+ int i;
+
+ oidTableSize = coll->getCardinality();
+ oidTable = (RPCOIdEntry*) mymalloc( sizeof(RPCOIdEntry) * oidTableSize );
+
+ TALK( oidTableSize << " elements..." );
+
+ for( collIter->reset(), i=0; collIter->notDone(); collIter->advance(), i++ )
+ {
+ MDDObj* mddObj = collIter->getElement();
+
+ if( mddObj->isPersistent() )
+ {
+ EOId eOId;
+
+ if( ((MDDObj*)mddObj)->getEOId( &eOId ) == 0 )
+ oidTable[i].oid = strdup( r_OId( eOId.getSystemName(), eOId.getBaseName(), eOId.getOId() ).get_string_representation() );
+ else
+ oidTable[i].oid = strdup("");
+ mddObj = 0;
+ }
+ else
+ oidTable[i].oid = strdup("");
+ }
+
+ delete collIter;
+
+ RMInit::logOut << MSG_OK << ", " << coll->getCardinality() << " result(s)." << endl;
+ }
+ else
+ {
+ RMInit::logOut << MSG_OK << ", result empty." << endl;
+ returnValue = 1;
+ }
+
+ delete coll;
+ }
+
+ //
+ // done
+ //
+
+ context->release();
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 3;
+ }
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "getCollOIdsByName " << returnValue)
+
+ return returnValue;
+}
+
+
+unsigned short
+ServerComm::getCollOIdsByOId( unsigned long callingClientId,
+ r_OId &oid,
+ char* &typeName,
+ char* &typeStructure,
+ RPCOIdEntry* &oidTable,
+ unsigned int &oidTableSize,
+ char* &collName )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "getCollOIdsByOId" )
+
+ RMInit::logOut << "Request: getCollOIdsByOId " << oid << "..." << std::flush;
+
+ unsigned short returnValue=0;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+ // check type and existence of oid
+ OId oidIf( oid.get_local_oid() );
+ OId::OIdType objType = oidIf.getType();
+
+ if( objType == OId::MDDCOLLOID )
+ {
+ //
+ // get collection
+ //
+
+ MDDColl* coll = 0;
+
+ try
+ {
+ RMDBGMIDDLE( 4, RMDebug::module_server, "ServerComm", "get mdd coll by oid " << oidIf)
+ coll = MDDColl::getMDDCollection(oidIf);
+ RMDBGMIDDLE( 4, RMDebug::module_server, "ServerComm", "retrieved mdd coll" )
+ }
+ catch(std::bad_alloc)
+ {
+ RMInit::logOut << "Error: cannot allocate memory." << std::endl;
+ throw;
+ }
+ catch (r_Error& err)
+ {
+ RMInit::logOut << "Error " << err.get_errorno() << ": " << err.what() << std::endl;
+ returnValue = 2; // collection name invalid
+ if (err.get_kind() != r_Error::r_Error_RefNull)
+ throw;
+ }
+ catch(...)
+ {
+ returnValue = 2; // collection name invalid
+ RMInit::logOut << "Error: unknown collection name." << std::endl;
+ }
+
+ if( returnValue == 0 )
+ {
+ // get collection name
+ collName = strdup(coll->getName());
+
+ // set typeName and typeStructure
+ CollectionType* collectionType = (CollectionType*) coll->getCollectionType();
+
+ if( collectionType )
+ {
+ typeName = strdup( collectionType->getTypeName() );
+ typeStructure = collectionType->getTypeStructure(); // no copy !!!
+
+ // set oid
+ EOId eOId;
+
+ if (coll->getEOId(eOId) == true)
+ oid = r_OId( eOId.getSystemName(), eOId.getBaseName(), eOId.getOId() );
+ }
+ else
+ {
+ RMInit::logOut << "Warning: no type information available..." << std::flush;
+ typeName = strdup("");
+ typeStructure = strdup("");
+ }
+
+ if( coll->getCardinality() )
+ {
+ // create iterator
+ MDDCollIter* collIter = coll->createIterator();
+ int i;
+
+ oidTableSize = coll->getCardinality();
+ oidTable = (RPCOIdEntry*) mymalloc( sizeof(RPCOIdEntry) * oidTableSize );
+
+ TALK( oidTableSize << " elements..." );
+
+ for( collIter->reset(), i=0; collIter->notDone(); collIter->advance(), i++ )
+ {
+ MDDObj* mddObj = collIter->getElement();
+
+ if( mddObj->isPersistent() )
+ {
+ EOId eOId;
+
+ if( ((MDDObj*)mddObj)->getEOId( &eOId ) == 0 )
+ oidTable[i].oid = strdup( r_OId( eOId.getSystemName(), eOId.getBaseName(), eOId.getOId() ).get_string_representation() );
+ else
+ oidTable[i].oid = strdup("");
+ }
+ else
+ oidTable[i].oid = strdup("");
+ }
+
+ delete collIter;
+ //coll->releaseAll();
+
+ RMInit::logOut << MSG_OK << ", " << coll->getCardinality() << " result(s)." << endl;
+ }
+ else
+ {
+ RMInit::logOut << MSG_OK << ", result empty." << endl;
+ returnValue = 1;
+ }
+
+ delete coll;
+ }
+ }
+ else
+ {
+ returnValue = 2; // oid does not belong to a collection object
+ RMInit::logOut << "Error: not a collection oid: " << oid << std::endl;
+ }
+
+ //
+ // done
+ //
+
+ context->release();
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 3;
+ }
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "getCollOIdsByOId " << returnValue)
+ return returnValue;
+}
+
+
+
+unsigned short
+ServerComm::getNextMDD( unsigned long callingClientId,
+ r_Minterval &mddDomain,
+ char* &typeName,
+ char* &typeStructure,
+ r_OId &oid,
+ unsigned short &currentFormat )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "getNextMDD" )
+
+ RMInit::logOut << "Request: getNextMDD..." << std::flush;
+
+ unsigned short returnValue = 0;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+ try
+ {
+ if( context->transferData && context->transferDataIter && *(context->transferDataIter) != context->transferData->end() )
+ {
+ //
+ // convert the mdd to transfer to rpc data structures
+ //
+
+ // get the MDD object to be transfered
+ QtMDD* mddData = (QtMDD*) **(context->transferDataIter);
+ MDDObj* mddObj = mddData->getMDDObject();
+
+ // initialize mddDomain to give it back
+ mddDomain = mddData->getLoadDomain();
+
+ TALK( "domain " << mddDomain );
+
+ //
+ // initialize tiles to transfer
+ //
+
+#ifdef RMANBENCHMARK
+ // pause transfer timer and resume evaluation timer
+ if( context->transferTimer )
+ context->transferTimer->pause();
+ if( context->evaluationTimer )
+ context->evaluationTimer->resume();
+#endif
+
+ if( mddObj->getCurrentDomain() == mddData->getLoadDomain() )
+ context->transTiles = mddObj->getTiles();
+ else
+ {
+ // If the load domain is different from the current domain, we have
+ // a persitent MDD object. The border tiles have to be cut (and
+ // therefore copied) in order to be ready for transfering them.
+ // These temporary border tiles are added to the deletableTiles list
+ // which is deleted at the end.
+
+ context->transTiles = mddObj->intersect( mddData->getLoadDomain() );
+
+ // iterate over the tiles
+ for( vector<Tile*>::iterator iter = context->transTiles->begin(); iter != context->transTiles->end(); iter++ )
+ {
+ // get relevant area of source tile
+ r_Minterval sourceTileDomain( mddData->getLoadDomain().create_intersection( (*iter)->getDomain() ) );
+
+ if( sourceTileDomain != (*iter)->getDomain() )
+ {
+ // create a new transient tile and copy the transient data
+ Tile* newTransTile = new Tile( sourceTileDomain, mddObj->getCellType() );
+ newTransTile->copyTile( sourceTileDomain, *iter, sourceTileDomain );
+
+ // replace the tile in the list with the new one
+ *iter = newTransTile;
+
+ // add the new tile to deleteableTiles
+ if( !(context->deletableTiles) )
+ context->deletableTiles = new vector<Tile*>();
+ context->deletableTiles->push_back( newTransTile );
+ }
+ }
+ }
+
+#ifdef RMANBENCHMARK
+ // In order to be sure that reading tiles from disk is done
+ // in the evaluation phase, the contents pointers of each tile
+ // are got.
+ char* benchmarkPointer;
+
+ for( vector<Tile*>::iterator benchmarkIter = context->transTiles->begin();
+ benchmarkIter != context->transTiles->end(); benchmarkIter++ )
+ benchmarkPointer = (*benchmarkIter)->getContents();
+
+ // pause evaluation timer and resume transfer timer
+ if( context->evaluationTimer )
+ context->evaluationTimer->pause();
+ if( context->transferTimer )
+ context->transferTimer->resume();
+#endif
+
+ // initialize tile iterator
+ context->tileIter = new vector<Tile*>::iterator;
+ *(context->tileIter) = context->transTiles->begin();
+
+ const BaseType* baseType = mddObj->getCellType();
+
+ TALK( "cell length " << baseType->getSize() );
+
+ //
+ // set typeName and typeStructure
+ //
+ // old: typeName = strdup( mddObj->getCellTypeName() ); not known for the moment being
+ typeName = strdup("");
+
+ // create a temporary mdd type for the moment being
+ r_Minterval typeDomain( mddData->getLoadDomain() );
+ MDDType* mddType = new MDDDomainType( "tmp", (BaseType*)baseType, typeDomain );
+ TypeFactory::addTempType( mddType );
+
+ typeStructure = mddType->getTypeStructure(); // no copy !!!
+
+ // I'm not sure about this code...
+#if 0
+ // determine data format from the 1st tile
+ if( context->transTiles->size() && (*(context->transTiles))[0]->getDataFormat() == r_TIFF )
+ currentFormat = r_TIFF;
+ else
+ currentFormat = r_Array;
+#else
+ if (context->transTiles->size())
+ currentFormat = (*(context->transTiles))[0]->getDataFormat();
+ else
+ currentFormat = r_Array;
+#endif
+
+ // set oid in case of persistent MDD objects
+ if( mddObj->isPersistent() )
+ {
+ EOId eOId;
+
+ if( ((MDDObj*)mddObj)->getEOId( &eOId ) == 0 )
+ oid = r_OId( eOId.getSystemName(), eOId.getBaseName(), eOId.getOId() );
+ }
+
+ //
+ //
+ //
+
+ if( context->transTiles->size() > 0 )
+ {
+ RMInit::logOut << MSG_OK << ", " << context->transTiles->size() << " more tile(s)" << endl;
+ }
+ else // context->transTiles->size() == 0
+ {
+ returnValue = 2;
+ RMInit::logOut << "Error: no tiles in MDD object." << std::endl;
+ }
+
+ context->totalTransferedSize = 0;
+ context->totalRawSize = 0;
+ }
+ else
+ {
+ if( context->transferDataIter && *(context->transferDataIter) == context->transferData->end() )
+ {
+ returnValue = 1; // nothing left in the collection
+ RMInit::logOut << MSG_OK << ", no more tiles." << std::endl;
+ context->releaseTransferStructures();
+ }
+ else
+ {
+ returnValue = 2; // no actual transfer collection
+ RMInit::logOut << "Error: no transfer collection. " << std::endl;
+ }
+ }
+
+ //
+ // done
+ //
+
+ context->release();
+ }
+ catch( r_Ebase_dbms& myErr )
+ {
+ RMInit::logOut << "Error: base DBMS exception (kind " << myErr.get_kind() << ", errno " << myErr.get_errorno() << ") " << myErr.what() << std::endl;
+ returnValue = 42;
+ throw;
+ }
+ catch( r_Error& myErr )
+ {
+ RMInit::logOut << "Error: (kind " << myErr.get_kind() << ", errno " << myErr.get_errorno() << ") " << myErr.what() << std::endl;
+ throw;
+ }
+ catch(std::bad_alloc)
+ {
+ RMInit::logOut << "Error: cannot allocate memory." << std::endl;
+ throw;
+ }
+ catch(...)
+ {
+ RMInit::logOut << "Error: unspecified exception." << std::endl;
+ }
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 2;
+ }
+
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "getNextMDD" )
+
+ return returnValue;
+}
+
+
+unsigned short
+ServerComm::getNextElement( unsigned long callingClientId,
+ char* &buffer,
+ unsigned int &bufferSize)
+{
+ RMDBGENTER(1, RMDebug::module_servercomm, "ServerComm", "getNextElement(...)")
+
+ RMInit::logOut << "Request: getNextElement..." << std::flush;
+
+ unsigned short returnValue = 0;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+ RMDBGMIDDLE(1, RMDebug::module_servercomm, "ServerComm", "getNextElement(...) TRANSFER " << context->transferFormat << ", EXACT " << (bool)context->exactFormat);
+
+ if( context->transferData && context->transferDataIter &&
+ *(context->transferDataIter) != context->transferData->end() )
+ {
+
+ //
+ // convert data element to rpc data structures
+ //
+ // Buffer is allocated and has to be freed by the caller using free().
+
+ // get next object to be transfered
+ try
+ {
+ QtData* dataObj = **(context->transferDataIter);
+
+ switch( dataObj->getDataType() )
+ {
+ case QT_STRING:
+ {
+ QtStringData* stringDataObj = (QtStringData*)dataObj;
+ bufferSize = stringDataObj->getStringData().length();
+ buffer = (char*)mymalloc( bufferSize );
+ memcpy( (void*)buffer, (void*)stringDataObj->getStringData().c_str(), bufferSize );
+ }
+ break;
+ case QT_INTERVAL:
+ {
+ QtIntervalData* intervalDataObj = (QtIntervalData*)dataObj;
+ char* stringData = intervalDataObj->getIntervalData().get_string_representation();
+ bufferSize = strlen( stringData );
+ buffer = (char*)mymalloc( bufferSize );
+ memcpy( (void*)buffer, (void*)stringData, bufferSize );
+ free( stringData );
+ }
+ break;
+ case QT_MINTERVAL:
+ {
+ QtMintervalData* mintervalDataObj = (QtMintervalData*)dataObj;
+ char* stringData = mintervalDataObj->getMintervalData().get_string_representation();
+ bufferSize = strlen( stringData );
+ buffer = (char*)mymalloc( bufferSize );
+ memcpy( (void*)buffer, (void*)stringData, bufferSize );
+ free( stringData );
+ }
+ break;
+ case QT_POINT:
+ {
+ QtPointData* pointDataObj = (QtPointData*)dataObj;
+ char* stringData = pointDataObj->getPointData().get_string_representation();
+ bufferSize = strlen( stringData );
+ buffer = (char*)mymalloc( bufferSize );
+ memcpy( (void*)buffer, (void*)stringData, bufferSize );
+
+ free( stringData );
+ }
+ break;
+ default:
+ if( dataObj->isScalarData() )
+ {
+ QtScalarData* scalarDataObj = (QtScalarData*)dataObj;
+ bufferSize = scalarDataObj->getValueType()->getSize();
+ buffer = (char*)mymalloc( bufferSize );
+ memcpy( (void*)buffer, (void*)scalarDataObj->getValueBuffer(), bufferSize );
+ // server endianess
+ r_Endian::r_Endianness serverEndian = r_Endian::get_endianness();
+
+ // change endianess if necessary
+ // currently only one client is active at one time
+ // if((context->clientId == 1) && (strcmp(context->clientIdText, ServerComm::HTTPCLIENT) == 0) && (serverEndian != r_Endian::r_Endian_Big))
+ if( (strcmp(context->clientIdText, ServerComm::HTTPCLIENT) == 0) && (serverEndian != r_Endian::r_Endian_Big))
+ {
+ RMInit::logOut << "changing endianness..." << std::flush;
+ // calling client is a http-client(java -> always BigEndian) and server has LittleEndian
+ switch(scalarDataObj->getDataType())
+ {
+ case QT_USHORT:
+ {
+ r_UShort tmp = *(r_UShort*)buffer;
+ *(r_UShort*)buffer = r_Endian::swap(tmp);
+ }
+ break;
+
+ case QT_SHORT:
+ {
+ r_Short tmp = *(r_Short*)buffer;
+ *(r_Short*)buffer = r_Endian::swap(tmp);
+ }
+ break;
+
+ case QT_LONG:
+ {
+ r_Long tmp = *(r_Long*)buffer;
+ *(r_Long*)buffer = r_Endian::swap(tmp);
+ }
+ break;
+
+ case QT_ULONG:
+ {
+ r_ULong tmp = *(r_ULong*)buffer;
+ *(r_ULong*)buffer = r_Endian::swap(tmp);
+ }
+ break;
+
+ case QT_FLOAT:
+ {
+ r_Float tmp = *(r_Float*)buffer;
+ *(r_Float*)buffer = r_Endian::swap(tmp);
+ }
+ break;
+
+ case QT_DOUBLE:
+ {
+ r_Double tmp = *(r_Double*)buffer;
+ *(r_Double*)buffer = r_Endian::swap(tmp);
+ }
+ break;
+
+ default:
+ {
+ RMDBGENTER( 0, RMDebug::module_servercomm, "ServerComm", "getNextElement(...) bad dataType " << scalarDataObj->getDataType());
+ }
+ break;
+ }
+ }
+ }
+ break;
+ }
+ }
+ catch( r_Ebase_dbms& myErr)
+ {
+ RMInit::logOut << "Error: base BMS exception (kind " << myErr.get_kind() << ", errno " << myErr.get_errorno() << ") " << myErr.what() << std::endl;
+ throw;
+ }
+ catch (r_Error& err)
+ {
+ RMInit::logOut << "Error: exception (kind " << err.get_kind() << ", errno " << err.get_errorno() << ") " << err.what() << std::endl;
+ throw;
+ }
+
+ // increment list iterator
+ (*(context->transferDataIter))++;
+
+ if( *(context->transferDataIter) != context->transferData->end() )
+ {
+ returnValue = 0;
+ RMInit::logOut << MSG_OK << ", some more tile(s) left." << endl;
+ }
+ else
+ {
+ returnValue = 1;
+ RMInit::logOut << MSG_OK << ", no more tiles." << std::endl;
+ }
+ }
+ else
+ {
+ if( context->transferDataIter && *(context->transferDataIter) == context->transferData->end() )
+ {
+ returnValue = 1; // nothing left in the collection
+ TALK( "nothing left..." << MSG_OK );
+ context->releaseTransferStructures();
+ }
+ else
+ {
+ returnValue = 2; // no actual transfer collection
+ RMInit::logOut << "Error: no transfer collection." << endl;
+ }
+ }
+
+ //
+ // done
+ //
+
+ context->release();
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 2;
+ }
+
+ RMDBGEXIT(1, RMDebug::module_servercomm, "ServerComm", "getNextElement(...)")
+ return returnValue;
+}
+
+
+
+unsigned short
+ServerComm::getMDDByOId( unsigned long callingClientId,
+ r_OId &oid,
+ r_Minterval &mddDomain,
+ char* &typeName,
+ char* &typeStructure,
+ unsigned short &currentFormat )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "getMDDByOId" )
+
+ RMInit::logOut << "Request: getMDDByOId with oid " << oid << "..." << std::flush;
+
+ unsigned short returnValue = 0;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+ // delete old transfer collection/iterator
+ context->releaseTransferStructures();
+
+ // check type and existence of oid
+ OId oidIf( oid.get_local_oid() );
+ OId::OIdType objType = oidIf.getType();
+
+ if( objType == OId::MDDOID )
+ {
+ // get MDD object
+ try
+ {
+ context->transferMDD = new MDDObj( oidIf );
+ }
+ catch(std::bad_alloc)
+ {
+ RMInit::logOut << "Error: cannot allocate memory." << std::endl;
+ context->release();
+ throw;
+ }
+ catch (r_Error& err)
+ {
+ RMInit::logOut << "Error: (kind " << err.get_kind() << ", errno " << err.get_errorno() << ") " << err.what() << std::endl;
+ context->release();
+ throw;
+ }
+ catch(...)
+ {
+ returnValue = 2;
+ RMInit::logOut << "Error: unspecified exception." << endl;
+ }
+
+ if( !returnValue )
+ {
+ //
+ // convert the mdd to transfer to rpc data structures
+ //
+
+ // initialize mddDomain to give it back
+ mddDomain = context->transferMDD->getCurrentDomain();
+
+ TALK( "domain " << mddDomain );
+
+ // initialize context fields
+ context->transTiles = context->transferMDD->getTiles();
+ context->tileIter = new vector<Tile*>::iterator;
+ *(context->tileIter) = context->transTiles->begin();
+
+ const BaseType* baseType = context->transferMDD->getCellType();
+
+ TALK( "cell length " << baseType->getSize() );
+
+ //
+ // set typeName and typeStructure
+ //
+ // old: typeName = strdup( context->transferMDD->getCellTypeName() ); not known for the moment being
+
+ typeName = strdup("");
+
+ // create a temporary mdd type for the moment being
+ MDDType* mddType = new MDDDomainType( "tmp", (BaseType*)baseType, context->transferMDD->getCurrentDomain() );
+ TypeFactory::addTempType( mddType );
+
+ typeStructure = mddType->getTypeStructure(); // no copy !!!
+
+ // I'm not sure about this code either
+#if 0
+ // determine data format from the 1st tile
+ if( context->transTiles->size() && (*(context->transTiles))[0]->getDataFormat() == r_TIFF )
+ currentFormat = r_TIFF;
+ else
+ currentFormat = r_Array;
+#else
+ if (context->transTiles->size())
+ currentFormat = (*(context->transTiles))[0]->getDataFormat();
+ else
+ currentFormat = r_Array;
+#endif
+
+ // set oid in case of persistent MDD objects
+ if( context->transferMDD->isPersistent() )
+ {
+ EOId eOId;
+
+ if( ((MDDObj*)(context->transferMDD))->getEOId( &eOId ) == 0 )
+ oid = r_OId( eOId.getSystemName(), eOId.getBaseName(), eOId.getOId() );
+ }
+
+ //
+ //
+ //
+
+ if( context->transTiles->size() > 0 )
+ {
+ RMInit::logOut << MSG_OK << ", got " << context->transTiles->size() << " tile(s)." << endl;
+ }
+ else // context->transTiles->size() == 0
+ {
+ returnValue = 3;
+ RMInit::logOut << "Error: no tiles in MDD object." << endl;
+ }
+ }
+ }
+ else
+ {
+ returnValue = 2; // oid does not belong to an MDD object
+ RMInit::logOut << "Error: oid does not belong to an MDD object." << endl;
+ }
+
+ //
+ // done
+ //
+
+ context->release();
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 1; // client context not found
+ }
+
+ context->totalRawSize = 0;
+ context->totalTransferedSize = 0;
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "getMDDByOId" )
+
+ return returnValue;
+}
+
+
+
+unsigned short
+ServerComm::getNextTile( unsigned long callingClientId,
+ RPCMarray** rpcMarray )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "getNextTile" )
+
+ RMInit::logOut << "Request: getNextTile..." << std::flush;
+
+ unsigned long transOffset = 0;
+ unsigned long transSize = 0;
+ unsigned short statusValue = 0;
+ unsigned short returnValue = 0;
+
+ // initialize the result parameter for failure cases
+ *rpcMarray = 0;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+ if( context->transTiles && context->tileIter )
+ {
+ Tile* resultTile = **(context->tileIter);
+ r_Minterval mddDomain = resultTile->getDomain();
+ void* useTransData;
+ unsigned long totalSize;
+
+ // allocate memory for the output parameter rpcMarray
+ *rpcMarray = (RPCMarray*)mymalloc( sizeof( RPCMarray ) );
+
+ if ( context->bytesToTransfer == 0 )
+ {
+ // free old data
+ if (context->encodedData != NULL)
+ {
+ free(context->encodedData);
+ context->encodedData = NULL;
+ context->encodedSize = 0;
+ }
+
+ // Transfer compression...
+ // we have to repack the data if ((tf != cf) && exact) or ((tf != Array) && (cf == Array))
+ // where tf = transferFormat, cf = currentFormat.
+ r_Data_Format tf = context->transferFormat;
+ r_Data_Format cf = resultTile->getDataFormat();
+ RMDBGMIDDLE( 4, RMDebug::module_servercomm, "ServerComm", "getNextTile CURRENT " << cf << ", TRANSFER " << tf << ", EXACT " << (bool)context->exactFormat);
+ if (((tf != cf) && (context->exactFormat != 0)) || ((tf != r_Array) && (cf == r_Array)))
+ {
+ RMDBGMIDDLE(4, RMDebug::module_servercomm, "ServerComm", "repack data from " << cf << " to " << tf)
+
+ //the cast from const char* to char* is okay because the owner flag is set correctly
+ char *encData = (char*)resultTile->getCompressedContents();
+ unsigned long encSize = resultTile->getCompressedSize();
+ //the data format could have changed during compression
+ cf = resultTile->getDataFormat();
+ // this method actually repacks everything as needed
+ if(ensureTileFormat(cf, tf, mddDomain, resultTile->getType(),
+ encData, encSize, 1, 0, context->transferFormatParams) != ENSURE_TILE_FORMAT_OK)
+ {
+ //FIXME returnValue
+ returnValue = 4;
+
+ RMInit::logOut << "Error: tile format mismatch while fetching next tile." << endl;
+ (*rpcMarray)->domain = mddDomain.get_string_representation();
+
+ // allocate memory for the output parameter data and assign its fields
+ (*rpcMarray)->data.confarray_len = 0;
+ (*rpcMarray)->data.confarray_val = NULL;
+ // 3. store cell type length
+ (*rpcMarray)->cellTypeLength = 0;
+
+ context->release();
+ return returnValue;
+ }
+ // if the new format is bigger than the old one and we're allowed to, revert to the old one
+ if ((encSize >= resultTile->getCompressedSize()) && (context->exactFormat == 0))
+ {
+ free( encData );
+ }
+ else
+ {
+ context->encodedData = encData;
+ context->encodedSize = encSize;
+ }
+ }
+ }
+
+ // note: transfer compression affects the current format, not the storage format.
+ if ( context->encodedData == NULL )
+ {
+ totalSize = resultTile->getCompressedSize();
+ //this is bad because useTransData is char* although it is not modified
+ useTransData = (char*)resultTile->getCompressedContents();
+ (*rpcMarray)->currentFormat = resultTile->getDataFormat();
+ RMDBGMIDDLE(4, RMDebug::module_servercomm, "ServerComm", "using tile format " << (r_Data_Format)(*rpcMarray)->currentFormat)
+ }
+ else
+ {
+ totalSize = context->encodedSize;
+ useTransData = context->encodedData;
+ (*rpcMarray)->currentFormat = context->transferFormat;
+ //FILE *fp = fopen("trans_data.raw", "wb"); fwrite(useTransData, 1, totalSize, fp); fclose(fp);
+ RMDBGMIDDLE(4, RMDebug::module_servercomm, "ServerComm", "using transfer format " << (r_Data_Format)(*rpcMarray)->currentFormat)
+ }
+ // Preserve storage format
+ (*rpcMarray)->storageFormat = resultTile->getDataFormat();
+ RMDBGMIDDLE(4, RMDebug::module_servercomm, "ServerComm", "rpc storage " << (r_Data_Format)(*rpcMarray)->storageFormat)
+ RMDBGMIDDLE(4, RMDebug::module_servercomm, "ServerComm", "rpc current " << (r_Data_Format)(*rpcMarray)->currentFormat)
+
+ transSize = totalSize;
+
+ if( totalSize > maxTransferBufferSize )
+ {
+ // if there is the rest of a tile to transfer, do it!
+ if( context->bytesToTransfer )
+ {
+ TALK( " resuming block transfer..." );
+ transOffset = totalSize - context->bytesToTransfer;
+ if( context->bytesToTransfer > maxTransferBufferSize )
+ {
+ transSize = maxTransferBufferSize;
+ statusValue = 1;
+ }
+ else
+ {
+ transSize = context->bytesToTransfer;
+ statusValue = 2;
+ }
+
+ context->bytesToTransfer -= transSize;
+ }
+ else // transfer first block of too large tile
+ {
+ TALK( " has to be split..." );
+ transSize = maxTransferBufferSize;
+ context->bytesToTransfer = totalSize - transSize;
+ statusValue = 1;
+ }
+ }
+ else // resultTile->getSize() <= maxTransferBufferSize
+ statusValue = 3;
+
+ context->totalTransferedSize += transSize;
+
+ // 1. convert domain
+ (*rpcMarray)->domain = mddDomain.get_string_representation();
+
+ // 2. copy data pointers
+ TALK( " domain " << mddDomain << ", " << transSize << " bytes" );
+
+ // allocate memory for the output parameter data and assign its fields
+ (*rpcMarray)->data.confarray_len = (unsigned int)transSize;
+ (*rpcMarray)->data.confarray_val = ((char*)useTransData) + transOffset;
+
+ // 3. store cell type length
+ (*rpcMarray)->cellTypeLength = resultTile->getType()->getSize();
+
+ // increment iterator only if tile is transferred completely
+ if( statusValue > 1 )
+ {
+ context->totalRawSize += resultTile->getSize();
+ (*context->tileIter)++;
+ }
+
+ // delete tile vector and increment transfer collection iterator if tile iterator is exhausted
+ if( (*context->tileIter) == context->transTiles->end() )
+ {
+
+ // delete tile vector transTiles (tiles are deleted when the object is deleted)
+ if( context->transTiles )
+ {
+ delete context->transTiles;
+ context->transTiles = 0;
+ }
+
+ // delete tile iterator
+ if( context->tileIter )
+ {
+ delete context->tileIter;
+ context->tileIter = 0;
+ }
+
+ if( context->transferDataIter )
+ {
+ (*(context->transferDataIter))++;
+
+ if( *(context->transferDataIter) != context->transferData->end() )
+ {
+ returnValue = 1;
+ TALK( " some MDDs left..." );
+ RMInit::logOut << MSG_OK << ", some MDD(s) left." << endl;
+ }
+ else
+ {
+ // no elements left -> delete collection and iterator
+
+ // Memory of last tile is still needed for the last byte transfer,
+ // therefore, do not release memory now, but with any next RPC call.
+ // context->releaseTransferStructures();
+
+ returnValue = 0;
+ RMInit::logOut << MSG_OK << ", all MDDs fetched." << endl;
+ }
+ }
+ else
+ {
+ returnValue = 0;
+ RMInit::logOut << MSG_OK << ", MDD transfer complete." << endl;
+ }
+
+ if ((context->totalTransferedSize != context->totalRawSize) && (context->totalRawSize != 0))
+ {
+ TALK( "(compressed using " << context->transferFormat << " to " << ((r_Double)(100 * context->totalTransferedSize)) / context->totalRawSize << "%) " );
+ }
+ }
+ else
+ {
+ if( statusValue == 1 ) // at least one block in actual tile is left
+ {
+ RMInit::logOut << MSG_OK << ", some block(s) left." << endl;
+ returnValue = 3;
+ }
+ else // tiles left in actual MDD
+ {
+ RMInit::logOut << MSG_OK << ", some tile(s) left." << endl;
+ returnValue = 2;
+ }
+ }
+ }
+ else // no actual transfer collection or nothing left in the collection
+ {
+ returnValue = 4;
+ RMInit::logOut << "Error: no transfer collection or nothing left in collection." << endl;
+ }
+
+ context->release();
+ }
+ else
+ { // client context not found
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 4;
+ }
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "getNextTile" )
+ return returnValue;
+}
+
+
+unsigned short
+ServerComm::endTransfer( unsigned long client )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "endTransfer" )
+ unsigned short returnValue = 0;
+
+ RMInit::logOut << "Client " << client << " called: endTransfer..." << std::flush;
+
+ ClientTblElt* context = getClientContext( client );
+
+ if( context )
+ {
+#ifdef RMANBENCHMARK
+ Tile::relTimer.stop();
+ Tile::opTimer.stop();
+ ZLibCompression::decompTimer.stop();
+ ZLibCompression::compTimer.stop();
+ if( context->evaluationTimer ) delete context->evaluationTimer;
+ context->evaluationTimer = 0;
+ if( context->transferTimer ) delete context->transferTimer;
+ context->transferTimer = 0;
+ RMTimer* releaseTimer = 0;
+
+ if( RManBenchmark > 0 )
+ releaseTimer = new RMTimer("ServerComm", "release time ");
+#endif
+ // release transfer collection/iterator
+ context->releaseTransferStructures();
+
+#ifdef RMANBENCHMARK
+ if( releaseTimer ) delete releaseTimer;
+#endif
+
+ context->release();
+
+ RMInit::logOut << MSG_OK << std::endl;
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 1;
+ }
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "endTransfer" )
+ return returnValue;
+}
+
+
+
+/*************************************************************************
+ * Method name...: aliveSignal( unsigned long client )
+ ************************************************************************/
+unsigned short
+ServerComm::aliveSignal( unsigned long client )
+{
+ unsigned short returnValue = 0;
+
+ RMInit::logOut << "Client " << client << " called: endTransfer..." << std::flush;
+
+ ClientTblElt* context = getClientContext( client );
+
+ if( context )
+ {
+ // set the time of the client's last action to now
+ context->lastActionTime = time( NULL );
+
+ returnValue = 1;
+
+ context->release();
+
+ RMInit::logOut << MSG_OK << std::endl;
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ }
+
+ return returnValue;
+}
+
+
+
+unsigned short
+ServerComm::getNewOId( unsigned long callingClientId,
+ unsigned short objType,
+ r_OId& oid )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "getNewOId" )
+ unsigned short returnValue = 0;
+
+ RMInit::logOut << "Request: getNewOId of type "
+ << (objType==1?"MDD":"collection") << "..." << std::flush;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+ EOId eOId;
+
+ if( objType == 1 )
+ EOId::allocateEOId( eOId, OId::MDDOID );
+ else // objType == 2
+ EOId::allocateEOId( eOId, OId::MDDCOLLOID );
+
+ RMDBGMIDDLE( 4, RMDebug::module_servercomm, "ServerComm", "allocated " << eOId)
+ oid = r_OId( eOId.getSystemName(), eOId.getBaseName(), eOId.getOId() );
+
+ context->release();
+
+ RMInit::logOut << MSG_OK << std::endl;
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 1;
+ }
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "getNewOId " << returnValue)
+ return returnValue;
+}
+
+
+
+unsigned short
+ServerComm::getObjectType( unsigned long callingClientId,
+ r_OId& oid,
+ unsigned short &objType )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "getObjectType" )
+ unsigned short returnValue = 0;
+
+ RMInit::logOut << "Request: getObjectType by oid " << oid << "..." << std::flush;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if( context != 0 )
+ {
+ OId oidIf( oid.get_local_oid() );
+
+ objType = oidIf.getType();
+
+ if( objType == OId::INVALID )
+ {
+ // oid not found
+ RMInit::logOut << "Error: no type for this oid." << std::endl;
+ returnValue = 2;
+ }
+ else
+ {
+ RMInit::logOut << "type is " << (objType==1?"MDD":"collection") << "..." << MSG_OK << endl;
+ }
+
+ context->release();
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << endl;
+ returnValue = 1;
+ }
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "getObjectType" )
+ return returnValue;
+}
+
+
+
+unsigned short
+ServerComm::getTypeStructure( unsigned long callingClientId,
+ const char* typeName,
+ unsigned short typeType,
+ char* &typeStructure )
+{
+ RMDBGENTER( 4, RMDebug::module_servercomm, "ServerComm", "getTypeStructure" )
+ unsigned short returnValue = 0;
+
+ RMInit::logOut << "Request: getTypeStructure of type '" << typeName << "'..." << std::flush;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+ if (context == 0)
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ returnValue = 1;
+ }
+
+ if (returnValue==0 && !transactionActive)
+ {
+ RMInit::logOut << "Error: no transaction open." << endl;
+ returnValue = 1;
+ }
+
+ if (returnValue==0)
+ {
+ if( typeType == 1 )
+ {
+ // get collection type
+ CollectionType* collType = (CollectionType*)TypeFactory::mapSetType( (char*)typeName );
+
+ if( collType )
+ typeStructure = collType->getTypeStructure(); // no copy
+ else
+ returnValue = 2;
+ }
+ else if( typeType == 2 )
+ {
+ // get MDD type
+ const MDDType* mddType = TypeFactory::mapMDDType( typeName );
+
+ if( mddType )
+ typeStructure = mddType->getTypeStructure(); // no copy
+ else
+ returnValue = 2;
+ }
+ else // base type not implemented
+ {
+ returnValue = 2;
+ }
+
+ if( returnValue == 2 )
+ RMInit::logOut << "Error: unknown type." << endl;
+ else
+ RMInit::logOut << MSG_OK << endl;
+
+ context->release();
+ }
+
+ RMDBGEXIT( 4, RMDebug::module_servercomm, "ServerComm", "getTypeStructure" )
+ return returnValue;
+}
+
+
+unsigned short
+ServerComm::setTransferMode( unsigned long callingClientId,
+ unsigned short format,
+ const char* formatParams )
+{
+ RMDBGENTER(4, RMDebug::module_servercomm, "ServerComm", "setTransferMode(" << callingClientId << ", " << format << ", " << formatParams)
+
+ RMInit::logOut << "Request: setTransferMode..." << std::flush;
+
+ unsigned short retval = 1;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if (context != 0)
+ {
+ r_Data_Format fmt = (r_Data_Format)format;
+ // query compression module whether this is a legal format for transfer compression
+ if (r_Tile_Compression::check_data_format(fmt) == r_Tile_Compression::INVALID)
+ {
+ RMInit::logOut << "Error: invalid transfer compression format: " << format << std::endl;
+ retval = 2;
+ }
+ else
+ {
+ if (context->transferFormatParams != NULL)
+ {
+ delete [] context->transferFormatParams;
+ context->transferFormatParams = NULL;
+ // revert the transfer format strictness
+ context->exactFormat = 0;
+ }
+ if (formatParams != NULL)
+ {
+ context->transferFormatParams = new char[strlen(formatParams)+1];
+ strcpy(context->transferFormatParams, formatParams);
+ // extract any occurrences of ``exactformat''
+ context->clientParams->process(context->transferFormatParams);
+ }
+ context->transferFormat = fmt;
+
+ RMInit::logOut << MSG_OK << std::endl;
+ retval = 0;
+ }
+ context->release();
+ RMDBGMIDDLE(1, RMDebug::module_servercomm, "ServerComm", "setTransferMode(...) current transfer format :" << context->transferFormat)
+ RMDBGMIDDLE(1, RMDebug::module_servercomm, "ServerComm", "setTransferMode(...)current transfer params :" << context->transferFormatParams );
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ retval = 1;
+ }
+
+ RMDBGEXIT(4, RMDebug::module_servercomm, "ServerComm", "setTransferMode " << retval)
+ return retval;
+}
+
+unsigned short
+ServerComm::setStorageMode( unsigned long callingClientId,
+ unsigned short format,
+ const char* formatParams )
+{
+ RMDBGENTER(4, RMDebug::module_servercomm, "ServerComm", "setStorageMode(" << callingClientId << ", " << format << ", " << formatParams)
+
+ RMInit::logOut << "Request: setStorageMode..." << std::flush;
+
+ unsigned short retval = 1;
+
+ ClientTblElt* context = getClientContext( callingClientId );
+
+ if (context != 0)
+ {
+ r_Data_Format fmt = (r_Data_Format)format;
+ if (r_Tile_Compression::check_data_format(fmt) == r_Tile_Compression::INVALID)
+ {
+ RMInit::logOut << "Error: invalid storage compression format: " << format << std::endl;
+ retval = 2;
+ }
+ else
+ {
+ if (context->storageFormatParams != NULL)
+ {
+ delete [] context->storageFormatParams;
+ context->storageFormatParams = NULL;
+ }
+ if (formatParams != NULL)
+ {
+ context->storageFormatParams = new char[strlen(formatParams)+1];
+ strcpy(context->storageFormatParams, formatParams);
+ }
+ context->storageFormat = fmt;
+
+ RMInit::logOut << MSG_OK << std::endl;
+ retval = 0;
+ }
+ context->release();
+ RMDBGMIDDLE(1, RMDebug::module_servercomm, "ServerComm", "setStorageMode(...) current storage format :" << context->storageFormat)
+ RMDBGMIDDLE(1, RMDebug::module_servercomm, "ServerComm", "setStorageMode(...) current storage params :" << context->storageFormatParams)
+ }
+ else
+ {
+ RMInit::logOut << "Error: client not registered." << std::endl;
+ retval = 1;
+ }
+
+ RMDBGEXIT(4, RMDebug::module_servercomm, "ServerComm", "setStorageMode " << retval)
+ return retval;
+}
+
+int
+ServerComm::ensureTileFormat( r_Data_Format &hasFmt,
+ r_Data_Format needFmt,
+ const r_Minterval &dom,
+ const BaseType *type,
+ char *&data,
+ unsigned long &size,
+ int repack,
+ int owner,
+ const char *params )
+{
+ RMDBGENTER(2, RMDebug::module_servercomm, "ServerComm", "ensureTileFormat(" << hasFmt << ", " << needFmt << ", " << dom << ", " << type->getName() << ", data, " << size << ", repack " << repack << ", owner " << owner << ", params " << params << ")")
+ int status = ENSURE_TILE_FORMAT_OK;
+
+ RMDBGMIDDLE(2, RMDebug::module_servercomm, "ServerComm", "ensureTileFormat(...) #Size 1=" << size);
+
+ // convert to storage format (this should go into a separate function)
+ if (hasFmt != needFmt)
+ {
+ r_Tile_Compression *engine = NULL;
+ r_ULong newSize=0;
+ char *newData=NULL;
+
+ char *tpstruct = type->getTypeStructure();
+ r_Base_Type *compType = (r_Base_Type*)(r_Type::get_any_type(tpstruct));
+
+ // decompress
+ try
+ {
+ engine = r_Tile_Compression::create(hasFmt, dom, compType);
+ // decompression doesn't change the size variable!
+ newData = (char*)(engine->decompress(data, size, params));
+ delete engine;
+
+ if (newData == NULL)
+ {
+ RMInit::logOut << "Error: decompression failed for format '" << hasFmt << "'." << endl;
+ size = dom.cell_count() * compType->size();
+ newData = (char*)mymalloc(size * sizeof(char));
+ memset(newData, 0, size);
+ // FIXME: make it an error!! --PB 2005-aug-25
+ RMInit::logOut << "Error fixed by returning empty data of length " << size << " bytes." << std::endl;
+ }
+ // do I actually own the data?
+ if (owner != 0)
+ free(data);
+ data = newData;
+ size = dom.cell_count() * (compType->size());
+ hasFmt = r_Array;
+ }
+ catch (r_Error &err)
+ {
+ RMInit::logOut << "Error: cannot decompress format '" << hasFmt << "' (" << err.get_errorno() << "): " << err.what() << endl;
+ RMDBGEXIT(2, RMDebug::module_servercomm, "ServerComm", "ensureTileFormat(...) " << ENSURE_TILE_FORMAT_BAD)
+ status = ENSURE_TILE_FORMAT_BAD;
+ }
+
+ RMDBGMIDDLE(2, RMDebug::module_servercomm, "ServerComm", "ensureTileFormat(...) #Size 2=" << size);
+
+ if ((status == ENSURE_TILE_FORMAT_OK) && (repack != 0) && (needFmt != r_Array))
+ {
+ try
+ {
+ newSize = size;
+ engine = r_Tile_Compression::create(needFmt, dom, compType);
+ newData = (char*)(engine->compress(data, newSize, params));
+ delete engine;
+
+ if (newData == NULL)
+ {
+ RMInit::logOut << "Error: recompression failed for format '" << needFmt << "'." << endl;
+ RMDBGEXIT(2, RMDebug::module_servercomm, "ServerComm", "ensureTileFormat(...) " << ENSURE_TILE_FORMAT_BAD)
+ status = ENSURE_TILE_FORMAT_BAD;
+ }
+ else
+ {
+ free(data);
+ data = newData; size = newSize;
+ hasFmt = needFmt;
+ RMDBGMIDDLE(2, RMDebug::module_servercomm, "ServerComm", "recompressed to " << hasFmt << " size " << size)
+ }
+ }
+ catch (r_Error &err)
+ {
+ RMInit::logOut << "Error: unsupported tile format '" << needFmt << "' (" << err.get_errorno() << "): " << err.what() << endl;
+ RMDBGEXIT(2, RMDebug::module_servercomm, "ServerComm", "ensureTileFormat " << ENSURE_TILE_FORMAT_BAD)
+ status = ENSURE_TILE_FORMAT_BAD;
+ }
+ }
+ else
+ {
+ RMDBGMIDDLE(2, RMDebug::module_servercomm, "ServerComm", "ensureTileFormat(...) do not recompress")
+ }
+ delete compType;
+ free(tpstruct);
+ }
+
+ RMDBGMIDDLE(2, RMDebug::module_servercomm, "ServerComm", "ensureTileFormat(...) #Size 3=" << size);
+ RMDBGEXIT(2, RMDebug::module_servercomm, "ServerComm", "ensureTileFormat(...) " << ENSURE_TILE_FORMAT_OK)
+ return status;
+}
diff --git a/servercomm/test/Makefile b/servercomm/test/Makefile
new file mode 100644
index 0000000..bf035b4
--- /dev/null
+++ b/servercomm/test/Makefile
@@ -0,0 +1,117 @@
+# -*-Makefile-*-
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>. # Top Level makefile. This points to the various modules that have to be build
+# and/or deployed
+#
+# MAKEFILE FOR:
+# test programs of module servercomm
+######################### Definitions ############################
+
+# standard include with general options
+include $(RMANBASE)/Makefile.inc
+
+# all test programs
+SRCCXX = test_servercomm.cc test_dbcontent.cc test_oid.cc
+OBJS = ${SRCCXX:%.cc=%.o}
+ALLTESTS = ${SRCCXX:%.cc=%}
+
+# some additional flags for compiling and linking
+
+CXXFLAGS += -I$(RMANBASE)/servercomm
+LDFLAGS := -I$(RMANBASE)/servercomm $(LDFLAGS)
+
+# add communication flags
+CXXFLAGS += $(COMMCXXFLAGS)
+LDFLAGS += $(COMMLDFLAGS)
+
+# add compile and link options for STL
+CXXFLAGS += $(STLCXXFLAGS)
+LDFLAGS += $(STLLDFLAGS)
+
+########################### Targets ##############################
+
+# test target for servercomm
+.PHONY : servercomm
+servercomm: adminif raslib test_module test_servercomm
+
+# test target for dbcontent
+.PHONY : dbcontent
+dbcontent: adminif raslib test_module test_dbcontent
+
+.PHONY : adminif
+adminif:
+ cd $(RMANBASE)/reladminif; $(MAKE)
+
+.PHONY : raslib
+raslib:
+ cd $(RMANBASE)/raslib; $(MAKE)
+
+.PHONY : qlparser
+qlparser:
+ cd $(RMANBASE)/qlparser; $(MAKE)
+
+.PHONY : test_module
+test_module:
+ cd $(RMANBASE)/servercomm; $(MAKE)
+
+test_servercomm: test_servercomm.o \
+ $(QLPARSER) \
+ $(SERVERCOMM) \
+ $(CACHETAMGR) \
+ $(MDDIF) \
+ $(CATALOGIF) \
+ $(INDEXIF) \
+ $(INDEXMGR) \
+ $(BLOBIF) \
+ $(ADMINIF) \
+ $(PREPROCESSOR) \
+ $(STORAGEMGR) \
+ $(TILEMGR) \
+ $(RASLIB) \
+ $(RELINDEX) \
+ $(INDEXIF)
+ $(CXX) $(LDFLAGS) -o $@ $^ $(QLPARSER) $(INDEXMGR) $(CACHETAMGR) $(RELINDEX) $(RELSTORAGEIF) $(RELADMINIF) $(STORAGEMGR) $(CONVERSION) $(INDEXIF) $(RELCATALOGIF) /usr/local/pgsql/lib/libpq.a /usr/local/pgsql/lib/libecpg.a -lssl -lcrypt /usr/local/pgsql/lib/libpgtypes.a -lm -ljpeg -ltiff -lpng -lmfhdf -ldf -lz -ldl -lcrypto
+
+test_dbcontent: test_dbcontent.o \
+ $(QLPARSER) \
+ $(SERVERCOMM) \
+ $(RASLIB) \
+ $(CACHETAMGR) \
+ $(MDDIF) \
+ $(CATALOGIF) \
+ $(INDEXIF) \
+ $(INDEXMGR) \
+ $(BLOBIF) \
+ $(ADMINIF)
+ $(CXX) $(LDFLAGS) $(O2LDFLAGS) -o $@ $^ $(QLPARSER) $(INDEXMGR) $(CACHETAMGR) -lm
+
+test_oid: test_oid.o $(RASLIB) $(CACHETAMGR)\
+ $(MDDIF) $(CATALOGIF) $(INDEXIF) $(INDEXMGR) $(BLOBIF) $(ADMINIF)
+ $(PURIFY) $(CXX) $(O2LDFLAGS) $(LDFLAGS) -o $@ $^ \
+ $(RASLIB) -lm -L$(SUPPORT_BASE)/lib -lz
+
+
+# general rules
+include $(RMANBASE)/Makefile.rel
+
+# automatically created dependencies
+include Makefile.dep
diff --git a/servercomm/test/template_inst.hh b/servercomm/test/template_inst.hh
new file mode 100644
index 0000000..569c0bf
--- /dev/null
+++ b/servercomm/test/template_inst.hh
@@ -0,0 +1,138 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+//for rb_tree, select1st
+#include <function.h>
+#include <tree.h>
+#include <vector>
+#include <utility>
+#include <memory>
+
+#if(__GNUC__==2 &&__GNUC_MINOR__==95)
+using std::rb_tree;
+using std::select1st;
+#else
+using __gnu_cxx::rb_tree;
+using __gnu_cxx::select1st;
+#endif
+
+using std::vector;
+using std::pair;
+
+// commented by Constantin Jucovschi (gcc 3.4+ no longer supports __default_alloc_template)
+//using std::__default_alloc_template;
+using std::fill_n;
+
+#include "qlparser/symtab.hh"
+
+#include "raslib/attribute.hh"
+#include "raslib/itertype.hh"
+#include "raslib/dlist.hh"
+
+#include "tile.hh"
+
+#include "indexmgr/keyobject.hh"
+
+#include "reladminif/dbref.hh"
+#include "reladminif/dbobjectiditerator.hh"
+
+#include "relblobif/blobtile.hh"
+#include "relblobif/dbtile.hh"
+#include "relblobif/inlinetile.hh"
+
+#include "relcatalogif/typeiterator.hh"
+#include "relcatalogif/settype.hh"
+#include "relcatalogif/structtype.hh"
+#include "relcatalogif/mddtype.hh"
+#include "relcatalogif/inlineminterval.hh"
+#include "relcatalogif/dbminterval.hh"
+
+#include "relindexif/dbtcindex.hh"
+#include "relindexif/hierindex.hh"
+#include "relindexif/dbrcindexds.hh"
+
+#include "relmddif/dbmddobj.hh"
+#include "relmddif/dbmddset.hh"
+
+#include "relstorageif/dbudfds.hh"
+#include "relstorageif/dbudfpackageds.hh"
+#include "relstorageif/dbstoragelayout.hh"
+
+template class SymbolTable<int>;
+
+template class r_IterType<r_Attribute>;
+
+template class DBRef<DBHierIndex>;
+template class DBRef<DBRCIndexDS>;
+template class DBRef<DBTCIndex>;
+template class DBRef<BLOBTile>;
+template class DBRef<DBTile>;
+template class DBRef<InlineTile>;
+template class DBRef<DBMDDSet>;
+template class DBRef<DBMinterval>;
+template class DBRef<DBStorageLayout>;
+template class DBRef<DBUDFDS>;
+template class DBRef<DBUDFPackageDS>;
+//template class DBRef<DBMDDObj>;
+// template bool operator< (const DBRef<DBMDDObj>&, const DBRef<DBMDDObj>&);
+
+//template TypeIterator<StructType>;
+//template TypeIterator<SetType>;
+template class TypeIterator<MDDType>;
+template class DBRef<DBMDDObj>;
+template class DBRef<DBObject>;
+
+template class DBObjectIdIterator<DBMDDObj>;
+template class DBObjectIterator<DBMDDObj>;
+template class DBObjectIterator<DBMDDSet>;
+template class DBObjectIterator<StructType>;
+template class DBObjectIterator<SetType>;
+template class DBRef<StructType>;
+template class DBRef<SetType>;
+template class DBRef<MDDType>;
+
+template std::ostream& operator<< (const vector<KeyObject>&, std::ostream&);
+template std::ostream& operator<< (std::ostream &, const vector<KeyObject>&);
+template std::ostream& operator << (std::ostream& os, const std::vector<double>& list);
+template std::ostream& operator << (std::ostream& os, const std::vector<r_Minterval>& list);
+
+template class rb_tree<OId, pair<OId const, DBMDDObj *>, select1st<pair<OId const, DBMDDObj *> >, less<OId> >;
+template class rb_tree<OId, pair<OId const, DBMinterval *>, select1st<pair<OId const, DBMinterval *> >, less<OId> >;
+template class rb_tree<OId, pair<OId const, DBRef<DBMDDObj> >, select1st<pair<OId const, DBRef<DBMDDObj> > >, less<OId> >;
+template class rb_tree<OId, pair<OId const, DBMDDSet *>, select1st<pair<OId const, DBMDDSet *> >, less<OId> >;
+template class rb_tree<OId, pair<OId const, MDDType *>, select1st<pair<OId const, MDDType *> >, less<OId> >;
+template class rb_tree<OId, pair<OId const, SetType *>, select1st<pair<OId const, SetType *> >, less<OId> >;
+template class rb_tree<OId, pair<OId const, StructType *>, select1st<pair<OId const, StructType *> >, less<OId> >;
+template class rb_tree<long, pair<long const, BLOBTile *>, select1st<pair<long const, BLOBTile *> >, less<long> >;
+template class rb_tree<long, pair<long const, InlineTile *>, select1st<pair<long const, InlineTile *> >, less<long> >;
+template class vector<BaseType const * >;
+template class vector<OId >;
+template class vector<Tile * >;
+template class vector<Type * >;
+template class vector<char * >;
+template class vector<char >;
+template class vector<r_Data_Format >;
+template class vector<unsigned int >;
+
+template class Tile ** fill_n<Tile **, unsigned int, Tile *>(Tile **, unsigned int, Tile * const &);
+
diff --git a/servercomm/test/test_dbcontent.cc b/servercomm/test/test_dbcontent.cc
new file mode 100644
index 0000000..a0bd6da
--- /dev/null
+++ b/servercomm/test/test_dbcontent.cc
@@ -0,0 +1,161 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_dbcontent.cc
+ *
+ * MODULE: test
+ *
+ * PURPOSE:
+ * Reads the contents of the specified collection and prints
+ * it on the screen.
+ *
+ * COMMENTS:
+ * none
+ *
+*/
+
+#include <stdlib.h>
+#include <iostream.h>
+
+#include "o2template_CC.hxx" // declaration of O2 ref and coll classes
+
+#include "ulongtype.hh"
+
+#include "cachetamgr/persmddcoll.hh"
+#include "cachetamgr/persmddobj.hh"
+#include "cachetamgr/perstile.hh"
+
+#include "cachetamgr/persmddcolliter.hh"
+
+#include "adminif.hh"
+#include "databaseif.hh"
+#include "transactionif.hh"
+
+#include <unistd.h>
+
+extern char* myExecArgv0 = "";
+
+static void testAccessing( const char* collName );
+
+/*************************************************************
+ * Function name.: int main( int argc, char** argv)
+ *
+ * Arguments.....:
+ * argc: number of arguments given to program
+ * argv: array of char* with arguments
+ * Return value..: exit status
+ * Description...: none
+ ************************************************************/
+
+void
+main( int ac, char** av)
+{
+ char baseName[255];
+ char collName[255];
+
+ if( ac > 1 )
+ strcpy( baseName, av[1] );
+ else
+ strcpy( baseName, "RasDaBase" );
+
+ if( ac > 2 )
+ strcpy( collName, av[2] );
+ else
+ strcpy( collName, "Images" );
+
+ pid_t cpid;
+ cout << "Parent process id is " << getpid() << endl;
+
+ cpid = fork();
+
+ if( !cpid )
+ {
+ cout << "Child process id is " << getpid() << endl;
+ // sleep(1);
+ }
+
+ // variables representing O2 database, ta and session
+ DatabaseIf database;
+ TransactionIf ta;
+
+ // don't forget to initialize before using AdminIf!
+ myExecArgv0 = av[0];
+ AdminIf* myAdmin = AdminIf::instance();
+
+ // connect to the database
+ cout << getpid() << " Connecting to database " << baseName << "..." << endl;
+ database.open( baseName );
+
+ // read coll and print contents
+ cout << getpid() << " Read collection and print contents..." << endl;
+ ta.begin();
+ testAccessing( collName );
+ ta.commit();
+
+ cout << getpid() << " closing db ... "; cout.flush();
+ database.close();
+ cout << getpid() << " OK" << endl;
+
+ cout << getpid() << " Ending O2 session..." << endl;
+ delete myAdmin;
+ cout << getpid() << " OK" << endl;
+
+ return;
+}
+
+
+
+/*************************************************************
+ * Function......: testAccessing()
+ *
+ * Arguments.....: none
+ * Return value..: none
+ * Description...: reads DirTilesIx's and shows contents
+ ************************************************************/
+
+static void testAccessing( const char* collName )
+{
+ PersMDDObj* accessedObj;
+
+ cout << getpid() << " ....testAccessing" << endl;
+ /*
+ PersMDDColl objsSet( collName );
+
+ // To test PersMDDColl::printStatus( )
+ objsSet.printStatus( );
+
+ // To test PersMDDObj::printStatus( ), MDDCollIter::createIterator( ) and
+ // MDDCollIter methods :
+ MDDCollIter* objsIt = objsSet.createIterator( );
+
+ for( int i = 1 ; objsIt->notDone( ); i++, objsIt->advance( ))
+ {
+ accessedObj = (PersMDDObj*) objsIt->getElement();
+ cout << " --"<<i<<". MDD object in set:" << endl;
+ accessedObj->printStatus();
+ }
+ delete objsIt;
+ */
+}
+
+
diff --git a/servercomm/test/test_oid.cc b/servercomm/test/test_oid.cc
new file mode 100644
index 0000000..280b499
--- /dev/null
+++ b/servercomm/test/test_oid.cc
@@ -0,0 +1,229 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_dbcontent.cc
+ *
+ * MODULE: test
+ *
+ * PURPOSE:
+ * Reads the contents of the specified collection and prints
+ * it on the screen.
+ *
+ * COMMENTS:
+ * none
+ *
+*/
+
+#include <stdlib.h>
+#include <iostream.h>
+
+#include "o2template_CC.hxx" // declaration of O2 ref and coll classes
+
+#include "ulongtype.hh"
+
+#include "cachetamgr/persmddcoll.hh"
+#include "cachetamgr/persmddobj.hh"
+#include "cachetamgr/perstile.hh"
+
+#include "cachetamgr/persmddcolliter.hh"
+
+#include "adminif.hh"
+#include "databaseif.hh"
+#include "transactionif.hh"
+
+#include <unistd.h>
+
+RMINITGLOBALS('C')
+
+extern char* myExecArgv0 = "";
+
+static void
+insertObj( char* dbName, OId o, char* cn )
+{
+ MDDBaseType* mddType = (MDDBaseType*)TypeFactory::mapMDDType( "GreyImage" );
+ r_Minterval domain( "[0:9,0:9]" );
+
+ // cout << " " << o << "," << cn << " ... " << flush;
+
+ PersMDDObj* obj = new PersMDDObj( mddType, domain, dbName, o );
+ PersMDDColl objsSet( cn );
+ objsSet.insert( obj );
+ delete obj;
+}
+
+
+static void removeObj( char* dbName, char* collName, OId o )
+{
+ // open collection
+ PersMDDColl* coll = 0;
+
+ char answer = 'n';
+ cout << endl << "SCAN (y/n) ?" << flush;
+ cin >> answer;
+
+ if( answer == 'y' )
+ {
+ coll = new PersMDDColl( collName );
+ MDDCollIter* collIter = coll->createIterator();
+ MDDObj* mddObj;
+ for( collIter->reset(); collIter->notDone(); collIter->advance() )
+ {
+ mddObj = collIter->getElement();
+ /*
+ if( mddObj->isPersistent() )
+ {
+ EOId eOId;
+ ((PersMDDObj*)mddObj)->getEOId( &eOId );
+
+ cout << "MDD " << eOId.getOId() << flush;
+ }
+ */
+
+ }
+ /*
+ cout << endl << "PRINT OBJECT (y/n) ?" << flush;
+ cin >> answer;
+ if( answer == 'y' )
+ mddObj->printStatus( );
+ */
+ delete collIter;
+
+ coll->releaseAll();
+ delete coll;
+
+ cout << endl << "SCAN end" << endl;
+ }
+
+ coll = new PersMDDColl( collName );
+
+ if( coll )
+ {
+ cout <<"o == " << o << " dbName == " << dbName << endl;
+ coll->remove( o, dbName );
+
+ coll->releaseAll();
+ delete coll;
+ }
+}
+
+
+int checkArguments( int argc, char** argv, const char* searchText, int& optionValueIndex )
+{
+ int found = 0;
+ int i=1;
+
+ while( !found && i<argc )
+ found = !strcmp( searchText, argv[i++] );
+
+ if( found && i<argc && !strchr(argv[i],'-') )
+ optionValueIndex = i;
+ else
+ optionValueIndex = 0;
+
+ return found;
+}
+
+
+int
+main( int ac, char** av)
+{
+ int optionValueIndex;
+ char dbName[255];
+ char collName[255];
+
+ if( ac < 3 || checkArguments( ac, av, "-h", optionValueIndex ) )
+ {
+ cout << "Usage: test_oid base_name collection_name [options]" << endl << endl;
+ cout << "Options: -h ... this help" << endl;
+ cout << endl;
+ return 0;
+ }
+
+ strcpy( dbName, av[1] );
+ strcpy( collName, av[2] );
+
+ // variables representing O2 database, ta and session
+ DatabaseIf database;
+ TransactionIf ta;
+
+ // don't forget to initialize before using AdminIf!
+ myExecArgv0 = av[0];
+ AdminIf* myAdmin = AdminIf::instance();
+
+ // connect to the database
+ cout << "Connecting to database " << dbName << "..." << flush;
+ database.open( dbName );
+ cout << "OK" << endl;
+
+ // create collection with one object
+ cout << "Create collection ... " << flush;
+ ta.begin( &database );
+ cout << "getting type ... " << flush;
+ CollectionType* collType = (CollectionType*)TypeFactory::mapSetType( "GreySet" );
+ cout << "getting oid ... " << flush;
+ OId oidColl;
+ if( !OId::allocateMDDCollOId( &oidColl ) ) cout << oidColl << " ... " << flush;
+ PersMDDColl* pc = PersMDDColl::createRoot( collName, oidColl, collType, &database );
+ delete pc;
+ cout << "comitting ... " << flush;
+ ta.commit();
+ cout << "OK" << endl;
+
+ cout << "Insert object into collection ... " << flush;
+ ta.begin( &database );
+ cout << "getting oid ... " << flush;
+ OId oidMDD;
+ if( !OId::allocateMDDOId( &oidMDD ) ) cout << oidMDD << " ... " << flush;
+ cout << "inserting ..." << flush;
+ insertObj( dbName, oidMDD, collName );
+ cout << "comitting ... " << flush;
+ ta.commit();
+ cout << "OK" << endl;
+
+ cout << "Remove object again ... " << flush;
+ ta.begin( &database );
+ cout << "removing oid " << oidMDD << " ... " << flush;
+ removeObj( dbName, collName, oidMDD );
+ cout << "comitting ... " << flush;
+ ta.commit();
+ cout << "OK" << endl;
+
+ cout << "Delete collection ... " << flush;
+ ta.begin( &database );
+ cout << "destroying ... " << flush;
+ PersMDDColl::destroyRoot( collName, &database );
+ cout << "comitting ... " << flush;
+ ta.commit();
+ cout << "OK" << endl;
+
+ cout << "Closing db ... " << flush;
+ database.close();
+ cout << "OK" << endl;
+
+ cout << "Ending O2 session ... " << flush;
+ delete myAdmin;
+ cout << "OK" << endl;
+
+ return 0;
+}
+
diff --git a/servercomm/test/test_servercomm.cc b/servercomm/test/test_servercomm.cc
new file mode 100644
index 0000000..0be4610
--- /dev/null
+++ b/servercomm/test/test_servercomm.cc
@@ -0,0 +1,128 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: test_servercomm.cc
+ *
+ * MODULE: servercomm
+ *
+ * COMMENTS:
+ * None
+*/
+
+
+
+#include <iostream.h>
+
+#define __EXECUTABLE__
+#define EARLY_TEMPLATE
+#define DEBUG_MAIN
+#define DEBUG
+#include "debug.hh"
+#include "template_inst.hh"
+
+#include "raslib/rmdebug.hh"
+#include "qlparser/qtscalardata.hh"
+
+#include "servercomm/servercomm.hh"
+
+
+extern char* myExecArgv0 = "";
+extern int tiling = 1;
+extern unsigned long maxTransferBufferSize = 4000000;
+extern int globalOptimizationLevel = 4;
+extern char* dbSchema = 0;
+extern int noTimeOut = 0;
+char globalConnectId[255] = {0};
+bool udfEnabled = true;
+
+RMINITGLOBALS('C');
+
+#include <signal.h>
+
+
+int checkArguments( int argc, char** argv, const char* searchText, int& optionValueIndex )
+{
+ int found = 0;
+ int i=1;
+
+ while( !found && i<argc )
+ found = !strcmp( searchText, argv[i++] );
+
+ if( found && i<argc && !strchr(argv[i],'-') )
+ optionValueIndex = i;
+ else
+ optionValueIndex = 0;
+
+ return found;
+}
+
+
+int main( int argc, char** argv )
+{
+ strcpy(globalConnectId, "tcp:postgresql://localhost:5432/RASBASE");
+
+ ServerComm server(300, 120, 7013, "rasmgr", 7001, "N1");
+ ExecuteQueryRes result;
+
+ DatabaseIf database;
+ TransactionIf ta;
+ AdminIf* myAdmin = AdminIf::instance();
+ database.open( "RASSERVICE");
+ ta.begin( &database );
+
+ ServerComm::ClientTblElt *r = new ServerComm::ClientTblElt("testclient", 2);
+
+ server.addClientTblEntry (r);
+
+ accessControl.setServerName("NT1");
+ accessControl.crunchCapability("$I1$ER.$BRASBASE$T1:3:2008:23:39:24$NNT1$D983893f406445a922cba0301bc5a85ec$K");
+ server.openDB(2, "RASBASE", "costea");
+ SET_OUTPUT(TRUE);
+
+ char *buff = new char[1000];
+ unsigned int size;
+
+ QtScalarData* t;
+
+ try
+ {
+ server.executeQuery(2, "SELECT a from RAS_COLLECTIONNAMES as a", result );
+ vector<QtData*>::iterator i;
+ /* for (i=r->transferData->begin(); i!=r->transferData->end(); ++i) {
+ // t = (QtScalarData*)(*i);
+ // t->printStatus();
+ }*/
+ }
+ catch ( r_Error& errorObj )
+ {
+ cerr << errorObj.what() << endl;
+ return -1;
+ }
+ catch ( ... )
+ {
+ cerr << "Unknown exception caught in main." << endl;
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/storagemgr/Makefile.am b/storagemgr/Makefile.am
new file mode 100644
index 0000000..60e93bd
--- /dev/null
+++ b/storagemgr/Makefile.am
@@ -0,0 +1,35 @@
+# -*-Makefile-*- (for Emacs)
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+#
+# MAKEFILE FOR:
+# storagemgr
+#
+# COMMENTS:
+#
+##################################################################
+
+noinst_LIBRARIES = libstoragemgr.a
+libstoragemgr_a_SOURCES = sstoragelayout.cc sstoragelayout.hh
+
+CLEANFILES= core client.bm client.dbg client.log ir.out
+
diff --git a/storagemgr/sstoragelayout.cc b/storagemgr/sstoragelayout.cc
new file mode 100644
index 0000000..fc7a793
--- /dev/null
+++ b/storagemgr/sstoragelayout.cc
@@ -0,0 +1,260 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/****************************************************************************
+ *
+ *
+ *
+ * COMMENTS:
+ * none
+ *
+ ****************************************************************************/
+
+#include "sstoragelayout.hh"
+#include <stdlib.h>
+#include "raslib/rmdebug.hh"
+
+const r_Bytes StorageLayout::DBSPageSize = 4096;
+
+r_Bytes StorageLayout::DefaultMinimalTileSize = DBSPageSize;
+
+r_Bytes StorageLayout::DefaultPCTMax = 2 * DBSPageSize;
+
+r_Bytes StorageLayout::DefaultTileSize = 32 * DBSPageSize;
+
+unsigned int StorageLayout::DefaultIndexSize = 0;
+
+r_Index_Type StorageLayout::DefaultIndexType = r_RPlus_Tree_Index; // DirTilesIx; // AutoIx;
+
+r_Tiling_Scheme StorageLayout::DefaultTilingScheme = r_NoTiling;
+
+r_Minterval StorageLayout::DefaultTileConfiguration("[0:511,0:511]");
+
+r_Data_Format StorageLayout::DefaultDataFormat = r_Array;
+
+StorageLayout::StorageLayout(r_Index_Type ixType)
+ : myLayout(new DBStorageLayout())
+ {
+ setIndexType(ixType);
+ RMDBGONCE(4, RMDebug::module_storagemgr, "StorageLayout", "StorageLayout(" << ixType << ")")
+ }
+
+StorageLayout::StorageLayout()
+ : myLayout(new DBStorageLayout())
+ {
+ RMDBGONCE(4, RMDebug::module_storagemgr, "StorageLayout", "StorageLayout()")
+ }
+
+StorageLayout::StorageLayout(const DBStorageLayoutId& id)
+ : myLayout(id)
+ {
+ RMDBGONCE(4, RMDebug::module_storagemgr, "StorageLayout", "StorageLayout(" << id.getOId() << ")")
+ }
+
+/*
+const char*
+StorageLayout::getName() const
+ {
+ return stName;
+ }
+*/
+
+DBStorageLayoutId
+StorageLayout::getDBStorageLayout() const
+ {
+ return myLayout;
+ }
+
+r_Index_Type
+StorageLayout::getIndexType() const
+ {
+ return myLayout->getIndexType();
+ }
+
+
+r_Tiling_Scheme
+StorageLayout::getTilingScheme() const
+ {
+ return myLayout->getTilingScheme();
+ }
+
+r_Bytes
+StorageLayout::getTileSize() const
+ {
+ return myLayout->getTileSize();
+ }
+
+r_Bytes
+StorageLayout::getMinimalTileSize() const
+ {
+ return StorageLayout::DBSPageSize;
+ }
+
+r_Minterval
+StorageLayout::getTileConfiguration() const
+ {
+ return myLayout->getTileConfiguration();
+ }
+
+
+void
+StorageLayout::setIndexType(r_Index_Type it)
+ {
+ myLayout->setIndexType(it);
+ }
+
+void
+StorageLayout::setDataFormat(r_Data_Format cs)
+ {
+ myLayout->setDataFormat(cs);
+ }
+
+void
+StorageLayout::setTilingScheme(r_Tiling_Scheme ts)
+ {
+ myLayout->setTilingScheme(ts);
+ }
+
+void
+StorageLayout::setTileSize(r_Bytes newSize)
+ {
+ myLayout->setTileSize(newSize);
+ }
+
+void
+StorageLayout::setTileConfiguration(const r_Minterval& tc)
+ {
+ myLayout->setTileConfiguration(tc);
+ }
+
+r_Data_Format
+StorageLayout::getDataFormat(const r_Point& where) const
+ {
+ return myLayout->getDataFormat();
+ }
+
+std::vector< r_Minterval >
+StorageLayout::getLayout(const r_Minterval& tileDomain)
+ {
+ RMDBGENTER(5, RMDebug::module_storagemgr, "StorageLayout", "getLayout(" << tileDomain << ")");
+ std::vector< r_Minterval > retval;
+ if (myLayout->supportsTilingScheme())
+ switch (myLayout->getTilingScheme())
+ {
+ case r_RegularTiling:
+ if (myLayout->getTileConfiguration().dimension() == tileDomain.dimension())
+ retval = calcRegLayout(tileDomain);
+ else {
+ RMInit::logOut << "Regular Tiling chosen without Tiling Domain!\nPlease specify a Tiling Domain.\nNow using no tiling." << endl;
+ RMDBGMIDDLE(0, RMDebug::module_storagemgr, "StorageLayout", "getLayout(" << tileDomain << ") Regular Tiling without Tiling Domain");
+ retval.push_back(tileDomain);
+ }
+ break;
+ case r_InterestTiling:
+ case r_StatisticalTiling:
+ case r_AlignedTiling:
+ case r_DirectionalTiling:
+ case r_SizeTiling:
+ RMInit::logOut << "Tiling Scheme " << myLayout->getTilingScheme() << " " << (int)myLayout->getTilingScheme() << " not supported" << endl;
+ RMDBGMIDDLE(0, RMDebug::module_storagemgr, "StorageLayout", "getLayout(" << tileDomain << ") of " << myLayout->getOId() << " Tiling Scheme " << myLayout->getTilingScheme() << " " << (int)myLayout->getTilingScheme() << " not supported");
+ retval.push_back(tileDomain);
+ break;
+ default:
+ RMInit::logOut << "Unknown Tiling Scheme " << myLayout->getTilingScheme() << " " << (int)myLayout->getTilingScheme() << endl;
+ RMDBGMIDDLE(0, RMDebug::module_storagemgr, "StorageLayout", "getLayout(" << tileDomain << ") of " << myLayout->getOId() << " unknown Tiling Scheme " << myLayout->getTilingScheme() << " " << (int)myLayout->getTilingScheme());
+ case r_NoTiling:
+ retval.push_back(tileDomain);
+ break;
+ }
+ else
+ retval.push_back(tileDomain);
+ RMDBGEXIT(5, RMDebug::module_storagemgr, "StorageLayout", "getLayout(" << tileDomain << ")");
+ return retval;
+ }
+
+StorageLayout::~StorageLayout()
+ {
+ }
+
+std::vector< r_Minterval >
+StorageLayout::calcRegLayout(const r_Minterval& tileDomain) const
+ {
+ RMDBGENTER(4, RMDebug::module_storagemgr, "StorageLayout", "calcRegLayout(" << tileDomain << ") " << myLayout->getOId());
+ std::vector< r_Minterval > retval;
+ r_Minterval base = myLayout->getTileConfiguration();
+ RMDBGMIDDLE(5, RMDebug::module_storagemgr, "StorageLayout", "base: " << base)
+ r_Point borigin = base.get_origin();
+ r_Point bhigh = base.get_high();
+ r_Point bextent = base.get_extent();
+ r_Point torigin = tileDomain.get_origin();
+ r_Point thigh = tileDomain.get_high();
+ r_Point textent = tileDomain.get_extent();
+ r_Dimension dim = base.dimension();
+ r_Point transex(dim);
+ r_Point transexmax(dim);
+ r_Point transco(dim);
+ r_Point transcotemp(dim);
+ r_Minterval nextDomain(dim);
+ r_Dimension counter2 = 0;
+ r_Range extent = 0;
+ r_Range extent2 = 0;
+ r_Range origindiff = 0;
+ r_Range highdiff = 0;
+ for (counter2 = 0; counter2 < dim; counter2++)
+ {
+ origindiff = torigin[counter2] - borigin[counter2];
+ highdiff = thigh[counter2] - bhigh[counter2];
+ if (highdiff%bextent[counter2] > 0)
+ transexmax[counter2] = highdiff/bextent[counter2] + 1;
+ else
+ transexmax[counter2] = highdiff/bextent[counter2];
+ if (origindiff%bextent[counter2] < 0)
+ transex[counter2] = origindiff/bextent[counter2] - 1;
+ else
+ transex[counter2] = origindiff/bextent[counter2];
+ transco[counter2] = (transex[counter2]) * bextent[counter2];
+ }
+ for (extent = transex[dim - 1]; extent <= transexmax[dim - 1]; extent++)
+ {
+ transcotemp = transco;
+ transcotemp[dim - 1] = bextent[dim - 1] * extent;
+ nextDomain = base.create_translation(transcotemp);
+ retval.push_back(nextDomain);
+
+ for (counter2 = 0; counter2 < dim - 1; counter2++)
+ {
+ for (extent2 = transex[counter2] + 1; extent2 <= transexmax[counter2]; extent2++)
+ {
+ transcotemp[counter2] = bextent[counter2] * extent2;
+ nextDomain = base.create_translation(transcotemp);
+ retval.push_back(nextDomain);
+ }
+ }
+ }
+RMDBGIF(5, RMDebug::module_storagemgr, "StorageLayout", \
+ for (std::vector< r_Minterval >::iterator i = retval.begin(); i != retval.end(); i++) \
+ RMDBGMIDDLE(1, RMDebug::module_storagemgr, "StorageLayout", *i); \
+);
+ RMDBGEXIT(4, RMDebug::module_storagemgr, "StorageLayout", "calcRegLayout(" << tileDomain << ") " << myLayout->getOId());
+ return retval;
+ }
+
diff --git a/storagemgr/sstoragelayout.hh b/storagemgr/sstoragelayout.hh
new file mode 100644
index 0000000..4ac9e79
--- /dev/null
+++ b/storagemgr/sstoragelayout.hh
@@ -0,0 +1,236 @@
+#ifndef _STORAGELAYOUT_HH_
+#define _STORAGELAYOUT_HH_
+
+#include <vector>
+
+#include "raslib/minterval.hh"
+#include "relstorageif/dbstoragelayout.hh"
+
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+/****************************************************************************
+ *
+ *
+ *
+ * COMMENTS:
+ *
+ ****************************************************************************/
+
+//@ManMemo: Module: {\bf indexmgr}
+/*@Doc:
+ The {\bf StorageLayout} class is used to set the storage layout for persistent
+ MDD objects.
+*/
+
+class StorageLayout
+ {
+ public:
+
+ //@Man: Default values
+ //@{
+ /**
+ These values are initialized by rassserver.
+ */
+ static const r_Bytes DBSPageSize;
+ /*@Doc:
+ Database system page size. not used at the moment.
+ */
+
+ static r_Bytes DefaultMinimalTileSize;
+ /*@Doc:
+ For inlinetiles. this is the minimum size for a blobtile to be stored as a single blob.
+ if you use inlinetile index and a tile is smaller than this value the inlinetile will be stored inside the indexstructure.
+ this value should be smaller than a database system page size.
+ */
+
+ static r_Bytes DefaultPCTMax;
+ /*@Doc:
+ for inlinetiles. the maximum size of inlined inlinetiles. if they grow larger than this value they are outlined and stored as a single blob.
+ */
+
+ static r_Bytes DefaultTileSize;
+ /*@Doc:
+ for serverside retiling based on tile size. this is very bad for production systems but will allow for easier testing.
+ when an incomming tile from the client is larger than this number and tile size tiling is enabled the server will split the tile into smaller tiles so that each resulting tile has a smaller size than the incomming tile.
+ */
+
+ static unsigned int DefaultIndexSize;
+ /*@Doc:
+ this is usually computed by the index structures. for testing purposes and bugfixing it will allow the user to override the computed number of childs per hierarchical index node.
+ */
+
+ static r_Index_Type DefaultIndexType;
+ /*@Doc:
+ the default index to be used.
+ */
+
+ static r_Tiling_Scheme DefaultTilingScheme;
+ /*@Doc:
+ the default tiling to be used.
+ */
+ ///
+ static r_Minterval DefaultTileConfiguration;
+ /*@Doc:
+ the default tiling configuration to be used.
+ */
+ ///
+ static r_Data_Format DefaultDataFormat;
+ /*@Doc:
+ the default data format for tiles.
+ */
+ //@}
+
+ //@Man: Creation
+ //@{
+
+ StorageLayout();
+ /*@Doc:
+ Construct object with the default values.
+ */
+
+ StorageLayout(r_Index_Type ixtype);
+ /*@Doc:
+ this is needed for transdir
+ */
+
+ StorageLayout(const DBStorageLayoutId& myStorage);
+ /*@Doc:
+ Construct object with specific modes.
+ */
+
+ // StorageLayout(const char* storageLayoutName);
+ /*@Doc:
+ Construct object from an existing named one.
+ */
+ //@}
+
+ //@Man: Get operations
+ //@{
+
+ r_Index_Type getIndexType() const;
+ /*@Doc:
+ return the index type to be used.
+ this may be the default value if it was not defined previously.
+ */
+
+ r_Tiling_Scheme getTilingScheme() const;
+ /*@Doc:
+ return the tiling scheme to be used.
+ this may be the default value if it was not defined previously.
+ */
+
+ r_Bytes getTileSize() const;
+ /*@Doc:
+ return the tile size to be used for size based retiling (really bad!).
+ this may be the default value if it was not defined previously.
+ */
+
+ r_Bytes getMinimalTileSize() const;
+ /*@Doc:
+ Get minimum optimal tile size.
+ */
+
+ r_Minterval getTileConfiguration() const;
+ /*@Doc:
+ return the tile domain which defines origin and extent to be used.
+ this may be the default value if it was not defined previously.
+ */
+
+ //@}
+
+ //@Man: Set operations
+ //@{
+
+ void setIndexType(r_Index_Type it);
+ /*@Doc:
+ override previous values or default values for this option.
+ */
+
+ void setTilingScheme(r_Tiling_Scheme ts);
+ /*@Doc:
+ override previous values or default values for this option.
+ */
+
+ void setTileSize(r_Bytes ts);
+ /*@Doc:
+ override previous values or default values for this option.
+ */
+
+ void setTileConfiguration(const r_Minterval& tc);
+ /*@Doc:
+ override previous values or default values for this option.
+ */
+
+ void setDataFormat(r_Data_Format df);
+ /*@Doc:
+ override previous values or default values for this option.
+ */
+
+ //@}
+
+ //@Man: Operations
+ //@{
+
+ std::vector< r_Minterval > getLayout(const r_Minterval& tileDomain);
+ /*@Doc:
+ Partition a multidimensional array according to the storage layout.
+ */
+
+ r_Data_Format getDataFormat(const r_Point& where) const;
+ /*@Doc:
+ this is supplied to offer later implementations to specify the dataformat depending on the region of space.
+ */
+
+ //@}
+
+
+ //@Man: Destruction
+ //@{
+ ~StorageLayout();
+ //@}
+
+ DBStorageLayoutId getDBStorageLayout() const;
+ /*@Doc:
+ return the object which actually stores the option values.
+ */
+
+ protected:
+ std::vector< r_Minterval > calcRegLayout(const r_Minterval& layout) const;
+ /*@Doc:
+ calculate the domains which intersect the layout parameter. as point of origin the domain specified in myLayout is used.
+ */
+
+ //@Man: Actual Parameters:
+ //@{
+
+ DBStorageLayoutId myLayout;
+ //@Man: Persistent Representation of a StorageLayout object.
+ //@{
+ ///All parameters are stored there.
+ //@}
+
+ //@}
+
+ };
+#endif
diff --git a/systemtest/Makefile b/systemtest/Makefile
new file mode 100644
index 0000000..e431fdf
--- /dev/null
+++ b/systemtest/Makefile
@@ -0,0 +1,56 @@
+# -*-Makefile-*-
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+#
+# MAKEFILE FOR:
+# perform systemtest (overall rasdaman test suite)
+#
+# COMMENTS:
+# - not yet operational
+#
+##################################################################
+######################### Definitions ############################
+
+# all test programs
+SRCCXX =
+OBJS = ${SRCCXX:%.cc=%.o}
+ALLTESTS = ${SRCCXX:%.cc=%}
+MISCCLEAN = core
+
+# add compile and link options for STL
+CXXFLAGS += $(STLCXXFLAGS)
+LDFLAGS += $(STLLDFLAGS)
+
+########################### Targets ##############################
+
+# general system test
+.PHONY: systemtest
+systemtest:
+ ./testcenter.sh
+ ./testcenter2.sh
+ ./testjava.sh
+
+clean:
+ -rm $(MISCCLEAN)
+
+######################## Dependencies ############################
+
diff --git a/systemtest/image1.bmp b/systemtest/image1.bmp
new file mode 100644
index 0000000..8726663
--- /dev/null
+++ b/systemtest/image1.bmp
Binary files differ
diff --git a/systemtest/image1.hdf b/systemtest/image1.hdf
new file mode 100644
index 0000000..faf61b3
--- /dev/null
+++ b/systemtest/image1.hdf
Binary files differ
diff --git a/systemtest/image1.jpg b/systemtest/image1.jpg
new file mode 100644
index 0000000..05b4f5b
--- /dev/null
+++ b/systemtest/image1.jpg
Binary files differ
diff --git a/systemtest/image1.png b/systemtest/image1.png
new file mode 100644
index 0000000..28662b8
--- /dev/null
+++ b/systemtest/image1.png
Binary files differ
diff --git a/systemtest/image1.tif b/systemtest/image1.tif
new file mode 100644
index 0000000..3946810
--- /dev/null
+++ b/systemtest/image1.tif
Binary files differ
diff --git a/systemtest/image1.vff b/systemtest/image1.vff
new file mode 100644
index 0000000..10eed0d
--- /dev/null
+++ b/systemtest/image1.vff
Binary files differ
diff --git a/systemtest/image2.bmp b/systemtest/image2.bmp
new file mode 100644
index 0000000..8726663
--- /dev/null
+++ b/systemtest/image2.bmp
Binary files differ
diff --git a/systemtest/image2.hdf b/systemtest/image2.hdf
new file mode 100644
index 0000000..1f99e17
--- /dev/null
+++ b/systemtest/image2.hdf
Binary files differ
diff --git a/systemtest/image2.jpg b/systemtest/image2.jpg
new file mode 100644
index 0000000..05b4f5b
--- /dev/null
+++ b/systemtest/image2.jpg
Binary files differ
diff --git a/systemtest/image2.png b/systemtest/image2.png
new file mode 100644
index 0000000..28662b8
--- /dev/null
+++ b/systemtest/image2.png
Binary files differ
diff --git a/systemtest/image2.tif b/systemtest/image2.tif
new file mode 100644
index 0000000..3946810
--- /dev/null
+++ b/systemtest/image2.tif
Binary files differ
diff --git a/systemtest/image2.vff b/systemtest/image2.vff
new file mode 100644
index 0000000..b455d86
--- /dev/null
+++ b/systemtest/image2.vff
@@ -0,0 +1,15 @@
+ncaa
+rank=2;
+type=raster;
+format=slice;
+size=11 11;
+origin=0 0;
+extent=10 10;
+aspect=1.0 1.0;
+bands=1;
+bits=8;
+endianness=little_endian;
+data_order=xy;
+
+
+ \ No newline at end of file
diff --git a/systemtest/images/ovl1.ppm b/systemtest/images/ovl1.ppm
new file mode 100644
index 0000000..d897c90
--- /dev/null
+++ b/systemtest/images/ovl1.ppm
@@ -0,0 +1,4 @@
+P6
+10 10
+255
+¼l3¬c$´k+´w4´k+¬k,´l=¼yE¤wK´†C´r4¬c$¬k,´w4´k+¤k3¬k4´r=´€CÄT¬e=œX,¤^+´l=´r4¬k,´k+¬k4´€CÌR”X6„A&”L$¬d1´l4´l4´l4´l4½r>¼€D„F(t8„@¤Y,´e6¼l3´r4´r4¼l3´l4|B,t2|:œR.´d,´l4´k+´k+¼l3¬^*|K)f6&„@¤R#¬^*´d,´d,´k+´d,¬Y$|M4t8„@¤X#´^/´^!´k+´d"¼l3´d,•FœLœR"œW#¤Y,¬d1´l4´l4´d,¬^*œW#”L”L¤R#´l4½r>´l4¬^*´d,¬Y$ \ No newline at end of file
diff --git a/systemtest/images/ovl2.ppm b/systemtest/images/ovl2.ppm
new file mode 100644
index 0000000..03b0fec
--- /dev/null
+++ b/systemtest/images/ovl2.ppm
Binary files differ
diff --git a/systemtest/images/ovl3.ppm b/systemtest/images/ovl3.ppm
new file mode 100644
index 0000000..d4e7db0
--- /dev/null
+++ b/systemtest/images/ovl3.ppm
Binary files differ
diff --git a/systemtest/memleak/overview b/systemtest/memleak/overview
new file mode 100644
index 0000000..2e5cbc3
--- /dev/null
+++ b/systemtest/memleak/overview
@@ -0,0 +1,18 @@
+test server memleaks by invoking a large number of operations using rasql.
+
+RASQL=rasql
+
+REPETITIONS=100
+
+- subsetting
+
+QUERY_TRIM="select a[sdom(a)[0].lo+1:sdom(a)[0].hi-1,sdom(a)[1].lo+1:sdom(a)[1].hi-1] from $TESTCOLL_2D as a"
+
+
+
+for n in ($REPETITIONS)
+do
+ echo performing run $n...
+ $RASQL -q $UERY_TRIM # ignore result
+done
+
diff --git a/systemtest/rasdl/generator_rasdl.sh b/systemtest/rasdl/generator_rasdl.sh
new file mode 100644
index 0000000..6d8d31f
--- /dev/null
+++ b/systemtest/rasdl/generator_rasdl.sh
@@ -0,0 +1,41 @@
+#!/bin/bash
+
+EXC="exc.sh"
+
+CREDB="rasdl RASBASE -c"
+INSDB="rasdl RASBASE -r $RMANHOME/include/basictypes.odl -i"
+PRNDB="rasdl RASBASE -p"
+DELDB="rasdl RASBASE -deldatabase"
+
+
+CMD=$CREDB
+echo "1. Creating RASBASE."
+COUT="create1.out"
+$EXC "$CMD" $COUT
+echo "2. Creating RASBASE again."
+COUT="create2.out"
+$EXC "$CMD" $COUT
+
+
+CMD=$INSDB
+echo "3. Inserting basic types into RASBASE."
+COUT="insert1.out"
+$EXC "$CMD" $COUT
+echo "4. Inserting basic types into RASBASE again."
+COUT="insert2.out"
+$EXC "$CMD" $COUT
+
+
+CMD=$PRNDB
+echo "5. Printing basic types from RASBASE."
+COUT="types1.out"
+$EXC "$CMD" $COUT
+
+
+CMD=$DELDB
+echo "6. Deleting RASBASE."
+COUT="delete1.out"
+$EXC "$CMD" $COUT
+echo "7. Deleting RASBASE again."
+COUT="delete2.out"
+$EXC "$CMD" $COUT
diff --git a/systemtest/rasdl/rasdl.sh b/systemtest/rasdl/rasdl.sh
new file mode 100644
index 0000000..55848ca
--- /dev/null
+++ b/systemtest/rasdl/rasdl.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+cdir=$PWD
+cd $RMANHOME/systemtest/rasdl
+./test_rasdl.sh > log.out 2>&1
+diff log.out compare.out
+retval=$?
+cd $cdir
+echo $retval
+exit $retval
diff --git a/systemtest/rasdl/test_rasdl.sh b/systemtest/rasdl/test_rasdl.sh
new file mode 100644
index 0000000..111d754
--- /dev/null
+++ b/systemtest/rasdl/test_rasdl.sh
@@ -0,0 +1,90 @@
+#!/bin/bash
+
+if [ $USER != rastest ]; then
+ echo "You are $USER."
+ echo "Only user rastest is allowed to run $0."
+ exit 1
+fi
+
+EXC="exc.sh"
+
+CREDB="rasdl RASBASE -c"
+INSDB="rasdl RASBASE -r $RMANHOME/include/basictypes.odl -i"
+PRNDB="rasdl RASBASE -p"
+DELDB="rasdl RASBASE -deldatabase"
+
+TOUT="test_rasdl.out"
+
+CMD=$CREDB
+echo -n "1. Creating RASBASE: "
+COUT="create1.out"
+$EXC "$CMD" $TOUT
+diff $COUT $TOUT
+if [ $? = 0 ]; then
+ echo "OK"
+else
+ echo "FAILED"
+fi
+
+echo -n "2. Creating RASBASE again: "
+COUT="create2.out"
+$EXC "$CMD" $TOUT
+diff $COUT $TOUT
+if [ $? = 0 ]; then
+ echo "OK"
+else
+ echo "FAILED"
+fi
+
+CMD=$INSDB
+echo -n "3. Inserting basic types into RASBASE: "
+COUT="insert1.out"
+$EXC "$CMD" $TOUT
+diff $COUT $TOUT
+if [ $? = 0 ]; then
+ echo "OK"
+else
+ echo "FAILED"
+fi
+
+echo -n "4. Inserting basic types into RASBASE again: "
+COUT="insert2.out"
+$EXC "$CMD" $TOUT
+diff $COUT $TOUT
+if [ $? = 0 ]; then
+ echo "OK"
+else
+ echo "FAILED"
+fi
+
+CMD=$PRNDB
+echo -n "5. Printing basic types from RASBASE: "
+COUT="types1.out"
+$EXC "$CMD" $TOUT
+diff $COUT $TOUT
+if [ $? = 0 ]; then
+ echo "OK"
+else
+ echo "FAILED"
+fi
+
+CMD=$DELDB
+echo -n "6. Deleting RASBASE: "
+COUT="delete1.out"
+$EXC "$CMD" $TOUT
+diff $COUT $TOUT
+if [ $? = 0 ]; then
+ echo "OK"
+else
+ echo "FAILED"
+fi
+
+echo -n "7. Deleting RASBASE again: "
+COUT="delete2.out"
+$EXC "$CMD" $TOUT
+diff $COUT $TOUT
+if [ $? = 0 ]; then
+ echo "OK"
+else
+ echo "FAILED"
+fi
diff --git a/systemtest/scripts/rasql_1.png b/systemtest/scripts/rasql_1.png
new file mode 100644
index 0000000..125be48
--- /dev/null
+++ b/systemtest/scripts/rasql_1.png
Binary files differ
diff --git a/systemtest/scripts/test_error-par.old b/systemtest/scripts/test_error-par.old
new file mode 100644
index 0000000..55c5ece
--- /dev/null
+++ b/systemtest/scripts/test_error-par.old
@@ -0,0 +1,2 @@
+test_error-par.sh: testing client/server communication for open/close db/ta, protocol is RNP
+test_error-par.sh: 10 probed, 2 reached, 8 failed.
diff --git a/systemtest/scripts/test_error-par.sh b/systemtest/scripts/test_error-par.sh
new file mode 100644
index 0000000..748d285
--- /dev/null
+++ b/systemtest/scripts/test_error-par.sh
@@ -0,0 +1,130 @@
+#!/bin/bash
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+# test_errors-par.sh - test multi-server availability
+#
+# SYNOPSIS:
+# test_errors-par.sh
+#
+# DESCRIPTION
+# Performs test queries to check that multiple servers are really available.
+# To this end, several "ping" programs are spawned each keeping a server busy.
+# If a pinger fails then there is no (more) server available.
+# This way, the script determines the number of servers available.
+#
+# RESPONDING TO INCIDENT
+# none
+#
+# PROCEDURE
+# see above.
+#
+# PRECONDITIONS
+# - rasdaman up and running, with database having user/password as defined below
+#
+# RETURN CODES
+ RC_OK=0 # everything went fine
+ RC_ERROR=1 # something went wrong
+#
+
+
+RCTEXT_OK="OK"
+RCTEXT_ERROR="NOT_OK"
+
+# --- CONSTANTS -----------------------------------------------------
+
+# number of servers to be probed
+NO_OF_SERVERS=10
+
+# name of script
+PROG=`basename $0`
+
+# name of test program
+TESTPROG=`basename $0 .sh`
+
+# log output
+LOGFILE=/tmp/`basename $PROG .sh`.log
+
+# old log file for regression comparison:
+OLDFILE=`basename $PROG .sh`.old
+
+# how to react on error
+function raiseError() { echo "$PROG: fatal error, aborting."; exit $RC_ERROR; }
+#function raiseError() { echo "$PROG: error in test; resuming."; RC=$RC_ERROR; }
+
+# string to determine that a server connection suceeded; see test prog src!
+SUCCESS_INDICATOR=SUCCESS
+
+# --- ACTION --------------------------------------------------------
+
+echo $PROG: testing client/server communication for open/close db/ta, protocol is $RMANPROTOCOL
+echo $PROG: testing client/server communication for open/close db/ta, protocol is $RMANPROTOCOL >$LOGFILE
+
+# initialize overall return code
+RC=$RC_OK
+
+# --- make test progs
+( cd $TESTPROG; make )
+
+# --- check no of available servers
+for (( i=$NO_OF_SERVERS; $i > 0; i=`expr $i - 1` ))
+do
+ # each tester runs infinitely, thereby definitely blocking its server
+ $TESTPROG/$TESTPROG --wait 100 --requests 1000000 --id $i 2>&1 >${LOGFILE}_$i &
+ # collect process ids so that wen can kill them again lateron
+ PIDS="$PIDS $!"
+done
+
+echo -n "$PROG: waiting for test progs to settle down"
+for i in 1 2 3 4 5
+do
+ sleep 1
+ echo -n "."
+done
+echo
+
+# cleanup processes; we're not interested whether they really are alive still
+kill -TERM $PIDS 2>/dev/null
+
+# evaluate log file
+SUCCEEDS=`grep $SUCCESS_INDICATOR ${LOGFILE}*| wc -l`
+echo $PROG: $NO_OF_SERVERS probed, $SUCCEEDS reached, `expr $NO_OF_SERVERS - $SUCCEEDS` failed.
+echo $PROG: $NO_OF_SERVERS probed, $SUCCEEDS reached, `expr $NO_OF_SERVERS - $SUCCEEDS` failed. >>$LOGFILE
+
+# --- compare files against old ones
+if [ `diff $OLDFILE $LOGFILE | wc -l` -ne 0 ]
+then
+ echo "$PROG: Error: regression discrepancy between files $OLDFILE $LOGFILE -- $RCTEXT_ERROR"
+ RC=$RC_ERROR
+fi
+
+# --- cleanup and summarise
+if [ $RC -eq $RC_OK ]
+then
+ rm -f ${LOGFILE}*
+ RCTEXT=$RCTEXT_OK
+else
+ RCTEXT=$RCTEXT_ERROR
+fi
+
+echo $PROG: done, result is $RCTEXT.
+exit $RC
+
diff --git a/systemtest/scripts/test_error-par/Makefile b/systemtest/scripts/test_error-par/Makefile
new file mode 100644
index 0000000..84e596e
--- /dev/null
+++ b/systemtest/scripts/test_error-par/Makefile
@@ -0,0 +1,77 @@
+# -*-Makefile-*-
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>. # Top Level makefile. This points to the various modules that have to be build
+# and/or deployed
+#
+# MAKEFILE FOR:
+# test_error-par
+#
+# COMMENTS:
+#
+##################################################################
+
+######################### Definitions ############################
+
+# use client specific flags
+CXXFLAGS := $(CLIENTCXXFLAGS)
+LDFLAGS := $(CLIENTLDFLAGS)
+
+# add communication flags
+CXXFLAGS += $(COMMCXXFLAGS)
+LDFLAGS += $(COMMLDFLAGS)
+
+LIBS = $(RASODMG) $(CLIENTCOMM) $(RASLIB) \
+ $(CONVERSION) $(LIBAKINSIDE) $(LIBAKNET)
+
+IMGLIBS = $(l_SYM)tiff $(l_SYM)jpeg $(l_SYM)png $(l_SYM)crypto $(l_SYM)z \
+ $(l_SYM)mfhdf $(l_SYM)df $(l_SYM)ppm $(l_SYM)pgm $(l_SYM)pbm
+
+LDFLAGS += $(L_SYM)$(SUPPORT_BASE)/lib
+
+SRCCXX= test_error-par.cc
+OBJS = ${SRCCXX:%.cc=%.o}
+
+ifeq ($(OSTYPE),$(OSTYPE_SOLARIS))
+ LDFLAGS+= -lsocket
+endif
+
+MISCCLEAN = test_error-par
+
+########################### Targets ##############################
+# main target
+.PHONY: all
+all: test_error-par
+
+test_error-par: test_error-par.o $(LIBS)
+ $(PURIFY) $(CXX) $(LDFLAGS) -o test_error-par $^ $(LIBS) $(IMGLIBS) -lm
+
+.PHONY: depend
+depend:
+ -rm Makefile.dep
+ $(MAKEDEPEND) -m -f- -- $(CXXFLAGS) -- $(SRCCXX) $(SRCCC) > Makefile.dep
+
+.PHONY: clean
+clean:
+ -rm $(OBJS) $(MISCCLEAN)
+
+######################## Dependencies ############################
+
diff --git a/systemtest/scripts/test_error-par/test_error-par.cc b/systemtest/scripts/test_error-par/test_error-par.cc
new file mode 100644
index 0000000..05eb7f0
--- /dev/null
+++ b/systemtest/scripts/test_error-par/test_error-par.cc
@@ -0,0 +1,467 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * Open a db connection to block a server. To additionally keep
+ * it busy, a request is sent periodically with a configurable
+ * wait time inbetween.
+ * Upon a SIGTERM signal, the program gracefully exits, closing
+ * transaction and database.
+ * Request is a dummy get type request, it doesn't matter what
+ * the response is.
+ * This program is used to test behavior on erroneous API calls
+ * on multiple servers (ie, parallel behavior - sequential behavior
+ * is tested in the twin program test_rasgeo-seq.cc).
+ *
+ * PARAMETERS:
+ * -w n wait n millisecs until next request
+ * -i n identifier for logging
+ * -r n run n requests, then terminate
+ * ...plus server, port, db, user, passwd
+ *
+ *
+ * PRECONDITIONS:
+ * - have a rasdaman server running
+ * - have at least one 1 rasserver up
+ *
+ * COMMENTS:
+ * - server type controlled via RMANPROTOCOL
+ *
+ * BUGS:
+ *
+ ************************************************************/
+
+using namespace std;
+
+static const char test_error_par_rcsid[] = "@(#)test_test_error-par,test_error-par.cc: $Id: test_error-par.cc,v 1.2 2005/09/11 08:42:33 rasdev Exp $";
+
+// error indicator - should eventually go into a central systemtest include
+static const char MSG_OK[] = "ok";
+static const char MSG_FAILED[] = "error";
+
+/*
+COMPDATE=`date +"%d.%m.%Y %H:%M:%S"`
+and -DCOMPDATE="\"$(COMPDATE)\"" when compiling
+*/
+#ifndef RMANVERSION
+#error "Please specify RMANVERSION variable!"
+#endif
+
+#ifndef COMPDATE
+#error "Please specify the COMPDATE variable!"
+#endif
+
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#include "raslib/template_inst.hh"
+#endif
+
+#ifdef __VISUALC__
+#include <strstrea.h>
+#else
+#include <strstream>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <sstream>
+#include <fstream>
+
+#include <signal.h> // for signal()
+
+#ifdef __VISUALC__
+ #define __EXECUTABLE__
+#endif
+
+#include "rasodmg/transaction.hh"
+#include "rasodmg/database.hh"
+
+#include "rasodmg/ref.hh"
+#include "raslib/marraytype.hh"
+#include "rasodmg/set.hh"
+#include "rasodmg/marray.hh"
+#include "rasodmg/iterator.hh"
+#include "rasodmg/oqlquery.hh"
+
+#include "raslib/type.hh"
+
+#include "raslib/minterval.hh"
+
+#include "raslib/primitive.hh"
+#include "raslib/complex.hh"
+#include "raslib/structure.hh"
+
+#include "raslib/structuretype.hh"
+#include "raslib/primitivetype.hh"
+
+#include "cmlparser.hh"
+
+#ifdef __VISUALC__
+ #undef __EXECUTABLE__
+#endif
+
+// debug facility; relies on -DDEBUG at compile time
+// tell debug that here is the place for the variables (to be done in the main() src file)
+#define DEBUG_MAIN
+#include "debug-clt.hh"
+
+const int MAX_STR_LEN = 255;
+const int MAX_QUERY_LEN = 10240;
+
+/// log strings (keep consistent with shell script!)
+/// - log string indicating that the server cannot be reached
+const char *ERROR_INDICATOR = "ERROR";
+/// - log string indicating that the server cannot be reached
+const char *TOUCH_SUCCESS = "SUCCESS";
+
+/// program exit codes
+#define EXIT_SUCCESS 0
+#define EXIT_USAGE 2
+#define EXIT_FAILURE -1
+
+// parameter names, defaults, and help texts
+
+#define PARAM_HELP_FLAG 'h'
+#define PARAM_HELP "help"
+#define HELP_HELP "show command line switches"
+
+#define PARAM_WAIT_FLAG 'w'
+#define PARAM_WAIT "wait"
+#define HELP_WAIT "<n> wait time between requests [msecs]"
+#define DEFAULT_WAIT 1000
+#define DEFAULT_WAIT_STR "1000"
+
+#define PARAM_ID_FLAG 'i'
+#define PARAM_ID "id"
+#define HELP_ID "<n> id [integer]"
+#define DEFAULT_ID 1
+#define DEFAULT_ID_STR "1"
+
+#define PARAM_REQU_FLAG 'r'
+#define PARAM_REQU "requests"
+#define HELP_REQU "<n> number of requests [integer]"
+#define DEFAULT_REQU 1
+#define DEFAULT_REQU_STR "1"
+
+#define PARAM_SERV_FLAG 's'
+#define PARAM_SERV "server"
+#define HELP_SERV "<host-name> rasdaman server"
+#define DEFAULT_SERV "localhost"
+
+#define PARAM_PORT_FLAG 'p'
+#define PARAM_PORT "port"
+#define HELP_PORT "<p> rasmgr port number"
+#define DEFAULT_PORT 7001
+#define DEFAULT_PORT_STR "7001"
+
+#define PARAM_DB_FLAG 'd'
+#define PARAM_DB "database"
+#define HELP_DB "<db-name> name of database"
+#define DEFAULT_DB "RASBASE"
+
+#define PARAM_USER "user"
+#define HELP_USER "<user-name> name of user"
+#define DEFAULT_USER "rasguest"
+
+#define PARAM_PASSWD "passwd"
+#define HELP_PASSWD "<user-passwd> password of user"
+#define DEFAULT_PASSWD "rasguest"
+
+#define PARAM_DEBUG "debug"
+#define HELP_DEBUG "generate diagnostic output"
+
+// name to be tested in touch()
+const char* MDD_TYPE_NAME = "RGBImage";
+
+// global variables and default settings
+// -------------------------------------
+
+bool keepOn = true; // while true: keep in loop; reset by interrupt
+
+r_Database db;
+r_Transaction ta;
+
+bool dbIsOpen = false;
+bool taIsOpen = false;
+
+unsigned int id = DEFAULT_ID;
+unsigned long waitTime = DEFAULT_WAIT;
+unsigned int requests = DEFAULT_REQU;
+
+const char *serverName = DEFAULT_SERV;
+r_ULong serverPort = DEFAULT_PORT;
+const char *baseName = DEFAULT_DB;
+
+const char *user = DEFAULT_USER;
+const char *passwd = DEFAULT_PASSWD;
+
+const char *fileName = NULL;
+const char *queryString=NULL;
+
+// query result set.
+// we define it here because on empty results the set seems to be corrupt which kills the default destructor
+r_Set< r_Ref_Any > result_set;
+
+// end of globals
+
+void
+parseParams(int argc, char** argv) throw (r_Error)
+{
+ CommandLineParser &cmlInter = CommandLineParser::getInstance();
+
+ CommandLineParameter &clp_help = cmlInter.addFlagParameter( PARAM_HELP_FLAG, PARAM_HELP, HELP_HELP );
+
+ CommandLineParameter &clp_wait = cmlInter.addStringParameter( PARAM_WAIT_FLAG, PARAM_WAIT, HELP_WAIT, DEFAULT_WAIT_STR );
+
+ CommandLineParameter &clp_id = cmlInter.addStringParameter( PARAM_ID_FLAG, PARAM_ID, HELP_ID, DEFAULT_ID_STR );
+
+ CommandLineParameter &clp_requ = cmlInter.addStringParameter( PARAM_REQU_FLAG, PARAM_REQU, HELP_REQU, DEFAULT_REQU_STR );
+
+ CommandLineParameter &clp_server = cmlInter.addStringParameter( PARAM_SERV_FLAG, PARAM_SERV, HELP_SERV, DEFAULT_SERV );
+ CommandLineParameter &clp_port = cmlInter.addStringParameter( PARAM_PORT_FLAG, PARAM_PORT, HELP_PORT, DEFAULT_PORT_STR);
+ CommandLineParameter &clp_database = cmlInter.addStringParameter( PARAM_DB_FLAG, PARAM_DB, HELP_DB, DEFAULT_DB );
+ CommandLineParameter &clp_user = cmlInter.addStringParameter(CommandLineParser::noShortName, PARAM_USER, HELP_USER, DEFAULT_USER );
+ CommandLineParameter &clp_passwd = cmlInter.addStringParameter(CommandLineParser::noShortName, PARAM_PASSWD, HELP_PASSWD, DEFAULT_PASSWD );
+
+#ifdef DEBUG
+ CommandLineParameter &clp_debug = cmlInter.addFlagParameter( CommandLineParser::noShortName, PARAM_DEBUG, HELP_DEBUG );
+#endif
+
+ try
+ {
+ cmlInter.processCommandLine(argc, argv);
+
+ if (cmlInter.isPresent( PARAM_HELP_FLAG ))
+ {
+ cout << "usage: " << argv[0] << " [options]" << endl;
+ cout << "options:" << endl;
+ cmlInter.printHelp();
+ exit( EXIT_USAGE );
+ }
+
+ // check mandatory parameters ====================================================
+
+ // evaluate optional parameter server --------------------------------------
+ if (cmlInter.isPresent( PARAM_WAIT ))
+ waitTime = cmlInter.getValueAsLong( PARAM_WAIT );
+
+ // check optional parameters ====================================================
+
+ // evaluate optional parameter id --------------------------------------
+ if (cmlInter.isPresent( PARAM_ID ))
+ id = cmlInter.getValueAsLong( PARAM_ID );
+
+ // evaluate optional parameter requests --------------------------------------
+ if (cmlInter.isPresent( PARAM_REQU ))
+ requests = cmlInter.getValueAsLong( PARAM_REQU );
+
+ // evaluate optional parameter server --------------------------------------
+ if (cmlInter.isPresent( PARAM_SERV ))
+ serverName = cmlInter.getValueAsString( PARAM_SERV );
+
+ // evaluate optional parameter port --------------------------------------
+ if (cmlInter.isPresent( PARAM_PORT ))
+ serverPort = cmlInter.getValueAsLong( PARAM_PORT );
+
+ // evaluate optional parameter database --------------------------------------
+ if (cmlInter.isPresent( PARAM_DB ))
+ baseName = cmlInter.getValueAsString( PARAM_DB );
+
+ // evaluate optional parameter user --------------------------------------
+ if (cmlInter.isPresent( PARAM_USER ))
+ user = cmlInter.getValueAsString( PARAM_USER );
+
+ // evaluate optional parameter passwd --------------------------------------
+ if (cmlInter.isPresent( PARAM_PASSWD ))
+ passwd = cmlInter.getValueAsString( PARAM_PASSWD );
+
+#ifdef DEBUG
+ // evaluate optional parameter MDD type name --------------------------------------
+ SET_OUTPUT( cmlInter.isPresent( PARAM_DEBUG ) );
+#endif
+
+ }
+ catch(CmlException& err)
+ {
+ cout << argv[0] << ": " << err.what() << endl;
+ throw;
+ }
+} // parseParams()
+
+
+void catchInterrupt( int n )
+{
+ keepOn = false;
+}
+
+void
+openDatabase() throw (r_Error)
+{
+ ENTER( "openDatabase -- db is " << (dbIsOpen?"":"not ") << "open." );
+
+ db.set_servername(serverName, serverPort);
+ db.set_useridentification(user, passwd);
+ TALK( "database was closed, opening database=" << baseName << ", server=" << serverName << ", port=" << serverPort << ", user=" << user << ", passwd=" << passwd << "." );
+ db.open(baseName);
+ dbIsOpen = true;
+
+ LEAVE( "openDatabase" );
+} // openDatabase()
+
+void
+closeDatabase() throw (r_Error)
+{
+ ENTER( "closeDatabase -- db is " << (dbIsOpen?"":"not ") << "open." );
+
+ db.close();
+ dbIsOpen = false;
+
+ LEAVE( "closeDatabase" );
+ return;
+} // closeDatabase()
+
+void
+openTransaction(bool readwrite) throw (r_Error)
+{
+ ENTER( "openTransaction, readwrite=" << (readwrite?"rw":"ro") << ", ta is " << (taIsOpen?"":"not ") << "open." );
+
+ if (readwrite)
+ ta.begin(r_Transaction::read_write);
+ else
+ ta.begin(r_Transaction::read_only);
+ taIsOpen = true;
+
+ LEAVE( "openTransaction" );
+} // openTransaction()
+
+void
+closeTransaction() throw (r_Error)
+{
+ ENTER( "closeTransaction: aborting ta; ta is " << (taIsOpen?"":"not ") << "open." );
+
+ ta.abort();
+ taIsOpen = false;
+
+ LEAVE( "closeTransaction" );
+ return;
+} // closeTransaction()
+
+int
+touch() throw (r_Error)
+{
+ int returnValue = EXIT_SUCCESS;
+
+ ENTER( "touch -- fetching type information for " << MDD_TYPE_NAME << "." );
+
+ char* typeStructure = NULL;
+
+ // get type structure from database just to touch it
+ ClientComm *cc = db.getComm();
+ if (cc == NULL)
+ {
+ cout << "got NULL communication object from db...";
+ returnValue = EXIT_FAILURE;
+ }
+ else
+ {
+ typeStructure = cc->getTypeStructure( MDD_TYPE_NAME, ClientComm::r_MDDType_Type );
+ TALK( "type structure is " << typeStructure );
+ }
+
+ LEAVE( "touch -> " << returnValue );
+ return( returnValue );
+}
+
+void wait( unsigned long w )
+{
+ timeval tv;
+ tv.tv_sec = w / 1000;
+ tv.tv_usec = w * 1000;
+
+ select(0,NULL,NULL,NULL,&tv); // wait <tv> time
+}
+
+
+/*
+ * main prog: evaluate cmd line, access db.
+ * returns:
+ * EXIT_SUCCESS all went fine
+ * EXIT_HELP help was requested
+ * EXIT_FAILURE something went wrong
+ */
+int main(int argc, char** argv)
+{
+ SET_OUTPUT( true );
+
+ int retval = EXIT_SUCCESS; // overall result status
+
+ signal( SIGTERM, catchInterrupt );
+
+ try
+ {
+ parseParams( argc, argv );
+
+ cout << argv[0] << " id=" << id << ", " << requests << " requests...";
+ openDatabase();
+ openTransaction( false );
+
+ while (keepOn && requests > 0 && retval == EXIT_SUCCESS)
+ {
+ cout << id << ":" << flush;
+ retval = touch();
+ cout << TOUCH_SUCCESS << " " << flush;
+ wait( waitTime );
+ requests--;
+ }
+
+ closeTransaction();
+ closeDatabase();
+ }
+ catch (const r_Error& e)
+ {
+ cout << argv[0] << ": " << ERROR_INDICATOR << ": " << e.get_errorno() << ": " << e.what() << endl;
+ retval = EXIT_FAILURE;
+ }
+ catch (...)
+ {
+ cerr << argv[0] << ERROR_INDICATOR << ": panic: unexpected internal exception." << endl;
+ retval = EXIT_FAILURE;
+ }
+
+ if (retval != EXIT_SUCCESS && (dbIsOpen || taIsOpen) )
+ {
+ closeTransaction(); // abort transaction and close database, ignore any further exceptions
+ closeDatabase();
+ }
+
+ cout << " id=" << id << " done." << endl;
+
+ return retval;
+} // main()
+
+// end of test_error-par.cc
+
diff --git a/systemtest/scripts/test_error-seq.old b/systemtest/scripts/test_error-seq.old
new file mode 100644
index 0000000..c258bbc
--- /dev/null
+++ b/systemtest/scripts/test_error-seq.old
@@ -0,0 +1,13 @@
+test_error-seq.sh: testing client/server communication for open/close db/ta, Fri Sep 2 22:02:32 CEST 2005
+test_error-seq/test_error-seq v1.0, rasdaman v5 -- generated on 02.09.2005 21:49:12.
+- good cycle...ok
+- bad cycle: do not close db, reopen...ok: 0: Exception: Database Open
+- bad cycle: do not close ta, reopen...ok: 0: Exception: Transaction Open
+- bad cycle: do not open ta, touch...ok: 0: Exception: Transaction Not Open
+- bad cycle: double open ta, touch...ok: 0: Exception: Transaction Open
+- bad cycle: double open db, touch...ok: 0: Exception: Database Open
+- bad cycle: double open ta, touch...ok: 0: Exception: Transaction Open
+- bad cycle: double abort ta (handled gracefully)...ok: 0: Exception: Transaction Not Open
+- bad cycle: double close db (handled gracefully)...ok
+- bad cycle: touch without any db/ta open...got NULL communication object from db...ok
+test_error-seq/test_error-seq done.
diff --git a/systemtest/scripts/test_error-seq.sh b/systemtest/scripts/test_error-seq.sh
new file mode 100644
index 0000000..9d0813e
--- /dev/null
+++ b/systemtest/scripts/test_error-seq.sh
@@ -0,0 +1,99 @@
+#!/bin/bash
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+# test_errors-seq.sh - test single-client errors due to bad client behavior
+#
+# SYNOPSIS:
+# test_errors-seq.sh
+#
+# DESCRIPTION
+# Performs test queries to check proper handling of error conditions.
+# - Errors on query level are handled by rasql.
+# - Errors on protocol level are triggered via a test program.
+# Ater provoking an error, it is tested whether the server remains
+# available fur same/other clients (whatever is appropriate).
+#
+# RESPONDING TO INCIDENT
+# none
+#
+# PROCEDURE
+# perform invocations, checks response and subsequent server availbility.
+#
+# PRECONDITIONS
+# - rasql utility available
+# - rasdaman up and running, with database having user/password as defined below
+#
+# RETURN CODES
+ RC_OK=0 # everything went fine
+ RC_ERROR=1 # something went wrong
+#
+RCTEXT_OK="OK"
+RCTEXT_ERROR="NOT_OK"
+
+# --- CONSTANTS -----------------------------------------------------
+
+# name of script
+PROG=`basename $0`
+
+# name of test program
+TESTPROG=`basename $0 .sh`
+
+# log output
+LOGFILE=/tmp/`basename $PROG .sh`.log
+
+# old log file for regression comparison:
+OLDFILE=`basename $PROG .sh`.old
+
+# how to react on error
+function raiseError() { echo "$PROG: fatal error, aborting."; exit $RC_ERROR; }
+#function raiseError() { echo "$PROG: error in test; resuming."; RC=$RC_ERROR; }
+
+# --- ACTION --------------------------------------------------------
+
+echo $PROG: testing client/server communication for open/close db/ta
+echo $PROG: testing client/server communication for open/close db/ta, `date` >$LOGFILE
+
+# initialize overall return code
+RC=$RC_OK
+
+# --- test
+(cd $TESTPROG; make )
+$TESTPROG/$TESTPROG 2>&1 >>$LOGFILE || raiseError
+
+# --- compare files against old ones
+if [ `cmp -s $OLDFILE $LOGFILE` ]
+then
+ echo "Error: regression discrepancy between files $OLDDIR/$i and $LOGDIR/$i -- $RCTEXT_ERROR"
+fi
+
+# --- cleanup and summarise
+if [ $RC -eq $RC_OK ]
+then
+ rm -f $LOGFILE
+ RCTEXT=$RCTEXT_OK
+else
+ RCTEXT=$RCTEXT_ERROR
+fi
+
+echo $PROG: done, result is $RCTEXT.
+exit $RC
+
diff --git a/systemtest/scripts/test_error-seq/Makefile b/systemtest/scripts/test_error-seq/Makefile
new file mode 100644
index 0000000..09826d6
--- /dev/null
+++ b/systemtest/scripts/test_error-seq/Makefile
@@ -0,0 +1,70 @@
+# -*-Makefile-*-
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>. # Top Level makefile. This points to the various modules that have to be build
+# and/or deployed
+#
+# MAKEFILE FOR:
+# test_error-seq
+#
+# COMMENTS:
+#
+##################################################################
+
+######################### Definitions ############################
+
+# use client specific flags
+CXXFLAGS := $(CLIENTCXXFLAGS)
+LDFLAGS := $(CLIENTLDFLAGS)
+
+# add communication flags
+CXXFLAGS += $(COMMCXXFLAGS)
+LDFLAGS += $(COMMLDFLAGS)
+
+LIBS = $(RASODMG) $(CLIENTCOMM) $(RASLIB) \
+ $(CONVERSION) $(LIBAKINSIDE) $(LIBAKNET)
+
+IMGLIBS = $(l_SYM)tiff $(l_SYM)jpeg $(l_SYM)png $(l_SYM)crypto $(l_SYM)z \
+ $(l_SYM)mfhdf $(l_SYM)df $(l_SYM)ppm $(l_SYM)pgm $(l_SYM)pbm
+
+LDFLAGS += $(L_SYM)$(SUPPORT_BASE)/lib
+
+SRCCXX= test_error-seq.cc
+OBJS = ${SRCCXX:%.cc=%.o}
+
+ifeq ($(OSTYPE),$(OSTYPE_SOLARIS))
+ LDFLAGS+= -lsocket
+endif
+
+MISCCLEAN = test_error-seq
+
+########################### Targets ##############################
+# main target
+.PHONY: all
+all: test_error-seq
+
+test_error-seq: test_error-seq.o $(LIBS)
+ $(PURIFY) $(CXX) $(LDFLAGS) -o test_error-seq $^ $(LIBS) $(IMGLIBS) -lm
+
+.PHONY: clean
+clean:
+ -rm $(OBJS) $(MISCCLEAN)
+
diff --git a/systemtest/scripts/test_error-seq/test_error-seq.cc b/systemtest/scripts/test_error-seq/test_error-seq.cc
new file mode 100644
index 0000000..79d889f
--- /dev/null
+++ b/systemtest/scripts/test_error-seq/test_error-seq.cc
@@ -0,0 +1,515 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * test behavior on erroneous API calls on a single server
+ * (ie, sequential behavior - parallel behavior is tested in
+ * the twin program test_rasgeo-par.cc).
+ *
+ *
+ * PRECONDITIONS:
+ * - have a rasdaman server running, with std types inserted
+ * - use exactly 1 rasserver
+ *
+ * COMMENTS:
+ *
+ * BUGS:
+ *
+ ************************************************************/
+
+static const char test_error_seq_rcsid[] = "@(#)test_test_error-seq,test_error-seq.cc: $Id: test_error-seq.cc,v 1.1 2003/12/27 19:30:23 rasdev Exp $";
+
+// error indicator - should eventually go into a central systemtest include
+static const char MSG_OK[] = "ok";
+static const char MSG_FAILED[] = "error";
+
+/*
+COMPDATE=`date +"%d.%m.%Y %H:%M:%S"`
+and -DCOMPDATE="\"$(COMPDATE)\"" when compiling
+*/
+#ifndef RMANVERSION
+#error "Please specify RMANVERSION variable!"
+#endif
+
+#ifndef COMPDATE
+#error "Please specify the COMPDATE variable!"
+#endif
+
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#include "raslib/template_inst.hh"
+#endif
+
+#ifdef __VISUALC__
+#include <strstrea.h>
+#else
+#include <strstream>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <sstream>
+#include <fstream>
+
+using namespace std;
+
+#ifdef __VISUALC__
+ #define __EXECUTABLE__
+#endif
+
+#include "rasodmg/transaction.hh"
+#include "rasodmg/database.hh"
+
+#include "rasodmg/ref.hh"
+#include "raslib/marraytype.hh"
+#include "rasodmg/set.hh"
+#include "rasodmg/marray.hh"
+#include "rasodmg/iterator.hh"
+#include "rasodmg/oqlquery.hh"
+
+#include "raslib/type.hh"
+
+#include "raslib/minterval.hh"
+
+#include "raslib/primitive.hh"
+#include "raslib/complex.hh"
+#include "raslib/structure.hh"
+
+#include "raslib/structuretype.hh"
+#include "raslib/primitivetype.hh"
+
+#include "cmlparser.hh"
+
+#ifdef __VISUALC__
+ #undef __EXECUTABLE__
+#endif
+
+// debug facility; relies on -DDEBUG at compile time
+// tell debug that here is the place for the variables (to be done in the main() src file)
+#define DEBUG_MAIN
+#include "debug-clt.hh"
+
+const int MAX_STR_LEN = 255;
+const int MAX_QUERY_LEN = 10240;
+
+
+/// program exit codes
+#define EXIT_SUCCESS 0
+#define EXIT_USAGE 2
+#define EXIT_FAILURE -1
+
+// parameter names, defaults, and help texts
+
+#define PARAM_HELP_FLAG 'h'
+#define PARAM_HELP "help"
+#define HELP_HELP "show command line switches"
+
+#define PARAM_SERV_FLAG 's'
+#define PARAM_SERV "server"
+#define HELP_SERV "<host-name> rasdaman server"
+#define DEFAULT_SERV "localhost"
+
+#define PARAM_PORT_FLAG 'p'
+#define PARAM_PORT "port"
+#define HELP_PORT "<p> rasmgr port number"
+#define DEFAULT_PORT 7001
+#define DEFAULT_PORT_STR "7001"
+
+#define PARAM_DB_FLAG 'd'
+#define PARAM_DB "database"
+#define HELP_DB "<db-name> name of database"
+#define DEFAULT_DB "RASBASE"
+
+#define PARAM_USER "user"
+#define HELP_USER "<user-name> name of user"
+#define DEFAULT_USER "rasguest"
+
+#define PARAM_PASSWD "passwd"
+#define HELP_PASSWD "<user-passwd> password of user"
+#define DEFAULT_PASSWD "rasguest"
+
+#define PARAM_DEBUG "debug"
+#define HELP_DEBUG "generate diagnostic output"
+
+// name to be tested in touch()
+const char* MDD_TYPE_NAME = "RGBImage";
+
+// global variables and default settings
+// -------------------------------------
+
+r_Database db;
+r_Transaction ta;
+
+bool dbIsOpen = false;
+bool taIsOpen = false;
+
+const char *serverName = DEFAULT_SERV;
+r_ULong serverPort = DEFAULT_PORT;
+const char *baseName = DEFAULT_DB;
+
+const char *user = DEFAULT_USER;
+const char *passwd = DEFAULT_PASSWD;
+
+const char *fileName = NULL;
+const char *queryString=NULL;
+
+// query result set.
+// we define it here because on empty results the set seems to be corrupt which kills the default destructor
+r_Set< r_Ref_Any > result_set;
+
+// end of globals
+
+void
+parseParams(int argc, char** argv) throw (r_Error)
+{
+ CommandLineParser &cmlInter = CommandLineParser::getInstance();
+
+ CommandLineParameter &clp_help = cmlInter.addFlagParameter( PARAM_HELP_FLAG, PARAM_HELP, HELP_HELP );
+
+ CommandLineParameter &clp_server = cmlInter.addStringParameter( PARAM_SERV_FLAG, PARAM_SERV, HELP_SERV, DEFAULT_SERV );
+ CommandLineParameter &clp_port = cmlInter.addStringParameter( PARAM_PORT_FLAG, PARAM_PORT, HELP_PORT, DEFAULT_PORT_STR);
+ CommandLineParameter &clp_database = cmlInter.addStringParameter( PARAM_DB_FLAG, PARAM_DB, HELP_DB, DEFAULT_DB );
+ CommandLineParameter &clp_user = cmlInter.addStringParameter(CommandLineParser::noShortName, PARAM_USER, HELP_USER, DEFAULT_USER );
+ CommandLineParameter &clp_passwd = cmlInter.addStringParameter(CommandLineParser::noShortName, PARAM_PASSWD, HELP_PASSWD, DEFAULT_PASSWD );
+
+#ifdef DEBUG
+ CommandLineParameter &clp_debug = cmlInter.addFlagParameter( CommandLineParser::noShortName, PARAM_DEBUG, HELP_DEBUG );
+#endif
+
+ try
+ {
+ cmlInter.processCommandLine(argc, argv);
+
+ if (cmlInter.isPresent( PARAM_HELP_FLAG ))
+ {
+ cout << "usage: " << argv[0] << " [options]" << endl;
+ cout << "options:" << endl;
+ cmlInter.printHelp();
+ exit( EXIT_USAGE );
+ }
+
+ // check optional parameters ====================================================
+
+ // evaluate optional parameter server --------------------------------------
+ if (cmlInter.isPresent( PARAM_SERV ))
+ serverName = cmlInter.getValueAsString( PARAM_SERV );
+
+ // evaluate optional parameter port --------------------------------------
+ if (cmlInter.isPresent( PARAM_PORT ))
+ serverPort = cmlInter.getValueAsLong( PARAM_PORT );
+
+ // evaluate optional parameter database --------------------------------------
+ if (cmlInter.isPresent( PARAM_DB ))
+ baseName = cmlInter.getValueAsString( PARAM_DB );
+
+ // evaluate optional parameter user --------------------------------------
+ if (cmlInter.isPresent( PARAM_USER ))
+ user = cmlInter.getValueAsString( PARAM_USER );
+
+ // evaluate optional parameter passwd --------------------------------------
+ if (cmlInter.isPresent( PARAM_PASSWD ))
+ passwd = cmlInter.getValueAsString( PARAM_PASSWD );
+
+#ifdef DEBUG
+ // evaluate optional parameter MDD type name --------------------------------------
+ SET_OUTPUT( cmlInter.isPresent( PARAM_DEBUG ) );
+#endif
+
+ }
+ catch(CmlException& err)
+ {
+ cout << argv[0] << ": " << err.what() << endl;
+ throw;
+ }
+} // parseParams()
+
+
+void
+openDatabase() throw (r_Error)
+{
+ ENTER( "openDatabase -- db is " << (dbIsOpen?"":"not ") << "open." );
+
+ db.set_servername(serverName, serverPort);
+ db.set_useridentification(user, passwd);
+ TALK( "database was closed, opening database=" << baseName << ", server=" << serverName << ", port=" << serverPort << ", user=" << user << ", passwd=" << passwd << "." );
+ db.open(baseName);
+ dbIsOpen = true;
+
+ LEAVE( "openDatabase" );
+} // openDatabase()
+
+void
+closeDatabase() throw (r_Error)
+{
+ ENTER( "closeDatabase -- db is " << (dbIsOpen?"":"not ") << "open." );
+
+ db.close();
+ dbIsOpen = false;
+
+ LEAVE( "closeDatabase" );
+ return;
+} // closeDatabase()
+
+void
+openTransaction(bool readwrite) throw (r_Error)
+{
+ ENTER( "openTransaction, readwrite=" << (readwrite?"rw":"ro") << ", ta is " << (taIsOpen?"":"not ") << "open." );
+
+ if (readwrite)
+ ta.begin(r_Transaction::read_write);
+ else
+ ta.begin(r_Transaction::read_only);
+ taIsOpen = true;
+
+ LEAVE( "openTransaction" );
+} // openTransaction()
+
+void
+closeTransaction() throw (r_Error)
+{
+ ENTER( "closeTransaction: aborting ta; ta is " << (taIsOpen?"":"not ") << "open." );
+
+ ta.abort();
+ taIsOpen = false;
+
+ LEAVE( "closeTransaction" );
+ return;
+} // closeTransaction()
+
+void
+touch() throw (r_Error)
+{
+ ENTER( "touch -- fetching type information for " << MDD_TYPE_NAME << "." );
+
+ char* typeStructure = NULL;
+
+ // get type structure from database just to touch it
+ ClientComm *cc = db.getComm();
+ if (cc == NULL)
+ cout << "got NULL communication object from db...";
+ else
+ {
+ typeStructure = cc->getTypeStructure( MDD_TYPE_NAME, ClientComm::r_MDDType_Type );
+ TALK( "type structure is " << typeStructure );
+ }
+
+ LEAVE( "touch" );
+}
+
+void
+doStuff() throw (r_Error)
+{
+ ENTER( "doStuff" );
+
+ cout << "- good cycle..." << flush;
+ openDatabase();
+ openTransaction( false );
+ touch();
+ closeTransaction();
+ closeDatabase();
+ cout << MSG_OK << endl;
+
+ cout << "- bad cycle: do not close db, reopen..." << flush;
+ openDatabase();
+ openTransaction( false );
+ touch();
+ closeTransaction();
+ try
+ {
+ openDatabase();
+ cout << MSG_FAILED << endl;
+ }
+ catch (r_Error& e)
+ {
+ cout << MSG_OK << ": " << e.get_errorno() << ": " << e.what() << endl;
+ }
+ closeDatabase();
+
+ cout << "- bad cycle: do not close ta, reopen..." << flush;
+ openDatabase();
+ openTransaction( false );
+ touch();
+ try
+ {
+ openTransaction( false );
+ cout << MSG_FAILED << endl;
+ }
+ catch (r_Error& e)
+ {
+ cout << MSG_OK << ": " << e.get_errorno() << ": " << e.what() << endl;
+ }
+ closeDatabase();
+
+ cout << "- bad cycle: do not open ta, touch..." << flush;
+ openDatabase();
+ try
+ {
+ touch();
+ closeTransaction();
+ cout << MSG_FAILED << endl;
+ }
+ catch (r_Error& e)
+ {
+ cout << MSG_OK << ": " << e.get_errorno() << ": " << e.what() << endl;
+ }
+ closeDatabase();
+
+ cout << "- bad cycle: double open ta, touch..." << flush;
+ openDatabase();
+ openTransaction( false );
+ try
+ {
+ openTransaction( false );
+ cout << MSG_FAILED << endl;
+ }
+ catch (r_Error& e)
+ {
+ cout << MSG_OK << ": " << e.get_errorno() << ": " << e.what() << endl;
+ }
+ touch();
+ closeDatabase();
+
+ cout << "- bad cycle: double open db, touch..." << flush;
+ openDatabase();
+ try
+ {
+ openDatabase();
+ cout << MSG_FAILED << endl;
+ }
+ catch (r_Error& e)
+ {
+ cout << MSG_OK << ": " << e.get_errorno() << ": " << e.what() << endl;
+ }
+ openTransaction( false );
+ touch();
+ closeDatabase();
+
+ cout << "- bad cycle: double open ta, touch..." << flush;
+ openDatabase();
+ openTransaction( false );
+ try
+ {
+ openTransaction( false );
+ cout << MSG_FAILED << endl;
+ }
+ catch (r_Error& e)
+ {
+ cout << MSG_OK << ": " << e.get_errorno() << ": " << e.what() << endl;
+ }
+ touch();
+ closeTransaction();
+ closeDatabase();
+
+ cout << "- bad cycle: double abort ta (handled gracefully)..." << flush;
+ openDatabase();
+ openTransaction( false );
+ touch();
+ closeTransaction();
+ try
+ {
+ closeTransaction();
+ cout << MSG_FAILED << endl;
+ }
+ catch (r_Error& e)
+ {
+ cout << MSG_OK << ": " << e.get_errorno() << ": " << e.what() << endl;
+ }
+ closeDatabase();
+
+ cout << "- bad cycle: double close db (handled gracefully)..." << flush;
+ openDatabase();
+ openTransaction( false );
+ touch();
+ closeTransaction();
+ closeDatabase();
+ try
+ {
+ closeDatabase();
+ cout << MSG_OK << endl;
+ }
+ catch (r_Error& e)
+ {
+ cout << MSG_FAILED << ": " << e.get_errorno() << ": " << e.what() << endl;
+ }
+
+ cout << "- bad cycle: touch without any db/ta open..." << flush;
+ try
+ {
+ touch();
+ cout << MSG_OK << endl;
+ }
+ catch (r_Error& e)
+ {
+ cout << MSG_FAILED << ": " << e.get_errorno() << ": " << e.what() << endl;
+ }
+
+ LEAVE( "doStuff" );
+}
+
+/*
+ * returns 0 on success, -1 on error
+ */
+int main(int argc, char** argv)
+{
+ SET_OUTPUT( true );
+
+ int retval = EXIT_SUCCESS; // overall result status
+
+ try
+ {
+ parseParams( argc, argv );
+
+ cout << argv[0] << " v1.0, rasdaman v" << RMANVERSION/1000 << " -- generated on " << COMPDATE << "." << endl;
+
+ doStuff();
+ retval = EXIT_SUCCESS;
+ cout << argv[0] << " done." << endl;
+ }
+ catch (const r_Error& e)
+ {
+ cout << argv[0] << ": error " << e.get_errorno() << ": " << e.what() << endl;
+ retval = EXIT_FAILURE;
+ }
+ catch (...)
+ {
+ cerr << argv[0] << ": panic: unexpected internal exception." << endl;
+ retval = EXIT_FAILURE;
+ }
+
+ if (retval != EXIT_SUCCESS && (dbIsOpen || taIsOpen) )
+ {
+ cout << "aborting transaction..." << flush;
+ closeTransaction(); // abort transaction and close database, ignore any further exceptions
+ cout << "ok" << endl;
+ closeDatabase();
+ }
+
+ return retval;
+} // main()
+
+// end of test_error-seq.cc
+
diff --git a/systemtest/scripts/test_ql-extend.sh b/systemtest/scripts/test_ql-extend.sh
new file mode 100644
index 0000000..6a8a9ff
--- /dev/null
+++ b/systemtest/scripts/test_ql-extend.sh
@@ -0,0 +1,131 @@
+#!/bin/ksh
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+# test_ql-extend.sh - test extend() function of rasql
+#
+# SYNOPSIS:
+# test_ql-extend.sh
+#
+# DESCRIPTION
+# Performs test queries to check whether extend() function works.
+echo not yet done!
+exit
+#
+# RESPONDING TO INCIDENT
+# Incident_2005-07-12_IGN_png-transparency
+#
+# PROCEDURE
+# Perform rasql calls, check output and, where applicable, the image generated.
+# Output checking inspects target domain and image contents
+# (original area unchanged, new areas set to 0; contents check just by dumping
+# and relying on regression comparison)
+#
+# PRECONDITIONS
+# - rasql utility available
+# - rasdaman up and running, with database having user/password as defined below
+# - ImageMagick installed to have 'identify' utility
+#
+# RETURN CODES
+ RC_OK=0 # everything went fine
+ RC_ERROR=1 # something went wrong
+#
+# CHANGE HISTORY
+# 2005-jul-16 P.Baumann created
+#
+# RESTRICTIONS
+# test only with 2D, should be extended
+# test only with RGB, should be extended to cover all pixel types
+#
+
+
+# --- CONSTANTS -----------------------------------------------------
+
+RCTEXT_OK="OK"
+RCTEXT_ERROR="NOT_OK"
+
+# name of script
+PROG=`basename $0`
+
+# temp file for getcap response:
+TMPFILE=/tmp/`basename $PROG .sh`.tmp
+
+# --- TEST SETTINGS -------------------------------------------------
+
+# login (must allow r/w)
+USER=rasadmin
+PASSWD=rasadmin
+
+# test collection
+TESTCOLL=ExtendTestCollection
+
+# test image boxes
+BOX_ALLPOS=[10:20,30:40]
+BOX_ALLNEG=[-20:-10,-40:-30]
+BOX_MIXED=[-10:20,-30:40]
+
+# extend boxes, good cases: top right
+EXTEND_GOOD_TOPRIGHT_ALLPOS=[10:20,30:40] ??
+EXTEND_GOOD_TOPRIGHT_ALLNEG=[-20:-10,-40:-30] ??
+EXTEND_GOOD_TOPRIGHT_MIXED=[-10:20,-30:40] ??
+
+...
+
+# bad test cases: extend area inside image
+EXTED_BAD_INSIDE_ALLPOS=[11:19,31:39]
+EXTED_BAD_INSIDE_ALLNEG=[-19:-11,-39:-31]
+EXTED_BAD_INSIDE_MIXED=[-11:19,-29:39]
+
+# --- ACTION --------------------------------------------------------
+
+echo $PROG: Verify rasql extend function
+
+# delete eventually preexisting test collection
+# create test collection
+# create white test images
+# - all corner points in positive quadrant
+# - corner points in all quadrants
+# - all corner points in negative quadrant
+# extend each test image, good cases
+# - extend top right (cross origin for neg locations!)
+# - extend bottom left (cross origin for pos locations!)
+# - extend in all directions
+# extend each test image, bad cases
+# - extend area completely inside test image
+
+# delete test collection
+
+# search for proper string in response
+if [ ...... ]
+then
+ RC=$RC_ERROR
+ RCTEXT=$RCTEXT_ERROR
+else
+ RC=$RC_OK
+ RCTEXT=$RCTEXT_OK
+fi
+
+# clean up
+rm -f $TMPFILE
+
+echo $PROG: done, result is $RCTEXT.
+exit $RC
+
diff --git a/systemtest/scripts/test_ql-png-options.sh b/systemtest/scripts/test_ql-png-options.sh
new file mode 100644
index 0000000..ba6421c
--- /dev/null
+++ b/systemtest/scripts/test_ql-png-options.sh
@@ -0,0 +1,251 @@
+#!/bin/bash
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+# test_ql-png-options.sh - test png(mdd,options) function of rasql
+#
+# SYNOPSIS:
+# test_ql-png-options.sh
+#
+# DESCRIPTION
+# Performs test queries to check whether transparency and background
+# option works in function png(_,_).
+#Write log to stdout/stderr for ???
+# Does not test general image encoding!
+#
+# RESPONDING TO INCIDENT
+# Incident_2005-07-12_IGN_png-transparency
+#
+# PROCEDURE
+# - create test collections and objects
+# - perform rasql calls, check output and, where applicable, the image generated
+# check that (i) file is generated, (ii) has transparency color set appropriately
+# - remove output files and test collections
+#
+# PRECONDITIONS
+# - rasql binary available in the $RMANBASE/applications/rasql development directory
+# - rasdaman up and running,
+# - database allows write access using user/password as defined below
+# - ImageMagick installed to have 'identify' utility
+# - can create subdir in cwd
+#
+# RETURN CODES
+ RC_OK=0 # everything went fine
+ RC_ERROR=1 # something went wrong
+#
+# CHANGE HISTORY
+# 2005-jul-26 P.Baumann created
+# 2005-aug-25 P.Baumann use raiseError() to centralize bailout behavior
+#
+# COMMENTS
+# - add test for INV_PNG()
+#
+
+
+# --- CONSTANTS -----------------------------------------------------
+
+# textual representation of error conditions
+RCTEXT_OK="OK"
+RCTEXT_ERROR="NOT_OK"
+
+# name of script
+PROG=`basename $0`
+
+# reference data directory
+OLDDIR=./`basename $PROG .sh`.old
+
+# temp dir for image files
+TMPDIR=./`basename $PROG .sh`.test
+
+# user/password (must have r/w rights!)
+USER=rasadmin
+PASSWD=rasadmin
+
+# test collections for monochrome/gray/color images
+TESTCOLL_MONO=TestPngMono
+TESTCOLL_GRAY=TestPngGray
+TESTCOLL_COLOR=TestPngColor
+
+# the rasql utility, suppressing unnecessarily verbose output
+RMANBASE=~rasdev/Compile/rasdaman
+RASQL="$RMANBASE/applications/rasql/rasql --quiet"
+
+# to get error messages (from $RMANHOME/bin/errtxts):
+RMANHOME=$RMANBASE
+
+# how to react on error
+function raiseError() { echo "$PROG: fatal error, aborting."; exit $RC_ERROR; }
+#function raiseError() { echo "$PROG: error in test; resuming."; RC=$RC_ERROR; }
+
+# --- ACTION --------------------------------------------------------
+
+echo "$PROG: test rasql PNG() function"
+
+# --- preparation
+
+echo "$PROG: create test dir"
+mkdir -p $TMPDIR
+
+# initialize overall return code
+RC=$RC_OK
+
+# --- cleanup to prepare
+# delete test collection & image & temp data
+$RASQL -q "drop collection $TESTCOLL_MONO" --user $USER --passwd $PASSWD
+$RASQL -q "drop collection $TESTCOLL_GRAY" --user $USER --passwd $PASSWD
+$RASQL -q "drop collection $TESTCOLL_COLOR" --user $USER --passwd $PASSWD
+
+# create test collections
+# - mono
+$RASQL -q "create collection $TESTCOLL_MONO BoolSet" --user $USER --passwd $PASSWD || raiseError
+# - gray
+$RASQL -q "create collection $TESTCOLL_GRAY GreySet" --user $USER --passwd $PASSWD || raiseError
+# - color
+$RASQL -q "create collection $TESTCOLL_COLOR RGBSet" --user $USER --passwd $PASSWD || raiseError
+
+# create test objects
+# - mono
+$RASQL -q "insert into $TESTCOLL_MONO values marray x in [0:3,0:3] values (x[0]+x[1]) = 1" --user $USER --passwd $PASSWD || raiseError
+# - gray
+$RASQL -q "insert into $TESTCOLL_GRAY values marray x in [0:3,0:3] values (char) (x[0]*x[1])" --user $USER --passwd $PASSWD || raiseError
+# - color
+$RASQL -q "insert into $TESTCOLL_COLOR values marray x in [0:3,0:3] values ((char)(x[0]*x[1]))*{1c,1c,1c}" --user $USER --passwd $PASSWD || raiseError
+
+# --- tests
+
+echo "$PROG: test good cases pf transp / non-transp, bg colors"
+echo "$PROG: --- set bg to transparent"
+echo "$PROG: --- --- mono"
+echo "$PROG: --- --- --- dec"
+$RASQL -q "select png(a,\"tRNS=0)\" ) from $TESTCOLL_MONO as a" --out file --outfile $TMPDIR/png-mono-trns_1 || raiseError
+if [ `identify -verbose $TMPDIR/png-mono-trns_1.png | grep Opacity | grep 0 | wc -l` -eq 0 ]
+then
+ echo "Error: transparency not set in PNG file $TMPDIR/pngmono-trns_1.png -- $RCTEXT_ERROR"
+ raiseError
+fi
+if [ ! `cmp -s $OLDDIR/png-mono-trns_1.png $TMPDIR/png-mono-trns_1.png` ]
+then
+ echo "Error: PNG file contents in file $TMPDIR/pngmono-trns_1.png does not match regression source -- $RCTEXT_ERROR"
+ raiseError
+fi
+
+# ==== complete down here:
+$RASQL -q "select png(a,\"tRNS=1)\" ) from $TESTCOLL_MONO as a" --out file --outfile $TMPDIR/png-mono-trns_2 || raiseError
+
+echo "$PROG: --- --- gray"
+echo "$PROG: --- --- --- dec"
+$RASQL -q "select png(a,\"tRNS=0)\" ) from $TESTCOLL_GRAY as a" --out file --outfile $TMPDIR/png-gray-trns_1 || raiseError
+$RASQL -q "select png(a,\"tRNS=2)\" ) from $TESTCOLL_GRAY as a" --out file --outfile $TMPDIR/png-gray-trns_2 || raiseError
+$RASQL -q "select png(a,\"tRNS=255)\" ) from $TESTCOLL_GRAY as a" --out file --outfile $TMPDIR/png-gray-trns_3 || raiseError
+echo "$PROG: --- --- --- oct"
+$RASQL -q "select png(a,\"tRNS=00)\" ) from $TESTCOLL_GRAY as a" --out file --outfile $TMPDIR/png-gray-trns_4 || raiseError
+$RASQL -q "select png(a,\"tRNS=02)\" ) from $TESTCOLL_GRAY as a" --out file --outfile $TMPDIR/png-gray-trns_5 || raiseError
+$RASQL -q "select png(a,\"tRNS=07777)\" ) from $TESTCOLL_GRAY as a" --out file --outfile $TMPDIR/png-gray-trns_6 || raiseError
+echo "$PROG: --- --- --- hex"
+$RASQL -q "select png(a,\"tRNS=0x0)\" ) from $TESTCOLL_GRAY as a" --out file --outfile $TMPDIR/png-gray-trns_7 || raiseError
+$RASQL -q "select png(a,\"tRNS=0x2)\" ) from $TESTCOLL_GRAY as a" --out file --outfile $TMPDIR/png-gray-trns_8 || raiseError
+$RASQL -q "select png(a,\"tRNS=0xff)\" ) from $TESTCOLL_GRAY as a" --out file --outfile $TMPDIR/png-gray-trns_9 || raiseError
+
+echo "$PROG: --- --- color"
+echo "$PROG: --- --- --- dec"
+$RASQL -q "select png(a,\"tRNS=(1;2;3)\" ) from $TESTCOLL_COLOR as a" --out file --outfile $TMPDIR/png-color-trns_1 || raiseError
+echo "$PROG: --- --- --- hex"
+$RASQL -q "select png(a,\"tRNS=(0x77;0xd0;0xf8)\" ) from rgb as a" --out file || raiseError
+echo "$PROG: --- --- --- mixed"
+$RASQL -q "select png(a,\"tRNS=(1;02;0x3)\" ) from $TESTCOLL_COLOR as a" --out file --outfile $TMPDIR/png-color-trns_10 || raiseError
+
+
+echo "$PROG: test bad cases: syntax errors, overflow in bg colors"
+
+echo "$PROG: --- tRNS tag wrong"
+if [ `$RASQL -q "select png(a,\"XXX=(1;2;3)\" ) from $TESTCOLL_COLOR as a" 2>&1 | grep "Execution error 381" | wc -l` -ne 1 ]
+then
+ echo "Error: cannot sense proper error message -- $RCTEXT_ERROR"
+ raiseError
+fi
+
+echo "$PROG: --- no number, gray"
+if [ `$RASQL -q "select png(a,\"tRNS=zzz\" ) from $TESTCOLL_GRAY as a" 2>&1 | grep "Execution error 381" | wc -l` -ne 1 ]
+then
+ echo "Error: cannot sense proper error message -- $RCTEXT_ERROR"
+ raiseError
+fi
+
+echo "$PROG: --- no number, color"
+if [ `$RASQL -q "select png(a,\"tRNS=(q;w;s)\" ) from $TESTCOLL_GRAY as a" 2>&1 | grep "Execution error 381" | wc -l` -ne 1 ]
+then
+ echo "Error: cannot sense proper error message -- $RCTEXT_ERROR"
+ raiseError
+fi
+
+echo "$PROG: --- color/gray mismatch"
+if [ `$RASQL -q "select png(a,\"tRNS=12\" ) from $TESTCOLL_COLOR as a" 2>&1 | grep "Execution error 381" | wc -l` -ne 1 ]
+then
+ echo "Error: cannot sense proper error message -- $RCTEXT_ERROR"
+ raiseError
+fi
+
+if [ `$RASQL -q "select png(a,\"tRNS=(1;2;3)\" ) from $TESTCOLL_GRAY as a" 2>&1 | grep "Execution error 381" | wc -l` -ne 1 ]
+then
+ echo "Error: cannot sense proper error message -- $RCTEXT_ERROR"
+ raiseError
+fi
+
+echo "$PROG: --- paren error (not recognized currently)"
+if [ `$RASQL -q "select png(a,\"tRNS=12;13;14)\" ) from $TESTCOLL_GRAY as a" 2>&1 | grep "Execution error 381" | wc -l` -ne 1 ]
+then
+ echo "Error: cannot sense proper error message -- $RCTEXT_ERROR"
+ raiseError
+fi
+
+echo "$PROG: --- number overflow"
+if [ `$RASQL -q "select png(a,\"tRNS=1000000000;2000000000;30000000000000)\" ) from $TESTCOLL_COLOR as a" 2>&1 | grep "Execution error 381" | wc -l` -ne 1 ]
+then
+ echo "Error: cannot sense proper error message -- $RCTEXT_ERROR"
+ raiseError
+fi
+
+
+# compare files against old ones
+for i in `(cd $TMPDIR; ls *.png)`
+do
+ if [ `cmp -s $OLDDIR/$i $TMPDIR/$i` ]
+ then
+ echo "Error: regression discrepancy between files $OLDDIR/$i and $TMPDIR/$i -- $RCTEXT_ERROR"
+ fi
+done
+
+# --- cleanup and summarise
+# delete test collection & image & temp data
+$RASQL -q "drop collection $TESTCOLL_MONO" --user $USER --passwd $PASSWD || raiseError
+$RASQL -q "drop collection $TESTCOLL_GRAY" --user $USER --passwd $PASSWD || raiseError
+$RASQL -q "drop collection $TESTCOLL_COLOR" --user $USER --passwd $PASSWD || raiseError
+
+if [ $RC -eq $RC_OK ]
+then
+ rm -rf $TMPDIR
+ RCTEXT=$RCTEXT_OK
+else
+ RCTEXT=$RCTEXT_ERROR
+fi
+
+echo $PROG: done, result is $RCTEXT.
+exit $RC
diff --git a/systemtest/scripts/test_ql-png-options.test/png-color-trns_1.png b/systemtest/scripts/test_ql-png-options.test/png-color-trns_1.png
new file mode 100644
index 0000000..adf7769
--- /dev/null
+++ b/systemtest/scripts/test_ql-png-options.test/png-color-trns_1.png
Binary files differ
diff --git a/systemtest/scripts/test_ql-png-options.test/png-color-trns_10.png b/systemtest/scripts/test_ql-png-options.test/png-color-trns_10.png
new file mode 100644
index 0000000..adf7769
--- /dev/null
+++ b/systemtest/scripts/test_ql-png-options.test/png-color-trns_10.png
Binary files differ
diff --git a/systemtest/scripts/test_ql-png-options.test/png-gray-trns_1.png b/systemtest/scripts/test_ql-png-options.test/png-gray-trns_1.png
new file mode 100644
index 0000000..70a5bd6
--- /dev/null
+++ b/systemtest/scripts/test_ql-png-options.test/png-gray-trns_1.png
Binary files differ
diff --git a/systemtest/scripts/test_ql-png-options.test/png-gray-trns_2.png b/systemtest/scripts/test_ql-png-options.test/png-gray-trns_2.png
new file mode 100644
index 0000000..036b6ec
--- /dev/null
+++ b/systemtest/scripts/test_ql-png-options.test/png-gray-trns_2.png
Binary files differ
diff --git a/systemtest/scripts/test_ql-png-options.test/png-gray-trns_3.png b/systemtest/scripts/test_ql-png-options.test/png-gray-trns_3.png
new file mode 100644
index 0000000..3b57c56
--- /dev/null
+++ b/systemtest/scripts/test_ql-png-options.test/png-gray-trns_3.png
Binary files differ
diff --git a/systemtest/scripts/test_ql-png-options.test/png-gray-trns_4.png b/systemtest/scripts/test_ql-png-options.test/png-gray-trns_4.png
new file mode 100644
index 0000000..70a5bd6
--- /dev/null
+++ b/systemtest/scripts/test_ql-png-options.test/png-gray-trns_4.png
Binary files differ
diff --git a/systemtest/scripts/test_ql-png-options.test/png-gray-trns_5.png b/systemtest/scripts/test_ql-png-options.test/png-gray-trns_5.png
new file mode 100644
index 0000000..036b6ec
--- /dev/null
+++ b/systemtest/scripts/test_ql-png-options.test/png-gray-trns_5.png
Binary files differ
diff --git a/systemtest/scripts/test_ql-png-options.test/png-gray-trns_6.png b/systemtest/scripts/test_ql-png-options.test/png-gray-trns_6.png
new file mode 100644
index 0000000..3b57c56
--- /dev/null
+++ b/systemtest/scripts/test_ql-png-options.test/png-gray-trns_6.png
Binary files differ
diff --git a/systemtest/scripts/test_ql-png-options.test/png-gray-trns_7.png b/systemtest/scripts/test_ql-png-options.test/png-gray-trns_7.png
new file mode 100644
index 0000000..70a5bd6
--- /dev/null
+++ b/systemtest/scripts/test_ql-png-options.test/png-gray-trns_7.png
Binary files differ
diff --git a/systemtest/scripts/test_ql-png-options.test/png-gray-trns_8.png b/systemtest/scripts/test_ql-png-options.test/png-gray-trns_8.png
new file mode 100644
index 0000000..036b6ec
--- /dev/null
+++ b/systemtest/scripts/test_ql-png-options.test/png-gray-trns_8.png
Binary files differ
diff --git a/systemtest/scripts/test_ql-png-options.test/png-gray-trns_9.png b/systemtest/scripts/test_ql-png-options.test/png-gray-trns_9.png
new file mode 100644
index 0000000..3b57c56
--- /dev/null
+++ b/systemtest/scripts/test_ql-png-options.test/png-gray-trns_9.png
Binary files differ
diff --git a/systemtest/scripts/test_ql-png-options.test/png-mono-trns_1.png b/systemtest/scripts/test_ql-png-options.test/png-mono-trns_1.png
new file mode 100644
index 0000000..e6c26c9
--- /dev/null
+++ b/systemtest/scripts/test_ql-png-options.test/png-mono-trns_1.png
Binary files differ
diff --git a/systemtest/scripts/test_ql-png-options.test/png-mono-trns_2.png b/systemtest/scripts/test_ql-png-options.test/png-mono-trns_2.png
new file mode 100644
index 0000000..583edee
--- /dev/null
+++ b/systemtest/scripts/test_ql-png-options.test/png-mono-trns_2.png
Binary files differ
diff --git a/systemtest/scripts/test_user.sh b/systemtest/scripts/test_user.sh
new file mode 100644
index 0000000..d6a4e7e
--- /dev/null
+++ b/systemtest/scripts/test_user.sh
@@ -0,0 +1,157 @@
+#!/bin/ksh
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+# test_user - test rasdaman server authentication
+#
+# SYNOPSIS:
+# test_user.sh
+#
+# DESCRIPTION
+# Performs rasql test queries to check whether authentication is observed.
+#
+# RESPONDING TO INCIDENT
+# -none-
+#
+# PROCEDURE
+# Perform rasql calls performing different operations types requiring
+# different authentication. check whether operations are recejcted/accepted
+# properly.
+#
+# PRECONDITIONS
+# - rasql utility available
+# - rasdaman up and running, with database having user/password as defined below
+#
+# RETURN CODES
+ RC_OK=0 # everything went fine
+ RC_ERROR=1 # something went wrong
+#
+# CHANGE HISTORY
+# 2006-jan-02 P.Baumann created
+#
+# RESTRICTIONS
+# -/-
+#
+
+
+# --- CONSTANTS -----------------------------------------------------
+
+RCTEXT_OK="OK"
+RCTEXT_ERROR="NOT_OK"
+
+ERROR=ERROR
+INDENT="+++"
+
+# name of script
+PROG=`basename $0`
+PROGBASE=`basename $0 .sh`
+
+# log file output
+LOG=$PROGBASE.log
+
+# reference log file
+REFLOG=$LOG.reference
+# save old log here if it exists
+SAVELOG=$LOG.save
+
+# --- TEST SETTINGS -------------------------------------------------
+
+# r/o login
+USER_RO=rasguest
+PASSWD_RO=rasguest
+
+# r/w login
+USER_RW=rasadmin
+PASSWD_RW=rasadmin
+
+# nonex login
+USER_NONEX=nonex
+PASSWD_NONEX=nonex
+
+# test collection
+TESTCOLL=AuthentTestCollection
+TESTCOLL_TYPE=GreySet
+
+# --- ACTION --------------------------------------------------------
+
+# save old log if present
+if [ -f $LOG ]
+then
+ echo found old log file, shifting it to $SAVELOG
+ mv $LOG $SAVELOG
+fi
+
+echo $PROG: testing rasdaman authentication at `date` | tee $LOG
+
+# good cases
+echo $INDENT good cases | tee -a $LOG
+echo $INDENT $INDENT write
+( rasql --quiet -q "create collection $TESTCOLL $TESTCOLL_TYPE" --user $USER_RW --passwd $PASSWD_RW \
+ || (export RC=$?; echo Fatal $ERROR, exit code $RC) ) | tee -a $LOG
+( rasql --quiet -q "insert into $TESTCOLL values marray x in [1:10,1:10] values (char) x[0]" --user $USER_RW --passwd $PASSWD_RW \
+ || (export RC=$?; echo Fatal $ERROR, exit code $RC) ) | tee -a $LOG
+( rasql --quiet -q "update $TESTCOLL as m set m[1:1,1:1] assign marray x in [1:1,1:1] values 42c" --user $USER_RW --passwd $PASSWD_RW \
+ || (export RC=$?; echo Fatal $ERROR, exit code $RC) ) | tee -a $LOG
+echo $INDENT $INDENT read
+( rasql --quiet -q "select a[1,1] from $TESTCOLL as a" --user $USER_RW --passwd $PASSWD_RW \
+ || (export RC=$?; echo Fatal $ERROR, exit code $RC) ) | tee -a $LOG
+( rasql --quiet -q "select a[1,1] from $TESTCOLL as a" --user $USER_RO --passwd $PASSWD_RO \
+ || (export RC=$?; echo Fatal $ERROR, exit code $RC) ) | tee -a $LOG
+echo $INDENT $INDENT "write (2)"
+# not yet supported by server:
+# ( rasql --quiet -q "delete from $TESTCOLL" --user $USER_RW --passwd $PASSWD_RW \
+( rasql --quiet -q "delete from $TESTCOLL where true" --user $USER_RW --passwd $PASSWD_RW \
+ || (export RC=$?; echo Fatal $ERROR, exit code $RC) ) | tee -a $LOG
+( rasql --quiet -q "drop collection $TESTCOLL" --user $USER_RW --passwd $PASSWD_RW \
+ || (export RC=$?; echo Fatal $ERROR, exit code $RC) ) | tee -a $LOG
+echo $INDENT $INDENT set up test env for subsequent cases
+( rasql --quiet -q "create collection $TESTCOLL $TESTCOLL_TYPE" --user $USER_RW --passwd $PASSWD_RW \
+ || (export RC=$?; echo Fatal $ERROR, exit code $RC) ) | tee -a $LOG
+( rasql --quiet -q "insert into $TESTCOLL values marray x in [1:10,1:10] values (char) x[0]" --user $USER_RW --passwd $PASSWD_RW \
+ || (export RC=$?; echo Fatal $ERROR, exit code $RC) ) | tee -a $LOG
+echo $INDENT good cases done. | tee -a $LOG
+
+# bad cases
+echo $INDENT bad cases | tee -a $LOG
+echo $INDENT $INDENT nonex login
+( rasql --quiet -q "select a[1,1] from $TESTCOLL as a" --user $USER_NONEX --passwd $PASSWD_NONEX \
+ || (export RC=$?; echo Recognized bad case, exit code $RC) ) | tee -a $LOG
+echo $INDENT $INDENT write op with r/o login
+( rasql --quiet -q "update $TESTCOLL as m set m[1:1,1:1] assign marray x in [1:1,1:1] values 42c" --user $USER_RO --passwd $PASSWD_RO \
+ || (export RC=$?; echo Recognized bad case, exit code $RC) ) | tee -a $LOG
+( rasql --quiet -q "insert into $TESTCOLL values marray x in [1:10,1:10] values (char) x[0]" --user $USER_RO --passwd $PASSWD_RO \
+ || (export RC=$?; echo Recognized bad case, exit code $RC) ) | tee -a $LOG
+( rasql --quiet -q "delete from $TESTCOLL where true" --user $USER_RO --passwd $PASSWD_RO \
+ || (export RC=$?; echo Recognized bad case, exit code $RC) ) | tee -a $LOG
+echo $INDENT $INDENT wrong passwd
+( rasql --quiet -q "select a[1,1] from $TESTCOLL as a" --user $USER_RO --passwd $PASSWD_NONEX \
+ || (export RC=$?; echo Recognized bad case, exit code $RC) ) | tee -a $LOG
+( rasql --quiet -q "update $TESTCOLL as m set m[1:1,1:1] assign marray x in [1:1,1:1] values 42c" --user $USER_RW --passwd $PASSWD_RO \
+ || (export RC=$?; echo Recognized bad case, exit code $RC) ) | tee -a $LOG
+echo $INDENT bad cases done. | tee -a $LOG
+
+echo $INDENT cleanup:
+( rasql --quiet -q "drop collection $TESTCOLL" --user $USER_RW --passwd $PASSWD_RW \
+ || (export RC=$?; echo Fatal $ERROR, exit code $RC) ) | tee -a $LOG
+
+echo $PROG: done at `date`.
+exit $RC
+
diff --git a/systemtest/scripts/testoid.sh b/systemtest/scripts/testoid.sh
new file mode 100644
index 0000000..b8cdbb4
--- /dev/null
+++ b/systemtest/scripts/testoid.sh
@@ -0,0 +1,114 @@
+#!/bin/ksh
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+if [[ $1 = "" || $2 = "" ]]; then
+ echo "usage: testoid.sh <server name> <base name>"
+ return
+fi
+
+SERVER=$1
+BASENAME=$2
+
+# test programs
+insert="$RMANBASE/rasodmg/test/test_insert3 -server $SERVER -base $BASENAME "
+query="$RMANBASE/rasodmg/test/test_query -server $SERVER -base $BASENAME "
+lookup="$RMANBASE/rasodmg/test/test_lookup -server $SERVER -base $BASENAME "
+
+
+testExitStatus()
+{
+ if [[ ( $2 = 0 && $1 = 0 ) || ( $2 != 0 && $1 != 0 ) ]]; then
+ echo "OK"
+ else
+ echo "FAILED"
+ echo "\nProgram output:"
+ cat log
+ echo "\n\n"
+ fi
+}
+
+
+#
+# main
+#
+
+setOId=""
+imageOId=""
+
+echo "-- Testbed start block."
+echo "Delete test set oidSet ... " ;
+echo "10\n" | $insert -setname oidSet > log ;
+testExitStatus $? -1;
+
+echo "Insert test image into oidSet ... " ;
+echo "5\n 0\n 2\n 0\n 10\n 0\n 10\n" | $insert -setname oidSet -testbed > log ;
+testExitStatus $? 0;
+echo "-- Testbed end block."
+
+# get oids
+setOId=`grep set_oid log | sed 's/-- Testbed:.*=//g' `
+imageOId=`grep image_oid log | sed 's/-- Testbed:.*=//g' `
+
+echo "Set OId: " $setOId
+echo "Image OId: " $imageOId
+
+echo "-- Testbed start block."
+echo "Get set by oid ... "
+$lookup -oid $setOId -testbed -nooutput > log;
+testExitStatus $? 0;
+
+echo "Get image by oid ... "
+$lookup -oid $imageOId -testbed -nooutput > log;
+testExitStatus $? 0;
+
+echo "Get set by name ... "
+$lookup -setname oidSet -testbed -nooutput > log;
+testExitStatus $? 0;
+
+echo "Remove image from oidSet ... " ;
+echo "11\n 1\n" | $insert -setname oidSet > log ;
+testExitStatus $? 0;
+
+echo "Try to access image by oid again ... "
+$lookup -oid $imageOId -testbed -nooutput > log;
+testExitStatus $? -1;
+
+echo "Delete test set oidSet ... " ;
+echo "10\n" | $insert -setname oidSet > log ;
+testExitStatus $? 0;
+
+echo "Try to access set by oid again ... "
+$lookup -oid $setOId -testbed -nooutput > log;
+testExitStatus $? -1;
+
+echo "Try to access set by name again ... "
+$lookup -setname oidSet -testbed -nooutput > log;
+testExitStatus $? -1;
+echo "-- Testbed end block."
+
+echo "\nTesting finnished."
+
+
+
+
+
+
diff --git a/systemtest/testOutputGen.awk b/systemtest/testOutputGen.awk
new file mode 100644
index 0000000..f29b104
--- /dev/null
+++ b/systemtest/testOutputGen.awk
@@ -0,0 +1,19 @@
+BEGIN { testSection = 0; }
+# ignore empty lines
+/^$/ { next; }
+
+# ignore oid lines
+/^ *Oid\.*:*/ { next; }
+
+# turn on flag
+/^-- Testbed start block.*/ { testSection = 1; }
+
+# turn off flag
+/^-- Testbed end block.*/ { testSection = 0; }
+
+# print lines in test section
+testSection==1 { print $0; next; }
+
+# print lines starting with -- Testbed
+/^-- Testbed .*/ { print $0; }
+
diff --git a/systemtest/testcenter.sh b/systemtest/testcenter.sh
new file mode 100644
index 0000000..71ec49e
--- /dev/null
+++ b/systemtest/testcenter.sh
@@ -0,0 +1,710 @@
+#!/bin/ksh
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+######################### testcenter.sh header ###################
+#
+# testcenter.sh FOR:
+# Release of RASDAMAN
+#
+# COMMENTS:
+#
+#
+##################################################################
+
+TESTER=$USER
+CLIENT=$HOSTNAME
+SERVER=$HOSTNAME
+BASENAME=RASBASE
+USERNAME=rasguest
+USERPASSWD=rasguest
+TRANSFER=Array
+TRANSFERPARAMS=""
+STORAGE=Array
+STORAGEPARAMS=""
+TILING=""
+TILINGPARAMS=""
+LOGFILE=testcenter.log
+TESTINTERACTIVE="off"
+DIFFINTERACTIVE="on"
+UPDATEINTERACTIVE="on"
+RESETDB="on"
+SCRIPTS="off"
+QUERIES="on"
+TESTDIR="testdata"
+returnValue="EXECUTION OK"
+DEBUG="off"
+
+if (test -n "$1"); then
+ if (test -d $1 -o -f $1); then
+ TESTDIR=$1
+ else
+ SERVER=$1
+ if (test -n "$2"); then
+ TESTDIR=$2
+ fi
+ fi
+fi
+
+showOptions()
+{
+ echo "===================================================================="
+ echo " TEST CENTER OPTIONS:"
+ echo "===================================================================="
+ echo " Date...........................: " `date`
+ echo " (T)ester.......................: " $TESTER
+ echo " (C)lient name..................: " $CLIENT
+ echo " (S)erver name..................: " $SERVER
+ echo " (B)ase name....................: " $BASENAME
+ echo " (U)ser name....................: " $USERNAME
+ echo " User (p)assword................: " $USERPASSWD
+ echo " T(r)ansfer format..............: " $TRANSFER
+ echo " Tra(n)sfer format params.......: " $TRANSFERPARAMS
+ echo " Stora(g)e format...............: " $STORAGE
+ echo " Stor(a)ge format params........: " $STORAGEPARAMS
+ echo " Tiling sc(h)eme................: " $TILING
+ echo " Tiling sche(m)e params.........: " $TILINGPARAMS
+ echo " (L)og file.....................: " $LOGFILE
+ echo " (Q)uery dir....................: " $TESTDIR
+ echo ""
+ echo " Tests (i)nteractive............: " $TESTINTERACTIVE
+ echo " Show dif(f) interactive........: " $DIFFINTERACTIVE
+ echo " Update testbe(d) interactive...: " $UPDATEINTERACTIVE
+ echo " R(e)set test database..........: " $RESETDB
+ echo " Debug c(o)mmands...............: " $DEBUG
+ echo ""
+ echo " Phase (1) Test queries.........: " $QUERIES
+ echo " Phase (2) Test scripts.........: " $SCRIPTS
+ echo ""
+}
+
+setParameters()
+{
+ option="*"
+
+ while [[ $option != "" ]]; do
+
+ clear
+ showOptions
+
+ echo " \nEnter option to change setting or <return> to continue! \c"
+ read option
+ echo "\n"
+
+ if [[ $option = t ]]; then
+ echo " Enter new name for tester: \c"
+ read TESTER
+ echo
+ elif [[ $option = c ]]; then
+ echo " Enter new client name: \c"
+ read CLIENT
+ echo
+ elif [[ $option = u ]]; then
+ echo " Enter new user name: \c"
+ read USERNAME
+ echo
+ elif [[ $option = p ]]; then
+ echo " Enter new user password: \c"
+ read USERPASSWD
+ echo
+ elif [[ $option = r ]]; then
+ echo " Enter new transfer format: \c"
+ read TRANSFER
+ echo
+ elif [[ $option = n ]]; then
+ echo " Enter new transfer format params: \c"
+ read TRANSFERPARAMS
+ echo
+ elif [[ $option = g ]]; then
+ echo " Enter new storage format: \c"
+ read STORAGE
+ echo
+ elif [[ $option = a ]]; then
+ echo " Enter new storage format params: \c"
+ read STORAGEPARAMS
+ echo
+ elif [[ $option = h ]]; then
+ echo " Enter new tiling scheme: \c"
+ read TILING
+ echo
+ elif [[ $option = m ]]; then
+ echo " Enter new tiling scheme params: \c"
+ read TILINGPARAMS
+ echo
+ elif [[ $option = s ]]; then
+ echo " Enter new server name: \c"
+ read SERVER
+ echo
+ elif [[ $option = b ]]; then
+ echo " Enter new base name: \c"
+ read BASENAME
+ echo
+ elif [[ $option = l ]]; then
+ echo " Enter new name for the log file: \c"
+ read LOGFILE
+ echo
+ elif [[ $option = q ]]; then
+ echo " Enter new name for the query data directory: \c"
+ read TESTDIR
+ echo
+ elif [[ $option = i ]]; then
+ if [[ $TESTINTERACTIVE = "off" ]]; then
+ TESTINTERACTIVE="on"
+ else
+ TESTINTERACTIVE="off"
+ fi
+ elif [[ $option = f ]]; then
+ if [[ $DIFFINTERACTIVE = "off" ]]; then
+ DIFFINTERACTIVE="on"
+ else
+ DIFFINTERACTIVE="off"
+ fi
+ elif [[ $option = d ]]; then
+ if [[ $UPDATEINTERACTIVE = "off" ]]; then
+ UPDATEINTERACTIVE="on"
+ else
+ UPDATEINTERACTIVE="off"
+ fi
+ elif [[ $option = o ]]; then
+ if [[ $DEBUG = "off" ]]; then
+ DEBUG="on"
+ else
+ DEBUG="off"
+ fi
+ elif [[ $option = e ]]; then
+ if [[ $RESETDB = "off" ]]; then
+ RESETDB="on"
+ else
+ RESETDB="off"
+ fi
+ elif [[ $option = 1 ]]; then
+ if [[ $QUERIES = "off" ]]; then
+ QUERIES="on"
+ else
+ QUERIES="off"
+ fi
+ elif [[ $option = 2 ]]; then
+ if [[ $SCRIPTS = "off" ]]; then
+ SCRIPTS="on"
+ else
+ SCRIPTS="off"
+ fi
+ fi
+
+ done
+}
+
+
+
+testQuery()
+{
+ testFile=$1
+
+
+ echo $testCnt ". Test query: " $testFile "\c"
+
+ if [[ $DEBUG = "on" ]]; then
+ echo "shell command:"
+ echo $query -file $testFile -testbed
+ else
+
+ YesNo="y"
+ if [[ $TESTINTERACTIVE = "on" ]]; then
+ echo " Test it (y/n) ? \c"
+ read YesNo
+ fi
+
+ if [[ $YesNo = "y" ]]; then
+ $query -file $testFile -testbed > testbedOutput
+ checkTestImage $testFile;
+ fi
+ fi
+}
+
+
+
+testScript()
+{
+ testFile=$1
+
+ echo $testCnt ". Test script: " $testFile "\c"
+
+ if [[ $DEBUG = "on" ]]; then
+ echo "shell command:"
+ echo $testFile $SERVER $BASENAME > testbedOutput
+ else
+ YesNo="y"
+ if [[ $TESTINTERACTIVE = "on" ]]; then
+ echo " Test it (y/n) ? \c"
+ read YesNo
+ fi
+
+ if [[ $YesNo = "y" ]]; then
+ $testFile $SERVER $BASENAME > testbedOutput
+ checkTestImage $testFile;
+ fi
+ fi
+}
+
+
+
+checkTestImage()
+{
+ returnValue="EXECUTION OK"
+
+ # create info file
+ gawk -f testOutputGen.awk testbedOutput > testbedOutputInfo
+
+ # check for verification file
+ verificationFile=$testFile".out"
+
+ if [[ ! -a $verificationFile ]]; then
+ echo FAILED
+ echo " ERROR: verification file $verificationFile does not exist"
+
+ YesNo="n"
+ if [[ $DIFFINTERACTIVE = "on" ]]; then
+ echo " Do you want to see the output (y/n) ? \c"
+ read YesNo__
+ fi
+
+ if [[ $YesNo = "y" ]]; then
+ echo "\n\nI. TEST FILE"
+ cat $testFile
+ echo "\n\nII. OUTPUT"
+ cat testbedOutputInfo
+ echo "\n\n"
+ fi
+
+ YesNo="n"
+ if [[ $UPDATEINTERACTIVE = "on" ]]; then
+ echo " Do you want to create a verification file (y/n) ? \c"
+ read YesNo
+ fi
+ if [[ $YesNo = "y" ]]; then
+ cp testbedOutputInfo $verificationFile
+ echo " CREATED\n"
+ returnValue=$returnValue" VERIFICATION FILE NOT FOUND, CREATED AS NEW"
+ cvs add -m "testcenter verificationf file for query $testFile" $verificationFile
+ cvs commit -m "testcenter verification file created as new by TESTER=$TESTER" $verificationFile
+ else
+ cp testbedOutputInfo $testFile".tmp"
+ echo " NOT CREATED\n"
+ returnValue=$returnValue" VERIFICATION FILE NOT FOUND, NOT CREATED"
+ fi
+
+ else
+
+
+ diff -c testbedOutputInfo $verificationFile 2>&1 1> /tmp/diff.out
+
+ if [[ $? != 0 ]]; then
+ echo "FAILED"
+ returnValue="EXECUTION FAILED"
+
+ YesNo="n"
+ if [[ $DIFFINTERACTIVE = "on" ]]; then
+ echo " Do you want to see the diff output (y/n) ? \c"
+ read YesNo
+ fi
+
+
+ if [[ $YesNo = "y" ]]; then
+ echo "\n\nI. TEST FILE"
+ cat $testFile
+ echo "\n\n DIFF OUTPUT:"
+ cat /tmp/diff.out
+ echo "\n\n"
+ fi
+
+ YesNo="n"
+ if [[ $UPDATEINTERACTIVE = "on" ]]; then
+ echo " Do you want to update the verification file (y/n) ? \c"
+ read YesNo
+ fi
+ if [[ $YesNo = "y" ]]; then
+ if(cvs status $verificationFile); then
+ cvs edit $verificationFile
+ cp testbedOutputInfo $verificationFile
+ echo " UPDATED\n"
+ cvs commit -m "testcenter verification file updated by TESTER=$TESTER" $verificationFile
+ returnValue=$returnValue" VERIFICATION FILE UPDATED"
+ else
+ cp testbedOutputInfo $verificationFile
+ echo " CREATED\n"
+ cvs add -m "testcenter verificationf file for query $testFile" $verificationFile
+ cvs commit -m "testcenter verification file created as new by TESTER=$TESTER" $verificationFile
+ returnValue=$returnValue" VERIFICATION FILE NOT IN REPOSITORY, CHECKED AS NEW"
+ fi
+ else
+ cp testbedOutputInfo $testFile".tmp"
+ fi
+
+ else
+ echo "OK"
+ fi
+
+ fi
+
+ rm testbedOutput testbedOutputInfo /tmp/diff.out
+}
+
+checkBinaries()
+{
+ # test programs
+ insert="$RMANBASE/bin/test_insert3"
+ query="$RMANBASE/bin/test_query"
+ insertppm="$RMANBASE/insertutils/insertppm"
+ images="$RMANBASE/systemtest/images"
+
+ if [[ ! -a $insertppm ]]; then
+ echo "\nTest program $insertppm not found"
+ echo "Please build the program and try again."
+ exit 1
+ fi
+
+ if [[ ! -a $insert ]]; then
+ echo "\nTest program $insert not found"
+ echo "Please build the program and try again."
+ exit 1
+ fi
+
+ if [[ ! -a $query ]]; then
+ echo "\nTest program $query not found"
+ echo "Please build the program and try again."
+ exit 1
+ fi
+}
+
+setBinariesParams()
+{
+# server and database required
+if(test -z "$SERVER"); then
+ echo "Server name is not set!"
+ exit 1
+fi
+if(test -z "$BASENAME"); then
+ echo "Base name is not set!"
+ exit 1
+fi
+
+if(test -z "$USERNAME"); then
+ echo "User name is not set!"
+ exit 1
+fi
+
+if(test -z "$USERPASSWD"); then
+ echo "User password is not set!"
+ exit 1
+fi
+
+#test_insert3 params
+insert="$insert -server $SERVER -base $BASENAME -user $USERNAME -passwd $USERPASSWD"
+if(test -n "$TRANSFER"); then
+ insert="$insert -transferformat $TRANSFER"
+fi
+if(test -n "$TRANSFERPARAMS"); then
+ insert="$insert -transferformatparams $TRANSFERPARAMS"
+fi
+if(test -n "$STORAGE"); then
+ insert="$insert -storageformat $STORAGE"
+fi
+if(test -n "$STORAGEPARAMS"); then
+ insert="$insert -storageformatparams $STORAGEPARAMS"
+fi
+if(test -n "$TILING"); then
+ insert="$insert -tiling $TILING"
+fi
+if(test -n "$TILINGPARAMS"); then
+ insert="$insert -tilingparams $TILINGPARAMS"
+fi
+
+#insertppm params
+insertppm="$insertppm -server $SERVER -base $BASENAME -user $USERNAME -passwd $USERPASSWD"
+if(test -n "$TRANSFER"); then
+insertppm="$insertppm -transferformat $TRANSFER"
+fi
+if(test -n "$TRANSFERPARAMS"); then
+insertppm="$insertppm -transferformatparams $TRANSFERPARAMS"
+fi
+if(test -n "$STORAGE"); then
+insertppm="$insertppm -storageformat $STORAGE"
+fi
+if(test -n "$STORAGEPARAMS"); then
+insertppm="$insertppm -storageformatparams $STORAGEPARAMS"
+fi
+
+#test_query params
+query="$query -server $SERVER -base $BASENAME -user $USERNAME -passwd $USERPASSWD"
+if(test -n "$TRANSFER"); then
+ query="$query -transferformat $TRANSFER"
+fi
+if(test -n "$TRANSFERPARAMS"); then
+ query="$query -transferformatparams $TRANSFERPARAMS"
+fi
+if(test -n "$STORAGE"); then
+ query="$query -storageformat $STORAGE"
+fi
+if(test -n "$STORAGEPARAMS"); then
+ query="$query -storageformatparams $STORAGEPARAMS"
+fi
+if(test -n "$TILING"); then
+ query="$query -tiling $TILING"
+fi
+if(test -n "$TILINGPARAMS"); then
+ query="$query -tilingparams $TILINGPARAMS"
+fi
+}
+
+resetLog()
+{
+YesNo="n"
+if [[ $UPDATEINTERACTIVE = "on" ]]; then
+ if [[ -a $LOGFILE ]]; then
+ echo "Delete log file $LOGFILE (y/n) ? \c"
+ read YesNo
+ echo "\n"
+ fi
+fi
+if [[ $YesNo = y ]]; then
+ rm -f $LOGFILE
+fi
+}
+
+resetDB()
+{
+if [[ $RESETDB = "on" ]]; then
+ echo "Reset demo data in db (y/n) ? \c"
+ read YesNo
+ echo "\n"
+
+ if [[ $YesNo = y ]]; then
+
+ # delete collections
+ echo "Delete test collections of $BASENAME...\c" ;
+ echo "=============================================================================" >> $LOGFILE
+ echo "Delete test collections of $BASENAME" >> $LOGFILE ;
+ echo "=============================================================================\n" >> $LOGFILE
+
+ if [[ $DEBUG = "on" ]]; then
+ echo "shell command:"
+ echo "10\n" $insert -setname ImgCharA
+ echo "10\n" $insert -setname ImgCharB
+ echo "10\n" $insert -setname ImgCharC
+ echo "10\n" $insert -setname ImgCharD
+ echo "10\n" $insert -setname ImgCharMask
+ echo "10\n" $insert -setname OvlCharA
+ echo "10\n" $insert -setname OvlCharB
+ echo "10\n" $insert -setname OvlCharC
+
+ echo "10\n" $insert -setname ImgRGBA
+ echo "10\n" $insert -setname ImgULongC
+ echo "10\n" $insert -setname OlapCharA
+ echo "10\n" $insert -setname StringCharA
+ echo "10\n" $insert -setname CubeCharA
+ echo "10\n" $insert -setname OvlRGBA
+ echo "10\n" $insert -setname OvlRGBB
+ echo "10\n" $insert -setname OvlRGBC
+ else
+ echo "10\n" | $insert -setname ImgCharA >> $LOGFILE ;
+ echo "10\n" | $insert -setname ImgCharB >> $LOGFILE ;
+ echo "10\n" | $insert -setname ImgCharC >> $LOGFILE ;
+ echo "10\n" | $insert -setname ImgCharD >> $LOGFILE ;
+ echo "10\n" | $insert -setname ImgCharMask >> $LOGFILE ;
+ echo "10\n" | $insert -setname OvlCharA >> $LOGFILE ;
+ echo "10\n" | $insert -setname OvlCharB >> $LOGFILE ;
+ echo "10\n" | $insert -setname OvlCharC >> $LOGFILE ;
+
+ echo "10\n" | $insert -setname ImgRGBA >> $LOGFILE ;
+ echo "10\n" | $insert -setname ImgULongC >> $LOGFILE ;
+ echo "10\n" | $insert -setname OlapCharA >> $LOGFILE ;
+ echo "10\n" | $insert -setname StringCharA >> $LOGFILE ;
+ echo "10\n" | $insert -setname CubeCharA >> $LOGFILE ;
+ echo "10\n" | $insert -setname OvlRGBA >> $LOGFILE ;
+ echo "10\n" | $insert -setname OvlRGBB >> $LOGFILE ;
+ echo "10\n" | $insert -setname OvlRGBC >> $LOGFILE ;
+ fi
+
+
+ echo "OK" ;
+
+ echo "\n\nCreate demo data in db (y/n) ? \c"
+ read YesNo
+ echo "\n"
+
+ if [[ $YesNo = y ]]; then
+ #create collections
+ echo "Insert test collections into $BASENAME...\c" ;
+ echo "=============================================================================" >> $LOGFILE
+ echo "Insert test collections into $BASENAME" >> $LOGFILE ;
+ echo "=============================================================================\n" >> $LOGFILE
+
+ if [[ $DEBUG = "on" ]]; then
+ echo "shell command:"
+ echo "5\n 0\n 2\n 0\n 10\n 0\n 10\n" $insert -setname ImgCharA
+ echo "5\n 1\n 2\n 0\n 10\n 0\n 10\n" $insert -setname ImgCharA
+
+ echo "5\n 10\n 2\n 0\n 10\n 0\n 10\n" $insert -setname ImgCharB
+ echo "5\n 20\n 2\n 0\n 10\n 0\n 10\n" $insert -setname ImgCharB
+
+ echo "5\n 100\n 2\n 0\n 10\n 0\n 10\n" $insert -setname ImgCharC
+ echo "5\n 200\n 2\n 0\n 10\n 0\n 10\n" $insert -setname ImgCharC
+
+ echo "13\n 2\n 0\n 10\n 0\n 10\n" $insert -setname ImgCharD
+
+ echo "5\n 2\n 2\n-2\n 2\n-1\n 1\n" $insert -setname ImgCharMask
+
+ echo "1\n 2\n 0\n 9\n 0\n 9\n" $insert -setname ImgULongC
+
+ echo "6\n 2\n 0\n 10\n 0\n 10\n" $insert -setname ImgRGBA
+ echo "6\n 2\n 0\n 10\n 0\n 10\n" $insert -setname ImgRGBA
+
+ echo "13\n 2\n 0\n 13\n 0\n 1\n" $insert -setname OlapCharA
+
+ echo "13\n 1\n 0\n 99\n " $insert -setname StringCharA -settype GreySet1 -mddtype GreyString
+ echo "5\n 0\n 3\n 0\n 10\n 0\n 10\n 0\n 10\n" $insert -setname CubeCharA -settype GreySet3 -mddtype GreyCube
+
+ echo $insertppm -collection OvlRGBA $images/ovl1.ppm
+ echo $insertppm -collection OvlRGBB $images/ovl2.ppm
+ echo $insertppm -collection OvlRGBC $images/ovl3.ppm
+ echo $insertppm -grey -collection OvlCharA $images/ovl1.ppm
+ echo $insertppm -grey -collection OvlCharB $images/ovl2.ppm
+ echo $insertppm -grey -collection OvlCharC $images/ovl3.ppm
+ else
+ echo "5\n 0\n 2\n 0\n 10\n 0\n 10\n" | $insert -setname ImgCharA >> $LOGFILE ;
+ echo "5\n 1\n 2\n 0\n 10\n 0\n 10\n" | $insert -setname ImgCharA >> $LOGFILE ;
+
+ echo "5\n 10\n 2\n 0\n 10\n 0\n 10\n" | $insert -setname ImgCharB >> $LOGFILE ;
+ echo "5\n 20\n 2\n 0\n 10\n 0\n 10\n" | $insert -setname ImgCharB >> $LOGFILE ;
+
+ echo "5\n 100\n 2\n 0\n 10\n 0\n 10\n" | $insert -setname ImgCharC >> $LOGFILE ;
+ echo "5\n 200\n 2\n 0\n 10\n 0\n 10\n" | $insert -setname ImgCharC >> $LOGFILE ;
+
+ echo "13\n 2\n 0\n 10\n 0\n 10\n" | $insert -setname ImgCharD >> $LOGFILE ;
+
+ echo "5\n 2\n 2\n-2\n 2\n-1\n 1\n" | $insert -setname ImgCharMask >> $LOGFILE;
+
+ echo "1\n 2\n 0\n 9\n 0\n 9\n" | $insert -setname ImgULongC >> $LOGFILE;
+
+ echo "6\n 2\n 0\n 10\n 0\n 10\n" | $insert -setname ImgRGBA >> $LOGFILE ;
+ echo "6\n 2\n 0\n 10\n 0\n 10\n" | $insert -setname ImgRGBA >> $LOGFILE ;
+
+ echo "13\n 2\n 0\n 13\n 0\n 1\n" | $insert -setname OlapCharA >> $LOGFILE ;
+
+ echo "13\n 1\n 0\n 99\n " | $insert -setname StringCharA -settype GreySet1 -mddtype GreyString >> $LOGFILE ;
+ echo "5\n 0\n 3\n 0\n 10\n 0\n 10\n 0\n 10\n" | $insert -setname CubeCharA -settype GreySet3 -mddtype GreyCube >> $LOGFILE ;
+
+ $insertppm -collection OvlRGBA $images/ovl1.ppm >> $LOGFILE
+ $insertppm -collection OvlRGBB $images/ovl2.ppm >> $LOGFILE
+ $insertppm -collection OvlRGBC $images/ovl3.ppm >> $LOGFILE
+ $insertppm -grey -collection OvlCharA $images/ovl1.ppm >> $LOGFILE
+ $insertppm -grey -collection OvlCharB $images/ovl2.ppm >> $LOGFILE
+ $insertppm -grey -collection OvlCharC $images/ovl3.ppm >> $LOGFILE
+ fi
+
+ echo "OK" ;
+ fi
+ fi
+fi
+}
+
+#
+# main
+#
+
+checkBinaries;
+
+setParameters;
+
+setBinariesParams;
+
+resetLog;
+
+showOptions >> $LOGFILE
+
+resetDB;
+
+#
+# test query files
+#
+
+if [[ $QUERIES = "on" ]]; then
+
+ echo "\nPhase 1: Testing Query Files\n"
+ echo "\n=============================================================================" >> $LOGFILE
+ echo "Phase 1: Testing Query Files..." >> $LOGFILE ;
+ echo "=============================================================================\n" >> $LOGFILE
+
+ testCnt=1
+ queryFiles=`find $TESTDIR -name '*.ql' | sort`
+
+ for queryFile in $queryFiles; do
+
+ testQuery $queryFile
+
+ echo "Query " $testCnt $queryFile":" $returnValue >> $LOGFILE
+
+ testCnt=$(($testCnt+1))
+ done
+fi
+
+
+#
+# test scripts
+#
+
+if [[ $SCRIPTS = "on" ]]; then
+ echo "\nPhase 2: Testing Scripts\n"
+ echo "\n=============================================================================" >> $LOGFILE
+ echo "Phase 2: Testing Scripts" >> $LOGFILE
+ echo "=============================================================================\n" >> $LOGFILE
+
+ testCnt=1
+ scriptFiles=`find scripts -name '*.sh' | sort`
+
+ for scriptFile in $scriptFiles; do
+
+ testScript $scriptFile
+
+ echo "Script " $testCnt $scriptFile":" $returnValue >> $LOGFILE
+
+ testCnt=$(($testCnt+1))
+ done
+fi
+
+echo "\nTesting finnished at " `date`
+echo "\n===================================================================" >> $LOGFILE
+echo "Test finnished at " `date` >> $LOGFILE
+echo "===================================================================\n" >> $LOGFILE
+
+
+YesNo="n"
+if [[ $UPDATEINTERACTIVE = "on" ]]; then
+ echo "\nDo you want to check in the log file (y/n) ? \c"
+ read YesNo
+ echo "\n\n"
+fi
+if [[ $YesNo = y ]]; then
+ cvs edit session.log
+ cp $LOGFILE session.log
+ cvs commit -m "updated by testcenter runned by TESTER=$TESTER" session.log
+fi
+exit 0
diff --git a/systemtest/testcenter2.sh b/systemtest/testcenter2.sh
new file mode 100644
index 0000000..44e2d92
--- /dev/null
+++ b/systemtest/testcenter2.sh
@@ -0,0 +1,444 @@
+#!/bin/ksh
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+######################### testcenter.sh header ###################
+#
+# testcenter.sh FOR:
+# Release of RASDAMAN
+#
+# COMMENTS:
+# args needed: serverhost databasehost logdirectory testjava queries scripts checkin conversion compression
+# last six are "on"/"off"-switches.
+#
+##################################################################
+
+TESTER=$USER
+BASENAME=RASBASE
+TIMESTAMP=`date +%d%b%y%H%M%S`
+LOGFILE="$3/$HOSTNAME.$TIMESTAMP.log"
+SEEOUTPUT="off"
+CREATEVFILE="off"
+UPDATEVFILE="off"
+INTERACTIVE="off"
+DEMODATA="on"
+CREATEDATA="on"
+TESTJAVA=$4
+QUERIES=$5
+SCRIPTS=$6
+CHECKINLOG=$7
+CONV=$8
+COMP=$9
+TESTDIR=testdata
+
+echo "$0 $1 $2 $3 $4 $5 $6 $7 $8 $9"
+
+if [[ $1 = "" || $2 = "" ]]; then
+ SERVER=$HOSTNAME
+ CLIENT=$HOSTNAME
+else
+ SERVER=$1
+ CLIENT=$2
+fi
+
+if [[ $7 = "" ]]; then
+ CHECKINLOG="off"
+else
+ CHECKINLOG=$7
+fi
+
+if [[ $6 = "" ]]; then
+ SCRIPTS="off"
+else
+ SCRIPTS=$6
+fi
+
+if [[ $5 = "" ]]; then
+ QUERIES="off"
+else
+ QUERIES=$5
+fi
+
+if [[ $4 = "" ]]; then
+ TESTJAVA="off"
+else
+ TESTJAVA=$4
+fi
+
+
+setParameters()
+{
+ option="*"
+
+ while [[ $option != "" ]]; do
+
+ echo "\n"
+ echo " (T)ester...............: " $TESTER
+ echo " (C)lient name..........: " $CLIENT
+ echo " (S)erver name..........: " $SERVER
+ echo " (B)ase name............: " $BASENAME
+ echo " (L)og file.............: " $LOGFILE
+ echo " (Q)uery dir............: " $TESTDIR
+ echo " (I)nteractive..........: " $INTERACTIVE
+ echo ""
+ echo " Phase (1) Test Queries.: " $QUERIES
+ echo " Phase (2) Test Scripts.: " $SCRIPTS
+
+ echo " \nEnter [tcsblqi12] to change setting or <return> to continue! \c"
+ read option
+ echo "\n"
+
+ if [[ $option = t ]]; then
+ echo " Enter new name for tester: \c"
+ read TESTER
+ echo
+ elif [[ $option = c ]]; then
+ echo " Enter new client name: \c"
+ read CLIENT
+ echo
+ elif [[ $option = s ]]; then
+ echo " Enter new server name: \c"
+ read SERVER
+ echo
+ elif [[ $option = b ]]; then
+ echo " Enter new base name: \c"
+ read BASENAME
+ echo
+ elif [[ $option = l ]]; then
+ echo " Enter new name for the log file: \c"
+ read LOGFILE
+ echo
+ elif [[ $option = q ]]; then
+ echo " Enter new name for the query data directory: \c"
+ read TESTDIR
+ echo
+ elif [[ $option = i ]]; then
+ if [[ $INTERACTIVE = "off" ]]; then
+ INTERACTIVE="on"
+ else
+ INTERACTIVE="off"
+ fi
+ elif [[ $option = 1 ]]; then
+ if [[ $QUERIES = "off" ]]; then
+ QUERIES="on"
+ else
+ QUERIES="off"
+ fi
+ elif [[ $option = 2 ]]; then
+ if [[ $SCRIPTS = "off" ]]; then
+ SCRIPTS="on"
+ else
+ SCRIPTS="off"
+ fi
+ fi
+ done
+}
+
+
+
+testQuery()
+{
+ testFile=$1
+
+ echo $testCnt ". Test query: " $testFile "\c" >> $LOGFILE 2>&1
+
+ YesNo="y"
+ if [[ $INTERACTIVE = "on" ]]; then
+ echo $testCnt ". Test query: " $testFile "\c"
+ echo " Test it (y/n) ? \c"
+ read YesNo
+ fi
+
+ if [[ $YesNo = "y" ]]; then
+ $query $testFile -testbed > testbedOutput
+ checkTestImage $testFile;
+ fi
+}
+
+
+testScript()
+{
+ testFile=$1
+
+ echo $testCnt ". Test script: " $testFile "\c" >> $LOGFILE 2>&1
+
+ YesNo="y"
+ if [[ $INTERACTIVE = "on" ]]; then
+ echo $testCnt ". Test script: " $testFile "\c"
+ echo " Test it (y/n) ? \c"
+ read YesNo
+ fi
+
+ if [[ $YesNo = "y" ]]; then
+ $testFile $SERVER $BASENAME > testbedOutput
+ checkTestImage $testFile;
+ fi
+}
+
+
+checkTestImage()
+{
+ returnValue="EXECUTION OK"
+
+ # create info file
+ gawk -f testOutputGen.awk testbedOutput > testbedOutputInfo
+
+ # check for verification file
+ verificationFile=$testFile".out"
+
+ if [[ ! -a $verificationFile ]]; then
+ echo FAILED >> $LOGFILE 2>&1
+ echo " ERROR: verification file $verificationFile does not exist" >> $LOGFILE 2>&1
+ if [[ $SEEOUTPUT = "on" ]]; then
+ echo "I. TEST FILE" >> $LOGFILE 2>&1
+ cat $testFile >> $LOGFILE 2>&1
+ echo "\n\nII. OUTPUT" >> $LOGFILE 2>&1
+ cat testbedOutputInfo >> $LOGFILE 2>&1
+ echo "\n\n"
+ fi
+ if [[ $CREATEVFILE = "on" ]]; then
+ cp testbedOutputInfo $verificationFile
+ echo " CREATED\n" >> $LOGFILE 2>&1
+ returnValue="VERIFICATION FILE CREATED"
+ else
+ echo " NOT CREATED\n" >> $LOGFILE 2>&1
+ returnValue="VERIFICATION FILE NOT FOUND"
+ fi
+ else
+ diff testbedOutputInfo $verificationFile >> $LOGFILE 2>&1
+ if [[ $? = 1 ]]; then
+ echo "FAILED" >> $LOGFILE 2>&1
+ echo "\nProgram output:" >> $LOGFILE 2>&1
+ cat testbedOutput >> $LOGFILE 2>&1
+ echo "\n\n" >> $LOGFILE 2>&1
+ returnValue="EXECUTION FAILED"
+ if [[ $UPDATEVFILE = "on" ]]; then
+ co -l $verificationFile
+ cp testbedOutputInfo $verificationFile
+ echo " UPDATED\n" >> $LOGFILE 2>&1
+ ci -u -m"testcenter update" $verificationFile
+ returnValue="VERIFICATION FILE UPDATED"
+ fi
+ else
+ echo "OK" >> $LOGFILE 2>&1
+ fi
+ fi
+ rm testbedOutput testbedOutputInfo
+}
+
+
+
+#
+# main
+#
+
+# test programs
+insert="$RMANBASE/bin/test_insert3"
+query="$RMANBASE/bin/test_query"
+insertppm="$RMANBASE/insertutils/insertppm"
+images="$RMANBASE/systemtest/images"
+rasdltest="$RMANBASE/systemtest/rasdl/rasdl.sh"
+
+echo "Test log file." > $LOGFILE 2>&1
+
+if [[ ! -a $insert ]]; then
+ echo "\nTest program $insertppm not found" >> $LOGFILE 2>&1
+ echo "Please build the program and try again." >> $LOGFILE 2>&1
+ return
+fi
+
+if [[ ! -a $insert ]]; then
+ echo "\nTest program $insert not found" >> $LOGFILE 2>&1
+ echo "Please build the program and try again." >> $LOGFILE 2>&1
+ return
+fi
+
+if [[ ! -a $query ]]; then
+ echo "\nTest program $query not found" >> $LOGFILE 2>&1
+ echo "Please build the program and try again." >> $LOGFILE 2>&1
+ return
+fi
+
+if [[ ! -a $rasdltest ]]; then
+ echo "\nTest program $rasdltest not found" >> $LOGFILE 2>&1
+ echo "Please build the program and try again." >> $LOGFILE 2>&1
+ return
+fi
+
+#
+# test rasdl
+#
+echo "\nPhase -1: Testing RasDL\n" >> $LOGFILE 2>&1
+$rasdl >> $LOGFILE 2>&1
+if [[ $? != 0 ]]; then
+ echo "\nTest program $rasdltest failed" >> $LOGFILE 2>&1
+ return
+fi
+
+insert="$insert $SERVER $BASENAME"
+insertppm="$insertppm -server $SERVER -base $BASENAME"
+query="$query $SERVER $BASENAME"
+YesNo=""
+
+
+if [[ $DEMODATA = "on" ]]; then
+ echo "\n\nReset demo data in db: \n" >> $LOGFILE 2>&1
+
+ # delete collections
+ echo "Delete test collections of $BASENAME..." >> $LOGFILE 2>&1;
+ echo "10\n" | $insert ImgCharA >> $LOGFILE 2>&1 ;
+ echo "10\n" | $insert ImgCharB >> $LOGFILE 2>&1 ;
+ echo "10\n" | $insert ImgCharC >> $LOGFILE 2>&1 ;
+ echo "10\n" | $insert ImgCharD >> $LOGFILE 2>&1 ;
+ echo "10\n" | $insert ImgCharMask >> $LOGFILE 2>&1 ;
+ echo "10\n" | $insert OvlCharA >> $LOGFILE 2>&1 ;
+ echo "10\n" | $insert OvlCharB >> $LOGFILE 2>&1 ;
+ echo "10\n" | $insert OvlCharC >> $LOGFILE 2>&1 ;
+ echo "10\n" | $insert ImgRGBA >> $LOGFILE 2>&1 ;
+ echo "10\n" | $insert ImgULongC >> $LOGFILE 2>&1 ;
+ echo "10\n" | $insert OlapCharA >> $LOGFILE 2>&1 ;
+ echo "10\n" | $insert StringCharA >> $LOGFILE 2>&1 ;
+ echo "10\n" | $insert CubeCharA >> $LOGFILE 2>&1 ;
+ echo "10\n" | $insert OvlRGBA >> $LOGFILE 2>&1 ;
+ echo "10\n" | $insert OvlRGBB >> $LOGFILE 2>&1 ;
+ echo "10\n" | $insert OvlRGBC >> $LOGFILE 2>&1 ;
+
+ if [[ $CREATEDATA = "on" ]]; then
+ echo "\n\nCreate demo data in db: \n" >> $LOGFILE 2>&1
+
+ #create collections
+ echo "Insert test collections into $BASENAME..." >> $LOGFILE 2>&1;
+ echo "5\n 0\n 2\n 0\n 10\n 0\n 10\n" | $insert ImgCharA >> $LOGFILE 2>&1 ;
+ echo "5\n 1\n 2\n 0\n 10\n 0\n 10\n" | $insert ImgCharA >> $LOGFILE 2>&1 ;
+ echo "5\n 10\n 2\n 0\n 10\n 0\n 10\n" | $insert ImgCharB >> $LOGFILE 2>&1 ;
+ echo "5\n 20\n 2\n 0\n 10\n 0\n 10\n" | $insert ImgCharB >> $LOGFILE 2>&1 ;
+ echo "5\n 100\n 2\n 0\n 10\n 0\n 10\n" | $insert ImgCharC >> $LOGFILE 2>&1 ;
+ echo "5\n 200\n 2\n 0\n 10\n 0\n 10\n" | $insert ImgCharC >> $LOGFILE 2>&1 ;
+ echo "13\n 2\n 0\n 10\n 0\n 10\n" | $insert ImgCharD >> $LOGFILE 2>&1 ;
+ echo "5\n 2\n 2\n-2\n 2\n-1\n 1\n" | $insert ImgCharMask >> $LOGFILE 2>&1;
+ echo "1\n 2\n 0\n 9\n 0\n 9\n" | $insert ImgULongC >> $LOGFILE 2>&1;
+ echo "6\n 2\n 0\n 10\n 0\n 10\n" | $insert ImgRGBA >> $LOGFILE 2>&1 ;
+ echo "6\n 2\n 0\n 10\n 0\n 10\n" | $insert ImgRGBA >> $LOGFILE 2>&1 ;
+ echo "13\n 2\n 0\n 13\n 0\n 1\n" | $insert OlapCharA >> $LOGFILE 2>&1 ;
+ echo "13\n 1\n 0\n 99\n " | $insert StringCharA -settype GreySet1 -mddtype GreyString >> $LOGFILE 2>&1 ;
+ echo "5\n 0\n 3\n 0\n 10\n 0\n 10\n 0\n 10\n" | $insert CubeCharA -settype GreySet3 -mddtype GreyCube >> $LOGFILE 2>&1 ;
+
+ $insertppm -collection OvlRGBA $images/ovl1.ppm >> $LOGFILE 2>&1
+ $insertppm -collection OvlRGBB $images/ovl2.ppm >> $LOGFILE 2>&1
+ $insertppm -collection OvlRGBC $images/ovl3.ppm >> $LOGFILE 2>&1
+ $insertppm -grey -collection OvlCharA $images/ovl1.ppm >> $LOGFILE 2>&1
+ $insertppm -grey -collection OvlCharB $images/ovl2.ppm >> $LOGFILE 2>&1
+ $insertppm -grey -collection OvlCharC $images/ovl3.ppm >> $LOGFILE 2>&1
+ fi
+fi
+
+#
+# print some summary information
+#
+echo "--------------------------------------------------------------TEST SESSION--" >> $LOGFILE 2>&1
+echo "- Date........ : " `date` >> $LOGFILE 2>&1
+echo "- Tester.......: " $TESTER >> $LOGFILE 2>&1
+echo "- Directory....: " $PWD/$TESTDIR >> $LOGFILE 2>&1
+echo "- Client name..: " $CLIENT >> $LOGFILE 2>&1
+echo "- Server name..: " $SERVER >> $LOGFILE 2>&1
+echo "- Base name....: " $BASENAME >> $LOGFILE 2>&1
+echo "- Time stamp...: " $TIMESTAMP >> $LOGFILE 2>&1
+echo "----------------------------------------------------------------------START-" >> $LOGFILE 2>&1
+
+
+#
+# test java
+#
+if [[ $TESTJAVA = "on" ]]; then
+ javaquery="$RMANBASE/java/examples/TestQuery.class"
+ if [[ ! -a $javaquery ]]; then
+ echo "\nTest program $javaquery not found"
+ echo "Please build the program and try again."
+ return
+ fi
+ echo "\nPhase 0: Testing Java Query Files\n" >> $LOGFILE 2>&1
+ java -classpath $CLASSPATH:/usr/local/dist/dir/java/:$RMANBASE/java/:$RMANBASE/java/classes:$RMANHOME/java/:$RMANHOME/java/classes examples.TestQuery -server $SERVER -database $BASENAME -testdirectory /home/staff/rastest/testdata -logfile testjava.log
+ cat testjava.log >> $LOGFILE
+fi
+
+#
+# test query files
+#
+if [[ $QUERIES = "on" ]]; then
+ echo "\nPhase 1: Testing Query Files\n" >> $LOGFILE 2>&1
+ testCnt=1
+ queryFiles=`find $TESTDIR -name '*.ql' | sort`
+ for queryFile in $queryFiles; do
+ testQuery $queryFile
+ echo "Query " $testCnt $queryFile":" $returnValue
+ testCnt=$(($testCnt+1))
+ done
+fi
+
+#
+# test scripts
+#
+if [[ $SCRIPTS = "on" ]]; then
+ echo "\nPhase 2: Testing Scripts\n" >> $LOGFILE 2>&1
+ testCnt=1
+ scriptFiles=`find scripts -name '*.sh' | sort`
+ for scriptFile in $scriptFiles; do
+ testScript $scriptFile
+ echo "Script " $testCnt $scriptFile":" $returnValue
+ testCnt=$(($testCnt+1))
+ done
+fi
+
+#
+# test conversion
+#
+if [[ $CONV = "on" ]]; then
+ echo "\nPhase 3: Testing Conversion\n" >> $LOGFILE 2>&1
+ cdir=$PWD
+ cd $RMANHOME/rasodmg/test
+ (echo "v"; echo "e") | ./test_comp_conv.sh
+ cd cdir
+fi
+
+#
+# test compresion
+#
+if [[ $COMP = "on" ]]; then
+ echo "\nPhase 4: Testing Compression\n" >> $LOGFILE 2>&1
+ cdir=$PWD
+ cd $RMANHOME/rasodmg/test
+ (echo "p"; echo "e") | ./test_comp_conv.sh
+ cd cdir
+fi
+
+echo "\n\n" >> $LOGFILE 2>&1
+
+#
+# check in log file
+#
+
+if [[ $CHECKINLOG = "on" ]]; then
+ co -l session.log
+ cp $LOGFILE session.log
+ ci -u session.log
+fi
+
+echo "Testing finnished."
diff --git a/systemtest/testdata/1dset1/cellaccess.ql b/systemtest/testdata/1dset1/cellaccess.ql
new file mode 100644
index 0000000..687d2e4
--- /dev/null
+++ b/systemtest/testdata/1dset1/cellaccess.ql
@@ -0,0 +1,3 @@
+select a
+from StringCharA as a
+where a[1] = 1
diff --git a/systemtest/testdata/1dset1/cellaccess.ql.java.out b/systemtest/testdata/1dset1/cellaccess.ql.java.out
new file mode 100644
index 0000000..e755164
--- /dev/null
+++ b/systemtest/testdata/1dset1/cellaccess.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:99]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 100
+ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 \ No newline at end of file
diff --git a/systemtest/testdata/1dset1/cellaccess.ql.out b/systemtest/testdata/1dset1/cellaccess.ql.out
new file mode 100644
index 0000000..324d73b
--- /dev/null
+++ b/systemtest/testdata/1dset1/cellaccess.ql.out
@@ -0,0 +1,14 @@
+-- Testbed line: result_type=set <marray <char, [0:99]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [0:99]>
+ Type Schema...........: marray< char >
+ Domain................: [0:99]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 100
+ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
+-- Testbed end block:
diff --git a/systemtest/testdata/1dset1/trim.ql b/systemtest/testdata/1dset1/trim.ql
new file mode 100644
index 0000000..26a5145
--- /dev/null
+++ b/systemtest/testdata/1dset1/trim.ql
@@ -0,0 +1,2 @@
+select a[4:8]
+from StringCharA as a
diff --git a/systemtest/testdata/1dset1/trim.ql.java.out b/systemtest/testdata/1dset1/trim.ql.java.out
new file mode 100644
index 0000000..ce45b10
--- /dev/null
+++ b/systemtest/testdata/1dset1/trim.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [4:8]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 5
+ 4 5 6 7 8 \ No newline at end of file
diff --git a/systemtest/testdata/1dset1/trim.ql.out b/systemtest/testdata/1dset1/trim.ql.out
new file mode 100644
index 0000000..ee9bbf4
--- /dev/null
+++ b/systemtest/testdata/1dset1/trim.ql.out
@@ -0,0 +1,14 @@
+-- Testbed line: result_type=set <marray <char, [4:8]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [4:8]>
+ Type Schema...........: marray< char >
+ Domain................: [4:8]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 5
+ 4 5 6 7 8
+-- Testbed end block:
diff --git a/systemtest/testdata/3dset1/proj1.ql b/systemtest/testdata/3dset1/proj1.ql
new file mode 100644
index 0000000..fce0d2b
--- /dev/null
+++ b/systemtest/testdata/3dset1/proj1.ql
@@ -0,0 +1,2 @@
+SELECT a[*:*,7,8]
+FROM CubeCharA AS a
diff --git a/systemtest/testdata/3dset1/proj1.ql.java.out b/systemtest/testdata/3dset1/proj1.ql.java.out
new file mode 100644
index 0000000..7ae2801
--- /dev/null
+++ b/systemtest/testdata/3dset1/proj1.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 11
+ 0 0 0 0 0 0 0 0 0 0 0 \ No newline at end of file
diff --git a/systemtest/testdata/3dset1/proj1.ql.out b/systemtest/testdata/3dset1/proj1.ql.out
new file mode 100644
index 0000000..7568bc9
--- /dev/null
+++ b/systemtest/testdata/3dset1/proj1.ql.out
@@ -0,0 +1,14 @@
+-- Testbed line: result_type=set <marray <char, [0:10]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 11
+ 0 0 0 0 0 0 0 0 0 0 0
+-- Testbed end block:
diff --git a/systemtest/testdata/3dset1/proj2.ql b/systemtest/testdata/3dset1/proj2.ql
new file mode 100644
index 0000000..601c712
--- /dev/null
+++ b/systemtest/testdata/3dset1/proj2.ql
@@ -0,0 +1,2 @@
+SELECT a[7,8,*:*]
+FROM CubeCharA AS a
diff --git a/systemtest/testdata/3dset1/proj2.ql.java.out b/systemtest/testdata/3dset1/proj2.ql.java.out
new file mode 100644
index 0000000..7ae2801
--- /dev/null
+++ b/systemtest/testdata/3dset1/proj2.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 11
+ 0 0 0 0 0 0 0 0 0 0 0 \ No newline at end of file
diff --git a/systemtest/testdata/3dset1/proj2.ql.out b/systemtest/testdata/3dset1/proj2.ql.out
new file mode 100644
index 0000000..7568bc9
--- /dev/null
+++ b/systemtest/testdata/3dset1/proj2.ql.out
@@ -0,0 +1,14 @@
+-- Testbed line: result_type=set <marray <char, [0:10]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 11
+ 0 0 0 0 0 0 0 0 0 0 0
+-- Testbed end block:
diff --git a/systemtest/testdata/3dset1/proj3.ql b/systemtest/testdata/3dset1/proj3.ql
new file mode 100644
index 0000000..436a266
--- /dev/null
+++ b/systemtest/testdata/3dset1/proj3.ql
@@ -0,0 +1,2 @@
+SELECT marray x in [0:0] values a[2,7,8]
+FROM CubeCharA AS a
diff --git a/systemtest/testdata/3dset1/proj3.ql.java.out b/systemtest/testdata/3dset1/proj3.ql.java.out
new file mode 100644
index 0000000..354d1e8
--- /dev/null
+++ b/systemtest/testdata/3dset1/proj3.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 1
+ 0 \ No newline at end of file
diff --git a/systemtest/testdata/3dset1/proj3.ql.out b/systemtest/testdata/3dset1/proj3.ql.out
new file mode 100644
index 0000000..d5fbdd9
--- /dev/null
+++ b/systemtest/testdata/3dset1/proj3.ql.out
@@ -0,0 +1,14 @@
+-- Testbed line: result_type=set <marray <char, [0:0]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [0:0]>
+ Type Schema...........: marray< char >
+ Domain................: [0:0]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 1
+ 0
+-- Testbed end block:
diff --git a/systemtest/testdata/bit/bit_01.ql b/systemtest/testdata/bit/bit_01.ql
new file mode 100644
index 0000000..37debb3
--- /dev/null
+++ b/systemtest/testdata/bit/bit_01.ql
@@ -0,0 +1,2 @@
+
+ select bit(a, 0) from ImgCharA as a -- F, T
diff --git a/systemtest/testdata/bit/bit_01.ql.java.out b/systemtest/testdata/bit/bit_01.ql.java.out
new file mode 100644
index 0000000..f2deb7a
--- /dev/null
+++ b/systemtest/testdata/bit/bit_01.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 \ No newline at end of file
diff --git a/systemtest/testdata/bit/bit_01.ql.out b/systemtest/testdata/bit/bit_01.ql.out
new file mode 100644
index 0000000..53e26a4
--- /dev/null
+++ b/systemtest/testdata/bit/bit_01.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <bool, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <bool, [0:10,0:10]>
+ Type Schema...........: marray< bool >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: bool
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+Image 2
+GMarray
+ Type Structure........: marray <bool, [0:10,0:10]>
+ Type Schema...........: marray< bool >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: bool
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+-- Testbed end block:
diff --git a/systemtest/testdata/bit/bit_02.ql b/systemtest/testdata/bit/bit_02.ql
new file mode 100644
index 0000000..7bd737f
--- /dev/null
+++ b/systemtest/testdata/bit/bit_02.ql
@@ -0,0 +1,2 @@
+
+ select bit(a, 9) from ImgCharA as a -- F, F
diff --git a/systemtest/testdata/bit/bit_02.ql.java.out b/systemtest/testdata/bit/bit_02.ql.java.out
new file mode 100644
index 0000000..8315bc2
--- /dev/null
+++ b/systemtest/testdata/bit/bit_02.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \ No newline at end of file
diff --git a/systemtest/testdata/bit/bit_02.ql.out b/systemtest/testdata/bit/bit_02.ql.out
new file mode 100644
index 0000000..83e6fdb
--- /dev/null
+++ b/systemtest/testdata/bit/bit_02.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <bool, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <bool, [0:10,0:10]>
+ Type Schema...........: marray< bool >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: bool
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+Image 2
+GMarray
+ Type Structure........: marray <bool, [0:10,0:10]>
+ Type Schema...........: marray< bool >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: bool
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+-- Testbed end block:
diff --git a/systemtest/testdata/bit/bit_03.ql b/systemtest/testdata/bit/bit_03.ql
new file mode 100644
index 0000000..f63957d
--- /dev/null
+++ b/systemtest/testdata/bit/bit_03.ql
@@ -0,0 +1,2 @@
+
+ select bit(3, 0) from ImgCharA -- T
diff --git a/systemtest/testdata/bit/bit_03.ql.java.out b/systemtest/testdata/bit/bit_03.ql.java.out
new file mode 100644
index 0000000..9d60796
--- /dev/null
+++ b/systemtest/testdata/bit/bit_03.ql.java.out
@@ -0,0 +1 @@
+11 \ No newline at end of file
diff --git a/systemtest/testdata/bit/bit_03.ql.out b/systemtest/testdata/bit/bit_03.ql.out
new file mode 100644
index 0000000..89db772
--- /dev/null
+++ b/systemtest/testdata/bit/bit_03.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<bool>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: T
+Element 2: T
+-- Testbed end block:
diff --git a/systemtest/testdata/bit/bit_04.ql b/systemtest/testdata/bit/bit_04.ql
new file mode 100644
index 0000000..703dabf
--- /dev/null
+++ b/systemtest/testdata/bit/bit_04.ql
@@ -0,0 +1,2 @@
+
+ select bit(3, 1) from ImgCharA -- T
diff --git a/systemtest/testdata/bit/bit_04.ql.java.out b/systemtest/testdata/bit/bit_04.ql.java.out
new file mode 100644
index 0000000..9d60796
--- /dev/null
+++ b/systemtest/testdata/bit/bit_04.ql.java.out
@@ -0,0 +1 @@
+11 \ No newline at end of file
diff --git a/systemtest/testdata/bit/bit_04.ql.out b/systemtest/testdata/bit/bit_04.ql.out
new file mode 100644
index 0000000..89db772
--- /dev/null
+++ b/systemtest/testdata/bit/bit_04.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<bool>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: T
+Element 2: T
+-- Testbed end block:
diff --git a/systemtest/testdata/bit/bit_05.ql b/systemtest/testdata/bit/bit_05.ql
new file mode 100644
index 0000000..90a8a47
--- /dev/null
+++ b/systemtest/testdata/bit/bit_05.ql
@@ -0,0 +1,2 @@
+
+ select bit(3, 2) from ImgCharA -- F
diff --git a/systemtest/testdata/bit/bit_05.ql.java.out b/systemtest/testdata/bit/bit_05.ql.java.out
new file mode 100644
index 0000000..857f065
--- /dev/null
+++ b/systemtest/testdata/bit/bit_05.ql.java.out
@@ -0,0 +1 @@
+00 \ No newline at end of file
diff --git a/systemtest/testdata/bit/bit_05.ql.out b/systemtest/testdata/bit/bit_05.ql.out
new file mode 100644
index 0000000..7fda105
--- /dev/null
+++ b/systemtest/testdata/bit/bit_05.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<bool>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: F
+Element 2: F
+-- Testbed end block:
diff --git a/systemtest/testdata/bit/bit_06.ql b/systemtest/testdata/bit/bit_06.ql
new file mode 100644
index 0000000..d413f3b
--- /dev/null
+++ b/systemtest/testdata/bit/bit_06.ql
@@ -0,0 +1,2 @@
+
+ select bit(3, 3) from ImgCharA -- F
diff --git a/systemtest/testdata/bit/bit_06.ql.java.out b/systemtest/testdata/bit/bit_06.ql.java.out
new file mode 100644
index 0000000..857f065
--- /dev/null
+++ b/systemtest/testdata/bit/bit_06.ql.java.out
@@ -0,0 +1 @@
+00 \ No newline at end of file
diff --git a/systemtest/testdata/bit/bit_06.ql.out b/systemtest/testdata/bit/bit_06.ql.out
new file mode 100644
index 0000000..7fda105
--- /dev/null
+++ b/systemtest/testdata/bit/bit_06.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<bool>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: F
+Element 2: F
+-- Testbed end block:
diff --git a/systemtest/testdata/bit/bit_07.ql b/systemtest/testdata/bit/bit_07.ql
new file mode 100644
index 0000000..657d539
--- /dev/null
+++ b/systemtest/testdata/bit/bit_07.ql
@@ -0,0 +1,2 @@
+
+ select bit(3, 4) from ImgCharA -- F
diff --git a/systemtest/testdata/bit/bit_07.ql.java.out b/systemtest/testdata/bit/bit_07.ql.java.out
new file mode 100644
index 0000000..857f065
--- /dev/null
+++ b/systemtest/testdata/bit/bit_07.ql.java.out
@@ -0,0 +1 @@
+00 \ No newline at end of file
diff --git a/systemtest/testdata/bit/bit_07.ql.out b/systemtest/testdata/bit/bit_07.ql.out
new file mode 100644
index 0000000..7fda105
--- /dev/null
+++ b/systemtest/testdata/bit/bit_07.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<bool>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: F
+Element 2: F
+-- Testbed end block:
diff --git a/systemtest/testdata/bit/bit_08.ql b/systemtest/testdata/bit/bit_08.ql
new file mode 100644
index 0000000..d904288
--- /dev/null
+++ b/systemtest/testdata/bit/bit_08.ql
@@ -0,0 +1,2 @@
+
+ select bit(3, 5) from ImgCharA -- F
diff --git a/systemtest/testdata/bit/bit_08.ql.java.out b/systemtest/testdata/bit/bit_08.ql.java.out
new file mode 100644
index 0000000..857f065
--- /dev/null
+++ b/systemtest/testdata/bit/bit_08.ql.java.out
@@ -0,0 +1 @@
+00 \ No newline at end of file
diff --git a/systemtest/testdata/bit/bit_08.ql.out b/systemtest/testdata/bit/bit_08.ql.out
new file mode 100644
index 0000000..7fda105
--- /dev/null
+++ b/systemtest/testdata/bit/bit_08.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<bool>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: F
+Element 2: F
+-- Testbed end block:
diff --git a/systemtest/testdata/bit/bit_09.ql b/systemtest/testdata/bit/bit_09.ql
new file mode 100644
index 0000000..9c4dff2
--- /dev/null
+++ b/systemtest/testdata/bit/bit_09.ql
@@ -0,0 +1,2 @@
+
+ select bit(3, 6) from ImgCharA -- F
diff --git a/systemtest/testdata/bit/bit_09.ql.java.out b/systemtest/testdata/bit/bit_09.ql.java.out
new file mode 100644
index 0000000..857f065
--- /dev/null
+++ b/systemtest/testdata/bit/bit_09.ql.java.out
@@ -0,0 +1 @@
+00 \ No newline at end of file
diff --git a/systemtest/testdata/bit/bit_09.ql.out b/systemtest/testdata/bit/bit_09.ql.out
new file mode 100644
index 0000000..7fda105
--- /dev/null
+++ b/systemtest/testdata/bit/bit_09.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<bool>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: F
+Element 2: F
+-- Testbed end block:
diff --git a/systemtest/testdata/bit/bit_10.ql b/systemtest/testdata/bit/bit_10.ql
new file mode 100644
index 0000000..9fbcb5d
--- /dev/null
+++ b/systemtest/testdata/bit/bit_10.ql
@@ -0,0 +1,2 @@
+
+ select bit(3, 7) from ImgCharA -- F
diff --git a/systemtest/testdata/bit/bit_10.ql.java.out b/systemtest/testdata/bit/bit_10.ql.java.out
new file mode 100644
index 0000000..857f065
--- /dev/null
+++ b/systemtest/testdata/bit/bit_10.ql.java.out
@@ -0,0 +1 @@
+00 \ No newline at end of file
diff --git a/systemtest/testdata/bit/bit_10.ql.out b/systemtest/testdata/bit/bit_10.ql.out
new file mode 100644
index 0000000..7fda105
--- /dev/null
+++ b/systemtest/testdata/bit/bit_10.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<bool>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: F
+Element 2: F
+-- Testbed end block:
diff --git a/systemtest/testdata/bit/bit_11.ql b/systemtest/testdata/bit/bit_11.ql
new file mode 100644
index 0000000..230413f
--- /dev/null
+++ b/systemtest/testdata/bit/bit_11.ql
@@ -0,0 +1,2 @@
+
+ select bit(3, 8) from ImgCharA -- F
diff --git a/systemtest/testdata/bit/bit_11.ql.java.out b/systemtest/testdata/bit/bit_11.ql.java.out
new file mode 100644
index 0000000..857f065
--- /dev/null
+++ b/systemtest/testdata/bit/bit_11.ql.java.out
@@ -0,0 +1 @@
+00 \ No newline at end of file
diff --git a/systemtest/testdata/bit/bit_11.ql.out b/systemtest/testdata/bit/bit_11.ql.out
new file mode 100644
index 0000000..7fda105
--- /dev/null
+++ b/systemtest/testdata/bit/bit_11.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<bool>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: F
+Element 2: F
+-- Testbed end block:
diff --git a/systemtest/testdata/bit/bit_12.ql b/systemtest/testdata/bit/bit_12.ql
new file mode 100644
index 0000000..59c6043
--- /dev/null
+++ b/systemtest/testdata/bit/bit_12.ql
@@ -0,0 +1,2 @@
+
+ select bit(3, 10000) from ImgCharA -- F
diff --git a/systemtest/testdata/bit/bit_12.ql.java.out b/systemtest/testdata/bit/bit_12.ql.java.out
new file mode 100644
index 0000000..857f065
--- /dev/null
+++ b/systemtest/testdata/bit/bit_12.ql.java.out
@@ -0,0 +1 @@
+00 \ No newline at end of file
diff --git a/systemtest/testdata/bit/bit_12.ql.out b/systemtest/testdata/bit/bit_12.ql.out
new file mode 100644
index 0000000..7fda105
--- /dev/null
+++ b/systemtest/testdata/bit/bit_12.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<bool>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: F
+Element 2: F
+-- Testbed end block:
diff --git a/systemtest/testdata/bit/bit_13.ql b/systemtest/testdata/bit/bit_13.ql
new file mode 100644
index 0000000..cd6d7a1
--- /dev/null
+++ b/systemtest/testdata/bit/bit_13.ql
@@ -0,0 +1,2 @@
+
+ select bit(3.14, 2) from ImgCharA -- Err 365
diff --git a/systemtest/testdata/bit/bit_13.ql.java.out b/systemtest/testdata/bit/bit_13.ql.java.out
new file mode 100644
index 0000000..288cdab
--- /dev/null
+++ b/systemtest/testdata/bit/bit_13.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Execution error 365 in line 4, column 9, near token bit: Scalar types of binary operation are incompatible. \ No newline at end of file
diff --git a/systemtest/testdata/bit/bit_13.ql.out b/systemtest/testdata/bit/bit_13.ql.out
new file mode 100644
index 0000000..261350d
--- /dev/null
+++ b/systemtest/testdata/bit/bit_13.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=365
diff --git a/systemtest/testdata/bit/bit_14.ql b/systemtest/testdata/bit/bit_14.ql
new file mode 100644
index 0000000..29db6fb
--- /dev/null
+++ b/systemtest/testdata/bit/bit_14.ql
@@ -0,0 +1,2 @@
+
+ select bit(2, 3.14) from ImgCharA -- Err 418
diff --git a/systemtest/testdata/bit/bit_14.ql.java.out b/systemtest/testdata/bit/bit_14.ql.java.out
new file mode 100644
index 0000000..339ae35
--- /dev/null
+++ b/systemtest/testdata/bit/bit_14.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Execution error 418 in line 4, column 9, near token bit: Second operand of bit function must be of integral type. \ No newline at end of file
diff --git a/systemtest/testdata/bit/bit_14.ql.out b/systemtest/testdata/bit/bit_14.ql.out
new file mode 100644
index 0000000..3ee1d3a
--- /dev/null
+++ b/systemtest/testdata/bit/bit_14.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=418
diff --git a/systemtest/testdata/bit/bit_15.ql b/systemtest/testdata/bit/bit_15.ql
new file mode 100644
index 0000000..a03914e
--- /dev/null
+++ b/systemtest/testdata/bit/bit_15.ql
@@ -0,0 +1,2 @@
+
+ select bit({2, 3, 4}, 1) from ImgCharA -- {T, T, F}
diff --git a/systemtest/testdata/bit/bit_15.ql.java.out b/systemtest/testdata/bit/bit_15.ql.java.out
new file mode 100644
index 0000000..f8b474d
--- /dev/null
+++ b/systemtest/testdata/bit/bit_15.ql.java.out
@@ -0,0 +1,16 @@
+
+ RasRuntimeException: Exception: Base type typeName:
+ typeID: 7
+ typeSize: 2
+struct
+{
+ typeName: RAS_BOOLEAN
+ typeID: 16
+ typeSize: 1
+ 0,
+typeName: RAS_BOOLEAN
+ typeID: 16
+ typeSize: 1
+ 1
+}
+ as ElementType is not supported yet. \ No newline at end of file
diff --git a/systemtest/testdata/bit/bit_15.ql.out b/systemtest/testdata/bit/bit_15.ql.out
new file mode 100644
index 0000000..fb11d74
--- /dev/null
+++ b/systemtest/testdata/bit/bit_15.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<struct { bool 0, bool 1, bool 2 }>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: { T, T, F }
+Element 2: { T, T, F }
+-- Testbed end block:
diff --git a/systemtest/testdata/bit/bit_16.ql b/systemtest/testdata/bit/bit_16.ql
new file mode 100644
index 0000000..6516304
--- /dev/null
+++ b/systemtest/testdata/bit/bit_16.ql
@@ -0,0 +1,2 @@
+
+ select bit(3.14 * a, 2) from ImgRGBA as a -- Err 364
diff --git a/systemtest/testdata/bit/bit_16.ql.java.out b/systemtest/testdata/bit/bit_16.ql.java.out
new file mode 100644
index 0000000..6301cf7
--- /dev/null
+++ b/systemtest/testdata/bit/bit_16.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Execution error 364 in line 4, column 9, near token bit: Cell base type and scalar type of binary induce operation are incompatible. \ No newline at end of file
diff --git a/systemtest/testdata/bit/bit_16.ql.out b/systemtest/testdata/bit/bit_16.ql.out
new file mode 100644
index 0000000..c517ceb
--- /dev/null
+++ b/systemtest/testdata/bit/bit_16.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=364
diff --git a/systemtest/testdata/bugfixes/all_collections.ql b/systemtest/testdata/bugfixes/all_collections.ql
new file mode 100644
index 0000000..bdbc119
--- /dev/null
+++ b/systemtest/testdata/bugfixes/all_collections.ql
@@ -0,0 +1,4 @@
+/*+opt 0*/
+select a
+from RAS_COLLECTIONNAMES as a
+
diff --git a/systemtest/testdata/bugfixes/all_collections.ql.java.out b/systemtest/testdata/bugfixes/all_collections.ql.java.out
new file mode 100644
index 0000000..d5e7d87
--- /dev/null
+++ b/systemtest/testdata/bugfixes/all_collections.ql.java.out
@@ -0,0 +1,841 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:7]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 111 114 116 104 111 95 51 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:8]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 9
+ 111 114 116 104 111 114 103 98 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 11
+ 111 114 116 104 111 114 103 98 95 56 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:5]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 6
+ 116 107 49 48 48 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:7]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 111 114 116 104 111 95 49 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:6]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 7
+ 97 102 114 105 107 97 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:4]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 5
+ 99 110 105 103 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:7]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 114 111 99 107 105 101 115 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:8]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 9
+ 79 118 108 67 104 97 114 67 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 11
+ 111 114 116 104 111 114 103 98 95 52 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:5]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 6
+ 111 114 116 104 111 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:4]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 5
+ 116 107 50 53 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:7]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 111 114 116 104 111 95 50 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:9]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 10
+ 79 108 97 112 67 104 97 114 65 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:11]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 12
+ 83 116 114 105 110 103 67 104 97 114 65 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:9]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 10
+ 67 117 98 101 67 104 97 114 65 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:7]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 79 118 108 82 71 66 65 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:4]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 5
+ 116 107 49 48 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:7]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 111 114 116 104 111 95 52 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:7]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 111 114 116 104 111 95 56 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:2]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 3
+ 109 114 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:3]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 4
+ 109 114 50 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:6]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 7
+ 101 97 114 116 104 49 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:5]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 6
+ 101 97 114 116 104 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 11
+ 111 114 116 104 111 114 103 98 95 51 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:7]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 111 114 116 104 111 95 55 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:7]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 111 114 116 104 111 95 53 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:4]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 5
+ 116 107 53 48 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:8]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 9
+ 73 109 103 67 104 97 114 68 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:11]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 12
+ 73 109 103 67 104 97 114 77 97 115 107 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:9]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 10
+ 73 109 103 85 76 111 110 103 67 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:7]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 73 109 103 82 71 66 65 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:7]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 116 107 49 48 48 95 52 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:7]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 116 107 49 48 48 95 53 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:11]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 12
+ 116 101 115 116 115 101 112 122 108 105 98 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 11
+ 111 114 116 104 111 114 103 98 95 50 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:7]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 116 107 49 48 48 95 49 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:7]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 116 107 49 48 48 95 50 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 11
+ 116 111 109 111 95 99 117 98 101 100 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:8]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 9
+ 73 109 103 67 104 97 114 65 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:8]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 9
+ 73 109 103 67 104 97 114 66 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:8]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 9
+ 73 109 103 67 104 97 114 67 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 11
+ 111 114 116 104 111 114 103 98 95 49 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:7]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 116 107 49 48 48 95 54 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:7]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 116 107 49 48 48 95 55 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:7]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 111 114 116 104 111 95 54 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:7]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 79 118 108 82 71 66 66 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:7]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 79 118 108 82 71 66 67 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:8]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 9
+ 79 118 108 67 104 97 114 65 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:8]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 9
+ 79 118 108 67 104 97 114 66 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:5]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 6
+ 109 111 118 105 101 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:5]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 6
+ 97 114 114 111 119 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:11]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 12
+ 116 111 109 111 95 115 108 105 99 101 100 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 11
+ 111 114 116 104 111 114 103 98 95 53 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:4]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 5
+ 116 101 115 116 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:3]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 4
+ 114 103 98 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:4]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 5
+ 100 101 109 99 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 11
+ 111 114 116 104 111 114 103 98 95 54 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 11
+ 111 114 116 104 111 114 103 98 95 55 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:7]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 116 107 49 48 48 95 51 0 \ No newline at end of file
diff --git a/systemtest/testdata/bugfixes/all_collections.ql.out b/systemtest/testdata/bugfixes/all_collections.ql.out
new file mode 100644
index 0000000..3f4b87b
--- /dev/null
+++ b/systemtest/testdata/bugfixes/all_collections.ql.out
@@ -0,0 +1,164 @@
+-- Testbed line: result_type=set <marray <char, [0:8]>>
+-- Testbed line: result_elements=16
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [0:8]>
+ Type Schema...........: marray< char >
+ Domain................: [0:8]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 9
+ 73 109 103 67 104 97 114 67 0
+Image 2
+GMarray
+ Type Structure........: marray <char, [0:8]>
+ Type Schema...........: marray< char >
+ Domain................: [0:8]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 9
+ 79 118 108 67 104 97 114 67 0
+Image 3
+GMarray
+ Type Structure........: marray <char, [0:7]>
+ Type Schema...........: marray< char >
+ Domain................: [0:7]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 8
+ 79 118 108 82 71 66 67 0
+Image 4
+GMarray
+ Type Structure........: marray <char, [0:8]>
+ Type Schema...........: marray< char >
+ Domain................: [0:8]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 9
+ 79 118 108 67 104 97 114 65 0
+Image 5
+GMarray
+ Type Structure........: marray <char, [0:8]>
+ Type Schema...........: marray< char >
+ Domain................: [0:8]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 9
+ 73 109 103 67 104 97 114 66 0
+Image 6
+GMarray
+ Type Structure........: marray <char, [0:7]>
+ Type Schema...........: marray< char >
+ Domain................: [0:7]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 8
+ 79 118 108 82 71 66 65 0
+Image 7
+GMarray
+ Type Structure........: marray <char, [0:7]>
+ Type Schema...........: marray< char >
+ Domain................: [0:7]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 8
+ 79 118 108 82 71 66 66 0
+Image 8
+GMarray
+ Type Structure........: marray <char, [0:7]>
+ Type Schema...........: marray< char >
+ Domain................: [0:7]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 8
+ 73 109 103 82 71 66 65 0
+Image 9
+GMarray
+ Type Structure........: marray <char, [0:8]>
+ Type Schema...........: marray< char >
+ Domain................: [0:8]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 9
+ 73 109 103 67 104 97 114 68 0
+Image 10
+GMarray
+ Type Structure........: marray <char, [0:11]>
+ Type Schema...........: marray< char >
+ Domain................: [0:11]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 12
+ 73 109 103 67 104 97 114 77 97 115 107 0
+Image 11
+GMarray
+ Type Structure........: marray <char, [0:9]>
+ Type Schema...........: marray< char >
+ Domain................: [0:9]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 10
+ 67 117 98 101 67 104 97 114 65 0
+Image 12
+GMarray
+ Type Structure........: marray <char, [0:9]>
+ Type Schema...........: marray< char >
+ Domain................: [0:9]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 10
+ 79 108 97 112 67 104 97 114 65 0
+Image 13
+GMarray
+ Type Structure........: marray <char, [0:8]>
+ Type Schema...........: marray< char >
+ Domain................: [0:8]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 9
+ 73 109 103 67 104 97 114 65 0
+Image 14
+GMarray
+ Type Structure........: marray <char, [0:11]>
+ Type Schema...........: marray< char >
+ Domain................: [0:11]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 12
+ 83 116 114 105 110 103 67 104 97 114 65 0
+Image 15
+GMarray
+ Type Structure........: marray <char, [0:9]>
+ Type Schema...........: marray< char >
+ Domain................: [0:9]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 10
+ 73 109 103 85 76 111 110 103 67 0
+Image 16
+GMarray
+ Type Structure........: marray <char, [0:8]>
+ Type Schema...........: marray< char >
+ Domain................: [0:8]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 9
+ 79 118 108 67 104 97 114 66 0
+-- Testbed end block:
diff --git a/systemtest/testdata/bugfixes/all_collections.ql.tmp b/systemtest/testdata/bugfixes/all_collections.ql.tmp
new file mode 100644
index 0000000..498e1f2
--- /dev/null
+++ b/systemtest/testdata/bugfixes/all_collections.ql.tmp
@@ -0,0 +1,164 @@
+-- Testbed line: result_type=set <marray <char, [0:8]>>
+-- Testbed line: result_elements=16
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [0:8]>
+ Type Schema...........: marray< char >
+ Domain................: [0:8]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 9
+ 73 109 103 67 104 97 114 65 0
+Image 2
+GMarray
+ Type Structure........: marray <char, [0:8]>
+ Type Schema...........: marray< char >
+ Domain................: [0:8]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 9
+ 73 109 103 67 104 97 114 66 0
+Image 3
+GMarray
+ Type Structure........: marray <char, [0:8]>
+ Type Schema...........: marray< char >
+ Domain................: [0:8]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 9
+ 73 109 103 67 104 97 114 67 0
+Image 4
+GMarray
+ Type Structure........: marray <char, [0:8]>
+ Type Schema...........: marray< char >
+ Domain................: [0:8]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 9
+ 73 109 103 67 104 97 114 68 0
+Image 5
+GMarray
+ Type Structure........: marray <char, [0:11]>
+ Type Schema...........: marray< char >
+ Domain................: [0:11]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 12
+ 73 109 103 67 104 97 114 77 97 115 107 0
+Image 6
+GMarray
+ Type Structure........: marray <char, [0:9]>
+ Type Schema...........: marray< char >
+ Domain................: [0:9]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 10
+ 73 109 103 85 76 111 110 103 67 0
+Image 7
+GMarray
+ Type Structure........: marray <char, [0:7]>
+ Type Schema...........: marray< char >
+ Domain................: [0:7]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 8
+ 73 109 103 82 71 66 65 0
+Image 8
+GMarray
+ Type Structure........: marray <char, [0:9]>
+ Type Schema...........: marray< char >
+ Domain................: [0:9]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 10
+ 79 108 97 112 67 104 97 114 65 0
+Image 9
+GMarray
+ Type Structure........: marray <char, [0:11]>
+ Type Schema...........: marray< char >
+ Domain................: [0:11]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 12
+ 83 116 114 105 110 103 67 104 97 114 65 0
+Image 10
+GMarray
+ Type Structure........: marray <char, [0:9]>
+ Type Schema...........: marray< char >
+ Domain................: [0:9]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 10
+ 67 117 98 101 67 104 97 114 65 0
+Image 11
+GMarray
+ Type Structure........: marray <char, [0:7]>
+ Type Schema...........: marray< char >
+ Domain................: [0:7]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 8
+ 79 118 108 82 71 66 65 0
+Image 12
+GMarray
+ Type Structure........: marray <char, [0:7]>
+ Type Schema...........: marray< char >
+ Domain................: [0:7]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 8
+ 79 118 108 82 71 66 66 0
+Image 13
+GMarray
+ Type Structure........: marray <char, [0:7]>
+ Type Schema...........: marray< char >
+ Domain................: [0:7]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 8
+ 79 118 108 82 71 66 67 0
+Image 14
+GMarray
+ Type Structure........: marray <char, [0:8]>
+ Type Schema...........: marray< char >
+ Domain................: [0:8]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 9
+ 79 118 108 67 104 97 114 65 0
+Image 15
+GMarray
+ Type Structure........: marray <char, [0:8]>
+ Type Schema...........: marray< char >
+ Domain................: [0:8]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 9
+ 79 118 108 67 104 97 114 66 0
+Image 16
+GMarray
+ Type Structure........: marray <char, [0:8]>
+ Type Schema...........: marray< char >
+ Domain................: [0:8]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 9
+ 79 118 108 67 104 97 114 67 0
+-- Testbed end block:
diff --git a/systemtest/testdata/bugfixes/charcast.ql b/systemtest/testdata/bugfixes/charcast.ql
new file mode 100644
index 0000000..2e6aa80
--- /dev/null
+++ b/systemtest/testdata/bugfixes/charcast.ql
@@ -0,0 +1,2 @@
+select a<132
+from ImgCharA as a
diff --git a/systemtest/testdata/bugfixes/charcast.ql.java.out b/systemtest/testdata/bugfixes/charcast.ql.java.out
new file mode 100644
index 0000000..3b345ff
--- /dev/null
+++ b/systemtest/testdata/bugfixes/charcast.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 \ No newline at end of file
diff --git a/systemtest/testdata/bugfixes/charcast.ql.out b/systemtest/testdata/bugfixes/charcast.ql.out
new file mode 100644
index 0000000..8de3580
--- /dev/null
+++ b/systemtest/testdata/bugfixes/charcast.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <bool, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <bool, [0:10,0:10]>
+ Type Schema...........: marray< bool >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: bool
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+Image 2
+GMarray
+ Type Structure........: marray <bool, [0:10,0:10]>
+ Type Schema...........: marray< bool >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: bool
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+-- Testbed end block:
diff --git a/systemtest/testdata/bugfixes/error308.ql b/systemtest/testdata/bugfixes/error308.ql
new file mode 100644
index 0000000..d5870ce
--- /dev/null
+++ b/systemtest/testdata/bugfixes/error308.ql
@@ -0,0 +1 @@
+select sdom(ImgULongC) \ No newline at end of file
diff --git a/systemtest/testdata/bugfixes/error308.ql.java.out b/systemtest/testdata/bugfixes/error308.ql.java.out
new file mode 100644
index 0000000..26e1b5c
--- /dev/null
+++ b/systemtest/testdata/bugfixes/error308.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Parsing error: Unexpected end of query. \ No newline at end of file
diff --git a/systemtest/testdata/bugfixes/error308.ql.out b/systemtest/testdata/bugfixes/error308.ql.out
new file mode 100644
index 0000000..d1ec6cb
--- /dev/null
+++ b/systemtest/testdata/bugfixes/error308.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=308
diff --git a/systemtest/testdata/bugfixes/floatcondense.ql b/systemtest/testdata/bugfixes/floatcondense.ql
new file mode 100644
index 0000000..7f213f0
--- /dev/null
+++ b/systemtest/testdata/bugfixes/floatcondense.ql
@@ -0,0 +1,4 @@
+select marray x in [0:0] values
+ condense + over y in sdom(a) using 1f
+from ImgCharA as a
+
diff --git a/systemtest/testdata/bugfixes/floatcondense.ql.java.out b/systemtest/testdata/bugfixes/floatcondense.ql.java.out
new file mode 100644
index 0000000..4baff43
--- /dev/null
+++ b/systemtest/testdata/bugfixes/floatcondense.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayFloat
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:31999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 4
+ 66 -14 0 0
+rasj.RasMArrayFloat
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:31999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 4
+ 66 -14 0 0 \ No newline at end of file
diff --git a/systemtest/testdata/bugfixes/floatcondense.ql.out b/systemtest/testdata/bugfixes/floatcondense.ql.out
new file mode 100644
index 0000000..cfafb59
--- /dev/null
+++ b/systemtest/testdata/bugfixes/floatcondense.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <float, [0:0]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <float, [0:0]>
+ Type Schema...........: marray< float >
+ Domain................: [0:0]
+ Base Type Schema......: float
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 4
+ 121
+Image 2
+GMarray
+ Type Structure........: marray <float, [0:0]>
+ Type Schema...........: marray< float >
+ Domain................: [0:0]
+ Base Type Schema......: float
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 4
+ 121
+-- Testbed end block:
diff --git a/systemtest/testdata/caset1/cond1.ql b/systemtest/testdata/caset1/cond1.ql
new file mode 100644
index 0000000..695dcee
--- /dev/null
+++ b/systemtest/testdata/caset1/cond1.ql
@@ -0,0 +1,4 @@
+-- count cells and add value by induction
+
+select a + condense + over x in sdom(a) using 1c
+from ImgCharA as a
diff --git a/systemtest/testdata/caset1/cond1.ql.java.out b/systemtest/testdata/caset1/cond1.ql.java.out
new file mode 100644
index 0000000..0e601ce
--- /dev/null
+++ b/systemtest/testdata/caset1/cond1.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121 121
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 \ No newline at end of file
diff --git a/systemtest/testdata/caset1/cond1.ql.out b/systemtest/testdata/caset1/cond1.ql.out
new file mode 100644
index 0000000..92ac81e
--- /dev/null
+++ b/systemtest/testdata/caset1/cond1.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <char, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [0:10,0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ 121 121 121 121 121 121 121 121 121 121 121
+ 121 121 121 121 121 121 121 121 121 121 121
+ 121 121 121 121 121 121 121 121 121 121 121
+ 121 121 121 121 121 121 121 121 121 121 121
+ 121 121 121 121 121 121 121 121 121 121 121
+ 121 121 121 121 121 121 121 121 121 121 121
+ 121 121 121 121 121 121 121 121 121 121 121
+ 121 121 121 121 121 121 121 121 121 121 121
+ 121 121 121 121 121 121 121 121 121 121 121
+ 121 121 121 121 121 121 121 121 121 121 121
+ 121 121 121 121 121 121 121 121 121 121 121
+Image 2
+GMarray
+ Type Structure........: marray <char, [0:10,0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ 122 122 122 122 122 122 122 122 122 122 122
+ 122 122 122 122 122 122 122 122 122 122 122
+ 122 122 122 122 122 122 122 122 122 122 122
+ 122 122 122 122 122 122 122 122 122 122 122
+ 122 122 122 122 122 122 122 122 122 122 122
+ 122 122 122 122 122 122 122 122 122 122 122
+ 122 122 122 122 122 122 122 122 122 122 122
+ 122 122 122 122 122 122 122 122 122 122 122
+ 122 122 122 122 122 122 122 122 122 122 122
+ 122 122 122 122 122 122 122 122 122 122 122
+ 122 122 122 122 122 122 122 122 122 122 122
+-- Testbed end block:
diff --git a/systemtest/testdata/caset1/cond2.ql b/systemtest/testdata/caset1/cond2.ql
new file mode 100644
index 0000000..75ee59a
--- /dev/null
+++ b/systemtest/testdata/caset1/cond2.ql
@@ -0,0 +1,4 @@
+-- sum cell values and add result by induction
+
+select a + condense + over x in sdom(a) using a[x]
+from ImgCharA as a
diff --git a/systemtest/testdata/caset1/cond2.ql.java.out b/systemtest/testdata/caset1/cond2.ql.java.out
new file mode 100644
index 0000000..8504c07
--- /dev/null
+++ b/systemtest/testdata/caset1/cond2.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 122 \ No newline at end of file
diff --git a/systemtest/testdata/caset1/cond2.ql.out b/systemtest/testdata/caset1/cond2.ql.out
new file mode 100644
index 0000000..873c469
--- /dev/null
+++ b/systemtest/testdata/caset1/cond2.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <char, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [0:10,0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+Image 2
+GMarray
+ Type Structure........: marray <char, [0:10,0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ 122 122 122 122 122 122 122 122 122 122 122
+ 122 122 122 122 122 122 122 122 122 122 122
+ 122 122 122 122 122 122 122 122 122 122 122
+ 122 122 122 122 122 122 122 122 122 122 122
+ 122 122 122 122 122 122 122 122 122 122 122
+ 122 122 122 122 122 122 122 122 122 122 122
+ 122 122 122 122 122 122 122 122 122 122 122
+ 122 122 122 122 122 122 122 122 122 122 122
+ 122 122 122 122 122 122 122 122 122 122 122
+ 122 122 122 122 122 122 122 122 122 122 122
+ 122 122 122 122 122 122 122 122 122 122 122
+-- Testbed end block:
diff --git a/systemtest/testdata/caset1/count1.ql b/systemtest/testdata/caset1/count1.ql
new file mode 100644
index 0000000..a6bf41b
--- /dev/null
+++ b/systemtest/testdata/caset1/count1.ql
@@ -0,0 +1,3 @@
+select marray x in [0:0] values count_cells( a >= 0 )
+from ImgCharA as a
+
diff --git a/systemtest/testdata/caset1/count1.ql.java.out b/systemtest/testdata/caset1/count1.ql.java.out
new file mode 100644
index 0000000..6e01fb6
--- /dev/null
+++ b/systemtest/testdata/caset1/count1.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayLong
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:15999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 0 0 0 0 0 0 0 121
+rasj.RasMArrayLong
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:15999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 0 0 0 0 0 0 0 121 \ No newline at end of file
diff --git a/systemtest/testdata/caset1/count1.ql.out b/systemtest/testdata/caset1/count1.ql.out
new file mode 100644
index 0000000..5b55f5e
--- /dev/null
+++ b/systemtest/testdata/caset1/count1.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <ulong, [0:0]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <ulong, [0:0]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:0]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 4
+ 121
+Image 2
+GMarray
+ Type Structure........: marray <ulong, [0:0]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:0]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 4
+ 121
+-- Testbed end block:
diff --git a/systemtest/testdata/caset1/count2.ql b/systemtest/testdata/caset1/count2.ql
new file mode 100644
index 0000000..da8e5eb
--- /dev/null
+++ b/systemtest/testdata/caset1/count2.ql
@@ -0,0 +1,3 @@
+select marray x in [0:0] values count_cells( a > 100 )
+from ImgCharD as a
+
diff --git a/systemtest/testdata/caset1/count2.ql.java.out b/systemtest/testdata/caset1/count2.ql.java.out
new file mode 100644
index 0000000..ef66475
--- /dev/null
+++ b/systemtest/testdata/caset1/count2.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayLong
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:15999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 0 0 0 0 0 0 0 20 \ No newline at end of file
diff --git a/systemtest/testdata/caset1/count2.ql.out b/systemtest/testdata/caset1/count2.ql.out
new file mode 100644
index 0000000..4470164
--- /dev/null
+++ b/systemtest/testdata/caset1/count2.ql.out
@@ -0,0 +1,14 @@
+-- Testbed line: result_type=set <marray <ulong, [0:0]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <ulong, [0:0]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:0]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 4
+ 20
+-- Testbed end block:
diff --git a/systemtest/testdata/caset1/count3.ql b/systemtest/testdata/caset1/count3.ql
new file mode 100644
index 0000000..b5b874f
--- /dev/null
+++ b/systemtest/testdata/caset1/count3.ql
@@ -0,0 +1,3 @@
+select marray x in [0:0] values count_cells( a >= 50 )
+from ImgULongC as a
+
diff --git a/systemtest/testdata/caset1/count3.ql.java.out b/systemtest/testdata/caset1/count3.ql.java.out
new file mode 100644
index 0000000..0c60742
--- /dev/null
+++ b/systemtest/testdata/caset1/count3.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayLong
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:15999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 0 0 0 0 0 0 0 50 \ No newline at end of file
diff --git a/systemtest/testdata/caset1/count3.ql.out b/systemtest/testdata/caset1/count3.ql.out
new file mode 100644
index 0000000..6d8ec71
--- /dev/null
+++ b/systemtest/testdata/caset1/count3.ql.out
@@ -0,0 +1,14 @@
+-- Testbed line: result_type=set <marray <ulong, [0:0]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <ulong, [0:0]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:0]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 4
+ 50
+-- Testbed end block:
diff --git a/systemtest/testdata/caset1/hist1.ql b/systemtest/testdata/caset1/hist1.ql
new file mode 100644
index 0000000..b601fa2
--- /dev/null
+++ b/systemtest/testdata/caset1/hist1.ql
@@ -0,0 +1,3 @@
+select marray n in [0:1] values
+ condense + over x in sdom(a) using (a[x] = n[0])*1c
+from ImgCharA as a
diff --git a/systemtest/testdata/caset1/hist1.ql.java.out b/systemtest/testdata/caset1/hist1.ql.java.out
new file mode 100644
index 0000000..6039b5e
--- /dev/null
+++ b/systemtest/testdata/caset1/hist1.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:1]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 2
+ 121 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:1]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 2
+ 0 121 \ No newline at end of file
diff --git a/systemtest/testdata/caset1/hist1.ql.out b/systemtest/testdata/caset1/hist1.ql.out
new file mode 100644
index 0000000..0f625b9
--- /dev/null
+++ b/systemtest/testdata/caset1/hist1.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <char, [0:1]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [0:1]>
+ Type Schema...........: marray< char >
+ Domain................: [0:1]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 2
+ 121 0
+Image 2
+GMarray
+ Type Structure........: marray <char, [0:1]>
+ Type Schema...........: marray< char >
+ Domain................: [0:1]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 2
+ 0 121
+-- Testbed end block:
diff --git a/systemtest/testdata/caset1/hist2.ql b/systemtest/testdata/caset1/hist2.ql
new file mode 100644
index 0000000..8b0c746
--- /dev/null
+++ b/systemtest/testdata/caset1/hist2.ql
@@ -0,0 +1,4 @@
+select marray n in [0:1] values
+ condense + over x in sdom(a) where a[x] = n[0] using 1c
+from ImgCharA as a
+
diff --git a/systemtest/testdata/caset1/hist2.ql.java.out b/systemtest/testdata/caset1/hist2.ql.java.out
new file mode 100644
index 0000000..6039b5e
--- /dev/null
+++ b/systemtest/testdata/caset1/hist2.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:1]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 2
+ 121 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:1]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 2
+ 0 121 \ No newline at end of file
diff --git a/systemtest/testdata/caset1/hist2.ql.out b/systemtest/testdata/caset1/hist2.ql.out
new file mode 100644
index 0000000..0f625b9
--- /dev/null
+++ b/systemtest/testdata/caset1/hist2.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <char, [0:1]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [0:1]>
+ Type Schema...........: marray< char >
+ Domain................: [0:1]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 2
+ 121 0
+Image 2
+GMarray
+ Type Structure........: marray <char, [0:1]>
+ Type Schema...........: marray< char >
+ Domain................: [0:1]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 2
+ 0 121
+-- Testbed end block:
diff --git a/systemtest/testdata/caset1/marray1.ql b/systemtest/testdata/caset1/marray1.ql
new file mode 100644
index 0000000..8ee87af
--- /dev/null
+++ b/systemtest/testdata/caset1/marray1.ql
@@ -0,0 +1,4 @@
+-- initialize marray with constant
+
+select marray x in sdom(a) values 1
+from ImgCharC as a
diff --git a/systemtest/testdata/caset1/marray1.ql.java.out b/systemtest/testdata/caset1/marray1.ql.java.out
new file mode 100644
index 0000000..f386b12
--- /dev/null
+++ b/systemtest/testdata/caset1/marray1.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayInteger
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:177,0:177]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 484
+ 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1
+rasj.RasMArrayInteger
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:177,0:177]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 484
+ 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 \ No newline at end of file
diff --git a/systemtest/testdata/caset1/marray1.ql.out b/systemtest/testdata/caset1/marray1.ql.out
new file mode 100644
index 0000000..3833bd7
--- /dev/null
+++ b/systemtest/testdata/caset1/marray1.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <long, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <long, [0:10,0:10]>
+ Type Schema...........: marray< long >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: long
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 484
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+Image 2
+GMarray
+ Type Structure........: marray <long, [0:10,0:10]>
+ Type Schema...........: marray< long >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: long
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 484
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+-- Testbed end block:
diff --git a/systemtest/testdata/caset1/marray2.ql.out b/systemtest/testdata/caset1/marray2.ql.out
new file mode 100644
index 0000000..db49fb7
--- /dev/null
+++ b/systemtest/testdata/caset1/marray2.ql.out
@@ -0,0 +1,23 @@
+-- Testbed line: result_type=set <marray <ulong, [0:9,0:9]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <ulong, [0:9,0:9]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:9,0:9]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 400
+ 0 1 2 3 4 5 6 7 8 9
+ 10 11 12 13 14 15 16 17 18 19
+ 20 21 22 23 24 25 26 27 28 29
+ 30 31 32 33 34 35 36 37 38 39
+ 40 41 42 43 44 45 46 47 48 49
+ 50 51 52 53 54 55 56 57 58 59
+ 60 61 62 63 64 65 66 67 68 69
+ 70 71 72 73 74 75 76 77 78 79
+ 80 81 82 83 84 85 86 87 88 89
+ 90 91 92 93 94 95 96 97 98 99
+-- Testbed end block:
diff --git a/systemtest/testdata/caset1/marray3.ql.out b/systemtest/testdata/caset1/marray3.ql.out
new file mode 100644
index 0000000..312dbd1
--- /dev/null
+++ b/systemtest/testdata/caset1/marray3.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <char, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [0:10,0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+Image 2
+GMarray
+ Type Structure........: marray <char, [0:10,0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ 2 2 2 2 2 2 2 2 2 2 2
+ 2 2 2 2 2 2 2 2 2 2 2
+ 2 2 2 2 2 2 2 2 2 2 2
+ 2 2 2 2 2 2 2 2 2 2 2
+ 2 2 2 2 2 2 2 2 2 2 2
+ 2 2 2 2 2 2 2 2 2 2 2
+ 2 2 2 2 2 2 2 2 2 2 2
+ 2 2 2 2 2 2 2 2 2 2 2
+ 2 2 2 2 2 2 2 2 2 2 2
+ 2 2 2 2 2 2 2 2 2 2 2
+ 2 2 2 2 2 2 2 2 2 2 2
+-- Testbed end block:
diff --git a/systemtest/testdata/caset1/marray4.ql b/systemtest/testdata/caset1/marray4.ql
new file mode 100644
index 0000000..4818975
--- /dev/null
+++ b/systemtest/testdata/caset1/marray4.ql
@@ -0,0 +1,4 @@
+-- mirror mdd objects with marray
+
+select marray x in sdom(a) values a[ sdom(a)[0].hi-x[0], x[1] ]
+from ImgULongC as a
diff --git a/systemtest/testdata/caset1/marray4.ql.java.out b/systemtest/testdata/caset1/marray4.ql.java.out
new file mode 100644
index 0000000..6045e9a
--- /dev/null
+++ b/systemtest/testdata/caset1/marray4.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayLong
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:9,0:9]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 800
+ 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 19 0 0 0 0 0 0 0 29 0 0 0 0 0 0 0 39 0 0 0 0 0 0 0 49 0 0 0 0 0 0 0 59 0 0 0 0 0 0 0 69 0 0 0 0 0 0 0 79 0 0 0 0 0 0 0 89 0 0 0 0 0 0 0 99 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 18 0 0 0 0 0 0 0 28 0 0 0 0 0 0 0 38 0 0 0 0 0 0 0 48 0 0 0 0 0 0 0 58 0 0 0 0 0 0 0 68 0 0 0 0 0 0 0 78 0 0 0 0 0 0 0 88 0 0 0 0 0 0 0 98 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 27 0 0 0 0 0 0 0 37 0 0 0 0 0 0 0 47 0 0 0 0 0 0 0 57 0 0 0 0 0 0 0 67 0 0 0 0 0 0 0 77 0 0 0 0 0 0 0 87 0 0 0 0 0 0 0 97 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 16 0 0 0 0 0 0 0 26 0 0 0 0 0 0 0 36 0 0 0 0 0 0 0 46 0 0 0 0 0 0 0 56 0 0 0 0 0 0 0 66 0 0 0 0 0 0 0 76 0 0 0 0 0 0 0 86 0 0 0 0 0 0 0 96 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 15 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 35 0 0 0 0 0 0 0 45 0 0 0 0 0 0 0 55 0 0 0 0 0 0 0 65 0 0 0 0 0 0 0 75 0 0 0 0 0 0 0 85 0 0 0 0 0 0 0 95 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 14 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 34 0 0 0 0 0 0 0 44 0 0 0 0 0 0 0 54 0 0 0 0 0 0 0 64 0 0 0 0 0 0 0 74 0 0 0 0 0 0 0 84 0 0 0 0 0 0 0 94 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 13 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 33 0 0 0 0 0 0 0 43 0 0 0 0 0 0 0 53 0 0 0 0 0 0 0 63 0 0 0 0 0 0 0 73 0 0 0 0 0 0 0 83 0 0 0 0 0 0 0 93 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 12 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 32 0 0 0 0 0 0 0 42 0 0 0 0 0 0 0 52 0 0 0 0 0 0 0 62 0 0 0 0 0 0 0 72 0 0 0 0 0 0 0 82 0 0 0 0 0 0 0 92 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 11 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 31 0 0 0 0 0 0 0 41 0 0 0 0 0 0 0 51 0 0 0 0 0 0 0 61 0 0 0 0 0 0 0 71 0 0 0 0 0 0 0 81 0 0 0 0 0 0 0 91 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 20 0 0 0 0 0 0 0 30 0 0 0 0 0 0 0 40 0 0 0 0 0 0 0 50 0 0 0 0 0 0 0 60 0 0 0 0 0 0 0 70 0 0 0 0 0 0 0 80 0 0 0 0 0 0 0 90 \ No newline at end of file
diff --git a/systemtest/testdata/caset1/marray4.ql.out b/systemtest/testdata/caset1/marray4.ql.out
new file mode 100644
index 0000000..148c08f
--- /dev/null
+++ b/systemtest/testdata/caset1/marray4.ql.out
@@ -0,0 +1,23 @@
+-- Testbed line: result_type=set <marray <ulong, [0:9,0:9]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <ulong, [0:9,0:9]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:9,0:9]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 400
+ 9 8 7 6 5 4 3 2 1 0
+ 19 18 17 16 15 14 13 12 11 10
+ 29 28 27 26 25 24 23 22 21 20
+ 39 38 37 36 35 34 33 32 31 30
+ 49 48 47 46 45 44 43 42 41 40
+ 59 58 57 56 55 54 53 52 51 50
+ 69 68 67 66 65 64 63 62 61 60
+ 79 78 77 76 75 74 73 72 71 70
+ 89 88 87 86 85 84 83 82 81 80
+ 99 98 97 96 95 94 93 92 91 90
+-- Testbed end block:
diff --git a/systemtest/testdata/caset1/olap1.ql b/systemtest/testdata/caset1/olap1.ql
new file mode 100644
index 0000000..0594e11
--- /dev/null
+++ b/systemtest/testdata/caset1/olap1.ql
@@ -0,0 +1,4 @@
+select marray x in [0:1,0:1] values
+ condense + over y in [0:6] using a[x[0]*7+y[0],x[1]]*1l
+from OlapCharA as a
+
diff --git a/systemtest/testdata/caset1/olap1.ql.java.out b/systemtest/testdata/caset1/olap1.ql.java.out
new file mode 100644
index 0000000..a2fd1cc
--- /dev/null
+++ b/systemtest/testdata/caset1/olap1.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayInteger
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:1,0:1]
+ TilingDomain..........: [0:177,0:177]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 16
+ 0 0 0 21 0 0 0 119 0 0 0 70 0 0 0 -88 \ No newline at end of file
diff --git a/systemtest/testdata/caset1/olap1.ql.out b/systemtest/testdata/caset1/olap1.ql.out
new file mode 100644
index 0000000..91e70a1
--- /dev/null
+++ b/systemtest/testdata/caset1/olap1.ql.out
@@ -0,0 +1,15 @@
+-- Testbed line: result_type=set <marray <long, [0:1,0:1]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <long, [0:1,0:1]>
+ Type Schema...........: marray< long >
+ Domain................: [0:1,0:1]
+ Base Type Schema......: long
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 16
+ 21 70
+ 119 168
+-- Testbed end block:
diff --git a/systemtest/testdata/caset1/olap2.ql b/systemtest/testdata/caset1/olap2.ql
new file mode 100644
index 0000000..4c1b962
--- /dev/null
+++ b/systemtest/testdata/caset1/olap2.ql
@@ -0,0 +1,4 @@
+select marray x in [0:6,0:1] values
+ condense + over y in [0:1] using (a[x[0]+y[0]*7,x[1]])
+from OlapCharA as a
+
diff --git a/systemtest/testdata/caset1/olap2.ql.java.out b/systemtest/testdata/caset1/olap2.ql.java.out
new file mode 100644
index 0000000..1ddae78
--- /dev/null
+++ b/systemtest/testdata/caset1/olap2.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:6,0:1]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 14
+ 7 35 9 37 11 39 13 41 15 43 17 45 19 47 \ No newline at end of file
diff --git a/systemtest/testdata/caset1/olap2.ql.out b/systemtest/testdata/caset1/olap2.ql.out
new file mode 100644
index 0000000..fe211de
--- /dev/null
+++ b/systemtest/testdata/caset1/olap2.ql.out
@@ -0,0 +1,15 @@
+-- Testbed line: result_type=set <marray <char, [0:6,0:1]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [0:6,0:1]>
+ Type Schema...........: marray< char >
+ Domain................: [0:6,0:1]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 14
+ 7 9 11 13 15 17 19
+ 35 37 39 41 43 45 47
+-- Testbed end block:
diff --git a/systemtest/testdata/cast/cast_01.ql b/systemtest/testdata/cast/cast_01.ql
new file mode 100644
index 0000000..34bc3ec
--- /dev/null
+++ b/systemtest/testdata/cast/cast_01.ql
@@ -0,0 +1,2 @@
+
+ select (bool)3.14 from ImgCharA -- T
diff --git a/systemtest/testdata/cast/cast_01.ql.java.out b/systemtest/testdata/cast/cast_01.ql.java.out
new file mode 100644
index 0000000..dc7b54a
--- /dev/null
+++ b/systemtest/testdata/cast/cast_01.ql.java.out
@@ -0,0 +1 @@
+33 \ No newline at end of file
diff --git a/systemtest/testdata/cast/cast_01.ql.out b/systemtest/testdata/cast/cast_01.ql.out
new file mode 100644
index 0000000..89db772
--- /dev/null
+++ b/systemtest/testdata/cast/cast_01.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<bool>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: T
+Element 2: T
+-- Testbed end block:
diff --git a/systemtest/testdata/cast/cast_02.ql b/systemtest/testdata/cast/cast_02.ql
new file mode 100644
index 0000000..3e6bba0
--- /dev/null
+++ b/systemtest/testdata/cast/cast_02.ql
@@ -0,0 +1,2 @@
+
+ select (char)exp(1) from ImgCharA -- 2
diff --git a/systemtest/testdata/cast/cast_02.ql.java.out b/systemtest/testdata/cast/cast_02.ql.java.out
new file mode 100644
index 0000000..8fdd954
--- /dev/null
+++ b/systemtest/testdata/cast/cast_02.ql.java.out
@@ -0,0 +1 @@
+22 \ No newline at end of file
diff --git a/systemtest/testdata/cast/cast_02.ql.out b/systemtest/testdata/cast/cast_02.ql.out
new file mode 100644
index 0000000..19e8c1f
--- /dev/null
+++ b/systemtest/testdata/cast/cast_02.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<char>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 2
+Element 2: 2
+-- Testbed end block:
diff --git a/systemtest/testdata/cast/cast_03.ql b/systemtest/testdata/cast/cast_03.ql
new file mode 100644
index 0000000..76b9211
--- /dev/null
+++ b/systemtest/testdata/cast/cast_03.ql
@@ -0,0 +1,2 @@
+
+ select (octet)sqrt((long)2.4) from ImgCharA -- 1
diff --git a/systemtest/testdata/cast/cast_03.ql.java.out b/systemtest/testdata/cast/cast_03.ql.java.out
new file mode 100644
index 0000000..9d60796
--- /dev/null
+++ b/systemtest/testdata/cast/cast_03.ql.java.out
@@ -0,0 +1 @@
+11 \ No newline at end of file
diff --git a/systemtest/testdata/cast/cast_03.ql.out b/systemtest/testdata/cast/cast_03.ql.out
new file mode 100644
index 0000000..4c7aef4
--- /dev/null
+++ b/systemtest/testdata/cast/cast_03.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<octet>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 1
+Element 2: 1
+-- Testbed end block:
diff --git a/systemtest/testdata/cast/cast_04.ql b/systemtest/testdata/cast/cast_04.ql
new file mode 100644
index 0000000..7367f5b
--- /dev/null
+++ b/systemtest/testdata/cast/cast_04.ql
@@ -0,0 +1,2 @@
+
+ select (short)3.14 from ImgCharA -- 3
diff --git a/systemtest/testdata/cast/cast_04.ql.java.out b/systemtest/testdata/cast/cast_04.ql.java.out
new file mode 100644
index 0000000..dc7b54a
--- /dev/null
+++ b/systemtest/testdata/cast/cast_04.ql.java.out
@@ -0,0 +1 @@
+33 \ No newline at end of file
diff --git a/systemtest/testdata/cast/cast_04.ql.out b/systemtest/testdata/cast/cast_04.ql.out
new file mode 100644
index 0000000..2dbd161
--- /dev/null
+++ b/systemtest/testdata/cast/cast_04.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<short>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 3
+Element 2: 3
+-- Testbed end block:
diff --git a/systemtest/testdata/cast/cast_05.ql b/systemtest/testdata/cast/cast_05.ql
new file mode 100644
index 0000000..7423782
--- /dev/null
+++ b/systemtest/testdata/cast/cast_05.ql
@@ -0,0 +1,2 @@
+
+ select (unsigned short)3.14 from ImgCharA -- 3
diff --git a/systemtest/testdata/cast/cast_05.ql.java.out b/systemtest/testdata/cast/cast_05.ql.java.out
new file mode 100644
index 0000000..dc7b54a
--- /dev/null
+++ b/systemtest/testdata/cast/cast_05.ql.java.out
@@ -0,0 +1 @@
+33 \ No newline at end of file
diff --git a/systemtest/testdata/cast/cast_05.ql.out b/systemtest/testdata/cast/cast_05.ql.out
new file mode 100644
index 0000000..a253c3b
--- /dev/null
+++ b/systemtest/testdata/cast/cast_05.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<ushort>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 3
+Element 2: 3
+-- Testbed end block:
diff --git a/systemtest/testdata/cast/cast_06.ql b/systemtest/testdata/cast/cast_06.ql
new file mode 100644
index 0000000..2dd1568
--- /dev/null
+++ b/systemtest/testdata/cast/cast_06.ql
@@ -0,0 +1,2 @@
+
+ select (long)3.14 from ImgCharA -- 3
diff --git a/systemtest/testdata/cast/cast_06.ql.java.out b/systemtest/testdata/cast/cast_06.ql.java.out
new file mode 100644
index 0000000..dc7b54a
--- /dev/null
+++ b/systemtest/testdata/cast/cast_06.ql.java.out
@@ -0,0 +1 @@
+33 \ No newline at end of file
diff --git a/systemtest/testdata/cast/cast_06.ql.out b/systemtest/testdata/cast/cast_06.ql.out
new file mode 100644
index 0000000..58af424
--- /dev/null
+++ b/systemtest/testdata/cast/cast_06.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<long>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 3
+Element 2: 3
+-- Testbed end block:
diff --git a/systemtest/testdata/cast/cast_07.ql b/systemtest/testdata/cast/cast_07.ql
new file mode 100644
index 0000000..84b7604
--- /dev/null
+++ b/systemtest/testdata/cast/cast_07.ql
@@ -0,0 +1,2 @@
+
+ select (unsigned long)3.14 from ImgCharA -- 3
diff --git a/systemtest/testdata/cast/cast_07.ql.java.out b/systemtest/testdata/cast/cast_07.ql.java.out
new file mode 100644
index 0000000..dc7b54a
--- /dev/null
+++ b/systemtest/testdata/cast/cast_07.ql.java.out
@@ -0,0 +1 @@
+33 \ No newline at end of file
diff --git a/systemtest/testdata/cast/cast_07.ql.out b/systemtest/testdata/cast/cast_07.ql.out
new file mode 100644
index 0000000..908e61c
--- /dev/null
+++ b/systemtest/testdata/cast/cast_07.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<ulong>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 3
+Element 2: 3
+-- Testbed end block:
diff --git a/systemtest/testdata/cast/cast_08.ql b/systemtest/testdata/cast/cast_08.ql
new file mode 100644
index 0000000..84b7604
--- /dev/null
+++ b/systemtest/testdata/cast/cast_08.ql
@@ -0,0 +1,2 @@
+
+ select (unsigned long)3.14 from ImgCharA -- 3
diff --git a/systemtest/testdata/cast/cast_08.ql.java.out b/systemtest/testdata/cast/cast_08.ql.java.out
new file mode 100644
index 0000000..dc7b54a
--- /dev/null
+++ b/systemtest/testdata/cast/cast_08.ql.java.out
@@ -0,0 +1 @@
+33 \ No newline at end of file
diff --git a/systemtest/testdata/cast/cast_08.ql.out b/systemtest/testdata/cast/cast_08.ql.out
new file mode 100644
index 0000000..908e61c
--- /dev/null
+++ b/systemtest/testdata/cast/cast_08.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<ulong>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 3
+Element 2: 3
+-- Testbed end block:
diff --git a/systemtest/testdata/cast/cast_09.ql b/systemtest/testdata/cast/cast_09.ql
new file mode 100644
index 0000000..7bbba5f
--- /dev/null
+++ b/systemtest/testdata/cast/cast_09.ql
@@ -0,0 +1,2 @@
+
+ select (float)1 from ImgCharA -- 1
diff --git a/systemtest/testdata/cast/cast_09.ql.java.out b/systemtest/testdata/cast/cast_09.ql.java.out
new file mode 100644
index 0000000..85aae69
--- /dev/null
+++ b/systemtest/testdata/cast/cast_09.ql.java.out
@@ -0,0 +1 @@
+1.01.0 \ No newline at end of file
diff --git a/systemtest/testdata/cast/cast_09.ql.out b/systemtest/testdata/cast/cast_09.ql.out
new file mode 100644
index 0000000..5fa7d5a
--- /dev/null
+++ b/systemtest/testdata/cast/cast_09.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<float>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 1
+Element 2: 1
+-- Testbed end block:
diff --git a/systemtest/testdata/cast/cast_10.ql b/systemtest/testdata/cast/cast_10.ql
new file mode 100644
index 0000000..2bf7254
--- /dev/null
+++ b/systemtest/testdata/cast/cast_10.ql
@@ -0,0 +1,2 @@
+
+ select (double)1 from ImgCharA -- 1
diff --git a/systemtest/testdata/cast/cast_10.ql.java.out b/systemtest/testdata/cast/cast_10.ql.java.out
new file mode 100644
index 0000000..85aae69
--- /dev/null
+++ b/systemtest/testdata/cast/cast_10.ql.java.out
@@ -0,0 +1 @@
+1.01.0 \ No newline at end of file
diff --git a/systemtest/testdata/cast/cast_10.ql.out b/systemtest/testdata/cast/cast_10.ql.out
new file mode 100644
index 0000000..5b5eff0
--- /dev/null
+++ b/systemtest/testdata/cast/cast_10.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 1
+Element 2: 1
+-- Testbed end block:
diff --git a/systemtest/testdata/cast/cast_11.ql b/systemtest/testdata/cast/cast_11.ql
new file mode 100644
index 0000000..817164f
--- /dev/null
+++ b/systemtest/testdata/cast/cast_11.ql
@@ -0,0 +1,2 @@
+
+ select (long)true from ImgCharA -- 1
diff --git a/systemtest/testdata/cast/cast_11.ql.java.out b/systemtest/testdata/cast/cast_11.ql.java.out
new file mode 100644
index 0000000..9d60796
--- /dev/null
+++ b/systemtest/testdata/cast/cast_11.ql.java.out
@@ -0,0 +1 @@
+11 \ No newline at end of file
diff --git a/systemtest/testdata/cast/cast_11.ql.out b/systemtest/testdata/cast/cast_11.ql.out
new file mode 100644
index 0000000..5f11d14
--- /dev/null
+++ b/systemtest/testdata/cast/cast_11.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<long>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 1
+Element 2: 1
+-- Testbed end block:
diff --git a/systemtest/testdata/cast/cast_12.ql b/systemtest/testdata/cast/cast_12.ql
new file mode 100644
index 0000000..d4b8870
--- /dev/null
+++ b/systemtest/testdata/cast/cast_12.ql
@@ -0,0 +1,2 @@
+
+ select (float)true from ImgCharA -- 1
diff --git a/systemtest/testdata/cast/cast_12.ql.java.out b/systemtest/testdata/cast/cast_12.ql.java.out
new file mode 100644
index 0000000..85aae69
--- /dev/null
+++ b/systemtest/testdata/cast/cast_12.ql.java.out
@@ -0,0 +1 @@
+1.01.0 \ No newline at end of file
diff --git a/systemtest/testdata/cast/cast_12.ql.out b/systemtest/testdata/cast/cast_12.ql.out
new file mode 100644
index 0000000..5fa7d5a
--- /dev/null
+++ b/systemtest/testdata/cast/cast_12.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<float>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 1
+Element 2: 1
+-- Testbed end block:
diff --git a/systemtest/testdata/cast/cast_13.ql b/systemtest/testdata/cast/cast_13.ql
new file mode 100644
index 0000000..135bd52
--- /dev/null
+++ b/systemtest/testdata/cast/cast_13.ql
@@ -0,0 +1,2 @@
+
+ select (float)count_cells((bool)a) from ImgCharA as a --
diff --git a/systemtest/testdata/cast/cast_13.ql.java.out b/systemtest/testdata/cast/cast_13.ql.java.out
new file mode 100644
index 0000000..19f508f
--- /dev/null
+++ b/systemtest/testdata/cast/cast_13.ql.java.out
@@ -0,0 +1 @@
+0.0121.0 \ No newline at end of file
diff --git a/systemtest/testdata/cast/cast_13.ql.out b/systemtest/testdata/cast/cast_13.ql.out
new file mode 100644
index 0000000..a20d8ee
--- /dev/null
+++ b/systemtest/testdata/cast/cast_13.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<float>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 0
+Element 2: 121
+-- Testbed end block:
diff --git a/systemtest/testdata/cast/cast_14.ql b/systemtest/testdata/cast/cast_14.ql
new file mode 100644
index 0000000..cab030c
--- /dev/null
+++ b/systemtest/testdata/cast/cast_14.ql
@@ -0,0 +1 @@
+select count_cells(((bool)a).red) from ImgRGBA as a -- 121
diff --git a/systemtest/testdata/cast/cast_14.ql.java.out b/systemtest/testdata/cast/cast_14.ql.java.out
new file mode 100644
index 0000000..e81ca37
--- /dev/null
+++ b/systemtest/testdata/cast/cast_14.ql.java.out
@@ -0,0 +1 @@
+121121 \ No newline at end of file
diff --git a/systemtest/testdata/cast/cast_14.ql.out b/systemtest/testdata/cast/cast_14.ql.out
new file mode 100644
index 0000000..0c2802d
--- /dev/null
+++ b/systemtest/testdata/cast/cast_14.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<ulong>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 121
+Element 2: 121
+-- Testbed end block:
diff --git a/systemtest/testdata/cast/cast_15.ql b/systemtest/testdata/cast/cast_15.ql
new file mode 100644
index 0000000..2f00802
--- /dev/null
+++ b/systemtest/testdata/cast/cast_15.ql
@@ -0,0 +1,5 @@
+select (
+ 2 * { 1, { 0, 0.3, 1.3 } } +
+ 4 * { 3, { -1, 0f, 1f } }
+ )
+from ImgCharA as a -- { 14, { -4, 0.6, 6.6 } }
diff --git a/systemtest/testdata/cast/cast_15.ql.java.out b/systemtest/testdata/cast/cast_15.ql.java.out
new file mode 100644
index 0000000..b4dc813
--- /dev/null
+++ b/systemtest/testdata/cast/cast_15.ql.java.out
@@ -0,0 +1,4 @@
+
+ RasRuntimeException: Exception: Base type typeName:
+ typeID: 0
+ as RasCollectionType is not supported yet. \ No newline at end of file
diff --git a/systemtest/testdata/cast/cast_15.ql.out b/systemtest/testdata/cast/cast_15.ql.out
new file mode 100644
index 0000000..bf9cea6
--- /dev/null
+++ b/systemtest/testdata/cast/cast_15.ql.out
@@ -0,0 +1,8 @@
+-- Testbed line: result_type=set<struct { long 0, struct { long 0, float 1, float 2 } 1 }>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: { 14, { -4, 0.6, 6.6 }
+ }
+Element 2: { 14, { -4, 0.6, 6.6 }
+ }
+-- Testbed end block:
diff --git a/systemtest/testdata/cast/cast_16.ql b/systemtest/testdata/cast/cast_16.ql
new file mode 100644
index 0000000..805beba
--- /dev/null
+++ b/systemtest/testdata/cast/cast_16.ql
@@ -0,0 +1,5 @@
+select (octet)(
+ 2 * { 1, { 0, 0.3, 1.3 } } +
+ 4 * { 3, { -1, 0f, 1f } }
+ )
+from ImgCharA as a -- {14, {-4, 0, 6} } }
diff --git a/systemtest/testdata/cast/cast_16.ql.java.out b/systemtest/testdata/cast/cast_16.ql.java.out
new file mode 100644
index 0000000..b4dc813
--- /dev/null
+++ b/systemtest/testdata/cast/cast_16.ql.java.out
@@ -0,0 +1,4 @@
+
+ RasRuntimeException: Exception: Base type typeName:
+ typeID: 0
+ as RasCollectionType is not supported yet. \ No newline at end of file
diff --git a/systemtest/testdata/cast/cast_16.ql.out b/systemtest/testdata/cast/cast_16.ql.out
new file mode 100644
index 0000000..1750992
--- /dev/null
+++ b/systemtest/testdata/cast/cast_16.ql.out
@@ -0,0 +1,8 @@
+-- Testbed line: result_type=set<struct { octet 0, struct { octet 0, octet 1, octet 2 } 1 }>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: { 14, { -4, 0, 6 }
+ }
+Element 2: { 14, { -4, 0, 6 }
+ }
+-- Testbed end block:
diff --git a/systemtest/testdata/cast/cast_17.ql b/systemtest/testdata/cast/cast_17.ql
new file mode 100644
index 0000000..752b10a
--- /dev/null
+++ b/systemtest/testdata/cast/cast_17.ql
@@ -0,0 +1,5 @@
+select (char)(
+ 2 * { 1, { 0, 0.3, 1.3 } } +
+ 4 * { 3, { -1, 0f, 1f } }
+ )
+from ImgCharA as a -- { 14, { 255, 0, 6 } }
diff --git a/systemtest/testdata/cast/cast_17.ql.java.out b/systemtest/testdata/cast/cast_17.ql.java.out
new file mode 100644
index 0000000..b4dc813
--- /dev/null
+++ b/systemtest/testdata/cast/cast_17.ql.java.out
@@ -0,0 +1,4 @@
+
+ RasRuntimeException: Exception: Base type typeName:
+ typeID: 0
+ as RasCollectionType is not supported yet. \ No newline at end of file
diff --git a/systemtest/testdata/cast/cast_17.ql.out b/systemtest/testdata/cast/cast_17.ql.out
new file mode 100644
index 0000000..1996a23
--- /dev/null
+++ b/systemtest/testdata/cast/cast_17.ql.out
@@ -0,0 +1,8 @@
+-- Testbed line: result_type=set<struct { char 0, struct { char 0, char 1, char 2 } 1 }>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: { 14, { 255, 0, 6 }
+ }
+Element 2: { 14, { 255, 0, 6 }
+ }
+-- Testbed end block:
diff --git a/systemtest/testdata/cast/cast_18.ql b/systemtest/testdata/cast/cast_18.ql
new file mode 100644
index 0000000..a26f7a9
--- /dev/null
+++ b/systemtest/testdata/cast/cast_18.ql
@@ -0,0 +1,5 @@
+select (bool)(
+ 2 * { 1, { 0, 0.3, 1.3 } } +
+ 4 * { 3, { -1, 0f, 1f } }
+ )
+from ImgCharA as a -- { T, { T, F, T } }
diff --git a/systemtest/testdata/cast/cast_18.ql.java.out b/systemtest/testdata/cast/cast_18.ql.java.out
new file mode 100644
index 0000000..b4dc813
--- /dev/null
+++ b/systemtest/testdata/cast/cast_18.ql.java.out
@@ -0,0 +1,4 @@
+
+ RasRuntimeException: Exception: Base type typeName:
+ typeID: 0
+ as RasCollectionType is not supported yet. \ No newline at end of file
diff --git a/systemtest/testdata/cast/cast_18.ql.out b/systemtest/testdata/cast/cast_18.ql.out
new file mode 100644
index 0000000..e459e73
--- /dev/null
+++ b/systemtest/testdata/cast/cast_18.ql.out
@@ -0,0 +1,8 @@
+-- Testbed line: result_type=set<struct { bool 0, struct { bool 0, bool 1, bool 2 } 1 }>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: { T, { T, F, T }
+ }
+Element 2: { T, { T, F, T }
+ }
+-- Testbed end block:
diff --git a/systemtest/testdata/complex/complex01.ql b/systemtest/testdata/complex/complex01.ql
new file mode 100644
index 0000000..25c08c5
--- /dev/null
+++ b/systemtest/testdata/complex/complex01.ql
@@ -0,0 +1 @@
+select complex(3.14, 10f) from ImgCharD -- complex1(3.14, 10) \ No newline at end of file
diff --git a/systemtest/testdata/complex/complex01.ql.java.out b/systemtest/testdata/complex/complex01.ql.java.out
new file mode 100644
index 0000000..b4dc813
--- /dev/null
+++ b/systemtest/testdata/complex/complex01.ql.java.out
@@ -0,0 +1,4 @@
+
+ RasRuntimeException: Exception: Base type typeName:
+ typeID: 0
+ as RasCollectionType is not supported yet. \ No newline at end of file
diff --git a/systemtest/testdata/complex/complex01.ql.out b/systemtest/testdata/complex/complex01.ql.out
new file mode 100644
index 0000000..37568f5
--- /dev/null
+++ b/systemtest/testdata/complex/complex01.ql.out
@@ -0,0 +1,5 @@
+-- Testbed line: result_type=set<complex>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Element 1: (3.14, 10)
+-- Testbed end block:
diff --git a/systemtest/testdata/complex/complex02.ql b/systemtest/testdata/complex/complex02.ql
new file mode 100644
index 0000000..5c62493
--- /dev/null
+++ b/systemtest/testdata/complex/complex02.ql
@@ -0,0 +1 @@
+select complex(3.14, 6.28f) + complex(100f, 200f) from ImgCharD -- complex1(103.14, 206.28) \ No newline at end of file
diff --git a/systemtest/testdata/complex/complex02.ql.java.out b/systemtest/testdata/complex/complex02.ql.java.out
new file mode 100644
index 0000000..b4dc813
--- /dev/null
+++ b/systemtest/testdata/complex/complex02.ql.java.out
@@ -0,0 +1,4 @@
+
+ RasRuntimeException: Exception: Base type typeName:
+ typeID: 0
+ as RasCollectionType is not supported yet. \ No newline at end of file
diff --git a/systemtest/testdata/complex/complex02.ql.out b/systemtest/testdata/complex/complex02.ql.out
new file mode 100644
index 0000000..a0487fd
--- /dev/null
+++ b/systemtest/testdata/complex/complex02.ql.out
@@ -0,0 +1,5 @@
+-- Testbed line: result_type=set<complex>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Element 1: (103.14, 206.28)
+-- Testbed end block:
diff --git a/systemtest/testdata/complex/complex03.ql b/systemtest/testdata/complex/complex03.ql
new file mode 100644
index 0000000..1f6c2d1
--- /dev/null
+++ b/systemtest/testdata/complex/complex03.ql
@@ -0,0 +1 @@
+select complex(3.14, 6.28f) - complex(100f, 200f) from ImgCharD -- complex1(-96.86, 193.72) \ No newline at end of file
diff --git a/systemtest/testdata/complex/complex03.ql.java.out b/systemtest/testdata/complex/complex03.ql.java.out
new file mode 100644
index 0000000..b4dc813
--- /dev/null
+++ b/systemtest/testdata/complex/complex03.ql.java.out
@@ -0,0 +1,4 @@
+
+ RasRuntimeException: Exception: Base type typeName:
+ typeID: 0
+ as RasCollectionType is not supported yet. \ No newline at end of file
diff --git a/systemtest/testdata/complex/complex03.ql.out b/systemtest/testdata/complex/complex03.ql.out
new file mode 100644
index 0000000..b477fe1
--- /dev/null
+++ b/systemtest/testdata/complex/complex03.ql.out
@@ -0,0 +1,5 @@
+-- Testbed line: result_type=set<complex>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Element 1: (-96.86, -193.72)
+-- Testbed end block:
diff --git a/systemtest/testdata/complex/complex04.ql b/systemtest/testdata/complex/complex04.ql
new file mode 100644
index 0000000..fa94e91
--- /dev/null
+++ b/systemtest/testdata/complex/complex04.ql
@@ -0,0 +1 @@
+select complex(10f, 20f) * complex(3.0, 4.0) from ImgCharD -- complex1(-50, 100) \ No newline at end of file
diff --git a/systemtest/testdata/complex/complex04.ql.java.out b/systemtest/testdata/complex/complex04.ql.java.out
new file mode 100644
index 0000000..b4dc813
--- /dev/null
+++ b/systemtest/testdata/complex/complex04.ql.java.out
@@ -0,0 +1,4 @@
+
+ RasRuntimeException: Exception: Base type typeName:
+ typeID: 0
+ as RasCollectionType is not supported yet. \ No newline at end of file
diff --git a/systemtest/testdata/complex/complex04.ql.out b/systemtest/testdata/complex/complex04.ql.out
new file mode 100644
index 0000000..d0407b2
--- /dev/null
+++ b/systemtest/testdata/complex/complex04.ql.out
@@ -0,0 +1,5 @@
+-- Testbed line: result_type=set<complex>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Element 1: (-50, 100)
+-- Testbed end block:
diff --git a/systemtest/testdata/complex/complex05.ql b/systemtest/testdata/complex/complex05.ql
new file mode 100644
index 0000000..9c6cab9
--- /dev/null
+++ b/systemtest/testdata/complex/complex05.ql
@@ -0,0 +1 @@
+select complex(10f, 20f) / complex(1.0, 2.0) from ImgCharD -- complex1(10, 0) \ No newline at end of file
diff --git a/systemtest/testdata/complex/complex05.ql.java.out b/systemtest/testdata/complex/complex05.ql.java.out
new file mode 100644
index 0000000..b4dc813
--- /dev/null
+++ b/systemtest/testdata/complex/complex05.ql.java.out
@@ -0,0 +1,4 @@
+
+ RasRuntimeException: Exception: Base type typeName:
+ typeID: 0
+ as RasCollectionType is not supported yet. \ No newline at end of file
diff --git a/systemtest/testdata/complex/complex05.ql.out b/systemtest/testdata/complex/complex05.ql.out
new file mode 100644
index 0000000..ddd98e6
--- /dev/null
+++ b/systemtest/testdata/complex/complex05.ql.out
@@ -0,0 +1,5 @@
+-- Testbed line: result_type=set<complex>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Element 1: (10, 0)
+-- Testbed end block:
diff --git a/systemtest/testdata/complex/complex06.ql b/systemtest/testdata/complex/complex06.ql
new file mode 100644
index 0000000..9f510c6
--- /dev/null
+++ b/systemtest/testdata/complex/complex06.ql
@@ -0,0 +1 @@
+select complex(3.14d, 6.28d) + complex(100d, 200d) from ImgCharD -- complex2(103.14, 206.28) \ No newline at end of file
diff --git a/systemtest/testdata/complex/complex06.ql.java.out b/systemtest/testdata/complex/complex06.ql.java.out
new file mode 100644
index 0000000..b4dc813
--- /dev/null
+++ b/systemtest/testdata/complex/complex06.ql.java.out
@@ -0,0 +1,4 @@
+
+ RasRuntimeException: Exception: Base type typeName:
+ typeID: 0
+ as RasCollectionType is not supported yet. \ No newline at end of file
diff --git a/systemtest/testdata/complex/complex06.ql.out b/systemtest/testdata/complex/complex06.ql.out
new file mode 100644
index 0000000..c9357dc
--- /dev/null
+++ b/systemtest/testdata/complex/complex06.ql.out
@@ -0,0 +1,5 @@
+-- Testbed line: result_type=set<complexd>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Element 1: (103.14, 206.28)
+-- Testbed end block:
diff --git a/systemtest/testdata/complex/complex07.ql b/systemtest/testdata/complex/complex07.ql
new file mode 100644
index 0000000..27e9b54
--- /dev/null
+++ b/systemtest/testdata/complex/complex07.ql
@@ -0,0 +1 @@
+select complex(3.14d, 6.28d) - complex(100d, 200d) from ImgCharD -- complex2(-96.86, 193.72) \ No newline at end of file
diff --git a/systemtest/testdata/complex/complex07.ql.java.out b/systemtest/testdata/complex/complex07.ql.java.out
new file mode 100644
index 0000000..b4dc813
--- /dev/null
+++ b/systemtest/testdata/complex/complex07.ql.java.out
@@ -0,0 +1,4 @@
+
+ RasRuntimeException: Exception: Base type typeName:
+ typeID: 0
+ as RasCollectionType is not supported yet. \ No newline at end of file
diff --git a/systemtest/testdata/complex/complex07.ql.out b/systemtest/testdata/complex/complex07.ql.out
new file mode 100644
index 0000000..e5b41ab
--- /dev/null
+++ b/systemtest/testdata/complex/complex07.ql.out
@@ -0,0 +1,5 @@
+-- Testbed line: result_type=set<complexd>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Element 1: (-96.86, -193.72)
+-- Testbed end block:
diff --git a/systemtest/testdata/complex/complex08.ql b/systemtest/testdata/complex/complex08.ql
new file mode 100644
index 0000000..3b89fae
--- /dev/null
+++ b/systemtest/testdata/complex/complex08.ql
@@ -0,0 +1 @@
+select complex(10d, 20d) * complex(3.0d, 4.0d) from ImgCharD -- complex2(-50, 100) \ No newline at end of file
diff --git a/systemtest/testdata/complex/complex08.ql.java.out b/systemtest/testdata/complex/complex08.ql.java.out
new file mode 100644
index 0000000..b4dc813
--- /dev/null
+++ b/systemtest/testdata/complex/complex08.ql.java.out
@@ -0,0 +1,4 @@
+
+ RasRuntimeException: Exception: Base type typeName:
+ typeID: 0
+ as RasCollectionType is not supported yet. \ No newline at end of file
diff --git a/systemtest/testdata/complex/complex08.ql.out b/systemtest/testdata/complex/complex08.ql.out
new file mode 100644
index 0000000..2575c9f
--- /dev/null
+++ b/systemtest/testdata/complex/complex08.ql.out
@@ -0,0 +1,5 @@
+-- Testbed line: result_type=set<complexd>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Element 1: (-50, 100)
+-- Testbed end block:
diff --git a/systemtest/testdata/complex/complex09.ql b/systemtest/testdata/complex/complex09.ql
new file mode 100644
index 0000000..847815a
--- /dev/null
+++ b/systemtest/testdata/complex/complex09.ql
@@ -0,0 +1 @@
+select complex(10d, 20d) / complex(1.0d, 2.0d) from ImgCharD -- complex2(10, 0) \ No newline at end of file
diff --git a/systemtest/testdata/complex/complex09.ql.java.out b/systemtest/testdata/complex/complex09.ql.java.out
new file mode 100644
index 0000000..b4dc813
--- /dev/null
+++ b/systemtest/testdata/complex/complex09.ql.java.out
@@ -0,0 +1,4 @@
+
+ RasRuntimeException: Exception: Base type typeName:
+ typeID: 0
+ as RasCollectionType is not supported yet. \ No newline at end of file
diff --git a/systemtest/testdata/complex/complex09.ql.out b/systemtest/testdata/complex/complex09.ql.out
new file mode 100644
index 0000000..a277bd1
--- /dev/null
+++ b/systemtest/testdata/complex/complex09.ql.out
@@ -0,0 +1,5 @@
+-- Testbed line: result_type=set<complexd>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Element 1: (10, 0)
+-- Testbed end block:
diff --git a/systemtest/testdata/complex/complex10.ql b/systemtest/testdata/complex/complex10.ql
new file mode 100644
index 0000000..811e04e
--- /dev/null
+++ b/systemtest/testdata/complex/complex10.ql
@@ -0,0 +1 @@
+select complex(10f, 20f) / complex(1.0d, 2.0d) from ImgCharD -- complex2(10, 0) \ No newline at end of file
diff --git a/systemtest/testdata/complex/complex10.ql.java.out b/systemtest/testdata/complex/complex10.ql.java.out
new file mode 100644
index 0000000..b4dc813
--- /dev/null
+++ b/systemtest/testdata/complex/complex10.ql.java.out
@@ -0,0 +1,4 @@
+
+ RasRuntimeException: Exception: Base type typeName:
+ typeID: 0
+ as RasCollectionType is not supported yet. \ No newline at end of file
diff --git a/systemtest/testdata/complex/complex10.ql.out b/systemtest/testdata/complex/complex10.ql.out
new file mode 100644
index 0000000..a277bd1
--- /dev/null
+++ b/systemtest/testdata/complex/complex10.ql.out
@@ -0,0 +1,5 @@
+-- Testbed line: result_type=set<complexd>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Element 1: (10, 0)
+-- Testbed end block:
diff --git a/systemtest/testdata/complex/complex11.ql b/systemtest/testdata/complex/complex11.ql
new file mode 100644
index 0000000..a9557b2
--- /dev/null
+++ b/systemtest/testdata/complex/complex11.ql
@@ -0,0 +1 @@
+select 10.0 / complex(1.0d, 2.0d) from ImgCharD -- complex2(2, -4) \ No newline at end of file
diff --git a/systemtest/testdata/complex/complex11.ql.java.out b/systemtest/testdata/complex/complex11.ql.java.out
new file mode 100644
index 0000000..b4dc813
--- /dev/null
+++ b/systemtest/testdata/complex/complex11.ql.java.out
@@ -0,0 +1,4 @@
+
+ RasRuntimeException: Exception: Base type typeName:
+ typeID: 0
+ as RasCollectionType is not supported yet. \ No newline at end of file
diff --git a/systemtest/testdata/complex/complex11.ql.out b/systemtest/testdata/complex/complex11.ql.out
new file mode 100644
index 0000000..428b61b
--- /dev/null
+++ b/systemtest/testdata/complex/complex11.ql.out
@@ -0,0 +1,5 @@
+-- Testbed line: result_type=set<complexd>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Element 1: (2, -4)
+-- Testbed end block:
diff --git a/systemtest/testdata/complex/complex12.ql b/systemtest/testdata/complex/complex12.ql
new file mode 100644
index 0000000..8a2166f
--- /dev/null
+++ b/systemtest/testdata/complex/complex12.ql
@@ -0,0 +1 @@
+select complex(10.0d, 20.0d) / 5 from ImgCharD -- complex2(2.0, 4.0) \ No newline at end of file
diff --git a/systemtest/testdata/complex/complex12.ql.java.out b/systemtest/testdata/complex/complex12.ql.java.out
new file mode 100644
index 0000000..b4dc813
--- /dev/null
+++ b/systemtest/testdata/complex/complex12.ql.java.out
@@ -0,0 +1,4 @@
+
+ RasRuntimeException: Exception: Base type typeName:
+ typeID: 0
+ as RasCollectionType is not supported yet. \ No newline at end of file
diff --git a/systemtest/testdata/complex/complex12.ql.out b/systemtest/testdata/complex/complex12.ql.out
new file mode 100644
index 0000000..0fed385
--- /dev/null
+++ b/systemtest/testdata/complex/complex12.ql.out
@@ -0,0 +1,5 @@
+-- Testbed line: result_type=set<complexd>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Element 1: (2, 4)
+-- Testbed end block:
diff --git a/systemtest/testdata/complex/complex13.ql b/systemtest/testdata/complex/complex13.ql
new file mode 100644
index 0000000..44ea5f5
--- /dev/null
+++ b/systemtest/testdata/complex/complex13.ql
@@ -0,0 +1 @@
+select a * complex(3.14, 6.28) from ImgCharD as a -- marray<complex1> \ No newline at end of file
diff --git a/systemtest/testdata/complex/complex13.ql.java.out b/systemtest/testdata/complex/complex13.ql.java.out
new file mode 100644
index 0000000..b749f3e
--- /dev/null
+++ b/systemtest/testdata/complex/complex13.ql.java.out
@@ -0,0 +1,2 @@
+
+ RasRuntimeException: Exception: RasType complex is unknown. \ No newline at end of file
diff --git a/systemtest/testdata/complex/complex13.ql.out b/systemtest/testdata/complex/complex13.ql.out
new file mode 100644
index 0000000..a70bec9
--- /dev/null
+++ b/systemtest/testdata/complex/complex13.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <complex, [0:10,0:10]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <complex, [0:10,0:10]>
+ Type Schema...........: marray< complex(float, float) >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: complex(float, float)
+ Base Type Length......: 8
+ Data format.......... : Array
+ Data size (bytes).... : 968
+(0, 0) (3.14, 6.28) (6.28, 12.56) (9.42, 18.84) (12.56, 25.12) (15.7, 31.4) (18.84, 37.68) (21.98, 43.96) (25.12, 50.24) (28.26, 56.52) (31.4, 62.8)
+(34.54, 69.08) (37.68, 75.36) (40.82, 81.64) (43.96, 87.92) (47.1, 94.2) (50.24, 100.48) (53.38, 106.76) (56.52, 113.04) (59.66, 119.32) (62.8, 125.6) (65.94, 131.88)
+(69.08, 138.16) (72.22, 144.44) (75.36, 150.72) (78.5, 157) (81.64, 163.28) (84.78, 169.56) (87.92, 175.84) (91.06, 182.12) (94.2, 188.4) (97.34, 194.68) (100.48, 200.96)
+(103.62, 207.24) (106.76, 213.52) (109.9, 219.8) (113.04, 226.08) (116.18, 232.36) (119.32, 238.64) (122.46, 244.92) (125.6, 251.2) (128.74, 257.48) (131.88, 263.76) (135.02, 270.04)
+(138.16, 276.32) (141.3, 282.6) (144.44, 288.88) (147.58, 295.16) (150.72, 301.44) (153.86, 307.72) (157, 314) (160.14, 320.28) (163.28, 326.56) (166.42, 332.84) (169.56, 339.12)
+(172.7, 345.4) (175.84, 351.68) (178.98, 357.96) (182.12, 364.24) (185.26, 370.52) (188.4, 376.8) (191.54, 383.08) (194.68, 389.36) (197.82, 395.64) (200.96, 401.92) (204.1, 408.2)
+(207.24, 414.48) (210.38, 420.76) (213.52, 427.04) (216.66, 433.32) (219.8, 439.6) (222.94, 445.88) (226.08, 452.16) (229.22, 458.44) (232.36, 464.72) (235.5, 471) (238.64, 477.28)
+(241.78, 483.56) (244.92, 489.84) (248.06, 496.12) (251.2, 502.4) (254.34, 508.68) (257.48, 514.96) (260.62, 521.24) (263.76, 527.52) (266.9, 533.8) (270.04, 540.08) (273.18, 546.36)
+(276.32, 552.64) (279.46, 558.92) (282.6, 565.2) (285.74, 571.48) (288.88, 577.76) (292.02, 584.04) (295.16, 590.32) (298.3, 596.6) (301.44, 602.88) (304.58, 609.16) (307.72, 615.44)
+(310.86, 621.72) (314, 628) (317.14, 634.28) (320.28, 640.56) (323.42, 646.84) (326.56, 653.12) (329.7, 659.4) (332.84, 665.68) (335.98, 671.96) (339.12, 678.24) (342.26, 684.52)
+(345.4, 690.8) (348.54, 697.08) (351.68, 703.36) (354.82, 709.64) (357.96, 715.92) (361.1, 722.2) (364.24, 728.48) (367.38, 734.76) (370.52, 741.04) (373.66, 747.32) (376.8, 753.6)
+-- Testbed end block:
diff --git a/systemtest/testdata/complex/complex14.ql b/systemtest/testdata/complex/complex14.ql
new file mode 100644
index 0000000..676b136
--- /dev/null
+++ b/systemtest/testdata/complex/complex14.ql
@@ -0,0 +1 @@
+select a * complex(3.14d, 6.28d) from ImgCharD as a -- marray<complex2> \ No newline at end of file
diff --git a/systemtest/testdata/complex/complex14.ql.java.out b/systemtest/testdata/complex/complex14.ql.java.out
new file mode 100644
index 0000000..5bd62a4
--- /dev/null
+++ b/systemtest/testdata/complex/complex14.ql.java.out
@@ -0,0 +1,2 @@
+
+ RasRuntimeException: Exception: RasType complexd is unknown. \ No newline at end of file
diff --git a/systemtest/testdata/complex/complex14.ql.out b/systemtest/testdata/complex/complex14.ql.out
new file mode 100644
index 0000000..af48217
--- /dev/null
+++ b/systemtest/testdata/complex/complex14.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <complexd, [0:10,0:10]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <complexd, [0:10,0:10]>
+ Type Schema...........: marray< complex(double, double) >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: complex(double, double)
+ Base Type Length......: 16
+ Data format.......... : Array
+ Data size (bytes).... : 1936
+(0, 0) (3.14, 6.28) (6.28, 12.56) (9.42, 18.84) (12.56, 25.12) (15.7, 31.4) (18.84, 37.68) (21.98, 43.96) (25.12, 50.24) (28.26, 56.52) (31.4, 62.8)
+(34.54, 69.08) (37.68, 75.36) (40.82, 81.64) (43.96, 87.92) (47.1, 94.2) (50.24, 100.48) (53.38, 106.76) (56.52, 113.04) (59.66, 119.32) (62.8, 125.6) (65.94, 131.88)
+(69.08, 138.16) (72.22, 144.44) (75.36, 150.72) (78.5, 157) (81.64, 163.28) (84.78, 169.56) (87.92, 175.84) (91.06, 182.12) (94.2, 188.4) (97.34, 194.68) (100.48, 200.96)
+(103.62, 207.24) (106.76, 213.52) (109.9, 219.8) (113.04, 226.08) (116.18, 232.36) (119.32, 238.64) (122.46, 244.92) (125.6, 251.2) (128.74, 257.48) (131.88, 263.76) (135.02, 270.04)
+(138.16, 276.32) (141.3, 282.6) (144.44, 288.88) (147.58, 295.16) (150.72, 301.44) (153.86, 307.72) (157, 314) (160.14, 320.28) (163.28, 326.56) (166.42, 332.84) (169.56, 339.12)
+(172.7, 345.4) (175.84, 351.68) (178.98, 357.96) (182.12, 364.24) (185.26, 370.52) (188.4, 376.8) (191.54, 383.08) (194.68, 389.36) (197.82, 395.64) (200.96, 401.92) (204.1, 408.2)
+(207.24, 414.48) (210.38, 420.76) (213.52, 427.04) (216.66, 433.32) (219.8, 439.6) (222.94, 445.88) (226.08, 452.16) (229.22, 458.44) (232.36, 464.72) (235.5, 471) (238.64, 477.28)
+(241.78, 483.56) (244.92, 489.84) (248.06, 496.12) (251.2, 502.4) (254.34, 508.68) (257.48, 514.96) (260.62, 521.24) (263.76, 527.52) (266.9, 533.8) (270.04, 540.08) (273.18, 546.36)
+(276.32, 552.64) (279.46, 558.92) (282.6, 565.2) (285.74, 571.48) (288.88, 577.76) (292.02, 584.04) (295.16, 590.32) (298.3, 596.6) (301.44, 602.88) (304.58, 609.16) (307.72, 615.44)
+(310.86, 621.72) (314, 628) (317.14, 634.28) (320.28, 640.56) (323.42, 646.84) (326.56, 653.12) (329.7, 659.4) (332.84, 665.68) (335.98, 671.96) (339.12, 678.24) (342.26, 684.52)
+(345.4, 690.8) (348.54, 697.08) (351.68, 703.36) (354.82, 709.64) (357.96, 715.92) (361.1, 722.2) (364.24, 728.48) (367.38, 734.76) (370.52, 741.04) (373.66, 747.32) (376.8, 753.6)
+-- Testbed end block:
diff --git a/systemtest/testdata/conversion/bmp1.ql b/systemtest/testdata/conversion/bmp1.ql
new file mode 100644
index 0000000..07350a8
--- /dev/null
+++ b/systemtest/testdata/conversion/bmp1.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <char, [0:1881]>>
+-- Testbed: result_elements=2
+
+SELECT bmp(a)
+FROM ImgCharA AS a
diff --git a/systemtest/testdata/conversion/bmp1.ql.java.out b/systemtest/testdata/conversion/bmp1.ql.java.out
new file mode 100644
index 0000000..c816b20
--- /dev/null
+++ b/systemtest/testdata/conversion/bmp1.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:103]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 104
+ 66 77 104 0 0 0 0 0 0 0 58 0 0 0 40 0 0 0 11 0 0 0 11 0 0 0 1 0 8 0 1 0 0 0 46 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 11 0 0 0 11 0 0 0 11 0 0 0 11 0 0 0 11 0 0 0 11 0 0 0 11 0 0 0 11 0 0 0 11 0 0 0 11 0 0 0 11 0 0 0 0 1
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:103]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 104
+ 66 77 104 0 0 0 0 0 0 0 58 0 0 0 40 0 0 0 11 0 0 0 11 0 0 0 1 0 8 0 1 0 0 0 46 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 1 0 11 0 0 0 11 0 0 0 11 0 0 0 11 0 0 0 11 0 0 0 11 0 0 0 11 0 0 0 11 0 0 0 11 0 0 0 11 0 0 0 11 0 0 0 0 1 \ No newline at end of file
diff --git a/systemtest/testdata/conversion/bmp1.ql.out b/systemtest/testdata/conversion/bmp1.ql.out
new file mode 100644
index 0000000..b227131
--- /dev/null
+++ b/systemtest/testdata/conversion/bmp1.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set <marray <char, [0:103]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1 written to image1.bmp
+Image 2 written to image2.bmp
+-- Testbed end block:
diff --git a/systemtest/testdata/conversion/bmp2.ql b/systemtest/testdata/conversion/bmp2.ql
new file mode 100644
index 0000000..6f1f911
--- /dev/null
+++ b/systemtest/testdata/conversion/bmp2.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <char, [0:1919]>>
+-- Testbed: result_elements=2
+
+SELECT bmp(a)
+FROM ImgRGBA AS a
diff --git a/systemtest/testdata/conversion/bmp2.ql.java.out b/systemtest/testdata/conversion/bmp2.ql.java.out
new file mode 100644
index 0000000..218dbc1
--- /dev/null
+++ b/systemtest/testdata/conversion/bmp2.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:449]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 450
+ 66 77 -62 1 0 0 0 0 0 0 54 0 0 0 40 0 0 0 11 0 0 0 11 0 0 0 1 0 24 0 0 0 0 0 -116 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 0 0 0 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 0 0 0 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 0 0 0 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 0 0 0 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 0 0 0 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 0 0 0 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 0 0 0 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 0 0 0 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 0 0 0 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 0 0 0 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 0 0 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:449]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 450
+ 66 77 -62 1 0 0 0 0 0 0 54 0 0 0 40 0 0 0 11 0 0 0 11 0 0 0 1 0 24 0 0 0 0 0 -116 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 0 0 0 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 0 0 0 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 0 0 0 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 0 0 0 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 0 0 0 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 0 0 0 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 0 0 0 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 0 0 0 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 0 0 0 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 0 0 0 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 3 2 1 0 0 0 \ No newline at end of file
diff --git a/systemtest/testdata/conversion/bmp2.ql.out b/systemtest/testdata/conversion/bmp2.ql.out
new file mode 100644
index 0000000..60a9f4f
--- /dev/null
+++ b/systemtest/testdata/conversion/bmp2.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set <marray <char, [0:449]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1 written to image1.bmp
+Image 2 written to image2.bmp
+-- Testbed end block:
diff --git a/systemtest/testdata/conversion/hdf1.ql b/systemtest/testdata/conversion/hdf1.ql
new file mode 100644
index 0000000..036fea5
--- /dev/null
+++ b/systemtest/testdata/conversion/hdf1.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <char, [0:1881]>>
+-- Testbed: result_elements=2
+
+SELECT hdf(a)
+FROM ImgCharA AS a
diff --git a/systemtest/testdata/conversion/hdf1.ql.java.out b/systemtest/testdata/conversion/hdf1.ql.java.out
new file mode 100644
index 0000000..f44d2c4
--- /dev/null
+++ b/systemtest/testdata/conversion/hdf1.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:2967]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 2968
+ 14 3 19 1 0 -56 0 0 0 0 0 30 0 1 0 0 9 106 0 0 0 92 2 -66 0 3 0 0 9 -58 0 0 0 121 7 -85 0 4 0 0 10 63 0 0 0 4 7 -86 0 4 0 0 10 67 0 0 0 60 7 -83 0 5 0 0 10 127 0 0 0 33 7 -85 0 6 0 0 10 -96 0 0 0 4 7 -86 0 6 0 0 10 -92 0 0 0 60 7 -83 0 7 0 0 10 -32 0 0 0 33 0 106 0 8 0 0 11 1 0 0 0 4 2 -67 0 8 0 0 11 5 0 0 0 22 2 -48 0 2 0 0 11 27 0 0 0 16 7 -83 0 9 0 0 11 43 0 0 0 60 7 -83 0 10 0 0 11 103 0 0 0 48 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 0 0 4 0 0 0 1 0 0 0 5 78 67 83 65 32 72 68 70 32 86 101 114 115 105 111 110 32 52 46 49 32 82 101 108 101 97 115 101 32 53 44 32 78 111 118 101 109 98 101 114 32 53 44 32 50 48 48 49 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 0 0 0 0 0 1 0 4 0 1 0 24 0 4 0 0 0 1 0 6 86 97 108 117 101 115 0 8 102 97 107 101 68 105 109 48 0 9 68 105 109 86 97 108 48 46 49 0 0 0 0 0 3 0 0 0 3 0 0 0 0 1 7 -86 0 4 0 8 102 97 107 101 68 105 109 48 0 6 68 105 109 48 46 48 0 0 0 0 0 3 0 0 0 0 0 0 11 0 0 0 0 0 1 0 4 0 1 0 24 0 4 0 0 0 1 0 6 86 97 108 117 101 115 0 8 102 97 107 101 68 105 109 49 0 9 68 105 109 86 97 108 48 46 49 0 0 0 0 0 3 0 0 0 3 0 0 0 0 1 7 -86 0 6 0 8 102 97 107 101 68 105 109 49 0 6 68 105 109 48 46 48 0 0 0 0 0 3 0 0 0 1 3 8 1 0 2 0 0 0 11 0 0 0 11 0 106 0 8 0 106 0 8 0 106 0 8 2 -66 0 3 0 106 0 8 2 -67 0 8 2 -47 0 8 0 6 7 -83 7 -83 2 -66 0 106 2 -67 2 -48 0 5 0 7 0 3 0 8 0 8 0 2 0 15 82 97 115 68 97 77 97 110 32 111 98 106 101 99 116 0 6 86 97 114 48 46 48 0 0 0 0 0 3 0 0 0 0 3 7 -83 7 -83 7 -83 0 5 0 7 0 9 0 15 47 116 109 112 47 102 105 108 101 86 82 69 88 71 57 0 6 67 68 70 48 46 48 0 0 0 0 0 3 0 0 0 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:2967]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 2968
+ 14 3 19 1 0 -56 0 0 0 0 0 30 0 1 0 0 9 106 0 0 0 92 2 -66 0 3 0 0 9 -58 0 0 0 121 7 -85 0 4 0 0 10 63 0 0 0 4 7 -86 0 4 0 0 10 67 0 0 0 60 7 -83 0 5 0 0 10 127 0 0 0 33 7 -85 0 6 0 0 10 -96 0 0 0 4 7 -86 0 6 0 0 10 -92 0 0 0 60 7 -83 0 7 0 0 10 -32 0 0 0 33 0 106 0 8 0 0 11 1 0 0 0 4 2 -67 0 8 0 0 11 5 0 0 0 22 2 -48 0 2 0 0 11 27 0 0 0 16 7 -83 0 9 0 0 11 43 0 0 0 60 7 -83 0 10 0 0 11 103 0 0 0 48 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 0 0 0 4 0 0 0 1 0 0 0 5 78 67 83 65 32 72 68 70 32 86 101 114 115 105 111 110 32 52 46 49 32 82 101 108 101 97 115 101 32 53 44 32 78 111 118 101 109 98 101 114 32 53 44 32 50 48 48 49 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 11 0 0 0 0 0 1 0 4 0 1 0 24 0 4 0 0 0 1 0 6 86 97 108 117 101 115 0 8 102 97 107 101 68 105 109 48 0 9 68 105 109 86 97 108 48 46 49 0 0 0 0 0 3 0 0 0 3 0 0 0 0 1 7 -86 0 4 0 8 102 97 107 101 68 105 109 48 0 6 68 105 109 48 46 48 0 0 0 0 0 3 0 0 0 0 0 0 11 0 0 0 0 0 1 0 4 0 1 0 24 0 4 0 0 0 1 0 6 86 97 108 117 101 115 0 8 102 97 107 101 68 105 109 49 0 9 68 105 109 86 97 108 48 46 49 0 0 0 0 0 3 0 0 0 3 0 0 0 0 1 7 -86 0 6 0 8 102 97 107 101 68 105 109 49 0 6 68 105 109 48 46 48 0 0 0 0 0 3 0 0 0 1 3 8 1 0 2 0 0 0 11 0 0 0 11 0 106 0 8 0 106 0 8 0 106 0 8 2 -66 0 3 0 106 0 8 2 -67 0 8 2 -47 0 8 0 6 7 -83 7 -83 2 -66 0 106 2 -67 2 -48 0 5 0 7 0 3 0 8 0 8 0 2 0 15 82 97 115 68 97 77 97 110 32 111 98 106 101 99 116 0 6 86 97 114 48 46 48 0 0 0 0 0 3 0 0 0 0 3 7 -83 7 -83 7 -83 0 5 0 7 0 9 0 15 47 116 109 112 47 102 105 108 101 113 56 103 99 115 87 0 6 67 68 70 48 46 48 0 0 0 0 0 3 0 0 0 0 \ No newline at end of file
diff --git a/systemtest/testdata/conversion/hdf1.ql.out b/systemtest/testdata/conversion/hdf1.ql.out
new file mode 100644
index 0000000..7bd6fdd
--- /dev/null
+++ b/systemtest/testdata/conversion/hdf1.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set <marray <char, [0:2967]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1 written to image1.hdf
+Image 2 written to image2.hdf
+-- Testbed end block:
diff --git a/systemtest/testdata/conversion/hdf2.ql b/systemtest/testdata/conversion/hdf2.ql
new file mode 100644
index 0000000..cdbdc69
--- /dev/null
+++ b/systemtest/testdata/conversion/hdf2.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <char, [0:1919]>>
+-- Testbed: result_elements=2
+
+SELECT hdf(a)
+FROM ImgRGBA AS a
diff --git a/systemtest/testdata/conversion/hdf2.ql.java.out b/systemtest/testdata/conversion/hdf2.ql.java.out
new file mode 100644
index 0000000..2b14e44
--- /dev/null
+++ b/systemtest/testdata/conversion/hdf2.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Execution error 381 in line 6, column 8, near token hdf: Error in convertor of the selected data exchange format. \ No newline at end of file
diff --git a/systemtest/testdata/conversion/hdf2.ql.out b/systemtest/testdata/conversion/hdf2.ql.out
new file mode 100644
index 0000000..3684eb8
--- /dev/null
+++ b/systemtest/testdata/conversion/hdf2.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=381
diff --git a/systemtest/testdata/conversion/inv_bmp1.ql b/systemtest/testdata/conversion/inv_bmp1.ql
new file mode 100644
index 0000000..f3053ba
--- /dev/null
+++ b/systemtest/testdata/conversion/inv_bmp1.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <char, [0:1881]>>
+-- Testbed: result_elements=2
+
+SELECT inv_bmp(bmp(a))
+FROM ImgCharA AS a
diff --git a/systemtest/testdata/conversion/inv_bmp1.ql.java.out b/systemtest/testdata/conversion/inv_bmp1.ql.java.out
new file mode 100644
index 0000000..f2deb7a
--- /dev/null
+++ b/systemtest/testdata/conversion/inv_bmp1.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 \ No newline at end of file
diff --git a/systemtest/testdata/conversion/inv_bmp1.ql.out b/systemtest/testdata/conversion/inv_bmp1.ql.out
new file mode 100644
index 0000000..8e3e87c
--- /dev/null
+++ b/systemtest/testdata/conversion/inv_bmp1.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <char, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [0:10,0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+Image 2
+GMarray
+ Type Structure........: marray <char, [0:10,0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+-- Testbed end block:
diff --git a/systemtest/testdata/conversion/inv_bmp2.ql b/systemtest/testdata/conversion/inv_bmp2.ql
new file mode 100644
index 0000000..997a917
--- /dev/null
+++ b/systemtest/testdata/conversion/inv_bmp2.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <char, [0:1919]>>
+-- Testbed: result_elements=2
+
+SELECT inv_bmp(bmp(a))
+FROM ImgRGBA AS a
diff --git a/systemtest/testdata/conversion/inv_bmp2.ql.java.out b/systemtest/testdata/conversion/inv_bmp2.ql.java.out
new file mode 100644
index 0000000..c039a78
--- /dev/null
+++ b/systemtest/testdata/conversion/inv_bmp2.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasGMArray
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:205,0:205]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 3
+ Data format...........: 0
+ Data size (bytes).....: 363
+ 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 \ No newline at end of file
diff --git a/systemtest/testdata/conversion/inv_bmp2.ql.out b/systemtest/testdata/conversion/inv_bmp2.ql.out
new file mode 100644
index 0000000..79f970f
--- /dev/null
+++ b/systemtest/testdata/conversion/inv_bmp2.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <struct { char red, char green, char blue }, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <struct { char red, char green, char blue }, [0:10,0:10]>
+ Type Schema...........: marray< struct{ char red, char green, char blue } >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: struct{ char red, char green, char blue }
+ Base Type Length......: 3
+ Data format.......... : Array
+ Data size (bytes).... : 363
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+Image 2
+GMarray
+ Type Structure........: marray <struct { char red, char green, char blue }, [0:10,0:10]>
+ Type Schema...........: marray< struct{ char red, char green, char blue } >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: struct{ char red, char green, char blue }
+ Base Type Length......: 3
+ Data format.......... : Array
+ Data size (bytes).... : 363
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+-- Testbed end block:
diff --git a/systemtest/testdata/conversion/inv_hdf1.ql b/systemtest/testdata/conversion/inv_hdf1.ql
new file mode 100644
index 0000000..523ad6a
--- /dev/null
+++ b/systemtest/testdata/conversion/inv_hdf1.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <char, [0:1881]>>
+-- Testbed: result_elements=2
+
+SELECT inv_hdf(hdf(a))
+FROM ImgCharA AS a
diff --git a/systemtest/testdata/conversion/inv_hdf1.ql.java.out b/systemtest/testdata/conversion/inv_hdf1.ql.java.out
new file mode 100644
index 0000000..f2deb7a
--- /dev/null
+++ b/systemtest/testdata/conversion/inv_hdf1.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 \ No newline at end of file
diff --git a/systemtest/testdata/conversion/inv_hdf1.ql.out b/systemtest/testdata/conversion/inv_hdf1.ql.out
new file mode 100644
index 0000000..8e3e87c
--- /dev/null
+++ b/systemtest/testdata/conversion/inv_hdf1.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <char, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [0:10,0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+Image 2
+GMarray
+ Type Structure........: marray <char, [0:10,0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+-- Testbed end block:
diff --git a/systemtest/testdata/conversion/inv_hdf2.ql b/systemtest/testdata/conversion/inv_hdf2.ql
new file mode 100644
index 0000000..30c86e1
--- /dev/null
+++ b/systemtest/testdata/conversion/inv_hdf2.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <char, [0:1919]>>
+-- Testbed: result_elements=2
+
+SELECT inv_hdf(hdf(a))
+FROM ImgRGBA AS a
diff --git a/systemtest/testdata/conversion/inv_hdf2.ql.java.out b/systemtest/testdata/conversion/inv_hdf2.ql.java.out
new file mode 100644
index 0000000..d45254c
--- /dev/null
+++ b/systemtest/testdata/conversion/inv_hdf2.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Execution error 381 in line 6, column 16, near token hdf: Error in convertor of the selected data exchange format. \ No newline at end of file
diff --git a/systemtest/testdata/conversion/inv_hdf2.ql.out b/systemtest/testdata/conversion/inv_hdf2.ql.out
new file mode 100644
index 0000000..3684eb8
--- /dev/null
+++ b/systemtest/testdata/conversion/inv_hdf2.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=381
diff --git a/systemtest/testdata/conversion/inv_hdf3.ql b/systemtest/testdata/conversion/inv_hdf3.ql
new file mode 100644
index 0000000..76f9954
--- /dev/null
+++ b/systemtest/testdata/conversion/inv_hdf3.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <char, [0:1919]>>
+-- Testbed: result_elements=2
+
+SELECT inv_hdf(a)
+FROM ImgCharA AS a
diff --git a/systemtest/testdata/conversion/inv_hdf3.ql.java.out b/systemtest/testdata/conversion/inv_hdf3.ql.java.out
new file mode 100644
index 0000000..1090cd0
--- /dev/null
+++ b/systemtest/testdata/conversion/inv_hdf3.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Execution error 381 in line 6, column 8, near token inv_hdf: Error in convertor of the selected data exchange format. \ No newline at end of file
diff --git a/systemtest/testdata/conversion/inv_hdf3.ql.out b/systemtest/testdata/conversion/inv_hdf3.ql.out
new file mode 100644
index 0000000..3684eb8
--- /dev/null
+++ b/systemtest/testdata/conversion/inv_hdf3.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=381
diff --git a/systemtest/testdata/conversion/inv_hdf4.ql b/systemtest/testdata/conversion/inv_hdf4.ql
new file mode 100644
index 0000000..c672a97
--- /dev/null
+++ b/systemtest/testdata/conversion/inv_hdf4.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <char, [0:1919]>>
+-- Testbed: result_elements=2
+
+SELECT inv_hdf(a)
+FROM ImgRGBA AS a
diff --git a/systemtest/testdata/conversion/inv_hdf4.ql.java.out b/systemtest/testdata/conversion/inv_hdf4.ql.java.out
new file mode 100644
index 0000000..1090cd0
--- /dev/null
+++ b/systemtest/testdata/conversion/inv_hdf4.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Execution error 381 in line 6, column 8, near token inv_hdf: Error in convertor of the selected data exchange format. \ No newline at end of file
diff --git a/systemtest/testdata/conversion/inv_hdf4.ql.out b/systemtest/testdata/conversion/inv_hdf4.ql.out
new file mode 100644
index 0000000..3684eb8
--- /dev/null
+++ b/systemtest/testdata/conversion/inv_hdf4.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=381
diff --git a/systemtest/testdata/conversion/inv_jpeg1.ql b/systemtest/testdata/conversion/inv_jpeg1.ql
new file mode 100644
index 0000000..81b6650
--- /dev/null
+++ b/systemtest/testdata/conversion/inv_jpeg1.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <char, [0:1881]>>
+-- Testbed: result_elements=2
+
+SELECT inv_jpeg(jpeg(a))
+FROM ImgCharA AS a
diff --git a/systemtest/testdata/conversion/inv_jpeg1.ql.java.out b/systemtest/testdata/conversion/inv_jpeg1.ql.java.out
new file mode 100644
index 0000000..f2deb7a
--- /dev/null
+++ b/systemtest/testdata/conversion/inv_jpeg1.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 \ No newline at end of file
diff --git a/systemtest/testdata/conversion/inv_jpeg1.ql.out b/systemtest/testdata/conversion/inv_jpeg1.ql.out
new file mode 100644
index 0000000..8e3e87c
--- /dev/null
+++ b/systemtest/testdata/conversion/inv_jpeg1.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <char, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [0:10,0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+Image 2
+GMarray
+ Type Structure........: marray <char, [0:10,0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+-- Testbed end block:
diff --git a/systemtest/testdata/conversion/inv_jpeg2.ql b/systemtest/testdata/conversion/inv_jpeg2.ql
new file mode 100644
index 0000000..94bf4ce
--- /dev/null
+++ b/systemtest/testdata/conversion/inv_jpeg2.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <char, [0:1919]>>
+-- Testbed: result_elements=2
+
+SELECT inv_jpeg(jpeg(a))
+FROM ImgRGBA AS a
diff --git a/systemtest/testdata/conversion/inv_jpeg2.ql.java.out b/systemtest/testdata/conversion/inv_jpeg2.ql.java.out
new file mode 100644
index 0000000..c2cb6bc
--- /dev/null
+++ b/systemtest/testdata/conversion/inv_jpeg2.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasGMArray
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:205,0:205]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 3
+ Data format...........: 0
+ Data size (bytes).....: 363
+ 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 \ No newline at end of file
diff --git a/systemtest/testdata/conversion/inv_jpeg2.ql.out b/systemtest/testdata/conversion/inv_jpeg2.ql.out
new file mode 100644
index 0000000..85b8118
--- /dev/null
+++ b/systemtest/testdata/conversion/inv_jpeg2.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <struct { char red, char green, char blue }, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <struct { char red, char green, char blue }, [0:10,0:10]>
+ Type Schema...........: marray< struct{ char red, char green, char blue } >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: struct{ char red, char green, char blue }
+ Base Type Length......: 3
+ Data format.......... : Array
+ Data size (bytes).... : 363
+{ 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4}
+{ 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4}
+{ 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4}
+{ 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4}
+{ 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4}
+{ 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4}
+{ 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4}
+{ 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4}
+{ 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4}
+{ 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4}
+{ 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4}
+Image 2
+GMarray
+ Type Structure........: marray <struct { char red, char green, char blue }, [0:10,0:10]>
+ Type Schema...........: marray< struct{ char red, char green, char blue } >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: struct{ char red, char green, char blue }
+ Base Type Length......: 3
+ Data format.......... : Array
+ Data size (bytes).... : 363
+{ 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4}
+{ 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4}
+{ 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4}
+{ 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4}
+{ 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4}
+{ 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4}
+{ 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4}
+{ 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4}
+{ 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4}
+{ 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4}
+{ 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4} { 1, 2, 4}
+-- Testbed end block:
diff --git a/systemtest/testdata/conversion/inv_png1.ql b/systemtest/testdata/conversion/inv_png1.ql
new file mode 100644
index 0000000..429e64e
--- /dev/null
+++ b/systemtest/testdata/conversion/inv_png1.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <char, [0:1881]>>
+-- Testbed: result_elements=2
+
+SELECT inv_png(png(a))
+FROM ImgCharA AS a
diff --git a/systemtest/testdata/conversion/inv_png1.ql.java.out b/systemtest/testdata/conversion/inv_png1.ql.java.out
new file mode 100644
index 0000000..f2deb7a
--- /dev/null
+++ b/systemtest/testdata/conversion/inv_png1.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 \ No newline at end of file
diff --git a/systemtest/testdata/conversion/inv_png1.ql.out b/systemtest/testdata/conversion/inv_png1.ql.out
new file mode 100644
index 0000000..8e3e87c
--- /dev/null
+++ b/systemtest/testdata/conversion/inv_png1.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <char, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [0:10,0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+Image 2
+GMarray
+ Type Structure........: marray <char, [0:10,0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+-- Testbed end block:
diff --git a/systemtest/testdata/conversion/inv_png2.ql b/systemtest/testdata/conversion/inv_png2.ql
new file mode 100644
index 0000000..514c612
--- /dev/null
+++ b/systemtest/testdata/conversion/inv_png2.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <char, [0:1919]>>
+-- Testbed: result_elements=2
+
+SELECT inv_png(png(a))
+FROM ImgRGBA AS a
diff --git a/systemtest/testdata/conversion/inv_png2.ql.java.out b/systemtest/testdata/conversion/inv_png2.ql.java.out
new file mode 100644
index 0000000..c039a78
--- /dev/null
+++ b/systemtest/testdata/conversion/inv_png2.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasGMArray
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:205,0:205]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 3
+ Data format...........: 0
+ Data size (bytes).....: 363
+ 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 \ No newline at end of file
diff --git a/systemtest/testdata/conversion/inv_png2.ql.out b/systemtest/testdata/conversion/inv_png2.ql.out
new file mode 100644
index 0000000..79f970f
--- /dev/null
+++ b/systemtest/testdata/conversion/inv_png2.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <struct { char red, char green, char blue }, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <struct { char red, char green, char blue }, [0:10,0:10]>
+ Type Schema...........: marray< struct{ char red, char green, char blue } >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: struct{ char red, char green, char blue }
+ Base Type Length......: 3
+ Data format.......... : Array
+ Data size (bytes).... : 363
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+Image 2
+GMarray
+ Type Structure........: marray <struct { char red, char green, char blue }, [0:10,0:10]>
+ Type Schema...........: marray< struct{ char red, char green, char blue } >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: struct{ char red, char green, char blue }
+ Base Type Length......: 3
+ Data format.......... : Array
+ Data size (bytes).... : 363
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+-- Testbed end block:
diff --git a/systemtest/testdata/conversion/inv_tiff1.ql b/systemtest/testdata/conversion/inv_tiff1.ql
new file mode 100644
index 0000000..48aa564
--- /dev/null
+++ b/systemtest/testdata/conversion/inv_tiff1.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <char, [0:1881]>>
+-- Testbed: result_elements=2
+
+SELECT inv_tiff(tiff(a))
+FROM ImgCharA AS a
diff --git a/systemtest/testdata/conversion/inv_tiff1.ql.java.out b/systemtest/testdata/conversion/inv_tiff1.ql.java.out
new file mode 100644
index 0000000..f2deb7a
--- /dev/null
+++ b/systemtest/testdata/conversion/inv_tiff1.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 \ No newline at end of file
diff --git a/systemtest/testdata/conversion/inv_tiff1.ql.out b/systemtest/testdata/conversion/inv_tiff1.ql.out
new file mode 100644
index 0000000..8e3e87c
--- /dev/null
+++ b/systemtest/testdata/conversion/inv_tiff1.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <char, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [0:10,0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+Image 2
+GMarray
+ Type Structure........: marray <char, [0:10,0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+-- Testbed end block:
diff --git a/systemtest/testdata/conversion/inv_tiff2.ql b/systemtest/testdata/conversion/inv_tiff2.ql
new file mode 100644
index 0000000..ec64d03
--- /dev/null
+++ b/systemtest/testdata/conversion/inv_tiff2.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <char, [0:1919]>>
+-- Testbed: result_elements=2
+
+SELECT inv_tiff(tiff(a))
+FROM ImgRGBA AS a
diff --git a/systemtest/testdata/conversion/inv_tiff2.ql.java.out b/systemtest/testdata/conversion/inv_tiff2.ql.java.out
new file mode 100644
index 0000000..c039a78
--- /dev/null
+++ b/systemtest/testdata/conversion/inv_tiff2.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasGMArray
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:205,0:205]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 3
+ Data format...........: 0
+ Data size (bytes).....: 363
+ 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 \ No newline at end of file
diff --git a/systemtest/testdata/conversion/inv_tiff2.ql.out b/systemtest/testdata/conversion/inv_tiff2.ql.out
new file mode 100644
index 0000000..79f970f
--- /dev/null
+++ b/systemtest/testdata/conversion/inv_tiff2.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <struct { char red, char green, char blue }, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <struct { char red, char green, char blue }, [0:10,0:10]>
+ Type Schema...........: marray< struct{ char red, char green, char blue } >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: struct{ char red, char green, char blue }
+ Base Type Length......: 3
+ Data format.......... : Array
+ Data size (bytes).... : 363
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+Image 2
+GMarray
+ Type Structure........: marray <struct { char red, char green, char blue }, [0:10,0:10]>
+ Type Schema...........: marray< struct{ char red, char green, char blue } >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: struct{ char red, char green, char blue }
+ Base Type Length......: 3
+ Data format.......... : Array
+ Data size (bytes).... : 363
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+-- Testbed end block:
diff --git a/systemtest/testdata/conversion/inv_vff1.ql b/systemtest/testdata/conversion/inv_vff1.ql
new file mode 100644
index 0000000..8c5d9df
--- /dev/null
+++ b/systemtest/testdata/conversion/inv_vff1.ql
@@ -0,0 +1,6 @@
+-- Testbed: result_type=set <marray <char, [0:276]>>
+-- Testbed: result_elements=2
+
+SELECT inv_vff(vff(a))
+FROM ImgCharA AS a
+ \ No newline at end of file
diff --git a/systemtest/testdata/conversion/inv_vff1.ql.java.out b/systemtest/testdata/conversion/inv_vff1.ql.java.out
new file mode 100644
index 0000000..f2deb7a
--- /dev/null
+++ b/systemtest/testdata/conversion/inv_vff1.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 \ No newline at end of file
diff --git a/systemtest/testdata/conversion/inv_vff1.ql.out b/systemtest/testdata/conversion/inv_vff1.ql.out
new file mode 100644
index 0000000..8e3e87c
--- /dev/null
+++ b/systemtest/testdata/conversion/inv_vff1.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <char, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [0:10,0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+Image 2
+GMarray
+ Type Structure........: marray <char, [0:10,0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+-- Testbed end block:
diff --git a/systemtest/testdata/conversion/inv_vff2.ql b/systemtest/testdata/conversion/inv_vff2.ql
new file mode 100644
index 0000000..2fb3554
--- /dev/null
+++ b/systemtest/testdata/conversion/inv_vff2.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <char, [0:1919]>>
+-- Testbed: result_elements=2
+
+SELECT inv_vff(vff(a))
+FROM ImgRGBA AS a
diff --git a/systemtest/testdata/conversion/inv_vff2.ql.java.out b/systemtest/testdata/conversion/inv_vff2.ql.java.out
new file mode 100644
index 0000000..043ded0
--- /dev/null
+++ b/systemtest/testdata/conversion/inv_vff2.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Execution error 381 in line 6, column 16, near token vff: Error in convertor of the selected data exchange format. \ No newline at end of file
diff --git a/systemtest/testdata/conversion/inv_vff2.ql.out b/systemtest/testdata/conversion/inv_vff2.ql.out
new file mode 100644
index 0000000..3684eb8
--- /dev/null
+++ b/systemtest/testdata/conversion/inv_vff2.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=381
diff --git a/systemtest/testdata/conversion/jpeg1.ql b/systemtest/testdata/conversion/jpeg1.ql
new file mode 100644
index 0000000..adf1afc
--- /dev/null
+++ b/systemtest/testdata/conversion/jpeg1.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <char, [0:1881]>>
+-- Testbed: result_elements=2
+
+SELECT jpeg(a)
+FROM ImgCharA AS a
diff --git a/systemtest/testdata/conversion/jpeg1.ql.java.out b/systemtest/testdata/conversion/jpeg1.ql.java.out
new file mode 100644
index 0000000..04aa648
--- /dev/null
+++ b/systemtest/testdata/conversion/jpeg1.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:334]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 335
+ -1 -40 -1 -32 0 16 74 70 73 70 0 1 1 0 0 1 0 1 0 0 -1 -37 0 67 0 6 4 5 6 5 4 6 6 5 6 7 7 6 8 10 16 10 10 9 9 10 20 14 15 12 16 23 20 24 24 23 20 22 22 26 29 37 31 26 27 35 28 22 22 32 44 32 35 38 39 41 42 41 25 31 45 48 45 40 48 37 40 41 40 -1 -64 0 11 8 0 11 0 11 1 1 17 0 -1 -60 0 31 0 0 1 5 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 2 3 4 5 6 7 8 9 10 11 -1 -60 0 -75 16 0 2 1 3 3 2 4 3 5 5 4 4 0 0 1 125 1 2 3 0 4 17 5 18 33 49 65 6 19 81 97 7 34 113 20 50 -127 -111 -95 8 35 66 -79 -63 21 82 -47 -16 36 51 98 114 -126 9 10 22 23 24 25 26 37 38 39 40 41 42 52 53 54 55 56 57 58 67 68 69 70 71 72 73 74 83 84 85 86 87 88 89 90 99 100 101 102 103 104 105 106 115 116 117 118 119 120 121 122 -125 -124 -123 -122 -121 -120 -119 -118 -110 -109 -108 -107 -106 -105 -104 -103 -102 -94 -93 -92 -91 -90 -89 -88 -87 -86 -78 -77 -76 -75 -74 -73 -72 -71 -70 -62 -61 -60 -59 -58 -57 -56 -55 -54 -46 -45 -44 -43 -42 -41 -40 -39 -38 -31 -30 -29 -28 -27 -26 -25 -24 -23 -22 -15 -14 -13 -12 -11 -10 -9 -8 -7 -6 -1 -38 0 8 1 1 0 0 63 0 -7 82 -118 40 -81 -1 -39
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:334]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 335
+ -1 -40 -1 -32 0 16 74 70 73 70 0 1 1 0 0 1 0 1 0 0 -1 -37 0 67 0 6 4 5 6 5 4 6 6 5 6 7 7 6 8 10 16 10 10 9 9 10 20 14 15 12 16 23 20 24 24 23 20 22 22 26 29 37 31 26 27 35 28 22 22 32 44 32 35 38 39 41 42 41 25 31 45 48 45 40 48 37 40 41 40 -1 -64 0 11 8 0 11 0 11 1 1 17 0 -1 -60 0 31 0 0 1 5 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 2 3 4 5 6 7 8 9 10 11 -1 -60 0 -75 16 0 2 1 3 3 2 4 3 5 5 4 4 0 0 1 125 1 2 3 0 4 17 5 18 33 49 65 6 19 81 97 7 34 113 20 50 -127 -111 -95 8 35 66 -79 -63 21 82 -47 -16 36 51 98 114 -126 9 10 22 23 24 25 26 37 38 39 40 41 42 52 53 54 55 56 57 58 67 68 69 70 71 72 73 74 83 84 85 86 87 88 89 90 99 100 101 102 103 104 105 106 115 116 117 118 119 120 121 122 -125 -124 -123 -122 -121 -120 -119 -118 -110 -109 -108 -107 -106 -105 -104 -103 -102 -94 -93 -92 -91 -90 -89 -88 -87 -86 -78 -77 -76 -75 -74 -73 -72 -71 -70 -62 -61 -60 -59 -58 -57 -56 -55 -54 -46 -45 -44 -43 -42 -41 -40 -39 -38 -31 -30 -29 -28 -27 -26 -25 -24 -23 -22 -15 -14 -13 -12 -11 -10 -9 -8 -7 -6 -1 -38 0 8 1 1 0 0 63 0 -7 90 -118 40 -81 -1 -39 \ No newline at end of file
diff --git a/systemtest/testdata/conversion/jpeg1.ql.out b/systemtest/testdata/conversion/jpeg1.ql.out
new file mode 100644
index 0000000..1122006
--- /dev/null
+++ b/systemtest/testdata/conversion/jpeg1.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set <marray <char, [0:334]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1 written to image1.jpg
+Image 2 written to image2.jpg
+-- Testbed end block:
diff --git a/systemtest/testdata/conversion/jpeg2.ql b/systemtest/testdata/conversion/jpeg2.ql
new file mode 100644
index 0000000..b539982
--- /dev/null
+++ b/systemtest/testdata/conversion/jpeg2.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <char, [0:1919]>>
+-- Testbed: result_elements=2
+
+SELECT jpeg(a)
+FROM ImgRGBA AS a
diff --git a/systemtest/testdata/conversion/jpeg2.ql.java.out b/systemtest/testdata/conversion/jpeg2.ql.java.out
new file mode 100644
index 0000000..3c8db7b
--- /dev/null
+++ b/systemtest/testdata/conversion/jpeg2.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:630]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 631
+ -1 -40 -1 -32 0 16 74 70 73 70 0 1 1 0 0 1 0 1 0 0 -1 -37 0 67 0 6 4 5 6 5 4 6 6 5 6 7 7 6 8 10 16 10 10 9 9 10 20 14 15 12 16 23 20 24 24 23 20 22 22 26 29 37 31 26 27 35 28 22 22 32 44 32 35 38 39 41 42 41 25 31 45 48 45 40 48 37 40 41 40 -1 -37 0 67 1 7 7 7 10 8 10 19 10 10 19 40 26 22 26 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 -1 -64 0 17 8 0 11 0 11 3 1 34 0 2 17 1 3 17 1 -1 -60 0 31 0 0 1 5 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 2 3 4 5 6 7 8 9 10 11 -1 -60 0 -75 16 0 2 1 3 3 2 4 3 5 5 4 4 0 0 1 125 1 2 3 0 4 17 5 18 33 49 65 6 19 81 97 7 34 113 20 50 -127 -111 -95 8 35 66 -79 -63 21 82 -47 -16 36 51 98 114 -126 9 10 22 23 24 25 26 37 38 39 40 41 42 52 53 54 55 56 57 58 67 68 69 70 71 72 73 74 83 84 85 86 87 88 89 90 99 100 101 102 103 104 105 106 115 116 117 118 119 120 121 122 -125 -124 -123 -122 -121 -120 -119 -118 -110 -109 -108 -107 -106 -105 -104 -103 -102 -94 -93 -92 -91 -90 -89 -88 -87 -86 -78 -77 -76 -75 -74 -73 -72 -71 -70 -62 -61 -60 -59 -58 -57 -56 -55 -54 -46 -45 -44 -43 -42 -41 -40 -39 -38 -31 -30 -29 -28 -27 -26 -25 -24 -23 -22 -15 -14 -13 -12 -11 -10 -9 -8 -7 -6 -1 -60 0 31 1 0 3 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 1 2 3 4 5 6 7 8 9 10 11 -1 -60 0 -75 17 0 2 1 2 4 4 3 4 7 5 4 4 0 1 2 119 0 1 2 3 17 4 5 33 49 6 18 65 81 7 97 113 19 34 50 -127 8 20 66 -111 -95 -79 -63 9 35 51 82 -16 21 98 114 -47 10 22 36 52 -31 37 -15 23 24 25 26 38 39 40 41 42 53 54 55 56 57 58 67 68 69 70 71 72 73 74 83 84 85 86 87 88 89 90 99 100 101 102 103 104 105 106 115 116 117 118 119 120 121 122 -126 -125 -124 -123 -122 -121 -120 -119 -118 -110 -109 -108 -107 -106 -105 -104 -103 -102 -94 -93 -92 -91 -90 -89 -88 -87 -86 -78 -77 -76 -75 -74 -73 -72 -71 -70 -62 -61 -60 -59 -58 -57 -56 -55 -54 -46 -45 -44 -43 -42 -41 -40 -39 -38 -30 -29 -28 -27 -26 -25 -24 -23 -22 -14 -13 -12 -11 -10 -9 -8 -7 -6 -1 -38 0 12 3 1 0 2 17 3 17 0 63 0 -7 94 -118 40 -90 35 -1 -39
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:630]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 631
+ -1 -40 -1 -32 0 16 74 70 73 70 0 1 1 0 0 1 0 1 0 0 -1 -37 0 67 0 6 4 5 6 5 4 6 6 5 6 7 7 6 8 10 16 10 10 9 9 10 20 14 15 12 16 23 20 24 24 23 20 22 22 26 29 37 31 26 27 35 28 22 22 32 44 32 35 38 39 41 42 41 25 31 45 48 45 40 48 37 40 41 40 -1 -37 0 67 1 7 7 7 10 8 10 19 10 10 19 40 26 22 26 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 -1 -64 0 17 8 0 11 0 11 3 1 34 0 2 17 1 3 17 1 -1 -60 0 31 0 0 1 5 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 2 3 4 5 6 7 8 9 10 11 -1 -60 0 -75 16 0 2 1 3 3 2 4 3 5 5 4 4 0 0 1 125 1 2 3 0 4 17 5 18 33 49 65 6 19 81 97 7 34 113 20 50 -127 -111 -95 8 35 66 -79 -63 21 82 -47 -16 36 51 98 114 -126 9 10 22 23 24 25 26 37 38 39 40 41 42 52 53 54 55 56 57 58 67 68 69 70 71 72 73 74 83 84 85 86 87 88 89 90 99 100 101 102 103 104 105 106 115 116 117 118 119 120 121 122 -125 -124 -123 -122 -121 -120 -119 -118 -110 -109 -108 -107 -106 -105 -104 -103 -102 -94 -93 -92 -91 -90 -89 -88 -87 -86 -78 -77 -76 -75 -74 -73 -72 -71 -70 -62 -61 -60 -59 -58 -57 -56 -55 -54 -46 -45 -44 -43 -42 -41 -40 -39 -38 -31 -30 -29 -28 -27 -26 -25 -24 -23 -22 -15 -14 -13 -12 -11 -10 -9 -8 -7 -6 -1 -60 0 31 1 0 3 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 1 2 3 4 5 6 7 8 9 10 11 -1 -60 0 -75 17 0 2 1 2 4 4 3 4 7 5 4 4 0 1 2 119 0 1 2 3 17 4 5 33 49 6 18 65 81 7 97 113 19 34 50 -127 8 20 66 -111 -95 -79 -63 9 35 51 82 -16 21 98 114 -47 10 22 36 52 -31 37 -15 23 24 25 26 38 39 40 41 42 53 54 55 56 57 58 67 68 69 70 71 72 73 74 83 84 85 86 87 88 89 90 99 100 101 102 103 104 105 106 115 116 117 118 119 120 121 122 -126 -125 -124 -123 -122 -121 -120 -119 -118 -110 -109 -108 -107 -106 -105 -104 -103 -102 -94 -93 -92 -91 -90 -89 -88 -87 -86 -78 -77 -76 -75 -74 -73 -72 -71 -70 -62 -61 -60 -59 -58 -57 -56 -55 -54 -46 -45 -44 -43 -42 -41 -40 -39 -38 -30 -29 -28 -27 -26 -25 -24 -23 -22 -14 -13 -12 -11 -10 -9 -8 -7 -6 -1 -38 0 12 3 1 0 2 17 3 17 0 63 0 -7 94 -118 40 -90 35 -1 -39 \ No newline at end of file
diff --git a/systemtest/testdata/conversion/jpeg2.ql.out b/systemtest/testdata/conversion/jpeg2.ql.out
new file mode 100644
index 0000000..7113105
--- /dev/null
+++ b/systemtest/testdata/conversion/jpeg2.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set <marray <char, [0:630]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1 written to image1.jpg
+Image 2 written to image2.jpg
+-- Testbed end block:
diff --git a/systemtest/testdata/conversion/png1.ql b/systemtest/testdata/conversion/png1.ql
new file mode 100644
index 0000000..53bcb69
--- /dev/null
+++ b/systemtest/testdata/conversion/png1.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <char, [0:1881]>>
+-- Testbed: result_elements=2
+
+SELECT png(a)
+FROM ImgCharA AS a
diff --git a/systemtest/testdata/conversion/png1.ql.java.out b/systemtest/testdata/conversion/png1.ql.java.out
new file mode 100644
index 0000000..50e7461
--- /dev/null
+++ b/systemtest/testdata/conversion/png1.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:132]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 133
+ -119 80 78 71 13 10 26 10 0 0 0 13 73 72 68 82 0 0 0 11 0 0 0 11 8 0 0 0 0 -116 -57 40 -6 0 0 0 1 115 66 73 84 8 -26 10 91 -103 0 0 0 39 116 69 88 116 68 101 115 99 114 105 112 116 105 111 110 0 82 97 115 68 97 77 97 110 32 77 68 68 32 101 110 99 111 100 101 100 32 97 115 32 80 78 71 40 12 -78 -46 0 0 0 12 73 68 65 84 120 -100 99 96 24 120 0 0 0 -124 0 1 60 -90 123 89 0 0 0 0 73 69 78 68 -82 66 96 -126
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:137]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 138
+ -119 80 78 71 13 10 26 10 0 0 0 13 73 72 68 82 0 0 0 11 0 0 0 11 8 0 0 0 0 -116 -57 40 -6 0 0 0 1 115 66 73 84 8 -26 10 91 -103 0 0 0 39 116 69 88 116 68 101 115 99 114 105 112 116 105 111 110 0 82 97 115 68 97 77 97 110 32 77 68 68 32 101 110 99 111 100 101 100 32 97 115 32 80 78 71 40 12 -78 -46 0 0 0 17 73 68 65 84 120 -100 99 100 100 -128 3 38 -122 -127 97 3 0 6 -77 0 23 29 -35 -23 -90 0 0 0 0 73 69 78 68 -82 66 96 -126 \ No newline at end of file
diff --git a/systemtest/testdata/conversion/png1.ql.out b/systemtest/testdata/conversion/png1.ql.out
new file mode 100644
index 0000000..5cced6c
--- /dev/null
+++ b/systemtest/testdata/conversion/png1.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set <marray <char, [0:132]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1 written to image1.png
+Image 2 written to image2.png
+-- Testbed end block:
diff --git a/systemtest/testdata/conversion/png2.ql b/systemtest/testdata/conversion/png2.ql
new file mode 100644
index 0000000..c5fa915
--- /dev/null
+++ b/systemtest/testdata/conversion/png2.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <char, [0:1919]>>
+-- Testbed: result_elements=2
+
+SELECT png(a)
+FROM ImgRGBA AS a
diff --git a/systemtest/testdata/conversion/png2.ql.java.out b/systemtest/testdata/conversion/png2.ql.java.out
new file mode 100644
index 0000000..b8c0183
--- /dev/null
+++ b/systemtest/testdata/conversion/png2.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:144]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 145
+ -119 80 78 71 13 10 26 10 0 0 0 13 73 72 68 82 0 0 0 11 0 0 0 11 8 2 0 0 0 38 -50 -32 113 0 0 0 3 115 66 73 84 8 8 8 -37 -31 79 -32 0 0 0 39 116 69 88 116 68 101 115 99 114 105 112 116 105 111 110 0 82 97 115 68 97 77 97 110 32 77 68 68 32 101 110 99 111 100 101 100 32 97 115 32 80 78 71 40 12 -78 -46 0 0 0 22 73 68 65 84 120 -100 99 100 100 98 102 -64 11 -104 -16 75 -113 -86 32 67 5 0 26 62 0 28 -114 -41 30 -110 0 0 0 0 73 69 78 68 -82 66 96 -126
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:144]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 145
+ -119 80 78 71 13 10 26 10 0 0 0 13 73 72 68 82 0 0 0 11 0 0 0 11 8 2 0 0 0 38 -50 -32 113 0 0 0 3 115 66 73 84 8 8 8 -37 -31 79 -32 0 0 0 39 116 69 88 116 68 101 115 99 114 105 112 116 105 111 110 0 82 97 115 68 97 77 97 110 32 77 68 68 32 101 110 99 111 100 101 100 32 97 115 32 80 78 71 40 12 -78 -46 0 0 0 22 73 68 65 84 120 -100 99 100 100 98 102 -64 11 -104 -16 75 -113 -86 32 67 5 0 26 62 0 28 -114 -41 30 -110 0 0 0 0 73 69 78 68 -82 66 96 -126 \ No newline at end of file
diff --git a/systemtest/testdata/conversion/png2.ql.out b/systemtest/testdata/conversion/png2.ql.out
new file mode 100644
index 0000000..53915b1
--- /dev/null
+++ b/systemtest/testdata/conversion/png2.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set <marray <char, [0:144]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1 written to image1.png
+Image 2 written to image2.png
+-- Testbed end block:
diff --git a/systemtest/testdata/conversion/tiff1.ql b/systemtest/testdata/conversion/tiff1.ql
new file mode 100644
index 0000000..02ff04e
--- /dev/null
+++ b/systemtest/testdata/conversion/tiff1.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <char, [0:1881]>>
+-- Testbed: result_elements=2
+
+SELECT tiff(a)
+FROM ImgCharA AS a
diff --git a/systemtest/testdata/conversion/tiff1.ql.java.out b/systemtest/testdata/conversion/tiff1.ql.java.out
new file mode 100644
index 0000000..29a61c9
--- /dev/null
+++ b/systemtest/testdata/conversion/tiff1.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:1981]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 1982
+ 73 73 42 0 -126 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 115 21 0 0 1 3 0 1 0 0 0 11 0 0 0 1 1 3 0 1 0 0 0 11 0 0 0 2 1 3 0 1 0 0 0 8 0 0 0 3 1 3 0 1 0 0 0 1 0 0 0 6 1 3 0 1 0 0 0 3 0 0 0 10 1 3 0 1 0 0 0 1 0 0 0 13 1 2 0 6 0 0 0 -124 1 0 0 17 1 4 0 1 0 0 0 8 0 0 0 18 1 3 0 1 0 0 0 1 0 0 0 21 1 3 0 1 0 0 0 1 0 0 0 22 1 3 0 1 0 0 0 -24 2 0 0 23 1 4 0 1 0 0 0 121 0 0 0 26 1 5 0 1 0 0 0 -118 1 0 0 27 1 5 0 1 0 0 0 -110 1 0 0 28 1 3 0 1 0 0 0 1 0 0 0 30 1 5 0 1 0 0 0 -102 1 0 0 31 1 5 0 1 0 0 0 -94 1 0 0 40 1 3 0 1 0 0 0 2 0 0 0 49 1 2 0 9 0 0 0 -86 1 0 0 59 1 2 0 9 0 0 0 -76 1 0 0 64 1 3 0 0 3 0 0 -66 1 0 0 0 0 0 0 73 109 97 103 101 0 0 0 0 90 0 0 0 1 0 0 0 90 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 82 97 115 68 97 77 97 110 0 0 82 97 115 68 97 77 97 110 0 0 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11 12 12 13 13 14 14 15 15 16 16 17 17 18 18 19 19 20 20 21 21 22 22 23 23 24 24 25 25 26 26 27 27 28 28 29 29 30 30 31 31 32 32 33 33 34 34 35 35 36 36 37 37 38 38 39 39 40 40 41 41 42 42 43 43 44 44 45 45 46 46 47 47 48 48 49 49 50 50 51 51 52 52 53 53 54 54 55 55 56 56 57 57 58 58 59 59 60 60 61 61 62 62 63 63 64 64 65 65 66 66 67 67 68 68 69 69 70 70 71 71 72 72 73 73 74 74 75 75 76 76 77 77 78 78 79 79 80 80 81 81 82 82 83 83 84 84 85 85 86 86 87 87 88 88 89 89 90 90 91 91 92 92 93 93 94 94 95 95 96 96 97 97 98 98 99 99 100 100 101 101 102 102 103 103 104 104 105 105 106 106 107 107 108 108 109 109 110 110 111 111 112 112 113 113 114 114 115 115 116 116 117 117 118 118 119 119 120 120 121 121 122 122 123 123 124 124 125 125 126 126 127 127 -128 -128 -127 -127 -126 -126 -125 -125 -124 -124 -123 -123 -122 -122 -121 -121 -120 -120 -119 -119 -118 -118 -117 -117 -116 -116 -115 -115 -114 -114 -113 -113 -112 -112 -111 -111 -110 -110 -109 -109 -108 -108 -107 -107 -106 -106 -105 -105 -104 -104 -103 -103 -102 -102 -101 -101 -100 -100 -99 -99 -98 -98 -97 -97 -96 -96 -95 -95 -94 -94 -93 -93 -92 -92 -91 -91 -90 -90 -89 -89 -88 -88 -87 -87 -86 -86 -85 -85 -84 -84 -83 -83 -82 -82 -81 -81 -80 -80 -79 -79 -78 -78 -77 -77 -76 -76 -75 -75 -74 -74 -73 -73 -72 -72 -71 -71 -70 -70 -69 -69 -68 -68 -67 -67 -66 -66 -65 -65 -64 -64 -63 -63 -62 -62 -61 -61 -60 -60 -59 -59 -58 -58 -57 -57 -56 -56 -55 -55 -54 -54 -53 -53 -52 -52 -51 -51 -50 -50 -49 -49 -48 -48 -47 -47 -46 -46 -45 -45 -44 -44 -43 -43 -42 -42 -41 -41 -40 -40 -39 -39 -38 -38 -37 -37 -36 -36 -35 -35 -34 -34 -33 -33 -32 -32 -31 -31 -30 -30 -29 -29 -28 -28 -27 -27 -26 -26 -25 -25 -24 -24 -23 -23 -22 -22 -21 -21 -20 -20 -19 -19 -18 -18 -17 -17 -16 -16 -15 -15 -14 -14 -13 -13 -12 -12 -11 -11 -10 -10 -9 -9 -8 -8 -7 -7 -6 -6 -5 -5 -4 -4 -3 -3 -2 -2 -1 -1 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11 12 12 13 13 14 14 15 15 16 16 17 17 18 18 19 19 20 20 21 21 22 22 23 23 24 24 25 25 26 26 27 27 28 28 29 29 30 30 31 31 32 32 33 33 34 34 35 35 36 36 37 37 38 38 39 39 40 40 41 41 42 42 43 43 44 44 45 45 46 46 47 47 48 48 49 49 50 50 51 51 52 52 53 53 54 54 55 55 56 56 57 57 58 58 59 59 60 60 61 61 62 62 63 63 64 64 65 65 66 66 67 67 68 68 69 69 70 70 71 71 72 72 73 73 74 74 75 75 76 76 77 77 78 78 79 79 80 80 81 81 82 82 83 83 84 84 85 85 86 86 87 87 88 88 89 89 90 90 91 91 92 92 93 93 94 94 95 95 96 96 97 97 98 98 99 99 100 100 101 101 102 102 103 103 104 104 105 105 106 106 107 107 108 108 109 109 110 110 111 111 112 112 113 113 114 114 115 115 116 116 117 117 118 118 119 119 120 120 121 121 122 122 123 123 124 124 125 125 126 126 127 127 -128 -128 -127 -127 -126 -126 -125 -125 -124 -124 -123 -123 -122 -122 -121 -121 -120 -120 -119 -119 -118 -118 -117 -117 -116 -116 -115 -115 -114 -114 -113 -113 -112 -112 -111 -111 -110 -110 -109 -109 -108 -108 -107 -107 -106 -106 -105 -105 -104 -104 -103 -103 -102 -102 -101 -101 -100 -100 -99 -99 -98 -98 -97 -97 -96 -96 -95 -95 -94 -94 -93 -93 -92 -92 -91 -91 -90 -90 -89 -89 -88 -88 -87 -87 -86 -86 -85 -85 -84 -84 -83 -83 -82 -82 -81 -81 -80 -80 -79 -79 -78 -78 -77 -77 -76 -76 -75 -75 -74 -74 -73 -73 -72 -72 -71 -71 -70 -70 -69 -69 -68 -68 -67 -67 -66 -66 -65 -65 -64 -64 -63 -63 -62 -62 -61 -61 -60 -60 -59 -59 -58 -58 -57 -57 -56 -56 -55 -55 -54 -54 -53 -53 -52 -52 -51 -51 -50 -50 -49 -49 -48 -48 -47 -47 -46 -46 -45 -45 -44 -44 -43 -43 -42 -42 -41 -41 -40 -40 -39 -39 -38 -38 -37 -37 -36 -36 -35 -35 -34 -34 -33 -33 -32 -32 -31 -31 -30 -30 -29 -29 -28 -28 -27 -27 -26 -26 -25 -25 -24 -24 -23 -23 -22 -22 -21 -21 -20 -20 -19 -19 -18 -18 -17 -17 -16 -16 -15 -15 -14 -14 -13 -13 -12 -12 -11 -11 -10 -10 -9 -9 -8 -8 -7 -7 -6 -6 -5 -5 -4 -4 -3 -3 -2 -2 -1 -1 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11 12 12 13 13 14 14 15 15 16 16 17 17 18 18 19 19 20 20 21 21 22 22 23 23 24 24 25 25 26 26 27 27 28 28 29 29 30 30 31 31 32 32 33 33 34 34 35 35 36 36 37 37 38 38 39 39 40 40 41 41 42 42 43 43 44 44 45 45 46 46 47 47 48 48 49 49 50 50 51 51 52 52 53 53 54 54 55 55 56 56 57 57 58 58 59 59 60 60 61 61 62 62 63 63 64 64 65 65 66 66 67 67 68 68 69 69 70 70 71 71 72 72 73 73 74 74 75 75 76 76 77 77 78 78 79 79 80 80 81 81 82 82 83 83 84 84 85 85 86 86 87 87 88 88 89 89 90 90 91 91 92 92 93 93 94 94 95 95 96 96 97 97 98 98 99 99 100 100 101 101 102 102 103 103 104 104 105 105 106 106 107 107 108 108 109 109 110 110 111 111 112 112 113 113 114 114 115 115 116 116 117 117 118 118 119 119 120 120 121 121 122 122 123 123 124 124 125 125 126 126 127 127 -128 -128 -127 -127 -126 -126 -125 -125 -124 -124 -123 -123 -122 -122 -121 -121 -120 -120 -119 -119 -118 -118 -117 -117 -116 -116 -115 -115 -114 -114 -113 -113 -112 -112 -111 -111 -110 -110 -109 -109 -108 -108 -107 -107 -106 -106 -105 -105 -104 -104 -103 -103 -102 -102 -101 -101 -100 -100 -99 -99 -98 -98 -97 -97 -96 -96 -95 -95 -94 -94 -93 -93 -92 -92 -91 -91 -90 -90 -89 -89 -88 -88 -87 -87 -86 -86 -85 -85 -84 -84 -83 -83 -82 -82 -81 -81 -80 -80 -79 -79 -78 -78 -77 -77 -76 -76 -75 -75 -74 -74 -73 -73 -72 -72 -71 -71 -70 -70 -69 -69 -68 -68 -67 -67 -66 -66 -65 -65 -64 -64 -63 -63 -62 -62 -61 -61 -60 -60 -59 -59 -58 -58 -57 -57 -56 -56 -55 -55 -54 -54 -53 -53 -52 -52 -51 -51 -50 -50 -49 -49 -48 -48 -47 -47 -46 -46 -45 -45 -44 -44 -43 -43 -42 -42 -41 -41 -40 -40 -39 -39 -38 -38 -37 -37 -36 -36 -35 -35 -34 -34 -33 -33 -32 -32 -31 -31 -30 -30 -29 -29 -28 -28 -27 -27 -26 -26 -25 -25 -24 -24 -23 -23 -22 -22 -21 -21 -20 -20 -19 -19 -18 -18 -17 -17 -16 -16 -15 -15 -14 -14 -13 -13 -12 -12 -11 -11 -10 -10 -9 -9 -8 -8 -7 -7 -6 -6 -5 -5 -4 -4 -3 -3 -2 -2 -1 -1
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:1981]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 1982
+ 73 73 42 0 -126 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 21 0 0 1 3 0 1 0 0 0 11 0 0 0 1 1 3 0 1 0 0 0 11 0 0 0 2 1 3 0 1 0 0 0 8 0 0 0 3 1 3 0 1 0 0 0 1 0 0 0 6 1 3 0 1 0 0 0 3 0 0 0 10 1 3 0 1 0 0 0 1 0 0 0 13 1 2 0 6 0 0 0 -124 1 0 0 17 1 4 0 1 0 0 0 8 0 0 0 18 1 3 0 1 0 0 0 1 0 0 0 21 1 3 0 1 0 0 0 1 0 0 0 22 1 3 0 1 0 0 0 -24 2 0 0 23 1 4 0 1 0 0 0 121 0 0 0 26 1 5 0 1 0 0 0 -118 1 0 0 27 1 5 0 1 0 0 0 -110 1 0 0 28 1 3 0 1 0 0 0 1 0 0 0 30 1 5 0 1 0 0 0 -102 1 0 0 31 1 5 0 1 0 0 0 -94 1 0 0 40 1 3 0 1 0 0 0 2 0 0 0 49 1 2 0 9 0 0 0 -86 1 0 0 59 1 2 0 9 0 0 0 -76 1 0 0 64 1 3 0 0 3 0 0 -66 1 0 0 0 0 0 0 73 109 97 103 101 0 0 0 0 90 0 0 0 1 0 0 0 90 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 82 97 115 68 97 77 97 110 0 0 82 97 115 68 97 77 97 110 0 0 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11 12 12 13 13 14 14 15 15 16 16 17 17 18 18 19 19 20 20 21 21 22 22 23 23 24 24 25 25 26 26 27 27 28 28 29 29 30 30 31 31 32 32 33 33 34 34 35 35 36 36 37 37 38 38 39 39 40 40 41 41 42 42 43 43 44 44 45 45 46 46 47 47 48 48 49 49 50 50 51 51 52 52 53 53 54 54 55 55 56 56 57 57 58 58 59 59 60 60 61 61 62 62 63 63 64 64 65 65 66 66 67 67 68 68 69 69 70 70 71 71 72 72 73 73 74 74 75 75 76 76 77 77 78 78 79 79 80 80 81 81 82 82 83 83 84 84 85 85 86 86 87 87 88 88 89 89 90 90 91 91 92 92 93 93 94 94 95 95 96 96 97 97 98 98 99 99 100 100 101 101 102 102 103 103 104 104 105 105 106 106 107 107 108 108 109 109 110 110 111 111 112 112 113 113 114 114 115 115 116 116 117 117 118 118 119 119 120 120 121 121 122 122 123 123 124 124 125 125 126 126 127 127 -128 -128 -127 -127 -126 -126 -125 -125 -124 -124 -123 -123 -122 -122 -121 -121 -120 -120 -119 -119 -118 -118 -117 -117 -116 -116 -115 -115 -114 -114 -113 -113 -112 -112 -111 -111 -110 -110 -109 -109 -108 -108 -107 -107 -106 -106 -105 -105 -104 -104 -103 -103 -102 -102 -101 -101 -100 -100 -99 -99 -98 -98 -97 -97 -96 -96 -95 -95 -94 -94 -93 -93 -92 -92 -91 -91 -90 -90 -89 -89 -88 -88 -87 -87 -86 -86 -85 -85 -84 -84 -83 -83 -82 -82 -81 -81 -80 -80 -79 -79 -78 -78 -77 -77 -76 -76 -75 -75 -74 -74 -73 -73 -72 -72 -71 -71 -70 -70 -69 -69 -68 -68 -67 -67 -66 -66 -65 -65 -64 -64 -63 -63 -62 -62 -61 -61 -60 -60 -59 -59 -58 -58 -57 -57 -56 -56 -55 -55 -54 -54 -53 -53 -52 -52 -51 -51 -50 -50 -49 -49 -48 -48 -47 -47 -46 -46 -45 -45 -44 -44 -43 -43 -42 -42 -41 -41 -40 -40 -39 -39 -38 -38 -37 -37 -36 -36 -35 -35 -34 -34 -33 -33 -32 -32 -31 -31 -30 -30 -29 -29 -28 -28 -27 -27 -26 -26 -25 -25 -24 -24 -23 -23 -22 -22 -21 -21 -20 -20 -19 -19 -18 -18 -17 -17 -16 -16 -15 -15 -14 -14 -13 -13 -12 -12 -11 -11 -10 -10 -9 -9 -8 -8 -7 -7 -6 -6 -5 -5 -4 -4 -3 -3 -2 -2 -1 -1 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11 12 12 13 13 14 14 15 15 16 16 17 17 18 18 19 19 20 20 21 21 22 22 23 23 24 24 25 25 26 26 27 27 28 28 29 29 30 30 31 31 32 32 33 33 34 34 35 35 36 36 37 37 38 38 39 39 40 40 41 41 42 42 43 43 44 44 45 45 46 46 47 47 48 48 49 49 50 50 51 51 52 52 53 53 54 54 55 55 56 56 57 57 58 58 59 59 60 60 61 61 62 62 63 63 64 64 65 65 66 66 67 67 68 68 69 69 70 70 71 71 72 72 73 73 74 74 75 75 76 76 77 77 78 78 79 79 80 80 81 81 82 82 83 83 84 84 85 85 86 86 87 87 88 88 89 89 90 90 91 91 92 92 93 93 94 94 95 95 96 96 97 97 98 98 99 99 100 100 101 101 102 102 103 103 104 104 105 105 106 106 107 107 108 108 109 109 110 110 111 111 112 112 113 113 114 114 115 115 116 116 117 117 118 118 119 119 120 120 121 121 122 122 123 123 124 124 125 125 126 126 127 127 -128 -128 -127 -127 -126 -126 -125 -125 -124 -124 -123 -123 -122 -122 -121 -121 -120 -120 -119 -119 -118 -118 -117 -117 -116 -116 -115 -115 -114 -114 -113 -113 -112 -112 -111 -111 -110 -110 -109 -109 -108 -108 -107 -107 -106 -106 -105 -105 -104 -104 -103 -103 -102 -102 -101 -101 -100 -100 -99 -99 -98 -98 -97 -97 -96 -96 -95 -95 -94 -94 -93 -93 -92 -92 -91 -91 -90 -90 -89 -89 -88 -88 -87 -87 -86 -86 -85 -85 -84 -84 -83 -83 -82 -82 -81 -81 -80 -80 -79 -79 -78 -78 -77 -77 -76 -76 -75 -75 -74 -74 -73 -73 -72 -72 -71 -71 -70 -70 -69 -69 -68 -68 -67 -67 -66 -66 -65 -65 -64 -64 -63 -63 -62 -62 -61 -61 -60 -60 -59 -59 -58 -58 -57 -57 -56 -56 -55 -55 -54 -54 -53 -53 -52 -52 -51 -51 -50 -50 -49 -49 -48 -48 -47 -47 -46 -46 -45 -45 -44 -44 -43 -43 -42 -42 -41 -41 -40 -40 -39 -39 -38 -38 -37 -37 -36 -36 -35 -35 -34 -34 -33 -33 -32 -32 -31 -31 -30 -30 -29 -29 -28 -28 -27 -27 -26 -26 -25 -25 -24 -24 -23 -23 -22 -22 -21 -21 -20 -20 -19 -19 -18 -18 -17 -17 -16 -16 -15 -15 -14 -14 -13 -13 -12 -12 -11 -11 -10 -10 -9 -9 -8 -8 -7 -7 -6 -6 -5 -5 -4 -4 -3 -3 -2 -2 -1 -1 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11 12 12 13 13 14 14 15 15 16 16 17 17 18 18 19 19 20 20 21 21 22 22 23 23 24 24 25 25 26 26 27 27 28 28 29 29 30 30 31 31 32 32 33 33 34 34 35 35 36 36 37 37 38 38 39 39 40 40 41 41 42 42 43 43 44 44 45 45 46 46 47 47 48 48 49 49 50 50 51 51 52 52 53 53 54 54 55 55 56 56 57 57 58 58 59 59 60 60 61 61 62 62 63 63 64 64 65 65 66 66 67 67 68 68 69 69 70 70 71 71 72 72 73 73 74 74 75 75 76 76 77 77 78 78 79 79 80 80 81 81 82 82 83 83 84 84 85 85 86 86 87 87 88 88 89 89 90 90 91 91 92 92 93 93 94 94 95 95 96 96 97 97 98 98 99 99 100 100 101 101 102 102 103 103 104 104 105 105 106 106 107 107 108 108 109 109 110 110 111 111 112 112 113 113 114 114 115 115 116 116 117 117 118 118 119 119 120 120 121 121 122 122 123 123 124 124 125 125 126 126 127 127 -128 -128 -127 -127 -126 -126 -125 -125 -124 -124 -123 -123 -122 -122 -121 -121 -120 -120 -119 -119 -118 -118 -117 -117 -116 -116 -115 -115 -114 -114 -113 -113 -112 -112 -111 -111 -110 -110 -109 -109 -108 -108 -107 -107 -106 -106 -105 -105 -104 -104 -103 -103 -102 -102 -101 -101 -100 -100 -99 -99 -98 -98 -97 -97 -96 -96 -95 -95 -94 -94 -93 -93 -92 -92 -91 -91 -90 -90 -89 -89 -88 -88 -87 -87 -86 -86 -85 -85 -84 -84 -83 -83 -82 -82 -81 -81 -80 -80 -79 -79 -78 -78 -77 -77 -76 -76 -75 -75 -74 -74 -73 -73 -72 -72 -71 -71 -70 -70 -69 -69 -68 -68 -67 -67 -66 -66 -65 -65 -64 -64 -63 -63 -62 -62 -61 -61 -60 -60 -59 -59 -58 -58 -57 -57 -56 -56 -55 -55 -54 -54 -53 -53 -52 -52 -51 -51 -50 -50 -49 -49 -48 -48 -47 -47 -46 -46 -45 -45 -44 -44 -43 -43 -42 -42 -41 -41 -40 -40 -39 -39 -38 -38 -37 -37 -36 -36 -35 -35 -34 -34 -33 -33 -32 -32 -31 -31 -30 -30 -29 -29 -28 -28 -27 -27 -26 -26 -25 -25 -24 -24 -23 -23 -22 -22 -21 -21 -20 -20 -19 -19 -18 -18 -17 -17 -16 -16 -15 -15 -14 -14 -13 -13 -12 -12 -11 -11 -10 -10 -9 -9 -8 -8 -7 -7 -6 -6 -5 -5 -4 -4 -3 -3 -2 -2 -1 -1 \ No newline at end of file
diff --git a/systemtest/testdata/conversion/tiff1.ql.out b/systemtest/testdata/conversion/tiff1.ql.out
new file mode 100644
index 0000000..52d3548
--- /dev/null
+++ b/systemtest/testdata/conversion/tiff1.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set <marray <char, [0:1981]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1 written to image1.tif
+Image 2 written to image2.tif
+-- Testbed end block:
diff --git a/systemtest/testdata/conversion/tiff2.ql b/systemtest/testdata/conversion/tiff2.ql
new file mode 100644
index 0000000..2f2f3aa
--- /dev/null
+++ b/systemtest/testdata/conversion/tiff2.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <char, [0:1919]>>
+-- Testbed: result_elements=2
+
+SELECT tiff(a)
+FROM ImgRGBA AS a
diff --git a/systemtest/testdata/conversion/tiff2.ql.java.out b/systemtest/testdata/conversion/tiff2.ql.java.out
new file mode 100644
index 0000000..2c61647
--- /dev/null
+++ b/systemtest/testdata/conversion/tiff2.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:2229]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 2230
+ 73 73 42 0 116 1 0 0 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 0 21 0 0 1 3 0 1 0 0 0 11 0 0 0 1 1 3 0 1 0 0 0 11 0 0 0 2 1 3 0 3 0 0 0 118 2 0 0 3 1 3 0 1 0 0 0 1 0 0 0 6 1 3 0 1 0 0 0 2 0 0 0 10 1 3 0 1 0 0 0 1 0 0 0 13 1 2 0 6 0 0 0 124 2 0 0 17 1 4 0 1 0 0 0 8 0 0 0 18 1 3 0 1 0 0 0 1 0 0 0 21 1 3 0 1 0 0 0 3 0 0 0 22 1 3 0 1 0 0 0 -8 0 0 0 23 1 4 0 1 0 0 0 107 1 0 0 26 1 5 0 1 0 0 0 -126 2 0 0 27 1 5 0 1 0 0 0 -118 2 0 0 28 1 3 0 1 0 0 0 1 0 0 0 30 1 5 0 1 0 0 0 -110 2 0 0 31 1 5 0 1 0 0 0 -102 2 0 0 40 1 3 0 1 0 0 0 2 0 0 0 49 1 2 0 9 0 0 0 -94 2 0 0 59 1 2 0 9 0 0 0 -84 2 0 0 64 1 3 0 0 3 0 0 -74 2 0 0 0 0 0 0 8 0 8 0 8 0 73 109 97 103 101 0 0 0 0 90 0 0 0 1 0 0 0 90 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 82 97 115 68 97 77 97 110 0 0 82 97 115 68 97 77 97 110 0 0 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11 12 12 13 13 14 14 15 15 16 16 17 17 18 18 19 19 20 20 21 21 22 22 23 23 24 24 25 25 26 26 27 27 28 28 29 29 30 30 31 31 32 32 33 33 34 34 35 35 36 36 37 37 38 38 39 39 40 40 41 41 42 42 43 43 44 44 45 45 46 46 47 47 48 48 49 49 50 50 51 51 52 52 53 53 54 54 55 55 56 56 57 57 58 58 59 59 60 60 61 61 62 62 63 63 64 64 65 65 66 66 67 67 68 68 69 69 70 70 71 71 72 72 73 73 74 74 75 75 76 76 77 77 78 78 79 79 80 80 81 81 82 82 83 83 84 84 85 85 86 86 87 87 88 88 89 89 90 90 91 91 92 92 93 93 94 94 95 95 96 96 97 97 98 98 99 99 100 100 101 101 102 102 103 103 104 104 105 105 106 106 107 107 108 108 109 109 110 110 111 111 112 112 113 113 114 114 115 115 116 116 117 117 118 118 119 119 120 120 121 121 122 122 123 123 124 124 125 125 126 126 127 127 -128 -128 -127 -127 -126 -126 -125 -125 -124 -124 -123 -123 -122 -122 -121 -121 -120 -120 -119 -119 -118 -118 -117 -117 -116 -116 -115 -115 -114 -114 -113 -113 -112 -112 -111 -111 -110 -110 -109 -109 -108 -108 -107 -107 -106 -106 -105 -105 -104 -104 -103 -103 -102 -102 -101 -101 -100 -100 -99 -99 -98 -98 -97 -97 -96 -96 -95 -95 -94 -94 -93 -93 -92 -92 -91 -91 -90 -90 -89 -89 -88 -88 -87 -87 -86 -86 -85 -85 -84 -84 -83 -83 -82 -82 -81 -81 -80 -80 -79 -79 -78 -78 -77 -77 -76 -76 -75 -75 -74 -74 -73 -73 -72 -72 -71 -71 -70 -70 -69 -69 -68 -68 -67 -67 -66 -66 -65 -65 -64 -64 -63 -63 -62 -62 -61 -61 -60 -60 -59 -59 -58 -58 -57 -57 -56 -56 -55 -55 -54 -54 -53 -53 -52 -52 -51 -51 -50 -50 -49 -49 -48 -48 -47 -47 -46 -46 -45 -45 -44 -44 -43 -43 -42 -42 -41 -41 -40 -40 -39 -39 -38 -38 -37 -37 -36 -36 -35 -35 -34 -34 -33 -33 -32 -32 -31 -31 -30 -30 -29 -29 -28 -28 -27 -27 -26 -26 -25 -25 -24 -24 -23 -23 -22 -22 -21 -21 -20 -20 -19 -19 -18 -18 -17 -17 -16 -16 -15 -15 -14 -14 -13 -13 -12 -12 -11 -11 -10 -10 -9 -9 -8 -8 -7 -7 -6 -6 -5 -5 -4 -4 -3 -3 -2 -2 -1 -1 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11 12 12 13 13 14 14 15 15 16 16 17 17 18 18 19 19 20 20 21 21 22 22 23 23 24 24 25 25 26 26 27 27 28 28 29 29 30 30 31 31 32 32 33 33 34 34 35 35 36 36 37 37 38 38 39 39 40 40 41 41 42 42 43 43 44 44 45 45 46 46 47 47 48 48 49 49 50 50 51 51 52 52 53 53 54 54 55 55 56 56 57 57 58 58 59 59 60 60 61 61 62 62 63 63 64 64 65 65 66 66 67 67 68 68 69 69 70 70 71 71 72 72 73 73 74 74 75 75 76 76 77 77 78 78 79 79 80 80 81 81 82 82 83 83 84 84 85 85 86 86 87 87 88 88 89 89 90 90 91 91 92 92 93 93 94 94 95 95 96 96 97 97 98 98 99 99 100 100 101 101 102 102 103 103 104 104 105 105 106 106 107 107 108 108 109 109 110 110 111 111 112 112 113 113 114 114 115 115 116 116 117 117 118 118 119 119 120 120 121 121 122 122 123 123 124 124 125 125 126 126 127 127 -128 -128 -127 -127 -126 -126 -125 -125 -124 -124 -123 -123 -122 -122 -121 -121 -120 -120 -119 -119 -118 -118 -117 -117 -116 -116 -115 -115 -114 -114 -113 -113 -112 -112 -111 -111 -110 -110 -109 -109 -108 -108 -107 -107 -106 -106 -105 -105 -104 -104 -103 -103 -102 -102 -101 -101 -100 -100 -99 -99 -98 -98 -97 -97 -96 -96 -95 -95 -94 -94 -93 -93 -92 -92 -91 -91 -90 -90 -89 -89 -88 -88 -87 -87 -86 -86 -85 -85 -84 -84 -83 -83 -82 -82 -81 -81 -80 -80 -79 -79 -78 -78 -77 -77 -76 -76 -75 -75 -74 -74 -73 -73 -72 -72 -71 -71 -70 -70 -69 -69 -68 -68 -67 -67 -66 -66 -65 -65 -64 -64 -63 -63 -62 -62 -61 -61 -60 -60 -59 -59 -58 -58 -57 -57 -56 -56 -55 -55 -54 -54 -53 -53 -52 -52 -51 -51 -50 -50 -49 -49 -48 -48 -47 -47 -46 -46 -45 -45 -44 -44 -43 -43 -42 -42 -41 -41 -40 -40 -39 -39 -38 -38 -37 -37 -36 -36 -35 -35 -34 -34 -33 -33 -32 -32 -31 -31 -30 -30 -29 -29 -28 -28 -27 -27 -26 -26 -25 -25 -24 -24 -23 -23 -22 -22 -21 -21 -20 -20 -19 -19 -18 -18 -17 -17 -16 -16 -15 -15 -14 -14 -13 -13 -12 -12 -11 -11 -10 -10 -9 -9 -8 -8 -7 -7 -6 -6 -5 -5 -4 -4 -3 -3 -2 -2 -1 -1 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11 12 12 13 13 14 14 15 15 16 16 17 17 18 18 19 19 20 20 21 21 22 22 23 23 24 24 25 25 26 26 27 27 28 28 29 29 30 30 31 31 32 32 33 33 34 34 35 35 36 36 37 37 38 38 39 39 40 40 41 41 42 42 43 43 44 44 45 45 46 46 47 47 48 48 49 49 50 50 51 51 52 52 53 53 54 54 55 55 56 56 57 57 58 58 59 59 60 60 61 61 62 62 63 63 64 64 65 65 66 66 67 67 68 68 69 69 70 70 71 71 72 72 73 73 74 74 75 75 76 76 77 77 78 78 79 79 80 80 81 81 82 82 83 83 84 84 85 85 86 86 87 87 88 88 89 89 90 90 91 91 92 92 93 93 94 94 95 95 96 96 97 97 98 98 99 99 100 100 101 101 102 102 103 103 104 104 105 105 106 106 107 107 108 108 109 109 110 110 111 111 112 112 113 113 114 114 115 115 116 116 117 117 118 118 119 119 120 120 121 121 122 122 123 123 124 124 125 125 126 126 127 127 -128 -128 -127 -127 -126 -126 -125 -125 -124 -124 -123 -123 -122 -122 -121 -121 -120 -120 -119 -119 -118 -118 -117 -117 -116 -116 -115 -115 -114 -114 -113 -113 -112 -112 -111 -111 -110 -110 -109 -109 -108 -108 -107 -107 -106 -106 -105 -105 -104 -104 -103 -103 -102 -102 -101 -101 -100 -100 -99 -99 -98 -98 -97 -97 -96 -96 -95 -95 -94 -94 -93 -93 -92 -92 -91 -91 -90 -90 -89 -89 -88 -88 -87 -87 -86 -86 -85 -85 -84 -84 -83 -83 -82 -82 -81 -81 -80 -80 -79 -79 -78 -78 -77 -77 -76 -76 -75 -75 -74 -74 -73 -73 -72 -72 -71 -71 -70 -70 -69 -69 -68 -68 -67 -67 -66 -66 -65 -65 -64 -64 -63 -63 -62 -62 -61 -61 -60 -60 -59 -59 -58 -58 -57 -57 -56 -56 -55 -55 -54 -54 -53 -53 -52 -52 -51 -51 -50 -50 -49 -49 -48 -48 -47 -47 -46 -46 -45 -45 -44 -44 -43 -43 -42 -42 -41 -41 -40 -40 -39 -39 -38 -38 -37 -37 -36 -36 -35 -35 -34 -34 -33 -33 -32 -32 -31 -31 -30 -30 -29 -29 -28 -28 -27 -27 -26 -26 -25 -25 -24 -24 -23 -23 -22 -22 -21 -21 -20 -20 -19 -19 -18 -18 -17 -17 -16 -16 -15 -15 -14 -14 -13 -13 -12 -12 -11 -11 -10 -10 -9 -9 -8 -8 -7 -7 -6 -6 -5 -5 -4 -4 -3 -3 -2 -2 -1 -1
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:2229]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 2230
+ 73 73 42 0 116 1 0 0 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 0 21 0 0 1 3 0 1 0 0 0 11 0 0 0 1 1 3 0 1 0 0 0 11 0 0 0 2 1 3 0 3 0 0 0 118 2 0 0 3 1 3 0 1 0 0 0 1 0 0 0 6 1 3 0 1 0 0 0 2 0 0 0 10 1 3 0 1 0 0 0 1 0 0 0 13 1 2 0 6 0 0 0 124 2 0 0 17 1 4 0 1 0 0 0 8 0 0 0 18 1 3 0 1 0 0 0 1 0 0 0 21 1 3 0 1 0 0 0 3 0 0 0 22 1 3 0 1 0 0 0 -8 0 0 0 23 1 4 0 1 0 0 0 107 1 0 0 26 1 5 0 1 0 0 0 -126 2 0 0 27 1 5 0 1 0 0 0 -118 2 0 0 28 1 3 0 1 0 0 0 1 0 0 0 30 1 5 0 1 0 0 0 -110 2 0 0 31 1 5 0 1 0 0 0 -102 2 0 0 40 1 3 0 1 0 0 0 2 0 0 0 49 1 2 0 9 0 0 0 -94 2 0 0 59 1 2 0 9 0 0 0 -84 2 0 0 64 1 3 0 0 3 0 0 -74 2 0 0 0 0 0 0 8 0 8 0 8 0 73 109 97 103 101 0 0 0 0 90 0 0 0 1 0 0 0 90 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 82 97 115 68 97 77 97 110 0 0 82 97 115 68 97 77 97 110 0 0 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11 12 12 13 13 14 14 15 15 16 16 17 17 18 18 19 19 20 20 21 21 22 22 23 23 24 24 25 25 26 26 27 27 28 28 29 29 30 30 31 31 32 32 33 33 34 34 35 35 36 36 37 37 38 38 39 39 40 40 41 41 42 42 43 43 44 44 45 45 46 46 47 47 48 48 49 49 50 50 51 51 52 52 53 53 54 54 55 55 56 56 57 57 58 58 59 59 60 60 61 61 62 62 63 63 64 64 65 65 66 66 67 67 68 68 69 69 70 70 71 71 72 72 73 73 74 74 75 75 76 76 77 77 78 78 79 79 80 80 81 81 82 82 83 83 84 84 85 85 86 86 87 87 88 88 89 89 90 90 91 91 92 92 93 93 94 94 95 95 96 96 97 97 98 98 99 99 100 100 101 101 102 102 103 103 104 104 105 105 106 106 107 107 108 108 109 109 110 110 111 111 112 112 113 113 114 114 115 115 116 116 117 117 118 118 119 119 120 120 121 121 122 122 123 123 124 124 125 125 126 126 127 127 -128 -128 -127 -127 -126 -126 -125 -125 -124 -124 -123 -123 -122 -122 -121 -121 -120 -120 -119 -119 -118 -118 -117 -117 -116 -116 -115 -115 -114 -114 -113 -113 -112 -112 -111 -111 -110 -110 -109 -109 -108 -108 -107 -107 -106 -106 -105 -105 -104 -104 -103 -103 -102 -102 -101 -101 -100 -100 -99 -99 -98 -98 -97 -97 -96 -96 -95 -95 -94 -94 -93 -93 -92 -92 -91 -91 -90 -90 -89 -89 -88 -88 -87 -87 -86 -86 -85 -85 -84 -84 -83 -83 -82 -82 -81 -81 -80 -80 -79 -79 -78 -78 -77 -77 -76 -76 -75 -75 -74 -74 -73 -73 -72 -72 -71 -71 -70 -70 -69 -69 -68 -68 -67 -67 -66 -66 -65 -65 -64 -64 -63 -63 -62 -62 -61 -61 -60 -60 -59 -59 -58 -58 -57 -57 -56 -56 -55 -55 -54 -54 -53 -53 -52 -52 -51 -51 -50 -50 -49 -49 -48 -48 -47 -47 -46 -46 -45 -45 -44 -44 -43 -43 -42 -42 -41 -41 -40 -40 -39 -39 -38 -38 -37 -37 -36 -36 -35 -35 -34 -34 -33 -33 -32 -32 -31 -31 -30 -30 -29 -29 -28 -28 -27 -27 -26 -26 -25 -25 -24 -24 -23 -23 -22 -22 -21 -21 -20 -20 -19 -19 -18 -18 -17 -17 -16 -16 -15 -15 -14 -14 -13 -13 -12 -12 -11 -11 -10 -10 -9 -9 -8 -8 -7 -7 -6 -6 -5 -5 -4 -4 -3 -3 -2 -2 -1 -1 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11 12 12 13 13 14 14 15 15 16 16 17 17 18 18 19 19 20 20 21 21 22 22 23 23 24 24 25 25 26 26 27 27 28 28 29 29 30 30 31 31 32 32 33 33 34 34 35 35 36 36 37 37 38 38 39 39 40 40 41 41 42 42 43 43 44 44 45 45 46 46 47 47 48 48 49 49 50 50 51 51 52 52 53 53 54 54 55 55 56 56 57 57 58 58 59 59 60 60 61 61 62 62 63 63 64 64 65 65 66 66 67 67 68 68 69 69 70 70 71 71 72 72 73 73 74 74 75 75 76 76 77 77 78 78 79 79 80 80 81 81 82 82 83 83 84 84 85 85 86 86 87 87 88 88 89 89 90 90 91 91 92 92 93 93 94 94 95 95 96 96 97 97 98 98 99 99 100 100 101 101 102 102 103 103 104 104 105 105 106 106 107 107 108 108 109 109 110 110 111 111 112 112 113 113 114 114 115 115 116 116 117 117 118 118 119 119 120 120 121 121 122 122 123 123 124 124 125 125 126 126 127 127 -128 -128 -127 -127 -126 -126 -125 -125 -124 -124 -123 -123 -122 -122 -121 -121 -120 -120 -119 -119 -118 -118 -117 -117 -116 -116 -115 -115 -114 -114 -113 -113 -112 -112 -111 -111 -110 -110 -109 -109 -108 -108 -107 -107 -106 -106 -105 -105 -104 -104 -103 -103 -102 -102 -101 -101 -100 -100 -99 -99 -98 -98 -97 -97 -96 -96 -95 -95 -94 -94 -93 -93 -92 -92 -91 -91 -90 -90 -89 -89 -88 -88 -87 -87 -86 -86 -85 -85 -84 -84 -83 -83 -82 -82 -81 -81 -80 -80 -79 -79 -78 -78 -77 -77 -76 -76 -75 -75 -74 -74 -73 -73 -72 -72 -71 -71 -70 -70 -69 -69 -68 -68 -67 -67 -66 -66 -65 -65 -64 -64 -63 -63 -62 -62 -61 -61 -60 -60 -59 -59 -58 -58 -57 -57 -56 -56 -55 -55 -54 -54 -53 -53 -52 -52 -51 -51 -50 -50 -49 -49 -48 -48 -47 -47 -46 -46 -45 -45 -44 -44 -43 -43 -42 -42 -41 -41 -40 -40 -39 -39 -38 -38 -37 -37 -36 -36 -35 -35 -34 -34 -33 -33 -32 -32 -31 -31 -30 -30 -29 -29 -28 -28 -27 -27 -26 -26 -25 -25 -24 -24 -23 -23 -22 -22 -21 -21 -20 -20 -19 -19 -18 -18 -17 -17 -16 -16 -15 -15 -14 -14 -13 -13 -12 -12 -11 -11 -10 -10 -9 -9 -8 -8 -7 -7 -6 -6 -5 -5 -4 -4 -3 -3 -2 -2 -1 -1 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11 12 12 13 13 14 14 15 15 16 16 17 17 18 18 19 19 20 20 21 21 22 22 23 23 24 24 25 25 26 26 27 27 28 28 29 29 30 30 31 31 32 32 33 33 34 34 35 35 36 36 37 37 38 38 39 39 40 40 41 41 42 42 43 43 44 44 45 45 46 46 47 47 48 48 49 49 50 50 51 51 52 52 53 53 54 54 55 55 56 56 57 57 58 58 59 59 60 60 61 61 62 62 63 63 64 64 65 65 66 66 67 67 68 68 69 69 70 70 71 71 72 72 73 73 74 74 75 75 76 76 77 77 78 78 79 79 80 80 81 81 82 82 83 83 84 84 85 85 86 86 87 87 88 88 89 89 90 90 91 91 92 92 93 93 94 94 95 95 96 96 97 97 98 98 99 99 100 100 101 101 102 102 103 103 104 104 105 105 106 106 107 107 108 108 109 109 110 110 111 111 112 112 113 113 114 114 115 115 116 116 117 117 118 118 119 119 120 120 121 121 122 122 123 123 124 124 125 125 126 126 127 127 -128 -128 -127 -127 -126 -126 -125 -125 -124 -124 -123 -123 -122 -122 -121 -121 -120 -120 -119 -119 -118 -118 -117 -117 -116 -116 -115 -115 -114 -114 -113 -113 -112 -112 -111 -111 -110 -110 -109 -109 -108 -108 -107 -107 -106 -106 -105 -105 -104 -104 -103 -103 -102 -102 -101 -101 -100 -100 -99 -99 -98 -98 -97 -97 -96 -96 -95 -95 -94 -94 -93 -93 -92 -92 -91 -91 -90 -90 -89 -89 -88 -88 -87 -87 -86 -86 -85 -85 -84 -84 -83 -83 -82 -82 -81 -81 -80 -80 -79 -79 -78 -78 -77 -77 -76 -76 -75 -75 -74 -74 -73 -73 -72 -72 -71 -71 -70 -70 -69 -69 -68 -68 -67 -67 -66 -66 -65 -65 -64 -64 -63 -63 -62 -62 -61 -61 -60 -60 -59 -59 -58 -58 -57 -57 -56 -56 -55 -55 -54 -54 -53 -53 -52 -52 -51 -51 -50 -50 -49 -49 -48 -48 -47 -47 -46 -46 -45 -45 -44 -44 -43 -43 -42 -42 -41 -41 -40 -40 -39 -39 -38 -38 -37 -37 -36 -36 -35 -35 -34 -34 -33 -33 -32 -32 -31 -31 -30 -30 -29 -29 -28 -28 -27 -27 -26 -26 -25 -25 -24 -24 -23 -23 -22 -22 -21 -21 -20 -20 -19 -19 -18 -18 -17 -17 -16 -16 -15 -15 -14 -14 -13 -13 -12 -12 -11 -11 -10 -10 -9 -9 -8 -8 -7 -7 -6 -6 -5 -5 -4 -4 -3 -3 -2 -2 -1 -1 \ No newline at end of file
diff --git a/systemtest/testdata/conversion/tiff2.ql.out b/systemtest/testdata/conversion/tiff2.ql.out
new file mode 100644
index 0000000..5b8c057
--- /dev/null
+++ b/systemtest/testdata/conversion/tiff2.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set <marray <char, [0:2229]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1 written to image1.tif
+Image 2 written to image2.tif
+-- Testbed end block:
diff --git a/systemtest/testdata/conversion/vff1.ql b/systemtest/testdata/conversion/vff1.ql
new file mode 100644
index 0000000..e6df59e
--- /dev/null
+++ b/systemtest/testdata/conversion/vff1.ql
@@ -0,0 +1,6 @@
+-- Testbed: result_type=set <marray <char, [0:276]>>
+-- Testbed: result_elements=2
+
+SELECT vff(a)
+FROM ImgCharA AS a
+ \ No newline at end of file
diff --git a/systemtest/testdata/conversion/vff1.ql.java.out b/systemtest/testdata/conversion/vff1.ql.java.out
new file mode 100644
index 0000000..65dcbb3
--- /dev/null
+++ b/systemtest/testdata/conversion/vff1.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:275]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 276
+ 110 99 97 97 10 114 97 110 107 61 50 59 10 116 121 112 101 61 114 97 115 116 101 114 59 10 102 111 114 109 97 116 61 115 108 105 99 101 59 10 115 105 122 101 61 49 49 32 49 49 59 10 111 114 105 103 105 110 61 48 32 48 59 10 101 120 116 101 110 116 61 49 48 32 49 48 59 10 97 115 112 101 99 116 61 49 46 48 32 49 46 48 59 10 98 97 110 100 115 61 49 59 10 98 105 116 115 61 56 59 10 101 110 100 105 97 110 110 101 115 115 61 108 105 116 116 108 101 95 101 110 100 105 97 110 59 10 100 97 116 97 95 111 114 100 101 114 61 120 121 59 10 10 12 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:275]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 276
+ 110 99 97 97 10 114 97 110 107 61 50 59 10 116 121 112 101 61 114 97 115 116 101 114 59 10 102 111 114 109 97 116 61 115 108 105 99 101 59 10 115 105 122 101 61 49 49 32 49 49 59 10 111 114 105 103 105 110 61 48 32 48 59 10 101 120 116 101 110 116 61 49 48 32 49 48 59 10 97 115 112 101 99 116 61 49 46 48 32 49 46 48 59 10 98 97 110 100 115 61 49 59 10 98 105 116 115 61 56 59 10 101 110 100 105 97 110 110 101 115 115 61 108 105 116 116 108 101 95 101 110 100 105 97 110 59 10 100 97 116 97 95 111 114 100 101 114 61 120 121 59 10 10 12 10 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 \ No newline at end of file
diff --git a/systemtest/testdata/conversion/vff1.ql.out b/systemtest/testdata/conversion/vff1.ql.out
new file mode 100644
index 0000000..d6af2ca
--- /dev/null
+++ b/systemtest/testdata/conversion/vff1.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set <marray <char, [0:275]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1 written to image1.vff
+Image 2 written to image2.vff
+-- Testbed end block:
diff --git a/systemtest/testdata/conversion/vff2.ql b/systemtest/testdata/conversion/vff2.ql
new file mode 100644
index 0000000..6047ac1
--- /dev/null
+++ b/systemtest/testdata/conversion/vff2.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <char, [0:1919]>>
+-- Testbed: result_elements=2
+
+SELECT vff(a)
+FROM ImgRGBA AS a
diff --git a/systemtest/testdata/conversion/vff2.ql.java.out b/systemtest/testdata/conversion/vff2.ql.java.out
new file mode 100644
index 0000000..a407a85
--- /dev/null
+++ b/systemtest/testdata/conversion/vff2.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Execution error 381 in line 6, column 8, near token vff: Error in convertor of the selected data exchange format. \ No newline at end of file
diff --git a/systemtest/testdata/conversion/vff2.ql.out b/systemtest/testdata/conversion/vff2.ql.out
new file mode 100644
index 0000000..3684eb8
--- /dev/null
+++ b/systemtest/testdata/conversion/vff2.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=381
diff --git a/systemtest/testdata/empty/empty.ql b/systemtest/testdata/empty/empty.ql
new file mode 100644
index 0000000..3104df5
--- /dev/null
+++ b/systemtest/testdata/empty/empty.ql
@@ -0,0 +1 @@
+-- select a<132 from ImgCharA as a
diff --git a/systemtest/testdata/empty/empty.ql.java.out b/systemtest/testdata/empty/empty.ql.java.out
new file mode 100644
index 0000000..26e1b5c
--- /dev/null
+++ b/systemtest/testdata/empty/empty.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Parsing error: Unexpected end of query. \ No newline at end of file
diff --git a/systemtest/testdata/empty/empty.ql.out b/systemtest/testdata/empty/empty.ql.out
new file mode 100644
index 0000000..d1ec6cb
--- /dev/null
+++ b/systemtest/testdata/empty/empty.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=308
diff --git a/systemtest/testdata/empty/empty2.ql b/systemtest/testdata/empty/empty2.ql
new file mode 100644
index 0000000..76743dc
--- /dev/null
+++ b/systemtest/testdata/empty/empty2.ql
@@ -0,0 +1 @@
+// select a<132 from ImgCharA as a
diff --git a/systemtest/testdata/empty/empty2.ql.java.out b/systemtest/testdata/empty/empty2.ql.java.out
new file mode 100644
index 0000000..26e1b5c
--- /dev/null
+++ b/systemtest/testdata/empty/empty2.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Parsing error: Unexpected end of query. \ No newline at end of file
diff --git a/systemtest/testdata/empty/empty2.ql.out b/systemtest/testdata/empty/empty2.ql.out
new file mode 100644
index 0000000..d1ec6cb
--- /dev/null
+++ b/systemtest/testdata/empty/empty2.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=308
diff --git a/systemtest/testdata/empty/empty3.ql b/systemtest/testdata/empty/empty3.ql
new file mode 100644
index 0000000..6752782
--- /dev/null
+++ b/systemtest/testdata/empty/empty3.ql
@@ -0,0 +1,3 @@
+/*
+ select a<132 from ImgCharA as a
+*/
diff --git a/systemtest/testdata/empty/empty3.ql.java.out b/systemtest/testdata/empty/empty3.ql.java.out
new file mode 100644
index 0000000..26e1b5c
--- /dev/null
+++ b/systemtest/testdata/empty/empty3.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Parsing error: Unexpected end of query. \ No newline at end of file
diff --git a/systemtest/testdata/empty/empty3.ql.out b/systemtest/testdata/empty/empty3.ql.out
new file mode 100644
index 0000000..d1ec6cb
--- /dev/null
+++ b/systemtest/testdata/empty/empty3.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=308
diff --git a/systemtest/testdata/empty/empty4.ql b/systemtest/testdata/empty/empty4.ql
new file mode 100644
index 0000000..0ca7574
--- /dev/null
+++ b/systemtest/testdata/empty/empty4.ql
@@ -0,0 +1,3 @@
+/*
+ select a<132 from ImgCharA as a
+
diff --git a/systemtest/testdata/empty/empty4.ql.java.out b/systemtest/testdata/empty/empty4.ql.java.out
new file mode 100644
index 0000000..65b2739
--- /dev/null
+++ b/systemtest/testdata/empty/empty4.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Parsing error 300 in line 3, column 1: Unexpected name /. \ No newline at end of file
diff --git a/systemtest/testdata/empty/empty4.ql.out b/systemtest/testdata/empty/empty4.ql.out
new file mode 100644
index 0000000..addb1c0
--- /dev/null
+++ b/systemtest/testdata/empty/empty4.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=300
diff --git a/systemtest/testdata/empty/empty5.ql b/systemtest/testdata/empty/empty5.ql
new file mode 100644
index 0000000..7c804a4
--- /dev/null
+++ b/systemtest/testdata/empty/empty5.ql
@@ -0,0 +1,2 @@
+- select a<132 from ImgCharA as a
+
diff --git a/systemtest/testdata/empty/empty5.ql.java.out b/systemtest/testdata/empty/empty5.ql.java.out
new file mode 100644
index 0000000..1c3e17f
--- /dev/null
+++ b/systemtest/testdata/empty/empty5.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Parsing error 300 in line 3, column 1: Unexpected name -. \ No newline at end of file
diff --git a/systemtest/testdata/empty/empty5.ql.out b/systemtest/testdata/empty/empty5.ql.out
new file mode 100644
index 0000000..addb1c0
--- /dev/null
+++ b/systemtest/testdata/empty/empty5.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=300
diff --git a/systemtest/testdata/empty/empty6.ql b/systemtest/testdata/empty/empty6.ql
new file mode 100644
index 0000000..11108c9
--- /dev/null
+++ b/systemtest/testdata/empty/empty6.ql
@@ -0,0 +1,2 @@
+/ select a<132 from ImgCharA as a
+
diff --git a/systemtest/testdata/empty/empty6.ql.java.out b/systemtest/testdata/empty/empty6.ql.java.out
new file mode 100644
index 0000000..65b2739
--- /dev/null
+++ b/systemtest/testdata/empty/empty6.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Parsing error 300 in line 3, column 1: Unexpected name /. \ No newline at end of file
diff --git a/systemtest/testdata/empty/empty6.ql.out b/systemtest/testdata/empty/empty6.ql.out
new file mode 100644
index 0000000..addb1c0
--- /dev/null
+++ b/systemtest/testdata/empty/empty6.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=300
diff --git a/systemtest/testdata/empty/opt.ql b/systemtest/testdata/empty/opt.ql
new file mode 100644
index 0000000..475edc1
--- /dev/null
+++ b/systemtest/testdata/empty/opt.ql
@@ -0,0 +1,3 @@
+/*+opt 0
+ select a<132 from ImgCharA as a
+*/
diff --git a/systemtest/testdata/empty/opt.ql.java.out b/systemtest/testdata/empty/opt.ql.java.out
new file mode 100644
index 0000000..26e1b5c
--- /dev/null
+++ b/systemtest/testdata/empty/opt.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Parsing error: Unexpected end of query. \ No newline at end of file
diff --git a/systemtest/testdata/empty/opt.ql.out b/systemtest/testdata/empty/opt.ql.out
new file mode 100644
index 0000000..d1ec6cb
--- /dev/null
+++ b/systemtest/testdata/empty/opt.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=308
diff --git a/systemtest/testdata/empty/opt1.ql b/systemtest/testdata/empty/opt1.ql
new file mode 100644
index 0000000..b2389e1
--- /dev/null
+++ b/systemtest/testdata/empty/opt1.ql
@@ -0,0 +1,3 @@
+/*+opt 1
+ select a<132 from ImgCharA as a
+*/
diff --git a/systemtest/testdata/empty/opt1.ql.java.out b/systemtest/testdata/empty/opt1.ql.java.out
new file mode 100644
index 0000000..26e1b5c
--- /dev/null
+++ b/systemtest/testdata/empty/opt1.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Parsing error: Unexpected end of query. \ No newline at end of file
diff --git a/systemtest/testdata/empty/opt1.ql.out b/systemtest/testdata/empty/opt1.ql.out
new file mode 100644
index 0000000..d1ec6cb
--- /dev/null
+++ b/systemtest/testdata/empty/opt1.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=308
diff --git a/systemtest/testdata/empty/opt2.ql b/systemtest/testdata/empty/opt2.ql
new file mode 100644
index 0000000..758ff22
--- /dev/null
+++ b/systemtest/testdata/empty/opt2.ql
@@ -0,0 +1,3 @@
+/*+opt 2
+ select a<132 from ImgCharA as a
+*/
diff --git a/systemtest/testdata/empty/opt2.ql.java.out b/systemtest/testdata/empty/opt2.ql.java.out
new file mode 100644
index 0000000..26e1b5c
--- /dev/null
+++ b/systemtest/testdata/empty/opt2.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Parsing error: Unexpected end of query. \ No newline at end of file
diff --git a/systemtest/testdata/empty/opt2.ql.out b/systemtest/testdata/empty/opt2.ql.out
new file mode 100644
index 0000000..d1ec6cb
--- /dev/null
+++ b/systemtest/testdata/empty/opt2.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=308
diff --git a/systemtest/testdata/empty/opt3.ql b/systemtest/testdata/empty/opt3.ql
new file mode 100644
index 0000000..65eb556
--- /dev/null
+++ b/systemtest/testdata/empty/opt3.ql
@@ -0,0 +1,3 @@
+/*+opt 3
+ select a<132 from ImgCharA as a
+*/
diff --git a/systemtest/testdata/empty/opt3.ql.java.out b/systemtest/testdata/empty/opt3.ql.java.out
new file mode 100644
index 0000000..26e1b5c
--- /dev/null
+++ b/systemtest/testdata/empty/opt3.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Parsing error: Unexpected end of query. \ No newline at end of file
diff --git a/systemtest/testdata/empty/opt3.ql.out b/systemtest/testdata/empty/opt3.ql.out
new file mode 100644
index 0000000..d1ec6cb
--- /dev/null
+++ b/systemtest/testdata/empty/opt3.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=308
diff --git a/systemtest/testdata/empty/opt4.ql b/systemtest/testdata/empty/opt4.ql
new file mode 100644
index 0000000..1c6dee8
--- /dev/null
+++ b/systemtest/testdata/empty/opt4.ql
@@ -0,0 +1,3 @@
+/*+opt 4
+ select a<132 from ImgCharA as a
+*/
diff --git a/systemtest/testdata/empty/opt4.ql.java.out b/systemtest/testdata/empty/opt4.ql.java.out
new file mode 100644
index 0000000..26e1b5c
--- /dev/null
+++ b/systemtest/testdata/empty/opt4.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Parsing error: Unexpected end of query. \ No newline at end of file
diff --git a/systemtest/testdata/empty/opt4.ql.out b/systemtest/testdata/empty/opt4.ql.out
new file mode 100644
index 0000000..d1ec6cb
--- /dev/null
+++ b/systemtest/testdata/empty/opt4.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=308
diff --git a/systemtest/testdata/empty/opt41.ql b/systemtest/testdata/empty/opt41.ql
new file mode 100644
index 0000000..e064d9f
--- /dev/null
+++ b/systemtest/testdata/empty/opt41.ql
@@ -0,0 +1,3 @@
+/*+opt 4*/
+ select a<132 from ImgCharA as a
+*/
diff --git a/systemtest/testdata/empty/opt41.ql.java.out b/systemtest/testdata/empty/opt41.ql.java.out
new file mode 100644
index 0000000..da83965
--- /dev/null
+++ b/systemtest/testdata/empty/opt41.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Parsing error 300 in line 5, column 1: Unexpected name *. \ No newline at end of file
diff --git a/systemtest/testdata/empty/opt41.ql.out b/systemtest/testdata/empty/opt41.ql.out
new file mode 100644
index 0000000..addb1c0
--- /dev/null
+++ b/systemtest/testdata/empty/opt41.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=300
diff --git a/systemtest/testdata/empty/opt5.ql b/systemtest/testdata/empty/opt5.ql
new file mode 100644
index 0000000..6136e69
--- /dev/null
+++ b/systemtest/testdata/empty/opt5.ql
@@ -0,0 +1,2 @@
+[opt 0]
+-- select a>123 from ImgChar as a \ No newline at end of file
diff --git a/systemtest/testdata/empty/opt5.ql.java.out b/systemtest/testdata/empty/opt5.ql.java.out
new file mode 100644
index 0000000..26e1b5c
--- /dev/null
+++ b/systemtest/testdata/empty/opt5.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Parsing error: Unexpected end of query. \ No newline at end of file
diff --git a/systemtest/testdata/empty/opt5.ql.out b/systemtest/testdata/empty/opt5.ql.out
new file mode 100644
index 0000000..d1ec6cb
--- /dev/null
+++ b/systemtest/testdata/empty/opt5.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=308
diff --git a/systemtest/testdata/empty/opt6.ql b/systemtest/testdata/empty/opt6.ql
new file mode 100644
index 0000000..ad397b6
--- /dev/null
+++ b/systemtest/testdata/empty/opt6.ql
@@ -0,0 +1,2 @@
+[opt 1]
+-- select a>123 from ImgChar as a \ No newline at end of file
diff --git a/systemtest/testdata/empty/opt6.ql.java.out b/systemtest/testdata/empty/opt6.ql.java.out
new file mode 100644
index 0000000..26e1b5c
--- /dev/null
+++ b/systemtest/testdata/empty/opt6.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Parsing error: Unexpected end of query. \ No newline at end of file
diff --git a/systemtest/testdata/empty/opt6.ql.out b/systemtest/testdata/empty/opt6.ql.out
new file mode 100644
index 0000000..d1ec6cb
--- /dev/null
+++ b/systemtest/testdata/empty/opt6.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=308
diff --git a/systemtest/testdata/empty/opt7.ql b/systemtest/testdata/empty/opt7.ql
new file mode 100644
index 0000000..7607aea
--- /dev/null
+++ b/systemtest/testdata/empty/opt7.ql
@@ -0,0 +1,2 @@
+[opt 2]
+-- select a>123 from ImgChar as a \ No newline at end of file
diff --git a/systemtest/testdata/empty/opt7.ql.java.out b/systemtest/testdata/empty/opt7.ql.java.out
new file mode 100644
index 0000000..26e1b5c
--- /dev/null
+++ b/systemtest/testdata/empty/opt7.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Parsing error: Unexpected end of query. \ No newline at end of file
diff --git a/systemtest/testdata/empty/opt7.ql.out b/systemtest/testdata/empty/opt7.ql.out
new file mode 100644
index 0000000..d1ec6cb
--- /dev/null
+++ b/systemtest/testdata/empty/opt7.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=308
diff --git a/systemtest/testdata/empty/opt8.ql b/systemtest/testdata/empty/opt8.ql
new file mode 100644
index 0000000..0060b74
--- /dev/null
+++ b/systemtest/testdata/empty/opt8.ql
@@ -0,0 +1,2 @@
+[opt 3]
+-- select a>123 from ImgChar as a \ No newline at end of file
diff --git a/systemtest/testdata/empty/opt8.ql.java.out b/systemtest/testdata/empty/opt8.ql.java.out
new file mode 100644
index 0000000..26e1b5c
--- /dev/null
+++ b/systemtest/testdata/empty/opt8.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Parsing error: Unexpected end of query. \ No newline at end of file
diff --git a/systemtest/testdata/empty/opt8.ql.out b/systemtest/testdata/empty/opt8.ql.out
new file mode 100644
index 0000000..d1ec6cb
--- /dev/null
+++ b/systemtest/testdata/empty/opt8.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=308
diff --git a/systemtest/testdata/empty/opt9.ql b/systemtest/testdata/empty/opt9.ql
new file mode 100644
index 0000000..76ae25a
--- /dev/null
+++ b/systemtest/testdata/empty/opt9.ql
@@ -0,0 +1,2 @@
+[opt 4]
+-- select a>123 from ImgChar as a \ No newline at end of file
diff --git a/systemtest/testdata/empty/opt9.ql.java.out b/systemtest/testdata/empty/opt9.ql.java.out
new file mode 100644
index 0000000..26e1b5c
--- /dev/null
+++ b/systemtest/testdata/empty/opt9.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Parsing error: Unexpected end of query. \ No newline at end of file
diff --git a/systemtest/testdata/empty/opt9.ql.out b/systemtest/testdata/empty/opt9.ql.out
new file mode 100644
index 0000000..d1ec6cb
--- /dev/null
+++ b/systemtest/testdata/empty/opt9.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=308
diff --git a/systemtest/testdata/errorset1/err300.ql b/systemtest/testdata/errorset1/err300.ql
new file mode 100644
index 0000000..025a546
--- /dev/null
+++ b/systemtest/testdata/errorset1/err300.ql
@@ -0,0 +1,4 @@
+-- Testbed: error_no=300
+
+select a * -2ul
+from ImgCharMask
diff --git a/systemtest/testdata/errorset1/err300.ql.java.out b/systemtest/testdata/errorset1/err300.ql.java.out
new file mode 100644
index 0000000..1760d17
--- /dev/null
+++ b/systemtest/testdata/errorset1/err300.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Parsing error 300 in line 5, column 14: Unexpected name ul. \ No newline at end of file
diff --git a/systemtest/testdata/errorset1/err300.ql.out b/systemtest/testdata/errorset1/err300.ql.out
new file mode 100644
index 0000000..addb1c0
--- /dev/null
+++ b/systemtest/testdata/errorset1/err300.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=300
diff --git a/systemtest/testdata/errorset1/err301.ql b/systemtest/testdata/errorset1/err301.ql
new file mode 100644
index 0000000..2a11319
--- /dev/null
+++ b/systemtest/testdata/errorset1/err301.ql
@@ -0,0 +1,3 @@
+select < [-2:2,-1:1] 1l, 2c, 3c; 1c, 2c, 3c; 1c, 2c, 3c; 1c, 2c, 3c; 1c, 2c, 3c >
+from ImgCharMask as a
+
diff --git a/systemtest/testdata/errorset1/err301.ql.java.out b/systemtest/testdata/errorset1/err301.ql.java.out
new file mode 100644
index 0000000..e4ab0a1
--- /dev/null
+++ b/systemtest/testdata/errorset1/err301.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Parsing error 301 in line 3, column 8, token <: All cell values of an MDD must be of the same type. \ No newline at end of file
diff --git a/systemtest/testdata/errorset1/err301.ql.out b/systemtest/testdata/errorset1/err301.ql.out
new file mode 100644
index 0000000..78b7215
--- /dev/null
+++ b/systemtest/testdata/errorset1/err301.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=301
diff --git a/systemtest/testdata/errorset1/err302.ql b/systemtest/testdata/errorset1/err302.ql
new file mode 100644
index 0000000..9b7c3d5
--- /dev/null
+++ b/systemtest/testdata/errorset1/err302.ql
@@ -0,0 +1,3 @@
+select < [-2:2,-1:1] 2c, 3c; 1c, 2c, 3c; 1c, 2c, 3c; 1c, 2c, 3c; 1c, 2c, 3c >
+from ImgCharMask as a
+
diff --git a/systemtest/testdata/errorset1/err302.ql.java.out b/systemtest/testdata/errorset1/err302.ql.java.out
new file mode 100644
index 0000000..0784bd9
--- /dev/null
+++ b/systemtest/testdata/errorset1/err302.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Parsing error 302 in line 3, column 8, token <: Number of cells specified does not match the number of cells of the given spatial domain. \ No newline at end of file
diff --git a/systemtest/testdata/errorset1/err302.ql.out b/systemtest/testdata/errorset1/err302.ql.out
new file mode 100644
index 0000000..963950e
--- /dev/null
+++ b/systemtest/testdata/errorset1/err302.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=302
diff --git a/systemtest/testdata/errorset1/err349.ql.out b/systemtest/testdata/errorset1/err349.ql.out
new file mode 100644
index 0000000..b35f983
--- /dev/null
+++ b/systemtest/testdata/errorset1/err349.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: nan
+Element 2: nan
+-- Testbed end block:
diff --git a/systemtest/testdata/errorset1/err355.ql b/systemtest/testdata/errorset1/err355.ql
new file mode 100644
index 0000000..b19504a
--- /dev/null
+++ b/systemtest/testdata/errorset1/err355.ql
@@ -0,0 +1,4 @@
+-- Testbed: error_no=355
+
+select a
+from xxx as a
diff --git a/systemtest/testdata/errorset1/err355.ql.java.out b/systemtest/testdata/errorset1/err355.ql.java.out
new file mode 100644
index 0000000..9e6e07b
--- /dev/null
+++ b/systemtest/testdata/errorset1/err355.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Execution error 355 in line 6, column 8, near token xxx: Collection name is unknown. \ No newline at end of file
diff --git a/systemtest/testdata/errorset1/err355.ql.out b/systemtest/testdata/errorset1/err355.ql.out
new file mode 100644
index 0000000..4ff4c0a
--- /dev/null
+++ b/systemtest/testdata/errorset1/err355.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=355
diff --git a/systemtest/testdata/errorset1/err356.ql b/systemtest/testdata/errorset1/err356.ql
new file mode 100644
index 0000000..1390590
--- /dev/null
+++ b/systemtest/testdata/errorset1/err356.ql
@@ -0,0 +1,4 @@
+-- Testbed: error_no=356
+
+select marray x in [ 0:sdom(a)[0].hi+1, 0:sdom(a)[1].hi ] values a[x]
+from ImgCharA as a
diff --git a/systemtest/testdata/errorset1/err356.ql.java.out b/systemtest/testdata/errorset1/err356.ql.java.out
new file mode 100644
index 0000000..4ef0833
--- /dev/null
+++ b/systemtest/testdata/errorset1/err356.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Execution error 356 in line 0, column 0, near token : Specified domain does not intersect with spatial domain of MDD. \ No newline at end of file
diff --git a/systemtest/testdata/errorset1/err356.ql.out b/systemtest/testdata/errorset1/err356.ql.out
new file mode 100644
index 0000000..9e3e653
--- /dev/null
+++ b/systemtest/testdata/errorset1/err356.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=356
diff --git a/systemtest/testdata/errorset1/err357.ql b/systemtest/testdata/errorset1/err357.ql
new file mode 100644
index 0000000..8ee1d75
--- /dev/null
+++ b/systemtest/testdata/errorset1/err357.ql
@@ -0,0 +1,4 @@
+-- Testbed: error_no=357
+
+select b
+from ImgCharA as a
diff --git a/systemtest/testdata/errorset1/err357.ql.java.out b/systemtest/testdata/errorset1/err357.ql.java.out
new file mode 100644
index 0000000..6549bfe
--- /dev/null
+++ b/systemtest/testdata/errorset1/err357.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Execution error 357 in line 5, column 8, near token b: Variable is unknown. \ No newline at end of file
diff --git a/systemtest/testdata/errorset1/err357.ql.out b/systemtest/testdata/errorset1/err357.ql.out
new file mode 100644
index 0000000..c377248
--- /dev/null
+++ b/systemtest/testdata/errorset1/err357.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=357
diff --git a/systemtest/testdata/errorset1/err359.ql b/systemtest/testdata/errorset1/err359.ql
new file mode 100644
index 0000000..4105ffc
--- /dev/null
+++ b/systemtest/testdata/errorset1/err359.ql
@@ -0,0 +1,5 @@
+-- Testbed: error_no=359
+
+select a
+from ImgCharA as a
+where 1
diff --git a/systemtest/testdata/errorset1/err359.ql.java.out b/systemtest/testdata/errorset1/err359.ql.java.out
new file mode 100644
index 0000000..657ab1b
--- /dev/null
+++ b/systemtest/testdata/errorset1/err359.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Execution error 359 in line 7, column 1, near token where: Result of the where clause must be of type boolean. \ No newline at end of file
diff --git a/systemtest/testdata/errorset1/err359.ql.out b/systemtest/testdata/errorset1/err359.ql.out
new file mode 100644
index 0000000..24d1b9f
--- /dev/null
+++ b/systemtest/testdata/errorset1/err359.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=359
diff --git a/systemtest/testdata/errorset1/err364.ql b/systemtest/testdata/errorset1/err364.ql
new file mode 100644
index 0000000..15566c7
--- /dev/null
+++ b/systemtest/testdata/errorset1/err364.ql
@@ -0,0 +1,4 @@
+-- Testbed: error_no=364
+
+select a * { 1l, 0l, 0l }
+from ImgRGBA as a
diff --git a/systemtest/testdata/errorset1/err364.ql.java.out b/systemtest/testdata/errorset1/err364.ql.java.out
new file mode 100644
index 0000000..4e9345b
--- /dev/null
+++ b/systemtest/testdata/errorset1/err364.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Execution error 364 in line 5, column 10, near token *: Cell base type and scalar type of binary induce operation are incompatible. \ No newline at end of file
diff --git a/systemtest/testdata/errorset1/err364.ql.out b/systemtest/testdata/errorset1/err364.ql.out
new file mode 100644
index 0000000..c517ceb
--- /dev/null
+++ b/systemtest/testdata/errorset1/err364.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=364
diff --git a/systemtest/testdata/errorset1/err385.ql b/systemtest/testdata/errorset1/err385.ql
new file mode 100644
index 0000000..237e09a
--- /dev/null
+++ b/systemtest/testdata/errorset1/err385.ql
@@ -0,0 +1,5 @@
+-- Testbed: error_no=385
+
+select a
+from ImgRGBA as a
+where "abc" * "ab"
diff --git a/systemtest/testdata/errorset1/err385.ql.java.out b/systemtest/testdata/errorset1/err385.ql.java.out
new file mode 100644
index 0000000..98c3afc
--- /dev/null
+++ b/systemtest/testdata/errorset1/err385.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Execution error 385 in line 7, column 14, near token *: Operation is not supported on strings. \ No newline at end of file
diff --git a/systemtest/testdata/errorset1/err385.ql.out b/systemtest/testdata/errorset1/err385.ql.out
new file mode 100644
index 0000000..0bf7214
--- /dev/null
+++ b/systemtest/testdata/errorset1/err385.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=385
diff --git a/systemtest/testdata/errorset1/err386.ql b/systemtest/testdata/errorset1/err386.ql
new file mode 100644
index 0000000..3f9584c
--- /dev/null
+++ b/systemtest/testdata/errorset1/err386.ql
@@ -0,0 +1,5 @@
+-- Testbed: error_no=386
+
+select a
+from ImgCharA as a
+where oid(a) = <"test50|this should no be a valid base|1">
diff --git a/systemtest/testdata/errorset1/err386.ql.java.out b/systemtest/testdata/errorset1/err386.ql.java.out
new file mode 100644
index 0000000..b23b69c
--- /dev/null
+++ b/systemtest/testdata/errorset1/err386.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Execution error 386 in line 7, column 18, near token "test50|this should no be a valid base|1: Base name of oid is not matching the currently opened one. \ No newline at end of file
diff --git a/systemtest/testdata/errorset1/err386.ql.out b/systemtest/testdata/errorset1/err386.ql.out
new file mode 100644
index 0000000..ad4ef93
--- /dev/null
+++ b/systemtest/testdata/errorset1/err386.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=386
diff --git a/systemtest/testdata/errorset1/err390.ql b/systemtest/testdata/errorset1/err390.ql
new file mode 100644
index 0000000..59ac73c
--- /dev/null
+++ b/systemtest/testdata/errorset1/err390.ql
@@ -0,0 +1,4 @@
+-- Testbed: error_no=390
+
+select a[2:0, 1.0]
+from ImgCharA as a
diff --git a/systemtest/testdata/errorset1/err390.ql.java.out b/systemtest/testdata/errorset1/err390.ql.java.out
new file mode 100644
index 0000000..c3fa8d9
--- /dev/null
+++ b/systemtest/testdata/errorset1/err390.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Execution error 390 in line 5, column 9, near token [: Minterval dimension specifications must be either of type interval or integer. \ No newline at end of file
diff --git a/systemtest/testdata/errorset1/err390.ql.out b/systemtest/testdata/errorset1/err390.ql.out
new file mode 100644
index 0000000..5794547
--- /dev/null
+++ b/systemtest/testdata/errorset1/err390.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=390
diff --git a/systemtest/testdata/errorset1/err393.ql b/systemtest/testdata/errorset1/err393.ql
new file mode 100644
index 0000000..daefa72
--- /dev/null
+++ b/systemtest/testdata/errorset1/err393.ql
@@ -0,0 +1,4 @@
+-- Testbed: error_no=393
+
+select a * [2:4].lo
+from ImgCharA as a
diff --git a/systemtest/testdata/errorset1/err393.ql.java.out b/systemtest/testdata/errorset1/err393.ql.java.out
new file mode 100644
index 0000000..208940f
--- /dev/null
+++ b/systemtest/testdata/errorset1/err393.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Execution error 393 in line 5, column 18, near token lo: Operand of operation lo/hi must be of type interval. \ No newline at end of file
diff --git a/systemtest/testdata/errorset1/err393.ql.out b/systemtest/testdata/errorset1/err393.ql.out
new file mode 100644
index 0000000..e201d02
--- /dev/null
+++ b/systemtest/testdata/errorset1/err393.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=393
diff --git a/systemtest/testdata/errorset1/err394.ql b/systemtest/testdata/errorset1/err394.ql
new file mode 100644
index 0000000..27098a1
--- /dev/null
+++ b/systemtest/testdata/errorset1/err394.ql
@@ -0,0 +1,4 @@
+-- Testbed: error_no=394
+
+select a * (*:*).lo
+from ImgCharA as a
diff --git a/systemtest/testdata/errorset1/err394.ql.java.out b/systemtest/testdata/errorset1/err394.ql.java.out
new file mode 100644
index 0000000..0e451ef
--- /dev/null
+++ b/systemtest/testdata/errorset1/err394.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Execution error 394 in line 5, column 18, near token lo: Operation lo/hi can not be used for an open bound. \ No newline at end of file
diff --git a/systemtest/testdata/errorset1/err394.ql.out b/systemtest/testdata/errorset1/err394.ql.out
new file mode 100644
index 0000000..1071377
--- /dev/null
+++ b/systemtest/testdata/errorset1/err394.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=394
diff --git a/systemtest/testdata/errorset1/err396.ql b/systemtest/testdata/errorset1/err396.ql
new file mode 100644
index 0000000..4cb77b9
--- /dev/null
+++ b/systemtest/testdata/errorset1/err396.ql
@@ -0,0 +1,4 @@
+-- Testbed: error_no=396
+
+select 2[4]
+from ImgCharA as a
diff --git a/systemtest/testdata/errorset1/err396.ql.java.out b/systemtest/testdata/errorset1/err396.ql.java.out
new file mode 100644
index 0000000..1a7be77
--- /dev/null
+++ b/systemtest/testdata/errorset1/err396.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Execution error 396 in line 0, column 0, near token : Selection operation is not supported on this data type. \ No newline at end of file
diff --git a/systemtest/testdata/errorset1/err396.ql.out b/systemtest/testdata/errorset1/err396.ql.out
new file mode 100644
index 0000000..82270cb
--- /dev/null
+++ b/systemtest/testdata/errorset1/err396.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=396
diff --git a/systemtest/testdata/errorset1/err397.ql b/systemtest/testdata/errorset1/err397.ql
new file mode 100644
index 0000000..0a9c1b4
--- /dev/null
+++ b/systemtest/testdata/errorset1/err397.ql
@@ -0,0 +1,4 @@
+-- Testbed: error_no=397
+
+select a * [0:5][1.0].lo
+from ImgCharA as a
diff --git a/systemtest/testdata/errorset1/err397.ql.java.out b/systemtest/testdata/errorset1/err397.ql.java.out
new file mode 100644
index 0000000..fd429ce
--- /dev/null
+++ b/systemtest/testdata/errorset1/err397.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Execution error 397 in line 0, column 0, near token : Operand of minterval selection must be of type integer. \ No newline at end of file
diff --git a/systemtest/testdata/errorset1/err397.ql.out b/systemtest/testdata/errorset1/err397.ql.out
new file mode 100644
index 0000000..4146cc5
--- /dev/null
+++ b/systemtest/testdata/errorset1/err397.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=397
diff --git a/systemtest/testdata/errorset1/err398.ql b/systemtest/testdata/errorset1/err398.ql
new file mode 100644
index 0000000..9b5b510
--- /dev/null
+++ b/systemtest/testdata/errorset1/err398.ql
@@ -0,0 +1,4 @@
+-- Testbed: error_no=398
+
+select a * [0:5][1].lo
+from ImgCharA as a
diff --git a/systemtest/testdata/errorset1/err398.ql.java.out b/systemtest/testdata/errorset1/err398.ql.java.out
new file mode 100644
index 0000000..e8a168a
--- /dev/null
+++ b/systemtest/testdata/errorset1/err398.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Execution error 398 in line 0, column 0, near token : Index for minterval selection is out of range. \ No newline at end of file
diff --git a/systemtest/testdata/errorset1/err398.ql.out b/systemtest/testdata/errorset1/err398.ql.out
new file mode 100644
index 0000000..36ee5b0
--- /dev/null
+++ b/systemtest/testdata/errorset1/err398.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=398
diff --git a/systemtest/testdata/errorset1/err403.ql b/systemtest/testdata/errorset1/err403.ql
new file mode 100644
index 0000000..1352c71
--- /dev/null
+++ b/systemtest/testdata/errorset1/err403.ql
@@ -0,0 +1,5 @@
+-- Testbed: error_no=403
+
+select a
+from ImgRGBA as a
+where "abc" * 2
diff --git a/systemtest/testdata/errorset1/err403.ql.java.out b/systemtest/testdata/errorset1/err403.ql.java.out
new file mode 100644
index 0000000..4561b05
--- /dev/null
+++ b/systemtest/testdata/errorset1/err403.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Execution error 403 in line 7, column 14, near token *: Binary operation is not supported on these data types. \ No newline at end of file
diff --git a/systemtest/testdata/errorset1/err403.ql.out b/systemtest/testdata/errorset1/err403.ql.out
new file mode 100644
index 0000000..8211603
--- /dev/null
+++ b/systemtest/testdata/errorset1/err403.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=403
diff --git a/systemtest/testdata/errorset1/err405.ql b/systemtest/testdata/errorset1/err405.ql
new file mode 100644
index 0000000..feef611
--- /dev/null
+++ b/systemtest/testdata/errorset1/err405.ql
@@ -0,0 +1,4 @@
+-- Testbed: error_no=405
+
+select shift( 1, [0,0] )
+from ImgCharA as a
diff --git a/systemtest/testdata/errorset1/err405.ql.java.out b/systemtest/testdata/errorset1/err405.ql.java.out
new file mode 100644
index 0000000..36d8206
--- /dev/null
+++ b/systemtest/testdata/errorset1/err405.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Execution error 405 in line 5, column 8, near token shift: First operand of shift function must be of type MDD. \ No newline at end of file
diff --git a/systemtest/testdata/errorset1/err405.ql.out b/systemtest/testdata/errorset1/err405.ql.out
new file mode 100644
index 0000000..c9b4e9b
--- /dev/null
+++ b/systemtest/testdata/errorset1/err405.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=405
diff --git a/systemtest/testdata/errorset1/err406.ql b/systemtest/testdata/errorset1/err406.ql
new file mode 100644
index 0000000..46b5571
--- /dev/null
+++ b/systemtest/testdata/errorset1/err406.ql
@@ -0,0 +1,4 @@
+-- Testbed: error_no=406
+
+select shift( a, 1 )
+from ImgCharA as a
diff --git a/systemtest/testdata/errorset1/err406.ql.java.out b/systemtest/testdata/errorset1/err406.ql.java.out
new file mode 100644
index 0000000..2e51163
--- /dev/null
+++ b/systemtest/testdata/errorset1/err406.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Execution error 406 in line 5, column 8, near token shift: Second operand of shift function must be of type Point. \ No newline at end of file
diff --git a/systemtest/testdata/errorset1/err406.ql.out b/systemtest/testdata/errorset1/err406.ql.out
new file mode 100644
index 0000000..8ff8936
--- /dev/null
+++ b/systemtest/testdata/errorset1/err406.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=406
diff --git a/systemtest/testdata/errorset1/err407.ql b/systemtest/testdata/errorset1/err407.ql
new file mode 100644
index 0000000..4c6d408
--- /dev/null
+++ b/systemtest/testdata/errorset1/err407.ql
@@ -0,0 +1,4 @@
+-- Testbed: error_no=407
+
+select shift( a, [0,1,2] )
+from ImgCharA as a
diff --git a/systemtest/testdata/errorset1/err407.ql.java.out b/systemtest/testdata/errorset1/err407.ql.java.out
new file mode 100644
index 0000000..7a19e95
--- /dev/null
+++ b/systemtest/testdata/errorset1/err407.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Execution error 407 in line 5, column 8, near token shift: Dimensionality of MDD and point expression are not matching. \ No newline at end of file
diff --git a/systemtest/testdata/errorset1/err407.ql.out b/systemtest/testdata/errorset1/err407.ql.out
new file mode 100644
index 0000000..303168e
--- /dev/null
+++ b/systemtest/testdata/errorset1/err407.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=407
diff --git a/systemtest/testdata/errorset1/err408.ql b/systemtest/testdata/errorset1/err408.ql
new file mode 100644
index 0000000..887af1e
--- /dev/null
+++ b/systemtest/testdata/errorset1/err408.ql
@@ -0,0 +1,4 @@
+-- Testbed: error_no=408
+
+select shift( a, [0,sdom(a)[0].hi] )
+from ImgCharA as a
diff --git a/systemtest/testdata/errorset1/err408.ql.java.out b/systemtest/testdata/errorset1/err408.ql.java.out
new file mode 100644
index 0000000..5d1ab70
--- /dev/null
+++ b/systemtest/testdata/errorset1/err408.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Execution error 408 in line 5, column 8, near token shift: Second operand of shift function must be a constant expression. \ No newline at end of file
diff --git a/systemtest/testdata/errorset1/err408.ql.out b/systemtest/testdata/errorset1/err408.ql.out
new file mode 100644
index 0000000..b43027d
--- /dev/null
+++ b/systemtest/testdata/errorset1/err408.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=408
diff --git a/systemtest/testdata/errorset1/err409.ql b/systemtest/testdata/errorset1/err409.ql
new file mode 100644
index 0000000..09f56f4
--- /dev/null
+++ b/systemtest/testdata/errorset1/err409.ql
@@ -0,0 +1,4 @@
+-- Testbed: error_no=409
+
+select shift( a, [5,5] )[5:10,*:*]
+from ImgCharD as a
diff --git a/systemtest/testdata/errorset1/err409.ql.java.out b/systemtest/testdata/errorset1/err409.ql.java.out
new file mode 100644
index 0000000..4bbedb1
--- /dev/null
+++ b/systemtest/testdata/errorset1/err409.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Execution error 409 in line 5, column 8, near token shift: Spatial domain shift of open bounds is not supported. \ No newline at end of file
diff --git a/systemtest/testdata/errorset1/err409.ql.out b/systemtest/testdata/errorset1/err409.ql.out
new file mode 100644
index 0000000..0c16eab
--- /dev/null
+++ b/systemtest/testdata/errorset1/err409.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=409
diff --git a/systemtest/testdata/errorset1/err413.ql b/systemtest/testdata/errorset1/err413.ql
new file mode 100644
index 0000000..3e6eb2b
--- /dev/null
+++ b/systemtest/testdata/errorset1/err413.ql
@@ -0,0 +1,6 @@
+-- Testbed: error_no=413
+
+select marray n in [0:1] values
+ condense + over x in sdom(a) where 1c using 1c
+from ImgCharA as a
+
diff --git a/systemtest/testdata/errorset1/err413.ql.java.out b/systemtest/testdata/errorset1/err413.ql.java.out
new file mode 100644
index 0000000..b0769d6
--- /dev/null
+++ b/systemtest/testdata/errorset1/err413.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Execution error 413 in line 6, column 10, near token condense: Condition expression must be of type boolean. \ No newline at end of file
diff --git a/systemtest/testdata/errorset1/err413.ql.out b/systemtest/testdata/errorset1/err413.ql.out
new file mode 100644
index 0000000..a572180
--- /dev/null
+++ b/systemtest/testdata/errorset1/err413.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=413
diff --git a/systemtest/testdata/errorset1/err415.ql b/systemtest/testdata/errorset1/err415.ql
new file mode 100644
index 0000000..ec24ad4
--- /dev/null
+++ b/systemtest/testdata/errorset1/err415.ql
@@ -0,0 +1,3 @@
+select marray x in [0:0] values count_cells( a )
+from ImgCharA as a
+
diff --git a/systemtest/testdata/errorset1/err415.ql.java.out b/systemtest/testdata/errorset1/err415.ql.java.out
new file mode 100644
index 0000000..da2d08b
--- /dev/null
+++ b/systemtest/testdata/errorset1/err415.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Execution error 415 in line 3, column 33, near token count_cells: Operand of count_cells must be of type r_Marray<d_Boolean>. \ No newline at end of file
diff --git a/systemtest/testdata/errorset1/err415.ql.out b/systemtest/testdata/errorset1/err415.ql.out
new file mode 100644
index 0000000..ec49f32
--- /dev/null
+++ b/systemtest/testdata/errorset1/err415.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=415
diff --git a/systemtest/testdata/errorset1/err950_300.ql b/systemtest/testdata/errorset1/err950_300.ql
new file mode 100644
index 0000000..97a244f
--- /dev/null
+++ b/systemtest/testdata/errorset1/err950_300.ql
@@ -0,0 +1,5 @@
+-- Testbed: error_no=300
+
+UPDATE ImgCharD AS image
+SET 1c ASSIGN $1
+
diff --git a/systemtest/testdata/errorset1/err950_300.ql.java.out b/systemtest/testdata/errorset1/err950_300.ql.java.out
new file mode 100644
index 0000000..c19a4a3
--- /dev/null
+++ b/systemtest/testdata/errorset1/err950_300.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Parsing error 300 in line 6, column 8: Unexpected name 1c. \ No newline at end of file
diff --git a/systemtest/testdata/errorset1/err950_300.ql.out b/systemtest/testdata/errorset1/err950_300.ql.out
new file mode 100644
index 0000000..addb1c0
--- /dev/null
+++ b/systemtest/testdata/errorset1/err950_300.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=300
diff --git a/systemtest/testdata/errorset1/err951.ql b/systemtest/testdata/errorset1/err951.ql
new file mode 100644
index 0000000..6bcac87
--- /dev/null
+++ b/systemtest/testdata/errorset1/err951.ql
@@ -0,0 +1,5 @@
+-- Testbed: error_no=951
+
+UPDATE ImgCharD AS image
+SET image ASSIGN 1c
+
diff --git a/systemtest/testdata/errorset1/err951.ql.java.out b/systemtest/testdata/errorset1/err951.ql.java.out
new file mode 100644
index 0000000..9a53de7
--- /dev/null
+++ b/systemtest/testdata/errorset1/err951.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Update error 951 in line 5, column 1, near token UPDATE: Update source must be an expression resulting in an r_Marray<>. \ No newline at end of file
diff --git a/systemtest/testdata/errorset1/err951.ql.out b/systemtest/testdata/errorset1/err951.ql.out
new file mode 100644
index 0000000..cfd56b3
--- /dev/null
+++ b/systemtest/testdata/errorset1/err951.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=951
diff --git a/systemtest/testdata/errorset1/err952.ql b/systemtest/testdata/errorset1/err952.ql
new file mode 100644
index 0000000..e9ebd64
--- /dev/null
+++ b/systemtest/testdata/errorset1/err952.ql
@@ -0,0 +1,5 @@
+-- Testbed: error_no=952
+
+UPDATE ImgCharD AS image
+SET image ASSIGN < [-2:2,-1:1] 1l, 2l, 3l; 1l, 2l, 3l; 1l, 2l, 3l; 1l, 2l, 3l; 1l, 2l, 3l >
+
diff --git a/systemtest/testdata/errorset1/err952.ql.java.out b/systemtest/testdata/errorset1/err952.ql.java.out
new file mode 100644
index 0000000..7687493
--- /dev/null
+++ b/systemtest/testdata/errorset1/err952.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Update error 952 in line 5, column 1, near token UPDATE: Update base type does not match MDD base type. \ No newline at end of file
diff --git a/systemtest/testdata/errorset1/err952.ql.out b/systemtest/testdata/errorset1/err952.ql.out
new file mode 100644
index 0000000..46470cd
--- /dev/null
+++ b/systemtest/testdata/errorset1/err952.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=952
diff --git a/systemtest/testdata/errorset1/err954_300.ql b/systemtest/testdata/errorset1/err954_300.ql
new file mode 100644
index 0000000..1ab9be6
--- /dev/null
+++ b/systemtest/testdata/errorset1/err954_300.ql
@@ -0,0 +1,3 @@
+UPDATE ImgULongC AS image
+SET image/2ul ASSIGN $1
+
diff --git a/systemtest/testdata/errorset1/err954_300.ql.java.out b/systemtest/testdata/errorset1/err954_300.ql.java.out
new file mode 100644
index 0000000..07e8dbe
--- /dev/null
+++ b/systemtest/testdata/errorset1/err954_300.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Parsing error 300 in line 4, column 13: Unexpected name /. \ No newline at end of file
diff --git a/systemtest/testdata/errorset1/err954_300.ql.out b/systemtest/testdata/errorset1/err954_300.ql.out
new file mode 100644
index 0000000..addb1c0
--- /dev/null
+++ b/systemtest/testdata/errorset1/err954_300.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=300
diff --git a/systemtest/testdata/errorset1/err961.ql b/systemtest/testdata/errorset1/err961.ql
new file mode 100644
index 0000000..ec60003
--- /dev/null
+++ b/systemtest/testdata/errorset1/err961.ql
@@ -0,0 +1,3 @@
+UPDATE ImgULongC AS image
+SET image[8,8] ASSIGN $1[0:4,0:4]/2ul
+
diff --git a/systemtest/testdata/errorset1/err961.ql.java.out b/systemtest/testdata/errorset1/err961.ql.java.out
new file mode 100644
index 0000000..5c0d1b0
--- /dev/null
+++ b/systemtest/testdata/errorset1/err961.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Update error 961 in line 3, column 1, near token UPDATE: Update domain must be of type Minterval. \ No newline at end of file
diff --git a/systemtest/testdata/errorset1/err961.ql.out b/systemtest/testdata/errorset1/err961.ql.out
new file mode 100644
index 0000000..daefe00
--- /dev/null
+++ b/systemtest/testdata/errorset1/err961.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=961
diff --git a/systemtest/testdata/errorset1/err962.ql b/systemtest/testdata/errorset1/err962.ql
new file mode 100644
index 0000000..0a5e925
--- /dev/null
+++ b/systemtest/testdata/errorset1/err962.ql
@@ -0,0 +1,3 @@
+UPDATE ImgULongC AS image
+SET image[8,*:*] ASSIGN $1[0:4,0:4]/2ul
+
diff --git a/systemtest/testdata/errorset1/err962.ql.java.out b/systemtest/testdata/errorset1/err962.ql.java.out
new file mode 100644
index 0000000..79efbc5
--- /dev/null
+++ b/systemtest/testdata/errorset1/err962.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Update error 962 in line 3, column 1, near token UPDATE: Number of update intervals must match source dimensionaltiy. \ No newline at end of file
diff --git a/systemtest/testdata/errorset1/err962.ql.out b/systemtest/testdata/errorset1/err962.ql.out
new file mode 100644
index 0000000..3ea67fb
--- /dev/null
+++ b/systemtest/testdata/errorset1/err962.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=962
diff --git a/systemtest/testdata/errorset1/err963.ql b/systemtest/testdata/errorset1/err963.ql
new file mode 100644
index 0000000..e545888
--- /dev/null
+++ b/systemtest/testdata/errorset1/err963.ql
@@ -0,0 +1,3 @@
+UPDATE ImgULongC AS image
+SET image[6,8,*:*] ASSIGN $1[0:4,0:4]/2ul
+
diff --git a/systemtest/testdata/errorset1/err963.ql.java.out b/systemtest/testdata/errorset1/err963.ql.java.out
new file mode 100644
index 0000000..38928fe
--- /dev/null
+++ b/systemtest/testdata/errorset1/err963.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Update error 963 in line 3, column 1, near token UPDATE: Update domain dimensionality must match target MDD dimensionaltiy. \ No newline at end of file
diff --git a/systemtest/testdata/errorset1/err963.ql.out b/systemtest/testdata/errorset1/err963.ql.out
new file mode 100644
index 0000000..2303b8d
--- /dev/null
+++ b/systemtest/testdata/errorset1/err963.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=963
diff --git a/systemtest/testdata/optimization/opt.ql b/systemtest/testdata/optimization/opt.ql
new file mode 100644
index 0000000..e0f6943
--- /dev/null
+++ b/systemtest/testdata/optimization/opt.ql
@@ -0,0 +1,2 @@
+/*+opt 0*/
+select a<132 from ImgCharA as a
diff --git a/systemtest/testdata/optimization/opt.ql.java.out b/systemtest/testdata/optimization/opt.ql.java.out
new file mode 100644
index 0000000..3b345ff
--- /dev/null
+++ b/systemtest/testdata/optimization/opt.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 \ No newline at end of file
diff --git a/systemtest/testdata/optimization/opt.ql.out b/systemtest/testdata/optimization/opt.ql.out
new file mode 100644
index 0000000..8de3580
--- /dev/null
+++ b/systemtest/testdata/optimization/opt.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <bool, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <bool, [0:10,0:10]>
+ Type Schema...........: marray< bool >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: bool
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+Image 2
+GMarray
+ Type Structure........: marray <bool, [0:10,0:10]>
+ Type Schema...........: marray< bool >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: bool
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+-- Testbed end block:
diff --git a/systemtest/testdata/optimization/opt1.ql b/systemtest/testdata/optimization/opt1.ql
new file mode 100644
index 0000000..86c765a
--- /dev/null
+++ b/systemtest/testdata/optimization/opt1.ql
@@ -0,0 +1,2 @@
+/*+opt 1*/
+select a<132 from ImgCharA as a
diff --git a/systemtest/testdata/optimization/opt1.ql.java.out b/systemtest/testdata/optimization/opt1.ql.java.out
new file mode 100644
index 0000000..3b345ff
--- /dev/null
+++ b/systemtest/testdata/optimization/opt1.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 \ No newline at end of file
diff --git a/systemtest/testdata/optimization/opt1.ql.out b/systemtest/testdata/optimization/opt1.ql.out
new file mode 100644
index 0000000..8de3580
--- /dev/null
+++ b/systemtest/testdata/optimization/opt1.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <bool, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <bool, [0:10,0:10]>
+ Type Schema...........: marray< bool >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: bool
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+Image 2
+GMarray
+ Type Structure........: marray <bool, [0:10,0:10]>
+ Type Schema...........: marray< bool >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: bool
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+-- Testbed end block:
diff --git a/systemtest/testdata/optimization/opt2.ql b/systemtest/testdata/optimization/opt2.ql
new file mode 100644
index 0000000..3446c8e
--- /dev/null
+++ b/systemtest/testdata/optimization/opt2.ql
@@ -0,0 +1,2 @@
+/*+opt 2*/
+select a<132 from ImgCharA as a
diff --git a/systemtest/testdata/optimization/opt2.ql.java.out b/systemtest/testdata/optimization/opt2.ql.java.out
new file mode 100644
index 0000000..3b345ff
--- /dev/null
+++ b/systemtest/testdata/optimization/opt2.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 \ No newline at end of file
diff --git a/systemtest/testdata/optimization/opt2.ql.out b/systemtest/testdata/optimization/opt2.ql.out
new file mode 100644
index 0000000..8de3580
--- /dev/null
+++ b/systemtest/testdata/optimization/opt2.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <bool, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <bool, [0:10,0:10]>
+ Type Schema...........: marray< bool >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: bool
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+Image 2
+GMarray
+ Type Structure........: marray <bool, [0:10,0:10]>
+ Type Schema...........: marray< bool >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: bool
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+-- Testbed end block:
diff --git a/systemtest/testdata/optimization/opt3.ql b/systemtest/testdata/optimization/opt3.ql
new file mode 100644
index 0000000..5095827
--- /dev/null
+++ b/systemtest/testdata/optimization/opt3.ql
@@ -0,0 +1,2 @@
+/*+opt 3*/
+select a<132 from ImgCharA as a
diff --git a/systemtest/testdata/optimization/opt3.ql.java.out b/systemtest/testdata/optimization/opt3.ql.java.out
new file mode 100644
index 0000000..3b345ff
--- /dev/null
+++ b/systemtest/testdata/optimization/opt3.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 \ No newline at end of file
diff --git a/systemtest/testdata/optimization/opt3.ql.out b/systemtest/testdata/optimization/opt3.ql.out
new file mode 100644
index 0000000..8de3580
--- /dev/null
+++ b/systemtest/testdata/optimization/opt3.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <bool, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <bool, [0:10,0:10]>
+ Type Schema...........: marray< bool >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: bool
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+Image 2
+GMarray
+ Type Structure........: marray <bool, [0:10,0:10]>
+ Type Schema...........: marray< bool >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: bool
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+-- Testbed end block:
diff --git a/systemtest/testdata/optimization/opt4.ql b/systemtest/testdata/optimization/opt4.ql
new file mode 100644
index 0000000..0599052
--- /dev/null
+++ b/systemtest/testdata/optimization/opt4.ql
@@ -0,0 +1,2 @@
+/*+opt 4*/
+select a<132 from ImgCharA as a
diff --git a/systemtest/testdata/optimization/opt4.ql.java.out b/systemtest/testdata/optimization/opt4.ql.java.out
new file mode 100644
index 0000000..3b345ff
--- /dev/null
+++ b/systemtest/testdata/optimization/opt4.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 \ No newline at end of file
diff --git a/systemtest/testdata/optimization/opt4.ql.out b/systemtest/testdata/optimization/opt4.ql.out
new file mode 100644
index 0000000..8de3580
--- /dev/null
+++ b/systemtest/testdata/optimization/opt4.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <bool, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <bool, [0:10,0:10]>
+ Type Schema...........: marray< bool >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: bool
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+Image 2
+GMarray
+ Type Structure........: marray <bool, [0:10,0:10]>
+ Type Schema...........: marray< bool >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: bool
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+-- Testbed end block:
diff --git a/systemtest/testdata/optimization/opt5.ql b/systemtest/testdata/optimization/opt5.ql
new file mode 100644
index 0000000..9f5b38b
--- /dev/null
+++ b/systemtest/testdata/optimization/opt5.ql
@@ -0,0 +1,2 @@
+[opt 0]
+select a>123 from ImgCharA as a \ No newline at end of file
diff --git a/systemtest/testdata/optimization/opt5.ql.java.out b/systemtest/testdata/optimization/opt5.ql.java.out
new file mode 100644
index 0000000..8315bc2
--- /dev/null
+++ b/systemtest/testdata/optimization/opt5.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \ No newline at end of file
diff --git a/systemtest/testdata/optimization/opt5.ql.out b/systemtest/testdata/optimization/opt5.ql.out
new file mode 100644
index 0000000..83e6fdb
--- /dev/null
+++ b/systemtest/testdata/optimization/opt5.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <bool, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <bool, [0:10,0:10]>
+ Type Schema...........: marray< bool >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: bool
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+Image 2
+GMarray
+ Type Structure........: marray <bool, [0:10,0:10]>
+ Type Schema...........: marray< bool >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: bool
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+-- Testbed end block:
diff --git a/systemtest/testdata/optimization/opt6.ql b/systemtest/testdata/optimization/opt6.ql
new file mode 100644
index 0000000..f1d402b
--- /dev/null
+++ b/systemtest/testdata/optimization/opt6.ql
@@ -0,0 +1,2 @@
+[opt 1]
+select a>123 from ImgCharA as a \ No newline at end of file
diff --git a/systemtest/testdata/optimization/opt6.ql.java.out b/systemtest/testdata/optimization/opt6.ql.java.out
new file mode 100644
index 0000000..8315bc2
--- /dev/null
+++ b/systemtest/testdata/optimization/opt6.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \ No newline at end of file
diff --git a/systemtest/testdata/optimization/opt6.ql.out b/systemtest/testdata/optimization/opt6.ql.out
new file mode 100644
index 0000000..83e6fdb
--- /dev/null
+++ b/systemtest/testdata/optimization/opt6.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <bool, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <bool, [0:10,0:10]>
+ Type Schema...........: marray< bool >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: bool
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+Image 2
+GMarray
+ Type Structure........: marray <bool, [0:10,0:10]>
+ Type Schema...........: marray< bool >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: bool
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+-- Testbed end block:
diff --git a/systemtest/testdata/optimization/opt7.ql b/systemtest/testdata/optimization/opt7.ql
new file mode 100644
index 0000000..e80b4fb
--- /dev/null
+++ b/systemtest/testdata/optimization/opt7.ql
@@ -0,0 +1,2 @@
+[opt 2]
+select a>123 from ImgCharA as a \ No newline at end of file
diff --git a/systemtest/testdata/optimization/opt7.ql.java.out b/systemtest/testdata/optimization/opt7.ql.java.out
new file mode 100644
index 0000000..8315bc2
--- /dev/null
+++ b/systemtest/testdata/optimization/opt7.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \ No newline at end of file
diff --git a/systemtest/testdata/optimization/opt7.ql.out b/systemtest/testdata/optimization/opt7.ql.out
new file mode 100644
index 0000000..83e6fdb
--- /dev/null
+++ b/systemtest/testdata/optimization/opt7.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <bool, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <bool, [0:10,0:10]>
+ Type Schema...........: marray< bool >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: bool
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+Image 2
+GMarray
+ Type Structure........: marray <bool, [0:10,0:10]>
+ Type Schema...........: marray< bool >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: bool
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+-- Testbed end block:
diff --git a/systemtest/testdata/optimization/opt8.ql b/systemtest/testdata/optimization/opt8.ql
new file mode 100644
index 0000000..b1ac0f8
--- /dev/null
+++ b/systemtest/testdata/optimization/opt8.ql
@@ -0,0 +1,2 @@
+[opt 3]
+select a>123 from ImgCharA as a \ No newline at end of file
diff --git a/systemtest/testdata/optimization/opt8.ql.java.out b/systemtest/testdata/optimization/opt8.ql.java.out
new file mode 100644
index 0000000..8315bc2
--- /dev/null
+++ b/systemtest/testdata/optimization/opt8.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \ No newline at end of file
diff --git a/systemtest/testdata/optimization/opt8.ql.out b/systemtest/testdata/optimization/opt8.ql.out
new file mode 100644
index 0000000..83e6fdb
--- /dev/null
+++ b/systemtest/testdata/optimization/opt8.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <bool, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <bool, [0:10,0:10]>
+ Type Schema...........: marray< bool >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: bool
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+Image 2
+GMarray
+ Type Structure........: marray <bool, [0:10,0:10]>
+ Type Schema...........: marray< bool >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: bool
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+-- Testbed end block:
diff --git a/systemtest/testdata/optimization/opt9.ql b/systemtest/testdata/optimization/opt9.ql
new file mode 100644
index 0000000..88e7f74
--- /dev/null
+++ b/systemtest/testdata/optimization/opt9.ql
@@ -0,0 +1,2 @@
+[opt 4]
+select a>123 from ImgCharA as a \ No newline at end of file
diff --git a/systemtest/testdata/optimization/opt9.ql.java.out b/systemtest/testdata/optimization/opt9.ql.java.out
new file mode 100644
index 0000000..8315bc2
--- /dev/null
+++ b/systemtest/testdata/optimization/opt9.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \ No newline at end of file
diff --git a/systemtest/testdata/optimization/opt9.ql.out b/systemtest/testdata/optimization/opt9.ql.out
new file mode 100644
index 0000000..83e6fdb
--- /dev/null
+++ b/systemtest/testdata/optimization/opt9.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <bool, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <bool, [0:10,0:10]>
+ Type Schema...........: marray< bool >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: bool
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+Image 2
+GMarray
+ Type Structure........: marray <bool, [0:10,0:10]>
+ Type Schema...........: marray< bool >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: bool
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+-- Testbed end block:
diff --git a/systemtest/testdata/overlay/overlay1.ql b/systemtest/testdata/overlay/overlay1.ql
new file mode 100644
index 0000000..3fa404b
--- /dev/null
+++ b/systemtest/testdata/overlay/overlay1.ql
@@ -0,0 +1,2 @@
+-- rview-Query
+select b overlay a from OvlRGBA as a, OvlRGBB as b \ No newline at end of file
diff --git a/systemtest/testdata/overlay/overlay1.ql.java.out b/systemtest/testdata/overlay/overlay1.ql.java.out
new file mode 100644
index 0000000..aa9db3c
--- /dev/null
+++ b/systemtest/testdata/overlay/overlay1.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasGMArray
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:9,0:9]
+ TilingDomain..........: [0:205,0:205]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 3
+ Data format...........: 0
+ Data size (bytes).....: 300
+ -68 108 51 -76 114 52 -84 101 61 -108 88 54 -124 70 40 124 66 44 124 75 41 124 77 52 -107 70 27 -100 87 35 -84 99 36 -84 99 36 -100 88 44 -124 65 38 116 56 25 116 50 20 102 54 38 116 56 25 -100 76 27 -108 76 27 -76 107 43 -84 107 44 -92 94 43 -108 76 36 -124 64 25 124 58 26 -124 64 25 -124 64 25 -100 82 34 -108 76 27 -76 119 52 -76 119 52 -76 108 61 -84 100 49 -92 89 44 -100 82 46 -92 82 35 -92 88 35 -100 87 35 -92 82 35 -76 107 43 -76 107 43 -76 114 52 -76 108 52 -76 101 54 -76 100 44 -84 94 42 -76 94 47 -92 89 44 -76 108 52 -84 107 44 -92 107 51 -84 107 44 -76 108 52 -68 108 51 -76 108 52 -76 100 44 -76 94 33 -84 100 49 -67 114 62 -76 108 61 -84 107 52 -76 107 43 -76 108 52 -76 114 52 -76 107 43 -76 100 44 -76 107 43 -76 108 52 -76 108 52 -68 121 69 -76 114 61 -84 107 52 -76 108 52 -76 114 52 -76 107 43 -76 107 43 -76 100 34 -76 108 52 -84 94 42 -92 119 75 -76 -128 67 -76 -128 67 -67 114 62 -68 108 51 -68 108 51 -76 100 44 -68 108 51 -76 100 44 -76 100 44 -76 -122 67 -60 -112 84 -52 -112 82 -68 -128 68 -76 108 52 -84 94 42 -84 89 36 -76 100 44 -84 94 42 -84 89 36 \ No newline at end of file
diff --git a/systemtest/testdata/overlay/overlay1.ql.out b/systemtest/testdata/overlay/overlay1.ql.out
new file mode 100644
index 0000000..edc1b37
--- /dev/null
+++ b/systemtest/testdata/overlay/overlay1.ql.out
@@ -0,0 +1,23 @@
+-- Testbed line: result_type=set <marray <struct { char red, char green, char blue }, [0:9,0:9]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <struct { char red, char green, char blue }, [0:9,0:9]>
+ Type Schema...........: marray< struct{ char red, char green, char blue } >
+ Domain................: [0:9,0:9]
+ Base Type Schema......: struct{ char red, char green, char blue }
+ Base Type Length......: 3
+ Data format.......... : Array
+ Data size (bytes).... : 300
+{ 188, 108, 51} { 172, 99, 36} { 180, 107, 43} { 180, 119, 52} { 180, 107, 43} { 172, 107, 44} { 180, 108, 61} { 188, 121, 69} { 164, 119, 75} { 180, 134, 67}
+{ 180, 114, 52} { 172, 99, 36} { 172, 107, 44} { 180, 119, 52} { 180, 107, 43} { 164, 107, 51} { 172, 107, 52} { 180, 114, 61} { 180, 128, 67} { 196, 144, 84}
+{ 172, 101, 61} { 156, 88, 44} { 164, 94, 43} { 180, 108, 61} { 180, 114, 52} { 172, 107, 44} { 180, 107, 43} { 172, 107, 52} { 180, 128, 67} { 204, 144, 82}
+{ 148, 88, 54} { 132, 65, 38} { 148, 76, 36} { 172, 100, 49} { 180, 108, 52} { 180, 108, 52} { 180, 108, 52} { 180, 108, 52} { 189, 114, 62} { 188, 128, 68}
+{ 132, 70, 40} { 116, 56, 25} { 132, 64, 25} { 164, 89, 44} { 180, 101, 54} { 188, 108, 51} { 180, 114, 52} { 180, 114, 52} { 188, 108, 51} { 180, 108, 52}
+{ 124, 66, 44} { 116, 50, 20} { 124, 58, 26} { 156, 82, 46} { 180, 100, 44} { 180, 108, 52} { 180, 107, 43} { 180, 107, 43} { 188, 108, 51} { 172, 94, 42}
+{ 124, 75, 41} { 102, 54, 38} { 132, 64, 25} { 164, 82, 35} { 172, 94, 42} { 180, 100, 44} { 180, 100, 44} { 180, 107, 43} { 180, 100, 44} { 172, 89, 36}
+{ 124, 77, 52} { 116, 56, 25} { 132, 64, 25} { 164, 88, 35} { 180, 94, 47} { 180, 94, 33} { 180, 107, 43} { 180, 100, 34} { 188, 108, 51} { 180, 100, 44}
+{ 149, 70, 27} { 156, 76, 27} { 156, 82, 34} { 156, 87, 35} { 164, 89, 44} { 172, 100, 49} { 180, 108, 52} { 180, 108, 52} { 180, 100, 44} { 172, 94, 42}
+{ 156, 87, 35} { 148, 76, 27} { 148, 76, 27} { 164, 82, 35} { 180, 108, 52} { 189, 114, 62} { 180, 108, 52} { 172, 94, 42} { 180, 100, 44} { 172, 89, 36}
+-- Testbed end block:
diff --git a/systemtest/testdata/overlay/overlay2.ql b/systemtest/testdata/overlay/overlay2.ql
new file mode 100644
index 0000000..f120500
--- /dev/null
+++ b/systemtest/testdata/overlay/overlay2.ql
@@ -0,0 +1,2 @@
+-- rview-Query
+select a[2:7,2:7] overlay b[2:7,2:7] from OvlRGBA as a, OvlRGBB as b \ No newline at end of file
diff --git a/systemtest/testdata/overlay/overlay2.ql.java.out b/systemtest/testdata/overlay/overlay2.ql.java.out
new file mode 100644
index 0000000..688293f
--- /dev/null
+++ b/systemtest/testdata/overlay/overlay2.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Parsing error 300 in line 4, column 8: Unexpected name . \ No newline at end of file
diff --git a/systemtest/testdata/overlay/overlay2.ql.out b/systemtest/testdata/overlay/overlay2.ql.out
new file mode 100644
index 0000000..addb1c0
--- /dev/null
+++ b/systemtest/testdata/overlay/overlay2.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=300
diff --git a/systemtest/testdata/overlay/overlay3.ql b/systemtest/testdata/overlay/overlay3.ql
new file mode 100644
index 0000000..72b0172
--- /dev/null
+++ b/systemtest/testdata/overlay/overlay3.ql
@@ -0,0 +1,2 @@
+-- rview-Query
+select a[0:7,2:7] overlay b[2:7,2:7] from OvlRGBA as a, OvlRGBB as b \ No newline at end of file
diff --git a/systemtest/testdata/overlay/overlay3.ql.java.out b/systemtest/testdata/overlay/overlay3.ql.java.out
new file mode 100644
index 0000000..688293f
--- /dev/null
+++ b/systemtest/testdata/overlay/overlay3.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Parsing error 300 in line 4, column 8: Unexpected name . \ No newline at end of file
diff --git a/systemtest/testdata/overlay/overlay3.ql.out b/systemtest/testdata/overlay/overlay3.ql.out
new file mode 100644
index 0000000..addb1c0
--- /dev/null
+++ b/systemtest/testdata/overlay/overlay3.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=300
diff --git a/systemtest/testdata/overlay/overlay4.ql b/systemtest/testdata/overlay/overlay4.ql
new file mode 100644
index 0000000..6359523
--- /dev/null
+++ b/systemtest/testdata/overlay/overlay4.ql
@@ -0,0 +1,2 @@
+-- rview-Query
+select b overlay a from OvlCharA as a, OvlRGBA as b \ No newline at end of file
diff --git a/systemtest/testdata/overlay/overlay4.ql.java.out b/systemtest/testdata/overlay/overlay4.ql.java.out
new file mode 100644
index 0000000..3be9e97
--- /dev/null
+++ b/systemtest/testdata/overlay/overlay4.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Execution error 363 in line 4, column 10, near token overlay: Cell base types of binary induce operation are incompatible. \ No newline at end of file
diff --git a/systemtest/testdata/overlay/overlay4.ql.out b/systemtest/testdata/overlay/overlay4.ql.out
new file mode 100644
index 0000000..a3281cd
--- /dev/null
+++ b/systemtest/testdata/overlay/overlay4.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=363
diff --git a/systemtest/testdata/overlay/overlay5.ql b/systemtest/testdata/overlay/overlay5.ql
new file mode 100644
index 0000000..a3c1e0a
--- /dev/null
+++ b/systemtest/testdata/overlay/overlay5.ql
@@ -0,0 +1,2 @@
+-- rview-Query
+select c overlay b overlay a from OvlRGBA as a, OvlRGBB as b, OvlRGBC as c \ No newline at end of file
diff --git a/systemtest/testdata/overlay/overlay5.ql.java.out b/systemtest/testdata/overlay/overlay5.ql.java.out
new file mode 100644
index 0000000..aa9db3c
--- /dev/null
+++ b/systemtest/testdata/overlay/overlay5.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasGMArray
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:9,0:9]
+ TilingDomain..........: [0:205,0:205]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 3
+ Data format...........: 0
+ Data size (bytes).....: 300
+ -68 108 51 -76 114 52 -84 101 61 -108 88 54 -124 70 40 124 66 44 124 75 41 124 77 52 -107 70 27 -100 87 35 -84 99 36 -84 99 36 -100 88 44 -124 65 38 116 56 25 116 50 20 102 54 38 116 56 25 -100 76 27 -108 76 27 -76 107 43 -84 107 44 -92 94 43 -108 76 36 -124 64 25 124 58 26 -124 64 25 -124 64 25 -100 82 34 -108 76 27 -76 119 52 -76 119 52 -76 108 61 -84 100 49 -92 89 44 -100 82 46 -92 82 35 -92 88 35 -100 87 35 -92 82 35 -76 107 43 -76 107 43 -76 114 52 -76 108 52 -76 101 54 -76 100 44 -84 94 42 -76 94 47 -92 89 44 -76 108 52 -84 107 44 -92 107 51 -84 107 44 -76 108 52 -68 108 51 -76 108 52 -76 100 44 -76 94 33 -84 100 49 -67 114 62 -76 108 61 -84 107 52 -76 107 43 -76 108 52 -76 114 52 -76 107 43 -76 100 44 -76 107 43 -76 108 52 -76 108 52 -68 121 69 -76 114 61 -84 107 52 -76 108 52 -76 114 52 -76 107 43 -76 107 43 -76 100 34 -76 108 52 -84 94 42 -92 119 75 -76 -128 67 -76 -128 67 -67 114 62 -68 108 51 -68 108 51 -76 100 44 -68 108 51 -76 100 44 -76 100 44 -76 -122 67 -60 -112 84 -52 -112 82 -68 -128 68 -76 108 52 -84 94 42 -84 89 36 -76 100 44 -84 94 42 -84 89 36 \ No newline at end of file
diff --git a/systemtest/testdata/overlay/overlay5.ql.out b/systemtest/testdata/overlay/overlay5.ql.out
new file mode 100644
index 0000000..edc1b37
--- /dev/null
+++ b/systemtest/testdata/overlay/overlay5.ql.out
@@ -0,0 +1,23 @@
+-- Testbed line: result_type=set <marray <struct { char red, char green, char blue }, [0:9,0:9]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <struct { char red, char green, char blue }, [0:9,0:9]>
+ Type Schema...........: marray< struct{ char red, char green, char blue } >
+ Domain................: [0:9,0:9]
+ Base Type Schema......: struct{ char red, char green, char blue }
+ Base Type Length......: 3
+ Data format.......... : Array
+ Data size (bytes).... : 300
+{ 188, 108, 51} { 172, 99, 36} { 180, 107, 43} { 180, 119, 52} { 180, 107, 43} { 172, 107, 44} { 180, 108, 61} { 188, 121, 69} { 164, 119, 75} { 180, 134, 67}
+{ 180, 114, 52} { 172, 99, 36} { 172, 107, 44} { 180, 119, 52} { 180, 107, 43} { 164, 107, 51} { 172, 107, 52} { 180, 114, 61} { 180, 128, 67} { 196, 144, 84}
+{ 172, 101, 61} { 156, 88, 44} { 164, 94, 43} { 180, 108, 61} { 180, 114, 52} { 172, 107, 44} { 180, 107, 43} { 172, 107, 52} { 180, 128, 67} { 204, 144, 82}
+{ 148, 88, 54} { 132, 65, 38} { 148, 76, 36} { 172, 100, 49} { 180, 108, 52} { 180, 108, 52} { 180, 108, 52} { 180, 108, 52} { 189, 114, 62} { 188, 128, 68}
+{ 132, 70, 40} { 116, 56, 25} { 132, 64, 25} { 164, 89, 44} { 180, 101, 54} { 188, 108, 51} { 180, 114, 52} { 180, 114, 52} { 188, 108, 51} { 180, 108, 52}
+{ 124, 66, 44} { 116, 50, 20} { 124, 58, 26} { 156, 82, 46} { 180, 100, 44} { 180, 108, 52} { 180, 107, 43} { 180, 107, 43} { 188, 108, 51} { 172, 94, 42}
+{ 124, 75, 41} { 102, 54, 38} { 132, 64, 25} { 164, 82, 35} { 172, 94, 42} { 180, 100, 44} { 180, 100, 44} { 180, 107, 43} { 180, 100, 44} { 172, 89, 36}
+{ 124, 77, 52} { 116, 56, 25} { 132, 64, 25} { 164, 88, 35} { 180, 94, 47} { 180, 94, 33} { 180, 107, 43} { 180, 100, 34} { 188, 108, 51} { 180, 100, 44}
+{ 149, 70, 27} { 156, 76, 27} { 156, 82, 34} { 156, 87, 35} { 164, 89, 44} { 172, 100, 49} { 180, 108, 52} { 180, 108, 52} { 180, 100, 44} { 172, 94, 42}
+{ 156, 87, 35} { 148, 76, 27} { 148, 76, 27} { 164, 82, 35} { 180, 108, 52} { 189, 114, 62} { 180, 108, 52} { 172, 94, 42} { 180, 100, 44} { 172, 89, 36}
+-- Testbed end block:
diff --git a/systemtest/testdata/overlay/overlay6.ql b/systemtest/testdata/overlay/overlay6.ql
new file mode 100644
index 0000000..11412c9
--- /dev/null
+++ b/systemtest/testdata/overlay/overlay6.ql
@@ -0,0 +1,12 @@
+-- rview-Query
+select
+
+(marray x in [0:6, 0:6, 0:6]
+values (char)(216-x[0]*x[1]*x[2] ) )
+
+overlay
+
+(marray x in [0:6, 0:6, 0:6]
+values (char)(x[0]*x[1]*x[2] ) )
+
+from ImgCharA as a \ No newline at end of file
diff --git a/systemtest/testdata/overlay/overlay6.ql.java.out b/systemtest/testdata/overlay/overlay6.ql.java.out
new file mode 100644
index 0000000..5294e14
--- /dev/null
+++ b/systemtest/testdata/overlay/overlay6.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:6,0:6,0:6]
+ TilingDomain..........: [0:49,0:49,0:49]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 343
+ -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -41 -42 -43 -44 -45 -46 -40 -42 -44 -46 -48 -50 -52 -40 -43 -46 -49 -52 -55 -58 -40 -44 -48 -52 -56 -60 -64 -40 -45 -50 -55 -60 -65 -70 -40 -46 -52 -58 -64 -70 -76 -40 -40 -40 -40 -40 -40 -40 -40 -42 -44 -46 -48 -50 -52 -40 -44 -48 -52 -56 -60 -64 -40 -46 -52 -58 -64 -70 -76 -40 -48 -56 -64 -72 -80 -88 -40 -50 -60 -70 -80 -90 -100 -40 -52 -64 -76 -88 -100 -112 -40 -40 -40 -40 -40 -40 -40 -40 -43 -46 -49 -52 -55 -58 -40 -46 -52 -58 -64 -70 -76 -40 -49 -58 -67 -76 -85 -94 -40 -52 -64 -76 -88 -100 -112 -40 -55 -70 -85 -100 -115 126 -40 -58 -76 -94 -112 126 108 -40 -40 -40 -40 -40 -40 -40 -40 -44 -48 -52 -56 -60 -64 -40 -48 -56 -64 -72 -80 -88 -40 -52 -64 -76 -88 -100 -112 -40 -56 -72 -88 -104 -120 120 -40 -60 -80 -100 -120 116 96 -40 -64 -88 -112 120 96 72 -40 -40 -40 -40 -40 -40 -40 -40 -45 -50 -55 -60 -65 -70 -40 -50 -60 -70 -80 -90 -100 -40 -55 -70 -85 -100 -115 126 -40 -60 -80 -100 -120 116 96 -40 -65 -90 -115 116 91 66 -40 -70 -100 126 96 66 36 -40 -40 -40 -40 -40 -40 -40 -40 -46 -52 -58 -64 -70 -76 -40 -52 -64 -76 -88 -100 -112 -40 -58 -76 -94 -112 126 108 -40 -64 -88 -112 120 96 72 -40 -70 -100 126 96 66 36 -40 -76 -112 108 72 36 -40
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:6,0:6,0:6]
+ TilingDomain..........: [0:49,0:49,0:49]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 343
+ -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -41 -42 -43 -44 -45 -46 -40 -42 -44 -46 -48 -50 -52 -40 -43 -46 -49 -52 -55 -58 -40 -44 -48 -52 -56 -60 -64 -40 -45 -50 -55 -60 -65 -70 -40 -46 -52 -58 -64 -70 -76 -40 -40 -40 -40 -40 -40 -40 -40 -42 -44 -46 -48 -50 -52 -40 -44 -48 -52 -56 -60 -64 -40 -46 -52 -58 -64 -70 -76 -40 -48 -56 -64 -72 -80 -88 -40 -50 -60 -70 -80 -90 -100 -40 -52 -64 -76 -88 -100 -112 -40 -40 -40 -40 -40 -40 -40 -40 -43 -46 -49 -52 -55 -58 -40 -46 -52 -58 -64 -70 -76 -40 -49 -58 -67 -76 -85 -94 -40 -52 -64 -76 -88 -100 -112 -40 -55 -70 -85 -100 -115 126 -40 -58 -76 -94 -112 126 108 -40 -40 -40 -40 -40 -40 -40 -40 -44 -48 -52 -56 -60 -64 -40 -48 -56 -64 -72 -80 -88 -40 -52 -64 -76 -88 -100 -112 -40 -56 -72 -88 -104 -120 120 -40 -60 -80 -100 -120 116 96 -40 -64 -88 -112 120 96 72 -40 -40 -40 -40 -40 -40 -40 -40 -45 -50 -55 -60 -65 -70 -40 -50 -60 -70 -80 -90 -100 -40 -55 -70 -85 -100 -115 126 -40 -60 -80 -100 -120 116 96 -40 -65 -90 -115 116 91 66 -40 -70 -100 126 96 66 36 -40 -40 -40 -40 -40 -40 -40 -40 -46 -52 -58 -64 -70 -76 -40 -52 -64 -76 -88 -100 -112 -40 -58 -76 -94 -112 126 108 -40 -64 -88 -112 120 96 72 -40 -70 -100 126 96 66 36 -40 -76 -112 108 72 36 -40 \ No newline at end of file
diff --git a/systemtest/testdata/overlay/overlay6.ql.out b/systemtest/testdata/overlay/overlay6.ql.out
new file mode 100644
index 0000000..39a4e53
--- /dev/null
+++ b/systemtest/testdata/overlay/overlay6.ql.out
@@ -0,0 +1,120 @@
+-- Testbed line: result_type=set <marray <char, [0:6,0:6,0:6]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [0:6,0:6,0:6]>
+ Type Schema...........: marray< char >
+ Domain................: [0:6,0:6,0:6]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 343
+ 216 216 216 216 216 216 216
+ 216 216 216 216 216 216 216
+ 216 216 216 216 216 216 216
+ 216 216 216 216 216 216 216
+ 216 216 216 216 216 216 216
+ 216 216 216 216 216 216 216
+ 216 216 216 216 216 216 216
+ 216 216 216 216 216 216 216
+ 216 1 2 3 4 5 6
+ 216 2 4 6 8 10 12
+ 216 3 6 9 12 15 18
+ 216 4 8 12 16 20 24
+ 216 5 10 15 20 25 30
+ 216 6 12 18 24 30 36
+ 216 216 216 216 216 216 216
+ 216 2 4 6 8 10 12
+ 216 4 8 12 16 20 24
+ 216 6 12 18 24 30 36
+ 216 8 16 24 32 40 48
+ 216 10 20 30 40 50 60
+ 216 12 24 36 48 60 72
+ 216 216 216 216 216 216 216
+ 216 3 6 9 12 15 18
+ 216 6 12 18 24 30 36
+ 216 9 18 27 36 45 54
+ 216 12 24 36 48 60 72
+ 216 15 30 45 60 75 90
+ 216 18 36 54 72 90 108
+ 216 216 216 216 216 216 216
+ 216 4 8 12 16 20 24
+ 216 8 16 24 32 40 48
+ 216 12 24 36 48 60 72
+ 216 16 32 48 64 80 96
+ 216 20 40 60 80 100 120
+ 216 24 48 72 96 120 144
+ 216 216 216 216 216 216 216
+ 216 5 10 15 20 25 30
+ 216 10 20 30 40 50 60
+ 216 15 30 45 60 75 90
+ 216 20 40 60 80 100 120
+ 216 25 50 75 100 125 150
+ 216 30 60 90 120 150 180
+ 216 216 216 216 216 216 216
+ 216 6 12 18 24 30 36
+ 216 12 24 36 48 60 72
+ 216 18 36 54 72 90 108
+ 216 24 48 72 96 120 144
+ 216 30 60 90 120 150 180
+ 216 36 72 108 144 180 216
+Image 2
+GMarray
+ Type Structure........: marray <char, [0:6,0:6,0:6]>
+ Type Schema...........: marray< char >
+ Domain................: [0:6,0:6,0:6]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 343
+ 216 216 216 216 216 216 216
+ 216 216 216 216 216 216 216
+ 216 216 216 216 216 216 216
+ 216 216 216 216 216 216 216
+ 216 216 216 216 216 216 216
+ 216 216 216 216 216 216 216
+ 216 216 216 216 216 216 216
+ 216 216 216 216 216 216 216
+ 216 1 2 3 4 5 6
+ 216 2 4 6 8 10 12
+ 216 3 6 9 12 15 18
+ 216 4 8 12 16 20 24
+ 216 5 10 15 20 25 30
+ 216 6 12 18 24 30 36
+ 216 216 216 216 216 216 216
+ 216 2 4 6 8 10 12
+ 216 4 8 12 16 20 24
+ 216 6 12 18 24 30 36
+ 216 8 16 24 32 40 48
+ 216 10 20 30 40 50 60
+ 216 12 24 36 48 60 72
+ 216 216 216 216 216 216 216
+ 216 3 6 9 12 15 18
+ 216 6 12 18 24 30 36
+ 216 9 18 27 36 45 54
+ 216 12 24 36 48 60 72
+ 216 15 30 45 60 75 90
+ 216 18 36 54 72 90 108
+ 216 216 216 216 216 216 216
+ 216 4 8 12 16 20 24
+ 216 8 16 24 32 40 48
+ 216 12 24 36 48 60 72
+ 216 16 32 48 64 80 96
+ 216 20 40 60 80 100 120
+ 216 24 48 72 96 120 144
+ 216 216 216 216 216 216 216
+ 216 5 10 15 20 25 30
+ 216 10 20 30 40 50 60
+ 216 15 30 45 60 75 90
+ 216 20 40 60 80 100 120
+ 216 25 50 75 100 125 150
+ 216 30 60 90 120 150 180
+ 216 216 216 216 216 216 216
+ 216 6 12 18 24 30 36
+ 216 12 24 36 48 60 72
+ 216 18 36 54 72 90 108
+ 216 24 48 72 96 120 144
+ 216 30 60 90 120 150 180
+ 216 36 72 108 144 180 216
+-- Testbed end block:
diff --git a/systemtest/testdata/parser/gentest.awk b/systemtest/testdata/parser/gentest.awk
new file mode 100644
index 0000000..b743c6c
--- /dev/null
+++ b/systemtest/testdata/parser/gentest.awk
@@ -0,0 +1,29 @@
+#! /bin/gawk -f
+##
+## This AWK-script generates some example queries, when applied on "testcases",
+## as command line argument. When you need to add new test cases, edit the
+## file "testcases". Each line in this file should be of the form:
+##
+## filename @ query @ -- comment @ -- comment
+##
+## For example the line:
+##
+## mm.ql @ select 2- -1 from ImgCharA as a @ -- caution: -- introduces comments.
+##
+## should generate a test file named mm.ql with the folowing content:
+##
+## -- caution: -- introduces comments.
+##
+## select 2- -1 from ImgCharA as a
+##
+## The char @ is somewhat unusual for SQL and I chose it as field separator.
+
+BEGIN {FS = "@"} ;
+
+{
+ for (i = 3; i < NF; i++) {
+ printf "%s\n", $i > $1
+ }
+ printf "\n" >> $1
+ printf "%s\n", $2 >> $1
+}
diff --git a/systemtest/testdata/parser/mm_long.ql b/systemtest/testdata/parser/mm_long.ql
new file mode 100644
index 0000000..5f79ee8
--- /dev/null
+++ b/systemtest/testdata/parser/mm_long.ql
@@ -0,0 +1,3 @@
+ -- test unary and binary operators on long.
+
+ select 2++1 from ImgCharA as i
diff --git a/systemtest/testdata/parser/mm_long.ql.java.out b/systemtest/testdata/parser/mm_long.ql.java.out
new file mode 100644
index 0000000..dc7b54a
--- /dev/null
+++ b/systemtest/testdata/parser/mm_long.ql.java.out
@@ -0,0 +1 @@
+33 \ No newline at end of file
diff --git a/systemtest/testdata/parser/mm_long.ql.out b/systemtest/testdata/parser/mm_long.ql.out
new file mode 100644
index 0000000..58af424
--- /dev/null
+++ b/systemtest/testdata/parser/mm_long.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<long>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 3
+Element 2: 3
+-- Testbed end block:
diff --git a/systemtest/testdata/parser/mp_long.ql b/systemtest/testdata/parser/mp_long.ql
new file mode 100644
index 0000000..0d613de
--- /dev/null
+++ b/systemtest/testdata/parser/mp_long.ql
@@ -0,0 +1,2 @@
+
+ select 2-+1 from ImgCharA as i
diff --git a/systemtest/testdata/parser/mp_long.ql.java.out b/systemtest/testdata/parser/mp_long.ql.java.out
new file mode 100644
index 0000000..9d60796
--- /dev/null
+++ b/systemtest/testdata/parser/mp_long.ql.java.out
@@ -0,0 +1 @@
+11 \ No newline at end of file
diff --git a/systemtest/testdata/parser/mp_long.ql.out b/systemtest/testdata/parser/mp_long.ql.out
new file mode 100644
index 0000000..5f11d14
--- /dev/null
+++ b/systemtest/testdata/parser/mp_long.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<long>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 1
+Element 2: 1
+-- Testbed end block:
diff --git a/systemtest/testdata/parser/nm_long.ql b/systemtest/testdata/parser/nm_long.ql
new file mode 100644
index 0000000..188c6ae
--- /dev/null
+++ b/systemtest/testdata/parser/nm_long.ql
@@ -0,0 +1,2 @@
+
+ select -0 from ImgCharA as i
diff --git a/systemtest/testdata/parser/nm_long.ql.java.out b/systemtest/testdata/parser/nm_long.ql.java.out
new file mode 100644
index 0000000..857f065
--- /dev/null
+++ b/systemtest/testdata/parser/nm_long.ql.java.out
@@ -0,0 +1 @@
+00 \ No newline at end of file
diff --git a/systemtest/testdata/parser/nm_long.ql.out b/systemtest/testdata/parser/nm_long.ql.out
new file mode 100644
index 0000000..0b8f0e4
--- /dev/null
+++ b/systemtest/testdata/parser/nm_long.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<long>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 0
+Element 2: 0
+-- Testbed end block:
diff --git a/systemtest/testdata/parser/nn_long.ql b/systemtest/testdata/parser/nn_long.ql
new file mode 100644
index 0000000..c3b31a6
--- /dev/null
+++ b/systemtest/testdata/parser/nn_long.ql
@@ -0,0 +1,2 @@
+
+ select 0 from ImgCharA as i
diff --git a/systemtest/testdata/parser/nn_long.ql.java.out b/systemtest/testdata/parser/nn_long.ql.java.out
new file mode 100644
index 0000000..857f065
--- /dev/null
+++ b/systemtest/testdata/parser/nn_long.ql.java.out
@@ -0,0 +1 @@
+00 \ No newline at end of file
diff --git a/systemtest/testdata/parser/nn_long.ql.out b/systemtest/testdata/parser/nn_long.ql.out
new file mode 100644
index 0000000..0b8f0e4
--- /dev/null
+++ b/systemtest/testdata/parser/nn_long.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<long>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 0
+Element 2: 0
+-- Testbed end block:
diff --git a/systemtest/testdata/parser/np_long.ql b/systemtest/testdata/parser/np_long.ql
new file mode 100644
index 0000000..819cdf4
--- /dev/null
+++ b/systemtest/testdata/parser/np_long.ql
@@ -0,0 +1,2 @@
+
+ select +0 from ImgCharA as i
diff --git a/systemtest/testdata/parser/np_long.ql.java.out b/systemtest/testdata/parser/np_long.ql.java.out
new file mode 100644
index 0000000..857f065
--- /dev/null
+++ b/systemtest/testdata/parser/np_long.ql.java.out
@@ -0,0 +1 @@
+00 \ No newline at end of file
diff --git a/systemtest/testdata/parser/np_long.ql.out b/systemtest/testdata/parser/np_long.ql.out
new file mode 100644
index 0000000..0b8f0e4
--- /dev/null
+++ b/systemtest/testdata/parser/np_long.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<long>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 0
+Element 2: 0
+-- Testbed end block:
diff --git a/systemtest/testdata/parser/om_long.ql b/systemtest/testdata/parser/om_long.ql
new file mode 100644
index 0000000..2e65dfa
--- /dev/null
+++ b/systemtest/testdata/parser/om_long.ql
@@ -0,0 +1,2 @@
+
+ select -1 from ImgCharA as i
diff --git a/systemtest/testdata/parser/om_long.ql.java.out b/systemtest/testdata/parser/om_long.ql.java.out
new file mode 100644
index 0000000..c92a447
--- /dev/null
+++ b/systemtest/testdata/parser/om_long.ql.java.out
@@ -0,0 +1 @@
+-1-1 \ No newline at end of file
diff --git a/systemtest/testdata/parser/om_long.ql.out b/systemtest/testdata/parser/om_long.ql.out
new file mode 100644
index 0000000..08b0f64
--- /dev/null
+++ b/systemtest/testdata/parser/om_long.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<long>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: -1
+Element 2: -1
+-- Testbed end block:
diff --git a/systemtest/testdata/parser/on_long.ql b/systemtest/testdata/parser/on_long.ql
new file mode 100644
index 0000000..dd16912
--- /dev/null
+++ b/systemtest/testdata/parser/on_long.ql
@@ -0,0 +1,2 @@
+
+ select 1 from ImgCharA as i
diff --git a/systemtest/testdata/parser/on_long.ql.java.out b/systemtest/testdata/parser/on_long.ql.java.out
new file mode 100644
index 0000000..9d60796
--- /dev/null
+++ b/systemtest/testdata/parser/on_long.ql.java.out
@@ -0,0 +1 @@
+11 \ No newline at end of file
diff --git a/systemtest/testdata/parser/on_long.ql.out b/systemtest/testdata/parser/on_long.ql.out
new file mode 100644
index 0000000..5f11d14
--- /dev/null
+++ b/systemtest/testdata/parser/on_long.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<long>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 1
+Element 2: 1
+-- Testbed end block:
diff --git a/systemtest/testdata/parser/op_long.ql b/systemtest/testdata/parser/op_long.ql
new file mode 100644
index 0000000..0dab606
--- /dev/null
+++ b/systemtest/testdata/parser/op_long.ql
@@ -0,0 +1,2 @@
+
+ select +1 from ImgCharA as i
diff --git a/systemtest/testdata/parser/op_long.ql.java.out b/systemtest/testdata/parser/op_long.ql.java.out
new file mode 100644
index 0000000..9d60796
--- /dev/null
+++ b/systemtest/testdata/parser/op_long.ql.java.out
@@ -0,0 +1 @@
+11 \ No newline at end of file
diff --git a/systemtest/testdata/parser/op_long.ql.out b/systemtest/testdata/parser/op_long.ql.out
new file mode 100644
index 0000000..5f11d14
--- /dev/null
+++ b/systemtest/testdata/parser/op_long.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<long>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 1
+Element 2: 1
+-- Testbed end block:
diff --git a/systemtest/testdata/parser/p1_long.ql b/systemtest/testdata/parser/p1_long.ql
new file mode 100644
index 0000000..55915d7
--- /dev/null
+++ b/systemtest/testdata/parser/p1_long.ql
@@ -0,0 +1,2 @@
+
+ select 2+1 from ImgCharA as i
diff --git a/systemtest/testdata/parser/p1_long.ql.java.out b/systemtest/testdata/parser/p1_long.ql.java.out
new file mode 100644
index 0000000..dc7b54a
--- /dev/null
+++ b/systemtest/testdata/parser/p1_long.ql.java.out
@@ -0,0 +1 @@
+33 \ No newline at end of file
diff --git a/systemtest/testdata/parser/p1_long.ql.out b/systemtest/testdata/parser/p1_long.ql.out
new file mode 100644
index 0000000..58af424
--- /dev/null
+++ b/systemtest/testdata/parser/p1_long.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<long>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 3
+Element 2: 3
+-- Testbed end block:
diff --git a/systemtest/testdata/parser/p2_long.ql b/systemtest/testdata/parser/p2_long.ql
new file mode 100644
index 0000000..b3581cd
--- /dev/null
+++ b/systemtest/testdata/parser/p2_long.ql
@@ -0,0 +1,2 @@
+
+ select -2+1 from ImgCharA as i
diff --git a/systemtest/testdata/parser/p2_long.ql.java.out b/systemtest/testdata/parser/p2_long.ql.java.out
new file mode 100644
index 0000000..c92a447
--- /dev/null
+++ b/systemtest/testdata/parser/p2_long.ql.java.out
@@ -0,0 +1 @@
+-1-1 \ No newline at end of file
diff --git a/systemtest/testdata/parser/p2_long.ql.out b/systemtest/testdata/parser/p2_long.ql.out
new file mode 100644
index 0000000..08b0f64
--- /dev/null
+++ b/systemtest/testdata/parser/p2_long.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<long>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: -1
+Element 2: -1
+-- Testbed end block:
diff --git a/systemtest/testdata/parser/pm_long.ql b/systemtest/testdata/parser/pm_long.ql
new file mode 100644
index 0000000..ee67e1c
--- /dev/null
+++ b/systemtest/testdata/parser/pm_long.ql
@@ -0,0 +1,2 @@
+
+ select 2+-1 from ImgCharA as i
diff --git a/systemtest/testdata/parser/pm_long.ql.java.out b/systemtest/testdata/parser/pm_long.ql.java.out
new file mode 100644
index 0000000..9d60796
--- /dev/null
+++ b/systemtest/testdata/parser/pm_long.ql.java.out
@@ -0,0 +1 @@
+11 \ No newline at end of file
diff --git a/systemtest/testdata/parser/pm_long.ql.out b/systemtest/testdata/parser/pm_long.ql.out
new file mode 100644
index 0000000..5f11d14
--- /dev/null
+++ b/systemtest/testdata/parser/pm_long.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<long>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 1
+Element 2: 1
+-- Testbed end block:
diff --git a/systemtest/testdata/parser/pp_long.ql b/systemtest/testdata/parser/pp_long.ql
new file mode 100644
index 0000000..98cf8b0
--- /dev/null
+++ b/systemtest/testdata/parser/pp_long.ql
@@ -0,0 +1,2 @@
+
+ select 2++1 from ImgCharA as i
diff --git a/systemtest/testdata/parser/pp_long.ql.java.out b/systemtest/testdata/parser/pp_long.ql.java.out
new file mode 100644
index 0000000..dc7b54a
--- /dev/null
+++ b/systemtest/testdata/parser/pp_long.ql.java.out
@@ -0,0 +1 @@
+33 \ No newline at end of file
diff --git a/systemtest/testdata/parser/pp_long.ql.out b/systemtest/testdata/parser/pp_long.ql.out
new file mode 100644
index 0000000..58af424
--- /dev/null
+++ b/systemtest/testdata/parser/pp_long.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<long>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 3
+Element 2: 3
+-- Testbed end block:
diff --git a/systemtest/testdata/parser/sqrt_1.ql b/systemtest/testdata/parser/sqrt_1.ql
new file mode 100644
index 0000000..205e344
--- /dev/null
+++ b/systemtest/testdata/parser/sqrt_1.ql
@@ -0,0 +1,2 @@
+
+ select sqrt(2.0d) from ImgCharA as i
diff --git a/systemtest/testdata/parser/sqrt_1.ql.java.out b/systemtest/testdata/parser/sqrt_1.ql.java.out
new file mode 100644
index 0000000..27ceb54
--- /dev/null
+++ b/systemtest/testdata/parser/sqrt_1.ql.java.out
@@ -0,0 +1 @@
+1.41421356237309511.4142135623730951 \ No newline at end of file
diff --git a/systemtest/testdata/parser/sqrt_1.ql.out b/systemtest/testdata/parser/sqrt_1.ql.out
new file mode 100644
index 0000000..a23dbb9
--- /dev/null
+++ b/systemtest/testdata/parser/sqrt_1.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 1.41421
+Element 2: 1.41421
+-- Testbed end block:
diff --git a/systemtest/testdata/parser/sqrt_2.ql b/systemtest/testdata/parser/sqrt_2.ql
new file mode 100644
index 0000000..6cf337a
--- /dev/null
+++ b/systemtest/testdata/parser/sqrt_2.ql
@@ -0,0 +1,2 @@
+
+ select sqrt(1.0d + 2.0d) from ImgCharA as i
diff --git a/systemtest/testdata/parser/sqrt_2.ql.java.out b/systemtest/testdata/parser/sqrt_2.ql.java.out
new file mode 100644
index 0000000..6367268
--- /dev/null
+++ b/systemtest/testdata/parser/sqrt_2.ql.java.out
@@ -0,0 +1 @@
+1.73205080756887721.7320508075688772 \ No newline at end of file
diff --git a/systemtest/testdata/parser/sqrt_2.ql.out b/systemtest/testdata/parser/sqrt_2.ql.out
new file mode 100644
index 0000000..7c1432a
--- /dev/null
+++ b/systemtest/testdata/parser/sqrt_2.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 1.73205
+Element 2: 1.73205
+-- Testbed end block:
diff --git a/systemtest/testdata/parser/sqrt_3.ql b/systemtest/testdata/parser/sqrt_3.ql
new file mode 100644
index 0000000..f8f97d8
--- /dev/null
+++ b/systemtest/testdata/parser/sqrt_3.ql
@@ -0,0 +1,2 @@
+
+ select sqrt(sqrt(4.0d)) from ImgCharA as i
diff --git a/systemtest/testdata/parser/sqrt_3.ql.java.out b/systemtest/testdata/parser/sqrt_3.ql.java.out
new file mode 100644
index 0000000..27ceb54
--- /dev/null
+++ b/systemtest/testdata/parser/sqrt_3.ql.java.out
@@ -0,0 +1 @@
+1.41421356237309511.4142135623730951 \ No newline at end of file
diff --git a/systemtest/testdata/parser/sqrt_3.ql.out b/systemtest/testdata/parser/sqrt_3.ql.out
new file mode 100644
index 0000000..a23dbb9
--- /dev/null
+++ b/systemtest/testdata/parser/sqrt_3.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 1.41421
+Element 2: 1.41421
+-- Testbed end block:
diff --git a/systemtest/testdata/parser/sqrt_4.ql b/systemtest/testdata/parser/sqrt_4.ql
new file mode 100644
index 0000000..3eb8806
--- /dev/null
+++ b/systemtest/testdata/parser/sqrt_4.ql
@@ -0,0 +1,2 @@
+
+ select sqrt(0.0d) from ImgCharA as i
diff --git a/systemtest/testdata/parser/sqrt_4.ql.java.out b/systemtest/testdata/parser/sqrt_4.ql.java.out
new file mode 100644
index 0000000..b2024e1
--- /dev/null
+++ b/systemtest/testdata/parser/sqrt_4.ql.java.out
@@ -0,0 +1 @@
+0.00.0 \ No newline at end of file
diff --git a/systemtest/testdata/parser/sqrt_4.ql.out b/systemtest/testdata/parser/sqrt_4.ql.out
new file mode 100644
index 0000000..eb05dc2
--- /dev/null
+++ b/systemtest/testdata/parser/sqrt_4.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 0
+Element 2: 0
+-- Testbed end block:
diff --git a/systemtest/testdata/parser/sqrt_5.ql b/systemtest/testdata/parser/sqrt_5.ql
new file mode 100644
index 0000000..a3a6f82
--- /dev/null
+++ b/systemtest/testdata/parser/sqrt_5.ql
@@ -0,0 +1,2 @@
+
+ select 1.0d + sqrt(2.0d) from ImgCharA as i
diff --git a/systemtest/testdata/parser/sqrt_5.ql.java.out b/systemtest/testdata/parser/sqrt_5.ql.java.out
new file mode 100644
index 0000000..785bccc
--- /dev/null
+++ b/systemtest/testdata/parser/sqrt_5.ql.java.out
@@ -0,0 +1 @@
+2.4142135623730952.414213562373095 \ No newline at end of file
diff --git a/systemtest/testdata/parser/sqrt_5.ql.out b/systemtest/testdata/parser/sqrt_5.ql.out
new file mode 100644
index 0000000..9a7b7d3
--- /dev/null
+++ b/systemtest/testdata/parser/sqrt_5.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 2.41421
+Element 2: 2.41421
+-- Testbed end block:
diff --git a/systemtest/testdata/parser/sqrt_6.ql b/systemtest/testdata/parser/sqrt_6.ql
new file mode 100644
index 0000000..ba6cb0d
--- /dev/null
+++ b/systemtest/testdata/parser/sqrt_6.ql
@@ -0,0 +1,2 @@
+
+ select sqrt(2.0d) - 1.0d from ImgCharA as i
diff --git a/systemtest/testdata/parser/sqrt_6.ql.java.out b/systemtest/testdata/parser/sqrt_6.ql.java.out
new file mode 100644
index 0000000..eb428b9
--- /dev/null
+++ b/systemtest/testdata/parser/sqrt_6.ql.java.out
@@ -0,0 +1 @@
+0.414213562373095150.41421356237309515 \ No newline at end of file
diff --git a/systemtest/testdata/parser/sqrt_6.ql.out b/systemtest/testdata/parser/sqrt_6.ql.out
new file mode 100644
index 0000000..0851541
--- /dev/null
+++ b/systemtest/testdata/parser/sqrt_6.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 0.414214
+Element 2: 0.414214
+-- Testbed end block:
diff --git a/systemtest/testdata/parser/testcases b/systemtest/testdata/parser/testcases
new file mode 100644
index 0000000..be7e51a
--- /dev/null
+++ b/systemtest/testdata/parser/testcases
@@ -0,0 +1,21 @@
+pp_long.ql@ select 2++1 from ImgCharA as i @ -- test unary and binary operators on long.
+pm_long.ql@ select 2+-1 from ImgCharA as i @ -- test unary and binary operators on long.
+mp_long.ql@ select 2-+1 from ImgCharA as i @ -- test unary and binary operators on long.
+mm_long.ql@ select 2++1 from ImgCharA as i @ -- test unary and binary operators on long. @ -- Caution: don't use -- as it introduces comments.
+nn_long.ql@ select 0 from ImgCharA as i @ -- test long zero.
+np_long.ql@ select +0 from ImgCharA as i @ -- test long zero.
+nm_long.ql@ select -0 from ImgCharA as i @ -- test long zero.
+on_long.ql@ select 1 from ImgCharA as i @ -- test long one.
+op_long.ql@ select +1 from ImgCharA as i @ -- test long one.
+om_long.ql@ select -1 from ImgCharA as i @ -- test long one.
+p1_long.ql@ select 2+1 from ImgCharA as i @ -- test basic arithmetic.
+p2_long.ql@ select -2+1 from ImgCharA as i @ -- test basic arithmetic.
+m1_long.ql@ select 2-1 from ImgCharA as i @ -- test basic arithmetic.
+m2_long.ql@ select -2-1 from ImgCharA as i @ -- test basic arithmetic.
+sqrt_1.ql@ select sqrt(2.0d) from ImgCharA as i @ -- test square root.
+sqrt_2.ql@ select sqrt(1.0d + 2.0d) from ImgCharA as i @ -- test square root.
+sqrt_3.ql@ select sqrt(sqrt(4.0d)) from ImgCharA as i @ -- test square root.
+sqrt_4.ql@ select sqrt(0.0d) from ImgCharA as i @ -- test square root.
+sqrt_5.ql@ select 1.0d + sqrt(2.0d) from ImgCharA as i @ -- test square root.
+sqrt_6.ql@ select sqrt(2.0d) - 1.0d from ImgCharA as i @ -- test square root.
+sqrt_nan.ql@ select sqrt(-10.0d) from ImgCharA as i @ -- negative argument leads to NaN. \ No newline at end of file
diff --git a/systemtest/testdata/partialoverlay/u01_create.ql b/systemtest/testdata/partialoverlay/u01_create.ql
new file mode 100644
index 0000000..17e070a
--- /dev/null
+++ b/systemtest/testdata/partialoverlay/u01_create.ql
@@ -0,0 +1 @@
+CREATE COLLECTION PartialOverlay1 ULongSet
diff --git a/systemtest/testdata/partialoverlay/u01_create.ql.out b/systemtest/testdata/partialoverlay/u01_create.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialoverlay/u01_create.ql.out
diff --git a/systemtest/testdata/partialoverlay/u02_create.ql b/systemtest/testdata/partialoverlay/u02_create.ql
new file mode 100644
index 0000000..36ceda2
--- /dev/null
+++ b/systemtest/testdata/partialoverlay/u02_create.ql
@@ -0,0 +1 @@
+CREATE COLLECTION PartialOverlay2 ULongSet
diff --git a/systemtest/testdata/partialoverlay/u02_create.ql.out b/systemtest/testdata/partialoverlay/u02_create.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialoverlay/u02_create.ql.out
diff --git a/systemtest/testdata/partialoverlay/u03_insert.ql b/systemtest/testdata/partialoverlay/u03_insert.ql
new file mode 100644
index 0000000..c508a46
--- /dev/null
+++ b/systemtest/testdata/partialoverlay/u03_insert.ql
@@ -0,0 +1,14 @@
+insert into PartialOverlay2 values < [0:10,0:10]
+ 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul;
+ 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul;
+ 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul;
+ 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul;
+ 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul;
+ 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul;
+ 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul;
+ 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul;
+ 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul;
+ 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul;
+ 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul
+ >
+
diff --git a/systemtest/testdata/partialoverlay/u03_insert.ql.out b/systemtest/testdata/partialoverlay/u03_insert.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialoverlay/u03_insert.ql.out
diff --git a/systemtest/testdata/partialoverlay/u04_insert.ql b/systemtest/testdata/partialoverlay/u04_insert.ql
new file mode 100644
index 0000000..de9816e
--- /dev/null
+++ b/systemtest/testdata/partialoverlay/u04_insert.ql
@@ -0,0 +1,13 @@
+insert into PartialOverlay1 values < [0:10,0:10]
+ 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul;
+ 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul;
+ 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul;
+ 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul;
+ 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul;
+ 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul;
+ 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul;
+ 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul;
+ 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul;
+ 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul;
+ 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul
+ >
diff --git a/systemtest/testdata/partialoverlay/u04_insert.ql.out b/systemtest/testdata/partialoverlay/u04_insert.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialoverlay/u04_insert.ql.out
diff --git a/systemtest/testdata/partialoverlay/u05_update.ql b/systemtest/testdata/partialoverlay/u05_update.ql
new file mode 100644
index 0000000..c4555c4
--- /dev/null
+++ b/systemtest/testdata/partialoverlay/u05_update.ql
@@ -0,0 +1,15 @@
+UPDATE PartialOverlay2 AS image
+SET image ASSIGN < [90:100,90:100]
+ 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul;
+ 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul;
+ 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul;
+ 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul;
+ 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul;
+ 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul;
+ 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul;
+ 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul;
+ 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul;
+ 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul;
+ 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul
+ >
+
diff --git a/systemtest/testdata/partialoverlay/u05_update.ql.out b/systemtest/testdata/partialoverlay/u05_update.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialoverlay/u05_update.ql.out
diff --git a/systemtest/testdata/partialoverlay/u06_update.ql b/systemtest/testdata/partialoverlay/u06_update.ql
new file mode 100644
index 0000000..179a754
--- /dev/null
+++ b/systemtest/testdata/partialoverlay/u06_update.ql
@@ -0,0 +1,14 @@
+UPDATE PartialOverlay2 AS image
+SET image ASSIGN < [45:55,25:35]
+ 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul;
+ 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul;
+ 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul;
+ 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul;
+ 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul;
+ 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul;
+ 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul;
+ 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul;
+ 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul;
+ 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul;
+ 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul
+ >
diff --git a/systemtest/testdata/partialoverlay/u06_update.ql.out b/systemtest/testdata/partialoverlay/u06_update.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialoverlay/u06_update.ql.out
diff --git a/systemtest/testdata/partialoverlay/u07_update.ql b/systemtest/testdata/partialoverlay/u07_update.ql
new file mode 100644
index 0000000..748e48e
--- /dev/null
+++ b/systemtest/testdata/partialoverlay/u07_update.ql
@@ -0,0 +1,15 @@
+UPDATE PartialOverlay1 AS image
+SET image ASSIGN < [45:55,65:75]
+ 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul;
+ 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul;
+ 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul;
+ 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul;
+ 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul;
+ 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul;
+ 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul;
+ 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul;
+ 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul;
+ 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul;
+ 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul
+ >
+
diff --git a/systemtest/testdata/partialoverlay/u07_update.ql.out b/systemtest/testdata/partialoverlay/u07_update.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialoverlay/u07_update.ql.out
diff --git a/systemtest/testdata/partialoverlay/u08_update.ql b/systemtest/testdata/partialoverlay/u08_update.ql
new file mode 100644
index 0000000..5c2fd28
--- /dev/null
+++ b/systemtest/testdata/partialoverlay/u08_update.ql
@@ -0,0 +1,15 @@
+UPDATE PartialOverlay1 AS image
+SET image ASSIGN < [90:100,90:100]
+ 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul;
+ 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul;
+ 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul;
+ 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul;
+ 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul;
+ 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul;
+ 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul;
+ 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul;
+ 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul;
+ 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul;
+ 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul
+ >
+
diff --git a/systemtest/testdata/partialoverlay/u08_update.ql.out b/systemtest/testdata/partialoverlay/u08_update.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialoverlay/u08_update.ql.out
diff --git a/systemtest/testdata/partialoverlay/u09_lookup.ql b/systemtest/testdata/partialoverlay/u09_lookup.ql
new file mode 100644
index 0000000..c720367
--- /dev/null
+++ b/systemtest/testdata/partialoverlay/u09_lookup.ql
@@ -0,0 +1,3 @@
+SELECT scale(a, [0:10,0:10])
+FROM PartialOverlay1 AS a
+
diff --git a/systemtest/testdata/partialoverlay/u09_lookup.ql.out b/systemtest/testdata/partialoverlay/u09_lookup.ql.out
new file mode 100644
index 0000000..0e0e0fb
--- /dev/null
+++ b/systemtest/testdata/partialoverlay/u09_lookup.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <ulong, [0:10,0:10]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <ulong, [0:10,0:10]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 484
+ 1 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 1 1 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 1 1
+ 0 0 0 0 0 0 0 0 0 1 1
+-- Testbed end block:
diff --git a/systemtest/testdata/partialoverlay/u10_lookup.ql b/systemtest/testdata/partialoverlay/u10_lookup.ql
new file mode 100644
index 0000000..a17efa3
--- /dev/null
+++ b/systemtest/testdata/partialoverlay/u10_lookup.ql
@@ -0,0 +1,3 @@
+SELECT scale(a, [0:10,0:10])
+FROM PartialOverlay2 AS a
+
diff --git a/systemtest/testdata/partialoverlay/u10_lookup.ql.out b/systemtest/testdata/partialoverlay/u10_lookup.ql.out
new file mode 100644
index 0000000..a56f5d3
--- /dev/null
+++ b/systemtest/testdata/partialoverlay/u10_lookup.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <ulong, [0:10,0:10]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <ulong, [0:10,0:10]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 484
+ 2 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 2 2 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 2 2
+ 0 0 0 0 0 0 0 0 0 2 2
+-- Testbed end block:
diff --git a/systemtest/testdata/partialoverlay/u11_overlay.ql.out b/systemtest/testdata/partialoverlay/u11_overlay.ql.out
new file mode 100644
index 0000000..4ff4c0a
--- /dev/null
+++ b/systemtest/testdata/partialoverlay/u11_overlay.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=355
diff --git a/systemtest/testdata/partialoverlay/u12_overlay.ql.out b/systemtest/testdata/partialoverlay/u12_overlay.ql.out
new file mode 100644
index 0000000..7ec12ef
--- /dev/null
+++ b/systemtest/testdata/partialoverlay/u12_overlay.ql.out
@@ -0,0 +1,84 @@
+-- Testbed line: result_type=set <marray <ulong, [0:10,0:10]>>
+-- Testbed line: result_elements=4
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <ulong, [0:10,0:10]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 484
+ 1 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 1 1
+ 0 0 0 0 0 0 0 0 0 1 1
+Image 2
+GMarray
+ Type Structure........: marray <ulong, [0:10,0:10]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 484
+ 1 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 1 1
+ 0 0 0 0 0 0 0 0 0 1 1
+Image 3
+GMarray
+ Type Structure........: marray <ulong, [0:10,0:10]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 484
+ 1 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 1 1
+ 0 0 0 0 0 0 0 0 0 1 1
+Image 4
+GMarray
+ Type Structure........: marray <ulong, [0:10,0:10]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 484
+ 1 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 1 1
+ 0 0 0 0 0 0 0 0 0 1 1
+-- Testbed end block:
diff --git a/systemtest/testdata/partialoverlay/u13_overlay.ql.out b/systemtest/testdata/partialoverlay/u13_overlay.ql.out
new file mode 100644
index 0000000..592070d
--- /dev/null
+++ b/systemtest/testdata/partialoverlay/u13_overlay.ql.out
@@ -0,0 +1,84 @@
+-- Testbed line: result_type=set <marray <ulong, [0:10,0:10]>>
+-- Testbed line: result_elements=4
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <ulong, [0:10,0:10]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 484
+ 1 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+Image 2
+GMarray
+ Type Structure........: marray <ulong, [0:10,0:10]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 484
+ 1 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+Image 3
+GMarray
+ Type Structure........: marray <ulong, [0:10,0:10]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 484
+ 1 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+Image 4
+GMarray
+ Type Structure........: marray <ulong, [0:10,0:10]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 484
+ 1 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+-- Testbed end block:
diff --git a/systemtest/testdata/partialoverlay/u98_drop.ql b/systemtest/testdata/partialoverlay/u98_drop.ql
new file mode 100644
index 0000000..422c875
--- /dev/null
+++ b/systemtest/testdata/partialoverlay/u98_drop.ql
@@ -0,0 +1,2 @@
+DROP COLLECTION PartialOverlay1
+
diff --git a/systemtest/testdata/partialoverlay/u98_drop.ql.out b/systemtest/testdata/partialoverlay/u98_drop.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialoverlay/u98_drop.ql.out
diff --git a/systemtest/testdata/partialoverlay/u99_drop.ql b/systemtest/testdata/partialoverlay/u99_drop.ql
new file mode 100644
index 0000000..c89121f
--- /dev/null
+++ b/systemtest/testdata/partialoverlay/u99_drop.ql
@@ -0,0 +1 @@
+DROP COLLECTION PartialOverlay2
diff --git a/systemtest/testdata/partialoverlay/u99_drop.ql.out b/systemtest/testdata/partialoverlay/u99_drop.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialoverlay/u99_drop.ql.out
diff --git a/systemtest/testdata/partialupdate/u01_create.ql b/systemtest/testdata/partialupdate/u01_create.ql
new file mode 100644
index 0000000..afd4c0a
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u01_create.ql
@@ -0,0 +1 @@
+CREATE COLLECTION PartialUpdate ULongSet
diff --git a/systemtest/testdata/partialupdate/u01_create.ql.java.out b/systemtest/testdata/partialupdate/u01_create.ql.java.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u01_create.ql.java.out
diff --git a/systemtest/testdata/partialupdate/u01_create.ql.out b/systemtest/testdata/partialupdate/u01_create.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u01_create.ql.out
diff --git a/systemtest/testdata/partialupdate/u02_insert.ql b/systemtest/testdata/partialupdate/u02_insert.ql
new file mode 100644
index 0000000..296d8f0
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u02_insert.ql
@@ -0,0 +1,13 @@
+insert into PartialUpdate values < [0:10,0:10]
+ 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul;
+ 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul;
+ 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul;
+ 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul;
+ 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul;
+ 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul;
+ 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul;
+ 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul;
+ 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul;
+ 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul;
+ 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul
+ >
diff --git a/systemtest/testdata/partialupdate/u02_insert.ql.java.out b/systemtest/testdata/partialupdate/u02_insert.ql.java.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u02_insert.ql.java.out
diff --git a/systemtest/testdata/partialupdate/u02_insert.ql.out b/systemtest/testdata/partialupdate/u02_insert.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u02_insert.ql.out
diff --git a/systemtest/testdata/partialupdate/u03_lookup.ql b/systemtest/testdata/partialupdate/u03_lookup.ql
new file mode 100644
index 0000000..bd885e9
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u03_lookup.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <ulong, [0:10,0:10]>>
+-- Testbed: result_elements=1
+
+SELECT a
+FROM PartialUpdate AS a
diff --git a/systemtest/testdata/partialupdate/u03_lookup.ql.java.out b/systemtest/testdata/partialupdate/u03_lookup.ql.java.out
new file mode 100644
index 0000000..3f9e31c
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u03_lookup.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayLong
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 968
+ 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 \ No newline at end of file
diff --git a/systemtest/testdata/partialupdate/u03_lookup.ql.out b/systemtest/testdata/partialupdate/u03_lookup.ql.out
new file mode 100644
index 0000000..e0f70fd
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u03_lookup.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <ulong, [0:10,0:10]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <ulong, [0:10,0:10]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 484
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+-- Testbed end block:
diff --git a/systemtest/testdata/partialupdate/u04_update.ql b/systemtest/testdata/partialupdate/u04_update.ql
new file mode 100644
index 0000000..56c5cea
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u04_update.ql
@@ -0,0 +1,15 @@
+UPDATE PartialUpdate AS image
+SET image ASSIGN < [15:25,10:20]
+ 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul;
+ 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul;
+ 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul;
+ 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul;
+ 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul;
+ 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul;
+ 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul;
+ 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul;
+ 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul;
+ 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul;
+ 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul, 2ul
+ >
+
diff --git a/systemtest/testdata/partialupdate/u04_update.ql.java.out b/systemtest/testdata/partialupdate/u04_update.ql.java.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u04_update.ql.java.out
diff --git a/systemtest/testdata/partialupdate/u04_update.ql.out b/systemtest/testdata/partialupdate/u04_update.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u04_update.ql.out
diff --git a/systemtest/testdata/partialupdate/u05_lookup.ql b/systemtest/testdata/partialupdate/u05_lookup.ql
new file mode 100644
index 0000000..bd885e9
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u05_lookup.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <ulong, [0:10,0:10]>>
+-- Testbed: result_elements=1
+
+SELECT a
+FROM PartialUpdate AS a
diff --git a/systemtest/testdata/partialupdate/u05_lookup.ql.java.out b/systemtest/testdata/partialupdate/u05_lookup.ql.java.out
new file mode 100644
index 0000000..1309861
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u05_lookup.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayLong
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:25,0:20]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 4368
+ 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 \ No newline at end of file
diff --git a/systemtest/testdata/partialupdate/u05_lookup.ql.out b/systemtest/testdata/partialupdate/u05_lookup.ql.out
new file mode 100644
index 0000000..8129803
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u05_lookup.ql.out
@@ -0,0 +1,34 @@
+-- Testbed line: result_type=set <marray <ulong, [0:25,0:20]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <ulong, [0:25,0:20]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:25,0:20]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 2184
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2
+-- Testbed end block:
diff --git a/systemtest/testdata/partialupdate/u06_update.ql b/systemtest/testdata/partialupdate/u06_update.ql
new file mode 100644
index 0000000..57bb09f
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u06_update.ql
@@ -0,0 +1,14 @@
+UPDATE PartialUpdate AS image
+SET image ASSIGN < [15:25,21:30]
+ 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul;
+ 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul;
+ 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul;
+ 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul;
+ 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul;
+ 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul;
+ 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul;
+ 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul;
+ 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul;
+ 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul
+ >
+
diff --git a/systemtest/testdata/partialupdate/u06_update.ql.java.out b/systemtest/testdata/partialupdate/u06_update.ql.java.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u06_update.ql.java.out
diff --git a/systemtest/testdata/partialupdate/u06_update.ql.out b/systemtest/testdata/partialupdate/u06_update.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u06_update.ql.out
diff --git a/systemtest/testdata/partialupdate/u071_update.ql b/systemtest/testdata/partialupdate/u071_update.ql
new file mode 100644
index 0000000..b011c4c
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u071_update.ql
@@ -0,0 +1,14 @@
+UPDATE PartialUpdate AS image
+SET image ASSIGN < [15:25,31:40]
+ 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul;
+ 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul;
+ 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul;
+ 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul;
+ 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul;
+ 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul;
+ 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul;
+ 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul;
+ 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul;
+ 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul
+ >
+
diff --git a/systemtest/testdata/partialupdate/u071_update.ql.java.out b/systemtest/testdata/partialupdate/u071_update.ql.java.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u071_update.ql.java.out
diff --git a/systemtest/testdata/partialupdate/u071_update.ql.out b/systemtest/testdata/partialupdate/u071_update.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u071_update.ql.out
diff --git a/systemtest/testdata/partialupdate/u072_lookup.ql b/systemtest/testdata/partialupdate/u072_lookup.ql
new file mode 100644
index 0000000..bd885e9
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u072_lookup.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <ulong, [0:10,0:10]>>
+-- Testbed: result_elements=1
+
+SELECT a
+FROM PartialUpdate AS a
diff --git a/systemtest/testdata/partialupdate/u072_lookup.ql.java.out b/systemtest/testdata/partialupdate/u072_lookup.ql.java.out
new file mode 100644
index 0000000..d34546a
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u072_lookup.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayLong
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:25,0:40]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 8528
+ 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 \ No newline at end of file
diff --git a/systemtest/testdata/partialupdate/u072_lookup.ql.out b/systemtest/testdata/partialupdate/u072_lookup.ql.out
new file mode 100644
index 0000000..a873fb3
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u072_lookup.ql.out
@@ -0,0 +1,54 @@
+-- Testbed line: result_type=set <marray <ulong, [0:25,0:40]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <ulong, [0:25,0:40]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:25,0:40]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 4264
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4
+-- Testbed end block:
diff --git a/systemtest/testdata/partialupdate/u07_lookup.ql b/systemtest/testdata/partialupdate/u07_lookup.ql
new file mode 100644
index 0000000..bd885e9
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u07_lookup.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <ulong, [0:10,0:10]>>
+-- Testbed: result_elements=1
+
+SELECT a
+FROM PartialUpdate AS a
diff --git a/systemtest/testdata/partialupdate/u07_lookup.ql.java.out b/systemtest/testdata/partialupdate/u07_lookup.ql.java.out
new file mode 100644
index 0000000..d34546a
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u07_lookup.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayLong
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:25,0:40]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 8528
+ 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 \ No newline at end of file
diff --git a/systemtest/testdata/partialupdate/u07_lookup.ql.out b/systemtest/testdata/partialupdate/u07_lookup.ql.out
new file mode 100644
index 0000000..a873fb3
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u07_lookup.ql.out
@@ -0,0 +1,54 @@
+-- Testbed line: result_type=set <marray <ulong, [0:25,0:40]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <ulong, [0:25,0:40]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:25,0:40]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 4264
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4
+-- Testbed end block:
diff --git a/systemtest/testdata/partialupdate/u08_update.ql b/systemtest/testdata/partialupdate/u08_update.ql
new file mode 100644
index 0000000..943744b
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u08_update.ql
@@ -0,0 +1,15 @@
+UPDATE PartialUpdate AS image
+SET image ASSIGN < [40:50,40:50]
+ 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul;
+ 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul;
+ 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul;
+ 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul;
+ 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul;
+ 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul;
+ 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul;
+ 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul;
+ 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul;
+ 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul;
+ 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul, 5ul
+ >
+
diff --git a/systemtest/testdata/partialupdate/u08_update.ql.java.out b/systemtest/testdata/partialupdate/u08_update.ql.java.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u08_update.ql.java.out
diff --git a/systemtest/testdata/partialupdate/u08_update.ql.out b/systemtest/testdata/partialupdate/u08_update.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u08_update.ql.out
diff --git a/systemtest/testdata/partialupdate/u09_lookup.ql b/systemtest/testdata/partialupdate/u09_lookup.ql
new file mode 100644
index 0000000..bd885e9
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u09_lookup.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <ulong, [0:10,0:10]>>
+-- Testbed: result_elements=1
+
+SELECT a
+FROM PartialUpdate AS a
diff --git a/systemtest/testdata/partialupdate/u09_lookup.ql.java.out b/systemtest/testdata/partialupdate/u09_lookup.ql.java.out
new file mode 100644
index 0000000..c1f1ca9
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u09_lookup.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayLong
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:50,0:50]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 20808
+ 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 \ No newline at end of file
diff --git a/systemtest/testdata/partialupdate/u09_lookup.ql.out b/systemtest/testdata/partialupdate/u09_lookup.ql.out
new file mode 100644
index 0000000..8ba2601
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u09_lookup.ql.out
@@ -0,0 +1,64 @@
+-- Testbed line: result_type=set <marray <ulong, [0:50,0:50]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <ulong, [0:50,0:50]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:50,0:50]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 10404
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+-- Testbed end block:
diff --git a/systemtest/testdata/partialupdate/u10_update.ql b/systemtest/testdata/partialupdate/u10_update.ql
new file mode 100644
index 0000000..8dbb3ce
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u10_update.ql
@@ -0,0 +1,11 @@
+UPDATE PartialUpdate AS image
+SET image ASSIGN < [35:41,25:35]
+ 6ul, 6ul, 6ul, 6ul, 6ul, 6ul, 6ul, 6ul, 6ul, 6ul, 6ul;
+ 6ul, 6ul, 6ul, 6ul, 6ul, 6ul, 6ul, 6ul, 6ul, 6ul, 6ul;
+ 6ul, 6ul, 6ul, 6ul, 6ul, 6ul, 6ul, 6ul, 6ul, 6ul, 6ul;
+ 6ul, 6ul, 6ul, 6ul, 6ul, 6ul, 6ul, 6ul, 6ul, 6ul, 6ul;
+ 6ul, 6ul, 6ul, 6ul, 6ul, 6ul, 6ul, 6ul, 6ul, 6ul, 6ul;
+ 6ul, 6ul, 6ul, 6ul, 6ul, 6ul, 6ul, 6ul, 6ul, 6ul, 6ul;
+ 6ul, 6ul, 6ul, 6ul, 6ul, 6ul, 6ul, 6ul, 6ul, 6ul, 6ul
+ >
+
diff --git a/systemtest/testdata/partialupdate/u10_update.ql.java.out b/systemtest/testdata/partialupdate/u10_update.ql.java.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u10_update.ql.java.out
diff --git a/systemtest/testdata/partialupdate/u10_update.ql.out b/systemtest/testdata/partialupdate/u10_update.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u10_update.ql.out
diff --git a/systemtest/testdata/partialupdate/u11_lookup.ql b/systemtest/testdata/partialupdate/u11_lookup.ql
new file mode 100644
index 0000000..bd885e9
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u11_lookup.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <ulong, [0:10,0:10]>>
+-- Testbed: result_elements=1
+
+SELECT a
+FROM PartialUpdate AS a
diff --git a/systemtest/testdata/partialupdate/u11_lookup.ql.java.out b/systemtest/testdata/partialupdate/u11_lookup.ql.java.out
new file mode 100644
index 0000000..52f34a6
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u11_lookup.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayLong
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:50,0:50]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 20808
+ 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 \ No newline at end of file
diff --git a/systemtest/testdata/partialupdate/u11_lookup.ql.out b/systemtest/testdata/partialupdate/u11_lookup.ql.out
new file mode 100644
index 0000000..64787d1
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u11_lookup.ql.out
@@ -0,0 +1,64 @@
+-- Testbed line: result_type=set <marray <ulong, [0:50,0:50]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <ulong, [0:50,0:50]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:50,0:50]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 10404
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+-- Testbed end block:
diff --git a/systemtest/testdata/partialupdate/u12_update.ql b/systemtest/testdata/partialupdate/u12_update.ql
new file mode 100644
index 0000000..a24668d
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u12_update.ql
@@ -0,0 +1,9 @@
+UPDATE PartialUpdate AS image
+SET image ASSIGN < [28:32,28:32]
+ 7ul, 7ul, 7ul, 7ul, 7ul;
+ 7ul, 7ul, 7ul, 7ul, 7ul;
+ 7ul, 7ul, 7ul, 7ul, 7ul;
+ 7ul, 7ul, 7ul, 7ul, 7ul;
+ 7ul, 7ul, 7ul, 7ul, 7ul
+ >
+
diff --git a/systemtest/testdata/partialupdate/u12_update.ql.java.out b/systemtest/testdata/partialupdate/u12_update.ql.java.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u12_update.ql.java.out
diff --git a/systemtest/testdata/partialupdate/u12_update.ql.out b/systemtest/testdata/partialupdate/u12_update.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u12_update.ql.out
diff --git a/systemtest/testdata/partialupdate/u13_lookup.ql b/systemtest/testdata/partialupdate/u13_lookup.ql
new file mode 100644
index 0000000..bd885e9
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u13_lookup.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <ulong, [0:10,0:10]>>
+-- Testbed: result_elements=1
+
+SELECT a
+FROM PartialUpdate AS a
diff --git a/systemtest/testdata/partialupdate/u13_lookup.ql.java.out b/systemtest/testdata/partialupdate/u13_lookup.ql.java.out
new file mode 100644
index 0000000..e9dbf7f
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u13_lookup.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayLong
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:50,0:50]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 20808
+ 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 \ No newline at end of file
diff --git a/systemtest/testdata/partialupdate/u13_lookup.ql.out b/systemtest/testdata/partialupdate/u13_lookup.ql.out
new file mode 100644
index 0000000..d5df472
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u13_lookup.ql.out
@@ -0,0 +1,64 @@
+-- Testbed line: result_type=set <marray <ulong, [0:50,0:50]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <ulong, [0:50,0:50]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:50,0:50]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 10404
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 7 7 7 7 7 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 7 7 7 7 7 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 7 7 7 7 7 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 7 7 7 7 7 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 7 7 7 7 7 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+-- Testbed end block:
diff --git a/systemtest/testdata/partialupdate/u14_update.ql b/systemtest/testdata/partialupdate/u14_update.ql
new file mode 100644
index 0000000..1eb1655
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u14_update.ql
@@ -0,0 +1,5 @@
+UPDATE PartialUpdate AS image
+SET image ASSIGN < [40:40,0:10]
+ 8ul, 8ul, 8ul, 8ul, 8ul, 8ul, 8ul, 8ul, 8ul, 8ul, 8ul
+ >
+
diff --git a/systemtest/testdata/partialupdate/u14_update.ql.java.out b/systemtest/testdata/partialupdate/u14_update.ql.java.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u14_update.ql.java.out
diff --git a/systemtest/testdata/partialupdate/u14_update.ql.out b/systemtest/testdata/partialupdate/u14_update.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u14_update.ql.out
diff --git a/systemtest/testdata/partialupdate/u15_lookup.ql b/systemtest/testdata/partialupdate/u15_lookup.ql
new file mode 100644
index 0000000..bd885e9
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u15_lookup.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <ulong, [0:10,0:10]>>
+-- Testbed: result_elements=1
+
+SELECT a
+FROM PartialUpdate AS a
diff --git a/systemtest/testdata/partialupdate/u15_lookup.ql.java.out b/systemtest/testdata/partialupdate/u15_lookup.ql.java.out
new file mode 100644
index 0000000..12062df
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u15_lookup.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayLong
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:50,0:50]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 20808
+ 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 \ No newline at end of file
diff --git a/systemtest/testdata/partialupdate/u15_lookup.ql.out b/systemtest/testdata/partialupdate/u15_lookup.ql.out
new file mode 100644
index 0000000..84787f0
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u15_lookup.ql.out
@@ -0,0 +1,64 @@
+-- Testbed line: result_type=set <marray <ulong, [0:50,0:50]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <ulong, [0:50,0:50]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:50,0:50]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 10404
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 7 7 7 7 7 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 7 7 7 7 7 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 7 7 7 7 7 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 7 7 7 7 7 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 7 7 7 7 7 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+-- Testbed end block:
diff --git a/systemtest/testdata/partialupdate/u16_update.ql b/systemtest/testdata/partialupdate/u16_update.ql
new file mode 100644
index 0000000..0bf1bfa
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u16_update.ql
@@ -0,0 +1,15 @@
+UPDATE PartialUpdate AS image
+SET image ASSIGN < [40:50,11:11]
+ 9ul;
+ 9ul;
+ 9ul;
+ 9ul;
+ 9ul;
+ 9ul;
+ 9ul;
+ 9ul;
+ 9ul;
+ 9ul;
+ 9ul
+ >
+
diff --git a/systemtest/testdata/partialupdate/u16_update.ql.java.out b/systemtest/testdata/partialupdate/u16_update.ql.java.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u16_update.ql.java.out
diff --git a/systemtest/testdata/partialupdate/u16_update.ql.out b/systemtest/testdata/partialupdate/u16_update.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u16_update.ql.out
diff --git a/systemtest/testdata/partialupdate/u17_lookup.ql b/systemtest/testdata/partialupdate/u17_lookup.ql
new file mode 100644
index 0000000..bd885e9
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u17_lookup.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <ulong, [0:10,0:10]>>
+-- Testbed: result_elements=1
+
+SELECT a
+FROM PartialUpdate AS a
diff --git a/systemtest/testdata/partialupdate/u17_lookup.ql.java.out b/systemtest/testdata/partialupdate/u17_lookup.ql.java.out
new file mode 100644
index 0000000..0e316b6
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u17_lookup.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayLong
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:50,0:50]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 20808
+ 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 \ No newline at end of file
diff --git a/systemtest/testdata/partialupdate/u17_lookup.ql.out b/systemtest/testdata/partialupdate/u17_lookup.ql.out
new file mode 100644
index 0000000..bab95ef
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u17_lookup.ql.out
@@ -0,0 +1,64 @@
+-- Testbed line: result_type=set <marray <ulong, [0:50,0:50]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <ulong, [0:50,0:50]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:50,0:50]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 10404
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 9 9 9 9 9 9 9 9 9 9
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 7 7 7 7 7 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 7 7 7 7 7 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 7 7 7 7 7 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 7 7 7 7 7 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 7 7 7 7 7 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+-- Testbed end block:
diff --git a/systemtest/testdata/partialupdate/u18_update.ql b/systemtest/testdata/partialupdate/u18_update.ql
new file mode 100644
index 0000000..22ceb80
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u18_update.ql
@@ -0,0 +1,5 @@
+UPDATE PartialUpdate AS image
+SET image ASSIGN < [35:35,0:10]
+ 10ul, 10ul, 10ul, 10ul, 10ul, 10ul, 10ul, 10ul, 10ul, 10ul, 10ul
+ >
+
diff --git a/systemtest/testdata/partialupdate/u18_update.ql.java.out b/systemtest/testdata/partialupdate/u18_update.ql.java.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u18_update.ql.java.out
diff --git a/systemtest/testdata/partialupdate/u18_update.ql.out b/systemtest/testdata/partialupdate/u18_update.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u18_update.ql.out
diff --git a/systemtest/testdata/partialupdate/u19_lookup.ql b/systemtest/testdata/partialupdate/u19_lookup.ql
new file mode 100644
index 0000000..bd885e9
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u19_lookup.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <ulong, [0:10,0:10]>>
+-- Testbed: result_elements=1
+
+SELECT a
+FROM PartialUpdate AS a
diff --git a/systemtest/testdata/partialupdate/u19_lookup.ql.java.out b/systemtest/testdata/partialupdate/u19_lookup.ql.java.out
new file mode 100644
index 0000000..eb9d40a
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u19_lookup.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayLong
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:50,0:50]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 20808
+ 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 \ No newline at end of file
diff --git a/systemtest/testdata/partialupdate/u19_lookup.ql.out b/systemtest/testdata/partialupdate/u19_lookup.ql.out
new file mode 100644
index 0000000..7e9dc61
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u19_lookup.ql.out
@@ -0,0 +1,64 @@
+-- Testbed line: result_type=set <marray <ulong, [0:50,0:50]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <ulong, [0:50,0:50]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:50,0:50]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 10404
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 9 9 9 9 9 9 9 9 9 9
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 7 7 7 7 7 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 7 7 7 7 7 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 7 7 7 7 7 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 7 7 7 7 7 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 7 7 7 7 7 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+-- Testbed end block:
diff --git a/systemtest/testdata/partialupdate/u20_update.ql b/systemtest/testdata/partialupdate/u20_update.ql
new file mode 100644
index 0000000..0b99272
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u20_update.ql
@@ -0,0 +1,9 @@
+UPDATE PartialUpdate AS image
+SET image ASSIGN < [30:34,10:10]
+ 11ul;
+ 11ul;
+ 11ul;
+ 11ul;
+ 11ul
+ >
+
diff --git a/systemtest/testdata/partialupdate/u20_update.ql.java.out b/systemtest/testdata/partialupdate/u20_update.ql.java.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u20_update.ql.java.out
diff --git a/systemtest/testdata/partialupdate/u20_update.ql.out b/systemtest/testdata/partialupdate/u20_update.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u20_update.ql.out
diff --git a/systemtest/testdata/partialupdate/u21_lookup.ql b/systemtest/testdata/partialupdate/u21_lookup.ql
new file mode 100644
index 0000000..bd885e9
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u21_lookup.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <ulong, [0:10,0:10]>>
+-- Testbed: result_elements=1
+
+SELECT a
+FROM PartialUpdate AS a
diff --git a/systemtest/testdata/partialupdate/u21_lookup.ql.java.out b/systemtest/testdata/partialupdate/u21_lookup.ql.java.out
new file mode 100644
index 0000000..989c9c0
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u21_lookup.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayLong
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:50,0:50]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 20808
+ 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 \ No newline at end of file
diff --git a/systemtest/testdata/partialupdate/u21_lookup.ql.out b/systemtest/testdata/partialupdate/u21_lookup.ql.out
new file mode 100644
index 0000000..e617272
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u21_lookup.ql.out
@@ -0,0 +1,64 @@
+-- Testbed line: result_type=set <marray <ulong, [0:50,0:50]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <ulong, [0:50,0:50]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:50,0:50]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 10404
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 11 11 11 11 11 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 9 9 9 9 9 9 9 9 9 9
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 7 7 7 7 7 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 7 7 7 7 7 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 7 7 7 7 7 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 7 7 7 7 7 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 7 7 7 7 7 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+-- Testbed end block:
diff --git a/systemtest/testdata/partialupdate/u30_update.ql b/systemtest/testdata/partialupdate/u30_update.ql
new file mode 100644
index 0000000..e76d6fa
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u30_update.ql
@@ -0,0 +1,10 @@
+UPDATE PartialUpdate AS image
+SET image ASSIGN < [05:10,05:10]
+ 21ul, 21ul, 21ul, 21ul, 21ul, 21ul;
+ 21ul, 21ul, 21ul, 21ul, 21ul, 21ul;
+ 21ul, 21ul, 21ul, 21ul, 21ul, 21ul;
+ 21ul, 21ul, 21ul, 21ul, 21ul, 21ul;
+ 21ul, 21ul, 21ul, 21ul, 21ul, 21ul;
+ 21ul, 21ul, 21ul, 21ul, 21ul, 21ul
+ >
+
diff --git a/systemtest/testdata/partialupdate/u30_update.ql.java.out b/systemtest/testdata/partialupdate/u30_update.ql.java.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u30_update.ql.java.out
diff --git a/systemtest/testdata/partialupdate/u30_update.ql.out b/systemtest/testdata/partialupdate/u30_update.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u30_update.ql.out
diff --git a/systemtest/testdata/partialupdate/u31_lookup.ql b/systemtest/testdata/partialupdate/u31_lookup.ql
new file mode 100644
index 0000000..bd885e9
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u31_lookup.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <ulong, [0:10,0:10]>>
+-- Testbed: result_elements=1
+
+SELECT a
+FROM PartialUpdate AS a
diff --git a/systemtest/testdata/partialupdate/u31_lookup.ql.java.out b/systemtest/testdata/partialupdate/u31_lookup.ql.java.out
new file mode 100644
index 0000000..0cdad49
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u31_lookup.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayLong
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:50,0:50]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 20808
+ 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 \ No newline at end of file
diff --git a/systemtest/testdata/partialupdate/u31_lookup.ql.out b/systemtest/testdata/partialupdate/u31_lookup.ql.out
new file mode 100644
index 0000000..640b7ed
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u31_lookup.ql.out
@@ -0,0 +1,64 @@
+-- Testbed line: result_type=set <marray <ulong, [0:50,0:50]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <ulong, [0:50,0:50]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:50,0:50]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 10404
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 21 21 21 21 21 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 21 21 21 21 21 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 21 21 21 21 21 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 21 21 21 21 21 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 21 21 21 21 21 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 21 21 21 21 21 21 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 11 11 11 11 11 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 9 9 9 9 9 9 9 9 9 9
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 7 7 7 7 7 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 7 7 7 7 7 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 7 7 7 7 7 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 7 7 7 7 7 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 7 7 7 7 7 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+-- Testbed end block:
diff --git a/systemtest/testdata/partialupdate/u32_update.ql b/systemtest/testdata/partialupdate/u32_update.ql
new file mode 100644
index 0000000..b1a1ad7
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u32_update.ql
@@ -0,0 +1,15 @@
+UPDATE PartialUpdate AS image
+SET image ASSIGN < [15:25,12:45]
+ 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul;
+ 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul;
+ 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul;
+ 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul;
+ 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul;
+ 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul;
+ 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul;
+ 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul;
+ 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul;
+ 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul;
+ 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul, 22ul
+ >
+
diff --git a/systemtest/testdata/partialupdate/u32_update.ql.java.out b/systemtest/testdata/partialupdate/u32_update.ql.java.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u32_update.ql.java.out
diff --git a/systemtest/testdata/partialupdate/u32_update.ql.out b/systemtest/testdata/partialupdate/u32_update.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u32_update.ql.out
diff --git a/systemtest/testdata/partialupdate/u33_lookup.ql b/systemtest/testdata/partialupdate/u33_lookup.ql
new file mode 100644
index 0000000..bd885e9
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u33_lookup.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <ulong, [0:10,0:10]>>
+-- Testbed: result_elements=1
+
+SELECT a
+FROM PartialUpdate AS a
diff --git a/systemtest/testdata/partialupdate/u33_lookup.ql.java.out b/systemtest/testdata/partialupdate/u33_lookup.ql.java.out
new file mode 100644
index 0000000..6acc502
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u33_lookup.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayLong
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:50,0:50]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 20808
+ 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 \ No newline at end of file
diff --git a/systemtest/testdata/partialupdate/u33_lookup.ql.out b/systemtest/testdata/partialupdate/u33_lookup.ql.out
new file mode 100644
index 0000000..d2f2a3b
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u33_lookup.ql.out
@@ -0,0 +1,64 @@
+-- Testbed line: result_type=set <marray <ulong, [0:50,0:50]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <ulong, [0:50,0:50]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:50,0:50]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 10404
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 21 21 21 21 21 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 21 21 21 21 21 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 21 21 21 21 21 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 21 21 21 21 21 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 21 21 21 21 21 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 21 21 21 21 21 21 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 11 11 11 11 11 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 9 9 9 9 9 9 9 9 9 9
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 7 7 7 7 7 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 7 7 7 7 7 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 7 7 7 7 7 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 7 7 7 7 7 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 7 7 7 7 7 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+-- Testbed end block:
diff --git a/systemtest/testdata/partialupdate/u34_update.ql b/systemtest/testdata/partialupdate/u34_update.ql
new file mode 100644
index 0000000..68d7d8c
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u34_update.ql
@@ -0,0 +1,20 @@
+UPDATE PartialUpdate AS image
+SET image ASSIGN < [30:45,30:38]
+ 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul;
+ 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul;
+ 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul;
+ 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul;
+ 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul;
+ 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul;
+ 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul;
+ 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul;
+ 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul;
+ 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul;
+ 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul;
+ 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul;
+ 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul;
+ 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul;
+ 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul;
+ 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul, 23ul
+ >
+
diff --git a/systemtest/testdata/partialupdate/u34_update.ql.java.out b/systemtest/testdata/partialupdate/u34_update.ql.java.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u34_update.ql.java.out
diff --git a/systemtest/testdata/partialupdate/u34_update.ql.out b/systemtest/testdata/partialupdate/u34_update.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u34_update.ql.out
diff --git a/systemtest/testdata/partialupdate/u35_lookup.ql b/systemtest/testdata/partialupdate/u35_lookup.ql
new file mode 100644
index 0000000..bd885e9
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u35_lookup.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <ulong, [0:10,0:10]>>
+-- Testbed: result_elements=1
+
+SELECT a
+FROM PartialUpdate AS a
diff --git a/systemtest/testdata/partialupdate/u35_lookup.ql.java.out b/systemtest/testdata/partialupdate/u35_lookup.ql.java.out
new file mode 100644
index 0000000..0dd950c
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u35_lookup.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayLong
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:50,0:50]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 20808
+ 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 \ No newline at end of file
diff --git a/systemtest/testdata/partialupdate/u35_lookup.ql.out b/systemtest/testdata/partialupdate/u35_lookup.ql.out
new file mode 100644
index 0000000..9b0ca8c
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u35_lookup.ql.out
@@ -0,0 +1,64 @@
+-- Testbed line: result_type=set <marray <ulong, [0:50,0:50]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <ulong, [0:50,0:50]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:50,0:50]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 10404
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 21 21 21 21 21 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 21 21 21 21 21 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 21 21 21 21 21 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 21 21 21 21 21 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 21 21 21 21 21 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 21 21 21 21 21 21 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 11 11 11 11 11 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 9 9 9 9 9 9 9 9 9 9
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 7 7 7 7 7 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 7 7 7 7 7 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 7 7 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 7 7 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 7 7 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+-- Testbed end block:
diff --git a/systemtest/testdata/partialupdate/u36_update.ql b/systemtest/testdata/partialupdate/u36_update.ql
new file mode 100644
index 0000000..0efb774
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u36_update.ql
@@ -0,0 +1,10 @@
+UPDATE PartialUpdate AS image
+SET image ASSIGN < [40:45,40:45]
+ 24ul, 24ul, 24ul, 24ul, 24ul, 24ul;
+ 24ul, 24ul, 24ul, 24ul, 24ul, 24ul;
+ 24ul, 24ul, 24ul, 24ul, 24ul, 24ul;
+ 24ul, 24ul, 24ul, 24ul, 24ul, 24ul;
+ 24ul, 24ul, 24ul, 24ul, 24ul, 24ul;
+ 24ul, 24ul, 24ul, 24ul, 24ul, 24ul
+ >
+
diff --git a/systemtest/testdata/partialupdate/u36_update.ql.java.out b/systemtest/testdata/partialupdate/u36_update.ql.java.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u36_update.ql.java.out
diff --git a/systemtest/testdata/partialupdate/u36_update.ql.out b/systemtest/testdata/partialupdate/u36_update.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u36_update.ql.out
diff --git a/systemtest/testdata/partialupdate/u37_lookup.ql b/systemtest/testdata/partialupdate/u37_lookup.ql
new file mode 100644
index 0000000..bd885e9
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u37_lookup.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <ulong, [0:10,0:10]>>
+-- Testbed: result_elements=1
+
+SELECT a
+FROM PartialUpdate AS a
diff --git a/systemtest/testdata/partialupdate/u37_lookup.ql.java.out b/systemtest/testdata/partialupdate/u37_lookup.ql.java.out
new file mode 100644
index 0000000..b08c68e
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u37_lookup.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayLong
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:50,0:50]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 20808
+ 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 \ No newline at end of file
diff --git a/systemtest/testdata/partialupdate/u37_lookup.ql.out b/systemtest/testdata/partialupdate/u37_lookup.ql.out
new file mode 100644
index 0000000..777b7e2
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u37_lookup.ql.out
@@ -0,0 +1,64 @@
+-- Testbed line: result_type=set <marray <ulong, [0:50,0:50]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <ulong, [0:50,0:50]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:50,0:50]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 10404
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 21 21 21 21 21 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 21 21 21 21 21 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 21 21 21 21 21 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 21 21 21 21 21 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 21 21 21 21 21 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 21 21 21 21 21 21 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 11 11 11 11 11 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 9 9 9 9 9 9 9 9 9 9
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 7 7 7 7 7 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 7 7 7 7 7 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 7 7 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 7 7 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 7 7 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 24 24 24 24 24 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 24 24 24 24 24 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 24 24 24 24 24 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 24 24 24 24 24 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 24 24 24 24 24 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 24 24 24 24 24 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+-- Testbed end block:
diff --git a/systemtest/testdata/partialupdate/u38_update.ql b/systemtest/testdata/partialupdate/u38_update.ql
new file mode 100644
index 0000000..5678465
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u38_update.ql
@@ -0,0 +1,20 @@
+UPDATE PartialUpdate AS image
+SET image ASSIGN < [30:45,25:28]
+ 25ul, 25ul, 25ul, 25ul;
+ 25ul, 25ul, 25ul, 25ul;
+ 25ul, 25ul, 25ul, 25ul;
+ 25ul, 25ul, 25ul, 25ul;
+ 25ul, 25ul, 25ul, 25ul;
+ 25ul, 25ul, 25ul, 25ul;
+ 25ul, 25ul, 25ul, 25ul;
+ 25ul, 25ul, 25ul, 25ul;
+ 25ul, 25ul, 25ul, 25ul;
+ 25ul, 25ul, 25ul, 25ul;
+ 25ul, 25ul, 25ul, 25ul;
+ 25ul, 25ul, 25ul, 25ul;
+ 25ul, 25ul, 25ul, 25ul;
+ 25ul, 25ul, 25ul, 25ul;
+ 25ul, 25ul, 25ul, 25ul;
+ 25ul, 25ul, 25ul, 25ul
+ >
+
diff --git a/systemtest/testdata/partialupdate/u38_update.ql.java.out b/systemtest/testdata/partialupdate/u38_update.ql.java.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u38_update.ql.java.out
diff --git a/systemtest/testdata/partialupdate/u38_update.ql.out b/systemtest/testdata/partialupdate/u38_update.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u38_update.ql.out
diff --git a/systemtest/testdata/partialupdate/u39_lookup.ql b/systemtest/testdata/partialupdate/u39_lookup.ql
new file mode 100644
index 0000000..bd885e9
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u39_lookup.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <ulong, [0:10,0:10]>>
+-- Testbed: result_elements=1
+
+SELECT a
+FROM PartialUpdate AS a
diff --git a/systemtest/testdata/partialupdate/u39_lookup.ql.java.out b/systemtest/testdata/partialupdate/u39_lookup.ql.java.out
new file mode 100644
index 0000000..cb4319a
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u39_lookup.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayLong
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:50,0:50]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 20808
+ 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 \ No newline at end of file
diff --git a/systemtest/testdata/partialupdate/u39_lookup.ql.out b/systemtest/testdata/partialupdate/u39_lookup.ql.out
new file mode 100644
index 0000000..72b2fac
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u39_lookup.ql.out
@@ -0,0 +1,64 @@
+-- Testbed line: result_type=set <marray <ulong, [0:50,0:50]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <ulong, [0:50,0:50]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:50,0:50]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 10404
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 21 21 21 21 21 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 21 21 21 21 21 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 21 21 21 21 21 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 21 21 21 21 21 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 21 21 21 21 21 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 21 21 21 21 21 21 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 11 11 11 11 11 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 9 9 9 9 9 9 9 9 9 9
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 7 7 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 7 7 7 7 7 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 7 7 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 7 7 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 7 7 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 24 24 24 24 24 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 24 24 24 24 24 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 24 24 24 24 24 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 24 24 24 24 24 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 24 24 24 24 24 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 24 24 24 24 24 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+-- Testbed end block:
diff --git a/systemtest/testdata/partialupdate/u40_update.ql b/systemtest/testdata/partialupdate/u40_update.ql
new file mode 100644
index 0000000..305619a
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u40_update.ql
@@ -0,0 +1,7 @@
+UPDATE PartialUpdate AS image
+SET image ASSIGN < [39:41,9:11]
+ 26ul, 26ul, 26ul;
+ 26ul, 26ul, 26ul;
+ 26ul, 26ul, 26ul
+ >
+
diff --git a/systemtest/testdata/partialupdate/u40_update.ql.java.out b/systemtest/testdata/partialupdate/u40_update.ql.java.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u40_update.ql.java.out
diff --git a/systemtest/testdata/partialupdate/u40_update.ql.out b/systemtest/testdata/partialupdate/u40_update.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u40_update.ql.out
diff --git a/systemtest/testdata/partialupdate/u41_lookup.ql b/systemtest/testdata/partialupdate/u41_lookup.ql
new file mode 100644
index 0000000..bd885e9
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u41_lookup.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <ulong, [0:10,0:10]>>
+-- Testbed: result_elements=1
+
+SELECT a
+FROM PartialUpdate AS a
diff --git a/systemtest/testdata/partialupdate/u41_lookup.ql.java.out b/systemtest/testdata/partialupdate/u41_lookup.ql.java.out
new file mode 100644
index 0000000..c62661a
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u41_lookup.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayLong
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:50,0:50]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 20808
+ 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 26 0 0 0 0 0 0 0 26 0 0 0 0 0 0 0 26 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 26 0 0 0 0 0 0 0 26 0 0 0 0 0 0 0 26 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 26 0 0 0 0 0 0 0 26 0 0 0 0 0 0 0 26 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 \ No newline at end of file
diff --git a/systemtest/testdata/partialupdate/u41_lookup.ql.out b/systemtest/testdata/partialupdate/u41_lookup.ql.out
new file mode 100644
index 0000000..bd1eaf8
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u41_lookup.ql.out
@@ -0,0 +1,64 @@
+-- Testbed line: result_type=set <marray <ulong, [0:50,0:50]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <ulong, [0:50,0:50]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:50,0:50]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 10404
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 21 21 21 21 21 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 21 21 21 21 21 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 21 21 21 21 21 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 21 21 21 21 21 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 21 21 21 21 21 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 26 26 26 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 21 21 21 21 21 21 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 11 11 11 11 11 10 0 0 0 26 26 26 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 26 26 26 9 9 9 9 9 9 9 9 9
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 7 7 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 7 7 7 7 7 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 7 7 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 7 7 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 7 7 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 24 24 24 24 24 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 24 24 24 24 24 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 24 24 24 24 24 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 24 24 24 24 24 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 24 24 24 24 24 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 24 24 24 24 24 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+-- Testbed end block:
diff --git a/systemtest/testdata/partialupdate/u42_update.ql b/systemtest/testdata/partialupdate/u42_update.ql
new file mode 100644
index 0000000..1e379d7
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u42_update.ql
@@ -0,0 +1,7 @@
+UPDATE PartialUpdate AS image
+SET image ASSIGN < [34:36,9:11]
+ 27ul, 27ul, 27ul;
+ 27ul, 27ul, 27ul;
+ 27ul, 27ul, 27ul
+ >
+
diff --git a/systemtest/testdata/partialupdate/u42_update.ql.java.out b/systemtest/testdata/partialupdate/u42_update.ql.java.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u42_update.ql.java.out
diff --git a/systemtest/testdata/partialupdate/u42_update.ql.out b/systemtest/testdata/partialupdate/u42_update.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u42_update.ql.out
diff --git a/systemtest/testdata/partialupdate/u43_lookup.ql b/systemtest/testdata/partialupdate/u43_lookup.ql
new file mode 100644
index 0000000..bd885e9
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u43_lookup.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <ulong, [0:10,0:10]>>
+-- Testbed: result_elements=1
+
+SELECT a
+FROM PartialUpdate AS a
diff --git a/systemtest/testdata/partialupdate/u43_lookup.ql.java.out b/systemtest/testdata/partialupdate/u43_lookup.ql.java.out
new file mode 100644
index 0000000..b877ce2
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u43_lookup.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayLong
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:50,0:50]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 20808
+ 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 27 0 0 0 0 0 0 0 27 0 0 0 0 0 0 0 27 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 27 0 0 0 0 0 0 0 27 0 0 0 0 0 0 0 27 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 27 0 0 0 0 0 0 0 27 0 0 0 0 0 0 0 27 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 26 0 0 0 0 0 0 0 26 0 0 0 0 0 0 0 26 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 26 0 0 0 0 0 0 0 26 0 0 0 0 0 0 0 26 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 26 0 0 0 0 0 0 0 26 0 0 0 0 0 0 0 26 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 24 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 \ No newline at end of file
diff --git a/systemtest/testdata/partialupdate/u43_lookup.ql.out b/systemtest/testdata/partialupdate/u43_lookup.ql.out
new file mode 100644
index 0000000..8d8116e
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u43_lookup.ql.out
@@ -0,0 +1,64 @@
+-- Testbed line: result_type=set <marray <ulong, [0:50,0:50]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <ulong, [0:50,0:50]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:50,0:50]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 10404
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 21 21 21 21 21 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 21 21 21 21 21 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 21 21 21 21 21 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 21 21 21 21 21 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 21 21 21 21 21 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 27 27 27 0 0 26 26 26 0 0 0 0 0 0 0 0 0
+ 1 1 1 1 1 21 21 21 21 21 21 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 11 11 11 11 27 27 27 0 0 26 26 26 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 27 27 27 0 0 26 26 26 9 9 9 9 9 9 9 9 9
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 7 7 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 7 7 7 7 7 0 0 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 7 7 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 7 7 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 7 7 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 24 24 24 24 24 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 24 24 24 24 24 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 24 24 24 24 24 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 24 24 24 24 24 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 24 24 24 24 24 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 22 22 22 22 22 22 22 22 22 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 24 24 24 24 24 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5
+-- Testbed end block:
diff --git a/systemtest/testdata/partialupdate/u98_deletemdd.ql b/systemtest/testdata/partialupdate/u98_deletemdd.ql
new file mode 100644
index 0000000..2b37e5f
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u98_deletemdd.ql
@@ -0,0 +1,2 @@
+DELETE FROM PartialUpdate AS a
+WHERE true
diff --git a/systemtest/testdata/partialupdate/u98_deletemdd.ql.java.out b/systemtest/testdata/partialupdate/u98_deletemdd.ql.java.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u98_deletemdd.ql.java.out
diff --git a/systemtest/testdata/partialupdate/u98_deletemdd.ql.out b/systemtest/testdata/partialupdate/u98_deletemdd.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u98_deletemdd.ql.out
diff --git a/systemtest/testdata/partialupdate/u99_dropcoll.ql b/systemtest/testdata/partialupdate/u99_dropcoll.ql
new file mode 100644
index 0000000..ae73fd9
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u99_dropcoll.ql
@@ -0,0 +1 @@
+DROP COLLECTION PartialUpdate
diff --git a/systemtest/testdata/partialupdate/u99_dropcoll.ql.java.out b/systemtest/testdata/partialupdate/u99_dropcoll.ql.java.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u99_dropcoll.ql.java.out
diff --git a/systemtest/testdata/partialupdate/u99_dropcoll.ql.out b/systemtest/testdata/partialupdate/u99_dropcoll.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/partialupdate/u99_dropcoll.ql.out
diff --git a/systemtest/testdata/queryresult/boolean.ql b/systemtest/testdata/queryresult/boolean.ql
new file mode 100644
index 0000000..633889f
--- /dev/null
+++ b/systemtest/testdata/queryresult/boolean.ql
@@ -0,0 +1,2 @@
+select true
+from ImgCharA as a
diff --git a/systemtest/testdata/queryresult/boolean.ql.java.out b/systemtest/testdata/queryresult/boolean.ql.java.out
new file mode 100644
index 0000000..9d60796
--- /dev/null
+++ b/systemtest/testdata/queryresult/boolean.ql.java.out
@@ -0,0 +1 @@
+11 \ No newline at end of file
diff --git a/systemtest/testdata/queryresult/boolean.ql.out b/systemtest/testdata/queryresult/boolean.ql.out
new file mode 100644
index 0000000..89db772
--- /dev/null
+++ b/systemtest/testdata/queryresult/boolean.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<bool>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: T
+Element 2: T
+-- Testbed end block:
diff --git a/systemtest/testdata/queryresult/char.ql b/systemtest/testdata/queryresult/char.ql
new file mode 100644
index 0000000..0f4916d
--- /dev/null
+++ b/systemtest/testdata/queryresult/char.ql
@@ -0,0 +1,2 @@
+select 69c
+from ImgCharA as a
diff --git a/systemtest/testdata/queryresult/char.ql.java.out b/systemtest/testdata/queryresult/char.ql.java.out
new file mode 100644
index 0000000..b01cb97
--- /dev/null
+++ b/systemtest/testdata/queryresult/char.ql.java.out
@@ -0,0 +1 @@
+6969 \ No newline at end of file
diff --git a/systemtest/testdata/queryresult/char.ql.out b/systemtest/testdata/queryresult/char.ql.out
new file mode 100644
index 0000000..835b0f9
--- /dev/null
+++ b/systemtest/testdata/queryresult/char.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<char>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 69
+Element 2: 69
+-- Testbed end block:
diff --git a/systemtest/testdata/queryresult/double.ql b/systemtest/testdata/queryresult/double.ql
new file mode 100644
index 0000000..c1dd0a4
--- /dev/null
+++ b/systemtest/testdata/queryresult/double.ql
@@ -0,0 +1,2 @@
+select 1.9d
+from ImgCharA as a
diff --git a/systemtest/testdata/queryresult/double.ql.java.out b/systemtest/testdata/queryresult/double.ql.java.out
new file mode 100644
index 0000000..a926092
--- /dev/null
+++ b/systemtest/testdata/queryresult/double.ql.java.out
@@ -0,0 +1 @@
+1.91.9 \ No newline at end of file
diff --git a/systemtest/testdata/queryresult/double.ql.out b/systemtest/testdata/queryresult/double.ql.out
new file mode 100644
index 0000000..263963b
--- /dev/null
+++ b/systemtest/testdata/queryresult/double.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 1.9
+Element 2: 1.9
+-- Testbed end block:
diff --git a/systemtest/testdata/queryresult/float.ql b/systemtest/testdata/queryresult/float.ql
new file mode 100644
index 0000000..77fdb64
--- /dev/null
+++ b/systemtest/testdata/queryresult/float.ql
@@ -0,0 +1,2 @@
+select 1.9f
+from ImgCharA as a
diff --git a/systemtest/testdata/queryresult/float.ql.java.out b/systemtest/testdata/queryresult/float.ql.java.out
new file mode 100644
index 0000000..a926092
--- /dev/null
+++ b/systemtest/testdata/queryresult/float.ql.java.out
@@ -0,0 +1 @@
+1.91.9 \ No newline at end of file
diff --git a/systemtest/testdata/queryresult/float.ql.out b/systemtest/testdata/queryresult/float.ql.out
new file mode 100644
index 0000000..e5506ae
--- /dev/null
+++ b/systemtest/testdata/queryresult/float.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<float>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 1.9
+Element 2: 1.9
+-- Testbed end block:
diff --git a/systemtest/testdata/queryresult/long.ql b/systemtest/testdata/queryresult/long.ql
new file mode 100644
index 0000000..4605041
--- /dev/null
+++ b/systemtest/testdata/queryresult/long.ql
@@ -0,0 +1,2 @@
+select 1l
+from ImgCharA as a
diff --git a/systemtest/testdata/queryresult/long.ql.java.out b/systemtest/testdata/queryresult/long.ql.java.out
new file mode 100644
index 0000000..9d60796
--- /dev/null
+++ b/systemtest/testdata/queryresult/long.ql.java.out
@@ -0,0 +1 @@
+11 \ No newline at end of file
diff --git a/systemtest/testdata/queryresult/long.ql.out b/systemtest/testdata/queryresult/long.ql.out
new file mode 100644
index 0000000..5f11d14
--- /dev/null
+++ b/systemtest/testdata/queryresult/long.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<long>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 1
+Element 2: 1
+-- Testbed end block:
diff --git a/systemtest/testdata/queryresult/minterval.ql b/systemtest/testdata/queryresult/minterval.ql
new file mode 100644
index 0000000..057f5d4
--- /dev/null
+++ b/systemtest/testdata/queryresult/minterval.ql
@@ -0,0 +1,2 @@
+select [0:10,0:10,0:10]
+from ImgCharA as a
diff --git a/systemtest/testdata/queryresult/minterval.ql.java.out b/systemtest/testdata/queryresult/minterval.ql.java.out
new file mode 100644
index 0000000..72f4876
--- /dev/null
+++ b/systemtest/testdata/queryresult/minterval.ql.java.out
@@ -0,0 +1 @@
+[0:10,0:10,0:10][0:10,0:10,0:10] \ No newline at end of file
diff --git a/systemtest/testdata/queryresult/minterval.ql.out b/systemtest/testdata/queryresult/minterval.ql.out
new file mode 100644
index 0000000..c7c6c2e
--- /dev/null
+++ b/systemtest/testdata/queryresult/minterval.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<minterval>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: [0:10,0:10,0:10]
+Element 2: [0:10,0:10,0:10]
+-- Testbed end block:
diff --git a/systemtest/testdata/queryresult/octet.ql b/systemtest/testdata/queryresult/octet.ql
new file mode 100644
index 0000000..a593c5b
--- /dev/null
+++ b/systemtest/testdata/queryresult/octet.ql
@@ -0,0 +1,2 @@
+select 69o
+from ImgCharA as a
diff --git a/systemtest/testdata/queryresult/octet.ql.java.out b/systemtest/testdata/queryresult/octet.ql.java.out
new file mode 100644
index 0000000..b01cb97
--- /dev/null
+++ b/systemtest/testdata/queryresult/octet.ql.java.out
@@ -0,0 +1 @@
+6969 \ No newline at end of file
diff --git a/systemtest/testdata/queryresult/octet.ql.out b/systemtest/testdata/queryresult/octet.ql.out
new file mode 100644
index 0000000..ad82aab
--- /dev/null
+++ b/systemtest/testdata/queryresult/octet.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<octet>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 69
+Element 2: 69
+-- Testbed end block:
diff --git a/systemtest/testdata/queryresult/point.ql b/systemtest/testdata/queryresult/point.ql
new file mode 100644
index 0000000..b4ce3d9
--- /dev/null
+++ b/systemtest/testdata/queryresult/point.ql
@@ -0,0 +1,2 @@
+select [1,2,3,4,5]
+from ImgCharA as a
diff --git a/systemtest/testdata/queryresult/point.ql.java.out b/systemtest/testdata/queryresult/point.ql.java.out
new file mode 100644
index 0000000..e1bf7a2
--- /dev/null
+++ b/systemtest/testdata/queryresult/point.ql.java.out
@@ -0,0 +1 @@
+[1,2,3,4,5][1,2,3,4,5] \ No newline at end of file
diff --git a/systemtest/testdata/queryresult/point.ql.out b/systemtest/testdata/queryresult/point.ql.out
new file mode 100644
index 0000000..a9a3907
--- /dev/null
+++ b/systemtest/testdata/queryresult/point.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<point>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: [1,2,3,4,5]
+Element 2: [1,2,3,4,5]
+-- Testbed end block:
diff --git a/systemtest/testdata/queryresult/short.ql b/systemtest/testdata/queryresult/short.ql
new file mode 100644
index 0000000..717aa9a
--- /dev/null
+++ b/systemtest/testdata/queryresult/short.ql
@@ -0,0 +1,2 @@
+select 1s
+from ImgCharA as a
diff --git a/systemtest/testdata/queryresult/short.ql.java.out b/systemtest/testdata/queryresult/short.ql.java.out
new file mode 100644
index 0000000..9d60796
--- /dev/null
+++ b/systemtest/testdata/queryresult/short.ql.java.out
@@ -0,0 +1 @@
+11 \ No newline at end of file
diff --git a/systemtest/testdata/queryresult/short.ql.out b/systemtest/testdata/queryresult/short.ql.out
new file mode 100644
index 0000000..8d5ef87
--- /dev/null
+++ b/systemtest/testdata/queryresult/short.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<short>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 1
+Element 2: 1
+-- Testbed end block:
diff --git a/systemtest/testdata/queryresult/sinterval.ql b/systemtest/testdata/queryresult/sinterval.ql
new file mode 100644
index 0000000..0299f5e
--- /dev/null
+++ b/systemtest/testdata/queryresult/sinterval.ql
@@ -0,0 +1,2 @@
+select 5:10
+from ImgCharA as a
diff --git a/systemtest/testdata/queryresult/sinterval.ql.java.out b/systemtest/testdata/queryresult/sinterval.ql.java.out
new file mode 100644
index 0000000..450ec6f
--- /dev/null
+++ b/systemtest/testdata/queryresult/sinterval.ql.java.out
@@ -0,0 +1 @@
+5:105:10 \ No newline at end of file
diff --git a/systemtest/testdata/queryresult/sinterval.ql.out b/systemtest/testdata/queryresult/sinterval.ql.out
new file mode 100644
index 0000000..a29d4cd
--- /dev/null
+++ b/systemtest/testdata/queryresult/sinterval.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<interval>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 5:10
+Element 2: 5:10
+-- Testbed end block:
diff --git a/systemtest/testdata/queryresult/struct.ql b/systemtest/testdata/queryresult/struct.ql
new file mode 100644
index 0000000..dfbfd5c
--- /dev/null
+++ b/systemtest/testdata/queryresult/struct.ql
@@ -0,0 +1,2 @@
+select { 71c, 72c, 3s, 4s }
+from ImgCharA as a
diff --git a/systemtest/testdata/queryresult/struct.ql.java.out b/systemtest/testdata/queryresult/struct.ql.java.out
new file mode 100644
index 0000000..a5d28eb
--- /dev/null
+++ b/systemtest/testdata/queryresult/struct.ql.java.out
@@ -0,0 +1,16 @@
+
+ RasRuntimeException: Exception: Base type typeName:
+ typeID: 7
+ typeSize: 2
+struct
+{
+ typeName: RAS_CHAR
+ typeID: 18
+ typeSize: 1
+ 0,
+typeName: RAS_CHAR
+ typeID: 18
+ typeSize: 1
+ 1
+}
+ as ElementType is not supported yet. \ No newline at end of file
diff --git a/systemtest/testdata/queryresult/struct.ql.out b/systemtest/testdata/queryresult/struct.ql.out
new file mode 100644
index 0000000..d270999
--- /dev/null
+++ b/systemtest/testdata/queryresult/struct.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<struct { char 0, char 1, short 2, short 3 }>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: { 71, 72, 3, 4 }
+Element 2: { 71, 72, 3, 4 }
+-- Testbed end block:
diff --git a/systemtest/testdata/queryresult/ulong.ql b/systemtest/testdata/queryresult/ulong.ql
new file mode 100644
index 0000000..f20944f
--- /dev/null
+++ b/systemtest/testdata/queryresult/ulong.ql
@@ -0,0 +1,2 @@
+select 1ul
+from ImgCharA as a
diff --git a/systemtest/testdata/queryresult/ulong.ql.java.out b/systemtest/testdata/queryresult/ulong.ql.java.out
new file mode 100644
index 0000000..9d60796
--- /dev/null
+++ b/systemtest/testdata/queryresult/ulong.ql.java.out
@@ -0,0 +1 @@
+11 \ No newline at end of file
diff --git a/systemtest/testdata/queryresult/ulong.ql.out b/systemtest/testdata/queryresult/ulong.ql.out
new file mode 100644
index 0000000..832318d
--- /dev/null
+++ b/systemtest/testdata/queryresult/ulong.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<ulong>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 1
+Element 2: 1
+-- Testbed end block:
diff --git a/systemtest/testdata/queryresult/ushort.ql b/systemtest/testdata/queryresult/ushort.ql
new file mode 100644
index 0000000..f32aefa
--- /dev/null
+++ b/systemtest/testdata/queryresult/ushort.ql
@@ -0,0 +1,2 @@
+select 1us
+from ImgCharA as a
diff --git a/systemtest/testdata/queryresult/ushort.ql.java.out b/systemtest/testdata/queryresult/ushort.ql.java.out
new file mode 100644
index 0000000..9d60796
--- /dev/null
+++ b/systemtest/testdata/queryresult/ushort.ql.java.out
@@ -0,0 +1 @@
+11 \ No newline at end of file
diff --git a/systemtest/testdata/queryresult/ushort.ql.out b/systemtest/testdata/queryresult/ushort.ql.out
new file mode 100644
index 0000000..f4faee3
--- /dev/null
+++ b/systemtest/testdata/queryresult/ushort.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<ushort>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 1
+Element 2: 1
+-- Testbed end block:
diff --git a/systemtest/testdata/reduce/addcellschar.ql b/systemtest/testdata/reduce/addcellschar.ql
new file mode 100644
index 0000000..4cdd5fe
--- /dev/null
+++ b/systemtest/testdata/reduce/addcellschar.ql
@@ -0,0 +1,3 @@
+select marray x in [0:0] values (char)add_cells( a )
+from ImgCharA as a
+
diff --git a/systemtest/testdata/reduce/addcellschar.ql.java.out b/systemtest/testdata/reduce/addcellschar.ql.java.out
new file mode 100644
index 0000000..bb5d0a8
--- /dev/null
+++ b/systemtest/testdata/reduce/addcellschar.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 1
+ 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 1
+ 121 \ No newline at end of file
diff --git a/systemtest/testdata/reduce/addcellschar.ql.out b/systemtest/testdata/reduce/addcellschar.ql.out
new file mode 100644
index 0000000..c3c6efc
--- /dev/null
+++ b/systemtest/testdata/reduce/addcellschar.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <char, [0:0]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [0:0]>
+ Type Schema...........: marray< char >
+ Domain................: [0:0]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 1
+ 0
+Image 2
+GMarray
+ Type Structure........: marray <char, [0:0]>
+ Type Schema...........: marray< char >
+ Domain................: [0:0]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 1
+ 121
+-- Testbed end block:
diff --git a/systemtest/testdata/reduce/addcellsdouble.ql b/systemtest/testdata/reduce/addcellsdouble.ql
new file mode 100644
index 0000000..a460c9b
--- /dev/null
+++ b/systemtest/testdata/reduce/addcellsdouble.ql
@@ -0,0 +1,3 @@
+select marray x in [0:0] values add_cells( a*1d )
+from ImgCharA as a
+
diff --git a/systemtest/testdata/reduce/addcellsdouble.ql.java.out b/systemtest/testdata/reduce/addcellsdouble.ql.java.out
new file mode 100644
index 0000000..3ec8a71
--- /dev/null
+++ b/systemtest/testdata/reduce/addcellsdouble.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayDouble
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:15999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 0 0 0 0 0 0 0 0
+rasj.RasMArrayDouble
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:15999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 64 94 64 0 0 0 0 0 \ No newline at end of file
diff --git a/systemtest/testdata/reduce/addcellsdouble.ql.out b/systemtest/testdata/reduce/addcellsdouble.ql.out
new file mode 100644
index 0000000..af33e1d
--- /dev/null
+++ b/systemtest/testdata/reduce/addcellsdouble.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <double, [0:0]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <double, [0:0]>
+ Type Schema...........: marray< double >
+ Domain................: [0:0]
+ Base Type Schema......: double
+ Base Type Length......: 8
+ Data format.......... : Array
+ Data size (bytes).... : 8
+ 0
+Image 2
+GMarray
+ Type Structure........: marray <double, [0:0]>
+ Type Schema...........: marray< double >
+ Domain................: [0:0]
+ Base Type Schema......: double
+ Base Type Length......: 8
+ Data format.......... : Array
+ Data size (bytes).... : 8
+ 121
+-- Testbed end block:
diff --git a/systemtest/testdata/reduce/addcellsfloat.ql b/systemtest/testdata/reduce/addcellsfloat.ql
new file mode 100644
index 0000000..fd91e46
--- /dev/null
+++ b/systemtest/testdata/reduce/addcellsfloat.ql
@@ -0,0 +1,3 @@
+select marray x in [0:0] values (float)add_cells( a*1f )
+from ImgCharA as a
+
diff --git a/systemtest/testdata/reduce/addcellsfloat.ql.java.out b/systemtest/testdata/reduce/addcellsfloat.ql.java.out
new file mode 100644
index 0000000..7892cd0
--- /dev/null
+++ b/systemtest/testdata/reduce/addcellsfloat.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayFloat
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:31999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 4
+ 0 0 0 0
+rasj.RasMArrayFloat
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:31999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 4
+ 66 -14 0 0 \ No newline at end of file
diff --git a/systemtest/testdata/reduce/addcellsfloat.ql.out b/systemtest/testdata/reduce/addcellsfloat.ql.out
new file mode 100644
index 0000000..cd36146
--- /dev/null
+++ b/systemtest/testdata/reduce/addcellsfloat.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <float, [0:0]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <float, [0:0]>
+ Type Schema...........: marray< float >
+ Domain................: [0:0]
+ Base Type Schema......: float
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 4
+ 0
+Image 2
+GMarray
+ Type Structure........: marray <float, [0:0]>
+ Type Schema...........: marray< float >
+ Domain................: [0:0]
+ Base Type Schema......: float
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 4
+ 121
+-- Testbed end block:
diff --git a/systemtest/testdata/reduce/addcellslong.ql b/systemtest/testdata/reduce/addcellslong.ql
new file mode 100644
index 0000000..ec59db1
--- /dev/null
+++ b/systemtest/testdata/reduce/addcellslong.ql
@@ -0,0 +1,3 @@
+select marray x in [0:0] values add_cells( a*1l )
+from ImgCharA as a
+
diff --git a/systemtest/testdata/reduce/addcellslong.ql.java.out b/systemtest/testdata/reduce/addcellslong.ql.java.out
new file mode 100644
index 0000000..405c6e1
--- /dev/null
+++ b/systemtest/testdata/reduce/addcellslong.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayInteger
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:31999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 4
+ 0 0 0 0
+rasj.RasMArrayInteger
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:31999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 4
+ 0 0 0 121 \ No newline at end of file
diff --git a/systemtest/testdata/reduce/addcellslong.ql.out b/systemtest/testdata/reduce/addcellslong.ql.out
new file mode 100644
index 0000000..076ef00
--- /dev/null
+++ b/systemtest/testdata/reduce/addcellslong.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <long, [0:0]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <long, [0:0]>
+ Type Schema...........: marray< long >
+ Domain................: [0:0]
+ Base Type Schema......: long
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 4
+ 0
+Image 2
+GMarray
+ Type Structure........: marray <long, [0:0]>
+ Type Schema...........: marray< long >
+ Domain................: [0:0]
+ Base Type Schema......: long
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 4
+ 121
+-- Testbed end block:
diff --git a/systemtest/testdata/reduce/addcellsoctet.ql b/systemtest/testdata/reduce/addcellsoctet.ql
new file mode 100644
index 0000000..87e97d0
--- /dev/null
+++ b/systemtest/testdata/reduce/addcellsoctet.ql
@@ -0,0 +1,3 @@
+select marray x in [0:0] values (octet)add_cells( a*1o )
+from ImgCharA as a
+
diff --git a/systemtest/testdata/reduce/addcellsoctet.ql.java.out b/systemtest/testdata/reduce/addcellsoctet.ql.java.out
new file mode 100644
index 0000000..bb5d0a8
--- /dev/null
+++ b/systemtest/testdata/reduce/addcellsoctet.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 1
+ 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 1
+ 121 \ No newline at end of file
diff --git a/systemtest/testdata/reduce/addcellsoctet.ql.out b/systemtest/testdata/reduce/addcellsoctet.ql.out
new file mode 100644
index 0000000..3b8d71d
--- /dev/null
+++ b/systemtest/testdata/reduce/addcellsoctet.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <octet, [0:0]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <octet, [0:0]>
+ Type Schema...........: marray< octet >
+ Domain................: [0:0]
+ Base Type Schema......: octet
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 1
+ 0
+Image 2
+GMarray
+ Type Structure........: marray <octet, [0:0]>
+ Type Schema...........: marray< octet >
+ Domain................: [0:0]
+ Base Type Schema......: octet
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 1
+ 121
+-- Testbed end block:
diff --git a/systemtest/testdata/reduce/addcellsshort.ql b/systemtest/testdata/reduce/addcellsshort.ql
new file mode 100644
index 0000000..a2371f6
--- /dev/null
+++ b/systemtest/testdata/reduce/addcellsshort.ql
@@ -0,0 +1,3 @@
+select marray x in [0:0] values (short)add_cells( a*1s )
+from ImgCharA as a
+
diff --git a/systemtest/testdata/reduce/addcellsshort.ql.java.out b/systemtest/testdata/reduce/addcellsshort.ql.java.out
new file mode 100644
index 0000000..e90632e
--- /dev/null
+++ b/systemtest/testdata/reduce/addcellsshort.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayShort
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:63999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 2
+ Data format...........: 0
+ Data size (bytes).....: 2
+ 0 0
+rasj.RasMArrayShort
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:63999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 2
+ Data format...........: 0
+ Data size (bytes).....: 2
+ 0 121 \ No newline at end of file
diff --git a/systemtest/testdata/reduce/addcellsshort.ql.out b/systemtest/testdata/reduce/addcellsshort.ql.out
new file mode 100644
index 0000000..9f7979e
--- /dev/null
+++ b/systemtest/testdata/reduce/addcellsshort.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <short, [0:0]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <short, [0:0]>
+ Type Schema...........: marray< short >
+ Domain................: [0:0]
+ Base Type Schema......: short
+ Base Type Length......: 2
+ Data format.......... : Array
+ Data size (bytes).... : 2
+ 0
+Image 2
+GMarray
+ Type Structure........: marray <short, [0:0]>
+ Type Schema...........: marray< short >
+ Domain................: [0:0]
+ Base Type Schema......: short
+ Base Type Length......: 2
+ Data format.......... : Array
+ Data size (bytes).... : 2
+ 121
+-- Testbed end block:
diff --git a/systemtest/testdata/reduce/addcellsstruct.ql b/systemtest/testdata/reduce/addcellsstruct.ql
new file mode 100644
index 0000000..8f22d50
--- /dev/null
+++ b/systemtest/testdata/reduce/addcellsstruct.ql
@@ -0,0 +1,3 @@
+select marray x in [0:0] values add_cells( a*{1,1} )
+from ImgCharA as a
+
diff --git a/systemtest/testdata/reduce/addcellsstruct.ql.java.out b/systemtest/testdata/reduce/addcellsstruct.ql.java.out
new file mode 100644
index 0000000..95769c2
--- /dev/null
+++ b/systemtest/testdata/reduce/addcellsstruct.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasGMArray
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:15999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 0 0 0 0 0 0 0 0 \ No newline at end of file
diff --git a/systemtest/testdata/reduce/addcellsstruct.ql.out b/systemtest/testdata/reduce/addcellsstruct.ql.out
new file mode 100644
index 0000000..287bc81
--- /dev/null
+++ b/systemtest/testdata/reduce/addcellsstruct.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <struct { long 0, long 1 }, [0:0]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <struct { long 0, long 1 }, [0:0]>
+ Type Schema...........: marray< struct{ long 0, long 1 } >
+ Domain................: [0:0]
+ Base Type Schema......: struct{ long 0, long 1 }
+ Base Type Length......: 8
+ Data format.......... : Array
+ Data size (bytes).... : 8
+{ 0, 0}
+Image 2
+GMarray
+ Type Structure........: marray <struct { long 0, long 1 }, [0:0]>
+ Type Schema...........: marray< struct{ long 0, long 1 } >
+ Domain................: [0:0]
+ Base Type Schema......: struct{ long 0, long 1 }
+ Base Type Length......: 8
+ Data format.......... : Array
+ Data size (bytes).... : 8
+{ 121, 121}
+-- Testbed end block:
diff --git a/systemtest/testdata/reduce/addcellsulong.ql b/systemtest/testdata/reduce/addcellsulong.ql
new file mode 100644
index 0000000..525592a
--- /dev/null
+++ b/systemtest/testdata/reduce/addcellsulong.ql
@@ -0,0 +1,3 @@
+select marray x in [0:0] values add_cells( a*1ul )
+from ImgCharA as a
+
diff --git a/systemtest/testdata/reduce/addcellsulong.ql.java.out b/systemtest/testdata/reduce/addcellsulong.ql.java.out
new file mode 100644
index 0000000..39ec10d
--- /dev/null
+++ b/systemtest/testdata/reduce/addcellsulong.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayLong
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:15999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 0 0 0 0 0 0 0 0
+rasj.RasMArrayLong
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:15999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 0 0 0 0 0 0 0 121 \ No newline at end of file
diff --git a/systemtest/testdata/reduce/addcellsulong.ql.out b/systemtest/testdata/reduce/addcellsulong.ql.out
new file mode 100644
index 0000000..44a8e47
--- /dev/null
+++ b/systemtest/testdata/reduce/addcellsulong.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <ulong, [0:0]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <ulong, [0:0]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:0]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 4
+ 0
+Image 2
+GMarray
+ Type Structure........: marray <ulong, [0:0]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:0]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 4
+ 121
+-- Testbed end block:
diff --git a/systemtest/testdata/reduce/addcellsushort.ql b/systemtest/testdata/reduce/addcellsushort.ql
new file mode 100644
index 0000000..ff3c08d
--- /dev/null
+++ b/systemtest/testdata/reduce/addcellsushort.ql
@@ -0,0 +1,3 @@
+select marray x in [0:0] values (ushort)add_cells( a*1us )
+from ImgCharA as a
+
diff --git a/systemtest/testdata/reduce/addcellsushort.ql.java.out b/systemtest/testdata/reduce/addcellsushort.ql.java.out
new file mode 100644
index 0000000..405c6e1
--- /dev/null
+++ b/systemtest/testdata/reduce/addcellsushort.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayInteger
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:31999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 4
+ 0 0 0 0
+rasj.RasMArrayInteger
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:31999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 4
+ 0 0 0 121 \ No newline at end of file
diff --git a/systemtest/testdata/reduce/addcellsushort.ql.out b/systemtest/testdata/reduce/addcellsushort.ql.out
new file mode 100644
index 0000000..5fd6f75
--- /dev/null
+++ b/systemtest/testdata/reduce/addcellsushort.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <ushort, [0:0]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <ushort, [0:0]>
+ Type Schema...........: marray< ushort >
+ Domain................: [0:0]
+ Base Type Schema......: ushort
+ Base Type Length......: 2
+ Data format.......... : Array
+ Data size (bytes).... : 2
+ 0
+Image 2
+GMarray
+ Type Structure........: marray <ushort, [0:0]>
+ Type Schema...........: marray< ushort >
+ Domain................: [0:0]
+ Base Type Schema......: ushort
+ Base Type Length......: 2
+ Data format.......... : Array
+ Data size (bytes).... : 2
+ 121
+-- Testbed end block:
diff --git a/systemtest/testdata/reduce/avgcellschar.ql b/systemtest/testdata/reduce/avgcellschar.ql
new file mode 100644
index 0000000..a8a25a4
--- /dev/null
+++ b/systemtest/testdata/reduce/avgcellschar.ql
@@ -0,0 +1,3 @@
+select marray x in [0:0] values avg_cells( a[0:2, 0:2] )
+from ImgCharD as a
+
diff --git a/systemtest/testdata/reduce/avgcellschar.ql.java.out b/systemtest/testdata/reduce/avgcellschar.ql.java.out
new file mode 100644
index 0000000..f891225
--- /dev/null
+++ b/systemtest/testdata/reduce/avgcellschar.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayDouble
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:15999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 64 40 0 0 0 0 0 0 \ No newline at end of file
diff --git a/systemtest/testdata/reduce/avgcellschar.ql.out b/systemtest/testdata/reduce/avgcellschar.ql.out
new file mode 100644
index 0000000..dcc1a99
--- /dev/null
+++ b/systemtest/testdata/reduce/avgcellschar.ql.out
@@ -0,0 +1,14 @@
+-- Testbed line: result_type=set <marray <double, [0:0]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <double, [0:0]>
+ Type Schema...........: marray< double >
+ Domain................: [0:0]
+ Base Type Schema......: double
+ Base Type Length......: 8
+ Data format.......... : Array
+ Data size (bytes).... : 8
+ 12
+-- Testbed end block:
diff --git a/systemtest/testdata/reduce/avgcellsdouble.ql b/systemtest/testdata/reduce/avgcellsdouble.ql
new file mode 100644
index 0000000..8856397
--- /dev/null
+++ b/systemtest/testdata/reduce/avgcellsdouble.ql
@@ -0,0 +1,3 @@
+select marray x in [0:0] values avg_cells( a[0:2,0:2]*1d )
+from ImgCharD as a
+
diff --git a/systemtest/testdata/reduce/avgcellsdouble.ql.java.out b/systemtest/testdata/reduce/avgcellsdouble.ql.java.out
new file mode 100644
index 0000000..f891225
--- /dev/null
+++ b/systemtest/testdata/reduce/avgcellsdouble.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayDouble
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:15999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 64 40 0 0 0 0 0 0 \ No newline at end of file
diff --git a/systemtest/testdata/reduce/avgcellsdouble.ql.out b/systemtest/testdata/reduce/avgcellsdouble.ql.out
new file mode 100644
index 0000000..dcc1a99
--- /dev/null
+++ b/systemtest/testdata/reduce/avgcellsdouble.ql.out
@@ -0,0 +1,14 @@
+-- Testbed line: result_type=set <marray <double, [0:0]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <double, [0:0]>
+ Type Schema...........: marray< double >
+ Domain................: [0:0]
+ Base Type Schema......: double
+ Base Type Length......: 8
+ Data format.......... : Array
+ Data size (bytes).... : 8
+ 12
+-- Testbed end block:
diff --git a/systemtest/testdata/reduce/avgcellsfloat.ql b/systemtest/testdata/reduce/avgcellsfloat.ql
new file mode 100644
index 0000000..00e9bc5
--- /dev/null
+++ b/systemtest/testdata/reduce/avgcellsfloat.ql
@@ -0,0 +1,3 @@
+select marray x in [0:0] values avg_cells( a[0:2,0:2]*1f )
+from ImgCharD as a
+
diff --git a/systemtest/testdata/reduce/avgcellsfloat.ql.java.out b/systemtest/testdata/reduce/avgcellsfloat.ql.java.out
new file mode 100644
index 0000000..f891225
--- /dev/null
+++ b/systemtest/testdata/reduce/avgcellsfloat.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayDouble
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:15999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 64 40 0 0 0 0 0 0 \ No newline at end of file
diff --git a/systemtest/testdata/reduce/avgcellsfloat.ql.out b/systemtest/testdata/reduce/avgcellsfloat.ql.out
new file mode 100644
index 0000000..dcc1a99
--- /dev/null
+++ b/systemtest/testdata/reduce/avgcellsfloat.ql.out
@@ -0,0 +1,14 @@
+-- Testbed line: result_type=set <marray <double, [0:0]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <double, [0:0]>
+ Type Schema...........: marray< double >
+ Domain................: [0:0]
+ Base Type Schema......: double
+ Base Type Length......: 8
+ Data format.......... : Array
+ Data size (bytes).... : 8
+ 12
+-- Testbed end block:
diff --git a/systemtest/testdata/reduce/avgcellslong.ql b/systemtest/testdata/reduce/avgcellslong.ql
new file mode 100644
index 0000000..a2c4380
--- /dev/null
+++ b/systemtest/testdata/reduce/avgcellslong.ql
@@ -0,0 +1,3 @@
+select marray x in [0:0] values avg_cells( a[0:2,0:2]*1l )
+from ImgCharD as a
+
diff --git a/systemtest/testdata/reduce/avgcellslong.ql.java.out b/systemtest/testdata/reduce/avgcellslong.ql.java.out
new file mode 100644
index 0000000..f891225
--- /dev/null
+++ b/systemtest/testdata/reduce/avgcellslong.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayDouble
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:15999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 64 40 0 0 0 0 0 0 \ No newline at end of file
diff --git a/systemtest/testdata/reduce/avgcellslong.ql.out b/systemtest/testdata/reduce/avgcellslong.ql.out
new file mode 100644
index 0000000..dcc1a99
--- /dev/null
+++ b/systemtest/testdata/reduce/avgcellslong.ql.out
@@ -0,0 +1,14 @@
+-- Testbed line: result_type=set <marray <double, [0:0]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <double, [0:0]>
+ Type Schema...........: marray< double >
+ Domain................: [0:0]
+ Base Type Schema......: double
+ Base Type Length......: 8
+ Data format.......... : Array
+ Data size (bytes).... : 8
+ 12
+-- Testbed end block:
diff --git a/systemtest/testdata/reduce/avgcellsoctet.ql b/systemtest/testdata/reduce/avgcellsoctet.ql
new file mode 100644
index 0000000..da66278
--- /dev/null
+++ b/systemtest/testdata/reduce/avgcellsoctet.ql
@@ -0,0 +1,3 @@
+select marray x in [0:0] values avg_cells( a[0:2,0:2]*1o )
+from ImgCharD as a
+
diff --git a/systemtest/testdata/reduce/avgcellsoctet.ql.java.out b/systemtest/testdata/reduce/avgcellsoctet.ql.java.out
new file mode 100644
index 0000000..f891225
--- /dev/null
+++ b/systemtest/testdata/reduce/avgcellsoctet.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayDouble
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:15999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 64 40 0 0 0 0 0 0 \ No newline at end of file
diff --git a/systemtest/testdata/reduce/avgcellsoctet.ql.out b/systemtest/testdata/reduce/avgcellsoctet.ql.out
new file mode 100644
index 0000000..dcc1a99
--- /dev/null
+++ b/systemtest/testdata/reduce/avgcellsoctet.ql.out
@@ -0,0 +1,14 @@
+-- Testbed line: result_type=set <marray <double, [0:0]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <double, [0:0]>
+ Type Schema...........: marray< double >
+ Domain................: [0:0]
+ Base Type Schema......: double
+ Base Type Length......: 8
+ Data format.......... : Array
+ Data size (bytes).... : 8
+ 12
+-- Testbed end block:
diff --git a/systemtest/testdata/reduce/avgcellsshort.ql b/systemtest/testdata/reduce/avgcellsshort.ql
new file mode 100644
index 0000000..b5cf09d
--- /dev/null
+++ b/systemtest/testdata/reduce/avgcellsshort.ql
@@ -0,0 +1,3 @@
+select marray x in [0:0] values avg_cells( a[0:2,0:2]*1s )
+from ImgCharD as a
+
diff --git a/systemtest/testdata/reduce/avgcellsshort.ql.java.out b/systemtest/testdata/reduce/avgcellsshort.ql.java.out
new file mode 100644
index 0000000..f891225
--- /dev/null
+++ b/systemtest/testdata/reduce/avgcellsshort.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayDouble
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:15999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 64 40 0 0 0 0 0 0 \ No newline at end of file
diff --git a/systemtest/testdata/reduce/avgcellsshort.ql.out b/systemtest/testdata/reduce/avgcellsshort.ql.out
new file mode 100644
index 0000000..dcc1a99
--- /dev/null
+++ b/systemtest/testdata/reduce/avgcellsshort.ql.out
@@ -0,0 +1,14 @@
+-- Testbed line: result_type=set <marray <double, [0:0]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <double, [0:0]>
+ Type Schema...........: marray< double >
+ Domain................: [0:0]
+ Base Type Schema......: double
+ Base Type Length......: 8
+ Data format.......... : Array
+ Data size (bytes).... : 8
+ 12
+-- Testbed end block:
diff --git a/systemtest/testdata/reduce/avgcellsstruct.ql b/systemtest/testdata/reduce/avgcellsstruct.ql
new file mode 100644
index 0000000..c121dad
--- /dev/null
+++ b/systemtest/testdata/reduce/avgcellsstruct.ql
@@ -0,0 +1,3 @@
+select marray x in [0:0] values avg_cells( a[0:2,0:2]*{1,1} )
+from ImgCharD as a
+
diff --git a/systemtest/testdata/reduce/avgcellsstruct.ql.java.out b/systemtest/testdata/reduce/avgcellsstruct.ql.java.out
new file mode 100644
index 0000000..cabf973
--- /dev/null
+++ b/systemtest/testdata/reduce/avgcellsstruct.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasGMArray
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:7999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 16
+ Data format...........: 0
+ Data size (bytes).....: 16
+ 64 40 0 0 0 0 0 0 64 40 0 0 0 0 0 0 \ No newline at end of file
diff --git a/systemtest/testdata/reduce/avgcellsstruct.ql.out b/systemtest/testdata/reduce/avgcellsstruct.ql.out
new file mode 100644
index 0000000..898ec58
--- /dev/null
+++ b/systemtest/testdata/reduce/avgcellsstruct.ql.out
@@ -0,0 +1,14 @@
+-- Testbed line: result_type=set <marray <struct { double 0, double 1 }, [0:0]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <struct { double 0, double 1 }, [0:0]>
+ Type Schema...........: marray< struct{ double 0, double 1 } >
+ Domain................: [0:0]
+ Base Type Schema......: struct{ double 0, double 1 }
+ Base Type Length......: 16
+ Data format.......... : Array
+ Data size (bytes).... : 16
+{ 12, 12}
+-- Testbed end block:
diff --git a/systemtest/testdata/reduce/avgcellsulong.ql b/systemtest/testdata/reduce/avgcellsulong.ql
new file mode 100644
index 0000000..dd13d6b
--- /dev/null
+++ b/systemtest/testdata/reduce/avgcellsulong.ql
@@ -0,0 +1,3 @@
+select marray x in [0:0] values avg_cells( a[0:2,0:2]*1ul )
+from ImgCharD as a
+
diff --git a/systemtest/testdata/reduce/avgcellsulong.ql.java.out b/systemtest/testdata/reduce/avgcellsulong.ql.java.out
new file mode 100644
index 0000000..f891225
--- /dev/null
+++ b/systemtest/testdata/reduce/avgcellsulong.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayDouble
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:15999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 64 40 0 0 0 0 0 0 \ No newline at end of file
diff --git a/systemtest/testdata/reduce/avgcellsulong.ql.out b/systemtest/testdata/reduce/avgcellsulong.ql.out
new file mode 100644
index 0000000..dcc1a99
--- /dev/null
+++ b/systemtest/testdata/reduce/avgcellsulong.ql.out
@@ -0,0 +1,14 @@
+-- Testbed line: result_type=set <marray <double, [0:0]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <double, [0:0]>
+ Type Schema...........: marray< double >
+ Domain................: [0:0]
+ Base Type Schema......: double
+ Base Type Length......: 8
+ Data format.......... : Array
+ Data size (bytes).... : 8
+ 12
+-- Testbed end block:
diff --git a/systemtest/testdata/reduce/avgcellsushort.ql b/systemtest/testdata/reduce/avgcellsushort.ql
new file mode 100644
index 0000000..529f1a3
--- /dev/null
+++ b/systemtest/testdata/reduce/avgcellsushort.ql
@@ -0,0 +1,3 @@
+select marray x in [0:0] values avg_cells( a[0:2,0:2]*1us )
+from ImgCharD as a
+
diff --git a/systemtest/testdata/reduce/avgcellsushort.ql.java.out b/systemtest/testdata/reduce/avgcellsushort.ql.java.out
new file mode 100644
index 0000000..f891225
--- /dev/null
+++ b/systemtest/testdata/reduce/avgcellsushort.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayDouble
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:15999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 64 40 0 0 0 0 0 0 \ No newline at end of file
diff --git a/systemtest/testdata/reduce/avgcellsushort.ql.out b/systemtest/testdata/reduce/avgcellsushort.ql.out
new file mode 100644
index 0000000..dcc1a99
--- /dev/null
+++ b/systemtest/testdata/reduce/avgcellsushort.ql.out
@@ -0,0 +1,14 @@
+-- Testbed line: result_type=set <marray <double, [0:0]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <double, [0:0]>
+ Type Schema...........: marray< double >
+ Domain................: [0:0]
+ Base Type Schema......: double
+ Base Type Length......: 8
+ Data format.......... : Array
+ Data size (bytes).... : 8
+ 12
+-- Testbed end block:
diff --git a/systemtest/testdata/reduce/countcells.ql b/systemtest/testdata/reduce/countcells.ql
new file mode 100644
index 0000000..591ce39
--- /dev/null
+++ b/systemtest/testdata/reduce/countcells.ql
@@ -0,0 +1,3 @@
+select marray x in [0:0] values count_cells( a>=0 )
+from ImgCharA as a
+
diff --git a/systemtest/testdata/reduce/countcells.ql.java.out b/systemtest/testdata/reduce/countcells.ql.java.out
new file mode 100644
index 0000000..6e01fb6
--- /dev/null
+++ b/systemtest/testdata/reduce/countcells.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayLong
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:15999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 0 0 0 0 0 0 0 121
+rasj.RasMArrayLong
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:15999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 0 0 0 0 0 0 0 121 \ No newline at end of file
diff --git a/systemtest/testdata/reduce/countcells.ql.out b/systemtest/testdata/reduce/countcells.ql.out
new file mode 100644
index 0000000..5b55f5e
--- /dev/null
+++ b/systemtest/testdata/reduce/countcells.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <ulong, [0:0]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <ulong, [0:0]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:0]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 4
+ 121
+Image 2
+GMarray
+ Type Structure........: marray <ulong, [0:0]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:0]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 4
+ 121
+-- Testbed end block:
diff --git a/systemtest/testdata/reduce/maxcellschar.ql b/systemtest/testdata/reduce/maxcellschar.ql
new file mode 100644
index 0000000..849b5be
--- /dev/null
+++ b/systemtest/testdata/reduce/maxcellschar.ql
@@ -0,0 +1,3 @@
+select marray x in [0:0] values max_cells( a*1c )
+from ImgCharA as a
+
diff --git a/systemtest/testdata/reduce/maxcellschar.ql.java.out b/systemtest/testdata/reduce/maxcellschar.ql.java.out
new file mode 100644
index 0000000..1c2dc22
--- /dev/null
+++ b/systemtest/testdata/reduce/maxcellschar.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 1
+ 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 1
+ 1 \ No newline at end of file
diff --git a/systemtest/testdata/reduce/maxcellschar.ql.out b/systemtest/testdata/reduce/maxcellschar.ql.out
new file mode 100644
index 0000000..9afe5e7
--- /dev/null
+++ b/systemtest/testdata/reduce/maxcellschar.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <char, [0:0]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [0:0]>
+ Type Schema...........: marray< char >
+ Domain................: [0:0]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 1
+ 0
+Image 2
+GMarray
+ Type Structure........: marray <char, [0:0]>
+ Type Schema...........: marray< char >
+ Domain................: [0:0]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 1
+ 1
+-- Testbed end block:
diff --git a/systemtest/testdata/reduce/maxcellsdouble.ql b/systemtest/testdata/reduce/maxcellsdouble.ql
new file mode 100644
index 0000000..ca80e82
--- /dev/null
+++ b/systemtest/testdata/reduce/maxcellsdouble.ql
@@ -0,0 +1,3 @@
+select marray x in [0:0] values max_cells( a*1d )
+from ImgCharA as a
+
diff --git a/systemtest/testdata/reduce/maxcellsdouble.ql.java.out b/systemtest/testdata/reduce/maxcellsdouble.ql.java.out
new file mode 100644
index 0000000..92d0741
--- /dev/null
+++ b/systemtest/testdata/reduce/maxcellsdouble.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayDouble
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:15999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 0 0 0 0 0 0 0 0
+rasj.RasMArrayDouble
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:15999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 63 -16 0 0 0 0 0 0 \ No newline at end of file
diff --git a/systemtest/testdata/reduce/maxcellsdouble.ql.out b/systemtest/testdata/reduce/maxcellsdouble.ql.out
new file mode 100644
index 0000000..a73516d
--- /dev/null
+++ b/systemtest/testdata/reduce/maxcellsdouble.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <double, [0:0]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <double, [0:0]>
+ Type Schema...........: marray< double >
+ Domain................: [0:0]
+ Base Type Schema......: double
+ Base Type Length......: 8
+ Data format.......... : Array
+ Data size (bytes).... : 8
+ 0
+Image 2
+GMarray
+ Type Structure........: marray <double, [0:0]>
+ Type Schema...........: marray< double >
+ Domain................: [0:0]
+ Base Type Schema......: double
+ Base Type Length......: 8
+ Data format.......... : Array
+ Data size (bytes).... : 8
+ 1
+-- Testbed end block:
diff --git a/systemtest/testdata/reduce/maxcellsfloat.ql b/systemtest/testdata/reduce/maxcellsfloat.ql
new file mode 100644
index 0000000..362f66e
--- /dev/null
+++ b/systemtest/testdata/reduce/maxcellsfloat.ql
@@ -0,0 +1,3 @@
+select marray x in [0:0] values max_cells( a*1f )
+from ImgCharA as a
+
diff --git a/systemtest/testdata/reduce/maxcellsfloat.ql.java.out b/systemtest/testdata/reduce/maxcellsfloat.ql.java.out
new file mode 100644
index 0000000..37f3462
--- /dev/null
+++ b/systemtest/testdata/reduce/maxcellsfloat.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayFloat
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:31999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 4
+ 0 0 0 0
+rasj.RasMArrayFloat
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:31999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 4
+ 63 -128 0 0 \ No newline at end of file
diff --git a/systemtest/testdata/reduce/maxcellsfloat.ql.out b/systemtest/testdata/reduce/maxcellsfloat.ql.out
new file mode 100644
index 0000000..d0e80bb
--- /dev/null
+++ b/systemtest/testdata/reduce/maxcellsfloat.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <float, [0:0]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <float, [0:0]>
+ Type Schema...........: marray< float >
+ Domain................: [0:0]
+ Base Type Schema......: float
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 4
+ 0
+Image 2
+GMarray
+ Type Structure........: marray <float, [0:0]>
+ Type Schema...........: marray< float >
+ Domain................: [0:0]
+ Base Type Schema......: float
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 4
+ 1
+-- Testbed end block:
diff --git a/systemtest/testdata/reduce/maxcellslong.ql b/systemtest/testdata/reduce/maxcellslong.ql
new file mode 100644
index 0000000..883f41a
--- /dev/null
+++ b/systemtest/testdata/reduce/maxcellslong.ql
@@ -0,0 +1,3 @@
+select marray x in [0:0] values max_cells( a*1l )
+from ImgCharA as a
+
diff --git a/systemtest/testdata/reduce/maxcellslong.ql.java.out b/systemtest/testdata/reduce/maxcellslong.ql.java.out
new file mode 100644
index 0000000..2add3d4
--- /dev/null
+++ b/systemtest/testdata/reduce/maxcellslong.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayInteger
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:31999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 4
+ 0 0 0 0
+rasj.RasMArrayInteger
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:31999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 4
+ 0 0 0 1 \ No newline at end of file
diff --git a/systemtest/testdata/reduce/maxcellslong.ql.out b/systemtest/testdata/reduce/maxcellslong.ql.out
new file mode 100644
index 0000000..c0fd730
--- /dev/null
+++ b/systemtest/testdata/reduce/maxcellslong.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <long, [0:0]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <long, [0:0]>
+ Type Schema...........: marray< long >
+ Domain................: [0:0]
+ Base Type Schema......: long
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 4
+ 0
+Image 2
+GMarray
+ Type Structure........: marray <long, [0:0]>
+ Type Schema...........: marray< long >
+ Domain................: [0:0]
+ Base Type Schema......: long
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 4
+ 1
+-- Testbed end block:
diff --git a/systemtest/testdata/reduce/maxcellsoctet.ql b/systemtest/testdata/reduce/maxcellsoctet.ql
new file mode 100644
index 0000000..0506bd7
--- /dev/null
+++ b/systemtest/testdata/reduce/maxcellsoctet.ql
@@ -0,0 +1,3 @@
+select marray x in [0:0] values max_cells( a*1o )
+from ImgCharA as a
+
diff --git a/systemtest/testdata/reduce/maxcellsoctet.ql.java.out b/systemtest/testdata/reduce/maxcellsoctet.ql.java.out
new file mode 100644
index 0000000..1c2dc22
--- /dev/null
+++ b/systemtest/testdata/reduce/maxcellsoctet.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 1
+ 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 1
+ 1 \ No newline at end of file
diff --git a/systemtest/testdata/reduce/maxcellsoctet.ql.out b/systemtest/testdata/reduce/maxcellsoctet.ql.out
new file mode 100644
index 0000000..29bdfac
--- /dev/null
+++ b/systemtest/testdata/reduce/maxcellsoctet.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <octet, [0:0]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <octet, [0:0]>
+ Type Schema...........: marray< octet >
+ Domain................: [0:0]
+ Base Type Schema......: octet
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 1
+ 0
+Image 2
+GMarray
+ Type Structure........: marray <octet, [0:0]>
+ Type Schema...........: marray< octet >
+ Domain................: [0:0]
+ Base Type Schema......: octet
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 1
+ 1
+-- Testbed end block:
diff --git a/systemtest/testdata/reduce/maxcellsshort.ql b/systemtest/testdata/reduce/maxcellsshort.ql
new file mode 100644
index 0000000..b574171
--- /dev/null
+++ b/systemtest/testdata/reduce/maxcellsshort.ql
@@ -0,0 +1,3 @@
+select marray x in [0:0] values max_cells( a*1s )
+from ImgCharA as a
+
diff --git a/systemtest/testdata/reduce/maxcellsshort.ql.java.out b/systemtest/testdata/reduce/maxcellsshort.ql.java.out
new file mode 100644
index 0000000..aac1a90
--- /dev/null
+++ b/systemtest/testdata/reduce/maxcellsshort.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayShort
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:63999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 2
+ Data format...........: 0
+ Data size (bytes).....: 2
+ 0 0
+rasj.RasMArrayShort
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:63999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 2
+ Data format...........: 0
+ Data size (bytes).....: 2
+ 0 1 \ No newline at end of file
diff --git a/systemtest/testdata/reduce/maxcellsshort.ql.out b/systemtest/testdata/reduce/maxcellsshort.ql.out
new file mode 100644
index 0000000..50396af
--- /dev/null
+++ b/systemtest/testdata/reduce/maxcellsshort.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <short, [0:0]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <short, [0:0]>
+ Type Schema...........: marray< short >
+ Domain................: [0:0]
+ Base Type Schema......: short
+ Base Type Length......: 2
+ Data format.......... : Array
+ Data size (bytes).... : 2
+ 0
+Image 2
+GMarray
+ Type Structure........: marray <short, [0:0]>
+ Type Schema...........: marray< short >
+ Domain................: [0:0]
+ Base Type Schema......: short
+ Base Type Length......: 2
+ Data format.......... : Array
+ Data size (bytes).... : 2
+ 1
+-- Testbed end block:
diff --git a/systemtest/testdata/reduce/maxcellsstruct.ql b/systemtest/testdata/reduce/maxcellsstruct.ql
new file mode 100644
index 0000000..c38bf9a
--- /dev/null
+++ b/systemtest/testdata/reduce/maxcellsstruct.ql
@@ -0,0 +1,3 @@
+select marray x in [0:0] values max_cells( a*{1,1} )
+from ImgCharA as a
+
diff --git a/systemtest/testdata/reduce/maxcellsstruct.ql.java.out b/systemtest/testdata/reduce/maxcellsstruct.ql.java.out
new file mode 100644
index 0000000..95769c2
--- /dev/null
+++ b/systemtest/testdata/reduce/maxcellsstruct.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasGMArray
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:15999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 0 0 0 0 0 0 0 0 \ No newline at end of file
diff --git a/systemtest/testdata/reduce/maxcellsstruct.ql.out b/systemtest/testdata/reduce/maxcellsstruct.ql.out
new file mode 100644
index 0000000..a11892f
--- /dev/null
+++ b/systemtest/testdata/reduce/maxcellsstruct.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <struct { long 0, long 1 }, [0:0]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <struct { long 0, long 1 }, [0:0]>
+ Type Schema...........: marray< struct{ long 0, long 1 } >
+ Domain................: [0:0]
+ Base Type Schema......: struct{ long 0, long 1 }
+ Base Type Length......: 8
+ Data format.......... : Array
+ Data size (bytes).... : 8
+{ 0, 0}
+Image 2
+GMarray
+ Type Structure........: marray <struct { long 0, long 1 }, [0:0]>
+ Type Schema...........: marray< struct{ long 0, long 1 } >
+ Domain................: [0:0]
+ Base Type Schema......: struct{ long 0, long 1 }
+ Base Type Length......: 8
+ Data format.......... : Array
+ Data size (bytes).... : 8
+{ 1, 1}
+-- Testbed end block:
diff --git a/systemtest/testdata/reduce/maxcellsulong.ql b/systemtest/testdata/reduce/maxcellsulong.ql
new file mode 100644
index 0000000..b0176d9
--- /dev/null
+++ b/systemtest/testdata/reduce/maxcellsulong.ql
@@ -0,0 +1,3 @@
+select marray x in [0:0] values max_cells( a*1ul )
+from ImgCharA as a
+
diff --git a/systemtest/testdata/reduce/maxcellsulong.ql.java.out b/systemtest/testdata/reduce/maxcellsulong.ql.java.out
new file mode 100644
index 0000000..1819dba
--- /dev/null
+++ b/systemtest/testdata/reduce/maxcellsulong.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayLong
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:15999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 0 0 0 0 0 0 0 0
+rasj.RasMArrayLong
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:15999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 0 0 0 0 0 0 0 1 \ No newline at end of file
diff --git a/systemtest/testdata/reduce/maxcellsulong.ql.out b/systemtest/testdata/reduce/maxcellsulong.ql.out
new file mode 100644
index 0000000..fd766bf
--- /dev/null
+++ b/systemtest/testdata/reduce/maxcellsulong.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <ulong, [0:0]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <ulong, [0:0]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:0]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 4
+ 0
+Image 2
+GMarray
+ Type Structure........: marray <ulong, [0:0]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:0]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 4
+ 1
+-- Testbed end block:
diff --git a/systemtest/testdata/reduce/maxcellsushort.ql b/systemtest/testdata/reduce/maxcellsushort.ql
new file mode 100644
index 0000000..3133cb3
--- /dev/null
+++ b/systemtest/testdata/reduce/maxcellsushort.ql
@@ -0,0 +1,3 @@
+select marray x in [0:0] values max_cells( a*1us )
+from ImgCharA as a
+
diff --git a/systemtest/testdata/reduce/maxcellsushort.ql.java.out b/systemtest/testdata/reduce/maxcellsushort.ql.java.out
new file mode 100644
index 0000000..2add3d4
--- /dev/null
+++ b/systemtest/testdata/reduce/maxcellsushort.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayInteger
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:31999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 4
+ 0 0 0 0
+rasj.RasMArrayInteger
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:31999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 4
+ 0 0 0 1 \ No newline at end of file
diff --git a/systemtest/testdata/reduce/maxcellsushort.ql.out b/systemtest/testdata/reduce/maxcellsushort.ql.out
new file mode 100644
index 0000000..aadec84
--- /dev/null
+++ b/systemtest/testdata/reduce/maxcellsushort.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <ushort, [0:0]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <ushort, [0:0]>
+ Type Schema...........: marray< ushort >
+ Domain................: [0:0]
+ Base Type Schema......: ushort
+ Base Type Length......: 2
+ Data format.......... : Array
+ Data size (bytes).... : 2
+ 0
+Image 2
+GMarray
+ Type Structure........: marray <ushort, [0:0]>
+ Type Schema...........: marray< ushort >
+ Domain................: [0:0]
+ Base Type Schema......: ushort
+ Base Type Length......: 2
+ Data format.......... : Array
+ Data size (bytes).... : 2
+ 1
+-- Testbed end block:
diff --git a/systemtest/testdata/reduce/mincellschar.ql b/systemtest/testdata/reduce/mincellschar.ql
new file mode 100644
index 0000000..3b8fa91
--- /dev/null
+++ b/systemtest/testdata/reduce/mincellschar.ql
@@ -0,0 +1,3 @@
+select marray x in [0:0] values min_cells( a )
+from ImgCharA as a
+
diff --git a/systemtest/testdata/reduce/mincellschar.ql.java.out b/systemtest/testdata/reduce/mincellschar.ql.java.out
new file mode 100644
index 0000000..1c2dc22
--- /dev/null
+++ b/systemtest/testdata/reduce/mincellschar.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 1
+ 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 1
+ 1 \ No newline at end of file
diff --git a/systemtest/testdata/reduce/mincellschar.ql.out b/systemtest/testdata/reduce/mincellschar.ql.out
new file mode 100644
index 0000000..9afe5e7
--- /dev/null
+++ b/systemtest/testdata/reduce/mincellschar.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <char, [0:0]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [0:0]>
+ Type Schema...........: marray< char >
+ Domain................: [0:0]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 1
+ 0
+Image 2
+GMarray
+ Type Structure........: marray <char, [0:0]>
+ Type Schema...........: marray< char >
+ Domain................: [0:0]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 1
+ 1
+-- Testbed end block:
diff --git a/systemtest/testdata/reduce/mincellsdouble.ql b/systemtest/testdata/reduce/mincellsdouble.ql
new file mode 100644
index 0000000..6a5765f
--- /dev/null
+++ b/systemtest/testdata/reduce/mincellsdouble.ql
@@ -0,0 +1,3 @@
+select marray x in [0:0] values min_cells( a*1d )
+from ImgCharA as a
+
diff --git a/systemtest/testdata/reduce/mincellsdouble.ql.java.out b/systemtest/testdata/reduce/mincellsdouble.ql.java.out
new file mode 100644
index 0000000..92d0741
--- /dev/null
+++ b/systemtest/testdata/reduce/mincellsdouble.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayDouble
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:15999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 0 0 0 0 0 0 0 0
+rasj.RasMArrayDouble
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:15999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 63 -16 0 0 0 0 0 0 \ No newline at end of file
diff --git a/systemtest/testdata/reduce/mincellsdouble.ql.out b/systemtest/testdata/reduce/mincellsdouble.ql.out
new file mode 100644
index 0000000..a73516d
--- /dev/null
+++ b/systemtest/testdata/reduce/mincellsdouble.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <double, [0:0]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <double, [0:0]>
+ Type Schema...........: marray< double >
+ Domain................: [0:0]
+ Base Type Schema......: double
+ Base Type Length......: 8
+ Data format.......... : Array
+ Data size (bytes).... : 8
+ 0
+Image 2
+GMarray
+ Type Structure........: marray <double, [0:0]>
+ Type Schema...........: marray< double >
+ Domain................: [0:0]
+ Base Type Schema......: double
+ Base Type Length......: 8
+ Data format.......... : Array
+ Data size (bytes).... : 8
+ 1
+-- Testbed end block:
diff --git a/systemtest/testdata/reduce/mincellsfloat.ql b/systemtest/testdata/reduce/mincellsfloat.ql
new file mode 100644
index 0000000..29214b5
--- /dev/null
+++ b/systemtest/testdata/reduce/mincellsfloat.ql
@@ -0,0 +1,3 @@
+select marray x in [0:0] values min_cells( a*1f )
+from ImgCharA as a
+
diff --git a/systemtest/testdata/reduce/mincellsfloat.ql.java.out b/systemtest/testdata/reduce/mincellsfloat.ql.java.out
new file mode 100644
index 0000000..37f3462
--- /dev/null
+++ b/systemtest/testdata/reduce/mincellsfloat.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayFloat
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:31999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 4
+ 0 0 0 0
+rasj.RasMArrayFloat
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:31999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 4
+ 63 -128 0 0 \ No newline at end of file
diff --git a/systemtest/testdata/reduce/mincellsfloat.ql.out b/systemtest/testdata/reduce/mincellsfloat.ql.out
new file mode 100644
index 0000000..d0e80bb
--- /dev/null
+++ b/systemtest/testdata/reduce/mincellsfloat.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <float, [0:0]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <float, [0:0]>
+ Type Schema...........: marray< float >
+ Domain................: [0:0]
+ Base Type Schema......: float
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 4
+ 0
+Image 2
+GMarray
+ Type Structure........: marray <float, [0:0]>
+ Type Schema...........: marray< float >
+ Domain................: [0:0]
+ Base Type Schema......: float
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 4
+ 1
+-- Testbed end block:
diff --git a/systemtest/testdata/reduce/mincellslong.ql b/systemtest/testdata/reduce/mincellslong.ql
new file mode 100644
index 0000000..264c1bf
--- /dev/null
+++ b/systemtest/testdata/reduce/mincellslong.ql
@@ -0,0 +1,3 @@
+select marray x in [0:0] values min_cells( a*1l )
+from ImgCharA as a
+
diff --git a/systemtest/testdata/reduce/mincellslong.ql.java.out b/systemtest/testdata/reduce/mincellslong.ql.java.out
new file mode 100644
index 0000000..2add3d4
--- /dev/null
+++ b/systemtest/testdata/reduce/mincellslong.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayInteger
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:31999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 4
+ 0 0 0 0
+rasj.RasMArrayInteger
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:31999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 4
+ 0 0 0 1 \ No newline at end of file
diff --git a/systemtest/testdata/reduce/mincellslong.ql.out b/systemtest/testdata/reduce/mincellslong.ql.out
new file mode 100644
index 0000000..c0fd730
--- /dev/null
+++ b/systemtest/testdata/reduce/mincellslong.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <long, [0:0]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <long, [0:0]>
+ Type Schema...........: marray< long >
+ Domain................: [0:0]
+ Base Type Schema......: long
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 4
+ 0
+Image 2
+GMarray
+ Type Structure........: marray <long, [0:0]>
+ Type Schema...........: marray< long >
+ Domain................: [0:0]
+ Base Type Schema......: long
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 4
+ 1
+-- Testbed end block:
diff --git a/systemtest/testdata/reduce/mincellsoctet.ql.out b/systemtest/testdata/reduce/mincellsoctet.ql.out
new file mode 100644
index 0000000..05a9ea7
--- /dev/null
+++ b/systemtest/testdata/reduce/mincellsoctet.ql.out
@@ -0,0 +1,16 @@
+-- Testbed line: result_type=set <marray <octet, [0:0]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+ Domain : [0:0] and cell type length 1
+ Structure : marray <octet, [0:0]>
+ Base type .: octet
+ Data format : array
+ff
+Image 2
+ Domain : [0:0] and cell type length 1
+ Structure : marray <octet, [0:0]>
+ Base type .: octet
+ Data format : array
+ff
+-- Testbed end block:
diff --git a/systemtest/testdata/reduce/mincellsshort.ql b/systemtest/testdata/reduce/mincellsshort.ql
new file mode 100644
index 0000000..e8d03ce
--- /dev/null
+++ b/systemtest/testdata/reduce/mincellsshort.ql
@@ -0,0 +1,3 @@
+select marray x in [0:0] values min_cells( a*1s )
+from ImgCharA as a
+
diff --git a/systemtest/testdata/reduce/mincellsshort.ql.java.out b/systemtest/testdata/reduce/mincellsshort.ql.java.out
new file mode 100644
index 0000000..aac1a90
--- /dev/null
+++ b/systemtest/testdata/reduce/mincellsshort.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayShort
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:63999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 2
+ Data format...........: 0
+ Data size (bytes).....: 2
+ 0 0
+rasj.RasMArrayShort
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:63999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 2
+ Data format...........: 0
+ Data size (bytes).....: 2
+ 0 1 \ No newline at end of file
diff --git a/systemtest/testdata/reduce/mincellsshort.ql.out b/systemtest/testdata/reduce/mincellsshort.ql.out
new file mode 100644
index 0000000..50396af
--- /dev/null
+++ b/systemtest/testdata/reduce/mincellsshort.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <short, [0:0]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <short, [0:0]>
+ Type Schema...........: marray< short >
+ Domain................: [0:0]
+ Base Type Schema......: short
+ Base Type Length......: 2
+ Data format.......... : Array
+ Data size (bytes).... : 2
+ 0
+Image 2
+GMarray
+ Type Structure........: marray <short, [0:0]>
+ Type Schema...........: marray< short >
+ Domain................: [0:0]
+ Base Type Schema......: short
+ Base Type Length......: 2
+ Data format.......... : Array
+ Data size (bytes).... : 2
+ 1
+-- Testbed end block:
diff --git a/systemtest/testdata/reduce/mincellsstruct.ql b/systemtest/testdata/reduce/mincellsstruct.ql
new file mode 100644
index 0000000..7227033
--- /dev/null
+++ b/systemtest/testdata/reduce/mincellsstruct.ql
@@ -0,0 +1,3 @@
+select marray x in [0:0] values min_cells( a*{1,1} )
+from ImgCharA as a
+
diff --git a/systemtest/testdata/reduce/mincellsstruct.ql.java.out b/systemtest/testdata/reduce/mincellsstruct.ql.java.out
new file mode 100644
index 0000000..95769c2
--- /dev/null
+++ b/systemtest/testdata/reduce/mincellsstruct.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasGMArray
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:15999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 0 0 0 0 0 0 0 0 \ No newline at end of file
diff --git a/systemtest/testdata/reduce/mincellsstruct.ql.out b/systemtest/testdata/reduce/mincellsstruct.ql.out
new file mode 100644
index 0000000..a11892f
--- /dev/null
+++ b/systemtest/testdata/reduce/mincellsstruct.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <struct { long 0, long 1 }, [0:0]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <struct { long 0, long 1 }, [0:0]>
+ Type Schema...........: marray< struct{ long 0, long 1 } >
+ Domain................: [0:0]
+ Base Type Schema......: struct{ long 0, long 1 }
+ Base Type Length......: 8
+ Data format.......... : Array
+ Data size (bytes).... : 8
+{ 0, 0}
+Image 2
+GMarray
+ Type Structure........: marray <struct { long 0, long 1 }, [0:0]>
+ Type Schema...........: marray< struct{ long 0, long 1 } >
+ Domain................: [0:0]
+ Base Type Schema......: struct{ long 0, long 1 }
+ Base Type Length......: 8
+ Data format.......... : Array
+ Data size (bytes).... : 8
+{ 1, 1}
+-- Testbed end block:
diff --git a/systemtest/testdata/reduce/mincellsulong.ql b/systemtest/testdata/reduce/mincellsulong.ql
new file mode 100644
index 0000000..8eb51eb
--- /dev/null
+++ b/systemtest/testdata/reduce/mincellsulong.ql
@@ -0,0 +1,3 @@
+select marray x in [0:0] values min_cells( a*1ul )
+from ImgCharA as a
+
diff --git a/systemtest/testdata/reduce/mincellsulong.ql.java.out b/systemtest/testdata/reduce/mincellsulong.ql.java.out
new file mode 100644
index 0000000..1819dba
--- /dev/null
+++ b/systemtest/testdata/reduce/mincellsulong.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayLong
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:15999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 0 0 0 0 0 0 0 0
+rasj.RasMArrayLong
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:15999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 8
+ 0 0 0 0 0 0 0 1 \ No newline at end of file
diff --git a/systemtest/testdata/reduce/mincellsulong.ql.out b/systemtest/testdata/reduce/mincellsulong.ql.out
new file mode 100644
index 0000000..fd766bf
--- /dev/null
+++ b/systemtest/testdata/reduce/mincellsulong.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <ulong, [0:0]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <ulong, [0:0]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:0]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 4
+ 0
+Image 2
+GMarray
+ Type Structure........: marray <ulong, [0:0]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:0]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 4
+ 1
+-- Testbed end block:
diff --git a/systemtest/testdata/reduce/mincellsushort.ql b/systemtest/testdata/reduce/mincellsushort.ql
new file mode 100644
index 0000000..d278205
--- /dev/null
+++ b/systemtest/testdata/reduce/mincellsushort.ql
@@ -0,0 +1,3 @@
+select marray x in [0:0] values min_cells( a*1us )
+from ImgCharA as a
+
diff --git a/systemtest/testdata/reduce/mincellsushort.ql.java.out b/systemtest/testdata/reduce/mincellsushort.ql.java.out
new file mode 100644
index 0000000..2add3d4
--- /dev/null
+++ b/systemtest/testdata/reduce/mincellsushort.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayInteger
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:31999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 4
+ 0 0 0 0
+rasj.RasMArrayInteger
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:0]
+ TilingDomain..........: [0:31999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 4
+ 0 0 0 1 \ No newline at end of file
diff --git a/systemtest/testdata/reduce/mincellsushort.ql.out b/systemtest/testdata/reduce/mincellsushort.ql.out
new file mode 100644
index 0000000..aadec84
--- /dev/null
+++ b/systemtest/testdata/reduce/mincellsushort.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <ushort, [0:0]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <ushort, [0:0]>
+ Type Schema...........: marray< ushort >
+ Domain................: [0:0]
+ Base Type Schema......: ushort
+ Base Type Length......: 2
+ Data format.......... : Array
+ Data size (bytes).... : 2
+ 0
+Image 2
+GMarray
+ Type Structure........: marray <ushort, [0:0]>
+ Type Schema...........: marray< ushort >
+ Domain................: [0:0]
+ Base Type Schema......: ushort
+ Base Type Length......: 2
+ Data format.......... : Array
+ Data size (bytes).... : 2
+ 1
+-- Testbed end block:
diff --git a/systemtest/testdata/rewriteset1/pushdownall.ql b/systemtest/testdata/rewriteset1/pushdownall.ql
new file mode 100644
index 0000000..e868fc0
--- /dev/null
+++ b/systemtest/testdata/rewriteset1/pushdownall.ql
@@ -0,0 +1,7 @@
+-- all_cell( a and b ) -> all_cell( a ) and all_cell( b )
+
+SELECT a+b
+FROM ImgCharA as a, ImgCharB as b
+WHERE all_cell ( a > 0 and b > 10 )
+
+
diff --git a/systemtest/testdata/rewriteset1/pushdownall.ql.java.out b/systemtest/testdata/rewriteset1/pushdownall.ql.java.out
new file mode 100644
index 0000000..776212b
--- /dev/null
+++ b/systemtest/testdata/rewriteset1/pushdownall.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 \ No newline at end of file
diff --git a/systemtest/testdata/rewriteset1/pushdownall.ql.out b/systemtest/testdata/rewriteset1/pushdownall.ql.out
new file mode 100644
index 0000000..212bf48
--- /dev/null
+++ b/systemtest/testdata/rewriteset1/pushdownall.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <char, [0:10,0:10]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [0:10,0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ 21 21 21 21 21 21 21 21 21 21 21
+ 21 21 21 21 21 21 21 21 21 21 21
+ 21 21 21 21 21 21 21 21 21 21 21
+ 21 21 21 21 21 21 21 21 21 21 21
+ 21 21 21 21 21 21 21 21 21 21 21
+ 21 21 21 21 21 21 21 21 21 21 21
+ 21 21 21 21 21 21 21 21 21 21 21
+ 21 21 21 21 21 21 21 21 21 21 21
+ 21 21 21 21 21 21 21 21 21 21 21
+ 21 21 21 21 21 21 21 21 21 21 21
+ 21 21 21 21 21 21 21 21 21 21 21
+-- Testbed end block:
diff --git a/systemtest/testdata/rewriteset1/pushdownsome.ql b/systemtest/testdata/rewriteset1/pushdownsome.ql
new file mode 100644
index 0000000..a65fecc
--- /dev/null
+++ b/systemtest/testdata/rewriteset1/pushdownsome.ql
@@ -0,0 +1,7 @@
+-- some_cell( a or b ) -> some_cell( a ) or some_cell( b )
+
+SELECT a+b
+FROM ImgCharA as a, ImgCharB as b
+WHERE some_cell ( a > 0 OR b > 10 )
+
+
diff --git a/systemtest/testdata/rewriteset1/pushdownsome.ql.java.out b/systemtest/testdata/rewriteset1/pushdownsome.ql.java.out
new file mode 100644
index 0000000..f3b0f63
--- /dev/null
+++ b/systemtest/testdata/rewriteset1/pushdownsome.ql.java.out
@@ -0,0 +1,43 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 \ No newline at end of file
diff --git a/systemtest/testdata/rewriteset1/pushdownsome.ql.out b/systemtest/testdata/rewriteset1/pushdownsome.ql.out
new file mode 100644
index 0000000..20ccc3b
--- /dev/null
+++ b/systemtest/testdata/rewriteset1/pushdownsome.ql.out
@@ -0,0 +1,64 @@
+-- Testbed line: result_type=set <marray <char, [0:10,0:10]>>
+-- Testbed line: result_elements=3
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [0:10,0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ 11 11 11 11 11 11 11 11 11 11 11
+ 11 11 11 11 11 11 11 11 11 11 11
+ 11 11 11 11 11 11 11 11 11 11 11
+ 11 11 11 11 11 11 11 11 11 11 11
+ 11 11 11 11 11 11 11 11 11 11 11
+ 11 11 11 11 11 11 11 11 11 11 11
+ 11 11 11 11 11 11 11 11 11 11 11
+ 11 11 11 11 11 11 11 11 11 11 11
+ 11 11 11 11 11 11 11 11 11 11 11
+ 11 11 11 11 11 11 11 11 11 11 11
+ 11 11 11 11 11 11 11 11 11 11 11
+Image 2
+GMarray
+ Type Structure........: marray <char, [0:10,0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ 20 20 20 20 20 20 20 20 20 20 20
+ 20 20 20 20 20 20 20 20 20 20 20
+ 20 20 20 20 20 20 20 20 20 20 20
+ 20 20 20 20 20 20 20 20 20 20 20
+ 20 20 20 20 20 20 20 20 20 20 20
+ 20 20 20 20 20 20 20 20 20 20 20
+ 20 20 20 20 20 20 20 20 20 20 20
+ 20 20 20 20 20 20 20 20 20 20 20
+ 20 20 20 20 20 20 20 20 20 20 20
+ 20 20 20 20 20 20 20 20 20 20 20
+ 20 20 20 20 20 20 20 20 20 20 20
+Image 3
+GMarray
+ Type Structure........: marray <char, [0:10,0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ 21 21 21 21 21 21 21 21 21 21 21
+ 21 21 21 21 21 21 21 21 21 21 21
+ 21 21 21 21 21 21 21 21 21 21 21
+ 21 21 21 21 21 21 21 21 21 21 21
+ 21 21 21 21 21 21 21 21 21 21 21
+ 21 21 21 21 21 21 21 21 21 21 21
+ 21 21 21 21 21 21 21 21 21 21 21
+ 21 21 21 21 21 21 21 21 21 21 21
+ 21 21 21 21 21 21 21 21 21 21 21
+ 21 21 21 21 21 21 21 21 21 21 21
+ 21 21 21 21 21 21 21 21 21 21 21
+-- Testbed end block:
diff --git a/systemtest/testdata/testset1/agg1.ql b/systemtest/testdata/testset1/agg1.ql
new file mode 100644
index 0000000..9534f28
--- /dev/null
+++ b/systemtest/testdata/testset1/agg1.ql
@@ -0,0 +1,6 @@
+-- Testbed: result_type=set <marray <char, [0:10,0:10]>>
+-- Testbed: result_elements=1
+
+select a
+from ImgCharA as a
+where some_cell( a > 0 )
diff --git a/systemtest/testdata/testset1/agg1.ql.java.out b/systemtest/testdata/testset1/agg1.ql.java.out
new file mode 100644
index 0000000..ec9b48e
--- /dev/null
+++ b/systemtest/testdata/testset1/agg1.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 \ No newline at end of file
diff --git a/systemtest/testdata/testset1/agg1.ql.out b/systemtest/testdata/testset1/agg1.ql.out
new file mode 100644
index 0000000..6afbc1f
--- /dev/null
+++ b/systemtest/testdata/testset1/agg1.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <char, [0:10,0:10]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [0:10,0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+-- Testbed end block:
diff --git a/systemtest/testdata/testset1/agg2.ql b/systemtest/testdata/testset1/agg2.ql
new file mode 100644
index 0000000..27ef685
--- /dev/null
+++ b/systemtest/testdata/testset1/agg2.ql
@@ -0,0 +1,6 @@
+-- Testbed: result_type=set <marray <char, [0:10,0:10]>>
+-- Testbed: result_elements=2
+
+select a * b
+from ImgCharA as a, ImgCharB as b
+where some_cell( a*b > 0 )
diff --git a/systemtest/testdata/testset1/agg2.ql.java.out b/systemtest/testdata/testset1/agg2.ql.java.out
new file mode 100644
index 0000000..ac09ddd
--- /dev/null
+++ b/systemtest/testdata/testset1/agg2.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 \ No newline at end of file
diff --git a/systemtest/testdata/testset1/agg2.ql.out b/systemtest/testdata/testset1/agg2.ql.out
new file mode 100644
index 0000000..816708e
--- /dev/null
+++ b/systemtest/testdata/testset1/agg2.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <char, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [0:10,0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+Image 2
+GMarray
+ Type Structure........: marray <char, [0:10,0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ 20 20 20 20 20 20 20 20 20 20 20
+ 20 20 20 20 20 20 20 20 20 20 20
+ 20 20 20 20 20 20 20 20 20 20 20
+ 20 20 20 20 20 20 20 20 20 20 20
+ 20 20 20 20 20 20 20 20 20 20 20
+ 20 20 20 20 20 20 20 20 20 20 20
+ 20 20 20 20 20 20 20 20 20 20 20
+ 20 20 20 20 20 20 20 20 20 20 20
+ 20 20 20 20 20 20 20 20 20 20 20
+ 20 20 20 20 20 20 20 20 20 20 20
+ 20 20 20 20 20 20 20 20 20 20 20
+-- Testbed end block:
diff --git a/systemtest/testdata/testset1/agg3.ql b/systemtest/testdata/testset1/agg3.ql
new file mode 100644
index 0000000..9833e16
--- /dev/null
+++ b/systemtest/testdata/testset1/agg3.ql
@@ -0,0 +1,6 @@
+-- Testbed: result_type=set <marray <long, [0:10,0:10]>>
+-- Testbed: result_elements=4
+
+select (a+2)*(b+1)
+from ImgCharA as a, ImgCharB as b
+where some_cell( (a+2)*(b+1) > 0 )
diff --git a/systemtest/testdata/testset1/agg3.ql.java.out b/systemtest/testdata/testset1/agg3.ql.java.out
new file mode 100644
index 0000000..aff941e
--- /dev/null
+++ b/systemtest/testdata/testset1/agg3.ql.java.out
@@ -0,0 +1,57 @@
+
+rasj.RasMArrayInteger
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:177,0:177]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 484
+ 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22
+rasj.RasMArrayInteger
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:177,0:177]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 484
+ 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33
+rasj.RasMArrayInteger
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:177,0:177]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 484
+ 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42
+rasj.RasMArrayInteger
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:177,0:177]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 484
+ 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 \ No newline at end of file
diff --git a/systemtest/testdata/testset1/agg3.ql.out b/systemtest/testdata/testset1/agg3.ql.out
new file mode 100644
index 0000000..14fa211
--- /dev/null
+++ b/systemtest/testdata/testset1/agg3.ql.out
@@ -0,0 +1,84 @@
+-- Testbed line: result_type=set <marray <long, [0:10,0:10]>>
+-- Testbed line: result_elements=4
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <long, [0:10,0:10]>
+ Type Schema...........: marray< long >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: long
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 484
+ 22 22 22 22 22 22 22 22 22 22 22
+ 22 22 22 22 22 22 22 22 22 22 22
+ 22 22 22 22 22 22 22 22 22 22 22
+ 22 22 22 22 22 22 22 22 22 22 22
+ 22 22 22 22 22 22 22 22 22 22 22
+ 22 22 22 22 22 22 22 22 22 22 22
+ 22 22 22 22 22 22 22 22 22 22 22
+ 22 22 22 22 22 22 22 22 22 22 22
+ 22 22 22 22 22 22 22 22 22 22 22
+ 22 22 22 22 22 22 22 22 22 22 22
+ 22 22 22 22 22 22 22 22 22 22 22
+Image 2
+GMarray
+ Type Structure........: marray <long, [0:10,0:10]>
+ Type Schema...........: marray< long >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: long
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 484
+ 33 33 33 33 33 33 33 33 33 33 33
+ 33 33 33 33 33 33 33 33 33 33 33
+ 33 33 33 33 33 33 33 33 33 33 33
+ 33 33 33 33 33 33 33 33 33 33 33
+ 33 33 33 33 33 33 33 33 33 33 33
+ 33 33 33 33 33 33 33 33 33 33 33
+ 33 33 33 33 33 33 33 33 33 33 33
+ 33 33 33 33 33 33 33 33 33 33 33
+ 33 33 33 33 33 33 33 33 33 33 33
+ 33 33 33 33 33 33 33 33 33 33 33
+ 33 33 33 33 33 33 33 33 33 33 33
+Image 3
+GMarray
+ Type Structure........: marray <long, [0:10,0:10]>
+ Type Schema...........: marray< long >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: long
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 484
+ 42 42 42 42 42 42 42 42 42 42 42
+ 42 42 42 42 42 42 42 42 42 42 42
+ 42 42 42 42 42 42 42 42 42 42 42
+ 42 42 42 42 42 42 42 42 42 42 42
+ 42 42 42 42 42 42 42 42 42 42 42
+ 42 42 42 42 42 42 42 42 42 42 42
+ 42 42 42 42 42 42 42 42 42 42 42
+ 42 42 42 42 42 42 42 42 42 42 42
+ 42 42 42 42 42 42 42 42 42 42 42
+ 42 42 42 42 42 42 42 42 42 42 42
+ 42 42 42 42 42 42 42 42 42 42 42
+Image 4
+GMarray
+ Type Structure........: marray <long, [0:10,0:10]>
+ Type Schema...........: marray< long >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: long
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 484
+ 63 63 63 63 63 63 63 63 63 63 63
+ 63 63 63 63 63 63 63 63 63 63 63
+ 63 63 63 63 63 63 63 63 63 63 63
+ 63 63 63 63 63 63 63 63 63 63 63
+ 63 63 63 63 63 63 63 63 63 63 63
+ 63 63 63 63 63 63 63 63 63 63 63
+ 63 63 63 63 63 63 63 63 63 63 63
+ 63 63 63 63 63 63 63 63 63 63 63
+ 63 63 63 63 63 63 63 63 63 63 63
+ 63 63 63 63 63 63 63 63 63 63 63
+ 63 63 63 63 63 63 63 63 63 63 63
+-- Testbed end block:
diff --git a/systemtest/testdata/testset1/dot1.ql b/systemtest/testdata/testset1/dot1.ql
new file mode 100644
index 0000000..4ae5b39
--- /dev/null
+++ b/systemtest/testdata/testset1/dot1.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <long, [0:10,0:10]>>
+-- Testbed: result_elements=2
+
+select a * { 5l, 10l, true }.1
+from ImgCharA as a
diff --git a/systemtest/testdata/testset1/dot1.ql.java.out b/systemtest/testdata/testset1/dot1.ql.java.out
new file mode 100644
index 0000000..063c356
--- /dev/null
+++ b/systemtest/testdata/testset1/dot1.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayInteger
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:177,0:177]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 484
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+rasj.RasMArrayInteger
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:177,0:177]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 484
+ 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 \ No newline at end of file
diff --git a/systemtest/testdata/testset1/dot1.ql.out b/systemtest/testdata/testset1/dot1.ql.out
new file mode 100644
index 0000000..1fb429d
--- /dev/null
+++ b/systemtest/testdata/testset1/dot1.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <long, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <long, [0:10,0:10]>
+ Type Schema...........: marray< long >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: long
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 484
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+Image 2
+GMarray
+ Type Structure........: marray <long, [0:10,0:10]>
+ Type Schema...........: marray< long >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: long
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 484
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+-- Testbed end block:
diff --git a/systemtest/testdata/testset1/dot2.ql b/systemtest/testdata/testset1/dot2.ql
new file mode 100644
index 0000000..b0470f4
--- /dev/null
+++ b/systemtest/testdata/testset1/dot2.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <float, [0:10,0:10]>>
+-- Testbed: result_elements=2
+
+select a * ({ 10l, { 8ul, 10f, 10.0 }}.1).2
+from ImgCharA as a
diff --git a/systemtest/testdata/testset1/dot2.ql.java.out b/systemtest/testdata/testset1/dot2.ql.java.out
new file mode 100644
index 0000000..1a89a0b
--- /dev/null
+++ b/systemtest/testdata/testset1/dot2.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayFloat
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:177,0:177]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 484
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+rasj.RasMArrayFloat
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:177,0:177]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 484
+ 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 65 32 0 0 \ No newline at end of file
diff --git a/systemtest/testdata/testset1/dot2.ql.out b/systemtest/testdata/testset1/dot2.ql.out
new file mode 100644
index 0000000..8bfe824
--- /dev/null
+++ b/systemtest/testdata/testset1/dot2.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <float, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <float, [0:10,0:10]>
+ Type Schema...........: marray< float >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: float
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 484
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+Image 2
+GMarray
+ Type Structure........: marray <float, [0:10,0:10]>
+ Type Schema...........: marray< float >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: float
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 484
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+-- Testbed end block:
diff --git a/systemtest/testdata/testset1/dot3.ql b/systemtest/testdata/testset1/dot3.ql
new file mode 100644
index 0000000..558643a
--- /dev/null
+++ b/systemtest/testdata/testset1/dot3.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <octet, [0:10,0:10]>>
+-- Testbed: result_elements=2
+
+select a * ({1l,2o}+{3l,4o}).1
+from ImgCharA as a
diff --git a/systemtest/testdata/testset1/dot3.ql.java.out b/systemtest/testdata/testset1/dot3.ql.java.out
new file mode 100644
index 0000000..7cfff06
--- /dev/null
+++ b/systemtest/testdata/testset1/dot3.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 \ No newline at end of file
diff --git a/systemtest/testdata/testset1/dot3.ql.out b/systemtest/testdata/testset1/dot3.ql.out
new file mode 100644
index 0000000..c6f0ef5
--- /dev/null
+++ b/systemtest/testdata/testset1/dot3.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <octet, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <octet, [0:10,0:10]>
+ Type Schema...........: marray< octet >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: octet
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+Image 2
+GMarray
+ Type Structure........: marray <octet, [0:10,0:10]>
+ Type Schema...........: marray< octet >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: octet
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ 6 6 6 6 6 6 6 6 6 6 6
+ 6 6 6 6 6 6 6 6 6 6 6
+ 6 6 6 6 6 6 6 6 6 6 6
+ 6 6 6 6 6 6 6 6 6 6 6
+ 6 6 6 6 6 6 6 6 6 6 6
+ 6 6 6 6 6 6 6 6 6 6 6
+ 6 6 6 6 6 6 6 6 6 6 6
+ 6 6 6 6 6 6 6 6 6 6 6
+ 6 6 6 6 6 6 6 6 6 6 6
+ 6 6 6 6 6 6 6 6 6 6 6
+ 6 6 6 6 6 6 6 6 6 6 6
+-- Testbed end block:
diff --git a/systemtest/testdata/testset1/dot4.ql b/systemtest/testdata/testset1/dot4.ql
new file mode 100644
index 0000000..58ba945
--- /dev/null
+++ b/systemtest/testdata/testset1/dot4.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <long, [0:10,0:10]>>
+-- Testbed: result_elements=2
+
+select a * ({ 1l, { 8l, 10l, 10l }}.1).2
+from ImgCharA as a
diff --git a/systemtest/testdata/testset1/dot4.ql.java.out b/systemtest/testdata/testset1/dot4.ql.java.out
new file mode 100644
index 0000000..063c356
--- /dev/null
+++ b/systemtest/testdata/testset1/dot4.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayInteger
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:177,0:177]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 484
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+rasj.RasMArrayInteger
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:177,0:177]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 484
+ 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 0 0 0 10 \ No newline at end of file
diff --git a/systemtest/testdata/testset1/dot4.ql.out b/systemtest/testdata/testset1/dot4.ql.out
new file mode 100644
index 0000000..1fb429d
--- /dev/null
+++ b/systemtest/testdata/testset1/dot4.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <long, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <long, [0:10,0:10]>
+ Type Schema...........: marray< long >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: long
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 484
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+Image 2
+GMarray
+ Type Structure........: marray <long, [0:10,0:10]>
+ Type Schema...........: marray< long >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: long
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 484
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+-- Testbed end block:
diff --git a/systemtest/testdata/testset1/dot5.ql b/systemtest/testdata/testset1/dot5.ql
new file mode 100644
index 0000000..d375924
--- /dev/null
+++ b/systemtest/testdata/testset1/dot5.ql
@@ -0,0 +1,6 @@
+-- Testbed: result_type=set <marray <char, [0:10,0:10]>>
+-- Testbed: result_elements=2
+
+select a.red + a.green + a.blue
+from ImgRGBA as a
+where some_cell( a.red > 0 )
diff --git a/systemtest/testdata/testset1/dot5.ql.java.out b/systemtest/testdata/testset1/dot5.ql.java.out
new file mode 100644
index 0000000..8668345
--- /dev/null
+++ b/systemtest/testdata/testset1/dot5.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 \ No newline at end of file
diff --git a/systemtest/testdata/testset1/dot5.ql.out b/systemtest/testdata/testset1/dot5.ql.out
new file mode 100644
index 0000000..f63bae4
--- /dev/null
+++ b/systemtest/testdata/testset1/dot5.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <char, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [0:10,0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ 6 6 6 6 6 6 6 6 6 6 6
+ 6 6 6 6 6 6 6 6 6 6 6
+ 6 6 6 6 6 6 6 6 6 6 6
+ 6 6 6 6 6 6 6 6 6 6 6
+ 6 6 6 6 6 6 6 6 6 6 6
+ 6 6 6 6 6 6 6 6 6 6 6
+ 6 6 6 6 6 6 6 6 6 6 6
+ 6 6 6 6 6 6 6 6 6 6 6
+ 6 6 6 6 6 6 6 6 6 6 6
+ 6 6 6 6 6 6 6 6 6 6 6
+ 6 6 6 6 6 6 6 6 6 6 6
+Image 2
+GMarray
+ Type Structure........: marray <char, [0:10,0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ 6 6 6 6 6 6 6 6 6 6 6
+ 6 6 6 6 6 6 6 6 6 6 6
+ 6 6 6 6 6 6 6 6 6 6 6
+ 6 6 6 6 6 6 6 6 6 6 6
+ 6 6 6 6 6 6 6 6 6 6 6
+ 6 6 6 6 6 6 6 6 6 6 6
+ 6 6 6 6 6 6 6 6 6 6 6
+ 6 6 6 6 6 6 6 6 6 6 6
+ 6 6 6 6 6 6 6 6 6 6 6
+ 6 6 6 6 6 6 6 6 6 6 6
+ 6 6 6 6 6 6 6 6 6 6 6
+-- Testbed end block:
diff --git a/systemtest/testdata/testset1/dot6.ql b/systemtest/testdata/testset1/dot6.ql
new file mode 100644
index 0000000..f3f7239
--- /dev/null
+++ b/systemtest/testdata/testset1/dot6.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <char, [0:10,0:10]>>
+-- Testbed: result_elements=2
+
+select (a * 2c).green
+from ImgRGBA as a
diff --git a/systemtest/testdata/testset1/dot6.ql.java.out b/systemtest/testdata/testset1/dot6.ql.java.out
new file mode 100644
index 0000000..44c334a
--- /dev/null
+++ b/systemtest/testdata/testset1/dot6.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 \ No newline at end of file
diff --git a/systemtest/testdata/testset1/dot6.ql.out b/systemtest/testdata/testset1/dot6.ql.out
new file mode 100644
index 0000000..94951cf
--- /dev/null
+++ b/systemtest/testdata/testset1/dot6.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <char, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [0:10,0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ 4 4 4 4 4 4 4 4 4 4 4
+ 4 4 4 4 4 4 4 4 4 4 4
+ 4 4 4 4 4 4 4 4 4 4 4
+ 4 4 4 4 4 4 4 4 4 4 4
+ 4 4 4 4 4 4 4 4 4 4 4
+ 4 4 4 4 4 4 4 4 4 4 4
+ 4 4 4 4 4 4 4 4 4 4 4
+ 4 4 4 4 4 4 4 4 4 4 4
+ 4 4 4 4 4 4 4 4 4 4 4
+ 4 4 4 4 4 4 4 4 4 4 4
+ 4 4 4 4 4 4 4 4 4 4 4
+Image 2
+GMarray
+ Type Structure........: marray <char, [0:10,0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ 4 4 4 4 4 4 4 4 4 4 4
+ 4 4 4 4 4 4 4 4 4 4 4
+ 4 4 4 4 4 4 4 4 4 4 4
+ 4 4 4 4 4 4 4 4 4 4 4
+ 4 4 4 4 4 4 4 4 4 4 4
+ 4 4 4 4 4 4 4 4 4 4 4
+ 4 4 4 4 4 4 4 4 4 4 4
+ 4 4 4 4 4 4 4 4 4 4 4
+ 4 4 4 4 4 4 4 4 4 4 4
+ 4 4 4 4 4 4 4 4 4 4 4
+ 4 4 4 4 4 4 4 4 4 4 4
+-- Testbed end block:
diff --git a/systemtest/testdata/testset1/dot7.ql b/systemtest/testdata/testset1/dot7.ql
new file mode 100644
index 0000000..75b845f
--- /dev/null
+++ b/systemtest/testdata/testset1/dot7.ql
@@ -0,0 +1,2 @@
+select ( a.green > 0 ) * { 255c, 0c, 0c } + ( a.red > 0 ) * { 0c, 127c, 0c }
+from ImgRGBA as a
diff --git a/systemtest/testdata/testset1/dot7.ql.java.out b/systemtest/testdata/testset1/dot7.ql.java.out
new file mode 100644
index 0000000..a6d1707
--- /dev/null
+++ b/systemtest/testdata/testset1/dot7.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasGMArray
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:205,0:205]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 3
+ Data format...........: 0
+ Data size (bytes).....: 363
+ -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 -1 127 0 \ No newline at end of file
diff --git a/systemtest/testdata/testset1/dot7.ql.out b/systemtest/testdata/testset1/dot7.ql.out
new file mode 100644
index 0000000..115b9c5
--- /dev/null
+++ b/systemtest/testdata/testset1/dot7.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <struct { char 0, char 1, char 2 }, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <struct { char 0, char 1, char 2 }, [0:10,0:10]>
+ Type Schema...........: marray< struct{ char 0, char 1, char 2 } >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: struct{ char 0, char 1, char 2 }
+ Base Type Length......: 3
+ Data format.......... : Array
+ Data size (bytes).... : 363
+{ 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0}
+{ 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0}
+{ 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0}
+{ 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0}
+{ 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0}
+{ 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0}
+{ 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0}
+{ 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0}
+{ 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0}
+{ 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0}
+{ 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0}
+Image 2
+GMarray
+ Type Structure........: marray <struct { char 0, char 1, char 2 }, [0:10,0:10]>
+ Type Schema...........: marray< struct{ char 0, char 1, char 2 } >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: struct{ char 0, char 1, char 2 }
+ Base Type Length......: 3
+ Data format.......... : Array
+ Data size (bytes).... : 363
+{ 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0}
+{ 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0}
+{ 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0}
+{ 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0}
+{ 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0}
+{ 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0}
+{ 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0}
+{ 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0}
+{ 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0}
+{ 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0}
+{ 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0} { 255, 127, 0}
+-- Testbed end block:
diff --git a/systemtest/testdata/testset1/ind1.ql b/systemtest/testdata/testset1/ind1.ql
new file mode 100644
index 0000000..5cea87c
--- /dev/null
+++ b/systemtest/testdata/testset1/ind1.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <octet, [0:10,0:10]>>
+-- Testbed: result_elements=2
+
+select -a
+from ImgCharA as a
diff --git a/systemtest/testdata/testset1/ind1.ql.java.out b/systemtest/testdata/testset1/ind1.ql.java.out
new file mode 100644
index 0000000..5f995b1
--- /dev/null
+++ b/systemtest/testdata/testset1/ind1.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 \ No newline at end of file
diff --git a/systemtest/testdata/testset1/ind1.ql.out b/systemtest/testdata/testset1/ind1.ql.out
new file mode 100644
index 0000000..229c499
--- /dev/null
+++ b/systemtest/testdata/testset1/ind1.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <octet, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <octet, [0:10,0:10]>
+ Type Schema...........: marray< octet >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: octet
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+Image 2
+GMarray
+ Type Structure........: marray <octet, [0:10,0:10]>
+ Type Schema...........: marray< octet >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: octet
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+ -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+ -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+ -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+ -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+ -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+ -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+ -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+ -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+ -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+ -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+-- Testbed end block:
diff --git a/systemtest/testdata/testset1/ind2.ql b/systemtest/testdata/testset1/ind2.ql
new file mode 100644
index 0000000..4a626e1
--- /dev/null
+++ b/systemtest/testdata/testset1/ind2.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <struct { char red, char green, char blue }, [0:10,0:10]>>
+-- Testbed: result_elements=2
+
+select a * 2c
+from ImgRGBA as a
diff --git a/systemtest/testdata/testset1/ind2.ql.java.out b/systemtest/testdata/testset1/ind2.ql.java.out
new file mode 100644
index 0000000..81be0e5
--- /dev/null
+++ b/systemtest/testdata/testset1/ind2.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasGMArray
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:205,0:205]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 3
+ Data format...........: 0
+ Data size (bytes).....: 363
+ 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 2 4 6 \ No newline at end of file
diff --git a/systemtest/testdata/testset1/ind2.ql.out b/systemtest/testdata/testset1/ind2.ql.out
new file mode 100644
index 0000000..947574e
--- /dev/null
+++ b/systemtest/testdata/testset1/ind2.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <struct { char red, char green, char blue }, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <struct { char red, char green, char blue }, [0:10,0:10]>
+ Type Schema...........: marray< struct{ char red, char green, char blue } >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: struct{ char red, char green, char blue }
+ Base Type Length......: 3
+ Data format.......... : Array
+ Data size (bytes).... : 363
+{ 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6}
+{ 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6}
+{ 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6}
+{ 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6}
+{ 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6}
+{ 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6}
+{ 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6}
+{ 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6}
+{ 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6}
+{ 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6}
+{ 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6}
+Image 2
+GMarray
+ Type Structure........: marray <struct { char red, char green, char blue }, [0:10,0:10]>
+ Type Schema...........: marray< struct{ char red, char green, char blue } >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: struct{ char red, char green, char blue }
+ Base Type Length......: 3
+ Data format.......... : Array
+ Data size (bytes).... : 363
+{ 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6}
+{ 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6}
+{ 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6}
+{ 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6}
+{ 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6}
+{ 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6}
+{ 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6}
+{ 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6}
+{ 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6}
+{ 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6}
+{ 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6} { 2, 4, 6}
+-- Testbed end block:
diff --git a/systemtest/testdata/testset1/ind3.ql b/systemtest/testdata/testset1/ind3.ql
new file mode 100644
index 0000000..623f422
--- /dev/null
+++ b/systemtest/testdata/testset1/ind3.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <bool, [0:10,0:10]>>
+-- Testbed: result_elements=2
+
+select a > 0
+from ImgCharA as a
diff --git a/systemtest/testdata/testset1/ind3.ql.java.out b/systemtest/testdata/testset1/ind3.ql.java.out
new file mode 100644
index 0000000..f2deb7a
--- /dev/null
+++ b/systemtest/testdata/testset1/ind3.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 \ No newline at end of file
diff --git a/systemtest/testdata/testset1/ind3.ql.out b/systemtest/testdata/testset1/ind3.ql.out
new file mode 100644
index 0000000..53e26a4
--- /dev/null
+++ b/systemtest/testdata/testset1/ind3.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <bool, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <bool, [0:10,0:10]>
+ Type Schema...........: marray< bool >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: bool
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+ F F F F F F F F F F F
+Image 2
+GMarray
+ Type Structure........: marray <bool, [0:10,0:10]>
+ Type Schema...........: marray< bool >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: bool
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+ T T T T T T T T T T T
+-- Testbed end block:
diff --git a/systemtest/testdata/testset1/opt1.ql b/systemtest/testdata/testset1/opt1.ql
new file mode 100644
index 0000000..36ea1b8
--- /dev/null
+++ b/systemtest/testdata/testset1/opt1.ql
@@ -0,0 +1,7 @@
+-- Opt: evaluation on constant expressions
+
+-- Testbed: result_type=set <marray <long, [0:10,0:10]>>
+-- Testbed: result_elements=2
+
+select a + 1 * 2
+from ImgCharA as a
diff --git a/systemtest/testdata/testset1/opt1.ql.java.out b/systemtest/testdata/testset1/opt1.ql.java.out
new file mode 100644
index 0000000..9b791b0
--- /dev/null
+++ b/systemtest/testdata/testset1/opt1.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayInteger
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:177,0:177]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 484
+ 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2
+rasj.RasMArrayInteger
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:177,0:177]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 484
+ 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 \ No newline at end of file
diff --git a/systemtest/testdata/testset1/opt1.ql.out b/systemtest/testdata/testset1/opt1.ql.out
new file mode 100644
index 0000000..1f50401
--- /dev/null
+++ b/systemtest/testdata/testset1/opt1.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <long, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <long, [0:10,0:10]>
+ Type Schema...........: marray< long >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: long
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 484
+ 2 2 2 2 2 2 2 2 2 2 2
+ 2 2 2 2 2 2 2 2 2 2 2
+ 2 2 2 2 2 2 2 2 2 2 2
+ 2 2 2 2 2 2 2 2 2 2 2
+ 2 2 2 2 2 2 2 2 2 2 2
+ 2 2 2 2 2 2 2 2 2 2 2
+ 2 2 2 2 2 2 2 2 2 2 2
+ 2 2 2 2 2 2 2 2 2 2 2
+ 2 2 2 2 2 2 2 2 2 2 2
+ 2 2 2 2 2 2 2 2 2 2 2
+ 2 2 2 2 2 2 2 2 2 2 2
+Image 2
+GMarray
+ Type Structure........: marray <long, [0:10,0:10]>
+ Type Schema...........: marray< long >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: long
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 484
+ 3 3 3 3 3 3 3 3 3 3 3
+ 3 3 3 3 3 3 3 3 3 3 3
+ 3 3 3 3 3 3 3 3 3 3 3
+ 3 3 3 3 3 3 3 3 3 3 3
+ 3 3 3 3 3 3 3 3 3 3 3
+ 3 3 3 3 3 3 3 3 3 3 3
+ 3 3 3 3 3 3 3 3 3 3 3
+ 3 3 3 3 3 3 3 3 3 3 3
+ 3 3 3 3 3 3 3 3 3 3 3
+ 3 3 3 3 3 3 3 3 3 3 3
+ 3 3 3 3 3 3 3 3 3 3 3
+-- Testbed end block:
diff --git a/systemtest/testdata/testset1/opt2.ql b/systemtest/testdata/testset1/opt2.ql
new file mode 100644
index 0000000..d6af2bb
--- /dev/null
+++ b/systemtest/testdata/testset1/opt2.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <long, [0:10,0:10]>>
+-- Testbed: result_elements=4
+
+select a + 1 + b + 2
+from ImgCharA as a, ImgCharB as b
diff --git a/systemtest/testdata/testset1/opt2.ql.java.out b/systemtest/testdata/testset1/opt2.ql.java.out
new file mode 100644
index 0000000..8d63a2c
--- /dev/null
+++ b/systemtest/testdata/testset1/opt2.ql.java.out
@@ -0,0 +1,57 @@
+
+rasj.RasMArrayInteger
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:177,0:177]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 484
+ 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13 0 0 0 13
+rasj.RasMArrayInteger
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:177,0:177]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 484
+ 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14 0 0 0 14
+rasj.RasMArrayInteger
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:177,0:177]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 484
+ 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23 0 0 0 23
+rasj.RasMArrayInteger
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:177,0:177]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 484
+ 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 0 0 0 24 \ No newline at end of file
diff --git a/systemtest/testdata/testset1/opt2.ql.out b/systemtest/testdata/testset1/opt2.ql.out
new file mode 100644
index 0000000..f47a6c4
--- /dev/null
+++ b/systemtest/testdata/testset1/opt2.ql.out
@@ -0,0 +1,84 @@
+-- Testbed line: result_type=set <marray <long, [0:10,0:10]>>
+-- Testbed line: result_elements=4
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <long, [0:10,0:10]>
+ Type Schema...........: marray< long >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: long
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 484
+ 13 13 13 13 13 13 13 13 13 13 13
+ 13 13 13 13 13 13 13 13 13 13 13
+ 13 13 13 13 13 13 13 13 13 13 13
+ 13 13 13 13 13 13 13 13 13 13 13
+ 13 13 13 13 13 13 13 13 13 13 13
+ 13 13 13 13 13 13 13 13 13 13 13
+ 13 13 13 13 13 13 13 13 13 13 13
+ 13 13 13 13 13 13 13 13 13 13 13
+ 13 13 13 13 13 13 13 13 13 13 13
+ 13 13 13 13 13 13 13 13 13 13 13
+ 13 13 13 13 13 13 13 13 13 13 13
+Image 2
+GMarray
+ Type Structure........: marray <long, [0:10,0:10]>
+ Type Schema...........: marray< long >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: long
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 484
+ 14 14 14 14 14 14 14 14 14 14 14
+ 14 14 14 14 14 14 14 14 14 14 14
+ 14 14 14 14 14 14 14 14 14 14 14
+ 14 14 14 14 14 14 14 14 14 14 14
+ 14 14 14 14 14 14 14 14 14 14 14
+ 14 14 14 14 14 14 14 14 14 14 14
+ 14 14 14 14 14 14 14 14 14 14 14
+ 14 14 14 14 14 14 14 14 14 14 14
+ 14 14 14 14 14 14 14 14 14 14 14
+ 14 14 14 14 14 14 14 14 14 14 14
+ 14 14 14 14 14 14 14 14 14 14 14
+Image 3
+GMarray
+ Type Structure........: marray <long, [0:10,0:10]>
+ Type Schema...........: marray< long >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: long
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 484
+ 23 23 23 23 23 23 23 23 23 23 23
+ 23 23 23 23 23 23 23 23 23 23 23
+ 23 23 23 23 23 23 23 23 23 23 23
+ 23 23 23 23 23 23 23 23 23 23 23
+ 23 23 23 23 23 23 23 23 23 23 23
+ 23 23 23 23 23 23 23 23 23 23 23
+ 23 23 23 23 23 23 23 23 23 23 23
+ 23 23 23 23 23 23 23 23 23 23 23
+ 23 23 23 23 23 23 23 23 23 23 23
+ 23 23 23 23 23 23 23 23 23 23 23
+ 23 23 23 23 23 23 23 23 23 23 23
+Image 4
+GMarray
+ Type Structure........: marray <long, [0:10,0:10]>
+ Type Schema...........: marray< long >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: long
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 484
+ 24 24 24 24 24 24 24 24 24 24 24
+ 24 24 24 24 24 24 24 24 24 24 24
+ 24 24 24 24 24 24 24 24 24 24 24
+ 24 24 24 24 24 24 24 24 24 24 24
+ 24 24 24 24 24 24 24 24 24 24 24
+ 24 24 24 24 24 24 24 24 24 24 24
+ 24 24 24 24 24 24 24 24 24 24 24
+ 24 24 24 24 24 24 24 24 24 24 24
+ 24 24 24 24 24 24 24 24 24 24 24
+ 24 24 24 24 24 24 24 24 24 24 24
+ 24 24 24 24 24 24 24 24 24 24 24
+-- Testbed end block:
diff --git a/systemtest/testdata/testset1/opt4.ql b/systemtest/testdata/testset1/opt4.ql
new file mode 100644
index 0000000..27ef685
--- /dev/null
+++ b/systemtest/testdata/testset1/opt4.ql
@@ -0,0 +1,6 @@
+-- Testbed: result_type=set <marray <char, [0:10,0:10]>>
+-- Testbed: result_elements=2
+
+select a * b
+from ImgCharA as a, ImgCharB as b
+where some_cell( a*b > 0 )
diff --git a/systemtest/testdata/testset1/opt4.ql.java.out b/systemtest/testdata/testset1/opt4.ql.java.out
new file mode 100644
index 0000000..ac09ddd
--- /dev/null
+++ b/systemtest/testdata/testset1/opt4.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 \ No newline at end of file
diff --git a/systemtest/testdata/testset1/opt4.ql.out b/systemtest/testdata/testset1/opt4.ql.out
new file mode 100644
index 0000000..816708e
--- /dev/null
+++ b/systemtest/testdata/testset1/opt4.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <char, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [0:10,0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10
+Image 2
+GMarray
+ Type Structure........: marray <char, [0:10,0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ 20 20 20 20 20 20 20 20 20 20 20
+ 20 20 20 20 20 20 20 20 20 20 20
+ 20 20 20 20 20 20 20 20 20 20 20
+ 20 20 20 20 20 20 20 20 20 20 20
+ 20 20 20 20 20 20 20 20 20 20 20
+ 20 20 20 20 20 20 20 20 20 20 20
+ 20 20 20 20 20 20 20 20 20 20 20
+ 20 20 20 20 20 20 20 20 20 20 20
+ 20 20 20 20 20 20 20 20 20 20 20
+ 20 20 20 20 20 20 20 20 20 20 20
+ 20 20 20 20 20 20 20 20 20 20 20
+-- Testbed end block:
diff --git a/systemtest/testdata/testset1/opt5.ql b/systemtest/testdata/testset1/opt5.ql
new file mode 100644
index 0000000..9833e16
--- /dev/null
+++ b/systemtest/testdata/testset1/opt5.ql
@@ -0,0 +1,6 @@
+-- Testbed: result_type=set <marray <long, [0:10,0:10]>>
+-- Testbed: result_elements=4
+
+select (a+2)*(b+1)
+from ImgCharA as a, ImgCharB as b
+where some_cell( (a+2)*(b+1) > 0 )
diff --git a/systemtest/testdata/testset1/opt5.ql.java.out b/systemtest/testdata/testset1/opt5.ql.java.out
new file mode 100644
index 0000000..aff941e
--- /dev/null
+++ b/systemtest/testdata/testset1/opt5.ql.java.out
@@ -0,0 +1,57 @@
+
+rasj.RasMArrayInteger
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:177,0:177]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 484
+ 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22 0 0 0 22
+rasj.RasMArrayInteger
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:177,0:177]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 484
+ 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33 0 0 0 33
+rasj.RasMArrayInteger
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:177,0:177]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 484
+ 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42 0 0 0 42
+rasj.RasMArrayInteger
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:177,0:177]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 484
+ 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 0 0 0 63 \ No newline at end of file
diff --git a/systemtest/testdata/testset1/opt5.ql.out b/systemtest/testdata/testset1/opt5.ql.out
new file mode 100644
index 0000000..14fa211
--- /dev/null
+++ b/systemtest/testdata/testset1/opt5.ql.out
@@ -0,0 +1,84 @@
+-- Testbed line: result_type=set <marray <long, [0:10,0:10]>>
+-- Testbed line: result_elements=4
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <long, [0:10,0:10]>
+ Type Schema...........: marray< long >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: long
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 484
+ 22 22 22 22 22 22 22 22 22 22 22
+ 22 22 22 22 22 22 22 22 22 22 22
+ 22 22 22 22 22 22 22 22 22 22 22
+ 22 22 22 22 22 22 22 22 22 22 22
+ 22 22 22 22 22 22 22 22 22 22 22
+ 22 22 22 22 22 22 22 22 22 22 22
+ 22 22 22 22 22 22 22 22 22 22 22
+ 22 22 22 22 22 22 22 22 22 22 22
+ 22 22 22 22 22 22 22 22 22 22 22
+ 22 22 22 22 22 22 22 22 22 22 22
+ 22 22 22 22 22 22 22 22 22 22 22
+Image 2
+GMarray
+ Type Structure........: marray <long, [0:10,0:10]>
+ Type Schema...........: marray< long >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: long
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 484
+ 33 33 33 33 33 33 33 33 33 33 33
+ 33 33 33 33 33 33 33 33 33 33 33
+ 33 33 33 33 33 33 33 33 33 33 33
+ 33 33 33 33 33 33 33 33 33 33 33
+ 33 33 33 33 33 33 33 33 33 33 33
+ 33 33 33 33 33 33 33 33 33 33 33
+ 33 33 33 33 33 33 33 33 33 33 33
+ 33 33 33 33 33 33 33 33 33 33 33
+ 33 33 33 33 33 33 33 33 33 33 33
+ 33 33 33 33 33 33 33 33 33 33 33
+ 33 33 33 33 33 33 33 33 33 33 33
+Image 3
+GMarray
+ Type Structure........: marray <long, [0:10,0:10]>
+ Type Schema...........: marray< long >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: long
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 484
+ 42 42 42 42 42 42 42 42 42 42 42
+ 42 42 42 42 42 42 42 42 42 42 42
+ 42 42 42 42 42 42 42 42 42 42 42
+ 42 42 42 42 42 42 42 42 42 42 42
+ 42 42 42 42 42 42 42 42 42 42 42
+ 42 42 42 42 42 42 42 42 42 42 42
+ 42 42 42 42 42 42 42 42 42 42 42
+ 42 42 42 42 42 42 42 42 42 42 42
+ 42 42 42 42 42 42 42 42 42 42 42
+ 42 42 42 42 42 42 42 42 42 42 42
+ 42 42 42 42 42 42 42 42 42 42 42
+Image 4
+GMarray
+ Type Structure........: marray <long, [0:10,0:10]>
+ Type Schema...........: marray< long >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: long
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 484
+ 63 63 63 63 63 63 63 63 63 63 63
+ 63 63 63 63 63 63 63 63 63 63 63
+ 63 63 63 63 63 63 63 63 63 63 63
+ 63 63 63 63 63 63 63 63 63 63 63
+ 63 63 63 63 63 63 63 63 63 63 63
+ 63 63 63 63 63 63 63 63 63 63 63
+ 63 63 63 63 63 63 63 63 63 63 63
+ 63 63 63 63 63 63 63 63 63 63 63
+ 63 63 63 63 63 63 63 63 63 63 63
+ 63 63 63 63 63 63 63 63 63 63 63
+ 63 63 63 63 63 63 63 63 63 63 63
+-- Testbed end block:
diff --git a/systemtest/testdata/testset1/trim1.ql b/systemtest/testdata/testset1/trim1.ql
new file mode 100644
index 0000000..e811114
--- /dev/null
+++ b/systemtest/testdata/testset1/trim1.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <char, [2:5,5:8]>>
+-- Testbed: result_elements=2
+
+select a[2:5,5:8]
+from ImgCharA as a
diff --git a/systemtest/testdata/testset1/trim1.ql.java.out b/systemtest/testdata/testset1/trim1.ql.java.out
new file mode 100644
index 0000000..fb615af
--- /dev/null
+++ b/systemtest/testdata/testset1/trim1.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [2:5,5:8]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 16
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [2:5,5:8]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 16
+ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 \ No newline at end of file
diff --git a/systemtest/testdata/testset1/trim1.ql.out b/systemtest/testdata/testset1/trim1.ql.out
new file mode 100644
index 0000000..dd783e2
--- /dev/null
+++ b/systemtest/testdata/testset1/trim1.ql.out
@@ -0,0 +1,30 @@
+-- Testbed line: result_type=set <marray <char, [2:5,5:8]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [2:5,5:8]>
+ Type Schema...........: marray< char >
+ Domain................: [2:5,5:8]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 16
+ 0 0 0 0
+ 0 0 0 0
+ 0 0 0 0
+ 0 0 0 0
+Image 2
+GMarray
+ Type Structure........: marray <char, [2:5,5:8]>
+ Type Schema...........: marray< char >
+ Domain................: [2:5,5:8]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 16
+ 1 1 1 1
+ 1 1 1 1
+ 1 1 1 1
+ 1 1 1 1
+-- Testbed end block:
diff --git a/systemtest/testdata/testset1/trim2.ql b/systemtest/testdata/testset1/trim2.ql
new file mode 100644
index 0000000..f0b3ee4
--- /dev/null
+++ b/systemtest/testdata/testset1/trim2.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <long, [2:5,5:8]>>
+-- Testbed: result_elements=2
+
+select (a*2)[2:5,5:8]
+from ImgCharA as a
diff --git a/systemtest/testdata/testset1/trim2.ql.java.out b/systemtest/testdata/testset1/trim2.ql.java.out
new file mode 100644
index 0000000..bef0467
--- /dev/null
+++ b/systemtest/testdata/testset1/trim2.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayInteger
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [2:5,5:8]
+ TilingDomain..........: [0:177,0:177]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 64
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+rasj.RasMArrayInteger
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [2:5,5:8]
+ TilingDomain..........: [0:177,0:177]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 64
+ 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 \ No newline at end of file
diff --git a/systemtest/testdata/testset1/trim2.ql.out b/systemtest/testdata/testset1/trim2.ql.out
new file mode 100644
index 0000000..f18042c
--- /dev/null
+++ b/systemtest/testdata/testset1/trim2.ql.out
@@ -0,0 +1,30 @@
+-- Testbed line: result_type=set <marray <long, [2:5,5:8]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <long, [2:5,5:8]>
+ Type Schema...........: marray< long >
+ Domain................: [2:5,5:8]
+ Base Type Schema......: long
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 64
+ 0 0 0 0
+ 0 0 0 0
+ 0 0 0 0
+ 0 0 0 0
+Image 2
+GMarray
+ Type Structure........: marray <long, [2:5,5:8]>
+ Type Schema...........: marray< long >
+ Domain................: [2:5,5:8]
+ Base Type Schema......: long
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 64
+ 2 2 2 2
+ 2 2 2 2
+ 2 2 2 2
+ 2 2 2 2
+-- Testbed end block:
diff --git a/systemtest/testdata/testset1/trim3.ql b/systemtest/testdata/testset1/trim3.ql
new file mode 100644
index 0000000..51a6c32
--- /dev/null
+++ b/systemtest/testdata/testset1/trim3.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <char, [2:5,5:8]>>
+-- Testbed: result_elements=4
+
+select a[2:5,5:8]+b[2:5,5:8]
+from ImgCharA as a, ImgCharB as b
diff --git a/systemtest/testdata/testset1/trim3.ql.java.out b/systemtest/testdata/testset1/trim3.ql.java.out
new file mode 100644
index 0000000..ac8312e
--- /dev/null
+++ b/systemtest/testdata/testset1/trim3.ql.java.out
@@ -0,0 +1,57 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [2:5,5:8]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 16
+ 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [2:5,5:8]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 16
+ 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [2:5,5:8]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 16
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [2:5,5:8]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 16
+ 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 \ No newline at end of file
diff --git a/systemtest/testdata/testset1/trim3.ql.out b/systemtest/testdata/testset1/trim3.ql.out
new file mode 100644
index 0000000..6cab68c
--- /dev/null
+++ b/systemtest/testdata/testset1/trim3.ql.out
@@ -0,0 +1,56 @@
+-- Testbed line: result_type=set <marray <char, [2:5,5:8]>>
+-- Testbed line: result_elements=4
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [2:5,5:8]>
+ Type Schema...........: marray< char >
+ Domain................: [2:5,5:8]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 16
+ 10 10 10 10
+ 10 10 10 10
+ 10 10 10 10
+ 10 10 10 10
+Image 2
+GMarray
+ Type Structure........: marray <char, [2:5,5:8]>
+ Type Schema...........: marray< char >
+ Domain................: [2:5,5:8]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 16
+ 11 11 11 11
+ 11 11 11 11
+ 11 11 11 11
+ 11 11 11 11
+Image 3
+GMarray
+ Type Structure........: marray <char, [2:5,5:8]>
+ Type Schema...........: marray< char >
+ Domain................: [2:5,5:8]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 16
+ 20 20 20 20
+ 20 20 20 20
+ 20 20 20 20
+ 20 20 20 20
+Image 4
+GMarray
+ Type Structure........: marray <char, [2:5,5:8]>
+ Type Schema...........: marray< char >
+ Domain................: [2:5,5:8]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 16
+ 21 21 21 21
+ 21 21 21 21
+ 21 21 21 21
+ 21 21 21 21
+-- Testbed end block:
diff --git a/systemtest/testdata/testset1/trim4.ql b/systemtest/testdata/testset1/trim4.ql
new file mode 100644
index 0000000..9750e1b
--- /dev/null
+++ b/systemtest/testdata/testset1/trim4.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <char, [2:5,5:8]>>
+-- Testbed: result_elements=4
+
+select (a+b)[2:5,5:8]
+from ImgCharA as a, ImgCharB as b
diff --git a/systemtest/testdata/testset1/trim4.ql.java.out b/systemtest/testdata/testset1/trim4.ql.java.out
new file mode 100644
index 0000000..ac8312e
--- /dev/null
+++ b/systemtest/testdata/testset1/trim4.ql.java.out
@@ -0,0 +1,57 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [2:5,5:8]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 16
+ 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [2:5,5:8]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 16
+ 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [2:5,5:8]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 16
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [2:5,5:8]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 16
+ 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 \ No newline at end of file
diff --git a/systemtest/testdata/testset1/trim4.ql.out b/systemtest/testdata/testset1/trim4.ql.out
new file mode 100644
index 0000000..6cab68c
--- /dev/null
+++ b/systemtest/testdata/testset1/trim4.ql.out
@@ -0,0 +1,56 @@
+-- Testbed line: result_type=set <marray <char, [2:5,5:8]>>
+-- Testbed line: result_elements=4
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [2:5,5:8]>
+ Type Schema...........: marray< char >
+ Domain................: [2:5,5:8]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 16
+ 10 10 10 10
+ 10 10 10 10
+ 10 10 10 10
+ 10 10 10 10
+Image 2
+GMarray
+ Type Structure........: marray <char, [2:5,5:8]>
+ Type Schema...........: marray< char >
+ Domain................: [2:5,5:8]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 16
+ 11 11 11 11
+ 11 11 11 11
+ 11 11 11 11
+ 11 11 11 11
+Image 3
+GMarray
+ Type Structure........: marray <char, [2:5,5:8]>
+ Type Schema...........: marray< char >
+ Domain................: [2:5,5:8]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 16
+ 20 20 20 20
+ 20 20 20 20
+ 20 20 20 20
+ 20 20 20 20
+Image 4
+GMarray
+ Type Structure........: marray <char, [2:5,5:8]>
+ Type Schema...........: marray< char >
+ Domain................: [2:5,5:8]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 16
+ 21 21 21 21
+ 21 21 21 21
+ 21 21 21 21
+ 21 21 21 21
+-- Testbed end block:
diff --git a/systemtest/testdata/testset1/trim5.ql b/systemtest/testdata/testset1/trim5.ql
new file mode 100644
index 0000000..3f68232
--- /dev/null
+++ b/systemtest/testdata/testset1/trim5.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <char, [0:10]>>
+-- Testbed: result_elements=4
+
+select (a * b)[5,*:*].green
+from ImgRGBA as a, ImgRGBA as b
diff --git a/systemtest/testdata/testset1/trim5.ql.java.out b/systemtest/testdata/testset1/trim5.ql.java.out
new file mode 100644
index 0000000..c104e32
--- /dev/null
+++ b/systemtest/testdata/testset1/trim5.ql.java.out
@@ -0,0 +1,57 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 11
+ 4 4 4 4 4 4 4 4 4 4 4
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 11
+ 4 4 4 4 4 4 4 4 4 4 4
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 11
+ 4 4 4 4 4 4 4 4 4 4 4
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 11
+ 4 4 4 4 4 4 4 4 4 4 4 \ No newline at end of file
diff --git a/systemtest/testdata/testset1/trim5.ql.out b/systemtest/testdata/testset1/trim5.ql.out
new file mode 100644
index 0000000..276581c
--- /dev/null
+++ b/systemtest/testdata/testset1/trim5.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <char, [0:10]>>
+-- Testbed line: result_elements=4
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 11
+ 4 4 4 4 4 4 4 4 4 4 4
+Image 2
+GMarray
+ Type Structure........: marray <char, [0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 11
+ 4 4 4 4 4 4 4 4 4 4 4
+Image 3
+GMarray
+ Type Structure........: marray <char, [0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 11
+ 4 4 4 4 4 4 4 4 4 4 4
+Image 4
+GMarray
+ Type Structure........: marray <char, [0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 11
+ 4 4 4 4 4 4 4 4 4 4 4
+-- Testbed end block:
diff --git a/systemtest/testdata/testset1/trim6.ql b/systemtest/testdata/testset1/trim6.ql
new file mode 100644
index 0000000..f8a8468
--- /dev/null
+++ b/systemtest/testdata/testset1/trim6.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <char, [0:10]>>
+-- Testbed: result_elements=4
+
+select (a * b).green [5,*:*]
+from ImgRGBA as a, ImgRGBA as b
diff --git a/systemtest/testdata/testset1/trim6.ql.java.out b/systemtest/testdata/testset1/trim6.ql.java.out
new file mode 100644
index 0000000..c104e32
--- /dev/null
+++ b/systemtest/testdata/testset1/trim6.ql.java.out
@@ -0,0 +1,57 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 11
+ 4 4 4 4 4 4 4 4 4 4 4
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 11
+ 4 4 4 4 4 4 4 4 4 4 4
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 11
+ 4 4 4 4 4 4 4 4 4 4 4
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 11
+ 4 4 4 4 4 4 4 4 4 4 4 \ No newline at end of file
diff --git a/systemtest/testdata/testset1/trim6.ql.out b/systemtest/testdata/testset1/trim6.ql.out
new file mode 100644
index 0000000..276581c
--- /dev/null
+++ b/systemtest/testdata/testset1/trim6.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <char, [0:10]>>
+-- Testbed line: result_elements=4
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 11
+ 4 4 4 4 4 4 4 4 4 4 4
+Image 2
+GMarray
+ Type Structure........: marray <char, [0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 11
+ 4 4 4 4 4 4 4 4 4 4 4
+Image 3
+GMarray
+ Type Structure........: marray <char, [0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 11
+ 4 4 4 4 4 4 4 4 4 4 4
+Image 4
+GMarray
+ Type Structure........: marray <char, [0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 11
+ 4 4 4 4 4 4 4 4 4 4 4
+-- Testbed end block:
diff --git a/systemtest/testdata/testset2/const1.ql b/systemtest/testdata/testset2/const1.ql
new file mode 100644
index 0000000..54f1f5d
--- /dev/null
+++ b/systemtest/testdata/testset2/const1.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <long, [-2:2,-1:1]>>
+-- Testbed: result_elements=1
+
+select a * 1
+from ImgCharMask as a
diff --git a/systemtest/testdata/testset2/const1.ql.java.out b/systemtest/testdata/testset2/const1.ql.java.out
new file mode 100644
index 0000000..c12f763
--- /dev/null
+++ b/systemtest/testdata/testset2/const1.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayInteger
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [-2:2,-1:1]
+ TilingDomain..........: [0:177,0:177]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 60
+ 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 \ No newline at end of file
diff --git a/systemtest/testdata/testset2/const1.ql.out b/systemtest/testdata/testset2/const1.ql.out
new file mode 100644
index 0000000..939573c
--- /dev/null
+++ b/systemtest/testdata/testset2/const1.ql.out
@@ -0,0 +1,16 @@
+-- Testbed line: result_type=set <marray <long, [-2:2,-1:1]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <long, [-2:2,-1:1]>
+ Type Schema...........: marray< long >
+ Domain................: [-2:2,-1:1]
+ Base Type Schema......: long
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 60
+ 2 2 2 2 2
+ 2 2 2 2 2
+ 2 2 2 2 2
+-- Testbed end block:
diff --git a/systemtest/testdata/testset2/const10.ql b/systemtest/testdata/testset2/const10.ql
new file mode 100644
index 0000000..b90d539
--- /dev/null
+++ b/systemtest/testdata/testset2/const10.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <long, [-2:2,-1:1]>>
+-- Testbed: result_elements=1
+
+select a - -2
+from ImgCharMask as a
diff --git a/systemtest/testdata/testset2/const10.ql.java.out b/systemtest/testdata/testset2/const10.ql.java.out
new file mode 100644
index 0000000..29e925f
--- /dev/null
+++ b/systemtest/testdata/testset2/const10.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayInteger
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [-2:2,-1:1]
+ TilingDomain..........: [0:177,0:177]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 60
+ 0 0 0 4 0 0 0 4 0 0 0 4 0 0 0 4 0 0 0 4 0 0 0 4 0 0 0 4 0 0 0 4 0 0 0 4 0 0 0 4 0 0 0 4 0 0 0 4 0 0 0 4 0 0 0 4 0 0 0 4 \ No newline at end of file
diff --git a/systemtest/testdata/testset2/const10.ql.out b/systemtest/testdata/testset2/const10.ql.out
new file mode 100644
index 0000000..a8f95b2
--- /dev/null
+++ b/systemtest/testdata/testset2/const10.ql.out
@@ -0,0 +1,16 @@
+-- Testbed line: result_type=set <marray <long, [-2:2,-1:1]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <long, [-2:2,-1:1]>
+ Type Schema...........: marray< long >
+ Domain................: [-2:2,-1:1]
+ Base Type Schema......: long
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 60
+ 4 4 4 4 4
+ 4 4 4 4 4
+ 4 4 4 4 4
+-- Testbed end block:
diff --git a/systemtest/testdata/testset2/const11.ql b/systemtest/testdata/testset2/const11.ql
new file mode 100644
index 0000000..6171ca1
--- /dev/null
+++ b/systemtest/testdata/testset2/const11.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <struct { long 0, float 1, long 2 }, [-2:2,-1:1]>>
+-- Testbed: result_elements=1
+
+select a + { -1, 1.0, 1 }
+from ImgCharMask as a
diff --git a/systemtest/testdata/testset2/const11.ql.java.out b/systemtest/testdata/testset2/const11.ql.java.out
new file mode 100644
index 0000000..76703de
--- /dev/null
+++ b/systemtest/testdata/testset2/const11.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasGMArray
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [-2:2,-1:1]
+ TilingDomain..........: [0:102,0:102]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 12
+ Data format...........: 0
+ Data size (bytes).....: 180
+ 0 0 0 1 64 64 0 0 0 0 0 3 0 0 0 1 64 64 0 0 0 0 0 3 0 0 0 1 64 64 0 0 0 0 0 3 0 0 0 1 64 64 0 0 0 0 0 3 0 0 0 1 64 64 0 0 0 0 0 3 0 0 0 1 64 64 0 0 0 0 0 3 0 0 0 1 64 64 0 0 0 0 0 3 0 0 0 1 64 64 0 0 0 0 0 3 0 0 0 1 64 64 0 0 0 0 0 3 0 0 0 1 64 64 0 0 0 0 0 3 0 0 0 1 64 64 0 0 0 0 0 3 0 0 0 1 64 64 0 0 0 0 0 3 0 0 0 1 64 64 0 0 0 0 0 3 0 0 0 1 64 64 0 0 0 0 0 3 0 0 0 1 64 64 0 0 0 0 0 3 \ No newline at end of file
diff --git a/systemtest/testdata/testset2/const11.ql.out b/systemtest/testdata/testset2/const11.ql.out
new file mode 100644
index 0000000..8dd2850
--- /dev/null
+++ b/systemtest/testdata/testset2/const11.ql.out
@@ -0,0 +1,16 @@
+-- Testbed line: result_type=set <marray <struct { long 0, float 1, long 2 }, [-2:2,-1:1]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <struct { long 0, float 1, long 2 }, [-2:2,-1:1]>
+ Type Schema...........: marray< struct{ long 0, float 1, long 2 } >
+ Domain................: [-2:2,-1:1]
+ Base Type Schema......: struct{ long 0, float 1, long 2 }
+ Base Type Length......: 12
+ Data format.......... : Array
+ Data size (bytes).... : 180
+{ 1, 3, 3} { 1, 3, 3} { 1, 3, 3} { 1, 3, 3} { 1, 3, 3}
+{ 1, 3, 3} { 1, 3, 3} { 1, 3, 3} { 1, 3, 3} { 1, 3, 3}
+{ 1, 3, 3} { 1, 3, 3} { 1, 3, 3} { 1, 3, 3} { 1, 3, 3}
+-- Testbed end block:
diff --git a/systemtest/testdata/testset2/const2.ql b/systemtest/testdata/testset2/const2.ql
new file mode 100644
index 0000000..f9fbb8d
--- /dev/null
+++ b/systemtest/testdata/testset2/const2.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <long, [-2:2,-1:1]>>
+-- Testbed: result_elements=1
+
+select a * -1
+from ImgCharMask as a
diff --git a/systemtest/testdata/testset2/const2.ql.java.out b/systemtest/testdata/testset2/const2.ql.java.out
new file mode 100644
index 0000000..d8208e8
--- /dev/null
+++ b/systemtest/testdata/testset2/const2.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayInteger
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [-2:2,-1:1]
+ TilingDomain..........: [0:177,0:177]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 60
+ -1 -1 -1 -2 -1 -1 -1 -2 -1 -1 -1 -2 -1 -1 -1 -2 -1 -1 -1 -2 -1 -1 -1 -2 -1 -1 -1 -2 -1 -1 -1 -2 -1 -1 -1 -2 -1 -1 -1 -2 -1 -1 -1 -2 -1 -1 -1 -2 -1 -1 -1 -2 -1 -1 -1 -2 -1 -1 -1 -2 \ No newline at end of file
diff --git a/systemtest/testdata/testset2/const2.ql.out b/systemtest/testdata/testset2/const2.ql.out
new file mode 100644
index 0000000..247f1fe
--- /dev/null
+++ b/systemtest/testdata/testset2/const2.ql.out
@@ -0,0 +1,16 @@
+-- Testbed line: result_type=set <marray <long, [-2:2,-1:1]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <long, [-2:2,-1:1]>
+ Type Schema...........: marray< long >
+ Domain................: [-2:2,-1:1]
+ Base Type Schema......: long
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 60
+ -2 -2 -2 -2 -2
+ -2 -2 -2 -2 -2
+ -2 -2 -2 -2 -2
+-- Testbed end block:
diff --git a/systemtest/testdata/testset2/const3.ql b/systemtest/testdata/testset2/const3.ql
new file mode 100644
index 0000000..63b107f
--- /dev/null
+++ b/systemtest/testdata/testset2/const3.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <ulong, [-2:2,-1:1]>>
+-- Testbed: result_elements=1
+
+select a * 0x1ul
+from ImgCharMask as a
diff --git a/systemtest/testdata/testset2/const3.ql.java.out b/systemtest/testdata/testset2/const3.ql.java.out
new file mode 100644
index 0000000..5edfee3
--- /dev/null
+++ b/systemtest/testdata/testset2/const3.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayLong
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [-2:2,-1:1]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 120
+ 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 \ No newline at end of file
diff --git a/systemtest/testdata/testset2/const3.ql.out b/systemtest/testdata/testset2/const3.ql.out
new file mode 100644
index 0000000..c581628
--- /dev/null
+++ b/systemtest/testdata/testset2/const3.ql.out
@@ -0,0 +1,16 @@
+-- Testbed line: result_type=set <marray <ulong, [-2:2,-1:1]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <ulong, [-2:2,-1:1]>
+ Type Schema...........: marray< ulong >
+ Domain................: [-2:2,-1:1]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 60
+ 2 2 2 2 2
+ 2 2 2 2 2
+ 2 2 2 2 2
+-- Testbed end block:
diff --git a/systemtest/testdata/testset2/const4.ql b/systemtest/testdata/testset2/const4.ql
new file mode 100644
index 0000000..6bcb53b
--- /dev/null
+++ b/systemtest/testdata/testset2/const4.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <long, [-2:2,-1:1]>>
+-- Testbed: result_elements=1
+
+select a * -0x1
+from ImgCharMask as a
diff --git a/systemtest/testdata/testset2/const4.ql.java.out b/systemtest/testdata/testset2/const4.ql.java.out
new file mode 100644
index 0000000..d8208e8
--- /dev/null
+++ b/systemtest/testdata/testset2/const4.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayInteger
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [-2:2,-1:1]
+ TilingDomain..........: [0:177,0:177]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 60
+ -1 -1 -1 -2 -1 -1 -1 -2 -1 -1 -1 -2 -1 -1 -1 -2 -1 -1 -1 -2 -1 -1 -1 -2 -1 -1 -1 -2 -1 -1 -1 -2 -1 -1 -1 -2 -1 -1 -1 -2 -1 -1 -1 -2 -1 -1 -1 -2 -1 -1 -1 -2 -1 -1 -1 -2 -1 -1 -1 -2 \ No newline at end of file
diff --git a/systemtest/testdata/testset2/const4.ql.out b/systemtest/testdata/testset2/const4.ql.out
new file mode 100644
index 0000000..247f1fe
--- /dev/null
+++ b/systemtest/testdata/testset2/const4.ql.out
@@ -0,0 +1,16 @@
+-- Testbed line: result_type=set <marray <long, [-2:2,-1:1]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <long, [-2:2,-1:1]>
+ Type Schema...........: marray< long >
+ Domain................: [-2:2,-1:1]
+ Base Type Schema......: long
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 60
+ -2 -2 -2 -2 -2
+ -2 -2 -2 -2 -2
+ -2 -2 -2 -2 -2
+-- Testbed end block:
diff --git a/systemtest/testdata/testset2/const5.ql b/systemtest/testdata/testset2/const5.ql
new file mode 100644
index 0000000..df1dfbf
--- /dev/null
+++ b/systemtest/testdata/testset2/const5.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <octet, [-2:2,-1:1]>>
+-- Testbed: result_elements=1
+
+select a + 1o
+from ImgCharMask as a
diff --git a/systemtest/testdata/testset2/const5.ql.java.out b/systemtest/testdata/testset2/const5.ql.java.out
new file mode 100644
index 0000000..ed610fa
--- /dev/null
+++ b/systemtest/testdata/testset2/const5.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [-2:2,-1:1]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 15
+ 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 \ No newline at end of file
diff --git a/systemtest/testdata/testset2/const5.ql.out b/systemtest/testdata/testset2/const5.ql.out
new file mode 100644
index 0000000..203db73
--- /dev/null
+++ b/systemtest/testdata/testset2/const5.ql.out
@@ -0,0 +1,16 @@
+-- Testbed line: result_type=set <marray <octet, [-2:2,-1:1]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <octet, [-2:2,-1:1]>
+ Type Schema...........: marray< octet >
+ Domain................: [-2:2,-1:1]
+ Base Type Schema......: octet
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 15
+ 3 3 3 3 3
+ 3 3 3 3 3
+ 3 3 3 3 3
+-- Testbed end block:
diff --git a/systemtest/testdata/testset2/const6.ql b/systemtest/testdata/testset2/const6.ql
new file mode 100644
index 0000000..bd62a70
--- /dev/null
+++ b/systemtest/testdata/testset2/const6.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <float, [-2:2,-1:1]>>
+-- Testbed: result_elements=1
+
+select a + 1.0f
+from ImgCharMask as a
diff --git a/systemtest/testdata/testset2/const6.ql.java.out b/systemtest/testdata/testset2/const6.ql.java.out
new file mode 100644
index 0000000..06b1698
--- /dev/null
+++ b/systemtest/testdata/testset2/const6.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayFloat
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [-2:2,-1:1]
+ TilingDomain..........: [0:177,0:177]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 60
+ 64 64 0 0 64 64 0 0 64 64 0 0 64 64 0 0 64 64 0 0 64 64 0 0 64 64 0 0 64 64 0 0 64 64 0 0 64 64 0 0 64 64 0 0 64 64 0 0 64 64 0 0 64 64 0 0 64 64 0 0 \ No newline at end of file
diff --git a/systemtest/testdata/testset2/const6.ql.out b/systemtest/testdata/testset2/const6.ql.out
new file mode 100644
index 0000000..5ba865c
--- /dev/null
+++ b/systemtest/testdata/testset2/const6.ql.out
@@ -0,0 +1,16 @@
+-- Testbed line: result_type=set <marray <float, [-2:2,-1:1]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <float, [-2:2,-1:1]>
+ Type Schema...........: marray< float >
+ Domain................: [-2:2,-1:1]
+ Base Type Schema......: float
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 60
+ 3 3 3 3 3
+ 3 3 3 3 3
+ 3 3 3 3 3
+-- Testbed end block:
diff --git a/systemtest/testdata/testset2/const7.ql b/systemtest/testdata/testset2/const7.ql
new file mode 100644
index 0000000..813115d
--- /dev/null
+++ b/systemtest/testdata/testset2/const7.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <float, [-2:2,-1:1]>>
+-- Testbed: result_elements=1
+
+select a + 1.0
+from ImgCharMask as a
diff --git a/systemtest/testdata/testset2/const7.ql.java.out b/systemtest/testdata/testset2/const7.ql.java.out
new file mode 100644
index 0000000..06b1698
--- /dev/null
+++ b/systemtest/testdata/testset2/const7.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayFloat
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [-2:2,-1:1]
+ TilingDomain..........: [0:177,0:177]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 60
+ 64 64 0 0 64 64 0 0 64 64 0 0 64 64 0 0 64 64 0 0 64 64 0 0 64 64 0 0 64 64 0 0 64 64 0 0 64 64 0 0 64 64 0 0 64 64 0 0 64 64 0 0 64 64 0 0 64 64 0 0 \ No newline at end of file
diff --git a/systemtest/testdata/testset2/const7.ql.out b/systemtest/testdata/testset2/const7.ql.out
new file mode 100644
index 0000000..5ba865c
--- /dev/null
+++ b/systemtest/testdata/testset2/const7.ql.out
@@ -0,0 +1,16 @@
+-- Testbed line: result_type=set <marray <float, [-2:2,-1:1]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <float, [-2:2,-1:1]>
+ Type Schema...........: marray< float >
+ Domain................: [-2:2,-1:1]
+ Base Type Schema......: float
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 60
+ 3 3 3 3 3
+ 3 3 3 3 3
+ 3 3 3 3 3
+-- Testbed end block:
diff --git a/systemtest/testdata/testset2/const8.ql b/systemtest/testdata/testset2/const8.ql
new file mode 100644
index 0000000..9f0f057
--- /dev/null
+++ b/systemtest/testdata/testset2/const8.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <float, [-2:2,-1:1]>>
+-- Testbed: result_elements=1
+
+select a - 1f
+from ImgCharMask as a
diff --git a/systemtest/testdata/testset2/const8.ql.java.out b/systemtest/testdata/testset2/const8.ql.java.out
new file mode 100644
index 0000000..38a2388
--- /dev/null
+++ b/systemtest/testdata/testset2/const8.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayFloat
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [-2:2,-1:1]
+ TilingDomain..........: [0:177,0:177]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 60
+ 63 -128 0 0 63 -128 0 0 63 -128 0 0 63 -128 0 0 63 -128 0 0 63 -128 0 0 63 -128 0 0 63 -128 0 0 63 -128 0 0 63 -128 0 0 63 -128 0 0 63 -128 0 0 63 -128 0 0 63 -128 0 0 63 -128 0 0 \ No newline at end of file
diff --git a/systemtest/testdata/testset2/const8.ql.out b/systemtest/testdata/testset2/const8.ql.out
new file mode 100644
index 0000000..0d4e9e6
--- /dev/null
+++ b/systemtest/testdata/testset2/const8.ql.out
@@ -0,0 +1,16 @@
+-- Testbed line: result_type=set <marray <float, [-2:2,-1:1]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <float, [-2:2,-1:1]>
+ Type Schema...........: marray< float >
+ Domain................: [-2:2,-1:1]
+ Base Type Schema......: float
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 60
+ 1 1 1 1 1
+ 1 1 1 1 1
+ 1 1 1 1 1
+-- Testbed end block:
diff --git a/systemtest/testdata/testset2/const9.ql b/systemtest/testdata/testset2/const9.ql
new file mode 100644
index 0000000..d34db82
--- /dev/null
+++ b/systemtest/testdata/testset2/const9.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <char, [-2:2,-1:1]>>
+-- Testbed: result_elements=1
+
+select a - 1c
+from ImgCharMask as a
diff --git a/systemtest/testdata/testset2/const9.ql.java.out b/systemtest/testdata/testset2/const9.ql.java.out
new file mode 100644
index 0000000..b9f0d3f
--- /dev/null
+++ b/systemtest/testdata/testset2/const9.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [-2:2,-1:1]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 15
+ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 \ No newline at end of file
diff --git a/systemtest/testdata/testset2/const9.ql.out b/systemtest/testdata/testset2/const9.ql.out
new file mode 100644
index 0000000..9887b9e
--- /dev/null
+++ b/systemtest/testdata/testset2/const9.ql.out
@@ -0,0 +1,16 @@
+-- Testbed line: result_type=set <marray <char, [-2:2,-1:1]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [-2:2,-1:1]>
+ Type Schema...........: marray< char >
+ Domain................: [-2:2,-1:1]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 15
+ 1 1 1 1 1
+ 1 1 1 1 1
+ 1 1 1 1 1
+-- Testbed end block:
diff --git a/systemtest/testdata/testset2/constmdd.ql b/systemtest/testdata/testset2/constmdd.ql
new file mode 100644
index 0000000..18bf9ef
--- /dev/null
+++ b/systemtest/testdata/testset2/constmdd.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <char, [-2:2,-1:1]>>
+-- Testbed: result_elements=1
+
+select a + < [-2:2,-1:1] 1c, 2c, 3c; 1c, 2c, 3c; 1c, 2c, 3c; 1c, 2c, 3c; 1c, 2c, 3c >
+from ImgCharMask as a
diff --git a/systemtest/testdata/testset2/constmdd.ql.java.out b/systemtest/testdata/testset2/constmdd.ql.java.out
new file mode 100644
index 0000000..61fe4a5
--- /dev/null
+++ b/systemtest/testdata/testset2/constmdd.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [-2:2,-1:1]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 15
+ 3 4 5 3 4 5 3 4 5 3 4 5 3 4 5 \ No newline at end of file
diff --git a/systemtest/testdata/testset2/constmdd.ql.out b/systemtest/testdata/testset2/constmdd.ql.out
new file mode 100644
index 0000000..98fe471
--- /dev/null
+++ b/systemtest/testdata/testset2/constmdd.ql.out
@@ -0,0 +1,16 @@
+-- Testbed line: result_type=set <marray <char, [-2:2,-1:1]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [-2:2,-1:1]>
+ Type Schema...........: marray< char >
+ Domain................: [-2:2,-1:1]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 15
+ 3 3 3 3 3
+ 4 4 4 4 4
+ 5 5 5 5 5
+-- Testbed end block:
diff --git a/systemtest/testdata/testset2/oid5.ql b/systemtest/testdata/testset2/oid5.ql
new file mode 100644
index 0000000..71b9709
--- /dev/null
+++ b/systemtest/testdata/testset2/oid5.ql
@@ -0,0 +1,6 @@
+-- Testbed: result_type=
+-- Testbed: result_elements=0
+
+select a
+from ImgRGBA as a
+where oid(a) <= 0
diff --git a/systemtest/testdata/testset2/oid5.ql.java.out b/systemtest/testdata/testset2/oid5.ql.java.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/testset2/oid5.ql.java.out
diff --git a/systemtest/testdata/testset2/oid5.ql.out b/systemtest/testdata/testset2/oid5.ql.out
new file mode 100644
index 0000000..bb90a32
--- /dev/null
+++ b/systemtest/testdata/testset2/oid5.ql.out
@@ -0,0 +1,4 @@
+-- Testbed line: result_type=
+-- Testbed line: result_elements=0
+-- Testbed start block:
+-- Testbed end block:
diff --git a/systemtest/testdata/testset2/oid6.ql b/systemtest/testdata/testset2/oid6.ql
new file mode 100644
index 0000000..16f2449
--- /dev/null
+++ b/systemtest/testdata/testset2/oid6.ql
@@ -0,0 +1,6 @@
+-- Testbed: result_type=set <marray <struct { char red, char green, char blue }, [0:10,0:10]>>
+-- Testbed: result_elements=2
+
+select a
+from ImgRGBA as a
+where oid(a) > 0
diff --git a/systemtest/testdata/testset2/oid6.ql.java.out b/systemtest/testdata/testset2/oid6.ql.java.out
new file mode 100644
index 0000000..c039a78
--- /dev/null
+++ b/systemtest/testdata/testset2/oid6.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasGMArray
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:205,0:205]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 3
+ Data format...........: 0
+ Data size (bytes).....: 363
+ 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 \ No newline at end of file
diff --git a/systemtest/testdata/testset2/oid6.ql.out b/systemtest/testdata/testset2/oid6.ql.out
new file mode 100644
index 0000000..79f970f
--- /dev/null
+++ b/systemtest/testdata/testset2/oid6.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <struct { char red, char green, char blue }, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <struct { char red, char green, char blue }, [0:10,0:10]>
+ Type Schema...........: marray< struct{ char red, char green, char blue } >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: struct{ char red, char green, char blue }
+ Base Type Length......: 3
+ Data format.......... : Array
+ Data size (bytes).... : 363
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+Image 2
+GMarray
+ Type Structure........: marray <struct { char red, char green, char blue }, [0:10,0:10]>
+ Type Schema...........: marray< struct{ char red, char green, char blue } >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: struct{ char red, char green, char blue }
+ Base Type Length......: 3
+ Data format.......... : Array
+ Data size (bytes).... : 363
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+{ 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3} { 1, 2, 3}
+-- Testbed end block:
diff --git a/systemtest/testdata/testset3/domexp1.ql b/systemtest/testdata/testset3/domexp1.ql
new file mode 100644
index 0000000..e602045
--- /dev/null
+++ b/systemtest/testdata/testset3/domexp1.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <char, [0:5,0:10]>>
+-- Testbed: result_elements=2
+
+select a[0:5,sdom(a)[1]]
+from ImgCharA as a
diff --git a/systemtest/testdata/testset3/domexp1.ql.java.out b/systemtest/testdata/testset3/domexp1.ql.java.out
new file mode 100644
index 0000000..24fe099
--- /dev/null
+++ b/systemtest/testdata/testset3/domexp1.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:5,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 66
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:5,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 66
+ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 \ No newline at end of file
diff --git a/systemtest/testdata/testset3/domexp1.ql.out b/systemtest/testdata/testset3/domexp1.ql.out
new file mode 100644
index 0000000..9a0b256
--- /dev/null
+++ b/systemtest/testdata/testset3/domexp1.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <char, [0:5,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [0:5,0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:5,0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 66
+ 0 0 0 0 0 0
+ 0 0 0 0 0 0
+ 0 0 0 0 0 0
+ 0 0 0 0 0 0
+ 0 0 0 0 0 0
+ 0 0 0 0 0 0
+ 0 0 0 0 0 0
+ 0 0 0 0 0 0
+ 0 0 0 0 0 0
+ 0 0 0 0 0 0
+ 0 0 0 0 0 0
+Image 2
+GMarray
+ Type Structure........: marray <char, [0:5,0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:5,0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 66
+ 1 1 1 1 1 1
+ 1 1 1 1 1 1
+ 1 1 1 1 1 1
+ 1 1 1 1 1 1
+ 1 1 1 1 1 1
+ 1 1 1 1 1 1
+ 1 1 1 1 1 1
+ 1 1 1 1 1 1
+ 1 1 1 1 1 1
+ 1 1 1 1 1 1
+ 1 1 1 1 1 1
+-- Testbed end block:
diff --git a/systemtest/testdata/testset3/domexp2.ql b/systemtest/testdata/testset3/domexp2.ql
new file mode 100644
index 0000000..2e997d6
--- /dev/null
+++ b/systemtest/testdata/testset3/domexp2.ql
@@ -0,0 +1,6 @@
+-- Testbed: result_type=set <marray <char, [0:10,0:9]>>
+-- Testbed: result_elements=2
+
+select a [sdom(a)[0], *:sdom(a)[1].hi - 1]
+from ImgCharA as a
+
diff --git a/systemtest/testdata/testset3/domexp2.ql.java.out b/systemtest/testdata/testset3/domexp2.ql.java.out
new file mode 100644
index 0000000..2407813
--- /dev/null
+++ b/systemtest/testdata/testset3/domexp2.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:9]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 110
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:9]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 110
+ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 \ No newline at end of file
diff --git a/systemtest/testdata/testset3/domexp2.ql.out b/systemtest/testdata/testset3/domexp2.ql.out
new file mode 100644
index 0000000..b99539f
--- /dev/null
+++ b/systemtest/testdata/testset3/domexp2.ql.out
@@ -0,0 +1,42 @@
+-- Testbed line: result_type=set <marray <char, [0:10,0:9]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [0:10,0:9]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10,0:9]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 110
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+Image 2
+GMarray
+ Type Structure........: marray <char, [0:10,0:9]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10,0:9]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 110
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+-- Testbed end block:
diff --git a/systemtest/testdata/testset3/domexp3.ql b/systemtest/testdata/testset3/domexp3.ql
new file mode 100644
index 0000000..b6025f6
--- /dev/null
+++ b/systemtest/testdata/testset3/domexp3.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <char, [0:10,0:5]>>
+-- Testbed: result_elements=2
+
+select a[*:*, *:sdom(a)[1].hi/2]
+from ImgCharA as a
diff --git a/systemtest/testdata/testset3/domexp3.ql.java.out b/systemtest/testdata/testset3/domexp3.ql.java.out
new file mode 100644
index 0000000..982a34e
--- /dev/null
+++ b/systemtest/testdata/testset3/domexp3.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:5]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 66
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:5]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 66
+ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 \ No newline at end of file
diff --git a/systemtest/testdata/testset3/domexp3.ql.out b/systemtest/testdata/testset3/domexp3.ql.out
new file mode 100644
index 0000000..879e054
--- /dev/null
+++ b/systemtest/testdata/testset3/domexp3.ql.out
@@ -0,0 +1,34 @@
+-- Testbed line: result_type=set <marray <char, [0:10,0:5]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [0:10,0:5]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10,0:5]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 66
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+Image 2
+GMarray
+ Type Structure........: marray <char, [0:10,0:5]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10,0:5]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 66
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+-- Testbed end block:
diff --git a/systemtest/testdata/testset3/domexp4.ql b/systemtest/testdata/testset3/domexp4.ql
new file mode 100644
index 0000000..695d355
--- /dev/null
+++ b/systemtest/testdata/testset3/domexp4.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <char, [0:10]>>
+-- Testbed: result_elements=2
+
+select a[*:*, (sdom(a)[1].hi-sdom(a)[1].lo)/2 ]
+from ImgCharA as a
diff --git a/systemtest/testdata/testset3/domexp4.ql.java.out b/systemtest/testdata/testset3/domexp4.ql.java.out
new file mode 100644
index 0000000..c4c4737
--- /dev/null
+++ b/systemtest/testdata/testset3/domexp4.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 11
+ 0 0 0 0 0 0 0 0 0 0 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 11
+ 1 1 1 1 1 1 1 1 1 1 1 \ No newline at end of file
diff --git a/systemtest/testdata/testset3/domexp4.ql.out b/systemtest/testdata/testset3/domexp4.ql.out
new file mode 100644
index 0000000..495b98f
--- /dev/null
+++ b/systemtest/testdata/testset3/domexp4.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <char, [0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 11
+ 0 0 0 0 0 0 0 0 0 0 0
+Image 2
+GMarray
+ Type Structure........: marray <char, [0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 11
+ 1 1 1 1 1 1 1 1 1 1 1
+-- Testbed end block:
diff --git a/systemtest/testdata/testset3/domexp5.ql b/systemtest/testdata/testset3/domexp5.ql
new file mode 100644
index 0000000..ac141b2
--- /dev/null
+++ b/systemtest/testdata/testset3/domexp5.ql
@@ -0,0 +1,6 @@
+-- Testbed: result_type=set <marray <char, [0:10,4:7]>>
+-- Testbed: result_elements=2
+
+select (a[sdom(a)[0],2:8])[*:*,4:sdom(a)[1].hi - 3]
+from ImgCharA as a
+
diff --git a/systemtest/testdata/testset3/domexp5.ql.java.out b/systemtest/testdata/testset3/domexp5.ql.java.out
new file mode 100644
index 0000000..d5172a6
--- /dev/null
+++ b/systemtest/testdata/testset3/domexp5.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,4:7]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 44
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,4:7]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 44
+ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 \ No newline at end of file
diff --git a/systemtest/testdata/testset3/domexp5.ql.out b/systemtest/testdata/testset3/domexp5.ql.out
new file mode 100644
index 0000000..d106168
--- /dev/null
+++ b/systemtest/testdata/testset3/domexp5.ql.out
@@ -0,0 +1,30 @@
+-- Testbed line: result_type=set <marray <char, [0:10,4:7]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [0:10,4:7]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10,4:7]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 44
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+Image 2
+GMarray
+ Type Structure........: marray <char, [0:10,4:7]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10,4:7]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 44
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+-- Testbed end block:
diff --git a/systemtest/testdata/testset3/minterval1.ql b/systemtest/testdata/testset3/minterval1.ql
new file mode 100644
index 0000000..86e2b0e
--- /dev/null
+++ b/systemtest/testdata/testset3/minterval1.ql
@@ -0,0 +1,6 @@
+-- Testbed: result_type=set <marray <char, [0:4,0:3]>>
+-- Testbed: result_elements=2
+
+select a[0:1*4,0:3]*2c
+from ImgCharA as a
+
diff --git a/systemtest/testdata/testset3/minterval1.ql.java.out b/systemtest/testdata/testset3/minterval1.ql.java.out
new file mode 100644
index 0000000..88b67fe
--- /dev/null
+++ b/systemtest/testdata/testset3/minterval1.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:4,0:3]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 20
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:4,0:3]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 20
+ 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 \ No newline at end of file
diff --git a/systemtest/testdata/testset3/minterval1.ql.out b/systemtest/testdata/testset3/minterval1.ql.out
new file mode 100644
index 0000000..e5ea4ff
--- /dev/null
+++ b/systemtest/testdata/testset3/minterval1.ql.out
@@ -0,0 +1,30 @@
+-- Testbed line: result_type=set <marray <char, [0:4,0:3]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [0:4,0:3]>
+ Type Schema...........: marray< char >
+ Domain................: [0:4,0:3]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 20
+ 0 0 0 0 0
+ 0 0 0 0 0
+ 0 0 0 0 0
+ 0 0 0 0 0
+Image 2
+GMarray
+ Type Structure........: marray <char, [0:4,0:3]>
+ Type Schema...........: marray< char >
+ Domain................: [0:4,0:3]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 20
+ 2 2 2 2 2
+ 2 2 2 2 2
+ 2 2 2 2 2
+ 2 2 2 2 2
+-- Testbed end block:
diff --git a/systemtest/testdata/testset3/proj1.ql b/systemtest/testdata/testset3/proj1.ql
new file mode 100644
index 0000000..55ccf98
--- /dev/null
+++ b/systemtest/testdata/testset3/proj1.ql
@@ -0,0 +1,6 @@
+-- Testbed: result_type=set <marray <char, [0:10]>>
+-- Testbed: result_elements=2
+
+select a[*:*, 5]
+from ImgCharA as a
+
diff --git a/systemtest/testdata/testset3/proj1.ql.java.out b/systemtest/testdata/testset3/proj1.ql.java.out
new file mode 100644
index 0000000..c4c4737
--- /dev/null
+++ b/systemtest/testdata/testset3/proj1.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 11
+ 0 0 0 0 0 0 0 0 0 0 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 11
+ 1 1 1 1 1 1 1 1 1 1 1 \ No newline at end of file
diff --git a/systemtest/testdata/testset3/proj1.ql.out b/systemtest/testdata/testset3/proj1.ql.out
new file mode 100644
index 0000000..495b98f
--- /dev/null
+++ b/systemtest/testdata/testset3/proj1.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <char, [0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 11
+ 0 0 0 0 0 0 0 0 0 0 0
+Image 2
+GMarray
+ Type Structure........: marray <char, [0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 11
+ 1 1 1 1 1 1 1 1 1 1 1
+-- Testbed end block:
diff --git a/systemtest/testdata/testset3/proj2.ql b/systemtest/testdata/testset3/proj2.ql
new file mode 100644
index 0000000..21d51fd
--- /dev/null
+++ b/systemtest/testdata/testset3/proj2.ql
@@ -0,0 +1,6 @@
+-- Testbed: result_type=set <marray <char, [0:10]>>
+-- Testbed: result_elements=2
+
+select a[2,*:*]
+from ImgCharA as a
+
diff --git a/systemtest/testdata/testset3/proj2.ql.java.out b/systemtest/testdata/testset3/proj2.ql.java.out
new file mode 100644
index 0000000..c4c4737
--- /dev/null
+++ b/systemtest/testdata/testset3/proj2.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 11
+ 0 0 0 0 0 0 0 0 0 0 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 11
+ 1 1 1 1 1 1 1 1 1 1 1 \ No newline at end of file
diff --git a/systemtest/testdata/testset3/proj2.ql.out b/systemtest/testdata/testset3/proj2.ql.out
new file mode 100644
index 0000000..495b98f
--- /dev/null
+++ b/systemtest/testdata/testset3/proj2.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <char, [0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 11
+ 0 0 0 0 0 0 0 0 0 0 0
+Image 2
+GMarray
+ Type Structure........: marray <char, [0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 11
+ 1 1 1 1 1 1 1 1 1 1 1
+-- Testbed end block:
diff --git a/systemtest/testdata/testset3/proj3.ql b/systemtest/testdata/testset3/proj3.ql
new file mode 100644
index 0000000..3448f5b
--- /dev/null
+++ b/systemtest/testdata/testset3/proj3.ql
@@ -0,0 +1,6 @@
+-- Testbed: result_type=set <marray <char, [5:10]>>
+-- Testbed: result_elements=2
+
+select a[(5:10).lo:10, 5]
+from ImgCharA as a
+
diff --git a/systemtest/testdata/testset3/proj3.ql.java.out b/systemtest/testdata/testset3/proj3.ql.java.out
new file mode 100644
index 0000000..36eaaa0
--- /dev/null
+++ b/systemtest/testdata/testset3/proj3.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [5:10]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 6
+ 0 0 0 0 0 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [5:10]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 6
+ 1 1 1 1 1 1 \ No newline at end of file
diff --git a/systemtest/testdata/testset3/proj3.ql.out b/systemtest/testdata/testset3/proj3.ql.out
new file mode 100644
index 0000000..d6c637b
--- /dev/null
+++ b/systemtest/testdata/testset3/proj3.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <char, [5:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [5:10]>
+ Type Schema...........: marray< char >
+ Domain................: [5:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 6
+ 0 0 0 0 0 0
+Image 2
+GMarray
+ Type Structure........: marray <char, [5:10]>
+ Type Schema...........: marray< char >
+ Domain................: [5:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 6
+ 1 1 1 1 1 1
+-- Testbed end block:
diff --git a/systemtest/testdata/testset3/proj4.ql b/systemtest/testdata/testset3/proj4.ql
new file mode 100644
index 0000000..48500e3
--- /dev/null
+++ b/systemtest/testdata/testset3/proj4.ql
@@ -0,0 +1,6 @@
+-- Testbed: result_type=set <marray <char, [5:10]>>
+-- Testbed: result_elements=2
+
+select a[(5:10).lo, 5:10]
+from ImgCharA as a
+
diff --git a/systemtest/testdata/testset3/proj4.ql.java.out b/systemtest/testdata/testset3/proj4.ql.java.out
new file mode 100644
index 0000000..36eaaa0
--- /dev/null
+++ b/systemtest/testdata/testset3/proj4.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [5:10]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 6
+ 0 0 0 0 0 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [5:10]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 6
+ 1 1 1 1 1 1 \ No newline at end of file
diff --git a/systemtest/testdata/testset3/proj4.ql.out b/systemtest/testdata/testset3/proj4.ql.out
new file mode 100644
index 0000000..d6c637b
--- /dev/null
+++ b/systemtest/testdata/testset3/proj4.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <char, [5:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [5:10]>
+ Type Schema...........: marray< char >
+ Domain................: [5:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 6
+ 0 0 0 0 0 0
+Image 2
+GMarray
+ Type Structure........: marray <char, [5:10]>
+ Type Schema...........: marray< char >
+ Domain................: [5:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 6
+ 1 1 1 1 1 1
+-- Testbed end block:
diff --git a/systemtest/testdata/testset3/proj5.ql b/systemtest/testdata/testset3/proj5.ql
new file mode 100644
index 0000000..63d402e
--- /dev/null
+++ b/systemtest/testdata/testset3/proj5.ql
@@ -0,0 +1,6 @@
+-- Testbed: result_type=set <marray <char, [0:10]>>
+-- Testbed: result_elements=2
+
+select (a[*:*,2:8])[*:*,5]
+from ImgCharA as a
+
diff --git a/systemtest/testdata/testset3/proj5.ql.java.out b/systemtest/testdata/testset3/proj5.ql.java.out
new file mode 100644
index 0000000..c4c4737
--- /dev/null
+++ b/systemtest/testdata/testset3/proj5.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 11
+ 0 0 0 0 0 0 0 0 0 0 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10]
+ TilingDomain..........: [0:127999]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 11
+ 1 1 1 1 1 1 1 1 1 1 1 \ No newline at end of file
diff --git a/systemtest/testdata/testset3/proj5.ql.out b/systemtest/testdata/testset3/proj5.ql.out
new file mode 100644
index 0000000..495b98f
--- /dev/null
+++ b/systemtest/testdata/testset3/proj5.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <char, [0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 11
+ 0 0 0 0 0 0 0 0 0 0 0
+Image 2
+GMarray
+ Type Structure........: marray <char, [0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 11
+ 1 1 1 1 1 1 1 1 1 1 1
+-- Testbed end block:
diff --git a/systemtest/testdata/testset3/proj6.ql b/systemtest/testdata/testset3/proj6.ql
new file mode 100644
index 0000000..3cc3aaf
--- /dev/null
+++ b/systemtest/testdata/testset3/proj6.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <ulong, [0:10,0:10]>>
+-- Testbed: result_elements=2
+
+select a[5,0] * b
+from ImgULongC as a, ImgCharA as b
diff --git a/systemtest/testdata/testset3/proj6.ql.java.out b/systemtest/testdata/testset3/proj6.ql.java.out
new file mode 100644
index 0000000..620e52c
--- /dev/null
+++ b/systemtest/testdata/testset3/proj6.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayLong
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 968
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+rasj.RasMArrayLong
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 968
+ 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 5 \ No newline at end of file
diff --git a/systemtest/testdata/testset3/proj6.ql.out b/systemtest/testdata/testset3/proj6.ql.out
new file mode 100644
index 0000000..6fd700a
--- /dev/null
+++ b/systemtest/testdata/testset3/proj6.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <ulong, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <ulong, [0:10,0:10]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 484
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+Image 2
+GMarray
+ Type Structure........: marray <ulong, [0:10,0:10]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 484
+ 5 5 5 5 5 5 5 5 5 5 5
+ 5 5 5 5 5 5 5 5 5 5 5
+ 5 5 5 5 5 5 5 5 5 5 5
+ 5 5 5 5 5 5 5 5 5 5 5
+ 5 5 5 5 5 5 5 5 5 5 5
+ 5 5 5 5 5 5 5 5 5 5 5
+ 5 5 5 5 5 5 5 5 5 5 5
+ 5 5 5 5 5 5 5 5 5 5 5
+ 5 5 5 5 5 5 5 5 5 5 5
+ 5 5 5 5 5 5 5 5 5 5 5
+ 5 5 5 5 5 5 5 5 5 5 5
+-- Testbed end block:
diff --git a/systemtest/testdata/testset3/sdom1.ql b/systemtest/testdata/testset3/sdom1.ql
new file mode 100644
index 0000000..b59d595
--- /dev/null
+++ b/systemtest/testdata/testset3/sdom1.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <char, [0:10,0:10]>>
+-- Testbed: result_elements=2
+
+select a sdom(a)
+from ImgCharA as a
diff --git a/systemtest/testdata/testset3/sdom1.ql.java.out b/systemtest/testdata/testset3/sdom1.ql.java.out
new file mode 100644
index 0000000..f2deb7a
--- /dev/null
+++ b/systemtest/testdata/testset3/sdom1.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 \ No newline at end of file
diff --git a/systemtest/testdata/testset3/sdom1.ql.out b/systemtest/testdata/testset3/sdom1.ql.out
new file mode 100644
index 0000000..8e3e87c
--- /dev/null
+++ b/systemtest/testdata/testset3/sdom1.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <char, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [0:10,0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+Image 2
+GMarray
+ Type Structure........: marray <char, [0:10,0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+-- Testbed end block:
diff --git a/systemtest/testdata/testset3/shift1.ql b/systemtest/testdata/testset3/shift1.ql
new file mode 100644
index 0000000..715d94b
--- /dev/null
+++ b/systemtest/testdata/testset3/shift1.ql
@@ -0,0 +1,2 @@
+select shift( a, [5,10] )
+from ImgCharD as a
diff --git a/systemtest/testdata/testset3/shift1.ql.java.out b/systemtest/testdata/testset3/shift1.ql.java.out
new file mode 100644
index 0000000..0a6d6a5
--- /dev/null
+++ b/systemtest/testdata/testset3/shift1.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [5:15,10:20]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 0 11 22 33 44 55 66 77 88 99 110 1 12 23 34 45 56 67 78 89 100 111 2 13 24 35 46 57 68 79 90 101 112 3 14 25 36 47 58 69 80 91 102 113 4 15 26 37 48 59 70 81 92 103 114 5 16 27 38 49 60 71 82 93 104 115 6 17 28 39 50 61 72 83 94 105 116 7 18 29 40 51 62 73 84 95 106 117 8 19 30 41 52 63 74 85 96 107 118 9 20 31 42 53 64 75 86 97 108 119 10 21 32 43 54 65 76 87 98 109 120 \ No newline at end of file
diff --git a/systemtest/testdata/testset3/shift1.ql.out b/systemtest/testdata/testset3/shift1.ql.out
new file mode 100644
index 0000000..7422eb4
--- /dev/null
+++ b/systemtest/testdata/testset3/shift1.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <char, [5:15,10:20]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [5:15,10:20]>
+ Type Schema...........: marray< char >
+ Domain................: [5:15,10:20]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ 0 1 2 3 4 5 6 7 8 9 10
+ 11 12 13 14 15 16 17 18 19 20 21
+ 22 23 24 25 26 27 28 29 30 31 32
+ 33 34 35 36 37 38 39 40 41 42 43
+ 44 45 46 47 48 49 50 51 52 53 54
+ 55 56 57 58 59 60 61 62 63 64 65
+ 66 67 68 69 70 71 72 73 74 75 76
+ 77 78 79 80 81 82 83 84 85 86 87
+ 88 89 90 91 92 93 94 95 96 97 98
+ 99 100 101 102 103 104 105 106 107 108 109
+ 110 111 112 113 114 115 116 117 118 119 120
+-- Testbed end block:
diff --git a/systemtest/testdata/testset3/shift2.ql b/systemtest/testdata/testset3/shift2.ql
new file mode 100644
index 0000000..9c2abcd
--- /dev/null
+++ b/systemtest/testdata/testset3/shift2.ql
@@ -0,0 +1,2 @@
+select shift( a*2c, [5,10] )
+from ImgCharD as a
diff --git a/systemtest/testdata/testset3/shift2.ql.java.out b/systemtest/testdata/testset3/shift2.ql.java.out
new file mode 100644
index 0000000..c3eb53d
--- /dev/null
+++ b/systemtest/testdata/testset3/shift2.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [5:15,10:20]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 0 22 44 66 88 110 -124 -102 -80 -58 -36 2 24 46 68 90 112 -122 -100 -78 -56 -34 4 26 48 70 92 114 -120 -98 -76 -54 -32 6 28 50 72 94 116 -118 -96 -74 -52 -30 8 30 52 74 96 118 -116 -94 -72 -50 -28 10 32 54 76 98 120 -114 -92 -70 -48 -26 12 34 56 78 100 122 -112 -90 -68 -46 -24 14 36 58 80 102 124 -110 -88 -66 -44 -22 16 38 60 82 104 126 -108 -86 -64 -42 -20 18 40 62 84 106 -128 -106 -84 -62 -40 -18 20 42 64 86 108 -126 -104 -82 -60 -38 -16 \ No newline at end of file
diff --git a/systemtest/testdata/testset3/shift2.ql.out b/systemtest/testdata/testset3/shift2.ql.out
new file mode 100644
index 0000000..286db80
--- /dev/null
+++ b/systemtest/testdata/testset3/shift2.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <char, [5:15,10:20]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [5:15,10:20]>
+ Type Schema...........: marray< char >
+ Domain................: [5:15,10:20]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ 0 2 4 6 8 10 12 14 16 18 20
+ 22 24 26 28 30 32 34 36 38 40 42
+ 44 46 48 50 52 54 56 58 60 62 64
+ 66 68 70 72 74 76 78 80 82 84 86
+ 88 90 92 94 96 98 100 102 104 106 108
+ 110 112 114 116 118 120 122 124 126 128 130
+ 132 134 136 138 140 142 144 146 148 150 152
+ 154 156 158 160 162 164 166 168 170 172 174
+ 176 178 180 182 184 186 188 190 192 194 196
+ 198 200 202 204 206 208 210 212 214 216 218
+ 220 222 224 226 228 230 232 234 236 238 240
+-- Testbed end block:
diff --git a/systemtest/testdata/testset3/shift3.ql b/systemtest/testdata/testset3/shift3.ql
new file mode 100644
index 0000000..c753d4b
--- /dev/null
+++ b/systemtest/testdata/testset3/shift3.ql
@@ -0,0 +1,2 @@
+select shift( a, [5,5] )[5:10,5:10]
+from ImgCharD as a
diff --git a/systemtest/testdata/testset3/shift3.ql.java.out b/systemtest/testdata/testset3/shift3.ql.java.out
new file mode 100644
index 0000000..61bf3f5
--- /dev/null
+++ b/systemtest/testdata/testset3/shift3.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [5:10,5:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 36
+ 0 11 22 33 44 55 1 12 23 34 45 56 2 13 24 35 46 57 3 14 25 36 47 58 4 15 26 37 48 59 5 16 27 38 49 60 \ No newline at end of file
diff --git a/systemtest/testdata/testset3/shift3.ql.out b/systemtest/testdata/testset3/shift3.ql.out
new file mode 100644
index 0000000..a52fe1a
--- /dev/null
+++ b/systemtest/testdata/testset3/shift3.ql.out
@@ -0,0 +1,19 @@
+-- Testbed line: result_type=set <marray <char, [5:10,5:10]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [5:10,5:10]>
+ Type Schema...........: marray< char >
+ Domain................: [5:10,5:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 36
+ 0 1 2 3 4 5
+ 11 12 13 14 15 16
+ 22 23 24 25 26 27
+ 33 34 35 36 37 38
+ 44 45 46 47 48 49
+ 55 56 57 58 59 60
+-- Testbed end block:
diff --git a/systemtest/testdata/testset3/shift4.ql b/systemtest/testdata/testset3/shift4.ql
new file mode 100644
index 0000000..677d9e3
--- /dev/null
+++ b/systemtest/testdata/testset3/shift4.ql
@@ -0,0 +1,2 @@
+select shift( a[5:10,5:10], [5,10] )
+from ImgCharD as a
diff --git a/systemtest/testdata/testset3/shift4.ql.java.out b/systemtest/testdata/testset3/shift4.ql.java.out
new file mode 100644
index 0000000..130def3
--- /dev/null
+++ b/systemtest/testdata/testset3/shift4.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [10:15,15:20]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 36
+ 60 71 82 93 104 115 61 72 83 94 105 116 62 73 84 95 106 117 63 74 85 96 107 118 64 75 86 97 108 119 65 76 87 98 109 120 \ No newline at end of file
diff --git a/systemtest/testdata/testset3/shift4.ql.out b/systemtest/testdata/testset3/shift4.ql.out
new file mode 100644
index 0000000..97d421b
--- /dev/null
+++ b/systemtest/testdata/testset3/shift4.ql.out
@@ -0,0 +1,19 @@
+-- Testbed line: result_type=set <marray <char, [10:15,15:20]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [10:15,15:20]>
+ Type Schema...........: marray< char >
+ Domain................: [10:15,15:20]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 36
+ 60 61 62 63 64 65
+ 71 72 73 74 75 76
+ 82 83 84 85 86 87
+ 93 94 95 96 97 98
+ 104 105 106 107 108 109
+ 115 116 117 118 119 120
+-- Testbed end block:
diff --git a/systemtest/testdata/testset3/shift41.ql b/systemtest/testdata/testset3/shift41.ql
new file mode 100644
index 0000000..03ae88b
--- /dev/null
+++ b/systemtest/testdata/testset3/shift41.ql
@@ -0,0 +1,2 @@
+select shift( a[5:*,5:*], [5,10] )
+from ImgCharD as a
diff --git a/systemtest/testdata/testset3/shift41.ql.java.out b/systemtest/testdata/testset3/shift41.ql.java.out
new file mode 100644
index 0000000..130def3
--- /dev/null
+++ b/systemtest/testdata/testset3/shift41.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [10:15,15:20]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 36
+ 60 71 82 93 104 115 61 72 83 94 105 116 62 73 84 95 106 117 63 74 85 96 107 118 64 75 86 97 108 119 65 76 87 98 109 120 \ No newline at end of file
diff --git a/systemtest/testdata/testset3/shift41.ql.out b/systemtest/testdata/testset3/shift41.ql.out
new file mode 100644
index 0000000..97d421b
--- /dev/null
+++ b/systemtest/testdata/testset3/shift41.ql.out
@@ -0,0 +1,19 @@
+-- Testbed line: result_type=set <marray <char, [10:15,15:20]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [10:15,15:20]>
+ Type Schema...........: marray< char >
+ Domain................: [10:15,15:20]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 36
+ 60 61 62 63 64 65
+ 71 72 73 74 75 76
+ 82 83 84 85 86 87
+ 93 94 95 96 97 98
+ 104 105 106 107 108 109
+ 115 116 117 118 119 120
+-- Testbed end block:
diff --git a/systemtest/testdata/testset3/trim1.ql b/systemtest/testdata/testset3/trim1.ql
new file mode 100644
index 0000000..9c7c048
--- /dev/null
+++ b/systemtest/testdata/testset3/trim1.ql
@@ -0,0 +1,6 @@
+-- Testbed: result_type=set <marray <char, [0:10,0:10]>>
+-- Testbed: result_elements=2
+
+select a[*:*, *:*]
+from ImgCharA as a
+
diff --git a/systemtest/testdata/testset3/trim1.ql.java.out b/systemtest/testdata/testset3/trim1.ql.java.out
new file mode 100644
index 0000000..f2deb7a
--- /dev/null
+++ b/systemtest/testdata/testset3/trim1.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 121
+ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 \ No newline at end of file
diff --git a/systemtest/testdata/testset3/trim1.ql.out b/systemtest/testdata/testset3/trim1.ql.out
new file mode 100644
index 0000000..8e3e87c
--- /dev/null
+++ b/systemtest/testdata/testset3/trim1.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <char, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [0:10,0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+Image 2
+GMarray
+ Type Structure........: marray <char, [0:10,0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 121
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+-- Testbed end block:
diff --git a/systemtest/testdata/testset3/trim2.ql b/systemtest/testdata/testset3/trim2.ql
new file mode 100644
index 0000000..7318b2e
--- /dev/null
+++ b/systemtest/testdata/testset3/trim2.ql
@@ -0,0 +1,6 @@
+-- Testbed: result_type=set <marray <char, [2:6,1:3]>>
+-- Testbed: result_elements=2
+
+select a[2:6, 1:3]
+from ImgCharA as a
+
diff --git a/systemtest/testdata/testset3/trim2.ql.java.out b/systemtest/testdata/testset3/trim2.ql.java.out
new file mode 100644
index 0000000..059ae11
--- /dev/null
+++ b/systemtest/testdata/testset3/trim2.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [2:6,1:3]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 15
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [2:6,1:3]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 15
+ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 \ No newline at end of file
diff --git a/systemtest/testdata/testset3/trim2.ql.out b/systemtest/testdata/testset3/trim2.ql.out
new file mode 100644
index 0000000..0f287f9
--- /dev/null
+++ b/systemtest/testdata/testset3/trim2.ql.out
@@ -0,0 +1,28 @@
+-- Testbed line: result_type=set <marray <char, [2:6,1:3]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [2:6,1:3]>
+ Type Schema...........: marray< char >
+ Domain................: [2:6,1:3]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 15
+ 0 0 0 0 0
+ 0 0 0 0 0
+ 0 0 0 0 0
+Image 2
+GMarray
+ Type Structure........: marray <char, [2:6,1:3]>
+ Type Schema...........: marray< char >
+ Domain................: [2:6,1:3]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 15
+ 1 1 1 1 1
+ 1 1 1 1 1
+ 1 1 1 1 1
+-- Testbed end block:
diff --git a/systemtest/testdata/testset3/trim3.ql b/systemtest/testdata/testset3/trim3.ql
new file mode 100644
index 0000000..88c7600
--- /dev/null
+++ b/systemtest/testdata/testset3/trim3.ql
@@ -0,0 +1,6 @@
+-- Testbed: result_type=set <marray <char, [5:10,0:10]>>
+-- Testbed: result_elements=2
+
+select a[(5:10).lo : 10, *:*]
+from ImgCharA as a
+
diff --git a/systemtest/testdata/testset3/trim3.ql.java.out b/systemtest/testdata/testset3/trim3.ql.java.out
new file mode 100644
index 0000000..ea59e7a
--- /dev/null
+++ b/systemtest/testdata/testset3/trim3.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [5:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 66
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [5:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 66
+ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 \ No newline at end of file
diff --git a/systemtest/testdata/testset3/trim3.ql.out b/systemtest/testdata/testset3/trim3.ql.out
new file mode 100644
index 0000000..1d7e80d
--- /dev/null
+++ b/systemtest/testdata/testset3/trim3.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <char, [5:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [5:10,0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [5:10,0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 66
+ 0 0 0 0 0 0
+ 0 0 0 0 0 0
+ 0 0 0 0 0 0
+ 0 0 0 0 0 0
+ 0 0 0 0 0 0
+ 0 0 0 0 0 0
+ 0 0 0 0 0 0
+ 0 0 0 0 0 0
+ 0 0 0 0 0 0
+ 0 0 0 0 0 0
+ 0 0 0 0 0 0
+Image 2
+GMarray
+ Type Structure........: marray <char, [5:10,0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [5:10,0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 66
+ 1 1 1 1 1 1
+ 1 1 1 1 1 1
+ 1 1 1 1 1 1
+ 1 1 1 1 1 1
+ 1 1 1 1 1 1
+ 1 1 1 1 1 1
+ 1 1 1 1 1 1
+ 1 1 1 1 1 1
+ 1 1 1 1 1 1
+ 1 1 1 1 1 1
+ 1 1 1 1 1 1
+-- Testbed end block:
diff --git a/systemtest/testdata/testset3/trim4.ql b/systemtest/testdata/testset3/trim4.ql
new file mode 100644
index 0000000..b916e52
--- /dev/null
+++ b/systemtest/testdata/testset3/trim4.ql
@@ -0,0 +1,6 @@
+-- Testbed: result_type=set <marray <char, [6:10,0:10]>>
+-- Testbed: result_elements=2
+
+select a[(5:6).hi : 10, *:*]
+from ImgCharA as a
+
diff --git a/systemtest/testdata/testset3/trim4.ql.java.out b/systemtest/testdata/testset3/trim4.ql.java.out
new file mode 100644
index 0000000..5a35f08
--- /dev/null
+++ b/systemtest/testdata/testset3/trim4.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [6:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 55
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [6:10,0:10]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 55
+ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 \ No newline at end of file
diff --git a/systemtest/testdata/testset3/trim4.ql.out b/systemtest/testdata/testset3/trim4.ql.out
new file mode 100644
index 0000000..80cdb59
--- /dev/null
+++ b/systemtest/testdata/testset3/trim4.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <char, [6:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [6:10,0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [6:10,0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 55
+ 0 0 0 0 0
+ 0 0 0 0 0
+ 0 0 0 0 0
+ 0 0 0 0 0
+ 0 0 0 0 0
+ 0 0 0 0 0
+ 0 0 0 0 0
+ 0 0 0 0 0
+ 0 0 0 0 0
+ 0 0 0 0 0
+ 0 0 0 0 0
+Image 2
+GMarray
+ Type Structure........: marray <char, [6:10,0:10]>
+ Type Schema...........: marray< char >
+ Domain................: [6:10,0:10]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 55
+ 1 1 1 1 1
+ 1 1 1 1 1
+ 1 1 1 1 1
+ 1 1 1 1 1
+ 1 1 1 1 1
+ 1 1 1 1 1
+ 1 1 1 1 1
+ 1 1 1 1 1
+ 1 1 1 1 1
+ 1 1 1 1 1
+ 1 1 1 1 1
+-- Testbed end block:
diff --git a/systemtest/testdata/testset3/trim5.ql b/systemtest/testdata/testset3/trim5.ql
new file mode 100644
index 0000000..b06e25c
--- /dev/null
+++ b/systemtest/testdata/testset3/trim5.ql
@@ -0,0 +1,6 @@
+-- Testbed: result_type=set <marray <char, [0:10,4:6]>>
+-- Testbed: result_elements=2
+
+select (a[*:*,2:8])[*:*,4:6]
+from ImgCharA as a
+
diff --git a/systemtest/testdata/testset3/trim5.ql.java.out b/systemtest/testdata/testset3/trim5.ql.java.out
new file mode 100644
index 0000000..7b7cb2c
--- /dev/null
+++ b/systemtest/testdata/testset3/trim5.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,4:6]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 33
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+rasj.RasMArrayByte
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,4:6]
+ TilingDomain..........: [0:356,0:356]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 1
+ Data format...........: 0
+ Data size (bytes).....: 33
+ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 \ No newline at end of file
diff --git a/systemtest/testdata/testset3/trim5.ql.out b/systemtest/testdata/testset3/trim5.ql.out
new file mode 100644
index 0000000..09d0bd4
--- /dev/null
+++ b/systemtest/testdata/testset3/trim5.ql.out
@@ -0,0 +1,28 @@
+-- Testbed line: result_type=set <marray <char, [0:10,4:6]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <char, [0:10,4:6]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10,4:6]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 33
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+Image 2
+GMarray
+ Type Structure........: marray <char, [0:10,4:6]>
+ Type Schema...........: marray< char >
+ Domain................: [0:10,4:6]
+ Base Type Schema......: char
+ Base Type Length......: 1
+ Data format.......... : Array
+ Data size (bytes).... : 33
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/abs_1.ql b/systemtest/testdata/unaryfunc/abs_1.ql
new file mode 100644
index 0000000..e90ab87
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/abs_1.ql
@@ -0,0 +1,2 @@
+
+ select abs(-1) from ImgCharA -- 1
diff --git a/systemtest/testdata/unaryfunc/abs_1.ql.java.out b/systemtest/testdata/unaryfunc/abs_1.ql.java.out
new file mode 100644
index 0000000..85aae69
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/abs_1.ql.java.out
@@ -0,0 +1 @@
+1.01.0 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/abs_1.ql.out b/systemtest/testdata/unaryfunc/abs_1.ql.out
new file mode 100644
index 0000000..5b5eff0
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/abs_1.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 1
+Element 2: 1
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/abs_2.ql b/systemtest/testdata/unaryfunc/abs_2.ql
new file mode 100644
index 0000000..dd63ead
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/abs_2.ql
@@ -0,0 +1,2 @@
+
+ select abs(-3.141592) from ImgCharA -- pi
diff --git a/systemtest/testdata/unaryfunc/abs_2.ql.java.out b/systemtest/testdata/unaryfunc/abs_2.ql.java.out
new file mode 100644
index 0000000..ac30b53
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/abs_2.ql.java.out
@@ -0,0 +1 @@
+3.1415920257568363.141592025756836 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/abs_2.ql.out b/systemtest/testdata/unaryfunc/abs_2.ql.out
new file mode 100644
index 0000000..eaf926b
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/abs_2.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 3.14159
+Element 2: 3.14159
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/abs_3.ql b/systemtest/testdata/unaryfunc/abs_3.ql
new file mode 100644
index 0000000..35bc3df
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/abs_3.ql
@@ -0,0 +1,2 @@
+
+ select abs(0) from ImgCharA -- 0
diff --git a/systemtest/testdata/unaryfunc/abs_3.ql.java.out b/systemtest/testdata/unaryfunc/abs_3.ql.java.out
new file mode 100644
index 0000000..b2024e1
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/abs_3.ql.java.out
@@ -0,0 +1 @@
+0.00.0 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/abs_3.ql.out b/systemtest/testdata/unaryfunc/abs_3.ql.out
new file mode 100644
index 0000000..eb05dc2
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/abs_3.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 0
+Element 2: 0
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/abs_4.ql b/systemtest/testdata/unaryfunc/abs_4.ql
new file mode 100644
index 0000000..5563163
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/abs_4.ql
@@ -0,0 +1,2 @@
+
+ select abs(-0.0) from ImgCharA -- 0
diff --git a/systemtest/testdata/unaryfunc/abs_4.ql.java.out b/systemtest/testdata/unaryfunc/abs_4.ql.java.out
new file mode 100644
index 0000000..b2024e1
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/abs_4.ql.java.out
@@ -0,0 +1 @@
+0.00.0 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/abs_4.ql.out b/systemtest/testdata/unaryfunc/abs_4.ql.out
new file mode 100644
index 0000000..eb05dc2
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/abs_4.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 0
+Element 2: 0
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/abs_5.ql b/systemtest/testdata/unaryfunc/abs_5.ql
new file mode 100644
index 0000000..9d41e43
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/abs_5.ql
@@ -0,0 +1,2 @@
+
+ select abs(1) from ImgCharA -- 1
diff --git a/systemtest/testdata/unaryfunc/abs_5.ql.java.out b/systemtest/testdata/unaryfunc/abs_5.ql.java.out
new file mode 100644
index 0000000..85aae69
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/abs_5.ql.java.out
@@ -0,0 +1 @@
+1.01.0 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/abs_5.ql.out b/systemtest/testdata/unaryfunc/abs_5.ql.out
new file mode 100644
index 0000000..5b5eff0
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/abs_5.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 1
+Element 2: 1
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/abs_6.ql b/systemtest/testdata/unaryfunc/abs_6.ql
new file mode 100644
index 0000000..00bdaa9
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/abs_6.ql
@@ -0,0 +1,2 @@
+
+ select abs(3.141592) from ImgCharA -- pi
diff --git a/systemtest/testdata/unaryfunc/abs_6.ql.java.out b/systemtest/testdata/unaryfunc/abs_6.ql.java.out
new file mode 100644
index 0000000..ac30b53
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/abs_6.ql.java.out
@@ -0,0 +1 @@
+3.1415920257568363.141592025756836 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/abs_6.ql.out b/systemtest/testdata/unaryfunc/abs_6.ql.out
new file mode 100644
index 0000000..eaf926b
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/abs_6.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 3.14159
+Element 2: 3.14159
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/acos_1.ql b/systemtest/testdata/unaryfunc/acos_1.ql
new file mode 100644
index 0000000..76b54e7
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/acos_1.ql
@@ -0,0 +1,2 @@
+
+ select arccos(-1) from ImgCharA -- pi
diff --git a/systemtest/testdata/unaryfunc/acos_1.ql.java.out b/systemtest/testdata/unaryfunc/acos_1.ql.java.out
new file mode 100644
index 0000000..8144360
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/acos_1.ql.java.out
@@ -0,0 +1 @@
+3.1415926535897933.141592653589793 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/acos_1.ql.out b/systemtest/testdata/unaryfunc/acos_1.ql.out
new file mode 100644
index 0000000..eaf926b
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/acos_1.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 3.14159
+Element 2: 3.14159
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/acos_2.ql b/systemtest/testdata/unaryfunc/acos_2.ql
new file mode 100644
index 0000000..c3abe5f
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/acos_2.ql
@@ -0,0 +1,2 @@
+
+ select 2 * arccos(-0) from ImgCharA -- pi
diff --git a/systemtest/testdata/unaryfunc/acos_2.ql.java.out b/systemtest/testdata/unaryfunc/acos_2.ql.java.out
new file mode 100644
index 0000000..8144360
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/acos_2.ql.java.out
@@ -0,0 +1 @@
+3.1415926535897933.141592653589793 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/acos_2.ql.out b/systemtest/testdata/unaryfunc/acos_2.ql.out
new file mode 100644
index 0000000..eaf926b
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/acos_2.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 3.14159
+Element 2: 3.14159
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/acos_3.ql b/systemtest/testdata/unaryfunc/acos_3.ql
new file mode 100644
index 0000000..78a0d31
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/acos_3.ql
@@ -0,0 +1,2 @@
+
+ select 2*arccos(0) from ImgCharA -- pi
diff --git a/systemtest/testdata/unaryfunc/acos_3.ql.java.out b/systemtest/testdata/unaryfunc/acos_3.ql.java.out
new file mode 100644
index 0000000..8144360
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/acos_3.ql.java.out
@@ -0,0 +1 @@
+3.1415926535897933.141592653589793 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/acos_3.ql.out b/systemtest/testdata/unaryfunc/acos_3.ql.out
new file mode 100644
index 0000000..eaf926b
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/acos_3.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 3.14159
+Element 2: 3.14159
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/acos_4.ql b/systemtest/testdata/unaryfunc/acos_4.ql
new file mode 100644
index 0000000..fc466df
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/acos_4.ql
@@ -0,0 +1,2 @@
+
+ select 4 * arccos(sqrt(2)/2) from ImgCharA -- pi
diff --git a/systemtest/testdata/unaryfunc/acos_4.ql.java.out b/systemtest/testdata/unaryfunc/acos_4.ql.java.out
new file mode 100644
index 0000000..8144360
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/acos_4.ql.java.out
@@ -0,0 +1 @@
+3.1415926535897933.141592653589793 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/acos_4.ql.out b/systemtest/testdata/unaryfunc/acos_4.ql.out
new file mode 100644
index 0000000..eaf926b
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/acos_4.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 3.14159
+Element 2: 3.14159
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/acos_5.ql b/systemtest/testdata/unaryfunc/acos_5.ql
new file mode 100644
index 0000000..ee5be77
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/acos_5.ql
@@ -0,0 +1,2 @@
+
+ select arccos(1) from ImgCharA -- 0
diff --git a/systemtest/testdata/unaryfunc/acos_5.ql.java.out b/systemtest/testdata/unaryfunc/acos_5.ql.java.out
new file mode 100644
index 0000000..b2024e1
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/acos_5.ql.java.out
@@ -0,0 +1 @@
+0.00.0 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/acos_5.ql.out b/systemtest/testdata/unaryfunc/acos_5.ql.out
new file mode 100644
index 0000000..eb05dc2
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/acos_5.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 0
+Element 2: 0
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/acos_dom_1.ql b/systemtest/testdata/unaryfunc/acos_dom_1.ql
new file mode 100644
index 0000000..f8ba915
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/acos_dom_1.ql
@@ -0,0 +1,2 @@
+
+ select arccos(-3.14) from ImgCharA -- errno 510: EDOM
diff --git a/systemtest/testdata/unaryfunc/acos_dom_1.ql.java.out b/systemtest/testdata/unaryfunc/acos_dom_1.ql.java.out
new file mode 100644
index 0000000..9310cf4
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/acos_dom_1.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Execution error 510 in line 4, column 9, near token arccos: The argument is outside the function domain. \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/acos_dom_1.ql.out b/systemtest/testdata/unaryfunc/acos_dom_1.ql.out
new file mode 100644
index 0000000..0e9ec7e
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/acos_dom_1.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=510
diff --git a/systemtest/testdata/unaryfunc/acos_dom_2.ql b/systemtest/testdata/unaryfunc/acos_dom_2.ql
new file mode 100644
index 0000000..14516d0
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/acos_dom_2.ql
@@ -0,0 +1,2 @@
+
+ select arccos(1.1) from ImgCharA -- errno 510: EDOM
diff --git a/systemtest/testdata/unaryfunc/acos_dom_2.ql.java.out b/systemtest/testdata/unaryfunc/acos_dom_2.ql.java.out
new file mode 100644
index 0000000..9310cf4
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/acos_dom_2.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Execution error 510 in line 4, column 9, near token arccos: The argument is outside the function domain. \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/acos_dom_2.ql.out b/systemtest/testdata/unaryfunc/acos_dom_2.ql.out
new file mode 100644
index 0000000..0e9ec7e
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/acos_dom_2.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=510
diff --git a/systemtest/testdata/unaryfunc/asin_1.ql b/systemtest/testdata/unaryfunc/asin_1.ql
new file mode 100644
index 0000000..3c3d03b
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/asin_1.ql
@@ -0,0 +1,2 @@
+
+ select arcsin(-1) from ImgCharA -- -pi/2 (-1.5707...)
diff --git a/systemtest/testdata/unaryfunc/asin_1.ql.java.out b/systemtest/testdata/unaryfunc/asin_1.ql.java.out
new file mode 100644
index 0000000..9217cca
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/asin_1.ql.java.out
@@ -0,0 +1 @@
+-1.5707963267948966-1.5707963267948966 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/asin_1.ql.out b/systemtest/testdata/unaryfunc/asin_1.ql.out
new file mode 100644
index 0000000..8c62930
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/asin_1.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: -1.5708
+Element 2: -1.5708
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/asin_2.ql b/systemtest/testdata/unaryfunc/asin_2.ql
new file mode 100644
index 0000000..7f7d3a7
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/asin_2.ql
@@ -0,0 +1,2 @@
+
+ select arcsin(-0) from ImgCharA -- 0
diff --git a/systemtest/testdata/unaryfunc/asin_2.ql.java.out b/systemtest/testdata/unaryfunc/asin_2.ql.java.out
new file mode 100644
index 0000000..b2024e1
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/asin_2.ql.java.out
@@ -0,0 +1 @@
+0.00.0 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/asin_2.ql.out b/systemtest/testdata/unaryfunc/asin_2.ql.out
new file mode 100644
index 0000000..eb05dc2
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/asin_2.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 0
+Element 2: 0
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/asin_3.ql b/systemtest/testdata/unaryfunc/asin_3.ql
new file mode 100644
index 0000000..f6a8e51
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/asin_3.ql
@@ -0,0 +1,2 @@
+
+ select arcsin(0) from ImgCharA -- 0
diff --git a/systemtest/testdata/unaryfunc/asin_3.ql.java.out b/systemtest/testdata/unaryfunc/asin_3.ql.java.out
new file mode 100644
index 0000000..b2024e1
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/asin_3.ql.java.out
@@ -0,0 +1 @@
+0.00.0 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/asin_3.ql.out b/systemtest/testdata/unaryfunc/asin_3.ql.out
new file mode 100644
index 0000000..eb05dc2
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/asin_3.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 0
+Element 2: 0
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/asin_4.ql b/systemtest/testdata/unaryfunc/asin_4.ql
new file mode 100644
index 0000000..4c760bd
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/asin_4.ql
@@ -0,0 +1,2 @@
+
+ select 4 * arcsin(sqrt(2)/2) from ImgCharA -- pi
diff --git a/systemtest/testdata/unaryfunc/asin_4.ql.java.out b/systemtest/testdata/unaryfunc/asin_4.ql.java.out
new file mode 100644
index 0000000..45c5e5d
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/asin_4.ql.java.out
@@ -0,0 +1 @@
+3.14159265358979363.1415926535897936 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/asin_4.ql.out b/systemtest/testdata/unaryfunc/asin_4.ql.out
new file mode 100644
index 0000000..eaf926b
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/asin_4.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 3.14159
+Element 2: 3.14159
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/asin_5.ql b/systemtest/testdata/unaryfunc/asin_5.ql
new file mode 100644
index 0000000..8d9e716
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/asin_5.ql
@@ -0,0 +1,2 @@
+
+ select 2 * arcsin(1) from ImgCharA -- pi
diff --git a/systemtest/testdata/unaryfunc/asin_5.ql.java.out b/systemtest/testdata/unaryfunc/asin_5.ql.java.out
new file mode 100644
index 0000000..8144360
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/asin_5.ql.java.out
@@ -0,0 +1 @@
+3.1415926535897933.141592653589793 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/asin_5.ql.out b/systemtest/testdata/unaryfunc/asin_5.ql.out
new file mode 100644
index 0000000..eaf926b
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/asin_5.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 3.14159
+Element 2: 3.14159
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/asin_dom_1.ql b/systemtest/testdata/unaryfunc/asin_dom_1.ql
new file mode 100644
index 0000000..e22196c
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/asin_dom_1.ql
@@ -0,0 +1,2 @@
+
+ select arcsin(-3.14) from ImgCharA -- errno 510: EDOM
diff --git a/systemtest/testdata/unaryfunc/asin_dom_1.ql.java.out b/systemtest/testdata/unaryfunc/asin_dom_1.ql.java.out
new file mode 100644
index 0000000..9eeb7b5
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/asin_dom_1.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Execution error 510 in line 4, column 9, near token arcsin: The argument is outside the function domain. \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/asin_dom_1.ql.out b/systemtest/testdata/unaryfunc/asin_dom_1.ql.out
new file mode 100644
index 0000000..0e9ec7e
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/asin_dom_1.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=510
diff --git a/systemtest/testdata/unaryfunc/asin_dom_2.ql b/systemtest/testdata/unaryfunc/asin_dom_2.ql
new file mode 100644
index 0000000..32cf104
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/asin_dom_2.ql
@@ -0,0 +1,2 @@
+
+ select arcsin(3) from ImgCharA -- errno 510: EDOM
diff --git a/systemtest/testdata/unaryfunc/asin_dom_2.ql.java.out b/systemtest/testdata/unaryfunc/asin_dom_2.ql.java.out
new file mode 100644
index 0000000..9eeb7b5
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/asin_dom_2.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Execution error 510 in line 4, column 9, near token arcsin: The argument is outside the function domain. \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/asin_dom_2.ql.out b/systemtest/testdata/unaryfunc/asin_dom_2.ql.out
new file mode 100644
index 0000000..0e9ec7e
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/asin_dom_2.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=510
diff --git a/systemtest/testdata/unaryfunc/atan_1.ql b/systemtest/testdata/unaryfunc/atan_1.ql
new file mode 100644
index 0000000..8e8dd8a
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/atan_1.ql
@@ -0,0 +1,2 @@
+
+ select 2*arctan(-1000000) from ImgCharA -- -pi
diff --git a/systemtest/testdata/unaryfunc/atan_1.ql.java.out b/systemtest/testdata/unaryfunc/atan_1.ql.java.out
new file mode 100644
index 0000000..e17610a
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/atan_1.ql.java.out
@@ -0,0 +1 @@
+-3.1415906535897933-3.1415906535897933 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/atan_1.ql.out b/systemtest/testdata/unaryfunc/atan_1.ql.out
new file mode 100644
index 0000000..d410008
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/atan_1.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: -3.14159
+Element 2: -3.14159
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/atan_2.ql b/systemtest/testdata/unaryfunc/atan_2.ql
new file mode 100644
index 0000000..a4a4e6a
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/atan_2.ql
@@ -0,0 +1,2 @@
+
+ select 4*arctan(-1) from ImgCharA -- -pi
diff --git a/systemtest/testdata/unaryfunc/atan_2.ql.java.out b/systemtest/testdata/unaryfunc/atan_2.ql.java.out
new file mode 100644
index 0000000..c7210be
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/atan_2.ql.java.out
@@ -0,0 +1 @@
+-3.141592653589793-3.141592653589793 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/atan_2.ql.out b/systemtest/testdata/unaryfunc/atan_2.ql.out
new file mode 100644
index 0000000..d410008
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/atan_2.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: -3.14159
+Element 2: -3.14159
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/atan_3.ql b/systemtest/testdata/unaryfunc/atan_3.ql
new file mode 100644
index 0000000..7241674
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/atan_3.ql
@@ -0,0 +1,2 @@
+
+ select arctan(0) from ImgCharA -- 0
diff --git a/systemtest/testdata/unaryfunc/atan_3.ql.java.out b/systemtest/testdata/unaryfunc/atan_3.ql.java.out
new file mode 100644
index 0000000..b2024e1
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/atan_3.ql.java.out
@@ -0,0 +1 @@
+0.00.0 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/atan_3.ql.out b/systemtest/testdata/unaryfunc/atan_3.ql.out
new file mode 100644
index 0000000..eb05dc2
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/atan_3.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 0
+Element 2: 0
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/atan_4.ql b/systemtest/testdata/unaryfunc/atan_4.ql
new file mode 100644
index 0000000..6f93f44
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/atan_4.ql
@@ -0,0 +1,2 @@
+
+ select 4*arctan(1) from ImgCharA -- pi
diff --git a/systemtest/testdata/unaryfunc/atan_4.ql.java.out b/systemtest/testdata/unaryfunc/atan_4.ql.java.out
new file mode 100644
index 0000000..8144360
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/atan_4.ql.java.out
@@ -0,0 +1 @@
+3.1415926535897933.141592653589793 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/atan_4.ql.out b/systemtest/testdata/unaryfunc/atan_4.ql.out
new file mode 100644
index 0000000..eaf926b
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/atan_4.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 3.14159
+Element 2: 3.14159
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/atan_5.ql b/systemtest/testdata/unaryfunc/atan_5.ql
new file mode 100644
index 0000000..199f553
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/atan_5.ql
@@ -0,0 +1,2 @@
+
+ select 2*arctan(10000000) from ImgCharA -- pi
diff --git a/systemtest/testdata/unaryfunc/atan_5.ql.java.out b/systemtest/testdata/unaryfunc/atan_5.ql.java.out
new file mode 100644
index 0000000..8cd77d4
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/atan_5.ql.java.out
@@ -0,0 +1 @@
+3.14159245358979343.1415924535897934 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/atan_5.ql.out b/systemtest/testdata/unaryfunc/atan_5.ql.out
new file mode 100644
index 0000000..eaf926b
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/atan_5.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 3.14159
+Element 2: 3.14159
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/coll_1.ql b/systemtest/testdata/unaryfunc/coll_1.ql
new file mode 100644
index 0000000..f972aa8
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/coll_1.ql
@@ -0,0 +1,2 @@
+
+ select abs(ImgCharA) from ImgCharA
diff --git a/systemtest/testdata/unaryfunc/coll_1.ql.java.out b/systemtest/testdata/unaryfunc/coll_1.ql.java.out
new file mode 100644
index 0000000..f500de4
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/coll_1.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayDouble
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 968
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+rasj.RasMArrayDouble
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 968
+ 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/coll_1.ql.out b/systemtest/testdata/unaryfunc/coll_1.ql.out
new file mode 100644
index 0000000..262c46a
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/coll_1.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <double, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <double, [0:10,0:10]>
+ Type Schema...........: marray< double >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: double
+ Base Type Length......: 8
+ Data format.......... : Array
+ Data size (bytes).... : 968
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+Image 2
+GMarray
+ Type Structure........: marray <double, [0:10,0:10]>
+ Type Schema...........: marray< double >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: double
+ Base Type Length......: 8
+ Data format.......... : Array
+ Data size (bytes).... : 968
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/coll_10.ql b/systemtest/testdata/unaryfunc/coll_10.ql
new file mode 100644
index 0000000..d38b0f7
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/coll_10.ql
@@ -0,0 +1,2 @@
+
+ select arccos(ImgCharA) from ImgCharA
diff --git a/systemtest/testdata/unaryfunc/coll_10.ql.java.out b/systemtest/testdata/unaryfunc/coll_10.ql.java.out
new file mode 100644
index 0000000..1238907
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/coll_10.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayDouble
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 968
+ 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24
+rasj.RasMArrayDouble
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 968
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/coll_10.ql.out b/systemtest/testdata/unaryfunc/coll_10.ql.out
new file mode 100644
index 0000000..0056551
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/coll_10.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <double, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <double, [0:10,0:10]>
+ Type Schema...........: marray< double >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: double
+ Base Type Length......: 8
+ Data format.......... : Array
+ Data size (bytes).... : 968
+1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708
+1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708
+1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708
+1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708
+1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708
+1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708
+1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708
+1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708
+1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708
+1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708
+1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708
+Image 2
+GMarray
+ Type Structure........: marray <double, [0:10,0:10]>
+ Type Schema...........: marray< double >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: double
+ Base Type Length......: 8
+ Data format.......... : Array
+ Data size (bytes).... : 968
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/coll_11.ql b/systemtest/testdata/unaryfunc/coll_11.ql
new file mode 100644
index 0000000..af905f7
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/coll_11.ql
@@ -0,0 +1,2 @@
+
+ select arctan(ImgCharA) from ImgCharA
diff --git a/systemtest/testdata/unaryfunc/coll_11.ql.java.out b/systemtest/testdata/unaryfunc/coll_11.ql.java.out
new file mode 100644
index 0000000..7560fcf
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/coll_11.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayDouble
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 968
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+rasj.RasMArrayDouble
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 968
+ 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 63 -23 33 -5 84 68 45 24 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/coll_11.ql.out b/systemtest/testdata/unaryfunc/coll_11.ql.out
new file mode 100644
index 0000000..bba7c3e
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/coll_11.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <double, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <double, [0:10,0:10]>
+ Type Schema...........: marray< double >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: double
+ Base Type Length......: 8
+ Data format.......... : Array
+ Data size (bytes).... : 968
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+Image 2
+GMarray
+ Type Structure........: marray <double, [0:10,0:10]>
+ Type Schema...........: marray< double >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: double
+ Base Type Length......: 8
+ Data format.......... : Array
+ Data size (bytes).... : 968
+0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398
+0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398
+0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398
+0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398
+0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398
+0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398
+0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398
+0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398
+0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398
+0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398
+0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398 0.785398
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/coll_2.ql b/systemtest/testdata/unaryfunc/coll_2.ql
new file mode 100644
index 0000000..62d365a
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/coll_2.ql
@@ -0,0 +1,2 @@
+
+ select sqrt(ImgCharA) from ImgCharA
diff --git a/systemtest/testdata/unaryfunc/coll_2.ql.java.out b/systemtest/testdata/unaryfunc/coll_2.ql.java.out
new file mode 100644
index 0000000..f500de4
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/coll_2.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayDouble
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 968
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+rasj.RasMArrayDouble
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 968
+ 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/coll_2.ql.out b/systemtest/testdata/unaryfunc/coll_2.ql.out
new file mode 100644
index 0000000..262c46a
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/coll_2.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <double, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <double, [0:10,0:10]>
+ Type Schema...........: marray< double >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: double
+ Base Type Length......: 8
+ Data format.......... : Array
+ Data size (bytes).... : 968
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+Image 2
+GMarray
+ Type Structure........: marray <double, [0:10,0:10]>
+ Type Schema...........: marray< double >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: double
+ Base Type Length......: 8
+ Data format.......... : Array
+ Data size (bytes).... : 968
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/coll_3.ql b/systemtest/testdata/unaryfunc/coll_3.ql
new file mode 100644
index 0000000..312e973
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/coll_3.ql
@@ -0,0 +1,2 @@
+
+ select exp(ImgCharA) from ImgCharA
diff --git a/systemtest/testdata/unaryfunc/coll_3.ql.java.out b/systemtest/testdata/unaryfunc/coll_3.ql.java.out
new file mode 100644
index 0000000..7502b88
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/coll_3.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayDouble
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 968
+ 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0
+rasj.RasMArrayDouble
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 968
+ 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 64 5 -65 10 -117 20 87 105 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/coll_3.ql.out b/systemtest/testdata/unaryfunc/coll_3.ql.out
new file mode 100644
index 0000000..59576c4
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/coll_3.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <double, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <double, [0:10,0:10]>
+ Type Schema...........: marray< double >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: double
+ Base Type Length......: 8
+ Data format.......... : Array
+ Data size (bytes).... : 968
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+Image 2
+GMarray
+ Type Structure........: marray <double, [0:10,0:10]>
+ Type Schema...........: marray< double >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: double
+ Base Type Length......: 8
+ Data format.......... : Array
+ Data size (bytes).... : 968
+2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828
+2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828
+2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828
+2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828
+2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828
+2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828
+2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828
+2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828
+2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828
+2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828
+2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828 2.71828
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/coll_4.ql b/systemtest/testdata/unaryfunc/coll_4.ql
new file mode 100644
index 0000000..451a832
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/coll_4.ql
@@ -0,0 +1,2 @@
+
+ select ln(ImgCharA) from ImgCharA -- errno 511: ERANGE
diff --git a/systemtest/testdata/unaryfunc/coll_4.ql.java.out b/systemtest/testdata/unaryfunc/coll_4.ql.java.out
new file mode 100644
index 0000000..c77df2d
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/coll_4.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Execution error 511 in line 4, column 9, near token ln: The function result exceeds the allowed range. \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/coll_4.ql.out b/systemtest/testdata/unaryfunc/coll_4.ql.out
new file mode 100644
index 0000000..081dfc0
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/coll_4.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=511
diff --git a/systemtest/testdata/unaryfunc/coll_5.ql b/systemtest/testdata/unaryfunc/coll_5.ql
new file mode 100644
index 0000000..3b20d59
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/coll_5.ql
@@ -0,0 +1,2 @@
+
+ select log(ImgCharA) from ImgCharA -- errno 511: ERANGE
diff --git a/systemtest/testdata/unaryfunc/coll_5.ql.java.out b/systemtest/testdata/unaryfunc/coll_5.ql.java.out
new file mode 100644
index 0000000..38465d1
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/coll_5.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Execution error 511 in line 4, column 9, near token log: The function result exceeds the allowed range. \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/coll_5.ql.out b/systemtest/testdata/unaryfunc/coll_5.ql.out
new file mode 100644
index 0000000..081dfc0
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/coll_5.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=511
diff --git a/systemtest/testdata/unaryfunc/coll_6.ql b/systemtest/testdata/unaryfunc/coll_6.ql
new file mode 100644
index 0000000..cb45c09
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/coll_6.ql
@@ -0,0 +1,2 @@
+
+ select sin(ImgCharA) from ImgCharA
diff --git a/systemtest/testdata/unaryfunc/coll_6.ql.java.out b/systemtest/testdata/unaryfunc/coll_6.ql.java.out
new file mode 100644
index 0000000..fc98afc
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/coll_6.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayDouble
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 968
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+rasj.RasMArrayDouble
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 968
+ 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 63 -22 -19 84 -113 9 12 -18 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/coll_6.ql.out b/systemtest/testdata/unaryfunc/coll_6.ql.out
new file mode 100644
index 0000000..0a35a5a
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/coll_6.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <double, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <double, [0:10,0:10]>
+ Type Schema...........: marray< double >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: double
+ Base Type Length......: 8
+ Data format.......... : Array
+ Data size (bytes).... : 968
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+Image 2
+GMarray
+ Type Structure........: marray <double, [0:10,0:10]>
+ Type Schema...........: marray< double >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: double
+ Base Type Length......: 8
+ Data format.......... : Array
+ Data size (bytes).... : 968
+0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471
+0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471
+0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471
+0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471
+0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471
+0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471
+0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471
+0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471
+0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471
+0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471
+0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471 0.841471
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/coll_7.ql b/systemtest/testdata/unaryfunc/coll_7.ql
new file mode 100644
index 0000000..f68389b
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/coll_7.ql
@@ -0,0 +1,2 @@
+
+ select cos(ImgCharA) from ImgCharA
diff --git a/systemtest/testdata/unaryfunc/coll_7.ql.java.out b/systemtest/testdata/unaryfunc/coll_7.ql.java.out
new file mode 100644
index 0000000..685a4f0
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/coll_7.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayDouble
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 968
+ 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0 63 -16 0 0 0 0 0 0
+rasj.RasMArrayDouble
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 968
+ 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 63 -31 74 40 15 -75 6 -116 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/coll_7.ql.out b/systemtest/testdata/unaryfunc/coll_7.ql.out
new file mode 100644
index 0000000..6981952
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/coll_7.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <double, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <double, [0:10,0:10]>
+ Type Schema...........: marray< double >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: double
+ Base Type Length......: 8
+ Data format.......... : Array
+ Data size (bytes).... : 968
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 1 1 1 1
+Image 2
+GMarray
+ Type Structure........: marray <double, [0:10,0:10]>
+ Type Schema...........: marray< double >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: double
+ Base Type Length......: 8
+ Data format.......... : Array
+ Data size (bytes).... : 968
+0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302
+0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302
+0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302
+0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302
+0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302
+0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302
+0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302
+0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302
+0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302
+0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302
+0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302 0.540302
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/coll_8.ql b/systemtest/testdata/unaryfunc/coll_8.ql
new file mode 100644
index 0000000..810d72e
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/coll_8.ql
@@ -0,0 +1,2 @@
+
+ select tan(ImgCharA) from ImgCharA
diff --git a/systemtest/testdata/unaryfunc/coll_8.ql.java.out b/systemtest/testdata/unaryfunc/coll_8.ql.java.out
new file mode 100644
index 0000000..a8418f4
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/coll_8.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayDouble
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 968
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+rasj.RasMArrayDouble
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 968
+ 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 63 -8 -21 36 92 -66 -29 -90 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/coll_8.ql.out b/systemtest/testdata/unaryfunc/coll_8.ql.out
new file mode 100644
index 0000000..62327b7
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/coll_8.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <double, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <double, [0:10,0:10]>
+ Type Schema...........: marray< double >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: double
+ Base Type Length......: 8
+ Data format.......... : Array
+ Data size (bytes).... : 968
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+Image 2
+GMarray
+ Type Structure........: marray <double, [0:10,0:10]>
+ Type Schema...........: marray< double >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: double
+ Base Type Length......: 8
+ Data format.......... : Array
+ Data size (bytes).... : 968
+1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741
+1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741
+1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741
+1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741
+1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741
+1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741
+1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741
+1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741
+1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741
+1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741
+1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741 1.55741
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/coll_9.ql b/systemtest/testdata/unaryfunc/coll_9.ql
new file mode 100644
index 0000000..9e099c5
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/coll_9.ql
@@ -0,0 +1,2 @@
+
+ select arcsin(ImgCharA) from ImgCharA
diff --git a/systemtest/testdata/unaryfunc/coll_9.ql.java.out b/systemtest/testdata/unaryfunc/coll_9.ql.java.out
new file mode 100644
index 0000000..56d33b4
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/coll_9.ql.java.out
@@ -0,0 +1,29 @@
+
+rasj.RasMArrayDouble
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 968
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+rasj.RasMArrayDouble
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 968
+ 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 63 -7 33 -5 84 68 45 24 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/coll_9.ql.out b/systemtest/testdata/unaryfunc/coll_9.ql.out
new file mode 100644
index 0000000..42eada3
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/coll_9.ql.out
@@ -0,0 +1,44 @@
+-- Testbed line: result_type=set <marray <double, [0:10,0:10]>>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <double, [0:10,0:10]>
+ Type Schema...........: marray< double >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: double
+ Base Type Length......: 8
+ Data format.......... : Array
+ Data size (bytes).... : 968
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0
+Image 2
+GMarray
+ Type Structure........: marray <double, [0:10,0:10]>
+ Type Schema...........: marray< double >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: double
+ Base Type Length......: 8
+ Data format.......... : Array
+ Data size (bytes).... : 968
+1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708
+1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708
+1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708
+1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708
+1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708
+1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708
+1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708
+1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708
+1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708
+1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708
+1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708 1.5708
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/cos_1.ql b/systemtest/testdata/unaryfunc/cos_1.ql
new file mode 100644
index 0000000..232f416
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/cos_1.ql
@@ -0,0 +1,2 @@
+
+ select cos(0) from ImgCharA -- 1
diff --git a/systemtest/testdata/unaryfunc/cos_1.ql.java.out b/systemtest/testdata/unaryfunc/cos_1.ql.java.out
new file mode 100644
index 0000000..85aae69
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/cos_1.ql.java.out
@@ -0,0 +1 @@
+1.01.0 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/cos_1.ql.out b/systemtest/testdata/unaryfunc/cos_1.ql.out
new file mode 100644
index 0000000..5b5eff0
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/cos_1.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 1
+Element 2: 1
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/cos_2.ql b/systemtest/testdata/unaryfunc/cos_2.ql
new file mode 100644
index 0000000..48f873b
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/cos_2.ql
@@ -0,0 +1,2 @@
+
+ select 2 * cos(3.1415927 / 4) from ImgCharA -- 1.4142136
diff --git a/systemtest/testdata/unaryfunc/cos_2.ql.java.out b/systemtest/testdata/unaryfunc/cos_2.ql.java.out
new file mode 100644
index 0000000..e3b68f6
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/cos_2.ql.java.out
@@ -0,0 +1 @@
+1.41421353146447441.4142135314644744 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/cos_2.ql.out b/systemtest/testdata/unaryfunc/cos_2.ql.out
new file mode 100644
index 0000000..a23dbb9
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/cos_2.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 1.41421
+Element 2: 1.41421
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/cos_3.ql b/systemtest/testdata/unaryfunc/cos_3.ql
new file mode 100644
index 0000000..27ecf3b
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/cos_3.ql
@@ -0,0 +1,2 @@
+
+ select cos(3.1415927/2) from ImgCharA -- 0
diff --git a/systemtest/testdata/unaryfunc/cos_3.ql.java.out b/systemtest/testdata/unaryfunc/cos_3.ql.java.out
new file mode 100644
index 0000000..84dc787
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/cos_3.ql.java.out
@@ -0,0 +1 @@
+-4.371139000186444E-8-4.371139000186444E-8 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/cos_3.ql.out b/systemtest/testdata/unaryfunc/cos_3.ql.out
new file mode 100644
index 0000000..e69d8ef
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/cos_3.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: -4.37114e-08
+Element 2: -4.37114e-08
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/cos_4.ql b/systemtest/testdata/unaryfunc/cos_4.ql
new file mode 100644
index 0000000..997189e
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/cos_4.ql
@@ -0,0 +1,2 @@
+
+ select cos(3.1415927) from ImgCharA -- -1
diff --git a/systemtest/testdata/unaryfunc/cos_4.ql.java.out b/systemtest/testdata/unaryfunc/cos_4.ql.java.out
new file mode 100644
index 0000000..b902162
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/cos_4.ql.java.out
@@ -0,0 +1 @@
+-0.9999999999999962-0.9999999999999962 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/cos_4.ql.out b/systemtest/testdata/unaryfunc/cos_4.ql.out
new file mode 100644
index 0000000..0f7dc93
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/cos_4.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: -1
+Element 2: -1
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/cos_5.ql b/systemtest/testdata/unaryfunc/cos_5.ql
new file mode 100644
index 0000000..094f44a
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/cos_5.ql
@@ -0,0 +1,2 @@
+
+ select cos(3*3.1415927/2) from ImgCharA -- 0
diff --git a/systemtest/testdata/unaryfunc/cos_5.ql.java.out b/systemtest/testdata/unaryfunc/cos_5.ql.java.out
new file mode 100644
index 0000000..2e699af
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/cos_5.ql.java.out
@@ -0,0 +1 @@
+1.1924880454812102E-81.1924880454812102E-8 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/cos_5.ql.out b/systemtest/testdata/unaryfunc/cos_5.ql.out
new file mode 100644
index 0000000..3a2efa1
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/cos_5.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 1.19249e-08
+Element 2: 1.19249e-08
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/cos_6.ql b/systemtest/testdata/unaryfunc/cos_6.ql
new file mode 100644
index 0000000..393423c
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/cos_6.ql
@@ -0,0 +1,2 @@
+
+ select cos(2* 3.1415927) from ImgCharA -- 1
diff --git a/systemtest/testdata/unaryfunc/cos_6.ql.java.out b/systemtest/testdata/unaryfunc/cos_6.ql.java.out
new file mode 100644
index 0000000..2a00f38
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/cos_6.ql.java.out
@@ -0,0 +1 @@
+0.99999999999998470.9999999999999847 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/cos_6.ql.out b/systemtest/testdata/unaryfunc/cos_6.ql.out
new file mode 100644
index 0000000..5b5eff0
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/cos_6.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 1
+Element 2: 1
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/cos_7.ql b/systemtest/testdata/unaryfunc/cos_7.ql
new file mode 100644
index 0000000..c995f6b
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/cos_7.ql
@@ -0,0 +1,2 @@
+
+ select cos(1000000 * 3.1415927) from ImgCharA -- 1
diff --git a/systemtest/testdata/unaryfunc/cos_7.ql.java.out b/systemtest/testdata/unaryfunc/cos_7.ql.java.out
new file mode 100644
index 0000000..64a533b
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/cos_7.ql.java.out
@@ -0,0 +1 @@
+0.99535613472119480.9953561347211948 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/cos_7.ql.out b/systemtest/testdata/unaryfunc/cos_7.ql.out
new file mode 100644
index 0000000..49dfb79
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/cos_7.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 0.995356
+Element 2: 0.995356
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/exp_1.ql b/systemtest/testdata/unaryfunc/exp_1.ql
new file mode 100644
index 0000000..b32fdc3
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/exp_1.ql
@@ -0,0 +1,2 @@
+
+ select exp(1) from ImgCharA -- e
diff --git a/systemtest/testdata/unaryfunc/exp_1.ql.java.out b/systemtest/testdata/unaryfunc/exp_1.ql.java.out
new file mode 100644
index 0000000..dfce99e
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/exp_1.ql.java.out
@@ -0,0 +1 @@
+2.7182818284590452.718281828459045 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/exp_1.ql.out b/systemtest/testdata/unaryfunc/exp_1.ql.out
new file mode 100644
index 0000000..9b92e98
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/exp_1.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 2.71828
+Element 2: 2.71828
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/exp_2.ql b/systemtest/testdata/unaryfunc/exp_2.ql
new file mode 100644
index 0000000..3893f13
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/exp_2.ql
@@ -0,0 +1,2 @@
+
+ select exp(0.0) from ImgCharA -- 1
diff --git a/systemtest/testdata/unaryfunc/exp_2.ql.java.out b/systemtest/testdata/unaryfunc/exp_2.ql.java.out
new file mode 100644
index 0000000..85aae69
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/exp_2.ql.java.out
@@ -0,0 +1 @@
+1.01.0 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/exp_2.ql.out b/systemtest/testdata/unaryfunc/exp_2.ql.out
new file mode 100644
index 0000000..5b5eff0
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/exp_2.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 1
+Element 2: 1
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/exp_3.ql b/systemtest/testdata/unaryfunc/exp_3.ql
new file mode 100644
index 0000000..236b028
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/exp_3.ql
@@ -0,0 +1,2 @@
+
+ select exp(-10) from ImgCharA -- 4.539993e-05
diff --git a/systemtest/testdata/unaryfunc/exp_3.ql.java.out b/systemtest/testdata/unaryfunc/exp_3.ql.java.out
new file mode 100644
index 0000000..4619872
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/exp_3.ql.java.out
@@ -0,0 +1 @@
+4.5399929762484854E-54.5399929762484854E-5 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/exp_3.ql.out b/systemtest/testdata/unaryfunc/exp_3.ql.out
new file mode 100644
index 0000000..ceaffa1
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/exp_3.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 4.53999e-05
+Element 2: 4.53999e-05
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/exp_erange_1.ql b/systemtest/testdata/unaryfunc/exp_erange_1.ql
new file mode 100644
index 0000000..cc13bb3
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/exp_erange_1.ql
@@ -0,0 +1,2 @@
+
+ select exp(745.15) from ImgCharA -- errno 511: ERANGE
diff --git a/systemtest/testdata/unaryfunc/exp_erange_1.ql.java.out b/systemtest/testdata/unaryfunc/exp_erange_1.ql.java.out
new file mode 100644
index 0000000..4fd2e8e
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/exp_erange_1.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Execution error 511 in line 4, column 9, near token exp: The function result exceeds the allowed range. \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/exp_erange_1.ql.out b/systemtest/testdata/unaryfunc/exp_erange_1.ql.out
new file mode 100644
index 0000000..081dfc0
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/exp_erange_1.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=511
diff --git a/systemtest/testdata/unaryfunc/exp_erange_2.ql b/systemtest/testdata/unaryfunc/exp_erange_2.ql
new file mode 100644
index 0000000..6dd1d1f
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/exp_erange_2.ql
@@ -0,0 +1,2 @@
+
+ select exp(-745.15) from ImgCharA -- errno 511: ERANGE
diff --git a/systemtest/testdata/unaryfunc/exp_erange_2.ql.java.out b/systemtest/testdata/unaryfunc/exp_erange_2.ql.java.out
new file mode 100644
index 0000000..4fd2e8e
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/exp_erange_2.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Execution error 511 in line 4, column 9, near token exp: The function result exceeds the allowed range. \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/exp_erange_2.ql.out b/systemtest/testdata/unaryfunc/exp_erange_2.ql.out
new file mode 100644
index 0000000..081dfc0
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/exp_erange_2.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=511
diff --git a/systemtest/testdata/unaryfunc/ln_1.ql b/systemtest/testdata/unaryfunc/ln_1.ql
new file mode 100644
index 0000000..216b327
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/ln_1.ql
@@ -0,0 +1,2 @@
+
+ select ln(exp(1)) from ImgCharA -- 1
diff --git a/systemtest/testdata/unaryfunc/ln_1.ql.java.out b/systemtest/testdata/unaryfunc/ln_1.ql.java.out
new file mode 100644
index 0000000..85aae69
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/ln_1.ql.java.out
@@ -0,0 +1 @@
+1.01.0 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/ln_1.ql.out b/systemtest/testdata/unaryfunc/ln_1.ql.out
new file mode 100644
index 0000000..5b5eff0
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/ln_1.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 1
+Element 2: 1
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/ln_2.ql b/systemtest/testdata/unaryfunc/ln_2.ql
new file mode 100644
index 0000000..c5dd8fe
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/ln_2.ql
@@ -0,0 +1,2 @@
+
+ select ln(1) from ImgCharA -- 0
diff --git a/systemtest/testdata/unaryfunc/ln_2.ql.java.out b/systemtest/testdata/unaryfunc/ln_2.ql.java.out
new file mode 100644
index 0000000..b2024e1
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/ln_2.ql.java.out
@@ -0,0 +1 @@
+0.00.0 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/ln_2.ql.out b/systemtest/testdata/unaryfunc/ln_2.ql.out
new file mode 100644
index 0000000..eb05dc2
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/ln_2.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 0
+Element 2: 0
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/ln_3.ql b/systemtest/testdata/unaryfunc/ln_3.ql
new file mode 100644
index 0000000..6091381
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/ln_3.ql
@@ -0,0 +1,2 @@
+
+ select ln(0.1) from ImgCharA -- -2.3025851
diff --git a/systemtest/testdata/unaryfunc/ln_3.ql.java.out b/systemtest/testdata/unaryfunc/ln_3.ql.java.out
new file mode 100644
index 0000000..96646ff
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/ln_3.ql.java.out
@@ -0,0 +1 @@
+-2.3025850780928847-2.3025850780928847 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/ln_3.ql.out b/systemtest/testdata/unaryfunc/ln_3.ql.out
new file mode 100644
index 0000000..4f3f174
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/ln_3.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: -2.30259
+Element 2: -2.30259
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/ln_edom.ql b/systemtest/testdata/unaryfunc/ln_edom.ql
new file mode 100644
index 0000000..d110293
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/ln_edom.ql
@@ -0,0 +1,2 @@
+
+ select ln(-1) from ImgCharA -- errno 510: EDOM
diff --git a/systemtest/testdata/unaryfunc/ln_edom.ql.java.out b/systemtest/testdata/unaryfunc/ln_edom.ql.java.out
new file mode 100644
index 0000000..f047993
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/ln_edom.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Execution error 510 in line 4, column 9, near token ln: The argument is outside the function domain. \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/ln_edom.ql.out b/systemtest/testdata/unaryfunc/ln_edom.ql.out
new file mode 100644
index 0000000..0e9ec7e
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/ln_edom.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=510
diff --git a/systemtest/testdata/unaryfunc/ln_erange.ql b/systemtest/testdata/unaryfunc/ln_erange.ql
new file mode 100644
index 0000000..82009bf
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/ln_erange.ql
@@ -0,0 +1,2 @@
+
+ select ln(0) from ImgCharA -- errno 511: ERANGE
diff --git a/systemtest/testdata/unaryfunc/ln_erange.ql.java.out b/systemtest/testdata/unaryfunc/ln_erange.ql.java.out
new file mode 100644
index 0000000..c77df2d
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/ln_erange.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Execution error 511 in line 4, column 9, near token ln: The function result exceeds the allowed range. \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/ln_erange.ql.out b/systemtest/testdata/unaryfunc/ln_erange.ql.out
new file mode 100644
index 0000000..081dfc0
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/ln_erange.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=511
diff --git a/systemtest/testdata/unaryfunc/log_1.ql b/systemtest/testdata/unaryfunc/log_1.ql
new file mode 100644
index 0000000..3def8a6
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/log_1.ql
@@ -0,0 +1,2 @@
+
+ select log(10) from ImgCharA -- 1
diff --git a/systemtest/testdata/unaryfunc/log_1.ql.java.out b/systemtest/testdata/unaryfunc/log_1.ql.java.out
new file mode 100644
index 0000000..85aae69
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/log_1.ql.java.out
@@ -0,0 +1 @@
+1.01.0 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/log_1.ql.out b/systemtest/testdata/unaryfunc/log_1.ql.out
new file mode 100644
index 0000000..5b5eff0
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/log_1.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 1
+Element 2: 1
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/log_2.ql b/systemtest/testdata/unaryfunc/log_2.ql
new file mode 100644
index 0000000..ee569e8
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/log_2.ql
@@ -0,0 +1,2 @@
+
+ select log(1) from ImgCharA -- 0
diff --git a/systemtest/testdata/unaryfunc/log_2.ql.java.out b/systemtest/testdata/unaryfunc/log_2.ql.java.out
new file mode 100644
index 0000000..b2024e1
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/log_2.ql.java.out
@@ -0,0 +1 @@
+0.00.0 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/log_2.ql.out b/systemtest/testdata/unaryfunc/log_2.ql.out
new file mode 100644
index 0000000..eb05dc2
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/log_2.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 0
+Element 2: 0
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/log_3.ql b/systemtest/testdata/unaryfunc/log_3.ql
new file mode 100644
index 0000000..21b0003
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/log_3.ql
@@ -0,0 +1,2 @@
+
+ select log(0.1) from ImgCharA -- -1
diff --git a/systemtest/testdata/unaryfunc/log_3.ql.java.out b/systemtest/testdata/unaryfunc/log_3.ql.java.out
new file mode 100644
index 0000000..d2c3908
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/log_3.ql.java.out
@@ -0,0 +1 @@
+-0.999999993528508-0.999999993528508 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/log_3.ql.out b/systemtest/testdata/unaryfunc/log_3.ql.out
new file mode 100644
index 0000000..0f7dc93
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/log_3.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: -1
+Element 2: -1
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/log_edom.ql b/systemtest/testdata/unaryfunc/log_edom.ql
new file mode 100644
index 0000000..be19c83
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/log_edom.ql
@@ -0,0 +1,2 @@
+
+ select log(-1) from ImgCharA -- errno 510: EDOM
diff --git a/systemtest/testdata/unaryfunc/log_edom.ql.java.out b/systemtest/testdata/unaryfunc/log_edom.ql.java.out
new file mode 100644
index 0000000..1373616
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/log_edom.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Execution error 510 in line 4, column 9, near token log: The argument is outside the function domain. \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/log_edom.ql.out b/systemtest/testdata/unaryfunc/log_edom.ql.out
new file mode 100644
index 0000000..0e9ec7e
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/log_edom.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=510
diff --git a/systemtest/testdata/unaryfunc/log_erange.ql b/systemtest/testdata/unaryfunc/log_erange.ql
new file mode 100644
index 0000000..c6825b9
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/log_erange.ql
@@ -0,0 +1,2 @@
+
+ select log(0) from ImgCharA -- errno 511: ERANGE
diff --git a/systemtest/testdata/unaryfunc/log_erange.ql.java.out b/systemtest/testdata/unaryfunc/log_erange.ql.java.out
new file mode 100644
index 0000000..38465d1
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/log_erange.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Execution error 511 in line 4, column 9, near token log: The function result exceeds the allowed range. \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/log_erange.ql.out b/systemtest/testdata/unaryfunc/log_erange.ql.out
new file mode 100644
index 0000000..081dfc0
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/log_erange.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=511
diff --git a/systemtest/testdata/unaryfunc/mix_1.ql b/systemtest/testdata/unaryfunc/mix_1.ql
new file mode 100644
index 0000000..7121c63
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/mix_1.ql
@@ -0,0 +1,2 @@
+
+ select abs(log(exp(-sqrt(25)/log(exp(1))))) from ImgCharA -- 5
diff --git a/systemtest/testdata/unaryfunc/mix_1.ql.java.out b/systemtest/testdata/unaryfunc/mix_1.ql.java.out
new file mode 100644
index 0000000..2ee6b4b
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/mix_1.ql.java.out
@@ -0,0 +1 @@
+5.05.0 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/mix_1.ql.out b/systemtest/testdata/unaryfunc/mix_1.ql.out
new file mode 100644
index 0000000..6f640b8
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/mix_1.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 5
+Element 2: 5
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/mix_2.ql b/systemtest/testdata/unaryfunc/mix_2.ql
new file mode 100644
index 0000000..7506261
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/mix_2.ql
@@ -0,0 +1,2 @@
+
+ select sqrt(count_cells(a > 0)) from ImgCharA as a
diff --git a/systemtest/testdata/unaryfunc/mix_2.ql.java.out b/systemtest/testdata/unaryfunc/mix_2.ql.java.out
new file mode 100644
index 0000000..c784127
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/mix_2.ql.java.out
@@ -0,0 +1 @@
+0.011.0 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/mix_2.ql.out b/systemtest/testdata/unaryfunc/mix_2.ql.out
new file mode 100644
index 0000000..c195d25
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/mix_2.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 0
+Element 2: 11
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/mix_3.ql b/systemtest/testdata/unaryfunc/mix_3.ql
new file mode 100644
index 0000000..f512f9f
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/mix_3.ql
@@ -0,0 +1,2 @@
+
+ select count_cells(log(a) > 0) from ImgCharA as a -- -- errno 511: ERANGE
diff --git a/systemtest/testdata/unaryfunc/mix_3.ql.java.out b/systemtest/testdata/unaryfunc/mix_3.ql.java.out
new file mode 100644
index 0000000..78b42dd
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/mix_3.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Execution error 511 in line 4, column 21, near token log: The function result exceeds the allowed range. \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/mix_3.ql.out b/systemtest/testdata/unaryfunc/mix_3.ql.out
new file mode 100644
index 0000000..081dfc0
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/mix_3.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=511
diff --git a/systemtest/testdata/unaryfunc/sin_1.ql b/systemtest/testdata/unaryfunc/sin_1.ql
new file mode 100644
index 0000000..97f200b
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/sin_1.ql
@@ -0,0 +1,2 @@
+
+ select sin(0) from ImgCharA -- 0
diff --git a/systemtest/testdata/unaryfunc/sin_1.ql.java.out b/systemtest/testdata/unaryfunc/sin_1.ql.java.out
new file mode 100644
index 0000000..b2024e1
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/sin_1.ql.java.out
@@ -0,0 +1 @@
+0.00.0 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/sin_1.ql.out b/systemtest/testdata/unaryfunc/sin_1.ql.out
new file mode 100644
index 0000000..eb05dc2
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/sin_1.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 0
+Element 2: 0
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/sin_2.ql b/systemtest/testdata/unaryfunc/sin_2.ql
new file mode 100644
index 0000000..fb05a0b
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/sin_2.ql
@@ -0,0 +1,2 @@
+
+ select 2*sin(3.1415927 / 4) from ImgCharA -- 1.4142136
diff --git a/systemtest/testdata/unaryfunc/sin_2.ql.java.out b/systemtest/testdata/unaryfunc/sin_2.ql.java.out
new file mode 100644
index 0000000..ab6fe9a
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/sin_2.ql.java.out
@@ -0,0 +1 @@
+1.4142135932817151.414213593281715 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/sin_2.ql.out b/systemtest/testdata/unaryfunc/sin_2.ql.out
new file mode 100644
index 0000000..a23dbb9
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/sin_2.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 1.41421
+Element 2: 1.41421
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/sin_3.ql b/systemtest/testdata/unaryfunc/sin_3.ql
new file mode 100644
index 0000000..ee6f07f
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/sin_3.ql
@@ -0,0 +1,2 @@
+
+ select sin(3.1415927/2) from ImgCharA -- 1
diff --git a/systemtest/testdata/unaryfunc/sin_3.ql.java.out b/systemtest/testdata/unaryfunc/sin_3.ql.java.out
new file mode 100644
index 0000000..128ea34
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/sin_3.ql.java.out
@@ -0,0 +1 @@
+0.9999999999999990.999999999999999 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/sin_3.ql.out b/systemtest/testdata/unaryfunc/sin_3.ql.out
new file mode 100644
index 0000000..5b5eff0
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/sin_3.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 1
+Element 2: 1
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/sin_4.ql b/systemtest/testdata/unaryfunc/sin_4.ql
new file mode 100644
index 0000000..3cad6a8
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/sin_4.ql
@@ -0,0 +1,2 @@
+
+ select sin(3.1415927) from ImgCharA -- 0
diff --git a/systemtest/testdata/unaryfunc/sin_4.ql.java.out b/systemtest/testdata/unaryfunc/sin_4.ql.java.out
new file mode 100644
index 0000000..3c6d95b
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/sin_4.ql.java.out
@@ -0,0 +1 @@
+-8.74227800037288E-8-8.74227800037288E-8 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/sin_4.ql.out b/systemtest/testdata/unaryfunc/sin_4.ql.out
new file mode 100644
index 0000000..c5f150b
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/sin_4.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: -8.74228e-08
+Element 2: -8.74228e-08
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/sin_5.ql b/systemtest/testdata/unaryfunc/sin_5.ql
new file mode 100644
index 0000000..675cba0
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/sin_5.ql
@@ -0,0 +1,2 @@
+
+ select sin(3*3.1415927/2) from ImgCharA -- -1
diff --git a/systemtest/testdata/unaryfunc/sin_5.ql.java.out b/systemtest/testdata/unaryfunc/sin_5.ql.java.out
new file mode 100644
index 0000000..4cd29aa
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/sin_5.ql.java.out
@@ -0,0 +1 @@
+-0.9999999999999999-0.9999999999999999 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/sin_5.ql.out b/systemtest/testdata/unaryfunc/sin_5.ql.out
new file mode 100644
index 0000000..0f7dc93
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/sin_5.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: -1
+Element 2: -1
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/sin_6.ql b/systemtest/testdata/unaryfunc/sin_6.ql
new file mode 100644
index 0000000..6349198
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/sin_6.ql
@@ -0,0 +1,2 @@
+
+ select sin(2* 3.1415927) from ImgCharA -- 0
diff --git a/systemtest/testdata/unaryfunc/sin_6.ql.java.out b/systemtest/testdata/unaryfunc/sin_6.ql.java.out
new file mode 100644
index 0000000..9c2cd6c
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/sin_6.ql.java.out
@@ -0,0 +1 @@
+1.748455600074569E-71.748455600074569E-7 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/sin_6.ql.out b/systemtest/testdata/unaryfunc/sin_6.ql.out
new file mode 100644
index 0000000..24c8df7
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/sin_6.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 1.74846e-07
+Element 2: 1.74846e-07
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/sin_7.ql b/systemtest/testdata/unaryfunc/sin_7.ql
new file mode 100644
index 0000000..fe39848
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/sin_7.ql
@@ -0,0 +1,2 @@
+
+ select sin(1000000 * 3.1415927) from ImgCharA -- 0.096 ???
diff --git a/systemtest/testdata/unaryfunc/sin_7.ql.java.out b/systemtest/testdata/unaryfunc/sin_7.ql.java.out
new file mode 100644
index 0000000..822d401
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/sin_7.ql.java.out
@@ -0,0 +1 @@
+0.096260921836863260.09626092183686326 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/sin_7.ql.out b/systemtest/testdata/unaryfunc/sin_7.ql.out
new file mode 100644
index 0000000..e1163c2
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/sin_7.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 0.0962609
+Element 2: 0.0962609
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/sqrt_1.ql b/systemtest/testdata/unaryfunc/sqrt_1.ql
new file mode 100644
index 0000000..a1c87a5
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/sqrt_1.ql
@@ -0,0 +1,2 @@
+
+ select sqrt(4.0) from ImgCharA -- 2
diff --git a/systemtest/testdata/unaryfunc/sqrt_1.ql.java.out b/systemtest/testdata/unaryfunc/sqrt_1.ql.java.out
new file mode 100644
index 0000000..9f2cc4e
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/sqrt_1.ql.java.out
@@ -0,0 +1 @@
+2.02.0 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/sqrt_1.ql.out b/systemtest/testdata/unaryfunc/sqrt_1.ql.out
new file mode 100644
index 0000000..c9c30f1
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/sqrt_1.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 2
+Element 2: 2
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/sqrt_2.ql b/systemtest/testdata/unaryfunc/sqrt_2.ql
new file mode 100644
index 0000000..262b41f
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/sqrt_2.ql
@@ -0,0 +1,2 @@
+
+ select sqrt(3.5 + 5.5) from ImgCharA -- 3
diff --git a/systemtest/testdata/unaryfunc/sqrt_2.ql.java.out b/systemtest/testdata/unaryfunc/sqrt_2.ql.java.out
new file mode 100644
index 0000000..9566c4f
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/sqrt_2.ql.java.out
@@ -0,0 +1 @@
+3.03.0 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/sqrt_2.ql.out b/systemtest/testdata/unaryfunc/sqrt_2.ql.out
new file mode 100644
index 0000000..0d53948
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/sqrt_2.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 3
+Element 2: 3
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/sqrt_3.ql b/systemtest/testdata/unaryfunc/sqrt_3.ql
new file mode 100644
index 0000000..75ea2b8
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/sqrt_3.ql
@@ -0,0 +1,2 @@
+
+ select sqrt(sqrt(16)) from ImgCharA -- 2
diff --git a/systemtest/testdata/unaryfunc/sqrt_3.ql.java.out b/systemtest/testdata/unaryfunc/sqrt_3.ql.java.out
new file mode 100644
index 0000000..9f2cc4e
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/sqrt_3.ql.java.out
@@ -0,0 +1 @@
+2.02.0 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/sqrt_3.ql.out b/systemtest/testdata/unaryfunc/sqrt_3.ql.out
new file mode 100644
index 0000000..c9c30f1
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/sqrt_3.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 2
+Element 2: 2
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/sqrt_4.ql b/systemtest/testdata/unaryfunc/sqrt_4.ql
new file mode 100644
index 0000000..496fd35
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/sqrt_4.ql
@@ -0,0 +1,2 @@
+
+ select sqrt(0.0) from ImgCharA -- 0
diff --git a/systemtest/testdata/unaryfunc/sqrt_4.ql.java.out b/systemtest/testdata/unaryfunc/sqrt_4.ql.java.out
new file mode 100644
index 0000000..b2024e1
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/sqrt_4.ql.java.out
@@ -0,0 +1 @@
+0.00.0 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/sqrt_4.ql.out b/systemtest/testdata/unaryfunc/sqrt_4.ql.out
new file mode 100644
index 0000000..eb05dc2
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/sqrt_4.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 0
+Element 2: 0
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/sqrt_5.ql b/systemtest/testdata/unaryfunc/sqrt_5.ql
new file mode 100644
index 0000000..eeed736
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/sqrt_5.ql
@@ -0,0 +1,2 @@
+
+ select sqrt(0) from ImgCharA -- 0
diff --git a/systemtest/testdata/unaryfunc/sqrt_5.ql.java.out b/systemtest/testdata/unaryfunc/sqrt_5.ql.java.out
new file mode 100644
index 0000000..b2024e1
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/sqrt_5.ql.java.out
@@ -0,0 +1 @@
+0.00.0 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/sqrt_5.ql.out b/systemtest/testdata/unaryfunc/sqrt_5.ql.out
new file mode 100644
index 0000000..eb05dc2
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/sqrt_5.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 0
+Element 2: 0
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/sqrt_6.ql b/systemtest/testdata/unaryfunc/sqrt_6.ql
new file mode 100644
index 0000000..a9eb40b
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/sqrt_6.ql
@@ -0,0 +1,2 @@
+
+ select 1.0 + sqrt(1.0) from ImgCharA -- 2
diff --git a/systemtest/testdata/unaryfunc/sqrt_6.ql.java.out b/systemtest/testdata/unaryfunc/sqrt_6.ql.java.out
new file mode 100644
index 0000000..9f2cc4e
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/sqrt_6.ql.java.out
@@ -0,0 +1 @@
+2.02.0 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/sqrt_6.ql.out b/systemtest/testdata/unaryfunc/sqrt_6.ql.out
new file mode 100644
index 0000000..c9c30f1
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/sqrt_6.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 2
+Element 2: 2
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/sqrt_7.ql b/systemtest/testdata/unaryfunc/sqrt_7.ql
new file mode 100644
index 0000000..a838d68
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/sqrt_7.ql
@@ -0,0 +1,2 @@
+
+ select sqrt(2.0) - 1.0 from ImgCharA -- 0.4142...
diff --git a/systemtest/testdata/unaryfunc/sqrt_7.ql.java.out b/systemtest/testdata/unaryfunc/sqrt_7.ql.java.out
new file mode 100644
index 0000000..eb428b9
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/sqrt_7.ql.java.out
@@ -0,0 +1 @@
+0.414213562373095150.41421356237309515 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/sqrt_7.ql.out b/systemtest/testdata/unaryfunc/sqrt_7.ql.out
new file mode 100644
index 0000000..0851541
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/sqrt_7.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 0.414214
+Element 2: 0.414214
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/sqrt_edom.ql b/systemtest/testdata/unaryfunc/sqrt_edom.ql
new file mode 100644
index 0000000..740f40b
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/sqrt_edom.ql
@@ -0,0 +1,2 @@
+
+ select sqrt(-10.0) from ImgCharA -- errno 510: EDOM
diff --git a/systemtest/testdata/unaryfunc/sqrt_edom.ql.java.out b/systemtest/testdata/unaryfunc/sqrt_edom.ql.java.out
new file mode 100644
index 0000000..623759c
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/sqrt_edom.ql.java.out
@@ -0,0 +1,2 @@
+
+ ODMGException: Execution error 510 in line 4, column 9, near token sqrt: The argument is outside the function domain. \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/sqrt_edom.ql.out b/systemtest/testdata/unaryfunc/sqrt_edom.ql.out
new file mode 100644
index 0000000..0e9ec7e
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/sqrt_edom.ql.out
@@ -0,0 +1 @@
+-- Testbed line: error_no=510
diff --git a/systemtest/testdata/unaryfunc/tan_1.ql b/systemtest/testdata/unaryfunc/tan_1.ql
new file mode 100644
index 0000000..794e257
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/tan_1.ql
@@ -0,0 +1,2 @@
+
+ select tan(0) from ImgCharA -- 0
diff --git a/systemtest/testdata/unaryfunc/tan_1.ql.java.out b/systemtest/testdata/unaryfunc/tan_1.ql.java.out
new file mode 100644
index 0000000..b2024e1
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/tan_1.ql.java.out
@@ -0,0 +1 @@
+0.00.0 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/tan_1.ql.out b/systemtest/testdata/unaryfunc/tan_1.ql.out
new file mode 100644
index 0000000..eb05dc2
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/tan_1.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 0
+Element 2: 0
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/tan_2.ql b/systemtest/testdata/unaryfunc/tan_2.ql
new file mode 100644
index 0000000..96bf599
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/tan_2.ql
@@ -0,0 +1,2 @@
+
+ select tan(3.1415927/ 4) from ImgCharA -- 1
diff --git a/systemtest/testdata/unaryfunc/tan_2.ql.java.out b/systemtest/testdata/unaryfunc/tan_2.ql.java.out
new file mode 100644
index 0000000..bc5381b
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/tan_2.ql.java.out
@@ -0,0 +1 @@
+1.0000000437113911.000000043711391 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/tan_2.ql.out b/systemtest/testdata/unaryfunc/tan_2.ql.out
new file mode 100644
index 0000000..5b5eff0
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/tan_2.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 1
+Element 2: 1
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/tan_3.ql b/systemtest/testdata/unaryfunc/tan_3.ql
new file mode 100644
index 0000000..8f78d2c
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/tan_3.ql
@@ -0,0 +1,2 @@
+
+ select tan(-3.1415927 / 4) from ImgCharA -- -1
diff --git a/systemtest/testdata/unaryfunc/tan_3.ql.java.out b/systemtest/testdata/unaryfunc/tan_3.ql.java.out
new file mode 100644
index 0000000..3dc700d
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/tan_3.ql.java.out
@@ -0,0 +1 @@
+-1.000000043711391-1.000000043711391 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/tan_3.ql.out b/systemtest/testdata/unaryfunc/tan_3.ql.out
new file mode 100644
index 0000000..0f7dc93
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/tan_3.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: -1
+Element 2: -1
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/tan_4.ql b/systemtest/testdata/unaryfunc/tan_4.ql
new file mode 100644
index 0000000..edade02
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/tan_4.ql
@@ -0,0 +1,2 @@
+
+ select tan(1000000 * 3.1415927) from ImgCharA -- 0.096 ???
diff --git a/systemtest/testdata/unaryfunc/tan_4.ql.java.out b/systemtest/testdata/unaryfunc/tan_4.ql.java.out
new file mode 100644
index 0000000..4fbfa9c
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/tan_4.ql.java.out
@@ -0,0 +1 @@
+0.096710030188166290.09671003018816629 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/tan_4.ql.out b/systemtest/testdata/unaryfunc/tan_4.ql.out
new file mode 100644
index 0000000..56502ab
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/tan_4.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 0.09671
+Element 2: 0.09671
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/tan_edom_1.ql b/systemtest/testdata/unaryfunc/tan_edom_1.ql
new file mode 100644
index 0000000..aa82c6b
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/tan_edom_1.ql
@@ -0,0 +1,2 @@
+
+ select tan(1.5707962) from ImgCharA -- -> ~ 10^7
diff --git a/systemtest/testdata/unaryfunc/tan_edom_1.ql.java.out b/systemtest/testdata/unaryfunc/tan_edom_1.ql.java.out
new file mode 100644
index 0000000..3cc7962
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/tan_edom_1.ql.java.out
@@ -0,0 +1 @@
+1.3245401606862923E71.3245401606862923E7 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/tan_edom_1.ql.out b/systemtest/testdata/unaryfunc/tan_edom_1.ql.out
new file mode 100644
index 0000000..56490a1
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/tan_edom_1.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: 1.32454e+07
+Element 2: 1.32454e+07
+-- Testbed end block:
diff --git a/systemtest/testdata/unaryfunc/tan_edom_2.ql b/systemtest/testdata/unaryfunc/tan_edom_2.ql
new file mode 100644
index 0000000..f541dd2
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/tan_edom_2.ql
@@ -0,0 +1,2 @@
+
+ select tan(-1.5707962) from ImgCharA -- -> ~ -10^7
diff --git a/systemtest/testdata/unaryfunc/tan_edom_2.ql.java.out b/systemtest/testdata/unaryfunc/tan_edom_2.ql.java.out
new file mode 100644
index 0000000..01d4511
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/tan_edom_2.ql.java.out
@@ -0,0 +1 @@
+-1.3245401606862923E7-1.3245401606862923E7 \ No newline at end of file
diff --git a/systemtest/testdata/unaryfunc/tan_edom_2.ql.out b/systemtest/testdata/unaryfunc/tan_edom_2.ql.out
new file mode 100644
index 0000000..783f49c
--- /dev/null
+++ b/systemtest/testdata/unaryfunc/tan_edom_2.ql.out
@@ -0,0 +1,6 @@
+-- Testbed line: result_type=set<double>
+-- Testbed line: result_elements=2
+-- Testbed start block:
+Element 1: -1.32454e+07
+Element 2: -1.32454e+07
+-- Testbed end block:
diff --git a/systemtest/testdata/updateset1/u1_create.ql b/systemtest/testdata/updateset1/u1_create.ql
new file mode 100644
index 0000000..6c7aaec
--- /dev/null
+++ b/systemtest/testdata/updateset1/u1_create.ql
@@ -0,0 +1 @@
+CREATE COLLECTION UpdateULong1 ULongSet
diff --git a/systemtest/testdata/updateset1/u1_create.ql.java.out b/systemtest/testdata/updateset1/u1_create.ql.java.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset1/u1_create.ql.java.out
diff --git a/systemtest/testdata/updateset1/u1_create.ql.out b/systemtest/testdata/updateset1/u1_create.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset1/u1_create.ql.out
diff --git a/systemtest/testdata/updateset1/u2_insert.ql b/systemtest/testdata/updateset1/u2_insert.ql
new file mode 100644
index 0000000..4e0e455
--- /dev/null
+++ b/systemtest/testdata/updateset1/u2_insert.ql
@@ -0,0 +1 @@
+insert into UpdateULong1 values $1
diff --git a/systemtest/testdata/updateset1/u2_insert.ql.java.out b/systemtest/testdata/updateset1/u2_insert.ql.java.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset1/u2_insert.ql.java.out
diff --git a/systemtest/testdata/updateset1/u2_insert.ql.out b/systemtest/testdata/updateset1/u2_insert.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset1/u2_insert.ql.out
diff --git a/systemtest/testdata/updateset1/u3_lookup.ql b/systemtest/testdata/updateset1/u3_lookup.ql
new file mode 100644
index 0000000..cd258f6
--- /dev/null
+++ b/systemtest/testdata/updateset1/u3_lookup.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <ulong, [0:10,0:10]>>
+-- Testbed: result_elements=1
+
+SELECT a
+FROM UpdateULong1 AS a
diff --git a/systemtest/testdata/updateset1/u3_lookup.ql.java.out b/systemtest/testdata/updateset1/u3_lookup.ql.java.out
new file mode 100644
index 0000000..aee8152
--- /dev/null
+++ b/systemtest/testdata/updateset1/u3_lookup.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayLong
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 968
+ 0 0 0 0 0 1 2 3 0 0 0 0 4 5 6 7 0 0 0 0 8 9 10 11 0 0 0 0 12 13 14 15 0 0 0 0 16 17 18 19 0 0 0 0 20 21 22 23 0 0 0 0 24 25 26 27 0 0 0 0 28 29 30 31 0 0 0 0 32 33 34 35 0 0 0 0 36 37 38 39 0 0 0 0 40 41 42 43 0 0 0 0 44 45 46 47 0 0 0 0 48 49 50 51 0 0 0 0 52 53 54 55 0 0 0 0 56 57 58 59 0 0 0 0 60 61 62 63 0 0 0 0 64 65 66 67 0 0 0 0 68 69 70 71 0 0 0 0 72 73 74 75 0 0 0 0 76 77 78 79 0 0 0 0 80 81 82 83 0 0 0 0 84 85 86 87 0 0 0 0 88 89 90 91 0 0 0 0 92 93 94 95 0 0 0 0 96 97 98 99 0 0 0 0 100 101 102 103 0 0 0 0 104 105 106 107 0 0 0 0 108 109 110 111 0 0 0 0 112 113 114 115 0 0 0 0 116 117 118 119 0 0 0 0 120 121 122 123 0 0 0 0 124 125 126 127 0 0 0 0 -128 -127 -126 -125 0 0 0 0 -124 -123 -122 -121 0 0 0 0 -120 -119 -118 -117 0 0 0 0 -116 -115 -114 -113 0 0 0 0 -112 -111 -110 -109 0 0 0 0 -108 -107 -106 -105 0 0 0 0 -104 -103 -102 -101 0 0 0 0 -100 -99 -98 -97 0 0 0 0 -96 -95 -94 -93 0 0 0 0 -92 -91 -90 -89 0 0 0 0 -88 -87 -86 -85 0 0 0 0 -84 -83 -82 -81 0 0 0 0 -80 -79 -78 -77 0 0 0 0 -76 -75 -74 -73 0 0 0 0 -72 -71 -70 -69 0 0 0 0 -68 -67 -66 -65 0 0 0 0 -64 -63 -62 -61 0 0 0 0 -60 -59 -58 -57 0 0 0 0 -56 -55 -54 -53 0 0 0 0 -52 -51 -50 -49 0 0 0 0 -48 -47 -46 -45 0 0 0 0 -44 -43 -42 -41 0 0 0 0 -40 -39 -38 -37 0 0 0 0 -36 -35 -34 -33 0 0 0 0 -32 -31 -30 -29 0 0 0 0 -28 -27 -26 -25 0 0 0 0 -24 -23 -22 -21 0 0 0 0 -20 -19 -18 -17 0 0 0 0 -16 -15 -14 -13 0 0 0 0 -12 -11 -10 -9 0 0 0 0 -8 -7 -6 -5 0 0 0 0 -4 -3 -2 -1 0 0 0 0 0 1 2 3 0 0 0 0 4 5 6 7 0 0 0 0 8 9 10 11 0 0 0 0 12 13 14 15 0 0 0 0 16 17 18 19 0 0 0 0 20 21 22 23 0 0 0 0 24 25 26 27 0 0 0 0 28 29 30 31 0 0 0 0 32 33 34 35 0 0 0 0 36 37 38 39 0 0 0 0 40 41 42 43 0 0 0 0 44 45 46 47 0 0 0 0 48 49 50 51 0 0 0 0 52 53 54 55 0 0 0 0 56 57 58 59 0 0 0 0 60 61 62 63 0 0 0 0 64 65 66 67 0 0 0 0 68 69 70 71 0 0 0 0 72 73 74 75 0 0 0 0 76 77 78 79 0 0 0 0 80 81 82 83 0 0 0 0 84 85 86 87 0 0 0 0 88 89 90 91 0 0 0 0 92 93 94 95 0 0 0 0 96 97 98 99 0 0 0 0 100 101 102 103 0 0 0 0 104 105 106 107 0 0 0 0 108 109 110 111 0 0 0 0 112 113 114 115 0 0 0 0 116 117 118 119 0 0 0 0 120 121 122 123 0 0 0 0 124 125 126 127 0 0 0 0 -128 -127 -126 -125 0 0 0 0 -124 -123 -122 -121 0 0 0 0 -120 -119 -118 -117 0 0 0 0 -116 -115 -114 -113 0 0 0 0 -112 -111 -110 -109 0 0 0 0 -108 -107 -106 -105 0 0 0 0 -104 -103 -102 -101 0 0 0 0 -100 -99 -98 -97 0 0 0 0 -96 -95 -94 -93 0 0 0 0 -92 -91 -90 -89 0 0 0 0 -88 -87 -86 -85 0 0 0 0 -84 -83 -82 -81 0 0 0 0 -80 -79 -78 -77 0 0 0 0 -76 -75 -74 -73 0 0 0 0 -72 -71 -70 -69 0 0 0 0 -68 -67 -66 -65 0 0 0 0 -64 -63 -62 -61 0 0 0 0 -60 -59 -58 -57 0 0 0 0 -56 -55 -54 -53 0 0 0 0 -52 -51 -50 -49 0 0 0 0 -48 -47 -46 -45 0 0 0 0 -44 -43 -42 -41 0 0 0 0 -40 -39 -38 -37 0 0 0 0 -36 -35 -34 -33 0 0 0 0 -32 -31 -30 -29 \ No newline at end of file
diff --git a/systemtest/testdata/updateset1/u3_lookup.ql.out b/systemtest/testdata/updateset1/u3_lookup.ql.out
new file mode 100644
index 0000000..27b664a
--- /dev/null
+++ b/systemtest/testdata/updateset1/u3_lookup.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <ulong, [0:10,0:10]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <ulong, [0:10,0:10]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 484
+ 9 9 9 9 9 9 9 9 9 9 9
+ 9 9 9 9 9 9 9 9 9 9 9
+ 9 9 9 9 9 9 9 9 9 9 9
+ 9 9 9 9 9 9 9 9 9 9 9
+ 9 9 9 9 9 9 9 9 9 9 9
+ 9 9 9 9 9 9 9 9 9 9 9
+ 9 9 9 9 9 9 9 9 9 9 9
+ 9 9 9 9 9 9 9 9 9 9 9
+ 9 9 9 9 9 9 9 9 9 9 9
+ 9 9 9 9 9 9 9 9 9 9 9
+ 9 9 9 9 9 9 9 9 9 9 9
+-- Testbed end block:
diff --git a/systemtest/testdata/updateset1/u4_update.ql b/systemtest/testdata/updateset1/u4_update.ql
new file mode 100644
index 0000000..33bc899
--- /dev/null
+++ b/systemtest/testdata/updateset1/u4_update.ql
@@ -0,0 +1,3 @@
+UPDATE UpdateULong1 AS image
+SET image ASSIGN $1[7:9,7:9]*2ul
+
diff --git a/systemtest/testdata/updateset1/u4_update.ql.java.out b/systemtest/testdata/updateset1/u4_update.ql.java.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset1/u4_update.ql.java.out
diff --git a/systemtest/testdata/updateset1/u4_update.ql.out b/systemtest/testdata/updateset1/u4_update.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset1/u4_update.ql.out
diff --git a/systemtest/testdata/updateset1/u51_lookup.ql b/systemtest/testdata/updateset1/u51_lookup.ql
new file mode 100644
index 0000000..cd258f6
--- /dev/null
+++ b/systemtest/testdata/updateset1/u51_lookup.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <ulong, [0:10,0:10]>>
+-- Testbed: result_elements=1
+
+SELECT a
+FROM UpdateULong1 AS a
diff --git a/systemtest/testdata/updateset1/u51_lookup.ql.java.out b/systemtest/testdata/updateset1/u51_lookup.ql.java.out
new file mode 100644
index 0000000..d48dffe
--- /dev/null
+++ b/systemtest/testdata/updateset1/u51_lookup.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayLong
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 968
+ 0 0 0 0 0 1 2 3 0 0 0 0 4 5 6 7 0 0 0 0 8 9 10 11 0 0 0 0 12 13 14 15 0 0 0 0 16 17 18 19 0 0 0 0 20 21 22 23 0 0 0 0 24 25 26 27 0 0 0 0 28 29 30 31 0 0 0 0 32 33 34 35 0 0 0 0 36 37 38 39 0 0 0 0 40 41 42 43 0 0 0 0 44 45 46 47 0 0 0 0 48 49 50 51 0 0 0 0 52 53 54 55 0 0 0 0 56 57 58 59 0 0 0 0 60 61 62 63 0 0 0 0 64 65 66 67 0 0 0 0 68 69 70 71 0 0 0 0 72 73 74 75 0 0 0 0 76 77 78 79 0 0 0 0 80 81 82 83 0 0 0 0 84 85 86 87 0 0 0 0 88 89 90 91 0 0 0 0 92 93 94 95 0 0 0 0 96 97 98 99 0 0 0 0 100 101 102 103 0 0 0 0 104 105 106 107 0 0 0 0 108 109 110 111 0 0 0 0 112 113 114 115 0 0 0 0 116 117 118 119 0 0 0 0 120 121 122 123 0 0 0 0 124 125 126 127 0 0 0 0 -128 -127 -126 -125 0 0 0 0 -124 -123 -122 -121 0 0 0 0 -120 -119 -118 -117 0 0 0 0 -116 -115 -114 -113 0 0 0 0 -112 -111 -110 -109 0 0 0 0 -108 -107 -106 -105 0 0 0 0 -104 -103 -102 -101 0 0 0 0 -100 -99 -98 -97 0 0 0 0 -96 -95 -94 -93 0 0 0 0 -92 -91 -90 -89 0 0 0 0 -88 -87 -86 -85 0 0 0 0 -84 -83 -82 -81 0 0 0 0 -80 -79 -78 -77 0 0 0 0 -76 -75 -74 -73 0 0 0 0 -72 -71 -70 -69 0 0 0 0 -68 -67 -66 -65 0 0 0 0 -64 -63 -62 -61 0 0 0 0 -60 -59 -58 -57 0 0 0 0 -56 -55 -54 -53 0 0 0 0 -52 -51 -50 -49 0 0 0 0 -48 -47 -46 -45 0 0 0 0 -44 -43 -42 -41 0 0 0 0 -40 -39 -38 -37 0 0 0 0 -36 -35 -34 -33 0 0 0 0 -32 -31 -30 -29 0 0 0 0 -28 -27 -26 -25 0 0 0 0 -24 -23 -22 -21 0 0 0 0 -20 -19 -18 -17 0 0 0 0 -16 -15 -14 -13 0 0 0 0 -12 -11 -10 -9 0 0 0 0 -8 -7 -6 -5 0 0 0 0 -4 -3 -2 -1 0 0 0 0 0 1 2 3 0 0 0 0 4 5 6 7 0 0 0 0 8 9 10 11 0 0 0 0 12 13 14 15 0 0 0 0 16 17 18 19 0 0 0 0 20 21 22 23 0 0 0 0 24 25 26 27 0 0 0 0 28 29 30 31 0 0 0 0 32 33 34 35 0 0 0 0 36 37 38 39 0 0 0 0 40 41 42 43 0 0 0 0 44 45 46 47 0 0 0 0 48 49 50 51 0 0 0 0 52 53 54 55 0 0 0 0 56 57 58 59 0 0 0 0 60 61 62 63 0 0 0 0 64 65 66 67 0 0 0 0 68 69 70 71 0 0 0 0 72 73 74 75 0 0 0 0 76 77 78 79 0 0 0 0 -96 -94 -92 -90 0 0 0 0 -88 -86 -84 -82 0 0 0 0 -80 -78 -76 -74 0 0 0 0 92 93 94 95 0 0 0 0 96 97 98 99 0 0 0 0 100 101 102 103 0 0 0 0 104 105 106 107 0 0 0 0 108 109 110 111 0 0 0 0 112 113 114 115 0 0 0 0 116 117 118 119 0 0 0 0 120 121 122 123 0 0 0 0 -8 -6 -4 -2 0 0 0 0 1 3 5 6 0 0 0 0 9 11 13 14 0 0 0 0 -120 -119 -118 -117 0 0 0 0 -116 -115 -114 -113 0 0 0 0 -112 -111 -110 -109 0 0 0 0 -108 -107 -106 -105 0 0 0 0 -104 -103 -102 -101 0 0 0 0 -100 -99 -98 -97 0 0 0 0 -96 -95 -94 -93 0 0 0 0 -92 -91 -90 -89 0 0 0 0 81 83 85 86 0 0 0 0 89 91 93 94 0 0 0 0 97 99 101 102 0 0 0 0 -76 -75 -74 -73 0 0 0 0 -72 -71 -70 -69 0 0 0 0 -68 -67 -66 -65 0 0 0 0 -64 -63 -62 -61 0 0 0 0 -60 -59 -58 -57 0 0 0 0 -56 -55 -54 -53 0 0 0 0 -52 -51 -50 -49 0 0 0 0 -48 -47 -46 -45 0 0 0 0 -44 -43 -42 -41 0 0 0 0 -40 -39 -38 -37 0 0 0 0 -36 -35 -34 -33 0 0 0 0 -32 -31 -30 -29 \ No newline at end of file
diff --git a/systemtest/testdata/updateset1/u51_lookup.ql.out b/systemtest/testdata/updateset1/u51_lookup.ql.out
new file mode 100644
index 0000000..304bcda
--- /dev/null
+++ b/systemtest/testdata/updateset1/u51_lookup.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <ulong, [0:10,0:10]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <ulong, [0:10,0:10]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 484
+ 9 9 9 9 9 9 9 9 9 9 9
+ 9 9 9 9 9 9 9 9 9 9 9
+ 9 9 9 9 9 9 9 9 9 9 9
+ 9 9 9 9 9 9 9 9 9 9 9
+ 9 9 9 9 9 9 9 9 9 9 9
+ 9 9 9 9 9 9 9 9 9 9 9
+ 9 9 9 9 9 9 9 9 9 9 9
+ 9 9 9 9 9 9 9 18 18 18 9
+ 9 9 9 9 9 9 9 18 18 18 9
+ 9 9 9 9 9 9 9 18 18 18 9
+ 9 9 9 9 9 9 9 9 9 9 9
+-- Testbed end block:
diff --git a/systemtest/testdata/updateset1/u5_deletemdd.ql b/systemtest/testdata/updateset1/u5_deletemdd.ql
new file mode 100644
index 0000000..d6b362b
--- /dev/null
+++ b/systemtest/testdata/updateset1/u5_deletemdd.ql
@@ -0,0 +1,2 @@
+DELETE FROM UpdateULong1 AS a
+WHERE true
diff --git a/systemtest/testdata/updateset1/u5_deletemdd.ql.java.out b/systemtest/testdata/updateset1/u5_deletemdd.ql.java.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset1/u5_deletemdd.ql.java.out
diff --git a/systemtest/testdata/updateset1/u5_deletemdd.ql.out b/systemtest/testdata/updateset1/u5_deletemdd.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset1/u5_deletemdd.ql.out
diff --git a/systemtest/testdata/updateset1/u7_dropcoll.ql b/systemtest/testdata/updateset1/u7_dropcoll.ql
new file mode 100644
index 0000000..e053de6
--- /dev/null
+++ b/systemtest/testdata/updateset1/u7_dropcoll.ql
@@ -0,0 +1 @@
+DROP COLLECTION UpdateULong1
diff --git a/systemtest/testdata/updateset1/u7_dropcoll.ql.java.out b/systemtest/testdata/updateset1/u7_dropcoll.ql.java.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset1/u7_dropcoll.ql.java.out
diff --git a/systemtest/testdata/updateset1/u7_dropcoll.ql.out b/systemtest/testdata/updateset1/u7_dropcoll.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset1/u7_dropcoll.ql.out
diff --git a/systemtest/testdata/updateset2/u1_create.ql b/systemtest/testdata/updateset2/u1_create.ql
new file mode 100644
index 0000000..fad7183
--- /dev/null
+++ b/systemtest/testdata/updateset2/u1_create.ql
@@ -0,0 +1 @@
+CREATE COLLECTION UpdateULong2 ULongSet
diff --git a/systemtest/testdata/updateset2/u1_create.ql.java.out b/systemtest/testdata/updateset2/u1_create.ql.java.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset2/u1_create.ql.java.out
diff --git a/systemtest/testdata/updateset2/u1_create.ql.out b/systemtest/testdata/updateset2/u1_create.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset2/u1_create.ql.out
diff --git a/systemtest/testdata/updateset2/u2_insert.ql b/systemtest/testdata/updateset2/u2_insert.ql
new file mode 100644
index 0000000..e345122
--- /dev/null
+++ b/systemtest/testdata/updateset2/u2_insert.ql
@@ -0,0 +1 @@
+insert into UpdateULong2 values $1
diff --git a/systemtest/testdata/updateset2/u2_insert.ql.java.out b/systemtest/testdata/updateset2/u2_insert.ql.java.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset2/u2_insert.ql.java.out
diff --git a/systemtest/testdata/updateset2/u2_insert.ql.out b/systemtest/testdata/updateset2/u2_insert.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset2/u2_insert.ql.out
diff --git a/systemtest/testdata/updateset2/u4_update.ql b/systemtest/testdata/updateset2/u4_update.ql
new file mode 100644
index 0000000..76c2a42
--- /dev/null
+++ b/systemtest/testdata/updateset2/u4_update.ql
@@ -0,0 +1,3 @@
+UPDATE UpdateULong2 AS image
+SET image ASSIGN < [11:11,0:10] 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul, 1ul >
+
diff --git a/systemtest/testdata/updateset2/u4_update.ql.java.out b/systemtest/testdata/updateset2/u4_update.ql.java.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset2/u4_update.ql.java.out
diff --git a/systemtest/testdata/updateset2/u4_update.ql.out b/systemtest/testdata/updateset2/u4_update.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset2/u4_update.ql.out
diff --git a/systemtest/testdata/updateset2/u5_update.ql b/systemtest/testdata/updateset2/u5_update.ql
new file mode 100644
index 0000000..6ad018e
--- /dev/null
+++ b/systemtest/testdata/updateset2/u5_update.ql
@@ -0,0 +1,3 @@
+UPDATE UpdateULong2 AS image
+SET image ASSIGN < [0:11,11:11] 1ul; 1ul; 1ul; 1ul; 1ul; 1ul; 1ul; 1ul; 1ul; 1ul; 1ul, 1ul >
+
diff --git a/systemtest/testdata/updateset2/u5_update.ql.java.out b/systemtest/testdata/updateset2/u5_update.ql.java.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset2/u5_update.ql.java.out
diff --git a/systemtest/testdata/updateset2/u5_update.ql.out b/systemtest/testdata/updateset2/u5_update.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset2/u5_update.ql.out
diff --git a/systemtest/testdata/updateset2/u97_lookup.ql b/systemtest/testdata/updateset2/u97_lookup.ql
new file mode 100644
index 0000000..037ef28
--- /dev/null
+++ b/systemtest/testdata/updateset2/u97_lookup.ql
@@ -0,0 +1,5 @@
+-- Testbed: result_type=set <marray <ulong, [0:10,0:10]>>
+-- Testbed: result_elements=1
+
+SELECT a
+FROM UpdateULong2 AS a
diff --git a/systemtest/testdata/updateset2/u97_lookup.ql.java.out b/systemtest/testdata/updateset2/u97_lookup.ql.java.out
new file mode 100644
index 0000000..4d57291
--- /dev/null
+++ b/systemtest/testdata/updateset2/u97_lookup.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayLong
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:11,0:11]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 1152
+ 0 0 0 0 0 1 2 3 0 0 0 0 4 5 6 7 0 0 0 0 8 9 10 11 0 0 0 0 12 13 14 15 0 0 0 0 16 17 18 19 0 0 0 0 20 21 22 23 0 0 0 0 24 25 26 27 0 0 0 0 28 29 30 31 0 0 0 0 32 33 34 35 0 0 0 0 36 37 38 39 0 0 0 0 40 41 42 43 0 0 0 0 0 0 0 1 0 0 0 0 44 45 46 47 0 0 0 0 48 49 50 51 0 0 0 0 52 53 54 55 0 0 0 0 56 57 58 59 0 0 0 0 60 61 62 63 0 0 0 0 64 65 66 67 0 0 0 0 68 69 70 71 0 0 0 0 72 73 74 75 0 0 0 0 76 77 78 79 0 0 0 0 80 81 82 83 0 0 0 0 84 85 86 87 0 0 0 0 0 0 0 1 0 0 0 0 88 89 90 91 0 0 0 0 92 93 94 95 0 0 0 0 96 97 98 99 0 0 0 0 100 101 102 103 0 0 0 0 104 105 106 107 0 0 0 0 108 109 110 111 0 0 0 0 112 113 114 115 0 0 0 0 116 117 118 119 0 0 0 0 120 121 122 123 0 0 0 0 124 125 126 127 0 0 0 0 -128 -127 -126 -125 0 0 0 0 0 0 0 1 0 0 0 0 -124 -123 -122 -121 0 0 0 0 -120 -119 -118 -117 0 0 0 0 -116 -115 -114 -113 0 0 0 0 -112 -111 -110 -109 0 0 0 0 -108 -107 -106 -105 0 0 0 0 -104 -103 -102 -101 0 0 0 0 -100 -99 -98 -97 0 0 0 0 -96 -95 -94 -93 0 0 0 0 -92 -91 -90 -89 0 0 0 0 -88 -87 -86 -85 0 0 0 0 -84 -83 -82 -81 0 0 0 0 0 0 0 1 0 0 0 0 -80 -79 -78 -77 0 0 0 0 -76 -75 -74 -73 0 0 0 0 -72 -71 -70 -69 0 0 0 0 -68 -67 -66 -65 0 0 0 0 -64 -63 -62 -61 0 0 0 0 -60 -59 -58 -57 0 0 0 0 -56 -55 -54 -53 0 0 0 0 -52 -51 -50 -49 0 0 0 0 -48 -47 -46 -45 0 0 0 0 -44 -43 -42 -41 0 0 0 0 -40 -39 -38 -37 0 0 0 0 0 0 0 1 0 0 0 0 -36 -35 -34 -33 0 0 0 0 -32 -31 -30 -29 0 0 0 0 -28 -27 -26 -25 0 0 0 0 -24 -23 -22 -21 0 0 0 0 -20 -19 -18 -17 0 0 0 0 -16 -15 -14 -13 0 0 0 0 -12 -11 -10 -9 0 0 0 0 -8 -7 -6 -5 0 0 0 0 -4 -3 -2 -1 0 0 0 0 0 1 2 3 0 0 0 0 4 5 6 7 0 0 0 0 0 0 0 1 0 0 0 0 8 9 10 11 0 0 0 0 12 13 14 15 0 0 0 0 16 17 18 19 0 0 0 0 20 21 22 23 0 0 0 0 24 25 26 27 0 0 0 0 28 29 30 31 0 0 0 0 32 33 34 35 0 0 0 0 36 37 38 39 0 0 0 0 40 41 42 43 0 0 0 0 44 45 46 47 0 0 0 0 48 49 50 51 0 0 0 0 0 0 0 1 0 0 0 0 52 53 54 55 0 0 0 0 56 57 58 59 0 0 0 0 60 61 62 63 0 0 0 0 64 65 66 67 0 0 0 0 68 69 70 71 0 0 0 0 72 73 74 75 0 0 0 0 76 77 78 79 0 0 0 0 80 81 82 83 0 0 0 0 84 85 86 87 0 0 0 0 88 89 90 91 0 0 0 0 92 93 94 95 0 0 0 0 0 0 0 1 0 0 0 0 96 97 98 99 0 0 0 0 100 101 102 103 0 0 0 0 104 105 106 107 0 0 0 0 108 109 110 111 0 0 0 0 112 113 114 115 0 0 0 0 116 117 118 119 0 0 0 0 120 121 122 123 0 0 0 0 124 125 126 127 0 0 0 0 -128 -127 -126 -125 0 0 0 0 -124 -123 -122 -121 0 0 0 0 -120 -119 -118 -117 0 0 0 0 0 0 0 1 0 0 0 0 -116 -115 -114 -113 0 0 0 0 -112 -111 -110 -109 0 0 0 0 -108 -107 -106 -105 0 0 0 0 -104 -103 -102 -101 0 0 0 0 -100 -99 -98 -97 0 0 0 0 -96 -95 -94 -93 0 0 0 0 -92 -91 -90 -89 0 0 0 0 -88 -87 -86 -85 0 0 0 0 -84 -83 -82 -81 0 0 0 0 -80 -79 -78 -77 0 0 0 0 -76 -75 -74 -73 0 0 0 0 0 0 0 1 0 0 0 0 -72 -71 -70 -69 0 0 0 0 -68 -67 -66 -65 0 0 0 0 -64 -63 -62 -61 0 0 0 0 -60 -59 -58 -57 0 0 0 0 -56 -55 -54 -53 0 0 0 0 -52 -51 -50 -49 0 0 0 0 -48 -47 -46 -45 0 0 0 0 -44 -43 -42 -41 0 0 0 0 -40 -39 -38 -37 0 0 0 0 -36 -35 -34 -33 0 0 0 0 -32 -31 -30 -29 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 \ No newline at end of file
diff --git a/systemtest/testdata/updateset2/u97_lookup.ql.out b/systemtest/testdata/updateset2/u97_lookup.ql.out
new file mode 100644
index 0000000..62bcea6
--- /dev/null
+++ b/systemtest/testdata/updateset2/u97_lookup.ql.out
@@ -0,0 +1,25 @@
+-- Testbed line: result_type=set <marray <ulong, [0:11,0:11]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <ulong, [0:11,0:11]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:11,0:11]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 576
+ 9 9 9 9 9 9 9 9 9 9 9 1
+ 9 9 9 9 9 9 9 9 9 9 9 1
+ 9 9 9 9 9 9 9 9 9 9 9 1
+ 9 9 9 9 9 9 9 9 9 9 9 1
+ 9 9 9 9 9 9 9 9 9 9 9 1
+ 9 9 9 9 9 9 9 9 9 9 9 1
+ 9 9 9 9 9 9 9 9 9 9 9 1
+ 9 9 9 9 9 9 9 9 9 9 9 1
+ 9 9 9 9 9 9 9 9 9 9 9 1
+ 9 9 9 9 9 9 9 9 9 9 9 1
+ 9 9 9 9 9 9 9 9 9 9 9 1
+ 1 1 1 1 1 1 1 1 1 1 1 1
+-- Testbed end block:
diff --git a/systemtest/testdata/updateset2/u98_deletemdd.ql b/systemtest/testdata/updateset2/u98_deletemdd.ql
new file mode 100644
index 0000000..334eb71
--- /dev/null
+++ b/systemtest/testdata/updateset2/u98_deletemdd.ql
@@ -0,0 +1,2 @@
+DELETE FROM UpdateULong2 AS a
+WHERE true
diff --git a/systemtest/testdata/updateset2/u98_deletemdd.ql.java.out b/systemtest/testdata/updateset2/u98_deletemdd.ql.java.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset2/u98_deletemdd.ql.java.out
diff --git a/systemtest/testdata/updateset2/u98_deletemdd.ql.out b/systemtest/testdata/updateset2/u98_deletemdd.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset2/u98_deletemdd.ql.out
diff --git a/systemtest/testdata/updateset2/u99_dropcoll.ql b/systemtest/testdata/updateset2/u99_dropcoll.ql
new file mode 100644
index 0000000..96b69f4
--- /dev/null
+++ b/systemtest/testdata/updateset2/u99_dropcoll.ql
@@ -0,0 +1 @@
+DROP COLLECTION UpdateULong2
diff --git a/systemtest/testdata/updateset2/u99_dropcoll.ql.java.out b/systemtest/testdata/updateset2/u99_dropcoll.ql.java.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset2/u99_dropcoll.ql.java.out
diff --git a/systemtest/testdata/updateset2/u99_dropcoll.ql.out b/systemtest/testdata/updateset2/u99_dropcoll.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset2/u99_dropcoll.ql.out
diff --git a/systemtest/testdata/updateset3/u01_create.ql b/systemtest/testdata/updateset3/u01_create.ql
new file mode 100644
index 0000000..fad7183
--- /dev/null
+++ b/systemtest/testdata/updateset3/u01_create.ql
@@ -0,0 +1 @@
+CREATE COLLECTION UpdateULong2 ULongSet
diff --git a/systemtest/testdata/updateset3/u01_create.ql.java.out b/systemtest/testdata/updateset3/u01_create.ql.java.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset3/u01_create.ql.java.out
diff --git a/systemtest/testdata/updateset3/u01_create.ql.out b/systemtest/testdata/updateset3/u01_create.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset3/u01_create.ql.out
diff --git a/systemtest/testdata/updateset3/u02_insert.ql b/systemtest/testdata/updateset3/u02_insert.ql
new file mode 100644
index 0000000..07d8258
--- /dev/null
+++ b/systemtest/testdata/updateset3/u02_insert.ql
@@ -0,0 +1 @@
+insert into UpdateULong2 values < [0:1,0:4] 1ul, 1ul, 1ul, 1ul, 1ul; 2ul, 2ul, 2ul, 2ul, 2ul >
diff --git a/systemtest/testdata/updateset3/u02_insert.ql.java.out b/systemtest/testdata/updateset3/u02_insert.ql.java.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset3/u02_insert.ql.java.out
diff --git a/systemtest/testdata/updateset3/u02_insert.ql.out b/systemtest/testdata/updateset3/u02_insert.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset3/u02_insert.ql.out
diff --git a/systemtest/testdata/updateset3/u03_lookup.ql b/systemtest/testdata/updateset3/u03_lookup.ql
new file mode 100644
index 0000000..99cf48a
--- /dev/null
+++ b/systemtest/testdata/updateset3/u03_lookup.ql
@@ -0,0 +1,2 @@
+SELECT a
+FROM UpdateULong2 AS a
diff --git a/systemtest/testdata/updateset3/u03_lookup.ql.java.out b/systemtest/testdata/updateset3/u03_lookup.ql.java.out
new file mode 100644
index 0000000..24549dd
--- /dev/null
+++ b/systemtest/testdata/updateset3/u03_lookup.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayLong
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:1,0:4]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 80
+ 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 \ No newline at end of file
diff --git a/systemtest/testdata/updateset3/u03_lookup.ql.out b/systemtest/testdata/updateset3/u03_lookup.ql.out
new file mode 100644
index 0000000..1a2605d
--- /dev/null
+++ b/systemtest/testdata/updateset3/u03_lookup.ql.out
@@ -0,0 +1,18 @@
+-- Testbed line: result_type=set <marray <ulong, [0:1,0:4]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <ulong, [0:1,0:4]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:1,0:4]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 40
+ 1 2
+ 1 2
+ 1 2
+ 1 2
+ 1 2
+-- Testbed end block:
diff --git a/systemtest/testdata/updateset3/u04_update.ql b/systemtest/testdata/updateset3/u04_update.ql
new file mode 100644
index 0000000..9628169
--- /dev/null
+++ b/systemtest/testdata/updateset3/u04_update.ql
@@ -0,0 +1,3 @@
+UPDATE UpdateULong2 AS image
+SET image[*:*,5] ASSIGN < [0:1] 0ul, 0ul >
+
diff --git a/systemtest/testdata/updateset3/u04_update.ql.java.out b/systemtest/testdata/updateset3/u04_update.ql.java.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset3/u04_update.ql.java.out
diff --git a/systemtest/testdata/updateset3/u04_update.ql.out b/systemtest/testdata/updateset3/u04_update.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset3/u04_update.ql.out
diff --git a/systemtest/testdata/updateset3/u05_lookup.ql b/systemtest/testdata/updateset3/u05_lookup.ql
new file mode 100644
index 0000000..99cf48a
--- /dev/null
+++ b/systemtest/testdata/updateset3/u05_lookup.ql
@@ -0,0 +1,2 @@
+SELECT a
+FROM UpdateULong2 AS a
diff --git a/systemtest/testdata/updateset3/u05_lookup.ql.java.out b/systemtest/testdata/updateset3/u05_lookup.ql.java.out
new file mode 100644
index 0000000..4688cf3
--- /dev/null
+++ b/systemtest/testdata/updateset3/u05_lookup.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayLong
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:1,0:5]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 96
+ 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 \ No newline at end of file
diff --git a/systemtest/testdata/updateset3/u05_lookup.ql.out b/systemtest/testdata/updateset3/u05_lookup.ql.out
new file mode 100644
index 0000000..7813a05
--- /dev/null
+++ b/systemtest/testdata/updateset3/u05_lookup.ql.out
@@ -0,0 +1,19 @@
+-- Testbed line: result_type=set <marray <ulong, [0:1,0:5]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <ulong, [0:1,0:5]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:1,0:5]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 48
+ 1 2
+ 1 2
+ 1 2
+ 1 2
+ 1 2
+ 0 0
+-- Testbed end block:
diff --git a/systemtest/testdata/updateset3/u06_update.ql b/systemtest/testdata/updateset3/u06_update.ql
new file mode 100644
index 0000000..86c998a
--- /dev/null
+++ b/systemtest/testdata/updateset3/u06_update.ql
@@ -0,0 +1,3 @@
+UPDATE UpdateULong2 AS image
+SET image[2,*:*] ASSIGN < [0:5] 0ul, 0ul, 0ul, 0ul, 0ul, 0ul >
+
diff --git a/systemtest/testdata/updateset3/u06_update.ql.java.out b/systemtest/testdata/updateset3/u06_update.ql.java.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset3/u06_update.ql.java.out
diff --git a/systemtest/testdata/updateset3/u06_update.ql.out b/systemtest/testdata/updateset3/u06_update.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset3/u06_update.ql.out
diff --git a/systemtest/testdata/updateset3/u07_lookup.ql b/systemtest/testdata/updateset3/u07_lookup.ql
new file mode 100644
index 0000000..99cf48a
--- /dev/null
+++ b/systemtest/testdata/updateset3/u07_lookup.ql
@@ -0,0 +1,2 @@
+SELECT a
+FROM UpdateULong2 AS a
diff --git a/systemtest/testdata/updateset3/u07_lookup.ql.java.out b/systemtest/testdata/updateset3/u07_lookup.ql.java.out
new file mode 100644
index 0000000..c776c52
--- /dev/null
+++ b/systemtest/testdata/updateset3/u07_lookup.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayLong
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:2,0:5]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 144
+ 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \ No newline at end of file
diff --git a/systemtest/testdata/updateset3/u07_lookup.ql.out b/systemtest/testdata/updateset3/u07_lookup.ql.out
new file mode 100644
index 0000000..3c4b0b5
--- /dev/null
+++ b/systemtest/testdata/updateset3/u07_lookup.ql.out
@@ -0,0 +1,19 @@
+-- Testbed line: result_type=set <marray <ulong, [0:2,0:5]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <ulong, [0:2,0:5]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:2,0:5]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 72
+ 1 2 0
+ 1 2 0
+ 1 2 0
+ 1 2 0
+ 1 2 0
+ 0 0 0
+-- Testbed end block:
diff --git a/systemtest/testdata/updateset3/u08_update.ql b/systemtest/testdata/updateset3/u08_update.ql
new file mode 100644
index 0000000..b03dfff
--- /dev/null
+++ b/systemtest/testdata/updateset3/u08_update.ql
@@ -0,0 +1,3 @@
+UPDATE UpdateULong2 AS image
+SET image[*:*,sdom(image)[1].hi+1] ASSIGN < [0:2] 3ul, 3ul, 3ul >
+
diff --git a/systemtest/testdata/updateset3/u08_update.ql.java.out b/systemtest/testdata/updateset3/u08_update.ql.java.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset3/u08_update.ql.java.out
diff --git a/systemtest/testdata/updateset3/u08_update.ql.out b/systemtest/testdata/updateset3/u08_update.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset3/u08_update.ql.out
diff --git a/systemtest/testdata/updateset3/u09_update.ql b/systemtest/testdata/updateset3/u09_update.ql
new file mode 100644
index 0000000..64782bf
--- /dev/null
+++ b/systemtest/testdata/updateset3/u09_update.ql
@@ -0,0 +1,3 @@
+UPDATE UpdateULong2 AS image
+SET image[sdom(image)[0].hi+1,*:*] ASSIGN < [0:6] 3ul, 3ul, 3ul, 3ul, 3ul, 3ul, 3ul >
+
diff --git a/systemtest/testdata/updateset3/u09_update.ql.java.out b/systemtest/testdata/updateset3/u09_update.ql.java.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset3/u09_update.ql.java.out
diff --git a/systemtest/testdata/updateset3/u09_update.ql.out b/systemtest/testdata/updateset3/u09_update.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset3/u09_update.ql.out
diff --git a/systemtest/testdata/updateset3/u10_update.ql b/systemtest/testdata/updateset3/u10_update.ql
new file mode 100644
index 0000000..c7cb769
--- /dev/null
+++ b/systemtest/testdata/updateset3/u10_update.ql
@@ -0,0 +1,3 @@
+UPDATE UpdateULong2 AS image
+SET image[sdom(image)[0].hi+1,*:*] ASSIGN < [0:6] 4ul, 4ul, 4ul, 4ul, 4ul, 4ul, 4ul >
+
diff --git a/systemtest/testdata/updateset3/u10_update.ql.java.out b/systemtest/testdata/updateset3/u10_update.ql.java.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset3/u10_update.ql.java.out
diff --git a/systemtest/testdata/updateset3/u10_update.ql.out b/systemtest/testdata/updateset3/u10_update.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset3/u10_update.ql.out
diff --git a/systemtest/testdata/updateset3/u97_lookup.ql b/systemtest/testdata/updateset3/u97_lookup.ql
new file mode 100644
index 0000000..99cf48a
--- /dev/null
+++ b/systemtest/testdata/updateset3/u97_lookup.ql
@@ -0,0 +1,2 @@
+SELECT a
+FROM UpdateULong2 AS a
diff --git a/systemtest/testdata/updateset3/u97_lookup.ql.java.out b/systemtest/testdata/updateset3/u97_lookup.ql.java.out
new file mode 100644
index 0000000..11794b4
--- /dev/null
+++ b/systemtest/testdata/updateset3/u97_lookup.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayLong
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:4,0:6]
+ TilingDomain..........: [0:125,0:125]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 8
+ Data format...........: 0
+ Data size (bytes).....: 280
+ 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 \ No newline at end of file
diff --git a/systemtest/testdata/updateset3/u97_lookup.ql.out b/systemtest/testdata/updateset3/u97_lookup.ql.out
new file mode 100644
index 0000000..7224cf7
--- /dev/null
+++ b/systemtest/testdata/updateset3/u97_lookup.ql.out
@@ -0,0 +1,20 @@
+-- Testbed line: result_type=set <marray <ulong, [0:4,0:6]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <ulong, [0:4,0:6]>
+ Type Schema...........: marray< ulong >
+ Domain................: [0:4,0:6]
+ Base Type Schema......: ulong
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 140
+ 1 2 0 3 4
+ 1 2 0 3 4
+ 1 2 0 3 4
+ 1 2 0 3 4
+ 1 2 0 3 4
+ 0 0 0 3 4
+ 3 3 3 3 4
+-- Testbed end block:
diff --git a/systemtest/testdata/updateset3/u98_deletemdd.ql b/systemtest/testdata/updateset3/u98_deletemdd.ql
new file mode 100644
index 0000000..334eb71
--- /dev/null
+++ b/systemtest/testdata/updateset3/u98_deletemdd.ql
@@ -0,0 +1,2 @@
+DELETE FROM UpdateULong2 AS a
+WHERE true
diff --git a/systemtest/testdata/updateset3/u98_deletemdd.ql.java.out b/systemtest/testdata/updateset3/u98_deletemdd.ql.java.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset3/u98_deletemdd.ql.java.out
diff --git a/systemtest/testdata/updateset3/u98_deletemdd.ql.out b/systemtest/testdata/updateset3/u98_deletemdd.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset3/u98_deletemdd.ql.out
diff --git a/systemtest/testdata/updateset3/u99_dropcoll.ql b/systemtest/testdata/updateset3/u99_dropcoll.ql
new file mode 100644
index 0000000..96b69f4
--- /dev/null
+++ b/systemtest/testdata/updateset3/u99_dropcoll.ql
@@ -0,0 +1 @@
+DROP COLLECTION UpdateULong2
diff --git a/systemtest/testdata/updateset3/u99_dropcoll.ql.java.out b/systemtest/testdata/updateset3/u99_dropcoll.ql.java.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset3/u99_dropcoll.ql.java.out
diff --git a/systemtest/testdata/updateset3/u99_dropcoll.ql.out b/systemtest/testdata/updateset3/u99_dropcoll.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset3/u99_dropcoll.ql.out
diff --git a/systemtest/testdata/updateset4/u01_create.ql b/systemtest/testdata/updateset4/u01_create.ql
new file mode 100644
index 0000000..bcb9280
--- /dev/null
+++ b/systemtest/testdata/updateset4/u01_create.ql
@@ -0,0 +1 @@
+CREATE COLLECTION UpdateFloat1 FloatSet
diff --git a/systemtest/testdata/updateset4/u01_create.ql.java.out b/systemtest/testdata/updateset4/u01_create.ql.java.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset4/u01_create.ql.java.out
diff --git a/systemtest/testdata/updateset4/u01_create.ql.out b/systemtest/testdata/updateset4/u01_create.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset4/u01_create.ql.out
diff --git a/systemtest/testdata/updateset4/u02_insert.ql b/systemtest/testdata/updateset4/u02_insert.ql
new file mode 100644
index 0000000..cc0a568
--- /dev/null
+++ b/systemtest/testdata/updateset4/u02_insert.ql
@@ -0,0 +1 @@
+insert into UpdateFloat1 values $1 * 2f
diff --git a/systemtest/testdata/updateset4/u02_insert.ql.java.out b/systemtest/testdata/updateset4/u02_insert.ql.java.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset4/u02_insert.ql.java.out
diff --git a/systemtest/testdata/updateset4/u02_insert.ql.out b/systemtest/testdata/updateset4/u02_insert.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset4/u02_insert.ql.out
diff --git a/systemtest/testdata/updateset4/u97_lookup.ql b/systemtest/testdata/updateset4/u97_lookup.ql
new file mode 100644
index 0000000..a5da017
--- /dev/null
+++ b/systemtest/testdata/updateset4/u97_lookup.ql
@@ -0,0 +1,2 @@
+SELECT a
+FROM UpdateFloat1 AS a
diff --git a/systemtest/testdata/updateset4/u97_lookup.ql.java.out b/systemtest/testdata/updateset4/u97_lookup.ql.java.out
new file mode 100644
index 0000000..fe4e976
--- /dev/null
+++ b/systemtest/testdata/updateset4/u97_lookup.ql.java.out
@@ -0,0 +1,15 @@
+
+rasj.RasMArrayFloat
+ Object Name...........:
+ Object Type...........: 1
+ Object Type Name......:
+ Type Structure........:
+ Type Schema...........: <nn>
+ Domain................: [0:10,0:10]
+ TilingDomain..........: [0:177,0:177]
+ TileSize..............: 128000 bytes
+ Base Type Schema......: <nn>
+ Base Type Length......: 4
+ Data format...........: 0
+ Data size (bytes).....: 484
+ 72 1 1 -128 77 0 -96 -63 77 -128 -112 -95 77 -64 -48 -31 78 0 -120 -111 78 32 -88 -79 78 64 -56 -47 78 96 -24 -15 78 -128 -124 -119 78 -112 -108 -103 78 -96 -92 -87 78 -80 -76 -71 78 -64 -60 -55 78 -48 -44 -39 78 -32 -28 -23 78 -16 -12 -7 79 0 -126 -123 79 8 -118 -115 79 16 -110 -107 79 24 -102 -99 79 32 -94 -91 79 40 -86 -83 79 48 -78 -75 79 56 -70 -67 79 64 -62 -59 79 72 -54 -51 79 80 -46 -43 79 88 -38 -35 79 96 -30 -27 79 104 -22 -19 79 112 -14 -11 79 120 -6 -3 -49 126 -4 -5 -49 118 -12 -13 -49 110 -20 -21 -49 102 -28 -29 -49 94 -36 -37 -49 86 -44 -45 -49 78 -52 -53 -49 70 -60 -61 -49 62 -68 -69 -49 54 -76 -77 -49 46 -84 -85 -49 38 -92 -93 -49 30 -100 -101 -49 22 -108 -109 -49 14 -116 -117 -49 6 -124 -125 -50 -4 -8 -11 -50 -20 -24 -27 -50 -36 -40 -43 -50 -52 -56 -59 -50 -68 -72 -75 -50 -84 -88 -91 -50 -100 -104 -107 -50 -116 -120 -123 -50 120 -16 -23 -50 88 -48 -55 -50 56 -80 -87 -50 24 -112 -119 -51 -16 -32 -47 -51 -80 -96 -111 -51 96 -64 -95 -52 -64 -128 64 72 1 1 -128 77 0 -96 -63 77 -128 -112 -95 77 -64 -48 -31 78 0 -120 -111 78 32 -88 -79 78 64 -56 -47 78 96 -24 -15 78 -128 -124 -119 78 -112 -108 -103 78 -96 -92 -87 78 -80 -76 -71 78 -64 -60 -55 78 -48 -44 -39 78 -32 -28 -23 78 -16 -12 -7 79 0 -126 -123 79 8 -118 -115 79 16 -110 -107 79 24 -102 -99 79 32 -94 -91 79 40 -86 -83 79 48 -78 -75 79 56 -70 -67 79 64 -62 -59 79 72 -54 -51 79 80 -46 -43 79 88 -38 -35 79 96 -30 -27 79 104 -22 -19 79 112 -14 -11 79 120 -6 -3 -49 126 -4 -5 -49 118 -12 -13 -49 110 -20 -21 -49 102 -28 -29 -49 94 -36 -37 -49 86 -44 -45 -49 78 -52 -53 -49 70 -60 -61 -49 62 -68 -69 -49 54 -76 -77 -49 46 -84 -85 -49 38 -92 -93 -49 30 -100 -101 -49 22 -108 -109 -49 14 -116 -117 -49 6 -124 -125 -50 -4 -8 -11 -50 -20 -24 -27 -50 -36 -40 -43 -50 -52 -56 -59 -50 -68 -72 -75 -50 -84 -88 -91 -50 -100 -104 -107 -50 -116 -120 -123 -50 120 -16 -23 \ No newline at end of file
diff --git a/systemtest/testdata/updateset4/u97_lookup.ql.out b/systemtest/testdata/updateset4/u97_lookup.ql.out
new file mode 100644
index 0000000..67c8388
--- /dev/null
+++ b/systemtest/testdata/updateset4/u97_lookup.ql.out
@@ -0,0 +1,24 @@
+-- Testbed line: result_type=set <marray <float, [0:10,0:10]>>
+-- Testbed line: result_elements=1
+-- Testbed start block:
+Image 1
+GMarray
+ Type Structure........: marray <float, [0:10,0:10]>
+ Type Schema...........: marray< float >
+ Domain................: [0:10,0:10]
+ Base Type Schema......: float
+ Base Type Length......: 4
+ Data format.......... : Array
+ Data size (bytes).... : 484
+ 18 18 18 18 18 18 18 18 18 18 18
+ 18 18 18 18 18 18 18 18 18 18 18
+ 18 18 18 18 18 18 18 18 18 18 18
+ 18 18 18 18 18 18 18 18 18 18 18
+ 18 18 18 18 18 18 18 18 18 18 18
+ 18 18 18 18 18 18 18 18 18 18 18
+ 18 18 18 18 18 18 18 18 18 18 18
+ 18 18 18 18 18 18 18 18 18 18 18
+ 18 18 18 18 18 18 18 18 18 18 18
+ 18 18 18 18 18 18 18 18 18 18 18
+ 18 18 18 18 18 18 18 18 18 18 18
+-- Testbed end block:
diff --git a/systemtest/testdata/updateset4/u98_deletemdd.ql b/systemtest/testdata/updateset4/u98_deletemdd.ql
new file mode 100644
index 0000000..7b89f8e
--- /dev/null
+++ b/systemtest/testdata/updateset4/u98_deletemdd.ql
@@ -0,0 +1,2 @@
+DELETE FROM UpdateFloat1 AS a
+WHERE true
diff --git a/systemtest/testdata/updateset4/u98_deletemdd.ql.java.out b/systemtest/testdata/updateset4/u98_deletemdd.ql.java.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset4/u98_deletemdd.ql.java.out
diff --git a/systemtest/testdata/updateset4/u98_deletemdd.ql.out b/systemtest/testdata/updateset4/u98_deletemdd.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset4/u98_deletemdd.ql.out
diff --git a/systemtest/testdata/updateset4/u99_dropcoll.ql b/systemtest/testdata/updateset4/u99_dropcoll.ql
new file mode 100644
index 0000000..3160425
--- /dev/null
+++ b/systemtest/testdata/updateset4/u99_dropcoll.ql
@@ -0,0 +1 @@
+DROP COLLECTION UpdateFloat1
diff --git a/systemtest/testdata/updateset4/u99_dropcoll.ql.java.out b/systemtest/testdata/updateset4/u99_dropcoll.ql.java.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset4/u99_dropcoll.ql.java.out
diff --git a/systemtest/testdata/updateset4/u99_dropcoll.ql.out b/systemtest/testdata/updateset4/u99_dropcoll.ql.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/systemtest/testdata/updateset4/u99_dropcoll.ql.out
diff --git a/systemtest/testjava.sh b/systemtest/testjava.sh
new file mode 100644
index 0000000..5e1cda7
--- /dev/null
+++ b/systemtest/testjava.sh
@@ -0,0 +1,353 @@
+#!/bin/ksh
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+######################### testcenter.sh header ###################
+#
+# testcenter.sh FOR:
+# Release of RASDAMAN
+#
+#
+# COMMENTS: needs class examples.TestQuery
+# This facility is not necessary because you can start manualy the server
+#
+##################################################################
+
+TESTER=$USER
+CLIENT=$HOSTNAME
+SERVER=$HOSTNAME
+BASENAME=RASBASE
+TESTDATE=$(date +"%d.%m.%Y_%H:%M:%S")
+LOGFILE=testjava.log
+LOGRCS=javasession.log
+INTERACTIVE="off"
+SCRIPTS="off"
+QUERIES="on"
+PRESERVERESULTS="off"
+DEBUGCOMMANDS="off"
+PROTOCOL=$RMANPROTOCOL
+
+if [[ $1 = "" ]]; then
+ TESTDIR="testdata"
+else
+ TESTDIR=$1
+fi
+
+showOptions()
+{
+ clear
+ echo "===================================================================="
+ echo " TEST JAVA OPTIONS:"
+ echo "===================================================================="
+ echo " Date...........................: " `date`
+ echo " (T)ester...............: " $TESTER
+ echo " (C)lient name..........: " $CLIENT
+ echo " (S)erver name..........: " $SERVER
+ echo " (B)ase name............: " $BASENAME
+ echo " (L)og file.............: " $LOGFILE
+ echo " (Q)uery dir............: " $TESTDIR
+ echo ""
+ echo " (I)nteractive..........: " $INTERACTIVE
+ echo " (P)reserve results.....: " $PRESERVERESULTS
+ echo " (D)ebug commands.......: " $DEBUGCOMMANDS
+ echo ""
+ echo " Phase (1) Test Queries.: " $QUERIES
+ echo " Phase (2) Test Scripts.: " $SCRIPTS
+ echo ""
+ echo " Protocol................: " $PROTOCOL
+}
+setParameters()
+{
+ option="*"
+
+ while [[ $option != "" ]]; do
+
+ showOptions
+
+ echo " \nEnter [tcsblqipd12] to change setting or <return> to continue! \c"
+ read option
+ echo "\n"
+
+ if [[ $option = t ]]; then
+ echo " Enter new name for tester: \c"
+ read TESTER
+ echo
+ elif [[ $option = c ]]; then
+ echo " Enter new client name: \c"
+ read CLIENT
+ echo
+ elif [[ $option = s ]]; then
+ echo " Enter new server name: \c"
+ read SERVER
+ echo
+ elif [[ $option = b ]]; then
+ echo " Enter new base name: \c"
+ read BASENAME
+ echo
+ elif [[ $option = l ]]; then
+ echo " Enter new name for the log file: \c"
+ read LOGFILE
+ echo
+ elif [[ $option = q ]]; then
+ echo " Enter new name for the query data directory: \c"
+ read TESTDIR
+ echo
+ elif [[ $option = i ]]; then
+ if [[ $INTERACTIVE = "off" ]]; then
+ INTERACTIVE="on"
+ else
+ INTERACTIVE="off"
+ fi
+ elif [[ $option = p ]]; then
+ if [[ $PRESERVERESULTS = "off" ]]; then
+ PRESERVERESULTS="on"
+ else
+ PRESERVERESULTS="off"
+ fi
+ elif [[ $option = d ]]; then
+ if [[ $DEBUGCOMMANDS = "off" ]]; then
+ DEBUGCOMMANDS="on"
+ else
+ DEBUGCOMMANDS="off"
+ fi
+ elif [[ $option = 1 ]]; then
+ if [[ $QUERIES = "off" ]]; then
+ QUERIES="on"
+ else
+ QUERIES="off"
+ fi
+ elif [[ $option = 2 ]]; then
+ if [[ $SCRIPTS = "off" ]]; then
+ SCRIPTS="on"
+ else
+ SCRIPTS="off"
+ fi
+ fi
+
+ done
+}
+
+
+
+testQuery()
+{
+ testFile=$1
+
+ echo $testCnt ". Test query: " $testFile "\c"
+
+ YesNo="y"
+ if [[ $INTERACTIVE = "on" ]]; then
+ echo " Test it (y/n) ? \c"
+ read YesNo
+ fi
+
+ if [[ $YesNo = "y" ]]; then
+ $query $testFile -testbed > testbedOutput
+ checkTestImage $testFile;
+ fi
+}
+
+
+
+testScript()
+{
+ testFile=$1
+
+ echo $testCnt ". Test script: " $testFile "\c"
+
+ YesNo="y"
+ if [[ $INTERACTIVE = "on" ]]; then
+ echo " Test it (y/n) ? \c"
+ read YesNo
+ fi
+
+ if [[ $YesNo = "y" ]]; then
+ $testFile $SERVER $BASENAME > testbedOutput
+ checkTestImage $testFile;
+ fi
+}
+
+
+
+checkTestImage()
+{
+ returnValue="EXECUTION OK"
+
+ # create info file
+ gawk -f testOutputGen.awk testbedOutput > testbedOutputInfo
+
+ # check for verification file
+ verificationFile=$testFile".out"
+
+ if [[ ! -a $verificationFile ]]; then
+ echo FAILED
+ echo " ERROR: verification file $verificationFile does not exist"
+
+ echo " Do you want to see the output (y/n) ? \c"
+ read YesNo
+ echo "\n"
+
+ if [[ $YesNo = y ]]; then
+ echo "I. TEST FILE"
+ cat $testFile
+ echo "\n\nII. OUTPUT"
+ cat testbedOutputInfo
+ echo "\n\n"
+ fi
+
+ echo " Do you want to create a verification file (y/n) ? \c"
+ read YesNo
+ echo "\n"
+
+ if [[ $YesNo = y ]]; then
+ cp testbedOutputInfo $verificationFile
+ echo " CREATED\n"
+ returnValue="VERIFICATION FILE CREATED"
+ else
+ echo " NOT CREATED\n"
+ returnValue="VERIFICATION FILE NOT FOUND"
+ fi
+
+ else
+
+ diff testbedOutputInfo $verificationFile
+
+ if [[ $? = 1 ]]; then
+ echo "FAILED"
+ echo "\nProgram output:"
+ cat testbedOutput
+ echo "\n\n"
+ returnValue="EXECUTION FAILED"
+
+ echo " Do you want to update the verification file (y/n) ? \c"
+ read YesNo
+ echo "\n"
+
+ if [[ $YesNo = y ]]; then
+ co -l $verificationFile
+ cp testbedOutputInfo $verificationFile
+ echo " UPDATED\n"
+ ci -u -m"testcenter update" $verificationFile
+ returnValue="VERIFICATION FILE UPDATED"
+ fi
+
+ else
+ echo "OK"
+ fi
+
+ fi
+
+ rm testbedOutput testbedOutputInfo
+}
+
+
+
+#
+# main
+#
+
+# test programs
+query="$RMANBASE/java/examples/TestQuery.class"
+images="$RMANBASE/systemtest/images"
+
+if [[ ! -a $query ]]; then
+ query="$RMANBASE/java/classes/examples/TestQuery.class"
+ if [[ ! -a $query ]]; then
+ echo "\nTest program $query not found"
+ echo "Please build the program and try again."
+ return
+ fi
+fi
+
+setParameters;
+query="$query -s $SERVER -d $BASENAME"
+YesNo=""
+
+if [[ -f $LOGFILE ]]; then
+ echo "\nDelete log file $LOGFILE (y/n) ? \c"
+ read YesNo
+ echo "\n\n"
+ if [[ $YesNo = y ]]; then
+ rm $LOGFILE
+ fi
+fi
+
+
+echo "----------------------------------JAVA TEST SESSION-------------------------" >> $LOGFILE
+echo "- Date........ : " $TESTDATE >> $LOGFILE
+echo "- Tester.......: " $TESTER >> $LOGFILE
+echo "- Directory....: " $PWD/$TESTDIR >> $LOGFILE
+echo "- Client name..: " $CLIENT >> $LOGFILE
+echo "- Server name..: " $SERVER >> $LOGFILE
+echo "- Base name....: " $BASENAME >> $LOGFILE
+echo "-------------------------------------START----------------------------------" >> $LOGFILE
+
+
+
+#
+# test query files
+#
+
+if [[ $QUERIES = "on" ]]; then
+ echo "\nPhase 1: Testing Query Files\n"
+
+ if [[ $PRESERVERESULTS = "on" ]]; then
+ if [[ $DEBUGCOMMANDS = "on" ]]; then
+ echo java -Xms100m -Xmx200m -DRMANPROTOCOL=$PROTOCOL -classpath $CLASSPATH examples.TestQuery -server $SERVER -database $BASENAME -testdirectory $TESTDIR -logfile $LOGFILE -preserveresult
+ else
+ java -Xms100m -Xmx200m -DRMANPROTOCOL=$PROTOCOL -classpath $CLASSPATH examples.TestQuery -server $SERVER -database $BASENAME -testdirectory $TESTDIR -logfile $LOGFILE -preserveresult
+ fi
+ else
+ if [[ $DEBUGCOMMANDS = "on" ]]; then
+ echo java -Xms100m -Xmx200m -DRMANPROTOCOL=$PROTOCOL -classpath $CLASSPATH examples.TestQuery -server $SERVER -database $BASENAME -testdirectory $TESTDIR -logfile $LOGFILE
+ else
+ java -Xms100m -Xmx200m -DRMANPROTOCOL=$PROTOCOL -classpath $CLASSPATH examples.TestQuery -server $SERVER -database $BASENAME -testdirectory $TESTDIR -logfile $LOGFILE
+ fi
+ fi
+
+fi
+
+
+#
+# test scripts
+#
+
+if [[ $SCRIPTS = "on" ]]; then
+ echo "\nPhase 2: Testing Scripts\n"
+
+ testCnt=1
+ scriptFiles=`find scripts -name '*.sh' | sort`
+
+ for scriptFile in $scriptFiles; do
+
+ testScript $scriptFile
+
+ echo "Script " $testCnt $scriptFile":" $returnValue >> $LOGFILE
+
+ testCnt=$(($testCnt+1))
+ done
+fi
+
+echo "\n-------------------------------------END------------------------------------" >> $LOGFILE
+echo "\n\n" >> $LOGFILE
+
+
+echo "\nTesting finnished.\n"
diff --git a/tilemgr/Makefile.am b/tilemgr/Makefile.am
new file mode 100644
index 0000000..676d354
--- /dev/null
+++ b/tilemgr/Makefile.am
@@ -0,0 +1,33 @@
+# -*-Makefile-*- (for Emacs)
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+#
+# MAKEFILE FOR:
+# tilemgr
+#
+#
+# COMMENTS:
+#
+##################################################################
+
+noinst_LIBRARIES = libtilemgr.a
+libtilemgr_a_SOURCES = tile.cc tile.hh tile.icc tiler.cc tiler.hh
diff --git a/tilemgr/cell.cc b/tilemgr/cell.cc
new file mode 100644
index 0000000..bcab9cd
--- /dev/null
+++ b/tilemgr/cell.cc
@@ -0,0 +1 @@
+//not used
diff --git a/tilemgr/cell.hh b/tilemgr/cell.hh
new file mode 100644
index 0000000..4c8af27
--- /dev/null
+++ b/tilemgr/cell.hh
@@ -0,0 +1,2 @@
+//not used
+
diff --git a/tilemgr/cell.icc b/tilemgr/cell.icc
new file mode 100644
index 0000000..4c8af27
--- /dev/null
+++ b/tilemgr/cell.icc
@@ -0,0 +1,2 @@
+//not used
+
diff --git a/tilemgr/compression.hh b/tilemgr/compression.hh
new file mode 100644
index 0000000..2e291ae
--- /dev/null
+++ b/tilemgr/compression.hh
@@ -0,0 +1 @@
+//not used anymore
diff --git a/tilemgr/comptile.cc b/tilemgr/comptile.cc
new file mode 100644
index 0000000..bcab9cd
--- /dev/null
+++ b/tilemgr/comptile.cc
@@ -0,0 +1 @@
+//not used
diff --git a/tilemgr/comptile.hh b/tilemgr/comptile.hh
new file mode 100644
index 0000000..bcab9cd
--- /dev/null
+++ b/tilemgr/comptile.hh
@@ -0,0 +1 @@
+//not used
diff --git a/tilemgr/gencompression.cc b/tilemgr/gencompression.cc
new file mode 100644
index 0000000..5fa2fce
--- /dev/null
+++ b/tilemgr/gencompression.cc
@@ -0,0 +1,2 @@
+//not used anymore
+
diff --git a/tilemgr/gencompression.hh b/tilemgr/gencompression.hh
new file mode 100644
index 0000000..5fa2fce
--- /dev/null
+++ b/tilemgr/gencompression.hh
@@ -0,0 +1,2 @@
+//not used anymore
+
diff --git a/tilemgr/nocompression.cc b/tilemgr/nocompression.cc
new file mode 100644
index 0000000..5fa2fce
--- /dev/null
+++ b/tilemgr/nocompression.cc
@@ -0,0 +1,2 @@
+//not used anymore
+
diff --git a/tilemgr/nocompression.hh b/tilemgr/nocompression.hh
new file mode 100644
index 0000000..5fa2fce
--- /dev/null
+++ b/tilemgr/nocompression.hh
@@ -0,0 +1,2 @@
+//not used anymore
+
diff --git a/tilemgr/perstile.cc b/tilemgr/perstile.cc
new file mode 100644
index 0000000..a23f993
--- /dev/null
+++ b/tilemgr/perstile.cc
@@ -0,0 +1 @@
+//moved to tile
diff --git a/tilemgr/perstile.hh b/tilemgr/perstile.hh
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tilemgr/perstile.hh
diff --git a/tilemgr/perstile.icc b/tilemgr/perstile.icc
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tilemgr/perstile.icc
diff --git a/tilemgr/test/Makefile b/tilemgr/test/Makefile
new file mode 100644
index 0000000..2070f70
--- /dev/null
+++ b/tilemgr/test/Makefile
@@ -0,0 +1,81 @@
+# -*-Makefile-*-
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>. # Top Level makefile. This points to the various modules that have to be build
+# and/or deployed
+#
+# MAKEFILE FOR:
+# test programs of module tilemgr
+#
+# COMMENTS:
+#
+##################################################################
+######################### Definitions ############################
+
+# all test programs
+SRCCXX = test_access.cc test_splittile.cc test_tile.cc tilertest.cc
+OBJS = ${SRCCXX:%.cc=%.o}
+ALLTESTS = ${SRCCXX:%.cc=%}
+
+
+# Sun Solaris: -lposix4 is needed for test_tile because of clock_gettime
+ifeq ($(OSTYPE),$(OSTYPE_SOLARIS))
+ LDFLAGS += -lposix4
+endif
+
+ALLFLAGS = $(BASEDBLDFLAGS) $(LDFLAGS) $(STLLDFLAGS) -L$(SUPPORT_BASE)/lib -lz
+
+MAINLIBS = $(RASLIB) $(TILEMGR) $(MDDIF) $(CATALOGIF) $(CATALOGMGR) \
+ $(INDEXMGR) $(BLOBIF) $(MDDMGR) $(ADMINIF) $(QLPARSER) $(INDEXIF)
+
+########################### Targets ##############################
+
+# make all tests
+.PHONY: test
+test: test_tile test_splittile test_access
+
+
+######################## Dependencies ############################
+
+test_splittile: test_splittile.o $(RASLIB) $(TILEMGR) $(MDDMGR) $(CATALOGMGR) \
+ $(MDDIF) $(CATALOGIF) $(INDEXIF) $(INDEXMGR) $(BLOBIF) $(ADMINIF)
+ $(PURIFY) $(CXX) $(BASEDBLDFLAGS) $(STLLDFLAGS) $(LDFLAGS) -o $@ $^ \
+ $(STLLDFLAGS)
+
+tilertest: tilertest.o $(RASLIB) $(TILEMGR) $(MDDMGR) $(CATALOGMGR) \
+ $(MDDIF) $(CATALOGIF) $(INDEXIF) $(INDEXMGR) $(BLOBIF) $(ADMINIF)
+ $(PURIFY) $(CXX) $(BASEDBLDFLAGS) $(STLLDFLAGS) $(LDFLAGS) -o $@ $^ $(BLOBIF) $(ADMINIF) $(CATALOGIF) $(INDEXIF) $(MDDIF) $(CATALOGIF) $(STLLDFLAGS) $(INDEXMGR) $(COMPRESSION) $(RASLIB)
+
+
+# can not be used as a target (module library is not remade!)
+test_tile: test_tile.o $(QLPARSER) $(RASLIB) $(ADMINIF) $(CATALOGMGR) \
+ $(TILEMGR) $(MDDMGR) $(MDDIF) $(CATALOGIF) $(INDEXMGR) $(BLOBIF) $(INDEXIF)
+ $(PURIFY) $(CXX) $(LDFLAGS) $(STLLDFLAGS) $(BASEDBLDFLAGS) \
+ -L$(SUPPORT_BASE)/lib -o $@ $^ -lmalloc -lospace \
+ $(RASLIB) $(QLPARSER) -lz
+
+
+test_access: test_access.o $(SERVERCOMM) $(QLPARSER) $(CONVERSION) $(RASLIB) \
+ $(ADMINIF) $(CACHETAMGR) $(COMPRESSION) $(MDDIF) $(CATALOGIF) \
+ $(INDEXMGR) $(BLOBIF) $(INDEXIF) $(HTTPSERVER)
+ $(PURIFY) $(CXX) $(LDFLAGS) $(BASEDBLDFLAGS) -o $@ $^ \
+ $(RELCATALOGIF) -lstdc++ -L$(SUPPORT_BASE)/lib $(RASLIB) -ltiff -lz
+
diff --git a/tilemgr/test/test_access.cc b/tilemgr/test/test_access.cc
new file mode 100644
index 0000000..0b9149c
--- /dev/null
+++ b/tilemgr/test/test_access.cc
@@ -0,0 +1,673 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+/****************************************************************************
+ *
+ *
+ * PURPOSE:
+ * accesses data from a RasDaMan database according to the options
+ * specified in an input file. Optionally outputs timing and size
+ * information.
+ *
+ * DESCRIPTION:
+ * test_access reads from a text file a database name, and mddcolls
+ * names and for each one of them, it either reads a PersMDDColl and
+ * prints the status of all the mddobjs it contains (or part of them)
+ * or it deletes the MDDObjs.
+ * The program is able to print the tiles contents, show the accessing
+ * time and the sizes of each MDDObject.
+ * The input file has to start with the line:
+ * 'Database: <database name> '
+ * and after it, for every MDDCollection, the line:
+ * 'MDDColl: <mddcoll name> '
+ * which can be followed by the line:
+ * ' intersect: <domain> '
+ * or by the line:
+ * ' pointQuery: <domain> '
+ * in this case, the cell with address equal to the origin of the
+ * tile is accessed.
+ * which causes printing only the status of the mddobjs which
+ * intersect with <domain>.
+ * Options and arguments are described in the printUsage( ) function.
+ *
+ * Example input file :
+ * Database: SMRasDaBase
+ * MDDColl: Images2DA
+ * intersect: [0:29,9:19]
+ * MDDColl: Toms3DA
+ *
+ *
+ * COMMENTS:
+ * In this version, the -r option deletes whole collections only.
+ * To be extended in the future to delete selected objects and/or
+ * selected parts of objects.
+ *
+ ***************************************************************************/
+
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#ifdef __GNUG__
+#include "server/template_inst.hh"
+#endif
+#endif
+
+#include <stdlib.h>
+#include <iostream.h>
+#include <fstream.h>
+#include <string.h>
+#include <vector.h>
+
+#ifdef BASEDB_O2
+#include "o2template_CC.hxx" // declaration of O2 ref and coll classes
+#endif
+
+#include "raslib/rminit.hh"
+#include "raslib/rmdebug.hh"
+#include "typefactory.hh"
+#include "ulongtype.hh" // from the catalogif base DBMS interface module
+
+#include "mddmgr/persmddcoll.hh"
+#include "mddmgr/persmddobj.hh"
+
+#include "mddmgr/persmddcolliter.hh"
+
+#include "adminif.hh"
+#include "databaseif.hh"
+#include "transactionif.hh"
+
+#include "compression/tilecompression.hh"
+
+extern char* myExecArgv0 = "";
+
+RMINITGLOBALS('C')
+
+#define MAX 256
+ifstream testfile;
+
+void testAccessing( char* persMDDCollName, char* search,
+ int printTilesContents, int timeAccess,
+ int printSizes, int printCompression );
+void intersectOption( char* search,
+ PersMDDColl* accessedColl,
+ int printTilesContents,
+ int timeAccess,
+ int printSizes );
+void pointQueryOption( char* search,
+ PersMDDColl* accessedColl,
+ int timeAccess,
+ int printSizes );
+void testDeleteColls( DatabaseIf* db, char* persMDDCollName,
+ char* search, int timeAccess, int printSizes );
+
+int checkArguments( int argc, char** argv, const char* searchText,
+ int& optionValueIndex );
+void printUsage( );
+
+/**********************************************************************
+ * Function name.: int main (int argc, char** argv)
+ *
+ * Arguments.....:
+ * argc: number of arguments given to program
+ * argv: array of char* with arguments
+ * Return value..: exit status
+ * Description...: none
+ **********************************************************************/
+
+int
+main( int argc, char** argv)
+{
+ // variables representing O2 database, test file, ta and session
+ DatabaseIf database;
+ TransactionIf ta;
+ // static char O2BenchSchemaName[] = "SMRasDaSchema";
+ static char O2BenchDBName[MAX];
+ char mc_name[MAX],search[MAX];
+ int printTilesContents = 0;
+ int timeAccess = 0;
+ int printSizes = 0;
+ int printCompression = 0;
+ int deleteColls = 0;
+ int i, optionValueIndex;
+
+ // don't forget to initialize before using AdminIf!
+ myExecArgv0 = argv[0];
+ AdminIf* myAdmin = AdminIf::instance();
+
+ // is help is needed
+ if (checkArguments (argc, argv, "-h", optionValueIndex))
+ {
+ printUsage( );
+ delete myAdmin;
+ exit( 0 );
+ }
+
+ // openning the test file
+ if (checkArguments (argc, argv, "-f", optionValueIndex))
+ {
+ for (i = 0; argv[optionValueIndex][i+1] != '\0'; i++)
+ search[i] = argv[optionValueIndex][i+2];
+ testfile.open (search);
+ if (!testfile)
+ {
+ cout << "cannot open this file" << endl;
+ return 1;
+ }
+ }
+ else
+ printUsage( );
+ /*
+ {
+ cout << "Please write: test_access -f<testfile-name>" << endl;
+ cout << "Or maybe: test_access -h for help...." << endl;
+ return 1;
+ }
+ */
+
+ // updating the flag of printing the tiles
+ if (checkArguments (argc, argv, "-p", optionValueIndex))
+ printTilesContents = 1;
+
+ // updating the flag of timming the access
+ if (checkArguments (argc, argv, "-t", optionValueIndex))
+ timeAccess = 1;
+
+ // updating the flag of printing the sizes of mddobjs
+ if (checkArguments (argc, argv, "-s", optionValueIndex))
+ printSizes = 1;
+
+ // updating the flag of deletion
+ if (checkArguments (argc, argv, "-r", optionValueIndex))
+ deleteColls = 1;
+
+ // updating the flag of compression
+ if (checkArguments (argc, argv, "-c", optionValueIndex))
+ printCompression = 1;
+
+ // reading data-base name
+ testfile.getline (search, MAX, ':');
+ while ((!strstr (search, "Database")) && (!testfile.eof ( )))
+ testfile.getline (search, MAX, ':');
+ testfile >> O2BenchDBName;
+
+ // connect to the database
+ cout << "Connecting to database " << O2BenchDBName
+ << "..." << endl;
+ database.open (O2BenchDBName);
+
+ // searching for mddcalls
+ testfile.getline (search, MAX, ':');
+ while (!testfile.eof ( ))
+ {
+ ta.begin ( &database );
+
+ // searching for mddcall
+ while ((!strstr (search, "MDDColl")) && (!testfile.eof ( )))
+ testfile.getline (search, MAX, ':');
+ if (strstr (search, "MDDColl"))
+ {
+ testfile >> mc_name;
+ testfile.getline (search, MAX, ':');
+ if (!deleteColls)
+ testAccessing (mc_name, search, printTilesContents, timeAccess,
+ printSizes, printCompression);
+ else
+ testDeleteColls(&database, mc_name, search, timeAccess, printSizes);
+ }
+
+ ta.commit( );
+ }
+
+ cout << endl<< "Ending O2 session..." << endl;
+ database.close( );
+ testfile.close( );
+ delete myAdmin;
+}
+
+/**********************************************************************
+ * Function......:
+ * testAccessing( char* persMDDCollName, char* search,
+ * int printTilesContents, int timeAccess,
+ * int printSizes)
+ * Arguments.....:
+ * persMDDCollName: the MDDColl name
+ * search: for searching the words from the file
+ * printTilesContents: the flag of printing the tiles
+ * timeAccess: the flag of timming the access
+ * Return value..: none
+ * Description...: reads DirTilesIx's and shows contents
+ **********************************************************************/
+
+void testAccessing( char* persMDDCollName, char* search,
+ int printTilesContents, int timeAccess,
+ int printSizes, int printCompression)
+{
+ PersMDDObj* accessedObj;
+ PersMDDColl* accessedColl;
+
+ cout << endl << endl << "....testAccessing " << persMDDCollName << endl;
+ try
+ {
+ accessedColl = new PersMDDColl(persMDDCollName);
+ }
+ catch(...)
+ {
+ cout << " Error: exception caught when trying to access collection ";
+ cout << endl;
+ return;
+ }
+
+ // To test PersMDDColl::printStatus( )
+ // accessedColl->printStatus( );
+
+ // To test PersMDDObj::printStatus( ), MDDCollIter::createIterator( ) and
+ // MDDCollIter methods :
+
+ // cout << " Iterating through the collection with PersMDDCollIter " << endl;
+ // MDDCollIter* objsIt = accessedColl->createIterator( );
+
+
+ // the regular option of showing the contents
+ if ((strstr (search, "MDDColl")) || (testfile.eof ( )))
+ {
+ cout << " Iterating through the collection with PersMDDCollIter " << endl;
+ MDDCollIter* objsIt = accessedColl->createIterator( );
+
+ for( int i = 1 ; objsIt->notDone( ); i++, objsIt->advance( ))
+ {
+ accessedObj = (PersMDDObj*) objsIt->getElement();
+ cout << endl << endl << " --" << i << ". MDD object in set:" << endl;
+
+ if (printTilesContents && timeAccess)
+ {
+ vector<Tile*>* TileVector;
+
+ // start counter
+ RMInit::dbgOut.rdbuf(cout.rdbuf());
+ RMTimer* Counter = new RMTimer("PersMDDObj", "getTiles");
+ TileVector = accessedObj->getTiles ( );
+
+ // stop counter
+ cout << "The time of accessing by ";
+ delete Counter;
+
+ vector<Tile*> ::iterator t;
+ for (t = TileVector->begin ( ); t != TileVector->end ( ); t++)
+ {
+ (*t)->printStatus( );
+ cout << endl;
+ }
+
+ TileVector->erase( TileVector->begin(), TileVector->end() );
+ delete TileVector;
+ }
+
+ else if (printTilesContents && !timeAccess)
+ {
+ vector<Tile*>* TileVector;
+ TileVector = accessedObj->getTiles ( );
+
+ vector<Tile*> ::iterator t;
+ for (t = TileVector->begin ( ); t != TileVector->end ( ); t++)
+ {
+ (*t)->printStatus( );
+ cout << endl;
+ }
+
+ TileVector->erase( TileVector->begin(), TileVector->end() );
+ delete TileVector;
+ }
+
+ else if (!printTilesContents && timeAccess)
+ {
+ // start counter
+ RMInit::dbgOut.rdbuf(cout.rdbuf());
+ RMTimer* Counter = new RMTimer("PersMDDObj", "printStatus");
+ accessedObj->printStatus ( );
+
+ // stop counter
+ cout << endl << "The time of accessing by ";
+ delete Counter;
+ }
+
+ else if (!printTilesContents && !timeAccess)
+ {
+ accessedObj->printStatus ( );
+ }
+
+ if (printSizes)
+ {
+ // printing the sizes of the mddobj
+ cout << endl << "The logical-size of the mddobj: " << accessedObj->getLogicalSize ( ) << endl;
+ cout << "The physical-size of the mddobj: " << accessedObj->getPhysicalSize ( ) << endl;
+ cout << "The physical-cells-size of the mddobj: " << accessedObj->getPhysicalCellsSize ( ) << endl;
+ cout << "The index-size of the mddobj: " << accessedObj->getIxSize ( ) << endl;
+ }
+
+ if (printCompression)
+ {
+ int i = 0;
+ unsigned long totalSize = 0;
+
+ vector<Tile*>* TileVector;
+ TileVector = accessedObj->getTiles ( );
+
+ vector<Tile*> ::iterator t;
+ for (t = TileVector->begin ( ); t != TileVector->end ( ); t++)
+ {
+ cout << ++i << ". ";
+ if( (*t)->getDataFormat() == r_ZLib )
+ {
+ totalSize += (*t)->getPhysicalSize( );
+ cout << "Size of compressed tile: "
+ << (*t)->getPhysicalSize( ) << endl;
+ }
+ else
+ {
+ cout << "Tile not compressed! Size: " << (*t)->getSize() << endl;
+
+ }
+ }
+ TileVector->erase( TileVector->begin(), TileVector->end() );
+ delete TileVector;
+
+ if(totalSize != 0)
+ cout << "Total size of compressed tiles: " << totalSize << endl;
+ }
+ } // for objsIt loop
+
+ delete objsIt;
+
+ } // if MDDColl
+
+ // the intersect option
+ else if (strstr (search, "intersect"))
+ {
+ intersectOption( search, accessedColl, printTilesContents, timeAccess, printSizes);
+ }
+ else if (strstr (search, "pointQuery"))
+ {
+ pointQueryOption( search, accessedColl, timeAccess, printSizes);
+ }
+ else
+ {
+ cout << "don't know what is this..." << endl;
+ testfile.getline (search, MAX, ':');
+ }
+
+
+
+ accessedColl->releaseAll( );
+ delete accessedColl;
+}
+
+
+
+void
+intersectOption( char* search,
+ PersMDDColl* accessedColl,
+ int printTilesContents,
+ int timeAccess,
+ int printSizes )
+{
+ PersMDDObj* accessedObj;
+
+ int cont = 1;
+ for ( ; cont == 1 ; ) // intersect loop
+ {
+ testfile.get (search, MAX, '[');
+ testfile.getline (search, MAX, ']');
+ strcat (search, "]");
+
+ cout << " Iterating through the collection with PersMDDCollIter " << endl;
+ MDDCollIter* objsIt = accessedColl->createIterator( );
+
+ for( int i = 1 ; objsIt->notDone( ); i++, objsIt->advance( ))
+ {
+ accessedObj = (PersMDDObj*) objsIt->getElement();
+ cout << endl << endl << " --" << i << ". MDD object in set:" << endl;
+
+ r_Minterval interval (search);
+ cout << "Intersecting to "<< interval << endl;
+ vector<Tile*>* TileVector;
+ vector<Tile*> ::iterator t;
+ RMTimer* Counter;
+
+ if ( timeAccess )
+ {
+ // start counter
+ // RMInit::dbgOut = cout.rdbuf();
+ RMInit::bmOut << "Intersect Region " << interval << " " << "\t";
+ // Counter = new RMTimer(" PersMDDObj", "intersect");
+ }
+
+ TileVector = accessedObj->intersect (interval);
+
+ if ( printTilesContents )
+ {
+ int j = 1;
+ for (t = TileVector->begin ( ); t != TileVector->end ( ); t++, j++)
+ {
+ cout << "Tile "<< j <<": "<<endl;
+ (*t)->printStatus( );
+ cout << endl;
+ }
+ }
+ else
+ {
+ int j = 1;
+ for (t = TileVector->begin ( ); t != TileVector->end ( ); t++, j++)
+ cout << "Tile " << j << ": " << (*t)->getDomain ( ) << endl;
+ }
+
+ // ?? TileVector->erase( );
+ delete TileVector;
+
+ if (printSizes)
+ {
+ // printing the sizes of the mddobj
+ cout << endl << "The logical-size of the mddobj: " << accessedObj->getLogicalSize ( ) << endl;
+ cout << "The physical-size of the mddobj: " << accessedObj->getPhysicalSize ( ) << endl;
+ cout << "The physical-cells-size of the mddobj: " << accessedObj->getPhysicalCellsSize ( ) << endl;
+ cout << "The index-size of the mddobj: " << accessedObj->getIxSize ( ) << endl;
+ }
+ } // for objsIt loop
+
+ delete objsIt;
+ testfile.getline (search, MAX, ':');
+ cout << search << endl;
+ if ( !strstr( search, "intersect") )
+ cont = 0;
+ // cout << " cont "<< cont << endl;
+ } // for cont loop
+}
+
+void
+pointQueryOption( char* search,
+ PersMDDColl* accessedColl,
+ int timeAccess,
+ int printSizes )
+{
+ PersMDDObj* accessedObj;
+
+ int cont = 1;
+ for ( ; cont == 1 ; ) // intersect loop
+ {
+ testfile.get (search, MAX, '[');
+ testfile.getline (search, MAX, ']');
+ strcat (search, "]");
+
+ cout << " Iterating through the collection with PersMDDCollIter " << endl;
+ MDDCollIter* objsIt = accessedColl->createIterator( );
+
+ for( int i = 1 ; objsIt->notDone( ); i++, objsIt->advance( ))
+ {
+ accessedObj = (PersMDDObj*) objsIt->getElement();
+ cout << endl << endl << " --" << i << ". MDD object in set:" << endl;
+
+ r_Minterval interval (search);
+ r_Point pnt = interval.get_origin( );
+ cout << "Point query to "<< pnt << endl;
+
+ RMTimer* Counter;
+ if ( timeAccess )
+ {
+ // start counter
+ RMInit::bmOut << "Intersect Region " << interval << " " << "\t";
+ // Counter = new RMTimer(" PersMDDObj", "intersect");
+ }
+
+ char* result = accessedObj->pointQuery(pnt);
+ if ( result )
+ cout << "Result of point query : "<< long(*result) <<endl;
+ else
+ cout << "Null pointer returned from pointQuery!!!! "<< endl;
+
+ if (printSizes)
+ {
+ // printing the sizes of the mddobj
+ cout << endl << "The logical-size of the mddobj: " << accessedObj->getLogicalSize ( ) << endl;
+ cout << "The physical-size of the mddobj: " << accessedObj->getPhysicalSize ( ) << endl;
+ cout << "The physical-cells-size of the mddobj: " << accessedObj->getPhysicalCellsSize ( ) << endl;
+ cout << "The index-size of the mddobj: " << accessedObj->getIxSize ( ) << endl;
+ }
+ } // for objsIt loop
+
+ delete objsIt;
+ testfile.getline (search, MAX, ':');
+ cout << search << endl;
+ if ( !strstr( search, "pointQuery") )
+ cont = 0;
+ // cout << " cont "<< cont << endl;
+ } // for cont loop
+}
+
+
+
+/**********************************************************************
+ * Function......:
+ * testDeleteColls( DatabaseIf* db, char* persMDDCollName,
+ * char* search, int timeAccess,int printSizes )
+ *
+ * Arguments.....:
+ * persMDDCollName: the MDDColl name
+ * search: for searching the words from the file
+ * printTilesContents: the flag of printing the tiles
+ * timeAccess: the flag of timming the access
+ * Return value..: none
+ * Description...: reads DirTilesIx's and shows contents
+ **********************************************************************/
+
+void testDeleteColls( DatabaseIf* db, char* persMDDCollName,
+ char* search, int timeAccess, int printSizes)
+{
+ // PersMDDObj* accessedObj;
+ PersMDDColl* accessedColl;
+
+ /*
+ cout << endl << endl << "... Destroying root collection "
+ << persMDDCollName << endl;
+ PersMDDColl::destroyRoot( persMDDCollName, db );
+ */
+
+ cout << endl << endl << "....testAccessing " << persMDDCollName << endl;
+ try
+ {
+ accessedColl = new PersMDDColl( persMDDCollName );
+ }
+ catch(...)
+ {
+ cout << " Error: exception caught when trying to access collection ";
+ cout << endl;
+ return;
+ }
+
+ accessedColl->removeAll( );
+ accessedColl->releaseAll( );
+
+ cout << endl << endl << "... Destroying root collection "
+ << persMDDCollName << endl;
+ PersMDDColl::destroyRoot( persMDDCollName, db );
+
+}
+
+/**********************************************************************
+ * Function......: checkArguments (int argc, char** argv,
+ * const char* searchText,
+ * int& optionValueIndex)
+ *
+ * Arguments.....:
+ * argc: number of arguments given to program
+ * argv: array of char* with arguments
+ * searchText: the desire option
+ * optionValueIndex: the index of the found option
+ * Return value..: int
+ * Description...: searching an option in the accexuting line
+ **********************************************************************/
+int checkArguments (int argc, char** argv, const char* searchText,
+ int& optionValueIndex)
+{
+ int found = 0;
+ int i = 1;
+
+ while (!found && i < argc)
+ {
+ found = !strncmp (searchText, argv[i], 2);
+ if (!found)
+ i++;
+ }
+ if (found)
+ optionValueIndex = i;
+ else
+ optionValueIndex = 0;
+
+ return found;
+}
+
+
+void printUsage( )
+{
+ cout << endl << "Usage: " << endl;
+ cout << "test_access -h" << endl;
+ cout << "test_access -f<file> [-t] [-p] [-s]" << endl;
+ cout << "test_access -f<file> -r " << endl;
+ cout << " -h ... this help" << endl;
+ cout << " -p ... for printing tiles contents" << endl;
+ cout << " -t ... for timming the access" << endl;
+ cout << " -s ... for printing the sizes of mddobjs" << endl;
+ cout << " -f<file> ... for the name of the text file" << endl;
+ cout << " -r ... for deleting the collections listed in <file>" << endl;
+ cout << " -c ... for printing info on compressed tiles";
+ cout << endl << endl;
+
+}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tilemgr/test/test_access.data b/tilemgr/test/test_access.data
new file mode 100644
index 0000000..d3b434f
--- /dev/null
+++ b/tilemgr/test/test_access.data
@@ -0,0 +1,3 @@
+Database: RASBASE
+MDDColl: rockies_comp
+
diff --git a/tilemgr/test/test_splittile.cc b/tilemgr/test/test_splittile.cc
new file mode 100644
index 0000000..de713e2
--- /dev/null
+++ b/tilemgr/test/test_splittile.cc
@@ -0,0 +1,142 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+/*************************************************************
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#include <stdlib.h>
+#include <iostream>
+#include "typefactory.hh"
+#include "basetype.hh"
+#include "tilemgr/tile.hh"
+#include "tilemgr/transtile.hh"
+
+
+#include "raslib/rminit.hh"
+RMINITGLOBALS('C')
+
+#include "raslib/minterval.hh"
+#include "raslib/sinterval.hh"
+#include "adminif.hh"
+#include "databaseif.hh"
+#include "transactionif.hh"
+
+// perhaps used later
+static char O2BenchDBName[] = "TestSMBase";
+static char O2BenchSchemaName[] = "TestSMSchema";
+
+// static void ClearDB( d_Database &DB );
+extern char* myExecArgv0 = "";
+
+/*************************************************************
+ * Function name.: int main( int argc, char** argv)
+ *
+ * Arguments.....:
+ * argc: number of arguments given to program
+ * argv: array of char* with arguments
+ * Return value..: exit status
+ * Description...: none
+ ************************************************************/
+int
+main( int argc, char** argv)
+{
+ // variables representing O2 database, ta and session
+ DatabaseIf database;
+ TransactionIf ta;
+
+ // don't forget to initialize before using AdminIf!
+ myExecArgv0 = argv[0];
+ AdminIf* myAdmin = AdminIf::instance();
+
+
+ // connect to the database
+ cout << "Connecting to database " << O2BenchDBName << "..." << endl;
+ database.open( O2BenchDBName );
+
+
+ // create indexes and put them in TestMDDObjContainer
+ cout << " SplitTile..." << endl;
+ ta.begin();
+
+ static BaseType* bt = TypeFactory::mapType( "Short" );
+ cout << "BaseType " << bt->getTypeName( ) << endl;
+
+ r_Minterval tileDom =
+ r_Minterval(2) << r_Sinterval(0l,0l) << r_Sinterval(0l,99l);
+ //r_Minterval(2) << r_Sinterval(0l,9l) << r_Sinterval(0l,9l);
+ //("[0:9,0:9]");
+ cout << "tileDom " << tileDom << endl;
+ r_Minterval BigTileDom =
+ r_Minterval(2) << r_Sinterval(0l,39l) << r_Sinterval(0l, 99l);
+ // ("[0:39,0:39]");
+ cout << "BigTileDom " << BigTileDom << endl;
+
+ unsigned long sz = bt->getSize( ) * BigTileDom.cell_count( );
+
+ char* cells = new char[sz];
+ /*
+ for (int i = 0; i < sz ; i++ )
+ {
+ if (i /2) cells[i] = char (i/10);
+ else cells[i] = 0;
+ }
+ */
+ short* typedCells = (short*) cells;
+ unsigned typedSz = BigTileDom.cell_count( );
+ for (int i = 0; i < typedSz; i++ )
+ typedCells[i] = i;
+
+ vector< Tile* >* tilesReturned;
+ TransTile* tile1Obj1 = new TransTile( BigTileDom,
+ (const BaseType* ) bt,
+ ( char*) cells, 1);
+
+ cout << "Calling splitTile " << endl;
+ tilesReturned = tile1Obj1->splitTile( tileDom );
+ cout << "Finished splitTile " << endl;
+
+
+ vector<Tile*>::iterator entryIt = tilesReturned->begin();
+
+ i = 0 ;
+ while (entryIt != tilesReturned->end())
+ {
+ cout << "Tile " << i << endl;
+ (*entryIt)->printStatus();
+ entryIt++;
+ i++;
+ }
+
+ ta.commit();
+
+ delete[] cells;
+
+ cout << endl << "Ending O2 session..." << endl;
+ database.close( );
+ delete myAdmin;
+}
+
diff --git a/tilemgr/test/test_tile.cc b/tilemgr/test/test_tile.cc
new file mode 100644
index 0000000..18f5b97
--- /dev/null
+++ b/tilemgr/test/test_tile.cc
@@ -0,0 +1,979 @@
+#include "mymalloc/mymalloc.h"
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * creates Tiles and does ops
+ *
+ *
+ * COMMENTS:
+ * none
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)cachetamgr,test_tile: $Id: test_tile.cc,v 1.26 2002/08/30 11:51:22 coman Exp $";
+
+#include <stdlib.h>
+#include <iostream>
+#include <time.h>
+#include "ulongtype.hh"
+#include "booltype.hh"
+#include "chartype.hh"
+#include "structtype.hh"
+
+#ifndef bool
+ #include <bool.h>
+ #define OS_OMIT_BOOL
+#endif
+
+#include "adminif.hh"
+#include "databaseif.hh"
+#include "transactionif.hh"
+#include "tilemgr/perstile.hh"
+#include "tilemgr/transtile.hh"
+#include "typefactory.hh"
+#include "raslib/rminit.hh"
+#include "raslib/rmdebug.hh"
+
+// global variable for AdminIf because of O2 d_Session::begin()
+extern char* myExecArgv0 = "";
+
+RMINITGLOBALS('C')
+
+// perhaps used later
+static char O2BenchDBName[256] = "NorbertBase";
+static char O2BenchSchemaName[256] = "NorbertSchema";
+
+void
+printTime()
+{
+ struct timespec cur_time;
+ clock_gettime(CLOCK_REALTIME, &cur_time);
+
+ cout << asctime(localtime(&(cur_time.tv_sec)));
+}
+
+void
+testConstructors()
+{
+ // for for loops
+ unsigned long i;
+ // Tile used for tests
+ Tile* myTile;
+ // base types for tiles
+ BaseType* ulongType = TypeFactory::mapType("ULong");
+ // domain of all Tiles
+ r_Minterval dom =
+ r_Minterval(3) << r_Sinterval(1L,10L) << r_Sinterval(11L,20L)
+ << r_Sinterval(5L,7L);
+
+ // testing constructor executing section operation
+ // first create a tile with the whole domain
+ // char* containing data for one ULong Tile
+ char* tileData = (char*)mymalloc(dom.cell_count() * ulongType->getSize());
+ for(i = 0; i < dom.cell_count() * ulongType->getSize(); i++)
+ {
+ if(i % ulongType->getSize() == 3 )
+ tileData[i] = 10;
+ else
+ tileData[i] = 0;
+ }
+
+ // transient with value
+ cout << "Creating transient ULong Tile containing 10 with domain "
+ << dom << ":" << endl;
+ myTile = new TransTile( dom, ulongType, tileData );
+
+ // now project it
+ set<r_Dimension, less<r_Dimension> >* projSet =
+ new set<r_Dimension, less<r_Dimension> >;
+ projSet->insert(1);
+
+ r_Minterval projDom =
+ r_Minterval(3) << r_Sinterval(1l, 10l) << r_Sinterval(15l, 15l)
+ << r_Sinterval(5l, 7l);
+
+ Tile* projectedTile = new TransTile(myTile, projDom, projSet);
+
+ projectedTile->printStatus();
+
+ delete projSet;
+ delete projectedTile;
+}
+
+void
+testCompression()
+{
+ // for for loops
+ unsigned long i;
+ // Tile used for tests
+ Tile* myTile;
+ // Tile used for inititializing tiles with OP_IDENTITY
+ Tile* myContentTile;
+ // for contents of tiles
+ char* tileData;
+ // base types for tiles
+ BaseType* ulongType = TypeFactory::mapType("ULong");
+ // domain of all Tiles
+ r_Minterval dom =
+ r_Minterval(3) << r_Sinterval(1L,10L) << r_Sinterval(11L,20L)
+ << r_Sinterval(5L,7L);
+
+ cout << "Testing Constructors for Tiles" << endl;
+ cout << "------------------------------" << endl << endl;
+
+ // ------------------------------------------------------------
+ // uncompressed TransTile
+ // ------------------------------------------------------------
+
+ // char* containing data for one ULong Tile
+ tileData = (char*)mymalloc(dom.cell_count() * ulongType->getSize());
+ for(i = 0; i < dom.cell_count() * ulongType->getSize(); i++)
+ {
+ if(i % ulongType->getSize() == 3 )
+ tileData[i] = 10;
+ else
+ tileData[i] = 0;
+ }
+
+ // transient with value
+ cout << "Creating transient ULong Tile containing 10 with domain "
+ << dom << ":" << endl;
+ myTile = new TransTile( dom, ulongType, tileData );
+
+ cout << " Printing created Tile: " << endl;
+ myTile->printStatus();
+
+ cout << " Deleting created Tile" << endl << endl;
+ delete myTile;
+
+ // ------------------------------------------------------------
+ // uncompressed PersTile
+ // ------------------------------------------------------------
+
+ // char* containing data for one ULong Tile
+ tileData = (char*)mymalloc(dom.cell_count() * ulongType->getSize());
+ for(i = 0; i < dom.cell_count() * ulongType->getSize(); i++)
+ {
+ if(i % ulongType->getSize() == 3 )
+ tileData[i] = 10;
+ else
+ tileData[i] = 0;
+ }
+
+ // persistent with value
+ cout << "Creating persistent ULong Tile containing 10 with domain "
+ << dom << ":" << endl;
+ myTile = new PersTile( dom, ulongType, tileData );
+
+ cout << " Printing created Tile: " << endl;
+ myTile->printStatus();
+
+ cout << " Deleting created Tile" << endl << endl;
+ delete myTile;
+
+ // ------------------------------------------------------------
+ // uncompressed TransTile
+ // ------------------------------------------------------------
+
+ // char* containing data for one ULong Tile
+ tileData = (char*)mymalloc(dom.cell_count() * ulongType->getSize());
+ for(i = 0; i < dom.cell_count() * ulongType->getSize(); i++)
+ {
+ if(i % ulongType->getSize() == 3 )
+ tileData[i] = 10;
+ else
+ tileData[i] = 0;
+ }
+
+ // transient with value
+ cout << "Creating transient ULong Tile containing 10 with domain "
+ << dom << ":" << endl;
+ myContentTile = new TransTile( dom, ulongType, tileData );
+ myTile = new TransTile( dom, ulongType );
+ myTile->execUnaryOp( Ops::OP_IDENTITY, dom, myContentTile, dom );
+
+ cout << " Printing created Tile: " << endl;
+ myTile->printStatus();
+
+ cout << " Deleting created Tile" << endl << endl;
+ delete myTile;
+
+ // ------------------------------------------------------------
+ // uncompressed PersTile
+ // ------------------------------------------------------------
+
+ // char* containing data for one ULong Tile
+ tileData = (char*)mymalloc(dom.cell_count() * ulongType->getSize());
+ for(i = 0; i < dom.cell_count() * ulongType->getSize(); i++)
+ {
+ if(i % ulongType->getSize() == 3 )
+ tileData[i] = 10;
+ else
+ tileData[i] = 0;
+ }
+
+ // persistent with value
+ cout << "Creating persistent ULong Tile containing 10 with domain "
+ << dom << ":" << endl;
+ myContentTile = new PersTile( dom, ulongType, tileData );
+ myTile = new PersTile( dom, ulongType, r_ZLib );
+ myTile->execUnaryOp( Ops::OP_IDENTITY, dom, myContentTile, dom );
+
+ cout << " Printing created Tile: " << endl;
+ myTile->printStatus();
+
+ cout << " Deleting created Tile" << endl << endl;
+ delete myTile;
+
+ // ------------------------------------------------------------
+ // compressed TransTile
+ // ------------------------------------------------------------
+
+ // char* containing data for one ULong Tile
+ tileData = (char*)mymalloc(dom.cell_count() * ulongType->getSize());
+ for(i = 0; i < dom.cell_count() * ulongType->getSize(); i++)
+ {
+ if(i % ulongType->getSize() == 3 )
+ tileData[i] = 10;
+ else
+ tileData[i] = 0;
+ }
+
+ // transient with value
+ cout << "Creating compressed transient ULong Tile containing 10 with domain "
+ << dom << ":" << endl;
+ myTile = new TransTile( dom, ulongType, r_ZLib );
+ myTile->setContents(tileData);
+
+ cout << " Physical Size: " << myTile->getPhysicalSize() << endl;
+
+ cout << " Printing created Tile: " << endl;
+ myTile->printStatus();
+
+ cout << " Physical Size: " << myTile->getPhysicalSize() << endl;
+
+ cout << " Deleting created Tile" << endl << endl;
+ delete myTile;
+
+ // ------------------------------------------------------------
+ // compressed PersTile
+ // ------------------------------------------------------------
+
+ // char* containing data for one ULong Tile
+ tileData = (char*)mymalloc(dom.cell_count() * ulongType->getSize());
+ for(i = 0; i < dom.cell_count() * ulongType->getSize(); i++)
+ {
+ if(i % ulongType->getSize() == 3 )
+ tileData[i] = 10;
+ else
+ tileData[i] = 0;
+ }
+
+ // persistent with value
+ cout << "Creating compressed persistent ULong Tile containing 10 with domain "
+ << dom << ":" << endl;
+ myTile = new PersTile( dom, ulongType, r_ZLib );
+ myTile->setContents(tileData);
+
+ cout << " Physical Size: " << myTile->getPhysicalSize() << endl;
+
+ cout << " Printing created Tile: " << endl;
+ myTile->printStatus();
+
+ cout << " Physical Size: " << myTile->getPhysicalSize() << endl;
+
+ cout << " Deleting created Tile" << endl << endl;
+ delete myTile;
+
+ // ------------------------------------------------------------
+ // compressed TransTile
+ // ------------------------------------------------------------
+
+ // char* containing data for one ULong Tile
+ tileData = (char*)mymalloc(dom.cell_count() * ulongType->getSize());
+ for(i = 0; i < dom.cell_count() * ulongType->getSize(); i++)
+ {
+ if(i % ulongType->getSize() == 3 )
+ tileData[i] = 10;
+ else
+ tileData[i] = 0;
+ }
+
+ // transient with value
+ cout << "Creating compressed transient ULong Tile containing 10 with domain "
+ << dom << ":" << endl;
+ myContentTile = new TransTile( dom, ulongType, tileData );
+ myTile = new TransTile( dom, ulongType, r_ZLib );
+ myTile->execUnaryOp( Ops::OP_IDENTITY, dom, myContentTile, dom );
+
+ cout << " Physical Size: " << myTile->getPhysicalSize() << endl;
+
+ cout << " Printing created Tile: " << endl;
+ myTile->printStatus();
+
+ cout << " Physical Size: " << myTile->getPhysicalSize() << endl;
+
+ cout << " Deleting created Tile" << endl << endl;
+ delete myTile;
+
+ // ------------------------------------------------------------
+ // compressed PersTile
+ // ------------------------------------------------------------
+
+ // char* containing data for one ULong Tile
+ tileData = (char*)mymalloc(dom.cell_count() * ulongType->getSize());
+ for(i = 0; i < dom.cell_count() * ulongType->getSize(); i++)
+ {
+ if(i % ulongType->getSize() == 3 )
+ tileData[i] = 10;
+ else
+ tileData[i] = 0;
+ }
+
+ // persistent with value
+ cout << "Creating compressed persistent ULong Tile containing 10 with domain "
+ << dom << ":" << endl;
+ myContentTile = new PersTile( dom, ulongType, tileData );
+ myTile = new PersTile( dom, ulongType, r_ZLib );
+ myTile->execUnaryOp( Ops::OP_IDENTITY, dom, myContentTile, dom );
+
+ cout << " Physical Size: " << myTile->getPhysicalSize() << endl;
+
+ cout << " Printing created Tile: " << endl;
+ myTile->printStatus();
+
+ cout << " Physical Size: " << myTile->getPhysicalSize() << endl;
+
+ cout << " Deleting created Tile" << endl << endl;
+ delete myTile;
+}
+
+void
+testUnaryOps()
+{
+ // base types for tiles
+ BaseType* ulongType = TypeFactory::mapType("ULong");
+ BaseType* boolType = TypeFactory::mapType("Bool");;
+ BaseType* charType = TypeFactory::mapType("Char");;
+
+ // default cell for filling ULong Tiles
+ unsigned long longVal = 4294966295;
+ char* ulongCell = (char*)&longVal;
+
+ // default cell for filling Bool Tiles
+ unsigned char boolVal = 1;
+ char* boolCell = (char*)&boolVal;
+
+ // domain of all Tiles
+ r_Minterval dom =
+ r_Minterval(2) << r_Sinterval(1L,10L) << r_Sinterval(11L,20L);
+
+ r_Minterval domOp =
+ r_Minterval(2) << r_Sinterval(1L,5L) << r_Sinterval(11L,15L);
+
+ // domain of one dimensional result
+ r_Minterval res1D =
+ r_Minterval(2) << r_Sinterval(1L,10L);
+
+ unsigned char charVal = 20;
+ char* charCell = (char*)&charVal;
+
+ // Tiles used for tests
+ Tile* transULongTile;
+ Tile* transBoolTile;
+ Tile* persULongTile;
+ Tile* persBoolTile;
+ Tile* transCharTile;
+ Tile* transCharRes;
+
+ cout << "Testing Unary Operations on Tiles" << endl;
+ cout << "---------------------------------" << endl << endl;
+
+ // transient with value
+ cout << "Creating Tiles for Unary Operations with domain "
+ << dom << ":" << endl;
+ transULongTile = new TransTile( dom, ulongType, ulongCell );
+ transBoolTile = new TransTile( dom, boolType, boolCell );
+ persULongTile = new PersTile( dom, ulongType, ulongCell );
+ persBoolTile = new PersTile( dom, boolType, boolCell );
+ transCharTile = new TransTile( dom, charType, charCell );
+ transCharRes = new TransTile( domOp, charType, boolCell );
+
+
+ cout << "Operations with ULong:" << endl << endl;
+
+ cout << "Carrying out NOT on TransTile (should be 1000)" << endl;
+ transULongTile->execUnaryOp(Ops::OP_NOT, dom, transULongTile, dom);
+
+ cout << "Contents after operation: " << endl;
+ transULongTile->printStatus();
+
+ cout << "Carrying out IDENTITY on TransTile (should be 1000)" << endl;
+ transULongTile->execUnaryOp(Ops::OP_IDENTITY, dom, transULongTile, dom);
+
+ cout << "Contents after operation: " << endl;
+ transULongTile->printStatus();
+
+ cout << "Carrying out NOT on PersTile (should be 1000)" << endl;
+ persULongTile->execUnaryOp(Ops::OP_NOT, dom, persULongTile, dom);
+
+ cout << "Contents after operation: " << endl;
+ persULongTile->printStatus();
+
+ cout << "Carrying out IDENTITY on PersTile (should be 1000)" << endl;
+ persULongTile->execUnaryOp(Ops::OP_IDENTITY, dom, persULongTile, dom);
+
+ cout << "Contents after operation: " << endl;
+ persULongTile->printStatus();
+
+ cout << "Operations with Bool:" << endl << endl;
+
+ cout << "Carrying out NOT on TransTile (should be FALSE)" << endl;
+ transBoolTile->execUnaryOp(Ops::OP_NOT, dom, transBoolTile, dom);
+
+ cout << "Contents after operation: " << endl;
+ transBoolTile->printStatus();
+
+ cout << "Carrying out IDENTITY on TransTile (should be FALSE)" << endl;
+ transBoolTile->execUnaryOp(Ops::OP_IDENTITY, dom, transBoolTile, dom);
+
+ cout << "Contents after operation: " << endl;
+ transBoolTile->printStatus();
+
+ cout << "Carrying out NOT on PersTile (should be FALSE)" << endl;
+ persBoolTile->execUnaryOp(Ops::OP_NOT, dom, persBoolTile, dom);
+
+ cout << "Contents after operation: " << endl;
+ persBoolTile->printStatus();
+
+ cout << "Carrying out IDENTITY on PersTile (should be FALSE)" << endl;
+ persBoolTile->execUnaryOp(Ops::OP_IDENTITY, dom, persBoolTile, dom);
+
+ cout << "Contents after operation: " << endl;
+ persBoolTile->printStatus();
+
+ cout << "Carrying out IDENTITY on subset of char tile" << endl;
+ transCharRes->execUnaryOp(Ops::OP_IDENTITY, domOp, transCharTile, domOp);
+
+ cout << "Contents after operation: " << endl;
+ transCharRes->printStatus();
+
+ // Trying to get more interesting values into tile
+ unsigned char val = 0;
+ for(int i = 0; i < transCharTile->getSize(); i++) {
+ transCharTile->setCell(i, (const char*)&val);
+ val++;
+ }
+
+ cout << "Tile with more interesting values: " << endl;
+ transCharTile->printStatus();
+
+ cout << "Carrying out IDENTITY on subset of char tile" << endl;
+ transCharRes->execUnaryOp(Ops::OP_IDENTITY, domOp, transCharTile, domOp);
+
+ cout << "Contents after operation: " << endl;
+ transCharRes->printStatus();
+
+ // Operation with result of a different dimensionality
+
+ // domain of all Tiles
+ r_Minterval horSlice =
+ r_Minterval(2) << r_Sinterval(1L,10L) << r_Sinterval(15L,15L);
+ r_Minterval verSlice =
+ r_Minterval(2) << r_Sinterval(5L,5L) << r_Sinterval(11L,20L);
+ Tile* transRes1D = new TransTile( res1D, charType, charCell );
+
+ cout << "Carrying out IDENTITY to receive a 1D vertical slice" << endl;
+ transRes1D->execUnaryOp(Ops::OP_IDENTITY, res1D, transCharTile, horSlice);
+
+ cout << "Contents after operation: " << endl;
+ transRes1D->printStatus();
+
+ cout << "Carrying out IDENTITY to receive a 1D horizontal slice" << endl;
+ transRes1D->execUnaryOp(Ops::OP_IDENTITY, res1D, transCharTile, verSlice);
+
+ cout << "Contents after operation: " << endl;
+ transRes1D->printStatus();
+
+ cout << "Deleting created Tiles ..." << endl << endl;
+
+ delete transULongTile;
+ delete transBoolTile;
+ delete persULongTile;
+ delete persBoolTile;
+ delete transCharRes;
+ delete transCharTile;
+ delete transRes1D;
+}
+
+void
+testBinaryOps()
+{
+ // base types for tiles
+ BaseType* ulongType = TypeFactory::mapType("ULong");
+ BaseType* boolType = TypeFactory::mapType("Bool");;
+
+ // default cell for filling ULong Tiles
+ unsigned long longVal = 1000;
+ char* ulongCell = (char*)&longVal;
+
+ // default cell for filling Bool Tiles
+ unsigned char boolVal = 1;
+ char* boolCell = (char*)&boolVal;
+
+ // domain of all Tiles
+ r_Minterval dom =
+ r_Minterval(3) << r_Sinterval(1L,10L) << r_Sinterval(11L,20L)
+ << r_Sinterval(5L,7L);
+
+ // Tiles used for tests
+ Tile* transULongTile;
+ Tile* transBoolTile;
+ Tile* persULongTile;
+ Tile* persBoolTile;
+ Tile* constULongTile;
+ Tile* constBoolTile;
+
+ cout << "Testing Binary Operations on Tiles" << endl;
+ cout << "---------------------------------" << endl << endl;
+
+ cout << "Creating Tiles for Binary Operations with domain "
+ << dom << ":" << endl;
+ transULongTile = new TransTile( dom, ulongType, ulongCell );
+ transBoolTile = new TransTile( dom, boolType, boolCell );
+ persULongTile = new PersTile( dom, ulongType, ulongCell );
+ persBoolTile = new PersTile( dom, boolType, boolCell );
+
+ cout << "Creating a TransTile for the two operands..." << endl;
+ TransTile ttileOp = TransTile(dom, ulongType, ulongCell);
+
+ cout << "Contents: " << endl;
+ ttileOp.printStatus();
+
+ cout << "Creating a TransTile for the result..." << endl;
+ TransTile ttileRes = TransTile(dom, ulongType, ulongCell);
+
+ cout << "Carrying out binary operation..." << endl;
+ ttileRes.execBinaryOp(Ops::OP_PLUS, dom, &ttileOp, dom, &ttileOp, dom);
+
+ cout << "Contents after operation: " << endl;
+ ttileRes.printStatus();
+
+ // testing binary operation with Bool as result
+ long bval = 10000;
+
+ // default cell for filling all Tiles
+ char* bvalCell = (char*)&bval;
+
+ cout << "Creating a TransTile for the two operands..." << endl;
+ TransTile btileOp = TransTile(dom, ulongType, boolCell);
+
+ cout << "Contents: " << endl;
+ btileOp.printStatus();
+
+ cout << "Creating a TransTile for the result..." << endl;
+ TransTile btileRes = TransTile(dom, boolType, boolCell);
+
+ cout << "Carrying out binary operation..." << endl;
+ btileRes.execBinaryOp(Ops::OP_EQUAL, dom, &btileOp, dom, &btileOp, dom);
+
+ cout << "Contents after operation: " << endl;
+ btileRes.printStatus();
+
+ cout << "Carrying out PLUS with TransTile and constant (should be 2000)"
+ << endl;
+
+ transULongTile->execConstOp(Ops::OP_PLUS, dom, transULongTile, dom,
+ ulongCell, ulongType);
+
+ cout << "Contents after operation: " << endl;
+ transULongTile->printStatus();
+
+ delete transULongTile;
+ delete transBoolTile;
+ delete persULongTile;
+ delete persBoolTile;
+ delete constULongTile;
+ delete constBoolTile;
+}
+
+void
+testCompTile()
+{
+// // size of tiles in one direction
+// const long testSize = 10;
+// // base types for tiles
+// BaseType* ulongType = TypeFactory::mapType("ULong");
+
+// // default cell for filling ULong Tiles
+// unsigned long longVal = 1000;
+// char* ulongCell = (char*)&longVal;
+
+// // domain of all Tiles
+// r_Minterval dom =
+// r_Minterval(2) << r_Sinterval(1L,testSize) << r_Sinterval(1L,testSize);
+
+// // Tiles used for tests
+// Tile* compTile1;
+// Tile* compTile2;
+// TransTile* transTile;
+
+// cout << "Testing CompTile" << endl;
+// cout << "----------------" << endl << endl;
+
+// cout << "Creating Tiles with domain "
+// << dom << ":" << endl;
+// compTile1 = new CompTile( dom, ulongType, Tile::COMP_ZLIB, ulongCell );
+// compTile2 = new CompTile( dom, ulongType, Tile::COMP_ZLIB, ulongCell );
+// transTile = new TransTile( dom, ulongType, ulongCell );
+
+ // initialize with random values
+// long val;
+// for(int i = 0; i < testSize; i++) {
+// for(int j = 0; j < testSize; j++) {
+// val = (long)(LONG_MIN + ((double)LONG_MAX-LONG_MIN)*drand48());
+// compTile1->setCell(i*testSize+j, (char*)&val);
+// val = (long)(LONG_MIN + ((double)LONG_MAX-LONG_MIN)*drand48());
+// compTile2->setCell(i*testSize+j, (char*)&val);
+// }
+// }
+
+ // initialize with incrementing values.
+// long val;
+// for(int i = 0; i < testSize; i++) {
+// for(int j = 0; j < testSize; j++) {
+// val = i*testSize+j;
+// compTile1->setCell(i*testSize+j, (char*)&val);
+// compTile2->setCell(i*testSize+j, (char*)&val);
+// }
+// }
+
+ // initialize with incrementing values, simulate struct
+// long val;
+// for(int i = 0; i < testSize; i++) {
+// for(int j = 0; j < testSize; j += 3) {
+// val = i*testSize+j;
+
+// compTile1->setCell(i*testSize+j, (char*)&val);
+// if(j+1 < testSize)
+// compTile1->setCell(i*testSize+j+1, (char*)&val+1000000);
+// if(j+2 < testSize)
+// compTile1->setCell(i*testSize+j+2, (char*)&val+2000000);
+
+// compTile2->setCell(i*testSize+j, (char*)&val);
+// if(j+1 < testSize)
+// compTile2->setCell(i*testSize+j+1, (char*)&val+1000000);
+// if(j+2 < testSize)
+// compTile2->setCell(i*testSize+j+2, (char*)&val+2000000);
+// }
+// }
+
+// cout << "Contents transTile: " << endl;
+// if(transTile->getSize() <= 1000)
+// transTile->printStatus();
+
+// cout << "Contents compTile1: " << endl;
+// if(transTile->getSize() <= 1000)
+// compTile1->printStatus();
+
+// cout << "Contents compTile2: " << endl;
+// if(transTile->getSize() <= 1000)
+// compTile2->printStatus();
+
+ // does only work if compress() is not protected.
+// cout << "Compressing compTiles" << endl;
+// ((CompTile*)compTile1)->compress();
+// ((CompTile*)compTile2)->compress();
+
+// cout << "Carrying out binary operation..." << endl;
+// transTile->execBinaryOp(Ops::OP_PLUS, dom, compTile1, dom, compTile2, dom);
+
+// cout << "Contents after operation: " << endl;
+// if(transTile->getSize() <= 1000)
+// transTile->printStatus();
+
+// delete compTile1;
+// delete compTile2;
+// delete transTile;
+}
+
+void
+testOpsWithConsts()
+{
+ // base types for tiles
+ BaseType* ulongType = TypeFactory::mapType("ULong");
+ BaseType* charType = TypeFactory::mapType("Char");
+
+ StructType* structType = new StructType("TestStruct", 2);
+ structType->addElement("Band1", "ULong");
+ structType->addElement("Band2", "Char");
+
+ // default cell for filling ULong Tiles
+ unsigned long uLongVal = 1000;
+ char* ulongCell = (char*)&uLongVal;
+ // default cell for filling Char Tiles
+ unsigned char charVal = 112;
+ char* charCell = (char*)&charVal;
+ // default cell for filling Struct Tiles
+ unsigned char structCell[5];
+ structCell[0] = ulongCell[0];
+ structCell[1] = ulongCell[1];
+ structCell[2] = ulongCell[2];
+ structCell[3] = ulongCell[3];
+ structCell[4] = charCell[0];
+
+ // domain of all Tiles
+ r_Minterval dom =
+ r_Minterval(2) << r_Sinterval(1L,5L) << r_Sinterval(1L,5L);
+
+ // Tiles used for tests
+ cout << "Creating Tiles with domain "
+ << dom << ":" << endl;
+ Tile* charTile = new TransTile(dom, charType, charCell);
+ Tile* ulongTile = new TransTile(dom, ulongType, ulongCell);
+ Tile* structTile = new TransTile(dom, structType, (char*)structCell);
+
+ cout << "Contents of Tiles: " << endl;
+ charTile->printStatus();
+ ulongTile->printStatus();
+ structTile->printStatus();
+
+ cout << "Result Type for Struct and Char: "
+ << (Ops::getResultType(Ops::OP_PLUS, structType, charType))->getTypeName() << endl;
+
+ cout << "Carrying out binary operation with constant on structTile ..."
+ << endl;
+ structTile->execConstOp(Ops::OP_PLUS, dom, structTile, dom, charCell,
+ charType);
+
+ cout << "Contents after operation: " << endl;
+ structTile->printStatus();
+
+ cout << "Carrying out binary operation with charTile on structTile ..."
+ << endl;
+ structTile->execBinaryOp(Ops::OP_PLUS, dom, structTile, dom, charTile, dom);
+
+ cout << "Contents after operation: " << endl;
+ structTile->printStatus();
+
+ cout << "Carrying out binary operation with two structTiles ..."
+ << endl;
+ structTile->execBinaryOp(Ops::OP_PLUS, dom, structTile, dom, structTile, dom);
+
+ cout << "Contents after operation: " << endl;
+ structTile->printStatus();
+
+ delete charTile;
+ delete ulongTile;
+ delete structTile;
+}
+
+void
+testCellAccess()
+{
+ // base types for tiles
+ BaseType* ulongType = TypeFactory::mapType("ULong");
+ BaseType* charType = TypeFactory::mapType("Char");
+
+ // default cell for filling ULong Tiles
+ unsigned long uLongVal = 1000;
+ char* ulongCell = (char*)&uLongVal;
+ // default cell for filling Char Tiles
+ unsigned char charVal = 112;
+ char* charCell = (char*)&charVal;
+
+ // domain of all Tiles
+ r_Minterval dom =
+ r_Minterval(2) << r_Sinterval(1L,10L) << r_Sinterval(1L,10L);
+
+ // Tiles used for tests
+ cout << "Creating Tiles with domain "
+ << dom << ":" << endl;
+ Tile* charTile = new TransTile(dom, charType, charCell);
+ Tile* ulongTile = new TransTile(dom, ulongType, ulongCell);
+
+ cout << "Accessing cell by point: ";
+ r_Point a = r_Point(2) << 5 << 5;
+ cout << (int)*(charTile->getCell(a)) << " "
+ << *(unsigned long*)ulongTile->getCell(a) << endl;
+
+ delete charTile;
+ delete ulongTile;
+}
+
+void
+testScaleOp(void)
+{
+ r_Dimension dim = 2;
+ r_Dimension i;
+ BaseType* charType = TypeFactory::mapType("Char");
+ r_Minterval dom = r_Minterval(dim);
+ r_Minterval nextDom = r_Minterval(dim);
+ r_Point origin(dim);
+ r_Point offset(dim);
+ unsigned long fullSize;
+ float scaleBy, incrementBy, eps;
+
+ for (i=0; i<dim; i++)
+ {
+ origin[i] = (r_Range)0;
+ offset[i] = (r_Range)64;
+ dom << r_Sinterval(origin[i] + offset[i], (r_Range)511 + offset[i]);
+ nextDom << r_Sinterval((r_Range)512 + offset[i], (r_Range)1023 + offset[i]);
+ }
+
+ fullSize = dom.cell_count();
+ char *tileValues = (char*)mymalloc(fullSize);
+ Tile *charTile = new TransTile(dom, charType, tileValues, fullSize);
+ Tile *nextTile = new TransTile(dom, charType);
+ memset(charTile->getContents(), 0, dom.cell_count());
+
+ vector<float> scaleFactors(dim);
+
+ incrementBy = 0.05; eps = 1e-2;
+ for (scaleBy=incrementBy; scaleBy <= 8-eps; scaleBy += incrementBy)
+ {
+ vector<float>::iterator iter = scaleFactors.begin();
+
+ cout << "Scale " << dom << " by " << scaleBy << endl;
+
+ for (i=0; i<dim; i++, iter++)
+ *iter = scaleBy;
+
+ r_Minterval scaledDom;
+ if (charTile->scaleGetDomain(dom, origin, scaleFactors, scaledDom))
+ {
+ unsigned long scaledSize = scaledDom.cell_count();
+ char *scaledValues = (char*)mymalloc(scaledSize);
+ Tile *scaledTile = new TransTile(scaledDom, charType, scaledValues, scaledSize);
+
+ r_Minterval nextScaledDom;
+ if (nextTile->scaleGetDomain(nextDom, origin, scaleFactors, nextScaledDom))
+ {
+ cout << "scaledDom: " << scaledDom << ", nextScaledDom: " << nextScaledDom << endl;
+ for (i=0; i<dim; i++)
+ {
+ if (nextScaledDom[i].low() != scaledDom[i].high() + 1)
+ {
+ cout << "NO SEAMLESS MATCH IN DIM " << i << '!' << endl;
+ }
+ }
+ }
+
+ scaledTile->execScaleOp(charTile, dom, origin, scaleFactors);
+
+ delete scaledTile;
+ }
+ else
+ {
+ cout << "Tile scaled to zero domain" << endl;
+ }
+
+ incrementBy = 0.05 * (1 << (int)((scaleBy + eps) / 2));
+ }
+
+ delete charTile;
+ delete nextTile;
+}
+
+
+/*************************************************************
+ * Function name.: int main( int argc, char** argv)
+ *
+ * Arguments.....:
+ * argc: number of arguments given to program
+ * argv: array of char* with arguments
+ * Return value..: exit status
+ * Description...: none
+ ************************************************************/
+
+int
+main( int argc , char* argv[] )
+{
+ int i;
+
+ i = 1;
+ while (i < argc)
+ {
+ if (argv[i][0] == '-')
+ {
+ switch (argv[i][1])
+ {
+ case 'd':
+ strcpy(O2BenchDBName, argv[++i]); break;
+ case 's':
+ strcpy(O2BenchSchemaName, argv[++i]); break;
+ case 'h':
+ cout << "Use: " << argv[0] << " [-d dbname -s schemaname -h]" << endl;
+ exit(0);
+ default:
+ break;
+ }
+ }
+ i++;
+ }
+
+ // variables representing O2 database, ta and session
+ DatabaseIf database;
+ TransactionIf ta;
+
+ // don't forget to initialize before using AdminIf!
+ myExecArgv0 = argv[0];
+ AdminIf* myAdmin = AdminIf::instance();
+
+ cout << "RManDebug: " << RManDebug << endl;
+
+ // connect to the database
+ cout << "Connecting to database " << O2BenchDBName
+ << "..." << endl;
+ database.open( O2BenchDBName );
+
+ ta.begin(&database);
+
+ cout << "These tests were done with:" << endl
+ << " " << rcsid << endl;
+ cout << "This protocol was created on:" << endl << " ";
+ printTime();
+ cout << endl;
+
+ // testConstructors();
+ // testCompression();
+ // testUnaryOps();
+ // testBinaryOps();
+ // testCompTile();
+ // testOpsWithConsts();
+ // testAlgebraOps();
+ // testCellAccess();
+ // testScaleOp();
+ testScaleOp();
+
+ ta.commit();
+
+ cout << "Ending O2 session..." << endl;
+ database.close();
+ delete myAdmin;
+}
diff --git a/tilemgr/test/tilertest.cc b/tilemgr/test/tilertest.cc
new file mode 100644
index 0000000..3502ccc
--- /dev/null
+++ b/tilemgr/test/tilertest.cc
@@ -0,0 +1,288 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#include "mymalloc/mymalloc.h"
+#ifdef EARLY_TEMPLATE
+#define __EXECUTABLE__
+#ifdef __GNUG__
+#include "server/template_inst.hh"
+#endif
+#endif
+
+#include "raslib/rmdebug.hh"
+#include "raslib/minterval.hh"
+#include <iostream.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <vector.h>
+#include <pair.h>
+#include "tilemgr/transtile.hh"
+#include "octettype.hh"
+#include "tilemgr/tiler.hh"
+
+RMINITGLOBALS('C')
+
+
+int
+main(int argc, char *argv[])
+ {
+ vector<r_Minterval> sourceDomains;
+ vector<r_Minterval> targetDomains;
+ vector<r_Minterval> retvalDomains;
+ vector<r_Minterval>::iterator sourceDIt;
+ vector<r_Minterval>::iterator targetDIt;
+ vector<r_Minterval>::iterator retvalDIt;
+
+
+ vector<Tile*>::iterator sourceIt;
+ vector<Tile*>::iterator targetIt;
+ vector<Tile*>::iterator retvalIt;
+
+ r_Minterval targetDom("[0:50,0:50]");
+ r_Minterval targetInt1("[0:10,0:10]");
+ r_Minterval targetInt2("[15:25,10:20]");
+ r_Minterval targetInt3("[15:25,21:30]");
+ r_Minterval targetInt4("[15:25,31:40]");
+ r_Minterval targetInt5("[40:50,40:50]");
+ r_Minterval targetInt6("[35:41,25:35]");
+ r_Minterval targetInt7("[28:32,28:32]");
+ r_Minterval targetInt8("[40:40,0:10]");
+ r_Minterval targetInt9("[40:50,11:11]");
+ r_Minterval targetInt10("[35:35,0:10]");
+ r_Minterval targetInt11("[30:34,10:10]");
+ OctetType* o = new OctetType();
+
+ char* cont1 = 0;
+ char* cont2 = 0;
+ char* cont3 = 0;
+ char* cont4 = 0;
+ char* cont5 = 0;
+ char* cont6 = 0;
+ char* cont7 = 0;
+ char* cont8 = 0;
+ char* cont9 = 0;
+ char* cont10 = 0;
+ char* cont11 = 0;
+ char* outc = 0;
+ cont1 = (char*)mymalloc(500);
+ cont2 = (char*)mymalloc(500);
+ cont3 = (char*)mymalloc(500);
+ cont4 = (char*)mymalloc(500);
+ cont5 = (char*)mymalloc(500);
+ cont6 = (char*)mymalloc(500);
+ cont7 = (char*)mymalloc(500);
+ cont8 = (char*)mymalloc(500);
+ cont9 = (char*)mymalloc(500);
+ cont10 = (char*)mymalloc(500);
+ cont11 = (char*)mymalloc(500);
+ outc = (char*)mymalloc(101*101);
+ memset(cont1, 1, 500);
+ memset(cont2, 2, 500);
+ memset(cont3, 3, 500);
+ memset(cont4, 4, 500);
+ memset(cont5, 5, 500);
+ memset(cont6, 6, 500);
+ memset(cont7, 7, 500);
+ memset(cont8, 8, 500);
+ memset(cont9, 9, 500);
+ memset(cont10, 10, 500);
+ memset(cont11, 11, 500);
+ memset(outc, 0, 3500);
+ TransTile output(targetDom, o, outc);
+
+ TransTile* ttile1 = new TransTile(targetInt1, (const BaseType*)o, cont1);
+ TransTile* ttile2 = new TransTile(targetInt2, (const BaseType*)o, cont2);
+ TransTile* ttile3 = new TransTile(targetInt3, (const BaseType*)o, cont3);
+ TransTile* ttile4 = new TransTile(targetInt4, (const BaseType*)o, cont4);
+ TransTile* ttile5 = new TransTile(targetInt5, (const BaseType*)o, cont5);
+ TransTile* ttile6 = new TransTile(targetInt6, (const BaseType*)o, cont6);
+ TransTile* ttile7 = new TransTile(targetInt7, (const BaseType*)o, cont7);
+ TransTile* ttile8 = new TransTile(targetInt8, (const BaseType*)o, cont8);
+ TransTile* ttile9 = new TransTile(targetInt9, (const BaseType*)o, cont9);
+ TransTile* ttile10 = new TransTile(targetInt10, (const BaseType*)o, cont10);
+ TransTile* ttile11 = new TransTile(targetInt11, (const BaseType*)o, cont11);
+
+ r_Minterval sourceDom("[5:45,5:45]");
+ r_Minterval sourceInt1("[5:10,5:10]");
+ r_Minterval sourceInt2("[15:25,12:45]");
+ r_Minterval sourceInt3("[30:45,30:38]");
+ r_Minterval sourceInt4("[40:45,40:45]");
+ r_Minterval sourceInt5("[30:45,25:28]");
+ r_Minterval sourceInt6("[39:41,9:11]");
+ r_Minterval sourceInt7("[34:36,9:11]");
+
+ char* scont1 = 0;
+ char* scont2 = 0;
+ char* scont3 = 0;
+ char* scont4 = 0;
+ char* scont5 = 0;
+ char* scont6 = 0;
+ char* scont7 = 0;
+ scont1 = (char*)mymalloc(500);
+ scont2 = (char*)mymalloc(500);
+ scont3 = (char*)mymalloc(500);
+ scont4 = (char*)mymalloc(500);
+ scont5 = (char*)mymalloc(500);
+ scont6 = (char*)mymalloc(500);
+ scont7 = (char*)mymalloc(500);
+ memset(scont1, 21, 500);
+ memset(scont2, 22, 500);
+ memset(scont3, 23, 500);
+ memset(scont4, 24, 500);
+ memset(scont5, 25, 500);
+ memset(scont6, 26, 500);
+ memset(scont7, 27, 500);
+ TransTile* stile1 = new TransTile(sourceInt1, (const BaseType*)o, scont1);
+ TransTile* stile2 = new TransTile(sourceInt2, (const BaseType*)o, scont2);
+ TransTile* stile3 = new TransTile(sourceInt3, (const BaseType*)o, scont3);
+ TransTile* stile4 = new TransTile(sourceInt4, (const BaseType*)o, scont4);
+ TransTile* stile5 = new TransTile(sourceInt5, (const BaseType*)o, scont5);
+ TransTile* stile6 = new TransTile(sourceInt6, (const BaseType*)o, scont6);
+ TransTile* stile7 = new TransTile(sourceInt7, (const BaseType*)o, scont7);
+
+ vector<Tile*> sourceTiles;
+ sourceTiles.push_back(stile1);
+ sourceTiles.push_back(stile2);
+ sourceTiles.push_back(stile3);
+ sourceTiles.push_back(stile4);
+ sourceTiles.push_back(stile5);
+ sourceTiles.push_back(stile6);
+ sourceTiles.push_back(stile7);
+
+ vector<Tile*> targetTiles;
+ targetTiles.push_back(ttile1);
+ targetTiles.push_back(ttile2);
+ targetTiles.push_back(ttile3);
+ targetTiles.push_back(ttile4);
+ targetTiles.push_back(ttile5);
+ targetTiles.push_back(ttile6);
+ targetTiles.push_back(ttile7);
+ targetTiles.push_back(ttile8);
+ targetTiles.push_back(ttile9);
+ targetTiles.push_back(ttile10);
+ targetTiles.push_back(ttile11);
+
+ vector<Tile*> retval;
+
+ unsigned long targetTileArea = 0;
+ unsigned long sourceTileArea = 0;
+ unsigned long targetTileDomain = 0;
+ unsigned long updatedArea = 0;
+ bool intersection = false;
+
+ r_Minterval intersectUpdateDomain;
+
+ bool computed = true;
+
+ cout << "Target Tiles" << endl;
+ for (targetIt = targetTiles.begin(); targetIt != targetTiles.end(); targetIt++)
+ cout << (*targetIt)->getDomain() << endl;
+ cout << endl << "Source Tiles" << endl;
+ for (sourceIt = sourceTiles.begin(); sourceIt != sourceTiles.end(); sourceIt++)
+ cout << (*sourceIt)->getDomain() << endl;
+ cout << endl;
+ cout << "Checking if only update, insert or update and insert" << endl;
+
+ for (sourceIt = sourceTiles.begin(); sourceIt != sourceTiles.end(); sourceIt++)
+ {
+ intersection = false;
+ sourceTileArea = sourceTileArea + (*sourceIt)->getDomain().cell_count();
+ cout << "SourceDomain " << (*sourceIt)->getDomain() << " source area is " << sourceTileArea << endl;
+ for (targetIt = targetTiles.begin(); targetIt != targetTiles.end(); targetIt++)
+ {
+ if (computed)
+ {
+ targetTileArea = targetTileArea + (*targetIt)->getDomain().cell_count();
+ cout << "Target Tile " << (*targetIt)->getDomain() << " area " << targetTileArea << endl;
+ }
+
+ if( (*sourceIt)->getDomain().intersects_with( (*targetIt)->getDomain() ) )
+ {
+ cout << "Intersection" << endl;
+ intersection = true;
+ intersectUpdateDomain = (*sourceIt)->getDomain().create_intersection( (*targetIt)->getDomain() );
+ cout << "Updated " << intersectUpdateDomain << " on source " << (*sourceIt)->getDomain() << " and target " << (*targetIt)->getDomain() << endl;
+ updatedArea = updatedArea + intersectUpdateDomain.cell_count();
+ (*targetIt)->execUnaryOp(Ops::OP_IDENTITY, intersectUpdateDomain, *sourceIt, intersectUpdateDomain );
+ }
+ }
+ if (!intersection)
+ {
+ // Create a new persistent tile, copy the transient data,
+ // and insert it into the target mdd object.
+ cout << "No Intersection" << endl;
+ TransTile* newPersTile = new TransTile((*sourceIt)->getDomain(), o, (*sourceIt)->getDataFormat());
+ newPersTile->execUnaryOp(Ops::OP_IDENTITY, (*sourceIt)->getDomain(), *sourceIt, (*sourceIt)->getDomain());
+ //targetObj->insertTile( newPersTile );
+ updatedArea = updatedArea + (*sourceIt)->getDomain().cell_count();
+ }
+ computed = false;
+ }
+ cout << "Source Domain " << sourceDom << " has area " << sourceDom.cell_count() << endl;
+ cout << "Source Tile Area " << sourceTileArea << endl;
+ cout << "Target Tile Area " << targetTileArea << endl;
+ cout << "Updated Area " << updatedArea << endl << endl;
+ // insert the tile
+
+ if (sourceTileArea <= updatedArea)
+ {
+ cout << "and all sources were used" << endl;
+ }
+ else {
+ cout << "and there are still some cells to do" << endl << endl;
+
+ for (retvalIt = sourceTiles.begin(); retvalIt != sourceTiles.end(); retvalIt++)
+ {
+ sourceDomains.push_back((*retvalIt)->getDomain());
+ }
+
+ for (retvalIt = targetTiles.begin(); retvalIt != targetTiles.end(); retvalIt++)
+ {
+ targetDomains.push_back((*retvalIt)->getDomain());
+ }
+
+ r_Tiler tiler(sourceDomains, targetDomains);
+ tiler.split();
+ tiler.removeCoveredDomains();
+ tiler.removeDoubleDomains();
+ retvalDomains = tiler.getTiledDomains();
+ cout << "we have now" << endl;
+ for (retvalDIt = retvalDomains.begin(); retvalDIt != retvalDomains.end(); retvalDIt++)
+ cout << (*retvalDIt) << endl;
+ tiler.mergeDomains();
+ retvalDomains = tiler.getTiledDomains();
+ cout << "we have now" << endl;
+ for (retvalDIt = retvalDomains.begin(); retvalDIt != retvalDomains.end(); retvalDIt++)
+ cout << (*retvalDIt) << endl;
+ vector<Tile*> t = tiler.generateTransTiles(sourceTiles);
+ for (retvalIt = targetTiles.begin(); retvalIt != targetTiles.end(); retvalIt++)
+ output.execUnaryOp(Ops::OP_IDENTITY, (*retvalIt)->getDomain(), (*retvalIt), (*retvalIt)->getDomain());
+ for (retvalIt = t.begin(); retvalIt != t.end(); retvalIt++)
+ output.execUnaryOp(Ops::OP_IDENTITY, (*retvalIt)->getDomain(), (*retvalIt), (*retvalIt)->getDomain());
+ RManDebug = 30;
+ output.printStatus(cout);
+ RManDebug = 1;
+ }
+ }
+
diff --git a/tilemgr/tile.cc b/tilemgr/tile.cc
new file mode 100644
index 0000000..627a336
--- /dev/null
+++ b/tilemgr/tile.cc
@@ -0,0 +1,1187 @@
+#include "mymalloc/mymalloc.h"
+
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * Tiles store BLOBTiles together with their type and
+ * their coordinates.
+ *
+ *
+ * COMMENTS:
+ * none
+ *
+ ************************************************************/
+
+static const char rcsid[] = "@(#)cachetamgr,Tile: $Id: tile.cc,v 1.79 2005/09/03 21:05:53 rasdev Exp $";
+
+#include <iostream>
+#include "catalogmgr/ops.hh"
+#include "tile.hh"
+#include "relblobif/blobtile.hh"
+#include "reladminif/adminif.hh"
+#include "relblobif/inlinetile.hh"
+#include "compression/tilecompression.hh"
+#include "raslib/rmdebug.hh"
+#include "raslib/miter.hh"
+#include "raslib/miterf.hh"
+#include "raslib/miterd.hh"
+#include "raslib/basetype.hh"
+
+#include <cstring>
+
+const Tile&
+Tile::operator=(const Tile& tile)
+ {
+ if(this != &tile)
+ {
+ type = tile.type;
+ domain = tile.domain;
+ //cloning is faster than recreation
+ if (tile.compEngine != NULL) {
+ if(compEngine != NULL) {
+ delete compEngine;
+ }
+ compEngine = tile.compEngine->clone();
+ }
+ blobTile->resize(tile.blobTile->getSize());
+ blobTile->setDataFormat(tile.blobTile->getDataFormat());
+ blobTile->setCurrentFormat(tile.blobTile->getCurrentFormat());
+ memcpy(blobTile->getCells(), tile.blobTile->getCells(), blobTile->getSize());
+ setParameters(tile.getParameters());
+ }
+ return *this;
+ }
+
+Tile::Tile(const Tile& tile)
+ : domain(tile.domain),
+ type(tile.type),
+ blobTile((DBTile*)NULL),
+ //cloning is faster than recreation
+ compEngine(NULL),
+ params(NULL)
+ {
+ if (tile.compEngine != NULL)
+ compEngine = tile.compEngine->clone();
+ if (RMInit::useTileContainer)
+ blobTile = new InlineTile(tile.blobTile->getSize(), tile.blobTile->getCells(), tile.blobTile->getDataFormat());
+ else
+ blobTile = new BLOBTile(tile.blobTile->getSize(), tile.blobTile->getCells(), tile.blobTile->getDataFormat());
+ blobTile->setCurrentFormat(tile.blobTile->getCurrentFormat());
+ setParameters(tile.getParameters());
+ }
+
+Tile::Tile(std::vector<Tile*>* tilesVec)
+ : domain(),
+ type(NULL),
+ compEngine(NULL),
+ params(NULL),
+ blobTile((DBTile*)NULL)
+ {
+ // iterators for tiles
+ std::vector<Tile*>::iterator tileIt = tilesVec->begin();
+ std::vector<Tile*>::iterator tileEnd = tilesVec->end();
+ domain = (*(tileIt++))->getDomain();
+ while (tileIt != tilesVec->end())
+ {
+ domain.closure_with((*(tileIt++))->getDomain());
+ }
+ tileIt = tilesVec->begin();
+ // initialize type with type of first tile
+ type = (*tileIt)->getType();
+ if (RMInit::useTileContainer)
+ blobTile = new InlineTile(getSize(), (char)0, (*tileIt)->getDataFormat());
+ else
+ blobTile = new BLOBTile(getSize(), (char)0, (*tileIt)->getDataFormat());
+ // initialize compression with compression of first tile
+ //cloning is faster than recreation
+ if ((*tileIt)->compEngine != NULL)
+ compEngine = (*tileIt)->compEngine->clone();
+ setParameters((*tileIt)->getParameters());
+ // initialize domain
+ domain = (*(tileIt++))->getDomain();
+ while (tileIt != tileEnd)
+ domain.closure_with((*(tileIt++))->getDomain());
+
+ // insert all tiles in the result tile
+ tileIt = tilesVec->begin();
+ while (tileIt != tileEnd)
+ {
+ const r_Minterval& currDom = (*tileIt)->getDomain();
+ copyTile(currDom, (*tileIt), currDom);
+ tileIt++;
+ }
+ }
+
+Tile::Tile(std::vector<Tile*>* tilesVec, const r_Minterval& resDom)
+ : params(NULL),
+ domain(resDom),
+ compEngine(NULL)
+ {
+ // iterators for tiles
+ std::vector<Tile*>::iterator tileIt;
+ // domain of the current tile
+ r_Minterval currDom;
+
+ // get first Tile
+ tileIt = tilesVec->begin();
+ // initialize type with type of first tile
+ type = (*tileIt)->getType();
+ // initialize compression with compression of first tile
+ //cloning is faster than recreation
+ if ((*tileIt)->compEngine != NULL)
+ compEngine = (*tileIt)->compEngine->clone();
+ setParameters((*tileIt)->getParameters());
+
+ // init contents
+ if (RMInit::useTileContainer)
+ blobTile = new InlineTile(getSize(), (char)0, (*tileIt)->getDataFormat());
+ else
+ blobTile = new BLOBTile(getSize(), (char)0, (*tileIt)->getDataFormat());
+
+ // insert all tiles in the result tile
+ tileIt = tilesVec->begin();
+ while (tileIt != tilesVec->end())
+ {
+ currDom = (*tileIt)->getDomain();
+ currDom.intersection_with(resDom);
+
+ copyTile(currDom, (*tileIt), currDom);
+
+ tileIt++;
+ }
+ }
+
+Tile::Tile(const Tile* projTile, const r_Minterval& projDom, const std::set<r_Dimension, std::less<r_Dimension> >* projDimSet)
+ : domain(projDom.dimension() - projDimSet->size()),
+ type(projTile->type),
+ compEngine(NULL),
+ params(NULL),
+ blobTile((DBTile*)NULL)
+ {
+ // calculate dimension of new Tile
+ r_Dimension dim = 0;
+ // pointer to cells in tile to be projected and new tile
+ char* cellTile = NULL;
+ char* cellProj = NULL;
+
+ for(dim = 0; dim < projDom.dimension(); dim++)
+ {
+ // do not include dimensions projected away
+ std::set<r_Dimension, std::less<r_Dimension> >::const_iterator tempIt = projDimSet->find(dim);
+ if(tempIt == projDimSet->end())
+ {
+ domain << projDom[dim];
+ }
+ }
+
+ RMDBGONCE(3, RMDebug::module_tilemgr, "Tile", "domain result: " << domain << " domain original: " << projTile->getDomain());
+
+ // have to initialize the uncompressed contents in case an operation is called on the tile
+ //cloning is faster than recreation
+ if (projTile->compEngine)
+ compEngine = projTile->compEngine->clone();
+ setParameters(projTile->getParameters());
+
+ // init contents
+ if (RMInit::useTileContainer)
+ blobTile = new InlineTile(getSize(), (char)0, projTile->getDataFormat());
+ else
+ blobTile = new BLOBTile(getSize(), (char)0, projTile->getDataFormat());
+ // using r_Miter to iterate through tile to be projected and new tile.
+ r_Miter projTileIter(&projDom, &projTile->getDomain(), type->getSize(), (const char*)projTile->getContents());
+ r_Miter newTileIter(&domain, &domain, type->getSize(), blobTile->getCells());
+
+ // identity operation for base type, used for copying
+ UnaryOp* op = type->getUnaryOp(Ops::OP_IDENTITY, (BaseType*)type);
+
+ while(!projTileIter.isDone())
+ {
+ cellTile = newTileIter.nextCell();
+ cellProj = projTileIter.nextCell();
+ RMDBGONCE(3, RMDebug::module_tilemgr, "TransTile", "offset in original: " << (int)(cellProj-((Tile*)projTile)->getContents()) << " {" << (int)*cellProj << "} offset in result: " << (int)((int)(cellTile-getContents())) << " {" << (int)*cellTile << "}");
+ // execute operation on cell
+ (*op)(cellTile, cellProj);
+ }
+
+ delete op;
+ }
+
+Tile::Tile(const r_Minterval& newDom, const BaseType* newType, DBTileId newBLOBTile)
+ : domain(newDom),
+ type(newType),
+ params(NULL),
+ compEngine(NULL),
+ blobTile(newBLOBTile)
+ {
+ RMDBGONCE(3, RMDebug::module_rasodmg, "Tile","Tile(" << newDom << ", " << newType->getName() << ", blob)");
+ }
+
+Tile::Tile(const r_Minterval& newDom, const BaseType* newType, r_Data_Format newFormat)
+ : domain(newDom),
+ params(NULL),
+ type(newType),
+ compEngine(NULL),
+ blobTile((DBTile*)NULL)
+ {
+ RMDBGONCE(3, RMDebug::module_rasodmg, "Tile","Tile(new), size " << getSize());
+ // note that the size is not correct (usually too big) for compressed
+ // tiles. Doesn't matter, because resize is called anyway.
+ if (RMInit::useTileContainer)
+ blobTile = new InlineTile(getSize(), (char)0, newFormat);
+ else
+ blobTile = new BLOBTile(getSize(), (char)0, newFormat);
+ //not neccessary now
+ //initCompEngine();
+ }
+
+Tile::Tile(const r_Minterval& newDom, const BaseType* newType, char* newCells, r_Bytes newSize, r_Data_Format newFormat)
+ : domain(newDom),
+ params(NULL),
+ type(newType),
+ compEngine(NULL),
+ blobTile((DBTile*)NULL)
+ {
+ RMDBGONCE(3, RMDebug::module_rasodmg, "Tile","Tile(), fmt " << newFormat << ", size " << newSize);
+ r_Data_Format current = r_Array;
+ if (!newSize)
+ {
+ // setting uncompressed contents
+ newSize = getSize();
+ }
+ else {
+ // setting compressed contents
+ current = newFormat;
+ }
+ if (RMInit::useTileContainer)
+ blobTile = new InlineTile(newSize, newCells, newFormat);
+ else
+ blobTile = new BLOBTile(newSize, newCells, newFormat);
+ blobTile->setCurrentFormat(current);
+ free(newCells);
+ //not neccessary now
+ //initCompEngine();
+ }
+
+Tile::Tile(const r_Minterval& newDom, const BaseType* newType, const char* newCells, bool, r_Bytes newSize, r_Data_Format newFormat)
+ : domain(newDom),
+ params(NULL),
+ type(newType),
+ compEngine(NULL),
+ blobTile((DBTile*)NULL)
+ {
+ RMDBGONCE(3, RMDebug::module_rasodmg, "Tile","Tile(), fmt " << newFormat << ", size " << newSize);
+ r_Data_Format current = r_Array;
+ if (!newSize)
+ {
+ // setting uncompressed contents
+ newSize = getSize();
+ }
+ else {
+ // setting compressed contents
+ current = newFormat;
+ }
+ if (RMInit::useTileContainer)
+ blobTile = new InlineTile(newSize, newCells, newFormat);
+ else
+ blobTile = new BLOBTile(newSize, newCells, newFormat);
+ blobTile->setCurrentFormat(current);
+ // this one doesn't do this stupid thing: free(newCells);
+ //not neccessary now
+ //initCompEngine();
+ }
+
+void
+Tile::initCompEngine() const
+ {
+ if (compEngine == NULL)
+ {
+ char* typeStruct = type->getTypeStructure();
+ r_Base_Type *useType = (r_Base_Type*)(r_Type::get_any_type(typeStruct));
+ compEngine = r_Tile_Compression::create(blobTile->getDataFormat(), domain, useType);
+ delete useType;
+ free(typeStruct);
+ }
+ }
+
+void
+Tile::setCompressionFormat(r_Data_Format newFormat)
+ {
+ if (blobTile->getDataFormat() != newFormat)
+ {
+ decompress();
+ delete compEngine;
+ char* typeStruct = type->getTypeStructure();
+ r_Base_Type *useType = (r_Base_Type*)(r_Type::get_any_type(typeStruct));
+ compEngine = r_Tile_Compression::create(newFormat, domain, useType);
+ delete useType;
+ free(typeStruct);
+ blobTile->setDataFormat(newFormat);
+ }
+ }
+
+void
+Tile::setPersistent(bool state)
+ {
+ blobTile->setPersistent(state);
+ }
+
+r_Bytes
+Tile::getCompressedSize() const
+ {
+ RMDBGONCE(3, RMDebug::module_rasodmg, "Tile","getCompressedSize()");
+ compress();
+ return blobTile->getSize();
+ }
+
+const char*
+Tile::getCompressedContents() const
+ {
+ RMDBGONCE(3, RMDebug::module_rasodmg, "Tile","getCompressedContents() const");
+ compress();
+ const char* cellPtr = blobTile->getCells();
+ return cellPtr;
+ }
+
+bool
+Tile::isPersistent() const
+ {
+ return blobTile->isPersistent();
+ }
+
+Tile::~Tile()
+ {
+ RMDBGONCE(3, RMDebug::module_rasodmg, "Tile", "~Tile() " << (r_Ptr) this);
+ // this function has to check now if a tile has to be compressed.
+ // The old scheme of compression in AdminIf::compCompTiles does
+ // not work, because tiles may be destroyed before with releaseAll.
+ compress();
+ delete compEngine;
+ delete [] params;
+ }
+
+DBTileId
+Tile::getDBTile()
+ {
+ return blobTile;
+ }
+
+char*
+Tile::execCondenseOp(CondenseOp* myOp, const r_Minterval& areaOp)
+ {
+ RMDBGENTER(3, RMDebug::module_tilemgr, "Tile", "execCondenseOp()");
+ char* cellOp = NULL;
+ char* dummy = getContents();
+ r_Miter opTileIter(&areaOp, &getDomain(), getType()->getSize(), dummy);
+#ifdef RMANBENCHMARK
+ opTimer.resume();
+#endif
+
+ while(!opTileIter.isDone())
+ {
+ cellOp = opTileIter.nextCell();
+ // execute operation on cell
+ (*myOp)(cellOp);
+ }
+
+#ifdef RMANBENCHMARK
+ opTimer.pause();
+#endif
+ RMDBGEXIT(3, RMDebug::module_tilemgr, "Tile", "execCondenseOp()");
+
+ return myOp->getAccuVal();
+ }
+
+
+void
+Tile::execUnaryOp(UnaryOp* myOp, const r_Minterval& areaRes, const Tile* opTile, const r_Minterval& areaOp)
+ {
+ RMDBGENTER(3, RMDebug::module_tilemgr, "Tile", "execUnaryOp()");
+ char* cellRes = NULL;
+ const char* cellOp = NULL;
+
+ char* dummy1 = getContents();
+ const char* dummy2 = opTile->getContents();
+ r_Miter resTileIter(&areaRes, &getDomain(), getType()->getSize(), dummy1);
+ r_Miter opTileIter(&areaOp, &opTile->getDomain(), opTile->getType()->getSize(), dummy2);
+
+#ifdef RMANBENCHMARK
+ opTimer.resume();
+#endif
+
+ while(!resTileIter.isDone())
+ {
+ cellRes = resTileIter.nextCell();
+ cellOp = opTileIter.nextCell();
+ // execute operation on cell
+ (*myOp)(cellRes, cellOp);
+ }
+
+#ifdef RMANBENCHMARK
+ opTimer.pause();
+#endif
+ RMDBGEXIT(3, RMDebug::module_tilemgr, "Tile", "execUnaryOp()");
+ }
+
+void
+Tile::execBinaryOp(BinaryOp* myOp, const r_Minterval& areaRes, const Tile* op1Tile, const r_Minterval& areaOp1, const Tile* op2Tile, const r_Minterval& areaOp2)
+
+ {
+ if ( myOp == NULL )
+ {
+ throw r_Error (OPERANDSRESULTTYPESNOMATCH);
+ }
+ RMDBGENTER(3, RMDebug::module_tilemgr, "Tile", "execBinaryOp()");
+ char* cellRes = NULL;
+ const char* cellOp1 = NULL;
+ const char* cellOp2 = NULL;
+
+ char* dummy1 = getContents();
+ const char* dummy2 = op1Tile->getContents();
+ const char* dummy3 = op2Tile->getContents();
+
+ r_Miter resTileIter(&areaRes, &getDomain(), getType()->getSize(), dummy1);
+ r_Miter op1TileIter(&areaOp1, &op1Tile->getDomain(), op1Tile->getType()->getSize(), dummy2);
+ r_Miter op2TileIter(&areaOp2, &op2Tile->getDomain(), op2Tile->getType()->getSize(), dummy3);
+
+#ifdef RMANBENCHMARK
+ opTimer.resume();
+#endif
+
+ while(!resTileIter.isDone())
+ {
+ cellRes = resTileIter.nextCell();
+ cellOp1 = op1TileIter.nextCell();
+ cellOp2 = op2TileIter.nextCell();
+ // execute operation on cell
+ (*myOp)(cellRes, cellOp1, cellOp2);
+ }
+
+#ifdef RMANBENCHMARK
+ opTimer.pause();
+#endif
+ RMDBGEXIT(3, RMDebug::module_tilemgr, "Tile", "execBinaryOp()");
+ }
+
+void
+Tile::execConstOp(BinaryOp* myOp, const r_Minterval& areaRes, const Tile* opTile, const r_Minterval& areaOp, const char* cell, int constPos)
+ {
+ RMDBGENTER(3, RMDebug::module_tilemgr, "Tile", "execConstOp()");
+ char* cellRes = NULL;
+ const char* cellOp = NULL;
+ char* dummy1 = getContents();
+ const char* dummy2 = opTile->getContents();
+ r_Miter resTileIter(&areaRes, &getDomain(), getType()->getSize(), dummy1);
+ r_Miter opTileIter(&areaOp, &opTile->getDomain(), opTile->getType()->getSize(), dummy2);
+#ifdef RMANBENCHMARK
+ opTimer.resume();
+#endif
+
+ if (constPos == 1)
+ {
+ while(!resTileIter.isDone())
+ {
+ cellRes = resTileIter.nextCell();
+ cellOp = opTileIter.nextCell();
+ // execute operation on cell
+ (*myOp)(cellRes, cell, cellOp);
+ }
+ }
+ else {
+ while(!resTileIter.isDone())
+ {
+ cellRes = resTileIter.nextCell();
+ cellOp = opTileIter.nextCell();
+ // execute operation on cell
+ (*myOp)(cellRes, cellOp, cell);
+ }
+ }
+
+#ifdef RMANBENCHMARK
+ opTimer.pause();
+#endif
+ RMDBGEXIT(3, RMDebug::module_tilemgr, "Tile", "execConstOp()");
+ }
+
+void
+Tile::execMarrayOp(MarrayOp* myOp, const r_Minterval& areaRes, const r_Minterval& areaOp)
+ {
+ r_Point pRes(areaRes.dimension());
+ r_Point pOp(areaOp.dimension());
+ int done = 0;
+ int recalc = 0;
+ int i = 0;
+ int j = 0;
+ int innerExtent = 0;
+ int resSize = 0;
+ int opSize = 0;
+ int dim = 0;
+ char* cellRes = NULL;
+ const char* cellOp = NULL;
+
+ // !!!! check, if areaRes is inside Tile
+
+ resSize = type->getSize();
+
+ dim = areaRes.dimension();
+ innerExtent = (areaOp.get_extent())[dim-1];
+
+ // initialize points
+ for(i = 0; i < areaRes.dimension(); i++)
+ {
+ pRes << areaRes[i].low();
+ pOp << areaOp[i].low();
+ }
+
+ cellRes = getCell(calcOffset(pRes));
+ // iterate over all cells
+#ifdef RMANBENCHMARK
+ opTimer.resume();
+#endif
+ while(!done)
+ {
+ if(recalc)
+ {
+ cellRes = getCell(calcOffset(pRes));
+ recalc = 0;
+ }
+
+ (*myOp)(cellRes, pOp);
+
+ cellRes += resSize;
+
+ // increment coordinates
+ i = dim - 1;
+ ++pRes[i];
+ ++pOp[i];
+ while(pRes[i] > areaRes[i].high())
+ {
+ recalc = 1;
+ pRes[i] = areaRes[i].low();
+ pOp[i] = areaOp[i].low();
+ i--;
+ if(i < 0)
+ {
+ done = 1;
+ break;
+ }
+ ++pRes[i];
+ ++pOp[i];
+ }
+ }
+#ifdef RMANBENCHMARK
+ opTimer.pause();
+#endif
+ }
+
+char*
+Tile::execGenCondenseOp(GenCondenseOp* myOp, const r_Minterval& areaOp)
+ {
+ r_Point pOp(areaOp.dimension());
+ int done = 0;
+ int i = 0;
+ int dim = areaOp.dimension();
+
+ // initialize points
+ for(i = 0; i < areaOp.dimension(); i++)
+ {
+ pOp << areaOp[i].low();
+ }
+
+#ifdef RMANBENCHMARK
+ opTimer.resume();
+#endif
+ // iterate over all cells
+ while(!done)
+ {
+ (*myOp)(pOp);
+
+ // increment coordinates
+ i = dim - 1;
+ ++pOp[i];
+ while(pOp[i] > areaOp[i].high())
+ {
+ pOp[i] = areaOp[i].low();
+ i--;
+ if(i < 0)
+ {
+ done = 1;
+ break;
+ }
+ ++pOp[i];
+ }
+ }
+#ifdef RMANBENCHMARK
+ opTimer.pause();
+#endif
+ return myOp->getAccuVal();
+ }
+
+
+#ifdef RMANDEBUG
+#define CHECK_ITER_SYNC(a,b) \
+ if (a.isDone() != b.isDone()) {RMDBGONCE(3, RMDebug::module_tilemgr, "Tile", "iterators out of sync!");}
+#else
+#define CHECK_ITER_SYNC(a,b)
+#endif
+
+template<class T>
+static inline void tile_scale_core(r_Miter &iterDest, r_MiterFloat &iterSrc, T *dummy)
+ {
+ while (!iterDest.isDone())
+ {
+ const T* srcPtr = (const T*)iterSrc.nextCell();
+ T* destPtr = (T*)iterDest.nextCell();
+ *destPtr = *srcPtr;
+
+ CHECK_ITER_SYNC(iterSrc, iterDest)
+ }
+ CHECK_ITER_SYNC(iterSrc, iterDest)
+ }
+
+#ifdef BLVAHELP
+
+void fast_scale_resample_array(char *dest, const char *src, const r_Minterval &destIv, const r_Minterval &srcIv, const r_Minterval &iterDom, unsigned int type_len, unsigned int length)
+ {
+ r_MiterDirect destIter((void*)dest, destIv, destIv, type_len, 1);
+ r_MiterDirect subIter((void*)src, srcIv, iterDom, type_len, 1);
+ r_MiterDirect srcIter((void*)src, srcIv, iterDom, type_len, length);
+ unsigned int dim = (unsigned int)srcIv.dimension();
+ unsigned int i;
+
+ for (i=0; i<dim; i++)
+ {
+ subIter.id[i].low = 0;
+ }
+
+ while (srcIter.done == 0)
+ {
+ double sum = 0;
+ unsigned int count = 0;
+
+ if (destIter.done != 0) cout << "dest out of sync!" << endl;
+ if (srcIter.id[dim-1].pos == srcIter.id[dim-1].low)
+ {
+ cout << srcIter << " : " << destIter << endl;
+ }
+
+ // init sub iterator
+ subIter.done = 0;
+ for (i=0; i<dim; i++)
+ {
+ long rest;
+
+ subIter.id[i].pos = 0;
+ subIter.id[i].data = srcIter.getData();
+ rest = srcIter.id[i].high - srcIter.id[i].pos;
+ if (rest >= (long)length) rest = (long)length-1;
+ subIter.id[i].high = rest;
+ //count *= rest+1;
+ }
+ while (subIter.done == 0)
+ {
+ sum += *((const unsigned char*)(subIter.getData()));
+ ++subIter;
+ count++;
+ }
+
+ cout<<"Sum="<<sum<<" count="<<count<<endl;
+ // use round to nearest
+ *((char*)(destIter.getData())) = (char)(sum / count + 0.5);
+ //cout << (long)(((const T*)(srcIter.getData())) - src) << " , " << (long)(((T*)(destIter.getData())) - dest) << endl;
+ ++srcIter;
+ ++destIter;
+ }
+ cout << "End: " << srcIter << " : " << destIter << endl;
+ if (destIter.done == 0) cout << "dest out of sync!" << endl;
+ }
+#endif
+
+void
+Tile::execScaleOp(const Tile* opTile, const r_Minterval& sourceDomain, const r_Point& origin, const std::vector<double>& scaleFactors)
+ {
+ // origin is not used in this version
+ RMDBGENTER(3, RMDebug::module_tilemgr, "Tile", "execScaleOp()")
+
+#ifdef BLVAHELP
+ fast_scale_resample_array((char*)getContents(),((Tile*)opTile)->getContents(), domain, opTile->getDomain(), sourceDomain, 1, 2);
+#else
+
+ int typeLength = getType()->getSize();
+ const char *srcPtr = ((Tile*)opTile)->getContents();
+
+ r_MiterFloat iterSrc((Tile*)opTile, (r_Minterval&)sourceDomain, domain);
+ r_Miter iterDest(&domain, &domain, typeLength, getContents());
+
+ // optimize for common basetypes
+ switch (typeLength)
+ {
+ case 1:
+ tile_scale_core(iterDest, iterSrc, (char*)0);
+ break;
+ case 2:
+ tile_scale_core(iterDest, iterSrc, (short*)0);
+ break;
+ case 4:
+ tile_scale_core(iterDest, iterSrc, (long*)0);
+ break;
+ case 8:
+ tile_scale_core(iterDest, iterSrc, (double*)0);
+ break;
+ default:
+ while (!iterDest.isDone())
+ {
+ char *destPtr = iterDest.nextCell();
+ srcPtr = iterSrc.nextCell();
+ memcpy(destPtr, srcPtr, typeLength);
+ CHECK_ITER_SYNC(iterSrc, iterDest)
+ }
+ CHECK_ITER_SYNC(iterSrc, iterDest)
+ break;
+ }
+
+#endif
+ RMDBGEXIT(3, RMDebug::module_tilemgr, "Tile", "leaving Tile::execScaleOp()")
+ }
+
+// the used version
+int
+Tile::scaleGetDomain(const r_Minterval& areaOp, const std::vector<double>& scaleFactors, r_Minterval &areaScaled)
+ {
+ RMDBGENTER(2, RMDebug::module_tilemgr, "Tile", "scaleGetDomain() - second version")
+
+ try {
+ areaScaled= areaOp.create_scale(scaleFactors);
+ }
+ catch(r_Error& err) {
+ //error on scalling
+ RMDBGEXIT(2, RMDebug::module_tilemgr, "Tile", "scaleGetDomain(): areaOp = " << areaOp << " error performing scale")
+ return 0;
+ }
+
+ RMDBGEXIT(2, RMDebug::module_tilemgr, "Tile", "scaleGetDomain(): areaOp = " << areaOp << ", scaled = " << areaScaled)
+
+ return 1;
+ }
+
+
+void
+Tile::copyTile(const r_Minterval &areaRes, const Tile *opTile, const r_Minterval &areaOp)
+ {
+ RMDBGENTER(3, RMDebug::module_tilemgr, "Tile", "copyTile(" << areaRes << ", " << (r_Ptr)opTile << "," << areaOp << ")");
+
+ const char *cellOp = NULL;
+ char *cellRes = NULL;
+
+ // this may trigger decompression
+ cellOp = opTile->getContents();
+ cellRes = getContents();
+
+ r_Dimension dim = areaRes.dimension();
+ r_Range width = areaRes[dim-1].get_extent();
+ unsigned int tsize = getType()->getSize();
+ unsigned int tsizeOp = opTile->getType()->getSize();
+
+ if (tsize != tsizeOp) {
+ RMDBGONCE(0, RMDebug::module_tilemgr, "Tile", "copyTile() ERROR: type sizes incompatible!"
+ << endl << "this type: " << getType()->getName() << "(" << tsize << "), opTile type: "
+ << opTile->getType()->getName() << "(" << tsizeOp << ")" );
+ // FIXME here we have to check if is appropiate to continue
+ }
+
+ // these iterators iterate last dimension first, i.e. minimal step size
+ r_MiterDirect resTileIter((void*)cellRes, getDomain(), areaRes, tsize);
+ r_MiterDirect opTileIter((void*)cellOp, opTile->getDomain(), areaOp, tsize);
+
+#ifdef RMANBENCHMARK
+ opTiler.resume();
+#endif
+
+ while (!resTileIter.isDone())
+ {
+ // copy entire line (continuous chunk in last dimension) in one go
+ memcpy(resTileIter.getData(), opTileIter.getData(), width * tsize);
+ // force overflow of last dimension
+ resTileIter.id[dim-1].pos += width;
+ opTileIter.id[dim-1].pos += width;
+ // iterate; the last dimension will always overflow now
+ ++resTileIter;
+ ++opTileIter;
+ }
+
+#ifdef RMANBENCHMARK
+ opTimer.pause();
+#endif
+
+ RMDBGEXIT(3, RMDebug::module_tilemgr, "Tile", "copyTile(" << areaRes << ", " << (r_Ptr)opTile << "," << areaOp << ")");
+ }
+
+std::vector<Tile*>*
+Tile::splitTile(r_Minterval resDom, int storageDomain)
+ {
+ // domain of current tile
+ r_Minterval currDom(resDom.dimension());
+ // type of result tiles
+ const BaseType* resType;
+ // iterators for tiles
+ std::vector<Tile*>* resultVec = new std::vector<Tile*>;
+ // pointer to generated current tile
+ Tile* smallTile;
+ // current factor for translating
+ r_Point cursor(resDom.dimension());
+ // origin of big tile
+ r_Point origin;
+ // size of result tiles
+ r_Point tileSize;
+ // flag
+ int done = 0;
+ // for loops
+ int i = 0;
+
+ // initialize cursor
+ for(i = 0; i < cursor.dimension(); i++)
+ cursor[i] = 0;
+ // calculate size of Tiles
+ tileSize = resDom.get_extent();
+ // initialize resType
+ resType = this->getType();
+ // origin of bigTile
+ origin = (this->getDomain()).get_origin();
+
+ // initialize currDom
+ for(i = 0; i < cursor.dimension(); i++)
+ currDom << r_Sinterval(origin[i], origin[i] + tileSize[i] - 1);
+ // resets resDom to lower left side of bigTile
+ resDom = currDom;
+
+ // intersect with bigTile
+ currDom.intersection_with(this->getDomain());
+ initCompEngine();
+ // iterate with smallTile over bigTile
+ while(!done)
+ {
+ currDom.intersection_with(this->getDomain());
+
+ // create new smallTile
+ smallTile = new Tile(currDom, resType, compEngine->get_data_format());
+ // fill it with relevant area
+ smallTile->copyTile(currDom, this, currDom);
+ // insert it in result vector
+ resultVec->push_back(smallTile);
+
+ // increment cursor, start with highest dimension
+ i = cursor.dimension() - 1;
+ cursor[i] += tileSize[i];
+ // move cursor
+ currDom = resDom.create_translation(cursor);
+ while(!(currDom.intersects_with(this->getDomain())))
+ {
+ cursor[i] = 0;
+ i--;
+ if(i < 0)
+ {
+ done = 1;
+ break;
+ }
+ cursor[i] += tileSize[i];
+ // move cursor
+ currDom = resDom.create_translation(cursor);
+ }
+ }
+ return resultVec;
+ }
+
+void
+Tile::printStatus(unsigned int level, std::ostream& stream) const
+ {
+ r_Point p(domain.dimension());
+ int done = 0;
+ int i = 0;
+ const char* cell;
+ int dim = domain.dimension();
+
+ // print the contents only on very high debug level
+
+ // initialize point
+ for(i = 0; i < dim; i++)
+ {
+ p << domain[i].low();
+ }
+
+ // iterate over all cells
+ while(!done)
+ {
+ // print cell
+ cell = getCell(calcOffset(p));
+ type->printCell(stream, cell);
+
+ // increment coordinate
+ i = dim - 1;
+ while(++p[i] > domain[i].high())
+ {
+ stream << endl;
+ p[i] = domain[i].low();
+ i--;
+ if(i < 0)
+ {
+ done = 1;
+ break;
+ }
+ }
+ if(i < (dim - 2)) stream << endl;
+ }
+ }
+
+char*
+Tile::getCell(const r_Point& aPoint)
+ {
+ r_Area cellOffset = domain.cell_offset(aPoint);
+ return getCell(cellOffset);
+ }
+
+const char*
+Tile::getCell(const r_Point& aPoint) const
+ {
+ r_Area cellOffset = domain.cell_offset(aPoint);
+ return getCell(cellOffset);
+ }
+
+void
+Tile::setCompressionEngine(r_Tile_Compression* newCompAlg)
+ {
+ decompress();
+ delete compEngine;
+ compEngine = newCompAlg;
+ blobTile->setDataFormat(compEngine->get_data_format());
+ }
+
+const r_Minterval&
+Tile::getDomain() const
+ {
+ return domain;
+ }
+
+const BaseType*
+Tile::getType() const
+ {
+ return type;
+ }
+
+r_Dimension
+Tile::getDimension() const
+ {
+ return domain.dimension();
+ }
+
+r_Bytes
+Tile::getSize() const
+ {
+ return domain.cell_count() * type->getSize();
+ }
+
+r_Data_Format
+Tile::getDataFormat() const
+ {
+ return blobTile->getDataFormat();
+ }
+
+const char*
+Tile::getCell(r_Area index) const
+ {
+ decompress();
+ return &(blobTile->getCells()[index * type->getSize()]);
+ }
+
+char*
+Tile::getCell(r_Area index)
+ {
+ decompress();
+ return &(blobTile->getCells()[index * type->getSize()]);
+ }
+
+void
+Tile::setCell(r_Area index, const char* newCell)
+ {
+ char* cells = getCell(index);
+ int typeSize = type->getSize();
+ for (int i = 0; i < typeSize; i++)
+ cells[i] = newCell[i];
+ }
+
+char*
+Tile::getContents()
+ {
+ decompress();
+ return blobTile->getCells();
+ }
+
+const char*
+Tile::getContents() const
+ {
+ decompress();
+ return blobTile->getCells();
+ }
+
+void
+Tile::setContents(char* newContents)
+ {
+ decompress();
+ blobTile->setCells(newContents);
+ }
+
+void
+Tile::setParameters(const char *par)
+ {
+ delete [] params;
+ if (par != NULL)
+ {
+ params = new char[strlen(par) + 1];
+ strcpy(params, par);
+ }
+ else
+ params = NULL;
+ }
+
+const char*
+Tile::getParameters() const
+ {
+ return params;
+ }
+
+const r_Tile_Compression*
+Tile::getCompressionEngine() const
+ {
+ return compEngine;
+ }
+
+void
+Tile::compress() const
+ {
+ if (blobTile->getCurrentFormat() != blobTile->getDataFormat())
+ {
+ initCompEngine();
+ r_ULong compressedSize = 0;
+ char* compressedData = (char*)(compEngine->compress(blobTile->getCells(), compressedSize, params));
+ if (!AdminIf::isReadOnlyTA())
+ {
+ r_ULong sizee = getSize();
+ if (compressedSize > sizee)
+ {
+ RMInit::logOut << "Warning: overriding compression setting(" << blobTile->getDataFormat() << ") to "
+ << r_Array << " for tile " << getDomain()
+ << " " << blobTile->getOId() << " because compressed size( " << compressedSize
+ << " bytes) > uncompressed size( " << sizee << " bytes)" << endl;
+ r_Tile_Compression* compEngineN = r_Tile_Compression::create(r_Array, getDomain(), compEngine->get_base_type());
+ delete compEngine;
+ compEngine = compEngineN;
+ compEngineN = NULL;
+ ((DBTile*)blobTile.ptr())->setDataFormat(compEngine->get_data_format());
+ free(compressedData);
+ compressedData = NULL;
+ compressedSize = sizee;
+ //not neccessary because already there
+ //blobTile->setNoModificationData(compressedData);
+ }
+ else {
+ blobTile->setNoModificationData(compressedData);
+ }
+ }
+ else {
+ blobTile->setNoModificationData(compressedData);
+ }
+ blobTile->setNoModificationSize(compressedSize);
+ blobTile->setCurrentFormat(compEngine->get_data_format());
+ }
+ }
+
+bool
+Tile::decompress() const
+ {
+ bool retval = true;
+ if (blobTile->getCurrentFormat() != r_Array)
+ {
+ initCompEngine();
+ bool wrongDecompress = false;
+ r_Bytes compressedSize = blobTile->getSize();
+ char* decompressedData = (char*)(compEngine->decompress(blobTile->getCells(), blobTile->getSize(), params));
+ if (decompressedData == NULL)
+ {
+ RMInit::logOut << "Error: decompress returned NULL " << blobTile->getOId() << " " << getDomain() << endl;
+ wrongDecompress = true;
+ decompressedData = (char*)mymalloc(getSize() * sizeof(char));
+ memset(decompressedData, 0, getSize());
+ RMInit::logOut << "Error fixed by returning empty data. ";
+ if (!AdminIf::isReadOnlyTA())
+ {
+ ((DBTile*)blobTile.ptr())->setModified();
+ RMInit::logOut << "Fix was made persistent.";
+ }
+ RMInit::logOut << endl;
+ retval = false;
+ }
+ blobTile->setNoModificationData(decompressedData);
+ blobTile->setNoModificationSize(getSize());
+ blobTile->setCurrentFormat(r_Array);
+ }
+ else {
+ if (getSize() != blobTile->getSize())
+ {
+ RMInit::logOut << "Error: tile with wrong size " << blobTile->getOId() << " " << getDomain() << " is " << blobTile->getSize() << " should be " << getSize() << " format " << blobTile->getDataFormat() << endl;
+ char* tempPtr = (char*)mymalloc(getSize() * sizeof(char));
+ memset(tempPtr, '\0', getSize()*sizeof(char));
+ if(getSize() < blobTile->getSize())
+ {
+ memcpy(tempPtr, blobTile->getCells(), getSize());
+ }
+ else {
+ memcpy(tempPtr, blobTile->getCells(), blobTile->getSize());
+ }
+ ((DBTile*)blobTile.ptr())->setCells(tempPtr);
+ blobTile->setNoModificationSize(getSize());
+ RMInit::logOut << "Error fixed by resizing and copying data" << endl;
+ retval = false;
+ }
+ }
+ return retval;
+ }
+
+
+r_Bytes
+Tile::calcOffset(const r_Point& point) const
+ {
+ int i = 0;
+ r_Bytes offset = 0;
+ r_Bytes factor = 1;
+
+ // calculate offset
+ for(i = domain.dimension() - 1; i >= 0; i--)
+ {
+ offset += (point[i] - domain[i].low()) * factor;
+ factor *= domain[i].high() - domain[i].low() + 1;
+ }
+
+ return offset;
+ }
diff --git a/tilemgr/tile.hh b/tilemgr/tile.hh
new file mode 100644
index 0000000..5534fda
--- /dev/null
+++ b/tilemgr/tile.hh
@@ -0,0 +1,391 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+/*************************************************************
+ *
+ *
+ * PURPOSE:
+ * Tile is the abstract base class for persTile, transTile
+ * and constTile
+ *
+ *
+ * COMMENTS:
+ *
+ ************************************************************/
+
+#ifndef _TILE_HH_
+#define _TILE_HH_
+
+#include <vector>
+#include <set>
+
+#include "raslib/minterval.hh" // for r_Minterval
+#include "raslib/point.hh" // for r_Point
+#include "raslib/mddtypes.hh" // for r_Data_Format
+#include "catalogmgr/ops.hh" // for Ops::OpType
+#include "relcatalogif/basetype.hh" // for BaseType
+#include "relblobif/tileid.hh"
+#include "relblobif/dbtile.hh"
+#include "reladminif/dbref.hh"
+
+#ifdef RMANBENCHMARK
+#include "raslib/rmdebug.hh" // for RMTimer
+#endif
+class KeyObject;
+class PersMDDObjIx;
+class r_Tile_Compression;
+
+
+//@ManMemo: Module: {\bf cachetamgr}.
+
+/*@Doc:
+Tile can be compressed with different algorithms which are implemented as subclasses of \Ref{Compression}. For uncompressed tiles, the special
+subclass NoCompression is used.
+
+{\bf Interdependencies}
+
+Tile uses a pointer to \Ref{BaseType} to store the base type of the Tile.
+It uses a \Ref{r_Minterval} to store the domain of the Tile.
+Pointers to Tiles are used by many classes.
+Compression is done in subclasses of \Ref{Compression}.
+
+Persistent Tiles are created either by servercomm, when data is received from a client, or by indexif if a BLOBTile is retrieved from the
+index. The query tree can also create tiles in case of INSERT or UPDATE queries, and Tile::splitTile creates new tiles.
+*/
+
+class Tile
+{
+ public:
+
+ /// assignment operator (needed, as class uses dynamic memory).
+ const Tile& operator=(const Tile& cell);
+
+ Tile(const r_Minterval& newDom, const BaseType* newType, DBTileId newBLOBTile);
+ /*Doc
+ Constructs a new Tile with basetype {\tt newType} and spatial
+ domain {\tt newDom}. Its contents are stored in \Ref{BLOBTile}
+ {\tt newBLOBTile}. The contents are potentially compressed.
+ */
+ Tile(const Tile& tile);
+ /// constructs a TransTile joined out of the Tiles in {\tt tilesVec}.
+ Tile(std::vector<Tile*>* tilesVec);
+ /*@Doc:
+ Constructs a new Tile out of the vector {\tt tilesVec}
+ containing pointers to tiles. The Tile created has the
+ closure of the domains of all tiles in the vector as it's domain
+ and the same base type. The tiles should not overlap and must have
+ the same basetype and dimension. Non filled areas in the created
+ tile are of undefined value. The contents are copied, the memory
+ of the tiles and the vector has to be freed by the caller. The
+ resulting Tile is by default uncompressed.
+ */
+ /*@ManMemo:
+ constructs a Tile with the domain {\tt resDom}
+ and the contents joined out of the Tiles in {\tt tilesVec}.
+ */
+ Tile(std::vector<Tile*>* tilesVec, const r_Minterval& resDom);
+ /*@Doc:
+ Constructs a new Tile out of the vector {\tt tilesVec}
+ containing pointers to tiles. The contents which fall in the area
+ {\tt resDom} are copied into the new Tile. The Tile
+ created has the domain {\tt resDom} and the same base type as the
+ Tiles in {\tt tilesVec}. The tiles should not overlap and must
+ have the same basetype and dimension. Non filled areas in the
+ created tile are of undefined value. The memory of the tiles and
+ the vector has to be freed by the caller. Every tile in {\tt
+ tilesVec} has to overlap with {\tt resDom}.
+ */
+ /// constructs Tile as projection of {\tt projTile}.
+ Tile(const Tile* projTile, const r_Minterval& projDom, const std::set<r_Dimension, std::less<r_Dimension> >* projDim);
+ /*@Doc:
+ Constructs a new Tile out of the projection of Tile {\tt
+ projTile} with the dimensions given in {\tt projDim} projected
+ away (zero based dimension counting!). Only the area specified in
+ projDom is used for the new Tile. {\tt projDom} must have the
+ same dimension as the domain of {\tt projTile}. Dimensions
+ projected away must have the coordinate to be projected at
+ as domain, e.g. 28:28.
+ */
+ /*@ManMemo: constructs a Tile with base type {\tt newType} and
+ spatial domain {\tt newDom}. */
+ Tile(const r_Minterval& newDom, const BaseType* newType, r_Data_Format newFormat = r_Array);
+ /*@Doc
+ The contents are undefined! This constructor should usually not
+ be used.
+ */
+ /// constructs a Tile with contents {\tt newCells}.
+ Tile(const r_Minterval& newDom, const BaseType* newType, char* newCells, r_Bytes newSize = 0, r_Data_Format newFormat = r_Array);
+ /*Doc
+ Constructs a new Tile with basetype {\tt newType} and spatial
+ domain {\tt newDom}. The char array {\tt newCells} contains the
+ potentially compressed contents of the new Tile. The memory for
+ the cells is managed by Tile and has to be allocated with
+ malloc(). If newSize is 0, it is assumed to be uncompressed contents,
+ and the size is calculated from domain and base type.
+ */
+ Tile(const r_Minterval& newDom, const BaseType* newType, const char* newCells, bool, r_Bytes newSize = 0, r_Data_Format newFormat = r_Array);
+ /*Doc
+ Constructs a new Tile with basetype {\tt newType} and spatial
+ domain {\tt newDom}. The char array {\tt newCells} contains the
+ potentially compressed contents of the new Tile. 'bool' is used only,
+ for making the difference between this constructor and the upper one.
+ This one doesn't delete the passed data!
+ If newSize is 0, it is assumed to be uncompressed contents,
+ and the size is calculated from domain and base type.
+ */
+ //@Man: read methods
+ //@{
+ /// returns the spatial domain of the tile.
+ const r_Minterval& getDomain() const;
+ /// returns the BaseType of the tile.
+ const BaseType* getType() const;
+ /// returns the dimension of the tile.
+ r_Dimension getDimension() const;
+ /// returns size of the (uncompressed) contents of the tile in chars.
+ r_Bytes getSize() const;
+ /// returns size of the contents of the tile as stored in chars.
+ r_Bytes getCompressedSize() const;
+ /// returns the format of the data maintained by the tile
+ r_Data_Format getDataFormat() const;
+ /// returns true for persistent instances.
+ bool isPersistent() const;
+ /// returns true if the contents are currently compressed and must be decompressed in order to be usefull
+ bool isCompressed() const;
+ //@}
+
+ //@Man: functions to reading and writing the content.
+ //@{
+ /// access to cell for reading (index is 1D) one cell length is basetype length.
+ const char* getCell(r_Area index) const;
+ /// access to cell for modifying (index is 1D).
+ char* getCell(r_Area index);
+ /// set cell (index is 1D).
+ void setCell(r_Area index, const char* newCell);
+ /// access to a cell using an r_Point.
+ char* getCell(const r_Point& aPoint);
+ /// access to a cell using an r_Point.
+ const char* getCell(const r_Point& aPoint) const;
+ /// returns pointer to (uncompressed) contents of Tile.
+ const char* getContents() const;
+ /// returns pointer to (uncompressed) contents of Tile.
+ char* getContents();
+ /// sets (uncompressed) contents of Tile.
+ void setContents(char* newContents);
+ /*@Doc:
+ The memory for the cells is managed by the Tile and has to be
+ allocated with malloc(). Its size has to be correct according to
+ domain and base type of the Tile.
+ */
+ /// returns pointer to compressed contents of Tile as stored.
+ const char* getCompressedContents() const;
+ /// returns pointer to potentially compressed contents of Tile as stored.
+ const r_Tile_Compression* getCompressionEngine() const;
+ /// this is a quick hack for BLVA (r_RLE seems not to work on DEC)
+ void setCompressionEngine(r_Tile_Compression* newCompEngine);
+ /// this is a quick hack for BLVA (r_RLE seems not to work on DEC)
+ void setCompressionFormat(r_Data_Format newFormat);
+ //@}
+
+ //@Man: functions related to compression
+ //@{
+ /// set parameters for compression/decompression
+ void setParameters(const char *par);
+ /// get compression/decompression parameters
+ const char *getParameters(void) const;
+ /// make sure the tile is compressed
+ void compress() const;
+ /// make sure the tile is decompressed
+ /// returns true if no errors were encountered and false if black data was generated
+ bool decompress() const;
+ //@}
+
+ /// printed output for testing.
+ void printStatus(unsigned int level = 0, std::ostream &stream = std::cout) const;
+ /*@Doc:
+ Prints the contents of the Tile on stream. Prints every cell in
+ the Tile with the {\tt printCell} function of the \Ref{BaseType}.
+ For dimensionality > 1, 2D-slices are printed with an empty line
+ in between. These 2D slices cover the lowest 2 indices (0 and 1).
+ */
+
+ void setPersistent(bool state = true);
+
+ /// splits tile in vector of tiles of smaller size.
+ std::vector<Tile*>* splitTile(r_Minterval resDom, int storageDomain = 0);
+ /*@Doc:
+ The Tile is split into subtiles with the same extent as {\tt
+ resDom}. The storage domain (pers. or transient) of the subtiles is
+ defined by {\tt storageDomain}. If it is null (default value) they
+ have the same type (\Ref{TransTile} resp. \Ref{Tile}) as self.
+ If {\tt storageDomain} is 1, they are persistent, if {\tt storageDomain}
+ has a value other than 0 or 1, they are made transient.
+ The algoritm starts with the smallest
+ coordinate in each dimension, so that if the Tile does not divide
+ into Tiles of extent {\tt resDom}, the last Tiles in each
+ dimension may be smaller. The Tiles returned as pointers have to
+ be freed by the caller!
+ */
+
+
+ //@Man: methods for carrying out operations
+ //@{
+ /// carries out condense function (const)
+ char* execCondenseOp(CondenseOp* myOp, const r_Minterval& areaOp);
+ /*@Doc:
+ The condense function {\tt myOp} is applied to all cells of self in
+ the area {\tt areaOp}. The result is stored in myOp which also
+ gives the start value for the condense operation. The return value
+ is a pointer to a member of myOp, so it gets invalid if myOp is
+ deleted! For further information on condense operations see \Ref{Ops}.
+ */
+
+
+ /// carries out unary function with self as result.
+ void execUnaryOp(UnaryOp* myOp, const r_Minterval& areaRes, const Tile* opTile, const r_Minterval& areaOp);
+ /*@Doc:
+ The unary function {\tt myOp} is applied to all cells of the tile
+ {\tt opTile} in the area {\tt areaOp}. The result of the
+ operation is stored in self in the area {\tt areaRes}. The areas
+ must have the same extent, but may differ in an offset.
+ */
+
+ /// carries out binary function with self as result.
+ void execBinaryOp( BinaryOp* myOp, const r_Minterval& areaRes,
+ const Tile* op1Tile, const r_Minterval& areaOp1,
+ const Tile* op2Tile, const r_Minterval& areaOp2);
+ /*@Doc:
+ The binary function {\tt myOp} is applied to all cells of the tiles
+ {\tt op1Tile} and {\tt op2Tile} in the respective areas. The
+ result of the operation is stored in self in the area {\tt
+ areaRes}. The areas must have the same extent for all tiles. but
+ may differ in an offset vector.
+ */
+
+ /// carries out binary function with self as result.
+ virtual void execConstOp( BinaryOp* myOp, const r_Minterval& areaRes,
+ const Tile* opTile, const r_Minterval& areaOp,
+ const char* cell, int constPos = 1);
+ /*@Doc:
+ The binary function {\tt op} is applied to all cells of the tile
+ {\tt op1Tile} and the constant {\tt cell} in the area {\tt
+ areaOp}. If {\tt constPos} is 1, then {\tt const op cell} is
+ carried out; if it is 2, then {\tt cell op const} is carried out.
+ The result of the operations is stored in self in the area {\tt
+ areaRes}. {\tt areaOp} and {\tt areaRes} must have the same
+ extent, but may differ in an offset.
+ */
+
+
+ /// fills tile in area {\tt areaRes} using MarrayOp {\tt myOp}.
+ virtual void execMarrayOp(MarrayOp* myOp, const r_Minterval& areaRes, const r_Minterval& areaOp);
+ /*@Doc:
+ {\tt myOp} maps a point to a value. It is important that the base
+ type specified it the same as the tile has.
+ */
+
+ /// executes general condense operation {\tt myOp} in area {\tt areaOp} (const)
+ static char* execGenCondenseOp(GenCondenseOp* myOp, const r_Minterval& areaOp);
+ /*@Doc:
+ {\tt myOp} maps a point to a value. The return values has the resType
+ defined in {\tt myOp}. The tile is not accessed (static function),
+ the function is defined here to be located together with the other
+ operation execution functions.
+ */
+ /// executes scaling operation.
+ virtual void execScaleOp( const Tile* opTile, const r_Minterval& areaOp,
+ const r_Point& origin,
+ const std::vector<double>& scaleFactors);
+ /*@Doc:
+ The tile {\tt opTile} is scaled down in each dimension by the
+ corresponding element in vector {\tt scaleFactors}. The result
+ is stored in the tile on which the operation is called. Scaling
+ is done by using a nearest neighbour algorithm based on
+ {\tt origin} as the point where the scaling process started.
+ {\tt opTile} has to have the same dimensionality as the result
+ tile and scaleFactors has to have a corresponding number of
+ elements.
+ */
+ //@}
+ /// return spatial domain of result tile for scaling in areaScaled.
+ /// return 0 if the result tile will be empty.
+ /// (the same function, but with implicit origin (0,0,...0) and working fine!)
+ int scaleGetDomain( const r_Minterval& areaOp,
+ const std::vector<double>& scaleFactors,
+ r_Minterval& areaScaled);
+
+ /*@Doc:
+ Return result domain in areaScaled if scaling using the factors in
+ scaleFactors would be applied in area {\tt areaOp} with the scaling
+ factors specified in {\tt scaleFactors}. If the tile would become
+ completely empty, false is returned. This can then be used to create
+ a temporary tile for the result on which the {\tt execScaleOp}
+ function can be called.
+ */
+
+ /// virtual destructor.
+ virtual ~Tile();
+
+ /// copy a subcube from one tile to another
+ virtual void copyTile(const r_Minterval& areaRes, const Tile *opTile, const r_Minterval& areaOp);
+ /*@Doc:
+ The part of opTile covered by areaOp is copied to areaRes of this tile. Identical in functionality to execUnaryOp(OP_IDENTITY, ...) but much faster.
+ Requires matching base types and matching domains.
+ */
+
+ DBTileId getDBTile();
+ /*Doc
+ Returns a pointer to the \Ref{BLOBTile} holding the contents of
+ the Tile. This function is used to persistently store the
+ contents of a Tile.
+ */
+
+#ifdef RMANBENCHMARK
+ // RMTimer for taking O2 times. Could be protected. Is controlled
+ // in servercomm/servercomm2.cc.
+ static RMTimer opTimer;
+#endif
+
+ protected:
+ //@Man: utility functions used internally.
+ //@{
+ /// calculate offset in cells
+ r_Bytes calcOffset(const r_Point& point) const;
+ // fill cells of size size with pattern newCell of size patSize.
+
+ /// instantiate a compression engine
+ void initCompEngine() const;
+ //@}
+
+ /// spatial domain of the tile.
+ r_Minterval domain;
+ /// pointer to base type for cells of Tile.
+ const BaseType* type;
+ /// Smart pointer to the persistent BLOBTile.
+ DBTileId blobTile;
+ /// The compression algorithm
+ mutable r_Tile_Compression *compEngine;
+ /// compression parameters
+ char* params;
+ };
+
+#endif
diff --git a/tilemgr/tile.icc b/tilemgr/tile.icc
new file mode 100644
index 0000000..cafa4ab
--- /dev/null
+++ b/tilemgr/tile.icc
@@ -0,0 +1 @@
+//moved to tile.cc
diff --git a/tilemgr/tiler.cc b/tilemgr/tiler.cc
new file mode 100644
index 0000000..9924cd4
--- /dev/null
+++ b/tilemgr/tiler.cc
@@ -0,0 +1,397 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#include "tiler.hh"
+#include "tilemgr/tile.hh"
+
+r_Tiler::r_Tiler(std::vector<r_Minterval>& sourceDomain2s, const std::vector<r_Minterval>& targetDomain2s)
+ : sourceDomains(sourceDomain2s),
+ targetDomains(targetDomain2s)
+ {
+ }
+
+void
+r_Tiler::mergeDomains()
+ {
+ std::vector<r_Minterval>::iterator splitedIt;
+ std::vector<r_Minterval> temp;
+ r_Minterval tempDom;
+ bool merged = false;
+ while (!splitedDomains.empty())
+ {
+ merged = false;
+ tempDom = *(splitedDomains.begin());
+ splitedDomains.erase(splitedDomains.begin());
+ for (splitedIt = splitedDomains.begin(); splitedDomains.end() != splitedIt; splitedIt++)
+ {
+ if (tempDom.is_mergeable(*splitedIt))
+ {
+ //cout << "is mergeable " << tempDom << " " << *splitedIt << endl;
+ tempDom.closure_with(*splitedIt);
+ //cout << "closure " << tempDom << endl;
+ splitedDomains.erase(splitedIt);
+ merged = true;
+ break;
+ }
+ else {
+ //cout << "is not mergeable " << tempDom << " " << *splitedIt << endl;
+ }
+ }
+ if (merged)
+ splitedDomains.push_back(tempDom);
+ else
+ temp.push_back(tempDom);
+ }
+ splitedDomains = temp;
+ }
+
+void
+r_Tiler::split()
+ {
+ std::vector<r_Minterval>::iterator sourceIt;
+ std::vector<r_Minterval>::iterator retvalIt;
+ std::vector<r_Minterval> splits;
+ std::vector<RangePair> points;
+
+ for (sourceIt = sourceDomains.begin(); sourceIt != sourceDomains.end(); sourceIt++)
+ {
+ //cout << "starting with source domain " << *sourceIt << endl;
+ points = computeSplitDimensions(*sourceIt);
+ splits = splitMinterval(*sourceIt, points);
+ for (retvalIt = splits.begin(); retvalIt != splits.end(); retvalIt++)
+ {
+ splitedDomains.push_back(*retvalIt);
+ }
+ //it is either splitted and in retval or not splitted and then there is an error, because not splitted were inserted
+ }
+ }
+
+std::vector<RangePair>
+r_Tiler::computeSplitDimensions(const r_Minterval& sourceDomain) const
+ {
+ r_Dimension dim = 0;
+ r_Range slow = 0;
+ r_Range shigh = 0;
+ r_Range ilow = 0;
+ r_Range ihigh = 0;
+
+ std::vector<r_Minterval> intersects;
+ std::vector<r_Minterval>::iterator intersectIt;
+ std::vector<r_Minterval>::const_iterator targetIt;
+
+ std::vector<RangePair> points;
+ std::vector<RangePair>::iterator pointIt;
+ RangePair pair;
+
+ //cout << "\tfinding the intersections of current source with targets" << endl;
+ for (targetIt = targetDomains.begin(); targetIt != targetDomains.end(); targetIt++)
+ {
+ if ((*targetIt).intersects_with(sourceDomain))
+ {
+ //cout << "\t\tsource intersected target " << *targetIt << endl;
+ intersects.push_back((*targetIt).create_intersection(sourceDomain));
+ }
+ else {
+ //cout << "\t\tsource did not intersect target " << *targetIt << endl;
+ }
+ }
+
+ //cout << "\titerating through intersecting domains to determine the spliting dimensions" << endl;
+ for (intersectIt = intersects.begin(); intersectIt != intersects.end(); intersectIt++)
+ {
+ //cout << "\t\tstarting to compute split dimensions with " << *intersectIt << endl;
+ for (dim = 0; dim < (*intersectIt).dimension(); dim++)
+ {
+ ilow = (*intersectIt)[dim].low();
+ ihigh = (*intersectIt)[dim].high();
+ slow = (sourceDomain)[dim].low();
+ shigh = (sourceDomain)[dim].high();
+ //cout << "\t\t\tdimension " << dim << endl;
+ //cout << "\t\t\tsource low " << (sourceDomain)[dim].low() << "=" << slow << ", intersect low " << (*intersectIt)[dim].low() << "=" << ilow << endl;
+ //cout << "\t\t\tsource high " << (sourceDomain)[dim].high() << "=" << shigh << ", intersect high " << (*intersectIt)[dim].high() << "=" << ihigh << endl;
+ if ((slow <= ilow) & (shigh >= ilow))
+ {
+ pair.first = dim;
+ pair.second = ilow - 1;
+ //cout << "\t\t\tadding " << pair.second << endl;
+ points.push_back(pair);
+ }
+ if ((slow <= ihigh) & (shigh >= ihigh))
+ {
+ pair.first = dim;
+ pair.second = ihigh;
+ //cout << "\t\t\tadding " << pair.second << endl;
+ points.push_back(pair);
+ }
+ }
+ //cout << "\t\tfound all split dimensions for the current source with intersect " << *intersectIt << endl;
+ }
+ //cout << "\t\t\tfound all split dimensions for source " << sourceDomain << endl;
+ //for (pointIt = points.begin(); pointIt != points.end(); pointIt++)
+ //cout << "\t\t\tsplit in dimension " << (*pointIt).first << " at coordinate " << (*pointIt).second << endl;
+ //cout << "try " << endl;
+ std::vector<RangePair> temp;
+ std::vector<RangePair>::iterator tempIt;
+ RangePair tempP;
+ bool tempadd = true;
+ temp.swap(points);
+ //for (pointIt = points.begin(); pointIt != points.end(); pointIt++)
+ //cout << "\t\t\tsplit in dimension " << (*pointIt).first << " at coordinate " << (*pointIt).second << endl;
+ //cout << "try end" << endl;
+ while (!temp.empty())
+ {
+ tempadd = true;
+ tempP = *(temp.begin());
+ temp.erase(temp.begin());
+ for (tempIt = temp.begin(); tempIt != temp.end(); tempIt++)
+ {
+ if ((tempP.first == (*tempIt).first) & (tempP.second == (*tempIt).second))
+ {
+ //cout << "matched" << endl;
+ tempadd = false;
+ break;
+ }
+ }
+ if (tempadd)
+ points.push_back(tempP);
+ }
+ //cout << "try end 2" << endl;
+ //for (pointIt = points.begin(); pointIt != points.end(); pointIt++)
+ //cout << "\t\t\tsplit in dimension " << (*pointIt).first << " at coordinate " << (*pointIt).second << endl;
+ //cout << "try end 3" << endl;
+ return points;
+ }
+
+std::vector<r_Minterval>
+r_Tiler::splitMinterval(const r_Minterval& sourceTile, std::vector<RangePair>& points)
+ {
+ std::vector<r_Minterval> splits;
+ std::vector<r_Minterval> split2s;
+ std::vector<r_Minterval>::iterator splitIt;
+ std::vector<r_Minterval>::iterator split2It;
+
+ r_Minterval splitInterval1;
+ r_Minterval splitInterval2;
+
+ std::vector<RangePair>::iterator pointIt;
+
+ bool addDomain = false;
+
+ r_Dimension dim = 0;
+ r_Range low = 0;
+ r_Range high = 0;
+ r_Range splitCoordinate = 0;
+
+ //initialize the split std::vector. the result will contain a list of splitted domains.
+ splits.push_back(sourceTile);
+
+ //cout << "\t\tstarting to actually split" << endl;
+ for (pointIt = points.begin(); pointIt != points.end(); pointIt++)
+ {
+ split2s = std::vector<r_Minterval>();
+ //cout << "\t\t\tstarting to split at dimension " << (*pointIt).first << " coordinate " << (*pointIt).second << endl;
+ //cout << "\t\t\titerating through all the tiles to be split, stemming from current source tile" << endl;
+ while (!splits.empty())
+ {
+ splitIt = splits.begin();
+ //cout << "\t\t\t\tsplitting " << (*splitIt) << endl;
+ addDomain = false;
+ splitInterval1 = r_Minterval(((*splitIt)).dimension());
+ splitInterval2 = r_Minterval(((*splitIt)).dimension());
+ //cout << "\t\t\t\ttrying split" << endl;
+ for (dim = 0; dim < ((*splitIt)).dimension(); dim++)
+ {
+ if ((dim == (*pointIt).first))
+ {
+ high = (*splitIt)[dim].high();
+ low = (*splitIt)[dim].low();
+ splitCoordinate = (*pointIt).second;
+ if ((splitCoordinate < high) & (splitCoordinate > low))
+ {
+ //cout << "\t\t\t\t\tsplit middle adding [" << low << ":" << splitCoordinate << "]" << endl;
+ splitInterval1 << r_Sinterval(low, splitCoordinate);
+ //cout << "\t\t\t\t\tsplit middle adding [" << splitCoordinate+1 << ":" << high << "]" << endl;
+ splitInterval2 << r_Sinterval(splitCoordinate + 1, high);
+ addDomain = true;
+ }
+ else {
+ if (splitCoordinate == high)
+ {
+ addDomain = true;
+ if (low == high)
+ {
+ //cout << "\t\t\t\t\tsplit high adding [" << low << ":" << low << "]" << endl;
+ splitInterval1 << r_Sinterval(low, high);
+ }
+ else {
+ //cout << "\t\t\t\t\tsplit high adding [" << low << ":" << high-1<<"]" << endl;
+ splitInterval1 << r_Sinterval(low, splitCoordinate - 1);
+ }
+
+ splitInterval2 << r_Sinterval(splitCoordinate, splitCoordinate);
+ }
+ else {
+ if ((*pointIt).second == ((*splitIt))[dim].low())
+ {
+ addDomain = true;
+ if (low == high)
+ {
+ //cout<<"\t\t\t\t\tsplit low adding ["<<low<<":"<<high<< "]"<<endl;
+ splitInterval1 << r_Sinterval(low, high);
+ }
+ else {
+ //cout<<"\t\t\t\t\tsplit low adding ["<<low+1<<":"<< high<< "]"<<endl;
+ splitInterval1 << r_Sinterval(low + 1, high);
+ }
+ splitInterval2<< r_Sinterval((*pointIt).second,(*pointIt).second);
+ }
+ else {
+ //cout << "\t\t\t\t\tno match, break" << endl;
+ break;
+ }
+ }
+ }
+ }
+ else {
+ //cout << "\t\t\t\t\tdimension unmatched, adding " << ((*splitIt))[dim] << endl;
+ splitInterval1 << ((*splitIt))[dim];
+ splitInterval2 << ((*splitIt))[dim];
+ }
+ }
+ if (addDomain)
+ {
+ //cout << "\t\t\t\tadding split domain 1 " << splitInterval1 << endl;
+ split2s.push_back(splitInterval1);
+ //cout << "\t\t\t\tadding split domain 2 " << splitInterval2 << endl;
+ split2s.push_back(splitInterval2);
+ }
+ else {
+ //cout << "\t\t\t\tnot adding split domains " << splitInterval1 << " " << splitInterval1 << endl;
+ //cout << "\t\t\t\tadding because of no splits " << (*splitIt) << endl;
+ split2s.push_back(*splitIt);
+ }
+ splits.erase(splitIt);
+ }
+ splits = split2s;
+ }
+ //cout << "splitMinterval computed" << endl;
+ //for (splitIt = splits.begin(); splitIt != splits.end(); splitIt++)
+ // {
+ //cout << (*splitIt) << endl;
+ // }
+ return splits;
+ }
+
+void
+r_Tiler::removeCoveredDomains()
+ {
+ r_Minterval temp;
+ std::vector<r_Minterval> retval;
+ bool kill = false;
+ std::vector<r_Minterval>::iterator targetIt;
+ retval.swap(splitedDomains);
+ while (!retval.empty())
+ {
+ temp = *(retval.begin());
+ retval.erase(retval.begin());
+ kill = false;
+ for (targetIt = retval.begin(); targetIt != retval.end(); targetIt++)
+ {
+ if ((*targetIt).intersects_with(temp))
+ {
+ kill = true;
+ break;
+ }
+ }
+ if (!kill)
+ splitedDomains.push_back(temp);
+ }
+ }
+
+void
+r_Tiler::removeDoubleDomains()
+ {
+ r_Minterval temp;
+ std::vector<r_Minterval> retval;
+ bool kill = false;
+ std::vector<r_Minterval>::iterator targetIt;
+ while (!splitedDomains.empty())
+ {
+ temp = *(splitedDomains.begin());
+ splitedDomains.erase(splitedDomains.begin());
+ kill = false;
+ for (targetIt = targetDomains.begin(); targetIt != targetDomains.end(); targetIt++)
+ {
+ if ((*targetIt).intersects_with(temp))
+ {
+ kill = true;
+ break;
+ }
+ }
+ if (!kill)
+ retval.push_back(temp);
+ }
+ retval.swap(splitedDomains);
+ }
+
+std::vector<r_Minterval>
+r_Tiler::getTiledDomains() const
+ {
+ return splitedDomains;
+ }
+
+std::vector<Tile*>
+r_Tiler::generateTiles(const std::vector<Tile*>& sourceTiles) const
+ {
+ std::vector<r_Minterval>::const_iterator splitedDomIt;
+ std::vector<Tile*>::const_iterator sourceTileIt;
+ std::vector<Tile*> retval;
+ r_Minterval dummy;
+ Tile* p = 0;
+ const BaseType* basetype = (*sourceTiles.begin())->getType();
+ r_Data_Format dataformat = (*sourceTiles.begin())->getDataFormat();
+
+ for (splitedDomIt = splitedDomains.begin(); splitedDomIt != splitedDomains.end(); splitedDomIt++)
+ {
+ dummy = *splitedDomIt;
+ p = new Tile(dummy, basetype, dataformat);
+ //std::cout << "new tile " << dummy << " " << basetype->getName() << " " << dataformat << " size " << p->getSize() << " other size " << p->getDBTile()->getSize() << std::endl;
+ for (sourceTileIt = sourceTiles.begin(); sourceTileIt != sourceTiles.end(); sourceTileIt++)
+ {
+ //std::cout << " the other tile domain " << (*sourceTileIt)->getDomain() << " type " << (*sourceTileIt)->getType()->getName() << std::endl;
+ if (dummy.intersects_with((*sourceTileIt)->getDomain()))
+ {
+ const r_Minterval& updateDomain = dummy.create_intersection((*sourceTileIt)->getDomain());
+ //std::cout << " they intersect. on " << updateDomain << std::endl;
+ //UnaryOp* tempOp = Ops::getUnaryOp(Ops::OP_IDENTITY, p->getType(), (*sourceTileIt)->getType(), 0, 0);
+ //causes fmr/abr/umr
+ p->copyTile(updateDomain, *sourceTileIt, updateDomain);
+ //p->execUnaryOp(tempOp, dummy.create_intersection((*sourceTileIt)->getDomain()), *sourceTileIt, dummy.create_intersection((*sourceTileIt)->getDomain()));
+ //delete tempOp;
+ }
+ }
+ retval.push_back(p);
+ }
+ return retval;
+ }
+
diff --git a/tilemgr/tiler.hh b/tilemgr/tiler.hh
new file mode 100644
index 0000000..796ab59
--- /dev/null
+++ b/tilemgr/tiler.hh
@@ -0,0 +1,93 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#ifndef _D_TILER_
+#define _D_TILER_
+
+#include "raslib/minterval.hh"
+#include <vector>
+#include <utility>
+//#include<pair>
+
+class Tile;
+class PersTile;
+class TransTile;
+
+typedef std::pair<r_Range,r_Range> RangePair;
+typedef std::pair<const r_Range,const r_Range> ConstRangePair;
+
+class r_Tiler
+ {
+ public:
+ r_Tiler(std::vector<r_Minterval>& sourceDomains, const std::vector<r_Minterval>& targetDomains);
+ /*
+ sourceDomains will be splitted.
+ targetDomains will not be touched.
+ */
+
+ void split();
+ /*
+ will split the source domains.
+ */
+
+ void removeCoveredDomains();
+ /*
+ removes those splited domains which are covered by target domains.
+ */
+
+ void removeDoubleDomains();
+ /*
+ removes those splited domains which are covered by other splited domains.
+ */
+
+ void mergeDomains();
+ /*
+ tries to merge splited domains into larger domains.
+ */
+
+ std::vector<r_Minterval> getTiledDomains() const;
+ /*
+ returns the computed domains. you must call split() first.
+ */
+
+ std::vector<Tile*> generateTiles(const std::vector<Tile*>& sourceTiles) const;
+ /*
+ uses the previously computed tiled domains to generate the output.
+ call split, removeCoveredDomains, removeDoubleDomains, mergeDomains first!
+ memory must be freed by the caller!
+ */
+
+ private:
+
+ std::vector<r_Minterval> splitMinterval(const r_Minterval& sourceDomain, std::vector<RangePair>& splitDimensions);
+
+ std::vector<RangePair> computeSplitDimensions(const r_Minterval& sourceDomain) const;
+
+ std::vector<r_Minterval> splitedDomains;
+
+ std::vector<r_Minterval> sourceDomains;
+
+ std::vector<r_Minterval> targetDomains;
+ };
+#endif
+
diff --git a/tilemgr/transtile.cc b/tilemgr/transtile.cc
new file mode 100644
index 0000000..a23f993
--- /dev/null
+++ b/tilemgr/transtile.cc
@@ -0,0 +1 @@
+//moved to tile
diff --git a/tilemgr/transtile.hh b/tilemgr/transtile.hh
new file mode 100644
index 0000000..a23f993
--- /dev/null
+++ b/tilemgr/transtile.hh
@@ -0,0 +1 @@
+//moved to tile
diff --git a/time/Makefile.am b/time/Makefile.am
new file mode 100644
index 0000000..edb58f6
--- /dev/null
+++ b/time/Makefile.am
@@ -0,0 +1,31 @@
+#
+# This file is part of rasdaman community.
+#
+# Rasdaman community is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Rasdaman community is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+# rasdaman GmbH.
+#
+# For more information please see <http://www.rasdaman.org>
+# or contact Peter Baumann via <baumann@rasdaman.com>.
+#
+# MAKEFILE FOR:
+# module clientcomm
+#
+# COMMENTS:
+#
+##################################################################
+
+noinst_LIBRARIES=libtime.a
+libtime_a_SOURCES= akg_localtime.cc akg_benchmark.cc akgtime.hh
diff --git a/time/README b/time/README
new file mode 100644
index 0000000..0477b16
--- /dev/null
+++ b/time/README
@@ -0,0 +1,2 @@
+currently unused; instead: ../rasmgr/rasmgr_config.cc
+
diff --git a/time/akg_benchmark.cc b/time/akg_benchmark.cc
new file mode 100644
index 0000000..6bb0c8d
--- /dev/null
+++ b/time/akg_benchmark.cc
@@ -0,0 +1,123 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+/*************************************************************************
+ *
+ *
+ * PURPOSE:
+ *
+ *
+ *
+ * COMMENTS:
+ * none
+ *
+ ***********************************************************************/
+
+#include "akgtime.hh"
+#include<iomanip>
+
+using namespace akg;
+
+
+BenchmarkTimer::BenchmarkTimer(const char *lText, bool highPrecision) throw()
+ {
+ text = (char*)lText;
+
+ precHigh = highPrecision;
+ }
+BenchmarkTimer::~BenchmarkTimer() throw()
+ {
+ }
+
+void BenchmarkTimer::reset() throw()
+ {
+ tvStart.tv_sec = 0;
+ tvStart.tv_usec = 0;
+ tvEnd.tv_sec = 0;
+ tvEnd.tv_usec = 0;
+ }
+
+void BenchmarkTimer::start() throw()
+ {
+ gettimeofday(&tvStart,NULL);
+ }
+
+void BenchmarkTimer::stop() throw()
+ {
+ gettimeofday(&tvEnd,NULL);
+ timeval_subtract(&tvResult,&tvEnd,&tvStart);
+ }
+
+void BenchmarkTimer::setPrecision(bool high) throw()
+ {
+ precHigh = high;
+ }
+
+bool BenchmarkTimer::getPrecision() const throw()
+ {
+ return precHigh;
+ }
+
+int BenchmarkTimer::timeval_subtract(timeval *lResult,timeval *x,timeval *y) throw()
+ {
+ /* Perform the carry for the later subtraction by updating Y. */
+ if (x->tv_usec < y->tv_usec) {
+ int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
+ y->tv_usec -= 1000000 * nsec;
+ y->tv_sec += nsec;
+ }
+ if (x->tv_usec - y->tv_usec > 1000000) {
+ int nsec = (x->tv_usec - y->tv_usec) / 1000000;
+ y->tv_usec += 1000000 * nsec;
+ y->tv_sec -= nsec;
+ }
+
+ /* Compute the time remaining to wait.
+ `tv_usec' is certainly positive. */
+ lResult->tv_sec = x->tv_sec - y->tv_sec;
+ lResult->tv_usec = (x->tv_usec - y->tv_usec);
+
+ /* Return 1 if result is negative. */
+ return x->tv_sec < y->tv_sec;
+ }
+
+
+std::ostream& akg::operator<<(std::ostream &os, BenchmarkTimer &bm)
+ {
+ if(bm.precHigh == true)
+ {
+ unsigned int msec = bm.tvResult.tv_sec*1000 + bm.tvResult.tv_usec / 1000;
+ unsigned int usec = bm.tvResult.tv_usec % 1000;
+
+ os<<bm.text<<"="<<msec<<'.'<<std::setfill('0')<<std::setw(3)<<usec<<"ms";
+ }
+ else
+ {
+ unsigned int msec = bm.tvResult.tv_usec / 1000;
+ unsigned int sec = bm.tvResult.tv_sec;
+
+ os<<bm.text<<"="<<sec<<'.'<<std::setfill('0')<<std::setw(3)<<msec<<"s";
+ }
+ return os;
+ }
+
diff --git a/time/akg_localtime.cc b/time/akg_localtime.cc
new file mode 100644
index 0000000..0831cbc
--- /dev/null
+++ b/time/akg_localtime.cc
@@ -0,0 +1,60 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+/*
+ * 2007-feb-07 PB #include <akgtime.hh> -> "akgtime.hh"
+ */
+
+#include "akgtime.hh"
+#include <iomanip>
+
+using namespace akg;
+
+
+LocalTime::LocalTime() throw()
+ {
+ now();
+ }
+
+void LocalTime::now() throw()
+ {
+ //gettimeofday(&value,NULL);
+ value = time(NULL);
+ }
+
+std::ostream& akg::operator<<(std::ostream &os, const LocalTime &lt)
+ {
+ struct tm broken;
+
+ localtime_r(&lt.value, &broken);
+
+ os<<std::setw(2)<<broken.tm_mday<<'.';
+ os<<std::setw(2)<<std::setfill('0')<<broken.tm_mon+1;
+ os<<'.'<<broken.tm_year+1900<<' ';
+ os<<std::setw(2)<<std::setfill('0')<<broken.tm_hour<<':';
+ os<<std::setw(2)<<std::setfill('0')<<broken.tm_min<<':';
+ os<<std::setw(2)<<std::setfill('0')<<broken.tm_sec;
+
+ return os;
+ }
+
diff --git a/time/akgtime.hh b/time/akgtime.hh
new file mode 100644
index 0000000..925eeb8
--- /dev/null
+++ b/time/akgtime.hh
@@ -0,0 +1,85 @@
+#ifndef AKGTIME_HH
+#define AKGTIME_HH
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+/****************************************************************************
+ *
+ *
+ * COMMENTS:
+ * Namespace akg
+ *
+ ****************************************************************************/
+
+#include <iostream>
+
+
+#include <sys/time.h>
+#include <time.h>
+
+namespace akg
+{
+
+class LocalTime
+ {
+ public:
+ LocalTime() throw();
+
+ void now() throw();
+
+ private:
+ time_t value;
+
+ friend std::ostream& operator<<(std::ostream&, const LocalTime&);
+
+ };
+
+
+class BenchmarkTimer
+ {
+ public:
+ BenchmarkTimer(const char *text, bool highPrecision = false) throw();
+ ~BenchmarkTimer() throw();
+
+ void reset() throw();
+ void start() throw();
+ void stop() throw();
+
+ void setPrecision(bool high) throw();
+ bool getPrecision() const throw();
+
+ friend std::ostream& operator<<(std::ostream&, BenchmarkTimer&);
+ private:
+ int timeval_subtract(timeval *result,timeval *x,timeval *y) throw();
+
+ struct timeval tvStart;
+ struct timeval tvEnd;
+ struct timeval tvResult;
+
+ char* text;
+ bool precHigh;
+ };
+
+} // namespace
+
+#endif
diff --git a/time/main.cc b/time/main.cc
new file mode 100644
index 0000000..4f4aad8
--- /dev/null
+++ b/time/main.cc
@@ -0,0 +1,46 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+*/
+
+#include <iostream>
+#include <akgtime.hh>
+
+using namespace std;
+using namespace akg;
+
+int main()
+{
+
+ BenchmarkTimer bm("Got Localtime");
+ bm.start();
+
+ LocalTime ltime;
+
+ cout<<"Now is "<<ltime<<endl;
+
+ bm.stop();
+ bm.setPrecision(true);
+
+ cout<<"Benchmark: "<<bm<<endl;
+
+return 0;
+}